@m2-ai/lattice-cli 0.0.0-stage → 0.8.7

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 (743) hide show
  1. package/DISCLOSURE +1 -0
  2. package/README.md +118 -2
  3. package/bundles/expo-mobile/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
  4. package/bundles/expo-mobile/.agents/skills/lattice-release-manager/SKILL.md +29 -0
  5. package/bundles/expo-mobile/.agents/skills/lattice-verify/SKILL.md +27 -0
  6. package/bundles/expo-mobile/.claude/agents/lattice-feature-agent.md +10 -0
  7. package/bundles/expo-mobile/.claude/agents/lattice-release-manager.md +9 -0
  8. package/bundles/expo-mobile/.claude/hooks/README.md +9 -0
  9. package/bundles/expo-mobile/.claude/hooks/pre-commit-verify.mjs +10 -0
  10. package/bundles/expo-mobile/.claude/hooks/pre-tool-use.mjs +51 -0
  11. package/bundles/expo-mobile/.claude/rules/lattice-core.md +20 -0
  12. package/bundles/expo-mobile/.claude/settings.json +38 -0
  13. package/bundles/expo-mobile/.claude/skills/lattice-verify/SKILL.md +27 -0
  14. package/bundles/expo-mobile/.codex/agents/lattice-feature-agent.toml +9 -0
  15. package/bundles/expo-mobile/.codex/agents/lattice-release-manager.toml +9 -0
  16. package/bundles/expo-mobile/.cursor/mcp.json +34 -0
  17. package/bundles/expo-mobile/.cursor/rules/lattice-core.mdc +35 -0
  18. package/bundles/expo-mobile/.cursor/rules.md +94 -0
  19. package/bundles/expo-mobile/.env.example +19 -0
  20. package/bundles/expo-mobile/.github/PULL_REQUEST_TEMPLATE.md +42 -0
  21. package/bundles/expo-mobile/.github/agents/lattice-feature-agent.agent.md +7 -0
  22. package/bundles/expo-mobile/.github/agents/lattice-release-manager.agent.md +7 -0
  23. package/bundles/expo-mobile/.github/copilot-instructions.md +37 -0
  24. package/bundles/expo-mobile/.github/instructions/lattice-core.instructions.md +11 -0
  25. package/bundles/expo-mobile/.github/workflows/ci.yml +26 -0
  26. package/bundles/expo-mobile/.gitmessage +24 -0
  27. package/bundles/expo-mobile/.lattice/config.json +9 -0
  28. package/bundles/expo-mobile/.lattice/dependency-security.json +91 -0
  29. package/bundles/expo-mobile/.lattice/prompts/01-feature.md +36 -0
  30. package/bundles/expo-mobile/.lattice/prompts/02-bugfix.md +32 -0
  31. package/bundles/expo-mobile/.lattice/prompts/03-refactor.md +30 -0
  32. package/bundles/expo-mobile/.lattice/prompts/04-test.md +31 -0
  33. package/bundles/expo-mobile/.lattice/prompts/05-polish.md +38 -0
  34. package/bundles/expo-mobile/.lattice/prompts/06-security.md +32 -0
  35. package/bundles/expo-mobile/.lattice/release-workflow.json +55 -0
  36. package/bundles/expo-mobile/.lattice/schemas/feature-handoff.schema.json +264 -0
  37. package/bundles/expo-mobile/.lattice/templates/feature-handoff.json +52 -0
  38. package/bundles/expo-mobile/.mcp.json +35 -0
  39. package/bundles/expo-mobile/AGENTS.md +58 -0
  40. package/bundles/expo-mobile/CLAUDE.md +75 -0
  41. package/bundles/expo-mobile/PROJECT_GUIDE.md +299 -0
  42. package/bundles/expo-mobile/README.md +39 -0
  43. package/bundles/expo-mobile/__tests__/home.test.tsx +22 -0
  44. package/bundles/expo-mobile/app/_layout.tsx +20 -0
  45. package/bundles/expo-mobile/app/index.tsx +72 -0
  46. package/bundles/expo-mobile/app.json +33 -0
  47. package/bundles/expo-mobile/components/ui/Button.tsx +75 -0
  48. package/bundles/expo-mobile/components/ui/Input.tsx +50 -0
  49. package/bundles/expo-mobile/components/ui/index.ts +2 -0
  50. package/bundles/expo-mobile/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
  51. package/bundles/expo-mobile/docs/rules/codex.md +62 -0
  52. package/bundles/expo-mobile/eslint.config.js +7 -0
  53. package/bundles/expo-mobile/lib/supabase/client.ts +22 -0
  54. package/bundles/expo-mobile/lib/supabase/realtime.ts +10 -0
  55. package/bundles/expo-mobile/lib/supabase/storage.ts +6 -0
  56. package/bundles/expo-mobile/package.json +65 -0
  57. package/bundles/expo-mobile/plugins/with-lattice-commons-io.cjs +42 -0
  58. package/bundles/expo-mobile/prompts/01-feature-implementation.md +48 -0
  59. package/bundles/expo-mobile/prompts/02-bug-fix.md +43 -0
  60. package/bundles/expo-mobile/prompts/03-safe-refactor.md +38 -0
  61. package/bundles/expo-mobile/prompts/04-test-first.md +41 -0
  62. package/bundles/expo-mobile/prompts/05-ui-polish.md +44 -0
  63. package/bundles/expo-mobile/prompts/06-security-review.md +39 -0
  64. package/bundles/expo-mobile/prompts/quality.md +143 -0
  65. package/bundles/expo-mobile/supabase/migrations/001_initial_schema.sql +66 -0
  66. package/bundles/expo-mobile/tsconfig.json +21 -0
  67. package/bundles/expo-mobile/types/database.types.ts +76 -0
  68. package/bundles/expo-mobile/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
  69. package/bundles/expo-supabase/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
  70. package/bundles/expo-supabase/.agents/skills/lattice-release-manager/SKILL.md +29 -0
  71. package/bundles/expo-supabase/.agents/skills/lattice-verify/SKILL.md +27 -0
  72. package/bundles/expo-supabase/.claude/agents/lattice-feature-agent.md +10 -0
  73. package/bundles/expo-supabase/.claude/agents/lattice-release-manager.md +9 -0
  74. package/bundles/expo-supabase/.claude/hooks/README.md +9 -0
  75. package/bundles/expo-supabase/.claude/hooks/pre-commit-verify.mjs +10 -0
  76. package/bundles/expo-supabase/.claude/hooks/pre-tool-use.mjs +51 -0
  77. package/bundles/expo-supabase/.claude/rules/lattice-core.md +20 -0
  78. package/bundles/expo-supabase/.claude/settings.json +38 -0
  79. package/bundles/expo-supabase/.claude/skills/lattice-verify/SKILL.md +27 -0
  80. package/bundles/expo-supabase/.codex/agents/lattice-feature-agent.toml +9 -0
  81. package/bundles/expo-supabase/.codex/agents/lattice-release-manager.toml +9 -0
  82. package/bundles/expo-supabase/.cursor/mcp.json +34 -0
  83. package/bundles/expo-supabase/.cursor/rules/lattice-core.mdc +35 -0
  84. package/bundles/expo-supabase/.cursor/rules.md +94 -0
  85. package/bundles/expo-supabase/.env.example +12 -0
  86. package/bundles/expo-supabase/.github/PULL_REQUEST_TEMPLATE.md +42 -0
  87. package/bundles/expo-supabase/.github/agents/lattice-feature-agent.agent.md +7 -0
  88. package/bundles/expo-supabase/.github/agents/lattice-release-manager.agent.md +7 -0
  89. package/bundles/expo-supabase/.github/copilot-instructions.md +37 -0
  90. package/bundles/expo-supabase/.github/instructions/lattice-core.instructions.md +11 -0
  91. package/bundles/expo-supabase/.github/workflows/ci.yml +26 -0
  92. package/bundles/expo-supabase/.gitmessage +24 -0
  93. package/bundles/expo-supabase/.lattice/config.json +9 -0
  94. package/bundles/expo-supabase/.lattice/dependency-security.json +91 -0
  95. package/bundles/expo-supabase/.lattice/prompts/01-feature.md +36 -0
  96. package/bundles/expo-supabase/.lattice/prompts/02-bugfix.md +32 -0
  97. package/bundles/expo-supabase/.lattice/prompts/03-refactor.md +30 -0
  98. package/bundles/expo-supabase/.lattice/prompts/04-test.md +31 -0
  99. package/bundles/expo-supabase/.lattice/prompts/05-polish.md +38 -0
  100. package/bundles/expo-supabase/.lattice/prompts/06-security.md +32 -0
  101. package/bundles/expo-supabase/.lattice/release-workflow.json +55 -0
  102. package/bundles/expo-supabase/.lattice/schemas/feature-handoff.schema.json +264 -0
  103. package/bundles/expo-supabase/.lattice/templates/feature-handoff.json +52 -0
  104. package/bundles/expo-supabase/.mcp.json +35 -0
  105. package/bundles/expo-supabase/AGENTS.md +58 -0
  106. package/bundles/expo-supabase/CLAUDE.md +75 -0
  107. package/bundles/expo-supabase/PROJECT_GUIDE.md +201 -0
  108. package/bundles/expo-supabase/README.md +38 -0
  109. package/bundles/expo-supabase/__tests__/home.test.tsx +22 -0
  110. package/bundles/expo-supabase/app/_layout.tsx +14 -0
  111. package/bundles/expo-supabase/app/index.tsx +72 -0
  112. package/bundles/expo-supabase/app.json +33 -0
  113. package/bundles/expo-supabase/components/ui/Button.tsx +75 -0
  114. package/bundles/expo-supabase/components/ui/Input.tsx +50 -0
  115. package/bundles/expo-supabase/components/ui/index.ts +2 -0
  116. package/bundles/expo-supabase/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
  117. package/bundles/expo-supabase/docs/rules/codex.md +62 -0
  118. package/bundles/expo-supabase/eslint.config.js +7 -0
  119. package/bundles/expo-supabase/lib/supabase/client.ts +22 -0
  120. package/bundles/expo-supabase/lib/supabase/realtime.ts +10 -0
  121. package/bundles/expo-supabase/lib/supabase/storage.ts +6 -0
  122. package/bundles/expo-supabase/package.json +60 -0
  123. package/bundles/expo-supabase/plugins/with-lattice-commons-io.cjs +42 -0
  124. package/bundles/expo-supabase/prompts/01-feature-implementation.md +8 -0
  125. package/bundles/expo-supabase/prompts/02-bug-fix.md +9 -0
  126. package/bundles/expo-supabase/prompts/03-safe-refactor.md +8 -0
  127. package/bundles/expo-supabase/prompts/04-test-first.md +7 -0
  128. package/bundles/expo-supabase/prompts/05-ui-polish.md +7 -0
  129. package/bundles/expo-supabase/prompts/06-security-review.md +7 -0
  130. package/bundles/expo-supabase/prompts/quality.md +143 -0
  131. package/bundles/expo-supabase/supabase/migrations/001_initial_schema.sql +66 -0
  132. package/bundles/expo-supabase/tsconfig.json +21 -0
  133. package/bundles/expo-supabase/types/database.types.ts +76 -0
  134. package/bundles/expo-supabase/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
  135. package/bundles/nextjs-landing/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
  136. package/bundles/nextjs-landing/.agents/skills/lattice-release-manager/SKILL.md +29 -0
  137. package/bundles/nextjs-landing/.agents/skills/lattice-verify/SKILL.md +27 -0
  138. package/bundles/nextjs-landing/.claude/agents/lattice-feature-agent.md +10 -0
  139. package/bundles/nextjs-landing/.claude/agents/lattice-release-manager.md +9 -0
  140. package/bundles/nextjs-landing/.claude/hooks/README.md +9 -0
  141. package/bundles/nextjs-landing/.claude/hooks/pre-commit-verify.mjs +10 -0
  142. package/bundles/nextjs-landing/.claude/hooks/pre-tool-use.mjs +51 -0
  143. package/bundles/nextjs-landing/.claude/rules/lattice-core.md +20 -0
  144. package/bundles/nextjs-landing/.claude/settings.json +38 -0
  145. package/bundles/nextjs-landing/.claude/skills/lattice-verify/SKILL.md +27 -0
  146. package/bundles/nextjs-landing/.codex/agents/lattice-feature-agent.toml +9 -0
  147. package/bundles/nextjs-landing/.codex/agents/lattice-release-manager.toml +9 -0
  148. package/bundles/nextjs-landing/.cursor/mcp.json +34 -0
  149. package/bundles/nextjs-landing/.cursor/rules/lattice-core.mdc +35 -0
  150. package/bundles/nextjs-landing/.cursor/rules.md +95 -0
  151. package/bundles/nextjs-landing/.env.example +24 -0
  152. package/bundles/nextjs-landing/.github/PULL_REQUEST_TEMPLATE.md +42 -0
  153. package/bundles/nextjs-landing/.github/agents/lattice-feature-agent.agent.md +7 -0
  154. package/bundles/nextjs-landing/.github/agents/lattice-release-manager.agent.md +7 -0
  155. package/bundles/nextjs-landing/.github/copilot-instructions.md +37 -0
  156. package/bundles/nextjs-landing/.github/instructions/lattice-core.instructions.md +11 -0
  157. package/bundles/nextjs-landing/.github/workflows/ci.yml +26 -0
  158. package/bundles/nextjs-landing/.gitmessage +24 -0
  159. package/bundles/nextjs-landing/.lattice/config.json +9 -0
  160. package/bundles/nextjs-landing/.lattice/dependency-security.json +46 -0
  161. package/bundles/nextjs-landing/.lattice/prompts/01-feature.md +36 -0
  162. package/bundles/nextjs-landing/.lattice/prompts/02-bugfix.md +32 -0
  163. package/bundles/nextjs-landing/.lattice/prompts/03-refactor.md +30 -0
  164. package/bundles/nextjs-landing/.lattice/prompts/04-test.md +31 -0
  165. package/bundles/nextjs-landing/.lattice/prompts/05-polish.md +38 -0
  166. package/bundles/nextjs-landing/.lattice/prompts/06-security.md +32 -0
  167. package/bundles/nextjs-landing/.lattice/release-workflow.json +55 -0
  168. package/bundles/nextjs-landing/.lattice/schemas/feature-handoff.schema.json +264 -0
  169. package/bundles/nextjs-landing/.lattice/templates/feature-handoff.json +52 -0
  170. package/bundles/nextjs-landing/.mcp.json +35 -0
  171. package/bundles/nextjs-landing/AGENTS.md +58 -0
  172. package/bundles/nextjs-landing/CLAUDE.md +76 -0
  173. package/bundles/nextjs-landing/PROJECT_GUIDE.md +216 -0
  174. package/bundles/nextjs-landing/README.md +39 -0
  175. package/bundles/nextjs-landing/app/api/example/[id]/route.ts +34 -0
  176. package/bundles/nextjs-landing/app/api/example/route.ts +24 -0
  177. package/bundles/nextjs-landing/app/api/health/route.ts +8 -0
  178. package/bundles/nextjs-landing/app/global-error.tsx +17 -0
  179. package/bundles/nextjs-landing/app/globals.css +55 -0
  180. package/bundles/nextjs-landing/app/layout.tsx +22 -0
  181. package/bundles/nextjs-landing/app/page.tsx +42 -0
  182. package/bundles/nextjs-landing/components/ui/button.tsx +39 -0
  183. package/bundles/nextjs-landing/components/ui/card.tsx +53 -0
  184. package/bundles/nextjs-landing/components/ui/index.ts +4 -0
  185. package/bundles/nextjs-landing/components/ui/input.tsx +23 -0
  186. package/bundles/nextjs-landing/components/ui/spinner.tsx +22 -0
  187. package/bundles/nextjs-landing/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
  188. package/bundles/nextjs-landing/docs/rules/codex.md +62 -0
  189. package/bundles/nextjs-landing/eslint.config.mjs +16 -0
  190. package/bundles/nextjs-landing/instrumentation-client.ts +30 -0
  191. package/bundles/nextjs-landing/instrumentation.ts +12 -0
  192. package/bundles/nextjs-landing/jest.config.mjs +16 -0
  193. package/bundles/nextjs-landing/jest.setup.js +1 -0
  194. package/bundles/nextjs-landing/lib/utils.ts +6 -0
  195. package/bundles/nextjs-landing/next-env.d.ts +5 -0
  196. package/bundles/nextjs-landing/next.config.ts +15 -0
  197. package/bundles/nextjs-landing/package.json +48 -0
  198. package/bundles/nextjs-landing/postcss.config.mjs +7 -0
  199. package/bundles/nextjs-landing/prompts/01-feature-implementation.md +9 -0
  200. package/bundles/nextjs-landing/prompts/02-bug-fix.md +10 -0
  201. package/bundles/nextjs-landing/prompts/03-safe-refactor.md +8 -0
  202. package/bundles/nextjs-landing/prompts/04-test-first.md +8 -0
  203. package/bundles/nextjs-landing/prompts/05-ui-polish.md +8 -0
  204. package/bundles/nextjs-landing/prompts/06-security-review.md +7 -0
  205. package/bundles/nextjs-landing/prompts/quality.md +269 -0
  206. package/bundles/nextjs-landing/sentry.edge.config.ts +15 -0
  207. package/bundles/nextjs-landing/sentry.server.config.ts +15 -0
  208. package/bundles/nextjs-landing/tsconfig.json +42 -0
  209. package/bundles/nextjs-landing/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
  210. package/bundles/nextjs-saas/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
  211. package/bundles/nextjs-saas/.agents/skills/lattice-release-manager/SKILL.md +29 -0
  212. package/bundles/nextjs-saas/.agents/skills/lattice-verify/SKILL.md +27 -0
  213. package/bundles/nextjs-saas/.claude/agents/lattice-feature-agent.md +10 -0
  214. package/bundles/nextjs-saas/.claude/agents/lattice-release-manager.md +9 -0
  215. package/bundles/nextjs-saas/.claude/hooks/README.md +9 -0
  216. package/bundles/nextjs-saas/.claude/hooks/pre-commit-verify.mjs +10 -0
  217. package/bundles/nextjs-saas/.claude/hooks/pre-tool-use.mjs +51 -0
  218. package/bundles/nextjs-saas/.claude/rules/lattice-core.md +20 -0
  219. package/bundles/nextjs-saas/.claude/settings.json +38 -0
  220. package/bundles/nextjs-saas/.claude/skills/lattice-verify/SKILL.md +27 -0
  221. package/bundles/nextjs-saas/.codex/agents/lattice-feature-agent.toml +9 -0
  222. package/bundles/nextjs-saas/.codex/agents/lattice-release-manager.toml +9 -0
  223. package/bundles/nextjs-saas/.cursor/mcp.json +34 -0
  224. package/bundles/nextjs-saas/.cursor/rules/lattice-core.mdc +35 -0
  225. package/bundles/nextjs-saas/.cursor/rules.md +95 -0
  226. package/bundles/nextjs-saas/.env.example +48 -0
  227. package/bundles/nextjs-saas/.github/PULL_REQUEST_TEMPLATE.md +42 -0
  228. package/bundles/nextjs-saas/.github/agents/lattice-feature-agent.agent.md +7 -0
  229. package/bundles/nextjs-saas/.github/agents/lattice-release-manager.agent.md +7 -0
  230. package/bundles/nextjs-saas/.github/copilot-instructions.md +37 -0
  231. package/bundles/nextjs-saas/.github/instructions/lattice-core.instructions.md +11 -0
  232. package/bundles/nextjs-saas/.github/workflows/ci.yml +26 -0
  233. package/bundles/nextjs-saas/.gitmessage +24 -0
  234. package/bundles/nextjs-saas/.lattice/config.json +9 -0
  235. package/bundles/nextjs-saas/.lattice/dependency-security.json +46 -0
  236. package/bundles/nextjs-saas/.lattice/prompts/01-feature.md +36 -0
  237. package/bundles/nextjs-saas/.lattice/prompts/02-bugfix.md +32 -0
  238. package/bundles/nextjs-saas/.lattice/prompts/03-refactor.md +30 -0
  239. package/bundles/nextjs-saas/.lattice/prompts/04-test.md +31 -0
  240. package/bundles/nextjs-saas/.lattice/prompts/05-polish.md +38 -0
  241. package/bundles/nextjs-saas/.lattice/prompts/06-security.md +32 -0
  242. package/bundles/nextjs-saas/.lattice/prompts/quality.md +269 -0
  243. package/bundles/nextjs-saas/.lattice/release-workflow.json +55 -0
  244. package/bundles/nextjs-saas/.lattice/schemas/feature-handoff.schema.json +264 -0
  245. package/bundles/nextjs-saas/.lattice/templates/feature-handoff.json +52 -0
  246. package/bundles/nextjs-saas/.mcp.json +35 -0
  247. package/bundles/nextjs-saas/AGENTS.md +58 -0
  248. package/bundles/nextjs-saas/CLAUDE.md +76 -0
  249. package/bundles/nextjs-saas/PROJECT_GUIDE.md +279 -0
  250. package/bundles/nextjs-saas/README.md +42 -0
  251. package/bundles/nextjs-saas/app/(auth)/forgot-password/page.tsx +101 -0
  252. package/bundles/nextjs-saas/app/(auth)/layout.tsx +7 -0
  253. package/bundles/nextjs-saas/app/(auth)/login/page.tsx +108 -0
  254. package/bundles/nextjs-saas/app/(auth)/reset-password/page.tsx +135 -0
  255. package/bundles/nextjs-saas/app/(auth)/signup/page.tsx +144 -0
  256. package/bundles/nextjs-saas/app/(dashboard)/dashboard/page.tsx +80 -0
  257. package/bundles/nextjs-saas/app/(dashboard)/layout.tsx +49 -0
  258. package/bundles/nextjs-saas/app/api/billing/checkout/route.ts +47 -0
  259. package/bundles/nextjs-saas/app/api/billing/portal/route.ts +29 -0
  260. package/bundles/nextjs-saas/app/api/example/[id]/route.ts +93 -0
  261. package/bundles/nextjs-saas/app/api/example/route.ts +61 -0
  262. package/bundles/nextjs-saas/app/api/health/route.ts +8 -0
  263. package/bundles/nextjs-saas/app/api/stripe/webhook/route.ts +57 -0
  264. package/bundles/nextjs-saas/app/api/user/route.ts +49 -0
  265. package/bundles/nextjs-saas/app/auth/callback/route.ts +16 -0
  266. package/bundles/nextjs-saas/app/auth/signout/route.ts +10 -0
  267. package/bundles/nextjs-saas/app/global-error.tsx +17 -0
  268. package/bundles/nextjs-saas/app/globals.css +55 -0
  269. package/bundles/nextjs-saas/app/layout.tsx +22 -0
  270. package/bundles/nextjs-saas/app/page.tsx +84 -0
  271. package/bundles/nextjs-saas/components/ui/button.tsx +39 -0
  272. package/bundles/nextjs-saas/components/ui/card.tsx +53 -0
  273. package/bundles/nextjs-saas/components/ui/index.ts +4 -0
  274. package/bundles/nextjs-saas/components/ui/input.tsx +23 -0
  275. package/bundles/nextjs-saas/components/ui/spinner.tsx +22 -0
  276. package/bundles/nextjs-saas/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
  277. package/bundles/nextjs-saas/docs/rules/codex.md +62 -0
  278. package/bundles/nextjs-saas/eslint.config.mjs +16 -0
  279. package/bundles/nextjs-saas/instrumentation-client.ts +30 -0
  280. package/bundles/nextjs-saas/instrumentation.ts +12 -0
  281. package/bundles/nextjs-saas/jest.config.mjs +16 -0
  282. package/bundles/nextjs-saas/jest.setup.js +1 -0
  283. package/bundles/nextjs-saas/lib/auth/password-recovery.ts +94 -0
  284. package/bundles/nextjs-saas/lib/stripe.ts +10 -0
  285. package/bundles/nextjs-saas/lib/supabase/admin.ts +14 -0
  286. package/bundles/nextjs-saas/lib/supabase/client.ts +8 -0
  287. package/bundles/nextjs-saas/lib/supabase/server.ts +27 -0
  288. package/bundles/nextjs-saas/lib/utils.ts +6 -0
  289. package/bundles/nextjs-saas/next-env.d.ts +5 -0
  290. package/bundles/nextjs-saas/next.config.ts +15 -0
  291. package/bundles/nextjs-saas/package.json +50 -0
  292. package/bundles/nextjs-saas/postcss.config.mjs +7 -0
  293. package/bundles/nextjs-saas/prompts/01-feature-implementation.md +92 -0
  294. package/bundles/nextjs-saas/prompts/02-bug-fix.md +78 -0
  295. package/bundles/nextjs-saas/prompts/03-safe-refactor.md +82 -0
  296. package/bundles/nextjs-saas/prompts/04-test-first.md +80 -0
  297. package/bundles/nextjs-saas/prompts/05-ui-polish.md +82 -0
  298. package/bundles/nextjs-saas/prompts/06-security-review.md +74 -0
  299. package/bundles/nextjs-saas/proxy.ts +61 -0
  300. package/bundles/nextjs-saas/sentry.edge.config.ts +15 -0
  301. package/bundles/nextjs-saas/sentry.server.config.ts +15 -0
  302. package/bundles/nextjs-saas/supabase/migrations/001_initial_schema.sql +66 -0
  303. package/bundles/nextjs-saas/supabase/migrations/002_billing.sql +17 -0
  304. package/bundles/nextjs-saas/tsconfig.json +42 -0
  305. package/bundles/nextjs-saas/types/database.types.ts +76 -0
  306. package/bundles/nextjs-saas/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
  307. package/bundles/nextjs-trpc/.agents/skills/lattice-feature-handoff/SKILL.md +31 -0
  308. package/bundles/nextjs-trpc/.agents/skills/lattice-release-manager/SKILL.md +29 -0
  309. package/bundles/nextjs-trpc/.agents/skills/lattice-verify/SKILL.md +27 -0
  310. package/bundles/nextjs-trpc/.claude/agents/lattice-feature-agent.md +10 -0
  311. package/bundles/nextjs-trpc/.claude/agents/lattice-release-manager.md +9 -0
  312. package/bundles/nextjs-trpc/.claude/hooks/README.md +9 -0
  313. package/bundles/nextjs-trpc/.claude/hooks/pre-commit-verify.mjs +10 -0
  314. package/bundles/nextjs-trpc/.claude/hooks/pre-tool-use.mjs +51 -0
  315. package/bundles/nextjs-trpc/.claude/rules/lattice-core.md +20 -0
  316. package/bundles/nextjs-trpc/.claude/settings.json +38 -0
  317. package/bundles/nextjs-trpc/.claude/skills/lattice-verify/SKILL.md +27 -0
  318. package/bundles/nextjs-trpc/.codex/agents/lattice-feature-agent.toml +9 -0
  319. package/bundles/nextjs-trpc/.codex/agents/lattice-release-manager.toml +9 -0
  320. package/bundles/nextjs-trpc/.cursor/mcp.json +34 -0
  321. package/bundles/nextjs-trpc/.cursor/rules/lattice-core.mdc +35 -0
  322. package/bundles/nextjs-trpc/.cursor/rules.md +95 -0
  323. package/bundles/nextjs-trpc/.env.example +21 -0
  324. package/bundles/nextjs-trpc/.github/PULL_REQUEST_TEMPLATE.md +42 -0
  325. package/bundles/nextjs-trpc/.github/agents/lattice-feature-agent.agent.md +7 -0
  326. package/bundles/nextjs-trpc/.github/agents/lattice-release-manager.agent.md +7 -0
  327. package/bundles/nextjs-trpc/.github/copilot-instructions.md +37 -0
  328. package/bundles/nextjs-trpc/.github/instructions/lattice-core.instructions.md +11 -0
  329. package/bundles/nextjs-trpc/.github/workflows/ci.yml +26 -0
  330. package/bundles/nextjs-trpc/.gitmessage +24 -0
  331. package/bundles/nextjs-trpc/.lattice/config.json +9 -0
  332. package/bundles/nextjs-trpc/.lattice/dependency-security.json +46 -0
  333. package/bundles/nextjs-trpc/.lattice/prompts/01-feature.md +36 -0
  334. package/bundles/nextjs-trpc/.lattice/prompts/02-bugfix.md +32 -0
  335. package/bundles/nextjs-trpc/.lattice/prompts/03-refactor.md +30 -0
  336. package/bundles/nextjs-trpc/.lattice/prompts/04-test.md +31 -0
  337. package/bundles/nextjs-trpc/.lattice/prompts/05-polish.md +38 -0
  338. package/bundles/nextjs-trpc/.lattice/prompts/06-security.md +32 -0
  339. package/bundles/nextjs-trpc/.lattice/release-workflow.json +55 -0
  340. package/bundles/nextjs-trpc/.lattice/schemas/feature-handoff.schema.json +264 -0
  341. package/bundles/nextjs-trpc/.lattice/templates/feature-handoff.json +52 -0
  342. package/bundles/nextjs-trpc/.mcp.json +35 -0
  343. package/bundles/nextjs-trpc/AGENTS.md +58 -0
  344. package/bundles/nextjs-trpc/CLAUDE.md +76 -0
  345. package/bundles/nextjs-trpc/PROJECT_GUIDE.md +187 -0
  346. package/bundles/nextjs-trpc/README.md +49 -0
  347. package/bundles/nextjs-trpc/app/api/trpc/[trpc]/route.ts +12 -0
  348. package/bundles/nextjs-trpc/app/global-error.tsx +17 -0
  349. package/bundles/nextjs-trpc/app/globals.css +55 -0
  350. package/bundles/nextjs-trpc/app/layout.tsx +19 -0
  351. package/bundles/nextjs-trpc/app/page.tsx +16 -0
  352. package/bundles/nextjs-trpc/app/providers.tsx +24 -0
  353. package/bundles/nextjs-trpc/components/ui/button.tsx +39 -0
  354. package/bundles/nextjs-trpc/components/ui/card.tsx +53 -0
  355. package/bundles/nextjs-trpc/components/ui/index.ts +4 -0
  356. package/bundles/nextjs-trpc/components/ui/input.tsx +23 -0
  357. package/bundles/nextjs-trpc/components/ui/spinner.tsx +22 -0
  358. package/bundles/nextjs-trpc/components/user-list.tsx +17 -0
  359. package/bundles/nextjs-trpc/docs/LATTICE_RELEASE_WORKFLOW.md +53 -0
  360. package/bundles/nextjs-trpc/docs/rules/codex.md +62 -0
  361. package/bundles/nextjs-trpc/eslint.config.mjs +16 -0
  362. package/bundles/nextjs-trpc/instrumentation-client.ts +20 -0
  363. package/bundles/nextjs-trpc/instrumentation.ts +12 -0
  364. package/bundles/nextjs-trpc/jest.config.mjs +16 -0
  365. package/bundles/nextjs-trpc/jest.setup.js +1 -0
  366. package/bundles/nextjs-trpc/lib/db.ts +17 -0
  367. package/bundles/nextjs-trpc/lib/trpc/react.tsx +7 -0
  368. package/bundles/nextjs-trpc/lib/utils.ts +6 -0
  369. package/bundles/nextjs-trpc/next-env.d.ts +5 -0
  370. package/bundles/nextjs-trpc/next.config.ts +15 -0
  371. package/bundles/nextjs-trpc/package.json +62 -0
  372. package/bundles/nextjs-trpc/postcss.config.mjs +7 -0
  373. package/bundles/nextjs-trpc/prisma/schema.prisma +41 -0
  374. package/bundles/nextjs-trpc/prisma.config.ts +10 -0
  375. package/bundles/nextjs-trpc/prompts/01-feature-implementation.md +9 -0
  376. package/bundles/nextjs-trpc/prompts/02-bug-fix.md +9 -0
  377. package/bundles/nextjs-trpc/prompts/03-safe-refactor.md +8 -0
  378. package/bundles/nextjs-trpc/prompts/04-test-first.md +8 -0
  379. package/bundles/nextjs-trpc/prompts/05-ui-polish.md +7 -0
  380. package/bundles/nextjs-trpc/prompts/06-security-review.md +7 -0
  381. package/bundles/nextjs-trpc/prompts/quality.md +269 -0
  382. package/bundles/nextjs-trpc/sentry.edge.config.ts +15 -0
  383. package/bundles/nextjs-trpc/sentry.server.config.ts +15 -0
  384. package/bundles/nextjs-trpc/server/routers/_app.test.ts +60 -0
  385. package/bundles/nextjs-trpc/server/routers/_app.ts +25 -0
  386. package/bundles/nextjs-trpc/server/trpc.ts +12 -0
  387. package/bundles/nextjs-trpc/tsconfig.json +42 -0
  388. package/bundles/nextjs-trpc/vendor/m2ai-braces-3.0.3-m2ai.1.tar +0 -0
  389. package/dist/agent-install-session.d.ts +17 -0
  390. package/dist/agent-install-session.d.ts.map +1 -0
  391. package/dist/agent-install-session.js +106 -0
  392. package/dist/agent-install-session.js.map +1 -0
  393. package/dist/agent-install-session.test.d.ts +2 -0
  394. package/dist/agent-install-session.test.d.ts.map +1 -0
  395. package/dist/agent-install-session.test.js +62 -0
  396. package/dist/agent-install-session.test.js.map +1 -0
  397. package/dist/agent-install.d.ts +41 -0
  398. package/dist/agent-install.d.ts.map +1 -0
  399. package/dist/agent-install.js +42 -0
  400. package/dist/agent-install.js.map +1 -0
  401. package/dist/agent-install.test.d.ts +2 -0
  402. package/dist/agent-install.test.d.ts.map +1 -0
  403. package/dist/agent-install.test.js +58 -0
  404. package/dist/agent-install.test.js.map +1 -0
  405. package/dist/apply-merge.test.d.ts +2 -0
  406. package/dist/apply-merge.test.d.ts.map +1 -0
  407. package/dist/apply-merge.test.js +123 -0
  408. package/dist/apply-merge.test.js.map +1 -0
  409. package/dist/bundle-download.d.ts +23 -0
  410. package/dist/bundle-download.d.ts.map +1 -0
  411. package/dist/bundle-download.js +180 -0
  412. package/dist/bundle-download.js.map +1 -0
  413. package/dist/bundle-download.test.d.ts +2 -0
  414. package/dist/bundle-download.test.d.ts.map +1 -0
  415. package/dist/bundle-download.test.js +200 -0
  416. package/dist/bundle-download.test.js.map +1 -0
  417. package/dist/bundle-rollback.test.d.ts +2 -0
  418. package/dist/bundle-rollback.test.d.ts.map +1 -0
  419. package/dist/bundle-rollback.test.js +127 -0
  420. package/dist/bundle-rollback.test.js.map +1 -0
  421. package/dist/bundle-scaffold.test.d.ts +2 -0
  422. package/dist/bundle-scaffold.test.d.ts.map +1 -0
  423. package/dist/bundle-scaffold.test.js +105 -0
  424. package/dist/bundle-scaffold.test.js.map +1 -0
  425. package/dist/commands.d.ts +132 -0
  426. package/dist/commands.d.ts.map +1 -0
  427. package/dist/commands.js +2012 -0
  428. package/dist/commands.js.map +1 -0
  429. package/dist/credential-store.d.ts +27 -0
  430. package/dist/credential-store.d.ts.map +1 -0
  431. package/dist/credential-store.js +48 -0
  432. package/dist/credential-store.js.map +1 -0
  433. package/dist/credential-store.test.d.ts +2 -0
  434. package/dist/credential-store.test.d.ts.map +1 -0
  435. package/dist/credential-store.test.js +80 -0
  436. package/dist/credential-store.test.js.map +1 -0
  437. package/dist/delivered-project-files.d.ts +31 -0
  438. package/dist/delivered-project-files.d.ts.map +1 -0
  439. package/dist/delivered-project-files.js +158 -0
  440. package/dist/delivered-project-files.js.map +1 -0
  441. package/dist/delivered-project-files.test.d.ts +2 -0
  442. package/dist/delivered-project-files.test.d.ts.map +1 -0
  443. package/dist/delivered-project-files.test.js +107 -0
  444. package/dist/delivered-project-files.test.js.map +1 -0
  445. package/dist/doctor-agents.test.d.ts +2 -0
  446. package/dist/doctor-agents.test.d.ts.map +1 -0
  447. package/dist/doctor-agents.test.js +65 -0
  448. package/dist/doctor-agents.test.js.map +1 -0
  449. package/dist/hermes-install.d.ts +102 -0
  450. package/dist/hermes-install.d.ts.map +1 -0
  451. package/dist/hermes-install.js +641 -0
  452. package/dist/hermes-install.js.map +1 -0
  453. package/dist/hermes-install.test.d.ts +2 -0
  454. package/dist/hermes-install.test.d.ts.map +1 -0
  455. package/dist/hermes-install.test.js +866 -0
  456. package/dist/hermes-install.test.js.map +1 -0
  457. package/dist/index.d.ts +115 -0
  458. package/dist/index.d.ts.map +1 -0
  459. package/dist/index.js +5311 -0
  460. package/dist/index.js.map +1 -0
  461. package/dist/openclaw-install.d.ts +67 -0
  462. package/dist/openclaw-install.d.ts.map +1 -0
  463. package/dist/openclaw-install.js +358 -0
  464. package/dist/openclaw-install.js.map +1 -0
  465. package/dist/openclaw-install.test.d.ts +2 -0
  466. package/dist/openclaw-install.test.d.ts.map +1 -0
  467. package/dist/openclaw-install.test.js +296 -0
  468. package/dist/openclaw-install.test.js.map +1 -0
  469. package/dist/password-recovery-bundle.test.d.ts +2 -0
  470. package/dist/password-recovery-bundle.test.d.ts.map +1 -0
  471. package/dist/password-recovery-bundle.test.js +132 -0
  472. package/dist/password-recovery-bundle.test.js.map +1 -0
  473. package/dist/project-bundle-env.d.ts +19 -0
  474. package/dist/project-bundle-env.d.ts.map +1 -0
  475. package/dist/project-bundle-env.js +111 -0
  476. package/dist/project-bundle-env.js.map +1 -0
  477. package/dist/project-bundle-env.test.d.ts +2 -0
  478. package/dist/project-bundle-env.test.d.ts.map +1 -0
  479. package/dist/project-bundle-env.test.js +93 -0
  480. package/dist/project-bundle-env.test.js.map +1 -0
  481. package/dist/project-path-confinement.test.d.ts +2 -0
  482. package/dist/project-path-confinement.test.d.ts.map +1 -0
  483. package/dist/project-path-confinement.test.js +222 -0
  484. package/dist/project-path-confinement.test.js.map +1 -0
  485. package/dist/security/api.d.ts +18 -0
  486. package/dist/security/api.d.ts.map +1 -0
  487. package/dist/security/api.js +238 -0
  488. package/dist/security/api.js.map +1 -0
  489. package/dist/security/api.test.d.ts +2 -0
  490. package/dist/security/api.test.d.ts.map +1 -0
  491. package/dist/security/api.test.js +220 -0
  492. package/dist/security/api.test.js.map +1 -0
  493. package/dist/security/artifact.d.ts +10 -0
  494. package/dist/security/artifact.d.ts.map +1 -0
  495. package/dist/security/artifact.js +283 -0
  496. package/dist/security/artifact.js.map +1 -0
  497. package/dist/security/artifact.test.d.ts +2 -0
  498. package/dist/security/artifact.test.d.ts.map +1 -0
  499. package/dist/security/artifact.test.js +229 -0
  500. package/dist/security/artifact.test.js.map +1 -0
  501. package/dist/security/commands.d.ts +42 -0
  502. package/dist/security/commands.d.ts.map +1 -0
  503. package/dist/security/commands.js +825 -0
  504. package/dist/security/commands.js.map +1 -0
  505. package/dist/security/commands.test.d.ts +2 -0
  506. package/dist/security/commands.test.d.ts.map +1 -0
  507. package/dist/security/commands.test.js +1051 -0
  508. package/dist/security/commands.test.js.map +1 -0
  509. package/dist/security/connection.d.ts +19 -0
  510. package/dist/security/connection.d.ts.map +1 -0
  511. package/dist/security/connection.js +145 -0
  512. package/dist/security/connection.js.map +1 -0
  513. package/dist/security/connection.test.d.ts +2 -0
  514. package/dist/security/connection.test.d.ts.map +1 -0
  515. package/dist/security/connection.test.js +62 -0
  516. package/dist/security/connection.test.js.map +1 -0
  517. package/dist/security/index-routing.test.d.ts +2 -0
  518. package/dist/security/index-routing.test.d.ts.map +1 -0
  519. package/dist/security/index-routing.test.js +169 -0
  520. package/dist/security/index-routing.test.js.map +1 -0
  521. package/dist/security/journal.d.ts +26 -0
  522. package/dist/security/journal.d.ts.map +1 -0
  523. package/dist/security/journal.js +441 -0
  524. package/dist/security/journal.js.map +1 -0
  525. package/dist/security/journal.test.d.ts +2 -0
  526. package/dist/security/journal.test.d.ts.map +1 -0
  527. package/dist/security/journal.test.js +226 -0
  528. package/dist/security/journal.test.js.map +1 -0
  529. package/dist/security/package-verifier.d.ts +15 -0
  530. package/dist/security/package-verifier.d.ts.map +1 -0
  531. package/dist/security/package-verifier.js +65 -0
  532. package/dist/security/package-verifier.js.map +1 -0
  533. package/dist/security/package-verifier.test.d.ts +2 -0
  534. package/dist/security/package-verifier.test.d.ts.map +1 -0
  535. package/dist/security/package-verifier.test.js +57 -0
  536. package/dist/security/package-verifier.test.js.map +1 -0
  537. package/dist/security/runtime.d.ts +43 -0
  538. package/dist/security/runtime.d.ts.map +1 -0
  539. package/dist/security/runtime.js +81 -0
  540. package/dist/security/runtime.js.map +1 -0
  541. package/dist/security/runtime.test.d.ts +2 -0
  542. package/dist/security/runtime.test.d.ts.map +1 -0
  543. package/dist/security/runtime.test.js +88 -0
  544. package/dist/security/runtime.test.js.map +1 -0
  545. package/dist/security/types.d.ts +169 -0
  546. package/dist/security/types.d.ts.map +1 -0
  547. package/dist/security/types.js +3 -0
  548. package/dist/security/types.js.map +1 -0
  549. package/dist/security-runtime/LICENSE +202 -0
  550. package/dist/security-runtime/NOTICE +16 -0
  551. package/dist/security-runtime/artifact-manifest.json +960 -0
  552. package/dist/security-runtime/bin/vsg.mjs +5 -0
  553. package/dist/security-runtime/lattice-catalog.json +176585 -0
  554. package/dist/security-runtime/lattice-runtime.mjs +90 -0
  555. package/dist/security-runtime/licensing/candidates/apache-source-license-evidence.json +478 -0
  556. package/dist/security-runtime/licensing/candidates/betterleaks-generic-api-key.json +76 -0
  557. package/dist/security-runtime/licensing/candidates/betterleaks-jwt.json +74 -0
  558. package/dist/security-runtime/licensing/candidates/blackberry-additional-source-declaration-evidence.json +276 -0
  559. package/dist/security-runtime/licensing/candidates/blackberry-source-declaration-evidence.json +369 -0
  560. package/dist/security-runtime/licensing/candidates/cado-source-declaration-evidence.json +283 -0
  561. package/dist/security-runtime/licensing/candidates/commercial-rule-candidate.json +280 -0
  562. package/dist/security-runtime/licensing/candidates/commercial-runtime-release.json +389 -0
  563. package/dist/security-runtime/licensing/candidates/data-feed-evidence.json +259 -0
  564. package/dist/security-runtime/licensing/candidates/gitlab-sast-rule-identities.json +178 -0
  565. package/dist/security-runtime/licensing/candidates/gitlab-sast-source-evidence.json +1824 -0
  566. package/dist/security-runtime/licensing/candidates/gitlab-sast-source-notice-bundle.json +45 -0
  567. package/dist/security-runtime/licensing/candidates/malpedia-source-license-evidence.json +41 -0
  568. package/dist/security-runtime/licensing/candidates/rule-license-evidence.json +376 -0
  569. package/dist/security-runtime/licensing/candidates/runner-image-composition.json +1500 -0
  570. package/dist/security-runtime/licensing/candidates/selected-runtime-coverage.json +91 -0
  571. package/dist/security-runtime/licensing/candidates/yara-forge-20260927.json +58502 -0
  572. package/dist/security-runtime/licensing/commercial-components.json +379 -0
  573. package/dist/security-runtime/licensing/notices/betterleaks-1.9.0-MIT.txt +21 -0
  574. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/28a9529c7d0bb4dc51f4bf5c116a3d16ef247a052f7591466768ddf563fd1cf5.txt +428 -0
  575. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/33acf42afdd03163d75fe856cb431e70710e0b5deede3362e6d1c4697cfe1c6a.txt +28 -0
  576. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/3972dc9744f6499f0f9b2dbf76696f2ae7ad8af9b23dde66d6af86c9dfb36986.txt +674 -0
  577. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/4fecb8fcaf80fd9a6315bca5225ee43377015b46a0459c2925495be885cab19a.txt +21 -0
  578. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/811515f8723aa4007de2fbb75a364127fdec51cda534b87a7ea8f2fef2f96dd7.txt +24 -0
  579. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/814442c3987a2c0411171ad8ad43118e8c08f85c9c5d1dcdecc9787c7ca8689b.txt +664 -0
  580. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/8a959b2413d0c83ca1b3ce9153076c649abf2e4bbfebbb493fb24c2074a1eb8a.txt +38 -0
  581. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/995182e185856186fbbe49f150409ae026aa4cda7e94f83c6ed737cbb77fa9c7.txt +23 -0
  582. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/9b8e1305e46d1dd4011b6ed933c9f6223e08c9c4625001c5fd75a34fa930f616.txt +202 -0
  583. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/a01f1a28424bfe7f49a23d339a01847cfa9ace3864d5e7295051772a4bae2271.txt +38 -0
  584. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/a5681bf9b05db14d86776930017c647ad9e6e56ff6bbcfdf21e5848288dfaf1b.txt +165 -0
  585. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/a5b8bd9ae96c630bbf229d61c5c5def20274e00be39abfd2fab4d7879ceab462.txt +24 -0
  586. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/ada32b3747ce108d5e8bab7918af94abbd03f2fe2a46304f74c6333bbfd914ed.txt +8 -0
  587. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4.txt +201 -0
  588. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/c738ae413cf561f174e34f6961f8ca458aae2369a73640dda6234c629b98bcc4.txt +2732 -0
  589. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/ce41c9a2c986277f7f9ab146a2195c1888a5d8da062e22d7c9c88666bb7c38cd.txt +17 -0
  590. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/d5f4c36a0528e01cfdd9e4fc60879201d3af49b41c520200643d321fe53da5f9.txt +17 -0
  591. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/e08c368ccd455f85c7fb9e04830e730f26e9dbb5c0f77bc88e09a5b0cb37df5b.txt +38 -0
  592. package/dist/security-runtime/licensing/notices/candidate-sources/sha256/e9efb2f7daf11bb6379c06c16b870dddcecc4a10f8704bb8aad807529c8b3c97.txt +8 -0
  593. package/dist/security-runtime/licensing/notices/gitleaks-generic-origin-782f3104-MIT.txt +21 -0
  594. package/dist/security-runtime/package.json +17 -0
  595. package/dist/security-runtime/playbook/README.md +76 -0
  596. package/dist/security-runtime/playbook/access-control.md +56 -0
  597. package/dist/security-runtime/playbook/ai-features.md +53 -0
  598. package/dist/security-runtime/playbook/desktop-python.md +59 -0
  599. package/dist/security-runtime/playbook/input-handling.md +59 -0
  600. package/dist/security-runtime/playbook/mobile-expo.md +59 -0
  601. package/dist/security-runtime/playbook/payments.md +53 -0
  602. package/dist/security-runtime/playbook/privacy-account-recovery.md +59 -0
  603. package/dist/security-runtime/playbook/secrets-config.md +47 -0
  604. package/dist/security-runtime/playbook/supabase.md +48 -0
  605. package/dist/security-runtime/playbook/supply-chain.md +62 -0
  606. package/dist/security-runtime/playbook/webhooks-integrations.md +52 -0
  607. package/dist/security-runtime/rules/vsg-ai-key-in-client.yaml +41 -0
  608. package/dist/security-runtime/rules/vsg-ai-output-raw-html.yaml +35 -0
  609. package/dist/security-runtime/rules/vsg-angular-sanitizer-bypass.yaml +23 -0
  610. package/dist/security-runtime/rules/vsg-expo-token-in-asyncstorage.yaml +22 -0
  611. package/dist/security-runtime/rules/vsg-flask-public-bind.yaml +32 -0
  612. package/dist/security-runtime/rules/vsg-nextjs-action-write-no-auth.yaml +144 -0
  613. package/dist/security-runtime/rules/vsg-nextjs-inline-action-write-no-auth.yaml +161 -0
  614. package/dist/security-runtime/rules/vsg-nextjs-route-write-no-auth.yaml +193 -0
  615. package/dist/security-runtime/rules/vsg-nosql-where-injection.yaml +36 -0
  616. package/dist/security-runtime/rules/vsg-python-pickle-load.yaml +26 -0
  617. package/dist/security-runtime/rules/vsg-python-requests-verify-false.yaml +34 -0
  618. package/dist/security-runtime/rules/vsg-python-subprocess-shell.yaml +23 -0
  619. package/dist/security-runtime/rules/vsg-stripe-client-price.yaml +51 -0
  620. package/dist/security-runtime/rules/vsg-stripe-webhook-no-signature.yaml +31 -0
  621. package/dist/security-runtime/rules/vsg-stripe-webhook-pages-no-signature.yaml +51 -0
  622. package/dist/security-runtime/rules/vsg-supabase-service-role-in-client.yaml +27 -0
  623. package/dist/security-runtime/rules/vsg-supabase-service-role-public-env.yaml +24 -0
  624. package/dist/security-runtime/rules/vsg-xml-external-entities.yaml +19 -0
  625. package/dist/security-runtime/src/agent/brief.mjs +95 -0
  626. package/dist/security-runtime/src/agent/discover.mjs +108 -0
  627. package/dist/security-runtime/src/agent/exec.mjs +64 -0
  628. package/dist/security-runtime/src/agent/ingest.mjs +213 -0
  629. package/dist/security-runtime/src/agent/report.mjs +94 -0
  630. package/dist/security-runtime/src/agent/schema.mjs +62 -0
  631. package/dist/security-runtime/src/agent/tokenize.mjs +38 -0
  632. package/dist/security-runtime/src/checks/README.md +8 -0
  633. package/dist/security-runtime/src/checks/_lib/gitfiles.mjs +35 -0
  634. package/dist/security-runtime/src/checks/_lib/lockfiles.mjs +135 -0
  635. package/dist/security-runtime/src/checks/_lib/osv.mjs +6 -0
  636. package/dist/security-runtime/src/checks/_lib/secrets.mjs +381 -0
  637. package/dist/security-runtime/src/checks/_lib/targets.mjs +79 -0
  638. package/dist/security-runtime/src/checks/agent-review/index.mjs +52 -0
  639. package/dist/security-runtime/src/checks/agent-surface/config.mjs +223 -0
  640. package/dist/security-runtime/src/checks/agent-surface/index.mjs +113 -0
  641. package/dist/security-runtime/src/checks/agent-surface/instructions.mjs +87 -0
  642. package/dist/security-runtime/src/checks/agent-surface/patterns.mjs +68 -0
  643. package/dist/security-runtime/src/checks/agent-surface/unicode.mjs +88 -0
  644. package/dist/security-runtime/src/checks/code/auth-helpers.mjs +659 -0
  645. package/dist/security-runtime/src/checks/code/index.mjs +617 -0
  646. package/dist/security-runtime/src/checks/code/opengrep-container.mjs +85 -0
  647. package/dist/security-runtime/src/checks/code/opengrep-runner.mjs +86 -0
  648. package/dist/security-runtime/src/checks/code/selected-opengrep-runner.mjs +112 -0
  649. package/dist/security-runtime/src/checks/dep-change/guarddog.mjs +142 -0
  650. package/dist/security-runtime/src/checks/dep-change/index.mjs +316 -0
  651. package/dist/security-runtime/src/checks/dep-change/registries.mjs +199 -0
  652. package/dist/security-runtime/src/checks/deps-vuln/index.mjs +305 -0
  653. package/dist/security-runtime/src/checks/desktop-config/index.mjs +112 -0
  654. package/dist/security-runtime/src/checks/dns-mail/index.mjs +71 -0
  655. package/dist/security-runtime/src/checks/iac/index.mjs +83 -0
  656. package/dist/security-runtime/src/checks/install-posture/index.mjs +123 -0
  657. package/dist/security-runtime/src/checks/licenses/index.mjs +143 -0
  658. package/dist/security-runtime/src/checks/live-basic/index.mjs +77 -0
  659. package/dist/security-runtime/src/checks/live-js-secrets/index.mjs +100 -0
  660. package/dist/security-runtime/src/checks/malware/clamav.mjs +17 -0
  661. package/dist/security-runtime/src/checks/malware/defender.mjs +43 -0
  662. package/dist/security-runtime/src/checks/malware/index.mjs +186 -0
  663. package/dist/security-runtime/src/checks/malware/targets.mjs +147 -0
  664. package/dist/security-runtime/src/checks/malware/yara-runner.mjs +201 -0
  665. package/dist/security-runtime/src/checks/malware/yara.mjs +124 -0
  666. package/dist/security-runtime/src/checks/mobile-config/index.mjs +173 -0
  667. package/dist/security-runtime/src/checks/mobile-config/mobsf.mjs +105 -0
  668. package/dist/security-runtime/src/checks/posture/index.mjs +133 -0
  669. package/dist/security-runtime/src/checks/project-scripts/index.mjs +187 -0
  670. package/dist/security-runtime/src/checks/sbom/index.mjs +98 -0
  671. package/dist/security-runtime/src/checks/secrets-build/index.mjs +63 -0
  672. package/dist/security-runtime/src/checks/secrets-history/index.mjs +112 -0
  673. package/dist/security-runtime/src/checks/secrets-tree/env.mjs +120 -0
  674. package/dist/security-runtime/src/checks/secrets-tree/index.mjs +73 -0
  675. package/dist/security-runtime/src/checks/supabase-static/index.mjs +240 -0
  676. package/dist/security-runtime/src/checks/supabase-static/sql.mjs +557 -0
  677. package/dist/security-runtime/src/checks/workflows/index.mjs +93 -0
  678. package/dist/security-runtime/src/cli/deep.mjs +13 -0
  679. package/dist/security-runtime/src/cli/doctor.mjs +82 -0
  680. package/dist/security-runtime/src/cli/index.mjs +60 -0
  681. package/dist/security-runtime/src/cli/live-common.mjs +27 -0
  682. package/dist/security-runtime/src/cli/parse.mjs +56 -0
  683. package/dist/security-runtime/src/cli/portfolio.mjs +34 -0
  684. package/dist/security-runtime/src/cli/release.mjs +28 -0
  685. package/dist/security-runtime/src/cli/report.mjs +18 -0
  686. package/dist/security-runtime/src/cli/run-common.mjs +54 -0
  687. package/dist/security-runtime/src/cli/scan.mjs +12 -0
  688. package/dist/security-runtime/src/cli/setup.mjs +59 -0
  689. package/dist/security-runtime/src/cli/url.mjs +38 -0
  690. package/dist/security-runtime/src/core/accept.mjs +141 -0
  691. package/dist/security-runtime/src/core/archive.mjs +114 -0
  692. package/dist/security-runtime/src/core/base-ref.mjs +43 -0
  693. package/dist/security-runtime/src/core/checks.mjs +39 -0
  694. package/dist/security-runtime/src/core/detect.mjs +90 -0
  695. package/dist/security-runtime/src/core/errors.mjs +5 -0
  696. package/dist/security-runtime/src/core/fetch.mjs +139 -0
  697. package/dist/security-runtime/src/core/findings.mjs +177 -0
  698. package/dist/security-runtime/src/core/gate.mjs +131 -0
  699. package/dist/security-runtime/src/core/installer.mjs +255 -0
  700. package/dist/security-runtime/src/core/lock.mjs +38 -0
  701. package/dist/security-runtime/src/core/nested.mjs +107 -0
  702. package/dist/security-runtime/src/core/paths.mjs +20 -0
  703. package/dist/security-runtime/src/core/pipeline.mjs +196 -0
  704. package/dist/security-runtime/src/core/registry.mjs +81 -0
  705. package/dist/security-runtime/src/core/report.mjs +128 -0
  706. package/dist/security-runtime/src/core/runner.mjs +86 -0
  707. package/dist/security-runtime/src/core/sarif.mjs +141 -0
  708. package/dist/security-runtime/src/lattice/artifact.mjs +1201 -0
  709. package/dist/security-runtime/src/lattice/execution.mjs +45 -0
  710. package/dist/security-runtime/src/lattice/export.mjs +215 -0
  711. package/dist/security-runtime/src/lattice/provenance.mjs +70 -0
  712. package/dist/security-runtime/src/lattice/runtime.mjs +158 -0
  713. package/dist/security-runtime/src/lattice/selected-runtime.mjs +189 -0
  714. package/dist/security-runtime/src/lattice/source-acquirer.mjs +51 -0
  715. package/dist/security-runtime/src/lattice/source-fetcher.mjs +88 -0
  716. package/dist/security-runtime/src/lattice/transport.mjs +232 -0
  717. package/dist/security-runtime/src/live/analyze.mjs +101 -0
  718. package/dist/security-runtime/src/live/exposure.mjs +79 -0
  719. package/dist/security-runtime/src/live/secrets.mjs +31 -0
  720. package/dist/security-runtime/src/live/session.mjs +98 -0
  721. package/dist/security-runtime/src/live/targets.mjs +81 -0
  722. package/dist/security-runtime/src/portfolio/index.mjs +116 -0
  723. package/dist/security-runtime/tools/registry/betterleaks.json +29 -0
  724. package/dist/security-runtime/tools/registry/guarddog.json +9 -0
  725. package/dist/security-runtime/tools/registry/mobsf.json +10 -0
  726. package/dist/security-runtime/tools/registry/opengrep.json +28 -0
  727. package/dist/security-runtime/tools/registry/osv-scanner.json +14 -0
  728. package/dist/security-runtime/tools/registry/semgrep-rules.json +21 -0
  729. package/dist/security-runtime/tools/registry/trivy.json +30 -0
  730. package/dist/security-runtime/tools/registry/yara-forge-exclusions.json +14 -0
  731. package/dist/security-runtime/tools/registry/yara-forge.json +22 -0
  732. package/dist/security-runtime/tools/registry/yara-runner.json +10 -0
  733. package/dist/security-runtime/tools/registry/yara-x.json +24 -0
  734. package/dist/security-runtime/tools/registry/zizmor.json +30 -0
  735. package/dist/spinner.d.ts +16 -0
  736. package/dist/spinner.d.ts.map +1 -0
  737. package/dist/spinner.js +72 -0
  738. package/dist/spinner.js.map +1 -0
  739. package/dist/verify.test.d.ts +2 -0
  740. package/dist/verify.test.d.ts.map +1 -0
  741. package/dist/verify.test.js +98 -0
  742. package/dist/verify.test.js.map +1 -0
  743. package/package.json +73 -4
@@ -0,0 +1,2012 @@
1
+ "use strict";
2
+ /**
3
+ * Additional CLI commands for Lattice
4
+ * These extend the core functionality with quality-of-life improvements
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.validateProjectSetup = validateProjectSetup;
8
+ exports.configShow = configShow;
9
+ exports.rulesExplain = rulesExplain;
10
+ exports.diff = diff;
11
+ exports.ci = ci;
12
+ exports.completions = completions;
13
+ exports.detectProjectType = detectProjectType;
14
+ exports.doctorFix = doctorFix;
15
+ exports.securityScan = securityScan;
16
+ exports.loadAllowlist = loadAllowlist;
17
+ exports.addToAllowlist = addToAllowlist;
18
+ exports.generateSarifReport = generateSarifReport;
19
+ const fs_1 = require("fs");
20
+ const path_1 = require("path");
21
+ const child_process_1 = require("child_process");
22
+ // ============================================================================
23
+ // PACKAGE.JSON VALIDATION - Check if project is properly initialized
24
+ // ============================================================================
25
+ async function validateProjectSetup(cwd) {
26
+ const packageJsonPath = (0, path_1.join)(cwd, 'package.json');
27
+ try {
28
+ await fs_1.promises.access(packageJsonPath);
29
+ // Check if it's a valid JSON
30
+ try {
31
+ const content = await fs_1.promises.readFile(packageJsonPath, 'utf-8');
32
+ JSON.parse(content);
33
+ return { valid: true };
34
+ }
35
+ catch {
36
+ return {
37
+ valid: false,
38
+ error: 'package.json exists but is not valid JSON',
39
+ suggestion: 'Fix the JSON syntax in package.json',
40
+ };
41
+ }
42
+ }
43
+ catch {
44
+ return {
45
+ valid: false,
46
+ error: 'package.json not found',
47
+ suggestion: getProjectSetupSuggestion(cwd),
48
+ };
49
+ }
50
+ }
51
+ function getProjectSetupSuggestion(cwd) {
52
+ return `
53
+ Lattice requires an existing project. To fix this:
54
+
55
+ Option 1 - Initialize a new Next.js project:
56
+ npx create-next-app@latest . --typescript --tailwind --app
57
+
58
+ Option 2 - Initialize a new Expo project:
59
+ npx create-expo-app@latest . --template blank-typescript
60
+
61
+ Option 3 - Initialize a basic Node project:
62
+ npm init -y
63
+
64
+ Then run 'npx latticeai' to add Lattice to your project.
65
+
66
+ Note: Lattice adds guardrails and verification to existing projects.
67
+ It does not create the base project structure.
68
+ `;
69
+ }
70
+ async function configShow(options = {}) {
71
+ const cwd = options.cwd || process.cwd();
72
+ const configPath = (0, path_1.join)(cwd, '.lattice', 'config.json');
73
+ try {
74
+ const configContent = await fs_1.promises.readFile(configPath, 'utf-8');
75
+ const config = JSON.parse(configContent);
76
+ if (options.json) {
77
+ console.log(JSON.stringify(config, null, 2));
78
+ return;
79
+ }
80
+ console.log('\n📋 Lattice Configuration\n');
81
+ console.log('─'.repeat(50));
82
+ console.log(` 📁 Config file: .lattice/config.json`);
83
+ console.log('─'.repeat(50));
84
+ console.log('');
85
+ console.log(' Project Type: ' + formatValue(config.projectType));
86
+ console.log(' Strictness: ' + formatValue(config.strictnessPreset));
87
+ if (config.integrations) {
88
+ console.log('');
89
+ console.log(' Integrations:');
90
+ for (const [key, value] of Object.entries(config.integrations)) {
91
+ console.log(` • ${key}: ${formatValue(value)}`);
92
+ }
93
+ }
94
+ // Show manifest info if available
95
+ const manifestPath = (0, path_1.join)(cwd, '.lattice', 'manifest.json');
96
+ try {
97
+ const manifestContent = await fs_1.promises.readFile(manifestPath, 'utf-8');
98
+ const manifest = JSON.parse(manifestContent);
99
+ console.log('');
100
+ console.log(' Manifest:');
101
+ console.log(` • Generator: v${manifest.generatorVersion || 'unknown'}`);
102
+ console.log(` • Generated: ${manifest.timestamp ? new Date(manifest.timestamp).toLocaleString() : 'unknown'}`);
103
+ console.log(` • Files: ${manifest.files?.length || 0}`);
104
+ }
105
+ catch {
106
+ // No manifest
107
+ }
108
+ // Show compliance info if available
109
+ const compliancePath = (0, path_1.join)(cwd, '.lattice', 'compliance.json');
110
+ try {
111
+ const complianceContent = await fs_1.promises.readFile(compliancePath, 'utf-8');
112
+ const compliance = JSON.parse(complianceContent);
113
+ const lastRun = compliance.history?.[0];
114
+ if (lastRun) {
115
+ console.log('');
116
+ console.log(' Last Verify:');
117
+ console.log(` • Status: ${lastRun.passed ? '✓ Passed' : '✗ Failed'}`);
118
+ console.log(` • Time: ${new Date(lastRun.timestamp).toLocaleString()}`);
119
+ console.log(` • Checks: ${lastRun.checksRun?.join(', ') || 'unknown'}`);
120
+ }
121
+ }
122
+ catch {
123
+ // No compliance
124
+ }
125
+ console.log('');
126
+ console.log('─'.repeat(50));
127
+ console.log(' Run: lattice config show --json for raw output');
128
+ console.log('─'.repeat(50));
129
+ console.log('');
130
+ }
131
+ catch (error) {
132
+ if (error.code === 'ENOENT') {
133
+ console.log('\n✗ No Lattice configuration found.');
134
+ console.log(' Run: npx latticeai to set up Lattice\n');
135
+ return;
136
+ }
137
+ throw error;
138
+ }
139
+ }
140
+ function formatValue(value) {
141
+ if (value === null || value === undefined)
142
+ return '(not set)';
143
+ if (typeof value === 'boolean')
144
+ return value ? 'yes' : 'no';
145
+ if (typeof value === 'object')
146
+ return JSON.stringify(value);
147
+ return String(value);
148
+ }
149
+ async function rulesExplain(options = {}) {
150
+ const cwd = options.cwd || process.cwd();
151
+ const rulesPath = (0, path_1.join)(cwd, '.cursor', 'rules.md');
152
+ try {
153
+ const rulesContent = await fs_1.promises.readFile(rulesPath, 'utf-8');
154
+ console.log('\n📖 Lattice Rules Explanation\n');
155
+ console.log('─'.repeat(60));
156
+ console.log('');
157
+ console.log('Lattice generates shared agent instructions for Cursor, Codex, and Claude.');
158
+ console.log('The legacy compatibility file at .cursor/rules.md contains:');
159
+ console.log('');
160
+ // Analyze the rules content
161
+ const sections = [];
162
+ if (rulesContent.includes('Version Protocol')) {
163
+ sections.push('📦 Version Protocol - Ensures AI uses correct package versions');
164
+ }
165
+ if (rulesContent.includes('Project Type')) {
166
+ sections.push('🏗️ Project Type - Specifies framework (Next.js, Expo, etc.)');
167
+ }
168
+ if (rulesContent.includes('Verification') || rulesContent.includes('verify')) {
169
+ sections.push('✓ Verification Rules - How to check code quality');
170
+ }
171
+ if (rulesContent.includes('CI') || rulesContent.includes('Continuous Integration')) {
172
+ sections.push('🔄 CI Enforcement - GitHub Actions workflow requirements');
173
+ }
174
+ if (rulesContent.includes('Architecture') || rulesContent.includes('directory structure')) {
175
+ sections.push('📁 Architecture - Directory structure and patterns');
176
+ }
177
+ if (sections.length > 0) {
178
+ console.log('Detected sections:');
179
+ for (const section of sections) {
180
+ console.log(` ${section}`);
181
+ }
182
+ }
183
+ console.log('');
184
+ console.log('─'.repeat(60));
185
+ console.log('');
186
+ // Show stats
187
+ const lines = rulesContent.split('\n').length;
188
+ const headers = (rulesContent.match(/^#+\s/gm) || []).length;
189
+ const codeBlocks = (rulesContent.match(/```/g) || []).length / 2;
190
+ console.log('📊 Stats:');
191
+ console.log(` Lines: ${lines}`);
192
+ console.log(` Sections: ${headers}`);
193
+ console.log(` Code blocks: ${Math.floor(codeBlocks)}`);
194
+ console.log('');
195
+ // Extract the LATTICE markers
196
+ const latticeMatch = rulesContent.match(/\x3c!-- LATTICE:START v([\d.]+)/);
197
+ if (latticeMatch) {
198
+ console.log(`🔖 Lattice version: ${latticeMatch[1]}`);
199
+ }
200
+ console.log('');
201
+ console.log('─'.repeat(60));
202
+ console.log(' View files: .cursor/rules.md, .cursor/rules/lattice-core.mdc, AGENTS.md');
203
+ console.log(' Regenerate: npx latticeai update');
204
+ console.log('─'.repeat(60));
205
+ console.log('');
206
+ }
207
+ catch (error) {
208
+ if (error.code === 'ENOENT') {
209
+ console.log('\n✗ No Lattice rules file found at .cursor/rules.md');
210
+ console.log(' Run: npx latticeai to generate rules, AGENTS.md, and Claude settings\n');
211
+ return;
212
+ }
213
+ throw error;
214
+ }
215
+ }
216
+ async function diff(options = {}) {
217
+ const cwd = options.cwd || process.cwd();
218
+ const manifestPath = (0, path_1.join)(cwd, '.lattice', 'manifest.json');
219
+ try {
220
+ const manifestContent = await fs_1.promises.readFile(manifestPath, 'utf-8');
221
+ const manifest = JSON.parse(manifestContent);
222
+ const trackedFiles = manifest.files || [];
223
+ if (options.json) {
224
+ const changes = await computeChanges(cwd, trackedFiles);
225
+ console.log(JSON.stringify(changes, null, 2));
226
+ return;
227
+ }
228
+ console.log('\n📊 Lattice Diff\n');
229
+ console.log('Changes since last generation:\n');
230
+ const changes = await computeChanges(cwd, trackedFiles);
231
+ if (changes.modified.length === 0 && changes.deleted.length === 0 && changes.added.length === 0) {
232
+ console.log(' ✓ No changes detected\n');
233
+ return;
234
+ }
235
+ if (changes.modified.length > 0) {
236
+ console.log(' Modified:');
237
+ for (const file of changes.modified) {
238
+ console.log(` • ${file}`);
239
+ }
240
+ console.log('');
241
+ }
242
+ if (changes.deleted.length > 0) {
243
+ console.log(' Deleted:');
244
+ for (const file of changes.deleted) {
245
+ console.log(` ✗ ${file}`);
246
+ }
247
+ console.log('');
248
+ }
249
+ if (changes.added.length > 0) {
250
+ console.log(' New (untracked by Lattice):');
251
+ for (const file of changes.added.slice(0, 10)) {
252
+ console.log(` + ${file}`);
253
+ }
254
+ if (changes.added.length > 10) {
255
+ console.log(` ... and ${changes.added.length - 10} more`);
256
+ }
257
+ console.log('');
258
+ }
259
+ console.log('─'.repeat(50));
260
+ console.log(' Run: npx latticeai update to regenerate rules');
261
+ console.log('─'.repeat(50));
262
+ console.log('');
263
+ }
264
+ catch (error) {
265
+ if (error.code === 'ENOENT') {
266
+ console.log('\n✗ No Lattice manifest found.');
267
+ console.log(' Run: npx latticeai to set up Lattice\n');
268
+ return;
269
+ }
270
+ throw error;
271
+ }
272
+ }
273
+ async function computeChanges(cwd, trackedFiles) {
274
+ const changes = {
275
+ modified: [],
276
+ deleted: [],
277
+ added: [],
278
+ };
279
+ for (const file of trackedFiles) {
280
+ const fullPath = (0, path_1.join)(cwd, file.path);
281
+ try {
282
+ await fs_1.promises.access(fullPath);
283
+ // File exists - could check hash for modification
284
+ // For now, we just check existence
285
+ }
286
+ catch {
287
+ changes.deleted.push(file.path);
288
+ }
289
+ }
290
+ // Check for new config files in .lattice or .cursor
291
+ const latticeDir = (0, path_1.join)(cwd, '.lattice');
292
+ const cursorDir = (0, path_1.join)(cwd, '.cursor');
293
+ try {
294
+ const latticeFiles = await fs_1.promises.readdir(latticeDir);
295
+ for (const file of latticeFiles) {
296
+ const relativePath = `.lattice/${file}`;
297
+ if (!trackedFiles.some((f) => f.path === relativePath)) {
298
+ changes.added.push(relativePath);
299
+ }
300
+ }
301
+ }
302
+ catch {
303
+ // Directory doesn't exist
304
+ }
305
+ try {
306
+ const cursorFiles = await fs_1.promises.readdir(cursorDir);
307
+ for (const file of cursorFiles) {
308
+ const relativePath = `.cursor/${file}`;
309
+ if (!trackedFiles.some((f) => f.path === relativePath)) {
310
+ changes.added.push(relativePath);
311
+ }
312
+ }
313
+ }
314
+ catch {
315
+ // Directory doesn't exist
316
+ }
317
+ return changes;
318
+ }
319
+ async function ci(options = {}) {
320
+ const cwd = options.cwd || process.cwd();
321
+ const provider = options.provider || 'github';
322
+ // Read config to determine project type
323
+ let projectType = 'nextjs';
324
+ try {
325
+ const configPath = (0, path_1.join)(cwd, '.lattice', 'config.json');
326
+ const configContent = await fs_1.promises.readFile(configPath, 'utf-8');
327
+ const config = JSON.parse(configContent);
328
+ projectType = config.projectType || 'nextjs';
329
+ }
330
+ catch {
331
+ // Use default
332
+ }
333
+ const isExpo = projectType === 'expo-eas';
334
+ let workflow;
335
+ if (provider === 'github') {
336
+ workflow = generateGitHubWorkflow(isExpo);
337
+ const outputPath = (0, path_1.join)(cwd, '.github', 'workflows', 'ci.yml');
338
+ if (options.dryRun) {
339
+ console.log('\n📄 Generated GitHub Actions Workflow:\n');
340
+ console.log(workflow);
341
+ console.log(`\nWould write to: ${outputPath}`);
342
+ return;
343
+ }
344
+ await fs_1.promises.mkdir((0, path_1.dirname)(outputPath), { recursive: true });
345
+ await fs_1.promises.writeFile(outputPath, workflow);
346
+ console.log(`\n✓ Generated: ${outputPath}\n`);
347
+ }
348
+ else {
349
+ workflow = generateGitLabCI(isExpo);
350
+ const outputPath = (0, path_1.join)(cwd, '.gitlab-ci.yml');
351
+ if (options.dryRun) {
352
+ console.log('\n📄 Generated GitLab CI:\n');
353
+ console.log(workflow);
354
+ console.log(`\nWould write to: ${outputPath}`);
355
+ return;
356
+ }
357
+ await fs_1.promises.writeFile(outputPath, workflow);
358
+ console.log(`\n✓ Generated: ${outputPath}\n`);
359
+ }
360
+ }
361
+ function generateGitHubWorkflow(isExpo) {
362
+ const buildStep = isExpo
363
+ ? ''
364
+ : `
365
+ - name: Build
366
+ run: npm run build`;
367
+ return `name: CI
368
+
369
+ on:
370
+ push:
371
+ branches: [main, master]
372
+ pull_request:
373
+ branches: [main, master]
374
+
375
+ jobs:
376
+ verify:
377
+ runs-on: ubuntu-latest
378
+
379
+ steps:
380
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
381
+
382
+ - name: Setup Node.js
383
+ uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
384
+ with:
385
+ node-version: '24.22.0'
386
+ cache: 'npm'
387
+
388
+ - name: Install dependencies
389
+ run: npm ci
390
+
391
+ - name: Lint
392
+ run: npm run lint
393
+
394
+ - name: Typecheck
395
+ run: npm run typecheck
396
+
397
+ - name: Test
398
+ run: npm run test
399
+ ${buildStep}
400
+ `;
401
+ }
402
+ function generateGitLabCI(isExpo) {
403
+ const buildJob = isExpo
404
+ ? ''
405
+ : `
406
+ build:
407
+ stage: build
408
+ script:
409
+ - npm run build
410
+ `;
411
+ return `image: node:24.22.0
412
+
413
+ stages:
414
+ - verify
415
+ - build
416
+
417
+ cache:
418
+ paths:
419
+ - node_modules/
420
+
421
+ before_script:
422
+ - npm ci
423
+
424
+ lint:
425
+ stage: verify
426
+ script:
427
+ - npm run lint
428
+
429
+ typecheck:
430
+ stage: verify
431
+ script:
432
+ - npm run typecheck
433
+
434
+ test:
435
+ stage: verify
436
+ script:
437
+ - npm run test
438
+ ${buildJob}`;
439
+ }
440
+ function completions(shell) {
441
+ switch (shell) {
442
+ case 'bash':
443
+ console.log(generateBashCompletions());
444
+ break;
445
+ case 'zsh':
446
+ console.log(generateZshCompletions());
447
+ break;
448
+ case 'fish':
449
+ console.log(generateFishCompletions());
450
+ break;
451
+ case 'powershell':
452
+ console.log(generatePowerShellCompletions());
453
+ break;
454
+ default:
455
+ console.error(`Unknown shell: ${shell}`);
456
+ console.error('Supported: bash, zsh, fish, powershell');
457
+ }
458
+ }
459
+ function generateBashCompletions() {
460
+ return `# Lattice CLI bash completions
461
+ # Add to ~/.bashrc: eval "$(lattice completions bash)"
462
+
463
+ _lattice_completions() {
464
+ local cur="\${COMP_WORDS[COMP_CWORD]}"
465
+ local commands="init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci security-scan scan completions help"
466
+
467
+ if [ "\${COMP_CWORD}" -eq 1 ]; then
468
+ COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
469
+ elif [ "\${COMP_WORDS[1]}" = "bundle" ]; then
470
+ COMPREPLY=( $(compgen -W "update diff rollback" -- "\${cur}") )
471
+ elif [ "\${COMP_WORDS[1]}" = "config" ]; then
472
+ COMPREPLY=( $(compgen -W "show" -- "\${cur}") )
473
+ elif [ "\${COMP_WORDS[1]}" = "rules" ]; then
474
+ COMPREPLY=( $(compgen -W "explain" -- "\${cur}") )
475
+ elif [ "\${COMP_WORDS[1]}" = "completions" ]; then
476
+ COMPREPLY=( $(compgen -W "bash zsh fish powershell" -- "\${cur}") )
477
+ fi
478
+ }
479
+
480
+ complete -F _lattice_completions lattice
481
+ complete -F _lattice_completions latticeai
482
+ `;
483
+ }
484
+ function generateZshCompletions() {
485
+ return `#compdef lattice latticeai
486
+ # Lattice CLI zsh completions
487
+ # Add to ~/.zshrc: eval "$(lattice completions zsh)"
488
+
489
+ _lattice() {
490
+ local commands=(
491
+ 'init:Initialize Lattice configuration'
492
+ 'generate:Generate the Lattice pack'
493
+ 'apply:Apply pack to project'
494
+ 'verify:Run verification checks'
495
+ 'verify-rules:Verify rules file'
496
+ 'doctor:Check environment'
497
+ 'status:Show current status'
498
+ 'drift:Detect configuration drift'
499
+ 'progress:Show PROJECT_GUIDE.md progress'
500
+ 'bundle:Manage bundles'
501
+ 'check:Check for updates'
502
+ 'update:Update Lattice rules'
503
+ 'setup:Interactive setup'
504
+ 'login:Authenticate with Lattice'
505
+ 'logout:Remove credentials'
506
+ 'whoami:Show login status'
507
+ 'create:Create project from Architect'
508
+ 'config:Configuration commands'
509
+ 'rules:Rules commands'
510
+ 'ci:Generate CI workflow'
511
+ 'diff:Show changes since generation'
512
+ 'security-scan:Scan for exposed secrets'
513
+ 'scan:Scan for exposed secrets (alias)'
514
+ 'completions:Generate shell completions'
515
+ 'help:Show help'
516
+ )
517
+
518
+ _describe 'command' commands
519
+ }
520
+
521
+ compdef _lattice lattice
522
+ compdef _lattice latticeai
523
+ `;
524
+ }
525
+ function generateFishCompletions() {
526
+ return `# Lattice CLI fish completions
527
+ # Add to ~/.config/fish/completions/lattice.fish
528
+
529
+ complete -c lattice -f
530
+ complete -c latticeai -f
531
+
532
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff completions help" -a init -d "Initialize Lattice"
533
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff completions help" -a generate -d "Generate pack"
534
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff completions help" -a apply -d "Apply pack"
535
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff completions help" -a verify -d "Run checks"
536
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff completions help" -a doctor -d "Check environment"
537
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff completions help" -a status -d "Show status"
538
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff completions help" -a login -d "Authenticate"
539
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff completions help" -a create -d "Create from Architect"
540
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff completions help" -a config -d "Config commands"
541
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff security-scan scan completions help" -a ci -d "Generate CI"
542
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff security-scan scan completions help" -a security-scan -d "Scan for exposed secrets"
543
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff security-scan scan completions help" -a scan -d "Scan for exposed secrets (alias)"
544
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff security-scan scan completions help" -a completions -d "Shell completions"
545
+ complete -c lattice -n "not __fish_seen_subcommand_from init generate apply verify verify-rules doctor status drift progress bundle check update setup login logout whoami create config rules ci diff security-scan scan completions help" -a help -d "Show help"
546
+
547
+ complete -c lattice -n "__fish_seen_subcommand_from bundle" -a "update diff rollback"
548
+ complete -c lattice -n "__fish_seen_subcommand_from config" -a "show"
549
+ complete -c lattice -n "__fish_seen_subcommand_from rules" -a "explain"
550
+ complete -c lattice -n "__fish_seen_subcommand_from completions" -a "bash zsh fish powershell"
551
+
552
+ # Copy for latticeai alias
553
+ complete -c latticeai -w lattice
554
+ `;
555
+ }
556
+ function generatePowerShellCompletions() {
557
+ return `# Lattice CLI PowerShell completions
558
+ # Add to $PROFILE: Invoke-Expression (lattice completions powershell | Out-String)
559
+
560
+ $scriptblock = {
561
+ param($wordToComplete, $commandAst, $cursorPosition)
562
+
563
+ $commands = @(
564
+ @{ Name = 'init'; Description = 'Initialize Lattice configuration' }
565
+ @{ Name = 'generate'; Description = 'Generate the Lattice pack' }
566
+ @{ Name = 'apply'; Description = 'Apply pack to project' }
567
+ @{ Name = 'verify'; Description = 'Run verification checks' }
568
+ @{ Name = 'verify-rules'; Description = 'Verify rules file' }
569
+ @{ Name = 'doctor'; Description = 'Check environment' }
570
+ @{ Name = 'status'; Description = 'Show current status' }
571
+ @{ Name = 'drift'; Description = 'Detect configuration drift' }
572
+ @{ Name = 'progress'; Description = 'Show PROJECT_GUIDE.md progress' }
573
+ @{ Name = 'bundle'; Description = 'Manage bundles' }
574
+ @{ Name = 'check'; Description = 'Check for updates' }
575
+ @{ Name = 'update'; Description = 'Update Lattice rules' }
576
+ @{ Name = 'setup'; Description = 'Interactive setup' }
577
+ @{ Name = 'login'; Description = 'Authenticate with Lattice' }
578
+ @{ Name = 'logout'; Description = 'Remove credentials' }
579
+ @{ Name = 'whoami'; Description = 'Show login status' }
580
+ @{ Name = 'create'; Description = 'Create project from Architect' }
581
+ @{ Name = 'config'; Description = 'Configuration commands' }
582
+ @{ Name = 'rules'; Description = 'Rules commands' }
583
+ @{ Name = 'ci'; Description = 'Generate CI workflow' }
584
+ @{ Name = 'diff'; Description = 'Show changes since generation' }
585
+ @{ Name = 'security-scan'; Description = 'Scan for exposed secrets' }
586
+ @{ Name = 'scan'; Description = 'Scan for exposed secrets (alias)' }
587
+ @{ Name = 'completions'; Description = 'Generate shell completions' }
588
+ @{ Name = 'help'; Description = 'Show help' }
589
+ )
590
+
591
+ $commands | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object {
592
+ [System.Management.Automation.CompletionResult]::new($_.Name, $_.Name, 'ParameterValue', $_.Description)
593
+ }
594
+ }
595
+
596
+ Register-ArgumentCompleter -Native -CommandName lattice -ScriptBlock $scriptblock
597
+ Register-ArgumentCompleter -Native -CommandName latticeai -ScriptBlock $scriptblock
598
+ `;
599
+ }
600
+ // ============================================================================
601
+ // DETECT PROJECT TYPE
602
+ // ============================================================================
603
+ async function detectProjectType(cwd) {
604
+ const packageJsonPath = (0, path_1.join)(cwd, 'package.json');
605
+ try {
606
+ const packageContent = await fs_1.promises.readFile(packageJsonPath, 'utf-8');
607
+ const pkg = JSON.parse(packageContent);
608
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
609
+ // Check for Next.js
610
+ if (deps['next']) {
611
+ return {
612
+ projectType: 'nextjs',
613
+ confidence: 'high',
614
+ reason: 'Found "next" in dependencies',
615
+ };
616
+ }
617
+ // Check for Expo
618
+ if (deps['expo']) {
619
+ return {
620
+ projectType: 'expo-eas',
621
+ confidence: 'high',
622
+ reason: 'Found "expo" in dependencies',
623
+ };
624
+ }
625
+ // Check for React Native without Expo
626
+ if (deps['react-native'] && !deps['expo']) {
627
+ return {
628
+ projectType: 'expo-eas',
629
+ confidence: 'medium',
630
+ reason: 'Found "react-native" (assuming Expo)',
631
+ };
632
+ }
633
+ // Check for other React frameworks
634
+ if (deps['react']) {
635
+ return {
636
+ projectType: 'nextjs',
637
+ confidence: 'low',
638
+ reason: 'Found "react" but no framework - assuming Next.js',
639
+ };
640
+ }
641
+ return {
642
+ projectType: null,
643
+ confidence: 'low',
644
+ reason: 'Could not detect project type from dependencies',
645
+ };
646
+ }
647
+ catch {
648
+ return {
649
+ projectType: null,
650
+ confidence: 'low',
651
+ reason: 'No package.json found',
652
+ };
653
+ }
654
+ }
655
+ async function doctorFix(options = {}) {
656
+ const cwd = options.cwd || process.cwd();
657
+ const results = [];
658
+ // 1. Check for missing required scripts in package.json
659
+ const packageJsonPath = (0, path_1.join)(cwd, 'package.json');
660
+ try {
661
+ const packageContent = await fs_1.promises.readFile(packageJsonPath, 'utf-8');
662
+ const pkg = JSON.parse(packageContent);
663
+ const scripts = pkg.scripts || {};
664
+ const requiredScripts = ['lint', 'typecheck', 'test', 'build'];
665
+ let modified = false;
666
+ for (const script of requiredScripts) {
667
+ if (!scripts[script]) {
668
+ const defaultScript = getDefaultScript(script, pkg);
669
+ if (!options.dryRun) {
670
+ pkg.scripts = pkg.scripts || {};
671
+ pkg.scripts[script] = defaultScript;
672
+ modified = true;
673
+ }
674
+ results.push({
675
+ issue: `Missing script: ${script}`,
676
+ fixed: !options.dryRun,
677
+ action: `Added "${script}": "${defaultScript}"`,
678
+ });
679
+ }
680
+ }
681
+ if (modified && !options.dryRun) {
682
+ await fs_1.promises.writeFile(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n');
683
+ }
684
+ }
685
+ catch {
686
+ results.push({
687
+ issue: 'No package.json found',
688
+ fixed: false,
689
+ action: 'Create package.json manually',
690
+ });
691
+ }
692
+ // 2. Check for .gitignore
693
+ const gitignorePath = (0, path_1.join)(cwd, '.gitignore');
694
+ try {
695
+ await fs_1.promises.access(gitignorePath);
696
+ }
697
+ catch {
698
+ if (!options.dryRun) {
699
+ const defaultGitignore = `node_modules/
700
+ .next/
701
+ dist/
702
+ .env.local
703
+ .env*.local
704
+ *.log
705
+ .DS_Store
706
+ `;
707
+ await fs_1.promises.writeFile(gitignorePath, defaultGitignore);
708
+ }
709
+ results.push({
710
+ issue: 'Missing .gitignore',
711
+ fixed: !options.dryRun,
712
+ action: 'Created default .gitignore',
713
+ });
714
+ }
715
+ // 3. Check for tsconfig.json if TypeScript is installed
716
+ try {
717
+ const packageContent = await fs_1.promises.readFile(packageJsonPath, 'utf-8');
718
+ const pkg = JSON.parse(packageContent);
719
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
720
+ if (deps['typescript']) {
721
+ const tsconfigPath = (0, path_1.join)(cwd, 'tsconfig.json');
722
+ try {
723
+ await fs_1.promises.access(tsconfigPath);
724
+ }
725
+ catch {
726
+ results.push({
727
+ issue: 'TypeScript installed but no tsconfig.json',
728
+ fixed: false,
729
+ action: 'Run: npx tsc --init',
730
+ });
731
+ }
732
+ }
733
+ }
734
+ catch {
735
+ // No package.json
736
+ }
737
+ return results;
738
+ }
739
+ function getDefaultScript(name, pkg) {
740
+ const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
741
+ const isNext = !!deps['next'];
742
+ const isExpo = !!deps['expo'];
743
+ switch (name) {
744
+ case 'lint':
745
+ return 'eslint . --ext .ts,.tsx,.js,.jsx';
746
+ case 'typecheck':
747
+ return 'tsc --noEmit';
748
+ case 'test':
749
+ if (deps['jest'])
750
+ return 'jest --passWithNoTests';
751
+ if (deps['vitest'])
752
+ return 'vitest run';
753
+ return 'echo "No tests configured" && exit 0';
754
+ case 'build':
755
+ if (isNext)
756
+ return 'next build';
757
+ if (isExpo)
758
+ return 'expo prebuild';
759
+ return 'tsc';
760
+ default:
761
+ return `echo "TODO: add ${name} script"`;
762
+ }
763
+ }
764
+ // Common secret patterns
765
+ const SECRET_PATTERNS = [
766
+ // Generic API Keys - catch various naming patterns
767
+ {
768
+ name: 'API Key',
769
+ pattern: /(?:api[_-]?key|apikey|api[_-]?token|api[_-]?secret)\s*[:=]\s*['"]([a-zA-Z0-9_\-+/=]{20,})['"]/gi,
770
+ severity: 'critical',
771
+ envVarName: () => 'API_KEY',
772
+ },
773
+ // API Key in camelCase/PascalCase
774
+ {
775
+ name: 'API Key',
776
+ pattern: /(?:apiKey|apiToken|apiSecret|ApiKey|ApiToken|ApiSecret)\s*[:=]\s*['"]([a-zA-Z0-9_\-+/=]{20,})['"]/gi,
777
+ severity: 'critical',
778
+ envVarName: () => 'API_KEY',
779
+ },
780
+ // Environment variable style API keys (ALL_CAPS format)
781
+ {
782
+ name: 'API Key (Env Var Format)',
783
+ pattern: /([A-Z][A-Z0-9_]*API[_-]?KEY|[A-Z][A-Z0-9_]*API[_-]?TOKEN)\s*[:=]\s*['"]([a-zA-Z0-9_\-+/=]{20,})['"]/g,
784
+ severity: 'critical',
785
+ envVarName: (match) => {
786
+ // match[1] is the variable name, match[2] is the value
787
+ if (match && match[1]) {
788
+ return match[1];
789
+ }
790
+ return 'API_KEY';
791
+ },
792
+ },
793
+ // Generic secret/token patterns (catch-all for unknown services)
794
+ {
795
+ name: 'Secret/Token',
796
+ pattern: /(?:secret|token|auth[_-]?token|access[_-]?token)\s*[:=]\s*['"]([a-zA-Z0-9_\-+/=]{32,})['"]/gi,
797
+ severity: 'high',
798
+ envVarName: (match) => {
799
+ const varName = match[0].match(/(\w+)\s*[:=]/)?.[1]?.toUpperCase().replace(/[_-]/g, '_') || 'SECRET';
800
+ return varName;
801
+ },
802
+ },
803
+ // AI/ML Service API Keys
804
+ {
805
+ name: 'Anthropic API Key',
806
+ pattern: /(?:anthropic[_-]?api[_-]?key|ANTHROPIC_API_KEY)\s*[:=]\s*['"](sk-ant-[a-zA-Z0-9\-_]{95,})['"]/gi,
807
+ severity: 'critical',
808
+ envVarName: () => 'ANTHROPIC_API_KEY',
809
+ },
810
+ {
811
+ name: 'OpenAI API Key',
812
+ pattern: /(?:openai[_-]?api[_-]?key|OPENAI_API_KEY)\s*[:=]\s*['"](sk-[a-zA-Z0-9]{32,})['"]/gi,
813
+ severity: 'critical',
814
+ envVarName: () => 'OPENAI_API_KEY',
815
+ },
816
+ {
817
+ name: 'Replicate API Token',
818
+ pattern: /(?:replicate[_-]?api[_-]?token|REPLICATE_API_TOKEN)\s*[:=]\s*['"](r8_[a-zA-Z0-9\-_]{37,})['"]/gi,
819
+ severity: 'critical',
820
+ envVarName: () => 'REPLICATE_API_TOKEN',
821
+ },
822
+ {
823
+ name: 'Google Gemini API Key',
824
+ pattern: /(?:google[_-]?gemini[_-]?api[_-]?key|GOOGLE_GEMINI_API_KEY|gemini[_-]?api[_-]?key)\s*[:=]\s*['"](AIza[0-9A-Za-z\-_]{35})['"]/gi,
825
+ severity: 'critical',
826
+ envVarName: () => 'GOOGLE_GEMINI_API_KEY',
827
+ },
828
+ {
829
+ name: 'Google API Key',
830
+ pattern: /(?:google[_-]?api[_-]?key|GOOGLE_API_KEY)\s*[:=]\s*['"](AIza[0-9A-Za-z\-_]{35})['"]/gi,
831
+ severity: 'critical',
832
+ envVarName: () => 'GOOGLE_API_KEY',
833
+ },
834
+ {
835
+ name: 'Cohere API Key',
836
+ pattern: /(?:cohere[_-]?api[_-]?key|COHERE_API_KEY)\s*[:=]\s*['"]([a-zA-Z0-9\-_]{40,})['"]/gi,
837
+ severity: 'critical',
838
+ envVarName: () => 'COHERE_API_KEY',
839
+ },
840
+ {
841
+ name: 'Hugging Face Token',
842
+ pattern: /(?:huggingface[_-]?token|hf[_-]?token|HUGGINGFACE_TOKEN)\s*[:=]\s*['"](hf_[a-zA-Z0-9\-_]{37,})['"]/gi,
843
+ severity: 'critical',
844
+ envVarName: () => 'HUGGINGFACE_TOKEN',
845
+ },
846
+ {
847
+ name: 'Together AI API Key',
848
+ pattern: /(?:together[_-]?ai[_-]?api[_-]?key|TOGETHER_API_KEY)\s*[:=]\s*['"]([a-zA-Z0-9\-_]{40,})['"]/gi,
849
+ severity: 'critical',
850
+ envVarName: () => 'TOGETHER_API_KEY',
851
+ },
852
+ {
853
+ name: 'Groq API Key',
854
+ pattern: /(?:groq[_-]?api[_-]?key|GROQ_API_KEY)\s*[:=]\s*['"](gsk_[a-zA-Z0-9\-_]{48,})['"]/gi,
855
+ severity: 'critical',
856
+ envVarName: () => 'GROQ_API_KEY',
857
+ },
858
+ {
859
+ name: 'Perplexity API Key',
860
+ pattern: /(?:perplexity[_-]?api[_-]?key|PERPLEXITY_API_KEY)\s*[:=]\s*['"](pplx-[a-zA-Z0-9\-_]{40,})['"]/gi,
861
+ severity: 'critical',
862
+ envVarName: () => 'PERPLEXITY_API_KEY',
863
+ },
864
+ {
865
+ name: 'AWS Access Key',
866
+ pattern: /(?:aws[_-]?access[_-]?key[_-]?id|aws_access_key)\s*[:=]\s*['"](AKIA[0-9A-Z]{16})['"]/gi,
867
+ severity: 'critical',
868
+ envVarName: () => 'AWS_ACCESS_KEY_ID',
869
+ },
870
+ {
871
+ name: 'AWS Secret Key',
872
+ pattern: /(?:aws[_-]?secret[_-]?access[_-]?key|aws_secret_key)\s*[:=]\s*['"]([a-zA-Z0-9/+=]{40})['"]/gi,
873
+ severity: 'critical',
874
+ envVarName: () => 'AWS_SECRET_ACCESS_KEY',
875
+ },
876
+ {
877
+ name: 'GitHub Token',
878
+ pattern: /(?:github[_-]?token|gh_token|ghp_)\s*[:=]\s*['"](ghp_[a-zA-Z0-9]{36})['"]/gi,
879
+ severity: 'critical',
880
+ envVarName: () => 'GITHUB_TOKEN',
881
+ },
882
+ {
883
+ name: 'Stripe Key',
884
+ pattern: /(?:stripe[_-]?(?:secret|private)[_-]?key|sk_live_)\s*[:=]\s*['"](sk_(live|test)_[a-zA-Z0-9]{24,})['"]/gi,
885
+ severity: 'critical',
886
+ envVarName: () => 'STRIPE_SECRET_KEY',
887
+ },
888
+ {
889
+ name: 'Stripe Publishable Key',
890
+ pattern: /(?:stripe[_-]?publishable[_-]?key|pk_live_)\s*[:=]\s*['"](pk_(live|test)_[a-zA-Z0-9]{24,})['"]/gi,
891
+ severity: 'high',
892
+ envVarName: () => 'STRIPE_PUBLISHABLE_KEY',
893
+ },
894
+ {
895
+ name: 'JWT Secret',
896
+ pattern: /(?:jwt[_-]?secret|jwt_secret)\s*[:=]\s*['"]([a-zA-Z0-9_\-]{32,})['"]/gi,
897
+ severity: 'critical',
898
+ envVarName: () => 'JWT_SECRET',
899
+ },
900
+ {
901
+ name: 'Database Password',
902
+ pattern: /(?:db[_-]?password|database[_-]?password|password)\s*[:=]\s*['"]([^'"]{8,})['"]/gi,
903
+ severity: 'critical',
904
+ envVarName: () => 'DB_PASSWORD',
905
+ },
906
+ {
907
+ name: 'MongoDB Connection String',
908
+ pattern: /(?:mongodb[_-]?uri|mongo[_-]?connection)\s*[:=]\s*['"](mongodb(?:\+srv)?:\/\/[^'"]+)['"]/gi,
909
+ severity: 'critical',
910
+ envVarName: () => 'MONGODB_URI',
911
+ },
912
+ {
913
+ name: 'PostgreSQL Connection String',
914
+ pattern: /(?:postgres[_-]?uri|postgresql[_-]?connection|DATABASE_URL)\s*[:=]\s*['"](postgres(?:ql)?:\/\/[^'"]+)['"]/gi,
915
+ severity: 'critical',
916
+ envVarName: () => 'DATABASE_URL',
917
+ },
918
+ {
919
+ name: 'Private Key',
920
+ pattern: /(?:private[_-]?key|-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----)/gi,
921
+ severity: 'critical',
922
+ envVarName: () => 'PRIVATE_KEY',
923
+ },
924
+ {
925
+ name: 'OAuth Client Secret',
926
+ pattern: /(?:oauth[_-]?client[_-]?secret|client[_-]?secret)\s*[:=]\s*['"]([a-zA-Z0-9_\-]{20,})['"]/gi,
927
+ severity: 'critical',
928
+ envVarName: () => 'OAUTH_CLIENT_SECRET',
929
+ },
930
+ {
931
+ name: 'SendGrid API Key',
932
+ pattern: /(?:sendgrid[_-]?api[_-]?key)\s*[:=]\s*['"](SG\.[a-zA-Z0-9_\-]{22}\.[a-zA-Z0-9_\-]{43})['"]/gi,
933
+ severity: 'critical',
934
+ envVarName: () => 'SENDGRID_API_KEY',
935
+ },
936
+ {
937
+ name: 'Twilio Auth Token',
938
+ pattern: /(?:twilio[_-]?auth[_-]?token)\s*[:=]\s*['"]([a-zA-Z0-9]{32})['"]/gi,
939
+ severity: 'critical',
940
+ envVarName: () => 'TWILIO_AUTH_TOKEN',
941
+ },
942
+ {
943
+ name: 'Slack Webhook URL',
944
+ pattern: /(?:slack[_-]?webhook)\s*[:=]\s*['"](https:\/\/hooks\.slack\.com\/services\/[^'"]+)['"]/gi,
945
+ severity: 'high',
946
+ envVarName: () => 'SLACK_WEBHOOK_URL',
947
+ },
948
+ {
949
+ name: 'Firebase Service Account',
950
+ pattern: /(?:firebase[_-]?service[_-]?account|GOOGLE_APPLICATION_CREDENTIALS)\s*[:=]\s*['"]([^'"]+\.json)['"]/gi,
951
+ severity: 'critical',
952
+ envVarName: () => 'FIREBASE_SERVICE_ACCOUNT',
953
+ },
954
+ // Cloud Services
955
+ {
956
+ name: 'Azure Connection String',
957
+ pattern: /(?:azure[_-]?connection[_-]?string|AZURE_STORAGE_CONNECTION_STRING)\s*[:=]\s*['"](DefaultEndpointsProtocol=https[^'"]+)['"]/gi,
958
+ severity: 'critical',
959
+ envVarName: () => 'AZURE_STORAGE_CONNECTION_STRING',
960
+ },
961
+ {
962
+ name: 'GCP Service Account Key',
963
+ pattern: /(?:gcp[_-]?service[_-]?account|GOOGLE_APPLICATION_CREDENTIALS|GCP_SERVICE_ACCOUNT)\s*[:=]\s*['"]([^'"]+\.json)['"]/gi,
964
+ severity: 'critical',
965
+ envVarName: () => 'GCP_SERVICE_ACCOUNT_KEY',
966
+ },
967
+ {
968
+ name: 'Vercel Token',
969
+ pattern: /(?:vercel[_-]?token|VERCEL_TOKEN)\s*[:=]\s*['"]([a-zA-Z0-9_\-]{40,})['"]/gi,
970
+ severity: 'critical',
971
+ envVarName: () => 'VERCEL_TOKEN',
972
+ },
973
+ {
974
+ name: 'Netlify Token',
975
+ pattern: /(?:netlify[_-]?token|NETLIFY_TOKEN)\s*[:=]\s*['"]([a-zA-Z0-9_\-]{40,})['"]/gi,
976
+ severity: 'critical',
977
+ envVarName: () => 'NETLIFY_TOKEN',
978
+ },
979
+ {
980
+ name: 'Heroku API Key',
981
+ pattern: /(?:heroku[_-]?api[_-]?key|HEROKU_API_KEY)\s*[:=]\s*['"]([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})['"]/gi,
982
+ severity: 'critical',
983
+ envVarName: () => 'HEROKU_API_KEY',
984
+ },
985
+ // Additional Database Services
986
+ {
987
+ name: 'Redis Connection String',
988
+ pattern: /(?:redis[_-]?url|REDIS_URL|redis[_-]?connection)\s*[:=]\s*['"](redis[s]?:\/\/[^'"]+)['"]/gi,
989
+ severity: 'critical',
990
+ envVarName: () => 'REDIS_URL',
991
+ },
992
+ {
993
+ name: 'MySQL Connection String',
994
+ pattern: /(?:mysql[_-]?uri|MYSQL_URL|mysql[_-]?connection)\s*[:=]\s*['"](mysql:\/\/[^'"]+)['"]/gi,
995
+ severity: 'critical',
996
+ envVarName: () => 'MYSQL_URL',
997
+ },
998
+ {
999
+ name: 'Supabase Anon Key',
1000
+ pattern: /(?:supabase[_-]?anon[_-]?key|SUPABASE_ANON_KEY)\s*[:=]\s*['"](eyJ[a-zA-Z0-9_\-]{100,})['"]/gi,
1001
+ severity: 'critical',
1002
+ envVarName: () => 'SUPABASE_ANON_KEY',
1003
+ },
1004
+ {
1005
+ name: 'Supabase Service Role Key',
1006
+ pattern: /(?:supabase[_-]?service[_-]?role[_-]?key|SUPABASE_SERVICE_ROLE_KEY)\s*[:=]\s*['"](eyJ[a-zA-Z0-9_\-]{100,})['"]/gi,
1007
+ severity: 'critical',
1008
+ envVarName: () => 'SUPABASE_SERVICE_ROLE_KEY',
1009
+ },
1010
+ // Authentication Services
1011
+ {
1012
+ name: 'Auth0 Client Secret',
1013
+ pattern: /(?:auth0[_-]?client[_-]?secret|AUTH0_CLIENT_SECRET)\s*[:=]\s*['"]([a-zA-Z0-9_\-]{32,})['"]/gi,
1014
+ severity: 'critical',
1015
+ envVarName: () => 'AUTH0_CLIENT_SECRET',
1016
+ },
1017
+ {
1018
+ name: 'Clerk Secret Key',
1019
+ pattern: /(?:clerk[_-]?secret[_-]?key|CLERK_SECRET_KEY)\s*[:=]\s*['"](sk_[a-z]_[a-zA-Z0-9_\-]{50,})['"]/gi,
1020
+ severity: 'critical',
1021
+ envVarName: () => 'CLERK_SECRET_KEY',
1022
+ },
1023
+ // Email Services
1024
+ {
1025
+ name: 'Mailgun API Key',
1026
+ pattern: /(?:mailgun[_-]?api[_-]?key|MAILGUN_API_KEY)\s*[:=]\s*['"](key-[a-f0-9]{32})['"]/gi,
1027
+ severity: 'critical',
1028
+ envVarName: () => 'MAILGUN_API_KEY',
1029
+ },
1030
+ {
1031
+ name: 'Postmark API Key',
1032
+ pattern: /(?:postmark[_-]?api[_-]?key|POSTMARK_API_KEY)\s*[:=]\s*['"]([a-zA-Z0-9_\-]{40,})['"]/gi,
1033
+ severity: 'critical',
1034
+ envVarName: () => 'POSTMARK_API_KEY',
1035
+ },
1036
+ {
1037
+ name: 'Resend API Key',
1038
+ pattern: /(?:resend[_-]?api[_-]?key|RESEND_API_KEY)\s*[:=]\s*['"](re_[a-zA-Z0-9_\-]{40,})['"]/gi,
1039
+ severity: 'critical',
1040
+ envVarName: () => 'RESEND_API_KEY',
1041
+ },
1042
+ // Monitoring & Error Tracking
1043
+ {
1044
+ name: 'Sentry DSN',
1045
+ pattern: /(?:sentry[_-]?dsn|SENTRY_DSN)\s*[:=]\s*['"](https:\/\/[a-f0-9]{32}@[^'"]+\/[0-9]+)['"]/gi,
1046
+ severity: 'high',
1047
+ envVarName: () => 'SENTRY_DSN',
1048
+ },
1049
+ {
1050
+ name: 'Datadog API Key',
1051
+ pattern: /(?:datadog[_-]?api[_-]?key|DD_API_KEY)\s*[:=]\s*['"]([a-f0-9]{32})['"]/gi,
1052
+ severity: 'critical',
1053
+ envVarName: () => 'DD_API_KEY',
1054
+ },
1055
+ {
1056
+ name: 'New Relic License Key',
1057
+ pattern: /(?:newrelic[_-]?license[_-]?key|NEW_RELIC_LICENSE_KEY)\s*[:=]\s*['"]([a-f0-9]{40})['"]/gi,
1058
+ severity: 'critical',
1059
+ envVarName: () => 'NEW_RELIC_LICENSE_KEY',
1060
+ },
1061
+ // Payment Services
1062
+ {
1063
+ name: 'PayPal Client Secret',
1064
+ pattern: /(?:paypal[_-]?client[_-]?secret|PAYPAL_CLIENT_SECRET)\s*[:=]\s*['"]([a-zA-Z0-9_\-]{40,})['"]/gi,
1065
+ severity: 'critical',
1066
+ envVarName: () => 'PAYPAL_CLIENT_SECRET',
1067
+ },
1068
+ {
1069
+ name: 'Square Access Token',
1070
+ pattern: /(?:square[_-]?access[_-]?token|SQUARE_ACCESS_TOKEN)\s*[:=]\s*['"](EAAA[a-zA-Z0-9_\-]{40,})['"]/gi,
1071
+ severity: 'critical',
1072
+ envVarName: () => 'SQUARE_ACCESS_TOKEN',
1073
+ },
1074
+ // Communication Services
1075
+ {
1076
+ name: 'Discord Bot Token',
1077
+ pattern: /(?:discord[_-]?bot[_-]?token|DISCORD_BOT_TOKEN)\s*[:=]\s*['"]([MN][A-Za-z\d]{23}\.[\w-]{6}\.[\w-]{27})['"]/gi,
1078
+ severity: 'critical',
1079
+ envVarName: () => 'DISCORD_BOT_TOKEN',
1080
+ },
1081
+ {
1082
+ name: 'Discord Webhook URL',
1083
+ pattern: /(?:discord[_-]?webhook|DISCORD_WEBHOOK)\s*[:=]\s*['"](https:\/\/discord\.com\/api\/webhooks\/[^'"]+)['"]/gi,
1084
+ severity: 'high',
1085
+ envVarName: () => 'DISCORD_WEBHOOK_URL',
1086
+ },
1087
+ {
1088
+ name: 'Telegram Bot Token',
1089
+ pattern: /(?:telegram[_-]?bot[_-]?token|TELEGRAM_BOT_TOKEN)\s*[:=]\s*['"]([0-9]{8,10}:[a-zA-Z0-9_-]{35})['"]/gi,
1090
+ severity: 'critical',
1091
+ envVarName: () => 'TELEGRAM_BOT_TOKEN',
1092
+ },
1093
+ // Search & CDN Services
1094
+ {
1095
+ name: 'Algolia API Key',
1096
+ pattern: /(?:algolia[_-]?api[_-]?key|ALGOLIA_API_KEY)\s*[:=]\s*['"]([a-f0-9]{32})['"]/gi,
1097
+ severity: 'critical',
1098
+ envVarName: () => 'ALGOLIA_API_KEY',
1099
+ },
1100
+ {
1101
+ name: 'Cloudinary URL',
1102
+ pattern: /(?:cloudinary[_-]?url|CLOUDINARY_URL)\s*[:=]\s*['"](cloudinary:\/\/[^'"]+)['"]/gi,
1103
+ severity: 'critical',
1104
+ envVarName: () => 'CLOUDINARY_URL',
1105
+ },
1106
+ // CI/CD Services
1107
+ {
1108
+ name: 'CircleCI Token',
1109
+ pattern: /(?:circleci[_-]?token|CIRCLE_TOKEN)\s*[:=]\s*['"]([a-f0-9]{40})['"]/gi,
1110
+ severity: 'critical',
1111
+ envVarName: () => 'CIRCLE_TOKEN',
1112
+ },
1113
+ {
1114
+ name: 'Travis CI Token',
1115
+ pattern: /(?:travis[_-]?ci[_-]?token|TRAVIS_TOKEN)\s*[:=]\s*['"]([a-zA-Z0-9_\-]{22})['"]/gi,
1116
+ severity: 'critical',
1117
+ envVarName: () => 'TRAVIS_TOKEN',
1118
+ },
1119
+ // Analytics & Mobile Services
1120
+ {
1121
+ name: 'RevenueCat API Key',
1122
+ pattern: /(?:revenuecat[_-]?api[_-]?key|revenue[_-]?cat[_-]?key|REVENUECAT_API_KEY)\s*[:=]\s*['"](test_[a-zA-Z0-9_\-]{30,}|rcat_[a-zA-Z0-9_\-]{30,})['"]/gi,
1123
+ severity: 'critical',
1124
+ envVarName: () => 'REVENUECAT_API_KEY',
1125
+ },
1126
+ {
1127
+ name: 'Amplitude API Key',
1128
+ pattern: /(?:amplitude[_-]?api[_-]?key|AMPLITUDE_API_KEY)\s*[:=]\s*['"]([a-f0-9]{32})['"]/gi,
1129
+ severity: 'critical',
1130
+ envVarName: () => 'AMPLITUDE_API_KEY',
1131
+ },
1132
+ {
1133
+ name: 'Mixpanel Token',
1134
+ pattern: /(?:mixpanel[_-]?token|MIXPANEL_TOKEN)\s*[:=]\s*['"]([a-f0-9]{32})['"]/gi,
1135
+ severity: 'critical',
1136
+ envVarName: () => 'MIXPANEL_TOKEN',
1137
+ },
1138
+ {
1139
+ name: 'Segment Write Key',
1140
+ pattern: /(?:segment[_-]?write[_-]?key|SEGMENT_WRITE_KEY)\s*[:=]\s*['"]([a-zA-Z0-9_\-]{20,})['"]/gi,
1141
+ severity: 'critical',
1142
+ envVarName: () => 'SEGMENT_WRITE_KEY',
1143
+ },
1144
+ // Email addresses in config files (especially sensitive ones)
1145
+ {
1146
+ name: 'Email Address in Config',
1147
+ pattern: /(?:email|apple[_-]?id|admin[_-]?email|contact[_-]?email|appleId)\s*[:=]\s*['"]([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})['"]/gi,
1148
+ severity: 'medium',
1149
+ envVarName: (match) => {
1150
+ const varName = match[0].match(/(\w+)\s*[:=]/)?.[1]?.toUpperCase().replace(/[_-]/g, '_') || 'EMAIL';
1151
+ return varName;
1152
+ },
1153
+ },
1154
+ // Catch emails in JSON config files (eas.json, app.config.js, etc.) - only in config files
1155
+ // Only trigger if the field name suggests it's sensitive (appleId, email, adminEmail, etc.)
1156
+ {
1157
+ name: 'Email in JSON Config',
1158
+ pattern: /(?:appleId|apple[_-]?id|email|admin[_-]?email|contact[_-]?email|support[_-]?email)\s*[:=]\s*['"]([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})['"]/gi,
1159
+ severity: 'medium',
1160
+ envVarName: () => 'EMAIL',
1161
+ },
1162
+ // Generic hex strings that look like API keys (32+ chars) - catch any hex string that looks like a key
1163
+ {
1164
+ name: 'Hex API Key',
1165
+ pattern: /(?:key|api[_-]?key|token|amplitude|analytics)\s*[:=]\s*['"]([a-f0-9]{32,})['"]/gi,
1166
+ severity: 'high',
1167
+ envVarName: (match) => {
1168
+ const varName = match[0].match(/(\w+)\s*[:=]/)?.[1]?.toUpperCase().replace(/[_-]/g, '_') || 'API_KEY';
1169
+ return varName;
1170
+ },
1171
+ },
1172
+ // Catch any hex string in assignment (very generic, catches Amplitude and similar)
1173
+ // Only trigger if it's in a context that suggests it's a key (near "key", "api", "token", etc.)
1174
+ {
1175
+ name: 'Hex String (Potential Key)',
1176
+ pattern: /(?:key|api|token|secret|amplitude|analytics|mixpanel|amplitudeKey|apiKey).*[:=]\s*['"]([a-f0-9]{32})['"]/gi,
1177
+ severity: 'high',
1178
+ envVarName: () => 'API_KEY',
1179
+ },
1180
+ // Very generic: catch any 32-char hex string that's assigned (Amplitude, Mixpanel, etc.)
1181
+ // This is more aggressive but necessary to catch keys with generic variable names
1182
+ {
1183
+ name: 'Hex API Key (Generic)',
1184
+ pattern: /(?:const|let|var|export\s+const)\s+\w*(?:key|api|token|id|secret)\w*\s*[:=]\s*['"]([a-f0-9]{32})['"]/gi,
1185
+ severity: 'high',
1186
+ envVarName: () => 'API_KEY',
1187
+ },
1188
+ // Fallback patterns (catches || 'secret' or ?? 'secret')
1189
+ {
1190
+ name: 'Hardcoded Secret Fallback',
1191
+ pattern: /\|\|\s*['"]([a-zA-Z0-9_\-+/=]{20,})['"]|\?\?\s*['"]([a-zA-Z0-9_\-+/=]{20,})['"]/gi,
1192
+ severity: 'high',
1193
+ envVarName: () => 'SECRET',
1194
+ },
1195
+ // Test keys (often start with test_)
1196
+ {
1197
+ name: 'Test API Key',
1198
+ pattern: /(?:test[_-]?key|test[_-]?api[_-]?key|TEST_KEY)\s*[:=]\s*['"](test_[a-zA-Z0-9_\-]{20,})['"]/gi,
1199
+ severity: 'critical',
1200
+ envVarName: () => 'TEST_API_KEY',
1201
+ },
1202
+ // Generic test_ prefixed keys (catches RevenueCat and others) - very generic to catch any test_ key
1203
+ {
1204
+ name: 'Test Key (test_ prefix)',
1205
+ pattern: /[:=]\s*['"](test_[a-zA-Z0-9_\-]{25,})['"]/gi,
1206
+ severity: 'critical',
1207
+ envVarName: () => 'TEST_API_KEY',
1208
+ },
1209
+ // RevenueCat specific (catches rcat_ prefix too)
1210
+ {
1211
+ name: 'RevenueCat Key',
1212
+ pattern: /[:=]\s*['"](rcat_[a-zA-Z0-9_\-]{25,})['"]/gi,
1213
+ severity: 'critical',
1214
+ envVarName: () => 'REVENUECAT_API_KEY',
1215
+ },
1216
+ // Ultra-generic patterns - catch secrets regardless of variable naming
1217
+ // These are aggressive but necessary to catch all secrets
1218
+ // Any string that looks like an API key (20+ alphanumeric chars) in assignment
1219
+ {
1220
+ name: 'Potential API Key (Generic)',
1221
+ pattern: /[:=]\s*['"]([a-zA-Z0-9_\-+/=]{32,})['"]/g,
1222
+ severity: 'medium',
1223
+ envVarName: () => 'API_KEY',
1224
+ },
1225
+ // Any hex string 32+ chars (common for API keys)
1226
+ {
1227
+ name: 'Potential Hex Key',
1228
+ pattern: /[:=]\s*['"]([a-f0-9]{32,})['"]/gi,
1229
+ severity: 'medium',
1230
+ envVarName: () => 'API_KEY',
1231
+ },
1232
+ // Base64-like strings (40+ chars, common for tokens)
1233
+ {
1234
+ name: 'Potential Base64 Token',
1235
+ pattern: /[:=]\s*['"]([A-Za-z0-9+/=]{40,})['"]/g,
1236
+ severity: 'medium',
1237
+ envVarName: () => 'TOKEN',
1238
+ },
1239
+ // Any string starting with common prefixes
1240
+ {
1241
+ name: 'Potential Key (Common Prefix)',
1242
+ pattern: /[:=]\s*['"](sk[_-][a-zA-Z0-9_\-]{20,}|pk[_-][a-zA-Z0-9_\-]{20,}|rk[_-][a-zA-Z0-9_\-]{20,})['"]/gi,
1243
+ severity: 'high',
1244
+ envVarName: () => 'API_KEY',
1245
+ },
1246
+ // JWT tokens (eyJ...)
1247
+ {
1248
+ name: 'JWT Token',
1249
+ pattern: /[:=]\s*['"](eyJ[A-Za-z0-9\-_]{20,}\.[A-Za-z0-9\-_]{20,}\.[A-Za-z0-9\-_]{20,})['"]/g,
1250
+ severity: 'critical',
1251
+ envVarName: () => 'JWT_TOKEN',
1252
+ },
1253
+ // Connection strings (common patterns)
1254
+ {
1255
+ name: 'Connection String',
1256
+ pattern: /[:=]\s*['"]((?:mongodb|postgres|mysql|redis|amqp|https?):\/\/[^'"]{20,})['"]/gi,
1257
+ severity: 'critical',
1258
+ envVarName: () => 'CONNECTION_STRING',
1259
+ },
1260
+ // AWS keys (AKIA prefix)
1261
+ {
1262
+ name: 'AWS Access Key',
1263
+ pattern: /[:=]\s*['"](AKIA[0-9A-Z]{16})['"]/gi,
1264
+ severity: 'critical',
1265
+ envVarName: () => 'AWS_ACCESS_KEY_ID',
1266
+ },
1267
+ // Private keys (PEM format)
1268
+ {
1269
+ name: 'Private Key (PEM)',
1270
+ pattern: /-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----[\s\S]{50,}-----END\s+(?:RSA\s+)?PRIVATE\s+KEY-----/gi,
1271
+ severity: 'critical',
1272
+ envVarName: () => 'PRIVATE_KEY',
1273
+ },
1274
+ // OAuth tokens
1275
+ {
1276
+ name: 'OAuth Token',
1277
+ pattern: /[:=]\s*['"](ya29\.[A-Za-z0-9\-_]{50,}|1\/\/[A-Za-z0-9\-_]{50,})['"]/gi,
1278
+ severity: 'critical',
1279
+ envVarName: () => 'OAUTH_TOKEN',
1280
+ },
1281
+ // Generic password pattern (8+ chars, not just "password")
1282
+ {
1283
+ name: 'Password',
1284
+ pattern: /(?:password|pwd|passwd|secret[_-]?key)\s*[:=]\s*['"]([^'"]{8,})['"]/gi,
1285
+ severity: 'critical',
1286
+ envVarName: () => 'PASSWORD',
1287
+ },
1288
+ ];
1289
+ // Files to ignore during scan
1290
+ const IGNORE_PATTERNS = [
1291
+ /node_modules/,
1292
+ /\.git/,
1293
+ /dist/,
1294
+ /build/,
1295
+ /\.next/,
1296
+ /\.env/,
1297
+ /\.env\.local/,
1298
+ /\.env\.example/,
1299
+ /package-lock\.json/,
1300
+ /yarn\.lock/,
1301
+ /pnpm-lock\.yaml/,
1302
+ /\.lattice/,
1303
+ ];
1304
+ // File extensions to scan - comprehensive list of all text-based files that could be publicly exposed
1305
+ const SCAN_EXTENSIONS = [
1306
+ // Source code
1307
+ '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
1308
+ // Config files
1309
+ '.json', '.yaml', '.yml', '.toml', '.ini', '.conf', '.config',
1310
+ // Web files (publicly exposed)
1311
+ '.html', '.htm', '.css', '.scss', '.sass', '.less', '.styl',
1312
+ // Documentation (could contain examples with secrets)
1313
+ '.md', '.txt', '.rst', '.adoc',
1314
+ // Scripts
1315
+ '.sh', '.bash', '.zsh', '.fish', '.ps1', '.bat', '.cmd',
1316
+ // Docker & deployment
1317
+ '.dockerfile', '.dockerignore', '.gitignore', '.gitattributes',
1318
+ // Environment files
1319
+ '.env', '.env.local', '.env.production', '.env.development',
1320
+ // Config variants
1321
+ '.config.js', '.config.ts', '.config.json', '.config.yaml',
1322
+ // App configs
1323
+ 'app.json', 'app.config.js', 'app.config.ts',
1324
+ // Build configs
1325
+ 'webpack.config.js', 'vite.config.js', 'rollup.config.js',
1326
+ 'next.config.js', 'nuxt.config.js', 'svelte.config.js',
1327
+ // Other configs
1328
+ 'tsconfig.json', 'jsconfig.json', 'tailwind.config.js',
1329
+ 'postcss.config.js', 'babel.config.js', 'jest.config.js',
1330
+ // EAS config
1331
+ 'eas.json',
1332
+ // No extension but important files
1333
+ 'Dockerfile', 'docker-compose.yml', 'Makefile', 'Procfile',
1334
+ ];
1335
+ async function shouldScanFile(filePath, cwd) {
1336
+ const relativePath = (0, path_1.relative)(cwd, filePath);
1337
+ const fileName = relativePath.split(/[/\\]/).pop() || '';
1338
+ const lowerPath = relativePath.toLowerCase();
1339
+ // Check ignore patterns
1340
+ for (const pattern of IGNORE_PATTERNS) {
1341
+ if (pattern.test(relativePath)) {
1342
+ return false;
1343
+ }
1344
+ }
1345
+ // Check if file has no extension but is a known config file
1346
+ const noExtConfigFiles = ['Dockerfile', 'Makefile', 'Procfile', 'docker-compose.yml', 'eas.json', 'app.json'];
1347
+ if (noExtConfigFiles.includes(fileName) || noExtConfigFiles.some(name => lowerPath.includes(name.toLowerCase()))) {
1348
+ return true;
1349
+ }
1350
+ // Check file extension - handle files with multiple dots like app.config.js
1351
+ const lastDot = relativePath.lastIndexOf('.');
1352
+ if (lastDot === -1) {
1353
+ // No extension - check if it's a config file by name
1354
+ if (fileName.includes('config') || fileName.includes('Config')) {
1355
+ return true;
1356
+ }
1357
+ return false;
1358
+ }
1359
+ const ext = relativePath.substring(lastDot).toLowerCase();
1360
+ const baseName = relativePath.substring(0, lastDot).toLowerCase();
1361
+ // Check if extension matches directly
1362
+ if (SCAN_EXTENSIONS.some(e => e.toLowerCase() === ext)) {
1363
+ return true;
1364
+ }
1365
+ // Check for compound extensions like .config.js, .config.ts
1366
+ if (ext === '.js' || ext === '.ts' || ext === '.json' || ext === '.yaml' || ext === '.yml') {
1367
+ if (baseName.endsWith('.config') || baseName.includes('.config.')) {
1368
+ return true;
1369
+ }
1370
+ }
1371
+ // Check for build config files (webpack.config.js, vite.config.js, etc.)
1372
+ if (baseName.includes('webpack.config') || baseName.includes('vite.config') ||
1373
+ baseName.includes('rollup.config') || baseName.includes('next.config') ||
1374
+ baseName.includes('nuxt.config') || baseName.includes('svelte.config') ||
1375
+ baseName.includes('tailwind.config') || baseName.includes('postcss.config') ||
1376
+ baseName.includes('babel.config') || baseName.includes('jest.config') ||
1377
+ baseName.includes('tsconfig') || baseName.includes('jsconfig') ||
1378
+ baseName.includes('app.config')) {
1379
+ return true;
1380
+ }
1381
+ // Scan any text file that could be publicly exposed
1382
+ // This is aggressive but necessary for security
1383
+ const textFileExtensions = ['.txt', '.log', '.xml', '.svg', '.vue', '.svelte', '.astro'];
1384
+ if (textFileExtensions.includes(ext)) {
1385
+ return true;
1386
+ }
1387
+ return false;
1388
+ }
1389
+ // Validate secret formats
1390
+ async function validateSecret(type, value) {
1391
+ // OpenAI API Key validation
1392
+ if (type.includes('OpenAI')) {
1393
+ if (!value.startsWith('sk-')) {
1394
+ return {
1395
+ isValid: false,
1396
+ reason: 'OpenAI keys must start with "sk-"',
1397
+ suggestions: ['Check if this is a valid OpenAI API key'],
1398
+ };
1399
+ }
1400
+ if (value.length < 32) {
1401
+ return {
1402
+ isValid: false,
1403
+ reason: 'OpenAI keys must be at least 32 characters',
1404
+ suggestions: ['Key appears truncated'],
1405
+ };
1406
+ }
1407
+ return { isValid: true };
1408
+ }
1409
+ // AWS Access Key validation
1410
+ if (type.includes('AWS')) {
1411
+ if (!value.startsWith('AKIA')) {
1412
+ return {
1413
+ isValid: false,
1414
+ reason: 'AWS access keys must start with "AKIA"',
1415
+ suggestions: ['This may not be a valid AWS access key'],
1416
+ };
1417
+ }
1418
+ if (value.length !== 20) {
1419
+ return {
1420
+ isValid: false,
1421
+ reason: 'AWS access keys must be exactly 20 characters',
1422
+ suggestions: ['Key length is incorrect'],
1423
+ };
1424
+ }
1425
+ return { isValid: true };
1426
+ }
1427
+ // JWT Token validation
1428
+ if (type.includes('JWT')) {
1429
+ const parts = value.split('.');
1430
+ if (parts.length !== 3) {
1431
+ return {
1432
+ isValid: false,
1433
+ reason: 'JWT tokens must have 3 parts separated by dots',
1434
+ suggestions: ['Invalid JWT format'],
1435
+ };
1436
+ }
1437
+ return { isValid: true };
1438
+ }
1439
+ // Generic hex validation
1440
+ if (/^[a-f0-9]{32,}$/i.test(value)) {
1441
+ return { isValid: true };
1442
+ }
1443
+ // Generic base64 validation
1444
+ if (/^[A-Za-z0-9+/=]{40,}$/.test(value)) {
1445
+ return { isValid: true };
1446
+ }
1447
+ return {
1448
+ isValid: false,
1449
+ reason: 'Unknown secret format',
1450
+ suggestions: ['Verify this is a valid secret'],
1451
+ };
1452
+ }
1453
+ async function scanFileForSecrets(filePath, cwd) {
1454
+ const findings = [];
1455
+ try {
1456
+ const content = await fs_1.promises.readFile(filePath, 'utf-8');
1457
+ const lines = content.split('\n');
1458
+ for (const pattern of SECRET_PATTERNS) {
1459
+ let match;
1460
+ const regex = new RegExp(pattern.pattern.source, pattern.pattern.flags);
1461
+ while ((match = regex.exec(content)) !== null) {
1462
+ if (match.index === undefined)
1463
+ continue;
1464
+ const lineNumber = content.substring(0, match.index).split('\n').length;
1465
+ const line = lines[lineNumber - 1] || '';
1466
+ const column = match.index - content.substring(0, match.index).lastIndexOf('\n');
1467
+ // Extract the secret value
1468
+ // For ALL_CAPS pattern: match[1]=varName, match[2]=value
1469
+ // For other patterns: match[1]=value
1470
+ let secretValue;
1471
+ if (match.length > 2 && match[2] !== undefined && match[2] !== '') {
1472
+ secretValue = match[2];
1473
+ }
1474
+ else if (match[1] !== undefined && match[1] !== '') {
1475
+ secretValue = match[1];
1476
+ }
1477
+ else {
1478
+ secretValue = match[0];
1479
+ }
1480
+ // Validate the secret
1481
+ const validation = await validateSecret(pattern.name, secretValue);
1482
+ // Skip if already using environment variable (but not if it's a fallback like process.env.KEY || 'hardcoded')
1483
+ // Check if the line has a hardcoded value as a fallback
1484
+ const hasEnvVar = line.includes('process.env') || line.includes('import.meta.env') || line.includes('process.env');
1485
+ const hasFallback = line.includes('||') || line.includes('??') || line.includes('||') || line.includes('??');
1486
+ // If it's using env var AND has NO fallback, skip (it's safe)
1487
+ // BUT if it has a fallback, that's still a security issue - flag it
1488
+ if (hasEnvVar && !hasFallback) {
1489
+ continue;
1490
+ }
1491
+ // Also skip if it's clearly a comment or documentation example
1492
+ // (but be careful - some secrets are in comments!)
1493
+ if (line.trim().startsWith('//') || line.trim().startsWith('*') || line.trim().startsWith('#')) {
1494
+ // Only skip if it's clearly an example (contains "example", "demo", "placeholder")
1495
+ if (line.toLowerCase().includes('example') || line.toLowerCase().includes('demo') ||
1496
+ line.toLowerCase().includes('placeholder') || line.toLowerCase().includes('your_')) {
1497
+ continue;
1498
+ }
1499
+ }
1500
+ findings.push({
1501
+ file: (0, path_1.relative)(cwd, filePath),
1502
+ line: lineNumber,
1503
+ column: column - 1,
1504
+ type: pattern.name,
1505
+ severity: pattern.severity,
1506
+ value: secretValue.substring(0, 20) + '...',
1507
+ suggestion: pattern.envVarName ? `Use ${pattern.envVarName(match)} environment variable` : 'Move to environment variable',
1508
+ validation: validation,
1509
+ });
1510
+ }
1511
+ }
1512
+ }
1513
+ catch (error) {
1514
+ // Skip files that can't be read (binary, etc.)
1515
+ if (error.code !== 'EISDIR') {
1516
+ // Silently skip
1517
+ }
1518
+ }
1519
+ return findings;
1520
+ }
1521
+ async function getAllFiles(dir, cwd) {
1522
+ const files = [];
1523
+ try {
1524
+ const entries = await fs_1.promises.readdir(dir, { withFileTypes: true });
1525
+ for (const entry of entries) {
1526
+ const fullPath = (0, path_1.join)(dir, entry.name);
1527
+ if (entry.isDirectory()) {
1528
+ if (await shouldScanFile(fullPath, cwd)) {
1529
+ files.push(...await getAllFiles(fullPath, cwd));
1530
+ }
1531
+ }
1532
+ else if (entry.isFile()) {
1533
+ if (await shouldScanFile(fullPath, cwd)) {
1534
+ files.push(fullPath);
1535
+ }
1536
+ }
1537
+ }
1538
+ }
1539
+ catch {
1540
+ // Skip directories we can't read
1541
+ }
1542
+ return files;
1543
+ }
1544
+ async function ensureGitignore(cwd) {
1545
+ const gitignorePath = (0, path_1.join)(cwd, '.gitignore');
1546
+ const envPatterns = [
1547
+ '.env',
1548
+ '.env.local',
1549
+ '.env*.local',
1550
+ '.env.production',
1551
+ '.env.development',
1552
+ ];
1553
+ let gitignoreContent = '';
1554
+ try {
1555
+ gitignoreContent = await fs_1.promises.readFile(gitignorePath, 'utf-8');
1556
+ }
1557
+ catch {
1558
+ // .gitignore doesn't exist, create it
1559
+ }
1560
+ let needsUpdate = false;
1561
+ for (const pattern of envPatterns) {
1562
+ if (!gitignoreContent.includes(pattern)) {
1563
+ gitignoreContent += `\n${pattern}`;
1564
+ needsUpdate = true;
1565
+ }
1566
+ }
1567
+ if (needsUpdate) {
1568
+ await fs_1.promises.writeFile(gitignorePath, gitignoreContent.trim() + '\n', 'utf-8');
1569
+ }
1570
+ }
1571
+ async function fixSecretInFile(filePath, finding, envVarName, cwd) {
1572
+ try {
1573
+ let content = await fs_1.promises.readFile(filePath, 'utf-8');
1574
+ const lines = content.split('\n');
1575
+ const lineIndex = finding.line - 1;
1576
+ if (lineIndex >= lines.length) {
1577
+ return false;
1578
+ }
1579
+ const originalLine = lines[lineIndex];
1580
+ // Try to extract the variable name and replace the value
1581
+ // Pattern: variableName = "secret" or variableName: "secret"
1582
+ const assignmentMatch = originalLine.match(/(\w+)\s*[:=]\s*['"]([^'"]+)['"]/);
1583
+ if (assignmentMatch) {
1584
+ const varName = assignmentMatch[1];
1585
+ const isJson = filePath.endsWith('.json');
1586
+ if (isJson) {
1587
+ // For JSON files, replace with environment variable reference comment
1588
+ const newLine = originalLine.replace(/['"]([^'"]+)['"]/, `"${envVarName}" // TODO: Replace with process.env.${envVarName} in code`);
1589
+ lines[lineIndex] = newLine;
1590
+ }
1591
+ else {
1592
+ // For code files, replace with process.env reference
1593
+ const isNext = filePath.match(/\.(ts|tsx|js|jsx)$/);
1594
+ const envRef = isNext ? `process.env.${envVarName}` : `process.env.${envVarName}`;
1595
+ const newLine = originalLine.replace(/['"]([^'"]+)['"]/, `\`\${${envRef}}\``);
1596
+ lines[lineIndex] = newLine;
1597
+ }
1598
+ content = lines.join('\n');
1599
+ await fs_1.promises.writeFile(filePath, content, 'utf-8');
1600
+ return true;
1601
+ }
1602
+ }
1603
+ catch {
1604
+ return false;
1605
+ }
1606
+ return false;
1607
+ }
1608
+ async function addToEnvFile(cwd, envVarName, secretValue) {
1609
+ const envPath = (0, path_1.join)(cwd, '.env.local');
1610
+ let envContent = '';
1611
+ try {
1612
+ envContent = await fs_1.promises.readFile(envPath, 'utf-8');
1613
+ }
1614
+ catch {
1615
+ // File doesn't exist, create it
1616
+ }
1617
+ // Check if variable already exists
1618
+ if (envContent.includes(`${envVarName}=`)) {
1619
+ return; // Already exists
1620
+ }
1621
+ envContent += `\n${envVarName}=${secretValue}\n`;
1622
+ await fs_1.promises.writeFile(envPath, envContent.trim() + '\n', 'utf-8');
1623
+ }
1624
+ async function securityScan(options = {}) {
1625
+ const cwd = options.cwd || process.cwd();
1626
+ const findings = [];
1627
+ const errors = [];
1628
+ let fixed = 0;
1629
+ let totalFilesScanned = 0;
1630
+ try {
1631
+ // 1. Scan current files
1632
+ const files = await getAllFiles(cwd, cwd);
1633
+ totalFilesScanned = files.length;
1634
+ for (const file of files) {
1635
+ const fileFindings = await scanFileForSecrets(file, cwd);
1636
+ findings.push(...fileFindings);
1637
+ }
1638
+ // 2. Scan git history if requested
1639
+ if (options.scanGitHistory) {
1640
+ try {
1641
+ const gitFindings = await scanGitHistory(cwd);
1642
+ findings.push(...gitFindings);
1643
+ }
1644
+ catch (error) {
1645
+ errors.push(`Git history scan failed: ${error.message}`);
1646
+ }
1647
+ }
1648
+ // 3. Validate .env files are properly gitignored
1649
+ if (options.checkEnvFiles !== false) {
1650
+ try {
1651
+ const envIssues = await validateEnvFiles(cwd);
1652
+ if (envIssues.length > 0) {
1653
+ errors.push(...envIssues);
1654
+ }
1655
+ }
1656
+ catch (error) {
1657
+ errors.push(`Env file validation failed: ${error.message}`);
1658
+ }
1659
+ }
1660
+ if (options.fix && findings.length > 0) {
1661
+ // Group findings by file for efficient processing
1662
+ const findingsByFile = new Map();
1663
+ for (const finding of findings) {
1664
+ const fullPath = (0, path_1.join)(cwd, finding.file);
1665
+ if (!findingsByFile.has(fullPath)) {
1666
+ findingsByFile.set(fullPath, []);
1667
+ }
1668
+ findingsByFile.get(fullPath).push(finding);
1669
+ }
1670
+ // Ensure .gitignore includes .env files
1671
+ await ensureGitignore(cwd);
1672
+ // Fix each finding
1673
+ for (const [filePath, fileFindings] of findingsByFile.entries()) {
1674
+ try {
1675
+ const content = await fs_1.promises.readFile(filePath, 'utf-8');
1676
+ const lines = content.split('\n');
1677
+ for (const finding of fileFindings) {
1678
+ // Determine environment variable name
1679
+ const pattern = SECRET_PATTERNS.find(p => p.name === finding.type);
1680
+ if (!pattern || !pattern.envVarName) {
1681
+ continue;
1682
+ }
1683
+ // Re-scan the line to get the full secret value
1684
+ const lineIndex = finding.line - 1;
1685
+ if (lineIndex >= lines.length) {
1686
+ continue;
1687
+ }
1688
+ const line = lines[lineIndex];
1689
+ const regex = new RegExp(pattern.pattern.source, pattern.pattern.flags);
1690
+ const match = regex.exec(line);
1691
+ if (match) {
1692
+ // Extract the secret value
1693
+ // For ALL_CAPS pattern: match[1]=varName, match[2]=value
1694
+ // For other patterns: match[1]=value
1695
+ let secretValue;
1696
+ if (match.length > 2 && match[2] !== undefined && match[2] !== '') {
1697
+ secretValue = match[2];
1698
+ }
1699
+ else if (match[1] !== undefined && match[1] !== '') {
1700
+ secretValue = match[1];
1701
+ }
1702
+ else {
1703
+ secretValue = match[0];
1704
+ }
1705
+ const envVarName = pattern.envVarName(match);
1706
+ // Add to .env file
1707
+ await addToEnvFile(cwd, envVarName, secretValue);
1708
+ // Fix in source file
1709
+ if (await fixSecretInFile(filePath, finding, envVarName, cwd)) {
1710
+ fixed++;
1711
+ }
1712
+ }
1713
+ }
1714
+ }
1715
+ catch (error) {
1716
+ errors.push(`Failed to fix ${filePath}: ${error.message}`);
1717
+ }
1718
+ }
1719
+ }
1720
+ }
1721
+ catch (error) {
1722
+ errors.push(`Scan error: ${error.message}`);
1723
+ }
1724
+ // Install pre-commit hook if requested
1725
+ if (options.installHook) {
1726
+ try {
1727
+ await installPreCommitHook(cwd, options.hookPath);
1728
+ }
1729
+ catch (error) {
1730
+ errors.push(`Failed to install pre-commit hook: ${error.message}`);
1731
+ }
1732
+ }
1733
+ // Generate summary
1734
+ const summary = {
1735
+ totalFilesScanned,
1736
+ criticalFindings: findings.filter(f => f.severity === 'critical').length,
1737
+ highFindings: findings.filter(f => f.severity === 'high').length,
1738
+ mediumFindings: findings.filter(f => f.severity === 'medium').length,
1739
+ gitHistoryFindings: findings.filter(f => f.file.startsWith('git:')).length,
1740
+ envFileIssues: errors.filter(e => e.includes('.env') || e.includes('gitignore')).length,
1741
+ };
1742
+ // Export report if requested
1743
+ if (options.exportPath) {
1744
+ const format = options.exportFormat || (options.sarif ? 'sarif' : 'json');
1745
+ let content;
1746
+ if (format === 'sarif') {
1747
+ content = JSON.stringify(generateSarifReport({ findings, fixed, errors, summary }, cwd), null, 2);
1748
+ }
1749
+ else {
1750
+ content = JSON.stringify({ findings, fixed, errors, summary }, null, 2);
1751
+ }
1752
+ await fs_1.promises.writeFile(options.exportPath, content, 'utf-8');
1753
+ console.log(`✅ Report exported to: ${options.exportPath}`);
1754
+ }
1755
+ return { findings, fixed, errors, summary };
1756
+ }
1757
+ // Scan git history for secrets
1758
+ async function scanGitHistory(cwd) {
1759
+ const findings = [];
1760
+ try {
1761
+ // Check if git is available
1762
+ const { execSync } = require('child_process');
1763
+ // Get all commits
1764
+ const commits = execSync('git log --all --pretty=format:"%H"', {
1765
+ cwd,
1766
+ encoding: 'utf-8',
1767
+ stdio: 'pipe'
1768
+ }).trim().split('\n').filter(Boolean);
1769
+ // Scan each commit's diff
1770
+ for (const commit of commits.slice(0, 100)) { // Limit to last 100 commits for performance
1771
+ try {
1772
+ const diff = execSync(`git show ${commit}`, {
1773
+ cwd,
1774
+ encoding: 'utf-8',
1775
+ stdio: 'pipe',
1776
+ maxBuffer: 10 * 1024 * 1024 // 10MB buffer
1777
+ });
1778
+ // Scan diff for secrets
1779
+ for (const pattern of SECRET_PATTERNS) {
1780
+ const regex = new RegExp(pattern.pattern.source, pattern.pattern.flags);
1781
+ let match;
1782
+ while ((match = regex.exec(diff)) !== null) {
1783
+ if (match.index === undefined)
1784
+ continue;
1785
+ findings.push({
1786
+ file: `git:${commit.substring(0, 8)}`,
1787
+ line: 0,
1788
+ column: 0,
1789
+ type: `${pattern.name} (in git history)`,
1790
+ severity: pattern.severity,
1791
+ value: (match[1] || match[0]).substring(0, 20) + '...',
1792
+ suggestion: `Secret found in git history. Consider: 1) Rotating the secret, 2) Using git-filter-repo to remove it, 3) Using BFG Repo-Cleaner`,
1793
+ });
1794
+ }
1795
+ }
1796
+ }
1797
+ catch (error) {
1798
+ // Skip commits that can't be read
1799
+ continue;
1800
+ }
1801
+ }
1802
+ }
1803
+ catch (error) {
1804
+ // Git not available or not a git repo
1805
+ throw new Error(`Git history scan failed: ${error.message}`);
1806
+ }
1807
+ return findings;
1808
+ }
1809
+ // Validate .env files are properly gitignored
1810
+ async function validateEnvFiles(cwd) {
1811
+ const issues = [];
1812
+ try {
1813
+ const gitignorePath = (0, path_1.join)(cwd, '.gitignore');
1814
+ // Check if .gitignore exists
1815
+ let gitignoreContent = '';
1816
+ try {
1817
+ gitignoreContent = await fs_1.promises.readFile(gitignorePath, 'utf-8');
1818
+ }
1819
+ catch {
1820
+ issues.push('⚠️ No .gitignore file found. Create one to protect .env files.');
1821
+ return issues;
1822
+ }
1823
+ // Check if .env files are tracked by git
1824
+ try {
1825
+ const allFiles = (0, child_process_1.execSync)('git ls-files', {
1826
+ cwd,
1827
+ encoding: 'utf-8',
1828
+ stdio: 'pipe'
1829
+ }).trim().split('\n');
1830
+ const trackedEnvFiles = allFiles.filter((f) => f.includes('.env') && !f.includes('.env.example'));
1831
+ if (trackedEnvFiles.length > 0) {
1832
+ issues.push(`🚨 CRITICAL: .env files are tracked in git: ${trackedEnvFiles.join(', ')}`);
1833
+ issues.push(' Action required: Remove from git with: git rm --cached <file>');
1834
+ }
1835
+ }
1836
+ catch {
1837
+ // Git not available
1838
+ }
1839
+ // Check if .env files exist but aren't in .gitignore
1840
+ const envFiles = ['.env', '.env.local', '.env.production', '.env.development'];
1841
+ for (const envFile of envFiles) {
1842
+ const envPath = (0, path_1.join)(cwd, envFile);
1843
+ try {
1844
+ await fs_1.promises.access(envPath);
1845
+ // File exists, check if it's in .gitignore
1846
+ // Check for explicit filename, or patterns like .env*, .env.*, .env.local, etc.
1847
+ const isExplicitlyIgnored = gitignoreContent.includes(envFile);
1848
+ const hasEnvPattern = gitignoreContent.includes('.env*') || gitignoreContent.includes('.env.*');
1849
+ const isEnvFile = envFile.startsWith('.env');
1850
+ // Use git check-ignore to verify (most accurate)
1851
+ let isActuallyIgnored = false;
1852
+ try {
1853
+ const checkResult = (0, child_process_1.execSync)(`git check-ignore "${envFile}"`, {
1854
+ cwd,
1855
+ encoding: 'utf-8',
1856
+ stdio: 'pipe'
1857
+ }).trim();
1858
+ isActuallyIgnored = checkResult === envFile;
1859
+ }
1860
+ catch {
1861
+ // git check-ignore returns non-zero if file is NOT ignored
1862
+ isActuallyIgnored = false;
1863
+ }
1864
+ // Only warn if file exists AND is not actually ignored by git
1865
+ if (!isActuallyIgnored && !isExplicitlyIgnored && !hasEnvPattern) {
1866
+ issues.push(`⚠️ ${envFile} exists but may not be in .gitignore`);
1867
+ }
1868
+ }
1869
+ catch {
1870
+ // File doesn't exist, that's fine
1871
+ }
1872
+ }
1873
+ }
1874
+ catch (error) {
1875
+ // Not a git repo or git not available
1876
+ issues.push(`⚠️ Could not validate .env files: ${error.message}`);
1877
+ }
1878
+ return issues;
1879
+ }
1880
+ const ALLOWLIST_FILE = '.lattice/security-allowlist.json';
1881
+ async function loadAllowlist(cwd) {
1882
+ const allowlistPath = (0, path_1.join)(cwd, ALLOWLIST_FILE);
1883
+ try {
1884
+ const content = await fs_1.promises.readFile(allowlistPath, 'utf-8');
1885
+ return JSON.parse(content);
1886
+ }
1887
+ catch {
1888
+ return { patterns: [] };
1889
+ }
1890
+ }
1891
+ async function saveAllowlist(cwd, allowlist) {
1892
+ const allowlistPath = (0, path_1.join)(cwd, ALLOWLIST_FILE);
1893
+ const allowlistDir = (0, path_1.dirname)(allowlistPath);
1894
+ await fs_1.promises.mkdir(allowlistDir, { recursive: true });
1895
+ await fs_1.promises.writeFile(allowlistPath, JSON.stringify(allowlist, null, 2));
1896
+ }
1897
+ function isAllowlisted(finding, allowlist, cwd) {
1898
+ const relativeFile = (0, path_1.relative)(cwd, finding.file);
1899
+ return allowlist.patterns.some(pattern => {
1900
+ return pattern.file === relativeFile &&
1901
+ pattern.line === finding.line &&
1902
+ pattern.type === finding.type;
1903
+ });
1904
+ }
1905
+ async function addToAllowlist(cwd, finding, reason) {
1906
+ const allowlist = await loadAllowlist(cwd);
1907
+ const relativeFile = (0, path_1.relative)(cwd, finding.file);
1908
+ allowlist.patterns.push({
1909
+ file: relativeFile,
1910
+ line: finding.line,
1911
+ type: finding.type,
1912
+ reason,
1913
+ addedBy: process.env.USER || process.env.USERNAME || 'unknown',
1914
+ addedAt: new Date().toISOString(),
1915
+ });
1916
+ await saveAllowlist(cwd, allowlist);
1917
+ }
1918
+ // Install pre-commit hook
1919
+ async function installPreCommitHook(cwd, hookPath) {
1920
+ const gitHooksDir = (0, path_1.join)(cwd, '.git', 'hooks');
1921
+ const hookFile = hookPath || (0, path_1.join)(gitHooksDir, 'pre-commit');
1922
+ try {
1923
+ // Check if .git/hooks exists
1924
+ await fs_1.promises.access(gitHooksDir);
1925
+ }
1926
+ catch {
1927
+ throw new Error('Not a git repository. Run "git init" first.');
1928
+ }
1929
+ // Get the CLI path - try to find it relative to the hook location
1930
+ // In a published package, this would be in node_modules/@m2-ai/lattice-cli/dist/index.js
1931
+ // For development, it's in packages/cli/dist/index.js
1932
+ let cliPath;
1933
+ try {
1934
+ // Try to find the CLI in node_modules first (when installed as package)
1935
+ const nodeModulesPath = (0, path_1.join)(cwd, 'node_modules', '@latticeai', 'cli', 'dist', 'index.js');
1936
+ await fs_1.promises.access(nodeModulesPath);
1937
+ cliPath = nodeModulesPath;
1938
+ }
1939
+ catch {
1940
+ // Fall back to npx/latticeai command
1941
+ cliPath = 'latticeai';
1942
+ }
1943
+ const hookContent = process.platform === 'win32'
1944
+ ? `@echo off
1945
+ REM Lattice Security Scan Pre-commit Hook
1946
+ REM Generated by: lattice security-scan --install-hook
1947
+
1948
+ ${cliPath === 'latticeai' ? 'npx' : 'node'} "${cliPath}" security-scan --scan-git-history
1949
+
1950
+ if %errorlevel% neq 0 (
1951
+ echo.
1952
+ echo ❌ Pre-commit hook failed: Security scan detected secrets
1953
+ echo 💡 Tip: Run 'lattice security-scan --fix' to fix issues
1954
+ exit /b 1
1955
+ )
1956
+ `
1957
+ : `#!/bin/sh
1958
+ # Lattice Security Scan Pre-commit Hook
1959
+ # Generated by: lattice security-scan --install-hook
1960
+
1961
+ ${cliPath === 'latticeai' ? 'npx' : 'node'} "${cliPath}" security-scan --scan-git-history
1962
+
1963
+ # Exit with error if scan fails
1964
+ if [ $? -ne 0 ]; then
1965
+ echo ""
1966
+ echo "❌ Pre-commit hook failed: Security scan detected secrets"
1967
+ echo "💡 Tip: Run 'lattice security-scan --fix' to fix issues"
1968
+ exit 1
1969
+ fi
1970
+ `;
1971
+ await fs_1.promises.writeFile(hookFile, hookContent, { mode: process.platform === 'win32' ? undefined : 0o755 });
1972
+ console.log(`✅ Pre-commit hook installed at: ${hookFile}`);
1973
+ console.log(` The hook will run security scans before each commit.`);
1974
+ }
1975
+ function generateSarifReport(result, cwd) {
1976
+ const severityMap = {
1977
+ critical: 'error',
1978
+ high: 'error',
1979
+ medium: 'warning',
1980
+ };
1981
+ return {
1982
+ version: '2.1.0',
1983
+ $schema: 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',
1984
+ runs: [{
1985
+ tool: {
1986
+ driver: {
1987
+ name: 'Lattice Security Scan',
1988
+ version: '0.7.1',
1989
+ },
1990
+ },
1991
+ results: result.findings.map(finding => ({
1992
+ ruleId: finding.type.replace(/\s+/g, '_').replace(/[^a-zA-Z0-9_]/g, '_'),
1993
+ level: severityMap[finding.severity] || 'warning',
1994
+ message: {
1995
+ text: `${finding.type} found: ${finding.value}`,
1996
+ },
1997
+ locations: [{
1998
+ physicalLocation: {
1999
+ artifactLocation: {
2000
+ uri: finding.file.replace(/\\/g, '/'), // Normalize path separators
2001
+ },
2002
+ region: {
2003
+ startLine: finding.line || 1,
2004
+ startColumn: finding.column || 1,
2005
+ },
2006
+ },
2007
+ }],
2008
+ })),
2009
+ }],
2010
+ };
2011
+ }
2012
+ //# sourceMappingURL=commands.js.map