evergreen-deprecation 0.6.1 → 0.7.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.
Files changed (270) hide show
  1. package/README.md +1 -1
  2. package/dist/src/capabilities.js +7 -5
  3. package/dist/src/cle-ingest.d.ts +41 -0
  4. package/dist/src/cle-ingest.js +300 -0
  5. package/dist/src/cli.js +64 -7
  6. package/dist/src/completions.js +2 -0
  7. package/dist/src/data-bundle.d.ts +1 -1
  8. package/dist/src/data-bundle.js +1 -1
  9. package/dist/src/detectors/container/index.js +260 -8
  10. package/dist/src/detectors/container/parse-dockerfile.d.ts +12 -5
  11. package/dist/src/detectors/container/parse-dockerfile.js +69 -8
  12. package/dist/src/detectors/container/rootfs.d.ts +63 -0
  13. package/dist/src/detectors/container/rootfs.js +463 -0
  14. package/dist/src/detectors/database/index.js +30 -6
  15. package/dist/src/detectors/database/parse-terraform.d.ts +38 -10
  16. package/dist/src/detectors/database/parse-terraform.js +204 -25
  17. package/dist/src/detectors/deno/index.d.ts +12 -0
  18. package/dist/src/detectors/deno/index.js +167 -0
  19. package/dist/src/detectors/deno/parse.d.ts +29 -0
  20. package/dist/src/detectors/deno/parse.js +125 -0
  21. package/dist/src/detectors/elixir/index.d.ts +14 -0
  22. package/dist/src/detectors/elixir/index.js +198 -0
  23. package/dist/src/detectors/elixir/parse-elixir-runtime.d.ts +29 -0
  24. package/dist/src/detectors/elixir/parse-elixir-runtime.js +60 -0
  25. package/dist/src/detectors/elixir/parse-mix-exs.d.ts +31 -0
  26. package/dist/src/detectors/elixir/parse-mix-exs.js +41 -0
  27. package/dist/src/detectors/elixir/parse-mix-lock.d.ts +24 -0
  28. package/dist/src/detectors/elixir/parse-mix-lock.js +36 -0
  29. package/dist/src/detectors/index.js +8 -0
  30. package/dist/src/detectors/kubernetes/index.d.ts +9 -0
  31. package/dist/src/detectors/kubernetes/index.js +123 -32
  32. package/dist/src/detectors/kubernetes/parse-helm.d.ts +32 -4
  33. package/dist/src/detectors/kubernetes/parse-helm.js +74 -17
  34. package/dist/src/detectors/kubernetes/parse-manifest.d.ts +1 -1
  35. package/dist/src/detectors/kubernetes/parse-manifest.js +22 -5
  36. package/dist/src/detectors/scala/index.d.ts +14 -0
  37. package/dist/src/detectors/scala/index.js +177 -0
  38. package/dist/src/detectors/scala/parse-build-properties.d.ts +20 -0
  39. package/dist/src/detectors/scala/parse-build-properties.js +35 -0
  40. package/dist/src/detectors/scala/parse-build-sbt.d.ts +19 -0
  41. package/dist/src/detectors/scala/parse-build-sbt.js +36 -0
  42. package/dist/src/detectors/scala/parse-scala-version.d.ts +21 -0
  43. package/dist/src/detectors/scala/parse-scala-version.js +31 -0
  44. package/dist/src/detectors/terraform/hcl.d.ts +15 -0
  45. package/dist/src/detectors/terraform/hcl.js +43 -0
  46. package/dist/src/detectors/terraform/index.d.ts +1 -1
  47. package/dist/src/detectors/terraform/index.js +154 -16
  48. package/dist/src/detectors/terraform/kubernetes.d.ts +46 -0
  49. package/dist/src/detectors/terraform/kubernetes.js +130 -0
  50. package/dist/src/detectors/terraform/plan.d.ts +36 -0
  51. package/dist/src/detectors/terraform/plan.js +193 -0
  52. package/dist/src/domain.d.ts +5 -0
  53. package/dist/src/engine.js +15 -5
  54. package/dist/src/export/cle.d.ts +39 -0
  55. package/dist/src/export/cle.js +56 -0
  56. package/dist/src/guard.d.ts +89 -0
  57. package/dist/src/guard.js +283 -0
  58. package/dist/src/lsp.d.ts +74 -0
  59. package/dist/src/lsp.js +667 -0
  60. package/dist/src/osv-advisories.d.ts +2 -0
  61. package/dist/src/osv-advisories.js +39 -0
  62. package/dist/src/renovate-preset.d.ts +27 -0
  63. package/dist/src/renovate-preset.js +158 -0
  64. package/dist/src/reporters.d.ts +34 -0
  65. package/dist/src/reporters.js +245 -0
  66. package/dist/src/sbom/cyclonedx.d.ts +16 -0
  67. package/dist/src/sbom/cyclonedx.js +107 -0
  68. package/dist/src/sbom/input.d.ts +26 -0
  69. package/dist/src/sbom/input.js +146 -0
  70. package/dist/src/sdk.d.ts +7 -0
  71. package/dist/src/usage/symbols.d.ts +1 -1
  72. package/dist/src/usage/tree-sitter.d.ts +1 -1
  73. package/dist/src/usage/tree-sitter.js +7 -6
  74. package/dist/src/usage/vendor/tree-sitter/LICENSE +21 -0
  75. package/dist/src/usage/vendor/tree-sitter/README.md +15 -0
  76. package/dist/src/usage/vendor/tree-sitter/tree-sitter-javascript.wasm +0 -0
  77. package/dist/src/usage/vendor/tree-sitter/tree-sitter-python.wasm +0 -0
  78. package/dist/src/usage/vendor/tree-sitter/tree-sitter-tsx.wasm +0 -0
  79. package/dist/src/usage/vendor/tree-sitter/tree-sitter-typescript.wasm +0 -0
  80. package/dist/src/usage/vendor/tree-sitter/tree-sitter.cjs +4075 -0
  81. package/dist/src/usage/vendor/tree-sitter/tree-sitter.d.ts +1027 -0
  82. package/dist/src/usage/vendor/tree-sitter/tree-sitter.wasm +0 -0
  83. package/dist/src/version.d.ts +1 -1
  84. package/dist/src/version.js +1 -1
  85. package/examples/agents/copilot/.vscode/mcp.json +1 -1
  86. package/examples/agents/copilot/coding-agent-mcp.json +1 -1
  87. package/examples/agents/cursor/.cursor/mcp.json +1 -1
  88. package/examples/agents/gemini/gemini-extension.json +2 -2
  89. package/examples/agents/gemini/settings.json +1 -1
  90. package/examples/agents/kilo/kilo.jsonc +1 -1
  91. package/examples/capabilities.json +12 -10
  92. package/examples/lifecycle-watch.yml +1 -1
  93. package/package.json +8 -5
  94. package/registry/container.json +269 -0
  95. package/registry/database.json +410 -0
  96. package/registry/deno.json +177 -0
  97. package/registry/elixir.json +309 -0
  98. package/registry/java.json +164 -0
  99. package/registry/kubernetes.json +114 -0
  100. package/registry/osv.json +66 -0
  101. package/registry/scala.json +191 -0
  102. package/registry/terraform.json +1037 -0
  103. package/schemas/finding.v1.schema.json +10 -0
  104. package/schemas/scan.v1.schema.json +10 -0
  105. package/dist/src/action.js.map +0 -1
  106. package/dist/src/agent-instructions.js.map +0 -1
  107. package/dist/src/agent-tools.js.map +0 -1
  108. package/dist/src/as-of.js.map +0 -1
  109. package/dist/src/badge.js.map +0 -1
  110. package/dist/src/baseline.js.map +0 -1
  111. package/dist/src/capabilities.js.map +0 -1
  112. package/dist/src/check-dependency.js.map +0 -1
  113. package/dist/src/cli.js.map +0 -1
  114. package/dist/src/codeowners.js.map +0 -1
  115. package/dist/src/completions.js.map +0 -1
  116. package/dist/src/conformance/checks/bounds.js.map +0 -1
  117. package/dist/src/conformance/checks/determinism.js.map +0 -1
  118. package/dist/src/conformance/checks/evidence.js.map +0 -1
  119. package/dist/src/conformance/checks/inputs.js.map +0 -1
  120. package/dist/src/conformance/checks/locations.js.map +0 -1
  121. package/dist/src/conformance/checks/malformed.js.map +0 -1
  122. package/dist/src/conformance/checks/zero.js.map +0 -1
  123. package/dist/src/conformance/index.js.map +0 -1
  124. package/dist/src/conformance/trace-reads.js.map +0 -1
  125. package/dist/src/data-bundle.js.map +0 -1
  126. package/dist/src/data-signature.js.map +0 -1
  127. package/dist/src/data-source.js.map +0 -1
  128. package/dist/src/data-status.js.map +0 -1
  129. package/dist/src/data-update.js.map +0 -1
  130. package/dist/src/detector-inputs.js.map +0 -1
  131. package/dist/src/detectors/android/gradle-scan.js.map +0 -1
  132. package/dist/src/detectors/android/index.js.map +0 -1
  133. package/dist/src/detectors/android/parse-build-gradle.js.map +0 -1
  134. package/dist/src/detectors/android/parse-libs-versions-toml.js.map +0 -1
  135. package/dist/src/detectors/android/parse-settings-gradle.js.map +0 -1
  136. package/dist/src/detectors/ci-images/index.js.map +0 -1
  137. package/dist/src/detectors/ci-images/parse-azure-pipelines.js.map +0 -1
  138. package/dist/src/detectors/ci-images/parse-circleci.js.map +0 -1
  139. package/dist/src/detectors/ci-images/parse-gitlab-ci.js.map +0 -1
  140. package/dist/src/detectors/container/index.js.map +0 -1
  141. package/dist/src/detectors/container/parse-compose.js.map +0 -1
  142. package/dist/src/detectors/container/parse-dockerfile.js.map +0 -1
  143. package/dist/src/detectors/container/parse-image.js.map +0 -1
  144. package/dist/src/detectors/cpp/index.js.map +0 -1
  145. package/dist/src/detectors/cpp/parse-cmakelists.js.map +0 -1
  146. package/dist/src/detectors/cpp/parse-conan.js.map +0 -1
  147. package/dist/src/detectors/cpp/parse-vcpkg.js.map +0 -1
  148. package/dist/src/detectors/dart/index.js.map +0 -1
  149. package/dist/src/detectors/dart/parse-fvm.js.map +0 -1
  150. package/dist/src/detectors/dart/parse-pubspec-lock.js.map +0 -1
  151. package/dist/src/detectors/dart/parse-pubspec.js.map +0 -1
  152. package/dist/src/detectors/database/index.js.map +0 -1
  153. package/dist/src/detectors/database/parse-compose.js.map +0 -1
  154. package/dist/src/detectors/database/parse-terraform.js.map +0 -1
  155. package/dist/src/detectors/dotnet/index.js.map +0 -1
  156. package/dist/src/detectors/dotnet/msbuild-xml.js.map +0 -1
  157. package/dist/src/detectors/dotnet/parse-global-json.js.map +0 -1
  158. package/dist/src/detectors/dotnet/parse-msbuild.js.map +0 -1
  159. package/dist/src/detectors/dotnet/parse-packages-lock.js.map +0 -1
  160. package/dist/src/detectors/github-actions-dotnet.js.map +0 -1
  161. package/dist/src/detectors/github-actions-node.js.map +0 -1
  162. package/dist/src/detectors/github-actions.js.map +0 -1
  163. package/dist/src/detectors/go/index.js.map +0 -1
  164. package/dist/src/detectors/go/parse-go-mod.js.map +0 -1
  165. package/dist/src/detectors/go/parse-go-work.js.map +0 -1
  166. package/dist/src/detectors/index.js.map +0 -1
  167. package/dist/src/detectors/java/index.js.map +0 -1
  168. package/dist/src/detectors/java/jdk-version.js.map +0 -1
  169. package/dist/src/detectors/java/parse-gradle.js.map +0 -1
  170. package/dist/src/detectors/java/parse-pins.js.map +0 -1
  171. package/dist/src/detectors/java/parse-pom.js.map +0 -1
  172. package/dist/src/detectors/java/parse-wrapper.js.map +0 -1
  173. package/dist/src/detectors/java/xml.js.map +0 -1
  174. package/dist/src/detectors/json-lines.js.map +0 -1
  175. package/dist/src/detectors/kubernetes/api-version.js.map +0 -1
  176. package/dist/src/detectors/kubernetes/index.js.map +0 -1
  177. package/dist/src/detectors/kubernetes/parse-helm.js.map +0 -1
  178. package/dist/src/detectors/kubernetes/parse-kustomize.js.map +0 -1
  179. package/dist/src/detectors/kubernetes/parse-manifest.js.map +0 -1
  180. package/dist/src/detectors/npm.js.map +0 -1
  181. package/dist/src/detectors/php/index.js.map +0 -1
  182. package/dist/src/detectors/php/parse-composer-json.js.map +0 -1
  183. package/dist/src/detectors/php/parse-composer-lock.js.map +0 -1
  184. package/dist/src/detectors/php/parse-php-runtime.js.map +0 -1
  185. package/dist/src/detectors/python.js.map +0 -1
  186. package/dist/src/detectors/ruby/index.js.map +0 -1
  187. package/dist/src/detectors/ruby/parse-gemfile-lock.js.map +0 -1
  188. package/dist/src/detectors/ruby/parse-gemfile.js.map +0 -1
  189. package/dist/src/detectors/ruby/parse-gemspec.js.map +0 -1
  190. package/dist/src/detectors/ruby/parse-ruby-runtime.js.map +0 -1
  191. package/dist/src/detectors/rust/index.js.map +0 -1
  192. package/dist/src/detectors/rust/parse-cargo-lock.js.map +0 -1
  193. package/dist/src/detectors/rust/parse-cargo-toml.js.map +0 -1
  194. package/dist/src/detectors/rust/parse-rust-toolchain.js.map +0 -1
  195. package/dist/src/detectors/rust/toml-lines.js.map +0 -1
  196. package/dist/src/detectors/serverless/index.js.map +0 -1
  197. package/dist/src/detectors/serverless/parse-serverless-yml.js.map +0 -1
  198. package/dist/src/detectors/serverless/parse-template.js.map +0 -1
  199. package/dist/src/detectors/serverless/parse-tf.js.map +0 -1
  200. package/dist/src/detectors/shell/index.js.map +0 -1
  201. package/dist/src/detectors/shell/parse-powershell.js.map +0 -1
  202. package/dist/src/detectors/shell/parse-workflow.js.map +0 -1
  203. package/dist/src/detectors/swift/index.js.map +0 -1
  204. package/dist/src/detectors/swift/parse-package-resolved.js.map +0 -1
  205. package/dist/src/detectors/swift/parse-package-swift.js.map +0 -1
  206. package/dist/src/detectors/swift/parse-swift-toolchain.js.map +0 -1
  207. package/dist/src/detectors/swift/parse-xcode-project.js.map +0 -1
  208. package/dist/src/detectors/terraform/hcl.js.map +0 -1
  209. package/dist/src/detectors/terraform/index.js.map +0 -1
  210. package/dist/src/detectors/terraform/parse-lock.js.map +0 -1
  211. package/dist/src/detectors/terraform/parse-terraform.js.map +0 -1
  212. package/dist/src/detectors/terraform/parse-version-files.js.map +0 -1
  213. package/dist/src/diff.js.map +0 -1
  214. package/dist/src/doctor.js.map +0 -1
  215. package/dist/src/domain.js.map +0 -1
  216. package/dist/src/engine.js.map +0 -1
  217. package/dist/src/exposure.js.map +0 -1
  218. package/dist/src/fix/codemods/index.js.map +0 -1
  219. package/dist/src/fix/git.js.map +0 -1
  220. package/dist/src/fix/github-actions.js.map +0 -1
  221. package/dist/src/fix/index.js.map +0 -1
  222. package/dist/src/fix/runtime-pins.js.map +0 -1
  223. package/dist/src/fix/verify.js.map +0 -1
  224. package/dist/src/forecast.js.map +0 -1
  225. package/dist/src/github-action.js.map +0 -1
  226. package/dist/src/index.js.map +0 -1
  227. package/dist/src/init-agents.js.map +0 -1
  228. package/dist/src/init-hooks.js.map +0 -1
  229. package/dist/src/init-personal.js.map +0 -1
  230. package/dist/src/mcp-cli.js.map +0 -1
  231. package/dist/src/mcp-server.js.map +0 -1
  232. package/dist/src/mcp.js.map +0 -1
  233. package/dist/src/migration-packet.js.map +0 -1
  234. package/dist/src/migration-prompt.js.map +0 -1
  235. package/dist/src/min-support.js.map +0 -1
  236. package/dist/src/package-files.js.map +0 -1
  237. package/dist/src/paths.js.map +0 -1
  238. package/dist/src/pr-comment.js.map +0 -1
  239. package/dist/src/purl.js.map +0 -1
  240. package/dist/src/registry.js.map +0 -1
  241. package/dist/src/report-issue.js.map +0 -1
  242. package/dist/src/reporters.js.map +0 -1
  243. package/dist/src/rollup.js.map +0 -1
  244. package/dist/src/rule-resources.js.map +0 -1
  245. package/dist/src/runtime-pin.js.map +0 -1
  246. package/dist/src/sdk.js.map +0 -1
  247. package/dist/src/setup.js.map +0 -1
  248. package/dist/src/source-usage.js.map +0 -1
  249. package/dist/src/status-file.js.map +0 -1
  250. package/dist/src/tui.js.map +0 -1
  251. package/dist/src/usage/javascript.js.map +0 -1
  252. package/dist/src/usage/python.js.map +0 -1
  253. package/dist/src/usage/symbols.js.map +0 -1
  254. package/dist/src/usage/tree-sitter.js.map +0 -1
  255. package/dist/src/usage-log.js.map +0 -1
  256. package/dist/src/vers/gem.js.map +0 -1
  257. package/dist/src/vers/index.js.map +0 -1
  258. package/dist/src/vers/maven.js.map +0 -1
  259. package/dist/src/vers/nuget.js.map +0 -1
  260. package/dist/src/vers/pep440.js.map +0 -1
  261. package/dist/src/vers/semver.js.map +0 -1
  262. package/dist/src/vers.js.map +0 -1
  263. package/dist/src/version.js.map +0 -1
  264. package/dist/src/watch.js.map +0 -1
  265. package/dist/src/workspaces.js.map +0 -1
  266. package/examples/demo/.github/workflows/ci.yml +0 -10
  267. package/examples/demo/package.json +0 -10
  268. package/examples/demo/src/client.js +0 -5
  269. package/skills/evergreen-deprecation/evals/cases.json +0 -67
  270. package/skills/evergreen-deprecation/evals/dependency-cases.json +0 -389
package/README.md CHANGED
@@ -214,7 +214,7 @@ permissions:
214
214
 
215
215
  steps:
216
216
  - uses: actions/checkout@v7
217
- - uses: arminazimi/evergreen@v0.6.1
217
+ - uses: arminazimi/evergreen@v0.7.1
218
218
  with:
219
219
  baseline: .evergreen-baseline.json
220
220
  fail-on-severity: high
@@ -80,6 +80,7 @@ const manifest = {
80
80
  { id: "cpp", status: "experimental", maturity: "experimental", detectorIds: ["cpp"] },
81
81
  { id: "dart", status: "experimental", maturity: "experimental", detectorIds: ["dart"] },
82
82
  { id: "dotnet", status: "supported", maturity: "beta", detectorIds: ["dotnet"] },
83
+ { id: "elixir", status: "experimental", maturity: "experimental", detectorIds: ["elixir"] },
83
84
  { id: "github-actions", status: "supported", maturity: "stable", detectorIds: ["github-actions"] },
84
85
  { id: "go", status: "experimental", maturity: "experimental", detectorIds: ["go"] },
85
86
  { id: "java", status: "supported", maturity: "beta", detectorIds: ["java"] },
@@ -91,6 +92,7 @@ const manifest = {
91
92
  { id: "python", status: "supported", maturity: "stable", detectorIds: ["python"] },
92
93
  { id: "ruby", status: "experimental", maturity: "experimental", detectorIds: ["ruby"] },
93
94
  { id: "rust", status: "experimental", maturity: "experimental", detectorIds: ["rust"] },
95
+ { id: "scala", status: "experimental", maturity: "experimental", detectorIds: ["scala"] },
94
96
  { id: "serverless", status: "supported", maturity: "beta", detectorIds: ["serverless"] },
95
97
  { id: "swift", status: "supported", maturity: "beta", detectorIds: ["swift"] },
96
98
  { id: "terraform", status: "experimental", maturity: "experimental", detectorIds: ["terraform"] },
@@ -103,35 +105,35 @@ const manifest = {
103
105
  status: "supported",
104
106
  version: "1",
105
107
  description: "Scan a local repository with all built-in lifecycle detectors.",
106
- ecosystems: ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "php", "python", "ruby", "rust", "serverless", "shell", "swift", "terraform"],
108
+ ecosystems: ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "elixir", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "php", "python", "ruby", "rust", "scala", "serverless", "shell", "swift", "terraform"],
107
109
  },
108
110
  {
109
111
  id: "deprecation.list",
110
112
  status: "supported",
111
113
  version: "1",
112
114
  description: "List compact lifecycle findings from a fresh local scan.",
113
- ecosystems: ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "php", "python", "ruby", "rust", "serverless", "shell", "swift", "terraform"],
115
+ ecosystems: ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "elixir", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "php", "python", "ruby", "rust", "scala", "serverless", "shell", "swift", "terraform"],
114
116
  },
115
117
  {
116
118
  id: "deprecation.explain",
117
119
  status: "supported",
118
120
  version: "1",
119
121
  description: "Explain one evidence-backed finding by its exact identifier.",
120
- ecosystems: ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "php", "python", "ruby", "rust", "serverless", "shell", "swift", "terraform"],
122
+ ecosystems: ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "elixir", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "php", "python", "ruby", "rust", "scala", "serverless", "shell", "swift", "terraform"],
121
123
  },
122
124
  {
123
125
  id: "migration.context.create",
124
126
  status: "supported",
125
127
  version: "1",
126
128
  description: "Create a validated migration packet for one finding.",
127
- ecosystems: ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "php", "python", "ruby", "rust", "serverless", "shell", "swift", "terraform"],
129
+ ecosystems: ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "elixir", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "php", "python", "ruby", "rust", "scala", "serverless", "shell", "swift", "terraform"],
128
130
  },
129
131
  {
130
132
  id: "migration.verify",
131
133
  status: "supported",
132
134
  version: "1",
133
135
  description: "Re-scan and verify that an observed finding is absent.",
134
- ecosystems: ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "php", "python", "ruby", "rust", "serverless", "shell", "swift", "terraform"],
136
+ ecosystems: ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "elixir", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "php", "python", "ruby", "rust", "scala", "serverless", "shell", "swift", "terraform"],
135
137
  },
136
138
  {
137
139
  id: "environment.doctor",
@@ -0,0 +1,41 @@
1
+ import type { Detector, DetectorContext, DetectorFinding, DetectorInputs } from "./sdk.js";
2
+ /** File name Evergreen looks for at the root of an installed package. */
3
+ export declare const CLE_FILE_NAME = "cle.json";
4
+ interface CleVersionSpec {
5
+ range: string;
6
+ }
7
+ interface CleEventRecord {
8
+ id: number;
9
+ type: string;
10
+ effective: string;
11
+ published: string;
12
+ versions?: CleVersionSpec[];
13
+ description?: string;
14
+ references?: string[];
15
+ }
16
+ interface CleDocumentRecord {
17
+ $schema: string;
18
+ identifier: string | string[];
19
+ updatedAt: string;
20
+ events: CleEventRecord[];
21
+ }
22
+ export interface CleIngestOptions {
23
+ /**
24
+ * ISO-8601 scan time used to decide scheduled vs reached severity (decision 0010).
25
+ * Callers must pass the same timestamp the scan uses; do not read the clock here.
26
+ */
27
+ readonly scannedAt: string;
28
+ }
29
+ /** Parses a CLE 1.0 document without inventing lifecycle claims. Malformed input yields undefined. */
30
+ export declare function parseCleDocument(input: unknown): CleDocumentRecord | undefined;
31
+ /** Findings from maintainer CLE documents shipped inside installed packages. Offline only. */
32
+ export declare function ingestCle(root: string, options: CleIngestOptions): Promise<DetectorFinding[]>;
33
+ /** Reads CLE documents from installed packages during a repository scan. */
34
+ export declare class CleIngestDetector implements Detector {
35
+ readonly apiVersion: "evergreen.detector.v1";
36
+ readonly id = "cle";
37
+ readonly inputs: DetectorInputs;
38
+ scan(context: DetectorContext): Promise<readonly DetectorFinding[]>;
39
+ }
40
+ export declare const cleDetector: CleIngestDetector;
41
+ export {};
@@ -0,0 +1,300 @@
1
+ import { readFile, readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { CLE_SCHEMA } from "./export/cle.js";
5
+ import { relativePosix } from "./paths.js";
6
+ import { parsePurl, purlIdentity, PurlError } from "./purl.js";
7
+ import { DETECTOR_API_VERSION } from "./sdk.js";
8
+ import { versContains } from "./vers/index.js";
9
+ /** File name Evergreen looks for at the root of an installed package. */
10
+ export const CLE_FILE_NAME = "cle.json";
11
+ const REPORTABLE = new Set(["endOfSupport", "endOfLife", "endOfDevelopment", "endOfDistribution"]);
12
+ const REACHED_SEVERITY = {
13
+ endOfLife: "high",
14
+ endOfDistribution: "high",
15
+ endOfSupport: "medium",
16
+ endOfDevelopment: "medium",
17
+ };
18
+ const TITLE = {
19
+ endOfLife: "End of life",
20
+ endOfDistribution: "End of distribution",
21
+ endOfSupport: "End of support",
22
+ endOfDevelopment: "End of development",
23
+ };
24
+ const SKIPPED_NODE_MODULES = new Set([".bin", ".cache"]);
25
+ function isRecord(value) {
26
+ return typeof value === "object" && value !== null && !Array.isArray(value);
27
+ }
28
+ function isNonEmptyString(value) {
29
+ return typeof value === "string" && value.trim().length > 0;
30
+ }
31
+ /** Parses a CLE 1.0 document without inventing lifecycle claims. Malformed input yields undefined. */
32
+ export function parseCleDocument(input) {
33
+ if (!isRecord(input) || input.$schema !== CLE_SCHEMA)
34
+ return undefined;
35
+ if (!isNonEmptyString(input.updatedAt) || !Array.isArray(input.events))
36
+ return undefined;
37
+ const identifiers = Array.isArray(input.identifier)
38
+ ? input.identifier.filter(isNonEmptyString)
39
+ : isNonEmptyString(input.identifier) ? [input.identifier] : [];
40
+ if (identifiers.length === 0)
41
+ return undefined;
42
+ const events = [];
43
+ for (const raw of input.events) {
44
+ if (!isRecord(raw) || typeof raw.id !== "number" || !Number.isInteger(raw.id) || raw.id < 1)
45
+ return undefined;
46
+ if (!isNonEmptyString(raw.type) || !isNonEmptyString(raw.effective) || !isNonEmptyString(raw.published))
47
+ return undefined;
48
+ const event = {
49
+ id: raw.id,
50
+ type: raw.type,
51
+ effective: raw.effective,
52
+ published: raw.published,
53
+ };
54
+ if (raw.versions !== undefined) {
55
+ if (!Array.isArray(raw.versions) || raw.versions.length === 0)
56
+ return undefined;
57
+ const versions = [];
58
+ for (const spec of raw.versions) {
59
+ if (!isRecord(spec) || !isNonEmptyString(spec.range))
60
+ return undefined;
61
+ versions.push({ range: spec.range });
62
+ }
63
+ event.versions = versions;
64
+ }
65
+ if (raw.description !== undefined) {
66
+ if (!isNonEmptyString(raw.description))
67
+ return undefined;
68
+ event.description = raw.description;
69
+ }
70
+ if (raw.references !== undefined) {
71
+ if (!Array.isArray(raw.references) || !raw.references.every(isNonEmptyString))
72
+ return undefined;
73
+ event.references = raw.references;
74
+ }
75
+ events.push(event);
76
+ }
77
+ return {
78
+ $schema: CLE_SCHEMA,
79
+ identifier: identifiers.length === 1 ? identifiers[0] : identifiers,
80
+ updatedAt: input.updatedAt,
81
+ events,
82
+ };
83
+ }
84
+ function deadlineOf(effective) {
85
+ const match = /^(\d{4}-\d{2}-\d{2})/.exec(effective);
86
+ return match?.[1];
87
+ }
88
+ /** True when the event's effective time is still in the future relative to the scan timestamp. */
89
+ function isScheduled(effective, scannedAt) {
90
+ const effectiveMs = Date.parse(effective);
91
+ const scannedMs = Date.parse(scannedAt);
92
+ if (!Number.isFinite(effectiveMs) || !Number.isFinite(scannedMs))
93
+ return false;
94
+ return effectiveMs > scannedMs;
95
+ }
96
+ function packagePurl(name) {
97
+ if (!name || name.startsWith(".") || name.includes("\\") || name.includes(".."))
98
+ return undefined;
99
+ try {
100
+ if (name.startsWith("@")) {
101
+ const slash = name.indexOf("/");
102
+ if (slash <= 1 || slash === name.length - 1)
103
+ return undefined;
104
+ return purlIdentity(`pkg:npm/${name.slice(1, slash)}/${name.slice(slash + 1)}`);
105
+ }
106
+ return purlIdentity(`pkg:npm/${name}`);
107
+ }
108
+ catch (error) {
109
+ if (error instanceof PurlError)
110
+ return undefined;
111
+ throw error;
112
+ }
113
+ }
114
+ function identifiersMatch(document, packageIdentity) {
115
+ const listed = Array.isArray(document.identifier) ? document.identifier : [document.identifier];
116
+ return listed.some((value) => {
117
+ try {
118
+ return purlIdentity(value) === packageIdentity;
119
+ }
120
+ catch (error) {
121
+ if (error instanceof PurlError)
122
+ return false;
123
+ throw error;
124
+ }
125
+ });
126
+ }
127
+ function eventApplies(event, version) {
128
+ if (!REPORTABLE.has(event.type))
129
+ return false;
130
+ if (!event.versions?.length)
131
+ return false;
132
+ return event.versions.some((spec) => {
133
+ try {
134
+ return versContains(spec.range, version);
135
+ }
136
+ catch {
137
+ return false;
138
+ }
139
+ });
140
+ }
141
+ function sourcesFor(clePath, event) {
142
+ const sources = [
143
+ { title: "Maintainer CLE declaration", url: pathToFileURL(clePath).href },
144
+ ];
145
+ for (const reference of event.references ?? []) {
146
+ if (/^https?:\/\//i.test(reference))
147
+ sources.push({ title: "CLE event reference", url: reference });
148
+ }
149
+ return sources;
150
+ }
151
+ function ruleIdFor(packageIdentity, event) {
152
+ const slug = packageIdentity.replace(/^pkg:/, "").replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-|-$/g, "");
153
+ return `cle.${event.type}.${slug}.${event.id}`;
154
+ }
155
+ function findingFor(root, clePath, packageIdentity, version, event, scannedAt) {
156
+ const type = event.type;
157
+ const path = relativePosix(root, clePath);
158
+ const deadline = deadlineOf(event.effective);
159
+ const scheduled = isScheduled(event.effective, scannedAt);
160
+ const title = scheduled
161
+ ? `${TITLE[type]} scheduled (maintainer CLE)`
162
+ : `${TITLE[type]} (maintainer CLE)`;
163
+ const detail = event.description?.trim() || `${packageIdentity}@${version} matches a maintainer-declared ${type} event.`;
164
+ const when = deadline
165
+ ? scheduled ? ` Scheduled for ${deadline}.` : ` Effective ${deadline}.`
166
+ : "";
167
+ const ruleId = ruleIdFor(packageIdentity, event);
168
+ return {
169
+ id: `${ruleId}:${path}:1`,
170
+ ruleId,
171
+ title,
172
+ summary: `${detail}${when}`,
173
+ severity: scheduled ? "low" : REACHED_SEVERITY[type],
174
+ location: { path, line: 1 },
175
+ ...(deadline ? { deadline } : {}),
176
+ sources: sourcesFor(clePath, event),
177
+ };
178
+ }
179
+ async function readJson(path) {
180
+ try {
181
+ return JSON.parse(await readFile(path, "utf8"));
182
+ }
183
+ catch (error) {
184
+ if (error.code === "ENOENT")
185
+ return undefined;
186
+ if (error instanceof SyntaxError)
187
+ return undefined;
188
+ throw error;
189
+ }
190
+ }
191
+ /**
192
+ * Installed packages that ship a parseable CLE document next to package.json.
193
+ * Reads `cle.json` first so ordinary packages cost one failed read; only then opens package.json.
194
+ */
195
+ async function clePackages(root) {
196
+ const found = [];
197
+ async function walkNodeModules(directory) {
198
+ let entries;
199
+ try {
200
+ entries = await readdir(directory, { withFileTypes: true });
201
+ }
202
+ catch {
203
+ return;
204
+ }
205
+ for (const entry of entries.sort((left, right) => left.name.localeCompare(right.name))) {
206
+ if (entry.isSymbolicLink() || SKIPPED_NODE_MODULES.has(entry.name))
207
+ continue;
208
+ if (!entry.isDirectory())
209
+ continue;
210
+ const path = join(directory, entry.name);
211
+ if (entry.name === ".pnpm") {
212
+ let stores;
213
+ try {
214
+ stores = await readdir(path, { withFileTypes: true });
215
+ }
216
+ catch {
217
+ continue;
218
+ }
219
+ for (const store of stores.sort((left, right) => left.name.localeCompare(right.name))) {
220
+ if (store.isSymbolicLink() || !store.isDirectory())
221
+ continue;
222
+ await walkNodeModules(join(path, store.name, "node_modules"));
223
+ }
224
+ continue;
225
+ }
226
+ if (entry.name.startsWith("@")) {
227
+ let scoped;
228
+ try {
229
+ scoped = await readdir(path, { withFileTypes: true });
230
+ }
231
+ catch {
232
+ continue;
233
+ }
234
+ for (const child of scoped.sort((left, right) => left.name.localeCompare(right.name))) {
235
+ if (child.isSymbolicLink() || !child.isDirectory())
236
+ continue;
237
+ await considerPackage(join(path, child.name));
238
+ }
239
+ continue;
240
+ }
241
+ await considerPackage(path);
242
+ }
243
+ }
244
+ async function considerPackage(directory) {
245
+ const clePath = join(directory, CLE_FILE_NAME);
246
+ const document = parseCleDocument(await readJson(clePath));
247
+ if (document) {
248
+ const manifest = await readJson(join(directory, "package.json"));
249
+ if (isRecord(manifest))
250
+ found.push({ directory, clePath, document, manifest });
251
+ }
252
+ await walkNodeModules(join(directory, "node_modules"));
253
+ }
254
+ await walkNodeModules(join(root, "node_modules"));
255
+ return found.sort((left, right) => left.directory.localeCompare(right.directory));
256
+ }
257
+ /** Findings from maintainer CLE documents shipped inside installed packages. Offline only. */
258
+ export async function ingestCle(root, options) {
259
+ const findings = [];
260
+ for (const { clePath, document, manifest } of await clePackages(root)) {
261
+ if (!isNonEmptyString(manifest.name) || !isNonEmptyString(manifest.version))
262
+ continue;
263
+ const packageIdentity = packagePurl(manifest.name);
264
+ if (!packageIdentity || !identifiersMatch(document, packageIdentity))
265
+ continue;
266
+ // CLE may include a version on the identifier; identity comparison already strips it.
267
+ try {
268
+ for (const value of Array.isArray(document.identifier) ? document.identifier : [document.identifier]) {
269
+ parsePurl(value);
270
+ }
271
+ }
272
+ catch (error) {
273
+ if (error instanceof PurlError)
274
+ continue;
275
+ throw error;
276
+ }
277
+ for (const event of document.events) {
278
+ if (!eventApplies(event, manifest.version))
279
+ continue;
280
+ findings.push(findingFor(root, clePath, packageIdentity, manifest.version, event, options.scannedAt));
281
+ }
282
+ }
283
+ return findings.sort((left, right) => left.id.localeCompare(right.id));
284
+ }
285
+ /** Reads CLE documents from installed packages during a repository scan. */
286
+ export class CleIngestDetector {
287
+ apiVersion = DETECTOR_API_VERSION;
288
+ id = "cle";
289
+ inputs = {
290
+ fileNames: [CLE_FILE_NAME, "package.json"],
291
+ directories: ["node_modules"],
292
+ };
293
+ async scan(context) {
294
+ // The engine always passes scannedAt. Harnesses that call scan({ root }) omit it; without a
295
+ // timestamp every matching event is treated as reached so we never read the clock here.
296
+ return ingestCle(context.root, { scannedAt: context.scannedAt ?? "9999-12-31T23:59:59.999Z" });
297
+ }
298
+ }
299
+ export const cleDetector = new CleIngestDetector();
300
+ //# sourceMappingURL=cle-ingest.js.map
package/dist/src/cli.js CHANGED
@@ -15,6 +15,7 @@ import { AgentFileError } from "./agent-instructions.js";
15
15
  import { configureActiveData, DataPinError, getActiveData } from "./data-source.js";
16
16
  import { DataUpdateError, renderDataUpdateText, updateData } from "./data-update.js";
17
17
  import { getDataStatus, renderDataStatusText } from "./data-status.js";
18
+ import { guardCommand, GuardUsageError } from "./guard.js";
18
19
  import { initAgents } from "./init-agents.js";
19
20
  import { initHooks } from "./init-hooks.js";
20
21
  import { hasPersonalConfig, initPersonal } from "./init-personal.js";
@@ -32,17 +33,20 @@ import { readPinnedRuntimes } from "./runtime-pin.js";
32
33
  import { DiffError, diffRefs, renderDiffText } from "./diff.js";
33
34
  import { groupScanByOwner, renderOwnerGroupsText } from "./codeowners.js";
34
35
  import { RollupError, renderRollupText, rollupFiles } from "./rollup.js";
36
+ import { buildRenovatePreset } from "./renovate-preset.js";
35
37
  import { diagnoseEnvironment, renderDoctorText } from "./doctor.js";
36
38
  import { createIssueReport, ReportIssueError } from "./report-issue.js";
37
- import { renderCheckText, renderCodeQuality, renderCompact, renderFindingText, renderHtml, renderJson, renderMigrationPacketText, renderRdjson, renderSarif, renderText } from "./reporters.js";
39
+ import { renderCheckText, renderCodeQuality, renderCompact, renderFindingText, renderHtml, renderJson, renderJunit, renderMarkdown, renderMigrationPacketText, renderRdjson, renderSarif, renderSlack, renderTeams, renderText, renderWebhook } from "./reporters.js";
38
40
  import { STATUS_FILE_NAME, writeStatusFile } from "./status-file.js";
39
41
  import { browseFindings, canBrowse } from "./tui.js";
40
42
  import { VERSION } from "./version.js";
43
+ import { exportActiveCle } from "./export/cle.js";
44
+ import { CycloneDxError, enrichCycloneDxFile } from "./sbom/cyclonedx.js";
41
45
  import { addWatched, listWatched, removeWatched, renderWatchText, runWatch } from "./watch.js";
42
46
  const HELP = `Evergreen — local-first deprecation intelligence
43
47
 
44
48
  Usage:
45
- evergreen scan [path] [--json | --format <text|json|sarif|rdjson|codequality|compact|html>]
49
+ evergreen scan [path] [--json | --format <text|json|markdown|junit|sarif|rdjson|codequality|compact|html|slack|teams|webhook>]
46
50
  evergreen scan [path] --baseline <file> [--baseline-warn-days <n>] [--on-expired resurface|fail] [--today <YYYY-MM-DD>] [--json]
47
51
  evergreen scan [path] --as-of <YYYY-MM-DD> [--json] # scan as the world will look on a date; --today is an alias
48
52
  evergreen scan [path] --min-support-days <n> # warn on lines whose support ends within n days
@@ -54,13 +58,17 @@ Usage:
54
58
  evergreen diff <base>..<head> [path] [--json] # findings a change introduced or fixed; exit 1 only when it introduced some
55
59
  evergreen scan [path] --by-owner [--json] # group findings by CODEOWNERS owner; files with no owner are listed as unowned
56
60
  evergreen rollup <report.json>... [--owners <file>] [--json] # merge saved scan reports by product and owner; reads files only
61
+ evergreen renovate-preset [path] # print Renovate packageRules for replacements and runtime pins; does not edit config
57
62
  evergreen fix [path] [--dry-run] # print patches for deterministic fixes; nothing is written
58
63
  evergreen fix [path] --branch # apply the fixes on a local evergreen/fix branch and commit; never pushes
59
64
  evergreen baseline [path] [--output <file>]
60
65
  evergreen check <purl> [--fail-on <severity|none>] [--json]
66
+ evergreen guard [--fail-on <severity|none>] [--force] npm install <package>... # check first; flags after npm go to npm
61
67
  evergreen usage [--file <path>] [--json]
62
68
  evergreen mcp
63
69
  evergreen data status [--json]
70
+ evergreen export --format cle [--data-version <version>] # CLE 1.0 snapshots, one JSON document per line and component; skipped rules reported on stderr
71
+ evergreen sbom enrich <bom.json> [--data-version <version>] # print enriched CycloneDX JSON; leaves the input unchanged
64
72
  evergreen watch add|remove <path> # register a project for the digest
65
73
  evergreen watch [run] [--weekly] [--json] # re-scan registered projects, print only what changed
66
74
  evergreen watch list [--json]
@@ -360,7 +368,7 @@ async function main(args) {
360
368
  return 0;
361
369
  }
362
370
  const [command] = args;
363
- if (command !== "scan" && command !== "check" && command !== "data" && command !== "new-detector" && command !== "init" && command !== "setup" && command !== "usage" && command !== "mcp" && command !== "explain" && command !== "context" && command !== "baseline" && command !== "forecast" && command !== "diff" && command !== "rollup" && command !== "fix" && command !== "doctor" && command !== "report-issue" && command !== "capabilities" && command !== "watch" && command !== "completions") {
371
+ if (command !== "sbom" && command !== "export" && command !== "scan" && command !== "check" && command !== "guard" && command !== "data" && command !== "new-detector" && command !== "init" && command !== "setup" && command !== "usage" && command !== "mcp" && command !== "explain" && command !== "context" && command !== "baseline" && command !== "forecast" && command !== "diff" && command !== "rollup" && command !== "renovate-preset" && command !== "fix" && command !== "doctor" && command !== "report-issue" && command !== "capabilities" && command !== "watch" && command !== "completions") {
364
372
  return fail("usage", `Unknown command: ${command ?? ""}`, `\n${HELP}`);
365
373
  }
366
374
  if (command === "mcp") {
@@ -402,19 +410,60 @@ async function main(args) {
402
410
  }
403
411
  const formatIndex = args.indexOf("--format");
404
412
  const format = formatIndex === -1 ? undefined : args[formatIndex + 1];
405
- if (formatIndex !== -1 && format !== "text" && format !== "json" && format !== "sarif" && format !== "rdjson" && format !== "codequality" && format !== "compact" && format !== "html") {
406
- return fail("usage", `Unknown format: ${format ?? ""} (expected text, json, sarif, rdjson, codequality, compact, or html).`);
413
+ if (command === "sbom") {
414
+ const operands = args.slice(1).filter((_, index) => dataVersionIndex === -1 ||
415
+ (index + 1 !== dataVersionIndex && index + 1 !== dataVersionIndex + 1));
416
+ if (operands.length !== 2 || operands[0] !== "enrich" || operands[1].startsWith("-")) {
417
+ return fail("usage", "Usage: evergreen sbom enrich <bom.json> [--data-version <version>]");
418
+ }
419
+ try {
420
+ const bom = await enrichCycloneDxFile(operands[1]);
421
+ process.stdout.write(`${JSON.stringify(bom, null, 2)}\n`);
422
+ return 0;
423
+ }
424
+ catch (error) {
425
+ if (error instanceof CycloneDxError)
426
+ return fail("parse", error.message);
427
+ throw error;
428
+ }
429
+ }
430
+ if (command === "export") {
431
+ const operands = args.slice(1).filter((_, index) => index + 1 !== formatIndex && index + 1 !== formatIndex + 1 &&
432
+ (dataVersionIndex === -1 || (index + 1 !== dataVersionIndex && index + 1 !== dataVersionIndex + 1)));
433
+ if (format !== "cle" || operands.length > 0) {
434
+ return fail("usage", "Usage: evergreen export --format cle [--data-version <version>]");
435
+ }
436
+ const result = await exportActiveCle();
437
+ for (const document of result.documents)
438
+ process.stdout.write(`${JSON.stringify(document)}\n`);
439
+ if (result.skipped > 0)
440
+ process.stderr.write(`Skipped ${result.skipped} rules: CLE requires a dated component lifecycle event; deprecation, removal, symbol rules, and undated rules cannot be faithfully represented.\n`);
441
+ return 0;
442
+ }
443
+ if (formatIndex !== -1 && format !== "text" && format !== "json" && format !== "markdown" && format !== "junit" && format !== "sarif" && format !== "rdjson" && format !== "codequality" && format !== "compact" && format !== "html" && format !== "slack" && format !== "teams" && format !== "webhook") {
444
+ return fail("usage", `Unknown format: ${format ?? ""} (expected text, json, markdown, junit, sarif, rdjson, codequality, compact, html, slack, teams, or webhook).`);
407
445
  }
408
446
  if (command === "check" && format !== undefined && format !== "json" && format !== "text") {
409
447
  return fail("usage", "check supports --json and --format text|json only.");
410
448
  }
411
- if ((format === "sarif" || format === "rdjson" || format === "codequality" || format === "compact" || format === "html") && command !== "scan") {
449
+ if ((format === "markdown" || format === "junit" || format === "sarif" || format === "rdjson" || format === "codequality" || format === "compact" || format === "html" || format === "slack" || format === "teams" || format === "webhook") && command !== "scan") {
412
450
  return fail("usage", `--format ${format} is only available for the scan command.`);
413
451
  }
414
452
  const json = args.includes("--json") || format === "json";
415
453
  if (args.includes("--write-status") && command !== "scan") {
416
454
  return fail("usage", "--write-status is only available for the scan command.");
417
455
  }
456
+ if (command === "guard") {
457
+ try {
458
+ const result = await guardCommand(args.slice(1), { report: (output) => process.stderr.write(`${output}\n`) });
459
+ return result.exitCode;
460
+ }
461
+ catch (error) {
462
+ if (error instanceof GuardUsageError)
463
+ return fail("usage", error.message);
464
+ throw error;
465
+ }
466
+ }
418
467
  if (command === "watch")
419
468
  return watch(args.slice(1), json);
420
469
  if (command === "capabilities") {
@@ -513,6 +562,14 @@ async function main(args) {
513
562
  throw error;
514
563
  }
515
564
  }
565
+ if (command === "renovate-preset") {
566
+ if (positional.length > 1)
567
+ return fail("usage", "Usage: evergreen renovate-preset [path]");
568
+ const result = await scanRepository(resolve(pathArgument), builtInDetectors);
569
+ const preset = buildRenovatePreset(result.findings, await bundledRules());
570
+ process.stdout.write(`${JSON.stringify(preset, null, 2)}\n`);
571
+ return 0;
572
+ }
516
573
  if (command === "diff") {
517
574
  const range = positional[0];
518
575
  if (!range)
@@ -693,7 +750,7 @@ async function main(args) {
693
750
  process.stdout.write(`${json ? JSON.stringify(groups, null, 2) : renderOwnerGroupsText(groups)}\n`);
694
751
  }
695
752
  else {
696
- const output = format === "sarif" ? renderSarif(result) : format === "rdjson" ? renderRdjson(result) : format === "codequality" ? renderCodeQuality(result) : format === "compact" ? renderCompact(result) : format === "html" ? renderHtml(result) : json ? renderJson(result) : renderText(result, { firstRun: command === "scan" && !(await hasPersonalConfig()) });
753
+ const output = format === "sarif" ? renderSarif(result) : format === "rdjson" ? renderRdjson(result) : format === "codequality" ? renderCodeQuality(result) : format === "compact" ? renderCompact(result) : format === "html" ? renderHtml(result) : format === "markdown" ? renderMarkdown(result) : format === "junit" ? renderJunit(result) : format === "slack" ? renderSlack(result) : format === "teams" ? renderTeams(result) : format === "webhook" ? renderWebhook(result) : json ? renderJson(result) : renderText(result, { firstRun: command === "scan" && !(await hasPersonalConfig()) });
697
754
  process.stdout.write(`${output}\n`);
698
755
  if (args.includes("--write-status")) {
699
756
  const statusRoot = resolve(pathArgument);
@@ -6,8 +6,10 @@ export const COMMANDS = [
6
6
  { name: "forecast", flags: ["--months", "--as-of", "--today", "--json", "--data-version"], example: "evergreen forecast . --months 6" },
7
7
  { name: "diff", flags: ["--json", "--data-version"], example: "evergreen diff main..HEAD" },
8
8
  { name: "rollup", flags: ["--owners", "--json"], example: "evergreen rollup reports/*.json --owners owners.json" },
9
+ { name: "renovate-preset", flags: ["--data-version"], example: "evergreen renovate-preset ." },
9
10
  { name: "fix", flags: ["--dry-run", "--data-version"], example: "evergreen fix . --dry-run" },
10
11
  { name: "check", flags: ["--fail-on", "--json", "--format", "--data-version"], example: "evergreen check pkg:npm/request@2.88.2" },
12
+ { name: "guard", flags: ["--fail-on", "--force", "--data-version"], example: "evergreen guard npm install request" },
11
13
  { name: "usage", flags: ["--file", "--json"], example: "evergreen usage --json" },
12
14
  { name: "mcp", flags: [], example: "evergreen mcp" },
13
15
  { name: "data", flags: ["--json", "--data-version"], example: "evergreen data status" },
@@ -1,6 +1,6 @@
1
1
  export declare const DATA_BUNDLE_SCHEMA_VERSION: "evergreen.data-bundle.v1";
2
2
  /** The registries a bundle carries, in the order they are listed. The SHA map is carried as kind "sha-map". */
3
- export declare const BUNDLED_ECOSYSTEMS: readonly ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "python", "ruby", "rust", "serverless", "shell", "swift", "terraform"];
3
+ export declare const BUNDLED_ECOSYSTEMS: readonly ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "osv", "python", "ruby", "rust", "serverless", "shell", "swift", "terraform"];
4
4
  /**
5
5
  * Who may sign a data bundle: the keyless Sigstore certificate must carry this OIDC issuer and an identity
6
6
  * (the signing workflow's ref) that matches the pattern. The pattern names the repository, the workflow file, and
@@ -4,7 +4,7 @@ import { resolve } from "node:path";
4
4
  import { DEFAULT_MAX_REVIEW_AGE_DAYS, validateRegistryV2 } from "./registry.js";
5
5
  export const DATA_BUNDLE_SCHEMA_VERSION = "evergreen.data-bundle.v1";
6
6
  /** The registries a bundle carries, in the order they are listed. The SHA map is carried as kind "sha-map". */
7
- export const BUNDLED_ECOSYSTEMS = ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "python", "ruby", "rust", "serverless", "shell", "swift", "terraform"];
7
+ export const BUNDLED_ECOSYSTEMS = ["android", "ci-images", "container", "cpp", "dart", "database", "dotnet", "github-actions", "go", "java", "kubernetes", "nodejs", "npm", "osv", "python", "ruby", "rust", "serverless", "shell", "swift", "terraform"];
8
8
  const SHA_MAP_PATH = "registry/github-actions-shas.json";
9
9
  /**
10
10
  * Who may sign a data bundle: the keyless Sigstore certificate must carry this OIDC issuer and an identity