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