@@ -14,20 +14,27 @@ export const RUNTIME_MODE = {
1414 LOCAL : "local" as const ,
1515 WORKTREE : "worktree" as const ,
1616 SSH : "ssh" as const ,
17+ DOCKER : "docker" as const ,
1718} as const ;
1819
1920/** Runtime string prefix for SSH mode (e.g., "ssh hostname") */
2021export const SSH_RUNTIME_PREFIX = "ssh " ;
2122
23+ /** Runtime string prefix for Docker mode (e.g., "docker ubuntu:22.04") */
24+ export const DOCKER_RUNTIME_PREFIX = "docker " ;
25+
2226export type RuntimeConfig = z . infer < typeof RuntimeConfigSchema > ;
2327
2428/**
25- * Parse runtime string from localStorage or UI input into mode and host
29+ * Parse runtime string from localStorage or UI input into mode and host/image
2630 * Format: "ssh <host>" -> { mode: "ssh", host: "<host>" }
2731 * "ssh" -> { mode: "ssh", host: "" }
32+ * "docker <image>" -> { mode: "docker", host: "<image>" }
33+ * "docker" -> { mode: "docker", host: "" }
2834 * "worktree" -> { mode: "worktree", host: "" }
2935 * "local" or undefined -> { mode: "local", host: "" }
3036 *
37+ * Note: For Docker, "host" field stores the image name for consistency.
3138 * Use this for UI state management (localStorage, form inputs)
3239 */
3340export function parseRuntimeModeAndHost ( runtime : string | null | undefined ) : {
@@ -60,6 +67,17 @@ export function parseRuntimeModeAndHost(runtime: string | null | undefined): {
6067 return { mode : RUNTIME_MODE . SSH , host : "" } ;
6168 }
6269
70+ // Check for "docker <image>" format
71+ if ( lowerTrimmed . startsWith ( DOCKER_RUNTIME_PREFIX ) ) {
72+ const image = trimmed . substring ( DOCKER_RUNTIME_PREFIX . length ) . trim ( ) ;
73+ return { mode : RUNTIME_MODE . DOCKER , host : image } ;
74+ }
75+
76+ // Plain "docker" without image
77+ if ( lowerTrimmed === RUNTIME_MODE . DOCKER ) {
78+ return { mode : RUNTIME_MODE . DOCKER , host : "" } ;
79+ }
80+
6381 // Try to parse as a plain mode
6482 const modeResult = RuntimeModeSchema . safeParse ( lowerTrimmed ) ;
6583 if ( modeResult . success ) {
@@ -71,15 +89,20 @@ export function parseRuntimeModeAndHost(runtime: string | null | undefined): {
7189}
7290
7391/**
74- * Build runtime string for storage/IPC from mode and host
75- * Returns: "ssh <host>" for SSH, "local" for local, undefined for worktree (default)
92+ * Build runtime string for storage/IPC from mode and host/image
93+ * Returns: "ssh <host>" for SSH, "docker <image>" for Docker, " local" for local, undefined for worktree (default)
7694 */
7795export function buildRuntimeString ( mode : RuntimeMode , host : string ) : string | undefined {
7896 if ( mode === RUNTIME_MODE . SSH ) {
7997 const trimmedHost = host . trim ( ) ;
8098 // Persist SSH mode even without a host so UI remains in SSH state
8199 return trimmedHost ? `${ SSH_RUNTIME_PREFIX } ${ trimmedHost } ` : "ssh" ;
82100 }
101+ if ( mode === RUNTIME_MODE . DOCKER ) {
102+ const trimmedImage = host . trim ( ) ;
103+ // Persist Docker mode even without an image so UI remains in Docker state
104+ return trimmedImage ? `${ DOCKER_RUNTIME_PREFIX } ${ trimmedImage } ` : "docker" ;
105+ }
83106 if ( mode === RUNTIME_MODE . LOCAL ) {
84107 return "local" ;
85108 }
@@ -96,6 +119,15 @@ export function isSSHRuntime(
96119 return config ?. type === "ssh" ;
97120}
98121
122+ /**
123+ * Type guard to check if a runtime config is Docker
124+ */
125+ export function isDockerRuntime (
126+ config : RuntimeConfig | undefined
127+ ) : config is Extract < RuntimeConfig , { type : "docker" } > {
128+ return config ?. type === "docker" ;
129+ }
130+
99131/**
100132 * Type guard to check if a runtime config uses worktree semantics.
101133 * This includes both explicit "worktree" type AND legacy "local" with srcBaseDir.
0 commit comments