@brimveyn/aimux 1.21.0 → 1.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/README.md +27 -25
  2. package/package.json +2 -2
  3. package/src/app-runtime/auto-commit-driver.ts +22 -27
  4. package/src/app-runtime/backend-attach-runtime.ts +43 -36
  5. package/src/app-runtime/backend-runtime-events.ts +107 -88
  6. package/src/app-runtime/editor-actions.ts +201 -0
  7. package/src/app-runtime/git-actions.ts +197 -0
  8. package/src/app-runtime/measure-ref.ts +19 -0
  9. package/src/app-runtime/navigation-actions.ts +213 -0
  10. package/src/app-runtime/project-actions.ts +188 -0
  11. package/src/app-runtime/prompt-injection.ts +123 -0
  12. package/src/app-runtime/selection.ts +29 -0
  13. package/src/app-runtime/settings-actions.ts +156 -0
  14. package/src/app-runtime/setup-actions.ts +237 -0
  15. package/src/app-runtime/side-effect-context.ts +33 -0
  16. package/src/app-runtime/side-effects.ts +302 -1541
  17. package/src/app-runtime/snippet-actions.ts +3 -2
  18. package/src/app-runtime/tab-actions.ts +218 -0
  19. package/src/app-runtime/tab-runtime-timeouts.ts +1 -1
  20. package/src/app-runtime/use-auto-commit-driver.ts +14 -13
  21. package/src/app-runtime/use-backend-runtime.ts +12 -11
  22. package/src/app-runtime/use-directory-search.ts +5 -4
  23. package/src/app-runtime/use-mouse-handlers.ts +2 -1
  24. package/src/app-runtime/{use-workspace-autosave.ts → use-project-autosave.ts} +4 -4
  25. package/src/app-runtime/use-renderer-bindings.ts +2 -1
  26. package/src/app-runtime/use-setup-runner.ts +96 -0
  27. package/src/app-runtime/use-terminal-resize.ts +18 -14
  28. package/src/app-runtime/workspace-actions.ts +366 -0
  29. package/src/app-runtime/workspace-activity.ts +138 -0
  30. package/src/app-runtime/workspace-naming.ts +90 -0
  31. package/src/app.tsx +93 -48
  32. package/src/assets/sounds/bell.wav +0 -0
  33. package/src/assets/sounds/ding.wav +0 -0
  34. package/src/assets/sounds/plane.wav +0 -0
  35. package/src/cli/client/daemon-client.ts +2 -2
  36. package/src/cli/client/project-resolver.ts +112 -0
  37. package/src/cli/commands/project/close.ts +32 -0
  38. package/src/cli/commands/project/create.ts +93 -0
  39. package/src/cli/commands/project/list.ts +25 -0
  40. package/src/cli/commands/project/show.ts +32 -0
  41. package/src/cli/commands/{workspace → project}/switch.ts +19 -19
  42. package/src/cli/commands/tab/await.ts +2 -2
  43. package/src/cli/commands/tab/close.ts +3 -3
  44. package/src/cli/commands/tab/create.ts +74 -73
  45. package/src/cli/commands/tab/focus.ts +3 -3
  46. package/src/cli/commands/tab/list.ts +6 -6
  47. package/src/cli/commands/tab/run.ts +2 -2
  48. package/src/cli/commands/tab/send.ts +2 -2
  49. package/src/cli/commands/tab/snapshot.ts +2 -2
  50. package/src/cli/commands/tab/tail.ts +2 -2
  51. package/src/cli/commands/tab/wait.ts +2 -2
  52. package/src/cli/commands/worker/await.ts +3 -3
  53. package/src/cli/commands/worker/doctor.ts +30 -30
  54. package/src/cli/commands/worker/list.ts +15 -15
  55. package/src/cli/commands/worker/prompt.ts +3 -3
  56. package/src/cli/commands/worker/run.ts +23 -23
  57. package/src/cli/commands/worker/shared.ts +53 -59
  58. package/src/cli/commands/worker/stop.ts +29 -29
  59. package/src/cli/commands/worker/submit.ts +3 -3
  60. package/src/cli/commands/{worktree → workspace}/create-core.ts +26 -26
  61. package/src/cli/commands/workspace/create.ts +30 -68
  62. package/src/cli/commands/workspace/list.ts +52 -9
  63. package/src/cli/commands/workspace/remove.ts +81 -0
  64. package/src/cli/completion/plan.ts +2 -2
  65. package/src/cli/completion/sources.ts +18 -18
  66. package/src/cli/context.ts +13 -13
  67. package/src/cli/flags.ts +30 -10
  68. package/src/cli/index.ts +26 -16
  69. package/src/cli/output.ts +1 -1
  70. package/src/cli/registry.ts +12 -12
  71. package/src/config/loader.ts +16 -5
  72. package/src/config.ts +70 -112
  73. package/src/daemon/catalog-writer.ts +67 -67
  74. package/src/daemon/daemon.ts +205 -201
  75. package/src/daemon/session-manager.ts +39 -39
  76. package/src/daemon/session-registry.ts +14 -14
  77. package/src/git/divergence.ts +33 -2
  78. package/src/git/git-poller.ts +1 -1
  79. package/src/git/git-status.ts +2 -2
  80. package/src/git/{move-worktree.ts → move-workspace.ts} +5 -5
  81. package/src/git/pr-status.ts +1 -1
  82. package/src/git/repo-discovery.ts +1 -1
  83. package/src/git/use-repo-discovery.ts +1 -1
  84. package/src/git/workspace-branch-poller.ts +54 -0
  85. package/src/git/workspace-divergence-poller.ts +65 -0
  86. package/src/git/worktree.ts +29 -0
  87. package/src/index.tsx +4 -4
  88. package/src/input/keymap/help-entries.ts +7 -5
  89. package/src/input/modes/bridge.ts +13 -12
  90. package/src/input/modes/handlers/shared.ts +1 -1
  91. package/src/input/modes/transitions.ts +34 -21
  92. package/src/input/modes/types.ts +48 -31
  93. package/src/ipc/manager-protocol.ts +44 -44
  94. package/src/ipc/protocol.ts +192 -166
  95. package/src/platform/play-sound.ts +184 -0
  96. package/src/platform/project-search.ts +8 -8
  97. package/src/platform/worktree-paths.ts +8 -6
  98. package/src/pty/assistant-question-extractor.ts +1 -1
  99. package/src/pty/assistant-status-detection-loop.ts +79 -55
  100. package/src/pty/assistant-status-detector.ts +40 -15
  101. package/src/pty/command-registry.ts +81 -1
  102. package/src/restart-terminal-manager.ts +1 -1
  103. package/src/services/ai-usage/provider.ts +9 -2
  104. package/src/services/ai-usage/spawn.ts +19 -6
  105. package/src/session-backend/bootstrap.ts +4 -4
  106. package/src/session-backend/local-session-backend.ts +78 -75
  107. package/src/session-backend/remote-session-backend.ts +64 -52
  108. package/src/session-backend/types.ts +43 -32
  109. package/src/settings/live.ts +90 -0
  110. package/src/settings/search.ts +43 -0
  111. package/src/settings/sections/about.ts +49 -0
  112. package/src/settings/sections/appearance.ts +54 -0
  113. package/src/settings/sections/automation.ts +105 -0
  114. package/src/settings/sections/commands.ts +72 -0
  115. package/src/settings/sections/editor.ts +56 -0
  116. package/src/settings/sections/experimental.ts +57 -0
  117. package/src/settings/sections/git.ts +112 -0
  118. package/src/settings/sections/index.ts +95 -0
  119. package/src/settings/sections/integrations.ts +23 -0
  120. package/src/settings/sections/layout.ts +72 -0
  121. package/src/settings/sections/notifications.ts +99 -0
  122. package/src/settings/sections/setup.ts +54 -0
  123. package/src/settings/sections/status-bar.ts +63 -0
  124. package/src/settings/settings-store.ts +207 -0
  125. package/src/settings/types.ts +108 -0
  126. package/src/snippets/run-shell-var.ts +48 -22
  127. package/src/state/actions.ts +342 -0
  128. package/src/state/app-store.ts +2 -1
  129. package/src/state/bars.ts +1 -1
  130. package/src/state/dispatch-ref.ts +1 -1
  131. package/src/state/layout-resize.ts +2 -2
  132. package/src/state/project-catalog.ts +275 -0
  133. package/src/state/project-data.ts +143 -0
  134. package/src/state/{session-persistence.ts → project-persistence.ts} +74 -68
  135. package/src/state/project-save.ts +46 -0
  136. package/src/state/project-workspaces.ts +392 -0
  137. package/src/state/reducers/auto-commit-state.ts +11 -10
  138. package/src/state/reducers/git-commit-modal-state.ts +122 -0
  139. package/src/state/reducers/git-mode-state.ts +1 -1
  140. package/src/state/reducers/git-panel-state.ts +10 -6
  141. package/src/state/reducers/modal-state.ts +290 -681
  142. package/src/state/reducers/multi-repo-state.ts +3 -6
  143. package/src/state/reducers/project-state.ts +312 -0
  144. package/src/state/reducers/settings-state.ts +80 -0
  145. package/src/state/reducers/tab-state.ts +107 -60
  146. package/src/state/reducers/ui-state.ts +4 -3
  147. package/src/state/selectors.ts +49 -37
  148. package/src/state/store.ts +57 -24
  149. package/src/state/types.ts +244 -405
  150. package/src/state/validation.ts +14 -12
  151. package/src/terminal-manager/manager-client.ts +32 -32
  152. package/src/terminal-manager/terminal-manager.ts +24 -24
  153. package/src/ui/components/git/git-panel.tsx +2 -2
  154. package/src/ui/components/git/git-view.tsx +12 -12
  155. package/src/ui/components/git/image-diff/image-diff-view.tsx +1 -1
  156. package/src/ui/components/git/pane/git-pane-widget.tsx +7 -7
  157. package/src/ui/components/layout/sidebar/project-list.tsx +444 -0
  158. package/src/ui/components/layout/sidebar/tab-item.tsx +27 -12
  159. package/src/ui/components/layout/sidebar/use-sidebar-auto-scroll.ts +1 -1
  160. package/src/ui/components/layout/sidebar/workspace-row.tsx +253 -0
  161. package/src/ui/components/layout/status-bar.tsx +6 -2
  162. package/src/ui/components/layout/terminal-pane.tsx +34 -29
  163. package/src/ui/components/layout/top-tab-bar.tsx +46 -36
  164. package/src/ui/components/modals/git/git-commit-modal.tsx +8 -8
  165. package/src/ui/components/modals/{sessions/create-session-modal.tsx → projects/create-project-modal.tsx} +12 -12
  166. package/src/ui/components/modals/{sessions/session-name-modal.tsx → projects/project-name-modal.tsx} +2 -2
  167. package/src/ui/components/modals/{sessions/session-picker-modal.tsx → projects/project-picker-modal.tsx} +33 -35
  168. package/src/ui/components/modals/settings/settings-search-modal.tsx +70 -0
  169. package/src/ui/components/modals/shared/form.tsx +34 -22
  170. package/src/ui/components/modals/shared/picker.tsx +10 -10
  171. package/src/ui/components/modals/shared/{worktree-delete-confirm.tsx → workspace-delete-confirm.tsx} +9 -9
  172. package/src/ui/components/modals/tabs/new-tab-modal.tsx +30 -324
  173. package/src/ui/components/modals/workspace/create-workspace-modal.tsx +101 -0
  174. package/src/ui/components/modals/{worktree/worktree-move-confirm-modal.tsx → workspace/workspace-move-confirm-modal.tsx} +5 -5
  175. package/src/ui/components/modals/{worktree/worktree-move-modal.tsx → workspace/workspace-move-modal.tsx} +29 -27
  176. package/src/ui/components/primitives/input-field.tsx +7 -3
  177. package/src/ui/components/primitives/surface.tsx +3 -0
  178. package/src/ui/components/settings/row-value.tsx +74 -0
  179. package/src/ui/components/settings/settings-row.tsx +78 -0
  180. package/src/ui/components/settings/settings-view.tsx +169 -0
  181. package/src/ui/components/setup/setup-widget.tsx +152 -0
  182. package/src/ui/flash/build-labels.ts +27 -27
  183. package/src/ui/hooks/use-activity-sprite.ts +73 -0
  184. package/src/ui/hooks/use-scroll-active-into-view.ts +26 -0
  185. package/src/ui/{session-ordering.ts → project-ordering.ts} +4 -4
  186. package/src/ui/root.tsx +139 -121
  187. package/src/ui/status-bar-model.ts +48 -34
  188. package/src/ui/terminal-graphics/kitty.ts +28 -2
  189. package/src/ui/terminal-graphics/sprites/done@330/0.png +0 -0
  190. package/src/ui/terminal-graphics/sprites/done@330/1.png +0 -0
  191. package/src/ui/terminal-graphics/sprites/idle@1000/0.png +0 -0
  192. package/src/ui/terminal-graphics/sprites/idle@1000/1.png +0 -0
  193. package/src/ui/terminal-graphics/sprites/waiting@170/0.png +0 -0
  194. package/src/ui/terminal-graphics/sprites/waiting@170/1.png +0 -0
  195. package/src/ui/terminal-graphics/sprites/working@150/0.png +0 -0
  196. package/src/ui/terminal-graphics/sprites/working@150/1.png +0 -0
  197. package/src/ui/terminal-graphics/sprites/working@150/2.png +0 -0
  198. package/src/ui/terminal-graphics/sprites/working@150/3.png +0 -0
  199. package/src/ui/terminal-graphics/sprites.ts +246 -0
  200. package/src/ui/truncate.ts +7 -0
  201. package/src/ui/widgets/registry.tsx +6 -3
  202. package/src/ui/widgets/widget-context-menu.ts +26 -10
  203. package/src/update.ts +2 -2
  204. package/src/app-runtime/session-actions.ts +0 -187
  205. package/src/cli/client/workspace-resolver.ts +0 -110
  206. package/src/cli/commands/workspace/close.ts +0 -32
  207. package/src/cli/commands/workspace/show.ts +0 -32
  208. package/src/cli/commands/worktree/create.ts +0 -55
  209. package/src/cli/commands/worktree/list.ts +0 -68
  210. package/src/cli/commands/worktree/remove.ts +0 -81
  211. package/src/git/worktree-branch-poller.ts +0 -54
  212. package/src/git/worktree-divergence-poller.ts +0 -59
  213. package/src/state/reducers/session-state.ts +0 -262
  214. package/src/state/session-catalog.ts +0 -143
  215. package/src/state/session-worktrees.ts +0 -260
  216. package/src/state/workspace-save.ts +0 -43
  217. package/src/ui/components/layout/sidebar/use-top-tab-bar-auto-scroll.ts +0 -30
  218. package/src/ui/components/layout/sidebar/workspace-list.tsx +0 -418
  219. package/src/ui/components/layout/sidebar/worktree-row.tsx +0 -149
  220. /package/src/ui/{components/git/image-diff → terminal-graphics}/dimensions.ts +0 -0
@@ -6,18 +6,22 @@ type SupportedModalType = Exclude<ModalType, null>
6
6
  const DIRECT_FOCUS_MODE_IDS: Partial<Record<FocusMode, ModeId>> = {
7
7
  'git': 'git-mode',
8
8
  'navigation': 'navigation',
9
+ 'settings': 'settings',
9
10
  'terminal-input': 'terminal-input',
10
11
  }
11
12
 
12
13
  const COMMAND_EDIT_MODE_IDS: Partial<Record<SupportedModalType, ModeId>> = {
13
- 'create-session': 'modal.create-session',
14
+ 'create-project': 'modal.create-project',
15
+ 'create-workspace': 'modal.create-workspace',
14
16
  'git-commit': 'modal.git-commit',
15
17
  'help': 'modal.help.filtering',
16
18
  'new-tab': 'modal.new-tab.command-edit',
19
+ 'project-name': 'modal.project-name',
20
+ 'project-picker': 'modal.project-picker.filtering',
17
21
  'rename-tab': 'modal.rename-tab',
18
- 'rename-worktree': 'modal.rename-worktree',
19
- 'session-name': 'modal.session-name',
20
- 'session-picker': 'modal.session-picker.filtering',
22
+ 'rename-workspace': 'modal.rename-workspace',
23
+ 'setting-text': 'modal.setting-text',
24
+ 'settings-search': 'modal.settings-search.filtering',
21
25
  'snippet-editor': 'modal.snippet-editor',
22
26
  'snippet-picker': 'modal.snippet-picker.filtering',
23
27
  'split-picker': 'modal.split-picker',
@@ -27,9 +31,9 @@ const COMMAND_EDIT_MODE_IDS: Partial<Record<SupportedModalType, ModeId>> = {
27
31
  const MODAL_MODE_IDS: Partial<Record<SupportedModalType, ModeId>> = {
28
32
  'ai-usage': 'modal.ai-usage',
29
33
  'update-available': 'modal.update-available',
30
- 'worktree-delete-confirm': 'modal.worktree-delete-confirm',
31
- 'worktree-move': 'modal.worktree-move',
32
- 'worktree-move-confirm': 'modal.worktree-move-confirm',
34
+ 'workspace-delete-confirm': 'modal.workspace-delete-confirm',
35
+ 'workspace-move': 'modal.workspace-move',
36
+ 'workspace-move-confirm': 'modal.workspace-move-confirm',
33
37
  }
34
38
 
35
39
  export function deriveModeId(state: AppState): ModeId {
@@ -41,8 +45,8 @@ export function deriveModeId(state: AppState): ModeId {
41
45
 
42
46
  // Overlay on top of git mode without flipping focusMode (like help) — route
43
47
  // input to the picker while it's open even though focus stays 'git'.
44
- if (state.modal.type === 'worktree-move') {
45
- return 'modal.worktree-move'
48
+ if (state.modal.type === 'workspace-move') {
49
+ return 'modal.workspace-move'
46
50
  }
47
51
 
48
52
  // Flash-jump overlay: same pattern — renders on top of navigation, all
@@ -60,9 +64,6 @@ export function deriveModeId(state: AppState): ModeId {
60
64
  if (state.modal.type === 'new-tab' && state.modal.editingCommand !== null) {
61
65
  return 'modal.new-tab.editing-command'
62
66
  }
63
- if (state.modal.type === 'new-tab' && state.modal.worktreeDeletePrompt !== null) {
64
- return 'modal.new-tab.worktree-delete-confirm'
65
- }
66
67
  if (state.modal.type === 'git-commit' && state.modal.stage === 'confirm') {
67
68
  return 'modal.git-commit.confirm'
68
69
  }
@@ -1,4 +1,4 @@
1
- import type { AppAction } from '../../../state/types'
1
+ import type { AppAction } from '../../../state/actions'
2
2
  import type { KeyInput, KeyResult, ModeId, SideEffect } from '../types'
3
3
 
4
4
  type SelectionDelta = -1 | 1
@@ -1,51 +1,64 @@
1
1
  import type { ModeId } from './types'
2
2
 
3
3
  const TRANSITIONS: Record<ModeId, readonly ModeId[]> = {
4
- 'git-mode': ['navigation', 'modal.git-commit', 'modal.worktree-move'],
4
+ 'git-mode': ['navigation', 'modal.git-commit', 'modal.workspace-move'],
5
5
  'modal.ai-usage': ['navigation', 'terminal-input'],
6
- 'modal.create-session': ['navigation', 'modal.session-picker.filtering'],
6
+ 'modal.create-project': ['navigation', 'modal.project-picker.filtering'],
7
+ 'modal.create-workspace': ['navigation', 'terminal-input'],
7
8
  'modal.flash-jump': ['navigation'],
8
9
  'modal.git-commit': ['git-mode', 'modal.git-commit.confirm', 'modal.git-commit.generating'],
9
10
  'modal.git-commit.confirm': ['modal.git-commit', 'git-mode'],
10
11
  'modal.git-commit.generating': ['modal.git-commit', 'modal.git-commit.confirm', 'git-mode'],
11
12
  'modal.help.filtering': ['navigation'],
12
- 'modal.new-tab.command-edit': [
13
- 'navigation',
14
- 'modal.new-tab.editing-command',
15
- 'modal.new-tab.worktree-delete-confirm',
16
- ],
13
+ 'modal.new-tab.command-edit': ['navigation', 'modal.new-tab.editing-command'],
17
14
  'modal.new-tab.editing-command': ['navigation', 'modal.new-tab.command-edit'],
18
- 'modal.new-tab.worktree-delete-confirm': ['navigation', 'modal.new-tab.command-edit'],
15
+ 'modal.project-name': ['modal.project-picker.filtering', 'navigation'],
16
+ 'modal.project-picker.filtering': ['navigation', 'modal.project-name', 'modal.create-project'],
19
17
  'modal.rename-tab': ['navigation'],
20
- 'modal.rename-worktree': ['navigation'],
21
- 'modal.session-name': ['modal.session-picker.filtering', 'navigation'],
22
- 'modal.session-picker.filtering': ['navigation', 'modal.session-name', 'modal.create-session'],
18
+ 'modal.rename-workspace': ['navigation'],
19
+ 'modal.setting-text': ['settings'],
20
+ 'modal.settings-search.filtering': ['settings'],
23
21
  'modal.snippet-editor': ['navigation', 'modal.snippet-picker.filtering'],
24
- 'modal.snippet-picker.filtering': ['navigation', 'modal.snippet-editor'],
22
+ // Both pickers are reachable from the settings screen as well as from the
23
+ // panes, and `returnTo` sends each one back where it came from.
24
+ 'modal.snippet-picker.filtering': ['navigation', 'settings', 'modal.snippet-editor'],
25
25
  'modal.split-picker': ['navigation', 'terminal-input'],
26
- 'modal.theme-picker.filtering': ['navigation'],
26
+ 'modal.theme-picker.filtering': ['navigation', 'settings'],
27
27
  'modal.update-available': ['navigation'],
28
- 'modal.worktree-delete-confirm': ['navigation'],
29
- 'modal.worktree-move': ['git-mode', 'navigation'],
30
- 'modal.worktree-move-confirm': ['navigation'],
28
+ 'modal.workspace-delete-confirm': ['navigation'],
29
+ 'modal.workspace-move': ['git-mode', 'navigation'],
30
+ 'modal.workspace-move-confirm': ['navigation'],
31
31
  'navigation': [
32
32
  'terminal-input',
33
+ 'modal.create-workspace',
33
34
  'modal.new-tab.command-edit',
34
35
  'modal.new-tab.editing-command',
35
- 'modal.session-picker.filtering',
36
+ 'modal.project-picker.filtering',
36
37
  'modal.help.filtering',
37
38
  'modal.snippet-picker.filtering',
38
39
  'modal.theme-picker.filtering',
39
40
  'modal.rename-tab',
40
- 'modal.rename-worktree',
41
+ 'modal.rename-workspace',
41
42
  'modal.update-available',
42
43
  'modal.ai-usage',
43
- 'modal.worktree-delete-confirm',
44
- 'modal.worktree-move-confirm',
44
+ 'modal.workspace-delete-confirm',
45
+ 'modal.workspace-move-confirm',
45
46
  'modal.flash-jump',
46
47
  'git-mode',
48
+ 'settings',
49
+ ],
50
+ // The help overlay opens over settings without a transition (it leaves
51
+ // focusMode alone). The two pickers an action row hands over to are dispatched
52
+ // directly rather than through a KeyResult, but they are listed because that is
53
+ // what this table is for: saying where a mode can go.
54
+ 'settings': [
55
+ 'navigation',
56
+ 'modal.setting-text',
57
+ 'modal.settings-search.filtering',
58
+ 'modal.theme-picker.filtering',
59
+ 'modal.snippet-picker.filtering',
47
60
  ],
48
- 'terminal-input': ['navigation', 'modal.split-picker', 'modal.ai-usage'],
61
+ 'terminal-input': ['navigation', 'modal.split-picker', 'modal.ai-usage', 'settings'],
49
62
  }
50
63
 
51
64
  export function isValidTransition(from: ModeId, to: ModeId): boolean {
@@ -1,7 +1,8 @@
1
1
  import type { KeyEvent } from '@opentui/core'
2
2
 
3
+ import type { AppAction } from '../../state/actions'
3
4
  import type { SplitDirection } from '../../state/layout-tree'
4
- import type { AppAction, AppState, GitFileListMode, TabSession } from '../../state/types'
5
+ import type { AppState, GitFileListMode, TabSession } from '../../state/types'
5
6
 
6
7
  export type ModeId =
7
8
  | 'navigation'
@@ -9,13 +10,15 @@ export type ModeId =
9
10
  | 'git-mode'
10
11
  | 'modal.new-tab.command-edit'
11
12
  | 'modal.new-tab.editing-command'
12
- | 'modal.new-tab.worktree-delete-confirm'
13
- | 'modal.worktree-delete-confirm'
14
- | 'modal.session-picker.filtering'
15
- | 'modal.session-name'
16
- | 'modal.create-session'
13
+ | 'modal.workspace-delete-confirm'
14
+ | 'modal.project-picker.filtering'
15
+ | 'modal.project-name'
16
+ | 'modal.create-project'
17
+ | 'modal.create-workspace'
17
18
  | 'modal.rename-tab'
18
- | 'modal.rename-worktree'
19
+ | 'modal.rename-workspace'
20
+ | 'modal.setting-text'
21
+ | 'modal.settings-search.filtering'
19
22
  | 'modal.snippet-picker.filtering'
20
23
  | 'modal.snippet-editor'
21
24
  | 'modal.theme-picker.filtering'
@@ -25,20 +28,23 @@ export type ModeId =
25
28
  | 'modal.git-commit.confirm'
26
29
  | 'modal.git-commit.generating'
27
30
  | 'modal.update-available'
28
- | 'modal.worktree-move'
29
- | 'modal.worktree-move-confirm'
31
+ | 'modal.workspace-move'
32
+ | 'modal.workspace-move-confirm'
30
33
  | 'modal.ai-usage'
31
34
  | 'modal.flash-jump'
35
+ | 'settings'
32
36
 
33
37
  export type SideEffect =
34
38
  | { type: 'quit'; state: AppState }
39
+ | { type: 'open-new-tab' }
35
40
  | { type: 'launch-selected-assistant' }
36
- | { type: 'load-new-tab-base-branches' }
37
41
  | { type: 'edit-selected-assistant' }
38
- | { type: 'confirm-selected-session' }
39
- | { type: 'delete-selected-session' }
40
- | { type: 'open-rename-selected-session' }
41
- | { type: 'create-session'; name: string; projectPath?: string }
42
+ | { type: 'confirm-selected-project' }
43
+ | { type: 'delete-selected-project' }
44
+ | { type: 'open-rename-selected-project' }
45
+ | { type: 'create-project'; name: string; projectPath?: string }
46
+ | { type: 'create-workspace' }
47
+ | { type: 'load-create-workspace-base-branches' }
42
48
  | { type: 'close-tab'; tabId: string }
43
49
  | { type: 'restart-tab'; tab: TabSession }
44
50
  | { type: 'paste-selected-snippet' }
@@ -51,7 +57,7 @@ export type SideEffect =
51
57
  | { type: 'apply-theme'; action: 'restore' }
52
58
  | { type: 'apply-theme'; action: 'confirm' }
53
59
  | { type: 'apply-theme'; action: 'preview'; delta: 1 | -1 }
54
- | { type: 'rename-session'; sessionId: string; name: string }
60
+ | { type: 'rename-project'; projectId: string; name: string }
55
61
  | { type: 'rename-tab'; tabId: string; title: string }
56
62
  | {
57
63
  type: 'split-pane'
@@ -71,40 +77,51 @@ export type SideEffect =
71
77
  | { type: 'git-rm'; path: string }
72
78
  | { type: 'git-commit'; title: string; body: string }
73
79
  | { type: 'git-commit-auto'; title: string; body: string }
74
- | { type: 'generate-auto-commit-now'; sessionId: string }
80
+ | { type: 'generate-auto-commit-now'; projectId: string }
75
81
  | { type: 'git-push' }
76
82
  | { type: 'confirm-update-selection' }
77
- | { type: 'switch-session-by-index'; index: number; worktreeId?: string }
83
+ | { type: 'switch-project-by-index'; index: number; workspaceId?: string }
78
84
  | { type: 'cycle-sidebar-item'; direction: 1 | -1 }
79
85
  | { type: 'switch-tab-by-index'; index: number }
80
- | { type: 'delete-session'; sessionId: string }
86
+ | { type: 'delete-project'; projectId: string }
81
87
  | {
82
- type: 'delete-worktree'
83
- sessionId: string
84
- worktreeId: string
88
+ type: 'delete-workspace'
89
+ projectId: string
90
+ workspaceId: string
85
91
  // Force the git worktree removal (discards uncommitted changes in the
86
- // worktree). Also implies closing the worktree's tabs.
92
+ // workspace). Also implies closing the workspace's tabs.
87
93
  force?: boolean
88
- // Close the worktree's tabs without forcing the git removal. Lets the
89
- // sidebar "Remove worktree" clean up tabs (avoiding orphans) while still
90
- // refusing to discard uncommitted work in a temp worktree.
94
+ // Close the workspace's tabs without forcing the git removal. Lets the
95
+ // sidebar "Remove workspace" clean up tabs (avoiding orphans) while still
96
+ // refusing to discard uncommitted work in a temp workspace.
91
97
  closeTabs?: boolean
92
98
  }
93
99
  | {
94
- type: 'move-worktree'
95
- sessionId: string
96
- sourceWorktreeId: string
97
- targetWorktreeId: string
100
+ type: 'move-workspace'
101
+ projectId: string
102
+ sourceWorkspaceId: string
103
+ targetWorkspaceId: string
98
104
  deleteSource?: boolean
99
- // Retry flags set by the worktree-move-confirm dialog.
105
+ // Retry flags set by the workspace-move-confirm dialog.
100
106
  stashTarget?: boolean
101
107
  keepConflicts?: boolean
102
108
  }
103
- | { type: 'load-worktree-move-stats' }
109
+ | { type: 'load-workspace-move-stats' }
104
110
  | { type: 'toggle-transparent' }
105
111
  | { type: 'toggle-mode' }
106
112
  | { type: 'open-file-in-editor'; path: string }
107
113
  | { type: 'open-selected-snippet-source-in-editor' }
114
+ | { type: 'run-setup' }
115
+ | { type: 'stop-setup' }
116
+ | { type: 'configure-setup-script'; projectId?: string }
117
+ | { type: 'ask-agent-for-setup-script' }
118
+ | { type: 'promote-setup-tab' }
119
+ /** Toggle a checkbox, cycle an enum, run a row's action — whatever the row is. */
120
+ | { type: 'activate-settings-row' }
121
+ | { type: 'adjust-settings-row'; delta: 1 | -1 }
122
+ | { type: 'reset-settings-row' }
123
+ | { type: 'confirm-settings-search' }
124
+ | { type: 'commit-setting-text'; settingId: string; value: string }
108
125
 
109
126
  export interface KeyResult {
110
127
  actions: AppAction[]
@@ -1,11 +1,11 @@
1
1
  import type {
2
+ ProjectSnapshotV1,
2
3
  TabSession,
3
4
  TerminalModeState,
4
5
  TerminalSnapshot,
5
- WorkspaceSnapshotV1,
6
6
  } from '../state/types'
7
7
 
8
- import { isWorkspaceSnapshotV1 } from '../state/validation'
8
+ import { isProjectSnapshotV1 } from '../state/validation'
9
9
  import {
10
10
  getProcessVersion,
11
11
  IpcProtocolError,
@@ -36,13 +36,13 @@ import {
36
36
  // v9: additive — `tabMetadata` updates titles and auto-rename state without
37
37
  // restarting PTYs. Capability-gated; MIN remains at 8.
38
38
  //
39
- // v10: additive — `workerName` persists a workspace-scoped orchestration
39
+ // v10: additive — `workerName` persists a project-scoped orchestration
40
40
  // handle on tabs created through the headless worker facade.
41
41
  //
42
42
  // v11: breaking release boundary — force a fresh terminal-manager so named
43
43
  // worker metadata is guaranteed to survive daemon reattach and process swaps.
44
- export const MANAGER_PROTOCOL_MIN_VERSION = 11
45
- export const MANAGER_PROTOCOL_VERSION = 11
44
+ export const MANAGER_PROTOCOL_MIN_VERSION = 12
45
+ export const MANAGER_PROTOCOL_VERSION = 12
46
46
 
47
47
  /**
48
48
  * Capability strings advertised by *this* process in its `helloResult`. New
@@ -52,7 +52,7 @@ export const MANAGER_PROTOCOL_VERSION = 11
52
52
  */
53
53
  export const MANAGER_PROTOCOL_CAPABILITIES: readonly string[] = [
54
54
  'setBroadcastEnabled',
55
- 'createTabWorktreeId',
55
+ 'createTabWorkspaceId',
56
56
  'tabMetadata',
57
57
  'workerMetadata',
58
58
  ]
@@ -96,10 +96,10 @@ export interface ManagerHelloResult {
96
96
 
97
97
  export interface ManagerAttachRequest {
98
98
  protocolVersion: number
99
- sessionId: string
99
+ projectId: string
100
100
  cols: number
101
101
  rows: number
102
- workspaceSnapshot?: WorkspaceSnapshotV1
102
+ projectSnapshot?: ProjectSnapshotV1
103
103
  }
104
104
 
105
105
  export interface ManagerAttachResult {
@@ -115,7 +115,7 @@ export type ManagerRequest =
115
115
  id: string
116
116
  type: 'createTab'
117
117
  payload: {
118
- sessionId: string
118
+ projectId: string
119
119
  tabId: string
120
120
  assistant: TabSession['assistant']
121
121
  title: string
@@ -127,22 +127,22 @@ export type ManagerRequest =
127
127
  /** Extra env vars merged into the spawned PTY's environment. */
128
128
  env?: Record<string, string>
129
129
  /**
130
- * Worktree this tab belongs to (UI grouping). Capability-gated on
131
- * `createTabWorktreeId`. Pre-cap TMs silently drop the field, which
130
+ * Workspace this tab belongs to (UI grouping). Capability-gated on
131
+ * `createTabWorkspaceId`. Pre-cap TMs silently drop the field, which
132
132
  * matches the previous behaviour where every new tab had
133
- * `worktreeId = undefined`.
133
+ * `workspaceId = undefined`.
134
134
  */
135
- worktreeId?: string
135
+ workspaceId?: string
136
136
  workerName?: string
137
137
  autoRenameStatus?: 'eligible' | 'attempted'
138
138
  }
139
139
  }
140
- | { id: string; type: 'write'; payload: { sessionId: string; tabId: string; data: string } }
140
+ | { id: string; type: 'write'; payload: { projectId: string; tabId: string; data: string } }
141
141
  | {
142
142
  id: string
143
143
  type: 'updateTabMetadata'
144
144
  payload: {
145
- sessionId: string
145
+ projectId: string
146
146
  tabId: string
147
147
  title?: string
148
148
  autoRenameStatus?: 'eligible' | 'attempted'
@@ -152,7 +152,7 @@ export type ManagerRequest =
152
152
  id: string
153
153
  type: 'resizeClient'
154
154
  payload: {
155
- sessionId: string
155
+ projectId: string
156
156
  cols: number
157
157
  rows: number
158
158
  }
@@ -161,7 +161,7 @@ export type ManagerRequest =
161
161
  id: string
162
162
  type: 'resizeTab'
163
163
  payload: {
164
- sessionId: string
164
+ projectId: string
165
165
  tabId: string
166
166
  cols: number
167
167
  rows: number
@@ -170,16 +170,16 @@ export type ManagerRequest =
170
170
  | {
171
171
  id: string
172
172
  type: 'scrollToBottom'
173
- payload: { sessionId: string; tabId: string }
173
+ payload: { projectId: string; tabId: string }
174
174
  }
175
175
  | {
176
176
  id: string
177
177
  type: 'scroll'
178
- payload: { sessionId: string; tabId: string; deltaLines: number }
178
+ payload: { projectId: string; tabId: string; deltaLines: number }
179
179
  }
180
- | { id: string; type: 'setActiveTab'; payload: { sessionId: string; tabId: string | null } }
181
- | { id: string; type: 'closeTab'; payload: { sessionId: string; tabId: string } }
182
- | { id: string; type: 'disposeSession'; payload: { sessionId: string } }
180
+ | { id: string; type: 'setActiveTab'; payload: { projectId: string; tabId: string | null } }
181
+ | { id: string; type: 'closeTab'; payload: { projectId: string; tabId: string } }
182
+ | { id: string; type: 'disposeSession'; payload: { projectId: string } }
183
183
  | { id: string; type: 'ping'; payload: Record<string, never> }
184
184
  | { id: string; type: 'setBroadcastEnabled'; payload: { enabled: boolean } }
185
185
 
@@ -193,14 +193,14 @@ export type ManagerEvent =
193
193
  | {
194
194
  type: 'tabRender'
195
195
  payload: {
196
- sessionId: string
196
+ projectId: string
197
197
  tabId: string
198
198
  viewport: TerminalSnapshot
199
199
  terminalModes: TerminalModeState
200
200
  }
201
201
  }
202
- | { type: 'tabExit'; payload: { sessionId: string; tabId: string; exitCode: number } }
203
- | { type: 'tabError'; payload: { sessionId: string; tabId: string; message: string } }
202
+ | { type: 'tabExit'; payload: { projectId: string; tabId: string; exitCode: number } }
203
+ | { type: 'tabError'; payload: { projectId: string; tabId: string; message: string } }
204
204
 
205
205
  export type ManagerMessage = ManagerRequest | ManagerResponse | ManagerEvent
206
206
 
@@ -354,17 +354,17 @@ export function parseManagerRequest(value: unknown): ManagerRequest {
354
354
  isFiniteNumber(value.payload.protocolVersion),
355
355
  'attachSession.protocolVersion must be a number'
356
356
  )
357
- assert(isString(value.payload.sessionId), 'attachSession.sessionId must be a string')
357
+ assert(isString(value.payload.projectId), 'attachSession.projectId must be a string')
358
358
  assert(isFiniteNumber(value.payload.cols), 'attachSession.cols must be a number')
359
359
  assert(isFiniteNumber(value.payload.rows), 'attachSession.rows must be a number')
360
360
  assert(
361
- value.payload.workspaceSnapshot === undefined ||
362
- isWorkspaceSnapshotV1(value.payload.workspaceSnapshot),
363
- 'attachSession.workspaceSnapshot must be a valid workspace snapshot'
361
+ value.payload.projectSnapshot === undefined ||
362
+ isProjectSnapshotV1(value.payload.projectSnapshot),
363
+ 'attachSession.projectSnapshot must be a valid project snapshot'
364
364
  )
365
365
  return value as ManagerRequest
366
366
  case 'createTab':
367
- assert(isString(value.payload.sessionId), 'createTab.sessionId must be a string')
367
+ assert(isString(value.payload.projectId), 'createTab.projectId must be a string')
368
368
  assert(isString(value.payload.tabId), 'createTab.tabId must be a string')
369
369
  assert(
370
370
  isString(value.payload.assistant) && value.payload.assistant.length > 0,
@@ -387,8 +387,8 @@ export function parseManagerRequest(value: unknown): ManagerRequest {
387
387
  'createTab.env must be a string-keyed string record'
388
388
  )
389
389
  assert(
390
- value.payload.worktreeId === undefined || isString(value.payload.worktreeId),
391
- 'createTab.worktreeId must be a string when present'
390
+ value.payload.workspaceId === undefined || isString(value.payload.workspaceId),
391
+ 'createTab.workspaceId must be a string when present'
392
392
  )
393
393
  assert(
394
394
  value.payload.workerName === undefined || isString(value.payload.workerName),
@@ -402,12 +402,12 @@ export function parseManagerRequest(value: unknown): ManagerRequest {
402
402
  )
403
403
  return value as ManagerRequest
404
404
  case 'write':
405
- assert(isString(value.payload.sessionId), 'write.sessionId must be a string')
405
+ assert(isString(value.payload.projectId), 'write.projectId must be a string')
406
406
  assert(isString(value.payload.tabId), 'write.tabId must be a string')
407
407
  assert(isString(value.payload.data), 'write.data must be a string')
408
408
  return value as ManagerRequest
409
409
  case 'updateTabMetadata':
410
- assert(isString(value.payload.sessionId), 'updateTabMetadata.sessionId must be a string')
410
+ assert(isString(value.payload.projectId), 'updateTabMetadata.projectId must be a string')
411
411
  assert(isString(value.payload.tabId), 'updateTabMetadata.tabId must be a string')
412
412
  assert(
413
413
  value.payload.title === undefined || isString(value.payload.title),
@@ -421,35 +421,35 @@ export function parseManagerRequest(value: unknown): ManagerRequest {
421
421
  )
422
422
  return value as ManagerRequest
423
423
  case 'resizeClient':
424
- assert(isString(value.payload.sessionId), 'resizeClient.sessionId must be a string')
424
+ assert(isString(value.payload.projectId), 'resizeClient.projectId must be a string')
425
425
  assert(isFiniteNumber(value.payload.cols), 'resizeClient.cols must be a number')
426
426
  assert(isFiniteNumber(value.payload.rows), 'resizeClient.rows must be a number')
427
427
  return value as ManagerRequest
428
428
  case 'resizeTab':
429
- assert(isString(value.payload.sessionId), 'resizeTab.sessionId must be a string')
429
+ assert(isString(value.payload.projectId), 'resizeTab.projectId must be a string')
430
430
  assert(isString(value.payload.tabId), 'resizeTab.tabId must be a string')
431
431
  assert(isFiniteNumber(value.payload.cols), 'resizeTab.cols must be a number')
432
432
  assert(isFiniteNumber(value.payload.rows), 'resizeTab.rows must be a number')
433
433
  return value as ManagerRequest
434
434
  case 'scroll':
435
- assert(isString(value.payload.sessionId), 'scroll.sessionId must be a string')
435
+ assert(isString(value.payload.projectId), 'scroll.projectId must be a string')
436
436
  assert(isString(value.payload.tabId), 'scroll.tabId must be a string')
437
437
  assert(isFiniteNumber(value.payload.deltaLines), 'scroll.deltaLines must be a number')
438
438
  return value as ManagerRequest
439
439
  case 'scrollToBottom':
440
- assert(isString(value.payload.sessionId), 'scrollToBottom.sessionId must be a string')
440
+ assert(isString(value.payload.projectId), 'scrollToBottom.projectId must be a string')
441
441
  assert(isString(value.payload.tabId), 'scrollToBottom.tabId must be a string')
442
442
  return value as ManagerRequest
443
443
  case 'setActiveTab':
444
- assert(isString(value.payload.sessionId), 'setActiveTab.sessionId must be a string')
444
+ assert(isString(value.payload.projectId), 'setActiveTab.projectId must be a string')
445
445
  assert(isNullableString(value.payload.tabId), 'setActiveTab.tabId must be a string or null')
446
446
  return value as ManagerRequest
447
447
  case 'closeTab':
448
- assert(isString(value.payload.sessionId), 'closeTab.sessionId must be a string')
448
+ assert(isString(value.payload.projectId), 'closeTab.projectId must be a string')
449
449
  assert(isString(value.payload.tabId), 'closeTab.tabId must be a string')
450
450
  return value as ManagerRequest
451
451
  case 'disposeSession':
452
- assert(isString(value.payload.sessionId), 'disposeSession.sessionId must be a string')
452
+ assert(isString(value.payload.projectId), 'disposeSession.projectId must be a string')
453
453
  return value as ManagerRequest
454
454
  case 'ping':
455
455
  return value as ManagerRequest
@@ -488,18 +488,18 @@ export function parseManagerMessage(value: unknown): ManagerResponse | ManagerEv
488
488
  assert(isString(value.payload.message), 'error.message must be a string')
489
489
  return value as ManagerResponse
490
490
  case 'tabRender':
491
- assert(isString(value.payload.sessionId), 'tabRender.sessionId must be a string')
491
+ assert(isString(value.payload.projectId), 'tabRender.projectId must be a string')
492
492
  assert(isString(value.payload.tabId), 'tabRender.tabId must be a string')
493
493
  assert(isTerminalSnapshot(value.payload.viewport), 'tabRender.viewport is invalid')
494
494
  assert(isTerminalModeState(value.payload.terminalModes), 'tabRender.terminalModes is invalid')
495
495
  return value as ManagerEvent
496
496
  case 'tabExit':
497
- assert(isString(value.payload.sessionId), 'tabExit.sessionId must be a string')
497
+ assert(isString(value.payload.projectId), 'tabExit.projectId must be a string')
498
498
  assert(isString(value.payload.tabId), 'tabExit.tabId must be a string')
499
499
  assert(isFiniteNumber(value.payload.exitCode), 'tabExit.exitCode must be a number')
500
500
  return value as ManagerEvent
501
501
  case 'tabError':
502
- assert(isString(value.payload.sessionId), 'tabError.sessionId must be a string')
502
+ assert(isString(value.payload.projectId), 'tabError.projectId must be a string')
503
503
  assert(isString(value.payload.tabId), 'tabError.tabId must be a string')
504
504
  assert(isString(value.payload.message), 'tabError.message must be a string')
505
505
  return value as ManagerEvent