@@ -48,49 +48,133 @@ Extensions are automatically discovered and loaded when cmux starts.
4848
4949``` typescript
5050interface Extension {
51+ /**
52+ * Hook called after a tool is executed.
53+ * Extensions can monitor, log, or modify the tool result.
54+ *
55+ * @param payload - Tool execution context with full Runtime access
56+ * @returns The tool result (modified or unmodified). Return undefined to leave unchanged.
57+ */
5158 onPostToolUse? : (payload : PostToolUseHookPayload ) => Promise <unknown > | unknown ;
5259}
5360
5461interface PostToolUseHookPayload {
55- toolName: string ; // e.g., "bash", "file_edit"
56- toolCallId: string ; // Unique ID for this tool invocation
57- args: unknown ; // Tool arguments
58- result: unknown ; // Tool result (can be modified)
59- workspaceId: string ; // Workspace identifier
60- timestamp: number ; // Unix timestamp (ms)
61- runtime: Runtime ; // Full workspace runtime access
62+ /** Tool name (e.g., "bash", "file_edit_replace_string") */
63+ toolName: string ;
64+
65+ /** Unique ID for this tool invocation */
66+ toolCallId: string ;
67+
68+ /** Tool-specific arguments (structure varies by tool) */
69+ args: unknown ;
70+
71+ /** Tool result (structure varies by tool) - can be modified and returned */
72+ result: unknown ;
73+
74+ /** Workspace identifier */
75+ workspaceId: string ;
76+
77+ /** Unix timestamp in milliseconds */
78+ timestamp: number ;
79+
80+ /** Full workspace runtime access (see Runtime API below) */
81+ runtime: Runtime ;
6282}
6383```
6484
6585## Runtime API
6686
67- Extensions receive a ` runtime ` object with full workspace access:
87+ Extensions receive a ` runtime ` object providing low-level access to the workspace :
6888
6989``` typescript
7090interface Runtime {
71- // Execute bash commands with streaming I/O
91+ /**
92+ * Execute a bash command with streaming I/O
93+ * @param command - Bash script to execute
94+ * @param options - Execution options (cwd, env, timeout, etc.)
95+ * @returns Streaming handles for stdin/stdout/stderr and exit code
96+ */
7297 exec(command : string , options : ExecOptions ): Promise <ExecStream >;
7398
74- // File operations (streaming primitives)
99+ /**
100+ * Read file contents as a stream
101+ * @param path - Path to file (relative to workspace root)
102+ * @param abortSignal - Optional abort signal
103+ * @returns Readable stream of file contents
104+ */
75105 readFile(path : string , abortSignal ? : AbortSignal ): ReadableStream <Uint8Array >;
106+
107+ /**
108+ * Write file contents from a stream
109+ * @param path - Path to file (relative to workspace root)
110+ * @param abortSignal - Optional abort signal
111+ * @returns Writable stream for file contents
112+ */
76113 writeFile(path : string , abortSignal ? : AbortSignal ): WritableStream <Uint8Array >;
114+
115+ /**
116+ * Get file statistics
117+ * @param path - Path to file or directory
118+ * @param abortSignal - Optional abort signal
119+ * @returns File statistics (size, modified time, isDirectory)
120+ */
77121 stat(path : string , abortSignal ? : AbortSignal ): Promise <FileStat >;
78122
79- // Path operations
123+ /**
124+ * Compute absolute workspace path
125+ * @param projectPath - Project root path
126+ * @param workspaceName - Workspace name
127+ * @returns Absolute path to workspace
128+ */
80129 getWorkspacePath(projectPath : string , workspaceName : string ): string ;
130+
131+ /**
132+ * Normalize a path for comparison
133+ * @param targetPath - Path to normalize
134+ * @param basePath - Base path for relative resolution
135+ * @returns Normalized path
136+ */
81137 normalizePath(targetPath : string , basePath : string ): string ;
82- resolvePath(path : string ): Promise <string >;
83138
84- // Workspace operations
85- createWorkspace(params : WorkspaceCreationParams ): Promise <WorkspaceCreationResult >;
86- initWorkspace(params : WorkspaceInitParams ): Promise <WorkspaceInitResult >;
87- deleteWorkspace(...): Promise <Result >;
88- renameWorkspace(...): Promise <Result >;
89- forkWorkspace(...): Promise <Result >;
139+ /**
140+ * Resolve path to absolute, canonical form
141+ * @param path - Path to resolve (may contain ~ or be relative)
142+ * @returns Absolute path
143+ */
144+ resolvePath(path : string ): Promise <string >;
145+ }
146+
147+ interface ExecOptions {
148+ /** Working directory (usually "." for workspace root) */
149+ cwd: string ;
150+ /** Environment variables */
151+ env? : Record <string , string >;
152+ /** Timeout in seconds (required) */
153+ timeout: number ;
154+ /** Process niceness (-20 to 19) */
155+ niceness? : number ;
156+ /** Abort signal */
157+ abortSignal? : AbortSignal ;
158+ }
159+
160+ interface ExecStream {
161+ stdout: ReadableStream <Uint8Array >;
162+ stderr: ReadableStream <Uint8Array >;
163+ stdin: WritableStream <Uint8Array >;
164+ exitCode: Promise <number >;
165+ duration: Promise <number >;
166+ }
167+
168+ interface FileStat {
169+ size: number ;
170+ modifiedTime: Date ;
171+ isDirectory: boolean ;
90172}
91173```
92174
93- ** Most extensions will use ` runtime.exec() ` for file operations:**
175+ ### Common Patterns
176+
177+ ** Most extensions will use ` runtime.exec() ` for simplicity:**
94178
95179``` typescript
96180// Write file
@@ -101,9 +185,13 @@ await runtime.exec(`echo "line" >> file.txt`, { cwd: ".", timeout: 5 });
101185
102186// Read file
103187const result = await runtime .exec (` cat file.txt ` , { cwd: " ." , timeout: 5 });
188+
189+ // Check if file exists
190+ const { exitCode } = await runtime .exec (` test -f file.txt ` , { cwd: " ." , timeout: 5 });
191+ const exists = exitCode === 0 ;
104192```
105193
106- All paths are relative to the workspace root.
194+ All file paths are relative to the workspace root.
107195
108196## Modifying Tool Results
109197
0 commit comments