@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.
- package/README.md +5 -5
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +2 -5
- package/dist/commands/history/types.d.ts +3 -2
- package/dist/commands/history/types.d.ts.map +1 -1
- package/dist/commands/init-project/utils.d.ts +0 -1
- package/dist/commands/init-project/utils.d.ts.map +1 -1
- package/dist/commands/init-project/utils.js +1 -12
- package/dist/commands/manager.d.ts.map +1 -1
- package/dist/commands/manager.js +6 -19
- package/dist/commands/resources/index.d.ts.map +1 -1
- package/dist/commands/resources/index.js +4 -1
- package/dist/commands/session/index.d.ts.map +1 -1
- package/dist/commands/session/index.js +6 -0
- package/dist/commands/session/types.d.ts +1 -0
- package/dist/commands/session/types.d.ts.map +1 -1
- package/dist/commands/share/html-renderer.d.ts.map +1 -1
- package/dist/commands/share/html-renderer.js +54 -48
- package/dist/commands/tools/index.d.ts +3 -0
- package/dist/commands/tools/index.d.ts.map +1 -0
- package/dist/commands/tools/index.js +191 -0
- package/dist/commands/tools/templates.d.ts +6 -0
- package/dist/commands/tools/templates.d.ts.map +1 -0
- package/dist/commands/tools/templates.js +97 -0
- package/dist/config/index.d.ts +5 -2
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +42 -6
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +98 -68
- package/dist/models/anthropic-provider.d.ts +1 -1
- package/dist/models/deepseek-provider.d.ts +3 -3
- package/dist/models/deepseek-provider.js +17 -17
- package/dist/models/google-provider.d.ts +2 -4
- package/dist/models/google-provider.d.ts.map +1 -1
- package/dist/models/google-provider.js +2 -17
- package/dist/models/groq-provider.d.ts +2 -4
- package/dist/models/groq-provider.d.ts.map +1 -1
- package/dist/models/groq-provider.js +3 -21
- package/dist/models/manager.d.ts +1 -10
- package/dist/models/manager.d.ts.map +1 -1
- package/dist/models/manager.js +2 -2
- package/dist/models/opencode-go-provider.d.ts +11 -1
- package/dist/models/opencode-go-provider.d.ts.map +1 -1
- package/dist/models/opencode-go-provider.js +130 -0
- package/dist/models/opencode-zen-provider.d.ts +3 -3
- package/dist/models/opencode-zen-provider.d.ts.map +1 -1
- package/dist/models/opencode-zen-provider.js +26 -32
- package/dist/models/openrouter-provider.d.ts +4 -15
- package/dist/models/openrouter-provider.d.ts.map +1 -1
- package/dist/models/openrouter-provider.js +26 -169
- package/dist/models/providers.d.ts +1 -1
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/models/xai-provider.d.ts +1 -2
- package/dist/models/xai-provider.d.ts.map +1 -1
- package/dist/models/xai-provider.js +0 -13
- package/dist/prompts/manager.d.ts.map +1 -1
- package/dist/prompts/manager.js +5 -1
- package/dist/prompts/system-prompt.d.ts +1 -2
- package/dist/prompts/system-prompt.d.ts.map +1 -1
- package/dist/prompts/system-prompt.js +26 -15
- package/dist/repl/index.d.ts +28 -13
- package/dist/repl/index.d.ts.map +1 -1
- package/dist/repl/index.js +242 -305
- package/dist/skills/activated-tracker.d.ts +11 -0
- package/dist/skills/activated-tracker.d.ts.map +1 -0
- package/dist/skills/activated-tracker.js +16 -0
- package/dist/skills/index.d.ts +12 -2
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +127 -71
- package/dist/terminal/control.d.ts +1 -21
- package/dist/terminal/control.d.ts.map +1 -1
- package/dist/terminal/control.js +1 -32
- package/dist/terminal/formatting.d.ts +0 -33
- package/dist/terminal/formatting.d.ts.map +1 -1
- package/dist/terminal/formatting.js +0 -91
- package/dist/terminal/highlight/theme.d.ts +0 -37
- package/dist/terminal/highlight/theme.d.ts.map +1 -1
- package/dist/terminal/highlight/theme.js +1 -79
- package/dist/terminal/keys.d.ts +0 -97
- package/dist/terminal/keys.d.ts.map +1 -1
- package/dist/terminal/keys.js +0 -194
- package/dist/terminal/select-prompt.d.ts.map +1 -1
- package/dist/terminal/select-prompt.js +65 -51
- package/dist/terminal/style.d.ts +1 -1
- package/dist/terminal/style.d.ts.map +1 -1
- package/dist/terminal/supports-color.d.ts.map +1 -1
- package/dist/terminal/supports-color.js +38 -20
- package/dist/terminal/supports-hyperlinks.d.ts +3 -0
- package/dist/terminal/supports-hyperlinks.d.ts.map +1 -1
- package/dist/terminal/supports-hyperlinks.js +72 -31
- package/dist/terminal/table/layout-manager.d.ts +0 -20
- package/dist/terminal/table/layout-manager.d.ts.map +1 -1
- package/dist/terminal/table/layout-manager.js +68 -44
- package/dist/terminal/table/utils.d.ts +0 -1
- package/dist/terminal/table/utils.d.ts.map +1 -1
- package/dist/terminal/table/utils.js +2 -4
- package/dist/tools/apply-patch.d.ts +5 -3
- package/dist/tools/apply-patch.d.ts.map +1 -1
- package/dist/tools/apply-patch.js +154 -123
- package/dist/tools/bash.d.ts +4 -4
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +27 -13
- package/dist/tools/dynamic-tool-loader.d.ts +17 -3
- package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-loader.js +360 -81
- package/dist/tools/edit-file.d.ts +2 -2
- package/dist/tools/index.d.ts +27 -151
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +16 -21
- package/dist/tools/read-file.d.ts +8 -8
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +32 -13
- package/dist/tools/save-file.d.ts +4 -4
- package/dist/tools/skill.d.ts +2 -1
- package/dist/tools/skill.d.ts.map +1 -1
- package/dist/tools/skill.js +64 -14
- package/dist/tools/types.d.ts +8 -2
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/web-fetch.d.ts +8 -12
- package/dist/tools/web-fetch.d.ts.map +1 -1
- package/dist/tools/web-fetch.js +86 -44
- package/dist/tools/web-search.d.ts +4 -8
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +41 -33
- package/dist/tui/autocomplete/utils.d.ts +0 -15
- package/dist/tui/autocomplete/utils.d.ts.map +1 -1
- package/dist/tui/autocomplete/utils.js +0 -85
- package/dist/tui/autocomplete.d.ts +1 -1
- package/dist/tui/autocomplete.d.ts.map +1 -1
- package/dist/tui/autocomplete.js +1 -1
- package/dist/tui/components/editor.d.ts +12 -0
- package/dist/tui/components/editor.d.ts.map +1 -1
- package/dist/tui/components/editor.js +181 -195
- package/dist/tui/components/footer.d.ts +0 -2
- package/dist/tui/components/footer.d.ts.map +1 -1
- package/dist/tui/components/footer.js +1 -17
- package/dist/tui/components/input.d.ts +4 -0
- package/dist/tui/components/input.d.ts.map +1 -1
- package/dist/tui/components/input.js +33 -31
- package/dist/tui/components/markdown.d.ts +30 -0
- package/dist/tui/components/markdown.d.ts.map +1 -1
- package/dist/tui/components/markdown.js +274 -242
- package/dist/tui/components/modal.d.ts.map +1 -1
- package/dist/tui/components/modal.js +11 -11
- package/dist/tui/components/select-list.d.ts +5 -0
- package/dist/tui/components/select-list.d.ts.map +1 -1
- package/dist/tui/components/select-list.js +69 -98
- package/dist/tui/components/table.d.ts +6 -0
- package/dist/tui/components/table.d.ts.map +1 -1
- package/dist/tui/components/table.js +61 -52
- package/dist/tui/index.d.ts +1 -8
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +0 -8
- package/dist/tui/tui.d.ts +9 -0
- package/dist/tui/tui.d.ts.map +1 -1
- package/dist/tui/tui.js +78 -48
- package/dist/tui/utils.d.ts +7 -0
- package/dist/tui/utils.d.ts.map +1 -1
- package/dist/tui/utils.js +117 -53
- package/dist/utils/bash.d.ts.map +1 -1
- package/dist/utils/bash.js +121 -104
- package/dist/utils/binary-output.d.ts +32 -0
- package/dist/utils/binary-output.d.ts.map +1 -0
- package/dist/utils/binary-output.js +127 -0
- package/dist/utils/command-protection.d.ts +3 -2
- package/dist/utils/command-protection.d.ts.map +1 -1
- package/dist/utils/command-protection.js +121 -29
- package/dist/utils/filesystem/operations.d.ts +0 -15
- package/dist/utils/filesystem/operations.d.ts.map +1 -1
- package/dist/utils/filesystem/operations.js +1 -38
- package/dist/utils/filesystem/security.d.ts.map +1 -1
- package/dist/utils/filesystem/security.js +22 -15
- package/dist/utils/filetype-detection.d.ts +0 -1
- package/dist/utils/filetype-detection.d.ts.map +1 -1
- package/dist/utils/filetype-detection.js +0 -12
- package/dist/utils/formatting.d.ts +0 -30
- package/dist/utils/formatting.d.ts.map +1 -1
- package/dist/utils/formatting.js +0 -44
- package/dist/utils/git.d.ts +4 -6
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +36 -46
- package/dist/utils/ignore.d.ts +1 -1
- package/dist/utils/ignore.d.ts.map +1 -1
- package/dist/utils/ignore.js +1 -1
- package/dist/utils/parsing.d.ts +1 -1
- package/dist/utils/parsing.d.ts.map +1 -1
- package/dist/utils/process.d.ts.map +1 -1
- package/dist/utils/process.js +77 -79
- package/dist/utils/yaml.d.ts +0 -1
- package/dist/utils/yaml.d.ts.map +1 -1
- package/dist/utils/yaml.js +80 -89
- package/dist/utils/zod.d.ts +0 -3
- package/dist/utils/zod.d.ts.map +1 -1
- package/dist/utils/zod.js +0 -7
- package/package.json +32 -29
- package/dist/agent/sub-agent.d.ts +0 -23
- package/dist/agent/sub-agent.d.ts.map +0 -1
- package/dist/agent/sub-agent.js +0 -109
- package/dist/commands/add-directory/index.d.ts +0 -3
- package/dist/commands/add-directory/index.d.ts.map +0 -1
- package/dist/commands/add-directory/index.js +0 -50
- package/dist/commands/add-directory/utils.d.ts +0 -3
- package/dist/commands/add-directory/utils.d.ts.map +0 -1
- package/dist/commands/add-directory/utils.js +0 -15
- package/dist/commands/clear/index.d.ts +0 -3
- package/dist/commands/clear/index.d.ts.map +0 -1
- package/dist/commands/clear/index.js +0 -13
- package/dist/commands/generate-rules/index.d.ts +0 -3
- package/dist/commands/generate-rules/index.d.ts.map +0 -1
- package/dist/commands/generate-rules/index.js +0 -206
- package/dist/commands/generate-rules/service.d.ts +0 -22
- package/dist/commands/generate-rules/service.d.ts.map +0 -1
- package/dist/commands/generate-rules/service.js +0 -103
- package/dist/commands/generate-rules/utils.d.ts +0 -5
- package/dist/commands/generate-rules/utils.d.ts.map +0 -1
- package/dist/commands/generate-rules/utils.js +0 -25
- package/dist/commands/handoff/index.d.ts +0 -3
- package/dist/commands/handoff/index.d.ts.map +0 -1
- package/dist/commands/handoff/index.js +0 -97
- package/dist/commands/handoff/utils.d.ts +0 -4
- package/dist/commands/handoff/utils.d.ts.map +0 -1
- package/dist/commands/handoff/utils.js +0 -123
- package/dist/commands/list-directories/index.d.ts +0 -3
- package/dist/commands/list-directories/index.d.ts.map +0 -1
- package/dist/commands/list-directories/index.js +0 -35
- package/dist/commands/pickup/index.d.ts +0 -3
- package/dist/commands/pickup/index.d.ts.map +0 -1
- package/dist/commands/pickup/index.js +0 -141
- package/dist/commands/pickup/types.d.ts +0 -6
- package/dist/commands/pickup/types.d.ts.map +0 -1
- package/dist/commands/pickup/types.js +0 -1
- package/dist/commands/pickup/utils.d.ts +0 -7
- package/dist/commands/pickup/utils.d.ts.map +0 -1
- package/dist/commands/pickup/utils.js +0 -56
- package/dist/commands/remove-directory/index.d.ts +0 -3
- package/dist/commands/remove-directory/index.d.ts.map +0 -1
- package/dist/commands/remove-directory/index.js +0 -55
- package/dist/commands/review/index.d.ts +0 -3
- package/dist/commands/review/index.d.ts.map +0 -1
- package/dist/commands/review/index.js +0 -12
- package/dist/commands/review/review-panel.d.ts +0 -3
- package/dist/commands/review/review-panel.d.ts.map +0 -1
- package/dist/commands/review/review-panel.js +0 -186
- package/dist/commands/review/utils.d.ts +0 -18
- package/dist/commands/review/utils.d.ts.map +0 -1
- package/dist/commands/review/utils.js +0 -146
- package/dist/commands/shell/index.d.ts +0 -3
- package/dist/commands/shell/index.d.ts.map +0 -1
- package/dist/commands/shell/index.js +0 -96
- package/dist/modes/manager.d.ts +0 -24
- package/dist/modes/manager.d.ts.map +0 -1
- package/dist/modes/manager.js +0 -77
- package/dist/modes/prompts.d.ts +0 -2
- package/dist/modes/prompts.d.ts.map +0 -1
- package/dist/modes/prompts.js +0 -142
- package/dist/subagents/index.d.ts +0 -16
- package/dist/subagents/index.d.ts.map +0 -1
- package/dist/subagents/index.js +0 -231
- package/dist/terminal/index.d.ts +0 -9
- package/dist/terminal/index.d.ts.map +0 -1
- package/dist/terminal/index.js +0 -8
- package/dist/tools/agent.d.ts +0 -27
- package/dist/tools/agent.d.ts.map +0 -1
- package/dist/tools/agent.js +0 -81
- package/dist/tools/directory-tree.d.ts +0 -28
- package/dist/tools/directory-tree.d.ts.map +0 -1
- package/dist/tools/directory-tree.js +0 -152
- package/dist/tools/glob.d.ts +0 -35
- package/dist/tools/glob.d.ts.map +0 -1
- package/dist/tools/glob.js +0 -159
- package/dist/tools/grep.d.ts +0 -100
- package/dist/tools/grep.d.ts.map +0 -1
- package/dist/tools/grep.js +0 -601
- package/dist/tools/ls.d.ts +0 -26
- package/dist/tools/ls.d.ts.map +0 -1
- package/dist/tools/ls.js +0 -82
- package/dist/tui/components/header.d.ts +0 -21
- package/dist/tui/components/header.d.ts.map +0 -1
- package/dist/tui/components/header.js +0 -63
- package/dist/utils/bash/parse.d.ts +0 -19
- package/dist/utils/bash/parse.d.ts.map +0 -1
- package/dist/utils/bash/parse.js +0 -223
- package/dist/utils/bash/quote.d.ts +0 -6
- package/dist/utils/bash/quote.d.ts.map +0 -1
- package/dist/utils/bash/quote.js +0 -23
- package/dist/utils/generators.d.ts +0 -3
- package/dist/utils/generators.d.ts.map +0 -1
- package/dist/utils/generators.js +0 -25
- package/dist/utils/glob.d.ts +0 -52
- package/dist/utils/glob.d.ts.map +0 -1
- package/dist/utils/glob.js +0 -376
package/dist/tools/skill.js
CHANGED
|
@@ -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
|
-
|
|
17
|
-
|
|
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
|
-
|
|
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
|
-
|
|
56
|
-
|
|
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
|
-
|
|
61
|
-
return errorMsg;
|
|
111
|
+
return error.message;
|
|
62
112
|
}
|
|
63
113
|
},
|
|
64
114
|
};
|
package/dist/tools/types.d.ts
CHANGED
|
@@ -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;
|
|
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.
|
|
18
|
-
timeout: z.ZodOptional<z.
|
|
19
|
-
headers: z.ZodOptional<z.
|
|
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.
|
|
41
|
-
timeout: z.ZodOptional<z.
|
|
42
|
-
headers: z.ZodOptional<z.
|
|
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":"
|
|
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"}
|
package/dist/tools/web-fetch.js
CHANGED
|
@@ -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
|
-
|
|
332
|
-
if (
|
|
333
|
-
|
|
334
|
-
|
|
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
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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
|
-
|
|
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
|
-
|
|
444
|
+
content = JSON.stringify(jsonOutput, null, 2);
|
|
445
|
+
break;
|
|
417
446
|
}
|
|
418
447
|
case "html":
|
|
419
|
-
|
|
448
|
+
content = result.content;
|
|
449
|
+
break;
|
|
420
450
|
case "markdown":
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
451
|
+
content = result.contentType.includes("text/html")
|
|
452
|
+
? htmlToMarkdown(result.content)
|
|
453
|
+
: result.content;
|
|
454
|
+
break;
|
|
425
455
|
default:
|
|
426
|
-
|
|
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
|
|
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.
|
|
12
|
-
timeout: z.ZodOptional<z.
|
|
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.
|
|
32
|
-
timeout: z.ZodOptional<z.
|
|
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;
|
|
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"}
|
package/dist/tools/web-search.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
|
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":"
|
|
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 {
|
|
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,
|
|
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"}
|