@brimveyn/aimux-config 0.6.8 → 0.6.10

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brimveyn/aimux-config",
3
- "version": "0.6.8",
3
+ "version": "0.6.10",
4
4
  "description": "TypeScript configuration API for aimux — keymaps, themes, and backends with a fluent builder.",
5
5
  "keywords": [
6
6
  "aimux",
package/src/actions.ts CHANGED
@@ -195,7 +195,7 @@ export const launchSelectedAssistant: ActionFn = (ctx: ModeContext) => {
195
195
  ctx.state.modal.step === 'worktree' &&
196
196
  ctx.state.modal.createWorktree
197
197
  ) {
198
- return r([{ type: 'enter-new-tab-worktree-create' }])
198
+ return r([{ type: 'enter-new-tab-worktree-create' }], [{ type: 'load-new-tab-base-branches' }])
199
199
  }
200
200
  return r([], [{ type: 'launch-selected-assistant' }])
201
201
  }
@@ -210,19 +210,49 @@ export const deleteSelectedWorktree: ActionFn = (ctx: ModeContext) => {
210
210
  const session = ctx.state.sessions.find((entry) => entry.id === sessionId)
211
211
  const worktree = session?.worktrees?.[modal.selectedIndex]
212
212
  if (!worktree) return null
213
+ // First attempt is never forced — a recoverable failure opens the confirm
214
+ // dialog (see set-new-tab-worktree-delete-prompt), where confirmDeleteWorktree
215
+ // retries with force.
213
216
  return r(
214
- [
215
- { index: modal.selectedIndex, type: 'set-modal-selection-index' },
216
- { message: null, type: 'set-new-tab-worktree-delete-state' },
217
- ],
217
+ [{ index: modal.selectedIndex, type: 'set-modal-selection-index' }],
218
+ [{ force: false, sessionId, type: 'delete-worktree', worktreeId: worktree.id }]
219
+ )
220
+ }
221
+
222
+ export const confirmDeleteWorktree: ActionFn = (ctx: ModeContext) => {
223
+ const modal = ctx.state.modal
224
+ const sessionId = ctx.state.currentSessionId
225
+ if (modal.type !== 'new-tab' || modal.worktreeDeletePrompt == null) return null
226
+ if (!(sessionId != null && sessionId !== '')) return null
227
+ const { worktreeId } = modal.worktreeDeletePrompt
228
+ return r(
229
+ [{ prompt: null, type: 'set-new-tab-worktree-delete-prompt' }],
230
+ [{ force: true, sessionId, type: 'delete-worktree', worktreeId }],
231
+ 'modal.new-tab.command-edit'
232
+ )
233
+ }
234
+
235
+ export const cancelDeleteWorktree: KeyResult = r(
236
+ [{ prompt: null, type: 'set-new-tab-worktree-delete-prompt' }],
237
+ [],
238
+ 'modal.new-tab.command-edit'
239
+ )
240
+
241
+ export const confirmWorktreeDeleteModal: ActionFn = (ctx: ModeContext) => {
242
+ const modal = ctx.state.modal
243
+ if (modal.type !== 'worktree-delete-confirm') return null
244
+ return r(
245
+ [{ type: 'close-modal' }],
218
246
  [
219
247
  {
220
- force: modal.worktreeDeleteConfirmId === worktree.id,
221
- sessionId,
248
+ closeTabs: modal.closeTabs,
249
+ force: modal.force,
250
+ sessionId: modal.sessionId,
222
251
  type: 'delete-worktree',
223
- worktreeId: worktree.id,
252
+ worktreeId: modal.worktreeId,
224
253
  },
225
- ]
254
+ ],
255
+ 'navigation'
226
256
  )
227
257
  }
228
258
 
package/src/defaults.ts CHANGED
@@ -204,6 +204,17 @@ export function getDefaultKeymapConfig(): ResolvedKeymapConfig {
204
204
  .map('<CR>', actions.confirmWorktreeMove, 'Move')
205
205
  )
206
206
 
207
+ // -----------------------------------------------------------------------
208
+ // Modal: standalone worktree delete confirmation (sidebar "Remove worktree")
209
+ // -----------------------------------------------------------------------
210
+ .mode('modal.worktree-delete-confirm', (m) =>
211
+ m
212
+ .map('<Esc>', actions.closeModal, 'Cancel')
213
+ .map('n', actions.closeModal, 'Cancel')
214
+ .map('<CR>', actions.confirmWorktreeDeleteModal, 'Delete worktree')
215
+ .map('y', actions.confirmWorktreeDeleteModal, 'Delete worktree')
216
+ )
217
+
207
218
  // -----------------------------------------------------------------------
208
219
  // Modal: rename-tab
209
220
  // -----------------------------------------------------------------------
@@ -239,6 +250,17 @@ export function getDefaultKeymapConfig(): ResolvedKeymapConfig {
239
250
  .passthrough()
240
251
  )
241
252
 
253
+ // -----------------------------------------------------------------------
254
+ // Modal: new-tab worktree delete confirmation dialog
255
+ // -----------------------------------------------------------------------
256
+ .mode('modal.new-tab.worktree-delete-confirm', (m) =>
257
+ m
258
+ .map('<Esc>', actions.cancelDeleteWorktree, 'Cancel')
259
+ .map('n', actions.cancelDeleteWorktree, 'Cancel')
260
+ .map('<CR>', actions.confirmDeleteWorktree, 'Delete worktree')
261
+ .map('y', actions.confirmDeleteWorktree, 'Delete worktree')
262
+ )
263
+
242
264
  // -----------------------------------------------------------------------
243
265
  // Modal: session-picker (always in filter mode via Picker)
244
266
  // -----------------------------------------------------------------------
package/src/index.ts CHANGED
@@ -87,4 +87,7 @@ export type {
87
87
  StatusBarConfig,
88
88
  StatusBarSeparator,
89
89
  TabSession,
90
+ WorktreeTemplate,
91
+ WorktreeTemplatePane,
92
+ WorktreeTemplateTab,
90
93
  } from './types'
package/src/resolver.ts CHANGED
@@ -48,6 +48,7 @@ export function resolveConfig(userConfig: AimuxUserConfig): ResolvedConfig {
48
48
  snippetTriggerChar: resolveSnippetTriggerChar(userConfig.snippetTriggerChar),
49
49
  statusBar: userConfig.statusBar ?? {},
50
50
  theme: resolveTheme(userConfig.theme),
51
+ worktreeTemplates: userConfig.worktreeTemplates ?? [],
51
52
  }
52
53
  }
53
54
 
package/src/types.ts CHANGED
@@ -14,6 +14,8 @@ export type ModeId =
14
14
  | 'git-mode'
15
15
  | 'modal.new-tab.command-edit'
16
16
  | 'modal.new-tab.editing-command'
17
+ | 'modal.new-tab.worktree-delete-confirm'
18
+ | 'modal.worktree-delete-confirm'
17
19
  | 'modal.session-picker.filtering'
18
20
  | 'modal.session-name'
19
21
  | 'modal.create-session'
@@ -124,6 +126,13 @@ export interface WorkspaceSnapshotV1 {
124
126
  layoutTree?: LayoutNode
125
127
  layoutTrees?: Record<string, LayoutNode>
126
128
  tabGroupMap?: Record<string, string>
129
+ /**
130
+ * Last viewed tab per worktree, keyed by worktree id. Optional and additive
131
+ * (no version bump): older builds ignore it, newer builds tolerate its
132
+ * absence. Written now so the data accrues, but restoring it at startup is
133
+ * gated off until a future change flips RESTORE_LAST_ACTIVE_TAB_BY_WORKTREE.
134
+ */
135
+ lastActiveTabByWorktree?: Record<string, string>
127
136
  }
128
137
 
129
138
  export type WorktreeSource = 'primary' | 'aimux-temp' | 'external'
@@ -289,16 +298,21 @@ export interface ModalClosed extends ModalBase {
289
298
  export interface ModalNewTab extends ModalBase {
290
299
  type: 'new-tab'
291
300
  editingCommand: AssistantId | null
292
- activeField: 'assistant' | 'branch-name' | 'target-worktree' | 'worktree-name'
301
+ activeField: 'assistant' | 'branch-name' | 'target-worktree' | 'worktree-name' | 'base'
293
302
  branchError: string | null
294
303
  branchName: string
295
304
  createWorktree: boolean
296
305
  selectedAssistantId: AssistantId | null
297
- step: 'assistant' | 'worktree' | 'worktree-create'
306
+ step: 'assistant' | 'worktree' | 'worktree-create' | 'template'
298
307
  targetWorktreeIndex: number
299
- worktreeDeleteConfirmId: string | null
300
- worktreeDeleteMessage: string | null
308
+ worktreeDeletePrompt: { worktreeId: string; reason: string } | null
301
309
  worktreeName: string
310
+ /** Filter text typed into the "Base" picker on the worktree-create step. */
311
+ baseQuery: string
312
+ /** Resolved base ref the new worktree is forked from (branch of a worktree or a local branch). */
313
+ baseRef: string
314
+ /** Local branches available as base refs, loaded when the create step opens. */
315
+ baseBranches: string[]
302
316
  }
303
317
  export interface ModalSessionPicker extends ModalBase {
304
318
  type: 'session-picker'
@@ -366,6 +380,22 @@ export interface ModalWorktreeMove extends ModalBase {
366
380
  deleteSource: boolean
367
381
  }
368
382
 
383
+ /**
384
+ * Standalone confirmation for a recoverable worktree delete failure triggered
385
+ * outside the new-tab picker (e.g. the sidebar's "Remove worktree"). Carries the
386
+ * params needed to re-run the delete with force once confirmed.
387
+ */
388
+ export interface ModalWorktreeDeleteConfirm extends ModalBase {
389
+ type: 'worktree-delete-confirm'
390
+ sessionId: string
391
+ worktreeId: string
392
+ worktreeLabel: string
393
+ reason: string
394
+ closeTabs: boolean
395
+ /** Whether confirming force-deletes — true only after a recoverable failure. */
396
+ force: boolean
397
+ }
398
+
369
399
  export type ModalState =
370
400
  | ModalClosed
371
401
  | ModalNewTab
@@ -382,6 +412,7 @@ export type ModalState =
382
412
  | ModalUpdateAvailable
383
413
  | ModalAIUsage
384
414
  | ModalWorktreeMove
415
+ | ModalWorktreeDeleteConfirm
385
416
 
386
417
  export interface LayoutState {
387
418
  terminalCols: number
@@ -446,7 +477,9 @@ export interface AppState {
446
477
  autoCommit: AutoCommitState
447
478
  multiRepo: MultiRepoState
448
479
  worktreeDivergence: Record<string, BranchDivergence>
480
+ lastActiveTabByWorktree: Record<string, string>
449
481
  pendingChords: string[] | null
482
+ worktreeTemplates: WorktreeTemplate[]
450
483
  }
451
484
 
452
485
  // ─── AppAction union ──────────────────────────────────────────────────────────
@@ -455,11 +488,13 @@ export type ModalAction =
455
488
  | { type: 'open-new-tab-modal' }
456
489
  | { type: 'set-new-tab-branch-error'; message: string | null }
457
490
  | {
458
- type: 'set-new-tab-worktree-delete-state'
459
- confirmWorktreeId?: string | null
460
- message: string | null
491
+ type: 'set-new-tab-worktree-delete-prompt'
492
+ prompt: { worktreeId: string; reason: string } | null
461
493
  }
494
+ | { type: 'set-new-tab-base-branches'; branches: string[] }
462
495
  | { type: 'enter-new-tab-worktree-create' }
496
+ | { type: 'enter-new-tab-template-pick' }
497
+ | { type: 'enter-new-tab-template-shortcut' }
463
498
  | { type: 'select-new-tab-assistant'; assistantId?: AssistantId }
464
499
  | { type: 'toggle-new-tab-worktree'; assistantId?: AssistantId }
465
500
  | { type: 'open-help-modal'; scope?: ModeId }
@@ -491,6 +526,15 @@ export type ModalAction =
491
526
  | { type: 'open-edit-custom-command'; assistantId: AssistantId }
492
527
  | { type: 'open-worktree-move-modal'; sourceWorktreeId: string }
493
528
  | { type: 'toggle-worktree-move-delete' }
529
+ | {
530
+ type: 'open-worktree-delete-confirm'
531
+ sessionId: string
532
+ worktreeId: string
533
+ worktreeLabel: string
534
+ reason: string
535
+ closeTabs: boolean
536
+ force: boolean
537
+ }
494
538
 
495
539
  export type SessionAction =
496
540
  | { type: 'load-session'; sessionId: string; workspaceSnapshot?: WorkspaceSnapshotV1 }
@@ -502,7 +546,6 @@ export type SessionAction =
502
546
  | { type: 'reorder-active-session'; delta: number }
503
547
  | { type: 'set-session-status'; sessionId: string; status: SessionStatus }
504
548
  | { type: 'add-worktree-record'; sessionId: string; worktree: WorktreeRecord; activate?: boolean }
505
- | { type: 'remove-worktree-record'; sessionId: string; worktreeId: string }
506
549
  | { type: 'set-active-worktree'; sessionId: string; worktreeId: string }
507
550
  | {
508
551
  type: 'update-worktree-record'
@@ -590,6 +633,26 @@ export interface BranchDivergence {
590
633
  behind: number
591
634
  }
592
635
 
636
+ export interface WorktreeTemplatePane {
637
+ id: string
638
+ assistant: string
639
+ splitFrom?: string
640
+ direction?: SplitDirection
641
+ ratio?: number
642
+ send?: string
643
+ }
644
+
645
+ export interface WorktreeTemplateTab {
646
+ panes: WorktreeTemplatePane[]
647
+ }
648
+
649
+ export interface WorktreeTemplate {
650
+ id: string
651
+ name: string
652
+ description?: string
653
+ tabs: WorktreeTemplateTab[]
654
+ }
655
+
593
656
  export type GitPanelAction =
594
657
  | { type: 'git-refresh-success'; payload: GitRefreshPayload }
595
658
  | { type: 'git-refresh-error'; kind: GitPanelError }
@@ -678,6 +741,7 @@ export type AppAction =
678
741
  export type SideEffect =
679
742
  | { type: 'quit'; state: AppState }
680
743
  | { type: 'launch-selected-assistant' }
744
+ | { type: 'load-new-tab-base-branches' }
681
745
  | { type: 'edit-selected-assistant' }
682
746
  | { type: 'confirm-selected-session' }
683
747
  | { type: 'delete-selected-session' }
@@ -717,7 +781,18 @@ export type SideEffect =
717
781
  | { type: 'cycle-sidebar-item'; direction: 1 | -1 }
718
782
  | { type: 'switch-tab-by-index'; index: number }
719
783
  | { type: 'delete-session'; sessionId: string }
720
- | { type: 'delete-worktree'; sessionId: string; worktreeId: string; force?: boolean }
784
+ | {
785
+ type: 'delete-worktree'
786
+ sessionId: string
787
+ worktreeId: string
788
+ // Force the git worktree removal (discards uncommitted changes in the
789
+ // worktree). Also implies closing the worktree's tabs.
790
+ force?: boolean
791
+ // Close the worktree's tabs without forcing the git removal. Lets the
792
+ // sidebar "Remove worktree" clean up tabs (avoiding orphans) while still
793
+ // refusing to discard uncommitted work in a temp worktree.
794
+ closeTabs?: boolean
795
+ }
721
796
  | {
722
797
  type: 'move-worktree'
723
798
  sessionId: string
@@ -1038,6 +1113,11 @@ export interface AimuxUserConfig {
1038
1113
  statusBar?: StatusBarConfig
1039
1114
  externalEditor?: ExternalEditorConfig
1040
1115
  integrations?: AimuxIntegrationsConfig
1116
+ /**
1117
+ * Worktree templates: layouts (multi-pane + initial commands) applied at
1118
+ * worktree creation. Selected from a picker in the new-tab modal.
1119
+ */
1120
+ worktreeTemplates?: WorktreeTemplate[]
1041
1121
  }
1042
1122
 
1043
1123
  // ─── Resolved config (internal) ───────────────────────────────────────────────
@@ -1114,4 +1194,5 @@ export interface ResolvedConfig {
1114
1194
  integrations: {
1115
1195
  claudeHooks: boolean
1116
1196
  }
1197
+ worktreeTemplates: WorktreeTemplate[]
1117
1198
  }