@brimveyn/aimux-config 0.10.8 → 0.11.0
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 +1 -1
- package/src/app-types.ts +1467 -0
- package/src/index.ts +24 -13
- package/src/keymap-builder.ts +6 -0
- package/src/plugin-actions-runtime.ts +50 -0
- package/src/resolver.ts +22 -0
- package/src/settings-types.ts +160 -0
- package/src/tui/index.ts +11 -1
- package/src/tui/registry.ts +46 -3
- package/src/types.ts +95 -994
package/src/types.ts
CHANGED
|
@@ -1,119 +1,58 @@
|
|
|
1
1
|
// -----------------------------------------------------------------------------
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// `
|
|
2
|
+
// The aimux keymap/config surface: everything a user's `aimux.config.ts` and a
|
|
3
|
+
// plugin author write against.
|
|
4
|
+
//
|
|
5
|
+
// The application state, mode and layout shapes it builds on live in
|
|
6
|
+
// `./app-types` and are re-exported here, so this module stays the one import
|
|
7
|
+
// a config file needs. Both halves are SOURCE definitions — `src/` re-exports
|
|
8
|
+
// from this package rather than declaring its own copies, which is what makes
|
|
9
|
+
// the two impossible to drift apart.
|
|
7
10
|
// -----------------------------------------------------------------------------
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
export type * from './app-types'
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
| 'modal.project-name'
|
|
20
|
-
| 'modal.create-project'
|
|
21
|
-
| 'modal.create-workspace'
|
|
22
|
-
| 'modal.rename-tab'
|
|
23
|
-
| 'modal.rename-workspace'
|
|
24
|
-
| 'modal.setting-text'
|
|
25
|
-
| 'modal.settings-search.filtering'
|
|
26
|
-
| 'modal.snippet-picker.filtering'
|
|
27
|
-
| 'modal.snippet-editor'
|
|
28
|
-
| 'modal.theme-picker.filtering'
|
|
29
|
-
| 'modal.help.filtering'
|
|
30
|
-
| 'modal.split-picker'
|
|
31
|
-
| 'modal.git-commit'
|
|
32
|
-
| 'modal.git-commit.confirm'
|
|
33
|
-
| 'modal.git-commit.generating'
|
|
34
|
-
| 'modal.update-available'
|
|
35
|
-
| 'modal.workspace-move'
|
|
36
|
-
| 'modal.workspace-move-confirm'
|
|
37
|
-
| 'modal.flash-jump'
|
|
38
|
-
| 'modal.quotas'
|
|
39
|
-
| 'settings'
|
|
40
|
-
| 'stats'
|
|
14
|
+
import type {
|
|
15
|
+
GitFileListMode,
|
|
16
|
+
GitPaneDiffCountConfig,
|
|
17
|
+
GitPanePathConfig,
|
|
18
|
+
KeyResult,
|
|
19
|
+
ModeContext,
|
|
20
|
+
ModeId,
|
|
21
|
+
} from './app-types'
|
|
41
22
|
|
|
42
|
-
// ───
|
|
23
|
+
// ─── Mode identifiers ─────────────────────────────────────────────────────────
|
|
43
24
|
|
|
44
|
-
|
|
45
|
-
| 'claude'
|
|
46
|
-
| 'codex'
|
|
47
|
-
| 'opencode'
|
|
48
|
-
| 'grok'
|
|
49
|
-
| 'kimi'
|
|
50
|
-
| 'terminal'
|
|
51
|
-
| 'antigravity'
|
|
52
|
-
export type AssistantId = BuiltinAssistantId | (string & {})
|
|
53
|
-
export type TabStatus = 'starting' | 'running' | 'disconnected' | 'error'
|
|
25
|
+
// ─── Primitive app types ──────────────────────────────────────────────────────
|
|
54
26
|
|
|
55
|
-
/**
|
|
56
|
-
* Status values that may appear in legacy on-disk project snapshots but are
|
|
57
|
-
* not produced by the running app anymore.
|
|
58
|
-
*/
|
|
59
|
-
export type LegacyPersistedTabStatus = TabStatus | 'exited'
|
|
60
|
-
export type TabActivity = 'working' | 'waiting-input' | 'idle'
|
|
61
|
-
export interface ProjectStatus {
|
|
62
|
-
working: boolean
|
|
63
|
-
waiting: boolean
|
|
64
|
-
}
|
|
65
|
-
export interface WorkspaceActivity {
|
|
66
|
-
working: boolean
|
|
67
|
-
waiting: boolean
|
|
68
|
-
done: boolean
|
|
69
|
-
}
|
|
70
|
-
export type FocusMode =
|
|
71
|
-
| 'navigation'
|
|
72
|
-
| 'terminal-input'
|
|
73
|
-
| 'modal'
|
|
74
|
-
| 'command-edit'
|
|
75
|
-
| 'git'
|
|
76
|
-
| 'settings'
|
|
77
|
-
| 'stats'
|
|
78
27
|
export type SplitDirection = 'horizontal' | 'vertical'
|
|
79
28
|
|
|
80
29
|
// ─── Terminal data shapes ─────────────────────────────────────────────────────
|
|
81
30
|
|
|
82
|
-
export interface TerminalSpan {
|
|
83
|
-
text: string
|
|
84
|
-
fg?: string
|
|
85
|
-
bg?: string
|
|
86
|
-
bold?: boolean
|
|
87
|
-
italic?: boolean
|
|
88
|
-
underline?: boolean
|
|
89
|
-
cursor?: boolean
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export interface TerminalLine {
|
|
93
|
-
spans: TerminalSpan[]
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
export interface TerminalSnapshot {
|
|
97
|
-
lines: TerminalLine[]
|
|
98
|
-
tailLines?: TerminalLine[]
|
|
99
|
-
viewportY: number
|
|
100
|
-
baseY: number
|
|
101
|
-
cursorVisible: boolean
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export interface TerminalModeState {
|
|
105
|
-
mouseTrackingMode: 'none' | 'x10' | 'vt200' | 'drag' | 'any'
|
|
106
|
-
sendFocusMode: boolean
|
|
107
|
-
alternateScrollMode: boolean
|
|
108
|
-
isAlternateBuffer: boolean
|
|
109
|
-
bracketedPasteMode: boolean
|
|
110
|
-
}
|
|
111
|
-
|
|
112
31
|
// ─── Layout ───────────────────────────────────────────────────────────────────
|
|
113
32
|
|
|
33
|
+
/**
|
|
34
|
+
* What occupies a pane. `tab` is a terminal; `plugin` is a renderer a plugin
|
|
35
|
+
* registered, and has no PTY behind it.
|
|
36
|
+
*/
|
|
37
|
+
export type LayoutLeafKind = 'tab' | 'plugin'
|
|
38
|
+
|
|
114
39
|
export interface LayoutLeaf {
|
|
115
40
|
type: 'leaf'
|
|
41
|
+
/**
|
|
42
|
+
* The tab id — or, when `kind` is `'plugin'`, the qualified pane id
|
|
43
|
+
* (`<pluginId>.<paneId>`).
|
|
44
|
+
*
|
|
45
|
+
* Still called `tabId` because it is the key in every layout ever written to
|
|
46
|
+
* `aimux.json`, and a rename would be a migration for the sake of a name.
|
|
47
|
+
* Code that means "whatever is in this pane" should say so by using
|
|
48
|
+
* `allPaneIds`; code that means "a terminal" uses `allTabIds`.
|
|
49
|
+
*/
|
|
116
50
|
tabId: string
|
|
51
|
+
/**
|
|
52
|
+
* Absent means `'tab'`. Every persisted layout omits it, and every pane that
|
|
53
|
+
* existed before plugins could hold one is a terminal.
|
|
54
|
+
*/
|
|
55
|
+
kind?: LayoutLeafKind
|
|
117
56
|
}
|
|
118
57
|
export interface LayoutSplit {
|
|
119
58
|
type: 'split'
|
|
@@ -124,895 +63,10 @@ export interface LayoutSplit {
|
|
|
124
63
|
}
|
|
125
64
|
export type LayoutNode = LayoutLeaf | LayoutSplit
|
|
126
65
|
|
|
127
|
-
// ─── Records ──────────────────────────────────────────────────────────────────
|
|
128
|
-
|
|
129
|
-
export interface PersistedTabSnapshot {
|
|
130
|
-
id: string
|
|
131
|
-
assistant: AssistantId
|
|
132
|
-
title: string
|
|
133
|
-
command: string
|
|
134
|
-
status: Exclude<LegacyPersistedTabStatus, 'disconnected'>
|
|
135
|
-
buffer: string
|
|
136
|
-
viewport?: TerminalSnapshot
|
|
137
|
-
terminalModes: TerminalModeState
|
|
138
|
-
errorMessage?: string
|
|
139
|
-
exitCode?: number
|
|
140
|
-
workspaceId?: string
|
|
141
|
-
autoRenameStatus?: 'eligible' | 'attempted'
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export interface ProjectSnapshotV1 {
|
|
145
|
-
version: 1
|
|
146
|
-
savedAt: string
|
|
147
|
-
activeTabId: string | null
|
|
148
|
-
sidebar: {
|
|
149
|
-
visible: boolean
|
|
150
|
-
width: number
|
|
151
|
-
}
|
|
152
|
-
tabs: PersistedTabSnapshot[]
|
|
153
|
-
layoutTree?: LayoutNode
|
|
154
|
-
layoutTrees?: Record<string, LayoutNode>
|
|
155
|
-
tabGroupMap?: Record<string, string>
|
|
156
|
-
/**
|
|
157
|
-
* Last viewed tab per workspace, keyed by workspace id. Optional and additive
|
|
158
|
-
* (no version bump): older builds ignore it, newer builds tolerate its
|
|
159
|
-
* absence. Written now so the data accrues, but restoring it at startup is
|
|
160
|
-
* gated off until a future change flips RESTORE_LAST_ACTIVE_TAB_BY_WORKSPACE.
|
|
161
|
-
*/
|
|
162
|
-
lastActiveTabByWorkspace?: Record<string, string>
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export type WorkspaceSource = 'primary' | 'aimux-temp' | 'external'
|
|
166
|
-
|
|
167
|
-
export interface WorkspaceRecord {
|
|
168
|
-
id: string
|
|
169
|
-
name: string
|
|
170
|
-
path: string
|
|
171
|
-
repoRoot: string
|
|
172
|
-
branch?: string
|
|
173
|
-
baseRef?: string
|
|
174
|
-
commitSha?: string
|
|
175
|
-
source: WorkspaceSource
|
|
176
|
-
createdByAimux: boolean
|
|
177
|
-
color?: string
|
|
178
|
-
createdAt: string
|
|
179
|
-
updatedAt: string
|
|
180
|
-
/** Last setup-script run for this workspace. Display only — the auto-run gate
|
|
181
|
-
* is "this session has not seen this workspace id before". */
|
|
182
|
-
setupRanAt?: string
|
|
183
|
-
setupExitCode?: number
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export interface ProjectRecord {
|
|
187
|
-
id: string
|
|
188
|
-
name: string
|
|
189
|
-
projectPath?: string
|
|
190
|
-
createdAt: string
|
|
191
|
-
updatedAt: string
|
|
192
|
-
lastOpenedAt: string
|
|
193
|
-
order?: number
|
|
194
|
-
projectSnapshot?: ProjectSnapshotV1
|
|
195
|
-
workspaces?: WorkspaceRecord[]
|
|
196
|
-
activeWorkspaceId?: string
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export interface TabSession {
|
|
200
|
-
id: string
|
|
201
|
-
assistant: AssistantId
|
|
202
|
-
title: string
|
|
203
|
-
status: TabStatus
|
|
204
|
-
activity?: TabActivity
|
|
205
|
-
buffer: string
|
|
206
|
-
viewport?: TerminalSnapshot
|
|
207
|
-
terminalModes: TerminalModeState
|
|
208
|
-
command: string
|
|
209
|
-
errorMessage?: string
|
|
210
|
-
exitCode?: number
|
|
211
|
-
workspaceId?: string
|
|
212
|
-
/** This tab finished a turn while you were elsewhere. See `src/state/types.ts`. */
|
|
213
|
-
unseen?: boolean
|
|
214
|
-
autoRenameStatus?: 'eligible' | 'attempted'
|
|
215
|
-
/** Real PTY tab that no chrome enumerates. See `src/state/types.ts`. */
|
|
216
|
-
hidden?: boolean
|
|
217
|
-
/** Who owns this tab, independent of visibility. See `src/state/types.ts`. */
|
|
218
|
-
role?: 'setup'
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export interface SnippetRecord {
|
|
222
|
-
id: string
|
|
223
|
-
name: string
|
|
224
|
-
content: string
|
|
225
|
-
trigger?: string
|
|
226
|
-
vars?: Record<string, SnippetVar>
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
export type DirectoryResultType = 'git-repo' | 'workspace' | 'project'
|
|
230
|
-
|
|
231
|
-
export interface DirectoryResult {
|
|
232
|
-
path: string
|
|
233
|
-
type: DirectoryResultType
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// ─── Bars / git panel / modal state (for ModeContext) ─────────────────────────
|
|
237
|
-
|
|
238
|
-
export type BarSide = 'left' | 'right'
|
|
239
|
-
|
|
240
|
-
export interface BarWidget {
|
|
241
|
-
id: string
|
|
242
|
-
grow: number
|
|
243
|
-
visible: boolean
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
export interface BarState {
|
|
247
|
-
visible: boolean
|
|
248
|
-
width: number
|
|
249
|
-
/** Ordered top → bottom. */
|
|
250
|
-
widgets: BarWidget[]
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export type BarsState = Record<BarSide, BarState>
|
|
254
|
-
|
|
255
|
-
export interface GitPaneState {
|
|
256
|
-
diffModeRatio: number
|
|
257
|
-
fileListMode: GitFileListMode
|
|
258
|
-
treeCompaction: boolean
|
|
259
|
-
path: GitPanePathConfig
|
|
260
|
-
diffCount: GitPaneDiffCountConfig
|
|
261
|
-
prefetchRadius: number
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export type GitFileStatus = 'M' | 'A' | 'D' | 'R' | 'C' | 'U' | '?'
|
|
265
|
-
export type GitFileSection = 'staged' | 'unstaged' | 'untracked' | 'historical'
|
|
266
|
-
|
|
267
|
-
export interface GitFileEntry {
|
|
268
|
-
path: string
|
|
269
|
-
renamedFrom?: string
|
|
270
|
-
section: GitFileSection
|
|
271
|
-
status: GitFileStatus
|
|
272
|
-
added: number | null
|
|
273
|
-
removed: number | null
|
|
274
|
-
repoPath?: string
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
export type GitPanelError = 'not-a-repo' | 'unknown'
|
|
278
|
-
|
|
279
|
-
export interface GitPanelState {
|
|
280
|
-
branch: string | null
|
|
281
|
-
ahead: number
|
|
282
|
-
behind: number
|
|
283
|
-
files: GitFileEntry[]
|
|
284
|
-
error: GitPanelError | null
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
export type DiffFileStatus =
|
|
288
|
-
| 'modified'
|
|
289
|
-
| 'new'
|
|
290
|
-
| 'deleted'
|
|
291
|
-
| 'binary'
|
|
292
|
-
| 'renamed'
|
|
293
|
-
| 'image'
|
|
294
|
-
| 'too-large'
|
|
295
|
-
|
|
296
|
-
export interface DiffData {
|
|
297
|
-
path: string
|
|
298
|
-
status: DiffFileStatus
|
|
299
|
-
oldPath?: string
|
|
300
|
-
rawDiff: string
|
|
301
|
-
binarySizeBefore?: number
|
|
302
|
-
binarySizeAfter?: number
|
|
303
|
-
errorMessage?: string
|
|
304
|
-
imageBytesBefore?: Uint8Array
|
|
305
|
-
imageBytesAfter?: Uint8Array
|
|
306
|
-
imageMime?: string
|
|
307
|
-
imageFormatLabel?: string
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
export type GitDiffView = 'split' | 'stacked'
|
|
311
|
-
export type GitFileListMode = 'tree' | 'flat'
|
|
312
|
-
|
|
313
|
-
export interface FoldState {
|
|
314
|
-
top: number
|
|
315
|
-
bottom: number
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
export interface GitModeState {
|
|
319
|
-
selectedEntryKey: string | null
|
|
320
|
-
collapsedFolders: Record<string, true>
|
|
321
|
-
diffs: Record<string, DiffData>
|
|
322
|
-
/** Parsed diff cache (internal); detailed shape lives in src/state/types. */
|
|
323
|
-
parsedFiles: Record<string, { hash: string; file: unknown }>
|
|
324
|
-
/** Syntax-highlight cache (internal). */
|
|
325
|
-
highlights: Record<string, { hash: string; themeId: string; add: unknown; del: unknown }>
|
|
326
|
-
loading: Record<string, boolean>
|
|
327
|
-
pendingDeletePath: string | null
|
|
328
|
-
actionMessage: string | null
|
|
329
|
-
diffView: GitDiffView
|
|
330
|
-
folds: Record<string, Record<string, FoldState>>
|
|
331
|
-
headOffset: number
|
|
332
|
-
reviewBase: boolean
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
interface ModalBase {
|
|
336
|
-
selectedIndex: number
|
|
337
|
-
editBuffer: string | null
|
|
338
|
-
projectTargetId: string | null
|
|
339
|
-
cursorPos?: number
|
|
340
|
-
/**
|
|
341
|
-
* Where the focus goes when this modal closes, when it is not back to the
|
|
342
|
-
* panes. Set by whoever opened it, because that is who knows what is behind it
|
|
343
|
-
* — the settings screen opens five different modals, and none of them should
|
|
344
|
-
* have to grow a case in the reducer to find their way home.
|
|
345
|
-
*/
|
|
346
|
-
returnTo?: FocusMode
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
export interface ModalClosed extends ModalBase {
|
|
350
|
-
type: null
|
|
351
|
-
editBuffer: null
|
|
352
|
-
projectTargetId: null
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
export interface ModalNewTab extends ModalBase {
|
|
356
|
-
type: 'new-tab'
|
|
357
|
-
editingCommand: AssistantId | null
|
|
358
|
-
/** Set when `create-workspace` chained into this picker. */
|
|
359
|
-
pendingWorkspace?: PendingWorkspaceLaunch
|
|
360
|
-
/** A prompt for the picked assistant, without the workspace pinning/rename. */
|
|
361
|
-
pendingPrompt?: string
|
|
362
|
-
}
|
|
363
|
-
export interface PendingWorkspaceLaunch {
|
|
364
|
-
projectId: string
|
|
365
|
-
workspaceId: string
|
|
366
|
-
prompt: string
|
|
367
|
-
}
|
|
368
|
-
export interface ModalProjectPicker extends ModalBase {
|
|
369
|
-
type: 'project-picker'
|
|
370
|
-
}
|
|
371
|
-
export interface ModalProjectName extends ModalBase {
|
|
372
|
-
type: 'project-name'
|
|
373
|
-
returnToProjectPicker: boolean
|
|
374
|
-
}
|
|
375
|
-
export interface ModalRenameTab extends ModalBase {
|
|
376
|
-
type: 'rename-tab'
|
|
377
|
-
}
|
|
378
|
-
/** Fuzzy-ish search across every setting, from inside the settings screen. */
|
|
379
|
-
export interface ModalSettingsSearch extends ModalBase {
|
|
380
|
-
type: 'settings-search'
|
|
381
|
-
}
|
|
382
|
-
export interface ModalSettingText extends ModalBase {
|
|
383
|
-
type: 'setting-text'
|
|
384
|
-
settingId: string
|
|
385
|
-
settingLabel: string
|
|
386
|
-
}
|
|
387
|
-
export interface ModalRenameWorkspace extends ModalBase {
|
|
388
|
-
type: 'rename-workspace'
|
|
389
|
-
workspaceProjectId: string
|
|
390
|
-
}
|
|
391
|
-
export interface ModalSnippetPicker extends ModalBase {
|
|
392
|
-
type: 'snippet-picker'
|
|
393
|
-
actionMessage?: string | null
|
|
394
|
-
}
|
|
395
|
-
export interface ModalThemePicker extends ModalBase {
|
|
396
|
-
type: 'theme-picker'
|
|
397
|
-
entryCount: number
|
|
398
|
-
}
|
|
399
|
-
export interface ModalHelp extends ModalBase {
|
|
400
|
-
type: 'help'
|
|
401
|
-
entryCount: number
|
|
402
|
-
scope: ModeId | null
|
|
403
|
-
}
|
|
404
|
-
export interface ModalSplitPicker extends ModalBase {
|
|
405
|
-
type: 'split-picker'
|
|
406
|
-
splitDirection: SplitDirection
|
|
407
|
-
}
|
|
408
|
-
export interface ModalCreateProject extends ModalBase {
|
|
409
|
-
type: 'create-project'
|
|
410
|
-
directoryResults: DirectoryResult[]
|
|
411
|
-
pendingProjectPath: string | null
|
|
412
|
-
activeField: 'directory' | 'name'
|
|
413
|
-
nameBuffer: string
|
|
414
|
-
returnToProjectPicker: boolean
|
|
415
|
-
}
|
|
416
|
-
export interface ModalCreateWorkspace extends ModalBase {
|
|
417
|
-
type: 'create-workspace'
|
|
418
|
-
activeField: 'prompt' | 'base'
|
|
419
|
-
/** "What do you want to work on?" — names the workspace and its branch. */
|
|
420
|
-
prompt: string
|
|
421
|
-
branchError: string | null
|
|
422
|
-
baseQuery: string
|
|
423
|
-
baseRef: string
|
|
424
|
-
baseBranches: string[]
|
|
425
|
-
}
|
|
426
|
-
export interface ModalGitCommit extends ModalBase {
|
|
427
|
-
type: 'git-commit'
|
|
428
|
-
activeField: 'title' | 'body'
|
|
429
|
-
contentBuffer: string
|
|
430
|
-
stage: 'edit' | 'generating' | 'confirm'
|
|
431
|
-
}
|
|
432
|
-
export interface ModalSnippetEditor extends ModalBase {
|
|
433
|
-
type: 'snippet-editor'
|
|
434
|
-
activeField: 'name' | 'trigger' | 'content'
|
|
435
|
-
nameBuffer: string
|
|
436
|
-
triggerBuffer: string
|
|
437
|
-
contentBuffer: string
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
export interface ModalUpdateAvailable extends ModalBase {
|
|
441
|
-
type: 'update-available'
|
|
442
|
-
currentVersion: string
|
|
443
|
-
latestVersion: string
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/** The status bar's usage indicator, expanded. Carries nothing: it is a readout. */
|
|
447
|
-
export interface ModalQuotas extends ModalBase {
|
|
448
|
-
type: 'quotas'
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
export interface ModalWorkspaceMove extends ModalBase {
|
|
452
|
-
type: 'workspace-move'
|
|
453
|
-
/** The workspace being moved (may differ from the active one, e.g. a tab menu). */
|
|
454
|
-
sourceWorkspaceId: string
|
|
455
|
-
deleteSource: boolean
|
|
456
|
-
/** Per-workspace dirty file counts, loaded async when the modal opens. */
|
|
457
|
-
stats: { kind: 'loading' } | { kind: 'ready'; dirtyFiles: Record<string, number> }
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
/**
|
|
461
|
-
* Confirmation for a recoverable move failure: the target's dirty files
|
|
462
|
-
* overlap the incoming changes (stash-target) or the squash conflicts
|
|
463
|
-
* (keep-conflicts). Both workspaces are already restored; confirming re-runs
|
|
464
|
-
* move-workspace with the matching flag.
|
|
465
|
-
*/
|
|
466
|
-
export interface ModalWorkspaceMoveConfirm extends ModalBase {
|
|
467
|
-
type: 'workspace-move-confirm'
|
|
468
|
-
variant: 'stash-target' | 'keep-conflicts'
|
|
469
|
-
files: string[]
|
|
470
|
-
projectId: string
|
|
471
|
-
sourceWorkspaceId: string
|
|
472
|
-
targetWorkspaceId: string
|
|
473
|
-
deleteSource: boolean
|
|
474
|
-
sourceLabel: string
|
|
475
|
-
targetLabel: string
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
/**
|
|
479
|
-
* Standalone confirmation for a recoverable workspace delete failure triggered
|
|
480
|
-
* outside the new-tab picker (e.g. the sidebar's "Remove workspace"). Carries the
|
|
481
|
-
* params needed to re-run the delete with force once confirmed.
|
|
482
|
-
*/
|
|
483
|
-
export interface ModalWorkspaceDeleteConfirm extends ModalBase {
|
|
484
|
-
type: 'workspace-delete-confirm'
|
|
485
|
-
projectId: string
|
|
486
|
-
workspaceId: string
|
|
487
|
-
workspaceLabel: string
|
|
488
|
-
reason: string
|
|
489
|
-
closeTabs: boolean
|
|
490
|
-
/** Whether confirming force-deletes — true only after a recoverable failure. */
|
|
491
|
-
force: boolean
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
export type FlashJumpTargetKind = 'project' | 'workspace' | 'tab'
|
|
495
|
-
|
|
496
|
-
export interface FlashJumpTarget {
|
|
497
|
-
kind: FlashJumpTargetKind
|
|
498
|
-
projectIndex: number
|
|
499
|
-
projectId: string
|
|
500
|
-
workspaceId?: string
|
|
501
|
-
tabId?: string
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
export interface FlashLabel {
|
|
505
|
-
key: string
|
|
506
|
-
label: string
|
|
507
|
-
target: FlashJumpTarget
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
export interface ModalFlashJump extends ModalBase {
|
|
511
|
-
type: 'flash-jump'
|
|
512
|
-
labels: FlashLabel[]
|
|
513
|
-
buffer: string
|
|
514
|
-
pendingJump: FlashJumpTarget | null
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
export type ModalState =
|
|
518
|
-
| ModalClosed
|
|
519
|
-
| ModalNewTab
|
|
520
|
-
| ModalProjectPicker
|
|
521
|
-
| ModalProjectName
|
|
522
|
-
| ModalRenameTab
|
|
523
|
-
| ModalRenameWorkspace
|
|
524
|
-
| ModalSnippetPicker
|
|
525
|
-
| ModalThemePicker
|
|
526
|
-
| ModalHelp
|
|
527
|
-
| ModalSplitPicker
|
|
528
|
-
| ModalCreateProject
|
|
529
|
-
| ModalCreateWorkspace
|
|
530
|
-
| ModalSnippetEditor
|
|
531
|
-
| ModalGitCommit
|
|
532
|
-
| ModalUpdateAvailable
|
|
533
|
-
| ModalQuotas
|
|
534
|
-
| ModalWorkspaceMove
|
|
535
|
-
| ModalWorkspaceMoveConfirm
|
|
536
|
-
| ModalWorkspaceDeleteConfirm
|
|
537
|
-
| ModalFlashJump
|
|
538
|
-
| ModalSettingText
|
|
539
|
-
| ModalSettingsSearch
|
|
540
|
-
|
|
541
|
-
export interface LayoutState {
|
|
542
|
-
terminalCols: number
|
|
543
|
-
terminalRows: number
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
export interface ProjectBarState {
|
|
547
|
-
visible: boolean
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
export type AutoCommitSuggestion =
|
|
551
|
-
| { kind: 'idle' }
|
|
552
|
-
| {
|
|
553
|
-
kind: 'generating'
|
|
554
|
-
tabId: string
|
|
555
|
-
workingTreeHash: string
|
|
556
|
-
abortController: AbortController
|
|
557
|
-
startedAt: number
|
|
558
|
-
}
|
|
559
|
-
| {
|
|
560
|
-
kind: 'ready'
|
|
561
|
-
tabId: string
|
|
562
|
-
workingTreeHash: string
|
|
563
|
-
title: string
|
|
564
|
-
body: string
|
|
565
|
-
generatedAt: number
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
export interface AutoCommitState {
|
|
569
|
-
byProject: Record<string, AutoCommitSuggestion>
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
export interface DiscoveredRepo {
|
|
573
|
-
path: string
|
|
574
|
-
name: string
|
|
575
|
-
isRoot: boolean
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
export interface MultiRepoState {
|
|
579
|
-
repos: DiscoveredRepo[]
|
|
580
|
-
prefixes: Record<string, string>
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
/** Where the cursor is in the settings screen — the cursor only, not the values. */
|
|
584
|
-
export interface SettingsUIState {
|
|
585
|
-
rowIndex: number
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
/** Mirror of the CLI's `StatsUIState`. */
|
|
589
|
-
export interface StatsUIState {
|
|
590
|
-
pageIndex: number
|
|
591
|
-
scrollTop: number
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
export interface AppState {
|
|
595
|
-
tabs: TabSession[]
|
|
596
|
-
activeTabId: string | null
|
|
597
|
-
layoutTrees: Record<string, LayoutNode>
|
|
598
|
-
tabGroupMap: Record<string, string>
|
|
599
|
-
projects: ProjectRecord[]
|
|
600
|
-
currentProjectId: string | null
|
|
601
|
-
projectStatuses: Record<string, ProjectStatus>
|
|
602
|
-
projectBar: ProjectBarState
|
|
603
|
-
snippets: SnippetRecord[]
|
|
604
|
-
focusMode: FocusMode
|
|
605
|
-
bars: BarsState
|
|
606
|
-
gitPane: GitPaneState
|
|
607
|
-
modal: ModalState
|
|
608
|
-
layout: LayoutState
|
|
609
|
-
customCommands: Record<AssistantId, string>
|
|
610
|
-
gitPanel: GitPanelState
|
|
611
|
-
gitMode: GitModeState
|
|
612
|
-
autoCommit: AutoCommitState
|
|
613
|
-
multiRepo: MultiRepoState
|
|
614
|
-
settings: SettingsUIState
|
|
615
|
-
stats: StatsUIState
|
|
616
|
-
workspaceDivergence: Record<string, BranchDivergence>
|
|
617
|
-
workspaceActivity: Record<string, WorkspaceActivity>
|
|
618
|
-
lastActiveTabByWorkspace: Record<string, string>
|
|
619
|
-
pendingChords: string[] | null
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
// ─── AppAction union ──────────────────────────────────────────────────────────
|
|
623
|
-
|
|
624
|
-
export type ModalAction =
|
|
625
|
-
| {
|
|
626
|
-
type: 'open-new-tab-modal'
|
|
627
|
-
pendingWorkspace?: PendingWorkspaceLaunch
|
|
628
|
-
pendingPrompt?: string
|
|
629
|
-
}
|
|
630
|
-
| { type: 'open-help-modal'; scope?: ModeId }
|
|
631
|
-
| { type: 'open-split-picker'; direction: SplitDirection }
|
|
632
|
-
| { type: 'open-project-picker' }
|
|
633
|
-
| {
|
|
634
|
-
type: 'open-project-name-modal'
|
|
635
|
-
projectTargetId?: string
|
|
636
|
-
initialName?: string
|
|
637
|
-
returnToProjectPicker?: boolean
|
|
638
|
-
}
|
|
639
|
-
| { type: 'close-modal' }
|
|
640
|
-
| { type: 'move-modal-selection'; delta: number }
|
|
641
|
-
| {
|
|
642
|
-
type: 'move-modal-cursor'
|
|
643
|
-
delta?: number
|
|
644
|
-
to?: 'end' | 'home' | 'line-down' | 'line-up' | 'word-left' | 'word-right'
|
|
645
|
-
}
|
|
646
|
-
| { type: 'update-command-edit'; char: string }
|
|
647
|
-
| { type: 'cancel-command-edit' }
|
|
648
|
-
| { type: 'open-create-project-modal'; returnToProjectPicker: boolean }
|
|
649
|
-
| { type: 'open-create-workspace-modal' }
|
|
650
|
-
| { type: 'set-create-workspace-base-branches'; branches: string[]; defaultBranch?: string }
|
|
651
|
-
| { type: 'set-create-workspace-branch-error'; message: string | null }
|
|
652
|
-
| { type: 'switch-create-workspace-field' }
|
|
653
|
-
| { type: 'set-directory-results'; results: DirectoryResult[] }
|
|
654
|
-
| { type: 'switch-create-project-field' }
|
|
655
|
-
| { type: 'select-directory' }
|
|
656
|
-
| { type: 'open-rename-tab-modal' }
|
|
657
|
-
| {
|
|
658
|
-
type: 'open-rename-workspace-modal'
|
|
659
|
-
projectId: string
|
|
660
|
-
workspaceId: string
|
|
661
|
-
initialName: string
|
|
662
|
-
}
|
|
663
|
-
| { type: 'open-snippet-picker'; returnTo?: FocusMode }
|
|
664
|
-
| { type: 'open-snippet-editor'; snippetId?: string }
|
|
665
|
-
| { type: 'set-help-entry-count'; count: number }
|
|
666
|
-
| { type: 'set-theme-entry-count'; count: number }
|
|
667
|
-
| { type: 'open-theme-picker'; returnTo?: FocusMode }
|
|
668
|
-
| { type: 'open-update-available-modal'; currentVersion: string; latestVersion: string }
|
|
669
|
-
| { type: 'open-quotas-modal' }
|
|
670
|
-
| { type: 'set-modal-selection-index'; index: number }
|
|
671
|
-
| { type: 'open-edit-custom-command'; assistantId: AssistantId }
|
|
672
|
-
| { type: 'open-workspace-move-modal'; sourceWorkspaceId: string }
|
|
673
|
-
| { type: 'toggle-workspace-move-delete' }
|
|
674
|
-
| { type: 'set-workspace-move-stats'; dirtyFiles: Record<string, number> }
|
|
675
|
-
| {
|
|
676
|
-
type: 'open-workspace-move-confirm'
|
|
677
|
-
variant: 'stash-target' | 'keep-conflicts'
|
|
678
|
-
files: string[]
|
|
679
|
-
projectId: string
|
|
680
|
-
sourceWorkspaceId: string
|
|
681
|
-
targetWorkspaceId: string
|
|
682
|
-
deleteSource: boolean
|
|
683
|
-
sourceLabel: string
|
|
684
|
-
targetLabel: string
|
|
685
|
-
}
|
|
686
|
-
| {
|
|
687
|
-
type: 'open-workspace-delete-confirm'
|
|
688
|
-
projectId: string
|
|
689
|
-
workspaceId: string
|
|
690
|
-
workspaceLabel: string
|
|
691
|
-
reason: string
|
|
692
|
-
closeTabs: boolean
|
|
693
|
-
force: boolean
|
|
694
|
-
}
|
|
695
|
-
| { type: 'open-flash-jump-modal' }
|
|
696
|
-
| { type: 'clear-flash-jump-pending' }
|
|
697
|
-
|
|
698
|
-
export type ProjectAction =
|
|
699
|
-
| { type: 'load-project'; projectId: string; projectSnapshot?: ProjectSnapshotV1 }
|
|
700
|
-
| { type: 'set-projects'; projects: ProjectRecord[] }
|
|
701
|
-
| { type: 'create-project-record'; project: ProjectRecord }
|
|
702
|
-
| { type: 'rename-project-record'; projectId: string; name: string }
|
|
703
|
-
| { type: 'delete-project-record'; projectId: string; openProjectPicker?: boolean }
|
|
704
|
-
| { type: 'reorder-projects'; orderedIds: string[] }
|
|
705
|
-
| { type: 'reorder-active-project'; delta: number }
|
|
706
|
-
| { type: 'set-project-status'; projectId: string; status: ProjectStatus }
|
|
707
|
-
| { type: 'set-workspace-activity'; workspaceId: string; working: boolean; waiting: boolean }
|
|
708
|
-
| { type: 'mark-workspace-done'; workspaceId: string }
|
|
709
|
-
| {
|
|
710
|
-
type: 'add-workspace-record'
|
|
711
|
-
projectId: string
|
|
712
|
-
workspace: WorkspaceRecord
|
|
713
|
-
activate?: boolean
|
|
714
|
-
}
|
|
715
|
-
| { type: 'set-active-workspace'; projectId: string; workspaceId: string }
|
|
716
|
-
| {
|
|
717
|
-
type: 'update-workspace-record'
|
|
718
|
-
projectId: string
|
|
719
|
-
workspaceId: string
|
|
720
|
-
patch: Partial<WorkspaceRecord>
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
export type TabAction =
|
|
724
|
-
| { type: 'add-tab'; tab: TabSession }
|
|
725
|
-
| {
|
|
726
|
-
type: 'hydrate-project'
|
|
727
|
-
tabs: TabSession[]
|
|
728
|
-
activeTabId: string | null
|
|
729
|
-
layoutTree?: LayoutNode | null
|
|
730
|
-
layoutTrees?: Record<string, LayoutNode>
|
|
731
|
-
tabGroupMap?: Record<string, string>
|
|
732
|
-
}
|
|
733
|
-
| { type: 'close-tab'; tabId: string }
|
|
734
|
-
| { type: 'close-active-tab' }
|
|
735
|
-
| { type: 'set-active-tab'; tabId: string }
|
|
736
|
-
| { type: 'move-active-tab'; delta: number }
|
|
737
|
-
| { type: 'reorder-active-tab'; delta: number }
|
|
738
|
-
| { type: 'reset-tab-project'; tabId: string }
|
|
739
|
-
| { type: 'rename-tab'; tabId: string; title: string }
|
|
740
|
-
| { type: 'append-tab-buffer'; tabId: string; chunk: string }
|
|
741
|
-
| {
|
|
742
|
-
type: 'replace-tab-viewport'
|
|
743
|
-
tabId: string
|
|
744
|
-
viewport: TerminalSnapshot
|
|
745
|
-
terminalModes: TerminalModeState
|
|
746
|
-
}
|
|
747
|
-
| { type: 'set-tab-activity'; tabId: string; activity?: TabActivity }
|
|
748
|
-
| { type: 'set-tab-error'; tabId: string; message: string }
|
|
749
|
-
|
|
750
|
-
export type LayoutAction =
|
|
751
|
-
| {
|
|
752
|
-
type: 'split-pane'
|
|
753
|
-
direction: SplitDirection
|
|
754
|
-
newTab: TabSession
|
|
755
|
-
}
|
|
756
|
-
| { type: 'close-pane'; tabId: string }
|
|
757
|
-
| {
|
|
758
|
-
type: 'focus-pane-direction'
|
|
759
|
-
direction: 'left' | 'right' | 'up' | 'down'
|
|
760
|
-
}
|
|
761
|
-
| {
|
|
762
|
-
type: 'resize-pane'
|
|
763
|
-
tabId: string
|
|
764
|
-
delta: number
|
|
765
|
-
axis?: SplitDirection
|
|
766
|
-
}
|
|
767
|
-
| {
|
|
768
|
-
type: 'set-split-ratio'
|
|
769
|
-
tabId: string
|
|
770
|
-
ratio: number
|
|
771
|
-
axis?: SplitDirection
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
export type UIAction =
|
|
775
|
-
| { type: 'toggle-bar'; side: BarSide }
|
|
776
|
-
| { type: 'resize-bar'; side: BarSide; delta: number }
|
|
777
|
-
| { type: 'set-bar-width'; side: BarSide; width: number }
|
|
778
|
-
| { type: 'toggle-widget'; widgetId: string }
|
|
779
|
-
| { type: 'move-widget'; widgetId: string; side: BarSide; index: number }
|
|
780
|
-
| { type: 'set-bar-boundary'; side: BarSide; index: number; ratio: number }
|
|
781
|
-
| { type: 'resize-widget'; widgetId: string; delta: number }
|
|
782
|
-
| { type: 'set-focus-mode'; focusMode: FocusMode }
|
|
783
|
-
| { type: 'set-terminal-size'; cols: number; rows: number }
|
|
784
|
-
| { type: 'resize-git-diff-pane'; delta: number }
|
|
785
|
-
| { type: 'set-pending-chords'; chords: string[] | null }
|
|
786
|
-
| { type: 'toggle-project-bar' }
|
|
787
|
-
|
|
788
|
-
export type SettingsAction =
|
|
789
|
-
| { type: 'enter-settings' }
|
|
790
|
-
| { type: 'exit-settings' }
|
|
791
|
-
| { type: 'settings-move-selection'; delta: -1 | 1 }
|
|
792
|
-
| { type: 'settings-jump-section'; delta: -1 | 1 }
|
|
793
|
-
| { type: 'settings-select-row'; rowIndex: number }
|
|
794
|
-
| { type: 'open-settings-search' }
|
|
795
|
-
| { type: 'open-setting-text-modal'; settingId: string; label: string; value: string }
|
|
796
|
-
|
|
797
|
-
export type StatsAction =
|
|
798
|
-
| { type: 'enter-stats' }
|
|
799
|
-
| { type: 'exit-stats' }
|
|
800
|
-
| { type: 'stats-move-page'; delta: -1 | 1 }
|
|
801
|
-
| { type: 'stats-select-page'; pageIndex: number }
|
|
802
|
-
/** Rows, not pixels: the view holds a scroll offset the page applies to its box. */
|
|
803
|
-
| { type: 'stats-scroll'; delta: number }
|
|
804
|
-
/** The offset the scrollbox actually accepted, sent back so the state cannot run past the page. */
|
|
805
|
-
| { type: 'stats-scroll-settled'; scrollTop: number }
|
|
806
|
-
|
|
807
|
-
export interface GitRefreshPayload {
|
|
808
|
-
branch: string | null
|
|
809
|
-
ahead: number
|
|
810
|
-
behind: number
|
|
811
|
-
files: GitFileEntry[]
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
/** Commits a workspace branch is ahead/behind the ref it forked from. */
|
|
815
|
-
export interface BranchDivergence {
|
|
816
|
-
ahead: number
|
|
817
|
-
behind: number
|
|
818
|
-
/** Lines changed since the fork point, working tree included. */
|
|
819
|
-
added?: number
|
|
820
|
-
removed?: number
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
export type GitPanelAction =
|
|
824
|
-
| { type: 'git-refresh-success'; payload: GitRefreshPayload }
|
|
825
|
-
| { type: 'git-refresh-error'; kind: GitPanelError }
|
|
826
|
-
| { type: 'git-panel-reset' }
|
|
827
|
-
| { type: 'set-workspace-divergence'; divergence: Record<string, BranchDivergence> }
|
|
828
|
-
| { type: 'set-git-pane'; patch: Partial<GitPaneState> }
|
|
829
|
-
|
|
830
|
-
export type GitModeAction =
|
|
831
|
-
| { type: 'enter-git-mode' }
|
|
832
|
-
| { type: 'exit-git-mode' }
|
|
833
|
-
| { type: 'git-mode-move-selection'; delta: -1 | 1 }
|
|
834
|
-
| { type: 'git-mode-move-file-selection'; delta: -1 | 1 }
|
|
835
|
-
| { type: 'git-mode-select-entry-by-key'; key: string }
|
|
836
|
-
| { type: 'git-mode-toggle-folder'; key: string }
|
|
837
|
-
| { type: 'git-mode-toggle-selected-folder' }
|
|
838
|
-
| { type: 'git-mode-collapse-selection' }
|
|
839
|
-
| { type: 'git-mode-expand-selection' }
|
|
840
|
-
| { type: 'git-mode-toggle-file-list-mode' }
|
|
841
|
-
| { type: 'git-mode-toggle-tree-compaction' }
|
|
842
|
-
| { type: 'git-mode-set-diff'; key: string; diff: DiffData; hash: string }
|
|
843
|
-
| { type: 'git-mode-set-loading'; key: string; loading: boolean }
|
|
844
|
-
| { type: 'git-mode-set-pending-delete'; path: string | null }
|
|
845
|
-
| { type: 'git-mode-clear-diff-cache'; path: string }
|
|
846
|
-
| { type: 'git-mode-set-message'; message: string | null }
|
|
847
|
-
| { type: 'snippet-picker-set-message'; message: string | null }
|
|
848
|
-
| { type: 'git-mode-toggle-diff-view' }
|
|
849
|
-
| { type: 'git-mode-toggle-review-base' }
|
|
850
|
-
| { type: 'git-mode-shift-head-offset'; delta: number }
|
|
851
|
-
| { type: 'git-mode-set-head-offset'; offset: number }
|
|
852
|
-
| {
|
|
853
|
-
type: 'git-mode-fold-adjust'
|
|
854
|
-
key: string
|
|
855
|
-
foldId: string
|
|
856
|
-
side: 'top' | 'bottom'
|
|
857
|
-
delta: number
|
|
858
|
-
}
|
|
859
|
-
| { type: 'git-mode-fold-set'; key: string; foldId: string; top: number; bottom: number }
|
|
860
|
-
| { type: 'git-mode-fold-toggle-all'; key: string }
|
|
861
|
-
| {
|
|
862
|
-
type: 'git-mode-optimistic-move'
|
|
863
|
-
path: string
|
|
864
|
-
fromSection: GitFileSection
|
|
865
|
-
toSection: GitFileSection | null
|
|
866
|
-
}
|
|
867
|
-
| { type: 'open-git-commit-modal'; projectId?: string }
|
|
868
|
-
| { type: 'git-commit-enter-confirm' }
|
|
869
|
-
| { type: 'git-commit-leave-confirm' }
|
|
870
|
-
| { type: 'git-commit-enter-generating'; projectId: string }
|
|
871
|
-
| { type: 'git-commit-leave-generating' }
|
|
872
|
-
|
|
873
|
-
export type DataAction =
|
|
874
|
-
| { type: 'set-snippets'; snippets: SnippetRecord[] }
|
|
875
|
-
| { type: 'delete-snippet'; snippetId: string }
|
|
876
|
-
|
|
877
|
-
export type AutoCommitAction =
|
|
878
|
-
| {
|
|
879
|
-
type: 'auto-commit-generation-started'
|
|
880
|
-
projectId: string
|
|
881
|
-
tabId: string
|
|
882
|
-
workingTreeHash: string
|
|
883
|
-
abortController: AbortController
|
|
884
|
-
startedAt: number
|
|
885
|
-
}
|
|
886
|
-
| {
|
|
887
|
-
type: 'auto-commit-generation-ready'
|
|
888
|
-
projectId: string
|
|
889
|
-
workingTreeHash: string
|
|
890
|
-
title: string
|
|
891
|
-
body: string
|
|
892
|
-
generatedAt: number
|
|
893
|
-
}
|
|
894
|
-
| { type: 'auto-commit-clear'; projectId: string }
|
|
895
|
-
|
|
896
|
-
export type AppAction =
|
|
897
|
-
| ModalAction
|
|
898
|
-
| ProjectAction
|
|
899
|
-
| TabAction
|
|
900
|
-
| LayoutAction
|
|
901
|
-
| UIAction
|
|
902
|
-
| SettingsAction
|
|
903
|
-
| StatsAction
|
|
904
|
-
| DataAction
|
|
905
|
-
| GitPanelAction
|
|
906
|
-
| GitModeAction
|
|
907
|
-
| AutoCommitAction
|
|
908
|
-
|
|
909
66
|
// ─── Side effects ─────────────────────────────────────────────────────────────
|
|
910
67
|
|
|
911
|
-
export type SideEffect =
|
|
912
|
-
| { type: 'quit'; state: AppState }
|
|
913
|
-
| { type: 'open-new-tab' }
|
|
914
|
-
| { type: 'launch-selected-assistant' }
|
|
915
|
-
| { type: 'edit-selected-assistant' }
|
|
916
|
-
| { type: 'confirm-selected-project' }
|
|
917
|
-
| { type: 'delete-selected-project' }
|
|
918
|
-
| { type: 'open-rename-selected-project' }
|
|
919
|
-
| { type: 'create-project'; name: string; projectPath?: string }
|
|
920
|
-
| { type: 'create-workspace' }
|
|
921
|
-
| { type: 'load-create-workspace-base-branches' }
|
|
922
|
-
| { type: 'close-tab'; tabId: string }
|
|
923
|
-
| { type: 'restart-tab'; tab: TabSession }
|
|
924
|
-
| { type: 'paste-selected-snippet' }
|
|
925
|
-
| { type: 'paste-snippet-to-group' }
|
|
926
|
-
| { type: 'edit-selected-snippet' }
|
|
927
|
-
| { type: 'delete-selected-snippet' }
|
|
928
|
-
| { type: 'save-snippet-editor' }
|
|
929
|
-
| { type: 'save-custom-command' }
|
|
930
|
-
| { type: 'apply-theme'; action: 'open' }
|
|
931
|
-
| { type: 'apply-theme'; action: 'restore' }
|
|
932
|
-
| { type: 'apply-theme'; action: 'confirm' }
|
|
933
|
-
| { type: 'apply-theme'; action: 'preview'; delta: 1 | -1 }
|
|
934
|
-
| { type: 'rename-project'; projectId: string; name: string }
|
|
935
|
-
| { type: 'rename-tab'; tabId: string; title: string }
|
|
936
|
-
| { type: 'split-pane'; direction: SplitDirection; sourceTabId?: string }
|
|
937
|
-
| { type: 'confirm-split' }
|
|
938
|
-
| { type: 'scroll-git-diff'; delta: number }
|
|
939
|
-
| { type: 'persist-git-diff-mode-ratio'; ratio: number }
|
|
940
|
-
| { type: 'persist-git-file-list-mode'; mode: GitFileListMode }
|
|
941
|
-
| { type: 'persist-git-tree-compaction'; enabled: boolean }
|
|
942
|
-
| { type: 'git-stage'; path: string }
|
|
943
|
-
| { type: 'git-unstage'; path: string }
|
|
944
|
-
| { type: 'git-stage-all' }
|
|
945
|
-
| { type: 'git-unstage-all' }
|
|
946
|
-
| { type: 'git-restore'; path: string }
|
|
947
|
-
| { type: 'git-rm'; path: string }
|
|
948
|
-
| { type: 'git-commit'; title: string; body: string }
|
|
949
|
-
| { type: 'git-commit-auto'; title: string; body: string }
|
|
950
|
-
| { type: 'generate-auto-commit-now'; projectId: string }
|
|
951
|
-
| { type: 'git-push' }
|
|
952
|
-
| { type: 'confirm-update-selection' }
|
|
953
|
-
| { type: 'switch-project-by-index'; index: number }
|
|
954
|
-
| { type: 'cycle-sidebar-item'; direction: 1 | -1 }
|
|
955
|
-
| { type: 'switch-tab-by-index'; index: number }
|
|
956
|
-
| { type: 'delete-project'; projectId: string }
|
|
957
|
-
| {
|
|
958
|
-
type: 'delete-workspace'
|
|
959
|
-
projectId: string
|
|
960
|
-
workspaceId: string
|
|
961
|
-
// Force the git worktree removal (discards uncommitted changes in the
|
|
962
|
-
// workspace). Also implies closing the workspace's tabs.
|
|
963
|
-
force?: boolean
|
|
964
|
-
// Close the workspace's tabs without forcing the git removal. Lets the
|
|
965
|
-
// sidebar "Remove workspace" clean up tabs (avoiding orphans) while still
|
|
966
|
-
// refusing to discard uncommitted work in a temp workspace.
|
|
967
|
-
closeTabs?: boolean
|
|
968
|
-
}
|
|
969
|
-
| {
|
|
970
|
-
type: 'move-workspace'
|
|
971
|
-
projectId: string
|
|
972
|
-
sourceWorkspaceId: string
|
|
973
|
-
targetWorkspaceId: string
|
|
974
|
-
deleteSource?: boolean
|
|
975
|
-
// Retry flags set by the workspace-move-confirm dialog.
|
|
976
|
-
stashTarget?: boolean
|
|
977
|
-
keepConflicts?: boolean
|
|
978
|
-
}
|
|
979
|
-
| { type: 'load-workspace-move-stats' }
|
|
980
|
-
| { type: 'toggle-transparent' }
|
|
981
|
-
| { type: 'toggle-mode' }
|
|
982
|
-
| { type: 'open-file-in-editor'; path: string }
|
|
983
|
-
| { type: 'open-selected-snippet-source-in-editor' }
|
|
984
|
-
| { type: 'run-setup' }
|
|
985
|
-
| { type: 'stop-setup' }
|
|
986
|
-
| { type: 'configure-setup-script'; projectId?: string }
|
|
987
|
-
| { type: 'ask-agent-for-setup-script' }
|
|
988
|
-
| { type: 'promote-setup-tab' }
|
|
989
|
-
| { type: 'activate-settings-row' }
|
|
990
|
-
| { type: 'adjust-settings-row'; delta: 1 | -1 }
|
|
991
|
-
| { type: 'reset-settings-row' }
|
|
992
|
-
| { type: 'confirm-settings-search' }
|
|
993
|
-
| { type: 'commit-setting-text'; settingId: string; value: string }
|
|
994
|
-
|
|
995
68
|
// ─── Key input / KeyResult / ModeContext ──────────────────────────────────────
|
|
996
69
|
|
|
997
|
-
/** Structural shape for a parsed key event. Matches @opentui/core's KeyEvent. */
|
|
998
|
-
export interface KeyInput {
|
|
999
|
-
name: string
|
|
1000
|
-
ctrl: boolean
|
|
1001
|
-
meta: boolean
|
|
1002
|
-
shift: boolean
|
|
1003
|
-
sequence: string
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
export interface KeyResult {
|
|
1007
|
-
actions: AppAction[]
|
|
1008
|
-
effects: SideEffect[]
|
|
1009
|
-
transition?: ModeId
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
export interface ModeContext {
|
|
1013
|
-
readonly state: AppState
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
70
|
// ─── Themes ───────────────────────────────────────────────────────────────────
|
|
1017
71
|
|
|
1018
72
|
// Theme types now live in `./tui` (1:1 port of opencode TUI). The aliases
|
|
@@ -1040,6 +94,35 @@ export interface HooksConfig {
|
|
|
1040
94
|
onProjectCreate?: (project: { name: string; projectPath?: string }) => void | Promise<void>
|
|
1041
95
|
}
|
|
1042
96
|
|
|
97
|
+
// ─── Plugin config ────────────────────────────────────────────────────────────
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* A plugin declared from `aimux.config.ts` rather than through
|
|
101
|
+
* `aimux plugin link`. Either form works; this one is the version-controllable
|
|
102
|
+
* half, and it outranks `aimux-plugins.json` on every key it sets.
|
|
103
|
+
*/
|
|
104
|
+
export interface PluginConfigEntry {
|
|
105
|
+
/**
|
|
106
|
+
* Directory holding `aimux-plugin.json`. Relative paths resolve against the
|
|
107
|
+
* profile config directory — the one `aimux.config.ts` itself lives in.
|
|
108
|
+
* Omit it to configure a plugin that is already linked or installed.
|
|
109
|
+
*/
|
|
110
|
+
path?: string
|
|
111
|
+
/**
|
|
112
|
+
* Plugin id. Required when there is no `path`; otherwise it is checked
|
|
113
|
+
* against the manifest so a moved directory fails loudly instead of loading
|
|
114
|
+
* something else.
|
|
115
|
+
*/
|
|
116
|
+
id?: string
|
|
117
|
+
/** Default true. `false` keeps the plugin registered but never loads it. */
|
|
118
|
+
enabled?: boolean
|
|
119
|
+
/** Merged over the manifest defaults and the registry, and wins over both. */
|
|
120
|
+
config?: Record<string, unknown>
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** A bare string is shorthand for `{ path }`. */
|
|
124
|
+
export type PluginConfigDecl = string | PluginConfigEntry
|
|
125
|
+
|
|
1043
126
|
// ─── Snippet config (stub) ────────────────────────────────────────────────────
|
|
1044
127
|
|
|
1045
128
|
/**
|
|
@@ -1111,6 +194,20 @@ export interface KeymapBuilderApi {
|
|
|
1111
194
|
id: ModeId | readonly ModeId[],
|
|
1112
195
|
configure: (m: ModeBindingBuilderApi) => ModeBindingBuilderApi
|
|
1113
196
|
): KeymapBuilderApi
|
|
197
|
+
/**
|
|
198
|
+
* Binds an action a plugin contributes, by its qualified `<pluginId>.<verb>`
|
|
199
|
+
* name:
|
|
200
|
+
*
|
|
201
|
+
* ```ts
|
|
202
|
+
* k.mode('navigation', (m) => m.map('<leader>r', k.plugin('acme.review.open')))
|
|
203
|
+
* ```
|
|
204
|
+
*
|
|
205
|
+
* A name, not a function, because the keymap is resolved at startup and
|
|
206
|
+
* plugins load after it. Requiring an import would mean a config file could
|
|
207
|
+
* only reference plugins it could reach — the coupling a plugin system
|
|
208
|
+
* exists to remove. An unresolved name is inert, the way an unbound key is.
|
|
209
|
+
*/
|
|
210
|
+
plugin(name: string): Action
|
|
1114
211
|
}
|
|
1115
212
|
|
|
1116
213
|
// ─── Top-level user config ────────────────────────────────────────────────────
|
|
@@ -1124,14 +221,6 @@ export interface ProjectBarConfig {
|
|
|
1124
221
|
|
|
1125
222
|
// ─── Git pane config (discriminated union) ────────────────────────────────────
|
|
1126
223
|
|
|
1127
|
-
export type GitPanePathConfig =
|
|
1128
|
-
| { enabled: false }
|
|
1129
|
-
| { enabled: true; pathFn?: (path: string) => string }
|
|
1130
|
-
|
|
1131
|
-
export interface GitPaneDiffCountConfig {
|
|
1132
|
-
enabled: boolean
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
224
|
interface GitPaneBaseConfig {
|
|
1136
225
|
/** Startup override for git pane visibility. Reapplied on each launch. */
|
|
1137
226
|
initialVisible?: boolean
|
|
@@ -1243,7 +332,12 @@ export interface AimuxThemeConfig {
|
|
|
1243
332
|
}
|
|
1244
333
|
}
|
|
1245
334
|
|
|
1246
|
-
|
|
335
|
+
/**
|
|
336
|
+
* A tool the usage indicator can poll. Widened with `(string & {})` because a
|
|
337
|
+
* plugin assistant can declare a `usage` adapter and its id is not knowable
|
|
338
|
+
* here; the literal half survives, so the built-in two still autocomplete.
|
|
339
|
+
*/
|
|
340
|
+
export type AIUsageTool = 'claude' | 'codex' | (string & {})
|
|
1247
341
|
|
|
1248
342
|
export interface AIUsageToolConfig {
|
|
1249
343
|
enabled?: boolean
|
|
@@ -1332,6 +426,11 @@ export interface AimuxUserConfig {
|
|
|
1332
426
|
statusBar?: StatusBarConfig
|
|
1333
427
|
externalEditor?: ExternalEditorConfig
|
|
1334
428
|
integrations?: AimuxIntegrationsConfig
|
|
429
|
+
/**
|
|
430
|
+
* Plugins to load, in addition to anything `aimux plugin link/install`
|
|
431
|
+
* registered. See `docs/developer/plugins.md`.
|
|
432
|
+
*/
|
|
433
|
+
plugins?: PluginConfigDecl[]
|
|
1335
434
|
/**
|
|
1336
435
|
* @deprecated Removed. Workspace provisioning is a per-project setup script
|
|
1337
436
|
* now — see `docs/guide/workspaces.md#setup`. Declared here only so the strike
|
|
@@ -1406,4 +505,6 @@ export interface ResolvedConfig {
|
|
|
1406
505
|
integrations: {
|
|
1407
506
|
claudeHooks: boolean
|
|
1408
507
|
}
|
|
508
|
+
/** Normalised to the object form; a bare string became `{ path }`. */
|
|
509
|
+
plugins: PluginConfigEntry[]
|
|
1409
510
|
}
|