@ruso-0/nreki 6.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 +648 -0
- package/LICENSE +21 -0
- package/README.md +425 -0
- package/dist/ast-navigator.d.ts +29 -0
- package/dist/ast-navigator.d.ts.map +1 -0
- package/dist/ast-navigator.js +279 -0
- package/dist/ast-navigator.js.map +1 -0
- package/dist/ast-sandbox.d.ts +74 -0
- package/dist/ast-sandbox.d.ts.map +1 -0
- package/dist/ast-sandbox.js +242 -0
- package/dist/ast-sandbox.js.map +1 -0
- package/dist/chronos-memory.d.ts +69 -0
- package/dist/chronos-memory.d.ts.map +1 -0
- package/dist/chronos-memory.js +247 -0
- package/dist/chronos-memory.js.map +1 -0
- package/dist/circuit-breaker.d.ts +107 -0
- package/dist/circuit-breaker.d.ts.map +1 -0
- package/dist/circuit-breaker.js +330 -0
- package/dist/circuit-breaker.js.map +1 -0
- package/dist/compressor-advanced.d.ts +80 -0
- package/dist/compressor-advanced.d.ts.map +1 -0
- package/dist/compressor-advanced.js +555 -0
- package/dist/compressor-advanced.js.map +1 -0
- package/dist/compressor.d.ts +81 -0
- package/dist/compressor.d.ts.map +1 -0
- package/dist/compressor.js +227 -0
- package/dist/compressor.js.map +1 -0
- package/dist/database.d.ts +169 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +1029 -0
- package/dist/database.js.map +1 -0
- package/dist/embedder.d.ts +73 -0
- package/dist/embedder.d.ts.map +1 -0
- package/dist/embedder.js +165 -0
- package/dist/embedder.js.map +1 -0
- package/dist/engine.d.ts +224 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +582 -0
- package/dist/engine.js.map +1 -0
- package/dist/hologram/harvester.d.ts +41 -0
- package/dist/hologram/harvester.d.ts.map +1 -0
- package/dist/hologram/harvester.js +129 -0
- package/dist/hologram/harvester.js.map +1 -0
- package/dist/hologram/shadow-cache.d.ts +49 -0
- package/dist/hologram/shadow-cache.d.ts.map +1 -0
- package/dist/hologram/shadow-cache.js +165 -0
- package/dist/hologram/shadow-cache.js.map +1 -0
- package/dist/hologram/shadow-generator.d.ts +32 -0
- package/dist/hologram/shadow-generator.d.ts.map +1 -0
- package/dist/hologram/shadow-generator.js +828 -0
- package/dist/hologram/shadow-generator.js.map +1 -0
- package/dist/hooks/preToolUse.d.ts +63 -0
- package/dist/hooks/preToolUse.d.ts.map +1 -0
- package/dist/hooks/preToolUse.js +103 -0
- package/dist/hooks/preToolUse.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +367 -0
- package/dist/index.js.map +1 -0
- package/dist/kernel/kernel-manager.d.ts +52 -0
- package/dist/kernel/kernel-manager.d.ts.map +1 -0
- package/dist/kernel/kernel-manager.js +197 -0
- package/dist/kernel/kernel-manager.js.map +1 -0
- package/dist/kernel/kernel-worker.d.ts +9 -0
- package/dist/kernel/kernel-worker.d.ts.map +1 -0
- package/dist/kernel/kernel-worker.js +76 -0
- package/dist/kernel/kernel-worker.js.map +1 -0
- package/dist/kernel/nreki-kernel.d.ts +244 -0
- package/dist/kernel/nreki-kernel.d.ts.map +1 -0
- package/dist/kernel/nreki-kernel.js +1656 -0
- package/dist/kernel/nreki-kernel.js.map +1 -0
- package/dist/middleware/circuit-breaker.d.ts +32 -0
- package/dist/middleware/circuit-breaker.d.ts.map +1 -0
- package/dist/middleware/circuit-breaker.js +160 -0
- package/dist/middleware/circuit-breaker.js.map +1 -0
- package/dist/middleware/file-lock.d.ts +33 -0
- package/dist/middleware/file-lock.d.ts.map +1 -0
- package/dist/middleware/file-lock.js +55 -0
- package/dist/middleware/file-lock.js.map +1 -0
- package/dist/middleware/validator.d.ts +26 -0
- package/dist/middleware/validator.d.ts.map +1 -0
- package/dist/middleware/validator.js +39 -0
- package/dist/middleware/validator.js.map +1 -0
- package/dist/monitor.d.ts +94 -0
- package/dist/monitor.d.ts.map +1 -0
- package/dist/monitor.js +221 -0
- package/dist/monitor.js.map +1 -0
- package/dist/parser-pool.d.ts +28 -0
- package/dist/parser-pool.d.ts.map +1 -0
- package/dist/parser-pool.js +81 -0
- package/dist/parser-pool.js.map +1 -0
- package/dist/parser.d.ts +91 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +311 -0
- package/dist/parser.js.map +1 -0
- package/dist/pin-memory.d.ts +35 -0
- package/dist/pin-memory.d.ts.map +1 -0
- package/dist/pin-memory.js +161 -0
- package/dist/pin-memory.js.map +1 -0
- package/dist/repo-map.d.ts +81 -0
- package/dist/repo-map.d.ts.map +1 -0
- package/dist/repo-map.js +550 -0
- package/dist/repo-map.js.map +1 -0
- package/dist/router.d.ts +102 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +1989 -0
- package/dist/router.js.map +1 -0
- package/dist/semantic-edit.d.ts +82 -0
- package/dist/semantic-edit.d.ts.map +1 -0
- package/dist/semantic-edit.js +529 -0
- package/dist/semantic-edit.js.map +1 -0
- package/dist/terminal-filter.d.ts +27 -0
- package/dist/terminal-filter.d.ts.map +1 -0
- package/dist/terminal-filter.js +257 -0
- package/dist/terminal-filter.js.map +1 -0
- package/dist/undo.d.ts +21 -0
- package/dist/undo.d.ts.map +1 -0
- package/dist/undo.js +55 -0
- package/dist/undo.js.map +1 -0
- package/dist/utils/code-tokenizer.d.ts +25 -0
- package/dist/utils/code-tokenizer.d.ts.map +1 -0
- package/dist/utils/code-tokenizer.js +52 -0
- package/dist/utils/code-tokenizer.js.map +1 -0
- package/dist/utils/file-filter.d.ts +23 -0
- package/dist/utils/file-filter.d.ts.map +1 -0
- package/dist/utils/file-filter.js +48 -0
- package/dist/utils/file-filter.js.map +1 -0
- package/dist/utils/imports.d.ts +32 -0
- package/dist/utils/imports.d.ts.map +1 -0
- package/dist/utils/imports.js +155 -0
- package/dist/utils/imports.js.map +1 -0
- package/dist/utils/path-jail.d.ts +27 -0
- package/dist/utils/path-jail.d.ts.map +1 -0
- package/dist/utils/path-jail.js +95 -0
- package/dist/utils/path-jail.js.map +1 -0
- package/dist/utils/read-source.d.ts +18 -0
- package/dist/utils/read-source.d.ts.map +1 -0
- package/dist/utils/read-source.js +22 -0
- package/dist/utils/read-source.js.map +1 -0
- package/dist/utils/safe-parse.d.ts +20 -0
- package/dist/utils/safe-parse.d.ts.map +1 -0
- package/dist/utils/safe-parse.js +25 -0
- package/dist/utils/safe-parse.js.map +1 -0
- package/package.json +75 -0
- package/scripts/download-wasm.js +46 -0
- package/wasm/.gitkeep +0 -0
- package/wasm/tree-sitter-go.wasm +0 -0
- package/wasm/tree-sitter-javascript.wasm +0 -0
- package/wasm/tree-sitter-python.wasm +0 -0
- package/wasm/tree-sitter-typescript.wasm +0 -0
package/dist/monitor.js
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* monitor.ts - Token consumption monitor for NREKI.
|
|
3
|
+
*
|
|
4
|
+
* Tracks Claude's token usage by reading JSONL session logs,
|
|
5
|
+
* computes real-time burn rate, and predicts when the context
|
|
6
|
+
* budget will be exhausted. Emits proactive alerts at configurable
|
|
7
|
+
* thresholds so you can adjust strategy before hitting limits.
|
|
8
|
+
*/
|
|
9
|
+
import fs from "fs";
|
|
10
|
+
import path from "path";
|
|
11
|
+
import os from "os";
|
|
12
|
+
// ─── Constants ───────────────────────────────────────────────────────
|
|
13
|
+
/** Default Claude pricing (per 1M tokens). Approximate - update if Anthropic changes pricing. */
|
|
14
|
+
const DEFAULT_PRICING = {
|
|
15
|
+
input: 3.0, // $3.00 per 1M input tokens
|
|
16
|
+
output: 15.0, // $15.00 per 1M output tokens
|
|
17
|
+
cacheRead: 0.3, // $0.30 per 1M cache read tokens
|
|
18
|
+
cacheWrite: 3.75, // $3.75 per 1M cache write tokens
|
|
19
|
+
};
|
|
20
|
+
export class TokenMonitor {
|
|
21
|
+
entries = [];
|
|
22
|
+
config;
|
|
23
|
+
lastReadPosition = 0;
|
|
24
|
+
constructor(config = {}) {
|
|
25
|
+
this.config = {
|
|
26
|
+
logPath: config.logPath ?? this.detectLogPath(),
|
|
27
|
+
budgetTokens: config.budgetTokens ?? 1_000_000,
|
|
28
|
+
warningThreshold: config.warningThreshold ?? 0.7,
|
|
29
|
+
criticalThreshold: config.criticalThreshold ?? 0.9,
|
|
30
|
+
pricing: { ...DEFAULT_PRICING, ...config.pricing },
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// ─── Log Detection ────────────────────────────────────────────
|
|
34
|
+
/**
|
|
35
|
+
* Auto-detect Claude's JSONL usage log path.
|
|
36
|
+
* Checks common locations across operating systems.
|
|
37
|
+
*/
|
|
38
|
+
detectLogPath() {
|
|
39
|
+
const home = os.homedir();
|
|
40
|
+
const candidates = [
|
|
41
|
+
// Claude Code / Claude Desktop on macOS
|
|
42
|
+
path.join(home, ".claude", "usage.jsonl"),
|
|
43
|
+
// Claude Code on Linux
|
|
44
|
+
path.join(home, ".config", "claude", "usage.jsonl"),
|
|
45
|
+
// Claude Code on Windows
|
|
46
|
+
path.join(home, "AppData", "Roaming", "claude", "usage.jsonl"),
|
|
47
|
+
// Alternative: local project usage
|
|
48
|
+
path.join(process.cwd(), ".claude", "usage.jsonl"),
|
|
49
|
+
];
|
|
50
|
+
for (const candidate of candidates) {
|
|
51
|
+
if (fs.existsSync(candidate)) {
|
|
52
|
+
return candidate;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Default fallback - will be created if Claude generates it
|
|
56
|
+
return path.join(home, ".claude", "usage.jsonl");
|
|
57
|
+
}
|
|
58
|
+
// ─── Log Reading ──────────────────────────────────────────────
|
|
59
|
+
/**
|
|
60
|
+
* Read and parse the JSONL usage log.
|
|
61
|
+
* Uses incremental reading - only processes new lines since last read.
|
|
62
|
+
*/
|
|
63
|
+
readUsageLog() {
|
|
64
|
+
if (!fs.existsSync(this.config.logPath)) {
|
|
65
|
+
return this.entries;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const content = fs.readFileSync(this.config.logPath, "utf-8");
|
|
69
|
+
const newContent = content.slice(this.lastReadPosition);
|
|
70
|
+
if (newContent.trim()) {
|
|
71
|
+
const newLines = newContent
|
|
72
|
+
.split("\n")
|
|
73
|
+
.filter((line) => line.trim())
|
|
74
|
+
.map((line) => {
|
|
75
|
+
try {
|
|
76
|
+
return JSON.parse(line);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
.filter((entry) => entry !== null);
|
|
83
|
+
this.entries.push(...newLines);
|
|
84
|
+
}
|
|
85
|
+
this.lastReadPosition = content.length;
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
console.error(`[NREKI] Failed to read usage log: ${err.message}`);
|
|
89
|
+
}
|
|
90
|
+
return this.entries;
|
|
91
|
+
}
|
|
92
|
+
// ─── Burn Rate Analysis ───────────────────────────────────────
|
|
93
|
+
/** Calculate the current token burn rate. */
|
|
94
|
+
computeBurnRate() {
|
|
95
|
+
this.readUsageLog();
|
|
96
|
+
if (this.entries.length === 0) {
|
|
97
|
+
return {
|
|
98
|
+
tokensPerMinute: 0,
|
|
99
|
+
tokensPerHour: 0,
|
|
100
|
+
totalConsumed: 0,
|
|
101
|
+
inputTokens: 0,
|
|
102
|
+
outputTokens: 0,
|
|
103
|
+
cacheReadTokens: 0,
|
|
104
|
+
estimatedCostUsd: 0,
|
|
105
|
+
sessionDurationMinutes: 0,
|
|
106
|
+
apiCalls: 0,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
let inputTokens = 0;
|
|
110
|
+
let outputTokens = 0;
|
|
111
|
+
let cacheReadTokens = 0;
|
|
112
|
+
let cacheWriteTokens = 0;
|
|
113
|
+
for (const entry of this.entries) {
|
|
114
|
+
inputTokens += entry.input_tokens ?? 0;
|
|
115
|
+
outputTokens += entry.output_tokens ?? 0;
|
|
116
|
+
cacheReadTokens += entry.cache_read_tokens ?? 0;
|
|
117
|
+
cacheWriteTokens += entry.cache_write_tokens ?? 0;
|
|
118
|
+
}
|
|
119
|
+
const totalConsumed = inputTokens + outputTokens;
|
|
120
|
+
// Calculate time span
|
|
121
|
+
const firstTime = new Date(this.entries[0].timestamp).getTime();
|
|
122
|
+
const lastTime = new Date(this.entries[this.entries.length - 1].timestamp).getTime();
|
|
123
|
+
const durationMs = Math.max(lastTime - firstTime, 60_000); // At least 1 minute
|
|
124
|
+
const durationMinutes = durationMs / 60_000;
|
|
125
|
+
const tokensPerMinute = totalConsumed / durationMinutes;
|
|
126
|
+
// Estimate cost (approximate - configurable via MonitorConfig.pricing)
|
|
127
|
+
const p = this.config.pricing;
|
|
128
|
+
const estimatedCostUsd = (inputTokens / 1_000_000) * p.input +
|
|
129
|
+
(outputTokens / 1_000_000) * p.output +
|
|
130
|
+
(cacheReadTokens / 1_000_000) * p.cacheRead +
|
|
131
|
+
(cacheWriteTokens / 1_000_000) * p.cacheWrite;
|
|
132
|
+
return {
|
|
133
|
+
tokensPerMinute: Math.round(tokensPerMinute),
|
|
134
|
+
tokensPerHour: Math.round(tokensPerMinute * 60),
|
|
135
|
+
totalConsumed,
|
|
136
|
+
inputTokens,
|
|
137
|
+
outputTokens,
|
|
138
|
+
cacheReadTokens,
|
|
139
|
+
estimatedCostUsd: Math.round(estimatedCostUsd * 100) / 100,
|
|
140
|
+
sessionDurationMinutes: Math.round(durationMinutes * 10) / 10,
|
|
141
|
+
apiCalls: this.entries.length,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// ─── Exhaustion Prediction ────────────────────────────────────
|
|
145
|
+
/** Predict when the token budget will be exhausted. */
|
|
146
|
+
predictExhaustion() {
|
|
147
|
+
const burnRate = this.computeBurnRate();
|
|
148
|
+
if (burnRate.tokensPerMinute === 0) {
|
|
149
|
+
return {
|
|
150
|
+
minutesRemaining: Infinity,
|
|
151
|
+
exhaustionTime: "N/A - no usage detected",
|
|
152
|
+
usageFraction: 0,
|
|
153
|
+
shouldAlert: false,
|
|
154
|
+
alertLevel: "none",
|
|
155
|
+
message: "📊 No token usage detected yet. Start coding!",
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
const remaining = this.config.budgetTokens - burnRate.totalConsumed;
|
|
159
|
+
const minutesRemaining = Math.max(0, remaining / burnRate.tokensPerMinute);
|
|
160
|
+
const exhaustionTime = new Date(Date.now() + minutesRemaining * 60_000).toISOString();
|
|
161
|
+
const usageFraction = burnRate.totalConsumed / this.config.budgetTokens;
|
|
162
|
+
// Determine alert level
|
|
163
|
+
let alertLevel = "none";
|
|
164
|
+
let shouldAlert = false;
|
|
165
|
+
let message = "";
|
|
166
|
+
if (usageFraction >= this.config.criticalThreshold) {
|
|
167
|
+
alertLevel = "critical";
|
|
168
|
+
shouldAlert = true;
|
|
169
|
+
message = `🔴 CRITICAL: ${Math.round(usageFraction * 100)}% of budget consumed! ~${Math.round(minutesRemaining)} min remaining. Switch to Tier 1 compression immediately.`;
|
|
170
|
+
}
|
|
171
|
+
else if (usageFraction >= this.config.warningThreshold) {
|
|
172
|
+
alertLevel = "warning";
|
|
173
|
+
shouldAlert = true;
|
|
174
|
+
message = `🟡 WARNING: ${Math.round(usageFraction * 100)}% of budget consumed. ~${Math.round(minutesRemaining)} min remaining. Consider using nreki_compress for large files.`;
|
|
175
|
+
}
|
|
176
|
+
else if (usageFraction >= 0.5) {
|
|
177
|
+
alertLevel = "info";
|
|
178
|
+
shouldAlert = false;
|
|
179
|
+
message = `🟢 ${Math.round(usageFraction * 100)}% of budget used. ~${Math.round(minutesRemaining)} min remaining at current pace.`;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
alertLevel = "none";
|
|
183
|
+
shouldAlert = false;
|
|
184
|
+
message = `✅ Budget healthy: ${Math.round(usageFraction * 100)}% used. ~${Math.round(minutesRemaining)} min remaining.`;
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
minutesRemaining: Math.round(minutesRemaining),
|
|
188
|
+
exhaustionTime,
|
|
189
|
+
usageFraction: Math.round(usageFraction * 1000) / 1000,
|
|
190
|
+
shouldAlert,
|
|
191
|
+
alertLevel,
|
|
192
|
+
message,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
// ─── Formatted Report ─────────────────────────────────────────
|
|
196
|
+
/** Generate a formatted status report for the nreki_status tool. */
|
|
197
|
+
generateReport() {
|
|
198
|
+
const burnRate = this.computeBurnRate();
|
|
199
|
+
const prediction = this.predictExhaustion();
|
|
200
|
+
const lines = [
|
|
201
|
+
"===========================================",
|
|
202
|
+
" NREKI -- Session Status Report",
|
|
203
|
+
"===========================================",
|
|
204
|
+
"",
|
|
205
|
+
` Burn Rate: ${burnRate.tokensPerMinute.toLocaleString()} tok/min (${burnRate.tokensPerHour.toLocaleString()} tok/hr)`,
|
|
206
|
+
` Total Used: ${burnRate.totalConsumed.toLocaleString()} tokens`,
|
|
207
|
+
` Input: ${burnRate.inputTokens.toLocaleString()} tokens`,
|
|
208
|
+
` Output: ${burnRate.outputTokens.toLocaleString()} tokens`,
|
|
209
|
+
` Cache Reads: ${burnRate.cacheReadTokens.toLocaleString()} tokens (saved)`,
|
|
210
|
+
` Est. Cost: $${burnRate.estimatedCostUsd.toFixed(2)}`,
|
|
211
|
+
` Session: ${burnRate.sessionDurationMinutes} min`,
|
|
212
|
+
` API Calls: ${burnRate.apiCalls}`,
|
|
213
|
+
"",
|
|
214
|
+
"-------------------------------------------",
|
|
215
|
+
` ${prediction.message}`,
|
|
216
|
+
"===========================================",
|
|
217
|
+
];
|
|
218
|
+
return lines.join("\n");
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"monitor.js","sourceRoot":"","sources":["../src/monitor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAuEpB,wEAAwE;AAExE,iGAAiG;AACjG,MAAM,eAAe,GAAG;IACpB,KAAK,EAAE,GAAG,EAAE,4BAA4B;IACxC,MAAM,EAAE,IAAI,EAAE,8BAA8B;IAC5C,SAAS,EAAE,GAAG,EAAE,iCAAiC;IACjD,UAAU,EAAE,IAAI,EAAE,kCAAkC;CACvD,CAAC;AAQF,MAAM,OAAO,YAAY;IACb,OAAO,GAAiB,EAAE,CAAC;IAC3B,MAAM,CAAwB;IAC9B,gBAAgB,GAAG,CAAC,CAAC;IAE7B,YAAY,SAAwB,EAAE;QAClC,IAAI,CAAC,MAAM,GAAG;YACV,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,aAAa,EAAE;YAC/C,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,SAAS;YAC9C,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,IAAI,GAAG;YAChD,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,IAAI,GAAG;YAClD,OAAO,EAAE,EAAE,GAAG,eAAe,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE;SACrD,CAAC;IACN,CAAC;IAED,iEAAiE;IAEjE;;;OAGG;IACK,aAAa;QACjB,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;QAE1B,MAAM,UAAU,GAAG;YACf,wCAAwC;YACxC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,CAAC;YACzC,uBAAuB;YACvB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC;YACnD,yBAAyB;YACzB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC;YAC9D,mCAAmC;YACnC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,aAAa,CAAC;SACrD,CAAC;QAEF,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACjC,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC3B,OAAO,SAAS,CAAC;YACrB,CAAC;QACL,CAAC;QAED,4DAA4D;QAC5D,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,CAAC,CAAC;IACrD,CAAC;IAED,iEAAiE;IAEjE;;;OAGG;IACH,YAAY;QACR,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC,OAAO,CAAC;QACxB,CAAC;QAED,IAAI,CAAC;YACD,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC9D,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAExD,IAAI,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC;gBACpB,MAAM,QAAQ,GAAG,UAAU;qBACtB,KAAK,CAAC,IAAI,CAAC;qBACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;qBAC7B,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;oBACV,IAAI,CAAC;wBACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC;oBAC1C,CAAC;oBAAC,MAAM,CAAC;wBACL,OAAO,IAAI,CAAC;oBAChB,CAAC;gBACL,CAAC,CAAC;qBACD,MAAM,CAAC,CAAC,KAAK,EAAuB,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;gBAE5D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;YACnC,CAAC;YAED,IAAI,CAAC,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CACT,qCAAsC,GAAa,CAAC,OAAO,EAAE,CAChE,CAAC;QACN,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAC;IACxB,CAAC;IAED,iEAAiE;IAEjE,6CAA6C;IAC7C,eAAe;QACX,IAAI,CAAC,YAAY,EAAE,CAAC;QAEpB,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,OAAO;gBACH,eAAe,EAAE,CAAC;gBAClB,aAAa,EAAE,CAAC;gBAChB,aAAa,EAAE,CAAC;gBAChB,WAAW,EAAE,CAAC;gBACd,YAAY,EAAE,CAAC;gBACf,eAAe,EAAE,CAAC;gBAClB,gBAAgB,EAAE,CAAC;gBACnB,sBAAsB,EAAE,CAAC;gBACzB,QAAQ,EAAE,CAAC;aACd,CAAC;QACN,CAAC;QAED,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,eAAe,GAAG,CAAC,CAAC;QACxB,IAAI,gBAAgB,GAAG,CAAC,CAAC;QAEzB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC/B,WAAW,IAAI,KAAK,CAAC,YAAY,IAAI,CAAC,CAAC;YACvC,YAAY,IAAI,KAAK,CAAC,aAAa,IAAI,CAAC,CAAC;YACzC,eAAe,IAAI,KAAK,CAAC,iBAAiB,IAAI,CAAC,CAAC;YAChD,gBAAgB,IAAI,KAAK,CAAC,kBAAkB,IAAI,CAAC,CAAC;QACtD,CAAC;QAED,MAAM,aAAa,GAAG,WAAW,GAAG,YAAY,CAAC;QAEjD,sBAAsB;QACtB,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;QAChE,MAAM,QAAQ,GAAG,IAAI,IAAI,CACrB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,SAAS,CAClD,CAAC,OAAO,EAAE,CAAC;QACZ,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,oBAAoB;QAC/E,MAAM,eAAe,GAAG,UAAU,GAAG,MAAM,CAAC;QAE5C,MAAM,eAAe,GAAG,aAAa,GAAG,eAAe,CAAC;QAExD,uEAAuE;QACvE,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;QAC9B,MAAM,gBAAgB,GAClB,CAAC,WAAW,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK;YACnC,CAAC,YAAY,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,MAAM;YACrC,CAAC,eAAe,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,SAAS;YAC3C,CAAC,gBAAgB,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC;QAElD,OAAO;YACH,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC;YAC5C,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,EAAE,CAAC;YAC/C,aAAa;YACb,WAAW;YACX,YAAY;YACZ,eAAe;YACf,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,gBAAgB,GAAG,GAAG,CAAC,GAAG,GAAG;YAC1D,sBAAsB,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,EAAE,CAAC,GAAG,EAAE;YAC7D,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;SAChC,CAAC;IACN,CAAC;IAED,iEAAiE;IAEjE,uDAAuD;IACvD,iBAAiB;QACb,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAExC,IAAI,QAAQ,CAAC,eAAe,KAAK,CAAC,EAAE,CAAC;YACjC,OAAO;gBACH,gBAAgB,EAAE,QAAQ;gBAC1B,cAAc,EAAE,yBAAyB;gBACzC,aAAa,EAAE,CAAC;gBAChB,WAAW,EAAE,KAAK;gBAClB,UAAU,EAAE,MAAM;gBAClB,OAAO,EAAE,+CAA+C;aAC3D,CAAC;QACN,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,GAAG,QAAQ,CAAC,aAAa,CAAC;QACpE,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAC7B,CAAC,EACD,SAAS,GAAG,QAAQ,CAAC,eAAe,CACvC,CAAC;QACF,MAAM,cAAc,GAAG,IAAI,IAAI,CAC3B,IAAI,CAAC,GAAG,EAAE,GAAG,gBAAgB,GAAG,MAAM,CACzC,CAAC,WAAW,EAAE,CAAC;QAChB,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;QAExE,wBAAwB;QACxB,IAAI,UAAU,GAAuC,MAAM,CAAC;QAC5D,IAAI,WAAW,GAAG,KAAK,CAAC;QACxB,IAAI,OAAO,GAAG,EAAE,CAAC;QAEjB,IAAI,aAAa,IAAI,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC;YACjD,UAAU,GAAG,UAAU,CAAC;YACxB,WAAW,GAAG,IAAI,CAAC;YACnB,OAAO,GAAG,gBAAgB,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,GAAG,CAAC,0BAA0B,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,2DAA2D,CAAC;QAC/K,CAAC;aAAM,IAAI,aAAa,IAAI,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;YACvD,UAAU,GAAG,SAAS,CAAC;YACvB,WAAW,GAAG,IAAI,CAAC;YACnB,OAAO,GAAG,eAAe,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,GAAG,CAAC,0BAA0B,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,gEAAgE,CAAC;QACnL,CAAC;aAAM,IAAI,aAAa,IAAI,GAAG,EAAE,CAAC;YAC9B,UAAU,GAAG,MAAM,CAAC;YACpB,WAAW,GAAG,KAAK,CAAC;YACpB,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,GAAG,CAAC,sBAAsB,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,iCAAiC,CAAC;QACvI,CAAC;aAAM,CAAC;YACJ,UAAU,GAAG,MAAM,CAAC;YACpB,WAAW,GAAG,KAAK,CAAC;YACpB,OAAO,GAAG,qBAAqB,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,GAAG,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,iBAAiB,CAAC;QAC5H,CAAC;QAED,OAAO;YACH,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC;YAC9C,cAAc;YACd,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,IAAI;YACtD,WAAW;YACX,UAAU;YACV,OAAO;SACV,CAAC;IACN,CAAC;IAED,iEAAiE;IAEjE,oEAAoE;IACpE,cAAc;QACV,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QACxC,MAAM,UAAU,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAE5C,MAAM,KAAK,GAAG;YACV,6CAA6C;YAC7C,kCAAkC;YAClC,6CAA6C;YAC7C,EAAE;YACF,oBAAoB,QAAQ,CAAC,eAAe,CAAC,cAAc,EAAE,aAAa,QAAQ,CAAC,aAAa,CAAC,cAAc,EAAE,UAAU;YAC3H,oBAAoB,QAAQ,CAAC,aAAa,CAAC,cAAc,EAAE,SAAS;YACpE,oBAAoB,QAAQ,CAAC,WAAW,CAAC,cAAc,EAAE,SAAS;YAClE,oBAAoB,QAAQ,CAAC,YAAY,CAAC,cAAc,EAAE,SAAS;YACnE,oBAAoB,QAAQ,CAAC,eAAe,CAAC,cAAc,EAAE,iBAAiB;YAC9E,qBAAqB,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;YAC3D,oBAAoB,QAAQ,CAAC,sBAAsB,MAAM;YACzD,oBAAoB,QAAQ,CAAC,QAAQ,EAAE;YACvC,EAAE;YACF,6CAA6C;YAC7C,KAAK,UAAU,CAAC,OAAO,EAAE;YACzB,6CAA6C;SAChD,CAAC;QAEF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;CACJ"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parser-pool.ts - Thread-safe parser pool for web-tree-sitter.
|
|
3
|
+
*
|
|
4
|
+
* Solves the race condition where a single Parser instance shared across
|
|
5
|
+
* concurrent calls can have setLanguage() interleaved with parse().
|
|
6
|
+
* Each acquire() returns a Parser with the language already set.
|
|
7
|
+
* Backpressure: if all parsers are in use, callers wait until one is released.
|
|
8
|
+
*/
|
|
9
|
+
import Parser from "web-tree-sitter";
|
|
10
|
+
export declare class ParserPool {
|
|
11
|
+
private pools;
|
|
12
|
+
private counts;
|
|
13
|
+
private waiters;
|
|
14
|
+
private readonly maxPerLang;
|
|
15
|
+
private initialized;
|
|
16
|
+
constructor(maxPerLang?: number);
|
|
17
|
+
/** Initialize the WASM runtime. Idempotent. */
|
|
18
|
+
initialize(): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Acquire a parser with the given language already set.
|
|
21
|
+
* Returns an idle parser from the pool, creates a new one (up to max),
|
|
22
|
+
* or waits for a release if at capacity.
|
|
23
|
+
*/
|
|
24
|
+
acquire(lang: Parser.Language, langKey: string): Promise<Parser>;
|
|
25
|
+
/** Return a parser to the pool or hand it to a waiting caller. */
|
|
26
|
+
release(langKey: string, parser: Parser): void;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=parser-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser-pool.d.ts","sourceRoot":"","sources":["../src/parser-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,MAAM,MAAM,iBAAiB,CAAC;AAErC,qBAAa,UAAU;IACnB,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,OAAO,CAAiD;IAChE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,WAAW,CAAS;gBAEhB,UAAU,GAAE,MAAU;IAIlC,+CAA+C;IACzC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC;;;;OAIG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA2CtE,kEAAkE;IAClE,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;CAYjD"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parser-pool.ts - Thread-safe parser pool for web-tree-sitter.
|
|
3
|
+
*
|
|
4
|
+
* Solves the race condition where a single Parser instance shared across
|
|
5
|
+
* concurrent calls can have setLanguage() interleaved with parse().
|
|
6
|
+
* Each acquire() returns a Parser with the language already set.
|
|
7
|
+
* Backpressure: if all parsers are in use, callers wait until one is released.
|
|
8
|
+
*/
|
|
9
|
+
import Parser from "web-tree-sitter";
|
|
10
|
+
export class ParserPool {
|
|
11
|
+
pools = new Map();
|
|
12
|
+
counts = new Map();
|
|
13
|
+
waiters = new Map();
|
|
14
|
+
maxPerLang;
|
|
15
|
+
initialized = false;
|
|
16
|
+
constructor(maxPerLang = 4) {
|
|
17
|
+
this.maxPerLang = maxPerLang;
|
|
18
|
+
}
|
|
19
|
+
/** Initialize the WASM runtime. Idempotent. */
|
|
20
|
+
async initialize() {
|
|
21
|
+
if (this.initialized)
|
|
22
|
+
return;
|
|
23
|
+
await Parser.init();
|
|
24
|
+
this.initialized = true;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Acquire a parser with the given language already set.
|
|
28
|
+
* Returns an idle parser from the pool, creates a new one (up to max),
|
|
29
|
+
* or waits for a release if at capacity.
|
|
30
|
+
*/
|
|
31
|
+
async acquire(lang, langKey) {
|
|
32
|
+
await this.initialize();
|
|
33
|
+
const pool = this.pools.get(langKey) ?? [];
|
|
34
|
+
this.pools.set(langKey, pool);
|
|
35
|
+
if (pool.length > 0) {
|
|
36
|
+
const parser = pool.pop();
|
|
37
|
+
parser.setLanguage(lang);
|
|
38
|
+
return parser;
|
|
39
|
+
}
|
|
40
|
+
const count = this.counts.get(langKey) ?? 0;
|
|
41
|
+
if (count < this.maxPerLang) {
|
|
42
|
+
this.counts.set(langKey, count + 1);
|
|
43
|
+
const parser = new Parser();
|
|
44
|
+
parser.setLanguage(lang);
|
|
45
|
+
return parser;
|
|
46
|
+
}
|
|
47
|
+
// Backpressure: wait for a parser to be released (with timeout)
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
const timer = setTimeout(() => {
|
|
50
|
+
const q = this.waiters.get(langKey);
|
|
51
|
+
if (q) {
|
|
52
|
+
const idx = q.indexOf(cb);
|
|
53
|
+
if (idx >= 0)
|
|
54
|
+
q.splice(idx, 1);
|
|
55
|
+
}
|
|
56
|
+
reject(new Error(`[NREKI] ParserPool.acquire("${langKey}") timed out after 30000ms`));
|
|
57
|
+
}, 30_000);
|
|
58
|
+
const cb = (p) => {
|
|
59
|
+
clearTimeout(timer);
|
|
60
|
+
p.setLanguage(lang);
|
|
61
|
+
resolve(p);
|
|
62
|
+
};
|
|
63
|
+
const q = this.waiters.get(langKey) ?? [];
|
|
64
|
+
this.waiters.set(langKey, q);
|
|
65
|
+
q.push(cb);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/** Return a parser to the pool or hand it to a waiting caller. */
|
|
69
|
+
release(langKey, parser) {
|
|
70
|
+
const q = this.waiters.get(langKey);
|
|
71
|
+
if (q && q.length > 0) {
|
|
72
|
+
const next = q.shift();
|
|
73
|
+
next(parser);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const pool = this.pools.get(langKey) ?? [];
|
|
77
|
+
this.pools.set(langKey, pool);
|
|
78
|
+
pool.push(parser);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=parser-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser-pool.js","sourceRoot":"","sources":["../src/parser-pool.ts"],"names":[],"mappings":"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"}
|
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* parser.ts - Universal AST parser for NREKI.
|
|
3
|
+
*
|
|
4
|
+
* Wraps web-tree-sitter to parse TypeScript, JavaScript, Python, and Go
|
|
5
|
+
* source files into semantic chunks. Each chunk is an AST node (class,
|
|
6
|
+
* function, method, interface) compressed into shorthand notation.
|
|
7
|
+
*
|
|
8
|
+
* Shorthand format: `[type] signature { /* TG:L42-L67 */ }`
|
|
9
|
+
* This preserves structure while stripping implementation - ~18% savings.
|
|
10
|
+
*/
|
|
11
|
+
import Parser from "web-tree-sitter";
|
|
12
|
+
export interface ParsedChunk {
|
|
13
|
+
/** Shorthand AST signature (compressed). */
|
|
14
|
+
shorthand: string;
|
|
15
|
+
/** Full raw source code of the node. */
|
|
16
|
+
rawCode: string;
|
|
17
|
+
/** AST node type: class, func, method, interface, etc. */
|
|
18
|
+
nodeType: string;
|
|
19
|
+
/** 1-indexed start line in the source file. */
|
|
20
|
+
startLine: number;
|
|
21
|
+
/** 1-indexed end line in the source file. */
|
|
22
|
+
endLine: number;
|
|
23
|
+
/** Absolute byte offset of the node start in the source file. */
|
|
24
|
+
startIndex: number;
|
|
25
|
+
/** Absolute byte offset of the node end in the source file. */
|
|
26
|
+
endIndex: number;
|
|
27
|
+
/** Symbol name extracted directly from AST name captures. */
|
|
28
|
+
symbolName: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ParseResult {
|
|
31
|
+
/** File path that was parsed. */
|
|
32
|
+
filePath: string;
|
|
33
|
+
/** Extracted AST chunks. */
|
|
34
|
+
chunks: ParsedChunk[];
|
|
35
|
+
/** Total lines in the source file. */
|
|
36
|
+
totalLines: number;
|
|
37
|
+
/** Language that was detected. */
|
|
38
|
+
language: string;
|
|
39
|
+
}
|
|
40
|
+
/** Supported language extensions. */
|
|
41
|
+
export type SupportedExtension = ".ts" | ".tsx" | ".js" | ".jsx" | ".py" | ".go";
|
|
42
|
+
export declare class ASTParser {
|
|
43
|
+
private parser;
|
|
44
|
+
private languageCache;
|
|
45
|
+
private languagePromises;
|
|
46
|
+
private queryCache;
|
|
47
|
+
private wasmDir;
|
|
48
|
+
private initialized;
|
|
49
|
+
constructor(wasmDir?: string);
|
|
50
|
+
/** Initialize the Tree-sitter WASM runtime. Must be called once. */
|
|
51
|
+
initialize(): Promise<void>;
|
|
52
|
+
/** Check if a file extension is supported. */
|
|
53
|
+
isSupported(ext: string): boolean;
|
|
54
|
+
/** Get supported file extensions. */
|
|
55
|
+
getSupportedExtensions(): string[];
|
|
56
|
+
/** Load a Tree-sitter language grammar from WASM. A-08: Deduplicates concurrent loads. */
|
|
57
|
+
private loadLanguage;
|
|
58
|
+
/** Get or create a Tree-sitter query for a language. */
|
|
59
|
+
private getQuery;
|
|
60
|
+
/**
|
|
61
|
+
* Parse a source file into semantic AST chunks.
|
|
62
|
+
*
|
|
63
|
+
* Each chunk contains:
|
|
64
|
+
* - shorthand: compressed signature (e.g., `[func] processFile(path: string) { /* TG:L12-L45 */ }`)
|
|
65
|
+
* - rawCode: the full implementation
|
|
66
|
+
* - nodeType: class, func, method, etc.
|
|
67
|
+
* - startLine/endLine: location in the original file
|
|
68
|
+
*/
|
|
69
|
+
parse(filePath: string, content: string): Promise<ParseResult>;
|
|
70
|
+
/**
|
|
71
|
+
* Parse a file and provide raw tree-sitter tree access via callback.
|
|
72
|
+
* Guarantees WASM memory cleanup via try/finally.
|
|
73
|
+
* Returns null if the file extension is unsupported.
|
|
74
|
+
*/
|
|
75
|
+
parseRaw<T>(filePath: string, content: string, callback: (tree: Parser.Tree, language: Parser.Language) => T): Promise<T | null>;
|
|
76
|
+
/**
|
|
77
|
+
* Generate compressed shorthand for an AST node.
|
|
78
|
+
*
|
|
79
|
+
* Strategy:
|
|
80
|
+
* 1. Extract the signature (everything before the first `{` or `:`)
|
|
81
|
+
* 2. Collapse the body into a TG marker with line range
|
|
82
|
+
* 3. Result: `[func] myFunction(a: string, b: number): void { /* TG:L12-L45 */ }`
|
|
83
|
+
*
|
|
84
|
+
* This preserves enough context for semantic search while
|
|
85
|
+
* cutting token count by ~60-80% per chunk.
|
|
86
|
+
*/
|
|
87
|
+
private generateShorthand;
|
|
88
|
+
/** Normalize Tree-sitter capture names to clean node types. */
|
|
89
|
+
private normalizeNodeType;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,MAAM,MAAM,iBAAiB,CAAC;AAOrC,MAAM,WAAW,WAAW;IACxB,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IACxB,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,qCAAqC;AACrC,MAAM,MAAM,kBAAkB,GACxB,KAAK,GACL,MAAM,GACN,KAAK,GACL,MAAM,GACN,KAAK,GACL,KAAK,CAAC;AA+EZ,qBAAa,SAAS;IAClB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,aAAa,CAAsC;IAC3D,OAAO,CAAC,gBAAgB,CAAsD;IAC9E,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,CAAC,EAAE,MAAM;IAM5B,oEAAoE;IAC9D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IASjC,8CAA8C;IAC9C,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIjC,qCAAqC;IACrC,sBAAsB,IAAI,MAAM,EAAE;IAIlC,0FAA0F;YAC5E,YAAY;IAiC1B,wDAAwD;IACxD,OAAO,CAAC,QAAQ;IAsBhB;;;;;;;;OAQG;IACG,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAgFpE;;;;OAIG;IACG,QAAQ,CAAC,CAAC,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,KAAK,CAAC,GAC9D,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAWpB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,iBAAiB;IAiDzB,+DAA+D;IAC/D,OAAO,CAAC,iBAAiB;CAgB5B"}
|