@calliopelabs/cli 2.5.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (476) hide show
  1. package/README.md +45 -661
  2. package/dist/acp.d.ts +78 -0
  3. package/dist/acp.d.ts.map +1 -0
  4. package/dist/acp.js +572 -0
  5. package/dist/acp.js.map +1 -0
  6. package/dist/bin.d.ts +3 -7
  7. package/dist/bin.d.ts.map +1 -1
  8. package/dist/bin.js +56 -79
  9. package/dist/bin.js.map +1 -1
  10. package/dist/budget.d.ts +64 -0
  11. package/dist/budget.d.ts.map +1 -0
  12. package/dist/budget.js +157 -0
  13. package/dist/budget.js.map +1 -0
  14. package/dist/checkpoint.d.ts +63 -30
  15. package/dist/checkpoint.d.ts.map +1 -1
  16. package/dist/checkpoint.js +247 -160
  17. package/dist/checkpoint.js.map +1 -1
  18. package/dist/circuit-breaker/breaker.js.map +1 -1
  19. package/dist/config.d.ts +86 -81
  20. package/dist/config.d.ts.map +1 -1
  21. package/dist/config.js +236 -304
  22. package/dist/config.js.map +1 -1
  23. package/dist/cost.d.ts +114 -0
  24. package/dist/cost.d.ts.map +1 -0
  25. package/dist/cost.js +499 -0
  26. package/dist/cost.js.map +1 -0
  27. package/dist/diff.d.ts.map +1 -1
  28. package/dist/diff.js +11 -7
  29. package/dist/diff.js.map +1 -1
  30. package/dist/errors.js +3 -3
  31. package/dist/errors.js.map +1 -1
  32. package/dist/files.js.map +1 -1
  33. package/dist/fleet.d.ts +30 -0
  34. package/dist/fleet.d.ts.map +1 -0
  35. package/dist/fleet.js +86 -0
  36. package/dist/fleet.js.map +1 -0
  37. package/dist/fuzzy-search.d.ts.map +1 -1
  38. package/dist/fuzzy-search.js +2 -1
  39. package/dist/fuzzy-search.js.map +1 -1
  40. package/dist/git-status.js.map +1 -1
  41. package/dist/headless.d.ts +1 -2
  42. package/dist/headless.d.ts.map +1 -1
  43. package/dist/headless.js +166 -24
  44. package/dist/headless.js.map +1 -1
  45. package/dist/hud/api.d.ts +3 -18
  46. package/dist/hud/api.d.ts.map +1 -1
  47. package/dist/hud/api.js +9 -352
  48. package/dist/hud/api.js.map +1 -1
  49. package/dist/hud/palettes.d.ts.map +1 -1
  50. package/dist/hud/palettes.js +0 -180
  51. package/dist/hud/palettes.js.map +1 -1
  52. package/dist/hud/skins.d.ts.map +1 -1
  53. package/dist/hud/skins.js +0 -263
  54. package/dist/hud/skins.js.map +1 -1
  55. package/dist/hud/types.d.ts +2 -5
  56. package/dist/hud/types.d.ts.map +1 -1
  57. package/dist/index.d.ts +1 -4
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +1 -4
  60. package/dist/index.js.map +1 -1
  61. package/dist/iteration-ledger.d.ts.map +1 -1
  62. package/dist/iteration-ledger.js +3 -2
  63. package/dist/iteration-ledger.js.map +1 -1
  64. package/dist/local-model.d.ts +150 -0
  65. package/dist/local-model.d.ts.map +1 -0
  66. package/dist/local-model.js +408 -0
  67. package/dist/local-model.js.map +1 -0
  68. package/dist/mcp.d.ts.map +1 -1
  69. package/dist/mcp.js +5 -2
  70. package/dist/mcp.js.map +1 -1
  71. package/dist/memory.d.ts.map +1 -1
  72. package/dist/memory.js +6 -4
  73. package/dist/memory.js.map +1 -1
  74. package/dist/model-detection.js +2 -2
  75. package/dist/model-detection.js.map +1 -1
  76. package/dist/parallel-tools.js.map +1 -1
  77. package/dist/plugins.d.ts +32 -1
  78. package/dist/plugins.d.ts.map +1 -1
  79. package/dist/plugins.js +116 -5
  80. package/dist/plugins.js.map +1 -1
  81. package/dist/policy.d.ts +43 -0
  82. package/dist/policy.d.ts.map +1 -0
  83. package/dist/policy.js +139 -0
  84. package/dist/policy.js.map +1 -0
  85. package/dist/project-config.d.ts +1 -2
  86. package/dist/project-config.d.ts.map +1 -1
  87. package/dist/project-config.js +0 -3
  88. package/dist/project-config.js.map +1 -1
  89. package/dist/providers/bedrock.d.ts.map +1 -1
  90. package/dist/providers/bedrock.js +2 -5
  91. package/dist/providers/bedrock.js.map +1 -1
  92. package/dist/providers/compat.d.ts +21 -0
  93. package/dist/providers/compat.d.ts.map +1 -1
  94. package/dist/providers/compat.js +176 -6
  95. package/dist/providers/compat.js.map +1 -1
  96. package/dist/providers/google.js.map +1 -1
  97. package/dist/providers/index.d.ts +19 -4
  98. package/dist/providers/index.d.ts.map +1 -1
  99. package/dist/providers/index.js +61 -10
  100. package/dist/providers/index.js.map +1 -1
  101. package/dist/providers/ollama.d.ts +2 -2
  102. package/dist/providers/ollama.d.ts.map +1 -1
  103. package/dist/providers/ollama.js +26 -6
  104. package/dist/providers/ollama.js.map +1 -1
  105. package/dist/providers/openai.d.ts.map +1 -1
  106. package/dist/providers/openai.js +14 -10
  107. package/dist/providers/openai.js.map +1 -1
  108. package/dist/providers/types.d.ts +8 -0
  109. package/dist/providers/types.d.ts.map +1 -1
  110. package/dist/providers/types.js.map +1 -1
  111. package/dist/replay.d.ts +37 -0
  112. package/dist/replay.d.ts.map +1 -0
  113. package/dist/replay.js +168 -0
  114. package/dist/replay.js.map +1 -0
  115. package/dist/router.d.ts +133 -0
  116. package/dist/router.d.ts.map +1 -0
  117. package/dist/{model-router.js → router.js} +329 -3
  118. package/dist/router.js.map +1 -0
  119. package/dist/runlog.d.ts +185 -0
  120. package/dist/runlog.d.ts.map +1 -0
  121. package/dist/runlog.js +398 -0
  122. package/dist/runlog.js.map +1 -0
  123. package/dist/{sandbox.d.ts → sandbox/docker.d.ts} +1 -1
  124. package/dist/sandbox/docker.d.ts.map +1 -0
  125. package/dist/{sandbox.js → sandbox/docker.js} +1 -1
  126. package/dist/sandbox/docker.js.map +1 -0
  127. package/dist/sandbox/index.d.ts +36 -0
  128. package/dist/sandbox/index.d.ts.map +1 -0
  129. package/dist/sandbox/index.js +62 -0
  130. package/dist/sandbox/index.js.map +1 -0
  131. package/dist/{sandbox-native.d.ts → sandbox/native.d.ts} +1 -1
  132. package/dist/sandbox/native.d.ts.map +1 -0
  133. package/dist/{sandbox-native.js → sandbox/native.js} +1 -1
  134. package/dist/sandbox/native.js.map +1 -0
  135. package/dist/scope.js +1 -1
  136. package/dist/scope.js.map +1 -1
  137. package/dist/scuttlebot/config.js.map +1 -1
  138. package/dist/scuttlebot/irc-client.js.map +1 -1
  139. package/dist/setup.d.ts.map +1 -1
  140. package/dist/setup.js +22 -54
  141. package/dist/setup.js.map +1 -1
  142. package/dist/skills.d.ts +39 -0
  143. package/dist/skills.d.ts.map +1 -1
  144. package/dist/skills.js +90 -8
  145. package/dist/skills.js.map +1 -1
  146. package/dist/storage.d.ts.map +1 -1
  147. package/dist/storage.js +6 -3
  148. package/dist/storage.js.map +1 -1
  149. package/dist/streaming.d.ts +25 -0
  150. package/dist/streaming.d.ts.map +1 -1
  151. package/dist/streaming.js +59 -0
  152. package/dist/streaming.js.map +1 -1
  153. package/dist/styles.d.ts +6 -0
  154. package/dist/styles.d.ts.map +1 -1
  155. package/dist/styles.js +11 -0
  156. package/dist/styles.js.map +1 -1
  157. package/dist/summarization.js.map +1 -1
  158. package/dist/terminal-image.js +1 -1
  159. package/dist/terminal-image.js.map +1 -1
  160. package/dist/themes.d.ts +5 -4
  161. package/dist/themes.d.ts.map +1 -1
  162. package/dist/themes.js +35 -90
  163. package/dist/themes.js.map +1 -1
  164. package/dist/tools.d.ts +27 -3
  165. package/dist/tools.d.ts.map +1 -1
  166. package/dist/tools.js +128 -179
  167. package/dist/tools.js.map +1 -1
  168. package/dist/types.d.ts +4 -3
  169. package/dist/types.d.ts.map +1 -1
  170. package/dist/types.js +21 -40
  171. package/dist/types.js.map +1 -1
  172. package/dist/ui/agent.d.ts +3 -6
  173. package/dist/ui/agent.d.ts.map +1 -1
  174. package/dist/ui/agent.js +328 -38
  175. package/dist/ui/agent.js.map +1 -1
  176. package/dist/ui/animations.d.ts +37 -0
  177. package/dist/ui/animations.d.ts.map +1 -0
  178. package/dist/ui/animations.js +227 -0
  179. package/dist/ui/animations.js.map +1 -0
  180. package/dist/ui/chat-input-keys.d.ts +42 -0
  181. package/dist/ui/chat-input-keys.d.ts.map +1 -0
  182. package/dist/ui/chat-input-keys.js +360 -0
  183. package/dist/ui/chat-input-keys.js.map +1 -0
  184. package/dist/ui/chat-input.d.ts +2 -1
  185. package/dist/ui/chat-input.d.ts.map +1 -1
  186. package/dist/ui/chat-input.js +31 -350
  187. package/dist/ui/chat-input.js.map +1 -1
  188. package/dist/ui/commands.d.ts +14 -46
  189. package/dist/ui/commands.d.ts.map +1 -1
  190. package/dist/ui/commands.js +416 -2899
  191. package/dist/ui/commands.js.map +1 -1
  192. package/dist/ui/completions.d.ts +1 -0
  193. package/dist/ui/completions.d.ts.map +1 -1
  194. package/dist/ui/completions.js +36 -107
  195. package/dist/ui/completions.js.map +1 -1
  196. package/dist/ui/components.d.ts +14 -6
  197. package/dist/ui/components.d.ts.map +1 -1
  198. package/dist/ui/components.js +17 -226
  199. package/dist/ui/components.js.map +1 -1
  200. package/dist/ui/context.js +6 -6
  201. package/dist/ui/context.js.map +1 -1
  202. package/dist/ui/debug-log.d.ts +11 -0
  203. package/dist/ui/debug-log.d.ts.map +1 -0
  204. package/dist/ui/debug-log.js +21 -0
  205. package/dist/ui/debug-log.js.map +1 -0
  206. package/dist/ui/error-boundary.d.ts.map +1 -1
  207. package/dist/ui/error-boundary.js.map +1 -1
  208. package/dist/ui/frame.d.ts.map +1 -1
  209. package/dist/ui/frame.js +1 -3
  210. package/dist/ui/frame.js.map +1 -1
  211. package/dist/ui/index.d.ts +11 -3
  212. package/dist/ui/index.d.ts.map +1 -1
  213. package/dist/ui/index.js +45 -1076
  214. package/dist/ui/index.js.map +1 -1
  215. package/dist/ui/messages.d.ts +4 -7
  216. package/dist/ui/messages.d.ts.map +1 -1
  217. package/dist/ui/messages.js +15 -30
  218. package/dist/ui/messages.js.map +1 -1
  219. package/dist/ui/modals/index.d.ts +11 -0
  220. package/dist/ui/modals/index.d.ts.map +1 -0
  221. package/dist/ui/modals/index.js +10 -0
  222. package/dist/ui/modals/index.js.map +1 -0
  223. package/dist/ui/modals/prompts.d.ts +37 -0
  224. package/dist/ui/modals/prompts.d.ts.map +1 -0
  225. package/dist/ui/modals/prompts.js +124 -0
  226. package/dist/ui/modals/prompts.js.map +1 -0
  227. package/dist/ui/modals/selectors.d.ts +33 -0
  228. package/dist/ui/modals/selectors.d.ts.map +1 -0
  229. package/dist/ui/modals/selectors.js +111 -0
  230. package/dist/ui/modals/selectors.js.map +1 -0
  231. package/dist/ui/modals/setup.d.ts +17 -0
  232. package/dist/ui/modals/setup.d.ts.map +1 -0
  233. package/dist/ui/modals/setup.js +51 -0
  234. package/dist/ui/modals/setup.js.map +1 -0
  235. package/dist/ui/regions/input-region.d.ts +40 -0
  236. package/dist/ui/regions/input-region.d.ts.map +1 -0
  237. package/dist/ui/regions/input-region.js +116 -0
  238. package/dist/ui/regions/input-region.js.map +1 -0
  239. package/dist/ui/regions/modal-host.d.ts +41 -0
  240. package/dist/ui/regions/modal-host.d.ts.map +1 -0
  241. package/dist/ui/regions/modal-host.js +51 -0
  242. package/dist/ui/regions/modal-host.js.map +1 -0
  243. package/dist/ui/regions/render-probe.d.ts +22 -0
  244. package/dist/ui/regions/render-probe.d.ts.map +1 -0
  245. package/dist/ui/regions/render-probe.js +45 -0
  246. package/dist/ui/regions/render-probe.js.map +1 -0
  247. package/dist/ui/regions/static-scrollback.d.ts +39 -0
  248. package/dist/ui/regions/static-scrollback.d.ts.map +1 -0
  249. package/dist/ui/regions/static-scrollback.js +68 -0
  250. package/dist/ui/regions/static-scrollback.js.map +1 -0
  251. package/dist/ui/regions/status-region.d.ts +24 -0
  252. package/dist/ui/regions/status-region.d.ts.map +1 -0
  253. package/dist/ui/regions/status-region.js +17 -0
  254. package/dist/ui/regions/status-region.js.map +1 -0
  255. package/dist/ui/regions/transcript-region.d.ts +41 -0
  256. package/dist/ui/regions/transcript-region.d.ts.map +1 -0
  257. package/dist/ui/regions/transcript-region.js +52 -0
  258. package/dist/ui/regions/transcript-region.js.map +1 -0
  259. package/dist/ui/self-restart.d.ts +9 -0
  260. package/dist/ui/self-restart.d.ts.map +1 -0
  261. package/dist/ui/self-restart.js +24 -0
  262. package/dist/ui/self-restart.js.map +1 -0
  263. package/dist/ui/state/use-chat-controller.d.ts +23 -0
  264. package/dist/ui/state/use-chat-controller.d.ts.map +1 -0
  265. package/dist/ui/state/use-chat-controller.js +643 -0
  266. package/dist/ui/state/use-chat-controller.js.map +1 -0
  267. package/dist/ui/state/use-loop-state.d.ts +23 -0
  268. package/dist/ui/state/use-loop-state.d.ts.map +1 -0
  269. package/dist/ui/state/use-loop-state.js +39 -0
  270. package/dist/ui/state/use-loop-state.js.map +1 -0
  271. package/dist/ui/state/use-modal-state.d.ts +52 -0
  272. package/dist/ui/state/use-modal-state.d.ts.map +1 -0
  273. package/dist/ui/state/use-modal-state.js +44 -0
  274. package/dist/ui/state/use-modal-state.js.map +1 -0
  275. package/dist/ui/state/use-model-state.d.ts +29 -0
  276. package/dist/ui/state/use-model-state.d.ts.map +1 -0
  277. package/dist/ui/state/use-model-state.js +47 -0
  278. package/dist/ui/state/use-model-state.js.map +1 -0
  279. package/dist/ui/state/use-processing-state.d.ts +24 -0
  280. package/dist/ui/state/use-processing-state.d.ts.map +1 -0
  281. package/dist/ui/state/use-processing-state.js +46 -0
  282. package/dist/ui/state/use-processing-state.js.map +1 -0
  283. package/dist/ui/state/use-queue-state.d.ts +19 -0
  284. package/dist/ui/state/use-queue-state.d.ts.map +1 -0
  285. package/dist/ui/state/use-queue-state.js +30 -0
  286. package/dist/ui/state/use-queue-state.js.map +1 -0
  287. package/dist/ui/state/use-session-init.d.ts +22 -0
  288. package/dist/ui/state/use-session-init.d.ts.map +1 -0
  289. package/dist/ui/state/use-session-init.js +77 -0
  290. package/dist/ui/state/use-session-init.js.map +1 -0
  291. package/dist/ui/state/use-session-stats.d.ts +16 -0
  292. package/dist/ui/state/use-session-stats.d.ts.map +1 -0
  293. package/dist/ui/state/use-session-stats.js +18 -0
  294. package/dist/ui/state/use-session-stats.js.map +1 -0
  295. package/dist/ui/state/use-terminal-width.d.ts +8 -0
  296. package/dist/ui/state/use-terminal-width.d.ts.map +1 -0
  297. package/dist/ui/state/use-terminal-width.js +22 -0
  298. package/dist/ui/state/use-terminal-width.js.map +1 -0
  299. package/dist/ui/state/use-transcript-state.d.ts +21 -0
  300. package/dist/ui/state/use-transcript-state.d.ts.map +1 -0
  301. package/dist/ui/state/use-transcript-state.js +49 -0
  302. package/dist/ui/state/use-transcript-state.js.map +1 -0
  303. package/dist/ui/status-bar.d.ts.map +1 -1
  304. package/dist/ui/status-bar.js +2 -3
  305. package/dist/ui/status-bar.js.map +1 -1
  306. package/dist/version-check.d.ts.map +1 -1
  307. package/dist/version-check.js +10 -0
  308. package/dist/version-check.js.map +1 -1
  309. package/package.json +10 -3
  310. package/dist/agents/agent-config-loader.d.ts +0 -60
  311. package/dist/agents/agent-config-loader.d.ts.map +0 -1
  312. package/dist/agents/agent-config-loader.js +0 -402
  313. package/dist/agents/agent-config-loader.js.map +0 -1
  314. package/dist/agents/agent-config-presets.d.ts +0 -10
  315. package/dist/agents/agent-config-presets.d.ts.map +0 -1
  316. package/dist/agents/agent-config-presets.js +0 -940
  317. package/dist/agents/agent-config-presets.js.map +0 -1
  318. package/dist/agents/agent-config-types.d.ts +0 -145
  319. package/dist/agents/agent-config-types.d.ts.map +0 -1
  320. package/dist/agents/agent-config-types.js +0 -12
  321. package/dist/agents/agent-config-types.js.map +0 -1
  322. package/dist/agents/agent-detection.d.ts +0 -35
  323. package/dist/agents/agent-detection.d.ts.map +0 -1
  324. package/dist/agents/agent-detection.js +0 -110
  325. package/dist/agents/agent-detection.js.map +0 -1
  326. package/dist/agents/aggregator.d.ts +0 -19
  327. package/dist/agents/aggregator.d.ts.map +0 -1
  328. package/dist/agents/aggregator.js +0 -141
  329. package/dist/agents/aggregator.js.map +0 -1
  330. package/dist/agents/cli-backend.d.ts +0 -32
  331. package/dist/agents/cli-backend.d.ts.map +0 -1
  332. package/dist/agents/cli-backend.js +0 -271
  333. package/dist/agents/cli-backend.js.map +0 -1
  334. package/dist/agents/council-types.d.ts +0 -115
  335. package/dist/agents/council-types.d.ts.map +0 -1
  336. package/dist/agents/council-types.js +0 -81
  337. package/dist/agents/council-types.js.map +0 -1
  338. package/dist/agents/council.d.ts +0 -112
  339. package/dist/agents/council.d.ts.map +0 -1
  340. package/dist/agents/council.js +0 -722
  341. package/dist/agents/council.js.map +0 -1
  342. package/dist/agents/decomposer.d.ts +0 -33
  343. package/dist/agents/decomposer.d.ts.map +0 -1
  344. package/dist/agents/decomposer.js +0 -138
  345. package/dist/agents/decomposer.js.map +0 -1
  346. package/dist/agents/dynamic-tools.d.ts +0 -52
  347. package/dist/agents/dynamic-tools.d.ts.map +0 -1
  348. package/dist/agents/dynamic-tools.js +0 -424
  349. package/dist/agents/dynamic-tools.js.map +0 -1
  350. package/dist/agents/index.d.ts +0 -29
  351. package/dist/agents/index.d.ts.map +0 -1
  352. package/dist/agents/index.js +0 -29
  353. package/dist/agents/index.js.map +0 -1
  354. package/dist/agents/installer.d.ts +0 -39
  355. package/dist/agents/installer.d.ts.map +0 -1
  356. package/dist/agents/installer.js +0 -205
  357. package/dist/agents/installer.js.map +0 -1
  358. package/dist/agents/orchestrator.d.ts +0 -106
  359. package/dist/agents/orchestrator.d.ts.map +0 -1
  360. package/dist/agents/orchestrator.js +0 -363
  361. package/dist/agents/orchestrator.js.map +0 -1
  362. package/dist/agents/sdk-backend.d.ts +0 -63
  363. package/dist/agents/sdk-backend.d.ts.map +0 -1
  364. package/dist/agents/sdk-backend.js +0 -489
  365. package/dist/agents/sdk-backend.js.map +0 -1
  366. package/dist/agents/swarm-types.d.ts +0 -84
  367. package/dist/agents/swarm-types.d.ts.map +0 -1
  368. package/dist/agents/swarm-types.js +0 -20
  369. package/dist/agents/swarm-types.js.map +0 -1
  370. package/dist/agents/swarm.d.ts +0 -79
  371. package/dist/agents/swarm.d.ts.map +0 -1
  372. package/dist/agents/swarm.js +0 -375
  373. package/dist/agents/swarm.js.map +0 -1
  374. package/dist/agents/tools.d.ts +0 -26
  375. package/dist/agents/tools.d.ts.map +0 -1
  376. package/dist/agents/tools.js +0 -776
  377. package/dist/agents/tools.js.map +0 -1
  378. package/dist/agents/types.d.ts +0 -108
  379. package/dist/agents/types.d.ts.map +0 -1
  380. package/dist/agents/types.js +0 -43
  381. package/dist/agents/types.js.map +0 -1
  382. package/dist/api-server.d.ts +0 -45
  383. package/dist/api-server.d.ts.map +0 -1
  384. package/dist/api-server.js +0 -326
  385. package/dist/api-server.js.map +0 -1
  386. package/dist/auto-checkpoint.d.ts +0 -35
  387. package/dist/auto-checkpoint.d.ts.map +0 -1
  388. package/dist/auto-checkpoint.js +0 -176
  389. package/dist/auto-checkpoint.js.map +0 -1
  390. package/dist/background-jobs.d.ts +0 -45
  391. package/dist/background-jobs.d.ts.map +0 -1
  392. package/dist/background-jobs.js +0 -127
  393. package/dist/background-jobs.js.map +0 -1
  394. package/dist/branching.d.ts +0 -56
  395. package/dist/branching.d.ts.map +0 -1
  396. package/dist/branching.js +0 -224
  397. package/dist/branching.js.map +0 -1
  398. package/dist/cli/agent.d.ts +0 -9
  399. package/dist/cli/agent.d.ts.map +0 -1
  400. package/dist/cli/agent.js +0 -330
  401. package/dist/cli/agent.js.map +0 -1
  402. package/dist/cli/commands.d.ts +0 -12
  403. package/dist/cli/commands.d.ts.map +0 -1
  404. package/dist/cli/commands.js +0 -1042
  405. package/dist/cli/commands.js.map +0 -1
  406. package/dist/cli/index.d.ts +0 -8
  407. package/dist/cli/index.d.ts.map +0 -1
  408. package/dist/cli/index.js +0 -268
  409. package/dist/cli/index.js.map +0 -1
  410. package/dist/cli/types.d.ts +0 -33
  411. package/dist/cli/types.d.ts.map +0 -1
  412. package/dist/cli/types.js +0 -21
  413. package/dist/cli/types.js.map +0 -1
  414. package/dist/companions.d.ts +0 -54
  415. package/dist/companions.d.ts.map +0 -1
  416. package/dist/companions.js +0 -440
  417. package/dist/companions.js.map +0 -1
  418. package/dist/file-watcher.d.ts +0 -91
  419. package/dist/file-watcher.d.ts.map +0 -1
  420. package/dist/file-watcher.js +0 -269
  421. package/dist/file-watcher.js.map +0 -1
  422. package/dist/hud/theme-packs/api.d.ts +0 -51
  423. package/dist/hud/theme-packs/api.d.ts.map +0 -1
  424. package/dist/hud/theme-packs/api.js +0 -145
  425. package/dist/hud/theme-packs/api.js.map +0 -1
  426. package/dist/hud/theme-packs/index.d.ts +0 -18
  427. package/dist/hud/theme-packs/index.d.ts.map +0 -1
  428. package/dist/hud/theme-packs/index.js +0 -38
  429. package/dist/hud/theme-packs/index.js.map +0 -1
  430. package/dist/hud/theme-packs/types.d.ts +0 -29
  431. package/dist/hud/theme-packs/types.d.ts.map +0 -1
  432. package/dist/hud/theme-packs/types.js +0 -9
  433. package/dist/hud/theme-packs/types.js.map +0 -1
  434. package/dist/idle-eviction.d.ts +0 -34
  435. package/dist/idle-eviction.d.ts.map +0 -1
  436. package/dist/idle-eviction.js +0 -85
  437. package/dist/idle-eviction.js.map +0 -1
  438. package/dist/model-router.d.ts +0 -67
  439. package/dist/model-router.d.ts.map +0 -1
  440. package/dist/model-router.js.map +0 -1
  441. package/dist/providers/openai-compat-shims.d.ts +0 -31
  442. package/dist/providers/openai-compat-shims.d.ts.map +0 -1
  443. package/dist/providers/openai-compat-shims.js +0 -179
  444. package/dist/providers/openai-compat-shims.js.map +0 -1
  445. package/dist/sandbox-native.d.ts.map +0 -1
  446. package/dist/sandbox-native.js.map +0 -1
  447. package/dist/sandbox.d.ts.map +0 -1
  448. package/dist/sandbox.js.map +0 -1
  449. package/dist/session-timeout.d.ts +0 -31
  450. package/dist/session-timeout.d.ts.map +0 -1
  451. package/dist/session-timeout.js +0 -100
  452. package/dist/session-timeout.js.map +0 -1
  453. package/dist/smart-router.d.ts +0 -73
  454. package/dist/smart-router.d.ts.map +0 -1
  455. package/dist/smart-router.js +0 -332
  456. package/dist/smart-router.js.map +0 -1
  457. package/dist/terminal-recording.d.ts +0 -55
  458. package/dist/terminal-recording.d.ts.map +0 -1
  459. package/dist/terminal-recording.js +0 -182
  460. package/dist/terminal-recording.js.map +0 -1
  461. package/dist/tmux.d.ts +0 -35
  462. package/dist/tmux.d.ts.map +0 -1
  463. package/dist/tmux.js +0 -106
  464. package/dist/tmux.js.map +0 -1
  465. package/dist/ui/modals.d.ts +0 -72
  466. package/dist/ui/modals.d.ts.map +0 -1
  467. package/dist/ui/modals.js +0 -266
  468. package/dist/ui/modals.js.map +0 -1
  469. package/dist/ui/pack-picker.d.ts +0 -12
  470. package/dist/ui/pack-picker.d.ts.map +0 -1
  471. package/dist/ui/pack-picker.js +0 -101
  472. package/dist/ui/pack-picker.js.map +0 -1
  473. package/dist/ui/theme-picker.d.ts +0 -24
  474. package/dist/ui/theme-picker.d.ts.map +0 -1
  475. package/dist/ui/theme-picker.js +0 -190
  476. package/dist/ui/theme-picker.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAY7D;;GAEG;AACH,eAAO,MAAM,KAAK,EAAE,IAAI,EA0UvB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,YAAY,GAAE,OAAe,GAAG,IAAI,EAAE,CAM9D;AAoCD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,MAAM,EACX,OAAO,SAAQ,EACf,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GACjC,OAAO,CAAC,UAAU,CAAC,CAgVrB"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAS7D;;GAEG;AACH,eAAO,MAAM,KAAK,EAAE,IAAI,EA2TvB,CAAC;AAEF;;GAEG;AACH,wBAAgB,QAAQ,IAAI,IAAI,EAAE,CAGjC;AAoCD;;;;;;;;;GASG;AACH,MAAM,WAAW,UAAU;IACzB,YAAY,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,aAAa,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjE;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,EAAE,CAAC,EAAE,UAAU,CAAC;CACjB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,MAAM,EACX,OAAO,SAAQ,EACf,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EAClC,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,UAAU,CAAC,CA+QrB"}
package/dist/tools.js CHANGED
@@ -8,16 +8,13 @@ import * as fs from 'fs';
8
8
  import * as path from 'path';
9
9
  import * as os from 'os';
10
10
  import { StringDecoder } from 'string_decoder';
11
- import * as sandbox from './sandbox.js';
12
- import * as nativeSandbox from './sandbox-native.js';
13
- import { getAgtermTools, isAgtermTool, executeAgtermTool } from './agents/index.js';
11
+ import * as sandbox from './sandbox/index.js';
14
12
  import { validatePath as scopeValidatePath, isInScope } from './scope.js';
15
13
  import { getPluginTools, isPluginTool, executePluginTool } from './plugins.js';
16
14
  import config from './config.js';
17
- import { applySkin, applyPalette, listSkins, listPalettes } from './hud/api.js';
18
- import { listCompanions } from './companions.js';
19
15
  import { generateDiff as generateFileDiff } from './diff.js';
20
- import { scuttlebotClient } from './scuttlebot/index.js';
16
+ import { fleetActive, fleetMirrorToolCall } from './fleet.js';
17
+ import { computeAnchorHash, anchorHashFooter } from './local-model.js';
21
18
  /**
22
19
  * Available tools for the agent
23
20
  */
@@ -273,36 +270,21 @@ export const TOOLS = [
273
270
  },
274
271
  {
275
272
  name: 'configure',
276
- description: `Read, set, or list Calliope configuration options. Use this when the user asks to change settings, switch themes, providers, models, companions, or any preference through natural conversation. Always use action "list" first if you need to show available options.
273
+ description: `Read, set, or list Calliope configuration options. Use this when the user asks to change settings, switch themes, providers, models, or any preference through natural conversation. Always use action "list" first if you need to show available options.
277
274
 
278
275
  CONFIGURABLE SETTINGS:
279
276
  - defaultProvider: AI provider (anthropic, google, openai, together, openrouter, groq, fireworks, mistral, ollama, ai21, huggingface, litellm, bedrock, auto)
280
277
  - defaultModel: Model name string (provider-specific, e.g. "claude-sonnet-4-6", "gemini-2.0-flash", "gpt-4o")
281
- - persona: Agent persona style (calliope, muse, minimal)
282
278
  - maxIterations: Max agent loop iterations (0 = unlimited)
283
279
  - maxIterationTime: Max seconds per iteration (0 = no limit, default: 600)
284
- - fancyOutput: Enable rich formatting (true/false)
285
280
  - autoSaveHistory: Auto-save session history (true/false)
286
281
  - autoUpgrade: Check for updates on startup (true/false)
287
282
  - collapseTools: Auto-collapse tool output (true/false)
288
- - collapseThinking: Auto-collapse think blocks (true/false)
289
283
  - toolDisplayLimit: Show last N tools expanded (0 = all)
290
- - layout: UI layout (classic, response-top, response-bottom, split, zen, focus, dashboard, minimal)
291
- - density: Display density (normal, compact)
292
- - activeSkin: Terminal skin/theme name (use action "list" category "skins" to see options)
293
- - activePalette: Color palette name (use action "list" category "palettes" to see options)
294
- - activeCompanion: AI companion personality (use action "list" category "companions" to see options)
295
- - companionIntensity: Companion personality level (professional, immersive)
296
- - useEmojis: Show emojis in UI (true/false)
297
284
  - diffStyle: Diff display format (inline, unified, side-by-side)
298
- - borderStyle: UI border style (rounded, sharp, double, ascii, none)
299
- - bannerStyle: Startup banner (full, compact, none)
300
285
  - circuitBreakersEnabled: Safety circuit breakers (true/false)
301
286
  - sandboxMode: Code execution sandbox (auto, native, docker, off)
302
- - smartRoutingEnabled: Dynamic model routing (true/false)
303
- - smartRoutingCostSensitivity: Cost vs quality (0-1, 0=best quality, 1=cheapest)
304
- - recordSessions: Record session audit logs (true/false)
305
- - recordingRetentionDays: Auto-delete old recordings after N days (0 = keep forever)`,
287
+ - sessionLogLimit: Cap retained session log items (0 = unlimited)`,
306
288
  parameters: {
307
289
  type: 'object',
308
290
  properties: {
@@ -321,8 +303,8 @@ CONFIGURABLE SETTINGS:
321
303
  },
322
304
  category: {
323
305
  type: 'string',
324
- description: 'Category to list options for (for list action): skins, palettes, companions, providers, layouts, all',
325
- enum: ['skins', 'palettes', 'companions', 'providers', 'layouts', 'all'],
306
+ description: 'Category to list options for (for list action): providers, layouts, all',
307
+ enum: ['providers', 'layouts', 'all'],
326
308
  },
327
309
  },
328
310
  required: ['action'],
@@ -354,13 +336,9 @@ CONFIGURABLE SETTINGS:
354
336
  ];
355
337
  /**
356
338
  * Get all available tools
357
- * Includes agent tools when agentEnabled is true
358
339
  */
359
- export function getTools(agentEnabled = false) {
340
+ export function getTools() {
360
341
  const pluginTools = getPluginTools();
361
- if (agentEnabled) {
362
- return [...TOOLS, ...getAgtermTools(), ...pluginTools];
363
- }
364
342
  return [...TOOLS, ...pluginTools];
365
343
  }
366
344
  /**
@@ -395,17 +373,11 @@ function validatePath(filePath, cwd) {
395
373
  /**
396
374
  * Execute a tool call
397
375
  */
398
- export async function executeTool(toolCall, cwd, timeout = 60000, onOutput) {
376
+ export async function executeTool(toolCall, cwd, timeout = 60000, onOutput, options) {
399
377
  const { id, name, arguments: args } = toolCall;
400
- // Mirror tool call to scuttlebot
401
- if (scuttlebotClient.isEnabled()) {
402
- await scuttlebotClient.mirrorToolCall(name, args).catch(() => {
403
- // Silently fail - don't interrupt tool execution
404
- });
405
- }
406
- // Handle agent tools
407
- if (isAgtermTool(name)) {
408
- return executeAgtermTool(toolCall, cwd);
378
+ // Mirror tool call to the fleet channel
379
+ if (fleetActive()) {
380
+ await fleetMirrorToolCall(name, args);
409
381
  }
410
382
  // Handle plugin tools
411
383
  if (isPluginTool(name)) {
@@ -425,7 +397,7 @@ export async function executeTool(toolCall, cwd, timeout = 60000, onOutput) {
425
397
  if (typeof args.path !== 'string') {
426
398
  return { toolCallId: id, result: 'Error: path must be a string', isError: true };
427
399
  }
428
- result = await readFile(args.path, cwd);
400
+ result = await readFile(args.path, cwd, options?.appendAnchorHash === true, options?.fs);
429
401
  break;
430
402
  }
431
403
  case 'write_file': {
@@ -435,7 +407,7 @@ export async function executeTool(toolCall, cwd, timeout = 60000, onOutput) {
435
407
  if (typeof args.content !== 'string') {
436
408
  return { toolCallId: id, result: 'Error: content must be a string', isError: true };
437
409
  }
438
- result = await writeFile(args.path, args.content, cwd);
410
+ result = await writeFile(args.path, args.content, cwd, options?.fs);
439
411
  break;
440
412
  }
441
413
  case 'list_files': {
@@ -520,42 +492,21 @@ export async function executeTool(toolCall, cwd, timeout = 60000, onOutput) {
520
492
  if (action === 'list') {
521
493
  const category = args.category || 'all';
522
494
  const sections = [];
523
- if (category === 'skins' || category === 'all') {
524
- const skins = listSkins();
525
- const current = config.get('activeSkin');
526
- sections.push('SKINS (activeSkin):\n' + skins.map(s => ` ${s.name === current ? '→ ' : ' '}${s.name} - ${s.description}`).join('\n'));
527
- }
528
- if (category === 'palettes' || category === 'all') {
529
- const palettes = listPalettes();
530
- const current = config.get('activePalette');
531
- sections.push('PALETTES (activePalette):\n' + palettes.map(p => ` ${p.name === current ? '→ ' : ' '}${p.name} - ${p.description}`).join('\n'));
532
- }
533
- if (category === 'companions' || category === 'all') {
534
- const companions = listCompanions();
535
- const current = config.get('activeCompanion');
536
- sections.push('COMPANIONS (activeCompanion):\n' + companions.map(c => ` ${c.name === current ? '→ ' : ' '}${c.name} - ${c.description}`).join('\n'));
537
- }
538
495
  if (category === 'providers' || category === 'all') {
539
496
  const providers = ['anthropic', 'google', 'openai', 'together', 'openrouter', 'groq', 'fireworks', 'mistral', 'ollama', 'ai21', 'huggingface', 'litellm', 'bedrock', 'auto'];
540
497
  const current = config.get('defaultProvider');
541
498
  sections.push('PROVIDERS (defaultProvider):\n' + providers.map(p => ` ${p === current ? '→ ' : ' '}${p}`).join('\n'));
542
499
  }
543
- if (category === 'layouts' || category === 'all') {
544
- const layouts = ['classic', 'response-top', 'response-bottom', 'split', 'zen', 'focus', 'dashboard', 'minimal'];
545
- const current = config.get('layout');
546
- sections.push('LAYOUTS (layout):\n' + layouts.map(l => ` ${l === current ? '→ ' : ' '}${l}`).join('\n'));
547
- }
548
500
  if (category === 'all') {
549
501
  // Also show current key settings
550
502
  const currentSettings = [
551
- `density: ${config.get('density')}`,
552
- `companionIntensity: ${config.get('companionIntensity')}`,
553
- `useEmojis: ${config.get('useEmojis')}`,
554
503
  `diffStyle: ${config.get('diffStyle')}`,
555
- `borderStyle: ${config.get('borderStyle')}`,
556
- `bannerStyle: ${config.get('bannerStyle')}`,
557
504
  `sandboxMode: ${config.get('sandboxMode')}`,
558
- `smartRoutingEnabled: ${config.get('smartRoutingEnabled')}`,
505
+ `collapseTools: ${config.get('collapseTools')}`,
506
+ `toolDisplayLimit: ${config.get('toolDisplayLimit')}`,
507
+ `maxIterations: ${config.get('maxIterations')}`,
508
+ `sessionLogLimit: ${config.get('sessionLogLimit')}`,
509
+ `routing.enabled: ${config.get('routing')?.enabled ?? false}`,
559
510
  `defaultModel: ${config.get('defaultModel') || '(auto)'}`,
560
511
  ];
561
512
  sections.push('CURRENT SETTINGS:\n' + currentSettings.map(s => ` ${s}`).join('\n'));
@@ -583,16 +534,11 @@ export async function executeTool(toolCall, cwd, timeout = 60000, onOutput) {
583
534
  }
584
535
  // Only allow setting safe keys through conversation (allowlist)
585
536
  const SAFE_CONFIG_KEYS = new Set([
586
- 'defaultProvider', 'defaultModel', 'persona', 'maxIterations', 'maxIterationTime',
587
- 'fancyOutput', 'autoSaveHistory', 'autoUpgrade',
588
- 'collapseTools', 'collapseThinking', 'toolDisplayLimit',
589
- 'layout', 'density',
590
- 'activeSkin', 'activePalette', 'activeCompanion', 'activeThemePack',
591
- 'companionIntensity', 'useEmojis', 'diffStyle', 'borderStyle', 'bannerStyle',
537
+ 'defaultProvider', 'defaultModel', 'maxIterations', 'maxIterationTime',
538
+ 'autoSaveHistory', 'autoUpgrade',
539
+ 'collapseTools', 'toolDisplayLimit', 'diffStyle',
592
540
  'circuitBreakersEnabled', 'sandboxMode',
593
- 'smartRoutingEnabled', 'smartRoutingCostSensitivity',
594
- 'recordSessions', 'recordingRetentionDays', 'sessionLogLimit',
595
- 'awsRegion', 'awsProfile',
541
+ 'sessionLogLimit',
596
542
  ]);
597
543
  if (!SAFE_CONFIG_KEYS.has(key)) {
598
544
  return { toolCallId: id, result: `Error: "${key}" cannot be set through conversation. Use /keys command, environment variables, or edit the config file directly.`, isError: true };
@@ -606,31 +552,6 @@ export async function executeTool(toolCall, cwd, timeout = 60000, onOutput) {
606
552
  else if (/^\d+(\.\d+)?$/.test(rawValue))
607
553
  parsedValue = Number(rawValue);
608
554
  try {
609
- // Special handling for HUD settings that need apply functions
610
- if (key === 'activeSkin') {
611
- const success = applySkin(rawValue);
612
- if (!success) {
613
- return { toolCallId: id, result: `Error: skin "${rawValue}" not found. Use action "list" category "skins" to see available skins.`, isError: true };
614
- }
615
- result = `Skin changed to "${rawValue}"`;
616
- break;
617
- }
618
- if (key === 'activePalette') {
619
- const success = applyPalette(rawValue);
620
- if (!success) {
621
- return { toolCallId: id, result: `Error: palette "${rawValue}" not found. Use action "list" category "palettes" to see available palettes.`, isError: true };
622
- }
623
- result = `Palette changed to "${rawValue}"`;
624
- break;
625
- }
626
- if (key === 'activeCompanion') {
627
- if (!listCompanions().some(c => c.name === rawValue)) {
628
- return { toolCallId: id, result: `Error: companion "${rawValue}" not found. Use action "list" category "companions" to see available companions.`, isError: true };
629
- }
630
- config.set('activeCompanion', rawValue);
631
- result = `Companion changed to "${rawValue}"`;
632
- break;
633
- }
634
555
  // Generic config set
635
556
  config.set(key, parsedValue);
636
557
  result = `Set ${key} = ${JSON.stringify(parsedValue)}`;
@@ -660,7 +581,10 @@ export async function executeTool(toolCall, cwd, timeout = 60000, onOutput) {
660
581
  return { toolCallId: id, result: 'Error: new_string must be a string', isError: true };
661
582
  }
662
583
  const replaceAll = args.replace_all === true;
663
- result = await editFile(args.path, args.old_string, args.new_string, replaceAll, cwd);
584
+ // anchor_hash is optional and accepted from any caller; it is only
585
+ // advertised in the simplified local schema (feature 4).
586
+ const anchorHash = typeof args.anchor_hash === 'string' ? args.anchor_hash : undefined;
587
+ result = await editFile(args.path, args.old_string, args.new_string, replaceAll, cwd, anchorHash, options?.fs);
664
588
  break;
665
589
  }
666
590
  case 'glob': {
@@ -708,7 +632,7 @@ export async function executeTool(toolCall, cwd, timeout = 60000, onOutput) {
708
632
  * SECURITY NOTE (#132): This denylist is ADVISORY / defense-in-depth only. It is
709
633
  * fundamentally unwinnable to perfectly screen an arbitrary `bash -c` string, so
710
634
  * treat this as a best-effort tripwire, NOT a security boundary. The real control
711
- * is the native sandbox (see src/sandbox-native.ts); when no sandbox is available
635
+ * is the native sandbox (see src/sandbox/native.ts); when no sandbox is available
712
636
  * the shell tool fails closed (see shouldUseNativeSandbox / executeShell).
713
637
  */
714
638
  const BLOCKED_COMMANDS = [
@@ -852,29 +776,11 @@ function validateShellPaths(command, cwd) {
852
776
  for (const p of extractedPaths) {
853
777
  const allowed = isInScope(p, cwd);
854
778
  if (!allowed) {
855
- return 'Shell command blocked: "' + p + '" is outside allowed scope. Use /add-dir to expand scope.';
779
+ return 'Shell command blocked: "' + p + '" is outside allowed scope. Use /scope add to expand scope.';
856
780
  }
857
781
  }
858
782
  return null;
859
783
  }
860
- /**
861
- * Determine whether to use native sandboxing for shell commands based on config.
862
- *
863
- * sandboxMode values:
864
- * - 'auto': use native sandbox when available, otherwise run unsandboxed
865
- * - 'native': require native sandbox (fail if unavailable)
866
- * - 'docker': defer to Docker sandbox (handled elsewhere)
867
- * - 'off': no sandboxing
868
- */
869
- function shouldUseNativeSandbox() {
870
- const mode = config.get('sandboxMode') || 'auto';
871
- if (mode === 'off' || mode === 'docker')
872
- return 'skip';
873
- if (mode === 'native')
874
- return 'require';
875
- // 'auto': use if available
876
- return nativeSandbox.isNativeSandboxAvailable() ? 'use' : 'skip';
877
- }
878
784
  /**
879
785
  * Execute a shell command
880
786
  */
@@ -890,8 +796,8 @@ async function executeShell(command, cwd, timeout, onOutput) {
890
796
  return `Error: ${scopeError}`;
891
797
  }
892
798
  // Check if native sandbox should be used
893
- const sandboxDecision = shouldUseNativeSandbox();
894
- if (sandboxDecision === 'require' && !nativeSandbox.isNativeSandboxAvailable()) {
799
+ const sandboxDecision = sandbox.shouldUseNativeSandbox();
800
+ if (sandboxDecision === 'require' && !sandbox.isNativeSandboxAvailable()) {
895
801
  return 'Error: Native sandbox required (sandboxMode=native) but not available on this platform.';
896
802
  }
897
803
  // 'auto' is best-effort: when no native backend exists (e.g. Linux/Windows
@@ -903,7 +809,7 @@ async function executeShell(command, cwd, timeout, onOutput) {
903
809
  if (sandboxDecision === 'use' || sandboxDecision === 'require') {
904
810
  // Network is OFF by default; opt in via CALLIOPE_SHELL_NETWORK=1 (#133).
905
811
  const networkEnabled = process.env.CALLIOPE_SHELL_NETWORK === '1';
906
- const result = await nativeSandbox.executeInNativeSandbox(command, cwd, {
812
+ const result = await sandbox.executeInNativeSandbox(command, cwd, {
907
813
  timeout,
908
814
  networkEnabled,
909
815
  });
@@ -974,27 +880,41 @@ async function executeShell(command, cwd, timeout, onOutput) {
974
880
  }
975
881
  /**
976
882
  * Read a file
883
+ *
884
+ * When `appendAnchorHash` is set (local backends only), the current content hash
885
+ * is appended so the model can echo it back on a subsequent anchored edit_file
886
+ * (stale-view protection, feature 4).
977
887
  */
978
- async function readFile(filePath, cwd) {
888
+ async function readFile(filePath, cwd, appendAnchorHash = false, fsDelegate) {
979
889
  const absPath = validatePath(filePath, cwd);
980
- if (!fs.existsSync(absPath)) {
981
- throw new Error(`File not found: ${absPath}`);
890
+ let content;
891
+ if (fsDelegate?.readTextFile) {
892
+ // Client-side fs (e.g. an ACP editor buffer that may hold unsaved changes).
893
+ // The client owns existence/size; a missing file surfaces as a thrown error
894
+ // that executeTool turns into a normal tool error.
895
+ content = await fsDelegate.readTextFile(absPath);
982
896
  }
983
- const stats = fs.statSync(absPath);
984
- if (stats.isDirectory()) {
985
- throw new Error(`Path is a directory: ${absPath}`);
986
- }
987
- // Check file size (limit to 1MB)
988
- if (stats.size > 1024 * 1024) {
989
- throw new Error(`File too large (${Math.round(stats.size / 1024)}KB). Max 1MB.`);
897
+ else {
898
+ if (!fs.existsSync(absPath)) {
899
+ throw new Error(`File not found: ${absPath}`);
900
+ }
901
+ const stats = fs.statSync(absPath);
902
+ if (stats.isDirectory()) {
903
+ throw new Error(`Path is a directory: ${absPath}`);
904
+ }
905
+ // Check file size (limit to 1MB)
906
+ if (stats.size > 1024 * 1024) {
907
+ throw new Error(`File too large (${Math.round(stats.size / 1024)}KB). Max 1MB.`);
908
+ }
909
+ content = fs.readFileSync(absPath, 'utf-8');
990
910
  }
991
- const content = fs.readFileSync(absPath, 'utf-8');
992
911
  // Inline file preview header (#119). The header carries the line count;
993
912
  // the full content follows once — no preview/footer, those duplicated the
994
913
  // first 20 lines on every read and cost ~20% extra tokens on short files.
995
914
  const totalLines = content.split('\n').length;
996
915
  const header = `[file: ${filePath} \u2014 ${totalLines} line${totalLines !== 1 ? 's' : ''}]\n${'─'.repeat(40)}`;
997
- return `${header}\n${content}`;
916
+ const footer = appendAnchorHash ? anchorHashFooter(computeAnchorHash(content)) : '';
917
+ return `${header}\n${content}${footer}`;
998
918
  }
999
919
  /**
1000
920
  * Generate a simple line-diff between old and new content
@@ -1009,9 +929,7 @@ function generateDiff(oldContent, newContent, maxLines = 20) {
1009
929
  let deletions = 0;
1010
930
  let changesShown = 0;
1011
931
  let contextLines = 0;
1012
- // Use density setting: compact = 1 context line, normal = 3
1013
- const density = config.get('density') || 'normal';
1014
- const contextWindow = density === 'compact' ? 1 : 3;
932
+ const contextWindow = 3;
1015
933
  // Compute line number width
1016
934
  const lineNumWidth = Math.max(4, maxIdx.toString().length);
1017
935
  const padNum = (n) => String(n).padStart(lineNumWidth, ' ');
@@ -1059,39 +977,46 @@ function generateDiff(oldContent, newContent, maxLines = 20) {
1059
977
  /**
1060
978
  * Write a file
1061
979
  */
1062
- async function writeFile(filePath, content, cwd) {
980
+ async function writeFile(filePath, content, cwd, fsDelegate) {
1063
981
  const absPath = validatePath(filePath, cwd);
1064
- // Create directory if needed
1065
- const dir = path.dirname(absPath);
1066
- if (!fs.existsSync(dir)) {
1067
- fs.mkdirSync(dir, { recursive: true });
1068
- }
1069
982
  // Read existing content for diff
1070
983
  let oldContent = '';
1071
984
  let isNewFile = true;
1072
- if (fs.existsSync(absPath)) {
1073
- try {
1074
- const stats = fs.statSync(absPath);
1075
- if (!stats.isDirectory() && stats.size < 100 * 1024) {
1076
- oldContent = fs.readFileSync(absPath, 'utf-8');
985
+ if (fsDelegate?.writeTextFile) {
986
+ // Client-side fs: read the current buffer for the diff (absent = new file),
987
+ // then write through the client instead of touching local disk.
988
+ if (fsDelegate.readTextFile) {
989
+ try {
990
+ oldContent = await fsDelegate.readTextFile(absPath);
1077
991
  isNewFile = false;
1078
992
  }
993
+ catch {
994
+ oldContent = '';
995
+ isNewFile = true;
996
+ }
1079
997
  }
1080
- catch {
1081
- // Ignore errors reading old content
1082
- }
998
+ await fsDelegate.writeTextFile(absPath, content);
1083
999
  }
1084
- // Auto-checkpoint before overwriting existing files (#20)
1085
- if (!isNewFile && oldContent) {
1086
- try {
1087
- const { createCheckpoint } = require('./checkpoint.js');
1088
- createCheckpoint(absPath, oldContent);
1000
+ else {
1001
+ // Create directory if needed
1002
+ const dir = path.dirname(absPath);
1003
+ if (!fs.existsSync(dir)) {
1004
+ fs.mkdirSync(dir, { recursive: true });
1089
1005
  }
1090
- catch {
1091
- // Checkpoint module not available or failed - continue with write
1006
+ if (fs.existsSync(absPath)) {
1007
+ try {
1008
+ const stats = fs.statSync(absPath);
1009
+ if (!stats.isDirectory() && stats.size < 100 * 1024) {
1010
+ oldContent = fs.readFileSync(absPath, 'utf-8');
1011
+ isNewFile = false;
1012
+ }
1013
+ }
1014
+ catch {
1015
+ // Ignore errors reading old content
1016
+ }
1092
1017
  }
1018
+ fs.writeFileSync(absPath, content);
1093
1019
  }
1094
- fs.writeFileSync(absPath, content);
1095
1020
  // Generate diff output (#119)
1096
1021
  const DIFF_CAP = 50;
1097
1022
  const header = `[wrote: ${filePath}]\n${'─'.repeat(Math.min(filePath.length + 9, 60))}`;
@@ -1193,12 +1118,10 @@ function listFilesRecursive(dir, prefix, depth) {
1193
1118
  * - 'off': no sandboxing
1194
1119
  */
1195
1120
  async function executeCode(language, code, cwd, timeout) {
1196
- const mode = config.get('sandboxMode') || 'auto';
1197
1121
  const sandboxLang = language === 'node' ? 'node' : language;
1198
- // Determine execution strategy
1199
- const useDocker = mode === 'docker' || (mode === 'auto' && sandbox.isDockerAvailable());
1200
- const useNative = mode === 'native' || (mode === 'auto' && !sandbox.isDockerAvailable() && nativeSandbox.isNativeSandboxAvailable());
1201
- if (useDocker) {
1122
+ // Determine execution strategy from sandboxMode config
1123
+ const strategy = sandbox.selectCodeSandbox();
1124
+ if (strategy === 'docker') {
1202
1125
  // Docker sandbox path (existing behaviour)
1203
1126
  const result = await sandbox.execute(sandboxLang, code, {
1204
1127
  timeout,
@@ -1217,7 +1140,7 @@ async function executeCode(language, code, cwd, timeout) {
1217
1140
  output += `Duration: ${result.duration}ms`;
1218
1141
  return output;
1219
1142
  }
1220
- if (useNative) {
1143
+ if (strategy === 'native') {
1221
1144
  // Native OS sandbox path — write code to temp file and execute
1222
1145
  const fs = await import('fs');
1223
1146
  const os = await import('os');
@@ -1230,7 +1153,7 @@ async function executeCode(language, code, cwd, timeout) {
1230
1153
  : language === 'node' ? `node "${codePath}"`
1231
1154
  : `bash "${codePath}"`;
1232
1155
  const startTime = Date.now();
1233
- const result = await nativeSandbox.executeInNativeSandbox(cmd, cwd, {
1156
+ const result = await sandbox.executeInNativeSandbox(cmd, cwd, {
1234
1157
  timeout,
1235
1158
  readOnlyPaths: [tempDir],
1236
1159
  });
@@ -1425,16 +1348,42 @@ ${content}
1425
1348
  * Edit a file by replacing an exact string (in-place edit).
1426
1349
  * Supports single-occurrence enforcement or replace_all mode.
1427
1350
  */
1428
- async function editFile(filePath, oldString, newString, replaceAll, cwd) {
1351
+ async function editFile(filePath, oldString, newString, replaceAll, cwd, anchorHash, fsDelegate) {
1429
1352
  const absPath = validatePath(filePath, cwd);
1430
- if (!fs.existsSync(absPath)) {
1431
- throw new Error(`File not found: ${absPath}`);
1353
+ let content;
1354
+ if (fsDelegate?.readTextFile) {
1355
+ // Client-side fs: edit against the editor's current buffer, not disk.
1356
+ content = await fsDelegate.readTextFile(absPath);
1432
1357
  }
1433
- const stats = fs.statSync(absPath);
1434
- if (stats.isDirectory()) {
1435
- throw new Error(`Path is a directory: ${absPath}`);
1358
+ else {
1359
+ if (!fs.existsSync(absPath)) {
1360
+ throw new Error(`File not found: ${absPath}`);
1361
+ }
1362
+ const stats = fs.statSync(absPath);
1363
+ if (stats.isDirectory()) {
1364
+ throw new Error(`Path is a directory: ${absPath}`);
1365
+ }
1366
+ content = fs.readFileSync(absPath, 'utf-8');
1367
+ }
1368
+ // Persist the edited content through the delegate when available, else disk.
1369
+ const writeUpdated = async (updated) => {
1370
+ if (fsDelegate?.writeTextFile) {
1371
+ await fsDelegate.writeTextFile(absPath, updated);
1372
+ }
1373
+ else {
1374
+ fs.writeFileSync(absPath, updated);
1375
+ }
1376
+ };
1377
+ // Stale-view protection (feature 4): if the caller supplied an anchor_hash, it
1378
+ // must match the file's current content. A mismatch means the model is acting
1379
+ // on an out-of-date view — fail loudly and tell it to re-read. Absent hash =
1380
+ // no check (inert for cloud providers, which never see the param).
1381
+ if (anchorHash !== undefined) {
1382
+ const currentHash = computeAnchorHash(content);
1383
+ if (anchorHash !== currentHash) {
1384
+ throw new Error(`anchor_hash mismatch: file has changed since you read it (you sent "${anchorHash}", current is "${currentHash}"). Re-read ${filePath} before editing.`);
1385
+ }
1436
1386
  }
1437
- const content = fs.readFileSync(absPath, 'utf-8');
1438
1387
  // Helper to build a compact edit diff from old_string/new_string (#119)
1439
1388
  const buildEditDiff = (oldStr, newStr, fPath, count) => {
1440
1389
  const DIFF_CAP = 50;
@@ -1476,7 +1425,7 @@ async function editFile(filePath, oldString, newString, replaceAll, cwd) {
1476
1425
  if (count === 0) {
1477
1426
  throw new Error(`old_string not found in file: ${absPath}`);
1478
1427
  }
1479
- fs.writeFileSync(absPath, updated);
1428
+ await writeUpdated(updated);
1480
1429
  return buildEditDiff(oldString, newString, filePath, count);
1481
1430
  }
1482
1431
  // Count occurrences
@@ -1488,7 +1437,7 @@ async function editFile(filePath, oldString, newString, replaceAll, cwd) {
1488
1437
  throw new Error(`old_string matches ${occurrences} occurrences — use replace_all: true or make it more specific`);
1489
1438
  }
1490
1439
  const updated = content.replace(oldString, newString);
1491
- fs.writeFileSync(absPath, updated);
1440
+ await writeUpdated(updated);
1492
1441
  return buildEditDiff(oldString, newString, filePath, 1);
1493
1442
  }
1494
1443
  /**