@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,11 +1,11 @@
1
1
  import type {
2
- SessionRecord,
2
+ ProjectRecord,
3
+ ProjectSnapshotV1,
3
4
  SnippetRecord,
4
5
  TerminalLine,
5
6
  TerminalModeState,
6
7
  TerminalSnapshot,
7
- WorkspaceSnapshotV1,
8
- WorktreeRecord,
8
+ WorkspaceRecord,
9
9
  } from './types'
10
10
 
11
11
  function isObjectRecord(value: unknown): value is Record<string, unknown> {
@@ -107,7 +107,7 @@ function isStringRecord(value: unknown): boolean {
107
107
  return Object.values(value).every(isString)
108
108
  }
109
109
 
110
- export function isWorktreeRecord(value: unknown): value is WorktreeRecord {
110
+ export function isWorkspaceRecord(value: unknown): value is WorkspaceRecord {
111
111
  return (
112
112
  isObjectRecord(value) &&
113
113
  isString(value.id) &&
@@ -121,11 +121,13 @@ export function isWorktreeRecord(value: unknown): value is WorktreeRecord {
121
121
  isBoolean(value.createdByAimux) &&
122
122
  (value.color === undefined || isString(value.color)) &&
123
123
  isString(value.createdAt) &&
124
- isString(value.updatedAt)
124
+ isString(value.updatedAt) &&
125
+ (value.setupRanAt === undefined || isString(value.setupRanAt)) &&
126
+ (value.setupExitCode === undefined || isFiniteNumber(value.setupExitCode))
125
127
  )
126
128
  }
127
129
 
128
- export function isWorkspaceSnapshotV1(value: unknown): value is WorkspaceSnapshotV1 {
130
+ export function isProjectSnapshotV1(value: unknown): value is ProjectSnapshotV1 {
129
131
  return (
130
132
  isObjectRecord(value) &&
131
133
  value.version === 1 &&
@@ -152,7 +154,7 @@ export function isWorkspaceSnapshotV1(value: unknown): value is WorkspaceSnapsho
152
154
  (tab.viewport === undefined || isTerminalSnapshot(tab.viewport)) &&
153
155
  (tab.errorMessage === undefined || isString(tab.errorMessage)) &&
154
156
  (tab.exitCode === undefined || isFiniteNumber(tab.exitCode)) &&
155
- (tab.worktreeId === undefined || isString(tab.worktreeId)) &&
157
+ (tab.workspaceId === undefined || isString(tab.workspaceId)) &&
156
158
  (tab.workerName === undefined || isString(tab.workerName)) &&
157
159
  (tab.autoRenameStatus === undefined ||
158
160
  tab.autoRenameStatus === 'eligible' ||
@@ -164,7 +166,7 @@ export function isWorkspaceSnapshotV1(value: unknown): value is WorkspaceSnapsho
164
166
  )
165
167
  }
166
168
 
167
- export function isSessionRecord(value: unknown): value is SessionRecord {
169
+ export function isProjectRecord(value: unknown): value is ProjectRecord {
168
170
  return (
169
171
  isObjectRecord(value) &&
170
172
  isString(value.id) &&
@@ -175,10 +177,10 @@ export function isSessionRecord(value: unknown): value is SessionRecord {
175
177
  isString(value.lastOpenedAt) &&
176
178
  (value.order === undefined ||
177
179
  (typeof value.order === 'number' && Number.isFinite(value.order))) &&
178
- (value.workspaceSnapshot === undefined || isWorkspaceSnapshotV1(value.workspaceSnapshot)) &&
179
- (value.worktrees === undefined ||
180
- (Array.isArray(value.worktrees) && value.worktrees.every(isWorktreeRecord))) &&
181
- (value.activeWorktreeId === undefined || isString(value.activeWorktreeId))
180
+ (value.projectSnapshot === undefined || isProjectSnapshotV1(value.projectSnapshot)) &&
181
+ (value.workspaces === undefined ||
182
+ (Array.isArray(value.workspaces) && value.workspaces.every(isWorkspaceRecord))) &&
183
+ (value.activeWorkspaceId === undefined || isString(value.activeWorkspaceId))
182
184
  )
183
185
  }
184
186
 
@@ -1,7 +1,7 @@
1
1
  import { EventEmitter } from 'node:events'
2
2
  import { connect, type Socket } from 'node:net'
3
3
 
4
- import type { TerminalModeState, TerminalSnapshot, WorkspaceSnapshotV1 } from '../state/types'
4
+ import type { ProjectSnapshotV1, TerminalModeState, TerminalSnapshot } from '../state/types'
5
5
 
6
6
  import { getTerminalManagerSocketPath } from '../daemon/runtime-paths'
7
7
  import { logDebug } from '../debug/input-log'
@@ -23,13 +23,13 @@ import {
23
23
 
24
24
  interface ManagerClientEvents {
25
25
  render: [
26
- sessionId: string,
26
+ projectId: string,
27
27
  tabId: string,
28
28
  viewport: TerminalSnapshot,
29
29
  terminalModes: TerminalModeState,
30
30
  ]
31
- exit: [sessionId: string, tabId: string, exitCode: number]
32
- error: [sessionId: string, tabId: string, message: string]
31
+ exit: [projectId: string, tabId: string, exitCode: number]
32
+ error: [projectId: string, tabId: string, message: string]
33
33
  }
34
34
 
35
35
  const REQUEST_TIMEOUT_MS = 10_000
@@ -126,7 +126,7 @@ export class TerminalManagerClient extends EventEmitter<ManagerClientEvents> {
126
126
 
127
127
  private handleManagerEvent(message: ManagerEvent): void {
128
128
  logDebug('managerClient.event', {
129
- sessionId: message.payload.sessionId,
129
+ projectId: message.payload.projectId,
130
130
  tabId: message.payload.tabId,
131
131
  type: message.type,
132
132
  })
@@ -134,7 +134,7 @@ export class TerminalManagerClient extends EventEmitter<ManagerClientEvents> {
134
134
  case 'tabRender':
135
135
  this.emit(
136
136
  'render',
137
- message.payload.sessionId,
137
+ message.payload.projectId,
138
138
  message.payload.tabId,
139
139
  message.payload.viewport,
140
140
  message.payload.terminalModes
@@ -143,7 +143,7 @@ export class TerminalManagerClient extends EventEmitter<ManagerClientEvents> {
143
143
  case 'tabExit':
144
144
  this.emit(
145
145
  'exit',
146
- message.payload.sessionId,
146
+ message.payload.projectId,
147
147
  message.payload.tabId,
148
148
  message.payload.exitCode
149
149
  )
@@ -151,7 +151,7 @@ export class TerminalManagerClient extends EventEmitter<ManagerClientEvents> {
151
151
  case 'tabError':
152
152
  this.emit(
153
153
  'error',
154
- message.payload.sessionId,
154
+ message.payload.projectId,
155
155
  message.payload.tabId,
156
156
  message.payload.message
157
157
  )
@@ -253,16 +253,16 @@ export class TerminalManagerClient extends EventEmitter<ManagerClientEvents> {
253
253
  }
254
254
 
255
255
  async attachSession(options: {
256
- sessionId: string
256
+ projectId: string
257
257
  cols: number
258
258
  rows: number
259
- workspaceSnapshot?: WorkspaceSnapshotV1
259
+ projectSnapshot?: ProjectSnapshotV1
260
260
  }): Promise<ManagerAttachResult> {
261
261
  logDebug('managerClient.attach.start', {
262
262
  cols: options.cols,
263
+ projectId: options.projectId,
263
264
  rows: options.rows,
264
- sessionId: options.sessionId,
265
- snapshotTabs: options.workspaceSnapshot?.tabs.length ?? 0,
265
+ snapshotTabs: options.projectSnapshot?.tabs.length ?? 0,
266
266
  })
267
267
  await this.connect()
268
268
  const response = await this.send({
@@ -282,7 +282,7 @@ export class TerminalManagerClient extends EventEmitter<ManagerClientEvents> {
282
282
 
283
283
  logDebug('managerClient.attach.success', {
284
284
  activeTabId: response.payload.activeTabId,
285
- sessionId: options.sessionId,
285
+ projectId: options.projectId,
286
286
  tabs: response.payload.tabs.length,
287
287
  })
288
288
  return response.payload
@@ -293,7 +293,7 @@ export class TerminalManagerClient extends EventEmitter<ManagerClientEvents> {
293
293
  ): Promise<void> {
294
294
  logDebug('managerClient.createTab', {
295
295
  command: options.command,
296
- sessionId: options.sessionId,
296
+ projectId: options.projectId,
297
297
  tabId: options.tabId,
298
298
  title: options.title,
299
299
  })
@@ -309,79 +309,79 @@ export class TerminalManagerClient extends EventEmitter<ManagerClientEvents> {
309
309
  return this.sendExpectOk({ id: crypto.randomUUID(), payload, type: 'createTab' })
310
310
  }
311
311
 
312
- async write(sessionId: string, tabId: string, data: string): Promise<void> {
312
+ async write(projectId: string, tabId: string, data: string): Promise<void> {
313
313
  return this.sendExpectOk({
314
314
  id: crypto.randomUUID(),
315
- payload: { data, sessionId, tabId },
315
+ payload: { data, projectId, tabId },
316
316
  type: 'write',
317
317
  })
318
318
  }
319
319
 
320
320
  async updateTabMetadata(
321
- sessionId: string,
321
+ projectId: string,
322
322
  tabId: string,
323
323
  patch: { title?: string; autoRenameStatus?: 'eligible' | 'attempted' }
324
324
  ): Promise<void> {
325
325
  if (!this.serverCapabilities.has(MANAGER_CAPABILITY_TAB_METADATA)) return
326
326
  return this.sendExpectOk({
327
327
  id: crypto.randomUUID(),
328
- payload: { ...patch, sessionId, tabId },
328
+ payload: { ...patch, projectId, tabId },
329
329
  type: 'updateTabMetadata',
330
330
  })
331
331
  }
332
332
 
333
- async resize(sessionId: string, cols: number, rows: number): Promise<void> {
333
+ async resize(projectId: string, cols: number, rows: number): Promise<void> {
334
334
  return this.sendExpectOk({
335
335
  id: crypto.randomUUID(),
336
- payload: { cols, rows, sessionId },
336
+ payload: { cols, projectId, rows },
337
337
  type: 'resizeClient',
338
338
  })
339
339
  }
340
340
 
341
- async resizeTab(sessionId: string, tabId: string, cols: number, rows: number): Promise<void> {
341
+ async resizeTab(projectId: string, tabId: string, cols: number, rows: number): Promise<void> {
342
342
  return this.sendExpectOk({
343
343
  id: crypto.randomUUID(),
344
- payload: { cols, rows, sessionId, tabId },
344
+ payload: { cols, projectId, rows, tabId },
345
345
  type: 'resizeTab',
346
346
  })
347
347
  }
348
348
 
349
- async scroll(sessionId: string, tabId: string, deltaLines: number): Promise<void> {
349
+ async scroll(projectId: string, tabId: string, deltaLines: number): Promise<void> {
350
350
  return this.sendExpectOk({
351
351
  id: crypto.randomUUID(),
352
- payload: { deltaLines, sessionId, tabId },
352
+ payload: { deltaLines, projectId, tabId },
353
353
  type: 'scroll',
354
354
  })
355
355
  }
356
356
 
357
- async scrollToBottom(sessionId: string, tabId: string): Promise<void> {
357
+ async scrollToBottom(projectId: string, tabId: string): Promise<void> {
358
358
  return this.sendExpectOk({
359
359
  id: crypto.randomUUID(),
360
- payload: { sessionId, tabId },
360
+ payload: { projectId, tabId },
361
361
  type: 'scrollToBottom',
362
362
  })
363
363
  }
364
364
 
365
- async setActiveTab(sessionId: string, tabId: string | null): Promise<void> {
365
+ async setActiveTab(projectId: string, tabId: string | null): Promise<void> {
366
366
  return this.sendExpectOk({
367
367
  id: crypto.randomUUID(),
368
- payload: { sessionId, tabId },
368
+ payload: { projectId, tabId },
369
369
  type: 'setActiveTab',
370
370
  })
371
371
  }
372
372
 
373
- async closeTab(sessionId: string, tabId: string): Promise<void> {
373
+ async closeTab(projectId: string, tabId: string): Promise<void> {
374
374
  return this.sendExpectOk({
375
375
  id: crypto.randomUUID(),
376
- payload: { sessionId, tabId },
376
+ payload: { projectId, tabId },
377
377
  type: 'closeTab',
378
378
  })
379
379
  }
380
380
 
381
- async disposeSession(sessionId: string): Promise<void> {
381
+ async disposeSession(projectId: string): Promise<void> {
382
382
  return this.sendExpectOk({
383
383
  id: crypto.randomUUID(),
384
- payload: { sessionId },
384
+ payload: { projectId },
385
385
  type: 'disposeSession',
386
386
  })
387
387
  }
@@ -95,23 +95,23 @@ export async function runTerminalManager(): Promise<void> {
95
95
  // attached — re-evaluate idle state in that case too.
96
96
  sessionManager.on('exit', () => scheduleIdleExitIfApplicable())
97
97
 
98
- sessionManager.on('render', (sessionId, tabId, viewport, terminalModes) => {
98
+ sessionManager.on('render', (projectId, tabId, viewport, terminalModes) => {
99
99
  const event: ManagerEvent = {
100
- payload: { sessionId, tabId, terminalModes, viewport },
100
+ payload: { projectId, tabId, terminalModes, viewport },
101
101
  type: 'tabRender',
102
102
  }
103
103
  for (const socket of sockets) {
104
104
  send(socket, event)
105
105
  }
106
106
  })
107
- sessionManager.on('exit', (sessionId, tabId, exitCode) => {
108
- const event: ManagerEvent = { payload: { exitCode, sessionId, tabId }, type: 'tabExit' }
107
+ sessionManager.on('exit', (projectId, tabId, exitCode) => {
108
+ const event: ManagerEvent = { payload: { exitCode, projectId, tabId }, type: 'tabExit' }
109
109
  for (const socket of sockets) {
110
110
  send(socket, event)
111
111
  }
112
112
  })
113
- sessionManager.on('error', (sessionId, tabId, message) => {
114
- const event: ManagerEvent = { payload: { message, sessionId, tabId }, type: 'tabError' }
113
+ sessionManager.on('error', (projectId, tabId, message) => {
114
+ const event: ManagerEvent = { payload: { message, projectId, tabId }, type: 'tabError' }
115
115
  for (const socket of sockets) {
116
116
  send(socket, event)
117
117
  }
@@ -154,9 +154,9 @@ export async function runTerminalManager(): Promise<void> {
154
154
  case 'attachSession': {
155
155
  logDebug('terminalManager.request.attach.start', {
156
156
  cols: message.payload.cols,
157
+ projectId: message.payload.projectId,
157
158
  rows: message.payload.rows,
158
- sessionId: message.payload.sessionId,
159
- snapshotTabs: message.payload.workspaceSnapshot?.tabs.length ?? 0,
159
+ snapshotTabs: message.payload.projectSnapshot?.tabs.length ?? 0,
160
160
  })
161
161
  const negotiatedVersion = requireNegotiatedVersion(socket, negotiatedVersions)
162
162
  if (message.payload.protocolVersion !== negotiatedVersion) {
@@ -165,13 +165,13 @@ export async function runTerminalManager(): Promise<void> {
165
165
  )
166
166
  }
167
167
  sessionManager.resize(
168
- message.payload.sessionId,
168
+ message.payload.projectId,
169
169
  message.payload.cols,
170
170
  message.payload.rows
171
171
  )
172
172
  const attachResult = sessionManager.attachSession(
173
- message.payload.sessionId,
174
- message.payload.workspaceSnapshot
173
+ message.payload.projectId,
174
+ message.payload.projectSnapshot
175
175
  )
176
176
  send(socket, {
177
177
  id: message.id,
@@ -180,7 +180,7 @@ export async function runTerminalManager(): Promise<void> {
180
180
  })
181
181
  logDebug('terminalManager.request.attach.success', {
182
182
  activeTabId: attachResult.activeTabId,
183
- sessionId: message.payload.sessionId,
183
+ projectId: message.payload.projectId,
184
184
  tabs: attachResult.tabs.length,
185
185
  })
186
186
  break
@@ -189,21 +189,21 @@ export async function runTerminalManager(): Promise<void> {
189
189
  requireNegotiatedVersion(socket, negotiatedVersions)
190
190
  logDebug('terminalManager.request.createTab.start', {
191
191
  command: message.payload.command,
192
- sessionId: message.payload.sessionId,
192
+ projectId: message.payload.projectId,
193
193
  tabId: message.payload.tabId,
194
194
  title: message.payload.title,
195
195
  })
196
- sessionManager.createTab(message.payload.sessionId, message.payload)
196
+ sessionManager.createTab(message.payload.projectId, message.payload)
197
197
  sendOk(socket, message.id)
198
198
  logDebug('terminalManager.request.createTab.success', {
199
- sessionId: message.payload.sessionId,
199
+ projectId: message.payload.projectId,
200
200
  tabId: message.payload.tabId,
201
201
  })
202
202
  break
203
203
  case 'write':
204
204
  requireNegotiatedVersion(socket, negotiatedVersions)
205
205
  sessionManager.write(
206
- message.payload.sessionId,
206
+ message.payload.projectId,
207
207
  message.payload.tabId,
208
208
  message.payload.data
209
209
  )
@@ -212,7 +212,7 @@ export async function runTerminalManager(): Promise<void> {
212
212
  case 'updateTabMetadata':
213
213
  requireNegotiatedVersion(socket, negotiatedVersions)
214
214
  sessionManager.updateTabMetadata(
215
- message.payload.sessionId,
215
+ message.payload.projectId,
216
216
  message.payload.tabId,
217
217
  message.payload
218
218
  )
@@ -221,7 +221,7 @@ export async function runTerminalManager(): Promise<void> {
221
221
  case 'resizeClient': {
222
222
  requireNegotiatedVersion(socket, negotiatedVersions)
223
223
  sessionManager.resize(
224
- message.payload.sessionId,
224
+ message.payload.projectId,
225
225
  message.payload.cols,
226
226
  message.payload.rows
227
227
  )
@@ -231,7 +231,7 @@ export async function runTerminalManager(): Promise<void> {
231
231
  case 'resizeTab':
232
232
  requireNegotiatedVersion(socket, negotiatedVersions)
233
233
  sessionManager.resizeTab(
234
- message.payload.sessionId,
234
+ message.payload.projectId,
235
235
  message.payload.tabId,
236
236
  message.payload.cols,
237
237
  message.payload.rows
@@ -241,7 +241,7 @@ export async function runTerminalManager(): Promise<void> {
241
241
  case 'scroll':
242
242
  requireNegotiatedVersion(socket, negotiatedVersions)
243
243
  sessionManager.scroll(
244
- message.payload.sessionId,
244
+ message.payload.projectId,
245
245
  message.payload.tabId,
246
246
  message.payload.deltaLines
247
247
  )
@@ -249,22 +249,22 @@ export async function runTerminalManager(): Promise<void> {
249
249
  break
250
250
  case 'scrollToBottom':
251
251
  requireNegotiatedVersion(socket, negotiatedVersions)
252
- sessionManager.scrollToBottom(message.payload.sessionId, message.payload.tabId)
252
+ sessionManager.scrollToBottom(message.payload.projectId, message.payload.tabId)
253
253
  sendOk(socket, message.id)
254
254
  break
255
255
  case 'setActiveTab':
256
256
  requireNegotiatedVersion(socket, negotiatedVersions)
257
- sessionManager.setActiveTab(message.payload.sessionId, message.payload.tabId)
257
+ sessionManager.setActiveTab(message.payload.projectId, message.payload.tabId)
258
258
  sendOk(socket, message.id)
259
259
  break
260
260
  case 'closeTab':
261
261
  requireNegotiatedVersion(socket, negotiatedVersions)
262
- sessionManager.closeTab(message.payload.sessionId, message.payload.tabId)
262
+ sessionManager.closeTab(message.payload.projectId, message.payload.tabId)
263
263
  sendOk(socket, message.id)
264
264
  break
265
265
  case 'disposeSession':
266
266
  requireNegotiatedVersion(socket, negotiatedVersions)
267
- sessionManager.disposeSession(message.payload.sessionId)
267
+ sessionManager.disposeSession(message.payload.projectId)
268
268
  sendOk(socket, message.id)
269
269
  break
270
270
  case 'ping':
@@ -29,7 +29,7 @@ interface GitPanelProps {
29
29
  pathConfig?: GitPanePathConfig
30
30
  diffCountConfig?: GitPaneDiffCountConfig
31
31
  headOffset?: number
32
- // When set, the single changed-files section is a worktree fork-point review
32
+ // When set, the single changed-files section is a workspace fork-point review
33
33
  // ("vs <base>") rather than a HEAD~N history walk.
34
34
  baseLabel?: string
35
35
  compact?: boolean
@@ -361,7 +361,7 @@ function computeStatusPlaceholder(
361
361
  ): StatusPlaceholder | null {
362
362
  const t = getCurrentTheme()
363
363
  if (!hasProjectPath) {
364
- return { label: 'No active session', labelColor: t.textMuted }
364
+ return { label: 'No active project', labelColor: t.textMuted }
365
365
  }
366
366
  if (gitPanel.error === 'not-a-repo') {
367
367
  return { label: 'Not a git repository', labelColor: t.textMuted }
@@ -15,14 +15,14 @@ import { useRepoDiscovery } from '../../../git/use-repo-discovery'
15
15
  import { useAppStore } from '../../../state/app-store'
16
16
  import { dispatchGlobal } from '../../../state/dispatch-ref'
17
17
  import { getSelectedGitFile, gitFileKey } from '../../../state/git-tree'
18
- import { getActiveWorktree, getSessionProjectPath } from '../../../state/session-worktrees'
18
+ import { getActiveWorkspace, getActiveWorkspacePath } from '../../../state/project-workspaces'
19
19
  import { setGitDiffScroller } from '../../git-view-controls'
20
+ import { formatBytes } from '../../terminal-graphics/dimensions'
20
21
  import { useTheme } from '../../theme'
21
22
  import { PierreDiff, type PierreDiffHandle } from './diff-renderer'
22
23
  import { useDiffPrefetch } from './diff-renderer/use-diff-prefetch'
23
24
  import { GitPanel } from './git-panel'
24
25
  import { ImageDiffView } from './image-diff'
25
- import { formatBytes } from './image-diff/dimensions'
26
26
  import { GitPaneHeader } from './pane/git-pane-header'
27
27
 
28
28
  interface DiffStageProps {
@@ -131,23 +131,23 @@ export const GitView = memo(function GitView({ themeId }: GitViewProps) {
131
131
  const gitPane = useAppStore((s) => s.gitPane)
132
132
  const gitPanel = useAppStore((s) => s.gitPanel)
133
133
  const gitMode = useAppStore((s) => s.gitMode)
134
- const currentSessionId = useAppStore((s) => s.currentSessionId)
135
- const sessions = useAppStore((s) => s.sessions)
134
+ const currentProjectId = useAppStore((s) => s.currentProjectId)
135
+ const projects = useAppStore((s) => s.projects)
136
136
  const focusMode = useAppStore((s) => s.focusMode)
137
137
  const diffRef = useRef<PierreDiffHandle | null>(null)
138
138
 
139
- const currentSession =
140
- currentSessionId != null && currentSessionId !== ''
141
- ? sessions.find((s) => s.id === currentSessionId)
139
+ const currentProject =
140
+ currentProjectId != null && currentProjectId !== ''
141
+ ? projects.find((s) => s.id === currentProjectId)
142
142
  : undefined
143
- const projectPath = getSessionProjectPath(currentSession)
143
+ const projectPath = getActiveWorkspacePath(currentProject)
144
144
 
145
- // Review-vs-base: when toggled on for a worktree that records a baseRef,
145
+ // Review-vs-base: when toggled on for a workspace that records a baseRef,
146
146
  // resolve the fork point and diff the working tree against it.
147
- const activeWorktree = getActiveWorktree(currentSession)
147
+ const activeWorkspace = getActiveWorkspace(currentProject)
148
148
  const reviewBaseRef =
149
- gitMode.reviewBase && activeWorktree?.baseRef != null && activeWorktree.baseRef !== ''
150
- ? activeWorktree.baseRef
149
+ gitMode.reviewBase && activeWorkspace?.baseRef != null && activeWorkspace.baseRef !== ''
150
+ ? activeWorkspace.baseRef
151
151
  : null
152
152
  const [compareRef, setCompareRef] = useState<string | undefined>(undefined)
153
153
  useEffect(() => {
@@ -8,8 +8,8 @@ import {
8
8
  isInsideTmux,
9
9
  terminalLabel,
10
10
  } from '../../../terminal-graphics/capabilities'
11
+ import { formatBytes, readImageDimensions } from '../../../terminal-graphics/dimensions'
11
12
  import { useTheme } from '../../../theme'
12
- import { formatBytes, readImageDimensions } from './dimensions'
13
13
  import { TerminalImagePane } from './terminal-image-pane'
14
14
 
15
15
  interface ImageDiffViewProps {
@@ -6,7 +6,7 @@ import { useGitPanelPolling } from '../../../../git/git-poller'
6
6
  import { usePrStatusPolling } from '../../../../git/pr-status-poller'
7
7
  import { useRepoDiscovery } from '../../../../git/use-repo-discovery'
8
8
  import { useAppStore } from '../../../../state/app-store'
9
- import { getSessionProjectPath } from '../../../../state/session-worktrees'
9
+ import { getActiveWorkspacePath } from '../../../../state/project-workspaces'
10
10
  import { GitPanel } from '../git-panel'
11
11
  import { GitPaneHeader, type GitPaneTab } from './git-pane-header'
12
12
  import { PrChecksPanel } from './pr-checks-panel'
@@ -26,13 +26,13 @@ export const GitPaneWidget = memo(function GitPaneWidget({
26
26
  const treeCompaction = useAppStore((s) => s.gitPane.treeCompaction)
27
27
  const pathConfig = useAppStore((s) => s.gitPane.path)
28
28
  const diffCountConfig = useAppStore((s) => s.gitPane.diffCount)
29
- const currentSessionId = useAppStore((s) => s.currentSessionId)
30
- const sessions = useAppStore((s) => s.sessions)
31
- const currentSession =
32
- currentSessionId != null && currentSessionId !== ''
33
- ? sessions.find((s) => s.id === currentSessionId)
29
+ const currentProjectId = useAppStore((s) => s.currentProjectId)
30
+ const projects = useAppStore((s) => s.projects)
31
+ const currentProject =
32
+ currentProjectId != null && currentProjectId !== ''
33
+ ? projects.find((s) => s.id === currentProjectId)
34
34
  : undefined
35
- const projectPath = getSessionProjectPath(currentSession)
35
+ const projectPath = getActiveWorkspacePath(currentProject)
36
36
 
37
37
  const [tab, setTab] = useState<GitPaneTab>('files')
38
38