@oculum/scanner 1.0.11 → 1.0.12

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 (309) hide show
  1. package/dist/ai-context/index.d.ts +6 -0
  2. package/dist/ai-context/index.d.ts.map +1 -0
  3. package/dist/ai-context/index.js +13 -0
  4. package/dist/ai-context/index.js.map +1 -0
  5. package/dist/ai-context/manager.d.ts +67 -0
  6. package/dist/ai-context/manager.d.ts.map +1 -0
  7. package/dist/ai-context/manager.js +104 -0
  8. package/dist/ai-context/manager.js.map +1 -0
  9. package/dist/category-filter.d.ts +125 -0
  10. package/dist/category-filter.d.ts.map +1 -0
  11. package/dist/category-filter.js +360 -0
  12. package/dist/category-filter.js.map +1 -0
  13. package/dist/filtering/context-adjustments.d.ts +23 -0
  14. package/dist/filtering/context-adjustments.d.ts.map +1 -0
  15. package/dist/filtering/context-adjustments.js +100 -0
  16. package/dist/filtering/context-adjustments.js.map +1 -0
  17. package/dist/filtering/index.d.ts +3 -0
  18. package/dist/filtering/index.d.ts.map +1 -0
  19. package/dist/filtering/index.js +8 -0
  20. package/dist/filtering/index.js.map +1 -0
  21. package/dist/filtering/pipeline.d.ts +48 -0
  22. package/dist/filtering/pipeline.d.ts.map +1 -0
  23. package/dist/filtering/pipeline.js +76 -0
  24. package/dist/filtering/pipeline.js.map +1 -0
  25. package/dist/formatters/ai-context.d.ts +23 -0
  26. package/dist/formatters/ai-context.d.ts.map +1 -0
  27. package/dist/formatters/ai-context.js +238 -0
  28. package/dist/formatters/ai-context.js.map +1 -0
  29. package/dist/formatters/github-comment.d.ts +1 -1
  30. package/dist/formatters/github-comment.d.ts.map +1 -1
  31. package/dist/formatters/github-comment.js +2 -2
  32. package/dist/formatters/github-comment.js.map +1 -1
  33. package/dist/formatters/ide/claude-code.d.ts +17 -0
  34. package/dist/formatters/ide/claude-code.d.ts.map +1 -0
  35. package/dist/formatters/ide/claude-code.js +94 -0
  36. package/dist/formatters/ide/claude-code.js.map +1 -0
  37. package/dist/formatters/ide/cursor.d.ts +13 -0
  38. package/dist/formatters/ide/cursor.d.ts.map +1 -0
  39. package/dist/formatters/ide/cursor.js +125 -0
  40. package/dist/formatters/ide/cursor.js.map +1 -0
  41. package/dist/formatters/ide/index.d.ts +62 -0
  42. package/dist/formatters/ide/index.d.ts.map +1 -0
  43. package/dist/formatters/ide/index.js +184 -0
  44. package/dist/formatters/ide/index.js.map +1 -0
  45. package/dist/formatters/ide/windsurf.d.ts +13 -0
  46. package/dist/formatters/ide/windsurf.d.ts.map +1 -0
  47. package/dist/formatters/ide/windsurf.js +117 -0
  48. package/dist/formatters/ide/windsurf.js.map +1 -0
  49. package/dist/formatters/index.d.ts +2 -0
  50. package/dist/formatters/index.d.ts.map +1 -1
  51. package/dist/formatters/index.js +17 -1
  52. package/dist/formatters/index.js.map +1 -1
  53. package/dist/index.d.ts +4 -0
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +272 -44
  56. package/dist/index.js.map +1 -1
  57. package/dist/layer1/comments.d.ts +4 -1
  58. package/dist/layer1/comments.d.ts.map +1 -1
  59. package/dist/layer1/comments.js +1 -1
  60. package/dist/layer1/comments.js.map +1 -1
  61. package/dist/layer1/config-audit.d.ts +4 -1
  62. package/dist/layer1/config-audit.d.ts.map +1 -1
  63. package/dist/layer1/config-audit.js +45 -11
  64. package/dist/layer1/config-audit.js.map +1 -1
  65. package/dist/layer1/config-mcp-audit.d.ts +4 -1
  66. package/dist/layer1/config-mcp-audit.d.ts.map +1 -1
  67. package/dist/layer1/config-mcp-audit.js +2 -2
  68. package/dist/layer1/config-mcp-audit.js.map +1 -1
  69. package/dist/layer1/entropy.d.ts +4 -1
  70. package/dist/layer1/entropy.d.ts.map +1 -1
  71. package/dist/layer1/entropy.js +212 -1
  72. package/dist/layer1/entropy.js.map +1 -1
  73. package/dist/layer1/file-flags.d.ts +4 -1
  74. package/dist/layer1/file-flags.d.ts.map +1 -1
  75. package/dist/layer1/file-flags.js +12 -5
  76. package/dist/layer1/file-flags.js.map +1 -1
  77. package/dist/layer1/index.d.ts.map +1 -1
  78. package/dist/layer1/index.js +14 -19
  79. package/dist/layer1/index.js.map +1 -1
  80. package/dist/layer1/patterns.d.ts +4 -1
  81. package/dist/layer1/patterns.d.ts.map +1 -1
  82. package/dist/layer1/patterns.js +34 -4
  83. package/dist/layer1/patterns.js.map +1 -1
  84. package/dist/layer1/urls.d.ts +4 -1
  85. package/dist/layer1/urls.d.ts.map +1 -1
  86. package/dist/layer1/urls.js +162 -14
  87. package/dist/layer1/urls.js.map +1 -1
  88. package/dist/layer1/weak-crypto.d.ts +4 -1
  89. package/dist/layer1/weak-crypto.d.ts.map +1 -1
  90. package/dist/layer1/weak-crypto.js +144 -7
  91. package/dist/layer1/weak-crypto.js.map +1 -1
  92. package/dist/layer2/ai-agent-tools.d.ts +4 -1
  93. package/dist/layer2/ai-agent-tools.d.ts.map +1 -1
  94. package/dist/layer2/ai-agent-tools.js +661 -2
  95. package/dist/layer2/ai-agent-tools.js.map +1 -1
  96. package/dist/layer2/ai-endpoint-protection.d.ts +2 -0
  97. package/dist/layer2/ai-endpoint-protection.d.ts.map +1 -1
  98. package/dist/layer2/ai-endpoint-protection.js +1 -1
  99. package/dist/layer2/ai-endpoint-protection.js.map +1 -1
  100. package/dist/layer2/ai-execution-sinks.d.ts +4 -1
  101. package/dist/layer2/ai-execution-sinks.d.ts.map +1 -1
  102. package/dist/layer2/ai-execution-sinks.js +252 -43
  103. package/dist/layer2/ai-execution-sinks.js.map +1 -1
  104. package/dist/layer2/ai-fingerprinting.d.ts +4 -1
  105. package/dist/layer2/ai-fingerprinting.d.ts.map +1 -1
  106. package/dist/layer2/ai-fingerprinting.js +25 -32
  107. package/dist/layer2/ai-fingerprinting.js.map +1 -1
  108. package/dist/layer2/ai-mcp-security.d.ts +4 -1
  109. package/dist/layer2/ai-mcp-security.d.ts.map +1 -1
  110. package/dist/layer2/ai-mcp-security.js +200 -2
  111. package/dist/layer2/ai-mcp-security.js.map +1 -1
  112. package/dist/layer2/ai-package-hallucination.d.ts +4 -1
  113. package/dist/layer2/ai-package-hallucination.d.ts.map +1 -1
  114. package/dist/layer2/ai-package-hallucination.js +136 -4
  115. package/dist/layer2/ai-package-hallucination.js.map +1 -1
  116. package/dist/layer2/ai-prompt-hygiene.d.ts +4 -1
  117. package/dist/layer2/ai-prompt-hygiene.d.ts.map +1 -1
  118. package/dist/layer2/ai-prompt-hygiene.js +342 -28
  119. package/dist/layer2/ai-prompt-hygiene.js.map +1 -1
  120. package/dist/layer2/ai-rag-safety.d.ts +4 -1
  121. package/dist/layer2/ai-rag-safety.d.ts.map +1 -1
  122. package/dist/layer2/ai-rag-safety.js +82 -2
  123. package/dist/layer2/ai-rag-safety.js.map +1 -1
  124. package/dist/layer2/ai-schema-validation.d.ts +4 -1
  125. package/dist/layer2/ai-schema-validation.d.ts.map +1 -1
  126. package/dist/layer2/ai-schema-validation.js +2 -2
  127. package/dist/layer2/ai-schema-validation.js.map +1 -1
  128. package/dist/layer2/auth-antipatterns.d.ts +2 -0
  129. package/dist/layer2/auth-antipatterns.d.ts.map +1 -1
  130. package/dist/layer2/auth-antipatterns.js +205 -20
  131. package/dist/layer2/auth-antipatterns.js.map +1 -1
  132. package/dist/layer2/byok-patterns.d.ts +4 -1
  133. package/dist/layer2/byok-patterns.d.ts.map +1 -1
  134. package/dist/layer2/byok-patterns.js +2 -2
  135. package/dist/layer2/byok-patterns.js.map +1 -1
  136. package/dist/layer2/dangerous-functions/dom-xss.d.ts +9 -4
  137. package/dist/layer2/dangerous-functions/dom-xss.d.ts.map +1 -1
  138. package/dist/layer2/dangerous-functions/dom-xss.js +73 -22
  139. package/dist/layer2/dangerous-functions/dom-xss.js.map +1 -1
  140. package/dist/layer2/dangerous-functions/index.d.ts +4 -1
  141. package/dist/layer2/dangerous-functions/index.d.ts.map +1 -1
  142. package/dist/layer2/dangerous-functions/index.js +551 -20
  143. package/dist/layer2/dangerous-functions/index.js.map +1 -1
  144. package/dist/layer2/dangerous-functions/math-random.d.ts +54 -4
  145. package/dist/layer2/dangerous-functions/math-random.d.ts.map +1 -1
  146. package/dist/layer2/dangerous-functions/math-random.js +241 -16
  147. package/dist/layer2/dangerous-functions/math-random.js.map +1 -1
  148. package/dist/layer2/dangerous-functions/patterns.d.ts.map +1 -1
  149. package/dist/layer2/dangerous-functions/patterns.js +3 -1
  150. package/dist/layer2/dangerous-functions/patterns.js.map +1 -1
  151. package/dist/layer2/dangerous-functions/utils/control-flow.d.ts +3 -2
  152. package/dist/layer2/dangerous-functions/utils/control-flow.d.ts.map +1 -1
  153. package/dist/layer2/dangerous-functions/utils/control-flow.js +41 -120
  154. package/dist/layer2/dangerous-functions/utils/control-flow.js.map +1 -1
  155. package/dist/layer2/dangerous-functions/utils/helpers.d.ts.map +1 -1
  156. package/dist/layer2/dangerous-functions/utils/helpers.js +26 -3
  157. package/dist/layer2/dangerous-functions/utils/helpers.js.map +1 -1
  158. package/dist/layer2/dangerous-functions/utils/schema-validation.d.ts.map +1 -1
  159. package/dist/layer2/dangerous-functions/utils/schema-validation.js +14 -1
  160. package/dist/layer2/dangerous-functions/utils/schema-validation.js.map +1 -1
  161. package/dist/layer2/data-exposure.d.ts +4 -1
  162. package/dist/layer2/data-exposure.d.ts.map +1 -1
  163. package/dist/layer2/data-exposure.js +11 -38
  164. package/dist/layer2/data-exposure.js.map +1 -1
  165. package/dist/layer2/framework-checks.d.ts +4 -1
  166. package/dist/layer2/framework-checks.d.ts.map +1 -1
  167. package/dist/layer2/framework-checks.js +2 -2
  168. package/dist/layer2/framework-checks.js.map +1 -1
  169. package/dist/layer2/index.d.ts +9 -1
  170. package/dist/layer2/index.d.ts.map +1 -1
  171. package/dist/layer2/index.js +57 -51
  172. package/dist/layer2/index.js.map +1 -1
  173. package/dist/layer2/logic-gates.d.ts +4 -1
  174. package/dist/layer2/logic-gates.d.ts.map +1 -1
  175. package/dist/layer2/logic-gates.js +54 -20
  176. package/dist/layer2/logic-gates.js.map +1 -1
  177. package/dist/layer2/model-supply-chain.d.ts +4 -1
  178. package/dist/layer2/model-supply-chain.d.ts.map +1 -1
  179. package/dist/layer2/model-supply-chain.js +72 -4
  180. package/dist/layer2/model-supply-chain.js.map +1 -1
  181. package/dist/layer2/risky-imports.d.ts +4 -1
  182. package/dist/layer2/risky-imports.d.ts.map +1 -1
  183. package/dist/layer2/risky-imports.js +2 -2
  184. package/dist/layer2/risky-imports.js.map +1 -1
  185. package/dist/layer2/variables.d.ts +4 -1
  186. package/dist/layer2/variables.d.ts.map +1 -1
  187. package/dist/layer2/variables.js +2 -2
  188. package/dist/layer2/variables.js.map +1 -1
  189. package/dist/layer3/anthropic/auto-dismiss.d.ts.map +1 -1
  190. package/dist/layer3/anthropic/auto-dismiss.js +11 -0
  191. package/dist/layer3/anthropic/auto-dismiss.js.map +1 -1
  192. package/dist/modes/incremental.js +1 -1
  193. package/dist/tiers.d.ts +2 -2
  194. package/dist/tiers.d.ts.map +1 -1
  195. package/dist/tiers.js +7 -7
  196. package/dist/tiers.js.map +1 -1
  197. package/dist/types.d.ts +78 -8
  198. package/dist/types.d.ts.map +1 -1
  199. package/dist/types.js +34 -0
  200. package/dist/types.js.map +1 -1
  201. package/dist/utils/code-analysis.d.ts +39 -0
  202. package/dist/utils/code-analysis.d.ts.map +1 -0
  203. package/dist/utils/code-analysis.js +159 -0
  204. package/dist/utils/code-analysis.js.map +1 -0
  205. package/dist/utils/comment-analyzer.d.ts +38 -0
  206. package/dist/utils/comment-analyzer.d.ts.map +1 -0
  207. package/dist/utils/comment-analyzer.js +218 -0
  208. package/dist/utils/comment-analyzer.js.map +1 -0
  209. package/dist/utils/context-helpers.d.ts +108 -1
  210. package/dist/utils/context-helpers.d.ts.map +1 -1
  211. package/dist/utils/context-helpers.js +351 -2
  212. package/dist/utils/context-helpers.js.map +1 -1
  213. package/dist/utils/environment-context.d.ts +76 -0
  214. package/dist/utils/environment-context.d.ts.map +1 -0
  215. package/dist/utils/environment-context.js +271 -0
  216. package/dist/utils/environment-context.js.map +1 -0
  217. package/dist/utils/intent-detector.d.ts +66 -0
  218. package/dist/utils/intent-detector.d.ts.map +1 -0
  219. package/dist/utils/intent-detector.js +282 -0
  220. package/dist/utils/intent-detector.js.map +1 -0
  221. package/dist/utils/parsed-file.d.ts +51 -0
  222. package/dist/utils/parsed-file.d.ts.map +1 -0
  223. package/dist/utils/parsed-file.js +95 -0
  224. package/dist/utils/parsed-file.js.map +1 -0
  225. package/dist/utils/route-hierarchy.d.ts +50 -0
  226. package/dist/utils/route-hierarchy.d.ts.map +1 -0
  227. package/dist/utils/route-hierarchy.js +226 -0
  228. package/dist/utils/route-hierarchy.js.map +1 -0
  229. package/dist/utils/schema-semantics.d.ts +45 -0
  230. package/dist/utils/schema-semantics.d.ts.map +1 -0
  231. package/dist/utils/schema-semantics.js +193 -0
  232. package/dist/utils/schema-semantics.js.map +1 -0
  233. package/package.json +1 -1
  234. package/src/__tests__/benchmark/fixtures/layer2/index.ts +12 -0
  235. package/src/__tests__/benchmark/fixtures/layer2/phase5-excessive-agency.ts +580 -0
  236. package/src/__tests__/benchmark/fixtures/layer2/sprint6-ai-enhancements.ts +515 -0
  237. package/src/__tests__/benchmark/run-depth-validation.ts +9 -9
  238. package/src/__tests__/category-filter.test.ts +478 -0
  239. package/src/__tests__/regression/known-false-positives.test.ts +490 -0
  240. package/src/__tests__/snapshots/__snapshots__/anthropic-validation-refactor.test.ts.snap +18 -14
  241. package/src/__tests__/snapshots/__snapshots__/scan-depth.test.ts.snap +0 -9
  242. package/src/__tests__/snapshots/anthropic-validation-refactor.test.ts +1 -1
  243. package/src/__tests__/validation/run-validation.ts +7 -7
  244. package/src/ai-context/__tests__/manager.test.ts +193 -0
  245. package/src/ai-context/index.ts +15 -0
  246. package/src/ai-context/manager.ts +145 -0
  247. package/src/baseline/__tests__/manager.test.ts +2 -2
  248. package/src/category-filter.ts +400 -0
  249. package/src/filtering/__tests__/pipeline.test.ts +134 -0
  250. package/src/filtering/context-adjustments.ts +111 -0
  251. package/src/filtering/index.ts +10 -0
  252. package/src/filtering/pipeline.ts +130 -0
  253. package/src/formatters/__tests__/ai-context.test.ts +254 -0
  254. package/src/formatters/ai-context.ts +302 -0
  255. package/src/formatters/github-comment.ts +3 -3
  256. package/src/formatters/ide/__tests__/ide.test.ts +319 -0
  257. package/src/formatters/ide/claude-code.ts +110 -0
  258. package/src/formatters/ide/cursor.ts +147 -0
  259. package/src/formatters/ide/index.ts +216 -0
  260. package/src/formatters/ide/windsurf.ts +135 -0
  261. package/src/formatters/index.ts +24 -0
  262. package/src/index.ts +312 -34
  263. package/src/layer1/comments.ts +3 -1
  264. package/src/layer1/config-audit.ts +50 -11
  265. package/src/layer1/config-mcp-audit.ts +4 -2
  266. package/src/layer1/entropy.ts +234 -1
  267. package/src/layer1/file-flags.ts +17 -6
  268. package/src/layer1/index.ts +14 -18
  269. package/src/layer1/patterns.ts +42 -4
  270. package/src/layer1/urls.ts +188 -14
  271. package/src/layer1/weak-crypto.ts +168 -16
  272. package/src/layer2/ai-agent-tools.ts +707 -2
  273. package/src/layer2/ai-endpoint-protection.ts +3 -1
  274. package/src/layer2/ai-execution-sinks.ts +265 -43
  275. package/src/layer2/ai-fingerprinting.ts +28 -32
  276. package/src/layer2/ai-mcp-security.ts +206 -3
  277. package/src/layer2/ai-package-hallucination.ts +153 -4
  278. package/src/layer2/ai-prompt-hygiene.ts +369 -26
  279. package/src/layer2/ai-rag-safety.ts +85 -2
  280. package/src/layer2/ai-schema-validation.ts +4 -2
  281. package/src/layer2/auth-antipatterns.ts +230 -20
  282. package/src/layer2/byok-patterns.ts +4 -2
  283. package/src/layer2/dangerous-functions/dom-xss.ts +94 -22
  284. package/src/layer2/dangerous-functions/index.ts +635 -51
  285. package/src/layer2/dangerous-functions/math-random.ts +268 -16
  286. package/src/layer2/dangerous-functions/patterns.ts +3 -1
  287. package/src/layer2/dangerous-functions/utils/control-flow.ts +8 -135
  288. package/src/layer2/dangerous-functions/utils/schema-validation.ts +16 -1
  289. package/src/layer2/data-exposure.ts +13 -38
  290. package/src/layer2/framework-checks.ts +4 -2
  291. package/src/layer2/index.ts +69 -50
  292. package/src/layer2/logic-gates.ts +59 -22
  293. package/src/layer2/model-supply-chain.ts +79 -4
  294. package/src/layer2/risky-imports.ts +4 -2
  295. package/src/layer2/variables.ts +4 -2
  296. package/src/layer3/anthropic/auto-dismiss.ts +11 -0
  297. package/src/modes/incremental.ts +1 -1
  298. package/src/tiers.ts +9 -9
  299. package/src/types.ts +122 -8
  300. package/src/utils/__tests__/code-analysis.test.ts +165 -0
  301. package/src/utils/__tests__/parsed-file.test.ts +124 -0
  302. package/src/utils/code-analysis.ts +179 -0
  303. package/src/utils/comment-analyzer.ts +249 -0
  304. package/src/utils/context-helpers.ts +408 -2
  305. package/src/utils/environment-context.ts +304 -0
  306. package/src/utils/intent-detector.ts +318 -0
  307. package/src/utils/parsed-file.ts +103 -0
  308. package/src/utils/route-hierarchy.ts +250 -0
  309. package/src/utils/schema-semantics.ts +233 -0
@@ -0,0 +1,216 @@
1
+ /**
2
+ * IDE Integration Module
3
+ * Exports formatters and utilities for IDE-specific config files
4
+ */
5
+
6
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync } from 'fs'
7
+ import { join, dirname } from 'path'
8
+
9
+ // Export formatters
10
+ export { formatCursorRules } from './cursor'
11
+ export { formatWindsurfRules } from './windsurf'
12
+ export { formatClaudeCodeSection, OCULUM_SECTION_START, OCULUM_SECTION_END } from './claude-code'
13
+
14
+ /** Supported IDE types */
15
+ export type IDEType = 'cursor' | 'windsurf' | 'claude-code'
16
+
17
+ /** Default file paths for each IDE */
18
+ export const IDE_FILE_PATHS: Record<IDEType, string> = {
19
+ cursor: '.cursor/rules/security.mdc',
20
+ windsurf: '.windsurfrules',
21
+ 'claude-code': 'CLAUDE.md',
22
+ }
23
+
24
+ /** Result of a file write operation */
25
+ export interface WriteIDEFileResult {
26
+ success: boolean
27
+ path: string
28
+ error?: string
29
+ }
30
+
31
+ /** Result of a file clear operation */
32
+ export interface ClearIDEFilesResult {
33
+ success: boolean
34
+ clearedFiles: string[]
35
+ errors: string[]
36
+ }
37
+
38
+ /**
39
+ * Detect which IDE configurations exist in the project
40
+ *
41
+ * @param projectPath - Path to the project root
42
+ * @returns Array of detected IDE types
43
+ */
44
+ export function detectIDEConfigs(projectPath: string): IDEType[] {
45
+ const detected: IDEType[] = []
46
+
47
+ // Check for Cursor
48
+ if (existsSync(join(projectPath, '.cursor'))) {
49
+ detected.push('cursor')
50
+ }
51
+
52
+ // Check for Windsurf rules
53
+ if (existsSync(join(projectPath, '.windsurfrules'))) {
54
+ detected.push('windsurf')
55
+ }
56
+
57
+ // Check for Claude Code
58
+ if (existsSync(join(projectPath, 'CLAUDE.md'))) {
59
+ detected.push('claude-code')
60
+ }
61
+
62
+ return detected
63
+ }
64
+
65
+ /**
66
+ * Write an IDE-specific file
67
+ *
68
+ * @param projectPath - Path to the project root
69
+ * @param relativePath - Relative path for the file
70
+ * @param content - Content to write
71
+ * @returns Result object
72
+ */
73
+ export function writeIDEFile(
74
+ projectPath: string,
75
+ relativePath: string,
76
+ content: string
77
+ ): WriteIDEFileResult {
78
+ const fullPath = join(projectPath, relativePath)
79
+
80
+ try {
81
+ // Ensure directory exists
82
+ const dir = dirname(fullPath)
83
+ if (!existsSync(dir)) {
84
+ mkdirSync(dir, { recursive: true })
85
+ }
86
+
87
+ // Write file
88
+ writeFileSync(fullPath, content)
89
+
90
+ return { success: true, path: fullPath }
91
+ } catch (err) {
92
+ return {
93
+ success: false,
94
+ path: fullPath,
95
+ error: `Failed to write ${relativePath}: ${err instanceof Error ? err.message : 'Unknown error'}`,
96
+ }
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Update the Oculum section in CLAUDE.md
102
+ * Replaces content between OCULUM_SECURITY_START and OCULUM_SECURITY_END markers
103
+ * If markers don't exist, appends the section at the end
104
+ *
105
+ * @param projectPath - Path to the project root
106
+ * @param section - The section content (including markers)
107
+ * @returns Result object
108
+ */
109
+ export function updateClaudeMdSection(
110
+ projectPath: string,
111
+ section: string
112
+ ): WriteIDEFileResult {
113
+ const filePath = join(projectPath, 'CLAUDE.md')
114
+
115
+ try {
116
+ let content: string
117
+
118
+ if (existsSync(filePath)) {
119
+ content = readFileSync(filePath, 'utf-8')
120
+
121
+ // Check if markers exist
122
+ const startMarker = '<!-- OCULUM_SECURITY_START -->'
123
+ const endMarker = '<!-- OCULUM_SECURITY_END -->'
124
+ const startIndex = content.indexOf(startMarker)
125
+ const endIndex = content.indexOf(endMarker)
126
+
127
+ if (startIndex !== -1 && endIndex !== -1 && endIndex > startIndex) {
128
+ // Replace existing section
129
+ content =
130
+ content.substring(0, startIndex) +
131
+ section +
132
+ content.substring(endIndex + endMarker.length)
133
+ } else {
134
+ // Append section at end
135
+ content = content.trimEnd() + '\n\n' + section
136
+ }
137
+ } else {
138
+ // Create new file with section
139
+ content = `# CLAUDE.md\n\n${section}`
140
+ }
141
+
142
+ writeFileSync(filePath, content)
143
+
144
+ return { success: true, path: filePath }
145
+ } catch (err) {
146
+ return {
147
+ success: false,
148
+ path: filePath,
149
+ error: `Failed to update CLAUDE.md: ${err instanceof Error ? err.message : 'Unknown error'}`,
150
+ }
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Clear IDE rule files
156
+ *
157
+ * @param projectPath - Path to the project root
158
+ * @param types - Optional array of IDE types to clear. If not provided, clears all.
159
+ * @returns Result object with list of cleared files
160
+ */
161
+ export function clearIDEFiles(
162
+ projectPath: string,
163
+ types?: IDEType[]
164
+ ): ClearIDEFilesResult {
165
+ const toCheck = types || (['cursor', 'windsurf', 'claude-code'] as IDEType[])
166
+ const clearedFiles: string[] = []
167
+ const errors: string[] = []
168
+
169
+ for (const ide of toCheck) {
170
+ const relativePath = IDE_FILE_PATHS[ide]
171
+ const fullPath = join(projectPath, relativePath)
172
+
173
+ try {
174
+ if (ide === 'claude-code') {
175
+ // For CLAUDE.md, remove only the Oculum section, not the whole file
176
+ if (existsSync(fullPath)) {
177
+ const content = readFileSync(fullPath, 'utf-8')
178
+ const startMarker = '<!-- OCULUM_SECURITY_START -->'
179
+ const endMarker = '<!-- OCULUM_SECURITY_END -->'
180
+ const startIndex = content.indexOf(startMarker)
181
+ const endIndex = content.indexOf(endMarker)
182
+
183
+ if (startIndex !== -1 && endIndex !== -1) {
184
+ // Remove section (including potential surrounding newlines)
185
+ let newContent = content.substring(0, startIndex) + content.substring(endIndex + endMarker.length)
186
+ // Clean up extra newlines
187
+ newContent = newContent.replace(/\n{3,}/g, '\n\n').trimEnd() + '\n'
188
+ writeFileSync(fullPath, newContent)
189
+ clearedFiles.push(relativePath)
190
+ }
191
+ }
192
+ } else {
193
+ // For other IDEs, delete the file
194
+ if (existsSync(fullPath)) {
195
+ unlinkSync(fullPath)
196
+ clearedFiles.push(relativePath)
197
+ }
198
+ }
199
+ } catch (err) {
200
+ errors.push(`Failed to clear ${relativePath}: ${err instanceof Error ? err.message : 'Unknown error'}`)
201
+ }
202
+ }
203
+
204
+ return {
205
+ success: errors.length === 0,
206
+ clearedFiles,
207
+ errors,
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Get the default file path for an IDE type
213
+ */
214
+ export function getIDEFilePath(ide: IDEType): string {
215
+ return IDE_FILE_PATHS[ide]
216
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Windsurf IDE Integration
3
+ * Generates .windsurfrules format
4
+ */
5
+
6
+ import type { ScanResult, Vulnerability, VulnerabilityCategory } from '../../types'
7
+ import { sortBySeverity } from '../grouping'
8
+
9
+ /**
10
+ * Get security pattern rule for a category
11
+ */
12
+ function getPatternRule(category: VulnerabilityCategory): string | null {
13
+ const rules: Partial<Record<VulnerabilityCategory, string>> = {
14
+ sql_injection: 'ALWAYS use parameterized queries for database operations.',
15
+ xss: 'ALWAYS escape user input before inserting into HTML.',
16
+ hardcoded_secret: 'NEVER hardcode secrets, API keys, or credentials in source code.',
17
+ high_entropy_string: 'NEVER commit high-entropy strings that could be secrets.',
18
+ missing_auth: 'ALWAYS add authentication middleware to API endpoints.',
19
+ dangerous_function: 'NEVER use eval(), exec(), or similar functions with user input.',
20
+ command_injection: 'ALWAYS sanitize input before passing to shell commands.',
21
+ sensitive_url: 'NEVER hardcode localhost or internal URLs in production code.',
22
+ insecure_config: 'ALWAYS review configuration files for security issues.',
23
+ data_exposure: 'NEVER log or expose sensitive data in error messages.',
24
+ weak_crypto: 'ALWAYS use strong cryptographic algorithms (avoid MD5, SHA1).',
25
+ ai_prompt_injection: 'ALWAYS sanitize user input before including in AI prompts.',
26
+ ai_unsafe_execution: 'NEVER execute code generated by AI without validation.',
27
+ }
28
+
29
+ return rules[category] || null
30
+ }
31
+
32
+ /**
33
+ * Format scan result as Windsurf rules
34
+ *
35
+ * @param result - The scan result to format
36
+ * @returns Markdown string for .windsurfrules
37
+ */
38
+ export function formatWindsurfRules(result: ScanResult): string {
39
+ const { vulnerabilities, timestamp } = result
40
+
41
+ // Sort by severity
42
+ const sorted = sortBySeverity(vulnerabilities)
43
+
44
+ let md = ''
45
+
46
+ // Header
47
+ md += `# Oculum Security Rules\n\n`
48
+ md += `> Generated: ${timestamp}\n\n`
49
+
50
+ // No findings case
51
+ if (vulnerabilities.length === 0) {
52
+ md += `## Status\n\n`
53
+ md += `No security issues found.\n\n`
54
+ md += `*Run \`oculum scan --windsurf --clear\` to remove this file.*\n`
55
+ return md
56
+ }
57
+
58
+ // Security Issues Section
59
+ md += `## Security Issues\n\n`
60
+ md += `The following security issues were detected and need attention:\n\n`
61
+
62
+ // Group by file
63
+ const byFile = new Map<string, Vulnerability[]>()
64
+ for (const vuln of sorted) {
65
+ const group = byFile.get(vuln.filePath) || []
66
+ group.push(vuln)
67
+ byFile.set(vuln.filePath, group)
68
+ }
69
+
70
+ // List by file
71
+ for (const [filePath, vulns] of byFile) {
72
+ md += `### ${filePath}\n\n`
73
+
74
+ for (const vuln of vulns) {
75
+ const severityEmoji =
76
+ vuln.severity === 'critical' ? '!!' :
77
+ vuln.severity === 'high' ? '!' :
78
+ vuln.severity === 'medium' ? '*' : '-'
79
+
80
+ md += `- ${severityEmoji} **Line ${vuln.lineNumber}:** ${vuln.title}`
81
+ if (vuln.suggestedFix) {
82
+ md += ` - ${vuln.suggestedFix}`
83
+ }
84
+ md += '\n'
85
+ }
86
+ md += '\n'
87
+ }
88
+
89
+ // Code Patterns Section
90
+ md += `## Code Patterns\n\n`
91
+ md += `Follow these security patterns when writing code:\n\n`
92
+
93
+ // Collect unique pattern rules
94
+ const patternRules = new Set<string>()
95
+ for (const vuln of vulnerabilities) {
96
+ const rule = getPatternRule(vuln.category)
97
+ if (rule) {
98
+ patternRules.add(rule)
99
+ }
100
+ }
101
+
102
+ for (const rule of patternRules) {
103
+ md += `- ${rule}\n`
104
+ }
105
+ md += '\n'
106
+
107
+ // Quick Reference
108
+ md += `## Quick Reference\n\n`
109
+ md += `| Severity | Count | Action |\n`
110
+ md += `|----------|-------|--------|\n`
111
+
112
+ const { severityCounts } = result
113
+ if (severityCounts.critical > 0) {
114
+ md += `| Critical | ${severityCounts.critical} | Fix immediately |\n`
115
+ }
116
+ if (severityCounts.high > 0) {
117
+ md += `| High | ${severityCounts.high} | Fix before commit |\n`
118
+ }
119
+ if (severityCounts.medium > 0) {
120
+ md += `| Medium | ${severityCounts.medium} | Review and fix |\n`
121
+ }
122
+ if (severityCounts.low > 0) {
123
+ md += `| Low | ${severityCounts.low} | Consider fixing |\n`
124
+ }
125
+ if (severityCounts.info > 0) {
126
+ md += `| Info | ${severityCounts.info} | For awareness |\n`
127
+ }
128
+ md += '\n'
129
+
130
+ // Footer
131
+ md += `---\n\n`
132
+ md += `*Run \`oculum scan\` to verify fixes. Run \`oculum scan --windsurf --clear\` to remove this file.*\n`
133
+
134
+ return md
135
+ }
@@ -16,6 +16,30 @@ export {
16
16
  type GroupedFindings,
17
17
  } from './grouping'
18
18
 
19
+ // AI Context formatter
20
+ export {
21
+ formatAIContext,
22
+ type AIContextOptions,
23
+ } from './ai-context'
24
+
25
+ // IDE integrations
26
+ export {
27
+ formatCursorRules,
28
+ formatWindsurfRules,
29
+ formatClaudeCodeSection,
30
+ detectIDEConfigs,
31
+ writeIDEFile,
32
+ updateClaudeMdSection,
33
+ clearIDEFiles,
34
+ getIDEFilePath,
35
+ OCULUM_SECTION_START,
36
+ OCULUM_SECTION_END,
37
+ IDE_FILE_PATHS,
38
+ type IDEType,
39
+ type WriteIDEFileResult,
40
+ type ClearIDEFilesResult,
41
+ } from './ide'
42
+
19
43
  // GitHub comment formatter
20
44
  export {
21
45
  formatGitHubComment,