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
@@ -0,0 +1,203 @@
1
+ import { watch } from 'node:fs';
2
+ import { readFile, lstat } from 'node:fs/promises';
3
+ import { resolve, relative, basename, sep } from 'node:path';
4
+ import chalk from 'chalk';
5
+ import { loadConfig } from '../config.js';
6
+ import { createRuleEngine } from '../scanner/rule-engine.js';
7
+ import { allRules } from '../rules/index.js';
8
+ import { scanFileForInjection } from '../scanner/injection-scanner.js';
9
+ import { SEVERITY_COLOR } from '../reporter/shared.js';
10
+ import { MAX_FILE_SIZE, shouldSkipExtension, isKnownText, isBinary, buildSkipSet, } from '../scanner/filesystem-scanner.js';
11
+ const SEVERITY_TAG = {
12
+ critical: 'CRIT',
13
+ high: 'HIGH',
14
+ medium: 'MED ',
15
+ low: 'LOW ',
16
+ };
17
+ const DEBOUNCE_MS = 200;
18
+ function containsSkipDir(filePath, skipSet) {
19
+ const segments = filePath.split(sep);
20
+ for (const seg of segments) {
21
+ if (skipSet.has(seg))
22
+ return true;
23
+ }
24
+ return false;
25
+ }
26
+ function contentHash(content) {
27
+ // Lightweight hash: first 64 chars + length. Not crypto, just change detection.
28
+ return content.slice(0, 64) + ':' + content.length;
29
+ }
30
+ export async function runWatch(targetDir, options) {
31
+ const dir = resolve(targetDir);
32
+ const config = loadConfig(dir);
33
+ const engine = createRuleEngine({ rules: allRules, config });
34
+ const skipSet = buildSkipSet({ extraSkipDirs: config.skipDirs });
35
+ // Session stats
36
+ let filesChecked = 0;
37
+ let totalFindings = 0;
38
+ const startTime = Date.now();
39
+ // Debounce timers per file
40
+ const timers = new Map();
41
+ // Content hash cache — skip re-scan if content unchanged
42
+ const hashCache = new Map();
43
+ // Per-file dedup — reset when file changes
44
+ const findingsDedup = new Map();
45
+ function formatDuration(ms) {
46
+ const totalSec = Math.floor(ms / 1000);
47
+ const min = Math.floor(totalSec / 60);
48
+ const sec = totalSec % 60;
49
+ if (min > 0)
50
+ return `${min}m ${sec}s`;
51
+ return `${sec}s`;
52
+ }
53
+ function printFinding(finding, relPath) {
54
+ if (options.json) {
55
+ const obj = {
56
+ severity: finding.severity,
57
+ ruleId: finding.ruleId,
58
+ file: relPath,
59
+ line: finding.line,
60
+ };
61
+ if (options.verbose) {
62
+ obj.description = finding.description;
63
+ obj.matchedText = finding.matchedText;
64
+ }
65
+ console.log(JSON.stringify(obj));
66
+ return;
67
+ }
68
+ const tag = SEVERITY_TAG[finding.severity];
69
+ const color = SEVERITY_COLOR[finding.severity];
70
+ const location = finding.line > 0 ? `${relPath}:${finding.line}` : relPath;
71
+ let line = color(`[${tag}]`) + ` ${finding.ruleId} \u2014 ${location}`;
72
+ if (options.verbose) {
73
+ line += `\n ${finding.description}`;
74
+ line += `\n matched: ${finding.matchedText}`;
75
+ }
76
+ console.log(line);
77
+ }
78
+ async function processFile(filePath) {
79
+ const relPath = relative(dir, filePath);
80
+ const name = basename(filePath);
81
+ // Skip checks
82
+ if (containsSkipDir(relPath, skipSet))
83
+ return;
84
+ if (shouldSkipExtension(name))
85
+ return;
86
+ let stat;
87
+ try {
88
+ stat = await lstat(filePath);
89
+ }
90
+ catch {
91
+ return; // File deleted or inaccessible
92
+ }
93
+ if (!stat.isFile())
94
+ return;
95
+ if (stat.size === 0 || stat.size > MAX_FILE_SIZE)
96
+ return;
97
+ // Skip binary files
98
+ if (!isKnownText(name) && await isBinary(filePath))
99
+ return;
100
+ let content;
101
+ try {
102
+ content = await readFile(filePath, 'utf-8');
103
+ }
104
+ catch {
105
+ return;
106
+ }
107
+ // Skip if content unchanged
108
+ const hash = contentHash(content);
109
+ if (hashCache.get(filePath) === hash)
110
+ return;
111
+ hashCache.set(filePath, hash);
112
+ // Reset dedup for this file on new content
113
+ findingsDedup.set(filePath, new Set());
114
+ filesChecked++;
115
+ // Run rule engine scan
116
+ const findings = engine.scanFile(filePath, content);
117
+ // Run injection scan on instruction files
118
+ const injectionFindings = scanFileForInjection(filePath, content);
119
+ const allFindings = [...findings, ...injectionFindings];
120
+ // Dedup within session per-file
121
+ const seen = findingsDedup.get(filePath);
122
+ for (const f of allFindings) {
123
+ const key = `${f.ruleId}:${f.line}`;
124
+ if (seen.has(key))
125
+ continue;
126
+ seen.add(key);
127
+ totalFindings++;
128
+ printFinding(f, relPath);
129
+ }
130
+ }
131
+ // Banner
132
+ if (!options.json) {
133
+ console.log(`${chalk.bold(`Watching ${dir} for changes...`)} (Ctrl+C to stop)`);
134
+ console.log(` ${allRules.length} rules loaded\n`);
135
+ }
136
+ // Set up fs.watch
137
+ let watcher;
138
+ try {
139
+ watcher = watch(dir, { recursive: true }, (_event, filename) => {
140
+ if (!filename)
141
+ return;
142
+ const fullPath = resolve(dir, filename);
143
+ // Debounce per file
144
+ const existing = timers.get(fullPath);
145
+ if (existing)
146
+ clearTimeout(existing);
147
+ timers.set(fullPath, setTimeout(() => {
148
+ timers.delete(fullPath);
149
+ processFile(fullPath).catch(() => {
150
+ // Silently ignore processing errors
151
+ });
152
+ }, DEBOUNCE_MS));
153
+ });
154
+ }
155
+ catch (err) {
156
+ const code = err.code;
157
+ if (code === 'ERR_FEATURE_UNAVAILABLE_ON_PLATFORM') {
158
+ // Fallback: watch without recursive (Linux < Node 19)
159
+ if (!options.json) {
160
+ console.log(chalk.yellow('Warning: Recursive watch not supported on this platform.'));
161
+ console.log(chalk.yellow('Only top-level directory changes will be detected.\n'));
162
+ }
163
+ watcher = watch(dir, {}, (_event, filename) => {
164
+ if (!filename)
165
+ return;
166
+ const fullPath = resolve(dir, filename);
167
+ const existing = timers.get(fullPath);
168
+ if (existing)
169
+ clearTimeout(existing);
170
+ timers.set(fullPath, setTimeout(() => {
171
+ timers.delete(fullPath);
172
+ processFile(fullPath).catch(() => { });
173
+ }, DEBOUNCE_MS));
174
+ });
175
+ }
176
+ else {
177
+ throw err;
178
+ }
179
+ }
180
+ watcher.on('error', (err) => {
181
+ if (!options.json) {
182
+ console.error(chalk.red(`Watch error: ${err.message}`));
183
+ }
184
+ });
185
+ // Clean exit on SIGINT
186
+ function printSummary() {
187
+ if (options.json)
188
+ return;
189
+ const elapsed = formatDuration(Date.now() - startTime);
190
+ console.log(`\n${chalk.bold('Watch ended')} \u2014 ${filesChecked} files checked, ${totalFindings} finding${totalFindings !== 1 ? 's' : ''} in ${elapsed}`);
191
+ }
192
+ process.on('SIGINT', () => {
193
+ watcher.close();
194
+ for (const t of timers.values())
195
+ clearTimeout(t);
196
+ timers.clear();
197
+ printSummary();
198
+ process.exit(0);
199
+ });
200
+ // Keep process alive
201
+ await new Promise(() => { });
202
+ }
203
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { Config } from './rules/types.js';
2
+ export declare function loadConfig(projectDir?: string): Config;
3
+ /** Write JSON atomically: write to temp file then rename (POSIX atomic). */
4
+ export declare function atomicWriteJson(filePath: string, data: unknown): void;
5
+ /** Returns true if real-time protection is enabled (default: true). */
6
+ export declare function isProtectionEnabled(): boolean;
7
+ /** Set the global protection toggle. Preserves all other config fields. */
8
+ export declare function setProtectionEnabled(enabled: boolean): void;
9
+ /** Add a file path to the global allowlist. Deduplicates. Rejects whitespace-only. */
10
+ export declare function addAllowlistPath(filePath: string): void;
11
+ /** Add a rule ID to the global allowlist (disables that rule). Deduplicates. Rejects whitespace-only. */
12
+ export declare function disableRule(ruleId: string): void;
13
+ /** Returns true if the user has seen the welcome screen (default: false). */
14
+ export declare function hasSeenWelcome(): boolean;
15
+ /** Mark the welcome screen as completed. Preserves all other config fields. */
16
+ export declare function setWelcomeComplete(): void;
17
+ /** Validate a config file against the Zod schema. Returns array of error messages (empty = valid). */
18
+ export declare function validateConfig(filePath: string): string[];
19
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAoC,MAAM,kBAAkB,CAAC;AAwFjF,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CA8CtD;AAID,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAMrE;AAWD,uEAAuE;AACvE,wBAAgB,mBAAmB,IAAI,OAAO,CAY7C;AAED,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAI3D;AAED,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAavD;AAED,yGAAyG;AACzG,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAahD;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,IAAI,OAAO,CAYxC;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,IAAI,IAAI,CAIzC;AAED,sGAAsG;AACtG,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAazD"}
package/dist/config.js ADDED
@@ -0,0 +1,235 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, renameSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import { z } from 'zod';
5
+ const AllowlistSchema = z.object({
6
+ paths: z.array(z.string()).optional().default([]),
7
+ patterns: z.array(z.string()).optional().default([]),
8
+ rules: z.array(z.string()).optional().default([]),
9
+ }).optional().default(() => ({ paths: [], patterns: [], rules: [] }));
10
+ const BlocklistSchema = z.object({
11
+ paths: z.array(z.string()).optional().default([]),
12
+ patterns: z.array(z.string()).optional().default([]),
13
+ }).optional().default(() => ({ paths: [], patterns: [] }));
14
+ const ConfigSchema = z.object({
15
+ enabled: z.boolean().optional(),
16
+ allowlist: AllowlistSchema,
17
+ blocklist: BlocklistSchema,
18
+ skipDirs: z.array(z.string()).optional(),
19
+ }).passthrough();
20
+ const EMPTY_CONFIG = {
21
+ allowlist: { paths: [], patterns: [], rules: [] },
22
+ blocklist: { paths: [], patterns: [] },
23
+ };
24
+ function toStringArray(value) {
25
+ if (!Array.isArray(value))
26
+ return [];
27
+ return value.filter((v) => typeof v === 'string');
28
+ }
29
+ function parseAllowlist(raw) {
30
+ if (!raw || typeof raw !== 'object')
31
+ return {};
32
+ const obj = raw;
33
+ return {
34
+ paths: toStringArray(obj.paths),
35
+ patterns: toStringArray(obj.patterns),
36
+ rules: toStringArray(obj.rules),
37
+ };
38
+ }
39
+ function parseBlocklist(raw) {
40
+ if (!raw || typeof raw !== 'object')
41
+ return {};
42
+ const obj = raw;
43
+ return {
44
+ paths: toStringArray(obj.paths),
45
+ patterns: toStringArray(obj.patterns),
46
+ };
47
+ }
48
+ function readConfigFile(filePath) {
49
+ try {
50
+ const raw = readFileSync(filePath, 'utf-8');
51
+ const parsed = JSON.parse(raw);
52
+ if (!parsed || typeof parsed !== 'object')
53
+ return null;
54
+ const obj = parsed;
55
+ const result = {
56
+ allowlist: parseAllowlist(obj.allowlist),
57
+ blocklist: parseBlocklist(obj.blocklist),
58
+ };
59
+ if (typeof obj.enabled === 'boolean') {
60
+ result.enabled = obj.enabled;
61
+ }
62
+ const skipDirs = toStringArray(obj.skipDirs);
63
+ if (skipDirs.length > 0) {
64
+ result.skipDirs = skipDirs;
65
+ }
66
+ return result;
67
+ }
68
+ catch {
69
+ // Missing file or invalid JSON — caller merges with defaults
70
+ return null;
71
+ }
72
+ }
73
+ function mergeAllowlists(a, b) {
74
+ return {
75
+ paths: [...(a.paths ?? []), ...(b.paths ?? [])],
76
+ patterns: [...(a.patterns ?? []), ...(b.patterns ?? [])],
77
+ rules: [...(a.rules ?? []), ...(b.rules ?? [])],
78
+ };
79
+ }
80
+ function mergeBlocklists(a, b) {
81
+ return {
82
+ paths: [...(a.paths ?? []), ...(b.paths ?? [])],
83
+ patterns: [...(a.patterns ?? []), ...(b.patterns ?? [])],
84
+ };
85
+ }
86
+ export function loadConfig(projectDir) {
87
+ const globalPath = join(homedir(), '.llm-av', 'config.json');
88
+ const projectPath = projectDir
89
+ ? join(projectDir, '.llm-av', 'config.json')
90
+ : join(process.cwd(), '.llm-av', 'config.json');
91
+ const globalConfig = readConfigFile(globalPath);
92
+ const projectConfig = readConfigFile(projectPath);
93
+ if (!globalConfig && !projectConfig) {
94
+ return EMPTY_CONFIG;
95
+ }
96
+ // Validate config files and log warnings (non-breaking)
97
+ for (const path of [globalPath, projectPath]) {
98
+ const errors = validateConfig(path);
99
+ if (errors.length > 0) {
100
+ for (const err of errors) {
101
+ process.stderr.write(`chainwall: config warning (${path}): ${err}\n`);
102
+ }
103
+ }
104
+ }
105
+ const baseAllowlist = globalConfig?.allowlist ?? {};
106
+ const projAllowlist = projectConfig?.allowlist ?? {};
107
+ const baseBlocklist = globalConfig?.blocklist ?? {};
108
+ const projBlocklist = projectConfig?.blocklist ?? {};
109
+ const config = {
110
+ allowlist: mergeAllowlists(baseAllowlist, projAllowlist),
111
+ blocklist: mergeBlocklists(baseBlocklist, projBlocklist),
112
+ };
113
+ // enabled is global-only (per-project would let malicious repos disable protection)
114
+ if (typeof globalConfig?.enabled === 'boolean') {
115
+ config.enabled = globalConfig.enabled;
116
+ }
117
+ // skipDirs: merge global + project (both trusted, similar to allowlist)
118
+ const globalSkip = globalConfig?.skipDirs ?? [];
119
+ const projectSkip = projectConfig?.skipDirs ?? [];
120
+ if (globalSkip.length > 0 || projectSkip.length > 0) {
121
+ config.skipDirs = [...globalSkip, ...projectSkip];
122
+ }
123
+ return config;
124
+ }
125
+ const globalConfigPath = join(homedir(), '.llm-av', 'config.json');
126
+ /** Write JSON atomically: write to temp file then rename (POSIX atomic). */
127
+ export function atomicWriteJson(filePath, data) {
128
+ const dir = dirname(filePath);
129
+ if (!existsSync(dir))
130
+ mkdirSync(dir, { recursive: true });
131
+ const tmpPath = filePath + '.tmp.' + process.pid;
132
+ writeFileSync(tmpPath, JSON.stringify(data, null, 2) + '\n');
133
+ renameSync(tmpPath, filePath);
134
+ }
135
+ /** Read and parse global config JSON. Returns empty object on error. */
136
+ function readGlobalConfigJson() {
137
+ try {
138
+ return JSON.parse(readFileSync(globalConfigPath, 'utf-8'));
139
+ }
140
+ catch {
141
+ return {};
142
+ }
143
+ }
144
+ /** Returns true if real-time protection is enabled (default: true). */
145
+ export function isProtectionEnabled() {
146
+ try {
147
+ const raw = readFileSync(globalConfigPath, 'utf-8');
148
+ const parsed = JSON.parse(raw);
149
+ if (parsed && typeof parsed === 'object') {
150
+ const obj = parsed;
151
+ if (typeof obj.enabled === 'boolean')
152
+ return obj.enabled;
153
+ }
154
+ }
155
+ catch {
156
+ // no config file = default enabled
157
+ }
158
+ return true;
159
+ }
160
+ /** Set the global protection toggle. Preserves all other config fields. */
161
+ export function setProtectionEnabled(enabled) {
162
+ const existing = readGlobalConfigJson();
163
+ existing.enabled = enabled;
164
+ atomicWriteJson(globalConfigPath, existing);
165
+ }
166
+ /** Add a file path to the global allowlist. Deduplicates. Rejects whitespace-only. */
167
+ export function addAllowlistPath(filePath) {
168
+ const trimmed = filePath.trim();
169
+ if (!trimmed)
170
+ throw new Error('Path cannot be empty');
171
+ const existing = readGlobalConfigJson();
172
+ const allowlist = (existing.allowlist ?? {});
173
+ const paths = Array.isArray(allowlist.paths) ? allowlist.paths : [];
174
+ if (!paths.includes(trimmed)) {
175
+ paths.push(trimmed);
176
+ }
177
+ allowlist.paths = paths;
178
+ existing.allowlist = allowlist;
179
+ atomicWriteJson(globalConfigPath, existing);
180
+ }
181
+ /** Add a rule ID to the global allowlist (disables that rule). Deduplicates. Rejects whitespace-only. */
182
+ export function disableRule(ruleId) {
183
+ const trimmed = ruleId.trim();
184
+ if (!trimmed)
185
+ throw new Error('Rule ID cannot be empty');
186
+ const existing = readGlobalConfigJson();
187
+ const allowlist = (existing.allowlist ?? {});
188
+ const rules = Array.isArray(allowlist.rules) ? allowlist.rules : [];
189
+ if (!rules.includes(trimmed)) {
190
+ rules.push(trimmed);
191
+ }
192
+ allowlist.rules = rules;
193
+ existing.allowlist = allowlist;
194
+ atomicWriteJson(globalConfigPath, existing);
195
+ }
196
+ /** Returns true if the user has seen the welcome screen (default: false). */
197
+ export function hasSeenWelcome() {
198
+ try {
199
+ const raw = readFileSync(globalConfigPath, 'utf-8');
200
+ const parsed = JSON.parse(raw);
201
+ if (parsed && typeof parsed === 'object') {
202
+ const obj = parsed;
203
+ if (typeof obj.hasSeenWelcome === 'boolean')
204
+ return obj.hasSeenWelcome;
205
+ }
206
+ }
207
+ catch {
208
+ // no config file = never seen
209
+ }
210
+ return false;
211
+ }
212
+ /** Mark the welcome screen as completed. Preserves all other config fields. */
213
+ export function setWelcomeComplete() {
214
+ const existing = readGlobalConfigJson();
215
+ existing.hasSeenWelcome = true;
216
+ atomicWriteJson(globalConfigPath, existing);
217
+ }
218
+ /** Validate a config file against the Zod schema. Returns array of error messages (empty = valid). */
219
+ export function validateConfig(filePath) {
220
+ try {
221
+ const raw = readFileSync(filePath, 'utf-8');
222
+ const parsed = JSON.parse(raw);
223
+ const result = ConfigSchema.safeParse(parsed);
224
+ if (!result.success) {
225
+ return result.error.issues.map(i => `${i.path.join('.')}: ${i.message}`);
226
+ }
227
+ return [];
228
+ }
229
+ catch (err) {
230
+ if (err instanceof SyntaxError)
231
+ return [`Invalid JSON: ${err.message}`];
232
+ return [];
233
+ }
234
+ }
235
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export declare function startMCPServer(): Promise<void>;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp-server/index.ts"],"names":[],"mappings":";AA4CA,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAsBpD"}
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ import { statSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
6
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
7
+ import { createRuleEngine } from '../scanner/rule-engine.js';
8
+ import { allRules } from '../rules/index.js';
9
+ import { loadConfig } from '../config.js';
10
+ import { scanFileTool } from './tools/scan-file.js';
11
+ import { scanContentTool } from './tools/scan-content.js';
12
+ import { checkCommandTool } from './tools/check-command.js';
13
+ import { auditStatusTool } from './tools/audit-status.js';
14
+ import { createRequire } from 'node:module';
15
+ const require = createRequire(import.meta.url);
16
+ const pkg = require('../../package.json');
17
+ /** Config-aware engine that reloads when config file changes. */
18
+ function createRefreshableEngine() {
19
+ const configPath = join(homedir(), '.llm-av', 'config.json');
20
+ let lastMtime = 0;
21
+ let engine = createRuleEngine({ rules: allRules, config: loadConfig(process.cwd()) });
22
+ function getEngine() {
23
+ try {
24
+ const mtime = statSync(configPath).mtimeMs;
25
+ if (mtime !== lastMtime) {
26
+ lastMtime = mtime;
27
+ engine = createRuleEngine({ rules: allRules, config: loadConfig(process.cwd()) });
28
+ }
29
+ }
30
+ catch {
31
+ // Config file doesn't exist or can't be read — keep current engine
32
+ }
33
+ return engine;
34
+ }
35
+ // Initialize mtime
36
+ try {
37
+ lastMtime = statSync(configPath).mtimeMs;
38
+ }
39
+ catch { /* no config */ }
40
+ return { getEngine };
41
+ }
42
+ export async function startMCPServer() {
43
+ const { getEngine } = createRefreshableEngine();
44
+ // Wrap engine so each call checks for config refresh
45
+ const engineProxy = {
46
+ scanFile(path, content) {
47
+ return getEngine().scanFile(path, content);
48
+ },
49
+ };
50
+ const server = new McpServer({
51
+ name: 'chainwall',
52
+ version: pkg.version,
53
+ });
54
+ scanFileTool(server, engineProxy);
55
+ scanContentTool(server, engineProxy);
56
+ checkCommandTool(server, engineProxy);
57
+ auditStatusTool(server);
58
+ const transport = new StdioServerTransport();
59
+ await server.connect(transport);
60
+ }
61
+ // Allow direct execution as MCP server binary
62
+ const isDirectExecution = process.argv[1]?.endsWith('mcp-server/index.js');
63
+ if (isDirectExecution) {
64
+ startMCPServer().catch((err) => {
65
+ console.error(`Fatal: ${err.message}`);
66
+ process.exitCode = 1;
67
+ });
68
+ }
69
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp-server/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { z } from 'zod';
2
+ export declare const ScanFileSchema: {
3
+ path: z.ZodString;
4
+ };
5
+ export declare const ScanContentSchema: {
6
+ content: z.ZodString;
7
+ filename: z.ZodOptional<z.ZodString>;
8
+ };
9
+ export declare const CheckCommandSchema: {
10
+ command: z.ZodString;
11
+ };
12
+ export declare const AuditStatusSchema: {};
13
+ //# sourceMappingURL=schemas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/mcp-server/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,cAAc;;CAE1B,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;CAG7B,CAAC;AAEF,eAAO,MAAM,kBAAkB;;CAE9B,CAAC;AAEF,eAAO,MAAM,iBAAiB,IAAK,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { z } from 'zod';
2
+ export const ScanFileSchema = {
3
+ path: z.string().min(1).describe('Absolute path to the file to scan'),
4
+ };
5
+ export const ScanContentSchema = {
6
+ content: z.string().max(10_000_000).describe('Text content to scan for security findings'),
7
+ filename: z.string().optional().describe('Optional filename for context (enables filename rules)'),
8
+ };
9
+ export const CheckCommandSchema = {
10
+ command: z.string().describe('Shell command to check for safety'),
11
+ };
12
+ export const AuditStatusSchema = {};
13
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/mcp-server/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,mCAAmC,CAAC;CACtE,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,4CAA4C,CAAC;IAC1F,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;CACnG,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mCAAmC,CAAC;CAClE,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function auditStatusTool(server: McpServer): void;
3
+ //# sourceMappingURL=audit-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-status.d.ts","sourceRoot":"","sources":["../../../src/mcp-server/tools/audit-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgDvD"}