@brimveyn/aimux-config 0.5.17 → 0.6.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.
- package/package.json +1 -1
- package/src/actions.ts +127 -19
- package/src/backends.ts +1 -1
- package/src/defaults.ts +22 -1
- package/src/tui/registry.ts +1 -1
- package/src/tui/resolve.ts +1 -7
- package/src/types.ts +88 -3
package/package.json
CHANGED
package/src/actions.ts
CHANGED
|
@@ -80,7 +80,7 @@ export const splitHorizontal: KeyResult = r(
|
|
|
80
80
|
)
|
|
81
81
|
|
|
82
82
|
export const enterInsert: ActionFn = (ctx: ModeContext) => {
|
|
83
|
-
if (!ctx.state.activeTabId) return null
|
|
83
|
+
if (!(ctx.state.activeTabId != null && ctx.state.activeTabId !== '')) return null
|
|
84
84
|
return r([{ focusMode: 'terminal-input', type: 'set-focus-mode' }], [], 'terminal-input')
|
|
85
85
|
}
|
|
86
86
|
|
|
@@ -88,13 +88,15 @@ export const closeModal: KeyResult = r([{ type: 'close-modal' }], [], 'navigatio
|
|
|
88
88
|
|
|
89
89
|
export const closeOverlayModal: KeyResult = r([{ type: 'close-modal' }])
|
|
90
90
|
|
|
91
|
+
export const cancelNewTabModal: KeyResult = r([{ type: 'cancel-command-edit' }])
|
|
92
|
+
|
|
91
93
|
// ---------------------------------------------------------------------------
|
|
92
94
|
// Dynamic actions (need ctx at runtime — ActionFn)
|
|
93
95
|
// ---------------------------------------------------------------------------
|
|
94
96
|
|
|
95
97
|
export const closeTab: ActionFn = (ctx: ModeContext) => {
|
|
96
98
|
const tabId = ctx.state.activeTabId
|
|
97
|
-
if (!tabId) return null
|
|
99
|
+
if (!(tabId != null && tabId !== '')) return null
|
|
98
100
|
return r([{ type: 'close-active-tab' }], [{ tabId, type: 'close-tab' }])
|
|
99
101
|
}
|
|
100
102
|
|
|
@@ -153,7 +155,7 @@ export function focusPane(direction: 'left' | 'right' | 'up' | 'down'): KeyResul
|
|
|
153
155
|
export function resizePane(delta: number, axis: 'horizontal' | 'vertical'): ActionFn {
|
|
154
156
|
return (ctx: ModeContext) => {
|
|
155
157
|
const tabId = ctx.state.activeTabId
|
|
156
|
-
if (!tabId) return null
|
|
158
|
+
if (!(tabId != null && tabId !== '')) return null
|
|
157
159
|
return r([{ axis, delta, tabId, type: 'resize-pane' }])
|
|
158
160
|
}
|
|
159
161
|
}
|
|
@@ -173,7 +175,45 @@ export function moveModalSelectionWithPreview(
|
|
|
173
175
|
// Modal-specific actions
|
|
174
176
|
// ---------------------------------------------------------------------------
|
|
175
177
|
|
|
176
|
-
export const launchSelectedAssistant:
|
|
178
|
+
export const launchSelectedAssistant: ActionFn = (ctx: ModeContext) => {
|
|
179
|
+
if (ctx.state.modal.type === 'new-tab' && ctx.state.modal.step === 'assistant') {
|
|
180
|
+
return r([{ type: 'select-new-tab-assistant' }])
|
|
181
|
+
}
|
|
182
|
+
if (
|
|
183
|
+
ctx.state.modal.type === 'new-tab' &&
|
|
184
|
+
ctx.state.modal.step === 'worktree' &&
|
|
185
|
+
ctx.state.modal.createWorktree
|
|
186
|
+
) {
|
|
187
|
+
return r([{ type: 'enter-new-tab-worktree-create' }])
|
|
188
|
+
}
|
|
189
|
+
return r([], [{ type: 'launch-selected-assistant' }])
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export const toggleNewTabWorktree: KeyResult = r([{ type: 'toggle-new-tab-worktree' }])
|
|
193
|
+
|
|
194
|
+
export const deleteSelectedWorktree: ActionFn = (ctx: ModeContext) => {
|
|
195
|
+
const modal = ctx.state.modal
|
|
196
|
+
const sessionId = ctx.state.currentSessionId
|
|
197
|
+
if (modal.type !== 'new-tab' || modal.step !== 'worktree' || modal.createWorktree) return null
|
|
198
|
+
if (!(sessionId != null && sessionId !== '')) return null
|
|
199
|
+
const session = ctx.state.sessions.find((entry) => entry.id === sessionId)
|
|
200
|
+
const worktree = session?.worktrees?.[modal.selectedIndex]
|
|
201
|
+
if (!worktree) return null
|
|
202
|
+
return r(
|
|
203
|
+
[
|
|
204
|
+
{ index: modal.selectedIndex, type: 'set-modal-selection-index' },
|
|
205
|
+
{ message: null, type: 'set-new-tab-worktree-delete-state' },
|
|
206
|
+
],
|
|
207
|
+
[
|
|
208
|
+
{
|
|
209
|
+
force: modal.worktreeDeleteConfirmId === worktree.id,
|
|
210
|
+
sessionId,
|
|
211
|
+
type: 'delete-worktree',
|
|
212
|
+
worktreeId: worktree.id,
|
|
213
|
+
},
|
|
214
|
+
]
|
|
215
|
+
)
|
|
216
|
+
}
|
|
177
217
|
|
|
178
218
|
export const cancelCommandEdit = (returnTo: KeyResult['transition']): KeyResult =>
|
|
179
219
|
r([{ type: 'cancel-command-edit' }], [], returnTo)
|
|
@@ -298,9 +338,66 @@ export const confirmUpdateSelection: KeyResult = r(
|
|
|
298
338
|
'navigation'
|
|
299
339
|
)
|
|
300
340
|
|
|
341
|
+
// ---------------------------------------------------------------------------
|
|
342
|
+
// Worktree-move modal
|
|
343
|
+
// ---------------------------------------------------------------------------
|
|
344
|
+
|
|
345
|
+
export const openWorktreeMove: ActionFn = (ctx: ModeContext) => {
|
|
346
|
+
if (ctx.state.gitMode.headOffset > 0) {
|
|
347
|
+
return r([
|
|
348
|
+
{
|
|
349
|
+
message: 'disabled while viewing HEAD~N (press 0 or [ to return)',
|
|
350
|
+
type: 'git-mode-set-message',
|
|
351
|
+
},
|
|
352
|
+
])
|
|
353
|
+
}
|
|
354
|
+
const session = ctx.state.sessions.find((entry) => entry.id === ctx.state.currentSessionId)
|
|
355
|
+
const worktrees = session?.worktrees ?? []
|
|
356
|
+
// From git mode, the source is the active worktree (the one being reviewed).
|
|
357
|
+
const source = worktrees.find((w) => w.id === session?.activeWorktreeId) ?? worktrees[0]
|
|
358
|
+
const hasBranch = source != null && source.branch != null && source.branch !== ''
|
|
359
|
+
const others = worktrees.filter((w) => w.id !== source?.id)
|
|
360
|
+
if (!hasBranch || source == null || others.length < 1) {
|
|
361
|
+
return r([{ message: 'no other worktree to move into', type: 'git-mode-set-message' }])
|
|
362
|
+
}
|
|
363
|
+
// Overlay: no mode transition — deriveModeId routes input to the picker and
|
|
364
|
+
// focusMode stays 'git' so the git view remains mounted underneath.
|
|
365
|
+
return r([{ sourceWorktreeId: source.id, type: 'open-worktree-move-modal' }])
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export const toggleWorktreeMoveDelete: KeyResult = r([{ type: 'toggle-worktree-move-delete' }])
|
|
369
|
+
|
|
370
|
+
export const confirmWorktreeMove: ActionFn = (ctx: ModeContext) => {
|
|
371
|
+
const modal = ctx.state.modal
|
|
372
|
+
const session = ctx.state.sessions.find((entry) => entry.id === ctx.state.currentSessionId)
|
|
373
|
+
const worktrees = session?.worktrees ?? []
|
|
374
|
+
const sourceId = modal.type === 'worktree-move' ? modal.sourceWorktreeId : undefined
|
|
375
|
+
const source = worktrees.find((w) => w.id === sourceId)
|
|
376
|
+
const targets = worktrees.filter((w) => w.id !== sourceId)
|
|
377
|
+
const selectedIndex = modal.type === 'worktree-move' ? modal.selectedIndex : 0
|
|
378
|
+
const target = targets[selectedIndex]
|
|
379
|
+
if (!target || !session || !source || modal.type !== 'worktree-move') {
|
|
380
|
+
return r([{ type: 'close-modal' }])
|
|
381
|
+
}
|
|
382
|
+
// Overlay close keeps focusMode 'git' (see close-modal reducer), so the move
|
|
383
|
+
// result lands back in the git view that was underneath the picker.
|
|
384
|
+
return r(
|
|
385
|
+
[{ type: 'close-modal' }],
|
|
386
|
+
[
|
|
387
|
+
{
|
|
388
|
+
deleteSource: modal.deleteSource,
|
|
389
|
+
sessionId: session.id,
|
|
390
|
+
sourceWorktreeId: source.id,
|
|
391
|
+
targetWorktreeId: target.id,
|
|
392
|
+
type: 'move-worktree',
|
|
393
|
+
},
|
|
394
|
+
]
|
|
395
|
+
)
|
|
396
|
+
}
|
|
397
|
+
|
|
301
398
|
export const closePane: ActionFn = (ctx: ModeContext) => {
|
|
302
399
|
const tabId = ctx.state.activeTabId
|
|
303
|
-
if (!tabId) return null
|
|
400
|
+
if (!(tabId != null && tabId !== '')) return null
|
|
304
401
|
return r(
|
|
305
402
|
[
|
|
306
403
|
{ tabId, type: 'close-pane' },
|
|
@@ -345,7 +442,9 @@ export const confirmSessionRename: ActionFn = (ctx: ModeContext) => {
|
|
|
345
442
|
? 'modal.session-picker.filtering'
|
|
346
443
|
: 'navigation'
|
|
347
444
|
const effects: KeyResult['effects'] =
|
|
348
|
-
trimmed && sessionId
|
|
445
|
+
trimmed && sessionId != null && sessionId !== ''
|
|
446
|
+
? [{ name: trimmed, sessionId, type: 'rename-session' }]
|
|
447
|
+
: []
|
|
349
448
|
return r([closeAction], effects, transition)
|
|
350
449
|
}
|
|
351
450
|
|
|
@@ -354,7 +453,7 @@ export const confirmRenameTab: ActionFn = (ctx: ModeContext) => {
|
|
|
354
453
|
const trimmed = (ctx.state.modal.editBuffer ?? '').trim()
|
|
355
454
|
const tabId = ctx.state.modal.sessionTargetId
|
|
356
455
|
const actions: KeyResult['actions'] = []
|
|
357
|
-
if (trimmed && tabId) {
|
|
456
|
+
if (trimmed && tabId != null && tabId !== '') {
|
|
358
457
|
actions.push({ tabId, title: trimmed, type: 'rename-tab' })
|
|
359
458
|
}
|
|
360
459
|
actions.push({ type: 'close-modal' })
|
|
@@ -387,14 +486,14 @@ export const confirmCreateSession: ActionFn = (ctx: ModeContext) => {
|
|
|
387
486
|
}
|
|
388
487
|
|
|
389
488
|
function getDefaultSessionName(projectPath?: string): string {
|
|
390
|
-
if (!projectPath) return ''
|
|
489
|
+
if (!(projectPath != null && projectPath !== '')) return ''
|
|
391
490
|
const segments = projectPath.split('/').filter(Boolean)
|
|
392
491
|
return segments.at(-1) ?? ''
|
|
393
492
|
}
|
|
394
493
|
|
|
395
494
|
// Session picker escape (conditional)
|
|
396
495
|
export const sessionPickerEscape: ActionFn = (ctx: ModeContext) => {
|
|
397
|
-
if (!ctx.state.currentSessionId) return null
|
|
496
|
+
if (!(ctx.state.currentSessionId != null && ctx.state.currentSessionId !== '')) return null
|
|
398
497
|
return r([{ type: 'close-modal' }], [], 'navigation')
|
|
399
498
|
}
|
|
400
499
|
|
|
@@ -420,15 +519,19 @@ function clearPendingDelete(ctx: ModeContext): AppAction[] {
|
|
|
420
519
|
return [{ path: null, type: 'git-mode-set-pending-delete' }]
|
|
421
520
|
}
|
|
422
521
|
|
|
423
|
-
function gitFileKey(section: string, path: string): string {
|
|
424
|
-
return
|
|
522
|
+
function gitFileKey(section: string, path: string, repoPath?: string): string {
|
|
523
|
+
return repoPath != null && repoPath !== ''
|
|
524
|
+
? `${section}:${repoPath}:${path}`
|
|
525
|
+
: `${section}:${path}`
|
|
425
526
|
}
|
|
426
527
|
|
|
427
528
|
function selectedGitFile(ctx: ModeContext) {
|
|
428
529
|
const key = ctx.state.gitMode.selectedEntryKey
|
|
429
|
-
if (!key) return null
|
|
530
|
+
if (!(key != null && key !== '')) return null
|
|
430
531
|
return (
|
|
431
|
-
ctx.state.gitPanel.files.find(
|
|
532
|
+
ctx.state.gitPanel.files.find(
|
|
533
|
+
(file) => gitFileKey(file.section, file.path, file.repoPath) === key
|
|
534
|
+
) ?? null
|
|
432
535
|
)
|
|
433
536
|
}
|
|
434
537
|
|
|
@@ -449,17 +552,20 @@ export function selectGitFileOnly(delta: -1 | 1): ActionFn {
|
|
|
449
552
|
}
|
|
450
553
|
|
|
451
554
|
export const toggleSelectedGitFolder: ActionFn = (ctx: ModeContext) => {
|
|
452
|
-
if (!ctx.state.gitMode.selectedEntryKey
|
|
555
|
+
if (!(ctx.state.gitMode.selectedEntryKey != null && ctx.state.gitMode.selectedEntryKey !== ''))
|
|
556
|
+
return r([])
|
|
453
557
|
return r([{ type: 'git-mode-toggle-selected-folder' }])
|
|
454
558
|
}
|
|
455
559
|
|
|
456
560
|
export const collapseGitSelection: ActionFn = (ctx: ModeContext) => {
|
|
457
|
-
if (!ctx.state.gitMode.selectedEntryKey
|
|
561
|
+
if (!(ctx.state.gitMode.selectedEntryKey != null && ctx.state.gitMode.selectedEntryKey !== ''))
|
|
562
|
+
return r([])
|
|
458
563
|
return r([{ type: 'git-mode-collapse-selection' }])
|
|
459
564
|
}
|
|
460
565
|
|
|
461
566
|
export const expandGitSelection: ActionFn = (ctx: ModeContext) => {
|
|
462
|
-
if (!ctx.state.gitMode.selectedEntryKey
|
|
567
|
+
if (!(ctx.state.gitMode.selectedEntryKey != null && ctx.state.gitMode.selectedEntryKey !== ''))
|
|
568
|
+
return r([])
|
|
463
569
|
return r([{ type: 'git-mode-expand-selection' }])
|
|
464
570
|
}
|
|
465
571
|
|
|
@@ -485,6 +591,8 @@ export function scrollGitDiff(delta: number): KeyResult {
|
|
|
485
591
|
|
|
486
592
|
export const toggleGitDiffView: KeyResult = r([{ type: 'git-mode-toggle-diff-view' }])
|
|
487
593
|
|
|
594
|
+
export const toggleGitReviewBase: KeyResult = r([{ type: 'git-mode-toggle-review-base' }])
|
|
595
|
+
|
|
488
596
|
export function shiftGitHeadOffset(delta: number): KeyResult {
|
|
489
597
|
return r([
|
|
490
598
|
{ delta, type: 'git-mode-shift-head-offset' },
|
|
@@ -561,7 +669,7 @@ export const gitDestructiveSelected: ActionFn = (ctx: ModeContext) => {
|
|
|
561
669
|
export const gitToggleFoldAll: ActionFn = (ctx: ModeContext) => {
|
|
562
670
|
const file = selectedGitFile(ctx)
|
|
563
671
|
if (!file) return r([])
|
|
564
|
-
const key = gitFileKey(file.section, file.path)
|
|
672
|
+
const key = gitFileKey(file.section, file.path, file.repoPath)
|
|
565
673
|
return r([{ key, type: 'git-mode-fold-toggle-all' }])
|
|
566
674
|
}
|
|
567
675
|
|
|
@@ -687,7 +795,7 @@ export const gitCommitEnterConfirm: ActionFn = (ctx: ModeContext) => {
|
|
|
687
795
|
return r([{ type: 'git-commit-enter-confirm' }], [], 'modal.git-commit.confirm')
|
|
688
796
|
}
|
|
689
797
|
const sessionId = ctx.state.currentSessionId
|
|
690
|
-
if (!sessionId) {
|
|
798
|
+
if (!(sessionId != null && sessionId !== '')) {
|
|
691
799
|
return r([{ type: 'git-commit-enter-confirm' }], [], 'modal.git-commit.confirm')
|
|
692
800
|
}
|
|
693
801
|
return r(
|
|
@@ -706,7 +814,7 @@ export const gitCommitLeaveConfirm: KeyResult = r(
|
|
|
706
814
|
export const gitCommitLeaveGenerating: ActionFn = (ctx: ModeContext) => {
|
|
707
815
|
const sessionId = ctx.state.currentSessionId
|
|
708
816
|
const actionsList: AppAction[] = [{ type: 'git-commit-leave-generating' }]
|
|
709
|
-
if (sessionId) {
|
|
817
|
+
if (sessionId != null && sessionId !== '') {
|
|
710
818
|
actionsList.push({ sessionId, type: 'auto-commit-clear' })
|
|
711
819
|
}
|
|
712
820
|
return r(actionsList, [], 'modal.git-commit')
|
package/src/backends.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { BackendConfig } from './types'
|
|
|
6
6
|
*/
|
|
7
7
|
export function claudeBackend(opts?: { model?: string }): BackendConfig {
|
|
8
8
|
return {
|
|
9
|
-
args: opts?.model ? ['--model', opts.model] : [],
|
|
9
|
+
args: opts?.model != null && opts.model !== '' ? ['--model', opts.model] : [],
|
|
10
10
|
command: 'claude',
|
|
11
11
|
}
|
|
12
12
|
}
|
package/src/defaults.ts
CHANGED
|
@@ -104,8 +104,10 @@ export function getDefaultKeymapConfig(): ResolvedKeymapConfig {
|
|
|
104
104
|
.map('e', actions.gitToggleFoldAll, 'Expand/collapse all folds')
|
|
105
105
|
.map('o', actions.openSelectedGitFileInEditor, 'Open in editor')
|
|
106
106
|
.map('c', actions.gitCommitOpen, 'Commit')
|
|
107
|
+
.map('m', actions.openWorktreeMove, 'Move worktree')
|
|
107
108
|
.map('p', actions.gitPush, 'Push')
|
|
108
109
|
.map('v', actions.toggleGitDiffView, 'Toggle split/stacked')
|
|
110
|
+
.map('b', actions.toggleGitReviewBase, 'Review vs base')
|
|
109
111
|
.map('t', actions.toggleGitFileListMode, 'Toggle flat/tree')
|
|
110
112
|
.map('T', actions.toggleTreeCompaction, 'Toggle tree compaction')
|
|
111
113
|
.map(']', actions.shiftGitHeadOffset(-1), 'Newer commit')
|
|
@@ -182,6 +184,22 @@ export function getDefaultKeymapConfig(): ResolvedKeymapConfig {
|
|
|
182
184
|
.map('<CR>', actions.confirmUpdateSelection, 'Confirm')
|
|
183
185
|
)
|
|
184
186
|
|
|
187
|
+
// -----------------------------------------------------------------------
|
|
188
|
+
// Modal: worktree-move
|
|
189
|
+
// -----------------------------------------------------------------------
|
|
190
|
+
.mode('modal.worktree-move', (m) =>
|
|
191
|
+
m
|
|
192
|
+
.map('<Esc>', actions.closeModal, 'Cancel')
|
|
193
|
+
.map('j', actions.moveModalSelection(1), 'Next')
|
|
194
|
+
.map('k', actions.moveModalSelection(-1), 'Prev')
|
|
195
|
+
.map('<Down>', actions.moveModalSelection(1))
|
|
196
|
+
.map('<Up>', actions.moveModalSelection(-1))
|
|
197
|
+
.map('<C-n>', actions.moveModalSelection(1))
|
|
198
|
+
.map('<C-p>', actions.moveModalSelection(-1))
|
|
199
|
+
.map('d', actions.toggleWorktreeMoveDelete, 'Toggle delete source')
|
|
200
|
+
.map('<CR>', actions.confirmWorktreeMove, 'Move')
|
|
201
|
+
)
|
|
202
|
+
|
|
185
203
|
// -----------------------------------------------------------------------
|
|
186
204
|
// Modal: rename-tab
|
|
187
205
|
// -----------------------------------------------------------------------
|
|
@@ -197,8 +215,11 @@ export function getDefaultKeymapConfig(): ResolvedKeymapConfig {
|
|
|
197
215
|
// -----------------------------------------------------------------------
|
|
198
216
|
.mode('modal.new-tab.command-edit', (m) =>
|
|
199
217
|
m
|
|
200
|
-
.map('<Esc>', actions.
|
|
218
|
+
.map('<Esc>', actions.cancelNewTabModal, 'Cancel')
|
|
201
219
|
.map('<CR>', actions.launchSelectedAssistant, 'Launch')
|
|
220
|
+
.map('<C-w>', actions.toggleNewTabWorktree, 'WT')
|
|
221
|
+
.map('<C-d>', actions.deleteSelectedWorktree, 'Delete WT')
|
|
222
|
+
.map('<Tab>', actions.switchField, 'Next field')
|
|
202
223
|
.map('<C-n>', actions.moveModalSelection(1), 'Next')
|
|
203
224
|
.map('<C-p>', actions.moveModalSelection(-1), 'Prev')
|
|
204
225
|
.map('<Down>', actions.moveModalSelection(1))
|
package/src/tui/registry.ts
CHANGED
|
@@ -76,7 +76,7 @@ export const TUI_THEMES: Record<string, TuiThemeJson> = {
|
|
|
76
76
|
'zenburn': zenburn as TuiThemeJson,
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
export type ThemeId = keyof typeof TUI_THEMES
|
|
79
|
+
export type ThemeId = keyof typeof TUI_THEMES
|
|
80
80
|
|
|
81
81
|
export const THEME_IDS: ThemeId[] = Object.keys(TUI_THEMES).sort() as ThemeId[]
|
|
82
82
|
|
package/src/tui/resolve.ts
CHANGED
|
@@ -12,13 +12,7 @@ const TRANSPARENT: RGBA = { a: 0, b: 0, g: 0, r: 0 }
|
|
|
12
12
|
function rgbaFromHex(hex: string): RGBA {
|
|
13
13
|
const h = hex.replace('#', '')
|
|
14
14
|
// expand short forms (#rgb, #rgba)
|
|
15
|
-
const expanded =
|
|
16
|
-
h.length === 3 || h.length === 4
|
|
17
|
-
? h
|
|
18
|
-
.split('')
|
|
19
|
-
.map((c) => c + c)
|
|
20
|
-
.join('')
|
|
21
|
-
: h
|
|
15
|
+
const expanded = h.length === 3 || h.length === 4 ? h.replaceAll(/(.)/g, '$1$1') : h
|
|
22
16
|
if (expanded.length === 6) {
|
|
23
17
|
const num = parseInt(expanded, 16)
|
|
24
18
|
return {
|
package/src/types.ts
CHANGED
|
@@ -27,6 +27,7 @@ export type ModeId =
|
|
|
27
27
|
| 'modal.git-commit.confirm'
|
|
28
28
|
| 'modal.git-commit.generating'
|
|
29
29
|
| 'modal.update-available'
|
|
30
|
+
| 'modal.worktree-move'
|
|
30
31
|
| 'modal.ai-usage'
|
|
31
32
|
|
|
32
33
|
// ─── Primitive app types ──────────────────────────────────────────────────────
|
|
@@ -82,8 +83,11 @@ export interface TerminalModeState {
|
|
|
82
83
|
|
|
83
84
|
// ─── Layout ───────────────────────────────────────────────────────────────────
|
|
84
85
|
|
|
85
|
-
export
|
|
86
|
-
|
|
86
|
+
export interface LayoutLeaf {
|
|
87
|
+
type: 'leaf'
|
|
88
|
+
tabId: string
|
|
89
|
+
}
|
|
90
|
+
export interface LayoutSplit {
|
|
87
91
|
type: 'split'
|
|
88
92
|
direction: SplitDirection
|
|
89
93
|
ratio: number
|
|
@@ -105,6 +109,7 @@ export interface PersistedTabSnapshot {
|
|
|
105
109
|
terminalModes: TerminalModeState
|
|
106
110
|
errorMessage?: string
|
|
107
111
|
exitCode?: number
|
|
112
|
+
worktreeId?: string
|
|
108
113
|
}
|
|
109
114
|
|
|
110
115
|
export interface WorkspaceSnapshotV1 {
|
|
@@ -121,6 +126,23 @@ export interface WorkspaceSnapshotV1 {
|
|
|
121
126
|
tabGroupMap?: Record<string, string>
|
|
122
127
|
}
|
|
123
128
|
|
|
129
|
+
export type WorktreeSource = 'primary' | 'aimux-temp' | 'external'
|
|
130
|
+
|
|
131
|
+
export interface WorktreeRecord {
|
|
132
|
+
id: string
|
|
133
|
+
name: string
|
|
134
|
+
path: string
|
|
135
|
+
repoRoot: string
|
|
136
|
+
branch?: string
|
|
137
|
+
baseRef?: string
|
|
138
|
+
commitSha?: string
|
|
139
|
+
source: WorktreeSource
|
|
140
|
+
createdByAimux: boolean
|
|
141
|
+
color?: string
|
|
142
|
+
createdAt: string
|
|
143
|
+
updatedAt: string
|
|
144
|
+
}
|
|
145
|
+
|
|
124
146
|
export interface SessionRecord {
|
|
125
147
|
id: string
|
|
126
148
|
name: string
|
|
@@ -130,6 +152,8 @@ export interface SessionRecord {
|
|
|
130
152
|
lastOpenedAt: string
|
|
131
153
|
order?: number
|
|
132
154
|
workspaceSnapshot?: WorkspaceSnapshotV1
|
|
155
|
+
worktrees?: WorktreeRecord[]
|
|
156
|
+
activeWorktreeId?: string
|
|
133
157
|
}
|
|
134
158
|
|
|
135
159
|
export interface TabSession {
|
|
@@ -144,6 +168,7 @@ export interface TabSession {
|
|
|
144
168
|
command: string
|
|
145
169
|
errorMessage?: string
|
|
146
170
|
exitCode?: number
|
|
171
|
+
worktreeId?: string
|
|
147
172
|
}
|
|
148
173
|
|
|
149
174
|
export interface SnippetRecord {
|
|
@@ -194,6 +219,7 @@ export interface GitFileEntry {
|
|
|
194
219
|
status: GitFileStatus
|
|
195
220
|
added: number | null
|
|
196
221
|
removed: number | null
|
|
222
|
+
repoPath?: string
|
|
197
223
|
}
|
|
198
224
|
|
|
199
225
|
export type GitPanelError = 'not-a-repo' | 'unknown'
|
|
@@ -244,6 +270,7 @@ export interface GitModeState {
|
|
|
244
270
|
diffView: GitDiffView
|
|
245
271
|
folds: Record<string, Record<string, FoldState>>
|
|
246
272
|
headOffset: number
|
|
273
|
+
reviewBase: boolean
|
|
247
274
|
}
|
|
248
275
|
|
|
249
276
|
interface ModalBase {
|
|
@@ -262,6 +289,16 @@ export interface ModalClosed extends ModalBase {
|
|
|
262
289
|
export interface ModalNewTab extends ModalBase {
|
|
263
290
|
type: 'new-tab'
|
|
264
291
|
editingCommand: AssistantId | null
|
|
292
|
+
activeField: 'assistant' | 'branch-name' | 'target-worktree' | 'worktree-name'
|
|
293
|
+
branchError: string | null
|
|
294
|
+
branchName: string
|
|
295
|
+
createWorktree: boolean
|
|
296
|
+
selectedAssistantId: AssistantId | null
|
|
297
|
+
step: 'assistant' | 'worktree' | 'worktree-create'
|
|
298
|
+
targetWorktreeIndex: number
|
|
299
|
+
worktreeDeleteConfirmId: string | null
|
|
300
|
+
worktreeDeleteMessage: string | null
|
|
301
|
+
worktreeName: string
|
|
265
302
|
}
|
|
266
303
|
export interface ModalSessionPicker extends ModalBase {
|
|
267
304
|
type: 'session-picker'
|
|
@@ -322,6 +359,13 @@ export interface ModalAIUsage extends ModalBase {
|
|
|
322
359
|
type: 'ai-usage'
|
|
323
360
|
}
|
|
324
361
|
|
|
362
|
+
export interface ModalWorktreeMove extends ModalBase {
|
|
363
|
+
type: 'worktree-move'
|
|
364
|
+
/** The worktree being moved (may differ from the active one, e.g. a tab menu). */
|
|
365
|
+
sourceWorktreeId: string
|
|
366
|
+
deleteSource: boolean
|
|
367
|
+
}
|
|
368
|
+
|
|
325
369
|
export type ModalState =
|
|
326
370
|
| ModalClosed
|
|
327
371
|
| ModalNewTab
|
|
@@ -337,6 +381,7 @@ export type ModalState =
|
|
|
337
381
|
| ModalGitCommit
|
|
338
382
|
| ModalUpdateAvailable
|
|
339
383
|
| ModalAIUsage
|
|
384
|
+
| ModalWorktreeMove
|
|
340
385
|
|
|
341
386
|
export interface LayoutState {
|
|
342
387
|
terminalCols: number
|
|
@@ -403,6 +448,7 @@ export interface AppState {
|
|
|
403
448
|
gitMode: GitModeState
|
|
404
449
|
autoCommit: AutoCommitState
|
|
405
450
|
multiRepo: MultiRepoState
|
|
451
|
+
worktreeDivergence: Record<string, BranchDivergence>
|
|
406
452
|
pendingChords: string[] | null
|
|
407
453
|
}
|
|
408
454
|
|
|
@@ -410,6 +456,15 @@ export interface AppState {
|
|
|
410
456
|
|
|
411
457
|
export type ModalAction =
|
|
412
458
|
| { type: 'open-new-tab-modal' }
|
|
459
|
+
| { type: 'set-new-tab-branch-error'; message: string | null }
|
|
460
|
+
| {
|
|
461
|
+
type: 'set-new-tab-worktree-delete-state'
|
|
462
|
+
confirmWorktreeId?: string | null
|
|
463
|
+
message: string | null
|
|
464
|
+
}
|
|
465
|
+
| { type: 'enter-new-tab-worktree-create' }
|
|
466
|
+
| { type: 'select-new-tab-assistant'; assistantId?: AssistantId }
|
|
467
|
+
| { type: 'toggle-new-tab-worktree'; assistantId?: AssistantId }
|
|
413
468
|
| { type: 'open-help-modal'; scope?: ModeId }
|
|
414
469
|
| { type: 'open-split-picker'; direction: SplitDirection }
|
|
415
470
|
| { type: 'open-session-picker' }
|
|
@@ -434,8 +489,11 @@ export type ModalAction =
|
|
|
434
489
|
| { type: 'set-theme-entry-count'; count: number }
|
|
435
490
|
| { type: 'open-theme-picker' }
|
|
436
491
|
| { type: 'open-update-available-modal'; currentVersion: string; latestVersion: string }
|
|
492
|
+
| { type: 'set-modal-selection-index'; index: number }
|
|
437
493
|
| { type: 'open-ai-usage-modal' }
|
|
438
494
|
| { type: 'open-edit-custom-command'; assistantId: AssistantId }
|
|
495
|
+
| { type: 'open-worktree-move-modal'; sourceWorktreeId: string }
|
|
496
|
+
| { type: 'toggle-worktree-move-delete' }
|
|
439
497
|
|
|
440
498
|
export type SessionAction =
|
|
441
499
|
| { type: 'load-session'; sessionId: string; workspaceSnapshot?: WorkspaceSnapshotV1 }
|
|
@@ -445,6 +503,15 @@ export type SessionAction =
|
|
|
445
503
|
| { type: 'delete-session-record'; sessionId: string; openSessionPicker?: boolean }
|
|
446
504
|
| { type: 'reorder-sessions'; orderedIds: string[] }
|
|
447
505
|
| { type: 'set-session-status'; sessionId: string; status: SessionStatus }
|
|
506
|
+
| { type: 'add-worktree-record'; sessionId: string; worktree: WorktreeRecord; activate?: boolean }
|
|
507
|
+
| { type: 'remove-worktree-record'; sessionId: string; worktreeId: string }
|
|
508
|
+
| { type: 'set-active-worktree'; sessionId: string; worktreeId: string }
|
|
509
|
+
| {
|
|
510
|
+
type: 'update-worktree-record'
|
|
511
|
+
sessionId: string
|
|
512
|
+
worktreeId: string
|
|
513
|
+
patch: Partial<WorktreeRecord>
|
|
514
|
+
}
|
|
448
515
|
|
|
449
516
|
export type TabAction =
|
|
450
517
|
| { type: 'add-tab'; tab: TabSession }
|
|
@@ -520,10 +587,17 @@ export interface GitRefreshPayload {
|
|
|
520
587
|
files: GitFileEntry[]
|
|
521
588
|
}
|
|
522
589
|
|
|
590
|
+
/** Commits a worktree branch is ahead/behind the ref it forked from. */
|
|
591
|
+
export interface BranchDivergence {
|
|
592
|
+
ahead: number
|
|
593
|
+
behind: number
|
|
594
|
+
}
|
|
595
|
+
|
|
523
596
|
export type GitPanelAction =
|
|
524
597
|
| { type: 'git-refresh-success'; payload: GitRefreshPayload }
|
|
525
598
|
| { type: 'git-refresh-error'; kind: GitPanelError }
|
|
526
599
|
| { type: 'git-panel-reset' }
|
|
600
|
+
| { type: 'set-worktree-divergence'; divergence: Record<string, BranchDivergence> }
|
|
527
601
|
|
|
528
602
|
export type GitModeAction =
|
|
529
603
|
| { type: 'enter-git-mode' }
|
|
@@ -544,6 +618,7 @@ export type GitModeAction =
|
|
|
544
618
|
| { type: 'git-mode-set-message'; message: string | null }
|
|
545
619
|
| { type: 'snippet-picker-set-message'; message: string | null }
|
|
546
620
|
| { type: 'git-mode-toggle-diff-view' }
|
|
621
|
+
| { type: 'git-mode-toggle-review-base' }
|
|
547
622
|
| { type: 'git-mode-shift-head-offset'; delta: number }
|
|
548
623
|
| { type: 'git-mode-set-head-offset'; offset: number }
|
|
549
624
|
| {
|
|
@@ -643,6 +718,14 @@ export type SideEffect =
|
|
|
643
718
|
| { type: 'confirm-update-selection' }
|
|
644
719
|
| { type: 'switch-session-by-index'; index: number }
|
|
645
720
|
| { type: 'delete-session'; sessionId: string }
|
|
721
|
+
| { type: 'delete-worktree'; sessionId: string; worktreeId: string; force?: boolean }
|
|
722
|
+
| {
|
|
723
|
+
type: 'move-worktree'
|
|
724
|
+
sessionId: string
|
|
725
|
+
sourceWorktreeId: string
|
|
726
|
+
targetWorktreeId: string
|
|
727
|
+
deleteSource?: boolean
|
|
728
|
+
}
|
|
646
729
|
| { type: 'toggle-transparent' }
|
|
647
730
|
| { type: 'toggle-mode' }
|
|
648
731
|
| { type: 'open-file-in-editor'; path: string }
|
|
@@ -788,7 +871,9 @@ export type GitPanePathConfig =
|
|
|
788
871
|
| { enabled: false }
|
|
789
872
|
| { enabled: true; pathFn?: (path: string) => string }
|
|
790
873
|
|
|
791
|
-
export
|
|
874
|
+
export interface GitPaneDiffCountConfig {
|
|
875
|
+
enabled: boolean
|
|
876
|
+
}
|
|
792
877
|
|
|
793
878
|
interface GitPaneBaseConfig {
|
|
794
879
|
/** Startup override for git pane visibility. Reapplied on each launch. */
|