arki 0.0.3 → 0.0.4

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 CHANGED
@@ -1,3 +1,5 @@
1
+ > **⚠️ Warning: This project is under active development. Please do not use it in production environments.**
2
+
1
3
  # Arki - AI Agent Programming Assistant
2
4
 
3
5
  Arki is an AI agent programming tool.
@@ -43,6 +45,7 @@ arki [options]
43
45
  Options:
44
46
  -p <path> Specify working directory
45
47
  --debug, -d Enable debug mode, show detailed logs
48
+ --reset Reset configuration to factory defaults
46
49
  --help, -h Show help information
47
50
  ```
48
51
 
@@ -81,39 +84,13 @@ Ways to enable:
81
84
 
82
85
  Configuration file is located at `~/.config/arki/config.json`:
83
86
 
84
- ```json
85
- {
86
- "agents": {
87
- "main": {
88
- "model": "gpt-5.1",
89
- "flex": false,
90
- "reasoningEffort": "medium"
91
- },
92
- "coder": {
93
- "model": "gpt-5.2",
94
- "flex": false,
95
- "reasoningEffort": "high"
96
- }
97
- }
98
- }
99
- ```
100
-
101
- Each Agent configuration:
102
- - `model` - Model ID to use
103
- - `flex` - Use Flex API (low priority, low cost)
104
- - `reasoningEffort` - Reasoning effort, optional values: `low`, `medium`, `high` (for models that support thinking mode)
105
-
106
- Default configuration is automatically copied from the package on first run.
87
+ ### Reset to Factory Defaults
107
88
 
108
- ## Built-in Tools
109
-
110
- Arki includes the following built-in tools that the AI assistant can automatically call:
89
+ ```bash
90
+ arki --reset
91
+ ```
111
92
 
112
- - `read_file` - Read file content
113
- - `write_file` - Write to file
114
- - `list_directory` - List directory contents
115
- - `run_command` - Execute shell commands
116
- - `get_tool_info` - View detailed usage instructions for tools
93
+ This will delete the current configuration file. The default configuration will be used on next startup.
117
94
 
118
95
  ## Development
119
96
 
package/dist/index.d.ts CHANGED
@@ -39,31 +39,44 @@ declare class AIMsg extends Msg {
39
39
  readonly type = MsgType.AI;
40
40
  constructor(content: string);
41
41
  }
42
+ /**
43
+ * Single tool call
44
+ */
45
+ interface ToolCall {
46
+ name: string;
47
+ arguments: Record<string, unknown>;
48
+ }
42
49
  /**
43
50
  * Tool call message constructor
44
51
  */
45
52
  declare class ToolCallMsg extends Msg {
46
53
  readonly type = MsgType.ToolCall;
47
- readonly toolCalls: Array<{
48
- name: string;
49
- arguments: Record<string, unknown>;
50
- }>;
51
- constructor(content: string, toolCalls: Array<{
52
- name: string;
53
- arguments: Record<string, unknown>;
54
- }>);
54
+ readonly toolCalls: ToolCall[];
55
+ constructor(content: string, toolCalls: ToolCall[]);
56
+ }
57
+ /**
58
+ * Single tool result
59
+ */
60
+ interface ToolResult {
61
+ toolName: string;
62
+ result: string;
63
+ isError?: boolean;
55
64
  }
56
65
  /**
57
- * Tool result message constructor
66
+ * Tool result message constructor (contains multiple results)
58
67
  */
59
68
  declare class ToolResultMsg extends Msg {
60
69
  readonly type = MsgType.ToolResult;
61
- readonly toolName: string;
62
- readonly result: string;
63
- readonly isError?: boolean;
64
- constructor(toolName: string, result: string, isError?: boolean);
70
+ readonly toolResults: ToolResult[];
71
+ constructor(toolResults: ToolResult[]);
72
+ /** Helper: create from single result */
73
+ static single(toolName: string, result: string, isError?: boolean): ToolResultMsg;
65
74
  }
66
75
 
76
+ /**
77
+ * Symbol indicating tool has detailed manual (needs to call read_tool_manual before use)
78
+ */
79
+ declare const HAS_MANUAL = "\uD83D\uDCD8";
67
80
  /**
68
81
  * Tool class
69
82
  */
@@ -88,6 +101,7 @@ declare class Tool {
88
101
  * Parse manual.md content
89
102
  * First line format: "tool_name: description", extract description
90
103
  * Remaining content is the manual
104
+ * If manual has content, prepend HAS_MANUAL symbol to description
91
105
  */
92
106
  static parseManual(content: string): {
93
107
  description: string;
@@ -96,7 +110,7 @@ declare class Tool {
96
110
  /**
97
111
  * Execute tool (with error handling and logging)
98
112
  */
99
- run(args: Record<string, unknown>): Promise<ToolResultMsg>;
113
+ run(args: Record<string, unknown>): Promise<ToolResult>;
100
114
  }
101
115
 
102
116
  /**
@@ -353,4 +367,4 @@ interface Model {
353
367
  readonly capabilities: ModelCapabilities;
354
368
  }
355
369
 
356
- export { AIMsg, Adapter, type AdapterResponse, Agent, type AgentResponse, type ColorName, MAX_COMPLETION_TOKENS, MODELS, type Model, type ModelCapabilities, type ModelProvider, Msg, MsgType, OpenAIAdapter, type ReasoningEffort$1 as ReasoningEffort, SystemMsg, TEMPERATURE, TOOLS, Tool, ToolCallMsg, ToolResultMsg, UserMsg, adapter, colors, config, debug, error, info, init, isDebugMode, log, setDebugMode, setWorkingDir, success, warn, workingDir };
370
+ export { AIMsg, Adapter, type AdapterResponse, Agent, type AgentResponse, type ColorName, HAS_MANUAL, MAX_COMPLETION_TOKENS, MODELS, type Model, type ModelCapabilities, type ModelProvider, Msg, MsgType, OpenAIAdapter, type ReasoningEffort$1 as ReasoningEffort, SystemMsg, TEMPERATURE, TOOLS, Tool, type ToolCall, ToolCallMsg, type ToolResult, ToolResultMsg, UserMsg, adapter, colors, config, debug, error, info, init, isDebugMode, log, setDebugMode, setWorkingDir, success, warn, workingDir };
package/dist/index.js CHANGED
@@ -166,16 +166,16 @@ var ToolCallMsg = class extends Msg {
166
166
  this.toolCalls = toolCalls;
167
167
  }
168
168
  };
169
- var ToolResultMsg = class extends Msg {
169
+ var ToolResultMsg = class _ToolResultMsg extends Msg {
170
170
  type = "tool_result" /* ToolResult */;
171
- toolName;
172
- result;
173
- isError;
174
- constructor(toolName, result, isError) {
171
+ toolResults;
172
+ constructor(toolResults) {
175
173
  super("");
176
- this.toolName = toolName;
177
- this.result = result;
178
- this.isError = isError;
174
+ this.toolResults = toolResults;
175
+ }
176
+ /** Helper: create from single result */
177
+ static single(toolName, result, isError) {
178
+ return new _ToolResultMsg([{ toolName, result, isError }]);
179
179
  }
180
180
  };
181
181
 
@@ -272,11 +272,13 @@ var OpenAIAdapter = class extends Adapter {
272
272
  });
273
273
  } else if (msg.type === "tool_result" /* ToolResult */) {
274
274
  const toolResultMsg = msg;
275
- result.push({
276
- role: "tool",
277
- tool_call_id: pendingIds.shift() || `call_${msg.timestamp}`,
278
- content: toolResultMsg.isError ? `Error: ${toolResultMsg.result}` : toolResultMsg.result
279
- });
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
+ });
281
+ }
280
282
  }
281
283
  }
282
284
  return result;
@@ -378,6 +380,7 @@ async function init(cwd) {
378
380
  }
379
381
 
380
382
  // src/tool/Tool.ts
383
+ var HAS_MANUAL = "\u{1F4D8}";
381
384
  var Tool = class _Tool {
382
385
  name;
383
386
  description;
@@ -398,6 +401,7 @@ var Tool = class _Tool {
398
401
  * Parse manual.md content
399
402
  * First line format: "tool_name: description", extract description
400
403
  * Remaining content is the manual
404
+ * If manual has content, prepend HAS_MANUAL symbol to description
401
405
  */
402
406
  static parseManual(content) {
403
407
  const lines = content.split("\n");
@@ -408,6 +412,9 @@ var Tool = class _Tool {
408
412
  description = firstLine.slice(colonIndex + 1).trim();
409
413
  }
410
414
  const manual = lines.slice(1).join("\n").trim();
415
+ if (manual) {
416
+ description = `${HAS_MANUAL}${description}`;
417
+ }
411
418
  return { description, manual };
412
419
  }
413
420
  /**
@@ -421,15 +428,15 @@ var Tool = class _Tool {
421
428
  const elapsed = Date.now() - startTime;
422
429
  if (typeof result === "string") {
423
430
  debug("Tool", `Tool execution successful: ${this.name} (elapsed: ${elapsed}ms, result length: ${result.length})`);
424
- return new ToolResultMsg(this.name, result);
431
+ return { toolName: this.name, result };
425
432
  }
426
433
  debug("Tool", `Tool execution completed: ${this.name} (elapsed: ${elapsed}ms, isError: ${result.isError || false})`);
427
- return new ToolResultMsg(this.name, result.content, result.isError);
434
+ return { toolName: this.name, result: result.content, isError: result.isError };
428
435
  } catch (error2) {
429
436
  const elapsed = Date.now() - startTime;
430
437
  const errorMsg = error2 instanceof Error ? error2.message : String(error2);
431
438
  debug("Tool", `Tool execution failed: ${this.name} (elapsed: ${elapsed}ms)`, errorMsg);
432
- return new ToolResultMsg(this.name, `Error: ${errorMsg}`, true);
439
+ return { toolName: this.name, result: `Error: ${errorMsg}`, isError: true };
433
440
  }
434
441
  }
435
442
  };
@@ -439,7 +446,7 @@ import * as fs2 from "fs/promises";
439
446
  import * as path2 from "path";
440
447
 
441
448
  // src/tool/read_file/manual.md
442
- var manual_default = "read_file: Read the content of a specified file\n\n## Parameters\n\n- `path` (string, required): File path\n";
449
+ var manual_default = "read_file: Read the content of a specified file\n";
443
450
 
444
451
  // src/tool/read_file/index.ts
445
452
  TOOLS["read_file"] = new Tool({
@@ -468,7 +475,7 @@ import * as fs3 from "fs/promises";
468
475
  import * as path3 from "path";
469
476
 
470
477
  // src/tool/write_file/manual.md
471
- var manual_default2 = "write_file: Write content to a specified file, create the file if it doesn't exist\n\n## Parameters\n\n- `path` (string, required): File path\n- `content` (string, required): Content to write\n";
478
+ var manual_default2 = "write_file: Write content to a specified file, create the file if it doesn't exist\n";
472
479
 
473
480
  // src/tool/write_file/index.ts
474
481
  TOOLS["write_file"] = new Tool({
@@ -501,7 +508,7 @@ import * as fs4 from "fs/promises";
501
508
  import * as path4 from "path";
502
509
 
503
510
  // src/tool/list_directory/manual.md
504
- var manual_default3 = "list_directory: List files and subdirectories in a specified directory\n\n## Parameters\n\n- `path` (string, optional): Directory path, defaults to current directory\n";
511
+ var manual_default3 = "list_directory: List files and subdirectories in a specified directory\n";
505
512
 
506
513
  // src/tool/list_directory/index.ts
507
514
  TOOLS["list_directory"] = new Tool({
@@ -566,12 +573,12 @@ ${stderr}`;
566
573
  }
567
574
  });
568
575
 
569
- // src/tool/get_tool_info/manual.md
570
- var manual_default5 = "get_tool_info: View detailed usage instructions for a specified tool\n\n## Parameters\n\n- `tool_name` (string, required): Tool name to view\n\n";
576
+ // src/tool/read_tool_manual/manual.md
577
+ var manual_default5 = "read_tool_manual: View detailed usage instructions for a specified tool\n";
571
578
 
572
- // src/tool/get_tool_info/index.ts
573
- TOOLS["get_tool_info"] = new Tool({
574
- name: "get_tool_info",
579
+ // src/tool/read_tool_manual/index.ts
580
+ TOOLS["read_tool_manual"] = new Tool({
581
+ name: "read_tool_manual",
575
582
  parameters: {
576
583
  tool_name: { type: "string", description: "Tool name to view" }
577
584
  },
@@ -686,11 +693,12 @@ var Agent = class {
686
693
  const toolCalls = toolCallMsg.toolCalls;
687
694
  debug("Agent", `Received tool call request`, toolCalls.map((tc) => tc.name));
688
695
  this.config.onToolCallMsg?.(toolCallMsg);
696
+ const toolResults = [];
689
697
  for (const tc of toolCalls) {
690
698
  this.config.onBeforeToolRun?.(tc.name, tc.arguments);
691
699
  debug("Agent", `Executing tool: ${tc.name}`, tc.arguments);
692
700
  const tool = TOOLS[tc.name];
693
- const result = tool ? await tool.run(tc.arguments) : new ToolResultMsg(tc.name, `Unknown tool: ${tc.name}`, true);
701
+ const result = tool ? await tool.run(tc.arguments) : { toolName: tc.name, result: `Unknown tool: ${tc.name}`, isError: true };
694
702
  debug("Agent", `Tool execution completed: ${tc.name}`, {
695
703
  isError: result.isError,
696
704
  contentLength: result.result.length
@@ -701,8 +709,9 @@ var Agent = class {
701
709
  result: result.result
702
710
  });
703
711
  this.config.onToolResult?.(tc.name, tc.arguments, result.result);
704
- this.messages.push(result);
712
+ toolResults.push(result);
705
713
  }
714
+ this.messages.push(new ToolResultMsg(toolResults));
706
715
  }
707
716
  }
708
717
  reset() {
@@ -711,7 +720,7 @@ var Agent = class {
711
720
  }
712
721
  };
713
722
 
714
- // src/agent/main/colors.ts
723
+ // src/agent/Arki/colors.ts
715
724
  var tagNames = Object.keys(colors).filter((k) => k !== "reset").join("|");
716
725
  var tagRegex = new RegExp(`<(\\/?)(${tagNames})>`, "gi");
717
726
  function convertColorTags(str) {
@@ -740,19 +749,17 @@ function createColorConverter() {
740
749
  };
741
750
  }
742
751
 
743
- // src/agent/main/system.md
744
- var system_default = "You are Arki, a professional AI programming assistant. You work in the codebase directory `{{working_dir}}`.\n\n## Available Tools\n\n{{tools}}\n\nTools can be called multiple times at once. Make good use of this to improve efficiency.\nIf you need to understand the detailed usage of a tool, use the `get_tool_info` tool to view it.\n\n## Working Principles\n\n1. **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.\n2. **Safety**: Consider potential risks before executing commands.\n3. **Conciseness**: Keep answers brief and concise, avoid repetition and redundancy. Keep each response within 200 words unless the user requests detailed explanation.\n4. **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**. **Do not** output Markdown. Use numbered lists for ordered lists, and \u2022 symbol for unordered lists.\nUse the following tags to format output:\n\n| Scenario | Format |\n|----------|--------|\n| Error/Danger | `<red>...</red>` |\n| Warning/Notice | `<yellow>...</yellow>` |\n| Success/Complete | `<green>...</green>` |\n| File path | `<cyan>...</cyan>` |\n| Code/Command | `<dim>...</dim>` |\n| Emphasis | `<bold>...</bold>` |\n\nTags can be combined, e.g., `<bold><red>Critical Error</red></bold>`\n\nPlease answer questions in the language the user is using, and flexibly use available tools to complete tasks.\n";
752
+ // 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";
745
754
 
746
- // src/agent/main/main.ts
755
+ // src/agent/Arki/Arki.ts
747
756
  function createMainAgent() {
748
757
  if (!adapter) {
749
758
  throw new Error("Adapter not initialized, please call init() first");
750
759
  }
751
- const toolDescriptions = Object.values(TOOLS).map((t) => `${t.name}: ${t.description}`).join("\n");
752
760
  const systemInstruction = Agent.renderTemplate(system_default, {
753
761
  working_dir: workingDir,
754
- current_time: (/* @__PURE__ */ new Date()).toLocaleString(),
755
- tools: toolDescriptions
762
+ has_manual: HAS_MANUAL
756
763
  });
757
764
  const convertColor = createColorConverter();
758
765
  const agent = new Agent({
@@ -764,15 +771,23 @@ function createMainAgent() {
764
771
  onBeforeToolRun: (name, args) => {
765
772
  const argsStr = JSON.stringify(args);
766
773
  const argsPreview = argsStr.length > 60 ? argsStr.substring(0, 60) + "..." : argsStr;
767
- process.stdout.write(`\x1B[33m\u{1F527} ${name}\x1B[0m \x1B[2m${argsPreview}\x1B[0m`);
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
+ }
768
779
  },
769
780
  onToolResult: (name, args, result) => {
770
781
  const argsStr = JSON.stringify(args);
771
782
  const argsPreview = argsStr.length > 60 ? argsStr.substring(0, 60) + "..." : argsStr;
772
783
  const resultPreview = result.length > 80 ? result.substring(0, 80) + "..." : result;
773
784
  const firstLine = resultPreview.split("\n")[0];
774
- process.stdout.write(`\r\x1B[2K\x1B[32m\u2714 ${name}\x1B[0m \x1B[2m${argsPreview}\x1B[0m
785
+ if (isDebugMode()) {
786
+ console.log(`\x1B[32m\u2714 ${name}\x1B[0m \x1B[2m${argsPreview}\x1B[0m`);
787
+ } else {
788
+ process.stdout.write(`\r\x1B[2K\x1B[32m\u2714 ${name}\x1B[0m \x1B[2m${argsPreview}\x1B[0m
775
789
  `);
790
+ }
776
791
  log("dim", ` ${firstLine}`);
777
792
  }
778
793
  });
@@ -782,7 +797,7 @@ function createMainAgent() {
782
797
  // package.json
783
798
  var package_default = {
784
799
  name: "arki",
785
- version: "0.0.3",
800
+ version: "0.0.4",
786
801
  description: "AI Agent Programming Assistant",
787
802
  type: "module",
788
803
  main: "dist/index.js",
@@ -978,6 +993,7 @@ export {
978
993
  AIMsg,
979
994
  Adapter,
980
995
  Agent,
996
+ HAS_MANUAL,
981
997
  MAX_COMPLETION_TOKENS,
982
998
  MODELS,
983
999
  Msg,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arki",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "AI Agent Programming Assistant",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",