@trenchwork/erosolar 1.1.16

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 (700) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +232 -0
  3. package/agents/erosolar-code.rules.json +199 -0
  4. package/dist/bin/cliMode.d.ts +8 -0
  5. package/dist/bin/cliMode.d.ts.map +1 -0
  6. package/dist/bin/cliMode.js +20 -0
  7. package/dist/bin/cliMode.js.map +1 -0
  8. package/dist/bin/deepseek.d.ts +3 -0
  9. package/dist/bin/deepseek.d.ts.map +1 -0
  10. package/dist/bin/deepseek.js +232 -0
  11. package/dist/bin/deepseek.js.map +1 -0
  12. package/dist/bin/erosolar.d.ts +7 -0
  13. package/dist/bin/erosolar.d.ts.map +1 -0
  14. package/dist/bin/erosolar.js +7 -0
  15. package/dist/bin/erosolar.js.map +1 -0
  16. package/dist/bin/selfTest.d.ts +14 -0
  17. package/dist/bin/selfTest.d.ts.map +1 -0
  18. package/dist/bin/selfTest.js +298 -0
  19. package/dist/bin/selfTest.js.map +1 -0
  20. package/dist/capabilities/baseCapability.d.ts +72 -0
  21. package/dist/capabilities/baseCapability.d.ts.map +1 -0
  22. package/dist/capabilities/baseCapability.js +183 -0
  23. package/dist/capabilities/baseCapability.js.map +1 -0
  24. package/dist/capabilities/bashCapability.d.ts +13 -0
  25. package/dist/capabilities/bashCapability.d.ts.map +1 -0
  26. package/dist/capabilities/bashCapability.js +24 -0
  27. package/dist/capabilities/bashCapability.js.map +1 -0
  28. package/dist/capabilities/editCapability.d.ts +17 -0
  29. package/dist/capabilities/editCapability.d.ts.map +1 -0
  30. package/dist/capabilities/editCapability.js +27 -0
  31. package/dist/capabilities/editCapability.js.map +1 -0
  32. package/dist/capabilities/enhancedGitCapability.d.ts +7 -0
  33. package/dist/capabilities/enhancedGitCapability.d.ts.map +1 -0
  34. package/dist/capabilities/enhancedGitCapability.js +220 -0
  35. package/dist/capabilities/enhancedGitCapability.js.map +1 -0
  36. package/dist/capabilities/filesystemCapability.d.ts +13 -0
  37. package/dist/capabilities/filesystemCapability.d.ts.map +1 -0
  38. package/dist/capabilities/filesystemCapability.js +24 -0
  39. package/dist/capabilities/filesystemCapability.js.map +1 -0
  40. package/dist/capabilities/gitHistoryCapability.d.ts +6 -0
  41. package/dist/capabilities/gitHistoryCapability.d.ts.map +1 -0
  42. package/dist/capabilities/gitHistoryCapability.js +184 -0
  43. package/dist/capabilities/gitHistoryCapability.js.map +1 -0
  44. package/dist/capabilities/hitlCapability.d.ts +18 -0
  45. package/dist/capabilities/hitlCapability.d.ts.map +1 -0
  46. package/dist/capabilities/hitlCapability.js +29 -0
  47. package/dist/capabilities/hitlCapability.js.map +1 -0
  48. package/dist/capabilities/index.d.ts +13 -0
  49. package/dist/capabilities/index.d.ts.map +1 -0
  50. package/dist/capabilities/index.js +18 -0
  51. package/dist/capabilities/index.js.map +1 -0
  52. package/dist/capabilities/kaliCapability.d.ts +14 -0
  53. package/dist/capabilities/kaliCapability.d.ts.map +1 -0
  54. package/dist/capabilities/kaliCapability.js +478 -0
  55. package/dist/capabilities/kaliCapability.js.map +1 -0
  56. package/dist/capabilities/mcpCapability.d.ts +7 -0
  57. package/dist/capabilities/mcpCapability.d.ts.map +1 -0
  58. package/dist/capabilities/mcpCapability.js +80 -0
  59. package/dist/capabilities/mcpCapability.js.map +1 -0
  60. package/dist/capabilities/memoryCapability.d.ts +10 -0
  61. package/dist/capabilities/memoryCapability.d.ts.map +1 -0
  62. package/dist/capabilities/memoryCapability.js +22 -0
  63. package/dist/capabilities/memoryCapability.js.map +1 -0
  64. package/dist/capabilities/notebookCapability.d.ts +6 -0
  65. package/dist/capabilities/notebookCapability.d.ts.map +1 -0
  66. package/dist/capabilities/notebookCapability.js +17 -0
  67. package/dist/capabilities/notebookCapability.js.map +1 -0
  68. package/dist/capabilities/searchCapability.d.ts +19 -0
  69. package/dist/capabilities/searchCapability.d.ts.map +1 -0
  70. package/dist/capabilities/searchCapability.js +29 -0
  71. package/dist/capabilities/searchCapability.js.map +1 -0
  72. package/dist/capabilities/skillCapability.d.ts +6 -0
  73. package/dist/capabilities/skillCapability.d.ts.map +1 -0
  74. package/dist/capabilities/skillCapability.js +17 -0
  75. package/dist/capabilities/skillCapability.js.map +1 -0
  76. package/dist/capabilities/todoCapability.d.ts +11 -0
  77. package/dist/capabilities/todoCapability.d.ts.map +1 -0
  78. package/dist/capabilities/todoCapability.js +22 -0
  79. package/dist/capabilities/todoCapability.js.map +1 -0
  80. package/dist/capabilities/toolManifest.d.ts +3 -0
  81. package/dist/capabilities/toolManifest.d.ts.map +1 -0
  82. package/dist/capabilities/toolManifest.js +163 -0
  83. package/dist/capabilities/toolManifest.js.map +1 -0
  84. package/dist/capabilities/toolRegistry.d.ts +25 -0
  85. package/dist/capabilities/toolRegistry.d.ts.map +1 -0
  86. package/dist/capabilities/toolRegistry.js +150 -0
  87. package/dist/capabilities/toolRegistry.js.map +1 -0
  88. package/dist/capabilities/unifiedCodingCapability.d.ts +62 -0
  89. package/dist/capabilities/unifiedCodingCapability.d.ts.map +1 -0
  90. package/dist/capabilities/unifiedCodingCapability.js +788 -0
  91. package/dist/capabilities/unifiedCodingCapability.js.map +1 -0
  92. package/dist/capabilities/webCapability.d.ts +23 -0
  93. package/dist/capabilities/webCapability.d.ts.map +1 -0
  94. package/dist/capabilities/webCapability.js +33 -0
  95. package/dist/capabilities/webCapability.js.map +1 -0
  96. package/dist/config.d.ts +25 -0
  97. package/dist/config.d.ts.map +1 -0
  98. package/dist/config.js +155 -0
  99. package/dist/config.js.map +1 -0
  100. package/dist/contracts/agent-profiles.schema.json +43 -0
  101. package/dist/contracts/agent-schemas.json +470 -0
  102. package/dist/contracts/models.schema.json +9 -0
  103. package/dist/contracts/module-schema.json +367 -0
  104. package/dist/contracts/schemas/agent-profile.schema.json +157 -0
  105. package/dist/contracts/schemas/agent-rules.schema.json +238 -0
  106. package/dist/contracts/schemas/agent-schemas.schema.json +528 -0
  107. package/dist/contracts/schemas/agent.schema.json +90 -0
  108. package/dist/contracts/schemas/tool-selection.schema.json +174 -0
  109. package/dist/contracts/tools.schema.json +42 -0
  110. package/dist/contracts/unified-schema.json +660 -0
  111. package/dist/contracts/v1/agent.d.ts +179 -0
  112. package/dist/contracts/v1/agent.d.ts.map +1 -0
  113. package/dist/contracts/v1/agent.js +8 -0
  114. package/dist/contracts/v1/agent.js.map +1 -0
  115. package/dist/contracts/v1/agentProfileManifest.d.ts +60 -0
  116. package/dist/contracts/v1/agentProfileManifest.d.ts.map +1 -0
  117. package/dist/contracts/v1/agentProfileManifest.js +9 -0
  118. package/dist/contracts/v1/agentProfileManifest.js.map +1 -0
  119. package/dist/contracts/v1/agentRules.d.ts +60 -0
  120. package/dist/contracts/v1/agentRules.d.ts.map +1 -0
  121. package/dist/contracts/v1/agentRules.js +10 -0
  122. package/dist/contracts/v1/agentRules.js.map +1 -0
  123. package/dist/contracts/v1/provider.d.ts +149 -0
  124. package/dist/contracts/v1/provider.d.ts.map +1 -0
  125. package/dist/contracts/v1/provider.js +7 -0
  126. package/dist/contracts/v1/provider.js.map +1 -0
  127. package/dist/contracts/v1/tool.d.ts +136 -0
  128. package/dist/contracts/v1/tool.d.ts.map +1 -0
  129. package/dist/contracts/v1/tool.js +7 -0
  130. package/dist/contracts/v1/tool.js.map +1 -0
  131. package/dist/contracts/v1/toolAccess.d.ts +43 -0
  132. package/dist/contracts/v1/toolAccess.d.ts.map +1 -0
  133. package/dist/contracts/v1/toolAccess.js +9 -0
  134. package/dist/contracts/v1/toolAccess.js.map +1 -0
  135. package/dist/core/agent.d.ts +320 -0
  136. package/dist/core/agent.d.ts.map +1 -0
  137. package/dist/core/agent.js +1627 -0
  138. package/dist/core/agent.js.map +1 -0
  139. package/dist/core/agentProfileManifest.d.ts +3 -0
  140. package/dist/core/agentProfileManifest.d.ts.map +1 -0
  141. package/dist/core/agentProfileManifest.js +188 -0
  142. package/dist/core/agentProfileManifest.js.map +1 -0
  143. package/dist/core/agentProfiles.d.ts +22 -0
  144. package/dist/core/agentProfiles.d.ts.map +1 -0
  145. package/dist/core/agentProfiles.js +35 -0
  146. package/dist/core/agentProfiles.js.map +1 -0
  147. package/dist/core/agentRegistry.d.ts +111 -0
  148. package/dist/core/agentRegistry.d.ts.map +1 -0
  149. package/dist/core/agentRegistry.js +229 -0
  150. package/dist/core/agentRegistry.js.map +1 -0
  151. package/dist/core/agentRulebook.d.ts +11 -0
  152. package/dist/core/agentRulebook.d.ts.map +1 -0
  153. package/dist/core/agentRulebook.js +136 -0
  154. package/dist/core/agentRulebook.js.map +1 -0
  155. package/dist/core/agentSchemaLoader.d.ts +131 -0
  156. package/dist/core/agentSchemaLoader.d.ts.map +1 -0
  157. package/dist/core/agentSchemaLoader.js +235 -0
  158. package/dist/core/agentSchemaLoader.js.map +1 -0
  159. package/dist/core/aiErrorFixer.d.ts +57 -0
  160. package/dist/core/aiErrorFixer.d.ts.map +1 -0
  161. package/dist/core/aiErrorFixer.js +214 -0
  162. package/dist/core/aiErrorFixer.js.map +1 -0
  163. package/dist/core/auth.d.ts +15 -0
  164. package/dist/core/auth.d.ts.map +1 -0
  165. package/dist/core/auth.js +291 -0
  166. package/dist/core/auth.js.map +1 -0
  167. package/dist/core/bashCommandGuidance.d.ts +16 -0
  168. package/dist/core/bashCommandGuidance.d.ts.map +1 -0
  169. package/dist/core/bashCommandGuidance.js +40 -0
  170. package/dist/core/bashCommandGuidance.js.map +1 -0
  171. package/dist/core/constants.d.ts +31 -0
  172. package/dist/core/constants.d.ts.map +1 -0
  173. package/dist/core/constants.js +62 -0
  174. package/dist/core/constants.js.map +1 -0
  175. package/dist/core/contextManager.d.ts +271 -0
  176. package/dist/core/contextManager.d.ts.map +1 -0
  177. package/dist/core/contextManager.js +1073 -0
  178. package/dist/core/contextManager.js.map +1 -0
  179. package/dist/core/contextWindow.d.ts +42 -0
  180. package/dist/core/contextWindow.d.ts.map +1 -0
  181. package/dist/core/contextWindow.js +123 -0
  182. package/dist/core/contextWindow.js.map +1 -0
  183. package/dist/core/customCommands.d.ts +19 -0
  184. package/dist/core/customCommands.d.ts.map +1 -0
  185. package/dist/core/customCommands.js +85 -0
  186. package/dist/core/customCommands.js.map +1 -0
  187. package/dist/core/errors/apiKeyErrors.d.ts +11 -0
  188. package/dist/core/errors/apiKeyErrors.d.ts.map +1 -0
  189. package/dist/core/errors/apiKeyErrors.js +159 -0
  190. package/dist/core/errors/apiKeyErrors.js.map +1 -0
  191. package/dist/core/errors/errorTypes.d.ts +111 -0
  192. package/dist/core/errors/errorTypes.d.ts.map +1 -0
  193. package/dist/core/errors/errorTypes.js +345 -0
  194. package/dist/core/errors/errorTypes.js.map +1 -0
  195. package/dist/core/errors/index.d.ts +50 -0
  196. package/dist/core/errors/index.d.ts.map +1 -0
  197. package/dist/core/errors/index.js +156 -0
  198. package/dist/core/errors/index.js.map +1 -0
  199. package/dist/core/errors/networkErrors.d.ts +14 -0
  200. package/dist/core/errors/networkErrors.d.ts.map +1 -0
  201. package/dist/core/errors/networkErrors.js +53 -0
  202. package/dist/core/errors/networkErrors.js.map +1 -0
  203. package/dist/core/errors/safetyValidator.d.ts +109 -0
  204. package/dist/core/errors/safetyValidator.d.ts.map +1 -0
  205. package/dist/core/errors/safetyValidator.js +271 -0
  206. package/dist/core/errors/safetyValidator.js.map +1 -0
  207. package/dist/core/errors.d.ts +4 -0
  208. package/dist/core/errors.d.ts.map +1 -0
  209. package/dist/core/errors.js +33 -0
  210. package/dist/core/errors.js.map +1 -0
  211. package/dist/core/finalResponseFormatter.d.ts +10 -0
  212. package/dist/core/finalResponseFormatter.d.ts.map +1 -0
  213. package/dist/core/finalResponseFormatter.js +14 -0
  214. package/dist/core/finalResponseFormatter.js.map +1 -0
  215. package/dist/core/guardrails.d.ts +146 -0
  216. package/dist/core/guardrails.d.ts.map +1 -0
  217. package/dist/core/guardrails.js +361 -0
  218. package/dist/core/guardrails.js.map +1 -0
  219. package/dist/core/hitl.d.ts +119 -0
  220. package/dist/core/hitl.d.ts.map +1 -0
  221. package/dist/core/hitl.js +387 -0
  222. package/dist/core/hitl.js.map +1 -0
  223. package/dist/core/hooks.d.ts +95 -0
  224. package/dist/core/hooks.d.ts.map +1 -0
  225. package/dist/core/hooks.js +239 -0
  226. package/dist/core/hooks.js.map +1 -0
  227. package/dist/core/index.d.ts +7 -0
  228. package/dist/core/index.d.ts.map +1 -0
  229. package/dist/core/index.js +7 -0
  230. package/dist/core/index.js.map +1 -0
  231. package/dist/core/inputProtection.d.ts +122 -0
  232. package/dist/core/inputProtection.d.ts.map +1 -0
  233. package/dist/core/inputProtection.js +422 -0
  234. package/dist/core/inputProtection.js.map +1 -0
  235. package/dist/core/modelDiscovery.d.ts +105 -0
  236. package/dist/core/modelDiscovery.d.ts.map +1 -0
  237. package/dist/core/modelDiscovery.js +768 -0
  238. package/dist/core/modelDiscovery.js.map +1 -0
  239. package/dist/core/multilinePasteHandler.d.ts +35 -0
  240. package/dist/core/multilinePasteHandler.d.ts.map +1 -0
  241. package/dist/core/multilinePasteHandler.js +81 -0
  242. package/dist/core/multilinePasteHandler.js.map +1 -0
  243. package/dist/core/preferences.d.ts +65 -0
  244. package/dist/core/preferences.d.ts.map +1 -0
  245. package/dist/core/preferences.js +305 -0
  246. package/dist/core/preferences.js.map +1 -0
  247. package/dist/core/providerKeys.d.ts +20 -0
  248. package/dist/core/providerKeys.d.ts.map +1 -0
  249. package/dist/core/providerKeys.js +40 -0
  250. package/dist/core/providerKeys.js.map +1 -0
  251. package/dist/core/refusalDetection.d.ts +2 -0
  252. package/dist/core/refusalDetection.d.ts.map +1 -0
  253. package/dist/core/refusalDetection.js +51 -0
  254. package/dist/core/refusalDetection.js.map +1 -0
  255. package/dist/core/resultVerification.d.ts +47 -0
  256. package/dist/core/resultVerification.d.ts.map +1 -0
  257. package/dist/core/resultVerification.js +126 -0
  258. package/dist/core/resultVerification.js.map +1 -0
  259. package/dist/core/schemaValidator.d.ts +49 -0
  260. package/dist/core/schemaValidator.d.ts.map +1 -0
  261. package/dist/core/schemaValidator.js +234 -0
  262. package/dist/core/schemaValidator.js.map +1 -0
  263. package/dist/core/secretStore.d.ts +48 -0
  264. package/dist/core/secretStore.d.ts.map +1 -0
  265. package/dist/core/secretStore.js +268 -0
  266. package/dist/core/secretStore.js.map +1 -0
  267. package/dist/core/sessionStorage.d.ts +10 -0
  268. package/dist/core/sessionStorage.d.ts.map +1 -0
  269. package/dist/core/sessionStorage.js +46 -0
  270. package/dist/core/sessionStorage.js.map +1 -0
  271. package/dist/core/sessionStore.d.ts +35 -0
  272. package/dist/core/sessionStore.d.ts.map +1 -0
  273. package/dist/core/sessionStore.js +191 -0
  274. package/dist/core/sessionStore.js.map +1 -0
  275. package/dist/core/shutdown.d.ts +34 -0
  276. package/dist/core/shutdown.d.ts.map +1 -0
  277. package/dist/core/shutdown.js +186 -0
  278. package/dist/core/shutdown.js.map +1 -0
  279. package/dist/core/sudoPasswordManager.d.ts +52 -0
  280. package/dist/core/sudoPasswordManager.d.ts.map +1 -0
  281. package/dist/core/sudoPasswordManager.js +115 -0
  282. package/dist/core/sudoPasswordManager.js.map +1 -0
  283. package/dist/core/taskCompletionDetector.d.ts +117 -0
  284. package/dist/core/taskCompletionDetector.d.ts.map +1 -0
  285. package/dist/core/taskCompletionDetector.js +532 -0
  286. package/dist/core/taskCompletionDetector.js.map +1 -0
  287. package/dist/core/testFailureMonitor.d.ts +67 -0
  288. package/dist/core/testFailureMonitor.d.ts.map +1 -0
  289. package/dist/core/testFailureMonitor.js +262 -0
  290. package/dist/core/testFailureMonitor.js.map +1 -0
  291. package/dist/core/toolPreconditions.d.ts +34 -0
  292. package/dist/core/toolPreconditions.d.ts.map +1 -0
  293. package/dist/core/toolPreconditions.js +242 -0
  294. package/dist/core/toolPreconditions.js.map +1 -0
  295. package/dist/core/toolRuntime.d.ts +192 -0
  296. package/dist/core/toolRuntime.d.ts.map +1 -0
  297. package/dist/core/toolRuntime.js +460 -0
  298. package/dist/core/toolRuntime.js.map +1 -0
  299. package/dist/core/types/utilityTypes.d.ts +183 -0
  300. package/dist/core/types/utilityTypes.d.ts.map +1 -0
  301. package/dist/core/types/utilityTypes.js +273 -0
  302. package/dist/core/types/utilityTypes.js.map +1 -0
  303. package/dist/core/types.d.ts +334 -0
  304. package/dist/core/types.d.ts.map +1 -0
  305. package/dist/core/types.js +76 -0
  306. package/dist/core/types.js.map +1 -0
  307. package/dist/core/updateChecker.d.ts +148 -0
  308. package/dist/core/updateChecker.d.ts.map +1 -0
  309. package/dist/core/updateChecker.js +599 -0
  310. package/dist/core/updateChecker.js.map +1 -0
  311. package/dist/core/usageTracker.d.ts +11 -0
  312. package/dist/core/usageTracker.d.ts.map +1 -0
  313. package/dist/core/usageTracker.js +128 -0
  314. package/dist/core/usageTracker.js.map +1 -0
  315. package/dist/headless/interactiveShell.d.ts +22 -0
  316. package/dist/headless/interactiveShell.d.ts.map +1 -0
  317. package/dist/headless/interactiveShell.js +2100 -0
  318. package/dist/headless/interactiveShell.js.map +1 -0
  319. package/dist/leanAgent.d.ts +73 -0
  320. package/dist/leanAgent.d.ts.map +1 -0
  321. package/dist/leanAgent.js +177 -0
  322. package/dist/leanAgent.js.map +1 -0
  323. package/dist/plugins/index.d.ts +49 -0
  324. package/dist/plugins/index.d.ts.map +1 -0
  325. package/dist/plugins/index.js +104 -0
  326. package/dist/plugins/index.js.map +1 -0
  327. package/dist/plugins/providers/anthropic/index.d.ts +9 -0
  328. package/dist/plugins/providers/anthropic/index.d.ts.map +1 -0
  329. package/dist/plugins/providers/anthropic/index.js +48 -0
  330. package/dist/plugins/providers/anthropic/index.js.map +1 -0
  331. package/dist/plugins/providers/deepseek/index.d.ts +11 -0
  332. package/dist/plugins/providers/deepseek/index.d.ts.map +1 -0
  333. package/dist/plugins/providers/deepseek/index.js +54 -0
  334. package/dist/plugins/providers/deepseek/index.js.map +1 -0
  335. package/dist/plugins/providers/index.d.ts +2 -0
  336. package/dist/plugins/providers/index.d.ts.map +1 -0
  337. package/dist/plugins/providers/index.js +17 -0
  338. package/dist/plugins/providers/index.js.map +1 -0
  339. package/dist/plugins/providers/openai/index.d.ts +10 -0
  340. package/dist/plugins/providers/openai/index.d.ts.map +1 -0
  341. package/dist/plugins/providers/openai/index.js +47 -0
  342. package/dist/plugins/providers/openai/index.js.map +1 -0
  343. package/dist/plugins/providers/xai/index.d.ts +10 -0
  344. package/dist/plugins/providers/xai/index.d.ts.map +1 -0
  345. package/dist/plugins/providers/xai/index.js +47 -0
  346. package/dist/plugins/providers/xai/index.js.map +1 -0
  347. package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.d.ts +10 -0
  348. package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.d.ts.map +1 -0
  349. package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.js +110 -0
  350. package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.js.map +1 -0
  351. package/dist/plugins/tools/bash/localBashPlugin.d.ts +3 -0
  352. package/dist/plugins/tools/bash/localBashPlugin.d.ts.map +1 -0
  353. package/dist/plugins/tools/bash/localBashPlugin.js +14 -0
  354. package/dist/plugins/tools/bash/localBashPlugin.js.map +1 -0
  355. package/dist/plugins/tools/edit/editPlugin.d.ts +9 -0
  356. package/dist/plugins/tools/edit/editPlugin.d.ts.map +1 -0
  357. package/dist/plugins/tools/edit/editPlugin.js +15 -0
  358. package/dist/plugins/tools/edit/editPlugin.js.map +1 -0
  359. package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.d.ts +3 -0
  360. package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.d.ts.map +1 -0
  361. package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.js +9 -0
  362. package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.js.map +1 -0
  363. package/dist/plugins/tools/filesystem/localFilesystemPlugin.d.ts +3 -0
  364. package/dist/plugins/tools/filesystem/localFilesystemPlugin.d.ts.map +1 -0
  365. package/dist/plugins/tools/filesystem/localFilesystemPlugin.js +14 -0
  366. package/dist/plugins/tools/filesystem/localFilesystemPlugin.js.map +1 -0
  367. package/dist/plugins/tools/gitHistory/gitHistoryPlugin.d.ts +3 -0
  368. package/dist/plugins/tools/gitHistory/gitHistoryPlugin.d.ts.map +1 -0
  369. package/dist/plugins/tools/gitHistory/gitHistoryPlugin.js +9 -0
  370. package/dist/plugins/tools/gitHistory/gitHistoryPlugin.js.map +1 -0
  371. package/dist/plugins/tools/index.d.ts +3 -0
  372. package/dist/plugins/tools/index.d.ts.map +1 -0
  373. package/dist/plugins/tools/index.js +3 -0
  374. package/dist/plugins/tools/index.js.map +1 -0
  375. package/dist/plugins/tools/integrity/integrityPlugin.d.ts +3 -0
  376. package/dist/plugins/tools/integrity/integrityPlugin.d.ts.map +1 -0
  377. package/dist/plugins/tools/integrity/integrityPlugin.js +31 -0
  378. package/dist/plugins/tools/integrity/integrityPlugin.js.map +1 -0
  379. package/dist/plugins/tools/kali/kaliPlugin.d.ts +3 -0
  380. package/dist/plugins/tools/kali/kaliPlugin.d.ts.map +1 -0
  381. package/dist/plugins/tools/kali/kaliPlugin.js +10 -0
  382. package/dist/plugins/tools/kali/kaliPlugin.js.map +1 -0
  383. package/dist/plugins/tools/mcp/mcpClient.d.ts +49 -0
  384. package/dist/plugins/tools/mcp/mcpClient.d.ts.map +1 -0
  385. package/dist/plugins/tools/mcp/mcpClient.js +112 -0
  386. package/dist/plugins/tools/mcp/mcpClient.js.map +1 -0
  387. package/dist/plugins/tools/mcp/mcpPlugin.d.ts +3 -0
  388. package/dist/plugins/tools/mcp/mcpPlugin.d.ts.map +1 -0
  389. package/dist/plugins/tools/mcp/mcpPlugin.js +10 -0
  390. package/dist/plugins/tools/mcp/mcpPlugin.js.map +1 -0
  391. package/dist/plugins/tools/nodeDefaults.d.ts +13 -0
  392. package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -0
  393. package/dist/plugins/tools/nodeDefaults.js +37 -0
  394. package/dist/plugins/tools/nodeDefaults.js.map +1 -0
  395. package/dist/plugins/tools/orchestration/orchestrationPlugin.d.ts +3 -0
  396. package/dist/plugins/tools/orchestration/orchestrationPlugin.d.ts.map +1 -0
  397. package/dist/plugins/tools/orchestration/orchestrationPlugin.js +340 -0
  398. package/dist/plugins/tools/orchestration/orchestrationPlugin.js.map +1 -0
  399. package/dist/plugins/tools/registry.d.ts +22 -0
  400. package/dist/plugins/tools/registry.d.ts.map +1 -0
  401. package/dist/plugins/tools/registry.js +58 -0
  402. package/dist/plugins/tools/registry.js.map +1 -0
  403. package/dist/plugins/tools/search/localSearchPlugin.d.ts +3 -0
  404. package/dist/plugins/tools/search/localSearchPlugin.d.ts.map +1 -0
  405. package/dist/plugins/tools/search/localSearchPlugin.js +14 -0
  406. package/dist/plugins/tools/search/localSearchPlugin.js.map +1 -0
  407. package/dist/plugins/tools/skills/skillPlugin.d.ts +3 -0
  408. package/dist/plugins/tools/skills/skillPlugin.d.ts.map +1 -0
  409. package/dist/plugins/tools/skills/skillPlugin.js +27 -0
  410. package/dist/plugins/tools/skills/skillPlugin.js.map +1 -0
  411. package/dist/plugins/tools/todo/todoPlugin.d.ts +3 -0
  412. package/dist/plugins/tools/todo/todoPlugin.d.ts.map +1 -0
  413. package/dist/plugins/tools/todo/todoPlugin.js +10 -0
  414. package/dist/plugins/tools/todo/todoPlugin.js.map +1 -0
  415. package/dist/providers/baseProvider.d.ts +148 -0
  416. package/dist/providers/baseProvider.d.ts.map +1 -0
  417. package/dist/providers/baseProvider.js +284 -0
  418. package/dist/providers/baseProvider.js.map +1 -0
  419. package/dist/providers/openaiChatCompletionsProvider.d.ts +64 -0
  420. package/dist/providers/openaiChatCompletionsProvider.d.ts.map +1 -0
  421. package/dist/providers/openaiChatCompletionsProvider.js +1018 -0
  422. package/dist/providers/openaiChatCompletionsProvider.js.map +1 -0
  423. package/dist/providers/providerFactory.d.ts +22 -0
  424. package/dist/providers/providerFactory.d.ts.map +1 -0
  425. package/dist/providers/providerFactory.js +25 -0
  426. package/dist/providers/providerFactory.js.map +1 -0
  427. package/dist/providers/resilientProvider.d.ts +103 -0
  428. package/dist/providers/resilientProvider.d.ts.map +1 -0
  429. package/dist/providers/resilientProvider.js +468 -0
  430. package/dist/providers/resilientProvider.js.map +1 -0
  431. package/dist/runtime/agentController.d.ts +121 -0
  432. package/dist/runtime/agentController.d.ts.map +1 -0
  433. package/dist/runtime/agentController.js +739 -0
  434. package/dist/runtime/agentController.js.map +1 -0
  435. package/dist/runtime/agentHost.d.ts +61 -0
  436. package/dist/runtime/agentHost.d.ts.map +1 -0
  437. package/dist/runtime/agentHost.js +158 -0
  438. package/dist/runtime/agentHost.js.map +1 -0
  439. package/dist/runtime/agentSession.d.ts +49 -0
  440. package/dist/runtime/agentSession.d.ts.map +1 -0
  441. package/dist/runtime/agentSession.js +218 -0
  442. package/dist/runtime/agentSession.js.map +1 -0
  443. package/dist/runtime/agentSpawningWiring.d.ts +23 -0
  444. package/dist/runtime/agentSpawningWiring.d.ts.map +1 -0
  445. package/dist/runtime/agentSpawningWiring.js +119 -0
  446. package/dist/runtime/agentSpawningWiring.js.map +1 -0
  447. package/dist/runtime/agentWorkerPool.d.ts +167 -0
  448. package/dist/runtime/agentWorkerPool.d.ts.map +1 -0
  449. package/dist/runtime/agentWorkerPool.js +435 -0
  450. package/dist/runtime/agentWorkerPool.js.map +1 -0
  451. package/dist/runtime/node.d.ts +7 -0
  452. package/dist/runtime/node.d.ts.map +1 -0
  453. package/dist/runtime/node.js +56 -0
  454. package/dist/runtime/node.js.map +1 -0
  455. package/dist/runtime/universal.d.ts +18 -0
  456. package/dist/runtime/universal.d.ts.map +1 -0
  457. package/dist/runtime/universal.js +21 -0
  458. package/dist/runtime/universal.js.map +1 -0
  459. package/dist/shell/autoExecutor.d.ts +70 -0
  460. package/dist/shell/autoExecutor.d.ts.map +1 -0
  461. package/dist/shell/autoExecutor.js +320 -0
  462. package/dist/shell/autoExecutor.js.map +1 -0
  463. package/dist/shell/commandRegistry.d.ts +122 -0
  464. package/dist/shell/commandRegistry.d.ts.map +1 -0
  465. package/dist/shell/commandRegistry.js +355 -0
  466. package/dist/shell/commandRegistry.js.map +1 -0
  467. package/dist/shell/composableMessage.d.ts +178 -0
  468. package/dist/shell/composableMessage.d.ts.map +1 -0
  469. package/dist/shell/composableMessage.js +384 -0
  470. package/dist/shell/composableMessage.js.map +1 -0
  471. package/dist/shell/liveStatus.d.ts +27 -0
  472. package/dist/shell/liveStatus.d.ts.map +1 -0
  473. package/dist/shell/liveStatus.js +53 -0
  474. package/dist/shell/liveStatus.js.map +1 -0
  475. package/dist/shell/systemPrompt.d.ts +12 -0
  476. package/dist/shell/systemPrompt.d.ts.map +1 -0
  477. package/dist/shell/systemPrompt.js +16 -0
  478. package/dist/shell/systemPrompt.js.map +1 -0
  479. package/dist/shell/vimMode.d.ts +66 -0
  480. package/dist/shell/vimMode.d.ts.map +1 -0
  481. package/dist/shell/vimMode.js +435 -0
  482. package/dist/shell/vimMode.js.map +1 -0
  483. package/dist/tools/bashTools.d.ts +11 -0
  484. package/dist/tools/bashTools.d.ts.map +1 -0
  485. package/dist/tools/bashTools.js +779 -0
  486. package/dist/tools/bashTools.js.map +1 -0
  487. package/dist/tools/diffUtils.d.ts +43 -0
  488. package/dist/tools/diffUtils.d.ts.map +1 -0
  489. package/dist/tools/diffUtils.js +607 -0
  490. package/dist/tools/diffUtils.js.map +1 -0
  491. package/dist/tools/editTools.d.ts +29 -0
  492. package/dist/tools/editTools.d.ts.map +1 -0
  493. package/dist/tools/editTools.js +792 -0
  494. package/dist/tools/editTools.js.map +1 -0
  495. package/dist/tools/fileChangeTracker.d.ts +47 -0
  496. package/dist/tools/fileChangeTracker.d.ts.map +1 -0
  497. package/dist/tools/fileChangeTracker.js +154 -0
  498. package/dist/tools/fileChangeTracker.js.map +1 -0
  499. package/dist/tools/fileReadTracker.d.ts +69 -0
  500. package/dist/tools/fileReadTracker.d.ts.map +1 -0
  501. package/dist/tools/fileReadTracker.js +213 -0
  502. package/dist/tools/fileReadTracker.js.map +1 -0
  503. package/dist/tools/fileTools.d.ts +3 -0
  504. package/dist/tools/fileTools.d.ts.map +1 -0
  505. package/dist/tools/fileTools.js +389 -0
  506. package/dist/tools/fileTools.js.map +1 -0
  507. package/dist/tools/grepTools.d.ts +3 -0
  508. package/dist/tools/grepTools.d.ts.map +1 -0
  509. package/dist/tools/grepTools.js +128 -0
  510. package/dist/tools/grepTools.js.map +1 -0
  511. package/dist/tools/heliaControl.d.ts +51 -0
  512. package/dist/tools/heliaControl.d.ts.map +1 -0
  513. package/dist/tools/heliaControl.js +93 -0
  514. package/dist/tools/heliaControl.js.map +1 -0
  515. package/dist/tools/hitlTools.d.ts +7 -0
  516. package/dist/tools/hitlTools.d.ts.map +1 -0
  517. package/dist/tools/hitlTools.js +185 -0
  518. package/dist/tools/hitlTools.js.map +1 -0
  519. package/dist/tools/localExplore.d.ts +38 -0
  520. package/dist/tools/localExplore.d.ts.map +1 -0
  521. package/dist/tools/localExplore.js +30 -0
  522. package/dist/tools/localExplore.js.map +1 -0
  523. package/dist/tools/memoryTools.d.ts +20 -0
  524. package/dist/tools/memoryTools.d.ts.map +1 -0
  525. package/dist/tools/memoryTools.js +180 -0
  526. package/dist/tools/memoryTools.js.map +1 -0
  527. package/dist/tools/notebookTools.d.ts +20 -0
  528. package/dist/tools/notebookTools.d.ts.map +1 -0
  529. package/dist/tools/notebookTools.js +140 -0
  530. package/dist/tools/notebookTools.js.map +1 -0
  531. package/dist/tools/searchTools.d.ts +12 -0
  532. package/dist/tools/searchTools.d.ts.map +1 -0
  533. package/dist/tools/searchTools.js +413 -0
  534. package/dist/tools/searchTools.js.map +1 -0
  535. package/dist/tools/skillTools.d.ts +24 -0
  536. package/dist/tools/skillTools.d.ts.map +1 -0
  537. package/dist/tools/skillTools.js +140 -0
  538. package/dist/tools/skillTools.js.map +1 -0
  539. package/dist/tools/todoTools.d.ts +24 -0
  540. package/dist/tools/todoTools.d.ts.map +1 -0
  541. package/dist/tools/todoTools.js +101 -0
  542. package/dist/tools/todoTools.js.map +1 -0
  543. package/dist/tools/webTools.d.ts +26 -0
  544. package/dist/tools/webTools.d.ts.map +1 -0
  545. package/dist/tools/webTools.js +332 -0
  546. package/dist/tools/webTools.js.map +1 -0
  547. package/dist/ui/RenderGate.d.ts +83 -0
  548. package/dist/ui/RenderGate.d.ts.map +1 -0
  549. package/dist/ui/RenderGate.js +138 -0
  550. package/dist/ui/RenderGate.js.map +1 -0
  551. package/dist/ui/animatedStatus.d.ts +140 -0
  552. package/dist/ui/animatedStatus.d.ts.map +1 -0
  553. package/dist/ui/animatedStatus.js +480 -0
  554. package/dist/ui/animatedStatus.js.map +1 -0
  555. package/dist/ui/animation/AnimationScheduler.d.ts +197 -0
  556. package/dist/ui/animation/AnimationScheduler.d.ts.map +1 -0
  557. package/dist/ui/animation/AnimationScheduler.js +440 -0
  558. package/dist/ui/animation/AnimationScheduler.js.map +1 -0
  559. package/dist/ui/codeHighlighter.d.ts +6 -0
  560. package/dist/ui/codeHighlighter.d.ts.map +1 -0
  561. package/dist/ui/codeHighlighter.js +855 -0
  562. package/dist/ui/codeHighlighter.js.map +1 -0
  563. package/dist/ui/designSystem.d.ts +26 -0
  564. package/dist/ui/designSystem.d.ts.map +1 -0
  565. package/dist/ui/designSystem.js +114 -0
  566. package/dist/ui/designSystem.js.map +1 -0
  567. package/dist/ui/errorFormatter.d.ts +64 -0
  568. package/dist/ui/errorFormatter.d.ts.map +1 -0
  569. package/dist/ui/errorFormatter.js +316 -0
  570. package/dist/ui/errorFormatter.js.map +1 -0
  571. package/dist/ui/globalWriteLock.d.ts +63 -0
  572. package/dist/ui/globalWriteLock.d.ts.map +1 -0
  573. package/dist/ui/globalWriteLock.js +173 -0
  574. package/dist/ui/globalWriteLock.js.map +1 -0
  575. package/dist/ui/index.d.ts +31 -0
  576. package/dist/ui/index.d.ts.map +1 -0
  577. package/dist/ui/index.js +49 -0
  578. package/dist/ui/index.js.map +1 -0
  579. package/dist/ui/ink/App.d.ts +39 -0
  580. package/dist/ui/ink/App.d.ts.map +1 -0
  581. package/dist/ui/ink/App.js +9 -0
  582. package/dist/ui/ink/App.js.map +1 -0
  583. package/dist/ui/ink/ChatStatic.d.ts +29 -0
  584. package/dist/ui/ink/ChatStatic.d.ts.map +1 -0
  585. package/dist/ui/ink/ChatStatic.js +14 -0
  586. package/dist/ui/ink/ChatStatic.js.map +1 -0
  587. package/dist/ui/ink/InkPromptController.d.ts +282 -0
  588. package/dist/ui/ink/InkPromptController.d.ts.map +1 -0
  589. package/dist/ui/ink/InkPromptController.js +508 -0
  590. package/dist/ui/ink/InkPromptController.js.map +1 -0
  591. package/dist/ui/ink/Prompt.d.ts +31 -0
  592. package/dist/ui/ink/Prompt.d.ts.map +1 -0
  593. package/dist/ui/ink/Prompt.js +197 -0
  594. package/dist/ui/ink/Prompt.js.map +1 -0
  595. package/dist/ui/ink/StatusLine.d.ts +25 -0
  596. package/dist/ui/ink/StatusLine.d.ts.map +1 -0
  597. package/dist/ui/ink/StatusLine.js +11 -0
  598. package/dist/ui/ink/StatusLine.js.map +1 -0
  599. package/dist/ui/ink/adapter.d.ts +58 -0
  600. package/dist/ui/ink/adapter.d.ts.map +1 -0
  601. package/dist/ui/ink/adapter.js +113 -0
  602. package/dist/ui/ink/adapter.js.map +1 -0
  603. package/dist/ui/interrupts/InterruptManager.d.ts +157 -0
  604. package/dist/ui/interrupts/InterruptManager.d.ts.map +1 -0
  605. package/dist/ui/interrupts/InterruptManager.js +501 -0
  606. package/dist/ui/interrupts/InterruptManager.js.map +1 -0
  607. package/dist/ui/layout.d.ts +27 -0
  608. package/dist/ui/layout.d.ts.map +1 -0
  609. package/dist/ui/layout.js +184 -0
  610. package/dist/ui/layout.js.map +1 -0
  611. package/dist/ui/outputMode.d.ts +58 -0
  612. package/dist/ui/outputMode.d.ts.map +1 -0
  613. package/dist/ui/outputMode.js +179 -0
  614. package/dist/ui/outputMode.js.map +1 -0
  615. package/dist/ui/overlay/OverlayManager.d.ts +105 -0
  616. package/dist/ui/overlay/OverlayManager.d.ts.map +1 -0
  617. package/dist/ui/overlay/OverlayManager.js +304 -0
  618. package/dist/ui/overlay/OverlayManager.js.map +1 -0
  619. package/dist/ui/premiumComponents.d.ts +54 -0
  620. package/dist/ui/premiumComponents.d.ts.map +1 -0
  621. package/dist/ui/premiumComponents.js +241 -0
  622. package/dist/ui/premiumComponents.js.map +1 -0
  623. package/dist/ui/richText.d.ts +13 -0
  624. package/dist/ui/richText.d.ts.map +1 -0
  625. package/dist/ui/richText.js +444 -0
  626. package/dist/ui/richText.js.map +1 -0
  627. package/dist/ui/telemetry/ResponseTracker.d.ts +22 -0
  628. package/dist/ui/telemetry/ResponseTracker.d.ts.map +1 -0
  629. package/dist/ui/telemetry/ResponseTracker.js +60 -0
  630. package/dist/ui/telemetry/ResponseTracker.js.map +1 -0
  631. package/dist/ui/telemetry/UITelemetry.d.ts +181 -0
  632. package/dist/ui/telemetry/UITelemetry.d.ts.map +1 -0
  633. package/dist/ui/telemetry/UITelemetry.js +446 -0
  634. package/dist/ui/telemetry/UITelemetry.js.map +1 -0
  635. package/dist/ui/textHighlighter.d.ts +83 -0
  636. package/dist/ui/textHighlighter.d.ts.map +1 -0
  637. package/dist/ui/textHighlighter.js +267 -0
  638. package/dist/ui/textHighlighter.js.map +1 -0
  639. package/dist/ui/theme.d.ts +351 -0
  640. package/dist/ui/theme.d.ts.map +1 -0
  641. package/dist/ui/theme.js +434 -0
  642. package/dist/ui/theme.js.map +1 -0
  643. package/dist/ui/toolDisplay.d.ts +221 -0
  644. package/dist/ui/toolDisplay.d.ts.map +1 -0
  645. package/dist/ui/toolDisplay.js +1654 -0
  646. package/dist/ui/toolDisplay.js.map +1 -0
  647. package/dist/ui/uiConstants.d.ts +253 -0
  648. package/dist/ui/uiConstants.d.ts.map +1 -0
  649. package/dist/ui/uiConstants.js +437 -0
  650. package/dist/ui/uiConstants.js.map +1 -0
  651. package/dist/utils/analytics.d.ts +2 -0
  652. package/dist/utils/analytics.d.ts.map +1 -0
  653. package/dist/utils/analytics.js +51 -0
  654. package/dist/utils/analytics.js.map +1 -0
  655. package/dist/utils/askUserPrompt.d.ts +21 -0
  656. package/dist/utils/askUserPrompt.d.ts.map +1 -0
  657. package/dist/utils/askUserPrompt.js +87 -0
  658. package/dist/utils/askUserPrompt.js.map +1 -0
  659. package/dist/utils/asyncUtils.d.ts +95 -0
  660. package/dist/utils/asyncUtils.d.ts.map +1 -0
  661. package/dist/utils/asyncUtils.js +286 -0
  662. package/dist/utils/asyncUtils.js.map +1 -0
  663. package/dist/utils/debugLogger.d.ts +6 -0
  664. package/dist/utils/debugLogger.d.ts.map +1 -0
  665. package/dist/utils/debugLogger.js +39 -0
  666. package/dist/utils/debugLogger.js.map +1 -0
  667. package/dist/utils/errorUtils.d.ts +12 -0
  668. package/dist/utils/errorUtils.d.ts.map +1 -0
  669. package/dist/utils/errorUtils.js +83 -0
  670. package/dist/utils/errorUtils.js.map +1 -0
  671. package/dist/utils/frontmatter.d.ts +10 -0
  672. package/dist/utils/frontmatter.d.ts.map +1 -0
  673. package/dist/utils/frontmatter.js +78 -0
  674. package/dist/utils/frontmatter.js.map +1 -0
  675. package/dist/utils/packageInfo.d.ts +14 -0
  676. package/dist/utils/packageInfo.d.ts.map +1 -0
  677. package/dist/utils/packageInfo.js +45 -0
  678. package/dist/utils/packageInfo.js.map +1 -0
  679. package/dist/utils/planFormatter.d.ts +34 -0
  680. package/dist/utils/planFormatter.d.ts.map +1 -0
  681. package/dist/utils/planFormatter.js +141 -0
  682. package/dist/utils/planFormatter.js.map +1 -0
  683. package/dist/utils/securityUtils.d.ts +145 -0
  684. package/dist/utils/securityUtils.d.ts.map +1 -0
  685. package/dist/utils/securityUtils.js +507 -0
  686. package/dist/utils/securityUtils.js.map +1 -0
  687. package/dist/utils/statusReporter.d.ts +6 -0
  688. package/dist/utils/statusReporter.d.ts.map +1 -0
  689. package/dist/utils/statusReporter.js +26 -0
  690. package/dist/utils/statusReporter.js.map +1 -0
  691. package/dist/workspace.d.ts +8 -0
  692. package/dist/workspace.d.ts.map +1 -0
  693. package/dist/workspace.js +135 -0
  694. package/dist/workspace.js.map +1 -0
  695. package/dist/workspace.validator.d.ts +49 -0
  696. package/dist/workspace.validator.d.ts.map +1 -0
  697. package/dist/workspace.validator.js +215 -0
  698. package/dist/workspace.validator.js.map +1 -0
  699. package/package.json +135 -0
  700. package/scripts/postinstall.cjs +58 -0
@@ -0,0 +1,792 @@
1
+ import { readFile, writeFile, stat, mkdir } from 'node:fs/promises';
2
+ import { join, relative, dirname, isAbsolute } from 'node:path';
3
+ import { buildError } from '../core/errors.js';
4
+ import { buildDiffSegmentsFast, formatDiffLines, buildDiffWithContext, formatDiffClaudeStyle } from './diffUtils.js';
5
+ import { logDebug } from '../utils/debugLogger.js';
6
+ import { validateReadForEditEx, recordFileRead } from './fileReadTracker.js';
7
+ import { recordFileChange } from './fileChangeTracker.js';
8
+ /**
9
+ * Track edit attempts per file to detect when edits keep being reverted (e.g., by linters/hooks)
10
+ */
11
+ const fileEditAttempts = new Map();
12
+ const MAX_EDIT_ATTEMPTS_PER_FILE = 3;
13
+ const EDIT_ATTEMPT_RESET_MS = 60000; // Reset counter after 1 minute of no edits
14
+ /**
15
+ * Creates the Edit tool for surgical file modifications using exact string replacement.
16
+ *
17
+ * This tool performs string-based edits without requiring full file rewrites,
18
+ * making it ideal for targeted changes while preserving exact formatting and indentation.
19
+ *
20
+ * Features:
21
+ * - Exact string matching (preserves indentation)
22
+ * - Replace all occurrences or enforce uniqueness
23
+ * - Unified diff preview
24
+ * - Validation before writing
25
+ *
26
+ * @param workingDir - The working directory for resolving relative paths
27
+ * @returns Array containing the Edit tool definition
28
+ */
29
+ export function createEditTools(workingDir) {
30
+ return [
31
+ {
32
+ name: 'Edit',
33
+ description: 'Performs exact string replacements in files. CRITICAL: For existing files, you MUST use the Read tool FIRST to get the exact text including whitespace and indentation, then copy it into old_string. The edit will FAIL if old_string is not unique unless replace_all is true. To CREATE a new file, use empty old_string (no prior read needed). To DELETE text, use empty new_string. For multiple edits to the SAME file, prefer MultiEdit.',
34
+ parameters: {
35
+ type: 'object',
36
+ properties: {
37
+ file_path: {
38
+ type: 'string',
39
+ description: 'The absolute path to the file to modify or create',
40
+ },
41
+ old_string: {
42
+ type: 'string',
43
+ description: 'The exact text to replace (must match precisely including whitespace and indentation). For existing files, use read_file FIRST, then copy the exact text from its output (excluding line numbers). Use empty string "" to create a new file without needing a prior read.',
44
+ },
45
+ new_string: {
46
+ type: 'string',
47
+ default: '',
48
+ description: 'The text to replace it with. Use empty string "" to delete the old_string. For new files, this is the full content. Defaults to "" when omitted.',
49
+ },
50
+ replace_all: {
51
+ type: 'boolean',
52
+ description: 'Replace all occurrences of old_string (default false). When false, the edit fails if old_string appears multiple times.',
53
+ },
54
+ },
55
+ required: ['file_path', 'old_string'],
56
+ additionalProperties: false,
57
+ },
58
+ handler: async (args) => performSurgicalEdit(workingDir, args),
59
+ },
60
+ {
61
+ name: 'MultiEdit',
62
+ description: 'Apply MULTIPLE exact string edits to a single file in one atomic operation. Edits are applied IN ORDER (each subsequent edit sees the results of the previous one). If ANY edit fails (old_string not found / not unique), the WHOLE batch is rolled back — the file is left untouched. Use this when you need to make several related changes to one file: it\'s faster than N separate Edit calls and prevents the file ending up in a half-edited state.',
63
+ parameters: {
64
+ type: 'object',
65
+ properties: {
66
+ file_path: { type: 'string', description: 'The absolute path to the file to modify.' },
67
+ edits: {
68
+ type: 'array',
69
+ description: 'List of edits to apply in order. Each edit\'s old_string must match the file content AT THAT POINT (after preceding edits have been applied).',
70
+ items: {
71
+ type: 'object',
72
+ properties: {
73
+ old_string: { type: 'string', description: 'Exact text to replace (must match including whitespace).' },
74
+ new_string: { type: 'string', description: 'Replacement text.' },
75
+ replace_all: { type: 'boolean', description: 'Replace every occurrence of old_string in this edit (default false).' },
76
+ },
77
+ required: ['old_string', 'new_string'],
78
+ },
79
+ },
80
+ },
81
+ required: ['file_path', 'edits'],
82
+ additionalProperties: false,
83
+ },
84
+ handler: async (args) => performMultiEdit(workingDir, args),
85
+ },
86
+ ];
87
+ }
88
+ /**
89
+ * Apply N edits to one file atomically. The strategy is to delegate
90
+ * each edit to performSurgicalEdit, but we capture the file's
91
+ * original content at the start so we can restore it if any edit
92
+ * fails. This is simpler than re-implementing all of performSurgicalEdit's
93
+ * matching logic (whitespace tolerance, escaped-literal handling,
94
+ * read-before-edit enforcement) — which would otherwise be ~150
95
+ * lines of duplicated code.
96
+ */
97
+ async function performMultiEdit(workingDir, args) {
98
+ const pathArg = args['file_path'];
99
+ const edits = args['edits'];
100
+ if (typeof pathArg !== 'string' || !pathArg.trim()) {
101
+ return 'Error: file_path must be a non-empty string.';
102
+ }
103
+ if (!Array.isArray(edits) || edits.length === 0) {
104
+ return 'Error: edits must be a non-empty array.';
105
+ }
106
+ if (edits.length > 50) {
107
+ return 'Error: max 50 edits per MultiEdit call.';
108
+ }
109
+ // Validate each edit shape upfront before touching the file.
110
+ for (let i = 0; i < edits.length; i++) {
111
+ const e = edits[i];
112
+ if (!e || typeof e !== 'object') {
113
+ return `Error: edits[${i}] must be an object {old_string, new_string}.`;
114
+ }
115
+ if (typeof e['old_string'] !== 'string') {
116
+ return `Error: edits[${i}].old_string must be a string.`;
117
+ }
118
+ if (typeof e['new_string'] !== 'string') {
119
+ return `Error: edits[${i}].new_string must be a string.`;
120
+ }
121
+ }
122
+ const filePath = resolveFilePath(workingDir, pathArg);
123
+ // Snapshot the file (or note it didn't exist) so we can roll back.
124
+ let originalContent = null;
125
+ let originallyExisted = false;
126
+ try {
127
+ const { stat } = await import('node:fs/promises');
128
+ await stat(filePath);
129
+ originallyExisted = true;
130
+ const { readFile } = await import('node:fs/promises');
131
+ originalContent = await readFile(filePath, 'utf-8');
132
+ }
133
+ catch {
134
+ originallyExisted = false;
135
+ originalContent = null;
136
+ }
137
+ const applied = [];
138
+ for (let i = 0; i < edits.length; i++) {
139
+ const e = edits[i];
140
+ const result = await performSurgicalEdit(workingDir, {
141
+ file_path: pathArg,
142
+ old_string: e['old_string'],
143
+ new_string: e['new_string'],
144
+ replace_all: e['replace_all'] === true,
145
+ });
146
+ if (typeof result === 'string' && result.startsWith('Error:')) {
147
+ // Roll back. Restore the original snapshot or delete the file
148
+ // if it didn't exist at the start.
149
+ try {
150
+ const fs = await import('node:fs/promises');
151
+ if (originallyExisted && originalContent !== null) {
152
+ await fs.writeFile(filePath, originalContent, 'utf-8');
153
+ }
154
+ else {
155
+ await fs.unlink(filePath).catch(() => undefined);
156
+ }
157
+ }
158
+ catch (err) {
159
+ return `Error: edit ${i + 1}/${edits.length} failed AND rollback also failed (${err.message}). File may be in inconsistent state. Original error: ${result}`;
160
+ }
161
+ return `Error: edit ${i + 1}/${edits.length} failed — rolled back ${applied.length} prior edit(s). File restored. Failure: ${result}`;
162
+ }
163
+ applied.push(result);
164
+ }
165
+ return [
166
+ `⏺ MultiEdit(${pathArg}) — ${edits.length} edit${edits.length === 1 ? '' : 's'} applied atomically`,
167
+ ...applied.map((r, i) => `\n--- edit ${i + 1}/${edits.length} ---\n${r}`),
168
+ ].join('\n');
169
+ }
170
+ /**
171
+ * Shared edit executor used by both legacy and unified tool flows.
172
+ * Provides consistent validation, creation/deletion handling, and diff output.
173
+ */
174
+ export async function performSurgicalEdit(workingDir, args) {
175
+ const pathArg = args['file_path'];
176
+ const oldString = args['old_string'];
177
+ const newStringRaw = args['new_string'];
178
+ const replaceAll = args['replace_all'] === true;
179
+ let replacementString = typeof newStringRaw === 'string' ? newStringRaw : '';
180
+ // Validate inputs
181
+ if (typeof pathArg !== 'string' || !pathArg.trim()) {
182
+ return 'Error: file_path must be a non-empty string.';
183
+ }
184
+ if (typeof oldString !== 'string') {
185
+ return 'Error: old_string must be a string (use "" for empty).';
186
+ }
187
+ if (newStringRaw !== undefined && typeof newStringRaw !== 'string') {
188
+ return 'Error: new_string must be a string (use "" for empty).';
189
+ }
190
+ // Only error if both are identical AND non-empty (no-op edit)
191
+ // Allow: empty old + content = create, content + empty new = delete
192
+ if (oldString === replacementString && oldString !== '') {
193
+ return 'Error: old_string and new_string are identical. No changes would be made.';
194
+ }
195
+ // Both empty is also a no-op
196
+ if (oldString === '' && replacementString === '') {
197
+ return 'Error: Both old_string and new_string are empty. Provide content to create a file or text to replace.';
198
+ }
199
+ try {
200
+ const filePath = resolveFilePath(workingDir, pathArg);
201
+ // Check if file exists
202
+ let fileExists = false;
203
+ try {
204
+ await stat(filePath);
205
+ fileExists = true;
206
+ }
207
+ catch {
208
+ fileExists = false;
209
+ }
210
+ // Handle file creation mode (empty old_string)
211
+ if (oldString === '') {
212
+ if (fileExists) {
213
+ return `Error: File already exists: ${filePath}\nTo modify an existing file, provide the exact text to replace in old_string.`;
214
+ }
215
+ // Create parent directories if needed
216
+ const dir = dirname(filePath);
217
+ await mkdir(dir, { recursive: true });
218
+ // Record for revert before writing
219
+ recordFileChange(filePath);
220
+ // Write new file
221
+ await writeFile(filePath, replacementString, 'utf-8');
222
+ const relativePath = relative(workingDir, filePath);
223
+ const displayPath = relativePath && !relativePath.startsWith('..') ? relativePath : filePath;
224
+ const lineCount = replacementString.split('\n').length;
225
+ const diffSegments = buildDiffSegmentsFast('', replacementString);
226
+ const addedLines = diffSegments.filter((s) => s.type === 'added').length;
227
+ // Limit to 5 diff lines for concise output
228
+ const MAX_DIFF_LINES = 5;
229
+ const truncatedSegments = diffSegments.slice(0, MAX_DIFF_LINES);
230
+ const diffLines = formatDiffLines(truncatedSegments, true);
231
+ if (diffSegments.length > MAX_DIFF_LINES) {
232
+ diffLines.push(` ... +${diffSegments.length - MAX_DIFF_LINES} more lines`);
233
+ }
234
+ const diffBlock = diffLines.length > 0 ? diffLines.join('\n') : '(No visual diff - whitespace or formatting changes only)';
235
+ return [
236
+ `⏺ Create(${displayPath})`,
237
+ ` ⎿ Created ${displayPath} with ${addedLines} additions`,
238
+ ` ${lineCount} line${lineCount === 1 ? '' : 's'} written`,
239
+ diffBlock,
240
+ ].join('\n');
241
+ }
242
+ // For modifications, file must exist
243
+ if (!fileExists) {
244
+ return `Error: File not found: ${filePath}\nTo create a new file, use empty old_string ("").`;
245
+ }
246
+ // Check file size before reading to prevent memory issues
247
+ const stats = await stat(filePath);
248
+ if (stats.size > 1024 * 1024) { // 1MB limit
249
+ return `Error: File is too large (${Math.round(stats.size / 1024)}KB). Edit tool size limit is 1MB to prevent memory exhaustion.`;
250
+ }
251
+ // Read current content (async for speed)
252
+ let currentContent = await readFile(filePath, 'utf-8');
253
+ let autoRefreshNote = '';
254
+ // ENFORCE READ BEFORE EDIT: Check that this file was read before attempting edit
255
+ const readValidation = validateReadForEditEx(filePath, oldString, currentContent);
256
+ if (!readValidation.valid) {
257
+ // If content changed but can auto-refresh, update the read record automatically
258
+ if (readValidation.canAutoRefresh && (readValidation.issue === 'content_changed' || readValidation.issue === 'stale')) {
259
+ // Auto-refresh: re-read the file and update the tracker
260
+ currentContent = await readFile(filePath, 'utf-8');
261
+ recordFileRead(filePath, currentContent);
262
+ autoRefreshNote = readValidation.issue === 'content_changed'
263
+ ? ' [auto-refreshed: file was modified externally]'
264
+ : ' [auto-refreshed: previous read was stale]';
265
+ logDebug(`Auto-refreshed file read for ${filePath}: ${readValidation.issue}`);
266
+ }
267
+ else {
268
+ // Cannot auto-refresh (file was never read) - return the error
269
+ return readValidation.errorMessage ?? 'Error: File validation failed.';
270
+ }
271
+ }
272
+ // Normalize escaped literals and whitespace differences to reduce mismatch errors
273
+ let targetString = oldString;
274
+ let matchNote = null;
275
+ if (!currentContent.includes(targetString)) {
276
+ const unescaped = unescapeLiteral(oldString);
277
+ if (unescaped !== oldString && currentContent.includes(unescaped)) {
278
+ targetString = unescaped;
279
+ matchNote = 'normalized escaped old_string';
280
+ }
281
+ }
282
+ if (!currentContent.includes(targetString)) {
283
+ const flexibleMatch = matchWithFlexibleWhitespace(currentContent, targetString);
284
+ if (flexibleMatch) {
285
+ // Check if it was a fuzzy match (different from exact whitespace normalization)
286
+ const fuzzyResult = findBestFuzzyMatch(currentContent, targetString);
287
+ if (fuzzyResult && fuzzyResult.match === flexibleMatch && fuzzyResult.similarity < 0.99) {
288
+ matchNote = `fuzzy matched (${Math.round(fuzzyResult.similarity * 100)}% similar)`;
289
+ }
290
+ else {
291
+ matchNote = matchNote ? matchNote : 'normalized whitespace';
292
+ }
293
+ targetString = flexibleMatch;
294
+ }
295
+ }
296
+ // Check if old_string exists in file
297
+ if (!currentContent.includes(targetString)) {
298
+ // Provide helpful debugging info when match fails
299
+ const firstLine = oldString.split('\n')[0] || '';
300
+ const suggestions = findSimilarLinesWithSuggestion(currentContent, firstLine, oldString, filePath, workingDir);
301
+ // AI Flow Design: Provide structured guidance for self-correction
302
+ const aiGuidance = buildAIRecoveryGuidance(oldString, currentContent);
303
+ return [
304
+ 'Error: old_string not found in file.',
305
+ '',
306
+ `File: ${filePath}`,
307
+ `Searching for: ${JSON.stringify(firstLine.substring(0, 80))}${firstLine.length > 80 ? '...' : ''}`,
308
+ '',
309
+ suggestions.hints,
310
+ '',
311
+ suggestions.actionable ? 'RECOMMENDED ACTION:' : 'Guidance:',
312
+ suggestions.actionable ? suggestions.actionable : '- Ensure exact whitespace/indentation matches\n- Copy text directly from Read output\n- Check for tabs vs spaces',
313
+ '',
314
+ '---',
315
+ 'AI SELF-CORRECTION GUIDANCE:',
316
+ aiGuidance,
317
+ ].join('\n');
318
+ }
319
+ // Count occurrences
320
+ // Preserve indentation when we had to normalize whitespace or use fuzzy matching
321
+ if (matchNote && (matchNote.includes('whitespace') || matchNote.includes('fuzzy'))) {
322
+ const adjusted = alignIndentation(targetString, replacementString);
323
+ if (adjusted !== replacementString) {
324
+ replacementString = adjusted;
325
+ }
326
+ }
327
+ const occurrences = countOccurrences(currentContent, targetString);
328
+ if (!replaceAll && occurrences > 1) {
329
+ return `Error: old_string appears ${occurrences} times in the file. Either:\n1. Provide a larger unique string that includes more context\n2. Set replace_all: true to replace all ${occurrences} occurrences\n\nFile: ${filePath}`;
330
+ }
331
+ // Perform replacement
332
+ const newContent = replaceAll
333
+ ? currentContent.split(targetString).join(replacementString)
334
+ : currentContent.replace(targetString, replacementString);
335
+ // Generate diff with context lines (Erosolar CLI style)
336
+ const diffResult = buildDiffWithContext(currentContent, newContent, 2);
337
+ // Check for repeated edit attempts on same file (detect linter/hook reversion loops)
338
+ const now = Date.now();
339
+ const attempts = fileEditAttempts.get(filePath);
340
+ if (attempts) {
341
+ // Reset if enough time has passed
342
+ if (now - attempts.lastTimestamp > EDIT_ATTEMPT_RESET_MS) {
343
+ fileEditAttempts.set(filePath, { count: 1, lastContent: newContent, lastTimestamp: now });
344
+ }
345
+ else if (attempts.lastContent === newContent) {
346
+ // Same exact edit being attempted again - likely in a loop
347
+ attempts.count++;
348
+ attempts.lastTimestamp = now;
349
+ if (attempts.count > MAX_EDIT_ATTEMPTS_PER_FILE) {
350
+ return [
351
+ `Error: Edit loop detected on ${filePath}`,
352
+ '',
353
+ `This edit has been attempted ${attempts.count} times in quick succession.`,
354
+ 'The file may be getting reverted by a linter, formatter, or pre-commit hook.',
355
+ '',
356
+ 'To resolve:',
357
+ '1. Check for active file watchers or formatters',
358
+ '2. Disable auto-formatting temporarily',
359
+ '3. Or accept the current file state and move on',
360
+ '',
361
+ 'STOPPING to prevent infinite loop.',
362
+ ].join('\n');
363
+ }
364
+ }
365
+ else {
366
+ // Different edit - reset counter but track the new content
367
+ fileEditAttempts.set(filePath, { count: 1, lastContent: newContent, lastTimestamp: now });
368
+ }
369
+ }
370
+ else {
371
+ fileEditAttempts.set(filePath, { count: 1, lastContent: newContent, lastTimestamp: now });
372
+ }
373
+ // Record for revert before writing
374
+ recordFileChange(filePath);
375
+ // Write file (async for speed)
376
+ await writeFile(filePath, newContent, 'utf-8');
377
+ // Verify the edit persisted (detect immediate reversion by hooks/watchers)
378
+ // Small delay to allow any file watchers to trigger
379
+ await new Promise(resolve => setTimeout(resolve, 50));
380
+ const verifyContent = await readFile(filePath, 'utf-8');
381
+ if (verifyContent !== newContent) {
382
+ // File was modified after our write - likely by a linter/formatter
383
+ // Update the read tracker with the new content so subsequent edits work
384
+ recordFileRead(filePath, verifyContent);
385
+ const editAttempts = fileEditAttempts.get(filePath);
386
+ if (editAttempts) {
387
+ editAttempts.count++;
388
+ }
389
+ // Check if the core change was preserved (fuzzy check)
390
+ const coreChangePreserved = verifyContent.includes(replacementString.trim());
391
+ if (coreChangePreserved) {
392
+ // Linter only reformatted, core change is there - continue with success
393
+ logDebug(`Edit reformatted by linter but core change preserved: ${filePath}`);
394
+ // Update autoRefreshNote to indicate linter ran
395
+ autoRefreshNote = autoRefreshNote
396
+ ? `${autoRefreshNote} [reformatted by linter]`
397
+ : ' [reformatted by linter]';
398
+ }
399
+ else {
400
+ return [
401
+ `Warning: Edit was immediately modified by an external process.`,
402
+ '',
403
+ `File: ${filePath}`,
404
+ 'The edit was written but the file content changed immediately after.',
405
+ 'This is likely caused by a linter, formatter, or file watcher.',
406
+ '',
407
+ 'The current file state may differ from the intended edit.',
408
+ 'The read tracker has been updated with the current content.',
409
+ 'You can retry the edit - it should work now.',
410
+ ].join('\n');
411
+ }
412
+ }
413
+ else {
414
+ // Edit persisted exactly - update the read tracker with new content
415
+ recordFileRead(filePath, newContent);
416
+ }
417
+ // Build summary (Erosolar CLI style)
418
+ const relativePath = relative(workingDir, filePath);
419
+ const displayPath = relativePath && !relativePath.startsWith('..') ? relativePath : filePath;
420
+ const { additions, removals } = diffResult;
421
+ const occurrencesText = replaceAll ? ` (${occurrences} occurrence${occurrences > 1 ? 's' : ''})` : '';
422
+ const noteText = matchNote ? ` [${matchNote}]` : '';
423
+ const refreshText = autoRefreshNote || '';
424
+ // Format diff with colors for terminal display (Erosolar CLI style)
425
+ // Limit to 5 diff lines to keep output concise
426
+ const MAX_DIFF_LINES = 5;
427
+ const truncatedSegments = diffResult.segments.slice(0, MAX_DIFF_LINES);
428
+ const diffLines = formatDiffClaudeStyle(truncatedSegments, true);
429
+ const remainingChanges = diffResult.segments.length - MAX_DIFF_LINES;
430
+ if (remainingChanges > 0) {
431
+ diffLines.push(` ... +${remainingChanges} more changes`);
432
+ }
433
+ const diffBlock = diffLines.length > 0 ? diffLines.join('\n') : ' (No visual diff - whitespace or formatting changes only)';
434
+ // Build Erosolar CLI style output:
435
+ // ⏺ Update(filepath)
436
+ // ⎿ Updated filepath with N additions and M removals
437
+ // 41 }
438
+ // 42 + new line
439
+ const additionText = additions === 1 ? '1 addition' : `${additions} additions`;
440
+ const removalText = removals === 1 ? '1 removal' : `${removals} removals`;
441
+ const summaryParts = [];
442
+ if (additions > 0)
443
+ summaryParts.push(additionText);
444
+ if (removals > 0)
445
+ summaryParts.push(removalText);
446
+ const summaryText = summaryParts.length > 0 ? summaryParts.join(' and ') : 'no changes';
447
+ return [
448
+ `⏺ Update(${displayPath})${occurrencesText}${noteText}${refreshText}`,
449
+ ` ⎿ Updated ${displayPath} with ${summaryText}`,
450
+ diffBlock,
451
+ ].filter(Boolean).join('\n');
452
+ }
453
+ catch (error) {
454
+ return buildError('editing file', error, {
455
+ file_path: typeof pathArg === 'string' ? pathArg : '',
456
+ old_string_length: typeof oldString === 'string' ? oldString.length : 0,
457
+ new_string_length: typeof replacementString === 'string' ? replacementString.length : 0,
458
+ });
459
+ }
460
+ }
461
+ function resolveFilePath(workingDir, path) {
462
+ const normalized = path.trim();
463
+ // Cross-platform: isAbsolute handles both POSIX (/foo) and Windows
464
+ // (C:\foo, \\?\C:\foo) absolute forms. The prior `startsWith('/')`
465
+ // check failed on Windows, joining `C:\…` onto workingDir.
466
+ return isAbsolute(normalized) ? normalized : join(workingDir, normalized);
467
+ }
468
+ function countOccurrences(text, search) {
469
+ if (!search)
470
+ return 0;
471
+ let count = 0;
472
+ let position = 0;
473
+ while ((position = text.indexOf(search, position)) !== -1) {
474
+ count++;
475
+ position += search.length;
476
+ }
477
+ return count;
478
+ }
479
+ /**
480
+ * Convert common escaped sequences (\\n, \\r, \\t, \\\\) into their literal forms.
481
+ */
482
+ function unescapeLiteral(value) {
483
+ if (!value.includes('\\'))
484
+ return value;
485
+ return value
486
+ .replace(/\\\\/g, '\\')
487
+ .replace(/\\n/g, '\n')
488
+ .replace(/\\r/g, '\r')
489
+ .replace(/\\t/g, '\t');
490
+ }
491
+ /**
492
+ * Try to locate the search string allowing whitespace differences (indentation, spacing).
493
+ * Returns the exact substring from the original content when matched.
494
+ */
495
+ function matchWithFlexibleWhitespace(content, search) {
496
+ // First try regex-based flexible whitespace matching
497
+ const normalizedPattern = buildWhitespaceFlexiblePattern(search);
498
+ if (normalizedPattern) {
499
+ const regex = new RegExp(normalizedPattern, 's');
500
+ const match = content.match(regex);
501
+ if (match)
502
+ return match[0];
503
+ }
504
+ // Then try fuzzy substring matching
505
+ const fuzzyMatch = findBestFuzzyMatch(content, search);
506
+ if (fuzzyMatch && fuzzyMatch.similarity >= 0.92) {
507
+ return fuzzyMatch.match;
508
+ }
509
+ return null;
510
+ }
511
+ /**
512
+ * Find the best fuzzy match for a search string within content.
513
+ * Uses a sliding window approach with similarity scoring.
514
+ */
515
+ function findBestFuzzyMatch(content, search) {
516
+ if (!search.trim() || search.length < 5)
517
+ return null;
518
+ const searchLines = search.split('\n');
519
+ const contentLines = content.split('\n');
520
+ // For single line searches, find the most similar line
521
+ if (searchLines.length === 1) {
522
+ let bestMatch = null;
523
+ let charPosition = 0;
524
+ for (let i = 0; i < contentLines.length; i++) {
525
+ const line = contentLines[i] || '';
526
+ const similarity = calculateLineSimilarity(search, line);
527
+ if (similarity > 0.85 && (!bestMatch || similarity > bestMatch.similarity)) {
528
+ bestMatch = { match: line, similarity, position: charPosition };
529
+ }
530
+ charPosition += line.length + 1; // +1 for newline
531
+ }
532
+ return bestMatch;
533
+ }
534
+ // For multi-line searches, use window matching
535
+ const windowSize = searchLines.length;
536
+ let bestMatch = null;
537
+ let charPosition = 0;
538
+ for (let i = 0; i <= contentLines.length - windowSize; i++) {
539
+ // Optimization: Quick check first line before full block calculation
540
+ const firstLineSim = calculateLineSimilarity(searchLines[0] || '', contentLines[i] || '');
541
+ // If first line completely mismatches, unlikely to be a good block match
542
+ if (firstLineSim < 0.5) {
543
+ charPosition += (contentLines[i] || '').length + 1;
544
+ continue;
545
+ }
546
+ const windowLines = contentLines.slice(i, i + windowSize);
547
+ // Pass arrays directly to avoid joining strings repeatedly
548
+ const similarity = calculateBlockSimilarity(searchLines, windowLines);
549
+ if (similarity > 0.85 && (!bestMatch || similarity > bestMatch.similarity)) {
550
+ bestMatch = { match: windowLines.join('\n'), similarity, position: charPosition };
551
+ }
552
+ charPosition += (contentLines[i] || '').length + 1;
553
+ }
554
+ return bestMatch;
555
+ }
556
+ /**
557
+ * Calculate similarity between two lines, ignoring leading/trailing whitespace differences.
558
+ */
559
+ function calculateLineSimilarity(a, b) {
560
+ const aTrimmed = a.trim();
561
+ const bTrimmed = b.trim();
562
+ if (aTrimmed === bTrimmed)
563
+ return 1.0;
564
+ if (!aTrimmed || !bTrimmed)
565
+ return 0;
566
+ // Normalize whitespace for comparison
567
+ const aNorm = aTrimmed.replace(/\s+/g, ' ');
568
+ const bNorm = bTrimmed.replace(/\s+/g, ' ');
569
+ if (aNorm === bNorm)
570
+ return 0.98;
571
+ // Calculate Levenshtein-based similarity
572
+ return 1 - (levenshteinDistance(aNorm, bNorm) / Math.max(aNorm.length, bNorm.length));
573
+ }
574
+ /**
575
+ * Calculate similarity between two multi-line blocks (optimized).
576
+ */
577
+ function calculateBlockSimilarity(aLines, bLines) {
578
+ if (aLines.length !== bLines.length) {
579
+ // Different line counts - lower base score
580
+ const minLen = Math.min(aLines.length, bLines.length);
581
+ const maxLen = Math.max(aLines.length, bLines.length);
582
+ let totalSim = 0;
583
+ for (let i = 0; i < minLen; i++) {
584
+ totalSim += calculateLineSimilarity(aLines[i] || '', bLines[i] || '');
585
+ }
586
+ return (totalSim / maxLen) * 0.9; // Penalty for length mismatch
587
+ }
588
+ let totalSimilarity = 0;
589
+ for (let i = 0; i < aLines.length; i++) {
590
+ totalSimilarity += calculateLineSimilarity(aLines[i] || '', bLines[i] || '');
591
+ }
592
+ return totalSimilarity / aLines.length;
593
+ }
594
+ /**
595
+ * Levenshtein distance calculation for fuzzy matching.
596
+ */
597
+ function levenshteinDistance(a, b) {
598
+ if (a.length === 0)
599
+ return b.length;
600
+ if (b.length === 0)
601
+ return a.length;
602
+ // Use two-row optimization for memory efficiency
603
+ let prevRow = Array.from({ length: b.length + 1 }, (_, i) => i);
604
+ let currRow = new Array(b.length + 1);
605
+ for (let i = 1; i <= a.length; i++) {
606
+ currRow[0] = i;
607
+ for (let j = 1; j <= b.length; j++) {
608
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
609
+ currRow[j] = Math.min((prevRow[j] ?? 0) + 1, // deletion
610
+ (currRow[j - 1] ?? 0) + 1, // insertion
611
+ (prevRow[j - 1] ?? 0) + cost // substitution
612
+ );
613
+ }
614
+ [prevRow, currRow] = [currRow, prevRow];
615
+ }
616
+ return prevRow[b.length] ?? 0;
617
+ }
618
+ function buildWhitespaceFlexiblePattern(search) {
619
+ if (!search.trim()) {
620
+ return null;
621
+ }
622
+ const escaped = search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
623
+ // Make whitespace flexible per-line: strip the search line's own
624
+ // leading/trailing whitespace and replace with `[ \t]*` so the match
625
+ // succeeds regardless of how the file is indented (the most common cause
626
+ // of "old_string not found" errors — AI guessing the wrong indent).
627
+ // Internal whitespace runs also become flexible, and blank/whitespace-only
628
+ // lines collapse to `[ \t]*`. Newlines stay anchored (`\r?\n`) so the
629
+ // match still can't span structural boundaries.
630
+ const lines = escaped.split(/\\n|\n/);
631
+ const flexibleLines = lines.map(line => {
632
+ const trimmed = line.replace(/^[ \t]+/, '').replace(/[ \t]+$/, '');
633
+ if (!trimmed)
634
+ return '[ \\t]*';
635
+ const inner = trimmed.replace(/[ \t]+/g, '[ \\t]*');
636
+ return `[ \\t]*${inner}[ \\t]*`;
637
+ });
638
+ return flexibleLines.join('\\r?\\n');
639
+ }
640
+ /**
641
+ * When whitespace normalization is used, keep the replacement aligned with the matched indentation.
642
+ * If a line in the replacement has no indentation, inherit indentation from the matched line.
643
+ */
644
+ function alignIndentation(target, replacement) {
645
+ const targetLines = target.split('\n');
646
+ const replacementLines = replacement.split('\n');
647
+ if (targetLines.length !== replacementLines.length) {
648
+ return replacement;
649
+ }
650
+ const adjusted = replacementLines.map((line, idx) => {
651
+ const targetLine = targetLines[idx] ?? '';
652
+ const targetIndent = targetLine.match(/^\s*/)?.[0] ?? '';
653
+ if (!line.trim()) {
654
+ return targetIndent;
655
+ }
656
+ const lineIndent = line.match(/^\s*/)?.[0] ?? '';
657
+ if (lineIndent.length < targetIndent.length) {
658
+ const missing = targetIndent.slice(lineIndent.length);
659
+ return `${lineIndent}${missing}${line.trimStart()}`;
660
+ }
661
+ return line;
662
+ });
663
+ return adjusted.join('\n');
664
+ }
665
+ /**
666
+ * Enhanced similar line finder with actionable suggestions for AI.
667
+ * Provides exact text to use in old_string and clear next steps.
668
+ */
669
+ function findSimilarLinesWithSuggestion(content, searchFirstLine, _fullSearchText, filePath, workingDir) {
670
+ const similarInfo = findSimilarLines(content, searchFirstLine, filePath);
671
+ // Extract line numbers from similar lines
672
+ const lineMatch = similarInfo.match(/Line (\d+)/);
673
+ if (lineMatch && lineMatch[1]) {
674
+ const lineNum = parseInt(lineMatch[1], 10);
675
+ const relativePath = relative(workingDir, filePath);
676
+ const displayPath = relativePath && !relativePath.startsWith('..') ? relativePath : filePath;
677
+ // Provide concrete action: Read the file to get exact text
678
+ const action = [
679
+ `1. Use Read tool to view ${displayPath} starting at line ${Math.max(1, lineNum - 5)}`,
680
+ `2. Copy the EXACT text from the Read output (including all indentation)`,
681
+ `3. Use that exact text as old_string in your Edit call`,
682
+ `4. Ensure you copy multiple lines if needed for uniqueness`,
683
+ ].join('\n ');
684
+ return { hints: similarInfo, actionable: action };
685
+ }
686
+ // No similar lines found - suggest reading entire file
687
+ const relativePath = relative(workingDir, filePath);
688
+ const displayPath = relativePath && !relativePath.startsWith('..') ? relativePath : filePath;
689
+ const action = [
690
+ `1. Use Read tool to view the entire file: ${displayPath}`,
691
+ `2. Locate the text you want to change`,
692
+ `3. Copy the EXACT text including whitespace`,
693
+ `4. Paste it as old_string in your Edit call`,
694
+ ].join('\n ');
695
+ return { hints: similarInfo, actionable: action };
696
+ }
697
+ /**
698
+ * Find lines in the file that are similar to the search text.
699
+ * Enhanced with whitespace detection and auto-correction suggestions.
700
+ */
701
+ function findSimilarLines(content, searchFirstLine, _filePath) {
702
+ if (!searchFirstLine.trim()) {
703
+ return 'The search string starts with an empty line.';
704
+ }
705
+ const lines = content.split('\n');
706
+ const searchNormalized = searchFirstLine.trim().toLowerCase();
707
+ const matches = [];
708
+ // Find lines that contain key words from the search
709
+ const searchWords = searchNormalized.split(/\s+/).filter((w) => w.length > 2);
710
+ for (let i = 0; i < lines.length; i++) {
711
+ const line = lines[i] || '';
712
+ const lineNormalized = line.trim().toLowerCase();
713
+ // Check for exact match with different whitespace
714
+ if (lineNormalized === searchNormalized && line !== searchFirstLine) {
715
+ const hasTabs = line.includes('\t') !== searchFirstLine.includes('\t');
716
+ const leadingDiff = line.match(/^\s*/)?.[0]?.length !== searchFirstLine.match(/^\s*/)?.[0]?.length;
717
+ const issue = hasTabs ? 'tabs vs spaces' : leadingDiff ? 'different indentation' : 'whitespace difference';
718
+ matches.push({ lineNum: i + 1, line, similarity: 0.99, issue });
719
+ continue;
720
+ }
721
+ // Check for partial match (contains significant portion of the search)
722
+ if (lineNormalized.includes(searchNormalized.substring(0, 20))) {
723
+ matches.push({ lineNum: i + 1, line, similarity: 1.0 });
724
+ continue;
725
+ }
726
+ // Check for word overlap
727
+ if (searchWords.length > 0) {
728
+ const matchingWords = searchWords.filter((w) => lineNormalized.includes(w));
729
+ const similarity = matchingWords.length / searchWords.length;
730
+ if (similarity >= 0.5) {
731
+ matches.push({ lineNum: i + 1, line, similarity });
732
+ }
733
+ }
734
+ }
735
+ if (matches.length === 0) {
736
+ return 'No similar lines found. The text may not exist in this file.';
737
+ }
738
+ // Sort by similarity and take top 3
739
+ matches.sort((a, b) => b.similarity - a.similarity);
740
+ const topMatches = matches.slice(0, 3);
741
+ const suggestions = topMatches.map((m) => {
742
+ const truncated = m.line.length > 80 ? `${m.line.substring(0, 77)}...` : m.line;
743
+ const issueNote = m.issue ? ` (${m.issue})` : '';
744
+ return ` Line ${m.lineNum}${issueNote}: ${JSON.stringify(truncated)}`;
745
+ });
746
+ // Add auto-correction hint for whitespace issues
747
+ const whitespaceMatch = topMatches.find((m) => m.issue);
748
+ if (whitespaceMatch) {
749
+ return `Similar lines found (possible whitespace mismatch):\n${suggestions.join('\n')}\n\nCopy the exact text from Read output including indentation.`;
750
+ }
751
+ return `Similar lines found:\n${suggestions.join('\n')}`;
752
+ }
753
+ /**
754
+ * Build AI-specific recovery guidance based on the failure pattern.
755
+ * This function implements AI flow design principles for self-correction.
756
+ */
757
+ function buildAIRecoveryGuidance(searchText, fileContent) {
758
+ const guidance = [];
759
+ // Analyze the failure pattern
760
+ const hasMultipleLines = searchText.includes('\n');
761
+ const hasLeadingWhitespace = /^\s/.test(searchText);
762
+ const searchLen = searchText.length;
763
+ const fileLen = fileContent.length;
764
+ // PATTERN: Single line search in multi-line file
765
+ if (!hasMultipleLines && fileLen > 1000) {
766
+ guidance.push('• PATTERN DETECTED: Single-line search in large file', ' → Include 2-3 surrounding lines for uniqueness', ' → Use Read tool with specific line offset to get exact context');
767
+ }
768
+ // PATTERN: Missing leading whitespace
769
+ if (!hasLeadingWhitespace && fileContent.includes(' ')) {
770
+ guidance.push('• PATTERN DETECTED: Search text may be missing indentation', ' → File uses indentation, but old_string starts without whitespace', ' → Copy exact text from Read output including leading spaces/tabs');
771
+ }
772
+ // PATTERN: Very short search
773
+ if (searchLen < 30) {
774
+ guidance.push('• PATTERN DETECTED: Search text is very short (<30 chars)', ' → Short strings are prone to false negatives due to whitespace', ' → Include more context: function body, surrounding statements');
775
+ }
776
+ // PATTERN: Potential escape sequence issues
777
+ if (searchText.includes('\\n') || searchText.includes('\\t')) {
778
+ guidance.push('• PATTERN DETECTED: Escaped characters in search text', ' → old_string contains \\n or \\t as literal strings', ' → Use actual newlines/tabs, not escaped versions');
779
+ }
780
+ // PATTERN: Function/class definition
781
+ if (/^(function|class|def |const |let |var |export )/.test(searchText.trim())) {
782
+ guidance.push('• PATTERN DETECTED: Function/class definition search', ' → Definitions often have complex indentation', ' → Read the exact definition including all decorators/comments above');
783
+ }
784
+ // Default guidance if no specific pattern detected
785
+ if (guidance.length === 0) {
786
+ guidance.push('• GENERAL GUIDANCE:', ' 1. Use Read tool to view file around expected location', ' 2. Copy exact text from Read output (including all whitespace)', ' 3. Verify the text exists in file before Edit call', ' 4. Include more context lines if text appears multiple times');
787
+ }
788
+ // Always add the critical reminder
789
+ guidance.push('', 'CRITICAL: Always Read → Copy → Edit. Never guess file content.');
790
+ return guidance.join('\n');
791
+ }
792
+ //# sourceMappingURL=editTools.js.map