@qduc/term2 0.5.0 → 0.6.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 (714) hide show
  1. package/dist/agent.d.ts +1 -1
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +53 -7
  4. package/dist/agent.js.map +1 -1
  5. package/dist/agent.test.js +122 -10
  6. package/dist/agent.test.js.map +1 -1
  7. package/dist/app.d.ts +13 -0
  8. package/dist/app.d.ts.map +1 -1
  9. package/dist/app.js +63 -16
  10. package/dist/app.js.map +1 -1
  11. package/dist/app.startup-banner.test.js +48 -1
  12. package/dist/app.startup-banner.test.js.map +1 -1
  13. package/dist/cli.js +197 -28
  14. package/dist/cli.js.map +1 -1
  15. package/dist/components/ApprovalPrompt.d.ts.map +1 -1
  16. package/dist/components/ApprovalPrompt.js +11 -35
  17. package/dist/components/ApprovalPrompt.js.map +1 -1
  18. package/dist/components/Banner.d.ts.map +1 -1
  19. package/dist/components/Banner.js +2 -7
  20. package/dist/components/Banner.js.map +1 -1
  21. package/dist/components/BottomArea.d.ts +7 -1
  22. package/dist/components/BottomArea.d.ts.map +1 -1
  23. package/dist/components/BottomArea.js +2 -2
  24. package/dist/components/BottomArea.js.map +1 -1
  25. package/dist/components/CommandMessage.d.ts.map +1 -1
  26. package/dist/components/CommandMessage.js +38 -42
  27. package/dist/components/CommandMessage.js.map +1 -1
  28. package/dist/components/CommandMessage.test.js +69 -0
  29. package/dist/components/CommandMessage.test.js.map +1 -1
  30. package/dist/components/DiffView.d.ts +7 -0
  31. package/dist/components/DiffView.d.ts.map +1 -0
  32. package/dist/components/DiffView.js +80 -0
  33. package/dist/components/DiffView.js.map +1 -0
  34. package/dist/components/DiffView.test.d.ts +2 -0
  35. package/dist/components/DiffView.test.d.ts.map +1 -0
  36. package/dist/components/DiffView.test.js +45 -0
  37. package/dist/components/DiffView.test.js.map +1 -0
  38. package/dist/components/Input/PopupManager.d.ts +7 -0
  39. package/dist/components/Input/PopupManager.d.ts.map +1 -1
  40. package/dist/components/Input/PopupManager.js +4 -2
  41. package/dist/components/Input/PopupManager.js.map +1 -1
  42. package/dist/components/Input/determine-active-menu.d.ts.map +1 -1
  43. package/dist/components/Input/determine-active-menu.js +4 -1
  44. package/dist/components/Input/determine-active-menu.js.map +1 -1
  45. package/dist/components/Input/popup-props.d.ts +3 -1
  46. package/dist/components/Input/popup-props.d.ts.map +1 -1
  47. package/dist/components/Input/popup-props.js +7 -1
  48. package/dist/components/Input/popup-props.js.map +1 -1
  49. package/dist/components/InputBox.d.ts +6 -0
  50. package/dist/components/InputBox.d.ts.map +1 -1
  51. package/dist/components/InputBox.js +74 -11
  52. package/dist/components/InputBox.js.map +1 -1
  53. package/dist/components/InputBox.menu-logic.test.js +16 -1
  54. package/dist/components/InputBox.menu-logic.test.js.map +1 -1
  55. package/dist/components/InputBox.test.js +1 -0
  56. package/dist/components/InputBox.test.js.map +1 -1
  57. package/dist/components/MarkdownRenderer.d.ts.map +1 -1
  58. package/dist/components/MarkdownRenderer.js +52 -1
  59. package/dist/components/MarkdownRenderer.js.map +1 -1
  60. package/dist/components/MessageList.d.ts.map +1 -1
  61. package/dist/components/MessageList.js +3 -2
  62. package/dist/components/MessageList.js.map +1 -1
  63. package/dist/components/MessageList.test.js +16 -0
  64. package/dist/components/MessageList.test.js.map +1 -1
  65. package/dist/components/SettingsValueSelectionMenu.d.ts.map +1 -1
  66. package/dist/components/SettingsValueSelectionMenu.js +4 -1
  67. package/dist/components/SettingsValueSelectionMenu.js.map +1 -1
  68. package/dist/components/StatusBar.d.ts.map +1 -1
  69. package/dist/components/StatusBar.js +5 -3
  70. package/dist/components/StatusBar.js.map +1 -1
  71. package/dist/components/StatusBar.test.js +24 -0
  72. package/dist/components/StatusBar.test.js.map +1 -1
  73. package/dist/components/SubagentActivityMessage.d.ts.map +1 -1
  74. package/dist/components/SubagentActivityMessage.js +16 -1
  75. package/dist/components/SubagentActivityMessage.js.map +1 -1
  76. package/dist/components/UndoSelectionMenu.d.ts +12 -0
  77. package/dist/components/UndoSelectionMenu.d.ts.map +1 -0
  78. package/dist/components/UndoSelectionMenu.js +46 -0
  79. package/dist/components/UndoSelectionMenu.js.map +1 -0
  80. package/dist/components/UndoSelectionMenu.test.d.ts +2 -0
  81. package/dist/components/UndoSelectionMenu.test.d.ts.map +1 -0
  82. package/dist/components/UndoSelectionMenu.test.js +40 -0
  83. package/dist/components/UndoSelectionMenu.test.js.map +1 -0
  84. package/dist/components/theme.d.ts +1 -1
  85. package/dist/components/theme.d.ts.map +1 -1
  86. package/dist/components/theme.js +1 -3
  87. package/dist/components/theme.js.map +1 -1
  88. package/dist/context/InputContext.d.ts +1 -1
  89. package/dist/context/InputContext.d.ts.map +1 -1
  90. package/dist/context/InputContext.js.map +1 -1
  91. package/dist/hooks/use-app-commands.d.ts +14 -2
  92. package/dist/hooks/use-app-commands.d.ts.map +1 -1
  93. package/dist/hooks/use-app-commands.js +115 -32
  94. package/dist/hooks/use-app-commands.js.map +1 -1
  95. package/dist/hooks/use-app-commands.test.js +231 -1
  96. package/dist/hooks/use-app-commands.test.js.map +1 -1
  97. package/dist/hooks/use-conversation.d.ts +8 -1
  98. package/dist/hooks/use-conversation.d.ts.map +1 -1
  99. package/dist/hooks/use-conversation.js +79 -2
  100. package/dist/hooks/use-conversation.js.map +1 -1
  101. package/dist/hooks/use-conversation.resume.test.d.ts +2 -0
  102. package/dist/hooks/use-conversation.resume.test.d.ts.map +1 -0
  103. package/dist/hooks/use-conversation.resume.test.js +26 -0
  104. package/dist/hooks/use-conversation.resume.test.js.map +1 -0
  105. package/dist/hooks/use-escape-key.d.ts.map +1 -1
  106. package/dist/hooks/use-escape-key.js +14 -7
  107. package/dist/hooks/use-escape-key.js.map +1 -1
  108. package/dist/hooks/use-escape-key.test.js +168 -4
  109. package/dist/hooks/use-escape-key.test.js.map +1 -1
  110. package/dist/hooks/use-input-history.d.ts +4 -3
  111. package/dist/hooks/use-input-history.d.ts.map +1 -1
  112. package/dist/hooks/use-input-history.js +10 -8
  113. package/dist/hooks/use-input-history.js.map +1 -1
  114. package/dist/hooks/use-input-history.test.d.ts +2 -0
  115. package/dist/hooks/use-input-history.test.d.ts.map +1 -0
  116. package/dist/hooks/use-input-history.test.js +43 -0
  117. package/dist/hooks/use-input-history.test.js.map +1 -0
  118. package/dist/hooks/use-mode-handlers.d.ts +10 -2
  119. package/dist/hooks/use-mode-handlers.d.ts.map +1 -1
  120. package/dist/hooks/use-mode-handlers.js +21 -2
  121. package/dist/hooks/use-mode-handlers.js.map +1 -1
  122. package/dist/hooks/use-model-selection.d.ts +3 -0
  123. package/dist/hooks/use-model-selection.d.ts.map +1 -1
  124. package/dist/hooks/use-model-selection.js +3 -0
  125. package/dist/hooks/use-model-selection.js.map +1 -1
  126. package/dist/hooks/use-path-completion.test.d.ts +2 -0
  127. package/dist/hooks/use-path-completion.test.d.ts.map +1 -0
  128. package/dist/hooks/use-path-completion.test.js +54 -0
  129. package/dist/hooks/use-path-completion.test.js.map +1 -0
  130. package/dist/hooks/use-runtime-settings.d.ts.map +1 -1
  131. package/dist/hooks/use-runtime-settings.js +15 -6
  132. package/dist/hooks/use-runtime-settings.js.map +1 -1
  133. package/dist/hooks/use-settings-completion.d.ts.map +1 -1
  134. package/dist/hooks/use-settings-completion.js +0 -1
  135. package/dist/hooks/use-settings-completion.js.map +1 -1
  136. package/dist/hooks/use-settings-value-completion.d.ts +1 -0
  137. package/dist/hooks/use-settings-value-completion.d.ts.map +1 -1
  138. package/dist/hooks/use-settings-value-completion.js +25 -19
  139. package/dist/hooks/use-settings-value-completion.js.map +1 -1
  140. package/dist/hooks/use-shell-mode.d.ts.map +1 -1
  141. package/dist/hooks/use-shell-mode.js +2 -1
  142. package/dist/hooks/use-shell-mode.js.map +1 -1
  143. package/dist/hooks/use-slash-commands.d.ts +1 -0
  144. package/dist/hooks/use-slash-commands.d.ts.map +1 -1
  145. package/dist/hooks/use-slash-commands.js +10 -1
  146. package/dist/hooks/use-slash-commands.js.map +1 -1
  147. package/dist/hooks/use-undo-selection.d.ts +19 -0
  148. package/dist/hooks/use-undo-selection.d.ts.map +1 -0
  149. package/dist/hooks/use-undo-selection.js +76 -0
  150. package/dist/hooks/use-undo-selection.js.map +1 -0
  151. package/dist/lib/openai-agent-client.d.ts +2 -0
  152. package/dist/lib/openai-agent-client.d.ts.map +1 -1
  153. package/dist/lib/openai-agent-client.js +71 -5
  154. package/dist/lib/openai-agent-client.js.map +1 -1
  155. package/dist/lib/openai-agent-client.test.js +23 -0
  156. package/dist/lib/openai-agent-client.test.js.map +1 -1
  157. package/dist/non-interactive.d.ts +6 -1
  158. package/dist/non-interactive.d.ts.map +1 -1
  159. package/dist/non-interactive.js +70 -4
  160. package/dist/non-interactive.js.map +1 -1
  161. package/dist/non-interactive.test.js +176 -1
  162. package/dist/non-interactive.test.js.map +1 -1
  163. package/dist/prompts/gpt-5.md +7 -4
  164. package/dist/prompts/orchestrator.md +46 -0
  165. package/dist/prompts/plan-mode-info.md +17 -0
  166. package/dist/prompts/prompt-selector.d.ts +2 -1
  167. package/dist/prompts/prompt-selector.d.ts.map +1 -1
  168. package/dist/prompts/prompt-selector.js +5 -1
  169. package/dist/prompts/prompt-selector.js.map +1 -1
  170. package/dist/prompts/prompt-selector.test.js +7 -0
  171. package/dist/prompts/prompt-selector.test.js.map +1 -1
  172. package/dist/prompts/prompt-selector.test.ts +18 -0
  173. package/dist/prompts/prompt-selector.ts +7 -1
  174. package/dist/prompts/reasoning-efficiency.d.ts +7 -0
  175. package/dist/prompts/reasoning-efficiency.d.ts.map +1 -0
  176. package/dist/prompts/reasoning-efficiency.js +19 -0
  177. package/dist/prompts/reasoning-efficiency.js.map +1 -0
  178. package/dist/prompts/reasoning-efficiency.ts +18 -0
  179. package/dist/prompts/search-via-shell.test.js +17 -17
  180. package/dist/prompts/search-via-shell.test.js.map +1 -1
  181. package/dist/prompts/search-via-shell.test.ts +17 -17
  182. package/dist/prompts/shell-auto-approval.d.ts +3 -0
  183. package/dist/prompts/shell-auto-approval.d.ts.map +1 -0
  184. package/dist/prompts/shell-auto-approval.js +23 -0
  185. package/dist/prompts/shell-auto-approval.js.map +1 -0
  186. package/dist/prompts/shell-auto-approval.ts +23 -0
  187. package/dist/prompts/subagent-delegation.d.ts +10 -0
  188. package/dist/prompts/subagent-delegation.d.ts.map +1 -0
  189. package/dist/prompts/subagent-delegation.js +33 -0
  190. package/dist/prompts/subagent-delegation.js.map +1 -0
  191. package/dist/prompts/subagent-delegation.test.d.ts +2 -0
  192. package/dist/prompts/subagent-delegation.test.d.ts.map +1 -0
  193. package/dist/prompts/subagent-delegation.test.js +17 -0
  194. package/dist/prompts/subagent-delegation.test.js.map +1 -0
  195. package/dist/prompts/subagent-delegation.test.ts +21 -0
  196. package/dist/prompts/subagent-delegation.ts +40 -0
  197. package/dist/prompts/subagents/explorer.md +1 -2
  198. package/dist/prompts/subagents/mentor.md +0 -1
  199. package/dist/prompts/subagents/researcher.md +0 -1
  200. package/dist/prompts/subagents/worker.md +3 -4
  201. package/dist/providers/ai-sdk-anthropic.provider.d.ts +1 -0
  202. package/dist/providers/ai-sdk-anthropic.provider.d.ts.map +1 -1
  203. package/dist/providers/ai-sdk-anthropic.provider.js +67 -1
  204. package/dist/providers/ai-sdk-anthropic.provider.js.map +1 -1
  205. package/dist/providers/ai-sdk-anthropic.provider.test.d.ts +2 -0
  206. package/dist/providers/ai-sdk-anthropic.provider.test.d.ts.map +1 -0
  207. package/dist/providers/ai-sdk-anthropic.provider.test.js +87 -0
  208. package/dist/providers/ai-sdk-anthropic.provider.test.js.map +1 -0
  209. package/dist/providers/ai-sdk-openai-compatible.provider.d.ts +0 -2
  210. package/dist/providers/ai-sdk-openai-compatible.provider.d.ts.map +1 -1
  211. package/dist/providers/ai-sdk-openai-compatible.provider.js +4 -8
  212. package/dist/providers/ai-sdk-openai-compatible.provider.js.map +1 -1
  213. package/dist/providers/ai-sdk-openai-compatible.provider.test.js +1 -119
  214. package/dist/providers/ai-sdk-openai-compatible.provider.test.js.map +1 -1
  215. package/dist/providers/common/openai-compatible-messages.d.ts.map +1 -1
  216. package/dist/providers/common/openai-compatible-messages.js +10 -4
  217. package/dist/providers/common/openai-compatible-messages.js.map +1 -1
  218. package/dist/providers/common/openai-compatible-messages.test.js +22 -0
  219. package/dist/providers/common/openai-compatible-messages.test.js.map +1 -1
  220. package/dist/providers/custom-provider-adapter.test.js +39 -1
  221. package/dist/providers/custom-provider-adapter.test.js.map +1 -1
  222. package/dist/providers/openai-compatible-behavior-gate.test.js +1 -42
  223. package/dist/providers/openai-compatible-behavior-gate.test.js.map +1 -1
  224. package/dist/providers/openai-compatible.provider.d.ts +11 -1
  225. package/dist/providers/openai-compatible.provider.d.ts.map +1 -1
  226. package/dist/providers/openai-compatible.provider.js +122 -8
  227. package/dist/providers/openai-compatible.provider.js.map +1 -1
  228. package/dist/providers/openai-compatible.provider.test.js +61 -0
  229. package/dist/providers/openai-compatible.provider.test.js.map +1 -1
  230. package/dist/providers/openai.provider.test.d.ts +2 -0
  231. package/dist/providers/openai.provider.test.d.ts.map +1 -0
  232. package/dist/providers/openai.provider.test.js +22 -0
  233. package/dist/providers/openai.provider.test.js.map +1 -0
  234. package/dist/scripts/eval-auto-approval/dataset.d.ts +1 -1
  235. package/dist/services/agent-stream.d.ts +1 -0
  236. package/dist/services/agent-stream.d.ts.map +1 -1
  237. package/dist/services/approval-flow-coordinator.d.ts +2 -0
  238. package/dist/services/approval-flow-coordinator.d.ts.map +1 -1
  239. package/dist/services/approval-flow-coordinator.js +45 -18
  240. package/dist/services/approval-flow-coordinator.js.map +1 -1
  241. package/dist/services/approval-flow-coordinator.test.js +87 -0
  242. package/dist/services/approval-flow-coordinator.test.js.map +1 -1
  243. package/dist/services/approval-state.d.ts +4 -0
  244. package/dist/services/approval-state.d.ts.map +1 -1
  245. package/dist/services/approval-state.js +2 -0
  246. package/dist/services/approval-state.js.map +1 -1
  247. package/dist/services/approval-state.test.js +21 -0
  248. package/dist/services/approval-state.test.js.map +1 -1
  249. package/dist/services/conversation-persistence.d.ts +52 -0
  250. package/dist/services/conversation-persistence.d.ts.map +1 -0
  251. package/dist/services/conversation-persistence.js +163 -0
  252. package/dist/services/conversation-persistence.js.map +1 -0
  253. package/dist/services/conversation-persistence.test.d.ts +2 -0
  254. package/dist/services/conversation-persistence.test.d.ts.map +1 -0
  255. package/dist/services/conversation-persistence.test.js +418 -0
  256. package/dist/services/conversation-persistence.test.js.map +1 -0
  257. package/dist/services/conversation-result-builder.d.ts.map +1 -1
  258. package/dist/services/conversation-result-builder.js +13 -0
  259. package/dist/services/conversation-result-builder.js.map +1 -1
  260. package/dist/services/conversation-service.d.ts +22 -0
  261. package/dist/services/conversation-service.d.ts.map +1 -1
  262. package/dist/services/conversation-service.js +18 -0
  263. package/dist/services/conversation-service.js.map +1 -1
  264. package/dist/services/conversation-session.auto-approval.test.js +5 -9
  265. package/dist/services/conversation-session.auto-approval.test.js.map +1 -1
  266. package/dist/services/conversation-session.d.ts +25 -0
  267. package/dist/services/conversation-session.d.ts.map +1 -1
  268. package/dist/services/conversation-session.js +144 -10
  269. package/dist/services/conversation-session.js.map +1 -1
  270. package/dist/services/conversation-store.d.ts +42 -0
  271. package/dist/services/conversation-store.d.ts.map +1 -1
  272. package/dist/services/conversation-store.js +182 -1
  273. package/dist/services/conversation-store.js.map +1 -1
  274. package/dist/services/conversation-store.test.js +310 -1
  275. package/dist/services/conversation-store.test.js.map +1 -1
  276. package/dist/services/history-service.d.ts +6 -1
  277. package/dist/services/history-service.d.ts.map +1 -1
  278. package/dist/services/history-service.js +46 -6
  279. package/dist/services/history-service.js.map +1 -1
  280. package/dist/services/history-service.test.d.ts +2 -0
  281. package/dist/services/history-service.test.d.ts.map +1 -0
  282. package/dist/services/history-service.test.js +77 -0
  283. package/dist/services/history-service.test.js.map +1 -0
  284. package/dist/services/input-surge-guard.d.ts +37 -0
  285. package/dist/services/input-surge-guard.d.ts.map +1 -0
  286. package/dist/services/input-surge-guard.js +190 -0
  287. package/dist/services/input-surge-guard.js.map +1 -0
  288. package/dist/services/input-surge-guard.test.d.ts +2 -0
  289. package/dist/services/input-surge-guard.test.d.ts.map +1 -0
  290. package/dist/services/input-surge-guard.test.js +126 -0
  291. package/dist/services/input-surge-guard.test.js.map +1 -0
  292. package/dist/services/mode-notices.d.ts +11 -0
  293. package/dist/services/mode-notices.d.ts.map +1 -0
  294. package/dist/services/mode-notices.js +16 -0
  295. package/dist/services/mode-notices.js.map +1 -0
  296. package/dist/services/plan-mode-interceptor.d.ts +10 -0
  297. package/dist/services/plan-mode-interceptor.d.ts.map +1 -0
  298. package/dist/services/plan-mode-interceptor.js +38 -0
  299. package/dist/services/plan-mode-interceptor.js.map +1 -0
  300. package/dist/services/plan-mode-interceptor.test.d.ts +2 -0
  301. package/dist/services/plan-mode-interceptor.test.d.ts.map +1 -0
  302. package/dist/services/plan-mode-interceptor.test.js +55 -0
  303. package/dist/services/plan-mode-interceptor.test.js.map +1 -0
  304. package/dist/services/service-interfaces.d.ts +4 -1
  305. package/dist/services/service-interfaces.d.ts.map +1 -1
  306. package/dist/services/settings-persistence.js +1 -1
  307. package/dist/services/settings-schema.d.ts +107 -4
  308. package/dist/services/settings-schema.d.ts.map +1 -1
  309. package/dist/services/settings-schema.js +103 -5
  310. package/dist/services/settings-schema.js.map +1 -1
  311. package/dist/services/settings-schema.test.js +35 -1
  312. package/dist/services/settings-schema.test.js.map +1 -1
  313. package/dist/services/settings-service.d.ts +3 -1
  314. package/dist/services/settings-service.d.ts.map +1 -1
  315. package/dist/services/settings-service.js +40 -4
  316. package/dist/services/settings-service.js.map +1 -1
  317. package/dist/services/settings-sources.d.ts.map +1 -1
  318. package/dist/services/settings-sources.js +2 -1
  319. package/dist/services/settings-sources.js.map +1 -1
  320. package/dist/services/settings-sources.test.js +4 -0
  321. package/dist/services/settings-sources.test.js.map +1 -1
  322. package/dist/services/shell-auto-approval-evaluator.d.ts +2 -1
  323. package/dist/services/shell-auto-approval-evaluator.d.ts.map +1 -1
  324. package/dist/services/shell-auto-approval-evaluator.js +12 -29
  325. package/dist/services/shell-auto-approval-evaluator.js.map +1 -1
  326. package/dist/services/shell-auto-approval-evaluator.test.js +2 -4
  327. package/dist/services/shell-auto-approval-evaluator.test.js.map +1 -1
  328. package/dist/services/shell-auto-approval-resolver.test.js +1 -1
  329. package/dist/services/shell-auto-approval-resolver.test.js.map +1 -1
  330. package/dist/services/stream-event-processor.d.ts.map +1 -1
  331. package/dist/services/stream-event-processor.js +5 -0
  332. package/dist/services/stream-event-processor.js.map +1 -1
  333. package/dist/services/stream-event-processor.test.js +27 -0
  334. package/dist/services/stream-event-processor.test.js.map +1 -1
  335. package/dist/services/subagents/subagent-manager.d.ts.map +1 -1
  336. package/dist/services/subagents/subagent-manager.js +171 -31
  337. package/dist/services/subagents/subagent-manager.js.map +1 -1
  338. package/dist/services/subagents/subagent-manager.test.js +232 -42
  339. package/dist/services/subagents/subagent-manager.test.js.map +1 -1
  340. package/dist/services/subagents/types.d.ts +6 -0
  341. package/dist/services/subagents/types.d.ts.map +1 -1
  342. package/dist/services/terminal-result-collector.d.ts.map +1 -1
  343. package/dist/services/terminal-result-collector.js +1 -2
  344. package/dist/services/terminal-result-collector.js.map +1 -1
  345. package/dist/slash-commands.d.ts +1 -0
  346. package/dist/slash-commands.d.ts.map +1 -1
  347. package/dist/slash-commands.js +8 -1
  348. package/dist/slash-commands.js.map +1 -1
  349. package/dist/slash-commands.test.d.ts +2 -0
  350. package/dist/slash-commands.test.d.ts.map +1 -0
  351. package/dist/slash-commands.test.js +22 -0
  352. package/dist/slash-commands.test.js.map +1 -0
  353. package/dist/tools/apply-patch.d.ts.map +1 -1
  354. package/dist/tools/apply-patch.js +2 -6
  355. package/dist/tools/apply-patch.js.map +1 -1
  356. package/dist/tools/apply-patch.test.js +2 -13
  357. package/dist/tools/apply-patch.test.js.map +1 -1
  358. package/dist/tools/code-context.test.js +4 -3
  359. package/dist/tools/code-context.test.js.map +1 -1
  360. package/dist/tools/create-file.d.ts.map +1 -1
  361. package/dist/tools/create-file.js +2 -3
  362. package/dist/tools/create-file.js.map +1 -1
  363. package/dist/tools/create-file.test.js +3 -14
  364. package/dist/tools/create-file.test.js.map +1 -1
  365. package/dist/tools/edit-healing.d.ts +3 -3
  366. package/dist/tools/edit-healing.d.ts.map +1 -1
  367. package/dist/tools/edit-healing.js.map +1 -1
  368. package/dist/tools/edit-healing.test.js +0 -1
  369. package/dist/tools/edit-healing.test.js.map +1 -1
  370. package/dist/tools/find-files.test.js +3 -2
  371. package/dist/tools/find-files.test.js.map +1 -1
  372. package/dist/tools/grep.d.ts +1 -0
  373. package/dist/tools/grep.d.ts.map +1 -1
  374. package/dist/tools/grep.js +65 -4
  375. package/dist/tools/grep.js.map +1 -1
  376. package/dist/tools/grep.test.js +39 -0
  377. package/dist/tools/grep.test.js.map +1 -0
  378. package/dist/tools/read-file.d.ts +1 -0
  379. package/dist/tools/read-file.d.ts.map +1 -1
  380. package/dist/tools/read-file.js +7 -5
  381. package/dist/tools/read-file.js.map +1 -1
  382. package/dist/tools/read-file.test.js +3 -2
  383. package/dist/tools/read-file.test.js.map +1 -1
  384. package/dist/tools/run-subagent.d.ts +1 -1
  385. package/dist/tools/run-subagent.d.ts.map +1 -1
  386. package/dist/tools/run-subagent.js +27 -23
  387. package/dist/tools/run-subagent.js.map +1 -1
  388. package/dist/tools/run-subagent.test.js +55 -8
  389. package/dist/tools/run-subagent.test.js.map +1 -1
  390. package/dist/tools/search-replace.d.ts +13 -5
  391. package/dist/tools/search-replace.d.ts.map +1 -1
  392. package/dist/tools/search-replace.js +46 -115
  393. package/dist/tools/search-replace.js.map +1 -1
  394. package/dist/tools/search-replace.test.js +275 -240
  395. package/dist/tools/search-replace.test.js.map +1 -1
  396. package/dist/tools/shell.d.ts +1 -0
  397. package/dist/tools/shell.d.ts.map +1 -1
  398. package/dist/tools/shell.js +14 -6
  399. package/dist/tools/shell.js.map +1 -1
  400. package/dist/tools/shell.test.js +52 -0
  401. package/dist/tools/shell.test.js.map +1 -1
  402. package/dist/tools/tool-parameter-schema.test.js +13 -4
  403. package/dist/tools/tool-parameter-schema.test.js.map +1 -1
  404. package/dist/tools/types.d.ts +1 -1
  405. package/dist/tools/types.d.ts.map +1 -1
  406. package/dist/tools/web-fetch.d.ts.map +1 -1
  407. package/dist/tools/web-fetch.js +29 -4
  408. package/dist/tools/web-fetch.js.map +1 -1
  409. package/dist/tools/web-fetch.test.js +64 -0
  410. package/dist/tools/web-fetch.test.js.map +1 -1
  411. package/dist/utils/conversation-event-handler.d.ts.map +1 -1
  412. package/dist/utils/conversation-event-handler.js +4 -0
  413. package/dist/utils/conversation-event-handler.js.map +1 -1
  414. package/dist/utils/conversation-event-handler.test.js +22 -0
  415. package/dist/utils/conversation-event-handler.test.js.map +1 -1
  416. package/dist/utils/execute-shell.d.ts +2 -0
  417. package/dist/utils/execute-shell.d.ts.map +1 -1
  418. package/dist/utils/execute-shell.js +25 -1
  419. package/dist/utils/execute-shell.js.map +1 -1
  420. package/dist/utils/execute-shell.test.js +22 -0
  421. package/dist/utils/execute-shell.test.js.map +1 -1
  422. package/dist/utils/model-settings.d.ts.map +1 -1
  423. package/dist/utils/model-settings.js +18 -0
  424. package/dist/utils/model-settings.js.map +1 -1
  425. package/dist/utils/output-trim.d.ts.map +1 -1
  426. package/dist/utils/output-trim.js +14 -6
  427. package/dist/utils/output-trim.js.map +1 -1
  428. package/dist/utils/project-tree.d.ts +14 -0
  429. package/dist/utils/project-tree.d.ts.map +1 -0
  430. package/dist/utils/project-tree.js +111 -0
  431. package/dist/utils/project-tree.js.map +1 -0
  432. package/dist/utils/project-tree.test.d.ts +2 -0
  433. package/dist/utils/project-tree.test.d.ts.map +1 -0
  434. package/dist/utils/project-tree.test.js +149 -0
  435. package/dist/utils/project-tree.test.js.map +1 -0
  436. package/dist/utils/terminal-clear.d.ts +7 -0
  437. package/dist/utils/terminal-clear.d.ts.map +1 -0
  438. package/dist/utils/terminal-clear.js +5 -0
  439. package/dist/utils/terminal-clear.js.map +1 -0
  440. package/dist/utils/terminal-clear.test.d.ts +2 -0
  441. package/dist/utils/terminal-clear.test.d.ts.map +1 -0
  442. package/dist/utils/terminal-clear.test.js +13 -0
  443. package/dist/utils/terminal-clear.test.js.map +1 -0
  444. package/dist/utils/token-usage.test.js +31 -0
  445. package/dist/utils/token-usage.test.js.map +1 -1
  446. package/package.json +3 -3
  447. package/readme.md +271 -44
  448. package/dist/agent.lite-mode.test.d.ts +0 -2
  449. package/dist/agent.lite-mode.test.d.ts.map +0 -1
  450. package/dist/agent.lite-mode.test.js +0 -39
  451. package/dist/agent.lite-mode.test.js.map +0 -1
  452. package/dist/components/ApprovalPrompt.test.d.ts +0 -2
  453. package/dist/components/ApprovalPrompt.test.d.ts.map +0 -1
  454. package/dist/components/ApprovalPrompt.test.js +0 -23
  455. package/dist/components/ApprovalPrompt.test.js.map +0 -1
  456. package/dist/components/LiveResponse.test.d.ts +0 -2
  457. package/dist/components/LiveResponse.test.d.ts.map +0 -1
  458. package/dist/components/LiveResponse.test.js +0 -13
  459. package/dist/components/LiveResponse.test.js.map +0 -1
  460. package/dist/components/ModelSelectionMenu.error-tabs.test.d.ts +0 -2
  461. package/dist/components/ModelSelectionMenu.error-tabs.test.d.ts.map +0 -1
  462. package/dist/components/ModelSelectionMenu.error-tabs.test.js +0 -18
  463. package/dist/components/ModelSelectionMenu.error-tabs.test.js.map +0 -1
  464. package/dist/components/TextInput.d.ts +0 -42
  465. package/dist/components/TextInput.d.ts.map +0 -1
  466. package/dist/components/TextInput.js +0 -398
  467. package/dist/components/TextInput.js.map +0 -1
  468. package/dist/components/TextInput.test.d.ts +0 -2
  469. package/dist/components/TextInput.test.d.ts.map +0 -1
  470. package/dist/components/TextInput.test.js +0 -75
  471. package/dist/components/TextInput.test.js.map +0 -1
  472. package/dist/debug_ask_mentor.d.ts +0 -2
  473. package/dist/debug_ask_mentor.d.ts.map +0 -1
  474. package/dist/debug_ask_mentor.js +0 -73
  475. package/dist/debug_ask_mentor.js.map +0 -1
  476. package/dist/lib/shell.d.ts +0 -7
  477. package/dist/lib/shell.d.ts.map +0 -1
  478. package/dist/lib/shell.js +0 -56
  479. package/dist/lib/shell.js.map +0 -1
  480. package/dist/modes/companion/command-index.d.ts +0 -26
  481. package/dist/modes/companion/command-index.d.ts.map +0 -1
  482. package/dist/modes/companion/command-index.js +0 -50
  483. package/dist/modes/companion/command-index.js.map +0 -1
  484. package/dist/modes/companion/command-index.test.d.ts +0 -2
  485. package/dist/modes/companion/command-index.test.d.ts.map +0 -1
  486. package/dist/modes/companion/command-index.test.js +0 -86
  487. package/dist/modes/companion/command-index.test.js.map +0 -1
  488. package/dist/modes/companion/companion-app.d.ts +0 -12
  489. package/dist/modes/companion/companion-app.d.ts.map +0 -1
  490. package/dist/modes/companion/companion-app.js +0 -297
  491. package/dist/modes/companion/companion-app.js.map +0 -1
  492. package/dist/modes/companion/companion-session.d.ts +0 -63
  493. package/dist/modes/companion/companion-session.d.ts.map +0 -1
  494. package/dist/modes/companion/companion-session.js +0 -146
  495. package/dist/modes/companion/companion-session.js.map +0 -1
  496. package/dist/modes/companion/companion-session.test.d.ts +0 -2
  497. package/dist/modes/companion/companion-session.test.d.ts.map +0 -1
  498. package/dist/modes/companion/companion-session.test.js +0 -28
  499. package/dist/modes/companion/companion-session.test.js.map +0 -1
  500. package/dist/modes/companion/components/status-bar.d.ts +0 -13
  501. package/dist/modes/companion/components/status-bar.d.ts.map +0 -1
  502. package/dist/modes/companion/components/status-bar.js +0 -26
  503. package/dist/modes/companion/components/status-bar.js.map +0 -1
  504. package/dist/modes/companion/context-buffer.d.ts +0 -65
  505. package/dist/modes/companion/context-buffer.d.ts.map +0 -1
  506. package/dist/modes/companion/context-buffer.js +0 -156
  507. package/dist/modes/companion/context-buffer.js.map +0 -1
  508. package/dist/modes/companion/context-buffer.test.d.ts +0 -2
  509. package/dist/modes/companion/context-buffer.test.d.ts.map +0 -1
  510. package/dist/modes/companion/context-buffer.test.js +0 -154
  511. package/dist/modes/companion/context-buffer.test.js.map +0 -1
  512. package/dist/modes/companion/event-detector.d.ts +0 -46
  513. package/dist/modes/companion/event-detector.d.ts.map +0 -1
  514. package/dist/modes/companion/event-detector.js +0 -169
  515. package/dist/modes/companion/event-detector.js.map +0 -1
  516. package/dist/modes/companion/event-detector.test.d.ts +0 -2
  517. package/dist/modes/companion/event-detector.test.d.ts.map +0 -1
  518. package/dist/modes/companion/event-detector.test.js +0 -121
  519. package/dist/modes/companion/event-detector.test.js.map +0 -1
  520. package/dist/modes/companion/index.d.ts +0 -33
  521. package/dist/modes/companion/index.d.ts.map +0 -1
  522. package/dist/modes/companion/index.js +0 -21
  523. package/dist/modes/companion/index.js.map +0 -1
  524. package/dist/modes/companion/input-key-mapper.d.ts +0 -3
  525. package/dist/modes/companion/input-key-mapper.d.ts.map +0 -1
  526. package/dist/modes/companion/input-key-mapper.js +0 -31
  527. package/dist/modes/companion/input-key-mapper.js.map +0 -1
  528. package/dist/modes/companion/input-key-mapper.test.d.ts +0 -2
  529. package/dist/modes/companion/input-key-mapper.test.d.ts.map +0 -1
  530. package/dist/modes/companion/input-key-mapper.test.js +0 -26
  531. package/dist/modes/companion/input-key-mapper.test.js.map +0 -1
  532. package/dist/modes/companion/input-parser.d.ts +0 -53
  533. package/dist/modes/companion/input-parser.d.ts.map +0 -1
  534. package/dist/modes/companion/input-parser.js +0 -114
  535. package/dist/modes/companion/input-parser.js.map +0 -1
  536. package/dist/modes/companion/input-parser.test.d.ts +0 -2
  537. package/dist/modes/companion/input-parser.test.d.ts.map +0 -1
  538. package/dist/modes/companion/input-parser.test.js +0 -123
  539. package/dist/modes/companion/input-parser.test.js.map +0 -1
  540. package/dist/modes/companion/mode-manager.d.ts +0 -41
  541. package/dist/modes/companion/mode-manager.d.ts.map +0 -1
  542. package/dist/modes/companion/mode-manager.js +0 -56
  543. package/dist/modes/companion/mode-manager.js.map +0 -1
  544. package/dist/modes/companion/mode-manager.test.d.ts +0 -2
  545. package/dist/modes/companion/mode-manager.test.d.ts.map +0 -1
  546. package/dist/modes/companion/mode-manager.test.js +0 -65
  547. package/dist/modes/companion/mode-manager.test.js.map +0 -1
  548. package/dist/modes/companion/output-classifier.d.ts +0 -15
  549. package/dist/modes/companion/output-classifier.d.ts.map +0 -1
  550. package/dist/modes/companion/output-classifier.js +0 -77
  551. package/dist/modes/companion/output-classifier.js.map +0 -1
  552. package/dist/modes/companion/output-classifier.test.d.ts +0 -2
  553. package/dist/modes/companion/output-classifier.test.d.ts.map +0 -1
  554. package/dist/modes/companion/output-classifier.test.js +0 -133
  555. package/dist/modes/companion/output-classifier.test.js.map +0 -1
  556. package/dist/modes/companion/pty-wrapper.d.ts +0 -46
  557. package/dist/modes/companion/pty-wrapper.d.ts.map +0 -1
  558. package/dist/modes/companion/pty-wrapper.js +0 -143
  559. package/dist/modes/companion/pty-wrapper.js.map +0 -1
  560. package/dist/modes/companion/safety-classifier.d.ts +0 -31
  561. package/dist/modes/companion/safety-classifier.d.ts.map +0 -1
  562. package/dist/modes/companion/safety-classifier.js +0 -140
  563. package/dist/modes/companion/safety-classifier.js.map +0 -1
  564. package/dist/modes/companion/safety-classifier.test.d.ts +0 -2
  565. package/dist/modes/companion/safety-classifier.test.d.ts.map +0 -1
  566. package/dist/modes/companion/safety-classifier.test.js +0 -151
  567. package/dist/modes/companion/safety-classifier.test.js.map +0 -1
  568. package/dist/modes/companion/summarizer.d.ts +0 -24
  569. package/dist/modes/companion/summarizer.d.ts.map +0 -1
  570. package/dist/modes/companion/summarizer.js +0 -132
  571. package/dist/modes/companion/summarizer.js.map +0 -1
  572. package/dist/modes/companion/terminal-history.d.ts +0 -27
  573. package/dist/modes/companion/terminal-history.d.ts.map +0 -1
  574. package/dist/modes/companion/terminal-history.js +0 -142
  575. package/dist/modes/companion/terminal-history.js.map +0 -1
  576. package/dist/prompts/simple-mentor.md +0 -215
  577. package/dist/providers/ai-sdk-openai.provider.d.ts +0 -14
  578. package/dist/providers/ai-sdk-openai.provider.d.ts.map +0 -1
  579. package/dist/providers/ai-sdk-openai.provider.js +0 -18
  580. package/dist/providers/ai-sdk-openai.provider.js.map +0 -1
  581. package/dist/providers/github-copilot/converters.d.ts +0 -45
  582. package/dist/providers/github-copilot/converters.d.ts.map +0 -1
  583. package/dist/providers/github-copilot/converters.js +0 -118
  584. package/dist/providers/github-copilot/converters.js.map +0 -1
  585. package/dist/providers/github-copilot/converters.test.d.ts +0 -2
  586. package/dist/providers/github-copilot/converters.test.d.ts.map +0 -1
  587. package/dist/providers/github-copilot/converters.test.js +0 -162
  588. package/dist/providers/github-copilot/converters.test.js.map +0 -1
  589. package/dist/providers/github-copilot/github-copilot.provider.d.ts +0 -2
  590. package/dist/providers/github-copilot/github-copilot.provider.d.ts.map +0 -1
  591. package/dist/providers/github-copilot/github-copilot.provider.js +0 -75
  592. package/dist/providers/github-copilot/github-copilot.provider.js.map +0 -1
  593. package/dist/providers/github-copilot/github-copilot.provider.test.d.ts +0 -2
  594. package/dist/providers/github-copilot/github-copilot.provider.test.d.ts.map +0 -1
  595. package/dist/providers/github-copilot/github-copilot.provider.test.js +0 -26
  596. package/dist/providers/github-copilot/github-copilot.provider.test.js.map +0 -1
  597. package/dist/providers/github-copilot/index.d.ts +0 -4
  598. package/dist/providers/github-copilot/index.d.ts.map +0 -1
  599. package/dist/providers/github-copilot/index.js +0 -4
  600. package/dist/providers/github-copilot/index.js.map +0 -1
  601. package/dist/providers/github-copilot/model.d.ts +0 -24
  602. package/dist/providers/github-copilot/model.d.ts.map +0 -1
  603. package/dist/providers/github-copilot/model.delta.test.d.ts +0 -2
  604. package/dist/providers/github-copilot/model.delta.test.d.ts.map +0 -1
  605. package/dist/providers/github-copilot/model.delta.test.js +0 -15
  606. package/dist/providers/github-copilot/model.delta.test.js.map +0 -1
  607. package/dist/providers/github-copilot/model.js +0 -498
  608. package/dist/providers/github-copilot/model.js.map +0 -1
  609. package/dist/providers/github-copilot/model.test.d.ts +0 -2
  610. package/dist/providers/github-copilot/model.test.d.ts.map +0 -1
  611. package/dist/providers/github-copilot/model.test.js +0 -63
  612. package/dist/providers/github-copilot/model.test.js.map +0 -1
  613. package/dist/providers/github-copilot/provider.d.ts +0 -15
  614. package/dist/providers/github-copilot/provider.d.ts.map +0 -1
  615. package/dist/providers/github-copilot/provider.js +0 -25
  616. package/dist/providers/github-copilot/provider.js.map +0 -1
  617. package/dist/providers/github-copilot/provider.test.d.ts +0 -2
  618. package/dist/providers/github-copilot/provider.test.d.ts.map +0 -1
  619. package/dist/providers/github-copilot/provider.test.js +0 -52
  620. package/dist/providers/github-copilot/provider.test.js.map +0 -1
  621. package/dist/providers/github-copilot/utils.d.ts +0 -20
  622. package/dist/providers/github-copilot/utils.d.ts.map +0 -1
  623. package/dist/providers/github-copilot/utils.js +0 -142
  624. package/dist/providers/github-copilot/utils.js.map +0 -1
  625. package/dist/providers/github-copilot/utils.test.d.ts +0 -2
  626. package/dist/providers/github-copilot/utils.test.d.ts.map +0 -1
  627. package/dist/providers/github-copilot/utils.test.js +0 -21
  628. package/dist/providers/github-copilot/utils.test.js.map +0 -1
  629. package/dist/providers/openai-compatible/api.d.ts +0 -17
  630. package/dist/providers/openai-compatible/api.d.ts.map +0 -1
  631. package/dist/providers/openai-compatible/api.js +0 -58
  632. package/dist/providers/openai-compatible/api.js.map +0 -1
  633. package/dist/providers/openai-compatible/model.d.ts +0 -17
  634. package/dist/providers/openai-compatible/model.d.ts.map +0 -1
  635. package/dist/providers/openai-compatible/model.js +0 -473
  636. package/dist/providers/openai-compatible/model.js.map +0 -1
  637. package/dist/providers/openai-compatible/provider.d.ts +0 -22
  638. package/dist/providers/openai-compatible/provider.d.ts.map +0 -1
  639. package/dist/providers/openai-compatible/provider.js +0 -43
  640. package/dist/providers/openai-compatible/provider.js.map +0 -1
  641. package/dist/providers/openai-compatible/reasoning-content.test.d.ts +0 -2
  642. package/dist/providers/openai-compatible/reasoning-content.test.d.ts.map +0 -1
  643. package/dist/providers/openai-compatible/reasoning-content.test.js +0 -258
  644. package/dist/providers/openai-compatible/reasoning-content.test.js.map +0 -1
  645. package/dist/providers/openai-compatible/utils.d.ts +0 -3
  646. package/dist/providers/openai-compatible/utils.d.ts.map +0 -1
  647. package/dist/providers/openai-compatible/utils.js +0 -11
  648. package/dist/providers/openai-compatible/utils.js.map +0 -1
  649. package/dist/providers/openrouter/api.d.ts +0 -39
  650. package/dist/providers/openrouter/api.d.ts.map +0 -1
  651. package/dist/providers/openrouter/api.js +0 -164
  652. package/dist/providers/openrouter/api.js.map +0 -1
  653. package/dist/providers/openrouter/converters.d.ts +0 -8
  654. package/dist/providers/openrouter/converters.d.ts.map +0 -1
  655. package/dist/providers/openrouter/converters.js +0 -391
  656. package/dist/providers/openrouter/converters.js.map +0 -1
  657. package/dist/providers/openrouter/converters.test.d.ts +0 -2
  658. package/dist/providers/openrouter/converters.test.d.ts.map +0 -1
  659. package/dist/providers/openrouter/converters.test.js +0 -179
  660. package/dist/providers/openrouter/converters.test.js.map +0 -1
  661. package/dist/providers/openrouter/index.d.ts +0 -4
  662. package/dist/providers/openrouter/index.d.ts.map +0 -1
  663. package/dist/providers/openrouter/index.js +0 -4
  664. package/dist/providers/openrouter/index.js.map +0 -1
  665. package/dist/providers/openrouter/model.d.ts +0 -14
  666. package/dist/providers/openrouter/model.d.ts.map +0 -1
  667. package/dist/providers/openrouter/model.js +0 -457
  668. package/dist/providers/openrouter/model.js.map +0 -1
  669. package/dist/providers/openrouter/provider.d.ts +0 -15
  670. package/dist/providers/openrouter/provider.d.ts.map +0 -1
  671. package/dist/providers/openrouter/provider.js +0 -21
  672. package/dist/providers/openrouter/provider.js.map +0 -1
  673. package/dist/providers/openrouter/reasoning-content.test.d.ts +0 -2
  674. package/dist/providers/openrouter/reasoning-content.test.d.ts.map +0 -1
  675. package/dist/providers/openrouter/reasoning-content.test.js +0 -122
  676. package/dist/providers/openrouter/reasoning-content.test.js.map +0 -1
  677. package/dist/providers/openrouter/utils.d.ts +0 -11
  678. package/dist/providers/openrouter/utils.d.ts.map +0 -1
  679. package/dist/providers/openrouter/utils.js +0 -29
  680. package/dist/providers/openrouter/utils.js.map +0 -1
  681. package/dist/providers/openrouter.api.retry.test.d.ts +0 -2
  682. package/dist/providers/openrouter.api.retry.test.d.ts.map +0 -1
  683. package/dist/providers/openrouter.api.retry.test.js +0 -148
  684. package/dist/providers/openrouter.api.retry.test.js.map +0 -1
  685. package/dist/providers/openrouter.test.d.ts +0 -2
  686. package/dist/providers/openrouter.test.d.ts.map +0 -1
  687. package/dist/providers/openrouter.test.js +0 -1449
  688. package/dist/providers/openrouter.test.js.map +0 -1
  689. package/dist/safety-checker.js +0 -57
  690. package/dist/services/check_mock.d.ts +0 -2
  691. package/dist/services/check_mock.d.ts.map +0 -1
  692. package/dist/services/check_mock.js +0 -22
  693. package/dist/services/check_mock.js.map +0 -1
  694. package/dist/services/conversation-service.test.d.ts +0 -2
  695. package/dist/services/conversation-service.test.d.ts.map +0 -1
  696. package/dist/services/conversation-service.test.js +0 -156
  697. package/dist/services/conversation-service.test.js.map +0 -1
  698. package/dist/tools/bash.d.ts +0 -10
  699. package/dist/tools/bash.d.ts.map +0 -1
  700. package/dist/tools/bash.js +0 -55
  701. package/dist/tools/bash.js.map +0 -1
  702. package/dist/utils/command-safety.d.ts +0 -21
  703. package/dist/utils/command-safety.d.ts.map +0 -1
  704. package/dist/utils/command-safety.devnull.test.d.ts +0 -2
  705. package/dist/utils/command-safety.devnull.test.d.ts.map +0 -1
  706. package/dist/utils/command-safety.devnull.test.js +0 -13
  707. package/dist/utils/command-safety.devnull.test.js.map +0 -1
  708. package/dist/utils/command-safety.js +0 -348
  709. package/dist/utils/command-safety.js.map +0 -1
  710. package/dist/utils/extract-command-messages.test.d.ts +0 -2
  711. package/dist/utils/extract-command-messages.test.d.ts.map +0 -1
  712. package/dist/utils/provider-traffic-extractor.repro.test.d.ts +0 -2
  713. package/dist/utils/provider-traffic-extractor.repro.test.d.ts.map +0 -1
  714. package/dist/utils/provider-traffic-extractor.repro.test.js.map +0 -1
@@ -35,68 +35,80 @@ function createTool(settingsService = createMockSettingsService(), editHealing)
35
35
  ...(editHealing ? { editHealing } : {}),
36
36
  });
37
37
  }
38
- test.serial('needsApproval auto-approves creation when search_content is empty and file is missing in edit mode', async (t) => {
38
+ test.serial('needsApproval auto-approves creation when search_content is empty and file is missing', async (t) => {
39
39
  await withTempDir(async () => {
40
- const tool = createTool(createMockSettingsService({ app: { editMode: true } }));
40
+ const tool = createTool(createMockSettingsService());
41
41
  const filePath = 'new-file.txt';
42
42
  const result = await tool.needsApproval({
43
43
  path: filePath,
44
- search_content: '',
45
- replace_content: 'initial content',
46
- replace_all: false,
44
+ replacements: [
45
+ {
46
+ search_content: '',
47
+ replace_content: 'initial content',
48
+ },
49
+ ],
47
50
  });
48
51
  t.false(result);
49
52
  });
50
53
  });
51
- test.serial('needsApproval auto-approves a unique exact match in edit mode', async (t) => {
54
+ test.serial('needsApproval auto-approves a unique exact match', async (t) => {
52
55
  await withTempDir(async (dir) => {
53
- const tool = createTool(createMockSettingsService({ app: { editMode: true } }));
56
+ const tool = createTool(createMockSettingsService());
54
57
  const filePath = 'sample.txt';
55
58
  const absPath = path.join(dir, filePath);
56
59
  await fs.writeFile(absPath, 'hello world');
57
60
  const result = await tool.needsApproval({
58
61
  path: filePath,
59
- search_content: 'hello',
60
- replace_content: 'hi',
61
- replace_all: false,
62
+ replacements: [
63
+ {
64
+ search_content: 'hello',
65
+ replace_content: 'hi',
66
+ },
67
+ ],
62
68
  });
63
69
  t.false(result);
64
70
  });
65
71
  });
66
- test.serial('needsApproval requires approval when multiple exact matches and replace_all is false', async (t) => {
72
+ test.serial('needsApproval auto-approves when multiple exact matches are found', async (t) => {
67
73
  await withTempDir(async (dir) => {
68
- const tool = createTool(createMockSettingsService({ app: { editMode: true } }));
74
+ const tool = createTool(createMockSettingsService());
69
75
  const filePath = 'sample.txt';
70
76
  const absPath = path.join(dir, filePath);
71
77
  await fs.writeFile(absPath, 'hello world hello');
72
78
  const result = await tool.needsApproval({
73
79
  path: filePath,
74
- search_content: 'hello',
75
- replace_content: 'hi',
76
- replace_all: false,
80
+ replacements: [
81
+ {
82
+ search_content: 'hello',
83
+ replace_content: 'hi',
84
+ },
85
+ ],
77
86
  });
78
- t.true(result);
87
+ t.false(result);
79
88
  });
80
89
  });
81
- test.serial('execute replaces only the first exact match when replace_all is false', async (t) => {
90
+ test.serial('execute replaces only a unique exact match', async (t) => {
82
91
  await withTempDir(async (dir) => {
83
92
  const tool = createTool();
84
93
  const filePath = 'content.txt';
85
94
  const absPath = path.join(dir, filePath);
86
- await fs.writeFile(absPath, 'target before target after');
95
+ await fs.writeFile(absPath, 'target before unique after');
87
96
  const result = await tool.execute({
88
97
  path: filePath,
89
- search_content: 'target',
90
- replace_content: 'done',
91
- replace_all: false,
98
+ replacements: [
99
+ {
100
+ search_content: 'target',
101
+ replace_content: 'done',
102
+ },
103
+ ],
92
104
  });
93
105
  const parsed = JSON.parse(result);
94
106
  t.true(parsed.output[0].success);
95
107
  const updated = await fs.readFile(absPath, 'utf8');
96
- t.is(updated, 'done before target after');
108
+ t.is(updated, 'done before unique after');
97
109
  });
98
110
  });
99
- test.serial('execute replaces all exact matches when replace_all is true', async (t) => {
111
+ test.serial('execute fails when multiple exact matches are found', async (t) => {
100
112
  await withTempDir(async (dir) => {
101
113
  const tool = createTool();
102
114
  const filePath = 'content.txt';
@@ -104,14 +116,18 @@ test.serial('execute replaces all exact matches when replace_all is true', async
104
116
  await fs.writeFile(absPath, 'foo foo foo');
105
117
  const result = await tool.execute({
106
118
  path: filePath,
107
- search_content: 'foo',
108
- replace_content: 'bar',
109
- replace_all: true,
119
+ replacements: [
120
+ {
121
+ search_content: 'foo',
122
+ replace_content: 'bar',
123
+ },
124
+ ],
110
125
  });
111
126
  const parsed = JSON.parse(result);
112
- t.true(parsed.output[0].success);
127
+ t.false(parsed.output[0].success);
128
+ t.regex(parsed.output[0].error, /Found 3 exact matches/);
113
129
  const updated = await fs.readFile(absPath, 'utf8');
114
- t.is(updated, 'bar bar bar');
130
+ t.is(updated, 'foo foo foo');
115
131
  });
116
132
  });
117
133
  test.serial('execute performs relaxed match replacement when exact match is not found', async (t) => {
@@ -122,9 +138,12 @@ test.serial('execute performs relaxed match replacement when exact match is not
122
138
  await fs.writeFile(absPath, ' line one\n\tline two\nremainder');
123
139
  const result = await tool.execute({
124
140
  path: filePath,
125
- search_content: 'line one\nline two',
126
- replace_content: 'new block\n',
127
- replace_all: false,
141
+ replacements: [
142
+ {
143
+ search_content: 'line one\nline two',
144
+ replace_content: 'new block\n',
145
+ },
146
+ ],
128
147
  });
129
148
  const parsed = JSON.parse(result);
130
149
  t.true(parsed.output[0].success);
@@ -132,25 +151,7 @@ test.serial('execute performs relaxed match replacement when exact match is not
132
151
  t.is(updated, 'new block\nremainder');
133
152
  });
134
153
  });
135
- test.serial('execute replaces first of multiple exact matches when replace_all is false', async (t) => {
136
- await withTempDir(async (dir) => {
137
- const tool = createTool();
138
- const filePath = 'content.txt';
139
- const absPath = path.join(dir, filePath);
140
- await fs.writeFile(absPath, 'foo\nbar\n---\nfoo\nbar\n');
141
- const result = await tool.execute({
142
- path: filePath,
143
- search_content: 'foo\nbar',
144
- replace_content: 'replacement',
145
- replace_all: false,
146
- });
147
- const parsed = JSON.parse(result);
148
- t.true(parsed.output[0].success);
149
- const updated = await fs.readFile(absPath, 'utf8');
150
- t.is(updated, 'replacement\n---\nfoo\nbar\n');
151
- });
152
- });
153
- test.serial('execute rejects multiple relaxed matches when replace_all is false', async (t) => {
154
+ test.serial('execute fails when multiple relaxed matches are found', async (t) => {
154
155
  await withTempDir(async (dir) => {
155
156
  const tool = createTool();
156
157
  const filePath = 'content.txt';
@@ -158,36 +159,20 @@ test.serial('execute rejects multiple relaxed matches when replace_all is false'
158
159
  await fs.writeFile(absPath, ' foo \n\tbar\n---\n foo \n\tbar\n');
159
160
  const result = await tool.execute({
160
161
  path: filePath,
161
- search_content: 'foo\nbar',
162
- replace_content: 'replacement',
163
- replace_all: false,
162
+ replacements: [
163
+ {
164
+ search_content: 'foo\nbar',
165
+ replace_content: 'replacement',
166
+ },
167
+ ],
164
168
  });
165
169
  const parsed = JSON.parse(result);
166
170
  t.false(parsed.output[0].success);
167
- t.true(parsed.output[0].error.includes('relaxed matches'));
171
+ t.true(parsed.output[0].error.includes('relaxed matches') || parsed.output[0].error.includes('Found 2 relaxed matches'));
168
172
  const unchanged = await fs.readFile(absPath, 'utf8');
169
173
  t.is(unchanged, ' foo \n\tbar\n---\n foo \n\tbar\n');
170
174
  });
171
175
  });
172
- test.serial('execute replaces all relaxed matches when replace_all is true', async (t) => {
173
- await withTempDir(async (dir) => {
174
- const tool = createTool(createMockSettingsService({ 'tools.enableEditHealing': false }));
175
- const filePath = 'content.txt';
176
- const absPath = path.join(dir, filePath);
177
- await fs.writeFile(absPath, ' foo \n\tbar\n---\n foo \n\tbar\n');
178
- const result = await tool.execute({
179
- path: filePath,
180
- search_content: 'foo\nbar',
181
- replace_content: 'replacement',
182
- replace_all: true,
183
- });
184
- const parsed = JSON.parse(result);
185
- t.true(parsed.output[0].success);
186
- t.true(parsed.output[0].message.includes('relaxed'));
187
- const updated = await fs.readFile(absPath, 'utf8');
188
- t.is(updated, 'replacement---\nreplacement');
189
- });
190
- });
191
176
  test.serial('execute creates a new file when search_content is empty and file is missing', async (t) => {
192
177
  await withTempDir(async (dir) => {
193
178
  const tool = createTool();
@@ -195,9 +180,12 @@ test.serial('execute creates a new file when search_content is empty and file is
195
180
  const absPath = path.join(dir, filePath);
196
181
  const result = await tool.execute({
197
182
  path: filePath,
198
- search_content: '',
199
- replace_content: 'new content',
200
- replace_all: false,
183
+ replacements: [
184
+ {
185
+ search_content: '',
186
+ replace_content: 'new content',
187
+ },
188
+ ],
201
189
  });
202
190
  const parsed = JSON.parse(result);
203
191
  t.true(parsed.output[0].success);
@@ -210,13 +198,16 @@ test.serial('execute preserves parallel edits to different regions of the same f
210
198
  const tool = createTool(createMockSettingsService({ 'tools.enableEditHealing': false }));
211
199
  const filePath = 'parallel.txt';
212
200
  const absPath = path.join(dir, filePath);
213
- const tokens = Array.from({ length: 20 }, (_, index) => `token_${index}`);
201
+ const tokens = Array.from({ length: 20 }, (_, index) => `token_${String(index).padStart(2, '0')}`);
214
202
  await fs.writeFile(absPath, tokens.join('\n'));
215
203
  const results = await Promise.all(tokens.map((token, index) => tool.execute({
216
204
  path: filePath,
217
- search_content: token,
218
- replace_content: `done_${index}`,
219
- replace_all: false,
205
+ replacements: [
206
+ {
207
+ search_content: token,
208
+ replace_content: `done_${index}`,
209
+ },
210
+ ],
220
211
  })));
221
212
  for (const result of results) {
222
213
  const parsed = JSON.parse(result);
@@ -233,18 +224,15 @@ test.serial('execute applies batched replacements to one file with a single resu
233
224
  const absPath = path.join(dir, filePath);
234
225
  await fs.writeFile(absPath, 'alpha\nbeta\ngamma\n');
235
226
  const result = await tool.execute({
227
+ path: filePath,
236
228
  replacements: [
237
229
  {
238
- path: filePath,
239
230
  search_content: 'alpha',
240
231
  replace_content: 'ALPHA',
241
- replace_all: false,
242
232
  },
243
233
  {
244
- path: filePath,
245
234
  search_content: 'gamma',
246
235
  replace_content: 'GAMMA',
247
- replace_all: false,
248
236
  },
249
237
  ],
250
238
  });
@@ -263,24 +251,19 @@ test.serial('execute keeps successful batched replacements when another replacem
263
251
  const originalContent = 'alpha\nbeta\ngamma\n';
264
252
  await fs.writeFile(absPath, originalContent);
265
253
  const result = await tool.execute({
254
+ path: filePath,
266
255
  replacements: [
267
256
  {
268
- path: filePath,
269
257
  search_content: 'alpha',
270
258
  replace_content: 'ALPHA',
271
- replace_all: false,
272
259
  },
273
260
  {
274
- path: filePath,
275
261
  search_content: 'missing',
276
262
  replace_content: 'MISSING',
277
- replace_all: false,
278
263
  },
279
264
  {
280
- path: filePath,
281
265
  search_content: 'gamma',
282
266
  replace_content: 'GAMMA',
283
- replace_all: false,
284
267
  },
285
268
  ],
286
269
  });
@@ -301,9 +284,12 @@ test.serial('execute reports failure when search string is not found', async (t)
301
284
  await fs.writeFile(absPath, originalContent);
302
285
  const result = await tool.execute({
303
286
  path: filePath,
304
- search_content: 'nonexistent',
305
- replace_content: 'replacement',
306
- replace_all: false,
287
+ replacements: [
288
+ {
289
+ search_content: 'nonexistent',
290
+ replace_content: 'replacement',
291
+ },
292
+ ],
307
293
  });
308
294
  const parsed = JSON.parse(result);
309
295
  t.false(parsed.output[0].success);
@@ -326,9 +312,12 @@ test.serial('execute heals search content when no match is found', async (t) =>
326
312
  }));
327
313
  const result = await tool.execute({
328
314
  path: filePath,
329
- search_content: 'const foo = 2;\n',
330
- replace_content: 'const foo = 3;\n',
331
- replace_all: false,
315
+ replacements: [
316
+ {
317
+ search_content: 'const foo = 2;\n',
318
+ replace_content: 'const foo = 3;\n',
319
+ },
320
+ ],
332
321
  });
333
322
  const parsed = JSON.parse(result);
334
323
  t.true(parsed.output[0].success);
@@ -350,9 +339,12 @@ test.serial('execute includes auto-healing failure reason when healing does not
350
339
  }));
351
340
  const result = await tool.execute({
352
341
  path: filePath,
353
- search_content: 'const foo = 2;\n',
354
- replace_content: 'const foo = 3;\n',
355
- replace_all: false,
342
+ replacements: [
343
+ {
344
+ search_content: 'const foo = 2;\n',
345
+ replace_content: 'const foo = 3;\n',
346
+ },
347
+ ],
356
348
  });
357
349
  const parsed = JSON.parse(result);
358
350
  t.false(parsed.output[0].success);
@@ -369,9 +361,12 @@ test.serial('execute treats special regex characters literally', async (t) => {
369
361
  await fs.writeFile(absPath, originalContent);
370
362
  const result = await tool.execute({
371
363
  path: filePath,
372
- search_content: '[1, 2, 3]',
373
- replace_content: '[4, 5, 6]',
374
- replace_all: false,
364
+ replacements: [
365
+ {
366
+ search_content: '[1, 2, 3]',
367
+ replace_content: '[4, 5, 6]',
368
+ },
369
+ ],
375
370
  });
376
371
  const parsed = JSON.parse(result);
377
372
  t.true(parsed.output[0].success);
@@ -387,9 +382,12 @@ test.serial('execute deletes content when replacement is empty string', async (t
387
382
  await fs.writeFile(absPath, 'before DELETE_ME after');
388
383
  const result = await tool.execute({
389
384
  path: filePath,
390
- search_content: 'DELETE_ME ',
391
- replace_content: '',
392
- replace_all: false,
385
+ replacements: [
386
+ {
387
+ search_content: 'DELETE_ME ',
388
+ replace_content: '',
389
+ },
390
+ ],
393
391
  });
394
392
  const parsed = JSON.parse(result);
395
393
  t.true(parsed.output[0].success);
@@ -405,9 +403,12 @@ test.serial('execute performs exact multi-line match without whitespace normaliz
405
403
  await fs.writeFile(absPath, 'line one\nline two\nline three');
406
404
  const result = await tool.execute({
407
405
  path: filePath,
408
- search_content: 'line one\nline two',
409
- replace_content: 'new content',
410
- replace_all: false,
406
+ replacements: [
407
+ {
408
+ search_content: 'line one\nline two',
409
+ replace_content: 'new content',
410
+ },
411
+ ],
411
412
  });
412
413
  const parsed = JSON.parse(result);
413
414
  t.true(parsed.output[0].success);
@@ -423,9 +424,12 @@ test.serial('execute handles leading/trailing whitespace differences in relaxed
423
424
  await fs.writeFile(absPath, ' foo \nbar');
424
425
  const result = await tool.execute({
425
426
  path: filePath,
426
- search_content: 'foo\nbar',
427
- replace_content: 'replaced',
428
- replace_all: false,
427
+ replacements: [
428
+ {
429
+ search_content: 'foo\nbar',
430
+ replace_content: 'replaced',
431
+ },
432
+ ],
429
433
  });
430
434
  const parsed = JSON.parse(result);
431
435
  t.true(parsed.output[0].success);
@@ -441,9 +445,12 @@ test.serial('execute performs normalized whitespace match across line breaks', a
441
445
  await fs.writeFile(absPath, 'const foo = 1;\nconst bar = 2;\nconst baz = 3;\n');
442
446
  const result = await tool.execute({
443
447
  path: filePath,
444
- search_content: 'const foo = 1; const bar = 2;',
445
- replace_content: 'const foo = 1;\nconst bar = 42;',
446
- replace_all: false,
448
+ replacements: [
449
+ {
450
+ search_content: 'const foo = 1; const bar = 2;',
451
+ replace_content: 'const foo = 1;\nconst bar = 42;',
452
+ },
453
+ ],
447
454
  });
448
455
  const parsed = JSON.parse(result);
449
456
  t.true(parsed.output[0].success);
@@ -451,7 +458,7 @@ test.serial('execute performs normalized whitespace match across line breaks', a
451
458
  t.is(updated, 'const foo = 1;\nconst bar = 42;\nconst baz = 3;\n');
452
459
  });
453
460
  });
454
- test.serial('execute rejects multiple normalized matches when replace_all is false', async (t) => {
461
+ test.serial('execute rejects multiple normalized matches', async (t) => {
455
462
  await withTempDir(async (dir) => {
456
463
  const tool = createTool(createMockSettingsService({ 'tools.enableEditHealing': false }));
457
464
  const filePath = 'normalized-multi.txt';
@@ -459,9 +466,12 @@ test.serial('execute rejects multiple normalized matches when replace_all is fal
459
466
  await fs.writeFile(absPath, 'const foo = 1;\n const bar = 2;\n---\nconst foo = 1;\tconst bar = 2;\n');
460
467
  const result = await tool.execute({
461
468
  path: filePath,
462
- search_content: 'const foo = 1; const bar = 2;',
463
- replace_content: 'const foo = 9; const bar = 9;',
464
- replace_all: false,
469
+ replacements: [
470
+ {
471
+ search_content: 'const foo = 1; const bar = 2;',
472
+ replace_content: 'const foo = 9; const bar = 9;',
473
+ },
474
+ ],
465
475
  });
466
476
  const parsed = JSON.parse(result);
467
477
  t.false(parsed.output[0].success);
@@ -477,14 +487,14 @@ test.serial('execute does not match substrings in relaxed mode', async (t) => {
477
487
  const absPath = path.join(dir, filePath);
478
488
  const originalContent = ' formatted text ';
479
489
  await fs.writeFile(absPath, originalContent);
480
- // Search for "format" with different whitespace to trigger relaxed mode
481
- // Relaxed mode should NOT match because it compares entire trimmed lines,
482
- // and "format" (trimmed) !== "formatted text" (trimmed)
483
490
  const result = await tool.execute({
484
491
  path: filePath,
485
- search_content: ' format ',
486
- replace_content: 'replacement',
487
- replace_all: false,
492
+ replacements: [
493
+ {
494
+ search_content: ' format ',
495
+ replace_content: 'replacement',
496
+ },
497
+ ],
488
498
  });
489
499
  const parsed = JSON.parse(result);
490
500
  t.false(parsed.output[0].success);
@@ -492,22 +502,20 @@ test.serial('execute does not match substrings in relaxed mode', async (t) => {
492
502
  t.is(unchanged, originalContent);
493
503
  });
494
504
  });
495
- // ============================================================================
496
- // EOL Normalization Tests
497
- // ============================================================================
498
505
  test.serial('execute normalizes CRLF search content to match LF file', async (t) => {
499
506
  await withTempDir(async (dir) => {
500
507
  const tool = createTool();
501
508
  const filePath = 'lf-file.txt';
502
509
  const absPath = path.join(dir, filePath);
503
- // File has LF line endings
504
510
  await fs.writeFile(absPath, 'line one\nline two\nline three');
505
- // Search content has CRLF line endings
506
511
  const result = await tool.execute({
507
512
  path: filePath,
508
- search_content: 'line one\r\nline two',
509
- replace_content: 'replaced',
510
- replace_all: false,
513
+ replacements: [
514
+ {
515
+ search_content: 'line one\r\nline two',
516
+ replace_content: 'replaced',
517
+ },
518
+ ],
511
519
  });
512
520
  const parsed = JSON.parse(result);
513
521
  t.true(parsed.output[0].success);
@@ -520,19 +528,19 @@ test.serial('execute normalizes LF search content to match CRLF file', async (t)
520
528
  const tool = createTool();
521
529
  const filePath = 'crlf-file.txt';
522
530
  const absPath = path.join(dir, filePath);
523
- // File has CRLF line endings
524
531
  await fs.writeFile(absPath, 'line one\r\nline two\r\nline three');
525
- // Search content has LF line endings
526
532
  const result = await tool.execute({
527
533
  path: filePath,
528
- search_content: 'line one\nline two',
529
- replace_content: 'replaced',
530
- replace_all: false,
534
+ replacements: [
535
+ {
536
+ search_content: 'line one\nline two',
537
+ replace_content: 'replaced',
538
+ },
539
+ ],
531
540
  });
532
541
  const parsed = JSON.parse(result);
533
542
  t.true(parsed.output[0].success);
534
543
  const updated = await fs.readFile(absPath, 'utf8');
535
- // Result should preserve the file's CRLF style
536
544
  t.is(updated, 'replaced\r\nline three');
537
545
  });
538
546
  });
@@ -541,36 +549,36 @@ test.serial('execute preserves CRLF in replacement content when file uses CRLF',
541
549
  const tool = createTool();
542
550
  const filePath = 'crlf-file.txt';
543
551
  const absPath = path.join(dir, filePath);
544
- // File has CRLF line endings
545
552
  await fs.writeFile(absPath, 'hello\r\nworld');
546
553
  const result = await tool.execute({
547
554
  path: filePath,
548
- search_content: 'hello',
549
- replace_content: 'new\nline', // LF in replacement
550
- replace_all: false,
555
+ replacements: [
556
+ {
557
+ search_content: 'hello',
558
+ replace_content: 'new\nline',
559
+ },
560
+ ],
551
561
  });
552
562
  const parsed = JSON.parse(result);
553
563
  t.true(parsed.output[0].success);
554
564
  const updated = await fs.readFile(absPath, 'utf8');
555
- // Replacement should use file's CRLF style
556
565
  t.is(updated, 'new\r\nline\r\nworld');
557
566
  });
558
567
  });
559
- // ============================================================================
560
- // Leading Filepath Comment Stripping Tests
561
- // ============================================================================
562
568
  test.serial('execute strips leading filepath comment from search content', async (t) => {
563
569
  await withTempDir(async (dir) => {
564
570
  const tool = createTool();
565
571
  const filePath = 'sample.ts';
566
572
  const absPath = path.join(dir, filePath);
567
573
  await fs.writeFile(absPath, 'const x = 1;\nconst y = 2;');
568
- // Search content has a leading filepath comment (common model behavior)
569
574
  const result = await tool.execute({
570
575
  path: filePath,
571
- search_content: '// sample.ts\nconst x = 1;',
572
- replace_content: 'const x = 42;',
573
- replace_all: false,
576
+ replacements: [
577
+ {
578
+ search_content: '// sample.ts\nconst x = 1;',
579
+ replace_content: 'const x = 42;',
580
+ },
581
+ ],
574
582
  });
575
583
  const parsed = JSON.parse(result);
576
584
  t.true(parsed.output[0].success);
@@ -586,9 +594,12 @@ test.serial('execute strips leading hash filepath comment from search content',
586
594
  await fs.writeFile(absPath, 'x = 1\ny = 2');
587
595
  const result = await tool.execute({
588
596
  path: filePath,
589
- search_content: '# script.py\nx = 1',
590
- replace_content: 'x = 42',
591
- replace_all: false,
597
+ replacements: [
598
+ {
599
+ search_content: '# script.py\nx = 1',
600
+ replace_content: 'x = 42',
601
+ },
602
+ ],
592
603
  });
593
604
  const parsed = JSON.parse(result);
594
605
  t.true(parsed.output[0].success);
@@ -602,12 +613,14 @@ test.serial('execute does not strip non-filepath leading comments', async (t) =>
602
613
  const filePath = 'code.ts';
603
614
  const absPath = path.join(dir, filePath);
604
615
  await fs.writeFile(absPath, '// TODO: fix this\nconst x = 1;');
605
- // This comment is not a filepath, so it should NOT be stripped
606
616
  const result = await tool.execute({
607
617
  path: filePath,
608
- search_content: '// TODO: fix this\nconst x = 1;',
609
- replace_content: 'const x = 42;',
610
- replace_all: false,
618
+ replacements: [
619
+ {
620
+ search_content: '// TODO: fix this\nconst x = 1;',
621
+ replace_content: 'const x = 42;',
622
+ },
623
+ ],
611
624
  });
612
625
  const parsed = JSON.parse(result);
613
626
  t.true(parsed.output[0].success);
@@ -615,9 +628,6 @@ test.serial('execute does not strip non-filepath leading comments', async (t) =>
615
628
  t.is(updated, 'const x = 42;');
616
629
  });
617
630
  });
618
- // ============================================================================
619
- // Summarization Marker Detection Tests
620
- // ============================================================================
621
631
  test.serial('execute rejects search content with "Lines X-Y omitted" marker', async (t) => {
622
632
  await withTempDir(async (dir) => {
623
633
  const tool = createTool();
@@ -626,9 +636,12 @@ test.serial('execute rejects search content with "Lines X-Y omitted" marker', as
626
636
  await fs.writeFile(absPath, 'line 1\nline 2\nline 3');
627
637
  const result = await tool.execute({
628
638
  path: filePath,
629
- search_content: 'line 1\nLines 2-50 omitted\nline 3',
630
- replace_content: 'replaced',
631
- replace_all: false,
639
+ replacements: [
640
+ {
641
+ search_content: 'line 1\nLines 2-50 omitted\nline 3',
642
+ replace_content: 'replaced',
643
+ },
644
+ ],
632
645
  });
633
646
  const parsed = JSON.parse(result);
634
647
  t.false(parsed.output[0].success);
@@ -643,9 +656,12 @@ test.serial('execute rejects search content with ellipsis marker {…}', async (
643
656
  await fs.writeFile(absPath, 'function foo() { /* code */ }');
644
657
  const result = await tool.execute({
645
658
  path: filePath,
646
- search_content: 'function foo() {…}',
647
- replace_content: 'replaced',
648
- replace_all: false,
659
+ replacements: [
660
+ {
661
+ search_content: 'function foo() {…}',
662
+ replace_content: 'replaced',
663
+ },
664
+ ],
649
665
  });
650
666
  const parsed = JSON.parse(result);
651
667
  t.false(parsed.output[0].success);
@@ -660,9 +676,12 @@ test.serial('execute rejects search content with /*...*/ marker', async (t) => {
660
676
  await fs.writeFile(absPath, 'function foo() { return 1; }');
661
677
  const result = await tool.execute({
662
678
  path: filePath,
663
- search_content: 'function foo() { /*...*/ }',
664
- replace_content: 'replaced',
665
- replace_all: false,
679
+ replacements: [
680
+ {
681
+ search_content: 'function foo() { /*...*/ }',
682
+ replace_content: 'replaced',
683
+ },
684
+ ],
666
685
  });
667
686
  const parsed = JSON.parse(result);
668
687
  t.false(parsed.output[0].success);
@@ -677,18 +696,18 @@ test.serial('execute rejects search content with // ... marker', async (t) => {
677
696
  await fs.writeFile(absPath, 'const a = 1;\nconst b = 2;\nconst c = 3;');
678
697
  const result = await tool.execute({
679
698
  path: filePath,
680
- search_content: 'const a = 1;\n// ...\nconst c = 3;',
681
- replace_content: 'replaced',
682
- replace_all: false,
699
+ replacements: [
700
+ {
701
+ search_content: 'const a = 1;\n// ...\nconst c = 3;',
702
+ replace_content: 'replaced',
703
+ },
704
+ ],
683
705
  });
684
706
  const parsed = JSON.parse(result);
685
707
  t.false(parsed.output[0].success);
686
708
  t.true(parsed.output[0].error.includes('// ...'));
687
709
  });
688
710
  });
689
- // ============================================================================
690
- // Search and Replace Equality Validation Tests
691
- // ============================================================================
692
711
  test.serial('execute rejects search content when search and replace content are identical', async (t) => {
693
712
  await withTempDir(async (dir) => {
694
713
  const tool = createTool();
@@ -697,9 +716,12 @@ test.serial('execute rejects search content when search and replace content are
697
716
  await fs.writeFile(absPath, 'hello world');
698
717
  const result = await tool.execute({
699
718
  path: filePath,
700
- search_content: 'hello',
701
- replace_content: 'hello',
702
- replace_all: false,
719
+ replacements: [
720
+ {
721
+ search_content: 'hello',
722
+ replace_content: 'hello',
723
+ },
724
+ ],
703
725
  });
704
726
  const parsed = JSON.parse(result);
705
727
  t.false(parsed.output[0].success);
@@ -714,17 +736,16 @@ test.serial('needsApproval auto-approves when search and replace content are ide
714
736
  await fs.writeFile(absPath, 'hello world');
715
737
  const result = await tool.needsApproval({
716
738
  path: filePath,
717
- search_content: 'hello',
718
- replace_content: 'hello',
719
- replace_all: false,
739
+ replacements: [
740
+ {
741
+ search_content: 'hello',
742
+ replace_content: 'hello',
743
+ },
744
+ ],
720
745
  });
721
- // Should auto-approve so execute can return the error gracefully
722
746
  t.false(result);
723
747
  });
724
748
  });
725
- // ============================================================================
726
- // Gap Matching Tests (<...> marker)
727
- // ============================================================================
728
749
  test.serial('execute performs gap match: head <...> tail replaces entire region', async (t) => {
729
750
  await withTempDir(async (dir) => {
730
751
  const tool = createTool(createMockSettingsService({ 'tools.enableEditHealing': false }));
@@ -733,9 +754,12 @@ test.serial('execute performs gap match: head <...> tail replaces entire region'
733
754
  await fs.writeFile(absPath, 'function foo() {\n const x = 1;\n const y = 2;\n const z = 3;\n return x + y + z;\n}\n');
734
755
  const result = await tool.execute({
735
756
  path: filePath,
736
- search_content: 'function foo() {\n const x = 1;\n<...>\n return x + y + z;\n}',
737
- replace_content: 'function foo() {\n return 6;\n}\n',
738
- replace_all: false,
757
+ replacements: [
758
+ {
759
+ search_content: 'function foo() {\n const x = 1;\n<...>\n return x + y + z;\n}',
760
+ replace_content: 'function foo() {\n return 6;\n}\n',
761
+ },
762
+ ],
739
763
  });
740
764
  const parsed = JSON.parse(result);
741
765
  t.true(parsed.output[0].success);
@@ -752,9 +776,12 @@ test.serial('execute performs gap match with single-line head and tail', async (
752
776
  await fs.writeFile(absPath, 'start\nmiddle1\nmiddle2\nend\nafter');
753
777
  const result = await tool.execute({
754
778
  path: filePath,
755
- search_content: 'start\n<...>\nend',
756
- replace_content: 'replaced\n',
757
- replace_all: false,
779
+ replacements: [
780
+ {
781
+ search_content: 'start\n<...>\nend',
782
+ replace_content: 'replaced\n',
783
+ },
784
+ ],
758
785
  });
759
786
  const parsed = JSON.parse(result);
760
787
  t.true(parsed.output[0].success);
@@ -770,9 +797,12 @@ test.serial('execute performs gap match with adjacent head and tail (no actual g
770
797
  await fs.writeFile(absPath, 'line1\nline2\nline3');
771
798
  const result = await tool.execute({
772
799
  path: filePath,
773
- search_content: 'line1\n<...>\nline2',
774
- replace_content: 'replaced\n',
775
- replace_all: false,
800
+ replacements: [
801
+ {
802
+ search_content: 'line1\n<...>\nline2',
803
+ replace_content: 'replaced\n',
804
+ },
805
+ ],
776
806
  });
777
807
  const parsed = JSON.parse(result);
778
808
  t.true(parsed.output[0].success);
@@ -788,9 +818,12 @@ test.serial('execute performs gap match with multiple <...> markers', async (t)
788
818
  await fs.writeFile(absPath, 'function a() {\n body1;\n}\nfunction b() {\n body2;\n}\nfunction c() {\n body3;\n}\n');
789
819
  const result = await tool.execute({
790
820
  path: filePath,
791
- search_content: 'function a() {\n<...>\nfunction b() {\n<...>\nfunction c() {\n body3;\n}',
792
- replace_content: 'function abc() {\n combined;\n}\n',
793
- replace_all: false,
821
+ replacements: [
822
+ {
823
+ search_content: 'function a() {\n<...>\nfunction b() {\n<...>\nfunction c() {\n body3;\n}',
824
+ replace_content: 'function abc() {\n combined;\n}\n',
825
+ },
826
+ ],
794
827
  });
795
828
  const parsed = JSON.parse(result);
796
829
  t.true(parsed.output[0].success);
@@ -806,9 +839,12 @@ test.serial('execute gap match fails when head is not found', async (t) => {
806
839
  await fs.writeFile(absPath, 'line1\nline2\nline3');
807
840
  const result = await tool.execute({
808
841
  path: filePath,
809
- search_content: 'nonexistent\n<...>\nline3',
810
- replace_content: 'replaced',
811
- replace_all: false,
842
+ replacements: [
843
+ {
844
+ search_content: 'nonexistent\n<...>\nline3',
845
+ replace_content: 'replaced',
846
+ },
847
+ ],
812
848
  });
813
849
  const parsed = JSON.parse(result);
814
850
  t.false(parsed.output[0].success);
@@ -822,9 +858,12 @@ test.serial('execute gap match fails when tail is not found after head', async (
822
858
  await fs.writeFile(absPath, 'line1\nline2\nline3');
823
859
  const result = await tool.execute({
824
860
  path: filePath,
825
- search_content: 'line1\n<...>\nnonexistent',
826
- replace_content: 'replaced',
827
- replace_all: false,
861
+ replacements: [
862
+ {
863
+ search_content: 'line1\n<...>\nnonexistent',
864
+ replace_content: 'replaced',
865
+ },
866
+ ],
828
867
  });
829
868
  const parsed = JSON.parse(result);
830
869
  t.false(parsed.output[0].success);
@@ -841,9 +880,12 @@ test.serial('execute does not invoke healing for a failed gap pattern and report
841
880
  await fs.writeFile(path.join(dir, filePath), 'line1\nline2\nline3');
842
881
  const result = await tool.execute({
843
882
  path: filePath,
844
- search_content: 'nonexistent\n<...>\nline3',
845
- replace_content: 'replaced',
846
- replace_all: false,
883
+ replacements: [
884
+ {
885
+ search_content: 'nonexistent\n<...>\nline3',
886
+ replace_content: 'replaced',
887
+ },
888
+ ],
847
889
  });
848
890
  const parsed = JSON.parse(result);
849
891
  t.false(parsed.output[0].success);
@@ -863,16 +905,19 @@ test.serial('execute gap diagnostic identifies the anchor that failed after the
863
905
  await fs.writeFile(path.join(dir, filePath), 'line1\nline2\nline3');
864
906
  const result = await tool.execute({
865
907
  path: filePath,
866
- search_content: 'line1\n<...>\nnonexistent',
867
- replace_content: 'replaced',
868
- replace_all: false,
908
+ replacements: [
909
+ {
910
+ search_content: 'line1\n<...>\nnonexistent',
911
+ replace_content: 'replaced',
912
+ },
913
+ ],
869
914
  });
870
915
  const parsed = JSON.parse(result);
871
916
  t.false(parsed.output[0].success);
872
917
  t.regex(parsed.output[0].error, /not found after/i);
873
918
  });
874
919
  });
875
- test.serial('execute gap match rejects multiple matches when replace_all is false', async (t) => {
920
+ test.serial('execute gap match rejects multiple matches', async (t) => {
876
921
  await withTempDir(async (dir) => {
877
922
  const tool = createTool(createMockSettingsService({ 'tools.enableEditHealing': false }));
878
923
  const filePath = 'content.txt';
@@ -880,33 +925,18 @@ test.serial('execute gap match rejects multiple matches when replace_all is fals
880
925
  await fs.writeFile(absPath, 'start\nmiddle1\nend\nstart\nmiddle2\nend\n');
881
926
  const result = await tool.execute({
882
927
  path: filePath,
883
- search_content: 'start\n<...>\nend',
884
- replace_content: 'replaced',
885
- replace_all: false,
928
+ replacements: [
929
+ {
930
+ search_content: 'start\n<...>\nend',
931
+ replace_content: 'replaced',
932
+ },
933
+ ],
886
934
  });
887
935
  const parsed = JSON.parse(result);
888
936
  t.false(parsed.output[0].success);
889
937
  t.true(parsed.output[0].error.includes('gap'));
890
938
  });
891
939
  });
892
- test.serial('execute gap match replaces all when replace_all is true', async (t) => {
893
- await withTempDir(async (dir) => {
894
- const tool = createTool(createMockSettingsService({ 'tools.enableEditHealing': false }));
895
- const filePath = 'content.txt';
896
- const absPath = path.join(dir, filePath);
897
- await fs.writeFile(absPath, 'start\nmiddle1\nend\nstart\nmiddle2\nend\n');
898
- const result = await tool.execute({
899
- path: filePath,
900
- search_content: 'start\n<...>\nend',
901
- replace_content: 'replaced\n',
902
- replace_all: true,
903
- });
904
- const parsed = JSON.parse(result);
905
- t.true(parsed.output[0].success);
906
- const updated = await fs.readFile(absPath, 'utf8');
907
- t.is(updated, 'replaced\nreplaced\n');
908
- });
909
- });
910
940
  test.serial('execute gap match works with relaxed whitespace matching in segments', async (t) => {
911
941
  await withTempDir(async (dir) => {
912
942
  const tool = createTool(createMockSettingsService({ 'tools.enableEditHealing': false }));
@@ -915,9 +945,12 @@ test.serial('execute gap match works with relaxed whitespace matching in segment
915
945
  await fs.writeFile(absPath, ' function foo() {\n const x = 1;\n const y = 2;\n return x;\n }\n');
916
946
  const result = await tool.execute({
917
947
  path: filePath,
918
- search_content: 'function foo() {\n<...>\nreturn x;\n}',
919
- replace_content: 'function foo() {\n return 42;\n}\n',
920
- replace_all: false,
948
+ replacements: [
949
+ {
950
+ search_content: 'function foo() {\n<...>\nreturn x;\n}',
951
+ replace_content: 'function foo() {\n return 42;\n}\n',
952
+ },
953
+ ],
921
954
  });
922
955
  const parsed = JSON.parse(result);
923
956
  t.true(parsed.output[0].success);
@@ -925,19 +958,21 @@ test.serial('execute gap match works with relaxed whitespace matching in segment
925
958
  t.is(updated, 'function foo() {\n return 42;\n}\n');
926
959
  });
927
960
  });
928
- test.serial('needsApproval handles gap match in edit mode', async (t) => {
961
+ test.serial('needsApproval handles gap match', async (t) => {
929
962
  await withTempDir(async (dir) => {
930
- const tool = createTool(createMockSettingsService({ app: { editMode: true } }));
963
+ const tool = createTool(createMockSettingsService());
931
964
  const filePath = 'content.txt';
932
965
  const absPath = path.join(dir, filePath);
933
966
  await fs.writeFile(absPath, 'start\nmiddle\nend\n');
934
967
  const result = await tool.needsApproval({
935
968
  path: filePath,
936
- search_content: 'start\n<...>\nend',
937
- replace_content: 'replaced',
938
- replace_all: false,
969
+ replacements: [
970
+ {
971
+ search_content: 'start\n<...>\nend',
972
+ replace_content: 'replaced',
973
+ },
974
+ ],
939
975
  });
940
- // In edit mode with a unique gap match, should auto-approve
941
976
  t.false(result);
942
977
  });
943
978
  });