|
1 | 1 | import { createLogger } from '@sim/logger' |
2 | | -import { TERMINAL_TOOL_NAME } from '@sim/terminal-protocol' |
| 2 | +import { TERMINAL_TOOL_NAME, type TerminalOperation } from '@sim/terminal-protocol' |
3 | 3 | import { getErrorMessage } from '@sim/utils/errors' |
4 | 4 | import type { AsyncCompletionSignal } from '@/lib/mothership/async-runs/lifecycle' |
5 | 5 | import { PERMISSION_WAIT_TIMEOUT_MS } from '@/lib/mothership/constants' |
@@ -38,16 +38,32 @@ import { getToolEntry, toolRequiresApproval } from '@/lib/mothership/tool-execut |
38 | 38 | const logger = createLogger('CopilotToolPermissionGate') |
39 | 39 |
|
40 | 40 | /** |
41 | | - * Whether a `terminal` call is one worth stopping for. |
| 41 | + * `terminal` operations that never deliver keystrokes to a shell, so they run |
| 42 | + * without a prompt. |
42 | 43 | * |
43 | 44 | * The catalog's approval flag is per tool, but the terminal tool covers both |
44 | | - * running commands and merely looking at the screen. Only running one is |
45 | | - * consequential; gating `read` or `list` would put a card in front of the user |
46 | | - * every time the agent glanced at a terminal, which trains them to click |
47 | | - * through the ones that matter. |
| 45 | + * running commands and merely looking at the screen; gating `read` or `list` |
| 46 | + * would put a card in front of the user every time the agent glanced at a |
| 47 | + * terminal, which trains them to click through the ones that matter. `input` |
| 48 | + * is not here: in a tmux pane it is typed at the shell prompt and Enter submits |
| 49 | + * it, so it runs commands just as `run` does. Anything not listed, including an |
| 50 | + * operation added later, is gated. |
48 | 51 | */ |
| 52 | +const UNGATED_TERMINAL_OPERATIONS: ReadonlySet<string> = new Set<TerminalOperation>([ |
| 53 | + 'read', |
| 54 | + 'list', |
| 55 | + 'cwd', |
| 56 | + 'panes', |
| 57 | + 'new', |
| 58 | + 'switch', |
| 59 | + 'close', |
| 60 | + 'kill', |
| 61 | + 'handoff', |
| 62 | +]) |
| 63 | + |
49 | 64 | function terminalOperationNeedsApproval(args: Record<string, unknown> | undefined): boolean { |
50 | | - return args?.operation === 'run' |
| 65 | + const operation = args?.operation |
| 66 | + return typeof operation !== 'string' || !UNGATED_TERMINAL_OPERATIONS.has(operation) |
51 | 67 | } |
52 | 68 |
|
53 | 69 | export const TOOL_AWAITING_APPROVAL_STATUS = MothershipStreamV1ToolStatus.awaiting_approval |
|
0 commit comments