@animus-labs/cortex 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +73 -0
  3. package/dist/budget-guard.d.ts +75 -0
  4. package/dist/budget-guard.d.ts.map +1 -0
  5. package/dist/budget-guard.js +142 -0
  6. package/dist/budget-guard.js.map +1 -0
  7. package/dist/compaction/compaction.d.ts +99 -0
  8. package/dist/compaction/compaction.d.ts.map +1 -0
  9. package/dist/compaction/compaction.js +302 -0
  10. package/dist/compaction/compaction.js.map +1 -0
  11. package/dist/compaction/failsafe.d.ts +57 -0
  12. package/dist/compaction/failsafe.d.ts.map +1 -0
  13. package/dist/compaction/failsafe.js +135 -0
  14. package/dist/compaction/failsafe.js.map +1 -0
  15. package/dist/compaction/index.d.ts +381 -0
  16. package/dist/compaction/index.d.ts.map +1 -0
  17. package/dist/compaction/index.js +979 -0
  18. package/dist/compaction/index.js.map +1 -0
  19. package/dist/compaction/microcompaction.d.ts +219 -0
  20. package/dist/compaction/microcompaction.d.ts.map +1 -0
  21. package/dist/compaction/microcompaction.js +536 -0
  22. package/dist/compaction/microcompaction.js.map +1 -0
  23. package/dist/compaction/observational/buffering.d.ts +225 -0
  24. package/dist/compaction/observational/buffering.d.ts.map +1 -0
  25. package/dist/compaction/observational/buffering.js +354 -0
  26. package/dist/compaction/observational/buffering.js.map +1 -0
  27. package/dist/compaction/observational/constants.d.ts +70 -0
  28. package/dist/compaction/observational/constants.d.ts.map +1 -0
  29. package/dist/compaction/observational/constants.js +507 -0
  30. package/dist/compaction/observational/constants.js.map +1 -0
  31. package/dist/compaction/observational/index.d.ts +219 -0
  32. package/dist/compaction/observational/index.d.ts.map +1 -0
  33. package/dist/compaction/observational/index.js +641 -0
  34. package/dist/compaction/observational/index.js.map +1 -0
  35. package/dist/compaction/observational/observer.d.ts +97 -0
  36. package/dist/compaction/observational/observer.d.ts.map +1 -0
  37. package/dist/compaction/observational/observer.js +424 -0
  38. package/dist/compaction/observational/observer.js.map +1 -0
  39. package/dist/compaction/observational/recall-tool.d.ts +27 -0
  40. package/dist/compaction/observational/recall-tool.d.ts.map +1 -0
  41. package/dist/compaction/observational/recall-tool.js +93 -0
  42. package/dist/compaction/observational/recall-tool.js.map +1 -0
  43. package/dist/compaction/observational/reflector.d.ts +94 -0
  44. package/dist/compaction/observational/reflector.d.ts.map +1 -0
  45. package/dist/compaction/observational/reflector.js +167 -0
  46. package/dist/compaction/observational/reflector.js.map +1 -0
  47. package/dist/compaction/observational/types.d.ts +271 -0
  48. package/dist/compaction/observational/types.d.ts.map +1 -0
  49. package/dist/compaction/observational/types.js +15 -0
  50. package/dist/compaction/observational/types.js.map +1 -0
  51. package/dist/context-manager.d.ts +134 -0
  52. package/dist/context-manager.d.ts.map +1 -0
  53. package/dist/context-manager.js +170 -0
  54. package/dist/context-manager.js.map +1 -0
  55. package/dist/cortex-agent.d.ts +1020 -0
  56. package/dist/cortex-agent.d.ts.map +1 -0
  57. package/dist/cortex-agent.js +3589 -0
  58. package/dist/cortex-agent.js.map +1 -0
  59. package/dist/error-classifier.d.ts +48 -0
  60. package/dist/error-classifier.d.ts.map +1 -0
  61. package/dist/error-classifier.js +152 -0
  62. package/dist/error-classifier.js.map +1 -0
  63. package/dist/event-bridge.d.ts +166 -0
  64. package/dist/event-bridge.d.ts.map +1 -0
  65. package/dist/event-bridge.js +381 -0
  66. package/dist/event-bridge.js.map +1 -0
  67. package/dist/index.d.ts +55 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +57 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/mcp-client.d.ts +119 -0
  72. package/dist/mcp-client.d.ts.map +1 -0
  73. package/dist/mcp-client.js +474 -0
  74. package/dist/mcp-client.js.map +1 -0
  75. package/dist/model-wrapper.d.ts +58 -0
  76. package/dist/model-wrapper.d.ts.map +1 -0
  77. package/dist/model-wrapper.js +86 -0
  78. package/dist/model-wrapper.js.map +1 -0
  79. package/dist/noop-logger.d.ts +4 -0
  80. package/dist/noop-logger.d.ts.map +1 -0
  81. package/dist/noop-logger.js +8 -0
  82. package/dist/noop-logger.js.map +1 -0
  83. package/dist/prompt-diagnostics.d.ts +47 -0
  84. package/dist/prompt-diagnostics.d.ts.map +1 -0
  85. package/dist/prompt-diagnostics.js +230 -0
  86. package/dist/prompt-diagnostics.js.map +1 -0
  87. package/dist/provider-manager.d.ts +224 -0
  88. package/dist/provider-manager.d.ts.map +1 -0
  89. package/dist/provider-manager.js +563 -0
  90. package/dist/provider-manager.js.map +1 -0
  91. package/dist/provider-registry.d.ts +115 -0
  92. package/dist/provider-registry.d.ts.map +1 -0
  93. package/dist/provider-registry.js +305 -0
  94. package/dist/provider-registry.js.map +1 -0
  95. package/dist/schema-converter.d.ts +20 -0
  96. package/dist/schema-converter.d.ts.map +1 -0
  97. package/dist/schema-converter.js +48 -0
  98. package/dist/schema-converter.js.map +1 -0
  99. package/dist/skill-preprocessor.d.ts +46 -0
  100. package/dist/skill-preprocessor.d.ts.map +1 -0
  101. package/dist/skill-preprocessor.js +237 -0
  102. package/dist/skill-preprocessor.js.map +1 -0
  103. package/dist/skill-registry.d.ts +107 -0
  104. package/dist/skill-registry.d.ts.map +1 -0
  105. package/dist/skill-registry.js +330 -0
  106. package/dist/skill-registry.js.map +1 -0
  107. package/dist/skill-tool.d.ts +54 -0
  108. package/dist/skill-tool.d.ts.map +1 -0
  109. package/dist/skill-tool.js +88 -0
  110. package/dist/skill-tool.js.map +1 -0
  111. package/dist/sub-agent-manager.d.ts +90 -0
  112. package/dist/sub-agent-manager.d.ts.map +1 -0
  113. package/dist/sub-agent-manager.js +192 -0
  114. package/dist/sub-agent-manager.js.map +1 -0
  115. package/dist/token-estimator.d.ts +23 -0
  116. package/dist/token-estimator.d.ts.map +1 -0
  117. package/dist/token-estimator.js +27 -0
  118. package/dist/token-estimator.js.map +1 -0
  119. package/dist/tool-contract.d.ts +68 -0
  120. package/dist/tool-contract.d.ts.map +1 -0
  121. package/dist/tool-contract.js +35 -0
  122. package/dist/tool-contract.js.map +1 -0
  123. package/dist/tool-result-persistence.d.ts +89 -0
  124. package/dist/tool-result-persistence.d.ts.map +1 -0
  125. package/dist/tool-result-persistence.js +152 -0
  126. package/dist/tool-result-persistence.js.map +1 -0
  127. package/dist/tools/bash/index.d.ts +71 -0
  128. package/dist/tools/bash/index.d.ts.map +1 -0
  129. package/dist/tools/bash/index.js +485 -0
  130. package/dist/tools/bash/index.js.map +1 -0
  131. package/dist/tools/bash/interactive.d.ts +47 -0
  132. package/dist/tools/bash/interactive.d.ts.map +1 -0
  133. package/dist/tools/bash/interactive.js +262 -0
  134. package/dist/tools/bash/interactive.js.map +1 -0
  135. package/dist/tools/bash/safety.d.ts +149 -0
  136. package/dist/tools/bash/safety.d.ts.map +1 -0
  137. package/dist/tools/bash/safety.js +1116 -0
  138. package/dist/tools/bash/safety.js.map +1 -0
  139. package/dist/tools/edit.d.ts +57 -0
  140. package/dist/tools/edit.d.ts.map +1 -0
  141. package/dist/tools/edit.js +310 -0
  142. package/dist/tools/edit.js.map +1 -0
  143. package/dist/tools/glob.d.ts +34 -0
  144. package/dist/tools/glob.d.ts.map +1 -0
  145. package/dist/tools/glob.js +268 -0
  146. package/dist/tools/glob.js.map +1 -0
  147. package/dist/tools/grep.d.ts +53 -0
  148. package/dist/tools/grep.d.ts.map +1 -0
  149. package/dist/tools/grep.js +673 -0
  150. package/dist/tools/grep.js.map +1 -0
  151. package/dist/tools/index.d.ts +62 -0
  152. package/dist/tools/index.d.ts.map +1 -0
  153. package/dist/tools/index.js +52 -0
  154. package/dist/tools/index.js.map +1 -0
  155. package/dist/tools/read.d.ts +43 -0
  156. package/dist/tools/read.d.ts.map +1 -0
  157. package/dist/tools/read.js +459 -0
  158. package/dist/tools/read.js.map +1 -0
  159. package/dist/tools/runtime.d.ts +62 -0
  160. package/dist/tools/runtime.d.ts.map +1 -0
  161. package/dist/tools/runtime.js +116 -0
  162. package/dist/tools/runtime.js.map +1 -0
  163. package/dist/tools/shared/cwd-tracker.d.ts +32 -0
  164. package/dist/tools/shared/cwd-tracker.d.ts.map +1 -0
  165. package/dist/tools/shared/cwd-tracker.js +44 -0
  166. package/dist/tools/shared/cwd-tracker.js.map +1 -0
  167. package/dist/tools/shared/edit-history.d.ts +55 -0
  168. package/dist/tools/shared/edit-history.d.ts.map +1 -0
  169. package/dist/tools/shared/edit-history.js +72 -0
  170. package/dist/tools/shared/edit-history.js.map +1 -0
  171. package/dist/tools/shared/edit-matcher.d.ts +83 -0
  172. package/dist/tools/shared/edit-matcher.d.ts.map +1 -0
  173. package/dist/tools/shared/edit-matcher.js +359 -0
  174. package/dist/tools/shared/edit-matcher.js.map +1 -0
  175. package/dist/tools/shared/file-mutation-lock.d.ts +22 -0
  176. package/dist/tools/shared/file-mutation-lock.d.ts.map +1 -0
  177. package/dist/tools/shared/file-mutation-lock.js +35 -0
  178. package/dist/tools/shared/file-mutation-lock.js.map +1 -0
  179. package/dist/tools/shared/gitignore.d.ts +17 -0
  180. package/dist/tools/shared/gitignore.d.ts.map +1 -0
  181. package/dist/tools/shared/gitignore.js +59 -0
  182. package/dist/tools/shared/gitignore.js.map +1 -0
  183. package/dist/tools/shared/pdf-extractor.d.ts +96 -0
  184. package/dist/tools/shared/pdf-extractor.d.ts.map +1 -0
  185. package/dist/tools/shared/pdf-extractor.js +196 -0
  186. package/dist/tools/shared/pdf-extractor.js.map +1 -0
  187. package/dist/tools/shared/read-registry.d.ts +66 -0
  188. package/dist/tools/shared/read-registry.d.ts.map +1 -0
  189. package/dist/tools/shared/read-registry.js +65 -0
  190. package/dist/tools/shared/read-registry.js.map +1 -0
  191. package/dist/tools/shared/safe-env.d.ts +18 -0
  192. package/dist/tools/shared/safe-env.d.ts.map +1 -0
  193. package/dist/tools/shared/safe-env.js +70 -0
  194. package/dist/tools/shared/safe-env.js.map +1 -0
  195. package/dist/tools/sub-agent.d.ts +91 -0
  196. package/dist/tools/sub-agent.d.ts.map +1 -0
  197. package/dist/tools/sub-agent.js +89 -0
  198. package/dist/tools/sub-agent.js.map +1 -0
  199. package/dist/tools/task-output.d.ts +38 -0
  200. package/dist/tools/task-output.d.ts.map +1 -0
  201. package/dist/tools/task-output.js +186 -0
  202. package/dist/tools/task-output.js.map +1 -0
  203. package/dist/tools/tool-search/index.d.ts +40 -0
  204. package/dist/tools/tool-search/index.d.ts.map +1 -0
  205. package/dist/tools/tool-search/index.js +110 -0
  206. package/dist/tools/tool-search/index.js.map +1 -0
  207. package/dist/tools/tool-search/registry.d.ts +82 -0
  208. package/dist/tools/tool-search/registry.d.ts.map +1 -0
  209. package/dist/tools/tool-search/registry.js +238 -0
  210. package/dist/tools/tool-search/registry.js.map +1 -0
  211. package/dist/tools/undo-edit.d.ts +51 -0
  212. package/dist/tools/undo-edit.d.ts.map +1 -0
  213. package/dist/tools/undo-edit.js +231 -0
  214. package/dist/tools/undo-edit.js.map +1 -0
  215. package/dist/tools/web-fetch/cache.d.ts +49 -0
  216. package/dist/tools/web-fetch/cache.d.ts.map +1 -0
  217. package/dist/tools/web-fetch/cache.js +89 -0
  218. package/dist/tools/web-fetch/cache.js.map +1 -0
  219. package/dist/tools/web-fetch/index.d.ts +53 -0
  220. package/dist/tools/web-fetch/index.d.ts.map +1 -0
  221. package/dist/tools/web-fetch/index.js +513 -0
  222. package/dist/tools/web-fetch/index.js.map +1 -0
  223. package/dist/tools/write.d.ts +59 -0
  224. package/dist/tools/write.d.ts.map +1 -0
  225. package/dist/tools/write.js +316 -0
  226. package/dist/tools/write.js.map +1 -0
  227. package/dist/types.d.ts +881 -0
  228. package/dist/types.d.ts.map +1 -0
  229. package/dist/types.js +16 -0
  230. package/dist/types.js.map +1 -0
  231. package/dist/working-tags.d.ts +44 -0
  232. package/dist/working-tags.d.ts.map +1 -0
  233. package/dist/working-tags.js +103 -0
  234. package/dist/working-tags.js.map +1 -0
  235. package/package.json +87 -0
  236. package/src/budget-guard.ts +170 -0
  237. package/src/compaction/compaction.ts +386 -0
  238. package/src/compaction/failsafe.ts +185 -0
  239. package/src/compaction/index.ts +1199 -0
  240. package/src/compaction/microcompaction.ts +709 -0
  241. package/src/compaction/observational/buffering.ts +430 -0
  242. package/src/compaction/observational/constants.ts +532 -0
  243. package/src/compaction/observational/index.ts +837 -0
  244. package/src/compaction/observational/observer.ts +510 -0
  245. package/src/compaction/observational/recall-tool.ts +130 -0
  246. package/src/compaction/observational/reflector.ts +221 -0
  247. package/src/compaction/observational/types.ts +343 -0
  248. package/src/context-manager.ts +237 -0
  249. package/src/cortex-agent.ts +4297 -0
  250. package/src/error-classifier.ts +199 -0
  251. package/src/event-bridge.ts +508 -0
  252. package/src/index.ts +292 -0
  253. package/src/mcp-client.ts +582 -0
  254. package/src/model-wrapper.ts +128 -0
  255. package/src/noop-logger.ts +9 -0
  256. package/src/prompt-diagnostics.ts +296 -0
  257. package/src/provider-manager.ts +823 -0
  258. package/src/provider-registry.ts +386 -0
  259. package/src/schema-converter.ts +51 -0
  260. package/src/skill-preprocessor.ts +314 -0
  261. package/src/skill-registry.ts +378 -0
  262. package/src/skill-tool.ts +130 -0
  263. package/src/sub-agent-manager.ts +236 -0
  264. package/src/token-estimator.ts +26 -0
  265. package/src/tool-contract.ts +113 -0
  266. package/src/tool-result-persistence.ts +197 -0
  267. package/src/tools/bash/index.ts +633 -0
  268. package/src/tools/bash/interactive.ts +302 -0
  269. package/src/tools/bash/safety.ts +1297 -0
  270. package/src/tools/edit.ts +422 -0
  271. package/src/tools/glob.ts +330 -0
  272. package/src/tools/grep.ts +819 -0
  273. package/src/tools/index.ts +110 -0
  274. package/src/tools/read.ts +580 -0
  275. package/src/tools/runtime.ts +173 -0
  276. package/src/tools/shared/cwd-tracker.ts +50 -0
  277. package/src/tools/shared/edit-history.ts +96 -0
  278. package/src/tools/shared/edit-matcher.ts +457 -0
  279. package/src/tools/shared/file-mutation-lock.ts +40 -0
  280. package/src/tools/shared/gitignore.ts +61 -0
  281. package/src/tools/shared/pdf-extractor.ts +290 -0
  282. package/src/tools/shared/read-registry.ts +93 -0
  283. package/src/tools/shared/safe-env.ts +82 -0
  284. package/src/tools/sub-agent.ts +171 -0
  285. package/src/tools/task-output.ts +236 -0
  286. package/src/tools/tool-search/index.ts +167 -0
  287. package/src/tools/tool-search/registry.ts +278 -0
  288. package/src/tools/undo-edit.ts +314 -0
  289. package/src/tools/web-fetch/cache.ts +112 -0
  290. package/src/tools/web-fetch/index.ts +604 -0
  291. package/src/tools/write.ts +385 -0
  292. package/src/types.ts +1057 -0
  293. package/src/working-tags.ts +118 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/tools/runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Working directory tracking across Bash calls.
3
+ *
4
+ * Each Bash tool call spawns a new shell process. Shell state
5
+ * (env vars, aliases) does NOT persist between calls. Only the
6
+ * working directory persists via this tracker.
7
+ *
8
+ * The tracker is reset to the default directory at the start
9
+ * of each agentic loop.
10
+ */
11
+ export declare class CwdTracker {
12
+ private readonly defaultDir;
13
+ private currentDir;
14
+ constructor(defaultDir: string);
15
+ /**
16
+ * Get the current working directory.
17
+ */
18
+ getCwd(): string;
19
+ /**
20
+ * Update the working directory. The path is resolved to absolute.
21
+ */
22
+ updateCwd(newDir: string): void;
23
+ /**
24
+ * Reset to the default directory. Called at the start of each agentic loop.
25
+ */
26
+ reset(): void;
27
+ /**
28
+ * Get the default (initial) directory.
29
+ */
30
+ getDefaultDir(): string;
31
+ }
32
+ //# sourceMappingURL=cwd-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cwd-tracker.d.ts","sourceRoot":"","sources":["../../../src/tools/shared/cwd-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,EAAE,MAAM;IAK9B;;OAEG;IACH,MAAM,IAAI,MAAM;IAIhB;;OAEG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,aAAa,IAAI,MAAM;CAGxB"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Working directory tracking across Bash calls.
3
+ *
4
+ * Each Bash tool call spawns a new shell process. Shell state
5
+ * (env vars, aliases) does NOT persist between calls. Only the
6
+ * working directory persists via this tracker.
7
+ *
8
+ * The tracker is reset to the default directory at the start
9
+ * of each agentic loop.
10
+ */
11
+ import * as path from 'node:path';
12
+ export class CwdTracker {
13
+ defaultDir;
14
+ currentDir;
15
+ constructor(defaultDir) {
16
+ this.defaultDir = path.resolve(defaultDir);
17
+ this.currentDir = this.defaultDir;
18
+ }
19
+ /**
20
+ * Get the current working directory.
21
+ */
22
+ getCwd() {
23
+ return this.currentDir;
24
+ }
25
+ /**
26
+ * Update the working directory. The path is resolved to absolute.
27
+ */
28
+ updateCwd(newDir) {
29
+ this.currentDir = path.resolve(newDir);
30
+ }
31
+ /**
32
+ * Reset to the default directory. Called at the start of each agentic loop.
33
+ */
34
+ reset() {
35
+ this.currentDir = this.defaultDir;
36
+ }
37
+ /**
38
+ * Get the default (initial) directory.
39
+ */
40
+ getDefaultDir() {
41
+ return this.defaultDir;
42
+ }
43
+ }
44
+ //# sourceMappingURL=cwd-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cwd-tracker.js","sourceRoot":"","sources":["../../../src/tools/shared/cwd-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,MAAM,OAAO,UAAU;IACJ,UAAU,CAAS;IAC5B,UAAU,CAAS;IAE3B,YAAY,UAAkB;QAC5B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC3C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACpC,CAAC;IAED;;OAEG;IACH,MAAM;QACJ,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,MAAc;QACtB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;IACpC,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;CACF"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Per-file pre-mutation snapshot stack.
3
+ *
4
+ * Both Edit and Write push a snapshot immediately AFTER each successful
5
+ * mutation. The UndoEdit tool pops the most recent snapshot to revert
6
+ * a file to its prior state, as long as the on-disk state still matches
7
+ * what we recorded when the mutation completed (so we never undo on top
8
+ * of unrelated external changes).
9
+ *
10
+ * Scoped per-agent via `CortexToolRuntime`, cleared on each loop reset
11
+ * — history does not persist across agentic loops or across agents.
12
+ *
13
+ * The stack is intentionally bounded (`MAX_STACK_DEPTH`). An unbounded
14
+ * stack would accumulate full file contents during long refactors and
15
+ * bloat memory. A deep stack is also rarely useful for the agentic
16
+ * loop: if the model wants to roll back more than a few edits, it's
17
+ * more reliable to Read the file and write the intended content
18
+ * directly.
19
+ */
20
+ export interface EditHistoryEntry {
21
+ /**
22
+ * File contents BEFORE the mutation, or `null` when the file did not
23
+ * exist before the mutation (created by Write). Undoing a `null`
24
+ * entry deletes the file.
25
+ */
26
+ originalContent: string | null;
27
+ /** mtime (ms since epoch) of the file immediately AFTER the mutation. */
28
+ postMutationMtimeMs: number;
29
+ /** SHA-256 hex digest of the file bytes immediately AFTER the mutation. */
30
+ postMutationContentHash: string;
31
+ /** Which tool created the entry (for diagnostics / undo messaging). */
32
+ source: 'Edit' | 'Write';
33
+ }
34
+ /** Upper bound on snapshots retained per file. */
35
+ export declare const MAX_STACK_DEPTH = 5;
36
+ export declare class EditHistory {
37
+ private readonly stacks;
38
+ /**
39
+ * Push a snapshot for `filePath`. When the per-file stack is at its
40
+ * depth cap, the oldest entry is dropped so newer edits remain
41
+ * undoable.
42
+ */
43
+ record(filePath: string, entry: EditHistoryEntry): void;
44
+ /**
45
+ * Pop and return the most recent entry for `filePath`, or `undefined`
46
+ * when the file has no recorded history.
47
+ */
48
+ pop(filePath: string): EditHistoryEntry | undefined;
49
+ /** Current stack depth for `filePath` (0 when absent). Diagnostic use. */
50
+ depth(filePath: string): number;
51
+ /** Drop all history. Called from `CortexToolRuntime.resetForLoop`. */
52
+ clear(): void;
53
+ private normalize;
54
+ }
55
+ //# sourceMappingURL=edit-history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-history.d.ts","sourceRoot":"","sources":["../../../src/tools/shared/edit-history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,yEAAyE;IACzE,mBAAmB,EAAE,MAAM,CAAC;IAC5B,2EAA2E;IAC3E,uBAAuB,EAAE,MAAM,CAAC;IAChC,uEAAuE;IACvE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,kDAAkD;AAClD,eAAO,MAAM,eAAe,IAAI,CAAC;AAMjC,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyC;IAEhE;;;;OAIG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAWvD;;;OAGG;IACH,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IASnD,0EAA0E;IAC1E,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAI/B,sEAAsE;IACtE,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,SAAS;CAKlB"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Per-file pre-mutation snapshot stack.
3
+ *
4
+ * Both Edit and Write push a snapshot immediately AFTER each successful
5
+ * mutation. The UndoEdit tool pops the most recent snapshot to revert
6
+ * a file to its prior state, as long as the on-disk state still matches
7
+ * what we recorded when the mutation completed (so we never undo on top
8
+ * of unrelated external changes).
9
+ *
10
+ * Scoped per-agent via `CortexToolRuntime`, cleared on each loop reset
11
+ * — history does not persist across agentic loops or across agents.
12
+ *
13
+ * The stack is intentionally bounded (`MAX_STACK_DEPTH`). An unbounded
14
+ * stack would accumulate full file contents during long refactors and
15
+ * bloat memory. A deep stack is also rarely useful for the agentic
16
+ * loop: if the model wants to roll back more than a few edits, it's
17
+ * more reliable to Read the file and write the intended content
18
+ * directly.
19
+ */
20
+ import * as path from 'node:path';
21
+ /** Upper bound on snapshots retained per file. */
22
+ export const MAX_STACK_DEPTH = 5;
23
+ // ---------------------------------------------------------------------------
24
+ // Registry
25
+ // ---------------------------------------------------------------------------
26
+ export class EditHistory {
27
+ stacks = new Map();
28
+ /**
29
+ * Push a snapshot for `filePath`. When the per-file stack is at its
30
+ * depth cap, the oldest entry is dropped so newer edits remain
31
+ * undoable.
32
+ */
33
+ record(filePath, entry) {
34
+ const key = this.normalize(filePath);
35
+ const stack = this.stacks.get(key);
36
+ if (stack === undefined) {
37
+ this.stacks.set(key, [entry]);
38
+ return;
39
+ }
40
+ stack.push(entry);
41
+ while (stack.length > MAX_STACK_DEPTH)
42
+ stack.shift();
43
+ }
44
+ /**
45
+ * Pop and return the most recent entry for `filePath`, or `undefined`
46
+ * when the file has no recorded history.
47
+ */
48
+ pop(filePath) {
49
+ const key = this.normalize(filePath);
50
+ const stack = this.stacks.get(key);
51
+ if (!stack || stack.length === 0)
52
+ return undefined;
53
+ const entry = stack.pop();
54
+ if (stack.length === 0)
55
+ this.stacks.delete(key);
56
+ return entry;
57
+ }
58
+ /** Current stack depth for `filePath` (0 when absent). Diagnostic use. */
59
+ depth(filePath) {
60
+ return this.stacks.get(this.normalize(filePath))?.length ?? 0;
61
+ }
62
+ /** Drop all history. Called from `CortexToolRuntime.resetForLoop`. */
63
+ clear() {
64
+ this.stacks.clear();
65
+ }
66
+ normalize(filePath) {
67
+ // Matches the normalization used by FileMutationLock and
68
+ // ReadRegistry so keys stay consistent across the three.
69
+ return path.resolve(filePath);
70
+ }
71
+ }
72
+ //# sourceMappingURL=edit-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-history.js","sourceRoot":"","sources":["../../../src/tools/shared/edit-history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAqBlC,kDAAkD;AAClD,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AAEjC,8EAA8E;AAC9E,WAAW;AACX,8EAA8E;AAE9E,MAAM,OAAO,WAAW;IACL,MAAM,GAAG,IAAI,GAAG,EAA8B,CAAC;IAEhE;;;;OAIG;IACH,MAAM,CAAC,QAAgB,EAAE,KAAuB;QAC9C,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YAC9B,OAAO;QACT,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClB,OAAO,KAAK,CAAC,MAAM,GAAG,eAAe;YAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IACvD,CAAC;IAED;;;OAGG;IACH,GAAG,CAAC,QAAgB;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QACnD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;QAC3B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,0EAA0E;IAC1E,KAAK,CAAC,QAAgB;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC;IAChE,CAAC;IAED,sEAAsE;IACtE,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAEO,SAAS,CAAC,QAAgB;QAChC,yDAAyD;QACzD,yDAAyD;QACzD,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;CACF"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Edit matcher: resolve an Edit tool `old_string` against a file's content
3
+ * via a tiered cascade.
4
+ *
5
+ * Tiers (short-circuit on the first that yields any match):
6
+ * 1. exact — raw indexOf, caller handles multi-match based on replace_all
7
+ * 2. line-trimmed — per-line trailing-whitespace tolerance; must be unique
8
+ * 3. indentation-flexible — strips common leading indent on both sides,
9
+ * also tolerates trailing whitespace; must be unique
10
+ *
11
+ * Also exports `findNearestMatch` for "did you mean...?" error hints when
12
+ * no tier matches, and `reindentReplacement` for producing a replacement
13
+ * string that respects the haystack's indentation when tier 3 matched.
14
+ *
15
+ * This module is intentionally pure and I/O-free so the cascade can be
16
+ * exhaustively unit-tested without the filesystem.
17
+ */
18
+ export type MatchResult = {
19
+ kind: 'exact';
20
+ /** Char offset in haystack where the first match begins. */
21
+ startIndex: number;
22
+ /** Length of the matched span (equals needle.length). */
23
+ matchedLength: number;
24
+ /** Total number of exact occurrences in haystack. */
25
+ count: number;
26
+ /**
27
+ * 1-based line numbers where each match begins. Capped at the first
28
+ * 3 entries (diagnostic use only; full count is in `count`).
29
+ */
30
+ matchLines: number[];
31
+ } | {
32
+ kind: 'line-trimmed';
33
+ startIndex: number;
34
+ matchedLength: number;
35
+ } | {
36
+ kind: 'indentation-flexible';
37
+ startIndex: number;
38
+ matchedLength: number;
39
+ /** Common leading indent of the needle's non-empty lines. */
40
+ needleIndent: string;
41
+ /** Common leading indent of the matched haystack window. */
42
+ haystackIndent: string;
43
+ } | {
44
+ kind: 'ambiguous';
45
+ tier: 'line-trimmed' | 'indentation-flexible';
46
+ count: number;
47
+ /** 1-based line numbers, first 3. */
48
+ matchLines: number[];
49
+ } | {
50
+ kind: 'none';
51
+ };
52
+ /**
53
+ * Run the tiered matcher. Both arguments should already be line-ending
54
+ * normalized (CRLF -> LF) by the caller.
55
+ */
56
+ export declare function findMatch(haystack: string, needle: string): MatchResult;
57
+ /**
58
+ * Re-indent a replacement string so it fits the haystack's indentation
59
+ * when tier 3 (indentation-flexible) matched.
60
+ *
61
+ * Strips up to `needleIndent` leading whitespace from each non-empty line
62
+ * of `newString`, then prepends `haystackIndent`. Empty / whitespace-only
63
+ * lines pass through untouched.
64
+ */
65
+ export declare function reindentReplacement(newString: string, needleIndent: string, haystackIndent: string): string;
66
+ export interface NearestMatch {
67
+ /** 1-based line number of the best candidate. */
68
+ bestLine: number;
69
+ /** Similarity ratio in [0, 1]. */
70
+ bestRatio: number;
71
+ /**
72
+ * Pre-formatted multi-line snippet with line numbers and an arrow on
73
+ * the best candidate. Suitable for direct inclusion in an error message.
74
+ */
75
+ snippet: string;
76
+ }
77
+ /**
78
+ * Find the closest line in `haystack` to the first non-empty line of
79
+ * `needle`, returning a diff-style snippet with ±3 lines of context.
80
+ * Returns undefined when no reasonable candidate (ratio < 0.5) exists.
81
+ */
82
+ export declare function findNearestMatch(haystack: string, needle: string): NearestMatch | undefined;
83
+ //# sourceMappingURL=edit-matcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-matcher.d.ts","sourceRoot":"","sources":["../../../src/tools/shared/edit-matcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,MAAM,MAAM,WAAW,GACnB;IACE,IAAI,EAAE,OAAO,CAAC;IACd,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,aAAa,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,GACD;IACE,IAAI,EAAE,cAAc,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB,GACD;IACE,IAAI,EAAE,sBAAsB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,YAAY,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,cAAc,EAAE,MAAM,CAAC;CACxB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,cAAc,GAAG,sBAAsB,CAAC;IAC9C,KAAK,EAAE,MAAM,CAAC;IACd,qCAAqC;IACrC,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB,GACD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAMrB;;;GAGG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,WAAW,CAavE;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,GACrB,MAAM,CAYR;AAMD,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAOD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,YAAY,GAAG,SAAS,CAyC1B"}
@@ -0,0 +1,359 @@
1
+ /**
2
+ * Edit matcher: resolve an Edit tool `old_string` against a file's content
3
+ * via a tiered cascade.
4
+ *
5
+ * Tiers (short-circuit on the first that yields any match):
6
+ * 1. exact — raw indexOf, caller handles multi-match based on replace_all
7
+ * 2. line-trimmed — per-line trailing-whitespace tolerance; must be unique
8
+ * 3. indentation-flexible — strips common leading indent on both sides,
9
+ * also tolerates trailing whitespace; must be unique
10
+ *
11
+ * Also exports `findNearestMatch` for "did you mean...?" error hints when
12
+ * no tier matches, and `reindentReplacement` for producing a replacement
13
+ * string that respects the haystack's indentation when tier 3 matched.
14
+ *
15
+ * This module is intentionally pure and I/O-free so the cascade can be
16
+ * exhaustively unit-tested without the filesystem.
17
+ */
18
+ // ---------------------------------------------------------------------------
19
+ // Public API
20
+ // ---------------------------------------------------------------------------
21
+ /**
22
+ * Run the tiered matcher. Both arguments should already be line-ending
23
+ * normalized (CRLF -> LF) by the caller.
24
+ */
25
+ export function findMatch(haystack, needle) {
26
+ // Note: we intentionally do NOT bail on needle.length > haystack.length.
27
+ // Tier 3 tolerates over-indented needles, so a longer-than-haystack needle
28
+ // can still produce a valid match after common-indent stripping.
29
+ if (needle.length === 0)
30
+ return { kind: 'none' };
31
+ const exact = findExact(haystack, needle);
32
+ if (exact.kind === 'exact')
33
+ return exact;
34
+ const trimmed = findLineTrimmed(haystack, needle);
35
+ if (trimmed.kind !== 'none')
36
+ return trimmed;
37
+ return findIndentationFlexible(haystack, needle);
38
+ }
39
+ /**
40
+ * Re-indent a replacement string so it fits the haystack's indentation
41
+ * when tier 3 (indentation-flexible) matched.
42
+ *
43
+ * Strips up to `needleIndent` leading whitespace from each non-empty line
44
+ * of `newString`, then prepends `haystackIndent`. Empty / whitespace-only
45
+ * lines pass through untouched.
46
+ */
47
+ export function reindentReplacement(newString, needleIndent, haystackIndent) {
48
+ if (needleIndent === haystackIndent)
49
+ return newString;
50
+ return newString
51
+ .split('\n')
52
+ .map((line) => {
53
+ if (line.trim() === '')
54
+ return line;
55
+ const stripped = line.startsWith(needleIndent)
56
+ ? line.slice(needleIndent.length)
57
+ : line;
58
+ return haystackIndent + stripped;
59
+ })
60
+ .join('\n');
61
+ }
62
+ /** Hard scan limit on large files; Levenshtein is O(m*n) per line. */
63
+ const NEAREST_MATCH_SCAN_CAP = 2000;
64
+ const NEAREST_MATCH_MIN_RATIO = 0.5;
65
+ const NEAREST_MATCH_CONTEXT = 3;
66
+ /**
67
+ * Find the closest line in `haystack` to the first non-empty line of
68
+ * `needle`, returning a diff-style snippet with ±3 lines of context.
69
+ * Returns undefined when no reasonable candidate (ratio < 0.5) exists.
70
+ */
71
+ export function findNearestMatch(haystack, needle) {
72
+ const needleLines = needle.split('\n');
73
+ const firstNonEmpty = needleLines.find((line) => line.trim() !== '');
74
+ if (firstNonEmpty === undefined)
75
+ return undefined;
76
+ const haystackLines = haystack.split('\n');
77
+ const scanLimit = Math.min(haystackLines.length, NEAREST_MATCH_SCAN_CAP);
78
+ const needleTrim = firstNonEmpty.trim();
79
+ let bestIdx = -1;
80
+ let bestRatio = 0;
81
+ for (let i = 0; i < scanLimit; i++) {
82
+ const line = haystackLines[i];
83
+ const lineTrim = line.trim();
84
+ if (lineTrim === '')
85
+ continue;
86
+ const ratio = levenshteinRatio(needleTrim, lineTrim);
87
+ if (ratio > bestRatio) {
88
+ bestRatio = ratio;
89
+ bestIdx = i;
90
+ }
91
+ }
92
+ if (bestIdx === -1 || bestRatio < NEAREST_MATCH_MIN_RATIO)
93
+ return undefined;
94
+ const start = Math.max(0, bestIdx - NEAREST_MATCH_CONTEXT);
95
+ const end = Math.min(haystackLines.length - 1, bestIdx + NEAREST_MATCH_CONTEXT);
96
+ const gutterWidth = String(end + 1).length;
97
+ const rendered = [];
98
+ for (let i = start; i <= end; i++) {
99
+ const num = String(i + 1).padStart(gutterWidth);
100
+ const marker = i === bestIdx ? ' <- nearest' : '';
101
+ rendered.push(` ${num} | ${haystackLines[i]}${marker}`);
102
+ }
103
+ return {
104
+ bestLine: bestIdx + 1,
105
+ bestRatio,
106
+ snippet: rendered.join('\n'),
107
+ };
108
+ }
109
+ // ---------------------------------------------------------------------------
110
+ // Tier 1: exact
111
+ // ---------------------------------------------------------------------------
112
+ function findExact(haystack, needle) {
113
+ const uniqueLines = [];
114
+ let count = 0;
115
+ let firstStart = -1;
116
+ let pos = 0;
117
+ while (true) {
118
+ const idx = haystack.indexOf(needle, pos);
119
+ if (idx === -1)
120
+ break;
121
+ count++;
122
+ if (count === 1)
123
+ firstStart = idx;
124
+ // Keep up to 3 DISTINCT line numbers. Multiple hits on the same line
125
+ // (e.g. replace_all of a short variable) should show one line, not
126
+ // the same number repeated.
127
+ if (uniqueLines.length < 3) {
128
+ const line = charIndexToLine(haystack, idx);
129
+ if (!uniqueLines.includes(line))
130
+ uniqueLines.push(line);
131
+ }
132
+ pos = idx + needle.length;
133
+ }
134
+ if (count === 0)
135
+ return { kind: 'none' };
136
+ return {
137
+ kind: 'exact',
138
+ startIndex: firstStart,
139
+ matchedLength: needle.length,
140
+ count,
141
+ matchLines: uniqueLines,
142
+ };
143
+ }
144
+ // ---------------------------------------------------------------------------
145
+ // Tier 2: line-trimmed (tolerates per-line trailing whitespace)
146
+ // ---------------------------------------------------------------------------
147
+ function findLineTrimmed(haystack, needle) {
148
+ const needleLines = needle.split('\n');
149
+ const haystackLines = haystack.split('\n');
150
+ if (needleLines.length > haystackLines.length)
151
+ return { kind: 'none' };
152
+ const needleTrimmed = needleLines.map(trimEnd);
153
+ // Short-circuit when tier 2 would degenerate to tier 1: if trimming
154
+ // changes nothing on either side, tier 1 has already run and either
155
+ // found a match or not — re-running here would just rediscover the
156
+ // same result.
157
+ const needleEqual = arraysEqual(needleLines, needleTrimmed);
158
+ if (needleEqual && !haystackHasTrailingWhitespace(haystackLines)) {
159
+ return { kind: 'none' };
160
+ }
161
+ const windowLen = needleLines.length;
162
+ const matches = [];
163
+ for (let i = 0; i + windowLen <= haystackLines.length; i++) {
164
+ let ok = true;
165
+ for (let j = 0; j < windowLen; j++) {
166
+ if (trimEnd(haystackLines[i + j]) !== needleTrimmed[j]) {
167
+ ok = false;
168
+ break;
169
+ }
170
+ }
171
+ if (ok)
172
+ matches.push(i);
173
+ }
174
+ if (matches.length === 0)
175
+ return { kind: 'none' };
176
+ if (matches.length > 1) {
177
+ return {
178
+ kind: 'ambiguous',
179
+ tier: 'line-trimmed',
180
+ count: matches.length,
181
+ matchLines: matches.slice(0, 3).map((i) => i + 1),
182
+ };
183
+ }
184
+ const span = linesToSpan(haystackLines, matches[0], windowLen);
185
+ return {
186
+ kind: 'line-trimmed',
187
+ startIndex: span.startIndex,
188
+ matchedLength: span.matchedLength,
189
+ };
190
+ }
191
+ // ---------------------------------------------------------------------------
192
+ // Tier 3: indentation-flexible (common-indent strip + trailing trim)
193
+ // ---------------------------------------------------------------------------
194
+ function findIndentationFlexible(haystack, needle) {
195
+ const needleLines = needle.split('\n');
196
+ const haystackLines = haystack.split('\n');
197
+ if (needleLines.length > haystackLines.length)
198
+ return { kind: 'none' };
199
+ const needleIndent = commonLeadingIndent(needleLines);
200
+ const needleCanonical = needleLines.map((line) => trimEnd(stripLeading(line, needleIndent)));
201
+ // If the needle has no stripped content (e.g. entirely blank lines),
202
+ // fall out — we'd match noise.
203
+ if (needleCanonical.every((line) => line === ''))
204
+ return { kind: 'none' };
205
+ const windowLen = needleLines.length;
206
+ const matches = [];
207
+ for (let i = 0; i + windowLen <= haystackLines.length; i++) {
208
+ const window = haystackLines.slice(i, i + windowLen);
209
+ const windowIndent = commonLeadingIndent(window);
210
+ let ok = true;
211
+ for (let j = 0; j < windowLen; j++) {
212
+ const canonical = trimEnd(stripLeading(window[j], windowIndent));
213
+ if (canonical !== needleCanonical[j]) {
214
+ ok = false;
215
+ break;
216
+ }
217
+ }
218
+ if (ok)
219
+ matches.push({ startLine: i, haystackIndent: windowIndent });
220
+ }
221
+ if (matches.length === 0)
222
+ return { kind: 'none' };
223
+ if (matches.length > 1) {
224
+ return {
225
+ kind: 'ambiguous',
226
+ tier: 'indentation-flexible',
227
+ count: matches.length,
228
+ matchLines: matches.slice(0, 3).map((m) => m.startLine + 1),
229
+ };
230
+ }
231
+ const m = matches[0];
232
+ const span = linesToSpan(haystackLines, m.startLine, windowLen);
233
+ // Guard: if the indents are identical, tier 2 would have caught this
234
+ // (or tier 1 already did). Promote to 'none' so we don't mask a true
235
+ // no-match with a spurious tier 3 hit.
236
+ if (needleIndent === m.haystackIndent) {
237
+ return { kind: 'none' };
238
+ }
239
+ return {
240
+ kind: 'indentation-flexible',
241
+ startIndex: span.startIndex,
242
+ matchedLength: span.matchedLength,
243
+ needleIndent,
244
+ haystackIndent: m.haystackIndent,
245
+ };
246
+ }
247
+ // ---------------------------------------------------------------------------
248
+ // Utilities
249
+ // ---------------------------------------------------------------------------
250
+ function trimEnd(s) {
251
+ return s.replace(/[ \t]+$/u, '');
252
+ }
253
+ function stripLeading(line, indent) {
254
+ return line.startsWith(indent) ? line.slice(indent.length) : line;
255
+ }
256
+ function haystackHasTrailingWhitespace(lines) {
257
+ for (const line of lines) {
258
+ if (line.length > 0 && /[ \t]$/u.test(line))
259
+ return true;
260
+ }
261
+ return false;
262
+ }
263
+ function arraysEqual(a, b) {
264
+ if (a.length !== b.length)
265
+ return false;
266
+ for (let i = 0; i < a.length; i++) {
267
+ if (a[i] !== b[i])
268
+ return false;
269
+ }
270
+ return true;
271
+ }
272
+ /**
273
+ * Longest common leading whitespace prefix across non-empty lines.
274
+ * Lines that are empty or whitespace-only are skipped so a blank line
275
+ * inside a block doesn't collapse the shared indent to "".
276
+ */
277
+ function commonLeadingIndent(lines) {
278
+ let common;
279
+ for (const line of lines) {
280
+ if (line.trim() === '')
281
+ continue;
282
+ const m = /^[ \t]*/u.exec(line);
283
+ const leading = m ? m[0] : '';
284
+ if (common === undefined) {
285
+ common = leading;
286
+ continue;
287
+ }
288
+ let i = 0;
289
+ const max = Math.min(common.length, leading.length);
290
+ while (i < max && common[i] === leading[i])
291
+ i++;
292
+ common = common.slice(0, i);
293
+ if (common.length === 0)
294
+ return '';
295
+ }
296
+ return common ?? '';
297
+ }
298
+ /**
299
+ * Convert a (startLine, windowLen) line-index span into a (startIndex,
300
+ * matchedLength) character span in the original haystack. Assumes the
301
+ * haystack was split by '\n' — inner newlines are counted, but no
302
+ * trailing newline is included in `matchedLength`.
303
+ */
304
+ function linesToSpan(lines, startLine, windowLen) {
305
+ let startIndex = 0;
306
+ for (let i = 0; i < startLine; i++) {
307
+ startIndex += lines[i].length + 1;
308
+ }
309
+ let matchedLength = 0;
310
+ for (let i = 0; i < windowLen; i++) {
311
+ matchedLength += lines[startLine + i].length;
312
+ if (i < windowLen - 1)
313
+ matchedLength += 1;
314
+ }
315
+ return { startIndex, matchedLength };
316
+ }
317
+ /** Count 1-based line number of a character offset in haystack. */
318
+ function charIndexToLine(haystack, charIndex) {
319
+ let line = 1;
320
+ for (let i = 0; i < charIndex && i < haystack.length; i++) {
321
+ if (haystack.charCodeAt(i) === 10 /* \n */)
322
+ line++;
323
+ }
324
+ return line;
325
+ }
326
+ // ---------------------------------------------------------------------------
327
+ // Levenshtein (for findNearestMatch only)
328
+ // ---------------------------------------------------------------------------
329
+ function levenshteinRatio(a, b) {
330
+ if (a.length === 0 && b.length === 0)
331
+ return 1;
332
+ const max = Math.max(a.length, b.length);
333
+ if (max === 0)
334
+ return 1;
335
+ const dist = levenshteinDistance(a, b);
336
+ return 1 - dist / max;
337
+ }
338
+ function levenshteinDistance(a, b) {
339
+ const m = a.length;
340
+ const n = b.length;
341
+ if (m === 0)
342
+ return n;
343
+ if (n === 0)
344
+ return m;
345
+ let prev = new Array(n + 1);
346
+ let curr = new Array(n + 1);
347
+ for (let j = 0; j <= n; j++)
348
+ prev[j] = j;
349
+ for (let i = 1; i <= m; i++) {
350
+ curr[0] = i;
351
+ for (let j = 1; j <= n; j++) {
352
+ const cost = a.charCodeAt(i - 1) === b.charCodeAt(j - 1) ? 0 : 1;
353
+ curr[j] = Math.min(curr[j - 1] + 1, prev[j] + 1, prev[j - 1] + cost);
354
+ }
355
+ [prev, curr] = [curr, prev];
356
+ }
357
+ return prev[n];
358
+ }
359
+ //# sourceMappingURL=edit-matcher.js.map