Skip to content

Commit d65f52a

Browse files
committed
run terminal command with bang
1 parent d02a90a commit d65f52a

File tree

3 files changed

+68
-2
lines changed

3 files changed

+68
-2
lines changed

cli/src/commands/router.ts

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import { runTerminalCommand } from '@codebuff/sdk'
2+
13
import { handleInitializationFlowLocally } from './init'
24

35
import type { MultilineInputHandle } from '../components/multiline-input'
4-
import type { ChatMessage } from '../types/chat'
6+
import type { ChatMessage, ContentBlock } from '../types/chat'
57
import type { SendMessageFn } from '../types/contracts/send-message'
68
import type { User } from '../utils/auth'
79
import type { AgentMode } from '../utils/constants'
@@ -62,6 +64,67 @@ export function routeUserPrompt(params: {
6264
let postUserMessage: Parameters<SendMessageFn>[0]['postUserMessage'] =
6365
undefined
6466

67+
if (trimmed.startsWith('!')) {
68+
const toolCallId = crypto.randomUUID()
69+
const resultBlock: ContentBlock = {
70+
type: 'tool',
71+
toolName: 'run_terminal_command',
72+
toolCallId,
73+
input: { command: trimmed.slice(1).trim() },
74+
output: '',
75+
}
76+
77+
setMessages((prev) => [
78+
...prev,
79+
{
80+
id: `user-${Date.now()}`,
81+
variant: 'user',
82+
content: trimmed,
83+
timestamp: new Date().toISOString(),
84+
},
85+
{
86+
id: `sys-${Date.now()}`,
87+
variant: 'ai',
88+
content: '',
89+
blocks: [resultBlock],
90+
timestamp: new Date().toISOString(),
91+
},
92+
])
93+
94+
runTerminalCommand({
95+
command: trimmed.slice(1).trim(),
96+
process_type: 'SYNC',
97+
cwd: process.cwd(),
98+
timeout_seconds: -1,
99+
env: process.env,
100+
}).then(([{ value }]) => {
101+
setMessages((prev) => {
102+
const output = 'stdout' in value ? value.stdout : ''
103+
return prev.map((msg) => {
104+
if (!msg.blocks) {
105+
return msg
106+
}
107+
return {
108+
...msg,
109+
blocks: msg.blocks.map((block) =>
110+
'toolCallId' in block && block.toolCallId === toolCallId
111+
? {
112+
...block,
113+
output,
114+
}
115+
: block,
116+
),
117+
}
118+
})
119+
})
120+
})
121+
122+
saveToHistory(trimmed)
123+
setInputValue('')
124+
125+
return
126+
}
127+
65128
const normalized = trimmed.startsWith('/') ? trimmed.slice(1) : trimmed
66129
const cmd = normalized.split(/\s+/)[0].toLowerCase()
67130
if (cmd === 'login' || cmd === 'signin') {

sdk/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,5 @@ export { validateAgents } from './validate-agents'
3131
export type { ValidationResult, ValidateAgentsOptions } from './validate-agents'
3232

3333
export type { CodebuffFileSystem } from '@codebuff/common/types/filesystem'
34+
35+
export { runTerminalCommand } from './tools/run-terminal-command'

sdk/src/tools/run-terminal-command.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
stripColors,
77
truncateStringWithMessage,
88
} from '../../../common/src/util/string'
9+
910
import type { CodebuffToolOutput } from '../../../common/src/tools/list'
1011

1112
const COMMAND_OUTPUT_LIMIT = 50_000
@@ -21,7 +22,7 @@ export function runTerminalCommand({
2122
process_type: 'SYNC' | 'BACKGROUND'
2223
cwd: string
2324
timeout_seconds: number
24-
env?: Record<string, string>
25+
env?: Record<string, string | undefined>
2526
}): Promise<CodebuffToolOutput<'run_terminal_command'>> {
2627
if (process_type === 'BACKGROUND') {
2728
throw new Error('BACKGROUND process_type not implemented')

0 commit comments

Comments
 (0)