arki 0.0.4 → 0.0.5

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.d.ts CHANGED
@@ -113,6 +113,28 @@ declare class Tool {
113
113
  run(args: Record<string, unknown>): Promise<ToolResult>;
114
114
  }
115
115
 
116
+ /**
117
+ * Procedure class - step-by-step guide for specific workflows
118
+ */
119
+ declare class Procedure {
120
+ readonly name: string;
121
+ readonly description: string;
122
+ readonly manual: string;
123
+ constructor(config: {
124
+ name: string;
125
+ procedureContent: string;
126
+ });
127
+ /**
128
+ * Parse procedure.md content
129
+ * First line format: "procedure_name: description", extract description
130
+ * Remaining content is the procedure steps
131
+ */
132
+ static parseManual(content: string): {
133
+ description: string;
134
+ manual: string;
135
+ };
136
+ }
137
+
116
138
  /**
117
139
  * Fixed parameters
118
140
  */
@@ -221,6 +243,8 @@ declare let workingDir: string;
221
243
  declare function setWorkingDir(dir: string): void;
222
244
  /** Global tool registry */
223
245
  declare const TOOLS: Record<string, Tool>;
246
+ /** Global procedure registry */
247
+ declare const PROCEDURES: Record<string, Procedure>;
224
248
  /** Global Adapter instance */
225
249
  declare let adapter: Adapter | null;
226
250
  /** Initialize global state */
@@ -228,29 +252,31 @@ declare function init(cwd?: string): Promise<void>;
228
252
 
229
253
  /**
230
254
  * Debug logging module
255
+ * All debug output is single-line for log-friendly format
231
256
  */
232
257
  /** Get debug mode status */
233
258
  declare function isDebugMode(): boolean;
234
259
  /** Set debug mode */
235
260
  declare function setDebugMode(enabled: boolean): void;
236
261
  /**
237
- * Debug log function
262
+ * Debug log function - single line output with timestamp
238
263
  * @param category Log category (e.g., 'API', 'Agent', 'Tool')
239
264
  * @param message Log message
240
- * @param data Optional additional data
265
+ * @param data Optional additional data (will be formatted to single line)
241
266
  */
242
267
  declare function debug(category: string, message: string, data?: unknown): void;
243
268
 
244
269
  /**
245
270
  * General logging module
271
+ * All log output is single-line with timestamp prefix
272
+ * Supports XML-style color tags: <red>text</red>, <bold>text</bold>, etc.
246
273
  */
247
-
248
274
  /**
249
- * Colored log output
250
- * @param color Color name
251
- * @param args Content to output
275
+ * Log output with timestamp and XML color tag support
276
+ * @param message Message string with optional XML color tags
277
+ * @example log('<yellow>[TOOL]</yellow> read_file <dim>{"path":"test.txt"}</dim>')
252
278
  */
253
- declare function log(color: ColorName, ...args: unknown[]): void;
279
+ declare function log(message: string): void;
254
280
  /**
255
281
  * Info log
256
282
  */
@@ -271,6 +297,7 @@ declare function error(message: string): void;
271
297
  /**
272
298
  * Logging module
273
299
  * Provides debug mode and logging functionality
300
+ * Supports XML-style color tags: <red>text</red>, <bold>text</bold>, etc.
274
301
  */
275
302
  /**
276
303
  * Terminal colors and style definitions
@@ -293,6 +320,16 @@ declare const colors: {
293
320
  };
294
321
  /** Color name type */
295
322
  type ColorName = keyof typeof colors;
323
+ /**
324
+ * Convert XML-style color tags to ANSI escape sequences
325
+ * Example: "<red>error</red>" -> "\x1b[31merror\x1b[0m"
326
+ */
327
+ declare function convertColorTags(str: string): string;
328
+ /**
329
+ * Create a buffered streaming color converter
330
+ * Used for streaming output where tags may span multiple chunks
331
+ */
332
+ declare function createColorConverter(): (chunk: string) => string;
296
333
 
297
334
  declare class OpenAIAdapter extends Adapter {
298
335
  private client;
@@ -367,4 +404,4 @@ interface Model {
367
404
  readonly capabilities: ModelCapabilities;
368
405
  }
369
406
 
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 };
407
+ 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, PROCEDURES, type ReasoningEffort$1 as ReasoningEffort, SystemMsg, TEMPERATURE, TOOLS, Tool, type ToolCall, ToolCallMsg, type ToolResult, ToolResultMsg, UserMsg, adapter, colors, config, convertColorTags, createColorConverter, debug, error, info, init, isDebugMode, log, setDebugMode, setWorkingDir, success, warn, workingDir };
package/dist/index.js CHANGED
@@ -179,6 +179,27 @@ var ToolResultMsg = class _ToolResultMsg extends Msg {
179
179
  }
180
180
  };
181
181
 
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
+
182
203
  // src/log/debug.ts
183
204
  var _debugMode = false;
184
205
  function isDebugMode() {
@@ -187,43 +208,20 @@ function isDebugMode() {
187
208
  function setDebugMode(enabled) {
188
209
  _debugMode = enabled;
189
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
+ }
190
217
  function debug(category, message, data) {
191
218
  if (!_debugMode) return;
192
- const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
193
- const prefix = `${colors.gray}[${timestamp}]${colors.reset} ${colors.magenta}[DEBUG:${category}]${colors.reset}`;
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
- }
206
- }
207
-
208
- // src/log/log.ts
209
- function log(color, ...args) {
210
- console.log(colors[color], ...args, colors.reset);
211
- }
212
- function info(message) {
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}`);
220
- }
221
- function error(message) {
222
- console.log(`${colors.red}\u2716${colors.reset} ${message}`);
219
+ const dataStr = data !== void 0 ? ` <dim>${formatData(data)}</dim>` : "";
220
+ log(`<magenta>[${category}]</magenta> <cyan>${message}</cyan>${dataStr}`);
223
221
  }
224
222
 
225
223
  // src/log/index.ts
226
- var colors = {
224
+ var colors2 = {
227
225
  reset: "\x1B[0m",
228
226
  bold: "\x1B[1m",
229
227
  dim: "\x1B[2m",
@@ -239,6 +237,33 @@ var colors = {
239
237
  cyan: "\x1B[36m",
240
238
  gray: "\x1B[90m"
241
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
+ }
242
267
 
243
268
  // src/adapter/openai.ts
244
269
  var OpenAIAdapter = class extends Adapter {
@@ -300,7 +325,6 @@ var OpenAIAdapter = class extends Adapter {
300
325
  async chat(messages, onChunk) {
301
326
  debug("API", `Requesting OpenAI (model: ${this.model}, messages: ${messages.length})`);
302
327
  const openaiMessages = this.toOpenAIMessages(messages);
303
- debug("API", "Sent prompt:", openaiMessages);
304
328
  const startTime = Date.now();
305
329
  const requestParams = {
306
330
  model: this.model,
@@ -360,6 +384,7 @@ function setWorkingDir(dir) {
360
384
  workingDir = dir;
361
385
  }
362
386
  var TOOLS = {};
387
+ var PROCEDURES = {};
363
388
  var adapter = null;
364
389
  function initAdapter() {
365
390
  if (adapter) {
@@ -421,21 +446,15 @@ var Tool = class _Tool {
421
446
  * Execute tool (with error handling and logging)
422
447
  */
423
448
  async run(args) {
424
- debug("Tool", `Starting tool execution: ${this.name}`, args);
425
- const startTime = Date.now();
426
449
  try {
427
450
  const result = await this._execute(args);
428
- const elapsed = Date.now() - startTime;
429
451
  if (typeof result === "string") {
430
- debug("Tool", `Tool execution successful: ${this.name} (elapsed: ${elapsed}ms, result length: ${result.length})`);
431
452
  return { toolName: this.name, result };
432
453
  }
433
- debug("Tool", `Tool execution completed: ${this.name} (elapsed: ${elapsed}ms, isError: ${result.isError || false})`);
434
454
  return { toolName: this.name, result: result.content, isError: result.isError };
435
455
  } catch (error2) {
436
- const elapsed = Date.now() - startTime;
437
456
  const errorMsg = error2 instanceof Error ? error2.message : String(error2);
438
- debug("Tool", `Tool execution failed: ${this.name} (elapsed: ${elapsed}ms)`, errorMsg);
457
+ debug("Tool", `${this.name} error`, errorMsg);
439
458
  return { toolName: this.name, result: `Error: ${errorMsg}`, isError: true };
440
459
  }
441
460
  }
@@ -603,6 +622,76 @@ ${foundTool.manual}`;
603
622
  }
604
623
  });
605
624
 
625
+ // src/tool/read_procedure/manual.md
626
+ var manual_default6 = "read_procedure: View detailed steps for a specified procedure\n";
627
+
628
+ // src/tool/read_procedure/index.ts
629
+ TOOLS["read_procedure"] = new Tool({
630
+ name: "read_procedure",
631
+ parameters: {
632
+ procedure_name: { type: "string", description: "Procedure name to view" }
633
+ },
634
+ required: ["procedure_name"],
635
+ manualContent: manual_default6,
636
+ execute: async (args) => {
637
+ const procedureName = args.procedure_name;
638
+ const procedure = PROCEDURES[procedureName];
639
+ if (!procedure) {
640
+ const available = Object.keys(PROCEDURES).join(", ");
641
+ return {
642
+ content: `Procedure not found: ${procedureName}
643
+ Available: ${available}`,
644
+ isError: true
645
+ };
646
+ }
647
+ return `# ${procedure.name}
648
+
649
+ ${procedure.description}
650
+
651
+ ## Steps
652
+
653
+ ${procedure.manual}`;
654
+ }
655
+ });
656
+
657
+ // src/procedure/Procedure.ts
658
+ var Procedure = class _Procedure {
659
+ name;
660
+ description;
661
+ manual;
662
+ constructor(config2) {
663
+ this.name = config2.name;
664
+ const { description, manual } = _Procedure.parseManual(config2.procedureContent);
665
+ this.description = description;
666
+ this.manual = manual;
667
+ }
668
+ /**
669
+ * Parse procedure.md content
670
+ * First line format: "procedure_name: description", extract description
671
+ * Remaining content is the procedure steps
672
+ */
673
+ static parseManual(content) {
674
+ const lines = content.split("\n");
675
+ const firstLine = lines[0] || "";
676
+ let description = "";
677
+ const colonIndex = firstLine.indexOf(":");
678
+ if (colonIndex > 0) {
679
+ description = firstLine.slice(colonIndex + 1).trim();
680
+ }
681
+ const manual = lines.slice(1).join("\n").trim();
682
+ return { description, manual };
683
+ }
684
+ };
685
+
686
+ // src/procedure/understand_project/procedure.md
687
+ 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";
688
+
689
+ // src/procedure/understand_project/index.ts
690
+ PROCEDURES["understand_project"] = new Procedure({
691
+ name: "understand_project",
692
+ procedureContent: procedure_default
693
+ });
694
+
606
695
  // src/model/models.ts
607
696
  var MODELS = {
608
697
  "gpt-5.2": {
@@ -696,13 +785,8 @@ var Agent = class {
696
785
  const toolResults = [];
697
786
  for (const tc of toolCalls) {
698
787
  this.config.onBeforeToolRun?.(tc.name, tc.arguments);
699
- debug("Agent", `Executing tool: ${tc.name}`, tc.arguments);
700
788
  const tool = TOOLS[tc.name];
701
789
  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
790
  toolCallHistory.push({
707
791
  name: tc.name,
708
792
  arguments: tc.arguments,
@@ -720,46 +804,20 @@ var Agent = class {
720
804
  }
721
805
  };
722
806
 
723
- // src/agent/Arki/colors.ts
724
- var tagNames = Object.keys(colors).filter((k) => k !== "reset").join("|");
725
- var tagRegex = new RegExp(`<(\\/?)(${tagNames})>`, "gi");
726
- function convertColorTags(str) {
727
- return str.replace(tagRegex, (_, closing, tag) => {
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
- }
751
-
752
807
  // 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";
808
+ 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
809
 
755
810
  // src/agent/Arki/Arki.ts
811
+ var toolStartTimes = /* @__PURE__ */ new Map();
756
812
  function createMainAgent() {
757
813
  if (!adapter) {
758
814
  throw new Error("Adapter not initialized, please call init() first");
759
815
  }
816
+ const proceduresList = Object.values(PROCEDURES).map((p) => `- ${p.name}: ${p.description}`).join("\n");
760
817
  const systemInstruction = Agent.renderTemplate(system_default, {
761
818
  working_dir: workingDir,
762
- has_manual: HAS_MANUAL
819
+ has_manual: HAS_MANUAL,
820
+ procedures: proceduresList || "(none)"
763
821
  });
764
822
  const convertColor = createColorConverter();
765
823
  const agent = new Agent({
@@ -768,27 +826,31 @@ function createMainAgent() {
768
826
  onStream: (chunk) => {
769
827
  process.stdout.write(convertColor(chunk));
770
828
  },
771
- onBeforeToolRun: (name, args) => {
772
- const argsStr = JSON.stringify(args);
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
- }
829
+ onBeforeToolRun: (name) => {
830
+ toolStartTimes.set(name, Date.now());
779
831
  },
780
832
  onToolResult: (name, args, result) => {
833
+ const startTime = toolStartTimes.get(name) || Date.now();
834
+ const elapsed = Date.now() - startTime;
835
+ toolStartTimes.delete(name);
781
836
  const argsStr = JSON.stringify(args);
782
837
  const argsPreview = argsStr.length > 60 ? argsStr.substring(0, 60) + "..." : argsStr;
783
- const resultPreview = result.length > 80 ? result.substring(0, 80) + "..." : result;
784
- const firstLine = resultPreview.split("\n")[0];
838
+ let output = `<green>[TOOL]</green> ${name} <dim>${argsPreview} (${elapsed}ms)`;
785
839
  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
789
- `);
840
+ const lines = result.split("\n").filter((l) => l.trim());
841
+ let summary;
842
+ if (lines.length <= 3) {
843
+ summary = lines.join(", ");
844
+ if (summary.length > 60) summary = summary.substring(0, 60) + "...";
845
+ } else {
846
+ const preview = lines.slice(0, 3).join(", ");
847
+ summary = preview.length > 50 ? preview.substring(0, 50) + "..." : preview;
848
+ summary += ` (+${lines.length - 3} more)`;
849
+ }
850
+ output += ` -> ${summary}`;
790
851
  }
791
- log("dim", ` ${firstLine}`);
852
+ output += "</dim>";
853
+ log(output);
792
854
  }
793
855
  });
794
856
  return agent;
@@ -797,7 +859,7 @@ function createMainAgent() {
797
859
  // package.json
798
860
  var package_default = {
799
861
  name: "arki",
800
- version: "0.0.4",
862
+ version: "0.0.5",
801
863
  description: "AI Agent Programming Assistant",
802
864
  type: "module",
803
865
  main: "dist/index.js",
@@ -905,15 +967,15 @@ async function main() {
905
967
  const mainAgentConfig = config.getAgentConfig("main");
906
968
  const model = MODELS[mainAgentConfig.model];
907
969
  console.log();
908
- log("cyan", `Arki AI Agent v${package_default.version}`);
970
+ log(`<cyan>Arki AI Agent v${package_default.version}</cyan>`);
909
971
  console.log();
910
- log("dim", `Model: ${mainAgentConfig.model}${model ? ` (${model.name})` : ""}`);
911
- log("dim", `Working directory: ${workingDir}`);
972
+ log(`<dim>Model: ${mainAgentConfig.model}${model ? ` (${model.name})` : ""}</dim>`);
973
+ log(`<dim>Working directory: ${workingDir}</dim>`);
912
974
  if (isDebugMode()) {
913
- log("yellow", `\u{1F41B} Debug mode enabled`);
975
+ log(`<yellow>Debug mode enabled</yellow>`);
914
976
  }
915
977
  console.log();
916
- log("dim", `Loaded ${Object.keys(TOOLS).length} tools`);
978
+ log(`<dim>Loaded ${Object.keys(TOOLS).length} tools</dim>`);
917
979
  if (isDebugMode()) {
918
980
  debug("Init", "Loaded tools", Object.keys(TOOLS));
919
981
  debug("Init", "Agent config", mainAgentConfig);
@@ -924,38 +986,39 @@ async function main() {
924
986
  input: process.stdin,
925
987
  output: process.stdout
926
988
  });
927
- log("blue", "Enter your question and press Enter to send. Type /exit or /quit to exit.");
928
- log("blue", "Type /clear to clear conversation history.");
989
+ log(`<blue>Enter your question and press Enter to send. Type /exit or /quit to exit.</blue>`);
990
+ log(`<blue>Type /clear to clear conversation history.</blue>`);
929
991
  console.log();
992
+ const promptStr = convertColorTags("<green>> </green>");
930
993
  const prompt = () => {
931
- rl.question(`${colors.green}> ${colors.reset}`, async (input) => {
994
+ rl.question(promptStr, async (input) => {
932
995
  const trimmed = input.trim();
933
996
  if (trimmed === "/exit" || trimmed === "/quit") {
934
- log("cyan", "Goodbye!");
997
+ log(`<cyan>Goodbye!</cyan>`);
935
998
  rl.close();
936
999
  process.exit(0);
937
1000
  }
938
1001
  if (trimmed === "/clear") {
939
1002
  agent.reset();
940
- log("yellow", "Conversation history cleared");
1003
+ log(`<yellow>Conversation history cleared</yellow>`);
941
1004
  console.log();
942
1005
  prompt();
943
1006
  return;
944
1007
  }
945
1008
  if (trimmed === "/help") {
946
1009
  console.log();
947
- log("cyan", "Available commands:");
948
- log("dim", " /exit, /quit - Exit program");
949
- log("dim", " /clear - Clear conversation history");
950
- log("dim", " /debug - Toggle debug mode");
951
- log("dim", " /help - Show help");
1010
+ log(`<cyan>Available commands:</cyan>`);
1011
+ log(`<dim> /exit, /quit - Exit program</dim>`);
1012
+ log(`<dim> /clear - Clear conversation history</dim>`);
1013
+ log(`<dim> /debug - Toggle debug mode</dim>`);
1014
+ log(`<dim> /help - Show help</dim>`);
952
1015
  console.log();
953
1016
  prompt();
954
1017
  return;
955
1018
  }
956
1019
  if (trimmed === "/debug") {
957
1020
  setDebugMode(!isDebugMode());
958
- log("yellow", `Debug mode ${isDebugMode() ? "enabled \u{1F41B}" : "disabled"}`);
1021
+ log(`<yellow>Debug mode ${isDebugMode() ? "enabled" : "disabled"}</yellow>`);
959
1022
  console.log();
960
1023
  prompt();
961
1024
  return;
@@ -970,14 +1033,11 @@ async function main() {
970
1033
  console.log();
971
1034
  if (result.usage) {
972
1035
  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
- );
1036
+ log(`<dim>[Tokens: ${result.usage.totalTokens} (prompt: ${result.usage.promptTokens}, cached: ${result.usage.cachedTokens || 0}, limit: ${contextLimit})]</dim>`);
977
1037
  }
978
1038
  console.log();
979
1039
  } catch (error2) {
980
- log("red", `Error: ${error2 instanceof Error ? error2.message : String(error2)}`);
1040
+ log(`<red>Error: ${error2 instanceof Error ? error2.message : String(error2)}</red>`);
981
1041
  console.log();
982
1042
  }
983
1043
  prompt();
@@ -999,6 +1059,7 @@ export {
999
1059
  Msg,
1000
1060
  MsgType,
1001
1061
  OpenAIAdapter,
1062
+ PROCEDURES,
1002
1063
  SystemMsg,
1003
1064
  TEMPERATURE,
1004
1065
  TOOLS,
@@ -1007,8 +1068,10 @@ export {
1007
1068
  ToolResultMsg,
1008
1069
  UserMsg,
1009
1070
  adapter,
1010
- colors,
1071
+ colors2 as colors,
1011
1072
  config,
1073
+ convertColorTags,
1074
+ createColorConverter,
1012
1075
  debug,
1013
1076
  error,
1014
1077
  info,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arki",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "AI Agent Programming Assistant",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",