(
projectPath: string
)
| 394 | } |
| 395 | |
| 396 | async create( |
| 397 | projectPath: string |
| 398 | ): Promise<Result<{ projectConfig: ProjectConfig; normalizedPath: string }>> { |
| 399 | try { |
| 400 | // Validate input |
| 401 | if (!projectPath || projectPath.trim().length === 0) { |
| 402 | return Err("Project path cannot be empty"); |
| 403 | } |
| 404 | |
| 405 | // Resolve the path: |
| 406 | // - Bare names like "my-project" → ~/.mux/projects/my-project |
| 407 | // - Paths with ~ → expand to home directory |
| 408 | // - Absolute/relative paths → resolve normally |
| 409 | const isBareProjectName = |
| 410 | projectPath.length > 0 && |
| 411 | !projectPath.includes("/") && |
| 412 | !projectPath.includes("\\") && |
| 413 | !projectPath.startsWith("~"); |
| 414 | |
| 415 | const config = this.config.loadConfigOrDefault(); |
| 416 | let normalizedPath: string; |
| 417 | if (isBareProjectName) { |
| 418 | // Bare project name - put in default projects directory |
| 419 | const parentDir = resolveProjectParentDir(undefined, config.defaultProjectDir); |
| 420 | normalizedPath = path.join(parentDir, projectPath); |
| 421 | } else if ( |
| 422 | projectPath === "~" || |
| 423 | projectPath.startsWith("~/") || |
| 424 | projectPath.startsWith("~\\") |
| 425 | ) { |
| 426 | // Tilde expansion - uses expandTilde to respect MUX_ROOT for ~/.mux paths |
| 427 | normalizedPath = path.resolve(expandTilde(projectPath)); |
| 428 | } else { |
| 429 | normalizedPath = path.resolve(projectPath); |
| 430 | } |
| 431 | |
| 432 | let existingStat: Stats | null = null; |
| 433 | try { |
| 434 | existingStat = await fsPromises.stat(normalizedPath); |
| 435 | } catch (error) { |
| 436 | const err = error as NodeJS.ErrnoException; |
| 437 | if (err.code !== "ENOENT") { |
| 438 | throw error; |
| 439 | } |
| 440 | } |
| 441 | |
| 442 | if (existingStat && !existingStat.isDirectory()) { |
| 443 | return Err("Project path is not a directory"); |
| 444 | } |
| 445 | |
| 446 | if (config.projects.has(normalizedPath)) { |
| 447 | return Err("Project already exists"); |
| 448 | } |
| 449 | |
| 450 | const createdDirectory = existingStat == null; |
| 451 | const cleanupCreatedDirectory = async () => { |
| 452 | if (!createdDirectory) return; |
| 453 | try { |
nothing calls this directly
no test coverage detected