Skip to content

Commit 37ef566

Browse files
committed
plumb: add executeBash IPC call
1 parent fe29755 commit 37ef566

File tree

9 files changed

+307
-24
lines changed

9 files changed

+307
-24
lines changed

docs/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,31 @@ docs/
4040

4141
### Example Mermaid Diagram
4242

43-
~~~markdown
43+
````markdown
4444
```mermaid
4545
graph LR
4646
A[Start] --> B[Process]
4747
B --> C[End]
4848
```
49-
~~~
49+
````
5050

5151
## CI/CD
5252

5353
Docs are automatically built and deployed via `.github/workflows/docs.yml` when:
54+
5455
- Changes are pushed to `main` branch in the `docs/` directory
5556
- Workflow is manually triggered
5657

5758
## Requirements
5859

5960
The following tools are needed to build locally:
61+
6062
- `mdbook` (v0.4.52+)
6163
- `mdbook-mermaid` (v0.16.0+)
6264
- `mdbook-linkcheck` (v0.7.7+)
6365

6466
Install via cargo:
67+
6568
```bash
6669
cargo install mdbook mdbook-mermaid mdbook-linkcheck
6770
mdbook-mermaid install docs

docs/src/keybinds.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,35 +10,36 @@ cmux is designed to be keyboard-driven for maximum efficiency. All major actions
1010
- **Linux/Windows**: Shortcuts use `Ctrl` as the primary modifier
1111

1212
When documentation shows `Ctrl`, it means:
13+
1314
- `` (Command) on macOS
1415
- `Ctrl` on Linux/Windows
1516

1617
## General
1718

18-
| Action | Shortcut |
19-
|--------|----------|
20-
| Cancel / Close / Interrupt | `Esc` |
19+
| Action | Shortcut |
20+
| -------------------------- | -------- |
21+
| Cancel / Close / Interrupt | `Esc` |
2122

2223
## Chat & Messages
2324

24-
| Action | Shortcut |
25-
|--------|----------|
26-
| Send message | `Enter` |
27-
| New line in message | `Shift+Enter` |
28-
| Jump to bottom of chat | `Shift+G` |
25+
| Action | Shortcut |
26+
| ---------------------- | ------------- |
27+
| Send message | `Enter` |
28+
| New line in message | `Shift+Enter` |
29+
| Jump to bottom of chat | `Shift+G` |
2930

3031
## Workspaces
3132

32-
| Action | Shortcut |
33-
|--------|----------|
33+
| Action | Shortcut |
34+
| -------------------- | -------- |
3435
| Create new workspace | `Ctrl+N` |
35-
| Next workspace | `Ctrl+J` |
36-
| Previous workspace | `Ctrl+K` |
36+
| Next workspace | `Ctrl+J` |
37+
| Previous workspace | `Ctrl+K` |
3738

3839
## Modes
3940

40-
| Action | Shortcut |
41-
|--------|----------|
41+
| Action | Shortcut |
42+
| ---------------------------------- | -------------- |
4243
| Toggle between Plan and Exec modes | `Ctrl+Shift+M` |
4344

4445
## Tips

docs/theme/custom.css

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@
55
--bg-primary: #1e1e1e;
66
--bg-secondary: #262626;
77
--bg-tertiary: #333333;
8-
8+
99
--text-primary: #d4d4d4;
1010
--text-secondary: #6b6b6b;
1111
--text-muted: #404040;
12-
12+
1313
--accent-blue: #3b7fb5;
1414
--accent-green: #4a8a5f;
1515
--accent-yellow: #f59e0b;
1616
--accent-red: #b54040;
17-
17+
1818
--border-color: #404040;
1919
--link-color: #4a9eff;
2020
--link-hover: #6bb0ff;
21-
21+
2222
/* Override mdbook's default variables */
2323
--bg: var(--bg-primary) !important;
2424
--table-alternate-bg: var(--bg-secondary) !important; /* Fix blue alternate row background */
@@ -121,7 +121,7 @@ table tbody tr:hover {
121121
table code {
122122
background-color: var(--bg-primary) !important;
123123
color: var(--accent-yellow) !important;
124-
font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
124+
font-family: "Monaco", "Menlo", "Courier New", monospace;
125125
font-size: 0.9em;
126126
}
127127

@@ -139,7 +139,12 @@ blockquote strong {
139139
}
140140

141141
/* Headers */
142-
h1, h2, h3, h4, h5, h6 {
142+
h1,
143+
h2,
144+
h3,
145+
h4,
146+
h5,
147+
h6 {
143148
color: var(--text-primary) !important;
144149
border-bottom-color: var(--border-color) !important;
145150
}

src/constants/ipc-constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const IPC_CHANNELS = {
2525
WORKSPACE_TRUNCATE_HISTORY: "workspace:truncateHistory",
2626
WORKSPACE_STREAM_HISTORY: "workspace:streamHistory",
2727
WORKSPACE_GET_INFO: "workspace:getInfo",
28+
WORKSPACE_EXECUTE_BASH: "workspace:executeBash",
2829

2930
// Dynamic channel prefixes
3031
WORKSPACE_CHAT_PREFIX: "workspace:chat:",

src/preload.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ const api: IPCApi = {
4949
truncateHistory: (workspaceId, percentage) =>
5050
ipcRenderer.invoke(IPC_CHANNELS.WORKSPACE_TRUNCATE_HISTORY, workspaceId, percentage),
5151
getInfo: (workspaceId) => ipcRenderer.invoke(IPC_CHANNELS.WORKSPACE_GET_INFO, workspaceId),
52+
executeBash: (workspaceId, script, options) =>
53+
ipcRenderer.invoke(IPC_CHANNELS.WORKSPACE_EXECUTE_BASH, workspaceId, script, options),
5254

5355
onChat: (workspaceId, callback) => {
5456
const channel = getChatChannel(workspaceId);

src/services/ipcMain.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import type { SendMessageError } from "@/types/errors";
2222
import type { StreamErrorMessage, SendMessageOptions, DeleteMessage } from "@/types/ipc";
2323
import { Ok, Err } from "@/types/result";
2424
import { validateWorkspaceName } from "@/utils/validation/workspaceValidation";
25+
import { createBashTool } from "@/services/tools/bash";
26+
import type { BashToolResult } from "@/types/tools";
2527

2628
const createUnknownSendMessageError = (raw: string): SendMessageError => ({
2729
type: "unknown",
@@ -536,6 +538,48 @@ export class IpcMain {
536538
return { success: true, data: undefined };
537539
}
538540
);
541+
542+
ipcMain.handle(
543+
IPC_CHANNELS.WORKSPACE_EXECUTE_BASH,
544+
async (
545+
_event,
546+
workspaceId: string,
547+
script: string,
548+
options?: { timeout_secs?: number; max_lines?: number; stdin?: string }
549+
) => {
550+
try {
551+
// Get workspace metadata to find workspacePath
552+
const metadataResult = await this.aiService.getWorkspaceMetadata(workspaceId);
553+
if (!metadataResult.success) {
554+
return Err(`Failed to get workspace metadata: ${metadataResult.error}`);
555+
}
556+
557+
const workspacePath = metadataResult.data.workspacePath;
558+
559+
// Create bash tool with workspace's cwd
560+
const bashTool = createBashTool({ cwd: workspacePath });
561+
562+
// Execute the script with provided options
563+
const result = (await bashTool.execute!(
564+
{
565+
script,
566+
timeout_secs: options?.timeout_secs ?? 120,
567+
max_lines: options?.max_lines ?? 1000,
568+
stdin: options?.stdin,
569+
},
570+
{
571+
toolCallId: `bash-${Date.now()}`,
572+
messages: [],
573+
}
574+
)) as BashToolResult;
575+
576+
return Ok(result);
577+
} catch (error) {
578+
const message = error instanceof Error ? error.message : String(error);
579+
return Err(`Failed to execute bash command: ${message}`);
580+
}
581+
}
582+
);
539583
}
540584

541585
private registerProviderHandlers(ipcMain: ElectronIpcMain): void {

src/types/ipc.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { ProjectConfig } from "@/config";
55
import type { SendMessageError, StreamErrorType } from "./errors";
66
import type { ThinkingLevel } from "./thinking";
77
import type { ToolPolicy } from "@/utils/tools/toolPolicy";
8+
import type { BashToolResult } from "./tools";
89
import type {
910
StreamStartEvent,
1011
StreamDeltaEvent,
@@ -167,6 +168,11 @@ export interface IPCApi {
167168
): Promise<Result<void, SendMessageError>>;
168169
truncateHistory(workspaceId: string, percentage?: number): Promise<Result<void, string>>;
169170
getInfo(workspaceId: string): Promise<WorkspaceMetadata | null>;
171+
executeBash(
172+
workspaceId: string,
173+
script: string,
174+
options?: { timeout_secs?: number; max_lines?: number; stdin?: string }
175+
): Promise<Result<BashToolResult, string>>;
170176

171177
// Event subscriptions (renderer-only)
172178
// These methods are designed to send current state immediately upon subscription,

0 commit comments

Comments
 (0)