repoburg 1.3.9 → 1.3.10

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 (226) hide show
  1. package/backend/dist/bin/grammar/tree-sitter-bash.wasm +0 -0
  2. package/backend/dist/bin/grammar/tree-sitter-css.wasm +0 -0
  3. package/backend/dist/bin/grammar/tree-sitter-html.wasm +0 -0
  4. package/backend/dist/bin/grammar/tree-sitter-javascript.wasm +0 -0
  5. package/backend/dist/bin/grammar/tree-sitter-json.wasm +0 -0
  6. package/backend/dist/bin/grammar/tree-sitter-python.wasm +0 -0
  7. package/backend/dist/bin/grammar/tree-sitter-rust.wasm +0 -0
  8. package/backend/dist/bin/grammar/tree-sitter-toml.wasm +0 -0
  9. package/backend/dist/bin/grammar/tree-sitter-tsx.wasm +0 -0
  10. package/backend/dist/bin/grammar/tree-sitter-typescript.wasm +0 -0
  11. package/backend/dist/bin/grammar/tree-sitter-yaml.wasm +0 -0
  12. package/backend/dist/packages/tokenpatch/index.d.ts +1 -0
  13. package/backend/dist/packages/tokenpatch/index.js +52 -0
  14. package/backend/dist/packages/tokenpatch/index.js.map +1 -0
  15. package/backend/dist/packages/tokenpatch/parser.d.ts +2 -0
  16. package/backend/dist/packages/tokenpatch/parser.js +17 -0
  17. package/backend/dist/packages/tokenpatch/parser.js.map +1 -0
  18. package/backend/dist/packages/tokenpatch/patcher.d.ts +11 -0
  19. package/backend/dist/packages/tokenpatch/patcher.js +189 -0
  20. package/backend/dist/packages/tokenpatch/patcher.js.map +1 -0
  21. package/backend/dist/packages/tokenpatch/tokens.d.ts +6 -0
  22. package/backend/dist/packages/tokenpatch/tokens.js +49 -0
  23. package/backend/dist/packages/tokenpatch/tokens.js.map +1 -0
  24. package/backend/dist/packages/tokenpatch/types.d.ts +8 -0
  25. package/backend/dist/packages/tokenpatch/types.js +3 -0
  26. package/backend/dist/packages/tokenpatch/types.js.map +1 -0
  27. package/backend/dist/src/ai-actions/ai-actions.service.d.ts +1 -0
  28. package/backend/dist/src/ai-actions/ai-actions.service.js +2 -0
  29. package/backend/dist/src/ai-actions/ai-actions.service.js.map +1 -1
  30. package/backend/dist/src/llm-orchestration/action-handlers/dto/patch.args.dto.d.ts +4 -0
  31. package/backend/dist/src/llm-orchestration/action-handlers/dto/patch.args.dto.js +29 -0
  32. package/backend/dist/src/llm-orchestration/action-handlers/dto/patch.args.dto.js.map +1 -0
  33. package/backend/dist/src/llm-orchestration/action-handlers/patch.handler.d.ts +12 -0
  34. package/backend/dist/src/llm-orchestration/action-handlers/patch.handler.js +142 -0
  35. package/backend/dist/src/llm-orchestration/action-handlers/patch.handler.js.map +1 -0
  36. package/backend/dist/src/llm-orchestration/llm-orchestration.module.js +2 -0
  37. package/backend/dist/src/llm-orchestration/llm-orchestration.module.js.map +1 -1
  38. package/backend/dist/src/llm-orchestration/llm-turn-processor.service.js +1 -0
  39. package/backend/dist/src/llm-orchestration/llm-turn-processor.service.js.map +1 -1
  40. package/backend/dist/src/seeding/data/system-prompts/experimental_patch_master-agent.d.ts +2 -0
  41. package/backend/dist/src/seeding/data/system-prompts/experimental_patch_master-agent.js +463 -0
  42. package/backend/dist/src/seeding/data/system-prompts/experimental_patch_master-agent.js.map +1 -0
  43. package/backend/dist/tsconfig.build.tsbuildinfo +1 -1
  44. package/backend/package.json +6 -3
  45. package/backend/packages/tokenpatch/grammar/tree-sitter-tsx.wasm +0 -0
  46. package/backend/packages/tokenpatch/grammar/tree-sitter-typescript.wasm +0 -0
  47. package/backend/packages/tokenpatch/index.spec.ts +579 -0
  48. package/backend/packages/tokenpatch/index.ts +80 -0
  49. package/backend/packages/tokenpatch/parser.ts +18 -0
  50. package/backend/packages/tokenpatch/patcher.spec.ts +194 -0
  51. package/backend/packages/tokenpatch/patcher.ts +300 -0
  52. package/backend/packages/tokenpatch/tokens.spec.ts +84 -0
  53. package/backend/packages/tokenpatch/tokens.ts +50 -0
  54. package/backend/packages/tokenpatch/types.ts +9 -0
  55. package/package.json +13 -12
  56. package/backend/coverage/clover.xml +0 -3434
  57. package/backend/coverage/coverage-final.json +0 -120
  58. package/backend/coverage/lcov-report/base.css +0 -224
  59. package/backend/coverage/lcov-report/block-navigation.js +0 -87
  60. package/backend/coverage/lcov-report/favicon.png +0 -0
  61. package/backend/coverage/lcov-report/index.html +0 -701
  62. package/backend/coverage/lcov-report/prettify.css +0 -1
  63. package/backend/coverage/lcov-report/prettify.js +0 -2
  64. package/backend/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  65. package/backend/coverage/lcov-report/sorter.js +0 -196
  66. package/backend/coverage/lcov-report/src/action-execution/action-execution.module.ts.html +0 -109
  67. package/backend/coverage/lcov-report/src/action-execution/action-execution.service.ts.html +0 -448
  68. package/backend/coverage/lcov-report/src/action-execution/index.html +0 -131
  69. package/backend/coverage/lcov-report/src/ai-actions/ai-action-batch.service.ts.html +0 -940
  70. package/backend/coverage/lcov-report/src/ai-actions/ai-action-creation.service.ts.html +0 -1243
  71. package/backend/coverage/lcov-report/src/ai-actions/ai-actions.controller.ts.html +0 -664
  72. package/backend/coverage/lcov-report/src/ai-actions/ai-actions.module.ts.html +0 -154
  73. package/backend/coverage/lcov-report/src/ai-actions/ai-actions.service.ts.html +0 -859
  74. package/backend/coverage/lcov-report/src/ai-actions/index.html +0 -176
  75. package/backend/coverage/lcov-report/src/app.controller.ts.html +0 -151
  76. package/backend/coverage/lcov-report/src/app.module.ts.html +0 -373
  77. package/backend/coverage/lcov-report/src/app.service.ts.html +0 -196
  78. package/backend/coverage/lcov-report/src/application-state/application-state.controller.ts.html +0 -319
  79. package/backend/coverage/lcov-report/src/application-state/application-state.module.ts.html +0 -124
  80. package/backend/coverage/lcov-report/src/application-state/application-state.service.ts.html +0 -439
  81. package/backend/coverage/lcov-report/src/application-state/dto/index.html +0 -161
  82. package/backend/coverage/lcov-report/src/application-state/dto/set-auto-context-fetch-enabled.dto.ts.html +0 -103
  83. package/backend/coverage/lcov-report/src/application-state/dto/set-orchestration-timeout.dto.ts.html +0 -103
  84. package/backend/coverage/lcov-report/src/application-state/dto/set-theme.dto.ts.html +0 -106
  85. package/backend/coverage/lcov-report/src/application-state/dto/set-websocket-enabled.dto.ts.html +0 -103
  86. package/backend/coverage/lcov-report/src/application-state/index.html +0 -146
  87. package/backend/coverage/lcov-report/src/context-generation/context-generation.module.ts.html +0 -118
  88. package/backend/coverage/lcov-report/src/context-generation/context-generation.service.ts.html +0 -1348
  89. package/backend/coverage/lcov-report/src/context-generation/index.html +0 -131
  90. package/backend/coverage/lcov-report/src/context-snippets/context-snippets.controller.ts.html +0 -289
  91. package/backend/coverage/lcov-report/src/context-snippets/context-snippets.module.ts.html +0 -136
  92. package/backend/coverage/lcov-report/src/context-snippets/context-snippets.service.ts.html +0 -400
  93. package/backend/coverage/lcov-report/src/context-snippets/dto/context-snippet.dto.ts.html +0 -211
  94. package/backend/coverage/lcov-report/src/context-snippets/dto/index.html +0 -116
  95. package/backend/coverage/lcov-report/src/context-snippets/index.html +0 -146
  96. package/backend/coverage/lcov-report/src/context-templates/context-templates.controller.ts.html +0 -397
  97. package/backend/coverage/lcov-report/src/context-templates/context-templates.module.ts.html +0 -136
  98. package/backend/coverage/lcov-report/src/context-templates/context-templates.service.ts.html +0 -835
  99. package/backend/coverage/lcov-report/src/context-templates/dto/context-template.dto.ts.html +0 -358
  100. package/backend/coverage/lcov-report/src/context-templates/dto/index.html +0 -116
  101. package/backend/coverage/lcov-report/src/context-templates/index.html +0 -146
  102. package/backend/coverage/lcov-report/src/core-entities/ai-action.entity.ts.html +0 -241
  103. package/backend/coverage/lcov-report/src/core-entities/application-state.entity.ts.html +0 -115
  104. package/backend/coverage/lcov-report/src/core-entities/base.entity.ts.html +0 -145
  105. package/backend/coverage/lcov-report/src/core-entities/context-snippet.entity.ts.html +0 -130
  106. package/backend/coverage/lcov-report/src/core-entities/context-template.entity.ts.html +0 -223
  107. package/backend/coverage/lcov-report/src/core-entities/custom-snippet.entity.ts.html +0 -136
  108. package/backend/coverage/lcov-report/src/core-entities/execution-log.entity.ts.html +0 -157
  109. package/backend/coverage/lcov-report/src/core-entities/index.html +0 -281
  110. package/backend/coverage/lcov-report/src/core-entities/index.ts.html +0 -118
  111. package/backend/coverage/lcov-report/src/core-entities/project.entity.ts.html +0 -130
  112. package/backend/coverage/lcov-report/src/core-entities/session-input.entity.ts.html +0 -289
  113. package/backend/coverage/lcov-report/src/core-entities/session.entity.ts.html +0 -280
  114. package/backend/coverage/lcov-report/src/core-entities/system-prompt.entity.ts.html +0 -148
  115. package/backend/coverage/lcov-report/src/custom-snippets/custom-snippets.controller.ts.html +0 -277
  116. package/backend/coverage/lcov-report/src/custom-snippets/custom-snippets.module.ts.html +0 -124
  117. package/backend/coverage/lcov-report/src/custom-snippets/custom-snippets.service.ts.html +0 -304
  118. package/backend/coverage/lcov-report/src/custom-snippets/dto/custom-snippet.dto.ts.html +0 -205
  119. package/backend/coverage/lcov-report/src/custom-snippets/dto/index.html +0 -116
  120. package/backend/coverage/lcov-report/src/custom-snippets/index.html +0 -146
  121. package/backend/coverage/lcov-report/src/events/events.gateway.ts.html +0 -292
  122. package/backend/coverage/lcov-report/src/events/events.module.ts.html +0 -109
  123. package/backend/coverage/lcov-report/src/events/index.html +0 -131
  124. package/backend/coverage/lcov-report/src/execution-logs/dto/execution-log.dto.ts.html +0 -130
  125. package/backend/coverage/lcov-report/src/execution-logs/dto/index.html +0 -116
  126. package/backend/coverage/lcov-report/src/execution-logs/execution-logs.controller.ts.html +0 -130
  127. package/backend/coverage/lcov-report/src/execution-logs/execution-logs.module.ts.html +0 -124
  128. package/backend/coverage/lcov-report/src/execution-logs/execution-logs.service.ts.html +0 -238
  129. package/backend/coverage/lcov-report/src/execution-logs/index.html +0 -146
  130. package/backend/coverage/lcov-report/src/http-exception.filter.ts.html +0 -340
  131. package/backend/coverage/lcov-report/src/index.html +0 -191
  132. package/backend/coverage/lcov-report/src/llm-response-parser/dto/ai-action.dto.ts.html +0 -400
  133. package/backend/coverage/lcov-report/src/llm-response-parser/dto/index.html +0 -116
  134. package/backend/coverage/lcov-report/src/llm-response-parser/errors/index.html +0 -116
  135. package/backend/coverage/lcov-report/src/llm-response-parser/errors/parsing.error.ts.html +0 -118
  136. package/backend/coverage/lcov-report/src/llm-response-parser/index.html +0 -146
  137. package/backend/coverage/lcov-report/src/llm-response-parser/llm-response-parser.module.ts.html +0 -109
  138. package/backend/coverage/lcov-report/src/llm-response-parser/llm-response-parser.service.ts.html +0 -808
  139. package/backend/coverage/lcov-report/src/llm-response-parser/parsing.constants.ts.html +0 -139
  140. package/backend/coverage/lcov-report/src/llm-responses/dto/index.html +0 -116
  141. package/backend/coverage/lcov-report/src/llm-responses/dto/submit-llm-response.dto.ts.html +0 -172
  142. package/backend/coverage/lcov-report/src/llm-responses/index.html +0 -146
  143. package/backend/coverage/lcov-report/src/llm-responses/llm-responses.controller.ts.html +0 -154
  144. package/backend/coverage/lcov-report/src/llm-responses/llm-responses.module.ts.html +0 -166
  145. package/backend/coverage/lcov-report/src/llm-responses/llm-responses.service.ts.html +0 -787
  146. package/backend/coverage/lcov-report/src/main.ts.html +0 -382
  147. package/backend/coverage/lcov-report/src/orchestration/dto/index.html +0 -116
  148. package/backend/coverage/lcov-report/src/orchestration/dto/orchestration.dto.ts.html +0 -169
  149. package/backend/coverage/lcov-report/src/orchestration/index.html +0 -191
  150. package/backend/coverage/lcov-report/src/orchestration/orchestration-fs.service.ts.html +0 -595
  151. package/backend/coverage/lcov-report/src/orchestration/orchestration-parser.service.ts.html +0 -142
  152. package/backend/coverage/lcov-report/src/orchestration/orchestration.controller.ts.html +0 -406
  153. package/backend/coverage/lcov-report/src/orchestration/orchestration.module.ts.html +0 -169
  154. package/backend/coverage/lcov-report/src/orchestration/orchestration.service.ts.html +0 -1093
  155. package/backend/coverage/lcov-report/src/orchestration/orchestration.types.ts.html +0 -175
  156. package/backend/coverage/lcov-report/src/projects/dto/index.html +0 -116
  157. package/backend/coverage/lcov-report/src/projects/dto/project.dto.ts.html +0 -154
  158. package/backend/coverage/lcov-report/src/projects/index.html +0 -146
  159. package/backend/coverage/lcov-report/src/projects/projects.controller.ts.html +0 -232
  160. package/backend/coverage/lcov-report/src/projects/projects.module.ts.html +0 -124
  161. package/backend/coverage/lcov-report/src/projects/projects.service.ts.html +0 -223
  162. package/backend/coverage/lcov-report/src/seeding/context-template-seeding.service.ts.html +0 -355
  163. package/backend/coverage/lcov-report/src/seeding/custom-snippet-seeding.service.ts.html +0 -271
  164. package/backend/coverage/lcov-report/src/seeding/data/context-templates/default-followup_ad-hoc-focused-context.ts.html +0 -136
  165. package/backend/coverage/lcov-report/src/seeding/data/context-templates/default-initial_condensed-project-context.ts.html +0 -148
  166. package/backend/coverage/lcov-report/src/seeding/data/context-templates/default-initial_full-project-context.ts.html +0 -247
  167. package/backend/coverage/lcov-report/src/seeding/data/context-templates/index.html +0 -190
  168. package/backend/coverage/lcov-report/src/seeding/data/context-templates/pm-context.ts.html +0 -250
  169. package/backend/coverage/lcov-report/src/seeding/data/context-templates/pr-description.ts.html +0 -186
  170. package/backend/coverage/lcov-report/src/seeding/data/context-templates/sample_focused-tree.ts.html +0 -124
  171. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/default_rglob.ts.html +0 -94
  172. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/git-diff.ts.html +0 -94
  173. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/index.html +0 -236
  174. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/rg-exclude.ts.html +0 -94
  175. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/rg-search-glob.ts.html +0 -94
  176. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/rg-search.ts.html +0 -94
  177. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/run-command.ts.html +0 -94
  178. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/tree.ts.html +0 -94
  179. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/usr-adhoc-incl.ts.html +0 -100
  180. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/usr-input-incl.ts.html +0 -94
  181. package/backend/coverage/lcov-report/src/seeding/data/system-prompts/codebase-explorer.ts.html +0 -331
  182. package/backend/coverage/lcov-report/src/seeding/data/system-prompts/default_multi-file-action-generator-with-requester.ts.html +0 -675
  183. package/backend/coverage/lcov-report/src/seeding/data/system-prompts/index.html +0 -160
  184. package/backend/coverage/lcov-report/src/seeding/data/system-prompts/multi-file-action-generator.ts.html +0 -550
  185. package/backend/coverage/lcov-report/src/seeding/data/system-prompts/packup.ts.html +0 -184
  186. package/backend/coverage/lcov-report/src/seeding/data/system-prompts/refactor-split.ts.html +0 -244
  187. package/backend/coverage/lcov-report/src/seeding/index.html +0 -176
  188. package/backend/coverage/lcov-report/src/seeding/seeding.module.ts.html +0 -145
  189. package/backend/coverage/lcov-report/src/seeding/seeding.service.ts.html +0 -151
  190. package/backend/coverage/lcov-report/src/seeding/system-prompt-seeding.service.ts.html +0 -289
  191. package/backend/coverage/lcov-report/src/session-followup/index.html +0 -131
  192. package/backend/coverage/lcov-report/src/session-followup/session-followup.module.ts.html +0 -130
  193. package/backend/coverage/lcov-report/src/session-followup/session-followup.service.ts.html +0 -670
  194. package/backend/coverage/lcov-report/src/session-inputs/dto/index.html +0 -116
  195. package/backend/coverage/lcov-report/src/session-inputs/dto/session-input.dto.ts.html +0 -247
  196. package/backend/coverage/lcov-report/src/session-inputs/index.html +0 -161
  197. package/backend/coverage/lcov-report/src/session-inputs/session-input-context.service.ts.html +0 -763
  198. package/backend/coverage/lcov-report/src/session-inputs/session-inputs.controller.ts.html +0 -337
  199. package/backend/coverage/lcov-report/src/session-inputs/session-inputs.module.ts.html +0 -205
  200. package/backend/coverage/lcov-report/src/session-inputs/session-inputs.service.ts.html +0 -1621
  201. package/backend/coverage/lcov-report/src/session-transfer/index.html +0 -131
  202. package/backend/coverage/lcov-report/src/session-transfer/session-transfer.module.ts.html +0 -172
  203. package/backend/coverage/lcov-report/src/session-transfer/session-transfer.service.ts.html +0 -574
  204. package/backend/coverage/lcov-report/src/sessions/dto/index.html +0 -116
  205. package/backend/coverage/lcov-report/src/sessions/dto/session.dto.ts.html +0 -340
  206. package/backend/coverage/lcov-report/src/sessions/index.html +0 -146
  207. package/backend/coverage/lcov-report/src/sessions/sessions.controller.ts.html +0 -457
  208. package/backend/coverage/lcov-report/src/sessions/sessions.module.ts.html +0 -214
  209. package/backend/coverage/lcov-report/src/sessions/sessions.service.ts.html +0 -844
  210. package/backend/coverage/lcov-report/src/system-prompts/dto/index.html +0 -116
  211. package/backend/coverage/lcov-report/src/system-prompts/dto/system-prompt.dto.ts.html +0 -217
  212. package/backend/coverage/lcov-report/src/system-prompts/index.html +0 -146
  213. package/backend/coverage/lcov-report/src/system-prompts/system-prompts.controller.ts.html +0 -298
  214. package/backend/coverage/lcov-report/src/system-prompts/system-prompts.module.ts.html +0 -127
  215. package/backend/coverage/lcov-report/src/system-prompts/system-prompts.service.ts.html +0 -352
  216. package/backend/coverage/lcov-report/src/timeout.interceptor.ts.html +0 -178
  217. package/backend/coverage/lcov-report/src/utils/fuzzy-search.ts.html +0 -310
  218. package/backend/coverage/lcov-report/src/utils/index.html +0 -131
  219. package/backend/coverage/lcov-report/src/utils/index.ts.html +0 -88
  220. package/backend/coverage/lcov-report/src/workspace/dto/index.html +0 -116
  221. package/backend/coverage/lcov-report/src/workspace/dto/search-workspace.dto.ts.html +0 -193
  222. package/backend/coverage/lcov-report/src/workspace/index.html +0 -146
  223. package/backend/coverage/lcov-report/src/workspace/workspace.controller.ts.html +0 -247
  224. package/backend/coverage/lcov-report/src/workspace/workspace.module.ts.html +0 -121
  225. package/backend/coverage/lcov-report/src/workspace/workspace.service.ts.html +0 -745
  226. package/backend/coverage/lcov.info +0 -5590
@@ -13,7 +13,7 @@
13
13
  "start:debug": "nest start --debug --watch",
14
14
  "start:prod": "NODE_ENV=production node dist/main",
15
15
  "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
16
- "test": "jest --bail",
16
+ "test": "NODE_OPTIONS=--experimental-vm-modules jest --bail",
17
17
  "test:watch": "jest --watch",
18
18
  "test:cov": "jest --coverage",
19
19
  "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
@@ -57,7 +57,10 @@
57
57
  "json",
58
58
  "ts"
59
59
  ],
60
- "rootDir": "src",
60
+ "roots": [
61
+ "<rootDir>/src",
62
+ "<rootDir>/packages"
63
+ ],
61
64
  "testRegex": ".*\\.spec\\.ts$",
62
65
  "transform": {
63
66
  "^.+\\.(t|j)s$": "ts-jest"
@@ -65,7 +68,7 @@
65
68
  "collectCoverageFrom": [
66
69
  "**/*.(t|j)s"
67
70
  ],
68
- "coverageDirectory": "../coverage",
71
+ "coverageDirectory": "coverage",
69
72
  "testEnvironment": "node"
70
73
  }
71
74
  }
@@ -0,0 +1,579 @@
1
+ import { applySnippetPatch } from './index';
2
+ import * as path from 'path';
3
+
4
+ const TS_WASM_PATH = path.join(
5
+ __dirname,
6
+ './grammar/tree-sitter-typescript.wasm',
7
+ );
8
+
9
+ const TSX_WASM_PATH = path.join(__dirname, './grammar/tree-sitter-tsx.wasm');
10
+
11
+ // Helper to normalize whitespace for robust comparison
12
+ const normalize = (str: string) => str.replace(/\s+/g, ' ').trim();
13
+
14
+ describe('applySnippetPatch', () => {
15
+ it('should replace a method body in a class by automatically finding anchor size', async () => {
16
+ const sourceCode = `
17
+ class Greeter {
18
+ greet() {
19
+ return "Hello, world";
20
+ }
21
+
22
+ fc(){ return 42; }
23
+ }
24
+ `;
25
+ const patchCode = `
26
+ greet() {
27
+ // A new implementation
28
+ return "Hello, TypeScript!";
29
+ }
30
+ fc(){
31
+ `;
32
+ const expectedResult = `
33
+ class Greeter {
34
+ greet() {
35
+ // A new implementation
36
+ return "Hello, TypeScript!";
37
+ }
38
+ fc(){ return 42; }
39
+
40
+ }
41
+ `;
42
+ const result = await applySnippetPatch(sourceCode, patchCode, TS_WASM_PATH);
43
+ expect(normalize(result)).toEqual(normalize(expectedResult));
44
+ });
45
+
46
+ it('should replace a data structure definition', async () => {
47
+ const sourceCode = `
48
+ interface MyData {
49
+ field1: string;
50
+ }
51
+ console.log("hello");
52
+ `;
53
+ const patchCode = `
54
+ interface MyData {
55
+ field1: number;
56
+ field2: boolean;
57
+ }
58
+ `;
59
+ const expectedResult = `
60
+ interface MyData {
61
+ field1: number;
62
+ field2: boolean;
63
+ }
64
+ console.log("hello");
65
+ `;
66
+ const result = await applySnippetPatch(sourceCode, patchCode, TS_WASM_PATH);
67
+ expect(normalize(result)).toEqual(normalize(expectedResult));
68
+ });
69
+
70
+ it('should replace a full function definition', async () => {
71
+ const sourceCode = `
72
+ import fs from 'fs';
73
+
74
+ function calculate() {
75
+ return 1 + 1;
76
+ }
77
+
78
+ export { calculate };
79
+ `;
80
+ const patchCode = `
81
+ function calculate() {
82
+ // A more complex calculation
83
+ const result = 2 * 2;
84
+ return result;
85
+ }
86
+ `;
87
+ const expectedResult = `
88
+ import fs from 'fs';
89
+
90
+ function calculate() {
91
+ // A more complex calculation
92
+ const result = 2 * 2;
93
+ return result;
94
+ }
95
+
96
+ export { calculate };
97
+ `;
98
+ const result = await applySnippetPatch(sourceCode, patchCode, TS_WASM_PATH);
99
+ expect(normalize(result)).toEqual(normalize(expectedResult));
100
+ });
101
+
102
+ it('should replace a beginning of the file @begin-of-file', async () => {
103
+ const sourceCode = `
104
+ import { ModuleA } from './moduleA';
105
+ import { ModuleB } from './moduleB';
106
+
107
+ console.log('starting up');
108
+ `;
109
+ const patchCode = `
110
+ // @begin-of-file
111
+ import groupBy from 'lodash';
112
+ import { ModuleA } from './moduleA';
113
+ `;
114
+ const expectedResult = `
115
+ import groupBy from 'lodash';
116
+ import { ModuleA } from './moduleA';
117
+ import { ModuleB } from './moduleB';
118
+
119
+ console.log('starting up');
120
+ `;
121
+ const result = await applySnippetPatch(sourceCode, patchCode, TS_WASM_PATH);
122
+ expect(normalize(result)).toEqual(normalize(expectedResult));
123
+ });
124
+
125
+ it('should handle @begin-of-file marker with variations', async () => {
126
+ const sourceCode = `
127
+ import { ModuleA } from './moduleA';
128
+ import { ModuleB } from './moduleB';
129
+
130
+ console.log('starting up');
131
+ `;
132
+ const patchCode = `
133
+ //@begin-of-file extra text
134
+ import groupBy from 'lodash';
135
+ import { ModuleA } from './moduleA';
136
+ `;
137
+ const expectedResult = `
138
+ import groupBy from 'lodash';
139
+ import { ModuleA } from './moduleA';
140
+ import { ModuleB } from './moduleB';
141
+
142
+ console.log('starting up');
143
+ `;
144
+ const result = await applySnippetPatch(sourceCode, patchCode, TS_WASM_PATH);
145
+ expect(normalize(result)).toEqual(normalize(expectedResult));
146
+ });
147
+
148
+ it('should replace a end of the file @end-of-file', async () => {
149
+ const sourceCode = `
150
+ import fs from 'fs';
151
+
152
+ function calculate() {
153
+ return 1 + 1;
154
+ }
155
+
156
+ export { calculate };
157
+ `;
158
+ const patchCode = `
159
+ export { calculate };
160
+ export { sum };
161
+ // @end-of-file
162
+ `;
163
+ const expectedResult = `
164
+ import fs from 'fs';
165
+
166
+ function calculate() {
167
+ return 1 + 1;
168
+ }
169
+
170
+ export { calculate };
171
+ export { sum };
172
+ `;
173
+ const result = await applySnippetPatch(sourceCode, patchCode, TS_WASM_PATH);
174
+ expect(normalize(result)).toEqual(normalize(expectedResult));
175
+ });
176
+
177
+ it('should handle @end-of-file marker with variations', async () => {
178
+ const sourceCode = `
179
+ import fs from 'fs';
180
+
181
+ function calculate() {
182
+ return 1 + 1;
183
+ }
184
+
185
+ export { calculate };
186
+ `;
187
+ const patchCode = `
188
+ export { calculate };
189
+ export { sum };
190
+ //@end-of-file some extra text
191
+ `;
192
+ const expectedResult = `
193
+ import fs from 'fs';
194
+
195
+ function calculate() {
196
+ return 1 + 1;
197
+ }
198
+
199
+ export { calculate };
200
+ export { sum };
201
+ `;
202
+ const result = await applySnippetPatch(sourceCode, patchCode, TS_WASM_PATH);
203
+ expect(normalize(result)).toEqual(normalize(expectedResult));
204
+ });
205
+ it('should succeed with dynamic anchor sizing when initial anchors are ambiguous', async () => {
206
+ const sourceCode = `
207
+ const config = {
208
+ port: 8080,
209
+ host: 'localhost',
210
+ };
211
+
212
+ function connect() {
213
+ // uses config
214
+ }
215
+
216
+ const config2 = {
217
+ port: 3000,
218
+ host: 'remote',
219
+ };
220
+ `;
221
+ const patchCode = `
222
+ const config = {
223
+ port: 9000,
224
+ host: 'localhost',
225
+ protocol: 'https'
226
+ };
227
+
228
+ function connect() {
229
+ `;
230
+ const expectedResult = `
231
+ const config = {
232
+ port: 9000,
233
+ host: 'localhost',
234
+ protocol: 'https'
235
+ };
236
+
237
+ function connect() {
238
+ // uses config
239
+ }
240
+
241
+ const config2 = {
242
+ port: 3000,
243
+ host: 'remote',
244
+ };
245
+ `;
246
+ const result = await applySnippetPatch(sourceCode, patchCode, TS_WASM_PATH);
247
+ expect(normalize(result)).toEqual(normalize(expectedResult));
248
+ });
249
+
250
+ it('should handle partial type definitions by trimming ambiguous tokens', async () => {
251
+ const sourceCode = `
252
+ /**
253
+ * Bill date of the vendor bill
254
+ */
255
+ billDate: everest_appserver_primitive_PlainDate;
256
+ billNumber: everest_appserver_primitive_Text;
257
+ businessPartnerId: everest_appserver_primitive_ID;
258
+ /**
259
+ * Conditionally return status or paymentStatus
260
+ */
261
+ combinedStatus?: everest_appserver_primitive_Text | null;
262
+ /**
263
+ * Contains Billable Expense line
264
+ */
265
+ containsBillableItem?: everest_appserver_primitive_TrueFalse | null;
266
+ /**
267
+ * Denotes whether bill type is prepaid or not
268
+ */
269
+ containsPrepaidItem?: everest_appserver_primitive_TrueFalse | null;
270
+ `;
271
+ const patchCode = `
272
+ businessPartnerId: everest_appserver_primitive_ID;
273
+ /**
274
+ * Conditionally return status or paymentStatus
275
+ */
276
+ combinedStatusNew2?: everest_appserver_primitive_Text | null;
277
+ /**
278
+ `;
279
+ const expectedResult = `
280
+ /**
281
+ * Bill date of the vendor bill
282
+ */
283
+ billDate: everest_appserver_primitive_PlainDate;
284
+ billNumber: everest_appserver_primitive_Text;
285
+ businessPartnerId: everest_appserver_primitive_ID;
286
+ /**
287
+ * Conditionally return status or paymentStatus
288
+ */
289
+ combinedStatusNew2?: everest_appserver_primitive_Text | null;
290
+ /**
291
+ * Contains Billable Expense line
292
+ */
293
+ containsBillableItem?: everest_appserver_primitive_TrueFalse | null;
294
+ /**
295
+ * Denotes whether bill type is prepaid or not
296
+ */
297
+ containsPrepaidItem?: everest_appserver_primitive_TrueFalse | null;
298
+ `;
299
+ const result = await applySnippetPatch(sourceCode, patchCode, TS_WASM_PATH);
300
+ expect(normalize(result)).toEqual(normalize(expectedResult));
301
+ });
302
+
303
+ it('should patch TSX correctly by trimming tokens from invalid partial snippets', async () => {
304
+ const sourceCode = `
305
+ import { useEffect, useMemo } from "react"
306
+ import { trpc } from "@/lib/trpc"
307
+
308
+ import { Button } from "@/components/ui/button"
309
+ import { DataTable } from "@/components/ui/data-table"
310
+ import { useReconciliationStore } from "@/store/reconciliation"
311
+
312
+ import {
313
+ getBillColumns,
314
+ getInvoiceColumns,
315
+ getMatchedColumns,
316
+ getTransactionColumns,
317
+ } from "./transactions-columns"
318
+
319
+ export function TransactionsPage() {
320
+ const {
321
+ transactions,
322
+ invoices,
323
+ matchedItems,
324
+ selectedTransactionId,
325
+ selectedMatchableId,
326
+ loadInitialData,
327
+ selectTransaction,
328
+ selectMatchable,
329
+ matchItems,
330
+ unmatchItems,
331
+ } = useReconciliationStore()
332
+ const { data: bills = [] } = trpc.bills.getBills.useQuery()
333
+
334
+ // Load mock data when component mounts
335
+ useEffect(() => {
336
+ loadInitialData()
337
+ }, [loadInitialData])
338
+
339
+ const selectedTransaction =
340
+ transactions.find((t) => t.id === selectedTransactionId) || null
341
+
342
+ const transactionColumns = useMemo(() => getTransactionColumns(), [])
343
+
344
+ const invoiceColumns = useMemo(() => getInvoiceColumns(), [])
345
+
346
+ const billColumns = useMemo(() => getBillColumns(), [])
347
+
348
+ const matchedColumns = useMemo(
349
+ () =>
350
+ getMatchedColumns({
351
+ onUnmatch: unmatchItems,
352
+ }),
353
+ [unmatchItems]
354
+ )
355
+
356
+ const canMatch = selectedTransactionId && selectedMatchableId
357
+
358
+ return (
359
+ <div>
360
+ <div className="flex justify-between items-center mb-4">
361
+ <h2 className="text-2xl font-bold">Transaction Matching</h2>
362
+ <Button onClick={matchItems} disabled={!canMatch}>
363
+ Match Items
364
+ </Button>
365
+ </div>
366
+
367
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
368
+ {/* Left Panel: Bank Transactions */}
369
+ <div>
370
+ <h3 className="text-lg font-semibold mb-2">Bank Transactions</h3>
371
+ <p className="text-sm text-muted-foreground mb-4">
372
+ Select a transaction to begin matching.
373
+ </p>
374
+ <DataTable
375
+ columns={transactionColumns}
376
+ data={transactions}
377
+ onRowClick={(row) => selectTransaction(row.id)}
378
+ selectedId={selectedTransactionId}
379
+ />
380
+ </div>
381
+
382
+ {/* Right Panel: Matching Items */}
383
+ <div>
384
+ <h3 className="text-lg font-semibold mb-2">Potential Matches</h3>
385
+ {!selectedTransaction ? (
386
+ <div className="h-full flex items-center justify-center rounded-lg border-2 border-dashed border-muted-foreground/30 p-8">
387
+ <p className="text-muted-foreground">
388
+ Select a transaction to see potential matches.
389
+ </p>
390
+ </div>
391
+ ) : selectedTransaction.amount > 0 ? (
392
+ <div>
393
+ <h4 className="text-md font-semibold mb-2 text-muted-foreground">
394
+ Unpaid Invoices
395
+ </h4>
396
+ <DataTable
397
+ columns={invoiceColumns}
398
+ data={invoices}
399
+ onRowClick={(row) => selectMatchable(row.id)}
400
+ selectedId={selectedMatchableId}
401
+ />
402
+ </div>
403
+ ) : (
404
+ <div>
405
+ <h4 className="text-md font-semibold mb-2 text-muted-foreground">
406
+ Unpaid Bills
407
+ </h4>
408
+ <DataTable
409
+ columns={billColumns}
410
+ data={bills}
411
+ onRowClick={(row) => selectMatchable(row.id)}
412
+ selectedId={selectedMatchableId}
413
+ />
414
+ </div>
415
+ )}
416
+ </div>
417
+ </div>
418
+
419
+ {matchedItems.length > 0 && (
420
+ <div className="mt-12">
421
+ <h3 className="text-lg font-semibold mb-2">Matched Transactions</h3>
422
+ <DataTable columns={matchedColumns} data={matchedItems} />
423
+ </div>
424
+ )}
425
+ </div>
426
+ )
427
+ }
428
+ `;
429
+ const patchCode = `
430
+ Unpaid Bills
431
+ </h4>
432
+ <DataTable
433
+ columns={billColumns}
434
+ data={bills}
435
+ onRowClick={(row) => {
436
+ console.log(\`[UI] Selected matchable bill ID\`)
437
+ selectMatchable(row.id)
438
+ }}
439
+ selectedId={selectedMatchableId}
440
+ />
441
+ </div>
442
+ )}
443
+ `;
444
+ const expectedResult = `
445
+ import { useEffect, useMemo } from "react"
446
+ import { trpc } from "@/lib/trpc"
447
+
448
+ import { Button } from "@/components/ui/button"
449
+ import { DataTable } from "@/components/ui/data-table"
450
+ import { useReconciliationStore } from "@/store/reconciliation"
451
+
452
+ import {
453
+ getBillColumns,
454
+ getInvoiceColumns,
455
+ getMatchedColumns,
456
+ getTransactionColumns,
457
+ } from "./transactions-columns"
458
+
459
+ export function TransactionsPage() {
460
+ const {
461
+ transactions,
462
+ invoices,
463
+ matchedItems,
464
+ selectedTransactionId,
465
+ selectedMatchableId,
466
+ loadInitialData,
467
+ selectTransaction,
468
+ selectMatchable,
469
+ matchItems,
470
+ unmatchItems,
471
+ } = useReconciliationStore()
472
+ const { data: bills = [] } = trpc.bills.getBills.useQuery()
473
+
474
+ // Load mock data when component mounts
475
+ useEffect(() => {
476
+ loadInitialData()
477
+ }, [loadInitialData])
478
+
479
+ const selectedTransaction =
480
+ transactions.find((t) => t.id === selectedTransactionId) || null
481
+
482
+ const transactionColumns = useMemo(() => getTransactionColumns(), [])
483
+
484
+ const invoiceColumns = useMemo(() => getInvoiceColumns(), [])
485
+
486
+ const billColumns = useMemo(() => getBillColumns(), [])
487
+
488
+ const matchedColumns = useMemo(
489
+ () =>
490
+ getMatchedColumns({
491
+ onUnmatch: unmatchItems,
492
+ }),
493
+ [unmatchItems]
494
+ )
495
+
496
+ const canMatch = selectedTransactionId && selectedMatchableId
497
+
498
+ return (
499
+ <div>
500
+ <div className="flex justify-between items-center mb-4">
501
+ <h2 className="text-2xl font-bold">Transaction Matching</h2>
502
+ <Button onClick={matchItems} disabled={!canMatch}>
503
+ Match Items
504
+ </Button>
505
+ </div>
506
+
507
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
508
+ {/* Left Panel: Bank Transactions */}
509
+ <div>
510
+ <h3 className="text-lg font-semibold mb-2">Bank Transactions</h3>
511
+ <p className="text-sm text-muted-foreground mb-4">
512
+ Select a transaction to begin matching.
513
+ </p>
514
+ <DataTable
515
+ columns={transactionColumns}
516
+ data={transactions}
517
+ onRowClick={(row) => selectTransaction(row.id)}
518
+ selectedId={selectedTransactionId}
519
+ />
520
+ </div>
521
+
522
+ {/* Right Panel: Matching Items */}
523
+ <div>
524
+ <h3 className="text-lg font-semibold mb-2">Potential Matches</h3>
525
+ {!selectedTransaction ? (
526
+ <div className="h-full flex items-center justify-center rounded-lg border-2 border-dashed border-muted-foreground/30 p-8">
527
+ <p className="text-muted-foreground">
528
+ Select a transaction to see potential matches.
529
+ </p>
530
+ </div>
531
+ ) : selectedTransaction.amount > 0 ? (
532
+ <div>
533
+ <h4 className="text-md font-semibold mb-2 text-muted-foreground">
534
+ Unpaid Invoices
535
+ </h4>
536
+ <DataTable
537
+ columns={invoiceColumns}
538
+ data={invoices}
539
+ onRowClick={(row) => selectMatchable(row.id)}
540
+ selectedId={selectedMatchableId}
541
+ />
542
+ </div>
543
+ ) : (
544
+ <div>
545
+ <h4 className="text-md font-semibold mb-2 text-muted-foreground">
546
+ Unpaid Bills
547
+ </h4>
548
+ <DataTable
549
+ columns={billColumns}
550
+ data={bills}
551
+ onRowClick={(row) => {
552
+ console.log(\`[UI] Selected matchable bill ID\`)
553
+ selectMatchable(row.id)
554
+ }}
555
+ selectedId={selectedMatchableId}
556
+ />
557
+ </div>
558
+ )}
559
+ </div>
560
+ </div>
561
+
562
+ {matchedItems.length > 0 && (
563
+ <div className="mt-12">
564
+ <h3 className="text-lg font-semibold mb-2">Matched Transactions</h3>
565
+ <DataTable columns={matchedColumns} data={matchedItems} />
566
+ </div>
567
+ )}
568
+ </div>
569
+ )
570
+ }
571
+ `;
572
+ const result = await applySnippetPatch(
573
+ sourceCode,
574
+ patchCode,
575
+ TSX_WASM_PATH,
576
+ );
577
+ expect(normalize(result)).toEqual(normalize(expectedResult));
578
+ });
579
+ });
@@ -0,0 +1,80 @@
1
+ import { initializeParser } from './parser';
2
+ import { collectTokens } from './tokens';
3
+ import {
4
+ handleBeginOfFilePatch,
5
+ handleEndOfFilePatch,
6
+ handleStandardPatch,
7
+ } from './patcher';
8
+
9
+ export async function applySnippetPatch(
10
+ sourceCode: string,
11
+ patchCode: string,
12
+ grammarPath: string,
13
+ ): Promise<string> {
14
+ const parser = await initializeParser(grammarPath);
15
+
16
+ const sourceTree = parser.parse(sourceCode);
17
+ if (!sourceTree) {
18
+ throw new Error('Failed to parse source code.');
19
+ }
20
+ const sourceTokens = collectTokens(sourceTree, sourceCode);
21
+
22
+ let patchResult: {
23
+ replaceStart: number;
24
+ replaceEnd: number;
25
+ patchInsertStart: number;
26
+ patchInsertEnd: number;
27
+ };
28
+ let processedPatchCode = patchCode;
29
+
30
+ const beginOfFileRegex = /\/\/\s*@begin-of-file.*/;
31
+ const endOfFileRegex = /\/\/\s*@end-of-file.*/;
32
+
33
+ const hasBeginOfFile = beginOfFileRegex.test(patchCode);
34
+ const hasEndOfFile = endOfFileRegex.test(patchCode);
35
+
36
+ if (hasBeginOfFile) {
37
+ processedPatchCode = patchCode.replace(beginOfFileRegex, '');
38
+ const patchTree = parser.parse(processedPatchCode);
39
+ if (!patchTree) {
40
+ throw new Error('Failed to parse patch code.');
41
+ }
42
+ const patchTokens = collectTokens(patchTree, processedPatchCode).filter(
43
+ (t) => t.text !== '',
44
+ );
45
+ patchResult = handleBeginOfFilePatch(sourceTokens, patchTokens);
46
+ } else if (hasEndOfFile) {
47
+ processedPatchCode = patchCode.replace(endOfFileRegex, '');
48
+ const patchTree = parser.parse(processedPatchCode);
49
+ if (!patchTree) {
50
+ throw new Error('Failed to parse patch code.');
51
+ }
52
+ const patchTokens = collectTokens(patchTree, processedPatchCode).filter(
53
+ (t) => t.text !== '',
54
+ );
55
+ patchResult = handleEndOfFilePatch(sourceTokens, patchTokens, sourceCode);
56
+ } else {
57
+ processedPatchCode = patchCode.trim();
58
+ const patchTree = parser.parse(processedPatchCode);
59
+ if (!patchTree) {
60
+ throw new Error('Failed to parse patch code.');
61
+ }
62
+ const patchTokens = collectTokens(patchTree, processedPatchCode).filter(
63
+ (t) => t.text !== '',
64
+ );
65
+ patchResult = handleStandardPatch(sourceTokens, patchTokens);
66
+ }
67
+
68
+ // NOTE: replaceStart/End are byte offsets.
69
+ // If your code can contain non-ASCII characters, you need to
70
+ // map byte offsets to JS string indices. For pure ASCII, this
71
+ // works as-is.
72
+ const prefix = sourceCode.slice(0, patchResult.replaceStart);
73
+ const suffix = sourceCode.slice(patchResult.replaceEnd);
74
+ const finalPatchContent = processedPatchCode.slice(
75
+ patchResult.patchInsertStart,
76
+ patchResult.patchInsertEnd,
77
+ );
78
+
79
+ return prefix + finalPatchContent + suffix;
80
+ }
@@ -0,0 +1,18 @@
1
+ // import Parser from 'web-tree-sitter';
2
+
3
+ // Cache parsers by grammar path to avoid re-initialization.
4
+ import { Language, Parser } from 'web-tree-sitter';
5
+
6
+ const parsers = new Map<string, Parser>();
7
+
8
+ export async function initializeParser(grammarPath: string): Promise<Parser> {
9
+ if (parsers.has(grammarPath)) {
10
+ return parsers.get(grammarPath)!;
11
+ }
12
+ await Parser.init();
13
+ const newParser = new Parser();
14
+ const language = await Language.load(grammarPath);
15
+ newParser.setLanguage(language);
16
+ parsers.set(grammarPath, newParser);
17
+ return newParser;
18
+ }