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,21 @@
|
|
|
1
|
+
// Small bounded, atomic records inside the Skills Service's private data directory.
|
|
2
|
+
import { mkdirSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { canonicalInside, readConfinedFile, replaceFileAtomic } from '../confined-fs.js';
|
|
5
|
+
|
|
6
|
+
export function localRecord(dir, name, initial, maxBytes = 16 * 1024 * 1024) {
|
|
7
|
+
const path = join(dir, `${name}.json`);
|
|
8
|
+
return {
|
|
9
|
+
read() {
|
|
10
|
+
try { return JSON.parse(readConfinedFile(dir, path, { encoding: 'utf-8', maxBytes })); }
|
|
11
|
+
catch (e) { if (e.code === 'ENOENT' || e.status === 404) return structuredClone(initial); throw e; }
|
|
12
|
+
},
|
|
13
|
+
write(value) {
|
|
14
|
+
const text = `${JSON.stringify(value)}\n`;
|
|
15
|
+
if (Buffer.byteLength(text) > maxBytes) throw Object.assign(new Error('Skills record exceeds its storage limit.'), { status: 413, code: 'storage_limit' });
|
|
16
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
17
|
+
replaceFileAtomic(canonicalInside(dir, path), text, { mode: 0o600 });
|
|
18
|
+
return value;
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
// ── From the old prompt and command bridges to native skill folders ──
|
|
2
|
+
// SynaBun used to give Codex a custom prompt (~/.codex/prompts/<name>.md, a pointer back to the bundled skill)
|
|
3
|
+
// and OpenCode a command (~/.config/opencode/command/<name>.md, the skill's text with a banner). Both runtimes now
|
|
4
|
+
// read real skill folders (verified with codex-cli 0.163.0 and opencode 2.0.32), so a bridge moves to a native
|
|
5
|
+
// install of the same skill (owner decision, 2026-10-22). The move is:
|
|
6
|
+
//
|
|
7
|
+
// - owned first: a bridge moves by itself only when the install ledger recorded exactly these bytes, they are
|
|
8
|
+
// exactly what SynaBun writes for that bundled skill today, or exactly what an earlier SynaBun version wrote for
|
|
9
|
+
// that runtime and skill from this install's folder (`ledger`, `generated-current`, `generated-previous`: the
|
|
10
|
+
// shipped list of earlier generations, lib/skills/known-bridges.js). One that only carries the bridge's own
|
|
11
|
+
// signature banner (`generated-signature`: SynaBun's wording, but edited since, or bytes no list knows) is offered
|
|
12
|
+
// like any unproven file of a shipped skill, and moves only when the owner confirms its exact bytes (`confirm`).
|
|
13
|
+
// A file without any of that is not SynaBun's: it is listed and left alone.
|
|
14
|
+
// - native before anything is removed: the skill is installed into the runtime's skills folder through
|
|
15
|
+
// lib/skills/deploy.js (plan, digest, backup of anything there) and checked by digest;
|
|
16
|
+
// - backup-first: the bridge's exact bytes are copied into the migration's journal folder and read back before
|
|
17
|
+
// the bridge is taken out of the runtime's folder (removed only while it still is those bytes);
|
|
18
|
+
// - journaled: DATA_HOME/data/skills/migrations/<journalId>/journal.json lists every step and its outcome, and
|
|
19
|
+
// the install ledger's journal gets a line per bridge;
|
|
20
|
+
// - idempotent: a bridge already moved is gone from the plan; running the plan again changes nothing;
|
|
21
|
+
// - reversible: revert(journalId) puts every bridge back where it was (only into a free place) and rolls back
|
|
22
|
+
// each native install the migration made (only while it still holds what was installed).
|
|
23
|
+
//
|
|
24
|
+
// When it runs (owner decision 2026-10-22: switch to native folders with backups, and 2026-10-23: by itself): once at
|
|
25
|
+
// every server start, `autoMigrate()` moves the bridges that are proven SynaBun's (and only those), journaled and
|
|
26
|
+
// reversible as above, and leaves a one-time notice (`notice()`) the Studio shows with Undo. A bridge that is not
|
|
27
|
+
// proven SynaBun's is never moved by itself: the plan lists it with `offer` when SynaBun ships a skill of its name,
|
|
28
|
+
// and the owner may move it from the Studio or Settings by confirming its exact bytes (`confirm[bridgeId] =
|
|
29
|
+
// digest`). Undoing an automatic move pauses the automatic run (`autoPaused`) until the owner moves by hand again,
|
|
30
|
+
// so a move the owner took back never comes back by itself. The routes are the owner's, from the app's own page
|
|
31
|
+
// (POST /api/skills-studio/v2/migrations/bridges with the plan's digest); the server runs only `autoMigrate`.
|
|
32
|
+
|
|
33
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
34
|
+
import { lstatSync, mkdirSync, readdirSync, realpathSync, unlinkSync } from 'node:fs';
|
|
35
|
+
import { tmpdir } from 'node:os';
|
|
36
|
+
import { dirname, join, resolve, sep } from 'node:path';
|
|
37
|
+
import { PathConfineError } from '../path-confine.js';
|
|
38
|
+
import { readConfinedFile, replaceFileAtomic, writeConfinedFile } from '../confined-fs.js';
|
|
39
|
+
import { fileEntry, manifestDigest, sha256 } from './digest.js';
|
|
40
|
+
import { digestOf } from './library.js';
|
|
41
|
+
import { matchPreviousBridge } from './known-bridges.js';
|
|
42
|
+
|
|
43
|
+
export const MIGRATION_SCHEMA = 1;
|
|
44
|
+
const JOURNAL_RE = /^mig_[0-9a-f]{20}$/;
|
|
45
|
+
const BRIDGE_MAX_BYTES = 2 * 1024 * 1024;
|
|
46
|
+
const AUTO_STATE = 'auto-state.json';
|
|
47
|
+
|
|
48
|
+
export class MigrationError extends PathConfineError {
|
|
49
|
+
constructor(status, message, code, extra = {}) {
|
|
50
|
+
super(status, message);
|
|
51
|
+
this.code = code;
|
|
52
|
+
Object.assign(this, extra);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// The text SynaBun's bridges carried (lib/skill-prompt-bridge.js and server.js buildCliSkillPrompt): the Codex pointer
|
|
57
|
+
// (since 2026-07-13) and the OpenCode banner. Codex bridges written before 2026-07-13 were the OpenCode text with an
|
|
58
|
+
// invocation note: no Codex signature, so only the list of earlier generations (proof generated-previous) knows them.
|
|
59
|
+
const CODEX_SIGNATURE = /\n# SynaBun Skill Bridge\n\nRead `([^`\n]+)` with the local file tools and follow it exactly\./;
|
|
60
|
+
const OPENCODE_SIGNATURE = /\n> SynaBun skill bridge — full instructions live in the bundled SynaBun repo at\n> ([^\n]+)\. Load any referenced module files using your runtime's file-read tool\.\n/;
|
|
61
|
+
|
|
62
|
+
/** What a file says about being one of SynaBun's bridges: `{ runtime, skill, pointsTo }`, or null. */
|
|
63
|
+
export function bridgeSignature(text, { name, family }) {
|
|
64
|
+
const s = String(text || '');
|
|
65
|
+
if (family === 'codex') {
|
|
66
|
+
const m = CODEX_SIGNATURE.exec(s);
|
|
67
|
+
if (!m) return null;
|
|
68
|
+
const pointsTo = m[1];
|
|
69
|
+
const skill = /([^\\/]+)[\\/]SKILL\.md$/.exec(pointsTo)?.[1] || null;
|
|
70
|
+
return skill === name ? { runtime: 'codex', skill, pointsTo } : null;
|
|
71
|
+
}
|
|
72
|
+
if (family === 'opencode') {
|
|
73
|
+
const m = OPENCODE_SIGNATURE.exec(s);
|
|
74
|
+
if (!m) return null;
|
|
75
|
+
const pointsTo = m[1];
|
|
76
|
+
const skill = /([^\\/]+)$/.exec(pointsTo)?.[1] || null;
|
|
77
|
+
return skill === name ? { runtime: 'opencode', skill, pointsTo } : null;
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @param {object} o
|
|
84
|
+
* @param {string} o.dataDir DATA_HOME/data/skills
|
|
85
|
+
* @param {object} o.roots lib/skills/roots.js resolver
|
|
86
|
+
* @param {object} o.ownership lib/skills/ownership.js installer
|
|
87
|
+
* @param {object} o.deployer lib/skills/deploy.js
|
|
88
|
+
* @param {(name: string) => object|null} o.bundledRevision the library revision of a bundled skill (its upstream)
|
|
89
|
+
* @param {(name: string, runtime: string) => string|null} [o.currentBridge] what SynaBun's bridge for it would be today
|
|
90
|
+
* @param {(name: string) => string|null} [o.bundledSkillDir] the bundled skill's folder as the generator wrote it into
|
|
91
|
+
* a bridge; by default read from today's bridges (OpenCode's banner names it, Codex's pointer its SKILL.md)
|
|
92
|
+
* @param {Map<string, object[]>} [o.knownBridges] the earlier generations (lib/skills/known-bridges.js readKnownBridges);
|
|
93
|
+
* by default the shipped list
|
|
94
|
+
*/
|
|
95
|
+
export function createBridgeMigration({ dataDir, roots, ownership, deployer, bundledRevision, currentBridge = () => null, bundledSkillDir = null, knownBridges = undefined, emit = () => {}, now = () => new Date().toISOString(), newId = () => `mig_${randomBytes(10).toString('hex')}` }) {
|
|
96
|
+
const home = join(dataDir, 'migrations');
|
|
97
|
+
|
|
98
|
+
/** The bundled folder of a skill as its bridges name it, or null (then no earlier generation can be proven). */
|
|
99
|
+
function skillDirOf(name) {
|
|
100
|
+
const safe = (fn) => { try { return fn(); } catch { return null; } };
|
|
101
|
+
if (bundledSkillDir) { const dir = safe(() => bundledSkillDir(name)); return typeof dir === 'string' && dir ? dir : null; }
|
|
102
|
+
const oc = safe(() => currentBridge(name, 'opencode'));
|
|
103
|
+
const banner = typeof oc === 'string' ? bridgeSignature(oc, { name, family: 'opencode' }) : null;
|
|
104
|
+
if (banner) return banner.pointsTo;
|
|
105
|
+
const cx = safe(() => currentBridge(name, 'codex'));
|
|
106
|
+
const pointer = typeof cx === 'string' ? bridgeSignature(cx, { name, family: 'codex' }) : null;
|
|
107
|
+
// join(folder, 'SKILL.md'): the folder is the pointer without its last separator and file name.
|
|
108
|
+
if (pointer && /[\\/]SKILL\.md$/.test(pointer.pointsTo)) return pointer.pointsTo.slice(0, -'/SKILL.md'.length);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Every old bridge in the runtimes' folders, with its proof of being SynaBun's. */
|
|
113
|
+
function findBridges() {
|
|
114
|
+
const out = [];
|
|
115
|
+
const seen = new Set();
|
|
116
|
+
const dirs = new Map();
|
|
117
|
+
const dirOf = (name) => { if (!dirs.has(name)) dirs.set(name, skillDirOf(name)); return dirs.get(name); };
|
|
118
|
+
// Exactly the bytes an earlier SynaBun version wrote for this runtime and skill, from this install's folder.
|
|
119
|
+
const earlierGeneration = (bytes, name, runtime) => {
|
|
120
|
+
const dir = dirOf(name);
|
|
121
|
+
return dir ? matchPreviousBridge(bytes, { runtime, name, skillDir: dir, ...(knownBridges ? { known: knownBridges } : {}) }) : null;
|
|
122
|
+
};
|
|
123
|
+
for (const root of roots.listRoots()) {
|
|
124
|
+
if (root.sourceKind !== 'legacy-bridge' || root.status !== 'ok') continue;
|
|
125
|
+
const where = root.resolvedPath || root.path;
|
|
126
|
+
if (seen.has(where)) continue; // an account's prompts/ that links to Default's is one folder
|
|
127
|
+
seen.add(where);
|
|
128
|
+
let names = [];
|
|
129
|
+
try { names = readdirSync(where).filter((n) => /\.md$/i.test(n) && !n.startsWith('.')).sort(); } catch { continue; }
|
|
130
|
+
for (const file of names.slice(0, 500)) {
|
|
131
|
+
const path = join(root.path, file);
|
|
132
|
+
const name = file.replace(/\.md$/i, '');
|
|
133
|
+
let st;
|
|
134
|
+
try { st = lstatSync(path); } catch { continue; }
|
|
135
|
+
const bridgeId = `brg_${createHash('sha256').update(resolve(path)).digest('hex').slice(0, 20)}`;
|
|
136
|
+
const row = { bridgeId, runtime: root.family, rootId: root.rootId, accountId: root.accountId || 'default', path, name, kind: st.isSymbolicLink() ? 'link' : (st.isFile() ? 'file' : 'other') };
|
|
137
|
+
if (row.kind !== 'file') { out.push({ ...row, proof: 'none', digest: null, why: 'Not a regular file: left as it is.' }); continue; }
|
|
138
|
+
let bytes;
|
|
139
|
+
try { bytes = readConfinedFile(root.path, path, { maxBytes: BRIDGE_MAX_BYTES }); } catch (err) { out.push({ ...row, proof: 'none', digest: null, why: `Cannot be read (${err?.message || err}).` }); continue; }
|
|
140
|
+
const digest = sha256(bytes);
|
|
141
|
+
const text = bytes.toString('utf-8');
|
|
142
|
+
const record = ownership.recordFor(path);
|
|
143
|
+
const ledgerOwned = !!record && record.digest === digestManifest(bytes, (st.mode & 0o111) !== 0);
|
|
144
|
+
const today = (() => { try { return currentBridge(name, root.family); } catch { return null; } })();
|
|
145
|
+
const signature = bridgeSignature(text, { name, family: root.family });
|
|
146
|
+
let proof = 'none';
|
|
147
|
+
let previous = null;
|
|
148
|
+
if (ledgerOwned) proof = 'ledger';
|
|
149
|
+
else if (today !== null && today === text) proof = 'generated-current';
|
|
150
|
+
else if ((previous = earlierGeneration(bytes, name, root.family))) proof = 'generated-previous';
|
|
151
|
+
else if (signature) proof = 'generated-signature';
|
|
152
|
+
out.push({ ...row, digest, size: bytes.length, proof, signature, ...(previous ? { previous: { since: previous.firstDate || null, firstCommit: previous.firstCommit || null } } : {}), ledgerRecord: !!record, why: proof === 'none' ? (record ? 'SynaBun installed a bridge here, but it was changed since: left as it is.' : 'Not one of SynaBun\'s bridges: left as it is.') : '' });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* What a migration would do, bridge by bridge, with the native install plan of each. A bridge that is not proven
|
|
160
|
+
* SynaBun's is left (`action: 'leave'`) and, when SynaBun ships a skill of its name, offered (`offer: { digest }`):
|
|
161
|
+
* `confirm[bridgeId] === digest` is the owner's word for exactly those bytes, and the step then moves (proof
|
|
162
|
+
* `owner-confirmed`). The plan's digest covers the proofs, so a confirmation is part of what a move is taken by.
|
|
163
|
+
* @param {{ confirm?: Record<string, string> }} [o]
|
|
164
|
+
*/
|
|
165
|
+
async function plan({ confirm = {} } = {}) {
|
|
166
|
+
const bridges = findBridges();
|
|
167
|
+
const steps = [];
|
|
168
|
+
for (const b of bridges) {
|
|
169
|
+
const step = { ...b, action: 'skip', native: null, offer: null };
|
|
170
|
+
// By itself only on exact bytes (the ledger's, today's generation, or an earlier version's). A signature-only
|
|
171
|
+
// bridge (edited since, or bytes no list knows) and any other file of a shipped skill wait for the owner's word.
|
|
172
|
+
if (b.proof === 'none' || b.proof === 'generated-signature') {
|
|
173
|
+
const shipped = b.kind === 'file' && b.digest ? bundledRevision(b.name) : null;
|
|
174
|
+
if (shipped) step.offer = { digest: b.digest, revisionId: shipped.revisionId, signature: b.proof === 'generated-signature' };
|
|
175
|
+
if (shipped && confirm && typeof confirm === 'object' && confirm[b.bridgeId] === b.digest) step.proof = 'owner-confirmed';
|
|
176
|
+
else { step.action = 'leave'; if (b.proof === 'generated-signature' && !step.why) step.why = 'It has SynaBun\'s bridge wording but not the bytes SynaBun writes today (edited, or an older version): moved only when you confirm it.'; steps.push(step); continue; }
|
|
177
|
+
}
|
|
178
|
+
const revision = bundledRevision(b.name);
|
|
179
|
+
if (!revision) { step.action = 'leave'; step.why = `SynaBun no longer ships a "${b.name}" skill to install in its place: left as it is.`; steps.push(step); continue; }
|
|
180
|
+
const target = { runtime: b.runtime, scope: 'user', accountId: b.runtime === 'codex' ? b.accountId : 'default' };
|
|
181
|
+
try {
|
|
182
|
+
const p = await deployer.plan({ revisionId: revision.revisionId, targets: [target] });
|
|
183
|
+
const t = p.targets[0];
|
|
184
|
+
step.native = { revisionId: revision.revisionId, planDigest: p.planDigest, target, destination: t.destination, state: t.destinationState?.state || null, blocked: t.blocked, needs: t.needs, ready: t.ready, artifactDigest: t.export?.artifactDigest || null };
|
|
185
|
+
if (t.blocked.length) { step.action = 'blocked'; step.why = t.blocked.map((x) => x.message).join(' '); }
|
|
186
|
+
else if (t.needs.some((n) => n.code === 'confirm_replace')) { step.action = 'blocked'; step.why = `A "${b.name}" skill folder that SynaBun did not install is already there (${t.destination}): resolve it first; the bridge is left as it is.`; }
|
|
187
|
+
else step.action = 'migrate';
|
|
188
|
+
} catch (err) { step.action = 'blocked'; step.why = err?.message || String(err); }
|
|
189
|
+
steps.push(step);
|
|
190
|
+
}
|
|
191
|
+
const subject = steps.map((s) => [s.bridgeId, s.path, s.digest, s.proof, s.action, s.native?.planDigest || null]);
|
|
192
|
+
return { steps, planDigest: digestOf(subject), counts: { migrate: steps.filter((s) => s.action === 'migrate').length, leave: steps.filter((s) => s.action === 'leave').length, blocked: steps.filter((s) => s.action === 'blocked').length, offered: steps.filter((s) => s.action === 'leave' && s.offer).length }, createdAt: now() };
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ── The automatic run and its notice ──
|
|
196
|
+
|
|
197
|
+
function readAutoState() {
|
|
198
|
+
try { return { autoPaused: false, lastAuto: null, noticeDismissedAt: null, ...JSON.parse(readConfinedFile(home, join(home, AUTO_STATE), { maxBytes: 1024 * 1024, encoding: 'utf-8' })) }; } catch { return { autoPaused: false, lastAuto: null, noticeDismissedAt: null }; }
|
|
199
|
+
}
|
|
200
|
+
function writeAutoState(state) {
|
|
201
|
+
mkdirSync(home, { recursive: true, mode: 0o700 });
|
|
202
|
+
replaceFileAtomic(join(home, AUTO_STATE), `${JSON.stringify({ schemaVersion: 1, ...state, updatedAt: now() }, null, 2)}\n`, { mode: 0o600 });
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* The server's one run at start: move what is proven SynaBun's, if anything, and leave the notice. Nothing moves
|
|
207
|
+
* while the owner's undo of an earlier automatic move stands (`autoPaused`). Never throws.
|
|
208
|
+
* @returns {Promise<{ ran: boolean, reason?: string, result?: object, plan?: object }>}
|
|
209
|
+
*/
|
|
210
|
+
async function autoMigrate() {
|
|
211
|
+
const state = readAutoState();
|
|
212
|
+
if (state.autoPaused) return { ran: false, reason: 'paused' };
|
|
213
|
+
let fresh;
|
|
214
|
+
try { fresh = await plan(); } catch (err) { return { ran: false, reason: 'plan-failed', error: err?.message || String(err) }; }
|
|
215
|
+
if (!fresh.counts.migrate) return { ran: false, reason: 'nothing', plan: fresh };
|
|
216
|
+
let result;
|
|
217
|
+
try { result = await migrate({ planDigest: fresh.planDigest, principal: { kind: 'system' }, auto: true }); } catch (err) { return { ran: false, reason: 'failed', error: err?.message || String(err), plan: fresh }; }
|
|
218
|
+
let noticeError = null;
|
|
219
|
+
if (result.journalId) {
|
|
220
|
+
// The move stands whatever happens to the notice: a notice that cannot be written is said, never thrown.
|
|
221
|
+
try {
|
|
222
|
+
writeAutoState({ ...state, lastAuto: { journalId: result.journalId, at: now(), status: result.status, migrated: result.results.filter((r) => r.outcome === 'migrated').map((r) => ({ runtime: r.runtime, name: r.name, path: r.path, destination: r.destination, proof: r.proof })), notMoved: result.results.filter((r) => r.outcome !== 'migrated').map((r) => ({ runtime: r.runtime, name: r.name, path: r.path, outcome: r.outcome, error: r.error || null })) }, noticeDismissedAt: null });
|
|
223
|
+
} catch (err) { noticeError = err?.message || String(err); }
|
|
224
|
+
}
|
|
225
|
+
return { ran: true, result, plan: fresh, ...(noticeError ? { noticeError } : {}) };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* What the Studio shows once: the last automatic move while it stands (not undone, not dismissed), the bridges
|
|
230
|
+
* left behind that the owner may move by confirming them (`offers`, with the plan digest a confirmed move is
|
|
231
|
+
* taken by), and whether the automatic run is paused by an undo.
|
|
232
|
+
*/
|
|
233
|
+
async function notice() {
|
|
234
|
+
const state = readAutoState();
|
|
235
|
+
let pending = null;
|
|
236
|
+
if (state.lastAuto && !state.noticeDismissedAt) {
|
|
237
|
+
let journal = null;
|
|
238
|
+
try { journal = readJournal(state.lastAuto.journalId); } catch { journal = null; }
|
|
239
|
+
if (journal && !['reverted', 'partially-reverted'].includes(journal.status)) pending = { ...state.lastAuto, status: journal.status };
|
|
240
|
+
}
|
|
241
|
+
let offers = [];
|
|
242
|
+
let planDigest = null;
|
|
243
|
+
let left = 0;
|
|
244
|
+
try {
|
|
245
|
+
const fresh = await plan();
|
|
246
|
+
planDigest = fresh.planDigest;
|
|
247
|
+
offers = fresh.steps.filter((s) => s.action === 'leave' && s.offer).map((s) => ({ bridgeId: s.bridgeId, runtime: s.runtime, name: s.name, path: s.path, digest: s.offer.digest, why: s.why || '' }));
|
|
248
|
+
left = fresh.steps.filter((s) => s.action === 'leave' && !s.offer).length;
|
|
249
|
+
} catch { /* no offers: the plan could not be made */ }
|
|
250
|
+
return { pending, offers, planDigest, left, autoPaused: !!state.autoPaused };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** The owner read the notice: it is not shown again (the journal stays, Undo stays in Settings). */
|
|
254
|
+
function dismissNotice() {
|
|
255
|
+
const state = readAutoState();
|
|
256
|
+
writeAutoState({ ...state, noticeDismissedAt: now() });
|
|
257
|
+
return { ok: true };
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function journalDir(id) {
|
|
261
|
+
if (typeof id !== 'string' || !JOURNAL_RE.test(id)) throw new MigrationError(400, 'Not a migration id.', 'invalid_journal');
|
|
262
|
+
return join(home, id);
|
|
263
|
+
}
|
|
264
|
+
function readJournal(id) {
|
|
265
|
+
const dir = journalDir(id);
|
|
266
|
+
try { return JSON.parse(readConfinedFile(dir, join(dir, 'journal.json'), { maxBytes: 8 * 1024 * 1024, encoding: 'utf-8' })); } catch {
|
|
267
|
+
throw new MigrationError(404, 'There is no such migration.', 'journal_not_found');
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function writeJournal(j) {
|
|
271
|
+
const dir = journalDir(j.journalId);
|
|
272
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
273
|
+
j.updatedAt = now();
|
|
274
|
+
replaceFileAtomic(join(dir, 'journal.json'), `${JSON.stringify(j, null, 2)}\n`, { mode: 0o600 });
|
|
275
|
+
}
|
|
276
|
+
function listJournals() {
|
|
277
|
+
let names = [];
|
|
278
|
+
try { names = readdirSync(home).filter((n) => JOURNAL_RE.test(n)).sort(); } catch { names = []; }
|
|
279
|
+
return names.map((n) => { try { return readJournal(n); } catch { return null; } }).filter(Boolean).map((j) => ({ journalId: j.journalId, createdAt: j.createdAt, status: j.status, steps: j.steps.length, migrated: j.steps.filter((s) => s.bridgeRemoved).length }));
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Move every bridge the plan marks `migrate`. `planDigest` must be the plan's: anything that changed since
|
|
284
|
+
* (a file, a proof, a destination) makes it 409 with the new plan, and nothing happens.
|
|
285
|
+
*/
|
|
286
|
+
async function migrate({ planDigest, confirm = {}, principal = { kind: 'owner' }, auto = false }) {
|
|
287
|
+
const fresh = await plan({ confirm });
|
|
288
|
+
if (typeof planDigest !== 'string' || planDigest !== fresh.planDigest) throw new MigrationError(409, 'The bridges or their destinations changed since the plan was shown. Nothing was moved; look at the new plan.', 'plan_changed', { plan: fresh });
|
|
289
|
+
const todo = fresh.steps.filter((s) => s.action === 'migrate');
|
|
290
|
+
if (!todo.length) return { ok: true, journalId: null, results: [], plan: fresh, nothingToDo: true };
|
|
291
|
+
// A move the owner asks for by hand lifts the pause an undo of an automatic move left.
|
|
292
|
+
if (!auto) { const state = readAutoState(); if (state.autoPaused) writeAutoState({ ...state, autoPaused: false, pausedBy: null }); }
|
|
293
|
+
const journal = { schemaVersion: MIGRATION_SCHEMA, journalId: newId(), createdAt: now(), status: 'running', by: principal?.kind || 'owner', auto: !!auto, planDigest, steps: [], events: [] };
|
|
294
|
+
if (!JOURNAL_RE.test(journal.journalId)) throw new MigrationError(500, 'Bad migration id.', 'bad_id');
|
|
295
|
+
writeJournal(journal);
|
|
296
|
+
const event = (text) => { journal.events.push({ at: now(), text }); };
|
|
297
|
+
for (const s of todo) {
|
|
298
|
+
const step = { bridgeId: s.bridgeId, runtime: s.runtime, path: s.path, name: s.name, digest: s.digest, proof: s.proof, revisionId: s.native.revisionId, destination: s.native.destination, installationId: null, nativeCommitted: false, nativeWasThere: s.native.state === 'identical' || s.native.state === 'owned', bridgeBackup: null, bridgeRemoved: false, outcome: 'pending' };
|
|
299
|
+
journal.steps.push(step);
|
|
300
|
+
writeJournal(journal);
|
|
301
|
+
try {
|
|
302
|
+
// 1. The native folder, first.
|
|
303
|
+
const result = await deployer.install({ revisionId: s.native.revisionId, targets: [s.native.target], planDigest: s.native.planDigest, principal, migration: { journalId: journal.journalId, bridgeId: s.bridgeId } });
|
|
304
|
+
const r = result.results[0];
|
|
305
|
+
if (r.status !== 'committed') { step.outcome = 'native-not-installed'; step.error = r.error || (r.reasons || []).map((x) => x.message).join(' '); event(`${s.path}: the native skill was not installed; the bridge stays.`); writeJournal(journal); continue; }
|
|
306
|
+
step.installationId = r.installationId;
|
|
307
|
+
step.nativeCommitted = true;
|
|
308
|
+
event(`${s.path}: installed ${s.name} at ${r.destination}.`);
|
|
309
|
+
writeJournal(journal);
|
|
310
|
+
// 2. The bridge's bytes, kept and read back.
|
|
311
|
+
const dir = journalDir(journal.journalId);
|
|
312
|
+
const keep = join(dir, 'bridges', `${s.bridgeId}.md`);
|
|
313
|
+
const bytes = readConfinedFile(dirname(s.path), s.path, { maxBytes: BRIDGE_MAX_BYTES });
|
|
314
|
+
if (sha256(bytes) !== s.digest) { step.outcome = 'bridge-changed'; event(`${s.path}: changed since the plan; left in place.`); writeJournal(journal); continue; }
|
|
315
|
+
const st = lstatSync(s.path);
|
|
316
|
+
writeConfinedFile(dir, keep, bytes, { exclusive: true, mode: 0o600 });
|
|
317
|
+
if (sha256(readConfinedFile(dir, keep, { maxBytes: BRIDGE_MAX_BYTES })) !== s.digest) throw new MigrationError(500, 'The bridge\'s copy does not read back.', 'backup_failed');
|
|
318
|
+
step.bridgeBackup = `bridges/${s.bridgeId}.md`;
|
|
319
|
+
step.bridgeMode = st.mode & 0o777;
|
|
320
|
+
writeJournal(journal);
|
|
321
|
+
// 3. Out of the runtime's folder, while it still is those bytes.
|
|
322
|
+
const again = lstatSync(s.path);
|
|
323
|
+
const now2 = readConfinedFile(dirname(s.path), s.path, { maxBytes: BRIDGE_MAX_BYTES });
|
|
324
|
+
if (again.ino !== st.ino || sha256(now2) !== s.digest) { step.outcome = 'bridge-changed'; event(`${s.path}: changed while it was moved; left in place.`); writeJournal(journal); continue; }
|
|
325
|
+
// The intent first: a crash between the removal and its record would otherwise leave a bridge gone that an
|
|
326
|
+
// undo believes was never removed (revert restores from the kept copy whenever the file is missing).
|
|
327
|
+
step.removing = true;
|
|
328
|
+
writeJournal(journal);
|
|
329
|
+
unlinkSync(s.path);
|
|
330
|
+
step.bridgeRemoved = true;
|
|
331
|
+
step.outcome = 'migrated';
|
|
332
|
+
ownership.forget({ destination: s.path, target: s.runtime, name: s.name, reason: `bridge moved to ${s.native.destination} (${journal.journalId})` });
|
|
333
|
+
ownership.note({ action: 'migrate-bridge', target: s.runtime, name: s.name, destination: resolve(s.path), result: 'moved', digest: s.digest, journalId: journal.journalId, installationId: step.installationId });
|
|
334
|
+
event(`${s.path}: moved out (kept in the journal).`);
|
|
335
|
+
writeJournal(journal);
|
|
336
|
+
} catch (err) {
|
|
337
|
+
step.outcome = 'failed';
|
|
338
|
+
step.error = err?.message || String(err);
|
|
339
|
+
event(`${s.path}: ${step.error}`);
|
|
340
|
+
writeJournal(journal);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
journal.status = journal.steps.every((x) => x.outcome === 'migrated') ? 'done' : (journal.steps.some((x) => x.outcome === 'migrated') ? 'partial' : 'failed');
|
|
344
|
+
writeJournal(journal);
|
|
345
|
+
emit({ type: 'migration.changed', journalId: journal.journalId });
|
|
346
|
+
return { ok: journal.status === 'done', journalId: journal.journalId, status: journal.status, results: journal.steps, plan: fresh };
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** Undo a migration: bridges back where they were (only into a free place), native installs rolled back. */
|
|
350
|
+
async function revert(journalId, { principal = { kind: 'owner' } } = {}) {
|
|
351
|
+
const journal = readJournal(journalId);
|
|
352
|
+
if (journal.status === 'reverted') return { ok: true, journalId, status: 'reverted', results: journal.steps, already: true };
|
|
353
|
+
const dir = journalDir(journalId);
|
|
354
|
+
const results = [];
|
|
355
|
+
for (const step of [...journal.steps].reverse()) {
|
|
356
|
+
const out = { bridgeId: step.bridgeId, path: step.path, bridge: 'untouched', native: 'untouched' };
|
|
357
|
+
if ((step.bridgeRemoved || step.removing) && step.bridgeBackup && !step.bridgeRestored) {
|
|
358
|
+
try {
|
|
359
|
+
const bytes = readConfinedFile(dir, join(dir, step.bridgeBackup), { maxBytes: BRIDGE_MAX_BYTES });
|
|
360
|
+
if (sha256(bytes) !== step.digest) throw new MigrationError(500, 'The kept copy does not match.', 'backup_corrupt');
|
|
361
|
+
let present = true;
|
|
362
|
+
try { lstatSync(step.path); } catch { present = false; }
|
|
363
|
+
// Present and never recorded as removed: the move stopped before the removal; nothing to put back.
|
|
364
|
+
if (present && !step.bridgeRemoved) { out.bridge = 'untouched'; }
|
|
365
|
+
else if (present) { out.bridge = 'conflict'; out.why = `${step.path} exists again: the kept bridge was not put over it (it stays in ${join(dir, step.bridgeBackup)}).`; }
|
|
366
|
+
else {
|
|
367
|
+
mkdirSync(dirname(step.path), { recursive: true });
|
|
368
|
+
writeConfinedFile(dirname(step.path), step.path, bytes, { exclusive: true, mode: step.bridgeMode || 0o644 });
|
|
369
|
+
step.bridgeRestored = true;
|
|
370
|
+
out.bridge = 'restored';
|
|
371
|
+
ownership.recordWrite({ target: step.runtime, name: step.name, destination: step.path, digest: digestManifest(bytes, ((step.bridgeMode || 0) & 0o111) !== 0), kind: 'file', source: { kind: 'bridge-restore', journalId } });
|
|
372
|
+
}
|
|
373
|
+
} catch (err) { out.bridge = 'failed'; out.why = err?.message || String(err); }
|
|
374
|
+
}
|
|
375
|
+
// The native install this move made is rolled back whatever was there before: a folder of an older SynaBun
|
|
376
|
+
// install comes back from its backup (and its installation is the one in place again); one that already held
|
|
377
|
+
// these bytes is left as it is (deploy.js rollback changes no file for an install that wrote nothing).
|
|
378
|
+
if (step.nativeCommitted && step.installationId && !step.nativeRolledBack) {
|
|
379
|
+
try {
|
|
380
|
+
deployer.rollback(step.installationId, { principal });
|
|
381
|
+
step.nativeRolledBack = true;
|
|
382
|
+
out.native = 'rolled-back';
|
|
383
|
+
} catch (err) { out.native = 'kept'; out.why = `${out.why ? `${out.why} ` : ''}The native skill was left in place: ${err?.message || err}`; }
|
|
384
|
+
}
|
|
385
|
+
results.push(out);
|
|
386
|
+
}
|
|
387
|
+
const clean = results.every((r) => r.bridge !== 'conflict' && r.bridge !== 'failed' && r.native !== 'kept');
|
|
388
|
+
journal.status = clean ? 'reverted' : 'partially-reverted';
|
|
389
|
+
journal.events.push({ at: now(), text: `Reverted by ${principal?.kind || 'owner'}: ${clean ? 'everything is back' : 'some steps could not be undone'}.` });
|
|
390
|
+
writeJournal(journal);
|
|
391
|
+
// An automatic move the owner took back stays taken back: the next start moves nothing by itself.
|
|
392
|
+
if (journal.auto) { const state = readAutoState(); writeAutoState({ ...state, autoPaused: true, pausedBy: journalId }); }
|
|
393
|
+
ownership.note({ action: 'revert-migration', journalId, result: journal.status });
|
|
394
|
+
emit({ type: 'migration.changed', journalId });
|
|
395
|
+
return { ok: clean, journalId, status: journal.status, results };
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return { findBridges, plan, migrate, revert, autoMigrate, notice, dismissNotice, readJournal, listJournals, paths: { home } };
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/** The one-file manifest digest an install records for a bridge (lib/skills/ownership.js payloadFromText). */
|
|
402
|
+
function digestManifest(bytes, executable) {
|
|
403
|
+
return manifestDigest([fileEntry('.', bytes, { executable })]);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Whether the server may move the owner's bridges by itself at this start: never under a test run (NODE_TEST_CONTEXT,
|
|
408
|
+
* VITEST), never with the kill switch (SYNABUN_SKILLS_AUTO_MIGRATE=off|0), and never from a temporary data home, whatever
|
|
409
|
+
* HOME is: a dev or test boot with the real HOME and a data home under the system's temporary folders (os.tmpdir(),
|
|
410
|
+
* TMPDIR, /tmp, /private/tmp, /var/tmp, /var/folders and their /private twins) must not touch the owner's real
|
|
411
|
+
* folders. Paths are compared as real paths (macOS keeps /tmp and /var behind /private).
|
|
412
|
+
*/
|
|
413
|
+
export function autoMigrationAllowed({ env = process.env, dataHome = null, tmp = tmpdir() } = {}) {
|
|
414
|
+
if (env.SYNABUN_SKILLS_AUTO_MIGRATE === 'off' || env.SYNABUN_SKILLS_AUTO_MIGRATE === '0') return false;
|
|
415
|
+
if (env.NODE_TEST_CONTEXT || env.VITEST) return false;
|
|
416
|
+
if (!dataHome) return false;
|
|
417
|
+
const real = (p) => {
|
|
418
|
+
// A path that is not there yet (a data home about to be made): its nearest existing ancestor's real path, then the rest.
|
|
419
|
+
let head = resolve(String(p));
|
|
420
|
+
const tail = [];
|
|
421
|
+
for (;;) {
|
|
422
|
+
try { return tail.length ? join(realpathSync(head), ...tail) : realpathSync(head); } catch { /* not there: one up */ }
|
|
423
|
+
const parent = dirname(head);
|
|
424
|
+
if (parent === head) return resolve(String(p));
|
|
425
|
+
tail.unshift(head.slice(parent.length).replace(/^[\\/]/, ''));
|
|
426
|
+
head = parent;
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
const inside = (child, parent) => { const c = real(child); const p = real(parent); return c === p || c.startsWith(p.endsWith(sep) ? p : `${p}${sep}`); };
|
|
430
|
+
const roots = [tmp, env.TMPDIR, '/tmp', '/private/tmp', '/var/tmp', '/private/var/tmp', '/var/folders', '/private/var/folders'].filter(Boolean);
|
|
431
|
+
for (const root of roots) { try { if (inside(dataHome, root)) return false; } catch { /* a root that cannot be read is not the data home's */ } }
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { localRecord } from './local-store.js';
|
|
2
|
+
import { createSkillTelemetry } from './telemetry.js';
|
|
3
|
+
import { createSkillHealth } from './health.js';
|
|
4
|
+
import { createSkillDiscover, DISCOVER_SOURCES } from './discover.js';
|
|
5
|
+
import { createSkillPackages } from './packages.js';
|
|
6
|
+
import { createExternalScanners, EXTERNAL_SCANNERS } from './scanners.js';
|
|
7
|
+
import { isSkillId } from './library.js';
|
|
8
|
+
|
|
9
|
+
export const OPERATIONS_DEFAULTS = Object.freeze({ telemetryEnabled: true, retentionDays: 30, healthEnabled: false, cadenceHours: 24, sources: [], scanners: [], protectedSkillIds: [] });
|
|
10
|
+
|
|
11
|
+
export function attachSkillOperations(service, { dataDir, notify, request, adapters, now = Date.now }) {
|
|
12
|
+
const store = localRecord(dataDir, 'operations', OPERATIONS_DEFAULTS, 65536);
|
|
13
|
+
const settings = () => ({ ...OPERATIONS_DEFAULTS, ...store.read() });
|
|
14
|
+
function configure(patch) {
|
|
15
|
+
const next = settings();
|
|
16
|
+
const invalid = (message) => { throw Object.assign(new Error(message), { status: 400, code: 'invalid_config' }); };
|
|
17
|
+
if (!patch || Array.isArray(patch) || typeof patch !== 'object') invalid('Settings are an object.');
|
|
18
|
+
for (const key of Object.keys(patch)) if (!Object.hasOwn(OPERATIONS_DEFAULTS, key)) invalid(`Unknown setting: ${key}`);
|
|
19
|
+
for (const key of ['telemetryEnabled', 'healthEnabled']) if (patch[key] !== undefined) { if (typeof patch[key] !== 'boolean') invalid(`${key} is true or false.`); next[key] = patch[key]; }
|
|
20
|
+
for (const [key, min, max] of [['retentionDays', 1, 365], ['cadenceHours', 1, 168]]) if (patch[key] !== undefined) { if (!Number.isInteger(patch[key]) || patch[key] < min || patch[key] > max) invalid(`${key} is an integer from ${min} to ${max}.`); next[key] = patch[key]; }
|
|
21
|
+
for (const [key, allowed] of [['sources', DISCOVER_SOURCES.map((s) => s.id)], ['scanners', EXTERNAL_SCANNERS.map((s) => s.id)]]) if (patch[key] !== undefined) {
|
|
22
|
+
if (!Array.isArray(patch[key]) || !patch[key].every((id) => allowed.includes(id))) invalid(`${key} names known providers.`);
|
|
23
|
+
next[key] = [...new Set(patch[key])];
|
|
24
|
+
}
|
|
25
|
+
// Nothing with an unverified execution/disclosure contract can be enabled by guessing a CLI or API.
|
|
26
|
+
for (const id of next.scanners) if (!adapters?.[id]?.version || !adapters[id].isolated || adapters[id].outbound || typeof adapters[id].scan !== 'function') invalid(`The verified local ${id} adapter is unavailable. Hosted analysis remains off.`);
|
|
27
|
+
if (patch.protectedSkillIds !== undefined) { if (!Array.isArray(patch.protectedSkillIds) || patch.protectedSkillIds.length > 1000 || !patch.protectedSkillIds.every(isSkillId)) invalid('protectedSkillIds names library skills.'); next.protectedSkillIds = [...new Set(patch.protectedSkillIds)]; }
|
|
28
|
+
store.write(next); service.telemetry.prune();
|
|
29
|
+
service.announce({ type: 'operations.changed' });
|
|
30
|
+
return next;
|
|
31
|
+
}
|
|
32
|
+
service.telemetry = createSkillTelemetry({ dataDir, deployer: service.deployer, settings, now });
|
|
33
|
+
service.health = createSkillHealth({ dataDir, service, settings, notify, now });
|
|
34
|
+
service.discover = createSkillDiscover({ dataDir, service, settings, ...(request ? { request } : {}), liveRoots: () => service.roots().map((r) => r.path), now });
|
|
35
|
+
service.packages = createSkillPackages({ service });
|
|
36
|
+
service.scanners = createExternalScanners({ settings, adapters, dataDir });
|
|
37
|
+
service.library.setExternalEvidence((digest) => service.scanners.evidence(digest));
|
|
38
|
+
service.deployer.setExternalScanner((revision, folder) => service.scanners.scan(revision, folder));
|
|
39
|
+
service.operations = { settings, configure, proposals() {
|
|
40
|
+
// A conservative, typed triage fallback: repeated tool failures support an investigation, never an edit.
|
|
41
|
+
// No private trace mining, Jev call, model execution, grade or promotion is inferred from adoption.
|
|
42
|
+
return service.telemetry.summary().rows.filter((r) => r.failed >= 2).map((r) => ({ kind: 'investigate_failures', skillId: r.skillId, revisionId: r.revisionId, runtime: r.runtime, evidence: { failures: r.failed, lastAt: r.lastAt }, judgment: null, action: 'Review failures and run independent task/trigger evaluations before proposing a new revision.', protected: settings().protectedSkillIds.includes(r.skillId), automatic: false }));
|
|
43
|
+
} };
|
|
44
|
+
return service;
|
|
45
|
+
}
|