@ash-cloud/ash-ui 0.0.7 → 0.0.8
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/icons.cjs +7 -0
- package/dist/icons.cjs.map +1 -1
- package/dist/icons.d.cts +2 -1
- package/dist/icons.d.ts +2 -1
- package/dist/icons.js +7 -1
- package/dist/icons.js.map +1 -1
- package/dist/index.cjs +245 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +65 -9
- package/dist/index.d.ts +65 -9
- package/dist/index.js +242 -10
- package/dist/index.js.map +1 -1
- package/dist/styles-full.css +1 -1
- package/dist/styles.css +1 -1
- package/dist/types.cjs +4 -0
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +33 -2
- package/dist/types.d.ts +33 -2
- package/dist/types.js +4 -1
- package/dist/types.js.map +1 -1
- package/dist/utils.cjs +34 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts +8 -1
- package/dist/utils.d.ts +8 -1
- package/dist/utils.js +34 -1
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"names":[],"mappings":";AAyVO,SAAS,mBAAmB,MAAA,EAAgD;AACjF,EAAA,OAAO,OAAO,MAAA,KAAW,aAAA;AAC3B;AAEO,SAAS,iBAAiB,MAAA,EAA8C;AAC7E,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAEO,SAAS,iBAAiB,MAAA,EAA8C;AAC7E,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAEO,SAAS,kBAAkB,MAAA,EAA+C;AAC/E,EAAA,OAAO,OAAO,MAAA,KAAW,YAAA;AAC3B;AAEO,SAAS,eAAe,MAAA,EAA4C;AACzE,EAAA,OAAO,OAAO,MAAA,KAAW,QAAA;AAC3B;AAEO,SAAS,aAAa,MAAA,EAA0C;AACrE,EAAA,OAAO,OAAO,MAAA,KAAW,MAAA;AAC3B;AAEO,SAAS,iBAAiB,MAAA,EAA8C;AAC7E,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAEO,SAAS,kBAAkB,MAAA,EAA+C;AAC/E,EAAA,OAAO,OAAO,MAAA,KAAW,YAAA;AAC3B;AAEO,SAAS,gBAAgB,MAAA,EAA6C;AAC3E,EAAA,OAAO,OAAO,MAAA,KAAW,UAAA;AAC3B;AAEO,SAAS,oBAAoB,MAAA,EAAiD;AACnF,EAAA,OAAO,OAAO,MAAA,KAAW,cAAA;AAC3B;AAEO,SAAS,kBAAkB,MAAA,EAA+C;AAC/E,EAAA,OAAO,OAAO,MAAA,KAAW,YAAA;AAC3B;AAEO,SAAS,gBAAgB,KAAA,EAAoD;AAClF,EAAA,OAAO,MAAM,IAAA,KAAS,WAAA;AACxB;AAEO,SAAS,aAAa,KAAA,EAAiD;AAC5E,EAAA,OAAO,MAAM,IAAA,KAAS,OAAA;AACxB;AAEO,SAAS,cAAc,KAAA,EAAkD;AAC9E,EAAA,OAAO,MAAM,IAAA,KAAS,QAAA;AACxB;AAsIO,IAAM,sBAAA,GAA4C;AAAA,EACvD,IAAA,EAAM,QAAA;AAAA,EACN,oBAAA,EAAsB,CAAA;AAAA,EACtB,eAAA,EAAiB,KAAA;AAAA,EACjB,iBAAA,EAAmB;AACrB","file":"types.js","sourcesContent":["/**\n * @ash-cloud/ash-ui - Types\n *\n * Normalized types for structured tool call display in agentic UIs.\n * These types provide a unified representation for displaying tool calls\n * with their arguments and results together.\n */\n\nimport type { ReactNode } from 'react';\n\n// =============================================================================\n// Tool Status\n// =============================================================================\n\n/**\n * Status of a tool call execution\n */\nexport type ToolStatus = 'pending' | 'success' | 'failed';\n\n// =============================================================================\n// Action-Specific Result Types\n// =============================================================================\n\n/**\n * Result from a command/bash execution\n */\nexport interface CommandRunResult {\n exitCode?: number;\n success?: boolean;\n output?: string;\n}\n\n/**\n * Generic tool result that can be markdown or structured JSON\n */\nexport interface ToolResult {\n type: 'markdown' | 'json';\n value: unknown;\n}\n\n// =============================================================================\n// Action Types (Discriminated Union)\n// =============================================================================\n\n/**\n * Bash/command execution action\n */\nexport interface CommandRunAction {\n action: 'command_run';\n command: string;\n description?: string;\n result?: CommandRunResult;\n}\n\n/**\n * File read action\n */\nexport interface FileReadAction {\n action: 'file_read';\n path: string;\n offset?: number;\n limit?: number;\n /** Number of lines read (for display) */\n linesRead?: number;\n}\n\n/**\n * File edit action\n */\nexport interface FileEditAction {\n action: 'file_edit';\n path: string;\n oldString?: string;\n newString?: string;\n replaceAll?: boolean;\n /** Number of lines added */\n linesAdded?: number;\n /** Number of lines removed */\n linesRemoved?: number;\n}\n\n/**\n * File write action\n */\nexport interface FileWriteAction {\n action: 'file_write';\n path: string;\n content?: string;\n /** Number of lines written */\n linesWritten?: number;\n}\n\n/**\n * Search/grep action\n */\nexport interface SearchAction {\n action: 'search';\n pattern: string;\n path?: string;\n glob?: string;\n type?: string;\n}\n\n/**\n * Glob/file pattern matching action\n */\nexport interface GlobAction {\n action: 'glob';\n pattern: string;\n path?: string;\n}\n\n/**\n * Web fetch action\n */\nexport interface WebFetchAction {\n action: 'web_fetch';\n url: string;\n prompt?: string;\n}\n\n/**\n * Web search action\n */\nexport interface WebSearchAction {\n action: 'web_search';\n query: string;\n}\n\n/**\n * MCP (Model Context Protocol) tool action\n */\nexport interface McpToolAction {\n action: 'mcp_tool';\n serverName: string;\n toolName: string;\n arguments?: unknown;\n result?: ToolResult;\n}\n\n/**\n * Generic/unknown tool action\n */\nexport interface GenericToolAction {\n action: 'generic_tool';\n toolName: string;\n arguments?: unknown;\n result?: ToolResult;\n}\n\n// =============================================================================\n// Todo Types\n// =============================================================================\n\n/**\n * Status of a todo item\n */\nexport type TodoStatus = 'pending' | 'in_progress' | 'completed';\n\n/**\n * A single todo item from TodoWrite tool\n */\nexport interface TodoItem {\n /** Task content - imperative form (e.g., \"Run tests\") */\n content: string;\n /** Current status of the todo */\n status: TodoStatus;\n /** Active form shown during execution (e.g., \"Running tests\") */\n activeForm: string;\n}\n\n/**\n * TodoWrite tool action - tracks task progress\n */\nexport interface TodoWriteAction {\n action: 'todo_write';\n /** All todos in the current list */\n todos: TodoItem[];\n /** Summary statistics */\n stats?: {\n total: number;\n completed: number;\n inProgress: number;\n pending: number;\n };\n}\n\n/**\n * Discriminated union of all action types\n */\nexport type ActionType =\n | CommandRunAction\n | FileReadAction\n | FileEditAction\n | FileWriteAction\n | SearchAction\n | GlobAction\n | WebFetchAction\n | WebSearchAction\n | McpToolAction\n | GenericToolAction\n | TodoWriteAction;\n\n// =============================================================================\n// Normalized Tool Call\n// =============================================================================\n\n/**\n * A normalized tool call that combines tool_use and tool_result data\n */\nexport interface NormalizedToolCall {\n /** Unique ID from the tool_use block */\n id: string;\n\n /** Original tool name (e.g., 'Bash', 'Read', 'mcp__server__tool') */\n toolName: string;\n\n /** Parsed action type with structured arguments and result */\n actionType: ActionType;\n\n /** Current execution status */\n status: ToolStatus;\n\n /** Human-readable one-liner summary */\n summary: string;\n\n /** When the tool call started */\n startedAt?: string;\n\n /** When the tool call completed */\n completedAt?: string;\n\n /** Whether this tool call resulted in an error */\n isError?: boolean;\n}\n\n// =============================================================================\n// Normalized Entry Types\n// =============================================================================\n\n/**\n * User message entry\n */\nexport interface UserMessageEntry {\n type: 'user_message';\n}\n\n/**\n * Assistant message entry\n */\nexport interface AssistantMessageEntry {\n type: 'assistant_message';\n}\n\n/**\n * Thinking/reasoning entry (extended thinking)\n */\nexport interface ThinkingEntry {\n type: 'thinking';\n}\n\n/**\n * Tool call entry with full tool call data\n */\nexport interface ToolCallEntry {\n type: 'tool_call';\n toolCall: NormalizedToolCall;\n}\n\n/**\n * Error entry\n */\nexport interface ErrorEntry {\n type: 'error';\n message: string;\n code?: string;\n}\n\n/**\n * Custom widget entry - rendered via consumer-provided render function\n *\n * Use this for interactive UI components like:\n * - Image grid selectors\n * - Product carousels\n * - Form inputs\n * - Data visualizations\n * - Any custom interactive widget\n *\n * @example\n * ```tsx\n * const entry: NormalizedEntry = {\n * id: 'widget-1',\n * entryType: {\n * type: 'widget',\n * widgetType: 'image-grid',\n * widgetData: { images: [...], selected: null },\n * },\n * content: 'Select an image',\n * };\n * ```\n */\nexport interface WidgetEntry {\n type: 'widget';\n /** Widget type identifier (e.g., 'image-grid', 'product-selector') */\n widgetType: string;\n /** Widget-specific data passed to the render function */\n widgetData: unknown;\n}\n\n/**\n * Discriminated union of all entry types\n */\nexport type NormalizedEntryType =\n | UserMessageEntry\n | AssistantMessageEntry\n | ThinkingEntry\n | ToolCallEntry\n | ErrorEntry\n | WidgetEntry;\n\n// =============================================================================\n// Normalized Entry\n// =============================================================================\n\n/**\n * A normalized conversation entry for display\n */\nexport interface NormalizedEntry {\n /** Unique entry ID */\n id: string;\n\n /** ISO timestamp */\n timestamp?: string;\n\n /** Entry type with type-specific data */\n entryType: NormalizedEntryType;\n\n /** Text content for display */\n content: string;\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport function isCommandRunAction(action: ActionType): action is CommandRunAction {\n return action.action === 'command_run';\n}\n\nexport function isFileReadAction(action: ActionType): action is FileReadAction {\n return action.action === 'file_read';\n}\n\nexport function isFileEditAction(action: ActionType): action is FileEditAction {\n return action.action === 'file_edit';\n}\n\nexport function isFileWriteAction(action: ActionType): action is FileWriteAction {\n return action.action === 'file_write';\n}\n\nexport function isSearchAction(action: ActionType): action is SearchAction {\n return action.action === 'search';\n}\n\nexport function isGlobAction(action: ActionType): action is GlobAction {\n return action.action === 'glob';\n}\n\nexport function isWebFetchAction(action: ActionType): action is WebFetchAction {\n return action.action === 'web_fetch';\n}\n\nexport function isWebSearchAction(action: ActionType): action is WebSearchAction {\n return action.action === 'web_search';\n}\n\nexport function isMcpToolAction(action: ActionType): action is McpToolAction {\n return action.action === 'mcp_tool';\n}\n\nexport function isGenericToolAction(action: ActionType): action is GenericToolAction {\n return action.action === 'generic_tool';\n}\n\nexport function isTodoWriteAction(action: ActionType): action is TodoWriteAction {\n return action.action === 'todo_write';\n}\n\nexport function isToolCallEntry(entry: NormalizedEntryType): entry is ToolCallEntry {\n return entry.type === 'tool_call';\n}\n\nexport function isErrorEntry(entry: NormalizedEntryType): entry is ErrorEntry {\n return entry.type === 'error';\n}\n\nexport function isWidgetEntry(entry: NormalizedEntryType): entry is WidgetEntry {\n return entry.type === 'widget';\n}\n\n// =============================================================================\n// Widget Rendering\n// =============================================================================\n\n/**\n * Props passed to the widget render function\n */\nexport interface WidgetRenderProps<T = unknown> {\n /** The widget entry being rendered */\n entry: NormalizedEntry;\n /** Widget type identifier */\n widgetType: string;\n /** Widget-specific data */\n widgetData: T;\n /** Callback for widget interactions (e.g., selection, submit) */\n onAction?: (action: WidgetAction) => void;\n}\n\n/**\n * Action dispatched from a widget interaction\n */\nexport interface WidgetAction {\n /** Action type (e.g., 'select', 'submit', 'cancel') */\n type: string;\n /** Widget type that dispatched the action */\n widgetType: string;\n /** Entry ID of the widget */\n entryId: string;\n /** Action-specific payload */\n payload?: unknown;\n}\n\n/**\n * Function type for rendering custom widgets\n *\n * @example\n * ```tsx\n * const renderWidget: WidgetRenderFunction = ({ widgetType, widgetData, onAction }) => {\n * switch (widgetType) {\n * case 'image-grid':\n * return (\n * <ImageGrid\n * images={widgetData.images}\n * onSelect={(id) => onAction?.({ type: 'select', widgetType, entryId, payload: { id } })}\n * />\n * );\n * case 'product-selector':\n * return <ProductSelector data={widgetData} onAction={onAction} />;\n * default:\n * return null;\n * }\n * };\n *\n * <MessageList entries={entries} renderWidget={renderWidget} />\n * ```\n */\nexport type WidgetRenderFunction = (props: WidgetRenderProps) => ReactNode;\n\n// =============================================================================\n// Log Types (for SandboxLogsPanel)\n// =============================================================================\n\nexport type LogLevel = 'info' | 'warn' | 'error' | 'debug';\nexport type LogCategory = 'setup' | 'skills' | 'execution' | 'process' | 'startup';\n\nexport interface LogEntry {\n timestamp: string;\n level: LogLevel;\n category: LogCategory;\n message: string;\n data?: Record<string, unknown>;\n}\n\n// =============================================================================\n// File Attachment\n// =============================================================================\n\nexport interface FileAttachment {\n name: string;\n type: string;\n size: number;\n base64: string;\n}\n\n// =============================================================================\n// Display Mode Configuration\n// =============================================================================\n\n/**\n * Display mode for tool calls in the chat interface\n *\n * - 'inline': Each tool call rendered inline as expandable cards (current behavior)\n * - 'compact': Single animated status line that updates with each tool call,\n * with accordion to expand and see execution details. Text streams unbroken.\n * - 'accordion': Simpler step-based accordion list that accumulates tool calls\n * with icons, labels, and durations (like Vidra's ThinkingIndicator).\n */\nexport type ToolDisplayMode = 'inline' | 'compact' | 'accordion';\n\n/**\n * Configuration for tool display behavior\n */\nexport interface ToolDisplayConfig {\n /**\n * Display mode for tool calls\n * @default 'inline'\n */\n mode: ToolDisplayMode;\n\n /**\n * For 'compact' mode: break into a new group every N tool calls\n * Set to 0 or undefined to never break (all tool calls in single group)\n * @default 0\n */\n breakEveryNToolCalls?: number;\n\n /**\n * Whether tool call groups start expanded\n * @default false\n */\n defaultExpanded?: boolean;\n\n /**\n * Animation duration for status line transitions (ms)\n * @default 300\n */\n animationDuration?: number;\n}\n\n/**\n * Default display configuration\n */\nexport const DEFAULT_DISPLAY_CONFIG: ToolDisplayConfig = {\n mode: 'inline',\n breakEveryNToolCalls: 0,\n defaultExpanded: false,\n animationDuration: 300,\n};\n\n// =============================================================================\n// Tool Execution Group (for compact mode)\n// =============================================================================\n\n/**\n * A group of consecutive tool calls that are displayed together\n * in compact mode. Text content before/after flows around the group.\n */\nexport interface ToolExecutionGroup {\n /** Unique ID for the group */\n id: string;\n\n /** Tool calls in this group (in order) */\n toolCalls: NormalizedToolCall[];\n\n /** Index of the currently active/latest tool call for status display */\n activeIndex: number;\n\n /** Whether all tool calls in this group have completed */\n isComplete: boolean;\n\n /** Overall status of the group */\n status: 'pending' | 'success' | 'partial_failure' | 'failed';\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"names":[],"mappings":";AA6XO,SAAS,mBAAmB,MAAA,EAAgD;AACjF,EAAA,OAAO,OAAO,MAAA,KAAW,aAAA;AAC3B;AAEO,SAAS,iBAAiB,MAAA,EAA8C;AAC7E,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAEO,SAAS,iBAAiB,MAAA,EAA8C;AAC7E,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAEO,SAAS,kBAAkB,MAAA,EAA+C;AAC/E,EAAA,OAAO,OAAO,MAAA,KAAW,YAAA;AAC3B;AAEO,SAAS,eAAe,MAAA,EAA4C;AACzE,EAAA,OAAO,OAAO,MAAA,KAAW,QAAA;AAC3B;AAEO,SAAS,aAAa,MAAA,EAA0C;AACrE,EAAA,OAAO,OAAO,MAAA,KAAW,MAAA;AAC3B;AAEO,SAAS,iBAAiB,MAAA,EAA8C;AAC7E,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAEO,SAAS,kBAAkB,MAAA,EAA+C;AAC/E,EAAA,OAAO,OAAO,MAAA,KAAW,YAAA;AAC3B;AAEO,SAAS,gBAAgB,MAAA,EAA6C;AAC3E,EAAA,OAAO,OAAO,MAAA,KAAW,UAAA;AAC3B;AAEO,SAAS,oBAAoB,MAAA,EAAiD;AACnF,EAAA,OAAO,OAAO,MAAA,KAAW,cAAA;AAC3B;AAEO,SAAS,kBAAkB,MAAA,EAA+C;AAC/E,EAAA,OAAO,OAAO,MAAA,KAAW,YAAA;AAC3B;AAEO,SAAS,kBAAkB,MAAA,EAA+C;AAC/E,EAAA,OAAO,OAAO,MAAA,KAAW,YAAA;AAC3B;AAEO,SAAS,gBAAgB,KAAA,EAAoD;AAClF,EAAA,OAAO,MAAM,IAAA,KAAS,WAAA;AACxB;AAEO,SAAS,aAAa,KAAA,EAAiD;AAC5E,EAAA,OAAO,MAAM,IAAA,KAAS,OAAA;AACxB;AAEO,SAAS,cAAc,KAAA,EAAkD;AAC9E,EAAA,OAAO,MAAM,IAAA,KAAS,QAAA;AACxB;AAsIO,IAAM,sBAAA,GAA4C;AAAA,EACvD,IAAA,EAAM,QAAA;AAAA,EACN,oBAAA,EAAsB,CAAA;AAAA,EACtB,eAAA,EAAiB,KAAA;AAAA,EACjB,iBAAA,EAAmB;AACrB","file":"types.js","sourcesContent":["/**\n * @ash-cloud/ash-ui - Types\n *\n * Normalized types for structured tool call display in agentic UIs.\n * These types provide a unified representation for displaying tool calls\n * with their arguments and results together.\n */\n\nimport type { ReactNode } from 'react';\n\n// =============================================================================\n// Tool Status\n// =============================================================================\n\n/**\n * Status of a tool call execution\n */\nexport type ToolStatus = 'pending' | 'success' | 'failed';\n\n// =============================================================================\n// Action-Specific Result Types\n// =============================================================================\n\n/**\n * Result from a command/bash execution\n */\nexport interface CommandRunResult {\n exitCode?: number;\n success?: boolean;\n output?: string;\n}\n\n/**\n * Generic tool result that can be markdown or structured JSON\n */\nexport interface ToolResult {\n type: 'markdown' | 'json';\n value: unknown;\n}\n\n// =============================================================================\n// Action Types (Discriminated Union)\n// =============================================================================\n\n/**\n * Bash/command execution action\n */\nexport interface CommandRunAction {\n action: 'command_run';\n command: string;\n description?: string;\n result?: CommandRunResult;\n}\n\n/**\n * File read action\n */\nexport interface FileReadAction {\n action: 'file_read';\n path: string;\n offset?: number;\n limit?: number;\n /** Number of lines read (for display) */\n linesRead?: number;\n}\n\n/**\n * File edit action\n */\nexport interface FileEditAction {\n action: 'file_edit';\n path: string;\n oldString?: string;\n newString?: string;\n replaceAll?: boolean;\n /** Number of lines added */\n linesAdded?: number;\n /** Number of lines removed */\n linesRemoved?: number;\n}\n\n/**\n * File write action\n */\nexport interface FileWriteAction {\n action: 'file_write';\n path: string;\n content?: string;\n /** Number of lines written */\n linesWritten?: number;\n}\n\n/**\n * Search/grep action\n */\nexport interface SearchAction {\n action: 'search';\n pattern: string;\n path?: string;\n glob?: string;\n type?: string;\n}\n\n/**\n * Glob/file pattern matching action\n */\nexport interface GlobAction {\n action: 'glob';\n pattern: string;\n path?: string;\n}\n\n/**\n * Web fetch action\n */\nexport interface WebFetchAction {\n action: 'web_fetch';\n url: string;\n prompt?: string;\n}\n\n/**\n * Web search action\n */\nexport interface WebSearchAction {\n action: 'web_search';\n query: string;\n}\n\n/**\n * MCP (Model Context Protocol) tool action\n */\nexport interface McpToolAction {\n action: 'mcp_tool';\n serverName: string;\n toolName: string;\n arguments?: unknown;\n result?: ToolResult;\n}\n\n/**\n * Generic/unknown tool action\n */\nexport interface GenericToolAction {\n action: 'generic_tool';\n toolName: string;\n arguments?: unknown;\n result?: ToolResult;\n}\n\n/**\n * Agent/Task tool action - represents a sub-agent that can have nested tool calls\n */\nexport interface AgentToolAction {\n action: 'agent_tool';\n /** Agent type (e.g., 'Explore', 'Plan', 'Bash', 'general-purpose') */\n agentType: string;\n /** Description of what the agent is doing */\n description: string;\n /** Full prompt given to the agent */\n prompt?: string;\n /** Nested tool calls made by this agent */\n nestedToolCalls?: NormalizedToolCall[];\n /** Current count of tool calls (updates during streaming) */\n toolCallCount?: number;\n /** When the agent started */\n startedAt?: string;\n /** When the agent completed */\n completedAt?: string;\n /** Result/output from the agent */\n result?: ToolResult;\n}\n\n// =============================================================================\n// Todo Types\n// =============================================================================\n\n/**\n * Status of a todo item\n */\nexport type TodoStatus = 'pending' | 'in_progress' | 'completed';\n\n/**\n * A single todo item from TodoWrite tool\n */\nexport interface TodoItem {\n /** Task content - imperative form (e.g., \"Run tests\") */\n content: string;\n /** Current status of the todo */\n status: TodoStatus;\n /** Active form shown during execution (e.g., \"Running tests\") */\n activeForm: string;\n}\n\n/**\n * TodoWrite tool action - tracks task progress\n */\nexport interface TodoWriteAction {\n action: 'todo_write';\n /** All todos in the current list */\n todos: TodoItem[];\n /** Summary statistics */\n stats?: {\n total: number;\n completed: number;\n inProgress: number;\n pending: number;\n };\n}\n\n/**\n * Discriminated union of all action types\n */\nexport type ActionType =\n | CommandRunAction\n | FileReadAction\n | FileEditAction\n | FileWriteAction\n | SearchAction\n | GlobAction\n | WebFetchAction\n | WebSearchAction\n | McpToolAction\n | GenericToolAction\n | TodoWriteAction\n | AgentToolAction;\n\n// =============================================================================\n// Normalized Tool Call\n// =============================================================================\n\n/**\n * A normalized tool call that combines tool_use and tool_result data\n */\nexport interface NormalizedToolCall {\n /** Unique ID from the tool_use block */\n id: string;\n\n /** Original tool name (e.g., 'Bash', 'Read', 'mcp__server__tool') */\n toolName: string;\n\n /** Parsed action type with structured arguments and result */\n actionType: ActionType;\n\n /** Current execution status */\n status: ToolStatus;\n\n /** Human-readable one-liner summary */\n summary: string;\n\n /** Raw input from tool_use event (for display in UI) */\n input?: unknown;\n\n /** Raw output/result from tool_result event (for display in UI) */\n output?: unknown;\n\n /** When the tool call started */\n startedAt?: string;\n\n /** When the tool call completed */\n completedAt?: string;\n\n /** Whether this tool call resulted in an error */\n isError?: boolean;\n\n /** Nested tool calls (for agent/sub-agent tools like Task) */\n nestedToolCalls?: NormalizedToolCall[];\n\n /** Current count of nested tool calls (updates during streaming) */\n nestedToolCallCount?: number;\n}\n\n// =============================================================================\n// Normalized Entry Types\n// =============================================================================\n\n/**\n * User message entry\n */\nexport interface UserMessageEntry {\n type: 'user_message';\n}\n\n/**\n * Assistant message entry\n */\nexport interface AssistantMessageEntry {\n type: 'assistant_message';\n}\n\n/**\n * Thinking/reasoning entry (extended thinking)\n */\nexport interface ThinkingEntry {\n type: 'thinking';\n}\n\n/**\n * Tool call entry with full tool call data\n */\nexport interface ToolCallEntry {\n type: 'tool_call';\n toolCall: NormalizedToolCall;\n}\n\n/**\n * Error entry\n */\nexport interface ErrorEntry {\n type: 'error';\n message: string;\n code?: string;\n}\n\n/**\n * Custom widget entry - rendered via consumer-provided render function\n *\n * Use this for interactive UI components like:\n * - Image grid selectors\n * - Product carousels\n * - Form inputs\n * - Data visualizations\n * - Any custom interactive widget\n *\n * @example\n * ```tsx\n * const entry: NormalizedEntry = {\n * id: 'widget-1',\n * entryType: {\n * type: 'widget',\n * widgetType: 'image-grid',\n * widgetData: { images: [...], selected: null },\n * },\n * content: 'Select an image',\n * };\n * ```\n */\nexport interface WidgetEntry {\n type: 'widget';\n /** Widget type identifier (e.g., 'image-grid', 'product-selector') */\n widgetType: string;\n /** Widget-specific data passed to the render function */\n widgetData: unknown;\n}\n\n/**\n * Discriminated union of all entry types\n */\nexport type NormalizedEntryType =\n | UserMessageEntry\n | AssistantMessageEntry\n | ThinkingEntry\n | ToolCallEntry\n | ErrorEntry\n | WidgetEntry;\n\n// =============================================================================\n// Normalized Entry\n// =============================================================================\n\n/**\n * A normalized conversation entry for display\n */\nexport interface NormalizedEntry {\n /** Unique entry ID */\n id: string;\n\n /** ISO timestamp */\n timestamp?: string;\n\n /** Entry type with type-specific data */\n entryType: NormalizedEntryType;\n\n /** Text content for display */\n content: string;\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport function isCommandRunAction(action: ActionType): action is CommandRunAction {\n return action.action === 'command_run';\n}\n\nexport function isFileReadAction(action: ActionType): action is FileReadAction {\n return action.action === 'file_read';\n}\n\nexport function isFileEditAction(action: ActionType): action is FileEditAction {\n return action.action === 'file_edit';\n}\n\nexport function isFileWriteAction(action: ActionType): action is FileWriteAction {\n return action.action === 'file_write';\n}\n\nexport function isSearchAction(action: ActionType): action is SearchAction {\n return action.action === 'search';\n}\n\nexport function isGlobAction(action: ActionType): action is GlobAction {\n return action.action === 'glob';\n}\n\nexport function isWebFetchAction(action: ActionType): action is WebFetchAction {\n return action.action === 'web_fetch';\n}\n\nexport function isWebSearchAction(action: ActionType): action is WebSearchAction {\n return action.action === 'web_search';\n}\n\nexport function isMcpToolAction(action: ActionType): action is McpToolAction {\n return action.action === 'mcp_tool';\n}\n\nexport function isGenericToolAction(action: ActionType): action is GenericToolAction {\n return action.action === 'generic_tool';\n}\n\nexport function isTodoWriteAction(action: ActionType): action is TodoWriteAction {\n return action.action === 'todo_write';\n}\n\nexport function isAgentToolAction(action: ActionType): action is AgentToolAction {\n return action.action === 'agent_tool';\n}\n\nexport function isToolCallEntry(entry: NormalizedEntryType): entry is ToolCallEntry {\n return entry.type === 'tool_call';\n}\n\nexport function isErrorEntry(entry: NormalizedEntryType): entry is ErrorEntry {\n return entry.type === 'error';\n}\n\nexport function isWidgetEntry(entry: NormalizedEntryType): entry is WidgetEntry {\n return entry.type === 'widget';\n}\n\n// =============================================================================\n// Widget Rendering\n// =============================================================================\n\n/**\n * Props passed to the widget render function\n */\nexport interface WidgetRenderProps<T = unknown> {\n /** The widget entry being rendered */\n entry: NormalizedEntry;\n /** Widget type identifier */\n widgetType: string;\n /** Widget-specific data */\n widgetData: T;\n /** Callback for widget interactions (e.g., selection, submit) */\n onAction?: (action: WidgetAction) => void;\n}\n\n/**\n * Action dispatched from a widget interaction\n */\nexport interface WidgetAction {\n /** Action type (e.g., 'select', 'submit', 'cancel') */\n type: string;\n /** Widget type that dispatched the action */\n widgetType: string;\n /** Entry ID of the widget */\n entryId: string;\n /** Action-specific payload */\n payload?: unknown;\n}\n\n/**\n * Function type for rendering custom widgets\n *\n * @example\n * ```tsx\n * const renderWidget: WidgetRenderFunction = ({ widgetType, widgetData, onAction }) => {\n * switch (widgetType) {\n * case 'image-grid':\n * return (\n * <ImageGrid\n * images={widgetData.images}\n * onSelect={(id) => onAction?.({ type: 'select', widgetType, entryId, payload: { id } })}\n * />\n * );\n * case 'product-selector':\n * return <ProductSelector data={widgetData} onAction={onAction} />;\n * default:\n * return null;\n * }\n * };\n *\n * <MessageList entries={entries} renderWidget={renderWidget} />\n * ```\n */\nexport type WidgetRenderFunction = (props: WidgetRenderProps) => ReactNode;\n\n// =============================================================================\n// Log Types (for SandboxLogsPanel)\n// =============================================================================\n\nexport type LogLevel = 'info' | 'warn' | 'error' | 'debug';\nexport type LogCategory = 'setup' | 'skills' | 'execution' | 'process' | 'startup';\n\nexport interface LogEntry {\n timestamp: string;\n level: LogLevel;\n category: LogCategory;\n message: string;\n data?: Record<string, unknown>;\n}\n\n// =============================================================================\n// File Attachment\n// =============================================================================\n\nexport interface FileAttachment {\n name: string;\n type: string;\n size: number;\n base64: string;\n}\n\n// =============================================================================\n// Display Mode Configuration\n// =============================================================================\n\n/**\n * Display mode for tool calls in the chat interface\n *\n * - 'inline': Each tool call rendered inline as expandable cards (current behavior)\n * - 'compact': Single animated status line that updates with each tool call,\n * with accordion to expand and see execution details. Text streams unbroken.\n * - 'accordion': Simpler step-based accordion list that accumulates tool calls\n * with icons, labels, and durations (like Vidra's ThinkingIndicator).\n */\nexport type ToolDisplayMode = 'inline' | 'compact' | 'accordion';\n\n/**\n * Configuration for tool display behavior\n */\nexport interface ToolDisplayConfig {\n /**\n * Display mode for tool calls\n * @default 'inline'\n */\n mode: ToolDisplayMode;\n\n /**\n * For 'compact' mode: break into a new group every N tool calls\n * Set to 0 or undefined to never break (all tool calls in single group)\n * @default 0\n */\n breakEveryNToolCalls?: number;\n\n /**\n * Whether tool call groups start expanded\n * @default false\n */\n defaultExpanded?: boolean;\n\n /**\n * Animation duration for status line transitions (ms)\n * @default 300\n */\n animationDuration?: number;\n}\n\n/**\n * Default display configuration\n */\nexport const DEFAULT_DISPLAY_CONFIG: ToolDisplayConfig = {\n mode: 'inline',\n breakEveryNToolCalls: 0,\n defaultExpanded: false,\n animationDuration: 300,\n};\n\n// =============================================================================\n// Tool Execution Group (for compact mode)\n// =============================================================================\n\n/**\n * A group of consecutive tool calls that are displayed together\n * in compact mode. Text content before/after flows around the group.\n */\nexport interface ToolExecutionGroup {\n /** Unique ID for the group */\n id: string;\n\n /** Tool calls in this group (in order) */\n toolCalls: NormalizedToolCall[];\n\n /** Index of the currently active/latest tool call for status display */\n activeIndex: number;\n\n /** Whether all tool calls in this group have completed */\n isComplete: boolean;\n\n /** Overall status of the group */\n status: 'pending' | 'success' | 'partial_failure' | 'failed';\n}\n"]}
|
package/dist/utils.cjs
CHANGED
|
@@ -105,6 +105,16 @@ function mapToolToActionType(toolName, input) {
|
|
|
105
105
|
stats
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
|
+
case "Task": {
|
|
109
|
+
return {
|
|
110
|
+
action: "agent_tool",
|
|
111
|
+
agentType: inputObj.subagent_type || "general-purpose",
|
|
112
|
+
description: inputObj.description || "",
|
|
113
|
+
prompt: inputObj.prompt,
|
|
114
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
115
|
+
toolCallCount: 0
|
|
116
|
+
};
|
|
117
|
+
}
|
|
108
118
|
default: {
|
|
109
119
|
const mcpParts = parseMcpToolName(toolName);
|
|
110
120
|
if (mcpParts) {
|
|
@@ -154,6 +164,8 @@ function generateToolSummary(_toolName, _input, actionType) {
|
|
|
154
164
|
}
|
|
155
165
|
return `${actionType.todos.length} tasks`;
|
|
156
166
|
}
|
|
167
|
+
case "agent_tool":
|
|
168
|
+
return actionType.description;
|
|
157
169
|
default:
|
|
158
170
|
return "Unknown tool";
|
|
159
171
|
}
|
|
@@ -221,6 +233,7 @@ function createToolCall(toolUse) {
|
|
|
221
233
|
actionType,
|
|
222
234
|
status: "pending",
|
|
223
235
|
summary,
|
|
236
|
+
input: toolUse.input,
|
|
224
237
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
225
238
|
};
|
|
226
239
|
}
|
|
@@ -230,6 +243,7 @@ function updateToolCallWithResult(toolCall, content, isError) {
|
|
|
230
243
|
updatedToolCall.status = isError ? "failed" : "success";
|
|
231
244
|
updatedToolCall.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
232
245
|
updatedToolCall.isError = isError;
|
|
246
|
+
updatedToolCall.output = content;
|
|
233
247
|
if (actionType.action === "command_run") {
|
|
234
248
|
const result = parseCommandResult(content);
|
|
235
249
|
actionType.result = result;
|
|
@@ -267,6 +281,8 @@ function getActionIcon(actionType) {
|
|
|
267
281
|
return "tool";
|
|
268
282
|
case "todo_write":
|
|
269
283
|
return "list-checks";
|
|
284
|
+
case "agent_tool":
|
|
285
|
+
return "bot";
|
|
270
286
|
default:
|
|
271
287
|
return "tool";
|
|
272
288
|
}
|
|
@@ -295,6 +311,8 @@ function getActionLabel(actionType) {
|
|
|
295
311
|
return "Tool";
|
|
296
312
|
case "todo_write":
|
|
297
313
|
return "Tasks";
|
|
314
|
+
case "agent_tool":
|
|
315
|
+
return actionType.agentType;
|
|
298
316
|
default:
|
|
299
317
|
return "Tool";
|
|
300
318
|
}
|
|
@@ -317,6 +335,21 @@ function formatTimestamp(timestamp) {
|
|
|
317
335
|
return timestamp;
|
|
318
336
|
}
|
|
319
337
|
}
|
|
338
|
+
function formatElapsedTime(startTime, endTime) {
|
|
339
|
+
const start = typeof startTime === "string" ? new Date(startTime) : startTime;
|
|
340
|
+
const end = endTime ? typeof endTime === "string" ? new Date(endTime) : endTime : /* @__PURE__ */ new Date();
|
|
341
|
+
const elapsedMs = end.getTime() - start.getTime();
|
|
342
|
+
const elapsedSeconds = Math.floor(elapsedMs / 1e3);
|
|
343
|
+
if (elapsedSeconds < 60) {
|
|
344
|
+
return `${elapsedSeconds}s`;
|
|
345
|
+
}
|
|
346
|
+
const minutes = Math.floor(elapsedSeconds / 60);
|
|
347
|
+
const seconds = elapsedSeconds % 60;
|
|
348
|
+
if (seconds === 0) {
|
|
349
|
+
return `${minutes}m`;
|
|
350
|
+
}
|
|
351
|
+
return `${minutes}m ${seconds}s`;
|
|
352
|
+
}
|
|
320
353
|
function truncate(str, maxLength) {
|
|
321
354
|
if (str.length <= maxLength) return str;
|
|
322
355
|
return str.substring(0, maxLength - 3) + "...";
|
|
@@ -411,6 +444,7 @@ exports.cn = cn;
|
|
|
411
444
|
exports.createToolCall = createToolCall;
|
|
412
445
|
exports.extractTextContent = extractTextContent;
|
|
413
446
|
exports.extractToolCallsFromGroup = extractToolCallsFromGroup;
|
|
447
|
+
exports.formatElapsedTime = formatElapsedTime;
|
|
414
448
|
exports.formatFileSize = formatFileSize;
|
|
415
449
|
exports.formatTimestamp = formatTimestamp;
|
|
416
450
|
exports.formatToolName = formatToolName;
|
package/dist/utils.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.ts"],"names":[],"mappings":"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","file":"utils.cjs","sourcesContent":["/**\n * @ash-cloud/ash-ui - Utilities\n *\n * Utility functions for normalizing and formatting tool calls\n * for display in agentic UIs.\n */\n\nimport type {\n ActionType,\n ToolResult,\n CommandRunResult,\n NormalizedToolCall,\n NormalizedEntry,\n ToolDisplayConfig,\n TodoItem,\n} from './types';\n\n// =============================================================================\n// Tool Name Formatting\n// =============================================================================\n\n/**\n * Format MCP tool names from mcp__server__tool to mcp:server:tool\n */\nexport function formatToolName(name: string): string {\n if (name.startsWith('mcp__')) {\n const parts = name.split('__');\n if (parts.length >= 3) {\n return `mcp:${parts[1]}:${parts.slice(2).join(':')}`;\n }\n }\n return name;\n}\n\n/**\n * Parse MCP tool name to extract server and tool names\n */\nexport function parseMcpToolName(name: string): { serverName: string; toolName: string } | null {\n if (name.startsWith('mcp__')) {\n const parts = name.split('__');\n if (parts.length >= 3 && parts[1] !== undefined) {\n return {\n serverName: parts[1],\n toolName: parts.slice(2).join('__'),\n };\n }\n }\n return null;\n}\n\n// =============================================================================\n// Action Type Mapping\n// =============================================================================\n\n/**\n * Map a tool name and input to a structured ActionType\n */\nexport function mapToolToActionType(toolName: string, input: unknown): ActionType {\n const inputObj = (input as Record<string, unknown>) || {};\n\n switch (toolName) {\n case 'Bash':\n return {\n action: 'command_run',\n command: (inputObj.command as string) || '',\n description: inputObj.description as string | undefined,\n };\n\n case 'Read': {\n const limit = inputObj.limit as number | undefined;\n return {\n action: 'file_read',\n path: (inputObj.file_path as string) || '',\n offset: inputObj.offset as number | undefined,\n limit,\n linesRead: limit, // Use limit as approximate lines read if specified\n };\n }\n\n case 'Edit': {\n const oldStr = inputObj.old_string as string | undefined;\n const newStr = inputObj.new_string as string | undefined;\n // Calculate line diff stats\n const oldLines = oldStr ? oldStr.split('\\n').length : 0;\n const newLines = newStr ? newStr.split('\\n').length : 0;\n return {\n action: 'file_edit',\n path: (inputObj.file_path as string) || '',\n oldString: oldStr,\n newString: newStr,\n replaceAll: inputObj.replace_all as boolean | undefined,\n linesAdded: newLines,\n linesRemoved: oldLines,\n };\n }\n\n case 'Write': {\n const content = inputObj.content as string | undefined;\n return {\n action: 'file_write',\n path: (inputObj.file_path as string) || '',\n content,\n linesWritten: content ? content.split('\\n').length : undefined,\n };\n }\n\n case 'Grep':\n return {\n action: 'search',\n pattern: (inputObj.pattern as string) || '',\n path: inputObj.path as string | undefined,\n glob: inputObj.glob as string | undefined,\n type: inputObj.type as string | undefined,\n };\n\n case 'Glob':\n return {\n action: 'glob',\n pattern: (inputObj.pattern as string) || '',\n path: inputObj.path as string | undefined,\n };\n\n case 'WebFetch':\n return {\n action: 'web_fetch',\n url: (inputObj.url as string) || '',\n prompt: inputObj.prompt as string | undefined,\n };\n\n case 'WebSearch':\n return {\n action: 'web_search',\n query: (inputObj.query as string) || '',\n };\n\n case 'TodoWrite': {\n const todos = (inputObj.todos as TodoItem[]) || [];\n const stats = {\n total: todos.length,\n completed: todos.filter((t) => t.status === 'completed').length,\n inProgress: todos.filter((t) => t.status === 'in_progress').length,\n pending: todos.filter((t) => t.status === 'pending').length,\n };\n return {\n action: 'todo_write',\n todos,\n stats,\n };\n }\n\n default: {\n // Check if it's an MCP tool\n const mcpParts = parseMcpToolName(toolName);\n if (mcpParts) {\n return {\n action: 'mcp_tool',\n serverName: mcpParts.serverName,\n toolName: mcpParts.toolName,\n arguments: input,\n };\n }\n\n // Generic tool\n return {\n action: 'generic_tool',\n toolName: formatToolName(toolName),\n arguments: input,\n };\n }\n }\n}\n\n// =============================================================================\n// Summary Generation\n// =============================================================================\n\n/**\n * Generate a human-readable summary for a tool call\n */\nexport function generateToolSummary(\n _toolName: string,\n _input: unknown,\n actionType: ActionType\n): string {\n switch (actionType.action) {\n case 'command_run': {\n const cmd = actionType.command;\n return cmd.length > 60 ? cmd.substring(0, 57) + '...' : cmd;\n }\n\n case 'file_read':\n return actionType.path;\n\n case 'file_edit':\n return actionType.path;\n\n case 'file_write':\n return actionType.path;\n\n case 'search':\n return `${actionType.pattern}${actionType.path ? ` in ${actionType.path}` : ''}`;\n\n case 'glob':\n return actionType.pattern;\n\n case 'web_fetch':\n return actionType.url;\n\n case 'web_search':\n return actionType.query;\n\n case 'mcp_tool':\n return `${actionType.serverName}:${actionType.toolName}`;\n\n case 'generic_tool':\n return actionType.toolName;\n\n case 'todo_write': {\n const { stats } = actionType;\n if (stats) {\n return `${stats.completed}/${stats.total} completed`;\n }\n return `${actionType.todos.length} tasks`;\n }\n\n default:\n return 'Unknown tool';\n }\n}\n\n// =============================================================================\n// Result Normalization\n// =============================================================================\n\n/**\n * Extract text content from various content formats\n */\nexport function extractTextContent(content: unknown): string {\n if (typeof content === 'string') return content;\n\n if (Array.isArray(content)) {\n return content\n .filter((item): item is { text: string } => typeof item?.text === 'string')\n .map((item) => item.text)\n .join('\\n');\n }\n\n if (content && typeof content === 'object' && 'text' in content) {\n return String((content as { text: unknown }).text);\n }\n\n return JSON.stringify(content, null, 2);\n}\n\n/**\n * Normalize tool result content to markdown or JSON format\n */\nexport function normalizeToolResult(content: unknown): ToolResult {\n if (typeof content === 'string') {\n try {\n const parsed = JSON.parse(content);\n return { type: 'json', value: parsed };\n } catch {\n return { type: 'markdown', value: content };\n }\n }\n\n if (Array.isArray(content)) {\n const texts = content\n .filter(\n (item): item is { type: 'text'; text: string } =>\n item?.type === 'text' && typeof item.text === 'string'\n )\n .map((item) => item.text);\n\n if (texts.length > 0) {\n const joined = texts.join('\\n\\n');\n try {\n return { type: 'json', value: JSON.parse(joined) };\n } catch {\n return { type: 'markdown', value: joined };\n }\n }\n }\n\n return { type: 'json', value: content };\n}\n\n/**\n * Parse command result from tool result content\n */\nexport function parseCommandResult(content: unknown): CommandRunResult {\n const output = extractTextContent(content);\n\n if (typeof content === 'string') {\n try {\n const parsed = JSON.parse(content);\n if (typeof parsed.exitCode === 'number') {\n return {\n exitCode: parsed.exitCode,\n output: parsed.output || output,\n success: parsed.exitCode === 0,\n };\n }\n } catch {\n // Not JSON, use raw output\n }\n }\n\n return {\n output,\n success: true,\n };\n}\n\n// =============================================================================\n// Tool Call Creation\n// =============================================================================\n\nexport interface ToolUseInput {\n id: string;\n name: string;\n input: unknown;\n}\n\n/**\n * Create a NormalizedToolCall from a tool_use content block\n */\nexport function createToolCall(toolUse: ToolUseInput): NormalizedToolCall {\n const actionType = mapToolToActionType(toolUse.name, toolUse.input);\n const summary = generateToolSummary(toolUse.name, toolUse.input, actionType);\n\n return {\n id: toolUse.id,\n toolName: toolUse.name,\n actionType,\n status: 'pending',\n summary,\n startedAt: new Date().toISOString(),\n };\n}\n\n/**\n * Update a NormalizedToolCall with its result\n */\nexport function updateToolCallWithResult(\n toolCall: NormalizedToolCall,\n content: unknown,\n isError?: boolean\n): NormalizedToolCall {\n const updatedToolCall = { ...toolCall };\n const actionType = { ...toolCall.actionType };\n\n updatedToolCall.status = isError ? 'failed' : 'success';\n updatedToolCall.completedAt = new Date().toISOString();\n updatedToolCall.isError = isError;\n\n if (actionType.action === 'command_run') {\n const result = parseCommandResult(content);\n (actionType as typeof actionType).result = result;\n if (result.exitCode !== undefined && result.exitCode !== 0) {\n updatedToolCall.status = 'failed';\n updatedToolCall.isError = true;\n }\n } else if (actionType.action === 'mcp_tool' || actionType.action === 'generic_tool') {\n (actionType as typeof actionType).result = normalizeToolResult(content);\n }\n\n updatedToolCall.actionType = actionType;\n return updatedToolCall;\n}\n\n// =============================================================================\n// Display Helpers\n// =============================================================================\n\n/**\n * Get display icon name for an action type\n */\nexport function getActionIcon(actionType: ActionType): string {\n switch (actionType.action) {\n case 'command_run':\n return 'terminal';\n case 'file_read':\n return 'file-text';\n case 'file_edit':\n return 'edit';\n case 'file_write':\n return 'file-plus';\n case 'search':\n return 'search';\n case 'glob':\n return 'folder-search';\n case 'web_fetch':\n return 'globe';\n case 'web_search':\n return 'search';\n case 'mcp_tool':\n return 'plug';\n case 'generic_tool':\n return 'tool';\n case 'todo_write':\n return 'list-checks';\n default:\n return 'tool';\n }\n}\n\n/**\n * Get display label for an action type\n */\nexport function getActionLabel(actionType: ActionType): string {\n switch (actionType.action) {\n case 'command_run':\n return 'Command';\n case 'file_read':\n return 'Read';\n case 'file_edit':\n return 'Edit';\n case 'file_write':\n return 'Write';\n case 'search':\n return 'Search';\n case 'glob':\n return 'Glob';\n case 'web_fetch':\n return 'Fetch';\n case 'web_search':\n return 'Search';\n case 'mcp_tool':\n return 'MCP';\n case 'generic_tool':\n return 'Tool';\n case 'todo_write':\n return 'Tasks';\n default:\n return 'Tool';\n }\n}\n\n// =============================================================================\n// Formatting Helpers\n// =============================================================================\n\n/**\n * Format a file size in bytes to a human-readable string\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n/**\n * Format a timestamp to a locale time string\n */\nexport function formatTimestamp(timestamp: string): string {\n try {\n const date = new Date(timestamp);\n return date.toLocaleTimeString('en-US', {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n });\n } catch {\n return timestamp;\n }\n}\n\n/**\n * Truncate a string with ellipsis\n */\nexport function truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str;\n return str.substring(0, maxLength - 3) + '...';\n}\n\n/**\n * Join class names, filtering out falsy values\n */\nexport function cn(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(' ');\n}\n\n// =============================================================================\n// Entry Grouping for Compact Mode\n// =============================================================================\n\n/**\n * A grouped entry that contains either a single entry or a group of consecutive tool calls\n */\nexport type GroupedEntry =\n | { type: 'single'; entry: NormalizedEntry }\n | { type: 'tool_group'; entries: NormalizedEntry[]; id: string };\n\n/**\n * Group consecutive tool call entries together based on display config.\n *\n * This is used in compact mode to merge consecutive tool calls into\n * a single ToolExecutionGroup, while keeping text content separate.\n *\n * @param entries - Array of normalized entries\n * @param config - Display configuration (uses breakEveryNToolCalls)\n * @returns Array of grouped entries\n */\nexport function groupEntriesForCompactMode(\n entries: NormalizedEntry[],\n config: ToolDisplayConfig\n): GroupedEntry[] {\n const result: GroupedEntry[] = [];\n let currentToolGroup: NormalizedEntry[] = [];\n let toolGroupCounter = 0;\n\n const flushToolGroup = () => {\n if (currentToolGroup.length > 0) {\n result.push({\n type: 'tool_group',\n entries: [...currentToolGroup],\n id: `tool-group-${toolGroupCounter++}`,\n });\n currentToolGroup = [];\n }\n };\n\n for (const entry of entries) {\n if (entry.entryType.type === 'tool_call') {\n currentToolGroup.push(entry);\n\n // Check if we should break the group\n if (\n config.breakEveryNToolCalls &&\n config.breakEveryNToolCalls > 0 &&\n currentToolGroup.length >= config.breakEveryNToolCalls\n ) {\n flushToolGroup();\n }\n } else {\n // Non-tool-call entry - flush any pending tool group\n flushToolGroup();\n result.push({ type: 'single', entry });\n }\n }\n\n // Flush any remaining tool group\n flushToolGroup();\n\n return result;\n}\n\n/**\n * Extract tool calls from a group of entries\n */\nexport function extractToolCallsFromGroup(entries: NormalizedEntry[]): NormalizedToolCall[] {\n return entries\n .filter((e): e is NormalizedEntry & { entryType: { type: 'tool_call'; toolCall: NormalizedToolCall } } =>\n e.entryType.type === 'tool_call'\n )\n .map((e) => e.entryType.toolCall);\n}\n\n// =============================================================================\n// Option Parsing\n// =============================================================================\n\n/**\n * A parsed option from assistant message content\n */\nexport interface ParsedOption {\n /** Option identifier (e.g., \"1\", \"2\", \"A\", \"B\") */\n id: string;\n /** Option title/label */\n label: string;\n /** Optional description text */\n description?: string;\n}\n\n/**\n * Result of parsing options from content\n */\nexport interface ParsedOptionsResult {\n /** Text before the options */\n preamble: string;\n /** Parsed options */\n options: ParsedOption[];\n}\n\n/**\n * Parse options from assistant message content.\n * Detects patterns like:\n * - \"Option 1: Title\" / \"Option 2: Title\"\n * - \"**Option 1:** Title\" (bold markdown)\n * - Numbered lists with descriptions\n *\n * @returns ParsedOptionsResult if options found, null otherwise\n */\nexport function parseOptionsFromContent(content: string): ParsedOptionsResult | null {\n // Pattern 1: \"Option N:\" format (with or without bold markdown)\n // Matches: \"Option 1:\", \"**Option 1:**\", \"Option 1 -\", etc.\n const optionPattern = /(?:\\*\\*)?Option\\s+(\\d+)(?:\\*\\*)?[:\\-]\\s*([^\\n]+)(?:\\n((?:(?!\\n(?:\\*\\*)?Option\\s+\\d).)*?))?/gi;\n\n const options: ParsedOption[] = [];\n let firstMatchStart = -1;\n let match: RegExpExecArray | null;\n\n // Reset regex\n optionPattern.lastIndex = 0;\n\n while ((match = optionPattern.exec(content)) !== null) {\n if (firstMatchStart === -1) {\n firstMatchStart = match.index;\n }\n\n const id = match[1] ?? '';\n const labelRaw = match[2];\n const label = labelRaw ? labelRaw.trim() : '';\n // Description is everything after the label until the next option\n const descriptionRaw = match[3];\n\n // Clean up description - remove leading/trailing whitespace and normalize\n let description: string | undefined;\n if (descriptionRaw) {\n const cleaned = descriptionRaw\n .split('\\n')\n .map(line => line.trim())\n .filter(line => line.length > 0)\n .join(' ');\n if (cleaned) {\n description = cleaned;\n }\n }\n\n options.push({ id, label, description });\n }\n\n // Need at least 2 options to be considered a valid options list\n if (options.length >= 2) {\n const preamble = firstMatchStart > 0\n ? content.substring(0, firstMatchStart).trim()\n : '';\n\n return { preamble, options };\n }\n\n // Pattern 2: Simple numbered list at end of message\n // Look for \"What would you like to do?\" or similar followed by numbered items\n const questionPattern = /^(.*?(?:what would you like to do\\??|choose an option|select.*?:|here are your options.*?:))\\s*\\n+((?:\\d+\\.\\s+.+\\n?)+)/ims;\n const questionMatch = content.match(questionPattern);\n\n if (questionMatch && questionMatch[1] && questionMatch[2]) {\n const preamble = questionMatch[1].trim();\n const listSection = questionMatch[2];\n\n // Parse numbered list items\n const listPattern = /(\\d+)\\.\\s+([^\\n]+)/g;\n let listMatch: RegExpExecArray | null;\n\n while ((listMatch = listPattern.exec(listSection)) !== null) {\n const listId = listMatch[1] ?? '';\n const listLabelRaw = listMatch[2];\n const listLabel = listLabelRaw ? listLabelRaw.trim() : '';\n options.push({\n id: listId,\n label: listLabel,\n });\n }\n\n if (options.length >= 2) {\n return { preamble, options };\n }\n }\n\n return null;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils.ts"],"names":[],"mappings":";;;AAyBO,SAAS,eAAe,IAAA,EAAsB;AACnD,EAAA,IAAI,IAAA,CAAK,UAAA,CAAW,OAAO,CAAA,EAAG;AAC5B,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAC7B,IAAA,IAAI,KAAA,CAAM,UAAU,CAAA,EAAG;AACrB,MAAA,OAAO,CAAA,IAAA,EAAO,KAAA,CAAM,CAAC,CAAC,CAAA,CAAA,EAAI,KAAA,CAAM,KAAA,CAAM,CAAC,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA;AAAA,IACpD;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AAKO,SAAS,iBAAiB,IAAA,EAA+D;AAC9F,EAAA,IAAI,IAAA,CAAK,UAAA,CAAW,OAAO,CAAA,EAAG;AAC5B,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAC7B,IAAA,IAAI,MAAM,MAAA,IAAU,CAAA,IAAK,KAAA,CAAM,CAAC,MAAM,MAAA,EAAW;AAC/C,MAAA,OAAO;AAAA,QACL,UAAA,EAAY,MAAM,CAAC,CAAA;AAAA,QACnB,UAAU,KAAA,CAAM,KAAA,CAAM,CAAC,CAAA,CAAE,KAAK,IAAI;AAAA,OACpC;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AASO,SAAS,mBAAA,CAAoB,UAAkB,KAAA,EAA4B;AAChF,EAAA,MAAM,QAAA,GAAY,SAAqC,EAAC;AAExD,EAAA,QAAQ,QAAA;AAAU,IAChB,KAAK,MAAA;AACH,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,aAAA;AAAA,QACR,OAAA,EAAU,SAAS,OAAA,IAAsB,EAAA;AAAA,QACzC,aAAa,QAAA,CAAS;AAAA,OACxB;AAAA,IAEF,KAAK,MAAA,EAAQ;AACX,MAAA,MAAM,QAAQ,QAAA,CAAS,KAAA;AACvB,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,WAAA;AAAA,QACR,IAAA,EAAO,SAAS,SAAA,IAAwB,EAAA;AAAA,QACxC,QAAQ,QAAA,CAAS,MAAA;AAAA,QACjB,KAAA;AAAA,QACA,SAAA,EAAW;AAAA;AAAA,OACb;AAAA,IACF;AAAA,IAEA,KAAK,MAAA,EAAQ;AACX,MAAA,MAAM,SAAS,QAAA,CAAS,UAAA;AACxB,MAAA,MAAM,SAAS,QAAA,CAAS,UAAA;AAExB,MAAA,MAAM,WAAW,MAAA,GAAS,MAAA,CAAO,KAAA,CAAM,IAAI,EAAE,MAAA,GAAS,CAAA;AACtD,MAAA,MAAM,WAAW,MAAA,GAAS,MAAA,CAAO,KAAA,CAAM,IAAI,EAAE,MAAA,GAAS,CAAA;AACtD,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,WAAA;AAAA,QACR,IAAA,EAAO,SAAS,SAAA,IAAwB,EAAA;AAAA,QACxC,SAAA,EAAW,MAAA;AAAA,QACX,SAAA,EAAW,MAAA;AAAA,QACX,YAAY,QAAA,CAAS,WAAA;AAAA,QACrB,UAAA,EAAY,QAAA;AAAA,QACZ,YAAA,EAAc;AAAA,OAChB;AAAA,IACF;AAAA,IAEA,KAAK,OAAA,EAAS;AACZ,MAAA,MAAM,UAAU,QAAA,CAAS,OAAA;AACzB,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,YAAA;AAAA,QACR,IAAA,EAAO,SAAS,SAAA,IAAwB,EAAA;AAAA,QACxC,OAAA;AAAA,QACA,cAAc,OAAA,GAAU,OAAA,CAAQ,KAAA,CAAM,IAAI,EAAE,MAAA,GAAS;AAAA,OACvD;AAAA,IACF;AAAA,IAEA,KAAK,MAAA;AACH,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,QAAA;AAAA,QACR,OAAA,EAAU,SAAS,OAAA,IAAsB,EAAA;AAAA,QACzC,MAAM,QAAA,CAAS,IAAA;AAAA,QACf,MAAM,QAAA,CAAS,IAAA;AAAA,QACf,MAAM,QAAA,CAAS;AAAA,OACjB;AAAA,IAEF,KAAK,MAAA;AACH,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAU,SAAS,OAAA,IAAsB,EAAA;AAAA,QACzC,MAAM,QAAA,CAAS;AAAA,OACjB;AAAA,IAEF,KAAK,UAAA;AACH,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,WAAA;AAAA,QACR,GAAA,EAAM,SAAS,GAAA,IAAkB,EAAA;AAAA,QACjC,QAAQ,QAAA,CAAS;AAAA,OACnB;AAAA,IAEF,KAAK,WAAA;AACH,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,YAAA;AAAA,QACR,KAAA,EAAQ,SAAS,KAAA,IAAoB;AAAA,OACvC;AAAA,IAEF,KAAK,WAAA,EAAa;AAChB,MAAA,MAAM,KAAA,GAAS,QAAA,CAAS,KAAA,IAAwB,EAAC;AACjD,MAAA,MAAM,KAAA,GAAQ;AAAA,QACZ,OAAO,KAAA,CAAM,MAAA;AAAA,QACb,SAAA,EAAW,MAAM,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,WAAW,CAAA,CAAE,MAAA;AAAA,QACzD,UAAA,EAAY,MAAM,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,aAAa,CAAA,CAAE,MAAA;AAAA,QAC5D,OAAA,EAAS,MAAM,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,SAAS,CAAA,CAAE;AAAA,OACvD;AACA,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,YAAA;AAAA,QACR,KAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAAA,IAEA,KAAK,MAAA,EAAQ;AACX,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,YAAA;AAAA,QACR,SAAA,EAAY,SAAS,aAAA,IAA4B,iBAAA;AAAA,QACjD,WAAA,EAAc,SAAS,WAAA,IAA0B,EAAA;AAAA,QACjD,QAAQ,QAAA,CAAS,MAAA;AAAA,QACjB,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAAA,QAClC,aAAA,EAAe;AAAA,OACjB;AAAA,IACF;AAAA,IAEA,SAAS;AAEP,MAAA,MAAM,QAAA,GAAW,iBAAiB,QAAQ,CAAA;AAC1C,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,OAAO;AAAA,UACL,MAAA,EAAQ,UAAA;AAAA,UACR,YAAY,QAAA,CAAS,UAAA;AAAA,UACrB,UAAU,QAAA,CAAS,QAAA;AAAA,UACnB,SAAA,EAAW;AAAA,SACb;AAAA,MACF;AAGA,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,cAAA;AAAA,QACR,QAAA,EAAU,eAAe,QAAQ,CAAA;AAAA,QACjC,SAAA,EAAW;AAAA,OACb;AAAA,IACF;AAAA;AAEJ;AASO,SAAS,mBAAA,CACd,SAAA,EACA,MAAA,EACA,UAAA,EACQ;AACR,EAAA,QAAQ,WAAW,MAAA;AAAQ,IACzB,KAAK,aAAA,EAAe;AAClB,MAAA,MAAM,MAAM,UAAA,CAAW,OAAA;AACvB,MAAA,OAAO,GAAA,CAAI,SAAS,EAAA,GAAK,GAAA,CAAI,UAAU,CAAA,EAAG,EAAE,IAAI,KAAA,GAAQ,GAAA;AAAA,IAC1D;AAAA,IAEA,KAAK,WAAA;AACH,MAAA,OAAO,UAAA,CAAW,IAAA;AAAA,IAEpB,KAAK,WAAA;AACH,MAAA,OAAO,UAAA,CAAW,IAAA;AAAA,IAEpB,KAAK,YAAA;AACH,MAAA,OAAO,UAAA,CAAW,IAAA;AAAA,IAEpB,KAAK,QAAA;AACH,MAAA,OAAO,CAAA,EAAG,UAAA,CAAW,OAAO,CAAA,EAAG,UAAA,CAAW,OAAO,CAAA,IAAA,EAAO,UAAA,CAAW,IAAI,CAAA,CAAA,GAAK,EAAE,CAAA,CAAA;AAAA,IAEhF,KAAK,MAAA;AACH,MAAA,OAAO,UAAA,CAAW,OAAA;AAAA,IAEpB,KAAK,WAAA;AACH,MAAA,OAAO,UAAA,CAAW,GAAA;AAAA,IAEpB,KAAK,YAAA;AACH,MAAA,OAAO,UAAA,CAAW,KAAA;AAAA,IAEpB,KAAK,UAAA;AACH,MAAA,OAAO,CAAA,EAAG,UAAA,CAAW,UAAU,CAAA,CAAA,EAAI,WAAW,QAAQ,CAAA,CAAA;AAAA,IAExD,KAAK,cAAA;AACH,MAAA,OAAO,UAAA,CAAW,QAAA;AAAA,IAEpB,KAAK,YAAA,EAAc;AACjB,MAAA,MAAM,EAAE,OAAM,GAAI,UAAA;AAClB,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,OAAO,CAAA,EAAG,KAAA,CAAM,SAAS,CAAA,CAAA,EAAI,MAAM,KAAK,CAAA,UAAA,CAAA;AAAA,MAC1C;AACA,MAAA,OAAO,CAAA,EAAG,UAAA,CAAW,KAAA,CAAM,MAAM,CAAA,MAAA,CAAA;AAAA,IACnC;AAAA,IAEA,KAAK,YAAA;AACH,MAAA,OAAO,UAAA,CAAW,WAAA;AAAA,IAEpB;AACE,MAAA,OAAO,cAAA;AAAA;AAEb;AASO,SAAS,mBAAmB,OAAA,EAA0B;AAC3D,EAAA,IAAI,OAAO,OAAA,KAAY,QAAA,EAAU,OAAO,OAAA;AAExC,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,EAAG;AAC1B,IAAA,OAAO,QACJ,MAAA,CAAO,CAAC,IAAA,KAAmC,OAAO,MAAM,IAAA,KAAS,QAAQ,CAAA,CACzE,GAAA,CAAI,CAAC,IAAA,KAAS,IAAA,CAAK,IAAI,CAAA,CACvB,KAAK,IAAI,CAAA;AAAA,EACd;AAEA,EAAA,IAAI,OAAA,IAAW,OAAO,OAAA,KAAY,QAAA,IAAY,UAAU,OAAA,EAAS;AAC/D,IAAA,OAAO,MAAA,CAAQ,QAA8B,IAAI,CAAA;AAAA,EACnD;AAEA,EAAA,OAAO,IAAA,CAAK,SAAA,CAAU,OAAA,EAAS,IAAA,EAAM,CAAC,CAAA;AACxC;AAKO,SAAS,oBAAoB,OAAA,EAA8B;AAChE,EAAA,IAAI,OAAO,YAAY,QAAA,EAAU;AAC/B,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA;AACjC,MAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAO;AAAA,IACvC,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,EAAE,IAAA,EAAM,UAAA,EAAY,KAAA,EAAO,OAAA,EAAQ;AAAA,IAC5C;AAAA,EACF;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,EAAG;AAC1B,IAAA,MAAM,QAAQ,OAAA,CACX,MAAA;AAAA,MACC,CAAC,IAAA,KACC,IAAA,EAAM,SAAS,MAAA,IAAU,OAAO,KAAK,IAAA,KAAS;AAAA,KAClD,CACC,GAAA,CAAI,CAAC,IAAA,KAAS,KAAK,IAAI,CAAA;AAE1B,IAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpB,MAAA,MAAM,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,MAAM,CAAA;AAChC,MAAA,IAAI;AACF,QAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,OAAO,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA,EAAE;AAAA,MACnD,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,EAAE,IAAA,EAAM,UAAA,EAAY,KAAA,EAAO,MAAA,EAAO;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,KAAA,EAAO,OAAA,EAAQ;AACxC;AAKO,SAAS,mBAAmB,OAAA,EAAoC;AACrE,EAAA,MAAM,MAAA,GAAS,mBAAmB,OAAO,CAAA;AAEzC,EAAA,IAAI,OAAO,YAAY,QAAA,EAAU;AAC/B,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA;AACjC,MAAA,IAAI,OAAO,MAAA,CAAO,QAAA,KAAa,QAAA,EAAU;AACvC,QAAA,OAAO;AAAA,UACL,UAAU,MAAA,CAAO,QAAA;AAAA,UACjB,MAAA,EAAQ,OAAO,MAAA,IAAU,MAAA;AAAA,UACzB,OAAA,EAAS,OAAO,QAAA,KAAa;AAAA,SAC/B;AAAA,MACF;AAAA,IACF,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,MAAA;AAAA,IACA,OAAA,EAAS;AAAA,GACX;AACF;AAeO,SAAS,eAAe,OAAA,EAA2C;AACxE,EAAA,MAAM,UAAA,GAAa,mBAAA,CAAoB,OAAA,CAAQ,IAAA,EAAM,QAAQ,KAAK,CAAA;AAClE,EAAA,MAAM,UAAU,mBAAA,CAAoB,OAAA,CAAQ,IAAA,EAAM,OAAA,CAAQ,OAAO,UAAU,CAAA;AAE3E,EAAA,OAAO;AAAA,IACL,IAAI,OAAA,CAAQ,EAAA;AAAA,IACZ,UAAU,OAAA,CAAQ,IAAA;AAAA,IAClB,UAAA;AAAA,IACA,MAAA,EAAQ,SAAA;AAAA,IACR,OAAA;AAAA,IACA,OAAO,OAAA,CAAQ,KAAA;AAAA,IACf,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,GACpC;AACF;AAKO,SAAS,wBAAA,CACd,QAAA,EACA,OAAA,EACA,OAAA,EACoB;AACpB,EAAA,MAAM,eAAA,GAAkB,EAAE,GAAG,QAAA,EAAS;AACtC,EAAA,MAAM,UAAA,GAAa,EAAE,GAAG,QAAA,CAAS,UAAA,EAAW;AAE5C,EAAA,eAAA,CAAgB,MAAA,GAAS,UAAU,QAAA,GAAW,SAAA;AAC9C,EAAA,eAAA,CAAgB,WAAA,GAAA,iBAAc,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AACrD,EAAA,eAAA,CAAgB,OAAA,GAAU,OAAA;AAC1B,EAAA,eAAA,CAAgB,MAAA,GAAS,OAAA;AAEzB,EAAA,IAAI,UAAA,CAAW,WAAW,aAAA,EAAe;AACvC,IAAA,MAAM,MAAA,GAAS,mBAAmB,OAAO,CAAA;AACzC,IAAC,WAAiC,MAAA,GAAS,MAAA;AAC3C,IAAA,IAAI,MAAA,CAAO,QAAA,KAAa,MAAA,IAAa,MAAA,CAAO,aAAa,CAAA,EAAG;AAC1D,MAAA,eAAA,CAAgB,MAAA,GAAS,QAAA;AACzB,MAAA,eAAA,CAAgB,OAAA,GAAU,IAAA;AAAA,IAC5B;AAAA,EACF,WAAW,UAAA,CAAW,MAAA,KAAW,UAAA,IAAc,UAAA,CAAW,WAAW,cAAA,EAAgB;AACnF,IAAC,UAAA,CAAiC,MAAA,GAAS,mBAAA,CAAoB,OAAO,CAAA;AAAA,EACxE;AAEA,EAAA,eAAA,CAAgB,UAAA,GAAa,UAAA;AAC7B,EAAA,OAAO,eAAA;AACT;AASO,SAAS,cAAc,UAAA,EAAgC;AAC5D,EAAA,QAAQ,WAAW,MAAA;AAAQ,IACzB,KAAK,aAAA;AACH,MAAA,OAAO,UAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,OAAO,WAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,YAAA;AACH,MAAA,OAAO,WAAA;AAAA,IACT,KAAK,QAAA;AACH,MAAA,OAAO,QAAA;AAAA,IACT,KAAK,MAAA;AACH,MAAA,OAAO,eAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,OAAO,OAAA;AAAA,IACT,KAAK,YAAA;AACH,MAAA,OAAO,QAAA;AAAA,IACT,KAAK,UAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,cAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,YAAA;AACH,MAAA,OAAO,aAAA;AAAA,IACT,KAAK,YAAA;AACH,MAAA,OAAO,KAAA;AAAA,IACT;AACE,MAAA,OAAO,MAAA;AAAA;AAEb;AAKO,SAAS,eAAe,UAAA,EAAgC;AAC7D,EAAA,QAAQ,WAAW,MAAA;AAAQ,IACzB,KAAK,aAAA;AACH,MAAA,OAAO,SAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,YAAA;AACH,MAAA,OAAO,OAAA;AAAA,IACT,KAAK,QAAA;AACH,MAAA,OAAO,QAAA;AAAA,IACT,KAAK,MAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,WAAA;AACH,MAAA,OAAO,OAAA;AAAA,IACT,KAAK,YAAA;AACH,MAAA,OAAO,QAAA;AAAA,IACT,KAAK,UAAA;AACH,MAAA,OAAO,KAAA;AAAA,IACT,KAAK,cAAA;AACH,MAAA,OAAO,MAAA;AAAA,IACT,KAAK,YAAA;AACH,MAAA,OAAO,OAAA;AAAA,IACT,KAAK,YAAA;AACH,MAAA,OAAQ,UAAA,CAA+B,SAAA;AAAA,IACzC;AACE,MAAA,OAAO,MAAA;AAAA;AAEb;AASO,SAAS,eAAe,KAAA,EAAuB;AACpD,EAAA,IAAI,KAAA,GAAQ,IAAA,EAAM,OAAO,CAAA,EAAG,KAAK,CAAA,EAAA,CAAA;AACjC,EAAA,IAAI,KAAA,GAAQ,OAAO,IAAA,EAAM,OAAO,IAAI,KAAA,GAAQ,IAAA,EAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,GAAA,CAAA;AAC5D,EAAA,OAAO,IAAI,KAAA,IAAS,IAAA,GAAO,IAAA,CAAA,EAAO,OAAA,CAAQ,CAAC,CAAC,CAAA,GAAA,CAAA;AAC9C;AAKO,SAAS,gBAAgB,SAAA,EAA2B;AACzD,EAAA,IAAI;AACF,IAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,SAAS,CAAA;AAC/B,IAAA,OAAO,IAAA,CAAK,mBAAmB,OAAA,EAAS;AAAA,MACtC,IAAA,EAAM,SAAA;AAAA,MACN,MAAA,EAAQ,SAAA;AAAA,MACR,MAAA,EAAQ,SAAA;AAAA,MACR,MAAA,EAAQ;AAAA,KACT,CAAA;AAAA,EACH,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,SAAA;AAAA,EACT;AACF;AAQO,SAAS,iBAAA,CAAkB,WAA0B,OAAA,EAAiC;AAC3F,EAAA,MAAM,QAAQ,OAAO,SAAA,KAAc,WAAW,IAAI,IAAA,CAAK,SAAS,CAAA,GAAI,SAAA;AACpE,EAAA,MAAM,GAAA,GAAM,OAAA,GAAW,OAAO,OAAA,KAAY,QAAA,GAAW,IAAI,IAAA,CAAK,OAAO,CAAA,GAAI,OAAA,mBAAW,IAAI,IAAA,EAAK;AAE7F,EAAA,MAAM,SAAA,GAAY,GAAA,CAAI,OAAA,EAAQ,GAAI,MAAM,OAAA,EAAQ;AAChD,EAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,KAAA,CAAM,SAAA,GAAY,GAAI,CAAA;AAElD,EAAA,IAAI,iBAAiB,EAAA,EAAI;AACvB,IAAA,OAAO,GAAG,cAAc,CAAA,CAAA,CAAA;AAAA,EAC1B;AAEA,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,KAAA,CAAM,cAAA,GAAiB,EAAE,CAAA;AAC9C,EAAA,MAAM,UAAU,cAAA,GAAiB,EAAA;AAEjC,EAAA,IAAI,YAAY,CAAA,EAAG;AACjB,IAAA,OAAO,GAAG,OAAO,CAAA,CAAA,CAAA;AAAA,EACnB;AAEA,EAAA,OAAO,CAAA,EAAG,OAAO,CAAA,EAAA,EAAK,OAAO,CAAA,CAAA,CAAA;AAC/B;AAKO,SAAS,QAAA,CAAS,KAAa,SAAA,EAA2B;AAC/D,EAAA,IAAI,GAAA,CAAI,MAAA,IAAU,SAAA,EAAW,OAAO,GAAA;AACpC,EAAA,OAAO,GAAA,CAAI,SAAA,CAAU,CAAA,EAAG,SAAA,GAAY,CAAC,CAAA,GAAI,KAAA;AAC3C;AAKO,SAAS,MAAM,OAAA,EAAwD;AAC5E,EAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,GAAG,CAAA;AACzC;AAuBO,SAAS,0BAAA,CACd,SACA,MAAA,EACgB;AAChB,EAAA,MAAM,SAAyB,EAAC;AAChC,EAAA,IAAI,mBAAsC,EAAC;AAC3C,EAAA,IAAI,gBAAA,GAAmB,CAAA;AAEvB,EAAA,MAAM,iBAAiB,MAAM;AAC3B,IAAA,IAAI,gBAAA,CAAiB,SAAS,CAAA,EAAG;AAC/B,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,IAAA,EAAM,YAAA;AAAA,QACN,OAAA,EAAS,CAAC,GAAG,gBAAgB,CAAA;AAAA,QAC7B,EAAA,EAAI,cAAc,gBAAA,EAAkB,CAAA;AAAA,OACrC,CAAA;AACD,MAAA,gBAAA,GAAmB,EAAC;AAAA,IACtB;AAAA,EACF,CAAA;AAEA,EAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,IAAA,IAAI,KAAA,CAAM,SAAA,CAAU,IAAA,KAAS,WAAA,EAAa;AACxC,MAAA,gBAAA,CAAiB,KAAK,KAAK,CAAA;AAG3B,MAAA,IACE,MAAA,CAAO,wBACP,MAAA,CAAO,oBAAA,GAAuB,KAC9B,gBAAA,CAAiB,MAAA,IAAU,OAAO,oBAAA,EAClC;AACA,QAAA,cAAA,EAAe;AAAA,MACjB;AAAA,IACF,CAAA,MAAO;AAEL,MAAA,cAAA,EAAe;AACf,MAAA,MAAA,CAAO,IAAA,CAAK,EAAE,IAAA,EAAM,QAAA,EAAU,OAAO,CAAA;AAAA,IACvC;AAAA,EACF;AAGA,EAAA,cAAA,EAAe;AAEf,EAAA,OAAO,MAAA;AACT;AAKO,SAAS,0BAA0B,OAAA,EAAkD;AAC1F,EAAA,OAAO,OAAA,CACJ,MAAA;AAAA,IAAO,CAAC,CAAA,KACP,CAAA,CAAE,SAAA,CAAU,IAAA,KAAS;AAAA,IAEtB,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,UAAU,QAAQ,CAAA;AACpC;AAqCO,SAAS,wBAAwB,OAAA,EAA6C;AAGnF,EAAA,MAAM,aAAA,GAAgB,8FAAA;AAEtB,EAAA,MAAM,UAA0B,EAAC;AACjC,EAAA,IAAI,eAAA,GAAkB,EAAA;AACtB,EAAA,IAAI,KAAA;AAGJ,EAAA,aAAA,CAAc,SAAA,GAAY,CAAA;AAE1B,EAAA,OAAA,CAAQ,KAAA,GAAQ,aAAA,CAAc,IAAA,CAAK,OAAO,OAAO,IAAA,EAAM;AACrD,IAAA,IAAI,oBAAoB,EAAA,EAAI;AAC1B,MAAA,eAAA,GAAkB,KAAA,CAAM,KAAA;AAAA,IAC1B;AAEA,IAAA,MAAM,EAAA,GAAK,KAAA,CAAM,CAAC,CAAA,IAAK,EAAA;AACvB,IAAA,MAAM,QAAA,GAAW,MAAM,CAAC,CAAA;AACxB,IAAA,MAAM,KAAA,GAAQ,QAAA,GAAW,QAAA,CAAS,IAAA,EAAK,GAAI,EAAA;AAE3C,IAAA,MAAM,cAAA,GAAiB,MAAM,CAAC,CAAA;AAG9B,IAAA,IAAI,WAAA;AACJ,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,MAAM,UAAU,cAAA,CACb,KAAA,CAAM,IAAI,CAAA,CACV,GAAA,CAAI,UAAQ,IAAA,CAAK,IAAA,EAAM,CAAA,CACvB,OAAO,CAAA,IAAA,KAAQ,IAAA,CAAK,SAAS,CAAC,CAAA,CAC9B,KAAK,GAAG,CAAA;AACX,MAAA,IAAI,OAAA,EAAS;AACX,QAAA,WAAA,GAAc,OAAA;AAAA,MAChB;AAAA,IACF;AAEA,IAAA,OAAA,CAAQ,IAAA,CAAK,EAAE,EAAA,EAAI,KAAA,EAAO,aAAa,CAAA;AAAA,EACzC;AAGA,EAAA,IAAI,OAAA,CAAQ,UAAU,CAAA,EAAG;AACvB,IAAA,MAAM,QAAA,GAAW,kBAAkB,CAAA,GAC/B,OAAA,CAAQ,UAAU,CAAA,EAAG,eAAe,CAAA,CAAE,IAAA,EAAK,GAC3C,EAAA;AAEJ,IAAA,OAAO,EAAE,UAAU,OAAA,EAAQ;AAAA,EAC7B;AAIA,EAAA,MAAM,eAAA,GAAkB,2HAAA;AACxB,EAAA,MAAM,aAAA,GAAgB,OAAA,CAAQ,KAAA,CAAM,eAAe,CAAA;AAEnD,EAAA,IAAI,iBAAiB,aAAA,CAAc,CAAC,CAAA,IAAK,aAAA,CAAc,CAAC,CAAA,EAAG;AACzD,IAAA,MAAM,QAAA,GAAW,aAAA,CAAc,CAAC,CAAA,CAAE,IAAA,EAAK;AACvC,IAAA,MAAM,WAAA,GAAc,cAAc,CAAC,CAAA;AAGnC,IAAA,MAAM,WAAA,GAAc,qBAAA;AACpB,IAAA,IAAI,SAAA;AAEJ,IAAA,OAAA,CAAQ,SAAA,GAAY,WAAA,CAAY,IAAA,CAAK,WAAW,OAAO,IAAA,EAAM;AAC3D,MAAA,MAAM,MAAA,GAAS,SAAA,CAAU,CAAC,CAAA,IAAK,EAAA;AAC/B,MAAA,MAAM,YAAA,GAAe,UAAU,CAAC,CAAA;AAChC,MAAA,MAAM,SAAA,GAAY,YAAA,GAAe,YAAA,CAAa,IAAA,EAAK,GAAI,EAAA;AACvD,MAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,QACX,EAAA,EAAI,MAAA;AAAA,QACJ,KAAA,EAAO;AAAA,OACR,CAAA;AAAA,IACH;AAEA,IAAA,IAAI,OAAA,CAAQ,UAAU,CAAA,EAAG;AACvB,MAAA,OAAO,EAAE,UAAU,OAAA,EAAQ;AAAA,IAC7B;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT","file":"utils.cjs","sourcesContent":["/**\n * @ash-cloud/ash-ui - Utilities\n *\n * Utility functions for normalizing and formatting tool calls\n * for display in agentic UIs.\n */\n\nimport type {\n ActionType,\n ToolResult,\n CommandRunResult,\n NormalizedToolCall,\n NormalizedEntry,\n ToolDisplayConfig,\n TodoItem,\n AgentToolAction,\n} from './types';\n\n// =============================================================================\n// Tool Name Formatting\n// =============================================================================\n\n/**\n * Format MCP tool names from mcp__server__tool to mcp:server:tool\n */\nexport function formatToolName(name: string): string {\n if (name.startsWith('mcp__')) {\n const parts = name.split('__');\n if (parts.length >= 3) {\n return `mcp:${parts[1]}:${parts.slice(2).join(':')}`;\n }\n }\n return name;\n}\n\n/**\n * Parse MCP tool name to extract server and tool names\n */\nexport function parseMcpToolName(name: string): { serverName: string; toolName: string } | null {\n if (name.startsWith('mcp__')) {\n const parts = name.split('__');\n if (parts.length >= 3 && parts[1] !== undefined) {\n return {\n serverName: parts[1],\n toolName: parts.slice(2).join('__'),\n };\n }\n }\n return null;\n}\n\n// =============================================================================\n// Action Type Mapping\n// =============================================================================\n\n/**\n * Map a tool name and input to a structured ActionType\n */\nexport function mapToolToActionType(toolName: string, input: unknown): ActionType {\n const inputObj = (input as Record<string, unknown>) || {};\n\n switch (toolName) {\n case 'Bash':\n return {\n action: 'command_run',\n command: (inputObj.command as string) || '',\n description: inputObj.description as string | undefined,\n };\n\n case 'Read': {\n const limit = inputObj.limit as number | undefined;\n return {\n action: 'file_read',\n path: (inputObj.file_path as string) || '',\n offset: inputObj.offset as number | undefined,\n limit,\n linesRead: limit, // Use limit as approximate lines read if specified\n };\n }\n\n case 'Edit': {\n const oldStr = inputObj.old_string as string | undefined;\n const newStr = inputObj.new_string as string | undefined;\n // Calculate line diff stats\n const oldLines = oldStr ? oldStr.split('\\n').length : 0;\n const newLines = newStr ? newStr.split('\\n').length : 0;\n return {\n action: 'file_edit',\n path: (inputObj.file_path as string) || '',\n oldString: oldStr,\n newString: newStr,\n replaceAll: inputObj.replace_all as boolean | undefined,\n linesAdded: newLines,\n linesRemoved: oldLines,\n };\n }\n\n case 'Write': {\n const content = inputObj.content as string | undefined;\n return {\n action: 'file_write',\n path: (inputObj.file_path as string) || '',\n content,\n linesWritten: content ? content.split('\\n').length : undefined,\n };\n }\n\n case 'Grep':\n return {\n action: 'search',\n pattern: (inputObj.pattern as string) || '',\n path: inputObj.path as string | undefined,\n glob: inputObj.glob as string | undefined,\n type: inputObj.type as string | undefined,\n };\n\n case 'Glob':\n return {\n action: 'glob',\n pattern: (inputObj.pattern as string) || '',\n path: inputObj.path as string | undefined,\n };\n\n case 'WebFetch':\n return {\n action: 'web_fetch',\n url: (inputObj.url as string) || '',\n prompt: inputObj.prompt as string | undefined,\n };\n\n case 'WebSearch':\n return {\n action: 'web_search',\n query: (inputObj.query as string) || '',\n };\n\n case 'TodoWrite': {\n const todos = (inputObj.todos as TodoItem[]) || [];\n const stats = {\n total: todos.length,\n completed: todos.filter((t) => t.status === 'completed').length,\n inProgress: todos.filter((t) => t.status === 'in_progress').length,\n pending: todos.filter((t) => t.status === 'pending').length,\n };\n return {\n action: 'todo_write',\n todos,\n stats,\n };\n }\n\n case 'Task': {\n return {\n action: 'agent_tool',\n agentType: (inputObj.subagent_type as string) || 'general-purpose',\n description: (inputObj.description as string) || '',\n prompt: inputObj.prompt as string | undefined,\n startedAt: new Date().toISOString(),\n toolCallCount: 0,\n };\n }\n\n default: {\n // Check if it's an MCP tool\n const mcpParts = parseMcpToolName(toolName);\n if (mcpParts) {\n return {\n action: 'mcp_tool',\n serverName: mcpParts.serverName,\n toolName: mcpParts.toolName,\n arguments: input,\n };\n }\n\n // Generic tool\n return {\n action: 'generic_tool',\n toolName: formatToolName(toolName),\n arguments: input,\n };\n }\n }\n}\n\n// =============================================================================\n// Summary Generation\n// =============================================================================\n\n/**\n * Generate a human-readable summary for a tool call\n */\nexport function generateToolSummary(\n _toolName: string,\n _input: unknown,\n actionType: ActionType\n): string {\n switch (actionType.action) {\n case 'command_run': {\n const cmd = actionType.command;\n return cmd.length > 60 ? cmd.substring(0, 57) + '...' : cmd;\n }\n\n case 'file_read':\n return actionType.path;\n\n case 'file_edit':\n return actionType.path;\n\n case 'file_write':\n return actionType.path;\n\n case 'search':\n return `${actionType.pattern}${actionType.path ? ` in ${actionType.path}` : ''}`;\n\n case 'glob':\n return actionType.pattern;\n\n case 'web_fetch':\n return actionType.url;\n\n case 'web_search':\n return actionType.query;\n\n case 'mcp_tool':\n return `${actionType.serverName}:${actionType.toolName}`;\n\n case 'generic_tool':\n return actionType.toolName;\n\n case 'todo_write': {\n const { stats } = actionType;\n if (stats) {\n return `${stats.completed}/${stats.total} completed`;\n }\n return `${actionType.todos.length} tasks`;\n }\n\n case 'agent_tool':\n return actionType.description;\n\n default:\n return 'Unknown tool';\n }\n}\n\n// =============================================================================\n// Result Normalization\n// =============================================================================\n\n/**\n * Extract text content from various content formats\n */\nexport function extractTextContent(content: unknown): string {\n if (typeof content === 'string') return content;\n\n if (Array.isArray(content)) {\n return content\n .filter((item): item is { text: string } => typeof item?.text === 'string')\n .map((item) => item.text)\n .join('\\n');\n }\n\n if (content && typeof content === 'object' && 'text' in content) {\n return String((content as { text: unknown }).text);\n }\n\n return JSON.stringify(content, null, 2);\n}\n\n/**\n * Normalize tool result content to markdown or JSON format\n */\nexport function normalizeToolResult(content: unknown): ToolResult {\n if (typeof content === 'string') {\n try {\n const parsed = JSON.parse(content);\n return { type: 'json', value: parsed };\n } catch {\n return { type: 'markdown', value: content };\n }\n }\n\n if (Array.isArray(content)) {\n const texts = content\n .filter(\n (item): item is { type: 'text'; text: string } =>\n item?.type === 'text' && typeof item.text === 'string'\n )\n .map((item) => item.text);\n\n if (texts.length > 0) {\n const joined = texts.join('\\n\\n');\n try {\n return { type: 'json', value: JSON.parse(joined) };\n } catch {\n return { type: 'markdown', value: joined };\n }\n }\n }\n\n return { type: 'json', value: content };\n}\n\n/**\n * Parse command result from tool result content\n */\nexport function parseCommandResult(content: unknown): CommandRunResult {\n const output = extractTextContent(content);\n\n if (typeof content === 'string') {\n try {\n const parsed = JSON.parse(content);\n if (typeof parsed.exitCode === 'number') {\n return {\n exitCode: parsed.exitCode,\n output: parsed.output || output,\n success: parsed.exitCode === 0,\n };\n }\n } catch {\n // Not JSON, use raw output\n }\n }\n\n return {\n output,\n success: true,\n };\n}\n\n// =============================================================================\n// Tool Call Creation\n// =============================================================================\n\nexport interface ToolUseInput {\n id: string;\n name: string;\n input: unknown;\n}\n\n/**\n * Create a NormalizedToolCall from a tool_use content block\n */\nexport function createToolCall(toolUse: ToolUseInput): NormalizedToolCall {\n const actionType = mapToolToActionType(toolUse.name, toolUse.input);\n const summary = generateToolSummary(toolUse.name, toolUse.input, actionType);\n\n return {\n id: toolUse.id,\n toolName: toolUse.name,\n actionType,\n status: 'pending',\n summary,\n input: toolUse.input,\n startedAt: new Date().toISOString(),\n };\n}\n\n/**\n * Update a NormalizedToolCall with its result\n */\nexport function updateToolCallWithResult(\n toolCall: NormalizedToolCall,\n content: unknown,\n isError?: boolean\n): NormalizedToolCall {\n const updatedToolCall = { ...toolCall };\n const actionType = { ...toolCall.actionType };\n\n updatedToolCall.status = isError ? 'failed' : 'success';\n updatedToolCall.completedAt = new Date().toISOString();\n updatedToolCall.isError = isError;\n updatedToolCall.output = content;\n\n if (actionType.action === 'command_run') {\n const result = parseCommandResult(content);\n (actionType as typeof actionType).result = result;\n if (result.exitCode !== undefined && result.exitCode !== 0) {\n updatedToolCall.status = 'failed';\n updatedToolCall.isError = true;\n }\n } else if (actionType.action === 'mcp_tool' || actionType.action === 'generic_tool') {\n (actionType as typeof actionType).result = normalizeToolResult(content);\n }\n\n updatedToolCall.actionType = actionType;\n return updatedToolCall;\n}\n\n// =============================================================================\n// Display Helpers\n// =============================================================================\n\n/**\n * Get display icon name for an action type\n */\nexport function getActionIcon(actionType: ActionType): string {\n switch (actionType.action) {\n case 'command_run':\n return 'terminal';\n case 'file_read':\n return 'file-text';\n case 'file_edit':\n return 'edit';\n case 'file_write':\n return 'file-plus';\n case 'search':\n return 'search';\n case 'glob':\n return 'folder-search';\n case 'web_fetch':\n return 'globe';\n case 'web_search':\n return 'search';\n case 'mcp_tool':\n return 'plug';\n case 'generic_tool':\n return 'tool';\n case 'todo_write':\n return 'list-checks';\n case 'agent_tool':\n return 'bot';\n default:\n return 'tool';\n }\n}\n\n/**\n * Get display label for an action type\n */\nexport function getActionLabel(actionType: ActionType): string {\n switch (actionType.action) {\n case 'command_run':\n return 'Command';\n case 'file_read':\n return 'Read';\n case 'file_edit':\n return 'Edit';\n case 'file_write':\n return 'Write';\n case 'search':\n return 'Search';\n case 'glob':\n return 'Glob';\n case 'web_fetch':\n return 'Fetch';\n case 'web_search':\n return 'Search';\n case 'mcp_tool':\n return 'MCP';\n case 'generic_tool':\n return 'Tool';\n case 'todo_write':\n return 'Tasks';\n case 'agent_tool':\n return (actionType as AgentToolAction).agentType;\n default:\n return 'Tool';\n }\n}\n\n// =============================================================================\n// Formatting Helpers\n// =============================================================================\n\n/**\n * Format a file size in bytes to a human-readable string\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n/**\n * Format a timestamp to a locale time string\n */\nexport function formatTimestamp(timestamp: string): string {\n try {\n const date = new Date(timestamp);\n return date.toLocaleTimeString('en-US', {\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n });\n } catch {\n return timestamp;\n }\n}\n\n/**\n * Format elapsed time in human-readable format\n * @param startTime - ISO timestamp or Date when the operation started\n * @param endTime - Optional ISO timestamp or Date when the operation ended (defaults to now)\n * @returns Formatted string like \"2s\", \"1m 30s\", \"2m\", etc.\n */\nexport function formatElapsedTime(startTime: string | Date, endTime?: string | Date): string {\n const start = typeof startTime === 'string' ? new Date(startTime) : startTime;\n const end = endTime ? (typeof endTime === 'string' ? new Date(endTime) : endTime) : new Date();\n\n const elapsedMs = end.getTime() - start.getTime();\n const elapsedSeconds = Math.floor(elapsedMs / 1000);\n\n if (elapsedSeconds < 60) {\n return `${elapsedSeconds}s`;\n }\n\n const minutes = Math.floor(elapsedSeconds / 60);\n const seconds = elapsedSeconds % 60;\n\n if (seconds === 0) {\n return `${minutes}m`;\n }\n\n return `${minutes}m ${seconds}s`;\n}\n\n/**\n * Truncate a string with ellipsis\n */\nexport function truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str;\n return str.substring(0, maxLength - 3) + '...';\n}\n\n/**\n * Join class names, filtering out falsy values\n */\nexport function cn(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(' ');\n}\n\n// =============================================================================\n// Entry Grouping for Compact Mode\n// =============================================================================\n\n/**\n * A grouped entry that contains either a single entry or a group of consecutive tool calls\n */\nexport type GroupedEntry =\n | { type: 'single'; entry: NormalizedEntry }\n | { type: 'tool_group'; entries: NormalizedEntry[]; id: string };\n\n/**\n * Group consecutive tool call entries together based on display config.\n *\n * This is used in compact mode to merge consecutive tool calls into\n * a single ToolExecutionGroup, while keeping text content separate.\n *\n * @param entries - Array of normalized entries\n * @param config - Display configuration (uses breakEveryNToolCalls)\n * @returns Array of grouped entries\n */\nexport function groupEntriesForCompactMode(\n entries: NormalizedEntry[],\n config: ToolDisplayConfig\n): GroupedEntry[] {\n const result: GroupedEntry[] = [];\n let currentToolGroup: NormalizedEntry[] = [];\n let toolGroupCounter = 0;\n\n const flushToolGroup = () => {\n if (currentToolGroup.length > 0) {\n result.push({\n type: 'tool_group',\n entries: [...currentToolGroup],\n id: `tool-group-${toolGroupCounter++}`,\n });\n currentToolGroup = [];\n }\n };\n\n for (const entry of entries) {\n if (entry.entryType.type === 'tool_call') {\n currentToolGroup.push(entry);\n\n // Check if we should break the group\n if (\n config.breakEveryNToolCalls &&\n config.breakEveryNToolCalls > 0 &&\n currentToolGroup.length >= config.breakEveryNToolCalls\n ) {\n flushToolGroup();\n }\n } else {\n // Non-tool-call entry - flush any pending tool group\n flushToolGroup();\n result.push({ type: 'single', entry });\n }\n }\n\n // Flush any remaining tool group\n flushToolGroup();\n\n return result;\n}\n\n/**\n * Extract tool calls from a group of entries\n */\nexport function extractToolCallsFromGroup(entries: NormalizedEntry[]): NormalizedToolCall[] {\n return entries\n .filter((e): e is NormalizedEntry & { entryType: { type: 'tool_call'; toolCall: NormalizedToolCall } } =>\n e.entryType.type === 'tool_call'\n )\n .map((e) => e.entryType.toolCall);\n}\n\n// =============================================================================\n// Option Parsing\n// =============================================================================\n\n/**\n * A parsed option from assistant message content\n */\nexport interface ParsedOption {\n /** Option identifier (e.g., \"1\", \"2\", \"A\", \"B\") */\n id: string;\n /** Option title/label */\n label: string;\n /** Optional description text */\n description?: string;\n}\n\n/**\n * Result of parsing options from content\n */\nexport interface ParsedOptionsResult {\n /** Text before the options */\n preamble: string;\n /** Parsed options */\n options: ParsedOption[];\n}\n\n/**\n * Parse options from assistant message content.\n * Detects patterns like:\n * - \"Option 1: Title\" / \"Option 2: Title\"\n * - \"**Option 1:** Title\" (bold markdown)\n * - Numbered lists with descriptions\n *\n * @returns ParsedOptionsResult if options found, null otherwise\n */\nexport function parseOptionsFromContent(content: string): ParsedOptionsResult | null {\n // Pattern 1: \"Option N:\" format (with or without bold markdown)\n // Matches: \"Option 1:\", \"**Option 1:**\", \"Option 1 -\", etc.\n const optionPattern = /(?:\\*\\*)?Option\\s+(\\d+)(?:\\*\\*)?[:\\-]\\s*([^\\n]+)(?:\\n((?:(?!\\n(?:\\*\\*)?Option\\s+\\d).)*?))?/gi;\n\n const options: ParsedOption[] = [];\n let firstMatchStart = -1;\n let match: RegExpExecArray | null;\n\n // Reset regex\n optionPattern.lastIndex = 0;\n\n while ((match = optionPattern.exec(content)) !== null) {\n if (firstMatchStart === -1) {\n firstMatchStart = match.index;\n }\n\n const id = match[1] ?? '';\n const labelRaw = match[2];\n const label = labelRaw ? labelRaw.trim() : '';\n // Description is everything after the label until the next option\n const descriptionRaw = match[3];\n\n // Clean up description - remove leading/trailing whitespace and normalize\n let description: string | undefined;\n if (descriptionRaw) {\n const cleaned = descriptionRaw\n .split('\\n')\n .map(line => line.trim())\n .filter(line => line.length > 0)\n .join(' ');\n if (cleaned) {\n description = cleaned;\n }\n }\n\n options.push({ id, label, description });\n }\n\n // Need at least 2 options to be considered a valid options list\n if (options.length >= 2) {\n const preamble = firstMatchStart > 0\n ? content.substring(0, firstMatchStart).trim()\n : '';\n\n return { preamble, options };\n }\n\n // Pattern 2: Simple numbered list at end of message\n // Look for \"What would you like to do?\" or similar followed by numbered items\n const questionPattern = /^(.*?(?:what would you like to do\\??|choose an option|select.*?:|here are your options.*?:))\\s*\\n+((?:\\d+\\.\\s+.+\\n?)+)/ims;\n const questionMatch = content.match(questionPattern);\n\n if (questionMatch && questionMatch[1] && questionMatch[2]) {\n const preamble = questionMatch[1].trim();\n const listSection = questionMatch[2];\n\n // Parse numbered list items\n const listPattern = /(\\d+)\\.\\s+([^\\n]+)/g;\n let listMatch: RegExpExecArray | null;\n\n while ((listMatch = listPattern.exec(listSection)) !== null) {\n const listId = listMatch[1] ?? '';\n const listLabelRaw = listMatch[2];\n const listLabel = listLabelRaw ? listLabelRaw.trim() : '';\n options.push({\n id: listId,\n label: listLabel,\n });\n }\n\n if (options.length >= 2) {\n return { preamble, options };\n }\n }\n\n return null;\n}\n"]}
|
package/dist/utils.d.cts
CHANGED
|
@@ -68,6 +68,13 @@ declare function formatFileSize(bytes: number): string;
|
|
|
68
68
|
* Format a timestamp to a locale time string
|
|
69
69
|
*/
|
|
70
70
|
declare function formatTimestamp(timestamp: string): string;
|
|
71
|
+
/**
|
|
72
|
+
* Format elapsed time in human-readable format
|
|
73
|
+
* @param startTime - ISO timestamp or Date when the operation started
|
|
74
|
+
* @param endTime - Optional ISO timestamp or Date when the operation ended (defaults to now)
|
|
75
|
+
* @returns Formatted string like "2s", "1m 30s", "2m", etc.
|
|
76
|
+
*/
|
|
77
|
+
declare function formatElapsedTime(startTime: string | Date, endTime?: string | Date): string;
|
|
71
78
|
/**
|
|
72
79
|
* Truncate a string with ellipsis
|
|
73
80
|
*/
|
|
@@ -133,4 +140,4 @@ interface ParsedOptionsResult {
|
|
|
133
140
|
*/
|
|
134
141
|
declare function parseOptionsFromContent(content: string): ParsedOptionsResult | null;
|
|
135
142
|
|
|
136
|
-
export { type GroupedEntry, type ParsedOption, type ParsedOptionsResult, type ToolUseInput, cn, createToolCall, extractTextContent, extractToolCallsFromGroup, formatFileSize, formatTimestamp, formatToolName, generateToolSummary, getActionIcon, getActionLabel, groupEntriesForCompactMode, mapToolToActionType, normalizeToolResult, parseCommandResult, parseMcpToolName, parseOptionsFromContent, truncate, updateToolCallWithResult };
|
|
143
|
+
export { type GroupedEntry, type ParsedOption, type ParsedOptionsResult, type ToolUseInput, cn, createToolCall, extractTextContent, extractToolCallsFromGroup, formatElapsedTime, formatFileSize, formatTimestamp, formatToolName, generateToolSummary, getActionIcon, getActionLabel, groupEntriesForCompactMode, mapToolToActionType, normalizeToolResult, parseCommandResult, parseMcpToolName, parseOptionsFromContent, truncate, updateToolCallWithResult };
|
package/dist/utils.d.ts
CHANGED
|
@@ -68,6 +68,13 @@ declare function formatFileSize(bytes: number): string;
|
|
|
68
68
|
* Format a timestamp to a locale time string
|
|
69
69
|
*/
|
|
70
70
|
declare function formatTimestamp(timestamp: string): string;
|
|
71
|
+
/**
|
|
72
|
+
* Format elapsed time in human-readable format
|
|
73
|
+
* @param startTime - ISO timestamp or Date when the operation started
|
|
74
|
+
* @param endTime - Optional ISO timestamp or Date when the operation ended (defaults to now)
|
|
75
|
+
* @returns Formatted string like "2s", "1m 30s", "2m", etc.
|
|
76
|
+
*/
|
|
77
|
+
declare function formatElapsedTime(startTime: string | Date, endTime?: string | Date): string;
|
|
71
78
|
/**
|
|
72
79
|
* Truncate a string with ellipsis
|
|
73
80
|
*/
|
|
@@ -133,4 +140,4 @@ interface ParsedOptionsResult {
|
|
|
133
140
|
*/
|
|
134
141
|
declare function parseOptionsFromContent(content: string): ParsedOptionsResult | null;
|
|
135
142
|
|
|
136
|
-
export { type GroupedEntry, type ParsedOption, type ParsedOptionsResult, type ToolUseInput, cn, createToolCall, extractTextContent, extractToolCallsFromGroup, formatFileSize, formatTimestamp, formatToolName, generateToolSummary, getActionIcon, getActionLabel, groupEntriesForCompactMode, mapToolToActionType, normalizeToolResult, parseCommandResult, parseMcpToolName, parseOptionsFromContent, truncate, updateToolCallWithResult };
|
|
143
|
+
export { type GroupedEntry, type ParsedOption, type ParsedOptionsResult, type ToolUseInput, cn, createToolCall, extractTextContent, extractToolCallsFromGroup, formatElapsedTime, formatFileSize, formatTimestamp, formatToolName, generateToolSummary, getActionIcon, getActionLabel, groupEntriesForCompactMode, mapToolToActionType, normalizeToolResult, parseCommandResult, parseMcpToolName, parseOptionsFromContent, truncate, updateToolCallWithResult };
|
package/dist/utils.js
CHANGED
|
@@ -103,6 +103,16 @@ function mapToolToActionType(toolName, input) {
|
|
|
103
103
|
stats
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
|
+
case "Task": {
|
|
107
|
+
return {
|
|
108
|
+
action: "agent_tool",
|
|
109
|
+
agentType: inputObj.subagent_type || "general-purpose",
|
|
110
|
+
description: inputObj.description || "",
|
|
111
|
+
prompt: inputObj.prompt,
|
|
112
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
113
|
+
toolCallCount: 0
|
|
114
|
+
};
|
|
115
|
+
}
|
|
106
116
|
default: {
|
|
107
117
|
const mcpParts = parseMcpToolName(toolName);
|
|
108
118
|
if (mcpParts) {
|
|
@@ -152,6 +162,8 @@ function generateToolSummary(_toolName, _input, actionType) {
|
|
|
152
162
|
}
|
|
153
163
|
return `${actionType.todos.length} tasks`;
|
|
154
164
|
}
|
|
165
|
+
case "agent_tool":
|
|
166
|
+
return actionType.description;
|
|
155
167
|
default:
|
|
156
168
|
return "Unknown tool";
|
|
157
169
|
}
|
|
@@ -219,6 +231,7 @@ function createToolCall(toolUse) {
|
|
|
219
231
|
actionType,
|
|
220
232
|
status: "pending",
|
|
221
233
|
summary,
|
|
234
|
+
input: toolUse.input,
|
|
222
235
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
223
236
|
};
|
|
224
237
|
}
|
|
@@ -228,6 +241,7 @@ function updateToolCallWithResult(toolCall, content, isError) {
|
|
|
228
241
|
updatedToolCall.status = isError ? "failed" : "success";
|
|
229
242
|
updatedToolCall.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
230
243
|
updatedToolCall.isError = isError;
|
|
244
|
+
updatedToolCall.output = content;
|
|
231
245
|
if (actionType.action === "command_run") {
|
|
232
246
|
const result = parseCommandResult(content);
|
|
233
247
|
actionType.result = result;
|
|
@@ -265,6 +279,8 @@ function getActionIcon(actionType) {
|
|
|
265
279
|
return "tool";
|
|
266
280
|
case "todo_write":
|
|
267
281
|
return "list-checks";
|
|
282
|
+
case "agent_tool":
|
|
283
|
+
return "bot";
|
|
268
284
|
default:
|
|
269
285
|
return "tool";
|
|
270
286
|
}
|
|
@@ -293,6 +309,8 @@ function getActionLabel(actionType) {
|
|
|
293
309
|
return "Tool";
|
|
294
310
|
case "todo_write":
|
|
295
311
|
return "Tasks";
|
|
312
|
+
case "agent_tool":
|
|
313
|
+
return actionType.agentType;
|
|
296
314
|
default:
|
|
297
315
|
return "Tool";
|
|
298
316
|
}
|
|
@@ -315,6 +333,21 @@ function formatTimestamp(timestamp) {
|
|
|
315
333
|
return timestamp;
|
|
316
334
|
}
|
|
317
335
|
}
|
|
336
|
+
function formatElapsedTime(startTime, endTime) {
|
|
337
|
+
const start = typeof startTime === "string" ? new Date(startTime) : startTime;
|
|
338
|
+
const end = endTime ? typeof endTime === "string" ? new Date(endTime) : endTime : /* @__PURE__ */ new Date();
|
|
339
|
+
const elapsedMs = end.getTime() - start.getTime();
|
|
340
|
+
const elapsedSeconds = Math.floor(elapsedMs / 1e3);
|
|
341
|
+
if (elapsedSeconds < 60) {
|
|
342
|
+
return `${elapsedSeconds}s`;
|
|
343
|
+
}
|
|
344
|
+
const minutes = Math.floor(elapsedSeconds / 60);
|
|
345
|
+
const seconds = elapsedSeconds % 60;
|
|
346
|
+
if (seconds === 0) {
|
|
347
|
+
return `${minutes}m`;
|
|
348
|
+
}
|
|
349
|
+
return `${minutes}m ${seconds}s`;
|
|
350
|
+
}
|
|
318
351
|
function truncate(str, maxLength) {
|
|
319
352
|
if (str.length <= maxLength) return str;
|
|
320
353
|
return str.substring(0, maxLength - 3) + "...";
|
|
@@ -405,6 +438,6 @@ function parseOptionsFromContent(content) {
|
|
|
405
438
|
return null;
|
|
406
439
|
}
|
|
407
440
|
|
|
408
|
-
export { cn, createToolCall, extractTextContent, extractToolCallsFromGroup, formatFileSize, formatTimestamp, formatToolName, generateToolSummary, getActionIcon, getActionLabel, groupEntriesForCompactMode, mapToolToActionType, normalizeToolResult, parseCommandResult, parseMcpToolName, parseOptionsFromContent, truncate, updateToolCallWithResult };
|
|
441
|
+
export { cn, createToolCall, extractTextContent, extractToolCallsFromGroup, formatElapsedTime, formatFileSize, formatTimestamp, formatToolName, generateToolSummary, getActionIcon, getActionLabel, groupEntriesForCompactMode, mapToolToActionType, normalizeToolResult, parseCommandResult, parseMcpToolName, parseOptionsFromContent, truncate, updateToolCallWithResult };
|
|
409
442
|
//# sourceMappingURL=utils.js.map
|
|
410
443
|
//# sourceMappingURL=utils.js.map
|