@xagent/x-cli 1.2.1 → 1.2.3

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
@@ -20,11 +20,11 @@ import { glob } from 'glob';
20
20
  import crypto2 from 'crypto';
21
21
  import { encoding_for_model, get_encoding } from 'tiktoken';
22
22
  import * as readline from 'readline';
23
- import React5, { useState, useRef, useEffect, useMemo, useCallback } from 'react';
23
+ import React4, { useState, useRef, useEffect, useMemo, useCallback } from 'react';
24
24
  import { render, Box, Text, useApp, useInput } from 'ink';
25
25
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
26
+ import chalk2 from 'chalk';
26
27
  import { program, Command } from 'commander';
27
- import chalk from 'chalk';
28
28
  import * as dotenv from 'dotenv';
29
29
 
30
30
  var __create = Object.create;
@@ -19701,6 +19701,10 @@ ${output?.plan?.summary || "Task completed"}`,
19701
19701
  instructions += "- Keep responses CONCISE and to the point. Avoid lengthy explanations.\n";
19702
19702
  instructions += "- Prioritize brevity over detail unless specifically requested.\n";
19703
19703
  instructions += "- Use minimal formatting and avoid verbose tool descriptions.\n";
19704
+ instructions += "- NEVER use separators like ### or --- between tool results and your response.\n";
19705
+ instructions += "- Provide analysis immediately after tools without visual dividers.\n";
19706
+ instructions += "- You may use **bold** and _italic_ for emphasis when helpful.\n";
19707
+ instructions += "- Match Claude Code style: tool outputs followed by clean, well-formatted analysis.\n";
19704
19708
  break;
19705
19709
  case "normal":
19706
19710
  instructions += "- Provide balanced responses with appropriate detail.\n";
@@ -19726,6 +19730,11 @@ ${output?.plan?.summary || "Task completed"}`,
19726
19730
  instructions += "- Provide detailed context for all operations.\n";
19727
19731
  break;
19728
19732
  }
19733
+ instructions += "\n";
19734
+ instructions += "\n\u{1F4A1} VISUAL FORMATTING:\n";
19735
+ instructions += "- Use emojis for status: \u2705 success, \u274C error, \u26A0\uFE0F warning, \u{1F4A1} tips\n";
19736
+ instructions += "- Add checkmarks for completed features or working items\n";
19737
+ instructions += "- Use appropriate emojis to make responses more scannable\n";
19729
19738
  return instructions;
19730
19739
  }
19731
19740
  // Plan Mode integration methods
@@ -27083,7 +27092,7 @@ var init_package = __esm({
27083
27092
  package_default = {
27084
27093
  type: "module",
27085
27094
  name: "@xagent/one-shot",
27086
- version: "1.2.1",
27095
+ version: "1.2.3",
27087
27096
  description: "An open-source AI agent that brings advanced AI capabilities directly into your terminal with automatic documentation updates.",
27088
27097
  main: "dist/index.js",
27089
27098
  module: "dist/index.js",
@@ -27105,6 +27114,10 @@ var init_package = __esm({
27105
27114
  ],
27106
27115
  scripts: {
27107
27116
  local: "bun --watch src/index.ts",
27117
+ "test-agent": "bun run build && ./dist/index.js -p",
27118
+ "test-log": 'bun run build && ./dist/index.js -p "$1" 2>&1 | tee agent-test.log',
27119
+ "test-iterative": "./scripts/test-agent-iterative.sh",
27120
+ "test-self": "./scripts/agent-self-test.js",
27108
27121
  build: "tsup src/index.ts --format esm --dts",
27109
27122
  dev: "tsx watch src/index.ts",
27110
27123
  lint: "eslint src --ext .ts",
@@ -28815,12 +28828,12 @@ Auto-compact automatically enables compact mode when conversations exceed thresh
28815
28828
  content: `\u{1F50A} **Current Verbosity Level: ${verbosityLevel.toUpperCase()}**
28816
28829
 
28817
28830
  **Available levels:**
28818
- - \`quiet\` - Minimal output, suppress prefixes and extra formatting
28831
+ - \`quiet\` - \u{1F3AF} **Claude Code mode**: Ultra-brief tool output (\`\u23BF Read X lines (ctrl+r to expand)\`)
28819
28832
  - \`normal\` - Current default behavior with full details
28820
28833
  - \`verbose\` - Additional details and debug information
28821
28834
 
28822
28835
  **Usage:** \`/verbosity <level>\`
28823
- **Example:** \`/verbosity quiet\``,
28836
+ **Example:** \`/verbosity quiet\` (for Claude Code parity)`,
28824
28837
  timestamp: /* @__PURE__ */ new Date()
28825
28838
  };
28826
28839
  setChatHistory((prev) => [...prev, levelEntry]);
@@ -28835,7 +28848,7 @@ Auto-compact automatically enables compact mode when conversations exceed thresh
28835
28848
  type: "assistant",
28836
28849
  content: `\u2705 **Verbosity level set to: ${newLevel.toUpperCase()}**
28837
28850
 
28838
- Tool outputs will now show ${newLevel === "quiet" ? "minimal output" : newLevel === "normal" ? "full details" : "extra details and debug information"}.`,
28851
+ ${newLevel === "quiet" ? "\u{1F3AF} **Claude Code mode activated!** Tool outputs will now show ultra-brief format: `\u23BF Read X lines (ctrl+r to expand)`" : newLevel === "normal" ? "Tool outputs will now show full details." : "Tool outputs will now show extra details and debug information."}`,
28839
28852
  timestamp: /* @__PURE__ */ new Date()
28840
28853
  };
28841
28854
  setChatHistory((prev) => [...prev, confirmEntry]);
@@ -30472,18 +30485,179 @@ var init_user_message_entry = __esm({
30472
30485
  };
30473
30486
  }
30474
30487
  });
30488
+ function MarkdownRenderer({ content }) {
30489
+ try {
30490
+ return /* @__PURE__ */ jsx(InlineMarkdown, { content });
30491
+ } catch (error) {
30492
+ console.error("Markdown rendering error:", error);
30493
+ return /* @__PURE__ */ jsx(Text, { wrap: "wrap", dimColor: false, children: content });
30494
+ }
30495
+ }
30496
+ function InlineMarkdown({ content }) {
30497
+ const lines = content.split("\n");
30498
+ return /* @__PURE__ */ jsx(Text, { wrap: "wrap", dimColor: false, children: lines.map((line, lineIndex) => {
30499
+ const parts = parseInlineMarkdown(line);
30500
+ if (parts.length === 0) {
30501
+ return null;
30502
+ }
30503
+ return /* @__PURE__ */ jsxs(React4.Fragment, { children: [
30504
+ lineIndex > 0 && "\n",
30505
+ parts.map((part, partIndex) => {
30506
+ if (part.type === "header") {
30507
+ return /* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: part.text }, `${lineIndex}-${partIndex}`);
30508
+ }
30509
+ if (part.type === "bold") {
30510
+ return /* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: part.text }, `${lineIndex}-${partIndex}`);
30511
+ }
30512
+ if (part.type === "italic") {
30513
+ return /* @__PURE__ */ jsx(Text, { italic: true, color: "gray", children: part.text }, `${lineIndex}-${partIndex}`);
30514
+ }
30515
+ if (part.type === "code") {
30516
+ return /* @__PURE__ */ jsx(Text, { color: "cyan", children: part.text }, `${lineIndex}-${partIndex}`);
30517
+ }
30518
+ if (part.type === "emoji") {
30519
+ const emoji = part.text;
30520
+ if (emoji === "\u2705" || emoji === "\u2713") {
30521
+ return /* @__PURE__ */ jsx(Text, { color: "green", children: emoji }, `${lineIndex}-${partIndex}`);
30522
+ }
30523
+ if (emoji === "\u274C" || emoji === "\u2717") {
30524
+ return /* @__PURE__ */ jsx(Text, { color: "red", children: emoji }, `${lineIndex}-${partIndex}`);
30525
+ }
30526
+ if (emoji === "\u26A0\uFE0F" || emoji === "\u26A0") {
30527
+ return /* @__PURE__ */ jsx(Text, { color: "yellow", children: emoji }, `${lineIndex}-${partIndex}`);
30528
+ }
30529
+ if (emoji === "\u{1F4A1}" || emoji === "\u2139\uFE0F" || emoji === "\u{1F50D}") {
30530
+ return /* @__PURE__ */ jsx(Text, { color: "blue", children: emoji }, `${lineIndex}-${partIndex}`);
30531
+ }
30532
+ return /* @__PURE__ */ jsx(Text, { color: "white", children: emoji }, `${lineIndex}-${partIndex}`);
30533
+ }
30534
+ if (part.type === "metadata") {
30535
+ return /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: part.text }, `${lineIndex}-${partIndex}`);
30536
+ }
30537
+ if (part.type === "version") {
30538
+ return /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: part.text }, `${lineIndex}-${partIndex}`);
30539
+ }
30540
+ if (part.type === "section") {
30541
+ return /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: part.text }, `${lineIndex}-${partIndex}`);
30542
+ }
30543
+ return /* @__PURE__ */ jsx(Text, { color: "white", children: part.text }, `${lineIndex}-${partIndex}`);
30544
+ })
30545
+ ] }, lineIndex);
30546
+ }) });
30547
+ }
30548
+ function parseInlineMarkdown(content) {
30549
+ if (content.match(/^#+\s*$/) || content.trim() === "" || content.trim() === "\u23FA" || content.match(/^#+$/)) {
30550
+ return [];
30551
+ }
30552
+ const headerMatch = content.match(/^(#+)\s+(.*)$/);
30553
+ if (headerMatch) {
30554
+ const [, hashes, headerText] = headerMatch;
30555
+ return [{ type: "header", text: headerText.trim(), level: hashes.length }];
30556
+ }
30557
+ const parts = [];
30558
+ let current = "";
30559
+ let i = 0;
30560
+ while (i < content.length) {
30561
+ if (content[i] === "`" && i < content.length - 1) {
30562
+ if (current) {
30563
+ parts.push({ type: "text", text: current });
30564
+ current = "";
30565
+ }
30566
+ const closeIndex = content.indexOf("`", i + 1);
30567
+ if (closeIndex !== -1 && closeIndex > i + 1) {
30568
+ const codeText = content.substring(i + 1, closeIndex);
30569
+ parts.push({ type: "code", text: codeText });
30570
+ i = closeIndex + 1;
30571
+ continue;
30572
+ }
30573
+ }
30574
+ if (content.substr(i, 2) === "**") {
30575
+ if (current) {
30576
+ parts.push({ type: "text", text: current });
30577
+ current = "";
30578
+ }
30579
+ const closeIndex = content.indexOf("**", i + 2);
30580
+ if (closeIndex !== -1) {
30581
+ const boldText = content.substring(i + 2, closeIndex);
30582
+ parts.push({ type: "bold", text: boldText });
30583
+ i = closeIndex + 2;
30584
+ continue;
30585
+ }
30586
+ }
30587
+ if (content[i] === "_" && content[i + 1] !== "_") {
30588
+ if (current) {
30589
+ parts.push({ type: "text", text: current });
30590
+ current = "";
30591
+ }
30592
+ const closeIndex = content.indexOf("_", i + 1);
30593
+ if (closeIndex !== -1) {
30594
+ const italicText = content.substring(i + 1, closeIndex);
30595
+ parts.push({ type: "italic", text: italicText });
30596
+ i = closeIndex + 1;
30597
+ continue;
30598
+ }
30599
+ }
30600
+ const char = content[i];
30601
+ if (/[\u{1F600}-\u{1F64F}]|[\u{1F300}-\u{1F5FF}]|[\u{1F680}-\u{1F6FF}]|[\u{1F1E0}-\u{1F1FF}]|[\u{2600}-\u{26FF}]|[\u{2700}-\u{27BF}]/u.test(char)) {
30602
+ if (current) {
30603
+ parts.push({ type: "text", text: current });
30604
+ current = "";
30605
+ }
30606
+ parts.push({ type: "emoji", text: char });
30607
+ i++;
30608
+ continue;
30609
+ }
30610
+ current += content[i];
30611
+ i++;
30612
+ }
30613
+ if (current) {
30614
+ const codePattern = /(view_file|str_replace_editor|create_file|search|semantic_search|ast_parser|package\.json|README\.md|GROK\.md|install\.sh|docs-getter\.sh|dist\/|src\/|scripts\/|apps\/|node_modules|\.git|\.js|\.ts|\.json|\.sh|\.md|bun\s+install|npm\s+install|npm\s+start|bun\s+start|TypeScript|React|Ink|ESLint|Husky|tsup|Vercel|GitHub|API|CLI|MCP|tsconfig\.json|\.env|\.gitignore|\.npmrc|package-lock\.json|bun\.lock|docs-index\.md|\.github\/|\.husky\/|\/Users\/[^\s]+|Grok\s+API|xAI|x\.ai)/g;
30615
+ const metadataPattern = /(\([^)]*(?:v\d+\.\d+\.\d+|v\d+\.\d+|\d+k?[+]?\s*(?:files?|lines?|items?|packages?|deps?|subdirs?|MB|KB|GB)|\d+\.\d+[xX]|~\d+[A-Z]*|dependencies?|scripts?|guides?|overview|project\s+docs?|source\s+code|detailed\s+setup|changelog|debugging|session\s+files?|build\s+artifacts|latest\s+release|current\s+Directory|for\s+CLI|via\s+Ink|xAI)[^)]*\))/g;
30616
+ const enhancedParts = [];
30617
+ let processedText = current;
30618
+ let lastIndex = 0;
30619
+ let match;
30620
+ const combinedPattern = new RegExp(`(${codePattern.source})|(${metadataPattern.source})|\\b(Overview|Key Features|Tech Stack|Current State|Purpose & Value|Structure)\\b`, "g");
30621
+ while ((match = combinedPattern.exec(processedText)) !== null) {
30622
+ if (match.index > lastIndex) {
30623
+ enhancedParts.push({ type: "text", text: processedText.substring(lastIndex, match.index) });
30624
+ }
30625
+ if (match[1]) {
30626
+ enhancedParts.push({ type: "code", text: match[1] });
30627
+ } else if (match[2]) {
30628
+ enhancedParts.push({ type: "metadata", text: match[2] });
30629
+ } else if (match[3]) {
30630
+ enhancedParts.push({ type: "section", text: match[3] });
30631
+ }
30632
+ lastIndex = match.index + match[0].length;
30633
+ }
30634
+ if (lastIndex < processedText.length) {
30635
+ enhancedParts.push({ type: "text", text: processedText.substring(lastIndex) });
30636
+ }
30637
+ const finalParts = enhancedParts;
30638
+ if (finalParts.length === 0) {
30639
+ parts.push({ type: "text", text: current });
30640
+ } else {
30641
+ parts.push(...finalParts);
30642
+ }
30643
+ }
30644
+ return parts;
30645
+ }
30646
+ var init_markdown_renderer = __esm({
30647
+ "src/ui/utils/markdown-renderer.tsx"() {
30648
+ }
30649
+ });
30475
30650
  function AssistantMessageEntry({ entry, verbosityLevel: _verbosityLevel }) {
30476
30651
  const { content: processedContent, isTruncated } = handleLongContent(entry.content);
30652
+ const trimmedContent = processedContent.trim();
30653
+ const isEffectivelyEmpty = !trimmedContent || trimmedContent.match(/^#+\s*$/) || trimmedContent === "\u23FA";
30654
+ if (isEffectivelyEmpty && !entry.isStreaming) {
30655
+ return null;
30656
+ }
30477
30657
  return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsxs(Box, { flexDirection: "row", alignItems: "flex-start", children: [
30478
30658
  /* @__PURE__ */ jsx(Text, { color: inkColors.text, children: "\u23FA " }),
30479
30659
  /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: "100%", children: [
30480
- entry.toolCalls ? (
30481
- // If there are tool calls, just show plain text
30482
- /* @__PURE__ */ jsx(Text, { color: inkColors.text, wrap: "wrap", dimColor: false, children: processedContent.trim() })
30483
- ) : (
30484
- // Use bright white text like Claude Code - explicit hex color to override any defaults
30485
- /* @__PURE__ */ jsx(Text, { color: inkColors.text, wrap: "wrap", dimColor: false, children: processedContent.trim() })
30486
- ),
30660
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: processedContent.trim() }),
30487
30661
  entry.isStreaming && /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u2588" }),
30488
30662
  isTruncated && /* @__PURE__ */ jsx(Text, { color: "yellow", italic: true, children: "[Response truncated for performance - full content in session log]" })
30489
30663
  ] })
@@ -30492,6 +30666,7 @@ function AssistantMessageEntry({ entry, verbosityLevel: _verbosityLevel }) {
30492
30666
  var handleLongContent;
30493
30667
  var init_assistant_message_entry = __esm({
30494
30668
  "src/ui/components/chat-entries/assistant-message-entry.tsx"() {
30669
+ init_markdown_renderer();
30495
30670
  init_colors();
30496
30671
  handleLongContent = (content, maxLength = 5e3) => {
30497
30672
  if (content.length <= maxLength) {
@@ -30743,6 +30918,221 @@ var init_file_content_renderer = __esm({
30743
30918
  "src/ui/components/content-renderers/file-content-renderer.tsx"() {
30744
30919
  }
30745
30920
  });
30921
+
30922
+ // src/services/tool-brevity-service.ts
30923
+ var ToolBrevityService;
30924
+ var init_tool_brevity_service = __esm({
30925
+ "src/services/tool-brevity-service.ts"() {
30926
+ ToolBrevityService = class {
30927
+ /**
30928
+ * Format tool result based on brevity mode
30929
+ */
30930
+ static formatToolResult(toolName, result, mode = "normal") {
30931
+ const normalizedToolName = this.normalizeToolName(toolName);
30932
+ const metadata = this.extractMetadata(normalizedToolName, result);
30933
+ const summary = this.generateSummary(normalizedToolName, result, metadata);
30934
+ return {
30935
+ toolName: normalizedToolName,
30936
+ summary,
30937
+ expansionHint: result.length > 0 ? "(ctrl+r to expand)" : "",
30938
+ hasContent: result.length > 0,
30939
+ originalContent: result,
30940
+ metadata
30941
+ };
30942
+ }
30943
+ /**
30944
+ * Normalize tool names to handle MCP and special cases
30945
+ */
30946
+ static normalizeToolName(toolName) {
30947
+ if (toolName.startsWith("mcp__")) {
30948
+ const parts = toolName.split("__");
30949
+ if (parts.length >= 3) {
30950
+ return parts[2];
30951
+ }
30952
+ }
30953
+ const toolMappings = {
30954
+ "str_replace_editor": "Edit",
30955
+ "bash": "Bash",
30956
+ "file_editor": "Edit",
30957
+ "grep": "Grep",
30958
+ "file_search": "Search",
30959
+ "list_files": "List",
30960
+ "read_file": "Read",
30961
+ "write_file": "Write"
30962
+ };
30963
+ return toolMappings[toolName] || this.capitalizeFirst(toolName);
30964
+ }
30965
+ /**
30966
+ * Extract metadata from tool result content
30967
+ */
30968
+ static extractMetadata(toolName, content) {
30969
+ const metadata = {};
30970
+ switch (toolName.toLowerCase()) {
30971
+ case "read":
30972
+ case "edit":
30973
+ case "write":
30974
+ metadata.lineCount = this.countLines(content);
30975
+ break;
30976
+ case "grep":
30977
+ case "search":
30978
+ const { matchCount, fileCount } = this.parseGrepResults(content);
30979
+ metadata.matchCount = matchCount;
30980
+ metadata.fileCount = fileCount;
30981
+ break;
30982
+ case "list":
30983
+ metadata.fileCount = this.countFileItems(content);
30984
+ break;
30985
+ case "bash":
30986
+ metadata.status = this.determineBashStatus(content);
30987
+ break;
30988
+ default:
30989
+ metadata.lineCount = this.countLines(content);
30990
+ }
30991
+ return metadata;
30992
+ }
30993
+ /**
30994
+ * Generate tool-specific summary text
30995
+ */
30996
+ static generateSummary(toolName, content, metadata) {
30997
+ const tool = toolName.toLowerCase();
30998
+ if (!content || content.trim().length === 0) {
30999
+ return `${this.capitalizeFirst(tool)} (no output)`;
31000
+ }
31001
+ switch (tool) {
31002
+ case "read":
31003
+ return `Read ${metadata.lineCount || 0} lines`;
31004
+ case "edit":
31005
+ return `Updated ${this.getFileName(content)} with ${metadata.lineCount || 0} lines`;
31006
+ case "write":
31007
+ return `Created file (${metadata.lineCount || 0} lines)`;
31008
+ case "grep":
31009
+ case "search":
31010
+ if (metadata.matchCount === 0) {
31011
+ return "No matches found";
31012
+ }
31013
+ return `${metadata.matchCount} matches across ${metadata.fileCount || 1} files`;
31014
+ case "list":
31015
+ return `Found ${metadata.fileCount || 0} items`;
31016
+ case "bash":
31017
+ if (metadata.status === "error") {
31018
+ return "Command failed";
31019
+ }
31020
+ return "Command completed successfully";
31021
+ case "glob":
31022
+ return `Found ${this.countFileItems(content)} files`;
31023
+ case "webfetch":
31024
+ return `Fetched content (${metadata.lineCount || 0} lines)`;
31025
+ case "websearch":
31026
+ return `Search completed (${this.countSearchResults(content)} results)`;
31027
+ default:
31028
+ const lines = metadata.lineCount || 0;
31029
+ return lines > 0 ? `${this.capitalizeFirst(tool)} (${lines} lines)` : this.capitalizeFirst(tool);
31030
+ }
31031
+ }
31032
+ /**
31033
+ * Count lines in content
31034
+ */
31035
+ static countLines(content) {
31036
+ if (!content) return 0;
31037
+ return content.split("\n").length;
31038
+ }
31039
+ /**
31040
+ * Parse grep/search results for match and file counts
31041
+ */
31042
+ static parseGrepResults(content) {
31043
+ if (!content) return { matchCount: 0, fileCount: 0 };
31044
+ const lines = content.split("\n").filter((line) => line.trim().length > 0);
31045
+ const files = /* @__PURE__ */ new Set();
31046
+ let matches = 0;
31047
+ for (const line of lines) {
31048
+ const fileMatch = line.match(/^([^:]+):/);
31049
+ if (fileMatch) {
31050
+ files.add(fileMatch[1]);
31051
+ matches++;
31052
+ } else if (line.includes(":")) {
31053
+ matches++;
31054
+ }
31055
+ }
31056
+ return {
31057
+ matchCount: matches || lines.length,
31058
+ fileCount: files.size || (matches > 0 ? 1 : 0)
31059
+ };
31060
+ }
31061
+ /**
31062
+ * Count file items in directory listing
31063
+ */
31064
+ static countFileItems(content) {
31065
+ if (!content) return 0;
31066
+ const lines = content.split("\n").filter((line) => line.trim().length > 0).filter((line) => !line.startsWith("total ")).filter((line) => !line.match(/^d.*\s+\.\s*$/)).filter((line) => !line.match(/^d.*\s+\.\.\s*$/));
31067
+ return lines.length;
31068
+ }
31069
+ /**
31070
+ * Determine bash command success/failure status
31071
+ */
31072
+ static determineBashStatus(content) {
31073
+ if (!content) return "success";
31074
+ const errorIndicators = [
31075
+ "error:",
31076
+ "Error:",
31077
+ "ERROR:",
31078
+ "failed",
31079
+ "Failed",
31080
+ "FAILED",
31081
+ "permission denied",
31082
+ "command not found",
31083
+ "no such file",
31084
+ "cannot"
31085
+ ];
31086
+ const contentLower = content.toLowerCase();
31087
+ return errorIndicators.some((indicator) => contentLower.includes(indicator.toLowerCase())) ? "error" : "success";
31088
+ }
31089
+ /**
31090
+ * Extract filename from edit/write operation content
31091
+ */
31092
+ static getFileName(content) {
31093
+ const fileMatch = content.match(/(?:updated|edited|created)\s+([^\s]+)/i);
31094
+ if (fileMatch) return fileMatch[1];
31095
+ const pathMatch = content.match(/([^/]+)$/);
31096
+ return pathMatch ? pathMatch[1] : "file";
31097
+ }
31098
+ /**
31099
+ * Count search results in web search content
31100
+ */
31101
+ static countSearchResults(content) {
31102
+ const resultMatches = content.match(/result\s+\d+/gi);
31103
+ return resultMatches ? resultMatches.length : 1;
31104
+ }
31105
+ /**
31106
+ * Capitalize first letter of string
31107
+ */
31108
+ static capitalizeFirst(str) {
31109
+ return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
31110
+ }
31111
+ /**
31112
+ * Check if content should use compact display
31113
+ */
31114
+ static shouldUseCompactDisplay(mode, contentLength) {
31115
+ if (mode === "brief") return true;
31116
+ if (mode === "verbose") return false;
31117
+ const lineCount = contentLength > 0 ? contentLength.toString().split("\n").length : 0;
31118
+ return lineCount > 5;
31119
+ }
31120
+ /**
31121
+ * Format expansion hint with content preview
31122
+ */
31123
+ static formatExpansionHint(hasContent, metadata) {
31124
+ if (!hasContent) return "";
31125
+ if (metadata.lineCount && metadata.lineCount > 10) {
31126
+ return `(${metadata.lineCount} lines, ctrl+r to expand)`;
31127
+ }
31128
+ if (metadata.matchCount && metadata.matchCount > 5) {
31129
+ return `(${metadata.matchCount} matches, ctrl+r to expand)`;
31130
+ }
31131
+ return "(ctrl+r to expand)";
31132
+ }
31133
+ };
31134
+ }
31135
+ });
30746
31136
  function ToolCallEntry({ entry, verbosityLevel, explainLevel }) {
30747
31137
  const [isExpanded, setIsExpanded] = useState(false);
30748
31138
  const getExplanation = (toolName2, filePath2, _isExecuting) => {
@@ -30852,8 +31242,15 @@ function ToolCallEntry({ entry, verbosityLevel, explainLevel }) {
30852
31242
  const shouldShowFileContent = (entry.toolCall?.function?.name === "view_file" || entry.toolCall?.function?.name === "create_file") && entry.toolResult?.success && !shouldShowDiff;
30853
31243
  const shouldShowToolContent = verbosityLevel !== "quiet";
30854
31244
  const shouldShowFullContent = verbosityLevel === "normal" || verbosityLevel === "verbose";
31245
+ const brevityMode = verbosityLevel === "quiet" ? "brief" : verbosityLevel === "verbose" ? "verbose" : "normal";
31246
+ const brevitySummary = ToolBrevityService.formatToolResult(
31247
+ toolName,
31248
+ entry.content || "",
31249
+ brevityMode
31250
+ );
30855
31251
  const explanation = getExplanation(toolName, filePath);
30856
31252
  const { preview, hasMore, totalLines } = truncateToClaudeStyle(entry.content || "");
31253
+ const useClaudeCodeFormat = verbosityLevel === "quiet" && brevitySummary.hasContent;
30857
31254
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
30858
31255
  /* @__PURE__ */ jsxs(Box, { children: [
30859
31256
  /* @__PURE__ */ jsx(Text, { color: "magenta", children: "\u23FA" }),
@@ -30862,11 +31259,19 @@ function ToolCallEntry({ entry, verbosityLevel, explainLevel }) {
30862
31259
  filePath ? `${actionName}(${filePath})` : actionName
30863
31260
  ] })
30864
31261
  ] }),
30865
- explanation && /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsxs(Text, { color: "blue", italic: true, children: [
31262
+ explanation && !useClaudeCodeFormat && /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsxs(Text, { color: "blue", italic: true, children: [
30866
31263
  "\u{1F4A1} ",
30867
31264
  explanation
30868
31265
  ] }) }),
30869
- shouldShowToolContent && /* @__PURE__ */ jsx(Box, { marginLeft: 2, flexDirection: "column", children: isExecuting ? /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u23BF Executing..." }) : shouldShowFileContent && shouldShowFullContent ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: !isExpanded ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
31266
+ useClaudeCodeFormat ? (
31267
+ // Claude Code style: ultra-brief format
31268
+ /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
31269
+ "\u23BF ",
31270
+ brevitySummary.summary,
31271
+ " ",
31272
+ brevitySummary.expansionHint
31273
+ ] }) })
31274
+ ) : shouldShowToolContent && /* @__PURE__ */ jsx(Box, { marginLeft: 2, flexDirection: "column", children: isExecuting ? /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u23BF Executing..." }) : shouldShowFileContent && shouldShowFullContent ? /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: !isExpanded ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
30870
31275
  /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
30871
31276
  "\u23BF ",
30872
31277
  preview
@@ -30902,7 +31307,7 @@ function ToolCallEntry({ entry, verbosityLevel, explainLevel }) {
30902
31307
  "\u23BF ",
30903
31308
  formatToolContent(entry.content, toolName)
30904
31309
  ] }) }),
30905
- shouldShowDiff && !isExecuting && shouldShowFullContent && /* @__PURE__ */ jsx(Box, { marginLeft: 4, flexDirection: "column", children: /* @__PURE__ */ jsx(
31310
+ shouldShowDiff && !isExecuting && shouldShowFullContent && !useClaudeCodeFormat && /* @__PURE__ */ jsx(Box, { marginLeft: 4, flexDirection: "column", children: /* @__PURE__ */ jsx(
30906
31311
  DiffRenderer,
30907
31312
  {
30908
31313
  diffContent: entry.content,
@@ -30917,6 +31322,7 @@ var init_tool_call_entry = __esm({
30917
31322
  "src/ui/components/chat-entries/tool-call-entry.tsx"() {
30918
31323
  init_diff_renderer();
30919
31324
  init_file_content_renderer();
31325
+ init_tool_brevity_service();
30920
31326
  truncateContent2 = (content, maxLength = 100) => {
30921
31327
  if (process.env.COMPACT !== "1") return content;
30922
31328
  return content.length > maxLength ? content.substring(0, maxLength) + "..." : content;
@@ -30967,7 +31373,7 @@ var MemoizedChatEntry;
30967
31373
  var init_chat_history = __esm({
30968
31374
  "src/ui/components/chat-history.tsx"() {
30969
31375
  init_chat_entry_router();
30970
- MemoizedChatEntry = React5.memo(
31376
+ MemoizedChatEntry = React4.memo(
30971
31377
  ({ entry, verbosityLevel, explainLevel }) => {
30972
31378
  return /* @__PURE__ */ jsx(ChatEntryRouter, { entry, verbosityLevel, explainLevel });
30973
31379
  }
@@ -32181,6 +32587,32 @@ var init_chat_interface = __esm({
32181
32587
  }
32182
32588
  });
32183
32589
 
32590
+ // src/utils/console-markdown.ts
32591
+ var console_markdown_exports = {};
32592
+ __export(console_markdown_exports, {
32593
+ renderMarkdownToConsole: () => renderMarkdownToConsole
32594
+ });
32595
+ function renderMarkdownToConsole(content) {
32596
+ let result = content;
32597
+ result = result.replace(/^#+\s+(.*)$/gm, (_, text) => chalk2.bold.white(text));
32598
+ result = result.replace(/\*\*(.*?)\*\*/g, (_, text) => chalk2.bold.white(text));
32599
+ result = result.replace(/_(.*?)_/g, (_, text) => chalk2.italic.gray(text));
32600
+ result = result.replace(/`([^`]+)`/g, (_, text) => chalk2.cyan(text));
32601
+ result = result.replace(/(view_file|str_replace_editor|create_file|search|semantic_search|ast_parser|package\.json|README\.md|GROK\.md|install\.sh|docs-getter\.sh|dist\/|src\/|scripts\/|apps\/|node_modules|\.git|\.js|\.ts|\.json|\.sh|\.md|bun\s+install|npm\s+install|npm\s+start|bun\s+start|TypeScript|React|Ink|ESLint|Husky|tsup|Vercel|GitHub|API|CLI|MCP|tsconfig\.json|\.env|\.gitignore|\.npmrc|package-lock\.json|bun\.lock|docs-index\.md|\.github\/|\.husky\/|\/Users\/[^\s]+|Grok\s+API|xAI|x\.ai)/g, (match) => chalk2.cyan(match));
32602
+ result = result.replace(/\b(Overview|Key Features|Tech Stack|Current State|Purpose & Value|Structure)\b/g, (match) => chalk2.bold.cyan(match));
32603
+ result = result.replace(/(\([^)]*(?:v\d+\.\d+\.\d+|v\d+\.\d+|\d+k?[+]?\s*(?:files?|lines?|items?|packages?|deps?|subdirs?|MB|KB|GB)|\d+\.\d+[xX]|~\d+[A-Z]*|dependencies?|scripts?|guides?|overview|project\s+docs?|source\s+code|detailed\s+setup|changelog|debugging|session\s+files?|build\s+artifacts|latest\s+release|current\s+Directory|for\s+CLI|via\s+Ink|xAI)[^)]*\))/g, (match) => chalk2.gray.dim(match));
32604
+ result = result.replace(/(\b(?:v\d+\.\d+\.\d+|v\d+\.\d+|~\d+[A-Z]+|\d+k?\+?\s*(?:files?|lines?|packages?|deps?|items?)|\d+\.\d+[xX])\b)/g, (match) => chalk2.gray.dim(match));
32605
+ result = result.replace(/(✅|✓)/g, (match) => chalk2.green(match));
32606
+ result = result.replace(/(❌|✗)/g, (match) => chalk2.red(match));
32607
+ result = result.replace(/(⚠️|⚠)/g, (match) => chalk2.yellow(match));
32608
+ result = result.replace(/(ℹ️|💡|🔍)/g, (match) => chalk2.blue(match));
32609
+ return result;
32610
+ }
32611
+ var init_console_markdown = __esm({
32612
+ "src/utils/console-markdown.ts"() {
32613
+ }
32614
+ });
32615
+
32184
32616
  // src/commands/mcp.ts
32185
32617
  var mcp_exports = {};
32186
32618
  __export(mcp_exports, {
@@ -32194,27 +32626,27 @@ function createMCPCommand() {
32194
32626
  if (PREDEFINED_SERVERS[name]) {
32195
32627
  const config3 = PREDEFINED_SERVERS[name];
32196
32628
  addMCPServer(config3);
32197
- console.log(chalk.green(`\u2713 Added predefined MCP server: ${name}`));
32629
+ console.log(chalk2.green(`\u2713 Added predefined MCP server: ${name}`));
32198
32630
  const manager2 = getMCPManager();
32199
32631
  await manager2.addServer(config3);
32200
- console.log(chalk.green(`\u2713 Connected to MCP server: ${name}`));
32632
+ console.log(chalk2.green(`\u2713 Connected to MCP server: ${name}`));
32201
32633
  const tools2 = manager2.getTools().filter((t) => t.serverName === name);
32202
- console.log(chalk.blue(` Available tools: ${tools2.length}`));
32634
+ console.log(chalk2.blue(` Available tools: ${tools2.length}`));
32203
32635
  return;
32204
32636
  }
32205
32637
  const transportType = options.transport.toLowerCase();
32206
32638
  if (transportType === "stdio") {
32207
32639
  if (!options.command) {
32208
- console.error(chalk.red("Error: --command is required for stdio transport"));
32640
+ console.error(chalk2.red("Error: --command is required for stdio transport"));
32209
32641
  process.exit(1);
32210
32642
  }
32211
32643
  } else if (transportType === "http" || transportType === "sse" || transportType === "streamable_http") {
32212
32644
  if (!options.url) {
32213
- console.error(chalk.red(`Error: --url is required for ${transportType} transport`));
32645
+ console.error(chalk2.red(`Error: --url is required for ${transportType} transport`));
32214
32646
  process.exit(1);
32215
32647
  }
32216
32648
  } else {
32217
- console.error(chalk.red("Error: Transport type must be stdio, http, sse, or streamable_http"));
32649
+ console.error(chalk2.red("Error: Transport type must be stdio, http, sse, or streamable_http"));
32218
32650
  process.exit(1);
32219
32651
  }
32220
32652
  const env = {};
@@ -32243,14 +32675,14 @@ function createMCPCommand() {
32243
32675
  }
32244
32676
  };
32245
32677
  addMCPServer(config2);
32246
- console.log(chalk.green(`\u2713 Added MCP server: ${name}`));
32678
+ console.log(chalk2.green(`\u2713 Added MCP server: ${name}`));
32247
32679
  const manager = getMCPManager();
32248
32680
  await manager.addServer(config2);
32249
- console.log(chalk.green(`\u2713 Connected to MCP server: ${name}`));
32681
+ console.log(chalk2.green(`\u2713 Connected to MCP server: ${name}`));
32250
32682
  const tools = manager.getTools().filter((t) => t.serverName === name);
32251
- console.log(chalk.blue(` Available tools: ${tools.length}`));
32683
+ console.log(chalk2.blue(` Available tools: ${tools.length}`));
32252
32684
  } catch (error) {
32253
- console.error(chalk.red(`Error adding MCP server: ${error.message}`));
32685
+ console.error(chalk2.red(`Error adding MCP server: ${error.message}`));
32254
32686
  process.exit(1);
32255
32687
  }
32256
32688
  });
@@ -32260,7 +32692,7 @@ function createMCPCommand() {
32260
32692
  try {
32261
32693
  config2 = JSON.parse(jsonConfig);
32262
32694
  } catch {
32263
- console.error(chalk.red("Error: Invalid JSON configuration"));
32695
+ console.error(chalk2.red("Error: Invalid JSON configuration"));
32264
32696
  process.exit(1);
32265
32697
  }
32266
32698
  const serverConfig = {
@@ -32283,14 +32715,14 @@ function createMCPCommand() {
32283
32715
  }
32284
32716
  }
32285
32717
  addMCPServer(serverConfig);
32286
- console.log(chalk.green(`\u2713 Added MCP server: ${name}`));
32718
+ console.log(chalk2.green(`\u2713 Added MCP server: ${name}`));
32287
32719
  const manager = getMCPManager();
32288
32720
  await manager.addServer(serverConfig);
32289
- console.log(chalk.green(`\u2713 Connected to MCP server: ${name}`));
32721
+ console.log(chalk2.green(`\u2713 Connected to MCP server: ${name}`));
32290
32722
  const tools = manager.getTools().filter((t) => t.serverName === name);
32291
- console.log(chalk.blue(` Available tools: ${tools.length}`));
32723
+ console.log(chalk2.blue(` Available tools: ${tools.length}`));
32292
32724
  } catch (error) {
32293
- console.error(chalk.red(`Error adding MCP server: ${error.message}`));
32725
+ console.error(chalk2.red(`Error adding MCP server: ${error.message}`));
32294
32726
  process.exit(1);
32295
32727
  }
32296
32728
  });
@@ -32299,9 +32731,9 @@ function createMCPCommand() {
32299
32731
  const manager = getMCPManager();
32300
32732
  await manager.removeServer(name);
32301
32733
  removeMCPServer(name);
32302
- console.log(chalk.green(`\u2713 Removed MCP server: ${name}`));
32734
+ console.log(chalk2.green(`\u2713 Removed MCP server: ${name}`));
32303
32735
  } catch (error) {
32304
- console.error(chalk.red(`Error removing MCP server: ${error.message}`));
32736
+ console.error(chalk2.red(`Error removing MCP server: ${error.message}`));
32305
32737
  process.exit(1);
32306
32738
  }
32307
32739
  });
@@ -32309,15 +32741,15 @@ function createMCPCommand() {
32309
32741
  const config2 = loadMCPConfig();
32310
32742
  const manager = getMCPManager();
32311
32743
  if (config2.servers.length === 0) {
32312
- console.log(chalk.yellow("No MCP servers configured"));
32744
+ console.log(chalk2.yellow("No MCP servers configured"));
32313
32745
  return;
32314
32746
  }
32315
- console.log(chalk.bold("Configured MCP servers:"));
32747
+ console.log(chalk2.bold("Configured MCP servers:"));
32316
32748
  console.log();
32317
32749
  for (const server of config2.servers) {
32318
32750
  const isConnected = manager.getServers().includes(server.name);
32319
- const status = isConnected ? chalk.green("\u2713 Connected") : chalk.red("\u2717 Disconnected");
32320
- console.log(`${chalk.bold(server.name)}: ${status}`);
32751
+ const status = isConnected ? chalk2.green("\u2713 Connected") : chalk2.red("\u2717 Disconnected");
32752
+ console.log(`${chalk2.bold(server.name)}: ${status}`);
32321
32753
  if (server.transport) {
32322
32754
  console.log(` Transport: ${server.transport.type}`);
32323
32755
  if (server.transport.type === "stdio") {
@@ -32350,15 +32782,15 @@ function createMCPCommand() {
32350
32782
  const config2 = loadMCPConfig();
32351
32783
  const serverConfig = config2.servers.find((s) => s.name === name);
32352
32784
  if (!serverConfig) {
32353
- console.error(chalk.red(`Server ${name} not found`));
32785
+ console.error(chalk2.red(`Server ${name} not found`));
32354
32786
  process.exit(1);
32355
32787
  }
32356
- console.log(chalk.blue(`Testing connection to ${name}...`));
32788
+ console.log(chalk2.blue(`Testing connection to ${name}...`));
32357
32789
  const manager = getMCPManager();
32358
32790
  await manager.addServer(serverConfig);
32359
32791
  const tools = manager.getTools().filter((t) => t.serverName === name);
32360
- console.log(chalk.green(`\u2713 Successfully connected to ${name}`));
32361
- console.log(chalk.blue(` Available tools: ${tools.length}`));
32792
+ console.log(chalk2.green(`\u2713 Successfully connected to ${name}`));
32793
+ console.log(chalk2.blue(` Available tools: ${tools.length}`));
32362
32794
  if (tools.length > 0) {
32363
32795
  console.log(" Tools:");
32364
32796
  tools.forEach((tool) => {
@@ -32367,7 +32799,7 @@ function createMCPCommand() {
32367
32799
  });
32368
32800
  }
32369
32801
  } catch (error) {
32370
- console.error(chalk.red(`\u2717 Failed to connect to ${name}: ${error.message}`));
32802
+ console.error(chalk2.red(`\u2717 Failed to connect to ${name}: ${error.message}`));
32371
32803
  process.exit(1);
32372
32804
  }
32373
32805
  });
@@ -32391,9 +32823,9 @@ function createSetNameCommand() {
32391
32823
  try {
32392
32824
  const settingsManager = getSettingsManager();
32393
32825
  settingsManager.updateUserSetting("assistantName", name);
32394
- console.log(chalk.green(`\u2705 Assistant name set to: ${name}`));
32826
+ console.log(chalk2.green(`\u2705 Assistant name set to: ${name}`));
32395
32827
  } catch (error) {
32396
- console.error(chalk.red(`\u274C Failed to set assistant name: ${error.message}`));
32828
+ console.error(chalk2.red(`\u274C Failed to set assistant name: ${error.message}`));
32397
32829
  process.exit(1);
32398
32830
  }
32399
32831
  });
@@ -32418,10 +32850,10 @@ function createToggleConfirmationsCommand() {
32418
32850
  const currentValue = settingsManager.getUserSetting("requireConfirmation") ?? true;
32419
32851
  const newValue = !currentValue;
32420
32852
  settingsManager.updateUserSetting("requireConfirmation", newValue);
32421
- console.log(chalk.green(`\u2705 Confirmation requirement ${newValue ? "enabled" : "disabled"}`));
32853
+ console.log(chalk2.green(`\u2705 Confirmation requirement ${newValue ? "enabled" : "disabled"}`));
32422
32854
  console.log(`File operations and bash commands will ${newValue ? "now" : "no longer"} require confirmation.`);
32423
32855
  } catch (error) {
32424
- console.error(chalk.red(`\u274C Failed to toggle confirmations: ${error.message}`));
32856
+ console.error(chalk2.red(`\u274C Failed to toggle confirmations: ${error.message}`));
32425
32857
  process.exit(1);
32426
32858
  }
32427
32859
  });
@@ -32439,7 +32871,7 @@ var require_package = __commonJS({
32439
32871
  module.exports = {
32440
32872
  type: "module",
32441
32873
  name: "@xagent/one-shot",
32442
- version: "1.2.1",
32874
+ version: "1.2.3",
32443
32875
  description: "An open-source AI agent that brings advanced AI capabilities directly into your terminal with automatic documentation updates.",
32444
32876
  main: "dist/index.js",
32445
32877
  module: "dist/index.js",
@@ -32461,6 +32893,10 @@ var require_package = __commonJS({
32461
32893
  ],
32462
32894
  scripts: {
32463
32895
  local: "bun --watch src/index.ts",
32896
+ "test-agent": "bun run build && ./dist/index.js -p",
32897
+ "test-log": 'bun run build && ./dist/index.js -p "$1" 2>&1 | tee agent-test.log',
32898
+ "test-iterative": "./scripts/test-agent-iterative.sh",
32899
+ "test-self": "./scripts/agent-self-test.js",
32464
32900
  build: "tsup src/index.ts --format esm --dts",
32465
32901
  dev: "tsx watch src/index.ts",
32466
32902
  lint: "eslint src --ext .ts",
@@ -32624,6 +33060,7 @@ try {
32624
33060
  const { printWelcomeBanner: printWelcomeBanner2 } = await Promise.resolve().then(() => (init_use_console_setup(), use_console_setup_exports));
32625
33061
  const { getSettingsManager: getSettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
32626
33062
  const { ConfirmationService: ConfirmationService2 } = await Promise.resolve().then(() => (init_confirmation_service(), confirmation_service_exports));
33063
+ const { renderMarkdownToConsole: renderMarkdownToConsole2 } = await Promise.resolve().then(() => (init_console_markdown(), console_markdown_exports));
32627
33064
  const { createMCPCommand: createMCPCommand2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
32628
33065
  const { createSetNameCommand: createSetNameCommand2 } = await Promise.resolve().then(() => (init_set_name(), set_name_exports));
32629
33066
  const { createToggleConfirmationsCommand: createToggleConfirmationsCommand2 } = await Promise.resolve().then(() => (init_toggle_confirmations(), toggle_confirmations_exports));
@@ -32699,7 +33136,7 @@ try {
32699
33136
  const chatEntries = await agent.processUserMessage(options.prompt);
32700
33137
  for (const entry of chatEntries) {
32701
33138
  if (entry.type === "assistant" && entry.content) {
32702
- console.log(entry.content);
33139
+ console.log(renderMarkdownToConsole2(entry.content));
32703
33140
  }
32704
33141
  }
32705
33142
  } catch (error) {
@@ -32718,7 +33155,7 @@ try {
32718
33155
  printWelcomeBanner2(options.quiet);
32719
33156
  }
32720
33157
  const initialMessage = Array.isArray(message) ? message.join(" ") : message || "";
32721
- const app = render(React5.createElement(ChatInterface2, {
33158
+ const app = render(React4.createElement(ChatInterface2, {
32722
33159
  agent,
32723
33160
  initialMessage,
32724
33161
  quiet: options.quiet