arki 0.0.5 → 0.0.7

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 CHANGED
@@ -1,125 +1,421 @@
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/index.ts
4
- import * as readline from "readline";
5
- import * as fs5 from "fs";
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 getConfigPath() {
15
- return path.join(os.homedir(), ".config", "arki", "config.json");
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
+ }
28
+ }
29
+ function setWorkingDir(dir) {
30
+ workingDir = dir;
16
31
  }
17
- function getDefaultConfigPath() {
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, "config.json");
43
+ return path.join(__dirname, "..", relativePath);
20
44
  }
21
- var ConfigManager = class {
22
- config;
23
- loaded = false;
24
- /**
25
- * Load configuration (called at program startup)
26
- */
27
- async load() {
28
- if (this.loaded) {
29
- return this.config;
30
- }
31
- const configPath = getConfigPath();
32
- try {
33
- const content = await fs.readFile(configPath, "utf-8");
34
- this.config = JSON.parse(content);
35
- } catch {
36
- const defaultContent = await fs.readFile(getDefaultConfigPath(), "utf-8");
37
- this.config = JSON.parse(defaultContent);
38
- const configDir = path.dirname(configPath);
39
- await fs.mkdir(configDir, { recursive: true });
40
- await fs.writeFile(configPath, defaultContent, "utf-8");
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
- * Save configuration
48
- */
49
- async save() {
50
- const configPath = getConfigPath();
51
- const configToSave = { ...this.config };
52
- if (this.config.apiKeys) {
53
- configToSave.apiKeys = { ...this.config.apiKeys };
54
- if (process.env.OPENAI_API_KEY && configToSave.apiKeys.openai === process.env.OPENAI_API_KEY) {
55
- delete configToSave.apiKeys.openai;
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
- get() {
64
- return this.config;
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
- getApiKey(provider) {
67
- return this.config.apiKeys?.[provider];
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
- getAgentConfig(agentType) {
70
- const agentConfig = this.config.agents[agentType];
71
- if (!agentConfig) {
72
- throw new Error(`Agent config not found for type: ${agentType}`);
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";
103
+ }
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);
73
119
  }
74
- return agentConfig;
75
120
  }
76
- loadEnvApiKeys() {
77
- if (process.env.OPENAI_API_KEY) {
78
- if (!this.config.apiKeys) this.config.apiKeys = {};
79
- if (!this.config.apiKeys.openai) {
80
- this.config.apiKeys.openai = process.env.OPENAI_API_KEY;
81
- }
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
+ });
138
+
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
+ });
163
+
164
+ // src/log/log.ts
165
+ function getTimestamp() {
166
+ return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
167
+ }
168
+ function print(message) {
169
+ console.log(convertColorTags(message));
170
+ }
171
+ function log(message) {
172
+ print(`<gray>[${getTimestamp()}]</gray> ${message}`);
173
+ }
174
+ function info(message) {
175
+ log(`<blue>[INFO]</blue> ${message}`);
176
+ }
177
+ function success(message) {
178
+ log(`<green>[OK]</green> ${message}`);
179
+ }
180
+ function warn(message) {
181
+ log(`<yellow>[WARN]</yellow> ${message}`);
182
+ }
183
+ function error(message) {
184
+ log(`<red>[ERROR]</red> ${message}`);
185
+ }
186
+ var init_log = __esm({
187
+ "src/log/log.ts"() {
188
+ "use strict";
189
+ init_log2();
190
+ }
191
+ });
192
+
193
+ // src/log/debug.ts
194
+ function isDebugMode() {
195
+ return _debugMode;
196
+ }
197
+ function setDebugMode(enabled) {
198
+ _debugMode = enabled;
199
+ }
200
+ function formatData(data, maxLen = 100) {
201
+ if (data === void 0) return "";
202
+ const str = typeof data === "string" ? data : JSON.stringify(data);
203
+ const singleLine = str.replace(/\s+/g, " ").trim();
204
+ return singleLine.length > maxLen ? singleLine.slice(0, maxLen) + "..." : singleLine;
205
+ }
206
+ function debug(category, message, data) {
207
+ if (!_debugMode) return;
208
+ const dataStr = data !== void 0 ? ` <dim>${formatData(data)}</dim>` : "";
209
+ log(`<magenta>[${category}]</magenta> <cyan>${message}</cyan>${dataStr}`);
210
+ }
211
+ var _debugMode;
212
+ var init_debug = __esm({
213
+ "src/log/debug.ts"() {
214
+ "use strict";
215
+ init_log();
216
+ _debugMode = false;
217
+ }
218
+ });
219
+
220
+ // src/log/index.ts
221
+ function convertColorTags(str) {
222
+ return str.replace(tagRegex, (_, closing, tag) => {
223
+ return closing ? colors.reset : colors[tag.toLowerCase()] || "";
224
+ });
225
+ }
226
+ function createColorConverter() {
227
+ let buffer = "";
228
+ return (chunk) => {
229
+ buffer += chunk;
230
+ const lastOpen = buffer.lastIndexOf("<");
231
+ if (lastOpen === -1) {
232
+ const out2 = convertColorTags(buffer);
233
+ buffer = "";
234
+ return out2;
82
235
  }
83
- if (process.env.ANTHROPIC_API_KEY) {
84
- if (!this.config.apiKeys) this.config.apiKeys = {};
85
- if (!this.config.apiKeys.anthropic) {
86
- this.config.apiKeys.anthropic = process.env.ANTHROPIC_API_KEY;
87
- }
236
+ if (buffer.indexOf(">", lastOpen) !== -1) {
237
+ const out2 = convertColorTags(buffer);
238
+ buffer = "";
239
+ return out2;
88
240
  }
89
- if (process.env.GOOGLE_API_KEY) {
90
- if (!this.config.apiKeys) this.config.apiKeys = {};
91
- if (!this.config.apiKeys.google) {
92
- this.config.apiKeys.google = process.env.GOOGLE_API_KEY;
241
+ const out = convertColorTags(buffer.slice(0, lastOpen));
242
+ buffer = buffer.slice(lastOpen);
243
+ return out;
244
+ };
245
+ }
246
+ var colors, tagNames, tagRegex;
247
+ var init_log2 = __esm({
248
+ "src/log/index.ts"() {
249
+ "use strict";
250
+ init_debug();
251
+ init_log();
252
+ colors = {
253
+ reset: "\x1B[0m",
254
+ bold: "\x1B[1m",
255
+ dim: "\x1B[2m",
256
+ italic: "\x1B[3m",
257
+ underline: "\x1B[4m",
258
+ inverse: "\x1B[7m",
259
+ strikethrough: "\x1B[9m",
260
+ red: "\x1B[31m",
261
+ green: "\x1B[32m",
262
+ yellow: "\x1B[33m",
263
+ blue: "\x1B[34m",
264
+ magenta: "\x1B[35m",
265
+ cyan: "\x1B[36m",
266
+ gray: "\x1B[90m"
267
+ };
268
+ tagNames = Object.keys(colors).filter((k) => k !== "reset").join("|");
269
+ tagRegex = new RegExp(`<(\\/?)(${tagNames})>`, "gi");
270
+ }
271
+ });
272
+
273
+ // src/init/loader.ts
274
+ var loader_exports = {};
275
+ __export(loader_exports, {
276
+ getAgentConfig: () => getAgentConfig,
277
+ getApiKey: () => getApiKey,
278
+ getConfig: () => getConfig,
279
+ loadConfigs: () => loadConfigs,
280
+ saveConfig: () => saveConfig
281
+ });
282
+ import * as path3 from "path";
283
+ function deepMerge(base, override) {
284
+ const result = {
285
+ ...base,
286
+ agents: { ...base.agents }
287
+ };
288
+ if (override.agents) {
289
+ for (const key of Object.keys(override.agents)) {
290
+ const overrideAgent = override.agents[key];
291
+ if (overrideAgent) {
292
+ result.agents[key] = { ...result.agents[key], ...overrideAgent };
93
293
  }
94
294
  }
95
295
  }
96
- };
97
- var config = new ConfigManager();
296
+ return result;
297
+ }
298
+ async function loadConfigs() {
299
+ if (mergedConfig) {
300
+ return mergedConfig;
301
+ }
302
+ const globalConfigPath = path3.join(PATHS.globalConfig, "config.json");
303
+ const globalConfig = await readJsonFile(globalConfigPath);
304
+ if (!globalConfig) {
305
+ throw new Error(`Failed to load global config: ${globalConfigPath}`);
306
+ }
307
+ const projectConfigPath = path3.join(PATHS.projectConfig, "config.json");
308
+ const projectConfig = await readJsonFile(projectConfigPath);
309
+ if (projectConfig) {
310
+ mergedConfig = deepMerge(globalConfig, projectConfig);
311
+ } else {
312
+ mergedConfig = globalConfig;
313
+ }
314
+ return mergedConfig;
315
+ }
316
+ function getConfig() {
317
+ if (!mergedConfig) {
318
+ throw new Error("Config not loaded yet. Please call loadConfigs() first.");
319
+ }
320
+ return mergedConfig;
321
+ }
322
+ function getApiKey(provider) {
323
+ const envMap = {
324
+ openai: "OPENAI_API_KEY",
325
+ anthropic: "ANTHROPIC_API_KEY",
326
+ google: "GOOGLE_API_KEY"
327
+ };
328
+ const envVar = envMap[provider] || `${provider.toUpperCase()}_API_KEY`;
329
+ return process.env[envVar];
330
+ }
331
+ function getAgentConfig(agentType) {
332
+ const agentConfig = getConfig().agents[agentType];
333
+ if (!agentConfig) {
334
+ throw new Error(`Agent config not found: ${agentType}`);
335
+ }
336
+ return agentConfig;
337
+ }
338
+ async function saveConfig() {
339
+ const config = getConfig();
340
+ const configPath = path3.join(PATHS.globalConfig, "config.json");
341
+ await writeJsonFile(configPath, config);
342
+ }
343
+ var mergedConfig;
344
+ var init_loader = __esm({
345
+ "src/init/loader.ts"() {
346
+ "use strict";
347
+ init_fs();
348
+ mergedConfig = null;
349
+ }
350
+ });
351
+
352
+ // src/init/project.ts
353
+ var project_exports = {};
354
+ __export(project_exports, {
355
+ initProject: () => initProject
356
+ });
357
+ import * as path4 from "path";
358
+ import * as readline from "readline";
359
+ async function askQuestion(question) {
360
+ const rl = readline.createInterface({
361
+ input: process.stdin,
362
+ output: process.stdout
363
+ });
364
+ return new Promise((resolve4) => {
365
+ rl.question(`${question} (y/n): `, (answer) => {
366
+ rl.close();
367
+ resolve4(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
368
+ });
369
+ });
370
+ }
371
+ async function initProject(forceInit) {
372
+ const projectConfigDir = PATHS.projectConfig;
373
+ if (await dirExists(projectConfigDir)) {
374
+ return;
375
+ }
376
+ const trusted = forceInit ? true : await (async () => {
377
+ print(`
378
+ <dim>Project directory: ${workingDir}</dim>`);
379
+ return askQuestion("Do you trust this project and want to initialize arki config?");
380
+ })();
381
+ if (!trusted) {
382
+ print("<yellow>Initialization cancelled.</yellow>");
383
+ process.exit(0);
384
+ }
385
+ await copyDir(PATHS.projectTemplate, projectConfigDir);
386
+ const statePath = path4.join(projectConfigDir, "state.json");
387
+ const state = {
388
+ initialized: true,
389
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
390
+ };
391
+ await writeJsonFile(statePath, state);
392
+ print("<green>Project configuration initialized.</green>");
393
+ }
394
+ var init_project = __esm({
395
+ "src/init/project.ts"() {
396
+ "use strict";
397
+ init_fs();
398
+ init_log2();
399
+ }
400
+ });
401
+
402
+ // src/index.ts
403
+ import * as readline2 from "readline";
404
+ import * as fs6 from "fs";
405
+ import * as path8 from "path";
406
+ import * as os2 from "os";
407
+
408
+ // src/global.ts
409
+ init_fs();
98
410
 
99
411
  // src/adapter/openai.ts
100
412
  import OpenAI from "openai";
101
413
 
102
414
  // src/adapter/Adapter.ts
103
- var TEMPERATURE = 0.2;
104
- var MAX_COMPLETION_TOKENS = 4096;
105
415
  var Adapter = class {
106
416
  apiKey;
107
- model;
108
- /** Use Flex API (OpenAI) - low priority, low cost */
109
- flex;
110
- /** Reasoning effort (thinking mode) */
111
- reasoningEffort;
112
- /** Available tools list */
113
- tools;
114
- constructor(config2) {
115
- this.apiKey = config2.apiKey;
116
- this.model = config2.model;
117
- this.flex = config2.flex;
118
- this.reasoningEffort = config2.reasoningEffort;
119
- this.tools = config2.tools;
120
- }
121
- getModel() {
122
- return this.model;
417
+ constructor(apiKey) {
418
+ this.apiKey = apiKey;
123
419
  }
124
420
  };
125
421
 
@@ -179,97 +475,12 @@ var ToolResultMsg = class _ToolResultMsg extends Msg {
179
475
  }
180
476
  };
181
477
 
182
- // src/log/log.ts
183
- function getTimestamp() {
184
- return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
185
- }
186
- function log(message) {
187
- const ts = `<gray>[${getTimestamp()}]</gray>`;
188
- console.log(convertColorTags(`${ts} ${message}`));
189
- }
190
- function info(message) {
191
- log(`<blue>[INFO]</blue> ${message}`);
192
- }
193
- function success(message) {
194
- log(`<green>[OK]</green> ${message}`);
195
- }
196
- function warn(message) {
197
- log(`<yellow>[WARN]</yellow> ${message}`);
198
- }
199
- function error(message) {
200
- log(`<red>[ERROR]</red> ${message}`);
201
- }
202
-
203
- // src/log/debug.ts
204
- var _debugMode = false;
205
- function isDebugMode() {
206
- return _debugMode;
207
- }
208
- function setDebugMode(enabled) {
209
- _debugMode = enabled;
210
- }
211
- function formatData(data, maxLen = 100) {
212
- if (data === void 0) return "";
213
- const str = typeof data === "string" ? data : JSON.stringify(data);
214
- const singleLine = str.replace(/\s+/g, " ").trim();
215
- return singleLine.length > maxLen ? singleLine.slice(0, maxLen) + "..." : singleLine;
216
- }
217
- function debug(category, message, data) {
218
- if (!_debugMode) return;
219
- const dataStr = data !== void 0 ? ` <dim>${formatData(data)}</dim>` : "";
220
- log(`<magenta>[${category}]</magenta> <cyan>${message}</cyan>${dataStr}`);
221
- }
222
-
223
- // src/log/index.ts
224
- var colors2 = {
225
- reset: "\x1B[0m",
226
- bold: "\x1B[1m",
227
- dim: "\x1B[2m",
228
- italic: "\x1B[3m",
229
- underline: "\x1B[4m",
230
- inverse: "\x1B[7m",
231
- strikethrough: "\x1B[9m",
232
- red: "\x1B[31m",
233
- green: "\x1B[32m",
234
- yellow: "\x1B[33m",
235
- blue: "\x1B[34m",
236
- magenta: "\x1B[35m",
237
- cyan: "\x1B[36m",
238
- gray: "\x1B[90m"
239
- };
240
- var tagNames = Object.keys(colors2).filter((k) => k !== "reset").join("|");
241
- var tagRegex = new RegExp(`<(\\/?)(${tagNames})>`, "gi");
242
- function convertColorTags(str) {
243
- return str.replace(tagRegex, (_, closing, tag) => {
244
- return closing ? colors2.reset : colors2[tag.toLowerCase()] || "";
245
- });
246
- }
247
- function createColorConverter() {
248
- let buffer = "";
249
- return (chunk) => {
250
- buffer += chunk;
251
- const lastOpen = buffer.lastIndexOf("<");
252
- if (lastOpen === -1) {
253
- const out2 = convertColorTags(buffer);
254
- buffer = "";
255
- return out2;
256
- }
257
- if (buffer.indexOf(">", lastOpen) !== -1) {
258
- const out2 = convertColorTags(buffer);
259
- buffer = "";
260
- return out2;
261
- }
262
- const out = convertColorTags(buffer.slice(0, lastOpen));
263
- buffer = buffer.slice(lastOpen);
264
- return out;
265
- };
266
- }
267
-
268
478
  // src/adapter/openai.ts
479
+ init_log2();
269
480
  var OpenAIAdapter = class extends Adapter {
270
481
  client;
271
- constructor(config2) {
272
- super(config2);
482
+ constructor(apiKey) {
483
+ super(apiKey);
273
484
  if (!this.apiKey) {
274
485
  throw new Error("OpenAI API key is required. Set OPENAI_API_KEY environment variable.");
275
486
  }
@@ -308,8 +519,9 @@ var OpenAIAdapter = class extends Adapter {
308
519
  }
309
520
  return result;
310
521
  }
311
- getTools() {
312
- return this.tools?.map((t) => ({
522
+ formatTools(tools) {
523
+ if (tools.length === 0) return void 0;
524
+ return tools.map((t) => ({
313
525
  type: "function",
314
526
  function: {
315
527
  name: t.name,
@@ -322,20 +534,19 @@ var OpenAIAdapter = class extends Adapter {
322
534
  }
323
535
  }));
324
536
  }
325
- async chat(messages, onChunk) {
326
- debug("API", `Requesting OpenAI (model: ${this.model}, messages: ${messages.length})`);
537
+ async chat(model, messages, tools, options, onChunk) {
538
+ debug("API", `Requesting OpenAI (model: ${model}, messages: ${messages.length})`);
327
539
  const openaiMessages = this.toOpenAIMessages(messages);
328
540
  const startTime = Date.now();
329
541
  const requestParams = {
330
- model: this.model,
542
+ model,
331
543
  messages: openaiMessages,
332
- tools: this.getTools(),
333
- temperature: TEMPERATURE,
334
- max_completion_tokens: MAX_COMPLETION_TOKENS,
544
+ tools: this.formatTools(tools),
545
+ max_completion_tokens: options.maxCompletionTokens,
335
546
  stream: true,
336
547
  stream_options: { include_usage: true },
337
- service_tier: this.flex ? "flex" : void 0,
338
- reasoning_effort: this.reasoningEffort
548
+ service_tier: options.flex ? "flex" : void 0,
549
+ reasoning_effort: options.reasoningEffort
339
550
  };
340
551
  const stream = await this.client.chat.completions.create(requestParams);
341
552
  let text = "";
@@ -378,33 +589,46 @@ var OpenAIAdapter = class extends Adapter {
378
589
  }
379
590
  };
380
591
 
381
- // src/global.ts
382
- var workingDir = process.cwd();
383
- function setWorkingDir(dir) {
384
- workingDir = dir;
385
- }
592
+ // src/init/global.ts
593
+ init_fs();
386
594
  var TOOLS = {};
387
595
  var PROCEDURES = {};
388
- var adapter = null;
389
- function initAdapter() {
390
- if (adapter) {
391
- return;
596
+ var adapters = {};
597
+ function getAdapter(platform) {
598
+ const adapter = adapters[platform];
599
+ if (!adapter) {
600
+ throw new Error(`Adapter not found for platform: ${platform}`);
601
+ }
602
+ return adapter;
603
+ }
604
+ async function initGlobalConfig() {
605
+ const globalConfigDir = PATHS.globalConfig;
606
+ if (await dirExists(globalConfigDir)) return;
607
+ await copyDir(PATHS.globalTemplate, globalConfigDir);
608
+ }
609
+ async function initAdapters() {
610
+ const { getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
611
+ const openaiKey = getApiKey2("openai");
612
+ if (openaiKey) {
613
+ adapters["openai"] = new OpenAIAdapter(openaiKey);
392
614
  }
393
- const mainAgentConfig = config.getAgentConfig("main");
394
- adapter = new OpenAIAdapter({
395
- apiKey: config.getApiKey("openai") || "",
396
- model: mainAgentConfig.model,
397
- flex: mainAgentConfig.flex,
398
- tools: Object.values(TOOLS)
399
- });
400
615
  }
401
- async function init(cwd) {
402
- workingDir = cwd || process.cwd();
403
- await config.load();
404
- initAdapter();
616
+ async function init(cwd, forceInit) {
617
+ const { setWorkingDir: setWorkingDir2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
618
+ setWorkingDir2(cwd || process.cwd());
619
+ await initGlobalConfig();
620
+ const { initProject: initProject2 } = await Promise.resolve().then(() => (init_project(), project_exports));
621
+ await initProject2(forceInit);
622
+ const { loadConfigs: loadConfigs2 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
623
+ await loadConfigs2();
624
+ await initAdapters();
405
625
  }
406
626
 
627
+ // src/init/index.ts
628
+ init_loader();
629
+
407
630
  // src/tool/Tool.ts
631
+ init_log2();
408
632
  var HAS_MANUAL = "\u{1F4D8}";
409
633
  var Tool = class _Tool {
410
634
  name;
@@ -413,12 +637,12 @@ var Tool = class _Tool {
413
637
  required;
414
638
  manual;
415
639
  _execute;
416
- constructor(config2) {
417
- this.name = config2.name;
418
- this.parameters = config2.parameters;
419
- this.required = config2.required;
420
- this._execute = config2.execute;
421
- const { description, manual } = _Tool.parseManual(config2.manualContent);
640
+ constructor(config) {
641
+ this.name = config.name;
642
+ this.parameters = config.parameters;
643
+ this.required = config.required;
644
+ this._execute = config.execute;
645
+ const { description, manual } = _Tool.parseManual(config.manualContent);
422
646
  this.description = description;
423
647
  this.manual = manual;
424
648
  }
@@ -461,8 +685,8 @@ var Tool = class _Tool {
461
685
  };
462
686
 
463
687
  // src/tool/read_file/index.ts
464
- import * as fs2 from "fs/promises";
465
- import * as path2 from "path";
688
+ import * as fs3 from "fs/promises";
689
+ import * as path5 from "path";
466
690
 
467
691
  // src/tool/read_file/manual.md
468
692
  var manual_default = "read_file: Read the content of a specified file\n";
@@ -478,8 +702,8 @@ TOOLS["read_file"] = new Tool({
478
702
  execute: async (args) => {
479
703
  const filePath = args.path;
480
704
  try {
481
- const fullPath = path2.resolve(workingDir, filePath);
482
- return await fs2.readFile(fullPath, "utf-8");
705
+ const fullPath = path5.resolve(workingDir, filePath);
706
+ return await fs3.readFile(fullPath, "utf-8");
483
707
  } catch (error2) {
484
708
  return {
485
709
  content: `Failed to read file: ${error2 instanceof Error ? error2.message : String(error2)}`,
@@ -490,8 +714,8 @@ TOOLS["read_file"] = new Tool({
490
714
  });
491
715
 
492
716
  // src/tool/write_file/index.ts
493
- import * as fs3 from "fs/promises";
494
- import * as path3 from "path";
717
+ import * as fs4 from "fs/promises";
718
+ import * as path6 from "path";
495
719
 
496
720
  // src/tool/write_file/manual.md
497
721
  var manual_default2 = "write_file: Write content to a specified file, create the file if it doesn't exist\n";
@@ -509,9 +733,9 @@ TOOLS["write_file"] = new Tool({
509
733
  const filePath = args.path;
510
734
  const content = args.content;
511
735
  try {
512
- const fullPath = path3.resolve(workingDir, filePath);
513
- await fs3.mkdir(path3.dirname(fullPath), { recursive: true });
514
- await fs3.writeFile(fullPath, content, "utf-8");
736
+ const fullPath = path6.resolve(workingDir, filePath);
737
+ await fs4.mkdir(path6.dirname(fullPath), { recursive: true });
738
+ await fs4.writeFile(fullPath, content, "utf-8");
515
739
  return `File written successfully: ${filePath}`;
516
740
  } catch (error2) {
517
741
  return {
@@ -523,8 +747,8 @@ TOOLS["write_file"] = new Tool({
523
747
  });
524
748
 
525
749
  // src/tool/list_directory/index.ts
526
- import * as fs4 from "fs/promises";
527
- import * as path4 from "path";
750
+ import * as fs5 from "fs/promises";
751
+ import * as path7 from "path";
528
752
 
529
753
  // src/tool/list_directory/manual.md
530
754
  var manual_default3 = "list_directory: List files and subdirectories in a specified directory\n";
@@ -540,8 +764,8 @@ TOOLS["list_directory"] = new Tool({
540
764
  execute: async (args) => {
541
765
  const dirPath = args.path || ".";
542
766
  try {
543
- const fullPath = path4.resolve(workingDir, dirPath);
544
- const entries = await fs4.readdir(fullPath, { withFileTypes: true });
767
+ const fullPath = path7.resolve(workingDir, dirPath);
768
+ const entries = await fs5.readdir(fullPath, { withFileTypes: true });
545
769
  const result = entries.map((entry) => {
546
770
  const type = entry.isDirectory() ? "[DIR]" : "[FILE]";
547
771
  return `${type} ${entry.name}`;
@@ -659,9 +883,9 @@ var Procedure = class _Procedure {
659
883
  name;
660
884
  description;
661
885
  manual;
662
- constructor(config2) {
663
- this.name = config2.name;
664
- const { description, manual } = _Procedure.parseManual(config2.procedureContent);
886
+ constructor(config) {
887
+ this.name = config.name;
888
+ const { description, manual } = _Procedure.parseManual(config.procedureContent);
665
889
  this.description = description;
666
890
  this.manual = manual;
667
891
  }
@@ -692,6 +916,9 @@ PROCEDURES["understand_project"] = new Procedure({
692
916
  procedureContent: procedure_default
693
917
  });
694
918
 
919
+ // src/index.ts
920
+ init_log2();
921
+
695
922
  // src/model/models.ts
696
923
  var MODELS = {
697
924
  "gpt-5.2": {
@@ -733,12 +960,17 @@ var MODELS = {
733
960
  };
734
961
 
735
962
  // src/agent/Agent.ts
963
+ init_log2();
736
964
  var Agent = class {
737
965
  config;
738
966
  messages = [];
739
- constructor(config2) {
740
- this.config = config2;
741
- this.messages = [...config2.messages];
967
+ toolsMap = {};
968
+ constructor(config) {
969
+ this.config = config;
970
+ this.messages = [...config.messages];
971
+ for (const tool of config.tools) {
972
+ this.toolsMap[tool.name] = tool;
973
+ }
742
974
  }
743
975
  /**
744
976
  * Render template string, replacing {{variable}} style variables
@@ -760,7 +992,16 @@ var Agent = class {
760
992
  let totalUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0, cachedTokens: 0 };
761
993
  while (true) {
762
994
  debug("Agent", `Starting conversation (message count: ${this.messages.length})`);
763
- const response = await this.config.adapter.chat(this.messages, this.config.onStream);
995
+ const response = await this.config.adapter.chat(
996
+ this.config.model,
997
+ this.messages,
998
+ this.config.tools,
999
+ {
1000
+ ...this.config.platformOptions,
1001
+ maxCompletionTokens: this.config.maxCompletionTokens
1002
+ },
1003
+ this.config.onStream
1004
+ );
764
1005
  if (response.usage) {
765
1006
  totalUsage.promptTokens += response.usage.promptTokens;
766
1007
  totalUsage.completionTokens += response.usage.completionTokens;
@@ -785,7 +1026,7 @@ var Agent = class {
785
1026
  const toolResults = [];
786
1027
  for (const tc of toolCalls) {
787
1028
  this.config.onBeforeToolRun?.(tc.name, tc.arguments);
788
- const tool = TOOLS[tc.name];
1029
+ const tool = this.toolsMap[tc.name];
789
1030
  const result = tool ? await tool.run(tc.arguments) : { toolName: tc.name, result: `Unknown tool: ${tc.name}`, isError: true };
790
1031
  toolCallHistory.push({
791
1032
  name: tc.name,
@@ -804,15 +1045,22 @@ var Agent = class {
804
1045
  }
805
1046
  };
806
1047
 
1048
+ // src/agent/Arki/Arki.ts
1049
+ init_log2();
1050
+
807
1051
  // src/agent/Arki/system.md
808
1052
  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";
809
1053
 
810
1054
  // src/agent/Arki/Arki.ts
1055
+ var MAX_COMPLETION_TOKENS = 4096;
811
1056
  var toolStartTimes = /* @__PURE__ */ new Map();
812
- function createMainAgent() {
813
- if (!adapter) {
814
- throw new Error("Adapter not initialized, please call init() first");
1057
+ function createArkiAgent() {
1058
+ const config = getAgentConfig("arki");
1059
+ const model = MODELS[config.model];
1060
+ if (!model) {
1061
+ throw new Error(`Unknown model: ${config.model}`);
815
1062
  }
1063
+ const adapter = getAdapter(model.provider);
816
1064
  const proceduresList = Object.values(PROCEDURES).map((p) => `- ${p.name}: ${p.description}`).join("\n");
817
1065
  const systemInstruction = Agent.renderTemplate(system_default, {
818
1066
  working_dir: workingDir,
@@ -822,6 +1070,13 @@ function createMainAgent() {
822
1070
  const convertColor = createColorConverter();
823
1071
  const agent = new Agent({
824
1072
  adapter,
1073
+ model: config.model,
1074
+ tools: Object.values(TOOLS),
1075
+ maxCompletionTokens: MAX_COMPLETION_TOKENS,
1076
+ platformOptions: {
1077
+ flex: config.flex,
1078
+ reasoningEffort: config.reasoningEffort
1079
+ },
825
1080
  messages: [new SystemMsg(systemInstruction)],
826
1081
  onStream: (chunk) => {
827
1082
  process.stdout.write(convertColor(chunk));
@@ -859,7 +1114,7 @@ function createMainAgent() {
859
1114
  // package.json
860
1115
  var package_default = {
861
1116
  name: "arki",
862
- version: "0.0.5",
1117
+ version: "0.0.7",
863
1118
  description: "AI Agent Programming Assistant",
864
1119
  type: "module",
865
1120
  main: "dist/index.js",
@@ -916,13 +1171,14 @@ var package_default = {
916
1171
  };
917
1172
 
918
1173
  // src/index.ts
919
- function getConfigPath2() {
920
- return path5.join(os2.homedir(), ".config", "arki", "config.json");
1174
+ init_log2();
1175
+ function getConfigPath() {
1176
+ return path8.join(os2.homedir(), ".config", "arki", "config.json");
921
1177
  }
922
1178
  function resetConfig() {
923
- const configPath = getConfigPath2();
924
- if (fs5.existsSync(configPath)) {
925
- fs5.unlinkSync(configPath);
1179
+ const configPath = getConfigPath();
1180
+ if (fs6.existsSync(configPath)) {
1181
+ fs6.unlinkSync(configPath);
926
1182
  console.log(`Configuration file deleted: ${configPath}`);
927
1183
  console.log("Default configuration will be used on next startup.");
928
1184
  } else {
@@ -934,6 +1190,7 @@ function parseArgs() {
934
1190
  const args = process.argv.slice(2);
935
1191
  let targetDir = process.cwd();
936
1192
  let enableDebug = false;
1193
+ let forceInit = false;
937
1194
  for (let i = 0; i < args.length; i++) {
938
1195
  if (args[i] === "-p" && args[i + 1]) {
939
1196
  targetDir = args[i + 1];
@@ -942,6 +1199,8 @@ function parseArgs() {
942
1199
  enableDebug = true;
943
1200
  } else if (args[i] === "--reset") {
944
1201
  resetConfig();
1202
+ } else if (args[i] === "--init") {
1203
+ forceInit = true;
945
1204
  } else if (args[i] === "--help" || args[i] === "-h") {
946
1205
  console.log(`
947
1206
  Usage: arki [options]
@@ -949,40 +1208,37 @@ Usage: arki [options]
949
1208
  Options:
950
1209
  -p <path> Specify working directory
951
1210
  --debug, -d Enable debug mode, show detailed logs
1211
+ --init Initialize project config without prompting
952
1212
  --reset Reset configuration to factory defaults
953
1213
  --help, -h Show help information
954
1214
  `);
955
1215
  process.exit(0);
956
1216
  }
957
1217
  }
958
- return { targetDir, enableDebug };
1218
+ return { targetDir, enableDebug, forceInit };
959
1219
  }
960
1220
  async function main() {
961
- const { targetDir, enableDebug } = parseArgs();
1221
+ const { targetDir, enableDebug, forceInit } = parseArgs();
962
1222
  if (enableDebug) {
963
1223
  setDebugMode(true);
964
1224
  debug("Init", "Debug mode enabled");
965
1225
  }
966
- await init(targetDir);
967
- const mainAgentConfig = config.getAgentConfig("main");
968
- const model = MODELS[mainAgentConfig.model];
969
- console.log();
970
- log(`<cyan>Arki AI Agent v${package_default.version}</cyan>`);
1226
+ await init(targetDir, forceInit);
1227
+ const arkiAgentConfig = getAgentConfig("arki");
1228
+ const model = MODELS[arkiAgentConfig.model];
971
1229
  console.log();
972
- log(`<dim>Model: ${mainAgentConfig.model}${model ? ` (${model.name})` : ""}</dim>`);
973
- log(`<dim>Working directory: ${workingDir}</dim>`);
1230
+ log(`<bold><cyan>Arki AI Agent</cyan></bold> <dim>v${package_default.version}</dim>`);
1231
+ log(`<green>Model:</green> <bold>${model?.name || arkiAgentConfig.model}</bold> <dim>|</dim> <green>OS:</green> ${OS.name} <dim>(${OS.version})</dim>`);
1232
+ log(`<green>Path:</green> <dim>${workingDir}</dim>`);
1233
+ log(`<green>Tools:</green> ${Object.keys(TOOLS).length} loaded`);
974
1234
  if (isDebugMode()) {
975
1235
  log(`<yellow>Debug mode enabled</yellow>`);
976
- }
977
- console.log();
978
- log(`<dim>Loaded ${Object.keys(TOOLS).length} tools</dim>`);
979
- if (isDebugMode()) {
980
1236
  debug("Init", "Loaded tools", Object.keys(TOOLS));
981
- debug("Init", "Agent config", mainAgentConfig);
1237
+ debug("Init", "Agent config", arkiAgentConfig);
982
1238
  }
983
1239
  console.log();
984
- const agent = createMainAgent();
985
- const rl = readline.createInterface({
1240
+ const agent = createArkiAgent();
1241
+ const rl = readline2.createInterface({
986
1242
  input: process.stdin,
987
1243
  output: process.stdout
988
1244
  });
@@ -1054,30 +1310,35 @@ export {
1054
1310
  Adapter,
1055
1311
  Agent,
1056
1312
  HAS_MANUAL,
1057
- MAX_COMPLETION_TOKENS,
1058
1313
  MODELS,
1059
1314
  Msg,
1060
1315
  MsgType,
1316
+ OS,
1061
1317
  OpenAIAdapter,
1318
+ PATHS,
1062
1319
  PROCEDURES,
1063
1320
  SystemMsg,
1064
- TEMPERATURE,
1065
1321
  TOOLS,
1066
1322
  Tool,
1067
1323
  ToolCallMsg,
1068
1324
  ToolResultMsg,
1069
1325
  UserMsg,
1070
- adapter,
1071
- colors2 as colors,
1072
- config,
1326
+ adapters,
1327
+ colors,
1073
1328
  convertColorTags,
1074
1329
  createColorConverter,
1075
1330
  debug,
1076
1331
  error,
1332
+ getAdapter,
1333
+ getAgentConfig,
1334
+ getApiKey,
1335
+ getConfig,
1077
1336
  info,
1078
1337
  init,
1079
1338
  isDebugMode,
1080
1339
  log,
1340
+ print,
1341
+ saveConfig,
1081
1342
  setDebugMode,
1082
1343
  setWorkingDir,
1083
1344
  success,