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.
- package/dist/agents/agent-registry.json +9 -0
- package/dist/agents/coding-agent/coding-agent.yml +37 -6
- package/dist/agents/explore-agent/explore-agent.yml +124 -0
- package/dist/cli/approval/cli-approval-handler.d.ts +28 -0
- package/dist/cli/approval/cli-approval-handler.d.ts.map +1 -0
- package/dist/cli/approval/cli-approval-handler.js +146 -0
- package/dist/cli/approval/index.d.ts +7 -0
- package/dist/cli/approval/index.d.ts.map +1 -0
- package/dist/cli/approval/index.js +6 -0
- package/dist/cli/commands/interactive-commands/general-commands.d.ts.map +1 -1
- package/dist/cli/commands/interactive-commands/general-commands.js +5 -2
- package/dist/cli/ink-cli/components/ApprovalPrompt.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/ApprovalPrompt.js +10 -2
- package/dist/cli/ink-cli/components/Footer.d.ts +3 -1
- package/dist/cli/ink-cli/components/Footer.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/Footer.js +4 -2
- package/dist/cli/ink-cli/components/TextBufferInput.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/TextBufferInput.js +3 -2
- package/dist/cli/ink-cli/components/chat/MessageItem.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/chat/MessageItem.js +10 -3
- package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/AlternateBufferCLI.js +1 -1
- package/dist/cli/ink-cli/components/modes/StaticCLI.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/modes/StaticCLI.js +1 -1
- package/dist/cli/ink-cli/components/renderers/SearchRenderer.d.ts.map +1 -1
- package/dist/cli/ink-cli/components/renderers/SearchRenderer.js +15 -1
- package/dist/cli/ink-cli/constants/processingPhrases.js +1 -1
- package/dist/cli/ink-cli/constants/tips.d.ts.map +1 -1
- package/dist/cli/ink-cli/constants/tips.js +2 -1
- package/dist/cli/ink-cli/services/processStream.d.ts.map +1 -1
- package/dist/cli/ink-cli/services/processStream.js +77 -13
- package/dist/cli/ink-cli/state/types.d.ts +17 -0
- package/dist/cli/ink-cli/state/types.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/messageFormatting.d.ts +24 -0
- package/dist/cli/ink-cli/utils/messageFormatting.d.ts.map +1 -1
- package/dist/cli/ink-cli/utils/messageFormatting.js +41 -2
- package/dist/index.js +5 -15
- package/dist/webui/assets/index-CUVc7IDL.css +1 -0
- package/dist/webui/assets/{index-8j-KMkX1.js → index-SGm5dxhp.js} +208 -208
- package/dist/webui/index.html +2 -2
- package/package.json +7 -7
- 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
|
-
|
|
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--
|
|
76
|
-
- custom--
|
|
77
|
-
- custom--
|
|
78
|
-
- custom--
|
|
79
|
-
- custom--
|
|
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 @@
|
|
|
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"}
|
|
@@ -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;
|
|
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
|
-
|
|
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,
|
|
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: [
|
|
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;
|
|
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
|
-
|
|
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,
|
|
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:
|
|
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:
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
}
|