@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.
Files changed (150) hide show
  1. package/CHANGELOG.md +648 -0
  2. package/LICENSE +21 -0
  3. package/README.md +425 -0
  4. package/dist/ast-navigator.d.ts +29 -0
  5. package/dist/ast-navigator.d.ts.map +1 -0
  6. package/dist/ast-navigator.js +279 -0
  7. package/dist/ast-navigator.js.map +1 -0
  8. package/dist/ast-sandbox.d.ts +74 -0
  9. package/dist/ast-sandbox.d.ts.map +1 -0
  10. package/dist/ast-sandbox.js +242 -0
  11. package/dist/ast-sandbox.js.map +1 -0
  12. package/dist/chronos-memory.d.ts +69 -0
  13. package/dist/chronos-memory.d.ts.map +1 -0
  14. package/dist/chronos-memory.js +247 -0
  15. package/dist/chronos-memory.js.map +1 -0
  16. package/dist/circuit-breaker.d.ts +107 -0
  17. package/dist/circuit-breaker.d.ts.map +1 -0
  18. package/dist/circuit-breaker.js +330 -0
  19. package/dist/circuit-breaker.js.map +1 -0
  20. package/dist/compressor-advanced.d.ts +80 -0
  21. package/dist/compressor-advanced.d.ts.map +1 -0
  22. package/dist/compressor-advanced.js +555 -0
  23. package/dist/compressor-advanced.js.map +1 -0
  24. package/dist/compressor.d.ts +81 -0
  25. package/dist/compressor.d.ts.map +1 -0
  26. package/dist/compressor.js +227 -0
  27. package/dist/compressor.js.map +1 -0
  28. package/dist/database.d.ts +169 -0
  29. package/dist/database.d.ts.map +1 -0
  30. package/dist/database.js +1029 -0
  31. package/dist/database.js.map +1 -0
  32. package/dist/embedder.d.ts +73 -0
  33. package/dist/embedder.d.ts.map +1 -0
  34. package/dist/embedder.js +165 -0
  35. package/dist/embedder.js.map +1 -0
  36. package/dist/engine.d.ts +224 -0
  37. package/dist/engine.d.ts.map +1 -0
  38. package/dist/engine.js +582 -0
  39. package/dist/engine.js.map +1 -0
  40. package/dist/hologram/harvester.d.ts +41 -0
  41. package/dist/hologram/harvester.d.ts.map +1 -0
  42. package/dist/hologram/harvester.js +129 -0
  43. package/dist/hologram/harvester.js.map +1 -0
  44. package/dist/hologram/shadow-cache.d.ts +49 -0
  45. package/dist/hologram/shadow-cache.d.ts.map +1 -0
  46. package/dist/hologram/shadow-cache.js +165 -0
  47. package/dist/hologram/shadow-cache.js.map +1 -0
  48. package/dist/hologram/shadow-generator.d.ts +32 -0
  49. package/dist/hologram/shadow-generator.d.ts.map +1 -0
  50. package/dist/hologram/shadow-generator.js +828 -0
  51. package/dist/hologram/shadow-generator.js.map +1 -0
  52. package/dist/hooks/preToolUse.d.ts +63 -0
  53. package/dist/hooks/preToolUse.d.ts.map +1 -0
  54. package/dist/hooks/preToolUse.js +103 -0
  55. package/dist/hooks/preToolUse.js.map +1 -0
  56. package/dist/index.d.ts +19 -0
  57. package/dist/index.d.ts.map +1 -0
  58. package/dist/index.js +367 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/kernel/kernel-manager.d.ts +52 -0
  61. package/dist/kernel/kernel-manager.d.ts.map +1 -0
  62. package/dist/kernel/kernel-manager.js +197 -0
  63. package/dist/kernel/kernel-manager.js.map +1 -0
  64. package/dist/kernel/kernel-worker.d.ts +9 -0
  65. package/dist/kernel/kernel-worker.d.ts.map +1 -0
  66. package/dist/kernel/kernel-worker.js +76 -0
  67. package/dist/kernel/kernel-worker.js.map +1 -0
  68. package/dist/kernel/nreki-kernel.d.ts +244 -0
  69. package/dist/kernel/nreki-kernel.d.ts.map +1 -0
  70. package/dist/kernel/nreki-kernel.js +1656 -0
  71. package/dist/kernel/nreki-kernel.js.map +1 -0
  72. package/dist/middleware/circuit-breaker.d.ts +32 -0
  73. package/dist/middleware/circuit-breaker.d.ts.map +1 -0
  74. package/dist/middleware/circuit-breaker.js +160 -0
  75. package/dist/middleware/circuit-breaker.js.map +1 -0
  76. package/dist/middleware/file-lock.d.ts +33 -0
  77. package/dist/middleware/file-lock.d.ts.map +1 -0
  78. package/dist/middleware/file-lock.js +55 -0
  79. package/dist/middleware/file-lock.js.map +1 -0
  80. package/dist/middleware/validator.d.ts +26 -0
  81. package/dist/middleware/validator.d.ts.map +1 -0
  82. package/dist/middleware/validator.js +39 -0
  83. package/dist/middleware/validator.js.map +1 -0
  84. package/dist/monitor.d.ts +94 -0
  85. package/dist/monitor.d.ts.map +1 -0
  86. package/dist/monitor.js +221 -0
  87. package/dist/monitor.js.map +1 -0
  88. package/dist/parser-pool.d.ts +28 -0
  89. package/dist/parser-pool.d.ts.map +1 -0
  90. package/dist/parser-pool.js +81 -0
  91. package/dist/parser-pool.js.map +1 -0
  92. package/dist/parser.d.ts +91 -0
  93. package/dist/parser.d.ts.map +1 -0
  94. package/dist/parser.js +311 -0
  95. package/dist/parser.js.map +1 -0
  96. package/dist/pin-memory.d.ts +35 -0
  97. package/dist/pin-memory.d.ts.map +1 -0
  98. package/dist/pin-memory.js +161 -0
  99. package/dist/pin-memory.js.map +1 -0
  100. package/dist/repo-map.d.ts +81 -0
  101. package/dist/repo-map.d.ts.map +1 -0
  102. package/dist/repo-map.js +550 -0
  103. package/dist/repo-map.js.map +1 -0
  104. package/dist/router.d.ts +102 -0
  105. package/dist/router.d.ts.map +1 -0
  106. package/dist/router.js +1989 -0
  107. package/dist/router.js.map +1 -0
  108. package/dist/semantic-edit.d.ts +82 -0
  109. package/dist/semantic-edit.d.ts.map +1 -0
  110. package/dist/semantic-edit.js +529 -0
  111. package/dist/semantic-edit.js.map +1 -0
  112. package/dist/terminal-filter.d.ts +27 -0
  113. package/dist/terminal-filter.d.ts.map +1 -0
  114. package/dist/terminal-filter.js +257 -0
  115. package/dist/terminal-filter.js.map +1 -0
  116. package/dist/undo.d.ts +21 -0
  117. package/dist/undo.d.ts.map +1 -0
  118. package/dist/undo.js +55 -0
  119. package/dist/undo.js.map +1 -0
  120. package/dist/utils/code-tokenizer.d.ts +25 -0
  121. package/dist/utils/code-tokenizer.d.ts.map +1 -0
  122. package/dist/utils/code-tokenizer.js +52 -0
  123. package/dist/utils/code-tokenizer.js.map +1 -0
  124. package/dist/utils/file-filter.d.ts +23 -0
  125. package/dist/utils/file-filter.d.ts.map +1 -0
  126. package/dist/utils/file-filter.js +48 -0
  127. package/dist/utils/file-filter.js.map +1 -0
  128. package/dist/utils/imports.d.ts +32 -0
  129. package/dist/utils/imports.d.ts.map +1 -0
  130. package/dist/utils/imports.js +155 -0
  131. package/dist/utils/imports.js.map +1 -0
  132. package/dist/utils/path-jail.d.ts +27 -0
  133. package/dist/utils/path-jail.d.ts.map +1 -0
  134. package/dist/utils/path-jail.js +95 -0
  135. package/dist/utils/path-jail.js.map +1 -0
  136. package/dist/utils/read-source.d.ts +18 -0
  137. package/dist/utils/read-source.d.ts.map +1 -0
  138. package/dist/utils/read-source.js +22 -0
  139. package/dist/utils/read-source.js.map +1 -0
  140. package/dist/utils/safe-parse.d.ts +20 -0
  141. package/dist/utils/safe-parse.d.ts.map +1 -0
  142. package/dist/utils/safe-parse.js +25 -0
  143. package/dist/utils/safe-parse.js.map +1 -0
  144. package/package.json +75 -0
  145. package/scripts/download-wasm.js +46 -0
  146. package/wasm/.gitkeep +0 -0
  147. package/wasm/tree-sitter-go.wasm +0 -0
  148. package/wasm/tree-sitter-javascript.wasm +0 -0
  149. package/wasm/tree-sitter-python.wasm +0 -0
  150. package/wasm/tree-sitter-typescript.wasm +0 -0
@@ -0,0 +1,279 @@
1
+ /**
2
+ * ast-navigator.ts - Deterministic AST navigation for NREKI.
3
+ *
4
+ * Provides go-to-definition, find-references, and file-outline using
5
+ * tree-sitter AST parsing. 100% precise, no vector search needed.
6
+ * Typical latency: 3-50ms vs 900ms+ for embedding-based search.
7
+ */
8
+ import fs from "fs";
9
+ import path from "path";
10
+ import { shouldProcess } from "./utils/file-filter.js";
11
+ import { readSource } from "./utils/read-source.js";
12
+ // ─── Constants ──────────────────────────────────────────────────────
13
+ const SUPPORTED_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".py", ".go"]);
14
+ const IGNORE_DIRS = new Set([
15
+ "node_modules", "dist", "build", ".git", "coverage",
16
+ ".next", "__pycache__", ".nreki",
17
+ ]);
18
+ // Map parser nodeType to user-facing kind
19
+ const NODE_TYPE_TO_KIND = {
20
+ func: "function",
21
+ class: "class",
22
+ method: "method",
23
+ interface: "interface",
24
+ type: "type",
25
+ type_decl: "type",
26
+ };
27
+ // ─── File Walking ───────────────────────────────────────────────────
28
+ function walkFiles(dirPath) {
29
+ const files = [];
30
+ const walk = (dir) => {
31
+ let entries;
32
+ try {
33
+ entries = fs.readdirSync(dir, { withFileTypes: true });
34
+ }
35
+ catch {
36
+ return;
37
+ }
38
+ for (const entry of entries) {
39
+ const fullPath = path.join(dir, entry.name);
40
+ if (entry.isDirectory()) {
41
+ if (!IGNORE_DIRS.has(entry.name))
42
+ walk(fullPath);
43
+ continue;
44
+ }
45
+ const ext = path.extname(entry.name).toLowerCase();
46
+ if (!SUPPORTED_EXTENSIONS.has(ext))
47
+ continue;
48
+ if (entry.name.endsWith(".d.ts"))
49
+ continue;
50
+ try {
51
+ const stat = fs.statSync(fullPath);
52
+ const filter = shouldProcess(fullPath, stat.size);
53
+ if (filter.process)
54
+ files.push(fullPath);
55
+ }
56
+ catch {
57
+ // Skip inaccessible files
58
+ }
59
+ }
60
+ };
61
+ walk(dirPath);
62
+ return files.sort();
63
+ }
64
+ // ─── Signature Extraction ───────────────────────────────────────────
65
+ function extractSignature(rawCode) {
66
+ const lines = rawCode.split("\n");
67
+ if (lines.length <= 1)
68
+ return rawCode.trim();
69
+ let parenDepth = 0;
70
+ let angleDepth = 0;
71
+ for (let i = 0; i < rawCode.length; i++) {
72
+ const ch = rawCode[i];
73
+ if (ch === "(")
74
+ parenDepth++;
75
+ else if (ch === ")")
76
+ parenDepth--;
77
+ else if (ch === "<")
78
+ angleDepth++;
79
+ else if (ch === ">")
80
+ angleDepth--;
81
+ else if (ch === "{" && parenDepth === 0 && angleDepth === 0) {
82
+ return rawCode.slice(0, i).trim();
83
+ }
84
+ // A-02: Python colon - only match at depth 0 (skip colons inside type hints)
85
+ else if (ch === ":" && parenDepth === 0 && angleDepth === 0) {
86
+ if (/^(?:async\s+)?def\s|^class\s/.test(rawCode)) {
87
+ return rawCode.slice(0, i).trim();
88
+ }
89
+ }
90
+ }
91
+ return lines[0].trim();
92
+ }
93
+ /** Extract the symbol name from a chunk's raw code. */
94
+ function extractName(chunk) {
95
+ const raw = chunk.rawCode.trim();
96
+ // TS/JS patterns
97
+ let m;
98
+ // TS/JS: Arrow functions (export const foo = async () => ...)
99
+ m = /(?:export\s+)?(?:default\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:(?:<[^>]*>\s*)?\([^)]*\)|[a-zA-Z0-9_]+)\s*=>/.exec(raw);
100
+ if (m)
101
+ return m[1];
102
+ // export [default] [async] function NAME
103
+ m = /(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s+(\w+)/.exec(raw);
104
+ if (m)
105
+ return m[1];
106
+ // export [default] class NAME
107
+ m = /(?:export\s+)?(?:default\s+)?(?:abstract\s+)?class\s+(\w+)/.exec(raw);
108
+ if (m)
109
+ return m[1];
110
+ // export interface NAME
111
+ m = /(?:export\s+)?interface\s+(\w+)/.exec(raw);
112
+ if (m)
113
+ return m[1];
114
+ // export type NAME
115
+ m = /(?:export\s+)?type\s+(\w+)/.exec(raw);
116
+ if (m)
117
+ return m[1];
118
+ // export enum NAME
119
+ m = /(?:export\s+)?enum\s+(\w+)/.exec(raw);
120
+ if (m)
121
+ return m[1];
122
+ // method: [async] NAME(
123
+ m = /(?:async\s+)?(?:static\s+)?(?:readonly\s+)?(?:public\s+|private\s+|protected\s+)?(\w+)\s*[(<]/.exec(raw);
124
+ if (m)
125
+ return m[1];
126
+ // Python: def NAME / class NAME
127
+ m = /(?:async\s+)?def\s+(\w+)/.exec(raw);
128
+ if (m)
129
+ return m[1];
130
+ m = /class\s+(\w+)/.exec(raw);
131
+ if (m)
132
+ return m[1];
133
+ // Go: func NAME / func (receiver) NAME
134
+ m = /func\s+(?:\([^)]*\)\s+)?(\w+)/.exec(raw);
135
+ if (m)
136
+ return m[1];
137
+ // Go: type NAME
138
+ m = /type\s+(\w+)/.exec(raw);
139
+ if (m)
140
+ return m[1];
141
+ // Fallback: first word-like token
142
+ m = /(\w+)/.exec(raw);
143
+ return m ? m[1] : "";
144
+ }
145
+ /** Determine if a chunk is exported. Checks rawCode and falls back to the original source line. */
146
+ function getExportStatus(rawCode, contentLines, startLine) {
147
+ const trimmed = rawCode.trim();
148
+ if (trimmed.startsWith("export default "))
149
+ return "default";
150
+ if (trimmed.startsWith("export "))
151
+ return "named";
152
+ // Tree-sitter may capture inner nodes (e.g., type_alias_declaration without export wrapper).
153
+ // Check the original source line for the export keyword.
154
+ if (contentLines && startLine) {
155
+ const line = contentLines[startLine - 1]; // 1-indexed
156
+ if (line) {
157
+ const lineTrimmed = line.trim();
158
+ if (lineTrimmed.startsWith("export default "))
159
+ return "default";
160
+ if (lineTrimmed.startsWith("export "))
161
+ return "named";
162
+ }
163
+ }
164
+ return null;
165
+ }
166
+ // ─── Core Navigation Functions ──────────────────────────────────────
167
+ export async function findDefinition(projectRoot, parser, symbolName, kind = "any") {
168
+ await parser.initialize();
169
+ const files = walkFiles(projectRoot);
170
+ const exact = [];
171
+ const partial = [];
172
+ const lowerSymbol = symbolName.toLowerCase();
173
+ for (const filePath of files) {
174
+ const ext = path.extname(filePath).toLowerCase();
175
+ if (!parser.isSupported(ext))
176
+ continue;
177
+ let content;
178
+ try {
179
+ content = readSource(filePath);
180
+ }
181
+ catch {
182
+ continue;
183
+ }
184
+ const result = await parser.parse(filePath, content);
185
+ const contentLines = content.split("\n");
186
+ for (const chunk of result.chunks) {
187
+ const name = extractName(chunk);
188
+ if (!name)
189
+ continue;
190
+ // Kind filtering
191
+ const chunkKind = NODE_TYPE_TO_KIND[chunk.nodeType] || chunk.nodeType;
192
+ if (kind !== "any" && chunkKind !== kind)
193
+ continue;
194
+ const relPath = path.relative(projectRoot, filePath).replace(/\\/g, "/");
195
+ const def = {
196
+ filePath: relPath,
197
+ name,
198
+ kind: chunkKind,
199
+ signature: extractSignature(chunk.rawCode),
200
+ body: chunk.rawCode,
201
+ startLine: chunk.startLine,
202
+ endLine: chunk.endLine,
203
+ exportedAs: getExportStatus(chunk.rawCode, contentLines, chunk.startLine),
204
+ };
205
+ if (name === symbolName) {
206
+ exact.push(def);
207
+ }
208
+ else if (name.toLowerCase() === lowerSymbol) {
209
+ partial.push(def);
210
+ }
211
+ }
212
+ }
213
+ // Exact matches first, then case-insensitive matches
214
+ return [...exact, ...partial];
215
+ }
216
+ export async function findReferences(projectRoot, parser, symbolName) {
217
+ await parser.initialize();
218
+ const files = walkFiles(projectRoot);
219
+ const results = [];
220
+ // Word boundary regex for the symbol
221
+ const symbolRe = new RegExp(`\\b${symbolName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, "g");
222
+ for (const filePath of files) {
223
+ let content;
224
+ try {
225
+ content = readSource(filePath);
226
+ }
227
+ catch {
228
+ continue;
229
+ }
230
+ const lines = content.split("\n");
231
+ const relPath = path.relative(projectRoot, filePath).replace(/\\/g, "/");
232
+ for (let i = 0; i < lines.length; i++) {
233
+ symbolRe.lastIndex = 0;
234
+ const match = symbolRe.exec(lines[i]);
235
+ if (!match)
236
+ continue;
237
+ // Build context: line + 1 line above and below
238
+ const ctxStart = Math.max(0, i - 1);
239
+ const ctxEnd = Math.min(lines.length - 1, i + 1);
240
+ const context = lines.slice(ctxStart, ctxEnd + 1).join("\n");
241
+ results.push({
242
+ filePath: relPath,
243
+ line: i + 1, // 1-indexed
244
+ column: match.index + 1,
245
+ context,
246
+ });
247
+ }
248
+ }
249
+ return results;
250
+ }
251
+ export async function getFileSymbols(filePath, parser, projectRoot) {
252
+ await parser.initialize();
253
+ const ext = path.extname(filePath).toLowerCase();
254
+ if (!parser.isSupported(ext))
255
+ return [];
256
+ let content;
257
+ try {
258
+ content = readSource(filePath);
259
+ }
260
+ catch {
261
+ return [];
262
+ }
263
+ const result = await parser.parse(filePath, content);
264
+ const contentLines = content.split("\n");
265
+ const relPath = projectRoot
266
+ ? path.relative(projectRoot, filePath).replace(/\\/g, "/")
267
+ : filePath;
268
+ return result.chunks.map((chunk) => ({
269
+ filePath: relPath,
270
+ name: extractName(chunk),
271
+ kind: NODE_TYPE_TO_KIND[chunk.nodeType] || chunk.nodeType,
272
+ signature: extractSignature(chunk.rawCode),
273
+ body: chunk.rawCode,
274
+ startLine: chunk.startLine,
275
+ endLine: chunk.endLine,
276
+ exportedAs: getExportStatus(chunk.rawCode, contentLines, chunk.startLine),
277
+ }));
278
+ }
279
+ //# sourceMappingURL=ast-navigator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-navigator.js","sourceRoot":"","sources":["../src/ast-navigator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * ast-sandbox.ts - AST-based code validator for NREKI.
3
+ *
4
+ * Intercepts code BEFORE it's written to disk. Parses with tree-sitter
5
+ * and walks the AST looking for ERROR/MISSING nodes. If found, rejects
6
+ * the code with specific error locations and fix suggestions.
7
+ *
8
+ * This prevents the "write broken code → see error → fix → fail again"
9
+ * loop that burns tokens.
10
+ */
11
+ export interface AstError {
12
+ /** 1-indexed line number. */
13
+ line: number;
14
+ /** 1-indexed column number. */
15
+ column: number;
16
+ /** Node type: "ERROR" or "MISSING(<expected>)". */
17
+ nodeType: string;
18
+ /** The source line containing the error. */
19
+ context: string;
20
+ }
21
+ export interface ValidationResult {
22
+ /** True if the code has zero syntax errors. */
23
+ valid: boolean;
24
+ /** List of all detected syntax errors. */
25
+ errors: AstError[];
26
+ /** Human-readable fix suggestions. */
27
+ suggestion: string;
28
+ }
29
+ export declare class AstSandbox {
30
+ private pool;
31
+ private languageCache;
32
+ private languagePromises;
33
+ private wasmDir;
34
+ private initialized;
35
+ constructor(wasmDir?: string);
36
+ /** Initialize the Tree-sitter WASM runtime. Must be called once. */
37
+ initialize(): Promise<void>;
38
+ /** Get supported language names. */
39
+ getSupportedLanguages(): string[];
40
+ /** Detect language from a file extension. */
41
+ detectLanguage(filePath: string): string | null;
42
+ /** A-08: Deduplicates concurrent WASM loads. */
43
+ private loadLanguage;
44
+ /**
45
+ * Validate code syntax using tree-sitter AST analysis.
46
+ *
47
+ * Parses the code and walks the resulting tree looking for
48
+ * ERROR and MISSING nodes. Returns specific error locations
49
+ * with human-readable fix suggestions.
50
+ */
51
+ validateCode(code: string, language: string): Promise<ValidationResult>;
52
+ /**
53
+ * Validate new code against the original, showing what changed.
54
+ *
55
+ * Parses the NEW code only. If it has errors, enhances the
56
+ * error context by showing the original line vs the new line.
57
+ */
58
+ validateDiff(originalCode: string, newCode: string, language: string): Promise<ValidationResult>;
59
+ /**
60
+ * Recursively walk the AST looking for ERROR and MISSING nodes.
61
+ *
62
+ * Uses hasError to skip clean subtrees (optimization for large files).
63
+ * Does not descend into ERROR nodes (their children are unparsed tokens).
64
+ */
65
+ private walkForErrors;
66
+ /**
67
+ * Generate human-readable fix suggestions from error nodes.
68
+ *
69
+ * Combines error location, context line, and heuristic hints
70
+ * to help Claude understand exactly what went wrong.
71
+ */
72
+ private generateSuggestion;
73
+ }
74
+ //# sourceMappingURL=ast-sandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-sandbox.d.ts","sourceRoot":"","sources":["../src/ast-sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,MAAM,WAAW,QAAQ;IACrB,6BAA6B;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC7B,+CAA+C;IAC/C,KAAK,EAAE,OAAO,CAAC;IACf,0CAA0C;IAC1C,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,sCAAsC;IACtC,UAAU,EAAE,MAAM,CAAC;CACtB;AAuBD,qBAAa,UAAU;IACnB,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,aAAa,CAAsC;IAC3D,OAAO,CAAC,gBAAgB,CAAsD;IAC9E,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAS;gBAEhB,OAAO,CAAC,EAAE,MAAM;IAM5B,oEAAoE;IAC9D,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC,oCAAoC;IACpC,qBAAqB,IAAI,MAAM,EAAE;IAIjC,6CAA6C;IAC7C,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAO/C,gDAAgD;YAClC,YAAY;IA+B1B;;;;;;OAMG;IACG,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA6C7E;;;;;OAKG;IACG,YAAY,CACd,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACjB,OAAO,CAAC,gBAAgB,CAAC;IA6B5B;;;;;OAKG;IACH,OAAO,CAAC,aAAa;IAsCrB;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;CA0C7B"}
@@ -0,0 +1,242 @@
1
+ /**
2
+ * ast-sandbox.ts - AST-based code validator for NREKI.
3
+ *
4
+ * Intercepts code BEFORE it's written to disk. Parses with tree-sitter
5
+ * and walks the AST looking for ERROR/MISSING nodes. If found, rejects
6
+ * the code with specific error locations and fix suggestions.
7
+ *
8
+ * This prevents the "write broken code → see error → fix → fail again"
9
+ * loop that burns tokens.
10
+ */
11
+ import Parser from "web-tree-sitter";
12
+ import path from "path";
13
+ import { fileURLToPath } from "url";
14
+ import { safeParse } from "./utils/safe-parse.js";
15
+ import { ParserPool } from "./parser-pool.js";
16
+ // ─── Language Mapping ────────────────────────────────────────────────
17
+ const LANGUAGE_MAP = {
18
+ typescript: "tree-sitter-typescript.wasm",
19
+ javascript: "tree-sitter-javascript.wasm",
20
+ python: "tree-sitter-python.wasm",
21
+ go: "tree-sitter-go.wasm",
22
+ };
23
+ /** Map file extensions to language names. */
24
+ const EXT_TO_LANGUAGE = {
25
+ ".ts": "typescript",
26
+ ".tsx": "typescript",
27
+ ".js": "javascript",
28
+ ".jsx": "javascript",
29
+ ".py": "python",
30
+ ".go": "go",
31
+ };
32
+ // ─── AstSandbox ──────────────────────────────────────────────────────
33
+ export class AstSandbox {
34
+ pool;
35
+ languageCache = new Map();
36
+ languagePromises = new Map();
37
+ wasmDir;
38
+ initialized = false;
39
+ constructor(wasmDir) {
40
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
41
+ this.wasmDir = wasmDir ?? path.join(__dirname, "..", "wasm");
42
+ this.pool = new ParserPool(4);
43
+ }
44
+ /** Initialize the Tree-sitter WASM runtime. Must be called once. */
45
+ async initialize() {
46
+ if (this.initialized)
47
+ return;
48
+ await this.pool.initialize();
49
+ this.initialized = true;
50
+ }
51
+ /** Get supported language names. */
52
+ getSupportedLanguages() {
53
+ return Object.keys(LANGUAGE_MAP);
54
+ }
55
+ /** Detect language from a file extension. */
56
+ detectLanguage(filePath) {
57
+ const ext = path.extname(filePath).toLowerCase();
58
+ return EXT_TO_LANGUAGE[ext] ?? null;
59
+ }
60
+ // ─── Language Loading ──────────────────────────────────────────
61
+ /** A-08: Deduplicates concurrent WASM loads. */
62
+ async loadLanguage(language) {
63
+ if (this.languageCache.has(language)) {
64
+ return this.languageCache.get(language);
65
+ }
66
+ if (this.languagePromises.has(language)) {
67
+ return this.languagePromises.get(language);
68
+ }
69
+ const wasmFile = LANGUAGE_MAP[language];
70
+ if (!wasmFile)
71
+ return null;
72
+ const promise = (async () => {
73
+ try {
74
+ const wasmPath = path.join(this.wasmDir, wasmFile);
75
+ const lang = await Parser.Language.load(wasmPath);
76
+ this.languageCache.set(language, lang);
77
+ return lang;
78
+ }
79
+ catch {
80
+ return null;
81
+ }
82
+ finally {
83
+ this.languagePromises.delete(language);
84
+ }
85
+ })();
86
+ this.languagePromises.set(language, promise);
87
+ return promise;
88
+ }
89
+ // ─── Validation ────────────────────────────────────────────────
90
+ /**
91
+ * Validate code syntax using tree-sitter AST analysis.
92
+ *
93
+ * Parses the code and walks the resulting tree looking for
94
+ * ERROR and MISSING nodes. Returns specific error locations
95
+ * with human-readable fix suggestions.
96
+ */
97
+ async validateCode(code, language) {
98
+ await this.initialize();
99
+ const lang = await this.loadLanguage(language);
100
+ if (!lang) {
101
+ return {
102
+ valid: false,
103
+ errors: [
104
+ {
105
+ line: 0,
106
+ column: 0,
107
+ nodeType: "UNSUPPORTED",
108
+ context: `Unsupported language: ${language}`,
109
+ },
110
+ ],
111
+ suggestion: `Language "${language}" is not supported. Supported: ${Object.keys(LANGUAGE_MAP).join(", ")}`,
112
+ };
113
+ }
114
+ const parser = await this.pool.acquire(lang, language);
115
+ try {
116
+ return safeParse(parser, code, (tree) => {
117
+ // Quick check: if no errors in the entire tree, skip the walk
118
+ if (!tree.rootNode.hasError) {
119
+ return { valid: true, errors: [], suggestion: "" };
120
+ }
121
+ const lines = code.split("\n");
122
+ const errors = [];
123
+ this.walkForErrors(tree.rootNode, lines, errors);
124
+ if (errors.length === 0) {
125
+ // hasError was true but no ERROR/MISSING nodes found
126
+ // (can happen with certain recoverable parse states)
127
+ return { valid: true, errors: [], suggestion: "" };
128
+ }
129
+ const suggestion = this.generateSuggestion(errors, lines);
130
+ return { valid: false, errors, suggestion };
131
+ });
132
+ }
133
+ finally {
134
+ this.pool.release(language, parser);
135
+ }
136
+ }
137
+ /**
138
+ * Validate new code against the original, showing what changed.
139
+ *
140
+ * Parses the NEW code only. If it has errors, enhances the
141
+ * error context by showing the original line vs the new line.
142
+ */
143
+ async validateDiff(originalCode, newCode, language) {
144
+ const result = await this.validateCode(newCode, language);
145
+ if (!result.valid) {
146
+ const origLines = originalCode.split("\n");
147
+ const newLines = newCode.split("\n");
148
+ for (const error of result.errors) {
149
+ const lineIdx = error.line - 1;
150
+ if (lineIdx >= 0 && lineIdx < newLines.length) {
151
+ const newLine = newLines[lineIdx];
152
+ const origLine = lineIdx < origLines.length
153
+ ? origLines[lineIdx]
154
+ : "(new line)";
155
+ if (newLine !== origLine) {
156
+ error.context +=
157
+ `\n Was: ${origLine.trim()}` +
158
+ `\n Now: ${newLine.trim()}`;
159
+ }
160
+ }
161
+ }
162
+ }
163
+ return result;
164
+ }
165
+ // ─── Tree Walking ──────────────────────────────────────────────
166
+ /**
167
+ * Recursively walk the AST looking for ERROR and MISSING nodes.
168
+ *
169
+ * Uses hasError to skip clean subtrees (optimization for large files).
170
+ * Does not descend into ERROR nodes (their children are unparsed tokens).
171
+ */
172
+ walkForErrors(node, lines, errors, depth = 0) {
173
+ // M-09: Guard against stack overflow on deeply nested ASTs
174
+ if (depth > 200)
175
+ return;
176
+ if (node.type === "ERROR" || node.isMissing) {
177
+ const line = node.startPosition.row + 1;
178
+ const column = node.startPosition.column + 1;
179
+ const lineText = line <= lines.length ? lines[line - 1] : "";
180
+ errors.push({
181
+ line,
182
+ column,
183
+ nodeType: node.isMissing
184
+ ? `MISSING(${node.type})`
185
+ : "ERROR",
186
+ context: lineText,
187
+ });
188
+ return; // don't descend into error nodes
189
+ }
190
+ // Optimization: skip subtrees with no errors
191
+ if (!node.hasError)
192
+ return;
193
+ for (let i = 0; i < node.childCount; i++) {
194
+ const child = node.child(i);
195
+ if (child) {
196
+ this.walkForErrors(child, lines, errors, depth + 1);
197
+ }
198
+ }
199
+ }
200
+ // ─── Suggestion Generation ─────────────────────────────────────
201
+ /**
202
+ * Generate human-readable fix suggestions from error nodes.
203
+ *
204
+ * Combines error location, context line, and heuristic hints
205
+ * to help Claude understand exactly what went wrong.
206
+ */
207
+ generateSuggestion(errors, lines) {
208
+ const parts = [];
209
+ for (const error of errors) {
210
+ let detail = `Syntax error at line ${error.line}, column ${error.column}`;
211
+ // MISSING nodes tell us what was expected
212
+ if (error.nodeType.startsWith("MISSING")) {
213
+ const missing = error.nodeType.match(/MISSING\((.+)\)/)?.[1] || "token";
214
+ detail += `: missing ${missing}`;
215
+ }
216
+ // Show the offending line
217
+ const contextLine = error.context.split("\n")[0];
218
+ if (contextLine.trim()) {
219
+ detail += `. The line reads: '${contextLine.trim()}'`;
220
+ }
221
+ // Heuristic hints for common mistakes
222
+ const ctx = contextLine;
223
+ if (ctx.match(/=\s*[;,\]})]/) || ctx.match(/=\s*$/)) {
224
+ detail += ". Likely missing a value after '='";
225
+ }
226
+ else if ((ctx.match(/\{/) && !ctx.match(/\}/)) ||
227
+ error.nodeType === "MISSING(})") {
228
+ detail += ". Possible unclosed brace '{'";
229
+ }
230
+ else if ((ctx.match(/\(/) && !ctx.match(/\)/)) ||
231
+ error.nodeType === "MISSING())") {
232
+ detail += ". Possible unclosed parenthesis '('";
233
+ }
234
+ else if (error.nodeType === "MISSING(;)") {
235
+ detail += ". Add a semicolon ';'";
236
+ }
237
+ parts.push(detail);
238
+ }
239
+ return parts.join("\n");
240
+ }
241
+ }
242
+ //# sourceMappingURL=ast-sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-sandbox.js","sourceRoot":"","sources":["../src/ast-sandbox.ts"],"names":[],"mappings":"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"}