ghagga-core 2.5.0 → 2.6.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/README.md +1 -1
- package/dist/agents/consensus.d.ts +16 -0
- package/dist/agents/consensus.d.ts.map +1 -1
- package/dist/agents/consensus.js +57 -33
- package/dist/agents/consensus.js.map +1 -1
- package/dist/agents/diagnostic.d.ts +55 -0
- package/dist/agents/diagnostic.d.ts.map +1 -0
- package/dist/agents/diagnostic.js +143 -0
- package/dist/agents/diagnostic.js.map +1 -0
- package/dist/agents/prompts.d.ts +6 -4
- package/dist/agents/prompts.d.ts.map +1 -1
- package/dist/agents/prompts.js +110 -24
- package/dist/agents/prompts.js.map +1 -1
- package/dist/agents/simple.d.ts +7 -0
- package/dist/agents/simple.d.ts.map +1 -1
- package/dist/agents/simple.js +32 -18
- package/dist/agents/simple.js.map +1 -1
- package/dist/agents/workflow.d.ts +28 -1
- package/dist/agents/workflow.d.ts.map +1 -1
- package/dist/agents/workflow.js +112 -45
- package/dist/agents/workflow.js.map +1 -1
- package/dist/enhance/enhance.d.ts.map +1 -1
- package/dist/enhance/enhance.js +16 -4
- package/dist/enhance/enhance.js.map +1 -1
- package/dist/format.d.ts +47 -1
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +175 -3
- package/dist/format.js.map +1 -1
- package/dist/graph/blast-radius.d.ts +57 -0
- package/dist/graph/blast-radius.d.ts.map +1 -0
- package/dist/graph/blast-radius.js +145 -0
- package/dist/graph/blast-radius.js.map +1 -0
- package/dist/graph/builder.d.ts +50 -0
- package/dist/graph/builder.d.ts.map +1 -0
- package/dist/graph/builder.js +210 -0
- package/dist/graph/builder.js.map +1 -0
- package/dist/graph/extractors/go.d.ts +9 -0
- package/dist/graph/extractors/go.d.ts.map +1 -0
- package/dist/graph/extractors/go.js +78 -0
- package/dist/graph/extractors/go.js.map +1 -0
- package/dist/graph/extractors/index.d.ts +22 -0
- package/dist/graph/extractors/index.d.ts.map +1 -0
- package/dist/graph/extractors/index.js +37 -0
- package/dist/graph/extractors/index.js.map +1 -0
- package/dist/graph/extractors/java.d.ts +9 -0
- package/dist/graph/extractors/java.d.ts.map +1 -0
- package/dist/graph/extractors/java.js +80 -0
- package/dist/graph/extractors/java.js.map +1 -0
- package/dist/graph/extractors/javascript.d.ts +9 -0
- package/dist/graph/extractors/javascript.d.ts.map +1 -0
- package/dist/graph/extractors/javascript.js +204 -0
- package/dist/graph/extractors/javascript.js.map +1 -0
- package/dist/graph/extractors/python.d.ts +9 -0
- package/dist/graph/extractors/python.d.ts.map +1 -0
- package/dist/graph/extractors/python.js +103 -0
- package/dist/graph/extractors/python.js.map +1 -0
- package/dist/graph/extractors/rust.d.ts +9 -0
- package/dist/graph/extractors/rust.d.ts.map +1 -0
- package/dist/graph/extractors/rust.js +115 -0
- package/dist/graph/extractors/rust.js.map +1 -0
- package/dist/graph/extractors/types.d.ts +31 -0
- package/dist/graph/extractors/types.d.ts.map +1 -0
- package/dist/graph/extractors/types.js +9 -0
- package/dist/graph/extractors/types.js.map +1 -0
- package/dist/graph/extractors/typescript.d.ts +9 -0
- package/dist/graph/extractors/typescript.d.ts.map +1 -0
- package/dist/graph/extractors/typescript.js +151 -0
- package/dist/graph/extractors/typescript.js.map +1 -0
- package/dist/graph/index.d.ts +15 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +14 -0
- package/dist/graph/index.js.map +1 -0
- package/dist/graph/loader.d.ts +43 -0
- package/dist/graph/loader.d.ts.map +1 -0
- package/dist/graph/loader.js +104 -0
- package/dist/graph/loader.js.map +1 -0
- package/dist/graph/schema.d.ts +113 -0
- package/dist/graph/schema.d.ts.map +1 -0
- package/dist/graph/schema.js +144 -0
- package/dist/graph/schema.js.map +1 -0
- package/dist/health/trends.js +1 -1
- package/dist/health/trends.js.map +1 -1
- package/dist/index.d.ts +20 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/memory/sqlite.js +4 -4
- package/dist/memory/sqlite.js.map +1 -1
- package/dist/pipeline.d.ts.map +1 -1
- package/dist/pipeline.js +291 -42
- package/dist/pipeline.js.map +1 -1
- package/dist/providers/cli-bridge.d.ts +136 -0
- package/dist/providers/cli-bridge.d.ts.map +1 -0
- package/dist/providers/cli-bridge.js +457 -0
- package/dist/providers/cli-bridge.js.map +1 -0
- package/dist/providers/fallback.d.ts +8 -0
- package/dist/providers/fallback.d.ts.map +1 -1
- package/dist/providers/fallback.js +24 -8
- package/dist/providers/fallback.js.map +1 -1
- package/dist/providers/gateway.d.ts +40 -0
- package/dist/providers/gateway.d.ts.map +1 -0
- package/dist/providers/gateway.js +52 -0
- package/dist/providers/gateway.js.map +1 -0
- package/dist/providers/generate-fn.d.ts +62 -0
- package/dist/providers/generate-fn.d.ts.map +1 -0
- package/dist/providers/generate-fn.js +84 -0
- package/dist/providers/generate-fn.js.map +1 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +53 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/tools/plugins/index.d.ts +2 -0
- package/dist/tools/plugins/index.d.ts.map +1 -1
- package/dist/tools/plugins/index.js +7 -0
- package/dist/tools/plugins/index.js.map +1 -1
- package/dist/tools/plugins/zizmor.d.ts +22 -0
- package/dist/tools/plugins/zizmor.d.ts.map +1 -0
- package/dist/tools/plugins/zizmor.js +112 -0
- package/dist/tools/plugins/zizmor.js.map +1 -0
- package/dist/tools/resolve.js +1 -1
- package/dist/tools/resolve.js.map +1 -1
- package/dist/tools/types.d.ts +1 -1
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types.d.ts +54 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +21 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/concurrency.d.ts +29 -0
- package/dist/utils/concurrency.d.ts.map +1 -0
- package/dist/utils/concurrency.js +40 -0
- package/dist/utils/concurrency.js.map +1 -0
- package/dist/utils/context-levels.d.ts +113 -0
- package/dist/utils/context-levels.d.ts.map +1 -0
- package/dist/utils/context-levels.js +255 -0
- package/dist/utils/context-levels.js.map +1 -0
- package/dist/utils/diff.d.ts +25 -0
- package/dist/utils/diff.d.ts.map +1 -1
- package/dist/utils/diff.js +28 -0
- package/dist/utils/diff.js.map +1 -1
- package/dist/utils/llm-timeout.d.ts +38 -0
- package/dist/utils/llm-timeout.d.ts.map +1 -0
- package/dist/utils/llm-timeout.js +76 -0
- package/dist/utils/llm-timeout.js.map +1 -0
- package/dist/utils/path-protection.d.ts +59 -0
- package/dist/utils/path-protection.d.ts.map +1 -0
- package/dist/utils/path-protection.js +136 -0
- package/dist/utils/path-protection.js.map +1 -0
- package/dist/utils/token-budget.d.ts +34 -1
- package/dist/utils/token-budget.d.ts.map +1 -1
- package/dist/utils/token-budget.js +108 -3
- package/dist/utils/token-budget.js.map +1 -1
- package/package.json +21 -19
- package/LICENSE +0 -21
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progressive context loading system (L0/L1/L2).
|
|
3
|
+
*
|
|
4
|
+
* For small models with tight token budgets (e.g., Groq free tier: 4-6K total),
|
|
5
|
+
* the full static analysis and memory context can consume the entire context budget,
|
|
6
|
+
* leaving little room for the actual diff. This module provides three fidelity
|
|
7
|
+
* levels that are automatically selected based on the available token budget.
|
|
8
|
+
*
|
|
9
|
+
* Levels:
|
|
10
|
+
* L0 (~20-50 tokens) — One-sentence summary
|
|
11
|
+
* L1 (~100-200 tokens) — Bullet list with key details
|
|
12
|
+
* L2 (full) — Current behavior, unchanged
|
|
13
|
+
*/
|
|
14
|
+
// ─── Constants ──────────────────────────────────────────────────
|
|
15
|
+
/** Rough chars-per-token heuristic (same as diff.ts truncateDiff). */
|
|
16
|
+
const CHARS_PER_TOKEN = 4;
|
|
17
|
+
/**
|
|
18
|
+
* L1 budget ceiling: if the context budget is at least this many tokens,
|
|
19
|
+
* we can afford the bullet-list (L1) representation. Below this → L0.
|
|
20
|
+
*/
|
|
21
|
+
const L1_MIN_BUDGET = 150;
|
|
22
|
+
// ─── Token estimation ───────────────────────────────────────────
|
|
23
|
+
/**
|
|
24
|
+
* Estimate token count from text using the 4-chars-per-token heuristic.
|
|
25
|
+
* Matches the same approximation used in `truncateDiff()`.
|
|
26
|
+
*/
|
|
27
|
+
export function estimateTokens(text) {
|
|
28
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN);
|
|
29
|
+
}
|
|
30
|
+
// ─── Level selection ────────────────────────────────────────────
|
|
31
|
+
/**
|
|
32
|
+
* Choose the optimal context fidelity level based on available budget.
|
|
33
|
+
*
|
|
34
|
+
* Decision tree:
|
|
35
|
+
* 1. If the full (L2) context fits within the budget → L2
|
|
36
|
+
* 2. If the budget can accommodate an L1 summary (≥150 tokens) → L1
|
|
37
|
+
* 3. Otherwise → L0
|
|
38
|
+
*
|
|
39
|
+
* @param contextBudget - Available tokens for context from `calculateTokenBudget()`
|
|
40
|
+
* @param estimatedFullTokens - Token estimate for the full (L2) context
|
|
41
|
+
*/
|
|
42
|
+
export function chooseContextLevel(contextBudget, estimatedFullTokens) {
|
|
43
|
+
if (estimatedFullTokens <= contextBudget) {
|
|
44
|
+
return 'L2';
|
|
45
|
+
}
|
|
46
|
+
if (contextBudget >= L1_MIN_BUDGET) {
|
|
47
|
+
return 'L1';
|
|
48
|
+
}
|
|
49
|
+
return 'L0';
|
|
50
|
+
}
|
|
51
|
+
// ─── Static analysis helpers ────────────────────────────────────
|
|
52
|
+
/**
|
|
53
|
+
* Extract all findings from a StaticAnalysisResult (all tools, dynamic).
|
|
54
|
+
*/
|
|
55
|
+
export function collectAllFindings(staticResult) {
|
|
56
|
+
const findings = [];
|
|
57
|
+
for (const toolResult of Object.values(staticResult)) {
|
|
58
|
+
if (toolResult && typeof toolResult === 'object' && 'findings' in toolResult) {
|
|
59
|
+
findings.push(...toolResult.findings);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return findings;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Extract the names of all tools that ran successfully.
|
|
66
|
+
*/
|
|
67
|
+
export function collectToolNames(staticResult) {
|
|
68
|
+
return Object.entries(staticResult)
|
|
69
|
+
.filter(([, toolResult]) => toolResult &&
|
|
70
|
+
typeof toolResult === 'object' &&
|
|
71
|
+
'status' in toolResult &&
|
|
72
|
+
toolResult.status === 'success')
|
|
73
|
+
.map(([name]) => name);
|
|
74
|
+
}
|
|
75
|
+
// ─── Severity grouping helper ───────────────────────────────────
|
|
76
|
+
/**
|
|
77
|
+
* Group findings by severity, returning counts.
|
|
78
|
+
* E.g. { critical: 1, high: 2, medium: 3 }
|
|
79
|
+
*/
|
|
80
|
+
function countBySeverity(findings) {
|
|
81
|
+
const counts = {};
|
|
82
|
+
for (const f of findings) {
|
|
83
|
+
counts[f.severity] = (counts[f.severity] ?? 0) + 1;
|
|
84
|
+
}
|
|
85
|
+
return counts;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Format severity counts into a compact string like "2 high, 3 medium".
|
|
89
|
+
* Ordered by severity: critical → high → medium → low → info.
|
|
90
|
+
*/
|
|
91
|
+
function formatSeverityCounts(counts) {
|
|
92
|
+
const order = ['critical', 'high', 'medium', 'low', 'info'];
|
|
93
|
+
return order
|
|
94
|
+
.filter((s) => (counts[s] ?? 0) > 0)
|
|
95
|
+
.map((s) => `${counts[s]} ${s}`)
|
|
96
|
+
.join(', ');
|
|
97
|
+
}
|
|
98
|
+
// ─── Static Context Formatters ──────────────────────────────────
|
|
99
|
+
/**
|
|
100
|
+
* L0: One-sentence summary of static analysis findings.
|
|
101
|
+
*
|
|
102
|
+
* Output: "Static analysis (semgrep, trivy): 5 findings (2 high, 3 medium)"
|
|
103
|
+
* Or: "Static analysis: no findings"
|
|
104
|
+
*
|
|
105
|
+
* @param findings - All findings from static analysis tools
|
|
106
|
+
* @param toolNames - Names of tools that ran successfully
|
|
107
|
+
*/
|
|
108
|
+
export function formatStaticContextL0(findings, toolNames) {
|
|
109
|
+
const toolList = toolNames.length > 0 ? ` (${toolNames.join(', ')})` : '';
|
|
110
|
+
if (findings.length === 0) {
|
|
111
|
+
return `Static analysis${toolList}: no findings`;
|
|
112
|
+
}
|
|
113
|
+
const counts = countBySeverity(findings);
|
|
114
|
+
const severityStr = formatSeverityCounts(counts);
|
|
115
|
+
return `Static analysis${toolList}: ${findings.length} finding(s) (${severityStr})`;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* L1: Bullet list with file, line, severity, and rule name.
|
|
119
|
+
*
|
|
120
|
+
* Output:
|
|
121
|
+
* ## Static Analysis Summary
|
|
122
|
+
* - [high] auth.ts:45 — SQL injection (semgrep)
|
|
123
|
+
* - [medium] db.ts:12 — Unparameterized query (semgrep)
|
|
124
|
+
*
|
|
125
|
+
* Caps at 15 findings to stay within ~200 tokens. Sorted by severity.
|
|
126
|
+
*
|
|
127
|
+
* @param findings - All findings from static analysis tools
|
|
128
|
+
*/
|
|
129
|
+
export function formatStaticContextL1(findings) {
|
|
130
|
+
if (findings.length === 0)
|
|
131
|
+
return '';
|
|
132
|
+
const SEVERITY_ORDER = {
|
|
133
|
+
critical: 0,
|
|
134
|
+
high: 1,
|
|
135
|
+
medium: 2,
|
|
136
|
+
low: 3,
|
|
137
|
+
info: 4,
|
|
138
|
+
};
|
|
139
|
+
const sorted = [...findings].sort((a, b) => (SEVERITY_ORDER[a.severity] ?? 4) - (SEVERITY_ORDER[b.severity] ?? 4));
|
|
140
|
+
const cap = 15;
|
|
141
|
+
const capped = sorted.slice(0, cap);
|
|
142
|
+
const lines = ['## Static Analysis Summary (do NOT repeat these)', ''];
|
|
143
|
+
for (const f of capped) {
|
|
144
|
+
const location = f.line ? `${f.file}:${f.line}` : f.file;
|
|
145
|
+
lines.push(`- [${f.severity}] ${location} — ${f.message} (${f.source})`);
|
|
146
|
+
}
|
|
147
|
+
if (findings.length > cap) {
|
|
148
|
+
lines.push(`- ... and ${findings.length - cap} more`);
|
|
149
|
+
}
|
|
150
|
+
return lines.join('\n');
|
|
151
|
+
}
|
|
152
|
+
// ─── Memory Context Formatters ──────────────────────────────────
|
|
153
|
+
/**
|
|
154
|
+
* Count the number of observation items in a memory context string.
|
|
155
|
+
* Observations are headed by "### [TYPE] Title" lines.
|
|
156
|
+
*/
|
|
157
|
+
function countMemoryObservations(memory) {
|
|
158
|
+
const matches = memory.match(/^### \[/gm);
|
|
159
|
+
return matches?.length ?? 0;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* L0: One-sentence summary of available memory context.
|
|
163
|
+
*
|
|
164
|
+
* Output: "Memory: 3 past observations about this codebase available"
|
|
165
|
+
* Or: "" (if no memory)
|
|
166
|
+
*
|
|
167
|
+
* @param memory - The full memory context string, or null
|
|
168
|
+
*/
|
|
169
|
+
export function formatMemoryContextL0(memory) {
|
|
170
|
+
if (!memory)
|
|
171
|
+
return '';
|
|
172
|
+
const count = countMemoryObservations(memory);
|
|
173
|
+
if (count === 0)
|
|
174
|
+
return '';
|
|
175
|
+
return `Memory: ${count} past observation(s) about this codebase available`;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* L1: Abbreviated bullet list of memory items (titles only).
|
|
179
|
+
*
|
|
180
|
+
* Output:
|
|
181
|
+
* ## Past Review Memory (summary)
|
|
182
|
+
* - [DECISION] Switched from sessions to JWT
|
|
183
|
+
* - [BUGFIX] Fixed N+1 in user list
|
|
184
|
+
*
|
|
185
|
+
* @param memory - The full memory context string, or null
|
|
186
|
+
*/
|
|
187
|
+
export function formatMemoryContextL1(memory) {
|
|
188
|
+
if (!memory)
|
|
189
|
+
return '';
|
|
190
|
+
// Extract "### [TYPE] Title" headers from the memory context
|
|
191
|
+
const headerRegex = /^### \[([A-Z]+)\] (.+)$/gm;
|
|
192
|
+
const items = [];
|
|
193
|
+
let match = headerRegex.exec(memory);
|
|
194
|
+
while (match !== null) {
|
|
195
|
+
items.push(`- [${match[1]}] ${match[2]}`);
|
|
196
|
+
match = headerRegex.exec(memory);
|
|
197
|
+
}
|
|
198
|
+
if (items.length === 0)
|
|
199
|
+
return '';
|
|
200
|
+
return ['## Past Review Memory (summary)', '', ...items].join('\n');
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Build context strings at the optimal fidelity level for the available budget.
|
|
204
|
+
*
|
|
205
|
+
* The budget is split: static analysis gets priority, then memory fills remaining.
|
|
206
|
+
* Stack hints pass through unchanged (they are already compact).
|
|
207
|
+
*
|
|
208
|
+
* @returns Context strings and chosen levels for logging
|
|
209
|
+
*/
|
|
210
|
+
export function buildProgressiveContext(input) {
|
|
211
|
+
const { staticResult, memoryContext, stackHints, contextBudget, fullStaticContext } = input;
|
|
212
|
+
// Estimate full token costs
|
|
213
|
+
const fullStaticTokens = estimateTokens(fullStaticContext);
|
|
214
|
+
const fullMemoryTokens = memoryContext ? estimateTokens(memoryContext) : 0;
|
|
215
|
+
const stackHintTokens = estimateTokens(stackHints);
|
|
216
|
+
// Stack hints always pass through — they're already very compact
|
|
217
|
+
const remainingBudget = Math.max(0, contextBudget - stackHintTokens);
|
|
218
|
+
// Allocate: 60% to static, 40% to memory (of remaining budget)
|
|
219
|
+
const staticBudget = Math.floor(remainingBudget * 0.6);
|
|
220
|
+
const memoryBudget = remainingBudget - staticBudget;
|
|
221
|
+
// Choose static level
|
|
222
|
+
const staticLevel = chooseContextLevel(staticBudget, fullStaticTokens);
|
|
223
|
+
let adjustedStaticContext;
|
|
224
|
+
if (staticLevel === 'L2') {
|
|
225
|
+
adjustedStaticContext = fullStaticContext;
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
const allFindings = collectAllFindings(staticResult);
|
|
229
|
+
const toolNames = collectToolNames(staticResult);
|
|
230
|
+
adjustedStaticContext =
|
|
231
|
+
staticLevel === 'L1'
|
|
232
|
+
? formatStaticContextL1(allFindings)
|
|
233
|
+
: formatStaticContextL0(allFindings, toolNames);
|
|
234
|
+
}
|
|
235
|
+
// Choose memory level
|
|
236
|
+
const memoryLevel = chooseContextLevel(memoryBudget, fullMemoryTokens);
|
|
237
|
+
let adjustedMemory;
|
|
238
|
+
if (memoryLevel === 'L2') {
|
|
239
|
+
adjustedMemory = memoryContext;
|
|
240
|
+
}
|
|
241
|
+
else if (memoryLevel === 'L1') {
|
|
242
|
+
adjustedMemory = formatMemoryContextL1(memoryContext) || null;
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
adjustedMemory = formatMemoryContextL0(memoryContext) || null;
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
staticContext: adjustedStaticContext,
|
|
249
|
+
memoryContext: adjustedMemory,
|
|
250
|
+
stackHints,
|
|
251
|
+
staticLevel,
|
|
252
|
+
memoryLevel,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=context-levels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-levels.js","sourceRoot":"","sources":["../../src/utils/context-levels.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/diff.d.ts
CHANGED
|
@@ -36,6 +36,31 @@ export declare function parseDiffFiles(diff: string): DiffFile[];
|
|
|
36
36
|
* @returns Filtered array with ignored files removed
|
|
37
37
|
*/
|
|
38
38
|
export declare function filterIgnoredFiles(files: DiffFile[], patterns: string[]): DiffFile[];
|
|
39
|
+
/**
|
|
40
|
+
* Result of applying all three filtering tiers to diff files.
|
|
41
|
+
*/
|
|
42
|
+
export interface FilterDiffResult {
|
|
43
|
+
/** Files that passed all tiers — ready for LLM review. */
|
|
44
|
+
filtered: DiffFile[];
|
|
45
|
+
/** File paths blocked by ZERO_ACCESS tier (for logging). */
|
|
46
|
+
blocked: string[];
|
|
47
|
+
/** File paths redacted by REDACT tier (for logging). */
|
|
48
|
+
redacted: string[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Apply all three tiers of file filtering in order:
|
|
52
|
+
* 1. ZERO_ACCESS — hardcoded security patterns (blocked entirely)
|
|
53
|
+
* 2. REDACT — sensitive templates (content replaced, path visible)
|
|
54
|
+
* 3. User ignorePatterns — configurable exclusions
|
|
55
|
+
*
|
|
56
|
+
* This is the recommended entry point for the pipeline. It applies
|
|
57
|
+
* non-overridable security filtering before user-configurable patterns.
|
|
58
|
+
*
|
|
59
|
+
* @param files - Array of DiffFile objects from the parsed diff
|
|
60
|
+
* @param ignorePatterns - User-configurable glob patterns to exclude
|
|
61
|
+
* @returns Object with filtered files, blocked paths, and redacted paths
|
|
62
|
+
*/
|
|
63
|
+
export declare function filterDiffFiles(files: DiffFile[], ignorePatterns: string[]): FilterDiffResult;
|
|
39
64
|
/**
|
|
40
65
|
* Truncate a diff string to fit within a token budget.
|
|
41
66
|
*
|
package/dist/utils/diff.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/utils/diff.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/utils/diff.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,8DAA8D;AAC9D,MAAM,WAAW,QAAQ;IACvB,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IAEb,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAC;IAElB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAElB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;CACjB;AAYD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CA2CvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAOpF;AAID;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAErB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,EAAE,CAAC;IAElB,wDAAwD;IACxD,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAe7F;AAID;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,CAc9C"}
|
package/dist/utils/diff.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* large diffs to fit within LLM token budgets.
|
|
7
7
|
*/
|
|
8
8
|
import { minimatch } from 'minimatch';
|
|
9
|
+
import { applyPathProtection } from './path-protection.js';
|
|
9
10
|
// ─── Constants ──────────────────────────────────────────────────
|
|
10
11
|
/**
|
|
11
12
|
* Regex to match the start of a file diff block.
|
|
@@ -79,6 +80,33 @@ export function filterIgnoredFiles(files, patterns) {
|
|
|
79
80
|
return !patterns.some((pattern) => minimatch(file.path, pattern, { dot: true }));
|
|
80
81
|
});
|
|
81
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Apply all three tiers of file filtering in order:
|
|
85
|
+
* 1. ZERO_ACCESS — hardcoded security patterns (blocked entirely)
|
|
86
|
+
* 2. REDACT — sensitive templates (content replaced, path visible)
|
|
87
|
+
* 3. User ignorePatterns — configurable exclusions
|
|
88
|
+
*
|
|
89
|
+
* This is the recommended entry point for the pipeline. It applies
|
|
90
|
+
* non-overridable security filtering before user-configurable patterns.
|
|
91
|
+
*
|
|
92
|
+
* @param files - Array of DiffFile objects from the parsed diff
|
|
93
|
+
* @param ignorePatterns - User-configurable glob patterns to exclude
|
|
94
|
+
* @returns Object with filtered files, blocked paths, and redacted paths
|
|
95
|
+
*/
|
|
96
|
+
export function filterDiffFiles(files, ignorePatterns) {
|
|
97
|
+
// Tier 1 & 2: Security filtering (non-overridable)
|
|
98
|
+
const { allowed, redacted, blocked } = applyPathProtection(files);
|
|
99
|
+
// Tier 3: User ignore patterns (applied to allowed files only)
|
|
100
|
+
const userFiltered = filterIgnoredFiles(allowed, ignorePatterns);
|
|
101
|
+
// Combine user-filtered files with redacted files for final output
|
|
102
|
+
const filtered = [...userFiltered, ...redacted];
|
|
103
|
+
return {
|
|
104
|
+
filtered,
|
|
105
|
+
blocked,
|
|
106
|
+
redacted: redacted.map((f) => f.path),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// ─── Truncation ─────────────────────────────────────────────────
|
|
82
110
|
/**
|
|
83
111
|
* Truncate a diff string to fit within a token budget.
|
|
84
112
|
*
|
package/dist/utils/diff.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/utils/diff.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/utils/diff.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAmB3D,mEAAmE;AAEnE;;;GAGG;AACH,MAAM,cAAc,GAAG,4BAA4B,CAAC;AAEpD,mEAAmE;AAEnE;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAE/B,IAAI,WAAW,GAAoB,IAAI,CAAC;IACxC,MAAM,YAAY,GAAa,EAAE,CAAC;IAElC,SAAS,YAAY;QACnB,IAAI,WAAW,EAAE,CAAC;YAChB,WAAW,CAAC,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9C,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACxB,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,KAAK,EAAE,CAAC;YACV,uCAAuC;YACvC,YAAY,EAAE,CAAC;YACf,WAAW,GAAG;gBACZ,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;gBACpB,SAAS,EAAE,CAAC;gBACZ,SAAS,EAAE,CAAC;gBACZ,OAAO,EAAE,EAAE;aACZ,CAAC;YACF,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;aAAM,IAAI,WAAW,EAAE,CAAC;YACvB,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAExB,wEAAwE;YACxE,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;gBACpD,WAAW,CAAC,SAAS,EAAE,CAAC;YAC1B,CAAC;iBAAM,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC3D,WAAW,CAAC,SAAS,EAAE,CAAC;YAC1B,CAAC;QACH,CAAC;IACH,CAAC;IAED,kBAAkB;IAClB,YAAY,EAAE,CAAC;IAEf,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAiB,EAAE,QAAkB;IACtE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAExC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAC3B,wDAAwD;QACxD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;AACL,CAAC;AAkBD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,KAAiB,EAAE,cAAwB;IACzE,mDAAmD;IACnD,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IAElE,+DAA+D;IAC/D,MAAM,YAAY,GAAG,kBAAkB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAEjE,mEAAmE;IACnE,MAAM,QAAQ,GAAG,CAAC,GAAG,YAAY,EAAE,GAAG,QAAQ,CAAC,CAAC;IAEhD,OAAO;QACL,QAAQ;QACR,OAAO;QACP,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;KACtC,CAAC;AACJ,CAAC;AAED,mEAAmE;AAEnE;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,SAAiB;IAEjB,MAAM,QAAQ,GAAG,SAAS,GAAG,CAAC,CAAC;IAE/B,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC5B,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;IAClD,CAAC;IAED,uEAAuE;IACvE,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAChD,MAAM,SAAS,GACb,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAC9D,kDAAkD,CAAC;IAErD,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM call timeout utility.
|
|
3
|
+
*
|
|
4
|
+
* Wraps the AI SDK's `generateText` with a configurable timeout
|
|
5
|
+
* (default 60 seconds). When the timeout fires, the call is aborted
|
|
6
|
+
* and the function returns `null` so callers can gracefully fall back
|
|
7
|
+
* to static-analysis-only results.
|
|
8
|
+
*/
|
|
9
|
+
import { type GenerateTextResult, generateText } from 'ai';
|
|
10
|
+
/** Default timeout for LLM calls: 60 seconds. */
|
|
11
|
+
export declare const LLM_TIMEOUT_MS = 60000;
|
|
12
|
+
/**
|
|
13
|
+
* Options accepted by `generateTextWithTimeout`.
|
|
14
|
+
*
|
|
15
|
+
* Same as `generateText` parameters, but `abortSignal` is managed
|
|
16
|
+
* internally (any caller-provided signal is combined via `AbortSignal.any`).
|
|
17
|
+
*/
|
|
18
|
+
type GenerateTextParams = Parameters<typeof generateText>[0];
|
|
19
|
+
/**
|
|
20
|
+
* Call `generateText` with an automatic timeout.
|
|
21
|
+
*
|
|
22
|
+
* - Creates an `AbortController` with a 60-second timeout.
|
|
23
|
+
* - If the caller already provides an `abortSignal`, both signals
|
|
24
|
+
* are combined so either one can cancel the request.
|
|
25
|
+
* - On timeout (or abort), logs a warning and returns `null`.
|
|
26
|
+
* - On any other error, **re-throws** so the caller's existing
|
|
27
|
+
* error handling continues to work.
|
|
28
|
+
*
|
|
29
|
+
* @param params - Standard `generateText` parameters
|
|
30
|
+
* @param context - Optional metadata for the warning log (provider, model)
|
|
31
|
+
* @returns The `generateText` result, or `null` if the call timed out
|
|
32
|
+
*/
|
|
33
|
+
export declare function generateTextWithTimeout(params: GenerateTextParams, context?: {
|
|
34
|
+
provider?: string;
|
|
35
|
+
model?: string;
|
|
36
|
+
}): Promise<GenerateTextResult<any, any> | null>;
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=llm-timeout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-timeout.d.ts","sourceRoot":"","sources":["../../src/utils/llm-timeout.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,kBAAkB,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAE3D,iDAAiD;AACjD,eAAO,MAAM,cAAc,QAAS,CAAC;AAErC;;;;;GAKG;AACH,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAE7D;;;;;;;;;;;;;GAaG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,kBAAkB,EAC1B,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAE9C,OAAO,CAAC,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,CAwC9C"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM call timeout utility.
|
|
3
|
+
*
|
|
4
|
+
* Wraps the AI SDK's `generateText` with a configurable timeout
|
|
5
|
+
* (default 60 seconds). When the timeout fires, the call is aborted
|
|
6
|
+
* and the function returns `null` so callers can gracefully fall back
|
|
7
|
+
* to static-analysis-only results.
|
|
8
|
+
*/
|
|
9
|
+
import { generateText } from 'ai';
|
|
10
|
+
/** Default timeout for LLM calls: 60 seconds. */
|
|
11
|
+
export const LLM_TIMEOUT_MS = 60_000;
|
|
12
|
+
/**
|
|
13
|
+
* Call `generateText` with an automatic timeout.
|
|
14
|
+
*
|
|
15
|
+
* - Creates an `AbortController` with a 60-second timeout.
|
|
16
|
+
* - If the caller already provides an `abortSignal`, both signals
|
|
17
|
+
* are combined so either one can cancel the request.
|
|
18
|
+
* - On timeout (or abort), logs a warning and returns `null`.
|
|
19
|
+
* - On any other error, **re-throws** so the caller's existing
|
|
20
|
+
* error handling continues to work.
|
|
21
|
+
*
|
|
22
|
+
* @param params - Standard `generateText` parameters
|
|
23
|
+
* @param context - Optional metadata for the warning log (provider, model)
|
|
24
|
+
* @returns The `generateText` result, or `null` if the call timed out
|
|
25
|
+
*/
|
|
26
|
+
export async function generateTextWithTimeout(params, context) {
|
|
27
|
+
const controller = new AbortController();
|
|
28
|
+
const timer = setTimeout(() => controller.abort(), LLM_TIMEOUT_MS);
|
|
29
|
+
// Combine with any caller-provided signal
|
|
30
|
+
let signal = controller.signal;
|
|
31
|
+
if (params.abortSignal) {
|
|
32
|
+
signal = AbortSignal.any([controller.signal, params.abortSignal]);
|
|
33
|
+
}
|
|
34
|
+
const startTime = Date.now();
|
|
35
|
+
try {
|
|
36
|
+
const result = await generateText({
|
|
37
|
+
...params,
|
|
38
|
+
abortSignal: signal,
|
|
39
|
+
});
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
const elapsed = Date.now() - startTime;
|
|
44
|
+
// Check if this was an abort/timeout
|
|
45
|
+
if (isAbortError(error)) {
|
|
46
|
+
const providerInfo = context?.provider && context?.model ? `${context.provider}/${context.model}` : 'unknown';
|
|
47
|
+
console.warn(`[ghagga] LLM call timed out after ${(elapsed / 1000).toFixed(1)}s ` +
|
|
48
|
+
`(limit: ${LLM_TIMEOUT_MS / 1000}s) — provider: ${providerInfo}. ` +
|
|
49
|
+
'Falling back to static-analysis-only results.');
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
// Not a timeout — re-throw for the caller's existing error handling
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Detect whether an error is an abort/timeout error.
|
|
61
|
+
*
|
|
62
|
+
* The AI SDK and Node.js throw different shapes depending on the
|
|
63
|
+
* runtime, so we check multiple patterns.
|
|
64
|
+
*/
|
|
65
|
+
function isAbortError(error) {
|
|
66
|
+
if (error instanceof DOMException && error.name === 'AbortError')
|
|
67
|
+
return true;
|
|
68
|
+
if (error instanceof Error) {
|
|
69
|
+
if (error.name === 'AbortError')
|
|
70
|
+
return true;
|
|
71
|
+
if (error.message.includes('aborted') || error.message.includes('AbortError'))
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=llm-timeout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-timeout.js","sourceRoot":"","sources":["../../src/utils/llm-timeout.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAA2B,YAAY,EAAE,MAAM,IAAI,CAAC;AAE3D,iDAAiD;AACjD,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC;AAUrC;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,MAA0B,EAC1B,OAA+C;IAG/C,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,cAAc,CAAC,CAAC;IAEnE,0CAA0C;IAC1C,IAAI,MAAM,GAAgB,UAAU,CAAC,MAAM,CAAC;IAC5C,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC;YAChC,GAAG,MAAM;YACT,WAAW,EAAE,MAAM;SACpB,CAAC,CAAC;QACH,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAEvC,qCAAqC;QACrC,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,MAAM,YAAY,GAChB,OAAO,EAAE,QAAQ,IAAI,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;YAE3F,OAAO,CAAC,IAAI,CACV,qCAAqC,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;gBAClE,WAAW,cAAc,GAAG,IAAI,kBAAkB,YAAY,IAAI;gBAClE,+CAA+C,CAClD,CAAC;YAEF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,oEAAoE;QACpE,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,KAAK,YAAY,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IAC9E,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY;YAAE,OAAO,IAAI,CAAC;QAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;YAAE,OAAO,IAAI,CAAC;IAC7F,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Three-tier path protection for sensitive files.
|
|
3
|
+
*
|
|
4
|
+
* Provides a non-overridable security layer that filters sensitive files
|
|
5
|
+
* BEFORE user-configurable ignorePatterns are applied. This ensures that
|
|
6
|
+
* secrets, credentials, and private keys are never sent to the LLM for review.
|
|
7
|
+
*
|
|
8
|
+
* Tiers:
|
|
9
|
+
* 1. ZERO_ACCESS — hardcoded, content never sent to LLM, non-overridable
|
|
10
|
+
* 2. REDACT — content replaced with redaction notice, path still visible
|
|
11
|
+
* 3. User ignore — existing configurable ignorePatterns (handled in diff.ts)
|
|
12
|
+
*/
|
|
13
|
+
import type { DiffFile } from './diff.js';
|
|
14
|
+
/** Redaction notice used to replace content of REDACT-tier files. */
|
|
15
|
+
export declare const REDACTED_CONTENT = "[REDACTED \u2014 sensitive file detected by GHAGGA path protection]";
|
|
16
|
+
/**
|
|
17
|
+
* Tier 1 — ZERO_ACCESS patterns.
|
|
18
|
+
*
|
|
19
|
+
* Files matching these patterns are completely blocked from the review
|
|
20
|
+
* pipeline. Their content is never sent to the LLM. These patterns are
|
|
21
|
+
* hardcoded and cannot be overridden by user configuration.
|
|
22
|
+
*/
|
|
23
|
+
export declare const ZERO_ACCESS_PATTERNS: readonly string[];
|
|
24
|
+
/**
|
|
25
|
+
* Tier 2 — REDACT patterns.
|
|
26
|
+
*
|
|
27
|
+
* Files matching these patterns have their content replaced with a
|
|
28
|
+
* redaction notice. The file path is still visible in the review so
|
|
29
|
+
* reviewers know the file was changed, but the actual content is not
|
|
30
|
+
* sent to the LLM.
|
|
31
|
+
*/
|
|
32
|
+
export declare const REDACT_PATTERNS: readonly string[];
|
|
33
|
+
/**
|
|
34
|
+
* Result of applying path protection to a set of diff files.
|
|
35
|
+
*/
|
|
36
|
+
export interface PathProtectionResult {
|
|
37
|
+
/** Files that passed all protection tiers — content untouched. */
|
|
38
|
+
allowed: DiffFile[];
|
|
39
|
+
/** Files matching REDACT patterns — content replaced with redaction notice. */
|
|
40
|
+
redacted: DiffFile[];
|
|
41
|
+
/** File paths matching ZERO_ACCESS patterns — completely blocked. */
|
|
42
|
+
blocked: string[];
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Apply three-tier path protection to a set of diff files.
|
|
46
|
+
*
|
|
47
|
+
* This function is pure and deterministic. It processes files in the
|
|
48
|
+
* following order:
|
|
49
|
+
* 1. Check against REDACT patterns first — these are specific exceptions
|
|
50
|
+
* (e.g., `.env.example`) that would otherwise be caught by broader
|
|
51
|
+
* ZERO_ACCESS globs (e.g., `.env.*`). Content is replaced.
|
|
52
|
+
* 2. Check against ZERO_ACCESS patterns — block entirely
|
|
53
|
+
* 3. Everything else passes through untouched
|
|
54
|
+
*
|
|
55
|
+
* @param files - Array of DiffFile objects from the parsed diff
|
|
56
|
+
* @returns Object with allowed, redacted, and blocked files
|
|
57
|
+
*/
|
|
58
|
+
export declare function applyPathProtection(files: DiffFile[]): PathProtectionResult;
|
|
59
|
+
//# sourceMappingURL=path-protection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-protection.d.ts","sourceRoot":"","sources":["../../src/utils/path-protection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAI1C,qEAAqE;AACrE,eAAO,MAAM,gBAAgB,wEAAmE,CAAC;AAEjG;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EA6CxC,CAAC;AAEX;;;;;;;GAOG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,MAAM,EAYnC,CAAC;AASX;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,kEAAkE;IAClE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAEpB,+EAA+E;IAC/E,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAErB,qEAAqE;IACrE,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,oBAAoB,CAyB3E"}
|