sandstream-kit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (519) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +617 -0
  3. package/dist/adapters/api-key-adapter.d.ts +35 -0
  4. package/dist/adapters/api-key-adapter.js +46 -0
  5. package/dist/adapters/api-key-adapter.js.map +1 -0
  6. package/dist/adapters/clerk-auth.d.ts +6 -0
  7. package/dist/adapters/clerk-auth.js +20 -0
  8. package/dist/adapters/clerk-auth.js.map +1 -0
  9. package/dist/adapters/cloudflare-r2.d.ts +6 -0
  10. package/dist/adapters/cloudflare-r2.js +136 -0
  11. package/dist/adapters/cloudflare-r2.js.map +1 -0
  12. package/dist/adapters/expo-eas.d.ts +6 -0
  13. package/dist/adapters/expo-eas.js +129 -0
  14. package/dist/adapters/expo-eas.js.map +1 -0
  15. package/dist/adapters/flagsmith-flags.d.ts +5 -0
  16. package/dist/adapters/flagsmith-flags.js +20 -0
  17. package/dist/adapters/flagsmith-flags.js.map +1 -0
  18. package/dist/adapters/flyio-hosting.d.ts +2 -0
  19. package/dist/adapters/flyio-hosting.js +143 -0
  20. package/dist/adapters/flyio-hosting.js.map +1 -0
  21. package/dist/adapters/index.d.ts +6 -0
  22. package/dist/adapters/index.js +48 -0
  23. package/dist/adapters/index.js.map +1 -0
  24. package/dist/adapters/inngest-background.d.ts +5 -0
  25. package/dist/adapters/inngest-background.js +19 -0
  26. package/dist/adapters/inngest-background.js.map +1 -0
  27. package/dist/adapters/liveblocks-realtime.d.ts +11 -0
  28. package/dist/adapters/liveblocks-realtime.js +62 -0
  29. package/dist/adapters/liveblocks-realtime.js.map +1 -0
  30. package/dist/adapters/loops-email.d.ts +6 -0
  31. package/dist/adapters/loops-email.js +18 -0
  32. package/dist/adapters/loops-email.js.map +1 -0
  33. package/dist/adapters/neon-db.d.ts +10 -0
  34. package/dist/adapters/neon-db.js +94 -0
  35. package/dist/adapters/neon-db.js.map +1 -0
  36. package/dist/adapters/planetscale-db.d.ts +11 -0
  37. package/dist/adapters/planetscale-db.js +134 -0
  38. package/dist/adapters/planetscale-db.js.map +1 -0
  39. package/dist/adapters/posthog-analytics.d.ts +6 -0
  40. package/dist/adapters/posthog-analytics.js +22 -0
  41. package/dist/adapters/posthog-analytics.js.map +1 -0
  42. package/dist/adapters/railway-hosting.d.ts +2 -0
  43. package/dist/adapters/railway-hosting.js +136 -0
  44. package/dist/adapters/railway-hosting.js.map +1 -0
  45. package/dist/adapters/resend-email.d.ts +35 -0
  46. package/dist/adapters/resend-email.js +109 -0
  47. package/dist/adapters/resend-email.js.map +1 -0
  48. package/dist/adapters/searxng-instance.d.ts +6 -0
  49. package/dist/adapters/searxng-instance.js +240 -0
  50. package/dist/adapters/searxng-instance.js.map +1 -0
  51. package/dist/adapters/sentry-monitoring.d.ts +7 -0
  52. package/dist/adapters/sentry-monitoring.js +27 -0
  53. package/dist/adapters/sentry-monitoring.js.map +1 -0
  54. package/dist/adapters/stripe-payments.d.ts +6 -0
  55. package/dist/adapters/stripe-payments.js +134 -0
  56. package/dist/adapters/stripe-payments.js.map +1 -0
  57. package/dist/adapters/supabase-db.d.ts +6 -0
  58. package/dist/adapters/supabase-db.js +130 -0
  59. package/dist/adapters/supabase-db.js.map +1 -0
  60. package/dist/adapters/tinybird-analytics.d.ts +5 -0
  61. package/dist/adapters/tinybird-analytics.js +20 -0
  62. package/dist/adapters/tinybird-analytics.js.map +1 -0
  63. package/dist/adapters/trigger-background.d.ts +6 -0
  64. package/dist/adapters/trigger-background.js +20 -0
  65. package/dist/adapters/trigger-background.js.map +1 -0
  66. package/dist/adapters/types.d.ts +7 -0
  67. package/dist/adapters/types.js +2 -0
  68. package/dist/adapters/types.js.map +1 -0
  69. package/dist/adapters/upstash-redis.d.ts +6 -0
  70. package/dist/adapters/upstash-redis.js +88 -0
  71. package/dist/adapters/upstash-redis.js.map +1 -0
  72. package/dist/adapters/vercel-hosting.d.ts +6 -0
  73. package/dist/adapters/vercel-hosting.js +112 -0
  74. package/dist/adapters/vercel-hosting.js.map +1 -0
  75. package/dist/agent-adapter-model.d.ts +108 -0
  76. package/dist/agent-adapter-model.js +6 -0
  77. package/dist/agent-adapter-model.js.map +1 -0
  78. package/dist/agent-adapter-service.d.ts +67 -0
  79. package/dist/agent-adapter-service.js +299 -0
  80. package/dist/agent-adapter-service.js.map +1 -0
  81. package/dist/agent-config.d.ts +56 -0
  82. package/dist/agent-config.js +129 -0
  83. package/dist/agent-config.js.map +1 -0
  84. package/dist/agent-governance-model.d.ts +128 -0
  85. package/dist/agent-governance-model.js +6 -0
  86. package/dist/agent-governance-model.js.map +1 -0
  87. package/dist/agent-governance-service.d.ts +101 -0
  88. package/dist/agent-governance-service.js +319 -0
  89. package/dist/agent-governance-service.js.map +1 -0
  90. package/dist/alert-rules-engine.d.ts +102 -0
  91. package/dist/alert-rules-engine.js +210 -0
  92. package/dist/alert-rules-engine.js.map +1 -0
  93. package/dist/analytics-service.d.ts +126 -0
  94. package/dist/analytics-service.js +318 -0
  95. package/dist/analytics-service.js.map +1 -0
  96. package/dist/analyze.d.ts +19 -0
  97. package/dist/analyze.js +311 -0
  98. package/dist/analyze.js.map +1 -0
  99. package/dist/apm-instrumentor.d.ts +119 -0
  100. package/dist/apm-instrumentor.js +225 -0
  101. package/dist/apm-instrumentor.js.map +1 -0
  102. package/dist/approval-model.d.ts +82 -0
  103. package/dist/approval-model.js +6 -0
  104. package/dist/approval-model.js.map +1 -0
  105. package/dist/approval-service.d.ts +39 -0
  106. package/dist/approval-service.js +236 -0
  107. package/dist/approval-service.js.map +1 -0
  108. package/dist/approval.d.ts +22 -0
  109. package/dist/approval.js +148 -0
  110. package/dist/approval.js.map +1 -0
  111. package/dist/audit-logging-model.d.ts +157 -0
  112. package/dist/audit-logging-model.js +6 -0
  113. package/dist/audit-logging-model.js.map +1 -0
  114. package/dist/audit-logging-service.d.ts +89 -0
  115. package/dist/audit-logging-service.js +367 -0
  116. package/dist/audit-logging-service.js.map +1 -0
  117. package/dist/audit-secrets.d.ts +42 -0
  118. package/dist/audit-secrets.js +126 -0
  119. package/dist/audit-secrets.js.map +1 -0
  120. package/dist/audit.d.ts +43 -0
  121. package/dist/audit.js +286 -0
  122. package/dist/audit.js.map +1 -0
  123. package/dist/author-dashboard.d.ts +84 -0
  124. package/dist/author-dashboard.js +204 -0
  125. package/dist/author-dashboard.js.map +1 -0
  126. package/dist/author-notifications.d.ts +130 -0
  127. package/dist/author-notifications.js +261 -0
  128. package/dist/author-notifications.js.map +1 -0
  129. package/dist/author-verification.d.ts +79 -0
  130. package/dist/author-verification.js +257 -0
  131. package/dist/author-verification.js.map +1 -0
  132. package/dist/autonomous-setup-model.d.ts +117 -0
  133. package/dist/autonomous-setup-model.js +6 -0
  134. package/dist/autonomous-setup-model.js.map +1 -0
  135. package/dist/autonomous-setup-service.d.ts +74 -0
  136. package/dist/autonomous-setup-service.js +325 -0
  137. package/dist/autonomous-setup-service.js.map +1 -0
  138. package/dist/badge-system.d.ts +70 -0
  139. package/dist/badge-system.js +210 -0
  140. package/dist/badge-system.js.map +1 -0
  141. package/dist/baseline.d.ts +34 -0
  142. package/dist/baseline.js +78 -0
  143. package/dist/baseline.js.map +1 -0
  144. package/dist/beta-program-service.d.ts +112 -0
  145. package/dist/beta-program-service.js +240 -0
  146. package/dist/beta-program-service.js.map +1 -0
  147. package/dist/budget.d.ts +34 -0
  148. package/dist/budget.js +159 -0
  149. package/dist/budget.js.map +1 -0
  150. package/dist/bumblebee.d.ts +143 -0
  151. package/dist/bumblebee.js +384 -0
  152. package/dist/bumblebee.js.map +1 -0
  153. package/dist/cache-manager.d.ts +97 -0
  154. package/dist/cache-manager.js +244 -0
  155. package/dist/cache-manager.js.map +1 -0
  156. package/dist/cdn-adapter.d.ts +64 -0
  157. package/dist/cdn-adapter.js +263 -0
  158. package/dist/cdn-adapter.js.map +1 -0
  159. package/dist/certification-workflow-model.d.ts +95 -0
  160. package/dist/certification-workflow-model.js +6 -0
  161. package/dist/certification-workflow-model.js.map +1 -0
  162. package/dist/certification-workflow-service.d.ts +72 -0
  163. package/dist/certification-workflow-service.js +305 -0
  164. package/dist/certification-workflow-service.js.map +1 -0
  165. package/dist/check-design.d.ts +38 -0
  166. package/dist/check-design.js +256 -0
  167. package/dist/check-design.js.map +1 -0
  168. package/dist/check-gitignore.d.ts +39 -0
  169. package/dist/check-gitignore.js +156 -0
  170. package/dist/check-gitignore.js.map +1 -0
  171. package/dist/check-hooks.d.ts +15 -0
  172. package/dist/check-hooks.js +72 -0
  173. package/dist/check-hooks.js.map +1 -0
  174. package/dist/check-lock.d.ts +16 -0
  175. package/dist/check-lock.js +94 -0
  176. package/dist/check-lock.js.map +1 -0
  177. package/dist/check-secrets.d.ts +11 -0
  178. package/dist/check-secrets.js +320 -0
  179. package/dist/check-secrets.js.map +1 -0
  180. package/dist/check-security.d.ts +13 -0
  181. package/dist/check-security.js +887 -0
  182. package/dist/check-security.js.map +1 -0
  183. package/dist/check-services.d.ts +10 -0
  184. package/dist/check-services.js +44 -0
  185. package/dist/check-services.js.map +1 -0
  186. package/dist/check-skills.d.ts +8 -0
  187. package/dist/check-skills.js +26 -0
  188. package/dist/check-skills.js.map +1 -0
  189. package/dist/check-tests.d.ts +43 -0
  190. package/dist/check-tests.js +175 -0
  191. package/dist/check-tests.js.map +1 -0
  192. package/dist/check-tools.d.ts +8 -0
  193. package/dist/check-tools.js +42 -0
  194. package/dist/check-tools.js.map +1 -0
  195. package/dist/check-web-search.d.ts +12 -0
  196. package/dist/check-web-search.js +168 -0
  197. package/dist/check-web-search.js.map +1 -0
  198. package/dist/ci-cd-publisher.d.ts +162 -0
  199. package/dist/ci-cd-publisher.js +319 -0
  200. package/dist/ci-cd-publisher.js.map +1 -0
  201. package/dist/cli.d.ts +2 -0
  202. package/dist/cli.js +4074 -0
  203. package/dist/cli.js.map +1 -0
  204. package/dist/clone.d.ts +25 -0
  205. package/dist/clone.js +73 -0
  206. package/dist/clone.js.map +1 -0
  207. package/dist/completions.d.ts +8 -0
  208. package/dist/completions.js +250 -0
  209. package/dist/completions.js.map +1 -0
  210. package/dist/compression-manager.d.ts +107 -0
  211. package/dist/compression-manager.js +250 -0
  212. package/dist/compression-manager.js.map +1 -0
  213. package/dist/config.d.ts +233 -0
  214. package/dist/config.js +255 -0
  215. package/dist/config.js.map +1 -0
  216. package/dist/context.d.ts +38 -0
  217. package/dist/context.js +86 -0
  218. package/dist/context.js.map +1 -0
  219. package/dist/cost-monitor.d.ts +72 -0
  220. package/dist/cost-monitor.js +218 -0
  221. package/dist/cost-monitor.js.map +1 -0
  222. package/dist/create-plugin.d.ts +22 -0
  223. package/dist/create-plugin.js +266 -0
  224. package/dist/create-plugin.js.map +1 -0
  225. package/dist/database.d.ts +123 -0
  226. package/dist/database.js +354 -0
  227. package/dist/database.js.map +1 -0
  228. package/dist/datadog-adapter.d.ts +60 -0
  229. package/dist/datadog-adapter.js +245 -0
  230. package/dist/datadog-adapter.js.map +1 -0
  231. package/dist/doctor.d.ts +15 -0
  232. package/dist/doctor.js +131 -0
  233. package/dist/doctor.js.map +1 -0
  234. package/dist/documentation-generator.d.ts +226 -0
  235. package/dist/documentation-generator.js +348 -0
  236. package/dist/documentation-generator.js.map +1 -0
  237. package/dist/elevation-scopes.d.ts +40 -0
  238. package/dist/elevation-scopes.js +110 -0
  239. package/dist/elevation-scopes.js.map +1 -0
  240. package/dist/elevation.d.ts +102 -0
  241. package/dist/elevation.js +449 -0
  242. package/dist/elevation.js.map +1 -0
  243. package/dist/env-diff.d.ts +27 -0
  244. package/dist/env-diff.js +104 -0
  245. package/dist/env-diff.js.map +1 -0
  246. package/dist/env-inspect.d.ts +28 -0
  247. package/dist/env-inspect.js +81 -0
  248. package/dist/env-inspect.js.map +1 -0
  249. package/dist/env-switch.d.ts +37 -0
  250. package/dist/env-switch.js +102 -0
  251. package/dist/env-switch.js.map +1 -0
  252. package/dist/environment.d.ts +27 -0
  253. package/dist/environment.js +148 -0
  254. package/dist/environment.js.map +1 -0
  255. package/dist/error-tracker.d.ts +92 -0
  256. package/dist/error-tracker.js +206 -0
  257. package/dist/error-tracker.js.map +1 -0
  258. package/dist/escalate.d.ts +11 -0
  259. package/dist/escalate.js +73 -0
  260. package/dist/escalate.js.map +1 -0
  261. package/dist/event-stream.d.ts +81 -0
  262. package/dist/event-stream.js +161 -0
  263. package/dist/event-stream.js.map +1 -0
  264. package/dist/fix.d.ts +42 -0
  265. package/dist/fix.js +419 -0
  266. package/dist/fix.js.map +1 -0
  267. package/dist/governance-middleware.d.ts +22 -0
  268. package/dist/governance-middleware.js +173 -0
  269. package/dist/governance-middleware.js.map +1 -0
  270. package/dist/governance.d.ts +44 -0
  271. package/dist/governance.js +236 -0
  272. package/dist/governance.js.map +1 -0
  273. package/dist/hooks.d.ts +25 -0
  274. package/dist/hooks.js +281 -0
  275. package/dist/hooks.js.map +1 -0
  276. package/dist/id-generator.d.ts +43 -0
  277. package/dist/id-generator.js +47 -0
  278. package/dist/id-generator.js.map +1 -0
  279. package/dist/image-optimizer.d.ts +92 -0
  280. package/dist/image-optimizer.js +202 -0
  281. package/dist/image-optimizer.js.map +1 -0
  282. package/dist/install.d.ts +15 -0
  283. package/dist/install.js +59 -0
  284. package/dist/install.js.map +1 -0
  285. package/dist/lock.d.ts +82 -0
  286. package/dist/lock.js +264 -0
  287. package/dist/lock.js.map +1 -0
  288. package/dist/login.d.ts +23 -0
  289. package/dist/login.js +132 -0
  290. package/dist/login.js.map +1 -0
  291. package/dist/mcp-kit-tools-model.d.ts +195 -0
  292. package/dist/mcp-kit-tools-model.js +6 -0
  293. package/dist/mcp-kit-tools-model.js.map +1 -0
  294. package/dist/mcp-kit-tools-service.d.ts +127 -0
  295. package/dist/mcp-kit-tools-service.js +943 -0
  296. package/dist/mcp-kit-tools-service.js.map +1 -0
  297. package/dist/mcp-orchestrator.d.ts +70 -0
  298. package/dist/mcp-orchestrator.js +175 -0
  299. package/dist/mcp-orchestrator.js.map +1 -0
  300. package/dist/mcp-server.d.ts +3 -0
  301. package/dist/mcp-server.js +722 -0
  302. package/dist/mcp-server.js.map +1 -0
  303. package/dist/middleware/rate-limiter.d.ts +74 -0
  304. package/dist/middleware/rate-limiter.js +342 -0
  305. package/dist/middleware/rate-limiter.js.map +1 -0
  306. package/dist/migration-runner.d.ts +66 -0
  307. package/dist/migration-runner.js +192 -0
  308. package/dist/migration-runner.js.map +1 -0
  309. package/dist/migrations.d.ts +25 -0
  310. package/dist/migrations.js +530 -0
  311. package/dist/migrations.js.map +1 -0
  312. package/dist/moderation-system.d.ts +153 -0
  313. package/dist/moderation-system.js +338 -0
  314. package/dist/moderation-system.js.map +1 -0
  315. package/dist/multi-agent-workflow-model.d.ts +125 -0
  316. package/dist/multi-agent-workflow-model.js +6 -0
  317. package/dist/multi-agent-workflow-model.js.map +1 -0
  318. package/dist/multi-agent-workflow-service.d.ts +102 -0
  319. package/dist/multi-agent-workflow-service.js +452 -0
  320. package/dist/multi-agent-workflow-service.js.map +1 -0
  321. package/dist/onepassword.d.ts +75 -0
  322. package/dist/onepassword.js +140 -0
  323. package/dist/onepassword.js.map +1 -0
  324. package/dist/open.d.ts +30 -0
  325. package/dist/open.js +166 -0
  326. package/dist/open.js.map +1 -0
  327. package/dist/output.d.ts +32 -0
  328. package/dist/output.js +295 -0
  329. package/dist/output.js.map +1 -0
  330. package/dist/partner-service.d.ts +101 -0
  331. package/dist/partner-service.js +191 -0
  332. package/dist/partner-service.js.map +1 -0
  333. package/dist/payout-service.d.ts +136 -0
  334. package/dist/payout-service.js +293 -0
  335. package/dist/payout-service.js.map +1 -0
  336. package/dist/pkg.d.ts +30 -0
  337. package/dist/pkg.js +162 -0
  338. package/dist/pkg.js.map +1 -0
  339. package/dist/plugin-loader.d.ts +16 -0
  340. package/dist/plugin-loader.js +124 -0
  341. package/dist/plugin-loader.js.map +1 -0
  342. package/dist/plugin-registry-model.d.ts +133 -0
  343. package/dist/plugin-registry-model.js +6 -0
  344. package/dist/plugin-registry-model.js.map +1 -0
  345. package/dist/plugin-registry-service.d.ts +109 -0
  346. package/dist/plugin-registry-service.js +361 -0
  347. package/dist/plugin-registry-service.js.map +1 -0
  348. package/dist/plugin-registry.d.ts +58 -0
  349. package/dist/plugin-registry.js +108 -0
  350. package/dist/plugin-registry.js.map +1 -0
  351. package/dist/plugin-updates.d.ts +135 -0
  352. package/dist/plugin-updates.js +326 -0
  353. package/dist/plugin-updates.js.map +1 -0
  354. package/dist/plugins-cli.d.ts +7 -0
  355. package/dist/plugins-cli.js +157 -0
  356. package/dist/plugins-cli.js.map +1 -0
  357. package/dist/plugins.d.ts +88 -0
  358. package/dist/plugins.js +251 -0
  359. package/dist/plugins.js.map +1 -0
  360. package/dist/policy.d.ts +66 -0
  361. package/dist/policy.js +160 -0
  362. package/dist/policy.js.map +1 -0
  363. package/dist/post-pull-audit.d.ts +39 -0
  364. package/dist/post-pull-audit.js +151 -0
  365. package/dist/post-pull-audit.js.map +1 -0
  366. package/dist/provision.d.ts +17 -0
  367. package/dist/provision.js +147 -0
  368. package/dist/provision.js.map +1 -0
  369. package/dist/query-optimizer.d.ts +102 -0
  370. package/dist/query-optimizer.js +199 -0
  371. package/dist/query-optimizer.js.map +1 -0
  372. package/dist/read-only-mode.d.ts +46 -0
  373. package/dist/read-only-mode.js +71 -0
  374. package/dist/read-only-mode.js.map +1 -0
  375. package/dist/redis-adapter.d.ts +71 -0
  376. package/dist/redis-adapter.js +278 -0
  377. package/dist/redis-adapter.js.map +1 -0
  378. package/dist/resilience-tests.d.ts +120 -0
  379. package/dist/resilience-tests.js +293 -0
  380. package/dist/resilience-tests.js.map +1 -0
  381. package/dist/revocation.d.ts +22 -0
  382. package/dist/revocation.js +100 -0
  383. package/dist/revocation.js.map +1 -0
  384. package/dist/run.d.ts +21 -0
  385. package/dist/run.js +80 -0
  386. package/dist/run.js.map +1 -0
  387. package/dist/scan-build.d.ts +18 -0
  388. package/dist/scan-build.js +100 -0
  389. package/dist/scan-build.js.map +1 -0
  390. package/dist/scan-plaintext.d.ts +24 -0
  391. package/dist/scan-plaintext.js +147 -0
  392. package/dist/scan-plaintext.js.map +1 -0
  393. package/dist/scan-staged.d.ts +15 -0
  394. package/dist/scan-staged.js +70 -0
  395. package/dist/scan-staged.js.map +1 -0
  396. package/dist/scan-transcripts.d.ts +23 -0
  397. package/dist/scan-transcripts.js +93 -0
  398. package/dist/scan-transcripts.js.map +1 -0
  399. package/dist/secret-backends.d.ts +50 -0
  400. package/dist/secret-backends.js +510 -0
  401. package/dist/secret-backends.js.map +1 -0
  402. package/dist/secret-expiration.d.ts +46 -0
  403. package/dist/secret-expiration.js +172 -0
  404. package/dist/secret-expiration.js.map +1 -0
  405. package/dist/secrets-migrate.d.ts +75 -0
  406. package/dist/secrets-migrate.js +185 -0
  407. package/dist/secrets-migrate.js.map +1 -0
  408. package/dist/secrets-model.d.ts +77 -0
  409. package/dist/secrets-model.js +6 -0
  410. package/dist/secrets-model.js.map +1 -0
  411. package/dist/secrets-onecli.d.ts +65 -0
  412. package/dist/secrets-onecli.js +113 -0
  413. package/dist/secrets-onecli.js.map +1 -0
  414. package/dist/secrets-propagate.d.ts +48 -0
  415. package/dist/secrets-propagate.js +201 -0
  416. package/dist/secrets-propagate.js.map +1 -0
  417. package/dist/secrets-pull.d.ts +34 -0
  418. package/dist/secrets-pull.js +118 -0
  419. package/dist/secrets-pull.js.map +1 -0
  420. package/dist/secrets-purge-history.d.ts +53 -0
  421. package/dist/secrets-purge-history.js +144 -0
  422. package/dist/secrets-purge-history.js.map +1 -0
  423. package/dist/secrets-rotate-cli.d.ts +54 -0
  424. package/dist/secrets-rotate-cli.js +438 -0
  425. package/dist/secrets-rotate-cli.js.map +1 -0
  426. package/dist/secrets-rotate.d.ts +38 -0
  427. package/dist/secrets-rotate.js +65 -0
  428. package/dist/secrets-rotate.js.map +1 -0
  429. package/dist/secrets-service.d.ts +73 -0
  430. package/dist/secrets-service.js +283 -0
  431. package/dist/secrets-service.js.map +1 -0
  432. package/dist/secrets-set.d.ts +25 -0
  433. package/dist/secrets-set.js +33 -0
  434. package/dist/secrets-set.js.map +1 -0
  435. package/dist/secrets-sync.d.ts +21 -0
  436. package/dist/secrets-sync.js +215 -0
  437. package/dist/secrets-sync.js.map +1 -0
  438. package/dist/secrets-validate.d.ts +41 -0
  439. package/dist/secrets-validate.js +126 -0
  440. package/dist/secrets-validate.js.map +1 -0
  441. package/dist/secrets-vault-migrate.d.ts +71 -0
  442. package/dist/secrets-vault-migrate.js +258 -0
  443. package/dist/secrets-vault-migrate.js.map +1 -0
  444. package/dist/secrets.d.ts +16 -0
  445. package/dist/secrets.js +72 -0
  446. package/dist/secrets.js.map +1 -0
  447. package/dist/security-hardening.d.ts +150 -0
  448. package/dist/security-hardening.js +275 -0
  449. package/dist/security-hardening.js.map +1 -0
  450. package/dist/security-policy.d.ts +89 -0
  451. package/dist/security-policy.js +174 -0
  452. package/dist/security-policy.js.map +1 -0
  453. package/dist/security-prescan.d.ts +117 -0
  454. package/dist/security-prescan.js +566 -0
  455. package/dist/security-prescan.js.map +1 -0
  456. package/dist/sentry-adapter.d.ts +49 -0
  457. package/dist/sentry-adapter.js +227 -0
  458. package/dist/sentry-adapter.js.map +1 -0
  459. package/dist/service-adapter.d.ts +94 -0
  460. package/dist/service-adapter.js +162 -0
  461. package/dist/service-adapter.js.map +1 -0
  462. package/dist/skills.d.ts +13 -0
  463. package/dist/skills.js +17 -0
  464. package/dist/skills.js.map +1 -0
  465. package/dist/sla-monitor.d.ts +107 -0
  466. package/dist/sla-monitor.js +233 -0
  467. package/dist/sla-monitor.js.map +1 -0
  468. package/dist/stack-detector.d.ts +12 -0
  469. package/dist/stack-detector.js +251 -0
  470. package/dist/stack-detector.js.map +1 -0
  471. package/dist/team-model.d.ts +58 -0
  472. package/dist/team-model.js +83 -0
  473. package/dist/team-model.js.map +1 -0
  474. package/dist/team-service.d.ts +54 -0
  475. package/dist/team-service.js +206 -0
  476. package/dist/team-service.js.map +1 -0
  477. package/dist/toml-generator.d.ts +8 -0
  478. package/dist/toml-generator.js +223 -0
  479. package/dist/toml-generator.js.map +1 -0
  480. package/dist/triage-sandbox.d.ts +34 -0
  481. package/dist/triage-sandbox.js +167 -0
  482. package/dist/triage-sandbox.js.map +1 -0
  483. package/dist/triage.d.ts +30 -0
  484. package/dist/triage.js +79 -0
  485. package/dist/triage.js.map +1 -0
  486. package/dist/update-check.d.ts +13 -0
  487. package/dist/update-check.js +91 -0
  488. package/dist/update-check.js.map +1 -0
  489. package/dist/utils/colors.d.ts +14 -0
  490. package/dist/utils/colors.js +15 -0
  491. package/dist/utils/colors.js.map +1 -0
  492. package/dist/utils/didYouMean.d.ts +15 -0
  493. package/dist/utils/didYouMean.js +47 -0
  494. package/dist/utils/didYouMean.js.map +1 -0
  495. package/dist/utils/exec.d.ts +21 -0
  496. package/dist/utils/exec.js +23 -0
  497. package/dist/utils/exec.js.map +1 -0
  498. package/dist/utils/execFileNoThrow.d.ts +14 -0
  499. package/dist/utils/execFileNoThrow.js +29 -0
  500. package/dist/utils/execFileNoThrow.js.map +1 -0
  501. package/dist/utils/flags.d.ts +19 -0
  502. package/dist/utils/flags.js +36 -0
  503. package/dist/utils/flags.js.map +1 -0
  504. package/dist/utils/parseCommand.d.ts +16 -0
  505. package/dist/utils/parseCommand.js +13 -0
  506. package/dist/utils/parseCommand.js.map +1 -0
  507. package/dist/utils/prompt.d.ts +13 -0
  508. package/dist/utils/prompt.js +35 -0
  509. package/dist/utils/prompt.js.map +1 -0
  510. package/dist/utils/promptSelect.d.ts +19 -0
  511. package/dist/utils/promptSelect.js +89 -0
  512. package/dist/utils/promptSelect.js.map +1 -0
  513. package/dist/utils/redactSecrets.d.ts +24 -0
  514. package/dist/utils/redactSecrets.js +134 -0
  515. package/dist/utils/redactSecrets.js.map +1 -0
  516. package/dist/validation/dynamic-schema.d.ts +29 -0
  517. package/dist/validation/dynamic-schema.js +76 -0
  518. package/dist/validation/dynamic-schema.js.map +1 -0
  519. package/package.json +52 -0
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Multi-repo security prescan.
3
+ *
4
+ * `kit security prescan <path>` walks every git-repo under <path> and
5
+ * produces a baseline-snapshot of cross-cutting security signals. Output:
6
+ * `~/.kit/prescans/<timestamp>.jsonl` (raw findings) +
7
+ * `<timestamp>-summary.md` (operator-facing rollup).
8
+ *
9
+ * Designed as the "first day onboarding" sweep — new operator points
10
+ * kit at their `~/projects/` (or whatever root), gets one document
11
+ * describing every actionable security gap across every repo.
12
+ *
13
+ * Default bundle (fast, ~30s for 10 repos):
14
+ * - secret-leak gitleaks full history (delegated to gitleaks CLI)
15
+ * - gitignore-holes missing .env* / *.pem / id_rsa / *.bak patterns
16
+ * - tracked-secrets git ls-files matches secret-file patterns
17
+ * - branch-protection gh api repos/{owner}/{repo}/branches/main/protection
18
+ * - public-private gh api repos/{owner}/{repo} --jq .private
19
+ *
20
+ * --deep adds:
21
+ * - npm-audit-high npm audit --audit-level=high per repo with package.json
22
+ * - bumblebee delegate to kit's existing supply-chain scanner
23
+ * - audit-gap repos with [governance] but empty .kit-audit.jsonl
24
+ * - workflow-drift repos missing .github/workflows/kit-security.yml
25
+ *
26
+ * Every check is BEST-EFFORT: missing tool (gitleaks not installed, gh not
27
+ * authed, etc.) emits a "skipped" finding instead of failing the whole sweep.
28
+ */
29
+ export type Severity = "info" | "low" | "medium" | "high" | "critical";
30
+ export interface PrescanFinding {
31
+ timestamp: string;
32
+ repo: string;
33
+ category: string;
34
+ severity: Severity;
35
+ detail: string;
36
+ remediation?: string;
37
+ }
38
+ /**
39
+ * A prescan check is the smallest extensibility unit. Built-in checks live
40
+ * in `BUILTIN_CHECKS`; callers (or future plugins) can pass additional
41
+ * `extraChecks` via `PrescanOptions.checks` to extend the registry without
42
+ * forking kit.
43
+ *
44
+ * Contract:
45
+ * - `name` is a unique kebab-case slug. Used by --only / --skip filters.
46
+ * - `tier === "deep"` checks only run when opts.deep is true.
47
+ * - `scope === "global"` runs once for the whole prescan; "per-repo" runs
48
+ * per discovered repo. Global checks receive the prescan root as `repo`.
49
+ * - `ctx.bumblebeeInstall` is set ONLY for deep mode + after the install
50
+ * succeeded. Checks that depend on it must defensively check for null.
51
+ */
52
+ export interface PrescanCheckContext {
53
+ bumblebeeInstall?: {
54
+ binPath: string;
55
+ catalogDir: string;
56
+ } | null;
57
+ }
58
+ export interface PrescanCheck {
59
+ name: string;
60
+ tier: "default" | "deep";
61
+ scope: "per-repo" | "global";
62
+ run: (repo: string, ctx: PrescanCheckContext) => Promise<PrescanFinding[]>;
63
+ }
64
+ export interface PrescanOptions {
65
+ /** Root path to walk. Required. */
66
+ root: string;
67
+ /** Include --deep checks (npm-audit, bumblebee, audit-gap, workflow-drift). */
68
+ deep?: boolean;
69
+ /** Write report to disk. Default true; set false in tests. */
70
+ persist?: boolean;
71
+ /** Max repo-depth from root (default 4). */
72
+ maxDepth?: number;
73
+ /** Override report dir (test injection). */
74
+ outDir?: string;
75
+ /** Repo-path substrings to skip (e.g. third-party clones like "convex-backend"). */
76
+ exclude?: string[];
77
+ /**
78
+ * Subset of check-names to run (whitelist). If unset, run all registered
79
+ * checks. Mutually exclusive with `skipChecks` in practice — both can be
80
+ * provided, only and skip stack (only first, then skip from the only-set).
81
+ */
82
+ onlyChecks?: string[];
83
+ /** Check-names to omit. Applied AFTER onlyChecks. */
84
+ skipChecks?: string[];
85
+ /**
86
+ * Additional checks beyond the built-in registry. Useful for plugins or
87
+ * tests; built-in checks always run first (subject to filtering).
88
+ */
89
+ extraChecks?: PrescanCheck[];
90
+ }
91
+ export interface PrescanReport {
92
+ startedAt: string;
93
+ finishedAt: string;
94
+ root: string;
95
+ repoCount: number;
96
+ findings: PrescanFinding[];
97
+ reportPath?: string;
98
+ summaryPath?: string;
99
+ }
100
+ /**
101
+ * Built-in checks. New checks should be added here; external plugins can
102
+ * pass additional checks via `PrescanOptions.extraChecks`.
103
+ */
104
+ export declare const BUILTIN_CHECKS: PrescanCheck[];
105
+ export declare function runPrescan(opts: PrescanOptions): Promise<PrescanReport>;
106
+ export declare function renderSummary(report: PrescanReport): string;
107
+ export interface PrescanDiff {
108
+ /** Findings present in B but not A — new regressions since the baseline. */
109
+ added: PrescanFinding[];
110
+ /** Findings present in A but not B — fixed (or excluded) since baseline. */
111
+ removed: PrescanFinding[];
112
+ /** Findings present in both — persistent. */
113
+ unchanged: PrescanFinding[];
114
+ }
115
+ export declare function diffReports(a: PrescanReport, b: PrescanReport): PrescanDiff;
116
+ export declare function loadReport(jsonlPath: string): Promise<PrescanReport>;
117
+ export declare function renderDiff(diff: PrescanDiff): string;
@@ -0,0 +1,566 @@
1
+ /**
2
+ * Multi-repo security prescan.
3
+ *
4
+ * `kit security prescan <path>` walks every git-repo under <path> and
5
+ * produces a baseline-snapshot of cross-cutting security signals. Output:
6
+ * `~/.kit/prescans/<timestamp>.jsonl` (raw findings) +
7
+ * `<timestamp>-summary.md` (operator-facing rollup).
8
+ *
9
+ * Designed as the "first day onboarding" sweep — new operator points
10
+ * kit at their `~/projects/` (or whatever root), gets one document
11
+ * describing every actionable security gap across every repo.
12
+ *
13
+ * Default bundle (fast, ~30s for 10 repos):
14
+ * - secret-leak gitleaks full history (delegated to gitleaks CLI)
15
+ * - gitignore-holes missing .env* / *.pem / id_rsa / *.bak patterns
16
+ * - tracked-secrets git ls-files matches secret-file patterns
17
+ * - branch-protection gh api repos/{owner}/{repo}/branches/main/protection
18
+ * - public-private gh api repos/{owner}/{repo} --jq .private
19
+ *
20
+ * --deep adds:
21
+ * - npm-audit-high npm audit --audit-level=high per repo with package.json
22
+ * - bumblebee delegate to kit's existing supply-chain scanner
23
+ * - audit-gap repos with [governance] but empty .kit-audit.jsonl
24
+ * - workflow-drift repos missing .github/workflows/kit-security.yml
25
+ *
26
+ * Every check is BEST-EFFORT: missing tool (gitleaks not installed, gh not
27
+ * authed, etc.) emits a "skipped" finding instead of failing the whole sweep.
28
+ */
29
+ import { readFile, writeFile, mkdir, readdir, access } from "node:fs/promises";
30
+ import { join } from "node:path";
31
+ import { homedir } from "node:os";
32
+ import { exec } from "./utils/exec.js";
33
+ const PRESCAN_DIR = join(homedir(), ".kit", "prescans");
34
+ async function pathExists(p) {
35
+ try {
36
+ await access(p);
37
+ return true;
38
+ }
39
+ catch {
40
+ return false;
41
+ }
42
+ }
43
+ /**
44
+ * Walk <root> looking for git repos. Skips node_modules / dist / .git /
45
+ * obvious build dirs. Returns absolute paths of every .git directory's
46
+ * parent (= the repo root).
47
+ */
48
+ async function findRepos(root, maxDepth) {
49
+ const repos = [];
50
+ const SKIP_DIRS = new Set([
51
+ "node_modules", ".git", "dist", "build", ".next", ".turbo",
52
+ "out", "coverage", ".cache", ".venv", "venv", "__pycache__",
53
+ ]);
54
+ async function walk(dir, depth) {
55
+ if (depth > maxDepth)
56
+ return;
57
+ // Is dir itself a repo? Check for .git as dir or file (worktrees).
58
+ if (await pathExists(join(dir, ".git"))) {
59
+ repos.push(dir);
60
+ return; // don't recurse into a repo
61
+ }
62
+ let entries;
63
+ try {
64
+ entries = (await readdir(dir, { withFileTypes: true, encoding: "utf-8" }));
65
+ }
66
+ catch {
67
+ return;
68
+ }
69
+ for (const ent of entries) {
70
+ if (!ent.isDirectory())
71
+ continue;
72
+ const name = String(ent.name);
73
+ if (name.startsWith(".") && name !== ".git")
74
+ continue;
75
+ if (SKIP_DIRS.has(name))
76
+ continue;
77
+ await walk(join(dir, name), depth + 1);
78
+ }
79
+ }
80
+ await walk(root, 0);
81
+ return repos;
82
+ }
83
+ async function gitOriginHttpsUrl(repo) {
84
+ try {
85
+ const { stdout } = await exec("git", ["-C", repo, "config", "--get", "remote.origin.url"], {
86
+ timeout: 5000,
87
+ });
88
+ const url = stdout.trim();
89
+ // git@github.com:owner/repo.git OR https://github.com/owner/repo(.git)?
90
+ const m = url.match(/[:/]([^/]+)\/([^/]+?)(?:\.git)?$/);
91
+ if (m && m[1] && m[2])
92
+ return { owner: m[1], name: m[2] };
93
+ return null;
94
+ }
95
+ catch {
96
+ return null;
97
+ }
98
+ }
99
+ function finding(repo, category, severity, detail, remediation) {
100
+ return {
101
+ timestamp: new Date().toISOString(),
102
+ repo,
103
+ category,
104
+ severity,
105
+ detail,
106
+ remediation,
107
+ };
108
+ }
109
+ // ── Check: gitignore holes ─────────────────────────────────────────────────
110
+ const REQUIRED_GITIGNORE = [
111
+ ".env",
112
+ ".env.local",
113
+ ".env.*.local",
114
+ ".env.*.backup",
115
+ "*.prod-backup",
116
+ "*.pem",
117
+ "id_rsa",
118
+ ".kit/elevation.json",
119
+ ];
120
+ async function checkGitignoreHoles(repo) {
121
+ const path = join(repo, ".gitignore");
122
+ let text = "";
123
+ try {
124
+ text = await readFile(path, "utf-8");
125
+ }
126
+ catch {
127
+ return [
128
+ finding(repo, "gitignore-missing", "high", "no .gitignore in repo root", "add .gitignore with at least: .env*, *.pem, id_rsa"),
129
+ ];
130
+ }
131
+ const lines = text.split("\n").map((l) => l.trim());
132
+ const missing = REQUIRED_GITIGNORE.filter((p) => !lines.includes(p));
133
+ if (missing.length === 0)
134
+ return [];
135
+ return [
136
+ finding(repo, "gitignore-holes", "medium", `missing ${missing.length} secret-leak patterns: ${missing.join(", ")}`, `append to .gitignore: ${missing.join(" ")}`),
137
+ ];
138
+ }
139
+ // ── Check: tracked secret-shaped files ─────────────────────────────────────
140
+ async function checkTrackedSecretFiles(repo) {
141
+ try {
142
+ const { stdout } = await exec("git", ["-C", repo, "ls-files"], {
143
+ timeout: 15000, maxBuffer: 20_000_000,
144
+ });
145
+ const tracked = stdout.split("\n");
146
+ const matches = tracked.filter((f) => /(?:^|\/)\.env(?:\.|$)|\.pem$|\.key$|id_rsa$|\.prod-backup$|\.bak$/.test(f)).filter((f) =>
147
+ // Allowlist anything that looks like a template / example / sample / patch / dist,
148
+ // and node-modules / vendor / fixtures / third-party demo folders.
149
+ !/\.(template|example|sample|dist|tmpl|patch|stub|mock|spec)$/.test(f) &&
150
+ !/(?:^|\/)(node_modules|vendor|__tests__|tests?|fixtures?|demos?|private-demos?|examples?|samples?)\//.test(f));
151
+ if (matches.length === 0)
152
+ return [];
153
+ return [
154
+ finding(repo, "tracked-secret-files", "critical", `${matches.length} tracked file(s) match secret-file pattern: ${matches.join(", ")}`, `git rm --cached <file> ; add to .gitignore ; rotate any leaked credential`),
155
+ ];
156
+ }
157
+ catch {
158
+ return [];
159
+ }
160
+ }
161
+ // ── Check: gitleaks ────────────────────────────────────────────────────────
162
+ async function checkSecretLeakage(repo) {
163
+ try {
164
+ await exec("gitleaks", ["--version"], { timeout: 3000 });
165
+ }
166
+ catch {
167
+ return [finding(repo, "secret-leak-skipped", "info", "gitleaks not installed — skipping", "install: https://github.com/gitleaks/gitleaks")];
168
+ }
169
+ try {
170
+ await exec("gitleaks", ["detect", "--source", repo, "--redact", "--no-banner", "--exit-code", "1"], {
171
+ timeout: 60_000,
172
+ });
173
+ return [];
174
+ }
175
+ catch (err) {
176
+ const e = err;
177
+ const out = (e.stdout ?? "") + (e.stderr ?? "");
178
+ const leakMatch = out.match(/\d+ leaks? found/i);
179
+ return [
180
+ finding(repo, "secret-leak", "critical", leakMatch ? leakMatch[0] : "gitleaks reported leaks (see report)", "review leaks; rotate; allowlist via .gitleaks.toml only AFTER revoking"),
181
+ ];
182
+ }
183
+ }
184
+ // ── Check: branch protection + public/private (via gh CLI) ────────────────
185
+ async function checkGitHubMeta(repo) {
186
+ const remote = await gitOriginHttpsUrl(repo);
187
+ if (!remote)
188
+ return [];
189
+ const findings = [];
190
+ try {
191
+ const { stdout } = await exec("gh", ["api", `repos/${remote.owner}/${remote.name}`, "--jq", ".private,.default_branch"], {
192
+ timeout: 10_000,
193
+ });
194
+ const [isPrivateStr, defaultBranch] = stdout.trim().split("\n");
195
+ const isPrivate = isPrivateStr === "true";
196
+ const branch = defaultBranch || "main";
197
+ if (!isPrivate) {
198
+ findings.push(finding(repo, "repo-public", "high", `repository is PUBLIC (${remote.owner}/${remote.name}) — any leaked credential in history is world-visible`, "consider whether truly intended; for private code, switch via Settings → Visibility"));
199
+ }
200
+ // Branch protection
201
+ try {
202
+ await exec("gh", ["api", `repos/${remote.owner}/${remote.name}/branches/${branch}/protection`], {
203
+ timeout: 10_000,
204
+ });
205
+ }
206
+ catch (err) {
207
+ const e = err;
208
+ if ((e.stderr ?? "").includes("404")) {
209
+ findings.push(finding(repo, "branch-unprotected", "medium", `branch '${branch}' has no protection rules`, `Settings → Branches → Add protection rule for ${branch}`));
210
+ }
211
+ }
212
+ }
213
+ catch {
214
+ findings.push(finding(repo, "gh-skipped", "info", `gh CLI not authed or repo not on github.com — skipping repo meta`, "run: gh auth login"));
215
+ }
216
+ return findings;
217
+ }
218
+ // ── Deep check: npm audit ──────────────────────────────────────────────────
219
+ /**
220
+ * Extract up to 3 representative package names from npm-audit's `vulnerabilities`
221
+ * map for crit+high entries. Helps the operator know WHICH dep is exposed
222
+ * without forcing them to re-run `npm audit` interactively.
223
+ */
224
+ function topAuditPackages(data) {
225
+ const vulns = data?.vulnerabilities;
226
+ if (!vulns)
227
+ return [];
228
+ const top = [];
229
+ for (const [name, info] of Object.entries(vulns)) {
230
+ if (top.length >= 3)
231
+ break;
232
+ const sev = info?.severity?.toLowerCase();
233
+ if (sev === "critical" || sev === "high")
234
+ top.push(name);
235
+ }
236
+ return top;
237
+ }
238
+ async function checkNpmAudit(repo) {
239
+ if (!(await pathExists(join(repo, "package.json"))))
240
+ return [];
241
+ if (!(await pathExists(join(repo, "package-lock.json")))) {
242
+ return [finding(repo, "npm-audit-skipped", "info", "no package-lock.json — skipping npm audit", "run: npm install to generate lockfile")];
243
+ }
244
+ const NPM_AUDIT_TIMEOUT_MS = 120_000; // 2 min — large lockfiles can be slow
245
+ const NPM_AUDIT_BUFFER = 64 * 1024 * 1024; // 64 MB — monorepos emit large json
246
+ const parseAndFormat = (stdout) => {
247
+ const data = JSON.parse(stdout);
248
+ const high = data?.metadata?.vulnerabilities?.high ?? 0;
249
+ const critical = data?.metadata?.vulnerabilities?.critical ?? 0;
250
+ if (high + critical === 0)
251
+ return [];
252
+ const top = topAuditPackages(data);
253
+ const where = top.length ? ` — top: ${top.join(", ")}` : "";
254
+ return [finding(repo, "npm-audit", critical > 0 ? "critical" : "high", `${critical} critical + ${high} high vulnerabilities${where}`, "npm audit fix; review individual reports")];
255
+ };
256
+ try {
257
+ const { stdout } = await exec("npm", ["audit", "--audit-level=high", "--json"], {
258
+ cwd: repo, timeout: NPM_AUDIT_TIMEOUT_MS, maxBuffer: NPM_AUDIT_BUFFER,
259
+ });
260
+ return parseAndFormat(stdout);
261
+ }
262
+ catch (err) {
263
+ // npm audit exits non-zero when findings exist
264
+ const e = err;
265
+ if (e.stdout) {
266
+ try {
267
+ return parseAndFormat(e.stdout);
268
+ }
269
+ catch { /* fallthrough */ }
270
+ }
271
+ return [finding(repo, "npm-audit-error", "info", "npm audit failed to parse", "manual investigation")];
272
+ }
273
+ }
274
+ // ── Deep check: workflow drift ─────────────────────────────────────────────
275
+ async function checkWorkflowDrift(repo) {
276
+ if (!(await pathExists(join(repo, ".github", "workflows"))))
277
+ return [];
278
+ const expectedFiles = ["kit-security.yml", "security.yml"];
279
+ for (const f of expectedFiles) {
280
+ if (await pathExists(join(repo, ".github", "workflows", f)))
281
+ return [];
282
+ }
283
+ return [finding(repo, "workflow-drift", "low", "no kit-security workflow in .github/workflows/", "copy templates/github/kit-security.yml from kit")];
284
+ }
285
+ // ── Deep check: bumblebee supply-chain exposure ────────────────────────────
286
+ /**
287
+ * One-time staleness check for the bundled exposure catalog. Stale catalogs
288
+ * mean the scanner is detecting old compromises only — new credential-stealing
289
+ * supply-chain attacks won't surface. Surfaced as a single warning across the
290
+ * whole prescan, not per-repo (the catalog is shared).
291
+ */
292
+ async function checkBumblebeeCatalogStale(install, root) {
293
+ try {
294
+ const { newestCatalogMtime, isCatalogStale, CATALOG_STALE_AFTER_DAYS } = await import("./bumblebee.js");
295
+ const mtime = await newestCatalogMtime(install.catalogDir);
296
+ if (mtime === null) {
297
+ return [finding(root, "bumblebee-catalog-missing", "medium", `bumblebee threat_intel catalog directory empty: ${install.catalogDir}`, `clear ~/.kit/tools/bumblebee and run any deep scan to re-download`)];
298
+ }
299
+ const { stale, ageDays } = isCatalogStale(mtime, Date.now());
300
+ if (stale) {
301
+ return [finding(root, "bumblebee-catalog-stale", "medium", `bumblebee threat_intel catalog is ${ageDays} days old (threshold: ${CATALOG_STALE_AFTER_DAYS}d) — new supply-chain compromises may not be detected`, `clear ~/.kit/tools/bumblebee to force a fresh download next deep scan`)];
302
+ }
303
+ return [];
304
+ }
305
+ catch {
306
+ return [];
307
+ }
308
+ }
309
+ /**
310
+ * Per-repo bumblebee scan. Returns one finding per detected exposure.
311
+ * `install` is hoisted to the caller so the binary is fetched ONCE per
312
+ * prescan run, not 27× — bumblebee install can do an HTTP download.
313
+ */
314
+ async function checkBumblebee(repo, install) {
315
+ try {
316
+ const { runScan } = await import("./bumblebee.js");
317
+ const { outcome, error } = await runScan({
318
+ install: install,
319
+ profile: "project",
320
+ roots: [repo],
321
+ maxDuration: "60s",
322
+ timeoutMs: 90_000,
323
+ });
324
+ if (error || !outcome)
325
+ return [];
326
+ if (!outcome.findings.length)
327
+ return [];
328
+ return outcome.findings.map((f) => finding(repo, "supply-chain", f.severity?.toLowerCase() ?? "medium", `${f.ecosystem}/${f.packageName}@${f.version} matches catalog ${f.catalogName} (${f.catalogId}) in ${f.sourceFile}`, "investigate package; remove if not directly required; pin to last-known-good version"));
329
+ }
330
+ catch {
331
+ return [];
332
+ }
333
+ }
334
+ // ── Deep check: audit-log gap ──────────────────────────────────────────────
335
+ async function checkAuditGap(repo) {
336
+ const kitToml = await pathExists(join(repo, ".kit.toml"));
337
+ if (!kitToml)
338
+ return [];
339
+ const auditFile = join(repo, ".kit-audit.jsonl");
340
+ if (!(await pathExists(auditFile))) {
341
+ return [finding(repo, "audit-gap", "info", "kit governance configured but .kit-audit.jsonl missing", "run any kit sensitive op to bootstrap; verify [governance.audit].enabled = true")];
342
+ }
343
+ return [];
344
+ }
345
+ // ── Built-in check registry ────────────────────────────────────────────────
346
+ /**
347
+ * Built-in checks. New checks should be added here; external plugins can
348
+ * pass additional checks via `PrescanOptions.extraChecks`.
349
+ */
350
+ export const BUILTIN_CHECKS = [
351
+ { name: "gitignore-holes", tier: "default", scope: "per-repo", run: (repo) => checkGitignoreHoles(repo) },
352
+ { name: "tracked-secret-files", tier: "default", scope: "per-repo", run: (repo) => checkTrackedSecretFiles(repo) },
353
+ { name: "secret-leak", tier: "default", scope: "per-repo", run: (repo) => checkSecretLeakage(repo) },
354
+ { name: "github-meta", tier: "default", scope: "per-repo", run: (repo) => checkGitHubMeta(repo) },
355
+ { name: "npm-audit", tier: "deep", scope: "per-repo", run: (repo) => checkNpmAudit(repo) },
356
+ { name: "workflow-drift", tier: "deep", scope: "per-repo", run: (repo) => checkWorkflowDrift(repo) },
357
+ { name: "audit-gap", tier: "deep", scope: "per-repo", run: (repo) => checkAuditGap(repo) },
358
+ {
359
+ name: "bumblebee-catalog-stale",
360
+ tier: "deep",
361
+ scope: "global",
362
+ run: async (root, ctx) => ctx.bumblebeeInstall
363
+ ? await checkBumblebeeCatalogStale(ctx.bumblebeeInstall, root)
364
+ : [],
365
+ },
366
+ {
367
+ name: "bumblebee",
368
+ tier: "deep",
369
+ scope: "per-repo",
370
+ run: async (repo, ctx) => ctx.bumblebeeInstall
371
+ ? await checkBumblebee(repo, ctx.bumblebeeInstall)
372
+ : [],
373
+ },
374
+ ];
375
+ /**
376
+ * Apply --only / --skip filters AFTER tier-filtering.
377
+ */
378
+ function selectChecks(all, deep, only, skip) {
379
+ const inTier = all.filter((c) => deep || c.tier !== "deep");
380
+ const onlySet = only && only.length > 0 ? new Set(only) : null;
381
+ const skipSet = skip && skip.length > 0 ? new Set(skip) : new Set();
382
+ return inTier.filter((c) => (onlySet === null || onlySet.has(c.name)) && !skipSet.has(c.name));
383
+ }
384
+ // ── Main entry point ───────────────────────────────────────────────────────
385
+ export async function runPrescan(opts) {
386
+ const startedAt = new Date().toISOString();
387
+ const allRepos = await findRepos(opts.root, opts.maxDepth ?? 4);
388
+ const excludes = opts.exclude ?? [];
389
+ const repos = excludes.length === 0
390
+ ? allRepos
391
+ : allRepos.filter((r) => !excludes.some((p) => r.includes(p)));
392
+ const findings = [];
393
+ // Hoist bumblebee install once for the whole run (deep mode only).
394
+ // Failure to ensure → ctx.bumblebeeInstall stays null and per-check
395
+ // run() callbacks defensively return [].
396
+ let bumblebeeInstall = null;
397
+ if (opts.deep) {
398
+ try {
399
+ const { ensureBumblebee } = await import("./bumblebee.js");
400
+ const { install } = await ensureBumblebee({ allowDownload: true });
401
+ if (install)
402
+ bumblebeeInstall = install;
403
+ }
404
+ catch {
405
+ // Best-effort — leave install null.
406
+ }
407
+ }
408
+ const ctx = { bumblebeeInstall };
409
+ const checks = selectChecks([...BUILTIN_CHECKS, ...(opts.extraChecks ?? [])], Boolean(opts.deep), opts.onlyChecks, opts.skipChecks);
410
+ const globalChecks = checks.filter((c) => c.scope === "global");
411
+ const perRepoChecks = checks.filter((c) => c.scope === "per-repo");
412
+ // Globals first (e.g. bumblebee-catalog-stale): they may influence later
413
+ // per-repo decisions, and they're typically O(1) rather than O(repos).
414
+ for (const check of globalChecks) {
415
+ findings.push(...await check.run(opts.root, ctx));
416
+ }
417
+ for (const repo of repos) {
418
+ for (const check of perRepoChecks) {
419
+ findings.push(...await check.run(repo, ctx));
420
+ }
421
+ }
422
+ const finishedAt = new Date().toISOString();
423
+ const report = {
424
+ startedAt,
425
+ finishedAt,
426
+ root: opts.root,
427
+ repoCount: repos.length,
428
+ findings,
429
+ };
430
+ if (opts.persist !== false) {
431
+ const outDir = opts.outDir ?? PRESCAN_DIR;
432
+ await mkdir(outDir, { recursive: true, mode: 0o700 });
433
+ const stamp = startedAt.replace(/[:.]/g, "-");
434
+ const reportPath = join(outDir, `${stamp}.jsonl`);
435
+ const summaryPath = join(outDir, `${stamp}-summary.md`);
436
+ const jsonl = findings.map((f) => JSON.stringify(f)).join("\n") + "\n";
437
+ await writeFile(reportPath, jsonl, { encoding: "utf-8", mode: 0o600 });
438
+ await writeFile(summaryPath, renderSummary(report), { encoding: "utf-8", mode: 0o600 });
439
+ report.reportPath = reportPath;
440
+ report.summaryPath = summaryPath;
441
+ }
442
+ return report;
443
+ }
444
+ export function renderSummary(report) {
445
+ const sevOrder = ["critical", "high", "medium", "low", "info"];
446
+ const bySev = new Map();
447
+ for (const f of report.findings) {
448
+ const arr = bySev.get(f.severity) ?? [];
449
+ arr.push(f);
450
+ bySev.set(f.severity, arr);
451
+ }
452
+ const lines = [];
453
+ lines.push(`# kit prescan report`);
454
+ lines.push("");
455
+ lines.push(`- **Root**: \`${report.root}\``);
456
+ lines.push(`- **Started**: ${report.startedAt}`);
457
+ lines.push(`- **Finished**: ${report.finishedAt}`);
458
+ lines.push(`- **Repos scanned**: ${report.repoCount}`);
459
+ lines.push(`- **Total findings**: ${report.findings.length}`);
460
+ lines.push("");
461
+ for (const sev of sevOrder) {
462
+ const arr = bySev.get(sev) ?? [];
463
+ if (arr.length === 0)
464
+ continue;
465
+ lines.push(`## ${sev.toUpperCase()} (${arr.length})`);
466
+ lines.push("");
467
+ for (const f of arr) {
468
+ lines.push(`### ${f.repo} — ${f.category}`);
469
+ lines.push(`${f.detail}`);
470
+ if (f.remediation)
471
+ lines.push(`> **Fix**: ${f.remediation}`);
472
+ lines.push("");
473
+ }
474
+ }
475
+ if (report.findings.length === 0) {
476
+ lines.push(`## All clean`);
477
+ lines.push("");
478
+ lines.push("No findings across all scanned repos. Re-run periodically to detect drift.");
479
+ }
480
+ return lines.join("\n");
481
+ }
482
+ /**
483
+ * A finding's identity is (repo, category, detail). Severity isn't part of
484
+ * the key — a severity-only change still counts as the same finding (caller
485
+ * can compare arr.severity manually if interested).
486
+ */
487
+ function findingKey(f) {
488
+ return `${f.repo}\x00${f.category}\x00${f.detail}`;
489
+ }
490
+ export function diffReports(a, b) {
491
+ const aKeys = new Map(a.findings.map((f) => [findingKey(f), f]));
492
+ const bKeys = new Map(b.findings.map((f) => [findingKey(f), f]));
493
+ const added = [];
494
+ const removed = [];
495
+ const unchanged = [];
496
+ for (const [k, f] of bKeys) {
497
+ if (aKeys.has(k))
498
+ unchanged.push(f);
499
+ else
500
+ added.push(f);
501
+ }
502
+ for (const [k, f] of aKeys) {
503
+ if (!bKeys.has(k))
504
+ removed.push(f);
505
+ }
506
+ return { added, removed, unchanged };
507
+ }
508
+ export async function loadReport(jsonlPath) {
509
+ const text = await readFile(jsonlPath, "utf-8");
510
+ const findings = [];
511
+ for (const line of text.split("\n")) {
512
+ const t = line.trim();
513
+ if (!t)
514
+ continue;
515
+ try {
516
+ findings.push(JSON.parse(t));
517
+ }
518
+ catch {
519
+ // Skip malformed lines — JSONL parsers should be tolerant.
520
+ }
521
+ }
522
+ // The JSONL only stores findings; reconstruct minimal report envelope.
523
+ return {
524
+ startedAt: findings[0]?.timestamp ?? "",
525
+ finishedAt: findings[findings.length - 1]?.timestamp ?? "",
526
+ root: "",
527
+ repoCount: new Set(findings.map((f) => f.repo)).size,
528
+ findings,
529
+ };
530
+ }
531
+ export function renderDiff(diff) {
532
+ const lines = [];
533
+ lines.push(`# kit prescan diff`);
534
+ lines.push("");
535
+ lines.push(`- **Added (regressions)**: ${diff.added.length}`);
536
+ lines.push(`- **Removed (fixed)**: ${diff.removed.length}`);
537
+ lines.push(`- **Unchanged (persistent)**: ${diff.unchanged.length}`);
538
+ lines.push("");
539
+ if (diff.added.length) {
540
+ lines.push(`## REGRESSIONS — new findings since baseline (${diff.added.length})`);
541
+ lines.push("");
542
+ for (const f of diff.added) {
543
+ lines.push(`### ${f.repo} — ${f.category} (${f.severity})`);
544
+ lines.push(f.detail);
545
+ if (f.remediation)
546
+ lines.push(`> **Fix**: ${f.remediation}`);
547
+ lines.push("");
548
+ }
549
+ }
550
+ if (diff.removed.length) {
551
+ lines.push(`## FIXED — gone since baseline (${diff.removed.length})`);
552
+ lines.push("");
553
+ for (const f of diff.removed) {
554
+ lines.push(`### ${f.repo} — ${f.category} (was ${f.severity})`);
555
+ lines.push(f.detail);
556
+ lines.push("");
557
+ }
558
+ }
559
+ if (diff.added.length === 0 && diff.removed.length === 0) {
560
+ lines.push(`## No drift`);
561
+ lines.push("");
562
+ lines.push(`${diff.unchanged.length} finding(s) carried over unchanged. No regressions, no fixes.`);
563
+ }
564
+ return lines.join("\n");
565
+ }
566
+ //# sourceMappingURL=security-prescan.js.map