mcp-code-context 2.1.3

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 (112) hide show
  1. package/AGENT_INSTRUCTIONS.md +135 -0
  2. package/CHANGELOG.md +84 -0
  3. package/DEPLOYMENT_INSTRUCTIONS.md +110 -0
  4. package/LICENSE +21 -0
  5. package/README.md +247 -0
  6. package/RELEASE_NOTES_v2.1.3.md +78 -0
  7. package/TROUBLESHOOTING.md +38 -0
  8. package/dist/src/ast/dartCompressor.d.ts +27 -0
  9. package/dist/src/ast/dartCompressor.js +859 -0
  10. package/dist/src/ast/dartCompressor.js.map +1 -0
  11. package/dist/src/ast/phpCompressor.d.ts +24 -0
  12. package/dist/src/ast/phpCompressor.js +634 -0
  13. package/dist/src/ast/phpCompressor.js.map +1 -0
  14. package/dist/src/ast/semanticCompressor.d.ts +22 -0
  15. package/dist/src/ast/semanticCompressor.js +677 -0
  16. package/dist/src/ast/semanticCompressor.js.map +1 -0
  17. package/dist/src/ast/writers/dartWriter.d.ts +37 -0
  18. package/dist/src/ast/writers/dartWriter.js +544 -0
  19. package/dist/src/ast/writers/dartWriter.js.map +1 -0
  20. package/dist/src/ast/writers/phpWriter.d.ts +37 -0
  21. package/dist/src/ast/writers/phpWriter.js +411 -0
  22. package/dist/src/ast/writers/phpWriter.js.map +1 -0
  23. package/dist/src/ast/writers/pyWriter.d.ts +37 -0
  24. package/dist/src/ast/writers/pyWriter.js +355 -0
  25. package/dist/src/ast/writers/pyWriter.js.map +1 -0
  26. package/dist/src/ast/writers/symbolWriter.d.ts +62 -0
  27. package/dist/src/ast/writers/symbolWriter.js +179 -0
  28. package/dist/src/ast/writers/symbolWriter.js.map +1 -0
  29. package/dist/src/ast/writers/tsWriter.d.ts +38 -0
  30. package/dist/src/ast/writers/tsWriter.js +344 -0
  31. package/dist/src/ast/writers/tsWriter.js.map +1 -0
  32. package/dist/src/index.d.ts +117 -0
  33. package/dist/src/index.js +1289 -0
  34. package/dist/src/index.js.map +1 -0
  35. package/dist/src/tests/test-confirmation-flow.d.ts +1 -0
  36. package/dist/src/tests/test-confirmation-flow.js +43 -0
  37. package/dist/src/tests/test-confirmation-flow.js.map +1 -0
  38. package/dist/src/utils/backupManager.d.ts +24 -0
  39. package/dist/src/utils/backupManager.js +59 -0
  40. package/dist/src/utils/backupManager.js.map +1 -0
  41. package/dist/src/utils/confirmationCache.d.ts +16 -0
  42. package/dist/src/utils/confirmationCache.js +40 -0
  43. package/dist/src/utils/confirmationCache.js.map +1 -0
  44. package/dist/src/utils/diffEngine.d.ts +21 -0
  45. package/dist/src/utils/diffEngine.js +163 -0
  46. package/dist/src/utils/diffEngine.js.map +1 -0
  47. package/dist/src/utils/fuzzyMatch.d.ts +8 -0
  48. package/dist/src/utils/fuzzyMatch.js +69 -0
  49. package/dist/src/utils/fuzzyMatch.js.map +1 -0
  50. package/dist/src/utils/ignoreManager.d.ts +22 -0
  51. package/dist/src/utils/ignoreManager.js +135 -0
  52. package/dist/src/utils/ignoreManager.js.map +1 -0
  53. package/dist/tests/debug-replace.d.ts +1 -0
  54. package/dist/tests/debug-replace.js +17 -0
  55. package/dist/tests/debug-replace.js.map +1 -0
  56. package/dist/tests/test-confirmation-flow.d.ts +1 -0
  57. package/dist/tests/test-confirmation-flow.js +43 -0
  58. package/dist/tests/test-confirmation-flow.js.map +1 -0
  59. package/dist/tests/test-dart.d.ts +1 -0
  60. package/dist/tests/test-dart.js +242 -0
  61. package/dist/tests/test-dart.js.map +1 -0
  62. package/dist/tests/test-php-ast.d.ts +1 -0
  63. package/dist/tests/test-php-ast.js +152 -0
  64. package/dist/tests/test-php-ast.js.map +1 -0
  65. package/dist/tests/test-php.d.ts +1 -0
  66. package/dist/tests/test-php.js +234 -0
  67. package/dist/tests/test-php.js.map +1 -0
  68. package/dist/tests/test-smoke.d.ts +5 -0
  69. package/dist/tests/test-smoke.js +83 -0
  70. package/dist/tests/test-smoke.js.map +1 -0
  71. package/dist/tests/writers/test-crlf-handling.d.ts +4 -0
  72. package/dist/tests/writers/test-crlf-handling.js +73 -0
  73. package/dist/tests/writers/test-crlf-handling.js.map +1 -0
  74. package/dist/tests/writers/test-write-smoke.d.ts +9 -0
  75. package/dist/tests/writers/test-write-smoke.js +346 -0
  76. package/dist/tests/writers/test-write-smoke.js.map +1 -0
  77. package/llms.txt +164 -0
  78. package/package.json +57 -0
  79. package/src/ast/dartCompressor.ts +1013 -0
  80. package/src/ast/phpCompressor.ts +814 -0
  81. package/src/ast/semanticCompressor.ts +808 -0
  82. package/src/ast/writers/dartWriter.ts +648 -0
  83. package/src/ast/writers/phpWriter.ts +508 -0
  84. package/src/ast/writers/pyWriter.ts +446 -0
  85. package/src/ast/writers/symbolWriter.ts +277 -0
  86. package/src/ast/writers/tsWriter.ts +418 -0
  87. package/src/index.ts +1553 -0
  88. package/src/utils/backupManager.ts +66 -0
  89. package/src/utils/confirmationCache.ts +61 -0
  90. package/src/utils/diffEngine.ts +223 -0
  91. package/src/utils/fuzzyMatch.ts +86 -0
  92. package/src/utils/ignoreManager.ts +144 -0
  93. package/tests/test-confirmation-flow.ts +49 -0
  94. package/tests/test-dart.d.ts +1 -0
  95. package/tests/test-dart.js +209 -0
  96. package/tests/test-dart.js.map +1 -0
  97. package/tests/test-dart.ts +265 -0
  98. package/tests/test-php-ast.d.ts +1 -0
  99. package/tests/test-php-ast.js +152 -0
  100. package/tests/test-php-ast.js.map +1 -0
  101. package/tests/test-php-ast.ts +155 -0
  102. package/tests/test-php.d.ts +1 -0
  103. package/tests/test-php.js +234 -0
  104. package/tests/test-php.js.map +1 -0
  105. package/tests/test-php.ts +261 -0
  106. package/tests/test-smoke.d.ts +5 -0
  107. package/tests/test-smoke.js +83 -0
  108. package/tests/test-smoke.js.map +1 -0
  109. package/tests/test-smoke.ts +93 -0
  110. package/tests/writers/test-crlf-handling.ts +100 -0
  111. package/tests/writers/test-write-smoke.ts +568 -0
  112. package/tsconfig.json +19 -0
@@ -0,0 +1,22 @@
1
+ /**
2
+ * SemanticCompressor — The AST engine that extracts structural signatures
3
+ * from source files, stripping implementation bodies to save tokens.
4
+ *
5
+ * Supports:
6
+ * - TypeScript / JavaScript (via ts-morph AST)
7
+ * - PHP (via php-parser AST — Glayzzle)
8
+ * - Dart (via regex + brace-counting)
9
+ * - Python (via regex-based extraction)
10
+ * - Generic files (passthrough for small configs, summary for large files)
11
+ */
12
+ /**
13
+ * Compress a source file into its semantic skeleton.
14
+ * Returns only structural signatures — no function bodies.
15
+ */
16
+ export declare function compressFile(filePath: string, content: string): string;
17
+ /**
18
+ * Extract the full source code of a named symbol from a file.
19
+ * When className is provided, scopes method search to within that class only.
20
+ * Returns null if the symbol is not found.
21
+ */
22
+ export declare function extractSymbol(content: string, symbolName: string, filePath: string, className?: string): string | null;
@@ -0,0 +1,677 @@
1
+ /**
2
+ * SemanticCompressor — The AST engine that extracts structural signatures
3
+ * from source files, stripping implementation bodies to save tokens.
4
+ *
5
+ * Supports:
6
+ * - TypeScript / JavaScript (via ts-morph AST)
7
+ * - PHP (via php-parser AST — Glayzzle)
8
+ * - Dart (via regex + brace-counting)
9
+ * - Python (via regex-based extraction)
10
+ * - Generic files (passthrough for small configs, summary for large files)
11
+ */
12
+ import { Project, SyntaxKind, ts, } from "ts-morph";
13
+ import * as path from "node:path";
14
+ import { compressPHP, extractPHPSymbol } from "./phpCompressor.js";
15
+ import { compressDart, extractDartSymbol } from "./dartCompressor.js";
16
+ // ─── Supported extensions ───────────────────────────────────────────
17
+ const TS_EXTENSIONS = new Set([
18
+ ".ts", ".tsx", ".js", ".jsx", ".mts", ".mjs", ".cts", ".cjs",
19
+ ]);
20
+ const PY_EXTENSIONS = new Set([".py", ".pyi"]);
21
+ const PHP_EXTENSIONS = new Set([".php", ".phtml"]);
22
+ const DART_EXTENSIONS = new Set([".dart"]);
23
+ const CONFIG_EXTENSIONS = new Set([
24
+ ".json", ".yaml", ".yml", ".toml", ".ini", ".env",
25
+ ".xml", ".html", ".css", ".scss", ".less",
26
+ ".md", ".txt", ".svg",
27
+ ]);
28
+ // ─── Singleton ts-morph Project (reusable, in-memory) ───────────────
29
+ let _project = null;
30
+ function getProject() {
31
+ if (!_project) {
32
+ _project = new Project({
33
+ useInMemoryFileSystem: true,
34
+ compilerOptions: {
35
+ target: ts.ScriptTarget.ESNext,
36
+ module: ts.ModuleKind.ESNext,
37
+ jsx: ts.JsxEmit.ReactJSX,
38
+ allowJs: true,
39
+ strict: false,
40
+ noEmit: true,
41
+ skipLibCheck: true,
42
+ },
43
+ });
44
+ }
45
+ return _project;
46
+ }
47
+ // ─── Public API ─────────────────────────────────────────────────────
48
+ /**
49
+ * Compress a source file into its semantic skeleton.
50
+ * Returns only structural signatures — no function bodies.
51
+ */
52
+ export function compressFile(filePath, content) {
53
+ const ext = path.extname(filePath).toLowerCase();
54
+ if (TS_EXTENSIONS.has(ext)) {
55
+ return compressTypeScript(content, filePath);
56
+ }
57
+ if (PHP_EXTENSIONS.has(ext)) {
58
+ return compressPHP(content);
59
+ }
60
+ if (DART_EXTENSIONS.has(ext)) {
61
+ return compressDart(content);
62
+ }
63
+ if (PY_EXTENSIONS.has(ext)) {
64
+ return compressPython(content);
65
+ }
66
+ return compressGeneric(content, filePath);
67
+ }
68
+ /**
69
+ * Extract the full source code of a named symbol from a file.
70
+ * When className is provided, scopes method search to within that class only.
71
+ * Returns null if the symbol is not found.
72
+ */
73
+ export function extractSymbol(content, symbolName, filePath, className) {
74
+ const ext = path.extname(filePath).toLowerCase();
75
+ if (TS_EXTENSIONS.has(ext)) {
76
+ return extractTSSymbol(content, symbolName, filePath, className);
77
+ }
78
+ if (PHP_EXTENSIONS.has(ext)) {
79
+ return extractPHPSymbol(content, symbolName, className);
80
+ }
81
+ if (DART_EXTENSIONS.has(ext)) {
82
+ return extractDartSymbol(content, symbolName, className);
83
+ }
84
+ if (PY_EXTENSIONS.has(ext)) {
85
+ return extractPySymbol(content, symbolName, className);
86
+ }
87
+ return null;
88
+ }
89
+ // ─── TypeScript / JavaScript Compression ────────────────────────────
90
+ function compressTypeScript(content, filePath) {
91
+ const project = getProject();
92
+ const ext = path.extname(filePath);
93
+ const tempName = `temp_${Date.now()}${ext}`;
94
+ let sourceFile;
95
+ try {
96
+ sourceFile = project.createSourceFile(tempName, content, {
97
+ overwrite: true,
98
+ });
99
+ }
100
+ catch {
101
+ return compressGeneric(content, filePath);
102
+ }
103
+ try {
104
+ const chunks = [];
105
+ // 1) Imports — keep for dependency context
106
+ const imports = sourceFile.getImportDeclarations();
107
+ if (imports.length > 0) {
108
+ chunks.push("// ── Imports ──");
109
+ for (const imp of imports) {
110
+ chunks.push(imp.getText());
111
+ }
112
+ chunks.push("");
113
+ }
114
+ // 2) Type aliases
115
+ for (const ta of sourceFile.getTypeAliases()) {
116
+ chunks.push(ta.getText());
117
+ }
118
+ // 3) Interfaces (already just signatures)
119
+ for (const iface of sourceFile.getInterfaces()) {
120
+ chunks.push(iface.getText());
121
+ }
122
+ // 4) Enums
123
+ for (const enumDecl of sourceFile.getEnums()) {
124
+ chunks.push(enumDecl.getText());
125
+ }
126
+ // 5) Function declarations (signature only, body stripped)
127
+ for (const func of sourceFile.getFunctions()) {
128
+ chunks.push(buildFunctionSignature(func));
129
+ }
130
+ // 6) Class declarations (signatures only)
131
+ for (const cls of sourceFile.getClasses()) {
132
+ chunks.push(buildClassSignature(cls));
133
+ }
134
+ // 7) Exported variable statements (arrow fns, consts, etc.)
135
+ for (const varStmt of sourceFile.getVariableStatements()) {
136
+ if (!varStmt.isExported())
137
+ continue;
138
+ for (const decl of varStmt.getDeclarations()) {
139
+ const init = decl.getInitializer();
140
+ if (!init)
141
+ continue;
142
+ const kind = init.getKind();
143
+ if (kind === SyntaxKind.ArrowFunction ||
144
+ kind === SyntaxKind.FunctionExpression) {
145
+ const fn = init;
146
+ const params = fn
147
+ .getParameters()
148
+ .map((p) => p.getText())
149
+ .join(", ");
150
+ const retNode = fn.getReturnTypeNode();
151
+ const retType = retNode ? `: ${retNode.getText()}` : "";
152
+ const asyncMod = fn.isAsync() ? "async " : "";
153
+ const declKind = varStmt.getDeclarationKind();
154
+ chunks.push(`export ${declKind} ${asyncMod}${decl.getName()} = (${params})${retType} => { /* ... */ };`);
155
+ }
156
+ else {
157
+ const declKind = varStmt.getDeclarationKind();
158
+ const typeNode = decl.getTypeNode();
159
+ const typeStr = typeNode ? `: ${typeNode.getText()}` : "";
160
+ chunks.push(`export ${declKind} ${decl.getName()}${typeStr};`);
161
+ }
162
+ }
163
+ }
164
+ // 8) Re-export declarations
165
+ for (const exp of sourceFile.getExportDeclarations()) {
166
+ chunks.push(exp.getText());
167
+ }
168
+ // 9) Export assignments (export default ...)
169
+ const exportAssignment = sourceFile.getExportAssignment((ea) => !ea.isExportEquals());
170
+ if (exportAssignment) {
171
+ chunks.push(exportAssignment.getText());
172
+ }
173
+ return chunks.filter((c) => c.trim()).join("\n\n");
174
+ }
175
+ finally {
176
+ // Clean up the in-memory source file to avoid memory leaks
177
+ try {
178
+ project.removeSourceFile(sourceFile);
179
+ }
180
+ catch {
181
+ // Ignore cleanup errors
182
+ }
183
+ }
184
+ }
185
+ function buildFunctionSignature(func) {
186
+ const name = func.getName() || "anonymous";
187
+ const params = func
188
+ .getParameters()
189
+ .map((p) => p.getText())
190
+ .join(", ");
191
+ const retNode = func.getReturnTypeNode();
192
+ const retType = retNode ? `: ${retNode.getText()}` : "";
193
+ const exported = func.isExported() ? "export " : "";
194
+ const isDefault = func.isDefaultExport() ? "default " : "";
195
+ const asyncMod = func.isAsync() ? "async " : "";
196
+ const generics = func
197
+ .getTypeParameters()
198
+ .map((tp) => tp.getText())
199
+ .join(", ");
200
+ const genericStr = generics ? `<${generics}>` : "";
201
+ const overloads = func.getOverloads();
202
+ const parts = [];
203
+ for (const overload of overloads) {
204
+ parts.push(overload.getText());
205
+ }
206
+ parts.push(`${exported}${isDefault}${asyncMod}function ${name}${genericStr}(${params})${retType} { /* ... */ }`);
207
+ return parts.join("\n");
208
+ }
209
+ function buildClassSignature(cls) {
210
+ const lines = [];
211
+ const name = cls.getName() || "AnonymousClass";
212
+ const exported = cls.isExported() ? "export " : "";
213
+ const isDefault = cls.isDefaultExport() ? "default " : "";
214
+ const isAbstract = cls.isAbstract() ? "abstract " : "";
215
+ const extendsExpr = cls.getExtends();
216
+ const implementsClauses = cls.getImplements();
217
+ const generics = cls
218
+ .getTypeParameters()
219
+ .map((tp) => tp.getText())
220
+ .join(", ");
221
+ const genericStr = generics ? `<${generics}>` : "";
222
+ let header = `${exported}${isDefault}${isAbstract}class ${name}${genericStr}`;
223
+ if (extendsExpr)
224
+ header += ` extends ${extendsExpr.getText()}`;
225
+ if (implementsClauses.length > 0) {
226
+ header += ` implements ${implementsClauses.map((i) => i.getText()).join(", ")}`;
227
+ }
228
+ header += " {";
229
+ lines.push(header);
230
+ // Constructor
231
+ for (const ctor of cls.getConstructors()) {
232
+ const params = ctor
233
+ .getParameters()
234
+ .map((p) => p.getText())
235
+ .join(", ");
236
+ lines.push(` constructor(${params}) { /* ... */ }`);
237
+ }
238
+ // Properties
239
+ for (const prop of cls.getProperties()) {
240
+ const mods = prop
241
+ .getModifiers()
242
+ .map((m) => m.getText())
243
+ .join(" ");
244
+ const modStr = mods ? `${mods} ` : "";
245
+ const typeNode = prop.getTypeNode();
246
+ const typeStr = typeNode ? `: ${typeNode.getText()}` : "";
247
+ const optional = prop.hasQuestionToken() ? "?" : "";
248
+ const isReadonly = prop.isReadonly() ? "readonly " : "";
249
+ lines.push(` ${modStr}${isReadonly}${prop.getName()}${optional}${typeStr};`);
250
+ }
251
+ // Methods (signature only)
252
+ for (const method of cls.getMethods()) {
253
+ lines.push(` ${buildMethodSignature(method)}`);
254
+ }
255
+ // Getters
256
+ for (const getter of cls.getGetAccessors()) {
257
+ const retNode = getter.getReturnTypeNode();
258
+ const retType = retNode ? `: ${retNode.getText()}` : "";
259
+ lines.push(` get ${getter.getName()}()${retType} { /* ... */ }`);
260
+ }
261
+ // Setters
262
+ for (const setter of cls.getSetAccessors()) {
263
+ const params = setter
264
+ .getParameters()
265
+ .map((p) => p.getText())
266
+ .join(", ");
267
+ lines.push(` set ${setter.getName()}(${params}) { /* ... */ }`);
268
+ }
269
+ lines.push("}");
270
+ return lines.join("\n");
271
+ }
272
+ function buildMethodSignature(method) {
273
+ const mods = method
274
+ .getModifiers()
275
+ .map((m) => m.getText())
276
+ .join(" ");
277
+ const modStr = mods ? `${mods} ` : "";
278
+ const asyncMod = method.isAsync() ? "async " : "";
279
+ const name = method.getName();
280
+ const params = method
281
+ .getParameters()
282
+ .map((p) => p.getText())
283
+ .join(", ");
284
+ const retNode = method.getReturnTypeNode();
285
+ const retType = retNode ? `: ${retNode.getText()}` : "";
286
+ const generics = method
287
+ .getTypeParameters()
288
+ .map((tp) => tp.getText())
289
+ .join(", ");
290
+ const genericStr = generics ? `<${generics}>` : "";
291
+ return `${modStr}${asyncMod}${name}${genericStr}(${params})${retType} { /* ... */ }`;
292
+ }
293
+ // ─── Python Compression ─────────────────────────────────────────────
294
+ function compressPython(content) {
295
+ const lines = content.split("\n");
296
+ const result = [];
297
+ let i = 0;
298
+ // Phase 1: Collect imports at the top
299
+ const importBlock = [];
300
+ for (const line of lines) {
301
+ const t = line.trim();
302
+ if (t.startsWith("import ") || t.startsWith("from ")) {
303
+ importBlock.push(line);
304
+ }
305
+ }
306
+ if (importBlock.length > 0) {
307
+ result.push("# ── Imports ──");
308
+ result.push(...importBlock);
309
+ result.push("");
310
+ }
311
+ // Phase 2: Walk the file extracting signatures
312
+ while (i < lines.length) {
313
+ const line = lines[i];
314
+ const trimmed = line.trim();
315
+ const indent = measureIndent(line);
316
+ // Skip import lines (already captured)
317
+ if (trimmed.startsWith("import ") || trimmed.startsWith("from ")) {
318
+ i++;
319
+ continue;
320
+ }
321
+ // Decorators — pass through
322
+ if (trimmed.startsWith("@")) {
323
+ result.push(line);
324
+ i++;
325
+ continue;
326
+ }
327
+ // Class definition
328
+ if (/^class\s+\w+/.test(trimmed)) {
329
+ // Capture the full class signature (may span multiple lines)
330
+ let signature = line;
331
+ i++;
332
+ while (i < lines.length && !signature.trimEnd().endsWith(":")) {
333
+ signature += "\n" + lines[i];
334
+ i++;
335
+ }
336
+ result.push(signature);
337
+ // Capture docstring
338
+ i = captureDocstring(lines, i, result);
339
+ // Now extract methods within this class
340
+ while (i < lines.length) {
341
+ const innerLine = lines[i];
342
+ const innerTrimmed = innerLine.trim();
343
+ // Empty line within class is OK
344
+ if (innerTrimmed === "") {
345
+ i++;
346
+ continue;
347
+ }
348
+ // Exited the class (non-indented non-empty line)
349
+ if (measureIndent(innerLine) <= indent && innerTrimmed !== "") {
350
+ break;
351
+ }
352
+ // Decorator before method
353
+ if (innerTrimmed.startsWith("@")) {
354
+ result.push(innerLine);
355
+ i++;
356
+ continue;
357
+ }
358
+ // Method definition
359
+ if (/^\s*(async\s+)?def\s+\w+/.test(innerLine)) {
360
+ let methodSig = innerLine;
361
+ i++;
362
+ while (i < lines.length && !methodSig.trimEnd().endsWith(":")) {
363
+ methodSig += "\n" + lines[i];
364
+ i++;
365
+ }
366
+ result.push(methodSig);
367
+ // Capture method docstring
368
+ i = captureDocstring(lines, i, result);
369
+ // Placeholder for body
370
+ const methodIndent = measureIndent(innerLine);
371
+ result.push(" ".repeat(methodIndent + 4) + "...");
372
+ result.push("");
373
+ // Skip method body
374
+ while (i < lines.length) {
375
+ const bodyLine = lines[i];
376
+ if (bodyLine.trim() === "") {
377
+ i++;
378
+ continue;
379
+ }
380
+ if (measureIndent(bodyLine) > methodIndent) {
381
+ i++;
382
+ }
383
+ else {
384
+ break;
385
+ }
386
+ }
387
+ continue;
388
+ }
389
+ // Class-level attribute with type hint
390
+ if (/^\s+\w+\s*:/.test(innerLine) && !innerTrimmed.startsWith("#")) {
391
+ result.push(innerLine);
392
+ }
393
+ i++;
394
+ }
395
+ result.push("");
396
+ continue;
397
+ }
398
+ // Top-level function definition
399
+ if (/^(async\s+)?def\s+\w+/.test(trimmed)) {
400
+ let signature = line;
401
+ i++;
402
+ while (i < lines.length && !signature.trimEnd().endsWith(":")) {
403
+ signature += "\n" + lines[i];
404
+ i++;
405
+ }
406
+ result.push(signature);
407
+ // Capture docstring
408
+ i = captureDocstring(lines, i, result);
409
+ // Placeholder
410
+ result.push(" ...");
411
+ result.push("");
412
+ // Skip body
413
+ while (i < lines.length) {
414
+ const bodyLine = lines[i];
415
+ if (bodyLine.trim() === "") {
416
+ i++;
417
+ continue;
418
+ }
419
+ if (bodyLine.startsWith(" ") || bodyLine.startsWith("\t")) {
420
+ i++;
421
+ }
422
+ else {
423
+ break;
424
+ }
425
+ }
426
+ continue;
427
+ }
428
+ // Top-level typed variable
429
+ if (indent === 0 && /^\w+\s*:/.test(trimmed) && !trimmed.startsWith("#")) {
430
+ result.push(line);
431
+ i++;
432
+ continue;
433
+ }
434
+ // Top-level assignment of special objects
435
+ if (indent === 0 &&
436
+ /^\w+\s*=/.test(trimmed) &&
437
+ !trimmed.startsWith("#")) {
438
+ // Keep only single-line assignments to constants, named tuples, etc.
439
+ if (!trimmed.includes("(") || trimmed.endsWith(")")) {
440
+ result.push(line);
441
+ }
442
+ i++;
443
+ continue;
444
+ }
445
+ i++;
446
+ }
447
+ return result.join("\n");
448
+ }
449
+ function captureDocstring(lines, i, result) {
450
+ if (i >= lines.length)
451
+ return i;
452
+ const trimmed = lines[i].trim();
453
+ if (!trimmed.startsWith('"""') && !trimmed.startsWith("'''")) {
454
+ return i;
455
+ }
456
+ const quoteType = trimmed.substring(0, 3);
457
+ result.push(lines[i]);
458
+ // Single-line docstring: """Something."""
459
+ if (trimmed.length > 6 && trimmed.endsWith(quoteType)) {
460
+ return i + 1;
461
+ }
462
+ // Multi-line docstring
463
+ i++;
464
+ while (i < lines.length) {
465
+ result.push(lines[i]);
466
+ if (lines[i].trim().endsWith(quoteType)) {
467
+ return i + 1;
468
+ }
469
+ i++;
470
+ }
471
+ return i;
472
+ }
473
+ function measureIndent(line) {
474
+ const match = line.match(/^(\s*)/);
475
+ return match ? match[1].length : 0;
476
+ }
477
+ // ─── Generic Compression ────────────────────────────────────────────
478
+ function compressGeneric(content, filePath) {
479
+ const ext = path.extname(filePath).toLowerCase();
480
+ const lines = content.split("\n");
481
+ const lineCount = lines.length;
482
+ // Small config/data files: return as-is
483
+ if (CONFIG_EXTENSIONS.has(ext) && lineCount <= 150) {
484
+ return content;
485
+ }
486
+ // Larger files: provide a summary + head
487
+ if (lineCount > 150) {
488
+ const head = lines.slice(0, 60).join("\n");
489
+ return [
490
+ `// File: ${path.basename(filePath)} (${lineCount} lines)`,
491
+ `// Language not supported for semantic compression.`,
492
+ `// Showing first 60 lines:`,
493
+ ``,
494
+ head,
495
+ ``,
496
+ `// ... (${lineCount - 60} more lines truncated)`,
497
+ ].join("\n");
498
+ }
499
+ return content;
500
+ }
501
+ // ─── Symbol Extraction (Full Source) ────────────────────────────────
502
+ function extractTSSymbol(content, symbolName, filePath, className) {
503
+ const project = getProject();
504
+ const ext = path.extname(filePath);
505
+ const tempName = `extract_${Date.now()}${ext}`;
506
+ let sourceFile;
507
+ try {
508
+ sourceFile = project.createSourceFile(tempName, content, {
509
+ overwrite: true,
510
+ });
511
+ }
512
+ catch {
513
+ return null;
514
+ }
515
+ try {
516
+ // If className is provided, scope search to within that class
517
+ if (className) {
518
+ const cls = sourceFile.getClass(className);
519
+ if (!cls)
520
+ return null;
521
+ const method = cls.getMethod(symbolName);
522
+ if (method)
523
+ return method.getFullText().trim();
524
+ const getter = cls.getGetAccessor(symbolName);
525
+ if (getter)
526
+ return getter.getFullText().trim();
527
+ const setter = cls.getSetAccessor(symbolName);
528
+ if (setter)
529
+ return setter.getFullText().trim();
530
+ const prop = cls.getProperty(symbolName);
531
+ if (prop)
532
+ return prop.getFullText().trim();
533
+ return null;
534
+ }
535
+ // Search top-level functions
536
+ const func = sourceFile.getFunction(symbolName);
537
+ if (func)
538
+ return func.getFullText().trim();
539
+ // Search classes
540
+ const cls = sourceFile.getClass(symbolName);
541
+ if (cls)
542
+ return cls.getFullText().trim();
543
+ // Search interfaces
544
+ const iface = sourceFile.getInterface(symbolName);
545
+ if (iface)
546
+ return iface.getFullText().trim();
547
+ // Search type aliases
548
+ const typeAlias = sourceFile.getTypeAlias(symbolName);
549
+ if (typeAlias)
550
+ return typeAlias.getFullText().trim();
551
+ // Search enums
552
+ const enumDecl = sourceFile.getEnum(symbolName);
553
+ if (enumDecl)
554
+ return enumDecl.getFullText().trim();
555
+ // Search methods inside classes
556
+ for (const c of sourceFile.getClasses()) {
557
+ const method = c.getMethod(symbolName);
558
+ if (method)
559
+ return method.getFullText().trim();
560
+ const getter = c.getGetAccessor(symbolName);
561
+ if (getter)
562
+ return getter.getFullText().trim();
563
+ const setter = c.getSetAccessor(symbolName);
564
+ if (setter)
565
+ return setter.getFullText().trim();
566
+ }
567
+ // Search variable declarations (arrow functions, consts)
568
+ for (const varStmt of sourceFile.getVariableStatements()) {
569
+ for (const decl of varStmt.getDeclarations()) {
570
+ if (decl.getName() === symbolName) {
571
+ return varStmt.getFullText().trim();
572
+ }
573
+ }
574
+ }
575
+ return null;
576
+ }
577
+ finally {
578
+ try {
579
+ project.removeSourceFile(sourceFile);
580
+ }
581
+ catch {
582
+ // Ignore
583
+ }
584
+ }
585
+ }
586
+ function extractPySymbol(content, symbolName, className) {
587
+ const lines = content.split("\n");
588
+ const escapedName = symbolName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
589
+ // If className is provided, find the class first, then search within it
590
+ if (className) {
591
+ const escapedClass = className.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
592
+ for (let i = 0; i < lines.length; i++) {
593
+ const trimmed = lines[i].trim();
594
+ if (!new RegExp(`^class\\s+${escapedClass}[\\s(:]`).test(trimmed))
595
+ continue;
596
+ // Found the class — now search for the method within it
597
+ const classIndent = measureIndent(lines[i]);
598
+ let j = i + 1;
599
+ while (j < lines.length) {
600
+ const bodyLine = lines[j];
601
+ if (bodyLine.trim() === "") {
602
+ j++;
603
+ continue;
604
+ }
605
+ if (measureIndent(bodyLine) <= classIndent && bodyLine.trim() !== "")
606
+ break;
607
+ const bodyTrimmed = bodyLine.trim();
608
+ const isFunc = new RegExp(`^(?:async\\s+)?def\\s+${escapedName}\\s*\\(`).test(bodyTrimmed);
609
+ if (isFunc) {
610
+ const startLine = j;
611
+ const baseIndent = measureIndent(bodyLine);
612
+ const blockLines = [bodyLine];
613
+ j++;
614
+ while (j < lines.length) {
615
+ const innerLine = lines[j];
616
+ if (innerLine.trim() === "") {
617
+ blockLines.push(innerLine);
618
+ j++;
619
+ continue;
620
+ }
621
+ if (measureIndent(innerLine) > baseIndent) {
622
+ blockLines.push(innerLine);
623
+ j++;
624
+ }
625
+ else
626
+ break;
627
+ }
628
+ while (blockLines.length > 0 && blockLines[blockLines.length - 1].trim() === "") {
629
+ blockLines.pop();
630
+ }
631
+ return blockLines.join("\n");
632
+ }
633
+ j++;
634
+ }
635
+ return null; // Method not found within class
636
+ }
637
+ return null; // Class not found
638
+ }
639
+ // Original behavior when no className is provided
640
+ for (let i = 0; i < lines.length; i++) {
641
+ const line = lines[i];
642
+ const trimmed = line.trim();
643
+ // Match class or function by exact name
644
+ const isClass = new RegExp(`^class\\s+${escapedName}[\\s(:]`).test(trimmed);
645
+ const isFunc = new RegExp(`^(?:async\\s+)?def\\s+${escapedName}\\s*\\(`).test(trimmed);
646
+ if (!isClass && !isFunc)
647
+ continue;
648
+ const startLine = i;
649
+ const baseIndent = measureIndent(line);
650
+ const blockLines = [line];
651
+ i++;
652
+ // Capture the entire block (including body)
653
+ while (i < lines.length) {
654
+ const bodyLine = lines[i];
655
+ if (bodyLine.trim() === "") {
656
+ blockLines.push(bodyLine);
657
+ i++;
658
+ continue;
659
+ }
660
+ if (measureIndent(bodyLine) > baseIndent) {
661
+ blockLines.push(bodyLine);
662
+ i++;
663
+ }
664
+ else {
665
+ break;
666
+ }
667
+ }
668
+ // Trim trailing empty lines
669
+ while (blockLines.length > 0 &&
670
+ blockLines[blockLines.length - 1].trim() === "") {
671
+ blockLines.pop();
672
+ }
673
+ return blockLines.join("\n");
674
+ }
675
+ return null;
676
+ }
677
+ //# sourceMappingURL=semanticCompressor.js.map