dexto 1.5.2 → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/agents/agent-registry.json +9 -0
  2. package/dist/agents/coding-agent/coding-agent.yml +37 -6
  3. package/dist/agents/explore-agent/explore-agent.yml +124 -0
  4. package/dist/cli/approval/cli-approval-handler.d.ts +28 -0
  5. package/dist/cli/approval/cli-approval-handler.d.ts.map +1 -0
  6. package/dist/cli/approval/cli-approval-handler.js +146 -0
  7. package/dist/cli/approval/index.d.ts +7 -0
  8. package/dist/cli/approval/index.d.ts.map +1 -0
  9. package/dist/cli/approval/index.js +6 -0
  10. package/dist/cli/commands/interactive-commands/general-commands.d.ts.map +1 -1
  11. package/dist/cli/commands/interactive-commands/general-commands.js +5 -2
  12. package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts.map +1 -1
  13. package/dist/cli/ink-cli/components/ApprovalPrompt.js +10 -2
  14. package/dist/cli/ink-cli/components/Footer.d.ts +3 -1
  15. package/dist/cli/ink-cli/components/Footer.d.ts.map +1 -1
  16. package/dist/cli/ink-cli/components/Footer.js +4 -2
  17. package/dist/cli/ink-cli/components/TextBufferInput.d.ts.map +1 -1
  18. package/dist/cli/ink-cli/components/TextBufferInput.js +3 -2
  19. package/dist/cli/ink-cli/components/chat/MessageItem.d.ts.map +1 -1
  20. package/dist/cli/ink-cli/components/chat/MessageItem.js +10 -3
  21. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts.map +1 -1
  22. package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +1 -1
  23. package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
  24. package/dist/cli/ink-cli/components/modes/StaticCLI.js +1 -1
  25. package/dist/cli/ink-cli/components/renderers/SearchRenderer.d.ts.map +1 -1
  26. package/dist/cli/ink-cli/components/renderers/SearchRenderer.js +15 -1
  27. package/dist/cli/ink-cli/constants/processingPhrases.js +1 -1
  28. package/dist/cli/ink-cli/constants/tips.d.ts.map +1 -1
  29. package/dist/cli/ink-cli/constants/tips.js +2 -1
  30. package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
  31. package/dist/cli/ink-cli/services/processStream.js +77 -13
  32. package/dist/cli/ink-cli/state/types.d.ts +17 -0
  33. package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
  34. package/dist/cli/ink-cli/utils/messageFormatting.d.ts +24 -0
  35. package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
  36. package/dist/cli/ink-cli/utils/messageFormatting.js +41 -2
  37. package/dist/index.js +5 -15
  38. package/dist/webui/assets/index-CUVc7IDL.css +1 -0
  39. package/dist/webui/assets/{index-8j-KMkX1.js → index-SGm5dxhp.js} +208 -208
  40. package/dist/webui/index.html +2 -2
  41. package/package.json +7 -7
  42. package/dist/webui/assets/index-c_AX24V4.css +0 -1
@@ -134,6 +134,15 @@
134
134
  "tags": ["gaming", "gameboy", "pokemon", "emulator", "mcp"],
135
135
  "source": "gaming-agent/",
136
136
  "main": "gaming-agent.yml"
137
+ },
138
+ "explore-agent": {
139
+ "id": "explore-agent",
140
+ "name": "Explore Agent",
141
+ "description": "Fast, read-only agent for codebase exploration. Use for: 'explore the codebase', 'what's in this folder', 'how does X work', 'find where Y is handled', 'understand the architecture'. Optimized for speed with Haiku.",
142
+ "author": "Truffle AI",
143
+ "tags": ["explore", "search", "understand", "find", "research"],
144
+ "source": "explore-agent/",
145
+ "main": "explore-agent.yml"
137
146
  }
138
147
  }
139
148
  }
@@ -24,8 +24,27 @@ systemPrompt:
24
24
  - Debug issues by examining error messages and code structure
25
25
  - Refactor code following best practices and design patterns
26
26
  - Explain complex code concepts clearly
27
+ - Delegate exploration tasks to specialized sub-agents
27
28
 
28
- Guidelines:
29
+ ## Task Delegation
30
+
31
+ You have access to spawn_agent for delegating tasks to specialized sub-agents.
32
+
33
+ **When to delegate to explore-agent:**
34
+ - Open-ended exploration: "explore the codebase", "what's in this folder", "how does X work"
35
+ - Understanding architecture: "explain the project structure", "how are components organized"
36
+ - Finding patterns: "where is authentication handled", "find all API endpoints"
37
+ - Research tasks: "what testing framework is used", "how is state managed"
38
+
39
+ **When to use your own tools directly:**
40
+ - Specific file operations: "read src/index.ts", "edit the config file"
41
+ - Targeted searches: "find the User class", "grep for 'TODO'"
42
+ - Writing/editing code: any task that requires modifications
43
+ - Running commands: build, test, install dependencies
44
+
45
+ **Rule of thumb:** If the task requires understanding or exploring before you know what to do, delegate to explore-agent first. If you know exactly what file/function to target, use your tools directly.
46
+
47
+ ## Guidelines
29
48
  - Always read relevant code before making changes to understand context
30
49
  - Use glob_files to find files and grep_content to search within files
31
50
  - Test changes when possible using bash_exec
@@ -70,13 +89,14 @@ toolConfirmation:
70
89
  # Tool policies optimized for coding workflows
71
90
  toolPolicies:
72
91
  # Tools that never require approval (safe, read-only operations)
92
+ # Use qualified names: custom--{tool_id} for custom tools, internal--{tool_id} for internal tools
73
93
  alwaysAllow:
74
94
  - internal--ask_user
75
- - custom--filesystem-tools--read_file # Read files without approval
76
- - custom--filesystem-tools--glob_files # Search for files without approval
77
- - custom--filesystem-tools--grep_content # Search within files without approval
78
- - custom--process-tools--bash_output # Check background process output
79
- - custom--process-tools--kill_process # Kill processes without approval
95
+ - custom--read_file # Read files without approval
96
+ - custom--glob_files # Search for files without approval
97
+ - custom--grep_content # Search within files without approval
98
+ - custom--bash_output # Check background process output
99
+ - custom--kill_process # Kill processes without approval (only processes started by agent)
80
100
 
81
101
  # Tools that are always denied (dangerous operations)
82
102
  # Uncomment to restrict certain operations
@@ -101,6 +121,17 @@ customTools:
101
121
  enableBackups: false
102
122
  - type: process-tools
103
123
  securityLevel: moderate
124
+ - type: agent-spawner
125
+ maxConcurrentAgents: 5
126
+ defaultTimeout: 300000
127
+ allowSpawning: true
128
+ # List of agent IDs from the registry that can be spawned.
129
+ # Agent metadata (name, description) is pulled from the registry at runtime.
130
+ allowedAgents:
131
+ - explore-agent
132
+ # Agents with read-only tools that should have auto-approved tool calls
133
+ autoApproveAgents:
134
+ - explore-agent
104
135
 
105
136
  # Internal resources configuration - expanded for coding projects
106
137
  internalResources:
@@ -0,0 +1,124 @@
1
+ # Explore Agent Configuration
2
+ # Lightweight, read-only agent optimized for codebase exploration
3
+ # Designed to be spawned by other agents for research tasks
4
+
5
+ # No image bundle - uses only explicitly defined tools below
6
+
7
+ # System prompt optimized for exploration tasks
8
+ systemPrompt:
9
+ contributors:
10
+ - id: primary
11
+ type: static
12
+ priority: 0
13
+ content: |
14
+ You are a fast, focused exploration agent specialized in understanding codebases and finding information.
15
+
16
+ ## Your Mission
17
+ Quickly and thoroughly explore codebases to answer questions, find patterns, locate files, and understand architecture. You are optimized for speed and accuracy.
18
+
19
+ ## Available Tools
20
+ You have access to read-only tools:
21
+ - `glob_files` - Find files matching patterns (e.g., "src/**/*.ts", "*.config.js")
22
+ - `grep_content` - Search for text/patterns within files
23
+ - `read_file` - Read file contents
24
+
25
+ ## Exploration Strategy
26
+
27
+ ### For "quick" searches:
28
+ - Single glob or grep to find the target
29
+ - Read 1-2 most relevant files
30
+ - Return focused answer
31
+
32
+ ### For "medium" exploration:
33
+ - Multiple search patterns to find related files
34
+ - Read key files to understand connections
35
+ - Summarize findings with file references
36
+
37
+ ### For "very thorough" analysis:
38
+ - Comprehensive search across multiple naming conventions
39
+ - Trace imports, exports, and dependencies
40
+ - Map relationships between components
41
+ - Provide detailed analysis with evidence
42
+
43
+ ## Guidelines
44
+ - Start with broad searches, then narrow down
45
+ - Use glob for file discovery, grep for content search
46
+ - Try multiple naming conventions (camelCase, snake_case, kebab-case, PascalCase)
47
+ - Check common locations: src/, lib/, packages/, tests/, config/
48
+ - Report what you found AND what you didn't find
49
+ - Include file paths and line numbers in your response
50
+ - Be concise but complete
51
+
52
+ ## Response Format
53
+ Structure your response as:
54
+ 1. **Summary** - Brief answer to the question
55
+ 2. **Key Files** - List of relevant files found
56
+ 3. **Details** - Specific findings with code references
57
+ 4. **Notes** - Any caveats or areas that need further exploration
58
+
59
+ # LLM configuration - Haiku for speed and cost efficiency
60
+ llm:
61
+ provider: anthropic
62
+ model: claude-haiku-4-5-20251001
63
+ apiKey: $ANTHROPIC_API_KEY
64
+
65
+ # Minimal storage - in-memory only for ephemeral use
66
+ storage:
67
+ cache:
68
+ type: in-memory
69
+ database:
70
+ type: in-memory
71
+ blob:
72
+ type: in-memory
73
+
74
+ # Auto-approve all tools since they're read-only
75
+ toolConfirmation:
76
+ mode: auto-approve
77
+ allowedToolsStorage: memory
78
+
79
+ # No internal tools needed for exploration
80
+ internalTools: []
81
+
82
+ # Read-only filesystem tools only - explicitly enable only read operations
83
+ customTools:
84
+ - type: filesystem-tools
85
+ enabledTools: ["read_file", "glob_files", "grep_content"] # Read-only tools only
86
+ allowedPaths: ["."]
87
+ blockedPaths:
88
+ # Version control
89
+ - ".git"
90
+ # Binaries
91
+ - "node_modules/.bin"
92
+ # Environment files with secrets
93
+ - ".env"
94
+ - ".env.local"
95
+ - ".env.production"
96
+ - ".env.development"
97
+ - ".env.test"
98
+ - ".env.staging"
99
+ # Package manager credentials
100
+ - ".npmrc"
101
+ - ".yarnrc"
102
+ - ".pypirc"
103
+ # Git credentials
104
+ - ".git-credentials"
105
+ - ".gitconfig"
106
+ # SSH keys
107
+ - ".ssh"
108
+ # Cloud provider credentials
109
+ - ".aws"
110
+ - ".gcp"
111
+ - ".azure"
112
+ # Kubernetes config
113
+ - ".kube"
114
+ # Docker credentials
115
+ - ".docker"
116
+ blockedExtensions: [".exe", ".dll", ".so", ".dylib"]
117
+ maxFileSize: 10485760 # 10MB
118
+ enableBackups: false
119
+
120
+ # Note: This agent intentionally excludes:
121
+ # - write_file, edit_file (write operations) - not in enabledTools
122
+ # - process-tools (bash execution) - provider not included
123
+ # - agent-spawner (no sub-agent spawning) - provider not included
124
+ # This ensures it remains a safe, read-only exploration tool
@@ -0,0 +1,28 @@
1
+ /**
2
+ * CLI-specific Approval Handler
3
+ *
4
+ * Creates a manual approval handler that works directly with AgentEventBus
5
+ * for the CLI/TUI mode. Unlike the server's ManualApprovalHandler which uses
6
+ * ApprovalCoordinator for HTTP-based flows, this handler emits events directly
7
+ * to the event bus that the TUI listens to.
8
+ *
9
+ * Flow:
10
+ * 1. Handler emits 'approval:request' → EventBus → TUI shows prompt
11
+ * 2. User responds in TUI → EventBus emits 'approval:response' → Handler resolves
12
+ * 3. For auto-approvals (parallel tools), handler emits 'approval:response' → TUI dismisses
13
+ */
14
+ import type { ApprovalHandler, AgentEventBus } from '@dexto/core';
15
+ /**
16
+ * Creates a manual approval handler for CLI mode that uses AgentEventBus directly.
17
+ *
18
+ * @param eventBus The agent event bus for request/response communication
19
+ * @returns ApprovalHandler with cancellation and auto-approve support
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const handler = createCLIApprovalHandler(agent.agentEventBus);
24
+ * agent.setApprovalHandler(handler);
25
+ * ```
26
+ */
27
+ export declare function createCLIApprovalHandler(eventBus: AgentEventBus): ApprovalHandler;
28
+ //# sourceMappingURL=cli-approval-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-approval-handler.d.ts","sourceRoot":"","sources":["../../../src/cli/approval/cli-approval-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACR,eAAe,EAGf,aAAa,EAChB,MAAM,aAAa,CAAC;AAGrB;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,aAAa,GAAG,eAAe,CAyJjF"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * CLI-specific Approval Handler
3
+ *
4
+ * Creates a manual approval handler that works directly with AgentEventBus
5
+ * for the CLI/TUI mode. Unlike the server's ManualApprovalHandler which uses
6
+ * ApprovalCoordinator for HTTP-based flows, this handler emits events directly
7
+ * to the event bus that the TUI listens to.
8
+ *
9
+ * Flow:
10
+ * 1. Handler emits 'approval:request' → EventBus → TUI shows prompt
11
+ * 2. User responds in TUI → EventBus emits 'approval:response' → Handler resolves
12
+ * 3. For auto-approvals (parallel tools), handler emits 'approval:response' → TUI dismisses
13
+ */
14
+ import { ApprovalStatus, DenialReason } from '@dexto/core';
15
+ /**
16
+ * Creates a manual approval handler for CLI mode that uses AgentEventBus directly.
17
+ *
18
+ * @param eventBus The agent event bus for request/response communication
19
+ * @returns ApprovalHandler with cancellation and auto-approve support
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const handler = createCLIApprovalHandler(agent.agentEventBus);
24
+ * agent.setApprovalHandler(handler);
25
+ * ```
26
+ */
27
+ export function createCLIApprovalHandler(eventBus) {
28
+ // Track pending approvals for cancellation support
29
+ const pendingApprovals = new Map();
30
+ const handleApproval = (request) => {
31
+ return new Promise((resolve) => {
32
+ // Use per-request timeout (optional - undefined means no timeout)
33
+ const effectiveTimeout = request.timeout;
34
+ // Set timeout timer ONLY if timeout is specified
35
+ let timer;
36
+ if (effectiveTimeout !== undefined) {
37
+ timer = setTimeout(() => {
38
+ cleanup();
39
+ pendingApprovals.delete(request.approvalId);
40
+ // Create timeout response
41
+ const timeoutResponse = {
42
+ approvalId: request.approvalId,
43
+ status: ApprovalStatus.CANCELLED,
44
+ sessionId: request.sessionId,
45
+ reason: DenialReason.TIMEOUT,
46
+ message: `Approval request timed out after ${effectiveTimeout}ms`,
47
+ timeoutMs: effectiveTimeout,
48
+ };
49
+ // Emit timeout response so TUI can dismiss the prompt
50
+ eventBus.emit('approval:response', timeoutResponse);
51
+ resolve(timeoutResponse);
52
+ }, effectiveTimeout);
53
+ }
54
+ // Cleanup function to remove listener and clear timeout
55
+ const controller = new AbortController();
56
+ const cleanup = () => {
57
+ if (timer !== undefined) {
58
+ clearTimeout(timer);
59
+ }
60
+ controller.abort();
61
+ };
62
+ // Listen for approval:response events
63
+ const listener = (res) => {
64
+ // Only handle responses for this specific approval
65
+ if (res.approvalId === request.approvalId) {
66
+ cleanup();
67
+ pendingApprovals.delete(request.approvalId);
68
+ resolve(res);
69
+ }
70
+ };
71
+ // Register listener with abort signal for cleanup
72
+ eventBus.on('approval:response', listener, { signal: controller.signal });
73
+ // Store for cancellation support
74
+ pendingApprovals.set(request.approvalId, {
75
+ cleanup,
76
+ resolve,
77
+ request,
78
+ });
79
+ // Emit the approval:request event for TUI to receive
80
+ eventBus.emit('approval:request', request);
81
+ });
82
+ };
83
+ const handler = Object.assign(handleApproval, {
84
+ cancel: (approvalId) => {
85
+ const pending = pendingApprovals.get(approvalId);
86
+ if (pending) {
87
+ pending.cleanup();
88
+ pendingApprovals.delete(approvalId);
89
+ // Create cancellation response
90
+ const cancelResponse = {
91
+ approvalId,
92
+ status: ApprovalStatus.CANCELLED,
93
+ sessionId: pending.request.sessionId,
94
+ reason: DenialReason.SYSTEM_CANCELLED,
95
+ message: 'Approval request was cancelled',
96
+ };
97
+ // Emit cancellation event so TUI can dismiss the prompt
98
+ eventBus.emit('approval:response', cancelResponse);
99
+ // Resolve with CANCELLED response
100
+ pending.resolve(cancelResponse);
101
+ }
102
+ },
103
+ cancelAll: () => {
104
+ for (const [approvalId] of pendingApprovals) {
105
+ handler.cancel?.(approvalId);
106
+ }
107
+ },
108
+ getPending: () => {
109
+ return Array.from(pendingApprovals.keys());
110
+ },
111
+ getPendingRequests: () => {
112
+ return Array.from(pendingApprovals.values()).map((p) => p.request);
113
+ },
114
+ /**
115
+ * Auto-approve pending requests that match a predicate.
116
+ * Used when a pattern is remembered to auto-approve other parallel requests
117
+ * that would now match the same pattern.
118
+ */
119
+ autoApprovePending: (predicate, responseData) => {
120
+ let count = 0;
121
+ // Find all pending approvals that match the predicate
122
+ for (const [approvalId, pending] of pendingApprovals) {
123
+ if (predicate(pending.request)) {
124
+ // Clean up the pending state
125
+ pending.cleanup();
126
+ pendingApprovals.delete(approvalId);
127
+ // Create auto-approval response
128
+ const autoApproveResponse = {
129
+ approvalId,
130
+ status: ApprovalStatus.APPROVED,
131
+ sessionId: pending.request.sessionId,
132
+ message: 'Auto-approved due to matching remembered pattern',
133
+ data: responseData,
134
+ };
135
+ // Emit response so TUI can dismiss the prompt
136
+ eventBus.emit('approval:response', autoApproveResponse);
137
+ // Resolve the pending promise
138
+ pending.resolve(autoApproveResponse);
139
+ count++;
140
+ }
141
+ }
142
+ return count;
143
+ },
144
+ });
145
+ return handler;
146
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * CLI Approval Module
3
+ *
4
+ * Provides CLI-specific approval handling that works directly with AgentEventBus.
5
+ */
6
+ export { createCLIApprovalHandler } from './cli-approval-handler.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/approval/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * CLI Approval Module
3
+ *
4
+ * Provides CLI-specific approval handling that works directly with AgentEventBus.
5
+ */
6
+ export { createCLIApprovalHandler } from './cli-approval-handler.js';
@@ -1 +1 @@
1
- {"version":3,"file":"general-commands.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/interactive-commands/general-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAwC,MAAM,qBAAqB,CAAC;AAiDnG;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,cAAc,EAAE,MAAM,iBAAiB,EAAE,GAAG,iBAAiB,CAgC9F;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,iBAAiB,EAyO9C,CAAC"}
1
+ {"version":3,"file":"general-commands.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/interactive-commands/general-commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAwC,MAAM,qBAAqB,CAAC;AAoDnG;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,cAAc,EAAE,MAAM,iBAAiB,EAAE,GAAG,iBAAiB,CAgC9F;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,iBAAiB,EAyO9C,CAAC"}
@@ -19,10 +19,13 @@ import { writeToClipboard } from '../../ink-cli/utils/clipboardUtils.js';
19
19
  */
20
20
  async function executeShellCommand(command, cwd, timeoutMs = 30000) {
21
21
  return new Promise((resolve) => {
22
- const child = spawn(command, [], {
22
+ // Use user's default shell from SHELL env var, fallback to /bin/sh
23
+ // Use -i flag for interactive mode to load aliases from shell config
24
+ const userShell = process.env.SHELL || '/bin/sh';
25
+ const child = spawn(userShell, ['-ic', command], {
23
26
  cwd,
24
- shell: true,
25
27
  stdio: ['ignore', 'pipe', 'pipe'],
28
+ env: { ...process.env },
26
29
  });
27
30
  let stdout = '';
28
31
  let stderr = '';
@@ -1 +1 @@
1
- {"version":3,"file":"ApprovalPrompt.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/ApprovalPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuE,MAAM,OAAO,CAAC;AAG5F,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AAK5D,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,oBAAoB;IACjC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,oEAAoE;IACpE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,gFAAgF;IAChF,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,UAAU,mBAAmB;IACzB,QAAQ,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC9C,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAOD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,kGA2R1B,CAAC"}
1
+ {"version":3,"file":"ApprovalPrompt.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/ApprovalPrompt.tsx"],"names":[],"mappings":"AAAA,OAAO,KAON,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AAM5D,MAAM,WAAW,eAAe;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC;AAED,MAAM,WAAW,oBAAoB;IACjC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC5B,oEAAoE;IACpE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mEAAmE;IACnE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yCAAyC;IACzC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,gFAAgF;IAChF,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,gDAAgD;IAChD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,UAAU,mBAAmB;IACzB,QAAQ,EAAE,eAAe,CAAC;IAC1B,SAAS,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAC9C,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAOD;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,kGAkS1B,CAAC"}
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { forwardRef, useState, useImperativeHandle, useRef, useEffect } from 'react';
2
+ import { forwardRef, useState, useImperativeHandle, useRef, useEffect, useMemo, } from 'react';
3
3
  import { Box, Text } from 'ink';
4
4
  import { ElicitationForm } from './ElicitationForm.js';
5
5
  import { DiffPreview, CreateFilePreview } from './renderers/index.js';
6
6
  import { isEditWriteTool } from '../utils/toolUtils.js';
7
+ import { formatToolHeader } from '../utils/messageFormatting.js';
7
8
  /**
8
9
  * Compact approval prompt component that displays above the input area
9
10
  * Shows options based on approval type:
@@ -20,7 +21,14 @@ export const ApprovalPrompt = forwardRef(({ approval, onApprove, onDeny, onCance
20
21
  const hasBashPatterns = suggestedPatterns.length > 0;
21
22
  // Check if this is an edit/write file tool
22
23
  const toolName = approval.metadata.toolName;
24
+ const toolArgs = approval.metadata.args || {};
23
25
  const isEditOrWriteTool = isEditWriteTool(toolName);
26
+ // Format tool header using shared utility (same format as tool messages)
27
+ const formattedTool = useMemo(() => {
28
+ if (!toolName)
29
+ return null;
30
+ return formatToolHeader(toolName, toolArgs);
31
+ }, [toolName, toolArgs]);
24
32
  const [selectedIndex, setSelectedIndex] = useState(0);
25
33
  // Ref for elicitation form
26
34
  const elicitationFormRef = useRef(null);
@@ -183,7 +191,7 @@ export const ApprovalPrompt = forwardRef(({ approval, onApprove, onDeny, onCance
183
191
  const directoryPath = approval.metadata.path;
184
192
  const parentDir = approval.metadata.parentDir;
185
193
  const operation = approval.metadata.operation;
186
- return (_jsxs(Box, { paddingX: 0, paddingY: 0, flexDirection: "column", children: [_jsx(Box, { flexDirection: "column", marginBottom: 0, children: isDirectoryAccess ? (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: "yellowBright", bold: true, children: ["\uD83D\uDD10 Directory Access:", ' '] }), _jsx(Text, { color: "cyan", children: parentDir || directoryPath })] }), _jsxs(Box, { flexDirection: "row", marginTop: 0, children: [_jsx(Text, { color: "gray", children: ' ' }), _jsxs(Text, { color: "gray", children: [toolName ? `"${toolName}"` : 'Tool', " wants to", ' ', operation || 'access', " files outside working directory"] })] })] })) : (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: "yellowBright", bold: true, children: ["\uD83D\uDD10 Approval:", ' '] }), toolName && _jsx(Text, { color: "cyan", children: toolName })] }), isCommandConfirmation && command && (_jsxs(Box, { flexDirection: "row", marginTop: 0, children: [_jsx(Text, { color: "gray", children: ' Command: ' }), _jsx(Text, { color: "red", children: command })] }))] })) }), renderPreview(), _jsx(Box, { flexDirection: "column", marginTop: 0, children: options.map((option, index) => {
194
+ return (_jsxs(Box, { paddingX: 0, paddingY: 0, flexDirection: "column", children: [_jsx(Box, { flexDirection: "column", marginBottom: 0, children: isDirectoryAccess ? (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: "yellowBright", bold: true, children: ["\uD83D\uDD10 Directory Access:", ' '] }), _jsx(Text, { color: "cyan", children: parentDir || directoryPath })] }), _jsxs(Box, { flexDirection: "row", marginTop: 0, children: [_jsx(Text, { color: "gray", children: ' ' }), _jsxs(Text, { color: "gray", children: [formattedTool ? `"${formattedTool.displayName}"` : 'Tool', ' ', "wants to ", operation || 'access', " files outside working directory"] })] })] })) : (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "row", children: [_jsxs(Text, { color: "yellowBright", bold: true, children: ["\uD83D\uDD10 Approval:", ' '] }), formattedTool && _jsx(Text, { color: "cyan", children: formattedTool.header })] }), isCommandConfirmation && command && (_jsxs(Box, { flexDirection: "row", marginTop: 0, children: [_jsx(Text, { color: "gray", children: ' Command: ' }), _jsx(Text, { color: "red", children: command })] }))] })) }), renderPreview(), _jsx(Box, { flexDirection: "column", marginTop: 0, children: options.map((option, index) => {
187
195
  const isSelected = index === selectedIndex;
188
196
  const isNo = option.id === 'no';
189
197
  return (_jsx(Box, { children: isSelected ? (_jsxs(Text, { color: isNo ? 'red' : 'green', bold: true, children: [' ▶ ', option.label] })) : (_jsxs(Text, { color: "gray", children: [' ', option.label] })) }, option.id));
@@ -7,10 +7,12 @@ interface FooterProps {
7
7
  cwd?: string;
8
8
  branchName?: string;
9
9
  autoApproveEdits?: boolean;
10
+ /** Whether user is in shell command mode (input starts with !) */
11
+ isShellMode?: boolean;
10
12
  }
11
13
  /**
12
14
  * Pure presentational component for footer status line
13
15
  */
14
- export declare function Footer({ modelName, cwd, branchName, autoApproveEdits }: FooterProps): import("react/jsx-runtime").JSX.Element;
16
+ export declare function Footer({ modelName, cwd, branchName, autoApproveEdits, isShellMode }: FooterProps): import("react/jsx-runtime").JSX.Element;
15
17
  export {};
16
18
  //# sourceMappingURL=Footer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Footer.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/Footer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,UAAU,WAAW;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAoBD;;GAEG;AACH,wBAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,gBAAgB,EAAE,EAAE,WAAW,2CAwBnF"}
1
+ {"version":3,"file":"Footer.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/Footer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,UAAU,WAAW;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,kEAAkE;IAClE,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAoBD;;GAEG;AACH,wBAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,UAAU,EAAE,gBAAgB,EAAE,WAAW,EAAE,EAAE,WAAW,2CAmChG"}
@@ -20,8 +20,10 @@ function shortenPath(path, maxLength = 40) {
20
20
  /**
21
21
  * Pure presentational component for footer status line
22
22
  */
23
- export function Footer({ modelName, cwd, branchName, autoApproveEdits }) {
23
+ export function Footer({ modelName, cwd, branchName, autoApproveEdits, isShellMode }) {
24
24
  const displayPath = cwd ? shortenPath(cwd) : '';
25
25
  const displayModelName = getModelDisplayName(modelName);
26
- return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsx(Text, { color: "blue", children: displayPath }), branchName && _jsxs(Text, { color: "gray", children: [" (", branchName, ")"] })] }), _jsx(Text, { color: "cyan", children: displayModelName })] }), autoApproveEdits && (_jsxs(Box, { children: [_jsx(Text, { color: "yellowBright", children: "accept edits" }), _jsx(Text, { color: "gray", children: " (shift + tab to toggle)" })] }))] }));
26
+ // Shell mode changes the path color to yellow as indicator
27
+ const pathColor = isShellMode ? 'yellow' : 'blue';
28
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsx(Text, { color: pathColor, children: displayPath }), branchName && _jsxs(Text, { color: "gray", children: [" (", branchName, ")"] })] }), _jsx(Text, { color: "cyan", children: displayModelName })] }), isShellMode && (_jsxs(Box, { children: [_jsx(Text, { color: "yellow", bold: true, children: "!" }), _jsx(Text, { color: "gray", children: " for shell mode" })] })), autoApproveEdits && !isShellMode && (_jsxs(Box, { children: [_jsx(Text, { color: "yellowBright", children: "accept edits" }), _jsx(Text, { color: "gray", children: " (shift + tab to toggle)" })] }))] }));
27
29
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TextBufferInput.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/TextBufferInput.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGnE,+DAA+D;AAC/D,MAAM,MAAM,cAAc,GAAG,oBAAoB,GAAG,uBAAuB,GAAG,OAAO,CAAC;AActF,UAAU,oBAAoB;IAC1B,oCAAoC;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,+CAA+C;IAC/C,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,mEAAmE;IACnE,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACrE,0DAA0D;IAC1D,gBAAgB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACnE,wCAAwC;IACxC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,kDAAkD;IAClD,QAAQ,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACpE,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,iDAAiD;IACjD,YAAY,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC3D,iEAAiE;IACjE,MAAM,CAAC,EAAE,YAAY,EAAE,GAAG,SAAS,CAAC;IACpC,4DAA4D;IAC5D,aAAa,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACxD,wDAAwD;IACxD,YAAY,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;IACzC,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC1D,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC5F,iEAAiE;IACjE,kBAAkB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC7D,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAuCD,wBAAgB,eAAe,CAAC,EAC5B,MAAM,EACN,QAAQ,EACR,WAAW,EACX,UAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAqB,EACrB,QAAQ,EACR,gBAAgB,EAChB,UAAc,EACd,YAAY,EACZ,MAAW,EACX,aAAa,EACb,YAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,GACjB,EAAE,oBAAoB,2CA0hBtB"}
1
+ {"version":3,"file":"TextBufferInput.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink-cli/components/TextBufferInput.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGnE,+DAA+D;AAC/D,MAAM,MAAM,cAAc,GAAG,oBAAoB,GAAG,uBAAuB,GAAG,OAAO,CAAC;AActF,UAAU,oBAAoB;IAC1B,oCAAoC;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,+CAA+C;IAC/C,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,mEAAmE;IACnE,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACrE,0DAA0D;IAC1D,gBAAgB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACnE,wCAAwC;IACxC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,kDAAkD;IAClD,QAAQ,EAAE,OAAO,CAAC;IAClB,2EAA2E;IAC3E,gBAAgB,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACpE,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,iDAAiD;IACjD,YAAY,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC3D,iEAAiE;IACjE,MAAM,CAAC,EAAE,YAAY,EAAE,GAAG,SAAS,CAAC;IACpC,4DAA4D;IAC5D,aAAa,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IACxD,wDAAwD;IACxD,YAAY,CAAC,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;IACzC,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC1D,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC5F,iEAAiE;IACjE,kBAAkB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;IAC7D,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAuCD,wBAAgB,eAAe,CAAC,EAC5B,MAAM,EACN,QAAQ,EACR,WAAW,EACX,UAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,gBAAqB,EACrB,QAAQ,EACR,gBAAgB,EAChB,UAAc,EACd,YAAY,EACZ,MAAW,EACX,aAAa,EACb,YAAiB,EACjB,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,cAAc,GACjB,EAAE,oBAAoB,2CA2hBtB"}
@@ -433,6 +433,7 @@ export function TextBufferInput({ buffer, onSubmit, placeholder, isDisabled = fa
433
433
  const isShellMode = bufferText.startsWith('!');
434
434
  const promptPrefix = isShellMode ? '$ ' : '> ';
435
435
  const promptColor = isShellMode ? 'yellow' : 'green';
436
+ const separatorColor = isShellMode ? 'yellow' : 'gray';
436
437
  // Calculate visible window
437
438
  let startLine = 0;
438
439
  let endLine = totalLines;
@@ -449,7 +450,7 @@ export function TextBufferInput({ buffer, onSubmit, placeholder, isDisabled = fa
449
450
  if (bufferText === '') {
450
451
  return (_jsxs(Box, { flexDirection: "column", width: terminalWidth, children: [_jsx(Text, { color: "gray", children: separator }), _jsxs(Box, { width: terminalWidth, children: [_jsx(Text, { color: "green", bold: true, children: '> ' }), _jsx(Text, { inverse: true, children: " " }), placeholder && _jsx(Text, { color: "gray", children: placeholder }), _jsx(Text, { children: ' '.repeat(Math.max(0, terminalWidth - 3 - (placeholder?.length || 0))) })] }), _jsx(Text, { color: "gray", children: separator })] }));
451
452
  }
452
- return (_jsxs(Box, { flexDirection: "column", width: terminalWidth, children: [_jsx(Text, { color: "gray", children: separator }), startLine > 0 && (_jsxs(Text, { color: "gray", children: [' ', "\u2191 ", startLine, " more line", startLine > 1 ? 's' : '', " above (", KEY_LABELS.altUp, " to jump)"] })), visibleLines.map((line, idx) => {
453
+ return (_jsxs(Box, { flexDirection: "column", width: terminalWidth, children: [_jsx(Text, { color: separatorColor, children: separator }), startLine > 0 && (_jsxs(Text, { color: "gray", children: [' ', "\u2191 ", startLine, " more line", startLine > 1 ? 's' : '', " above (", KEY_LABELS.altUp, " to jump)"] })), visibleLines.map((line, idx) => {
453
454
  const absoluteRow = startLine + idx;
454
455
  const isFirst = absoluteRow === 0;
455
456
  const prefix = isFirst ? promptPrefix : ' ';
@@ -461,7 +462,7 @@ export function TextBufferInput({ buffer, onSubmit, placeholder, isDisabled = fa
461
462
  const atCursor = line.charAt(cursorVisualCol) || ' ';
462
463
  const after = line.slice(cursorVisualCol + 1);
463
464
  return (_jsxs(Box, { width: terminalWidth, children: [_jsx(Text, { color: promptColor, bold: isFirst, children: prefix }), _jsx(HighlightedText, { text: before, query: highlightQuery }), _jsx(Text, { inverse: true, children: atCursor }), _jsx(HighlightedText, { text: after, query: highlightQuery }), _jsx(Text, { children: ' '.repeat(Math.max(0, terminalWidth - prefix.length - before.length - 1 - after.length)) })] }, absoluteRow));
464
- }), endLine < totalLines && (_jsxs(Text, { color: "gray", children: [' ', "\u2193 ", totalLines - endLine, " more line", totalLines - endLine > 1 ? 's' : '', ' ', "below (", KEY_LABELS.altDown, " to jump)"] })), pastedBlocks.length > 0 && (_jsx(PasteBlockHint, { pastedBlocks: pastedBlocks, expandedBlock: findExpandedBlock(), cursorOnCollapsed: findCollapsedBlockAtCursor() })), _jsx(Text, { color: "gray", children: separator })] }));
465
+ }), endLine < totalLines && (_jsxs(Text, { color: "gray", children: [' ', "\u2193 ", totalLines - endLine, " more line", totalLines - endLine > 1 ? 's' : '', ' ', "below (", KEY_LABELS.altDown, " to jump)"] })), pastedBlocks.length > 0 && (_jsx(PasteBlockHint, { pastedBlocks: pastedBlocks, expandedBlock: findExpandedBlock(), cursorOnCollapsed: findCollapsedBlockAtCursor() })), _jsx(Text, { color: separatorColor, children: separator })] }));
465
466
  }
466
467
  /** Hint component for paste blocks */
467
468
  function PasteBlockHint({ pastedBlocks, expandedBlock, cursorOnCollapsed, }) {
@@ -1 +1 @@
1
- {"version":3,"file":"MessageItem.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/chat/MessageItem.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EACR,OAAO,EAUV,MAAM,sBAAsB,CAAC;AAuC9B,UAAU,gBAAgB;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,mEACc,gBAAgB,6CA+LrD,CAAC"}
1
+ {"version":3,"file":"MessageItem.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/chat/MessageItem.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EACR,OAAO,EAUV,MAAM,sBAAsB,CAAC;AAuC9B,UAAU,gBAAgB;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,mEACc,gBAAgB,6CAkNrD,CAAC"}
@@ -105,12 +105,15 @@ export const MessageItem = memo(({ message, terminalWidth = 80 }) => {
105
105
  const hasStructuredDisplay = message.toolDisplayData && message.toolContent;
106
106
  const isRunning = message.toolStatus === 'running';
107
107
  const isPending = message.toolStatus === 'pending' || message.toolStatus === 'pending_approval';
108
+ // Check for sub-agent progress data
109
+ const subAgentProgress = message.subAgentProgress;
108
110
  // Parse tool name and args for bold formatting: "ToolName(args)" → bold name + normal args
109
111
  const parenIndex = message.content.indexOf('(');
110
112
  const toolName = parenIndex > 0 ? message.content.slice(0, parenIndex) : message.content;
111
113
  const toolArgs = parenIndex > 0 ? message.content.slice(parenIndex) : '';
112
114
  // Build the full tool header text for wrapping
113
- const statusSuffix = isRunning ? ' Running...' : isPending ? ' Waiting...' : '';
115
+ // Don't include status suffix if we have sub-agent progress (it shows its own status)
116
+ const statusSuffix = subAgentProgress ? '' : isRunning ? ' Running...' : isPending ? ' Waiting...' : '';
114
117
  const fullToolText = `${toolName}${toolArgs}${statusSuffix}`;
115
118
  // ToolIcon takes 2 chars ("● "), so available width is terminalWidth - 2
116
119
  const iconWidth = 2;
@@ -121,7 +124,7 @@ export const MessageItem = memo(({ message, terminalWidth = 80 }) => {
121
124
  trim: false,
122
125
  });
123
126
  const toolLines = wrappedToolText.split('\n');
124
- return (_jsxs(Box, { flexDirection: "column", marginTop: 1, width: terminalWidth, children: [toolLines.map((line, i) => (_jsxs(Box, { flexDirection: "row", children: [i === 0 ? (_jsx(ToolIcon, { status: message.toolStatus || 'finished', isError: message.isError ?? false })) : (_jsx(Text, { children: ' ' })), _jsx(Text, { children: i === 0 ? (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, children: line.slice(0, toolName.length) }), _jsx(Text, { children: line.slice(toolName.length) })] })) : (line) })] }, i))), hasStructuredDisplay ? (_jsx(ToolResultRenderer, { display: message.toolDisplayData, content: message.toolContent })) : (message.toolResult && (_jsx(Box, { flexDirection: "column", children: _jsxs(Text, { color: "gray", children: [" \u23BF ", message.toolResult] }) })))] }));
127
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 1, width: terminalWidth, children: [toolLines.map((line, i) => (_jsxs(Box, { flexDirection: "row", children: [i === 0 ? (_jsx(ToolIcon, { status: message.toolStatus || 'finished', isError: message.isError ?? false })) : (_jsx(Text, { children: ' ' })), _jsx(Text, { children: i === 0 ? (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, children: line.slice(0, toolName.length) }), _jsx(Text, { children: line.slice(toolName.length) })] })) : (line) })] }, i))), subAgentProgress && isRunning && (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { color: "gray", children: ["\u2514\u2500 ", subAgentProgress.toolsCalled, " tool", subAgentProgress.toolsCalled !== 1 ? 's' : '', " called | Current:", ' ', subAgentProgress.currentTool] }) })), hasStructuredDisplay ? (_jsx(ToolResultRenderer, { display: message.toolDisplayData, content: message.toolContent })) : (message.toolResult && (_jsx(Box, { flexDirection: "column", children: _jsxs(Text, { color: "gray", children: [" \u23BF ", message.toolResult] }) })))] }));
125
128
  }
126
129
  // System message: Compact gray text
127
130
  return (_jsx(Box, { flexDirection: "column", marginBottom: 1, width: terminalWidth, children: _jsx(Text, { color: "gray", children: message.content }) }));
@@ -140,6 +143,10 @@ export const MessageItem = memo(({ message, terminalWidth = 80 }) => {
140
143
  prev.message.isError === next.message.isError &&
141
144
  prev.message.toolDisplayData === next.message.toolDisplayData &&
142
145
  prev.message.toolContent === next.message.toolContent &&
143
- prev.terminalWidth === next.terminalWidth);
146
+ prev.terminalWidth === next.terminalWidth &&
147
+ prev.message.subAgentProgress?.toolsCalled ===
148
+ next.message.subAgentProgress?.toolsCalled &&
149
+ prev.message.subAgentProgress?.currentTool ===
150
+ next.message.subAgentProgress?.currentTool);
144
151
  });
145
152
  MessageItem.displayName = 'MessageItem';
@@ -1 +1 @@
1
- {"version":3,"file":"AlternateBufferCLI.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/modes/AlternateBufferCLI.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,sBAAsB,CAAC;AA2BjE,UAAU,uBAAuB;IAC7B,KAAK,EAAE,UAAU,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,WAAW,CAAC;IACzB,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,YAAmB,GACtB,EAAE,uBAAuB,2CAgTzB"}
1
+ {"version":3,"file":"AlternateBufferCLI.d.ts","sourceRoot":"","sources":["../../../../../src/cli/ink-cli/components/modes/AlternateBufferCLI.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,sBAAsB,CAAC;AA2BjE,UAAU,uBAAuB;IAC7B,KAAK,EAAE,UAAU,CAAC;IAClB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,EAAE,WAAW,CAAC;IACzB,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,EAC/B,KAAK,EACL,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,YAAmB,GACtB,EAAE,uBAAuB,2CAiTzB"}
@@ -162,5 +162,5 @@ export function AlternateBufferCLI({ agent, initialSessionId, startupInfo, onSel
162
162
  return 'header';
163
163
  return item.message.id;
164
164
  }, []);
165
- return (_jsxs(Box, { flexDirection: "column", height: terminalHeight, children: [_jsx(Box, { ref: listContainerRef, flexGrow: 1, flexShrink: 1, minHeight: 0, children: _jsx(VirtualizedList, { ref: listRef, data: listData, renderItem: renderListItem, estimatedItemHeight: estimateItemHeight, keyExtractor: getItemKey, initialScrollIndex: SCROLL_TO_ITEM_END, initialScrollOffsetInIndex: SCROLL_TO_ITEM_END }) }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [_jsx(StatusBar, { agent: agent, isProcessing: ui.isProcessing, isThinking: ui.isThinking, approvalQueueCount: approvalQueue.length, copyModeEnabled: ui.copyModeEnabled, isAwaitingApproval: approval !== null }), selectionHintVisible && (_jsx(Box, { paddingX: 1, children: _jsx(Text, { color: "yellowBright", children: "\uD83D\uDCA1 Tip: Hold Option (\u2325) and click to select text, or press Ctrl+S to toggle copy mode" }) })), _jsx(QueuedMessagesDisplay, { messages: queuedMessages }), _jsx(InputContainer, { ref: inputContainerRef, buffer: buffer, input: input, ui: ui, session: session, approval: approval, queuedMessages: queuedMessages, setInput: setInput, setUi: setUi, setSession: setSession, setMessages: setMessages, setPendingMessages: setPendingMessages, setDequeuedBuffer: setDequeuedBuffer, setQueuedMessages: setQueuedMessages, setApproval: setApproval, setApprovalQueue: setApprovalQueue, agent: agent, inputService: inputService, onKeyboardScroll: handleKeyboardScroll, useStreaming: useStreaming }), _jsx(OverlayContainer, { ref: overlayContainerRef, ui: ui, input: input, session: session, approval: approval, setInput: setInput, setUi: setUi, setSession: setSession, setMessages: setMessages, setApproval: setApproval, setApprovalQueue: setApprovalQueue, agent: agent, inputService: inputService, buffer: buffer, onSubmitPromptCommand: handleSubmitPromptCommand }), ui.exitWarningShown && (_jsxs(Box, { paddingX: 1, children: [_jsx(Text, { color: "yellowBright", bold: true, children: "\u26A0 Press Ctrl+C again to exit" }), _jsx(Text, { color: "gray", children: " (or press any key to cancel)" })] })), _jsx(Footer, { modelName: session.modelName, cwd: process.cwd(), autoApproveEdits: ui.autoApproveEdits }), ui.historySearch.isActive && (_jsx(HistorySearchBar, { query: ui.historySearch.query, hasMatch: historySearchHasMatch }))] })] }));
165
+ return (_jsxs(Box, { flexDirection: "column", height: terminalHeight, children: [_jsx(Box, { ref: listContainerRef, flexGrow: 1, flexShrink: 1, minHeight: 0, children: _jsx(VirtualizedList, { ref: listRef, data: listData, renderItem: renderListItem, estimatedItemHeight: estimateItemHeight, keyExtractor: getItemKey, initialScrollIndex: SCROLL_TO_ITEM_END, initialScrollOffsetInIndex: SCROLL_TO_ITEM_END }) }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [_jsx(StatusBar, { agent: agent, isProcessing: ui.isProcessing, isThinking: ui.isThinking, approvalQueueCount: approvalQueue.length, copyModeEnabled: ui.copyModeEnabled, isAwaitingApproval: approval !== null }), selectionHintVisible && (_jsx(Box, { paddingX: 1, children: _jsx(Text, { color: "yellowBright", children: "\uD83D\uDCA1 Tip: Hold Option (\u2325) and click to select text, or press Ctrl+S to toggle copy mode" }) })), _jsx(QueuedMessagesDisplay, { messages: queuedMessages }), _jsx(InputContainer, { ref: inputContainerRef, buffer: buffer, input: input, ui: ui, session: session, approval: approval, queuedMessages: queuedMessages, setInput: setInput, setUi: setUi, setSession: setSession, setMessages: setMessages, setPendingMessages: setPendingMessages, setDequeuedBuffer: setDequeuedBuffer, setQueuedMessages: setQueuedMessages, setApproval: setApproval, setApprovalQueue: setApprovalQueue, agent: agent, inputService: inputService, onKeyboardScroll: handleKeyboardScroll, useStreaming: useStreaming }), _jsx(OverlayContainer, { ref: overlayContainerRef, ui: ui, input: input, session: session, approval: approval, setInput: setInput, setUi: setUi, setSession: setSession, setMessages: setMessages, setApproval: setApproval, setApprovalQueue: setApprovalQueue, agent: agent, inputService: inputService, buffer: buffer, onSubmitPromptCommand: handleSubmitPromptCommand }), ui.exitWarningShown && (_jsxs(Box, { paddingX: 1, children: [_jsx(Text, { color: "yellowBright", bold: true, children: "\u26A0 Press Ctrl+C again to exit" }), _jsx(Text, { color: "gray", children: " (or press any key to cancel)" })] })), _jsx(Footer, { modelName: session.modelName, cwd: process.cwd(), autoApproveEdits: ui.autoApproveEdits, isShellMode: buffer.text.startsWith('!') }), ui.historySearch.isActive && (_jsx(HistorySearchBar, { query: ui.historySearch.query, hasMatch: historySearchHasMatch }))] })] }));
166
166
  }