@litfamily/litopencode 1.0.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/.gitattributes +8 -0
- package/ATTRIBUTION.md +56 -0
- package/CHANGELOG.md +267 -0
- package/CODE_OF_CONDUCT.md +30 -0
- package/CONTRIBUTING.md +82 -0
- package/LICENSE +21 -0
- package/README-Ko-KR.md +252 -0
- package/README.md +252 -0
- package/SECURITY.md +36 -0
- package/SUPPORT.md +37 -0
- package/bin/litopencode +3 -0
- package/bin/litopencode.cjs +10 -0
- package/dist/activation-managed-prompts.d.ts +2 -0
- package/dist/activation-managed-prompts.js +51 -0
- package/dist/activation-primary-prompts.d.ts +2 -0
- package/dist/activation-primary-prompts.js +176 -0
- package/dist/activation-probe.d.ts +3 -0
- package/dist/activation-probe.js +19 -0
- package/dist/activation-prompt-utils.d.ts +6 -0
- package/dist/activation-prompt-utils.js +36 -0
- package/dist/activation-routing.d.ts +5 -0
- package/dist/activation-routing.js +340 -0
- package/dist/activation-workflow-prompts.d.ts +26 -0
- package/dist/activation-workflow-prompts.js +295 -0
- package/dist/activation.d.ts +24 -0
- package/dist/activation.js +152 -0
- package/dist/agents/defaults.d.ts +15 -0
- package/dist/agents/defaults.js +112 -0
- package/dist/agents/registry.d.ts +65 -0
- package/dist/agents/registry.js +319 -0
- package/dist/agents/specialists.d.ts +49 -0
- package/dist/agents/specialists.js +307 -0
- package/dist/agents/types.d.ts +55 -0
- package/dist/agents/types.js +4 -0
- package/dist/agents.d.ts +4 -0
- package/dist/agents.js +3 -0
- package/dist/benchmark.d.ts +94 -0
- package/dist/benchmark.js +172 -0
- package/dist/bounded-authority-hooks.d.ts +19 -0
- package/dist/bounded-authority-hooks.js +157 -0
- package/dist/bounded-authority.d.ts +184 -0
- package/dist/bounded-authority.js +825 -0
- package/dist/cache-metrics.d.ts +54 -0
- package/dist/cache-metrics.js +81 -0
- package/dist/cli/args.d.ts +5 -0
- package/dist/cli/args.js +415 -0
- package/dist/cli/auto-update.d.ts +117 -0
- package/dist/cli/auto-update.js +604 -0
- package/dist/cli/command-alias-ownership.d.ts +2 -0
- package/dist/cli/command-alias-ownership.js +14 -0
- package/dist/cli/command-aliases.d.ts +12 -0
- package/dist/cli/command-aliases.js +112 -0
- package/dist/cli/doctor.d.ts +2 -0
- package/dist/cli/doctor.js +175 -0
- package/dist/cli/host-capabilities.d.ts +12 -0
- package/dist/cli/host-capabilities.js +25 -0
- package/dist/cli/host-limits.d.ts +21 -0
- package/dist/cli/host-limits.js +83 -0
- package/dist/cli/install-config.d.ts +13 -0
- package/dist/cli/install-config.js +201 -0
- package/dist/cli/install-report.d.ts +2 -0
- package/dist/cli/install-report.js +180 -0
- package/dist/cli/install-tui.d.ts +12 -0
- package/dist/cli/install-tui.js +174 -0
- package/dist/cli/install.d.ts +2 -0
- package/dist/cli/install.js +264 -0
- package/dist/cli/json.d.ts +4 -0
- package/dist/cli/json.js +31 -0
- package/dist/cli/loop.d.ts +3 -0
- package/dist/cli/loop.js +135 -0
- package/dist/cli/lsp-capability.d.ts +17 -0
- package/dist/cli/lsp-capability.js +92 -0
- package/dist/cli/managed-skill-assets.d.ts +23 -0
- package/dist/cli/managed-skill-assets.js +117 -0
- package/dist/cli/model-catalog.d.ts +21 -0
- package/dist/cli/model-catalog.js +107 -0
- package/dist/cli/model-policy.d.ts +3 -0
- package/dist/cli/model-policy.js +143 -0
- package/dist/cli/model-routing.d.ts +5 -0
- package/dist/cli/model-routing.js +208 -0
- package/dist/cli/native-canonical-backup.d.ts +9 -0
- package/dist/cli/native-canonical-backup.js +96 -0
- package/dist/cli/native-canonical-cache.d.ts +9 -0
- package/dist/cli/native-canonical-cache.js +37 -0
- package/dist/cli/native-skill-install.d.ts +2 -0
- package/dist/cli/native-skill-install.js +128 -0
- package/dist/cli/native-skill-integrity.d.ts +25 -0
- package/dist/cli/native-skill-integrity.js +178 -0
- package/dist/cli/native-skill-tree.d.ts +12 -0
- package/dist/cli/native-skill-tree.js +104 -0
- package/dist/cli/native-skills.d.ts +22 -0
- package/dist/cli/native-skills.js +105 -0
- package/dist/cli/plugin-mutation.d.ts +4 -0
- package/dist/cli/plugin-mutation.js +89 -0
- package/dist/cli/scientific-visualization-dependencies.d.ts +18 -0
- package/dist/cli/scientific-visualization-dependencies.js +91 -0
- package/dist/cli/skill-loop.d.ts +3 -0
- package/dist/cli/skill-loop.js +649 -0
- package/dist/cli/types.d.ts +188 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/update-check.d.ts +2 -0
- package/dist/cli/update-check.js +15 -0
- package/dist/cli/update-notifier.d.ts +70 -0
- package/dist/cli/update-notifier.js +717 -0
- package/dist/cli/vendor-path-migration.d.ts +9 -0
- package/dist/cli/vendor-path-migration.js +96 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.js +250 -0
- package/dist/commands.d.ts +331 -0
- package/dist/commands.js +600 -0
- package/dist/config-parser.d.ts +5 -0
- package/dist/config-parser.js +274 -0
- package/dist/config.d.ts +72 -0
- package/dist/config.js +157 -0
- package/dist/deliverable-hedge-guard.d.ts +26 -0
- package/dist/deliverable-hedge-guard.js +302 -0
- package/dist/durable-plan.d.ts +23 -0
- package/dist/durable-plan.js +349 -0
- package/dist/features.d.ts +828 -0
- package/dist/features.js +1109 -0
- package/dist/hooks.d.ts +17 -0
- package/dist/hooks.js +83 -0
- package/dist/ignition.d.ts +14 -0
- package/dist/ignition.js +33 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +30 -0
- package/dist/inert-data.d.ts +2 -0
- package/dist/inert-data.js +13 -0
- package/dist/knowledge.d.ts +98 -0
- package/dist/knowledge.js +961 -0
- package/dist/ledger.d.ts +181 -0
- package/dist/ledger.js +1179 -0
- package/dist/lit-fetch-classify.d.ts +8 -0
- package/dist/lit-fetch-classify.js +107 -0
- package/dist/lit-fetch-content.d.ts +2 -0
- package/dist/lit-fetch-content.js +43 -0
- package/dist/lit-fetch-http.d.ts +10 -0
- package/dist/lit-fetch-http.js +82 -0
- package/dist/lit-fetch-result.d.ts +2 -0
- package/dist/lit-fetch-result.js +65 -0
- package/dist/lit-fetch-ssrf.d.ts +9 -0
- package/dist/lit-fetch-ssrf.js +77 -0
- package/dist/lit-fetch-url.d.ts +3 -0
- package/dist/lit-fetch-url.js +28 -0
- package/dist/lit-fetch.d.ts +69 -0
- package/dist/lit-fetch.js +84 -0
- package/dist/lit-mark.d.ts +17 -0
- package/dist/lit-mark.js +129 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.js +21 -0
- package/dist/model-route-policy.d.ts +25 -0
- package/dist/model-route-policy.js +129 -0
- package/dist/reader-facing-output.d.ts +3 -0
- package/dist/reader-facing-output.js +28 -0
- package/dist/rules/discovery.d.ts +36 -0
- package/dist/rules/discovery.js +270 -0
- package/dist/rules/engine.d.ts +43 -0
- package/dist/rules/engine.js +236 -0
- package/dist/rules/frontmatter.d.ts +16 -0
- package/dist/rules/frontmatter.js +179 -0
- package/dist/rules/glob.d.ts +12 -0
- package/dist/rules/glob.js +233 -0
- package/dist/rules/hooks.d.ts +25 -0
- package/dist/rules/hooks.js +75 -0
- package/dist/rules/output-style.d.ts +1 -0
- package/dist/rules/output-style.js +20 -0
- package/dist/scientific-visualization-banner.d.ts +1 -0
- package/dist/scientific-visualization-banner.js +2 -0
- package/dist/search-workflow-ideas.d.ts +67 -0
- package/dist/search-workflow-ideas.js +128 -0
- package/dist/secret-shapes.d.ts +9 -0
- package/dist/secret-shapes.js +63 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +129 -0
- package/dist/session-lineage.d.ts +8 -0
- package/dist/session-lineage.js +12 -0
- package/dist/skill-loop/apply.d.ts +19 -0
- package/dist/skill-loop/apply.js +483 -0
- package/dist/skill-loop/config.d.ts +50 -0
- package/dist/skill-loop/config.js +215 -0
- package/dist/skill-loop/curator.d.ts +18 -0
- package/dist/skill-loop/curator.js +232 -0
- package/dist/skill-loop/ledger.d.ts +39 -0
- package/dist/skill-loop/ledger.js +344 -0
- package/dist/skill-loop/proposals.d.ts +48 -0
- package/dist/skill-loop/proposals.js +290 -0
- package/dist/skill-loop/storage.d.ts +72 -0
- package/dist/skill-loop/storage.js +817 -0
- package/dist/skill-loop/time.d.ts +2 -0
- package/dist/skill-loop/time.js +23 -0
- package/dist/skill-loop/transaction.d.ts +62 -0
- package/dist/skill-loop/transaction.js +836 -0
- package/dist/skill-loop/usage.d.ts +31 -0
- package/dist/skill-loop/usage.js +146 -0
- package/dist/skill-observer.d.ts +22 -0
- package/dist/skill-observer.js +1154 -0
- package/dist/skill-renames.d.ts +5 -0
- package/dist/skill-renames.js +8 -0
- package/dist/skills.d.ts +307 -0
- package/dist/skills.js +450 -0
- package/dist/stable-identity.d.ts +14 -0
- package/dist/stable-identity.js +15 -0
- package/dist/state.d.ts +25 -0
- package/dist/state.js +38 -0
- package/dist/strict-json.d.ts +2 -0
- package/dist/strict-json.js +94 -0
- package/dist/tool-guards.d.ts +34 -0
- package/dist/tool-guards.js +210 -0
- package/dist/tool-kit.d.ts +32 -0
- package/dist/tool-kit.js +75 -0
- package/dist/tools.d.ts +43 -0
- package/dist/tools.js +381 -0
- package/dist/uiux-visual-catalog.d.ts +50 -0
- package/dist/uiux-visual-catalog.js +103 -0
- package/dist/user-facing-markdown.d.ts +5 -0
- package/dist/user-facing-markdown.js +93 -0
- package/dist/workflow-families.d.ts +16 -0
- package/dist/workflow-families.js +95 -0
- package/docs/assets/cover.webp +0 -0
- package/docs/assets/litopencode-continuity-1600.webp +0 -0
- package/docs/assets/litopencode-ignition-1600.webp +0 -0
- package/docs/assets/readme/badge-license.svg +1 -0
- package/docs/assets/readme/badge-version.svg +1 -0
- package/docs/assets/readme/litopencode-clay-icon.png +0 -0
- package/docs/assets/readme/litopencode-wordmark.svg +5 -0
- package/docs/lit-mark.md +46 -0
- package/docs/migration.md +162 -0
- package/docs/privacy.md +82 -0
- package/docs/reference-Ko-KR.md +309 -0
- package/docs/reference.md +444 -0
- package/output-styles/asd-ste100-ko.md +41 -0
- package/output-styles/asd-ste100.md +40 -0
- package/output-styles/eli5-ko.md +13 -0
- package/output-styles/eli5.md +11 -0
- package/package.json +57 -0
- package/qa/fixtures/litfamily-harness-speed-v1.json +38 -0
- package/qa/harness-speed-contract.mjs +209 -0
- package/qa/harness-speed-v2-contract.mjs +213 -0
- package/qa/harness-speed-verdict.mjs +105 -0
- package/skills/agent-roster/SKILL.md +262 -0
- package/skills/autoconference/LICENSE +21 -0
- package/skills/autoconference/PROVENANCE.md +20 -0
- package/skills/autoconference/SKILL.md +125 -0
- package/skills/autoconference/assets/conference_template.md +76 -0
- package/skills/autoconference/assets/report_template.md +53 -0
- package/skills/autoconference/assets/synthesis_template.md +39 -0
- package/skills/autoconference/modes/analyze.md +255 -0
- package/skills/autoconference/modes/core.md +112 -0
- package/skills/autoconference/modes/debate.md +373 -0
- package/skills/autoconference/modes/plan.md +310 -0
- package/skills/autoconference/modes/resume.md +48 -0
- package/skills/autoconference/modes/ship.md +57 -0
- package/skills/autoconference/modes/survey.md +109 -0
- package/skills/autoconference/references/agent-prompts.md +134 -0
- package/skills/autoconference/references/conference-protocol.md +102 -0
- package/skills/autoconference/references/convergence-guide.md +167 -0
- package/skills/autoconference/references/core-principles.md +83 -0
- package/skills/autoconference/references/crash-recovery.md +104 -0
- package/skills/autoconference/references/results-logging.md +198 -0
- package/skills/autoconference/references/upstream-family-contract.md +130 -0
- package/skills/autoconference/references/visualization-guide.md +105 -0
- package/skills/autoconference/scripts/check_conference.sh +371 -0
- package/skills/autoconference/scripts/init_conference.py +625 -0
- package/skills/autoconference/scripts/style_presets.py +104 -0
- package/skills/autoresearch/LICENSE +21 -0
- package/skills/autoresearch/PROVENANCE.md +20 -0
- package/skills/autoresearch/SKILL.md +131 -0
- package/skills/autoresearch/assets/report_template.md +50 -0
- package/skills/autoresearch/assets/research_template.md +38 -0
- package/skills/autoresearch/assets/results_template.tsv +1 -0
- package/skills/autoresearch/modes/core.md +216 -0
- package/skills/autoresearch/modes/debug.md +235 -0
- package/skills/autoresearch/modes/fix.md +173 -0
- package/skills/autoresearch/modes/learn.md +91 -0
- package/skills/autoresearch/modes/plan.md +291 -0
- package/skills/autoresearch/modes/predict.md +266 -0
- package/skills/autoresearch/modes/reason.md +170 -0
- package/skills/autoresearch/modes/scenario.md +164 -0
- package/skills/autoresearch/modes/security.md +282 -0
- package/skills/autoresearch/modes/ship.md +49 -0
- package/skills/autoresearch/references/core-principles.md +80 -0
- package/skills/autoresearch/references/evaluator-contract.md +126 -0
- package/skills/autoresearch/references/investigation-techniques.md +205 -0
- package/skills/autoresearch/references/owasp-checklist.md +161 -0
- package/skills/autoresearch/references/persona-templates.md +232 -0
- package/skills/autoresearch/references/results-logging.md +96 -0
- package/skills/autoresearch/references/scenario-dimensions.md +178 -0
- package/skills/autoresearch/references/stride-model.md +196 -0
- package/skills/autoresearch/references/stuck-detection.md +107 -0
- package/skills/autoresearch/references/type-checklists.md +163 -0
- package/skills/autoresearch/references/upstream-family-contract.md +125 -0
- package/skills/autoresearch/references/visualization-guide.md +95 -0
- package/skills/autoresearch/scripts/check_progress.sh +272 -0
- package/skills/autoresearch/scripts/init_research.py +330 -0
- package/skills/autoresearch/scripts/run_with_deadline.py +164 -0
- package/skills/autoresearch/scripts/style_presets.py +104 -0
- package/skills/browser-drive/SKILL.md +133 -0
- package/skills/browser-drive/references/snapshot-act-loop.md +37 -0
- package/skills/browser-drive/scripts/capability-probe.mjs +262 -0
- package/skills/comment-checker/SKILL.md +171 -0
- package/skills/debugging/SKILL.md +202 -0
- package/skills/debugging/references/README.md +15 -0
- package/skills/debugging/references/escalation.md +43 -0
- package/skills/debugging/references/runtimes/README.md +17 -0
- package/skills/debugging/references/runtimes/bundled-js-binary.md +44 -0
- package/skills/debugging/references/runtimes/go.md +37 -0
- package/skills/debugging/references/runtimes/native-binary.md +44 -0
- package/skills/debugging/references/runtimes/node.md +43 -0
- package/skills/debugging/references/runtimes/python.md +41 -0
- package/skills/debugging/references/runtimes/rust.md +37 -0
- package/skills/debugging/references/tools.md +72 -0
- package/skills/deep-interview/SKILL.md +201 -0
- package/skills/doctor-installer/SKILL.md +252 -0
- package/skills/durable-litgoal/SKILL.md +248 -0
- package/skills/frontend-ui-ux/SKILL.md +70 -0
- package/skills/frontend-ui-ux/data/LICENSE +21 -0
- package/skills/frontend-ui-ux/data/PROVENANCE.json +1088 -0
- package/skills/frontend-ui-ux/data/THIRD-PARTY-NOTICE.txt +14 -0
- package/skills/frontend-ui-ux/data/design-intelligence.json +1 -0
- package/skills/frontend-ui-ux/references/_canonical-corpus/ATTRIBUTION.md +217 -0
- package/skills/frontend-ui-ux/references/_canonical-corpus/LICENSE +21 -0
- package/skills/frontend-ui-ux/references/_canonical-corpus/LICENSE-Apache-2.0.txt +201 -0
- package/skills/frontend-ui-ux/references/_canonical-corpus/manifest.json +867 -0
- package/skills/frontend-ui-ux/references/adaptive-layout.md +85 -0
- package/skills/frontend-ui-ux/references/brand-and-imagery.md +79 -0
- package/skills/frontend-ui-ux/references/complete-contract.md +282 -0
- package/skills/frontend-ui-ux/references/composition.md +87 -0
- package/skills/frontend-ui-ux/references/creative-directions.md +83 -0
- package/skills/frontend-ui-ux/references/design/README.md +248 -0
- package/skills/frontend-ui-ux/references/design/_INDEX.md +191 -0
- package/skills/frontend-ui-ux/references/design/airbnb.md +393 -0
- package/skills/frontend-ui-ux/references/design/airtable.md +92 -0
- package/skills/frontend-ui-ux/references/design/apple.md +250 -0
- package/skills/frontend-ui-ux/references/design/aside.md +209 -0
- package/skills/frontend-ui-ux/references/design/binance.md +348 -0
- package/skills/frontend-ui-ux/references/design/bmw.md +183 -0
- package/skills/frontend-ui-ux/references/design/brutalist-skill.md +92 -0
- package/skills/frontend-ui-ux/references/design/bugatti.md +271 -0
- package/skills/frontend-ui-ux/references/design/cal.md +262 -0
- package/skills/frontend-ui-ux/references/design/claude.md +315 -0
- package/skills/frontend-ui-ux/references/design/clay.md +307 -0
- package/skills/frontend-ui-ux/references/design/clickhouse.md +284 -0
- package/skills/frontend-ui-ux/references/design/clone-from-url.md +65 -0
- package/skills/frontend-ui-ux/references/design/cohere.md +269 -0
- package/skills/frontend-ui-ux/references/design/coinbase.md +132 -0
- package/skills/frontend-ui-ux/references/design/composio.md +310 -0
- package/skills/frontend-ui-ux/references/design/cursor.md +312 -0
- package/skills/frontend-ui-ux/references/design/design-system-architecture.md +244 -0
- package/skills/frontend-ui-ux/references/design/elevenlabs.md +268 -0
- package/skills/frontend-ui-ux/references/design/expo.md +284 -0
- package/skills/frontend-ui-ux/references/design/ferrari.md +317 -0
- package/skills/frontend-ui-ux/references/design/figma.md +223 -0
- package/skills/frontend-ui-ux/references/design/framer.md +249 -0
- package/skills/frontend-ui-ux/references/design/gpt-tasteskill.md +74 -0
- package/skills/frontend-ui-ux/references/design/hashicorp.md +281 -0
- package/skills/frontend-ui-ux/references/design/ibm.md +335 -0
- package/skills/frontend-ui-ux/references/design/image-to-code-skill.md +1228 -0
- package/skills/frontend-ui-ux/references/design/imagegen-brandkit.md +798 -0
- package/skills/frontend-ui-ux/references/design/imagegen-frontend-mobile.md +1465 -0
- package/skills/frontend-ui-ux/references/design/imagegen-frontend-web.md +987 -0
- package/skills/frontend-ui-ux/references/design/intercom.md +149 -0
- package/skills/frontend-ui-ux/references/design/kraken.md +128 -0
- package/skills/frontend-ui-ux/references/design/lamborghini.md +291 -0
- package/skills/frontend-ui-ux/references/design/layout-skill.md +107 -0
- package/skills/frontend-ui-ux/references/design/lazyweb.md +77 -0
- package/skills/frontend-ui-ux/references/design/linear.app.md +370 -0
- package/skills/frontend-ui-ux/references/design/lovable.md +301 -0
- package/skills/frontend-ui-ux/references/design/mastercard.md +368 -0
- package/skills/frontend-ui-ux/references/design/meta.md +369 -0
- package/skills/frontend-ui-ux/references/design/minimalist-skill.md +85 -0
- package/skills/frontend-ui-ux/references/design/minimax.md +260 -0
- package/skills/frontend-ui-ux/references/design/mintlify.md +329 -0
- package/skills/frontend-ui-ux/references/design/miro.md +111 -0
- package/skills/frontend-ui-ux/references/design/mistral.ai.md +264 -0
- package/skills/frontend-ui-ux/references/design/mongodb.md +269 -0
- package/skills/frontend-ui-ux/references/design/nike.md +366 -0
- package/skills/frontend-ui-ux/references/design/notion.md +312 -0
- package/skills/frontend-ui-ux/references/design/nvidia.md +296 -0
- package/skills/frontend-ui-ux/references/design/ollama.md +270 -0
- package/skills/frontend-ui-ux/references/design/opencode.ai.md +284 -0
- package/skills/frontend-ui-ux/references/design/output-skill.md +49 -0
- package/skills/frontend-ui-ux/references/design/pinterest.md +233 -0
- package/skills/frontend-ui-ux/references/design/playstation.md +367 -0
- package/skills/frontend-ui-ux/references/design/posthog.md +259 -0
- package/skills/frontend-ui-ux/references/design/raycast.md +271 -0
- package/skills/frontend-ui-ux/references/design/react-dev-tooling-skill.md +230 -0
- package/skills/frontend-ui-ux/references/design/redesign-skill.md +178 -0
- package/skills/frontend-ui-ux/references/design/renault.md +314 -0
- package/skills/frontend-ui-ux/references/design/replicate.md +264 -0
- package/skills/frontend-ui-ux/references/design/resend.md +306 -0
- package/skills/frontend-ui-ux/references/design/revolut.md +188 -0
- package/skills/frontend-ui-ux/references/design/runwayml.md +247 -0
- package/skills/frontend-ui-ux/references/design/sanity.md +360 -0
- package/skills/frontend-ui-ux/references/design/sentry.md +265 -0
- package/skills/frontend-ui-ux/references/design/shopify.md +353 -0
- package/skills/frontend-ui-ux/references/design/soft-skill.md +98 -0
- package/skills/frontend-ui-ux/references/design/spacex.md +197 -0
- package/skills/frontend-ui-ux/references/design/spotify.md +249 -0
- package/skills/frontend-ui-ux/references/design/starbucks.md +583 -0
- package/skills/frontend-ui-ux/references/design/stitch-design-example.md +121 -0
- package/skills/frontend-ui-ux/references/design/stitch-skill.md +184 -0
- package/skills/frontend-ui-ux/references/design/stripe.md +325 -0
- package/skills/frontend-ui-ux/references/design/supabase.md +258 -0
- package/skills/frontend-ui-ux/references/design/superhuman.md +255 -0
- package/skills/frontend-ui-ux/references/design/taste-skill.md +1206 -0
- package/skills/frontend-ui-ux/references/design/tesla.md +289 -0
- package/skills/frontend-ui-ux/references/design/theverge.md +342 -0
- package/skills/frontend-ui-ux/references/design/together.ai.md +266 -0
- package/skills/frontend-ui-ux/references/design/uber.md +298 -0
- package/skills/frontend-ui-ux/references/design/vercel.md +313 -0
- package/skills/frontend-ui-ux/references/design/vodafone.md +426 -0
- package/skills/frontend-ui-ux/references/design/voltagent.md +326 -0
- package/skills/frontend-ui-ux/references/design/warp.md +256 -0
- package/skills/frontend-ui-ux/references/design/webflow.md +95 -0
- package/skills/frontend-ui-ux/references/design/wired.md +281 -0
- package/skills/frontend-ui-ux/references/design/wise.md +176 -0
- package/skills/frontend-ui-ux/references/design/x.ai.md +260 -0
- package/skills/frontend-ui-ux/references/design/zapier.md +331 -0
- package/skills/frontend-ui-ux/references/designpowers/EVIDENCE.md +97 -0
- package/skills/frontend-ui-ux/references/designpowers/README.md +48 -0
- package/skills/frontend-ui-ux/references/designpowers/UPSTREAM.md +80 -0
- package/skills/frontend-ui-ux/references/designpowers/lane-a-direction.md +64 -0
- package/skills/frontend-ui-ux/references/designpowers/lane-b-execution.md +65 -0
- package/skills/frontend-ui-ux/references/designpowers/lane-c-review.md +65 -0
- package/skills/frontend-ui-ux/references/designpowers/lane-d-memory.md +83 -0
- package/skills/frontend-ui-ux/references/designpowers/orchestration.md +80 -0
- package/skills/frontend-ui-ux/references/designpowers/routing.md +79 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/LICENSE +21 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/agents/accessibility-reviewer.md +83 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/agents/content-writer.md +132 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/agents/design-builder.md +109 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/agents/design-critic.md +89 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/agents/design-lead.md +113 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/agents/design-scout.md +78 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/agents/design-strategist.md +121 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/agents/heuristic-evaluator.md +268 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/agents/inspiration-scout.md +107 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/agents/motion-designer.md +120 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/accessible-content/reference.md +101 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/adaptive-interfaces/reference.md +109 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/cognitive-accessibility/reference.md +107 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/design-debate/reference.md +199 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/design-debt-tracker/reference.md +174 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/design-handoff/reference.md +125 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/design-md/reference.md +106 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/design-retrospective/reference.md +266 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/design-review/reference.md +123 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/design-system-alignment/reference.md +120 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/designpowers-critique/reference.md +164 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/heuristic-evaluation/reference.md +85 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/inclusive-personas/reference.md +98 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/inspiration-scouting/reference.md +165 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/interaction-design/reference.md +122 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/motion-choreography/reference.md +81 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/research-planning/reference.md +96 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/responsive-patterns/reference.md +77 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/synthetic-user-testing/reference.md +192 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/taste-feedback/reference.md +165 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/taste-report/reference.md +78 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/token-architecture/reference.md +75 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/ui-composition/reference.md +117 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/usability-testing/reference.md +78 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/verification-before-shipping/reference.md +125 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/voice-and-tone/reference.md +79 -0
- package/skills/frontend-ui-ux/references/designpowers/vendor/skills/writing-design-plans/reference.md +119 -0
- package/skills/frontend-ui-ux/references/evidence-review.md +103 -0
- package/skills/frontend-ui-ux/references/implementation-platforms.md +94 -0
- package/skills/frontend-ui-ux/references/inclusive-interface.md +85 -0
- package/skills/frontend-ui-ux/references/interaction-motion.md +93 -0
- package/skills/frontend-ui-ux/references/operating-lanes.md +80 -0
- package/skills/frontend-ui-ux/references/perfection/README.md +160 -0
- package/skills/frontend-ui-ux/references/perfection/react-perf-tooling.md +127 -0
- package/skills/frontend-ui-ux/references/performance-delivery.md +77 -0
- package/skills/frontend-ui-ux/references/product-direction.md +84 -0
- package/skills/frontend-ui-ux/references/redesign-playbook.md +88 -0
- package/skills/frontend-ui-ux/references/system-foundations.md +86 -0
- package/skills/frontend-ui-ux/references/taste-direction.md +55 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/README.md +659 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/charts.csv +26 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/colors.csv +162 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/icons.csv +106 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/landing.csv +35 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/products.csv +162 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/react-performance.csv +45 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/stacks/astro.csv +54 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/stacks/flutter.csv +53 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/stacks/html-tailwind.csv +56 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/stacks/jetpack-compose.csv +53 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/stacks/nextjs.csv +53 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/stacks/nuxt-ui.csv +51 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/stacks/nuxtjs.csv +59 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/stacks/react-native.csv +52 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/stacks/react.csv +54 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/stacks/shadcn.csv +61 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/stacks/svelte.csv +54 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/stacks/swiftui.csv +51 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/stacks/vue.csv +50 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/styles.csv +85 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/typography.csv +74 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/ui-reasoning.csv +162 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/ux-guidelines.csv +100 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/data/web-interface.csv +31 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/scripts/core.py +262 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/scripts/design_system.py +1148 -0
- package/skills/frontend-ui-ux/references/ui-ux-db/scripts/search.py +114 -0
- package/skills/frontend-ui-ux/references/visual-language.md +84 -0
- package/skills/frontend-ui-ux/references/visual-reconstruction.md +87 -0
- package/skills/frontend-ui-ux/schemas/design-contract-v1alpha1.json +570 -0
- package/skills/frontend-ui-ux/schemas/design-contract-v1beta1.json +32 -0
- package/skills/frontend-ui-ux/schemas/design-contract-v1beta2.json +34 -0
- package/skills/frontend-ui-ux/scripts/bounded-json.mjs +45 -0
- package/skills/frontend-ui-ux/scripts/canonical-json.mjs +26 -0
- package/skills/frontend-ui-ux/scripts/contract-error.mjs +15 -0
- package/skills/frontend-ui-ux/scripts/csv.mjs +64 -0
- package/skills/frontend-ui-ux/scripts/dataset.mjs +65 -0
- package/skills/frontend-ui-ux/scripts/design-contract.mjs +609 -0
- package/skills/frontend-ui-ux/scripts/import-design-intelligence.mjs +193 -0
- package/skills/frontend-ui-ux/scripts/retrieval.mjs +92 -0
- package/skills/frontend-ui-ux/scripts/stable-file-read.mjs +237 -0
- package/skills/frontend-ui-ux/scripts/stdin-json.mjs +16 -0
- package/skills/frontend-ui-ux/scripts/strict-json.mjs +102 -0
- package/skills/frontend-ui-ux/scripts/uiux.mjs +86 -0
- package/skills/frontend-ui-ux/scripts/verify-canonical-corpus.mjs +266 -0
- package/skills/lit-burnoff/SKILL.md +227 -0
- package/skills/lit-burnoff-file/SKILL.md +175 -0
- package/skills/lit-code/SKILL.md +266 -0
- package/skills/lit-code/references/README.md +18 -0
- package/skills/lit-code/references/go/README.md +12 -0
- package/skills/lit-code/references/go/concurrency.md +42 -0
- package/skills/lit-code/references/go/error-handling.md +47 -0
- package/skills/lit-code/references/go/testing.md +55 -0
- package/skills/lit-code/references/go/tooling.md +35 -0
- package/skills/lit-code/references/go/type-patterns.md +50 -0
- package/skills/lit-code/references/python/README.md +12 -0
- package/skills/lit-code/references/python/async.md +50 -0
- package/skills/lit-code/references/python/error-handling.md +44 -0
- package/skills/lit-code/references/python/testing.md +50 -0
- package/skills/lit-code/references/python/tooling.md +38 -0
- package/skills/lit-code/references/python/type-patterns.md +46 -0
- package/skills/lit-code/references/rust/README.md +12 -0
- package/skills/lit-code/references/rust/concurrency.md +45 -0
- package/skills/lit-code/references/rust/error-handling.md +43 -0
- package/skills/lit-code/references/rust/tooling.md +36 -0
- package/skills/lit-code/references/rust/type-patterns.md +46 -0
- package/skills/lit-code/references/rust/unsafe.md +47 -0
- package/skills/lit-code/references/typescript/README.md +11 -0
- package/skills/lit-code/references/typescript/error-handling.md +56 -0
- package/skills/lit-code/references/typescript/testing.md +42 -0
- package/skills/lit-code/references/typescript/tsconfig-strict.md +40 -0
- package/skills/lit-code/references/typescript/type-patterns.md +60 -0
- package/skills/lit-commit/SKILL.md +222 -0
- package/skills/lit-comprehend/SKILL.md +278 -0
- package/skills/lit-comprehend/assets/explainer-scaffold.html +104 -0
- package/skills/lit-comprehend/references/artifact-template.md +114 -0
- package/skills/lit-comprehend/references/micro-worlds.md +115 -0
- package/skills/lit-comprehend/scripts/verify-explainer.ts +339 -0
- package/skills/lit-crucible/SKILL.md +212 -0
- package/skills/lit-fetch/SKILL.md +242 -0
- package/skills/lit-handoff/SKILL.md +199 -0
- package/skills/lit-init/SKILL.md +214 -0
- package/skills/lit-korean/SKILL.md +231 -0
- package/skills/lit-plan/SKILL.md +351 -0
- package/skills/lit-plan/scripts/scaffold-plan.mjs +275 -0
- package/skills/lit-recap/SKILL.md +233 -0
- package/skills/lit-scientific-visualization/SKILL.md +175 -0
- package/skills/litresearch/SKILL.md +436 -0
- package/skills/litwork/SKILL.md +227 -0
- package/skills/lsp/SKILL.md +186 -0
- package/skills/lsp-setup/SKILL.md +187 -0
- package/skills/lsp-setup/references/README.md +40 -0
- package/skills/lsp-setup/references/bash.md +31 -0
- package/skills/lsp-setup/references/c-cpp.md +43 -0
- package/skills/lsp-setup/references/csharp.md +29 -0
- package/skills/lsp-setup/references/dart.md +25 -0
- package/skills/lsp-setup/references/elixir.md +30 -0
- package/skills/lsp-setup/references/go.md +33 -0
- package/skills/lsp-setup/references/haskell.md +27 -0
- package/skills/lsp-setup/references/java.md +28 -0
- package/skills/lsp-setup/references/julia.md +28 -0
- package/skills/lsp-setup/references/kotlin.md +25 -0
- package/skills/lsp-setup/references/lua.md +26 -0
- package/skills/lsp-setup/references/php.md +30 -0
- package/skills/lsp-setup/references/python.md +33 -0
- package/skills/lsp-setup/references/ruby.md +34 -0
- package/skills/lsp-setup/references/rust.md +34 -0
- package/skills/lsp-setup/references/swift.md +26 -0
- package/skills/lsp-setup/references/terraform.md +26 -0
- package/skills/lsp-setup/references/typescript.md +35 -0
- package/skills/lsp-setup/references/yaml.md +27 -0
- package/skills/lsp-setup/references/zig.md +28 -0
- package/skills/managed-skill-manifest.json +1386 -0
- package/skills/native-goal-verdict/SKILL.md +216 -0
- package/skills/refactor/SKILL.md +221 -0
- package/skills/reference-benchmark-claims/SKILL.md +204 -0
- package/skills/release-guardrails/SKILL.md +245 -0
- package/skills/review-work/SKILL.md +301 -0
- package/skills/rules/SKILL.md +196 -0
- package/skills/search-workflow-ideas/SKILL.md +223 -0
- package/skills/skill-observer/SKILL.md +148 -0
- package/skills/skill-observer/references/review-contract.md +95 -0
- package/skills/skill-rename-aliases.json +10 -0
- package/skills/start-work/SKILL.md +334 -0
- package/skills/structural-search/SKILL.md +234 -0
- package/skills/tool-guards/SKILL.md +223 -0
- package/skills/visual-qa/SKILL.md +61 -0
- package/skills/visual-qa/references/capture-playbook.md +105 -0
- package/skills/visual-qa/references/complete-contract.md +411 -0
- package/skills/visual-qa/schemas/evidence-manifest-v1alpha1.json +201 -0
- package/skills/visual-qa/schemas/evidence-manifest-v1beta1.json +141 -0
- package/skills/visual-qa/schemas/review-receipt-v1alpha1.json +113 -0
- package/skills/visual-qa/scripts/artifact.mjs +123 -0
- package/skills/visual-qa/scripts/bounded-json.mjs +47 -0
- package/skills/visual-qa/scripts/canonical-json.mjs +28 -0
- package/skills/visual-qa/scripts/capabilities.mjs +66 -0
- package/skills/visual-qa/scripts/contract-text.mjs +15 -0
- package/skills/visual-qa/scripts/design-contract.mjs +611 -0
- package/skills/visual-qa/scripts/evidence-evaluate.mjs +521 -0
- package/skills/visual-qa/scripts/evidence.mjs +271 -0
- package/skills/visual-qa/scripts/png-decode.mjs +146 -0
- package/skills/visual-qa/scripts/png.mjs +154 -0
- package/skills/visual-qa/scripts/review.mjs +188 -0
- package/skills/visual-qa/scripts/stdin-json.mjs +16 -0
- package/skills/visual-qa/scripts/strict-json.mjs +102 -0
- package/skills/visual-qa/scripts/tui.mjs +149 -0
- package/skills/visual-qa/scripts/visual-qa.mjs +90 -0
- package/skills/wikify/LICENSE +21 -0
- package/skills/wikify/PROVENANCE.md +18 -0
- package/skills/wikify/SKILL.md +176 -0
- package/skills/wikify/assets/home-template.md +44 -0
- package/skills/wikify/assets/maintenance-report-template.md +46 -0
- package/skills/wikify/assets/paper-source-note-template.md +137 -0
- package/skills/wikify/assets/source-note-template.md +45 -0
- package/skills/wikify/assets/wiki-rules-template.md +117 -0
- package/skills/wikify/modes/ingest.md +57 -0
- package/skills/wikify/modes/init.md +44 -0
- package/skills/wikify/modes/lint.md +60 -0
- package/skills/wikify/modes/query.md +38 -0
- package/skills/wikify/modes/save.md +45 -0
- package/skills/wikify/references-upstream-contract.md +758 -0
- package/skills/workflow-loop/SKILL.md +387 -0
- package/tools/check-pack-payload.mjs +410 -0
- package/tools/check-payload-substance.mjs +738 -0
- package/tools/check-version-lockstep.mjs +238 -0
- package/tools/gen-canonical-frontend-manifest.mjs +66 -0
- package/tools/gen-managed-skill-manifest.mjs +135 -0
- package/tools/harness-speed-local.mjs +261 -0
- package/tools/payload-reference-exemptions.json +49 -0
- package/tools/payload-substance-allowlist.json +46 -0
- package/tools/payload-substance-parity.json +571 -0
- package/tools/qa-real-surface-fixtures.mjs +428 -0
- package/tools/qa-real-surface-harness.mjs +173 -0
- package/tools/run-behavior-replacement-probes.mjs +296 -0
- package/tools/run-build.mjs +101 -0
- package/tools/run-harness-speed-local.mjs +52 -0
- package/tools/run-harness-speed-v2.mjs +36 -0
- package/tools/run-installed-resource-tamper-probe.mjs +62 -0
- package/tools/run-negative-gate-matrix.mjs +516 -0
- package/tools/run-rules-glob-differential.mjs +232 -0
- package/tools/run-typecheck.mjs +25 -0
- package/tools/run-uiux-visual-qa-scenarios.mjs +234 -0
- package/tools/run-wikify-surface-probe.mjs +170 -0
- package/tools/scan-legacy-tokens.mjs +431 -0
- package/tools/version-manifests.json +60 -0
- package/tsconfig.build.json +12 -0
- package/tsconfig.json +13 -0
- package/vendor/NOTICE.md +21 -0
- package/vendor/handoff/SKILL.md +199 -0
- package/vendor/handoff/evals/evals.json +154 -0
- package/vendor/handoff/examples/HANDOFF-example-generic-auth-refactor.md +97 -0
- package/vendor/handoff/templates/HANDOFF.md +121 -0
- package/vendor/licenses/022_handoff-MIT.txt +21 -0
- package/vendor/licenses/045_scientific-visualization-MIT.txt +21 -0
- package/vendor/provenance/022_handoff.md +19 -0
- package/vendor/provenance/045_scientific-visualization.md +36 -0
- package/vendor/scientific-visualization/SKILL.md +283 -0
- package/vendor/scientific-visualization/assets/color_palettes.py +197 -0
- package/vendor/scientific-visualization/assets/nature.mplstyle +75 -0
- package/vendor/scientific-visualization/assets/presentation.mplstyle +74 -0
- package/vendor/scientific-visualization/assets/publication.mplstyle +78 -0
- package/vendor/scientific-visualization/evals/evals.json +158 -0
- package/vendor/scientific-visualization/references/color_palettes.md +380 -0
- package/vendor/scientific-visualization/references/journal_requirements.md +359 -0
- package/vendor/scientific-visualization/references/matplotlib_examples.md +608 -0
- package/vendor/scientific-visualization/references/mdanalysis_martini_visualization.md +85 -0
- package/vendor/scientific-visualization/references/publication_guidelines.md +217 -0
- package/vendor/scientific-visualization/references/seaborn_for_publications.md +293 -0
- package/vendor/scientific-visualization/scripts/figure_export.py +238 -0
- package/vendor/scientific-visualization/scripts/style_presets.py +467 -0
- package/vendor/scientific-visualization/tests/test_figure_export.py +51 -0
- package/vendor/scientific-visualization/tests/test_style_presets.py +114 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { defaultGlobalConfigJson } from "../config.js";
|
|
2
|
+
import { isRecord } from "./json.js";
|
|
3
|
+
const categoryIds = ["planning", "execution", "review", "research"];
|
|
4
|
+
const leadCategoryIds = new Set(["planning", "review"]);
|
|
5
|
+
const canonicalModels = new Set(["gpt-5.6-luna"]);
|
|
6
|
+
const legacyModels = new Set(["gpt-5.4", "gpt-5.5"]);
|
|
7
|
+
const offeredEfforts = new Set(["medium", "high", "max"]);
|
|
8
|
+
const astraEfforts = new Set(["low", "medium", "high", "xhigh", "max"]);
|
|
9
|
+
const managedLegacyRouteKeys = new Set(["provider", "model", "variant", "textVerbosity"]);
|
|
10
|
+
function normalizedRoute(value) {
|
|
11
|
+
if (!isRecord(value) || typeof value.model !== "string")
|
|
12
|
+
return undefined;
|
|
13
|
+
const slashIndex = value.model.indexOf("/");
|
|
14
|
+
const modelProvider = slashIndex > 0 ? value.model.slice(0, slashIndex) : undefined;
|
|
15
|
+
const model = slashIndex > 0 ? value.model.slice(slashIndex + 1) : value.model;
|
|
16
|
+
const provider = typeof value.provider === "string" ? value.provider : modelProvider;
|
|
17
|
+
if (provider === undefined || (modelProvider !== undefined && provider !== modelProvider))
|
|
18
|
+
return undefined;
|
|
19
|
+
return {
|
|
20
|
+
provider,
|
|
21
|
+
model,
|
|
22
|
+
dispatchId: slashIndex > 0 ? value.model : provider + "/" + model,
|
|
23
|
+
qualifiedModel: slashIndex > 0,
|
|
24
|
+
...(typeof value.variant === "string" ? { variant: value.variant } : {}),
|
|
25
|
+
hasLegacyEffort: value.reasoningEffort !== undefined,
|
|
26
|
+
raw: value
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function isExactManagedLegacyRoute(route) {
|
|
30
|
+
const keys = Object.keys(route.raw);
|
|
31
|
+
return (keys.length === managedLegacyRouteKeys.size &&
|
|
32
|
+
keys.every((key) => managedLegacyRouteKeys.has(key)) &&
|
|
33
|
+
route.provider === "openai" &&
|
|
34
|
+
!route.qualifiedModel &&
|
|
35
|
+
legacyModels.has(route.model) &&
|
|
36
|
+
route.variant === "high" &&
|
|
37
|
+
route.raw.textVerbosity === "medium" &&
|
|
38
|
+
!route.hasLegacyEffort);
|
|
39
|
+
}
|
|
40
|
+
function result(className, originalDispatchId = null) {
|
|
41
|
+
return { class: className, originalDispatchId };
|
|
42
|
+
}
|
|
43
|
+
function hasRouteOverride(value) {
|
|
44
|
+
return isRecord(value) && ["provider", "model", "variant", "reasoningEffort"].some((field) => value[field] !== undefined);
|
|
45
|
+
}
|
|
46
|
+
function originalDispatch(value) {
|
|
47
|
+
if (typeof value.model !== "string")
|
|
48
|
+
return null;
|
|
49
|
+
if (value.model.includes("/"))
|
|
50
|
+
return value.model;
|
|
51
|
+
return typeof value.provider === "string" ? value.provider + "/" + value.model : value.model;
|
|
52
|
+
}
|
|
53
|
+
function customOverrides(rawConfig) {
|
|
54
|
+
const agents = isRecord(rawConfig.agents) ? Object.values(rawConfig.agents).filter(hasRouteOverride) : [];
|
|
55
|
+
const categories = isRecord(rawConfig.categories)
|
|
56
|
+
? Object.entries(rawConfig.categories)
|
|
57
|
+
.filter(([id]) => !categoryIds.includes(id))
|
|
58
|
+
.map(([, value]) => value)
|
|
59
|
+
.filter((value) => isRecord(value))
|
|
60
|
+
: [];
|
|
61
|
+
return [...agents, ...categories];
|
|
62
|
+
}
|
|
63
|
+
function uniqueOriginalDispatch(overrides) {
|
|
64
|
+
const dispatches = [...new Set(overrides.map(originalDispatch).filter((value) => value !== null))];
|
|
65
|
+
return dispatches.length === 1 ? dispatches[0] : null;
|
|
66
|
+
}
|
|
67
|
+
export function classifyModelConfig(rawConfig) {
|
|
68
|
+
if (rawConfig === null)
|
|
69
|
+
return result("fresh");
|
|
70
|
+
const overrides = customOverrides(rawConfig);
|
|
71
|
+
if (overrides.length > 0)
|
|
72
|
+
return result("custom", uniqueOriginalDispatch(overrides));
|
|
73
|
+
if (!isRecord(rawConfig.categories))
|
|
74
|
+
return result("fresh");
|
|
75
|
+
const categories = rawConfig.categories;
|
|
76
|
+
const keys = Object.keys(categories);
|
|
77
|
+
const routes = categoryIds.map((id) => normalizedRoute(categories[id]));
|
|
78
|
+
if (routes.every((route) => route === undefined))
|
|
79
|
+
return result("fresh");
|
|
80
|
+
if (keys.length !== categoryIds.length || routes.some((route) => route === undefined)) {
|
|
81
|
+
return result("mixed");
|
|
82
|
+
}
|
|
83
|
+
const definedRoutes = routes.filter((route) => route !== undefined);
|
|
84
|
+
const first = definedRoutes[0];
|
|
85
|
+
if (first === undefined)
|
|
86
|
+
return result("fresh");
|
|
87
|
+
const homogeneous = definedRoutes.every((route) => route.dispatchId === first.dispatchId && route.variant === first.variant);
|
|
88
|
+
if (!homogeneous || definedRoutes.some((route) => route.hasLegacyEffort))
|
|
89
|
+
return result("mixed");
|
|
90
|
+
if (definedRoutes.every(isExactManagedLegacyRoute)) {
|
|
91
|
+
return result("managed_legacy", first.dispatchId);
|
|
92
|
+
}
|
|
93
|
+
if (first.qualifiedModel)
|
|
94
|
+
return result("custom", first.dispatchId);
|
|
95
|
+
if (first.provider === "openai" &&
|
|
96
|
+
first.model === "gpt-6-astra" &&
|
|
97
|
+
first.variant !== undefined &&
|
|
98
|
+
astraEfforts.has(first.variant)) {
|
|
99
|
+
return result("astra_managed", first.dispatchId);
|
|
100
|
+
}
|
|
101
|
+
if (first.provider === "openai" &&
|
|
102
|
+
canonicalModels.has(first.model) &&
|
|
103
|
+
(first.variant === undefined || offeredEfforts.has(first.variant))) {
|
|
104
|
+
return result("gpt56_managed", first.dispatchId);
|
|
105
|
+
}
|
|
106
|
+
if (first.provider === "openai" && /^gpt-5\.6(?:$|-)/u.test(first.model)) {
|
|
107
|
+
return result("gpt56_other", first.dispatchId);
|
|
108
|
+
}
|
|
109
|
+
return result("custom", first.dispatchId);
|
|
110
|
+
}
|
|
111
|
+
export function selectedLitConfig(rawConfig, selection, permissionMode = "safe", permissionModeExplicit = false, outputStyle = "off") {
|
|
112
|
+
const config = rawConfig === null ? defaultGlobalConfigJson() : { ...rawConfig };
|
|
113
|
+
if (permissionModeExplicit || permissionMode === "balanced" || permissionMode === "yolo") {
|
|
114
|
+
config.permissionMode = permissionMode;
|
|
115
|
+
}
|
|
116
|
+
if (outputStyle !== "off") {
|
|
117
|
+
config.outputStyle = outputStyle;
|
|
118
|
+
}
|
|
119
|
+
if (selection === undefined)
|
|
120
|
+
return config;
|
|
121
|
+
const defaults = defaultGlobalConfigJson();
|
|
122
|
+
const defaultCategories = isRecord(defaults.categories) ? defaults.categories : {};
|
|
123
|
+
const existingCategories = isRecord(config.categories) ? config.categories : {};
|
|
124
|
+
const categories = { ...existingCategories };
|
|
125
|
+
const helper = selection.helper;
|
|
126
|
+
for (const id of Object.keys(defaultCategories)) {
|
|
127
|
+
if (!leadCategoryIds.has(id) && helper === undefined)
|
|
128
|
+
continue;
|
|
129
|
+
const route = leadCategoryIds.has(id) ? selection : helper;
|
|
130
|
+
if (route === undefined)
|
|
131
|
+
continue;
|
|
132
|
+
const current = isRecord(categories[id]) ? categories[id] : {};
|
|
133
|
+
const category = { ...current };
|
|
134
|
+
delete category.reasoningEffort;
|
|
135
|
+
categories[id] = {
|
|
136
|
+
...category,
|
|
137
|
+
provider: route.provider,
|
|
138
|
+
model: route.model,
|
|
139
|
+
...(route.effort === undefined ? {} : { variant: route.effort })
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return { ...config, categories };
|
|
143
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { InstallModelSelection, InstallPermissionChoice, InstallPermissionMode, ModelConfigClassification, ModelPromptMode, PermissionPromptMode } from "./types.ts";
|
|
2
|
+
export declare function promptOutputStyle(existing: string, promptMode: PermissionPromptMode, dryRun: boolean): Promise<string>;
|
|
3
|
+
export declare function promptPermissionMode(selected: InstallPermissionMode, mode: PermissionPromptMode, dryRun: boolean): Promise<InstallPermissionChoice>;
|
|
4
|
+
export declare function renderModelRouteCard(selection: InstallModelSelection, configPath: string): string;
|
|
5
|
+
export declare function promptModelSelection(selection: InstallModelSelection | undefined, mode: ModelPromptMode, dryRun: boolean, classification: ModelConfigClassification, configPath: string, currentSelection?: InstallModelSelection | undefined): Promise<InstallModelSelection | undefined>;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import fsSync from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import readline from "node:readline/promises";
|
|
5
|
+
import { markColorMode } from "../lit-mark.js";
|
|
6
|
+
import { isRecord } from "./json.js";
|
|
7
|
+
import { isModelProvider, modelMenuRows, providerCredentialEnv, providerMenu, stripFastSuffix } from "./model-catalog.js";
|
|
8
|
+
const outputStyleOptions = [
|
|
9
|
+
{ id: "off", label: "None / keep current", hint: "No output style applied" },
|
|
10
|
+
{ id: "asd-ste100", label: "ASD-STE100 (English)", hint: "ASD Simplified Technical English" },
|
|
11
|
+
{ id: "asd-ste100-ko", label: "ASD-STE100 (한국어)", hint: "ASD 간소화 기술 영어 (한국어)" },
|
|
12
|
+
{ id: "eli5", label: "ELI5 (English)", hint: "Explain Like I'm 5" },
|
|
13
|
+
{ id: "eli5-ko", label: "ELI5 (한국어)", hint: "쉽게 설명하기" }
|
|
14
|
+
];
|
|
15
|
+
function shouldPromptForInstallChoice(mode, dryRun) {
|
|
16
|
+
if (dryRun)
|
|
17
|
+
return false;
|
|
18
|
+
if (mode === "never")
|
|
19
|
+
return false;
|
|
20
|
+
if (mode === "always")
|
|
21
|
+
return true;
|
|
22
|
+
return process.stdin.isTTY === true && process.stdout.isTTY === true && process.env.CI === undefined;
|
|
23
|
+
}
|
|
24
|
+
export async function promptOutputStyle(existing, promptMode, dryRun) {
|
|
25
|
+
if (!shouldPromptForInstallChoice(promptMode, dryRun))
|
|
26
|
+
return existing;
|
|
27
|
+
const defaultIndex = Math.max(0, outputStyleOptions.findIndex((opt) => opt.id === existing));
|
|
28
|
+
const reader = createPromptReader();
|
|
29
|
+
try {
|
|
30
|
+
const index = await chooseIndex(reader, "Choose an output style for LitOpenCode responses.", outputStyleOptions, defaultIndex);
|
|
31
|
+
return outputStyleOptions[index].id;
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
reader.close();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const permissionOptions = [
|
|
38
|
+
{
|
|
39
|
+
mode: "safe",
|
|
40
|
+
label: "Safe / ask-first",
|
|
41
|
+
hint: "Do not relax OpenCode permissions"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
mode: "balanced",
|
|
45
|
+
label: "Balanced automation",
|
|
46
|
+
hint: "Allow routine work but ask for dangerous shell commands such as rm -rf"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
mode: "yolo",
|
|
50
|
+
label: "Full automation / YOLO",
|
|
51
|
+
hint: "Allow bash/edit/task/webfetch; lit-plan remains deny-only"
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
function formatChoice(index, label, hint) {
|
|
55
|
+
return " " + String(index) + ". " + label + (hint.length === 0 ? "" : " — " + hint);
|
|
56
|
+
}
|
|
57
|
+
async function askLine(reader, prompt) {
|
|
58
|
+
return (await reader.question(prompt)).trim();
|
|
59
|
+
}
|
|
60
|
+
function createPromptReader() {
|
|
61
|
+
if (process.stdin.isTTY === true) {
|
|
62
|
+
return readline.createInterface({ input: process.stdin, output: process.stdout, terminal: markColorMode() !== "none" });
|
|
63
|
+
}
|
|
64
|
+
const answers = fsSync.readFileSync(0, "utf8").split(/\r?\n/u);
|
|
65
|
+
let index = 0;
|
|
66
|
+
return {
|
|
67
|
+
async question(prompt) {
|
|
68
|
+
process.stdout.write(prompt);
|
|
69
|
+
const answer = answers[index] ?? "";
|
|
70
|
+
index += 1;
|
|
71
|
+
return answer;
|
|
72
|
+
},
|
|
73
|
+
close() { }
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async function chooseIndex(reader, title, choices, defaultIndex) {
|
|
77
|
+
process.stdout.write("\n" + title + "\n");
|
|
78
|
+
for (const [index, choice] of choices.entries()) {
|
|
79
|
+
process.stdout.write(formatChoice(index, choice.label, choice.hint) + "\n");
|
|
80
|
+
}
|
|
81
|
+
const answer = await askLine(reader, "Select 0-" + String(choices.length - 1) + " [" + String(defaultIndex) + "]: ");
|
|
82
|
+
if (answer.length === 0)
|
|
83
|
+
return defaultIndex;
|
|
84
|
+
const selected = Number.parseInt(answer, 10);
|
|
85
|
+
if (/^\d+$/u.test(answer) && Number.isInteger(selected) && selected >= 0 && selected < choices.length)
|
|
86
|
+
return selected;
|
|
87
|
+
throw new Error("Invalid selection: " + answer);
|
|
88
|
+
}
|
|
89
|
+
function shouldPromptForModel(mode, selection, dryRun, classification, currentSelection) {
|
|
90
|
+
if (selection !== undefined || dryRun)
|
|
91
|
+
return false;
|
|
92
|
+
if (mode === "never")
|
|
93
|
+
return false;
|
|
94
|
+
if (mode === "always")
|
|
95
|
+
return true;
|
|
96
|
+
if (process.stdin.isTTY !== true || process.stdout.isTTY !== true || process.env.CI !== undefined)
|
|
97
|
+
return false;
|
|
98
|
+
return classification.class === "fresh" || classification.class === "managed_legacy" || currentSelection !== undefined;
|
|
99
|
+
}
|
|
100
|
+
function shouldPromptForPermissions(mode, selected, dryRun) {
|
|
101
|
+
return selected === "safe" && shouldPromptForInstallChoice(mode, dryRun);
|
|
102
|
+
}
|
|
103
|
+
export async function promptPermissionMode(selected, mode, dryRun) {
|
|
104
|
+
if (!shouldPromptForPermissions(mode, selected, dryRun))
|
|
105
|
+
return { mode: selected, explicit: selected !== "safe" };
|
|
106
|
+
const reader = createPromptReader();
|
|
107
|
+
try {
|
|
108
|
+
const index = await chooseIndex(reader, "Choose LitOpenCode permission behavior.", permissionOptions, 0);
|
|
109
|
+
return { mode: permissionOptions[index].mode, explicit: true };
|
|
110
|
+
}
|
|
111
|
+
finally {
|
|
112
|
+
reader.close();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function menuLabel(row) {
|
|
116
|
+
return row.model.padEnd(13, " ") + " · " + row.effort.padEnd(6, " ");
|
|
117
|
+
}
|
|
118
|
+
async function chooseProvider(reader, title, defaultProvider) {
|
|
119
|
+
const defaultIndex = Math.max(0, providerMenu.findIndex((row) => row.provider === defaultProvider));
|
|
120
|
+
const index = await chooseIndex(reader, title, providerMenu.map((row) => ({ label: row.label.padEnd(35, " ") + " (" + row.provider + ")", hint: "" })), defaultIndex);
|
|
121
|
+
return providerMenu[index].provider;
|
|
122
|
+
}
|
|
123
|
+
async function chooseRoute(reader, title, provider, defaultIndex, preferred) {
|
|
124
|
+
const rows = modelMenuRows(provider);
|
|
125
|
+
const preferredModel = preferred === undefined ? undefined : provider === "openai" ? stripFastSuffix(preferred.model) : preferred.model;
|
|
126
|
+
const preferredIndex = preferredModel === undefined ? -1 : rows.findIndex((row) => row.model === preferredModel);
|
|
127
|
+
const selectedDefault = preferredIndex >= 0 ? preferredIndex : Math.min(defaultIndex, rows.length - 1);
|
|
128
|
+
const index = await chooseIndex(reader, title, rows.map((row) => ({ label: menuLabel(row), hint: row.hint })), selectedDefault);
|
|
129
|
+
const row = rows[index];
|
|
130
|
+
if (preferred !== undefined &&
|
|
131
|
+
row.provider === preferred.provider &&
|
|
132
|
+
row.model === preferredModel) {
|
|
133
|
+
return preferred;
|
|
134
|
+
}
|
|
135
|
+
return { provider: row.provider, model: row.model, effort: row.effort };
|
|
136
|
+
}
|
|
137
|
+
function recommendedHelperIndex(provider) {
|
|
138
|
+
return Math.max(0, modelMenuRows(provider).findIndex((row) => row.hint.includes("recommended helper")));
|
|
139
|
+
}
|
|
140
|
+
function hostAuthPath() {
|
|
141
|
+
const dataHome = process.env.XDG_DATA_HOME;
|
|
142
|
+
const base = dataHome && dataHome.length > 0 ? dataHome : path.join(os.homedir(), ".local", "share");
|
|
143
|
+
return path.join(base, "opencode", "auth.json");
|
|
144
|
+
}
|
|
145
|
+
function hasProviderCredential(provider) {
|
|
146
|
+
const envName = providerCredentialEnv(provider);
|
|
147
|
+
if (envName !== undefined && (process.env[envName] ?? "").length > 0)
|
|
148
|
+
return true;
|
|
149
|
+
try {
|
|
150
|
+
const parsed = JSON.parse(fsSync.readFileSync(hostAuthPath(), "utf8"));
|
|
151
|
+
return isRecord(parsed) && isRecord(parsed[provider]);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function routeLabel(route) {
|
|
158
|
+
return route.model + " · " + (route.effort ?? "default");
|
|
159
|
+
}
|
|
160
|
+
export function renderModelRouteCard(selection, configPath) {
|
|
161
|
+
const helper = selection.helper ?? selection;
|
|
162
|
+
const providers = helper.provider === selection.provider ? selection.provider : selection.provider + " / " + helper.provider;
|
|
163
|
+
const warnings = [...new Set([selection.provider, helper.provider])]
|
|
164
|
+
.filter((provider) => !hasProviderCredential(provider))
|
|
165
|
+
.map((provider) => {
|
|
166
|
+
const envName = providerCredentialEnv(provider) ?? provider.toUpperCase() + "_API_KEY";
|
|
167
|
+
return "│ Warning " + envName + " is not set and OpenCode has no stored " + provider + " credential; the route is written anyway";
|
|
168
|
+
});
|
|
169
|
+
return [
|
|
170
|
+
"",
|
|
171
|
+
"╭─ MODEL ROUTE",
|
|
172
|
+
"│ Provider " + providers,
|
|
173
|
+
"│ Lead " + routeLabel(selection),
|
|
174
|
+
"│ Helpers " + routeLabel(helper),
|
|
175
|
+
"│ Writes " + configPath + " (managed keys only)",
|
|
176
|
+
...warnings,
|
|
177
|
+
"╰─ Enter to continue · Ctrl-C to abort (nothing written yet)"
|
|
178
|
+
].join("\n") + "\n";
|
|
179
|
+
}
|
|
180
|
+
export async function promptModelSelection(selection, mode, dryRun, classification, configPath, currentSelection = undefined) {
|
|
181
|
+
if (!shouldPromptForModel(mode, selection, dryRun, classification, currentSelection)) {
|
|
182
|
+
if (selection !== undefined && !dryRun)
|
|
183
|
+
process.stdout.write(renderModelRouteCard(selection, configPath));
|
|
184
|
+
return selection;
|
|
185
|
+
}
|
|
186
|
+
const preferredSelection = mode === "auto" ? currentSelection : undefined;
|
|
187
|
+
const reader = createPromptReader();
|
|
188
|
+
try {
|
|
189
|
+
if (classification.class === "managed_legacy") {
|
|
190
|
+
process.stdout.write("\nManaged GPT-5.4/GPT-5.5 route detected; choosing a route upgrades it.\n");
|
|
191
|
+
}
|
|
192
|
+
else if (classification.class !== "fresh") {
|
|
193
|
+
process.stdout.write("\nExisting route (" + classification.class + ") will be rewritten in managed keys only.\n");
|
|
194
|
+
}
|
|
195
|
+
const leadProvider = await chooseProvider(reader, "Choose the provider for LitOpenCode agents.", preferredSelection !== undefined && isModelProvider(preferredSelection.provider) ? preferredSelection.provider : "openai");
|
|
196
|
+
const lead = await chooseRoute(reader, "Choose the LEAD model (plans and reviews).", leadProvider, 0, preferredSelection);
|
|
197
|
+
const preferredHelper = preferredSelection?.helper;
|
|
198
|
+
const helperProvider = await chooseProvider(reader, "Choose the provider for HELPER agents (workers, explorers, librarians).", preferredHelper !== undefined && isModelProvider(preferredHelper.provider) ? preferredHelper.provider : leadProvider);
|
|
199
|
+
const helper = await chooseRoute(reader, "Choose the HELPER model (spawned and delegated agents).", helperProvider, recommendedHelperIndex(helperProvider), preferredHelper);
|
|
200
|
+
const chosen = { ...lead, helper };
|
|
201
|
+
process.stdout.write(renderModelRouteCard(chosen, configPath));
|
|
202
|
+
await askLine(reader, "");
|
|
203
|
+
return chosen;
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
reader.close();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type RetainedCanonicalCache } from "./native-canonical-cache.ts";
|
|
2
|
+
import { type RuntimeSkill } from "./native-skill-integrity.ts";
|
|
3
|
+
export declare function prepareCanonicalBackup(root: string, skillsRoot: string, skill: RuntimeSkill, caches: readonly RetainedCanonicalCache[]): Promise<{
|
|
4
|
+
backup: string;
|
|
5
|
+
validateBoundary: () => Promise<void>;
|
|
6
|
+
validateBeforeMove: () => Promise<void>;
|
|
7
|
+
validateMoved: () => Promise<void>;
|
|
8
|
+
complete: () => Promise<void>;
|
|
9
|
+
}>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { inspectCanonicalTree } from "./native-canonical-cache.js";
|
|
5
|
+
import { installedCanonicalDirectory, managedSkillDefinition } from "./managed-skill-assets.js";
|
|
6
|
+
import { assertInstalledCanonicalOwnership, nativeSkillsRoot } from "./native-skill-integrity.js";
|
|
7
|
+
import { lstatIfPresent } from "./native-skill-tree.js";
|
|
8
|
+
async function directoryIdentity(directory) {
|
|
9
|
+
const stat = await fs.lstat(directory, { bigint: true });
|
|
10
|
+
if (!stat.isDirectory() || stat.isSymbolicLink())
|
|
11
|
+
throw new Error(`Unsafe canonical backup directory: ${directory}`);
|
|
12
|
+
return `${stat.dev}:${stat.ino}:${stat.birthtimeNs}`;
|
|
13
|
+
}
|
|
14
|
+
async function directoryChain(...directories) {
|
|
15
|
+
const entries = new Map();
|
|
16
|
+
for (const directory of directories) {
|
|
17
|
+
let current = directory;
|
|
18
|
+
while (!entries.has(current)) {
|
|
19
|
+
entries.set(current, await directoryIdentity(current));
|
|
20
|
+
const parent = path.dirname(current);
|
|
21
|
+
if (parent === current)
|
|
22
|
+
break;
|
|
23
|
+
current = parent;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return entries;
|
|
27
|
+
}
|
|
28
|
+
export async function prepareCanonicalBackup(root, skillsRoot, skill, caches) {
|
|
29
|
+
const realRoot = await fs.realpath(root);
|
|
30
|
+
const realSkillsRoot = await fs.realpath(skillsRoot);
|
|
31
|
+
const parent = path.join(realRoot, ".litopencode-canonical-backups");
|
|
32
|
+
const relative = path.relative(realSkillsRoot, parent);
|
|
33
|
+
if (relative === "" || (!relative.startsWith(".." + path.sep) && relative !== ".." && !path.isAbsolute(relative))) {
|
|
34
|
+
throw new Error("Canonical backup must be outside native skills discovery");
|
|
35
|
+
}
|
|
36
|
+
const initial = await directoryChain(realRoot, realSkillsRoot);
|
|
37
|
+
async function assertInitial() {
|
|
38
|
+
if (await fs.realpath(root) !== realRoot || await fs.realpath(await nativeSkillsRoot(root)) !== realSkillsRoot) {
|
|
39
|
+
throw new Error("Canonical backup root changed; retained state must be reviewed");
|
|
40
|
+
}
|
|
41
|
+
for (const [directory, identity] of initial) {
|
|
42
|
+
if (await directoryIdentity(directory) !== identity)
|
|
43
|
+
throw new Error(`Canonical backup ancestor changed: ${directory}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
await assertInitial();
|
|
47
|
+
try {
|
|
48
|
+
await fs.mkdir(parent, { mode: 0o700 });
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (!(error instanceof Error && "code" in error && error.code === "EEXIST"))
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
initial.set(parent, await directoryIdentity(parent));
|
|
55
|
+
await assertInitial();
|
|
56
|
+
const container = path.join(parent, `${skill.id}-${randomUUID()}`);
|
|
57
|
+
await fs.mkdir(container, { mode: 0o700 });
|
|
58
|
+
const owned = await directoryChain(container);
|
|
59
|
+
const backup = path.join(container, "skill");
|
|
60
|
+
const receipt = { schemaVersion: 1, skill: skill.id, original: path.join(skillsRoot, skill.id), backup, caches };
|
|
61
|
+
await fs.writeFile(path.join(container, "prepared.json"), JSON.stringify(receipt, null, 2) + "\n", { flag: "wx", mode: 0o600 });
|
|
62
|
+
async function validateBoundary() {
|
|
63
|
+
await assertInitial();
|
|
64
|
+
for (const [directory, identity] of owned) {
|
|
65
|
+
if (await directoryIdentity(directory) !== identity)
|
|
66
|
+
throw new Error(`Canonical backup directory changed: ${directory}`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async function validateBeforeMove() {
|
|
70
|
+
await validateBoundary();
|
|
71
|
+
const current = await assertInstalledCanonicalOwnership(root, skill);
|
|
72
|
+
if (JSON.stringify(current) !== JSON.stringify(caches))
|
|
73
|
+
throw new Error("Canonical cache changed before retention");
|
|
74
|
+
if (await lstatIfPresent(backup) !== null)
|
|
75
|
+
throw new Error(`Canonical backup destination already exists: ${backup}`);
|
|
76
|
+
await validateBoundary();
|
|
77
|
+
}
|
|
78
|
+
async function validateMoved() {
|
|
79
|
+
await validateBoundary();
|
|
80
|
+
await directoryIdentity(backup);
|
|
81
|
+
const canonical = path.join(backup, installedCanonicalDirectory);
|
|
82
|
+
await directoryIdentity(canonical);
|
|
83
|
+
const definition = managedSkillDefinition(skill.id);
|
|
84
|
+
if (definition === undefined)
|
|
85
|
+
throw new Error(`Missing canonical definition for ${skill.id}`);
|
|
86
|
+
const current = await inspectCanonicalTree(canonical, definition.canonicalFiles);
|
|
87
|
+
if (current.failures.length > 0 || JSON.stringify(current.caches) !== JSON.stringify(caches)) {
|
|
88
|
+
throw new Error(`Retained canonical bytes changed; preserve backup at ${backup}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function complete() {
|
|
92
|
+
await validateMoved();
|
|
93
|
+
await fs.writeFile(path.join(container, "receipt.json"), JSON.stringify({ ...receipt, state: "retained" }, null, 2) + "\n", { flag: "wx", mode: 0o600 });
|
|
94
|
+
}
|
|
95
|
+
return { backup, validateBoundary, validateBeforeMove, validateMoved, complete };
|
|
96
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CanonicalManagedAsset } from "./managed-skill-assets.ts";
|
|
2
|
+
export type RetainedCanonicalCache = {
|
|
3
|
+
readonly path: string;
|
|
4
|
+
readonly sha256: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function inspectCanonicalTree(root: string, assets: readonly CanonicalManagedAsset[]): Promise<{
|
|
7
|
+
failures: string[];
|
|
8
|
+
caches: RetainedCanonicalCache[];
|
|
9
|
+
}>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { exactTreeFailures, inventoryTree } from "./native-skill-tree.js";
|
|
5
|
+
export async function inspectCanonicalTree(root, assets) {
|
|
6
|
+
const inventory = await inventoryTree(root);
|
|
7
|
+
const expected = new Set(assets.map((asset) => asset.path));
|
|
8
|
+
const failures = [...inventory.unsafe];
|
|
9
|
+
const caches = [];
|
|
10
|
+
// Bytecode is opaque user state, never validation input or an executable here.
|
|
11
|
+
// Its source must still be one of the exact unchanged packaged Python files.
|
|
12
|
+
for (const asset of assets) {
|
|
13
|
+
if (!inventory.files.includes(asset.path))
|
|
14
|
+
continue;
|
|
15
|
+
const actual = createHash("sha256").update(await fs.readFile(path.join(root, asset.path))).digest("hex");
|
|
16
|
+
if (actual !== asset.sha256)
|
|
17
|
+
failures.push(asset.path);
|
|
18
|
+
}
|
|
19
|
+
if (failures.length === 0) {
|
|
20
|
+
for (const file of inventory.files) {
|
|
21
|
+
if (expected.has(file))
|
|
22
|
+
continue;
|
|
23
|
+
const directory = path.posix.dirname(file);
|
|
24
|
+
if (path.posix.basename(directory) !== "__pycache__")
|
|
25
|
+
continue;
|
|
26
|
+
const match = /^(.*)\.(?:cpython-[0-9]+|pypy[0-9]+)(?:\.opt-[0-9]+)?\.pyc$/.exec(path.posix.basename(file));
|
|
27
|
+
if (match === null)
|
|
28
|
+
continue;
|
|
29
|
+
const source = path.posix.join(path.posix.dirname(directory), `${match[1]}.py`);
|
|
30
|
+
if (!expected.has(source) || !inventory.files.includes(source))
|
|
31
|
+
continue;
|
|
32
|
+
caches.push({ path: file, sha256: createHash("sha256").update(await fs.readFile(path.join(root, file))).digest("hex") });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
failures.push(...exactTreeFailures(inventory, [...expected, ...caches.map((cache) => cache.path)]));
|
|
36
|
+
return { failures: [...new Set(failures)].sort(), caches };
|
|
37
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { prepareCanonicalBackup } from "./native-canonical-backup.js";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { litOpenCodeRuntimeSkills } from "../skills.js";
|
|
6
|
+
import { assetPathsForManagedSkill, installedCanonicalDirectory, managedSkillDefinition, previousManagedSkillId } from "./managed-skill-assets.js";
|
|
7
|
+
import { destinationState, assertInstalledCanonicalOwnership, invalidInstalledAssets, nativeSkillContent, nativeSkillsRoot, sourceSkillDir, validateSkillSource } from "./native-skill-integrity.js";
|
|
8
|
+
import { assertContained, lstatIfPresent } from "./native-skill-tree.js";
|
|
9
|
+
async function createStagedSkill(skillsRoot, metadata, skill) {
|
|
10
|
+
const stage = path.join(skillsRoot, `.${skill.id}.${randomUUID()}.stage`);
|
|
11
|
+
await fs.mkdir(stage, { recursive: false });
|
|
12
|
+
try {
|
|
13
|
+
await fs.writeFile(path.join(stage, "SKILL.md"), await nativeSkillContent(metadata, skill), "utf8");
|
|
14
|
+
for (const relativePath of assetPathsForManagedSkill(skill.id)) {
|
|
15
|
+
const destination = path.join(stage, relativePath);
|
|
16
|
+
assertContained(stage, destination, `Staged native skill ${skill.id}`);
|
|
17
|
+
await fs.mkdir(path.dirname(destination), { recursive: true });
|
|
18
|
+
await fs.copyFile(path.join(sourceSkillDir(metadata, skill.id), relativePath), destination);
|
|
19
|
+
}
|
|
20
|
+
const definition = managedSkillDefinition(skill.id);
|
|
21
|
+
if (definition?.canonicalRoot !== undefined) {
|
|
22
|
+
const canonicalRoot = path.resolve(sourceSkillDir(metadata, skill.id), definition.canonicalRoot);
|
|
23
|
+
for (const asset of definition.canonicalFiles) {
|
|
24
|
+
const source = path.join(canonicalRoot, asset.path);
|
|
25
|
+
const destination = path.join(stage, installedCanonicalDirectory, asset.path);
|
|
26
|
+
assertContained(canonicalRoot, source, `Canonical source ${skill.id}`);
|
|
27
|
+
assertContained(stage, destination, `Staged canonical ${skill.id}`);
|
|
28
|
+
await fs.mkdir(path.dirname(destination), { recursive: true });
|
|
29
|
+
await fs.copyFile(source, destination);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const failures = await invalidInstalledAssets(stage, metadata, skill);
|
|
33
|
+
if (failures.length > 0)
|
|
34
|
+
throw new Error(`Staged native skill ${skill.id} failed verification: ${failures.join(", ")}`);
|
|
35
|
+
return stage;
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
await fs.rm(stage, { recursive: true, force: true });
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function swapStagedSkill(root, skillsRoot, target, stage, skill, caches) {
|
|
43
|
+
const id = skill.id;
|
|
44
|
+
if (await lstatIfPresent(target) === null) {
|
|
45
|
+
await fs.rename(stage, target);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const retained = caches.length === 0 ? undefined : await prepareCanonicalBackup(root, skillsRoot, skill, caches);
|
|
49
|
+
const backup = retained?.backup ?? path.join(skillsRoot, `.${id}.${randomUUID()}.backup`);
|
|
50
|
+
await retained?.validateBeforeMove();
|
|
51
|
+
await fs.rename(target, backup);
|
|
52
|
+
try {
|
|
53
|
+
await retained?.validateMoved();
|
|
54
|
+
if (retained !== undefined && await lstatIfPresent(target) !== null)
|
|
55
|
+
throw new Error(`Native skill target appeared during replacement: ${target}`);
|
|
56
|
+
await fs.rename(stage, target);
|
|
57
|
+
await retained?.complete();
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
try {
|
|
61
|
+
await retained?.validateMoved();
|
|
62
|
+
if (retained !== undefined && await lstatIfPresent(target) !== null)
|
|
63
|
+
throw new Error(`Unsafe rollback target already exists: ${target}`);
|
|
64
|
+
await fs.rename(backup, target);
|
|
65
|
+
}
|
|
66
|
+
catch (rollbackError) {
|
|
67
|
+
throw new Error(retained === undefined
|
|
68
|
+
? `Atomic native skill swap failed for ${id}, and rollback failed; previous tree remains at ${backup}: ${String(error)}; rollback: ${String(rollbackError)}`
|
|
69
|
+
: `Atomic native skill swap failed for ${id}; rollback unsafe or failed, state unknown; previous tree last recorded at ${backup}: ${String(error)}; rollback: ${String(rollbackError)}`);
|
|
70
|
+
}
|
|
71
|
+
throw new Error(`Atomic native skill swap failed for ${id}; previous tree was restored: ${String(error)}`);
|
|
72
|
+
}
|
|
73
|
+
if (retained === undefined)
|
|
74
|
+
await fs.rm(backup, { recursive: true, force: true });
|
|
75
|
+
}
|
|
76
|
+
async function stagedCleanup(stage) {
|
|
77
|
+
const identity = await fs.lstat(stage, { bigint: true });
|
|
78
|
+
const real = await fs.realpath(stage);
|
|
79
|
+
return async () => {
|
|
80
|
+
if (await lstatIfPresent(stage) === null)
|
|
81
|
+
return;
|
|
82
|
+
const current = await fs.lstat(stage, { bigint: true });
|
|
83
|
+
if (!current.isDirectory() || current.isSymbolicLink() || current.dev !== identity.dev ||
|
|
84
|
+
current.ino !== identity.ino || current.birthtimeNs !== identity.birthtimeNs || await fs.realpath(stage) !== real) {
|
|
85
|
+
throw new Error(`Staged cleanup refused changed identity or ancestry; preserve ${stage}`);
|
|
86
|
+
}
|
|
87
|
+
await fs.rm(stage, { recursive: true, force: true });
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
export async function ensureNativeSkills(root, metadata) {
|
|
91
|
+
const skillsRoot = await nativeSkillsRoot(root);
|
|
92
|
+
await fs.mkdir(skillsRoot, { recursive: true });
|
|
93
|
+
for (const skill of litOpenCodeRuntimeSkills) {
|
|
94
|
+
await validateSkillSource(metadata, skill);
|
|
95
|
+
const previousId = previousManagedSkillId(skill.id);
|
|
96
|
+
const destination = await destinationState(root, skill);
|
|
97
|
+
if (destination.kind === "preserved")
|
|
98
|
+
continue;
|
|
99
|
+
await assertInstalledCanonicalOwnership(root, skill);
|
|
100
|
+
const stage = await createStagedSkill(skillsRoot, metadata, skill);
|
|
101
|
+
const removeStage = await stagedCleanup(stage);
|
|
102
|
+
try {
|
|
103
|
+
const current = await destinationState(root, skill);
|
|
104
|
+
if (current.kind === "preserved") {
|
|
105
|
+
await removeStage();
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const caches = await assertInstalledCanonicalOwnership(root, skill);
|
|
109
|
+
await swapStagedSkill(root, skillsRoot, path.join(skillsRoot, skill.id), stage, skill, caches);
|
|
110
|
+
if (previousId !== undefined) {
|
|
111
|
+
const previousRoot = path.join(skillsRoot, previousId);
|
|
112
|
+
assertContained(skillsRoot, previousRoot, `Previous native skill ${skill.id}`);
|
|
113
|
+
const previous = await destinationState(root, { id: previousId });
|
|
114
|
+
if (previous.kind === "managed")
|
|
115
|
+
await fs.rm(previousRoot, { recursive: true });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
try {
|
|
120
|
+
await removeStage();
|
|
121
|
+
}
|
|
122
|
+
catch (cleanupError) {
|
|
123
|
+
throw new Error(`${String(error)}; ${String(cleanupError)}`);
|
|
124
|
+
}
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|