| 1 | export type WorkspaceNavigationPorts = { |
| 2 | claimIntent: () => number; |
| 3 | beginSurface: (intent: number) => void; |
| 4 | isIntentCurrent: (intent: number) => boolean; |
| 5 | pickWorkspace: (intent: number) => Promise<string>; |
| 6 | switchWorkspace: (path: string, intent: number) => Promise<string>; |
| 7 | markProjectChanged: (updater: (value: number) => number) => void; |
| 8 | refreshTabsAfterMutation: (latest: () => boolean) => Promise<unknown>; |
| 9 | maskTarget: (intent: number) => void; |
| 10 | }; |
| 11 | |
| 12 | /** Source-bound workspace navigation executor with one terminal surface owner. */ |
| 13 | export async function navigateWorkspace( |
| 14 | path: string | undefined, |
| 15 | ports: WorkspaceNavigationPorts, |
| 16 | ): Promise<string> { |
| 17 | const intent = ports.claimIntent(); |
| 18 | ports.beginSurface(intent); |
| 19 | try { |
| 20 | const picked = path === undefined |
| 21 | ? await ports.pickWorkspace(intent) |
| 22 | : await ports.switchWorkspace(path, intent); |
| 23 | if (!ports.isIntentCurrent(intent)) return picked; |
| 24 | if (picked) { |
| 25 | ports.markProjectChanged((value) => value + 1); |
| 26 | await ports.refreshTabsAfterMutation(() => ports.isIntentCurrent(intent)); |
| 27 | } |
| 28 | return picked; |
| 29 | } finally { |
| 30 | // Masking is intent-matched by the surface owner, so an old finally cannot |
| 31 | // release or advance a replacement request. |
| 32 | ports.maskTarget(intent); |
| 33 | } |
| 34 | } |
| 35 |