@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
@@ -1,7 +1,6 @@
1
1
  import type { ModeId, SnippetVar } from '@brimveyn/aimux-config'
2
2
  import type { ThemedToken } from 'shiki'
3
3
 
4
- import type { WorktreeTemplate } from '../config'
5
4
  import type { LayoutNode, SplitDirection } from './layout-tree'
6
5
 
7
6
  export type BuiltinAssistantId =
@@ -18,7 +17,7 @@ export type AssistantId = BuiltinAssistantId | (string & {})
18
17
  export type TabStatus = 'starting' | 'running' | 'disconnected' | 'error'
19
18
 
20
19
  /**
21
- * Status values that may appear in legacy on-disk workspace snapshots but are
20
+ * Status values that may appear in legacy on-disk project snapshots but are
22
21
  * not produced by the running app anymore. Filtered at restore time.
23
22
  */
24
23
  export type LegacyPersistedTabStatus = TabStatus | 'exited'
@@ -34,26 +33,51 @@ export type TabActivity = 'working' | 'waiting-input' | 'idle'
34
33
  export type QuestionKind = 'question' | 'permission'
35
34
 
36
35
  /**
37
- * Per-session status flags. Both can be true at once (e.g. one tab working,
36
+ * Per-project status flags. Both can be true at once (e.g. one tab working,
38
37
  * another waiting for user input) so we keep them as independent booleans
39
38
  * rather than a single priority enum.
40
39
  */
41
- export interface SessionStatus {
40
+ export interface ProjectStatus {
42
41
  working: boolean
43
42
  waiting: boolean
44
43
  }
45
44
 
46
- export const IDLE_SESSION_STATUS: SessionStatus = { waiting: false, working: false }
45
+ export const IDLE_PROJECT_STATUS: ProjectStatus = { waiting: false, working: false }
47
46
 
48
- export type FocusMode = 'navigation' | 'terminal-input' | 'modal' | 'command-edit' | 'git'
47
+ /**
48
+ * A workspace's status, as the sidebar draws it. `working`/`waiting` mirror
49
+ * `ProjectStatus` one level down; `done` is a latch — an assistant here
50
+ * finished a turn and nobody has looked yet — cleared when the workspace is
51
+ * entered or when it goes back to work.
52
+ */
53
+ export interface WorkspaceActivity {
54
+ working: boolean
55
+ waiting: boolean
56
+ done: boolean
57
+ }
58
+
59
+ export const IDLE_WORKSPACE_ACTIVITY: WorkspaceActivity = {
60
+ done: false,
61
+ waiting: false,
62
+ working: false,
63
+ }
64
+
65
+ export type FocusMode =
66
+ | 'navigation'
67
+ | 'terminal-input'
68
+ | 'modal'
69
+ | 'command-edit'
70
+ | 'git'
71
+ | 'settings'
49
72
 
50
73
  export type ModalType =
51
74
  | 'new-tab'
52
- | 'session-picker'
53
- | 'session-name'
54
- | 'create-session'
75
+ | 'project-picker'
76
+ | 'project-name'
77
+ | 'create-project'
78
+ | 'create-workspace'
55
79
  | 'rename-tab'
56
- | 'rename-worktree'
80
+ | 'rename-workspace'
57
81
  | 'snippet-picker'
58
82
  | 'snippet-editor'
59
83
  | 'theme-picker'
@@ -62,10 +86,12 @@ export type ModalType =
62
86
  | 'git-commit'
63
87
  | 'update-available'
64
88
  | 'ai-usage'
65
- | 'worktree-move'
66
- | 'worktree-move-confirm'
67
- | 'worktree-delete-confirm'
89
+ | 'workspace-move'
90
+ | 'workspace-move-confirm'
91
+ | 'workspace-delete-confirm'
68
92
  | 'flash-jump'
93
+ | 'setting-text'
94
+ | 'settings-search'
69
95
  | null
70
96
 
71
97
  export interface TerminalSpan {
@@ -132,13 +158,13 @@ export interface PersistedTabSnapshot {
132
158
  terminalModes: TerminalModeState
133
159
  errorMessage?: string
134
160
  exitCode?: number
135
- worktreeId?: string
136
- /** Stable workspace-scoped name assigned by the headless worker facade. */
161
+ workspaceId?: string
162
+ /** Stable project-scoped name assigned by the headless worker facade. */
137
163
  workerName?: string
138
164
  autoRenameStatus?: 'eligible' | 'attempted'
139
165
  }
140
166
 
141
- export interface WorkspaceSnapshotV1 {
167
+ export interface ProjectSnapshotV1 {
142
168
  version: 1
143
169
  savedAt: string
144
170
  activeTabId: string | null
@@ -151,17 +177,17 @@ export interface WorkspaceSnapshotV1 {
151
177
  layoutTrees?: Record<string, LayoutNode>
152
178
  tabGroupMap?: Record<string, string>
153
179
  /**
154
- * Last viewed tab per worktree, keyed by worktree id. Optional and additive
180
+ * Last viewed tab per workspace, keyed by workspace id. Optional and additive
155
181
  * (no version bump): older builds ignore it, newer builds tolerate its
156
182
  * absence. Written now so the data accrues, but restoring it at startup is
157
- * gated off until a future change flips RESTORE_LAST_ACTIVE_TAB_BY_WORKTREE.
183
+ * gated off until a future change flips RESTORE_LAST_ACTIVE_TAB_BY_WORKSPACE.
158
184
  */
159
- lastActiveTabByWorktree?: Record<string, string>
185
+ lastActiveTabByWorkspace?: Record<string, string>
160
186
  }
161
187
 
162
- export type WorktreeSource = 'primary' | 'aimux-temp' | 'external'
188
+ export type WorkspaceSource = 'primary' | 'aimux-temp' | 'external'
163
189
 
164
- export interface WorktreeRecord {
190
+ export interface WorkspaceRecord {
165
191
  id: string
166
192
  name: string
167
193
  path: string
@@ -169,14 +195,18 @@ export interface WorktreeRecord {
169
195
  branch?: string
170
196
  baseRef?: string
171
197
  commitSha?: string
172
- source: WorktreeSource
198
+ source: WorkspaceSource
173
199
  createdByAimux: boolean
174
200
  color?: string
175
201
  createdAt: string
176
202
  updatedAt: string
203
+ /** Last setup-script run for this workspace. Display only — the auto-run gate
204
+ * is "this session has not seen this workspace id before". */
205
+ setupRanAt?: string
206
+ setupExitCode?: number
177
207
  }
178
208
 
179
- export interface SessionRecord {
209
+ export interface ProjectRecord {
180
210
  id: string
181
211
  name: string
182
212
  projectPath?: string
@@ -184,12 +214,12 @@ export interface SessionRecord {
184
214
  updatedAt: string
185
215
  lastOpenedAt: string
186
216
  order?: number
187
- workspaceSnapshot?: WorkspaceSnapshotV1
188
- worktrees?: WorktreeRecord[]
189
- activeWorktreeId?: string
217
+ projectSnapshot?: ProjectSnapshotV1
218
+ workspaces?: WorkspaceRecord[]
219
+ activeWorkspaceId?: string
190
220
  }
191
221
 
192
- export interface SessionBarState {
222
+ export interface ProjectBarState {
193
223
  visible: boolean
194
224
  }
195
225
 
@@ -205,10 +235,36 @@ export interface TabSession {
205
235
  command: string
206
236
  errorMessage?: string
207
237
  exitCode?: number
208
- worktreeId?: string
209
- /** Stable workspace-scoped name assigned by the headless worker facade. */
238
+ workspaceId?: string
239
+ /**
240
+ * This tab is the one that rang: it finished a turn while you were looking
241
+ * elsewhere. Set alongside the workspace's own tick and cleared the moment
242
+ * the tab is opened or goes back to work, so the notification points at
243
+ * something rather than just happening. Ephemeral — never persisted, never
244
+ * on the wire.
245
+ */
246
+ unseen?: boolean
247
+ /** Stable project-scoped name assigned by the headless worker facade. */
210
248
  workerName?: string
211
249
  autoRenameStatus?: 'eligible' | 'attempted'
250
+ /**
251
+ * A real PTY tab that no chrome enumerates: absent from the top tab bar, from
252
+ * tab navigation, from `activeTabId` picks, and from the persisted snapshot.
253
+ * Rendered by whatever created it — today only the setup widget.
254
+ * `filterTabsForActiveWorkspace` is the single guard the UI paths share.
255
+ */
256
+ hidden?: boolean
257
+ /**
258
+ * Who owns this tab. Separate from `hidden` on purpose: promoting a setup tab
259
+ * into the main pane clears `hidden` but must not turn it back into an
260
+ * ordinary tab, or the PTY exit would close it and take the failure output
261
+ * with it — which is the one thing the promotion exists to read.
262
+ *
263
+ * ponytail: not on the ipc wire nor in the snapshot, so a promoted setup tab
264
+ * comes back from a restart as a plain tab running `bash …/setup.sh`. Add it
265
+ * to `TabSessionSummary` if that ever matters.
266
+ */
267
+ role?: 'setup'
212
268
  }
213
269
 
214
270
  export type BarSide = 'left' | 'right'
@@ -351,59 +407,89 @@ export interface GitModeState {
351
407
  folds: Record<string, Record<string, FoldState>>
352
408
  /** Working-tree-vs-HEAD~N offset. 0 = working tree vs HEAD (default). */
353
409
  headOffset: number
354
- /** When true, diff the active worktree's working tree against its fork point. */
410
+ /** When true, diff the active workspace's working tree against its fork point. */
355
411
  reviewBase: boolean
356
412
  }
357
413
 
358
414
  interface ModalBase {
359
415
  selectedIndex: number
360
416
  editBuffer: string | null
361
- sessionTargetId: string | null
417
+ projectTargetId: string | null
362
418
  cursorPos?: number
419
+ /**
420
+ * Where the focus goes when this modal closes, when it is not back to the
421
+ * panes. Set by whoever opened it, because that is who knows what is behind it
422
+ * — the settings screen opens five different modals, and none of them should
423
+ * have to grow a case in the reducer to find their way home.
424
+ */
425
+ returnTo?: FocusMode
363
426
  }
364
427
 
365
428
  export interface ModalClosed extends ModalBase {
366
429
  type: null
367
430
  editBuffer: null
368
- sessionTargetId: null
431
+ projectTargetId: null
369
432
  }
370
433
 
434
+ /**
435
+ * Picking an assistant for a new tab, and nothing else. The tab lands in the
436
+ * project's active workspace; creating a workspace is `create-workspace`'s job.
437
+ */
371
438
  export interface ModalNewTab extends ModalBase {
372
439
  type: 'new-tab'
373
440
  editingCommand: AssistantId | null
374
- activeField: 'assistant' | 'branch-name' | 'target-worktree' | 'worktree-name' | 'base'
375
- branchError: string | null
376
- branchName: string
377
- createWorktree: boolean
378
- selectedAssistantId: AssistantId | null
379
- step: 'assistant' | 'worktree' | 'worktree-create' | 'template'
380
- targetWorktreeIndex: number
381
- worktreeDeletePrompt: { worktreeId: string; reason: string } | null
382
- worktreeName: string
383
- /** Filter text typed into the "Base" picker on the worktree-create step. */
384
- baseQuery: string
385
- /** Resolved base ref the new worktree is forked from (branch of a worktree or a local branch). */
386
- baseRef: string
387
- /** Local branches available as base refs, loaded when the create step opens. */
388
- baseBranches: string[]
441
+ /**
442
+ * Set when `create-workspace` chained into this picker. The prompt the user
443
+ * typed there is sent to the assistant and drives the workspace's real name,
444
+ * and the tab is pinned to the freshly created workspace rather than the
445
+ * project's active one. Living on the modal means `close-modal` clears it, so
446
+ * escaping the picker cannot leak a stale prompt into a later tab.
447
+ */
448
+ pendingWorkspace?: PendingWorkspaceLaunch
449
+ /**
450
+ * A prompt to hand the picked assistant, with none of `pendingWorkspace`'s
451
+ * other behaviour: no workspace pinning, no rename. Used by "Ask an agent" in
452
+ * the setup widget.
453
+ */
454
+ pendingPrompt?: string
455
+ }
456
+
457
+ export interface PendingWorkspaceLaunch {
458
+ projectId: string
459
+ workspaceId: string
460
+ prompt: string
389
461
  }
390
462
 
391
- export interface ModalSessionPicker extends ModalBase {
392
- type: 'session-picker'
463
+ export interface ModalProjectPicker extends ModalBase {
464
+ type: 'project-picker'
393
465
  }
394
466
 
395
- export interface ModalSessionName extends ModalBase {
396
- type: 'session-name'
397
- returnToSessionPicker: boolean
467
+ export interface ModalProjectName extends ModalBase {
468
+ type: 'project-name'
469
+ returnToProjectPicker: boolean
398
470
  }
399
471
 
400
472
  export interface ModalRenameTab extends ModalBase {
401
473
  type: 'rename-tab'
402
474
  }
475
+ /**
476
+ * One text field over a settings row. Carries the row it belongs to so confirming
477
+ * writes back to the right one, and closing returns to the settings screen rather
478
+ * than to the panes.
479
+ */
480
+ /** Fuzzy-ish search across every setting, from inside the settings screen. */
481
+ export interface ModalSettingsSearch extends ModalBase {
482
+ type: 'settings-search'
483
+ }
484
+ export interface ModalSettingText extends ModalBase {
485
+ type: 'setting-text'
486
+ settingId: string
487
+ settingLabel: string
488
+ }
403
489
 
404
- export interface ModalRenameWorktree extends ModalBase {
405
- type: 'rename-worktree'
406
- worktreeSessionId: string
490
+ export interface ModalRenameWorkspace extends ModalBase {
491
+ type: 'rename-workspace'
492
+ workspaceProjectId: string
407
493
  }
408
494
 
409
495
  export interface ModalSnippetPicker extends ModalBase {
@@ -438,13 +524,35 @@ export interface ModalGitCommit extends ModalBase {
438
524
  stage: 'edit' | 'generating' | 'confirm'
439
525
  }
440
526
 
441
- export interface ModalCreateSession extends ModalBase {
442
- type: 'create-session'
527
+ export interface ModalCreateProject extends ModalBase {
528
+ type: 'create-project'
443
529
  directoryResults: DirectoryResult[]
444
530
  pendingProjectPath: string | null
445
531
  activeField: 'directory' | 'name'
446
532
  nameBuffer: string
447
- returnToSessionPicker: boolean
533
+ returnToProjectPicker: boolean
534
+ }
535
+
536
+ /**
537
+ * Creating a workspace inside the current project — the second of the three
538
+ * creation actions (project / workspace / tab). Deliberately carries no
539
+ * assistant: once the workspace exists the effect chains into the new-tab modal.
540
+ */
541
+ export interface ModalCreateWorkspace extends ModalBase {
542
+ type: 'create-workspace'
543
+ activeField: 'prompt' | 'base'
544
+ /**
545
+ * "What do you want to work on?" — the only thing the user types. It is sent
546
+ * to the assistant, and it names both the workspace and its branch.
547
+ */
548
+ prompt: string
549
+ branchError: string | null
550
+ /** Filter text typed into the "Base" picker. */
551
+ baseQuery: string
552
+ /** Resolved base ref the new workspace is forked from (a workspace's branch or a local branch). */
553
+ baseRef: string
554
+ /** Local branches available as base refs, loaded when the modal opens. */
555
+ baseBranches: string[]
448
556
  }
449
557
 
450
558
  export interface ModalSnippetEditor extends ModalBase {
@@ -468,68 +576,68 @@ export interface ModalAIUsage extends ModalBase {
468
576
  type: 'ai-usage'
469
577
  }
470
578
 
471
- export interface ModalWorktreeMove extends ModalBase {
472
- type: 'worktree-move'
473
- /** The worktree being moved (may differ from the active one, e.g. a tab menu). */
474
- sourceWorktreeId: string
579
+ export interface ModalWorkspaceMove extends ModalBase {
580
+ type: 'workspace-move'
581
+ /** The workspace being moved (may differ from the active one, e.g. a tab menu). */
582
+ sourceWorkspaceId: string
475
583
  deleteSource: boolean
476
- /** Per-worktree dirty file counts, loaded async when the modal opens. */
584
+ /** Per-workspace dirty file counts, loaded async when the modal opens. */
477
585
  stats: { kind: 'loading' } | { kind: 'ready'; dirtyFiles: Record<string, number> }
478
586
  }
479
587
 
480
588
  /**
481
589
  * Confirmation for a recoverable move failure: the target's dirty files
482
590
  * overlap the incoming changes (stash-target) or the squash conflicts
483
- * (keep-conflicts). Both worktrees are already restored; confirming re-runs
484
- * move-worktree with the matching flag.
591
+ * (keep-conflicts). Both workspaces are already restored; confirming re-runs
592
+ * move-workspace with the matching flag.
485
593
  */
486
- export interface ModalWorktreeMoveConfirm extends ModalBase {
487
- type: 'worktree-move-confirm'
594
+ export interface ModalWorkspaceMoveConfirm extends ModalBase {
595
+ type: 'workspace-move-confirm'
488
596
  variant: 'stash-target' | 'keep-conflicts'
489
597
  files: string[]
490
- sessionId: string
491
- sourceWorktreeId: string
492
- targetWorktreeId: string
598
+ projectId: string
599
+ sourceWorkspaceId: string
600
+ targetWorkspaceId: string
493
601
  deleteSource: boolean
494
602
  sourceLabel: string
495
603
  targetLabel: string
496
604
  }
497
605
 
498
606
  /**
499
- * Standalone confirmation for a recoverable worktree delete failure triggered
500
- * outside the new-tab picker (e.g. the sidebar's "Remove worktree"). Carries the
607
+ * Standalone confirmation for a recoverable workspace delete failure triggered
608
+ * outside the new-tab picker (e.g. the sidebar's "Remove workspace"). Carries the
501
609
  * params needed to re-run the delete with force once confirmed.
502
610
  */
503
- export interface ModalWorktreeDeleteConfirm extends ModalBase {
504
- type: 'worktree-delete-confirm'
505
- sessionId: string
506
- worktreeId: string
507
- worktreeLabel: string
611
+ export interface ModalWorkspaceDeleteConfirm extends ModalBase {
612
+ type: 'workspace-delete-confirm'
613
+ projectId: string
614
+ workspaceId: string
615
+ workspaceLabel: string
508
616
  reason: string
509
617
  closeTabs: boolean
510
618
  /** Whether confirming force-deletes — true only after a recoverable failure. */
511
619
  force: boolean
512
620
  }
513
621
 
514
- export type DirectoryResultType = 'git-repo' | 'worktree' | 'workspace'
622
+ export type DirectoryResultType = 'git-repo' | 'workspace' | 'project'
515
623
 
516
624
  export interface DirectoryResult {
517
625
  path: string
518
626
  type: DirectoryResultType
519
627
  }
520
628
 
521
- export type FlashJumpTargetKind = 'workspace' | 'worktree' | 'tab'
629
+ export type FlashJumpTargetKind = 'project' | 'workspace' | 'tab'
522
630
 
523
631
  export interface FlashJumpTarget {
524
632
  kind: FlashJumpTargetKind
525
633
  /**
526
- * 1-based index of the workspace in the visible session ordering — fed to
527
- * the existing `switch-session-by-index` side effect when jumping.
634
+ * 1-based index of the project in the visible project ordering — fed to
635
+ * the existing `switch-project-by-index` side effect when jumping.
528
636
  */
529
- sessionIndex: number
530
- sessionId: string
531
- /** Set for kind 'worktree' (the non-primary target) and kind 'tab' (the tab's worktree). */
532
- worktreeId?: string
637
+ projectIndex: number
638
+ projectId: string
639
+ /** Set for kind 'workspace' (the non-primary target) and kind 'tab' (the tab's workspace). */
640
+ workspaceId?: string
533
641
  /** Set for kind 'tab'. */
534
642
  tabId?: string
535
643
  }
@@ -557,23 +665,26 @@ export interface ModalFlashJump extends ModalBase {
557
665
  export type ModalState =
558
666
  | ModalClosed
559
667
  | ModalNewTab
560
- | ModalSessionPicker
561
- | ModalSessionName
668
+ | ModalProjectPicker
669
+ | ModalProjectName
562
670
  | ModalRenameTab
563
- | ModalRenameWorktree
671
+ | ModalRenameWorkspace
564
672
  | ModalSnippetPicker
565
673
  | ModalThemePicker
566
674
  | ModalHelp
567
675
  | ModalSplitPicker
568
- | ModalCreateSession
676
+ | ModalCreateProject
677
+ | ModalCreateWorkspace
569
678
  | ModalSnippetEditor
570
679
  | ModalGitCommit
571
680
  | ModalUpdateAvailable
572
681
  | ModalAIUsage
573
- | ModalWorktreeMove
574
- | ModalWorktreeMoveConfirm
575
- | ModalWorktreeDeleteConfirm
682
+ | ModalWorkspaceMove
683
+ | ModalWorkspaceMoveConfirm
684
+ | ModalWorkspaceDeleteConfirm
576
685
  | ModalFlashJump
686
+ | ModalSettingText
687
+ | ModalSettingsSearch
577
688
 
578
689
  export interface LayoutState {
579
690
  terminalCols: number
@@ -591,9 +702,9 @@ export interface SnippetRecord {
591
702
  export interface DiscoveredRepo {
592
703
  /** Absolute path to the repo. */
593
704
  path: string
594
- /** Label shown in UI (relative to the workspace root or repo basename). */
705
+ /** Label shown in UI (relative to the project root or repo basename). */
595
706
  name: string
596
- /** True when the repo is the session's projectPath itself. */
707
+ /** True when the repo is the project's projectPath itself. */
597
708
  isRoot: boolean
598
709
  }
599
710
 
@@ -606,15 +717,28 @@ export interface MultiRepoState {
606
717
 
607
718
  export const EMPTY_MULTI_REPO_STATE: MultiRepoState = { prefixes: {}, repos: [] }
608
719
 
720
+ /**
721
+ * Where the cursor is in the settings screen. Only the cursor: the values being
722
+ * edited live in `src/settings/settings-store.ts`, or already have a home in
723
+ * this state (`gitPane`, `customCommands`, …). Duplicating them here would make
724
+ * two of them.
725
+ */
726
+ export interface SettingsUIState {
727
+ sectionId: string
728
+ /** Which of the two columns has the keyboard: the section list, or its rows. */
729
+ pane: 'nav' | 'rows'
730
+ rowIndex: number
731
+ }
732
+
609
733
  export interface AppState {
610
734
  tabs: TabSession[]
611
735
  activeTabId: string | null
612
736
  layoutTrees: Record<string, LayoutNode>
613
737
  tabGroupMap: Record<string, string>
614
- sessions: SessionRecord[]
615
- currentSessionId: string | null
616
- sessionStatuses: Record<string, SessionStatus>
617
- sessionBar: SessionBarState
738
+ projects: ProjectRecord[]
739
+ currentProjectId: string | null
740
+ projectStatuses: Record<string, ProjectStatus>
741
+ projectBar: ProjectBarState
618
742
  snippets: SnippetRecord[]
619
743
  focusMode: FocusMode
620
744
  bars: BarsState
@@ -626,203 +750,30 @@ export interface AppState {
626
750
  gitMode: GitModeState
627
751
  autoCommit: AutoCommitState
628
752
  multiRepo: MultiRepoState
753
+ settings: SettingsUIState
629
754
  /**
630
- * Commits each worktree's branch is ahead/behind the ref it forked from,
631
- * keyed by worktree id. Ephemeral (polled); not persisted to the catalog.
755
+ * Commits each workspace's branch is ahead/behind the ref it forked from,
756
+ * keyed by workspace id. Ephemeral (polled); not persisted to the catalog.
632
757
  */
633
- worktreeDivergence: Record<string, BranchDivergence>
758
+ workspaceDivergence: Record<string, BranchDivergence>
634
759
  /**
635
- * Last active tab a user viewed within each worktree, keyed by worktree id.
636
- * Lets switching back to a worktree restore its last-viewed tab instead of
760
+ * What each workspace's assistants are doing, keyed by workspace id. Covers
761
+ * every project the daemon knows, not just the current one see
762
+ * `src/app-runtime/workspace-activity.ts`, which owns the aggregation.
763
+ * Ephemeral; not persisted to the catalog.
764
+ */
765
+ workspaceActivity: Record<string, WorkspaceActivity>
766
+ /**
767
+ * Last active tab a user viewed within each workspace, keyed by workspace id.
768
+ * Lets switching back to a workspace restore its last-viewed tab instead of
637
769
  * snapping to the first one. Ephemeral (in-memory); not persisted to the catalog.
638
770
  */
639
- lastActiveTabByWorktree: Record<string, string>
771
+ lastActiveTabByWorkspace: Record<string, string>
640
772
  /** Chord prefix the sequence resolver is currently waiting on, or null when idle. */
641
773
  pendingChords: string[] | null
642
- /** User-defined templates applied at worktree creation. Loaded from aimux.json. */
643
- worktreeTemplates: WorktreeTemplate[]
644
774
  }
645
775
 
646
- // -- Modal actions --
647
- export type ModalAction =
648
- | { type: 'move-modal-cursor'; delta?: number; to?: 'home' | 'end' }
649
- | { type: 'open-new-tab-modal' }
650
- | { type: 'set-new-tab-branch-error'; message: string | null }
651
- | {
652
- type: 'set-new-tab-worktree-delete-prompt'
653
- prompt: { worktreeId: string; reason: string } | null
654
- }
655
- | { type: 'set-new-tab-base-branches'; branches: string[] }
656
- | { type: 'enter-new-tab-worktree-create' }
657
- | { type: 'enter-new-tab-template-pick' }
658
- | { type: 'enter-new-tab-template-shortcut' }
659
- | { type: 'select-new-tab-assistant'; assistantId?: AssistantId }
660
- | { type: 'toggle-new-tab-worktree'; assistantId?: AssistantId }
661
- | { type: 'open-edit-custom-command'; assistantId: AssistantId }
662
- | { type: 'open-help-modal'; scope?: ModeId }
663
- | { type: 'open-split-picker'; direction: SplitDirection }
664
- | { type: 'open-session-picker' }
665
- | {
666
- type: 'open-session-name-modal'
667
- sessionTargetId?: string
668
- initialName?: string
669
- returnToSessionPicker?: boolean
670
- }
671
- | { type: 'close-modal' }
672
- | { type: 'move-modal-selection'; delta: number }
673
- | { type: 'update-command-edit'; char: string }
674
- | { type: 'cancel-command-edit' }
675
- | { type: 'open-create-session-modal'; returnToSessionPicker: boolean }
676
- | { type: 'set-directory-results'; results: DirectoryResult[] }
677
- | { type: 'switch-create-session-field' }
678
- | { type: 'select-directory' }
679
- | { type: 'open-rename-tab-modal' }
680
- | {
681
- type: 'open-rename-worktree-modal'
682
- sessionId: string
683
- worktreeId: string
684
- initialName: string
685
- }
686
- | { type: 'open-snippet-picker' }
687
- | { type: 'open-snippet-editor'; snippetId?: string }
688
- | { type: 'set-help-entry-count'; count: number }
689
- | { type: 'set-theme-entry-count'; count: number }
690
- | { type: 'open-theme-picker' }
691
- | { type: 'open-update-available-modal'; currentVersion: string; latestVersion: string }
692
- | { type: 'set-modal-selection-index'; index: number }
693
- | { type: 'open-ai-usage-modal' }
694
- | { type: 'open-worktree-move-modal'; sourceWorktreeId: string }
695
- | { type: 'toggle-worktree-move-delete' }
696
- | { type: 'set-worktree-move-stats'; dirtyFiles: Record<string, number> }
697
- | {
698
- type: 'open-worktree-move-confirm'
699
- variant: 'stash-target' | 'keep-conflicts'
700
- files: string[]
701
- sessionId: string
702
- sourceWorktreeId: string
703
- targetWorktreeId: string
704
- deleteSource: boolean
705
- sourceLabel: string
706
- targetLabel: string
707
- }
708
- | {
709
- type: 'open-worktree-delete-confirm'
710
- sessionId: string
711
- worktreeId: string
712
- worktreeLabel: string
713
- reason: string
714
- closeTabs: boolean
715
- force: boolean
716
- }
717
- | { type: 'open-flash-jump-modal' }
718
- | { type: 'clear-flash-jump-pending' }
719
-
720
- // -- Session actions --
721
- export type SessionAction =
722
- | {
723
- type: 'load-session'
724
- sessionId: string
725
- workspaceSnapshot?: WorkspaceSnapshotV1
726
- forceDisconnected?: boolean
727
- }
728
- | { type: 'set-sessions'; sessions: SessionRecord[] }
729
- | { type: 'create-session-record'; session: SessionRecord }
730
- | { type: 'rename-session-record'; sessionId: string; name: string }
731
- | { type: 'delete-session-record'; sessionId: string; openSessionPicker?: boolean }
732
- | { type: 'reorder-sessions'; orderedIds: string[] }
733
- | { type: 'reorder-active-session'; delta: number }
734
- | { type: 'set-session-status'; sessionId: string; status: SessionStatus }
735
- | { type: 'add-worktree-record'; sessionId: string; worktree: WorktreeRecord; activate?: boolean }
736
- | { type: 'set-active-worktree'; sessionId: string; worktreeId: string }
737
- | {
738
- type: 'update-worktree-record'
739
- sessionId: string
740
- worktreeId: string
741
- patch: Partial<WorktreeRecord>
742
- }
743
-
744
- // -- Tab actions --
745
- export type TabAction =
746
- | { type: 'add-tab'; tab: TabSession }
747
- | {
748
- type: 'hydrate-workspace'
749
- tabs: TabSession[]
750
- activeTabId: string | null
751
- layoutTree?: LayoutNode | null
752
- layoutTrees?: Record<string, LayoutNode>
753
- tabGroupMap?: Record<string, string>
754
- }
755
- | { type: 'close-tab'; tabId: string }
756
- | { type: 'close-active-tab' }
757
- | { type: 'set-active-tab'; tabId: string }
758
- | { type: 'move-active-tab'; delta: number }
759
- | { type: 'reorder-active-tab'; delta: number }
760
- | { type: 'reorder-tabs'; orderedTabIds: string[] }
761
- | { type: 'reset-tab-session'; tabId: string }
762
- | {
763
- type: 'rename-tab'
764
- tabId: string
765
- title: string
766
- autoRenameStatus?: 'eligible' | 'attempted'
767
- }
768
- | {
769
- type: 'update-tab-metadata'
770
- tabId: string
771
- title?: string
772
- autoRenameStatus?: 'eligible' | 'attempted'
773
- }
774
- | { type: 'append-tab-buffer'; tabId: string; chunk: string }
775
- | {
776
- type: 'replace-tab-viewport'
777
- tabId: string
778
- viewport: TerminalSnapshot
779
- terminalModes: TerminalModeState
780
- source?: 'resize' | 'scroll' | 'data' | 'switch'
781
- }
782
- | { type: 'set-tab-activity'; tabId: string; activity?: TabActivity }
783
- | { type: 'set-tab-error'; tabId: string; message: string }
784
-
785
- // -- Layout actions --
786
- export type LayoutAction =
787
- | {
788
- type: 'split-pane'
789
- direction: SplitDirection
790
- newTab: TabSession
791
- }
792
- | { type: 'close-pane'; tabId: string }
793
- | {
794
- type: 'focus-pane-direction'
795
- direction: 'left' | 'right' | 'up' | 'down'
796
- }
797
- | {
798
- type: 'resize-pane'
799
- tabId: string
800
- delta: number
801
- axis?: SplitDirection
802
- }
803
- | {
804
- type: 'set-split-ratio'
805
- tabId: string
806
- ratio: number
807
- axis?: SplitDirection
808
- }
809
-
810
- // -- UI actions --
811
- export type UIAction =
812
- | { type: 'toggle-bar'; side: BarSide }
813
- | { type: 'resize-bar'; side: BarSide; delta: number }
814
- | { type: 'set-bar-width'; side: BarSide; width: number }
815
- | { type: 'toggle-widget'; widgetId: string }
816
- | { type: 'move-widget'; widgetId: string; side: BarSide; index: number }
817
- | { type: 'set-bar-boundary'; side: BarSide; index: number; ratio: number }
818
- | { type: 'resize-widget'; widgetId: string; delta: number }
819
- | { type: 'set-focus-mode'; focusMode: FocusMode }
820
- | { type: 'set-terminal-size'; cols: number; rows: number }
821
- | { type: 'resize-git-diff-pane'; delta: number }
822
- | { type: 'set-pending-chords'; chords: string[] | null }
823
- | { type: 'toggle-session-bar' }
824
-
825
- // -- Git panel actions --
776
+ // -- Git panel payloads --
826
777
  export interface GitRefreshPayload {
827
778
  branch: string | null
828
779
  ahead: number
@@ -830,19 +781,16 @@ export interface GitRefreshPayload {
830
781
  files: GitFileEntry[]
831
782
  }
832
783
 
833
- /** Commits a worktree branch is ahead/behind the ref it forked from. */
784
+ /** Commits a workspace branch is ahead/behind the ref it forked from. */
834
785
  export interface BranchDivergence {
835
786
  ahead: number
836
787
  behind: number
788
+ /** Lines changed since the fork point, working tree included. */
789
+ added?: number
790
+ removed?: number
837
791
  }
838
792
 
839
- export type GitPanelAction =
840
- | { type: 'git-refresh-success'; payload: GitRefreshPayload }
841
- | { type: 'git-refresh-error'; kind: GitPanelError }
842
- | { type: 'git-panel-reset' }
843
- | { type: 'set-worktree-divergence'; divergence: Record<string, BranchDivergence> }
844
-
845
- // -- Auto-commit state & actions --
793
+ // -- Auto-commit state --
846
794
  export type AutoCommitSuggestion =
847
795
  | { kind: 'idle' }
848
796
  | {
@@ -862,116 +810,7 @@ export type AutoCommitSuggestion =
862
810
  }
863
811
 
864
812
  export interface AutoCommitState {
865
- bySession: Record<string, AutoCommitSuggestion>
813
+ byProject: Record<string, AutoCommitSuggestion>
866
814
  }
867
815
 
868
- export const EMPTY_AUTO_COMMIT_STATE: AutoCommitState = { bySession: {} }
869
-
870
- export type AutoCommitAction =
871
- | {
872
- type: 'auto-commit-generation-started'
873
- sessionId: string
874
- tabId: string
875
- workingTreeHash: string
876
- abortController: AbortController
877
- startedAt: number
878
- }
879
- | {
880
- type: 'auto-commit-generation-ready'
881
- sessionId: string
882
- workingTreeHash: string
883
- title: string
884
- body: string
885
- generatedAt: number
886
- }
887
- | { type: 'auto-commit-clear'; sessionId: string }
888
-
889
- export type GitModeAction =
890
- | { type: 'enter-git-mode' }
891
- | { type: 'exit-git-mode' }
892
- | { type: 'git-mode-move-selection'; delta: -1 | 1 }
893
- | { type: 'git-mode-move-file-selection'; delta: -1 | 1 }
894
- | { type: 'git-mode-select-entry-by-key'; key: string }
895
- | { type: 'git-mode-toggle-folder'; key: string }
896
- | { type: 'git-mode-toggle-selected-folder' }
897
- | { type: 'git-mode-collapse-selection' }
898
- | { type: 'git-mode-expand-selection' }
899
- | { type: 'git-mode-toggle-file-list-mode' }
900
- | { type: 'git-mode-toggle-tree-compaction' }
901
- | { type: 'git-mode-set-diff'; key: string; diff: DiffData; hash: string }
902
- | {
903
- type: 'git-mode-set-parsed'
904
- key: string
905
- hash: string
906
- file: unknown
907
- }
908
- | {
909
- type: 'git-mode-set-highlights'
910
- key: string
911
- hash: string
912
- themeId: string
913
- add: unknown
914
- del: unknown
915
- }
916
- | {
917
- type: 'git-mode-merge-highlights'
918
- key: string
919
- hash: string
920
- themeId: string
921
- add: { start: number; tokens: unknown }[]
922
- del: { start: number; tokens: unknown }[]
923
- }
924
- | { type: 'git-mode-invalidate-diffs'; paths: string[] }
925
- | { type: 'git-mode-set-loading'; key: string; loading: boolean }
926
- | { type: 'git-mode-set-pending-delete'; path: string | null }
927
- | { type: 'git-mode-clear-diff-cache'; path: string }
928
- | { type: 'git-mode-set-message'; message: string | null }
929
- | { type: 'snippet-picker-set-message'; message: string | null }
930
- | { type: 'git-mode-toggle-diff-view' }
931
- | { type: 'git-mode-toggle-review-base' }
932
- | { type: 'git-mode-shift-head-offset'; delta: number }
933
- | { type: 'git-mode-set-head-offset'; offset: number }
934
- | {
935
- type: 'git-mode-fold-adjust'
936
- key: string
937
- foldId: string
938
- side: 'top' | 'bottom'
939
- delta: number
940
- }
941
- | { type: 'git-mode-fold-set'; key: string; foldId: string; top: number; bottom: number }
942
- | { type: 'git-mode-fold-toggle-all'; key: string }
943
- | {
944
- type: 'git-mode-optimistic-move'
945
- path: string
946
- fromSection: GitFileSection
947
- toSection: GitFileSection | null
948
- }
949
- | { type: 'open-git-commit-modal'; sessionId?: string }
950
- | { type: 'git-commit-enter-confirm' }
951
- | { type: 'git-commit-leave-confirm' }
952
- | { type: 'git-commit-enter-generating'; sessionId: string }
953
- | { type: 'git-commit-leave-generating' }
954
- | { type: 'git-commit-use-background-suggestion'; sessionId: string }
955
-
956
- // -- Data actions --
957
- export type DataAction =
958
- | { type: 'set-snippets'; snippets: SnippetRecord[] }
959
- | { type: 'delete-snippet'; snippetId: string }
960
- | { type: 'set-custom-commands'; customCommands: Record<AssistantId, string> }
961
-
962
- // -- Multi-repo actions --
963
- export type MultiRepoAction =
964
- | { type: 'multi-repo-set-repos'; repos: DiscoveredRepo[] }
965
- | { type: 'multi-repo-clear' }
966
-
967
- export type AppAction =
968
- | ModalAction
969
- | SessionAction
970
- | TabAction
971
- | LayoutAction
972
- | UIAction
973
- | DataAction
974
- | GitPanelAction
975
- | GitModeAction
976
- | AutoCommitAction
977
- | MultiRepoAction
816
+ export const EMPTY_AUTO_COMMIT_STATE: AutoCommitState = { byProject: {} }