synabun 2.0.10 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +207 -0
- package/README.md +25 -2
- package/THIRD-PARTY-LICENSES.md +22 -0
- package/bin/synabun.js +71 -24
- package/docs/whatsapp.md +13 -13
- package/hooks/claude-code/pre-websearch.mjs +12 -1
- package/hooks/claude-code/shared.mjs +5 -0
- package/hooks/claude-code/stop.mjs +1 -1
- package/lib/claude-hooks.js +172 -18
- package/lib/client-config-repair.js +30 -17
- package/lib/desktop-app.js +7 -1
- package/lib/external-tools.js +7 -6
- package/lib/first-launch-protection.js +57 -12
- package/lib/mcp-dist.js +176 -0
- package/lib/release-npm-ci.mjs +138 -0
- package/lib/release-publish.mjs +91 -0
- package/lib/release-scan.mjs +50 -0
- package/lib/server-crash-record.js +123 -0
- package/lib/server-exit.js +318 -0
- package/lib/server-supervisor.js +508 -0
- package/lib/start-launcher.js +37 -4
- package/lib/tools-cli.js +45 -0
- package/lib/update-snapshot.js +302 -0
- package/lib/virustotal.mjs +203 -0
- package/lib/windows-crash-event.js +269 -0
- package/mcp-server/dist/http.d.ts +20 -1
- package/mcp-server/dist/http.d.ts.map +1 -1
- package/mcp-server/dist/http.js +59 -12
- package/mcp-server/dist/http.js.map +1 -1
- package/mcp-server/dist/index.d.ts +33 -27
- package/mcp-server/dist/index.d.ts.map +1 -1
- package/mcp-server/dist/index.js +128 -143
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/preload.js +1 -1
- package/mcp-server/dist/preload.js.map +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -1
- package/mcp-server/dist/services/budget-judgments.js +5 -3
- package/mcp-server/dist/services/budget-judgments.js.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.d.ts +6 -2
- package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.js +81 -28
- package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
- package/mcp-server/dist/services/identity.d.ts +2 -2
- package/mcp-server/dist/services/identity.js +2 -2
- package/mcp-server/dist/services/memory-judge-backfill.d.ts +6 -0
- package/mcp-server/dist/services/memory-judge-backfill.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-judge-backfill.js +7 -1
- package/mcp-server/dist/services/memory-judge-backfill.js.map +1 -1
- package/mcp-server/dist/services/memory-sessions.d.ts +1 -1
- package/mcp-server/dist/services/memory-sessions.d.ts.map +1 -1
- package/mcp-server/dist/services/memory-sessions.js +28 -2
- package/mcp-server/dist/services/memory-sessions.js.map +1 -1
- package/mcp-server/dist/services/neural-interface.d.ts +18 -11
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
- package/mcp-server/dist/services/neural-interface.js +67 -11
- package/mcp-server/dist/services/neural-interface.js.map +1 -1
- package/mcp-server/dist/services/server-instructions.d.ts +7 -2
- package/mcp-server/dist/services/server-instructions.d.ts.map +1 -1
- package/mcp-server/dist/services/server-instructions.js +22 -63
- package/mcp-server/dist/services/server-instructions.js.map +1 -1
- package/mcp-server/dist/services/tool-catalog.d.ts +120 -0
- package/mcp-server/dist/services/tool-catalog.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-catalog.js +339 -0
- package/mcp-server/dist/services/tool-catalog.js.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts +12 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js +40 -0
- package/mcp-server/dist/services/tool-list-refresh-barrier.js.map +1 -0
- package/mcp-server/dist/services/tool-list.d.ts +108 -0
- package/mcp-server/dist/services/tool-list.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-list.js +334 -0
- package/mcp-server/dist/services/tool-list.js.map +1 -0
- package/mcp-server/dist/services/tool-runtime.d.ts +161 -0
- package/mcp-server/dist/services/tool-runtime.d.ts.map +1 -0
- package/mcp-server/dist/services/tool-runtime.js +400 -0
- package/mcp-server/dist/services/tool-runtime.js.map +1 -0
- package/mcp-server/dist/services/typesafe-config.js +1 -1
- package/mcp-server/dist/services/typesafe-config.js.map +1 -1
- package/mcp-server/dist/services/whiteboard-geometry.d.ts +26 -2
- package/mcp-server/dist/services/whiteboard-geometry.d.ts.map +1 -1
- package/mcp-server/dist/services/whiteboard-geometry.js +91 -8
- package/mcp-server/dist/services/whiteboard-geometry.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +14 -14
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +29 -19
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/browser-batch.d.ts +3 -3
- package/mcp-server/dist/tools/choice.d.ts +6 -0
- package/mcp-server/dist/tools/choice.d.ts.map +1 -1
- package/mcp-server/dist/tools/choice.js +18 -13
- package/mcp-server/dist/tools/choice.js.map +1 -1
- package/mcp-server/dist/tools/git-tools.js +2 -2
- package/mcp-server/dist/tools/git-tools.js.map +1 -1
- package/mcp-server/dist/tools/image-tools.d.ts +1 -1
- package/mcp-server/dist/tools/image-tools.js +1 -1
- package/mcp-server/dist/tools/morelogin.d.ts.map +1 -1
- package/mcp-server/dist/tools/morelogin.js +9 -6
- package/mcp-server/dist/tools/morelogin.js.map +1 -1
- package/mcp-server/dist/tools/skill-tools.d.ts +505 -0
- package/mcp-server/dist/tools/skill-tools.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill-tools.js +642 -0
- package/mcp-server/dist/tools/skill-tools.js.map +1 -0
- package/mcp-server/dist/tools/skill.d.ts +7 -0
- package/mcp-server/dist/tools/skill.d.ts.map +1 -0
- package/mcp-server/dist/tools/skill.js +11 -0
- package/mcp-server/dist/tools/skill.js.map +1 -0
- package/mcp-server/dist/tools/tool-groups.d.ts +68 -0
- package/mcp-server/dist/tools/tool-groups.d.ts.map +1 -0
- package/mcp-server/dist/tools/tool-groups.js +147 -0
- package/mcp-server/dist/tools/tool-groups.js.map +1 -0
- package/mcp-server/dist/tools/whiteboard-format.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-format.js +7 -4
- package/mcp-server/dist/tools/whiteboard-format.js.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.d.ts +64 -13
- package/mcp-server/dist/tools/whiteboard-tools.d.ts.map +1 -1
- package/mcp-server/dist/tools/whiteboard-tools.js +30 -5
- package/mcp-server/dist/tools/whiteboard-tools.js.map +1 -1
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -1
- package/mcp-server/src/http.ts +75 -12
- package/mcp-server/src/index.ts +147 -154
- package/mcp-server/src/preload.ts +12 -12
- package/mcp-server/src/services/budget-judgments.ts +5 -3
- package/mcp-server/src/services/codex-config-heal.ts +80 -29
- package/mcp-server/src/services/identity.ts +2 -2
- package/mcp-server/src/services/memory-judge-backfill.ts +7 -1
- package/mcp-server/src/services/memory-sessions.ts +24 -3
- package/mcp-server/src/services/neural-interface.ts +81 -21
- package/mcp-server/src/services/server-instructions.ts +29 -64
- package/mcp-server/src/services/tool-catalog.ts +403 -0
- package/mcp-server/src/services/tool-list-refresh-barrier.ts +33 -0
- package/mcp-server/src/services/tool-list.ts +410 -0
- package/mcp-server/src/services/tool-runtime.ts +457 -0
- package/mcp-server/src/services/typesafe-config.ts +1 -1
- package/mcp-server/src/services/whiteboard-geometry.ts +94 -9
- package/mcp-server/src/tools/agents.ts +29 -20
- package/mcp-server/src/tools/choice.ts +17 -12
- package/mcp-server/src/tools/git-tools.ts +2 -2
- package/mcp-server/src/tools/image-tools.ts +1 -1
- package/mcp-server/src/tools/morelogin.ts +6 -4
- package/mcp-server/src/tools/skill-tools.ts +592 -0
- package/mcp-server/src/tools/skill.ts +13 -0
- package/mcp-server/src/tools/tool-groups.ts +164 -0
- package/mcp-server/src/tools/whiteboard-format.ts +9 -3
- package/mcp-server/src/tools/whiteboard-tools.ts +39 -5
- package/neural-interface/i18n/en.json +3953 -228
- package/neural-interface/i18n/pt-BR.json +3901 -179
- package/neural-interface/lib/agent-sandbox-elevation.js +6 -0
- package/neural-interface/lib/antigravity/acp-client-host.js +554 -0
- package/neural-interface/lib/antigravity/acp-connection.js +299 -0
- package/neural-interface/lib/antigravity/bypass.js +100 -0
- package/neural-interface/lib/antigravity/catalog.js +273 -0
- package/neural-interface/lib/antigravity/home.js +260 -0
- package/neural-interface/lib/antigravity/migrate-gemini.js +139 -0
- package/neural-interface/lib/antigravity/panel-bridge.js +1058 -0
- package/neural-interface/lib/antigravity/policy-hook.mjs +78 -0
- package/neural-interface/lib/antigravity/policy.js +74 -0
- package/neural-interface/lib/antigravity/tool-call.js +178 -0
- package/neural-interface/lib/antigravity/transcripts.js +252 -0
- package/neural-interface/lib/antigravity/usage.js +43 -0
- package/neural-interface/lib/assistant-api.js +128 -28
- package/neural-interface/lib/assistant-brains/antigravity.js +423 -0
- package/neural-interface/lib/assistant-brains/claude.js +4 -3
- package/neural-interface/lib/assistant-brains/codex-browser-policy-hook.mjs +12 -2
- package/neural-interface/lib/assistant-brains/codex-route-gate-hook.mjs +32 -9
- package/neural-interface/lib/assistant-brains/codex.js +9 -5
- package/neural-interface/lib/assistant-brains/opencode.js +120 -54
- package/neural-interface/lib/assistant-brains/opencode2-browser-policy/index.js +28 -13
- package/neural-interface/lib/assistant-brains/opencode2-route-gate/index.js +59 -19
- package/neural-interface/lib/assistant-budget-planner.js +7 -3
- package/neural-interface/lib/assistant-budget-split.js +42 -15
- package/neural-interface/lib/assistant-catalog.js +81 -15
- package/neural-interface/lib/assistant-config.js +6 -3
- package/neural-interface/lib/assistant-dispatch.js +1073 -200
- package/neural-interface/lib/assistant-envelope.js +156 -2
- package/neural-interface/lib/assistant-evidence.js +80 -0
- package/neural-interface/lib/assistant-hidden-models.js +7 -5
- package/neural-interface/lib/assistant-persona.js +93 -19
- package/neural-interface/lib/assistant-plan-permissions.js +25 -9
- package/neural-interface/lib/assistant-route-gate-codex.js +3 -0
- package/neural-interface/lib/assistant-route-gate.js +6 -4
- package/neural-interface/lib/assistant-router.js +245 -38
- package/neural-interface/lib/assistant-runtime.js +214 -30
- package/neural-interface/lib/assistant-task-prompt.js +87 -21
- package/neural-interface/lib/assistant-tools.js +51 -0
- package/neural-interface/lib/assistant-usage.js +29 -0
- package/neural-interface/lib/backup-service.js +626 -4
- package/neural-interface/lib/backup-zip-reader.js +10 -5
- package/neural-interface/lib/backup-zip-writer.js +257 -0
- package/neural-interface/lib/browser-execution.js +10 -2
- package/neural-interface/lib/browser-guard-cdp.js +84 -0
- package/neural-interface/lib/browser-network-guard.js +476 -0
- package/neural-interface/lib/browser-policy-roots.js +64 -0
- package/neural-interface/lib/browser-tool-policy.js +198 -38
- package/neural-interface/lib/claude-agent-bridge.js +11 -2
- package/neural-interface/lib/claude-history-cache.js +210 -0
- package/neural-interface/lib/claude-hooks-status.js +103 -0
- package/neural-interface/lib/claude-model-catalog.js +5 -1
- package/neural-interface/lib/claude-temporary.js +5 -11
- package/neural-interface/lib/cli-install-api.js +1 -1
- package/neural-interface/lib/cli-install.js +163 -154
- package/neural-interface/lib/cli-resolver.js +13 -3
- package/neural-interface/lib/cli-update-planner.js +52 -41
- package/neural-interface/lib/cloudflared/tunnel.js +42 -2
- package/neural-interface/lib/codex-mcp-approvals.js +11 -0
- package/neural-interface/lib/codex-rollout-reader.js +52 -0
- package/neural-interface/lib/codex-worker-app-server.js +191 -0
- package/neural-interface/lib/confined-fs.js +30 -3
- package/neural-interface/lib/crash-notice-api.js +98 -0
- package/neural-interface/lib/editor-completion-opencode.js +68 -68
- package/neural-interface/lib/editor-git-api.js +3 -20
- package/neural-interface/lib/exec-loop-command.js +13 -10
- package/neural-interface/lib/file-explorer-api.js +74 -40
- package/neural-interface/lib/file-explorer-watch.js +9 -3
- package/neural-interface/lib/git-bash/install.js +52 -6
- package/neural-interface/lib/git-bash/manager.js +59 -17
- package/neural-interface/lib/git-bash/pins.js +12 -0
- package/neural-interface/lib/git-read.js +2 -2
- package/neural-interface/lib/git-status-runner.js +390 -0
- package/neural-interface/lib/git-status-watchdog.js +40 -0
- package/neural-interface/lib/greeting/budgets.js +1 -0
- package/neural-interface/lib/greeting/engine.js +2 -2
- package/neural-interface/lib/greeting/sources.js +10 -12
- package/neural-interface/lib/greeting/writer.js +1 -1
- package/neural-interface/lib/http-guards.js +8 -2
- package/neural-interface/lib/install-details.js +4 -1
- package/neural-interface/lib/mcp-agent-servers.js +67 -0
- package/neural-interface/lib/mcp-client-config.js +35 -33
- package/neural-interface/lib/mcp-external-servers.js +332 -0
- package/neural-interface/lib/mcp-installer.js +2 -1
- package/neural-interface/lib/{mcp-profile-refresh-coordinator.js → mcp-tools-refresh-coordinator.js} +4 -4
- package/neural-interface/lib/memory-session-capture.js +17 -3
- package/neural-interface/lib/morelogin.js +177 -25
- package/neural-interface/lib/native-loop-providers.js +965 -66
- package/neural-interface/lib/native-loop-runtime.js +290 -42
- package/neural-interface/lib/opencode-config.js +557 -0
- package/neural-interface/lib/opencode-db-schema.js +17 -34
- package/neural-interface/lib/opencode-history.js +48 -218
- package/neural-interface/lib/opencode-mcp-ready.js +108 -0
- package/neural-interface/lib/opencode-native-boundary.js +53 -0
- package/neural-interface/lib/opencode-protocol.js +249 -112
- package/neural-interface/lib/opencode-runtime-config.js +32 -22
- package/neural-interface/lib/opencode-serve-records.js +39 -21
- package/neural-interface/lib/opencode-v2-client.js +48 -153
- package/neural-interface/lib/opencode-v2-ws-requests.js +36 -210
- package/neural-interface/lib/opencode-worker-data.js +27 -0
- package/neural-interface/lib/opencode2-client.js +73 -37
- package/neural-interface/lib/opencode2-proxy.js +23 -63
- package/neural-interface/lib/opencode2-translate.js +51 -2
- package/neural-interface/lib/owner-authority.js +249 -0
- package/neural-interface/lib/page-session.js +275 -0
- package/neural-interface/lib/path-confine.js +12 -9
- package/neural-interface/lib/peer-identity.js +793 -0
- package/neural-interface/lib/pty-host/core.js +28 -1
- package/neural-interface/lib/pty-host/lifetime.js +12 -0
- package/neural-interface/lib/pty-host/manager.js +12 -1
- package/neural-interface/lib/remote-policy.js +1 -1
- package/neural-interface/lib/request-gate.js +20 -2
- package/neural-interface/lib/rulesets/api.js +7 -6
- package/neural-interface/lib/rulesets/fs-safe.js +1 -1
- package/neural-interface/lib/rulesets/installer.js +180 -36
- package/neural-interface/lib/rulesets/json-edit.js +1 -1
- package/neural-interface/lib/rulesets/render.js +1 -1
- package/neural-interface/lib/session-cache-builder.js +81 -31
- package/neural-interface/lib/session-title-generator.js +58 -36
- package/neural-interface/lib/skills/api-v2.js +495 -0
- package/neural-interface/lib/skills/bundle.js +418 -0
- package/neural-interface/lib/skills/catalog.js +298 -0
- package/neural-interface/lib/skills/creation-api.js +191 -0
- package/neural-interface/lib/skills/creation-brief.js +247 -0
- package/neural-interface/lib/skills/creation-sources.js +285 -0
- package/neural-interface/lib/skills/creation.js +843 -0
- package/neural-interface/lib/skills/deploy.js +569 -0
- package/neural-interface/lib/skills/digest.js +119 -0
- package/neural-interface/lib/skills/discover.js +111 -0
- package/neural-interface/lib/skills/draft-confinement.js +216 -0
- package/neural-interface/lib/skills/eval-confinement.js +399 -0
- package/neural-interface/lib/skills/eval-sandbox.js +280 -0
- package/neural-interface/lib/skills/eval-trace.js +135 -0
- package/neural-interface/lib/skills/evals-api.js +212 -0
- package/neural-interface/lib/skills/evals.js +1573 -0
- package/neural-interface/lib/skills/export.js +203 -0
- package/neural-interface/lib/skills/frontmatter.js +64 -0
- package/neural-interface/lib/skills/health.js +75 -0
- package/neural-interface/lib/skills/json-edit.js +165 -0
- package/neural-interface/lib/skills/known-bridge-digests.json +441 -0
- package/neural-interface/lib/skills/known-bridges.js +96 -0
- package/neural-interface/lib/skills/library.js +823 -0
- package/neural-interface/lib/skills/local-store.js +21 -0
- package/neural-interface/lib/skills/migration.js +433 -0
- package/neural-interface/lib/skills/operations.js +45 -0
- package/neural-interface/lib/skills/ownership.js +427 -0
- package/neural-interface/lib/skills/packages.js +88 -0
- package/neural-interface/lib/skills/reviews.js +212 -0
- package/neural-interface/lib/skills/revision.js +80 -0
- package/neural-interface/lib/skills/roots.js +269 -0
- package/neural-interface/lib/skills/runtime-checks.js +358 -0
- package/neural-interface/lib/skills/scan-assets.js +252 -0
- package/neural-interface/lib/skills/scan-context.js +26 -0
- package/neural-interface/lib/skills/scan-shell.js +324 -0
- package/neural-interface/lib/skills/scan.js +364 -0
- package/neural-interface/lib/skills/scanners.js +54 -0
- package/neural-interface/lib/skills/service.js +530 -0
- package/neural-interface/lib/skills/telemetry.js +119 -0
- package/neural-interface/lib/sqlite-integrity-worker.js +22 -0
- package/neural-interface/lib/synabun-version.js +1 -1
- package/neural-interface/lib/system-activity.js +1 -1
- package/neural-interface/lib/tool-lists.js +124 -0
- package/neural-interface/lib/whatsapp/brain.js +7 -3
- package/neural-interface/lib/whatsapp/bridge.js +6 -3
- package/neural-interface/lib/whatsapp/cards.js +22 -9
- package/neural-interface/lib/whatsapp/config.js +1 -1
- package/neural-interface/lib/worker-confinement.js +1268 -0
- package/neural-interface/lib/worker-guard-setting.js +56 -0
- package/neural-interface/lib/worker-mcp-channel.js +175 -0
- package/neural-interface/lib/worker-question.js +74 -0
- package/neural-interface/lib/worker-relay-ports.js +227 -0
- package/neural-interface/lib/worker-resume.js +238 -0
- package/neural-interface/lib/worker-sandbox.js +329 -0
- package/neural-interface/package-lock.json +34 -12
- package/neural-interface/package.json +3 -2
- package/neural-interface/public/index.html +3 -1
- package/neural-interface/public/index2d.html +19 -11
- package/neural-interface/public/onboarding.html +3 -3
- package/neural-interface/public/shared/account-menu.js +8 -5
- package/neural-interface/public/shared/agent-runtime-options.js +125 -31
- package/neural-interface/public/shared/agy/agy-bypass.js +47 -0
- package/neural-interface/public/shared/agy/agy-client.js +266 -0
- package/neural-interface/public/shared/agy/agy-commands.js +120 -0
- package/neural-interface/public/shared/agy/agy-copy.js +326 -0
- package/neural-interface/public/shared/agy/agy-diff.js +161 -0
- package/neural-interface/public/shared/agy/agy-events.js +469 -0
- package/neural-interface/public/shared/agy/agy-greeting.js +26 -0
- package/neural-interface/public/shared/agy/agy-options.js +232 -0
- package/neural-interface/public/shared/agy/agy-panel.js +2543 -0
- package/neural-interface/public/shared/agy/agy-render.js +392 -0
- package/neural-interface/public/shared/agy/agy-setup.js +149 -0
- package/neural-interface/public/shared/agy/agy-styles.js +604 -0
- package/neural-interface/public/shared/agy/agy-tabs-logic.js +181 -0
- package/neural-interface/public/shared/api.js +1527 -1336
- package/neural-interface/public/shared/app-frame.js +192 -0
- package/neural-interface/public/shared/assistant/asst-agents-dock.js +36 -6
- package/neural-interface/public/shared/assistant/asst-api.js +1 -1
- package/neural-interface/public/shared/assistant/asst-ask-styles.js +270 -0
- package/neural-interface/public/shared/assistant/asst-ask-tail.js +118 -0
- package/neural-interface/public/shared/assistant/asst-ask.js +397 -0
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +105 -44
- package/neural-interface/public/shared/assistant/asst-budget.js +5 -4
- package/neural-interface/public/shared/assistant/asst-control.js +205 -26
- package/neural-interface/public/shared/assistant/asst-followups-card.js +383 -0
- package/neural-interface/public/shared/assistant/asst-followups.js +417 -0
- package/neural-interface/public/shared/assistant/asst-hosts.js +16 -7
- package/neural-interface/public/shared/assistant/asst-limit-dock.js +45 -0
- package/neural-interface/public/shared/assistant/asst-limit-wait.js +327 -0
- package/neural-interface/public/shared/assistant/asst-limit.js +168 -0
- package/neural-interface/public/shared/assistant/asst-mascot.js +49 -12
- package/neural-interface/public/shared/assistant/asst-menu.js +7 -6
- package/neural-interface/public/shared/assistant/asst-panel.js +151 -19
- package/neural-interface/public/shared/assistant/asst-rack-styles.js +66 -49
- package/neural-interface/public/shared/assistant/asst-render.js +445 -82
- package/neural-interface/public/shared/assistant/asst-route.js +304 -53
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +9 -8
- package/neural-interface/public/shared/assistant/asst-scenes.js +56 -1
- package/neural-interface/public/shared/assistant/asst-sidepanel.js +117 -10
- package/neural-interface/public/shared/assistant/asst-slash.js +17 -9
- package/neural-interface/public/shared/assistant/asst-state.js +87 -24
- package/neural-interface/public/shared/assistant/asst-stop.js +127 -0
- package/neural-interface/public/shared/assistant/asst-styles.js +93 -21
- package/neural-interface/public/shared/assistant/asst-tool-kinds.js +190 -23
- package/neural-interface/public/shared/assistant/asst-usage.js +2 -1
- package/neural-interface/public/shared/automation-context.js +5 -2
- package/neural-interface/public/shared/cc-dropdown.js +89 -19
- package/neural-interface/public/shared/cdx/cdx-context-menu.js +10 -9
- package/neural-interface/public/shared/cdx/cdx-copy.js +16 -0
- package/neural-interface/public/shared/cdx/cdx-output-model.js +22 -1
- package/neural-interface/public/shared/cdx/cdx-output.js +34 -10
- package/neural-interface/public/shared/cdx/cdx-panel.js +59 -151
- package/neural-interface/public/shared/cdx/cdx-preview.js +12 -0
- package/neural-interface/public/shared/cdx/cdx-protocol.js +39 -11
- package/neural-interface/public/shared/cdx/cdx-render.js +57 -38
- package/neural-interface/public/shared/cdx/cdx-requests.js +14 -4
- package/neural-interface/public/shared/cdx/cdx-skill-hints.js +54 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +15 -3
- package/neural-interface/public/shared/cdx/cdx-tabs.js +127 -44
- package/neural-interface/public/shared/cdx/cdx-ws.js +0 -1
- package/neural-interface/public/shared/cli-install-controller.js +218 -0
- package/neural-interface/public/shared/cli-install-view.js +11 -12
- package/neural-interface/public/shared/cli-status.js +11 -10
- package/neural-interface/public/shared/constants.js +5 -4
- package/neural-interface/public/shared/context-menu-areas.js +34 -0
- package/neural-interface/public/shared/context-menu-logic.js +243 -0
- package/neural-interface/public/shared/context-menu-model.js +367 -0
- package/neural-interface/public/shared/context-menu.js +372 -0
- package/neural-interface/public/shared/cp/cp-context-menu.js +10 -9
- package/neural-interface/public/shared/cp/cp-restore.js +162 -0
- package/neural-interface/public/shared/cp/cp-tool-cards.js +10 -3
- package/neural-interface/public/shared/crash-notice-view.js +168 -0
- package/neural-interface/public/shared/desktop-bridge.js +17 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +12 -0
- package/neural-interface/public/shared/desktop-titlebar.js +13 -4
- package/neural-interface/public/shared/desktop-update-view.js +21 -0
- package/neural-interface/public/shared/editor/editor-panel-logic.js +2 -2
- package/neural-interface/public/shared/explorer/fx-api.js +4 -4
- package/neural-interface/public/shared/explorer/fx-links.js +3 -3
- package/neural-interface/public/shared/explorer/fx-logic.js +1 -1
- package/neural-interface/public/shared/explorer/fx-main.js +48 -16
- package/neural-interface/public/shared/explorer/fx-tree.js +1 -0
- package/neural-interface/public/shared/greeting/greeting-card.js +2 -2
- package/neural-interface/public/shared/greeting/greeting-view.js +1 -0
- package/neural-interface/public/shared/html-shell.js +30 -15
- package/neural-interface/public/shared/i18n.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-approvals.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-binding.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-changes-logic.js +3 -101
- package/neural-interface/public/shared/ocp-v2/ocp-v2-childpanel.js +2 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-compact-button.js +1 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-composer-logic.js +2 -6
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-menu.js +11 -11
- package/neural-interface/public/shared/ocp-v2/ocp-v2-context-model.js +0 -3
- package/neural-interface/public/shared/ocp-v2/ocp-v2-events.js +8 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-manager.js +7 -7
- package/neural-interface/public/shared/ocp-v2/ocp-v2-outcome-notifications.js +16 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +74 -259
- package/neural-interface/public/shared/ocp-v2/ocp-v2-plan.js +1 -2
- package/neural-interface/public/shared/ocp-v2/ocp-v2-projectbar.js +95 -202
- package/neural-interface/public/shared/ocp-v2/ocp-v2-rehydrate.js +13 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-render.js +13 -22
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +4 -4
- package/neural-interface/public/shared/ocp-v2/ocp-v2-session-actions.js +8 -61
- package/neural-interface/public/shared/ocp-v2/ocp-v2-sessions-logic.js +2 -91
- package/neural-interface/public/shared/ocp-v2/ocp-v2-slash-hints.js +16 -15
- package/neural-interface/public/shared/ocp-v2/ocp-v2-state.js +8 -21
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status-logic.js +1 -99
- package/neural-interface/public/shared/ocp-v2/ocp-v2-status.js +5 -35
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +17 -21
- package/neural-interface/public/shared/ocp-v2/{ocp-v2-profile-inheritance.js → ocp-v2-tools-inheritance.js} +16 -16
- package/neural-interface/public/shared/ocp-v2/ocp-v2-ws.js +60 -50
- package/neural-interface/public/shared/page-session.js +96 -0
- package/neural-interface/public/shared/provider-icons.js +4 -2
- package/neural-interface/public/shared/registry.js +5 -3
- package/neural-interface/public/shared/retired-2d.js +3 -0
- package/neural-interface/public/shared/schedules-view.js +195 -61
- package/neural-interface/public/shared/settings/settings-claude-hooks.js +135 -0
- package/neural-interface/public/shared/settings/settings-data.js +3 -1
- package/neural-interface/public/shared/settings/settings-ia.js +6 -6
- package/neural-interface/public/shared/settings/settings-opencode.js +89 -0
- package/neural-interface/public/shared/settings/settings-rules.js +2 -2
- package/neural-interface/public/shared/settings/settings-skill-folders-pane.js +265 -0
- package/neural-interface/public/shared/settings/settings-skill-folders.js +130 -0
- package/neural-interface/public/shared/settings/settings-worker-guard.js +72 -0
- package/neural-interface/public/shared/showcase-privacy.js +6 -1
- package/neural-interface/public/shared/sidepanel-session-status.js +3 -3
- package/neural-interface/public/shared/skills/ss-args.js +96 -0
- package/neural-interface/public/shared/skills/ss-creation.js +222 -0
- package/neural-interface/public/shared/skills/ss-dialog.js +133 -0
- package/neural-interface/public/shared/skills/ss-doc.js +173 -0
- package/neural-interface/public/shared/skills/ss-eval-adapters.js +269 -0
- package/neural-interface/public/shared/skills/ss-eval-grade.js +359 -0
- package/neural-interface/public/shared/skills/ss-eval-optimise.js +153 -0
- package/neural-interface/public/shared/skills/ss-eval-plan.js +315 -0
- package/neural-interface/public/shared/skills/ss-evals.js +417 -0
- package/neural-interface/public/shared/skills/ss-form.js +159 -0
- package/neural-interface/public/shared/skills/ss-frontmatter.js +376 -0
- package/neural-interface/public/shared/skills/ss-ids.js +32 -0
- package/neural-interface/public/shared/skills/ss-lint.js +149 -0
- package/neural-interface/public/shared/skills/ss-presets.js +117 -0
- package/neural-interface/public/shared/skills/ss-profiles.js +513 -0
- package/neural-interface/public/shared/skills/ss-resources.js +165 -0
- package/neural-interface/public/shared/skills/ss-review-view.js +190 -0
- package/neural-interface/public/shared/skills/ss-tabs.js +79 -0
- package/neural-interface/public/shared/skills/ss-unicode.js +135 -0
- package/neural-interface/public/shared/skills/studio/sx-actions.js +222 -0
- package/neural-interface/public/shared/skills/studio/sx-cm.js +101 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai-view.js +749 -0
- package/neural-interface/public/shared/skills/studio/sx-create-ai.js +237 -0
- package/neural-interface/public/shared/skills/studio/sx-create-view.js +254 -0
- package/neural-interface/public/shared/skills/studio/sx-create.js +126 -0
- package/neural-interface/public/shared/skills/studio/sx-diff-view.js +43 -0
- package/neural-interface/public/shared/skills/studio/sx-diff.js +133 -0
- package/neural-interface/public/shared/skills/studio/sx-docs.js +480 -0
- package/neural-interface/public/shared/skills/studio/sx-dom.js +230 -0
- package/neural-interface/public/shared/skills/studio/sx-edit-view.js +848 -0
- package/neural-interface/public/shared/skills/studio/sx-editor-model.js +193 -0
- package/neural-interface/public/shared/skills/studio/sx-errors.js +22 -0
- package/neural-interface/public/shared/skills/studio/sx-fixes-view.js +359 -0
- package/neural-interface/public/shared/skills/studio/sx-fixes.js +327 -0
- package/neural-interface/public/shared/skills/studio/sx-geometry.js +82 -0
- package/neural-interface/public/shared/skills/studio/sx-import.js +262 -0
- package/neural-interface/public/shared/skills/studio/sx-inspector.js +308 -0
- package/neural-interface/public/shared/skills/studio/sx-install-flow.js +282 -0
- package/neural-interface/public/shared/skills/studio/sx-install.js +313 -0
- package/neural-interface/public/shared/skills/studio/sx-library-view.js +748 -0
- package/neural-interface/public/shared/skills/studio/sx-library.js +479 -0
- package/neural-interface/public/shared/skills/studio/sx-main.js +690 -0
- package/neural-interface/public/shared/skills/studio/sx-operations-view.js +98 -0
- package/neural-interface/public/shared/skills/studio/sx-operations.js +11 -0
- package/neural-interface/public/shared/skills/studio/sx-plan.js +158 -0
- package/neural-interface/public/shared/skills/studio/sx-publish-view.js +621 -0
- package/neural-interface/public/shared/skills/studio/sx-review-view.js +369 -0
- package/neural-interface/public/shared/skills/studio/sx-review.js +148 -0
- package/neural-interface/public/shared/skills/studio/sx-scan.js +35 -0
- package/neural-interface/public/shared/skills/studio/sx-snippets.js +96 -0
- package/neural-interface/public/shared/skills/studio/sx-subject.js +249 -0
- package/neural-interface/public/shared/skills/studio/sx-test-view.js +994 -0
- package/neural-interface/public/shared/skills/studio/sx-test.js +328 -0
- package/neural-interface/public/shared/skills/studio/sx-versions-view.js +241 -0
- package/neural-interface/public/shared/skills/studio/sx-workspace-view.js +426 -0
- package/neural-interface/public/shared/state.js +1 -1
- package/neural-interface/public/shared/streaming-markdown.js +58 -0
- package/neural-interface/public/shared/styleguide/sg-panel.js +4 -2
- package/neural-interface/public/shared/styles.css +1822 -1756
- package/neural-interface/public/shared/synabun-mascot.js +1115 -9
- package/neural-interface/public/shared/text-cache.js +29 -0
- package/neural-interface/public/shared/tool-list-picker.js +55 -0
- package/neural-interface/public/shared/tool-list-storage.js +24 -0
- package/neural-interface/public/shared/tool-list-view.js +112 -0
- package/neural-interface/public/shared/topright-overflow-logic.js +54 -0
- package/neural-interface/public/shared/tour/tour-actor.js +268 -0
- package/neural-interface/public/shared/tour/tour-beats.js +336 -0
- package/neural-interface/public/shared/tour/tour-engine.js +884 -0
- package/neural-interface/public/shared/tour/tour-ink.js +390 -0
- package/neural-interface/public/shared/tour/tour-stage.js +440 -0
- package/neural-interface/public/shared/tour/tour-state.js +40 -0
- package/neural-interface/public/shared/tour/tour-tips.js +99 -0
- package/neural-interface/public/shared/tour/tour.css +144 -0
- package/neural-interface/public/shared/ui-antigravity-panel.js +19 -0
- package/neural-interface/public/shared/ui-assistant.js +2 -0
- package/neural-interface/public/shared/ui-automation-studio.js +111 -140
- package/neural-interface/public/shared/ui-claude-panel.js +376 -82
- package/neural-interface/public/shared/ui-cli-banner.js +23 -167
- package/neural-interface/public/shared/ui-command-runner.js +6 -3
- package/neural-interface/public/shared/ui-context-menu.js +295 -0
- package/neural-interface/public/shared/ui-cost-widget.js +57 -59
- package/neural-interface/public/shared/ui-crash-notice.js +187 -0
- package/neural-interface/public/shared/ui-detail.js +15 -3
- package/neural-interface/public/shared/ui-file-explorer.js +48 -6
- package/neural-interface/public/shared/ui-file-links.js +2 -2
- package/neural-interface/public/shared/ui-games.js +2 -2
- package/neural-interface/public/shared/ui-image-gallery.js +50 -47
- package/neural-interface/public/shared/ui-judgments.js +1 -1
- package/neural-interface/public/shared/ui-keybinds.js +33 -2
- package/neural-interface/public/shared/ui-link.js +3 -3
- package/neural-interface/public/shared/ui-menubar.js +10 -20
- package/neural-interface/public/shared/ui-native-loop-router-state.js +5 -0
- package/neural-interface/public/shared/ui-native-loop-router.js +11 -1
- package/neural-interface/public/shared/ui-navbar.js +49 -24
- package/neural-interface/public/shared/ui-notifications.js +1 -0
- package/neural-interface/public/shared/ui-panels.js +96 -65
- package/neural-interface/public/shared/ui-resume.js +9 -7
- package/neural-interface/public/shared/ui-schedules-studio.js +546 -431
- package/neural-interface/public/shared/ui-scroll-follow.js +16 -5
- package/neural-interface/public/shared/ui-sessions.js +27 -15
- package/neural-interface/public/shared/ui-settings.js +683 -526
- package/neural-interface/public/shared/ui-sidepanel-session-entry.js +9 -2
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +4 -4
- package/neural-interface/public/shared/ui-sidepanel-state.js +23 -12
- package/neural-interface/public/shared/ui-sidepanel-tray.js +48 -7
- package/neural-interface/public/shared/ui-sidepanel-windows.js +18 -13
- package/neural-interface/public/shared/ui-skills.js +33 -2830
- package/neural-interface/public/shared/ui-styleguide.js +5 -2
- package/neural-interface/public/shared/ui-sync.js +15 -5
- package/neural-interface/public/shared/ui-terminal.js +270 -190
- package/neural-interface/public/shared/ui-tool-updates.js +6 -4
- package/neural-interface/public/shared/ui-tooltip.js +81 -51
- package/neural-interface/public/shared/ui-topright-overflow.js +233 -0
- package/neural-interface/public/shared/ui-trash.js +6 -4
- package/neural-interface/public/shared/ui-tutorial-layout.js +3 -117
- package/neural-interface/public/shared/ui-tutorial-preview.js +103 -0
- package/neural-interface/public/shared/ui-tutorial-steps.js +3 -65
- package/neural-interface/public/shared/ui-tutorial.css +47 -100
- package/neural-interface/public/shared/ui-tutorial.js +285 -509
- package/neural-interface/public/shared/ui-update.js +38 -2
- package/neural-interface/public/shared/ui-whiteboard.js +312 -59
- package/neural-interface/public/shared/ui-worker-end.js +5 -1
- package/neural-interface/public/shared/ui-workspaces.js +3 -2
- package/neural-interface/public/shared/view-variant.js +66 -0
- package/neural-interface/public/shared/whatsapp/wa-view.js +3 -3
- package/neural-interface/public/shared/whiteboard-list.js +172 -0
- package/neural-interface/public/shared/worker-end.js +10 -3
- package/neural-interface/public/shared/worker-questions.js +34 -0
- package/neural-interface/public/shared/worker-restart.js +12 -0
- package/neural-interface/public/sidepanel-session.html +2 -2
- package/neural-interface/public/variant/2d/background.js +2 -1
- package/neural-interface/public/variant/2d/context-menu.js +8 -2
- package/neural-interface/public/variant/2d/graph.js +42 -20
- package/neural-interface/public/variant/2d/hulls.js +14 -9
- package/neural-interface/public/variant/2d/lasso.js +11 -7
- package/neural-interface/public/variant/2d/main.js +32 -1
- package/neural-interface/public/variant/2d/minimap.js +11 -13
- package/neural-interface/public/variant/3d/main.js +69 -6
- package/neural-interface/public/variant/3d/map-controls.js +24 -9
- package/neural-interface/public/vendor/caveat/OFL.txt +93 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-400-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat-latin-700-normal.woff2 +0 -0
- package/neural-interface/public/vendor/caveat/caveat.css +17 -0
- package/neural-interface/public/vendor/caveat/manifest.json +12 -0
- package/neural-interface/public/vendor/yaml/LICENSE +13 -0
- package/neural-interface/public/vendor/yaml/manifest.json +4 -0
- package/neural-interface/public/vendor/yaml/yaml-2.9.1.min.js +137 -0
- package/neural-interface/scripts/build-vendor.mjs +32 -0
- package/neural-interface/server.js +4553 -2855
- package/neural-interface/templates/rulesets/README.md +1 -1
- package/neural-interface/templates/rulesets/core.md +1 -1
- package/neural-interface/templates/rulesets/legacy-hashes.json +23 -5
- package/neural-interface/templates/rulesets/manifest.json +8 -8
- package/npm-shrinkwrap.json +34 -12
- package/package.json +17 -3
- package/postinstall.js +9 -4
- package/preuninstall.js +1 -1
- package/setup.js +97 -322
- package/skills/skill-forge/SKILL.md +177 -0
- package/skills/skill-forge/evals/evals.json +54 -0
- package/skills/skill-forge/references/package.md +105 -0
- package/skills/skill-forge/references/review-and-recovery.md +63 -0
- package/skills/skill-forge/references/runtime-profiles.md +20 -0
- package/skills/skill-forge/references/sources-and-capabilities.md +51 -0
- package/skills/synabun/SKILL.md +10 -7
- package/skills/synabun/modules/audit.md +1 -5
- package/skills/synabun/modules/changelog.md +1 -5
- package/skills/synabun/modules/idea.md +1 -1
- package/skills/synabun/modules/memorize.md +6 -9
- package/skills/synabun/modules/schedule.md +6 -6
- package/mcp-server/dist/services/profiles.d.ts +0 -120
- package/mcp-server/dist/services/profiles.d.ts.map +0 -1
- package/mcp-server/dist/services/profiles.js +0 -387
- package/mcp-server/dist/services/profiles.js.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts +0 -97
- package/mcp-server/dist/tools/leonardo-browser-tools.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo-browser-tools.js +0 -228
- package/mcp-server/dist/tools/leonardo-browser-tools.js.map +0 -1
- package/mcp-server/dist/tools/leonardo.d.ts +0 -13
- package/mcp-server/dist/tools/leonardo.d.ts.map +0 -1
- package/mcp-server/dist/tools/leonardo.js +0 -21
- package/mcp-server/dist/tools/leonardo.js.map +0 -1
- package/mcp-server/dist/tools/profile.d.ts +0 -17
- package/mcp-server/dist/tools/profile.d.ts.map +0 -1
- package/mcp-server/dist/tools/profile.js +0 -114
- package/mcp-server/dist/tools/profile.js.map +0 -1
- package/mcp-server/src/services/profiles.ts +0 -428
- package/mcp-server/src/tools/leonardo-browser-tools.ts +0 -291
- package/mcp-server/src/tools/leonardo.ts +0 -30
- package/mcp-server/src/tools/profile.ts +0 -122
- package/neural-interface/lib/assistant-brains/opencode-browser-policy.js +0 -47
- package/neural-interface/lib/assistant-brains/opencode-route-gate.js +0 -62
- package/neural-interface/lib/mcp-profile-servers.js +0 -120
- package/neural-interface/public/shared/ui-tutorial-draw.js +0 -311
- package/skills/leonardo/SKILL.md +0 -168
- package/skills/leonardo/icon.svg +0 -1
- package/skills/leonardo/modules/browser-guide.md +0 -378
- package/skills/leonardo/modules/image-prompter.md +0 -283
- package/skills/leonardo/modules/model-advisor.md +0 -100
- package/skills/leonardo/modules/prompt-library.md +0 -110
- package/skills/leonardo/modules/style-guide.md +0 -186
- package/skills/leonardo/modules/video-prompter.md +0 -317
- /package/neural-interface/templates/rulesets/{gemini.md → antigravity.md} +0 -0
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════
|
|
2
|
+
// SynaBun Neural Interface — Skills Studio: runtime profiles
|
|
3
|
+
// ═══════════════════════════════════════════
|
|
4
|
+
//
|
|
5
|
+
// A skill is one folder; each runtime reads it its own way. A profile says, for one runtime or surface, which
|
|
6
|
+
// fields it reads, which it requires, its limits, where it looks for skills, how a skill is invoked and how a
|
|
7
|
+
// change reaches a running session, with the sources it was read from and how it was verified. The checks of a
|
|
8
|
+
// profile (lintForProfile) are separate from the Studio's editing checks (ss-lint.js): a field Claude Code reads
|
|
9
|
+
// may be an error in a strict upload and ignored by Codex, and each is said for the profile that sees it. Profiles
|
|
10
|
+
// are data with a version: a runtime that changes is a new version, never a silent edit of the old one.
|
|
11
|
+
//
|
|
12
|
+
// Invocation is kept as intent, apart from any one runtime's spelling of it: who may start the skill (the user
|
|
13
|
+
// by name, the model on its own), read from every dialect a folder carries (Claude Code fields, Codex's
|
|
14
|
+
// agents/openai.yaml, OpenCode's metadata, Antigravity's disable-slash-command) and compared with what a target
|
|
15
|
+
// would read from the exported bytes, so an install never lets a model start a skill its author kept
|
|
16
|
+
// explicit-only (invocationPlan).
|
|
17
|
+
//
|
|
18
|
+
// No DOM, no I/O: the page and the server load it; YAML is parsed by the caller.
|
|
19
|
+
|
|
20
|
+
import { findHiddenChars } from './ss-unicode.js';
|
|
21
|
+
|
|
22
|
+
export const PROFILE_SET_VERSION = '2026-10-30';
|
|
23
|
+
|
|
24
|
+
const RETRIEVED = '2026-10-21';
|
|
25
|
+
const SOURCES = Object.freeze({
|
|
26
|
+
standard: { title: 'Agent Skills specification', url: 'https://agentskills.io/specification', retrieved: RETRIEVED },
|
|
27
|
+
claude: { title: 'Claude Code skills', url: 'https://code.claude.com/docs/en/skills', retrieved: RETRIEVED },
|
|
28
|
+
claudeUpload: { title: 'Claude Code: frontmatter outside Claude Code', url: 'https://code.claude.com/docs/en/skills#using-skill-frontmatter-outside-claude-code', retrieved: RETRIEVED },
|
|
29
|
+
codex: { title: 'Build skills (Codex)', url: 'https://learn.chatgpt.com/docs/build-skills', retrieved: RETRIEVED },
|
|
30
|
+
codexPrompts: { title: 'Codex custom prompts (deprecated)', url: 'https://learn.chatgpt.com/docs/custom-prompts', retrieved: RETRIEVED },
|
|
31
|
+
opencode: { title: 'OpenCode skills', url: 'https://opencode.ai/docs/skills/', retrieved: RETRIEVED },
|
|
32
|
+
opencodeCommands: { title: 'OpenCode commands', url: 'https://opencode.ai/docs/commands/', retrieved: RETRIEVED },
|
|
33
|
+
antigravity: { title: 'Antigravity CLI reference', url: 'https://antigravity.google/docs/cli/reference', retrieved: '2026-10-30' },
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const PORTABLE_FIELDS = Object.freeze(['name', 'description', 'license', 'compatibility', 'metadata', 'allowed-tools']);
|
|
37
|
+
export const CLAUDE_FIELDS = Object.freeze([
|
|
38
|
+
'name', 'description', 'when_to_use', 'argument-hint', 'arguments', 'disable-model-invocation', 'user-invocable',
|
|
39
|
+
'allowed-tools', 'disallowed-tools', 'model', 'effort', 'context', 'agent', 'background', 'hooks', 'paths', 'shell',
|
|
40
|
+
'metadata', 'license', 'compatibility',
|
|
41
|
+
]);
|
|
42
|
+
const OPENCODE_FIELDS = Object.freeze(['name', 'description', 'license', 'compatibility', 'metadata', 'disable-model-invocation']);
|
|
43
|
+
const CODEX_FIELDS = Object.freeze(['name', 'description', 'metadata']);
|
|
44
|
+
const ANTIGRAVITY_FIELDS = Object.freeze(['name', 'description', 'disable-slash-command']);
|
|
45
|
+
/** The most of a SKILL.md body Antigravity reads (UTF-8 bytes after the frontmatter). */
|
|
46
|
+
export const ANTIGRAVITY_BODY_BYTES = 24 * 1024;
|
|
47
|
+
|
|
48
|
+
export const PORTABLE_NAME_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
49
|
+
export const CODEX_SIDECAR = 'agents/openai.yaml';
|
|
50
|
+
const CLAUDE_BOOLEAN_WORDS = new Set(['true', 'false', 'yes', 'no', 'on', 'off', '1', '0']);
|
|
51
|
+
const EFFORTS = new Set(['low', 'medium', 'high', 'xhigh', 'max']);
|
|
52
|
+
const SHELLS = new Set(['bash', 'powershell']);
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The profiles. `verified` is what was seen to work, not what a page says: the native roots of Codex and OpenCode
|
|
56
|
+
* were each confirmed on 2026-10-22 by starting the installed runtime in a temporary home and listing the skills
|
|
57
|
+
* it found (tests/skills-p1-native-runtimes.test.mjs repeats that check).
|
|
58
|
+
*/
|
|
59
|
+
export const PROFILES = Object.freeze({
|
|
60
|
+
'portable-six-field': Object.freeze({
|
|
61
|
+
id: 'portable-six-field', version: '2026-10-21', title: 'Agent Skills (portable)', runtime: 'portable', status: 'current',
|
|
62
|
+
sources: [SOURCES.standard], verified: null,
|
|
63
|
+
fields: { recognized: PORTABLE_FIELDS, required: ['name', 'description'], strictTopLevel: false },
|
|
64
|
+
limits: { nameChars: 64, descriptionChars: 1024, compatibilityChars: 500, bodyLinesGuidance: 500, bodyTokensGuidance: 5000 },
|
|
65
|
+
invocation: { model: 'not defined by the format', user: 'not defined by the format' },
|
|
66
|
+
substitutions: null,
|
|
67
|
+
roots: [],
|
|
68
|
+
reload: null,
|
|
69
|
+
}),
|
|
70
|
+
'claude-code': Object.freeze({
|
|
71
|
+
id: 'claude-code', version: '2026-10-21', title: 'Claude Code', runtime: 'claude', status: 'current',
|
|
72
|
+
sources: [SOURCES.claude], verified: { runtime: 'claude', version: '2.1.305', method: 'documentation and CLI help; discovery not fixture-tested' },
|
|
73
|
+
fields: { recognized: CLAUDE_FIELDS, required: [], strictTopLevel: false },
|
|
74
|
+
limits: { nameChars: 64, descriptionChars: 1024, listingChars: 1536, compatibilityChars: 500, bodyLinesGuidance: 500, bodyTokensGuidance: 5000 },
|
|
75
|
+
invocation: { model: '`disable-model-invocation: true` keeps the model from starting it', user: '`user-invocable: false` hides /name' },
|
|
76
|
+
substitutions: { body: ['$ARGUMENTS', '$ARGUMENTS[N]', '$N (from 0)', '$name (declared in arguments)', '${CLAUDE_SKILL_DIR}', '${CLAUDE_PROJECT_DIR}', '${CLAUDE_SESSION_ID}', '${CLAUDE_EFFORT}'], dynamicContext: true },
|
|
77
|
+
roots: [
|
|
78
|
+
{ scope: 'user', path: '<config dir>/skills', note: 'the account\'s CLAUDE_CONFIG_DIR, ~/.claude by default' },
|
|
79
|
+
{ scope: 'project', path: '<project>/.claude/skills', note: 'from the working folder up to the repository root' },
|
|
80
|
+
{ scope: 'managed', path: '<managed settings>/.claude/skills', note: 'read-only' },
|
|
81
|
+
{ scope: 'synced', path: '<config dir>/skills/synced', note: 'account skills, read-only' },
|
|
82
|
+
{ scope: 'plugin', path: '<plugin>/skills', note: 'namespaced /plugin:name, read-only' },
|
|
83
|
+
],
|
|
84
|
+
reload: { file: 'automatic', newRoot: 'reload-skills', note: 'Claude Code watches the skill folders that existed when it started; a folder created later needs /reload-skills.' },
|
|
85
|
+
}),
|
|
86
|
+
'claude-upload': Object.freeze({
|
|
87
|
+
id: 'claude-upload', version: '2026-10-21', title: 'Claude.ai / API upload', runtime: 'claude-cloud', status: 'export-only',
|
|
88
|
+
sources: [SOURCES.claudeUpload, SOURCES.standard], verified: null,
|
|
89
|
+
fields: { recognized: PORTABLE_FIELDS, required: ['name', 'description'], strictTopLevel: true },
|
|
90
|
+
limits: { nameChars: 64, descriptionChars: 1024, compatibilityChars: 500, uploadBytes: null, note: 'The app\'s ZIP size limit is not published; the API takes under 30 MB uncompressed.' },
|
|
91
|
+
invocation: { model: 'chosen by relevance; no Claude Code flag applies', user: 'no slash engine' },
|
|
92
|
+
substitutions: null,
|
|
93
|
+
roots: [],
|
|
94
|
+
reload: null,
|
|
95
|
+
}),
|
|
96
|
+
'codex-native': Object.freeze({
|
|
97
|
+
id: 'codex-native', version: '2026-10-22', title: 'Codex', runtime: 'codex', status: 'current',
|
|
98
|
+
sources: [SOURCES.codex], verified: { runtime: 'codex', version: '0.163.0', method: 'isolated app-server skills/list, 2026-10-22' },
|
|
99
|
+
fields: { recognized: CODEX_FIELDS, required: ['name', 'description'], strictTopLevel: false, sidecars: [CODEX_SIDECAR] },
|
|
100
|
+
limits: { nameChars: 64, descriptionChars: 1024, displayNameChars: 64, shortDescriptionChars: 1024, defaultPromptChars: 1024 },
|
|
101
|
+
invocation: { model: '`policy.allow_implicit_invocation: false` in agents/openai.yaml keeps the model from starting it', user: '$name or /skills; no flag hides it' },
|
|
102
|
+
substitutions: { body: [], note: 'A native skill body is read as written: $ARGUMENTS is not filled.' },
|
|
103
|
+
roots: [
|
|
104
|
+
{ scope: 'user', path: '$CODEX_HOME/skills', note: '~/.codex/skills by default (the installer\'s default); each Codex account has its own' },
|
|
105
|
+
{ scope: 'shared', path: '~/.agents/skills', note: 'read by Codex and OpenCode; SynaBun writes there only when the owner turned it on' },
|
|
106
|
+
{ scope: 'project', path: '<project>/.agents/skills', note: 'from the working folder up to the repository root' },
|
|
107
|
+
{ scope: 'project-compat', path: '<project>/.codex/skills', note: 'read by Codex 0.163.0; not in the guide' },
|
|
108
|
+
{ scope: 'system', path: '$CODEX_HOME/skills/.system', note: 'Codex\'s own, read-only' },
|
|
109
|
+
{ scope: 'admin', path: '/etc/codex/skills', note: 'read-only' },
|
|
110
|
+
],
|
|
111
|
+
reload: { file: 'automatic', newRoot: 'automatic', config: 'restart', note: 'Codex picks up skill files by itself; a change to config.toml ([[skills.config]]) needs a restart.' },
|
|
112
|
+
}),
|
|
113
|
+
'opencode-native': Object.freeze({
|
|
114
|
+
id: 'opencode-native', version: '2026-10-22', title: 'OpenCode', runtime: 'opencode', status: 'current',
|
|
115
|
+
sources: [SOURCES.opencode], verified: { runtime: 'opencode', version: '2.0.32', method: 'isolated serve /api/skill, 2026-10-22' },
|
|
116
|
+
fields: { recognized: OPENCODE_FIELDS, required: ['name', 'description'], strictTopLevel: false },
|
|
117
|
+
limits: { nameChars: 64, descriptionChars: 1024, compatibilityChars: 500 },
|
|
118
|
+
invocation: { model: '`metadata["opencode/autoinvoke"]: "false"` keeps it out of the model\'s list', user: '`metadata["opencode/slash"]: "true"` shows /name; the skill tool loads any skill by its exact name' },
|
|
119
|
+
substitutions: { body: [], note: 'A native skill body is read as written; $ARGUMENTS and $1 belong to commands.' },
|
|
120
|
+
roots: [
|
|
121
|
+
{ scope: 'user', path: '<config>/opencode/skills', note: 'XDG_CONFIG_HOME, ~/.config by default' },
|
|
122
|
+
{ scope: 'user-compat', path: '<config>/opencode/skill', note: 'the singular folder, read by OpenCode 2.0.32' },
|
|
123
|
+
{ scope: 'project', path: '<project>/.opencode/skills', note: '' },
|
|
124
|
+
{ scope: 'shared', path: '~/.agents/skills and <project>/.agents/skills', note: '' },
|
|
125
|
+
{ scope: 'claude-compat', path: '~/.claude/skills and <project>/.claude/skills', note: 'not read when OPENCODE_DISABLE_CLAUDE_CODE is set, as in SynaBun\'s own OpenCode panel' },
|
|
126
|
+
],
|
|
127
|
+
reload: { file: 'new-session', newRoot: 'new-session', note: 'A running OpenCode may not see a new skill; start a new session (or restart the server) to be sure.' },
|
|
128
|
+
}),
|
|
129
|
+
'antigravity-native': Object.freeze({
|
|
130
|
+
id: 'antigravity-native', version: '2026-10-30', title: 'Antigravity', runtime: 'antigravity', status: 'current',
|
|
131
|
+
sources: [SOURCES.antigravity], verified: null,
|
|
132
|
+
fields: { recognized: ANTIGRAVITY_FIELDS, required: ['name', 'description'], strictTopLevel: false },
|
|
133
|
+
limits: { nameChars: 64, descriptionChars: 1024, bodyBytes: ANTIGRAVITY_BODY_BYTES },
|
|
134
|
+
invocation: { model: 'chosen by its description; no field keeps the model from starting it', user: '/name; `disable-slash-command: true` hides it' },
|
|
135
|
+
substitutions: null,
|
|
136
|
+
roots: [
|
|
137
|
+
{ scope: 'user', path: '~/.gemini/config/skills', note: 'where SynaBun installs' },
|
|
138
|
+
{ scope: 'project', path: '<project>/.agents/skills', note: 'the Codex project folder, which Antigravity reads too' },
|
|
139
|
+
],
|
|
140
|
+
reload: { file: 'automatic', newRoot: 'automatic', note: 'Antigravity reads its skill folders again by itself; there is no command to run.' },
|
|
141
|
+
}),
|
|
142
|
+
'codex-prompt': Object.freeze({
|
|
143
|
+
id: 'codex-prompt', version: '2026-10-21', title: 'Codex custom prompt (deprecated)', runtime: 'codex', status: 'legacy',
|
|
144
|
+
sources: [SOURCES.codexPrompts], verified: null,
|
|
145
|
+
fields: { recognized: ['description', 'argument-hint'], required: [], strictTopLevel: false },
|
|
146
|
+
limits: {},
|
|
147
|
+
invocation: { model: 'never', user: '/prompts:name' },
|
|
148
|
+
substitutions: { body: ['$1-$9 (from 1)', '$ARGUMENTS', 'KEY=value', '$$'] },
|
|
149
|
+
roots: [{ scope: 'user', path: '$CODEX_HOME/prompts', note: 'where SynaBun\'s old bridges were written' }],
|
|
150
|
+
reload: { file: 'new-session' },
|
|
151
|
+
}),
|
|
152
|
+
'opencode-command': Object.freeze({
|
|
153
|
+
id: 'opencode-command', version: '2026-10-21', title: 'OpenCode command', runtime: 'opencode', status: 'legacy',
|
|
154
|
+
sources: [SOURCES.opencodeCommands], verified: { runtime: 'opencode', version: '2.0.32', method: 'isolated serve /api/command lists command/ and commands/, 2026-10-22' },
|
|
155
|
+
fields: { recognized: ['description', 'agent', 'model', 'subtask'], required: [], strictTopLevel: false },
|
|
156
|
+
limits: {},
|
|
157
|
+
invocation: { model: 'never', user: '/name' },
|
|
158
|
+
substitutions: { body: ['$ARGUMENTS', '$1… (from 1)', '!`command`', '@file'] },
|
|
159
|
+
roots: [{ scope: 'user', path: '<config>/opencode/command and commands', note: 'command/ is where SynaBun\'s old bridges were written' }],
|
|
160
|
+
reload: { file: 'new-session' },
|
|
161
|
+
}),
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
/** The profile an install into a runtime is checked against. */
|
|
165
|
+
export const TARGET_PROFILE = Object.freeze({ claude: 'claude-code', codex: 'codex-native', opencode: 'opencode-native', antigravity: 'antigravity-native', agents: 'portable-six-field' });
|
|
166
|
+
|
|
167
|
+
export function getProfile(id) {
|
|
168
|
+
return Object.prototype.hasOwnProperty.call(PROFILES, id) ? PROFILES[id] : null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Every profile, as the API lists them. */
|
|
172
|
+
export function profileList() {
|
|
173
|
+
return Object.values(PROFILES).map((p) => ({
|
|
174
|
+
id: p.id, version: p.version, title: p.title, runtime: p.runtime, status: p.status, sources: p.sources, verified: p.verified,
|
|
175
|
+
fields: p.fields, limits: p.limits, invocation: p.invocation, substitutions: p.substitutions, roots: p.roots, reload: p.reload,
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ── Reading values ──
|
|
180
|
+
|
|
181
|
+
const has = (data, key) => !!data && Object.prototype.hasOwnProperty.call(data, key);
|
|
182
|
+
const isMap = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
183
|
+
const ENCODER = new TextEncoder();
|
|
184
|
+
/** A text's length in UTF-8 bytes (0 for anything else). */
|
|
185
|
+
const utf8Length = (text) => (typeof text === 'string' ? ENCODER.encode(text).length : 0);
|
|
186
|
+
/** "24 KB", "25.3 KB", "812 bytes". */
|
|
187
|
+
const kb = (bytes) => (bytes < 1024 ? `${bytes} bytes` : `${Math.round((bytes / 1024) * 10) / 10} KB`);
|
|
188
|
+
const kindOf = (value) => {
|
|
189
|
+
if (value === undefined) return 'absent';
|
|
190
|
+
if (value === null) return 'empty';
|
|
191
|
+
if (Array.isArray(value)) return 'a list';
|
|
192
|
+
if (typeof value === 'object') return 'a mapping';
|
|
193
|
+
return typeof value === 'string' ? 'text' : `a ${typeof value}`;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
/** A Claude Code boolean field as Claude Code reads it: true / false, or null when it says neither. */
|
|
197
|
+
export function claudeBoolean(value) {
|
|
198
|
+
if (value === true || value === false) return value;
|
|
199
|
+
if (value === 1 || value === 0) return value === 1;
|
|
200
|
+
if (typeof value === 'string' && CLAUDE_BOOLEAN_WORDS.has(value.trim().toLowerCase())) return ['true', 'yes', 'on', '1'].includes(value.trim().toLowerCase());
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** An OpenCode metadata switch ("true" / "false", or the YAML booleans OpenCode also takes): true / false / null. */
|
|
205
|
+
function openSwitch(value) {
|
|
206
|
+
if (value === true || value === false) return value;
|
|
207
|
+
if (typeof value === 'string' && /^(true|false)$/i.test(value.trim())) return value.trim().toLowerCase() === 'true';
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// ── Invocation ──
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Who may start the skill, read from every dialect the folder carries. The most restrictive statement wins: one
|
|
215
|
+
* "not by the model" anywhere means not by the model. `conflicts` names dialects that disagree.
|
|
216
|
+
* @param {{ data: object|null, sidecar?: { data: object|null }|null }} o `data`: the SKILL.md frontmatter
|
|
217
|
+
* @returns {{ user: boolean, model: boolean, slash: boolean|null, said: object, conflicts: string[] }}
|
|
218
|
+
*/
|
|
219
|
+
export function readInvocationIntent({ data, sidecar = null }) {
|
|
220
|
+
const said = {};
|
|
221
|
+
if (has(data, 'disable-model-invocation')) said.claudeModel = claudeBoolean(data['disable-model-invocation']) === true ? false : (claudeBoolean(data['disable-model-invocation']) === false ? true : null);
|
|
222
|
+
if (has(data, 'user-invocable')) said.claudeUser = claudeBoolean(data['user-invocable']);
|
|
223
|
+
const policy = isMap(sidecar?.data) && isMap(sidecar.data.policy) ? sidecar.data.policy : null;
|
|
224
|
+
if (policy && has(policy, 'allow_implicit_invocation')) said.codexModel = typeof policy.allow_implicit_invocation === 'boolean' ? policy.allow_implicit_invocation : null;
|
|
225
|
+
const meta = isMap(data?.metadata) ? data.metadata : null;
|
|
226
|
+
if (meta && has(meta, 'opencode/autoinvoke')) said.opencodeModel = openSwitch(meta['opencode/autoinvoke']);
|
|
227
|
+
if (meta && has(meta, 'opencode/slash')) said.opencodeSlash = openSwitch(meta['opencode/slash']);
|
|
228
|
+
// Antigravity's `disable-slash-command: true` keeps /name from the person, as Claude Code's user-invocable: false does.
|
|
229
|
+
if (has(data, 'disable-slash-command')) said.antigravityUser = claudeBoolean(data['disable-slash-command']) === true ? false : (claudeBoolean(data['disable-slash-command']) === false ? true : null);
|
|
230
|
+
const modelSays = [said.claudeModel, said.codexModel, said.opencodeModel].filter((v) => v === true || v === false);
|
|
231
|
+
const model = !modelSays.includes(false);
|
|
232
|
+
const user = said.claudeUser !== false && said.antigravityUser !== false;
|
|
233
|
+
const conflicts = [];
|
|
234
|
+
if (modelSays.includes(false) && modelSays.includes(true)) conflicts.push('model');
|
|
235
|
+
return { user, model, slash: said.opencodeSlash ?? null, said, conflicts };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Who may start the skill as one runtime reads these bytes. */
|
|
239
|
+
export function effectiveInvocation(profileId, { data, sidecar = null }) {
|
|
240
|
+
const profile = getProfile(profileId);
|
|
241
|
+
const runtime = profile?.runtime;
|
|
242
|
+
if (runtime === 'claude') {
|
|
243
|
+
return { model: claudeBoolean(data?.['disable-model-invocation']) !== true, user: claudeBoolean(data?.['user-invocable']) !== false };
|
|
244
|
+
}
|
|
245
|
+
if (runtime === 'codex') {
|
|
246
|
+
const policy = isMap(sidecar?.data) && isMap(sidecar.data.policy) ? sidecar.data.policy : null;
|
|
247
|
+
return { model: policy?.allow_implicit_invocation !== false, user: true };
|
|
248
|
+
}
|
|
249
|
+
if (runtime === 'opencode') {
|
|
250
|
+
const meta = isMap(data?.metadata) ? data.metadata : null;
|
|
251
|
+
// OpenCode 2.0.32 also reads Claude's disable-model-invocation, and a YAML boolean in the metadata: its
|
|
252
|
+
// /api/skill answered `autoinvoke: false` for each in an isolated serve (2026-10-22).
|
|
253
|
+
const claudeOff = claudeBoolean(data?.['disable-model-invocation']) === true;
|
|
254
|
+
return { model: !(openSwitch(meta?.['opencode/autoinvoke']) === false || claudeOff), user: true, slash: openSwitch(meta?.['opencode/slash']) === true };
|
|
255
|
+
}
|
|
256
|
+
if (runtime === 'antigravity') {
|
|
257
|
+
// Only a YAML true is taken as hiding /name (anything else is not counted on); nothing keeps its model from starting a skill.
|
|
258
|
+
return { model: true, user: data?.['disable-slash-command'] !== true };
|
|
259
|
+
}
|
|
260
|
+
return { model: true, user: true };
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* What an export for a target must change so the target does not start the skill more freely than its intent
|
|
265
|
+
* says, and what it cannot express. Never widens: a change is only ever a restriction.
|
|
266
|
+
* @returns {{ transforms: object[], diagnostics: object[] }} transforms: `{ file, op, key|path, value, reason }`
|
|
267
|
+
*/
|
|
268
|
+
export function invocationPlan(profileId, { intent, data, sidecar = null }) {
|
|
269
|
+
const profile = getProfile(profileId);
|
|
270
|
+
const transforms = [];
|
|
271
|
+
const diagnostics = [];
|
|
272
|
+
if (!profile || !intent) return { transforms, diagnostics };
|
|
273
|
+
const now = effectiveInvocation(profileId, { data, sidecar });
|
|
274
|
+
const runtime = profile.runtime;
|
|
275
|
+
if (intent.conflicts?.includes('model')) {
|
|
276
|
+
diagnostics.push({ ruleId: 'L-08-invocation-conflict', severity: 'warning', message: 'The folder says in one place that the model may start this skill and in another that it may not; the stricter one is kept.', file: 'SKILL.md', line: null });
|
|
277
|
+
}
|
|
278
|
+
if (!intent.model && now.model) {
|
|
279
|
+
if (runtime === 'claude') transforms.push({ file: 'SKILL.md', op: 'frontmatter', key: 'disable-model-invocation', value: true, reason: 'Keeps Claude Code from starting it on its own, as the skill\'s other settings say.' });
|
|
280
|
+
else if (runtime === 'codex') transforms.push({ file: CODEX_SIDECAR, op: 'sidecar', path: ['policy', 'allow_implicit_invocation'], value: false, reason: 'Keeps Codex from starting it on its own, as the skill\'s other settings say.' });
|
|
281
|
+
else if (runtime === 'opencode') transforms.push({ file: 'SKILL.md', op: 'metadata', key: 'opencode/autoinvoke', value: 'false', reason: 'Keeps OpenCode\'s model list from offering it, as the skill\'s other settings say.' });
|
|
282
|
+
else diagnostics.push({ ruleId: 'L-08-invocation-unrepresentable', severity: 'error', message: `${profile.title} has no way to keep the model from starting this skill.`, file: 'SKILL.md', line: null });
|
|
283
|
+
}
|
|
284
|
+
if (!intent.user && now.user) {
|
|
285
|
+
if (runtime === 'claude') transforms.push({ file: 'SKILL.md', op: 'frontmatter', key: 'user-invocable', value: false, reason: 'Keeps /name hidden in Claude Code, as the skill\'s other settings say.' });
|
|
286
|
+
else if (runtime === 'antigravity') transforms.push({ file: 'SKILL.md', op: 'frontmatter', key: 'disable-slash-command', value: true, reason: 'Keeps /name hidden in Antigravity, as the skill\'s other settings say.' });
|
|
287
|
+
else diagnostics.push({ ruleId: 'L-08-user-invocation-broader', severity: 'warning', message: `${profile.title} has no setting that hides a skill from the person: there it can still be started by name.`, file: 'SKILL.md', line: null });
|
|
288
|
+
}
|
|
289
|
+
return { transforms, diagnostics };
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// ── Checks ──
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* The problems of a skill for one profile.
|
|
296
|
+
* @param {string} profileId
|
|
297
|
+
* @param {object} o
|
|
298
|
+
* @param {object} o.parsed ss-frontmatter.js parse() of the head file
|
|
299
|
+
* @param {string} [o.folderName] the skill's folder
|
|
300
|
+
* @param {string} [o.headPath] the head file's name as it is in the folder
|
|
301
|
+
* @param {{ path: string, size?: number }[]} [o.files] every file of the folder (for the sidecar's icons)
|
|
302
|
+
* @param {{ present: boolean, data: object|null, error: string|null }|null} [o.sidecar] agents/openai.yaml as read
|
|
303
|
+
* @returns {{ profile: { id, version }, errors: object[], warnings: object[], infos: object[], all: object[] }}
|
|
304
|
+
*/
|
|
305
|
+
export function lintForProfile(profileId, { parsed, folderName = '', headPath = 'SKILL.md', files = [], sidecar = null } = {}) {
|
|
306
|
+
const profile = getProfile(profileId);
|
|
307
|
+
const all = [];
|
|
308
|
+
const add = (ruleId, severity, message, line = null, file = headPath) => all.push({ ruleId, severity, message, line, file, profile: profileId });
|
|
309
|
+
if (!profile) {
|
|
310
|
+
add('profile-unknown', 'error', `There is no profile "${profileId}".`);
|
|
311
|
+
return finish(profileId, null, all);
|
|
312
|
+
}
|
|
313
|
+
const lineOf = (key) => parsed?.keys?.find((k) => k.key === key)?.line ?? (parsed?.split?.startLine || 1);
|
|
314
|
+
for (const d of parsed?.diagnostics || []) if (d.severity === 'error') add(`L-01-${d.ruleId || 'yaml'}`, 'error', d.message, d.line);
|
|
315
|
+
const data = parsed?.data && typeof parsed.data === 'object' ? parsed.data : null;
|
|
316
|
+
const strictPortable = profile.id === 'portable-six-field' || profile.id === 'claude-upload';
|
|
317
|
+
const runtime = profile.runtime;
|
|
318
|
+
|
|
319
|
+
if (profile.id === 'claude-upload' && headPath !== 'SKILL.md') add('L-03-head-name', 'error', 'An upload needs the file named SKILL.md (upper case).');
|
|
320
|
+
if (!parsed?.hasFrontmatter && data) {
|
|
321
|
+
if (profile.fields.required.length) add('L-02-frontmatter-missing', 'error', `${profile.title} needs frontmatter with a name and a description.`, 1);
|
|
322
|
+
}
|
|
323
|
+
if (!data) return finish(profileId, profile, all);
|
|
324
|
+
|
|
325
|
+
// name
|
|
326
|
+
const nameRequired = profile.fields.required.includes('name');
|
|
327
|
+
if (!has(data, 'name')) {
|
|
328
|
+
if (nameRequired && parsed?.hasFrontmatter) add('L-02-name-missing', 'error', `${profile.title} needs a "name".`, lineOf('name'));
|
|
329
|
+
} else {
|
|
330
|
+
const name = data.name;
|
|
331
|
+
if (typeof name !== 'string') add('L-02-name-type', 'error', `"name" must be text; it is ${kindOf(name)}.`, lineOf('name'));
|
|
332
|
+
else if (!name.trim()) add('L-02-name-empty', 'error', '"name" is empty.', lineOf('name'));
|
|
333
|
+
else {
|
|
334
|
+
if (name.length > (profile.limits.nameChars || 64)) add('L-03-name-length', 'error', `"name" is ${name.length} characters; ${profile.title} takes ${profile.limits.nameChars || 64}.`, lineOf('name'));
|
|
335
|
+
const hidden = findHiddenChars(name, { identifier: true });
|
|
336
|
+
if (hidden.length || /[<>]/.test(name)) add('L-03-name-chars', 'error', `"name" holds characters ${profile.title} refuses (${hidden.length ? hidden.map((h) => h.label).join(', ') : 'an angle bracket'}).`, lineOf('name'));
|
|
337
|
+
const portableName = PORTABLE_NAME_RE.test(name);
|
|
338
|
+
if (!portableName) {
|
|
339
|
+
if (strictPortable || runtime === 'opencode' || runtime === 'antigravity') add('L-03-name-format', 'error', `"name" must be lowercase letters, digits and single hyphens for ${profile.title}.`, lineOf('name'));
|
|
340
|
+
else add('L-03-name-format', 'warning', `"name" is not lowercase letters, digits and single hyphens: other runtimes may refuse it.`, lineOf('name'));
|
|
341
|
+
}
|
|
342
|
+
if (folderName && name !== folderName) {
|
|
343
|
+
if (strictPortable || runtime === 'opencode') add('L-03-name-folder', 'error', `"name" is "${name}" but the folder is "${folderName}": ${profile.title} needs them equal.`, lineOf('name'));
|
|
344
|
+
else add('L-03-name-folder', 'warning', `"name" is "${name}" but the folder is "${folderName}".`, lineOf('name'));
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (runtime === 'claude' && folderName === 'synced') add('L-03-reserved', 'error', '"synced" is the folder Claude Code keeps account skills in: a skill cannot use it.', 1);
|
|
349
|
+
if (runtime === 'claude' && typeof data.name === 'string' && /^anthropic-skills(?::|$)/.test(data.name)) add('L-03-reserved', 'warning', '"anthropic-skills" is the namespace of account skills in Claude Code.', lineOf('name'));
|
|
350
|
+
|
|
351
|
+
// description
|
|
352
|
+
const descRequired = profile.fields.required.includes('description');
|
|
353
|
+
if (!has(data, 'description')) {
|
|
354
|
+
if (descRequired && parsed?.hasFrontmatter) add('L-02-description-missing', 'error', `${profile.title} needs a "description": it is how the skill is chosen.`, lineOf('description'));
|
|
355
|
+
else if (!descRequired && runtime === 'claude') add('L-02-description-missing', 'warning', 'No "description": Claude Code falls back to the first line of the body to decide when to use it.', lineOf('description'));
|
|
356
|
+
} else {
|
|
357
|
+
const desc = data.description;
|
|
358
|
+
if (typeof desc !== 'string') add('L-02-description-type', 'error', `"description" must be text; it is ${kindOf(desc)}.`, lineOf('description'));
|
|
359
|
+
else if (!desc.trim()) add('L-02-description-empty', 'error', '"description" is empty.', lineOf('description'));
|
|
360
|
+
else if (desc.length > (profile.limits.descriptionChars || 1024)) {
|
|
361
|
+
add('L-03-description-length', strictPortable || runtime === 'opencode' ? 'error' : 'warning', `"description" is ${desc.length} characters; ${profile.title} takes ${profile.limits.descriptionChars || 1024}.`, lineOf('description'));
|
|
362
|
+
}
|
|
363
|
+
if (runtime === 'claude' && typeof desc === 'string') {
|
|
364
|
+
const listed = desc.length + (typeof data.when_to_use === 'string' ? data.when_to_use.length : 0);
|
|
365
|
+
if (listed > profile.limits.listingChars) add('L-09-listing-cut', 'info', `Claude Code lists the first ${profile.limits.listingChars} characters of the description and when_to_use together (${listed} here).`, lineOf('description'));
|
|
366
|
+
}
|
|
367
|
+
if (profile.id === 'claude-upload' && typeof desc === 'string' && desc.length > 200) add('L-09-upload-description', 'info', 'Claude.ai\'s help asks for 200 characters or fewer; whether the app enforces it is not known.', lineOf('description'));
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// optional portable fields
|
|
371
|
+
if (has(data, 'license') && data.license !== null && typeof data.license !== 'string') add('L-04-license-type', 'error', `"license" must be text; it is ${kindOf(data.license)}.`, lineOf('license'));
|
|
372
|
+
if (has(data, 'compatibility')) {
|
|
373
|
+
const c = data.compatibility;
|
|
374
|
+
if (typeof c !== 'string') add('L-04-compatibility-type', 'error', `"compatibility" must be text; it is ${kindOf(c)}.`, lineOf('compatibility'));
|
|
375
|
+
else if (!c.trim()) add('L-04-compatibility-empty', strictPortable ? 'error' : 'warning', '"compatibility" is empty: leave it out instead.', lineOf('compatibility'));
|
|
376
|
+
else if (c.length > (profile.limits.compatibilityChars || 500)) add('L-04-compatibility-length', strictPortable ? 'error' : 'warning', `"compatibility" is ${c.length} characters; the limit is ${profile.limits.compatibilityChars || 500}.`, lineOf('compatibility'));
|
|
377
|
+
}
|
|
378
|
+
if (has(data, 'metadata')) {
|
|
379
|
+
const meta = data.metadata;
|
|
380
|
+
if (!isMap(meta)) add('L-04-metadata-type', 'error', `"metadata" must be a mapping; it is ${kindOf(meta)}.`, lineOf('metadata'));
|
|
381
|
+
else {
|
|
382
|
+
for (const [key, value] of Object.entries(meta)) {
|
|
383
|
+
if (typeof value === 'string') continue;
|
|
384
|
+
const isOpencodeSwitch = key === 'opencode/autoinvoke' || key === 'opencode/slash';
|
|
385
|
+
if (runtime === 'opencode' && isOpencodeSwitch && typeof value === 'boolean') {
|
|
386
|
+
add('L-04-metadata-value', 'warning', `metadata "${key}" is a YAML ${value}; OpenCode reads it, but write it as text ("${value}") so other runtimes read it too.`, lineOf('metadata'));
|
|
387
|
+
} else if (strictPortable || runtime === 'opencode') {
|
|
388
|
+
add('L-04-metadata-value', 'error', `metadata "${key}" must be text; it is ${kindOf(value)}.`, lineOf('metadata'));
|
|
389
|
+
} else if (runtime !== 'claude') {
|
|
390
|
+
add('L-04-metadata-value', 'warning', `metadata "${key}" is ${kindOf(value)}; the portable format keeps text values only.`, lineOf('metadata'));
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (runtime === 'opencode') {
|
|
394
|
+
for (const key of ['opencode/autoinvoke', 'opencode/slash']) {
|
|
395
|
+
if (has(meta, key) && openSwitch(meta[key]) === null) add('L-04-opencode-switch', 'error', `metadata "${key}" must be "true" or "false".`, lineOf('metadata'));
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (has(data, 'allowed-tools')) {
|
|
401
|
+
const tools = data['allowed-tools'];
|
|
402
|
+
const textOk = typeof tools === 'string';
|
|
403
|
+
const listOk = Array.isArray(tools) && tools.every((t) => typeof t === 'string' && t.trim());
|
|
404
|
+
if (!textOk && !listOk) add('L-04-allowed-tools-type', 'error', `"allowed-tools" must be text or a list of tool names; it is ${kindOf(tools)}.`, lineOf('allowed-tools'));
|
|
405
|
+
else if (strictPortable && !textOk) add('L-04-allowed-tools-list', 'warning', '"allowed-tools" is a list; the portable format writes it as one space-separated text.', lineOf('allowed-tools'));
|
|
406
|
+
if (runtime === 'opencode') add('L-04-ignored-key', 'info', '"allowed-tools" is not one of the fields OpenCode reads: it grants nothing there.', lineOf('allowed-tools'));
|
|
407
|
+
if (runtime === 'codex') add('L-04-ignored-key', 'info', '"allowed-tools" is not read by Codex: Codex\'s own approval settings apply.', lineOf('allowed-tools'));
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Claude Code's own fields
|
|
411
|
+
if (runtime === 'claude') {
|
|
412
|
+
for (const key of ['disable-model-invocation', 'user-invocable', 'background']) {
|
|
413
|
+
if (has(data, key) && claudeBoolean(data[key]) === null) add(`L-04-${key}-type`, 'error', `"${key}" must be true or false; it is ${kindOf(data[key])}.`, lineOf(key));
|
|
414
|
+
}
|
|
415
|
+
if (has(data, 'effort') && !(typeof data.effort === 'string' && EFFORTS.has(data.effort))) add('L-04-effort', 'error', `"effort" must be one of ${[...EFFORTS].join(', ')}.`, lineOf('effort'));
|
|
416
|
+
if (has(data, 'shell') && !(typeof data.shell === 'string' && SHELLS.has(data.shell))) add('L-04-shell', 'error', '"shell" must be bash or powershell.', lineOf('shell'));
|
|
417
|
+
if (has(data, 'context') && data.context !== 'fork') add('L-04-context', 'warning', '"context" takes one value, fork.', lineOf('context'));
|
|
418
|
+
if (has(data, 'background') && data.context !== 'fork') add('L-04-background', 'warning', '"background" applies only with context: fork.', lineOf('background'));
|
|
419
|
+
if (has(data, 'agent') && data.context !== 'fork') add('L-04-agent', 'warning', '"agent" applies only with context: fork.', lineOf('agent'));
|
|
420
|
+
for (const key of ['paths', 'arguments', 'disallowed-tools']) {
|
|
421
|
+
if (!has(data, key)) continue;
|
|
422
|
+
const v = data[key];
|
|
423
|
+
if (!(typeof v === 'string' || (Array.isArray(v) && v.every((x) => typeof x === 'string')))) add(`L-04-${key}-type`, 'error', `"${key}" must be text or a list of text; it is ${kindOf(v)}.`, lineOf(key));
|
|
424
|
+
}
|
|
425
|
+
for (const key of ['model', 'when_to_use', 'argument-hint', 'agent']) {
|
|
426
|
+
if (has(data, key) && data[key] !== null && typeof data[key] !== 'string') add(`L-04-${key}-type`, 'error', `"${key}" must be text; it is ${kindOf(data[key])}.`, lineOf(key));
|
|
427
|
+
}
|
|
428
|
+
if (has(data, 'hooks') && !isMap(data.hooks)) add('L-04-hooks-type', 'error', `"hooks" must be a mapping of events; it is ${kindOf(data.hooks)}.`, lineOf('hooks'));
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Antigravity's own field and limit
|
|
432
|
+
if (runtime === 'antigravity') {
|
|
433
|
+
if (has(data, 'disable-slash-command') && typeof data['disable-slash-command'] !== 'boolean') add('L-04-disable-slash-command-type', 'error', `"disable-slash-command" must be true or false; it is ${kindOf(data['disable-slash-command'])}.`, lineOf('disable-slash-command'));
|
|
434
|
+
const bytes = utf8Length(parsed?.body);
|
|
435
|
+
const max = profile.limits.bodyBytes || ANTIGRAVITY_BODY_BYTES;
|
|
436
|
+
if (bytes > max) add('L-03-body-size', 'error', `The body is ${kb(bytes)}; ${profile.title} reads ${kb(max)} at most. Move detail into files the skill points to.`, parsed?.bodyLine || null);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Keys the profile does not read
|
|
440
|
+
for (const key of Object.keys(data)) {
|
|
441
|
+
if (profile.fields.recognized.includes(key)) continue;
|
|
442
|
+
if (profile.fields.strictTopLevel) add('L-04-upload-key', 'error', `"${key}" is not one of the six fields an upload takes: the upload is refused with it.`, lineOf(key));
|
|
443
|
+
else if (strictPortable) add('L-04-unknown-key', 'warning', `"${key}" is not part of the portable format: a strict validator refuses it, other runtimes ignore it.`, lineOf(key));
|
|
444
|
+
else if (runtime === 'claude') add('L-04-ignored-key', 'info', `Claude Code does not read "${key}"; it is kept as written.`, lineOf(key));
|
|
445
|
+
else if (CLAUDE_FIELDS.includes(key) && key !== 'allowed-tools') add('L-04-ignored-key', 'info', `"${key}" is a Claude Code field: ${profile.title} does not read it.`, lineOf(key));
|
|
446
|
+
else add('L-04-ignored-key', 'info', `${profile.title} does not read "${key}"; it is kept as written.`, lineOf(key));
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (runtime === 'codex') lintCodexSidecar(sidecar, files, add);
|
|
450
|
+
return finish(profileId, profile, all);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/** agents/openai.yaml, as Codex reads it (interface.rs, the creator's reference): what it shows and what it allows. */
|
|
454
|
+
function lintCodexSidecar(sidecar, files, add) {
|
|
455
|
+
if (!sidecar?.present) return;
|
|
456
|
+
const file = CODEX_SIDECAR;
|
|
457
|
+
if (sidecar.error) { add('L-04-sidecar-yaml', 'error', `${file} cannot be read: ${sidecar.error}`, null, file); return; }
|
|
458
|
+
const doc = sidecar.data;
|
|
459
|
+
if (!isMap(doc)) { add('L-04-sidecar-type', 'error', `${file} must be a mapping.`, null, file); return; }
|
|
460
|
+
const paths = new Set((files || []).map((f) => f.path));
|
|
461
|
+
const iface = doc.interface;
|
|
462
|
+
if (iface !== undefined) {
|
|
463
|
+
if (!isMap(iface)) add('L-04-sidecar-interface', 'error', '"interface" must be a mapping.', null, file);
|
|
464
|
+
else {
|
|
465
|
+
const text = (key, max, recommended = null) => {
|
|
466
|
+
if (!has(iface, key) || iface[key] === null) return;
|
|
467
|
+
const v = iface[key];
|
|
468
|
+
if (typeof v !== 'string' || !v.trim()) { add(`L-04-sidecar-${key}`, 'warning', `interface.${key} must be text; Codex ignores it otherwise.`, null, file); return; }
|
|
469
|
+
if (v.length > max) add(`L-04-sidecar-${key}`, 'warning', `interface.${key} is ${v.length} characters; Codex takes ${max}.`, null, file);
|
|
470
|
+
else if (recommended && (v.length < recommended[0] || v.length > recommended[1])) add(`L-09-sidecar-${key}`, 'info', `interface.${key} reads best at ${recommended[0]}–${recommended[1]} characters (${v.length} here).`, null, file);
|
|
471
|
+
};
|
|
472
|
+
text('display_name', 64);
|
|
473
|
+
text('short_description', 1024, [25, 64]);
|
|
474
|
+
text('default_prompt', 1024);
|
|
475
|
+
for (const key of ['icon_small', 'icon_large']) {
|
|
476
|
+
if (!has(iface, key) || iface[key] === null) continue;
|
|
477
|
+
const v = iface[key];
|
|
478
|
+
if (typeof v !== 'string' || !v.trim()) { add(`L-05-sidecar-${key}`, 'warning', `interface.${key} must be a path in the skill.`, null, file); continue; }
|
|
479
|
+
const rel = v.replace(/^\.\//, '');
|
|
480
|
+
if (rel.startsWith('/') || /^[A-Za-z]:/.test(rel) || rel.split('/').includes('..')) { add(`L-05-sidecar-${key}`, 'error', `interface.${key} must be a path inside the skill (${v}).`, null, file); continue; }
|
|
481
|
+
if (!rel.startsWith('assets/')) add(`L-05-sidecar-${key}`, 'warning', `interface.${key} should be under assets/ (${v}).`, null, file);
|
|
482
|
+
if (paths.size && !paths.has(rel)) add(`L-05-sidecar-${key}`, 'error', `interface.${key} names ${v}, which the skill does not have.`, null, file);
|
|
483
|
+
}
|
|
484
|
+
if (has(iface, 'brand_color') && iface.brand_color !== null && !(typeof iface.brand_color === 'string' && /^#[0-9A-Fa-f]{6}$/.test(iface.brand_color))) {
|
|
485
|
+
add('L-04-sidecar-brand_color', 'warning', 'interface.brand_color must be #RRGGBB; Codex ignores it otherwise.', null, file);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
if (doc.policy !== undefined) {
|
|
490
|
+
if (!isMap(doc.policy)) add('L-04-sidecar-policy', 'error', '"policy" must be a mapping.', null, file);
|
|
491
|
+
else if (has(doc.policy, 'allow_implicit_invocation') && typeof doc.policy.allow_implicit_invocation !== 'boolean') add('L-04-sidecar-policy', 'error', 'policy.allow_implicit_invocation must be true or false.', null, file);
|
|
492
|
+
}
|
|
493
|
+
if (doc.dependencies !== undefined) {
|
|
494
|
+
const tools = isMap(doc.dependencies) ? doc.dependencies.tools : undefined;
|
|
495
|
+
if (!isMap(doc.dependencies) || (tools !== undefined && !Array.isArray(tools))) add('L-04-sidecar-dependencies', 'error', 'dependencies.tools must be a list.', null, file);
|
|
496
|
+
else for (const [i, t] of (tools || []).entries()) {
|
|
497
|
+
if (!isMap(t) || typeof t.type !== 'string' || typeof t.value !== 'string') add('L-04-sidecar-dependencies', 'error', `dependencies.tools[${i}] needs a type and a value (text).`, null, file);
|
|
498
|
+
}
|
|
499
|
+
if (Array.isArray(tools) && tools.length) add('L-10-dependencies', 'info', `Declares ${tools.length} tool ${tools.length === 1 ? 'dependency' : 'dependencies'}: a declaration, not a grant; Codex asks for them as usual.`, null, file);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function finish(profileId, profile, all) {
|
|
504
|
+
const rank = { error: 0, warning: 1, info: 2 };
|
|
505
|
+
all.sort((a, b) => (rank[a.severity] - rank[b.severity]) || ((a.line || 0) - (b.line || 0)));
|
|
506
|
+
return {
|
|
507
|
+
profile: { id: profileId, version: profile?.version || null },
|
|
508
|
+
errors: all.filter((d) => d.severity === 'error'),
|
|
509
|
+
warnings: all.filter((d) => d.severity === 'warning'),
|
|
510
|
+
infos: all.filter((d) => d.severity === 'info'),
|
|
511
|
+
all,
|
|
512
|
+
};
|
|
513
|
+
}
|