guardlink 1.0.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.
- package/CHANGELOG.md +30 -0
- package/LICENSE +21 -0
- package/README.md +344 -0
- package/dist/agents/config.d.ts +46 -0
- package/dist/agents/config.d.ts.map +1 -0
- package/dist/agents/config.js +189 -0
- package/dist/agents/config.js.map +1 -0
- package/dist/agents/index.d.ts +24 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +42 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/agents/launcher.d.ts +54 -0
- package/dist/agents/launcher.d.ts.map +1 -0
- package/dist/agents/launcher.js +152 -0
- package/dist/agents/launcher.js.map +1 -0
- package/dist/agents/prompts.d.ts +14 -0
- package/dist/agents/prompts.d.ts.map +1 -0
- package/dist/agents/prompts.js +120 -0
- package/dist/agents/prompts.js.map +1 -0
- package/dist/analyze/index.d.ts +80 -0
- package/dist/analyze/index.d.ts.map +1 -0
- package/dist/analyze/index.js +306 -0
- package/dist/analyze/index.js.map +1 -0
- package/dist/analyze/llm.d.ts +52 -0
- package/dist/analyze/llm.d.ts.map +1 -0
- package/dist/analyze/llm.js +295 -0
- package/dist/analyze/llm.js.map +1 -0
- package/dist/analyze/prompts.d.ts +14 -0
- package/dist/analyze/prompts.d.ts.map +1 -0
- package/dist/analyze/prompts.js +205 -0
- package/dist/analyze/prompts.js.map +1 -0
- package/dist/analyzer/index.d.ts +5 -0
- package/dist/analyzer/index.d.ts.map +1 -0
- package/dist/analyzer/index.js +5 -0
- package/dist/analyzer/index.js.map +1 -0
- package/dist/analyzer/sarif.d.ts +84 -0
- package/dist/analyzer/sarif.d.ts.map +1 -0
- package/dist/analyzer/sarif.js +149 -0
- package/dist/analyzer/sarif.js.map +1 -0
- package/dist/cli/index.d.ts +25 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +821 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/dashboard/data.d.ts +52 -0
- package/dist/dashboard/data.d.ts.map +1 -0
- package/dist/dashboard/data.js +93 -0
- package/dist/dashboard/data.js.map +1 -0
- package/dist/dashboard/diagrams.d.ts +25 -0
- package/dist/dashboard/diagrams.d.ts.map +1 -0
- package/dist/dashboard/diagrams.js +243 -0
- package/dist/dashboard/diagrams.js.map +1 -0
- package/dist/dashboard/generate.d.ts +17 -0
- package/dist/dashboard/generate.d.ts.map +1 -0
- package/dist/dashboard/generate.js +1258 -0
- package/dist/dashboard/generate.js.map +1 -0
- package/dist/dashboard/index.d.ts +7 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +7 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/diff/engine.d.ts +51 -0
- package/dist/diff/engine.d.ts.map +1 -0
- package/dist/diff/engine.js +153 -0
- package/dist/diff/engine.js.map +1 -0
- package/dist/diff/format.d.ts +10 -0
- package/dist/diff/format.d.ts.map +1 -0
- package/dist/diff/format.js +111 -0
- package/dist/diff/format.js.map +1 -0
- package/dist/diff/git.d.ts +24 -0
- package/dist/diff/git.d.ts.map +1 -0
- package/dist/diff/git.js +85 -0
- package/dist/diff/git.js.map +1 -0
- package/dist/diff/index.d.ts +7 -0
- package/dist/diff/index.d.ts.map +1 -0
- package/dist/diff/index.js +7 -0
- package/dist/diff/index.js.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/init/detect.d.ts +42 -0
- package/dist/init/detect.d.ts.map +1 -0
- package/dist/init/detect.js +185 -0
- package/dist/init/detect.js.map +1 -0
- package/dist/init/index.d.ts +39 -0
- package/dist/init/index.d.ts.map +1 -0
- package/dist/init/index.js +228 -0
- package/dist/init/index.js.map +1 -0
- package/dist/init/picker.d.ts +32 -0
- package/dist/init/picker.d.ts.map +1 -0
- package/dist/init/picker.js +105 -0
- package/dist/init/picker.js.map +1 -0
- package/dist/init/templates.d.ts +25 -0
- package/dist/init/templates.d.ts.map +1 -0
- package/dist/init/templates.js +263 -0
- package/dist/init/templates.js.map +1 -0
- package/dist/mcp/index.d.ts +12 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +18 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/lookup.d.ts +27 -0
- package/dist/mcp/lookup.d.ts.map +1 -0
- package/dist/mcp/lookup.js +282 -0
- package/dist/mcp/lookup.js.map +1 -0
- package/dist/mcp/server.d.ts +41 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +388 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/suggest.d.ts +35 -0
- package/dist/mcp/suggest.d.ts.map +1 -0
- package/dist/mcp/suggest.js +268 -0
- package/dist/mcp/suggest.js.map +1 -0
- package/dist/parser/comment-strip.d.ts +15 -0
- package/dist/parser/comment-strip.d.ts.map +1 -0
- package/dist/parser/comment-strip.js +76 -0
- package/dist/parser/comment-strip.js.map +1 -0
- package/dist/parser/index.d.ts +10 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +9 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/normalize.d.ts +22 -0
- package/dist/parser/normalize.d.ts.map +1 -0
- package/dist/parser/normalize.js +42 -0
- package/dist/parser/normalize.js.map +1 -0
- package/dist/parser/parse-file.d.ts +18 -0
- package/dist/parser/parse-file.d.ts.map +1 -0
- package/dist/parser/parse-file.js +68 -0
- package/dist/parser/parse-file.js.map +1 -0
- package/dist/parser/parse-line.d.ts +21 -0
- package/dist/parser/parse-line.d.ts.map +1 -0
- package/dist/parser/parse-line.js +230 -0
- package/dist/parser/parse-line.js.map +1 -0
- package/dist/parser/parse-project.d.ts +31 -0
- package/dist/parser/parse-project.d.ts.map +1 -0
- package/dist/parser/parse-project.js +281 -0
- package/dist/parser/parse-project.js.map +1 -0
- package/dist/report/index.d.ts +6 -0
- package/dist/report/index.d.ts.map +1 -0
- package/dist/report/index.js +6 -0
- package/dist/report/index.js.map +1 -0
- package/dist/report/mermaid.d.ts +15 -0
- package/dist/report/mermaid.d.ts.map +1 -0
- package/dist/report/mermaid.js +260 -0
- package/dist/report/mermaid.js.map +1 -0
- package/dist/report/report.d.ts +16 -0
- package/dist/report/report.d.ts.map +1 -0
- package/dist/report/report.js +211 -0
- package/dist/report/report.js.map +1 -0
- package/dist/tui/commands.d.ts +42 -0
- package/dist/tui/commands.d.ts.map +1 -0
- package/dist/tui/commands.js +1216 -0
- package/dist/tui/commands.js.map +1 -0
- package/dist/tui/config.d.ts +27 -0
- package/dist/tui/config.d.ts.map +1 -0
- package/dist/tui/config.js +27 -0
- package/dist/tui/config.js.map +1 -0
- package/dist/tui/format.d.ts +63 -0
- package/dist/tui/format.d.ts.map +1 -0
- package/dist/tui/format.js +253 -0
- package/dist/tui/format.js.map +1 -0
- package/dist/tui/index.d.ts +18 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +470 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/input.d.ts +63 -0
- package/dist/tui/input.d.ts.map +1 -0
- package/dist/tui/input.js +454 -0
- package/dist/tui/input.js.map +1 -0
- package/dist/types/index.d.ts +254 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +97 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardLink Threat Reports — Lightweight LLM client using raw fetch.
|
|
3
|
+
*
|
|
4
|
+
* Supports:
|
|
5
|
+
* - Anthropic Messages API (claude-sonnet-4-5-20250929, etc.)
|
|
6
|
+
* - OpenAI-compatible Chat Completions (GPT-4o, DeepSeek, OpenRouter)
|
|
7
|
+
*
|
|
8
|
+
* Zero dependencies — uses Node 20+ built-in fetch.
|
|
9
|
+
*
|
|
10
|
+
* @exposes #llm-client to #api-key-exposure [high] cwe:CWE-798 -- "Reads API keys from environment variables"
|
|
11
|
+
* @exposes #llm-client to #ssrf [medium] cwe:CWE-918 -- "Makes HTTP requests to configurable provider URLs"
|
|
12
|
+
* @exposes #llm-client to #prompt-injection [medium] cwe:CWE-77 -- "Sends threat model content as LLM prompt"
|
|
13
|
+
* @accepts #prompt-injection on #llm-client -- "Core feature: threat model data is sent to LLM for analysis"
|
|
14
|
+
* @mitigates #llm-client against #ssrf using #config-validation -- "BASE_URLS are hardcoded to known providers"
|
|
15
|
+
* @mitigates #llm-client against #api-key-exposure using #key-redaction -- "Keys read from env, not logged"
|
|
16
|
+
* @handles secrets on #llm-client -- "API keys held in memory during request lifecycle"
|
|
17
|
+
* @boundary between #llm-client and External_LLM_APIs (#llm-boundary) -- "HTTP requests cross network trust boundary to external AI providers"
|
|
18
|
+
* @flows #llm-client -> External_LLM_APIs via fetch -- "HTTP POST with auth headers and prompt payload"
|
|
19
|
+
* @flows External_LLM_APIs -> #llm-client via response -- "Streaming or complete response from LLM provider"
|
|
20
|
+
*/
|
|
21
|
+
const DEFAULT_MODELS = {
|
|
22
|
+
anthropic: 'claude-sonnet-4-5-20250929',
|
|
23
|
+
openai: 'gpt-4o',
|
|
24
|
+
openrouter: 'anthropic/claude-sonnet-4-5-20250929',
|
|
25
|
+
deepseek: 'deepseek-chat',
|
|
26
|
+
};
|
|
27
|
+
const BASE_URLS = {
|
|
28
|
+
anthropic: 'https://api.anthropic.com',
|
|
29
|
+
openai: 'https://api.openai.com',
|
|
30
|
+
openrouter: 'https://openrouter.ai/api',
|
|
31
|
+
deepseek: 'https://api.deepseek.com',
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Auto-detect provider from environment variables.
|
|
35
|
+
* Returns null if no API key found.
|
|
36
|
+
*/
|
|
37
|
+
export function autoDetectConfig() {
|
|
38
|
+
// Priority: Anthropic > OpenAI > OpenRouter > DeepSeek
|
|
39
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
40
|
+
return {
|
|
41
|
+
provider: 'anthropic',
|
|
42
|
+
model: DEFAULT_MODELS.anthropic,
|
|
43
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (process.env.OPENAI_API_KEY) {
|
|
47
|
+
return {
|
|
48
|
+
provider: 'openai',
|
|
49
|
+
model: DEFAULT_MODELS.openai,
|
|
50
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (process.env.OPENROUTER_API_KEY) {
|
|
54
|
+
return {
|
|
55
|
+
provider: 'openrouter',
|
|
56
|
+
model: DEFAULT_MODELS.openrouter,
|
|
57
|
+
apiKey: process.env.OPENROUTER_API_KEY,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (process.env.DEEPSEEK_API_KEY) {
|
|
61
|
+
return {
|
|
62
|
+
provider: 'deepseek',
|
|
63
|
+
model: DEFAULT_MODELS.deepseek,
|
|
64
|
+
apiKey: process.env.DEEPSEEK_API_KEY,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Build config from explicit flags + env vars.
|
|
71
|
+
*/
|
|
72
|
+
export function buildConfig(opts) {
|
|
73
|
+
// If provider specified, use it
|
|
74
|
+
if (opts.provider) {
|
|
75
|
+
const provider = opts.provider;
|
|
76
|
+
const envKeyMap = {
|
|
77
|
+
anthropic: 'ANTHROPIC_API_KEY',
|
|
78
|
+
openai: 'OPENAI_API_KEY',
|
|
79
|
+
openrouter: 'OPENROUTER_API_KEY',
|
|
80
|
+
deepseek: 'DEEPSEEK_API_KEY',
|
|
81
|
+
};
|
|
82
|
+
const apiKey = opts.apiKey || process.env[envKeyMap[provider] || ''];
|
|
83
|
+
if (!apiKey)
|
|
84
|
+
return null;
|
|
85
|
+
return {
|
|
86
|
+
provider,
|
|
87
|
+
model: opts.model || DEFAULT_MODELS[provider] || 'gpt-4o',
|
|
88
|
+
apiKey,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// Auto-detect
|
|
92
|
+
const config = autoDetectConfig();
|
|
93
|
+
if (!config)
|
|
94
|
+
return null;
|
|
95
|
+
// Override model if specified
|
|
96
|
+
if (opts.model)
|
|
97
|
+
config.model = opts.model;
|
|
98
|
+
return config;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Send a message to the LLM and return the response.
|
|
102
|
+
*/
|
|
103
|
+
export async function chatCompletion(config, systemPrompt, userMessage, onChunk) {
|
|
104
|
+
if (config.provider === 'anthropic') {
|
|
105
|
+
return callAnthropic(config, systemPrompt, userMessage, onChunk);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
return callOpenAICompatible(config, systemPrompt, userMessage, onChunk);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// ─── Anthropic Messages API ──────────────────────────────────────────
|
|
112
|
+
async function callAnthropic(config, systemPrompt, userMessage, onChunk) {
|
|
113
|
+
const baseUrl = config.baseUrl || BASE_URLS.anthropic;
|
|
114
|
+
const maxTokens = config.maxTokens || 8192;
|
|
115
|
+
if (onChunk) {
|
|
116
|
+
// Streaming
|
|
117
|
+
const res = await fetch(`${baseUrl}/v1/messages`, {
|
|
118
|
+
method: 'POST',
|
|
119
|
+
headers: {
|
|
120
|
+
'Content-Type': 'application/json',
|
|
121
|
+
'x-api-key': config.apiKey,
|
|
122
|
+
'anthropic-version': '2023-06-01',
|
|
123
|
+
},
|
|
124
|
+
body: JSON.stringify({
|
|
125
|
+
model: config.model,
|
|
126
|
+
max_tokens: maxTokens,
|
|
127
|
+
system: systemPrompt,
|
|
128
|
+
stream: true,
|
|
129
|
+
messages: [{ role: 'user', content: userMessage }],
|
|
130
|
+
}),
|
|
131
|
+
});
|
|
132
|
+
if (!res.ok) {
|
|
133
|
+
const err = await res.text();
|
|
134
|
+
throw new Error(`Anthropic API error ${res.status}: ${err}`);
|
|
135
|
+
}
|
|
136
|
+
let content = '';
|
|
137
|
+
let inputTokens = 0;
|
|
138
|
+
let outputTokens = 0;
|
|
139
|
+
const reader = res.body?.getReader();
|
|
140
|
+
if (!reader)
|
|
141
|
+
throw new Error('No response body');
|
|
142
|
+
const decoder = new TextDecoder();
|
|
143
|
+
let buffer = '';
|
|
144
|
+
while (true) {
|
|
145
|
+
const { done, value } = await reader.read();
|
|
146
|
+
if (done)
|
|
147
|
+
break;
|
|
148
|
+
buffer += decoder.decode(value, { stream: true });
|
|
149
|
+
const lines = buffer.split('\n');
|
|
150
|
+
buffer = lines.pop() || '';
|
|
151
|
+
for (const line of lines) {
|
|
152
|
+
if (!line.startsWith('data: '))
|
|
153
|
+
continue;
|
|
154
|
+
const data = line.slice(6).trim();
|
|
155
|
+
if (data === '[DONE]')
|
|
156
|
+
continue;
|
|
157
|
+
try {
|
|
158
|
+
const event = JSON.parse(data);
|
|
159
|
+
if (event.type === 'content_block_delta' && event.delta?.text) {
|
|
160
|
+
content += event.delta.text;
|
|
161
|
+
onChunk(event.delta.text);
|
|
162
|
+
}
|
|
163
|
+
if (event.type === 'message_delta' && event.usage) {
|
|
164
|
+
outputTokens = event.usage.output_tokens || 0;
|
|
165
|
+
}
|
|
166
|
+
if (event.type === 'message_start' && event.message?.usage) {
|
|
167
|
+
inputTokens = event.message.usage.input_tokens || 0;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
catch { /* skip non-JSON lines */ }
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return { content, model: config.model, inputTokens, outputTokens };
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
// Non-streaming
|
|
177
|
+
const res = await fetch(`${baseUrl}/v1/messages`, {
|
|
178
|
+
method: 'POST',
|
|
179
|
+
headers: {
|
|
180
|
+
'Content-Type': 'application/json',
|
|
181
|
+
'x-api-key': config.apiKey,
|
|
182
|
+
'anthropic-version': '2023-06-01',
|
|
183
|
+
},
|
|
184
|
+
body: JSON.stringify({
|
|
185
|
+
model: config.model,
|
|
186
|
+
max_tokens: maxTokens,
|
|
187
|
+
system: systemPrompt,
|
|
188
|
+
messages: [{ role: 'user', content: userMessage }],
|
|
189
|
+
}),
|
|
190
|
+
});
|
|
191
|
+
if (!res.ok) {
|
|
192
|
+
const err = await res.text();
|
|
193
|
+
throw new Error(`Anthropic API error ${res.status}: ${err}`);
|
|
194
|
+
}
|
|
195
|
+
const data = await res.json();
|
|
196
|
+
return {
|
|
197
|
+
content: data.content?.[0]?.text || '',
|
|
198
|
+
model: data.model || config.model,
|
|
199
|
+
inputTokens: data.usage?.input_tokens,
|
|
200
|
+
outputTokens: data.usage?.output_tokens,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// ─── OpenAI-compatible Chat Completions ──────────────────────────────
|
|
205
|
+
async function callOpenAICompatible(config, systemPrompt, userMessage, onChunk) {
|
|
206
|
+
const baseUrl = config.baseUrl || BASE_URLS[config.provider] || BASE_URLS.openai;
|
|
207
|
+
const maxTokens = config.maxTokens || 8192;
|
|
208
|
+
const headers = {
|
|
209
|
+
'Content-Type': 'application/json',
|
|
210
|
+
'Authorization': `Bearer ${config.apiKey}`,
|
|
211
|
+
};
|
|
212
|
+
// OpenRouter requires extra headers
|
|
213
|
+
if (config.provider === 'openrouter') {
|
|
214
|
+
headers['HTTP-Referer'] = 'https://guardlink.bugb.io';
|
|
215
|
+
headers['X-Title'] = 'GuardLink CLI';
|
|
216
|
+
}
|
|
217
|
+
if (onChunk) {
|
|
218
|
+
// Streaming
|
|
219
|
+
const res = await fetch(`${baseUrl}/v1/chat/completions`, {
|
|
220
|
+
method: 'POST',
|
|
221
|
+
headers,
|
|
222
|
+
body: JSON.stringify({
|
|
223
|
+
model: config.model,
|
|
224
|
+
max_tokens: maxTokens,
|
|
225
|
+
stream: true,
|
|
226
|
+
messages: [
|
|
227
|
+
{ role: 'system', content: systemPrompt },
|
|
228
|
+
{ role: 'user', content: userMessage },
|
|
229
|
+
],
|
|
230
|
+
}),
|
|
231
|
+
});
|
|
232
|
+
if (!res.ok) {
|
|
233
|
+
const err = await res.text();
|
|
234
|
+
throw new Error(`${config.provider} API error ${res.status}: ${err}`);
|
|
235
|
+
}
|
|
236
|
+
let content = '';
|
|
237
|
+
const reader = res.body?.getReader();
|
|
238
|
+
if (!reader)
|
|
239
|
+
throw new Error('No response body');
|
|
240
|
+
const decoder = new TextDecoder();
|
|
241
|
+
let buffer = '';
|
|
242
|
+
while (true) {
|
|
243
|
+
const { done, value } = await reader.read();
|
|
244
|
+
if (done)
|
|
245
|
+
break;
|
|
246
|
+
buffer += decoder.decode(value, { stream: true });
|
|
247
|
+
const lines = buffer.split('\n');
|
|
248
|
+
buffer = lines.pop() || '';
|
|
249
|
+
for (const line of lines) {
|
|
250
|
+
if (!line.startsWith('data: '))
|
|
251
|
+
continue;
|
|
252
|
+
const data = line.slice(6).trim();
|
|
253
|
+
if (data === '[DONE]')
|
|
254
|
+
continue;
|
|
255
|
+
try {
|
|
256
|
+
const event = JSON.parse(data);
|
|
257
|
+
const delta = event.choices?.[0]?.delta?.content;
|
|
258
|
+
if (delta) {
|
|
259
|
+
content += delta;
|
|
260
|
+
onChunk(delta);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
catch { /* skip */ }
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return { content, model: config.model };
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
// Non-streaming
|
|
270
|
+
const res = await fetch(`${baseUrl}/v1/chat/completions`, {
|
|
271
|
+
method: 'POST',
|
|
272
|
+
headers,
|
|
273
|
+
body: JSON.stringify({
|
|
274
|
+
model: config.model,
|
|
275
|
+
max_tokens: maxTokens,
|
|
276
|
+
messages: [
|
|
277
|
+
{ role: 'system', content: systemPrompt },
|
|
278
|
+
{ role: 'user', content: userMessage },
|
|
279
|
+
],
|
|
280
|
+
}),
|
|
281
|
+
});
|
|
282
|
+
if (!res.ok) {
|
|
283
|
+
const err = await res.text();
|
|
284
|
+
throw new Error(`${config.provider} API error ${res.status}: ${err}`);
|
|
285
|
+
}
|
|
286
|
+
const data = await res.json();
|
|
287
|
+
return {
|
|
288
|
+
content: data.choices?.[0]?.message?.content || '',
|
|
289
|
+
model: data.model || config.model,
|
|
290
|
+
inputTokens: data.usage?.prompt_tokens,
|
|
291
|
+
outputTokens: data.usage?.completion_tokens,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=llm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm.js","sourceRoot":"","sources":["../../src/analyze/llm.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardLink Threat Reports — Framework-specific analysis prompts.
|
|
3
|
+
*
|
|
4
|
+
* Each framework produces a structured security analysis from the
|
|
5
|
+
* serialized threat model. The LLM acts as a senior security architect.
|
|
6
|
+
*/
|
|
7
|
+
export type AnalysisFramework = 'stride' | 'dread' | 'pasta' | 'attacker' | 'rapid' | 'general';
|
|
8
|
+
export declare const FRAMEWORK_LABELS: Record<AnalysisFramework, string>;
|
|
9
|
+
export declare const FRAMEWORK_PROMPTS: Record<AnalysisFramework, string>;
|
|
10
|
+
/**
|
|
11
|
+
* Build the user message containing the serialized threat model.
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildUserMessage(modelJson: string, framework: AnalysisFramework, customPrompt?: string): string;
|
|
14
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/analyze/prompts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;AAEhG,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAO9D,CAAC;AAkBF,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAsK/D,CAAC;AAEF;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAU/G"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardLink Threat Reports — Framework-specific analysis prompts.
|
|
3
|
+
*
|
|
4
|
+
* Each framework produces a structured security analysis from the
|
|
5
|
+
* serialized threat model. The LLM acts as a senior security architect.
|
|
6
|
+
*/
|
|
7
|
+
export const FRAMEWORK_LABELS = {
|
|
8
|
+
stride: 'STRIDE Threat Analysis',
|
|
9
|
+
dread: 'DREAD Risk Assessment',
|
|
10
|
+
pasta: 'PASTA Attack Simulation',
|
|
11
|
+
attacker: 'Attacker Persona Analysis',
|
|
12
|
+
rapid: 'Rapid Risk Assessment',
|
|
13
|
+
general: 'General Threat Analysis',
|
|
14
|
+
};
|
|
15
|
+
const SYSTEM_BASE = `You are an expert Security Architect and Threat Modeler with 15+ years of experience.
|
|
16
|
+
You are analyzing a codebase that uses GuardLink annotations — structured security metadata embedded in source code comments.
|
|
17
|
+
|
|
18
|
+
The threat model you receive contains:
|
|
19
|
+
- **Assets**: Components declared by developers
|
|
20
|
+
- **Threats**: Known threat vectors with severity and CWE references
|
|
21
|
+
- **Controls**: Security mechanisms in place
|
|
22
|
+
- **Mitigations**: Where controls defend assets against threats
|
|
23
|
+
- **Exposures**: Known vulnerabilities (asset exposed to threat)
|
|
24
|
+
- **Flows**: Data movement between components
|
|
25
|
+
- **Boundaries**: Trust boundaries between security zones
|
|
26
|
+
- **Comments**: Developer security notes
|
|
27
|
+
|
|
28
|
+
Your analysis must be actionable, specific to THIS codebase, and reference the actual assets/threats/controls by name.
|
|
29
|
+
Never give generic advice — always tie recommendations to concrete annotations in the model.`;
|
|
30
|
+
export const FRAMEWORK_PROMPTS = {
|
|
31
|
+
stride: `${SYSTEM_BASE}
|
|
32
|
+
|
|
33
|
+
Perform a **STRIDE** analysis of this threat model.
|
|
34
|
+
|
|
35
|
+
For each STRIDE category, evaluate the codebase:
|
|
36
|
+
|
|
37
|
+
## S — Spoofing
|
|
38
|
+
Identify where authentication can be bypassed. Check: are all assets with @exposes to auth-related threats properly mitigated?
|
|
39
|
+
|
|
40
|
+
## T — Tampering
|
|
41
|
+
Identify where data integrity is at risk. Check: @flows without integrity controls, @handles with sensitive data lacking validation.
|
|
42
|
+
|
|
43
|
+
## R — Repudiation
|
|
44
|
+
Identify where actions cannot be traced. Check: are there @audit annotations? Are critical operations logged?
|
|
45
|
+
|
|
46
|
+
## I — Information Disclosure
|
|
47
|
+
Identify where sensitive data leaks. Check: @exposes to info-disclosure/data-exposure threats, @handles pii/phi/secrets without encryption.
|
|
48
|
+
|
|
49
|
+
## D — Denial of Service
|
|
50
|
+
Identify resource exhaustion risks. Check: @exposes to dos threats, rate limiting controls, boundary protections.
|
|
51
|
+
|
|
52
|
+
## E — Elevation of Privilege
|
|
53
|
+
Identify privilege escalation paths. Check: @exposes to bac/idor threats, @boundary gaps, missing authorization controls.
|
|
54
|
+
|
|
55
|
+
For each category:
|
|
56
|
+
1. List specific findings referencing actual assets and threats from the model
|
|
57
|
+
2. Rate severity (Critical/High/Medium/Low)
|
|
58
|
+
3. Recommend specific mitigations referencing existing controls or suggesting new ones
|
|
59
|
+
4. Identify gaps — what SHOULD be annotated but isn't?
|
|
60
|
+
|
|
61
|
+
End with an Executive Summary and Priority Action Items.`,
|
|
62
|
+
dread: `${SYSTEM_BASE}
|
|
63
|
+
|
|
64
|
+
Perform a **DREAD** risk scoring analysis of this threat model.
|
|
65
|
+
|
|
66
|
+
For each unmitigated exposure and significant threat, calculate a DREAD score:
|
|
67
|
+
|
|
68
|
+
- **D — Damage Potential** (0-10): How bad if exploited?
|
|
69
|
+
- **R — Reproducibility** (0-10): How easy to reproduce?
|
|
70
|
+
- **E — Exploitability** (0-10): How easy to launch the attack?
|
|
71
|
+
- **A — Affected Users** (0-10): How many users impacted?
|
|
72
|
+
- **D — Discoverability** (0-10): How easy to find the vulnerability?
|
|
73
|
+
|
|
74
|
+
Present results as a ranked table:
|
|
75
|
+
|
|
76
|
+
| Threat | Asset | D | R | E | A | D | Total | Risk Level |
|
|
77
|
+
|--------|-------|---|---|---|---|---|-------|------------|
|
|
78
|
+
|
|
79
|
+
Then provide:
|
|
80
|
+
1. Top 5 risks by DREAD score with detailed justification
|
|
81
|
+
2. Quick wins — high-score items with easy mitigations
|
|
82
|
+
3. Systemic risks — patterns across multiple exposures
|
|
83
|
+
4. Recommended priority order for remediation`,
|
|
84
|
+
pasta: `${SYSTEM_BASE}
|
|
85
|
+
|
|
86
|
+
Perform a **PASTA** (Process for Attack Simulation and Threat Analysis) assessment.
|
|
87
|
+
|
|
88
|
+
Work through all 7 PASTA stages:
|
|
89
|
+
|
|
90
|
+
### Stage 1: Define Objectives
|
|
91
|
+
What are the business-critical assets? Which @asset declarations represent the crown jewels?
|
|
92
|
+
|
|
93
|
+
### Stage 2: Define Technical Scope
|
|
94
|
+
Map the attack surface from @flows, @boundary, and @handles annotations. What are the entry points?
|
|
95
|
+
|
|
96
|
+
### Stage 3: Application Decomposition
|
|
97
|
+
Analyze component relationships from flows and boundaries. Identify trust zones and data paths.
|
|
98
|
+
|
|
99
|
+
### Stage 4: Threat Analysis
|
|
100
|
+
Map declared @threat annotations to real-world attack techniques. Reference CWE/CAPEC where available.
|
|
101
|
+
|
|
102
|
+
### Stage 5: Vulnerability Analysis
|
|
103
|
+
Evaluate each @exposes annotation. Which are most exploitable given the technical context?
|
|
104
|
+
|
|
105
|
+
### Stage 6: Attack Simulation
|
|
106
|
+
For the top 3 most critical exposures, describe a realistic attack scenario step-by-step.
|
|
107
|
+
|
|
108
|
+
### Stage 7: Risk & Impact Analysis
|
|
109
|
+
Prioritized risk matrix with business impact assessment.
|
|
110
|
+
|
|
111
|
+
End with concrete remediation recommendations tied to specific annotations.`,
|
|
112
|
+
attacker: `${SYSTEM_BASE}
|
|
113
|
+
|
|
114
|
+
Perform an **Attacker Persona** analysis of this threat model.
|
|
115
|
+
|
|
116
|
+
Adopt the mindset of different attacker types and evaluate the codebase:
|
|
117
|
+
|
|
118
|
+
### 1. Script Kiddie (Low Skill)
|
|
119
|
+
What can be exploited with publicly available tools? Which @exposes have known CVEs (check cwe: refs)?
|
|
120
|
+
|
|
121
|
+
### 2. Opportunistic Attacker (Medium Skill)
|
|
122
|
+
What attack chains are possible? Can multiple exposures be combined? Check @flows for lateral movement paths.
|
|
123
|
+
|
|
124
|
+
### 3. Targeted Attacker (High Skill)
|
|
125
|
+
What are the high-value targets (@handles pii/phi/financial/secrets)? What's the path from @boundary entry points to crown jewel assets?
|
|
126
|
+
|
|
127
|
+
### 4. Insider Threat
|
|
128
|
+
Which @assumes annotations represent blind spots? Where does the model trust internal components without verification?
|
|
129
|
+
|
|
130
|
+
For each persona:
|
|
131
|
+
1. Most likely attack vector (reference specific annotations)
|
|
132
|
+
2. Attack path (chain of assets/flows/boundaries)
|
|
133
|
+
3. Impact if successful
|
|
134
|
+
4. Current defenses (existing @mitigates)
|
|
135
|
+
5. Gaps in defense
|
|
136
|
+
|
|
137
|
+
End with a prioritized defense improvement plan.`,
|
|
138
|
+
rapid: `${SYSTEM_BASE}
|
|
139
|
+
|
|
140
|
+
Perform a **Rapid Risk Assessment** — concise, actionable, focused on the highest-impact items.
|
|
141
|
+
|
|
142
|
+
### Critical Findings (Stop Everything)
|
|
143
|
+
List any P0/critical @exposes without @mitigates. These are active vulnerabilities.
|
|
144
|
+
|
|
145
|
+
### High-Priority Gaps
|
|
146
|
+
- Unmitigated exposures by severity
|
|
147
|
+
- @assumes that could be violated
|
|
148
|
+
- @boundary without proper controls on crossing flows
|
|
149
|
+
|
|
150
|
+
### Coverage Assessment
|
|
151
|
+
- What percentage of assets have threat coverage?
|
|
152
|
+
- Which components have @flows but no security annotations?
|
|
153
|
+
- Are there @handles (sensitive data) without corresponding @mitigates?
|
|
154
|
+
|
|
155
|
+
### Top 5 Recommendations
|
|
156
|
+
Numbered, actionable, with specific annotation suggestions (exact @mitigates lines to add).
|
|
157
|
+
|
|
158
|
+
### Risk Score
|
|
159
|
+
Rate overall security posture: A (excellent) through F (critical risk). Justify with data from the model.
|
|
160
|
+
|
|
161
|
+
Keep the entire analysis under 500 lines. Be direct — no filler.`,
|
|
162
|
+
general: `${SYSTEM_BASE}
|
|
163
|
+
|
|
164
|
+
Perform a comprehensive threat analysis of this codebase.
|
|
165
|
+
|
|
166
|
+
### Executive Summary
|
|
167
|
+
2-3 sentence overall assessment.
|
|
168
|
+
|
|
169
|
+
### Threat Landscape
|
|
170
|
+
What threats does this application face? Map @threat declarations to real-world attack patterns.
|
|
171
|
+
|
|
172
|
+
### Security Posture
|
|
173
|
+
- Strengths: well-mitigated areas, good control coverage
|
|
174
|
+
- Weaknesses: unmitigated exposures, missing controls
|
|
175
|
+
- Blind spots: areas with no annotations at all
|
|
176
|
+
|
|
177
|
+
### Data Flow Analysis
|
|
178
|
+
Trace sensitive data through @flows and @boundary annotations. Where does data cross trust boundaries without protection?
|
|
179
|
+
|
|
180
|
+
### Missing Annotations
|
|
181
|
+
Based on the architecture visible in @flows and @boundary, what security annotations are likely missing?
|
|
182
|
+
|
|
183
|
+
### Recommendations
|
|
184
|
+
Prioritized list with:
|
|
185
|
+
1. What to fix (specific exposure)
|
|
186
|
+
2. How to fix it (specific control/mitigation)
|
|
187
|
+
3. What annotation to add (exact syntax)
|
|
188
|
+
|
|
189
|
+
### Compliance Considerations
|
|
190
|
+
Based on @handles classifications (pii, phi, financial), note relevant compliance requirements (GDPR, HIPAA, PCI-DSS).`,
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* Build the user message containing the serialized threat model.
|
|
194
|
+
*/
|
|
195
|
+
export function buildUserMessage(modelJson, framework, customPrompt) {
|
|
196
|
+
const header = customPrompt
|
|
197
|
+
? `Analyze this threat model. ${customPrompt}`
|
|
198
|
+
: `Produce a ${FRAMEWORK_LABELS[framework]} for this threat model.`;
|
|
199
|
+
return `${header}
|
|
200
|
+
|
|
201
|
+
<threat_model>
|
|
202
|
+
${modelJson}
|
|
203
|
+
</threat_model>`;
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/analyze/prompts.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,CAAC,MAAM,gBAAgB,GAAsC;IACjE,MAAM,EAAE,wBAAwB;IAChC,KAAK,EAAE,uBAAuB;IAC9B,KAAK,EAAE,yBAAyB;IAChC,QAAQ,EAAE,2BAA2B;IACrC,KAAK,EAAE,uBAAuB;IAC9B,OAAO,EAAE,yBAAyB;CACnC,CAAC;AAEF,MAAM,WAAW,GAAG;;;;;;;;;;;;;;6FAcyE,CAAC;AAE9F,MAAM,CAAC,MAAM,iBAAiB,GAAsC;IAClE,MAAM,EAAE,GAAG,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yDA8BiC;IAEvD,KAAK,EAAE,GAAG,WAAW;;;;;;;;;;;;;;;;;;;;;8CAqBuB;IAE5C,KAAK,EAAE,GAAG,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;4EA2BqD;IAE1E,QAAQ,EAAE,GAAG,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;iDAyBuB;IAE/C,KAAK,EAAE,GAAG,WAAW;;;;;;;;;;;;;;;;;;;;;;;iEAuB0C;IAE/D,OAAO,EAAE,GAAG,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;uHA4B8F;CACtH,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,SAA4B,EAAE,YAAqB;IACrG,MAAM,MAAM,GAAG,YAAY;QACzB,CAAC,CAAC,8BAA8B,YAAY,EAAE;QAC9C,CAAC,CAAC,aAAa,gBAAgB,CAAC,SAAS,CAAC,yBAAyB,CAAC;IAEtE,OAAO,GAAG,MAAM;;;EAGhB,SAAS;gBACK,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/analyzer/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAqB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GuardLink SARIF — Convert threat model findings to SARIF 2.1.0.
|
|
3
|
+
*
|
|
4
|
+
* SARIF (Static Analysis Results Interchange Format) is consumed by:
|
|
5
|
+
* - GitHub Advanced Security (code scanning alerts)
|
|
6
|
+
* - VS Code SARIF Viewer extension
|
|
7
|
+
* - Azure DevOps
|
|
8
|
+
* - SonarQube, Snyk, etc.
|
|
9
|
+
*
|
|
10
|
+
* We emit results for:
|
|
11
|
+
* 1. Unmitigated exposures (the primary security findings)
|
|
12
|
+
* 2. Parse errors (annotation syntax problems)
|
|
13
|
+
* 3. Dangling references (broken #id refs)
|
|
14
|
+
*
|
|
15
|
+
* @exposes #sarif to #info-disclosure [low] cwe:CWE-200 -- "SARIF output contains detailed threat model findings"
|
|
16
|
+
* @accepts #info-disclosure on #sarif -- "SARIF export for security tools is the intended feature"
|
|
17
|
+
* @exposes #sarif to #arbitrary-write [high] cwe:CWE-73 -- "SARIF written to user-specified output path"
|
|
18
|
+
* @mitigates #sarif against #arbitrary-write using #path-validation -- "CLI resolves output path before write"
|
|
19
|
+
* @flows #parser -> #sarif via ThreatModel -- "SARIF generator receives parsed threat model"
|
|
20
|
+
* @flows #sarif -> External_Security_Tools via SARIF_JSON -- "Output consumed by GitHub, VS Code, etc."
|
|
21
|
+
*/
|
|
22
|
+
import type { ThreatModel, ParseDiagnostic, Severity } from '../types/index.js';
|
|
23
|
+
interface SarifLog {
|
|
24
|
+
$schema: string;
|
|
25
|
+
version: '2.1.0';
|
|
26
|
+
runs: SarifRun[];
|
|
27
|
+
}
|
|
28
|
+
interface SarifRun {
|
|
29
|
+
tool: {
|
|
30
|
+
driver: {
|
|
31
|
+
name: string;
|
|
32
|
+
version: string;
|
|
33
|
+
informationUri: string;
|
|
34
|
+
rules: SarifRule[];
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
results: SarifResult[];
|
|
38
|
+
}
|
|
39
|
+
interface SarifRule {
|
|
40
|
+
id: string;
|
|
41
|
+
name: string;
|
|
42
|
+
shortDescription: {
|
|
43
|
+
text: string;
|
|
44
|
+
};
|
|
45
|
+
fullDescription?: {
|
|
46
|
+
text: string;
|
|
47
|
+
};
|
|
48
|
+
helpUri?: string;
|
|
49
|
+
defaultConfiguration: {
|
|
50
|
+
level: 'error' | 'warning' | 'note';
|
|
51
|
+
};
|
|
52
|
+
properties?: Record<string, unknown>;
|
|
53
|
+
}
|
|
54
|
+
interface SarifResult {
|
|
55
|
+
ruleId: string;
|
|
56
|
+
level: 'error' | 'warning' | 'note';
|
|
57
|
+
message: {
|
|
58
|
+
text: string;
|
|
59
|
+
};
|
|
60
|
+
locations: SarifLocation[];
|
|
61
|
+
properties?: Record<string, unknown>;
|
|
62
|
+
}
|
|
63
|
+
interface SarifLocation {
|
|
64
|
+
physicalLocation: {
|
|
65
|
+
artifactLocation: {
|
|
66
|
+
uri: string;
|
|
67
|
+
};
|
|
68
|
+
region: {
|
|
69
|
+
startLine: number;
|
|
70
|
+
startColumn?: number;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export interface SarifOptions {
|
|
75
|
+
/** Include parse diagnostics as results */
|
|
76
|
+
includeDiagnostics?: boolean;
|
|
77
|
+
/** Include dangling reference warnings */
|
|
78
|
+
includeDanglingRefs?: boolean;
|
|
79
|
+
/** Only include unmitigated exposures at or above this severity */
|
|
80
|
+
minSeverity?: Severity;
|
|
81
|
+
}
|
|
82
|
+
export declare function generateSarif(model: ThreatModel, diagnostics?: ParseDiagnostic[], danglingRefs?: ParseDiagnostic[], options?: SarifOptions): SarifLog;
|
|
83
|
+
export {};
|
|
84
|
+
//# sourceMappingURL=sarif.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sarif.d.ts","sourceRoot":"","sources":["../../src/analyzer/sarif.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAuB,eAAe,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAIrG,UAAU,QAAQ;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,QAAQ,EAAE,CAAC;CAClB;AAED,UAAU,QAAQ;IAChB,IAAI,EAAE;QACJ,MAAM,EAAE;YACN,IAAI,EAAE,MAAM,CAAC;YACb,OAAO,EAAE,MAAM,CAAC;YAChB,cAAc,EAAE,MAAM,CAAC;YACvB,KAAK,EAAE,SAAS,EAAE,CAAC;SACpB,CAAC;KACH,CAAC;IACF,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB;AAED,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,eAAe,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE;QACpB,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;KACrC,CAAC;IACF,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACpC,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,UAAU,aAAa;IACrB,gBAAgB,EAAE;QAChB,gBAAgB,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,CAAC;QAClC,MAAM,EAAE;YACN,SAAS,EAAE,MAAM,CAAC;YAClB,WAAW,CAAC,EAAE,MAAM,CAAC;SACtB,CAAC;KACH,CAAC;CACH;AAyCD,MAAM,WAAW,YAAY;IAC3B,2CAA2C;IAC3C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,0CAA0C;IAC1C,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,mEAAmE;IACnE,WAAW,CAAC,EAAE,QAAQ,CAAC;CACxB;AAED,wBAAgB,aAAa,CAC3B,KAAK,EAAE,WAAW,EAClB,WAAW,GAAE,eAAe,EAAO,EACnC,YAAY,GAAE,eAAe,EAAO,EACpC,OAAO,GAAE,YAAiB,GACzB,QAAQ,CA+EV"}
|