@kenkaiiii/ggcoder 5.49.4 → 5.49.6

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 (991) hide show
  1. package/dist/app-sidecar.js +3 -1
  2. package/dist/app-sidecar.js.map +1 -1
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +4 -1
  5. package/dist/cli.js.map +1 -1
  6. package/dist/core/agent-session.d.ts.map +1 -1
  7. package/dist/core/agent-session.js +1 -0
  8. package/dist/core/agent-session.js.map +1 -1
  9. package/dist/core/lsp/edit-telemetry.d.ts +27 -0
  10. package/dist/core/lsp/edit-telemetry.d.ts.map +1 -0
  11. package/dist/core/lsp/edit-telemetry.js +50 -0
  12. package/dist/core/lsp/edit-telemetry.js.map +1 -0
  13. package/dist/core/lsp/manager.d.ts +24 -1
  14. package/dist/core/lsp/manager.d.ts.map +1 -1
  15. package/dist/core/lsp/manager.js +53 -2
  16. package/dist/core/lsp/manager.js.map +1 -1
  17. package/dist/core/mcp/content.d.ts +5 -0
  18. package/dist/core/mcp/content.d.ts.map +1 -1
  19. package/dist/core/mcp/content.js +20 -2
  20. package/dist/core/mcp/content.js.map +1 -1
  21. package/dist/core/sandbox.d.ts +17 -1
  22. package/dist/core/sandbox.d.ts.map +1 -1
  23. package/dist/core/sandbox.js +74 -8
  24. package/dist/core/sandbox.js.map +1 -1
  25. package/dist/core/settings-manager.d.ts +3 -2
  26. package/dist/core/settings-manager.d.ts.map +1 -1
  27. package/dist/core/settings-manager.js +10 -0
  28. package/dist/core/settings-manager.js.map +1 -1
  29. package/dist/tools/edit.d.ts +2 -1
  30. package/dist/tools/edit.d.ts.map +1 -1
  31. package/dist/tools/edit.js +21 -5
  32. package/dist/tools/edit.js.map +1 -1
  33. package/dist/tools/index.d.ts.map +1 -1
  34. package/dist/tools/index.js +1 -1
  35. package/dist/tools/index.js.map +1 -1
  36. package/dist/tools/web-fetch.d.ts.map +1 -1
  37. package/dist/tools/web-fetch.js +28 -4
  38. package/dist/tools/web-fetch.js.map +1 -1
  39. package/dist/tools/write.d.ts +1 -1
  40. package/dist/tools/write.d.ts.map +1 -1
  41. package/dist/tools/write.js +1 -1
  42. package/dist/tools/write.js.map +1 -1
  43. package/dist/ui/utils/text-utils.d.ts +0 -6
  44. package/dist/ui/utils/text-utils.d.ts.map +1 -1
  45. package/dist/ui/utils/text-utils.js +8 -3
  46. package/dist/ui/utils/text-utils.js.map +1 -1
  47. package/dist/utils/text.d.ts +41 -0
  48. package/dist/utils/text.d.ts.map +1 -1
  49. package/dist/utils/text.js +46 -0
  50. package/dist/utils/text.js.map +1 -1
  51. package/package.json +6 -10
  52. package/dist/app-sidecar-auth-broadcast.test.d.ts +0 -2
  53. package/dist/app-sidecar-auth-broadcast.test.d.ts.map +0 -1
  54. package/dist/app-sidecar-auth-broadcast.test.js +0 -383
  55. package/dist/app-sidecar-auth-broadcast.test.js.map +0 -1
  56. package/dist/app-sidecar-sessions.test.d.ts +0 -2
  57. package/dist/app-sidecar-sessions.test.d.ts.map +0 -1
  58. package/dist/app-sidecar-sessions.test.js +0 -178
  59. package/dist/app-sidecar-sessions.test.js.map +0 -1
  60. package/dist/chat-agents/general.test.d.ts +0 -2
  61. package/dist/chat-agents/general.test.d.ts.map +0 -1
  62. package/dist/chat-agents/general.test.js +0 -53
  63. package/dist/chat-agents/general.test.js.map +0 -1
  64. package/dist/chat-agents/jiwa.test.d.ts +0 -2
  65. package/dist/chat-agents/jiwa.test.d.ts.map +0 -1
  66. package/dist/chat-agents/jiwa.test.js +0 -66
  67. package/dist/chat-agents/jiwa.test.js.map +0 -1
  68. package/dist/chat-agents/memory.test.d.ts +0 -2
  69. package/dist/chat-agents/memory.test.d.ts.map +0 -1
  70. package/dist/chat-agents/memory.test.js +0 -165
  71. package/dist/chat-agents/memory.test.js.map +0 -1
  72. package/dist/chat-agents/specialists.test.d.ts +0 -2
  73. package/dist/chat-agents/specialists.test.d.ts.map +0 -1
  74. package/dist/chat-agents/specialists.test.js +0 -98
  75. package/dist/chat-agents/specialists.test.js.map +0 -1
  76. package/dist/cli/command-routing.test.d.ts +0 -2
  77. package/dist/cli/command-routing.test.d.ts.map +0 -1
  78. package/dist/cli/command-routing.test.js +0 -60
  79. package/dist/cli/command-routing.test.js.map +0 -1
  80. package/dist/config.test.d.ts +0 -2
  81. package/dist/config.test.d.ts.map +0 -1
  82. package/dist/config.test.js +0 -148
  83. package/dist/config.test.js.map +0 -1
  84. package/dist/core/agent-mcp-passthrough.test.d.ts +0 -2
  85. package/dist/core/agent-mcp-passthrough.test.d.ts.map +0 -1
  86. package/dist/core/agent-mcp-passthrough.test.js +0 -61
  87. package/dist/core/agent-mcp-passthrough.test.js.map +0 -1
  88. package/dist/core/agent-notifications.test.d.ts +0 -2
  89. package/dist/core/agent-notifications.test.d.ts.map +0 -1
  90. package/dist/core/agent-notifications.test.js +0 -97
  91. package/dist/core/agent-notifications.test.js.map +0 -1
  92. package/dist/core/agent-session-add-dir.test.d.ts +0 -2
  93. package/dist/core/agent-session-add-dir.test.d.ts.map +0 -1
  94. package/dist/core/agent-session-add-dir.test.js +0 -110
  95. package/dist/core/agent-session-add-dir.test.js.map +0 -1
  96. package/dist/core/agent-session-checkpoint-flush.test.d.ts +0 -2
  97. package/dist/core/agent-session-checkpoint-flush.test.d.ts.map +0 -1
  98. package/dist/core/agent-session-checkpoint-flush.test.js +0 -201
  99. package/dist/core/agent-session-checkpoint-flush.test.js.map +0 -1
  100. package/dist/core/agent-session-compaction.test.d.ts +0 -2
  101. package/dist/core/agent-session-compaction.test.d.ts.map +0 -1
  102. package/dist/core/agent-session-compaction.test.js +0 -1157
  103. package/dist/core/agent-session-compaction.test.js.map +0 -1
  104. package/dist/core/agent-session-crash-durability.test.d.ts +0 -2
  105. package/dist/core/agent-session-crash-durability.test.d.ts.map +0 -1
  106. package/dist/core/agent-session-crash-durability.test.js +0 -102
  107. package/dist/core/agent-session-crash-durability.test.js.map +0 -1
  108. package/dist/core/agent-session-marker-anchors.test.d.ts +0 -2
  109. package/dist/core/agent-session-marker-anchors.test.d.ts.map +0 -1
  110. package/dist/core/agent-session-marker-anchors.test.js +0 -326
  111. package/dist/core/agent-session-marker-anchors.test.js.map +0 -1
  112. package/dist/core/agent-session-memory-tail.test.d.ts +0 -2
  113. package/dist/core/agent-session-memory-tail.test.d.ts.map +0 -1
  114. package/dist/core/agent-session-memory-tail.test.js +0 -119
  115. package/dist/core/agent-session-memory-tail.test.js.map +0 -1
  116. package/dist/core/agent-session-model-switch.test.d.ts +0 -2
  117. package/dist/core/agent-session-model-switch.test.d.ts.map +0 -1
  118. package/dist/core/agent-session-model-switch.test.js +0 -161
  119. package/dist/core/agent-session-model-switch.test.js.map +0 -1
  120. package/dist/core/agent-session-notifications.test.d.ts +0 -2
  121. package/dist/core/agent-session-notifications.test.d.ts.map +0 -1
  122. package/dist/core/agent-session-notifications.test.js +0 -114
  123. package/dist/core/agent-session-notifications.test.js.map +0 -1
  124. package/dist/core/agent-session-pre-init-arming.test.d.ts +0 -2
  125. package/dist/core/agent-session-pre-init-arming.test.d.ts.map +0 -1
  126. package/dist/core/agent-session-pre-init-arming.test.js +0 -60
  127. package/dist/core/agent-session-pre-init-arming.test.js.map +0 -1
  128. package/dist/core/agent-session-process-gate.test.d.ts +0 -2
  129. package/dist/core/agent-session-process-gate.test.d.ts.map +0 -1
  130. package/dist/core/agent-session-process-gate.test.js +0 -98
  131. package/dist/core/agent-session-process-gate.test.js.map +0 -1
  132. package/dist/core/agent-session-queue.test.d.ts +0 -2
  133. package/dist/core/agent-session-queue.test.d.ts.map +0 -1
  134. package/dist/core/agent-session-queue.test.js +0 -184
  135. package/dist/core/agent-session-queue.test.js.map +0 -1
  136. package/dist/core/agent-session-review-coverage.test.d.ts +0 -2
  137. package/dist/core/agent-session-review-coverage.test.d.ts.map +0 -1
  138. package/dist/core/agent-session-review-coverage.test.js +0 -191
  139. package/dist/core/agent-session-review-coverage.test.js.map +0 -1
  140. package/dist/core/agent-session-slash-restore.test.d.ts +0 -2
  141. package/dist/core/agent-session-slash-restore.test.d.ts.map +0 -1
  142. package/dist/core/agent-session-slash-restore.test.js +0 -121
  143. package/dist/core/agent-session-slash-restore.test.js.map +0 -1
  144. package/dist/core/agent-session-subagent-policy.test.d.ts +0 -2
  145. package/dist/core/agent-session-subagent-policy.test.d.ts.map +0 -1
  146. package/dist/core/agent-session-subagent-policy.test.js +0 -40
  147. package/dist/core/agent-session-subagent-policy.test.js.map +0 -1
  148. package/dist/core/agent-session-tool-result-policy.test.d.ts +0 -2
  149. package/dist/core/agent-session-tool-result-policy.test.d.ts.map +0 -1
  150. package/dist/core/agent-session-tool-result-policy.test.js +0 -25
  151. package/dist/core/agent-session-tool-result-policy.test.js.map +0 -1
  152. package/dist/core/agent-session-tool-tiers.test.d.ts +0 -2
  153. package/dist/core/agent-session-tool-tiers.test.d.ts.map +0 -1
  154. package/dist/core/agent-session-tool-tiers.test.js +0 -138
  155. package/dist/core/agent-session-tool-tiers.test.js.map +0 -1
  156. package/dist/core/agent-session-verification-flow.test.d.ts +0 -2
  157. package/dist/core/agent-session-verification-flow.test.d.ts.map +0 -1
  158. package/dist/core/agent-session-verification-flow.test.js +0 -125
  159. package/dist/core/agent-session-verification-flow.test.js.map +0 -1
  160. package/dist/core/agent-session-verification-gate.test.d.ts +0 -2
  161. package/dist/core/agent-session-verification-gate.test.d.ts.map +0 -1
  162. package/dist/core/agent-session-verification-gate.test.js +0 -137
  163. package/dist/core/agent-session-verification-gate.test.js.map +0 -1
  164. package/dist/core/agent-tools-allowlist.test.d.ts +0 -2
  165. package/dist/core/agent-tools-allowlist.test.d.ts.map +0 -1
  166. package/dist/core/agent-tools-allowlist.test.js +0 -74
  167. package/dist/core/agent-tools-allowlist.test.js.map +0 -1
  168. package/dist/core/agents.test.d.ts +0 -2
  169. package/dist/core/agents.test.d.ts.map +0 -1
  170. package/dist/core/agents.test.js +0 -147
  171. package/dist/core/agents.test.js.map +0 -1
  172. package/dist/core/auto-update.test.d.ts +0 -2
  173. package/dist/core/auto-update.test.d.ts.map +0 -1
  174. package/dist/core/auto-update.test.js +0 -204
  175. package/dist/core/auto-update.test.js.map +0 -1
  176. package/dist/core/autopilot-cycle.test.d.ts +0 -2
  177. package/dist/core/autopilot-cycle.test.d.ts.map +0 -1
  178. package/dist/core/autopilot-cycle.test.js +0 -375
  179. package/dist/core/autopilot-cycle.test.js.map +0 -1
  180. package/dist/core/autopilot-gate.test.d.ts +0 -2
  181. package/dist/core/autopilot-gate.test.d.ts.map +0 -1
  182. package/dist/core/autopilot-gate.test.js +0 -298
  183. package/dist/core/autopilot-gate.test.js.map +0 -1
  184. package/dist/core/autopilot-verdict.test.d.ts +0 -2
  185. package/dist/core/autopilot-verdict.test.d.ts.map +0 -1
  186. package/dist/core/autopilot-verdict.test.js +0 -153
  187. package/dist/core/autopilot-verdict.test.js.map +0 -1
  188. package/dist/core/checkpoint-store.test.d.ts +0 -2
  189. package/dist/core/checkpoint-store.test.d.ts.map +0 -1
  190. package/dist/core/checkpoint-store.test.js +0 -111
  191. package/dist/core/checkpoint-store.test.js.map +0 -1
  192. package/dist/core/code-retrieval-chunkers.test.d.ts +0 -2
  193. package/dist/core/code-retrieval-chunkers.test.d.ts.map +0 -1
  194. package/dist/core/code-retrieval-chunkers.test.js +0 -203
  195. package/dist/core/code-retrieval-chunkers.test.js.map +0 -1
  196. package/dist/core/compaction/active-context.test.d.ts +0 -2
  197. package/dist/core/compaction/active-context.test.d.ts.map +0 -1
  198. package/dist/core/compaction/active-context.test.js +0 -57
  199. package/dist/core/compaction/active-context.test.js.map +0 -1
  200. package/dist/core/compaction/compactor.test.d.ts +0 -2
  201. package/dist/core/compaction/compactor.test.d.ts.map +0 -1
  202. package/dist/core/compaction/compactor.test.js +0 -1072
  203. package/dist/core/compaction/compactor.test.js.map +0 -1
  204. package/dist/core/compaction/policy.test.d.ts +0 -2
  205. package/dist/core/compaction/policy.test.d.ts.map +0 -1
  206. package/dist/core/compaction/policy.test.js +0 -35
  207. package/dist/core/compaction/policy.test.js.map +0 -1
  208. package/dist/core/compaction/query-aware-selector.test.d.ts +0 -2
  209. package/dist/core/compaction/query-aware-selector.test.d.ts.map +0 -1
  210. package/dist/core/compaction/query-aware-selector.test.js +0 -96
  211. package/dist/core/compaction/query-aware-selector.test.js.map +0 -1
  212. package/dist/core/compaction/token-estimator.test.d.ts +0 -2
  213. package/dist/core/compaction/token-estimator.test.d.ts.map +0 -1
  214. package/dist/core/compaction/token-estimator.test.js +0 -283
  215. package/dist/core/compaction/token-estimator.test.js.map +0 -1
  216. package/dist/core/compaction/tool-result-pruner.test.d.ts +0 -2
  217. package/dist/core/compaction/tool-result-pruner.test.d.ts.map +0 -1
  218. package/dist/core/compaction/tool-result-pruner.test.js +0 -320
  219. package/dist/core/compaction/tool-result-pruner.test.js.map +0 -1
  220. package/dist/core/context-limits.test.d.ts +0 -2
  221. package/dist/core/context-limits.test.d.ts.map +0 -1
  222. package/dist/core/context-limits.test.js +0 -55
  223. package/dist/core/context-limits.test.js.map +0 -1
  224. package/dist/core/continue-replay-inventory.test.d.ts +0 -2
  225. package/dist/core/continue-replay-inventory.test.d.ts.map +0 -1
  226. package/dist/core/continue-replay-inventory.test.js +0 -42
  227. package/dist/core/continue-replay-inventory.test.js.map +0 -1
  228. package/dist/core/encode-cwd.test.d.ts +0 -2
  229. package/dist/core/encode-cwd.test.d.ts.map +0 -1
  230. package/dist/core/encode-cwd.test.js +0 -80
  231. package/dist/core/encode-cwd.test.js.map +0 -1
  232. package/dist/core/event-bus.test.d.ts +0 -2
  233. package/dist/core/event-bus.test.d.ts.map +0 -1
  234. package/dist/core/event-bus.test.js +0 -33
  235. package/dist/core/event-bus.test.js.map +0 -1
  236. package/dist/core/extensions/plugin-bundles.test.d.ts +0 -2
  237. package/dist/core/extensions/plugin-bundles.test.d.ts.map +0 -1
  238. package/dist/core/extensions/plugin-bundles.test.js +0 -110
  239. package/dist/core/extensions/plugin-bundles.test.js.map +0 -1
  240. package/dist/core/foreign-session-import.test.d.ts +0 -2
  241. package/dist/core/foreign-session-import.test.d.ts.map +0 -1
  242. package/dist/core/foreign-session-import.test.js +0 -220
  243. package/dist/core/foreign-session-import.test.js.map +0 -1
  244. package/dist/core/hashline-edit-benchmark.test.d.ts +0 -2
  245. package/dist/core/hashline-edit-benchmark.test.d.ts.map +0 -1
  246. package/dist/core/hashline-edit-benchmark.test.js +0 -190
  247. package/dist/core/hashline-edit-benchmark.test.js.map +0 -1
  248. package/dist/core/ideal-review.test.d.ts +0 -2
  249. package/dist/core/ideal-review.test.d.ts.map +0 -1
  250. package/dist/core/ideal-review.test.js +0 -242
  251. package/dist/core/ideal-review.test.js.map +0 -1
  252. package/dist/core/input-normalization.test.d.ts +0 -2
  253. package/dist/core/input-normalization.test.d.ts.map +0 -1
  254. package/dist/core/input-normalization.test.js +0 -75
  255. package/dist/core/input-normalization.test.js.map +0 -1
  256. package/dist/core/json-mode-flag-parity.test.d.ts +0 -2
  257. package/dist/core/json-mode-flag-parity.test.d.ts.map +0 -1
  258. package/dist/core/json-mode-flag-parity.test.js +0 -66
  259. package/dist/core/json-mode-flag-parity.test.js.map +0 -1
  260. package/dist/core/ken-context.test.d.ts +0 -2
  261. package/dist/core/ken-context.test.d.ts.map +0 -1
  262. package/dist/core/ken-context.test.js +0 -342
  263. package/dist/core/ken-context.test.js.map +0 -1
  264. package/dist/core/ken-model.test.d.ts +0 -2
  265. package/dist/core/ken-model.test.d.ts.map +0 -1
  266. package/dist/core/ken-model.test.js +0 -51
  267. package/dist/core/ken-model.test.js.map +0 -1
  268. package/dist/core/ken-prompt.test.d.ts +0 -2
  269. package/dist/core/ken-prompt.test.d.ts.map +0 -1
  270. package/dist/core/ken-prompt.test.js +0 -191
  271. package/dist/core/ken-prompt.test.js.map +0 -1
  272. package/dist/core/language-detector.test.d.ts +0 -2
  273. package/dist/core/language-detector.test.d.ts.map +0 -1
  274. package/dist/core/language-detector.test.js +0 -109
  275. package/dist/core/language-detector.test.js.map +0 -1
  276. package/dist/core/local-endpoint-store.test.d.ts +0 -2
  277. package/dist/core/local-endpoint-store.test.d.ts.map +0 -1
  278. package/dist/core/local-endpoint-store.test.js +0 -123
  279. package/dist/core/local-endpoint-store.test.js.map +0 -1
  280. package/dist/core/loop-breaker.test.d.ts +0 -2
  281. package/dist/core/loop-breaker.test.d.ts.map +0 -1
  282. package/dist/core/loop-breaker.test.js +0 -238
  283. package/dist/core/loop-breaker.test.js.map +0 -1
  284. package/dist/core/lsp/client-navigation.test.d.ts +0 -2
  285. package/dist/core/lsp/client-navigation.test.d.ts.map +0 -1
  286. package/dist/core/lsp/client-navigation.test.js +0 -135
  287. package/dist/core/lsp/client-navigation.test.js.map +0 -1
  288. package/dist/core/lsp/format.test.d.ts +0 -2
  289. package/dist/core/lsp/format.test.d.ts.map +0 -1
  290. package/dist/core/lsp/format.test.js +0 -56
  291. package/dist/core/lsp/format.test.js.map +0 -1
  292. package/dist/core/lsp/integration.test.d.ts +0 -2
  293. package/dist/core/lsp/integration.test.d.ts.map +0 -1
  294. package/dist/core/lsp/integration.test.js +0 -60
  295. package/dist/core/lsp/integration.test.js.map +0 -1
  296. package/dist/core/lsp/jsonrpc.test.d.ts +0 -2
  297. package/dist/core/lsp/jsonrpc.test.d.ts.map +0 -1
  298. package/dist/core/lsp/jsonrpc.test.js +0 -127
  299. package/dist/core/lsp/jsonrpc.test.js.map +0 -1
  300. package/dist/core/lsp/manager-navigation.test.d.ts +0 -2
  301. package/dist/core/lsp/manager-navigation.test.d.ts.map +0 -1
  302. package/dist/core/lsp/manager-navigation.test.js +0 -121
  303. package/dist/core/lsp/manager-navigation.test.js.map +0 -1
  304. package/dist/core/lsp/manager.test.d.ts +0 -2
  305. package/dist/core/lsp/manager.test.d.ts.map +0 -1
  306. package/dist/core/lsp/manager.test.js +0 -220
  307. package/dist/core/lsp/manager.test.js.map +0 -1
  308. package/dist/core/lsp/pool.test.d.ts +0 -2
  309. package/dist/core/lsp/pool.test.d.ts.map +0 -1
  310. package/dist/core/lsp/pool.test.js +0 -286
  311. package/dist/core/lsp/pool.test.js.map +0 -1
  312. package/dist/core/lsp/servers.test.d.ts +0 -2
  313. package/dist/core/lsp/servers.test.d.ts.map +0 -1
  314. package/dist/core/lsp/servers.test.js +0 -67
  315. package/dist/core/lsp/servers.test.js.map +0 -1
  316. package/dist/core/lsp/uri.test.d.ts +0 -2
  317. package/dist/core/lsp/uri.test.d.ts.map +0 -1
  318. package/dist/core/lsp/uri.test.js +0 -56
  319. package/dist/core/lsp/uri.test.js.map +0 -1
  320. package/dist/core/lsp/windows.test.d.ts +0 -2
  321. package/dist/core/lsp/windows.test.d.ts.map +0 -1
  322. package/dist/core/lsp/windows.test.js +0 -239
  323. package/dist/core/lsp/windows.test.js.map +0 -1
  324. package/dist/core/mcp/catalog-cache.test.d.ts +0 -2
  325. package/dist/core/mcp/catalog-cache.test.d.ts.map +0 -1
  326. package/dist/core/mcp/catalog-cache.test.js +0 -99
  327. package/dist/core/mcp/catalog-cache.test.js.map +0 -1
  328. package/dist/core/mcp/client-session-recovery.test.d.ts +0 -2
  329. package/dist/core/mcp/client-session-recovery.test.d.ts.map +0 -1
  330. package/dist/core/mcp/client-session-recovery.test.js +0 -231
  331. package/dist/core/mcp/client-session-recovery.test.js.map +0 -1
  332. package/dist/core/mcp/content.test.d.ts +0 -2
  333. package/dist/core/mcp/content.test.d.ts.map +0 -1
  334. package/dist/core/mcp/content.test.js +0 -135
  335. package/dist/core/mcp/content.test.js.map +0 -1
  336. package/dist/core/mcp/defaults.test.d.ts +0 -2
  337. package/dist/core/mcp/defaults.test.d.ts.map +0 -1
  338. package/dist/core/mcp/defaults.test.js +0 -60
  339. package/dist/core/mcp/defaults.test.js.map +0 -1
  340. package/dist/core/mcp/elicitation.test.d.ts +0 -2
  341. package/dist/core/mcp/elicitation.test.d.ts.map +0 -1
  342. package/dist/core/mcp/elicitation.test.js +0 -158
  343. package/dist/core/mcp/elicitation.test.js.map +0 -1
  344. package/dist/core/mcp/legacy-negotiation.test.d.ts +0 -2
  345. package/dist/core/mcp/legacy-negotiation.test.d.ts.map +0 -1
  346. package/dist/core/mcp/legacy-negotiation.test.js +0 -80
  347. package/dist/core/mcp/legacy-negotiation.test.js.map +0 -1
  348. package/dist/core/mcp/loopback.test.d.ts +0 -2
  349. package/dist/core/mcp/loopback.test.d.ts.map +0 -1
  350. package/dist/core/mcp/loopback.test.js +0 -87
  351. package/dist/core/mcp/loopback.test.js.map +0 -1
  352. package/dist/core/mcp/oauth-store.test.d.ts +0 -2
  353. package/dist/core/mcp/oauth-store.test.d.ts.map +0 -1
  354. package/dist/core/mcp/oauth-store.test.js +0 -94
  355. package/dist/core/mcp/oauth-store.test.js.map +0 -1
  356. package/dist/core/mcp/parse-add-command.test.d.ts +0 -2
  357. package/dist/core/mcp/parse-add-command.test.d.ts.map +0 -1
  358. package/dist/core/mcp/parse-add-command.test.js +0 -81
  359. package/dist/core/mcp/parse-add-command.test.js.map +0 -1
  360. package/dist/core/mcp/resolve-stdio.test.d.ts +0 -2
  361. package/dist/core/mcp/resolve-stdio.test.d.ts.map +0 -1
  362. package/dist/core/mcp/resolve-stdio.test.js +0 -239
  363. package/dist/core/mcp/resolve-stdio.test.js.map +0 -1
  364. package/dist/core/mcp/session-elicitation-wiring.test.d.ts +0 -2
  365. package/dist/core/mcp/session-elicitation-wiring.test.d.ts.map +0 -1
  366. package/dist/core/mcp/session-elicitation-wiring.test.js +0 -138
  367. package/dist/core/mcp/session-elicitation-wiring.test.js.map +0 -1
  368. package/dist/core/mcp/shared-pool.test.d.ts +0 -2
  369. package/dist/core/mcp/shared-pool.test.d.ts.map +0 -1
  370. package/dist/core/mcp/shared-pool.test.js +0 -425
  371. package/dist/core/mcp/shared-pool.test.js.map +0 -1
  372. package/dist/core/mcp/store.test.d.ts +0 -2
  373. package/dist/core/mcp/store.test.d.ts.map +0 -1
  374. package/dist/core/mcp/store.test.js +0 -110
  375. package/dist/core/mcp/store.test.js.map +0 -1
  376. package/dist/core/mcp/when-connected.test.d.ts +0 -2
  377. package/dist/core/mcp/when-connected.test.d.ts.map +0 -1
  378. package/dist/core/mcp/when-connected.test.js +0 -46
  379. package/dist/core/mcp/when-connected.test.js.map +0 -1
  380. package/dist/core/message-images.test.d.ts +0 -2
  381. package/dist/core/message-images.test.d.ts.map +0 -1
  382. package/dist/core/message-images.test.js +0 -62
  383. package/dist/core/message-images.test.js.map +0 -1
  384. package/dist/core/network-guard.test.d.ts +0 -2
  385. package/dist/core/network-guard.test.d.ts.map +0 -1
  386. package/dist/core/network-guard.test.js +0 -72
  387. package/dist/core/network-guard.test.js.map +0 -1
  388. package/dist/core/persistent-shell.test.d.ts +0 -2
  389. package/dist/core/persistent-shell.test.d.ts.map +0 -1
  390. package/dist/core/persistent-shell.test.js +0 -84
  391. package/dist/core/persistent-shell.test.js.map +0 -1
  392. package/dist/core/process-gate.test.d.ts +0 -2
  393. package/dist/core/process-gate.test.d.ts.map +0 -1
  394. package/dist/core/process-gate.test.js +0 -87
  395. package/dist/core/process-gate.test.js.map +0 -1
  396. package/dist/core/process-manager-dev-server-repro.test.d.ts +0 -2
  397. package/dist/core/process-manager-dev-server-repro.test.d.ts.map +0 -1
  398. package/dist/core/process-manager-dev-server-repro.test.js +0 -225
  399. package/dist/core/process-manager-dev-server-repro.test.js.map +0 -1
  400. package/dist/core/process-manager-notifications.test.d.ts +0 -2
  401. package/dist/core/process-manager-notifications.test.d.ts.map +0 -1
  402. package/dist/core/process-manager-notifications.test.js +0 -245
  403. package/dist/core/process-manager-notifications.test.js.map +0 -1
  404. package/dist/core/process-manager-wake.test.d.ts +0 -2
  405. package/dist/core/process-manager-wake.test.d.ts.map +0 -1
  406. package/dist/core/process-manager-wake.test.js +0 -100
  407. package/dist/core/process-manager-wake.test.js.map +0 -1
  408. package/dist/core/progress/engine.test.d.ts +0 -2
  409. package/dist/core/progress/engine.test.d.ts.map +0 -1
  410. package/dist/core/progress/engine.test.js +0 -136
  411. package/dist/core/progress/engine.test.js.map +0 -1
  412. package/dist/core/progress/git-xp.test.d.ts +0 -2
  413. package/dist/core/progress/git-xp.test.d.ts.map +0 -1
  414. package/dist/core/progress/git-xp.test.js +0 -88
  415. package/dist/core/progress/git-xp.test.js.map +0 -1
  416. package/dist/core/progress/ranks.test.d.ts +0 -2
  417. package/dist/core/progress/ranks.test.d.ts.map +0 -1
  418. package/dist/core/progress/ranks.test.js +0 -100
  419. package/dist/core/progress/ranks.test.js.map +0 -1
  420. package/dist/core/progress/rebuild.test.d.ts +0 -2
  421. package/dist/core/progress/rebuild.test.d.ts.map +0 -1
  422. package/dist/core/progress/rebuild.test.js +0 -103
  423. package/dist/core/progress/rebuild.test.js.map +0 -1
  424. package/dist/core/progress/store.test.d.ts +0 -2
  425. package/dist/core/progress/store.test.d.ts.map +0 -1
  426. package/dist/core/progress/store.test.js +0 -108
  427. package/dist/core/progress/store.test.js.map +0 -1
  428. package/dist/core/project-discovery.test.d.ts +0 -2
  429. package/dist/core/project-discovery.test.d.ts.map +0 -1
  430. package/dist/core/project-discovery.test.js +0 -519
  431. package/dist/core/project-discovery.test.js.map +0 -1
  432. package/dist/core/prompt-commands.test.d.ts +0 -2
  433. package/dist/core/prompt-commands.test.d.ts.map +0 -1
  434. package/dist/core/prompt-commands.test.js +0 -180
  435. package/dist/core/prompt-commands.test.js.map +0 -1
  436. package/dist/core/provider-cache.e2e.test.d.ts +0 -2
  437. package/dist/core/provider-cache.e2e.test.d.ts.map +0 -1
  438. package/dist/core/provider-cache.e2e.test.js +0 -125
  439. package/dist/core/provider-cache.e2e.test.js.map +0 -1
  440. package/dist/core/radio.test.d.ts +0 -2
  441. package/dist/core/radio.test.d.ts.map +0 -1
  442. package/dist/core/radio.test.js +0 -117
  443. package/dist/core/radio.test.js.map +0 -1
  444. package/dist/core/regrounding.test.d.ts +0 -2
  445. package/dist/core/regrounding.test.d.ts.map +0 -1
  446. package/dist/core/regrounding.test.js +0 -38
  447. package/dist/core/regrounding.test.js.map +0 -1
  448. package/dist/core/resolve-start.test.d.ts +0 -2
  449. package/dist/core/resolve-start.test.d.ts.map +0 -1
  450. package/dist/core/resolve-start.test.js +0 -68
  451. package/dist/core/resolve-start.test.js.map +0 -1
  452. package/dist/core/run-claim.test.d.ts +0 -2
  453. package/dist/core/run-claim.test.d.ts.map +0 -1
  454. package/dist/core/run-claim.test.js +0 -107
  455. package/dist/core/run-claim.test.js.map +0 -1
  456. package/dist/core/run-journal.test.d.ts +0 -2
  457. package/dist/core/run-journal.test.d.ts.map +0 -1
  458. package/dist/core/run-journal.test.js +0 -195
  459. package/dist/core/run-journal.test.js.map +0 -1
  460. package/dist/core/run-lifecycle.test.d.ts +0 -2
  461. package/dist/core/run-lifecycle.test.d.ts.map +0 -1
  462. package/dist/core/run-lifecycle.test.js +0 -64
  463. package/dist/core/run-lifecycle.test.js.map +0 -1
  464. package/dist/core/sandbox-feedback.test.d.ts +0 -2
  465. package/dist/core/sandbox-feedback.test.d.ts.map +0 -1
  466. package/dist/core/sandbox-feedback.test.js +0 -32
  467. package/dist/core/sandbox-feedback.test.js.map +0 -1
  468. package/dist/core/sandbox.test.d.ts +0 -2
  469. package/dist/core/sandbox.test.d.ts.map +0 -1
  470. package/dist/core/sandbox.test.js +0 -221
  471. package/dist/core/sandbox.test.js.map +0 -1
  472. package/dist/core/semantic-search-benchmark.test.d.ts +0 -2
  473. package/dist/core/semantic-search-benchmark.test.d.ts.map +0 -1
  474. package/dist/core/semantic-search-benchmark.test.js +0 -89
  475. package/dist/core/semantic-search-benchmark.test.js.map +0 -1
  476. package/dist/core/session-compaction.test.d.ts +0 -2
  477. package/dist/core/session-compaction.test.d.ts.map +0 -1
  478. package/dist/core/session-compaction.test.js +0 -92
  479. package/dist/core/session-compaction.test.js.map +0 -1
  480. package/dist/core/session-export.test.d.ts +0 -2
  481. package/dist/core/session-export.test.d.ts.map +0 -1
  482. package/dist/core/session-export.test.js +0 -353
  483. package/dist/core/session-export.test.js.map +0 -1
  484. package/dist/core/session-history.test.d.ts +0 -2
  485. package/dist/core/session-history.test.d.ts.map +0 -1
  486. package/dist/core/session-history.test.js +0 -272
  487. package/dist/core/session-history.test.js.map +0 -1
  488. package/dist/core/session-injections.test.d.ts +0 -2
  489. package/dist/core/session-injections.test.d.ts.map +0 -1
  490. package/dist/core/session-injections.test.js +0 -117
  491. package/dist/core/session-injections.test.js.map +0 -1
  492. package/dist/core/session-manager.test.d.ts +0 -2
  493. package/dist/core/session-manager.test.d.ts.map +0 -1
  494. package/dist/core/session-manager.test.js +0 -571
  495. package/dist/core/session-manager.test.js.map +0 -1
  496. package/dist/core/session-notification-visibility.test.d.ts +0 -2
  497. package/dist/core/session-notification-visibility.test.d.ts.map +0 -1
  498. package/dist/core/session-notification-visibility.test.js +0 -113
  499. package/dist/core/session-notification-visibility.test.js.map +0 -1
  500. package/dist/core/session-reconstructability.test.d.ts +0 -2
  501. package/dist/core/session-reconstructability.test.d.ts.map +0 -1
  502. package/dist/core/session-reconstructability.test.js +0 -105
  503. package/dist/core/session-reconstructability.test.js.map +0 -1
  504. package/dist/core/session-restore-display.test.d.ts +0 -2
  505. package/dist/core/session-restore-display.test.d.ts.map +0 -1
  506. package/dist/core/session-restore-display.test.js +0 -103
  507. package/dist/core/session-restore-display.test.js.map +0 -1
  508. package/dist/core/session-storage-fd-leak.test.d.ts +0 -2
  509. package/dist/core/session-storage-fd-leak.test.d.ts.map +0 -1
  510. package/dist/core/session-storage-fd-leak.test.js +0 -116
  511. package/dist/core/session-storage-fd-leak.test.js.map +0 -1
  512. package/dist/core/session-storage.test.d.ts +0 -2
  513. package/dist/core/session-storage.test.d.ts.map +0 -1
  514. package/dist/core/session-storage.test.js +0 -277
  515. package/dist/core/session-storage.test.js.map +0 -1
  516. package/dist/core/setup-history.test.d.ts +0 -2
  517. package/dist/core/setup-history.test.d.ts.map +0 -1
  518. package/dist/core/setup-history.test.js +0 -59
  519. package/dist/core/setup-history.test.js.map +0 -1
  520. package/dist/core/shell.test.d.ts +0 -2
  521. package/dist/core/shell.test.d.ts.map +0 -1
  522. package/dist/core/shell.test.js +0 -87
  523. package/dist/core/shell.test.js.map +0 -1
  524. package/dist/core/shutdown.test.d.ts +0 -2
  525. package/dist/core/shutdown.test.d.ts.map +0 -1
  526. package/dist/core/shutdown.test.js +0 -160
  527. package/dist/core/shutdown.test.js.map +0 -1
  528. package/dist/core/sidecar-error-reporter.test.d.ts +0 -2
  529. package/dist/core/sidecar-error-reporter.test.d.ts.map +0 -1
  530. package/dist/core/sidecar-error-reporter.test.js +0 -61
  531. package/dist/core/sidecar-error-reporter.test.js.map +0 -1
  532. package/dist/core/skills-routing.test.d.ts +0 -2
  533. package/dist/core/skills-routing.test.d.ts.map +0 -1
  534. package/dist/core/skills-routing.test.js +0 -310
  535. package/dist/core/skills-routing.test.js.map +0 -1
  536. package/dist/core/slash-commands.test.d.ts +0 -2
  537. package/dist/core/slash-commands.test.d.ts.map +0 -1
  538. package/dist/core/slash-commands.test.js +0 -59
  539. package/dist/core/slash-commands.test.js.map +0 -1
  540. package/dist/core/source-maps.test.d.ts +0 -2
  541. package/dist/core/source-maps.test.d.ts.map +0 -1
  542. package/dist/core/source-maps.test.js +0 -175
  543. package/dist/core/source-maps.test.js.map +0 -1
  544. package/dist/core/speed-benchmark.test.d.ts +0 -2
  545. package/dist/core/speed-benchmark.test.d.ts.map +0 -1
  546. package/dist/core/speed-benchmark.test.js +0 -102
  547. package/dist/core/speed-benchmark.test.js.map +0 -1
  548. package/dist/core/subagent-manager.test.d.ts +0 -2
  549. package/dist/core/subagent-manager.test.d.ts.map +0 -1
  550. package/dist/core/subagent-manager.test.js +0 -536
  551. package/dist/core/subagent-manager.test.js.map +0 -1
  552. package/dist/core/subagent-store.test.d.ts +0 -2
  553. package/dist/core/subagent-store.test.d.ts.map +0 -1
  554. package/dist/core/subagent-store.test.js +0 -106
  555. package/dist/core/subagent-store.test.js.map +0 -1
  556. package/dist/core/subagent-turn-record.test.d.ts +0 -2
  557. package/dist/core/subagent-turn-record.test.d.ts.map +0 -1
  558. package/dist/core/subagent-turn-record.test.js +0 -70
  559. package/dist/core/subagent-turn-record.test.js.map +0 -1
  560. package/dist/core/verification-evidence.test.d.ts +0 -2
  561. package/dist/core/verification-evidence.test.d.ts.map +0 -1
  562. package/dist/core/verification-evidence.test.js +0 -103
  563. package/dist/core/verification-evidence.test.js.map +0 -1
  564. package/dist/core/verification-gate.test.d.ts +0 -2
  565. package/dist/core/verification-gate.test.d.ts.map +0 -1
  566. package/dist/core/verification-gate.test.js +0 -138
  567. package/dist/core/verification-gate.test.js.map +0 -1
  568. package/dist/core/verify-commands.test.d.ts +0 -2
  569. package/dist/core/verify-commands.test.d.ts.map +0 -1
  570. package/dist/core/verify-commands.test.js +0 -81
  571. package/dist/core/verify-commands.test.js.map +0 -1
  572. package/dist/core/workspace-guard.test.d.ts +0 -2
  573. package/dist/core/workspace-guard.test.d.ts.map +0 -1
  574. package/dist/core/workspace-guard.test.js +0 -107
  575. package/dist/core/workspace-guard.test.js.map +0 -1
  576. package/dist/hf-pull.test.d.ts +0 -2
  577. package/dist/hf-pull.test.d.ts.map +0 -1
  578. package/dist/hf-pull.test.js +0 -112
  579. package/dist/hf-pull.test.js.map +0 -1
  580. package/dist/modes/acp-mode.test.d.ts +0 -2
  581. package/dist/modes/acp-mode.test.d.ts.map +0 -1
  582. package/dist/modes/acp-mode.test.js +0 -1067
  583. package/dist/modes/acp-mode.test.js.map +0 -1
  584. package/dist/modes/json-mode.test.d.ts +0 -2
  585. package/dist/modes/json-mode.test.d.ts.map +0 -1
  586. package/dist/modes/json-mode.test.js +0 -84
  587. package/dist/modes/json-mode.test.js.map +0 -1
  588. package/dist/modes/subagent-worker-mode.test.d.ts +0 -2
  589. package/dist/modes/subagent-worker-mode.test.d.ts.map +0 -1
  590. package/dist/modes/subagent-worker-mode.test.js +0 -52
  591. package/dist/modes/subagent-worker-mode.test.js.map +0 -1
  592. package/dist/session.test.d.ts +0 -2
  593. package/dist/session.test.d.ts.map +0 -1
  594. package/dist/session.test.js +0 -35
  595. package/dist/session.test.js.map +0 -1
  596. package/dist/system-prompt.test.d.ts +0 -2
  597. package/dist/system-prompt.test.d.ts.map +0 -1
  598. package/dist/system-prompt.test.js +0 -684
  599. package/dist/system-prompt.test.js.map +0 -1
  600. package/dist/system-prompt.tiering.test.d.ts +0 -2
  601. package/dist/system-prompt.tiering.test.d.ts.map +0 -1
  602. package/dist/system-prompt.tiering.test.js +0 -112
  603. package/dist/system-prompt.tiering.test.js.map +0 -1
  604. package/dist/tools/bash.test.d.ts +0 -2
  605. package/dist/tools/bash.test.d.ts.map +0 -1
  606. package/dist/tools/bash.test.js +0 -248
  607. package/dist/tools/bash.test.js.map +0 -1
  608. package/dist/tools/checkpoint-hook.test.d.ts +0 -2
  609. package/dist/tools/checkpoint-hook.test.d.ts.map +0 -1
  610. package/dist/tools/checkpoint-hook.test.js +0 -65
  611. package/dist/tools/checkpoint-hook.test.js.map +0 -1
  612. package/dist/tools/code-nav.test.d.ts +0 -2
  613. package/dist/tools/code-nav.test.d.ts.map +0 -1
  614. package/dist/tools/code-nav.test.js +0 -136
  615. package/dist/tools/code-nav.test.js.map +0 -1
  616. package/dist/tools/code-skeleton.test.d.ts +0 -2
  617. package/dist/tools/code-skeleton.test.d.ts.map +0 -1
  618. package/dist/tools/code-skeleton.test.js +0 -115
  619. package/dist/tools/code-skeleton.test.js.map +0 -1
  620. package/dist/tools/compress-integration.test.d.ts +0 -2
  621. package/dist/tools/compress-integration.test.d.ts.map +0 -1
  622. package/dist/tools/compress-integration.test.js +0 -59
  623. package/dist/tools/compress-integration.test.js.map +0 -1
  624. package/dist/tools/compress.test.d.ts +0 -2
  625. package/dist/tools/compress.test.d.ts.map +0 -1
  626. package/dist/tools/compress.test.js +0 -60
  627. package/dist/tools/compress.test.js.map +0 -1
  628. package/dist/tools/edit-diff.test.d.ts +0 -2
  629. package/dist/tools/edit-diff.test.d.ts.map +0 -1
  630. package/dist/tools/edit-diff.test.js +0 -329
  631. package/dist/tools/edit-diff.test.js.map +0 -1
  632. package/dist/tools/edit-robustness.test.d.ts +0 -2
  633. package/dist/tools/edit-robustness.test.d.ts.map +0 -1
  634. package/dist/tools/edit-robustness.test.js +0 -417
  635. package/dist/tools/edit-robustness.test.js.map +0 -1
  636. package/dist/tools/edit.test.d.ts +0 -2
  637. package/dist/tools/edit.test.d.ts.map +0 -1
  638. package/dist/tools/edit.test.js +0 -984
  639. package/dist/tools/edit.test.js.map +0 -1
  640. package/dist/tools/exit-plan.test.d.ts +0 -2
  641. package/dist/tools/exit-plan.test.d.ts.map +0 -1
  642. package/dist/tools/exit-plan.test.js +0 -72
  643. package/dist/tools/exit-plan.test.js.map +0 -1
  644. package/dist/tools/generate-image.test.d.ts +0 -2
  645. package/dist/tools/generate-image.test.d.ts.map +0 -1
  646. package/dist/tools/generate-image.test.js +0 -240
  647. package/dist/tools/generate-image.test.js.map +0 -1
  648. package/dist/tools/grep-parity.test.d.ts +0 -2
  649. package/dist/tools/grep-parity.test.d.ts.map +0 -1
  650. package/dist/tools/grep-parity.test.js +0 -92
  651. package/dist/tools/grep-parity.test.js.map +0 -1
  652. package/dist/tools/grep-recall.test.d.ts +0 -2
  653. package/dist/tools/grep-recall.test.d.ts.map +0 -1
  654. package/dist/tools/grep-recall.test.js +0 -114
  655. package/dist/tools/grep-recall.test.js.map +0 -1
  656. package/dist/tools/grep-spawn.test.d.ts +0 -2
  657. package/dist/tools/grep-spawn.test.d.ts.map +0 -1
  658. package/dist/tools/grep-spawn.test.js +0 -66
  659. package/dist/tools/grep-spawn.test.js.map +0 -1
  660. package/dist/tools/grep.test.d.ts +0 -2
  661. package/dist/tools/grep.test.d.ts.map +0 -1
  662. package/dist/tools/grep.test.js +0 -82
  663. package/dist/tools/grep.test.js.map +0 -1
  664. package/dist/tools/html-extract.test.d.ts +0 -2
  665. package/dist/tools/html-extract.test.d.ts.map +0 -1
  666. package/dist/tools/html-extract.test.js +0 -60
  667. package/dist/tools/html-extract.test.js.map +0 -1
  668. package/dist/tools/index.test.d.ts +0 -2
  669. package/dist/tools/index.test.d.ts.map +0 -1
  670. package/dist/tools/index.test.js +0 -55
  671. package/dist/tools/index.test.js.map +0 -1
  672. package/dist/tools/overflow.test.d.ts +0 -2
  673. package/dist/tools/overflow.test.d.ts.map +0 -1
  674. package/dist/tools/overflow.test.js +0 -59
  675. package/dist/tools/overflow.test.js.map +0 -1
  676. package/dist/tools/path-utils.test.d.ts +0 -2
  677. package/dist/tools/path-utils.test.d.ts.map +0 -1
  678. package/dist/tools/path-utils.test.js +0 -110
  679. package/dist/tools/path-utils.test.js.map +0 -1
  680. package/dist/tools/pdf-extract.test.d.ts +0 -2
  681. package/dist/tools/pdf-extract.test.d.ts.map +0 -1
  682. package/dist/tools/pdf-extract.test.js +0 -15
  683. package/dist/tools/pdf-extract.test.js.map +0 -1
  684. package/dist/tools/plan-mode.test.d.ts +0 -2
  685. package/dist/tools/plan-mode.test.d.ts.map +0 -1
  686. package/dist/tools/plan-mode.test.js +0 -91
  687. package/dist/tools/plan-mode.test.js.map +0 -1
  688. package/dist/tools/read-only-bash.test.d.ts +0 -2
  689. package/dist/tools/read-only-bash.test.d.ts.map +0 -1
  690. package/dist/tools/read-only-bash.test.js +0 -96
  691. package/dist/tools/read-only-bash.test.js.map +0 -1
  692. package/dist/tools/read.test.d.ts +0 -2
  693. package/dist/tools/read.test.d.ts.map +0 -1
  694. package/dist/tools/read.test.js +0 -146
  695. package/dist/tools/read.test.js.map +0 -1
  696. package/dist/tools/screenshot.test.d.ts +0 -2
  697. package/dist/tools/screenshot.test.d.ts.map +0 -1
  698. package/dist/tools/screenshot.test.js +0 -145
  699. package/dist/tools/screenshot.test.js.map +0 -1
  700. package/dist/tools/search-code.test.d.ts +0 -2
  701. package/dist/tools/search-code.test.d.ts.map +0 -1
  702. package/dist/tools/search-code.test.js +0 -83
  703. package/dist/tools/search-code.test.js.map +0 -1
  704. package/dist/tools/source-path.test.d.ts +0 -2
  705. package/dist/tools/source-path.test.d.ts.map +0 -1
  706. package/dist/tools/source-path.test.js +0 -80
  707. package/dist/tools/source-path.test.js.map +0 -1
  708. package/dist/tools/subagent-control.test.d.ts +0 -2
  709. package/dist/tools/subagent-control.test.d.ts.map +0 -1
  710. package/dist/tools/subagent-control.test.js +0 -73
  711. package/dist/tools/subagent-control.test.js.map +0 -1
  712. package/dist/tools/subagent-shared.test.d.ts +0 -2
  713. package/dist/tools/subagent-shared.test.d.ts.map +0 -1
  714. package/dist/tools/subagent-shared.test.js +0 -83
  715. package/dist/tools/subagent-shared.test.js.map +0 -1
  716. package/dist/tools/subagent.test.d.ts +0 -2
  717. package/dist/tools/subagent.test.d.ts.map +0 -1
  718. package/dist/tools/subagent.test.js +0 -180
  719. package/dist/tools/subagent.test.js.map +0 -1
  720. package/dist/tools/task-send.test.d.ts +0 -2
  721. package/dist/tools/task-send.test.d.ts.map +0 -1
  722. package/dist/tools/task-send.test.js +0 -104
  723. package/dist/tools/task-send.test.js.map +0 -1
  724. package/dist/tools/tool-catalog.test.d.ts +0 -2
  725. package/dist/tools/tool-catalog.test.d.ts.map +0 -1
  726. package/dist/tools/tool-catalog.test.js +0 -124
  727. package/dist/tools/tool-catalog.test.js.map +0 -1
  728. package/dist/tools/tool-search.test.d.ts +0 -2
  729. package/dist/tools/tool-search.test.d.ts.map +0 -1
  730. package/dist/tools/tool-search.test.js +0 -127
  731. package/dist/tools/tool-search.test.js.map +0 -1
  732. package/dist/tools/tool-tiers.test.d.ts +0 -2
  733. package/dist/tools/tool-tiers.test.d.ts.map +0 -1
  734. package/dist/tools/tool-tiers.test.js +0 -48
  735. package/dist/tools/tool-tiers.test.js.map +0 -1
  736. package/dist/tools/truncate-utils.test.d.ts +0 -2
  737. package/dist/tools/truncate-utils.test.d.ts.map +0 -1
  738. package/dist/tools/truncate-utils.test.js +0 -93
  739. package/dist/tools/truncate-utils.test.js.map +0 -1
  740. package/dist/tools/truncate.test.d.ts +0 -2
  741. package/dist/tools/truncate.test.d.ts.map +0 -1
  742. package/dist/tools/truncate.test.js +0 -100
  743. package/dist/tools/truncate.test.js.map +0 -1
  744. package/dist/tools/web-fetch.test.d.ts +0 -2
  745. package/dist/tools/web-fetch.test.d.ts.map +0 -1
  746. package/dist/tools/web-fetch.test.js +0 -676
  747. package/dist/tools/web-fetch.test.js.map +0 -1
  748. package/dist/tools/web-search.test.d.ts +0 -2
  749. package/dist/tools/web-search.test.d.ts.map +0 -1
  750. package/dist/tools/web-search.test.js +0 -333
  751. package/dist/tools/web-search.test.js.map +0 -1
  752. package/dist/tools/write.test.d.ts +0 -2
  753. package/dist/tools/write.test.d.ts.map +0 -1
  754. package/dist/tools/write.test.js +0 -176
  755. package/dist/tools/write.test.js.map +0 -1
  756. package/dist/ui/anchor-pad-reclaim.test.d.ts +0 -2
  757. package/dist/ui/anchor-pad-reclaim.test.d.ts.map +0 -1
  758. package/dist/ui/anchor-pad-reclaim.test.js +0 -146
  759. package/dist/ui/anchor-pad-reclaim.test.js.map +0 -1
  760. package/dist/ui/app-items.test.d.ts +0 -2
  761. package/dist/ui/app-items.test.d.ts.map +0 -1
  762. package/dist/ui/app-items.test.js +0 -54
  763. package/dist/ui/app-items.test.js.map +0 -1
  764. package/dist/ui/app-state-persistence.test.d.ts +0 -2
  765. package/dist/ui/app-state-persistence.test.d.ts.map +0 -1
  766. package/dist/ui/app-state-persistence.test.js +0 -71
  767. package/dist/ui/app-state-persistence.test.js.map +0 -1
  768. package/dist/ui/assistant-stream-flush-parity.test.d.ts +0 -2
  769. package/dist/ui/assistant-stream-flush-parity.test.d.ts.map +0 -1
  770. package/dist/ui/assistant-stream-flush-parity.test.js +0 -85
  771. package/dist/ui/assistant-stream-flush-parity.test.js.map +0 -1
  772. package/dist/ui/atomic-flush-regression.test.d.ts +0 -2
  773. package/dist/ui/atomic-flush-regression.test.d.ts.map +0 -1
  774. package/dist/ui/atomic-flush-regression.test.js +0 -218
  775. package/dist/ui/atomic-flush-regression.test.js.map +0 -1
  776. package/dist/ui/chat-layout-pinning.test.d.ts +0 -2
  777. package/dist/ui/chat-layout-pinning.test.d.ts.map +0 -1
  778. package/dist/ui/chat-layout-pinning.test.js +0 -525
  779. package/dist/ui/chat-layout-pinning.test.js.map +0 -1
  780. package/dist/ui/components/ActivityIndicator.test.d.ts +0 -2
  781. package/dist/ui/components/ActivityIndicator.test.d.ts.map +0 -1
  782. package/dist/ui/components/ActivityIndicator.test.js +0 -40
  783. package/dist/ui/components/ActivityIndicator.test.js.map +0 -1
  784. package/dist/ui/components/AssistantMessage.test.d.ts +0 -2
  785. package/dist/ui/components/AssistantMessage.test.d.ts.map +0 -1
  786. package/dist/ui/components/AssistantMessage.test.js +0 -418
  787. package/dist/ui/components/AssistantMessage.test.js.map +0 -1
  788. package/dist/ui/components/Footer.test.d.ts +0 -2
  789. package/dist/ui/components/Footer.test.d.ts.map +0 -1
  790. package/dist/ui/components/Footer.test.js +0 -16
  791. package/dist/ui/components/Footer.test.js.map +0 -1
  792. package/dist/ui/components/InputArea.test.d.ts +0 -2
  793. package/dist/ui/components/InputArea.test.d.ts.map +0 -1
  794. package/dist/ui/components/InputArea.test.js +0 -95
  795. package/dist/ui/components/InputArea.test.js.map +0 -1
  796. package/dist/ui/components/PlanOverlay.test.d.ts +0 -2
  797. package/dist/ui/components/PlanOverlay.test.d.ts.map +0 -1
  798. package/dist/ui/components/PlanOverlay.test.js +0 -24
  799. package/dist/ui/components/PlanOverlay.test.js.map +0 -1
  800. package/dist/ui/components/StreamingArea.test.d.ts +0 -2
  801. package/dist/ui/components/StreamingArea.test.d.ts.map +0 -1
  802. package/dist/ui/components/StreamingArea.test.js +0 -18
  803. package/dist/ui/components/StreamingArea.test.js.map +0 -1
  804. package/dist/ui/components/UserMessage.test.d.ts +0 -2
  805. package/dist/ui/components/UserMessage.test.d.ts.map +0 -1
  806. package/dist/ui/components/UserMessage.test.js +0 -39
  807. package/dist/ui/components/UserMessage.test.js.map +0 -1
  808. package/dist/ui/components/themed-output.test.d.ts +0 -2
  809. package/dist/ui/components/themed-output.test.d.ts.map +0 -1
  810. package/dist/ui/components/themed-output.test.js +0 -111
  811. package/dist/ui/components/themed-output.test.js.map +0 -1
  812. package/dist/ui/footer-jump-regression.test.d.ts +0 -2
  813. package/dist/ui/footer-jump-regression.test.d.ts.map +0 -1
  814. package/dist/ui/footer-jump-regression.test.js +0 -224
  815. package/dist/ui/footer-jump-regression.test.js.map +0 -1
  816. package/dist/ui/footer-status-layout.test.d.ts +0 -2
  817. package/dist/ui/footer-status-layout.test.d.ts.map +0 -1
  818. package/dist/ui/footer-status-layout.test.js +0 -71
  819. package/dist/ui/footer-status-layout.test.js.map +0 -1
  820. package/dist/ui/frame-clip-regression.test.d.ts +0 -2
  821. package/dist/ui/frame-clip-regression.test.d.ts.map +0 -1
  822. package/dist/ui/frame-clip-regression.test.js +0 -215
  823. package/dist/ui/frame-clip-regression.test.js.map +0 -1
  824. package/dist/ui/hooks/stall-retry-duplicate.test.d.ts +0 -2
  825. package/dist/ui/hooks/stall-retry-duplicate.test.d.ts.map +0 -1
  826. package/dist/ui/hooks/stall-retry-duplicate.test.js +0 -94
  827. package/dist/ui/hooks/stall-retry-duplicate.test.js.map +0 -1
  828. package/dist/ui/hooks/useAgentLoop.test.d.ts +0 -2
  829. package/dist/ui/hooks/useAgentLoop.test.d.ts.map +0 -1
  830. package/dist/ui/hooks/useAgentLoop.test.js +0 -66
  831. package/dist/ui/hooks/useAgentLoop.test.js.map +0 -1
  832. package/dist/ui/hooks/useContextCompaction.test.d.ts +0 -2
  833. package/dist/ui/hooks/useContextCompaction.test.d.ts.map +0 -1
  834. package/dist/ui/hooks/useContextCompaction.test.js +0 -135
  835. package/dist/ui/hooks/useContextCompaction.test.js.map +0 -1
  836. package/dist/ui/hooks/useTranscriptHistory.sessionstore.test.d.ts +0 -2
  837. package/dist/ui/hooks/useTranscriptHistory.sessionstore.test.d.ts.map +0 -1
  838. package/dist/ui/hooks/useTranscriptHistory.sessionstore.test.js +0 -81
  839. package/dist/ui/hooks/useTranscriptHistory.sessionstore.test.js.map +0 -1
  840. package/dist/ui/hooks/useTranscriptHistory.test.d.ts +0 -2
  841. package/dist/ui/hooks/useTranscriptHistory.test.d.ts.map +0 -1
  842. package/dist/ui/hooks/useTranscriptHistory.test.js +0 -61
  843. package/dist/ui/hooks/useTranscriptHistory.test.js.map +0 -1
  844. package/dist/ui/hooks/useTranscriptScroll.test.d.ts +0 -2
  845. package/dist/ui/hooks/useTranscriptScroll.test.d.ts.map +0 -1
  846. package/dist/ui/hooks/useTranscriptScroll.test.js +0 -119
  847. package/dist/ui/hooks/useTranscriptScroll.test.js.map +0 -1
  848. package/dist/ui/live-area-clamp.test.d.ts +0 -2
  849. package/dist/ui/live-area-clamp.test.d.ts.map +0 -1
  850. package/dist/ui/live-area-clamp.test.js +0 -125
  851. package/dist/ui/live-area-clamp.test.js.map +0 -1
  852. package/dist/ui/live-area-height.test.d.ts +0 -2
  853. package/dist/ui/live-area-height.test.d.ts.map +0 -1
  854. package/dist/ui/live-area-height.test.js +0 -76
  855. package/dist/ui/live-area-height.test.js.map +0 -1
  856. package/dist/ui/live-frame-height.test.d.ts +0 -2
  857. package/dist/ui/live-frame-height.test.d.ts.map +0 -1
  858. package/dist/ui/live-frame-height.test.js +0 -116
  859. package/dist/ui/live-frame-height.test.js.map +0 -1
  860. package/dist/ui/live-item-flush.test.d.ts +0 -2
  861. package/dist/ui/live-item-flush.test.d.ts.map +0 -1
  862. package/dist/ui/live-item-flush.test.js +0 -437
  863. package/dist/ui/live-item-flush.test.js.map +0 -1
  864. package/dist/ui/long-prompt-regression-harness.test.d.ts +0 -2
  865. package/dist/ui/long-prompt-regression-harness.test.d.ts.map +0 -1
  866. package/dist/ui/long-prompt-regression-harness.test.js +0 -195
  867. package/dist/ui/long-prompt-regression-harness.test.js.map +0 -1
  868. package/dist/ui/plan-overlay.test.d.ts +0 -2
  869. package/dist/ui/plan-overlay.test.d.ts.map +0 -1
  870. package/dist/ui/plan-overlay.test.js +0 -305
  871. package/dist/ui/plan-overlay.test.js.map +0 -1
  872. package/dist/ui/queued-message.test.d.ts +0 -2
  873. package/dist/ui/queued-message.test.d.ts.map +0 -1
  874. package/dist/ui/queued-message.test.js +0 -172
  875. package/dist/ui/queued-message.test.js.map +0 -1
  876. package/dist/ui/render.test.d.ts +0 -2
  877. package/dist/ui/render.test.d.ts.map +0 -1
  878. package/dist/ui/render.test.js +0 -42
  879. package/dist/ui/render.test.js.map +0 -1
  880. package/dist/ui/scroll-stabilization.test.d.ts +0 -2
  881. package/dist/ui/scroll-stabilization.test.d.ts.map +0 -1
  882. package/dist/ui/scroll-stabilization.test.js +0 -64
  883. package/dist/ui/scroll-stabilization.test.js.map +0 -1
  884. package/dist/ui/slash-command-images.test.d.ts +0 -2
  885. package/dist/ui/slash-command-images.test.d.ts.map +0 -1
  886. package/dist/ui/slash-command-images.test.js +0 -110
  887. package/dist/ui/slash-command-images.test.js.map +0 -1
  888. package/dist/ui/startup-banner-order.test.d.ts +0 -2
  889. package/dist/ui/startup-banner-order.test.d.ts.map +0 -1
  890. package/dist/ui/startup-banner-order.test.js +0 -105
  891. package/dist/ui/startup-banner-order.test.js.map +0 -1
  892. package/dist/ui/stores/transcript-scroll-store.test.d.ts +0 -2
  893. package/dist/ui/stores/transcript-scroll-store.test.d.ts.map +0 -1
  894. package/dist/ui/stores/transcript-scroll-store.test.js +0 -73
  895. package/dist/ui/stores/transcript-scroll-store.test.js.map +0 -1
  896. package/dist/ui/streaming-flush-bounce.test.d.ts +0 -2
  897. package/dist/ui/streaming-flush-bounce.test.d.ts.map +0 -1
  898. package/dist/ui/streaming-flush-bounce.test.js +0 -177
  899. package/dist/ui/streaming-flush-bounce.test.js.map +0 -1
  900. package/dist/ui/submit-boundary-gap.test.d.ts +0 -2
  901. package/dist/ui/submit-boundary-gap.test.d.ts.map +0 -1
  902. package/dist/ui/submit-boundary-gap.test.js +0 -180
  903. package/dist/ui/submit-boundary-gap.test.js.map +0 -1
  904. package/dist/ui/terminal-history-repaint.test.d.ts +0 -2
  905. package/dist/ui/terminal-history-repaint.test.d.ts.map +0 -1
  906. package/dist/ui/terminal-history-repaint.test.js +0 -73
  907. package/dist/ui/terminal-history-repaint.test.js.map +0 -1
  908. package/dist/ui/terminal-history-retry-dedup.test.d.ts +0 -2
  909. package/dist/ui/terminal-history-retry-dedup.test.d.ts.map +0 -1
  910. package/dist/ui/terminal-history-retry-dedup.test.js +0 -61
  911. package/dist/ui/terminal-history-retry-dedup.test.js.map +0 -1
  912. package/dist/ui/terminal-history.test.d.ts +0 -2
  913. package/dist/ui/terminal-history.test.d.ts.map +0 -1
  914. package/dist/ui/terminal-history.test.js +0 -557
  915. package/dist/ui/terminal-history.test.js.map +0 -1
  916. package/dist/ui/thinking-level-cycle.test.d.ts +0 -2
  917. package/dist/ui/thinking-level-cycle.test.d.ts.map +0 -1
  918. package/dist/ui/thinking-level-cycle.test.js +0 -45
  919. package/dist/ui/thinking-level-cycle.test.js.map +0 -1
  920. package/dist/ui/tool-group-summary.test.d.ts +0 -2
  921. package/dist/ui/tool-group-summary.test.d.ts.map +0 -1
  922. package/dist/ui/tool-group-summary.test.js +0 -79
  923. package/dist/ui/tool-group-summary.test.js.map +0 -1
  924. package/dist/ui/transcript/spacing.test.d.ts +0 -2
  925. package/dist/ui/transcript/spacing.test.d.ts.map +0 -1
  926. package/dist/ui/transcript/spacing.test.js +0 -187
  927. package/dist/ui/transcript/spacing.test.js.map +0 -1
  928. package/dist/ui/transcript/transcript-lines.test.d.ts +0 -2
  929. package/dist/ui/transcript/transcript-lines.test.d.ts.map +0 -1
  930. package/dist/ui/transcript/transcript-lines.test.js +0 -76
  931. package/dist/ui/transcript/transcript-lines.test.js.map +0 -1
  932. package/dist/ui/transcript-viewport-pinning.test.d.ts +0 -2
  933. package/dist/ui/transcript-viewport-pinning.test.d.ts.map +0 -1
  934. package/dist/ui/transcript-viewport-pinning.test.js +0 -148
  935. package/dist/ui/transcript-viewport-pinning.test.js.map +0 -1
  936. package/dist/ui/tui-history-parity.test.d.ts +0 -2
  937. package/dist/ui/tui-history-parity.test.d.ts.map +0 -1
  938. package/dist/ui/tui-history-parity.test.js +0 -369
  939. package/dist/ui/tui-history-parity.test.js.map +0 -1
  940. package/dist/ui/tui-simulation.test.d.ts +0 -2
  941. package/dist/ui/tui-simulation.test.d.ts.map +0 -1
  942. package/dist/ui/tui-simulation.test.js +0 -145
  943. package/dist/ui/tui-simulation.test.js.map +0 -1
  944. package/dist/ui/tui-terminal-recorder.test.d.ts +0 -2
  945. package/dist/ui/tui-terminal-recorder.test.d.ts.map +0 -1
  946. package/dist/ui/tui-terminal-recorder.test.js +0 -134
  947. package/dist/ui/tui-terminal-recorder.test.js.map +0 -1
  948. package/dist/ui/utils/assistant-stream-split.test.d.ts +0 -2
  949. package/dist/ui/utils/assistant-stream-split.test.d.ts.map +0 -1
  950. package/dist/ui/utils/assistant-stream-split.test.js +0 -74
  951. package/dist/ui/utils/assistant-stream-split.test.js.map +0 -1
  952. package/dist/ui/utils/markdown-renderer.test.d.ts +0 -2
  953. package/dist/ui/utils/markdown-renderer.test.d.ts.map +0 -1
  954. package/dist/ui/utils/markdown-renderer.test.js +0 -63
  955. package/dist/ui/utils/markdown-renderer.test.js.map +0 -1
  956. package/dist/ui/utils/table-text.test.d.ts +0 -2
  957. package/dist/ui/utils/table-text.test.d.ts.map +0 -1
  958. package/dist/ui/utils/table-text.test.js +0 -202
  959. package/dist/ui/utils/table-text.test.js.map +0 -1
  960. package/dist/ui/utils/terminal-graphics.test.d.ts +0 -2
  961. package/dist/ui/utils/terminal-graphics.test.d.ts.map +0 -1
  962. package/dist/ui/utils/terminal-graphics.test.js +0 -100
  963. package/dist/ui/utils/terminal-graphics.test.js.map +0 -1
  964. package/dist/ui/utils/terminal-input.test.d.ts +0 -2
  965. package/dist/ui/utils/terminal-input.test.d.ts.map +0 -1
  966. package/dist/ui/utils/terminal-input.test.js +0 -15
  967. package/dist/ui/utils/terminal-input.test.js.map +0 -1
  968. package/dist/utils/git.test.d.ts +0 -2
  969. package/dist/utils/git.test.d.ts.map +0 -1
  970. package/dist/utils/git.test.js +0 -36
  971. package/dist/utils/git.test.js.map +0 -1
  972. package/dist/utils/github.test.d.ts +0 -2
  973. package/dist/utils/github.test.d.ts.map +0 -1
  974. package/dist/utils/github.test.js +0 -23
  975. package/dist/utils/github.test.js.map +0 -1
  976. package/dist/utils/http-body.test.d.ts +0 -2
  977. package/dist/utils/http-body.test.d.ts.map +0 -1
  978. package/dist/utils/http-body.test.js +0 -68
  979. package/dist/utils/http-body.test.js.map +0 -1
  980. package/dist/utils/image.test.d.ts +0 -2
  981. package/dist/utils/image.test.d.ts.map +0 -1
  982. package/dist/utils/image.test.js +0 -139
  983. package/dist/utils/image.test.js.map +0 -1
  984. package/dist/utils/plan-steps.test.d.ts +0 -2
  985. package/dist/utils/plan-steps.test.d.ts.map +0 -1
  986. package/dist/utils/plan-steps.test.js +0 -159
  987. package/dist/utils/plan-steps.test.js.map +0 -1
  988. package/dist/utils/process.test.d.ts +0 -2
  989. package/dist/utils/process.test.d.ts.map +0 -1
  990. package/dist/utils/process.test.js +0 -42
  991. package/dist/utils/process.test.js.map +0 -1
@@ -1,984 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import { prettifyError } from "zod";
3
- import fs from "node:fs/promises";
4
- import path from "node:path";
5
- import os from "node:os";
6
- import { createEditTool } from "./edit.js";
7
- import { lineHash } from "../core/hashline.js";
8
- import { recordRead } from "./read-tracker.js";
9
- function resultToString(result) {
10
- if (typeof result === "string")
11
- return result;
12
- if (result && typeof result === "object" && "details" in result) {
13
- const details = result.details;
14
- return details?.diff ?? "";
15
- }
16
- return "";
17
- }
18
- async function markRead(tracker, filePath) {
19
- const stat = await fs.stat(filePath);
20
- const content = await fs.readFile(filePath, "utf-8");
21
- recordRead(tracker, filePath, content, stat.mtimeMs);
22
- }
23
- describe("createEditTool", () => {
24
- let tmpDir;
25
- beforeEach(async () => {
26
- tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "edit-test-"));
27
- });
28
- afterEach(async () => {
29
- await fs.rm(tmpDir, { recursive: true, force: true });
30
- });
31
- it("opts into sequential agent-loop execution", () => {
32
- const tool = createEditTool(tmpDir);
33
- expect(tool.executionMode).toBe("sequential");
34
- });
35
- it("replaces exact text and returns a diff", async () => {
36
- const filePath = path.join(tmpDir, "hello.txt");
37
- await fs.writeFile(filePath, "hello world\n");
38
- const tool = createEditTool(tmpDir);
39
- const result = await tool.execute({ file_path: "hello.txt", edits: [{ old_text: "hello", new_text: "goodbye" }] }, { signal: new AbortController().signal, toolCallId: "test-1" });
40
- const diff = resultToString(result);
41
- expect(diff).toContain("-hello world");
42
- expect(diff).toContain("+goodbye world");
43
- const written = await fs.readFile(filePath, "utf-8");
44
- expect(written).toBe("goodbye world\n");
45
- });
46
- it("applies multiple edits sequentially", async () => {
47
- const filePath = path.join(tmpDir, "multi.txt");
48
- await fs.writeFile(filePath, "alpha\nbeta\ngamma\n");
49
- const tool = createEditTool(tmpDir);
50
- const result = await tool.execute({
51
- file_path: "multi.txt",
52
- edits: [
53
- { old_text: "alpha", new_text: "ALPHA" },
54
- { old_text: "gamma", new_text: "GAMMA" },
55
- ],
56
- }, { signal: new AbortController().signal, toolCallId: "test-multi" });
57
- const summary = typeof result === "string" ? result : result.content;
58
- expect(summary).toContain("2 edits");
59
- const written = await fs.readFile(filePath, "utf-8");
60
- expect(written).toBe("ALPHA\nbeta\nGAMMA\n");
61
- });
62
- it("supports chained edits where later edits depend on earlier ones", async () => {
63
- const filePath = path.join(tmpDir, "chain.txt");
64
- await fs.writeFile(filePath, "foo\n");
65
- const tool = createEditTool(tmpDir);
66
- await tool.execute({
67
- file_path: "chain.txt",
68
- edits: [
69
- { old_text: "foo", new_text: "bar" },
70
- { old_text: "bar", new_text: "baz" },
71
- ],
72
- }, { signal: new AbortController().signal, toolCallId: "test-chain" });
73
- const written = await fs.readFile(filePath, "utf-8");
74
- expect(written).toBe("baz\n");
75
- });
76
- it("reports edit index on failure within a multi-edit batch (atomic mode)", async () => {
77
- const filePath = path.join(tmpDir, "batch.txt");
78
- await fs.writeFile(filePath, "one two three\n");
79
- const tool = createEditTool(tmpDir);
80
- await expect(tool.execute({
81
- file_path: "batch.txt",
82
- edits: [
83
- { old_text: "one", new_text: "1" },
84
- { old_text: "missing", new_text: "x" },
85
- ],
86
- atomic: true,
87
- }, { signal: new AbortController().signal, toolCallId: "test-batch" })).rejects.toThrow(/edit 2\/2/);
88
- // Nothing should have been written — atomic
89
- const written = await fs.readFile(filePath, "utf-8");
90
- expect(written).toBe("one two three\n");
91
- });
92
- it("throws when file hasn't been read with readFiles tracking", async () => {
93
- const filePath = path.join(tmpDir, "unread.txt");
94
- await fs.writeFile(filePath, "content\n");
95
- const readFiles = new Map();
96
- const tool = createEditTool(tmpDir, readFiles);
97
- await expect(tool.execute({ file_path: "unread.txt", edits: [{ old_text: "content", new_text: "new" }] }, { signal: new AbortController().signal, toolCallId: "test-3" })).rejects.toThrow("File must be read first");
98
- });
99
- it("allows edit when file is in readFiles tracker", async () => {
100
- const filePath = path.join(tmpDir, "tracked.txt");
101
- await fs.writeFile(filePath, "alpha beta\n");
102
- const readFiles = new Map();
103
- await markRead(readFiles, filePath);
104
- const tool = createEditTool(tmpDir, readFiles);
105
- const result = await tool.execute({ file_path: "tracked.txt", edits: [{ old_text: "alpha", new_text: "gamma" }] }, { signal: new AbortController().signal, toolCallId: "test-4" });
106
- const diff = resultToString(result);
107
- expect(diff).toContain("-alpha beta");
108
- expect(diff).toContain("+gamma beta");
109
- const written = await fs.readFile(filePath, "utf-8");
110
- expect(written).toBe("gamma beta\n");
111
- });
112
- it("rejects edit when the file changed since it was read", async () => {
113
- const filePath = path.join(tmpDir, "stale.txt");
114
- await fs.writeFile(filePath, "alpha\n");
115
- const readFiles = new Map();
116
- await markRead(readFiles, filePath);
117
- // Simulate an external formatter rewriting the file (different bytes,
118
- // forced bumped mtime so the fast-path mtime check trips).
119
- await fs.writeFile(filePath, "ALPHA\n");
120
- const future = new Date(Date.now() + 5_000);
121
- await fs.utimes(filePath, future, future);
122
- const tool = createEditTool(tmpDir, readFiles);
123
- await expect(tool.execute({ file_path: "stale.txt", edits: [{ old_text: "ALPHA", new_text: "beta" }] }, { signal: new AbortController().signal, toolCallId: "test-stale" })).rejects.toThrow(/modified since/);
124
- });
125
- it("allows consecutive edits without re-reading (recordWrite refreshes)", async () => {
126
- const filePath = path.join(tmpDir, "consec.txt");
127
- await fs.writeFile(filePath, "one\ntwo\n");
128
- const readFiles = new Map();
129
- await markRead(readFiles, filePath);
130
- const tool = createEditTool(tmpDir, readFiles);
131
- await tool.execute({ file_path: "consec.txt", edits: [{ old_text: "one", new_text: "ONE" }] }, { signal: new AbortController().signal, toolCallId: "test-consec-1" });
132
- // Second edit must succeed without an explicit re-read.
133
- await tool.execute({ file_path: "consec.txt", edits: [{ old_text: "two", new_text: "TWO" }] }, { signal: new AbortController().signal, toolCallId: "test-consec-2" });
134
- const written = await fs.readFile(filePath, "utf-8");
135
- expect(written).toBe("ONE\nTWO\n");
136
- });
137
- it("appends a 'Closest match' snippet when old_text is not found", async () => {
138
- const filePath = path.join(tmpDir, "snippet.txt");
139
- await fs.writeFile(filePath, "import { useState } from 'react';\n\nexport function Counter() {\n const [count, setCount] = useState(0);\n return <div>{count}</div>;\n}\n");
140
- const tool = createEditTool(tmpDir);
141
- await expect(tool.execute({
142
- file_path: "snippet.txt",
143
- edits: [
144
- {
145
- old_text: "const [count, setCount] = useState(1);",
146
- new_text: "const [count, setCount] = useState(2);",
147
- },
148
- ],
149
- }, { signal: new AbortController().signal, toolCallId: "test-snippet" })).rejects.toThrow(/Closest match in file:[\s\S]*useState\(0\)/);
150
- });
151
- it("suggests a bounded re-read around the closest match when not_found", async () => {
152
- const filePath = path.join(tmpDir, "rehint.txt");
153
- await fs.writeFile(filePath, "import { useState } from 'react';\n\nexport function Counter() {\n const [count, setCount] = useState(0);\n return <div>{count}</div>;\n}\n");
154
- const tool = createEditTool(tmpDir);
155
- // The closest match is on line 4. With ±25 lines, offset clamps to 1 and
156
- // limit stays at 50. The hint uses the same file_path the model passed.
157
- await expect(tool.execute({
158
- file_path: "rehint.txt",
159
- edits: [
160
- {
161
- old_text: "const [count, setCount] = useState(1);",
162
- new_text: "const [count, setCount] = useState(2);",
163
- },
164
- ],
165
- }, { signal: new AbortController().signal, toolCallId: "rehint-1" })).rejects.toThrow(/Suggested re-read: `read file_path="rehint\.txt" offset=1 limit=50`/);
166
- });
167
- it("aggregates multiple edit failures into one error (atomic mode)", async () => {
168
- const filePath = path.join(tmpDir, "agg.txt");
169
- await fs.writeFile(filePath, "alpha\nbeta\ngamma\n");
170
- const tool = createEditTool(tmpDir);
171
- await expect(tool.execute({
172
- file_path: "agg.txt",
173
- edits: [
174
- { old_text: "alpha", new_text: "ALPHA" },
175
- { old_text: "MISSING", new_text: "X" },
176
- { old_text: "ALSO_MISSING", new_text: "Y" },
177
- ],
178
- atomic: true,
179
- }, { signal: new AbortController().signal, toolCallId: "test-agg" })).rejects.toThrow(/2 of 3 edits failed[\s\S]*edit 2\/3[\s\S]*edit 3\/3/);
180
- // Atomic — nothing written.
181
- const written = await fs.readFile(filePath, "utf-8");
182
- expect(written).toBe("alpha\nbeta\ngamma\n");
183
- });
184
- it("partial-apply (default): keeps successful edits and reports failures for retry", async () => {
185
- const filePath = path.join(tmpDir, "partial.txt");
186
- await fs.writeFile(filePath, "alpha\nbeta\ngamma\n");
187
- const tool = createEditTool(tmpDir);
188
- const result = await tool.execute({
189
- file_path: "partial.txt",
190
- edits: [
191
- { old_text: "alpha", new_text: "ALPHA" },
192
- { old_text: "MISSING", new_text: "X" },
193
- { old_text: "gamma", new_text: "GAMMA" },
194
- ],
195
- }, { signal: new AbortController().signal, toolCallId: "test-partial" });
196
- const summary = typeof result === "string" ? result : result.content;
197
- expect(summary).toMatch(/Applied 2 of 3 edits/);
198
- expect(summary).toMatch(/re-issue ONLY these/);
199
- expect(summary).toMatch(/edit 2\/3/);
200
- expect(summary).not.toMatch(/edit 1\/3/);
201
- expect(summary).not.toMatch(/edit 3\/3/);
202
- // Successful edits landed; failed one didn't.
203
- const written = await fs.readFile(filePath, "utf-8");
204
- expect(written).toBe("ALPHA\nbeta\nGAMMA\n");
205
- });
206
- it("partial-apply on a 19-edit batch with 2 failures lands the other 17", async () => {
207
- const filePath = path.join(tmpDir, "big.css");
208
- const lines = Array.from({ length: 19 }, (_, i) => `.cls${i} { color: red; }`);
209
- await fs.writeFile(filePath, lines.join("\n") + "\n");
210
- const edits = lines.map((line, i) => ({
211
- old_text: line,
212
- // Two of them deliberately drift so the batch sees real failures.
213
- new_text: i === 7 || i === 13
214
- ? line.replace("color: red", "color: blue")
215
- : line.replace("red", "green"),
216
- }));
217
- // Corrupt edits 8 (index 7) and 14 (index 13) by paraphrasing old_text.
218
- edits[7] = { old_text: ".cls7 { colour: red; }", new_text: ".cls7 { color: blue; }" };
219
- edits[13] = { old_text: ".cls13 { colur: red; }", new_text: ".cls13 { color: blue; }" };
220
- const tool = createEditTool(tmpDir);
221
- const result = await tool.execute({ file_path: "big.css", edits }, { signal: new AbortController().signal, toolCallId: "test-19" });
222
- const summary = typeof result === "string" ? result : result.content;
223
- expect(summary).toMatch(/Applied 17 of 19 edits/);
224
- expect(summary).toMatch(/edit 8\/19/);
225
- expect(summary).toMatch(/edit 14\/19/);
226
- const written = await fs.readFile(filePath, "utf-8");
227
- // 17 lines should have green, the two failed ones still red.
228
- expect((written.match(/color: green/g) ?? []).length).toBe(17);
229
- expect(written).toContain(".cls7 { color: red; }");
230
- expect(written).toContain(".cls13 { color: red; }");
231
- });
232
- it("throws when every edit fails even in partial-apply mode", async () => {
233
- const filePath = path.join(tmpDir, "all-fail.txt");
234
- await fs.writeFile(filePath, "untouched\n");
235
- const tool = createEditTool(tmpDir);
236
- await expect(tool.execute({
237
- file_path: "all-fail.txt",
238
- edits: [
239
- { old_text: "MISSING1", new_text: "X" },
240
- { old_text: "MISSING2", new_text: "Y" },
241
- ],
242
- }, { signal: new AbortController().signal, toolCallId: "test-all-fail" })).rejects.toThrow(/2 of 2 edits failed/);
243
- const written = await fs.readFile(filePath, "utf-8");
244
- expect(written).toBe("untouched\n");
245
- });
246
- it("suppresses Closest-match snippet in partial-apply when other edits succeeded", async () => {
247
- // Mirrors the StartingYourAgency.tsx scenario: token-heavy lines where
248
- // findClosestSnippet returns noisy top-of-file regions. When 17 of 19
249
- // edits succeed, those diffs already give the model context — the
250
- // snippet would just be noise.
251
- const filePath = path.join(tmpDir, "noisy.tsx");
252
- const lines = Array.from({ length: 6 }, (_, i) => ` <div className="card-${i}">Section ${i}</div>`);
253
- await fs.writeFile(filePath, lines.join("\n") + "\n");
254
- const edits = lines.map((line) => ({
255
- old_text: line,
256
- new_text: line.replace("card-", "glass-card-"),
257
- }));
258
- // Drift edit 4 — paraphrase the case so it doesn't match.
259
- edits[3] = {
260
- old_text: ` <div className="Card-3">Section 3</div>`,
261
- new_text: ` <div className="glass-card-3">Section 3</div>`,
262
- };
263
- const tool = createEditTool(tmpDir);
264
- const result = await tool.execute({ file_path: "noisy.tsx", edits }, { signal: new AbortController().signal, toolCallId: "test-suppress" });
265
- const summary = typeof result === "string" ? result : result.content;
266
- expect(summary).toMatch(/Applied 5 of 6/);
267
- expect(summary).toMatch(/edit 4\/6/);
268
- // The snippet would be ~3-7 lines starting with "Closest match in file:".
269
- // In partial-apply with successes, we suppress it.
270
- expect(summary).not.toMatch(/Closest match in file:/);
271
- });
272
- it("keeps Closest-match snippet when no other edit succeeded", async () => {
273
- // Single-edit call — no surrounding context for the model, so the snippet
274
- // is genuinely useful and must remain. Use overlapping tokens so the
275
- // closest-snippet heuristic actually fires.
276
- const filePath = path.join(tmpDir, "lonely.tsx");
277
- await fs.writeFile(filePath, "function Counter() {\n const [count, setCount] = useState(0);\n return count;\n}\n");
278
- const tool = createEditTool(tmpDir);
279
- await expect(tool.execute({
280
- file_path: "lonely.tsx",
281
- edits: [
282
- {
283
- old_text: "const [count, setCount] = useState(1);",
284
- new_text: "const [count, setCount] = useState(2);",
285
- },
286
- ],
287
- }, { signal: new AbortController().signal, toolCallId: "test-keep" })).rejects.toThrow(/Closest match in file:[\s\S]*useState\(0\)/);
288
- });
289
- it("atomic mode keeps Closest-match snippet (model retries against unchanged file)", async () => {
290
- const filePath = path.join(tmpDir, "atomic-snippet.tsx");
291
- const lines = Array.from({ length: 4 }, (_, i) => ` <div className="card-${i}">Section ${i}</div>`);
292
- await fs.writeFile(filePath, lines.join("\n") + "\n");
293
- const edits = lines.map((line) => ({
294
- old_text: line,
295
- new_text: line.replace("card-", "glass-card-"),
296
- }));
297
- edits[2] = {
298
- old_text: ` <div className="Card-2">Section 2</div>`,
299
- new_text: ` <div className="glass-card-2">Section 2</div>`,
300
- };
301
- const tool = createEditTool(tmpDir);
302
- await expect(tool.execute({ file_path: "atomic-snippet.tsx", edits, atomic: true }, { signal: new AbortController().signal, toolCallId: "test-atomic-snippet" })).rejects.toThrow(/Closest match in file:/);
303
- });
304
- it("indent-flex: model omits indentation entirely; file has 4-space prefix — applies it", async () => {
305
- const filePath = path.join(tmpDir, "indent.ts");
306
- await fs.writeFile(filePath, " const x = 1;\n const y = 2;\n const z = 3;\n");
307
- const tool = createEditTool(tmpDir);
308
- const result = await tool.execute({
309
- file_path: "indent.ts",
310
- edits: [
311
- {
312
- old_text: "const x = 1;\nconst y = 2;\nconst z = 3;",
313
- new_text: "const x = 10;\nconst y = 20;\nconst z = 30;",
314
- },
315
- ],
316
- }, { signal: new AbortController().signal, toolCallId: "test-indent-flex" });
317
- const summary = typeof result === "string" ? result : result.content;
318
- expect(summary).toMatch(/Successfully/);
319
- const written = await fs.readFile(filePath, "utf-8");
320
- expect(written).toBe(" const x = 10;\n const y = 20;\n const z = 30;\n");
321
- });
322
- it("indent-flex: model used 2-space but file uses 4 — outdents both, re-indents new", async () => {
323
- const filePath = path.join(tmpDir, "mixed-indent.ts");
324
- await fs.writeFile(filePath, " if (x) {\n return y;\n }\n");
325
- const tool = createEditTool(tmpDir);
326
- const result = await tool.execute({
327
- file_path: "mixed-indent.ts",
328
- edits: [
329
- {
330
- old_text: " if (x) {\n return y;\n }",
331
- new_text: " if (x) {\n return z;\n }",
332
- },
333
- ],
334
- }, { signal: new AbortController().signal, toolCallId: "test-mixed-indent" });
335
- const summary = typeof result === "string" ? result : result.content;
336
- expect(summary).toMatch(/Successfully/);
337
- const written = await fs.readFile(filePath, "utf-8");
338
- expect(written).toBe(" if (x) {\n return z;\n }\n");
339
- });
340
- it("dotdotdots: model elides middle with `...`, edit lands and middle preserved", async () => {
341
- const filePath = path.join(tmpDir, "elide.ts");
342
- await fs.writeFile(filePath, [
343
- "function pomodoro() {",
344
- " const timer = startTimer();",
345
- " trackPomodoro(timer);",
346
- " scheduleBreak();",
347
- " return timer;",
348
- "}",
349
- ].join("\n") + "\n");
350
- const tool = createEditTool(tmpDir);
351
- const result = await tool.execute({
352
- file_path: "elide.ts",
353
- edits: [
354
- {
355
- old_text: "function pomodoro() {\n ...\n return timer;\n}",
356
- new_text: "function pomodoro(): Timer {\n ...\n return timer;\n}",
357
- },
358
- ],
359
- }, { signal: new AbortController().signal, toolCallId: "test-elide" });
360
- const summary = typeof result === "string" ? result : result.content;
361
- expect(summary).toMatch(/Successfully/);
362
- const written = await fs.readFile(filePath, "utf-8");
363
- expect(written).toContain("function pomodoro(): Timer {");
364
- // Middle preserved verbatim.
365
- expect(written).toContain("trackPomodoro(timer);");
366
- expect(written).toContain("scheduleBreak();");
367
- });
368
- it("dotdotdots: model can omit common indentation from elided bookends", async () => {
369
- const filePath = path.join(tmpDir, "elide-indent.ts");
370
- await fs.writeFile(filePath, " function pomodoro() {\n trackPomodoro(timer);\n return timer;\n }\n");
371
- const tool = createEditTool(tmpDir);
372
- await tool.execute({
373
- file_path: "elide-indent.ts",
374
- edits: [
375
- {
376
- old_text: "function pomodoro() {\n ...\n return timer;\n}",
377
- new_text: "function pomodoro(): Timer {\n ...\n return timer;\n}",
378
- },
379
- ],
380
- }, { signal: new AbortController().signal, toolCallId: "test-elide-indent" });
381
- const written = await fs.readFile(filePath, "utf-8");
382
- expect(written).toBe(" function pomodoro(): Timer {\n trackPomodoro(timer);\n return timer;\n }\n");
383
- });
384
- it("dotdotdots: failed elision falls through to standard not_found error", async () => {
385
- const filePath = path.join(tmpDir, "elide-fail.ts");
386
- await fs.writeFile(filePath, "function actuallyExists() { return 1; }\n");
387
- const tool = createEditTool(tmpDir);
388
- await expect(tool.execute({
389
- file_path: "elide-fail.ts",
390
- edits: [
391
- {
392
- // Bookends don't exist in the file.
393
- old_text: "function nonexistent() {\n ...\n return x;\n}",
394
- new_text: "function nonexistent() {\n ...\n return y;\n}",
395
- },
396
- ],
397
- }, { signal: new AbortController().signal, toolCallId: "test-elide-fail" })).rejects.toThrow(/old_text not found/);
398
- });
399
- it("treats no-op edits where old_text equals new_text as successful no-ops", async () => {
400
- const filePath = path.join(tmpDir, "noop.txt");
401
- await fs.writeFile(filePath, "hello world\n");
402
- const mutated = [];
403
- const tool = createEditTool(tmpDir, undefined, undefined, undefined, (mutatedPath) => {
404
- mutated.push(mutatedPath);
405
- });
406
- const result = await tool.execute({
407
- file_path: "noop.txt",
408
- edits: [{ old_text: "hello", new_text: "hello" }],
409
- }, { signal: new AbortController().signal, toolCallId: "test-noop" });
410
- const summary = typeof result === "string" ? result : result.content;
411
- expect(summary).toMatch(/No changes needed[\s\S]*no-op/);
412
- expect(mutated).toEqual([]);
413
- // File untouched — confirms we didn't write a no-op.
414
- const written = await fs.readFile(filePath, "utf-8");
415
- expect(written).toBe("hello world\n");
416
- });
417
- it("applies real edits atomically when the batch also contains no-ops", async () => {
418
- const filePath = path.join(tmpDir, "noop-atomic.txt");
419
- await fs.writeFile(filePath, "alpha\nbeta\ngamma\n");
420
- const tool = createEditTool(tmpDir);
421
- const result = await tool.execute({
422
- file_path: "noop-atomic.txt",
423
- edits: [
424
- { old_text: "alpha", new_text: "ALPHA" },
425
- { old_text: "beta", new_text: "beta" },
426
- { old_text: "gamma", new_text: "GAMMA" },
427
- ],
428
- atomic: true,
429
- }, { signal: new AbortController().signal, toolCallId: "test-noop-atomic" });
430
- const summary = typeof result === "string" ? result : result.content;
431
- expect(summary).toContain("3 edits");
432
- const written = await fs.readFile(filePath, "utf-8");
433
- expect(written).toBe("ALPHA\nbeta\nGAMMA\n");
434
- });
435
- it("no-op edit in a partial-apply batch still lets the other edits land", async () => {
436
- const filePath = path.join(tmpDir, "noop-batch.txt");
437
- await fs.writeFile(filePath, "alpha\nbeta\n");
438
- const tool = createEditTool(tmpDir);
439
- const result = await tool.execute({
440
- file_path: "noop-batch.txt",
441
- edits: [
442
- { old_text: "alpha", new_text: "ALPHA" },
443
- { old_text: "beta", new_text: "beta" }, // no-op
444
- ],
445
- }, { signal: new AbortController().signal, toolCallId: "test-noop-batch" });
446
- const summary = typeof result === "string" ? result : result.content;
447
- expect(summary).toMatch(/Successfully applied 2 edits/);
448
- const written = await fs.readFile(filePath, "utf-8");
449
- expect(written).toBe("ALPHA\nbeta\n");
450
- });
451
- it("strips a spurious leading blank line in old_text and still matches", async () => {
452
- const filePath = path.join(tmpDir, "blank.ts");
453
- await fs.writeFile(filePath, "function foo() {\n return 42;\n}\n");
454
- const tool = createEditTool(tmpDir);
455
- const result = await tool.execute({
456
- file_path: "blank.ts",
457
- edits: [
458
- {
459
- // Note the leading blank line — the model often pastes one in.
460
- old_text: "\n return 42;",
461
- new_text: "\n return 100;",
462
- },
463
- ],
464
- }, { signal: new AbortController().signal, toolCallId: "test-blank" });
465
- const summary = typeof result === "string" ? result : result.content;
466
- expect(summary).toMatch(/Successfully/);
467
- const written = await fs.readFile(filePath, "utf-8");
468
- expect(written).toBe("function foo() {\n return 100;\n}\n");
469
- });
470
- it("throws when old_text is not found", async () => {
471
- const filePath = path.join(tmpDir, "missing.txt");
472
- await fs.writeFile(filePath, "some content here\n");
473
- const tool = createEditTool(tmpDir);
474
- await expect(tool.execute({
475
- file_path: "missing.txt",
476
- edits: [{ old_text: "nonexistent text", new_text: "replacement" }],
477
- }, { signal: new AbortController().signal, toolCallId: "test-5" })).rejects.toThrow("old_text not found");
478
- });
479
- it("keeps the read tracker valid after a not_found failure so the model can retry immediately", async () => {
480
- const filePath = path.join(tmpDir, "guardrail.txt");
481
- await fs.writeFile(filePath, "the actual content\n");
482
- const tracker = new Map();
483
- await markRead(tracker, filePath);
484
- const tool = createEditTool(tmpDir, tracker);
485
- // First edit fails with not_found. Nothing was written, so the file is
486
- // unchanged and the tracker must stay valid — invalidating it here used to
487
- // surface a misleading "File must be read first" on the next edit.
488
- await expect(tool.execute({
489
- file_path: "guardrail.txt",
490
- edits: [{ old_text: "the wrong content", new_text: "anything" }],
491
- }, { signal: new AbortController().signal, toolCallId: "guardrail-1" })).rejects.toThrow(/old_text not found/);
492
- expect(tracker.has(filePath)).toBe(true);
493
- // Second edit with corrected old_text succeeds without a forced re-read.
494
- const result = await tool.execute({
495
- file_path: "guardrail.txt",
496
- edits: [{ old_text: "the actual content", new_text: "replaced" }],
497
- }, { signal: new AbortController().signal, toolCallId: "guardrail-2" });
498
- const summary = typeof result === "string" ? result : result.content;
499
- expect(summary).toMatch(/Successfully replaced/);
500
- expect(await fs.readFile(filePath, "utf-8")).toBe("replaced\n");
501
- });
502
- it("refreshes (not clears) the tracker on partial-apply so retries validate against the written content", async () => {
503
- const filePath = path.join(tmpDir, "partial.txt");
504
- await fs.writeFile(filePath, "alpha\nbeta\ngamma\n");
505
- const tracker = new Map();
506
- await markRead(tracker, filePath);
507
- const tool = createEditTool(tmpDir, tracker);
508
- // One edit succeeds (alpha → ALPHA), one fails with not_found (missing).
509
- // The success is written and the tracker is refreshed to the new content.
510
- await tool.execute({
511
- file_path: "partial.txt",
512
- edits: [
513
- { old_text: "alpha", new_text: "ALPHA" },
514
- { old_text: "missing", new_text: "replacement" },
515
- ],
516
- }, { signal: new AbortController().signal, toolCallId: "partial-1" });
517
- expect(await fs.readFile(filePath, "utf-8")).toBe("ALPHA\nbeta\ngamma\n");
518
- expect(tracker.has(filePath)).toBe(true);
519
- // A follow-up edit against the just-written content applies without a re-read.
520
- const result = await tool.execute({
521
- file_path: "partial.txt",
522
- edits: [{ old_text: "beta", new_text: "BETA" }],
523
- }, { signal: new AbortController().signal, toolCallId: "partial-2" });
524
- const summary = typeof result === "string" ? result : result.content;
525
- expect(summary).toMatch(/Successfully replaced/);
526
- expect(await fs.readFile(filePath, "utf-8")).toBe("ALPHA\nBETA\ngamma\n");
527
- });
528
- it("throws when old_text matches multiple times", async () => {
529
- const filePath = path.join(tmpDir, "dupes.txt");
530
- await fs.writeFile(filePath, "foo bar foo baz foo\n");
531
- const tool = createEditTool(tmpDir);
532
- await expect(tool.execute({ file_path: "dupes.txt", edits: [{ old_text: "foo", new_text: "qux" }] }, { signal: new AbortController().signal, toolCallId: "test-6" })).rejects.toThrow(/found 3 times/);
533
- });
534
- it("includes line numbers of every duplicate match in the error", async () => {
535
- const filePath = path.join(tmpDir, "pomodoro.css");
536
- await fs.writeFile(filePath, [
537
- ".timer { color: white; }",
538
- ".button { color: black; }",
539
- ".label { color: white; }",
540
- ".footer { color: white; }",
541
- "",
542
- ].join("\n"));
543
- const tool = createEditTool(tmpDir);
544
- await expect(tool.execute({
545
- file_path: "pomodoro.css",
546
- edits: [{ old_text: "color: white;", new_text: "color: red;" }],
547
- }, { signal: new AbortController().signal, toolCallId: "test-dup-lines" })).rejects.toThrow(/Matches at:[\s\S]*line 1[\s\S]*line 3[\s\S]*line 4/);
548
- });
549
- it("hints at replace_all in the duplicate-match error", async () => {
550
- const filePath = path.join(tmpDir, "hint.txt");
551
- await fs.writeFile(filePath, "foo\nfoo\nfoo\n");
552
- const tool = createEditTool(tmpDir);
553
- await expect(tool.execute({ file_path: "hint.txt", edits: [{ old_text: "foo", new_text: "bar" }] }, { signal: new AbortController().signal, toolCallId: "test-dup-hint" })).rejects.toThrow(/replace_all: true/);
554
- });
555
- it("replaces every occurrence when replace_all: true is set", async () => {
556
- const filePath = path.join(tmpDir, "rename.css");
557
- await fs.writeFile(filePath, [".timer { color: white; }", ".label { color: white; }", ".footer { color: white; }"].join("\n") + "\n");
558
- const tool = createEditTool(tmpDir);
559
- const result = await tool.execute({
560
- file_path: "rename.css",
561
- edits: [{ old_text: "color: white;", new_text: "color: red;", replace_all: true }],
562
- }, { signal: new AbortController().signal, toolCallId: "test-replace-all" });
563
- const summary = typeof result === "string" ? result : result.content;
564
- expect(summary).toMatch(/Successfully/);
565
- const written = await fs.readFile(filePath, "utf-8");
566
- expect(written).toBe([".timer { color: red; }", ".label { color: red; }", ".footer { color: red; }"].join("\n") +
567
- "\n");
568
- });
569
- it("replace_all still errors when no occurrences exist (with closest-match hint)", async () => {
570
- const filePath = path.join(tmpDir, "missing-all.txt");
571
- await fs.writeFile(filePath, "alpha beta\n");
572
- const tool = createEditTool(tmpDir);
573
- await expect(tool.execute({
574
- file_path: "missing-all.txt",
575
- edits: [{ old_text: "gamma", new_text: "delta", replace_all: true }],
576
- }, { signal: new AbortController().signal, toolCallId: "test-replace-all-missing" })).rejects.toThrow(/old_text not found/);
577
- });
578
- it("replace_all applies fuzzy matches instead of requiring exact split", async () => {
579
- const filePath = path.join(tmpDir, "replace-all-fuzzy.txt");
580
- await fs.writeFile(filePath, "say “hi”\nsay “hi”\n");
581
- const tool = createEditTool(tmpDir);
582
- await tool.execute({
583
- file_path: "replace-all-fuzzy.txt",
584
- edits: [{ old_text: 'say "hi"', new_text: "say hello", replace_all: true }],
585
- }, { signal: new AbortController().signal, toolCallId: "test-replace-all-fuzzy" });
586
- const written = await fs.readFile(filePath, "utf-8");
587
- expect(written).toBe("say hello\nsay hello\n");
588
- });
589
- it("replace_all coexists with sequential edits in one batch", async () => {
590
- const filePath = path.join(tmpDir, "mixed.css");
591
- await fs.writeFile(filePath, [".a { color: white; }", ".b { color: white; }", ".header { font-size: 12px; }"].join("\n") +
592
- "\n");
593
- const tool = createEditTool(tmpDir);
594
- const result = await tool.execute({
595
- file_path: "mixed.css",
596
- edits: [
597
- { old_text: "color: white;", new_text: "color: red;", replace_all: true },
598
- { old_text: "font-size: 12px;", new_text: "font-size: 14px;" },
599
- ],
600
- }, { signal: new AbortController().signal, toolCallId: "test-mixed" });
601
- const summary = typeof result === "string" ? result : result.content;
602
- expect(summary).toContain("2 edits");
603
- const written = await fs.readFile(filePath, "utf-8");
604
- expect(written).toBe([".a { color: red; }", ".b { color: red; }", ".header { font-size: 14px; }"].join("\n") +
605
- "\n");
606
- });
607
- it("handles fuzzy matching with trailing whitespace and smart quotes", async () => {
608
- const filePath = path.join(tmpDir, "fuzzy.txt");
609
- await fs.writeFile(filePath, "const msg = 'hello'; \nend\n");
610
- const tool = createEditTool(tmpDir);
611
- const result = await tool.execute({
612
- file_path: "fuzzy.txt",
613
- edits: [
614
- {
615
- old_text: "const msg = \u2018hello\u2019;",
616
- new_text: "const msg = 'goodbye';",
617
- },
618
- ],
619
- }, { signal: new AbortController().signal, toolCallId: "test-7" });
620
- const diff = resultToString(result);
621
- expect(diff).toContain("+const msg = 'goodbye';");
622
- const written = await fs.readFile(filePath, "utf-8");
623
- expect(written).toContain("goodbye");
624
- });
625
- it("preserves CRLF line endings", async () => {
626
- const filePath = path.join(tmpDir, "crlf.txt");
627
- await fs.writeFile(filePath, "line one\r\nline two\r\nline three\r\n");
628
- const tool = createEditTool(tmpDir);
629
- const result = await tool.execute({ file_path: "crlf.txt", edits: [{ old_text: "line two", new_text: "line TWO" }] }, { signal: new AbortController().signal, toolCallId: "test-8" });
630
- const diff = resultToString(result);
631
- expect(diff).toContain("+line TWO");
632
- const written = await fs.readFile(filePath, "utf-8");
633
- expect(written).toBe("line one\r\nline TWO\r\nline three\r\n");
634
- });
635
- it("calls mutation callback after successful edits", async () => {
636
- const filePath = path.join(tmpDir, "mutated.txt");
637
- await fs.writeFile(filePath, "alpha\n");
638
- const mutated = [];
639
- const tool = createEditTool(tmpDir, undefined, undefined, undefined, (mutatedPath) => {
640
- mutated.push(mutatedPath);
641
- });
642
- await tool.execute({ file_path: "mutated.txt", edits: [{ old_text: "alpha", new_text: "beta" }] }, { signal: new AbortController().signal, toolCallId: "test-mutated" });
643
- expect(mutated).toEqual([filePath]);
644
- });
645
- it("does not call mutation callback when no edits are written", async () => {
646
- const filePath = path.join(tmpDir, "not-mutated.txt");
647
- await fs.writeFile(filePath, "alpha\n");
648
- const mutated = [];
649
- const tool = createEditTool(tmpDir, undefined, undefined, undefined, (mutatedPath) => {
650
- mutated.push(mutatedPath);
651
- });
652
- await expect(tool.execute({ file_path: "not-mutated.txt", edits: [{ old_text: "missing", new_text: "beta" }] }, { signal: new AbortController().signal, toolCallId: "test-not-mutated" })).rejects.toThrow("old_text not found");
653
- expect(mutated).toEqual([]);
654
- });
655
- describe("LSP diagnostics", () => {
656
- function contentOf(result) {
657
- if (result && typeof result === "object" && "content" in result) {
658
- const c = result.content;
659
- if (typeof c === "string")
660
- return c;
661
- }
662
- return String(result);
663
- }
664
- it("appends a non-empty diagnostics string to a successful edit", async () => {
665
- const filePath = path.join(tmpDir, "diag.ts");
666
- await fs.writeFile(filePath, "const x = 1;\n");
667
- const seen = [];
668
- const tool = createEditTool(tmpDir, undefined, undefined, undefined, undefined, undefined, async (fp, content) => {
669
- seen.push({ filePath: fp, content });
670
- return "\n\nDiagnostics in diag.ts (informational — may resolve after related edits):\nL1:7 boom (typescript)";
671
- });
672
- const result = await tool.execute({
673
- file_path: "diag.ts",
674
- edits: [{ old_text: "const x = 1;", new_text: 'const x: number = "a";' }],
675
- }, { signal: new AbortController().signal, toolCallId: "test-diag-1" });
676
- const content = contentOf(result);
677
- expect(content).toContain("Successfully replaced text in diag.ts.");
678
- expect(content).toContain("L1:7 boom (typescript)");
679
- expect(seen).toEqual([{ filePath, content: 'const x: number = "a";\n' }]);
680
- });
681
- it("leaves the result unchanged when the provider returns empty", async () => {
682
- const filePath = path.join(tmpDir, "clean.ts");
683
- await fs.writeFile(filePath, "alpha\n");
684
- const tool = createEditTool(tmpDir, undefined, undefined, undefined, undefined, undefined, async () => "");
685
- const result = await tool.execute({ file_path: "clean.ts", edits: [{ old_text: "alpha", new_text: "beta" }] }, { signal: new AbortController().signal, toolCallId: "test-diag-2" });
686
- expect(contentOf(result)).toBe("Successfully replaced text in clean.ts.");
687
- });
688
- it("leaves the result unchanged when the provider throws", async () => {
689
- const filePath = path.join(tmpDir, "throws.ts");
690
- await fs.writeFile(filePath, "alpha\n");
691
- const tool = createEditTool(tmpDir, undefined, undefined, undefined, undefined, undefined, async () => {
692
- throw new Error("lsp exploded");
693
- });
694
- const result = await tool.execute({ file_path: "throws.ts", edits: [{ old_text: "alpha", new_text: "beta" }] }, { signal: new AbortController().signal, toolCallId: "test-diag-3" });
695
- expect(contentOf(result)).toBe("Successfully replaced text in throws.ts.");
696
- expect(await fs.readFile(filePath, "utf-8")).toBe("beta\n");
697
- });
698
- it("does not call the provider when nothing was written", async () => {
699
- const filePath = path.join(tmpDir, "untouched.ts");
700
- await fs.writeFile(filePath, "alpha\n");
701
- let calls = 0;
702
- const tool = createEditTool(tmpDir, undefined, undefined, undefined, undefined, undefined, async () => {
703
- calls++;
704
- return "should not appear";
705
- });
706
- await expect(tool.execute({ file_path: "untouched.ts", edits: [{ old_text: "missing", new_text: "beta" }] }, { signal: new AbortController().signal, toolCallId: "test-diag-4" })).rejects.toThrow("old_text not found");
707
- expect(calls).toBe(0);
708
- });
709
- it("appends diagnostics to partial-success results", async () => {
710
- const filePath = path.join(tmpDir, "partial.ts");
711
- await fs.writeFile(filePath, "alpha\ngamma\n");
712
- const tool = createEditTool(tmpDir, undefined, undefined, undefined, undefined, undefined, async () => "\n\nDiagnostics in partial.ts (informational — may resolve after related edits):\nL1:1 oops (typescript)");
713
- const result = await tool.execute({
714
- file_path: "partial.ts",
715
- edits: [
716
- { old_text: "alpha", new_text: "beta" },
717
- { old_text: "missing", new_text: "x" },
718
- ],
719
- }, { signal: new AbortController().signal, toolCallId: "test-diag-5" });
720
- const content = contentOf(result);
721
- expect(content).toContain("Applied 1 of 2 edits");
722
- expect(content).toContain("L1:1 oops (typescript)");
723
- });
724
- });
725
- });
726
- describe("edit anchor guard", () => {
727
- let tmpDir;
728
- beforeEach(async () => {
729
- tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "edit-anchor-test-"));
730
- });
731
- afterEach(async () => {
732
- await fs.rm(tmpDir, { recursive: true, force: true });
733
- });
734
- function diffOf(result) {
735
- if (typeof result === "string")
736
- return result;
737
- if (result && typeof result === "object" && "details" in result) {
738
- return result.details?.diff ?? "";
739
- }
740
- return "";
741
- }
742
- /** Anchor for a 1-based line in `content`. */
743
- function anchorFor(content, line1) {
744
- const idx = line1 - 1;
745
- const text = content.split("\n")[idx];
746
- return { line: line1, hash: lineHash(text, idx) };
747
- }
748
- it("applies normally when the anchor matches", async () => {
749
- const filePath = path.join(tmpDir, "a.ts");
750
- const content = "const a = 1;\nconst b = 2;\nconst c = 3;\n";
751
- await fs.writeFile(filePath, content);
752
- const tracker = new Map();
753
- await markRead(tracker, filePath);
754
- const a = anchorFor(content, 2);
755
- const tool = createEditTool(tmpDir, tracker);
756
- const result = await tool.execute({
757
- file_path: "a.ts",
758
- edits: [
759
- {
760
- old_text: "const b = 2;",
761
- new_text: "const b = 20;",
762
- anchor: { start_line: a.line, start_hash: a.hash, end_line: a.line, end_hash: a.hash },
763
- },
764
- ],
765
- }, { signal: new AbortController().signal, toolCallId: "anc-1" });
766
- expect(diffOf(result)).toContain("+const b = 20;");
767
- expect(await fs.readFile(filePath, "utf-8")).toBe("const a = 1;\nconst b = 20;\nconst c = 3;\n");
768
- });
769
- it("rejects a wrong start_hash with stale_anchor and writes nothing", async () => {
770
- const filePath = path.join(tmpDir, "b.ts");
771
- const content = "const a = 1;\nconst b = 2;\n";
772
- await fs.writeFile(filePath, content);
773
- const tracker = new Map();
774
- await markRead(tracker, filePath);
775
- const tool = createEditTool(tmpDir, tracker);
776
- await expect(tool.execute({
777
- file_path: "b.ts",
778
- edits: [
779
- {
780
- old_text: "const b = 2;",
781
- new_text: "const b = 20;",
782
- anchor: { start_line: 2, start_hash: "dead", end_line: 2, end_hash: "dead" },
783
- },
784
- ],
785
- }, { signal: new AbortController().signal, toolCallId: "anc-2" })).rejects.toThrow(/changed since you read it/);
786
- // File untouched.
787
- expect(await fs.readFile(filePath, "utf-8")).toBe(content);
788
- });
789
- it("partial-applies a multi-edit batch where one anchor is stale", async () => {
790
- const filePath = path.join(tmpDir, "c.ts");
791
- const content = "const a = 1;\nconst b = 2;\nconst c = 3;\n";
792
- await fs.writeFile(filePath, content);
793
- const tracker = new Map();
794
- await markRead(tracker, filePath);
795
- const a = anchorFor(content, 1);
796
- const tool = createEditTool(tmpDir, tracker);
797
- const result = await tool.execute({
798
- file_path: "c.ts",
799
- edits: [
800
- {
801
- old_text: "const a = 1;",
802
- new_text: "const a = 10;",
803
- anchor: { start_line: a.line, start_hash: a.hash, end_line: a.line, end_hash: a.hash },
804
- },
805
- {
806
- old_text: "const c = 3;",
807
- new_text: "const c = 30;",
808
- anchor: { start_line: 3, start_hash: "dead", end_line: 3, end_hash: "dead" },
809
- },
810
- ],
811
- }, { signal: new AbortController().signal, toolCallId: "anc-3" });
812
- const content2 = contentOf(result);
813
- expect(content2).toContain("Applied 1 of 2 edits");
814
- expect(content2).toContain("changed since you read it");
815
- // First edit persisted; the stale one did not.
816
- expect(await fs.readFile(filePath, "utf-8")).toBe("const a = 10;\nconst b = 2;\nconst c = 3;\n");
817
- });
818
- it("absent anchor behaves exactly like today (fuzzy path)", async () => {
819
- const filePath = path.join(tmpDir, "d.ts");
820
- await fs.writeFile(filePath, "const a = 1;\n");
821
- const tracker = new Map();
822
- await markRead(tracker, filePath);
823
- const tool = createEditTool(tmpDir, tracker);
824
- const result = await tool.execute({ file_path: "d.ts", edits: [{ old_text: "const a = 1;", new_text: "const a = 2;" }] }, { signal: new AbortController().signal, toolCallId: "anc-4" });
825
- expect(diffOf(result)).toContain("+const a = 2;");
826
- expect(await fs.readFile(filePath, "utf-8")).toBe("const a = 2;\n");
827
- });
828
- // ── Span form { span, lines } ──
829
- function spanFor(content, startLine, endLine) {
830
- const lines = content.split("\n");
831
- return {
832
- start_line: startLine,
833
- start_hash: lineHash(lines[startLine - 1], startLine - 1),
834
- end_line: endLine,
835
- end_hash: lineHash(lines[endLine - 1], endLine - 1),
836
- };
837
- }
838
- it("span form replaces the pinned line range without old_text", async () => {
839
- const content = "const a = 1;\nconst b = 2;\nconst c = 3;\n";
840
- const filePath = path.join(tmpDir, "span1.ts");
841
- await fs.writeFile(filePath, content);
842
- const tool = createEditTool(tmpDir);
843
- const result = await tool.execute({
844
- file_path: "span1.ts",
845
- edits: [{ span: spanFor(content, 2, 2), lines: ["const b = 20;"] }],
846
- }, { signal: new AbortController().signal, toolCallId: "span-1" });
847
- expect(diffOf(result)).toContain("+const b = 20;");
848
- expect(await fs.readFile(filePath, "utf-8")).toBe("const a = 1;\nconst b = 20;\nconst c = 3;\n");
849
- });
850
- it("span form: multi-line replace, insert-by-expansion, and delete via empty lines", async () => {
851
- const content = "one\ntwo\nthree\nfour\nfive\n";
852
- const filePath = path.join(tmpDir, "span2.txt");
853
- await fs.writeFile(filePath, content);
854
- const tool = createEditTool(tmpDir);
855
- await tool.execute({
856
- file_path: "span2.txt",
857
- edits: [
858
- // Replace lines 2-3 with three lines (expansion = insertion).
859
- { span: spanFor(content, 2, 3), lines: ["TWO", "TWO.5", "THREE"] },
860
- // Delete line 5 ("five"). Anchors verify against the file AS READ,
861
- // and spans apply bottom-up, so the earlier expansion doesn't shift this.
862
- { span: spanFor(content, 5, 5), lines: [] },
863
- ],
864
- }, { signal: new AbortController().signal, toolCallId: "span-2" });
865
- // Deleting line 5 ("five") leaves the trailing newline's empty segment as EOF.
866
- expect(await fs.readFile(filePath, "utf-8")).toBe("one\nTWO\nTWO.5\nTHREE\nfour\n");
867
- });
868
- it("span form rejects stale hashes without touching the file", async () => {
869
- const content = "alpha\nbeta\n";
870
- const filePath = path.join(tmpDir, "span3.txt");
871
- await fs.writeFile(filePath, content);
872
- const tool = createEditTool(tmpDir);
873
- await expect(tool.execute({
874
- file_path: "span3.txt",
875
- edits: [
876
- {
877
- span: { start_line: 1, start_hash: "dead", end_line: 1, end_hash: "dead" },
878
- lines: ["hijacked"],
879
- },
880
- ],
881
- }, { signal: new AbortController().signal, toolCallId: "span-3" })).rejects.toThrow(/changed since you read it/);
882
- expect(await fs.readFile(filePath, "utf-8")).toBe(content);
883
- });
884
- it("span form rejects overlapping spans (first wins, overlap reported)", async () => {
885
- const content = "l1\nl2\nl3\nl4\n";
886
- const filePath = path.join(tmpDir, "span4.txt");
887
- await fs.writeFile(filePath, content);
888
- const tool = createEditTool(tmpDir);
889
- const result = await tool.execute({
890
- file_path: "span4.txt",
891
- edits: [
892
- { span: spanFor(content, 1, 2), lines: ["A"] },
893
- { span: spanFor(content, 2, 3), lines: ["B"] },
894
- ],
895
- }, { signal: new AbortController().signal, toolCallId: "span-4" });
896
- expect(contentOf(result)).toContain("overlaps");
897
- expect(await fs.readFile(filePath, "utf-8")).toBe("A\nl3\nl4\n");
898
- });
899
- it("span and text forms mix in one batch: spans first, then text on the result", async () => {
900
- const content = "const x = 1;\nconst y = 2;\n";
901
- const filePath = path.join(tmpDir, "span5.ts");
902
- await fs.writeFile(filePath, content);
903
- const tool = createEditTool(tmpDir);
904
- await tool.execute({
905
- file_path: "span5.ts",
906
- edits: [
907
- { span: spanFor(content, 1, 1), lines: ["const x = 10;"] },
908
- { old_text: "const y = 2;", new_text: "const y = 20;" },
909
- ],
910
- }, { signal: new AbortController().signal, toolCallId: "span-5" });
911
- expect(await fs.readFile(filePath, "utf-8")).toBe("const x = 10;\nconst y = 20;\n");
912
- });
913
- it("rejects an edit that mixes span with old_text, and one with neither form", async () => {
914
- const content = "a\nb\n";
915
- const filePath = path.join(tmpDir, "span6.txt");
916
- await fs.writeFile(filePath, content);
917
- const tool = createEditTool(tmpDir);
918
- await expect(tool.execute({
919
- file_path: "span6.txt",
920
- edits: [{ span: spanFor(content, 1, 1), lines: ["z"], old_text: "a", new_text: "z" }],
921
- }, { signal: new AbortController().signal, toolCallId: "span-6" })).rejects.toThrow(/must not mix/);
922
- await expect(tool.execute({ file_path: "span6.txt", edits: [{}] }, { signal: new AbortController().signal, toolCallId: "span-7" })).rejects.toThrow(/has neither/);
923
- expect(await fs.readFile(filePath, "utf-8")).toBe(content);
924
- });
925
- it("blocks edits outside the workspace with the guard error", async () => {
926
- const tool = createEditTool(tmpDir);
927
- const outside = path.join(os.homedir(), "Documents", "gg-guard-test-outside.txt");
928
- const raw = await tool.execute({ file_path: outside, edits: [{ old_text: "a", new_text: "b" }] }, { signal: new AbortController().signal, toolCallId: "guard-1" });
929
- expect(contentOf(raw)).toContain("outside the workspace");
930
- expect(contentOf(raw)).toContain("allowOutsideWorkspaceWrites");
931
- });
932
- });
933
- /**
934
- * Models intermittently hand-serialize `edits` into a JSON string instead of
935
- * emitting a real array (~1% of edit calls across opus-5/sonnet-5/glm-5.x).
936
- * Well-formed strings are coerced; malformed ones must be rejected with a
937
- * message that names the mistake, because the stock "expected array, received
938
- * string" made the model re-send the identical payload until the agent loop's
939
- * repeat counter killed the turn.
940
- */
941
- describe("edit stringified `edits` handling", () => {
942
- const parse = (edits) => createEditTool(os.tmpdir()).parameters.safeParse({ file_path: "a.ts", edits });
943
- const errorFor = (edits) => {
944
- const result = parse(edits);
945
- expect(result.success).toBe(false);
946
- return result.success ? "" : prettifyError(result.error);
947
- };
948
- it("coerces a well-formed stringified array back into edits", () => {
949
- const result = parse(JSON.stringify([{ old_text: "a", new_text: "b" }]));
950
- expect(result.success).toBe(true);
951
- expect(result.success && result.data.edits).toEqual([{ old_text: "a", new_text: "b" }]);
952
- });
953
- // Verbatim payloads recovered from ~/.gg session logs. Each broke a real
954
- // turn: unescaped control characters, a dropped `new_text` key, a `":`
955
- // corrupted into `>`, and a stream truncated mid-string.
956
- it.each([
957
- ["raw control character", '[{"old_text": "a\\nb", "new_text": "c\nd"}]'],
958
- ["missing new_text key", '[{"old_text": "a", " * Egress limits"}]'],
959
- ["corrupted key delimiter", '[{"old_text">function stopServer() {'],
960
- ["truncated mid-payload", '[{"old_text": "a", "new_text": "bb'],
961
- ])("rejects %s with actionable guidance", (_label, payload) => {
962
- const message = errorFor(payload);
963
- expect(message).toContain("JSON-encoded string");
964
- expect(message).toContain("real JSON array");
965
- expect(message).toContain("split the work");
966
- // The unactionable stock message is what caused the retry loop.
967
- expect(message).not.toContain("expected array, received string");
968
- });
969
- it("leaves non-string type errors on their default message", () => {
970
- expect(errorFor(42)).toContain("expected array, received number");
971
- });
972
- it("still reports per-item errors inside a real array", () => {
973
- expect(errorFor([{ old_text: 5 }])).toContain("expected string, received number");
974
- });
975
- });
976
- function contentOf(result) {
977
- if (typeof result === "string")
978
- return result;
979
- if (result && typeof result === "object" && "content" in result) {
980
- return result.content ?? "";
981
- }
982
- return "";
983
- }
984
- //# sourceMappingURL=edit.test.js.map