solidity-argus 0.3.3 → 0.3.4
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.
- package/package.json +1 -1
- package/src/agents/argus-prompt.ts +21 -8
- package/src/agents/scribe-prompt.ts +9 -5
- package/src/cli/index.ts +0 -0
- package/src/config/schema.ts +5 -0
- package/src/create-hooks.ts +78 -22
- package/src/features/migration/index.ts +14 -0
- package/src/features/migration/migration-adapter.ts +151 -0
- package/src/features/migration/parity-telemetry.ts +133 -0
- package/src/features/persistent-state/event-sink.ts +171 -0
- package/src/features/persistent-state/index.ts +2 -0
- package/src/features/persistent-state/run-finalizer.ts +175 -0
- package/src/features/persistent-state/run-journal.ts +1 -1
- package/src/hooks/agent-tracker.ts +15 -0
- package/src/hooks/event-hook.ts +93 -1
- package/src/hooks/tool-tracking-hook.ts +263 -33
- package/src/shared/audit-artifact-resolver.ts +74 -0
- package/src/shared/drop-diagnostics.ts +108 -0
- package/src/shared/index.ts +14 -0
- package/src/shared/report-path-resolver.ts +70 -0
- package/src/solodit-lifecycle.ts +86 -7
- package/src/state/adapters.ts +262 -0
- package/src/state/index.ts +15 -0
- package/src/state/projectors.ts +437 -0
- package/src/state/schemas.ts +356 -0
- package/src/tools/report-generator-tool.ts +569 -31
- package/src/tools/solodit-search-tool.ts +11 -24
- package/src/utils/solodit-health.ts +18 -0
package/src/solodit-lifecycle.ts
CHANGED
|
@@ -6,6 +6,15 @@ interface SoloditChildProcess {
|
|
|
6
6
|
kill(signal?: number): void
|
|
7
7
|
unref(): void
|
|
8
8
|
readonly exited: Promise<number | null>
|
|
9
|
+
readonly pid?: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type LifecycleState = "starting" | "running" | "failed" | "stopped"
|
|
13
|
+
|
|
14
|
+
export interface LifecycleStatus {
|
|
15
|
+
state: LifecycleState
|
|
16
|
+
error?: string
|
|
17
|
+
pid?: number
|
|
9
18
|
}
|
|
10
19
|
|
|
11
20
|
let soloditChild: SoloditChildProcess | null = null
|
|
@@ -15,6 +24,9 @@ let isRestarting = false
|
|
|
15
24
|
/** Whether the Solodit MCP server is currently available for tool calls. */
|
|
16
25
|
export let soloditAvailable = false
|
|
17
26
|
|
|
27
|
+
let lifecycleState: LifecycleState = "stopped"
|
|
28
|
+
let lifecycleError: string | undefined
|
|
29
|
+
|
|
18
30
|
const DEFAULT_RESTART_SETTLE_MS = 2_000
|
|
19
31
|
const DEFAULT_RETRY_BASE_DELAY_MS = 1_000
|
|
20
32
|
const HEALTH_CHECK_INTERVAL_MS = 60_000
|
|
@@ -43,10 +55,37 @@ export function _setTestConfig(config: {
|
|
|
43
55
|
if (config.spawnFn !== undefined) spawnFn = config.spawnFn
|
|
44
56
|
}
|
|
45
57
|
|
|
58
|
+
/** Returns the current lifecycle status of the Solodit MCP server. */
|
|
59
|
+
export function getLifecycleStatus(): LifecycleStatus {
|
|
60
|
+
const status: LifecycleStatus = { state: lifecycleState }
|
|
61
|
+
if (lifecycleError) status.error = lifecycleError
|
|
62
|
+
if (soloditChild?.pid !== undefined) status.pid = soloditChild.pid
|
|
63
|
+
return status
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function classifySpawnError(err: unknown, port: number): string {
|
|
67
|
+
const error = err instanceof Error ? err : new Error(String(err))
|
|
68
|
+
const code = (error as NodeJS.ErrnoException).code
|
|
69
|
+
if (code === "EADDRINUSE") {
|
|
70
|
+
return `Port ${port} already in use — cannot spawn Solodit MCP (EADDRINUSE)`
|
|
71
|
+
}
|
|
72
|
+
if (code === "ENOENT") {
|
|
73
|
+
return `Solodit MCP binary not found — ensure npx and @lyuboslavlyubenov/solodit-mcp are available (ENOENT)`
|
|
74
|
+
}
|
|
75
|
+
return `Failed to spawn Solodit MCP on port ${port}: ${error.message}`
|
|
76
|
+
}
|
|
77
|
+
|
|
46
78
|
function spawnSoloditChild(port: number): SoloditChildProcess {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
79
|
+
try {
|
|
80
|
+
const child = spawnFn(port)
|
|
81
|
+
child.unref()
|
|
82
|
+
return child
|
|
83
|
+
} catch (err) {
|
|
84
|
+
const message = classifySpawnError(err, port)
|
|
85
|
+
lifecycleState = "failed"
|
|
86
|
+
lifecycleError = message
|
|
87
|
+
throw new Error(message)
|
|
88
|
+
}
|
|
50
89
|
}
|
|
51
90
|
|
|
52
91
|
function trackChildExit(child: SoloditChildProcess): void {
|
|
@@ -64,6 +103,16 @@ function trackChildExit(child: SoloditChildProcess): void {
|
|
|
64
103
|
async function restartSoloditMcp(port: number): Promise<boolean> {
|
|
65
104
|
const logger = createLogger()
|
|
66
105
|
|
|
106
|
+
// Pre-check: if existing instance recovered, skip restart entirely
|
|
107
|
+
const preCheck = await checkSoloditHealth(port, true)
|
|
108
|
+
if (preCheck.reachable) {
|
|
109
|
+
soloditAvailable = true
|
|
110
|
+
lifecycleState = "running"
|
|
111
|
+
lifecycleError = undefined
|
|
112
|
+
logger.info("Solodit MCP already healthy — skipping restart")
|
|
113
|
+
return true
|
|
114
|
+
}
|
|
115
|
+
|
|
67
116
|
if (soloditChild) {
|
|
68
117
|
try {
|
|
69
118
|
soloditChild.kill()
|
|
@@ -74,10 +123,16 @@ async function restartSoloditMcp(port: number): Promise<boolean> {
|
|
|
74
123
|
}
|
|
75
124
|
|
|
76
125
|
try {
|
|
126
|
+
lifecycleState = "starting"
|
|
127
|
+
lifecycleError = undefined
|
|
77
128
|
soloditChild = spawnSoloditChild(port)
|
|
78
129
|
trackChildExit(soloditChild)
|
|
79
130
|
} catch (err) {
|
|
80
|
-
|
|
131
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
132
|
+
logger.warn(`Solodit MCP spawn failed: ${message}`)
|
|
133
|
+
lifecycleState = "failed"
|
|
134
|
+
lifecycleError = message
|
|
135
|
+
soloditAvailable = false
|
|
81
136
|
return false
|
|
82
137
|
}
|
|
83
138
|
|
|
@@ -99,10 +154,14 @@ async function restartSoloditMcp(port: number): Promise<boolean> {
|
|
|
99
154
|
|
|
100
155
|
if (result.success) {
|
|
101
156
|
soloditAvailable = true
|
|
157
|
+
lifecycleState = "running"
|
|
158
|
+
lifecycleError = undefined
|
|
102
159
|
logger.info("Solodit MCP restarted successfully")
|
|
103
160
|
return true
|
|
104
161
|
}
|
|
105
162
|
|
|
163
|
+
lifecycleState = "failed"
|
|
164
|
+
lifecycleError = "Solodit MCP not reachable after restart attempts"
|
|
106
165
|
logger.warn("Solodit MCP restart failed — will retry next cycle")
|
|
107
166
|
return false
|
|
108
167
|
}
|
|
@@ -115,6 +174,8 @@ export async function _runMonitoringCycle(port: number): Promise<void> {
|
|
|
115
174
|
if (health.reachable) {
|
|
116
175
|
if (!soloditAvailable) {
|
|
117
176
|
soloditAvailable = true
|
|
177
|
+
lifecycleState = "running"
|
|
178
|
+
lifecycleError = undefined
|
|
118
179
|
logger.info("Solodit MCP recovered — now available")
|
|
119
180
|
}
|
|
120
181
|
} else if (soloditAvailable) {
|
|
@@ -155,6 +216,8 @@ export function _resetSoloditState(): void {
|
|
|
155
216
|
stopSoloditMonitoring()
|
|
156
217
|
soloditAvailable = false
|
|
157
218
|
isRestarting = false
|
|
219
|
+
lifecycleState = "stopped"
|
|
220
|
+
lifecycleError = undefined
|
|
158
221
|
restartSettleMs = DEFAULT_RESTART_SETTLE_MS
|
|
159
222
|
retryBaseDelayMs = DEFAULT_RETRY_BASE_DELAY_MS
|
|
160
223
|
spawnFn = defaultSpawnFn
|
|
@@ -170,17 +233,30 @@ export function _resetSoloditState(): void {
|
|
|
170
233
|
|
|
171
234
|
export async function startSoloditMcp(port: number): Promise<void> {
|
|
172
235
|
const logger = createLogger()
|
|
236
|
+
lifecycleState = "starting"
|
|
237
|
+
lifecycleError = undefined
|
|
173
238
|
|
|
174
239
|
const health = await checkSoloditHealth(port, true)
|
|
175
240
|
if (health.reachable) {
|
|
176
241
|
logger.debug(`Solodit MCP already running on port ${port} — skipping spawn`)
|
|
177
242
|
soloditAvailable = true
|
|
243
|
+
lifecycleState = "running"
|
|
178
244
|
startMonitoring(port)
|
|
179
245
|
return
|
|
180
246
|
}
|
|
181
247
|
|
|
182
|
-
|
|
183
|
-
|
|
248
|
+
try {
|
|
249
|
+
soloditChild = spawnSoloditChild(port)
|
|
250
|
+
trackChildExit(soloditChild)
|
|
251
|
+
} catch (err) {
|
|
252
|
+
const message = err instanceof Error ? err.message : String(err)
|
|
253
|
+
logger.warn(`Solodit MCP startup failed: ${message}`)
|
|
254
|
+
lifecycleState = "failed"
|
|
255
|
+
lifecycleError = message
|
|
256
|
+
soloditAvailable = false
|
|
257
|
+
startMonitoring(port)
|
|
258
|
+
return
|
|
259
|
+
}
|
|
184
260
|
|
|
185
261
|
const deadline = AbortSignal.timeout(5000)
|
|
186
262
|
const delays = [1000, 2000]
|
|
@@ -191,12 +267,15 @@ export async function startSoloditMcp(port: number): Promise<void> {
|
|
|
191
267
|
const healthResult = await checkSoloditHealth(port, true)
|
|
192
268
|
if (healthResult.reachable) {
|
|
193
269
|
soloditAvailable = true
|
|
270
|
+
lifecycleState = "running"
|
|
194
271
|
logger.debug(`Solodit MCP healthy on port ${port}`)
|
|
195
272
|
break
|
|
196
273
|
}
|
|
197
274
|
}
|
|
198
275
|
if (!soloditAvailable) {
|
|
199
|
-
|
|
276
|
+
lifecycleState = "failed"
|
|
277
|
+
lifecycleError = "Solodit MCP not reachable after startup — monitoring will retry"
|
|
278
|
+
logger.warn(lifecycleError)
|
|
200
279
|
}
|
|
201
280
|
|
|
202
281
|
startMonitoring(port)
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type CanonicalFinding,
|
|
3
|
+
SCHEMA_VERSION,
|
|
4
|
+
type ValidationError,
|
|
5
|
+
validateCanonicalFinding,
|
|
6
|
+
} from "./schemas"
|
|
7
|
+
import type { AuditPhase, Finding, FindingSeverity } from "./types"
|
|
8
|
+
|
|
9
|
+
export interface Diagnostic {
|
|
10
|
+
level: "warn" | "error"
|
|
11
|
+
code: string
|
|
12
|
+
message: string
|
|
13
|
+
field?: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type AdapterResult<T> = { data: T; diagnostics: Diagnostic[] }
|
|
17
|
+
|
|
18
|
+
const VALID_SEVERITIES: ReadonlySet<FindingSeverity> = new Set([
|
|
19
|
+
"Critical",
|
|
20
|
+
"High",
|
|
21
|
+
"Medium",
|
|
22
|
+
"Low",
|
|
23
|
+
"Informational",
|
|
24
|
+
])
|
|
25
|
+
const VALID_CONFIDENCES: ReadonlySet<CanonicalFinding["confidence"]> = new Set([
|
|
26
|
+
"High",
|
|
27
|
+
"Medium",
|
|
28
|
+
"Low",
|
|
29
|
+
])
|
|
30
|
+
const VALID_SOURCES: ReadonlySet<CanonicalFinding["source"]> = new Set([
|
|
31
|
+
"slither",
|
|
32
|
+
"manual",
|
|
33
|
+
"pattern",
|
|
34
|
+
"scvd",
|
|
35
|
+
"solodit",
|
|
36
|
+
"fuzz",
|
|
37
|
+
])
|
|
38
|
+
|
|
39
|
+
const KNOWN_INPUT_FIELDS = new Set([
|
|
40
|
+
"id",
|
|
41
|
+
"check",
|
|
42
|
+
"detector",
|
|
43
|
+
"severity",
|
|
44
|
+
"confidence",
|
|
45
|
+
"description",
|
|
46
|
+
"impact",
|
|
47
|
+
"first_markdown_element",
|
|
48
|
+
"file",
|
|
49
|
+
"lines",
|
|
50
|
+
"line",
|
|
51
|
+
"line_start",
|
|
52
|
+
"line_end",
|
|
53
|
+
"source",
|
|
54
|
+
"remediation",
|
|
55
|
+
"exploitReference",
|
|
56
|
+
"provenance",
|
|
57
|
+
"run_id",
|
|
58
|
+
"seq",
|
|
59
|
+
"session_id",
|
|
60
|
+
"tool_call_id",
|
|
61
|
+
"schema_version",
|
|
62
|
+
"elements",
|
|
63
|
+
])
|
|
64
|
+
|
|
65
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
66
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function normalizeSeverity(value: unknown): CanonicalFinding["severity"] {
|
|
70
|
+
if (typeof value !== "string") return "Informational"
|
|
71
|
+
const lower = value.toLowerCase()
|
|
72
|
+
const map: Record<string, CanonicalFinding["severity"]> = {
|
|
73
|
+
critical: "Critical",
|
|
74
|
+
high: "High",
|
|
75
|
+
medium: "Medium",
|
|
76
|
+
low: "Low",
|
|
77
|
+
informational: "Informational",
|
|
78
|
+
info: "Informational",
|
|
79
|
+
}
|
|
80
|
+
return map[lower] ?? "Informational"
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function normalizeConfidence(value: unknown): CanonicalFinding["confidence"] {
|
|
84
|
+
if (typeof value !== "string") return "Low"
|
|
85
|
+
const lower = value.toLowerCase()
|
|
86
|
+
const map: Record<string, CanonicalFinding["confidence"]> = {
|
|
87
|
+
high: "High",
|
|
88
|
+
medium: "Medium",
|
|
89
|
+
low: "Low",
|
|
90
|
+
}
|
|
91
|
+
return map[lower] ?? "Low"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function normalizeLines(
|
|
95
|
+
value: unknown,
|
|
96
|
+
input: Record<string, unknown>,
|
|
97
|
+
): [number, number] | undefined {
|
|
98
|
+
if (
|
|
99
|
+
Array.isArray(value) &&
|
|
100
|
+
value.length === 2 &&
|
|
101
|
+
typeof value[0] === "number" &&
|
|
102
|
+
typeof value[1] === "number"
|
|
103
|
+
) {
|
|
104
|
+
return [value[0], value[1]]
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (typeof input.line === "number") {
|
|
108
|
+
return [input.line, input.line]
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (typeof input.line_start === "number" && typeof input.line_end === "number") {
|
|
112
|
+
return [input.line_start, input.line_end]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return undefined
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function slitherElementFileAlias(input: Record<string, unknown>): string | undefined {
|
|
119
|
+
if (!Array.isArray(input.elements) || input.elements.length === 0) {
|
|
120
|
+
return undefined
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const first = input.elements[0]
|
|
124
|
+
if (!isRecord(first)) return undefined
|
|
125
|
+
const sourceMapping = first.source_mapping
|
|
126
|
+
if (!isRecord(sourceMapping)) return undefined
|
|
127
|
+
const filenameRelative = sourceMapping.filename_relative
|
|
128
|
+
return typeof filenameRelative === "string" && filenameRelative.length > 0
|
|
129
|
+
? filenameRelative
|
|
130
|
+
: undefined
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function pushValidationDiagnostics(errors: ValidationError[]): Diagnostic[] {
|
|
134
|
+
return errors.map((error) => ({
|
|
135
|
+
level: "error",
|
|
136
|
+
code: `validation.${error.code}`,
|
|
137
|
+
message: error.message,
|
|
138
|
+
field: error.field,
|
|
139
|
+
}))
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function normalizeToCanonicalFinding(
|
|
143
|
+
raw: Finding | Record<string, unknown>,
|
|
144
|
+
runId: string,
|
|
145
|
+
seq: number,
|
|
146
|
+
): AdapterResult<CanonicalFinding> {
|
|
147
|
+
const diagnostics: Diagnostic[] = []
|
|
148
|
+
const input = isRecord(raw) ? raw : {}
|
|
149
|
+
|
|
150
|
+
for (const key of Object.keys(input)) {
|
|
151
|
+
if (!KNOWN_INPUT_FIELDS.has(key)) {
|
|
152
|
+
diagnostics.push({
|
|
153
|
+
level: "warn",
|
|
154
|
+
code: "field.dropped",
|
|
155
|
+
message: `Dropped unknown field: ${key}`,
|
|
156
|
+
field: key,
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const check =
|
|
162
|
+
typeof input.check === "string" && input.check.length > 0
|
|
163
|
+
? input.check
|
|
164
|
+
: typeof input.detector === "string" && input.detector.length > 0
|
|
165
|
+
? input.detector
|
|
166
|
+
: ""
|
|
167
|
+
|
|
168
|
+
const description =
|
|
169
|
+
typeof input.description === "string" && input.description.length > 0
|
|
170
|
+
? input.description
|
|
171
|
+
: typeof input.impact === "string" && input.impact.length > 0
|
|
172
|
+
? input.impact
|
|
173
|
+
: typeof input.first_markdown_element === "string" &&
|
|
174
|
+
input.first_markdown_element.length > 0
|
|
175
|
+
? input.first_markdown_element
|
|
176
|
+
: check
|
|
177
|
+
|
|
178
|
+
const file =
|
|
179
|
+
typeof input.file === "string" && input.file.length > 0
|
|
180
|
+
? input.file
|
|
181
|
+
: (slitherElementFileAlias(input) ?? "")
|
|
182
|
+
|
|
183
|
+
const lines = normalizeLines(input.lines, input)
|
|
184
|
+
const severity = normalizeSeverity(input.severity)
|
|
185
|
+
const confidence = normalizeConfidence(input.confidence)
|
|
186
|
+
const source =
|
|
187
|
+
typeof input.source === "string" &&
|
|
188
|
+
VALID_SOURCES.has(input.source as CanonicalFinding["source"])
|
|
189
|
+
? (input.source as CanonicalFinding["source"])
|
|
190
|
+
: "manual"
|
|
191
|
+
|
|
192
|
+
const canonical: CanonicalFinding = {
|
|
193
|
+
id:
|
|
194
|
+
typeof input.id === "string" && input.id.length > 0
|
|
195
|
+
? input.id
|
|
196
|
+
: `${check}:${file}:${lines?.[0] ?? 0}`,
|
|
197
|
+
check,
|
|
198
|
+
severity: VALID_SEVERITIES.has(severity) ? severity : "Informational",
|
|
199
|
+
confidence: VALID_CONFIDENCES.has(confidence) ? confidence : "Low",
|
|
200
|
+
description,
|
|
201
|
+
file,
|
|
202
|
+
lines: lines ?? [0, 0],
|
|
203
|
+
source,
|
|
204
|
+
remediation: typeof input.remediation === "string" ? input.remediation : undefined,
|
|
205
|
+
exploitReference:
|
|
206
|
+
typeof input.exploitReference === "string" ? input.exploitReference : undefined,
|
|
207
|
+
provenance: isRecord(input.provenance)
|
|
208
|
+
? {
|
|
209
|
+
timestamp:
|
|
210
|
+
typeof input.provenance.timestamp === "number"
|
|
211
|
+
? input.provenance.timestamp
|
|
212
|
+
: Date.now(),
|
|
213
|
+
toolVersion:
|
|
214
|
+
typeof input.provenance.toolVersion === "string"
|
|
215
|
+
? input.provenance.toolVersion
|
|
216
|
+
: undefined,
|
|
217
|
+
phase:
|
|
218
|
+
typeof input.provenance.phase === "string"
|
|
219
|
+
? (input.provenance.phase as AuditPhase)
|
|
220
|
+
: undefined,
|
|
221
|
+
}
|
|
222
|
+
: undefined,
|
|
223
|
+
run_id: runId,
|
|
224
|
+
seq,
|
|
225
|
+
schema_version:
|
|
226
|
+
typeof input.schema_version === "string" && input.schema_version.length > 0
|
|
227
|
+
? input.schema_version
|
|
228
|
+
: SCHEMA_VERSION,
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const validation = validateCanonicalFinding(canonical)
|
|
232
|
+
if (!validation.success) {
|
|
233
|
+
diagnostics.push(...pushValidationDiagnostics(validation.errors))
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return { data: canonical, diagnostics }
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export function normalizeLegacyFindingsArray(
|
|
240
|
+
raw: unknown[],
|
|
241
|
+
runId: string,
|
|
242
|
+
): { findings: CanonicalFinding[]; diagnostics: Diagnostic[] } {
|
|
243
|
+
const findings: CanonicalFinding[] = []
|
|
244
|
+
const diagnostics: Diagnostic[] = []
|
|
245
|
+
|
|
246
|
+
for (const [index, item] of raw.entries()) {
|
|
247
|
+
const normalized = normalizeToCanonicalFinding(isRecord(item) ? item : {}, runId, index + 1)
|
|
248
|
+
diagnostics.push(
|
|
249
|
+
...normalized.diagnostics.map((d) => ({
|
|
250
|
+
...d,
|
|
251
|
+
message: `[index:${index}] ${d.message}`,
|
|
252
|
+
})),
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
const hasErrors = normalized.diagnostics.some((d) => d.level === "error")
|
|
256
|
+
if (!hasErrors) {
|
|
257
|
+
findings.push(normalized.data)
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return { findings, diagnostics }
|
|
262
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from "./adapters"
|
|
2
|
+
export { createAuditState } from "./audit-state"
|
|
3
|
+
export { createFindingStore } from "./finding-store"
|
|
4
|
+
export {
|
|
5
|
+
ProjectorError,
|
|
6
|
+
projectAuditState,
|
|
7
|
+
projectFindings,
|
|
8
|
+
projectReportInput,
|
|
9
|
+
projectToolExecutions,
|
|
10
|
+
SEVERITY_RANK,
|
|
11
|
+
stableHash,
|
|
12
|
+
validateEventSequence,
|
|
13
|
+
} from "./projectors"
|
|
14
|
+
export * from "./schemas"
|
|
15
|
+
export * from "./types"
|