(workspaceId: string, newName: string)
| 4648 | } |
| 4649 | |
| 4650 | async rename(workspaceId: string, newName: string): Promise<Result<{ newWorkspaceId: string }>> { |
| 4651 | try { |
| 4652 | if (this.aiService.isStreaming(workspaceId)) { |
| 4653 | return Err( |
| 4654 | "Cannot rename workspace while AI stream is active. Please wait for the stream to complete." |
| 4655 | ); |
| 4656 | } |
| 4657 | |
| 4658 | const validation = validateWorkspaceName(newName); |
| 4659 | if (!validation.valid) { |
| 4660 | return Err(validation.error ?? "Invalid workspace name"); |
| 4661 | } |
| 4662 | |
| 4663 | // Mark workspace as renaming to block new streams during the rename operation |
| 4664 | this.renamingWorkspaces.add(workspaceId); |
| 4665 | |
| 4666 | const metadataResult = await this.aiService.getWorkspaceMetadata(workspaceId); |
| 4667 | if (!metadataResult.success) { |
| 4668 | return Err(`Failed to get workspace metadata: ${metadataResult.error}`); |
| 4669 | } |
| 4670 | const oldMetadata = metadataResult.data; |
| 4671 | const oldName = oldMetadata.name; |
| 4672 | |
| 4673 | if (newName === oldName) { |
| 4674 | return Ok({ newWorkspaceId: workspaceId }); |
| 4675 | } |
| 4676 | |
| 4677 | const allWorkspaces = await this.config.getAllWorkspaceMetadata(); |
| 4678 | const collision = allWorkspaces.find( |
| 4679 | (ws) => (ws.name === newName || ws.id === newName) && ws.id !== workspaceId |
| 4680 | ); |
| 4681 | if (collision) { |
| 4682 | return Err(`Workspace with name "${newName}" already exists`); |
| 4683 | } |
| 4684 | |
| 4685 | const workspace = this.config.findWorkspace(workspaceId); |
| 4686 | if (!workspace) { |
| 4687 | return Err("Failed to find workspace in config"); |
| 4688 | } |
| 4689 | const { projectPath: configProjectPath } = workspace; |
| 4690 | const configSnapshot = this.config.loadConfigOrDefault(); |
| 4691 | |
| 4692 | let oldPath: string; |
| 4693 | let newPath: string; |
| 4694 | let runtimeForPlanFile: ReturnType<typeof createRuntime>; |
| 4695 | |
| 4696 | if (isMultiProject(oldMetadata)) { |
| 4697 | const projects = getProjects(oldMetadata); |
| 4698 | const primaryProject = projects[0]; |
| 4699 | assert(primaryProject, "Multi-project workspace requires a primary project"); |
| 4700 | const renamedProjectWorkspaces: Array<{ |
| 4701 | projectName: string; |
| 4702 | projectPath: string; |
| 4703 | oldWorkspacePath: string; |
| 4704 | newWorkspacePath: string; |
| 4705 | }> = []; |
| 4706 | |
| 4707 | const rollbackRenamedProjects = async (): Promise<void> => { |
nothing calls this directly
no test coverage detected