repoburg 1.3.9 → 1.3.11

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 (300) 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/action-handler.interface.d.ts +1 -0
  31. package/backend/dist/src/llm-orchestration/action-handlers/apply-diff.handler.d.ts +1 -0
  32. package/backend/dist/src/llm-orchestration/action-handlers/apply-diff.handler.js +35 -0
  33. package/backend/dist/src/llm-orchestration/action-handlers/apply-diff.handler.js.map +1 -1
  34. package/backend/dist/src/llm-orchestration/action-handlers/create-file.handler.d.ts +1 -0
  35. package/backend/dist/src/llm-orchestration/action-handlers/create-file.handler.js +48 -0
  36. package/backend/dist/src/llm-orchestration/action-handlers/create-file.handler.js.map +1 -1
  37. package/backend/dist/src/llm-orchestration/action-handlers/delete-file.handler.d.ts +1 -0
  38. package/backend/dist/src/llm-orchestration/action-handlers/delete-file.handler.js +21 -0
  39. package/backend/dist/src/llm-orchestration/action-handlers/delete-file.handler.js.map +1 -1
  40. package/backend/dist/src/llm-orchestration/action-handlers/dto/howto.args.dto.d.ts +2 -0
  41. package/backend/dist/src/llm-orchestration/action-handlers/dto/howto.args.dto.js +7 -0
  42. package/backend/dist/src/llm-orchestration/action-handlers/dto/howto.args.dto.js.map +1 -0
  43. package/backend/dist/src/llm-orchestration/action-handlers/dto/patch.args.dto.d.ts +4 -0
  44. package/backend/dist/src/llm-orchestration/action-handlers/dto/patch.args.dto.js +29 -0
  45. package/backend/dist/src/llm-orchestration/action-handlers/dto/patch.args.dto.js.map +1 -0
  46. package/backend/dist/src/llm-orchestration/action-handlers/edit-file.handler.d.ts +1 -0
  47. package/backend/dist/src/llm-orchestration/action-handlers/edit-file.handler.js +55 -0
  48. package/backend/dist/src/llm-orchestration/action-handlers/edit-file.handler.js.map +1 -1
  49. package/backend/dist/src/llm-orchestration/action-handlers/final.handler.d.ts +1 -0
  50. package/backend/dist/src/llm-orchestration/action-handlers/final.handler.js +20 -0
  51. package/backend/dist/src/llm-orchestration/action-handlers/final.handler.js.map +1 -1
  52. package/backend/dist/src/llm-orchestration/action-handlers/howto.handler.d.ts +9 -0
  53. package/backend/dist/src/llm-orchestration/action-handlers/howto.handler.js +85 -0
  54. package/backend/dist/src/llm-orchestration/action-handlers/howto.handler.js.map +1 -0
  55. package/backend/dist/src/llm-orchestration/action-handlers/new-session.handler.d.ts +1 -0
  56. package/backend/dist/src/llm-orchestration/action-handlers/new-session.handler.js +21 -0
  57. package/backend/dist/src/llm-orchestration/action-handlers/new-session.handler.js.map +1 -1
  58. package/backend/dist/src/llm-orchestration/action-handlers/patch.handler.d.ts +13 -0
  59. package/backend/dist/src/llm-orchestration/action-handlers/patch.handler.js +247 -0
  60. package/backend/dist/src/llm-orchestration/action-handlers/patch.handler.js.map +1 -0
  61. package/backend/dist/src/llm-orchestration/action-handlers/quick-edit.handler.d.ts +1 -0
  62. package/backend/dist/src/llm-orchestration/action-handlers/quick-edit.handler.js +53 -0
  63. package/backend/dist/src/llm-orchestration/action-handlers/quick-edit.handler.js.map +1 -1
  64. package/backend/dist/src/llm-orchestration/action-handlers/request-context.handler.d.ts +1 -0
  65. package/backend/dist/src/llm-orchestration/action-handlers/request-context.handler.js +30 -0
  66. package/backend/dist/src/llm-orchestration/action-handlers/request-context.handler.js.map +1 -1
  67. package/backend/dist/src/llm-orchestration/action-handlers/run-command.handler.d.ts +1 -0
  68. package/backend/dist/src/llm-orchestration/action-handlers/run-command.handler.js +45 -0
  69. package/backend/dist/src/llm-orchestration/action-handlers/run-command.handler.js.map +1 -1
  70. package/backend/dist/src/llm-orchestration/action-handlers/use-mcp-tool.handler.d.ts +1 -0
  71. package/backend/dist/src/llm-orchestration/action-handlers/use-mcp-tool.handler.js +29 -0
  72. package/backend/dist/src/llm-orchestration/action-handlers/use-mcp-tool.handler.js.map +1 -1
  73. package/backend/dist/src/llm-orchestration/llm-orchestration.module.js +6 -2
  74. package/backend/dist/src/llm-orchestration/llm-orchestration.module.js.map +1 -1
  75. package/backend/dist/src/llm-orchestration/llm-turn-processor.service.js +1 -0
  76. package/backend/dist/src/llm-orchestration/llm-turn-processor.service.js.map +1 -1
  77. package/backend/dist/src/seeding/data/custom-snippets/eta-for.d.ts +4 -0
  78. package/backend/dist/src/seeding/data/custom-snippets/eta-for.js +8 -0
  79. package/backend/dist/src/seeding/data/custom-snippets/eta-for.js.map +1 -0
  80. package/backend/dist/src/seeding/data/custom-snippets/eta-if.d.ts +4 -0
  81. package/backend/dist/src/seeding/data/custom-snippets/eta-if.js +8 -0
  82. package/backend/dist/src/seeding/data/custom-snippets/eta-if.js.map +1 -0
  83. package/backend/dist/src/seeding/data/custom-snippets/eta-ifelse.d.ts +4 -0
  84. package/backend/dist/src/seeding/data/custom-snippets/eta-ifelse.js +8 -0
  85. package/backend/dist/src/seeding/data/custom-snippets/eta-ifelse.js.map +1 -0
  86. package/backend/dist/src/seeding/data/custom-snippets/it-mcp.d.ts +4 -0
  87. package/backend/dist/src/seeding/data/custom-snippets/it-mcp.js +8 -0
  88. package/backend/dist/src/seeding/data/custom-snippets/it-mcp.js.map +1 -0
  89. package/backend/dist/src/seeding/data/custom-snippets/it-tools.d.ts +4 -0
  90. package/backend/dist/src/seeding/data/custom-snippets/it-tools.js +8 -0
  91. package/backend/dist/src/seeding/data/custom-snippets/it-tools.js.map +1 -0
  92. package/backend/dist/src/seeding/data/system-prompts/default_master-agent.d.ts +1 -1
  93. package/backend/dist/src/seeding/data/system-prompts/default_master-agent.js +1 -1
  94. package/backend/dist/src/seeding/data/system-prompts/experimental_eta_master-agent.d.ts +2 -0
  95. package/backend/dist/src/seeding/data/system-prompts/experimental_eta_master-agent.js +62 -0
  96. package/backend/dist/src/seeding/data/system-prompts/experimental_eta_master-agent.js.map +1 -0
  97. package/backend/dist/src/seeding/data/system-prompts/experimental_patch_master-agent.d.ts +2 -0
  98. package/backend/dist/src/seeding/data/system-prompts/experimental_patch_master-agent.js +463 -0
  99. package/backend/dist/src/seeding/data/system-prompts/experimental_patch_master-agent.js.map +1 -0
  100. package/backend/dist/src/system-prompts/dto/system-prompt.dto.d.ts +6 -0
  101. package/backend/dist/src/system-prompts/dto/system-prompt.dto.js +12 -1
  102. package/backend/dist/src/system-prompts/dto/system-prompt.dto.js.map +1 -1
  103. package/backend/dist/src/system-prompts/system-prompts.controller.d.ts +3 -1
  104. package/backend/dist/src/system-prompts/system-prompts.controller.js +20 -0
  105. package/backend/dist/src/system-prompts/system-prompts.controller.js.map +1 -1
  106. package/backend/dist/src/system-prompts/system-prompts.module.js +11 -1
  107. package/backend/dist/src/system-prompts/system-prompts.module.js.map +1 -1
  108. package/backend/dist/src/system-prompts/system-prompts.service.d.ts +11 -3
  109. package/backend/dist/src/system-prompts/system-prompts.service.js +39 -12
  110. package/backend/dist/src/system-prompts/system-prompts.service.js.map +1 -1
  111. package/backend/dist/src/utils/ai-format-generator.d.ts +1 -0
  112. package/backend/dist/src/utils/ai-format-generator.js +23 -0
  113. package/backend/dist/src/utils/ai-format-generator.js.map +1 -0
  114. package/backend/dist/src/utils/index.d.ts +1 -0
  115. package/backend/dist/src/utils/index.js +1 -0
  116. package/backend/dist/src/utils/index.js.map +1 -1
  117. package/backend/dist/tsconfig.build.tsbuildinfo +1 -1
  118. package/backend/package.json +6 -3
  119. package/backend/packages/tokenpatch/grammar/tree-sitter-tsx.wasm +0 -0
  120. package/backend/packages/tokenpatch/grammar/tree-sitter-typescript.wasm +0 -0
  121. package/backend/packages/tokenpatch/index.spec.ts +579 -0
  122. package/backend/packages/tokenpatch/index.ts +80 -0
  123. package/backend/packages/tokenpatch/parser.ts +18 -0
  124. package/backend/packages/tokenpatch/patcher.spec.ts +194 -0
  125. package/backend/packages/tokenpatch/patcher.ts +300 -0
  126. package/backend/packages/tokenpatch/tokens.spec.ts +84 -0
  127. package/backend/packages/tokenpatch/tokens.ts +50 -0
  128. package/backend/packages/tokenpatch/types.ts +9 -0
  129. package/package.json +13 -12
  130. package/backend/coverage/clover.xml +0 -3434
  131. package/backend/coverage/coverage-final.json +0 -120
  132. package/backend/coverage/lcov-report/base.css +0 -224
  133. package/backend/coverage/lcov-report/block-navigation.js +0 -87
  134. package/backend/coverage/lcov-report/favicon.png +0 -0
  135. package/backend/coverage/lcov-report/index.html +0 -701
  136. package/backend/coverage/lcov-report/prettify.css +0 -1
  137. package/backend/coverage/lcov-report/prettify.js +0 -2
  138. package/backend/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  139. package/backend/coverage/lcov-report/sorter.js +0 -196
  140. package/backend/coverage/lcov-report/src/action-execution/action-execution.module.ts.html +0 -109
  141. package/backend/coverage/lcov-report/src/action-execution/action-execution.service.ts.html +0 -448
  142. package/backend/coverage/lcov-report/src/action-execution/index.html +0 -131
  143. package/backend/coverage/lcov-report/src/ai-actions/ai-action-batch.service.ts.html +0 -940
  144. package/backend/coverage/lcov-report/src/ai-actions/ai-action-creation.service.ts.html +0 -1243
  145. package/backend/coverage/lcov-report/src/ai-actions/ai-actions.controller.ts.html +0 -664
  146. package/backend/coverage/lcov-report/src/ai-actions/ai-actions.module.ts.html +0 -154
  147. package/backend/coverage/lcov-report/src/ai-actions/ai-actions.service.ts.html +0 -859
  148. package/backend/coverage/lcov-report/src/ai-actions/index.html +0 -176
  149. package/backend/coverage/lcov-report/src/app.controller.ts.html +0 -151
  150. package/backend/coverage/lcov-report/src/app.module.ts.html +0 -373
  151. package/backend/coverage/lcov-report/src/app.service.ts.html +0 -196
  152. package/backend/coverage/lcov-report/src/application-state/application-state.controller.ts.html +0 -319
  153. package/backend/coverage/lcov-report/src/application-state/application-state.module.ts.html +0 -124
  154. package/backend/coverage/lcov-report/src/application-state/application-state.service.ts.html +0 -439
  155. package/backend/coverage/lcov-report/src/application-state/dto/index.html +0 -161
  156. package/backend/coverage/lcov-report/src/application-state/dto/set-auto-context-fetch-enabled.dto.ts.html +0 -103
  157. package/backend/coverage/lcov-report/src/application-state/dto/set-orchestration-timeout.dto.ts.html +0 -103
  158. package/backend/coverage/lcov-report/src/application-state/dto/set-theme.dto.ts.html +0 -106
  159. package/backend/coverage/lcov-report/src/application-state/dto/set-websocket-enabled.dto.ts.html +0 -103
  160. package/backend/coverage/lcov-report/src/application-state/index.html +0 -146
  161. package/backend/coverage/lcov-report/src/context-generation/context-generation.module.ts.html +0 -118
  162. package/backend/coverage/lcov-report/src/context-generation/context-generation.service.ts.html +0 -1348
  163. package/backend/coverage/lcov-report/src/context-generation/index.html +0 -131
  164. package/backend/coverage/lcov-report/src/context-snippets/context-snippets.controller.ts.html +0 -289
  165. package/backend/coverage/lcov-report/src/context-snippets/context-snippets.module.ts.html +0 -136
  166. package/backend/coverage/lcov-report/src/context-snippets/context-snippets.service.ts.html +0 -400
  167. package/backend/coverage/lcov-report/src/context-snippets/dto/context-snippet.dto.ts.html +0 -211
  168. package/backend/coverage/lcov-report/src/context-snippets/dto/index.html +0 -116
  169. package/backend/coverage/lcov-report/src/context-snippets/index.html +0 -146
  170. package/backend/coverage/lcov-report/src/context-templates/context-templates.controller.ts.html +0 -397
  171. package/backend/coverage/lcov-report/src/context-templates/context-templates.module.ts.html +0 -136
  172. package/backend/coverage/lcov-report/src/context-templates/context-templates.service.ts.html +0 -835
  173. package/backend/coverage/lcov-report/src/context-templates/dto/context-template.dto.ts.html +0 -358
  174. package/backend/coverage/lcov-report/src/context-templates/dto/index.html +0 -116
  175. package/backend/coverage/lcov-report/src/context-templates/index.html +0 -146
  176. package/backend/coverage/lcov-report/src/core-entities/ai-action.entity.ts.html +0 -241
  177. package/backend/coverage/lcov-report/src/core-entities/application-state.entity.ts.html +0 -115
  178. package/backend/coverage/lcov-report/src/core-entities/base.entity.ts.html +0 -145
  179. package/backend/coverage/lcov-report/src/core-entities/context-snippet.entity.ts.html +0 -130
  180. package/backend/coverage/lcov-report/src/core-entities/context-template.entity.ts.html +0 -223
  181. package/backend/coverage/lcov-report/src/core-entities/custom-snippet.entity.ts.html +0 -136
  182. package/backend/coverage/lcov-report/src/core-entities/execution-log.entity.ts.html +0 -157
  183. package/backend/coverage/lcov-report/src/core-entities/index.html +0 -281
  184. package/backend/coverage/lcov-report/src/core-entities/index.ts.html +0 -118
  185. package/backend/coverage/lcov-report/src/core-entities/project.entity.ts.html +0 -130
  186. package/backend/coverage/lcov-report/src/core-entities/session-input.entity.ts.html +0 -289
  187. package/backend/coverage/lcov-report/src/core-entities/session.entity.ts.html +0 -280
  188. package/backend/coverage/lcov-report/src/core-entities/system-prompt.entity.ts.html +0 -148
  189. package/backend/coverage/lcov-report/src/custom-snippets/custom-snippets.controller.ts.html +0 -277
  190. package/backend/coverage/lcov-report/src/custom-snippets/custom-snippets.module.ts.html +0 -124
  191. package/backend/coverage/lcov-report/src/custom-snippets/custom-snippets.service.ts.html +0 -304
  192. package/backend/coverage/lcov-report/src/custom-snippets/dto/custom-snippet.dto.ts.html +0 -205
  193. package/backend/coverage/lcov-report/src/custom-snippets/dto/index.html +0 -116
  194. package/backend/coverage/lcov-report/src/custom-snippets/index.html +0 -146
  195. package/backend/coverage/lcov-report/src/events/events.gateway.ts.html +0 -292
  196. package/backend/coverage/lcov-report/src/events/events.module.ts.html +0 -109
  197. package/backend/coverage/lcov-report/src/events/index.html +0 -131
  198. package/backend/coverage/lcov-report/src/execution-logs/dto/execution-log.dto.ts.html +0 -130
  199. package/backend/coverage/lcov-report/src/execution-logs/dto/index.html +0 -116
  200. package/backend/coverage/lcov-report/src/execution-logs/execution-logs.controller.ts.html +0 -130
  201. package/backend/coverage/lcov-report/src/execution-logs/execution-logs.module.ts.html +0 -124
  202. package/backend/coverage/lcov-report/src/execution-logs/execution-logs.service.ts.html +0 -238
  203. package/backend/coverage/lcov-report/src/execution-logs/index.html +0 -146
  204. package/backend/coverage/lcov-report/src/http-exception.filter.ts.html +0 -340
  205. package/backend/coverage/lcov-report/src/index.html +0 -191
  206. package/backend/coverage/lcov-report/src/llm-response-parser/dto/ai-action.dto.ts.html +0 -400
  207. package/backend/coverage/lcov-report/src/llm-response-parser/dto/index.html +0 -116
  208. package/backend/coverage/lcov-report/src/llm-response-parser/errors/index.html +0 -116
  209. package/backend/coverage/lcov-report/src/llm-response-parser/errors/parsing.error.ts.html +0 -118
  210. package/backend/coverage/lcov-report/src/llm-response-parser/index.html +0 -146
  211. package/backend/coverage/lcov-report/src/llm-response-parser/llm-response-parser.module.ts.html +0 -109
  212. package/backend/coverage/lcov-report/src/llm-response-parser/llm-response-parser.service.ts.html +0 -808
  213. package/backend/coverage/lcov-report/src/llm-response-parser/parsing.constants.ts.html +0 -139
  214. package/backend/coverage/lcov-report/src/llm-responses/dto/index.html +0 -116
  215. package/backend/coverage/lcov-report/src/llm-responses/dto/submit-llm-response.dto.ts.html +0 -172
  216. package/backend/coverage/lcov-report/src/llm-responses/index.html +0 -146
  217. package/backend/coverage/lcov-report/src/llm-responses/llm-responses.controller.ts.html +0 -154
  218. package/backend/coverage/lcov-report/src/llm-responses/llm-responses.module.ts.html +0 -166
  219. package/backend/coverage/lcov-report/src/llm-responses/llm-responses.service.ts.html +0 -787
  220. package/backend/coverage/lcov-report/src/main.ts.html +0 -382
  221. package/backend/coverage/lcov-report/src/orchestration/dto/index.html +0 -116
  222. package/backend/coverage/lcov-report/src/orchestration/dto/orchestration.dto.ts.html +0 -169
  223. package/backend/coverage/lcov-report/src/orchestration/index.html +0 -191
  224. package/backend/coverage/lcov-report/src/orchestration/orchestration-fs.service.ts.html +0 -595
  225. package/backend/coverage/lcov-report/src/orchestration/orchestration-parser.service.ts.html +0 -142
  226. package/backend/coverage/lcov-report/src/orchestration/orchestration.controller.ts.html +0 -406
  227. package/backend/coverage/lcov-report/src/orchestration/orchestration.module.ts.html +0 -169
  228. package/backend/coverage/lcov-report/src/orchestration/orchestration.service.ts.html +0 -1093
  229. package/backend/coverage/lcov-report/src/orchestration/orchestration.types.ts.html +0 -175
  230. package/backend/coverage/lcov-report/src/projects/dto/index.html +0 -116
  231. package/backend/coverage/lcov-report/src/projects/dto/project.dto.ts.html +0 -154
  232. package/backend/coverage/lcov-report/src/projects/index.html +0 -146
  233. package/backend/coverage/lcov-report/src/projects/projects.controller.ts.html +0 -232
  234. package/backend/coverage/lcov-report/src/projects/projects.module.ts.html +0 -124
  235. package/backend/coverage/lcov-report/src/projects/projects.service.ts.html +0 -223
  236. package/backend/coverage/lcov-report/src/seeding/context-template-seeding.service.ts.html +0 -355
  237. package/backend/coverage/lcov-report/src/seeding/custom-snippet-seeding.service.ts.html +0 -271
  238. package/backend/coverage/lcov-report/src/seeding/data/context-templates/default-followup_ad-hoc-focused-context.ts.html +0 -136
  239. package/backend/coverage/lcov-report/src/seeding/data/context-templates/default-initial_condensed-project-context.ts.html +0 -148
  240. package/backend/coverage/lcov-report/src/seeding/data/context-templates/default-initial_full-project-context.ts.html +0 -247
  241. package/backend/coverage/lcov-report/src/seeding/data/context-templates/index.html +0 -190
  242. package/backend/coverage/lcov-report/src/seeding/data/context-templates/pm-context.ts.html +0 -250
  243. package/backend/coverage/lcov-report/src/seeding/data/context-templates/pr-description.ts.html +0 -186
  244. package/backend/coverage/lcov-report/src/seeding/data/context-templates/sample_focused-tree.ts.html +0 -124
  245. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/default_rglob.ts.html +0 -94
  246. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/git-diff.ts.html +0 -94
  247. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/index.html +0 -236
  248. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/rg-exclude.ts.html +0 -94
  249. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/rg-search-glob.ts.html +0 -94
  250. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/rg-search.ts.html +0 -94
  251. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/run-command.ts.html +0 -94
  252. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/tree.ts.html +0 -94
  253. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/usr-adhoc-incl.ts.html +0 -100
  254. package/backend/coverage/lcov-report/src/seeding/data/custom-snippets/usr-input-incl.ts.html +0 -94
  255. package/backend/coverage/lcov-report/src/seeding/data/system-prompts/codebase-explorer.ts.html +0 -331
  256. package/backend/coverage/lcov-report/src/seeding/data/system-prompts/default_multi-file-action-generator-with-requester.ts.html +0 -675
  257. package/backend/coverage/lcov-report/src/seeding/data/system-prompts/index.html +0 -160
  258. package/backend/coverage/lcov-report/src/seeding/data/system-prompts/multi-file-action-generator.ts.html +0 -550
  259. package/backend/coverage/lcov-report/src/seeding/data/system-prompts/packup.ts.html +0 -184
  260. package/backend/coverage/lcov-report/src/seeding/data/system-prompts/refactor-split.ts.html +0 -244
  261. package/backend/coverage/lcov-report/src/seeding/index.html +0 -176
  262. package/backend/coverage/lcov-report/src/seeding/seeding.module.ts.html +0 -145
  263. package/backend/coverage/lcov-report/src/seeding/seeding.service.ts.html +0 -151
  264. package/backend/coverage/lcov-report/src/seeding/system-prompt-seeding.service.ts.html +0 -289
  265. package/backend/coverage/lcov-report/src/session-followup/index.html +0 -131
  266. package/backend/coverage/lcov-report/src/session-followup/session-followup.module.ts.html +0 -130
  267. package/backend/coverage/lcov-report/src/session-followup/session-followup.service.ts.html +0 -670
  268. package/backend/coverage/lcov-report/src/session-inputs/dto/index.html +0 -116
  269. package/backend/coverage/lcov-report/src/session-inputs/dto/session-input.dto.ts.html +0 -247
  270. package/backend/coverage/lcov-report/src/session-inputs/index.html +0 -161
  271. package/backend/coverage/lcov-report/src/session-inputs/session-input-context.service.ts.html +0 -763
  272. package/backend/coverage/lcov-report/src/session-inputs/session-inputs.controller.ts.html +0 -337
  273. package/backend/coverage/lcov-report/src/session-inputs/session-inputs.module.ts.html +0 -205
  274. package/backend/coverage/lcov-report/src/session-inputs/session-inputs.service.ts.html +0 -1621
  275. package/backend/coverage/lcov-report/src/session-transfer/index.html +0 -131
  276. package/backend/coverage/lcov-report/src/session-transfer/session-transfer.module.ts.html +0 -172
  277. package/backend/coverage/lcov-report/src/session-transfer/session-transfer.service.ts.html +0 -574
  278. package/backend/coverage/lcov-report/src/sessions/dto/index.html +0 -116
  279. package/backend/coverage/lcov-report/src/sessions/dto/session.dto.ts.html +0 -340
  280. package/backend/coverage/lcov-report/src/sessions/index.html +0 -146
  281. package/backend/coverage/lcov-report/src/sessions/sessions.controller.ts.html +0 -457
  282. package/backend/coverage/lcov-report/src/sessions/sessions.module.ts.html +0 -214
  283. package/backend/coverage/lcov-report/src/sessions/sessions.service.ts.html +0 -844
  284. package/backend/coverage/lcov-report/src/system-prompts/dto/index.html +0 -116
  285. package/backend/coverage/lcov-report/src/system-prompts/dto/system-prompt.dto.ts.html +0 -217
  286. package/backend/coverage/lcov-report/src/system-prompts/index.html +0 -146
  287. package/backend/coverage/lcov-report/src/system-prompts/system-prompts.controller.ts.html +0 -298
  288. package/backend/coverage/lcov-report/src/system-prompts/system-prompts.module.ts.html +0 -127
  289. package/backend/coverage/lcov-report/src/system-prompts/system-prompts.service.ts.html +0 -352
  290. package/backend/coverage/lcov-report/src/timeout.interceptor.ts.html +0 -178
  291. package/backend/coverage/lcov-report/src/utils/fuzzy-search.ts.html +0 -310
  292. package/backend/coverage/lcov-report/src/utils/index.html +0 -131
  293. package/backend/coverage/lcov-report/src/utils/index.ts.html +0 -88
  294. package/backend/coverage/lcov-report/src/workspace/dto/index.html +0 -116
  295. package/backend/coverage/lcov-report/src/workspace/dto/search-workspace.dto.ts.html +0 -193
  296. package/backend/coverage/lcov-report/src/workspace/index.html +0 -146
  297. package/backend/coverage/lcov-report/src/workspace/workspace.controller.ts.html +0 -247
  298. package/backend/coverage/lcov-report/src/workspace/workspace.module.ts.html +0 -121
  299. package/backend/coverage/lcov-report/src/workspace/workspace.service.ts.html +0 -745
  300. package/backend/coverage/lcov.info +0 -5590
@@ -0,0 +1,194 @@
1
+ import {
2
+ handleBeginOfFilePatch,
3
+ handleEndOfFilePatch,
4
+ handleStandardPatch,
5
+ } from './patcher';
6
+ import type { Token } from './types';
7
+
8
+ // Helper to create mock tokens for testing.
9
+ // Simplified: we only care about text, startIndex, and endIndex for these tests.
10
+ const makeTokens = (texts: string[]): Token[] => {
11
+ let offset = 0;
12
+ return texts.map((text) => {
13
+ const start = offset;
14
+ const end = start + text.length;
15
+ offset = end + 1; // Simulate space
16
+ return {
17
+ text,
18
+ type: 'test',
19
+ startIndex: start,
20
+ endIndex: end,
21
+ startPosition: { row: 0, column: start },
22
+ };
23
+ });
24
+ };
25
+
26
+ describe('patcher', () => {
27
+ describe('handleStandardPatch', () => {
28
+ it('should find a unique prefix and suffix', () => {
29
+ const sourceTokens = makeTokens(['prefix', '(', 'old', ')', 'suffix']);
30
+ const patchTokens = makeTokens(['prefix', '(', 'new', ')', 'suffix']);
31
+ const result = handleStandardPatch(sourceTokens, patchTokens);
32
+ expect(result).toEqual({
33
+ patchInsertEnd: 21,
34
+ patchInsertStart: 0,
35
+ replaceStart: 0, // 'prefix' startIndex
36
+ replaceEnd: 21, // 'suffix' endIndex
37
+ });
38
+ });
39
+
40
+ it('should trim non-matching tokens from both ends to find a match', () => {
41
+ const sourceTokens = makeTokens(['prefix', 'content', 'suffix']);
42
+ // The patch has extra tokens at the start and end that aren't in the source.
43
+ const patchTokens = makeTokens([
44
+ 'bad', // 0-3
45
+ 'prefix', // 4-10
46
+ 'new-content', // 11-22
47
+ 'suffix', // 23-29
48
+ 'good', // 30-34
49
+ ]);
50
+ const result = handleStandardPatch(sourceTokens, patchTokens);
51
+ // It should fail with 'bad'/'good', then trim them, then succeed on ['prefix', 'new-content', 'suffix']
52
+ expect(result).toEqual({
53
+ replaceStart: 0, // start of 'prefix' in source
54
+ replaceEnd: 21, // end of 'suffix' in source
55
+ patchInsertStart: 4, // start of 'prefix' in patch
56
+ patchInsertEnd: 29, // end of 'suffix' in patch
57
+ });
58
+ });
59
+
60
+ it('should throw for persistently ambiguous prefix', () => {
61
+ const sourceTokens = makeTokens(['a', 'b', 'c', 'a', 'b', 'd']);
62
+ const patchTokens = makeTokens(['a', 'b', 'e']); // a b is ambiguous
63
+ expect(() => handleStandardPatch(sourceTokens, patchTokens)).toThrow(
64
+ /Ambiguous prefix anchor/,
65
+ );
66
+ });
67
+
68
+ it('should throw for persistently ambiguous suffix', () => {
69
+ const sourceTokens = makeTokens(['prefix', 'x', 'suffix', 'y', 'suffix']);
70
+ const patchTokens = makeTokens(['prefix', 'z', 'suffix']);
71
+ expect(() => handleStandardPatch(sourceTokens, patchTokens)).toThrow(
72
+ /Ambiguous suffix anchor/,
73
+ );
74
+ });
75
+
76
+ it('should throw if patch has fewer than two tokens', () => {
77
+ const sourceTokens = makeTokens(['a', 'b', 'c']);
78
+ const patchTokens = makeTokens(['a']);
79
+ expect(() => handleStandardPatch(sourceTokens, patchTokens)).toThrow(
80
+ 'Patch must contain at least two tokens to form a prefix and a suffix.',
81
+ );
82
+ });
83
+ });
84
+
85
+ describe('handleBeginOfFilePatch', () => {
86
+ it('should find a unique suffix anchor', () => {
87
+ const sourceTokens = makeTokens(['a', 'b', 'c', 'd']);
88
+ const patchTokens = makeTokens(['x', 'y', 'c', 'd']); // Suffix is 'c', 'd'
89
+ const result = handleBeginOfFilePatch(sourceTokens, patchTokens);
90
+ expect(result).toEqual({
91
+ patchInsertEnd: 7,
92
+ patchInsertStart: 0,
93
+ replaceStart: 0,
94
+ replaceEnd: 7, // endIndex of 'd'
95
+ });
96
+ });
97
+
98
+ it('should trim from the start to find a unique suffix', () => {
99
+ // The "good" part of the patch, ['a', 'b'], is unique in the source.
100
+ const sourceTokens = makeTokens(['x', 'y', 'a', 'b']);
101
+ // The initial patch will fail because the suffix ['y', 'a', 'b'] is not in the source.
102
+ const patchTokens = makeTokens([
103
+ 'bad', // 0-3
104
+ 'token', // 4-9
105
+ 'a', // 10-11
106
+ 'b', // 12-13
107
+ ]);
108
+ const result = handleBeginOfFilePatch(sourceTokens, patchTokens);
109
+ // Should fail, trim 'bad', fail, trim 'token', then succeed with suffix ['a', 'b'].
110
+ expect(result).toEqual({
111
+ replaceStart: 0,
112
+ replaceEnd: 7, // end of 'b' in source
113
+ patchInsertStart: 0, // start of 'a' in patch
114
+ patchInsertEnd: 13, // end of 'b' in patch
115
+ });
116
+ });
117
+
118
+ it('should throw for a persistently ambiguous suffix', () => {
119
+ const sourceTokens = makeTokens(['a', 'b', 'a', 'b']);
120
+ const patchTokens = makeTokens(['x', 'y', 'a', 'b']);
121
+ expect(() => handleBeginOfFilePatch(sourceTokens, patchTokens)).toThrow(
122
+ /Ambiguous suffix anchor/,
123
+ );
124
+ });
125
+
126
+ it('should throw if anchor not found even after trimming', () => {
127
+ const sourceTokens = makeTokens(['a', 'b', 'c']);
128
+ const patchTokens = makeTokens(['x', 'y', 'z']);
129
+ expect(() => handleBeginOfFilePatch(sourceTokens, patchTokens)).toThrow(
130
+ /Suffix anchor not found/,
131
+ );
132
+ });
133
+ });
134
+
135
+ describe('handleEndOfFilePatch', () => {
136
+ const sourceCode = 'a b c d'; // length 7
137
+ const sourceTokens = makeTokens(['a', 'b', 'c', 'd']);
138
+
139
+ it('should find a unique prefix anchor', () => {
140
+ const patchTokens = makeTokens(['a', 'b', 'x', 'y']); // Prefix is 'a', 'b'
141
+ const result = handleEndOfFilePatch(
142
+ sourceTokens,
143
+ patchTokens,
144
+ sourceCode,
145
+ );
146
+ expect(result).toEqual({
147
+ patchInsertEnd: 7,
148
+ patchInsertStart: 0,
149
+ replaceStart: 0, // startIndex of 'a'
150
+ replaceEnd: 7, // sourceCode.length
151
+ });
152
+ });
153
+
154
+ it('should trim from the end to find a unique prefix', () => {
155
+ // The "good" part of the patch, ['c', 'd'], is unique in the source.
156
+ const sourceTokens = makeTokens(['c', 'd', 'x', 'y']);
157
+ const sourceCode = 'c d x y'; // length 7
158
+ // The initial patch will fail because the prefix ['c', 'd', 'bad'] is not in the source.
159
+ const patchTokens = makeTokens([
160
+ 'c', // 0-1
161
+ 'd', // 2-3
162
+ 'bad', // 4-7
163
+ 'token', // 8-13
164
+ ]);
165
+ const result = handleEndOfFilePatch(
166
+ sourceTokens,
167
+ patchTokens,
168
+ sourceCode,
169
+ );
170
+ // Should fail, trim 'token', fail, trim 'bad', then succeed with prefix ['c', 'd'].
171
+ expect(result).toEqual({
172
+ replaceStart: 0, // start of 'c' in source
173
+ replaceEnd: 7, // sourceCode.length
174
+ patchInsertStart: 0, // start of 'c' in patch
175
+ patchInsertEnd: 13, // end of 'd' in patch
176
+ });
177
+ });
178
+
179
+ it('should throw for a persistently ambiguous prefix', () => {
180
+ const ambiguousSourceTokens = makeTokens(['a', 'b', 'a', 'b']);
181
+ const patchTokens = makeTokens(['a', 'b', 'x', 'y']);
182
+ expect(() =>
183
+ handleEndOfFilePatch(ambiguousSourceTokens, patchTokens, 'a b a b'),
184
+ ).toThrow(/Ambiguous prefix anchor/);
185
+ });
186
+
187
+ it('should throw if anchor not found even after trimming', () => {
188
+ const patchTokens = makeTokens(['x', 'y', 'z']);
189
+ expect(() =>
190
+ handleEndOfFilePatch(sourceTokens, patchTokens, sourceCode),
191
+ ).toThrow(/Prefix anchor not found/);
192
+ });
193
+ });
194
+ });
@@ -0,0 +1,300 @@
1
+ import type { Token } from './types';
2
+ import { findAllSequences, formatAnchor } from './tokens';
3
+
4
+ interface PatchResult {
5
+ replaceStart: number;
6
+ replaceEnd: number;
7
+ patchInsertStart: number;
8
+ patchInsertEnd: number;
9
+ }
10
+
11
+ interface SimplePatchResult {
12
+ replaceStart: number;
13
+ replaceEnd: number;
14
+ }
15
+
16
+ // Internal helper for the original matching logic
17
+ function _findBeginOfFilePatchLocation(
18
+ sourceTokens: Token[],
19
+ patchTokens: Token[],
20
+ ): SimplePatchResult {
21
+ let replaceStart: number | null = null;
22
+ let replaceEnd: number | null = null;
23
+ let lastError = '';
24
+
25
+ for (let anchorSize = 1; anchorSize <= patchTokens.length; anchorSize++) {
26
+ const suffixAnchor = patchTokens.slice(patchTokens.length - anchorSize);
27
+ const indices = findAllSequences(sourceTokens, suffixAnchor);
28
+
29
+ if (indices.length === 1) {
30
+ replaceStart = 0;
31
+ const suffixIndex = indices[0];
32
+ replaceEnd = sourceTokens[suffixIndex + anchorSize - 1].endIndex;
33
+ break; // Found unique anchor
34
+ }
35
+
36
+ if (indices.length > 1) {
37
+ const formattedAnchor = formatAnchor(suffixAnchor);
38
+ const locations = indices
39
+ .map((i) => `line ${sourceTokens[i].startPosition.row + 1}`)
40
+ .join(', ');
41
+ lastError = `Ambiguous suffix anchor. The sequence "${formattedAnchor}" was found at ${indices.length} locations: ${locations}.`;
42
+ }
43
+ }
44
+
45
+ if (replaceStart === null || replaceEnd === null) {
46
+ const smallestAnchor = patchTokens.slice(patchTokens.length - 1);
47
+ throw new Error(
48
+ lastError ||
49
+ `Suffix anchor not found. The sequence "${formatAnchor(
50
+ smallestAnchor,
51
+ )}" could not be located.`,
52
+ );
53
+ }
54
+
55
+ return { replaceStart, replaceEnd };
56
+ }
57
+
58
+ export function handleBeginOfFilePatch(
59
+ sourceTokens: Token[],
60
+ originalPatchTokens: Token[],
61
+ ): PatchResult {
62
+ if (originalPatchTokens.length === 0) {
63
+ throw new Error('Patch is empty after removing @begin-of-file marker.');
64
+ }
65
+
66
+ let patchAttempt = [...originalPatchTokens];
67
+ let lastError: Error | null = null;
68
+
69
+ // Outer loop for trimming tokens from the start
70
+ while (patchAttempt.length >= 1) {
71
+ try {
72
+ const { replaceStart, replaceEnd } = _findBeginOfFilePatchLocation(
73
+ sourceTokens,
74
+ patchAttempt,
75
+ );
76
+ const patchInsertStart = patchAttempt[0].startIndex;
77
+ const patchInsertEnd = patchAttempt[patchAttempt.length - 1].endIndex;
78
+ return { replaceStart, replaceEnd, patchInsertStart, patchInsertEnd };
79
+ } catch (e) {
80
+ lastError = e as Error;
81
+ patchAttempt = patchAttempt.slice(1); // Trim one token from the beginning
82
+ }
83
+ }
84
+
85
+ throw new Error(
86
+ `Failed to apply @begin-of-file patch. Could not find a unique anchor, even after trimming tokens. Last known error: ${lastError?.message}`,
87
+ );
88
+ }
89
+
90
+ // Internal helper for the original matching logic
91
+ function _findEndOfFilePatchLocation(
92
+ sourceTokens: Token[],
93
+ patchTokens: Token[],
94
+ sourceCode: string,
95
+ ): SimplePatchResult {
96
+ let replaceStart: number | null = null;
97
+ let replaceEnd: number | null = null;
98
+ let lastError = '';
99
+
100
+ for (let anchorSize = 1; anchorSize <= patchTokens.length; anchorSize++) {
101
+ const prefixAnchor = patchTokens.slice(0, anchorSize);
102
+ const indices = findAllSequences(sourceTokens, prefixAnchor);
103
+
104
+ if (indices.length === 1) {
105
+ replaceStart = sourceTokens[indices[0]].startIndex;
106
+ replaceEnd = sourceCode.length;
107
+ break; // Found unique anchor
108
+ }
109
+
110
+ if (indices.length > 1) {
111
+ const formattedAnchor = formatAnchor(prefixAnchor);
112
+ const locations = indices
113
+ .map((i) => `line ${sourceTokens[i].startPosition.row + 1}`)
114
+ .join(', ');
115
+ lastError = `Ambiguous prefix anchor. The sequence "${formattedAnchor}" was found at ${indices.length} locations: ${locations}.`;
116
+ }
117
+ }
118
+
119
+ if (replaceStart === null || replaceEnd === null) {
120
+ const smallestAnchor = patchTokens.slice(0, 1);
121
+ throw new Error(
122
+ lastError ||
123
+ `Prefix anchor not found. The sequence "${formatAnchor(
124
+ smallestAnchor,
125
+ )}" could not be located.`,
126
+ );
127
+ }
128
+ return { replaceStart, replaceEnd };
129
+ }
130
+
131
+ export function handleEndOfFilePatch(
132
+ sourceTokens: Token[],
133
+ originalPatchTokens: Token[],
134
+ sourceCode: string,
135
+ ): PatchResult {
136
+ if (originalPatchTokens.length === 0) {
137
+ throw new Error('Patch is empty after removing @end-of-file marker.');
138
+ }
139
+
140
+ let patchAttempt = [...originalPatchTokens];
141
+ let lastError: Error | null = null;
142
+
143
+ // Outer loop for trimming tokens from the end
144
+ while (patchAttempt.length >= 1) {
145
+ try {
146
+ const { replaceStart, replaceEnd } = _findEndOfFilePatchLocation(
147
+ sourceTokens,
148
+ patchAttempt,
149
+ sourceCode,
150
+ );
151
+ const patchInsertStart = patchAttempt[0].startIndex;
152
+ const patchInsertEnd = patchAttempt[patchAttempt.length - 1].endIndex;
153
+ return { replaceStart, replaceEnd, patchInsertStart, patchInsertEnd };
154
+ } catch (e) {
155
+ lastError = e as Error;
156
+ patchAttempt = patchAttempt.slice(0, -1); // Trim one token from the end
157
+ }
158
+ }
159
+
160
+ throw new Error(
161
+ `Failed to apply @end-of-file patch. Could not find a unique anchor, even after trimming tokens. Last known error: ${lastError?.message}`,
162
+ );
163
+ }
164
+
165
+ // Internal helper for the original matching logic
166
+ function _findStandardPatchLocation(
167
+ sourceTokens: Token[],
168
+ patchTokens: Token[],
169
+ ): SimplePatchResult {
170
+ // 1. Find smallest unique prefix
171
+ let prefixAnchor: Token[] | null = null;
172
+ let prefixIndex: number | null = null;
173
+ let bestPrefixError: string | null = null;
174
+
175
+ for (let prefixSize = 1; prefixSize < patchTokens.length; prefixSize++) {
176
+ const currentPrefix = patchTokens.slice(0, prefixSize);
177
+ const prefixIndices = findAllSequences(sourceTokens, currentPrefix);
178
+
179
+ if (prefixIndices.length === 1) {
180
+ prefixAnchor = currentPrefix;
181
+ prefixIndex = prefixIndices[0];
182
+ bestPrefixError = null; // Found it
183
+ break;
184
+ }
185
+ if (prefixIndices.length > 1) {
186
+ const formatted = formatAnchor(currentPrefix);
187
+ const locations = prefixIndices
188
+ .map((i) => `line ${sourceTokens[i].startPosition.row + 1}`)
189
+ .join(', ');
190
+ bestPrefixError = `Ambiguous prefix anchor. The sequence "${formatted}" was found at ${prefixIndices.length} locations: ${locations}.`;
191
+ }
192
+ if (prefixIndices.length === 0) {
193
+ if (!bestPrefixError) {
194
+ const formatted = formatAnchor(currentPrefix);
195
+ bestPrefixError = `Prefix anchor not found: "${formatted}"`;
196
+ }
197
+ break; // A larger prefix will also not be found
198
+ }
199
+ }
200
+
201
+ if (!prefixAnchor || prefixIndex === null) {
202
+ throw new Error(
203
+ bestPrefixError || 'Could not find a unique prefix anchor.',
204
+ );
205
+ }
206
+
207
+ // 2. Find smallest unique suffix after prefix
208
+ let suffixAnchor: Token[] | null = null;
209
+ let suffixIndex: number | null = null;
210
+ let bestSuffixError: string | null = null;
211
+ const searchStartIndex = prefixIndex + prefixAnchor.length;
212
+ const sourceAfterPrefix = sourceTokens.slice(searchStartIndex);
213
+
214
+ for (
215
+ let suffixSize = 1;
216
+ suffixSize <= patchTokens.length - prefixAnchor.length;
217
+ suffixSize++
218
+ ) {
219
+ const currentSuffix = patchTokens.slice(patchTokens.length - suffixSize);
220
+ const suffixIndices = findAllSequences(sourceAfterPrefix, currentSuffix);
221
+
222
+ if (suffixIndices.length === 1) {
223
+ suffixAnchor = currentSuffix;
224
+ suffixIndex = searchStartIndex + suffixIndices[0];
225
+ bestSuffixError = null; // Found it
226
+ break;
227
+ }
228
+ if (suffixIndices.length > 1) {
229
+ const formatted = formatAnchor(currentSuffix);
230
+ const locations = suffixIndices
231
+ .map(
232
+ (i) =>
233
+ `line ${
234
+ sourceTokens[searchStartIndex + i].startPosition.row + 1
235
+ }`,
236
+ )
237
+ .join(', ');
238
+ bestSuffixError = `Ambiguous suffix anchor. The sequence "${formatted}" was found ${suffixIndices.length} times after the prefix: ${locations}.`;
239
+ }
240
+ }
241
+ if (!suffixAnchor || suffixIndex === null) {
242
+ if (bestSuffixError) {
243
+ throw new Error(bestSuffixError);
244
+ }
245
+ const prefixLocation = `line ${
246
+ sourceTokens[prefixIndex].startPosition.row + 1
247
+ }`;
248
+ const formattedPrefix = formatAnchor(prefixAnchor);
249
+ const smallestSuffix = formatAnchor(
250
+ patchTokens.slice(patchTokens.length - 1),
251
+ );
252
+
253
+ throw new Error(
254
+ `Could not find a unique suffix anchor after the prefix anchor "${formattedPrefix}" (found at ${prefixLocation}). ` +
255
+ `The smallest suffix searched for ("${smallestSuffix}") was not found after it.`,
256
+ );
257
+ }
258
+
259
+ // 3. Apply patch
260
+ const replaceStart = sourceTokens[prefixIndex].startIndex;
261
+ const replaceEnd =
262
+ sourceTokens[suffixIndex + suffixAnchor.length - 1].endIndex;
263
+
264
+ return { replaceStart, replaceEnd };
265
+ }
266
+
267
+ export function handleStandardPatch(
268
+ sourceTokens: Token[],
269
+ originalPatchTokens: Token[],
270
+ ): PatchResult {
271
+ if (originalPatchTokens.length < 2) {
272
+ throw new Error(
273
+ 'Patch must contain at least two tokens to form a prefix and a suffix.',
274
+ );
275
+ }
276
+
277
+ let patchAttempt = [...originalPatchTokens];
278
+ let lastError: Error | null = null;
279
+
280
+ // Outer loop for trimming tokens from both ends
281
+ while (patchAttempt.length >= 2) {
282
+ try {
283
+ const { replaceStart, replaceEnd } = _findStandardPatchLocation(
284
+ sourceTokens,
285
+ patchAttempt,
286
+ );
287
+ const patchInsertStart = patchAttempt[0].startIndex;
288
+ const patchInsertEnd = patchAttempt[patchAttempt.length - 1].endIndex;
289
+ return { replaceStart, replaceEnd, patchInsertStart, patchInsertEnd };
290
+ } catch (e) {
291
+ lastError = e as Error;
292
+ // Trim one token from the start and one from the end for the next attempt
293
+ patchAttempt = patchAttempt.slice(1, -1);
294
+ }
295
+ }
296
+
297
+ throw new Error(
298
+ `Failed to apply patch. Could not find a unique anchor in the source file, even after trimming ambiguous tokens. Last known error: ${lastError?.message}`,
299
+ );
300
+ }
@@ -0,0 +1,84 @@
1
+ import { findAllSequences, tokensEqual, formatAnchor } from './tokens';
2
+ import type { Token } from './types';
3
+
4
+ // A helper to create mock tokens for testing
5
+ const makeTokens = (texts: string[]): Token[] => {
6
+ let startIndex = 0;
7
+ return texts.map((text) => {
8
+ const token: Token = {
9
+ text,
10
+ type: 'identifier', // type and positions are not important for these tests
11
+ startIndex: startIndex,
12
+ endIndex: startIndex + text.length,
13
+ startPosition: { row: 0, column: startIndex },
14
+ };
15
+ startIndex += text.length + 1; // +1 for space
16
+ return token;
17
+ });
18
+ };
19
+
20
+ describe('token-utils', () => {
21
+ describe('findAllSequences', () => {
22
+ it('should find a single unique sequence', () => {
23
+ const haystack = makeTokens(['a', 'b', 'c', 'd', 'e']);
24
+ const needle = makeTokens(['b', 'c']);
25
+ const indices = findAllSequences(haystack, needle);
26
+ expect(indices).toEqual([1]);
27
+ });
28
+
29
+ it('should find multiple occurrences of a sequence', () => {
30
+ const haystack = makeTokens(['a', 'b', 'c', 'a', 'b', 'c']);
31
+ const needle = makeTokens(['a', 'b', 'c']);
32
+ const indices = findAllSequences(haystack, needle);
33
+ expect(indices).toEqual([0, 3]);
34
+ });
35
+
36
+ it('should return an empty array if sequence is not found', () => {
37
+ const haystack = makeTokens(['a', 'b', 'c']);
38
+ const needle = makeTokens(['d', 'e']);
39
+ const indices = findAllSequences(haystack, needle);
40
+ expect(indices).toEqual([]);
41
+ });
42
+
43
+ it('should return an empty array for an empty needle', () => {
44
+ const haystack = makeTokens(['a', 'b', 'c']);
45
+ const needle = makeTokens([]);
46
+ const indices = findAllSequences(haystack, needle);
47
+ expect(indices).toEqual([]);
48
+ });
49
+
50
+ it('should handle sequences at the beginning and end of haystack', () => {
51
+ const haystack = makeTokens(['a', 'b', 'c', 'd', 'a', 'b']);
52
+ const needleAtStart = makeTokens(['a', 'b']);
53
+ const needleAtEnd = makeTokens(['a', 'b']);
54
+ expect(findAllSequences(haystack, needleAtStart)).toEqual([0, 4]);
55
+ expect(findAllSequences(haystack, needleAtEnd)).toEqual([0, 4]);
56
+ });
57
+ });
58
+
59
+ describe('tokensEqual', () => {
60
+ it('should return true for tokens with same text', () => {
61
+ const tokenA = makeTokens(['hello'])[0];
62
+ const tokenB = makeTokens(['hello'])[0];
63
+ expect(tokensEqual(tokenA, tokenB)).toBe(true);
64
+ });
65
+
66
+ it('should return false for tokens with different text', () => {
67
+ const tokenA = makeTokens(['hello'])[0];
68
+ const tokenB = makeTokens(['world'])[0];
69
+ expect(tokensEqual(tokenA, tokenB)).toBe(false);
70
+ });
71
+ });
72
+
73
+ describe('formatAnchor', () => {
74
+ it('should format an anchor to a space-separated string', () => {
75
+ const anchor = makeTokens(['const', 'x', '=', '1', ';']);
76
+ expect(formatAnchor(anchor)).toBe('const x = 1 ;');
77
+ });
78
+
79
+ it('should return an empty string for an empty anchor', () => {
80
+ const anchor = makeTokens([]);
81
+ expect(formatAnchor(anchor)).toBe('');
82
+ });
83
+ });
84
+ });
@@ -0,0 +1,50 @@
1
+ import type { Tree, Node } from 'web-tree-sitter';
2
+ import type { Token } from './types';
3
+
4
+ export function collectTokens(tree: Tree, code: string): Token[] {
5
+ const tokens: Token[] = [];
6
+
7
+ function visit(node: Node) {
8
+ if (node.childCount === 0) {
9
+ tokens.push({
10
+ text: code.slice(node.startIndex, node.endIndex),
11
+ type: node.type,
12
+ startIndex: node.startIndex,
13
+ endIndex: node.endIndex,
14
+ startPosition: node.startPosition,
15
+ });
16
+ return;
17
+ }
18
+ // By iterating over all children (not just named), we include punctuation
19
+ // which is critical for anchor-based matching.
20
+ for (let i = 0; i < node.childCount; i++) {
21
+ const child = node.child(i);
22
+ if (child) visit(child);
23
+ }
24
+ }
25
+
26
+ visit(tree.rootNode);
27
+ return tokens;
28
+ }
29
+
30
+ export function tokensEqual(a: Token, b: Token): boolean {
31
+ return a.text === b.text;
32
+ }
33
+
34
+ export function formatAnchor(anchor: Token[]): string {
35
+ return anchor.map((t) => t.text).join(' ');
36
+ }
37
+
38
+ export function findAllSequences(haystack: Token[], needle: Token[]): number[] {
39
+ if (needle.length === 0) return [];
40
+ const indices: number[] = [];
41
+ outer: for (let i = 0; i <= haystack.length - needle.length; i++) {
42
+ for (let j = 0; j < needle.length; j++) {
43
+ if (!tokensEqual(haystack[i + j], needle[j])) {
44
+ continue outer;
45
+ }
46
+ }
47
+ indices.push(i);
48
+ }
49
+ return indices;
50
+ }
@@ -0,0 +1,9 @@
1
+ import type { Point } from 'web-tree-sitter';
2
+
3
+ export interface Token {
4
+ text: string;
5
+ type: string;
6
+ startIndex: number; // byte offsets (tree-sitter)
7
+ endIndex: number;
8
+ startPosition: Point;
9
+ }