qafai 0.1.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/dist/index.js ADDED
@@ -0,0 +1,272 @@
1
+ /**
2
+ * CLI entry point for QafAI Agent.
3
+ *
4
+ * npm install -g qafai
5
+ *
6
+ * Usage:
7
+ * qaf "fix the bug in main.py" — One-shot agent
8
+ * qaf — Interactive REPL
9
+ * qaf --model groq:kimi-k2 "..." — Override model
10
+ * qaf init — Setup wizard
11
+ * qaf models — List available models
12
+ */
13
+ import { Command } from 'commander';
14
+ import chalk from 'chalk';
15
+ import { createInterface } from 'node:readline';
16
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
17
+ import { AgentLoop } from './agent.js';
18
+ import { QafClient, QafClientError } from './client.js';
19
+ import { getModel, isConfigured, loadConfig, saveConfig, HISTORY_FILE, } from './config.js';
20
+ import * as ui from './ui.js';
21
+ // Force tool registration
22
+ import './tools/index.js';
23
+ const VERSION = '0.1.0';
24
+ const program = new Command();
25
+ program
26
+ .name('qaf')
27
+ .description('QafAI Agent — AI coding assistant from qafai.net')
28
+ .version(VERSION)
29
+ .option('-m, --model <model>', 'Model to use (e.g. groq:llama-3.3-70b)')
30
+ .option('-t, --temperature <temp>', 'Temperature (0-2)', parseFloat)
31
+ .argument('[message...]', 'Message to send (one-shot mode)')
32
+ .action(async (messageParts, opts) => {
33
+ if (!isConfigured()) {
34
+ console.log(chalk.yellow('Not configured. Run ') + chalk.bold('qaf init') + chalk.yellow(' first.'));
35
+ process.exit(1);
36
+ }
37
+ const config = loadConfig();
38
+ const model = opts.model || getModel() || undefined;
39
+ const temperature = opts.temperature ?? config.temperature;
40
+ const client = new QafClient();
41
+ const message = messageParts.join(' ').trim();
42
+ if (message) {
43
+ await oneShot(client, message, model, temperature);
44
+ }
45
+ else {
46
+ await repl(client, model, temperature);
47
+ }
48
+ });
49
+ program
50
+ .command('init')
51
+ .description('Setup: server URL, API key, and connection test')
52
+ .action(async () => {
53
+ await initWizard();
54
+ });
55
+ program
56
+ .command('models')
57
+ .description('List available models')
58
+ .action(async () => {
59
+ if (!isConfigured()) {
60
+ console.log(chalk.yellow('Not configured. Run ') + chalk.bold('qaf init') + chalk.yellow(' first.'));
61
+ return;
62
+ }
63
+ await listModels();
64
+ });
65
+ program.parseAsync().catch((err) => {
66
+ ui.showError(err.message);
67
+ process.exit(1);
68
+ });
69
+ // ── One-shot mode ──────────────────────────────────────────────────
70
+ async function oneShot(client, message, model, temperature) {
71
+ const agent = new AgentLoop(client, model, temperature);
72
+ try {
73
+ await agent.run(message);
74
+ }
75
+ catch (err) {
76
+ ui.showError(err instanceof Error ? err.message : String(err));
77
+ process.exit(1);
78
+ }
79
+ }
80
+ // ── Interactive REPL ───────────────────────────────────────────────
81
+ async function repl(client, model, temperature) {
82
+ ui.showWelcome();
83
+ const agent = new AgentLoop(client, model, temperature);
84
+ // Simple history
85
+ const history = loadHistory();
86
+ const rl = createInterface({
87
+ input: process.stdin,
88
+ output: process.stdout,
89
+ prompt: chalk.cyan('qaf> '),
90
+ historySize: 200,
91
+ history,
92
+ });
93
+ rl.prompt();
94
+ for await (const line of rl) {
95
+ const input = line.trim();
96
+ if (!input) {
97
+ rl.prompt();
98
+ continue;
99
+ }
100
+ // Save to history
101
+ history.push(input);
102
+ saveHistory(history.slice(-200));
103
+ // REPL commands
104
+ if (input.startsWith('/')) {
105
+ const parts = input.toLowerCase().split(/\s+/);
106
+ const cmd = parts[0];
107
+ if (cmd === '/quit' || cmd === '/exit' || cmd === '/q') {
108
+ console.log(chalk.dim('Goodbye!'));
109
+ rl.close();
110
+ return;
111
+ }
112
+ if (cmd === '/clear') {
113
+ agent.clearHistory();
114
+ console.log(chalk.dim('History cleared.'));
115
+ rl.prompt();
116
+ continue;
117
+ }
118
+ if (cmd === '/help') {
119
+ showReplHelp();
120
+ rl.prompt();
121
+ continue;
122
+ }
123
+ if (cmd === '/model') {
124
+ if (parts[1]) {
125
+ agent.setModel(parts[1]);
126
+ console.log(chalk.dim(`Model set to ${parts[1]}`));
127
+ }
128
+ else {
129
+ console.log(chalk.dim(`Current model: ${model || 'server default'}`));
130
+ }
131
+ rl.prompt();
132
+ continue;
133
+ }
134
+ console.log(chalk.yellow(`Unknown command: ${cmd}. Type /help`));
135
+ rl.prompt();
136
+ continue;
137
+ }
138
+ try {
139
+ await agent.run(input);
140
+ }
141
+ catch (err) {
142
+ ui.showError(err instanceof Error ? err.message : String(err));
143
+ }
144
+ console.log();
145
+ rl.prompt();
146
+ }
147
+ }
148
+ function showReplHelp() {
149
+ console.log();
150
+ console.log(chalk.bold('Commands:'));
151
+ console.log(' /help Show this help');
152
+ console.log(' /clear Clear conversation history');
153
+ console.log(' /model [name] Show or change model');
154
+ console.log(' /quit Exit');
155
+ console.log();
156
+ }
157
+ // ── Init wizard ────────────────────────────────────────────────────
158
+ async function initWizard() {
159
+ console.log();
160
+ console.log(chalk.cyan.bold('QafAI Agent Setup'));
161
+ console.log();
162
+ const config = loadConfig();
163
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
164
+ const ask = (q, def) => new Promise(resolve => rl.question(`${q} ${chalk.dim(`[${def}]`)} `, a => resolve(a.trim() || def)));
165
+ const url = (await ask('Server URL:', config.server_url)).replace(/\/+$/, '');
166
+ saveConfig({ server_url: url });
167
+ console.log();
168
+ console.log(chalk.dim(`Get your API key from: ${url} → Settings → API Keys`));
169
+ const apiKey = await new Promise(resolve => rl.question('API Key: ', a => resolve(a.trim())));
170
+ if (!apiKey) {
171
+ console.log(chalk.red('API key is required.'));
172
+ rl.close();
173
+ return;
174
+ }
175
+ saveConfig({ api_key: apiKey });
176
+ // Connection test
177
+ console.log();
178
+ console.log(chalk.dim('Testing connection...'));
179
+ const client = new QafClient(url, apiKey);
180
+ const healthy = await client.healthCheck();
181
+ if (!healthy) {
182
+ console.log(chalk.red('Server not reachable. Check your URL.'));
183
+ rl.close();
184
+ return;
185
+ }
186
+ try {
187
+ const data = await client.listModels();
188
+ const count = data.models.length;
189
+ console.log(chalk.green(`Connected! ${count} models available.`));
190
+ }
191
+ catch (err) {
192
+ if (err instanceof QafClientError && err.statusCode === 401) {
193
+ console.log(chalk.red('Invalid API key.'));
194
+ }
195
+ else {
196
+ console.log(chalk.red(err instanceof Error ? err.message : String(err)));
197
+ }
198
+ rl.close();
199
+ return;
200
+ }
201
+ console.log();
202
+ const model = await ask('Default model (empty for server default):', '');
203
+ if (model)
204
+ saveConfig({ model });
205
+ rl.close();
206
+ console.log();
207
+ console.log(chalk.green.bold('Setup complete!') + ' Run ' + chalk.bold('qaf') + ' to start.');
208
+ console.log();
209
+ }
210
+ // ── Models list ────────────────────────────────────────────────────
211
+ async function listModels() {
212
+ const client = new QafClient();
213
+ try {
214
+ const data = await client.listModels();
215
+ const models = data.models;
216
+ const defaultModel = data.default;
217
+ // Header
218
+ console.log();
219
+ console.log(chalk.bold('Available Models'));
220
+ console.log(chalk.dim('─'.repeat(80)));
221
+ console.log(chalk.dim(padRight('MODEL ID', 30)) +
222
+ padRight('NAME', 25) +
223
+ chalk.dim(padRight('PROVIDER', 12)) +
224
+ padRight('CONTEXT', 10) +
225
+ 'AGENT');
226
+ console.log(chalk.dim('─'.repeat(80)));
227
+ for (const m of models) {
228
+ const id = String(m.id);
229
+ let name = String(m.name);
230
+ if (id === defaultModel)
231
+ name += chalk.green(' (default)');
232
+ const ctx = Number(m.context).toLocaleString();
233
+ const agent = m.agent_capable ? chalk.green('✓') : '';
234
+ console.log(chalk.cyan(padRight(id, 30)) +
235
+ padRight(name, 25) +
236
+ chalk.dim(padRight(String(m.provider), 12)) +
237
+ padRight(ctx, 10) +
238
+ agent);
239
+ }
240
+ console.log(chalk.dim('─'.repeat(80)));
241
+ console.log(chalk.dim(` ${models.length} models available`));
242
+ console.log();
243
+ }
244
+ catch (err) {
245
+ ui.showError(err instanceof Error ? err.message : String(err));
246
+ }
247
+ }
248
+ function padRight(s, len) {
249
+ // Strip ANSI for length calculation
250
+ const stripped = s.replace(/\x1b\[[0-9;]*m/g, '');
251
+ const pad = Math.max(0, len - stripped.length);
252
+ return s + ' '.repeat(pad);
253
+ }
254
+ // ── History persistence ────────────────────────────────────────────
255
+ function loadHistory() {
256
+ try {
257
+ if (existsSync(HISTORY_FILE)) {
258
+ return JSON.parse(readFileSync(HISTORY_FILE, 'utf-8'));
259
+ }
260
+ }
261
+ catch { /* ignore */ }
262
+ return [];
263
+ }
264
+ function saveHistory(history) {
265
+ try {
266
+ const dir = HISTORY_FILE.replace(/[/\\][^/\\]+$/, '');
267
+ mkdirSync(dir, { recursive: true });
268
+ writeFileSync(HISTORY_FILE, JSON.stringify(history), 'utf-8');
269
+ }
270
+ catch { /* ignore */ }
271
+ }
272
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * file_edit tool — Search-and-replace edit with confirmation.
3
+ */
4
+ export {};
@@ -0,0 +1,57 @@
1
+ /**
2
+ * file_edit tool — Search-and-replace edit with confirmation.
3
+ */
4
+ import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
5
+ import { resolve } from 'node:path';
6
+ import { registerTool } from './registry.js';
7
+ registerTool('file_edit', 'Edit a file by replacing an exact string match. Shows diff and requires confirmation.', {
8
+ type: 'object',
9
+ properties: {
10
+ path: { type: 'string', description: 'File path to edit' },
11
+ old_string: { type: 'string', description: 'Exact string to find and replace (must be unique in the file)' },
12
+ new_string: { type: 'string', description: 'Replacement string' },
13
+ },
14
+ required: ['path', 'old_string', 'new_string'],
15
+ }, true, async (args) => {
16
+ const filePath = resolve(String(args.path));
17
+ const oldStr = String(args.old_string);
18
+ const newStr = String(args.new_string);
19
+ if (!existsSync(filePath)) {
20
+ return { success: false, error: `File not found: ${filePath}` };
21
+ }
22
+ if (!statSync(filePath).isFile()) {
23
+ return { success: false, error: `Not a file: ${filePath}` };
24
+ }
25
+ let oldContent;
26
+ try {
27
+ oldContent = readFileSync(filePath, 'utf-8');
28
+ }
29
+ catch (e) {
30
+ return { success: false, error: `Cannot read file: ${e instanceof Error ? e.message : e}` };
31
+ }
32
+ if (oldStr === newStr) {
33
+ return { success: false, error: 'old_string and new_string are identical' };
34
+ }
35
+ const count = oldContent.split(oldStr).length - 1;
36
+ if (count === 0) {
37
+ return { success: false, error: 'old_string not found in file' };
38
+ }
39
+ if (count > 1) {
40
+ return { success: false, error: `old_string found ${count} times. Must be unique. Add more context.` };
41
+ }
42
+ const newContent = oldContent.replace(oldStr, newStr);
43
+ try {
44
+ writeFileSync(filePath, newContent, 'utf-8');
45
+ }
46
+ catch (e) {
47
+ return { success: false, error: `Cannot write file: ${e instanceof Error ? e.message : e}` };
48
+ }
49
+ return {
50
+ success: true,
51
+ path: filePath,
52
+ action: 'edited',
53
+ _old_content: oldContent,
54
+ _new_content: newContent,
55
+ };
56
+ });
57
+ //# sourceMappingURL=fileEdit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileEdit.js","sourceRoot":"","sources":["../../src/tools/fileEdit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * file_read tool — Read files with optional line ranges.
3
+ */
4
+ export {};
@@ -0,0 +1,53 @@
1
+ /**
2
+ * file_read tool — Read files with optional line ranges.
3
+ */
4
+ import { existsSync, openSync, readSync, closeSync, readFileSync, statSync } from 'node:fs';
5
+ import { resolve } from 'node:path';
6
+ import { registerTool } from './registry.js';
7
+ const MAX_FILE_SIZE = 2 * 1024 * 1024; // 2MB
8
+ registerTool('file_read', 'Read a file\'s contents. Supports optional line offset and limit.', {
9
+ type: 'object',
10
+ properties: {
11
+ path: { type: 'string', description: 'Absolute or relative file path to read' },
12
+ offset: { type: 'integer', description: 'Line number to start from (1-based). Default: 1' },
13
+ limit: { type: 'integer', description: 'Max number of lines to return. Default: all' },
14
+ },
15
+ required: ['path'],
16
+ }, false, async (args) => {
17
+ const filePath = resolve(String(args.path));
18
+ const offset = Number(args.offset) || 1;
19
+ const limit = Number(args.limit) || 0;
20
+ if (!existsSync(filePath)) {
21
+ return { success: false, error: `File not found: ${filePath}` };
22
+ }
23
+ const stat = statSync(filePath);
24
+ if (!stat.isFile()) {
25
+ return { success: false, error: `Not a file: ${filePath}` };
26
+ }
27
+ if (stat.size > MAX_FILE_SIZE) {
28
+ return { success: false, error: `File too large (${stat.size.toLocaleString()} bytes, max ${MAX_FILE_SIZE.toLocaleString()})` };
29
+ }
30
+ // Binary detection
31
+ const sample = Buffer.alloc(Math.min(8192, stat.size));
32
+ const fd = openSync(filePath, 'r');
33
+ readSync(fd, sample, 0, sample.length, 0);
34
+ closeSync(fd);
35
+ if (sample.includes(0)) {
36
+ return { success: false, error: 'Binary file detected. Cannot read as text.' };
37
+ }
38
+ const content = readFileSync(filePath, 'utf-8');
39
+ const allLines = content.split('\n');
40
+ const totalLines = allLines.length;
41
+ const start = Math.max(1, offset) - 1;
42
+ const end = limit > 0 ? Math.min(start + limit, totalLines) : totalLines;
43
+ const selected = allLines.slice(start, end);
44
+ const numbered = selected.map((line, i) => `${String(start + i + 1).padStart(6)}\t${line}`).join('\n');
45
+ return {
46
+ success: true,
47
+ path: filePath,
48
+ content: numbered,
49
+ total_lines: totalLines,
50
+ lines_shown: `${start + 1}-${end}`,
51
+ };
52
+ });
53
+ //# sourceMappingURL=fileRead.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileRead.js","sourceRoot":"","sources":["../../src/tools/fileRead.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * file_search tool — Glob patterns and content grep.
3
+ */
4
+ export {};
@@ -0,0 +1,113 @@
1
+ /**
2
+ * file_search tool — Glob patterns and content grep.
3
+ */
4
+ import { readdirSync, readFileSync, statSync } from 'node:fs';
5
+ import { join, relative, resolve } from 'node:path';
6
+ import { minimatch } from 'minimatch';
7
+ import { registerTool } from './registry.js';
8
+ const SKIP_DIRS = new Set([
9
+ '.git', 'node_modules', '__pycache__', '.venv', 'venv',
10
+ '.tox', '.mypy_cache', '.pytest_cache', 'dist', 'build',
11
+ '.idea', '.vscode', '.eggs',
12
+ ]);
13
+ const MAX_FILES = 100;
14
+ const MAX_CONTENT_MATCHES = 50;
15
+ function walkDir(base, pattern, maxFiles) {
16
+ const results = [];
17
+ function walk(dir) {
18
+ if (results.length >= maxFiles)
19
+ return;
20
+ let entries;
21
+ try {
22
+ entries = readdirSync(dir, { withFileTypes: true });
23
+ }
24
+ catch {
25
+ return;
26
+ }
27
+ for (const entry of entries) {
28
+ if (results.length >= maxFiles)
29
+ return;
30
+ if (entry.isDirectory()) {
31
+ if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith('.')) {
32
+ walk(join(dir, entry.name));
33
+ }
34
+ }
35
+ else if (entry.isFile()) {
36
+ const rel = relative(base, join(dir, entry.name)).replace(/\\/g, '/');
37
+ if (minimatch(rel, pattern)) {
38
+ results.push(rel);
39
+ }
40
+ }
41
+ }
42
+ }
43
+ walk(base);
44
+ return results;
45
+ }
46
+ registerTool('file_search', 'Search for files by glob pattern and optionally grep content with regex.', {
47
+ type: 'object',
48
+ properties: {
49
+ pattern: { type: 'string', description: "Glob pattern for file names (e.g. '**/*.py', 'src/**/*.ts')" },
50
+ path: { type: 'string', description: 'Directory to search in. Default: current directory' },
51
+ content: { type: 'string', description: 'Regex pattern to search within matching files' },
52
+ },
53
+ required: ['pattern'],
54
+ }, false, async (args) => {
55
+ const base = resolve(String(args.path || '.'));
56
+ const pattern = String(args.pattern);
57
+ const contentPattern = args.content ? String(args.content) : '';
58
+ try {
59
+ statSync(base);
60
+ }
61
+ catch {
62
+ return { success: false, error: `Directory not found: ${base}` };
63
+ }
64
+ const files = walkDir(base, pattern, MAX_FILES);
65
+ if (!contentPattern) {
66
+ return {
67
+ success: true,
68
+ files,
69
+ count: files.length,
70
+ truncated: files.length >= MAX_FILES,
71
+ };
72
+ }
73
+ let regex;
74
+ try {
75
+ regex = new RegExp(contentPattern, 'i');
76
+ }
77
+ catch (e) {
78
+ return { success: false, error: `Invalid regex: ${e instanceof Error ? e.message : e}` };
79
+ }
80
+ const contentMatches = [];
81
+ for (const rel of files) {
82
+ if (contentMatches.length >= MAX_CONTENT_MATCHES)
83
+ break;
84
+ const full = join(base, rel);
85
+ try {
86
+ const text = readFileSync(full, 'utf-8');
87
+ const lines = text.split('\n');
88
+ for (let i = 0; i < lines.length; i++) {
89
+ if (regex.test(lines[i])) {
90
+ contentMatches.push({
91
+ file: rel,
92
+ line: i + 1,
93
+ text: lines[i].slice(0, 200),
94
+ });
95
+ if (contentMatches.length >= MAX_CONTENT_MATCHES)
96
+ break;
97
+ }
98
+ }
99
+ }
100
+ catch {
101
+ continue;
102
+ }
103
+ }
104
+ return {
105
+ success: true,
106
+ files,
107
+ file_count: files.length,
108
+ content_matches: contentMatches,
109
+ match_count: contentMatches.length,
110
+ truncated: contentMatches.length >= MAX_CONTENT_MATCHES,
111
+ };
112
+ });
113
+ //# sourceMappingURL=fileSearch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileSearch.js","sourceRoot":"","sources":["../../src/tools/fileSearch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * file_write tool — Write/create files with confirmation.
3
+ */
4
+ export {};
@@ -0,0 +1,47 @@
1
+ /**
2
+ * file_write tool — Write/create files with confirmation.
3
+ */
4
+ import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
5
+ import { dirname, resolve } from 'node:path';
6
+ import { registerTool } from './registry.js';
7
+ registerTool('file_write', 'Write content to a file. Creates parent directories if needed. Requires confirmation.', {
8
+ type: 'object',
9
+ properties: {
10
+ path: { type: 'string', description: 'File path to write to (absolute or relative)' },
11
+ content: { type: 'string', description: 'The full content to write to the file' },
12
+ },
13
+ required: ['path', 'content'],
14
+ }, true, async (args) => {
15
+ const filePath = resolve(String(args.path));
16
+ const content = String(args.content);
17
+ let oldContent = null;
18
+ if (existsSync(filePath)) {
19
+ if (!statSync(filePath).isFile()) {
20
+ return { success: false, error: `Not a file: ${filePath}` };
21
+ }
22
+ try {
23
+ oldContent = readFileSync(filePath, 'utf-8');
24
+ }
25
+ catch { /* ignore */ }
26
+ }
27
+ const parent = dirname(filePath);
28
+ if (parent)
29
+ mkdirSync(parent, { recursive: true });
30
+ try {
31
+ writeFileSync(filePath, content, 'utf-8');
32
+ }
33
+ catch (e) {
34
+ return { success: false, error: `Cannot write file: ${e instanceof Error ? e.message : e}` };
35
+ }
36
+ const lines = content.split('\n').length;
37
+ return {
38
+ success: true,
39
+ path: filePath,
40
+ action: oldContent !== null ? 'updated' : 'created',
41
+ lines,
42
+ size: Buffer.byteLength(content, 'utf-8'),
43
+ _old_content: oldContent,
44
+ _new_content: content,
45
+ };
46
+ });
47
+ //# sourceMappingURL=fileWrite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileWrite.js","sourceRoot":"","sources":["../../src/tools/fileWrite.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACvF,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,YAAY,CACV,YAAY,EACZ,uFAAuF,EACvF;IACE,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,8CAA8C,EAAE;QACrF,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uCAAuC,EAAE;KAClF;IACD,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;CAC9B,EACD,IAAI,EACJ,KAAK,EAAE,IAAI,EAAE,EAAE;IACb,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAErC,IAAI,UAAU,GAAkB,IAAI,CAAC;IACrC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;YACjC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,QAAQ,EAAE,EAAE,CAAC;QAC9D,CAAC;QACD,IAAI,CAAC;YACH,UAAU,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjC,IAAI,MAAM;QAAE,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEnD,IAAI,CAAC;QACH,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,CAAU,EAAE,CAAC;QACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAC/F,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;IACzC,OAAO;QACL,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QACnD,KAAK;QACL,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC;QACzC,YAAY,EAAE,UAAU;QACxB,YAAY,EAAE,OAAO;KACtB,CAAC;AACJ,CAAC,CACF,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Local tool registry for QafAI CLI Agent.
3
+ * Re-exports registry functions and triggers tool registration via side-effect imports.
4
+ */
5
+ export { type ToolParams, type ToolDef, type ToolResult, registerTool, executeTool, toolRequiresConfirmation, getToolsPrompt, getToolsList, } from './registry.js';
6
+ import './fileRead.js';
7
+ import './fileSearch.js';
8
+ import './fileWrite.js';
9
+ import './fileEdit.js';
10
+ import './shellExec.js';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Local tool registry for QafAI CLI Agent.
3
+ * Re-exports registry functions and triggers tool registration via side-effect imports.
4
+ */
5
+ // Re-export everything from registry (no circular dep issues)
6
+ export { registerTool, executeTool, toolRequiresConfirmation, getToolsPrompt, getToolsList, } from './registry.js';
7
+ // Side-effect imports: each tool file calls registerTool() on load
8
+ import './fileRead.js';
9
+ import './fileSearch.js';
10
+ import './fileWrite.js';
11
+ import './fileEdit.js';
12
+ import './shellExec.js';
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,8DAA8D;AAC9D,OAAO,EAIL,YAAY,EACZ,WAAW,EACX,wBAAwB,EACxB,cAAc,EACd,YAAY,GACb,MAAM,eAAe,CAAC;AAEvB,mEAAmE;AACnE,OAAO,eAAe,CAAC;AACvB,OAAO,iBAAiB,CAAC;AACzB,OAAO,gBAAgB,CAAC;AACxB,OAAO,eAAe,CAAC;AACvB,OAAO,gBAAgB,CAAC"}