@lyse-labs/lyse 0.1.0-alpha.2
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/LICENSE +45 -0
- package/PRIVACY.md +181 -0
- package/README.md +34 -0
- package/SECURITY.md +43 -0
- package/dist/bench/evidence-pack/anti-dummy.d.ts +11 -0
- package/dist/bench/evidence-pack/anti-dummy.js +20 -0
- package/dist/bench/evidence-pack/anti-dummy.js.map +1 -0
- package/dist/bench/evidence-pack/builder.d.ts +14 -0
- package/dist/bench/evidence-pack/builder.js +77 -0
- package/dist/bench/evidence-pack/builder.js.map +1 -0
- package/dist/bench/evidence-pack/histograms.d.ts +2 -0
- package/dist/bench/evidence-pack/histograms.js +131 -0
- package/dist/bench/evidence-pack/histograms.js.map +1 -0
- package/dist/bench/evidence-pack/manifest-detector.d.ts +2 -0
- package/dist/bench/evidence-pack/manifest-detector.js +65 -0
- package/dist/bench/evidence-pack/manifest-detector.js.map +1 -0
- package/dist/bench/evidence-pack/package-json-digest.d.ts +2 -0
- package/dist/bench/evidence-pack/package-json-digest.js +51 -0
- package/dist/bench/evidence-pack/package-json-digest.js.map +1 -0
- package/dist/bench/evidence-pack/sampler.d.ts +2 -0
- package/dist/bench/evidence-pack/sampler.js +140 -0
- package/dist/bench/evidence-pack/sampler.js.map +1 -0
- package/dist/bench/evidence-pack/types.d.ts +127 -0
- package/dist/bench/evidence-pack/types.js +2 -0
- package/dist/bench/evidence-pack/types.js.map +1 -0
- package/dist/bench/evidence-pack/verifier-corpus.d.ts +5 -0
- package/dist/bench/evidence-pack/verifier-corpus.js +13 -0
- package/dist/bench/evidence-pack/verifier-corpus.js.map +1 -0
- package/dist/bench/taxonomy-loader.d.ts +20 -0
- package/dist/bench/taxonomy-loader.js +28 -0
- package/dist/bench/taxonomy-loader.js.map +1 -0
- package/dist/bench/taxonomy.v3.json +20 -0
- package/dist/cli/__tests__/version-migration.test.d.ts +1 -0
- package/dist/cli/__tests__/version-migration.test.js +69 -0
- package/dist/cli/__tests__/version-migration.test.js.map +1 -0
- package/dist/cli/output/__tests__/eslint-style.test.d.ts +1 -0
- package/dist/cli/output/__tests__/eslint-style.test.js +205 -0
- package/dist/cli/output/__tests__/eslint-style.test.js.map +1 -0
- package/dist/cli/output/__tests__/limit.test.d.ts +1 -0
- package/dist/cli/output/__tests__/limit.test.js +65 -0
- package/dist/cli/output/__tests__/limit.test.js.map +1 -0
- package/dist/cli/output/eslint-style.d.ts +18 -0
- package/dist/cli/output/eslint-style.js +42 -0
- package/dist/cli/output/eslint-style.js.map +1 -0
- package/dist/cli/output/limit.d.ts +5 -0
- package/dist/cli/output/limit.js +32 -0
- package/dist/cli/output/limit.js.map +1 -0
- package/dist/cli/output/score-gauge.d.ts +4 -0
- package/dist/cli/output/score-gauge.js +15 -0
- package/dist/cli/output/score-gauge.js.map +1 -0
- package/dist/cli/version-migration.d.ts +18 -0
- package/dist/cli/version-migration.js +49 -0
- package/dist/cli/version-migration.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +856 -0
- package/dist/cli.js.map +1 -0
- package/dist/codemods/diff.d.ts +17 -0
- package/dist/codemods/diff.js +77 -0
- package/dist/codemods/diff.js.map +1 -0
- package/dist/codemods/git-helpers.d.ts +10 -0
- package/dist/codemods/git-helpers.js +75 -0
- package/dist/codemods/git-helpers.js.map +1 -0
- package/dist/codemods/index.d.ts +27 -0
- package/dist/codemods/index.js +40 -0
- package/dist/codemods/index.js.map +1 -0
- package/dist/codemods/naming-component-pascalcase.d.ts +13 -0
- package/dist/codemods/naming-component-pascalcase.js +106 -0
- package/dist/codemods/naming-component-pascalcase.js.map +1 -0
- package/dist/codemods/naming-hook-prefix.d.ts +13 -0
- package/dist/codemods/naming-hook-prefix.js +86 -0
- package/dist/codemods/naming-hook-prefix.js.map +1 -0
- package/dist/codemods/safety.d.ts +50 -0
- package/dist/codemods/safety.js +109 -0
- package/dist/codemods/safety.js.map +1 -0
- package/dist/codemods/safety.test.d.ts +1 -0
- package/dist/codemods/safety.test.js +154 -0
- package/dist/codemods/safety.test.js.map +1 -0
- package/dist/codemods/shadow-native.d.ts +2 -0
- package/dist/codemods/shadow-native.js +103 -0
- package/dist/codemods/shadow-native.js.map +1 -0
- package/dist/codemods/tokens-color.d.ts +2 -0
- package/dist/codemods/tokens-color.js +69 -0
- package/dist/codemods/tokens-color.js.map +1 -0
- package/dist/codemods/tokens-spacing.d.ts +2 -0
- package/dist/codemods/tokens-spacing.js +66 -0
- package/dist/codemods/tokens-spacing.js.map +1 -0
- package/dist/commands/__tests__/email-prompt.test.d.ts +1 -0
- package/dist/commands/__tests__/email-prompt.test.js +126 -0
- package/dist/commands/__tests__/email-prompt.test.js.map +1 -0
- package/dist/commands/__tests__/explain-score.test.d.ts +1 -0
- package/dist/commands/__tests__/explain-score.test.js +88 -0
- package/dist/commands/__tests__/explain-score.test.js.map +1 -0
- package/dist/commands/__tests__/feedback.test.d.ts +1 -0
- package/dist/commands/__tests__/feedback.test.js +186 -0
- package/dist/commands/__tests__/feedback.test.js.map +1 -0
- package/dist/commands/audit-flags.d.ts +49 -0
- package/dist/commands/audit-flags.js +17 -0
- package/dist/commands/audit-flags.js.map +1 -0
- package/dist/commands/audit-pipeline.d.ts +31 -0
- package/dist/commands/audit-pipeline.js +342 -0
- package/dist/commands/audit-pipeline.js.map +1 -0
- package/dist/commands/bench-pack.d.ts +5 -0
- package/dist/commands/bench-pack.js +61 -0
- package/dist/commands/bench-pack.js.map +1 -0
- package/dist/commands/ci-setup.d.ts +9 -0
- package/dist/commands/ci-setup.js +42 -0
- package/dist/commands/ci-setup.js.map +1 -0
- package/dist/commands/email-prompt.d.ts +36 -0
- package/dist/commands/email-prompt.js +160 -0
- package/dist/commands/email-prompt.js.map +1 -0
- package/dist/commands/explain-score.d.ts +35 -0
- package/dist/commands/explain-score.js +137 -0
- package/dist/commands/explain-score.js.map +1 -0
- package/dist/commands/explain.d.ts +6 -0
- package/dist/commands/explain.js +93 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/feedback.d.ts +31 -0
- package/dist/commands/feedback.js +155 -0
- package/dist/commands/feedback.js.map +1 -0
- package/dist/commands/fix.d.ts +48 -0
- package/dist/commands/fix.js +191 -0
- package/dist/commands/fix.js.map +1 -0
- package/dist/commands/init-detect.d.ts +20 -0
- package/dist/commands/init-detect.js +124 -0
- package/dist/commands/init-detect.js.map +1 -0
- package/dist/commands/init-write-agents-md.d.ts +14 -0
- package/dist/commands/init-write-agents-md.js +71 -0
- package/dist/commands/init-write-agents-md.js.map +1 -0
- package/dist/commands/init-write-lyse-md.d.ts +14 -0
- package/dist/commands/init-write-lyse-md.js +253 -0
- package/dist/commands/init-write-lyse-md.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.js +147 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/mcp-entry.d.ts +33 -0
- package/dist/commands/mcp-entry.js +47 -0
- package/dist/commands/mcp-entry.js.map +1 -0
- package/dist/commands/mcp-setup.d.ts +10 -0
- package/dist/commands/mcp-setup.js +74 -0
- package/dist/commands/mcp-setup.js.map +1 -0
- package/dist/commands/share.d.ts +4 -0
- package/dist/commands/share.js +60 -0
- package/dist/commands/share.js.map +1 -0
- package/dist/commands/telemetry.d.ts +4 -0
- package/dist/commands/telemetry.js +27 -0
- package/dist/commands/telemetry.js.map +1 -0
- package/dist/commands/templates/lyse-workflow.yml.template +30 -0
- package/dist/config/schema.d.ts +158 -0
- package/dist/config/schema.js +136 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/credentials/keychain.d.ts +20 -0
- package/dist/credentials/keychain.js +35 -0
- package/dist/credentials/keychain.js.map +1 -0
- package/dist/credentials/keychain.test.d.ts +1 -0
- package/dist/credentials/keychain.test.js +32 -0
- package/dist/credentials/keychain.test.js.map +1 -0
- package/dist/credentials/paths.d.ts +1 -0
- package/dist/credentials/paths.js +6 -0
- package/dist/credentials/paths.js.map +1 -0
- package/dist/credentials/store.d.ts +17 -0
- package/dist/credentials/store.js +60 -0
- package/dist/credentials/store.js.map +1 -0
- package/dist/credentials/store.test.d.ts +1 -0
- package/dist/credentials/store.test.js +48 -0
- package/dist/credentials/store.test.js.map +1 -0
- package/dist/detection/from-filesystem.d.ts +2 -0
- package/dist/detection/from-filesystem.js +26 -0
- package/dist/detection/from-filesystem.js.map +1 -0
- package/dist/detection/from-git.d.ts +2 -0
- package/dist/detection/from-git.js +53 -0
- package/dist/detection/from-git.js.map +1 -0
- package/dist/detection/from-package-json.d.ts +2 -0
- package/dist/detection/from-package-json.js +194 -0
- package/dist/detection/from-package-json.js.map +1 -0
- package/dist/detection/pre-flight.d.ts +5 -0
- package/dist/detection/pre-flight.js +47 -0
- package/dist/detection/pre-flight.js.map +1 -0
- package/dist/detection/types.d.ts +27 -0
- package/dist/detection/types.js +2 -0
- package/dist/detection/types.js.map +1 -0
- package/dist/entitlement/check.d.ts +7 -0
- package/dist/entitlement/check.js +37 -0
- package/dist/entitlement/check.js.map +1 -0
- package/dist/entitlement/index.d.ts +1 -0
- package/dist/entitlement/index.js +2 -0
- package/dist/entitlement/index.js.map +1 -0
- package/dist/entitlement/keys.d.ts +10 -0
- package/dist/entitlement/keys.js +14 -0
- package/dist/entitlement/keys.js.map +1 -0
- package/dist/history/ndjson-store.d.ts +70 -0
- package/dist/history/ndjson-store.js +102 -0
- package/dist/history/ndjson-store.js.map +1 -0
- package/dist/identity/index.d.ts +1 -0
- package/dist/identity/index.js +2 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/identity/repo-bucket.d.ts +22 -0
- package/dist/identity/repo-bucket.js +78 -0
- package/dist/identity/repo-bucket.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/layer4-stage.d.ts +18 -0
- package/dist/llm/layer4-stage.js +12 -0
- package/dist/llm/layer4-stage.js.map +1 -0
- package/dist/loaders/components.d.ts +26 -0
- package/dist/loaders/components.js +285 -0
- package/dist/loaders/components.js.map +1 -0
- package/dist/loaders/stories.d.ts +2 -0
- package/dist/loaders/stories.js +231 -0
- package/dist/loaders/stories.js.map +1 -0
- package/dist/loaders/token-graph.d.ts +39 -0
- package/dist/loaders/token-graph.js +146 -0
- package/dist/loaders/token-graph.js.map +1 -0
- package/dist/loaders/tokens.d.ts +2 -0
- package/dist/loaders/tokens.js +521 -0
- package/dist/loaders/tokens.js.map +1 -0
- package/dist/mcp/_find-root.d.ts +12 -0
- package/dist/mcp/_find-root.js +28 -0
- package/dist/mcp/_find-root.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +42 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/audit-file.d.ts +25 -0
- package/dist/mcp/tools/audit-file.js +147 -0
- package/dist/mcp/tools/audit-file.js.map +1 -0
- package/dist/mcp/tools/suggest-fix.d.ts +13 -0
- package/dist/mcp/tools/suggest-fix.js +100 -0
- package/dist/mcp/tools/suggest-fix.js.map +1 -0
- package/dist/menu/action-menu.d.ts +6 -0
- package/dist/menu/action-menu.js +15 -0
- package/dist/menu/action-menu.js.map +1 -0
- package/dist/menu/prompts.d.ts +7 -0
- package/dist/menu/prompts.js +30 -0
- package/dist/menu/prompts.js.map +1 -0
- package/dist/menu/repl.d.ts +17 -0
- package/dist/menu/repl.js +77 -0
- package/dist/menu/repl.js.map +1 -0
- package/dist/parsers/css-in-js.d.ts +2 -0
- package/dist/parsers/css-in-js.js +69 -0
- package/dist/parsers/css-in-js.js.map +1 -0
- package/dist/parsers/css.d.ts +2 -0
- package/dist/parsers/css.js +32 -0
- package/dist/parsers/css.js.map +1 -0
- package/dist/parsers/scss-transform.d.ts +25 -0
- package/dist/parsers/scss-transform.js +55 -0
- package/dist/parsers/scss-transform.js.map +1 -0
- package/dist/parsers/tailwind-v4.d.ts +8 -0
- package/dist/parsers/tailwind-v4.js +90 -0
- package/dist/parsers/tailwind-v4.js.map +1 -0
- package/dist/parsers/ts-morph-project.d.ts +16 -0
- package/dist/parsers/ts-morph-project.js +77 -0
- package/dist/parsers/ts-morph-project.js.map +1 -0
- package/dist/parsers/ts.d.ts +2 -0
- package/dist/parsers/ts.js +61 -0
- package/dist/parsers/ts.js.map +1 -0
- package/dist/reliability/__tests__/types.test.d.ts +1 -0
- package/dist/reliability/__tests__/types.test.js +14 -0
- package/dist/reliability/__tests__/types.test.js.map +1 -0
- package/dist/reliability/catalogue/__tests__/promotion.test.d.ts +1 -0
- package/dist/reliability/catalogue/__tests__/promotion.test.js +23 -0
- package/dist/reliability/catalogue/__tests__/promotion.test.js.map +1 -0
- package/dist/reliability/catalogue/__tests__/sub-axes.test.d.ts +1 -0
- package/dist/reliability/catalogue/__tests__/sub-axes.test.js +27 -0
- package/dist/reliability/catalogue/__tests__/sub-axes.test.js.map +1 -0
- package/dist/reliability/catalogue/promotion.d.ts +8 -0
- package/dist/reliability/catalogue/promotion.js +25 -0
- package/dist/reliability/catalogue/promotion.js.map +1 -0
- package/dist/reliability/catalogue/sub-axes.d.ts +3 -0
- package/dist/reliability/catalogue/sub-axes.js +18 -0
- package/dist/reliability/catalogue/sub-axes.js.map +1 -0
- package/dist/reliability/confidence/__tests__/manifest-loader.test.d.ts +1 -0
- package/dist/reliability/confidence/__tests__/manifest-loader.test.js +103 -0
- package/dist/reliability/confidence/__tests__/manifest-loader.test.js.map +1 -0
- package/dist/reliability/confidence/bundled-manifest.d.ts +2 -0
- package/dist/reliability/confidence/bundled-manifest.js +8 -0
- package/dist/reliability/confidence/bundled-manifest.js.map +1 -0
- package/dist/reliability/confidence/index.d.ts +3 -0
- package/dist/reliability/confidence/index.js +3 -0
- package/dist/reliability/confidence/index.js.map +1 -0
- package/dist/reliability/confidence/manifest-loader.d.ts +8 -0
- package/dist/reliability/confidence/manifest-loader.js +53 -0
- package/dist/reliability/confidence/manifest-loader.js.map +1 -0
- package/dist/reliability/feedback/__tests__/interactive.test.d.ts +1 -0
- package/dist/reliability/feedback/__tests__/interactive.test.js +85 -0
- package/dist/reliability/feedback/__tests__/interactive.test.js.map +1 -0
- package/dist/reliability/feedback/__tests__/repo-bucket.test.d.ts +1 -0
- package/dist/reliability/feedback/__tests__/repo-bucket.test.js +18 -0
- package/dist/reliability/feedback/__tests__/repo-bucket.test.js.map +1 -0
- package/dist/reliability/feedback/__tests__/sender.test.d.ts +1 -0
- package/dist/reliability/feedback/__tests__/sender.test.js +101 -0
- package/dist/reliability/feedback/__tests__/sender.test.js.map +1 -0
- package/dist/reliability/feedback/interactive.d.ts +20 -0
- package/dist/reliability/feedback/interactive.js +150 -0
- package/dist/reliability/feedback/interactive.js.map +1 -0
- package/dist/reliability/feedback/repo-bucket.d.ts +2 -0
- package/dist/reliability/feedback/repo-bucket.js +9 -0
- package/dist/reliability/feedback/repo-bucket.js.map +1 -0
- package/dist/reliability/feedback/sender.d.ts +16 -0
- package/dist/reliability/feedback/sender.js +28 -0
- package/dist/reliability/feedback/sender.js.map +1 -0
- package/dist/reliability/index.d.ts +1 -0
- package/dist/reliability/index.js +2 -0
- package/dist/reliability/index.js.map +1 -0
- package/dist/reliability/llm-eval/__tests__/budget.test.d.ts +1 -0
- package/dist/reliability/llm-eval/__tests__/budget.test.js +39 -0
- package/dist/reliability/llm-eval/__tests__/budget.test.js.map +1 -0
- package/dist/reliability/llm-eval/budget.d.ts +14 -0
- package/dist/reliability/llm-eval/budget.js +43 -0
- package/dist/reliability/llm-eval/budget.js.map +1 -0
- package/dist/reliability/score/__tests__/formula-v1.test.d.ts +1 -0
- package/dist/reliability/score/__tests__/formula-v1.test.js +29 -0
- package/dist/reliability/score/__tests__/formula-v1.test.js.map +1 -0
- package/dist/reliability/score/formula-v1.d.ts +13 -0
- package/dist/reliability/score/formula-v1.js +19 -0
- package/dist/reliability/score/formula-v1.js.map +1 -0
- package/dist/reliability/score/version-pin.d.ts +1 -0
- package/dist/reliability/score/version-pin.js +2 -0
- package/dist/reliability/score/version-pin.js.map +1 -0
- package/dist/reliability/score/weight.d.ts +1 -0
- package/dist/reliability/score/weight.js +5 -0
- package/dist/reliability/score/weight.js.map +1 -0
- package/dist/reliability/types.d.ts +39 -0
- package/dist/reliability/types.js +2 -0
- package/dist/reliability/types.js.map +1 -0
- package/dist/reporters/coverage-footer.d.ts +2 -0
- package/dist/reporters/coverage-footer.js +7 -0
- package/dist/reporters/coverage-footer.js.map +1 -0
- package/dist/reporters/json.d.ts +5 -0
- package/dist/reporters/json.js +51 -0
- package/dist/reporters/json.js.map +1 -0
- package/dist/reporters/markdown.d.ts +7 -0
- package/dist/reporters/markdown.js +35 -0
- package/dist/reporters/markdown.js.map +1 -0
- package/dist/reporters/sarif.d.ts +5 -0
- package/dist/reporters/sarif.js +109 -0
- package/dist/reporters/sarif.js.map +1 -0
- package/dist/reporters/terminal-format.d.ts +34 -0
- package/dist/reporters/terminal-format.js +97 -0
- package/dist/reporters/terminal-format.js.map +1 -0
- package/dist/reporters/terminal.d.ts +4 -0
- package/dist/reporters/terminal.js +201 -0
- package/dist/reporters/terminal.js.map +1 -0
- package/dist/rule-runner.d.ts +8 -0
- package/dist/rule-runner.js +22 -0
- package/dist/rule-runner.js.map +1 -0
- package/dist/rules/_codemod-adapter.d.ts +16 -0
- package/dist/rules/_codemod-adapter.js +49 -0
- package/dist/rules/_codemod-adapter.js.map +1 -0
- package/dist/rules/_exclude.d.ts +11 -0
- package/dist/rules/_exclude.js +17 -0
- package/dist/rules/_exclude.js.map +1 -0
- package/dist/rules/_function-body-analysis.d.ts +82 -0
- package/dist/rules/_function-body-analysis.js +379 -0
- package/dist/rules/_function-body-analysis.js.map +1 -0
- package/dist/rules/_rule-module.d.ts +31 -0
- package/dist/rules/_rule-module.js +32 -0
- package/dist/rules/_rule-module.js.map +1 -0
- package/dist/rules/_skip-context.d.ts +36 -0
- package/dist/rules/_skip-context.js +128 -0
- package/dist/rules/_skip-context.js.map +1 -0
- package/dist/rules/a11y-essentials.d.ts +1 -0
- package/dist/rules/a11y-essentials.js +140 -0
- package/dist/rules/a11y-essentials.js.map +1 -0
- package/dist/rules/ai-surface-agents-md-quality.d.ts +22 -0
- package/dist/rules/ai-surface-agents-md-quality.js +233 -0
- package/dist/rules/ai-surface-agents-md-quality.js.map +1 -0
- package/dist/rules/ai-surface-component-manifest-json.d.ts +19 -0
- package/dist/rules/ai-surface-component-manifest-json.js +232 -0
- package/dist/rules/ai-surface-component-manifest-json.js.map +1 -0
- package/dist/rules/ai-surface-ds-index-exported.d.ts +19 -0
- package/dist/rules/ai-surface-ds-index-exported.js +239 -0
- package/dist/rules/ai-surface-ds-index-exported.js.map +1 -0
- package/dist/rules/components-shadow-native.d.ts +2 -0
- package/dist/rules/components-shadow-native.js +118 -0
- package/dist/rules/components-shadow-native.js.map +1 -0
- package/dist/rules/manifest.d.ts +5 -0
- package/dist/rules/manifest.js +20 -0
- package/dist/rules/manifest.js.map +1 -0
- package/dist/rules/naming-component-pascalcase.d.ts +7 -0
- package/dist/rules/naming-component-pascalcase.js +197 -0
- package/dist/rules/naming-component-pascalcase.js.map +1 -0
- package/dist/rules/naming-hook-prefix.d.ts +6 -0
- package/dist/rules/naming-hook-prefix.js +185 -0
- package/dist/rules/naming-hook-prefix.js.map +1 -0
- package/dist/rules/pack-loader.d.ts +30 -0
- package/dist/rules/pack-loader.js +60 -0
- package/dist/rules/pack-loader.js.map +1 -0
- package/dist/rules/pack-validator.d.ts +8 -0
- package/dist/rules/pack-validator.js +97 -0
- package/dist/rules/pack-validator.js.map +1 -0
- package/dist/rules/registry.d.ts +3 -0
- package/dist/rules/registry.js +28 -0
- package/dist/rules/registry.js.map +1 -0
- package/dist/rules/storybook-coverage.d.ts +1 -0
- package/dist/rules/storybook-coverage.js +49 -0
- package/dist/rules/storybook-coverage.js.map +1 -0
- package/dist/rules/templates/_regex-utils.d.ts +5 -0
- package/dist/rules/templates/_regex-utils.js +8 -0
- package/dist/rules/templates/_regex-utils.js.map +1 -0
- package/dist/rules/templates/a11y-jsx-template.d.ts +15 -0
- package/dist/rules/templates/a11y-jsx-template.js +69 -0
- package/dist/rules/templates/a11y-jsx-template.js.map +1 -0
- package/dist/rules/templates/css-property-token-compliance.d.ts +18 -0
- package/dist/rules/templates/css-property-token-compliance.js +56 -0
- package/dist/rules/templates/css-property-token-compliance.js.map +1 -0
- package/dist/rules/templates/import-source-restriction.d.ts +18 -0
- package/dist/rules/templates/import-source-restriction.js +60 -0
- package/dist/rules/templates/import-source-restriction.js.map +1 -0
- package/dist/rules/templates/js-call-token-compliance.d.ts +18 -0
- package/dist/rules/templates/js-call-token-compliance.js +61 -0
- package/dist/rules/templates/js-call-token-compliance.js.map +1 -0
- package/dist/rules/templates/js-prop-token-compliance.d.ts +21 -0
- package/dist/rules/templates/js-prop-token-compliance.js +56 -0
- package/dist/rules/templates/js-prop-token-compliance.js.map +1 -0
- package/dist/rules/templates/naming-convention.d.ts +18 -0
- package/dist/rules/templates/naming-convention.js +76 -0
- package/dist/rules/templates/naming-convention.js.map +1 -0
- package/dist/rules/templates/registry.d.ts +5 -0
- package/dist/rules/templates/registry.js +30 -0
- package/dist/rules/templates/registry.js.map +1 -0
- package/dist/rules/templates/storybook-coverage-template.d.ts +15 -0
- package/dist/rules/templates/storybook-coverage-template.js +58 -0
- package/dist/rules/templates/storybook-coverage-template.js.map +1 -0
- package/dist/rules/templates/tailwind-utility-class-compliance.d.ts +15 -0
- package/dist/rules/templates/tailwind-utility-class-compliance.js +70 -0
- package/dist/rules/templates/tailwind-utility-class-compliance.js.map +1 -0
- package/dist/rules/templates/types.d.ts +16 -0
- package/dist/rules/templates/types.js +2 -0
- package/dist/rules/templates/types.js.map +1 -0
- package/dist/rules/tokens-description-coverage.d.ts +15 -0
- package/dist/rules/tokens-description-coverage.js +193 -0
- package/dist/rules/tokens-description-coverage.js.map +1 -0
- package/dist/rules/tokens-dtcg-conformance.d.ts +47 -0
- package/dist/rules/tokens-dtcg-conformance.js +363 -0
- package/dist/rules/tokens-dtcg-conformance.js.map +1 -0
- package/dist/rules/tokens-no-hardcoded-color.d.ts +18 -0
- package/dist/rules/tokens-no-hardcoded-color.js +436 -0
- package/dist/rules/tokens-no-hardcoded-color.js.map +1 -0
- package/dist/rules/tokens-no-hardcoded-spacing.d.ts +8 -0
- package/dist/rules/tokens-no-hardcoded-spacing.js +193 -0
- package/dist/rules/tokens-no-hardcoded-spacing.js.map +1 -0
- package/dist/scorer.d.ts +38 -0
- package/dist/scorer.js +126 -0
- package/dist/scorer.js.map +1 -0
- package/dist/share/clipboard.d.ts +26 -0
- package/dist/share/clipboard.js +76 -0
- package/dist/share/clipboard.js.map +1 -0
- package/dist/suppression/__tests__/inline.test.d.ts +1 -0
- package/dist/suppression/__tests__/inline.test.js +25 -0
- package/dist/suppression/__tests__/inline.test.js.map +1 -0
- package/dist/suppression/__tests__/lyseignore.test.d.ts +1 -0
- package/dist/suppression/__tests__/lyseignore.test.js +32 -0
- package/dist/suppression/__tests__/lyseignore.test.js.map +1 -0
- package/dist/suppression/defaults.d.ts +1 -0
- package/dist/suppression/defaults.js +14 -0
- package/dist/suppression/defaults.js.map +1 -0
- package/dist/suppression/inline.d.ts +7 -0
- package/dist/suppression/inline.js +32 -0
- package/dist/suppression/inline.js.map +1 -0
- package/dist/suppression/lyseignore.d.ts +2 -0
- package/dist/suppression/lyseignore.js +22 -0
- package/dist/suppression/lyseignore.js.map +1 -0
- package/dist/telemetry/consent.d.ts +48 -0
- package/dist/telemetry/consent.js +139 -0
- package/dist/telemetry/consent.js.map +1 -0
- package/dist/telemetry/index.d.ts +2 -0
- package/dist/telemetry/index.js +3 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/local-log.d.ts +64 -0
- package/dist/telemetry/local-log.js +123 -0
- package/dist/telemetry/local-log.js.map +1 -0
- package/dist/tokens/dtcg-model.d.ts +53 -0
- package/dist/tokens/dtcg-model.js +18 -0
- package/dist/tokens/dtcg-model.js.map +1 -0
- package/dist/tokens/normalizer.d.ts +17 -0
- package/dist/tokens/normalizer.js +360 -0
- package/dist/tokens/normalizer.js.map +1 -0
- package/dist/types.d.ts +300 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/util/git.d.ts +6 -0
- package/dist/util/git.js +40 -0
- package/dist/util/git.js.map +1 -0
- package/dist/util/git.test.d.ts +5 -0
- package/dist/util/git.test.js +42 -0
- package/dist/util/git.test.js.map +1 -0
- package/dist/util/gitignore.d.ts +9 -0
- package/dist/util/gitignore.js +39 -0
- package/dist/util/gitignore.js.map +1 -0
- package/dist/util/hash-deps.d.ts +6 -0
- package/dist/util/hash-deps.js +24 -0
- package/dist/util/hash-deps.js.map +1 -0
- package/dist/util/spinner.d.ts +41 -0
- package/dist/util/spinner.js +126 -0
- package/dist/util/spinner.js.map +1 -0
- package/dist/util/with-spinner.d.ts +11 -0
- package/dist/util/with-spinner.js +19 -0
- package/dist/util/with-spinner.js.map +1 -0
- package/dist/walker.d.ts +14 -0
- package/dist/walker.js +91 -0
- package/dist/walker.js.map +1 -0
- package/package.json +83 -0
- package/rules-manifest.json +289 -0
- package/schemas/v1/lyse-config.json +82 -0
- package/schemas/v1/lyse-event.json +68 -0
- package/schemas/v1/lyse-license.json +19 -0
- package/schemas/v1/lyse-llm-payload.json +53 -0
- package/schemas/v1/lyse-llm-response.json +45 -0
- package/schemas/v1/lyse-result.json +98 -0
- package/schemas/v1/lyse-rules.json +42 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { copyToClipboard, formatShareMarkdown } from "../share/clipboard.js";
|
|
2
|
+
import { detectFromGit } from "../detection/from-git.js";
|
|
3
|
+
import { auditDirectory } from "./audit-pipeline.js";
|
|
4
|
+
import { ruleMap } from "../rules/registry.js";
|
|
5
|
+
import { createSpinner } from "../util/spinner.js";
|
|
6
|
+
export async function runShare(cwd, opts = {}) {
|
|
7
|
+
const isTTY = process.stderr.isTTY ?? false;
|
|
8
|
+
const isQuiet = opts.quiet === true || process.env["LYSE_QUIET"] === "1";
|
|
9
|
+
const spinner = createSpinner({ isTTY, enabled: isTTY && !isQuiet });
|
|
10
|
+
spinner.start("Discovering files…");
|
|
11
|
+
let audit;
|
|
12
|
+
try {
|
|
13
|
+
audit = await auditDirectory(cwd, { progress: spinner });
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
const msg = err instanceof Error ? err.message.split("\n")[0] : String(err);
|
|
17
|
+
spinner.fail(`Share failed: ${msg}`);
|
|
18
|
+
throw err;
|
|
19
|
+
}
|
|
20
|
+
spinner.update("Copying summary to clipboard…");
|
|
21
|
+
const git = await detectFromGit(cwd);
|
|
22
|
+
const repo = git.github.value ? `${git.github.value.owner}/${git.github.value.repo}` : null;
|
|
23
|
+
const counts = new Map();
|
|
24
|
+
for (const f of audit.result.findings) {
|
|
25
|
+
const rule = ruleMap.get(f.ruleId);
|
|
26
|
+
const isFixable = !!rule?.applyCodemod;
|
|
27
|
+
const existing = counts.get(f.ruleId) ?? { count: 0, fixable: isFixable };
|
|
28
|
+
existing.count++;
|
|
29
|
+
counts.set(f.ruleId, existing);
|
|
30
|
+
}
|
|
31
|
+
const topRules = Array.from(counts.entries())
|
|
32
|
+
.map(([ruleId, v]) => ({ ruleId, ...v }))
|
|
33
|
+
.sort((a, b) => b.count - a.count);
|
|
34
|
+
const axes = {
|
|
35
|
+
tokens: null,
|
|
36
|
+
a11y: null,
|
|
37
|
+
components: null,
|
|
38
|
+
stories: null,
|
|
39
|
+
};
|
|
40
|
+
for (const axisScore of audit.result.axes) {
|
|
41
|
+
if (axisScore.axis === "tokens" && typeof axisScore.score === "number")
|
|
42
|
+
axes.tokens = axisScore.score;
|
|
43
|
+
else if (axisScore.axis === "a11y" && typeof axisScore.score === "number")
|
|
44
|
+
axes.a11y = axisScore.score;
|
|
45
|
+
else if (axisScore.axis === "components" && typeof axisScore.score === "number")
|
|
46
|
+
axes.components = axisScore.score;
|
|
47
|
+
else if (axisScore.axis === "stories" && typeof axisScore.score === "number")
|
|
48
|
+
axes.stories = axisScore.score;
|
|
49
|
+
}
|
|
50
|
+
const md = formatShareMarkdown(audit.result.finalScore, axes, topRules, repo);
|
|
51
|
+
try {
|
|
52
|
+
await copyToClipboard(md);
|
|
53
|
+
spinner.succeed(`Summary copied · score ${audit.result.finalScore}/100 · paste into Slack / Notion / email`);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
spinner.fail("Clipboard unavailable — printing summary below");
|
|
57
|
+
console.log(md);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=share.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"share.js","sourceRoot":"","sources":["../../src/commands/share.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { readConsent, writeConsent, resetConsentCache } from "../telemetry/consent.js";
|
|
2
|
+
function writeFinal(accepted, deps = {}) {
|
|
3
|
+
writeConsent({
|
|
4
|
+
accepted,
|
|
5
|
+
attempt: 2,
|
|
6
|
+
decided_at: new Date().toISOString(),
|
|
7
|
+
version: "1.0.0",
|
|
8
|
+
}, deps);
|
|
9
|
+
resetConsentCache();
|
|
10
|
+
}
|
|
11
|
+
export function runTelemetryOn(deps = {}) {
|
|
12
|
+
writeFinal(true, deps);
|
|
13
|
+
console.log("Telemetry enabled. Anonymous bench events will be sent on future audits.");
|
|
14
|
+
}
|
|
15
|
+
export function runTelemetryOff(deps = {}) {
|
|
16
|
+
writeFinal(false, deps);
|
|
17
|
+
console.log("Telemetry disabled. No data will be sent.");
|
|
18
|
+
}
|
|
19
|
+
export function runTelemetryStatus(deps = {}) {
|
|
20
|
+
const c = readConsent(deps);
|
|
21
|
+
if (!c) {
|
|
22
|
+
console.log("Telemetry status: not yet decided. You will be asked on your next `lyse audit`.");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
console.log(`Telemetry status: ${c.accepted ? "enabled" : "disabled"} (decided ${c.decided_at}).`);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/commands/telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,iBAAiB,EAAoB,MAAM,yBAAyB,CAAC;AAEzG,SAAS,UAAU,CAAC,QAAiB,EAAE,OAAoB,EAAE;IAC3D,YAAY,CAAC;QACX,QAAQ;QACR,OAAO,EAAE,CAAC;QACV,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACpC,OAAO,EAAE,OAAO;KACjB,EAAE,IAAI,CAAC,CAAC;IACT,iBAAiB,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAoB,EAAE;IACnD,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACvB,OAAO,CAAC,GAAG,CAAC,0EAA0E,CAAC,CAAC;AAC1F,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAoB,EAAE;IACpD,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACxB,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAoB,EAAE;IACvD,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,iFAAiF,CAAC,CAAC;QAC/F,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,aAAa,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC;AACrG,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: Lyse audit
|
|
2
|
+
on:
|
|
3
|
+
pull_request:
|
|
4
|
+
push:
|
|
5
|
+
branches: [{{ default_branch }}]
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
security-events: write
|
|
9
|
+
pull-requests: write
|
|
10
|
+
issues: write
|
|
11
|
+
id-token: write
|
|
12
|
+
jobs:
|
|
13
|
+
audit:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/setup-node@v4
|
|
18
|
+
with:
|
|
19
|
+
node-version: 22
|
|
20
|
+
- uses: lyse-labs/lyse-action@<pinned-sha>
|
|
21
|
+
id: audit
|
|
22
|
+
with:
|
|
23
|
+
fail-on-threshold: {{ threshold }}
|
|
24
|
+
post-pr-comment: {{ post_pr_comment }}
|
|
25
|
+
upload-sarif: {{ upload_sarif }}
|
|
26
|
+
publish-bench: {{ publish_bench }}
|
|
27
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
28
|
+
if: always() && {{ upload_sarif }}
|
|
29
|
+
with:
|
|
30
|
+
sarif_file: lyse-report/lyse.sarif
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schema for .lyse.yaml — addresses T2 security gap:
|
|
3
|
+
* both loadConfig sites previously cast YAML via `as` without validation.
|
|
4
|
+
*
|
|
5
|
+
* Structurally compatible with LyseConfig in ../types.ts.
|
|
6
|
+
* The schema intentionally does NOT use .strict() so future fields in
|
|
7
|
+
* .lyse.yaml don't cause hard failures — unknown keys are stripped silently.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
import type { LyseConfig } from "../types.js";
|
|
11
|
+
export type { LyseConfig } from "../types.js";
|
|
12
|
+
export declare const LyseConfigSchema: z.ZodObject<{
|
|
13
|
+
designSystem: z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
14
|
+
componentsModule: z.ZodOptional<z.ZodString>;
|
|
15
|
+
elements: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
16
|
+
excludePaths: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
17
|
+
}, "strip", z.ZodTypeAny, {
|
|
18
|
+
componentsModule?: string | undefined;
|
|
19
|
+
elements?: Record<string, string> | undefined;
|
|
20
|
+
excludePaths?: string[] | undefined;
|
|
21
|
+
}, {
|
|
22
|
+
componentsModule?: string | undefined;
|
|
23
|
+
elements?: Record<string, string> | undefined;
|
|
24
|
+
excludePaths?: string[] | undefined;
|
|
25
|
+
}>>>, {
|
|
26
|
+
componentsModule?: string | undefined;
|
|
27
|
+
elements?: Record<string, string> | undefined;
|
|
28
|
+
excludePaths?: string[] | undefined;
|
|
29
|
+
} | undefined, {
|
|
30
|
+
componentsModule?: string | undefined;
|
|
31
|
+
elements?: Record<string, string> | undefined;
|
|
32
|
+
excludePaths?: string[] | undefined;
|
|
33
|
+
} | null | undefined>;
|
|
34
|
+
rules: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodLiteral<"off">, z.ZodObject<{
|
|
35
|
+
severity: z.ZodOptional<z.ZodEnum<["error", "warning", "info", "off"]>>;
|
|
36
|
+
tolerance: z.ZodOptional<z.ZodNumber>;
|
|
37
|
+
disable: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
38
|
+
}, "strip", z.ZodTypeAny, {
|
|
39
|
+
severity?: "error" | "warning" | "info" | "off" | undefined;
|
|
40
|
+
tolerance?: number | undefined;
|
|
41
|
+
disable?: string[] | undefined;
|
|
42
|
+
}, {
|
|
43
|
+
severity?: "error" | "warning" | "info" | "off" | undefined;
|
|
44
|
+
tolerance?: number | undefined;
|
|
45
|
+
disable?: string[] | undefined;
|
|
46
|
+
}>]>>>;
|
|
47
|
+
llm: z.ZodOptional<z.ZodObject<{
|
|
48
|
+
provider: z.ZodOptional<z.ZodEnum<["anthropic", "openai", "openai-compatible", "mcp", "none", "auto"]>>;
|
|
49
|
+
model: z.ZodOptional<z.ZodString>;
|
|
50
|
+
endpoint: z.ZodOptional<z.ZodString>;
|
|
51
|
+
connector: z.ZodOptional<z.ZodEnum<["auto", "mcp-host", "openrouter", "direct-api-key", "ollama"]>>;
|
|
52
|
+
costCapUsd: z.ZodOptional<z.ZodNumber>;
|
|
53
|
+
cacheMaxAgeDays: z.ZodOptional<z.ZodNumber>;
|
|
54
|
+
staticOnly: z.ZodOptional<z.ZodBoolean>;
|
|
55
|
+
}, "strip", z.ZodTypeAny, {
|
|
56
|
+
staticOnly?: boolean | undefined;
|
|
57
|
+
provider?: "anthropic" | "openai" | "openai-compatible" | "mcp" | "none" | "auto" | undefined;
|
|
58
|
+
model?: string | undefined;
|
|
59
|
+
endpoint?: string | undefined;
|
|
60
|
+
connector?: "auto" | "mcp-host" | "openrouter" | "direct-api-key" | "ollama" | undefined;
|
|
61
|
+
costCapUsd?: number | undefined;
|
|
62
|
+
cacheMaxAgeDays?: number | undefined;
|
|
63
|
+
}, {
|
|
64
|
+
staticOnly?: boolean | undefined;
|
|
65
|
+
provider?: "anthropic" | "openai" | "openai-compatible" | "mcp" | "none" | "auto" | undefined;
|
|
66
|
+
model?: string | undefined;
|
|
67
|
+
endpoint?: string | undefined;
|
|
68
|
+
connector?: "auto" | "mcp-host" | "openrouter" | "direct-api-key" | "ollama" | undefined;
|
|
69
|
+
costCapUsd?: number | undefined;
|
|
70
|
+
cacheMaxAgeDays?: number | undefined;
|
|
71
|
+
}>>;
|
|
72
|
+
}, "strip", z.ZodTypeAny, {
|
|
73
|
+
rules?: Record<string, "off" | {
|
|
74
|
+
severity?: "error" | "warning" | "info" | "off" | undefined;
|
|
75
|
+
tolerance?: number | undefined;
|
|
76
|
+
disable?: string[] | undefined;
|
|
77
|
+
}> | undefined;
|
|
78
|
+
designSystem?: {
|
|
79
|
+
componentsModule?: string | undefined;
|
|
80
|
+
elements?: Record<string, string> | undefined;
|
|
81
|
+
excludePaths?: string[] | undefined;
|
|
82
|
+
} | undefined;
|
|
83
|
+
llm?: {
|
|
84
|
+
staticOnly?: boolean | undefined;
|
|
85
|
+
provider?: "anthropic" | "openai" | "openai-compatible" | "mcp" | "none" | "auto" | undefined;
|
|
86
|
+
model?: string | undefined;
|
|
87
|
+
endpoint?: string | undefined;
|
|
88
|
+
connector?: "auto" | "mcp-host" | "openrouter" | "direct-api-key" | "ollama" | undefined;
|
|
89
|
+
costCapUsd?: number | undefined;
|
|
90
|
+
cacheMaxAgeDays?: number | undefined;
|
|
91
|
+
} | undefined;
|
|
92
|
+
}, {
|
|
93
|
+
rules?: Record<string, "off" | {
|
|
94
|
+
severity?: "error" | "warning" | "info" | "off" | undefined;
|
|
95
|
+
tolerance?: number | undefined;
|
|
96
|
+
disable?: string[] | undefined;
|
|
97
|
+
}> | undefined;
|
|
98
|
+
designSystem?: {
|
|
99
|
+
componentsModule?: string | undefined;
|
|
100
|
+
elements?: Record<string, string> | undefined;
|
|
101
|
+
excludePaths?: string[] | undefined;
|
|
102
|
+
} | null | undefined;
|
|
103
|
+
llm?: {
|
|
104
|
+
staticOnly?: boolean | undefined;
|
|
105
|
+
provider?: "anthropic" | "openai" | "openai-compatible" | "mcp" | "none" | "auto" | undefined;
|
|
106
|
+
model?: string | undefined;
|
|
107
|
+
endpoint?: string | undefined;
|
|
108
|
+
connector?: "auto" | "mcp-host" | "openrouter" | "direct-api-key" | "ollama" | undefined;
|
|
109
|
+
costCapUsd?: number | undefined;
|
|
110
|
+
cacheMaxAgeDays?: number | undefined;
|
|
111
|
+
} | undefined;
|
|
112
|
+
}>;
|
|
113
|
+
export type LyseConfigValidated = z.infer<typeof LyseConfigSchema>;
|
|
114
|
+
/**
|
|
115
|
+
* Parse and validate raw YAML output as a LyseConfig.
|
|
116
|
+
* Throws a ZodError with human-readable messages on invalid input.
|
|
117
|
+
*/
|
|
118
|
+
export declare function parseLyseConfig(raw: unknown): LyseConfigValidated;
|
|
119
|
+
/**
|
|
120
|
+
* Validate raw YAML output as a LyseConfig without throwing.
|
|
121
|
+
* Returns { ok: true, value } on success or { ok: false, error } with a
|
|
122
|
+
* semicolon-separated list of validation issues on failure.
|
|
123
|
+
*/
|
|
124
|
+
export declare function safeParseLyseConfig(raw: unknown): {
|
|
125
|
+
ok: true;
|
|
126
|
+
value: LyseConfigValidated;
|
|
127
|
+
} | {
|
|
128
|
+
ok: false;
|
|
129
|
+
error: string;
|
|
130
|
+
};
|
|
131
|
+
export interface LoadConfigOptions {
|
|
132
|
+
/**
|
|
133
|
+
* Error handling strategy:
|
|
134
|
+
* - "throw" (default): throw on invalid YAML or Zod validation failure.
|
|
135
|
+
* - "degrade": log to stderr and return empty config on any error.
|
|
136
|
+
*/
|
|
137
|
+
onError?: "throw" | "degrade";
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Load and validate .lyse.yaml for a given repository root.
|
|
141
|
+
*
|
|
142
|
+
* Respects the LYSE_CONFIG_PATH env var (set by --config flag) to override
|
|
143
|
+
* the default `.lyse.yaml` discovery path.
|
|
144
|
+
*
|
|
145
|
+
* @param repoRoot - Absolute path to the repository root.
|
|
146
|
+
* @param opts - Options. Default: { onError: "throw" }.
|
|
147
|
+
*/
|
|
148
|
+
export declare function loadConfig(repoRoot: string, opts?: LoadConfigOptions): LyseConfig;
|
|
149
|
+
/**
|
|
150
|
+
* Resolve where the .lyse.yaml WOULD be loaded from for this repo root, if at all.
|
|
151
|
+
* Returns the absolute path when a config file is discoverable, or `null` when
|
|
152
|
+
* no config file is present. Does NOT parse or validate the contents.
|
|
153
|
+
*
|
|
154
|
+
* Mirrors the discovery logic of `loadConfig` (LYSE_CONFIG_PATH > .lyse.yaml at root)
|
|
155
|
+
* so the value reported in `AuditResult.meta.coverage.configPath` matches the file
|
|
156
|
+
* `loadConfig` would actually read.
|
|
157
|
+
*/
|
|
158
|
+
export declare function resolveConfigPath(repoRoot: string): string | null;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schema for .lyse.yaml — addresses T2 security gap:
|
|
3
|
+
* both loadConfig sites previously cast YAML via `as` without validation.
|
|
4
|
+
*
|
|
5
|
+
* Structurally compatible with LyseConfig in ../types.ts.
|
|
6
|
+
* The schema intentionally does NOT use .strict() so future fields in
|
|
7
|
+
* .lyse.yaml don't cause hard failures — unknown keys are stripped silently.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { parse as parseYaml } from "yaml";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
export const LyseConfigSchema = z.object({
|
|
14
|
+
designSystem: z
|
|
15
|
+
.object({
|
|
16
|
+
componentsModule: z.string().optional(),
|
|
17
|
+
elements: z.record(z.string(), z.string()).optional(),
|
|
18
|
+
excludePaths: z.array(z.string()).optional(),
|
|
19
|
+
})
|
|
20
|
+
// YAML `designSystem:` with no value parses as null — treat as "not set".
|
|
21
|
+
.nullish()
|
|
22
|
+
.transform((v) => v ?? undefined),
|
|
23
|
+
rules: z
|
|
24
|
+
.record(z.string(), z.union([
|
|
25
|
+
z.literal("off"),
|
|
26
|
+
z.object({
|
|
27
|
+
severity: z.enum(["error", "warning", "info", "off"]).optional(),
|
|
28
|
+
tolerance: z.number().optional(),
|
|
29
|
+
disable: z.array(z.string()).optional(),
|
|
30
|
+
}),
|
|
31
|
+
]))
|
|
32
|
+
.optional(),
|
|
33
|
+
llm: z
|
|
34
|
+
.object({
|
|
35
|
+
provider: z
|
|
36
|
+
.enum(["anthropic", "openai", "openai-compatible", "mcp", "none", "auto"])
|
|
37
|
+
.optional(),
|
|
38
|
+
model: z.string().optional(),
|
|
39
|
+
endpoint: z.string().optional(),
|
|
40
|
+
// ADR-0015: ConnectorResolver fields (Task 2)
|
|
41
|
+
connector: z
|
|
42
|
+
.enum(["auto", "mcp-host", "openrouter", "direct-api-key", "ollama"])
|
|
43
|
+
.optional(),
|
|
44
|
+
costCapUsd: z.number().positive().optional(),
|
|
45
|
+
cacheMaxAgeDays: z.number().positive().optional(),
|
|
46
|
+
staticOnly: z.boolean().optional(),
|
|
47
|
+
})
|
|
48
|
+
.optional(),
|
|
49
|
+
});
|
|
50
|
+
/**
|
|
51
|
+
* Parse and validate raw YAML output as a LyseConfig.
|
|
52
|
+
* Throws a ZodError with human-readable messages on invalid input.
|
|
53
|
+
*/
|
|
54
|
+
export function parseLyseConfig(raw) {
|
|
55
|
+
return LyseConfigSchema.parse(raw);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Validate raw YAML output as a LyseConfig without throwing.
|
|
59
|
+
* Returns { ok: true, value } on success or { ok: false, error } with a
|
|
60
|
+
* semicolon-separated list of validation issues on failure.
|
|
61
|
+
*/
|
|
62
|
+
export function safeParseLyseConfig(raw) {
|
|
63
|
+
const result = LyseConfigSchema.safeParse(raw);
|
|
64
|
+
if (result.success)
|
|
65
|
+
return { ok: true, value: result.data };
|
|
66
|
+
return {
|
|
67
|
+
ok: false,
|
|
68
|
+
error: result.error.issues
|
|
69
|
+
.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`)
|
|
70
|
+
.join("; "),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Load and validate .lyse.yaml for a given repository root.
|
|
75
|
+
*
|
|
76
|
+
* Respects the LYSE_CONFIG_PATH env var (set by --config flag) to override
|
|
77
|
+
* the default `.lyse.yaml` discovery path.
|
|
78
|
+
*
|
|
79
|
+
* @param repoRoot - Absolute path to the repository root.
|
|
80
|
+
* @param opts - Options. Default: { onError: "throw" }.
|
|
81
|
+
*/
|
|
82
|
+
export function loadConfig(repoRoot, opts) {
|
|
83
|
+
const onError = opts?.onError ?? "throw";
|
|
84
|
+
// LYSE_CONFIG_PATH (set by --config flag) overrides .lyse.yaml discovery.
|
|
85
|
+
const configPath = process.env.LYSE_CONFIG_PATH ?? join(repoRoot, ".lyse.yaml");
|
|
86
|
+
try {
|
|
87
|
+
const raw = parseYaml(readFileSync(configPath, "utf8"));
|
|
88
|
+
const parsed = safeParseLyseConfig(raw);
|
|
89
|
+
if (!parsed.ok) {
|
|
90
|
+
const msg = `[lyse] Warning: Invalid .lyse.yaml: ${parsed.error}\n`;
|
|
91
|
+
if (onError === "degrade") {
|
|
92
|
+
process.stderr.write(msg);
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
// Hard-fail: invalid .lyse.yaml should never produce a misleading audit.
|
|
96
|
+
throw new Error(`Invalid .lyse.yaml: ${parsed.error}`);
|
|
97
|
+
}
|
|
98
|
+
const value = parsed.value;
|
|
99
|
+
// Migration: llm.provider: 'none' was removed in v0.1.
|
|
100
|
+
// Treat it as llm.staticOnly: true and warn the user.
|
|
101
|
+
if (value.llm?.provider === "none") {
|
|
102
|
+
process.stderr.write("[Lyse] DEPRECATION: llm.provider: 'none' is removed in v0.1. " +
|
|
103
|
+
"Treating as llm.staticOnly: true. Please update .lyse.yaml.\n");
|
|
104
|
+
const llmFixed = { ...value.llm, staticOnly: true };
|
|
105
|
+
delete llmFixed.provider;
|
|
106
|
+
value.llm = llmFixed;
|
|
107
|
+
}
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
// Re-throw validation errors in throw mode
|
|
112
|
+
if (err instanceof Error && err.message.startsWith("Invalid .lyse.yaml")) {
|
|
113
|
+
if (onError === "degrade") {
|
|
114
|
+
process.stderr.write(`[lyse] Warning: ${err.message}\n`);
|
|
115
|
+
return {};
|
|
116
|
+
}
|
|
117
|
+
throw err;
|
|
118
|
+
}
|
|
119
|
+
// File missing / unreadable → safe default (no config) in both modes.
|
|
120
|
+
return {};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Resolve where the .lyse.yaml WOULD be loaded from for this repo root, if at all.
|
|
125
|
+
* Returns the absolute path when a config file is discoverable, or `null` when
|
|
126
|
+
* no config file is present. Does NOT parse or validate the contents.
|
|
127
|
+
*
|
|
128
|
+
* Mirrors the discovery logic of `loadConfig` (LYSE_CONFIG_PATH > .lyse.yaml at root)
|
|
129
|
+
* so the value reported in `AuditResult.meta.coverage.configPath` matches the file
|
|
130
|
+
* `loadConfig` would actually read.
|
|
131
|
+
*/
|
|
132
|
+
export function resolveConfigPath(repoRoot) {
|
|
133
|
+
const candidate = process.env.LYSE_CONFIG_PATH ?? join(repoRoot, ".lyse.yaml");
|
|
134
|
+
return existsSync(candidate) ? candidate : null;
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,YAAY,EAAE,CAAC;SACZ,MAAM,CAAC;QACN,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QACvC,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;QACrD,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;KAC7C,CAAC;QACF,0EAA0E;SACzE,OAAO,EAAE;SACT,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,SAAS,CAAC;IACnC,KAAK,EAAE,CAAC;SACL,MAAM,CACL,CAAC,CAAC,MAAM,EAAE,EACV,CAAC,CAAC,KAAK,CAAC;QACN,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;QAChB,CAAC,CAAC,MAAM,CAAC;YACP,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE;YAChE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YAChC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;SACxC,CAAC;KACH,CAAC,CACH;SACA,QAAQ,EAAE;IACb,GAAG,EAAE,CAAC;SACH,MAAM,CAAC;QACN,QAAQ,EAAE,CAAC;aACR,IAAI,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;aACzE,QAAQ,EAAE;QACb,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC5B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC/B,8CAA8C;QAC9C,SAAS,EAAE,CAAC;aACT,IAAI,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC;aACpE,QAAQ,EAAE;QACb,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;QAC5C,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;QACjD,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;KACnC,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC;AAIH;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,GAAY;IAC1C,OAAO,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAAY;IAEZ,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC/C,IAAI,MAAM,CAAC,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;IAC5D,OAAO;QACL,EAAE,EAAE,KAAK;QACT,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM;aACvB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;aAC3D,IAAI,CAAC,IAAI,CAAC;KACd,CAAC;AACJ,CAAC;AAWD;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,IAAwB;IACnE,MAAM,OAAO,GAAG,IAAI,EAAE,OAAO,IAAI,OAAO,CAAC;IACzC,0EAA0E;IAC1E,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAChF,IAAI,CAAC;QACH,MAAM,GAAG,GAAY,SAAS,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC;QACjE,MAAM,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,GAAG,GAAG,uCAAuC,MAAM,CAAC,KAAK,IAAI,CAAC;YACpE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC1B,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,yEAAyE;YACzE,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QACzD,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAmB,CAAC;QACzC,uDAAuD;QACvD,sDAAsD;QACtD,IAAK,KAAK,CAAC,GAA2C,EAAE,QAAQ,KAAK,MAAM,EAAE,CAAC;YAC5E,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,+DAA+D;gBAC7D,+DAA+D,CAClE,CAAC;YACF,MAAM,QAAQ,GAA4B,EAAE,GAAI,KAAK,CAAC,GAA+B,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;YAC1G,OAAO,QAAQ,CAAC,QAAQ,CAAC;YACxB,KAAiC,CAAC,GAAG,GAAG,QAAQ,CAAC;QACpD,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,2CAA2C;QAC3C,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAAE,CAAC;YACzE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,mBAAmB,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;gBACzD,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;QACD,sEAAsE;QACtE,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAC/E,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { CredentialStore } from "./store.js";
|
|
2
|
+
export interface KeytarLike {
|
|
3
|
+
getPassword(service: string, account: string): Promise<string | null>;
|
|
4
|
+
setPassword(service: string, account: string, password: string): Promise<void>;
|
|
5
|
+
deletePassword(service: string, account: string): Promise<boolean>;
|
|
6
|
+
findCredentials(service: string): Promise<Array<{
|
|
7
|
+
account: string;
|
|
8
|
+
password: string;
|
|
9
|
+
}>>;
|
|
10
|
+
}
|
|
11
|
+
export declare class KeychainCredentialStore implements CredentialStore {
|
|
12
|
+
private service;
|
|
13
|
+
private keytar;
|
|
14
|
+
constructor(service: string, keytar: KeytarLike);
|
|
15
|
+
static create(service: string): Promise<KeychainCredentialStore | null>;
|
|
16
|
+
get(key: string): Promise<string | null>;
|
|
17
|
+
set(key: string, value: string): Promise<void>;
|
|
18
|
+
delete(key: string): Promise<void>;
|
|
19
|
+
listKeys(): Promise<string[]>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export class KeychainCredentialStore {
|
|
2
|
+
service;
|
|
3
|
+
keytar;
|
|
4
|
+
constructor(service, keytar) {
|
|
5
|
+
this.service = service;
|
|
6
|
+
this.keytar = keytar;
|
|
7
|
+
}
|
|
8
|
+
static async create(service) {
|
|
9
|
+
try {
|
|
10
|
+
const keytar = (await import("keytar"));
|
|
11
|
+
// Smoke test: try a no-op call to verify the native module loaded properly.
|
|
12
|
+
await keytar.findCredentials(service);
|
|
13
|
+
return new KeychainCredentialStore(service, keytar);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// keytar not installed, or native module failed to load (common on Linux without libsecret).
|
|
17
|
+
// Caller falls back to PlainFileCredentialStore.
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async get(key) {
|
|
22
|
+
return this.keytar.getPassword(this.service, key);
|
|
23
|
+
}
|
|
24
|
+
async set(key, value) {
|
|
25
|
+
await this.keytar.setPassword(this.service, key, value);
|
|
26
|
+
}
|
|
27
|
+
async delete(key) {
|
|
28
|
+
await this.keytar.deletePassword(this.service, key);
|
|
29
|
+
}
|
|
30
|
+
async listKeys() {
|
|
31
|
+
const creds = await this.keytar.findCredentials(this.service);
|
|
32
|
+
return creds.map((c) => c.account);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=keychain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain.js","sourceRoot":"","sources":["../../src/credentials/keychain.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,uBAAuB;IACd;IAAyB;IAA7C,YAAoB,OAAe,EAAU,MAAkB;QAA3C,YAAO,GAAP,OAAO,CAAQ;QAAU,WAAM,GAAN,MAAM,CAAY;IAAG,CAAC;IAEnE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAe;QACjC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,CAA0B,CAAC;YACjE,4EAA4E;YAC5E,MAAM,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACtC,OAAO,IAAI,uBAAuB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,6FAA6F;YAC7F,iDAAiD;YACjD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAa;QAClC,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,MAAM,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9D,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { KeychainCredentialStore } from "./keychain.js";
|
|
3
|
+
describe("KeychainCredentialStore", () => {
|
|
4
|
+
it("set + get delegates to keytar", async () => {
|
|
5
|
+
const fakeKeytar = {
|
|
6
|
+
getPassword: vi.fn().mockResolvedValueOnce("sk-ant"),
|
|
7
|
+
setPassword: vi.fn().mockResolvedValue(undefined),
|
|
8
|
+
deletePassword: vi.fn().mockResolvedValue(true),
|
|
9
|
+
findCredentials: vi.fn().mockResolvedValue([]),
|
|
10
|
+
};
|
|
11
|
+
const s = new KeychainCredentialStore("com.lyse-labs.lyse", fakeKeytar);
|
|
12
|
+
await s.set("anthropic_api_key", "sk-ant");
|
|
13
|
+
expect(fakeKeytar.setPassword).toHaveBeenCalledWith("com.lyse-labs.lyse", "anthropic_api_key", "sk-ant");
|
|
14
|
+
const v = await s.get("anthropic_api_key");
|
|
15
|
+
expect(v).toBe("sk-ant");
|
|
16
|
+
});
|
|
17
|
+
it("listKeys returns account names from findCredentials", async () => {
|
|
18
|
+
const fakeKeytar = {
|
|
19
|
+
getPassword: vi.fn(),
|
|
20
|
+
setPassword: vi.fn(),
|
|
21
|
+
deletePassword: vi.fn(),
|
|
22
|
+
findCredentials: vi.fn().mockResolvedValue([
|
|
23
|
+
{ account: "anthropic_api_key", password: "..." },
|
|
24
|
+
{ account: "openai_api_key", password: "..." },
|
|
25
|
+
]),
|
|
26
|
+
};
|
|
27
|
+
const s = new KeychainCredentialStore("com.lyse-labs.lyse", fakeKeytar);
|
|
28
|
+
const keys = await s.listKeys();
|
|
29
|
+
expect(keys.sort()).toEqual(["anthropic_api_key", "openai_api_key"]);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
//# sourceMappingURL=keychain.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain.test.js","sourceRoot":"","sources":["../../src/credentials/keychain.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAmB,MAAM,eAAe,CAAC;AAEzE,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,UAAU,GAAe;YAC7B,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,qBAAqB,CAAC,QAAQ,CAAC;YACpD,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS,CAAC;YACjD,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC;YAC/C,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC;SAC/C,CAAC;QACF,MAAM,CAAC,GAAG,IAAI,uBAAuB,CAAC,oBAAoB,EAAE,UAAU,CAAC,CAAC;QACxE,MAAM,CAAC,CAAC,GAAG,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAC;QAC3C,MAAM,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,oBAAoB,CACjD,oBAAoB,EACpB,mBAAmB,EACnB,QAAQ,CACT,CAAC;QACF,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QAC3C,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,UAAU,GAAe;YAC7B,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE;YACpB,WAAW,EAAE,EAAE,CAAC,EAAE,EAAE;YACpB,cAAc,EAAE,EAAE,CAAC,EAAE,EAAE;YACvB,eAAe,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;gBACzC,EAAE,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,KAAK,EAAE;gBACjD,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,KAAK,EAAE;aAC/C,CAAC;SACH,CAAC;QACF,MAAM,CAAC,GAAG,IAAI,uBAAuB,CAAC,oBAAoB,EAAE,UAAU,CAAC,CAAC;QACxE,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function defaultCredentialsPath(): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/credentials/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,UAAU,sBAAsB;IACpC,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface CredentialStore {
|
|
2
|
+
get(key: string): Promise<string | null>;
|
|
3
|
+
set(key: string, value: string): Promise<void>;
|
|
4
|
+
delete(key: string): Promise<void>;
|
|
5
|
+
listKeys(): Promise<string[]>;
|
|
6
|
+
}
|
|
7
|
+
export declare class PlainFileCredentialStore implements CredentialStore {
|
|
8
|
+
private path;
|
|
9
|
+
constructor(path: string);
|
|
10
|
+
get(key: string): Promise<string | null>;
|
|
11
|
+
set(key: string, value: string): Promise<void>;
|
|
12
|
+
delete(key: string): Promise<void>;
|
|
13
|
+
listKeys(): Promise<string[]>;
|
|
14
|
+
private read;
|
|
15
|
+
private write;
|
|
16
|
+
}
|
|
17
|
+
export declare function createCredentialStore(): Promise<CredentialStore>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { promises as fs } from "node:fs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { defaultCredentialsPath } from "./paths.js";
|
|
4
|
+
import { KeychainCredentialStore } from "./keychain.js";
|
|
5
|
+
export class PlainFileCredentialStore {
|
|
6
|
+
path;
|
|
7
|
+
constructor(path) {
|
|
8
|
+
this.path = path;
|
|
9
|
+
}
|
|
10
|
+
async get(key) {
|
|
11
|
+
const map = await this.read();
|
|
12
|
+
return map[key] ?? null;
|
|
13
|
+
}
|
|
14
|
+
async set(key, value) {
|
|
15
|
+
const map = await this.read();
|
|
16
|
+
map[key] = value;
|
|
17
|
+
await this.write(map);
|
|
18
|
+
}
|
|
19
|
+
async delete(key) {
|
|
20
|
+
const map = await this.read();
|
|
21
|
+
delete map[key];
|
|
22
|
+
await this.write(map);
|
|
23
|
+
}
|
|
24
|
+
async listKeys() {
|
|
25
|
+
const map = await this.read();
|
|
26
|
+
return Object.keys(map);
|
|
27
|
+
}
|
|
28
|
+
async read() {
|
|
29
|
+
try {
|
|
30
|
+
const raw = await fs.readFile(this.path, "utf8");
|
|
31
|
+
return JSON.parse(raw);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
if (err.code === "ENOENT")
|
|
35
|
+
return {};
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async write(map) {
|
|
40
|
+
if (Object.keys(map).length === 0) {
|
|
41
|
+
// Remove the file entirely when no keys remain — disconnect should leave no trace.
|
|
42
|
+
try {
|
|
43
|
+
await fs.unlink(this.path);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
if (err.code !== "ENOENT")
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
await fs.mkdir(dirname(this.path), { recursive: true, mode: 0o700 });
|
|
52
|
+
await fs.writeFile(this.path, JSON.stringify(map, null, 2), { mode: 0o600 });
|
|
53
|
+
await fs.chmod(this.path, 0o600);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export async function createCredentialStore() {
|
|
57
|
+
const keychain = await KeychainCredentialStore.create("com.lyse-labs.lyse");
|
|
58
|
+
return keychain ?? new PlainFileCredentialStore(defaultCredentialsPath());
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/credentials/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|