@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,717 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import fsSync from "node:fs";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
5
|
+
import https from "node:https";
|
|
6
|
+
import os from "node:os";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { readPackageMetadata } from "./json.js";
|
|
10
|
+
const packageName = "@litfamily/litopencode";
|
|
11
|
+
const cacheSchemaVersion = 1;
|
|
12
|
+
const updateCacheMaxBytes = 64 * 1024;
|
|
13
|
+
const updateLockOwnerMaxBytes = 4 * 1024;
|
|
14
|
+
export const npmLatestUrl = "https://registry.npmjs.org/%40litfamily%2Flitopencode/latest";
|
|
15
|
+
export const updateTimeoutMs = 3000;
|
|
16
|
+
export const updateResponseMaxBytes = 64 * 1024;
|
|
17
|
+
export const updateCheckIntervalMs = 24 * 60 * 60 * 1000;
|
|
18
|
+
export const updateLockStaleMs = 10 * 1000;
|
|
19
|
+
export function parseStableVersion(value) {
|
|
20
|
+
if (typeof value !== "string")
|
|
21
|
+
return undefined;
|
|
22
|
+
const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.exec(value);
|
|
23
|
+
if (!match)
|
|
24
|
+
return undefined;
|
|
25
|
+
return [BigInt(match[1]), BigInt(match[2]), BigInt(match[3])];
|
|
26
|
+
}
|
|
27
|
+
export function compareStableVersions(left, right) {
|
|
28
|
+
const leftParts = parseStableVersion(left);
|
|
29
|
+
const rightParts = parseStableVersion(right);
|
|
30
|
+
if (!leftParts || !rightParts)
|
|
31
|
+
return undefined;
|
|
32
|
+
for (let index = 0; index < leftParts.length; index += 1) {
|
|
33
|
+
if (leftParts[index] > rightParts[index])
|
|
34
|
+
return 1;
|
|
35
|
+
if (leftParts[index] < rightParts[index])
|
|
36
|
+
return -1;
|
|
37
|
+
}
|
|
38
|
+
return 0;
|
|
39
|
+
}
|
|
40
|
+
export function updateCachePath(homeDir = os.homedir()) {
|
|
41
|
+
return path.join(homeDir, ".litopencode", "update-check.json");
|
|
42
|
+
}
|
|
43
|
+
export function updateLockPath(homeDir = os.homedir()) {
|
|
44
|
+
return path.join(homeDir, ".litopencode", "update-check.lock");
|
|
45
|
+
}
|
|
46
|
+
export function updateTransitionLockPath(homeDir = os.homedir()) {
|
|
47
|
+
return path.join(homeDir, ".litopencode", "update-check.transition.lock");
|
|
48
|
+
}
|
|
49
|
+
function safeTimestamp(value) {
|
|
50
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
51
|
+
}
|
|
52
|
+
function currentUserOwns(stats) {
|
|
53
|
+
return typeof process.getuid !== "function" || stats.uid === process.getuid();
|
|
54
|
+
}
|
|
55
|
+
function hasPrivateMode(stats) {
|
|
56
|
+
return process.platform === "win32" || (stats.mode & 0o077) === 0;
|
|
57
|
+
}
|
|
58
|
+
function safePrivateDirectory(stats) {
|
|
59
|
+
return stats.isDirectory() && currentUserOwns(stats) && hasPrivateMode(stats);
|
|
60
|
+
}
|
|
61
|
+
function safePrivateFile(stats, maximumBytes) {
|
|
62
|
+
return stats.isFile() && stats.size <= maximumBytes && currentUserOwns(stats) && hasPrivateMode(stats);
|
|
63
|
+
}
|
|
64
|
+
function sameFilesystemEntry(left, right) {
|
|
65
|
+
return left.dev === right.dev && left.ino === right.ino;
|
|
66
|
+
}
|
|
67
|
+
function safeReadFlags() {
|
|
68
|
+
let flags = fsSync.constants.O_RDONLY;
|
|
69
|
+
if (typeof fsSync.constants.O_NOFOLLOW === "number")
|
|
70
|
+
flags |= fsSync.constants.O_NOFOLLOW;
|
|
71
|
+
if (typeof fsSync.constants.O_NONBLOCK === "number")
|
|
72
|
+
flags |= fsSync.constants.O_NONBLOCK;
|
|
73
|
+
return flags;
|
|
74
|
+
}
|
|
75
|
+
function missingFilesystemEntry(error) {
|
|
76
|
+
return error.code === "ENOENT";
|
|
77
|
+
}
|
|
78
|
+
async function safeDirectoryStatus(directoryPath) {
|
|
79
|
+
try {
|
|
80
|
+
return safePrivateDirectory(await fs.lstat(directoryPath)) ? "safe" : "unsafe";
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
return missingFilesystemEntry(error) ? "missing" : "unsafe";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function safeDirectoryStatusSync(directoryPath) {
|
|
87
|
+
try {
|
|
88
|
+
return safePrivateDirectory(fsSync.lstatSync(directoryPath)) ? "safe" : "unsafe";
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
return missingFilesystemEntry(error) ? "missing" : "unsafe";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function ensureSafePrivateDirectory(directoryPath) {
|
|
95
|
+
await fs.mkdir(directoryPath, { recursive: true, mode: 0o700 });
|
|
96
|
+
if ((await safeDirectoryStatus(directoryPath)) !== "safe") {
|
|
97
|
+
throw new Error("update state directory is unsafe");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async function readSafeRegularFile(filePath, maximumBytes) {
|
|
101
|
+
let handle;
|
|
102
|
+
try {
|
|
103
|
+
const pathStats = await fs.lstat(filePath);
|
|
104
|
+
if (!safePrivateFile(pathStats, maximumBytes))
|
|
105
|
+
return { status: "unsafe" };
|
|
106
|
+
handle = await fs.open(filePath, safeReadFlags());
|
|
107
|
+
const descriptorStats = await handle.stat();
|
|
108
|
+
if (!safePrivateFile(descriptorStats, maximumBytes) || !sameFilesystemEntry(pathStats, descriptorStats)) {
|
|
109
|
+
return { status: "unsafe" };
|
|
110
|
+
}
|
|
111
|
+
const bytes = Buffer.alloc(maximumBytes + 1);
|
|
112
|
+
let totalBytes = 0;
|
|
113
|
+
while (totalBytes < bytes.length) {
|
|
114
|
+
const { bytesRead } = await handle.read(bytes, totalBytes, bytes.length - totalBytes, totalBytes);
|
|
115
|
+
if (bytesRead === 0)
|
|
116
|
+
break;
|
|
117
|
+
totalBytes += bytesRead;
|
|
118
|
+
}
|
|
119
|
+
if (totalBytes > maximumBytes)
|
|
120
|
+
return { status: "unsafe" };
|
|
121
|
+
return { status: "ok", text: bytes.subarray(0, totalBytes).toString("utf8") };
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
return missingFilesystemEntry(error) ? { status: "missing" } : { status: "unsafe" };
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
await handle?.close().catch(() => undefined);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function readSafeRegularFileSync(filePath, maximumBytes) {
|
|
131
|
+
let descriptor;
|
|
132
|
+
try {
|
|
133
|
+
const pathStats = fsSync.lstatSync(filePath);
|
|
134
|
+
if (!safePrivateFile(pathStats, maximumBytes))
|
|
135
|
+
return { status: "unsafe" };
|
|
136
|
+
descriptor = fsSync.openSync(filePath, safeReadFlags());
|
|
137
|
+
const descriptorStats = fsSync.fstatSync(descriptor);
|
|
138
|
+
if (!safePrivateFile(descriptorStats, maximumBytes) || !sameFilesystemEntry(pathStats, descriptorStats)) {
|
|
139
|
+
return { status: "unsafe" };
|
|
140
|
+
}
|
|
141
|
+
const bytes = Buffer.alloc(maximumBytes + 1);
|
|
142
|
+
let totalBytes = 0;
|
|
143
|
+
while (totalBytes < bytes.length) {
|
|
144
|
+
const bytesRead = fsSync.readSync(descriptor, bytes, totalBytes, bytes.length - totalBytes, totalBytes);
|
|
145
|
+
if (bytesRead === 0)
|
|
146
|
+
break;
|
|
147
|
+
totalBytes += bytesRead;
|
|
148
|
+
}
|
|
149
|
+
if (totalBytes > maximumBytes)
|
|
150
|
+
return { status: "unsafe" };
|
|
151
|
+
return { status: "ok", text: bytes.subarray(0, totalBytes).toString("utf8") };
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
return missingFilesystemEntry(error) ? { status: "missing" } : { status: "unsafe" };
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
if (descriptor !== undefined) {
|
|
158
|
+
try {
|
|
159
|
+
fsSync.closeSync(descriptor);
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// A failed close does not make an advisory read actionable.
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
export function parseUpdateCache(value) {
|
|
168
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
169
|
+
return undefined;
|
|
170
|
+
const candidate = value;
|
|
171
|
+
if (candidate.schemaVersion !== cacheSchemaVersion || candidate.packageName !== packageName)
|
|
172
|
+
return undefined;
|
|
173
|
+
const latestVersion = candidate.latestVersion;
|
|
174
|
+
const checkedAt = candidate.checkedAt;
|
|
175
|
+
const failedAt = candidate.failedAt;
|
|
176
|
+
const attemptedAt = candidate.attemptedAt;
|
|
177
|
+
const ownerGeneration = candidate.ownerGeneration;
|
|
178
|
+
const hasSuccessfulResult = latestVersion !== undefined || checkedAt !== undefined;
|
|
179
|
+
if (hasSuccessfulResult && (parseStableVersion(latestVersion) === undefined || !safeTimestamp(checkedAt)))
|
|
180
|
+
return undefined;
|
|
181
|
+
if (failedAt !== undefined && !safeTimestamp(failedAt))
|
|
182
|
+
return undefined;
|
|
183
|
+
if (attemptedAt !== undefined && !safeTimestamp(attemptedAt))
|
|
184
|
+
return undefined;
|
|
185
|
+
if (ownerGeneration !== undefined && (typeof ownerGeneration !== "string" || ownerGeneration.length === 0 || attemptedAt === undefined)) {
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
if (!hasSuccessfulResult && failedAt === undefined && attemptedAt === undefined)
|
|
189
|
+
return undefined;
|
|
190
|
+
return {
|
|
191
|
+
schemaVersion: 1,
|
|
192
|
+
packageName,
|
|
193
|
+
...(hasSuccessfulResult ? { latestVersion: latestVersion, checkedAt: checkedAt } : {}),
|
|
194
|
+
...(failedAt === undefined ? {} : { failedAt }),
|
|
195
|
+
...(attemptedAt === undefined ? {} : { attemptedAt }),
|
|
196
|
+
...(ownerGeneration === undefined ? {} : { ownerGeneration: ownerGeneration })
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
async function readUpdateCacheState(cachePath) {
|
|
200
|
+
const read = await readSafeRegularFile(cachePath, updateCacheMaxBytes);
|
|
201
|
+
if (read.status === "unsafe")
|
|
202
|
+
return { status: "unsafe" };
|
|
203
|
+
if (read.status === "missing")
|
|
204
|
+
return { status: "safe", cache: undefined };
|
|
205
|
+
try {
|
|
206
|
+
return { status: "safe", cache: parseUpdateCache(JSON.parse(read.text)) };
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
return { status: "safe", cache: undefined };
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
export async function readUpdateCache(cachePath) {
|
|
213
|
+
const read = await readUpdateCacheState(cachePath);
|
|
214
|
+
return read.status === "safe" ? read.cache : undefined;
|
|
215
|
+
}
|
|
216
|
+
function lockIsOwnedBySync(lock) {
|
|
217
|
+
if (safeDirectoryStatusSync(lock.path) !== "safe")
|
|
218
|
+
return false;
|
|
219
|
+
const read = readSafeRegularFileSync(path.join(lock.path, "owner.json"), updateLockOwnerMaxBytes);
|
|
220
|
+
if (read.status !== "ok")
|
|
221
|
+
return false;
|
|
222
|
+
try {
|
|
223
|
+
const parsed = JSON.parse(read.text);
|
|
224
|
+
const generation = typeof parsed.generation === "string" ? parsed.generation : parsed.token;
|
|
225
|
+
return generation === lock.generation && safeTimestamp(parsed.acquiredAt);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
function updateCacheCommitIsOwned(cachePath, guard) {
|
|
232
|
+
if (guard.expectedCacheOwnerGeneration !== undefined) {
|
|
233
|
+
const read = readSafeRegularFileSync(cachePath, updateCacheMaxBytes);
|
|
234
|
+
if (read.status !== "ok")
|
|
235
|
+
return false;
|
|
236
|
+
try {
|
|
237
|
+
const current = parseUpdateCache(JSON.parse(read.text));
|
|
238
|
+
if (current?.ownerGeneration !== guard.expectedCacheOwnerGeneration)
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (!lockIsOwnedBySync(guard.refresh))
|
|
246
|
+
return false;
|
|
247
|
+
return lockIsOwnedBySync(guard.transition);
|
|
248
|
+
}
|
|
249
|
+
async function commitUpdateCacheAtomically(cachePath, cache, guard) {
|
|
250
|
+
const directory = path.dirname(cachePath);
|
|
251
|
+
await ensureSafePrivateDirectory(directory);
|
|
252
|
+
const temporaryPath = path.join(directory, `.update-check.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}.tmp`);
|
|
253
|
+
try {
|
|
254
|
+
await fs.writeFile(temporaryPath, `${JSON.stringify(cache, null, 2)}\n`, { encoding: "utf8", flag: "wx", mode: 0o600 });
|
|
255
|
+
if (guard && !updateCacheCommitIsOwned(cachePath, guard))
|
|
256
|
+
return false;
|
|
257
|
+
fsSync.renameSync(temporaryPath, cachePath);
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
finally {
|
|
261
|
+
await fs.rm(temporaryPath, { force: true }).catch(() => undefined);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
export async function writeUpdateCacheAtomically(cachePath, cache) {
|
|
265
|
+
await commitUpdateCacheAtomically(cachePath, cache);
|
|
266
|
+
}
|
|
267
|
+
export function shouldRunUpdateNotifier(input) {
|
|
268
|
+
if (input.exitCode !== 0)
|
|
269
|
+
return false;
|
|
270
|
+
if (input.argv[0] !== "install" && input.argv[0] !== "doctor")
|
|
271
|
+
return false;
|
|
272
|
+
if (input.argv.some((arg) => arg === "--dry-run" || arg === "--json" || arg === "--help" || arg === "-h"))
|
|
273
|
+
return false;
|
|
274
|
+
if (input.stdinIsTTY !== true || input.stdoutIsTTY !== true || input.stderrIsTTY !== true)
|
|
275
|
+
return false;
|
|
276
|
+
if (input.env.CI !== undefined)
|
|
277
|
+
return false;
|
|
278
|
+
if (input.env.NO_UPDATE_NOTIFIER !== undefined || input.env.LITOPENCODE_NO_UPDATE_CHECK !== undefined)
|
|
279
|
+
return false;
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
export function shouldRefreshUpdateCache(cache, now) {
|
|
283
|
+
if (cacheHasFutureTimestamp(cache, now))
|
|
284
|
+
return true;
|
|
285
|
+
if (cache?.failedAt !== undefined && now - cache.failedAt < updateCheckIntervalMs)
|
|
286
|
+
return false;
|
|
287
|
+
if (cache?.checkedAt !== undefined && now - cache.checkedAt < updateCheckIntervalMs)
|
|
288
|
+
return false;
|
|
289
|
+
if (cache?.attemptedAt !== undefined && now - cache.attemptedAt < updateCheckIntervalMs)
|
|
290
|
+
return false;
|
|
291
|
+
return true;
|
|
292
|
+
}
|
|
293
|
+
function cacheHasFutureTimestamp(cache, now) {
|
|
294
|
+
return cache !== undefined && [cache.checkedAt, cache.failedAt, cache.attemptedAt]
|
|
295
|
+
.some((timestamp) => timestamp !== undefined && timestamp > now);
|
|
296
|
+
}
|
|
297
|
+
function successfulCacheFields(cache, now) {
|
|
298
|
+
if (cache === undefined ||
|
|
299
|
+
cacheHasFutureTimestamp(cache, now) ||
|
|
300
|
+
cache.latestVersion === undefined ||
|
|
301
|
+
cache.checkedAt === undefined) {
|
|
302
|
+
return {};
|
|
303
|
+
}
|
|
304
|
+
return { latestVersion: cache.latestVersion, checkedAt: cache.checkedAt };
|
|
305
|
+
}
|
|
306
|
+
export function renderUpdateNotice(currentVersion, latestVersion) {
|
|
307
|
+
if (compareStableVersions(latestVersion, currentVersion) !== 1)
|
|
308
|
+
return undefined;
|
|
309
|
+
return [
|
|
310
|
+
`LitOpenCode update available: ${String(currentVersion)} -> ${String(latestVersion)}`,
|
|
311
|
+
`Run: npm exec --yes --package @litfamily/litopencode@${String(latestVersion)} -- litopencode install --no-model-prompt --no-permission-prompt --no-auto-update`,
|
|
312
|
+
"Restart OpenCode after installing."
|
|
313
|
+
].join("\n");
|
|
314
|
+
}
|
|
315
|
+
function contentType(headers) {
|
|
316
|
+
const value = headers["content-type"];
|
|
317
|
+
return typeof value === "string" ? value : undefined;
|
|
318
|
+
}
|
|
319
|
+
export async function readRegistryLatestVersion(response) {
|
|
320
|
+
if (response.statusCode !== 200)
|
|
321
|
+
throw new Error("npm latest endpoint must return exact status 200");
|
|
322
|
+
const responseContentType = contentType(response.headers);
|
|
323
|
+
if (!responseContentType || !/^application\/json(?:\s*;[^\r\n]*)?$/i.test(responseContentType)) {
|
|
324
|
+
throw new Error("npm latest endpoint must return a JSON content type");
|
|
325
|
+
}
|
|
326
|
+
const declaredLength = response.headers["content-length"];
|
|
327
|
+
if (typeof declaredLength === "string" && /^\d+$/.test(declaredLength) && BigInt(declaredLength) > BigInt(updateResponseMaxBytes)) {
|
|
328
|
+
throw new Error("npm latest response exceeds 64 KiB");
|
|
329
|
+
}
|
|
330
|
+
const chunks = [];
|
|
331
|
+
let totalBytes = 0;
|
|
332
|
+
for await (const chunk of response) {
|
|
333
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
334
|
+
totalBytes += buffer.byteLength;
|
|
335
|
+
if (totalBytes > updateResponseMaxBytes)
|
|
336
|
+
throw new Error("npm latest response exceeds 64 KiB");
|
|
337
|
+
chunks.push(buffer);
|
|
338
|
+
}
|
|
339
|
+
let parsed;
|
|
340
|
+
try {
|
|
341
|
+
parsed = JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
throw new Error("npm latest endpoint returned invalid JSON");
|
|
345
|
+
}
|
|
346
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
347
|
+
throw new Error("npm latest endpoint returned an invalid package record");
|
|
348
|
+
}
|
|
349
|
+
const record = parsed;
|
|
350
|
+
if (record.name !== packageName)
|
|
351
|
+
throw new Error("npm latest endpoint returned the wrong package identity");
|
|
352
|
+
if (parseStableVersion(record.version) === undefined)
|
|
353
|
+
throw new Error("npm latest endpoint returned an invalid stable version");
|
|
354
|
+
return record.version;
|
|
355
|
+
}
|
|
356
|
+
export function requestRegistryLatestVersionWithTransport(transport) {
|
|
357
|
+
return new Promise((resolve, reject) => {
|
|
358
|
+
let settled = false;
|
|
359
|
+
let request;
|
|
360
|
+
const finish = (callback) => {
|
|
361
|
+
if (settled)
|
|
362
|
+
return;
|
|
363
|
+
settled = true;
|
|
364
|
+
clearTimeout(deadline);
|
|
365
|
+
callback();
|
|
366
|
+
};
|
|
367
|
+
const deadline = setTimeout(() => {
|
|
368
|
+
const error = new Error("npm latest request exceeded the 3 second total timeout");
|
|
369
|
+
finish(() => {
|
|
370
|
+
request?.destroy(error);
|
|
371
|
+
reject(error);
|
|
372
|
+
});
|
|
373
|
+
}, updateTimeoutMs);
|
|
374
|
+
try {
|
|
375
|
+
request = transport(npmLatestUrl, {
|
|
376
|
+
headers: {
|
|
377
|
+
accept: "application/json",
|
|
378
|
+
"user-agent": "litopencode-update-check"
|
|
379
|
+
}
|
|
380
|
+
}, (response) => {
|
|
381
|
+
void readRegistryLatestVersion(response).then((version) => finish(() => resolve(version)), (error) => finish(() => {
|
|
382
|
+
const responseError = error instanceof Error ? error : new Error(String(error));
|
|
383
|
+
request?.destroy(responseError);
|
|
384
|
+
reject(responseError);
|
|
385
|
+
}));
|
|
386
|
+
});
|
|
387
|
+
request.once("error", (error) => finish(() => reject(error)));
|
|
388
|
+
}
|
|
389
|
+
catch (error) {
|
|
390
|
+
finish(() => reject(error));
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
export function requestRegistryLatestVersion() {
|
|
395
|
+
return requestRegistryLatestVersionWithTransport((url, options, callback) => https.get(url, options, callback));
|
|
396
|
+
}
|
|
397
|
+
async function readLockOwner(lockPath) {
|
|
398
|
+
if ((await safeDirectoryStatus(lockPath)) !== "safe")
|
|
399
|
+
return { status: "unsafe" };
|
|
400
|
+
const read = await readSafeRegularFile(path.join(lockPath, "owner.json"), updateLockOwnerMaxBytes);
|
|
401
|
+
if (read.status === "unsafe")
|
|
402
|
+
return { status: "unsafe" };
|
|
403
|
+
if (read.status === "missing")
|
|
404
|
+
return { status: "missing" };
|
|
405
|
+
try {
|
|
406
|
+
const parsed = JSON.parse(read.text);
|
|
407
|
+
const generation = typeof parsed.generation === "string" ? parsed.generation : parsed.token;
|
|
408
|
+
if (typeof generation !== "string" || generation.length === 0 || !safeTimestamp(parsed.acquiredAt)) {
|
|
409
|
+
return { status: "invalid" };
|
|
410
|
+
}
|
|
411
|
+
return { status: "valid", owner: { path: lockPath, generation, acquiredAt: parsed.acquiredAt } };
|
|
412
|
+
}
|
|
413
|
+
catch {
|
|
414
|
+
return { status: "invalid" };
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
async function lockOwner(lockPath) {
|
|
418
|
+
const read = await readLockOwner(lockPath);
|
|
419
|
+
return read.status === "valid" ? read.owner : undefined;
|
|
420
|
+
}
|
|
421
|
+
async function lockIsStale(lockPath, now) {
|
|
422
|
+
const read = await readLockOwner(lockPath);
|
|
423
|
+
if (read.status === "unsafe")
|
|
424
|
+
return false;
|
|
425
|
+
if (read.status === "valid") {
|
|
426
|
+
return read.owner.acquiredAt > now || now - read.owner.acquiredAt >= updateLockStaleMs;
|
|
427
|
+
}
|
|
428
|
+
try {
|
|
429
|
+
const stats = await fs.lstat(lockPath);
|
|
430
|
+
if (!safePrivateDirectory(stats))
|
|
431
|
+
return false;
|
|
432
|
+
return stats.mtimeMs > now || now - stats.mtimeMs >= updateLockStaleMs;
|
|
433
|
+
}
|
|
434
|
+
catch {
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function wait(milliseconds) {
|
|
439
|
+
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
440
|
+
}
|
|
441
|
+
async function lockIsOwnedBy(lock) {
|
|
442
|
+
return (await lockOwner(lock.path))?.generation === lock.generation;
|
|
443
|
+
}
|
|
444
|
+
async function acquireTransitionLock(homeDir) {
|
|
445
|
+
const lockPath = updateTransitionLockPath(homeDir);
|
|
446
|
+
await ensureSafePrivateDirectory(path.dirname(lockPath));
|
|
447
|
+
const deadline = Date.now() + updateLockStaleMs + 1000;
|
|
448
|
+
while (true) {
|
|
449
|
+
const generation = randomUUID();
|
|
450
|
+
const acquiredAt = Date.now();
|
|
451
|
+
try {
|
|
452
|
+
await fs.mkdir(lockPath, { mode: 0o700 });
|
|
453
|
+
const owner = { path: lockPath, generation, acquiredAt };
|
|
454
|
+
try {
|
|
455
|
+
await fs.writeFile(path.join(lockPath, "owner.json"), `${JSON.stringify({ generation, acquiredAt })}\n`, {
|
|
456
|
+
encoding: "utf8",
|
|
457
|
+
flag: "wx",
|
|
458
|
+
mode: 0o600
|
|
459
|
+
});
|
|
460
|
+
return owner;
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
await fs.rm(lockPath, { recursive: true, force: true });
|
|
464
|
+
throw error;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
catch (error) {
|
|
468
|
+
if (error.code !== "EEXIST")
|
|
469
|
+
throw error;
|
|
470
|
+
const lockStatus = await safeDirectoryStatus(lockPath);
|
|
471
|
+
if (lockStatus === "missing") {
|
|
472
|
+
if (Date.now() >= deadline)
|
|
473
|
+
throw new Error("update transition mutex acquisition timed out");
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
if (lockStatus === "unsafe") {
|
|
477
|
+
throw new Error("update transition mutex is unsafe");
|
|
478
|
+
}
|
|
479
|
+
const ownerRead = await readSafeRegularFile(path.join(lockPath, "owner.json"), updateLockOwnerMaxBytes);
|
|
480
|
+
if (ownerRead.status === "unsafe")
|
|
481
|
+
throw new Error("update transition mutex owner is unsafe");
|
|
482
|
+
const currentNow = Date.now();
|
|
483
|
+
// Never age-evict this mutex: an owner paused at a filesystem await can still resume and mutate.
|
|
484
|
+
if (currentNow >= deadline)
|
|
485
|
+
throw new Error("update transition mutex acquisition timed out");
|
|
486
|
+
await wait(10);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
async function releaseOwnedLock(lock) {
|
|
491
|
+
const owner = await lockOwner(lock.path);
|
|
492
|
+
if (owner?.generation !== lock.generation)
|
|
493
|
+
return;
|
|
494
|
+
await fs.rm(lock.path, { recursive: true, force: true });
|
|
495
|
+
}
|
|
496
|
+
async function withTransitionLock(homeDir, operation) {
|
|
497
|
+
const transition = await acquireTransitionLock(homeDir);
|
|
498
|
+
try {
|
|
499
|
+
return await operation(transition);
|
|
500
|
+
}
|
|
501
|
+
finally {
|
|
502
|
+
await releaseOwnedLock(transition);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
async function acquireRefreshLock(homeDir, clock) {
|
|
506
|
+
return withTransitionLock(homeDir, async (transition) => {
|
|
507
|
+
const lockPath = updateLockPath(homeDir);
|
|
508
|
+
if (!(await lockIsOwnedBy(transition)))
|
|
509
|
+
return undefined;
|
|
510
|
+
try {
|
|
511
|
+
await fs.mkdir(lockPath, { mode: 0o700 });
|
|
512
|
+
}
|
|
513
|
+
catch (error) {
|
|
514
|
+
if (error.code !== "EEXIST")
|
|
515
|
+
throw error;
|
|
516
|
+
if (!(await lockIsStale(lockPath, clock())))
|
|
517
|
+
return undefined;
|
|
518
|
+
if (!(await lockIsOwnedBy(transition)))
|
|
519
|
+
return undefined;
|
|
520
|
+
await fs.rm(lockPath, { recursive: true, force: true });
|
|
521
|
+
await fs.mkdir(lockPath, { mode: 0o700 });
|
|
522
|
+
}
|
|
523
|
+
const generation = randomUUID();
|
|
524
|
+
try {
|
|
525
|
+
if (!(await lockIsOwnedBy(transition)))
|
|
526
|
+
return undefined;
|
|
527
|
+
const acquiredAt = clock();
|
|
528
|
+
const owner = { path: lockPath, generation, acquiredAt };
|
|
529
|
+
await fs.writeFile(path.join(lockPath, "owner.json"), `${JSON.stringify({ generation, acquiredAt })}\n`, {
|
|
530
|
+
encoding: "utf8",
|
|
531
|
+
flag: "wx",
|
|
532
|
+
mode: 0o600
|
|
533
|
+
});
|
|
534
|
+
return owner;
|
|
535
|
+
}
|
|
536
|
+
catch (error) {
|
|
537
|
+
if (await lockIsOwnedBy(transition))
|
|
538
|
+
await fs.rm(lockPath, { recursive: true, force: true });
|
|
539
|
+
throw error;
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
async function reserveRefreshAttempt(homeDir, cachePath, lock, clock) {
|
|
544
|
+
return withTransitionLock(homeDir, async (transition) => {
|
|
545
|
+
const owner = await lockOwner(lock.path);
|
|
546
|
+
if (owner?.generation !== lock.generation)
|
|
547
|
+
return false;
|
|
548
|
+
const cacheRead = await readUpdateCacheState(cachePath);
|
|
549
|
+
if (cacheRead.status === "unsafe")
|
|
550
|
+
return false;
|
|
551
|
+
const current = cacheRead.cache;
|
|
552
|
+
if (!shouldRefreshUpdateCache(current, clock()))
|
|
553
|
+
return false;
|
|
554
|
+
if ((await lockOwner(lock.path))?.generation !== lock.generation)
|
|
555
|
+
return false;
|
|
556
|
+
if (!(await lockIsOwnedBy(transition)))
|
|
557
|
+
return false;
|
|
558
|
+
const attemptedAt = clock();
|
|
559
|
+
return commitUpdateCacheAtomically(cachePath, {
|
|
560
|
+
schemaVersion: 1,
|
|
561
|
+
packageName,
|
|
562
|
+
...successfulCacheFields(current, attemptedAt),
|
|
563
|
+
attemptedAt,
|
|
564
|
+
ownerGeneration: lock.generation
|
|
565
|
+
}, {
|
|
566
|
+
transition,
|
|
567
|
+
refresh: lock
|
|
568
|
+
});
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
async function commitRefreshCompletion(homeDir, cachePath, lock, clock, completion) {
|
|
572
|
+
return withTransitionLock(homeDir, async (transition) => {
|
|
573
|
+
const owner = await lockOwner(lock.path);
|
|
574
|
+
if (owner?.generation !== lock.generation)
|
|
575
|
+
return false;
|
|
576
|
+
const cacheRead = await readUpdateCacheState(cachePath);
|
|
577
|
+
if (cacheRead.status === "unsafe")
|
|
578
|
+
return false;
|
|
579
|
+
const current = cacheRead.cache;
|
|
580
|
+
if (current?.ownerGeneration !== lock.generation)
|
|
581
|
+
return false;
|
|
582
|
+
if ((await lockOwner(lock.path))?.generation !== lock.generation)
|
|
583
|
+
return false;
|
|
584
|
+
if (!(await lockIsOwnedBy(transition)))
|
|
585
|
+
return false;
|
|
586
|
+
const completedAt = clock();
|
|
587
|
+
let committed;
|
|
588
|
+
if (completion.status === "success") {
|
|
589
|
+
committed = await commitUpdateCacheAtomically(cachePath, {
|
|
590
|
+
schemaVersion: 1,
|
|
591
|
+
packageName,
|
|
592
|
+
latestVersion: completion.latestVersion,
|
|
593
|
+
checkedAt: completedAt
|
|
594
|
+
}, {
|
|
595
|
+
transition,
|
|
596
|
+
refresh: lock,
|
|
597
|
+
expectedCacheOwnerGeneration: lock.generation
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
else {
|
|
601
|
+
committed = await commitUpdateCacheAtomically(cachePath, {
|
|
602
|
+
schemaVersion: 1,
|
|
603
|
+
packageName,
|
|
604
|
+
...successfulCacheFields(current, completedAt),
|
|
605
|
+
failedAt: completedAt
|
|
606
|
+
}, {
|
|
607
|
+
transition,
|
|
608
|
+
refresh: lock,
|
|
609
|
+
expectedCacheOwnerGeneration: lock.generation
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
if (!committed)
|
|
613
|
+
return false;
|
|
614
|
+
if ((await lockOwner(lock.path))?.generation !== lock.generation)
|
|
615
|
+
return false;
|
|
616
|
+
if (!(await lockIsOwnedBy(transition)))
|
|
617
|
+
return false;
|
|
618
|
+
await fs.rm(lock.path, { recursive: true, force: true });
|
|
619
|
+
return true;
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
async function releaseRefreshLock(homeDir, lock) {
|
|
623
|
+
await withTransitionLock(homeDir, async (transition) => {
|
|
624
|
+
if ((await lockOwner(lock.path))?.generation !== lock.generation)
|
|
625
|
+
return;
|
|
626
|
+
if (!(await lockIsOwnedBy(transition)))
|
|
627
|
+
return;
|
|
628
|
+
await fs.rm(lock.path, { recursive: true, force: true });
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
export async function refreshUpdateCache(options = {}) {
|
|
632
|
+
const stateDirectory = path.dirname(updateCachePath(options.homeDir));
|
|
633
|
+
if ((await safeDirectoryStatus(stateDirectory)) === "unsafe")
|
|
634
|
+
return;
|
|
635
|
+
const transitionPath = updateTransitionLockPath(options.homeDir);
|
|
636
|
+
const transitionStatus = await safeDirectoryStatus(transitionPath);
|
|
637
|
+
if (transitionStatus === "unsafe")
|
|
638
|
+
return;
|
|
639
|
+
if (transitionStatus === "safe") {
|
|
640
|
+
const ownerRead = await readSafeRegularFile(path.join(transitionPath, "owner.json"), updateLockOwnerMaxBytes);
|
|
641
|
+
if (ownerRead.status === "unsafe")
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
const fixedNow = options.now;
|
|
645
|
+
const clock = options.clock ?? (fixedNow === undefined ? Date.now : () => fixedNow);
|
|
646
|
+
const cachePath = updateCachePath(options.homeDir);
|
|
647
|
+
const lock = await acquireRefreshLock(options.homeDir, clock);
|
|
648
|
+
if (!lock)
|
|
649
|
+
return;
|
|
650
|
+
try {
|
|
651
|
+
if (!(await reserveRefreshAttempt(options.homeDir, cachePath, lock, clock)))
|
|
652
|
+
return;
|
|
653
|
+
try {
|
|
654
|
+
const latestVersion = await (options.fetchLatestVersion ?? requestRegistryLatestVersion)();
|
|
655
|
+
if (parseStableVersion(latestVersion) === undefined)
|
|
656
|
+
throw new Error("update check returned an invalid stable version");
|
|
657
|
+
await commitRefreshCompletion(options.homeDir, cachePath, lock, clock, { status: "success", latestVersion });
|
|
658
|
+
}
|
|
659
|
+
catch {
|
|
660
|
+
await commitRefreshCompletion(options.homeDir, cachePath, lock, clock, { status: "failure" });
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
finally {
|
|
664
|
+
await releaseRefreshLock(options.homeDir, lock);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
function detachedUpdateEnvironment(env) {
|
|
668
|
+
const childEnv = {};
|
|
669
|
+
for (const key of ["HOME", "USERPROFILE", "HOMEDRIVE", "HOMEPATH", "SystemRoot", "SYSTEMROOT", "NODE_EXTRA_CA_CERTS", "SSL_CERT_FILE", "SSL_CERT_DIR"]) {
|
|
670
|
+
if (env[key] !== undefined)
|
|
671
|
+
childEnv[key] = env[key];
|
|
672
|
+
}
|
|
673
|
+
return childEnv;
|
|
674
|
+
}
|
|
675
|
+
export function launchDetachedUpdateRefreshWith(spawnProcess, env, execPath, helperPath) {
|
|
676
|
+
const child = spawnProcess(execPath, [helperPath, "--refresh"], {
|
|
677
|
+
detached: true,
|
|
678
|
+
stdio: "ignore",
|
|
679
|
+
env: detachedUpdateEnvironment(env)
|
|
680
|
+
});
|
|
681
|
+
child.once("error", () => undefined);
|
|
682
|
+
child.unref();
|
|
683
|
+
}
|
|
684
|
+
export function launchDetachedUpdateRefresh(env = process.env) {
|
|
685
|
+
const helperPath = fileURLToPath(new URL("./update-check.js", import.meta.url));
|
|
686
|
+
launchDetachedUpdateRefreshWith(spawn, env, process.execPath, helperPath);
|
|
687
|
+
}
|
|
688
|
+
export async function runUpdateNotifier(options) {
|
|
689
|
+
if (!shouldRunUpdateNotifier(options))
|
|
690
|
+
return;
|
|
691
|
+
try {
|
|
692
|
+
const metadata = options.currentVersion === undefined ? await readPackageMetadata() : undefined;
|
|
693
|
+
if (metadata && metadata.name !== packageName)
|
|
694
|
+
return;
|
|
695
|
+
const currentVersion = options.currentVersion ?? metadata?.version;
|
|
696
|
+
if (parseStableVersion(currentVersion) === undefined)
|
|
697
|
+
return;
|
|
698
|
+
const stateDirectory = path.dirname(updateCachePath(options.homeDir));
|
|
699
|
+
if ((await safeDirectoryStatus(stateDirectory)) === "unsafe")
|
|
700
|
+
return;
|
|
701
|
+
const now = options.now ?? Date.now();
|
|
702
|
+
const cacheRead = await readUpdateCacheState(updateCachePath(options.homeDir));
|
|
703
|
+
if (cacheRead.status === "unsafe")
|
|
704
|
+
return;
|
|
705
|
+
const cache = cacheRead.cache;
|
|
706
|
+
const notice = cache?.latestVersion === undefined || cacheHasFutureTimestamp(cache, now)
|
|
707
|
+
? undefined
|
|
708
|
+
: renderUpdateNotice(currentVersion, cache.latestVersion);
|
|
709
|
+
if (notice)
|
|
710
|
+
(options.writeStderr ?? ((text) => process.stderr.write(text)))(`${notice}\n`);
|
|
711
|
+
if (shouldRefreshUpdateCache(cache, now))
|
|
712
|
+
(options.launchRefresh ?? (() => launchDetachedUpdateRefresh(options.env)))();
|
|
713
|
+
}
|
|
714
|
+
catch {
|
|
715
|
+
// Update checks are advisory and must never change CLI command behavior.
|
|
716
|
+
}
|
|
717
|
+
}
|