@bouncesecurity/aghast 0.0.13
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/LICENSE +661 -0
- package/README.md +111 -0
- package/config/prompts/generic-instructions.md +56 -0
- package/config/prompts/test-cheaper-instructions.md +57 -0
- package/dist/check-library.d.ts +87 -0
- package/dist/check-library.d.ts.map +1 -0
- package/dist/check-library.js +374 -0
- package/dist/check-library.js.map +1 -0
- package/dist/claude-code-provider.d.ts +26 -0
- package/dist/claude-code-provider.d.ts.map +1 -0
- package/dist/claude-code-provider.js +247 -0
- package/dist/claude-code-provider.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +78 -0
- package/dist/cli.js.map +1 -0
- package/dist/colors.d.ts +7 -0
- package/dist/colors.d.ts.map +1 -0
- package/dist/colors.js +18 -0
- package/dist/colors.js.map +1 -0
- package/dist/error-codes.d.ts +42 -0
- package/dist/error-codes.d.ts.map +1 -0
- package/dist/error-codes.js +60 -0
- package/dist/error-codes.js.map +1 -0
- package/dist/formatters/index.d.ts +10 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +23 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/formatters/json-formatter.d.ts +11 -0
- package/dist/formatters/json-formatter.d.ts.map +1 -0
- package/dist/formatters/json-formatter.js +11 -0
- package/dist/formatters/json-formatter.js.map +1 -0
- package/dist/formatters/sarif-formatter.d.ts +18 -0
- package/dist/formatters/sarif-formatter.d.ts.map +1 -0
- package/dist/formatters/sarif-formatter.js +103 -0
- package/dist/formatters/sarif-formatter.js.map +1 -0
- package/dist/formatters/types.d.ts +11 -0
- package/dist/formatters/types.d.ts.map +1 -0
- package/dist/formatters/types.js +6 -0
- package/dist/formatters/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +406 -0
- package/dist/index.js.map +1 -0
- package/dist/logging.d.ts +26 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +79 -0
- package/dist/logging.js.map +1 -0
- package/dist/mock-ai-provider.d.ts +18 -0
- package/dist/mock-ai-provider.d.ts.map +1 -0
- package/dist/mock-ai-provider.js +28 -0
- package/dist/mock-ai-provider.js.map +1 -0
- package/dist/new-check.d.ts +13 -0
- package/dist/new-check.d.ts.map +1 -0
- package/dist/new-check.js +405 -0
- package/dist/new-check.js.map +1 -0
- package/dist/prompt-template.d.ts +12 -0
- package/dist/prompt-template.d.ts.map +1 -0
- package/dist/prompt-template.js +35 -0
- package/dist/prompt-template.js.map +1 -0
- package/dist/provider-registry.d.ts +15 -0
- package/dist/provider-registry.d.ts.map +1 -0
- package/dist/provider-registry.js +27 -0
- package/dist/provider-registry.js.map +1 -0
- package/dist/repository-analyzer.d.ts +68 -0
- package/dist/repository-analyzer.d.ts.map +1 -0
- package/dist/repository-analyzer.js +230 -0
- package/dist/repository-analyzer.js.map +1 -0
- package/dist/response-parser.d.ts +12 -0
- package/dist/response-parser.d.ts.map +1 -0
- package/dist/response-parser.js +109 -0
- package/dist/response-parser.js.map +1 -0
- package/dist/runtime-config.d.ts +15 -0
- package/dist/runtime-config.d.ts.map +1 -0
- package/dist/runtime-config.js +73 -0
- package/dist/runtime-config.js.map +1 -0
- package/dist/sarif-parser.d.ts +20 -0
- package/dist/sarif-parser.d.ts.map +1 -0
- package/dist/sarif-parser.js +76 -0
- package/dist/sarif-parser.js.map +1 -0
- package/dist/scan-runner.d.ts +29 -0
- package/dist/scan-runner.d.ts.map +1 -0
- package/dist/scan-runner.js +559 -0
- package/dist/scan-runner.js.map +1 -0
- package/dist/semgrep-runner.d.ts +25 -0
- package/dist/semgrep-runner.d.ts.map +1 -0
- package/dist/semgrep-runner.js +100 -0
- package/dist/semgrep-runner.js.map +1 -0
- package/dist/snippet-extractor.d.ts +25 -0
- package/dist/snippet-extractor.d.ts.map +1 -0
- package/dist/snippet-extractor.js +56 -0
- package/dist/snippet-extractor.js.map +1 -0
- package/dist/types.d.ts +206 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code AI provider implementation.
|
|
3
|
+
* Uses @anthropic-ai/claude-agent-sdk per spec Section 6.2 / Appendix C.8.
|
|
4
|
+
*/
|
|
5
|
+
import { DEFAULT_AI_MODEL, FatalProviderError } from './types.js';
|
|
6
|
+
// import { parseAIResponse } from './response-parser.js';
|
|
7
|
+
import { logProgress, logDebug, logDebugFull, createTimer } from './logging.js';
|
|
8
|
+
const TAG = 'ai-provider';
|
|
9
|
+
const HEARTBEAT_INTERVAL_MS = 15000; // Log heartbeat every 15s if no activity
|
|
10
|
+
const MAX_API_ERROR_RETRIES = 3; // Fail after this many consecutive API errors
|
|
11
|
+
// JSON schema for structured output (matches spec Section 4.4)
|
|
12
|
+
const OUTPUT_SCHEMA = {
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {
|
|
15
|
+
issues: {
|
|
16
|
+
type: 'array',
|
|
17
|
+
items: {
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
file: { type: 'string' },
|
|
21
|
+
startLine: { type: 'integer' },
|
|
22
|
+
endLine: { type: 'integer' },
|
|
23
|
+
description: { type: 'string' },
|
|
24
|
+
dataFlow: {
|
|
25
|
+
type: 'array',
|
|
26
|
+
items: {
|
|
27
|
+
type: 'object',
|
|
28
|
+
properties: {
|
|
29
|
+
file: { type: 'string' },
|
|
30
|
+
lineNumber: { type: 'integer' },
|
|
31
|
+
label: { type: 'string' },
|
|
32
|
+
},
|
|
33
|
+
required: ['file', 'lineNumber', 'label'],
|
|
34
|
+
additionalProperties: false,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
required: ['file', 'startLine', 'endLine', 'description'],
|
|
39
|
+
additionalProperties: false,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
required: ['issues'],
|
|
44
|
+
additionalProperties: false,
|
|
45
|
+
};
|
|
46
|
+
export class ClaudeCodeProvider {
|
|
47
|
+
apiKey;
|
|
48
|
+
useLocalClaude = false;
|
|
49
|
+
model = DEFAULT_AI_MODEL;
|
|
50
|
+
_queryFn;
|
|
51
|
+
debugEnabled = false;
|
|
52
|
+
constructor(options) {
|
|
53
|
+
this._queryFn = options?._queryFn;
|
|
54
|
+
}
|
|
55
|
+
async initialize(config) {
|
|
56
|
+
this.useLocalClaude = process.env.AGHAST_LOCAL_CLAUDE === 'true';
|
|
57
|
+
this.apiKey = config.apiKey ?? process.env.ANTHROPIC_API_KEY;
|
|
58
|
+
// Model selection priority: config.model (from AGHAST_AI_MODEL env or runtime config) > DEFAULT_AI_MODEL
|
|
59
|
+
if (config.model) {
|
|
60
|
+
this.model = config.model;
|
|
61
|
+
}
|
|
62
|
+
if (!this.apiKey && !this.useLocalClaude) {
|
|
63
|
+
throw new Error('ANTHROPIC_API_KEY is required (or set AGHAST_LOCAL_CLAUDE=true to use your local Claude Code session)');
|
|
64
|
+
}
|
|
65
|
+
if (this.useLocalClaude) {
|
|
66
|
+
logProgress(TAG, 'Using local Claude Code session for authentication');
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
logDebug(TAG, 'Using API key for authentication');
|
|
70
|
+
}
|
|
71
|
+
logDebug(TAG, `Provider initialized with model ${this.model}`);
|
|
72
|
+
}
|
|
73
|
+
getModelName() {
|
|
74
|
+
return this.model;
|
|
75
|
+
}
|
|
76
|
+
enableDebug() {
|
|
77
|
+
this.debugEnabled = true;
|
|
78
|
+
}
|
|
79
|
+
async executeCheck(instructions, repositoryPath, logPrefix) {
|
|
80
|
+
const queryFn = this._queryFn ?? (await import('@anthropic-ai/claude-agent-sdk')).query;
|
|
81
|
+
const timer = createTimer();
|
|
82
|
+
const prefix = logPrefix ? `${logPrefix} ` : '';
|
|
83
|
+
const prompt = instructions;
|
|
84
|
+
logDebug(TAG, `${prefix}Starting query: model=${this.model}, cwd=${repositoryPath}, promptLen=${prompt.length}`);
|
|
85
|
+
if (this.debugEnabled) {
|
|
86
|
+
logDebugFull(TAG, `${prefix}Full prompt sent to AI`, prompt);
|
|
87
|
+
}
|
|
88
|
+
const conversation = queryFn({
|
|
89
|
+
prompt,
|
|
90
|
+
options: {
|
|
91
|
+
model: this.model,
|
|
92
|
+
cwd: repositoryPath,
|
|
93
|
+
allowedTools: ['Read', 'Glob', 'Grep', 'Bash', 'WebSearch', 'WebFetch'],
|
|
94
|
+
maxTurns: 100,
|
|
95
|
+
permissionMode: 'bypassPermissions',
|
|
96
|
+
outputFormat: {
|
|
97
|
+
type: 'json_schema',
|
|
98
|
+
schema: OUTPUT_SCHEMA,
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
// Consume all messages from the async generator to get the result
|
|
103
|
+
let resultText = '';
|
|
104
|
+
let structuredOutput;
|
|
105
|
+
let errorMessage;
|
|
106
|
+
let turnCount = 0;
|
|
107
|
+
let toolCallCount = 0;
|
|
108
|
+
let tokenUsage;
|
|
109
|
+
let consecutiveApiErrors = 0;
|
|
110
|
+
let currentToolName;
|
|
111
|
+
let lastActivityTime = Date.now();
|
|
112
|
+
// Background heartbeat timer - logs if no activity for a while
|
|
113
|
+
const heartbeatInterval = setInterval(() => {
|
|
114
|
+
const silentSeconds = Math.round((Date.now() - lastActivityTime) / 1000);
|
|
115
|
+
if (silentSeconds >= HEARTBEAT_INTERVAL_MS / 1000) {
|
|
116
|
+
const status = currentToolName ? `running ${currentToolName}` : 'waiting';
|
|
117
|
+
logProgress(TAG, `${prefix}Still ${status}... (${timer.elapsedStr()})`);
|
|
118
|
+
}
|
|
119
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
120
|
+
try {
|
|
121
|
+
for await (const message of conversation) {
|
|
122
|
+
lastActivityTime = Date.now();
|
|
123
|
+
// Tool progress events - emitted during long-running tool executions
|
|
124
|
+
if (message.type === 'tool_progress') {
|
|
125
|
+
const progress = message;
|
|
126
|
+
currentToolName = progress.tool_name;
|
|
127
|
+
logProgress(TAG, `${prefix}Running ${progress.tool_name}... (${Math.round(progress.elapsed_time_seconds)}s)`);
|
|
128
|
+
}
|
|
129
|
+
if (message.type === 'assistant') {
|
|
130
|
+
turnCount++;
|
|
131
|
+
currentToolName = undefined;
|
|
132
|
+
// Simple activity indicator at info level
|
|
133
|
+
logProgress(TAG, `${prefix}Turn ${turnCount} (${timer.elapsedStr()})`);
|
|
134
|
+
const content = message.message?.content;
|
|
135
|
+
if (Array.isArray(content)) {
|
|
136
|
+
// Count and log tool calls at debug level (compact)
|
|
137
|
+
for (const block of content) {
|
|
138
|
+
if (block?.type === 'tool_use') {
|
|
139
|
+
toolCallCount++;
|
|
140
|
+
currentToolName = block.name;
|
|
141
|
+
const inputStr = JSON.stringify(block.input);
|
|
142
|
+
const inputPreview = inputStr.length > 100 ? inputStr.slice(0, 100) + '...' : inputStr;
|
|
143
|
+
logDebug(TAG, `${prefix}Tool[${toolCallCount}]: ${block.name} ${inputPreview}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Log assistant text at debug level
|
|
147
|
+
const textChunks = content
|
|
148
|
+
.filter((c) => c?.type === 'text' && typeof c.text === 'string')
|
|
149
|
+
.map((c) => c.text.trim())
|
|
150
|
+
.filter(Boolean);
|
|
151
|
+
if (textChunks.length > 0) {
|
|
152
|
+
logDebug(TAG, `${prefix}Assistant: ${textChunks.join(' | ')}`);
|
|
153
|
+
// Detect rate-limit messages — fail immediately since retrying won't help
|
|
154
|
+
const rateLimitMatch = textChunks.find((t) => /you've hit your limit|rate limit/i.test(t));
|
|
155
|
+
if (rateLimitMatch) {
|
|
156
|
+
throw new FatalProviderError(`AI provider rate limit reached: ${rateLimitMatch}`);
|
|
157
|
+
}
|
|
158
|
+
// Detect authentication errors (401) — fail immediately, unrecoverable
|
|
159
|
+
const authErrorMatch = textChunks.find((t) => /API Error:\s*401/i.test(t));
|
|
160
|
+
if (authErrorMatch) {
|
|
161
|
+
throw new FatalProviderError(`AI provider authentication failed (401): ${authErrorMatch}`);
|
|
162
|
+
}
|
|
163
|
+
// Detect API errors surfaced as assistant text by the SDK
|
|
164
|
+
const apiErrorMatch = textChunks.find((t) => t.includes('API Error:'));
|
|
165
|
+
if (apiErrorMatch) {
|
|
166
|
+
consecutiveApiErrors++;
|
|
167
|
+
if (consecutiveApiErrors >= MAX_API_ERROR_RETRIES) {
|
|
168
|
+
throw new Error(`AI provider API error (after ${MAX_API_ERROR_RETRIES} attempts): ${apiErrorMatch}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
consecutiveApiErrors = 0;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (message.type === 'result') {
|
|
178
|
+
if (message.subtype === 'success') {
|
|
179
|
+
resultText = message.result;
|
|
180
|
+
// Extract structured output if available
|
|
181
|
+
const resultMsg = message;
|
|
182
|
+
if (resultMsg.structured_output) {
|
|
183
|
+
structuredOutput = resultMsg.structured_output;
|
|
184
|
+
logDebug(TAG, `${prefix}Structured output: ${structuredOutput.issues.length} issues`);
|
|
185
|
+
}
|
|
186
|
+
// Extract token usage if available.
|
|
187
|
+
// Prefer modelUsage (camelCase, per-model breakdown) over usage (snake_case, raw API).
|
|
188
|
+
if (resultMsg.modelUsage && Object.keys(resultMsg.modelUsage).length > 0) {
|
|
189
|
+
let inputTokens = 0;
|
|
190
|
+
let outputTokens = 0;
|
|
191
|
+
for (const model of Object.values(resultMsg.modelUsage)) {
|
|
192
|
+
inputTokens += model.inputTokens;
|
|
193
|
+
outputTokens += model.outputTokens;
|
|
194
|
+
}
|
|
195
|
+
tokenUsage = { inputTokens, outputTokens, totalTokens: inputTokens + outputTokens };
|
|
196
|
+
logDebug(TAG, `${prefix}Token usage: ${tokenUsage.inputTokens} in, ${tokenUsage.outputTokens} out, ${tokenUsage.totalTokens} total`);
|
|
197
|
+
}
|
|
198
|
+
else if (resultMsg.usage) {
|
|
199
|
+
tokenUsage = {
|
|
200
|
+
inputTokens: resultMsg.usage.input_tokens,
|
|
201
|
+
outputTokens: resultMsg.usage.output_tokens,
|
|
202
|
+
totalTokens: resultMsg.usage.input_tokens + resultMsg.usage.output_tokens,
|
|
203
|
+
};
|
|
204
|
+
logDebug(TAG, `${prefix}Token usage: ${tokenUsage.inputTokens} in, ${tokenUsage.outputTokens} out, ${tokenUsage.totalTokens} total`);
|
|
205
|
+
}
|
|
206
|
+
logProgress(TAG, `${prefix}Completed in ${timer.elapsedStr()} (${turnCount} turns, ${toolCallCount} tool calls)`);
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
const errorResult = message;
|
|
210
|
+
errorMessage = errorResult.errors?.join('; ') ?? `AI provider error: ${errorResult.subtype}`;
|
|
211
|
+
logProgress(TAG, `${prefix}Failed: ${errorResult.subtype} (${timer.elapsedStr()})`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
finally {
|
|
217
|
+
clearInterval(heartbeatInterval);
|
|
218
|
+
}
|
|
219
|
+
if (errorMessage) {
|
|
220
|
+
logDebug(TAG, `${prefix}Error: ${errorMessage}`);
|
|
221
|
+
throw new Error(errorMessage);
|
|
222
|
+
}
|
|
223
|
+
if (!resultText && !structuredOutput && !errorMessage) {
|
|
224
|
+
throw new Error('AI provider returned no result');
|
|
225
|
+
}
|
|
226
|
+
logDebug(TAG, `${prefix}Result: ${resultText.length} chars`);
|
|
227
|
+
if (this.debugEnabled) {
|
|
228
|
+
logDebugFull(TAG, `${prefix}Full AI response`, resultText);
|
|
229
|
+
}
|
|
230
|
+
// Structured output from SDK is required - we enforce JSON schema output mode.
|
|
231
|
+
// The response parser (parseAIResponse) is kept in the codebase as a potential
|
|
232
|
+
// fallback for future use cases (e.g., alternative AI providers that don't support
|
|
233
|
+
// structured output), but this provider always requires structured output.
|
|
234
|
+
if (structuredOutput) {
|
|
235
|
+
return { raw: resultText, parsed: structuredOutput, tokenUsage };
|
|
236
|
+
}
|
|
237
|
+
// No fallback parsing - structured output is mandatory for this provider.
|
|
238
|
+
// If needed in the future, uncomment:
|
|
239
|
+
// const parsed = parseAIResponse(resultText);
|
|
240
|
+
// return { raw: resultText, parsed: parsed ?? undefined };
|
|
241
|
+
throw new Error('AI provider did not return structured output');
|
|
242
|
+
}
|
|
243
|
+
async validateConfig() {
|
|
244
|
+
return !!this.apiKey || this.useLocalClaude;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=claude-code-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code-provider.js","sourceRoot":"","sources":["../src/claude-code-provider.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Unified CLI entry point for aghast.
|
|
4
|
+
* Subcommand router: delegates to `scan` or `new-check`.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* aghast scan <repo-path> [options]
|
|
8
|
+
* aghast new-check [options]
|
|
9
|
+
* aghast --help
|
|
10
|
+
* aghast --version
|
|
11
|
+
*/
|
|
12
|
+
import 'dotenv/config';
|
|
13
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AAEH,OAAO,eAAe,CAAC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Unified CLI entry point for aghast.
|
|
4
|
+
* Subcommand router: delegates to `scan` or `new-check`.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* aghast scan <repo-path> [options]
|
|
8
|
+
* aghast new-check [options]
|
|
9
|
+
* aghast --help
|
|
10
|
+
* aghast --version
|
|
11
|
+
*/
|
|
12
|
+
import 'dotenv/config';
|
|
13
|
+
import { createRequire } from 'node:module';
|
|
14
|
+
import { ERROR_CODES, formatError, formatFatalError } from './error-codes.js';
|
|
15
|
+
// Signal to subcommand modules that they're being imported, not run directly
|
|
16
|
+
process.env._AGHAST_CLI = '1';
|
|
17
|
+
const USAGE = `Usage: aghast <command> [options]
|
|
18
|
+
|
|
19
|
+
Commands:
|
|
20
|
+
scan Run security checks against a repository
|
|
21
|
+
new-check Scaffold a new security check
|
|
22
|
+
|
|
23
|
+
Options:
|
|
24
|
+
--help Show this help message
|
|
25
|
+
--version Show version number
|
|
26
|
+
|
|
27
|
+
Run 'aghast <command> --help' for more information on a command.`;
|
|
28
|
+
function getVersion() {
|
|
29
|
+
const require = createRequire(import.meta.url);
|
|
30
|
+
const pkg = require('../package.json');
|
|
31
|
+
return pkg.version;
|
|
32
|
+
}
|
|
33
|
+
function printVersion() {
|
|
34
|
+
console.log(getVersion());
|
|
35
|
+
}
|
|
36
|
+
async function main() {
|
|
37
|
+
// Graceful shutdown on POSIX signals
|
|
38
|
+
process.on('SIGINT', () => {
|
|
39
|
+
process.exit(130);
|
|
40
|
+
});
|
|
41
|
+
process.on('SIGTERM', () => {
|
|
42
|
+
process.exit(143);
|
|
43
|
+
});
|
|
44
|
+
const args = process.argv.slice(2);
|
|
45
|
+
const command = args[0];
|
|
46
|
+
if (!command || command === '--help' || command === '-h') {
|
|
47
|
+
console.log(USAGE);
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}
|
|
50
|
+
if (command === '--version' || command === '-V') {
|
|
51
|
+
printVersion();
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
const subArgs = args.slice(1);
|
|
55
|
+
switch (command) {
|
|
56
|
+
case 'scan': {
|
|
57
|
+
const { runScan } = await import('./index.js');
|
|
58
|
+
await runScan(subArgs);
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
case 'new-check': {
|
|
62
|
+
const { runNewCheck } = await import('./new-check.js');
|
|
63
|
+
await runNewCheck(subArgs);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
default:
|
|
67
|
+
console.error(formatError(ERROR_CODES.E1002, `Unknown command: ${command}`));
|
|
68
|
+
console.error('');
|
|
69
|
+
console.error(USAGE);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
main().catch((err) => {
|
|
74
|
+
console.error('');
|
|
75
|
+
console.error(formatFatalError(err instanceof Error ? err.message : String(err), getVersion()));
|
|
76
|
+
process.exit(1);
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/colors.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color helpers for CLI output.
|
|
3
|
+
* Uses picocolors which automatically respects NO_COLOR env var and non-TTY.
|
|
4
|
+
*/
|
|
5
|
+
export declare function colorStatus(status: string): string;
|
|
6
|
+
export declare function colorError(message: string): string;
|
|
7
|
+
//# sourceMappingURL=colors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colors.d.ts","sourceRoot":"","sources":["../src/colors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAQlD;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElD"}
|
package/dist/colors.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color helpers for CLI output.
|
|
3
|
+
* Uses picocolors which automatically respects NO_COLOR env var and non-TTY.
|
|
4
|
+
*/
|
|
5
|
+
import pc from 'picocolors';
|
|
6
|
+
export function colorStatus(status) {
|
|
7
|
+
switch (status) {
|
|
8
|
+
case 'PASS': return pc.green(status);
|
|
9
|
+
case 'FAIL': return pc.red(status);
|
|
10
|
+
case 'FLAG': return pc.yellow(status);
|
|
11
|
+
case 'ERROR': return pc.red(status);
|
|
12
|
+
default: return status;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function colorError(message) {
|
|
16
|
+
return pc.red(message);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=colors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colors.js","sourceRoot":"","sources":["../src/colors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACrC,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACnC,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACtC,KAAK,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpC,OAAO,CAAC,CAAC,OAAO,MAAM,CAAC;IACzB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,OAAO,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trackable error codes for CLI error paths.
|
|
3
|
+
*
|
|
4
|
+
* Numbering scheme:
|
|
5
|
+
* E1xxx — CLI parsing (argument/flag/command errors)
|
|
6
|
+
* E2xxx — Configuration (config dir, checks, runtime config)
|
|
7
|
+
* E3xxx — AI provider
|
|
8
|
+
* E4xxx — Repository/target validation
|
|
9
|
+
* E5xxx — Semgrep
|
|
10
|
+
* E9xxx — Internal/fatal
|
|
11
|
+
*/
|
|
12
|
+
export interface ErrorCode {
|
|
13
|
+
code: string;
|
|
14
|
+
label: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const ERROR_CODES: {
|
|
17
|
+
readonly E1001: ErrorCode;
|
|
18
|
+
readonly E1002: ErrorCode;
|
|
19
|
+
readonly E1003: ErrorCode;
|
|
20
|
+
readonly E2001: ErrorCode;
|
|
21
|
+
readonly E2002: ErrorCode;
|
|
22
|
+
readonly E2003: ErrorCode;
|
|
23
|
+
readonly E2004: ErrorCode;
|
|
24
|
+
readonly E2005: ErrorCode;
|
|
25
|
+
readonly E3001: ErrorCode;
|
|
26
|
+
readonly E3002: ErrorCode;
|
|
27
|
+
readonly E3003: ErrorCode;
|
|
28
|
+
readonly E4001: ErrorCode;
|
|
29
|
+
readonly E5001: ErrorCode;
|
|
30
|
+
readonly E5002: ErrorCode;
|
|
31
|
+
readonly E9001: ErrorCode;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Format an error message with a trackable error code.
|
|
35
|
+
* Output: "Error [E1001]: <message>"
|
|
36
|
+
*/
|
|
37
|
+
export declare function formatError(errorCode: ErrorCode, message: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Format a fatal error with version and bug report URL.
|
|
40
|
+
*/
|
|
41
|
+
export declare function formatFatalError(message: string, version: string): string;
|
|
42
|
+
//# sourceMappingURL=error-codes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-codes.d.ts","sourceRoot":"","sources":["../src/error-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAMD,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;CA2Bd,CAAC;AAEX;;;GAGG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAWzE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trackable error codes for CLI error paths.
|
|
3
|
+
*
|
|
4
|
+
* Numbering scheme:
|
|
5
|
+
* E1xxx — CLI parsing (argument/flag/command errors)
|
|
6
|
+
* E2xxx — Configuration (config dir, checks, runtime config)
|
|
7
|
+
* E3xxx — AI provider
|
|
8
|
+
* E4xxx — Repository/target validation
|
|
9
|
+
* E5xxx — Semgrep
|
|
10
|
+
* E9xxx — Internal/fatal
|
|
11
|
+
*/
|
|
12
|
+
function ec(code, label) {
|
|
13
|
+
return { code, label };
|
|
14
|
+
}
|
|
15
|
+
export const ERROR_CODES = {
|
|
16
|
+
// E1xxx — CLI parsing
|
|
17
|
+
E1001: ec('E1001', 'Missing required flag argument'),
|
|
18
|
+
E1002: ec('E1002', 'Unknown command'),
|
|
19
|
+
E1003: ec('E1003', 'Required input missing'),
|
|
20
|
+
// E2xxx — Configuration
|
|
21
|
+
E2001: ec('E2001', 'Config directory not specified'),
|
|
22
|
+
E2002: ec('E2002', 'Config directory structure invalid'),
|
|
23
|
+
E2003: ec('E2003', 'No checks found'),
|
|
24
|
+
E2004: ec('E2004', 'Invalid check definition'),
|
|
25
|
+
E2005: ec('E2005', 'Configuration error'),
|
|
26
|
+
// E3xxx — AI provider
|
|
27
|
+
E3001: ec('E3001', 'API key missing'),
|
|
28
|
+
E3002: ec('E3002', 'Unknown AI provider'),
|
|
29
|
+
E3003: ec('E3003', 'Mock AI response file not found'),
|
|
30
|
+
// E4xxx — Repository/target validation
|
|
31
|
+
E4001: ec('E4001', 'Repository path not found'),
|
|
32
|
+
// E5xxx — Semgrep
|
|
33
|
+
E5001: ec('E5001', 'Semgrep not installed'),
|
|
34
|
+
E5002: ec('E5002', 'Semgrep execution failed'),
|
|
35
|
+
// E9xxx — Internal
|
|
36
|
+
E9001: ec('E9001', 'Fatal internal error'),
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Format an error message with a trackable error code.
|
|
40
|
+
* Output: "Error [E1001]: <message>"
|
|
41
|
+
*/
|
|
42
|
+
export function formatError(errorCode, message) {
|
|
43
|
+
return `Error [${errorCode.code}]: ${message}`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Format a fatal error with version and bug report URL.
|
|
47
|
+
*/
|
|
48
|
+
export function formatFatalError(message, version) {
|
|
49
|
+
const title = encodeURIComponent(`[Bug] ${message}`);
|
|
50
|
+
const body = encodeURIComponent(`**Version:** ${version}\n\n**Error:**\n${message}`);
|
|
51
|
+
const url = `https://github.com/BounceSecurity/aghast/issues/new?title=${title}&body=${body}&labels=bug`;
|
|
52
|
+
return [
|
|
53
|
+
`AGHAST Fatal Error [${ERROR_CODES.E9001.code}]: ${message}`,
|
|
54
|
+
`Version: ${version}`,
|
|
55
|
+
'',
|
|
56
|
+
`If this is unexpected, please report it:`,
|
|
57
|
+
` ${url}`,
|
|
58
|
+
].join('\n');
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=error-codes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-codes.js","sourceRoot":"","sources":["../src/error-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,SAAS,EAAE,CAAC,IAAY,EAAE,KAAa;IACrC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,sBAAsB;IACtB,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,gCAAgC,CAAC;IACpD,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACrC,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,wBAAwB,CAAC;IAE5C,wBAAwB;IACxB,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,gCAAgC,CAAC;IACpD,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,oCAAoC,CAAC;IACxD,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACrC,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,0BAA0B,CAAC;IAC9C,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,qBAAqB,CAAC;IAEzC,sBAAsB;IACtB,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACrC,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,qBAAqB,CAAC;IACzC,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,iCAAiC,CAAC;IAErD,uCAAuC;IACvC,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,2BAA2B,CAAC;IAE/C,kBAAkB;IAClB,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,uBAAuB,CAAC;IAC3C,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,0BAA0B,CAAC;IAE9C,mBAAmB;IACnB,KAAK,EAAE,EAAE,CAAC,OAAO,EAAE,sBAAsB,CAAC;CAClC,CAAC;AAEX;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,SAAoB,EAAE,OAAe;IAC/D,OAAO,UAAU,SAAS,CAAC,IAAI,MAAM,OAAO,EAAE,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAe,EAAE,OAAe;IAC/D,MAAM,KAAK,GAAG,kBAAkB,CAAC,SAAS,OAAO,EAAE,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,kBAAkB,CAAC,gBAAgB,OAAO,mBAAmB,OAAO,EAAE,CAAC,CAAC;IACrF,MAAM,GAAG,GAAG,6DAA6D,KAAK,SAAS,IAAI,aAAa,CAAC;IACzG,OAAO;QACL,uBAAuB,WAAW,CAAC,KAAK,CAAC,IAAI,MAAM,OAAO,EAAE;QAC5D,YAAY,OAAO,EAAE;QACrB,EAAE;QACF,0CAA0C;QAC1C,KAAK,GAAG,EAAE;KACX,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatter registry — resolves output format IDs to formatter instances.
|
|
3
|
+
*/
|
|
4
|
+
import type { OutputFormatter } from './types.js';
|
|
5
|
+
export type { OutputFormatter } from './types.js';
|
|
6
|
+
/** Returns the formatter for the given ID, or throws listing available formats. */
|
|
7
|
+
export declare function getFormatter(id: string): OutputFormatter;
|
|
8
|
+
/** Returns all registered format IDs. */
|
|
9
|
+
export declare function getAvailableFormats(): string[];
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIlD,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAOlD,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,CAOxD;AAED,yCAAyC;AACzC,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatter registry — resolves output format IDs to formatter instances.
|
|
3
|
+
*/
|
|
4
|
+
import { JsonFormatter } from './json-formatter.js';
|
|
5
|
+
import { SarifFormatter } from './sarif-formatter.js';
|
|
6
|
+
const formatters = new Map([
|
|
7
|
+
['json', new JsonFormatter()],
|
|
8
|
+
['sarif', new SarifFormatter()],
|
|
9
|
+
]);
|
|
10
|
+
/** Returns the formatter for the given ID, or throws listing available formats. */
|
|
11
|
+
export function getFormatter(id) {
|
|
12
|
+
const formatter = formatters.get(id);
|
|
13
|
+
if (!formatter) {
|
|
14
|
+
const available = getAvailableFormats().join(', ');
|
|
15
|
+
throw new Error(`Unknown output format "${id}". Available formats: ${available}`);
|
|
16
|
+
}
|
|
17
|
+
return formatter;
|
|
18
|
+
}
|
|
19
|
+
/** Returns all registered format IDs. */
|
|
20
|
+
export function getAvailableFormats() {
|
|
21
|
+
return Array.from(formatters.keys());
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAItD,MAAM,UAAU,GAAG,IAAI,GAAG,CAA0B;IAClD,CAAC,MAAM,EAAE,IAAI,aAAa,EAAE,CAAC;IAC7B,CAAC,OAAO,EAAE,IAAI,cAAc,EAAE,CAAC;CAChC,CAAC,CAAC;AAEH,mFAAmF;AACnF,MAAM,UAAU,YAAY,CAAC,EAAU;IACrC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,SAAS,GAAG,mBAAmB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,0BAA0B,EAAE,yBAAyB,SAAS,EAAE,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,yCAAyC;AACzC,MAAM,UAAU,mBAAmB;IACjC,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON output formatter — reproduces current default behavior.
|
|
3
|
+
*/
|
|
4
|
+
import type { ScanResults } from '../types.js';
|
|
5
|
+
import type { OutputFormatter } from './types.js';
|
|
6
|
+
export declare class JsonFormatter implements OutputFormatter {
|
|
7
|
+
readonly id = "json";
|
|
8
|
+
readonly fileExtension = ".json";
|
|
9
|
+
format(results: ScanResults): string;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=json-formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-formatter.d.ts","sourceRoot":"","sources":["../../src/formatters/json-formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,qBAAa,aAAc,YAAW,eAAe;IACnD,QAAQ,CAAC,EAAE,UAAU;IACrB,QAAQ,CAAC,aAAa,WAAW;IAEjC,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;CAGrC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON output formatter — reproduces current default behavior.
|
|
3
|
+
*/
|
|
4
|
+
export class JsonFormatter {
|
|
5
|
+
id = 'json';
|
|
6
|
+
fileExtension = '.json';
|
|
7
|
+
format(results) {
|
|
8
|
+
return JSON.stringify(results, null, 2);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=json-formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-formatter.js","sourceRoot":"","sources":["../../src/formatters/json-formatter.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,OAAO,aAAa;IACf,EAAE,GAAG,MAAM,CAAC;IACZ,aAAa,GAAG,OAAO,CAAC;IAEjC,MAAM,CAAC,OAAoB;QACzB,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1C,CAAC;CACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SARIF 2.1.0 output formatter.
|
|
3
|
+
* Maps ScanResults to the SARIF schema for integration with
|
|
4
|
+
* code scanning UIs (e.g. GitHub Code Scanning) and SARIF viewers.
|
|
5
|
+
*/
|
|
6
|
+
import type { ScanResults } from '../types.js';
|
|
7
|
+
import type { OutputFormatter } from './types.js';
|
|
8
|
+
/** Maps aghast severity to SARIF result level. */
|
|
9
|
+
export declare function mapSeverityToLevel(severity: string | undefined): 'error' | 'warning' | 'note';
|
|
10
|
+
export declare class SarifFormatter implements OutputFormatter {
|
|
11
|
+
readonly id = "sarif";
|
|
12
|
+
readonly fileExtension = ".sarif";
|
|
13
|
+
format(results: ScanResults): string;
|
|
14
|
+
private buildRules;
|
|
15
|
+
private buildResults;
|
|
16
|
+
private buildCodeFlow;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=sarif-formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sarif-formatter.d.ts","sourceRoot":"","sources":["../../src/formatters/sarif-formatter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAA+B,MAAM,aAAa,CAAC;AAC5E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,kDAAkD;AAClD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAY7F;AA0DD,qBAAa,cAAe,YAAW,eAAe;IACpD,QAAQ,CAAC,EAAE,WAAW;IACtB,QAAQ,CAAC,aAAa,YAAY;IAElC,MAAM,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;IAwBpC,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,YAAY;IAgCpB,OAAO,CAAC,aAAa;CAiBtB"}
|