@travisennis/acai 0.0.11 → 0.0.13

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 (292) hide show
  1. package/README.md +5 -5
  2. package/dist/agent/index.d.ts.map +1 -1
  3. package/dist/agent/index.js +2 -5
  4. package/dist/commands/history/types.d.ts +3 -2
  5. package/dist/commands/history/types.d.ts.map +1 -1
  6. package/dist/commands/init-project/utils.d.ts +0 -1
  7. package/dist/commands/init-project/utils.d.ts.map +1 -1
  8. package/dist/commands/init-project/utils.js +1 -12
  9. package/dist/commands/manager.d.ts.map +1 -1
  10. package/dist/commands/manager.js +6 -19
  11. package/dist/commands/resources/index.d.ts.map +1 -1
  12. package/dist/commands/resources/index.js +4 -1
  13. package/dist/commands/session/index.d.ts.map +1 -1
  14. package/dist/commands/session/index.js +6 -0
  15. package/dist/commands/session/types.d.ts +1 -0
  16. package/dist/commands/session/types.d.ts.map +1 -1
  17. package/dist/commands/share/html-renderer.d.ts.map +1 -1
  18. package/dist/commands/share/html-renderer.js +54 -48
  19. package/dist/commands/tools/index.d.ts +3 -0
  20. package/dist/commands/tools/index.d.ts.map +1 -0
  21. package/dist/commands/tools/index.js +191 -0
  22. package/dist/commands/tools/templates.d.ts +6 -0
  23. package/dist/commands/tools/templates.d.ts.map +1 -0
  24. package/dist/commands/tools/templates.js +97 -0
  25. package/dist/config/index.d.ts +5 -2
  26. package/dist/config/index.d.ts.map +1 -1
  27. package/dist/config/index.js +42 -6
  28. package/dist/index.d.ts +14 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +98 -68
  31. package/dist/models/anthropic-provider.d.ts +1 -1
  32. package/dist/models/deepseek-provider.d.ts +3 -3
  33. package/dist/models/deepseek-provider.js +17 -17
  34. package/dist/models/google-provider.d.ts +2 -4
  35. package/dist/models/google-provider.d.ts.map +1 -1
  36. package/dist/models/google-provider.js +2 -17
  37. package/dist/models/groq-provider.d.ts +2 -4
  38. package/dist/models/groq-provider.d.ts.map +1 -1
  39. package/dist/models/groq-provider.js +3 -21
  40. package/dist/models/manager.d.ts +1 -10
  41. package/dist/models/manager.d.ts.map +1 -1
  42. package/dist/models/manager.js +2 -2
  43. package/dist/models/opencode-go-provider.d.ts +11 -1
  44. package/dist/models/opencode-go-provider.d.ts.map +1 -1
  45. package/dist/models/opencode-go-provider.js +130 -0
  46. package/dist/models/opencode-zen-provider.d.ts +3 -3
  47. package/dist/models/opencode-zen-provider.d.ts.map +1 -1
  48. package/dist/models/opencode-zen-provider.js +26 -32
  49. package/dist/models/openrouter-provider.d.ts +4 -15
  50. package/dist/models/openrouter-provider.d.ts.map +1 -1
  51. package/dist/models/openrouter-provider.js +26 -169
  52. package/dist/models/providers.d.ts +1 -1
  53. package/dist/models/providers.d.ts.map +1 -1
  54. package/dist/models/xai-provider.d.ts +1 -2
  55. package/dist/models/xai-provider.d.ts.map +1 -1
  56. package/dist/models/xai-provider.js +0 -13
  57. package/dist/prompts/manager.d.ts.map +1 -1
  58. package/dist/prompts/manager.js +5 -1
  59. package/dist/prompts/system-prompt.d.ts +1 -2
  60. package/dist/prompts/system-prompt.d.ts.map +1 -1
  61. package/dist/prompts/system-prompt.js +26 -15
  62. package/dist/repl/index.d.ts +28 -13
  63. package/dist/repl/index.d.ts.map +1 -1
  64. package/dist/repl/index.js +242 -305
  65. package/dist/skills/activated-tracker.d.ts +11 -0
  66. package/dist/skills/activated-tracker.d.ts.map +1 -0
  67. package/dist/skills/activated-tracker.js +16 -0
  68. package/dist/skills/index.d.ts +12 -2
  69. package/dist/skills/index.d.ts.map +1 -1
  70. package/dist/skills/index.js +127 -71
  71. package/dist/terminal/control.d.ts +1 -21
  72. package/dist/terminal/control.d.ts.map +1 -1
  73. package/dist/terminal/control.js +1 -32
  74. package/dist/terminal/formatting.d.ts +0 -33
  75. package/dist/terminal/formatting.d.ts.map +1 -1
  76. package/dist/terminal/formatting.js +0 -91
  77. package/dist/terminal/highlight/theme.d.ts +0 -37
  78. package/dist/terminal/highlight/theme.d.ts.map +1 -1
  79. package/dist/terminal/highlight/theme.js +1 -79
  80. package/dist/terminal/keys.d.ts +0 -97
  81. package/dist/terminal/keys.d.ts.map +1 -1
  82. package/dist/terminal/keys.js +0 -194
  83. package/dist/terminal/select-prompt.d.ts.map +1 -1
  84. package/dist/terminal/select-prompt.js +65 -51
  85. package/dist/terminal/style.d.ts +1 -1
  86. package/dist/terminal/style.d.ts.map +1 -1
  87. package/dist/terminal/supports-color.d.ts.map +1 -1
  88. package/dist/terminal/supports-color.js +38 -20
  89. package/dist/terminal/supports-hyperlinks.d.ts +3 -0
  90. package/dist/terminal/supports-hyperlinks.d.ts.map +1 -1
  91. package/dist/terminal/supports-hyperlinks.js +72 -31
  92. package/dist/terminal/table/layout-manager.d.ts +0 -20
  93. package/dist/terminal/table/layout-manager.d.ts.map +1 -1
  94. package/dist/terminal/table/layout-manager.js +68 -44
  95. package/dist/terminal/table/utils.d.ts +0 -1
  96. package/dist/terminal/table/utils.d.ts.map +1 -1
  97. package/dist/terminal/table/utils.js +2 -4
  98. package/dist/tools/apply-patch.d.ts +5 -3
  99. package/dist/tools/apply-patch.d.ts.map +1 -1
  100. package/dist/tools/apply-patch.js +154 -123
  101. package/dist/tools/bash.d.ts +4 -4
  102. package/dist/tools/bash.d.ts.map +1 -1
  103. package/dist/tools/bash.js +27 -13
  104. package/dist/tools/dynamic-tool-loader.d.ts +17 -3
  105. package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
  106. package/dist/tools/dynamic-tool-loader.js +360 -81
  107. package/dist/tools/edit-file.d.ts +2 -2
  108. package/dist/tools/index.d.ts +27 -151
  109. package/dist/tools/index.d.ts.map +1 -1
  110. package/dist/tools/index.js +16 -21
  111. package/dist/tools/read-file.d.ts +8 -8
  112. package/dist/tools/read-file.d.ts.map +1 -1
  113. package/dist/tools/read-file.js +32 -13
  114. package/dist/tools/save-file.d.ts +4 -4
  115. package/dist/tools/skill.d.ts +2 -1
  116. package/dist/tools/skill.d.ts.map +1 -1
  117. package/dist/tools/skill.js +64 -14
  118. package/dist/tools/types.d.ts +8 -2
  119. package/dist/tools/types.d.ts.map +1 -1
  120. package/dist/tools/web-fetch.d.ts +8 -12
  121. package/dist/tools/web-fetch.d.ts.map +1 -1
  122. package/dist/tools/web-fetch.js +86 -44
  123. package/dist/tools/web-search.d.ts +4 -8
  124. package/dist/tools/web-search.d.ts.map +1 -1
  125. package/dist/tools/web-search.js +41 -33
  126. package/dist/tui/autocomplete/utils.d.ts +0 -15
  127. package/dist/tui/autocomplete/utils.d.ts.map +1 -1
  128. package/dist/tui/autocomplete/utils.js +0 -85
  129. package/dist/tui/autocomplete.d.ts +1 -1
  130. package/dist/tui/autocomplete.d.ts.map +1 -1
  131. package/dist/tui/autocomplete.js +1 -1
  132. package/dist/tui/components/editor.d.ts +12 -0
  133. package/dist/tui/components/editor.d.ts.map +1 -1
  134. package/dist/tui/components/editor.js +181 -195
  135. package/dist/tui/components/footer.d.ts +0 -2
  136. package/dist/tui/components/footer.d.ts.map +1 -1
  137. package/dist/tui/components/footer.js +1 -17
  138. package/dist/tui/components/input.d.ts +4 -0
  139. package/dist/tui/components/input.d.ts.map +1 -1
  140. package/dist/tui/components/input.js +33 -31
  141. package/dist/tui/components/markdown.d.ts +30 -0
  142. package/dist/tui/components/markdown.d.ts.map +1 -1
  143. package/dist/tui/components/markdown.js +274 -242
  144. package/dist/tui/components/modal.d.ts.map +1 -1
  145. package/dist/tui/components/modal.js +11 -11
  146. package/dist/tui/components/select-list.d.ts +5 -0
  147. package/dist/tui/components/select-list.d.ts.map +1 -1
  148. package/dist/tui/components/select-list.js +69 -98
  149. package/dist/tui/components/table.d.ts +6 -0
  150. package/dist/tui/components/table.d.ts.map +1 -1
  151. package/dist/tui/components/table.js +61 -52
  152. package/dist/tui/index.d.ts +1 -8
  153. package/dist/tui/index.d.ts.map +1 -1
  154. package/dist/tui/index.js +0 -8
  155. package/dist/tui/tui.d.ts +9 -0
  156. package/dist/tui/tui.d.ts.map +1 -1
  157. package/dist/tui/tui.js +78 -48
  158. package/dist/tui/utils.d.ts +7 -0
  159. package/dist/tui/utils.d.ts.map +1 -1
  160. package/dist/tui/utils.js +117 -53
  161. package/dist/utils/bash.d.ts.map +1 -1
  162. package/dist/utils/bash.js +121 -104
  163. package/dist/utils/binary-output.d.ts +32 -0
  164. package/dist/utils/binary-output.d.ts.map +1 -0
  165. package/dist/utils/binary-output.js +127 -0
  166. package/dist/utils/command-protection.d.ts +3 -2
  167. package/dist/utils/command-protection.d.ts.map +1 -1
  168. package/dist/utils/command-protection.js +121 -29
  169. package/dist/utils/filesystem/operations.d.ts +0 -15
  170. package/dist/utils/filesystem/operations.d.ts.map +1 -1
  171. package/dist/utils/filesystem/operations.js +1 -38
  172. package/dist/utils/filesystem/security.d.ts.map +1 -1
  173. package/dist/utils/filesystem/security.js +22 -15
  174. package/dist/utils/filetype-detection.d.ts +0 -1
  175. package/dist/utils/filetype-detection.d.ts.map +1 -1
  176. package/dist/utils/filetype-detection.js +0 -12
  177. package/dist/utils/formatting.d.ts +0 -30
  178. package/dist/utils/formatting.d.ts.map +1 -1
  179. package/dist/utils/formatting.js +0 -44
  180. package/dist/utils/git.d.ts +4 -6
  181. package/dist/utils/git.d.ts.map +1 -1
  182. package/dist/utils/git.js +36 -46
  183. package/dist/utils/ignore.d.ts +1 -1
  184. package/dist/utils/ignore.d.ts.map +1 -1
  185. package/dist/utils/ignore.js +1 -1
  186. package/dist/utils/parsing.d.ts +1 -1
  187. package/dist/utils/parsing.d.ts.map +1 -1
  188. package/dist/utils/process.d.ts.map +1 -1
  189. package/dist/utils/process.js +77 -79
  190. package/dist/utils/yaml.d.ts +0 -1
  191. package/dist/utils/yaml.d.ts.map +1 -1
  192. package/dist/utils/yaml.js +80 -89
  193. package/dist/utils/zod.d.ts +0 -3
  194. package/dist/utils/zod.d.ts.map +1 -1
  195. package/dist/utils/zod.js +0 -7
  196. package/package.json +32 -29
  197. package/dist/agent/sub-agent.d.ts +0 -23
  198. package/dist/agent/sub-agent.d.ts.map +0 -1
  199. package/dist/agent/sub-agent.js +0 -109
  200. package/dist/commands/add-directory/index.d.ts +0 -3
  201. package/dist/commands/add-directory/index.d.ts.map +0 -1
  202. package/dist/commands/add-directory/index.js +0 -50
  203. package/dist/commands/add-directory/utils.d.ts +0 -3
  204. package/dist/commands/add-directory/utils.d.ts.map +0 -1
  205. package/dist/commands/add-directory/utils.js +0 -15
  206. package/dist/commands/clear/index.d.ts +0 -3
  207. package/dist/commands/clear/index.d.ts.map +0 -1
  208. package/dist/commands/clear/index.js +0 -13
  209. package/dist/commands/generate-rules/index.d.ts +0 -3
  210. package/dist/commands/generate-rules/index.d.ts.map +0 -1
  211. package/dist/commands/generate-rules/index.js +0 -206
  212. package/dist/commands/generate-rules/service.d.ts +0 -22
  213. package/dist/commands/generate-rules/service.d.ts.map +0 -1
  214. package/dist/commands/generate-rules/service.js +0 -103
  215. package/dist/commands/generate-rules/utils.d.ts +0 -5
  216. package/dist/commands/generate-rules/utils.d.ts.map +0 -1
  217. package/dist/commands/generate-rules/utils.js +0 -25
  218. package/dist/commands/handoff/index.d.ts +0 -3
  219. package/dist/commands/handoff/index.d.ts.map +0 -1
  220. package/dist/commands/handoff/index.js +0 -97
  221. package/dist/commands/handoff/utils.d.ts +0 -4
  222. package/dist/commands/handoff/utils.d.ts.map +0 -1
  223. package/dist/commands/handoff/utils.js +0 -123
  224. package/dist/commands/list-directories/index.d.ts +0 -3
  225. package/dist/commands/list-directories/index.d.ts.map +0 -1
  226. package/dist/commands/list-directories/index.js +0 -35
  227. package/dist/commands/pickup/index.d.ts +0 -3
  228. package/dist/commands/pickup/index.d.ts.map +0 -1
  229. package/dist/commands/pickup/index.js +0 -141
  230. package/dist/commands/pickup/types.d.ts +0 -6
  231. package/dist/commands/pickup/types.d.ts.map +0 -1
  232. package/dist/commands/pickup/types.js +0 -1
  233. package/dist/commands/pickup/utils.d.ts +0 -7
  234. package/dist/commands/pickup/utils.d.ts.map +0 -1
  235. package/dist/commands/pickup/utils.js +0 -56
  236. package/dist/commands/remove-directory/index.d.ts +0 -3
  237. package/dist/commands/remove-directory/index.d.ts.map +0 -1
  238. package/dist/commands/remove-directory/index.js +0 -55
  239. package/dist/commands/review/index.d.ts +0 -3
  240. package/dist/commands/review/index.d.ts.map +0 -1
  241. package/dist/commands/review/index.js +0 -12
  242. package/dist/commands/review/review-panel.d.ts +0 -3
  243. package/dist/commands/review/review-panel.d.ts.map +0 -1
  244. package/dist/commands/review/review-panel.js +0 -186
  245. package/dist/commands/review/utils.d.ts +0 -18
  246. package/dist/commands/review/utils.d.ts.map +0 -1
  247. package/dist/commands/review/utils.js +0 -146
  248. package/dist/commands/shell/index.d.ts +0 -3
  249. package/dist/commands/shell/index.d.ts.map +0 -1
  250. package/dist/commands/shell/index.js +0 -96
  251. package/dist/modes/manager.d.ts +0 -24
  252. package/dist/modes/manager.d.ts.map +0 -1
  253. package/dist/modes/manager.js +0 -77
  254. package/dist/modes/prompts.d.ts +0 -2
  255. package/dist/modes/prompts.d.ts.map +0 -1
  256. package/dist/modes/prompts.js +0 -142
  257. package/dist/subagents/index.d.ts +0 -16
  258. package/dist/subagents/index.d.ts.map +0 -1
  259. package/dist/subagents/index.js +0 -231
  260. package/dist/terminal/index.d.ts +0 -9
  261. package/dist/terminal/index.d.ts.map +0 -1
  262. package/dist/terminal/index.js +0 -8
  263. package/dist/tools/agent.d.ts +0 -27
  264. package/dist/tools/agent.d.ts.map +0 -1
  265. package/dist/tools/agent.js +0 -81
  266. package/dist/tools/directory-tree.d.ts +0 -28
  267. package/dist/tools/directory-tree.d.ts.map +0 -1
  268. package/dist/tools/directory-tree.js +0 -152
  269. package/dist/tools/glob.d.ts +0 -35
  270. package/dist/tools/glob.d.ts.map +0 -1
  271. package/dist/tools/glob.js +0 -159
  272. package/dist/tools/grep.d.ts +0 -100
  273. package/dist/tools/grep.d.ts.map +0 -1
  274. package/dist/tools/grep.js +0 -601
  275. package/dist/tools/ls.d.ts +0 -26
  276. package/dist/tools/ls.d.ts.map +0 -1
  277. package/dist/tools/ls.js +0 -82
  278. package/dist/tui/components/header.d.ts +0 -21
  279. package/dist/tui/components/header.d.ts.map +0 -1
  280. package/dist/tui/components/header.js +0 -63
  281. package/dist/utils/bash/parse.d.ts +0 -19
  282. package/dist/utils/bash/parse.d.ts.map +0 -1
  283. package/dist/utils/bash/parse.js +0 -223
  284. package/dist/utils/bash/quote.d.ts +0 -6
  285. package/dist/utils/bash/quote.d.ts.map +0 -1
  286. package/dist/utils/bash/quote.js +0 -23
  287. package/dist/utils/generators.d.ts +0 -3
  288. package/dist/utils/generators.d.ts.map +0 -1
  289. package/dist/utils/generators.js +0 -25
  290. package/dist/utils/glob.d.ts +0 -52
  291. package/dist/utils/glob.d.ts.map +0 -1
  292. package/dist/utils/glob.js +0 -376
@@ -1,601 +0,0 @@
1
- import { execFile, } from "node:child_process";
2
- import { inspect } from "node:util";
3
- import { z } from "zod";
4
- import style from "../terminal/style.js";
5
- import { toDisplayPath } from "../utils/filesystem/path-display.js";
6
- import { convertNullString } from "../utils/zod.js";
7
- // default limit
8
- const DEFAULT_MAX_RESULTS = 100;
9
- export const GrepTool = {
10
- name: "Grep",
11
- };
12
- const inputSchema = z.object({
13
- pattern: z
14
- .string()
15
- .describe("The search pattern (regex by default, or fixed-string if literal=true or auto-detected as unbalanced)"),
16
- path: z.string().describe("The path to search in"),
17
- recursive: z
18
- .preprocess((val) => convertNullString(val), z.coerce.boolean().nullable())
19
- .describe("Search recursively. (default: true))"),
20
- ignoreCase: z
21
- .preprocess((val) => convertNullString(val), z.coerce.boolean().nullable())
22
- .describe("Use case-sensitive search. (default: false)"),
23
- filePattern: z
24
- .preprocess((val) => convertNullString(val), z.coerce.string().nullable())
25
- .describe("Glob pattern to filter files (e.g., '*.ts', '**/*.test.js'). (Default: no filtering)"),
26
- contextLines: z
27
- .preprocess((val) => convertNullString(val), z.coerce.number().nullable())
28
- .describe("The number of context lines needed in search results. (Default: 0)"),
29
- searchIgnored: z
30
- .preprocess((val) => convertNullString(val), z.coerce.boolean().nullable())
31
- .describe("Search ignored files. (Default: false)"),
32
- literal: z
33
- .preprocess((val) => convertNullString(val), z.coerce.boolean().nullable())
34
- .describe("Pass true for fixed-string search (-F), false for regex, (Default: auto-detects unbalanced patterns like mismatched parentheses/brackets.)"),
35
- maxResults: z
36
- .preprocess((val) => convertNullString(val), z.coerce.number().nullable())
37
- .describe("Maximum number of matches to return. Set to 0 for no limit. (Default: 100)"),
38
- });
39
- export const createGrepTool = () => {
40
- return {
41
- toolDef: {
42
- description: "Search file contents using ripgrep.",
43
- inputSchema,
44
- },
45
- display({ pattern, path, filePattern, recursive, ignoreCase, contextLines, }) {
46
- // grok doesn't follow my instructions
47
- const safeFilePattern = filePattern === "null" || filePattern === "undefined"
48
- ? null
49
- : filePattern;
50
- // Enhanced tool-init with detailed search parameters
51
- const displayPath = toDisplayPath(path);
52
- let initMessage = `${style.cyan(inspect(pattern))} in ${style.cyan(displayPath)}`;
53
- if (safeFilePattern) {
54
- initMessage += ` ${style.dim(`(filter: ${safeFilePattern})`)}`;
55
- }
56
- if (recursive === false) {
57
- initMessage += ` ${style.dim("(non-recursive)")}`;
58
- }
59
- if (ignoreCase) {
60
- initMessage += ` ${style.dim("(case-insensitive)")}`;
61
- }
62
- if (contextLines && contextLines > 0) {
63
- initMessage += ` ${style.dim(`(with ${contextLines} context line${contextLines === 1 ? "" : "s"})`)}`;
64
- }
65
- return initMessage;
66
- },
67
- async execute({ pattern, path, recursive, ignoreCase, filePattern, contextLines, searchIgnored, literal, maxResults, }, { abortSignal }) {
68
- if (abortSignal?.aborted) {
69
- throw new Error("Grep search aborted");
70
- }
71
- // Validate path - default to cwd if not provided
72
- const effectivePath = typeof path === "string" && path.trim() !== "" ? path : process.cwd();
73
- try {
74
- // Compute likelyUnbalancedRegex once and pass through
75
- const isLikelyUnbalanced = likelyUnbalancedRegex(pattern);
76
- let effectiveLiteral = null;
77
- if (literal === true) {
78
- effectiveLiteral = true;
79
- }
80
- else if (literal === false) {
81
- effectiveLiteral = false;
82
- }
83
- else {
84
- effectiveLiteral = isLikelyUnbalanced;
85
- }
86
- const effectiveMaxResults = maxResults ?? DEFAULT_MAX_RESULTS;
87
- const safeFilePattern = filePattern === "null" || filePattern === "undefined"
88
- ? null
89
- : filePattern;
90
- const grepResult = await grepFilesStructured(pattern, effectivePath, {
91
- recursive,
92
- ignoreCase,
93
- filePattern: safeFilePattern,
94
- contextLines,
95
- searchIgnored,
96
- literal: effectiveLiteral,
97
- maxResults: effectiveMaxResults,
98
- likelyUnbalanced: isLikelyUnbalanced,
99
- }, abortSignal);
100
- return grepResult.rawOutput;
101
- }
102
- catch (error) {
103
- const errorMessage = error.message;
104
- let userFriendlyError = `Error searching for "${pattern}" in ${effectivePath}: ${errorMessage}`;
105
- if (errorMessage.includes("No such file or directory")) {
106
- userFriendlyError = `Path not found: "${effectivePath}"`;
107
- if (filePattern) {
108
- userFriendlyError += ` with file pattern "${filePattern}"`;
109
- }
110
- userFriendlyError += " - check if the path exists and is accessible";
111
- }
112
- else if (errorMessage.includes("permission denied")) {
113
- userFriendlyError = `Permission denied accessing "${effectivePath}"`;
114
- }
115
- else if (errorMessage.includes("Regex parse error")) {
116
- userFriendlyError = `Invalid search pattern "${pattern}" - try using literal=true for fixed-string search`;
117
- }
118
- throw new Error(userFriendlyError);
119
- }
120
- },
121
- };
122
- };
123
- /**
124
- * Skips past a character class [...], handling escaped characters.
125
- * Returns the new index after the character class.
126
- */
127
- function skipCharacterClass(pattern, startIndex) {
128
- let i = startIndex + 1;
129
- while (i < pattern.length && pattern[i] !== "]") {
130
- if (pattern[i] === "\\")
131
- i++;
132
- i++;
133
- }
134
- return i;
135
- }
136
- /**
137
- * Checks if a character is valid inside braces (digits 0-9 or comma).
138
- */
139
- function isValidBraceChar(c) {
140
- return (c >= "0" && c <= "9") || c === ",";
141
- }
142
- /**
143
- * Checks if empty braces have a preceding atom.
144
- * Empty braces with no preceding atom are treated as literal.
145
- */
146
- function hasPrecedingAtom(pattern, startIndex) {
147
- if (startIndex === 0)
148
- return false;
149
- const prev = pattern[startIndex - 1];
150
- return /\S/.test(prev);
151
- }
152
- /**
153
- * Parses and validates the content inside braces {..}.
154
- * Returns true if the brace content is invalid.
155
- */
156
- function isInvalidBraceContent(pattern, startIndex) {
157
- const j = startIndex + 1;
158
- // Find closing brace and check for invalid characters
159
- let hasDigits = false;
160
- let k = j;
161
- while (k < pattern.length && pattern[k] !== "}") {
162
- if (!isValidBraceChar(pattern[k])) {
163
- return true;
164
- }
165
- if (pattern[k] >= "0" && pattern[k] <= "9") {
166
- hasDigits = true;
167
- }
168
- k++;
169
- }
170
- // No closing brace found
171
- if (k >= pattern.length) {
172
- return true;
173
- }
174
- // Empty braces {} with preceding atom are invalid
175
- if (!hasDigits && hasPrecedingAtom(pattern, startIndex)) {
176
- return true;
177
- }
178
- return false;
179
- }
180
- /**
181
- * Check for invalid repetition operators (e.g., {n}, {n,}, {n,m}) outside of character classes.
182
- * Returns true if any invalid repetition operators are found.
183
- */
184
- function hasInvalidRepetition(pattern) {
185
- for (let i = 0; i < pattern.length; i++) {
186
- const ch = pattern[i];
187
- if (ch === "\\") {
188
- i++; // Skip the next character (escaped)
189
- continue;
190
- }
191
- if (ch === "[") {
192
- i = skipCharacterClass(pattern, i);
193
- continue;
194
- }
195
- // Unmatched closing brace is invalid
196
- if (ch === "}") {
197
- return true;
198
- }
199
- // Handle opening brace
200
- if (ch === "{") {
201
- if (isInvalidBraceContent(pattern, i)) {
202
- return true;
203
- }
204
- i = findClosingBrace(pattern, i);
205
- }
206
- }
207
- return false;
208
- }
209
- /**
210
- * Finds the index of the closing brace matching an opening brace.
211
- * Returns the index of the closing brace, or the last index of pattern if not found.
212
- */
213
- function findClosingBrace(pattern, startIndex) {
214
- let j = startIndex + 1;
215
- while (j < pattern.length && pattern[j] !== "}") {
216
- j++;
217
- }
218
- return j;
219
- }
220
- /**
221
- * Count bracket/paren/brace pairs in a regex pattern, excluding character classes.
222
- */
223
- function countBrackets(pattern) {
224
- const counts = {
225
- openParen: 0,
226
- closeParen: 0,
227
- openBracket: 0,
228
- closeBracket: 0,
229
- openBrace: 0,
230
- closeBrace: 0,
231
- };
232
- let escaped = false;
233
- let inCharacterClass = false;
234
- for (let i = 0; i < pattern.length; i++) {
235
- const ch = pattern[i];
236
- if (escaped) {
237
- escaped = false;
238
- continue;
239
- }
240
- if (ch === "\\") {
241
- escaped = true;
242
- continue;
243
- }
244
- // Track character class boundaries
245
- if (ch === "[" && !inCharacterClass) {
246
- inCharacterClass = true;
247
- counts.openBracket++;
248
- continue;
249
- }
250
- if (ch === "]" && inCharacterClass) {
251
- inCharacterClass = false;
252
- counts.closeBracket++;
253
- continue;
254
- }
255
- // Only count brackets/parens/braces outside of character classes
256
- if (!inCharacterClass) {
257
- switch (ch) {
258
- case "(":
259
- counts.openParen++;
260
- break;
261
- case ")":
262
- counts.closeParen++;
263
- break;
264
- case "{":
265
- counts.openBrace++;
266
- break;
267
- case "}":
268
- counts.closeBrace++;
269
- break;
270
- default:
271
- break;
272
- }
273
- }
274
- }
275
- return counts;
276
- }
277
- /**
278
- * Check if a pattern contains regex metacharacters.
279
- * Returns true if the pattern likely needs regex mode.
280
- */
281
- function containsRegexMetacharacters(pattern) {
282
- // Regex metacharacters: ^ $ . * + ? [ ] ( ) { } | \
283
- const metacharacterPattern = /[\^$.*+?[\](){}|\\]/;
284
- return metacharacterPattern.test(pattern);
285
- }
286
- export function likelyUnbalancedRegex(pattern) {
287
- // First check: unbalanced brackets/parentheses/braces = likely a typo, use literal
288
- const counts = countBrackets(pattern);
289
- // Check for unbalanced brackets, parentheses, and braces
290
- const hasUnbalancedBrackets = counts.openBracket !== counts.closeBracket;
291
- const hasUnbalancedParens = counts.openParen !== counts.closeParen;
292
- const hasUnbalancedBraces = counts.openBrace !== counts.closeBrace;
293
- // Also check for invalid repetition operators
294
- const hasInvalidRepetitionFlag = hasInvalidRepetition(pattern);
295
- // If pattern has unbalanced syntax, treat as literal (user probably meant to type literal)
296
- if (hasUnbalancedBrackets ||
297
- hasUnbalancedParens ||
298
- hasUnbalancedBraces ||
299
- hasInvalidRepetitionFlag) {
300
- return true;
301
- }
302
- // Second check: if pattern has regex metacharacters, treat as regex (return false)
303
- // This allows ripgrep to handle the pattern as a proper regex
304
- if (containsRegexMetacharacters(pattern)) {
305
- return false;
306
- }
307
- // Default: simple alphanumeric strings should use literal mode
308
- return true;
309
- }
310
- /**
311
- * Build grep command args array directly
312
- *
313
- * @param pattern - The regex pattern to search for
314
- * @param path - The path to search in
315
- * @param options - Additional options for the grep command
316
- * @returns The args array for the grep command
317
- */
318
- export function buildGrepArgs(pattern, path, options = {}) {
319
- const effectiveRecursive = options.recursive === null ? true : options.recursive;
320
- const effectiveIgnoreCase = options.ignoreCase === null ? false : options.ignoreCase;
321
- const effectiveSearchIgnored = options.searchIgnored === null ? false : options.searchIgnored;
322
- const effectiveFilePattern = options.filePattern;
323
- const effectiveContextLines = options.contextLines;
324
- // Use the pre-computed likelyUnbalanced result if available
325
- let effectiveLiteral;
326
- if (options.literal === true) {
327
- effectiveLiteral = true;
328
- }
329
- else if (options.literal === false) {
330
- effectiveLiteral = false;
331
- }
332
- else if (options.likelyUnbalanced !== undefined) {
333
- effectiveLiteral = options.likelyUnbalanced;
334
- }
335
- else {
336
- effectiveLiteral = likelyUnbalancedRegex(pattern);
337
- }
338
- const args = ["--json"];
339
- if (effectiveRecursive === false) {
340
- args.push("--max-depth=0");
341
- }
342
- if (effectiveIgnoreCase) {
343
- args.push("--ignore-case");
344
- }
345
- if (effectiveContextLines !== null && effectiveContextLines !== undefined) {
346
- args.push(`--context=${effectiveContextLines}`);
347
- }
348
- if (effectiveFilePattern !== null && effectiveFilePattern !== undefined) {
349
- args.push(`--glob=${effectiveFilePattern}`);
350
- }
351
- if (effectiveSearchIgnored) {
352
- args.push("--no-ignore");
353
- }
354
- if (effectiveLiteral) {
355
- args.push("-F");
356
- }
357
- // Use ripgrep's --max-count flag to limit matches per file for efficiency
358
- // This helps prevent any single file from dominating results
359
- if (options.maxResults !== null &&
360
- options.maxResults !== undefined &&
361
- options.maxResults > 0) {
362
- // Use a reasonable per-file limit (max 100 per file) to balance efficiency and completeness
363
- const perFileLimit = Math.min(options.maxResults, 100);
364
- args.push(`--max-count=${perFileLimit}`);
365
- }
366
- args.push(pattern);
367
- args.push(path);
368
- return args;
369
- }
370
- /**
371
- * Parse ripgrep JSON output and extract structured match information
372
- */
373
- export function parseRipgrepJsonOutput(content) {
374
- if (!content || content.trim() === "") {
375
- return [];
376
- }
377
- const parsed = [];
378
- const lines = content.trim().split("\n");
379
- for (const line of lines) {
380
- if (!line.trim()) {
381
- continue;
382
- }
383
- try {
384
- const rgResult = JSON.parse(line);
385
- // Handle different ripgrep message types
386
- if (rgResult.type === "match") {
387
- const data = rgResult.data;
388
- parsed.push({
389
- file: data.path?.text ?? data.path?.bytes?.toString(),
390
- line: data.line_number ?? 0,
391
- content: data.lines?.text ?? data.line ?? "",
392
- isMatch: true,
393
- lineNumber: data.line_number,
394
- absolutePath: data.absolute_path?.text ?? data.absolute_path?.bytes?.toString(),
395
- submatches: data.submatches?.map((sm) => ({
396
- start: sm.start,
397
- end: sm.end,
398
- text: sm.text,
399
- })),
400
- });
401
- }
402
- else if (rgResult.type === "context") {
403
- const data = rgResult.data;
404
- parsed.push({
405
- file: data.path?.text ?? data.path?.bytes?.toString(),
406
- line: data.line_number ?? 0,
407
- content: data.lines?.text ?? data.line ?? "",
408
- isMatch: false,
409
- isContext: true,
410
- lineNumber: data.line_number,
411
- absolutePath: data.absolute_path?.text ?? data.absolute_path?.bytes?.toString(),
412
- });
413
- }
414
- // Ignore other message types like "begin", "end", "summary"
415
- }
416
- catch { }
417
- }
418
- return parsed;
419
- }
420
- /**
421
- * Convert parsed JSON matches back to legacy line-number format for backwards compatibility
422
- */
423
- function matchesToLegacyFormat(matches) {
424
- const lines = [];
425
- for (const match of matches) {
426
- const lineNum = match.lineNumber ?? match.line;
427
- const file = match.file ?? match.absolutePath;
428
- if (file) {
429
- if (match.isMatch) {
430
- lines.push(`${file}:${lineNum}:${match.content}`);
431
- }
432
- else if (match.isContext) {
433
- lines.push(`${file}-${lineNum}-${match.content}`);
434
- }
435
- }
436
- else {
437
- if (match.isMatch) {
438
- lines.push(`${lineNum}:${match.content}`);
439
- }
440
- else if (match.isContext) {
441
- lines.push(`${lineNum}-${match.content}`);
442
- }
443
- }
444
- }
445
- return lines.join("\n");
446
- }
447
- /**
448
- * Count actual matches (excluding context lines)
449
- */
450
- export function countActualMatches(parsed) {
451
- return parsed.filter((match) => match.isMatch && !match.isContext).length;
452
- }
453
- /**
454
- * Count context lines
455
- */
456
- export function countContextLines(parsed) {
457
- return parsed.filter((match) => match.isContext).length;
458
- }
459
- function isContextNearKeptMatch(matches, index, indicesToKeep, contextWindow) {
460
- for (let j = index - 1; j >= Math.max(0, index - contextWindow); j--) {
461
- if (matches[j].isMatch && !matches[j].isContext && indicesToKeep.has(j)) {
462
- return true;
463
- }
464
- }
465
- for (let j = index + 1; j < Math.min(matches.length, index + contextWindow + 1); j++) {
466
- if (matches[j].isMatch && !matches[j].isContext && indicesToKeep.has(j)) {
467
- return true;
468
- }
469
- }
470
- return false;
471
- }
472
- /**
473
- * Truncate matches to a maximum number of results, preserving context lines for kept matches
474
- */
475
- export function truncateMatches(matches, maxResults) {
476
- if (!maxResults || maxResults <= 0) {
477
- return { truncated: matches, isTruncated: false };
478
- }
479
- // Find indices of actual matches (excluding context lines)
480
- const matchIndices = [];
481
- for (let i = 0; i < matches.length; i++) {
482
- if (matches[i].isMatch && !matches[i].isContext) {
483
- matchIndices.push(i);
484
- }
485
- }
486
- if (matchIndices.length <= maxResults) {
487
- return { truncated: matches, isTruncated: false };
488
- }
489
- // Get the indices of matches we want to keep
490
- const indicesToKeep = new Set();
491
- for (let i = 0; i < maxResults; i++) {
492
- indicesToKeep.add(matchIndices[i]);
493
- }
494
- // Build truncated result: include all kept matches AND their associated context lines
495
- const truncated = [];
496
- let matchesKept = 0;
497
- const contextWindow = 3; // Include up to 3 context lines around each match
498
- for (let i = 0; i < matches.length; i++) {
499
- const match = matches[i];
500
- if (match.isMatch && !match.isContext) {
501
- // This is an actual match
502
- if (matchesKept < maxResults) {
503
- truncated.push(match);
504
- matchesKept++;
505
- }
506
- else {
507
- }
508
- }
509
- else if (match.isContext) {
510
- if (isContextNearKeptMatch(matches, i, indicesToKeep, contextWindow)) {
511
- truncated.push(match);
512
- }
513
- }
514
- else {
515
- // Other types, include them
516
- truncated.push(match);
517
- }
518
- }
519
- return {
520
- truncated,
521
- isTruncated: true,
522
- };
523
- }
524
- export async function grepFilesStructured(pattern, path, options = {}, abortSignal) {
525
- try {
526
- const args = buildGrepArgs(pattern, path, options);
527
- // Use execFile for async execution with proper abort signal handling
528
- const rawOutput = await new Promise((resolve, reject) => {
529
- const child = execFile("rg", args, {
530
- encoding: "utf-8",
531
- stdio: ["pipe", "pipe", "pipe"],
532
- });
533
- let stdout = "";
534
- let stderr = "";
535
- child.stdout?.on("data", (data) => {
536
- stdout += data;
537
- });
538
- child.stderr?.on("data", (data) => {
539
- stderr += data;
540
- });
541
- child.on("close", (code) => {
542
- if (code === 0 || code === 1) {
543
- resolve(stdout);
544
- }
545
- else {
546
- reject(new Error(stderr || `ripgrep exited with code ${code}`));
547
- }
548
- });
549
- child.on("error", (err) => {
550
- reject(err);
551
- });
552
- if (abortSignal) {
553
- abortSignal.addEventListener("abort", () => {
554
- child.kill("SIGTERM");
555
- reject(new Error("Grep search aborted"));
556
- });
557
- }
558
- });
559
- // Parse JSON output from ripgrep
560
- const parsedMatches = parseRipgrepJsonOutput(rawOutput);
561
- // If JSON parsing resulted in no matches, check if it's a "no matches" case
562
- // (ripgrep --json returns empty for no matches)
563
- const hasMatches = parsedMatches.length > 0;
564
- const matchCount = countActualMatches(parsedMatches);
565
- // Use the maxResults from options (which will be set by the execute function)
566
- const maxResults = options.maxResults;
567
- const { truncated, isTruncated } = truncateMatches(parsedMatches, maxResults);
568
- const displayedCount = countActualMatches(truncated);
569
- const displayedContextCount = countContextLines(truncated);
570
- // Convert to legacy format for backwards compatibility
571
- const legacyOutput = matchesToLegacyFormat(truncated);
572
- const finalOutput = legacyOutput || "No matches found.";
573
- return {
574
- rawOutput: finalOutput,
575
- parsedMatches: truncated,
576
- matchCount,
577
- displayedCount,
578
- contextCount: displayedContextCount,
579
- hasMatches,
580
- isTruncated,
581
- };
582
- }
583
- catch (error) {
584
- const execError = error;
585
- const exitCode = execError.code;
586
- if (exitCode === "1") {
587
- return {
588
- rawOutput: "No matches found.",
589
- parsedMatches: [],
590
- matchCount: 0,
591
- contextCount: 0,
592
- hasMatches: false,
593
- };
594
- }
595
- if (exitCode === "2") {
596
- const stderrStr = execError.message;
597
- throw new Error(`Regex parse error in pattern "${pattern}": ${stderrStr}`);
598
- }
599
- throw new Error(`Error executing ripgrep: ${execError.message}`);
600
- }
601
- }
@@ -1,26 +0,0 @@
1
- import { z } from "zod";
2
- import type { WorkspaceContext } from "../index.ts";
3
- import type { ToolExecutionOptions } from "./types.ts";
4
- export declare const LsTool: {
5
- name: "LS";
6
- };
7
- declare const inputSchema: z.ZodObject<{
8
- path: z.ZodOptional<z.ZodString>;
9
- limit: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodCoercedNumber<unknown>>>;
10
- }, z.core.$strip>;
11
- type LsInputSchema = z.infer<typeof inputSchema>;
12
- export declare const createLsTool: (options: {
13
- workspace: WorkspaceContext;
14
- }) => Promise<{
15
- toolDef: {
16
- description: string;
17
- inputSchema: z.ZodObject<{
18
- path: z.ZodOptional<z.ZodString>;
19
- limit: z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNullable<z.ZodCoercedNumber<unknown>>>;
20
- }, z.core.$strip>;
21
- };
22
- display({ path: providedPath, limit }: LsInputSchema): string;
23
- execute({ path: providedPath, limit }: LsInputSchema, { abortSignal }: ToolExecutionOptions): Promise<string>;
24
- }>;
25
- export {};
26
- //# sourceMappingURL=ls.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../source/tools/ls.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAMpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,MAAM;;CAElB,CAAC;AAEF,QAAA,MAAM,WAAW;;;iBAQf,CAAC;AAEH,KAAK,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAIjD,eAAO,MAAM,YAAY,GAAU,SAAS;IAC1C,SAAS,EAAE,gBAAgB,CAAC;CAC7B;;;;;;;;2CAU0C,aAAa;2CAOnB,aAAa,mBAC3B,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;EA6DrB,CAAC"}