@@ -4,7 +4,6 @@ import { useApp } from "./contexts/AppContext";
44import type { WorkspaceSelection } from "./components/ProjectSidebar" ;
55import type { FrontendWorkspaceMetadata } from "./types/workspace" ;
66import { LeftSidebar } from "./components/LeftSidebar" ;
7- import NewWorkspaceModal from "./components/NewWorkspaceModal" ;
87import { ProjectCreateModal } from "./components/ProjectCreateModal" ;
98import { AIView } from "./components/AIView" ;
109import { ErrorBoundary } from "./components/ErrorBoundary" ;
@@ -15,6 +14,7 @@ import { useUnreadTracking } from "./hooks/useUnreadTracking";
1514import { useAutoCompactContinue } from "./hooks/useAutoCompactContinue" ;
1615import { useWorkspaceStoreRaw , useWorkspaceRecency } from "./stores/WorkspaceStore" ;
1716import { ChatInput } from "./components/ChatInput/index" ;
17+ import type { ChatInputAPI } from "./components/ChatInput/types" ;
1818
1919import { useStableReference , compareMaps } from "./hooks/useStableReference" ;
2020import { CommandRegistryProvider , useCommandRegistry } from "./contexts/CommandRegistryContext" ;
@@ -25,13 +25,12 @@ import { CommandPalette } from "./components/CommandPalette";
2525import { buildCoreSources , type BuildSourcesParams } from "./utils/commands/sources" ;
2626
2727import type { ThinkingLevel } from "./types/thinking" ;
28- import type { RuntimeConfig } from "./types/runtime" ;
2928import { CUSTOM_EVENTS } from "./constants/events" ;
3029import { isWorkspaceForkSwitchEvent } from "./utils/workspaceFork" ;
31- import { getThinkingLevelKey , getRuntimeKey } from "./constants/storage" ;
30+ import { getThinkingLevelKey } from "./constants/storage" ;
3231import type { BranchListResult } from "./types/ipc" ;
3332import { useTelemetry } from "./hooks/useTelemetry" ;
34- import { parseRuntimeString } from "./utils/chatCommands " ;
33+ import { useStartWorkspaceCreation , getFirstProjectPath } from "./hooks/useStartWorkspaceCreation " ;
3534
3635const THINKING_LEVELS : ThinkingLevel [ ] = [ "off" , "low" , "medium" , "high" ] ;
3736
@@ -43,29 +42,40 @@ function AppInner() {
4342 removeProject,
4443 workspaceMetadata,
4544 setWorkspaceMetadata,
46- createWorkspace,
4745 removeWorkspace,
4846 renameWorkspace,
4947 selectedWorkspace,
5048 setSelectedWorkspace,
5149 } = useApp ( ) ;
5250 const [ projectCreateModalOpen , setProjectCreateModalOpen ] = useState ( false ) ;
53- const [ workspaceModalOpen , setWorkspaceModalOpen ] = useState ( false ) ;
54- const [ workspaceModalProject , setWorkspaceModalProject ] = useState < string | null > ( null ) ;
55- const [ workspaceModalProjectName , setWorkspaceModalProjectName ] = useState < string > ( "" ) ;
56- const [ workspaceModalBranches , setWorkspaceModalBranches ] = useState < string [ ] > ( [ ] ) ;
57- const [ workspaceModalDefaultTrunk , setWorkspaceModalDefaultTrunk ] = useState < string | undefined > (
58- undefined
59- ) ;
60- const [ workspaceModalLoadError , setWorkspaceModalLoadError ] = useState < string | null > ( null ) ;
61- const workspaceModalProjectRef = useRef < string | null > ( null ) ;
6251
6352 // Track when we're in "new workspace creation" mode (show FirstMessageInput)
6453 const [ pendingNewWorkspaceProject , setPendingNewWorkspaceProject ] = useState < string | null > ( null ) ;
6554
6655 // Auto-collapse sidebar on mobile by default
6756 const isMobile = typeof window !== "undefined" && window . innerWidth <= 768 ;
6857 const [ sidebarCollapsed , setSidebarCollapsed ] = usePersistedState ( "sidebarCollapsed" , isMobile ) ;
58+ const defaultProjectPath = getFirstProjectPath ( projects ) ;
59+ const creationChatInputRef = useRef < ChatInputAPI | null > ( null ) ;
60+ const creationProjectPath = ! selectedWorkspace
61+ ? ( pendingNewWorkspaceProject ?? ( projects . size === 1 ? defaultProjectPath : null ) )
62+ : null ;
63+ const handleCreationChatReady = useCallback ( ( api : ChatInputAPI ) => {
64+ creationChatInputRef . current = api ;
65+ api . focus ( ) ;
66+ } , [ ] ) ;
67+
68+ const startWorkspaceCreation = useStartWorkspaceCreation ( {
69+ projects,
70+ setPendingNewWorkspaceProject,
71+ setSelectedWorkspace,
72+ } ) ;
73+
74+ useEffect ( ( ) => {
75+ if ( creationProjectPath ) {
76+ creationChatInputRef . current ?. focus ( ) ;
77+ }
78+ } , [ creationProjectPath ] ) ;
6979
7080 const handleToggleSidebar = useCallback ( ( ) => {
7181 setSidebarCollapsed ( ( prev ) => ! prev ) ;
@@ -133,7 +143,6 @@ function AppInner() {
133143 void window . api . window . setTitle ( "mux" ) ;
134144 }
135145 } , [ selectedWorkspace , workspaceMetadata ] ) ;
136-
137146 // Validate selected workspace exists and has all required fields
138147 useEffect ( ( ) => {
139148 if ( selectedWorkspace ) {
@@ -177,12 +186,9 @@ function AppInner() {
177186
178187 const handleAddWorkspace = useCallback (
179188 ( projectPath : string ) => {
180- // Show FirstMessageInput for this project
181- setPendingNewWorkspaceProject ( projectPath ) ;
182- // Clear any selected workspace so FirstMessageInput is shown
183- setSelectedWorkspace ( null ) ;
189+ startWorkspaceCreation ( projectPath ) ;
184190 } ,
185- [ setSelectedWorkspace ]
191+ [ startWorkspaceCreation ]
186192 ) ;
187193
188194 // Memoize callbacks to prevent LeftSidebar/ProjectSidebar re-renders
@@ -204,48 +210,6 @@ function AppInner() {
204210 [ handleRemoveProject ]
205211 ) ;
206212
207- const handleCreateWorkspace = async (
208- branchName : string ,
209- trunkBranch : string ,
210- runtime ?: string
211- ) => {
212- if ( ! workspaceModalProject ) return ;
213-
214- console . assert (
215- typeof trunkBranch === "string" && trunkBranch . trim ( ) . length > 0 ,
216- "Expected trunk branch to be provided by the workspace modal"
217- ) ;
218-
219- // Parse runtime config if provided
220- let runtimeConfig : RuntimeConfig | undefined ;
221- if ( runtime ) {
222- try {
223- runtimeConfig = parseRuntimeString ( runtime , branchName ) ;
224- } catch ( err ) {
225- console . error ( "Failed to parse runtime config:" , err ) ;
226- throw err ; // Let modal handle the error
227- }
228- }
229-
230- const newWorkspace = await createWorkspace (
231- workspaceModalProject ,
232- branchName ,
233- trunkBranch ,
234- runtimeConfig
235- ) ;
236- if ( newWorkspace ) {
237- // Track workspace creation
238- telemetry . workspaceCreated ( newWorkspace . workspaceId ) ;
239- setSelectedWorkspace ( newWorkspace ) ;
240-
241- // Save runtime preference for this project if provided
242- if ( runtime ) {
243- const runtimeKey = getRuntimeKey ( workspaceModalProject ) ;
244- localStorage . setItem ( runtimeKey , runtime ) ;
245- }
246- }
247- } ;
248-
249213 const handleGetSecrets = useCallback ( async ( projectPath : string ) => {
250214 return await window . api . projects . secrets . get ( projectPath ) ;
251215 } , [ ] ) ;
@@ -398,9 +362,9 @@ function AppInner() {
398362
399363 const openNewWorkspaceFromPalette = useCallback (
400364 ( projectPath : string ) => {
401- void handleAddWorkspace ( projectPath ) ;
365+ startWorkspaceCreation ( projectPath ) ;
402366 } ,
403- [ handleAddWorkspace ]
367+ [ startWorkspaceCreation ]
404368 ) ;
405369
406370 const getBranchesForProject = useCallback (
@@ -469,7 +433,7 @@ function AppInner() {
469433 selectedWorkspace,
470434 getThinkingLevel : getThinkingLevelForWorkspace ,
471435 onSetThinkingLevel : setThinkingLevelFromPalette ,
472- onOpenNewWorkspaceModal : openNewWorkspaceFromPalette ,
436+ onStartWorkspaceCreation : openNewWorkspaceFromPalette ,
473437 getBranchesForProject,
474438 onSelectWorkspace : selectWorkspaceFromPalette ,
475439 onRemoveWorkspace : removeWorkspaceFromPalette ,
@@ -621,9 +585,9 @@ function AppInner() {
621585 }
622586 />
623587 </ ErrorBoundary >
624- ) : pendingNewWorkspaceProject || projects . size === 1 ? (
588+ ) : creationProjectPath ? (
625589 ( ( ) => {
626- const projectPath = pendingNewWorkspaceProject ?? Array . from ( projects . keys ( ) ) [ 0 ] ;
590+ const projectPath = creationProjectPath ;
627591 const projectName =
628592 projectPath . split ( "/" ) . pop ( ) ?? projectPath . split ( "\\" ) . pop ( ) ?? "Project" ;
629593 return (
@@ -633,6 +597,7 @@ function AppInner() {
633597 variant = "creation"
634598 projectPath = { projectPath }
635599 projectName = { projectName }
600+ onReady = { handleCreationChatReady }
636601 onWorkspaceCreated = { ( metadata ) => {
637602 // Add to workspace metadata map
638603 setWorkspaceMetadata ( ( prev ) => new Map ( prev ) . set ( metadata . id , metadata ) ) ;
@@ -686,26 +651,6 @@ function AppInner() {
686651 workspaceId : selectedWorkspace ?. workspaceId ,
687652 } ) }
688653 />
689- { workspaceModalOpen && workspaceModalProject && (
690- < NewWorkspaceModal
691- isOpen = { workspaceModalOpen }
692- projectName = { workspaceModalProjectName }
693- projectPath = { workspaceModalProject }
694- branches = { workspaceModalBranches }
695- defaultTrunkBranch = { workspaceModalDefaultTrunk }
696- loadErrorMessage = { workspaceModalLoadError }
697- onClose = { ( ) => {
698- workspaceModalProjectRef . current = null ;
699- setWorkspaceModalOpen ( false ) ;
700- setWorkspaceModalProject ( null ) ;
701- setWorkspaceModalProjectName ( "" ) ;
702- setWorkspaceModalBranches ( [ ] ) ;
703- setWorkspaceModalDefaultTrunk ( undefined ) ;
704- setWorkspaceModalLoadError ( null ) ;
705- } }
706- onAdd = { handleCreateWorkspace }
707- />
708- ) }
709654 < ProjectCreateModal
710655 isOpen = { projectCreateModalOpen }
711656 onClose = { ( ) => setProjectCreateModalOpen ( false ) }
0 commit comments