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/bin/qaf.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../dist/index.js';
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Client-side agent loop for QafAI CLI.
3
+ * Mirrors backend/agent.py: tool_call parsing, result formatting, context compression.
4
+ * All tool execution happens locally on the user's machine.
5
+ */
6
+ import { QafClient } from './client.js';
7
+ export declare class AgentLoop {
8
+ private client;
9
+ private model;
10
+ private temperature;
11
+ private contextLimit;
12
+ private messages;
13
+ private iteration;
14
+ private totalToolCalls;
15
+ private toolsUsed;
16
+ private autoConfirm;
17
+ constructor(client: QafClient, model?: string, temperature?: number, contextLimit?: number);
18
+ setModel(model: string): void;
19
+ clearHistory(): void;
20
+ run(userMessage: string): Promise<void>;
21
+ private confirmTool;
22
+ private estimateTokens;
23
+ private compressIfNeeded;
24
+ }
package/dist/agent.js ADDED
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Client-side agent loop for QafAI CLI.
3
+ * Mirrors backend/agent.py: tool_call parsing, result formatting, context compression.
4
+ * All tool execution happens locally on the user's machine.
5
+ */
6
+ import { readFileSync, existsSync } from 'node:fs';
7
+ import { resolve } from 'node:path';
8
+ import { loadConfig } from './config.js';
9
+ import { executeTool, getToolsPrompt, toolRequiresConfirmation } from './tools/index.js';
10
+ import * as ui from './ui.js';
11
+ // Same regex as backend/agent.py
12
+ const TOOL_CALL_PATTERN = /<tool_call>\s*([\s\S]*?)\s*<\/tool_call>/g;
13
+ // Agent limits
14
+ const MAX_ITERATIONS = 10;
15
+ const MAX_TOOL_CALLS = 30;
16
+ const TIMEOUT = 180; // seconds
17
+ function parseToolCalls(text) {
18
+ const calls = [];
19
+ TOOL_CALL_PATTERN.lastIndex = 0;
20
+ let match;
21
+ while ((match = TOOL_CALL_PATTERN.exec(text)) !== null) {
22
+ try {
23
+ const data = JSON.parse(match[1]);
24
+ if (data.name) {
25
+ calls.push({
26
+ name: data.name,
27
+ arguments: data.arguments || {},
28
+ raw: match[0],
29
+ });
30
+ }
31
+ }
32
+ catch {
33
+ continue;
34
+ }
35
+ }
36
+ return calls;
37
+ }
38
+ function buildSystemPrompt() {
39
+ return `You are QafAI Agent, an AI coding assistant running on the user's local machine.
40
+ You can read, write, and edit files, search the codebase, and run shell commands.
41
+
42
+ Working directory: ${process.cwd()}
43
+
44
+ ## Available Tools
45
+
46
+ To use a tool, write a tool call in this exact format:
47
+ <tool_call>{"name": "tool_name", "arguments": {"param": "value"}}</tool_call>
48
+
49
+ ${getToolsPrompt()}
50
+
51
+ ## Rules
52
+ 1. Use tools when needed to accomplish the user's request
53
+ 2. You can use multiple tools in one response
54
+ 3. Wait for tool results before giving your final answer
55
+ 4. After getting tool results, provide a helpful summary
56
+ 5. Don't repeat tool results verbatim — summarize and explain
57
+ 6. If a tool fails, inform the user and try another approach
58
+ 7. For file edits, provide enough context in old_string to ensure uniqueness
59
+ 8. Always use absolute paths or paths relative to the working directory
60
+ 9. Prefer reading files before editing them to understand context`;
61
+ }
62
+ export class AgentLoop {
63
+ client;
64
+ model;
65
+ temperature;
66
+ contextLimit;
67
+ messages;
68
+ iteration = 0;
69
+ totalToolCalls = 0;
70
+ toolsUsed = [];
71
+ autoConfirm;
72
+ constructor(client, model, temperature = 0.7, contextLimit = 131072) {
73
+ this.client = client;
74
+ this.model = model;
75
+ this.temperature = temperature;
76
+ this.contextLimit = contextLimit;
77
+ this.autoConfirm = loadConfig().auto_confirm;
78
+ this.messages = [{ role: 'system', content: buildSystemPrompt() }];
79
+ }
80
+ setModel(model) {
81
+ this.model = model;
82
+ }
83
+ clearHistory() {
84
+ const system = this.messages[0];
85
+ this.messages = system ? [system] : [{ role: 'system', content: buildSystemPrompt() }];
86
+ this.iteration = 0;
87
+ this.totalToolCalls = 0;
88
+ this.toolsUsed = [];
89
+ }
90
+ async run(userMessage) {
91
+ this.messages.push({ role: 'user', content: userMessage });
92
+ const startTime = Date.now();
93
+ this.iteration = 0;
94
+ this.totalToolCalls = 0;
95
+ this.toolsUsed = [];
96
+ while (this.iteration < MAX_ITERATIONS) {
97
+ // Timeout
98
+ if ((Date.now() - startTime) / 1000 >= TIMEOUT) {
99
+ ui.showError('Agent timeout reached.');
100
+ break;
101
+ }
102
+ // Compress context if needed
103
+ this.compressIfNeeded();
104
+ this.iteration++;
105
+ // Call model and stream response
106
+ ui.startThinking();
107
+ let fullResponse = '';
108
+ let hadError = false;
109
+ try {
110
+ for await (const event of this.client.streamInference(this.messages, this.model, this.temperature)) {
111
+ if (event.chunk) {
112
+ fullResponse += event.chunk;
113
+ ui.writeChunk(event.chunk);
114
+ }
115
+ else if (event.error) {
116
+ ui.stopThinking();
117
+ ui.showError(event.error);
118
+ hadError = true;
119
+ break;
120
+ }
121
+ else if (event.done) {
122
+ break;
123
+ }
124
+ }
125
+ }
126
+ catch (err) {
127
+ ui.stopThinking();
128
+ ui.showError(err instanceof Error ? err.message : String(err));
129
+ break;
130
+ }
131
+ ui.finishResponse();
132
+ if (hadError)
133
+ break;
134
+ // Parse tool calls
135
+ const toolCalls = parseToolCalls(fullResponse);
136
+ if (toolCalls.length === 0) {
137
+ // No tools — final answer
138
+ break;
139
+ }
140
+ // Append assistant message
141
+ this.messages.push({ role: 'assistant', content: fullResponse });
142
+ // Execute tools
143
+ const toolResultTexts = [];
144
+ for (const call of toolCalls) {
145
+ if (this.totalToolCalls >= MAX_TOOL_CALLS) {
146
+ ui.showError('Max tool calls reached.');
147
+ break;
148
+ }
149
+ ui.showToolCall(call.name, call.arguments);
150
+ // Confirmation flow
151
+ if (toolRequiresConfirmation(call.name) && !this.autoConfirm) {
152
+ const approved = await this.confirmTool(call.name, call.arguments);
153
+ if (!approved) {
154
+ const result = { success: false, error: 'User rejected this action.' };
155
+ ui.showToolResult(call.name, result);
156
+ toolResultTexts.push(`<tool_result name="${call.name}">\n${JSON.stringify(result)}\n</tool_result>`);
157
+ this.totalToolCalls++;
158
+ this.toolsUsed.push(call.name);
159
+ continue;
160
+ }
161
+ }
162
+ // Execute
163
+ this.totalToolCalls++;
164
+ this.toolsUsed.push(call.name);
165
+ const result = await executeTool(call.name, call.arguments);
166
+ ui.showToolResult(call.name, result);
167
+ // Clean internal fields
168
+ const clean = {};
169
+ for (const [k, v] of Object.entries(result)) {
170
+ if (!k.startsWith('_'))
171
+ clean[k] = v;
172
+ }
173
+ let resultText = JSON.stringify(clean);
174
+ if (resultText.length > 4000)
175
+ resultText = resultText.slice(0, 4000) + '...';
176
+ toolResultTexts.push(`<tool_result name="${call.name}">\n${resultText}\n</tool_result>`);
177
+ }
178
+ // Feed results back
179
+ if (toolResultTexts.length > 0) {
180
+ this.messages.push({
181
+ role: 'user',
182
+ content: toolResultTexts.join('\n\n')
183
+ + '\n\nBased on the tool results above, provide your response. Only use another tool if necessary.',
184
+ });
185
+ }
186
+ if (this.totalToolCalls >= MAX_TOOL_CALLS)
187
+ break;
188
+ }
189
+ const duration = (Date.now() - startTime) / 1000;
190
+ if (this.totalToolCalls > 0) {
191
+ ui.showAgentDone(this.iteration, this.totalToolCalls, duration);
192
+ }
193
+ }
194
+ async confirmTool(name, args) {
195
+ if (name === 'shell_exec') {
196
+ return ui.showCommandConfirm(String(args.command || ''));
197
+ }
198
+ if (name === 'file_write' || name === 'file_edit') {
199
+ const path = String(args.path || '');
200
+ if (!path)
201
+ return ui.confirm(`Allow ${name}?`);
202
+ const absPath = resolve(path);
203
+ let oldContent = null;
204
+ if (existsSync(absPath)) {
205
+ try {
206
+ oldContent = readFileSync(absPath, 'utf-8');
207
+ }
208
+ catch { /* */ }
209
+ }
210
+ if (name === 'file_write') {
211
+ return ui.showFileDiff(absPath, oldContent, String(args.content || ''));
212
+ }
213
+ if (name === 'file_edit' && oldContent !== null) {
214
+ const oldStr = String(args.old_string || '');
215
+ const newStr = String(args.new_string || '');
216
+ if (oldContent.includes(oldStr)) {
217
+ const preview = oldContent.replace(oldStr, newStr);
218
+ return ui.showFileDiff(absPath, oldContent, preview);
219
+ }
220
+ }
221
+ return ui.confirm(`Allow ${name} on ${path}?`);
222
+ }
223
+ return ui.confirm(`Allow ${name}?`);
224
+ }
225
+ estimateTokens(text) {
226
+ let arabic = 0;
227
+ for (const c of text) {
228
+ if (c >= '\u0600' && c <= '\u06FF')
229
+ arabic++;
230
+ }
231
+ return arabic + Math.floor((text.length - arabic) / 4);
232
+ }
233
+ compressIfNeeded() {
234
+ const threshold = Math.floor(this.contextLimit * 0.7);
235
+ let total = 0;
236
+ for (const m of this.messages) {
237
+ total += this.estimateTokens(m.content);
238
+ }
239
+ if (total <= threshold || this.messages.length <= 5)
240
+ return;
241
+ const system = this.messages[0];
242
+ const middle = this.messages.slice(1, -4);
243
+ const recent = this.messages.slice(-4);
244
+ const summaryParts = middle.slice(-6).map(m => `[${m.role}]: ${m.content.slice(0, 200)}`);
245
+ const summary = 'Previous conversation summary:\n' + summaryParts.join('\n');
246
+ this.messages = [
247
+ system,
248
+ { role: 'user', content: summary },
249
+ { role: 'assistant', content: 'Understood. I\'ll continue helping.' },
250
+ ...recent,
251
+ ];
252
+ }
253
+ }
254
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * HTTP client for QafAI inference API.
3
+ * SSE streaming via native fetch, manual event parsing.
4
+ */
5
+ export declare class QafClientError extends Error {
6
+ statusCode: number;
7
+ constructor(message: string, statusCode?: number);
8
+ }
9
+ export interface SSEEvent {
10
+ chunk?: string;
11
+ done?: boolean;
12
+ error?: string;
13
+ }
14
+ export declare class QafClient {
15
+ private serverUrl;
16
+ private apiKey;
17
+ constructor(serverUrl?: string, apiKey?: string);
18
+ private get headers();
19
+ streamInference(messages: Array<{
20
+ role: string;
21
+ content: string;
22
+ }>, model?: string, temperature?: number, maxTokens?: number): AsyncGenerator<SSEEvent>;
23
+ listModels(): Promise<{
24
+ models: Array<Record<string, unknown>>;
25
+ default: string;
26
+ }>;
27
+ healthCheck(): Promise<boolean>;
28
+ }
package/dist/client.js ADDED
@@ -0,0 +1,140 @@
1
+ /**
2
+ * HTTP client for QafAI inference API.
3
+ * SSE streaming via native fetch, manual event parsing.
4
+ */
5
+ import { getApiKey, getServerUrl } from './config.js';
6
+ export class QafClientError extends Error {
7
+ statusCode;
8
+ constructor(message, statusCode = 0) {
9
+ super(message);
10
+ this.statusCode = statusCode;
11
+ this.name = 'QafClientError';
12
+ }
13
+ }
14
+ export class QafClient {
15
+ serverUrl;
16
+ apiKey;
17
+ constructor(serverUrl, apiKey) {
18
+ this.serverUrl = serverUrl || getServerUrl();
19
+ this.apiKey = apiKey || getApiKey();
20
+ }
21
+ get headers() {
22
+ return {
23
+ 'Authorization': `Bearer ${this.apiKey}`,
24
+ 'Content-Type': 'application/json',
25
+ 'User-Agent': 'qaf-agent/0.1.0',
26
+ 'Accept': 'text/event-stream',
27
+ };
28
+ }
29
+ async *streamInference(messages, model, temperature = 0.7, maxTokens) {
30
+ const payload = { messages, temperature };
31
+ if (model)
32
+ payload.model = model;
33
+ if (maxTokens)
34
+ payload.max_tokens = maxTokens;
35
+ let response;
36
+ try {
37
+ response = await fetch(`${this.serverUrl}/api/inference`, {
38
+ method: 'POST',
39
+ headers: this.headers,
40
+ body: JSON.stringify(payload),
41
+ signal: AbortSignal.timeout(120_000),
42
+ });
43
+ }
44
+ catch (err) {
45
+ const msg = err instanceof Error ? err.message : String(err);
46
+ if (msg.includes('fetch failed') || msg.includes('ECONNREFUSED')) {
47
+ throw new QafClientError(`Cannot connect to ${this.serverUrl}. Check your server URL and network.`);
48
+ }
49
+ if (msg.includes('TimeoutError') || msg.includes('aborted')) {
50
+ throw new QafClientError('Request timed out. The server may be overloaded.');
51
+ }
52
+ throw new QafClientError(`Connection error: ${msg}`);
53
+ }
54
+ if (response.status === 401) {
55
+ throw new QafClientError("Invalid API key. Run 'qaf init' to configure.", 401);
56
+ }
57
+ if (response.status === 429) {
58
+ throw new QafClientError('Rate limit exceeded. Please wait.', 429);
59
+ }
60
+ if (response.status >= 400) {
61
+ let detail = 'Server error';
62
+ try {
63
+ const body = await response.json();
64
+ detail = body.detail || detail;
65
+ }
66
+ catch { /* ignore */ }
67
+ throw new QafClientError(`HTTP ${response.status}: ${detail}`, response.status);
68
+ }
69
+ if (!response.body) {
70
+ throw new QafClientError('Empty response body');
71
+ }
72
+ const reader = response.body.getReader();
73
+ const decoder = new TextDecoder();
74
+ let buffer = '';
75
+ try {
76
+ while (true) {
77
+ const { done, value } = await reader.read();
78
+ if (done)
79
+ break;
80
+ buffer += decoder.decode(value, { stream: true });
81
+ while (buffer.includes('\n\n')) {
82
+ const idx = buffer.indexOf('\n\n');
83
+ const eventStr = buffer.slice(0, idx);
84
+ buffer = buffer.slice(idx + 2);
85
+ for (const line of eventStr.split('\n')) {
86
+ const trimmed = line.trim();
87
+ if (!trimmed.startsWith('data: '))
88
+ continue;
89
+ const dataStr = trimmed.slice(6);
90
+ if (dataStr === '[DONE]') {
91
+ yield { done: true };
92
+ return;
93
+ }
94
+ try {
95
+ const data = JSON.parse(dataStr);
96
+ yield data;
97
+ if (data.done)
98
+ return;
99
+ }
100
+ catch {
101
+ continue;
102
+ }
103
+ }
104
+ }
105
+ }
106
+ }
107
+ finally {
108
+ reader.releaseLock();
109
+ }
110
+ }
111
+ async listModels() {
112
+ let response;
113
+ try {
114
+ response = await fetch(`${this.serverUrl}/api/inference/models`, {
115
+ headers: this.headers,
116
+ signal: AbortSignal.timeout(10_000),
117
+ });
118
+ }
119
+ catch {
120
+ throw new QafClientError(`Cannot connect to ${this.serverUrl}`);
121
+ }
122
+ if (response.status === 401)
123
+ throw new QafClientError('Invalid API key.', 401);
124
+ if (response.status >= 400)
125
+ throw new QafClientError(`HTTP ${response.status}`, response.status);
126
+ return response.json();
127
+ }
128
+ async healthCheck() {
129
+ try {
130
+ const res = await fetch(`${this.serverUrl}/api/health`, {
131
+ signal: AbortSignal.timeout(5_000),
132
+ });
133
+ return res.status === 200;
134
+ }
135
+ catch {
136
+ return false;
137
+ }
138
+ }
139
+ }
140
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,OAAO,cAAe,SAAQ,KAAK;IACH;IAApC,YAAY,OAAe,EAAS,aAAqB,CAAC;QACxD,KAAK,CAAC,OAAO,CAAC,CAAC;QADmB,eAAU,GAAV,UAAU,CAAY;QAExD,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAQD,MAAM,OAAO,SAAS;IACZ,SAAS,CAAS;IAClB,MAAM,CAAS;IAEvB,YAAY,SAAkB,EAAE,MAAe;QAC7C,IAAI,CAAC,SAAS,GAAG,SAAS,IAAI,YAAY,EAAE,CAAC;QAC7C,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,SAAS,EAAE,CAAC;IACtC,CAAC;IAED,IAAY,OAAO;QACjB,OAAO;YACL,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;YACxC,cAAc,EAAE,kBAAkB;YAClC,YAAY,EAAE,iBAAiB;YAC/B,QAAQ,EAAE,mBAAmB;SAC9B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,CAAC,eAAe,CACpB,QAAkD,EAClD,KAAc,EACd,WAAW,GAAG,GAAG,EACjB,SAAkB;QAElB,MAAM,OAAO,GAA4B,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;QACnE,IAAI,KAAK;YAAE,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC;QACjC,IAAI,SAAS;YAAE,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;QAE9C,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,gBAAgB,EAAE;gBACxD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;gBAC7B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC;aACrC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,IAAI,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;gBACjE,MAAM,IAAI,cAAc,CAAC,qBAAqB,IAAI,CAAC,SAAS,sCAAsC,CAAC,CAAC;YACtG,CAAC;YACD,IAAI,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC5D,MAAM,IAAI,cAAc,CAAC,kDAAkD,CAAC,CAAC;YAC/E,CAAC;YACD,MAAM,IAAI,cAAc,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,MAAM,IAAI,cAAc,CAAC,+CAA+C,EAAE,GAAG,CAAC,CAAC;QACjF,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,MAAM,IAAI,cAAc,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;QACrE,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;YAC3B,IAAI,MAAM,GAAG,cAAc,CAAC;YAC5B,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAyB,CAAC;gBAC1D,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC;YACjC,CAAC;YAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;YACxB,MAAM,IAAI,cAAc,CAAC,QAAQ,QAAQ,CAAC,MAAM,KAAK,MAAM,EAAE,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QAClF,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnB,MAAM,IAAI,cAAc,CAAC,qBAAqB,CAAC,CAAC;QAClD,CAAC;QAED,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;QAClC,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,IAAI,CAAC;YACH,OAAO,IAAI,EAAE,CAAC;gBACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;gBAC5C,IAAI,IAAI;oBAAE,MAAM;gBAEhB,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;gBAElD,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC/B,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;oBACnC,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;oBACtC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;oBAE/B,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;wBACxC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;wBAC5B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;4BAAE,SAAS;wBAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;wBACjC,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;4BACzB,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;4BACrB,OAAO;wBACT,CAAC;wBACD,IAAI,CAAC;4BACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAa,CAAC;4BAC7C,MAAM,IAAI,CAAC;4BACX,IAAI,IAAI,CAAC,IAAI;gCAAE,OAAO;wBACxB,CAAC;wBAAC,MAAM,CAAC;4BACP,SAAS;wBACX,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,WAAW,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU;QACd,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,uBAAuB,EAAE;gBAC/D,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;aACpC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,cAAc,CAAC,qBAAqB,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG;YAAE,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;QAC/E,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG;YAAE,MAAM,IAAI,cAAc,CAAC,QAAQ,QAAQ,CAAC,MAAM,EAAE,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;QACjG,OAAO,QAAQ,CAAC,IAAI,EAA0E,CAAC;IACjG,CAAC;IAED,KAAK,CAAC,WAAW;QACf,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,aAAa,EAAE;gBACtD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC;aACnC,CAAC,CAAC;YACH,OAAO,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Config management for QafAI CLI Agent.
3
+ * Manages ~/.qafai/config.json with server URL, API key, model preferences.
4
+ */
5
+ export interface Config {
6
+ server_url: string;
7
+ api_key: string;
8
+ model: string;
9
+ temperature: number;
10
+ max_iterations: number;
11
+ timeout: number;
12
+ auto_confirm: boolean;
13
+ }
14
+ export declare const HISTORY_FILE: string;
15
+ export declare function loadConfig(): Config;
16
+ export declare function saveConfig(config: Partial<Config>): void;
17
+ export declare function getApiKey(): string;
18
+ export declare function getServerUrl(): string;
19
+ export declare function getModel(): string;
20
+ export declare function isConfigured(): boolean;
package/dist/config.js ADDED
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Config management for QafAI CLI Agent.
3
+ * Manages ~/.qafai/config.json with server URL, API key, model preferences.
4
+ */
5
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from 'node:fs';
6
+ import { homedir } from 'node:os';
7
+ import { join } from 'node:path';
8
+ const CONFIG_DIR = join(homedir(), '.qafai');
9
+ const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
10
+ export const HISTORY_FILE = join(CONFIG_DIR, 'history.json');
11
+ const DEFAULTS = {
12
+ server_url: 'https://qafai.net',
13
+ api_key: '',
14
+ model: '',
15
+ temperature: 0.7,
16
+ max_iterations: 10,
17
+ timeout: 180,
18
+ auto_confirm: false,
19
+ };
20
+ function ensureConfigDir() {
21
+ if (!existsSync(CONFIG_DIR)) {
22
+ mkdirSync(CONFIG_DIR, { recursive: true });
23
+ }
24
+ }
25
+ export function loadConfig() {
26
+ const config = { ...DEFAULTS };
27
+ if (existsSync(CONFIG_FILE)) {
28
+ try {
29
+ const stored = JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));
30
+ Object.assign(config, stored);
31
+ }
32
+ catch {
33
+ // Ignore corrupt config
34
+ }
35
+ }
36
+ return config;
37
+ }
38
+ export function saveConfig(config) {
39
+ ensureConfigDir();
40
+ const current = loadConfig();
41
+ const merged = { ...current, ...config };
42
+ writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2), 'utf-8');
43
+ try {
44
+ chmodSync(CONFIG_FILE, 0o600);
45
+ }
46
+ catch {
47
+ // Windows may not support chmod
48
+ }
49
+ }
50
+ export function getApiKey() {
51
+ return process.env['QAFAI_API_KEY'] || loadConfig().api_key;
52
+ }
53
+ export function getServerUrl() {
54
+ const url = process.env['QAFAI_SERVER_URL'] || loadConfig().server_url || DEFAULTS.server_url;
55
+ return url.replace(/\/+$/, '');
56
+ }
57
+ export function getModel() {
58
+ return process.env['QAFAI_MODEL'] || loadConfig().model;
59
+ }
60
+ export function isConfigured() {
61
+ return !!getApiKey();
62
+ }
63
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAYjC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC7C,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AACpD,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;AAE7D,MAAM,QAAQ,GAAW;IACvB,UAAU,EAAE,mBAAmB;IAC/B,OAAO,EAAE,EAAE;IACX,KAAK,EAAE,EAAE;IACT,WAAW,EAAE,GAAG;IAChB,cAAc,EAAE,EAAE;IAClB,OAAO,EAAE,GAAG;IACZ,YAAY,EAAE,KAAK;CACpB,CAAC;AAEF,SAAS,eAAe;IACtB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;IAC/B,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;YAC9D,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAuB;IAChD,eAAe,EAAE,CAAC;IAClB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC;IACzC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACrE,IAAI,CAAC;QACH,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,gCAAgC;IAClC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,UAAU,EAAE,CAAC,OAAO,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,UAAU,EAAE,CAAC,UAAU,IAAI,QAAQ,CAAC,UAAU,CAAC;IAC9F,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,UAAU,EAAE,CAAC,KAAK,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC;AACvB,CAAC"}
@@ -0,0 +1,13 @@
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 './tools/index.js';