tiger-agent 0.2.0
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/.env.example +22 -0
- package/.env.secrets.example +14 -0
- package/LICENSE +22 -0
- package/README.md +284 -0
- package/bin/tiger.js +96 -0
- package/package.json +58 -0
- package/scripts/audit.sh +54 -0
- package/scripts/backup.sh +42 -0
- package/scripts/cryptoEnv.js +57 -0
- package/scripts/decrypt-env.js +34 -0
- package/scripts/encrypt-env.js +34 -0
- package/scripts/migrate-vector-db.js +44 -0
- package/scripts/onboard.js +319 -0
- package/scripts/scan-secrets.sh +87 -0
- package/scripts/setup.js +302 -0
- package/scripts/sqlite_memory.py +297 -0
- package/scripts/sqlite_vec_setup.py +112 -0
- package/src/agent/contextFiles.js +30 -0
- package/src/agent/db.js +349 -0
- package/src/agent/mainAgent.js +406 -0
- package/src/agent/reflectionAgent.js +193 -0
- package/src/agent/reflectionScheduler.js +21 -0
- package/src/agent/skills.js +169 -0
- package/src/agent/subAgent.js +39 -0
- package/src/agent/toolbox.js +291 -0
- package/src/apiProviders.js +217 -0
- package/src/cli.js +187 -0
- package/src/config.js +141 -0
- package/src/kimiClient.js +88 -0
- package/src/llmClient.js +147 -0
- package/src/telegram/bot.js +182 -0
- package/src/telegram/supervisor.js +84 -0
- package/src/tokenManager.js +223 -0
- package/src/utils.js +30 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { execFile } = require('child_process');
|
|
4
|
+
const { promisify } = require('util');
|
|
5
|
+
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
const localClawhubBin = path.resolve(process.cwd(), 'node_modules', '.bin', 'clawhub');
|
|
8
|
+
|
|
9
|
+
function listSkills(baseDir) {
|
|
10
|
+
if (!fs.existsSync(baseDir)) return [];
|
|
11
|
+
return fs
|
|
12
|
+
.readdirSync(baseDir, { withFileTypes: true })
|
|
13
|
+
.filter((d) => d.isDirectory())
|
|
14
|
+
.map((d) => d.name)
|
|
15
|
+
.sort();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function loadSkill(baseDir, skillName) {
|
|
19
|
+
const skillDir = path.join(baseDir, skillName);
|
|
20
|
+
const skillFile = path.join(skillDir, 'SKILL.md');
|
|
21
|
+
if (!fs.existsSync(skillFile)) {
|
|
22
|
+
throw new Error(`Skill not found: ${skillName}`);
|
|
23
|
+
}
|
|
24
|
+
return fs.readFileSync(skillFile, 'utf8');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isValidSlug(slug) {
|
|
28
|
+
return /^[a-z0-9][a-z0-9-]*$/.test(String(slug || ''));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function ensureClawhubCli() {
|
|
32
|
+
const candidates = ['clawhub'];
|
|
33
|
+
if (fs.existsSync(localClawhubBin)) {
|
|
34
|
+
candidates.unshift(localClawhubBin);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
for (const bin of candidates) {
|
|
38
|
+
try {
|
|
39
|
+
const { stdout, stderr } = await execFileAsync(bin, ['--cli-version'], {
|
|
40
|
+
timeout: 10000,
|
|
41
|
+
maxBuffer: 256 * 1024
|
|
42
|
+
});
|
|
43
|
+
return { ok: true, bin, version: String(stdout || stderr || '').trim() };
|
|
44
|
+
} catch (err) {
|
|
45
|
+
// try next candidate
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
error:
|
|
52
|
+
'clawhub CLI is not available. Install it with: npm i -g clawhub or npm i clawhub in this project.'
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function runClawhub(argv, opts = {}) {
|
|
57
|
+
const cli = await ensureClawhubCli();
|
|
58
|
+
if (!cli.ok) return cli;
|
|
59
|
+
try {
|
|
60
|
+
const { stdout, stderr } = await execFileAsync(cli.bin, argv, {
|
|
61
|
+
timeout: Number(opts.timeout || 30000),
|
|
62
|
+
maxBuffer: Number(opts.maxBuffer || 1024 * 1024)
|
|
63
|
+
});
|
|
64
|
+
return {
|
|
65
|
+
ok: true,
|
|
66
|
+
bin: cli.bin,
|
|
67
|
+
version: cli.version,
|
|
68
|
+
stdout: String(stdout || '').trim(),
|
|
69
|
+
stderr: String(stderr || '').trim()
|
|
70
|
+
};
|
|
71
|
+
} catch (err) {
|
|
72
|
+
return {
|
|
73
|
+
ok: false,
|
|
74
|
+
bin: cli.bin,
|
|
75
|
+
version: cli.version,
|
|
76
|
+
error: err.message,
|
|
77
|
+
stdout: String(err.stdout || '').trim(),
|
|
78
|
+
stderr: String(err.stderr || '').trim()
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function clawhubSearch(args = {}) {
|
|
84
|
+
const query = String(args.query || '').trim();
|
|
85
|
+
if (!query) return { ok: false, error: 'Missing query.' };
|
|
86
|
+
|
|
87
|
+
const limit = Math.max(1, Math.min(50, Number(args.limit || 10)));
|
|
88
|
+
const workdir = path.resolve(String(args.workdir || process.cwd()));
|
|
89
|
+
const dir = String(args.dir || 'skills').trim() || 'skills';
|
|
90
|
+
|
|
91
|
+
const argv = ['search', query, '--limit', String(limit), '--no-input', '--workdir', workdir, '--dir', dir];
|
|
92
|
+
const res = await runClawhub(argv, {
|
|
93
|
+
timeout: Number(args.timeout_ms || 30000),
|
|
94
|
+
maxBuffer: 1024 * 1024
|
|
95
|
+
});
|
|
96
|
+
if (res.ok) {
|
|
97
|
+
return {
|
|
98
|
+
ok: true,
|
|
99
|
+
bin: res.bin,
|
|
100
|
+
query,
|
|
101
|
+
limit,
|
|
102
|
+
workdir,
|
|
103
|
+
dir,
|
|
104
|
+
output: res.stdout,
|
|
105
|
+
warning: res.stderr
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
ok: false,
|
|
110
|
+
bin: res.bin,
|
|
111
|
+
query,
|
|
112
|
+
workdir,
|
|
113
|
+
dir,
|
|
114
|
+
error: res.error,
|
|
115
|
+
output: res.stdout || '',
|
|
116
|
+
warning: res.stderr || ''
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function clawhubInstall(args = {}) {
|
|
121
|
+
const slug = String(args.slug || '').trim();
|
|
122
|
+
if (!slug) return { ok: false, error: 'Missing slug.' };
|
|
123
|
+
if (!isValidSlug(slug)) {
|
|
124
|
+
return { ok: false, error: 'Invalid slug format. Use lowercase letters, numbers, and hyphens only.' };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const workdir = path.resolve(String(args.workdir || process.cwd()));
|
|
128
|
+
const dir = String(args.dir || 'skills').trim() || 'skills';
|
|
129
|
+
const version = String(args.version || '').trim();
|
|
130
|
+
const force = Boolean(args.force);
|
|
131
|
+
|
|
132
|
+
const argv = ['install', slug, '--no-input', '--workdir', workdir, '--dir', dir];
|
|
133
|
+
if (version) argv.push('--version', version);
|
|
134
|
+
if (force) argv.push('--force');
|
|
135
|
+
|
|
136
|
+
const res = await runClawhub(argv, {
|
|
137
|
+
timeout: Number(args.timeout_ms || 120000),
|
|
138
|
+
maxBuffer: 1024 * 1024
|
|
139
|
+
});
|
|
140
|
+
if (res.ok) {
|
|
141
|
+
const skillPath = path.join(workdir, dir, slug, 'SKILL.md');
|
|
142
|
+
return {
|
|
143
|
+
ok: true,
|
|
144
|
+
bin: res.bin,
|
|
145
|
+
slug,
|
|
146
|
+
version: version || 'latest',
|
|
147
|
+
installed_path: skillPath,
|
|
148
|
+
skill_exists: fs.existsSync(skillPath),
|
|
149
|
+
output: res.stdout,
|
|
150
|
+
warning: res.stderr
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
ok: false,
|
|
155
|
+
bin: res.bin,
|
|
156
|
+
slug,
|
|
157
|
+
version: version || 'latest',
|
|
158
|
+
error: res.error,
|
|
159
|
+
output: res.stdout || '',
|
|
160
|
+
warning: res.stderr || ''
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = {
|
|
165
|
+
listSkills,
|
|
166
|
+
loadSkill,
|
|
167
|
+
clawhubSearch,
|
|
168
|
+
clawhubInstall
|
|
169
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const { chatCompletion } = require('../llmClient');
|
|
2
|
+
|
|
3
|
+
async function runSubAgent(task, contextText) {
|
|
4
|
+
const system = [
|
|
5
|
+
'You are a focused sub-agent.',
|
|
6
|
+
'Complete only the assigned task.',
|
|
7
|
+
'Return concise findings, key facts, and action items.'
|
|
8
|
+
].join(' ');
|
|
9
|
+
|
|
10
|
+
const message = [
|
|
11
|
+
`Task: ${task}`,
|
|
12
|
+
contextText ? `Context:\n${contextText}` : ''
|
|
13
|
+
]
|
|
14
|
+
.filter(Boolean)
|
|
15
|
+
.join('\n\n');
|
|
16
|
+
|
|
17
|
+
const result = await chatCompletion([
|
|
18
|
+
{ role: 'system', content: system },
|
|
19
|
+
{ role: 'user', content: message }
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
return result.content || '';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function runSubAgentBatch(tasks, contextText) {
|
|
26
|
+
const safeTasks = Array.isArray(tasks) ? tasks : [];
|
|
27
|
+
const out = await Promise.all(
|
|
28
|
+
safeTasks.map(async (task) => {
|
|
29
|
+
const answer = await runSubAgent(task, contextText);
|
|
30
|
+
return { task, answer };
|
|
31
|
+
})
|
|
32
|
+
);
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = {
|
|
37
|
+
runSubAgent,
|
|
38
|
+
runSubAgentBatch
|
|
39
|
+
};
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { exec } = require('child_process');
|
|
4
|
+
const { promisify } = require('util');
|
|
5
|
+
const { allowShell } = require('../config');
|
|
6
|
+
const { listSkills, loadSkill, clawhubSearch, clawhubInstall } = require('./skills');
|
|
7
|
+
const { runSubAgentBatch } = require('./subAgent');
|
|
8
|
+
|
|
9
|
+
const execAsync = promisify(exec);
|
|
10
|
+
const skillsDir = path.resolve('./skills');
|
|
11
|
+
|
|
12
|
+
function toAbsolutePath(inputPath) {
|
|
13
|
+
return path.resolve(String(inputPath || '.'));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function listFiles(args = {}) {
|
|
17
|
+
const target = toAbsolutePath(args.path || '.');
|
|
18
|
+
const recursive = Boolean(args.recursive);
|
|
19
|
+
const limit = Number(args.limit || 200);
|
|
20
|
+
const out = [];
|
|
21
|
+
|
|
22
|
+
function walk(dir) {
|
|
23
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
const full = path.join(dir, entry.name);
|
|
26
|
+
out.push({
|
|
27
|
+
path: full,
|
|
28
|
+
type: entry.isDirectory() ? 'dir' : 'file'
|
|
29
|
+
});
|
|
30
|
+
if (out.length >= limit) return;
|
|
31
|
+
if (recursive && entry.isDirectory()) {
|
|
32
|
+
walk(full);
|
|
33
|
+
if (out.length >= limit) return;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
walk(target);
|
|
39
|
+
return { root: target, items: out, truncated: out.length >= limit };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function readFile(args = {}) {
|
|
43
|
+
const target = toAbsolutePath(args.path);
|
|
44
|
+
const maxChars = Number(args.max_chars || 16000);
|
|
45
|
+
const content = fs.readFileSync(target, 'utf8');
|
|
46
|
+
return {
|
|
47
|
+
path: target,
|
|
48
|
+
content: content.slice(0, maxChars),
|
|
49
|
+
truncated: content.length > maxChars
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function writeFile(args = {}) {
|
|
54
|
+
const target = toAbsolutePath(args.path);
|
|
55
|
+
const append = Boolean(args.append);
|
|
56
|
+
const content = String(args.content || '');
|
|
57
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
58
|
+
if (append) {
|
|
59
|
+
fs.appendFileSync(target, content, 'utf8');
|
|
60
|
+
} else {
|
|
61
|
+
fs.writeFileSync(target, content, 'utf8');
|
|
62
|
+
}
|
|
63
|
+
return { path: target, bytes: Buffer.byteLength(content, 'utf8'), append };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function runShell(args = {}) {
|
|
67
|
+
if (!allowShell) {
|
|
68
|
+
return { ok: false, error: 'Shell tool disabled. Set ALLOW_SHELL=true to enable.' };
|
|
69
|
+
}
|
|
70
|
+
const command = String(args.command || '').trim();
|
|
71
|
+
if (!command) {
|
|
72
|
+
return { ok: false, error: 'Missing command.' };
|
|
73
|
+
}
|
|
74
|
+
const cwd = toAbsolutePath(args.cwd || process.cwd());
|
|
75
|
+
try {
|
|
76
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
77
|
+
cwd,
|
|
78
|
+
timeout: Number(args.timeout_ms || 15000),
|
|
79
|
+
maxBuffer: 1024 * 1024
|
|
80
|
+
});
|
|
81
|
+
return { ok: true, cwd, stdout, stderr };
|
|
82
|
+
} catch (err) {
|
|
83
|
+
return {
|
|
84
|
+
ok: false,
|
|
85
|
+
cwd,
|
|
86
|
+
error: err.message,
|
|
87
|
+
stdout: err.stdout || '',
|
|
88
|
+
stderr: err.stderr || ''
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function runSubAgentsTool(args = {}) {
|
|
94
|
+
const tasks = Array.isArray(args.tasks) ? args.tasks.map(String) : [];
|
|
95
|
+
const context = String(args.context || '');
|
|
96
|
+
const results = await runSubAgentBatch(tasks, context);
|
|
97
|
+
return { count: results.length, results };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function listSkillsTool() {
|
|
101
|
+
const skills = listSkills(skillsDir);
|
|
102
|
+
return { skills, skills_dir: skillsDir };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function loadSkillTool(args = {}) {
|
|
106
|
+
const skill = String(args.skill || '').trim();
|
|
107
|
+
if (!skill) return { ok: false, error: 'Missing skill name.' };
|
|
108
|
+
const content = loadSkill(skillsDir, skill);
|
|
109
|
+
return { ok: true, skill, content };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async function clawhubSearchTool(args = {}) {
|
|
113
|
+
return clawhubSearch({
|
|
114
|
+
query: args.query,
|
|
115
|
+
limit: args.limit,
|
|
116
|
+
workdir: args.workdir || process.cwd(),
|
|
117
|
+
dir: args.dir || 'skills',
|
|
118
|
+
timeout_ms: args.timeout_ms
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function clawhubInstallTool(args = {}) {
|
|
123
|
+
return clawhubInstall({
|
|
124
|
+
slug: args.slug,
|
|
125
|
+
version: args.version,
|
|
126
|
+
force: args.force,
|
|
127
|
+
workdir: args.workdir || process.cwd(),
|
|
128
|
+
dir: args.dir || 'skills',
|
|
129
|
+
timeout_ms: args.timeout_ms
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const tools = [
|
|
134
|
+
{
|
|
135
|
+
type: 'function',
|
|
136
|
+
function: {
|
|
137
|
+
name: 'list_files',
|
|
138
|
+
description: 'List files/directories from a path. Supports recursive mode.',
|
|
139
|
+
parameters: {
|
|
140
|
+
type: 'object',
|
|
141
|
+
properties: {
|
|
142
|
+
path: { type: 'string' },
|
|
143
|
+
recursive: { type: 'boolean' },
|
|
144
|
+
limit: { type: 'integer' }
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
type: 'function',
|
|
151
|
+
function: {
|
|
152
|
+
name: 'read_file',
|
|
153
|
+
description: 'Read text file content from disk.',
|
|
154
|
+
parameters: {
|
|
155
|
+
type: 'object',
|
|
156
|
+
properties: {
|
|
157
|
+
path: { type: 'string' },
|
|
158
|
+
max_chars: { type: 'integer' }
|
|
159
|
+
},
|
|
160
|
+
required: ['path']
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
type: 'function',
|
|
166
|
+
function: {
|
|
167
|
+
name: 'write_file',
|
|
168
|
+
description: 'Write or append text content to a file on disk.',
|
|
169
|
+
parameters: {
|
|
170
|
+
type: 'object',
|
|
171
|
+
properties: {
|
|
172
|
+
path: { type: 'string' },
|
|
173
|
+
content: { type: 'string' },
|
|
174
|
+
append: { type: 'boolean' }
|
|
175
|
+
},
|
|
176
|
+
required: ['path', 'content']
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
type: 'function',
|
|
182
|
+
function: {
|
|
183
|
+
name: 'run_shell',
|
|
184
|
+
description: 'Execute shell command on the computer if enabled by ALLOW_SHELL=true.',
|
|
185
|
+
parameters: {
|
|
186
|
+
type: 'object',
|
|
187
|
+
properties: {
|
|
188
|
+
command: { type: 'string' },
|
|
189
|
+
cwd: { type: 'string' },
|
|
190
|
+
timeout_ms: { type: 'integer' }
|
|
191
|
+
},
|
|
192
|
+
required: ['command']
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
type: 'function',
|
|
198
|
+
function: {
|
|
199
|
+
name: 'list_skills',
|
|
200
|
+
description: 'List available local skills.',
|
|
201
|
+
parameters: { type: 'object', properties: {} }
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
type: 'function',
|
|
206
|
+
function: {
|
|
207
|
+
name: 'load_skill',
|
|
208
|
+
description: 'Load full SKILL.md content for a specific local skill.',
|
|
209
|
+
parameters: {
|
|
210
|
+
type: 'object',
|
|
211
|
+
properties: {
|
|
212
|
+
skill: { type: 'string' }
|
|
213
|
+
},
|
|
214
|
+
required: ['skill']
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
type: 'function',
|
|
220
|
+
function: {
|
|
221
|
+
name: 'clawhub_search',
|
|
222
|
+
description: 'Search ClawHub skills using the clawhub CLI.',
|
|
223
|
+
parameters: {
|
|
224
|
+
type: 'object',
|
|
225
|
+
properties: {
|
|
226
|
+
query: { type: 'string' },
|
|
227
|
+
limit: { type: 'integer' },
|
|
228
|
+
workdir: { type: 'string' },
|
|
229
|
+
dir: { type: 'string' },
|
|
230
|
+
timeout_ms: { type: 'integer' }
|
|
231
|
+
},
|
|
232
|
+
required: ['query']
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
type: 'function',
|
|
238
|
+
function: {
|
|
239
|
+
name: 'clawhub_install',
|
|
240
|
+
description: 'Install a ClawHub skill by slug into the local skills directory.',
|
|
241
|
+
parameters: {
|
|
242
|
+
type: 'object',
|
|
243
|
+
properties: {
|
|
244
|
+
slug: { type: 'string' },
|
|
245
|
+
version: { type: 'string' },
|
|
246
|
+
force: { type: 'boolean' },
|
|
247
|
+
workdir: { type: 'string' },
|
|
248
|
+
dir: { type: 'string' },
|
|
249
|
+
timeout_ms: { type: 'integer' }
|
|
250
|
+
},
|
|
251
|
+
required: ['slug']
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
type: 'function',
|
|
257
|
+
function: {
|
|
258
|
+
name: 'run_sub_agents',
|
|
259
|
+
description: 'Run multiple focused sub-agents and return all outputs for orchestration.',
|
|
260
|
+
parameters: {
|
|
261
|
+
type: 'object',
|
|
262
|
+
properties: {
|
|
263
|
+
tasks: {
|
|
264
|
+
type: 'array',
|
|
265
|
+
items: { type: 'string' }
|
|
266
|
+
},
|
|
267
|
+
context: { type: 'string' }
|
|
268
|
+
},
|
|
269
|
+
required: ['tasks']
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
];
|
|
274
|
+
|
|
275
|
+
async function callTool(name, args) {
|
|
276
|
+
if (name === 'list_files') return listFiles(args);
|
|
277
|
+
if (name === 'read_file') return readFile(args);
|
|
278
|
+
if (name === 'write_file') return writeFile(args);
|
|
279
|
+
if (name === 'run_shell') return runShell(args);
|
|
280
|
+
if (name === 'list_skills') return listSkillsTool();
|
|
281
|
+
if (name === 'load_skill') return loadSkillTool(args);
|
|
282
|
+
if (name === 'clawhub_search') return clawhubSearchTool(args);
|
|
283
|
+
if (name === 'clawhub_install') return clawhubInstallTool(args);
|
|
284
|
+
if (name === 'run_sub_agents') return runSubAgentsTool(args);
|
|
285
|
+
return { ok: false, error: `Unknown tool: ${name}` };
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
module.exports = {
|
|
289
|
+
tools,
|
|
290
|
+
callTool
|
|
291
|
+
};
|