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,135 @@
1
+ /**
2
+ * IgnoreManager — Reads .gitignore / .repomixignore and walks directories
3
+ * filtering out ignored paths. Always excludes common heavy directories.
4
+ */
5
+ import * as fs from "node:fs";
6
+ import * as path from "node:path";
7
+ import { createRequire } from "node:module";
8
+ // CJS interop: 'ignore' uses module.exports which doesn't resolve
9
+ // as a callable default export under Node16 module resolution.
10
+ const require = createRequire(import.meta.url);
11
+ const ignore = require("ignore");
12
+ /** Directories and patterns that are ALWAYS excluded regardless of .gitignore */
13
+ const ALWAYS_IGNORE = [
14
+ "node_modules",
15
+ ".git",
16
+ "dist",
17
+ "build",
18
+ "vendor",
19
+ ".next",
20
+ ".nuxt",
21
+ ".output",
22
+ "__pycache__",
23
+ ".pytest_cache",
24
+ "coverage",
25
+ ".nyc_output",
26
+ ".turbo",
27
+ ".cache",
28
+ ".parcel-cache",
29
+ ".venv",
30
+ "venv",
31
+ "env",
32
+ ".env.local",
33
+ ".tsbuildinfo",
34
+ "*.lock",
35
+ "package-lock.json",
36
+ "yarn.lock",
37
+ "pnpm-lock.yaml",
38
+ "bun.lockb",
39
+ "*.min.js",
40
+ "*.min.css",
41
+ "*.map",
42
+ "*.chunk.js",
43
+ "*.bundle.js",
44
+ ];
45
+ /** Max file size to read (512 KB). Files larger than this are skipped. */
46
+ const MAX_FILE_SIZE_BYTES = 512 * 1024;
47
+ export class IgnoreManager {
48
+ ig;
49
+ rootDir;
50
+ constructor(rootDir) {
51
+ this.rootDir = path.resolve(rootDir);
52
+ this.ig = ignore();
53
+ // Load hardcoded ignores first
54
+ this.ig.add(ALWAYS_IGNORE);
55
+ // Load .gitignore
56
+ this.loadIgnoreFile(path.join(this.rootDir, ".gitignore"));
57
+ // Load .repomixignore (Repomix-style overrides)
58
+ this.loadIgnoreFile(path.join(this.rootDir, ".repomixignore"));
59
+ }
60
+ /**
61
+ * Reads an ignore-pattern file and adds its rules to the filter.
62
+ * Silently skips if the file doesn't exist or is unreadable.
63
+ */
64
+ loadIgnoreFile(filePath) {
65
+ try {
66
+ if (!fs.existsSync(filePath))
67
+ return;
68
+ const content = fs.readFileSync(filePath, "utf-8");
69
+ const patterns = content
70
+ .split("\n")
71
+ .map((line) => line.trim())
72
+ .filter((line) => line.length > 0 && !line.startsWith("#"));
73
+ if (patterns.length > 0) {
74
+ this.ig.add(patterns);
75
+ }
76
+ }
77
+ catch {
78
+ // File unreadable — skip silently
79
+ }
80
+ }
81
+ /** Check if a relative path should be ignored. */
82
+ isIgnored(relativePath) {
83
+ if (!relativePath)
84
+ return false;
85
+ return this.ig.ignores(relativePath);
86
+ }
87
+ /**
88
+ * Recursively walk a directory, returning absolute paths to all
89
+ * non-ignored files.
90
+ */
91
+ walkDirectory(dir) {
92
+ const baseDir = dir ? path.resolve(dir) : this.rootDir;
93
+ const files = [];
94
+ this.walk(baseDir, files);
95
+ return files;
96
+ }
97
+ walk(currentDir, collected) {
98
+ let entries;
99
+ try {
100
+ entries = fs.readdirSync(currentDir, { withFileTypes: true });
101
+ }
102
+ catch {
103
+ return; // Permission denied, broken symlink, etc.
104
+ }
105
+ for (const entry of entries) {
106
+ const fullPath = path.join(currentDir, entry.name);
107
+ const relativePath = path
108
+ .relative(this.rootDir, fullPath)
109
+ .replace(/\\/g, "/");
110
+ // Check ignore rules
111
+ if (this.isIgnored(relativePath))
112
+ continue;
113
+ if (entry.isDirectory()) {
114
+ // Also test with trailing slash for directory-level patterns
115
+ if (this.isIgnored(relativePath + "/"))
116
+ continue;
117
+ this.walk(fullPath, collected);
118
+ }
119
+ else if (entry.isFile()) {
120
+ // Skip files that are too large
121
+ try {
122
+ const stat = fs.statSync(fullPath);
123
+ if (stat.size > MAX_FILE_SIZE_BYTES)
124
+ continue;
125
+ }
126
+ catch {
127
+ continue;
128
+ }
129
+ collected.push(fullPath);
130
+ }
131
+ // Symlinks and other entries are silently skipped
132
+ }
133
+ }
134
+ }
135
+ //# sourceMappingURL=ignoreManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ignoreManager.js","sourceRoot":"","sources":["../../../src/utils/ignoreManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,kEAAkE;AAClE,+DAA+D;AAC/D,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,MAAM,GAA+C,OAAO,CAAC,QAAQ,CAAC,CAAC;AAE7E,iFAAiF;AACjF,MAAM,aAAa,GAAa;IAC9B,cAAc;IACd,MAAM;IACN,MAAM;IACN,OAAO;IACP,QAAQ;IACR,OAAO;IACP,OAAO;IACP,SAAS;IACT,aAAa;IACb,eAAe;IACf,UAAU;IACV,aAAa;IACb,QAAQ;IACR,QAAQ;IACR,eAAe;IACf,OAAO;IACP,MAAM;IACN,KAAK;IACL,YAAY;IACZ,cAAc;IACd,QAAQ;IACR,mBAAmB;IACnB,WAAW;IACX,gBAAgB;IAChB,WAAW;IACX,UAAU;IACV,WAAW;IACX,OAAO;IACP,YAAY;IACZ,aAAa;CACd,CAAC;AAEF,0EAA0E;AAC1E,MAAM,mBAAmB,GAAG,GAAG,GAAG,IAAI,CAAC;AAEvC,MAAM,OAAO,aAAa;IAChB,EAAE,CAAS;IACX,OAAO,CAAS;IAExB,YAAY,OAAe;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,CAAC;QAEnB,+BAA+B;QAC/B,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAE3B,kBAAkB;QAClB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;QAE3D,gDAAgD;QAChD,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACjE,CAAC;IAED;;;OAGG;IACK,cAAc,CAAC,QAAgB;QACrC,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;gBAAE,OAAO;YAErC,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACnD,MAAM,QAAQ,GAAG,OAAO;iBACrB,KAAK,CAAC,IAAI,CAAC;iBACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;iBAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;YAE9D,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,kCAAkC;QACpC,CAAC;IACH,CAAC;IAED,kDAAkD;IAC3C,SAAS,CAAC,YAAoB;QACnC,IAAI,CAAC,YAAY;YAAE,OAAO,KAAK,CAAC;QAChC,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACvC,CAAC;IAED;;;OAGG;IACI,aAAa,CAAC,GAAY;QAC/B,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC;QACvD,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IAEO,IAAI,CAAC,UAAkB,EAAE,SAAmB;QAClD,IAAI,OAAoB,CAAC;QACzB,IAAI,CAAC;YACH,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,UAAU,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,0CAA0C;QACpD,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACnD,MAAM,YAAY,GAAG,IAAI;iBACtB,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC;iBAChC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAEvB,qBAAqB;YACrB,IAAI,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC;gBAAE,SAAS;YAE3C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,6DAA6D;gBAC7D,IAAI,IAAI,CAAC,SAAS,CAAC,YAAY,GAAG,GAAG,CAAC;oBAAE,SAAS;gBACjD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YACjC,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC1B,gCAAgC;gBAChC,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;oBACnC,IAAI,IAAI,CAAC,IAAI,GAAG,mBAAmB;wBAAE,SAAS;gBAChD,CAAC;gBAAC,MAAM,CAAC;oBACP,SAAS;gBACX,CAAC;gBACD,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC3B,CAAC;YACD,kDAAkD;QACpD,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,17 @@
1
+ import { replaceDartSymbol } from "../src/ast/writers/dartWriter.js";
2
+ const dartCRLF = "class BadgeService {\r\n static void update({int? cart}) {\r\n if (cart != null) {\r\n print(cart);\r\n }\r\n }\r\n}\r\n";
3
+ const newMethod = " static void update({int? cart}) {\r\n if (cart != null) {\r\n print('Updated: $cart');\r\n }\r\n }";
4
+ console.log("=== ORIGINAL ===");
5
+ console.log(dartCRLF);
6
+ console.log("\n=== NEW CONTENT ===");
7
+ console.log(newMethod);
8
+ const result = replaceDartSymbol(dartCRLF, "update", newMethod);
9
+ console.log("\n=== RESULT ===");
10
+ console.log(JSON.stringify(result, null, 2));
11
+ console.log("\n=== NEW FILE CONTENT ===");
12
+ console.log(result.newContent);
13
+ console.log("\n=== BRACE COUNT ===");
14
+ const openBraces = (result.newContent.match(/{/g) || []).length;
15
+ const closeBraces = (result.newContent.match(/}/g) || []).length;
16
+ console.log(`Open: ${openBraces}, Close: ${closeBraces}`);
17
+ //# sourceMappingURL=debug-replace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-replace.js","sourceRoot":"","sources":["../../tests/debug-replace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAErE,MAAM,QAAQ,GAAG,uIAAuI,CAAC;AAEzJ,MAAM,SAAS,GAAG,kHAAkH,CAAC;AAErI,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAChC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACtB,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;AACrC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAEvB,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;AAEhE,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAChC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAE7C,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;AAC1C,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAE/B,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;AACrC,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;AAChE,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;AACjE,OAAO,CAAC,GAAG,CAAC,SAAS,UAAU,YAAY,WAAW,EAAE,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,43 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { handleWriteFileSurgical, handleRollbackFile } from '../src/index.js';
4
+ async function testWorkflow() {
5
+ const testFile = path.resolve('test-artifact.ts');
6
+ const initialContent = 'export class Old { build() { return 1; } }';
7
+ fs.writeFileSync(testFile, initialContent, 'utf-8');
8
+ console.log('--- Step 1: Preview (Dry-Run) ---');
9
+ const previewArgs = {
10
+ filePath: testFile,
11
+ symbolName: 'build',
12
+ newContent: ' build() { return "new value"; }',
13
+ className: 'Old'
14
+ };
15
+ const p1 = await handleWriteFileSurgical(previewArgs);
16
+ const p1Text = p1.content[0].text;
17
+ console.log('Preview Result:', p1Text.split('\n')[0]);
18
+ const tokenMatch = p1Text.match(/confirmationToken: "([^"]+)"/);
19
+ if (!tokenMatch)
20
+ throw new Error('No token found');
21
+ const token = tokenMatch[1];
22
+ console.log('Token found:', token);
23
+ console.log('\n--- Step 2: Confirm ---');
24
+ const confirmArgs = {
25
+ ...previewArgs,
26
+ confirmationToken: token,
27
+ confirm: true
28
+ };
29
+ const p2 = await handleWriteFileSurgical(confirmArgs);
30
+ console.log('Confirm Result:', p2.content[0].text.split('\n')[0]);
31
+ console.log('File Content:', fs.readFileSync(testFile, 'utf-8'));
32
+ console.log('\n--- Step 3: Rollback ---');
33
+ await handleRollbackFile({ filePath: testFile, steps: 1 });
34
+ console.log('After Rollback:', fs.readFileSync(testFile, 'utf-8'));
35
+ // Clean up
36
+ fs.unlinkSync(testFile);
37
+ const backupDir = path.join(path.dirname(testFile), '.mcp-backups');
38
+ if (fs.existsSync(backupDir)) {
39
+ fs.rmSync(backupDir, { recursive: true, force: true });
40
+ }
41
+ }
42
+ testWorkflow().catch(console.error);
43
+ //# sourceMappingURL=test-confirmation-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-confirmation-flow.js","sourceRoot":"","sources":["../../tests/test-confirmation-flow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE9E,KAAK,UAAU,YAAY;IACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,4CAA4C,CAAC;IACpE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;IAEpD,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACjD,MAAM,WAAW,GAAG;QAClB,QAAQ,EAAE,QAAQ;QAClB,UAAU,EAAE,OAAO;QACnB,UAAU,EAAE,mCAAmC;QAC/C,SAAS,EAAE,KAAK;KACjB,CAAC;IAEF,MAAM,EAAE,GAAG,MAAM,uBAAuB,CAAC,WAAW,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEtD,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAChE,IAAI,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IAEnC,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG;QAClB,GAAG,WAAW;QACd,iBAAiB,EAAE,KAAK;QACxB,OAAO,EAAE,IAAI;KACd,CAAC;IACF,MAAM,EAAE,GAAG,MAAM,uBAAuB,CAAC,WAAW,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAEjE,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAC1C,MAAM,kBAAkB,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAEnE,WAAW;IACX,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACxB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC,CAAC;IACpE,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED,YAAY,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Test script for Dart compression.
3
+ */
4
+ import { compressDart, extractDartSymbol } from "../src/ast/dartCompressor.js";
5
+ import * as fs from "node:fs";
6
+ function log(label, value) {
7
+ console.log(`\n${"─".repeat(60)}`);
8
+ console.log(`✅ ${label}`);
9
+ console.log(`${"─".repeat(60)}`);
10
+ console.log(typeof value === "number" ? String(value) : value);
11
+ }
12
+ function fail(label, reason) {
13
+ console.log(`\n${"─".repeat(60)}`);
14
+ console.log(`❌ FAIL: ${label}`);
15
+ console.log(`${"─".repeat(60)}`);
16
+ console.log(reason);
17
+ process.exitCode = 1;
18
+ }
19
+ async function main() {
20
+ let passed = 0;
21
+ let failed = 0;
22
+ // ─── Test 1: Real class (HomeRepository) ──────────────────────────
23
+ console.log("\n\n🧪 TEST 1: Compress HomeRepository.dart (Classes, getters, Future methods, docstrings)");
24
+ const repoPath = "c:/code/detodo24_mobile/lib/features/home/data/repositories/home_repository.dart";
25
+ if (fs.existsSync(repoPath)) {
26
+ const content = fs.readFileSync(repoPath, "utf-8");
27
+ const compressed = compressDart(content);
28
+ const originalLines = content.split("\n").length;
29
+ const compressedLines = compressed.split("\n").length;
30
+ const ratio = ((1 - compressedLines / originalLines) * 100).toFixed(1);
31
+ log(`HomeRepository: ${originalLines} → ${compressedLines} lines (${ratio}% reduction)`, compressed);
32
+ const checks = [
33
+ ["import block", /import 'dart:convert';/],
34
+ ["class declaration", /class HomeRepository/],
35
+ ["final field", /final http\.Client _httpClient;/],
36
+ ["static const field", /static const String _authHomeApiUrl/],
37
+ ["constructor", /HomeRepository\(/],
38
+ ["async method", /Future<List<Map<String, dynamic>>> fetchSections/],
39
+ ["private async method", /Future<List<Map<String, dynamic>>> _fetchSectionsAuth/],
40
+ ["doc comment", /Obtiene recomendaciones por misión Amazon-style/],
41
+ ["body stripped", /\{ \/\* \.\.\. \*\/ \}/]
42
+ ];
43
+ for (const [name, pattern] of checks) {
44
+ if (pattern.test(compressed)) {
45
+ console.log(` ✓ Found: ${name}`);
46
+ passed++;
47
+ }
48
+ else {
49
+ fail(`Missing: ${name}`, `Pattern ${pattern} not found`);
50
+ failed++;
51
+ }
52
+ }
53
+ }
54
+ // ─── Test 2: Real Widget (DT24Loading) ────────────────────────────
55
+ console.log("\n\n🧪 TEST 2: Compress dt24_loading.dart (StatefulWidget, CustomPainter, @override)");
56
+ const widgetPath = "c:/code/detodo24_mobile/lib/widgets/dt24_loading.dart";
57
+ if (fs.existsSync(widgetPath)) {
58
+ const content = fs.readFileSync(widgetPath, "utf-8");
59
+ const compressed = compressDart(content);
60
+ log("DT24Loading compressed:", compressed);
61
+ const checks = [
62
+ ["StatefulWidget", /class DT24Loading extends StatefulWidget/],
63
+ ["doc comment", /Widget de carga personalizado/],
64
+ ["const constructor", /const DT24Loading/],
65
+ ["@override", /@override/],
66
+ ["State class", /class _DT24LoadingState extends State<DT24Loading>/],
67
+ ["mixin", /with SingleTickerProviderStateMixin/],
68
+ ["CustomPainter", /class _DT24LoadingPainter extends CustomPainter/],
69
+ ["method with complex generic", /State<DT24Loading> createState\(\) => \/\* \.\.\. \*\/;/]
70
+ ];
71
+ for (const [name, pattern] of checks) {
72
+ if (pattern.test(compressed)) {
73
+ console.log(` ✓ Found: ${name}`);
74
+ passed++;
75
+ }
76
+ else {
77
+ fail(`Missing: ${name}`, `Pattern ${pattern} not found`);
78
+ failed++;
79
+ }
80
+ }
81
+ }
82
+ // ─── Test 3: Symbol Extraction ────────────────────────────────────
83
+ console.log("\n\n🧪 TEST 3: Surgical Symbol Extraction (Dart)");
84
+ if (fs.existsSync(repoPath)) {
85
+ const content = fs.readFileSync(repoPath, "utf-8");
86
+ // Extract class
87
+ const repoClass = extractDartSymbol(content, "HomeRepository");
88
+ if (repoClass && repoClass.includes("class HomeRepository")) {
89
+ console.log(` ✓ Successfully extracted class HomeRepository (${repoClass.split("\n").length} lines)`);
90
+ passed++;
91
+ }
92
+ else {
93
+ fail("Extract class", "Failed to extract HomeRepository");
94
+ failed++;
95
+ }
96
+ // Extract method
97
+ const fetchMethod = extractDartSymbol(content, "fetchSections");
98
+ if (fetchMethod && fetchMethod.includes("Future<List<Map<String, dynamic>>> fetchSections")) {
99
+ console.log(` ✓ Successfully extracted method fetchSections (${fetchMethod.split("\n").length} lines)`);
100
+ passed++;
101
+ }
102
+ else {
103
+ fail("Extract method", "Failed to extract fetchSections");
104
+ failed++;
105
+ }
106
+ }
107
+ // ─── Test 4: Synthetic Dart with all patterns ─────────────────────
108
+ console.log("\n\n🧪 TEST 4: Synthetic Dart with mixins, enums, extensions, types");
109
+ const syntheticDart = `
110
+ import 'dart:async';
111
+ import 'package:flutter/material.dart';
112
+
113
+ part 'model.g.dart';
114
+
115
+ /// Top level typedef
116
+ typedef JsonMap = Map<String, dynamic>;
117
+
118
+ /// User State enum
119
+ enum UserState {
120
+ loggedOut,
121
+ loggedIn,
122
+ loading;
123
+
124
+ bool get isActive => this == UserState.loggedIn;
125
+ }
126
+
127
+ /// Logger mixin
128
+ mixin Logger on Object {
129
+ void log(String message) {
130
+ print('[\${runtimeType}] \$message');
131
+ }
132
+ }
133
+
134
+ /// Extension on String
135
+ extension StringUtils on String {
136
+ bool get isBlank => trim().isEmpty;
137
+
138
+ String capitalize() {
139
+ if (isBlank) return this;
140
+ return '\${this[0].toUpperCase()}\${substring(1)}';
141
+ }
142
+ }
143
+
144
+ /// Base user model
145
+ sealed class UserModel with Logger {
146
+ final String id;
147
+
148
+ const UserModel({required this.id});
149
+
150
+ factory UserModel.fromJson(JsonMap json) {
151
+ return NormalUser(id: json['id']);
152
+ }
153
+ }
154
+
155
+ class NormalUser extends UserModel {
156
+ final String name;
157
+ late final String uppercaseName;
158
+
159
+ NormalUser({
160
+ required String id,
161
+ this.name = '',
162
+ }) : super(id: id) {
163
+ uppercaseName = name.toUpperCase();
164
+ }
165
+
166
+ @override
167
+ String toString() => 'User(\$id, \$name)';
168
+
169
+ Future<void> save() async {
170
+ await Future.delayed(const Duration(seconds: 1));
171
+ log('Saved \$name');
172
+ }
173
+ }
174
+ `;
175
+ const compressedSyntax = compressDart(syntheticDart);
176
+ log("Synthetic compressed", compressedSyntax);
177
+ const synthChecks = [
178
+ ["part statement", /part 'model.g.dart';/],
179
+ ["typedef", /typedef JsonMap = Map<String, dynamic>;/],
180
+ ["enum", /enum UserState {/],
181
+ ["enum cases", /loggedOut,\s+loggedIn,\s+loading;/],
182
+ ["enum method", /bool get isActive => \/\* \.\.\. \*\/;/],
183
+ ["mixin", /mixin Logger on Object {/],
184
+ ["extension", /extension StringUtils on String {/],
185
+ ["extension getter", /bool get isBlank => \/\* \.\.\. \*\/;/],
186
+ ["sealed class", /sealed class UserModel with Logger {/],
187
+ ["const constructor", /const UserModel\({required this.id}\);/],
188
+ ["factory constructor", /factory UserModel.fromJson\(JsonMap json\) { \/\* \.\.\. \*\/ }/],
189
+ ["late final field", /late final String uppercaseName;/],
190
+ ["initializer list constructor", /NormalUser\([\s\S]*?\) : super\(id: id\) { \/\* \.\.\. \*\/ }/],
191
+ ["arrow function override", /@override\s+String toString\(\) => \/\* \.\.\. \*\/;/]
192
+ ];
193
+ for (const [name, pattern] of synthChecks) {
194
+ if (pattern.test(compressedSyntax)) {
195
+ console.log(` ✓ Found: ${name}`);
196
+ passed++;
197
+ }
198
+ else {
199
+ fail(`Missing: ${name}`, `Pattern ${pattern} not found in compressed output`);
200
+ failed++;
201
+ }
202
+ }
203
+ // ─── Test 5: ClassName Extraction Disambiguation ─────────────
204
+ console.log("\n\n🧪 TEST 5: ClassName Extraction Disambiguation");
205
+ const multiClassDart = `
206
+ class ClassA {
207
+ void build() {
208
+ print('A');
209
+ }
210
+ }
211
+
212
+ class ClassB {
213
+ void build() {
214
+ print('B');
215
+ }
216
+ }
217
+ `;
218
+ const extractedBuildA = extractDartSymbol(multiClassDart, "build", "ClassA");
219
+ if (extractedBuildA && extractedBuildA.includes("print('A');")) {
220
+ console.log(` ✓ Successfully extracted build from ClassA`);
221
+ passed++;
222
+ }
223
+ else {
224
+ fail("Extract ClassA build", "Failed to properly extract build from ClassA");
225
+ failed++;
226
+ }
227
+ const extractedBuildB = extractDartSymbol(multiClassDart, "build", "ClassB");
228
+ if (extractedBuildB && extractedBuildB.includes("print('B');")) {
229
+ console.log(` ✓ Successfully extracted build from ClassB`);
230
+ passed++;
231
+ }
232
+ else {
233
+ fail("Extract ClassB build", "Failed to properly extract build from ClassB");
234
+ failed++;
235
+ }
236
+ // ─── Summary ─────────────────────────────────────────────────
237
+ console.log(`\n\n${"═".repeat(60)}`);
238
+ console.log(`📊 RESULTS: ${passed} passed, ${failed} failed`);
239
+ console.log(`${"═".repeat(60)}\n`);
240
+ }
241
+ main().catch(console.error);
242
+ //# sourceMappingURL=test-dart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-dart.js","sourceRoot":"","sources":["../../tests/test-dart.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Quick test to understand php-parser AST node structure.
3
+ * Run: npx ts-node src/test-php-ast.ts
4
+ */
5
+ import { createRequire } from "node:module";
6
+ const require = createRequire(import.meta.url);
7
+ const Engine = require("php-parser");
8
+ const parser = new Engine({
9
+ parser: { extractDoc: true, php7: true, php8: true },
10
+ ast: { withPositions: true, withSource: true },
11
+ });
12
+ const code = `<?php
13
+ namespace App\\Services;
14
+
15
+ use App\\Models\\User;
16
+ use App\\Contracts\\Cacheable;
17
+
18
+ interface Loggable {
19
+ public function getLogName(): string;
20
+ }
21
+
22
+ trait HasTimestamps {
23
+ /** Get current timestamp */
24
+ private function now(): int {
25
+ return time();
26
+ }
27
+ }
28
+
29
+ abstract class BaseService {
30
+ abstract public function execute(): void;
31
+
32
+ protected function log(string $msg): void {
33
+ echo $msg;
34
+ }
35
+ }
36
+
37
+ class UserService extends BaseService implements Loggable, Cacheable {
38
+ use HasTimestamps;
39
+
40
+ private string $name;
41
+ public const VERSION = '1.0';
42
+
43
+ /**
44
+ * Create a new UserService instance.
45
+ * @param string $name The user name
46
+ */
47
+ public function __construct(string $name) {
48
+ $this->name = $name;
49
+ }
50
+
51
+ public function execute(): void {
52
+ $this->log($this->name);
53
+ }
54
+
55
+ public function getLogName(): string {
56
+ return $this->name;
57
+ }
58
+
59
+ public static function create(string $n): self {
60
+ return new self($n);
61
+ }
62
+ }
63
+
64
+ function helper(int $x, string $y = 'default'): bool {
65
+ return $x > 0;
66
+ }
67
+
68
+ $lambda = function(int $a): int {
69
+ return $a * 2;
70
+ };
71
+
72
+ enum Color: string {
73
+ case Red = 'red';
74
+ case Blue = 'blue';
75
+ }
76
+ `;
77
+ const ast = parser.parseCode(code, "test.php");
78
+ function printNode(node, depth = 0) {
79
+ if (!node || typeof node !== "object")
80
+ return;
81
+ const indent = " ".repeat(depth);
82
+ if (node.kind) {
83
+ const info = [`${indent}[${node.kind}]`];
84
+ if (node.name) {
85
+ const name = typeof node.name === "string" ? node.name : node.name?.name || "";
86
+ info.push(`name="${name}"`);
87
+ }
88
+ if (node.visibility)
89
+ info.push(`visibility="${node.visibility}"`);
90
+ if (node.isStatic)
91
+ info.push("static");
92
+ if (node.isAbstract)
93
+ info.push("abstract");
94
+ if (node.isFinal)
95
+ info.push("final");
96
+ if (node.nullable)
97
+ info.push("nullable");
98
+ if (node.type) {
99
+ const t = typeof node.type === "string" ? node.type : node.type?.name || JSON.stringify(node.type?.kind);
100
+ info.push(`type=${t}`);
101
+ }
102
+ if (node.extends) {
103
+ const ext = typeof node.extends === "string" ? node.extends : node.extends?.name || "";
104
+ info.push(`extends=${ext}`);
105
+ }
106
+ if (node.implements && node.implements.length > 0) {
107
+ info.push(`implements=[${node.implements.map((i) => i.name || i).join(", ")}]`);
108
+ }
109
+ if (node.value && typeof node.value === "string") {
110
+ info.push(`value="${node.value.substring(0, 40)}"`);
111
+ }
112
+ if (node.leadingComments) {
113
+ info.push(`docComment=YES`);
114
+ }
115
+ console.log(info.join(" "));
116
+ // Print arguments/parameters
117
+ if (node.arguments && Array.isArray(node.arguments)) {
118
+ for (const arg of node.arguments) {
119
+ printNode(arg, depth + 1);
120
+ }
121
+ }
122
+ // Print children/body
123
+ if (node.children && Array.isArray(node.children)) {
124
+ for (const child of node.children) {
125
+ printNode(child, depth + 1);
126
+ }
127
+ }
128
+ if (node.body && Array.isArray(node.body)) {
129
+ for (const child of node.body) {
130
+ printNode(child, depth + 1);
131
+ }
132
+ }
133
+ if (node.items && Array.isArray(node.items)) {
134
+ for (const item of node.items) {
135
+ printNode(item, depth + 1);
136
+ }
137
+ }
138
+ if (node.cases && Array.isArray(node.cases)) {
139
+ for (const c of node.cases) {
140
+ printNode(c, depth + 1);
141
+ }
142
+ }
143
+ if (node.traits && Array.isArray(node.traits)) {
144
+ for (const t of node.traits) {
145
+ printNode(t, depth + 1);
146
+ }
147
+ }
148
+ }
149
+ }
150
+ console.log("=== PHP AST Node Structure ===\n");
151
+ printNode(ast);
152
+ //# sourceMappingURL=test-php-ast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-php-ast.js","sourceRoot":"","sources":["../../tests/test-php-ast.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};