MCPcopy
hub / github.com/coder/mux / executeBash

Method executeBash

src/node/services/workspaceService.ts:8544–8752  ·  view source on GitHub ↗
(
    workspaceId: string,
    script: string,
    options?: ExecuteBashOptions,
    command?: string,
    args?: string[]
  )

Source from the content-addressed store, hash-verified

8542 }
8543
8544 async executeBash(
8545 workspaceId: string,
8546 script: string,
8547 options?: ExecuteBashOptions,
8548 command?: string,
8549 args?: string[]
8550 ): Promise<Result<BashToolResult>> {
8551 // Block bash execution while workspace is being removed to prevent races with directory deletion.
8552 // A common case: subagent calls agent_report → frontend's GitStatusStore triggers a git status
8553 // refresh → executeBash arrives while remove() is deleting the directory → spawn fails with ENOENT.
8554 // removingWorkspaces is set for the entire duration of remove(), covering the window between
8555 // disk deletion and metadata invalidation.
8556 if (this.removingWorkspaces.has(workspaceId)) {
8557 return Err(`Workspace ${workspaceId} is being removed`);
8558 }
8559
8560 // NOTE: This guard must run before any init/runtime operations that could wake a stopped SSH
8561 // runtime (e.g., Coder workspaces started via `coder ssh --wait=yes`).
8562 if (this.archivingWorkspaces.has(workspaceId)) {
8563 return Err(`Workspace ${workspaceId} is being archived; cannot execute bash`);
8564 }
8565
8566 const metadataResult = await this.aiService.getWorkspaceMetadata(workspaceId);
8567 if (!metadataResult.success) {
8568 return Err(`Failed to get workspace metadata: ${metadataResult.error}`);
8569 }
8570
8571 const metadata = metadataResult.data;
8572 if (isWorkspaceArchived(metadata.archivedAt, metadata.unarchivedAt)) {
8573 return Err(`Workspace ${workspaceId} is archived; cannot execute bash`);
8574 }
8575
8576 // Wait for workspace initialization (container creation, code sync, etc.)
8577 // Same behavior as AI tools - 5 min timeout, then proceeds anyway
8578 await this.initStateManager.waitForInit(workspaceId);
8579
8580 try {
8581 // Get the persisted workspace entry from config. Multi-project git command mode needs the
8582 // workspace checkout path rather than metadata.projectPath, and other path-addressable
8583 // runtimes also reuse the persisted workspace root shown in the Explorer.
8584 const workspace = this.config.findWorkspace(workspaceId);
8585 if (!workspace) {
8586 return Err(`Workspace ${workspaceId} not found in config`);
8587 }
8588
8589 const multiProjectRuntimes = isMultiProject(metadata)
8590 ? getProjects(metadata).map((project) => ({
8591 projectPath: project.projectPath,
8592 projectName: project.projectName,
8593 runtime: createRuntime(metadata.runtimeConfig, {
8594 projectPath: project.projectPath,
8595 workspaceName: metadata.name,
8596 workspacePath: isSSHRuntime(metadata.runtimeConfig)
8597 ? getWorkspacePathHintForProject(
8598 {
8599 workspaceId,
8600 workspaceName: metadata.name,
8601 workspacePath: workspace.workspacePath,

Callers 15

getProjectGitStatusesMethod · 0.95
BranchSelectorFunction · 0.80
readFileLinesFunction · 0.80
detectWorkspacePRMethod · 0.80
fetchMergeQueueEntryMethod · 0.80
checkWorkspaceStatusMethod · 0.80
executeWorkspaceFetchMethod · 0.80
useGitBranchDetailsFunction · 0.80
ensureOriginFetchedFunction · 0.80
loadUnreadAssistedFunction · 0.80

Calls 15

ErrFunction · 0.90
isWorkspaceArchivedFunction · 0.90
isMultiProjectFunction · 0.90
getProjectsFunction · 0.90
createRuntimeFunction · 0.90
isSSHRuntimeFunction · 0.90
getSrcBaseDirFunction · 0.90
resolveWorkspaceRootPathFunction · 0.90
mergeMultiProjectSecretsFunction · 0.90
createBashToolFunction · 0.90

Tested by 4

seedTwoHunkReviewDiffFunction · 0.64
executeBashFunction · 0.64
executeBashUntilReadyFunction · 0.64