@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,6 +1,6 @@
1
- import { readFile } from "node:fs/promises";
2
- import { dirname } from "node:path";
1
+ import { readdir, readFile } from "node:fs/promises";
3
2
  import { z } from "zod";
3
+ import { config, parseSkillsPath } from "../config/index.js";
4
4
  import { loadSkills } from "../skills/index.js";
5
5
  import style from "../terminal/style.js";
6
6
  import { replaceArgumentPlaceholders } from "../utils/templates.js";
@@ -13,8 +13,56 @@ const inputSchema = z.object({
13
13
  .describe('The skill name. E.g., "commit", "review-pr", or "pdf"'),
14
14
  args: z.string().optional().describe("Optional arguments for the skill"),
15
15
  });
16
- export async function createSkillTool() {
17
- const skills = await loadSkills();
16
+ /**
17
+ * List resources (files and directories) in a skill directory.
18
+ * Returns relative paths, excluding SKILL.md and hidden files.
19
+ */
20
+ async function listSkillResources(baseDir) {
21
+ try {
22
+ const entries = await readdir(baseDir, { withFileTypes: true });
23
+ const resources = [];
24
+ for (const entry of entries) {
25
+ // Skip SKILL.md (already included in body)
26
+ if (entry.name === "SKILL.md")
27
+ continue;
28
+ // Skip hidden files
29
+ if (entry.name.startsWith("."))
30
+ continue;
31
+ resources.push(entry.name);
32
+ }
33
+ // Sort for consistent output
34
+ resources.sort();
35
+ // Cap at 50 files to avoid overwhelming output
36
+ return resources.slice(0, 50);
37
+ }
38
+ catch {
39
+ // Directory read failed, return empty
40
+ return [];
41
+ }
42
+ }
43
+ /**
44
+ * Build the result string for a skill execution.
45
+ */
46
+ function buildSkillResult(skill, body, resources, args) {
47
+ let result = `# Skill: ${skill.name}\n\n`;
48
+ result += `**Base directory**: ${skill.baseDir}\n\n`;
49
+ if (resources.length > 0) {
50
+ result += "<skill_resources>\n";
51
+ for (const resource of resources) {
52
+ result += `${resource}\n`;
53
+ }
54
+ result += "</skill_resources>\n\n";
55
+ result +=
56
+ "Relative paths in this skill are relative to the base directory.\n\n";
57
+ }
58
+ const argsArray = args ? args.split(/\s+/).filter(Boolean) : [];
59
+ result += replaceArgumentPlaceholders(body, argsArray);
60
+ return result;
61
+ }
62
+ export async function createSkillTool(activatedSkillsTracker) {
63
+ const appConfig = await config.getConfig();
64
+ const skillPaths = parseSkillsPath(appConfig.skills.path);
65
+ const skills = await loadSkills(skillPaths);
18
66
  const modelInvocableSkills = skills.getModelInvocable();
19
67
  const description = "Run a skill (e.g., commit, review-pr).";
20
68
  return {
@@ -30,35 +78,37 @@ export async function createSkillTool() {
30
78
  if (abortSignal?.aborted) {
31
79
  throw new Error("Skill execution aborted");
32
80
  }
81
+ // Check for deduplication
82
+ if (activatedSkillsTracker.has(skillName)) {
83
+ return `Skill "${skillName}" is already loaded in this session. Its instructions are available in the conversation context.`;
84
+ }
33
85
  // Find the skill
34
86
  const skill = modelInvocableSkills.find((s) => s.name === skillName);
35
87
  if (!skill) {
36
88
  const availableSkillNames = modelInvocableSkills
37
89
  .map((s) => s.name)
38
90
  .join(", ");
39
- const errorMsg = `Skill "${skillName}" not found. Available skills: ${availableSkillNames}`;
40
- return errorMsg;
91
+ return `Skill "${skillName}" not found. Available skills: ${availableSkillNames}`;
41
92
  }
42
93
  if (skill.disableModelInvocation) {
43
94
  return `Skill "${skillName}" is not available for model invocation.`;
44
95
  }
45
96
  // Read the skill file
46
97
  const content = await readFile(skill.filePath, "utf8");
47
- let result = `# Skill Name: ${skill.name}`;
48
- result += `\n**Base directory**: ${dirname(skill.filePath)}\n\n`;
49
- result +=
50
- "Relative paths in this skill (e.g., scripts/, reference/) are relative to this base directory.\n";
51
98
  // Parse frontmatter and body
52
99
  const yamlStart = content.indexOf("---");
53
100
  const yamlEnd = content.indexOf("---", yamlStart + 3);
54
101
  const body = yamlEnd !== -1 ? content.slice(yamlEnd + 3).trim() : content;
55
- const argsArray = args ? args.split(/\s+/).filter(Boolean) : [];
56
- result += replaceArgumentPlaceholders(body, argsArray);
102
+ // List resources in skill directory
103
+ const resources = await listSkillResources(skill.baseDir);
104
+ // Build result
105
+ const result = buildSkillResult(skill, body, resources, args);
106
+ // Mark as activated
107
+ activatedSkillsTracker.add(skillName);
57
108
  return result;
58
109
  }
59
110
  catch (error) {
60
- const errorMsg = `${error.message}`;
61
- return errorMsg;
111
+ return error.message;
62
112
  }
63
113
  },
64
114
  };
@@ -1,20 +1,26 @@
1
1
  import { z } from "zod";
2
2
  export declare const fileEncodingSchema: z.ZodEnum<{
3
+ base64: "base64";
4
+ base64url: "base64url";
3
5
  utf8: "utf8";
4
6
  ascii: "ascii";
5
7
  "utf-8": "utf-8";
6
8
  utf16le: "utf16le";
7
9
  ucs2: "ucs2";
8
10
  "ucs-2": "ucs-2";
9
- base64: "base64";
10
- base64url: "base64url";
11
11
  latin1: "latin1";
12
12
  binary: "binary";
13
13
  hex: "hex";
14
14
  }>;
15
+ export type SessionContext = {
16
+ sessionId: string;
17
+ projectDir: string;
18
+ agentName: string;
19
+ };
15
20
  export type ToolExecutionOptions = {
16
21
  toolCallId: string;
17
22
  messages?: any[];
18
23
  abortSignal?: AbortSignal;
24
+ sessionContext?: SessionContext;
19
25
  };
20
26
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;EAY7B,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG;IACjC,UAAU,EAAE,MAAM,CAAC;IAEnB,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../source/tools/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;EAY7B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,UAAU,EAAE,MAAM,CAAC;IAEnB,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC,CAAC"}
@@ -11,18 +11,14 @@ declare const inputSchema: z.ZodObject<{
11
11
  output: z.ZodDefault<z.ZodEnum<{
12
12
  markdown: "markdown";
13
13
  text: "text";
14
- html: "html";
15
14
  json: "json";
15
+ html: "html";
16
16
  }>>;
17
- jina: z.ZodOptional<z.ZodPipe<z.ZodTransform<string | null, unknown>, z.ZodNullable<z.ZodCoercedBoolean<unknown>>>>;
18
- timeout: z.ZodOptional<z.ZodPipe<z.ZodTransform<string | null, unknown>, z.ZodNullable<z.ZodCoercedNumber<unknown>>>>;
19
- headers: z.ZodOptional<z.ZodPipe<z.ZodTransform<string | null, unknown>, z.ZodNullable<z.ZodCoercedBoolean<unknown>>>>;
17
+ jina: z.ZodOptional<z.ZodPreprocess<z.ZodNullable<z.ZodCoercedBoolean<unknown>>>>;
18
+ timeout: z.ZodOptional<z.ZodPreprocess<z.ZodNullable<z.ZodCoercedNumber<unknown>>>>;
19
+ headers: z.ZodOptional<z.ZodPreprocess<z.ZodNullable<z.ZodCoercedBoolean<unknown>>>>;
20
20
  }, z.core.$strip>;
21
21
  type WebFetchInputSchema = z.infer<typeof inputSchema>;
22
- /**
23
- * Execute web fetch
24
- */
25
- export declare function executeWebFetch(options: WebFetchInputSchema, executionOptions: ToolExecutionOptions): Promise<string>;
26
22
  /**
27
23
  * Create the web fetch tool
28
24
  */
@@ -34,12 +30,12 @@ export declare const createWebFetchTool: () => Promise<{
34
30
  output: z.ZodDefault<z.ZodEnum<{
35
31
  markdown: "markdown";
36
32
  text: "text";
37
- html: "html";
38
33
  json: "json";
34
+ html: "html";
39
35
  }>>;
40
- jina: z.ZodOptional<z.ZodPipe<z.ZodTransform<string | null, unknown>, z.ZodNullable<z.ZodCoercedBoolean<unknown>>>>;
41
- timeout: z.ZodOptional<z.ZodPipe<z.ZodTransform<string | null, unknown>, z.ZodNullable<z.ZodCoercedNumber<unknown>>>>;
42
- headers: z.ZodOptional<z.ZodPipe<z.ZodTransform<string | null, unknown>, z.ZodNullable<z.ZodCoercedBoolean<unknown>>>>;
36
+ jina: z.ZodOptional<z.ZodPreprocess<z.ZodNullable<z.ZodCoercedBoolean<unknown>>>>;
37
+ timeout: z.ZodOptional<z.ZodPreprocess<z.ZodNullable<z.ZodCoercedNumber<unknown>>>>;
38
+ headers: z.ZodOptional<z.ZodPreprocess<z.ZodNullable<z.ZodCoercedBoolean<unknown>>>>;
43
39
  }, z.core.$strip>;
44
40
  };
45
41
  display({ url }: WebFetchInputSchema): string;
@@ -1 +1 @@
1
- {"version":3,"file":"web-fetch.d.ts","sourceRoot":"","sources":["../../source/tools/web-fetch.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,YAAY;;CAExB,CAAC;AAQF;;GAEG;AACH,QAAA,MAAM,WAAW;;;;;;;;;;;iBAkBf,CAAC;AAEH,KAAK,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AA6bvD;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,mBAAmB,EAC5B,gBAAgB,EAAE,oBAAoB,GACrC,OAAO,CAAC,MAAM,CAAC,CAiEjB;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;qBAQV,mBAAmB;qBAIzB,mBAAmB,oBACV,oBAAoB,GACrC,OAAO,CAAC,MAAM,CAAC;EAIrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"web-fetch.d.ts","sourceRoot":"","sources":["../../source/tools/web-fetch.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,YAAY;;CAExB,CAAC;AASF;;GAEG;AACH,QAAA,MAAM,WAAW;;;;;;;;;;;iBAkBf,CAAC;AAEH,KAAK,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AA+jBvD;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;qBAQV,mBAAmB;qBAIzB,mBAAmB,oBACV,oBAAoB,GACrC,OAAO,CAAC,MAAM,CAAC;EAIrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC,CAAC"}
@@ -1,3 +1,6 @@
1
+ import { writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
1
4
  import { load } from "cheerio";
2
5
  import { z } from "zod";
3
6
  import style from "../terminal/style.js";
@@ -9,6 +12,7 @@ const DEFAULT_TIMEOUT = 30000; // 30 seconds
9
12
  const MAX_REDIRECTS = 5;
10
13
  const MAX_URL_LENGTH = 2048;
11
14
  const JINA_API_BASE = "https://r.jina.ai";
15
+ const MAX_INLINE_SIZE = 50_000; // bytes; content exceeding this is written to a temp file
12
16
  /**
13
17
  * Input schema for the web fetch tool
14
18
  */
@@ -297,6 +301,51 @@ async function handleTextResponse(response, contentType) {
297
301
  provider: "direct",
298
302
  };
299
303
  }
304
+ /**
305
+ * If the response is a redirect (3xx with a Location header), return the
306
+ * resolved redirect target URL. Otherwise returns null.
307
+ */
308
+ function getRedirectUrl(response, currentUrl) {
309
+ if (response.status < 300 || response.status >= 400) {
310
+ return null;
311
+ }
312
+ const location = response.headers.get("location");
313
+ if (!location) {
314
+ return null;
315
+ }
316
+ return new URL(location, currentUrl).toString();
317
+ }
318
+ /**
319
+ * Process a non-redirect fetch response: validate status, determine content
320
+ * type, and delegate to the appropriate handler.
321
+ */
322
+ async function processNonRedirectResponse(response, options) {
323
+ const { useJina, includeHeaders, signal, verbose } = options;
324
+ if (!response.ok) {
325
+ throw new Error(`HTTP error! status: ${response.status} ${response.statusText}`);
326
+ }
327
+ const contentType = getContentType(response);
328
+ const responseHeaders = {};
329
+ if (includeHeaders) {
330
+ response.headers.forEach((value, key) => {
331
+ responseHeaders[key] = value;
332
+ });
333
+ }
334
+ let result;
335
+ if (contentType.includes("text/html")) {
336
+ result = await handleHtmlResponse(response, useJina, signal, verbose);
337
+ }
338
+ else if (contentType.startsWith("image/")) {
339
+ result = await handleImageResponse(response, contentType);
340
+ }
341
+ else {
342
+ result = await handleTextResponse(response, contentType);
343
+ }
344
+ if (includeHeaders) {
345
+ result.headers = responseHeaders;
346
+ }
347
+ return result;
348
+ }
300
349
  /**
301
350
  * Main fetch function with redirect handling
302
351
  */
@@ -328,43 +377,21 @@ async function fetchUrl(url, options) {
328
377
  redirect: "manual",
329
378
  headers: requestHeaders,
330
379
  });
331
- // Handle redirects
332
- if (response.status >= 300 && response.status < 400) {
333
- const location = response.headers.get("location");
334
- if (location) {
335
- const redirectUrl = new URL(location, currentUrl).toString();
336
- if (verbose) {
337
- console.error(`Redirecting to: ${redirectUrl}`);
338
- }
339
- currentUrl = redirectUrl;
340
- redirectCount++;
341
- continue;
380
+ const redirectUrl = getRedirectUrl(response, currentUrl);
381
+ if (redirectUrl) {
382
+ if (verbose) {
383
+ console.error(`Redirecting to: ${redirectUrl}`);
342
384
  }
385
+ currentUrl = redirectUrl;
386
+ redirectCount++;
387
+ continue;
343
388
  }
344
- if (!response.ok) {
345
- throw new Error(`HTTP error! status: ${response.status} ${response.statusText}`);
346
- }
347
- const contentType = getContentType(response);
348
- const responseHeaders = {};
349
- if (includeHeaders) {
350
- response.headers.forEach((value, key) => {
351
- responseHeaders[key] = value;
352
- });
353
- }
354
- let result;
355
- if (contentType.includes("text/html")) {
356
- result = await handleHtmlResponse(response, useJina, signal, verbose);
357
- }
358
- else if (contentType.startsWith("image/")) {
359
- result = await handleImageResponse(response, contentType);
360
- }
361
- else {
362
- result = await handleTextResponse(response, contentType);
363
- }
364
- if (includeHeaders) {
365
- result.headers = responseHeaders;
366
- }
367
- return result;
389
+ return await processNonRedirectResponse(response, {
390
+ useJina,
391
+ includeHeaders,
392
+ signal,
393
+ verbose,
394
+ });
368
395
  }
369
396
  finally {
370
397
  cleanup();
@@ -375,7 +402,7 @@ async function fetchUrl(url, options) {
375
402
  /**
376
403
  * Execute web fetch
377
404
  */
378
- export async function executeWebFetch(options, executionOptions) {
405
+ async function executeWebFetch(options, executionOptions) {
379
406
  const { url, output = "text", jina = false, timeout, headers = false, } = options;
380
407
  if (executionOptions.abortSignal?.aborted) {
381
408
  throw new Error("Web fetch aborted");
@@ -400,6 +427,7 @@ export async function executeWebFetch(options, executionOptions) {
400
427
  const errorMessage = error instanceof Error ? error.message : String(error);
401
428
  throw new Error(`Web fetch failed: ${errorMessage}`);
402
429
  }
430
+ let content;
403
431
  switch (output) {
404
432
  case "json": {
405
433
  const jsonOutput = {
@@ -413,18 +441,32 @@ export async function executeWebFetch(options, executionOptions) {
413
441
  if (headers && result.headers) {
414
442
  jsonOutput["headers"] = result["headers"];
415
443
  }
416
- return JSON.stringify(jsonOutput, null, 2);
444
+ content = JSON.stringify(jsonOutput, null, 2);
445
+ break;
417
446
  }
418
447
  case "html":
419
- return result.content;
448
+ content = result.content;
449
+ break;
420
450
  case "markdown":
421
- if (result.contentType.includes("text/html")) {
422
- return htmlToMarkdown(result.content);
423
- }
424
- return result.content;
451
+ content = result.contentType.includes("text/html")
452
+ ? htmlToMarkdown(result.content)
453
+ : result.content;
454
+ break;
425
455
  default:
426
- return result.content;
456
+ content = result.content;
457
+ break;
458
+ }
459
+ const contentSize = Buffer.byteLength(content, "utf-8");
460
+ if (contentSize > MAX_INLINE_SIZE) {
461
+ const tmpFile = join(tmpdir(), `acai-webfetch-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.txt`);
462
+ writeFileSync(tmpFile, content, "utf-8");
463
+ return [
464
+ `The fetched content from ${url} is ${contentSize} bytes which exceeds the ${MAX_INLINE_SIZE} byte inline limit.`,
465
+ `The full content has been saved to: ${tmpFile}`,
466
+ "To use this content, read the file in parts using the Read tool or search it with the Grep tool.",
467
+ ].join("\n");
427
468
  }
469
+ return content;
428
470
  }
429
471
  /**
430
472
  * Create the web fetch tool
@@ -437,7 +479,7 @@ export const createWebFetchTool = async () => {
437
479
  inputSchema,
438
480
  },
439
481
  display({ url }) {
440
- return `🌐 ${style.cyan(url)}`;
482
+ return `${style.cyan(url)}`;
441
483
  },
442
484
  async execute(options, executionOptions) {
443
485
  return executeWebFetch(options, executionOptions);
@@ -8,18 +8,14 @@ export declare const WebSearchTool: {
8
8
  */
9
9
  declare const inputSchema: z.ZodObject<{
10
10
  query: z.ZodString;
11
- numResults: z.ZodOptional<z.ZodPipe<z.ZodTransform<string | null, unknown>, z.ZodNullable<z.ZodCoercedNumber<unknown>>>>;
12
- timeout: z.ZodOptional<z.ZodPipe<z.ZodTransform<string | null, unknown>, z.ZodNullable<z.ZodCoercedNumber<unknown>>>>;
11
+ numResults: z.ZodOptional<z.ZodPreprocess<z.ZodNullable<z.ZodCoercedNumber<unknown>>>>;
12
+ timeout: z.ZodOptional<z.ZodPreprocess<z.ZodNullable<z.ZodCoercedNumber<unknown>>>>;
13
13
  provider: z.ZodOptional<z.ZodEnum<{
14
14
  exa: "exa";
15
15
  duckduckgo: "duckduckgo";
16
16
  }>>;
17
17
  }, z.core.$strip>;
18
18
  type WebSearchInputSchema = z.infer<typeof inputSchema>;
19
- /**
20
- * Execute web search
21
- */
22
- export declare function executeWebSearch(options: WebSearchInputSchema, executionOptions: ToolExecutionOptions): Promise<string>;
23
19
  /**
24
20
  * Create the web search tool
25
21
  */
@@ -28,8 +24,8 @@ export declare const createWebSearchTool: () => Promise<{
28
24
  description: string;
29
25
  inputSchema: z.ZodObject<{
30
26
  query: z.ZodString;
31
- numResults: z.ZodOptional<z.ZodPipe<z.ZodTransform<string | null, unknown>, z.ZodNullable<z.ZodCoercedNumber<unknown>>>>;
32
- timeout: z.ZodOptional<z.ZodPipe<z.ZodTransform<string | null, unknown>, z.ZodNullable<z.ZodCoercedNumber<unknown>>>>;
27
+ numResults: z.ZodOptional<z.ZodPreprocess<z.ZodNullable<z.ZodCoercedNumber<unknown>>>>;
28
+ timeout: z.ZodOptional<z.ZodPreprocess<z.ZodNullable<z.ZodCoercedNumber<unknown>>>>;
33
29
  provider: z.ZodOptional<z.ZodEnum<{
34
30
  exa: "exa";
35
31
  duckduckgo: "duckduckgo";
@@ -1 +1 @@
1
- {"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../source/tools/web-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,aAAa;;CAEzB,CAAC;AAQF;;GAEG;AACH,QAAA,MAAM,WAAW;;;;;;;;iBAkBf,CAAC;AAEH,KAAK,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AA+MxD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,oBAAoB,EAC7B,gBAAgB,EAAE,oBAAoB,GACrC,OAAO,CAAC,MAAM,CAAC,CAwEjB;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;uBAQT,oBAAoB;qBAI5B,oBAAoB,oBACX,oBAAoB,GACrC,OAAO,CAAC,MAAM,CAAC;EAIrB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"web-search.d.ts","sourceRoot":"","sources":["../../source/tools/web-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,aAAa;;CAEzB,CAAC;AAQF;;GAEG;AACH,QAAA,MAAM,WAAW;;;;;;;;iBAkBf,CAAC;AAEH,KAAK,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AA6SxD;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;uBAQT,oBAAoB;qBAI5B,oBAAoB,oBACX,oBAAoB,GACrC,OAAO,CAAC,MAAM,CAAC;EAIrB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC"}
@@ -151,10 +151,45 @@ async function fetchDuckDuckGo(query, numResults, signal) {
151
151
  totalResults: data.RelatedTopics.length,
152
152
  };
153
153
  }
154
+ /**
155
+ * Attempt Exa search with automatic fallback to DuckDuckGo
156
+ */
157
+ async function fetchExaWithFallback(query, numResults, signal) {
158
+ try {
159
+ return await fetchExa(query, numResults, signal);
160
+ }
161
+ catch (error) {
162
+ // If aborted, re-throw the original error
163
+ if (signal.aborted) {
164
+ throw error;
165
+ }
166
+ // Provide more helpful error message about network failures
167
+ const errorMessage = error instanceof Error ? error.message : String(error);
168
+ if (errorMessage.includes("fetch failed") ||
169
+ errorMessage.includes("ENOTFOUND") ||
170
+ errorMessage.includes("connect")) {
171
+ throw new Error(`Exa API is not accessible (network error). Try using provider="duckduckgo" instead.`);
172
+ }
173
+ // For non-network errors (auth, rate limit, etc.), fall back to DuckDuckGo
174
+ return await fetchDuckDuckGo(query, numResults, signal);
175
+ }
176
+ }
177
+ /**
178
+ * Format search response into a human-readable string
179
+ */
180
+ function formatSearchResults(query, response) {
181
+ if (response.results.length === 0) {
182
+ return `No search results found for "${query}".`;
183
+ }
184
+ const resultsText = response.results
185
+ .map((result, index) => `${index + 1}. [${result.title}](${result.url})\n ${result.snippet.substring(0, 200)}${result.snippet.length > 200 ? "..." : ""}`)
186
+ .join("\n\n");
187
+ return `Search results for "${query}" (${response.provider}):\n\n${resultsText}\n\nTotal results: ${response.totalResults || response.results.length}`;
188
+ }
154
189
  /**
155
190
  * Execute web search
156
191
  */
157
- export async function executeWebSearch(options, executionOptions) {
192
+ async function executeWebSearch(options, executionOptions) {
158
193
  const { query, numResults = DEFAULT_NUM_RESULTS, timeout = DEFAULT_TIMEOUT, provider = "exa", } = options;
159
194
  if (executionOptions.abortSignal?.aborted) {
160
195
  throw new Error("Web search aborted");
@@ -166,37 +201,10 @@ export async function executeWebSearch(options, executionOptions) {
166
201
  const effectiveTimeout = Math.min(Math.max(timeout ?? 1000, 1000), 60000);
167
202
  const { signal, cleanup } = createTimeoutSignal(effectiveTimeout, executionOptions.abortSignal);
168
203
  try {
169
- let response;
170
- if (provider === "duckduckgo") {
171
- response = await fetchDuckDuckGo(query, effectiveNumResults, signal);
172
- }
173
- else {
174
- // Try Exa first, fall back to DuckDuckGo
175
- try {
176
- response = await fetchExa(query, effectiveNumResults, signal);
177
- }
178
- catch (exaError) {
179
- // Fall back to DuckDuckGo if Exa fails (but not if aborted)
180
- if (signal.aborted) {
181
- throw exaError;
182
- }
183
- // Provide more helpful error message about Exa failure
184
- const errorMsg = exaError instanceof Error ? exaError.message : String(exaError);
185
- if (errorMsg.includes("fetch failed") ||
186
- errorMsg.includes("ENOTFOUND") ||
187
- errorMsg.includes("connect")) {
188
- throw new Error(`Exa API is not accessible (network error). Try using provider="duckduckgo" instead.`);
189
- }
190
- response = await fetchDuckDuckGo(query, effectiveNumResults, signal);
191
- }
192
- }
193
- if (response.results.length === 0) {
194
- return `No search results found for "${query}".`;
195
- }
196
- const resultsText = response.results
197
- .map((result, index) => `${index + 1}. [${result.title}](${result.url})\n ${result.snippet.substring(0, 200)}${result.snippet.length > 200 ? "..." : ""}`)
198
- .join("\n\n");
199
- return `Search results for "${query}" (${response.provider}):\n\n${resultsText}\n\nTotal results: ${response.totalResults || response.results.length}`;
204
+ const response = provider === "duckduckgo"
205
+ ? await fetchDuckDuckGo(query, effectiveNumResults, signal)
206
+ : await fetchExaWithFallback(query, effectiveNumResults, signal);
207
+ return formatSearchResults(query, response);
200
208
  }
201
209
  catch (error) {
202
210
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -217,7 +225,7 @@ export const createWebSearchTool = async () => {
217
225
  inputSchema,
218
226
  },
219
227
  display({ query }) {
220
- return `🔍 ${style.cyan(query)}`;
228
+ return `${style.cyan(query)}`;
221
229
  },
222
230
  async execute(options, executionOptions) {
223
231
  return executeWebSearch(options, executionOptions);
@@ -1,17 +1,2 @@
1
- import type { Dirent } from "node:fs";
2
- export declare class DirectoryCache {
3
- private cache;
4
- private ttl;
5
- get(dir: string): Promise<Dirent[] | null>;
6
- set(dir: string, entries: Dirent[]): void;
7
- clear(): void;
8
- }
9
- export declare const directoryCache: DirectoryCache;
10
- interface DirentWithPath extends Dirent {
11
- parentPath: string;
12
- }
13
- export declare function getDirectoryEntries(dirs: string[]): Promise<DirentWithPath[]>;
14
- export declare function isPathWithinAllowedDirs(requestedPath: string, allowedDirs: string[]): Promise<boolean>;
15
1
  export declare function extractPathPrefix(text: string, forceExtract?: boolean): string | null;
16
- export {};
17
2
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../source/tui/autocomplete/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAKtC,qBAAa,cAAc;IACzB,OAAO,CAAC,KAAK,CAA+D;IAC5E,OAAO,CAAC,GAAG,CAAQ;IAEb,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;IAQhD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAIzC,KAAK,IAAI,IAAI;CAGd;AAED,eAAO,MAAM,cAAc,gBAAuB,CAAC;AAGnD,UAAU,cAAe,SAAQ,MAAM;IACrC,UAAU,EAAE,MAAM,CAAC;CACpB;AAGD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,cAAc,EAAE,CAAC,CA4B3B;AA8BD,wBAAsB,uBAAuB,CAC3C,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EAAE,GACpB,OAAO,CAAC,OAAO,CAAC,CAWlB;AAmCD,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,YAAY,UAAQ,GACnB,MAAM,GAAG,IAAI,CAuCf"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../source/tui/autocomplete/utils.ts"],"names":[],"mappings":"AAiCA,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,YAAY,UAAQ,GACnB,MAAM,GAAG,IAAI,CAuCf"}
@@ -1,88 +1,3 @@
1
- import { readdir, realpath } from "node:fs/promises";
2
- import { isAbsolute, relative, resolve } from "node:path";
3
- // Cache for directory listings to improve performance
4
- export class DirectoryCache {
5
- cache = new Map();
6
- ttl = 3000; // 3 seconds
7
- async get(dir) {
8
- const cached = this.cache.get(dir);
9
- if (cached && Date.now() - cached.timestamp < this.ttl) {
10
- return cached.entries;
11
- }
12
- return null;
13
- }
14
- set(dir, entries) {
15
- this.cache.set(dir, { entries, timestamp: Date.now() });
16
- }
17
- clear() {
18
- this.cache.clear();
19
- }
20
- }
21
- export const directoryCache = new DirectoryCache();
22
- // Helper function to get directory entries with caching and timeout
23
- export async function getDirectoryEntries(dirs) {
24
- const results = [];
25
- for (const dir of dirs) {
26
- const cached = await directoryCache.get(dir);
27
- if (cached) {
28
- for (const entry of cached) {
29
- results.push(Object.assign(entry, { parentPath: dir }));
30
- }
31
- continue;
32
- }
33
- try {
34
- // Add timeout to prevent hanging on slow file systems
35
- const entries = await Promise.race([
36
- readdir(dir, { withFileTypes: true }),
37
- new Promise((_, reject) => setTimeout(() => reject(new Error("Directory read timeout")), 2000)),
38
- ]);
39
- directoryCache.set(dir, entries);
40
- for (const entry of entries) {
41
- results.push(Object.assign(entry, { parentPath: dir }));
42
- }
43
- }
44
- catch (_e) {
45
- // ignore
46
- }
47
- }
48
- return results;
49
- }
50
- // Cache for resolved allowed directories to avoid repeated realpath calls
51
- const resolvedAllowedDirsCache = new Map();
52
- async function getResolvedPath(path) {
53
- const cached = resolvedAllowedDirsCache.get(path);
54
- if (cached !== undefined) {
55
- return cached;
56
- }
57
- const absPath = resolve(path);
58
- let resolved = absPath;
59
- try {
60
- resolved = await realpath(absPath);
61
- }
62
- catch {
63
- // If path doesn't exist, use the resolved absolute path
64
- }
65
- // Cache with a size limit
66
- if (resolvedAllowedDirsCache.size > 500) {
67
- const firstKey = resolvedAllowedDirsCache.keys().next().value;
68
- if (firstKey !== undefined) {
69
- resolvedAllowedDirsCache.delete(firstKey);
70
- }
71
- }
72
- resolvedAllowedDirsCache.set(path, resolved);
73
- return resolved;
74
- }
75
- export async function isPathWithinAllowedDirs(requestedPath, allowedDirs) {
76
- const target = await getResolvedPath(requestedPath);
77
- for (const allowedDir of allowedDirs) {
78
- const absAllowed = await getResolvedPath(allowedDir);
79
- const rel = relative(absAllowed, target);
80
- if (rel === "" || (!rel.startsWith("..") && !isAbsolute(rel))) {
81
- return true;
82
- }
83
- }
84
- return false;
85
- }
86
1
  function hasPathIndicator(pathPrefix) {
87
2
  return (pathPrefix.includes("/") ||
88
3
  pathPrefix.endsWith("/") ||
@@ -8,6 +8,6 @@ export type { SlashCommand } from "./autocomplete/command-provider.ts";
8
8
  export { CommandProvider } from "./autocomplete/command-provider.ts";
9
9
  export { FileSearchProvider } from "./autocomplete/file-search-provider.ts";
10
10
  export { SkillProvider } from "./autocomplete/skill-provider.ts";
11
- export { DirectoryCache, directoryCache, extractPathPrefix, getDirectoryEntries, isPathWithinAllowedDirs, } from "./autocomplete/utils.ts";
11
+ export { extractPathPrefix } from "./autocomplete/utils.ts";
12
12
  export declare function createDefaultProvider<T extends SlashCommand | AutocompleteItem>(commands?: T[], _allowedDirs?: string[]): CombinedProvider;
13
13
  //# sourceMappingURL=autocomplete.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"autocomplete.d.ts","sourceRoot":"","sources":["../../source/tui/autocomplete.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,YAAY,EACV,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AACvE,YAAY,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EACL,cAAc,EACd,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,yBAAyB,CAAC;AAGjC,wBAAgB,qBAAqB,CACnC,CAAC,SAAS,YAAY,GAAG,gBAAgB,EACzC,QAAQ,GAAE,CAAC,EAAO,EAAE,YAAY,GAAE,MAAM,EAAoB,oBAM7D"}
1
+ {"version":3,"file":"autocomplete.d.ts","sourceRoot":"","sources":["../../source/tui/autocomplete.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,EAEL,KAAK,YAAY,EAClB,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,YAAY,EACV,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AACvE,YAAY,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAG5D,wBAAgB,qBAAqB,CACnC,CAAC,SAAS,YAAY,GAAG,gBAAgB,EACzC,QAAQ,GAAE,CAAC,EAAO,EAAE,YAAY,GAAE,MAAM,EAAoB,oBAM7D"}