indusagi 0.12.19 → 0.12.21

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 (518) hide show
  1. package/README.md +16 -36
  2. package/dist/agent/agent-loop.d.ts +3 -9
  3. package/dist/agent/agent-loop.d.ts.map +1 -1
  4. package/dist/agent/agent-loop.js +19 -58
  5. package/dist/agent/agent-loop.js.map +1 -1
  6. package/dist/agent/agent.d.ts +9 -10
  7. package/dist/agent/agent.d.ts.map +1 -1
  8. package/dist/agent/agent.js +182 -129
  9. package/dist/agent/agent.js.map +1 -1
  10. package/dist/agent/error-handler.d.ts.map +1 -1
  11. package/dist/agent/error-handler.js.map +1 -1
  12. package/dist/agent/event-bus.d.ts.map +1 -1
  13. package/dist/agent/event-bus.js +1 -3
  14. package/dist/agent/event-bus.js.map +1 -1
  15. package/dist/agent/index.d.ts.map +1 -1
  16. package/dist/agent/index.js +0 -6
  17. package/dist/agent/index.js.map +1 -1
  18. package/dist/agent/messages.d.ts +1 -1
  19. package/dist/agent/messages.d.ts.map +1 -1
  20. package/dist/agent/proxy.d.ts +1 -14
  21. package/dist/agent/proxy.d.ts.map +1 -1
  22. package/dist/agent/proxy.js +67 -148
  23. package/dist/agent/proxy.js.map +1 -1
  24. package/dist/agent/session-manager.d.ts +10 -10
  25. package/dist/agent/session-manager.d.ts.map +1 -1
  26. package/dist/agent/session-manager.js +20 -16
  27. package/dist/agent/session-manager.js.map +1 -1
  28. package/dist/agent/state-manager.d.ts +1 -1
  29. package/dist/agent/state-manager.d.ts.map +1 -1
  30. package/dist/agent/state-manager.js +1 -0
  31. package/dist/agent/state-manager.js.map +1 -1
  32. package/dist/agent/telemetry.d.ts.map +1 -1
  33. package/dist/agent/telemetry.js +1 -3
  34. package/dist/agent/telemetry.js.map +1 -1
  35. package/dist/agent/tools/bash.d.ts.map +1 -1
  36. package/dist/agent/tools/bash.js +143 -118
  37. package/dist/agent/tools/bash.js.map +1 -1
  38. package/dist/agent/tools/edit-diff.d.ts +1 -1
  39. package/dist/agent/tools/edit-diff.d.ts.map +1 -1
  40. package/dist/agent/tools/edit-diff.js +189 -175
  41. package/dist/agent/tools/edit-diff.js.map +1 -1
  42. package/dist/agent/tools/edit.d.ts.map +1 -1
  43. package/dist/agent/tools/edit.js +137 -121
  44. package/dist/agent/tools/edit.js.map +1 -1
  45. package/dist/agent/tools/find.d.ts.map +1 -1
  46. package/dist/agent/tools/find.js +100 -65
  47. package/dist/agent/tools/find.js.map +1 -1
  48. package/dist/agent/tools/grep.d.ts.map +1 -1
  49. package/dist/agent/tools/grep.js +126 -97
  50. package/dist/agent/tools/grep.js.map +1 -1
  51. package/dist/agent/tools/index.d.ts +53 -40
  52. package/dist/agent/tools/index.d.ts.map +1 -1
  53. package/dist/agent/tools/index.js +19 -12
  54. package/dist/agent/tools/index.js.map +1 -1
  55. package/dist/agent/tools/ls.d.ts +2 -1
  56. package/dist/agent/tools/ls.d.ts.map +1 -1
  57. package/dist/agent/tools/ls.js +145 -94
  58. package/dist/agent/tools/ls.js.map +1 -1
  59. package/dist/agent/tools/path-utils.d.ts.map +1 -1
  60. package/dist/agent/tools/path-utils.js +48 -29
  61. package/dist/agent/tools/path-utils.js.map +1 -1
  62. package/dist/agent/tools/process-controller.d.ts +15 -0
  63. package/dist/agent/tools/process-controller.d.ts.map +1 -0
  64. package/dist/agent/tools/process-controller.js +39 -0
  65. package/dist/agent/tools/process-controller.js.map +1 -0
  66. package/dist/agent/tools/process-manager.d.ts +60 -0
  67. package/dist/agent/tools/process-manager.d.ts.map +1 -0
  68. package/dist/agent/tools/process-manager.js +485 -0
  69. package/dist/agent/tools/process-manager.js.map +1 -0
  70. package/dist/agent/tools/process-types.d.ts +74 -0
  71. package/dist/agent/tools/process-types.d.ts.map +1 -0
  72. package/dist/agent/tools/process-types.js +7 -0
  73. package/dist/agent/tools/process-types.js.map +1 -0
  74. package/dist/agent/tools/process.d.ts +38 -0
  75. package/dist/agent/tools/process.d.ts.map +1 -0
  76. package/dist/agent/tools/process.js +360 -0
  77. package/dist/agent/tools/process.js.map +1 -0
  78. package/dist/agent/tools/read.d.ts.map +1 -1
  79. package/dist/agent/tools/read.js +157 -135
  80. package/dist/agent/tools/read.js.map +1 -1
  81. package/dist/agent/tools/registry.js +2 -4
  82. package/dist/agent/tools/registry.js.map +1 -1
  83. package/dist/agent/tools/teams/activity-tracker.d.ts +66 -0
  84. package/dist/agent/tools/teams/activity-tracker.d.ts.map +1 -0
  85. package/dist/agent/tools/teams/activity-tracker.js +480 -0
  86. package/dist/agent/tools/teams/activity-tracker.js.map +1 -0
  87. package/dist/agent/tools/teams/cleanup.d.ts +51 -0
  88. package/dist/agent/tools/teams/cleanup.d.ts.map +1 -0
  89. package/dist/agent/tools/teams/cleanup.js +219 -0
  90. package/dist/agent/tools/teams/cleanup.js.map +1 -0
  91. package/dist/agent/tools/teams/fs-lock.d.ts +12 -0
  92. package/dist/agent/tools/teams/fs-lock.d.ts.map +1 -0
  93. package/dist/agent/tools/teams/fs-lock.js +74 -0
  94. package/dist/agent/tools/teams/fs-lock.js.map +1 -0
  95. package/dist/agent/tools/teams/index.d.ts +12 -0
  96. package/dist/agent/tools/teams/index.d.ts.map +1 -0
  97. package/dist/agent/tools/teams/index.js +12 -0
  98. package/dist/agent/tools/teams/index.js.map +1 -0
  99. package/dist/agent/tools/teams/mailbox.d.ts +21 -0
  100. package/dist/agent/tools/teams/mailbox.d.ts.map +1 -0
  101. package/dist/agent/tools/teams/mailbox.js +106 -0
  102. package/dist/agent/tools/teams/mailbox.js.map +1 -0
  103. package/dist/agent/tools/teams/model-policy.d.ts +23 -0
  104. package/dist/agent/tools/teams/model-policy.d.ts.map +1 -0
  105. package/dist/agent/tools/teams/model-policy.js +113 -0
  106. package/dist/agent/tools/teams/model-policy.js.map +1 -0
  107. package/dist/agent/tools/teams/names.d.ts +28 -0
  108. package/dist/agent/tools/teams/names.d.ts.map +1 -0
  109. package/dist/agent/tools/teams/names.js +109 -0
  110. package/dist/agent/tools/teams/names.js.map +1 -0
  111. package/dist/agent/tools/teams/protocol.d.ts +75 -0
  112. package/dist/agent/tools/teams/protocol.d.ts.map +1 -0
  113. package/dist/agent/tools/teams/protocol.js +205 -0
  114. package/dist/agent/tools/teams/protocol.js.map +1 -0
  115. package/dist/agent/tools/teams/task-store.d.ts +89 -0
  116. package/dist/agent/tools/teams/task-store.d.ts.map +1 -0
  117. package/dist/agent/tools/teams/task-store.js +445 -0
  118. package/dist/agent/tools/teams/task-store.js.map +1 -0
  119. package/dist/agent/tools/teams/team-attach-claim.d.ts +36 -0
  120. package/dist/agent/tools/teams/team-attach-claim.d.ts.map +1 -0
  121. package/dist/agent/tools/teams/team-attach-claim.js +144 -0
  122. package/dist/agent/tools/teams/team-attach-claim.js.map +1 -0
  123. package/dist/agent/tools/teams/team-config.d.ts +55 -0
  124. package/dist/agent/tools/teams/team-config.d.ts.map +1 -0
  125. package/dist/agent/tools/teams/team-config.js +252 -0
  126. package/dist/agent/tools/teams/team-config.js.map +1 -0
  127. package/dist/agent/tools/teams/worktree.d.ts +40 -0
  128. package/dist/agent/tools/teams/worktree.d.ts.map +1 -0
  129. package/dist/agent/tools/teams/worktree.js +213 -0
  130. package/dist/agent/tools/teams/worktree.js.map +1 -0
  131. package/dist/agent/tools/todo-store.js +2 -1
  132. package/dist/agent/tools/todo-store.js.map +1 -1
  133. package/dist/agent/tools/todo.d.ts +2 -2
  134. package/dist/agent/tools/todo.js +2 -2
  135. package/dist/agent/tools/truncate.d.ts.map +1 -1
  136. package/dist/agent/tools/truncate.js +150 -134
  137. package/dist/agent/tools/truncate.js.map +1 -1
  138. package/dist/agent/tools/utils/hook-runner.d.ts +9 -10
  139. package/dist/agent/tools/utils/hook-runner.d.ts.map +1 -1
  140. package/dist/agent/tools/utils/hook-runner.js +18 -16
  141. package/dist/agent/tools/utils/hook-runner.js.map +1 -1
  142. package/dist/agent/tools/utils/image-resize.d.ts +1 -14
  143. package/dist/agent/tools/utils/image-resize.d.ts.map +1 -1
  144. package/dist/agent/tools/utils/image-resize.js +80 -34
  145. package/dist/agent/tools/utils/image-resize.js.map +1 -1
  146. package/dist/agent/tools/utils/mime.d.ts +0 -8
  147. package/dist/agent/tools/utils/mime.d.ts.map +1 -1
  148. package/dist/agent/tools/utils/mime.js +43 -32
  149. package/dist/agent/tools/utils/mime.js.map +1 -1
  150. package/dist/agent/tools/utils/shell.d.ts +1 -23
  151. package/dist/agent/tools/utils/shell.d.ts.map +1 -1
  152. package/dist/agent/tools/utils/shell.js +43 -86
  153. package/dist/agent/tools/utils/shell.js.map +1 -1
  154. package/dist/agent/tools/write.d.ts.map +1 -1
  155. package/dist/agent/tools/write.js +105 -62
  156. package/dist/agent/tools/write.js.map +1 -1
  157. package/dist/agent/types.d.ts +69 -64
  158. package/dist/agent/types.d.ts.map +1 -1
  159. package/dist/agent/types.js +38 -23
  160. package/dist/agent/types.js.map +1 -1
  161. package/dist/agent.d.ts +4 -0
  162. package/dist/agent.d.ts.map +1 -1
  163. package/dist/agent.js +4 -0
  164. package/dist/agent.js.map +1 -1
  165. package/dist/ai/api-registry.d.ts.map +1 -1
  166. package/dist/ai/api-registry.js +3 -4
  167. package/dist/ai/api-registry.js.map +1 -1
  168. package/dist/ai/cli.js +62 -82
  169. package/dist/ai/cli.js.map +1 -1
  170. package/dist/ai/env-api-keys.d.ts.map +1 -1
  171. package/dist/ai/env-api-keys.js +78 -81
  172. package/dist/ai/env-api-keys.js.map +1 -1
  173. package/dist/ai/index.d.ts +6 -0
  174. package/dist/ai/index.d.ts.map +1 -1
  175. package/dist/ai/index.js +6 -0
  176. package/dist/ai/index.js.map +1 -1
  177. package/dist/ai/models.d.ts +7 -17
  178. package/dist/ai/models.d.ts.map +1 -1
  179. package/dist/ai/models.generated.d.ts +19 -0
  180. package/dist/ai/models.generated.d.ts.map +1 -1
  181. package/dist/ai/models.generated.js +14 -2
  182. package/dist/ai/models.generated.js.map +1 -1
  183. package/dist/ai/models.js +17 -11
  184. package/dist/ai/models.js.map +1 -1
  185. package/dist/ai/providers/amazon-bedrock.d.ts.map +1 -1
  186. package/dist/ai/providers/amazon-bedrock.js +319 -248
  187. package/dist/ai/providers/amazon-bedrock.js.map +1 -1
  188. package/dist/ai/providers/anthropic.d.ts.map +1 -1
  189. package/dist/ai/providers/anthropic.js +378 -324
  190. package/dist/ai/providers/anthropic.js.map +1 -1
  191. package/dist/ai/providers/azure-openai-responses.d.ts.map +1 -1
  192. package/dist/ai/providers/azure-openai-responses.js +164 -123
  193. package/dist/ai/providers/azure-openai-responses.js.map +1 -1
  194. package/dist/ai/providers/google-shared.d.ts +0 -18
  195. package/dist/ai/providers/google-shared.d.ts.map +1 -1
  196. package/dist/ai/providers/google-shared.js +224 -225
  197. package/dist/ai/providers/google-shared.js.map +1 -1
  198. package/dist/ai/providers/google-vertex.d.ts.map +1 -1
  199. package/dist/ai/providers/google-vertex.js +244 -226
  200. package/dist/ai/providers/google-vertex.js.map +1 -1
  201. package/dist/ai/providers/google.d.ts +3 -0
  202. package/dist/ai/providers/google.d.ts.map +1 -1
  203. package/dist/ai/providers/google.js +232 -210
  204. package/dist/ai/providers/google.js.map +1 -1
  205. package/dist/ai/providers/kimi.js +1 -0
  206. package/dist/ai/providers/kimi.js.map +1 -1
  207. package/dist/ai/providers/mock.d.ts +10 -0
  208. package/dist/ai/providers/mock.d.ts.map +1 -0
  209. package/dist/ai/providers/mock.js +64 -0
  210. package/dist/ai/providers/mock.js.map +1 -0
  211. package/dist/ai/providers/openai-codex-responses.d.ts.map +1 -1
  212. package/dist/ai/providers/openai-codex-responses.js +178 -133
  213. package/dist/ai/providers/openai-codex-responses.js.map +1 -1
  214. package/dist/ai/providers/openai-completions.d.ts.map +1 -1
  215. package/dist/ai/providers/openai-completions.js +468 -387
  216. package/dist/ai/providers/openai-completions.js.map +1 -1
  217. package/dist/ai/providers/openai-responses-shared.d.ts.map +1 -1
  218. package/dist/ai/providers/openai-responses-shared.js +187 -166
  219. package/dist/ai/providers/openai-responses-shared.js.map +1 -1
  220. package/dist/ai/providers/openai-responses.d.ts.map +1 -1
  221. package/dist/ai/providers/openai-responses.js +108 -85
  222. package/dist/ai/providers/openai-responses.js.map +1 -1
  223. package/dist/ai/providers/openai-scaffold.d.ts +4 -0
  224. package/dist/ai/providers/openai-scaffold.d.ts.map +1 -0
  225. package/dist/ai/providers/openai-scaffold.js +33 -0
  226. package/dist/ai/providers/openai-scaffold.js.map +1 -0
  227. package/dist/ai/providers/register-builtins.d.ts.map +1 -1
  228. package/dist/ai/providers/register-builtins.js +109 -42
  229. package/dist/ai/providers/register-builtins.js.map +1 -1
  230. package/dist/ai/providers/simple-options.js +2 -0
  231. package/dist/ai/providers/simple-options.js.map +1 -1
  232. package/dist/ai/providers/transform-messages.js +3 -9
  233. package/dist/ai/providers/transform-messages.js.map +1 -1
  234. package/dist/ai/stream.d.ts +4 -14
  235. package/dist/ai/stream.d.ts.map +1 -1
  236. package/dist/ai/stream.js +0 -36
  237. package/dist/ai/stream.js.map +1 -1
  238. package/dist/ai/types.d.ts +22 -3
  239. package/dist/ai/types.d.ts.map +1 -1
  240. package/dist/ai/types.js +154 -77
  241. package/dist/ai/types.js.map +1 -1
  242. package/dist/ai/utils/base-stream-handler.js +1 -0
  243. package/dist/ai/utils/base-stream-handler.js.map +1 -1
  244. package/dist/ai/utils/event-stream.d.ts +2 -0
  245. package/dist/ai/utils/event-stream.d.ts.map +1 -1
  246. package/dist/ai/utils/event-stream.js +22 -5
  247. package/dist/ai/utils/event-stream.js.map +1 -1
  248. package/dist/ai/utils/json-parse.d.ts +3 -0
  249. package/dist/ai/utils/json-parse.d.ts.map +1 -1
  250. package/dist/ai/utils/json-parse.js +8 -5
  251. package/dist/ai/utils/json-parse.js.map +1 -1
  252. package/dist/ai/utils/oauth/anthropic.d.ts.map +1 -1
  253. package/dist/ai/utils/oauth/anthropic.js +110 -65
  254. package/dist/ai/utils/oauth/anthropic.js.map +1 -1
  255. package/dist/ai/utils/oauth/github-copilot.d.ts +8 -16
  256. package/dist/ai/utils/oauth/github-copilot.d.ts.map +1 -1
  257. package/dist/ai/utils/oauth/github-copilot.js +218 -227
  258. package/dist/ai/utils/oauth/github-copilot.js.map +1 -1
  259. package/dist/ai/utils/oauth/openai-codex.d.ts +4 -2
  260. package/dist/ai/utils/oauth/openai-codex.d.ts.map +1 -1
  261. package/dist/ai/utils/oauth/openai-codex.js +221 -236
  262. package/dist/ai/utils/oauth/openai-codex.js.map +1 -1
  263. package/dist/ai/utils/oauth/pkce.d.ts +6 -5
  264. package/dist/ai/utils/oauth/pkce.d.ts.map +1 -1
  265. package/dist/ai/utils/oauth/pkce.js +24 -21
  266. package/dist/ai/utils/oauth/pkce.js.map +1 -1
  267. package/dist/ai/utils/oauth/types.d.ts +31 -12
  268. package/dist/ai/utils/oauth/types.d.ts.map +1 -1
  269. package/dist/ai/utils/oauth/types.js +10 -1
  270. package/dist/ai/utils/oauth/types.js.map +1 -1
  271. package/dist/ai/utils/overflow.d.ts.map +1 -1
  272. package/dist/ai/utils/overflow.js +49 -21
  273. package/dist/ai/utils/overflow.js.map +1 -1
  274. package/dist/ai/utils/provider-adapter.js +9 -0
  275. package/dist/ai/utils/provider-adapter.js.map +1 -1
  276. package/dist/ai/utils/provider-client-builder.js +1 -1
  277. package/dist/ai/utils/provider-client-builder.js.map +1 -1
  278. package/dist/ai/utils/provider-errors.js +2 -0
  279. package/dist/ai/utils/provider-errors.js.map +1 -1
  280. package/dist/ai/utils/sanitize-unicode.d.ts +0 -20
  281. package/dist/ai/utils/sanitize-unicode.d.ts.map +1 -1
  282. package/dist/ai/utils/sanitize-unicode.js +35 -17
  283. package/dist/ai/utils/sanitize-unicode.js.map +1 -1
  284. package/dist/ai/utils/stream-event-helper.js +3 -0
  285. package/dist/ai/utils/stream-event-helper.js.map +1 -1
  286. package/dist/ai/utils/stream-handler-types.js +5 -0
  287. package/dist/ai/utils/stream-handler-types.js.map +1 -1
  288. package/dist/ai/utils/streaming-state-manager.js +4 -2
  289. package/dist/ai/utils/streaming-state-manager.js.map +1 -1
  290. package/dist/ai/utils/typebox-helpers.d.ts +6 -4
  291. package/dist/ai/utils/typebox-helpers.d.ts.map +1 -1
  292. package/dist/ai/utils/typebox-helpers.js +25 -7
  293. package/dist/ai/utils/typebox-helpers.js.map +1 -1
  294. package/dist/ai/utils/validation.d.ts.map +1 -1
  295. package/dist/ai/utils/validation.js +67 -34
  296. package/dist/ai/utils/validation.js.map +1 -1
  297. package/dist/ai.d.ts +4 -0
  298. package/dist/ai.d.ts.map +1 -1
  299. package/dist/ai.js +4 -0
  300. package/dist/ai.js.map +1 -1
  301. package/dist/cli.d.ts +3 -0
  302. package/dist/cli.d.ts.map +1 -0
  303. package/dist/cli.js +3 -0
  304. package/dist/cli.js.map +1 -0
  305. package/dist/index.d.ts +1 -0
  306. package/dist/index.d.ts.map +1 -1
  307. package/dist/index.js +1 -0
  308. package/dist/index.js.map +1 -1
  309. package/dist/mcp/client-pool.js +3 -2
  310. package/dist/mcp/client-pool.js.map +1 -1
  311. package/dist/mcp/client.js +19 -6
  312. package/dist/mcp/client.js.map +1 -1
  313. package/dist/mcp/config.d.ts +6 -6
  314. package/dist/mcp/config.js +17 -17
  315. package/dist/mcp/config.js.map +1 -1
  316. package/dist/mcp/errors.js +8 -0
  317. package/dist/mcp/errors.js.map +1 -1
  318. package/dist/mcp/index.d.ts +5 -5
  319. package/dist/mcp/index.js +5 -5
  320. package/dist/mcp/schema-converter.d.ts +1 -1
  321. package/dist/mcp/schema-converter.js +1 -1
  322. package/dist/mcp/server.d.ts +4 -4
  323. package/dist/mcp/server.js +12 -7
  324. package/dist/mcp/server.js.map +1 -1
  325. package/dist/mcp/tool-factory.d.ts +2 -2
  326. package/dist/mcp/tool-factory.js +2 -2
  327. package/dist/mcp.d.ts +0 -4
  328. package/dist/mcp.d.ts.map +1 -1
  329. package/dist/mcp.js +0 -4
  330. package/dist/mcp.js.map +1 -1
  331. package/dist/observability.d.ts +2 -0
  332. package/dist/observability.d.ts.map +1 -0
  333. package/dist/observability.js +2 -0
  334. package/dist/observability.js.map +1 -0
  335. package/dist/tui/autocomplete.d.ts +14 -18
  336. package/dist/tui/autocomplete.d.ts.map +1 -1
  337. package/dist/tui/autocomplete.js +290 -402
  338. package/dist/tui/autocomplete.js.map +1 -1
  339. package/dist/tui/components/box.d.ts +1 -6
  340. package/dist/tui/components/box.d.ts.map +1 -1
  341. package/dist/tui/components/box.js +98 -67
  342. package/dist/tui/components/box.js.map +1 -1
  343. package/dist/tui/components/cancellable-loader.d.ts +6 -3
  344. package/dist/tui/components/cancellable-loader.d.ts.map +1 -1
  345. package/dist/tui/components/cancellable-loader.js +8 -9
  346. package/dist/tui/components/cancellable-loader.js.map +1 -1
  347. package/dist/tui/components/editor.d.ts +18 -0
  348. package/dist/tui/components/editor.d.ts.map +1 -1
  349. package/dist/tui/components/editor.js +356 -354
  350. package/dist/tui/components/editor.js.map +1 -1
  351. package/dist/tui/components/image.d.ts +2 -0
  352. package/dist/tui/components/image.d.ts.map +1 -1
  353. package/dist/tui/components/image.js +79 -37
  354. package/dist/tui/components/image.js.map +1 -1
  355. package/dist/tui/components/input.d.ts +4 -8
  356. package/dist/tui/components/input.d.ts.map +1 -1
  357. package/dist/tui/components/input.js +236 -232
  358. package/dist/tui/components/input.js.map +1 -1
  359. package/dist/tui/components/loader.d.ts +5 -5
  360. package/dist/tui/components/loader.d.ts.map +1 -1
  361. package/dist/tui/components/loader.js +22 -19
  362. package/dist/tui/components/loader.js.map +1 -1
  363. package/dist/tui/components/markdown.d.ts +2 -32
  364. package/dist/tui/components/markdown.d.ts.map +1 -1
  365. package/dist/tui/components/markdown.js +338 -357
  366. package/dist/tui/components/markdown.js.map +1 -1
  367. package/dist/tui/components/select-list.d.ts +1 -0
  368. package/dist/tui/components/select-list.d.ts.map +1 -1
  369. package/dist/tui/components/select-list.js +83 -82
  370. package/dist/tui/components/select-list.js.map +1 -1
  371. package/dist/tui/components/settings-list.d.ts +10 -10
  372. package/dist/tui/components/settings-list.d.ts.map +1 -1
  373. package/dist/tui/components/settings-list.js +48 -40
  374. package/dist/tui/components/settings-list.js.map +1 -1
  375. package/dist/tui/components/spacer.d.ts +1 -0
  376. package/dist/tui/components/spacer.d.ts.map +1 -1
  377. package/dist/tui/components/spacer.js +20 -5
  378. package/dist/tui/components/spacer.js.map +1 -1
  379. package/dist/tui/components/text.d.ts.map +1 -1
  380. package/dist/tui/components/text.js +47 -20
  381. package/dist/tui/components/text.js.map +1 -1
  382. package/dist/tui/components/truncated-text.d.ts +8 -4
  383. package/dist/tui/components/truncated-text.d.ts.map +1 -1
  384. package/dist/tui/components/truncated-text.js +15 -12
  385. package/dist/tui/components/truncated-text.js.map +1 -1
  386. package/dist/tui/editor-component.d.ts +87 -23
  387. package/dist/tui/editor-component.d.ts.map +1 -1
  388. package/dist/tui/fuzzy.d.ts.map +1 -1
  389. package/dist/tui/fuzzy.js +101 -50
  390. package/dist/tui/fuzzy.js.map +1 -1
  391. package/dist/tui/keybindings.d.ts +3 -3
  392. package/dist/tui/keybindings.d.ts.map +1 -1
  393. package/dist/tui/keybindings.js +137 -111
  394. package/dist/tui/keybindings.js.map +1 -1
  395. package/dist/tui/keys.d.ts +46 -43
  396. package/dist/tui/keys.d.ts.map +1 -1
  397. package/dist/tui/keys.js +493 -411
  398. package/dist/tui/keys.js.map +1 -1
  399. package/dist/tui/stdin-buffer.d.ts.map +1 -1
  400. package/dist/tui/stdin-buffer.js +162 -159
  401. package/dist/tui/stdin-buffer.js.map +1 -1
  402. package/dist/tui/terminal-image.d.ts +10 -5
  403. package/dist/tui/terminal-image.d.ts.map +1 -1
  404. package/dist/tui/terminal-image.js +53 -51
  405. package/dist/tui/terminal-image.js.map +1 -1
  406. package/dist/tui/terminal.d.ts +4 -27
  407. package/dist/tui/terminal.d.ts.map +1 -1
  408. package/dist/tui/terminal.js +123 -121
  409. package/dist/tui/terminal.js.map +1 -1
  410. package/dist/tui/tui.d.ts +14 -1
  411. package/dist/tui/tui.d.ts.map +1 -1
  412. package/dist/tui/tui.js +185 -145
  413. package/dist/tui/tui.js.map +1 -1
  414. package/dist/tui/utils.d.ts.map +1 -1
  415. package/dist/tui/utils.js +235 -216
  416. package/dist/tui/utils.js.map +1 -1
  417. package/dist/tui.d.ts +4 -0
  418. package/dist/tui.d.ts.map +1 -1
  419. package/dist/tui.js +4 -0
  420. package/dist/tui.js.map +1 -1
  421. package/package.json +23 -43
  422. package/LICENSE.md +0 -22
  423. package/dist/agent/tools/task-types.d.ts +0 -74
  424. package/dist/agent/tools/task-types.d.ts.map +0 -1
  425. package/dist/agent/tools/task-types.js +0 -8
  426. package/dist/agent/tools/task-types.js.map +0 -1
  427. package/dist/agent/tools/task.d.ts +0 -84
  428. package/dist/agent/tools/task.d.ts.map +0 -1
  429. package/dist/agent/tools/task.js +0 -184
  430. package/dist/agent/tools/task.js.map +0 -1
  431. package/dist/memory/embedder/base.d.ts +0 -41
  432. package/dist/memory/embedder/base.d.ts.map +0 -1
  433. package/dist/memory/embedder/base.js +0 -10
  434. package/dist/memory/embedder/base.js.map +0 -1
  435. package/dist/memory/embedder/index.d.ts +0 -8
  436. package/dist/memory/embedder/index.d.ts.map +0 -1
  437. package/dist/memory/embedder/index.js +0 -6
  438. package/dist/memory/embedder/index.js.map +0 -1
  439. package/dist/memory/embedder/openai.d.ts +0 -35
  440. package/dist/memory/embedder/openai.d.ts.map +0 -1
  441. package/dist/memory/embedder/openai.js +0 -103
  442. package/dist/memory/embedder/openai.js.map +0 -1
  443. package/dist/memory/index.d.ts +0 -33
  444. package/dist/memory/index.d.ts.map +0 -1
  445. package/dist/memory/index.js +0 -31
  446. package/dist/memory/index.js.map +0 -1
  447. package/dist/memory/memory.d.ts +0 -126
  448. package/dist/memory/memory.d.ts.map +0 -1
  449. package/dist/memory/memory.js +0 -280
  450. package/dist/memory/memory.js.map +0 -1
  451. package/dist/memory/processors/base.d.ts +0 -42
  452. package/dist/memory/processors/base.d.ts.map +0 -1
  453. package/dist/memory/processors/base.js +0 -6
  454. package/dist/memory/processors/base.js.map +0 -1
  455. package/dist/memory/processors/index.d.ts +0 -16
  456. package/dist/memory/processors/index.d.ts.map +0 -1
  457. package/dist/memory/processors/index.js +0 -18
  458. package/dist/memory/processors/index.js.map +0 -1
  459. package/dist/memory/processors/message-history.d.ts +0 -35
  460. package/dist/memory/processors/message-history.d.ts.map +0 -1
  461. package/dist/memory/processors/message-history.js +0 -51
  462. package/dist/memory/processors/message-history.js.map +0 -1
  463. package/dist/memory/processors/observational-memory/index.d.ts +0 -82
  464. package/dist/memory/processors/observational-memory/index.d.ts.map +0 -1
  465. package/dist/memory/processors/observational-memory/index.js +0 -234
  466. package/dist/memory/processors/observational-memory/index.js.map +0 -1
  467. package/dist/memory/processors/observational-memory/observer-agent.d.ts +0 -64
  468. package/dist/memory/processors/observational-memory/observer-agent.d.ts.map +0 -1
  469. package/dist/memory/processors/observational-memory/observer-agent.js +0 -362
  470. package/dist/memory/processors/observational-memory/observer-agent.js.map +0 -1
  471. package/dist/memory/processors/observational-memory/reflector-agent.d.ts +0 -38
  472. package/dist/memory/processors/observational-memory/reflector-agent.d.ts.map +0 -1
  473. package/dist/memory/processors/observational-memory/reflector-agent.js +0 -213
  474. package/dist/memory/processors/observational-memory/reflector-agent.js.map +0 -1
  475. package/dist/memory/processors/observational-memory/token-counter.d.ts +0 -35
  476. package/dist/memory/processors/observational-memory/token-counter.d.ts.map +0 -1
  477. package/dist/memory/processors/observational-memory/token-counter.js +0 -90
  478. package/dist/memory/processors/observational-memory/token-counter.js.map +0 -1
  479. package/dist/memory/processors/semantic-recall.d.ts +0 -55
  480. package/dist/memory/processors/semantic-recall.d.ts.map +0 -1
  481. package/dist/memory/processors/semantic-recall.js +0 -143
  482. package/dist/memory/processors/semantic-recall.js.map +0 -1
  483. package/dist/memory/processors/working-memory.d.ts +0 -41
  484. package/dist/memory/processors/working-memory.d.ts.map +0 -1
  485. package/dist/memory/processors/working-memory.js +0 -82
  486. package/dist/memory/processors/working-memory.js.map +0 -1
  487. package/dist/memory/storage/base.d.ts +0 -288
  488. package/dist/memory/storage/base.d.ts.map +0 -1
  489. package/dist/memory/storage/base.js +0 -211
  490. package/dist/memory/storage/base.js.map +0 -1
  491. package/dist/memory/storage/index.d.ts +0 -9
  492. package/dist/memory/storage/index.d.ts.map +0 -1
  493. package/dist/memory/storage/index.js +0 -7
  494. package/dist/memory/storage/index.js.map +0 -1
  495. package/dist/memory/storage/inmemory.d.ts +0 -93
  496. package/dist/memory/storage/inmemory.d.ts.map +0 -1
  497. package/dist/memory/storage/inmemory.js +0 -646
  498. package/dist/memory/storage/inmemory.js.map +0 -1
  499. package/dist/memory/tools/working-memory.d.ts +0 -100
  500. package/dist/memory/tools/working-memory.d.ts.map +0 -1
  501. package/dist/memory/tools/working-memory.js +0 -237
  502. package/dist/memory/tools/working-memory.js.map +0 -1
  503. package/dist/memory/types.d.ts +0 -386
  504. package/dist/memory/types.d.ts.map +0 -1
  505. package/dist/memory/types.js +0 -58
  506. package/dist/memory/types.js.map +0 -1
  507. package/dist/memory/vector/base.d.ts +0 -145
  508. package/dist/memory/vector/base.d.ts.map +0 -1
  509. package/dist/memory/vector/base.js +0 -83
  510. package/dist/memory/vector/base.js.map +0 -1
  511. package/dist/memory/vector/index.d.ts +0 -8
  512. package/dist/memory/vector/index.d.ts.map +0 -1
  513. package/dist/memory/vector/index.js +0 -7
  514. package/dist/memory/vector/index.js.map +0 -1
  515. package/dist/memory/vector/inmemory.d.ts +0 -47
  516. package/dist/memory/vector/inmemory.d.ts.map +0 -1
  517. package/dist/memory/vector/inmemory.js +0 -234
  518. package/dist/memory/vector/inmemory.js.map +0 -1
@@ -16,480 +16,368 @@ function walkDirectoryWithFd(baseDir, fdPath, query, maxResults) {
16
16
  "d",
17
17
  "--full-path",
18
18
  ];
19
- // Add query as pattern if provided
20
- if (query) {
19
+ if (query)
21
20
  args.push(query);
22
- }
23
21
  const result = spawnSync(fdPath, args, {
24
22
  encoding: "utf-8",
25
23
  stdio: ["pipe", "pipe", "pipe"],
26
24
  maxBuffer: 10 * 1024 * 1024,
27
25
  });
28
- if (result.status !== 0 || !result.stdout) {
26
+ if (result.status !== 0 || !result.stdout)
29
27
  return [];
28
+ return result.stdout
29
+ .trim()
30
+ .split("\n")
31
+ .filter(Boolean)
32
+ .map((line) => ({ path: line, isDirectory: line.endsWith("/") }));
33
+ }
34
+ class SuggestionCache {
35
+ store = new Map();
36
+ getOrLoad(key, loader) {
37
+ const cached = this.store.get(key);
38
+ if (cached)
39
+ return cached;
40
+ const loaded = loader();
41
+ this.evictIfNeeded();
42
+ this.store.set(key, loaded);
43
+ return loaded;
30
44
  }
31
- const lines = result.stdout.trim().split("\n").filter(Boolean);
32
- const results = [];
33
- for (const line of lines) {
34
- // fd outputs directories with trailing /
35
- const isDirectory = line.endsWith("/");
36
- results.push({
37
- path: line,
38
- isDirectory,
39
- });
45
+ clear() {
46
+ this.store.clear();
47
+ }
48
+ evictIfNeeded() {
49
+ if (this.store.size <= 200)
50
+ return;
51
+ const oldest = this.store.keys().next().value;
52
+ if (oldest)
53
+ this.store.delete(oldest);
40
54
  }
41
- return results;
42
55
  }
43
- // Combined provider that handles both slash commands and file paths
44
- export class CombinedAutocompleteProvider {
45
- constructor(commands = [], basePath = process.cwd(), fdPath = null) {
46
- this.suggestionCache = new Map();
56
+ class CommandAutocompleteEngine {
57
+ commands;
58
+ constructor(commands) {
47
59
  this.commands = commands;
48
- this.basePath = basePath;
49
- this.fdPath = fdPath;
50
60
  }
51
- getSuggestions(lines, cursorLine, cursorCol) {
52
- const currentLine = lines[cursorLine] || "";
53
- const textBeforeCursor = currentLine.slice(0, cursorCol);
54
- // Check for @ file reference (fuzzy search) - must be after a space or at start
55
- const atMatch = textBeforeCursor.match(/(?:^|[\s])(@[^\s]*)$/);
56
- if (atMatch) {
57
- const prefix = atMatch[1] ?? "@"; // The @... part
58
- const query = prefix.slice(1); // Remove the @
59
- const suggestions = this.getCachedSuggestions(`fuzzy:${query}`, () => this.getFuzzyFileSuggestions(query));
60
- if (suggestions.length === 0)
61
- return null;
62
- return {
63
- items: suggestions,
64
- prefix: prefix,
65
- };
66
- }
67
- // Check for slash commands
68
- if (textBeforeCursor.startsWith("/")) {
69
- const spaceIndex = textBeforeCursor.indexOf(" ");
70
- if (spaceIndex === -1) {
71
- // No space yet - complete command names with fuzzy matching
72
- const prefix = textBeforeCursor.slice(1); // Remove the "/"
73
- const commandItems = this.commands.map((cmd) => ({
74
- name: "name" in cmd ? cmd.name : cmd.value,
75
- label: "name" in cmd ? cmd.name : cmd.label,
76
- description: cmd.description,
77
- }));
78
- const filtered = fuzzyFilter(commandItems, prefix, (item) => item.name).map((item) => ({
79
- value: item.name,
80
- label: item.label,
81
- ...(item.description && { description: item.description }),
82
- }));
83
- if (filtered.length === 0)
84
- return null;
85
- return {
86
- items: filtered,
87
- prefix: textBeforeCursor,
88
- };
89
- }
90
- else {
91
- // Space found - complete command arguments
92
- const commandName = textBeforeCursor.slice(1, spaceIndex); // Command without "/"
93
- const argumentText = textBeforeCursor.slice(spaceIndex + 1); // Text after space
94
- const command = this.commands.find((cmd) => {
95
- const name = "name" in cmd ? cmd.name : cmd.value;
96
- return name === commandName;
97
- });
98
- if (!command || !("getArgumentCompletions" in command) || !command.getArgumentCompletions) {
99
- return null; // No argument completion for this command
100
- }
101
- const argumentSuggestions = command.getArgumentCompletions(argumentText);
102
- if (!argumentSuggestions || argumentSuggestions.length === 0) {
103
- return null;
104
- }
105
- return {
106
- items: argumentSuggestions,
107
- prefix: argumentText,
108
- };
109
- }
110
- }
111
- // Check for file paths - triggered by Tab or if we detect a path pattern
112
- const pathMatch = this.extractPathPrefix(textBeforeCursor, false);
113
- if (pathMatch !== null) {
114
- const suggestions = this.getCachedSuggestions(`path:${pathMatch}`, () => this.getFileSuggestions(pathMatch));
115
- if (suggestions.length === 0)
116
- return null;
117
- // Check if we have an exact match that is a directory
118
- // In that case, we might want to return suggestions for the directory content instead
119
- // But only if the prefix ends with /
120
- if (suggestions.length === 1 && suggestions[0]?.value === pathMatch && !pathMatch.endsWith("/")) {
121
- // Exact match found (e.g. user typed "src" and "src/" is the only match)
122
- // We still return it so user can select it and add /
123
- return {
124
- items: suggestions,
125
- prefix: pathMatch,
126
- };
127
- }
128
- return {
129
- items: suggestions,
130
- prefix: pathMatch,
131
- };
61
+ getSuggestions(textBeforeCursor) {
62
+ if (!textBeforeCursor.startsWith("/"))
63
+ return null;
64
+ const spaceIndex = textBeforeCursor.indexOf(" ");
65
+ if (spaceIndex === -1) {
66
+ return this.completeCommandName(textBeforeCursor);
132
67
  }
133
- return null;
68
+ return this.completeCommandArgument(textBeforeCursor, spaceIndex);
134
69
  }
135
- applyCompletion(lines, cursorLine, cursorCol, item, prefix) {
136
- const currentLine = lines[cursorLine] || "";
137
- const beforePrefix = currentLine.slice(0, cursorCol - prefix.length);
138
- const afterCursor = currentLine.slice(cursorCol);
139
- // Check if we're completing a slash command (prefix starts with "/" but NOT a file path)
140
- // Slash commands are at the start of the line and don't contain path separators after the first /
141
- const isSlashCommand = prefix.startsWith("/") && beforePrefix.trim() === "" && !prefix.slice(1).includes("/");
142
- if (isSlashCommand) {
143
- // This is a command name completion
144
- const newLine = `${beforePrefix}/${item.value} ${afterCursor}`;
145
- const newLines = [...lines];
146
- newLines[cursorLine] = newLine;
147
- return {
148
- lines: newLines,
149
- cursorLine,
150
- cursorCol: beforePrefix.length + item.value.length + 2, // +2 for "/" and space
151
- };
152
- }
153
- // Check if we're completing a file attachment (prefix starts with "@")
154
- if (prefix.startsWith("@")) {
155
- // This is a file attachment completion
156
- // Don't add space after directories so user can continue autocompleting
157
- const isDirectory = item.value.endsWith("/");
158
- const suffix = isDirectory ? "" : " ";
159
- const newLine = `${beforePrefix + item.value}${suffix}${afterCursor}`;
160
- const newLines = [...lines];
161
- newLines[cursorLine] = newLine;
162
- return {
163
- lines: newLines,
164
- cursorLine,
165
- cursorCol: beforePrefix.length + item.value.length + suffix.length,
166
- };
167
- }
168
- // Check if we're in a slash command context (beforePrefix contains "/command ")
169
- const textBeforeCursor = currentLine.slice(0, cursorCol);
170
- if (textBeforeCursor.includes("/") && textBeforeCursor.includes(" ")) {
171
- // This is likely a command argument completion
172
- const newLine = beforePrefix + item.value + afterCursor;
173
- const newLines = [...lines];
174
- newLines[cursorLine] = newLine;
175
- return {
176
- lines: newLines,
177
- cursorLine,
178
- cursorCol: beforePrefix.length + item.value.length,
179
- };
180
- }
181
- // For file paths, complete the path
182
- const newLine = beforePrefix + item.value + afterCursor;
183
- const newLines = [...lines];
184
- newLines[cursorLine] = newLine;
185
- return {
186
- lines: newLines,
187
- cursorLine,
188
- cursorCol: beforePrefix.length + item.value.length,
189
- };
70
+ completeCommandName(textBeforeCursor) {
71
+ const prefix = textBeforeCursor.slice(1);
72
+ const commandItems = this.commands.map((cmd) => ({
73
+ name: "name" in cmd ? cmd.name : cmd.value,
74
+ label: "name" in cmd ? cmd.name : cmd.label,
75
+ description: cmd.description,
76
+ }));
77
+ const items = fuzzyFilter(commandItems, prefix, (item) => item.name).map((item) => ({
78
+ value: item.name,
79
+ label: item.label,
80
+ ...(item.description && { description: item.description }),
81
+ }));
82
+ if (items.length === 0)
83
+ return null;
84
+ return { items, prefix: textBeforeCursor };
190
85
  }
191
- getCachedSuggestions(key, loader) {
192
- const cached = this.suggestionCache.get(key);
193
- if (cached)
194
- return cached;
195
- const items = loader();
196
- if (this.suggestionCache.size > 200) {
197
- const oldest = this.suggestionCache.keys().next().value;
198
- if (oldest)
199
- this.suggestionCache.delete(oldest);
86
+ completeCommandArgument(textBeforeCursor, spaceIndex) {
87
+ const commandName = textBeforeCursor.slice(1, spaceIndex);
88
+ const argumentPrefix = textBeforeCursor.slice(spaceIndex + 1);
89
+ const command = this.commands.find((cmd) => {
90
+ const name = "name" in cmd ? cmd.name : cmd.value;
91
+ return name === commandName;
92
+ });
93
+ if (!command || !("getArgumentCompletions" in command) || !command.getArgumentCompletions) {
94
+ return null;
200
95
  }
201
- this.suggestionCache.set(key, items);
202
- return items;
96
+ const items = command.getArgumentCompletions(argumentPrefix);
97
+ if (!items || items.length === 0)
98
+ return null;
99
+ return { items, prefix: argumentPrefix };
203
100
  }
204
- clearCache() {
205
- this.suggestionCache.clear();
101
+ }
102
+ class AttachmentAutocompleteEngine {
103
+ getAttachmentPrefix(textBeforeCursor) {
104
+ const match = textBeforeCursor.match(/(?:^|[\s])(@[^\s]*)$/);
105
+ return match?.[1] ?? null;
106
+ }
107
+ toQuery(prefix) {
108
+ return prefix.slice(1);
109
+ }
110
+ }
111
+ class PathAutocompleteEngine {
112
+ basePath;
113
+ fdPath;
114
+ constructor(basePath, fdPath) {
115
+ this.basePath = basePath;
116
+ this.fdPath = fdPath;
206
117
  }
207
- // Extract a path-like prefix from the text before cursor
208
118
  extractPathPrefix(text, forceExtract = false) {
209
- // Check for @ file attachment syntax first
210
119
  const atMatch = text.match(/@([^\s]*)$/);
211
- if (atMatch) {
212
- return atMatch[0]; // Return the full @path pattern
213
- }
214
- // Simple approach: find the last whitespace/delimiter and extract the word after it
215
- // This avoids catastrophic backtracking from nested quantifiers
120
+ if (atMatch)
121
+ return atMatch[0];
216
122
  const lastDelimiterIndex = Math.max(text.lastIndexOf(" "), text.lastIndexOf("\t"), text.lastIndexOf('"'), text.lastIndexOf("'"), text.lastIndexOf("="));
217
123
  const pathPrefix = lastDelimiterIndex === -1 ? text : text.slice(lastDelimiterIndex + 1);
218
- // For forced extraction (Tab key), always return something
219
- if (forceExtract) {
124
+ if (forceExtract)
220
125
  return pathPrefix;
221
- }
222
- // For natural triggers, return if it looks like a path, ends with /, starts with ~/, .
223
- // Only return empty string if the text looks like it's starting a path context
224
- if (pathPrefix.includes("/") || pathPrefix.startsWith(".") || pathPrefix.startsWith("~/")) {
126
+ if (pathPrefix.includes("/") || pathPrefix.startsWith(".") || pathPrefix.startsWith("~/"))
225
127
  return pathPrefix;
226
- }
227
- // Return empty string only if we're at the beginning of the line or after a space
228
- // (not after quotes or other delimiters that don't suggest file paths)
229
- if (pathPrefix === "" && (text === "" || text.endsWith(" "))) {
128
+ if (pathPrefix === "" && (text === "" || text.endsWith(" ")))
230
129
  return pathPrefix;
231
- }
232
130
  return null;
233
131
  }
234
- // Expand home directory (~/) to actual home path
235
- expandHomePath(path) {
236
- if (path.startsWith("~/")) {
237
- const expandedPath = join(homedir(), path.slice(2));
238
- // Preserve trailing slash if original path had one
239
- return path.endsWith("/") && !expandedPath.endsWith("/") ? `${expandedPath}/` : expandedPath;
240
- }
241
- else if (path === "~") {
242
- return homedir();
243
- }
244
- return path;
132
+ shouldTriggerForTab(textBeforeCursor) {
133
+ return !(textBeforeCursor.trim().startsWith("/") && !textBeforeCursor.trim().includes(" "));
245
134
  }
246
- // Get file/directory suggestions for a given path prefix
247
135
  getFileSuggestions(prefix) {
248
136
  try {
249
- let searchDir;
250
- let searchPrefix;
251
- let expandedPrefix = prefix;
252
- let isAtPrefix = false;
253
- // Handle @ file attachment prefix
254
- if (prefix.startsWith("@")) {
255
- isAtPrefix = true;
256
- expandedPrefix = prefix.slice(1); // Remove the @
257
- }
258
- // Handle home directory expansion
259
- if (expandedPrefix.startsWith("~")) {
260
- expandedPrefix = this.expandHomePath(expandedPrefix);
261
- }
262
- if (expandedPrefix === "" ||
263
- expandedPrefix === "./" ||
264
- expandedPrefix === "../" ||
265
- expandedPrefix === "~" ||
266
- expandedPrefix === "~/" ||
267
- expandedPrefix === "/" ||
268
- prefix === "@") {
269
- // Complete from specified position
270
- if (prefix.startsWith("~") || expandedPrefix === "/") {
271
- searchDir = expandedPrefix;
272
- }
273
- else {
274
- searchDir = join(this.basePath, expandedPrefix);
275
- }
276
- searchPrefix = "";
277
- }
278
- else if (expandedPrefix.endsWith("/")) {
279
- // If prefix ends with /, show contents of that directory
280
- if (prefix.startsWith("~") || expandedPrefix.startsWith("/")) {
281
- searchDir = expandedPrefix;
282
- }
283
- else {
284
- searchDir = join(this.basePath, expandedPrefix);
285
- }
286
- searchPrefix = "";
287
- }
288
- else {
289
- // Split into directory and file prefix
290
- const dir = dirname(expandedPrefix);
291
- const file = basename(expandedPrefix);
292
- if (prefix.startsWith("~") || expandedPrefix.startsWith("/")) {
293
- searchDir = dir;
294
- }
295
- else {
296
- searchDir = join(this.basePath, dir);
297
- }
298
- searchPrefix = file;
299
- }
300
- const entries = readdirSync(searchDir, { withFileTypes: true });
137
+ const plan = this.resolveSearchPlan(prefix);
138
+ const entries = readdirSync(plan.searchDir, { withFileTypes: true });
301
139
  const suggestions = [];
302
140
  for (const entry of entries) {
303
- if (!entry.name.toLowerCase().startsWith(searchPrefix.toLowerCase())) {
141
+ if (!entry.name.toLowerCase().startsWith(plan.searchPrefix.toLowerCase()))
304
142
  continue;
305
- }
306
- // Check if entry is a directory (or a symlink pointing to a directory)
307
- let isDirectory = entry.isDirectory();
308
- if (!isDirectory && entry.isSymbolicLink()) {
309
- try {
310
- const fullPath = join(searchDir, entry.name);
311
- isDirectory = statSync(fullPath).isDirectory();
312
- }
313
- catch {
314
- // Broken symlink or permission error - treat as file
315
- }
316
- }
317
- let relativePath;
318
- const name = entry.name;
319
- // Handle @ prefix path construction
320
- if (isAtPrefix) {
321
- const pathWithoutAt = expandedPrefix;
322
- if (pathWithoutAt.endsWith("/")) {
323
- relativePath = `@${pathWithoutAt}${name}`;
324
- }
325
- else if (pathWithoutAt.includes("/")) {
326
- if (pathWithoutAt.startsWith("~/")) {
327
- const homeRelativeDir = pathWithoutAt.slice(2); // Remove ~/
328
- const dir = dirname(homeRelativeDir);
329
- relativePath = `@~/${dir === "." ? name : join(dir, name)}`;
330
- }
331
- else {
332
- relativePath = `@${join(dirname(pathWithoutAt), name)}`;
333
- }
334
- }
335
- else {
336
- if (pathWithoutAt.startsWith("~")) {
337
- relativePath = `@~/${name}`;
338
- }
339
- else {
340
- relativePath = `@${name}`;
341
- }
342
- }
343
- }
344
- else if (prefix.endsWith("/")) {
345
- // If prefix ends with /, append entry to the prefix
346
- relativePath = prefix + name;
347
- }
348
- else if (prefix.includes("/")) {
349
- // Preserve ~/ format for home directory paths
350
- if (prefix.startsWith("~/")) {
351
- const homeRelativeDir = prefix.slice(2); // Remove ~/
352
- const dir = dirname(homeRelativeDir);
353
- relativePath = `~/${dir === "." ? name : join(dir, name)}`;
354
- }
355
- else if (prefix.startsWith("/")) {
356
- // Absolute path - construct properly
357
- const dir = dirname(prefix);
358
- if (dir === "/") {
359
- relativePath = `/${name}`;
360
- }
361
- else {
362
- relativePath = `${dir}/${name}`;
363
- }
364
- }
365
- else {
366
- relativePath = join(dirname(prefix), name);
367
- }
368
- }
369
- else {
370
- // For standalone entries, preserve ~/ if original prefix was ~/
371
- if (prefix.startsWith("~")) {
372
- relativePath = `~/${name}`;
373
- }
374
- else {
375
- relativePath = name;
376
- }
377
- }
143
+ const isDirectory = this.resolveDirectoryFlag(plan.searchDir, entry.name, entry.isDirectory(), entry.isSymbolicLink());
144
+ const relativePath = this.toRelativePath(prefix, plan.expandedPrefix, entry.name, plan.isAtPrefix);
378
145
  suggestions.push({
379
146
  value: isDirectory ? `${relativePath}/` : relativePath,
380
- label: name + (isDirectory ? "/" : ""),
147
+ label: entry.name + (isDirectory ? "/" : ""),
381
148
  });
382
149
  }
383
- // Sort directories first, then alphabetically
384
- suggestions.sort((a, b) => {
385
- const aIsDir = a.value.endsWith("/");
386
- const bIsDir = b.value.endsWith("/");
387
- if (aIsDir && !bIsDir)
150
+ return suggestions.sort((a, b) => {
151
+ const aDir = a.value.endsWith("/");
152
+ const bDir = b.value.endsWith("/");
153
+ if (aDir && !bDir)
388
154
  return -1;
389
- if (!aIsDir && bIsDir)
155
+ if (!aDir && bDir)
390
156
  return 1;
391
157
  return a.label.localeCompare(b.label);
392
158
  });
393
- return suggestions;
394
159
  }
395
- catch (_e) {
396
- // Directory doesn't exist or not accessible
160
+ catch {
397
161
  return [];
398
162
  }
399
163
  }
400
- // Score an entry against the query (higher = better match)
401
- // isDirectory adds bonus to prioritize folders
402
- scoreEntry(filePath, query, isDirectory) {
403
- const fileName = basename(filePath);
404
- const lowerFileName = fileName.toLowerCase();
405
- const lowerQuery = query.toLowerCase();
406
- let score = 0;
407
- // Exact filename match (highest)
408
- if (lowerFileName === lowerQuery)
409
- score = 100;
410
- // Filename starts with query
411
- else if (lowerFileName.startsWith(lowerQuery))
412
- score = 80;
413
- // Substring match in filename
414
- else if (lowerFileName.includes(lowerQuery))
415
- score = 50;
416
- // Substring match in full path
417
- else if (filePath.toLowerCase().includes(lowerQuery))
418
- score = 30;
419
- // Directories get a bonus to appear first
420
- if (isDirectory && score > 0)
421
- score += 10;
422
- return score;
423
- }
424
- // Fuzzy file search using fd (fast, respects .gitignore)
425
164
  getFuzzyFileSuggestions(query) {
426
- if (!this.fdPath) {
427
- // fd not available, return empty results
165
+ if (!this.fdPath)
428
166
  return [];
429
- }
430
167
  try {
431
168
  const entries = walkDirectoryWithFd(this.basePath, this.fdPath, query, 100);
432
- // Score entries
433
- const scoredEntries = entries
169
+ const scored = entries
434
170
  .map((entry) => ({
435
171
  ...entry,
436
172
  score: query ? this.scoreEntry(entry.path, query, entry.isDirectory) : 1,
437
173
  }))
438
- .filter((entry) => entry.score > 0);
439
- // Sort by score (descending) and take top 20
440
- scoredEntries.sort((a, b) => b.score - a.score);
441
- const topEntries = scoredEntries.slice(0, 20);
442
- // Build suggestions
443
- const suggestions = [];
444
- for (const { path: entryPath, isDirectory } of topEntries) {
445
- // fd already includes trailing / for directories
446
- const pathWithoutSlash = isDirectory ? entryPath.slice(0, -1) : entryPath;
447
- const entryName = basename(pathWithoutSlash);
448
- suggestions.push({
174
+ .filter((entry) => entry.score > 0)
175
+ .sort((a, b) => b.score - a.score)
176
+ .slice(0, 20);
177
+ return scored.map(({ path: entryPath, isDirectory }) => {
178
+ const normalizedPath = isDirectory ? entryPath.slice(0, -1) : entryPath;
179
+ return {
449
180
  value: `@${entryPath}`,
450
- label: entryName + (isDirectory ? "/" : ""),
451
- description: pathWithoutSlash,
452
- });
453
- }
454
- return suggestions;
181
+ label: basename(normalizedPath) + (isDirectory ? "/" : ""),
182
+ description: normalizedPath,
183
+ };
184
+ });
455
185
  }
456
186
  catch {
457
187
  return [];
458
188
  }
459
189
  }
190
+ resolveSearchPlan(prefix) {
191
+ const isAtPrefix = prefix.startsWith("@");
192
+ let expandedPrefix = isAtPrefix ? prefix.slice(1) : prefix;
193
+ if (expandedPrefix.startsWith("~"))
194
+ expandedPrefix = this.expandHomePath(expandedPrefix);
195
+ const rootLike = expandedPrefix === "" ||
196
+ expandedPrefix === "./" ||
197
+ expandedPrefix === "../" ||
198
+ expandedPrefix === "~" ||
199
+ expandedPrefix === "~/" ||
200
+ expandedPrefix === "/" ||
201
+ prefix === "@";
202
+ if (rootLike) {
203
+ const searchDir = prefix.startsWith("~") || expandedPrefix === "/" ? expandedPrefix : join(this.basePath, expandedPrefix);
204
+ return { searchDir, searchPrefix: "", expandedPrefix, isAtPrefix };
205
+ }
206
+ if (expandedPrefix.endsWith("/")) {
207
+ const searchDir = prefix.startsWith("~") || expandedPrefix.startsWith("/")
208
+ ? expandedPrefix
209
+ : join(this.basePath, expandedPrefix);
210
+ return { searchDir, searchPrefix: "", expandedPrefix, isAtPrefix };
211
+ }
212
+ const dir = dirname(expandedPrefix);
213
+ const file = basename(expandedPrefix);
214
+ const searchDir = prefix.startsWith("~") || expandedPrefix.startsWith("/") ? dir : join(this.basePath, dir);
215
+ return { searchDir, searchPrefix: file, expandedPrefix, isAtPrefix };
216
+ }
217
+ toRelativePath(prefix, expandedPrefix, name, isAtPrefix) {
218
+ if (isAtPrefix)
219
+ return this.buildAtPath(expandedPrefix, name);
220
+ if (prefix.endsWith("/"))
221
+ return prefix + name;
222
+ if (prefix.includes("/")) {
223
+ if (prefix.startsWith("~/")) {
224
+ const homeRelativeDir = prefix.slice(2);
225
+ const dir = dirname(homeRelativeDir);
226
+ return `~/${dir === "." ? name : join(dir, name)}`;
227
+ }
228
+ if (prefix.startsWith("/")) {
229
+ const dir = dirname(prefix);
230
+ return dir === "/" ? `/${name}` : `${dir}/${name}`;
231
+ }
232
+ return join(dirname(prefix), name);
233
+ }
234
+ return prefix.startsWith("~") ? `~/${name}` : name;
235
+ }
236
+ buildAtPath(pathWithoutAt, name) {
237
+ if (pathWithoutAt.endsWith("/")) {
238
+ return `@${pathWithoutAt}${name}`;
239
+ }
240
+ if (pathWithoutAt.includes("/")) {
241
+ if (pathWithoutAt.startsWith("~/")) {
242
+ const homeRelativeDir = pathWithoutAt.slice(2);
243
+ const dir = dirname(homeRelativeDir);
244
+ return `@~/${dir === "." ? name : join(dir, name)}`;
245
+ }
246
+ return `@${join(dirname(pathWithoutAt), name)}`;
247
+ }
248
+ return pathWithoutAt.startsWith("~") ? `@~/${name}` : `@${name}`;
249
+ }
250
+ resolveDirectoryFlag(searchDir, name, isDirectory, isSymlink) {
251
+ if (isDirectory || !isSymlink)
252
+ return isDirectory;
253
+ try {
254
+ return statSync(join(searchDir, name)).isDirectory();
255
+ }
256
+ catch {
257
+ return false;
258
+ }
259
+ }
260
+ expandHomePath(pathValue) {
261
+ if (pathValue.startsWith("~/")) {
262
+ const expanded = join(homedir(), pathValue.slice(2));
263
+ return pathValue.endsWith("/") && !expanded.endsWith("/") ? `${expanded}/` : expanded;
264
+ }
265
+ if (pathValue === "~")
266
+ return homedir();
267
+ return pathValue;
268
+ }
269
+ scoreEntry(filePath, query, isDirectory) {
270
+ const fileName = basename(filePath).toLowerCase();
271
+ const queryLower = query.toLowerCase();
272
+ let score = 0;
273
+ if (fileName === queryLower)
274
+ score = 100;
275
+ else if (fileName.startsWith(queryLower))
276
+ score = 80;
277
+ else if (fileName.includes(queryLower))
278
+ score = 50;
279
+ else if (filePath.toLowerCase().includes(queryLower))
280
+ score = 30;
281
+ if (isDirectory && score > 0)
282
+ score += 10;
283
+ return score;
284
+ }
285
+ }
286
+ class CompletionApplyStrategy {
287
+ apply(lines, cursorLine, cursorCol, item, prefix) {
288
+ const currentLine = lines[cursorLine] || "";
289
+ const beforePrefix = currentLine.slice(0, cursorCol - prefix.length);
290
+ const afterCursor = currentLine.slice(cursorCol);
291
+ if (this.isCommandName(prefix, beforePrefix)) {
292
+ return this.replaceWithSuffix(lines, cursorLine, `${beforePrefix}/${item.value} ${afterCursor}`, beforePrefix.length + item.value.length + 2);
293
+ }
294
+ if (prefix.startsWith("@")) {
295
+ const isDirectory = item.value.endsWith("/");
296
+ const suffix = isDirectory ? "" : " ";
297
+ return this.replaceWithSuffix(lines, cursorLine, `${beforePrefix + item.value}${suffix}${afterCursor}`, beforePrefix.length + item.value.length + suffix.length);
298
+ }
299
+ const textBeforeCursor = currentLine.slice(0, cursorCol);
300
+ const replacement = beforePrefix + item.value + afterCursor;
301
+ const nextCursor = beforePrefix.length + item.value.length;
302
+ if (textBeforeCursor.includes("/") && textBeforeCursor.includes(" ")) {
303
+ return this.replaceWithSuffix(lines, cursorLine, replacement, nextCursor);
304
+ }
305
+ return this.replaceWithSuffix(lines, cursorLine, replacement, nextCursor);
306
+ }
307
+ isCommandName(prefix, beforePrefix) {
308
+ return prefix.startsWith("/") && beforePrefix.trim() === "" && !prefix.slice(1).includes("/");
309
+ }
310
+ replaceWithSuffix(lines, cursorLine, line, cursorCol) {
311
+ const newLines = [...lines];
312
+ newLines[cursorLine] = line;
313
+ return { lines: newLines, cursorLine, cursorCol };
314
+ }
315
+ }
316
+ // Combined provider that handles both slash commands and file paths
317
+ export class CombinedAutocompleteProvider {
318
+ basePath;
319
+ fdPath;
320
+ cache = new SuggestionCache();
321
+ commandEngine;
322
+ attachmentEngine = new AttachmentAutocompleteEngine();
323
+ pathEngine;
324
+ applyStrategy = new CompletionApplyStrategy();
325
+ constructor(commands = [], basePath = process.cwd(), fdPath = null) {
326
+ this.basePath = basePath;
327
+ this.fdPath = fdPath;
328
+ this.commandEngine = new CommandAutocompleteEngine(commands);
329
+ this.pathEngine = new PathAutocompleteEngine(this.basePath, this.fdPath);
330
+ }
331
+ getSuggestions(lines, cursorLine, cursorCol) {
332
+ const currentLine = lines[cursorLine] || "";
333
+ const textBeforeCursor = currentLine.slice(0, cursorCol);
334
+ const attachmentPrefix = this.attachmentEngine.getAttachmentPrefix(textBeforeCursor);
335
+ if (attachmentPrefix) {
336
+ const query = this.attachmentEngine.toQuery(attachmentPrefix);
337
+ const items = this.cache.getOrLoad(`fuzzy:${query}`, () => this.pathEngine.getFuzzyFileSuggestions(query));
338
+ if (items.length > 0)
339
+ return { items, prefix: attachmentPrefix };
340
+ }
341
+ const commandSuggestions = this.commandEngine.getSuggestions(textBeforeCursor);
342
+ if (commandSuggestions)
343
+ return commandSuggestions;
344
+ const pathPrefix = this.pathEngine.extractPathPrefix(textBeforeCursor, false);
345
+ if (pathPrefix === null)
346
+ return null;
347
+ const items = this.cache.getOrLoad(`path:${pathPrefix}`, () => this.pathEngine.getFileSuggestions(pathPrefix));
348
+ if (items.length === 0)
349
+ return null;
350
+ return { items, prefix: pathPrefix };
351
+ }
352
+ applyCompletion(lines, cursorLine, cursorCol, item, prefix) {
353
+ return this.applyStrategy.apply(lines, cursorLine, cursorCol, item, prefix);
354
+ }
355
+ clearCache() {
356
+ this.cache.clear();
357
+ }
460
358
  // Force file completion (called on Tab key) - always returns suggestions
461
359
  getForceFileSuggestions(lines, cursorLine, cursorCol) {
462
360
  const currentLine = lines[cursorLine] || "";
463
361
  const textBeforeCursor = currentLine.slice(0, cursorCol);
464
- // Don't trigger if we're typing a slash command at the start of the line
465
- if (textBeforeCursor.trim().startsWith("/") && !textBeforeCursor.trim().includes(" ")) {
362
+ if (!this.pathEngine.shouldTriggerForTab(textBeforeCursor))
466
363
  return null;
467
- }
468
- // Force extract path prefix - this will always return something
469
- const pathMatch = this.extractPathPrefix(textBeforeCursor, true);
470
- if (pathMatch !== null) {
471
- const suggestions = this.getCachedSuggestions(`path:${pathMatch}`, () => this.getFileSuggestions(pathMatch));
472
- if (suggestions.length === 0)
473
- return null;
474
- return {
475
- items: suggestions,
476
- prefix: pathMatch,
477
- };
478
- }
479
- return null;
364
+ const pathPrefix = this.pathEngine.extractPathPrefix(textBeforeCursor, true);
365
+ if (pathPrefix === null)
366
+ return null;
367
+ const items = this.cache.getOrLoad(`path:${pathPrefix}`, () => this.pathEngine.getFileSuggestions(pathPrefix));
368
+ if (items.length === 0)
369
+ return null;
370
+ return { items, prefix: pathPrefix };
480
371
  }
481
372
  // Check if we should trigger file completion (called on Tab key)
482
373
  shouldTriggerFileCompletion(lines, cursorLine, cursorCol) {
483
374
  const currentLine = lines[cursorLine] || "";
484
375
  const textBeforeCursor = currentLine.slice(0, cursorCol);
485
- // Don't trigger if we're typing a slash command at the start of the line
486
- if (textBeforeCursor.trim().startsWith("/") && !textBeforeCursor.trim().includes(" ")) {
487
- return false;
488
- }
489
- return true;
376
+ return this.pathEngine.shouldTriggerForTab(textBeforeCursor);
490
377
  }
491
378
  }
492
379
  export class AsyncAutocompleteChain {
380
+ providers;
493
381
  constructor(providers) {
494
382
  this.providers = providers;
495
383
  }