oc-pilot 0.5.1 → 0.88.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +683 -0
- package/CONTRIBUTING.md +4 -2
- package/README.md +588 -20
- package/README.ru.md +572 -10
- package/dist/cli.js +185 -1
- package/dist/cli.js.map +1 -1
- package/dist/cli.test.js +1211 -1
- package/dist/cli.test.js.map +1 -1
- package/dist/commands/anti-regression.js +97 -0
- package/dist/commands/anti-regression.js.map +1 -0
- package/dist/commands/arch-diff.js +80 -0
- package/dist/commands/arch-diff.js.map +1 -0
- package/dist/commands/authz.js +167 -0
- package/dist/commands/authz.js.map +1 -0
- package/dist/commands/autopsy.js +64 -0
- package/dist/commands/autopsy.js.map +1 -0
- package/dist/commands/bankruptcy.js +60 -0
- package/dist/commands/bankruptcy.js.map +1 -0
- package/dist/commands/battle.js +119 -0
- package/dist/commands/battle.js.map +1 -0
- package/dist/commands/boundaries.js +114 -0
- package/dist/commands/boundaries.js.map +1 -0
- package/dist/commands/bounty.js +56 -0
- package/dist/commands/bounty.js.map +1 -0
- package/dist/commands/brag.js +62 -0
- package/dist/commands/brag.js.map +1 -0
- package/dist/commands/cache.js +62 -0
- package/dist/commands/cache.js.map +1 -0
- package/dist/commands/cinema.js +61 -0
- package/dist/commands/cinema.js.map +1 -0
- package/dist/commands/cleanup.js +110 -0
- package/dist/commands/cleanup.js.map +1 -0
- package/dist/commands/commit.js +177 -0
- package/dist/commands/commit.js.map +1 -0
- package/dist/commands/commit.test.js +160 -0
- package/dist/commands/commit.test.js.map +1 -0
- package/dist/commands/compliance.js +121 -0
- package/dist/commands/compliance.js.map +1 -0
- package/dist/commands/contract-drift.js +97 -0
- package/dist/commands/contract-drift.js.map +1 -0
- package/dist/commands/coverage.js +137 -0
- package/dist/commands/coverage.js.map +1 -0
- package/dist/commands/day.js +116 -0
- package/dist/commands/day.js.map +1 -0
- package/dist/commands/day.test.js +45 -0
- package/dist/commands/day.test.js.map +1 -0
- package/dist/commands/deps.js +245 -0
- package/dist/commands/deps.js.map +1 -0
- package/dist/commands/docgen.js +4 -2
- package/dist/commands/docgen.js.map +1 -1
- package/dist/commands/doctor.js +146 -2
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/doctor.test.js +69 -0
- package/dist/commands/doctor.test.js.map +1 -0
- package/dist/commands/echo.js +78 -0
- package/dist/commands/echo.js.map +1 -0
- package/dist/commands/ecosystem-verify.js +113 -0
- package/dist/commands/ecosystem-verify.js.map +1 -0
- package/dist/commands/env-sync.js +102 -0
- package/dist/commands/env-sync.js.map +1 -0
- package/dist/commands/explain.js +115 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/fix.js +145 -3
- package/dist/commands/fix.js.map +1 -1
- package/dist/commands/flaky.js +111 -0
- package/dist/commands/flaky.js.map +1 -0
- package/dist/commands/fuzz.js +119 -0
- package/dist/commands/fuzz.js.map +1 -0
- package/dist/commands/hivemind.js +124 -0
- package/dist/commands/hivemind.js.map +1 -0
- package/dist/commands/impact.js +73 -0
- package/dist/commands/impact.js.map +1 -0
- package/dist/commands/init.js +73 -11
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/init.test.js +138 -0
- package/dist/commands/init.test.js.map +1 -0
- package/dist/commands/install-hook.js +161 -0
- package/dist/commands/install-hook.js.map +1 -0
- package/dist/commands/install-hook.test.js +100 -0
- package/dist/commands/install-hook.test.js.map +1 -0
- package/dist/commands/invariants.js +103 -0
- package/dist/commands/invariants.js.map +1 -0
- package/dist/commands/mock-leak.js +97 -0
- package/dist/commands/mock-leak.js.map +1 -0
- package/dist/commands/mutate.js +99 -0
- package/dist/commands/mutate.js.map +1 -0
- package/dist/commands/pack.js +144 -0
- package/dist/commands/pack.js.map +1 -0
- package/dist/commands/preflight.js +137 -0
- package/dist/commands/preflight.js.map +1 -0
- package/dist/commands/query.js +57 -0
- package/dist/commands/query.js.map +1 -0
- package/dist/commands/ready.js +152 -0
- package/dist/commands/ready.js.map +1 -0
- package/dist/commands/receipt.js +289 -0
- package/dist/commands/receipt.js.map +1 -0
- package/dist/commands/replay.js +112 -0
- package/dist/commands/replay.js.map +1 -0
- package/dist/commands/replay.test.js +125 -0
- package/dist/commands/replay.test.js.map +1 -0
- package/dist/commands/restore.js +54 -0
- package/dist/commands/restore.js.map +1 -0
- package/dist/commands/review.js +263 -4
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/review.test.js +160 -0
- package/dist/commands/review.test.js.map +1 -0
- package/dist/commands/reviewers.js +86 -0
- package/dist/commands/reviewers.js.map +1 -0
- package/dist/commands/roast.js +102 -0
- package/dist/commands/roast.js.map +1 -0
- package/dist/commands/sandbox.js +82 -0
- package/dist/commands/sandbox.js.map +1 -0
- package/dist/commands/sast.js +162 -0
- package/dist/commands/sast.js.map +1 -0
- package/dist/commands/scan.js +47 -12
- package/dist/commands/scan.js.map +1 -1
- package/dist/commands/slop.js +145 -0
- package/dist/commands/slop.js.map +1 -0
- package/dist/commands/slop.test.js +135 -0
- package/dist/commands/slop.test.js.map +1 -0
- package/dist/commands/stats.js +61 -0
- package/dist/commands/stats.js.map +1 -0
- package/dist/commands/test-gen.js +372 -0
- package/dist/commands/test-gen.js.map +1 -0
- package/dist/commands/test-guard.js +89 -0
- package/dist/commands/test-guard.js.map +1 -0
- package/dist/commands/test-plan.js +133 -0
- package/dist/commands/test-plan.js.map +1 -0
- package/dist/commands/zoom-symbol.js +52 -0
- package/dist/commands/zoom-symbol.js.map +1 -0
- package/dist/core/agent-rules.js +35 -0
- package/dist/core/agent-rules.js.map +1 -0
- package/dist/core/anthropic.test.js +116 -0
- package/dist/core/anthropic.test.js.map +1 -0
- package/dist/core/anti-regression.js +161 -0
- package/dist/core/anti-regression.js.map +1 -0
- package/dist/core/anti-regression.test.js +154 -0
- package/dist/core/anti-regression.test.js.map +1 -0
- package/dist/core/aql.js +220 -0
- package/dist/core/aql.js.map +1 -0
- package/dist/core/aql.test.js +64 -0
- package/dist/core/aql.test.js.map +1 -0
- package/dist/core/arch-diff.js +122 -0
- package/dist/core/arch-diff.js.map +1 -0
- package/dist/core/arch-diff.test.js +93 -0
- package/dist/core/arch-diff.test.js.map +1 -0
- package/dist/core/authz.js +292 -0
- package/dist/core/authz.js.map +1 -0
- package/dist/core/authz.test.js +115 -0
- package/dist/core/authz.test.js.map +1 -0
- package/dist/core/autopsy.js +230 -0
- package/dist/core/autopsy.js.map +1 -0
- package/dist/core/autopsy.test.js +106 -0
- package/dist/core/autopsy.test.js.map +1 -0
- package/dist/core/bankruptcy.js +232 -0
- package/dist/core/bankruptcy.js.map +1 -0
- package/dist/core/bankruptcy.test.js +91 -0
- package/dist/core/bankruptcy.test.js.map +1 -0
- package/dist/core/baseline.js +131 -0
- package/dist/core/baseline.js.map +1 -0
- package/dist/core/baseline.test.js +91 -0
- package/dist/core/baseline.test.js.map +1 -0
- package/dist/core/battle.js +213 -0
- package/dist/core/battle.js.map +1 -0
- package/dist/core/battle.test.js +116 -0
- package/dist/core/battle.test.js.map +1 -0
- package/dist/core/boundaries.js +200 -0
- package/dist/core/boundaries.js.map +1 -0
- package/dist/core/boundaries.test.js +62 -0
- package/dist/core/boundaries.test.js.map +1 -0
- package/dist/core/bounty.js +128 -0
- package/dist/core/bounty.js.map +1 -0
- package/dist/core/bounty.test.js +82 -0
- package/dist/core/bounty.test.js.map +1 -0
- package/dist/core/brag.js +174 -0
- package/dist/core/brag.js.map +1 -0
- package/dist/core/brag.test.js +43 -0
- package/dist/core/brag.test.js.map +1 -0
- package/dist/core/cache.js +189 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/cache.test.js +159 -0
- package/dist/core/cache.test.js.map +1 -0
- package/dist/core/cinema.js +242 -0
- package/dist/core/cinema.js.map +1 -0
- package/dist/core/cinema.test.js +73 -0
- package/dist/core/cinema.test.js.map +1 -0
- package/dist/core/cleanup.js +107 -0
- package/dist/core/cleanup.js.map +1 -0
- package/dist/core/compliance.js +193 -0
- package/dist/core/compliance.js.map +1 -0
- package/dist/core/compliance.test.js +123 -0
- package/dist/core/compliance.test.js.map +1 -0
- package/dist/core/config.js +78 -0
- package/dist/core/config.js.map +1 -1
- package/dist/core/config.test.js +66 -0
- package/dist/core/config.test.js.map +1 -1
- package/dist/core/contract-drift.js +296 -0
- package/dist/core/contract-drift.js.map +1 -0
- package/dist/core/contract-drift.test.js +166 -0
- package/dist/core/contract-drift.test.js.map +1 -0
- package/dist/core/cost.test.js +103 -0
- package/dist/core/cost.test.js.map +1 -0
- package/dist/core/coverage.js +335 -0
- package/dist/core/coverage.js.map +1 -0
- package/dist/core/coverage.test.js +190 -0
- package/dist/core/coverage.test.js.map +1 -0
- package/dist/core/deps-fix.js +169 -0
- package/dist/core/deps-fix.js.map +1 -0
- package/dist/core/deps-fix.test.js +176 -0
- package/dist/core/deps-fix.test.js.map +1 -0
- package/dist/core/deps-health.js +353 -0
- package/dist/core/deps-health.js.map +1 -0
- package/dist/core/deps-health.test.js +230 -0
- package/dist/core/deps-health.test.js.map +1 -0
- package/dist/core/deps-why.js +260 -0
- package/dist/core/deps-why.js.map +1 -0
- package/dist/core/deps-why.test.js +175 -0
- package/dist/core/deps-why.test.js.map +1 -0
- package/dist/core/deps.js +179 -0
- package/dist/core/deps.js.map +1 -0
- package/dist/core/deps.test.js +88 -0
- package/dist/core/deps.test.js.map +1 -0
- package/dist/core/diff-source.js +4 -2
- package/dist/core/diff-source.js.map +1 -1
- package/dist/core/echo.js +151 -0
- package/dist/core/echo.js.map +1 -0
- package/dist/core/echo.test.js +90 -0
- package/dist/core/echo.test.js.map +1 -0
- package/dist/core/ecosystem-verify.js +331 -0
- package/dist/core/ecosystem-verify.js.map +1 -0
- package/dist/core/ecosystem-verify.test.js +158 -0
- package/dist/core/ecosystem-verify.test.js.map +1 -0
- package/dist/core/engine-preset.test.js +60 -0
- package/dist/core/engine-preset.test.js.map +1 -0
- package/dist/core/engine.js +278 -32
- package/dist/core/engine.js.map +1 -1
- package/dist/core/engine.test.js +63 -0
- package/dist/core/engine.test.js.map +1 -1
- package/dist/core/env-sync.js +122 -0
- package/dist/core/env-sync.js.map +1 -0
- package/dist/core/env-sync.test.js +99 -0
- package/dist/core/env-sync.test.js.map +1 -0
- package/dist/core/file-context.js +4 -2
- package/dist/core/file-context.js.map +1 -1
- package/dist/core/findings-baseline.js +60 -0
- package/dist/core/findings-baseline.js.map +1 -0
- package/dist/core/findings-baseline.test.js +77 -0
- package/dist/core/findings-baseline.test.js.map +1 -0
- package/dist/core/findings.js +68 -21
- package/dist/core/findings.js.map +1 -1
- package/dist/core/flaky.js +137 -0
- package/dist/core/flaky.js.map +1 -0
- package/dist/core/flaky.test.js +97 -0
- package/dist/core/flaky.test.js.map +1 -0
- package/dist/core/format.js +5 -3
- package/dist/core/format.js.map +1 -1
- package/dist/core/fuzz.js +306 -0
- package/dist/core/fuzz.js.map +1 -0
- package/dist/core/fuzz.test.js +121 -0
- package/dist/core/fuzz.test.js.map +1 -0
- package/dist/core/git.js +22 -0
- package/dist/core/git.js.map +1 -1
- package/dist/core/gitlab.js +176 -0
- package/dist/core/gitlab.js.map +1 -0
- package/dist/core/gitlab.test.js +199 -0
- package/dist/core/gitlab.test.js.map +1 -0
- package/dist/core/hivemind.js +250 -0
- package/dist/core/hivemind.js.map +1 -0
- package/dist/core/hivemind.test.js +79 -0
- package/dist/core/hivemind.test.js.map +1 -0
- package/dist/core/hologram.js +463 -0
- package/dist/core/hologram.js.map +1 -0
- package/dist/core/hologram.test.js +124 -0
- package/dist/core/hologram.test.js.map +1 -0
- package/dist/core/impact.js +240 -0
- package/dist/core/impact.js.map +1 -0
- package/dist/core/impact.test.js +105 -0
- package/dist/core/impact.test.js.map +1 -0
- package/dist/core/import-graph.js +170 -0
- package/dist/core/import-graph.js.map +1 -0
- package/dist/core/import-graph.test.js +52 -0
- package/dist/core/import-graph.test.js.map +1 -0
- package/dist/core/injection.js +55 -0
- package/dist/core/injection.js.map +1 -0
- package/dist/core/injection.test.js +45 -0
- package/dist/core/injection.test.js.map +1 -0
- package/dist/core/invariants.js +286 -0
- package/dist/core/invariants.js.map +1 -0
- package/dist/core/invariants.test.js +87 -0
- package/dist/core/invariants.test.js.map +1 -0
- package/dist/core/last-review.js +92 -0
- package/dist/core/last-review.js.map +1 -0
- package/dist/core/last-review.test.js +97 -0
- package/dist/core/last-review.test.js.map +1 -0
- package/dist/core/lockfile-support.test.js +112 -0
- package/dist/core/lockfile-support.test.js.map +1 -0
- package/dist/core/lockfile.js +284 -0
- package/dist/core/lockfile.js.map +1 -0
- package/dist/core/lockfile.test.js +203 -0
- package/dist/core/lockfile.test.js.map +1 -0
- package/dist/core/mock-leak.js +120 -0
- package/dist/core/mock-leak.js.map +1 -0
- package/dist/core/mock-leak.test.js +79 -0
- package/dist/core/mock-leak.test.js.map +1 -0
- package/dist/core/mutation.js +206 -0
- package/dist/core/mutation.js.map +1 -0
- package/dist/core/mutation.test.js +104 -0
- package/dist/core/mutation.test.js.map +1 -0
- package/dist/core/opencode.js +15 -2
- package/dist/core/opencode.js.map +1 -1
- package/dist/core/opencode.test.js +10 -1
- package/dist/core/opencode.test.js.map +1 -1
- package/dist/core/options.js +51 -3
- package/dist/core/options.js.map +1 -1
- package/dist/core/osv.js +202 -0
- package/dist/core/osv.js.map +1 -0
- package/dist/core/osv.test.js +173 -0
- package/dist/core/osv.test.js.map +1 -0
- package/dist/core/output-format.test.js +102 -0
- package/dist/core/output-format.test.js.map +1 -0
- package/dist/core/pack.js +212 -0
- package/dist/core/pack.js.map +1 -0
- package/dist/core/pack.test.js +129 -0
- package/dist/core/pack.test.js.map +1 -0
- package/dist/core/phantom.js +155 -0
- package/dist/core/phantom.js.map +1 -0
- package/dist/core/phantom.test.js +58 -0
- package/dist/core/phantom.test.js.map +1 -0
- package/dist/core/pr-comment.js +116 -0
- package/dist/core/pr-comment.js.map +1 -0
- package/dist/core/pr-comment.test.js +53 -0
- package/dist/core/pr-comment.test.js.map +1 -0
- package/dist/core/pr-review.js +160 -0
- package/dist/core/pr-review.js.map +1 -0
- package/dist/core/pr-review.test.js +62 -0
- package/dist/core/pr-review.test.js.map +1 -0
- package/dist/core/preflight-run.js +106 -0
- package/dist/core/preflight-run.js.map +1 -0
- package/dist/core/preflight.js +173 -0
- package/dist/core/preflight.js.map +1 -0
- package/dist/core/preflight.test.js +187 -0
- package/dist/core/preflight.test.js.map +1 -0
- package/dist/core/presets.js +408 -0
- package/dist/core/presets.js.map +1 -0
- package/dist/core/presets.test.js +79 -0
- package/dist/core/presets.test.js.map +1 -0
- package/dist/core/prompt.golden.test.js +74 -0
- package/dist/core/prompt.golden.test.js.map +1 -0
- package/dist/core/prompt.js +43 -4
- package/dist/core/prompt.js.map +1 -1
- package/dist/core/prompt.test.js +16 -0
- package/dist/core/prompt.test.js.map +1 -1
- package/dist/core/readiness-fix.js +111 -0
- package/dist/core/readiness-fix.js.map +1 -0
- package/dist/core/readiness-fix.test.js +99 -0
- package/dist/core/readiness-fix.test.js.map +1 -0
- package/dist/core/readiness.js +189 -0
- package/dist/core/readiness.js.map +1 -0
- package/dist/core/readiness.test.js +199 -0
- package/dist/core/readiness.test.js.map +1 -0
- package/dist/core/receipt.js +193 -0
- package/dist/core/receipt.js.map +1 -0
- package/dist/core/receipt.test.js +193 -0
- package/dist/core/receipt.test.js.map +1 -0
- package/dist/core/reviewers.js +179 -0
- package/dist/core/reviewers.js.map +1 -0
- package/dist/core/reviewers.test.js +105 -0
- package/dist/core/reviewers.test.js.map +1 -0
- package/dist/core/roast.js +27 -0
- package/dist/core/roast.js.map +1 -0
- package/dist/core/roast.test.js +19 -0
- package/dist/core/roast.test.js.map +1 -0
- package/dist/core/router.js +8 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/router.test.js +157 -0
- package/dist/core/router.test.js.map +1 -0
- package/dist/core/rules.js +2 -2
- package/dist/core/rules.js.map +1 -1
- package/dist/core/run.js +322 -20
- package/dist/core/run.js.map +1 -1
- package/dist/core/sarif.js +125 -0
- package/dist/core/sarif.js.map +1 -0
- package/dist/core/sarif.test.js +60 -0
- package/dist/core/sarif.test.js.map +1 -0
- package/dist/core/sast.js +324 -0
- package/dist/core/sast.js.map +1 -0
- package/dist/core/sast.test.js +105 -0
- package/dist/core/sast.test.js.map +1 -0
- package/dist/core/sbom.js +121 -0
- package/dist/core/sbom.js.map +1 -0
- package/dist/core/sbom.test.js +81 -0
- package/dist/core/sbom.test.js.map +1 -0
- package/dist/core/second-opinion.js +88 -0
- package/dist/core/second-opinion.js.map +1 -0
- package/dist/core/second-opinion.test.js +89 -0
- package/dist/core/second-opinion.test.js.map +1 -0
- package/dist/core/secrets.js +120 -5
- package/dist/core/secrets.js.map +1 -1
- package/dist/core/secrets.test.js +74 -1
- package/dist/core/secrets.test.js.map +1 -1
- package/dist/core/shadow.js +94 -0
- package/dist/core/shadow.js.map +1 -0
- package/dist/core/shadow.test.js +50 -0
- package/dist/core/shadow.test.js.map +1 -0
- package/dist/core/slicing.js +110 -0
- package/dist/core/slicing.js.map +1 -0
- package/dist/core/slicing.test.js +287 -0
- package/dist/core/slicing.test.js.map +1 -0
- package/dist/core/slop/churn.js +49 -0
- package/dist/core/slop/churn.js.map +1 -0
- package/dist/core/slop/collect.js +186 -0
- package/dist/core/slop/collect.js.map +1 -0
- package/dist/core/slop/dead-exports.js +101 -0
- package/dist/core/slop/dead-exports.js.map +1 -0
- package/dist/core/slop/duplicates.js +155 -0
- package/dist/core/slop/duplicates.js.map +1 -0
- package/dist/core/slop/index.js +72 -0
- package/dist/core/slop/index.js.map +1 -0
- package/dist/core/slop/model.js +2 -0
- package/dist/core/slop/model.js.map +1 -0
- package/dist/core/slop/score.js +185 -0
- package/dist/core/slop/score.js.map +1 -0
- package/dist/core/slop/slop.test.js +160 -0
- package/dist/core/slop/slop.test.js.map +1 -0
- package/dist/core/slop/source.js +129 -0
- package/dist/core/slop/source.js.map +1 -0
- package/dist/core/slop/test-debt.js +178 -0
- package/dist/core/slop/test-debt.js.map +1 -0
- package/dist/core/slop/test-debt.test.js +114 -0
- package/dist/core/slop/test-debt.test.js.map +1 -0
- package/dist/core/slop/todos.js +117 -0
- package/dist/core/slop/todos.js.map +1 -0
- package/dist/core/snapshot.js +214 -0
- package/dist/core/snapshot.js.map +1 -0
- package/dist/core/snapshot.test.js +101 -0
- package/dist/core/snapshot.test.js.map +1 -0
- package/dist/core/stats.js +119 -0
- package/dist/core/stats.js.map +1 -0
- package/dist/core/stats.test.js +86 -0
- package/dist/core/stats.test.js.map +1 -0
- package/dist/core/suppressions.js +96 -0
- package/dist/core/suppressions.js.map +1 -0
- package/dist/core/suppressions.test.js +90 -0
- package/dist/core/suppressions.test.js.map +1 -0
- package/dist/core/test-delta.js +53 -0
- package/dist/core/test-delta.js.map +1 -0
- package/dist/core/test-delta.test.js +41 -0
- package/dist/core/test-delta.test.js.map +1 -0
- package/dist/core/test-plan.js +212 -0
- package/dist/core/test-plan.js.map +1 -0
- package/dist/core/test-plan.test.js +94 -0
- package/dist/core/test-plan.test.js.map +1 -0
- package/dist/core/test-weakening.js +191 -0
- package/dist/core/test-weakening.js.map +1 -0
- package/dist/core/test-weakening.test.js +114 -0
- package/dist/core/test-weakening.test.js.map +1 -0
- package/dist/core/tree-scan.js +77 -0
- package/dist/core/tree-scan.js.map +1 -0
- package/dist/core/tree-scan.test.js +58 -0
- package/dist/core/tree-scan.test.js.map +1 -0
- package/dist/mcp-prompts.test.js +133 -0
- package/dist/mcp-prompts.test.js.map +1 -0
- package/dist/mcp.js +3303 -240
- package/dist/mcp.js.map +1 -1
- package/dist/mcp.test.js +1739 -1
- package/dist/mcp.test.js.map +1 -1
- package/dist/skills.test.js +221 -0
- package/dist/skills.test.js.map +1 -0
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/docs/integrations.md +151 -7
- package/package.json +2 -1
- package/prompts/oc-pilot.en.md +8 -1
- package/prompts/oc-pilot.ru.md +8 -1
- package/server.json +2 -2
- package/skills/agent-self-review/SKILL.md +87 -0
- package/skills/commit-discipline/SKILL.md +86 -0
- package/skills/oc-pilot/SKILL.md +86 -0
- package/skills/secure-diff-gate/SKILL.md +101 -0
- package/skills/stack-review-packs/SKILL.md +76 -0
- package/skills/test-failure-triage/SKILL.md +88 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { PilotError } from "./errors.js";
|
|
2
|
+
import { runGit } from "./git.js";
|
|
3
|
+
import { splitDiffBlocks } from "./diff.js";
|
|
4
|
+
import { analyzeMockLeaks } from "./mock-leak.js";
|
|
5
|
+
import { scanSource } from "./sast.js";
|
|
6
|
+
import { analyzeTestWeakness } from "./test-weakening.js";
|
|
7
|
+
import { isCodeFile, isGeneratedPath, isTestFile } from "./slop/source.js";
|
|
8
|
+
const RECORD = "\u001e";
|
|
9
|
+
const FIELD = "\u001f";
|
|
10
|
+
const SEVERITY_WEIGHT = { high: 5, medium: 3, low: 1 };
|
|
11
|
+
const SAST_WEIGHT = { high: 5, medium: 3, low: 1 };
|
|
12
|
+
function parseCommit(record) {
|
|
13
|
+
const [hash, shortHash, author, date, subject] = record.split(FIELD);
|
|
14
|
+
if (!hash || !shortHash || !date)
|
|
15
|
+
return undefined;
|
|
16
|
+
return {
|
|
17
|
+
hash,
|
|
18
|
+
shortHash,
|
|
19
|
+
author: author ?? "unknown",
|
|
20
|
+
date,
|
|
21
|
+
subject: subject ?? "(без темы)",
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function readCommit(cwd, ref) {
|
|
25
|
+
const result = runGit(["show", "-s", `--format=%H${FIELD}%h${FIELD}%an${FIELD}%aI${FIELD}%s`, ref], cwd);
|
|
26
|
+
if (result.status !== 0) {
|
|
27
|
+
throw new PilotError(`Коммит не найден: ${ref}`, {
|
|
28
|
+
hint: "Укажите существующий ref, например HEAD или HEAD~1.",
|
|
29
|
+
exitCode: 2,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const commit = parseCommit(result.stdout.trim());
|
|
33
|
+
if (!commit) {
|
|
34
|
+
throw new PilotError(`Не удалось прочитать коммит: ${ref}`, { exitCode: 2 });
|
|
35
|
+
}
|
|
36
|
+
return commit;
|
|
37
|
+
}
|
|
38
|
+
function readDiff(cwd, ref) {
|
|
39
|
+
const result = runGit(["show", "--format=", "--no-color", "--unified=0", ref], cwd);
|
|
40
|
+
if (result.status !== 0) {
|
|
41
|
+
throw new PilotError(`Не удалось получить diff коммита ${ref}`, { exitCode: 2 });
|
|
42
|
+
}
|
|
43
|
+
return result.stdout;
|
|
44
|
+
}
|
|
45
|
+
/** Added line numbers per file, used to keep SAST findings inside the commit. */
|
|
46
|
+
export function addedLinesByFile(diff) {
|
|
47
|
+
const result = new Map();
|
|
48
|
+
for (const block of splitDiffBlocks(diff)) {
|
|
49
|
+
if (block.path === "(diff)" || block.path === "(unknown)")
|
|
50
|
+
continue;
|
|
51
|
+
const lines = new Set();
|
|
52
|
+
let newLine = 0;
|
|
53
|
+
for (const line of block.text.split("\n")) {
|
|
54
|
+
const hunk = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/.exec(line);
|
|
55
|
+
if (hunk) {
|
|
56
|
+
newLine = Number(hunk[1]);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (line.startsWith("+++") || line.startsWith("---"))
|
|
60
|
+
continue;
|
|
61
|
+
if (line.startsWith("+")) {
|
|
62
|
+
lines.add(newLine);
|
|
63
|
+
newLine += 1;
|
|
64
|
+
}
|
|
65
|
+
else if (line.startsWith(" ")) {
|
|
66
|
+
newLine += 1;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (lines.size > 0)
|
|
70
|
+
result.set(block.path.replace(/\\/g, "/"), lines);
|
|
71
|
+
}
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
function diffStats(diff) {
|
|
75
|
+
let files = 0;
|
|
76
|
+
let additions = 0;
|
|
77
|
+
let deletions = 0;
|
|
78
|
+
for (const line of diff.split("\n")) {
|
|
79
|
+
if (line.startsWith("diff --git "))
|
|
80
|
+
files += 1;
|
|
81
|
+
else if (line.startsWith("+") && !line.startsWith("+++"))
|
|
82
|
+
additions += 1;
|
|
83
|
+
else if (line.startsWith("-") && !line.startsWith("---"))
|
|
84
|
+
deletions += 1;
|
|
85
|
+
}
|
|
86
|
+
return { files, additions, deletions };
|
|
87
|
+
}
|
|
88
|
+
function scanAddedFiles(cwd, ref, added) {
|
|
89
|
+
const signals = [];
|
|
90
|
+
for (const [file, lines] of added) {
|
|
91
|
+
if (!isCodeFile(file) || isTestFile(file) || isGeneratedPath(file))
|
|
92
|
+
continue;
|
|
93
|
+
const show = runGit(["show", `${ref}:${file}`], cwd);
|
|
94
|
+
if (show.status !== 0)
|
|
95
|
+
continue;
|
|
96
|
+
for (const finding of scanSource(file, show.stdout).findings) {
|
|
97
|
+
if (!lines.has(finding.line))
|
|
98
|
+
continue;
|
|
99
|
+
signals.push({
|
|
100
|
+
kind: "sast",
|
|
101
|
+
severity: finding.severity,
|
|
102
|
+
file,
|
|
103
|
+
line: finding.line,
|
|
104
|
+
detail: `${finding.rule}: ${finding.message}`,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return signals;
|
|
109
|
+
}
|
|
110
|
+
function timeline(cwd, ref, files, depth) {
|
|
111
|
+
if (files.length === 0)
|
|
112
|
+
return [];
|
|
113
|
+
const format = `--format=${RECORD}%H${FIELD}%h${FIELD}%an${FIELD}%aI${FIELD}%s`;
|
|
114
|
+
const before = runGit(["log", `-n${String(depth)}`, format, ref, "--", ...files], cwd);
|
|
115
|
+
const after = runGit(["log", `-n${String(depth)}`, format, `${ref}..HEAD`, "--", ...files], cwd);
|
|
116
|
+
const entries = [];
|
|
117
|
+
const targetHash = readCommit(cwd, ref).hash;
|
|
118
|
+
const push = (text, relation) => {
|
|
119
|
+
for (const record of text.split(RECORD)) {
|
|
120
|
+
const commit = parseCommit(record.trim());
|
|
121
|
+
if (!commit)
|
|
122
|
+
continue;
|
|
123
|
+
if (relation === "before" && commit.hash === targetHash) {
|
|
124
|
+
entries.push({ relation: "target", commit, files });
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
entries.push({ relation, commit, files });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
push(before.stdout, "before");
|
|
132
|
+
push(after.stdout, "after");
|
|
133
|
+
return entries;
|
|
134
|
+
}
|
|
135
|
+
/** Builds a deterministic post-mortem for one commit. */
|
|
136
|
+
export function analyzeAutopsy(cwd, ref, options = {}) {
|
|
137
|
+
const depth = Math.min(50, Math.max(1, options.depth ?? 5));
|
|
138
|
+
const commit = readCommit(cwd, ref);
|
|
139
|
+
const diff = readDiff(cwd, ref);
|
|
140
|
+
const added = addedLinesByFile(diff);
|
|
141
|
+
const changedFiles = [...added.keys()].sort();
|
|
142
|
+
const signals = [];
|
|
143
|
+
signals.push(...scanAddedFiles(cwd, ref, added));
|
|
144
|
+
for (const finding of analyzeTestWeakness(diff)) {
|
|
145
|
+
signals.push({
|
|
146
|
+
kind: "test-weakening",
|
|
147
|
+
severity: "high",
|
|
148
|
+
file: finding.file,
|
|
149
|
+
line: finding.line,
|
|
150
|
+
detail: `${finding.kind}: ${finding.detail}`,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
for (const leak of analyzeMockLeaks(diff).findings) {
|
|
154
|
+
signals.push({
|
|
155
|
+
kind: "mock-leak",
|
|
156
|
+
severity: leak.severity,
|
|
157
|
+
file: leak.file,
|
|
158
|
+
line: leak.line,
|
|
159
|
+
detail: `${leak.kind}: ${leak.detail}`,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
signals.sort((left, right) => left.file.localeCompare(right.file) || left.line - right.line || left.kind.localeCompare(right.kind));
|
|
163
|
+
const suspects = new Map();
|
|
164
|
+
for (const signal of signals) {
|
|
165
|
+
const entry = suspects.get(signal.file) ?? { file: signal.file, score: 0, reasons: [] };
|
|
166
|
+
entry.score += signal.kind === "sast" ? SAST_WEIGHT[signal.severity] : SEVERITY_WEIGHT[signal.severity];
|
|
167
|
+
entry.reasons.push(`${signal.kind}: ${signal.detail}`);
|
|
168
|
+
suspects.set(signal.file, entry);
|
|
169
|
+
}
|
|
170
|
+
const suspectList = [...suspects.values()]
|
|
171
|
+
.sort((left, right) => right.score - left.score || left.file.localeCompare(right.file))
|
|
172
|
+
.slice(0, 5);
|
|
173
|
+
const verdict = signals.some((signal) => signal.severity === "high")
|
|
174
|
+
? "dangerous"
|
|
175
|
+
: signals.length > 0
|
|
176
|
+
? "suspicious"
|
|
177
|
+
: "clean";
|
|
178
|
+
const summary = verdict === "dangerous"
|
|
179
|
+
? `Коммит ${commit.shortHash} оставил ${String(signals.length)} риск(ов), включая high.`
|
|
180
|
+
: verdict === "suspicious"
|
|
181
|
+
? `Коммит ${commit.shortHash} оставил ${String(signals.length)} риск(ов) без high.`
|
|
182
|
+
: `Коммит ${commit.shortHash} не оставил рискованных сигналов.`;
|
|
183
|
+
return {
|
|
184
|
+
commit,
|
|
185
|
+
stats: diffStats(diff),
|
|
186
|
+
changedFiles,
|
|
187
|
+
signals,
|
|
188
|
+
suspects: suspectList,
|
|
189
|
+
timeline: timeline(cwd, ref, changedFiles, depth),
|
|
190
|
+
verdict,
|
|
191
|
+
summary,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/** Detective-style Russian report. */
|
|
195
|
+
export function renderAutopsy(report) {
|
|
196
|
+
const lines = [
|
|
197
|
+
"ВСКРЫТИЕ КОММИТА",
|
|
198
|
+
`Коммит: ${report.commit.shortHash} ${report.commit.subject}`,
|
|
199
|
+
`Автор: ${report.commit.author}, ${report.commit.date}`,
|
|
200
|
+
`Изменено: ${String(report.stats.files)} файл(ов), +${String(report.stats.additions)} / -${String(report.stats.deletions)}.`,
|
|
201
|
+
`Вердикт: ${report.verdict}. ${report.summary}`,
|
|
202
|
+
];
|
|
203
|
+
if (report.changedFiles.length > 0) {
|
|
204
|
+
lines.push("", "Затронутые файлы:");
|
|
205
|
+
for (const file of report.changedFiles)
|
|
206
|
+
lines.push(` ${file}`);
|
|
207
|
+
}
|
|
208
|
+
if (report.signals.length > 0) {
|
|
209
|
+
lines.push("", "Улики:");
|
|
210
|
+
for (const signal of report.signals.slice(0, 20)) {
|
|
211
|
+
lines.push(` ${signal.file}:${String(signal.line)} [${signal.kind}/${signal.severity}] ${signal.detail}`);
|
|
212
|
+
}
|
|
213
|
+
if (report.signals.length > 20)
|
|
214
|
+
lines.push(` …и ещё ${String(report.signals.length - 20)}`);
|
|
215
|
+
}
|
|
216
|
+
if (report.suspects.length > 0) {
|
|
217
|
+
lines.push("", "Подозреваемые:");
|
|
218
|
+
for (const suspect of report.suspects) {
|
|
219
|
+
lines.push(` ${suspect.file} (${String(suspect.score)} очков): ${suspect.reasons.slice(0, 3).join("; ")}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (report.timeline.length > 0) {
|
|
223
|
+
lines.push("", "Хронология:");
|
|
224
|
+
for (const entry of report.timeline) {
|
|
225
|
+
lines.push(` ${entry.commit.shortHash} ${entry.commit.date.slice(0, 10)} [${entry.relation}] ${entry.commit.subject}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return `${lines.join("\n")}\n`;
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=autopsy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autopsy.js","sourceRoot":"","sources":["../../src/core/autopsy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAqB,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAsD3E,MAAM,MAAM,GAAG,QAAQ,CAAC;AACxB,MAAM,KAAK,GAAG,QAAQ,CAAC;AACvB,MAAM,eAAe,GAA8C,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AAClG,MAAM,WAAW,GAAiC,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC;AAEjF,SAAS,WAAW,CAAC,MAAc;IACjC,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrE,IAAI,CAAC,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IACnD,OAAO;QACL,IAAI;QACJ,SAAS;QACT,MAAM,EAAE,MAAM,IAAI,SAAS;QAC3B,IAAI;QACJ,OAAO,EAAE,OAAO,IAAI,YAAY;KACjC,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,GAAW,EAAE,GAAW;IAC1C,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,cAAc,KAAK,KAAK,KAAK,MAAM,KAAK,MAAM,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;IACzG,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,UAAU,CAAC,qBAAqB,GAAG,EAAE,EAAE;YAC/C,IAAI,EAAE,qDAAqD;YAC3D,QAAQ,EAAE,CAAC;SACZ,CAAC,CAAC;IACL,CAAC;IACD,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACjD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,UAAU,CAAC,gCAAgC,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW,EAAE,GAAW;IACxC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;IACpF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,UAAU,CAAC,oCAAoC,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC;AACvB,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC9C,KAAK,MAAM,KAAK,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;YAAE,SAAS;QACpE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;QAChC,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,uCAAuC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChE,IAAI,IAAI,EAAE,CAAC;gBACT,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC1B,SAAS;YACX,CAAC;YACD,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;gBAAE,SAAS;YAC/D,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzB,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACnB,OAAO,IAAI,CAAC,CAAC;YACf,CAAC;iBAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChC,OAAO,IAAI,CAAC,CAAC;YACf,CAAC;QACH,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;YAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC;YAAE,KAAK,IAAI,CAAC,CAAC;aAC1C,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,SAAS,IAAI,CAAC,CAAC;aACpE,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,SAAS,IAAI,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AACzC,CAAC;AAED,SAAS,cAAc,CAAC,GAAW,EAAE,GAAW,EAAE,KAA+B;IAC/E,MAAM,OAAO,GAAoB,EAAE,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC;QAClC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC;YAAE,SAAS;QAC7E,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;QACrD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAChC,KAAK,MAAM,OAAO,IAAI,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC7D,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,SAAS;YACvC,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,MAAM;gBACZ,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,IAAI;gBACJ,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,OAAO,EAAE;aAC9C,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW,EAAE,GAAW,EAAE,KAAe,EAAE,KAAa;IACxE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAClC,MAAM,MAAM,GAAG,YAAY,MAAM,KAAK,KAAK,KAAK,KAAK,MAAM,KAAK,MAAM,KAAK,IAAI,CAAC;IAChF,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IACvF,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,KAAK,EAAE,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,GAAG,QAAQ,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IACjG,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC;IAE7C,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,QAA4B,EAAQ,EAAE;QAChE,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YACxC,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;YAC1C,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,IAAI,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBACxD,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YACtD,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,cAAc,CAAC,GAAW,EAAE,GAAW,EAAE,UAA0B,EAAE;IACnF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,YAAY,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,MAAM,OAAO,GAAoB,EAAE,CAAC;IAEpC,OAAO,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;IAEjD,KAAK,MAAM,OAAO,IAAI,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,gBAAgB;YACtB,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,MAAM,EAAE;SAC7C,CAAC,CAAC;IACL,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC;YACX,IAAI,EAAE,WAAW;YACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,EAAE;SACvC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAEpI,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA0B,CAAC;IACnD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACxF,KAAK,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACvD,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACnC,CAAC;IACD,MAAM,WAAW,GAAG,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;SACvC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;SACtF,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEf,MAAM,OAAO,GAAmB,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC;QAClF,CAAC,CAAC,WAAW;QACb,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;YAClB,CAAC,CAAC,YAAY;YACd,CAAC,CAAC,OAAO,CAAC;IACd,MAAM,OAAO,GACX,OAAO,KAAK,WAAW;QACrB,CAAC,CAAC,UAAU,MAAM,CAAC,SAAS,YAAY,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,0BAA0B;QACxF,CAAC,CAAC,OAAO,KAAK,YAAY;YACxB,CAAC,CAAC,UAAU,MAAM,CAAC,SAAS,YAAY,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,qBAAqB;YACnF,CAAC,CAAC,UAAU,MAAM,CAAC,SAAS,mCAAmC,CAAC;IAEtE,OAAO;QACL,MAAM;QACN,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC;QACtB,YAAY;QACZ,OAAO;QACP,QAAQ,EAAE,WAAW;QACrB,QAAQ,EAAE,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,YAAY,EAAE,KAAK,CAAC;QACjD,OAAO;QACP,OAAO;KACR,CAAC;AACJ,CAAC;AAED,sCAAsC;AACtC,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,MAAM,KAAK,GAAG;QACZ,kBAAkB;QAClB,WAAW,MAAM,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE;QAC7D,UAAU,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;QACvD,aAAa,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,eAAe,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG;QAC5H,YAAY,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,OAAO,EAAE;KAChD,CAAC;IAEF,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,mBAAmB,CAAC,CAAC;QACpC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,YAAY;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QACzB,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YACjD,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7G,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,gBAAgB,CAAC,CAAC;QACjC,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACtC,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9G,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;QAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YACpC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,CAAC,QAAQ,KAAK,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1H,CAAC;IACH,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import test from "node:test";
|
|
7
|
+
import { analyzeAutopsy, renderAutopsy } from "./autopsy.js";
|
|
8
|
+
function git(args, cwd) {
|
|
9
|
+
const result = spawnSync("git", args, { cwd, encoding: "utf8" });
|
|
10
|
+
if (result.status !== 0) {
|
|
11
|
+
throw new Error(`git ${args.join(" ")} failed: ${result.stderr}`);
|
|
12
|
+
}
|
|
13
|
+
return result.stdout;
|
|
14
|
+
}
|
|
15
|
+
function makeRepo() {
|
|
16
|
+
const dir = mkdtempSync(join(tmpdir(), "oc-pilot-autopsy-"));
|
|
17
|
+
git(["init", "-q"], dir);
|
|
18
|
+
git(["config", "user.email", "test@example.com"], dir);
|
|
19
|
+
git(["config", "user.name", "Test"], dir);
|
|
20
|
+
git(["config", "core.autocrlf", "false"], dir);
|
|
21
|
+
mkdirSync(join(dir, "src"), { recursive: true });
|
|
22
|
+
return dir;
|
|
23
|
+
}
|
|
24
|
+
function commit(dir, message) {
|
|
25
|
+
git(["add", "."], dir);
|
|
26
|
+
git(["commit", "-m", message], dir);
|
|
27
|
+
return git(["rev-parse", "HEAD"], dir).trim();
|
|
28
|
+
}
|
|
29
|
+
test("analyzeAutopsy finds a dangerous command injection", () => {
|
|
30
|
+
const dir = makeRepo();
|
|
31
|
+
try {
|
|
32
|
+
writeFileSync(join(dir, "src", "app.js"), 'const { exec } = require("child_process");\nexec(req.query.cmd);\n', "utf8");
|
|
33
|
+
const hash = commit(dir, "add the debug command");
|
|
34
|
+
const report = analyzeAutopsy(dir, "HEAD");
|
|
35
|
+
assert.equal(report.commit.hash, hash);
|
|
36
|
+
assert.equal(report.verdict, "dangerous");
|
|
37
|
+
assert.ok(report.signals.some((signal) => signal.kind === "sast" && signal.file === "src/app.js"));
|
|
38
|
+
assert.equal(report.suspects[0]?.file, "src/app.js");
|
|
39
|
+
assert.match(report.summary, /high/);
|
|
40
|
+
assert.match(renderAutopsy(report), /ВСКРЫТИЕ КОММИТА/);
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
rmSync(dir, { recursive: true, force: true });
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
test("analyzeAutopsy flags a weakened test", () => {
|
|
47
|
+
const dir = makeRepo();
|
|
48
|
+
try {
|
|
49
|
+
writeFileSync(join(dir, "src", "app.ts"), "export const value = 1;\n", "utf8");
|
|
50
|
+
commit(dir, "add the value");
|
|
51
|
+
writeFileSync(join(dir, "src", "app.test.ts"), 'import { value } from "./app";\n\nit.skip("returns one", () => {\n expect(value).toBe(1);\n});\n', "utf8");
|
|
52
|
+
commit(dir, "skip the failing test");
|
|
53
|
+
const report = analyzeAutopsy(dir, "HEAD");
|
|
54
|
+
assert.ok(report.signals.some((signal) => signal.kind === "test-weakening"));
|
|
55
|
+
assert.equal(report.verdict, "dangerous");
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
rmSync(dir, { recursive: true, force: true });
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
test("analyzeAutopsy reports a clean commit", () => {
|
|
62
|
+
const dir = makeRepo();
|
|
63
|
+
try {
|
|
64
|
+
writeFileSync(join(dir, "src", "value.ts"), "export const value = 1;\n", "utf8");
|
|
65
|
+
commit(dir, "add a value");
|
|
66
|
+
const report = analyzeAutopsy(dir, "HEAD");
|
|
67
|
+
assert.equal(report.verdict, "clean");
|
|
68
|
+
assert.deepEqual(report.signals, []);
|
|
69
|
+
assert.deepEqual(report.suspects, []);
|
|
70
|
+
assert.match(report.summary, /не оставил рискованных сигналов/i);
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
rmSync(dir, { recursive: true, force: true });
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
test("analyzeAutopsy builds a before and after timeline", () => {
|
|
77
|
+
const dir = makeRepo();
|
|
78
|
+
try {
|
|
79
|
+
writeFileSync(join(dir, "src", "app.ts"), "export const value = 1;\n", "utf8");
|
|
80
|
+
commit(dir, "add the value");
|
|
81
|
+
writeFileSync(join(dir, "src", "app.ts"), "export const value = 2;\n", "utf8");
|
|
82
|
+
const target = commit(dir, "bump the value");
|
|
83
|
+
writeFileSync(join(dir, "src", "app.ts"), "export const value = 3;\n", "utf8");
|
|
84
|
+
commit(dir, "bump it again");
|
|
85
|
+
const report = analyzeAutopsy(dir, "HEAD~1", { depth: 5 });
|
|
86
|
+
assert.equal(report.commit.hash, target);
|
|
87
|
+
assert.ok(report.timeline.some((entry) => entry.relation === "target" && entry.commit.hash === target));
|
|
88
|
+
assert.ok(report.timeline.some((entry) => entry.relation === "after"));
|
|
89
|
+
assert.ok(report.timeline.some((entry) => entry.relation === "before"));
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
rmSync(dir, { recursive: true, force: true });
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
test("analyzeAutopsy rejects an unknown revision", () => {
|
|
96
|
+
const dir = makeRepo();
|
|
97
|
+
try {
|
|
98
|
+
writeFileSync(join(dir, "src", "app.ts"), "export const value = 1;\n", "utf8");
|
|
99
|
+
commit(dir, "add the value");
|
|
100
|
+
assert.throws(() => analyzeAutopsy(dir, "does-not-exist"), /does-not-exist|ревизи/i);
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
rmSync(dir, { recursive: true, force: true });
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
//# sourceMappingURL=autopsy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autopsy.test.js","sourceRoot":"","sources":["../../src/core/autopsy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { runGit } from "./git.js";
|
|
2
|
+
import { splitDiffBlocks } from "./diff.js";
|
|
3
|
+
import { scanSource } from "./sast.js";
|
|
4
|
+
import { analyzeTestWeakness } from "./test-weakening.js";
|
|
5
|
+
const DEFAULT_HISTORY_DAYS = 90;
|
|
6
|
+
const MIN_COMMITS = 10;
|
|
7
|
+
const MAX_COMMITS = 200;
|
|
8
|
+
const DAY_MS = 86_400_000;
|
|
9
|
+
const MOVING_WINDOW_DAYS = 14;
|
|
10
|
+
const INSUFFICIENT = "[INSUFFICIENT DATA: Need at least 10 commits to compute Slop Velocity]";
|
|
11
|
+
const WEIGHTS = {
|
|
12
|
+
testWeakening: 0.35,
|
|
13
|
+
security: 0.3,
|
|
14
|
+
slop: 0.15,
|
|
15
|
+
todos: 0.1,
|
|
16
|
+
churn: 0.1,
|
|
17
|
+
};
|
|
18
|
+
function clamp01(value) {
|
|
19
|
+
return Math.max(0, Math.min(1, value));
|
|
20
|
+
}
|
|
21
|
+
/** Parses 30d, 2w, 3m or a plain number of days. */
|
|
22
|
+
export function parseHistoryWindow(raw) {
|
|
23
|
+
if (raw === undefined || raw.trim() === "")
|
|
24
|
+
return DEFAULT_HISTORY_DAYS;
|
|
25
|
+
const match = /^(\d+(?:\.\d+)?)([dwm])?$/i.exec(raw.trim());
|
|
26
|
+
if (!match?.[1])
|
|
27
|
+
return DEFAULT_HISTORY_DAYS;
|
|
28
|
+
const value = Number(match[1]);
|
|
29
|
+
const unit = match[2]?.toLowerCase() ?? "d";
|
|
30
|
+
const days = unit === "w" ? value * 7 : unit === "m" ? value * 30 : value;
|
|
31
|
+
return Math.max(1, Math.min(3650, Math.round(days)));
|
|
32
|
+
}
|
|
33
|
+
function dayOf(iso) {
|
|
34
|
+
const date = new Date(iso);
|
|
35
|
+
return Number.isNaN(date.getTime()) ? iso.slice(0, 10) : date.toISOString().slice(0, 10);
|
|
36
|
+
}
|
|
37
|
+
function dayNumber(day) {
|
|
38
|
+
const time = new Date(`${day}T00:00:00.000Z`).getTime();
|
|
39
|
+
return Number.isNaN(time) ? 0 : Math.floor(time / DAY_MS);
|
|
40
|
+
}
|
|
41
|
+
function metricsOf(diff) {
|
|
42
|
+
let todos = 0;
|
|
43
|
+
let churn = 0;
|
|
44
|
+
let sastHigh = 0;
|
|
45
|
+
let sastMedium = 0;
|
|
46
|
+
for (const block of splitDiffBlocks(diff)) {
|
|
47
|
+
if (block.path === "(diff)" || block.path === "(unknown)")
|
|
48
|
+
continue;
|
|
49
|
+
const added = [];
|
|
50
|
+
for (const line of block.text.split("\n")) {
|
|
51
|
+
if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
52
|
+
added.push(line.slice(1));
|
|
53
|
+
churn += 1;
|
|
54
|
+
if (/\b(?:TODO|FIXME|HACK)\b/.test(line))
|
|
55
|
+
todos += 1;
|
|
56
|
+
}
|
|
57
|
+
else if (line.startsWith("-") && !line.startsWith("---")) {
|
|
58
|
+
churn += 1;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (added.length === 0)
|
|
62
|
+
continue;
|
|
63
|
+
for (const finding of scanSource(block.path, added.join("\n")).findings) {
|
|
64
|
+
if (finding.severity === "high")
|
|
65
|
+
sastHigh += 1;
|
|
66
|
+
else if (finding.severity === "medium")
|
|
67
|
+
sastMedium += 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const weakness = analyzeTestWeakness(diff).length;
|
|
71
|
+
const slopProxy = Math.min(100, todos * 5 + weakness * 20 + sastHigh * 25 + sastMedium * 10 + churn / 100);
|
|
72
|
+
const score = Math.round(100 *
|
|
73
|
+
(WEIGHTS.testWeakening * clamp01(weakness / 3) +
|
|
74
|
+
WEIGHTS.security * clamp01(sastHigh / 2 + sastMedium / 5) +
|
|
75
|
+
WEIGHTS.slop * clamp01(slopProxy / 100) +
|
|
76
|
+
WEIGHTS.todos * clamp01(todos / 5) +
|
|
77
|
+
WEIGHTS.churn * clamp01(churn / 2000)));
|
|
78
|
+
return { weakness, sastHigh, sastMedium, todos, churn, score };
|
|
79
|
+
}
|
|
80
|
+
function readCommits(cwd, sinceDays) {
|
|
81
|
+
const since = new Date(Date.now() - sinceDays * DAY_MS).toISOString();
|
|
82
|
+
const log = runGit(["log", `--since=${since}`, `--max-count=${String(MAX_COMMITS)}`, "--pretty=format:%H%x1f%aI"], cwd);
|
|
83
|
+
if (log.status !== 0)
|
|
84
|
+
return [];
|
|
85
|
+
const rows = log.stdout
|
|
86
|
+
.split(/\r?\n/)
|
|
87
|
+
.map((line) => line.trim())
|
|
88
|
+
.filter((line) => line.length > 0)
|
|
89
|
+
.map((line) => {
|
|
90
|
+
const [hash, at] = line.split("\u001f");
|
|
91
|
+
return { hash: hash ?? "", at: at ?? "" };
|
|
92
|
+
})
|
|
93
|
+
.filter((row) => row.hash && row.at)
|
|
94
|
+
.reverse();
|
|
95
|
+
const commits = [];
|
|
96
|
+
for (const row of rows) {
|
|
97
|
+
const diff = runGit(["show", "--format=", "--no-color", "--unified=0", row.hash], cwd);
|
|
98
|
+
if (diff.status !== 0)
|
|
99
|
+
continue;
|
|
100
|
+
commits.push({ hash: row.hash, date: dayOf(row.at), ...metricsOf(diff.stdout) });
|
|
101
|
+
}
|
|
102
|
+
return commits;
|
|
103
|
+
}
|
|
104
|
+
function dailyPoints(commits) {
|
|
105
|
+
const byDay = new Map();
|
|
106
|
+
for (const commit of commits) {
|
|
107
|
+
const entry = byDay.get(commit.date) ?? { total: 0, count: 0 };
|
|
108
|
+
entry.total += commit.score;
|
|
109
|
+
entry.count += 1;
|
|
110
|
+
byDay.set(commit.date, entry);
|
|
111
|
+
}
|
|
112
|
+
return [...byDay.entries()]
|
|
113
|
+
.sort((left, right) => left[0].localeCompare(right[0]))
|
|
114
|
+
.map(([date, entry]) => ({ date, score: Math.round(entry.total / entry.count), commits: entry.count }));
|
|
115
|
+
}
|
|
116
|
+
function movingAverage(points, windowDays) {
|
|
117
|
+
return points.map((point, index) => {
|
|
118
|
+
const current = dayNumber(point.date);
|
|
119
|
+
let total = 0;
|
|
120
|
+
let count = 0;
|
|
121
|
+
for (let cursor = index; cursor >= 0; cursor -= 1) {
|
|
122
|
+
const candidate = points[cursor];
|
|
123
|
+
if (current - dayNumber(candidate.date) > windowDays)
|
|
124
|
+
break;
|
|
125
|
+
total += candidate.score;
|
|
126
|
+
count += 1;
|
|
127
|
+
}
|
|
128
|
+
return { ...point, score: Math.round(total / count) };
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function withoutOutliers(points) {
|
|
132
|
+
if (points.length < 4)
|
|
133
|
+
return points;
|
|
134
|
+
const mean = points.reduce((sum, point) => sum + point.score, 0) / points.length;
|
|
135
|
+
const variance = points.reduce((sum, point) => sum + (point.score - mean) ** 2, 0) / points.length;
|
|
136
|
+
const limit = mean + 2 * Math.sqrt(variance);
|
|
137
|
+
const kept = points.filter((point) => point.score <= limit);
|
|
138
|
+
return kept.length >= 4 ? kept : points;
|
|
139
|
+
}
|
|
140
|
+
function regress(points) {
|
|
141
|
+
if (points.length < 2)
|
|
142
|
+
return { slope: 0, intercept: points[0]?.score ?? 0, firstDay: points[0] ? dayNumber(points[0].date) : 0 };
|
|
143
|
+
const firstDay = dayNumber(points[0].date);
|
|
144
|
+
const xs = points.map((point) => dayNumber(point.date) - firstDay);
|
|
145
|
+
const ys = points.map((point) => point.score);
|
|
146
|
+
const meanX = xs.reduce((sum, value) => sum + value, 0) / xs.length;
|
|
147
|
+
const meanY = ys.reduce((sum, value) => sum + value, 0) / ys.length;
|
|
148
|
+
let covariance = 0;
|
|
149
|
+
let variance = 0;
|
|
150
|
+
for (let index = 0; index < xs.length; index += 1) {
|
|
151
|
+
covariance += (xs[index] - meanX) * (ys[index] - meanY);
|
|
152
|
+
variance += (xs[index] - meanX) ** 2;
|
|
153
|
+
}
|
|
154
|
+
const slope = variance === 0 ? 0 : covariance / variance;
|
|
155
|
+
return { slope, intercept: meanY - slope * meanX, firstDay };
|
|
156
|
+
}
|
|
157
|
+
function escapeXml(value) {
|
|
158
|
+
return value
|
|
159
|
+
.replaceAll("&", "&")
|
|
160
|
+
.replaceAll("<", "<")
|
|
161
|
+
.replaceAll(">", ">")
|
|
162
|
+
.replaceAll('"', """);
|
|
163
|
+
}
|
|
164
|
+
/** Self-contained SVG chart with the smoothed score and the regression line. */
|
|
165
|
+
export function renderBankruptcySvg(points, slope, intercept, firstDay) {
|
|
166
|
+
const width = 720;
|
|
167
|
+
const height = 260;
|
|
168
|
+
const left = 48;
|
|
169
|
+
const right = 16;
|
|
170
|
+
const top = 24;
|
|
171
|
+
const bottom = 36;
|
|
172
|
+
const plotWidth = width - left - right;
|
|
173
|
+
const plotHeight = height - top - bottom;
|
|
174
|
+
const first = points[0] ? dayNumber(points[0].date) : firstDay;
|
|
175
|
+
const last = points.at(-1) ? dayNumber(points.at(-1).date) : first;
|
|
176
|
+
const span = Math.max(1, last - first);
|
|
177
|
+
const x = (day) => left + ((day - first) / span) * plotWidth;
|
|
178
|
+
const y = (score) => top + (1 - Math.max(0, Math.min(100, score)) / 100) * plotHeight;
|
|
179
|
+
const path = points.map((point) => `${x(dayNumber(point.date)).toFixed(1)},${y(point.score).toFixed(1)}`).join(" ");
|
|
180
|
+
const trendStart = slope * 0 + intercept;
|
|
181
|
+
const trendEnd = slope * span + intercept;
|
|
182
|
+
const trend = `M ${left.toFixed(1)} ${y(trendStart).toFixed(1)} L ${(left + plotWidth).toFixed(1)} ${y(trendEnd).toFixed(1)}`;
|
|
183
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${String(width)}" height="${String(height)}" viewBox="0 0 ${String(width)} ${String(height)}" role="img" aria-label="Tech debt forecast"><title>Tech debt forecast</title><rect width="${String(width)}" height="${String(height)}" fill="#0b0f14"/><line x1="${String(left)}" y1="${String(top)}" x2="${String(left)}" y2="${String(top + plotHeight)}" stroke="#30363d"/><line x1="${String(left)}" y1="${String(top + plotHeight)}" x2="${String(left + plotWidth)}" y2="${String(top + plotHeight)}" stroke="#30363d"/><line x1="${String(left)}" y1="${String(top)}" x2="${String(left + plotWidth)}" y2="${String(top)}" stroke="#c62828" stroke-dasharray="4 4"/><text x="${String(left - 8)}" y="${String(top + 4)}" text-anchor="end" fill="#c62828" font-family="monospace" font-size="11">100</text><text x="${String(left - 8)}" y="${String(top + plotHeight + 4)}" text-anchor="end" fill="#8b949e" font-family="monospace" font-size="11">0</text><polyline points="${path}" fill="none" stroke="#58a6ff" stroke-width="2"/><path d="${trend}" fill="none" stroke="#f0883e" stroke-width="2" stroke-dasharray="6 3"/>${points[0] ? `<text x="${String(left)}" y="${String(height - 10)}" fill="#8b949e" font-family="monospace" font-size="11">${escapeXml(points[0].date)}</text>` : ""}${points.at(-1) ? `<text x="${String(left + plotWidth)}" y="${String(height - 10)}" text-anchor="end" fill="#8b949e" font-family="monospace" font-size="11">${escapeXml(points.at(-1).date)}</text>` : ""}</svg>`;
|
|
184
|
+
}
|
|
185
|
+
export function buildBankruptcy(cwd, options = {}) {
|
|
186
|
+
const historyDays = Math.max(1, Math.min(3650, Math.round(options.historyDays ?? DEFAULT_HISTORY_DAYS)));
|
|
187
|
+
const commits = readCommits(cwd, historyDays);
|
|
188
|
+
const insufficient = commits.length < MIN_COMMITS;
|
|
189
|
+
const rawPoints = dailyPoints(commits);
|
|
190
|
+
const points = movingAverage(rawPoints, MOVING_WINDOW_DAYS);
|
|
191
|
+
const regressionPoints = withoutOutliers(points);
|
|
192
|
+
const { slope, intercept, firstDay } = regress(regressionPoints);
|
|
193
|
+
const currentScore = points.at(-1)?.score ?? 0;
|
|
194
|
+
const daysToBankruptcy = slope > 0.001 ? Math.max(0, Math.round((100 - intercept) / slope)) : null;
|
|
195
|
+
const forecastDate = daysToBankruptcy === null
|
|
196
|
+
? null
|
|
197
|
+
: new Date((firstDay + daysToBankruptcy) * DAY_MS).toISOString().slice(0, 10);
|
|
198
|
+
const verdict = insufficient ? "insufficient" : forecastDate ? "forecast" : "stable";
|
|
199
|
+
const lines = [];
|
|
200
|
+
if (insufficient) {
|
|
201
|
+
lines.push(INSUFFICIENT);
|
|
202
|
+
lines.push(`Коммитов в окне ${String(historyDays)} дн.: ${String(commits.length)}.`);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
lines.push(`Прогноз техдолга: ${String(commits.length)} коммитов за ${String(historyDays)} дн.`);
|
|
206
|
+
lines.push(`Текущий балл: ${String(currentScore)}/100. Скорость: ${slope >= 0 ? "+" : ""}${slope.toFixed(2)}/день.`);
|
|
207
|
+
if (forecastDate) {
|
|
208
|
+
lines.push(`Порог 100 будет достигнут: ${forecastDate} (через ${String(daysToBankruptcy)} дн.).`);
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
lines.push("Скорость не положительна: в обозримом окне банкротство не прогнозируется.");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (options.explain) {
|
|
215
|
+
lines.push("", "Формула: score = 100 * (0.35 * testWeakening + 0.30 * security + 0.15 * slop + 0.10 * todos + 0.10 * churn).", "testWeakening: ослабленные тесты из diff (вес 0.35), security: high/medium SAST на добавленных строках (0.30), slop: TODO + слабые тесты + SAST + churn (0.15), todos: добавленные TODO/FIXME/HACK (0.10), churn: добавленные и удалённые строки (0.10).", `Сглаживание: скользящее среднее ${String(MOVING_WINDOW_DAYS)} дн., выбросы выше mean+2σ исключены из регрессии.`);
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
historyDays,
|
|
219
|
+
commits: commits.length,
|
|
220
|
+
points,
|
|
221
|
+
weights: WEIGHTS,
|
|
222
|
+
slopePerDay: Number(slope.toFixed(3)),
|
|
223
|
+
currentScore,
|
|
224
|
+
forecastDate,
|
|
225
|
+
daysToBankruptcy,
|
|
226
|
+
verdict,
|
|
227
|
+
insufficient,
|
|
228
|
+
content: `${lines.join("\n")}\n`,
|
|
229
|
+
svg: renderBankruptcySvg(points, slope, intercept, firstDay),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=bankruptcy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bankruptcy.js","sourceRoot":"","sources":["../../src/core/bankruptcy.ts"],"names":[],"mappings":"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"}
|