@openadapter/koda 1.0.0-beta.3

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 (357) hide show
  1. package/CHANGELOG.md +4448 -0
  2. package/README.md +665 -0
  3. package/dist/bun/cli.d.ts +2 -0
  4. package/dist/bun/cli.js +2 -0
  5. package/dist/bun/register-bedrock.d.ts +1 -0
  6. package/dist/bun/register-bedrock.js +1 -0
  7. package/dist/bun/restore-sandbox-env.d.ts +12 -0
  8. package/dist/bun/restore-sandbox-env.js +1 -0
  9. package/dist/cli/args.d.ts +55 -0
  10. package/dist/cli/args.js +167 -0
  11. package/dist/cli/config-selector.d.ts +13 -0
  12. package/dist/cli/config-selector.js +1 -0
  13. package/dist/cli/file-processor.d.ts +14 -0
  14. package/dist/cli/file-processor.js +7 -0
  15. package/dist/cli/import-sessions.d.ts +34 -0
  16. package/dist/cli/import-sessions.js +6 -0
  17. package/dist/cli/initial-message.d.ts +17 -0
  18. package/dist/cli/initial-message.js +1 -0
  19. package/dist/cli/list-models.d.ts +8 -0
  20. package/dist/cli/list-models.js +2 -0
  21. package/dist/cli/openadapter-setup.d.ts +29 -0
  22. package/dist/cli/openadapter-setup.js +3 -0
  23. package/dist/cli/session-picker.d.ts +8 -0
  24. package/dist/cli/session-picker.js +1 -0
  25. package/dist/cli.d.ts +2 -0
  26. package/dist/cli.js +2 -0
  27. package/dist/config.d.ts +92 -0
  28. package/dist/config.js +1 -0
  29. package/dist/core/agent-session-runtime.d.ts +116 -0
  30. package/dist/core/agent-session-runtime.js +1 -0
  31. package/dist/core/agent-session-services.d.ts +86 -0
  32. package/dist/core/agent-session-services.js +1 -0
  33. package/dist/core/agent-session.d.ts +747 -0
  34. package/dist/core/agent-session.js +32 -0
  35. package/dist/core/auth-guidance.d.ts +4 -0
  36. package/dist/core/auth-guidance.js +8 -0
  37. package/dist/core/auth-storage.d.ts +140 -0
  38. package/dist/core/auth-storage.js +1 -0
  39. package/dist/core/bash-executor.d.ts +31 -0
  40. package/dist/core/bash-executor.js +1 -0
  41. package/dist/core/compaction/branch-summarization.d.ts +89 -0
  42. package/dist/core/compaction/branch-summarization.js +38 -0
  43. package/dist/core/compaction/compaction.d.ts +120 -0
  44. package/dist/core/compaction/compaction.js +104 -0
  45. package/dist/core/compaction/index.d.ts +6 -0
  46. package/dist/core/compaction/index.js +1 -0
  47. package/dist/core/compaction/utils.d.ts +37 -0
  48. package/dist/core/compaction/utils.js +19 -0
  49. package/dist/core/defaults.d.ts +2 -0
  50. package/dist/core/defaults.js +1 -0
  51. package/dist/core/diagnostics.d.ts +14 -0
  52. package/dist/core/diagnostics.js +0 -0
  53. package/dist/core/event-bus.d.ts +8 -0
  54. package/dist/core/event-bus.js +1 -0
  55. package/dist/core/exec.d.ts +28 -0
  56. package/dist/core/exec.js +1 -0
  57. package/dist/core/export-html/ansi-to-html.d.ts +21 -0
  58. package/dist/core/export-html/ansi-to-html.js +1 -0
  59. package/dist/core/export-html/index.d.ts +36 -0
  60. package/dist/core/export-html/index.js +2 -0
  61. package/dist/core/export-html/template.css +1066 -0
  62. package/dist/core/export-html/template.html +55 -0
  63. package/dist/core/export-html/template.js +72 -0
  64. package/dist/core/export-html/tool-renderer.d.ts +33 -0
  65. package/dist/core/export-html/tool-renderer.js +1 -0
  66. package/dist/core/export-html/vendor/highlight.min.js +8 -0
  67. package/dist/core/export-html/vendor/marked.min.js +56 -0
  68. package/dist/core/extensions/index.d.ts +11 -0
  69. package/dist/core/extensions/index.js +1 -0
  70. package/dist/core/extensions/loader.d.ts +23 -0
  71. package/dist/core/extensions/loader.js +1 -0
  72. package/dist/core/extensions/runner.d.ts +160 -0
  73. package/dist/core/extensions/runner.js +1 -0
  74. package/dist/core/extensions/types.d.ts +1180 -0
  75. package/dist/core/extensions/types.js +1 -0
  76. package/dist/core/extensions/wrapper.d.ts +19 -0
  77. package/dist/core/extensions/wrapper.js +1 -0
  78. package/dist/core/footer-data-provider.d.ts +53 -0
  79. package/dist/core/footer-data-provider.js +1 -0
  80. package/dist/core/http-dispatcher.d.ts +20 -0
  81. package/dist/core/http-dispatcher.js +1 -0
  82. package/dist/core/index.d.ts +11 -0
  83. package/dist/core/index.js +1 -0
  84. package/dist/core/keybindings.d.ts +352 -0
  85. package/dist/core/keybindings.js +1 -0
  86. package/dist/core/messages.d.ts +76 -0
  87. package/dist/core/messages.js +17 -0
  88. package/dist/core/model-registry.d.ts +149 -0
  89. package/dist/core/model-registry.js +9 -0
  90. package/dist/core/model-resolver.d.ts +109 -0
  91. package/dist/core/model-resolver.js +1 -0
  92. package/dist/core/output-guard.d.ts +6 -0
  93. package/dist/core/output-guard.js +1 -0
  94. package/dist/core/package-manager.d.ts +203 -0
  95. package/dist/core/package-manager.js +3 -0
  96. package/dist/core/prompt-templates.d.ts +51 -0
  97. package/dist/core/prompt-templates.js +2 -0
  98. package/dist/core/provider-attribution.d.ts +3 -0
  99. package/dist/core/provider-attribution.js +1 -0
  100. package/dist/core/provider-display-names.d.ts +1 -0
  101. package/dist/core/provider-display-names.js +1 -0
  102. package/dist/core/resolve-config-value.d.ts +30 -0
  103. package/dist/core/resolve-config-value.js +1 -0
  104. package/dist/core/resource-loader.d.ts +193 -0
  105. package/dist/core/resource-loader.js +1 -0
  106. package/dist/core/sdk.d.ts +108 -0
  107. package/dist/core/sdk.js +1 -0
  108. package/dist/core/session-cwd.d.ts +18 -0
  109. package/dist/core/session-cwd.js +7 -0
  110. package/dist/core/session-manager.d.ts +331 -0
  111. package/dist/core/session-manager.js +11 -0
  112. package/dist/core/settings-manager.d.ts +265 -0
  113. package/dist/core/settings-manager.js +1 -0
  114. package/dist/core/skills.d.ts +59 -0
  115. package/dist/core/skills.js +4 -0
  116. package/dist/core/slash-commands.d.ts +13 -0
  117. package/dist/core/slash-commands.js +1 -0
  118. package/dist/core/source-info.d.ts +17 -0
  119. package/dist/core/source-info.js +1 -0
  120. package/dist/core/system-prompt.d.ts +27 -0
  121. package/dist/core/system-prompt.js +52 -0
  122. package/dist/core/telemetry.d.ts +2 -0
  123. package/dist/core/telemetry.js +1 -0
  124. package/dist/core/timings.d.ts +7 -0
  125. package/dist/core/timings.js +3 -0
  126. package/dist/core/tools/bash.d.ts +67 -0
  127. package/dist/core/tools/bash.js +18 -0
  128. package/dist/core/tools/edit-diff.d.ts +86 -0
  129. package/dist/core/tools/edit-diff.js +16 -0
  130. package/dist/core/tools/edit.d.ts +50 -0
  131. package/dist/core/tools/edit.js +2 -0
  132. package/dist/core/tools/file-mutation-queue.d.ts +5 -0
  133. package/dist/core/tools/file-mutation-queue.js +1 -0
  134. package/dist/core/tools/find.d.ts +34 -0
  135. package/dist/core/tools/find.js +13 -0
  136. package/dist/core/tools/grep.d.ts +36 -0
  137. package/dist/core/tools/grep.js +13 -0
  138. package/dist/core/tools/index.d.ts +39 -0
  139. package/dist/core/tools/index.js +1 -0
  140. package/dist/core/tools/ls.d.ts +36 -0
  141. package/dist/core/tools/ls.js +9 -0
  142. package/dist/core/tools/output-accumulator.d.ts +51 -0
  143. package/dist/core/tools/output-accumulator.js +4 -0
  144. package/dist/core/tools/path-utils.d.ts +9 -0
  145. package/dist/core/tools/path-utils.js +1 -0
  146. package/dist/core/tools/read.d.ts +34 -0
  147. package/dist/core/tools/read.js +22 -0
  148. package/dist/core/tools/render-utils.d.ts +23 -0
  149. package/dist/core/tools/render-utils.js +4 -0
  150. package/dist/core/tools/tool-definition-wrapper.d.ts +13 -0
  151. package/dist/core/tools/tool-definition-wrapper.js +1 -0
  152. package/dist/core/tools/truncate.d.ts +69 -0
  153. package/dist/core/tools/truncate.js +5 -0
  154. package/dist/core/tools/write.d.ts +25 -0
  155. package/dist/core/tools/write.js +13 -0
  156. package/dist/index.d.ts +30 -0
  157. package/dist/index.js +1 -0
  158. package/dist/main.d.ts +11 -0
  159. package/dist/main.js +1 -0
  160. package/dist/migrations.d.ts +32 -0
  161. package/dist/migrations.js +8 -0
  162. package/dist/modes/index.d.ts +8 -0
  163. package/dist/modes/index.js +1 -0
  164. package/dist/modes/interactive/assets/clankolas.png +0 -0
  165. package/dist/modes/interactive/components/armin.d.ts +33 -0
  166. package/dist/modes/interactive/components/armin.js +1 -0
  167. package/dist/modes/interactive/components/assistant-message.d.ts +19 -0
  168. package/dist/modes/interactive/components/assistant-message.js +1 -0
  169. package/dist/modes/interactive/components/bash-execution.d.ts +33 -0
  170. package/dist/modes/interactive/components/bash-execution.js +13 -0
  171. package/dist/modes/interactive/components/bordered-loader.d.ts +15 -0
  172. package/dist/modes/interactive/components/bordered-loader.js +1 -0
  173. package/dist/modes/interactive/components/branch-summary-message.d.ts +15 -0
  174. package/dist/modes/interactive/components/branch-summary-message.js +3 -0
  175. package/dist/modes/interactive/components/compaction-summary-message.d.ts +15 -0
  176. package/dist/modes/interactive/components/compaction-summary-message.js +3 -0
  177. package/dist/modes/interactive/components/config-selector.d.ts +70 -0
  178. package/dist/modes/interactive/components/config-selector.js +1 -0
  179. package/dist/modes/interactive/components/countdown-timer.d.ts +13 -0
  180. package/dist/modes/interactive/components/countdown-timer.js +1 -0
  181. package/dist/modes/interactive/components/custom-editor.d.ts +20 -0
  182. package/dist/modes/interactive/components/custom-editor.js +1 -0
  183. package/dist/modes/interactive/components/custom-message.d.ts +19 -0
  184. package/dist/modes/interactive/components/custom-message.js +2 -0
  185. package/dist/modes/interactive/components/daxnuts.d.ts +22 -0
  186. package/dist/modes/interactive/components/daxnuts.js +1 -0
  187. package/dist/modes/interactive/components/diff.d.ts +11 -0
  188. package/dist/modes/interactive/components/diff.js +3 -0
  189. package/dist/modes/interactive/components/dynamic-border.d.ts +14 -0
  190. package/dist/modes/interactive/components/dynamic-border.js +1 -0
  191. package/dist/modes/interactive/components/earendil-announcement.d.ts +4 -0
  192. package/dist/modes/interactive/components/earendil-announcement.js +1 -0
  193. package/dist/modes/interactive/components/extension-editor.d.ts +19 -0
  194. package/dist/modes/interactive/components/extension-editor.js +3 -0
  195. package/dist/modes/interactive/components/extension-input.d.ts +22 -0
  196. package/dist/modes/interactive/components/extension-input.js +2 -0
  197. package/dist/modes/interactive/components/extension-selector.d.ts +25 -0
  198. package/dist/modes/interactive/components/extension-selector.js +2 -0
  199. package/dist/modes/interactive/components/footer.d.ts +27 -0
  200. package/dist/modes/interactive/components/footer.js +1 -0
  201. package/dist/modes/interactive/components/index.d.ts +31 -0
  202. package/dist/modes/interactive/components/index.js +1 -0
  203. package/dist/modes/interactive/components/keybinding-hints.d.ts +12 -0
  204. package/dist/modes/interactive/components/keybinding-hints.js +1 -0
  205. package/dist/modes/interactive/components/login-dialog.d.ts +51 -0
  206. package/dist/modes/interactive/components/login-dialog.js +1 -0
  207. package/dist/modes/interactive/components/model-selector.d.ts +46 -0
  208. package/dist/modes/interactive/components/model-selector.js +2 -0
  209. package/dist/modes/interactive/components/oauth-selector.d.ts +30 -0
  210. package/dist/modes/interactive/components/oauth-selector.js +1 -0
  211. package/dist/modes/interactive/components/scoped-models-selector.d.ts +41 -0
  212. package/dist/modes/interactive/components/scoped-models-selector.js +1 -0
  213. package/dist/modes/interactive/components/session-selector-search.d.ts +22 -0
  214. package/dist/modes/interactive/components/session-selector-search.js +1 -0
  215. package/dist/modes/interactive/components/session-selector.d.ts +95 -0
  216. package/dist/modes/interactive/components/session-selector.js +2 -0
  217. package/dist/modes/interactive/components/settings-selector.d.ts +68 -0
  218. package/dist/modes/interactive/components/settings-selector.js +1 -0
  219. package/dist/modes/interactive/components/show-images-selector.d.ts +9 -0
  220. package/dist/modes/interactive/components/show-images-selector.js +1 -0
  221. package/dist/modes/interactive/components/skill-invocation-message.d.ts +16 -0
  222. package/dist/modes/interactive/components/skill-invocation-message.js +3 -0
  223. package/dist/modes/interactive/components/theme-selector.d.ts +10 -0
  224. package/dist/modes/interactive/components/theme-selector.js +1 -0
  225. package/dist/modes/interactive/components/thinking-selector.d.ts +10 -0
  226. package/dist/modes/interactive/components/thinking-selector.js +1 -0
  227. package/dist/modes/interactive/components/tool-execution.d.ts +62 -0
  228. package/dist/modes/interactive/components/tool-execution.js +4 -0
  229. package/dist/modes/interactive/components/tree-selector.d.ts +88 -0
  230. package/dist/modes/interactive/components/tree-selector.js +1 -0
  231. package/dist/modes/interactive/components/user-message-selector.d.ts +29 -0
  232. package/dist/modes/interactive/components/user-message-selector.js +1 -0
  233. package/dist/modes/interactive/components/user-message.d.ts +9 -0
  234. package/dist/modes/interactive/components/user-message.js +1 -0
  235. package/dist/modes/interactive/components/visual-truncate.d.ts +23 -0
  236. package/dist/modes/interactive/components/visual-truncate.js +1 -0
  237. package/dist/modes/interactive/interactive-mode.d.ts +417 -0
  238. package/dist/modes/interactive/interactive-mode.js +116 -0
  239. package/dist/modes/interactive/theme/dark.json +86 -0
  240. package/dist/modes/interactive/theme/light.json +85 -0
  241. package/dist/modes/interactive/theme/theme-schema.json +335 -0
  242. package/dist/modes/interactive/theme/theme.d.ts +101 -0
  243. package/dist/modes/interactive/theme/theme.js +18 -0
  244. package/dist/modes/print-mode.d.ts +27 -0
  245. package/dist/modes/print-mode.js +4 -0
  246. package/dist/modes/rpc/jsonl.d.ts +16 -0
  247. package/dist/modes/rpc/jsonl.js +3 -0
  248. package/dist/modes/rpc/rpc-client.d.ts +226 -0
  249. package/dist/modes/rpc/rpc-client.js +1 -0
  250. package/dist/modes/rpc/rpc-mode.d.ts +19 -0
  251. package/dist/modes/rpc/rpc-mode.js +1 -0
  252. package/dist/modes/rpc/rpc-types.d.ts +419 -0
  253. package/dist/modes/rpc/rpc-types.js +0 -0
  254. package/dist/package-manager-cli.d.ts +3 -0
  255. package/dist/package-manager-cli.js +49 -0
  256. package/dist/utils/ansi.d.ts +1 -0
  257. package/dist/utils/ansi.js +1 -0
  258. package/dist/utils/auto-update.d.ts +13 -0
  259. package/dist/utils/auto-update.js +1 -0
  260. package/dist/utils/changelog.d.ts +20 -0
  261. package/dist/utils/changelog.js +4 -0
  262. package/dist/utils/child-process.d.ts +14 -0
  263. package/dist/utils/child-process.js +1 -0
  264. package/dist/utils/clipboard-image.d.ts +10 -0
  265. package/dist/utils/clipboard-image.js +1 -0
  266. package/dist/utils/clipboard-native.d.ts +9 -0
  267. package/dist/utils/clipboard-native.js +1 -0
  268. package/dist/utils/clipboard.d.ts +1 -0
  269. package/dist/utils/clipboard.js +1 -0
  270. package/dist/utils/deprecation.d.ts +3 -0
  271. package/dist/utils/deprecation.js +1 -0
  272. package/dist/utils/exif-orientation.d.ts +4 -0
  273. package/dist/utils/exif-orientation.js +1 -0
  274. package/dist/utils/frontmatter.d.ts +7 -0
  275. package/dist/utils/frontmatter.js +4 -0
  276. package/dist/utils/fs-watch.d.ts +4 -0
  277. package/dist/utils/fs-watch.js +1 -0
  278. package/dist/utils/git.d.ts +25 -0
  279. package/dist/utils/git.js +1 -0
  280. package/dist/utils/html.d.ts +6 -0
  281. package/dist/utils/html.js +1 -0
  282. package/dist/utils/image-convert.d.ts +8 -0
  283. package/dist/utils/image-convert.js +1 -0
  284. package/dist/utils/image-resize-core.d.ts +29 -0
  285. package/dist/utils/image-resize-core.js +1 -0
  286. package/dist/utils/image-resize-worker.d.ts +1 -0
  287. package/dist/utils/image-resize-worker.js +1 -0
  288. package/dist/utils/image-resize.d.ts +15 -0
  289. package/dist/utils/image-resize.js +1 -0
  290. package/dist/utils/json.d.ts +2 -0
  291. package/dist/utils/json.js +1 -0
  292. package/dist/utils/koda-user-agent.d.ts +1 -0
  293. package/dist/utils/koda-user-agent.js +1 -0
  294. package/dist/utils/mime.d.ts +2 -0
  295. package/dist/utils/mime.js +1 -0
  296. package/dist/utils/paths.d.ts +30 -0
  297. package/dist/utils/paths.js +1 -0
  298. package/dist/utils/photon.d.ts +20 -0
  299. package/dist/utils/photon.js +1 -0
  300. package/dist/utils/shell.d.ts +29 -0
  301. package/dist/utils/shell.js +8 -0
  302. package/dist/utils/sleep.d.ts +4 -0
  303. package/dist/utils/sleep.js +1 -0
  304. package/dist/utils/syntax-highlight.d.ts +11 -0
  305. package/dist/utils/syntax-highlight.js +2 -0
  306. package/dist/utils/tools-manager.d.ts +2 -0
  307. package/dist/utils/tools-manager.js +1 -0
  308. package/dist/utils/version-check.d.ts +14 -0
  309. package/dist/utils/version-check.js +1 -0
  310. package/dist/utils/windows-self-update.d.ts +2 -0
  311. package/dist/utils/windows-self-update.js +1 -0
  312. package/docs/compaction.md +394 -0
  313. package/docs/custom-provider.md +736 -0
  314. package/docs/development.md +71 -0
  315. package/docs/docs.json +148 -0
  316. package/docs/extensions.md +2626 -0
  317. package/docs/images/doom-extension.png +0 -0
  318. package/docs/images/exy.png +0 -0
  319. package/docs/images/interactive-mode.png +0 -0
  320. package/docs/images/tree-view.png +0 -0
  321. package/docs/index.md +80 -0
  322. package/docs/json.md +82 -0
  323. package/docs/keybindings.md +197 -0
  324. package/docs/models.md +493 -0
  325. package/docs/packages.md +226 -0
  326. package/docs/prompt-templates.md +88 -0
  327. package/docs/providers.md +253 -0
  328. package/docs/quickstart.md +165 -0
  329. package/docs/rpc.md +1408 -0
  330. package/docs/sdk.md +1137 -0
  331. package/docs/session-format.md +412 -0
  332. package/docs/sessions.md +145 -0
  333. package/docs/settings.md +281 -0
  334. package/docs/shell-aliases.md +13 -0
  335. package/docs/skills.md +231 -0
  336. package/docs/terminal-setup.md +114 -0
  337. package/docs/termux.md +127 -0
  338. package/docs/themes.md +295 -0
  339. package/docs/tmux.md +61 -0
  340. package/docs/tui.md +927 -0
  341. package/docs/usage.md +288 -0
  342. package/docs/windows.md +17 -0
  343. package/npm-shrinkwrap.json +1792 -0
  344. package/openadapter/extensions/koda-ask.js +12 -0
  345. package/openadapter/extensions/koda-bg.js +14 -0
  346. package/openadapter/extensions/koda-commands.mjs +15 -0
  347. package/openadapter/extensions/koda-help.js +8 -0
  348. package/openadapter/extensions/koda-memory.js +16 -0
  349. package/openadapter/extensions/koda-status.js +1 -0
  350. package/openadapter/extensions/koda-todo.js +4 -0
  351. package/openadapter/extensions/koda-vision.js +4 -0
  352. package/openadapter/extensions/koda-web.js +7 -0
  353. package/openadapter/setup.mjs +173 -0
  354. package/openadapter/skills/code-review/SKILL.md +22 -0
  355. package/openadapter/skills/debugging/SKILL.md +28 -0
  356. package/openadapter/skills/frontend/SKILL.md +38 -0
  357. package/package.json +108 -0
@@ -0,0 +1 @@
1
+ var P=Object.defineProperty;var h=(l,e)=>P(l,"name",{value:e,configurable:!0});import{existsSync as f,mkdirSync as v,readFileSync as j,writeFileSync as w}from"fs";import{dirname as C,join as S}from"path";import T from"proper-lockfile";import{CONFIG_DIR_NAME as E,getAgentDir as F}from"../config.js";import{normalizePath as x,resolvePath as p}from"../utils/paths.js";import{DEFAULT_HTTP_IDLE_TIMEOUT_MS as L,parseHttpIdleTimeoutMs as I}from"./http-dispatcher.js";function g(l,e){const t={...l};for(const s of Object.keys(e)){const i=e[s],r=l[s];i!==void 0&&(typeof i=="object"&&i!==null&&!Array.isArray(i)&&typeof r=="object"&&r!==null&&!Array.isArray(r)?t[s]={...r,...i}:t[s]=i)}return t}h(g,"deepMergeSettings");function b(l,e){const t=I(l);if(t!==void 0)return t;if(l!==void 0)throw new Error(`Invalid ${e} setting: ${String(l)}`)}h(b,"parseTimeoutSetting");class D{static{h(this,"FileSettingsStorage")}globalSettingsPath;projectSettingsPath;constructor(e,t){const s=p(e),i=p(t);this.globalSettingsPath=S(i,"settings.json"),this.projectSettingsPath=S(s,E,"settings.json")}acquireLockSyncWithRetry(e){let i;for(let r=1;r<=10;r++)try{return T.lockSync(e,{realpath:!1})}catch(o){if((typeof o=="object"&&o!==null&&"code"in o?String(o.code):void 0)!=="ELOCKED"||r===10)throw o;i=o;const a=Date.now();for(;Date.now()-a<20;);}throw i??new Error("Failed to acquire settings lock")}withLock(e,t){const s=e==="global"?this.globalSettingsPath:this.projectSettingsPath,i=C(s);let r;try{const o=f(s);o&&(r=this.acquireLockSyncWithRetry(s));const d=o?j(s,"utf-8"):void 0,a=t(d);a!==void 0&&(f(i)||v(i,{recursive:!0}),r||(r=this.acquireLockSyncWithRetry(s)),w(s,a,"utf-8"))}finally{r&&r()}}}class R{static{h(this,"InMemorySettingsStorage")}global;project;withLock(e,t){const s=e==="global"?this.global:this.project,i=t(s);i!==void 0&&(e==="global"?this.global=i:this.project=i)}}class n{static{h(this,"SettingsManager")}storage;globalSettings;projectSettings;settings;modifiedFields=new Set;modifiedNestedFields=new Map;modifiedProjectFields=new Set;modifiedProjectNestedFields=new Map;globalSettingsLoadError=null;projectSettingsLoadError=null;writeQueue=Promise.resolve();errors;constructor(e,t,s,i=null,r=null,o=[]){this.storage=e,this.globalSettings=t,this.projectSettings=s,this.globalSettingsLoadError=i,this.projectSettingsLoadError=r,this.errors=[...o],this.settings=g(this.globalSettings,this.projectSettings)}static create(e,t=F()){const s=new D(e,t);return n.fromStorage(s)}static fromStorage(e){const t=n.tryLoadFromStorage(e,"global"),s=n.tryLoadFromStorage(e,"project"),i=[];return t.error&&i.push({scope:"global",error:t.error}),s.error&&i.push({scope:"project",error:s.error}),new n(e,t.settings,s.settings,t.error,s.error,i)}static inMemory(e={}){const t=new R,s=n.migrateSettings(structuredClone(e));return t.withLock("global",()=>JSON.stringify(s,null,2)),n.fromStorage(t)}static loadFromStorage(e,t){let s;if(e.withLock(t,r=>{s=r}),!s)return{};const i=JSON.parse(s);return n.migrateSettings(i)}static tryLoadFromStorage(e,t){try{return{settings:n.loadFromStorage(e,t),error:null}}catch(s){return{settings:{},error:s}}}static migrateSettings(e){if("queueMode"in e&&!("steeringMode"in e)&&(e.steeringMode=e.queueMode,delete e.queueMode),!("transport"in e)&&typeof e.websockets=="boolean"&&(e.transport=e.websockets?"websocket":"sse",delete e.websockets),"skills"in e&&typeof e.skills=="object"&&e.skills!==null&&!Array.isArray(e.skills)){const t=e.skills;t.enableSkillCommands!==void 0&&e.enableSkillCommands===void 0&&(e.enableSkillCommands=t.enableSkillCommands),Array.isArray(t.customDirectories)&&t.customDirectories.length>0?e.skills=t.customDirectories:delete e.skills}if("retry"in e&&typeof e.retry=="object"&&e.retry!==null&&!Array.isArray(e.retry)){const t=e.retry,s=typeof t.provider=="object"&&t.provider!==null?t.provider:void 0;typeof t.maxDelayMs=="number"&&(s?.maxRetryDelayMs===void 0||s?.maxRetryDelayMs===null)&&(t.provider={...s??{},maxRetryDelayMs:t.maxDelayMs}),delete t.maxDelayMs}return e}getGlobalSettings(){return structuredClone(this.globalSettings)}getProjectSettings(){return structuredClone(this.projectSettings)}async reload(){await this.writeQueue;const e=n.tryLoadFromStorage(this.storage,"global");e.error?(this.globalSettingsLoadError=e.error,this.recordError("global",e.error)):(this.globalSettings=e.settings,this.globalSettingsLoadError=null),this.modifiedFields.clear(),this.modifiedNestedFields.clear(),this.modifiedProjectFields.clear(),this.modifiedProjectNestedFields.clear();const t=n.tryLoadFromStorage(this.storage,"project");t.error?(this.projectSettingsLoadError=t.error,this.recordError("project",t.error)):(this.projectSettings=t.settings,this.projectSettingsLoadError=null),this.settings=g(this.globalSettings,this.projectSettings)}applyOverrides(e){this.settings=g(this.settings,e)}markModified(e,t){this.modifiedFields.add(e),t&&(this.modifiedNestedFields.has(e)||this.modifiedNestedFields.set(e,new Set),this.modifiedNestedFields.get(e).add(t))}markProjectModified(e,t){this.modifiedProjectFields.add(e),t&&(this.modifiedProjectNestedFields.has(e)||this.modifiedProjectNestedFields.set(e,new Set),this.modifiedProjectNestedFields.get(e).add(t))}recordError(e,t){const s=t instanceof Error?t:new Error(String(t));this.errors.push({scope:e,error:s})}clearModifiedScope(e){if(e==="global"){this.modifiedFields.clear(),this.modifiedNestedFields.clear();return}this.modifiedProjectFields.clear(),this.modifiedProjectNestedFields.clear()}enqueueWrite(e,t){this.writeQueue=this.writeQueue.then(()=>{t(),this.clearModifiedScope(e)}).catch(s=>{this.recordError(e,s)})}cloneModifiedNestedFields(e){const t=new Map;for(const[s,i]of e.entries())t.set(s,new Set(i));return t}persistScopedSettings(e,t,s,i){this.storage.withLock(e,r=>{const o=r?n.migrateSettings(JSON.parse(r)):{},d={...o};for(const a of s){const c=t[a];if(i.has(a)&&typeof c=="object"&&c!==null){const k=i.get(a),M=o[a]??{},y=c,m={...M};for(const u of k)m[u]=y[u];d[a]=m}else d[a]=c}return JSON.stringify(d,null,2)})}save(){if(this.settings=g(this.globalSettings,this.projectSettings),this.globalSettingsLoadError)return;const e=structuredClone(this.globalSettings),t=new Set(this.modifiedFields),s=this.cloneModifiedNestedFields(this.modifiedNestedFields);this.enqueueWrite("global",()=>{this.persistScopedSettings("global",e,t,s)})}saveProjectSettings(e){if(this.projectSettings=structuredClone(e),this.settings=g(this.globalSettings,this.projectSettings),this.projectSettingsLoadError)return;const t=structuredClone(this.projectSettings),s=new Set(this.modifiedProjectFields),i=this.cloneModifiedNestedFields(this.modifiedProjectNestedFields);this.enqueueWrite("project",()=>{this.persistScopedSettings("project",t,s,i)})}async flush(){await this.writeQueue}drainErrors(){const e=[...this.errors];return this.errors=[],e}getLastChangelogVersion(){return this.settings.lastChangelogVersion}setLastChangelogVersion(e){this.globalSettings.lastChangelogVersion=e,this.markModified("lastChangelogVersion"),this.save()}getSessionDir(){const e=this.settings.sessionDir;return e&&x(e)}getDefaultProvider(){return this.settings.defaultProvider}getDefaultModel(){return this.settings.defaultModel}setDefaultProvider(e){this.globalSettings.defaultProvider=e,this.markModified("defaultProvider"),this.save()}setDefaultModel(e){this.globalSettings.defaultModel=e,this.markModified("defaultModel"),this.save()}setDefaultModelAndProvider(e,t){this.globalSettings.defaultProvider=e,this.globalSettings.defaultModel=t,this.markModified("defaultProvider"),this.markModified("defaultModel"),this.save()}getSteeringMode(){return this.settings.steeringMode||"one-at-a-time"}setSteeringMode(e){this.globalSettings.steeringMode=e,this.markModified("steeringMode"),this.save()}getFollowUpMode(){return this.settings.followUpMode||"one-at-a-time"}setFollowUpMode(e){this.globalSettings.followUpMode=e,this.markModified("followUpMode"),this.save()}getTheme(){return this.settings.theme}setTheme(e){this.globalSettings.theme=e,this.markModified("theme"),this.save()}getDefaultThinkingLevel(){return this.settings.defaultThinkingLevel}setDefaultThinkingLevel(e){this.globalSettings.defaultThinkingLevel=e,this.markModified("defaultThinkingLevel"),this.save()}getTransport(){return this.settings.transport??"auto"}setTransport(e){this.globalSettings.transport=e,this.markModified("transport"),this.save()}getCompactionEnabled(){return this.settings.compaction?.enabled??!0}setCompactionEnabled(e){this.globalSettings.compaction||(this.globalSettings.compaction={}),this.globalSettings.compaction.enabled=e,this.markModified("compaction","enabled"),this.save()}getCompactionReserveTokens(){return this.settings.compaction?.reserveTokens??16384}getCompactionKeepRecentTokens(){return this.settings.compaction?.keepRecentTokens??2e4}getCompactionSettings(){return{enabled:this.getCompactionEnabled(),reserveTokens:this.getCompactionReserveTokens(),keepRecentTokens:this.getCompactionKeepRecentTokens()}}getBranchSummarySettings(){return{reserveTokens:this.settings.branchSummary?.reserveTokens??16384,skipPrompt:this.settings.branchSummary?.skipPrompt??!1}}getBranchSummarySkipPrompt(){return this.settings.branchSummary?.skipPrompt??!1}getRetryEnabled(){return this.settings.retry?.enabled??!0}setRetryEnabled(e){this.globalSettings.retry||(this.globalSettings.retry={}),this.globalSettings.retry.enabled=e,this.markModified("retry","enabled"),this.save()}getRetrySettings(){return{enabled:this.getRetryEnabled(),maxRetries:this.settings.retry?.maxRetries??3,baseDelayMs:this.settings.retry?.baseDelayMs??2e3}}getHttpIdleTimeoutMs(){return b(this.settings.httpIdleTimeoutMs,"httpIdleTimeoutMs")??L}setHttpIdleTimeoutMs(e){if(!Number.isFinite(e)||e<0)throw new Error(`Invalid httpIdleTimeoutMs setting: ${String(e)}`);this.globalSettings.httpIdleTimeoutMs=Math.floor(e),this.markModified("httpIdleTimeoutMs"),this.save()}getProviderRetrySettings(){return{timeoutMs:this.settings.retry?.provider?.timeoutMs,maxRetries:this.settings.retry?.provider?.maxRetries,maxRetryDelayMs:this.settings.retry?.provider?.maxRetryDelayMs??6e4}}getWebSocketConnectTimeoutMs(){return b(this.settings.websocketConnectTimeoutMs,"websocketConnectTimeoutMs")}getHideThinkingBlock(){return this.settings.hideThinkingBlock??!1}setHideThinkingBlock(e){this.globalSettings.hideThinkingBlock=e,this.markModified("hideThinkingBlock"),this.save()}getShellPath(){return this.settings.shellPath}setShellPath(e){this.globalSettings.shellPath=e,this.markModified("shellPath"),this.save()}getQuietStartup(){return this.settings.quietStartup??!1}setQuietStartup(e){this.globalSettings.quietStartup=e,this.markModified("quietStartup"),this.save()}getShellCommandPrefix(){return this.settings.shellCommandPrefix}setShellCommandPrefix(e){this.globalSettings.shellCommandPrefix=e,this.markModified("shellCommandPrefix"),this.save()}getNpmCommand(){return this.settings.npmCommand?[...this.settings.npmCommand]:void 0}setNpmCommand(e){this.globalSettings.npmCommand=e?[...e]:void 0,this.markModified("npmCommand"),this.save()}getCollapseChangelog(){return this.settings.collapseChangelog??!1}setCollapseChangelog(e){this.globalSettings.collapseChangelog=e,this.markModified("collapseChangelog"),this.save()}getEnableInstallTelemetry(){return this.settings.enableInstallTelemetry??!0}setEnableInstallTelemetry(e){this.globalSettings.enableInstallTelemetry=e,this.markModified("enableInstallTelemetry"),this.save()}getPackages(){return[...this.settings.packages??[]]}setPackages(e){this.globalSettings.packages=e,this.markModified("packages"),this.save()}setProjectPackages(e){const t=structuredClone(this.projectSettings);t.packages=e,this.markProjectModified("packages"),this.saveProjectSettings(t)}getExtensionPaths(){return[...this.settings.extensions??[]]}setExtensionPaths(e){this.globalSettings.extensions=e,this.markModified("extensions"),this.save()}setProjectExtensionPaths(e){const t=structuredClone(this.projectSettings);t.extensions=e,this.markProjectModified("extensions"),this.saveProjectSettings(t)}getSkillPaths(){return[...this.settings.skills??[]]}setSkillPaths(e){this.globalSettings.skills=e,this.markModified("skills"),this.save()}setProjectSkillPaths(e){const t=structuredClone(this.projectSettings);t.skills=e,this.markProjectModified("skills"),this.saveProjectSettings(t)}getPromptTemplatePaths(){return[...this.settings.prompts??[]]}setPromptTemplatePaths(e){this.globalSettings.prompts=e,this.markModified("prompts"),this.save()}setProjectPromptTemplatePaths(e){const t=structuredClone(this.projectSettings);t.prompts=e,this.markProjectModified("prompts"),this.saveProjectSettings(t)}getThemePaths(){return[...this.settings.themes??[]]}setThemePaths(e){this.globalSettings.themes=e,this.markModified("themes"),this.save()}setProjectThemePaths(e){const t=structuredClone(this.projectSettings);t.themes=e,this.markProjectModified("themes"),this.saveProjectSettings(t)}getEnableSkillCommands(){return this.settings.enableSkillCommands??!0}setEnableSkillCommands(e){this.globalSettings.enableSkillCommands=e,this.markModified("enableSkillCommands"),this.save()}getThinkingBudgets(){return this.settings.thinkingBudgets}getShowImages(){return this.settings.terminal?.showImages??!0}setShowImages(e){this.globalSettings.terminal||(this.globalSettings.terminal={}),this.globalSettings.terminal.showImages=e,this.markModified("terminal","showImages"),this.save()}getImageWidthCells(){const e=this.settings.terminal?.imageWidthCells;return typeof e!="number"||!Number.isFinite(e)?60:Math.max(1,Math.floor(e))}setImageWidthCells(e){this.globalSettings.terminal||(this.globalSettings.terminal={}),this.globalSettings.terminal.imageWidthCells=Math.max(1,Math.floor(e)),this.markModified("terminal","imageWidthCells"),this.save()}getClearOnShrink(){return this.settings.terminal?.clearOnShrink!==void 0?this.settings.terminal.clearOnShrink:process.env.KODA_CLEAR_ON_SHRINK==="1"}setClearOnShrink(e){this.globalSettings.terminal||(this.globalSettings.terminal={}),this.globalSettings.terminal.clearOnShrink=e,this.markModified("terminal","clearOnShrink"),this.save()}getShowTerminalProgress(){return this.settings.terminal?.showTerminalProgress??!1}setShowTerminalProgress(e){this.globalSettings.terminal||(this.globalSettings.terminal={}),this.globalSettings.terminal.showTerminalProgress=e,this.markModified("terminal","showTerminalProgress"),this.save()}getImageAutoResize(){return this.settings.images?.autoResize??!0}setImageAutoResize(e){this.globalSettings.images||(this.globalSettings.images={}),this.globalSettings.images.autoResize=e,this.markModified("images","autoResize"),this.save()}getBlockImages(){return this.settings.images?.blockImages??!1}setBlockImages(e){this.globalSettings.images||(this.globalSettings.images={}),this.globalSettings.images.blockImages=e,this.markModified("images","blockImages"),this.save()}getEnabledModels(){return this.settings.enabledModels}setEnabledModels(e){this.globalSettings.enabledModels=e,this.markModified("enabledModels"),this.save()}getDoubleEscapeAction(){return this.settings.doubleEscapeAction??"tree"}setDoubleEscapeAction(e){this.globalSettings.doubleEscapeAction=e,this.markModified("doubleEscapeAction"),this.save()}getTreeFilterMode(){const e=this.settings.treeFilterMode;return e&&["default","no-tools","user-only","labeled-only","all"].includes(e)?e:"default"}setTreeFilterMode(e){this.globalSettings.treeFilterMode=e,this.markModified("treeFilterMode"),this.save()}getShowHardwareCursor(){return this.settings.showHardwareCursor??process.env.KODA_HARDWARE_CURSOR==="1"}setShowHardwareCursor(e){this.globalSettings.showHardwareCursor=e,this.markModified("showHardwareCursor"),this.save()}getEditorPaddingX(){return this.settings.editorPaddingX??0}setEditorPaddingX(e){this.globalSettings.editorPaddingX=Math.max(0,Math.min(3,Math.floor(e))),this.markModified("editorPaddingX"),this.save()}getAutocompleteMaxVisible(){return this.settings.autocompleteMaxVisible??5}setAutocompleteMaxVisible(e){this.globalSettings.autocompleteMaxVisible=Math.max(3,Math.min(20,Math.floor(e))),this.markModified("autocompleteMaxVisible"),this.save()}getCodeBlockIndent(){return this.settings.markdown?.codeBlockIndent??" "}getWarnings(){return{...this.settings.warnings??{}}}setWarnings(e){this.globalSettings.warnings={...e},this.markModified("warnings"),this.save()}}export{D as FileSettingsStorage,R as InMemorySettingsStorage,n as SettingsManager};
@@ -0,0 +1,59 @@
1
+ import type { ResourceDiagnostic } from "./diagnostics.ts";
2
+ import { type SourceInfo } from "./source-info.ts";
3
+ export interface SkillFrontmatter {
4
+ name?: string;
5
+ description?: string;
6
+ "disable-model-invocation"?: boolean;
7
+ [key: string]: unknown;
8
+ }
9
+ export interface Skill {
10
+ name: string;
11
+ description: string;
12
+ filePath: string;
13
+ baseDir: string;
14
+ sourceInfo: SourceInfo;
15
+ disableModelInvocation: boolean;
16
+ }
17
+ export interface LoadSkillsResult {
18
+ skills: Skill[];
19
+ diagnostics: ResourceDiagnostic[];
20
+ }
21
+ export interface LoadSkillsFromDirOptions {
22
+ /** Directory to scan for skills */
23
+ dir: string;
24
+ /** Source identifier for these skills */
25
+ source: string;
26
+ }
27
+ /**
28
+ * Load skills from a directory.
29
+ *
30
+ * Discovery rules:
31
+ * - if a directory contains SKILL.md, treat it as a skill root and do not recurse further
32
+ * - otherwise, load direct .md children in the root
33
+ * - recurse into subdirectories to find SKILL.md
34
+ */
35
+ export declare function loadSkillsFromDir(options: LoadSkillsFromDirOptions): LoadSkillsResult;
36
+ /**
37
+ * Format skills for inclusion in a system prompt.
38
+ * Uses XML format per Agent Skills standard.
39
+ * See: https://agentskills.io/integrate-skills
40
+ *
41
+ * Skills with disableModelInvocation=true are excluded from the prompt
42
+ * (they can only be invoked explicitly via /skill:name commands).
43
+ */
44
+ export declare function formatSkillsForPrompt(skills: Skill[]): string;
45
+ export interface LoadSkillsOptions {
46
+ /** Working directory for project-local skills. */
47
+ cwd: string;
48
+ /** Agent config directory for global skills. */
49
+ agentDir: string;
50
+ /** Explicit skill paths (files or directories) */
51
+ skillPaths: string[];
52
+ /** Include default skills directories. */
53
+ includeDefaults: boolean;
54
+ }
55
+ /**
56
+ * Load skills from all configured locations.
57
+ * Returns skills and any validation diagnostics.
58
+ */
59
+ export declare function loadSkills(options: LoadSkillsOptions): LoadSkillsResult;
@@ -0,0 +1,4 @@
1
+ var R=Object.defineProperty;var u=(t,e)=>R(t,"name",{value:e,configurable:!0});import{existsSync as I,readdirSync as T,readFileSync as L,statSync as P}from"fs";import z from"ignore";import{basename as C,dirname as G,join as v,relative as $,resolve as W,sep as x}from"path";import{CONFIG_DIR_NAME as M,getAgentDir as O}from"../config.js";import{parseFrontmatter as X}from"../utils/frontmatter.js";import{canonicalizePath as q,resolvePath as E}from"../utils/paths.js";import{createSyntheticSourceInfo as F}from"./source-info.js";const j=64,A=1024,H=[".gitignore",".ignore",".fdignore"];function _(t){return t.split(x).join("/")}u(_,"toPosixPath");function K(t,e){const n=t.trim();if(!n||n.startsWith("#")&&!n.startsWith("\\#"))return null;let s=t,r=!1;s.startsWith("!")?(r=!0,s=s.slice(1)):s.startsWith("\\!")&&(s=s.slice(1)),s.startsWith("/")&&(s=s.slice(1));const a=e?`${e}${s}`:s;return r?`!${a}`:a}u(K,"prefixIgnorePattern");function U(t,e,n){const s=$(n,e),r=s?`${_(s)}/`:"";for(const a of H){const p=v(e,a);if(I(p))try{const c=L(p,"utf-8").split(/\r?\n/).map(h=>K(h,r)).filter(h=>!!h);c.length>0&&t.add(c)}catch{}}}u(U,"addIgnoreRules");function B(t){const e=[];return t.length>j&&e.push(`name exceeds ${j} characters (${t.length})`),/^[a-z0-9-]+$/.test(t)||e.push("name contains invalid characters (must be lowercase a-z, 0-9, hyphens only)"),(t.startsWith("-")||t.endsWith("-"))&&e.push("name must not start or end with a hyphen"),t.includes("--")&&e.push("name must not contain consecutive hyphens"),e}u(B,"validateName");function J(t){const e=[];return!t||t.trim()===""?e.push("description is required"):t.length>A&&e.push(`description exceeds ${A} characters (${t.length})`),e}u(J,"validateDescription");function Q(t,e,n){switch(n){case"user":return F(t,{source:"local",scope:"user",baseDir:e});case"project":return F(t,{source:"local",scope:"project",baseDir:e});case"path":return F(t,{source:"local",baseDir:e});default:return F(t,{source:n,baseDir:e})}}u(Q,"createSkillSourceInfo");function ot(t){const{dir:e,source:n}=t;return w(e,n,!0)}u(ot,"loadSkillsFromDir");function w(t,e,n,s,r){const a=[],p=[];if(!I(t))return{skills:a,diagnostics:p};const d=r??t,c=s??z();U(c,t,d);try{const h=T(t,{withFileTypes:!0});for(const o of h){if(o.name!=="SKILL.md")continue;const m=v(t,o.name);let k=o.isFile();if(o.isSymbolicLink())try{k=P(m).isFile()}catch{continue}const S=_($(d,m));if(!k||c.ignores(S))continue;const y=b(m,e);return y.skill&&a.push(y.skill),p.push(...y.diagnostics),{skills:a,diagnostics:p}}for(const o of h){if(o.name.startsWith(".")||o.name==="node_modules")continue;const m=v(t,o.name);let k=o.isDirectory(),S=o.isFile();if(o.isSymbolicLink())try{const l=P(m);k=l.isDirectory(),S=l.isFile()}catch{continue}const y=_($(d,m)),f=k?`${y}/`:y;if(c.ignores(f))continue;if(k){const l=w(m,e,!1,c,d);a.push(...l.skills),p.push(...l.diagnostics);continue}if(!S||!n||!o.name.endsWith(".md"))continue;const i=b(m,e);i.skill&&a.push(i.skill),p.push(...i.diagnostics)}}catch{}return{skills:a,diagnostics:p}}u(w,"loadSkillsFromDirInternal");function b(t,e){const n=[];try{const s=L(t,"utf-8"),{frontmatter:r}=X(s),a=G(t),p=C(a),d=J(r.description);for(const o of d)n.push({type:"warning",message:o,path:t});const c=r.name||p,h=B(c);for(const o of h)n.push({type:"warning",message:o,path:t});return!r.description||r.description.trim()===""?{skill:null,diagnostics:n}:{skill:{name:c,description:r.description,filePath:t,baseDir:a,sourceInfo:Q(t,a,e),disableModelInvocation:r["disable-model-invocation"]===!0},diagnostics:n}}catch(s){const r=s instanceof Error?s.message:"failed to parse skill file";return n.push({type:"warning",message:r,path:t}),{skill:null,diagnostics:n}}}u(b,"loadSkillFromFile");function rt(t){const e=t.filter(s=>!s.disableModelInvocation);if(e.length===0)return"";const n=[`
2
+
3
+ The following skills provide specialized instructions for specific tasks.`,"Use the read tool to load a skill's file when the task matches its description.","When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.","","<available_skills>"];for(const s of e)n.push(" <skill>"),n.push(` <name>${N(s.name)}</name>`),n.push(` <description>${N(s.description)}</description>`),n.push(` <location>${N(s.filePath)}</location>`),n.push(" </skill>");return n.push("</available_skills>"),n.join(`
4
+ `)}u(rt,"formatSkillsForPrompt");function N(t){return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}u(N,"escapeXml");function lt(t){const{agentDir:e,skillPaths:n,includeDefaults:s}=t,r=E(t.cwd),a=E(e??O()),p=new Map,d=new Set,c=[],h=[];function o(f){c.push(...f.diagnostics);for(const i of f.skills){const l=q(i.filePath);if(d.has(l))continue;const g=p.get(i.name);g?h.push({type:"collision",message:`name "${i.name}" collision`,path:i.filePath,collision:{resourceType:"skill",name:i.name,winnerPath:g.filePath,loserPath:i.filePath}}):(p.set(i.name,i),d.add(l))}}u(o,"addSkills"),s&&(o(w(v(a,"skills"),"user",!0)),o(w(W(r,M,"skills"),"project",!0)));const m=v(a,"skills"),k=W(r,M,"skills"),S=u((f,i)=>{const l=W(i);if(f===l)return!0;const g=l.endsWith(x)?l:`${l}${x}`;return f.startsWith(g)},"isUnderPath"),y=u(f=>{if(!s){if(S(f,m))return"user";if(S(f,k))return"project"}return"path"},"getSource");for(const f of n){const i=E(f,r,{trim:!0});if(!I(i)){c.push({type:"warning",message:"skill path does not exist",path:i});continue}try{const l=P(i),g=y(i);if(l.isDirectory())o(w(i,g,!0));else if(l.isFile()&&i.endsWith(".md")){const D=b(i,g);D.skill?o({skills:[D.skill],diagnostics:D.diagnostics}):c.push(...D.diagnostics)}else c.push({type:"warning",message:"skill path is not a markdown file",path:i})}catch(l){const g=l instanceof Error?l.message:"failed to read skill path";c.push({type:"warning",message:g,path:i})}}return{skills:Array.from(p.values()),diagnostics:[...c,...h]}}u(lt,"loadSkills");export{rt as formatSkillsForPrompt,lt as loadSkills,ot as loadSkillsFromDir};
@@ -0,0 +1,13 @@
1
+ import type { SourceInfo } from "./source-info.ts";
2
+ export type SlashCommandSource = "extension" | "prompt" | "skill";
3
+ export interface SlashCommandInfo {
4
+ name: string;
5
+ description?: string;
6
+ source: SlashCommandSource;
7
+ sourceInfo: SourceInfo;
8
+ }
9
+ export interface BuiltinSlashCommand {
10
+ name: string;
11
+ description: string;
12
+ }
13
+ export declare const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand>;
@@ -0,0 +1 @@
1
+ import{APP_NAME as e}from"../config.js";const i=[{name:"settings",description:"Open settings menu"},{name:"goal",description:"Set the session goal (/goal <text>), show progress (/goal), or clear it (/goal clear)"},{name:"use",description:"Keep a skill active all session (/use <skill> to toggle; /use to list) \u2014 no chat triggered"},{name:"trace",description:"Show what the harness did this session \u2014 model switches, verification, escalation"},{name:"model",description:"Select model (opens selector UI)"},{name:"scoped-models",description:"Enable/disable models for Ctrl+P cycling"},{name:"export",description:"Export session (HTML default, or specify path: .html/.jsonl)"},{name:"import",description:"Import and resume a session from a JSONL file"},{name:"share",description:"Share session as a secret GitHub gist"},{name:"copy",description:"Copy last agent message to clipboard"},{name:"name",description:"Set session display name"},{name:"session",description:"Show session info and stats"},{name:"changelog",description:"Show changelog entries"},{name:"hotkeys",description:"Show all keyboard shortcuts"},{name:"fork",description:"Create a new fork from a previous user message"},{name:"clone",description:"Duplicate the current session at the current position"},{name:"tree",description:"Navigate session tree (switch branches)"},{name:"login",description:"Configure provider authentication"},{name:"logout",description:"Remove provider authentication"},{name:"new",description:"Start a new session"},{name:"clear",description:"Clear the conversation and start fresh (alias of /new)"},{name:"compact",description:"Manually compact the session context"},{name:"resume",description:"Resume a different session"},{name:"reload",description:"Reload keybindings, extensions, skills, prompts, and themes"},{name:"quit",description:`Quit ${e}`}];export{i as BUILTIN_SLASH_COMMANDS};
@@ -0,0 +1,17 @@
1
+ import type { PathMetadata } from "./package-manager.ts";
2
+ export type SourceScope = "user" | "project" | "temporary";
3
+ export type SourceOrigin = "package" | "top-level";
4
+ export interface SourceInfo {
5
+ path: string;
6
+ source: string;
7
+ scope: SourceScope;
8
+ origin: SourceOrigin;
9
+ baseDir?: string;
10
+ }
11
+ export declare function createSourceInfo(path: string, metadata: PathMetadata): SourceInfo;
12
+ export declare function createSyntheticSourceInfo(path: string, options: {
13
+ source: string;
14
+ scope?: SourceScope;
15
+ origin?: SourceOrigin;
16
+ baseDir?: string;
17
+ }): SourceInfo;
@@ -0,0 +1 @@
1
+ var c=Object.defineProperty;var o=(e,r)=>c(e,"name",{value:r,configurable:!0});function n(e,r){return{path:e,source:r.source,scope:r.scope,origin:r.origin,baseDir:r.baseDir}}o(n,"createSourceInfo");function u(e,r){return{path:e,source:r.source,scope:r.scope??"temporary",origin:r.origin??"top-level",baseDir:r.baseDir}}o(u,"createSyntheticSourceInfo");export{n as createSourceInfo,u as createSyntheticSourceInfo};
@@ -0,0 +1,27 @@
1
+ /**
2
+ * System prompt construction and project context loading
3
+ */
4
+ import { type Skill } from "./skills.ts";
5
+ export interface BuildSystemPromptOptions {
6
+ /** Custom system prompt (replaces default). */
7
+ customPrompt?: string;
8
+ /** Tools to include in prompt. Default: [read, bash, edit, write] */
9
+ selectedTools?: string[];
10
+ /** Optional one-line tool snippets keyed by tool name. */
11
+ toolSnippets?: Record<string, string>;
12
+ /** Additional guideline bullets appended to the default system prompt guidelines. */
13
+ promptGuidelines?: string[];
14
+ /** Text to append to system prompt. */
15
+ appendSystemPrompt?: string;
16
+ /** Working directory. */
17
+ cwd: string;
18
+ /** Pre-loaded context files. */
19
+ contextFiles?: Array<{
20
+ path: string;
21
+ content: string;
22
+ }>;
23
+ /** Pre-loaded skills. */
24
+ skills?: Skill[];
25
+ }
26
+ /** Build the system prompt with tools, guidelines, and context */
27
+ export declare function buildSystemPrompt(options: BuildSystemPromptOptions): string;
@@ -0,0 +1,52 @@
1
+ var L=Object.defineProperty;var h=(l,i)=>L(l,"name",{value:i,configurable:!0});import{getDocsPath as R,getExamplesPath as W,getReadmePath as Y}from"../config.js";import{formatSkillsForPrompt as P}from"./skills.js";function z(l){const{customPrompt:i,selectedTools:c,toolSnippets:u,promptGuidelines:$,appendSystemPrompt:m,cwd:D,contextFiles:S,skills:j}=l,f=D.replace(/\\/g,"/"),p=new Date,C=p.getFullYear(),F=String(p.getMonth()+1).padStart(2,"0"),T=String(p.getDate()).padStart(2,"0"),g=`${C}-${F}-${T}`,a=m?`
2
+
3
+ ${m}`:"",r=S??[],d=j??[];if(i){let e=i;if(a&&(e+=a),r.length>0){e+=`
4
+
5
+ <project_context>
6
+
7
+ `,e+=`Project-specific instructions and guidelines:
8
+
9
+ `;for(const{path:U,content:K}of r)e+=`<project_instructions path="${U}">
10
+ ${K}
11
+ </project_instructions>
12
+
13
+ `;e+=`</project_context>
14
+ `}return(!c||c.includes("read"))&&d.length>0&&(e+=P(d)),e+=`
15
+ Current date: ${g}`,e+=`
16
+ Current working directory: ${f}`,e}const A=Y(),I=R(),_=W(),n=c||["read","bash","edit","write"],y=n.filter(e=>!!u?.[e]),E=y.length>0?y.map(e=>`- ${e}: ${u[e]}`).join(`
17
+ `):"(none)",k=[],w=new Set,t=h(e=>{w.has(e)||(w.add(e),k.push(e))},"addGuideline"),N=n.includes("bash"),b=n.includes("grep"),v=n.includes("find"),x=n.includes("ls"),O=n.includes("read");N&&!b&&!v&&!x&&t("Use bash for file operations like ls, rg, find");for(const e of $??[]){const s=e.trim();s.length>0&&t(s)}t("Be concise in your responses"),t("Show file paths clearly when working with files"),t("Before declaring the task complete, VERIFY it actually works: re-run the relevant tests or build and confirm they pass. Never claim success without verifying \u2014 if a check fails, keep fixing."),t("Never modify test files, .git, lockfiles, or secrets (.env). Change the source code instead. Don't use shell redirects to overwrite files \u2014 use the edit/write tools."),t("Do exactly what's asked \u2014 nothing more, nothing less. Don't add features, refactors, or files the user didn't request. Skip preamble and recaps unless asked."),t("Follow the existing code's conventions. Before using a library, framework, or pattern, confirm it's already used in the project (check imports and manifests) \u2014 never assume a dependency is available."),t("Don't add comments unless asked or the logic is genuinely non-obvious. Match the surrounding style, naming, and structure."),t("Use your tools to get real information \u2014 read or grep files, search the web, recall memory \u2014 instead of answering from your own memory or guessing. Never say something is unknown, 'not specified', or that you can't find it WITHOUT first calling the relevant tool to actually look. Default to doing (a tool call) over explaining why you can't."),(b||v||x)&&t("Prefer the structured grep/find/ls tools over ad-hoc bash find/grep when searching the codebase."),t("When several independent operations are needed (reading multiple files, running multiple searches), issue those tool calls together in one turn instead of one at a time."),t("For large, multi-step, or destructive changes, briefly outline a plan before executing, then follow it."),n.includes("todo")&&t("For any task with more than a couple of steps, use the todo tool to lay out the steps first and mark each one done as you finish it \u2014 stay on track and let the user see progress.");const M=k.map(e=>`- ${e}`).join(`
18
+ `);let o=`You are an expert coding assistant operating inside koda, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.
19
+
20
+ Available tools:
21
+ ${E}
22
+
23
+ In addition to the tools above, you may have access to other custom tools depending on the project.
24
+
25
+ Guidelines:
26
+ ${M}
27
+
28
+ Koda documentation (read only when the user asks about koda itself, its SDK, extensions, themes, skills, or TUI):
29
+ - Main documentation: ${A}
30
+ - Additional docs: ${I}
31
+ - Examples: ${_} (extensions, custom tools, SDK)
32
+ - When reading koda docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory
33
+ - When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), koda packages (docs/packages.md)
34
+ - When working on koda topics, read the docs and examples, and follow .md cross-references before implementing
35
+ - Always read koda .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;if(a&&(o+=a),process.env.KODA_MODE==="plan"&&(o+=`
36
+
37
+ === PLAN MODE ===
38
+ You are in PLAN MODE. Investigate the codebase as needed (read and search are allowed), then produce a clear, concise, step-by-step plan to accomplish the task. Do NOT modify files or run state-changing commands \u2014 those are disabled and will be blocked. Do not implement anything yet.
39
+ If a todo tool is available, record each step of the plan as a todo (one per step) so they're ready to execute \u2014 the todo tool is NOT blocked in plan mode. Then present the plan and tell the user to run /build (or press Ctrl+Alt+P) to execute it.`),r.length>0){o+=`
40
+
41
+ <project_context>
42
+
43
+ `,o+=`Project-specific instructions and guidelines:
44
+
45
+ `;for(const{path:e,content:s}of r)o+=`<project_instructions path="${e}">
46
+ ${s}
47
+ </project_instructions>
48
+
49
+ `;o+=`</project_context>
50
+ `}return O&&d.length>0&&(o+=P(d)),o+=`
51
+ Current date: ${g}`,o+=`
52
+ Current working directory: ${f}`,o}h(z,"buildSystemPrompt");export{z as buildSystemPrompt};
@@ -0,0 +1,2 @@
1
+ import type { SettingsManager } from "./settings-manager.ts";
2
+ export declare function isInstallTelemetryEnabled(settingsManager: SettingsManager, telemetryEnv?: string | undefined): boolean;
@@ -0,0 +1 @@
1
+ var t=Object.defineProperty;var r=(e,n)=>t(e,"name",{value:n,configurable:!0});function s(e){return e?e==="1"||e.toLowerCase()==="true"||e.toLowerCase()==="yes":!1}r(s,"isTruthyEnvFlag");function i(e,n=process.env.KODA_TELEMETRY){return n!==void 0?s(n):e.getEnableInstallTelemetry()}r(i,"isInstallTelemetryEnabled");export{i as isInstallTelemetryEnabled};
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Central timing instrumentation for startup profiling.
3
+ * Enable with KODA_TIMING=1 environment variable.
4
+ */
5
+ export declare function resetTimings(): void;
6
+ export declare function time(label: string): void;
7
+ export declare function printTimings(): void;
@@ -0,0 +1,3 @@
1
+ var i=Object.defineProperty;var r=(n,e)=>i(n,"name",{value:e,configurable:!0});const t=process.env.KODA_TIMING==="1",o=[];let s=Date.now();function m(){t&&(o.length=0,s=Date.now())}r(m,"resetTimings");function l(n){if(!t)return;const e=Date.now();o.push({label:n,ms:e-s}),s=e}r(l,"time");function u(){if(!(!t||o.length===0)){console.error(`
2
+ --- Startup Timings ---`);for(const n of o)console.error(` ${n.label}: ${n.ms}ms`);console.error(` TOTAL: ${o.reduce((n,e)=>n+e.ms,0)}ms`),console.error(`------------------------
3
+ `)}}r(u,"printTimings");export{u as printTimings,m as resetTimings,l as time};
@@ -0,0 +1,67 @@
1
+ import type { AgentTool } from "@openadapter/koda-agent-core";
2
+ import { type Static, Type } from "typebox";
3
+ import type { ToolDefinition } from "../extensions/types.ts";
4
+ import { type TruncationResult } from "./truncate.ts";
5
+ declare const bashSchema: Type.TObject<{
6
+ command: Type.TString;
7
+ timeout: Type.TOptional<Type.TNumber>;
8
+ }>;
9
+ export type BashToolInput = Static<typeof bashSchema>;
10
+ export interface BashToolDetails {
11
+ truncation?: TruncationResult;
12
+ fullOutputPath?: string;
13
+ }
14
+ /**
15
+ * Pluggable operations for the bash tool.
16
+ * Override these to delegate command execution to remote systems (for example SSH).
17
+ */
18
+ export interface BashOperations {
19
+ /**
20
+ * Execute a command and stream output.
21
+ * @param command The command to execute
22
+ * @param cwd Working directory
23
+ * @param options Execution options
24
+ * @returns Promise resolving to exit code (null if killed)
25
+ */
26
+ exec: (command: string, cwd: string, options: {
27
+ onData: (data: Buffer) => void;
28
+ signal?: AbortSignal;
29
+ timeout?: number;
30
+ env?: NodeJS.ProcessEnv;
31
+ }) => Promise<{
32
+ exitCode: number | null;
33
+ }>;
34
+ }
35
+ /**
36
+ * Create bash operations using pi's built-in local shell execution backend.
37
+ *
38
+ * This is useful for extensions that intercept user_bash and still want pi's
39
+ * standard local shell behavior while wrapping or rewriting commands.
40
+ */
41
+ export declare function createLocalBashOperations(options?: {
42
+ shellPath?: string;
43
+ }): BashOperations;
44
+ export interface BashSpawnContext {
45
+ command: string;
46
+ cwd: string;
47
+ env: NodeJS.ProcessEnv;
48
+ }
49
+ export type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;
50
+ export interface BashToolOptions {
51
+ /** Custom operations for command execution. Default: local shell */
52
+ operations?: BashOperations;
53
+ /** Command prefix prepended to every command (for example shell setup commands) */
54
+ commandPrefix?: string;
55
+ /** Optional explicit shell path from settings */
56
+ shellPath?: string;
57
+ /** Hook to adjust command, cwd, or env before execution */
58
+ spawnHook?: BashSpawnHook;
59
+ }
60
+ type BashRenderState = {
61
+ startedAt: number | undefined;
62
+ endedAt: number | undefined;
63
+ interval: NodeJS.Timeout | undefined;
64
+ };
65
+ export declare function createBashToolDefinition(cwd: string, options?: BashToolOptions): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState>;
66
+ export declare function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema>;
67
+ export {};
@@ -0,0 +1,18 @@
1
+ var j=Object.defineProperty;var s=(i,r)=>j(i,"name",{value:r,configurable:!0});import{constants as M}from"node:fs";import{access as N}from"node:fs/promises";import{Container as U,Text as v,truncateToWidth as z}from"@openadapter/koda-tui";import{spawn as K}from"child_process";import{Type as E}from"typebox";import{keyHint as V}from"../../modes/interactive/components/keybinding-hints.js";import{truncateToVisualLines as X}from"../../modes/interactive/components/visual-truncate.js";import{theme as $}from"../../modes/interactive/theme/theme.js";import{waitForChildProcess as Y}from"../../utils/child-process.js";import{getShellConfig as q,getShellEnv as I,killProcessTree as W,trackDetachedChildPid as G,untrackDetachedChildPid as J}from"../../utils/shell.js";import{OutputAccumulator as Q}from"./output-accumulator.js";import{getTextOutput as Z,invalidArgText as tt,str as et}from"./render-utils.js";import{wrapToolDefinition as nt}from"./tool-definition-wrapper.js";import{DEFAULT_MAX_BYTES as D,DEFAULT_MAX_LINES as it,formatSize as P}from"./truncate.js";const ot=E.Object({command:E.String({description:"Bash command to execute"}),timeout:E.Optional(E.Number({description:"Timeout in seconds (optional, no default timeout)"}))});function at(i){return{exec:s(async(r,u,{onData:p,signal:c,timeout:h,env:n})=>{const{shell:d,args:o}=q(i?.shellPath);try{await N(u,M.F_OK)}catch{throw new Error(`Working directory does not exist: ${u}
2
+ Cannot execute bash commands.`)}if(c?.aborted)throw new Error("aborted");const t=K(d,[...o,r],{cwd:u,detached:process.platform!=="win32",env:n??I(),stdio:["ignore","pipe","pipe"],windowsHide:!0});t.pid&&G(t.pid);let a=!1,l;const m=s(()=>{t.pid&&W(t.pid)},"onAbort");try{h!==void 0&&h>0&&(l=setTimeout(()=>{a=!0,t.pid&&W(t.pid)},h*1e3)),t.stdout?.on("data",p),t.stderr?.on("data",p),c&&(c.aborted?m():c.addEventListener("abort",m,{once:!0}));const x=await Y(t);if(c?.aborted)throw new Error("aborted");if(a)throw new Error(`timeout:${h}`);return{exitCode:x}}finally{t.pid&&J(t.pid),l&&clearTimeout(l),c&&c.removeEventListener("abort",m)}},"exec")}}s(at,"createLocalBashOperations");function rt(i,r,u){const p={command:i,cwd:r,env:{...I()}};return u?u(p):p}s(rt,"resolveSpawnContext");const st=5,dt=100;class ut extends U{static{s(this,"BashResultRenderComponent")}state={cachedWidth:void 0,cachedLines:void 0,cachedSkipped:void 0}}function ct(i){return`${(i/1e3).toFixed(1)}s`}s(ct,"formatDuration");function lt(i){const r=et(i?.command),u=i?.timeout,p=u?$.fg("muted",` (timeout ${u}s)`):"",c=r===null?tt($):r||$.fg("toolOutput","...");return $.fg("toolTitle",$.bold(`$ ${c}`))+p}s(lt,"formatBashCall");function ft(i,r,u,p,c,h){const n=i.state;i.clear();let d=Z(r,p).trim();const o=r.details?.truncation,t=r.details?.fullOutputPath;if(!u.isPartial&&o?.truncated&&t&&d.endsWith("]")){const a=d.lastIndexOf(`
3
+
4
+ [`);a!==-1&&d.slice(a).includes(t)&&(d=d.slice(0,a).trimEnd())}if(d){const a=d.split(`
5
+ `).map(l=>$.fg("toolOutput",l)).join(`
6
+ `);u.expanded?i.addChild(new v(`
7
+ ${a}`,0,0)):i.addChild({render:s(l=>{if(n.cachedLines===void 0||n.cachedWidth!==l){const m=X(a,st,l);n.cachedLines=m.visualLines,n.cachedSkipped=m.skippedCount,n.cachedWidth=l}if(n.cachedSkipped&&n.cachedSkipped>0){const m=$.fg("muted",`... (${n.cachedSkipped} earlier lines,`)+` ${V("app.tools.expand","to expand")})`;return["",z(m,l,"..."),...n.cachedLines??[]]}return["",...n.cachedLines??[]]},"render"),invalidate:s(()=>{n.cachedWidth=void 0,n.cachedLines=void 0,n.cachedSkipped=void 0},"invalidate")})}if(o?.truncated||t){const a=[];t&&a.push(`Full output: ${t}`),o?.truncated&&(o.truncatedBy==="lines"?a.push(`Truncated: showing ${o.outputLines} of ${o.totalLines} lines`):a.push(`Truncated: ${o.outputLines} lines shown (${P(o.maxBytes??D)} limit)`)),i.addChild(new v(`
8
+ ${$.fg("warning",`[${a.join(". ")}]`)}`,0,0))}if(c!==void 0){const a=u.isPartial?"Elapsed":"Took",l=h??Date.now();i.addChild(new v(`
9
+ ${$.fg("muted",`${a} ${ct(l-c)}`)}`,0,0))}}s(ft,"rebuildBashResultRenderComponent");function pt(i,r){const u=r?.operations??at({shellPath:r?.shellPath}),p=r?.commandPrefix,c=r?.spawnHook;return{name:"bash",label:"bash",description:`Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${it} lines or ${D/1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,promptSnippet:"Execute bash commands (ls, grep, find, etc.)",parameters:ot,async execute(h,{command:n,timeout:d},o,t,a){const l=p?`${p}
10
+ ${n}`:n,m=rt(l,i,c),x=new Q({tempFilePrefix:"pi-bash"});let C,y=!1,k=0;const b=s(()=>{if(!t||!y)return;y=!1,k=Date.now();const e=x.snapshot({persistIfTruncated:!0});t({content:[{type:"text",text:e.content||""}],details:{truncation:e.truncation.truncated?e.truncation:void 0,fullOutputPath:e.fullOutputPath}})},"emitOutputUpdate"),g=s(()=>{C&&(clearTimeout(C),C=void 0)},"clearUpdateTimer"),R=s(()=>{if(!t)return;y=!0;const e=dt-(Date.now()-k);if(e<=0){g(),b();return}C??=setTimeout(()=>{C=void 0,b()},e)},"scheduleOutputUpdate");t&&t({content:[],details:void 0});const H=s(e=>{x.append(e),R()},"handleData"),_=s(async()=>{x.finish(),g(),b();const e=x.snapshot({persistIfTruncated:!0});return await x.closeTempFile(),e},"finishOutput"),F=s((e,S="(no output)")=>{const f=e.truncation;let T=e.content||S,w;if(f.truncated){w={truncation:f,fullOutputPath:e.fullOutputPath};const O=f.totalLines-f.outputLines+1,L=f.totalLines;if(f.lastLinePartial){const B=P(x.getLastLineBytes());T+=`
11
+
12
+ [Showing last ${P(f.outputBytes)} of line ${L} (line is ${B}). Full output: ${e.fullOutputPath}]`}else f.truncatedBy==="lines"?T+=`
13
+
14
+ [Showing lines ${O}-${L} of ${f.totalLines}. Full output: ${e.fullOutputPath}]`:T+=`
15
+
16
+ [Showing lines ${O}-${L} of ${f.totalLines} (${P(D)} limit). Full output: ${e.fullOutputPath}]`}return{text:T,details:w}},"formatOutput"),A=s((e,S)=>`${e?`${e}
17
+
18
+ `:""}${S}`,"appendStatus");try{let e;try{e=(await u.exec(m.command,m.cwd,{onData:H,signal:o,timeout:d,env:m.env})).exitCode}catch(w){const O=await _(),{text:L}=F(O,"");if(w instanceof Error&&w.message==="aborted")throw new Error(A(L,"Command aborted"));if(w instanceof Error&&w.message.startsWith("timeout:")){const B=w.message.split(":")[1];throw new Error(A(L,`Command timed out after ${B} seconds`))}throw w}const S=await _(),{text:f,details:T}=F(S);if(e!==0&&e!==null)throw new Error(A(f,`Command exited with code ${e}`));return{content:[{type:"text",text:f}],details:T}}finally{g()}},renderCall(h,n,d){const o=d.state;d.executionStarted&&o.startedAt===void 0&&(o.startedAt=Date.now(),o.endedAt=void 0);const t=d.lastComponent??new v("",0,0);return t.setText(lt(h)),t},renderResult(h,n,d,o){const t=o.state;t.startedAt!==void 0&&n.isPartial&&!t.interval&&(t.interval=setInterval(()=>o.invalidate(),1e3)),(!n.isPartial||o.isError)&&(t.endedAt??=Date.now(),t.interval&&(clearInterval(t.interval),t.interval=void 0));const a=o.lastComponent??new ut;return ft(a,h,n,o.showImages,t.startedAt,t.endedAt),a.invalidate(),a}}}s(pt,"createBashToolDefinition");function gt(i,r){return nt(pt(i,r))}s(gt,"createBashTool");export{gt as createBashTool,pt as createBashToolDefinition,at as createLocalBashOperations};
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Shared diff computation utilities for the edit tool.
3
+ * Used by both edit.ts (for execution) and tool-execution.ts (for preview rendering).
4
+ */
5
+ export declare function detectLineEnding(content: string): "\r\n" | "\n";
6
+ export declare function normalizeToLF(text: string): string;
7
+ export declare function restoreLineEndings(text: string, ending: "\r\n" | "\n"): string;
8
+ /**
9
+ * Normalize text for fuzzy matching. Applies progressive transformations:
10
+ * - Strip trailing whitespace from each line
11
+ * - Normalize smart quotes to ASCII equivalents
12
+ * - Normalize Unicode dashes/hyphens to ASCII hyphen
13
+ * - Normalize special Unicode spaces to regular space
14
+ */
15
+ export declare function normalizeForFuzzyMatch(text: string): string;
16
+ export interface FuzzyMatchResult {
17
+ /** Whether a match was found */
18
+ found: boolean;
19
+ /** The index where the match starts (in the content that should be used for replacement) */
20
+ index: number;
21
+ /** Length of the matched text */
22
+ matchLength: number;
23
+ /** Whether fuzzy matching was used (false = exact match) */
24
+ usedFuzzyMatch: boolean;
25
+ /**
26
+ * The content to use for replacement operations.
27
+ * When exact match: original content. When fuzzy match: normalized content.
28
+ */
29
+ contentForReplacement: string;
30
+ }
31
+ export interface Edit {
32
+ oldText: string;
33
+ newText: string;
34
+ }
35
+ export interface AppliedEditsResult {
36
+ baseContent: string;
37
+ newContent: string;
38
+ }
39
+ /**
40
+ * Find oldText in content, trying exact match first, then fuzzy match.
41
+ * When fuzzy matching is used, the returned contentForReplacement is the
42
+ * fuzzy-normalized version of the content (trailing whitespace stripped,
43
+ * Unicode quotes/dashes normalized to ASCII).
44
+ */
45
+ export declare function fuzzyFindText(content: string, oldText: string): FuzzyMatchResult;
46
+ /** Strip UTF-8 BOM if present, return both the BOM (if any) and the text without it */
47
+ export declare function stripBom(content: string): {
48
+ bom: string;
49
+ text: string;
50
+ };
51
+ /**
52
+ * Apply one or more exact-text replacements to LF-normalized content.
53
+ *
54
+ * All edits are matched against the same original content. Replacements are
55
+ * then applied in reverse order so offsets remain stable. If any edit needs
56
+ * fuzzy matching, the operation runs in fuzzy-normalized content space to
57
+ * preserve current single-edit behavior.
58
+ */
59
+ export declare function applyEditsToNormalizedContent(normalizedContent: string, edits: Edit[], path: string): AppliedEditsResult;
60
+ /** Generate a standard unified patch. */
61
+ export declare function generateUnifiedPatch(path: string, oldContent: string, newContent: string, contextLines?: number): string;
62
+ /**
63
+ * Generate a display-oriented diff string with line numbers and context.
64
+ * Returns both the diff string and the first changed line number (in the new file).
65
+ */
66
+ export declare function generateDiffString(oldContent: string, newContent: string, contextLines?: number): {
67
+ diff: string;
68
+ firstChangedLine: number | undefined;
69
+ };
70
+ export interface EditDiffResult {
71
+ diff: string;
72
+ firstChangedLine: number | undefined;
73
+ }
74
+ export interface EditDiffError {
75
+ error: string;
76
+ }
77
+ /**
78
+ * Compute the diff for one or more edit operations without applying them.
79
+ * Used for preview rendering in the TUI before the tool executes.
80
+ */
81
+ export declare function computeEditsDiff(path: string, edits: Edit[], cwd: string): Promise<EditDiffResult | EditDiffError>;
82
+ /**
83
+ * Compute the diff for a single edit operation without applying it.
84
+ * Kept as a convenience wrapper for single-edit callers.
85
+ */
86
+ export declare function computeEditDiff(path: string, oldText: string, newText: string, cwd: string): Promise<EditDiffResult | EditDiffError>;
@@ -0,0 +1,16 @@
1
+ var I=Object.defineProperty;var u=(e,r)=>I(e,"name",{value:r,configurable:!0});import*as S from"diff";import{constants as b}from"fs";import{access as M,readFile as O}from"fs/promises";import{resolveToCwd as v}from"./path-utils.js";function Y(e){const r=e.indexOf(`\r
2
+ `),o=e.indexOf(`
3
+ `);return o===-1||r===-1?`
4
+ `:r<o?`\r
5
+ `:`
6
+ `}u(Y,"detectLineEnding");function y(e){return e.replace(/\r\n/g,`
7
+ `).replace(/\r/g,`
8
+ `)}u(y,"normalizeToLF");function G(e,r){return r===`\r
9
+ `?e.replace(/\n/g,`\r
10
+ `):e}u(G,"restoreLineEndings");function E(e){return e.normalize("NFKC").split(`
11
+ `).map(r=>r.trimEnd()).join(`
12
+ `).replace(/[\u2018\u2019\u201A\u201B]/g,"'").replace(/[\u201C\u201D\u201E\u201F]/g,'"').replace(/[\u2010\u2011\u2012\u2013\u2014\u2015\u2212]/g,"-").replace(/[\u00A0\u2002-\u200A\u202F\u205F\u3000]/g," ")}u(E,"normalizeForFuzzyMatch");function C(e,r){const o=e.indexOf(r);if(o!==-1)return{found:!0,index:o,matchLength:r.length,usedFuzzyMatch:!1,contentForReplacement:e};const i=E(e),s=E(r),l=i.indexOf(s);return l===-1?{found:!1,index:-1,matchLength:0,usedFuzzyMatch:!1,contentForReplacement:e}:{found:!0,index:l,matchLength:s.length,usedFuzzyMatch:!0,contentForReplacement:i}}u(C,"fuzzyFindText");function D(e){return e.startsWith("\uFEFF")?{bom:"\uFEFF",text:e.slice(1)}:{bom:"",text:e}}u(D,"stripBom");function P(e,r){const o=E(e),i=E(r);return o.split(i).length-1}u(P,"countOccurrences");function R(e,r,o){return o===1?new Error(`Could not find the exact text in ${e}. The old text must match exactly including all whitespace and newlines.`):new Error(`Could not find edits[${r}] in ${e}. The oldText must match exactly including all whitespace and newlines.`)}u(R,"getNotFoundError");function k(e,r,o,i){return o===1?new Error(`Found ${i} occurrences of the text in ${e}. The text must be unique. Please provide more context to make it unique.`):new Error(`Found ${i} occurrences of edits[${r}] in ${e}. Each oldText must be unique. Please provide more context to make it unique.`)}u(k,"getDuplicateError");function q(e,r,o){return o===1?new Error(`oldText must not be empty in ${e}.`):new Error(`edits[${r}].oldText must not be empty in ${e}.`)}u(q,"getEmptyOldTextError");function A(e,r){return r===1?new Error(`No changes made to ${e}. The replacement produced identical content. This might indicate an issue with special characters or the text not existing as expected.`):new Error(`No changes made to ${e}. The replacements produced identical content.`)}u(A,"getNoChangeError");function j(e,r,o){const i=r.map(t=>({oldText:y(t.oldText),newText:y(t.newText)}));for(let t=0;t<i.length;t++)if(i[t].oldText.length===0)throw q(o,t,i.length);const l=i.map(t=>C(e,t.oldText)).some(t=>t.usedFuzzyMatch)?E(e):e,f=[];for(let t=0;t<i.length;t++){const n=i[t],c=C(l,n.oldText);if(!c.found)throw R(o,t,i.length);const m=P(l,n.oldText);if(m>1)throw k(o,t,i.length,m);f.push({editIndex:t,matchIndex:c.index,matchLength:c.matchLength,newText:n.newText})}f.sort((t,n)=>t.matchIndex-n.matchIndex);for(let t=1;t<f.length;t++){const n=f[t-1],c=f[t];if(n.matchIndex+n.matchLength>c.matchIndex)throw new Error(`edits[${n.editIndex}] and edits[${c.editIndex}] overlap in ${o}. Merge them into one edit or target disjoint regions.`)}let g=l;for(let t=f.length-1;t>=0;t--){const n=f[t];g=g.substring(0,n.matchIndex)+n.newText+g.substring(n.matchIndex+n.matchLength)}if(l===g)throw A(o,i.length);return{baseContent:l,newContent:g}}u(j,"applyEditsToNormalizedContent");function J(e,r,o,i=4){return S.createTwoFilesPatch(e,e,r,o,void 0,void 0,{context:i,headerOptions:S.FILE_HEADERS_ONLY})}u(J,"generateUnifiedPatch");function W(e,r,o=4){const i=S.diffLines(e,r),s=[],l=e.split(`
13
+ `),f=r.split(`
14
+ `),g=Math.max(l.length,f.length),t=String(g).length;let n=1,c=1,m=!1,z;for(let p=0;p<i.length;p++){const T=i[p],a=T.value.split(`
15
+ `);if(a[a.length-1]===""&&a.pop(),T.added||T.removed){z===void 0&&(z=c);for(const F of a)if(T.added){const x=String(c).padStart(t," ");s.push(`+${x} ${F}`),c++}else{const x=String(n).padStart(t," ");s.push(`-${x} ${F}`),n++}m=!0}else{const F=p<i.length-1&&(i[p+1].added||i[p+1].removed),x=m,N=F;if(x&&N)if(a.length<=o*2)for(const d of a){const h=String(n).padStart(t," ");s.push(` ${h} ${d}`),n++,c++}else{const d=a.slice(0,o),h=a.slice(a.length-o),$=a.length-d.length-h.length;for(const w of d){const L=String(n).padStart(t," ");s.push(` ${L} ${w}`),n++,c++}s.push(` ${"".padStart(t," ")} ...`),n+=$,c+=$;for(const w of h){const L=String(n).padStart(t," ");s.push(` ${L} ${w}`),n++,c++}}else if(x){const d=a.slice(0,o),h=a.length-d.length;for(const $ of d){const w=String(n).padStart(t," ");s.push(` ${w} ${$}`),n++,c++}h>0&&(s.push(` ${"".padStart(t," ")} ...`),n+=h,c+=h)}else if(N){const d=Math.max(0,a.length-o);d>0&&(s.push(` ${"".padStart(t," ")} ...`),n+=d,c+=d);for(const h of a.slice(d)){const $=String(n).padStart(t," ");s.push(` ${$} ${h}`),n++,c++}}else n+=a.length,c+=a.length;m=!1}}return{diff:s.join(`
16
+ `),firstChangedLine:z}}u(W,"generateDiffString");async function _(e,r,o){const i=v(e,o);try{try{await M(i,b.R_OK)}catch(n){const c=n instanceof Error&&"code"in n?`Error code: ${n.code}`:String(n);return{error:`Could not edit file: ${e}. ${c}.`}}const s=await O(i,"utf-8"),{text:l}=D(s),f=y(l),{baseContent:g,newContent:t}=j(f,r,e);return W(g,t)}catch(s){return{error:s instanceof Error?s.message:String(s)}}}u(_,"computeEditsDiff");async function Q(e,r,o,i){return _(e,[{oldText:r,newText:o}],i)}u(Q,"computeEditDiff");export{j as applyEditsToNormalizedContent,Q as computeEditDiff,_ as computeEditsDiff,Y as detectLineEnding,C as fuzzyFindText,W as generateDiffString,J as generateUnifiedPatch,E as normalizeForFuzzyMatch,y as normalizeToLF,G as restoreLineEndings,D as stripBom};
@@ -0,0 +1,50 @@
1
+ import type { AgentTool } from "@openadapter/koda-agent-core";
2
+ import { Box } from "@openadapter/koda-tui";
3
+ import { type Static, Type } from "typebox";
4
+ import type { ToolDefinition } from "../extensions/types.ts";
5
+ import { type EditDiffError, type EditDiffResult } from "./edit-diff.ts";
6
+ type EditPreview = EditDiffResult | EditDiffError;
7
+ type EditRenderState = {
8
+ callComponent?: EditCallRenderComponent;
9
+ };
10
+ declare const editSchema: Type.TObject<{
11
+ path: Type.TString;
12
+ edits: Type.TArray<Type.TObject<{
13
+ oldText: Type.TString;
14
+ newText: Type.TString;
15
+ }>>;
16
+ }>;
17
+ export type EditToolInput = Static<typeof editSchema>;
18
+ export interface EditToolDetails {
19
+ /** Display-oriented diff of the changes made */
20
+ diff: string;
21
+ /** Standard unified patch of the changes made */
22
+ patch: string;
23
+ /** Line number of the first change in the new file (for editor navigation) */
24
+ firstChangedLine?: number;
25
+ }
26
+ /**
27
+ * Pluggable operations for the edit tool.
28
+ * Override these to delegate file editing to remote systems (for example SSH).
29
+ */
30
+ export interface EditOperations {
31
+ /** Read file contents as a Buffer */
32
+ readFile: (absolutePath: string) => Promise<Buffer>;
33
+ /** Write content to a file */
34
+ writeFile: (absolutePath: string, content: string) => Promise<void>;
35
+ /** Check if file is readable and writable (throw if not) */
36
+ access: (absolutePath: string) => Promise<void>;
37
+ }
38
+ export interface EditToolOptions {
39
+ /** Custom operations for file editing. Default: local filesystem */
40
+ operations?: EditOperations;
41
+ }
42
+ type EditCallRenderComponent = Box & {
43
+ preview?: EditPreview;
44
+ previewArgsKey?: string;
45
+ previewPending?: boolean;
46
+ settledError?: boolean;
47
+ };
48
+ export declare function createEditToolDefinition(cwd: string, options?: EditToolOptions): ToolDefinition<typeof editSchema, EditToolDetails | undefined, EditRenderState>;
49
+ export declare function createEditTool(cwd: string, options?: EditToolOptions): AgentTool<typeof editSchema>;
50
+ export {};
@@ -0,0 +1,2 @@
1
+ var B=Object.defineProperty;var d=(e,t)=>B(e,"name",{value:t,configurable:!0});import{Box as x,Container as j,Spacer as v,Text as E}from"@openadapter/koda-tui";import{constants as A}from"fs";import{access as $,readFile as k,writeFile as q}from"fs/promises";import{Type as g}from"typebox";import{renderDiff as P}from"../../modes/interactive/components/diff.js";import{applyEditsToNormalizedContent as M,computeEditsDiff as N,detectLineEnding as z,generateDiffString as J,generateUnifiedPatch as U,normalizeToLF as W,restoreLineEndings as G,stripBom as H}from"./edit-diff.js";import{withFileMutationQueue as Q}from"./file-mutation-queue.js";import{resolveToCwd as V}from"./path-utils.js";import{renderToolPath as X,str as S}from"./render-utils.js";import{wrapToolDefinition as Y}from"./tool-definition-wrapper.js";const Z=g.Object({oldText:g.String({description:"Exact text for one targeted replacement. It must be unique in the original file and must not overlap with any other edits[].oldText in the same call."}),newText:g.String({description:"Replacement text for this targeted edit."})},{additionalProperties:!1}),ee=g.Object({path:g.String({description:"Path to the file to edit (relative or absolute)"}),edits:g.Array(Z,{description:"One or more targeted replacements. Each edit is matched against the original file, not incrementally. Do not include overlapping or nested edits. If two changes touch the same block or nearby lines, merge them into one edit instead."})},{additionalProperties:!1}),te={readFile:d(e=>k(e),"readFile"),writeFile:d((e,t)=>q(e,t,"utf-8"),"writeFile"),access:d(e=>$(e,A.R_OK|A.W_OK),"access")};function re(e){if(!e||typeof e!="object")return e;const t=e;if(typeof t.edits=="string")try{const o=JSON.parse(t.edits);Array.isArray(o)&&(t.edits=o)}catch{}const r=t;if(typeof r.oldText!="string"||typeof r.newText!="string")return t;const i=Array.isArray(r.edits)?[...r.edits]:[];i.push({oldText:r.oldText,newText:r.newText});const{oldText:f,newText:a,...n}=r;return{...n,edits:i}}d(re,"prepareEditArguments");function ie(e){if(!Array.isArray(e.edits)||e.edits.length===0)throw new Error("Edit tool input is invalid. edits must contain at least one replacement.");return{path:e.path,edits:e.edits}}d(ie,"validateEditInput");function ne(){return Object.assign(new x(1,1,e=>e),{preview:void 0,previewArgsKey:void 0,previewPending:!1,settledError:!1})}d(ne,"createEditCallRenderComponent");function oe(e,t){if(t instanceof x){const i=t;return e.callComponent=i,i}if(e.callComponent)return e.callComponent;const r=ne();return e.callComponent=r,r}d(oe,"getEditCallRenderComponent");function D(e){if(!e)return null;const t=typeof e.path=="string"?e.path:typeof e.file_path=="string"?e.file_path:null;return t?Array.isArray(e.edits)&&e.edits.length>0&&e.edits.every(r=>typeof r?.oldText=="string"&&typeof r?.newText=="string")?{path:t,edits:e.edits}:typeof e.oldText=="string"&&typeof e.newText=="string"?{path:t,edits:[{oldText:e.oldText,newText:e.newText}]}:null:null}d(D,"getRenderablePreviewInput");function se(e,t,r){const i=X(S(e?.file_path??e?.path),t,r);return`${t.fg("toolTitle",t.bold("edit"))} ${i}`}d(se,"formatEditCall");function de(e,t,r,i,f){const a=S(e?.file_path??e?.path),n=t&&!("error"in t)?t.diff:void 0,o=t&&"error"in t?t.error:void 0;if(f){const c=r.content.filter(l=>l.type==="text").map(l=>l.text||"").join(`
2
+ `);return!c||c===o?void 0:i.fg("error",c)}const s=r.details?.diff;if(s&&s!==n)return P(s,{filePath:a??void 0})}d(de,"formatEditResult");function ae(e,t,r){return e?"error"in e?i=>r.bg("toolErrorBg",i):i=>r.bg("toolSuccessBg",i):t?i=>r.bg("toolErrorBg",i):i=>r.bg("toolPendingBg",i)}d(ae,"getEditHeaderBg");function _(e,t,r,i){if(e.setBgFn(ae(e.preview,e.settledError,r)),e.clear(),e.addChild(new E(se(t,r,i),0,0)),!e.preview)return e;const f="error"in e.preview?r.fg("error",e.preview.error):P(e.preview.diff);return e.addChild(new v(1)),e.addChild(new E(f,0,0)),e}d(_,"buildEditCallComponent");function F(e,t,r){const i=e.preview,f=i===void 0||("error"in i&&"error"in t?i.error!==t.error:"error"in i!="error"in t)||!("error"in i)&&!("error"in t)&&(i.diff!==t.diff||i.firstChangedLine!==t.firstChangedLine);return e.preview=t,e.previewArgsKey=r,e.previewPending=!1,f}d(F,"setEditPreview");function le(e,t){const r=t?.operations??te;return{name:"edit",label:"edit",description:"Edit a single file using exact text replacement. Every edits[].oldText must match a unique, non-overlapping region of the original file. If two changes affect the same block or nearby lines, merge them into one edit instead of emitting overlapping edits. Do not include large unchanged regions just to connect distant changes.",promptSnippet:"Make precise file edits with exact text replacement, including multiple disjoint edits in one call",promptGuidelines:["Use edit for precise changes (edits[].oldText must match exactly)","When changing multiple separate locations in one file, use one edit call with multiple entries in edits[] instead of multiple edit calls","Each edits[].oldText is matched against the original file, not after earlier edits are applied. Do not emit overlapping or nested edits. Merge nearby changes into one edit.","Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions."],parameters:ee,renderShell:"self",prepareArguments:re,async execute(i,f,a,n,o){const{path:s,edits:c}=ie(f),l=V(s,e);return Q(l,async()=>{const p=d(()=>{if(a?.aborted)throw new Error("Operation aborted")},"throwIfAborted");p();try{await r.access(l)}catch(m){p();const L=m instanceof Error&&"code"in m?`Error code: ${m.code}`:String(m);throw new Error(`Could not edit file: ${s}. ${L}.`)}p();const w=(await r.readFile(l)).toString("utf-8");p();const{bom:u,text:C}=H(w),K=z(C),O=W(C),{baseContent:T,newContent:y}=M(O,c,s);p();const R=u+G(y,K);await r.writeFile(l,R),p();const b=J(T,y),I=U(s,T,y);return{content:[{type:"text",text:`Successfully replaced ${c.length} block(s) in ${s}.`}],details:{diff:b.diff,patch:I,firstChangedLine:b.firstChangedLine}}})},renderCall(i,f,a){const n=oe(a.state,a.lastComponent),o=D(i),s=o?JSON.stringify({path:o.path,edits:o.edits}):void 0;if(n.previewArgsKey!==s&&(n.preview=void 0,n.previewArgsKey=s,n.previewPending=!1,n.settledError=!1),a.argsComplete&&o&&!n.preview&&!n.previewPending){n.previewPending=!0;const c=s;N(o.path,o.edits,a.cwd).then(l=>{n.previewArgsKey===c&&(F(n,l,c),a.invalidate())})}return _(n,i,f,a.cwd)},renderResult(i,f,a,n){const o=n.state.callComponent,s=D(n.args),c=s?JSON.stringify({path:s.path,edits:s.edits}):void 0,l=i,p=n.isError?void 0:l.details?.diff;let h=!1;o&&(typeof p=="string"&&(h=F(o,{diff:p,firstChangedLine:l.details?.firstChangedLine},c)||h),o.settledError!==n.isError&&(o.settledError=n.isError,h=!0),h&&_(o,n.args,a,n.cwd));const w=de(n.args,o?.preview,l,a,n.isError),u=n.lastComponent??new j;return u.clear(),w&&(u.addChild(new v(1)),u.addChild(new E(w,1,0))),u}}}d(le,"createEditToolDefinition");function Te(e,t){return Y(le(e,t))}d(Te,"createEditTool");export{Te as createEditTool,le as createEditToolDefinition};
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Serialize file mutation operations targeting the same file.
3
+ * Operations for different files still run in parallel.
4
+ */
5
+ export declare function withFileMutationQueue<T>(filePath: string, fn: () => Promise<T>): Promise<T>;
@@ -0,0 +1 @@
1
+ var Q=Object.defineProperty;var i=(e,t)=>Q(e,"name",{value:t,configurable:!0});import{realpath as m}from"node:fs/promises";import{resolve as g}from"node:path";const u=new Map;let l=Promise.resolve();function p(e){return typeof e=="object"&&e!==null&&"code"in e&&(e.code==="ENOENT"||e.code==="ENOTDIR")}i(p,"isMissingPathError");async function M(e){const t=g(e);try{return await m(t)}catch(n){if(p(n))return t;throw n}}i(M,"getMutationQueueKey");async function x(e,t){const n=l.then(async()=>{const o=await M(e),a=u.get(o)??Promise.resolve();let s;const y=new Promise(w=>{s=w}),c=a.then(()=>y);return u.set(o,c),{key:o,currentQueue:a,chainedQueue:c,releaseNext:s}});l=n.then(()=>{},()=>{});const{key:r,currentQueue:f,chainedQueue:d,releaseNext:h}=await n;await f;try{return await t()}finally{h(),u.get(r)===d&&u.delete(r)}}i(x,"withFileMutationQueue");export{x as withFileMutationQueue};
@@ -0,0 +1,34 @@
1
+ import type { AgentTool } from "@openadapter/koda-agent-core";
2
+ import { type Static, Type } from "typebox";
3
+ import type { ToolDefinition } from "../extensions/types.ts";
4
+ import { type TruncationResult } from "./truncate.ts";
5
+ declare const findSchema: Type.TObject<{
6
+ pattern: Type.TString;
7
+ path: Type.TOptional<Type.TString>;
8
+ limit: Type.TOptional<Type.TNumber>;
9
+ }>;
10
+ export type FindToolInput = Static<typeof findSchema>;
11
+ export interface FindToolDetails {
12
+ truncation?: TruncationResult;
13
+ resultLimitReached?: number;
14
+ }
15
+ /**
16
+ * Pluggable operations for the find tool.
17
+ * Override these to delegate file search to remote systems (for example SSH).
18
+ */
19
+ export interface FindOperations {
20
+ /** Check if path exists */
21
+ exists: (absolutePath: string) => Promise<boolean> | boolean;
22
+ /** Find files matching glob pattern. Returns relative or absolute paths. */
23
+ glob: (pattern: string, cwd: string, options: {
24
+ ignore: string[];
25
+ limit: number;
26
+ }) => Promise<string[]> | string[];
27
+ }
28
+ export interface FindToolOptions {
29
+ /** Custom operations for find. Default: local filesystem plus fd */
30
+ operations?: FindOperations;
31
+ }
32
+ export declare function createFindToolDefinition(cwd: string, options?: FindToolOptions): ToolDefinition<typeof findSchema, FindToolDetails | undefined>;
33
+ export declare function createFindTool(cwd: string, options?: FindToolOptions): AgentTool<typeof findSchema>;
34
+ export {};