@xagent/one-shot 1.2.0 → 1.2.2

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
@@ -23,8 +23,8 @@ import * as readline from 'readline';
23
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;
@@ -726,7 +726,7 @@ var init_client2 = __esm({
726
726
  },
727
727
  {
728
728
  capabilities: {
729
- tools: {}
729
+ // Client capabilities - not tools (tools are for servers)
730
730
  }
731
731
  }
732
732
  );
@@ -7562,10 +7562,10 @@ var init_dependency_analyzer = __esm({
7562
7562
  const circularDeps = [];
7563
7563
  const visited = /* @__PURE__ */ new Set();
7564
7564
  const visiting = /* @__PURE__ */ new Set();
7565
- const dfs = (filePath, path38) => {
7565
+ const dfs = (filePath, path39) => {
7566
7566
  if (visiting.has(filePath)) {
7567
- const cycleStart = path38.indexOf(filePath);
7568
- const cycle = path38.slice(cycleStart).concat([filePath]);
7567
+ const cycleStart = path39.indexOf(filePath);
7568
+ const cycle = path39.slice(cycleStart).concat([filePath]);
7569
7569
  circularDeps.push({
7570
7570
  cycle: cycle.map((fp) => graph.nodes.get(fp)?.filePath || fp),
7571
7571
  severity: cycle.length <= 2 ? "error" : "warning",
@@ -7581,7 +7581,7 @@ var init_dependency_analyzer = __esm({
7581
7581
  if (node) {
7582
7582
  for (const dependency of node.dependencies) {
7583
7583
  if (graph.nodes.has(dependency)) {
7584
- dfs(dependency, [...path38, filePath]);
7584
+ dfs(dependency, [...path39, filePath]);
7585
7585
  }
7586
7586
  }
7587
7587
  }
@@ -12740,8 +12740,8 @@ var init_parseUtil = __esm({
12740
12740
  init_errors();
12741
12741
  init_en();
12742
12742
  makeIssue = (params) => {
12743
- const { data, path: path38, errorMaps, issueData } = params;
12744
- const fullPath = [...path38, ...issueData.path || []];
12743
+ const { data, path: path39, errorMaps, issueData } = params;
12744
+ const fullPath = [...path39, ...issueData.path || []];
12745
12745
  const fullIssue = {
12746
12746
  ...issueData,
12747
12747
  path: fullPath
@@ -13049,11 +13049,11 @@ var init_types = __esm({
13049
13049
  init_parseUtil();
13050
13050
  init_util();
13051
13051
  ParseInputLazyPath = class {
13052
- constructor(parent, value, path38, key) {
13052
+ constructor(parent, value, path39, key) {
13053
13053
  this._cachedPath = [];
13054
13054
  this.parent = parent;
13055
13055
  this.data = value;
13056
- this._path = path38;
13056
+ this._path = path39;
13057
13057
  this._key = key;
13058
13058
  }
13059
13059
  get path() {
@@ -18384,6 +18384,10 @@ var init_grok_agent = __esm({
18384
18384
  this.minRequestInterval = 500;
18385
18385
  // ms
18386
18386
  this.lastRequestTime = 0;
18387
+ this.recentToolCalls = /* @__PURE__ */ new Map();
18388
+ // Track recent tool calls to prevent duplicates
18389
+ this.duplicateWindowMs = 2e3;
18390
+ // 2 second window for duplicate detection
18387
18391
  // Plan Mode integration
18388
18392
  this.planModeState = null;
18389
18393
  this.readonlyOverlay = null;
@@ -18445,6 +18449,13 @@ The above project context should inform your responses and decision making.` : "
18445
18449
  role: "system",
18446
18450
  content: `You are Grok One-Shot, an AI-powered CLI assistant that helps with file editing, coding tasks, and system operations.${customInstructionsSection}${contextSection}${verbosityInstructions}
18447
18451
 
18452
+ \u{1F6A8} CRITICAL TOOL CALLING RULES:
18453
+ - NEVER use multiple tool calls in a single response
18454
+ - NEVER concatenate tool calls like "view_fileview_file" or "str_replace_editorstr_replace_editor"
18455
+ - ALWAYS use ONE tool call per message with proper XML structure
18456
+ - WAIT for tool results before making additional tool calls
18457
+ - Each tool call must have valid JSON arguments only
18458
+
18448
18459
  You have access to these tools:
18449
18460
 
18450
18461
  CORE TOOLS:
@@ -18979,6 +18990,24 @@ Current working directory: ${process.cwd()}`
18979
18990
  }
18980
18991
  async executeTool(toolCall) {
18981
18992
  try {
18993
+ const toolName = toolCall.function?.name;
18994
+ const now = Date.now();
18995
+ const callSignature = `${toolName}:${toolCall.function?.arguments || ""}`;
18996
+ const lastCallTime = this.recentToolCalls.get(callSignature);
18997
+ if (lastCallTime && now - lastCallTime < this.duplicateWindowMs) {
18998
+ console.log(`[GrokAgent] Skipping duplicate tool call: ${toolName}`);
18999
+ return {
19000
+ success: true,
19001
+ output: "Skipped duplicate tool call",
19002
+ details: `This tool call was already executed ${Math.round((now - lastCallTime) / 1e3)}s ago`
19003
+ };
19004
+ }
19005
+ this.recentToolCalls.set(callSignature, now);
19006
+ for (const [key, time] of this.recentToolCalls.entries()) {
19007
+ if (now - time > this.duplicateWindowMs) {
19008
+ this.recentToolCalls.delete(key);
19009
+ }
19010
+ }
18982
19011
  const planModeState = this.getPlanModeState();
18983
19012
  if (planModeState?.active) {
18984
19013
  const readonlyOverlay = this.getReadonlyOverlay();
@@ -18986,6 +19015,25 @@ Current working directory: ${process.cwd()}`
18986
19015
  return await readonlyOverlay.interceptToolCall(toolCall);
18987
19016
  }
18988
19017
  }
19018
+ if (!toolCall.function?.arguments) {
19019
+ console.error(`[GrokAgent] Tool call missing function arguments:`, toolCall);
19020
+ return {
19021
+ success: false,
19022
+ error: `Tool call ${toolCall.function?.name || "unknown"} missing required arguments`,
19023
+ details: `This appears to be a malformed tool call. The AI model may have generated invalid XML or concatenated multiple tool calls.`
19024
+ };
19025
+ }
19026
+ if (typeof toolCall.function.arguments === "string" && (toolCall.function.arguments.includes("str_replace_editorstr_replace_editor") || toolCall.function.arguments.includes("view_fileview_file") || toolCall.function.arguments.includes("create_filecreate_file") || toolCall.function.arguments.includes("}{") || toolCall.function.name?.includes("view_file") && toolCall.function.name !== "view_file")) {
19027
+ console.error(`[GrokAgent] Detected malformed XML in tool call - appears to be concatenated:`, {
19028
+ toolName: toolCall.function.name,
19029
+ arguments: toolCall.function.arguments
19030
+ });
19031
+ return {
19032
+ success: false,
19033
+ error: `Malformed tool call detected - appears to be concatenated XML without proper structure`,
19034
+ details: `The AI model generated invalid XML by concatenating multiple tool calls. This is a model generation issue that requires single, properly formatted tool calls.`
19035
+ };
19036
+ }
18989
19037
  let args;
18990
19038
  try {
18991
19039
  args = JSON.parse(toolCall.function.arguments);
@@ -18997,14 +19045,14 @@ Current working directory: ${process.cwd()}`
18997
19045
  toolCall
18998
19046
  });
18999
19047
  try {
19000
- const cleanedArgs = toolCall.function.arguments.replace(/,\s*}/g, "}").replace(/,\s*]/g, "]").trim();
19048
+ const cleanedArgs = toolCall.function.arguments.replace(/,\s*}/g, "}").replace(/,\s*]/g, "]").replace(/^\s*{?\s*/, "{").replace(/\s*}?\s*$/, "}").trim();
19001
19049
  args = JSON.parse(cleanedArgs);
19002
19050
  console.log(`[GrokAgent] JSON parsing recovered after cleanup`);
19003
19051
  } catch (retryError) {
19004
19052
  return {
19005
19053
  success: false,
19006
19054
  error: `Invalid JSON arguments for ${toolCall.function.name}: ${parseError.message}. Arguments: ${toolCall.function.arguments}`,
19007
- details: `Tool call failed due to malformed JSON. This is likely a model generation issue.`
19055
+ details: `Tool call failed due to malformed JSON. This is likely a model generation issue. Try using single tool calls with proper XML structure.`
19008
19056
  };
19009
19057
  }
19010
19058
  }
@@ -19050,10 +19098,10 @@ Current working directory: ${process.cwd()}`
19050
19098
  return await this.textEditor.view(args.path, range);
19051
19099
  } catch (error) {
19052
19100
  console.warn(`view_file tool failed, falling back to bash: ${error.message}`);
19053
- const path38 = args.path;
19054
- let command = `cat "${path38}"`;
19101
+ const path39 = args.path;
19102
+ let command = `cat "${path39}"`;
19055
19103
  if (args.start_line && args.end_line) {
19056
- command = `sed -n '${args.start_line},${args.end_line}p' "${path38}"`;
19104
+ command = `sed -n '${args.start_line},${args.end_line}p' "${path39}"`;
19057
19105
  }
19058
19106
  return await this.bash.execute(command);
19059
19107
  }
@@ -19264,6 +19312,25 @@ EOF`;
19264
19312
  }
19265
19313
  async executeMCPTool(toolCall) {
19266
19314
  try {
19315
+ if (!toolCall.function?.arguments) {
19316
+ console.error(`[GrokAgent] MCP tool call missing function arguments:`, toolCall);
19317
+ return {
19318
+ success: false,
19319
+ error: `MCP tool call ${toolCall.function?.name || "unknown"} missing required arguments`,
19320
+ details: `This appears to be a malformed MCP tool call. The AI model may have generated invalid XML or concatenated multiple tool calls.`
19321
+ };
19322
+ }
19323
+ if (typeof toolCall.function.arguments === "string" && (toolCall.function.arguments.includes("mcp__") && toolCall.function.arguments.match(/mcp__\w+mcp__/) || toolCall.function.name?.startsWith("mcp__") && toolCall.function.name.split("__").length > 3)) {
19324
+ console.error(`[GrokAgent] Detected malformed XML in MCP tool call:`, {
19325
+ toolName: toolCall.function.name,
19326
+ arguments: toolCall.function.arguments
19327
+ });
19328
+ return {
19329
+ success: false,
19330
+ error: `Malformed MCP tool call detected - appears to be concatenated XML`,
19331
+ details: `The AI model generated invalid XML by concatenating multiple MCP tool calls. Use single, properly formatted tool calls only.`
19332
+ };
19333
+ }
19267
19334
  let args;
19268
19335
  try {
19269
19336
  args = JSON.parse(toolCall.function.arguments);
@@ -19275,7 +19342,7 @@ EOF`;
19275
19342
  toolCall
19276
19343
  });
19277
19344
  try {
19278
- const cleanedArgs = toolCall.function.arguments.replace(/,\s*}/g, "}").replace(/,\s*]/g, "]").trim();
19345
+ const cleanedArgs = toolCall.function.arguments.replace(/,\s*}/g, "}").replace(/,\s*]/g, "]").replace(/^\s*{?\s*/, "{").replace(/\s*}?\s*$/, "}").trim();
19279
19346
  args = JSON.parse(cleanedArgs);
19280
19347
  console.log(`[GrokAgent] MCP JSON parsing recovered after cleanup`);
19281
19348
  } catch (retryError) {
@@ -19634,6 +19701,10 @@ ${output?.plan?.summary || "Task completed"}`,
19634
19701
  instructions += "- Keep responses CONCISE and to the point. Avoid lengthy explanations.\n";
19635
19702
  instructions += "- Prioritize brevity over detail unless specifically requested.\n";
19636
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";
19637
19708
  break;
19638
19709
  case "normal":
19639
19710
  instructions += "- Provide balanced responses with appropriate detail.\n";
@@ -19659,6 +19730,11 @@ ${output?.plan?.summary || "Task completed"}`,
19659
19730
  instructions += "- Provide detailed context for all operations.\n";
19660
19731
  break;
19661
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";
19662
19738
  return instructions;
19663
19739
  }
19664
19740
  // Plan Mode integration methods
@@ -19863,150 +19939,21 @@ var init_use_input_history = __esm({
19863
19939
  "src/hooks/use-input-history.ts"() {
19864
19940
  }
19865
19941
  });
19866
-
19867
- // src/services/paste-detection.ts
19868
- function getPasteDetectionService() {
19869
- if (!globalPasteService) {
19870
- globalPasteService = new PasteDetectionService();
19871
- }
19872
- return globalPasteService;
19873
- }
19874
- var PasteDetectionService, globalPasteService;
19875
- var init_paste_detection = __esm({
19876
- "src/services/paste-detection.ts"() {
19877
- PasteDetectionService = class {
19878
- constructor(thresholds) {
19879
- this.pasteCounter = 0;
19880
- this.debug = process.env.GROK_PASTE_DEBUG === "true";
19881
- this.thresholds = {
19882
- lineThreshold: thresholds?.lineThreshold ?? this.getDefaultLineThreshold(),
19883
- charThreshold: thresholds?.charThreshold ?? this.getDefaultCharThreshold()
19884
- };
19885
- }
19886
- /**
19887
- * Detects if new content represents a paste operation that should be summarized
19888
- */
19889
- detectPaste(oldValue, newValue) {
19890
- const added = this.getAddedContent(oldValue, newValue);
19891
- if (this.debug) {
19892
- console.log("\u{1F50D} Paste Detection Debug:", {
19893
- addedLength: added?.length || 0,
19894
- lineCount: added ? this.countLines(added) : 0,
19895
- thresholds: this.thresholds,
19896
- shouldSummarize: added ? this.shouldSummarize(added) : false
19897
- });
19898
- }
19899
- if (!added || !this.shouldSummarize(added)) {
19900
- return null;
19901
- }
19902
- this.pasteCounter++;
19903
- return {
19904
- content: added,
19905
- lineCount: this.countLines(added),
19906
- charCount: added.length,
19907
- pasteNumber: this.pasteCounter,
19908
- summary: this.createPasteSummary(added, this.pasteCounter)
19909
- };
19910
- }
19911
- /**
19912
- * Determines if content should be summarized based on thresholds
19913
- */
19914
- shouldSummarize(content) {
19915
- const lineCount = this.countLines(content);
19916
- return lineCount > this.thresholds.lineThreshold || content.length > this.thresholds.charThreshold;
19917
- }
19918
- /**
19919
- * Creates a paste summary in the format: [Pasted text #N +X lines]
19920
- */
19921
- createPasteSummary(content, pasteNumber) {
19922
- const lineCount = this.countLines(content);
19923
- const pluralLines = lineCount === 1 ? "line" : "lines";
19924
- return `[Pasted text #${pasteNumber} +${lineCount} ${pluralLines}]`;
19925
- }
19926
- /**
19927
- * Resets the paste counter (useful for new sessions)
19928
- */
19929
- resetCounter() {
19930
- this.pasteCounter = 0;
19931
- }
19932
- /**
19933
- * Updates thresholds for paste detection
19934
- */
19935
- updateThresholds(thresholds) {
19936
- this.thresholds = {
19937
- ...this.thresholds,
19938
- ...thresholds
19939
- };
19940
- }
19941
- /**
19942
- * Gets current paste counter value
19943
- */
19944
- getCurrentCounter() {
19945
- return this.pasteCounter;
19946
- }
19947
- /**
19948
- * Gets current thresholds
19949
- */
19950
- getThresholds() {
19951
- return { ...this.thresholds };
19952
- }
19953
- /**
19954
- * Extracts the content that was added between old and new values
19955
- */
19956
- getAddedContent(oldValue, newValue) {
19957
- if (newValue.startsWith(oldValue)) {
19958
- return newValue.slice(oldValue.length);
19959
- }
19960
- return "";
19961
- }
19962
- /**
19963
- * Counts the number of lines in content
19964
- */
19965
- countLines(content) {
19966
- if (!content) return 0;
19967
- const lines = content.split(/\r\n|\r|\n/);
19968
- return lines[lines.length - 1] === "" ? lines.length - 1 : lines.length;
19969
- }
19970
- /**
19971
- * Gets default line threshold from environment or config
19972
- */
19973
- getDefaultLineThreshold() {
19974
- const envValue = process.env.GROK_PASTE_LINE_THRESHOLD;
19975
- if (envValue) {
19976
- const parsed = parseInt(envValue, 10);
19977
- if (!isNaN(parsed) && parsed > 0) {
19978
- return parsed;
19979
- }
19980
- }
19981
- return 2;
19982
- }
19983
- /**
19984
- * Gets default character threshold from environment or config
19985
- */
19986
- getDefaultCharThreshold() {
19987
- const envValue = process.env.GROK_PASTE_CHAR_THRESHOLD;
19988
- if (envValue) {
19989
- const parsed = parseInt(envValue, 10);
19990
- if (!isNaN(parsed) && parsed > 0) {
19991
- return parsed;
19992
- }
19993
- }
19994
- return 50;
19995
- }
19996
- };
19997
- globalPasteService = null;
19998
- }
19999
- });
20000
19942
  function useEnhancedInput({
20001
19943
  onSubmit,
20002
19944
  onEscape,
20003
19945
  onSpecialKey,
20004
- onPasteDetected,
20005
19946
  disabled = false,
20006
19947
  multiline = false
20007
19948
  } = {}) {
20008
19949
  const [input, setInputState] = useState("");
20009
19950
  const [cursorPosition, setCursorPositionState] = useState(0);
19951
+ const debugSetInputState = useCallback((newInput) => {
19952
+ setInputState(newInput);
19953
+ }, []);
19954
+ const debugSetCursorPositionState = useCallback((newPos) => {
19955
+ setCursorPositionState(newPos);
19956
+ }, []);
20010
19957
  const isMultilineRef = useRef(multiline);
20011
19958
  const {
20012
19959
  addToHistory,
@@ -20016,32 +19963,34 @@ function useEnhancedInput({
20016
19963
  isNavigatingHistory
20017
19964
  } = useInputHistory();
20018
19965
  const setInput = useCallback((text) => {
20019
- const previousInput = input;
20020
- setInputState(text);
20021
- setCursorPositionState(Math.min(text.length, cursorPosition));
19966
+ enhancedLog("\u{1F504} setInput called");
19967
+ enhancedLog("setInput details:", {
19968
+ previousInput: input.slice(0, 100) + (input.length > 100 ? "..." : ""),
19969
+ newText: text.slice(0, 100) + (text.length > 100 ? "..." : ""),
19970
+ previousLength: input.length,
19971
+ newLength: text.length,
19972
+ cursorPosition,
19973
+ isNavigatingHistory: isNavigatingHistory()
19974
+ });
19975
+ debugSetInputState(text);
19976
+ debugSetCursorPositionState(Math.min(text.length, cursorPosition));
20022
19977
  if (!isNavigatingHistory()) {
20023
19978
  setOriginalInput(text);
20024
19979
  }
20025
- if (onPasteDetected && text !== previousInput) {
20026
- const pasteService = getPasteDetectionService();
20027
- const pasteEvent = pasteService.detectPaste(previousInput, text);
20028
- if (pasteEvent) {
20029
- onPasteDetected(pasteEvent);
20030
- }
20031
- }
20032
- }, [input, cursorPosition, isNavigatingHistory, setOriginalInput, onPasteDetected]);
19980
+ enhancedLog("\u2705 setInput completed");
19981
+ }, [input, cursorPosition, isNavigatingHistory, setOriginalInput]);
20033
19982
  const setCursorPosition = useCallback((position) => {
20034
- setCursorPositionState(Math.max(0, Math.min(input.length, position)));
20035
- }, [input.length]);
19983
+ debugSetCursorPositionState(Math.max(0, Math.min(input.length, position)));
19984
+ }, [input.length, debugSetCursorPositionState]);
20036
19985
  const clearInput = useCallback(() => {
20037
- setInputState("");
20038
- setCursorPositionState(0);
19986
+ debugSetInputState("");
19987
+ debugSetCursorPositionState(0);
20039
19988
  setOriginalInput("");
20040
- }, [setOriginalInput]);
19989
+ }, [setOriginalInput, debugSetInputState, debugSetCursorPositionState]);
20041
19990
  const insertAtCursor = useCallback((text) => {
20042
19991
  const result = insertText(input, cursorPosition, text);
20043
- setInputState(result.text);
20044
- setCursorPositionState(result.position);
19992
+ debugSetInputState(result.text);
19993
+ debugSetCursorPositionState(result.position);
20045
19994
  setOriginalInput(result.text);
20046
19995
  }, [input, cursorPosition, setOriginalInput]);
20047
19996
  const handleSubmit = useCallback(() => {
@@ -20052,10 +20001,31 @@ function useEnhancedInput({
20052
20001
  }
20053
20002
  }, [input, addToHistory, onSubmit, clearInput]);
20054
20003
  const handleInput = useCallback((inputChar, key) => {
20055
- if (disabled) return;
20004
+ enhancedLog("\u2328\uFE0F handleInput called");
20005
+ enhancedLog("Input event:", {
20006
+ inputChar: inputChar === "" ? "(empty)" : inputChar,
20007
+ charCode: inputChar.charCodeAt(0) || "N/A",
20008
+ key: {
20009
+ name: key.name || "undefined",
20010
+ ctrl: !!key.ctrl,
20011
+ meta: !!key.meta,
20012
+ shift: !!key.shift,
20013
+ paste: !!key.paste,
20014
+ return: !!key.return,
20015
+ backspace: !!key.backspace,
20016
+ delete: !!key.delete
20017
+ },
20018
+ currentInput: input.slice(0, 50) + (input.length > 50 ? "..." : ""),
20019
+ currentInputLength: input.length,
20020
+ disabled
20021
+ });
20022
+ if (disabled) {
20023
+ enhancedLog("\u274C Input disabled, returning early");
20024
+ return;
20025
+ }
20056
20026
  if (key.ctrl && inputChar === "c" || inputChar === "") {
20057
- setInputState("");
20058
- setCursorPositionState(0);
20027
+ debugSetInputState("");
20028
+ debugSetCursorPositionState(0);
20059
20029
  setOriginalInput("");
20060
20030
  return;
20061
20031
  }
@@ -20069,8 +20039,8 @@ function useEnhancedInput({
20069
20039
  if (key.return) {
20070
20040
  if (multiline && key.shift) {
20071
20041
  const result = insertText(input, cursorPosition, "\n");
20072
- setInputState(result.text);
20073
- setCursorPositionState(result.position);
20042
+ debugSetInputState(result.text);
20043
+ debugSetCursorPositionState(result.position);
20074
20044
  setOriginalInput(result.text);
20075
20045
  } else {
20076
20046
  handleSubmit();
@@ -20080,58 +20050,58 @@ function useEnhancedInput({
20080
20050
  if ((key.upArrow || key.name === "up") && !key.ctrl && !key.meta) {
20081
20051
  const historyInput = navigateHistory("up");
20082
20052
  if (historyInput !== null) {
20083
- setInputState(historyInput);
20084
- setCursorPositionState(historyInput.length);
20053
+ debugSetInputState(historyInput);
20054
+ debugSetCursorPositionState(historyInput.length);
20085
20055
  }
20086
20056
  return;
20087
20057
  }
20088
20058
  if ((key.downArrow || key.name === "down") && !key.ctrl && !key.meta) {
20089
20059
  const historyInput = navigateHistory("down");
20090
20060
  if (historyInput !== null) {
20091
- setInputState(historyInput);
20092
- setCursorPositionState(historyInput.length);
20061
+ debugSetInputState(historyInput);
20062
+ debugSetCursorPositionState(historyInput.length);
20093
20063
  }
20094
20064
  return;
20095
20065
  }
20096
20066
  if ((key.leftArrow || key.name === "left") && key.ctrl && !inputChar.includes("[")) {
20097
20067
  const newPos = moveToPreviousWord(input, cursorPosition);
20098
- setCursorPositionState(newPos);
20068
+ debugSetCursorPositionState(newPos);
20099
20069
  return;
20100
20070
  }
20101
20071
  if ((key.rightArrow || key.name === "right") && key.ctrl && !inputChar.includes("[")) {
20102
20072
  const newPos = moveToNextWord(input, cursorPosition);
20103
- setCursorPositionState(newPos);
20073
+ debugSetCursorPositionState(newPos);
20104
20074
  return;
20105
20075
  }
20106
20076
  if (key.leftArrow || key.name === "left") {
20107
20077
  const newPos = Math.max(0, cursorPosition - 1);
20108
- setCursorPositionState(newPos);
20078
+ debugSetCursorPositionState(newPos);
20109
20079
  return;
20110
20080
  }
20111
20081
  if (key.rightArrow || key.name === "right") {
20112
20082
  const newPos = Math.min(input.length, cursorPosition + 1);
20113
- setCursorPositionState(newPos);
20083
+ debugSetCursorPositionState(newPos);
20114
20084
  return;
20115
20085
  }
20116
20086
  if (key.ctrl && inputChar === "a" || key.name === "home") {
20117
- setCursorPositionState(0);
20087
+ debugSetCursorPositionState(0);
20118
20088
  return;
20119
20089
  }
20120
20090
  if (key.ctrl && inputChar === "e" || key.name === "end") {
20121
- setCursorPositionState(input.length);
20091
+ debugSetCursorPositionState(input.length);
20122
20092
  return;
20123
20093
  }
20124
20094
  const isBackspace = key.backspace || key.name === "backspace" || inputChar === "\b" || inputChar === "\x7F" || key.delete && inputChar === "" && !key.shift;
20125
20095
  if (isBackspace) {
20126
20096
  if (key.ctrl || key.meta) {
20127
20097
  const result = deleteWordBefore(input, cursorPosition);
20128
- setInputState(result.text);
20129
- setCursorPositionState(result.position);
20098
+ debugSetInputState(result.text);
20099
+ debugSetCursorPositionState(result.position);
20130
20100
  setOriginalInput(result.text);
20131
20101
  } else {
20132
20102
  const result = deleteCharBefore(input, cursorPosition);
20133
- setInputState(result.text);
20134
- setCursorPositionState(result.position);
20103
+ debugSetInputState(result.text);
20104
+ debugSetCursorPositionState(result.position);
20135
20105
  setOriginalInput(result.text);
20136
20106
  }
20137
20107
  return;
@@ -20139,13 +20109,13 @@ function useEnhancedInput({
20139
20109
  if (key.delete && inputChar !== "" || key.ctrl && inputChar === "d") {
20140
20110
  if (key.ctrl || key.meta) {
20141
20111
  const result = deleteWordAfter(input, cursorPosition);
20142
- setInputState(result.text);
20143
- setCursorPositionState(result.position);
20112
+ debugSetInputState(result.text);
20113
+ debugSetCursorPositionState(result.position);
20144
20114
  setOriginalInput(result.text);
20145
20115
  } else {
20146
20116
  const result = deleteCharAfter(input, cursorPosition);
20147
- setInputState(result.text);
20148
- setCursorPositionState(result.position);
20117
+ debugSetInputState(result.text);
20118
+ debugSetCursorPositionState(result.position);
20149
20119
  setOriginalInput(result.text);
20150
20120
  }
20151
20121
  return;
@@ -20153,36 +20123,57 @@ function useEnhancedInput({
20153
20123
  if (key.ctrl && inputChar === "k") {
20154
20124
  const lineEnd = moveToLineEnd(input, cursorPosition);
20155
20125
  const newText = input.slice(0, cursorPosition) + input.slice(lineEnd);
20156
- setInputState(newText);
20126
+ debugSetInputState(newText);
20157
20127
  setOriginalInput(newText);
20158
20128
  return;
20159
20129
  }
20160
20130
  if (key.ctrl && inputChar === "u") {
20161
20131
  const lineStart = moveToLineStart(input, cursorPosition);
20162
20132
  const newText = input.slice(0, lineStart) + input.slice(cursorPosition);
20163
- setInputState(newText);
20164
- setCursorPositionState(lineStart);
20133
+ debugSetInputState(newText);
20134
+ debugSetCursorPositionState(lineStart);
20165
20135
  setOriginalInput(newText);
20166
20136
  return;
20167
20137
  }
20168
20138
  if (key.ctrl && inputChar === "w") {
20169
20139
  const result = deleteWordBefore(input, cursorPosition);
20170
- setInputState(result.text);
20171
- setCursorPositionState(result.position);
20140
+ debugSetInputState(result.text);
20141
+ debugSetCursorPositionState(result.position);
20172
20142
  setOriginalInput(result.text);
20173
20143
  return;
20174
20144
  }
20175
20145
  if (key.ctrl && inputChar === "x") {
20176
- setInputState("");
20177
- setCursorPositionState(0);
20146
+ debugSetInputState("");
20147
+ debugSetCursorPositionState(0);
20178
20148
  setOriginalInput("");
20179
20149
  return;
20180
20150
  }
20181
20151
  if (inputChar && !key.ctrl && !key.meta) {
20152
+ enhancedLog("\u{1F4DD} Regular character input detected");
20153
+ enhancedLog("Character details:", {
20154
+ character: inputChar,
20155
+ currentPosition: cursorPosition,
20156
+ currentInputLength: input.length,
20157
+ willInsertAt: cursorPosition
20158
+ });
20182
20159
  const result = insertText(input, cursorPosition, inputChar);
20183
- setInputState(result.text);
20184
- setCursorPositionState(result.position);
20160
+ enhancedLog("\u{1F4DD} Text insertion result:", {
20161
+ oldLength: input.length,
20162
+ newLength: result.text.length,
20163
+ newPosition: result.position,
20164
+ insertedChar: inputChar
20165
+ });
20166
+ debugSetInputState(result.text);
20167
+ debugSetCursorPositionState(result.position);
20185
20168
  setOriginalInput(result.text);
20169
+ enhancedLog("\u2705 Regular character input completed");
20170
+ } else {
20171
+ enhancedLog("\u274C Character input skipped:", {
20172
+ hasInputChar: !!inputChar,
20173
+ isCtrl: !!key.ctrl,
20174
+ isMeta: !!key.meta,
20175
+ reason: !inputChar ? "No input char" : key.ctrl ? "Ctrl pressed" : "Meta pressed"
20176
+ });
20186
20177
  }
20187
20178
  }, [disabled, onSpecialKey, input, cursorPosition, multiline, handleSubmit, navigateHistory, setOriginalInput]);
20188
20179
  return {
@@ -20197,11 +20188,13 @@ function useEnhancedInput({
20197
20188
  handleInput
20198
20189
  };
20199
20190
  }
20191
+ var enhancedLog;
20200
20192
  var init_use_enhanced_input = __esm({
20201
20193
  "src/hooks/use-enhanced-input.ts"() {
20202
20194
  init_text_utils();
20203
20195
  init_use_input_history();
20204
- init_paste_detection();
20196
+ enhancedLog = (..._args) => {
20197
+ };
20205
20198
  }
20206
20199
  });
20207
20200
 
@@ -27099,7 +27092,7 @@ var init_package = __esm({
27099
27092
  package_default = {
27100
27093
  type: "module",
27101
27094
  name: "@xagent/one-shot",
27102
- version: "1.2.0",
27095
+ version: "1.2.2",
27103
27096
  description: "An open-source AI agent that brings advanced AI capabilities directly into your terminal with automatic documentation updates.",
27104
27097
  main: "dist/index.js",
27105
27098
  module: "dist/index.js",
@@ -27518,23 +27511,6 @@ function useInputHandler({
27518
27511
  }
27519
27512
  }
27520
27513
  };
27521
- const handlePasteDetected = (pasteEvent) => {
27522
- const userEntry = {
27523
- type: "user",
27524
- content: pasteEvent.content,
27525
- // Full content for AI (when submitted)
27526
- displayContent: pasteEvent.summary,
27527
- // Summary for UI display
27528
- timestamp: /* @__PURE__ */ new Date(),
27529
- isPasteSummary: true,
27530
- pasteMetadata: {
27531
- pasteNumber: pasteEvent.pasteNumber,
27532
- lineCount: pasteEvent.lineCount,
27533
- charCount: pasteEvent.charCount
27534
- }
27535
- };
27536
- setChatHistory((prev) => [...prev, userEntry]);
27537
- };
27538
27514
  const handleInputChange = (newInput) => {
27539
27515
  if (newInput.startsWith("/")) {
27540
27516
  setShowCommandSuggestions(true);
@@ -27550,20 +27526,75 @@ function useInputHandler({
27550
27526
  setInput,
27551
27527
  setCursorPosition,
27552
27528
  clearInput,
27529
+ insertAtCursor,
27553
27530
  resetHistory,
27554
27531
  handleInput
27555
27532
  } = useEnhancedInput({
27556
27533
  onSubmit: handleInputSubmit,
27557
27534
  onSpecialKey: handleSpecialKey,
27558
- onPasteDetected: handlePasteDetected,
27535
+ // Paste detection handled inline
27559
27536
  disabled: isConfirmationActive,
27560
27537
  multiline: true
27561
27538
  // Enable multiline mode to handle pasted content properly
27562
27539
  });
27540
+ if (typeof globalThis.grokPasteCache === "undefined") {
27541
+ globalThis.grokPasteCache = /* @__PURE__ */ new Map();
27542
+ }
27543
+ if (typeof globalThis.grokPasteCounter === "undefined") {
27544
+ globalThis.grokPasteCounter = 0;
27545
+ }
27563
27546
  useInput((inputChar, key) => {
27564
27547
  if (onGlobalShortcut && onGlobalShortcut(inputChar, key)) {
27565
27548
  return;
27566
27549
  }
27550
+ if (inputChar.length > 1) {
27551
+ const existingInputBeforePaste = input;
27552
+ const cursorPositionBeforePaste = cursorPosition;
27553
+ if (!globalThis.grokStreamingPasteBuffer) {
27554
+ globalThis.grokExistingInputBeforePaste = existingInputBeforePaste;
27555
+ globalThis.grokCursorPositionBeforePaste = cursorPositionBeforePaste;
27556
+ }
27557
+ if (!globalThis.grokStreamingPasteBuffer) {
27558
+ globalThis.grokStreamingPasteBuffer = "";
27559
+ }
27560
+ globalThis.grokStreamingPasteBuffer += inputChar;
27561
+ setTimeout(() => {
27562
+ const pastedContent = globalThis.grokStreamingPasteBuffer;
27563
+ if (pastedContent && (pastedContent.length > 100 || pastedContent.split(/\r\n|\r|\n/).length > 10)) {
27564
+ const lines = pastedContent.split(/\r\n|\r|\n/);
27565
+ globalThis.grokPasteCounter += 1;
27566
+ const summary = `[Pasted text #${globalThis.grokPasteCounter} +${lines.length} lines]`;
27567
+ globalThis.grokPasteCache.set(summary, pastedContent);
27568
+ const existingInput2 = globalThis.grokExistingInputBeforePaste || "";
27569
+ const cursorPos = globalThis.grokCursorPositionBeforePaste || 0;
27570
+ setInput(existingInput2);
27571
+ setCursorPosition(cursorPos);
27572
+ setTimeout(() => {
27573
+ insertAtCursor(summary);
27574
+ }, 10);
27575
+ const pasteConfirmationEntry = {
27576
+ type: "assistant",
27577
+ content: `\u{1F4C4} Large paste detected: ${lines.length} lines, showing summary`,
27578
+ timestamp: /* @__PURE__ */ new Date()
27579
+ };
27580
+ setChatHistory((prev) => [...prev, pasteConfirmationEntry]);
27581
+ } else if (pastedContent) {
27582
+ const existingInput2 = globalThis.grokExistingInputBeforePaste || "";
27583
+ const cursorPos = globalThis.grokCursorPositionBeforePaste || 0;
27584
+ const beforeCursor = existingInput2.slice(0, cursorPos);
27585
+ const afterCursor = existingInput2.slice(cursorPos);
27586
+ const combinedContent = beforeCursor + pastedContent + afterCursor;
27587
+ setInput(combinedContent);
27588
+ setTimeout(() => {
27589
+ setCursorPosition(beforeCursor.length + pastedContent.length);
27590
+ }, 0);
27591
+ }
27592
+ globalThis.grokStreamingPasteBuffer = void 0;
27593
+ globalThis.grokExistingInputBeforePaste = void 0;
27594
+ globalThis.grokCursorPositionBeforePaste = void 0;
27595
+ }, 100);
27596
+ return;
27597
+ }
27567
27598
  handleInput(inputChar, key);
27568
27599
  });
27569
27600
  useEffect(() => {
@@ -28793,12 +28824,12 @@ Auto-compact automatically enables compact mode when conversations exceed thresh
28793
28824
  content: `\u{1F50A} **Current Verbosity Level: ${verbosityLevel.toUpperCase()}**
28794
28825
 
28795
28826
  **Available levels:**
28796
- - \`quiet\` - Minimal output, suppress prefixes and extra formatting
28827
+ - \`quiet\` - \u{1F3AF} **Claude Code mode**: Ultra-brief tool output (\`\u23BF Read X lines (ctrl+r to expand)\`)
28797
28828
  - \`normal\` - Current default behavior with full details
28798
28829
  - \`verbose\` - Additional details and debug information
28799
28830
 
28800
28831
  **Usage:** \`/verbosity <level>\`
28801
- **Example:** \`/verbosity quiet\``,
28832
+ **Example:** \`/verbosity quiet\` (for Claude Code parity)`,
28802
28833
  timestamp: /* @__PURE__ */ new Date()
28803
28834
  };
28804
28835
  setChatHistory((prev) => [...prev, levelEntry]);
@@ -28813,7 +28844,7 @@ Auto-compact automatically enables compact mode when conversations exceed thresh
28813
28844
  type: "assistant",
28814
28845
  content: `\u2705 **Verbosity level set to: ${newLevel.toUpperCase()}**
28815
28846
 
28816
- Tool outputs will now show ${newLevel === "quiet" ? "minimal output" : newLevel === "normal" ? "full details" : "extra details and debug information"}.`,
28847
+ ${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."}`,
28817
28848
  timestamp: /* @__PURE__ */ new Date()
28818
28849
  };
28819
28850
  setChatHistory((prev) => [...prev, confirmEntry]);
@@ -29220,24 +29251,27 @@ ${pushResult.error || "Git push failed"}
29220
29251
  }
29221
29252
  return false;
29222
29253
  };
29223
- const processUserMessage = async (userInput) => {
29224
- const pasteService = getPasteDetectionService();
29225
- const shouldSummarize = pasteService.shouldSummarize(userInput);
29226
- const recentEntry = chatHistory[chatHistory.length - 1];
29227
- const isAlreadyShowingPasteSummary = recentEntry && recentEntry.isPasteSummary && recentEntry.content === userInput;
29228
- if (!isAlreadyShowingPasteSummary) {
29229
- const userEntry = {
29230
- type: "user",
29231
- content: userInput,
29232
- displayContent: shouldSummarize ? pasteService.createPasteSummary(userInput, pasteService.getCurrentCounter() + 1) : userInput,
29233
- timestamp: /* @__PURE__ */ new Date(),
29234
- isPasteSummary: shouldSummarize
29235
- };
29236
- if (shouldSummarize) {
29237
- pasteService.detectPaste("", userInput);
29238
- }
29239
- setChatHistory((prev) => [...prev, userEntry]);
29254
+ const expandPasteSummaryToFullContent = async (userInput) => {
29255
+ if (!globalThis.grokPasteCache) return userInput;
29256
+ let expandedInput = userInput;
29257
+ const cache = globalThis.grokPasteCache;
29258
+ for (const [summary, fullContent] of cache.entries()) {
29259
+ const cleanContent = fullContent.replace(/\r\n/g, "\n").replace(/\r/g, "\n").trim().split("\n").map((line) => line.trim()).join("\n");
29260
+ expandedInput = expandedInput.replace(summary, cleanContent);
29240
29261
  }
29262
+ return expandedInput;
29263
+ };
29264
+ const processUserMessage = async (userInput) => {
29265
+ const expandedInput = await expandPasteSummaryToFullContent(userInput);
29266
+ const userEntry = {
29267
+ type: "user",
29268
+ content: expandedInput,
29269
+ // AI receives expanded content
29270
+ displayContent: userInput,
29271
+ // UI shows what user typed (may be summary)
29272
+ timestamp: /* @__PURE__ */ new Date()
29273
+ };
29274
+ setChatHistory((prev) => [...prev, userEntry]);
29241
29275
  setIsProcessing(true);
29242
29276
  clearInput();
29243
29277
  try {
@@ -29326,7 +29360,7 @@ ${pushResult.error || "Git push failed"}
29326
29360
  }
29327
29361
  lastUpdateTime = now;
29328
29362
  };
29329
- for await (const chunk of agent.processUserMessageStream(userInput)) {
29363
+ for await (const chunk of agent.processUserMessageStream(expandedInput)) {
29330
29364
  switch (chunk.type) {
29331
29365
  case "content":
29332
29366
  if (chunk.content) {
@@ -29396,7 +29430,6 @@ var init_use_input_handler = __esm({
29396
29430
  "src/hooks/use-input-handler.ts"() {
29397
29431
  init_confirmation_service();
29398
29432
  init_use_enhanced_input();
29399
- init_paste_detection();
29400
29433
  init_use_plan_mode();
29401
29434
  init_command_suggestions();
29402
29435
  init_model_config();
@@ -30448,18 +30481,179 @@ var init_user_message_entry = __esm({
30448
30481
  };
30449
30482
  }
30450
30483
  });
30484
+ function MarkdownRenderer({ content }) {
30485
+ try {
30486
+ return /* @__PURE__ */ jsx(InlineMarkdown, { content });
30487
+ } catch (error) {
30488
+ console.error("Markdown rendering error:", error);
30489
+ return /* @__PURE__ */ jsx(Text, { wrap: "wrap", dimColor: false, children: content });
30490
+ }
30491
+ }
30492
+ function InlineMarkdown({ content }) {
30493
+ const lines = content.split("\n");
30494
+ return /* @__PURE__ */ jsx(Text, { wrap: "wrap", dimColor: false, children: lines.map((line, lineIndex) => /* @__PURE__ */ jsxs(React4.Fragment, { children: [
30495
+ lineIndex > 0 && "\n",
30496
+ parseInlineMarkdown(line).map((part, partIndex) => {
30497
+ if (part.type === "header") {
30498
+ return /* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: part.text }, `${lineIndex}-${partIndex}`);
30499
+ }
30500
+ if (part.type === "bold") {
30501
+ return /* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: part.text }, `${lineIndex}-${partIndex}`);
30502
+ }
30503
+ if (part.type === "italic") {
30504
+ return /* @__PURE__ */ jsx(Text, { italic: true, color: "gray", children: part.text }, `${lineIndex}-${partIndex}`);
30505
+ }
30506
+ if (part.type === "code") {
30507
+ return /* @__PURE__ */ jsx(Text, { color: "cyan", children: part.text }, `${lineIndex}-${partIndex}`);
30508
+ }
30509
+ if (part.type === "emoji") {
30510
+ const emoji = part.text;
30511
+ if (emoji === "\u2705" || emoji === "\u2713") {
30512
+ return /* @__PURE__ */ jsx(Text, { color: "green", children: emoji }, `${lineIndex}-${partIndex}`);
30513
+ }
30514
+ if (emoji === "\u274C" || emoji === "\u2717") {
30515
+ return /* @__PURE__ */ jsx(Text, { color: "red", children: emoji }, `${lineIndex}-${partIndex}`);
30516
+ }
30517
+ if (emoji === "\u26A0\uFE0F" || emoji === "\u26A0") {
30518
+ return /* @__PURE__ */ jsx(Text, { color: "yellow", children: emoji }, `${lineIndex}-${partIndex}`);
30519
+ }
30520
+ if (emoji === "\u{1F4A1}" || emoji === "\u2139\uFE0F" || emoji === "\u{1F50D}") {
30521
+ return /* @__PURE__ */ jsx(Text, { color: "blue", children: emoji }, `${lineIndex}-${partIndex}`);
30522
+ }
30523
+ return /* @__PURE__ */ jsx(Text, { color: "white", children: emoji }, `${lineIndex}-${partIndex}`);
30524
+ }
30525
+ if (part.type === "metadata") {
30526
+ return /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: part.text }, `${lineIndex}-${partIndex}`);
30527
+ }
30528
+ return /* @__PURE__ */ jsx(Text, { color: "white", children: part.text }, `${lineIndex}-${partIndex}`);
30529
+ })
30530
+ ] }, lineIndex)) });
30531
+ }
30532
+ function parseInlineMarkdown(content) {
30533
+ if (content.match(/^#+\s*$/)) {
30534
+ return [];
30535
+ }
30536
+ const headerMatch = content.match(/^(#+)\s+(.*)$/);
30537
+ if (headerMatch) {
30538
+ const [, hashes, headerText] = headerMatch;
30539
+ return [{ type: "header", text: headerText.trim(), level: hashes.length }];
30540
+ }
30541
+ const parts = [];
30542
+ let current = "";
30543
+ let i = 0;
30544
+ while (i < content.length) {
30545
+ if (content[i] === "`" && i < content.length - 1) {
30546
+ if (current) {
30547
+ parts.push({ type: "text", text: current });
30548
+ current = "";
30549
+ }
30550
+ const closeIndex = content.indexOf("`", i + 1);
30551
+ if (closeIndex !== -1 && closeIndex > i + 1) {
30552
+ const codeText = content.substring(i + 1, closeIndex);
30553
+ parts.push({ type: "code", text: codeText });
30554
+ i = closeIndex + 1;
30555
+ continue;
30556
+ }
30557
+ }
30558
+ if (content.substr(i, 2) === "**") {
30559
+ if (current) {
30560
+ parts.push({ type: "text", text: current });
30561
+ current = "";
30562
+ }
30563
+ const closeIndex = content.indexOf("**", i + 2);
30564
+ if (closeIndex !== -1) {
30565
+ const boldText = content.substring(i + 2, closeIndex);
30566
+ parts.push({ type: "bold", text: boldText });
30567
+ i = closeIndex + 2;
30568
+ continue;
30569
+ }
30570
+ }
30571
+ if (content[i] === "_" && content[i + 1] !== "_") {
30572
+ if (current) {
30573
+ parts.push({ type: "text", text: current });
30574
+ current = "";
30575
+ }
30576
+ const closeIndex = content.indexOf("_", i + 1);
30577
+ if (closeIndex !== -1) {
30578
+ const italicText = content.substring(i + 1, closeIndex);
30579
+ parts.push({ type: "italic", text: italicText });
30580
+ i = closeIndex + 1;
30581
+ continue;
30582
+ }
30583
+ }
30584
+ const char = content[i];
30585
+ 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)) {
30586
+ if (current) {
30587
+ parts.push({ type: "text", text: current });
30588
+ current = "";
30589
+ }
30590
+ parts.push({ type: "emoji", text: char });
30591
+ i++;
30592
+ continue;
30593
+ }
30594
+ current += content[i];
30595
+ i++;
30596
+ }
30597
+ if (current) {
30598
+ 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)/g;
30599
+ const metadataPattern = /(\([^)]*(?:v\d+\.\d+|\d+k?[+]?\s*(?:files?|lines?|items?)|\d+\.\d+[xX]|dependencies?|scripts?|guides?|overview|project\s+docs?|source\s+code|detailed\s+setup|changelog|debugging|session\s+files?|build\s+artifacts)[^)]*\))/g;
30600
+ let lastIndex = 0;
30601
+ let match;
30602
+ let processedText = current;
30603
+ const tempParts = [];
30604
+ lastIndex = 0;
30605
+ while ((match = codePattern.exec(processedText)) !== null) {
30606
+ if (match.index > lastIndex) {
30607
+ tempParts.push({ type: "text", text: processedText.substring(lastIndex, match.index) });
30608
+ }
30609
+ tempParts.push({ type: "code", text: match[0] });
30610
+ lastIndex = match.index + match[0].length;
30611
+ }
30612
+ if (lastIndex < processedText.length) {
30613
+ tempParts.push({ type: "text", text: processedText.substring(lastIndex) });
30614
+ }
30615
+ const finalParts = [];
30616
+ for (const part of tempParts) {
30617
+ if (part.type === "text") {
30618
+ lastIndex = 0;
30619
+ metadataPattern.lastIndex = 0;
30620
+ while ((match = metadataPattern.exec(part.text)) !== null) {
30621
+ if (match.index > lastIndex) {
30622
+ finalParts.push({ type: "text", text: part.text.substring(lastIndex, match.index) });
30623
+ }
30624
+ finalParts.push({ type: "metadata", text: match[0] });
30625
+ lastIndex = match.index + match[0].length;
30626
+ }
30627
+ if (lastIndex < part.text.length) {
30628
+ finalParts.push({ type: "text", text: part.text.substring(lastIndex) });
30629
+ }
30630
+ if (finalParts.length === 0 || finalParts[finalParts.length - 1].text !== part.text) {
30631
+ if (finalParts.length === 0) {
30632
+ finalParts.push(part);
30633
+ }
30634
+ }
30635
+ } else {
30636
+ finalParts.push(part);
30637
+ }
30638
+ }
30639
+ if (finalParts.length === 0) {
30640
+ parts.push({ type: "text", text: current });
30641
+ } else {
30642
+ parts.push(...finalParts);
30643
+ }
30644
+ }
30645
+ return parts;
30646
+ }
30647
+ var init_markdown_renderer = __esm({
30648
+ "src/ui/utils/markdown-renderer.tsx"() {
30649
+ }
30650
+ });
30451
30651
  function AssistantMessageEntry({ entry, verbosityLevel: _verbosityLevel }) {
30452
30652
  const { content: processedContent, isTruncated } = handleLongContent(entry.content);
30453
30653
  return /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsxs(Box, { flexDirection: "row", alignItems: "flex-start", children: [
30454
30654
  /* @__PURE__ */ jsx(Text, { color: inkColors.text, children: "\u23FA " }),
30455
30655
  /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: "100%", children: [
30456
- entry.toolCalls ? (
30457
- // If there are tool calls, just show plain text
30458
- /* @__PURE__ */ jsx(Text, { color: inkColors.text, wrap: "wrap", dimColor: false, children: processedContent.trim() })
30459
- ) : (
30460
- // Use bright white text like Claude Code - explicit hex color to override any defaults
30461
- /* @__PURE__ */ jsx(Text, { color: inkColors.text, wrap: "wrap", dimColor: false, children: processedContent.trim() })
30462
- ),
30656
+ /* @__PURE__ */ jsx(MarkdownRenderer, { content: processedContent.trim() }),
30463
30657
  entry.isStreaming && /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u2588" }),
30464
30658
  isTruncated && /* @__PURE__ */ jsx(Text, { color: "yellow", italic: true, children: "[Response truncated for performance - full content in session log]" })
30465
30659
  ] })
@@ -30468,6 +30662,7 @@ function AssistantMessageEntry({ entry, verbosityLevel: _verbosityLevel }) {
30468
30662
  var handleLongContent;
30469
30663
  var init_assistant_message_entry = __esm({
30470
30664
  "src/ui/components/chat-entries/assistant-message-entry.tsx"() {
30665
+ init_markdown_renderer();
30471
30666
  init_colors();
30472
30667
  handleLongContent = (content, maxLength = 5e3) => {
30473
30668
  if (content.length <= maxLength) {
@@ -30719,7 +30914,223 @@ var init_file_content_renderer = __esm({
30719
30914
  "src/ui/components/content-renderers/file-content-renderer.tsx"() {
30720
30915
  }
30721
30916
  });
30917
+
30918
+ // src/services/tool-brevity-service.ts
30919
+ var ToolBrevityService;
30920
+ var init_tool_brevity_service = __esm({
30921
+ "src/services/tool-brevity-service.ts"() {
30922
+ ToolBrevityService = class {
30923
+ /**
30924
+ * Format tool result based on brevity mode
30925
+ */
30926
+ static formatToolResult(toolName, result, mode = "normal") {
30927
+ const normalizedToolName = this.normalizeToolName(toolName);
30928
+ const metadata = this.extractMetadata(normalizedToolName, result);
30929
+ const summary = this.generateSummary(normalizedToolName, result, metadata);
30930
+ return {
30931
+ toolName: normalizedToolName,
30932
+ summary,
30933
+ expansionHint: result.length > 0 ? "(ctrl+r to expand)" : "",
30934
+ hasContent: result.length > 0,
30935
+ originalContent: result,
30936
+ metadata
30937
+ };
30938
+ }
30939
+ /**
30940
+ * Normalize tool names to handle MCP and special cases
30941
+ */
30942
+ static normalizeToolName(toolName) {
30943
+ if (toolName.startsWith("mcp__")) {
30944
+ const parts = toolName.split("__");
30945
+ if (parts.length >= 3) {
30946
+ return parts[2];
30947
+ }
30948
+ }
30949
+ const toolMappings = {
30950
+ "str_replace_editor": "Edit",
30951
+ "bash": "Bash",
30952
+ "file_editor": "Edit",
30953
+ "grep": "Grep",
30954
+ "file_search": "Search",
30955
+ "list_files": "List",
30956
+ "read_file": "Read",
30957
+ "write_file": "Write"
30958
+ };
30959
+ return toolMappings[toolName] || this.capitalizeFirst(toolName);
30960
+ }
30961
+ /**
30962
+ * Extract metadata from tool result content
30963
+ */
30964
+ static extractMetadata(toolName, content) {
30965
+ const metadata = {};
30966
+ switch (toolName.toLowerCase()) {
30967
+ case "read":
30968
+ case "edit":
30969
+ case "write":
30970
+ metadata.lineCount = this.countLines(content);
30971
+ break;
30972
+ case "grep":
30973
+ case "search":
30974
+ const { matchCount, fileCount } = this.parseGrepResults(content);
30975
+ metadata.matchCount = matchCount;
30976
+ metadata.fileCount = fileCount;
30977
+ break;
30978
+ case "list":
30979
+ metadata.fileCount = this.countFileItems(content);
30980
+ break;
30981
+ case "bash":
30982
+ metadata.status = this.determineBashStatus(content);
30983
+ break;
30984
+ default:
30985
+ metadata.lineCount = this.countLines(content);
30986
+ }
30987
+ return metadata;
30988
+ }
30989
+ /**
30990
+ * Generate tool-specific summary text
30991
+ */
30992
+ static generateSummary(toolName, content, metadata) {
30993
+ const tool = toolName.toLowerCase();
30994
+ if (!content || content.trim().length === 0) {
30995
+ return `${this.capitalizeFirst(tool)} (no output)`;
30996
+ }
30997
+ switch (tool) {
30998
+ case "read":
30999
+ return `Read ${metadata.lineCount || 0} lines`;
31000
+ case "edit":
31001
+ return `Updated ${this.getFileName(content)} with ${metadata.lineCount || 0} lines`;
31002
+ case "write":
31003
+ return `Created file (${metadata.lineCount || 0} lines)`;
31004
+ case "grep":
31005
+ case "search":
31006
+ if (metadata.matchCount === 0) {
31007
+ return "No matches found";
31008
+ }
31009
+ return `${metadata.matchCount} matches across ${metadata.fileCount || 1} files`;
31010
+ case "list":
31011
+ return `Found ${metadata.fileCount || 0} items`;
31012
+ case "bash":
31013
+ if (metadata.status === "error") {
31014
+ return "Command failed";
31015
+ }
31016
+ return "Command completed successfully";
31017
+ case "glob":
31018
+ return `Found ${this.countFileItems(content)} files`;
31019
+ case "webfetch":
31020
+ return `Fetched content (${metadata.lineCount || 0} lines)`;
31021
+ case "websearch":
31022
+ return `Search completed (${this.countSearchResults(content)} results)`;
31023
+ default:
31024
+ const lines = metadata.lineCount || 0;
31025
+ return lines > 0 ? `${this.capitalizeFirst(tool)} (${lines} lines)` : this.capitalizeFirst(tool);
31026
+ }
31027
+ }
31028
+ /**
31029
+ * Count lines in content
31030
+ */
31031
+ static countLines(content) {
31032
+ if (!content) return 0;
31033
+ return content.split("\n").length;
31034
+ }
31035
+ /**
31036
+ * Parse grep/search results for match and file counts
31037
+ */
31038
+ static parseGrepResults(content) {
31039
+ if (!content) return { matchCount: 0, fileCount: 0 };
31040
+ const lines = content.split("\n").filter((line) => line.trim().length > 0);
31041
+ const files = /* @__PURE__ */ new Set();
31042
+ let matches = 0;
31043
+ for (const line of lines) {
31044
+ const fileMatch = line.match(/^([^:]+):/);
31045
+ if (fileMatch) {
31046
+ files.add(fileMatch[1]);
31047
+ matches++;
31048
+ } else if (line.includes(":")) {
31049
+ matches++;
31050
+ }
31051
+ }
31052
+ return {
31053
+ matchCount: matches || lines.length,
31054
+ fileCount: files.size || (matches > 0 ? 1 : 0)
31055
+ };
31056
+ }
31057
+ /**
31058
+ * Count file items in directory listing
31059
+ */
31060
+ static countFileItems(content) {
31061
+ if (!content) return 0;
31062
+ 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*$/));
31063
+ return lines.length;
31064
+ }
31065
+ /**
31066
+ * Determine bash command success/failure status
31067
+ */
31068
+ static determineBashStatus(content) {
31069
+ if (!content) return "success";
31070
+ const errorIndicators = [
31071
+ "error:",
31072
+ "Error:",
31073
+ "ERROR:",
31074
+ "failed",
31075
+ "Failed",
31076
+ "FAILED",
31077
+ "permission denied",
31078
+ "command not found",
31079
+ "no such file",
31080
+ "cannot"
31081
+ ];
31082
+ const contentLower = content.toLowerCase();
31083
+ return errorIndicators.some((indicator) => contentLower.includes(indicator.toLowerCase())) ? "error" : "success";
31084
+ }
31085
+ /**
31086
+ * Extract filename from edit/write operation content
31087
+ */
31088
+ static getFileName(content) {
31089
+ const fileMatch = content.match(/(?:updated|edited|created)\s+([^\s]+)/i);
31090
+ if (fileMatch) return fileMatch[1];
31091
+ const pathMatch = content.match(/([^/]+)$/);
31092
+ return pathMatch ? pathMatch[1] : "file";
31093
+ }
31094
+ /**
31095
+ * Count search results in web search content
31096
+ */
31097
+ static countSearchResults(content) {
31098
+ const resultMatches = content.match(/result\s+\d+/gi);
31099
+ return resultMatches ? resultMatches.length : 1;
31100
+ }
31101
+ /**
31102
+ * Capitalize first letter of string
31103
+ */
31104
+ static capitalizeFirst(str) {
31105
+ return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
31106
+ }
31107
+ /**
31108
+ * Check if content should use compact display
31109
+ */
31110
+ static shouldUseCompactDisplay(mode, contentLength) {
31111
+ if (mode === "brief") return true;
31112
+ if (mode === "verbose") return false;
31113
+ const lineCount = contentLength > 0 ? contentLength.toString().split("\n").length : 0;
31114
+ return lineCount > 5;
31115
+ }
31116
+ /**
31117
+ * Format expansion hint with content preview
31118
+ */
31119
+ static formatExpansionHint(hasContent, metadata) {
31120
+ if (!hasContent) return "";
31121
+ if (metadata.lineCount && metadata.lineCount > 10) {
31122
+ return `(${metadata.lineCount} lines, ctrl+r to expand)`;
31123
+ }
31124
+ if (metadata.matchCount && metadata.matchCount > 5) {
31125
+ return `(${metadata.matchCount} matches, ctrl+r to expand)`;
31126
+ }
31127
+ return "(ctrl+r to expand)";
31128
+ }
31129
+ };
31130
+ }
31131
+ });
30722
31132
  function ToolCallEntry({ entry, verbosityLevel, explainLevel }) {
31133
+ const [isExpanded, setIsExpanded] = useState(false);
30723
31134
  const getExplanation = (toolName2, filePath2, _isExecuting) => {
30724
31135
  if (explainLevel === "off") return null;
30725
31136
  const explanations = {
@@ -30748,6 +31159,19 @@ function ToolCallEntry({ entry, verbosityLevel, explainLevel }) {
30748
31159
  if (!explanation2) return null;
30749
31160
  return explainLevel === "detailed" ? explanation2.detailed : explanation2.brief;
30750
31161
  };
31162
+ const truncateToClaudeStyle = (content) => {
31163
+ const lines = content.split("\n");
31164
+ const maxLines = 3;
31165
+ if (lines.length <= maxLines) {
31166
+ return { preview: content, hasMore: false, totalLines: lines.length };
31167
+ }
31168
+ const preview2 = lines.slice(0, maxLines).join("\n");
31169
+ return {
31170
+ preview: preview2,
31171
+ hasMore: true,
31172
+ totalLines: lines.length
31173
+ };
31174
+ };
30751
31175
  const getToolActionName = (toolName2) => {
30752
31176
  if (toolName2.startsWith("mcp__")) {
30753
31177
  const parts = toolName2.split("__");
@@ -30814,7 +31238,15 @@ function ToolCallEntry({ entry, verbosityLevel, explainLevel }) {
30814
31238
  const shouldShowFileContent = (entry.toolCall?.function?.name === "view_file" || entry.toolCall?.function?.name === "create_file") && entry.toolResult?.success && !shouldShowDiff;
30815
31239
  const shouldShowToolContent = verbosityLevel !== "quiet";
30816
31240
  const shouldShowFullContent = verbosityLevel === "normal" || verbosityLevel === "verbose";
31241
+ const brevityMode = verbosityLevel === "quiet" ? "brief" : verbosityLevel === "verbose" ? "verbose" : "normal";
31242
+ const brevitySummary = ToolBrevityService.formatToolResult(
31243
+ toolName,
31244
+ entry.content || "",
31245
+ brevityMode
31246
+ );
30817
31247
  const explanation = getExplanation(toolName, filePath);
31248
+ const { preview, hasMore, totalLines } = truncateToClaudeStyle(entry.content || "");
31249
+ const useClaudeCodeFormat = verbosityLevel === "quiet" && brevitySummary.hasContent;
30818
31250
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
30819
31251
  /* @__PURE__ */ jsxs(Box, { children: [
30820
31252
  /* @__PURE__ */ jsx(Text, { color: "magenta", children: "\u23FA" }),
@@ -30823,24 +31255,55 @@ function ToolCallEntry({ entry, verbosityLevel, explainLevel }) {
30823
31255
  filePath ? `${actionName}(${filePath})` : actionName
30824
31256
  ] })
30825
31257
  ] }),
30826
- explanation && /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsxs(Text, { color: "blue", italic: true, children: [
31258
+ explanation && !useClaudeCodeFormat && /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsxs(Text, { color: "blue", italic: true, children: [
30827
31259
  "\u{1F4A1} ",
30828
31260
  explanation
30829
31261
  ] }) }),
30830
- shouldShowToolContent && /* @__PURE__ */ jsx(Box, { marginLeft: 2, flexDirection: "column", children: isExecuting ? /* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u23BF Executing..." }) : shouldShowFileContent && shouldShowFullContent ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
31262
+ useClaudeCodeFormat ? (
31263
+ // Claude Code style: ultra-brief format
31264
+ /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
31265
+ "\u23BF ",
31266
+ brevitySummary.summary,
31267
+ " ",
31268
+ brevitySummary.expansionHint
31269
+ ] }) })
31270
+ ) : 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: [
31271
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
31272
+ "\u23BF ",
31273
+ preview
31274
+ ] }),
31275
+ hasMore && /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
31276
+ "\u2026 +",
31277
+ totalLines - 3,
31278
+ " lines (ctrl+r to expand)"
31279
+ ] })
31280
+ ] }) : /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
30831
31281
  /* @__PURE__ */ jsx(Text, { color: "gray", children: "\u23BF File contents:" }),
30832
31282
  /* @__PURE__ */ jsx(Box, { marginLeft: 2, flexDirection: "column", children: /* @__PURE__ */ jsx(FileContentRenderer, { content: entry.content }) })
30833
- ] }) : shouldShowDiff && shouldShowFullContent ? (
31283
+ ] }) }) : shouldShowDiff && shouldShowFullContent ? (
30834
31284
  // For diff results, show only the summary line, not the raw content
30835
31285
  /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
30836
31286
  "\u23BF ",
30837
31287
  entry.content.split("\n")[0]
30838
31288
  ] })
30839
- ) : !shouldShowFullContent ? /* @__PURE__ */ jsx(Text, { color: "gray", children: "\u23BF Completed" }) : /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
31289
+ ) : !shouldShowFullContent ? /* @__PURE__ */ jsx(Text, { color: "gray", children: "\u23BF Completed" }) : !isExpanded && hasMore ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
31290
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
31291
+ "\u23BF ",
31292
+ preview
31293
+ ] }),
31294
+ /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
31295
+ "\u2026 +",
31296
+ totalLines - 3,
31297
+ " lines (ctrl+r to expand)"
31298
+ ] })
31299
+ ] }) : !isExpanded ? /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
31300
+ "\u23BF ",
31301
+ preview
31302
+ ] }) : /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
30840
31303
  "\u23BF ",
30841
31304
  formatToolContent(entry.content, toolName)
30842
31305
  ] }) }),
30843
- shouldShowDiff && !isExecuting && shouldShowFullContent && /* @__PURE__ */ jsx(Box, { marginLeft: 4, flexDirection: "column", children: /* @__PURE__ */ jsx(
31306
+ shouldShowDiff && !isExecuting && shouldShowFullContent && !useClaudeCodeFormat && /* @__PURE__ */ jsx(Box, { marginLeft: 4, flexDirection: "column", children: /* @__PURE__ */ jsx(
30844
31307
  DiffRenderer,
30845
31308
  {
30846
31309
  diffContent: entry.content,
@@ -30855,6 +31318,7 @@ var init_tool_call_entry = __esm({
30855
31318
  "src/ui/components/chat-entries/tool-call-entry.tsx"() {
30856
31319
  init_diff_renderer();
30857
31320
  init_file_content_renderer();
31321
+ init_tool_brevity_service();
30858
31322
  truncateContent2 = (content, maxLength = 100) => {
30859
31323
  if (process.env.COMPACT !== "1") return content;
30860
31324
  return content.length > maxLength ? content.substring(0, maxLength) + "..." : content;
@@ -31154,31 +31618,64 @@ function ChatInput({
31154
31618
  isProcessing,
31155
31619
  isStreaming
31156
31620
  }) {
31157
- const beforeCursor = input.slice(0, cursorPosition);
31158
- const lines = input.split(/\r\n|\r|\n/);
31159
- const isMultiline = lines.length > 1;
31160
- const MAX_DISPLAY_LINES = 10;
31161
- const shouldTruncateDisplay = lines.length > MAX_DISPLAY_LINES;
31162
- if (shouldTruncateDisplay) {
31163
- console.log(`\u{1F4C4} Large paste detected: ${lines.length} lines, showing truncated view`);
31164
- }
31165
- let currentLineIndex = 0;
31166
- let currentCharIndex = 0;
31167
- let totalChars = 0;
31168
- for (let i = 0; i < lines.length; i++) {
31169
- if (totalChars + lines[i].length >= cursorPosition) {
31170
- currentLineIndex = i;
31171
- currentCharIndex = cursorPosition - totalChars;
31172
- break;
31621
+ try {
31622
+ let displayInput = input;
31623
+ const beforeCursor = displayInput.slice(0, Math.min(cursorPosition, displayInput.length));
31624
+ const lines = displayInput.split(/\r\n|\r|\n/);
31625
+ const isMultiline = lines.length > 1;
31626
+ const MAX_DISPLAY_LINES = 10;
31627
+ const shouldTruncateDisplay = lines.length > MAX_DISPLAY_LINES;
31628
+ if (shouldTruncateDisplay) {
31629
+ console.log(`\u{1F4C4} Large content: ${lines.length} lines, showing truncated view`);
31173
31630
  }
31174
- totalChars += lines[i].length + 1;
31175
- }
31176
- const showCursor = !isProcessing && !isStreaming;
31177
- const borderColor = isProcessing || isStreaming ? "yellow" : "blue";
31178
- const promptColor = "cyan";
31179
- const placeholderText = "Ask me anything...";
31180
- const isPlaceholder = !input;
31181
- if (isMultiline) {
31631
+ let currentLineIndex = 0;
31632
+ let currentCharIndex = 0;
31633
+ let totalChars = 0;
31634
+ for (let i = 0; i < lines.length; i++) {
31635
+ if (totalChars + lines[i].length >= cursorPosition) {
31636
+ currentLineIndex = i;
31637
+ currentCharIndex = cursorPosition - totalChars;
31638
+ break;
31639
+ }
31640
+ totalChars += lines[i].length + 1;
31641
+ }
31642
+ const showCursor = !isProcessing && !isStreaming;
31643
+ const borderColor = isProcessing || isStreaming ? "yellow" : "blue";
31644
+ const promptColor = "cyan";
31645
+ const placeholderText = "Ask me anything...";
31646
+ const isPlaceholder = !input;
31647
+ if (isMultiline) {
31648
+ return /* @__PURE__ */ jsx(
31649
+ Box,
31650
+ {
31651
+ borderStyle: "round",
31652
+ borderColor,
31653
+ paddingX: 1,
31654
+ paddingY: 0,
31655
+ marginTop: 1,
31656
+ flexDirection: "column",
31657
+ children: /* @__PURE__ */ jsx(Text, { children: shouldTruncateDisplay ? (
31658
+ // Show Claude Code style paste summary but don't replace input
31659
+ `\u276F [Pasted text #${globalThis.grokPasteCounter || 1} +${lines.length} lines]`
31660
+ ) : (
31661
+ // Normal multiline display for reasonable sizes
31662
+ lines.map((line, index) => {
31663
+ const isCurrentLine = index === currentLineIndex;
31664
+ const promptChar = index === 0 ? "\u276F " : " ";
31665
+ let lineText = promptChar + line;
31666
+ if (isCurrentLine && showCursor) {
31667
+ const cursorPos = promptChar.length + currentCharIndex;
31668
+ lineText = lineText.slice(0, cursorPos) + "\u2588" + lineText.slice(cursorPos + 1);
31669
+ }
31670
+ return index === lines.length - 1 ? lineText : lineText + "\n";
31671
+ }).join("")
31672
+ ) })
31673
+ }
31674
+ );
31675
+ }
31676
+ const adjustedCursorPos = Math.min(cursorPosition, displayInput.length);
31677
+ const cursorChar = displayInput.slice(adjustedCursorPos, adjustedCursorPos + 1) || " ";
31678
+ const afterCursorText = displayInput.slice(adjustedCursorPos + 1);
31182
31679
  return /* @__PURE__ */ jsx(
31183
31680
  Box,
31184
31681
  {
@@ -31187,57 +31684,36 @@ function ChatInput({
31187
31684
  paddingX: 1,
31188
31685
  paddingY: 0,
31189
31686
  marginTop: 1,
31190
- flexDirection: "column",
31191
- children: /* @__PURE__ */ jsx(Text, { children: shouldTruncateDisplay ? (
31192
- // Show truncated view for very large pastes
31193
- `\u276F [Large paste: ${lines.length} lines, ${input.length} chars]
31194
- First few lines:
31195
- ${lines.slice(0, 3).map((line) => ` ${line}`).join("\n")}
31196
- ...
31197
- Last few lines:
31198
- ${lines.slice(-2).map((line) => ` ${line}`).join("\n")}
31199
-
31200
- Press Enter to submit or edit to modify.`
31201
- ) : (
31202
- // Normal multiline display for reasonable sizes
31203
- lines.map((line, index) => {
31204
- const isCurrentLine = index === currentLineIndex;
31205
- const promptChar = index === 0 ? "\u276F " : " ";
31206
- let lineText = promptChar + line;
31207
- if (isCurrentLine && showCursor) {
31208
- const cursorPos = promptChar.length + currentCharIndex;
31209
- lineText = lineText.slice(0, cursorPos) + "\u2588" + lineText.slice(cursorPos + 1);
31210
- }
31211
- return index === lines.length - 1 ? lineText : lineText + "\n";
31212
- }).join("")
31213
- ) })
31687
+ children: /* @__PURE__ */ jsxs(Box, { children: [
31688
+ /* @__PURE__ */ jsx(Text, { color: promptColor, children: "\u276F " }),
31689
+ isPlaceholder ? /* @__PURE__ */ jsxs(Fragment, { children: [
31690
+ /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: placeholderText }),
31691
+ showCursor && /* @__PURE__ */ jsx(Text, { backgroundColor: "white", color: "black", children: " " })
31692
+ ] }) : /* @__PURE__ */ jsxs(Text, { children: [
31693
+ beforeCursor,
31694
+ showCursor && /* @__PURE__ */ jsx(Text, { backgroundColor: "white", color: "black", children: cursorChar }),
31695
+ !showCursor && cursorChar !== " " && cursorChar,
31696
+ afterCursorText
31697
+ ] })
31698
+ ] })
31699
+ }
31700
+ );
31701
+ } catch (error) {
31702
+ console.error("[ERROR] ChatInput component crashed:", error);
31703
+ console.error("[ERROR] Stack:", error instanceof Error ? error.stack : "No stack");
31704
+ console.error("[ERROR] Input data:", { input: input?.slice(0, 100), cursorPosition, isProcessing, isStreaming });
31705
+ return /* @__PURE__ */ jsx(
31706
+ Box,
31707
+ {
31708
+ borderStyle: "round",
31709
+ borderColor: "red",
31710
+ paddingX: 1,
31711
+ paddingY: 0,
31712
+ marginTop: 1,
31713
+ children: /* @__PURE__ */ jsx(Text, { color: "red", children: "\u276F [Input error - check console]" })
31214
31714
  }
31215
31715
  );
31216
31716
  }
31217
- const cursorChar = input.slice(cursorPosition, cursorPosition + 1) || " ";
31218
- const afterCursorText = input.slice(cursorPosition + 1);
31219
- return /* @__PURE__ */ jsx(
31220
- Box,
31221
- {
31222
- borderStyle: "round",
31223
- borderColor,
31224
- paddingX: 1,
31225
- paddingY: 0,
31226
- marginTop: 1,
31227
- children: /* @__PURE__ */ jsxs(Box, { children: [
31228
- /* @__PURE__ */ jsx(Text, { color: promptColor, children: "\u276F " }),
31229
- isPlaceholder ? /* @__PURE__ */ jsxs(Fragment, { children: [
31230
- /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: placeholderText }),
31231
- showCursor && /* @__PURE__ */ jsx(Text, { backgroundColor: "white", color: "black", children: " " })
31232
- ] }) : /* @__PURE__ */ jsxs(Text, { children: [
31233
- beforeCursor,
31234
- showCursor && /* @__PURE__ */ jsx(Text, { backgroundColor: "white", color: "black", children: cursorChar }),
31235
- !showCursor && cursorChar !== " " && cursorChar,
31236
- afterCursorText
31237
- ] })
31238
- ] })
31239
- }
31240
- );
31241
31717
  }
31242
31718
  var init_chat_input = __esm({
31243
31719
  "src/ui/components/chat-input.tsx"() {
@@ -31864,6 +32340,85 @@ var init_chat_interface_renderer = __esm({
31864
32340
  init_confirmation_dialog();
31865
32341
  }
31866
32342
  });
32343
+ function getSessionLogger() {
32344
+ if (!sessionLogger) {
32345
+ sessionLogger = new SessionLogger();
32346
+ }
32347
+ return sessionLogger;
32348
+ }
32349
+ function logTerminalState(state) {
32350
+ getSessionLogger().logTerminalState(state);
32351
+ }
32352
+ var SessionLogger, sessionLogger;
32353
+ var init_session_logger = __esm({
32354
+ "src/utils/session-logger.ts"() {
32355
+ SessionLogger = class {
32356
+ constructor() {
32357
+ this.sessionId = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
32358
+ this.logPath = path8__default.join(process.cwd(), `session-${this.sessionId}.log`);
32359
+ this.init();
32360
+ }
32361
+ init() {
32362
+ const header = `
32363
+ =================================================================
32364
+ \u{1F9EA} GROK ONE-SHOT TESTING SESSION
32365
+ Session ID: ${this.sessionId}
32366
+ Started: ${(/* @__PURE__ */ new Date()).toISOString()}
32367
+ =================================================================
32368
+
32369
+ `;
32370
+ fs7__default.writeFileSync(this.logPath, header);
32371
+ }
32372
+ logTerminalState(state) {
32373
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
32374
+ const entry = `
32375
+ [${timestamp}] \u{1F4FA} TERMINAL STATE - ${state.action}
32376
+ =====================================
32377
+ INPUT FIELD: "${state.input}"
32378
+ CURSOR POS: ${state.cursorPosition}
32379
+ PROCESSING: ${state.isProcessing}
32380
+ STREAMING: ${state.isStreaming}
32381
+ CHAT ENTRIES: ${state.chatHistory.length}
32382
+ LAST ENTRY: ${state.chatHistory.length > 0 ? JSON.stringify(state.chatHistory[state.chatHistory.length - 1], null, 2) : "None"}
32383
+ =====================================
32384
+
32385
+ `;
32386
+ fs7__default.appendFileSync(this.logPath, entry);
32387
+ }
32388
+ logUserAction(action, details = {}) {
32389
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
32390
+ const entry = `[${timestamp}] \u{1F464} USER ACTION: ${action}
32391
+ Details: ${JSON.stringify(details, null, 2)}
32392
+
32393
+ `;
32394
+ fs7__default.appendFileSync(this.logPath, entry);
32395
+ }
32396
+ logPasteEvent(event) {
32397
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
32398
+ const entry = `[${timestamp}] \u{1F4CB} PASTE EVENT: ${event.phase}
32399
+ Data: ${JSON.stringify(event.data, null, 2)}
32400
+
32401
+ `;
32402
+ fs7__default.appendFileSync(this.logPath, entry);
32403
+ }
32404
+ logTestResult(testName, result, details) {
32405
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
32406
+ const entry = `
32407
+ [${timestamp}] \u2705 TEST RESULT: ${testName}
32408
+ Result: ${result}
32409
+ Details: ${details}
32410
+ =================================================================
32411
+
32412
+ `;
32413
+ fs7__default.appendFileSync(this.logPath, entry);
32414
+ }
32415
+ getLogPath() {
32416
+ return this.logPath;
32417
+ }
32418
+ };
32419
+ sessionLogger = null;
32420
+ }
32421
+ });
31867
32422
 
31868
32423
  // src/ui/components/chat-interface.tsx
31869
32424
  var chat_interface_exports = {};
@@ -31928,6 +32483,16 @@ function ChatInterfaceWithAgent({
31928
32483
  explainLevel,
31929
32484
  planMode
31930
32485
  } = useInputHandler(inputHandlerProps);
32486
+ useEffect(() => {
32487
+ logTerminalState({
32488
+ input,
32489
+ cursorPosition,
32490
+ chatHistory,
32491
+ isProcessing,
32492
+ isStreaming,
32493
+ action: "STATE_CHANGE"
32494
+ });
32495
+ }, [input, cursorPosition, chatHistory.length, isProcessing, isStreaming]);
31931
32496
  useStreaming(agent, initialMessage, setChatHistory, {
31932
32497
  setIsProcessing,
31933
32498
  setIsStreaming,
@@ -32014,6 +32579,29 @@ var init_chat_interface = __esm({
32014
32579
  init_use_session_logging();
32015
32580
  init_use_processing_timer();
32016
32581
  init_chat_interface_renderer();
32582
+ init_session_logger();
32583
+ }
32584
+ });
32585
+
32586
+ // src/utils/console-markdown.ts
32587
+ var console_markdown_exports = {};
32588
+ __export(console_markdown_exports, {
32589
+ renderMarkdownToConsole: () => renderMarkdownToConsole
32590
+ });
32591
+ function renderMarkdownToConsole(content) {
32592
+ let result = content;
32593
+ result = result.replace(/^#+\s+(.*)$/gm, (_, text) => chalk2.bold.white(text));
32594
+ result = result.replace(/\*\*(.*?)\*\*/g, (_, text) => chalk2.bold.white(text));
32595
+ result = result.replace(/_(.*?)_/g, (_, text) => chalk2.italic.gray(text));
32596
+ result = result.replace(/`([^`]+)`/g, (_, text) => chalk2.cyan(text));
32597
+ result = result.replace(/(✅|✓)/g, (match) => chalk2.green(match));
32598
+ result = result.replace(/(❌|✗)/g, (match) => chalk2.red(match));
32599
+ result = result.replace(/(⚠️|⚠)/g, (match) => chalk2.yellow(match));
32600
+ result = result.replace(/(ℹ️|💡|🔍)/g, (match) => chalk2.blue(match));
32601
+ return result;
32602
+ }
32603
+ var init_console_markdown = __esm({
32604
+ "src/utils/console-markdown.ts"() {
32017
32605
  }
32018
32606
  });
32019
32607
 
@@ -32030,27 +32618,27 @@ function createMCPCommand() {
32030
32618
  if (PREDEFINED_SERVERS[name]) {
32031
32619
  const config3 = PREDEFINED_SERVERS[name];
32032
32620
  addMCPServer(config3);
32033
- console.log(chalk.green(`\u2713 Added predefined MCP server: ${name}`));
32621
+ console.log(chalk2.green(`\u2713 Added predefined MCP server: ${name}`));
32034
32622
  const manager2 = getMCPManager();
32035
32623
  await manager2.addServer(config3);
32036
- console.log(chalk.green(`\u2713 Connected to MCP server: ${name}`));
32624
+ console.log(chalk2.green(`\u2713 Connected to MCP server: ${name}`));
32037
32625
  const tools2 = manager2.getTools().filter((t) => t.serverName === name);
32038
- console.log(chalk.blue(` Available tools: ${tools2.length}`));
32626
+ console.log(chalk2.blue(` Available tools: ${tools2.length}`));
32039
32627
  return;
32040
32628
  }
32041
32629
  const transportType = options.transport.toLowerCase();
32042
32630
  if (transportType === "stdio") {
32043
32631
  if (!options.command) {
32044
- console.error(chalk.red("Error: --command is required for stdio transport"));
32632
+ console.error(chalk2.red("Error: --command is required for stdio transport"));
32045
32633
  process.exit(1);
32046
32634
  }
32047
32635
  } else if (transportType === "http" || transportType === "sse" || transportType === "streamable_http") {
32048
32636
  if (!options.url) {
32049
- console.error(chalk.red(`Error: --url is required for ${transportType} transport`));
32637
+ console.error(chalk2.red(`Error: --url is required for ${transportType} transport`));
32050
32638
  process.exit(1);
32051
32639
  }
32052
32640
  } else {
32053
- console.error(chalk.red("Error: Transport type must be stdio, http, sse, or streamable_http"));
32641
+ console.error(chalk2.red("Error: Transport type must be stdio, http, sse, or streamable_http"));
32054
32642
  process.exit(1);
32055
32643
  }
32056
32644
  const env = {};
@@ -32079,14 +32667,14 @@ function createMCPCommand() {
32079
32667
  }
32080
32668
  };
32081
32669
  addMCPServer(config2);
32082
- console.log(chalk.green(`\u2713 Added MCP server: ${name}`));
32670
+ console.log(chalk2.green(`\u2713 Added MCP server: ${name}`));
32083
32671
  const manager = getMCPManager();
32084
32672
  await manager.addServer(config2);
32085
- console.log(chalk.green(`\u2713 Connected to MCP server: ${name}`));
32673
+ console.log(chalk2.green(`\u2713 Connected to MCP server: ${name}`));
32086
32674
  const tools = manager.getTools().filter((t) => t.serverName === name);
32087
- console.log(chalk.blue(` Available tools: ${tools.length}`));
32675
+ console.log(chalk2.blue(` Available tools: ${tools.length}`));
32088
32676
  } catch (error) {
32089
- console.error(chalk.red(`Error adding MCP server: ${error.message}`));
32677
+ console.error(chalk2.red(`Error adding MCP server: ${error.message}`));
32090
32678
  process.exit(1);
32091
32679
  }
32092
32680
  });
@@ -32096,7 +32684,7 @@ function createMCPCommand() {
32096
32684
  try {
32097
32685
  config2 = JSON.parse(jsonConfig);
32098
32686
  } catch {
32099
- console.error(chalk.red("Error: Invalid JSON configuration"));
32687
+ console.error(chalk2.red("Error: Invalid JSON configuration"));
32100
32688
  process.exit(1);
32101
32689
  }
32102
32690
  const serverConfig = {
@@ -32119,14 +32707,14 @@ function createMCPCommand() {
32119
32707
  }
32120
32708
  }
32121
32709
  addMCPServer(serverConfig);
32122
- console.log(chalk.green(`\u2713 Added MCP server: ${name}`));
32710
+ console.log(chalk2.green(`\u2713 Added MCP server: ${name}`));
32123
32711
  const manager = getMCPManager();
32124
32712
  await manager.addServer(serverConfig);
32125
- console.log(chalk.green(`\u2713 Connected to MCP server: ${name}`));
32713
+ console.log(chalk2.green(`\u2713 Connected to MCP server: ${name}`));
32126
32714
  const tools = manager.getTools().filter((t) => t.serverName === name);
32127
- console.log(chalk.blue(` Available tools: ${tools.length}`));
32715
+ console.log(chalk2.blue(` Available tools: ${tools.length}`));
32128
32716
  } catch (error) {
32129
- console.error(chalk.red(`Error adding MCP server: ${error.message}`));
32717
+ console.error(chalk2.red(`Error adding MCP server: ${error.message}`));
32130
32718
  process.exit(1);
32131
32719
  }
32132
32720
  });
@@ -32135,9 +32723,9 @@ function createMCPCommand() {
32135
32723
  const manager = getMCPManager();
32136
32724
  await manager.removeServer(name);
32137
32725
  removeMCPServer(name);
32138
- console.log(chalk.green(`\u2713 Removed MCP server: ${name}`));
32726
+ console.log(chalk2.green(`\u2713 Removed MCP server: ${name}`));
32139
32727
  } catch (error) {
32140
- console.error(chalk.red(`Error removing MCP server: ${error.message}`));
32728
+ console.error(chalk2.red(`Error removing MCP server: ${error.message}`));
32141
32729
  process.exit(1);
32142
32730
  }
32143
32731
  });
@@ -32145,15 +32733,15 @@ function createMCPCommand() {
32145
32733
  const config2 = loadMCPConfig();
32146
32734
  const manager = getMCPManager();
32147
32735
  if (config2.servers.length === 0) {
32148
- console.log(chalk.yellow("No MCP servers configured"));
32736
+ console.log(chalk2.yellow("No MCP servers configured"));
32149
32737
  return;
32150
32738
  }
32151
- console.log(chalk.bold("Configured MCP servers:"));
32739
+ console.log(chalk2.bold("Configured MCP servers:"));
32152
32740
  console.log();
32153
32741
  for (const server of config2.servers) {
32154
32742
  const isConnected = manager.getServers().includes(server.name);
32155
- const status = isConnected ? chalk.green("\u2713 Connected") : chalk.red("\u2717 Disconnected");
32156
- console.log(`${chalk.bold(server.name)}: ${status}`);
32743
+ const status = isConnected ? chalk2.green("\u2713 Connected") : chalk2.red("\u2717 Disconnected");
32744
+ console.log(`${chalk2.bold(server.name)}: ${status}`);
32157
32745
  if (server.transport) {
32158
32746
  console.log(` Transport: ${server.transport.type}`);
32159
32747
  if (server.transport.type === "stdio") {
@@ -32186,15 +32774,15 @@ function createMCPCommand() {
32186
32774
  const config2 = loadMCPConfig();
32187
32775
  const serverConfig = config2.servers.find((s) => s.name === name);
32188
32776
  if (!serverConfig) {
32189
- console.error(chalk.red(`Server ${name} not found`));
32777
+ console.error(chalk2.red(`Server ${name} not found`));
32190
32778
  process.exit(1);
32191
32779
  }
32192
- console.log(chalk.blue(`Testing connection to ${name}...`));
32780
+ console.log(chalk2.blue(`Testing connection to ${name}...`));
32193
32781
  const manager = getMCPManager();
32194
32782
  await manager.addServer(serverConfig);
32195
32783
  const tools = manager.getTools().filter((t) => t.serverName === name);
32196
- console.log(chalk.green(`\u2713 Successfully connected to ${name}`));
32197
- console.log(chalk.blue(` Available tools: ${tools.length}`));
32784
+ console.log(chalk2.green(`\u2713 Successfully connected to ${name}`));
32785
+ console.log(chalk2.blue(` Available tools: ${tools.length}`));
32198
32786
  if (tools.length > 0) {
32199
32787
  console.log(" Tools:");
32200
32788
  tools.forEach((tool) => {
@@ -32203,7 +32791,7 @@ function createMCPCommand() {
32203
32791
  });
32204
32792
  }
32205
32793
  } catch (error) {
32206
- console.error(chalk.red(`\u2717 Failed to connect to ${name}: ${error.message}`));
32794
+ console.error(chalk2.red(`\u2717 Failed to connect to ${name}: ${error.message}`));
32207
32795
  process.exit(1);
32208
32796
  }
32209
32797
  });
@@ -32227,9 +32815,9 @@ function createSetNameCommand() {
32227
32815
  try {
32228
32816
  const settingsManager = getSettingsManager();
32229
32817
  settingsManager.updateUserSetting("assistantName", name);
32230
- console.log(chalk.green(`\u2705 Assistant name set to: ${name}`));
32818
+ console.log(chalk2.green(`\u2705 Assistant name set to: ${name}`));
32231
32819
  } catch (error) {
32232
- console.error(chalk.red(`\u274C Failed to set assistant name: ${error.message}`));
32820
+ console.error(chalk2.red(`\u274C Failed to set assistant name: ${error.message}`));
32233
32821
  process.exit(1);
32234
32822
  }
32235
32823
  });
@@ -32254,10 +32842,10 @@ function createToggleConfirmationsCommand() {
32254
32842
  const currentValue = settingsManager.getUserSetting("requireConfirmation") ?? true;
32255
32843
  const newValue = !currentValue;
32256
32844
  settingsManager.updateUserSetting("requireConfirmation", newValue);
32257
- console.log(chalk.green(`\u2705 Confirmation requirement ${newValue ? "enabled" : "disabled"}`));
32845
+ console.log(chalk2.green(`\u2705 Confirmation requirement ${newValue ? "enabled" : "disabled"}`));
32258
32846
  console.log(`File operations and bash commands will ${newValue ? "now" : "no longer"} require confirmation.`);
32259
32847
  } catch (error) {
32260
- console.error(chalk.red(`\u274C Failed to toggle confirmations: ${error.message}`));
32848
+ console.error(chalk2.red(`\u274C Failed to toggle confirmations: ${error.message}`));
32261
32849
  process.exit(1);
32262
32850
  }
32263
32851
  });
@@ -32275,7 +32863,7 @@ var require_package = __commonJS({
32275
32863
  module.exports = {
32276
32864
  type: "module",
32277
32865
  name: "@xagent/one-shot",
32278
- version: "1.2.0",
32866
+ version: "1.2.2",
32279
32867
  description: "An open-source AI agent that brings advanced AI capabilities directly into your terminal with automatic documentation updates.",
32280
32868
  main: "dist/index.js",
32281
32869
  module: "dist/index.js",
@@ -32460,6 +33048,7 @@ try {
32460
33048
  const { printWelcomeBanner: printWelcomeBanner2 } = await Promise.resolve().then(() => (init_use_console_setup(), use_console_setup_exports));
32461
33049
  const { getSettingsManager: getSettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), settings_manager_exports));
32462
33050
  const { ConfirmationService: ConfirmationService2 } = await Promise.resolve().then(() => (init_confirmation_service(), confirmation_service_exports));
33051
+ const { renderMarkdownToConsole: renderMarkdownToConsole2 } = await Promise.resolve().then(() => (init_console_markdown(), console_markdown_exports));
32463
33052
  const { createMCPCommand: createMCPCommand2 } = await Promise.resolve().then(() => (init_mcp(), mcp_exports));
32464
33053
  const { createSetNameCommand: createSetNameCommand2 } = await Promise.resolve().then(() => (init_set_name(), set_name_exports));
32465
33054
  const { createToggleConfirmationsCommand: createToggleConfirmationsCommand2 } = await Promise.resolve().then(() => (init_toggle_confirmations(), toggle_confirmations_exports));
@@ -32535,7 +33124,7 @@ try {
32535
33124
  const chatEntries = await agent.processUserMessage(options.prompt);
32536
33125
  for (const entry of chatEntries) {
32537
33126
  if (entry.type === "assistant" && entry.content) {
32538
- console.log(entry.content);
33127
+ console.log(renderMarkdownToConsole2(entry.content));
32539
33128
  }
32540
33129
  }
32541
33130
  } catch (error) {