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

Method remove

src/node/services/projectService.ts:935–1114  ·  view source on GitHub ↗
(projectPath: string, force = false)

Source from the content-addressed store, hash-verified

933 }
934
935 async remove(projectPath: string, force = false): Promise<Result<void, ProjectRemoveError>> {
936 try {
937 const normalizedPath = stripTrailingSlashes(projectPath);
938 let config = this.config.loadConfigOrDefault();
939 let projectConfig = config.projects.get(normalizedPath);
940
941 if (!projectConfig) {
942 return Err({ type: "project_not_found" as const });
943 }
944
945 if (projectConfig.parentProjectPath) {
946 const parentProject = config.projects.get(projectConfig.parentProjectPath);
947 if (parentProject) {
948 for (const workspace of parentProject.workspaces) {
949 if (workspace.subProjectPath === normalizedPath) {
950 workspace.subProjectPath = undefined;
951 }
952 }
953 }
954 try {
955 await this.config.updateProjectSecrets(normalizedPath, []);
956 } catch (error) {
957 log.error(`Failed to clean up secrets for sub-project ${normalizedPath}:`, error);
958 }
959 config.projects.delete(normalizedPath);
960 await this.config.saveConfig(config);
961 return Ok(undefined);
962 }
963
964 // Self-healing: purge workspace entries whose backing directories no longer exist.
965 // This handles the case where a user manually deleted workspace dirs from ~/.mux/src/.
966 // Only check local/worktree runtimes — remote runtimes (SSH, Docker, devcontainer)
967 // have paths on the remote host that won't exist locally.
968 const localRuntimeTypes = new Set(["local", "worktree"]);
969 const survivingWorkspaces = [];
970 for (const ws of projectConfig.workspaces) {
971 const runtimeType = ws.runtimeConfig?.type;
972 const isLocal = runtimeType == null || localRuntimeTypes.has(runtimeType);
973 if (!isLocal) {
974 survivingWorkspaces.push(ws);
975 continue;
976 }
977 try {
978 await fsPromises.access(ws.path);
979 survivingWorkspaces.push(ws);
980 } catch (err: unknown) {
981 // Only prune when the directory is truly gone (ENOENT/ENOTDIR).
982 // Other errors (EACCES, transient I/O) mean the path may still exist.
983 const code = (err as NodeJS.ErrnoException).code;
984 if (code === "ENOENT" || code === "ENOTDIR") {
985 log.info(`Pruning stale workspace entry (directory missing): ${ws.path}`);
986 } else {
987 log.warn(
988 `Keeping workspace entry despite access error (${code ?? "unknown"}): ${ws.path}`
989 );
990 survivingWorkspaces.push(ws);
991 }
992 }

Callers

nothing calls this directly

Calls 15

stripTrailingSlashesFunction · 0.90
ErrFunction · 0.90
OkFunction · 0.90
getErrorMessageFunction · 0.90
loadConfigOrDefaultMethod · 0.80
updateProjectSecretsMethod · 0.80
saveConfigMethod · 0.80
setMethod · 0.80
getMethod · 0.65
pushMethod · 0.65

Tested by

no test coverage detected