(params: TerminalCreateParams)
| 108 | } |
| 109 | |
| 110 | async create(params: TerminalCreateParams): Promise<TerminalSession> { |
| 111 | try { |
| 112 | // 1. Resolve workspace |
| 113 | const allMetadata = await this.config.getAllWorkspaceMetadata(); |
| 114 | const workspaceMetadata = allMetadata.find((w) => w.id === params.workspaceId); |
| 115 | |
| 116 | if (!workspaceMetadata) { |
| 117 | throw new Error(`Workspace not found: ${params.workspaceId}`); |
| 118 | } |
| 119 | |
| 120 | // Validate required fields before proceeding - projectPath is required for project-dir runtimes |
| 121 | if (!workspaceMetadata.projectPath) { |
| 122 | log.error("Workspace metadata missing projectPath", { |
| 123 | workspaceId: params.workspaceId, |
| 124 | name: workspaceMetadata.name, |
| 125 | runtimeConfig: workspaceMetadata.runtimeConfig, |
| 126 | projectName: workspaceMetadata.projectName, |
| 127 | metadata: JSON.stringify(workspaceMetadata), |
| 128 | }); |
| 129 | throw new Error( |
| 130 | `Workspace "${workspaceMetadata.name}" (${params.workspaceId}) is missing projectPath. ` + |
| 131 | `This may indicate a corrupted config or a workspace that was not properly associated with a project.` |
| 132 | ); |
| 133 | } |
| 134 | |
| 135 | // 2. Create runtime (pass workspace info for Docker container name derivation) |
| 136 | const runtime = createRuntimeForWorkspace(workspaceMetadata); |
| 137 | |
| 138 | // 3. Use the persisted workspace root everywhere users can observe it, except for runtimes |
| 139 | // like Docker whose executable cwd is intentionally translated inside the runtime. |
| 140 | const workspacePath = resolveWorkspaceExecutionPath(workspaceMetadata, runtime); |
| 141 | |
| 142 | // Keep integrated terminal context aligned with the bash tool for stable workspace metadata. |
| 143 | // We intentionally skip dynamic values (like cost/model) because long-lived shells would go stale. |
| 144 | const runtimeType = getRuntimeType(workspaceMetadata.runtimeConfig); |
| 145 | const shouldInjectLocalEnv = runtimeType === "local" || runtimeType === "worktree"; |
| 146 | const muxEnv = shouldInjectLocalEnv |
| 147 | ? getMuxEnv(workspaceMetadata.projectPath, runtimeType, workspaceMetadata.name, { |
| 148 | workspaceId: workspaceMetadata.id, |
| 149 | }) |
| 150 | : undefined; |
| 151 | |
| 152 | // Secrets are local/worktree only. Remote/docker-style transports would expose env via command args |
| 153 | // unless we add a dedicated secure propagation path. |
| 154 | const secrets = shouldInjectLocalEnv |
| 155 | ? await secretsToRecord( |
| 156 | this.config.getEffectiveSecrets(workspaceMetadata.projectPath), |
| 157 | this.opResolver |
| 158 | ) |
| 159 | : {}; |
| 160 | |
| 161 | // Any process launched from this terminal inherits these variables. |
| 162 | // Proxy URI propagation allows terminal tools to construct externally reachable links. |
| 163 | // MUX_PROXY_URI explicitly overrides VSCODE_PROXY_URI, and falls back to it when unset. |
| 164 | const terminalEnv = muxEnv ? { ...muxEnv, ...this.getProxyUriEnv(), ...secrets } : undefined; |
| 165 | |
| 166 | // 4. Setup emitters and buffer |
| 167 | // We don't know the sessionId yet (PTYService generates it), but PTYService uses a callback. |
nothing calls this directly
no test coverage detected