@travisennis/acai 0.0.10 → 0.0.12
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 +7 -4
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +29 -27
- package/dist/cli/stdin.d.ts +2 -1
- package/dist/cli/stdin.d.ts.map +1 -1
- package/dist/commands/generate-rules/service.d.ts +3 -2
- package/dist/commands/generate-rules/service.d.ts.map +1 -1
- package/dist/commands/health/utils.d.ts +3 -2
- package/dist/commands/health/utils.d.ts.map +1 -1
- package/dist/commands/init-project/utils.d.ts +2 -1
- package/dist/commands/init-project/utils.d.ts.map +1 -1
- package/dist/commands/init-project/utils.js +0 -11
- package/dist/commands/manager.d.ts.map +1 -1
- package/dist/commands/manager.js +6 -1
- package/dist/commands/resources/index.d.ts.map +1 -1
- package/dist/commands/resources/index.js +4 -1
- package/dist/commands/review/utils.d.ts +6 -1
- package/dist/commands/review/utils.d.ts.map +1 -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/tools/index.d.ts +3 -0
- package/dist/commands/tools/index.d.ts.map +1 -0
- package/dist/commands/tools/index.js +190 -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 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +41 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -3
- 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/opencode-go-provider.d.ts +35 -0
- package/dist/models/opencode-go-provider.d.ts.map +1 -0
- package/dist/models/opencode-go-provider.js +214 -0
- package/dist/models/opencode-zen-provider.d.ts +5 -5
- package/dist/models/opencode-zen-provider.d.ts.map +1 -1
- package/dist/models/opencode-zen-provider.js +41 -47
- package/dist/models/openrouter-provider.d.ts +5 -13
- package/dist/models/openrouter-provider.d.ts.map +1 -1
- package/dist/models/openrouter-provider.js +34 -138
- package/dist/models/providers.d.ts +3 -3
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/models/providers.js +6 -0
- 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/mentions.d.ts.map +1 -1
- package/dist/prompts/mentions.js +35 -6
- package/dist/prompts/system-prompt.d.ts +1 -0
- package/dist/prompts/system-prompt.d.ts.map +1 -1
- package/dist/prompts/system-prompt.js +20 -5
- package/dist/repl/index.d.ts +1 -2
- package/dist/repl/index.d.ts.map +1 -1
- package/dist/repl/index.js +14 -53
- package/dist/sessions/manager.d.ts +3 -3
- package/dist/sessions/manager.d.ts.map +1 -1
- package/dist/sessions/manager.js +1 -1
- 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 +3 -2
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +7 -1
- package/dist/subagents/index.d.ts +2 -1
- package/dist/subagents/index.d.ts.map +1 -1
- package/dist/terminal/table/utils.d.ts +1 -1
- package/dist/terminal/table/utils.d.ts.map +1 -1
- package/dist/terminal/wrap-ansi.js +2 -2
- package/dist/tools/agent.js +1 -1
- package/dist/tools/apply-patch.d.ts +62 -0
- package/dist/tools/apply-patch.d.ts.map +1 -0
- package/dist/tools/apply-patch.js +377 -0
- package/dist/tools/bash.d.ts +4 -4
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +40 -8
- package/dist/tools/directory-tree.d.ts +4 -4
- package/dist/tools/directory-tree.d.ts.map +1 -1
- package/dist/tools/directory-tree.js +3 -1
- package/dist/tools/dynamic-tool-loader.d.ts +12 -3
- package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-loader.js +299 -39
- package/dist/tools/edit-file.d.ts +2 -2
- package/dist/tools/edit-file.d.ts.map +1 -1
- package/dist/tools/edit-file.js +188 -79
- package/dist/tools/glob.d.ts +16 -16
- package/dist/tools/glob.d.ts.map +1 -1
- package/dist/tools/glob.js +30 -15
- package/dist/tools/grep.d.ts +14 -14
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +50 -29
- package/dist/tools/index.d.ts +57 -84
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +20 -5
- package/dist/tools/ls.d.ts +2 -2
- package/dist/tools/ls.d.ts.map +1 -1
- package/dist/tools/ls.js +2 -1
- package/dist/tools/read-file.d.ts +9 -11
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +21 -16
- package/dist/tools/save-file.d.ts +4 -4
- package/dist/tools/save-file.d.ts.map +1 -1
- package/dist/tools/save-file.js +26 -21
- package/dist/tools/skill.d.ts +2 -1
- package/dist/tools/skill.d.ts.map +1 -1
- package/dist/tools/skill.js +55 -12
- package/dist/tools/types.d.ts +8 -2
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/web-fetch.d.ts +6 -18
- package/dist/tools/web-fetch.d.ts.map +1 -1
- package/dist/tools/web-fetch.js +45 -9
- package/dist/tools/web-search.d.ts +4 -22
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +1 -1
- package/dist/tui/autocomplete/file-search-provider.js +1 -1
- package/dist/tui/autocomplete/utils.d.ts +2 -1
- package/dist/tui/autocomplete/utils.d.ts.map +1 -1
- package/dist/tui/autocomplete/utils.js +25 -23
- package/dist/tui/components/editor.d.ts +2 -1
- package/dist/tui/components/editor.d.ts.map +1 -1
- package/dist/tui/components/editor.js +1 -1
- 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/markdown.d.ts +2 -2
- package/dist/tui/components/markdown.d.ts.map +1 -1
- package/dist/tui/components/welcome.d.ts +2 -1
- package/dist/tui/components/welcome.d.ts.map +1 -1
- package/dist/tui/editor-launcher.d.ts +3 -2
- package/dist/tui/editor-launcher.d.ts.map +1 -1
- package/dist/tui/index.d.ts +0 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/tui.d.ts +1 -0
- package/dist/tui/tui.d.ts.map +1 -1
- package/dist/tui/tui.js +9 -0
- package/dist/tui/utils.d.ts +1 -5
- package/dist/tui/utils.d.ts.map +1 -1
- package/dist/tui/utils.js +271 -44
- 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.map +1 -1
- package/dist/utils/command-protection.js +92 -9
- package/dist/utils/parsing.d.ts +1 -1
- package/dist/utils/parsing.d.ts.map +1 -1
- package/package.json +28 -26
- package/dist/commands/add-directory/types.d.ts +0 -6
- package/dist/commands/add-directory/types.d.ts.map +0 -1
- package/dist/commands/add-directory/types.js +0 -1
- package/dist/commands/copy/types.d.ts +0 -3
- package/dist/commands/copy/types.d.ts.map +0 -1
- package/dist/commands/copy/types.js +0 -1
- package/dist/commands/review/types.d.ts +0 -12
- package/dist/commands/review/types.d.ts.map +0 -1
- package/dist/commands/review/types.js +0 -1
- package/dist/modes/manager.d.ts +0 -23
- 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 -143
- package/dist/tools/code-search.d.ts +0 -41
- package/dist/tools/code-search.d.ts.map +0 -1
- package/dist/tools/code-search.js +0 -195
- package/dist/utils/iterables.d.ts +0 -2
- package/dist/utils/iterables.d.ts.map +0 -1
- package/dist/utils/iterables.js +0 -6
|
@@ -18,6 +18,156 @@ const toolMetadataSchema = z.object({
|
|
|
18
18
|
})),
|
|
19
19
|
needsApproval: z.boolean().default(true),
|
|
20
20
|
});
|
|
21
|
+
const KNOWN_EXTENSIONS = [
|
|
22
|
+
".js",
|
|
23
|
+
".mjs",
|
|
24
|
+
".cjs",
|
|
25
|
+
".sh",
|
|
26
|
+
".bash",
|
|
27
|
+
".zsh",
|
|
28
|
+
".py",
|
|
29
|
+
".rb",
|
|
30
|
+
".tool",
|
|
31
|
+
];
|
|
32
|
+
const EXTENSION_INTERPRETER_MAP = {
|
|
33
|
+
".js": process.execPath,
|
|
34
|
+
".mjs": process.execPath,
|
|
35
|
+
".cjs": process.execPath,
|
|
36
|
+
".sh": "/bin/bash",
|
|
37
|
+
".bash": "/bin/bash",
|
|
38
|
+
".zsh": "/bin/zsh",
|
|
39
|
+
".py": "python3",
|
|
40
|
+
".rb": "ruby",
|
|
41
|
+
};
|
|
42
|
+
export function getShebang(scriptPath) {
|
|
43
|
+
try {
|
|
44
|
+
const fd = fs.openSync(scriptPath, "r");
|
|
45
|
+
const buffer = Buffer.alloc(256);
|
|
46
|
+
const bytesRead = fs.readSync(fd, buffer, 0, 256, 0);
|
|
47
|
+
fs.closeSync(fd);
|
|
48
|
+
const content = buffer.toString("utf8", 0, bytesRead);
|
|
49
|
+
if (content.startsWith("#!")) {
|
|
50
|
+
return content.slice(2).trim().split("\n")[0].trim();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Can't read file, skip
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
export function parseShebang(shebang, scriptPath) {
|
|
59
|
+
if (shebang.startsWith("/usr/bin/env ")) {
|
|
60
|
+
const interpreter = shebang
|
|
61
|
+
.slice("/usr/bin/env ".length)
|
|
62
|
+
.trim()
|
|
63
|
+
.split(" ")[0];
|
|
64
|
+
return { command: interpreter, args: [scriptPath] };
|
|
65
|
+
}
|
|
66
|
+
const parts = shebang.split(" ");
|
|
67
|
+
return { command: parts[0], args: [...parts.slice(1), scriptPath] };
|
|
68
|
+
}
|
|
69
|
+
export function resolveToolInterpreter(scriptPath) {
|
|
70
|
+
// 1. Check shebang
|
|
71
|
+
const shebang = getShebang(scriptPath);
|
|
72
|
+
if (shebang) {
|
|
73
|
+
return parseShebang(shebang, scriptPath);
|
|
74
|
+
}
|
|
75
|
+
// 2. Check extension
|
|
76
|
+
const ext = path.extname(scriptPath).toLowerCase();
|
|
77
|
+
if (EXTENSION_INTERPRETER_MAP[ext]) {
|
|
78
|
+
return { command: EXTENSION_INTERPRETER_MAP[ext], args: [scriptPath] };
|
|
79
|
+
}
|
|
80
|
+
// 3. Extensionless executable
|
|
81
|
+
if (!ext) {
|
|
82
|
+
try {
|
|
83
|
+
const stats = fs.statSync(scriptPath);
|
|
84
|
+
if (stats.mode & 0o111) {
|
|
85
|
+
return { command: scriptPath, args: [] };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// File doesn't exist or can't stat, skip
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
export function parseTextSchema(content) {
|
|
95
|
+
const lines = content
|
|
96
|
+
.trim()
|
|
97
|
+
.split("\n")
|
|
98
|
+
.map((l) => l.trim())
|
|
99
|
+
.filter((l) => l && !l.startsWith("#") && !l.startsWith("//"));
|
|
100
|
+
let name;
|
|
101
|
+
let description;
|
|
102
|
+
const parameters = [];
|
|
103
|
+
for (const line of lines) {
|
|
104
|
+
if (line.startsWith("name:")) {
|
|
105
|
+
name = line.slice(5).trim();
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (line.startsWith("description:")) {
|
|
109
|
+
description = line.slice(12).trim();
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
// Parse parameters: "paramName: type [optional|required] description text"
|
|
113
|
+
const paramMatch = line.match(/^(\w+):\s*(string|number|boolean)\s+(optional|required)?\s*(.*)$/);
|
|
114
|
+
if (paramMatch) {
|
|
115
|
+
const [, paramName, paramType, requirement, paramDescription] = paramMatch;
|
|
116
|
+
parameters.push({
|
|
117
|
+
name: paramName,
|
|
118
|
+
type: paramType,
|
|
119
|
+
description: paramDescription || `Parameter ${paramName}`,
|
|
120
|
+
required: requirement !== "optional",
|
|
121
|
+
});
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
// Handle params without type keyword (default to string)
|
|
125
|
+
const simpleMatch = line.match(/^(\w+):\s*(.*)$/);
|
|
126
|
+
if (simpleMatch &&
|
|
127
|
+
!line.startsWith("name:") &&
|
|
128
|
+
!line.startsWith("description:")) {
|
|
129
|
+
const [, paramName, rest] = simpleMatch;
|
|
130
|
+
const typeMatch = rest.match(/^(string|number|boolean)\s*(.*)$/);
|
|
131
|
+
if (typeMatch) {
|
|
132
|
+
const [, paramType, afterType] = typeMatch;
|
|
133
|
+
const optMatch = afterType.match(/^(optional|required)\s*(.*)$/);
|
|
134
|
+
parameters.push({
|
|
135
|
+
name: paramName,
|
|
136
|
+
type: paramType,
|
|
137
|
+
description: optMatch
|
|
138
|
+
? optMatch[2] || `Parameter ${paramName}`
|
|
139
|
+
: afterType || `Parameter ${paramName}`,
|
|
140
|
+
required: !optMatch || optMatch[1] !== "optional",
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
const optMatch = rest.match(/^(optional|required)\s*(.*)$/);
|
|
145
|
+
parameters.push({
|
|
146
|
+
name: paramName,
|
|
147
|
+
type: "string",
|
|
148
|
+
description: optMatch
|
|
149
|
+
? optMatch[2] || rest
|
|
150
|
+
: rest || `Parameter ${paramName}`,
|
|
151
|
+
required: !optMatch || optMatch[1] !== "optional",
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (!name || !description) {
|
|
157
|
+
logger.warn("Text schema missing required name or description");
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(name)) {
|
|
161
|
+
logger.warn(`Invalid tool name: ${name}`);
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
name,
|
|
166
|
+
description,
|
|
167
|
+
parameters,
|
|
168
|
+
needsApproval: true,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
21
171
|
export function parseToolMetadata(output) {
|
|
22
172
|
try {
|
|
23
173
|
const parsed = JSON.parse(output.trim());
|
|
@@ -58,20 +208,29 @@ function generateZodSchema(parameters) {
|
|
|
58
208
|
}
|
|
59
209
|
return z.object(fields);
|
|
60
210
|
}
|
|
61
|
-
async function getMetadata(scriptPath) {
|
|
211
|
+
async function getMetadata(scriptPath, sessionContext) {
|
|
212
|
+
const interpreter = resolveToolInterpreter(scriptPath);
|
|
213
|
+
if (!interpreter) {
|
|
214
|
+
logger.warn(`No valid interpreter for ${scriptPath}, skipping.`);
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
62
217
|
return new Promise((resolve) => {
|
|
63
218
|
let child;
|
|
64
219
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
220
|
+
const env = {
|
|
221
|
+
...process.env,
|
|
222
|
+
// biome-ignore lint/style/useNamingConvention: Environment variables are conventionally uppercase
|
|
223
|
+
TOOL_ACTION: "describe",
|
|
224
|
+
// biome-ignore lint/style/useNamingConvention: Environment variables are conventionally uppercase
|
|
225
|
+
NODE_ENV: "production",
|
|
226
|
+
};
|
|
227
|
+
if (sessionContext) {
|
|
228
|
+
env["ACAI_SESSION_ID"] = sessionContext.sessionId;
|
|
229
|
+
env["ACAI_PROJECT_DIR"] = sessionContext.projectDir;
|
|
230
|
+
env["ACAI_AGENT_NAME"] = sessionContext.agentName;
|
|
231
|
+
}
|
|
232
|
+
child = spawn(interpreter.command, interpreter.args, {
|
|
233
|
+
env,
|
|
75
234
|
stdio: ["ignore", "pipe", "pipe"],
|
|
76
235
|
});
|
|
77
236
|
}
|
|
@@ -96,11 +255,18 @@ async function getMetadata(scriptPath) {
|
|
|
96
255
|
}
|
|
97
256
|
try {
|
|
98
257
|
const metadata = parseToolMetadata(stdout);
|
|
99
|
-
resolve(metadata);
|
|
258
|
+
resolve({ ...metadata, format: "json" });
|
|
100
259
|
}
|
|
101
|
-
catch
|
|
102
|
-
|
|
103
|
-
|
|
260
|
+
catch {
|
|
261
|
+
// JSON parse failed, try text format
|
|
262
|
+
const textMetadata = parseTextSchema(stdout);
|
|
263
|
+
if (textMetadata) {
|
|
264
|
+
resolve({ ...textMetadata, format: "text" });
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
logger.error(`Failed to parse metadata from ${scriptPath}: not valid JSON or text format`);
|
|
268
|
+
resolve(null);
|
|
269
|
+
}
|
|
104
270
|
}
|
|
105
271
|
});
|
|
106
272
|
child.on("error", (err) => {
|
|
@@ -109,22 +275,40 @@ async function getMetadata(scriptPath) {
|
|
|
109
275
|
});
|
|
110
276
|
});
|
|
111
277
|
}
|
|
112
|
-
async function spawnChildProcess(scriptPath, params, abortSignal) {
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
278
|
+
async function spawnChildProcess(scriptPath, params, abortSignal, sessionContext, format = "json") {
|
|
279
|
+
const interpreter = resolveToolInterpreter(scriptPath);
|
|
280
|
+
if (!interpreter) {
|
|
281
|
+
throw new Error(`No valid interpreter for ${scriptPath}`);
|
|
282
|
+
}
|
|
283
|
+
let paramsInput;
|
|
284
|
+
if (format === "text") {
|
|
285
|
+
paramsInput = `${Object.entries(params)
|
|
286
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
287
|
+
.join("\n")}\n`;
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
const paramsArray = Object.entries(params).map(([name, value]) => ({
|
|
291
|
+
name,
|
|
292
|
+
value,
|
|
293
|
+
}));
|
|
294
|
+
paramsInput = `${JSON.stringify(paramsArray)}\n`;
|
|
295
|
+
}
|
|
296
|
+
const env = {
|
|
297
|
+
...process.env,
|
|
298
|
+
// biome-ignore lint/style/useNamingConvention: Environment variables are conventionally uppercase
|
|
299
|
+
TOOL_ACTION: "execute",
|
|
300
|
+
// biome-ignore lint/style/useNamingConvention: Environment variables are conventionally uppercase
|
|
301
|
+
NODE_ENV: "production",
|
|
302
|
+
};
|
|
303
|
+
if (sessionContext) {
|
|
304
|
+
env["ACAI_SESSION_ID"] = sessionContext.sessionId;
|
|
305
|
+
env["ACAI_PROJECT_DIR"] = sessionContext.projectDir;
|
|
306
|
+
env["ACAI_AGENT_NAME"] = sessionContext.agentName;
|
|
307
|
+
}
|
|
118
308
|
return new Promise((resolve, reject) => {
|
|
119
|
-
const child = spawn(
|
|
309
|
+
const child = spawn(interpreter.command, interpreter.args, {
|
|
120
310
|
cwd: path.dirname(scriptPath),
|
|
121
|
-
env
|
|
122
|
-
...process.env,
|
|
123
|
-
// biome-ignore lint/style/useNamingConvention: Environment variables are conventionally uppercase
|
|
124
|
-
TOOL_ACTION: "execute",
|
|
125
|
-
// biome-ignore lint/style/useNamingConvention: Environment variables are conventionally uppercase
|
|
126
|
-
NODE_ENV: "production",
|
|
127
|
-
},
|
|
311
|
+
env,
|
|
128
312
|
stdio: ["pipe", "pipe", "pipe"],
|
|
129
313
|
});
|
|
130
314
|
let stdout = "";
|
|
@@ -135,7 +319,7 @@ async function spawnChildProcess(scriptPath, params, abortSignal) {
|
|
|
135
319
|
child.kill();
|
|
136
320
|
reject(new Error("Execution timed out after 30 seconds"));
|
|
137
321
|
}, 30000);
|
|
138
|
-
child.stdin.write(
|
|
322
|
+
child.stdin.write(paramsInput);
|
|
139
323
|
child.stdin.end();
|
|
140
324
|
child.stdout.on("data", (data) => {
|
|
141
325
|
stdout += data.toString();
|
|
@@ -181,9 +365,10 @@ async function spawnChildProcess(scriptPath, params, abortSignal) {
|
|
|
181
365
|
}
|
|
182
366
|
});
|
|
183
367
|
}
|
|
184
|
-
function createDynamicTool(scriptPath, metadata) {
|
|
368
|
+
function createDynamicTool(scriptPath, metadata, sessionContext) {
|
|
185
369
|
const inputSchema = generateZodSchema(metadata.parameters);
|
|
186
370
|
const toolName = metadata.name;
|
|
371
|
+
const format = metadata.format;
|
|
187
372
|
return {
|
|
188
373
|
[toolName]: {
|
|
189
374
|
toolDef: {
|
|
@@ -193,7 +378,7 @@ function createDynamicTool(scriptPath, metadata) {
|
|
|
193
378
|
display() {
|
|
194
379
|
return "running";
|
|
195
380
|
},
|
|
196
|
-
async execute(input, { abortSignal }) {
|
|
381
|
+
async execute(input, { abortSignal, sessionContext: executionContext }) {
|
|
197
382
|
if (abortSignal?.aborted) {
|
|
198
383
|
throw new Error("Execution aborted");
|
|
199
384
|
}
|
|
@@ -203,12 +388,36 @@ function createDynamicTool(scriptPath, metadata) {
|
|
|
203
388
|
catch (e) {
|
|
204
389
|
throw new Error(`Invalid parameters for tool ${metadata.name}: ${e.message}`);
|
|
205
390
|
}
|
|
206
|
-
|
|
391
|
+
// Prefer execution-time context over load-time context
|
|
392
|
+
const context = executionContext ?? sessionContext;
|
|
393
|
+
return spawnChildProcess(scriptPath, input, abortSignal, context, format);
|
|
207
394
|
},
|
|
208
395
|
},
|
|
209
396
|
};
|
|
210
397
|
}
|
|
211
|
-
|
|
398
|
+
function findCompanion(dir, baseName) {
|
|
399
|
+
const companionExtensions = [
|
|
400
|
+
".sh",
|
|
401
|
+
".bash",
|
|
402
|
+
".zsh",
|
|
403
|
+
".py",
|
|
404
|
+
".rb",
|
|
405
|
+
".js",
|
|
406
|
+
".mjs",
|
|
407
|
+
".cjs",
|
|
408
|
+
"",
|
|
409
|
+
];
|
|
410
|
+
for (const ext of companionExtensions) {
|
|
411
|
+
const candidate = path.join(dir, baseName + ext);
|
|
412
|
+
if (fs.existsSync(candidate)) {
|
|
413
|
+
const interpreter = resolveToolInterpreter(candidate);
|
|
414
|
+
if (interpreter)
|
|
415
|
+
return candidate;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
export async function loadDynamicTools({ baseDir, existingToolNames = [], sessionContext, }) {
|
|
212
421
|
const projectConfig = await config.getConfig();
|
|
213
422
|
const dynamicConfig = projectConfig.tools.dynamicTools;
|
|
214
423
|
if (!dynamicConfig.enabled) {
|
|
@@ -222,13 +431,32 @@ export async function loadDynamicTools({ baseDir, existingToolNames = [], }) {
|
|
|
222
431
|
if (!fs.existsSync(dir))
|
|
223
432
|
return;
|
|
224
433
|
try {
|
|
225
|
-
const files = fs
|
|
226
|
-
|
|
227
|
-
.
|
|
434
|
+
const files = fs.readdirSync(dir).filter((f) => {
|
|
435
|
+
// Known extensions
|
|
436
|
+
if (KNOWN_EXTENSIONS.some((ext) => f.endsWith(ext))) {
|
|
437
|
+
return true;
|
|
438
|
+
}
|
|
439
|
+
// Extensionless files that are executable
|
|
440
|
+
if (!path.extname(f)) {
|
|
441
|
+
const fullPath = path.join(dir, f);
|
|
442
|
+
try {
|
|
443
|
+
const stats = fs.statSync(fullPath);
|
|
444
|
+
if (stats.mode & 0o111)
|
|
445
|
+
return true;
|
|
446
|
+
}
|
|
447
|
+
catch {
|
|
448
|
+
// Can't stat, skip
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
return false;
|
|
452
|
+
});
|
|
228
453
|
for (const file of files) {
|
|
454
|
+
// Skip .tool files, they are handled separately
|
|
455
|
+
if (file.endsWith(".tool"))
|
|
456
|
+
continue;
|
|
229
457
|
const scriptPath = path.join(dir, file);
|
|
230
458
|
try {
|
|
231
|
-
const metadata = await getMetadata(scriptPath);
|
|
459
|
+
const metadata = await getMetadata(scriptPath, sessionContext);
|
|
232
460
|
if (metadata) {
|
|
233
461
|
toolMap.set(metadata.name, { path: scriptPath, metadata });
|
|
234
462
|
logger.info(`Loaded ${isProject ? "project" : "user"} tool: ${metadata.name}`);
|
|
@@ -241,6 +469,38 @@ export async function loadDynamicTools({ baseDir, existingToolNames = [], }) {
|
|
|
241
469
|
logger.error(`Error scanning ${file}: ${e}`);
|
|
242
470
|
}
|
|
243
471
|
}
|
|
472
|
+
// Scan for .tool files (text schema with companion executable)
|
|
473
|
+
const allDirFiles = fs.readdirSync(dir);
|
|
474
|
+
const allToolFiles = allDirFiles.filter((f) => f.endsWith(".tool"));
|
|
475
|
+
for (const toolFile of allToolFiles) {
|
|
476
|
+
const toolPath = path.join(dir, toolFile);
|
|
477
|
+
try {
|
|
478
|
+
const content = fs.readFileSync(toolPath, "utf8");
|
|
479
|
+
const metadata = parseTextSchema(content);
|
|
480
|
+
if (!metadata) {
|
|
481
|
+
logger.warn(`Failed to parse .tool file: ${toolFile}`);
|
|
482
|
+
continue;
|
|
483
|
+
}
|
|
484
|
+
const baseName = toolFile.slice(0, -5); // Remove .tool extension
|
|
485
|
+
const companionPath = findCompanion(dir, baseName);
|
|
486
|
+
if (!companionPath) {
|
|
487
|
+
logger.warn(`No companion executable found for ${toolFile}`);
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
const metadataWithFormat = {
|
|
491
|
+
...metadata,
|
|
492
|
+
format: "text",
|
|
493
|
+
};
|
|
494
|
+
toolMap.set(metadata.name, {
|
|
495
|
+
path: companionPath,
|
|
496
|
+
metadata: metadataWithFormat,
|
|
497
|
+
});
|
|
498
|
+
logger.info(`Loaded ${isProject ? "project" : "user"} tool: ${metadata.name} (from .tool file)`);
|
|
499
|
+
}
|
|
500
|
+
catch (e) {
|
|
501
|
+
logger.error(`Error reading .tool file ${toolFile}: ${e}`);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
244
504
|
}
|
|
245
505
|
catch (e) {
|
|
246
506
|
logger.error(`Error reading dir ${dir}: ${e}`);
|
|
@@ -274,7 +534,7 @@ export async function loadDynamicTools({ baseDir, existingToolNames = [], }) {
|
|
|
274
534
|
logger.warn(`Duplicate dynamic tool name '${toolName}' found. Skipping duplicate.`);
|
|
275
535
|
continue;
|
|
276
536
|
}
|
|
277
|
-
Object.assign(tools, createDynamicTool(path, metadata));
|
|
537
|
+
Object.assign(tools, createDynamicTool(path, metadata, sessionContext));
|
|
278
538
|
}
|
|
279
539
|
if (conflictingTools.length > 0) {
|
|
280
540
|
logger.warn(`Warning: ${conflictingTools.length} dynamic tool(s) skipped due to name conflicts: ${conflictingTools.join(", ")}`);
|
|
@@ -6,7 +6,7 @@ export declare const EditFileTool: {
|
|
|
6
6
|
};
|
|
7
7
|
declare const inputSchema: z.ZodObject<{
|
|
8
8
|
path: z.ZodString;
|
|
9
|
-
edits: z.
|
|
9
|
+
edits: z.ZodPreprocess<z.ZodArray<z.ZodObject<{
|
|
10
10
|
oldText: z.ZodString;
|
|
11
11
|
newText: z.ZodString;
|
|
12
12
|
}, z.core.$strip>>>;
|
|
@@ -19,7 +19,7 @@ export declare const createEditFileTool: (options: {
|
|
|
19
19
|
description: string;
|
|
20
20
|
inputSchema: z.ZodObject<{
|
|
21
21
|
path: z.ZodString;
|
|
22
|
-
edits: z.
|
|
22
|
+
edits: z.ZodPreprocess<z.ZodArray<z.ZodObject<{
|
|
23
23
|
oldText: z.ZodString;
|
|
24
24
|
newText: z.ZodString;
|
|
25
25
|
}, z.core.$strip>>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"edit-file.d.ts","sourceRoot":"","sources":["../../source/tools/edit-file.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AASpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,YAAY;;CAExB,CAAC;AAIF,QAAA,MAAM,WAAW;;;;;;iBAqCf,CAAC;AAEH,KAAK,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEvD,eAAO,MAAM,kBAAkB,GAAU,SAAS;IAChD,SAAS,EAAE,gBAAgB,CAAC;CAC7B;;;;;;;;;;;6BAY4B,mBAAmB;6BAKzB,mBAAmB,mBACnB,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;EA6BrB,CAAC;AAiDF,UAAU,QAAQ;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;
|
|
1
|
+
{"version":3,"file":"edit-file.d.ts","sourceRoot":"","sources":["../../source/tools/edit-file.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AASpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,YAAY;;CAExB,CAAC;AAIF,QAAA,MAAM,WAAW;;;;;;iBAqCf,CAAC;AAEH,KAAK,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAEvD,eAAO,MAAM,kBAAkB,GAAU,SAAS;IAChD,SAAS,EAAE,gBAAgB,CAAC;CAC7B;;;;;;;;;;;6BAY4B,mBAAmB;6BAKzB,mBAAmB,mBACnB,oBAAoB,GACpC,OAAO,CAAC,MAAM,CAAC;EA6BrB,CAAC;AAiDF,UAAU,QAAQ;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAgQD,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,QAAQ,EAAE,EACjB,MAAM,UAAQ,EACd,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,MAAM,CAAC,CAqEjB"}
|