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
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
// ── The skills catalog: what every runtime folder holds ──
|
|
2
|
+
// Reads every root lib/skills/roots.js lists, asynchronously and within bounds, and answers with one entry per
|
|
3
|
+
// skill folder, command, agent and prompt file: what it is, where, which runtimes read it, its name and
|
|
4
|
+
// description as text, the count of its problems, whether SynaBun installed it, and how it collides with
|
|
5
|
+
// same-named entries ("which one runs"). A root that cannot be read, an entry skipped and why, and a scan that
|
|
6
|
+
// stopped at its limits are said, never dropped: `roots[].status`, `diagnostics`, `truncated`.
|
|
7
|
+
//
|
|
8
|
+
// The scan is cached (a fresh answer for `ttlMs`, then read again; any write SynaBun makes invalidates it) and
|
|
9
|
+
// the metadata of each head file is cached by its inode, size and modification time, so an unchanged file is
|
|
10
|
+
// never parsed twice. File trees are not read for the list: an entry's tree is read when it is opened (detail).
|
|
11
|
+
// Ids are opaque (`art_<hash>`): an id is looked up in the scan, never decoded into a path.
|
|
12
|
+
|
|
13
|
+
import { createHash } from 'node:crypto';
|
|
14
|
+
import { promises as fsp } from 'node:fs';
|
|
15
|
+
import { join, relative, sep } from 'node:path';
|
|
16
|
+
import { isInside, realPathOf } from '../path-confine.js';
|
|
17
|
+
import { listConfined } from '../confined-fs.js';
|
|
18
|
+
|
|
19
|
+
export const CATALOG_LIMITS = Object.freeze({ maxPerRoot: 500, maxEntries: 5000, maxCommandDepth: 4, budgetMs: 8000, ttlMs: 15000, headCache: 4000, yieldEvery: 25 });
|
|
20
|
+
|
|
21
|
+
const tick = () => new Promise((r) => setImmediate(r));
|
|
22
|
+
const artifactIdOf = (rootId, rel) => `art_${createHash('sha256').update(`${rootId}\0${rel}`).digest('hex').slice(0, 20)}`;
|
|
23
|
+
export const isArtifactId = (v) => typeof v === 'string' && /^art_[0-9a-f]{20}$/.test(v);
|
|
24
|
+
|
|
25
|
+
// Claude Code's same-name order (code.claude.com/docs/en/skills, "Resolve skills that share a name").
|
|
26
|
+
const CLAUDE_RANK = { managed: 0, user: 1, synced: 3, project: 2, plugin: 9 };
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {object} o
|
|
30
|
+
* @param {() => object[]} o.roots lib/skills/roots.js listRoots
|
|
31
|
+
* @param {(realBase: string, file: string) => { text: string, binary: boolean, revision: string, size: number }} o.readHead
|
|
32
|
+
* a bounded, confined read of a head file (throws when it cannot be read as a regular file)
|
|
33
|
+
* @param {(o: { type, text, folderName, binary }) => { name: string, description: string, problems: object, data: object }} o.describe
|
|
34
|
+
* @param {(path: string) => object|null} [o.ownership] what the install ledger says of a folder or file
|
|
35
|
+
* @param {(o: { text: string, name: string, family: string }) => object|null} [o.classifyBridge] an old bridge's signature
|
|
36
|
+
*/
|
|
37
|
+
export function createSkillsCatalog({ roots, readHead, describe, ownership = () => null, classifyBridge = () => null, limits = CATALOG_LIMITS, now = () => Date.now() }) {
|
|
38
|
+
let snapshot = null;
|
|
39
|
+
let pending = null;
|
|
40
|
+
let generation = 0;
|
|
41
|
+
let stale = true;
|
|
42
|
+
const headCache = new Map();
|
|
43
|
+
|
|
44
|
+
function cachedDescribe(key, read) {
|
|
45
|
+
const hit = headCache.get(key);
|
|
46
|
+
if (hit) { headCache.delete(key); headCache.set(key, hit); return hit; }
|
|
47
|
+
const value = read();
|
|
48
|
+
headCache.set(key, value);
|
|
49
|
+
if (headCache.size > limits.headCache) headCache.delete(headCache.keys().next().value);
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function headOf(realBase, file, { type, folderName }) {
|
|
54
|
+
// The key follows a link inside the folder; the read itself (readHead) refuses one that leads out of it.
|
|
55
|
+
const st = await fsp.stat(file);
|
|
56
|
+
if (!st.isFile()) throw new Error('not a regular file');
|
|
57
|
+
const key = `${file}\0${st.ino}\0${st.size}\0${st.mtimeMs}\0${type}\0${folderName}`;
|
|
58
|
+
return cachedDescribe(key, () => {
|
|
59
|
+
const head = readHead(realBase, file);
|
|
60
|
+
const described = describe({ type, text: head.text, folderName, binary: head.binary });
|
|
61
|
+
// When the head file last changed: the Library's "updated" column (an entry is never sorted by a guess).
|
|
62
|
+
const updatedAt = Number.isFinite(st.mtimeMs) && st.mtimeMs > 0 ? new Date(st.mtimeMs).toISOString() : null;
|
|
63
|
+
return { ...described, revision: head.revision, size: head.size, binary: head.binary, text: head.binary ? '' : head.text, updatedAt };
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Read one root. @returns {{ entries: object[], diagnostics: object[], truncated: boolean, count: number }} */
|
|
68
|
+
async function scanRoot(root, state) {
|
|
69
|
+
const entries = [];
|
|
70
|
+
const diagnostics = [];
|
|
71
|
+
let truncated = false;
|
|
72
|
+
const base = root.resolvedPath;
|
|
73
|
+
const skip = (rel, reason, message) => diagnostics.push({ rootId: root.rootId, path: rel, reason, message });
|
|
74
|
+
const outOfAnchor = (real) => root.anchor && !(() => { try { return isInside(realPathOf(root.anchor), real, { allowRoot: true }); } catch { return false; } })();
|
|
75
|
+
const common = {
|
|
76
|
+
rootId: root.rootId, family: root.family, scope: root.scope, sourceKind: root.sourceKind, runtimes: root.runtimes,
|
|
77
|
+
accountId: root.accountId, projectPath: root.projectPath, projectLabel: root.projectLabel, pluginId: root.pluginId || null,
|
|
78
|
+
readOnly: root.policy?.write !== 'owner',
|
|
79
|
+
};
|
|
80
|
+
if (root.layout === 'skill-folders') {
|
|
81
|
+
let names = [];
|
|
82
|
+
try { names = (await fsp.readdir(base, { withFileTypes: true })).map((d) => d.name).sort(); } catch (err) { return { entries, diagnostics: [{ rootId: root.rootId, path: '', reason: 'unreadable', message: String(err?.code || err?.message || err) }], truncated, count: 0 }; }
|
|
83
|
+
for (const name of names) {
|
|
84
|
+
if (name.startsWith('.') || name === 'node_modules') continue;
|
|
85
|
+
// Claude's account skills and Codex's system skills are roots of their own.
|
|
86
|
+
if (root.scope === 'user' && root.family === 'claude' && name === 'synced') continue;
|
|
87
|
+
if (entries.length >= limits.maxPerRoot || state.total >= limits.maxEntries || now() > state.deadline) { truncated = true; break; }
|
|
88
|
+
if (++state.seen % limits.yieldEvery === 0) await tick();
|
|
89
|
+
const dir = join(base, name);
|
|
90
|
+
let real;
|
|
91
|
+
try { real = realPathOf(dir); } catch { skip(name, 'link', 'A link that leads nowhere.'); continue; }
|
|
92
|
+
let st;
|
|
93
|
+
try { st = await fsp.stat(real); } catch { skip(name, 'unreadable', 'Cannot be read.'); continue; }
|
|
94
|
+
if (!st.isDirectory()) continue;
|
|
95
|
+
if (outOfAnchor(real)) { skip(name, 'outside-project', 'A link that leads out of the project: not read.'); continue; }
|
|
96
|
+
const linked = real !== join(base, name);
|
|
97
|
+
// A link in a project's folder must stay in the project; one in the user's own folder is theirs.
|
|
98
|
+
if (linked && root.scope !== 'user' && root.scope !== 'shared' && !isInside(base, real)) { skip(name, 'link', 'A link out of its folder: not read.'); continue; }
|
|
99
|
+
const head = join(real, 'SKILL.md');
|
|
100
|
+
let meta;
|
|
101
|
+
try { meta = await headOf(real, head, { type: 'skill', folderName: name }); } catch (err) {
|
|
102
|
+
if (err?.code === 'ENOENT') skip(name, 'no-skill-md', 'A folder without SKILL.md: not a skill.');
|
|
103
|
+
else skip(name, 'unreadable-head', `SKILL.md cannot be read (${err?.status === 413 ? 'too large' : (err?.code || err?.message || 'error')}).`);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const rel = name;
|
|
107
|
+
entries.push({
|
|
108
|
+
...common, id: artifactIdOf(root.rootId, rel), kind: 'skill', name: meta.name || name, folderName: name, relPath: rel,
|
|
109
|
+
invocationName: root.scope === 'plugin' && root.pluginId ? `${root.pluginId.split('@')[0]}:${meta.name || name}` : (root.scope === 'synced' ? `anthropic-skills:${meta.name || name}` : (meta.name || name)),
|
|
110
|
+
description: meta.description, problems: meta.problems, path: dir, realPath: real, headPath: head, linked,
|
|
111
|
+
revision: meta.revision, size: meta.size, binary: meta.binary, data: meta.data, updatedAt: meta.updatedAt || null,
|
|
112
|
+
ownership: ownership(dir), files: null,
|
|
113
|
+
});
|
|
114
|
+
state.total++;
|
|
115
|
+
}
|
|
116
|
+
} else {
|
|
117
|
+
const maxDepth = root.kind === 'commands' ? limits.maxCommandDepth : 1;
|
|
118
|
+
const kind = root.kind === 'commands' ? 'command' : root.kind === 'agents' ? 'agent' : 'prompt';
|
|
119
|
+
const walk = async (dir, relDir, depth) => {
|
|
120
|
+
let dirents = [];
|
|
121
|
+
try { dirents = await fsp.readdir(dir, { withFileTypes: true }); } catch (err) { if (!relDir) throw err; skip(relDir, 'unreadable', 'A folder that cannot be read.'); return; }
|
|
122
|
+
dirents.sort((a, b) => (a.name < b.name ? -1 : 1));
|
|
123
|
+
for (const d of dirents) {
|
|
124
|
+
if (d.name.startsWith('.')) continue;
|
|
125
|
+
if (entries.length >= limits.maxPerRoot || state.total >= limits.maxEntries || now() > state.deadline) { truncated = true; return; }
|
|
126
|
+
if (++state.seen % limits.yieldEvery === 0) await tick();
|
|
127
|
+
const full = join(dir, d.name);
|
|
128
|
+
const rel = relDir ? `${relDir}/${d.name}` : d.name;
|
|
129
|
+
if (d.isDirectory()) { if (depth + 1 < maxDepth) await walk(full, rel, depth + 1); else if (kind === 'command') skip(rel, 'too-deep', 'Nested deeper than SynaBun reads.'); continue; }
|
|
130
|
+
if (!/\.md$/i.test(d.name)) continue;
|
|
131
|
+
let meta;
|
|
132
|
+
try { meta = await headOf(base, full, { type: kind === 'prompt' ? 'command' : kind, folderName: d.name.replace(/\.md$/i, '') }); } catch (err) {
|
|
133
|
+
skip(rel, d.isSymbolicLink() ? 'link' : 'unreadable-head', d.isSymbolicLink() ? 'A link: read only when it stays in its folder.' : `Cannot be read (${err?.status === 413 ? 'too large' : (err?.code || err?.message || 'error')}).`);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const stem = d.name.replace(/\.md$/i, '');
|
|
137
|
+
const namespace = relDir ? relDir.split('/').join(':') : '';
|
|
138
|
+
const plugin = root.scope === 'plugin' && root.pluginId ? root.pluginId.split('@')[0] : '';
|
|
139
|
+
const invocationName = kind === 'prompt' ? `prompts:${stem}` : [plugin, namespace, stem].filter(Boolean).join(':');
|
|
140
|
+
const bridge = kind === 'prompt' || root.sourceKind === 'legacy-bridge' ? classifyBridge({ text: meta.text || '', name: stem, family: root.family, path: full }) : null;
|
|
141
|
+
entries.push({
|
|
142
|
+
...common, id: artifactIdOf(root.rootId, rel), kind, name: kind === 'agent' && meta.name ? meta.name : stem, folderName: stem, relPath: rel, namespace,
|
|
143
|
+
invocationName, description: meta.description, problems: meta.problems, path: full, realPath: full, headPath: full, linked: d.isSymbolicLink(),
|
|
144
|
+
revision: meta.revision, size: meta.size, binary: meta.binary, data: meta.data, updatedAt: meta.updatedAt || null, ownership: ownership(full), bridge, files: null,
|
|
145
|
+
});
|
|
146
|
+
state.total++;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
try { await walk(base, '', 0); } catch (err) { return { entries, diagnostics: [{ rootId: root.rootId, path: '', reason: 'unreadable', message: String(err?.code || err?.message || err) }], truncated, count: 0 }; }
|
|
150
|
+
}
|
|
151
|
+
return { entries, diagnostics, truncated, count: entries.length };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Same-named entries, runtime by runtime: which one a runtime runs, or that it lists both. */
|
|
155
|
+
function collide(entries) {
|
|
156
|
+
const groups = new Map();
|
|
157
|
+
for (const e of entries) {
|
|
158
|
+
if (e.kind === 'prompt') continue;
|
|
159
|
+
for (const runtime of e.runtimes) {
|
|
160
|
+
const key = `${runtime}\0${e.invocationName}`;
|
|
161
|
+
if (!groups.has(key)) groups.set(key, []);
|
|
162
|
+
groups.get(key).push(e);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
for (const [key, list] of groups) {
|
|
166
|
+
if (list.length < 2) continue;
|
|
167
|
+
const runtime = key.split('\0')[0];
|
|
168
|
+
// One folder seen through two roots (a link) is one skill, not a collision.
|
|
169
|
+
const distinct = new Map(list.map((e) => [e.realPath, e]));
|
|
170
|
+
if (distinct.size < 2) continue;
|
|
171
|
+
if (runtime === 'claude') {
|
|
172
|
+
const ranked = [...list].sort((a, b) => (a.kind === b.kind ? 0 : a.kind === 'skill' ? -1 : 1) || ((CLAUDE_RANK[a.scope] ?? 5) - (CLAUDE_RANK[b.scope] ?? 5)));
|
|
173
|
+
const winner = ranked[0];
|
|
174
|
+
for (const e of list) {
|
|
175
|
+
(e.collisions ||= []).push({
|
|
176
|
+
runtime, with: list.filter((x) => x !== e).map((x) => x.id), outcome: e === winner ? 'runs' : 'shadowed',
|
|
177
|
+
why: e === winner ? `/${e.invocationName} runs this one in Claude Code.` : `Claude Code runs the ${winner.scope} ${winner.kind} of the same name instead (a skill comes before a command; managed, then personal, then project).`,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
} else {
|
|
181
|
+
for (const e of list) {
|
|
182
|
+
(e.collisions ||= []).push({ runtime, with: list.filter((x) => x !== e).map((x) => x.id), outcome: 'both-listed', why: `${runtime === 'codex' ? 'Codex' : 'OpenCode'} lists every skill of this name; which one the model picks is not fixed. Give them different names.` });
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async function build() {
|
|
189
|
+
const state = { total: 0, seen: 0, deadline: now() + limits.budgetMs };
|
|
190
|
+
const rootList = roots();
|
|
191
|
+
const entries = [];
|
|
192
|
+
const diagnostics = [];
|
|
193
|
+
const rootRows = [];
|
|
194
|
+
let truncated = false;
|
|
195
|
+
for (const root of rootList) {
|
|
196
|
+
const row = { ...root, count: 0, truncated: false };
|
|
197
|
+
if (root.status !== 'ok') {
|
|
198
|
+
if (root.status !== 'absent') diagnostics.push({ rootId: root.rootId, path: '', reason: root.status, message: root.status === 'not-a-folder' ? 'Not a folder.' : 'Cannot be read.' });
|
|
199
|
+
rootRows.push(row);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (now() > state.deadline || state.total >= limits.maxEntries) { row.truncated = true; truncated = true; rootRows.push(row); continue; }
|
|
203
|
+
const res = await scanRoot(root, state);
|
|
204
|
+
entries.push(...res.entries);
|
|
205
|
+
diagnostics.push(...res.diagnostics);
|
|
206
|
+
if (res.diagnostics.some((d) => d.path === '' && d.reason === 'unreadable')) row.status = 'unreadable';
|
|
207
|
+
row.count = res.count;
|
|
208
|
+
row.truncated = res.truncated;
|
|
209
|
+
truncated ||= res.truncated;
|
|
210
|
+
rootRows.push(row);
|
|
211
|
+
}
|
|
212
|
+
collide(entries);
|
|
213
|
+
generation += 1;
|
|
214
|
+
return { generation, generatedAt: new Date(now()).toISOString(), entries, roots: rootRows, diagnostics, truncated };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** The catalog, read again when it is stale; one read at a time (callers share it). */
|
|
218
|
+
async function scan({ force = false } = {}) {
|
|
219
|
+
if (!force && snapshot && !stale && now() - Date.parse(snapshot.generatedAt) < limits.ttlMs) return snapshot;
|
|
220
|
+
if (pending) return pending;
|
|
221
|
+
pending = build().then((s) => { snapshot = s; stale = false; return s; }).finally(() => { pending = null; });
|
|
222
|
+
return pending;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function invalidate() { stale = true; }
|
|
226
|
+
|
|
227
|
+
/** One page of entries, filtered. A cursor of an older scan restarts at the top (`cursorReset`). */
|
|
228
|
+
async function page({ cursor = null, limit = 100, kind = null, runtime = null, rootId = null, scope = null, q = '' } = {}) {
|
|
229
|
+
const s = await scan();
|
|
230
|
+
let offset = 0;
|
|
231
|
+
let cursorReset = false;
|
|
232
|
+
if (cursor) {
|
|
233
|
+
try {
|
|
234
|
+
const c = JSON.parse(Buffer.from(String(cursor), 'base64url').toString('utf-8'));
|
|
235
|
+
if (c && c.g === s.generation && Number.isInteger(c.o) && c.o >= 0) offset = c.o; else cursorReset = true;
|
|
236
|
+
} catch { cursorReset = true; }
|
|
237
|
+
}
|
|
238
|
+
const needle = String(q || '').toLowerCase();
|
|
239
|
+
const filtered = s.entries.filter((e) => (!kind || e.kind === kind) && (!runtime || e.runtimes.includes(runtime)) && (!rootId || e.rootId === rootId)
|
|
240
|
+
&& (!scope || e.scope === scope) && (!needle || `${e.name} ${e.description}`.toLowerCase().includes(needle)));
|
|
241
|
+
const size = Math.max(1, Math.min(500, Number(limit) || 100));
|
|
242
|
+
const items = filtered.slice(offset, offset + size).map(publicEntry);
|
|
243
|
+
const next = offset + size < filtered.length ? Buffer.from(JSON.stringify({ g: s.generation, o: offset + size })).toString('base64url') : null;
|
|
244
|
+
return { items, nextCursor: next, total: filtered.length, generation: s.generation, generatedAt: s.generatedAt, truncated: s.truncated, cursorReset };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** One entry by id, with its file tree (read now, bounded) and its head file's text. */
|
|
248
|
+
async function detail(id, { tree = true } = {}) {
|
|
249
|
+
if (!isArtifactId(id)) return null;
|
|
250
|
+
let s = await scan();
|
|
251
|
+
let entry = s.entries.find((e) => e.id === id);
|
|
252
|
+
if (!entry) { s = await scan({ force: true }); entry = s.entries.find((e) => e.id === id); }
|
|
253
|
+
if (!entry) return null;
|
|
254
|
+
const out = { ...publicEntry(entry), text: null };
|
|
255
|
+
// The head file's text, read now the way the scan reads it: bounded, a regular file inside its folder (a skill)
|
|
256
|
+
// or its root (a command, an agent). A file that is not text is said to be binary; one that cannot be read says why.
|
|
257
|
+
try {
|
|
258
|
+
const base = entry.kind === 'skill' ? entry.realPath : (s.roots.find((r) => r.rootId === entry.rootId)?.resolvedPath || entry.realPath);
|
|
259
|
+
const head = readHead(base, entry.headPath);
|
|
260
|
+
if (head.binary) out.binary = true;
|
|
261
|
+
else out.text = head.text;
|
|
262
|
+
} catch (err) {
|
|
263
|
+
out.textError = err?.status === 413 ? 'too large' : (err?.code || err?.message || 'unreadable');
|
|
264
|
+
}
|
|
265
|
+
if (entry.kind === 'skill' && tree) {
|
|
266
|
+
const listing = listConfined(entry.realPath, entry.realPath, { skip: (n) => n === 'node_modules' });
|
|
267
|
+
const plain = (nodes) => nodes.map((n) => (n.type === 'dir' ? { name: n.name, path: n.path, type: 'dir', children: plain(n.children || []) } : { name: n.name, path: n.path, type: 'file', size: n.size }));
|
|
268
|
+
out.files = plain(listing.entries);
|
|
269
|
+
out.filesTruncated = listing.truncated;
|
|
270
|
+
}
|
|
271
|
+
return { entry: out, internal: entry };
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** The internal entry (paths included), for the service. */
|
|
275
|
+
async function find(id) {
|
|
276
|
+
if (!isArtifactId(id)) return null;
|
|
277
|
+
const s = await scan();
|
|
278
|
+
return s.entries.find((e) => e.id === id) || (await scan({ force: true })).entries.find((e) => e.id === id) || null;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return { scan, invalidate, page, detail, find, roots: () => roots(), _headCache: headCache };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** An entry as the API answers it (no frontmatter object; paths are the user's own and stay). */
|
|
285
|
+
export function publicEntry(e) {
|
|
286
|
+
const { data, realPath, ...rest } = e;
|
|
287
|
+
return { ...rest, linked: !!e.linked, collisions: e.collisions || [] };
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** A path inside a root, as the root's own relative path (forward slashes). */
|
|
291
|
+
export function relativeIn(root, path) {
|
|
292
|
+
return relative(root, path).split(sep).join('/');
|
|
293
|
+
}
|
|
294
|
+
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// ── /api/skills-studio/v2/creations: AI skill creation over HTTP (P3) ──
|
|
2
|
+
// The routes of lib/skills/creation.js, beside the rest of the Skills Service's v2 routes (lib/skills/api-v2.js),
|
|
3
|
+
// and the skill-forge guide the Assistant's `skill` tool reads (`GET /guide`). Who may do what:
|
|
4
|
+
//
|
|
5
|
+
// the owner from SynaBun's own page (no agent header, X-SynaBun-UI: 1, this boot's page secret cookie,
|
|
6
|
+
// lib/page-session.js, the owner route guard): starts,
|
|
7
|
+
// reads, waits on, cancels and retries every creation; lists the sessions a conversation source
|
|
8
|
+
// can use.
|
|
9
|
+
// the Assistant a request carrying the credential an Assistant brain's launch was given (X-Synabun-Brain-Token,
|
|
10
|
+
// assistant-runtime.js mintBrainCredential; the MCP `skill` tool forwards it), resolved to that
|
|
11
|
+
// brain's session (assistantCaller): starts, reads, waits on, cancels and retries the creations of
|
|
12
|
+
// its session, which pays for the worker. X-Synabun-Role and X-Synabun-Terminal prove nothing (any
|
|
13
|
+
// local process can send them): without the credential an agent is refused, and a dispatched worker
|
|
14
|
+
// is refused whatever it sends. Creating skills is not a worker's to do.
|
|
15
|
+
// anyone else 403 (a guest, an agent without a brain's credential).
|
|
16
|
+
//
|
|
17
|
+
// A creation runs a worker and spends money: nothing here is open to a reader.
|
|
18
|
+
|
|
19
|
+
import { sendGuardError } from '../http-guards.js';
|
|
20
|
+
import { PathConfineError } from '../path-confine.js';
|
|
21
|
+
import { V2_BASE, principalOf } from './api-v2.js';
|
|
22
|
+
import { isCreationId } from './creation.js';
|
|
23
|
+
import { CONVERSATION_PROVIDERS, CREATION_LIMITS, DRAFT_PROVIDERS, SOURCE_KINDS } from '../../public/shared/skills/ss-creation.js';
|
|
24
|
+
|
|
25
|
+
export const SKILL_FORGE = 'skill-forge';
|
|
26
|
+
const IDEMPOTENCY_TTL_MS = 10 * 60 * 1000;
|
|
27
|
+
|
|
28
|
+
function fail(res, err) {
|
|
29
|
+
const status = err instanceof PathConfineError ? err.status : (Number.isInteger(err?.status) && err.status >= 400 && err.status < 600 ? err.status : 500);
|
|
30
|
+
const body = { ok: false, error: status >= 500 && !(err instanceof PathConfineError) ? `Skill creation failed: ${err?.message || err}` : (err?.message || String(err)) };
|
|
31
|
+
if (typeof err?.code === 'string' && !/^E[A-Z]+$/.test(err.code)) body.code = err.code;
|
|
32
|
+
for (const key of ['problems']) if (err?.[key] !== undefined) body[key] = err[key];
|
|
33
|
+
return res.status(status).json(body);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @param {object} app express app
|
|
38
|
+
* @param {object} o
|
|
39
|
+
* @param {object} o.creations lib/skills/creation.js
|
|
40
|
+
* @param {object} o.service lib/skills/service.js (the bundled skill-forge for GET /guide)
|
|
41
|
+
* @param {(req) => boolean} [o.isGuestRequest]
|
|
42
|
+
* @param {Function} [o.ownerGuard] lib/http-guards.js ownerRouteGuard(…) of this server
|
|
43
|
+
* @param {(req) => ({ kind: 'assistant', assistantSessionId: string } | { kind: 'worker' } | null)} [o.assistantCaller]
|
|
44
|
+
* who an agent request is: an Assistant brain (the session its credential belongs to), a dispatched worker, or nobody
|
|
45
|
+
* @param {() => object} [o.options] what can run now: { conversation: string[] (providers), url: boolean, urlReason,
|
|
46
|
+
* repo: { path, label }[], memory: boolean, import: boolean, defaultTarget, drafting: { available, reason, providers } }
|
|
47
|
+
* @param {{ verify(req): boolean, require(req, res, next), attach(res) }} [o.pageSession] lib/page-session.js: the owner's
|
|
48
|
+
* writes carry this boot's page secret; the owner's reads hand it to the page
|
|
49
|
+
* @param {(q) => Promise<object[]>} [o.sessions] the sessions a conversation source can use
|
|
50
|
+
*/
|
|
51
|
+
export function registerSkillCreationRoutes(app, { creations, service, isGuestRequest = null, ownerGuard = null, assistantCaller = null, options = () => ({}), sessions = null, pageSession = null } = {}) {
|
|
52
|
+
const idem = new Map();
|
|
53
|
+
const route = (method, path, ...handlers) => app[method](`${V2_BASE}${path}`, ...handlers);
|
|
54
|
+
const safe = (fn) => async (req, res) => { try { await fn(req, res); } catch (err) { fail(res, err); } };
|
|
55
|
+
|
|
56
|
+
const json = (req, res, next) => {
|
|
57
|
+
if (String(req.headers['sec-fetch-site'] || '').toLowerCase() === 'cross-site') return sendGuardError(res, 403, 'CROSS_SITE', 'Cross-site requests are refused.');
|
|
58
|
+
const hasBody = Number(req.headers['content-length'] || 0) > 0 || req.headers['transfer-encoding'] !== undefined;
|
|
59
|
+
if (hasBody && typeof req.is === 'function' && !req.is('application/json')) return sendGuardError(res, 415, 'UNSUPPORTED_MEDIA_TYPE', 'Send JSON (Content-Type: application/json).');
|
|
60
|
+
if (req.body !== undefined && req.body !== null && (typeof req.body !== 'object' || Array.isArray(req.body))) return res.status(400).json({ ok: false, error: 'The body is a JSON object.', code: 'invalid_body' });
|
|
61
|
+
next();
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Who may create: the owner from the page, or an Assistant brain. `write`: the owner's page header and route
|
|
66
|
+
* guard are asked too (a read from the page needs neither, but never a guest's).
|
|
67
|
+
*/
|
|
68
|
+
const caller = (write) => (req, res, next) => {
|
|
69
|
+
const principal = principalOf(req, isGuestRequest);
|
|
70
|
+
if (principal.kind === 'guest') return sendGuardError(res, 403, 'GUEST_FORBIDDEN', 'Available to the owner only.');
|
|
71
|
+
if (principal.kind === 'owner') {
|
|
72
|
+
req.creator = { kind: 'owner', assistantSessionId: null };
|
|
73
|
+
if (!write) { pageSession?.attach?.(res); return next(); }
|
|
74
|
+
if (req.headers['x-synabun-ui'] !== '1') return sendGuardError(res, 403, 'UI_HEADER_REQUIRED', 'Send the X-SynaBun-UI: 1 header.');
|
|
75
|
+
// The page secret (lib/page-session.js): what a local process that merely left the agent headers out lacks.
|
|
76
|
+
if (pageSession && !pageSession.verify(req)) return pageSession.require(req, res, next);
|
|
77
|
+
return ownerGuard ? ownerGuard(req, res, next) : next();
|
|
78
|
+
}
|
|
79
|
+
// An agent: only an Assistant brain, by its credential (never by a header any local process can send), and never
|
|
80
|
+
// a dispatched worker.
|
|
81
|
+
let who = null;
|
|
82
|
+
try { who = typeof assistantCaller === 'function' ? assistantCaller(req) : null; } catch { who = null; }
|
|
83
|
+
if (who?.kind === 'worker') return sendGuardError(res, 403, 'WORKERS_NOT_PERMITTED', 'Dispatched workers cannot create skills: the Assistant or the owner does.');
|
|
84
|
+
if (who?.kind !== 'assistant' || typeof who.assistantSessionId !== 'string' || !who.assistantSessionId) {
|
|
85
|
+
return sendGuardError(res, 403, 'ASSISTANT_CREDENTIAL_REQUIRED', 'Drafting skills with AI is the owner\'s (Skills Studio) and the SynaBun Assistant\'s own brain\'s (its launch credential): a role header is not enough.');
|
|
86
|
+
}
|
|
87
|
+
req.creator = { kind: 'assistant', assistantSessionId: who.assistantSessionId, terminal: principal.terminal || null };
|
|
88
|
+
next();
|
|
89
|
+
};
|
|
90
|
+
/** The owner sees every creation; an Assistant brain the ones its own session started. */
|
|
91
|
+
const ownOnly = (creation, req) => req.creator.kind === 'owner' || (creation.by?.kind === 'assistant' && typeof creation.assistantSessionId === 'string' && creation.assistantSessionId !== '' && creation.assistantSessionId === req.creator.assistantSessionId);
|
|
92
|
+
const idCheck = (req, res, next) => (isCreationId(req.params.creationId) ? next() : res.status(400).json({ ok: false, error: 'Not a creation id.', code: 'invalid_id' }));
|
|
93
|
+
/** Same caller, same route, same key within ten minutes: the first answer again (one creation, not two). */
|
|
94
|
+
const once = (handler) => async (req, res) => {
|
|
95
|
+
const key = typeof req.headers['idempotency-key'] === 'string' ? req.headers['idempotency-key'] : (typeof req.body?.idempotencyKey === 'string' ? req.body.idempotencyKey : null);
|
|
96
|
+
if (!key) return handler(req, res);
|
|
97
|
+
if (key.length > 200) return res.status(400).json({ ok: false, error: 'An idempotency key is at most 200 characters.', code: 'invalid_idempotency_key' });
|
|
98
|
+
const slot = `${req.creator?.kind}\0${req.creator?.assistantSessionId || ''}\0${req.method}\0${req.originalUrl || req.url}\0${key}`;
|
|
99
|
+
const hit = idem.get(slot);
|
|
100
|
+
if (hit && Date.now() - hit.at < IDEMPOTENCY_TTL_MS) return res.status(hit.status).json({ ...hit.body, replayed: true });
|
|
101
|
+
const original = res.json.bind(res);
|
|
102
|
+
res.json = (body) => {
|
|
103
|
+
if (res.statusCode < 300) { idem.set(slot, { at: Date.now(), status: res.statusCode, body }); if (idem.size > 300) idem.delete(idem.keys().next().value); }
|
|
104
|
+
return original(body);
|
|
105
|
+
};
|
|
106
|
+
return handler(req, res);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
route('get', '/creations/options', caller(false), safe(async (req, res) => {
|
|
110
|
+
const o = (typeof options === 'function' ? options() : options) || {};
|
|
111
|
+
res.json({
|
|
112
|
+
ok: true, kinds: SOURCE_KINDS, limits: CREATION_LIMITS, active: creations.activeCount(), maxActive: creations.limits.maxActive,
|
|
113
|
+
conversation: Array.isArray(o.conversation) ? o.conversation.filter((p) => CONVERSATION_PROVIDERS.includes(p)) : [],
|
|
114
|
+
url: o.url === true, ...(o.url !== true && typeof o.urlReason === 'string' && o.urlReason ? { urlReason: o.urlReason.slice(0, 400) } : {}),
|
|
115
|
+
memory: o.memory === true, import: o.import === true,
|
|
116
|
+
// Who drafts (every provider a drafting run can be held to its folder on: lib/skills/draft-confinement.js), whether
|
|
117
|
+
// one can run here now, and, when the host says, each provider's own answer (`providerStatus`: installed or not,
|
|
118
|
+
// with why, and how it is confined) so the page can grey out what cannot run.
|
|
119
|
+
drafting: {
|
|
120
|
+
providers: DRAFT_PROVIDERS, available: o.drafting?.available !== false,
|
|
121
|
+
...(o.drafting?.available === false && typeof o.drafting?.reason === 'string' ? { reason: o.drafting.reason.slice(0, 400) } : {}),
|
|
122
|
+
...(Array.isArray(o.drafting?.providers) && o.drafting.providers.every((p) => p && typeof p === 'object') ? { providerStatus: o.drafting.providers.filter((p) => DRAFT_PROVIDERS.includes(p.provider)).map((p) => ({ provider: p.provider, available: p.available === true, ...(p.reason ? { reason: String(p.reason).slice(0, 400) } : {}), ...(p.level ? { level: String(p.level) } : {}), ...(p.note ? { note: String(p.note).slice(0, 400) } : {}) })) } : {}),
|
|
123
|
+
},
|
|
124
|
+
repo: (Array.isArray(o.repo) ? o.repo : []).map((p) => ({ path: String(p.path), label: String(p.label || p.path) })).slice(0, 200),
|
|
125
|
+
defaultTarget: o.defaultTarget && typeof o.defaultTarget === 'object' ? { provider: o.defaultTarget.provider, model: o.defaultTarget.model || null, effort: o.defaultTarget.effort || null, route: o.defaultTarget.route === true } : null,
|
|
126
|
+
});
|
|
127
|
+
}));
|
|
128
|
+
route('get', '/creations/sessions', caller(false), safe(async (req, res) => {
|
|
129
|
+
const q = req.query || {};
|
|
130
|
+
const provider = typeof q.provider === 'string' ? q.provider : '';
|
|
131
|
+
if (!CONVERSATION_PROVIDERS.includes(provider)) return res.status(400).json({ ok: false, error: `provider is one of ${CONVERSATION_PROVIDERS.join(', ')}.`, code: 'invalid_provider' });
|
|
132
|
+
if (typeof sessions !== 'function') return res.status(409).json({ ok: false, error: 'This server lists no sessions.', code: 'source_unavailable' });
|
|
133
|
+
const list = await sessions({ provider, project: typeof q.project === 'string' && q.project ? q.project.slice(0, 4000) : null, q: typeof q.q === 'string' ? q.q.slice(0, 200) : '', limit: Math.min(100, Math.max(1, Number(q.limit) || 40)) });
|
|
134
|
+
res.json({ ok: true, provider, sessions: Array.isArray(list) ? list.slice(0, 100) : [] });
|
|
135
|
+
}));
|
|
136
|
+
route('get', '/creations', caller(false), safe(async (req, res) => {
|
|
137
|
+
const all = creations.list({ limit: Number(req.query?.limit) || 30 });
|
|
138
|
+
res.json({ ok: true, creations: req.creator.kind === 'owner' ? all : all.filter((c) => ownOnly(c, req)) });
|
|
139
|
+
}));
|
|
140
|
+
route('post', '/creations', json, caller(true), once(safe(async (req, res) => {
|
|
141
|
+
const body = { ...(req.body || {}) };
|
|
142
|
+
delete body.idempotencyKey; delete body.assistantSessionId; delete body.assistant_session_id;
|
|
143
|
+
const creation = creations.start(body, {
|
|
144
|
+
by: { kind: req.creator.kind },
|
|
145
|
+
assistantSessionId: req.creator.assistantSessionId,
|
|
146
|
+
// The owner's draft goes to Review by itself; the Assistant looks at it first unless it says otherwise.
|
|
147
|
+
submitDefault: req.creator.kind === 'owner',
|
|
148
|
+
});
|
|
149
|
+
res.status(202).json({ ok: true, creation });
|
|
150
|
+
})));
|
|
151
|
+
route('get', '/creations/:creationId', caller(false), idCheck, safe(async (req, res) => {
|
|
152
|
+
const creation = creations.get(req.params.creationId);
|
|
153
|
+
if (!ownOnly(creation, req)) return sendGuardError(res, 403, 'NOT_YOURS', 'This creation was started by someone else.');
|
|
154
|
+
res.json({ ok: true, creation });
|
|
155
|
+
}));
|
|
156
|
+
route('get', '/creations/:creationId/wait', caller(false), idCheck, safe(async (req, res) => {
|
|
157
|
+
const current = creations.get(req.params.creationId);
|
|
158
|
+
if (!ownOnly(current, req)) return sendGuardError(res, 403, 'NOT_YOURS', 'This creation was started by someone else.');
|
|
159
|
+
const since = Number.isInteger(Number(req.query?.since)) ? Number(req.query.since) : -1;
|
|
160
|
+
const creation = await creations.wait(req.params.creationId, { sinceVersion: since, timeoutMs: Math.min(50, Math.max(1, Number(req.query?.seconds) || 25)) * 1000 });
|
|
161
|
+
res.json({ ok: true, creation });
|
|
162
|
+
}));
|
|
163
|
+
route('post', '/creations/:creationId/cancel', json, caller(true), idCheck, safe(async (req, res) => {
|
|
164
|
+
const current = creations.get(req.params.creationId);
|
|
165
|
+
if (!ownOnly(current, req)) return sendGuardError(res, 403, 'NOT_YOURS', 'This creation was started by someone else.');
|
|
166
|
+
res.json({ ok: true, creation: await creations.cancel(req.params.creationId) });
|
|
167
|
+
}));
|
|
168
|
+
route('post', '/creations/:creationId/retry', json, caller(true), idCheck, once(safe(async (req, res) => {
|
|
169
|
+
const current = creations.get(req.params.creationId);
|
|
170
|
+
if (!ownOnly(current, req)) return sendGuardError(res, 403, 'NOT_YOURS', 'This creation was started by someone else.');
|
|
171
|
+
const creation = creations.retry(req.params.creationId, { by: { kind: req.creator.kind }, assistantSessionId: req.creator.assistantSessionId });
|
|
172
|
+
res.status(202).json({ ok: true, creation });
|
|
173
|
+
})));
|
|
174
|
+
|
|
175
|
+
// The skill-forge workflow SynaBun ships (skills/skill-forge), for the Assistant's `skill` action "guide": its
|
|
176
|
+
// SKILL.md, or one of its files (`file`). Read from the library's copy of what this app version ships.
|
|
177
|
+
route('get', '/guide', (req, res, next) => {
|
|
178
|
+
const principal = principalOf(req, isGuestRequest);
|
|
179
|
+
if (principal.kind === 'guest') return sendGuardError(res, 403, 'GUEST_FORBIDDEN', 'Available to the owner only.');
|
|
180
|
+
next();
|
|
181
|
+
}, safe(async (req, res) => {
|
|
182
|
+
const file = typeof req.query?.file === 'string' && req.query.file ? req.query.file : 'SKILL.md';
|
|
183
|
+
const revision = service.bundledRevision(SKILL_FORGE);
|
|
184
|
+
if (!revision) return res.status(404).json({ ok: false, error: 'This SynaBun ships no skill-forge.', code: 'guide_missing' });
|
|
185
|
+
const entry = revision.manifest.files.find((f) => f.path === file);
|
|
186
|
+
if (!entry) return res.status(404).json({ ok: false, error: `skill-forge has no file "${String(file).slice(0, 200)}".`, code: 'file_not_found', files: revision.manifest.files.map((f) => f.path) });
|
|
187
|
+
const { bytes } = service.library.readRevisionFile(revision.revisionId, entry.path);
|
|
188
|
+
res.json({ ok: true, skill: SKILL_FORGE, revisionId: revision.revisionId, path: entry.path, files: revision.manifest.files.map((f) => f.path), content: bytes.toString('utf-8') });
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
|