chainwall 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (348) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +278 -0
  3. package/commands/security-scan.md +35 -0
  4. package/dist/auditor/access-mapper.d.ts +3 -0
  5. package/dist/auditor/access-mapper.d.ts.map +1 -0
  6. package/dist/auditor/access-mapper.js +15 -0
  7. package/dist/auditor/access-mapper.js.map +1 -0
  8. package/dist/auditor/cli-detector.d.ts +7 -0
  9. package/dist/auditor/cli-detector.d.ts.map +1 -0
  10. package/dist/auditor/cli-detector.js +63 -0
  11. package/dist/auditor/cli-detector.js.map +1 -0
  12. package/dist/auditor/cross-reference.d.ts +4 -0
  13. package/dist/auditor/cross-reference.d.ts.map +1 -0
  14. package/dist/auditor/cross-reference.js +16 -0
  15. package/dist/auditor/cross-reference.js.map +1 -0
  16. package/dist/auditor/env-auditor.d.ts +9 -0
  17. package/dist/auditor/env-auditor.d.ts.map +1 -0
  18. package/dist/auditor/env-auditor.js +83 -0
  19. package/dist/auditor/env-auditor.js.map +1 -0
  20. package/dist/auditor/mcp-analyzer.d.ts +11 -0
  21. package/dist/auditor/mcp-analyzer.d.ts.map +1 -0
  22. package/dist/auditor/mcp-analyzer.js +145 -0
  23. package/dist/auditor/mcp-analyzer.js.map +1 -0
  24. package/dist/auditor/mcp-detector.d.ts +17 -0
  25. package/dist/auditor/mcp-detector.d.ts.map +1 -0
  26. package/dist/auditor/mcp-detector.js +86 -0
  27. package/dist/auditor/mcp-detector.js.map +1 -0
  28. package/dist/auditor/remediation.d.ts +26 -0
  29. package/dist/auditor/remediation.d.ts.map +1 -0
  30. package/dist/auditor/remediation.js +222 -0
  31. package/dist/auditor/remediation.js.map +1 -0
  32. package/dist/auditor/tool-detector.d.ts +15 -0
  33. package/dist/auditor/tool-detector.d.ts.map +1 -0
  34. package/dist/auditor/tool-detector.js +241 -0
  35. package/dist/auditor/tool-detector.js.map +1 -0
  36. package/dist/auditor/types.d.ts +31 -0
  37. package/dist/auditor/types.d.ts.map +1 -0
  38. package/dist/auditor/types.js +2 -0
  39. package/dist/auditor/types.js.map +1 -0
  40. package/dist/auditor/vscode-extension-scanner.d.ts +8 -0
  41. package/dist/auditor/vscode-extension-scanner.d.ts.map +1 -0
  42. package/dist/auditor/vscode-extension-scanner.js +51 -0
  43. package/dist/auditor/vscode-extension-scanner.js.map +1 -0
  44. package/dist/cli.d.ts +3 -0
  45. package/dist/cli.d.ts.map +1 -0
  46. package/dist/cli.js +159 -0
  47. package/dist/cli.js.map +1 -0
  48. package/dist/commands/audit.d.ts +8 -0
  49. package/dist/commands/audit.d.ts.map +1 -0
  50. package/dist/commands/audit.js +151 -0
  51. package/dist/commands/audit.js.map +1 -0
  52. package/dist/commands/init.d.ts +2 -0
  53. package/dist/commands/init.d.ts.map +1 -0
  54. package/dist/commands/init.js +34 -0
  55. package/dist/commands/init.js.map +1 -0
  56. package/dist/commands/remediate-cli.d.ts +3 -0
  57. package/dist/commands/remediate-cli.d.ts.map +1 -0
  58. package/dist/commands/remediate-cli.js +96 -0
  59. package/dist/commands/remediate-cli.js.map +1 -0
  60. package/dist/commands/scan.d.ts +11 -0
  61. package/dist/commands/scan.d.ts.map +1 -0
  62. package/dist/commands/scan.js +138 -0
  63. package/dist/commands/scan.js.map +1 -0
  64. package/dist/commands/watch.d.ts +6 -0
  65. package/dist/commands/watch.d.ts.map +1 -0
  66. package/dist/commands/watch.js +203 -0
  67. package/dist/commands/watch.js.map +1 -0
  68. package/dist/config.d.ts +19 -0
  69. package/dist/config.d.ts.map +1 -0
  70. package/dist/config.js +235 -0
  71. package/dist/config.js.map +1 -0
  72. package/dist/mcp-server/index.d.ts +3 -0
  73. package/dist/mcp-server/index.d.ts.map +1 -0
  74. package/dist/mcp-server/index.js +69 -0
  75. package/dist/mcp-server/index.js.map +1 -0
  76. package/dist/mcp-server/schemas.d.ts +13 -0
  77. package/dist/mcp-server/schemas.d.ts.map +1 -0
  78. package/dist/mcp-server/schemas.js +13 -0
  79. package/dist/mcp-server/schemas.js.map +1 -0
  80. package/dist/mcp-server/tools/audit-status.d.ts +3 -0
  81. package/dist/mcp-server/tools/audit-status.d.ts.map +1 -0
  82. package/dist/mcp-server/tools/audit-status.js +46 -0
  83. package/dist/mcp-server/tools/audit-status.js.map +1 -0
  84. package/dist/mcp-server/tools/check-command.d.ts +4 -0
  85. package/dist/mcp-server/tools/check-command.d.ts.map +1 -0
  86. package/dist/mcp-server/tools/check-command.js +30 -0
  87. package/dist/mcp-server/tools/check-command.js.map +1 -0
  88. package/dist/mcp-server/tools/scan-content.d.ts +4 -0
  89. package/dist/mcp-server/tools/scan-content.d.ts.map +1 -0
  90. package/dist/mcp-server/tools/scan-content.js +18 -0
  91. package/dist/mcp-server/tools/scan-content.js.map +1 -0
  92. package/dist/mcp-server/tools/scan-file.d.ts +4 -0
  93. package/dist/mcp-server/tools/scan-file.d.ts.map +1 -0
  94. package/dist/mcp-server/tools/scan-file.js +48 -0
  95. package/dist/mcp-server/tools/scan-file.js.map +1 -0
  96. package/dist/mcp-server/types.d.ts +15 -0
  97. package/dist/mcp-server/types.d.ts.map +1 -0
  98. package/dist/mcp-server/types.js +2 -0
  99. package/dist/mcp-server/types.js.map +1 -0
  100. package/dist/reporter/audit-report.d.ts +4 -0
  101. package/dist/reporter/audit-report.d.ts.map +1 -0
  102. package/dist/reporter/audit-report.js +186 -0
  103. package/dist/reporter/audit-report.js.map +1 -0
  104. package/dist/reporter/json-report.d.ts +3 -0
  105. package/dist/reporter/json-report.d.ts.map +1 -0
  106. package/dist/reporter/json-report.js +4 -0
  107. package/dist/reporter/json-report.js.map +1 -0
  108. package/dist/reporter/remediation-text.d.ts +3 -0
  109. package/dist/reporter/remediation-text.d.ts.map +1 -0
  110. package/dist/reporter/remediation-text.js +12 -0
  111. package/dist/reporter/remediation-text.js.map +1 -0
  112. package/dist/reporter/risk-scorer.d.ts +8 -0
  113. package/dist/reporter/risk-scorer.d.ts.map +1 -0
  114. package/dist/reporter/risk-scorer.js +40 -0
  115. package/dist/reporter/risk-scorer.js.map +1 -0
  116. package/dist/reporter/sarif-report.d.ts +3 -0
  117. package/dist/reporter/sarif-report.d.ts.map +1 -0
  118. package/dist/reporter/sarif-report.js +80 -0
  119. package/dist/reporter/sarif-report.js.map +1 -0
  120. package/dist/reporter/shared.d.ts +11 -0
  121. package/dist/reporter/shared.d.ts.map +1 -0
  122. package/dist/reporter/shared.js +85 -0
  123. package/dist/reporter/shared.js.map +1 -0
  124. package/dist/reporter/summary-generator.d.ts +16 -0
  125. package/dist/reporter/summary-generator.d.ts.map +1 -0
  126. package/dist/reporter/summary-generator.js +89 -0
  127. package/dist/reporter/summary-generator.js.map +1 -0
  128. package/dist/reporter/terminal-report.d.ts +4 -0
  129. package/dist/reporter/terminal-report.d.ts.map +1 -0
  130. package/dist/reporter/terminal-report.js +135 -0
  131. package/dist/reporter/terminal-report.js.map +1 -0
  132. package/dist/rules/crypto-rules.d.ts +3 -0
  133. package/dist/rules/crypto-rules.d.ts.map +1 -0
  134. package/dist/rules/crypto-rules.js +252 -0
  135. package/dist/rules/crypto-rules.js.map +1 -0
  136. package/dist/rules/default-rules.d.ts +9 -0
  137. package/dist/rules/default-rules.d.ts.map +1 -0
  138. package/dist/rules/default-rules.js +1319 -0
  139. package/dist/rules/default-rules.js.map +1 -0
  140. package/dist/rules/index.d.ts +7 -0
  141. package/dist/rules/index.d.ts.map +1 -0
  142. package/dist/rules/index.js +7 -0
  143. package/dist/rules/index.js.map +1 -0
  144. package/dist/rules/injection-rules.d.ts +8 -0
  145. package/dist/rules/injection-rules.d.ts.map +1 -0
  146. package/dist/rules/injection-rules.js +108 -0
  147. package/dist/rules/injection-rules.js.map +1 -0
  148. package/dist/rules/types.d.ts +52 -0
  149. package/dist/rules/types.d.ts.map +1 -0
  150. package/dist/rules/types.js +2 -0
  151. package/dist/rules/types.js.map +1 -0
  152. package/dist/scanner/filesystem-scanner.d.ts +26 -0
  153. package/dist/scanner/filesystem-scanner.d.ts.map +1 -0
  154. package/dist/scanner/filesystem-scanner.js +369 -0
  155. package/dist/scanner/filesystem-scanner.js.map +1 -0
  156. package/dist/scanner/injection-scanner.d.ts +12 -0
  157. package/dist/scanner/injection-scanner.d.ts.map +1 -0
  158. package/dist/scanner/injection-scanner.js +136 -0
  159. package/dist/scanner/injection-scanner.js.map +1 -0
  160. package/dist/scanner/permission-checker.d.ts +4 -0
  161. package/dist/scanner/permission-checker.d.ts.map +1 -0
  162. package/dist/scanner/permission-checker.js +37 -0
  163. package/dist/scanner/permission-checker.js.map +1 -0
  164. package/dist/scanner/redact.d.ts +3 -0
  165. package/dist/scanner/redact.d.ts.map +1 -0
  166. package/dist/scanner/redact.js +17 -0
  167. package/dist/scanner/redact.js.map +1 -0
  168. package/dist/scanner/rule-engine.d.ts +9 -0
  169. package/dist/scanner/rule-engine.d.ts.map +1 -0
  170. package/dist/scanner/rule-engine.js +129 -0
  171. package/dist/scanner/rule-engine.js.map +1 -0
  172. package/dist/scanner/system-targets.d.ts +17 -0
  173. package/dist/scanner/system-targets.d.ts.map +1 -0
  174. package/dist/scanner/system-targets.js +81 -0
  175. package/dist/scanner/system-targets.js.map +1 -0
  176. package/dist/tui/App.d.ts +6 -0
  177. package/dist/tui/App.d.ts.map +1 -0
  178. package/dist/tui/App.js +224 -0
  179. package/dist/tui/App.js.map +1 -0
  180. package/dist/tui/components/BootSequence.d.ts +6 -0
  181. package/dist/tui/components/BootSequence.d.ts.map +1 -0
  182. package/dist/tui/components/BootSequence.js +40 -0
  183. package/dist/tui/components/BootSequence.js.map +1 -0
  184. package/dist/tui/components/BorderedSection.d.ts +12 -0
  185. package/dist/tui/components/BorderedSection.d.ts.map +1 -0
  186. package/dist/tui/components/BorderedSection.js +7 -0
  187. package/dist/tui/components/BorderedSection.js.map +1 -0
  188. package/dist/tui/components/ErrorBoundary.d.ts +18 -0
  189. package/dist/tui/components/ErrorBoundary.d.ts.map +1 -0
  190. package/dist/tui/components/ErrorBoundary.js +36 -0
  191. package/dist/tui/components/ErrorBoundary.js.map +1 -0
  192. package/dist/tui/components/FirstUseHint.d.ts +7 -0
  193. package/dist/tui/components/FirstUseHint.d.ts.map +1 -0
  194. package/dist/tui/components/FirstUseHint.js +20 -0
  195. package/dist/tui/components/FirstUseHint.js.map +1 -0
  196. package/dist/tui/components/Footer.d.ts +10 -0
  197. package/dist/tui/components/Footer.d.ts.map +1 -0
  198. package/dist/tui/components/Footer.js +51 -0
  199. package/dist/tui/components/Footer.js.map +1 -0
  200. package/dist/tui/components/MetricCard.d.ts +11 -0
  201. package/dist/tui/components/MetricCard.d.ts.map +1 -0
  202. package/dist/tui/components/MetricCard.js +8 -0
  203. package/dist/tui/components/MetricCard.js.map +1 -0
  204. package/dist/tui/components/Panel.d.ts +15 -0
  205. package/dist/tui/components/Panel.d.ts.map +1 -0
  206. package/dist/tui/components/Panel.js +25 -0
  207. package/dist/tui/components/Panel.js.map +1 -0
  208. package/dist/tui/components/RemediationMenu.d.ts +10 -0
  209. package/dist/tui/components/RemediationMenu.d.ts.map +1 -0
  210. package/dist/tui/components/RemediationMenu.js +84 -0
  211. package/dist/tui/components/RemediationMenu.js.map +1 -0
  212. package/dist/tui/components/RiskGauge.d.ts +7 -0
  213. package/dist/tui/components/RiskGauge.d.ts.map +1 -0
  214. package/dist/tui/components/RiskGauge.js +55 -0
  215. package/dist/tui/components/RiskGauge.js.map +1 -0
  216. package/dist/tui/components/ScrollableList.d.ts +11 -0
  217. package/dist/tui/components/ScrollableList.d.ts.map +1 -0
  218. package/dist/tui/components/ScrollableList.js +14 -0
  219. package/dist/tui/components/ScrollableList.js.map +1 -0
  220. package/dist/tui/components/Section.d.ts +9 -0
  221. package/dist/tui/components/Section.d.ts.map +1 -0
  222. package/dist/tui/components/Section.js +7 -0
  223. package/dist/tui/components/Section.js.map +1 -0
  224. package/dist/tui/components/SectionHeader.d.ts +8 -0
  225. package/dist/tui/components/SectionHeader.d.ts.map +1 -0
  226. package/dist/tui/components/SectionHeader.js +15 -0
  227. package/dist/tui/components/SectionHeader.js.map +1 -0
  228. package/dist/tui/components/SeverityBadge.d.ts +5 -0
  229. package/dist/tui/components/SeverityBadge.d.ts.map +1 -0
  230. package/dist/tui/components/SeverityBadge.js +7 -0
  231. package/dist/tui/components/SeverityBadge.js.map +1 -0
  232. package/dist/tui/components/Sidebar.d.ts +2 -0
  233. package/dist/tui/components/Sidebar.d.ts.map +1 -0
  234. package/dist/tui/components/Sidebar.js +40 -0
  235. package/dist/tui/components/Sidebar.js.map +1 -0
  236. package/dist/tui/components/StatusIndicator.d.ts +8 -0
  237. package/dist/tui/components/StatusIndicator.d.ts.map +1 -0
  238. package/dist/tui/components/StatusIndicator.js +15 -0
  239. package/dist/tui/components/StatusIndicator.js.map +1 -0
  240. package/dist/tui/components/Table.d.ts +21 -0
  241. package/dist/tui/components/Table.d.ts.map +1 -0
  242. package/dist/tui/components/Table.js +38 -0
  243. package/dist/tui/components/Table.js.map +1 -0
  244. package/dist/tui/components/Transition.d.ts +8 -0
  245. package/dist/tui/components/Transition.d.ts.map +1 -0
  246. package/dist/tui/components/Transition.js +38 -0
  247. package/dist/tui/components/Transition.js.map +1 -0
  248. package/dist/tui/components/WelcomeScreen.d.ts +6 -0
  249. package/dist/tui/components/WelcomeScreen.d.ts.map +1 -0
  250. package/dist/tui/components/WelcomeScreen.js +14 -0
  251. package/dist/tui/components/WelcomeScreen.js.map +1 -0
  252. package/dist/tui/educational.d.ts +32 -0
  253. package/dist/tui/educational.d.ts.map +1 -0
  254. package/dist/tui/educational.js +117 -0
  255. package/dist/tui/educational.js.map +1 -0
  256. package/dist/tui/hooks/useAudit.d.ts +24 -0
  257. package/dist/tui/hooks/useAudit.d.ts.map +1 -0
  258. package/dist/tui/hooks/useAudit.js +263 -0
  259. package/dist/tui/hooks/useAudit.js.map +1 -0
  260. package/dist/tui/hooks/useConfig.d.ts +18 -0
  261. package/dist/tui/hooks/useConfig.d.ts.map +1 -0
  262. package/dist/tui/hooks/useConfig.js +85 -0
  263. package/dist/tui/hooks/useConfig.js.map +1 -0
  264. package/dist/tui/hooks/useHookStatus.d.ts +10 -0
  265. package/dist/tui/hooks/useHookStatus.d.ts.map +1 -0
  266. package/dist/tui/hooks/useHookStatus.js +59 -0
  267. package/dist/tui/hooks/useHookStatus.js.map +1 -0
  268. package/dist/tui/hooks/useLogs.d.ts +42 -0
  269. package/dist/tui/hooks/useLogs.d.ts.map +1 -0
  270. package/dist/tui/hooks/useLogs.js +105 -0
  271. package/dist/tui/hooks/useLogs.js.map +1 -0
  272. package/dist/tui/hooks/useScan.d.ts +39 -0
  273. package/dist/tui/hooks/useScan.d.ts.map +1 -0
  274. package/dist/tui/hooks/useScan.js +255 -0
  275. package/dist/tui/hooks/useScan.js.map +1 -0
  276. package/dist/tui/hooks/useTerminalSize.d.ts +10 -0
  277. package/dist/tui/hooks/useTerminalSize.d.ts.map +1 -0
  278. package/dist/tui/hooks/useTerminalSize.js +27 -0
  279. package/dist/tui/hooks/useTerminalSize.js.map +1 -0
  280. package/dist/tui/index.d.ts +2 -0
  281. package/dist/tui/index.d.ts.map +1 -0
  282. package/dist/tui/index.js +8 -0
  283. package/dist/tui/index.js.map +1 -0
  284. package/dist/tui/screens/AuditPanel.d.ts +7 -0
  285. package/dist/tui/screens/AuditPanel.d.ts.map +1 -0
  286. package/dist/tui/screens/AuditPanel.js +467 -0
  287. package/dist/tui/screens/AuditPanel.js.map +1 -0
  288. package/dist/tui/screens/LogsPanel.d.ts +2 -0
  289. package/dist/tui/screens/LogsPanel.d.ts.map +1 -0
  290. package/dist/tui/screens/LogsPanel.js +127 -0
  291. package/dist/tui/screens/LogsPanel.js.map +1 -0
  292. package/dist/tui/screens/OverviewPanel.d.ts +2 -0
  293. package/dist/tui/screens/OverviewPanel.d.ts.map +1 -0
  294. package/dist/tui/screens/OverviewPanel.js +84 -0
  295. package/dist/tui/screens/OverviewPanel.js.map +1 -0
  296. package/dist/tui/screens/ScanPanel.d.ts +2 -0
  297. package/dist/tui/screens/ScanPanel.d.ts.map +1 -0
  298. package/dist/tui/screens/ScanPanel.js +188 -0
  299. package/dist/tui/screens/ScanPanel.js.map +1 -0
  300. package/dist/tui/screens/ScanResultsPanel.d.ts +2 -0
  301. package/dist/tui/screens/ScanResultsPanel.d.ts.map +1 -0
  302. package/dist/tui/screens/ScanResultsPanel.js +394 -0
  303. package/dist/tui/screens/ScanResultsPanel.js.map +1 -0
  304. package/dist/tui/screens/SettingsPanel.d.ts +2 -0
  305. package/dist/tui/screens/SettingsPanel.d.ts.map +1 -0
  306. package/dist/tui/screens/SettingsPanel.js +353 -0
  307. package/dist/tui/screens/SettingsPanel.js.map +1 -0
  308. package/dist/tui/state.d.ts +35 -0
  309. package/dist/tui/state.d.ts.map +1 -0
  310. package/dist/tui/state.js +13 -0
  311. package/dist/tui/state.js.map +1 -0
  312. package/dist/tui/theme.d.ts +58 -0
  313. package/dist/tui/theme.d.ts.map +1 -0
  314. package/dist/tui/theme.js +80 -0
  315. package/dist/tui/theme.js.map +1 -0
  316. package/dist/version.d.ts +2 -0
  317. package/dist/version.d.ts.map +1 -0
  318. package/dist/version.js +5 -0
  319. package/dist/version.js.map +1 -0
  320. package/hooks/audit-logger.sh +74 -0
  321. package/hooks/detection-lib.sh +301 -0
  322. package/hooks/git-pre-commit.sh +195 -0
  323. package/hooks/git-pre-push.sh +125 -0
  324. package/hooks/git-safety.sh +152 -0
  325. package/hooks/security-scanner.sh +527 -0
  326. package/install.sh +543 -0
  327. package/package.json +67 -0
  328. package/patterns/credentials.yaml +317 -0
  329. package/patterns/dangerous-commands.yaml +167 -0
  330. package/patterns/pii.yaml +95 -0
  331. package/patterns/prompt-injection.yaml +131 -0
  332. package/patterns/supply-chain.yaml +119 -0
  333. package/rules/AGENTS.md +60 -0
  334. package/rules/SECURITY-RULES.md +177 -0
  335. package/rules/claude.md +9 -0
  336. package/rules/clinerules +29 -0
  337. package/rules/continuerules +29 -0
  338. package/rules/copilot-instructions.md +9 -0
  339. package/rules/cursor-security.mdc +14 -0
  340. package/rules/gemini.md +9 -0
  341. package/rules/kiro-security.md +29 -0
  342. package/rules/roocode-security.md +29 -0
  343. package/rules/trae-security.md +29 -0
  344. package/rules/windsurfrules +9 -0
  345. package/skill/llm-antivirus/SKILL.md +73 -0
  346. package/skill/llm-antivirus/references/threat-patterns.yaml +82 -0
  347. package/skill/llm-antivirus/scripts/security-audit.sh +244 -0
  348. package/uninstall.sh +215 -0
package/install.sh ADDED
@@ -0,0 +1,543 @@
1
+ #!/bin/bash
2
+ #
3
+ # ChainWall — Universal Installer
4
+ #
5
+ # Detects installed AI coding tools and installs appropriate security
6
+ # layers: hooks, instruction files, skills, and commands.
7
+ #
8
+ # Usage:
9
+ # ./install.sh # Install in current directory
10
+ # ./install.sh /path/to/project # Install in specific project
11
+ #
12
+ # Requirements: bash 3.2+, jq
13
+ # Idempotent: safe to run multiple times
14
+ #
15
+
16
+ set -euo pipefail
17
+
18
+ # ═══════════════════════════════════════════════════════════════════════
19
+ # Configuration
20
+ # ═══════════════════════════════════════════════════════════════════════
21
+
22
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
23
+ PROJECT_DIR="${1:-$(pwd)}"
24
+ LLMAV_DIR="${PROJECT_DIR}/.llm-av"
25
+
26
+ # Colors
27
+ RED=$'\e[31m'
28
+ GREEN=$'\e[32m'
29
+ YELLOW=$'\e[33m'
30
+ CYAN=$'\e[36m'
31
+ BOLD=$'\e[1m'
32
+ RESET=$'\e[0m'
33
+
34
+ # Installed components tracker
35
+ INSTALLED=()
36
+ SKIPPED=()
37
+ WARNINGS=()
38
+
39
+ # ═══════════════════════════════════════════════════════════════════════
40
+ # Helpers
41
+ # ═══════════════════════════════════════════════════════════════════════
42
+
43
+ info() { echo -e "${CYAN}[info]${RESET} $1"; }
44
+ ok() { echo -e "${GREEN}[ok]${RESET} $1"; INSTALLED+=("$1"); }
45
+ skip() { echo -e "${YELLOW}[skip]${RESET} $1"; SKIPPED+=("$1"); }
46
+ fail() { echo -e "${RED}[error]${RESET} $1" >&2; }
47
+ warn() { echo -e "${YELLOW}[warn]${RESET} $1"; WARNINGS+=("$1"); }
48
+
49
+ # Check if jq is available
50
+ check_jq() {
51
+ if ! command -v jq &> /dev/null; then
52
+ fail "jq is required but not installed."
53
+ echo " Install: brew install jq (macOS) or apt install jq (Linux)" >&2
54
+ exit 1
55
+ fi
56
+ }
57
+
58
+ # Merge hooks into Claude Code settings.local.json
59
+ # Non-destructive: preserves existing settings and hooks
60
+ merge_claude_hooks() {
61
+ local settings_dir="$1"
62
+ local settings_file="${settings_dir}/settings.local.json"
63
+
64
+ mkdir -p "$settings_dir"
65
+
66
+ # Read existing settings or create empty object
67
+ local settings='{}'
68
+ if [[ -f "$settings_file" ]]; then
69
+ settings=$(cat "$settings_file" 2>/dev/null || echo '{}')
70
+ # Validate JSON
71
+ if ! echo "$settings" | jq empty 2>/dev/null; then
72
+ local backup="${settings_file}.bak.$(date +%s)"
73
+ cp "$settings_file" "$backup"
74
+ warn "Malformed settings backed up to $backup"
75
+ settings='{}'
76
+ fi
77
+ fi
78
+
79
+ # Define hook entries
80
+ local security_scanner_hook
81
+ security_scanner_hook=$(jq -n '{
82
+ matcher: "Bash|Write|Edit|Read",
83
+ hooks: [{
84
+ type: "command",
85
+ command: ($dir + "/hooks/security-scanner.sh"),
86
+ timeout: 10
87
+ }]
88
+ }' --arg dir "$SCRIPT_DIR")
89
+
90
+ local git_safety_hook
91
+ git_safety_hook=$(jq -n '{
92
+ matcher: "Bash",
93
+ hooks: [{
94
+ type: "command",
95
+ command: ($dir + "/hooks/git-safety.sh"),
96
+ timeout: 10
97
+ }]
98
+ }' --arg dir "$SCRIPT_DIR")
99
+
100
+ local audit_logger_hook
101
+ audit_logger_hook=$(jq -n '{
102
+ matcher: ".*",
103
+ hooks: [{
104
+ type: "command",
105
+ command: ($dir + "/hooks/audit-logger.sh"),
106
+ timeout: 10
107
+ }]
108
+ }' --arg dir "$SCRIPT_DIR")
109
+
110
+ # Check if hooks already exist (by checking for security-scanner.sh)
111
+ local has_scanner
112
+ has_scanner=$(echo "$settings" | jq '[.hooks.PreToolUse[]? | .hooks[]? | .command | select(contains("security-scanner.sh"))] | length')
113
+
114
+ if [[ "$has_scanner" -gt 0 ]]; then
115
+ skip "Claude Code hooks (already installed)"
116
+ return
117
+ fi
118
+
119
+ # Merge hooks into settings
120
+ settings=$(echo "$settings" | jq \
121
+ --argjson scanner "$security_scanner_hook" \
122
+ --argjson git_safety "$git_safety_hook" \
123
+ --argjson audit "$audit_logger_hook" \
124
+ '
125
+ .hooks.PreToolUse = (.hooks.PreToolUse // []) + [$scanner, $git_safety] |
126
+ .hooks.PostToolUse = (.hooks.PostToolUse // []) + [$audit]
127
+ ')
128
+
129
+ # Atomic write
130
+ local tmp_file="${settings_file}.tmp.$$"
131
+ echo "$settings" | jq '.' > "$tmp_file"
132
+ mv "$tmp_file" "$settings_file"
133
+ manifest_add "$settings_file"
134
+ ok "Claude Code hooks (security-scanner, git-safety, audit-logger)"
135
+ }
136
+
137
+ # Record installed file in manifest
138
+ manifest_add() {
139
+ local path="$1"
140
+ if [[ -n "${MANIFEST_FILE:-}" ]] && [[ -f "${MANIFEST_FILE:-}" ]]; then
141
+ echo "$path" >> "$MANIFEST_FILE"
142
+ fi
143
+ }
144
+
145
+ # Copy instruction file if it doesn't exist (non-destructive)
146
+ copy_if_absent() {
147
+ local src="$1"
148
+ local dst="$2"
149
+ local label="$3"
150
+
151
+ if [[ -f "$dst" ]]; then
152
+ skip "$label (already exists)"
153
+ else
154
+ mkdir -p "$(dirname "$dst")"
155
+ cp "$src" "$dst"
156
+ manifest_add "$dst"
157
+ ok "$label"
158
+ fi
159
+ }
160
+
161
+ # ═══════════════════════════════════════════════════════════════════════
162
+ # Detection: Which AI tools are installed?
163
+ # ═══════════════════════════════════════════════════════════════════════
164
+
165
+ detect_tools() {
166
+ local tools=()
167
+
168
+ # Claude Code: .claude/ directory or claude in PATH
169
+ if [[ -d "${PROJECT_DIR}/.claude" ]] || command -v claude &> /dev/null; then
170
+ tools+=("claude")
171
+ fi
172
+
173
+ # Cursor: .cursor/ directory or .cursorrules file
174
+ if [[ -d "${PROJECT_DIR}/.cursor" ]] || [[ -f "${PROJECT_DIR}/.cursorrules" ]]; then
175
+ tools+=("cursor")
176
+ fi
177
+
178
+ # Copilot: .github/ directory detected
179
+ if [[ -d "${PROJECT_DIR}/.github" ]]; then
180
+ tools+=("copilot")
181
+ info "Detected .github/ directory — installing Copilot instructions"
182
+ fi
183
+
184
+ # Windsurf: .windsurfrules file
185
+ if [[ -f "${PROJECT_DIR}/.windsurfrules" ]]; then
186
+ tools+=("windsurf")
187
+ fi
188
+
189
+ # Gemini/Jules: GEMINI.md or .gemini/ directory
190
+ if [[ -f "${PROJECT_DIR}/GEMINI.md" ]] || [[ -d "${PROJECT_DIR}/.gemini" ]]; then
191
+ tools+=("gemini")
192
+ fi
193
+
194
+ # Cline: .cline/ directory or .clinerules file
195
+ if [[ -d "${PROJECT_DIR}/.cline" ]] || [[ -f "${PROJECT_DIR}/.clinerules" ]]; then
196
+ tools+=("cline")
197
+ fi
198
+
199
+ # RooCode: .roo/ directory
200
+ if [[ -d "${PROJECT_DIR}/.roo" ]]; then
201
+ tools+=("roocode")
202
+ fi
203
+
204
+ # Continue.dev: .continue/ directory or .continuerules file
205
+ if [[ -d "${PROJECT_DIR}/.continue" ]] || [[ -f "${PROJECT_DIR}/.continuerules" ]]; then
206
+ tools+=("continue")
207
+ fi
208
+
209
+ # Trae IDE: .trae/ directory
210
+ if [[ -d "${PROJECT_DIR}/.trae" ]]; then
211
+ tools+=("trae")
212
+ fi
213
+
214
+ # Kiro: .kiro/ directory
215
+ if [[ -d "${PROJECT_DIR}/.kiro" ]]; then
216
+ tools+=("kiro")
217
+ fi
218
+
219
+ # Always install AGENTS.md (universal standard)
220
+ tools+=("agents")
221
+
222
+ echo "${tools[@]}"
223
+ }
224
+
225
+ # ═══════════════════════════════════════════════════════════════════════
226
+ # Installation
227
+ # ═══════════════════════════════════════════════════════════════════════
228
+
229
+ echo -e "${BOLD}╔══════════════════════════════════════════════╗${RESET}"
230
+ echo -e "${BOLD}║ ChainWall — Universal Installer ║${RESET}"
231
+ echo -e "${BOLD}╚══════════════════════════════════════════════╝${RESET}"
232
+ echo ""
233
+
234
+ # Prerequisite check
235
+ check_jq
236
+
237
+ info "Project: ${PROJECT_DIR}"
238
+ info "Source: ${SCRIPT_DIR}"
239
+ echo ""
240
+
241
+ # Detect installed tools
242
+ TOOLS=$(detect_tools)
243
+ info "Detected tools: ${TOOLS}"
244
+ echo ""
245
+
246
+ # ─── Create .llm-av directory ──────────────────────────────────────────
247
+ mkdir -p "$LLMAV_DIR"
248
+ MANIFEST_FILE="${LLMAV_DIR}/manifest.txt"
249
+ : > "$MANIFEST_FILE" # Create/truncate manifest
250
+ ok "Created .llm-av/ directory"
251
+
252
+ # Create default config if absent
253
+ if [[ ! -f "${LLMAV_DIR}/config.json" ]]; then
254
+ cat > "${LLMAV_DIR}/config.json" << 'DEFAULTCONFIG'
255
+ {
256
+ "allowlist": {
257
+ "paths": [],
258
+ "patterns": []
259
+ },
260
+ "blocklist": {
261
+ "paths": [],
262
+ "patterns": []
263
+ }
264
+ }
265
+ DEFAULTCONFIG
266
+ ok "Default config (.llm-av/config.json)"
267
+ else
268
+ skip "Config file (already exists)"
269
+ fi
270
+
271
+ # ─── Install AGENTS.md (universal) ────────────────────────────────────
272
+ copy_if_absent \
273
+ "${SCRIPT_DIR}/rules/AGENTS.md" \
274
+ "${PROJECT_DIR}/AGENTS.md" \
275
+ "AGENTS.md (universal security rules)"
276
+
277
+ # ─── Platform-specific installations ──────────────────────────────────
278
+ for tool in $TOOLS; do
279
+ case "$tool" in
280
+ claude)
281
+ # Install hooks into .claude/settings.local.json
282
+ merge_claude_hooks "${PROJECT_DIR}/.claude"
283
+
284
+ # Install skill
285
+ if [[ -d "${SCRIPT_DIR}/skill/llm-antivirus" ]]; then
286
+ local_skill_dir="${PROJECT_DIR}/.claude/skill/llm-antivirus"
287
+ if [[ ! -d "$local_skill_dir" ]]; then
288
+ mkdir -p "$local_skill_dir"
289
+ cp -r "${SCRIPT_DIR}/skill/llm-antivirus/"* "$local_skill_dir/"
290
+ manifest_add "$local_skill_dir"
291
+ ok "Claude Code skill (llm-antivirus)"
292
+ else
293
+ skip "Claude Code skill (already exists)"
294
+ fi
295
+ fi
296
+
297
+ # Install commands
298
+ if [[ -d "${SCRIPT_DIR}/commands" ]]; then
299
+ local_commands_dir="${PROJECT_DIR}/.claude/commands"
300
+ if [[ ! -f "${local_commands_dir}/security-scan.md" ]]; then
301
+ mkdir -p "$local_commands_dir"
302
+ cp "${SCRIPT_DIR}/commands/security-scan.md" "$local_commands_dir/"
303
+ manifest_add "${local_commands_dir}/security-scan.md"
304
+ ok "Claude Code /security-scan command"
305
+ else
306
+ skip "Claude Code /security-scan command (already exists)"
307
+ fi
308
+ fi
309
+ ;;
310
+
311
+ cursor)
312
+ copy_if_absent \
313
+ "${SCRIPT_DIR}/rules/cursor-security.mdc" \
314
+ "${PROJECT_DIR}/.cursor/rules/security.mdc" \
315
+ "Cursor security rules (.cursor/rules/security.mdc)"
316
+ # Also deploy .cursorrules fallback for older Cursor versions
317
+ copy_if_absent \
318
+ "${SCRIPT_DIR}/rules/cursor-security.mdc" \
319
+ "${PROJECT_DIR}/.cursorrules" \
320
+ "Cursor fallback rules (.cursorrules)"
321
+ ;;
322
+
323
+ copilot)
324
+ copy_if_absent \
325
+ "${SCRIPT_DIR}/rules/copilot-instructions.md" \
326
+ "${PROJECT_DIR}/.github/copilot-instructions.md" \
327
+ "Copilot instructions (.github/copilot-instructions.md)"
328
+ ;;
329
+
330
+ windsurf)
331
+ # Append to existing .windsurfrules rather than overwrite
332
+ if [[ -f "${PROJECT_DIR}/.windsurfrules" ]]; then
333
+ if ! grep -q "ChainWall" "${PROJECT_DIR}/.windsurfrules" 2>/dev/null; then
334
+ cat "${SCRIPT_DIR}/rules/windsurfrules" >> "${PROJECT_DIR}/.windsurfrules"
335
+ manifest_add "${PROJECT_DIR}/.windsurfrules"
336
+ ok "Windsurf security rules (appended to .windsurfrules)"
337
+ else
338
+ skip "Windsurf security rules (already present)"
339
+ fi
340
+ else
341
+ cp "${SCRIPT_DIR}/rules/windsurfrules" "${PROJECT_DIR}/.windsurfrules"
342
+ ok "Windsurf security rules (.windsurfrules)"
343
+ fi
344
+ ;;
345
+
346
+ gemini)
347
+ copy_if_absent \
348
+ "${SCRIPT_DIR}/rules/gemini.md" \
349
+ "${PROJECT_DIR}/GEMINI.md" \
350
+ "Gemini security rules (GEMINI.md)"
351
+ copy_if_absent \
352
+ "${SCRIPT_DIR}/rules/gemini.md" \
353
+ "${PROJECT_DIR}/.gemini/styleguide.md" \
354
+ "Gemini styleguide (.gemini/styleguide.md)"
355
+ ;;
356
+
357
+ cline)
358
+ copy_if_absent \
359
+ "${SCRIPT_DIR}/rules/clinerules" \
360
+ "${PROJECT_DIR}/.clinerules" \
361
+ "Cline security rules (.clinerules)"
362
+ ;;
363
+
364
+ roocode)
365
+ copy_if_absent \
366
+ "${SCRIPT_DIR}/rules/roocode-security.md" \
367
+ "${PROJECT_DIR}/.roo/rules/security.md" \
368
+ "RooCode security rules (.roo/rules/security.md)"
369
+ ;;
370
+
371
+ continue)
372
+ copy_if_absent \
373
+ "${SCRIPT_DIR}/rules/continuerules" \
374
+ "${PROJECT_DIR}/.continuerules" \
375
+ "Continue.dev security rules (.continuerules)"
376
+ ;;
377
+
378
+ trae)
379
+ copy_if_absent \
380
+ "${SCRIPT_DIR}/rules/trae-security.md" \
381
+ "${PROJECT_DIR}/.trae/rules/security.md" \
382
+ "Trae IDE security rules (.trae/rules/security.md)"
383
+ ;;
384
+
385
+ kiro)
386
+ copy_if_absent \
387
+ "${SCRIPT_DIR}/rules/kiro-security.md" \
388
+ "${PROJECT_DIR}/.kiro/rules/security.md" \
389
+ "Kiro security rules (.kiro/rules/security.md)"
390
+ ;;
391
+
392
+ agents)
393
+ # Already handled above
394
+ ;;
395
+ esac
396
+ done
397
+
398
+ # ─── Update .gitignore ────────────────────────────────────────────────
399
+ if [[ -f "${PROJECT_DIR}/.gitignore" ]]; then
400
+ GITIGNORE_UPDATED=false
401
+ for pattern in ".llm-av/" ".env" ".env.local"; do
402
+ if ! grep -qxF "$pattern" "${PROJECT_DIR}/.gitignore" 2>/dev/null; then
403
+ echo "$pattern" >> "${PROJECT_DIR}/.gitignore"
404
+ GITIGNORE_UPDATED=true
405
+ fi
406
+ done
407
+ if [[ "$GITIGNORE_UPDATED" == "true" ]]; then
408
+ ok "Updated .gitignore with sensitive patterns"
409
+ else
410
+ skip ".gitignore (patterns already present)"
411
+ fi
412
+ else
413
+ cat > "${PROJECT_DIR}/.gitignore" << 'GITIGNORE'
414
+ # ChainWall
415
+ .llm-av/
416
+ .env
417
+ .env.local
418
+ GITIGNORE
419
+ ok "Created .gitignore with sensitive patterns"
420
+ fi
421
+
422
+ # ─── Install git hooks ───────────────────────────────────────────────
423
+ if [[ -d "${PROJECT_DIR}/.git" ]]; then
424
+ HOOKS_DIR="${PROJECT_DIR}/.git/hooks"
425
+ mkdir -p "$HOOKS_DIR"
426
+
427
+ for hook_name in pre-commit pre-push; do
428
+ src_hook="${SCRIPT_DIR}/hooks/git-${hook_name}.sh"
429
+ dst_hook="${HOOKS_DIR}/${hook_name}"
430
+
431
+ if [[ ! -f "$src_hook" ]]; then
432
+ continue
433
+ fi
434
+
435
+ if [[ -f "$dst_hook" ]]; then
436
+ # Check if it's already our hook
437
+ if grep -q "ChainWall" "$dst_hook" 2>/dev/null; then
438
+ skip "Git ${hook_name} hook (already installed)"
439
+ else
440
+ # Backup existing hook, create wrapper
441
+ cp "$dst_hook" "${dst_hook}.existing"
442
+ cat > "$dst_hook" << HOOKWRAPPER
443
+ #!/bin/bash
444
+ # ChainWall wrapper — runs both existing and security hooks
445
+ # Original hook backed up to ${hook_name}.existing
446
+
447
+ # Run existing hook first
448
+ if [[ -x "${dst_hook}.existing" ]]; then
449
+ "${dst_hook}.existing" "\$@"
450
+ EXISTING_RC=\$?
451
+ if [[ \$EXISTING_RC -ne 0 ]]; then
452
+ exit \$EXISTING_RC
453
+ fi
454
+ fi
455
+
456
+ # Run ChainWall hook
457
+ exec "${src_hook}" "\$@"
458
+ HOOKWRAPPER
459
+ chmod +x "$dst_hook"
460
+ manifest_add "$dst_hook"
461
+ ok "Git ${hook_name} hook (wrapped existing)"
462
+ fi
463
+ else
464
+ # No existing hook — create a simple forwarding script
465
+ cat > "$dst_hook" << HOOKSCRIPT
466
+ #!/bin/bash
467
+ # ChainWall — ${hook_name} hook
468
+ exec "${src_hook}" "\$@"
469
+ HOOKSCRIPT
470
+ chmod +x "$dst_hook"
471
+ manifest_add "$dst_hook"
472
+ ok "Git ${hook_name} hook"
473
+ fi
474
+ done
475
+ else
476
+ skip "Git hooks (no .git directory found)"
477
+ fi
478
+
479
+ # ─── Offer MCP server config (Claude Desktop / Cursor) ──────────────
480
+ MCP_SERVER_PATH="${SCRIPT_DIR}/dist/mcp-server/index.js"
481
+ if [[ -f "$MCP_SERVER_PATH" ]]; then
482
+ # Claude Desktop
483
+ CLAUDE_DESKTOP_CONFIG="${HOME}/Library/Application Support/Claude/claude_desktop_config.json"
484
+ if [[ -f "$CLAUDE_DESKTOP_CONFIG" ]]; then
485
+ if ! jq -e '.mcpServers."llm-antivirus"' "$CLAUDE_DESKTOP_CONFIG" &>/dev/null; then
486
+ UPDATED=$(jq --arg path "$MCP_SERVER_PATH" \
487
+ '.mcpServers."llm-antivirus" = { "command": "node", "args": [$path] }' \
488
+ "$CLAUDE_DESKTOP_CONFIG")
489
+ echo "$UPDATED" | jq '.' > "${CLAUDE_DESKTOP_CONFIG}.tmp.$$"
490
+ mv "${CLAUDE_DESKTOP_CONFIG}.tmp.$$" "$CLAUDE_DESKTOP_CONFIG"
491
+ ok "MCP server registered (Claude Desktop)"
492
+ else
493
+ skip "MCP server (already in Claude Desktop config)"
494
+ fi
495
+ fi
496
+
497
+ # Cursor MCP config
498
+ CURSOR_MCP_CONFIG="${HOME}/.cursor/mcp.json"
499
+ if [[ -d "${HOME}/.cursor" ]]; then
500
+ if [[ ! -f "$CURSOR_MCP_CONFIG" ]]; then
501
+ echo '{"mcpServers":{}}' > "$CURSOR_MCP_CONFIG"
502
+ fi
503
+ if ! jq -e '.mcpServers."llm-antivirus"' "$CURSOR_MCP_CONFIG" &>/dev/null; then
504
+ UPDATED=$(jq --arg path "$MCP_SERVER_PATH" \
505
+ '.mcpServers."llm-antivirus" = { "command": "node", "args": [$path] }' \
506
+ "$CURSOR_MCP_CONFIG")
507
+ echo "$UPDATED" | jq '.' > "${CURSOR_MCP_CONFIG}.tmp.$$"
508
+ mv "${CURSOR_MCP_CONFIG}.tmp.$$" "$CURSOR_MCP_CONFIG"
509
+ ok "MCP server registered (Cursor)"
510
+ else
511
+ skip "MCP server (already in Cursor config)"
512
+ fi
513
+ fi
514
+ fi
515
+
516
+ # ═══════════════════════════════════════════════════════════════════════
517
+ # Summary
518
+ # ═══════════════════════════════════════════════════════════════════════
519
+
520
+ echo ""
521
+ echo -e "${BOLD}=== Installation Summary ===${RESET}"
522
+ echo -e "${GREEN}Installed: ${#INSTALLED[@]}${RESET}"
523
+ for item in "${INSTALLED[@]}"; do
524
+ echo -e " ${GREEN}+${RESET} $item"
525
+ done
526
+
527
+ if [[ ${#SKIPPED[@]} -gt 0 ]]; then
528
+ echo -e "${YELLOW}Skipped: ${#SKIPPED[@]}${RESET}"
529
+ for item in "${SKIPPED[@]}"; do
530
+ echo -e " ${YELLOW}-${RESET} $item"
531
+ done
532
+ fi
533
+
534
+ if [[ ${#WARNINGS[@]} -gt 0 ]]; then
535
+ echo -e "${RED}Warnings: ${#WARNINGS[@]}${RESET}"
536
+ for item in "${WARNINGS[@]}"; do
537
+ echo -e " ${RED}!${RESET} $item"
538
+ done
539
+ fi
540
+
541
+ echo ""
542
+ echo -e "${GREEN}${BOLD}ChainWall installed successfully.${RESET}"
543
+ echo -e "Run ${CYAN}chainwall scan${RESET} to scan your project."
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "chainwall",
3
+ "version": "0.1.0",
4
+ "description": "Antivirus for AI coding agents — scan your machine, see what's exposed, block threats",
5
+ "type": "module",
6
+ "bin": {
7
+ "chainwall": "./dist/cli.js",
8
+ "chainwall-mcp": "./dist/mcp-server/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "prepare": "tsc",
13
+ "test": "vitest run",
14
+ "test:watch": "vitest",
15
+ "dev": "tsx src/cli.ts"
16
+ },
17
+ "engines": {
18
+ "node": ">=18.17.0"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/consulalialpric/chainwall.git"
23
+ },
24
+ "homepage": "https://github.com/consulalialpric/chainwall",
25
+ "bugs": {
26
+ "url": "https://github.com/consulalialpric/chainwall/issues"
27
+ },
28
+ "author": "consulalialpric",
29
+ "license": "MIT",
30
+ "keywords": [
31
+ "security", "ai-safety", "antivirus", "secrets-detection",
32
+ "prompt-injection", "llm-security", "ai-agents", "mcp",
33
+ "pre-commit-hook", "claude-code", "cursor", "copilot"
34
+ ],
35
+ "files": [
36
+ "dist/",
37
+ "hooks/",
38
+ "patterns/",
39
+ "rules/",
40
+ "skill/",
41
+ "commands/",
42
+ "install.sh",
43
+ "uninstall.sh",
44
+ "LICENSE",
45
+ "README.md"
46
+ ],
47
+ "dependencies": {
48
+ "@inkjs/ui": "^2.0.0",
49
+ "@modelcontextprotocol/sdk": "^1.26.0",
50
+ "chalk": "^5.4.1",
51
+ "commander": "^13.1.0",
52
+ "ink": "^6.6.0",
53
+ "ink-big-text": "^2.0.0",
54
+ "ink-gradient": "^3.0.0",
55
+ "ink-spinner": "^5.0.0",
56
+ "ora": "^8.2.0",
57
+ "react": "^19.2.4",
58
+ "zod": "^4.3.6"
59
+ },
60
+ "devDependencies": {
61
+ "@types/node": "^22.13.1",
62
+ "@types/react": "^19.2.13",
63
+ "tsx": "^4.19.2",
64
+ "typescript": "^5.7.3",
65
+ "vitest": "^3.0.5"
66
+ }
67
+ }