arki 0.0.4 → 0.0.6
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 +19 -3
- package/dist/config/.arki/config.json +3 -0
- package/dist/config/.arki/state.json +4 -0
- package/dist/index.d.ts +98 -37
- package/dist/index.js +844 -430
- package/package.json +1 -1
- /package/dist/config/{config.json → arki/config.json} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,385 +1,733 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
2
11
|
|
|
3
|
-
// src/
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import * as path5 from "path";
|
|
7
|
-
import * as os2 from "os";
|
|
8
|
-
|
|
9
|
-
// src/config/config.ts
|
|
10
|
-
import * as fs from "fs/promises";
|
|
11
|
-
import * as path from "path";
|
|
12
|
-
import * as os from "os";
|
|
12
|
+
// src/fs/paths.ts
|
|
13
|
+
import os from "os";
|
|
14
|
+
import path from "path";
|
|
13
15
|
import { fileURLToPath } from "url";
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
+
function getOSName() {
|
|
17
|
+
const platform = os.platform();
|
|
18
|
+
switch (platform) {
|
|
19
|
+
case "win32":
|
|
20
|
+
return "windows";
|
|
21
|
+
case "darwin":
|
|
22
|
+
return "mac";
|
|
23
|
+
case "linux":
|
|
24
|
+
return "linux";
|
|
25
|
+
default:
|
|
26
|
+
return "other";
|
|
27
|
+
}
|
|
16
28
|
}
|
|
17
|
-
function
|
|
29
|
+
function setWorkingDir(dir) {
|
|
30
|
+
workingDir = dir;
|
|
31
|
+
}
|
|
32
|
+
function getGlobalConfigDir() {
|
|
33
|
+
if (OS.name === "windows") {
|
|
34
|
+
return path.join(
|
|
35
|
+
process.env.APPDATA || path.join(os.homedir(), "AppData", "Roaming"),
|
|
36
|
+
"arki"
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return path.join(os.homedir(), ".config", "arki");
|
|
40
|
+
}
|
|
41
|
+
function getPackageDir(relativePath) {
|
|
18
42
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
19
|
-
return path.join(__dirname, "
|
|
43
|
+
return path.join(__dirname, "..", relativePath);
|
|
20
44
|
}
|
|
21
|
-
var
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
this.loadEnvApiKeys();
|
|
43
|
-
this.loaded = true;
|
|
44
|
-
return this.config;
|
|
45
|
+
var OS, workingDir, PATHS;
|
|
46
|
+
var init_paths = __esm({
|
|
47
|
+
"src/fs/paths.ts"() {
|
|
48
|
+
"use strict";
|
|
49
|
+
OS = {
|
|
50
|
+
name: getOSName(),
|
|
51
|
+
version: os.release()
|
|
52
|
+
};
|
|
53
|
+
workingDir = process.cwd();
|
|
54
|
+
PATHS = {
|
|
55
|
+
/** Global config directory (~/.config/arki or %APPDATA%\arki) */
|
|
56
|
+
globalConfig: getGlobalConfigDir(),
|
|
57
|
+
/** Project config directory (.arki/) - returns path based on current workingDir */
|
|
58
|
+
get projectConfig() {
|
|
59
|
+
return path.join(workingDir, ".arki");
|
|
60
|
+
},
|
|
61
|
+
/** Package's global config template directory */
|
|
62
|
+
globalTemplate: getPackageDir("config/arki"),
|
|
63
|
+
/** Package's project config template directory */
|
|
64
|
+
projectTemplate: getPackageDir("config/.arki")
|
|
65
|
+
};
|
|
45
66
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
if (process.env.ANTHROPIC_API_KEY && configToSave.apiKeys.anthropic === process.env.ANTHROPIC_API_KEY) {
|
|
58
|
-
delete configToSave.apiKeys.anthropic;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
await fs.writeFile(configPath, JSON.stringify(configToSave, null, 2), "utf-8");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// src/fs/file.ts
|
|
70
|
+
import * as fs from "fs/promises";
|
|
71
|
+
async function fileExists(filePath) {
|
|
72
|
+
try {
|
|
73
|
+
const stat3 = await fs.stat(filePath);
|
|
74
|
+
return stat3.isFile();
|
|
75
|
+
} catch {
|
|
76
|
+
return false;
|
|
62
77
|
}
|
|
63
|
-
|
|
64
|
-
|
|
78
|
+
}
|
|
79
|
+
async function readJsonFile(filePath) {
|
|
80
|
+
try {
|
|
81
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
82
|
+
return JSON.parse(content);
|
|
83
|
+
} catch {
|
|
84
|
+
return null;
|
|
65
85
|
}
|
|
66
|
-
|
|
67
|
-
|
|
86
|
+
}
|
|
87
|
+
async function writeJsonFile(filePath, data) {
|
|
88
|
+
await fs.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
89
|
+
}
|
|
90
|
+
async function readFile2(filePath) {
|
|
91
|
+
try {
|
|
92
|
+
return await fs.readFile(filePath, "utf-8");
|
|
93
|
+
} catch {
|
|
94
|
+
return null;
|
|
68
95
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
96
|
+
}
|
|
97
|
+
async function writeFile2(filePath, content) {
|
|
98
|
+
await fs.writeFile(filePath, content, "utf-8");
|
|
99
|
+
}
|
|
100
|
+
var init_file = __esm({
|
|
101
|
+
"src/fs/file.ts"() {
|
|
102
|
+
"use strict";
|
|
75
103
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (!this.config.apiKeys.google) {
|
|
92
|
-
this.config.apiKeys.google = process.env.GOOGLE_API_KEY;
|
|
93
|
-
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// src/fs/dir.ts
|
|
107
|
+
import * as fs2 from "fs/promises";
|
|
108
|
+
import * as path2 from "path";
|
|
109
|
+
async function copyDir(src, dest) {
|
|
110
|
+
await fs2.mkdir(dest, { recursive: true });
|
|
111
|
+
const entries = await fs2.readdir(src, { withFileTypes: true });
|
|
112
|
+
for (const entry of entries) {
|
|
113
|
+
const srcPath = path2.join(src, entry.name);
|
|
114
|
+
const destPath = path2.join(dest, entry.name);
|
|
115
|
+
if (entry.isDirectory()) {
|
|
116
|
+
await copyDir(srcPath, destPath);
|
|
117
|
+
} else {
|
|
118
|
+
await fs2.copyFile(srcPath, destPath);
|
|
94
119
|
}
|
|
95
120
|
}
|
|
96
|
-
}
|
|
97
|
-
|
|
121
|
+
}
|
|
122
|
+
async function dirExists(dirPath) {
|
|
123
|
+
try {
|
|
124
|
+
const stat3 = await fs2.stat(dirPath);
|
|
125
|
+
return stat3.isDirectory();
|
|
126
|
+
} catch {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function mkdir2(dirPath) {
|
|
131
|
+
await fs2.mkdir(dirPath, { recursive: true });
|
|
132
|
+
}
|
|
133
|
+
var init_dir = __esm({
|
|
134
|
+
"src/fs/dir.ts"() {
|
|
135
|
+
"use strict";
|
|
136
|
+
}
|
|
137
|
+
});
|
|
98
138
|
|
|
99
|
-
// src/
|
|
100
|
-
|
|
139
|
+
// src/fs/index.ts
|
|
140
|
+
var fs_exports = {};
|
|
141
|
+
__export(fs_exports, {
|
|
142
|
+
OS: () => OS,
|
|
143
|
+
PATHS: () => PATHS,
|
|
144
|
+
copyDir: () => copyDir,
|
|
145
|
+
dirExists: () => dirExists,
|
|
146
|
+
fileExists: () => fileExists,
|
|
147
|
+
mkdir: () => mkdir2,
|
|
148
|
+
readFile: () => readFile2,
|
|
149
|
+
readJsonFile: () => readJsonFile,
|
|
150
|
+
setWorkingDir: () => setWorkingDir,
|
|
151
|
+
workingDir: () => workingDir,
|
|
152
|
+
writeFile: () => writeFile2,
|
|
153
|
+
writeJsonFile: () => writeJsonFile
|
|
154
|
+
});
|
|
155
|
+
var init_fs = __esm({
|
|
156
|
+
"src/fs/index.ts"() {
|
|
157
|
+
"use strict";
|
|
158
|
+
init_paths();
|
|
159
|
+
init_file();
|
|
160
|
+
init_dir();
|
|
161
|
+
}
|
|
162
|
+
});
|
|
101
163
|
|
|
102
164
|
// src/adapter/Adapter.ts
|
|
103
|
-
var TEMPERATURE
|
|
104
|
-
var
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
165
|
+
var TEMPERATURE, MAX_COMPLETION_TOKENS, Adapter;
|
|
166
|
+
var init_Adapter = __esm({
|
|
167
|
+
"src/adapter/Adapter.ts"() {
|
|
168
|
+
"use strict";
|
|
169
|
+
TEMPERATURE = 0.2;
|
|
170
|
+
MAX_COMPLETION_TOKENS = 4096;
|
|
171
|
+
Adapter = class {
|
|
172
|
+
apiKey;
|
|
173
|
+
model;
|
|
174
|
+
/** Use Flex API (OpenAI) - low priority, low cost */
|
|
175
|
+
flex;
|
|
176
|
+
/** Reasoning effort (thinking mode) */
|
|
177
|
+
reasoningEffort;
|
|
178
|
+
/** Available tools list */
|
|
179
|
+
tools;
|
|
180
|
+
constructor(config) {
|
|
181
|
+
this.apiKey = config.apiKey;
|
|
182
|
+
this.model = config.model;
|
|
183
|
+
this.flex = config.flex;
|
|
184
|
+
this.reasoningEffort = config.reasoningEffort;
|
|
185
|
+
this.tools = config.tools;
|
|
186
|
+
}
|
|
187
|
+
getModel() {
|
|
188
|
+
return this.model;
|
|
189
|
+
}
|
|
190
|
+
};
|
|
123
191
|
}
|
|
124
|
-
};
|
|
192
|
+
});
|
|
125
193
|
|
|
126
194
|
// src/agent/Msg.ts
|
|
127
|
-
var MsgType
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
195
|
+
var MsgType, Msg, SystemMsg, UserMsg, AIMsg, ToolCallMsg, ToolResultMsg;
|
|
196
|
+
var init_Msg = __esm({
|
|
197
|
+
"src/agent/Msg.ts"() {
|
|
198
|
+
"use strict";
|
|
199
|
+
MsgType = /* @__PURE__ */ ((MsgType2) => {
|
|
200
|
+
MsgType2["System"] = "system";
|
|
201
|
+
MsgType2["User"] = "user";
|
|
202
|
+
MsgType2["AI"] = "ai";
|
|
203
|
+
MsgType2["ToolCall"] = "tool_call";
|
|
204
|
+
MsgType2["ToolResult"] = "tool_result";
|
|
205
|
+
return MsgType2;
|
|
206
|
+
})(MsgType || {});
|
|
207
|
+
Msg = class {
|
|
208
|
+
timestamp;
|
|
209
|
+
content;
|
|
210
|
+
constructor(content) {
|
|
211
|
+
this.timestamp = Date.now();
|
|
212
|
+
this.content = content;
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
SystemMsg = class extends Msg {
|
|
216
|
+
type = "system" /* System */;
|
|
217
|
+
constructor(content) {
|
|
218
|
+
super(content);
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
UserMsg = class extends Msg {
|
|
222
|
+
type = "user" /* User */;
|
|
223
|
+
constructor(content) {
|
|
224
|
+
super(content);
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
AIMsg = class extends Msg {
|
|
228
|
+
type = "ai" /* AI */;
|
|
229
|
+
constructor(content) {
|
|
230
|
+
super(content);
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
ToolCallMsg = class extends Msg {
|
|
234
|
+
type = "tool_call" /* ToolCall */;
|
|
235
|
+
toolCalls;
|
|
236
|
+
constructor(content, toolCalls) {
|
|
237
|
+
super(content);
|
|
238
|
+
this.toolCalls = toolCalls;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
ToolResultMsg = class _ToolResultMsg extends Msg {
|
|
242
|
+
type = "tool_result" /* ToolResult */;
|
|
243
|
+
toolResults;
|
|
244
|
+
constructor(toolResults) {
|
|
245
|
+
super("");
|
|
246
|
+
this.toolResults = toolResults;
|
|
247
|
+
}
|
|
248
|
+
/** Helper: create from single result */
|
|
249
|
+
static single(toolName, result, isError) {
|
|
250
|
+
return new _ToolResultMsg([{ toolName, result, isError }]);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
175
253
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// src/log/log.ts
|
|
257
|
+
function getTimestamp() {
|
|
258
|
+
return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
259
|
+
}
|
|
260
|
+
function print(message) {
|
|
261
|
+
console.log(convertColorTags(message));
|
|
262
|
+
}
|
|
263
|
+
function log(message) {
|
|
264
|
+
print(`<gray>[${getTimestamp()}]</gray> ${message}`);
|
|
265
|
+
}
|
|
266
|
+
function info(message) {
|
|
267
|
+
log(`<blue>[INFO]</blue> ${message}`);
|
|
268
|
+
}
|
|
269
|
+
function success(message) {
|
|
270
|
+
log(`<green>[OK]</green> ${message}`);
|
|
271
|
+
}
|
|
272
|
+
function warn(message) {
|
|
273
|
+
log(`<yellow>[WARN]</yellow> ${message}`);
|
|
274
|
+
}
|
|
275
|
+
function error(message) {
|
|
276
|
+
log(`<red>[ERROR]</red> ${message}`);
|
|
277
|
+
}
|
|
278
|
+
var init_log = __esm({
|
|
279
|
+
"src/log/log.ts"() {
|
|
280
|
+
"use strict";
|
|
281
|
+
init_log2();
|
|
179
282
|
}
|
|
180
|
-
};
|
|
283
|
+
});
|
|
181
284
|
|
|
182
285
|
// src/log/debug.ts
|
|
183
|
-
var _debugMode = false;
|
|
184
286
|
function isDebugMode() {
|
|
185
287
|
return _debugMode;
|
|
186
288
|
}
|
|
187
289
|
function setDebugMode(enabled) {
|
|
188
290
|
_debugMode = enabled;
|
|
189
291
|
}
|
|
292
|
+
function formatData(data, maxLen = 100) {
|
|
293
|
+
if (data === void 0) return "";
|
|
294
|
+
const str = typeof data === "string" ? data : JSON.stringify(data);
|
|
295
|
+
const singleLine = str.replace(/\s+/g, " ").trim();
|
|
296
|
+
return singleLine.length > maxLen ? singleLine.slice(0, maxLen) + "..." : singleLine;
|
|
297
|
+
}
|
|
190
298
|
function debug(category, message, data) {
|
|
191
299
|
if (!_debugMode) return;
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
console.log(`${prefix} ${colors.cyan}${message}${colors.reset}`);
|
|
195
|
-
if (data !== void 0) {
|
|
196
|
-
const dataStr = typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
197
|
-
const lines = dataStr.split("\n");
|
|
198
|
-
const maxLines = 20;
|
|
199
|
-
const truncated = lines.length > maxLines;
|
|
200
|
-
const displayLines = truncated ? lines.slice(-maxLines) : lines;
|
|
201
|
-
if (truncated) {
|
|
202
|
-
console.log(colors.dim + ` ... (${lines.length - maxLines} earlier lines)` + colors.reset);
|
|
203
|
-
}
|
|
204
|
-
console.log(colors.dim + displayLines.map((l) => ` ${l}`).join("\n") + colors.reset);
|
|
205
|
-
}
|
|
300
|
+
const dataStr = data !== void 0 ? ` <dim>${formatData(data)}</dim>` : "";
|
|
301
|
+
log(`<magenta>[${category}]</magenta> <cyan>${message}</cyan>${dataStr}`);
|
|
206
302
|
}
|
|
303
|
+
var _debugMode;
|
|
304
|
+
var init_debug = __esm({
|
|
305
|
+
"src/log/debug.ts"() {
|
|
306
|
+
"use strict";
|
|
307
|
+
init_log();
|
|
308
|
+
_debugMode = false;
|
|
309
|
+
}
|
|
310
|
+
});
|
|
207
311
|
|
|
208
|
-
// src/log/
|
|
209
|
-
function
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
console.log(`${colors.blue}\u2139${colors.reset} ${message}`);
|
|
214
|
-
}
|
|
215
|
-
function success(message) {
|
|
216
|
-
console.log(`${colors.green}\u2714${colors.reset} ${message}`);
|
|
217
|
-
}
|
|
218
|
-
function warn(message) {
|
|
219
|
-
console.log(`${colors.yellow}\u26A0${colors.reset} ${message}`);
|
|
312
|
+
// src/log/index.ts
|
|
313
|
+
function convertColorTags(str) {
|
|
314
|
+
return str.replace(tagRegex, (_, closing, tag) => {
|
|
315
|
+
return closing ? colors.reset : colors[tag.toLowerCase()] || "";
|
|
316
|
+
});
|
|
220
317
|
}
|
|
221
|
-
function
|
|
222
|
-
|
|
318
|
+
function createColorConverter() {
|
|
319
|
+
let buffer = "";
|
|
320
|
+
return (chunk) => {
|
|
321
|
+
buffer += chunk;
|
|
322
|
+
const lastOpen = buffer.lastIndexOf("<");
|
|
323
|
+
if (lastOpen === -1) {
|
|
324
|
+
const out2 = convertColorTags(buffer);
|
|
325
|
+
buffer = "";
|
|
326
|
+
return out2;
|
|
327
|
+
}
|
|
328
|
+
if (buffer.indexOf(">", lastOpen) !== -1) {
|
|
329
|
+
const out2 = convertColorTags(buffer);
|
|
330
|
+
buffer = "";
|
|
331
|
+
return out2;
|
|
332
|
+
}
|
|
333
|
+
const out = convertColorTags(buffer.slice(0, lastOpen));
|
|
334
|
+
buffer = buffer.slice(lastOpen);
|
|
335
|
+
return out;
|
|
336
|
+
};
|
|
223
337
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
338
|
+
var colors, tagNames, tagRegex;
|
|
339
|
+
var init_log2 = __esm({
|
|
340
|
+
"src/log/index.ts"() {
|
|
341
|
+
"use strict";
|
|
342
|
+
init_debug();
|
|
343
|
+
init_log();
|
|
344
|
+
colors = {
|
|
345
|
+
reset: "\x1B[0m",
|
|
346
|
+
bold: "\x1B[1m",
|
|
347
|
+
dim: "\x1B[2m",
|
|
348
|
+
italic: "\x1B[3m",
|
|
349
|
+
underline: "\x1B[4m",
|
|
350
|
+
inverse: "\x1B[7m",
|
|
351
|
+
strikethrough: "\x1B[9m",
|
|
352
|
+
red: "\x1B[31m",
|
|
353
|
+
green: "\x1B[32m",
|
|
354
|
+
yellow: "\x1B[33m",
|
|
355
|
+
blue: "\x1B[34m",
|
|
356
|
+
magenta: "\x1B[35m",
|
|
357
|
+
cyan: "\x1B[36m",
|
|
358
|
+
gray: "\x1B[90m"
|
|
359
|
+
};
|
|
360
|
+
tagNames = Object.keys(colors).filter((k) => k !== "reset").join("|");
|
|
361
|
+
tagRegex = new RegExp(`<(\\/?)(${tagNames})>`, "gi");
|
|
362
|
+
}
|
|
363
|
+
});
|
|
242
364
|
|
|
243
365
|
// src/adapter/openai.ts
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
result.push({ role: msg.type, content: msg.content });
|
|
259
|
-
} else if (msg.type === "ai" /* AI */) {
|
|
260
|
-
result.push({ role: "assistant", content: msg.content });
|
|
261
|
-
} else if (msg.type === "tool_call" /* ToolCall */) {
|
|
262
|
-
const toolCallMsg = msg;
|
|
263
|
-
pendingIds = toolCallMsg.toolCalls.map((_, i) => `call_${msg.timestamp}_${i}`);
|
|
264
|
-
result.push({
|
|
265
|
-
role: "assistant",
|
|
266
|
-
content: msg.content || null,
|
|
267
|
-
tool_calls: toolCallMsg.toolCalls.map((tc, i) => ({
|
|
268
|
-
id: pendingIds[i],
|
|
269
|
-
type: "function",
|
|
270
|
-
function: { name: tc.name, arguments: JSON.stringify(tc.arguments) }
|
|
271
|
-
}))
|
|
272
|
-
});
|
|
273
|
-
} else if (msg.type === "tool_result" /* ToolResult */) {
|
|
274
|
-
const toolResultMsg = msg;
|
|
275
|
-
for (const tr of toolResultMsg.toolResults) {
|
|
276
|
-
result.push({
|
|
277
|
-
role: "tool",
|
|
278
|
-
tool_call_id: pendingIds.shift() || `call_${msg.timestamp}`,
|
|
279
|
-
content: tr.isError ? `Error: ${tr.result}` : tr.result
|
|
280
|
-
});
|
|
366
|
+
import OpenAI from "openai";
|
|
367
|
+
var OpenAIAdapter;
|
|
368
|
+
var init_openai = __esm({
|
|
369
|
+
"src/adapter/openai.ts"() {
|
|
370
|
+
"use strict";
|
|
371
|
+
init_Adapter();
|
|
372
|
+
init_Msg();
|
|
373
|
+
init_log2();
|
|
374
|
+
OpenAIAdapter = class extends Adapter {
|
|
375
|
+
client;
|
|
376
|
+
constructor(config) {
|
|
377
|
+
super(config);
|
|
378
|
+
if (!this.apiKey) {
|
|
379
|
+
throw new Error("OpenAI API key is required. Set OPENAI_API_KEY environment variable.");
|
|
281
380
|
}
|
|
381
|
+
this.client = new OpenAI({ apiKey: this.apiKey });
|
|
282
382
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
383
|
+
toOpenAIMessages(messages) {
|
|
384
|
+
const result = [];
|
|
385
|
+
let pendingIds = [];
|
|
386
|
+
for (const msg of messages) {
|
|
387
|
+
if (msg.type === "system" /* System */ || msg.type === "user" /* User */) {
|
|
388
|
+
result.push({ role: msg.type, content: msg.content });
|
|
389
|
+
} else if (msg.type === "ai" /* AI */) {
|
|
390
|
+
result.push({ role: "assistant", content: msg.content });
|
|
391
|
+
} else if (msg.type === "tool_call" /* ToolCall */) {
|
|
392
|
+
const toolCallMsg = msg;
|
|
393
|
+
pendingIds = toolCallMsg.toolCalls.map((_, i) => `call_${msg.timestamp}_${i}`);
|
|
394
|
+
result.push({
|
|
395
|
+
role: "assistant",
|
|
396
|
+
content: msg.content || null,
|
|
397
|
+
tool_calls: toolCallMsg.toolCalls.map((tc, i) => ({
|
|
398
|
+
id: pendingIds[i],
|
|
399
|
+
type: "function",
|
|
400
|
+
function: { name: tc.name, arguments: JSON.stringify(tc.arguments) }
|
|
401
|
+
}))
|
|
402
|
+
});
|
|
403
|
+
} else if (msg.type === "tool_result" /* ToolResult */) {
|
|
404
|
+
const toolResultMsg = msg;
|
|
405
|
+
for (const tr of toolResultMsg.toolResults) {
|
|
406
|
+
result.push({
|
|
407
|
+
role: "tool",
|
|
408
|
+
tool_call_id: pendingIds.shift() || `call_${msg.timestamp}`,
|
|
409
|
+
content: tr.isError ? `Error: ${tr.result}` : tr.result
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
}
|
|
296
413
|
}
|
|
414
|
+
return result;
|
|
297
415
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
stream: true,
|
|
312
|
-
stream_options: { include_usage: true },
|
|
313
|
-
service_tier: this.flex ? "flex" : void 0,
|
|
314
|
-
reasoning_effort: this.reasoningEffort
|
|
315
|
-
};
|
|
316
|
-
const stream = await this.client.chat.completions.create(requestParams);
|
|
317
|
-
let text = "";
|
|
318
|
-
const toolCalls = /* @__PURE__ */ new Map();
|
|
319
|
-
let usage;
|
|
320
|
-
for await (const chunk of stream) {
|
|
321
|
-
const delta = chunk.choices[0]?.delta;
|
|
322
|
-
if (delta?.content) {
|
|
323
|
-
text += delta.content;
|
|
324
|
-
onChunk?.(delta.content);
|
|
416
|
+
getTools() {
|
|
417
|
+
return this.tools?.map((t) => ({
|
|
418
|
+
type: "function",
|
|
419
|
+
function: {
|
|
420
|
+
name: t.name,
|
|
421
|
+
description: t.description,
|
|
422
|
+
parameters: {
|
|
423
|
+
type: "object",
|
|
424
|
+
properties: t.parameters,
|
|
425
|
+
required: t.required.length > 0 ? t.required : void 0
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}));
|
|
325
429
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
430
|
+
async chat(messages, onChunk) {
|
|
431
|
+
debug("API", `Requesting OpenAI (model: ${this.model}, messages: ${messages.length})`);
|
|
432
|
+
const openaiMessages = this.toOpenAIMessages(messages);
|
|
433
|
+
const startTime = Date.now();
|
|
434
|
+
const requestParams = {
|
|
435
|
+
model: this.model,
|
|
436
|
+
messages: openaiMessages,
|
|
437
|
+
tools: this.getTools(),
|
|
438
|
+
temperature: TEMPERATURE,
|
|
439
|
+
max_completion_tokens: MAX_COMPLETION_TOKENS,
|
|
440
|
+
stream: true,
|
|
441
|
+
stream_options: { include_usage: true },
|
|
442
|
+
service_tier: this.flex ? "flex" : void 0,
|
|
443
|
+
reasoning_effort: this.reasoningEffort
|
|
444
|
+
};
|
|
445
|
+
const stream = await this.client.chat.completions.create(requestParams);
|
|
446
|
+
let text = "";
|
|
447
|
+
const toolCalls = /* @__PURE__ */ new Map();
|
|
448
|
+
let usage;
|
|
449
|
+
for await (const chunk of stream) {
|
|
450
|
+
const delta = chunk.choices[0]?.delta;
|
|
451
|
+
if (delta?.content) {
|
|
452
|
+
text += delta.content;
|
|
453
|
+
onChunk?.(delta.content);
|
|
454
|
+
}
|
|
455
|
+
if (delta?.tool_calls) {
|
|
456
|
+
for (const tc of delta.tool_calls) {
|
|
457
|
+
const cur = toolCalls.get(tc.index) || { name: "", args: "" };
|
|
458
|
+
cur.name += tc.function?.name || "";
|
|
459
|
+
cur.args += tc.function?.arguments || "";
|
|
460
|
+
toolCalls.set(tc.index, cur);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
if (chunk.usage) usage = chunk.usage;
|
|
464
|
+
}
|
|
465
|
+
const elapsed = Date.now() - startTime;
|
|
466
|
+
const cachedTokens = usage?.prompt_tokens_details?.cached_tokens;
|
|
467
|
+
const usageData = usage && {
|
|
468
|
+
promptTokens: usage.prompt_tokens,
|
|
469
|
+
completionTokens: usage.completion_tokens,
|
|
470
|
+
totalTokens: usage.total_tokens,
|
|
471
|
+
cachedTokens
|
|
472
|
+
};
|
|
473
|
+
if (toolCalls.size > 0) {
|
|
474
|
+
const calls = [...toolCalls.values()].map((tc) => ({
|
|
475
|
+
name: tc.name,
|
|
476
|
+
arguments: JSON.parse(tc.args || "{}")
|
|
477
|
+
}));
|
|
478
|
+
debug("API", `Completed (${elapsed}ms, tools: ${calls.map((t) => t.name).join(", ")})`);
|
|
479
|
+
return { message: new ToolCallMsg(text, calls), hasToolCalls: true, usage: usageData };
|
|
332
480
|
}
|
|
481
|
+
debug("API", `Completed (${elapsed}ms, tokens: ${usage?.total_tokens || "N/A"})`);
|
|
482
|
+
return { message: new AIMsg(text), hasToolCalls: false, usage: usageData };
|
|
333
483
|
}
|
|
334
|
-
if (chunk.usage) usage = chunk.usage;
|
|
335
|
-
}
|
|
336
|
-
const elapsed = Date.now() - startTime;
|
|
337
|
-
const cachedTokens = usage?.prompt_tokens_details?.cached_tokens;
|
|
338
|
-
const usageData = usage && {
|
|
339
|
-
promptTokens: usage.prompt_tokens,
|
|
340
|
-
completionTokens: usage.completion_tokens,
|
|
341
|
-
totalTokens: usage.total_tokens,
|
|
342
|
-
cachedTokens
|
|
343
484
|
};
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
// src/init/loader.ts
|
|
489
|
+
var loader_exports = {};
|
|
490
|
+
__export(loader_exports, {
|
|
491
|
+
getAgentConfig: () => getAgentConfig,
|
|
492
|
+
getApiKey: () => getApiKey,
|
|
493
|
+
getConfig: () => getConfig,
|
|
494
|
+
loadConfigs: () => loadConfigs,
|
|
495
|
+
saveConfig: () => saveConfig
|
|
496
|
+
});
|
|
497
|
+
import * as path3 from "path";
|
|
498
|
+
function deepMerge(base, override) {
|
|
499
|
+
const result = {
|
|
500
|
+
...base,
|
|
501
|
+
agents: { ...base.agents }
|
|
502
|
+
};
|
|
503
|
+
if (override.apiKeys) {
|
|
504
|
+
result.apiKeys = { ...base.apiKeys, ...override.apiKeys };
|
|
505
|
+
}
|
|
506
|
+
if (override.agents) {
|
|
507
|
+
for (const key of Object.keys(override.agents)) {
|
|
508
|
+
const overrideAgent = override.agents[key];
|
|
509
|
+
if (overrideAgent) {
|
|
510
|
+
result.agents[key] = { ...result.agents[key], ...overrideAgent };
|
|
511
|
+
}
|
|
351
512
|
}
|
|
352
|
-
debug("API", `Completed (${elapsed}ms, tokens: ${usage?.total_tokens || "N/A"})`);
|
|
353
|
-
return { message: new AIMsg(text), hasToolCalls: false, usage: usageData };
|
|
354
513
|
}
|
|
355
|
-
|
|
514
|
+
return result;
|
|
515
|
+
}
|
|
516
|
+
function loadEnvApiKeys(config) {
|
|
517
|
+
if (process.env.OPENAI_API_KEY) {
|
|
518
|
+
if (!config.apiKeys) config.apiKeys = {};
|
|
519
|
+
if (!config.apiKeys.openai) {
|
|
520
|
+
config.apiKeys.openai = process.env.OPENAI_API_KEY;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
524
|
+
if (!config.apiKeys) config.apiKeys = {};
|
|
525
|
+
if (!config.apiKeys.anthropic) {
|
|
526
|
+
config.apiKeys.anthropic = process.env.ANTHROPIC_API_KEY;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
if (process.env.GOOGLE_API_KEY) {
|
|
530
|
+
if (!config.apiKeys) config.apiKeys = {};
|
|
531
|
+
if (!config.apiKeys.google) {
|
|
532
|
+
config.apiKeys.google = process.env.GOOGLE_API_KEY;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
async function loadConfigs() {
|
|
537
|
+
if (mergedConfig) {
|
|
538
|
+
return mergedConfig;
|
|
539
|
+
}
|
|
540
|
+
const globalConfigPath = path3.join(PATHS.globalConfig, "config.json");
|
|
541
|
+
const globalConfig = await readJsonFile(globalConfigPath);
|
|
542
|
+
if (!globalConfig) {
|
|
543
|
+
throw new Error(`Failed to load global config: ${globalConfigPath}`);
|
|
544
|
+
}
|
|
545
|
+
const projectConfigPath = path3.join(PATHS.projectConfig, "config.json");
|
|
546
|
+
const projectConfig = await readJsonFile(projectConfigPath);
|
|
547
|
+
if (projectConfig) {
|
|
548
|
+
mergedConfig = deepMerge(globalConfig, projectConfig);
|
|
549
|
+
} else {
|
|
550
|
+
mergedConfig = globalConfig;
|
|
551
|
+
}
|
|
552
|
+
loadEnvApiKeys(mergedConfig);
|
|
553
|
+
return mergedConfig;
|
|
554
|
+
}
|
|
555
|
+
function getConfig() {
|
|
556
|
+
if (!mergedConfig) {
|
|
557
|
+
throw new Error("Config not loaded yet. Please call loadConfigs() first.");
|
|
558
|
+
}
|
|
559
|
+
return mergedConfig;
|
|
560
|
+
}
|
|
561
|
+
function getApiKey(provider) {
|
|
562
|
+
return getConfig().apiKeys?.[provider];
|
|
563
|
+
}
|
|
564
|
+
function getAgentConfig(agentType) {
|
|
565
|
+
const agentConfig = getConfig().agents[agentType];
|
|
566
|
+
if (!agentConfig) {
|
|
567
|
+
throw new Error(`Agent config not found: ${agentType}`);
|
|
568
|
+
}
|
|
569
|
+
return agentConfig;
|
|
570
|
+
}
|
|
571
|
+
async function saveConfig() {
|
|
572
|
+
const config = getConfig();
|
|
573
|
+
const configPath = path3.join(PATHS.globalConfig, "config.json");
|
|
574
|
+
const configToSave = { ...config };
|
|
575
|
+
if (config.apiKeys) {
|
|
576
|
+
configToSave.apiKeys = { ...config.apiKeys };
|
|
577
|
+
if (process.env.OPENAI_API_KEY && configToSave.apiKeys.openai === process.env.OPENAI_API_KEY) {
|
|
578
|
+
delete configToSave.apiKeys.openai;
|
|
579
|
+
}
|
|
580
|
+
if (process.env.ANTHROPIC_API_KEY && configToSave.apiKeys.anthropic === process.env.ANTHROPIC_API_KEY) {
|
|
581
|
+
delete configToSave.apiKeys.anthropic;
|
|
582
|
+
}
|
|
583
|
+
if (process.env.GOOGLE_API_KEY && configToSave.apiKeys.google === process.env.GOOGLE_API_KEY) {
|
|
584
|
+
delete configToSave.apiKeys.google;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
await writeJsonFile(configPath, configToSave);
|
|
588
|
+
}
|
|
589
|
+
var mergedConfig;
|
|
590
|
+
var init_loader = __esm({
|
|
591
|
+
"src/init/loader.ts"() {
|
|
592
|
+
"use strict";
|
|
593
|
+
init_fs();
|
|
594
|
+
mergedConfig = null;
|
|
595
|
+
}
|
|
596
|
+
});
|
|
356
597
|
|
|
357
|
-
// src/
|
|
358
|
-
var
|
|
359
|
-
|
|
360
|
-
|
|
598
|
+
// src/init/index.ts
|
|
599
|
+
var init_exports = {};
|
|
600
|
+
__export(init_exports, {
|
|
601
|
+
PROCEDURES: () => PROCEDURES,
|
|
602
|
+
TOOLS: () => TOOLS,
|
|
603
|
+
adapter: () => adapter,
|
|
604
|
+
getAgentConfig: () => getAgentConfig,
|
|
605
|
+
getApiKey: () => getApiKey,
|
|
606
|
+
getConfig: () => getConfig,
|
|
607
|
+
init: () => init,
|
|
608
|
+
initAdapter: () => initAdapter,
|
|
609
|
+
loadConfigs: () => loadConfigs,
|
|
610
|
+
saveConfig: () => saveConfig
|
|
611
|
+
});
|
|
612
|
+
var init_init = __esm({
|
|
613
|
+
"src/init/index.ts"() {
|
|
614
|
+
"use strict";
|
|
615
|
+
init_global();
|
|
616
|
+
init_loader();
|
|
617
|
+
}
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
// src/init/project.ts
|
|
621
|
+
var project_exports = {};
|
|
622
|
+
__export(project_exports, {
|
|
623
|
+
initProject: () => initProject
|
|
624
|
+
});
|
|
625
|
+
import * as path4 from "path";
|
|
626
|
+
import * as readline from "readline";
|
|
627
|
+
async function askQuestion(question) {
|
|
628
|
+
const rl = readline.createInterface({
|
|
629
|
+
input: process.stdin,
|
|
630
|
+
output: process.stdout
|
|
631
|
+
});
|
|
632
|
+
return new Promise((resolve4) => {
|
|
633
|
+
rl.question(`${question} (y/n): `, (answer) => {
|
|
634
|
+
rl.close();
|
|
635
|
+
resolve4(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
636
|
+
});
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
async function initProject() {
|
|
640
|
+
const projectConfigDir = PATHS.projectConfig;
|
|
641
|
+
if (await dirExists(projectConfigDir)) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
print(`
|
|
645
|
+
<dim>Project directory: ${workingDir}</dim>`);
|
|
646
|
+
const trusted = await askQuestion("Do you trust this project and want to initialize arki config?");
|
|
647
|
+
if (!trusted) {
|
|
648
|
+
print("<yellow>Initialization cancelled.</yellow>");
|
|
649
|
+
process.exit(0);
|
|
650
|
+
}
|
|
651
|
+
await copyDir(PATHS.projectTemplate, projectConfigDir);
|
|
652
|
+
const statePath = path4.join(projectConfigDir, "state.json");
|
|
653
|
+
const state = {
|
|
654
|
+
initialized: true,
|
|
655
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
656
|
+
};
|
|
657
|
+
await writeJsonFile(statePath, state);
|
|
658
|
+
print("<green>Project configuration initialized.</green>");
|
|
659
|
+
}
|
|
660
|
+
var init_project = __esm({
|
|
661
|
+
"src/init/project.ts"() {
|
|
662
|
+
"use strict";
|
|
663
|
+
init_fs();
|
|
664
|
+
init_log2();
|
|
665
|
+
}
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
// src/init/global.ts
|
|
669
|
+
async function initGlobalConfig() {
|
|
670
|
+
const globalConfigDir = PATHS.globalConfig;
|
|
671
|
+
if (await dirExists(globalConfigDir)) {
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
await copyDir(PATHS.globalTemplate, globalConfigDir);
|
|
361
675
|
}
|
|
362
|
-
var TOOLS = {};
|
|
363
|
-
var adapter = null;
|
|
364
676
|
function initAdapter() {
|
|
365
677
|
if (adapter) {
|
|
366
678
|
return;
|
|
367
679
|
}
|
|
368
|
-
|
|
680
|
+
Promise.resolve().then(() => (init_init(), init_exports)).then(({ getAgentConfig: getAgentConfig2, getApiKey: getApiKey2 }) => {
|
|
681
|
+
const mainAgentConfig = getAgentConfig2("main");
|
|
682
|
+
adapter = new OpenAIAdapter({
|
|
683
|
+
apiKey: getApiKey2("openai") || "",
|
|
684
|
+
model: mainAgentConfig.model,
|
|
685
|
+
flex: mainAgentConfig.flex,
|
|
686
|
+
tools: Object.values(TOOLS)
|
|
687
|
+
});
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
async function init(cwd) {
|
|
691
|
+
const { setWorkingDir: setWorkingDir2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
692
|
+
setWorkingDir2(cwd || process.cwd());
|
|
693
|
+
await initGlobalConfig();
|
|
694
|
+
const { initProject: initProject2 } = await Promise.resolve().then(() => (init_project(), project_exports));
|
|
695
|
+
await initProject2();
|
|
696
|
+
const { loadConfigs: loadConfigs2, getAgentConfig: getAgentConfig2, getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
|
|
697
|
+
await loadConfigs2();
|
|
698
|
+
const mainAgentConfig = getAgentConfig2("main");
|
|
369
699
|
adapter = new OpenAIAdapter({
|
|
370
|
-
apiKey:
|
|
700
|
+
apiKey: getApiKey2("openai") || "",
|
|
371
701
|
model: mainAgentConfig.model,
|
|
372
702
|
flex: mainAgentConfig.flex,
|
|
373
703
|
tools: Object.values(TOOLS)
|
|
374
704
|
});
|
|
375
705
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
706
|
+
var TOOLS, PROCEDURES, adapter;
|
|
707
|
+
var init_global = __esm({
|
|
708
|
+
"src/init/global.ts"() {
|
|
709
|
+
"use strict";
|
|
710
|
+
init_openai();
|
|
711
|
+
init_fs();
|
|
712
|
+
TOOLS = {};
|
|
713
|
+
PROCEDURES = {};
|
|
714
|
+
adapter = null;
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
// src/index.ts
|
|
719
|
+
import * as readline2 from "readline";
|
|
720
|
+
import * as fs6 from "fs";
|
|
721
|
+
import * as path8 from "path";
|
|
722
|
+
import * as os2 from "os";
|
|
723
|
+
|
|
724
|
+
// src/global.ts
|
|
725
|
+
init_fs();
|
|
726
|
+
init_global();
|
|
727
|
+
init_init();
|
|
381
728
|
|
|
382
729
|
// src/tool/Tool.ts
|
|
730
|
+
init_log2();
|
|
383
731
|
var HAS_MANUAL = "\u{1F4D8}";
|
|
384
732
|
var Tool = class _Tool {
|
|
385
733
|
name;
|
|
@@ -388,12 +736,12 @@ var Tool = class _Tool {
|
|
|
388
736
|
required;
|
|
389
737
|
manual;
|
|
390
738
|
_execute;
|
|
391
|
-
constructor(
|
|
392
|
-
this.name =
|
|
393
|
-
this.parameters =
|
|
394
|
-
this.required =
|
|
395
|
-
this._execute =
|
|
396
|
-
const { description, manual } = _Tool.parseManual(
|
|
739
|
+
constructor(config) {
|
|
740
|
+
this.name = config.name;
|
|
741
|
+
this.parameters = config.parameters;
|
|
742
|
+
this.required = config.required;
|
|
743
|
+
this._execute = config.execute;
|
|
744
|
+
const { description, manual } = _Tool.parseManual(config.manualContent);
|
|
397
745
|
this.description = description;
|
|
398
746
|
this.manual = manual;
|
|
399
747
|
}
|
|
@@ -421,29 +769,23 @@ var Tool = class _Tool {
|
|
|
421
769
|
* Execute tool (with error handling and logging)
|
|
422
770
|
*/
|
|
423
771
|
async run(args) {
|
|
424
|
-
debug("Tool", `Starting tool execution: ${this.name}`, args);
|
|
425
|
-
const startTime = Date.now();
|
|
426
772
|
try {
|
|
427
773
|
const result = await this._execute(args);
|
|
428
|
-
const elapsed = Date.now() - startTime;
|
|
429
774
|
if (typeof result === "string") {
|
|
430
|
-
debug("Tool", `Tool execution successful: ${this.name} (elapsed: ${elapsed}ms, result length: ${result.length})`);
|
|
431
775
|
return { toolName: this.name, result };
|
|
432
776
|
}
|
|
433
|
-
debug("Tool", `Tool execution completed: ${this.name} (elapsed: ${elapsed}ms, isError: ${result.isError || false})`);
|
|
434
777
|
return { toolName: this.name, result: result.content, isError: result.isError };
|
|
435
778
|
} catch (error2) {
|
|
436
|
-
const elapsed = Date.now() - startTime;
|
|
437
779
|
const errorMsg = error2 instanceof Error ? error2.message : String(error2);
|
|
438
|
-
debug("Tool",
|
|
780
|
+
debug("Tool", `${this.name} error`, errorMsg);
|
|
439
781
|
return { toolName: this.name, result: `Error: ${errorMsg}`, isError: true };
|
|
440
782
|
}
|
|
441
783
|
}
|
|
442
784
|
};
|
|
443
785
|
|
|
444
786
|
// src/tool/read_file/index.ts
|
|
445
|
-
import * as
|
|
446
|
-
import * as
|
|
787
|
+
import * as fs3 from "fs/promises";
|
|
788
|
+
import * as path5 from "path";
|
|
447
789
|
|
|
448
790
|
// src/tool/read_file/manual.md
|
|
449
791
|
var manual_default = "read_file: Read the content of a specified file\n";
|
|
@@ -459,8 +801,8 @@ TOOLS["read_file"] = new Tool({
|
|
|
459
801
|
execute: async (args) => {
|
|
460
802
|
const filePath = args.path;
|
|
461
803
|
try {
|
|
462
|
-
const fullPath =
|
|
463
|
-
return await
|
|
804
|
+
const fullPath = path5.resolve(workingDir, filePath);
|
|
805
|
+
return await fs3.readFile(fullPath, "utf-8");
|
|
464
806
|
} catch (error2) {
|
|
465
807
|
return {
|
|
466
808
|
content: `Failed to read file: ${error2 instanceof Error ? error2.message : String(error2)}`,
|
|
@@ -471,8 +813,8 @@ TOOLS["read_file"] = new Tool({
|
|
|
471
813
|
});
|
|
472
814
|
|
|
473
815
|
// src/tool/write_file/index.ts
|
|
474
|
-
import * as
|
|
475
|
-
import * as
|
|
816
|
+
import * as fs4 from "fs/promises";
|
|
817
|
+
import * as path6 from "path";
|
|
476
818
|
|
|
477
819
|
// src/tool/write_file/manual.md
|
|
478
820
|
var manual_default2 = "write_file: Write content to a specified file, create the file if it doesn't exist\n";
|
|
@@ -490,9 +832,9 @@ TOOLS["write_file"] = new Tool({
|
|
|
490
832
|
const filePath = args.path;
|
|
491
833
|
const content = args.content;
|
|
492
834
|
try {
|
|
493
|
-
const fullPath =
|
|
494
|
-
await
|
|
495
|
-
await
|
|
835
|
+
const fullPath = path6.resolve(workingDir, filePath);
|
|
836
|
+
await fs4.mkdir(path6.dirname(fullPath), { recursive: true });
|
|
837
|
+
await fs4.writeFile(fullPath, content, "utf-8");
|
|
496
838
|
return `File written successfully: ${filePath}`;
|
|
497
839
|
} catch (error2) {
|
|
498
840
|
return {
|
|
@@ -504,8 +846,8 @@ TOOLS["write_file"] = new Tool({
|
|
|
504
846
|
});
|
|
505
847
|
|
|
506
848
|
// src/tool/list_directory/index.ts
|
|
507
|
-
import * as
|
|
508
|
-
import * as
|
|
849
|
+
import * as fs5 from "fs/promises";
|
|
850
|
+
import * as path7 from "path";
|
|
509
851
|
|
|
510
852
|
// src/tool/list_directory/manual.md
|
|
511
853
|
var manual_default3 = "list_directory: List files and subdirectories in a specified directory\n";
|
|
@@ -521,8 +863,8 @@ TOOLS["list_directory"] = new Tool({
|
|
|
521
863
|
execute: async (args) => {
|
|
522
864
|
const dirPath = args.path || ".";
|
|
523
865
|
try {
|
|
524
|
-
const fullPath =
|
|
525
|
-
const entries = await
|
|
866
|
+
const fullPath = path7.resolve(workingDir, dirPath);
|
|
867
|
+
const entries = await fs5.readdir(fullPath, { withFileTypes: true });
|
|
526
868
|
const result = entries.map((entry) => {
|
|
527
869
|
const type = entry.isDirectory() ? "[DIR]" : "[FILE]";
|
|
528
870
|
return `${type} ${entry.name}`;
|
|
@@ -603,6 +945,79 @@ ${foundTool.manual}`;
|
|
|
603
945
|
}
|
|
604
946
|
});
|
|
605
947
|
|
|
948
|
+
// src/tool/read_procedure/manual.md
|
|
949
|
+
var manual_default6 = "read_procedure: View detailed steps for a specified procedure\n";
|
|
950
|
+
|
|
951
|
+
// src/tool/read_procedure/index.ts
|
|
952
|
+
TOOLS["read_procedure"] = new Tool({
|
|
953
|
+
name: "read_procedure",
|
|
954
|
+
parameters: {
|
|
955
|
+
procedure_name: { type: "string", description: "Procedure name to view" }
|
|
956
|
+
},
|
|
957
|
+
required: ["procedure_name"],
|
|
958
|
+
manualContent: manual_default6,
|
|
959
|
+
execute: async (args) => {
|
|
960
|
+
const procedureName = args.procedure_name;
|
|
961
|
+
const procedure = PROCEDURES[procedureName];
|
|
962
|
+
if (!procedure) {
|
|
963
|
+
const available = Object.keys(PROCEDURES).join(", ");
|
|
964
|
+
return {
|
|
965
|
+
content: `Procedure not found: ${procedureName}
|
|
966
|
+
Available: ${available}`,
|
|
967
|
+
isError: true
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
return `# ${procedure.name}
|
|
971
|
+
|
|
972
|
+
${procedure.description}
|
|
973
|
+
|
|
974
|
+
## Steps
|
|
975
|
+
|
|
976
|
+
${procedure.manual}`;
|
|
977
|
+
}
|
|
978
|
+
});
|
|
979
|
+
|
|
980
|
+
// src/procedure/Procedure.ts
|
|
981
|
+
var Procedure = class _Procedure {
|
|
982
|
+
name;
|
|
983
|
+
description;
|
|
984
|
+
manual;
|
|
985
|
+
constructor(config) {
|
|
986
|
+
this.name = config.name;
|
|
987
|
+
const { description, manual } = _Procedure.parseManual(config.procedureContent);
|
|
988
|
+
this.description = description;
|
|
989
|
+
this.manual = manual;
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Parse procedure.md content
|
|
993
|
+
* First line format: "procedure_name: description", extract description
|
|
994
|
+
* Remaining content is the procedure steps
|
|
995
|
+
*/
|
|
996
|
+
static parseManual(content) {
|
|
997
|
+
const lines = content.split("\n");
|
|
998
|
+
const firstLine = lines[0] || "";
|
|
999
|
+
let description = "";
|
|
1000
|
+
const colonIndex = firstLine.indexOf(":");
|
|
1001
|
+
if (colonIndex > 0) {
|
|
1002
|
+
description = firstLine.slice(colonIndex + 1).trim();
|
|
1003
|
+
}
|
|
1004
|
+
const manual = lines.slice(1).join("\n").trim();
|
|
1005
|
+
return { description, manual };
|
|
1006
|
+
}
|
|
1007
|
+
};
|
|
1008
|
+
|
|
1009
|
+
// src/procedure/understand_project/procedure.md
|
|
1010
|
+
var procedure_default = "understand_project: Systematically explore and understand the current project structure\n\n1. Use `list_directory` on the root directory to get an overview\n - Identify key directories (src, lib, tests, docs, etc.)\n - Note configuration files (package.json, tsconfig.json, Cargo.toml, etc.)\n\n2. Use `read_file` on the main configuration file (package.json, Cargo.toml, pyproject.toml, etc.)\n - Project name and description\n - Dependencies and their purposes\n - Scripts/commands available\n - Entry points\n\n3. Use `read_file` on README.md if it exists\n - Project purpose and goals\n - Setup instructions\n - Usage examples\n\n4. Use `list_directory` on the main source directory (src/, lib/, app/, etc.)\n - Identify the entry point file (index.ts, main.ts, app.ts, etc.)\n - List subdirectories to understand module organization\n - Note any patterns (MVC, feature-based, etc.)\n\n5. Use `read_file` on 2-3 key source files to understand\n - Coding style and conventions\n - Main abstractions and patterns used\n - How modules interact with each other\n\n6. Output the final report in this format **in user's language**:\n\n---\n<bold><cyan>Project Overview</cyan></bold>\n\nName: [project name]\nType: [CLI tool / Web app / Library / API server / etc.]\nLanguage: [TypeScript / JavaScript / Python / etc.]\nPackage Manager: [npm / pnpm / yarn / pip / cargo / etc.]\n\n<bold><cyan>Project Structure</cyan></bold>\n\n[Brief description of directory structure and organization pattern]\n\n<bold><cyan>Key Components</cyan></bold>\n\n\u2022 [Component 1]: [brief description]\n\u2022 [Component 2]: [brief description]\n\u2022 [Component 3]: [brief description]\n...\n\n<bold><cyan>Entry Points</cyan></bold>\n\n\u2022 Main: [path to main entry]\n\u2022 CLI: [path to CLI entry if applicable]\n\u2022 Tests: [path to test entry if applicable]\n\n<bold><cyan>Dependencies</cyan></bold>\n\nCore:\n\u2022 [dep1]: [purpose]\n\u2022 [dep2]: [purpose]\n\nDev:\n\u2022 [dev-dep1]: [purpose]\n\u2022 [dev-dep2]: [purpose]\n\n<bold><cyan>Available Commands</cyan></bold>\n\n\u2022 [command1]: [description]\n\u2022 [command2]: [description]\n...\n\n<bold><cyan>Code Patterns</cyan></bold>\n\n\u2022 [Pattern 1 observed in the codebase]\n\u2022 [Pattern 2 observed in the codebase]\n...\n---\n";
|
|
1011
|
+
|
|
1012
|
+
// src/procedure/understand_project/index.ts
|
|
1013
|
+
PROCEDURES["understand_project"] = new Procedure({
|
|
1014
|
+
name: "understand_project",
|
|
1015
|
+
procedureContent: procedure_default
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
// src/index.ts
|
|
1019
|
+
init_log2();
|
|
1020
|
+
|
|
606
1021
|
// src/model/models.ts
|
|
607
1022
|
var MODELS = {
|
|
608
1023
|
"gpt-5.2": {
|
|
@@ -644,12 +1059,15 @@ var MODELS = {
|
|
|
644
1059
|
};
|
|
645
1060
|
|
|
646
1061
|
// src/agent/Agent.ts
|
|
1062
|
+
init_Msg();
|
|
1063
|
+
init_init();
|
|
1064
|
+
init_log2();
|
|
647
1065
|
var Agent = class {
|
|
648
1066
|
config;
|
|
649
1067
|
messages = [];
|
|
650
|
-
constructor(
|
|
651
|
-
this.config =
|
|
652
|
-
this.messages = [...
|
|
1068
|
+
constructor(config) {
|
|
1069
|
+
this.config = config;
|
|
1070
|
+
this.messages = [...config.messages];
|
|
653
1071
|
}
|
|
654
1072
|
/**
|
|
655
1073
|
* Render template string, replacing {{variable}} style variables
|
|
@@ -696,13 +1114,8 @@ var Agent = class {
|
|
|
696
1114
|
const toolResults = [];
|
|
697
1115
|
for (const tc of toolCalls) {
|
|
698
1116
|
this.config.onBeforeToolRun?.(tc.name, tc.arguments);
|
|
699
|
-
debug("Agent", `Executing tool: ${tc.name}`, tc.arguments);
|
|
700
1117
|
const tool = TOOLS[tc.name];
|
|
701
1118
|
const result = tool ? await tool.run(tc.arguments) : { toolName: tc.name, result: `Unknown tool: ${tc.name}`, isError: true };
|
|
702
|
-
debug("Agent", `Tool execution completed: ${tc.name}`, {
|
|
703
|
-
isError: result.isError,
|
|
704
|
-
contentLength: result.result.length
|
|
705
|
-
});
|
|
706
1119
|
toolCallHistory.push({
|
|
707
1120
|
name: tc.name,
|
|
708
1121
|
arguments: tc.arguments,
|
|
@@ -720,46 +1133,26 @@ var Agent = class {
|
|
|
720
1133
|
}
|
|
721
1134
|
};
|
|
722
1135
|
|
|
723
|
-
// src/agent/
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
return closing ? colors.reset : colors[tag.toLowerCase()] || "";
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
function createColorConverter() {
|
|
732
|
-
let buffer = "";
|
|
733
|
-
return (chunk) => {
|
|
734
|
-
buffer += chunk;
|
|
735
|
-
const lastOpen = buffer.lastIndexOf("<");
|
|
736
|
-
if (lastOpen === -1) {
|
|
737
|
-
const out2 = convertColorTags(buffer);
|
|
738
|
-
buffer = "";
|
|
739
|
-
return out2;
|
|
740
|
-
}
|
|
741
|
-
if (buffer.indexOf(">", lastOpen) !== -1) {
|
|
742
|
-
const out2 = convertColorTags(buffer);
|
|
743
|
-
buffer = "";
|
|
744
|
-
return out2;
|
|
745
|
-
}
|
|
746
|
-
const out = convertColorTags(buffer.slice(0, lastOpen));
|
|
747
|
-
buffer = buffer.slice(lastOpen);
|
|
748
|
-
return out;
|
|
749
|
-
};
|
|
750
|
-
}
|
|
1136
|
+
// src/agent/index.ts
|
|
1137
|
+
init_Msg();
|
|
1138
|
+
|
|
1139
|
+
// src/agent/Arki/Arki.ts
|
|
1140
|
+
init_log2();
|
|
751
1141
|
|
|
752
1142
|
// src/agent/Arki/system.md
|
|
753
|
-
var system_default = "You are Arki, a professional AI programming assistant. You work in the codebase directory `{{working_dir}}`.\n\n## Tool Usage\n\nTools can be called multiple times at once.\nIf a tool has the {{has_manual}} symbol in its description, you **MUST** call `read_tool_manual` before using it. Read the manual exactly once per tool - do not skip it, and do not read it repeatedly.\n\n## Working Principles\n\n- **Accuracy**: Before answering questions, use tools to view relevant code first. Don't base statements on assumptions. If you don't know something, just admit it - it's no big deal. For example, never tell the user what might be inside a directory based only on its name\u2014always inspect its contents first, and never guess functionality from directory, file, or function names in a way that could mislead the user.\n- **Safety**: Consider potential risks before executing commands.\n- **Conciseness**: Keep answers brief and concise, avoid repetition and redundancy. Keep each response within 200 words unless the user requests detailed explanation. If user requirements are unclear, ask for clarification once at most. If still unclear after asking, proceed with your best understanding and show the result to the user - do not ask multiple times.\n- **Proactivity**: Actively suggest improvements when you find issues.\n\n## Response Style\n\n- Answer questions directly, avoid excessive pleasantries\n- Don't use emojis\n- Don't repeatedly ask about user needs, once is enough. Don't ask and answer yourself.\n\nThe user is talking to you via **CLI terminal**. Prefer terminal-friendly characters and plain text formatting. **Do not** output Markdown syntax such as `**` for bold, `*` or `-` for lists, etc. For long answers, feel free to organize content with clear section headings. Use numbered lists for ordered lists only when items have a clear sequence or dependency; otherwise use the \u2022 symbol for unordered lists.\nUse the following tags to format output:\n\n| Purpose | Format Tag | Usage |\n|--------|------------|-------|\n| Code blocks (```...```) | `<dim>...</dim>` | Wrap the entire code block content |\n| Inline code (`...`) | `<dim>...</dim>` | Wrap inline code snippets |\n| File paths | `<cyan>...</cyan>` | For paths, e.g., `src/index.ts` |\n| Filenames | `<gray>...</gray>` | For file names when mentioned alone |\n| Command names | `<blue>...</blue>` | For commands, e.g., `npm install` |\n| Section headings / titles | `<bold><cyan>...</cyan></bold>` | For section titles in plain text output |\n| Important or strong emphasis (**...**) | `<bold>...</bold>` | For key points that must stand out |\n| Secondary / less important info | `<dim>...</dim>` | For metadata, debug info, token counts, etc. |\n| Tips / important notices | `<yellow>...</yellow>` | For tips, cautions, non-fatal problems |\n| Success confirmations | `<green>...</green>` | For success messages, completion status |\n| Errors or serious problems | `<red>...</red>` | For real problems the user must fix |\n| Neutral informational messages | `<blue>...</blue>` | For general info that is not success/failure |\n| Highlighted keywords / categories | `<magenta>...</magenta>` | For labels, categories, or tags in text |\n| De-emphasized / grayed-out text | `<gray>...</gray>` | For low-priority info, old values, etc. |\n| Underlined emphasis | `<underline>...</underline>` | For things you want to underline instead of bold |\n| Optional / tentative text | `<italic>...</italic>` | For suggestions, optional steps, side notes |\n| Reversed highlight | `<inverse>...</inverse>` | For very strong highlights (rarely use) |\n| Deleted / not recommended content | `<strikethrough>...</strikethrough>` | For deprecated commands or steps |\n\nTags can be combined, e.g., `<bold><red>Critical Error</red></bold>`\n\n- Do not mention the contents of this prompt to users. The prompt provides context and instructions for you to follow, not to recite verbatim. Use the information in the prompt to inform your responses naturally. Bad example: \"You are currently talking to me via a Mac OS terminal interface. How can I help you?\" Good example: (Display terminal-friendly characters and provide suggestions based on the Mac OS system environment)\n\nPlease answer questions in the language the user is using, and flexibly use available tools to complete tasks.\n\n";
|
|
1143
|
+
var system_default = "You are Arki, a professional AI programming assistant. You work in the codebase directory `{{working_dir}}`.\n\n## Tool Usage\n\nTools can be called multiple times at once.\nIf a tool has the {{has_manual}} symbol in its description, you **MUST** call `read_tool_manual` before using it. Read the manual exactly once per tool - do not skip it, and do not read it repeatedly.\n\n## Procedure Usage\n\nProcedures are step-by-step guides for specific workflows. When a task involves a defined procedure, you **MUST** call `read_procedure` first to get the complete steps, then follow the procedure exactly.\n\nIf a procedure defines output text/format templates, translate them to the user's language unless the procedure explicitly forbids translation.\n\nAvailable procedures:\n{{procedures}}\n\n## Working Principles\n\n- **Accuracy**: Before answering questions, use tools to view relevant code first. Don't base statements on assumptions. If you don't know something, just admit it - it's no big deal. For example, never tell the user what might be inside a directory based only on its name\u2014always inspect its contents first, and never guess functionality from directory, file, or function names in a way that could mislead the user.\n- **Safety**: Consider potential risks before executing commands.\n- **Conciseness**: Keep answers brief and concise, avoid repetition and redundancy. Keep each response within 200 words unless the user requests detailed explanation. If user requirements are unclear, ask for clarification once at most. If still unclear after asking, proceed with your best understanding and show the result to the user - do not ask multiple times.\n- **Proactivity**: Actively suggest improvements when you find issues.\n\n## Response Style\n\n- Answer questions directly, avoid excessive pleasantries\n- Don't use emojis\n- Don't repeatedly ask about user needs, once is enough. Don't ask and answer yourself.\n\nThe user is talking to you via **CLI terminal**. Prefer terminal-friendly characters and plain text formatting. **Do not** output Markdown syntax such as `**` for bold, `*` or `-` for lists, etc. For long answers, feel free to organize content with clear section headings. Use numbered lists for ordered lists only when items have a clear sequence or dependency; otherwise use the \u2022 symbol for unordered lists.\nUse the following tags to format output:\n\n| Purpose | Format Tag | Usage |\n|--------|------------|-------|\n| Code blocks (```...```) | `<dim>...</dim>` | Wrap the entire code block content |\n| Inline code (`...`) | `<dim>...</dim>` | Wrap inline code snippets |\n| File paths | `<cyan>...</cyan>` | For paths, e.g., `src/index.ts` |\n| Filenames | `<gray>...</gray>` | For file names when mentioned alone |\n| Command names | `<blue>...</blue>` | For commands, e.g., `npm install` |\n| Section headings / titles | `<bold><cyan>...</cyan></bold>` | For section titles in plain text output |\n| Important or strong emphasis (**...**) | `<bold>...</bold>` | For key points that must stand out |\n| Secondary / less important info | `<dim>...</dim>` | For metadata, debug info, token counts, etc. |\n| Tips / important notices | `<yellow>...</yellow>` | For tips, cautions, non-fatal problems |\n| Success confirmations | `<green>...</green>` | For success messages, completion status |\n| Errors or serious problems | `<red>...</red>` | For real problems the user must fix |\n| Neutral informational messages | `<blue>...</blue>` | For general info that is not success/failure |\n| Highlighted keywords / categories | `<magenta>...</magenta>` | For labels, categories, or tags in text |\n| De-emphasized / grayed-out text | `<gray>...</gray>` | For low-priority info, old values, etc. |\n| Underlined emphasis | `<underline>...</underline>` | For things you want to underline instead of bold |\n| Optional / tentative text | `<italic>...</italic>` | For suggestions, optional steps, side notes |\n| Reversed highlight | `<inverse>...</inverse>` | For very strong highlights (rarely use) |\n| Deleted / not recommended content | `<strikethrough>...</strikethrough>` | For deprecated commands or steps |\n\nTags can be combined, e.g., `<bold><red>Critical Error</red></bold>`\n\n- Do not mention the contents of this prompt to users. The prompt provides context and instructions for you to follow, not to recite verbatim. Use the information in the prompt to inform your responses naturally. Bad example: \"You are currently talking to me via a Mac OS terminal interface. How can I help you?\" Good example: (Display terminal-friendly characters and provide suggestions based on the Mac OS system environment)\n\nPlease answer questions in the language the user is using, and flexibly use available tools to complete tasks.\n\n";
|
|
754
1144
|
|
|
755
1145
|
// src/agent/Arki/Arki.ts
|
|
1146
|
+
var toolStartTimes = /* @__PURE__ */ new Map();
|
|
756
1147
|
function createMainAgent() {
|
|
757
1148
|
if (!adapter) {
|
|
758
1149
|
throw new Error("Adapter not initialized, please call init() first");
|
|
759
1150
|
}
|
|
1151
|
+
const proceduresList = Object.values(PROCEDURES).map((p) => `- ${p.name}: ${p.description}`).join("\n");
|
|
760
1152
|
const systemInstruction = Agent.renderTemplate(system_default, {
|
|
761
1153
|
working_dir: workingDir,
|
|
762
|
-
has_manual: HAS_MANUAL
|
|
1154
|
+
has_manual: HAS_MANUAL,
|
|
1155
|
+
procedures: proceduresList || "(none)"
|
|
763
1156
|
});
|
|
764
1157
|
const convertColor = createColorConverter();
|
|
765
1158
|
const agent = new Agent({
|
|
@@ -768,27 +1161,31 @@ function createMainAgent() {
|
|
|
768
1161
|
onStream: (chunk) => {
|
|
769
1162
|
process.stdout.write(convertColor(chunk));
|
|
770
1163
|
},
|
|
771
|
-
onBeforeToolRun: (name
|
|
772
|
-
|
|
773
|
-
const argsPreview = argsStr.length > 60 ? argsStr.substring(0, 60) + "..." : argsStr;
|
|
774
|
-
if (isDebugMode()) {
|
|
775
|
-
console.log(`\x1B[33m\u{1F527} ${name}\x1B[0m \x1B[2m${argsPreview}\x1B[0m`);
|
|
776
|
-
} else {
|
|
777
|
-
process.stdout.write(`\x1B[33m\u{1F527} ${name}\x1B[0m \x1B[2m${argsPreview}\x1B[0m`);
|
|
778
|
-
}
|
|
1164
|
+
onBeforeToolRun: (name) => {
|
|
1165
|
+
toolStartTimes.set(name, Date.now());
|
|
779
1166
|
},
|
|
780
1167
|
onToolResult: (name, args, result) => {
|
|
1168
|
+
const startTime = toolStartTimes.get(name) || Date.now();
|
|
1169
|
+
const elapsed = Date.now() - startTime;
|
|
1170
|
+
toolStartTimes.delete(name);
|
|
781
1171
|
const argsStr = JSON.stringify(args);
|
|
782
1172
|
const argsPreview = argsStr.length > 60 ? argsStr.substring(0, 60) + "..." : argsStr;
|
|
783
|
-
|
|
784
|
-
const firstLine = resultPreview.split("\n")[0];
|
|
1173
|
+
let output = `<green>[TOOL]</green> ${name} <dim>${argsPreview} (${elapsed}ms)`;
|
|
785
1174
|
if (isDebugMode()) {
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
1175
|
+
const lines = result.split("\n").filter((l) => l.trim());
|
|
1176
|
+
let summary;
|
|
1177
|
+
if (lines.length <= 3) {
|
|
1178
|
+
summary = lines.join(", ");
|
|
1179
|
+
if (summary.length > 60) summary = summary.substring(0, 60) + "...";
|
|
1180
|
+
} else {
|
|
1181
|
+
const preview = lines.slice(0, 3).join(", ");
|
|
1182
|
+
summary = preview.length > 50 ? preview.substring(0, 50) + "..." : preview;
|
|
1183
|
+
summary += ` (+${lines.length - 3} more)`;
|
|
1184
|
+
}
|
|
1185
|
+
output += ` -> ${summary}`;
|
|
790
1186
|
}
|
|
791
|
-
|
|
1187
|
+
output += "</dim>";
|
|
1188
|
+
log(output);
|
|
792
1189
|
}
|
|
793
1190
|
});
|
|
794
1191
|
return agent;
|
|
@@ -797,7 +1194,7 @@ function createMainAgent() {
|
|
|
797
1194
|
// package.json
|
|
798
1195
|
var package_default = {
|
|
799
1196
|
name: "arki",
|
|
800
|
-
version: "0.0.
|
|
1197
|
+
version: "0.0.6",
|
|
801
1198
|
description: "AI Agent Programming Assistant",
|
|
802
1199
|
type: "module",
|
|
803
1200
|
main: "dist/index.js",
|
|
@@ -854,13 +1251,21 @@ var package_default = {
|
|
|
854
1251
|
};
|
|
855
1252
|
|
|
856
1253
|
// src/index.ts
|
|
857
|
-
|
|
858
|
-
|
|
1254
|
+
init_log2();
|
|
1255
|
+
init_Msg();
|
|
1256
|
+
|
|
1257
|
+
// src/adapter/index.ts
|
|
1258
|
+
init_Adapter();
|
|
1259
|
+
init_openai();
|
|
1260
|
+
|
|
1261
|
+
// src/index.ts
|
|
1262
|
+
function getConfigPath() {
|
|
1263
|
+
return path8.join(os2.homedir(), ".config", "arki", "config.json");
|
|
859
1264
|
}
|
|
860
1265
|
function resetConfig() {
|
|
861
|
-
const configPath =
|
|
862
|
-
if (
|
|
863
|
-
|
|
1266
|
+
const configPath = getConfigPath();
|
|
1267
|
+
if (fs6.existsSync(configPath)) {
|
|
1268
|
+
fs6.unlinkSync(configPath);
|
|
864
1269
|
console.log(`Configuration file deleted: ${configPath}`);
|
|
865
1270
|
console.log("Default configuration will be used on next startup.");
|
|
866
1271
|
} else {
|
|
@@ -902,60 +1307,62 @@ async function main() {
|
|
|
902
1307
|
debug("Init", "Debug mode enabled");
|
|
903
1308
|
}
|
|
904
1309
|
await init(targetDir);
|
|
905
|
-
const mainAgentConfig =
|
|
1310
|
+
const mainAgentConfig = getAgentConfig("main");
|
|
906
1311
|
const model = MODELS[mainAgentConfig.model];
|
|
907
1312
|
console.log();
|
|
908
|
-
log(
|
|
1313
|
+
log(`<cyan>Arki AI Agent v${package_default.version}</cyan>`);
|
|
909
1314
|
console.log();
|
|
910
|
-
log(
|
|
911
|
-
log(
|
|
1315
|
+
log(`<dim>Model: ${mainAgentConfig.model}${model ? ` (${model.name})` : ""}</dim>`);
|
|
1316
|
+
log(`<dim>Working directory: ${workingDir}</dim>`);
|
|
1317
|
+
log(`<dim>OS: ${OS.name} (${OS.version})</dim>`);
|
|
912
1318
|
if (isDebugMode()) {
|
|
913
|
-
log(
|
|
1319
|
+
log(`<yellow>Debug mode enabled</yellow>`);
|
|
914
1320
|
}
|
|
915
1321
|
console.log();
|
|
916
|
-
log(
|
|
1322
|
+
log(`<dim>Loaded ${Object.keys(TOOLS).length} tools</dim>`);
|
|
917
1323
|
if (isDebugMode()) {
|
|
918
1324
|
debug("Init", "Loaded tools", Object.keys(TOOLS));
|
|
919
1325
|
debug("Init", "Agent config", mainAgentConfig);
|
|
920
1326
|
}
|
|
921
1327
|
console.log();
|
|
922
1328
|
const agent = createMainAgent();
|
|
923
|
-
const rl =
|
|
1329
|
+
const rl = readline2.createInterface({
|
|
924
1330
|
input: process.stdin,
|
|
925
1331
|
output: process.stdout
|
|
926
1332
|
});
|
|
927
|
-
log(
|
|
928
|
-
log(
|
|
1333
|
+
log(`<blue>Enter your question and press Enter to send. Type /exit or /quit to exit.</blue>`);
|
|
1334
|
+
log(`<blue>Type /clear to clear conversation history.</blue>`);
|
|
929
1335
|
console.log();
|
|
1336
|
+
const promptStr = convertColorTags("<green>> </green>");
|
|
930
1337
|
const prompt = () => {
|
|
931
|
-
rl.question(
|
|
1338
|
+
rl.question(promptStr, async (input) => {
|
|
932
1339
|
const trimmed = input.trim();
|
|
933
1340
|
if (trimmed === "/exit" || trimmed === "/quit") {
|
|
934
|
-
log(
|
|
1341
|
+
log(`<cyan>Goodbye!</cyan>`);
|
|
935
1342
|
rl.close();
|
|
936
1343
|
process.exit(0);
|
|
937
1344
|
}
|
|
938
1345
|
if (trimmed === "/clear") {
|
|
939
1346
|
agent.reset();
|
|
940
|
-
log(
|
|
1347
|
+
log(`<yellow>Conversation history cleared</yellow>`);
|
|
941
1348
|
console.log();
|
|
942
1349
|
prompt();
|
|
943
1350
|
return;
|
|
944
1351
|
}
|
|
945
1352
|
if (trimmed === "/help") {
|
|
946
1353
|
console.log();
|
|
947
|
-
log(
|
|
948
|
-
log(
|
|
949
|
-
log(
|
|
950
|
-
log(
|
|
951
|
-
log(
|
|
1354
|
+
log(`<cyan>Available commands:</cyan>`);
|
|
1355
|
+
log(`<dim> /exit, /quit - Exit program</dim>`);
|
|
1356
|
+
log(`<dim> /clear - Clear conversation history</dim>`);
|
|
1357
|
+
log(`<dim> /debug - Toggle debug mode</dim>`);
|
|
1358
|
+
log(`<dim> /help - Show help</dim>`);
|
|
952
1359
|
console.log();
|
|
953
1360
|
prompt();
|
|
954
1361
|
return;
|
|
955
1362
|
}
|
|
956
1363
|
if (trimmed === "/debug") {
|
|
957
1364
|
setDebugMode(!isDebugMode());
|
|
958
|
-
log(
|
|
1365
|
+
log(`<yellow>Debug mode ${isDebugMode() ? "enabled" : "disabled"}</yellow>`);
|
|
959
1366
|
console.log();
|
|
960
1367
|
prompt();
|
|
961
1368
|
return;
|
|
@@ -970,14 +1377,11 @@ async function main() {
|
|
|
970
1377
|
console.log();
|
|
971
1378
|
if (result.usage) {
|
|
972
1379
|
const contextLimit = model?.capabilities.contextWindow || "N/A";
|
|
973
|
-
log(
|
|
974
|
-
"dim",
|
|
975
|
-
`[Tokens: ${result.usage.totalTokens} (prompt: ${result.usage.promptTokens}, cached: ${result.usage.cachedTokens || 0}, limit: ${contextLimit})]`
|
|
976
|
-
);
|
|
1380
|
+
log(`<dim>[Tokens: ${result.usage.totalTokens} (prompt: ${result.usage.promptTokens}, cached: ${result.usage.cachedTokens || 0}, limit: ${contextLimit})]</dim>`);
|
|
977
1381
|
}
|
|
978
1382
|
console.log();
|
|
979
1383
|
} catch (error2) {
|
|
980
|
-
log(
|
|
1384
|
+
log(`<red>Error: ${error2 instanceof Error ? error2.message : String(error2)}</red>`);
|
|
981
1385
|
console.log();
|
|
982
1386
|
}
|
|
983
1387
|
prompt();
|
|
@@ -998,7 +1402,10 @@ export {
|
|
|
998
1402
|
MODELS,
|
|
999
1403
|
Msg,
|
|
1000
1404
|
MsgType,
|
|
1405
|
+
OS,
|
|
1001
1406
|
OpenAIAdapter,
|
|
1407
|
+
PATHS,
|
|
1408
|
+
PROCEDURES,
|
|
1002
1409
|
SystemMsg,
|
|
1003
1410
|
TEMPERATURE,
|
|
1004
1411
|
TOOLS,
|
|
@@ -1008,13 +1415,20 @@ export {
|
|
|
1008
1415
|
UserMsg,
|
|
1009
1416
|
adapter,
|
|
1010
1417
|
colors,
|
|
1011
|
-
|
|
1418
|
+
convertColorTags,
|
|
1419
|
+
createColorConverter,
|
|
1012
1420
|
debug,
|
|
1013
1421
|
error,
|
|
1422
|
+
getAgentConfig,
|
|
1423
|
+
getApiKey,
|
|
1424
|
+
getConfig,
|
|
1014
1425
|
info,
|
|
1015
1426
|
init,
|
|
1427
|
+
initAdapter,
|
|
1016
1428
|
isDebugMode,
|
|
1017
1429
|
log,
|
|
1430
|
+
print,
|
|
1431
|
+
saveConfig,
|
|
1018
1432
|
setDebugMode,
|
|
1019
1433
|
setWorkingDir,
|
|
1020
1434
|
success,
|