@brimveyn/aimux 1.7.3 → 1.8.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/README.md +27 -15
- package/package.json +2 -2
- package/src/app-runtime/auto-commit-driver.ts +286 -0
- package/src/app-runtime/auto-commit-ref.ts +20 -0
- package/src/app-runtime/backend-attach-runtime.ts +3 -1
- package/src/app-runtime/session-actions.ts +7 -2
- package/src/app-runtime/side-effects.ts +111 -4
- package/src/app-runtime/split-drag-controller.ts +31 -1
- package/src/app-runtime/use-auto-commit-driver.ts +133 -0
- package/src/app-runtime/use-mouse-handlers.ts +93 -5
- package/src/app-runtime/use-terminal-resize.ts +24 -16
- package/src/app.tsx +71 -19
- package/src/auto-commit/default-auto-commit-prompt.md +46 -0
- package/src/auto-commit/headless-commands.ts +40 -0
- package/src/auto-commit/output-parser.ts +21 -0
- package/src/auto-commit/prompt-loader.ts +33 -0
- package/src/auto-commit/staging-mode.ts +5 -0
- package/src/auto-commit/strip-ansi.ts +13 -0
- package/src/auto-commit/suggestion-runner.ts +55 -0
- package/src/auto-commit/working-tree-hash.ts +24 -0
- package/src/config.ts +45 -2
- package/src/daemon/session-registry.ts +1 -0
- package/src/index.tsx +1 -1
- package/src/input/keymap/help-entries.ts +4 -4
- package/src/input/modes/bridge.ts +6 -0
- package/src/input/modes/transitions.ts +3 -1
- package/src/input/modes/types.ts +4 -0
- package/src/ipc/manager-protocol.ts +2 -2
- package/src/ipc/protocol.ts +2 -8
- package/src/pty/assistant-status-detector.ts +1 -1
- package/src/pty/terminal-snapshot.ts +38 -4
- package/src/services/ai-usage/adapters/claude.ts +139 -0
- package/src/services/ai-usage/adapters/codex.ts +191 -0
- package/src/services/ai-usage/provider.ts +84 -0
- package/src/services/ai-usage/spawn.ts +49 -0
- package/src/services/ai-usage/types.ts +20 -0
- package/src/session-backend/local-session-backend.ts +10 -2
- package/src/state/ai-usage-store.ts +29 -0
- package/src/state/git-pane-sizing.ts +15 -0
- package/src/state/reducers/auto-commit-state.ts +59 -0
- package/src/state/reducers/git-panel-state.ts +12 -7
- package/src/state/reducers/modal-state.ts +106 -2
- package/src/state/reducers/session-state.ts +26 -14
- package/src/state/reducers/ui-state.ts +6 -0
- package/src/state/session-persistence.ts +14 -5
- package/src/state/store.ts +26 -15
- package/src/state/types.ts +59 -3
- package/src/state/workspace-save.ts +6 -1
- package/src/ui/ai-usage/controller.ts +35 -0
- package/src/ui/components/ai-usage-indicator.tsx +131 -0
- package/src/ui/components/ai-usage-popover.tsx +152 -0
- package/src/ui/components/context-menu-overlay.tsx +4 -2
- package/src/ui/components/create-session-modal.tsx +2 -2
- package/src/ui/components/git-commit-modal.tsx +167 -18
- package/src/ui/components/git-pane-context-menu.ts +26 -0
- package/src/ui/components/session-bar.tsx +2 -2
- package/src/ui/components/session-picker-modal.tsx +4 -4
- package/src/ui/components/sidebar.tsx +117 -31
- package/src/ui/components/status-bar.tsx +2 -0
- package/src/ui/components/terminal-pane.tsx +18 -3
- package/src/ui/root.tsx +114 -13
- package/src/ui/status-bar-model.ts +1 -1
package/src/ui/root.tsx
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import type { MouseEvent } from '@opentui/core'
|
|
2
2
|
|
|
3
3
|
import type { TerminalContentOrigin } from '../input/raw-input-handler'
|
|
4
|
-
import type { ModalState, SessionRecord, SnippetRecord } from '../state/types'
|
|
4
|
+
import type { FocusMode, ModalState, SessionRecord, SnippetRecord } from '../state/types'
|
|
5
5
|
import type { ThemeId } from './themes'
|
|
6
6
|
|
|
7
7
|
import { useAppStore } from '../state/app-store'
|
|
8
|
+
import { dispatchGlobal } from '../state/dispatch-ref'
|
|
9
|
+
import { getGitPaneWidthFromRatio } from '../state/git-pane-sizing'
|
|
8
10
|
import { getTreeForTab, PANE_BORDER, type SplitDirection } from '../state/layout-tree'
|
|
11
|
+
import { AIUsagePopover } from './components/ai-usage-popover'
|
|
12
|
+
import { ContextMenuBox } from './components/context-menu-box'
|
|
9
13
|
import { ContextMenuOverlay } from './components/context-menu-overlay'
|
|
10
14
|
import { CreateSessionModal } from './components/create-session-modal'
|
|
11
15
|
import { GitCommitModal } from './components/git-commit-modal'
|
|
16
|
+
import { buildGitPaneContextMenu } from './components/git-pane-context-menu'
|
|
12
17
|
import { GitPaneWidget } from './components/git-pane-widget'
|
|
13
18
|
import { GitView } from './components/git-view'
|
|
14
19
|
import { HelpModal } from './components/help-modal'
|
|
@@ -25,7 +30,7 @@ import { StatusBar } from './components/status-bar'
|
|
|
25
30
|
import { TerminalPane } from './components/terminal-pane'
|
|
26
31
|
import { ThemePickerModal } from './components/theme-picker-modal'
|
|
27
32
|
import { UpdateAvailableModal } from './components/update-available-modal'
|
|
28
|
-
import { useBg } from './theme'
|
|
33
|
+
import { useBg, useTokens } from './theme'
|
|
29
34
|
|
|
30
35
|
function getCreateSessionFields(modal: ModalState) {
|
|
31
36
|
if (modal.type !== 'create-session') {
|
|
@@ -74,6 +79,9 @@ function renderModal(
|
|
|
74
79
|
themeId: ThemeId
|
|
75
80
|
createSessionFields: { directoryQuery: string; sessionName: string }
|
|
76
81
|
snippetEditorFields: { snippetName: string; snippetContent: string }
|
|
82
|
+
focusMode: FocusMode
|
|
83
|
+
activeAssistant?: string
|
|
84
|
+
autoCommitModel?: string
|
|
77
85
|
}
|
|
78
86
|
) {
|
|
79
87
|
switch (modal.type) {
|
|
@@ -103,7 +111,7 @@ function renderModal(
|
|
|
103
111
|
case 'session-name':
|
|
104
112
|
return (
|
|
105
113
|
<SessionNameModal
|
|
106
|
-
title={modal.sessionTargetId ? 'Rename
|
|
114
|
+
title={modal.sessionTargetId ? 'Rename workspace' : 'Create workspace'}
|
|
107
115
|
value={modal.editBuffer ?? ''}
|
|
108
116
|
/>
|
|
109
117
|
)
|
|
@@ -172,8 +180,11 @@ function renderModal(
|
|
|
172
180
|
return (
|
|
173
181
|
<GitCommitModal
|
|
174
182
|
activeField={modal.activeField}
|
|
183
|
+
assistant={options.activeAssistant}
|
|
175
184
|
body={bodyText}
|
|
176
185
|
cursorPos={modal.cursorPos ?? (modal.editBuffer ?? '').length}
|
|
186
|
+
model={options.autoCommitModel}
|
|
187
|
+
stage={modal.stage}
|
|
177
188
|
title={titleText}
|
|
178
189
|
/>
|
|
179
190
|
)
|
|
@@ -195,6 +206,17 @@ interface RootViewProps {
|
|
|
195
206
|
onTerminalClick?: (event: MouseEvent, origin: TerminalContentOrigin, tabId?: string) => void
|
|
196
207
|
onPaneActivate?: (tabId: string) => void
|
|
197
208
|
onSplitResize?: (tabId: string, ratio: number, axis: SplitDirection) => void
|
|
209
|
+
onSidebarResizeStart?: (info: { initialWidth: number; screenStart: number }) => void
|
|
210
|
+
onGitPaneResizeStart?: (info: {
|
|
211
|
+
initialWidth: number
|
|
212
|
+
screenStart: number
|
|
213
|
+
side: 'left' | 'right'
|
|
214
|
+
}) => void
|
|
215
|
+
onEmbeddedGitResizeStart?: (info: {
|
|
216
|
+
containerStart: number
|
|
217
|
+
position: 'top' | 'bottom'
|
|
218
|
+
totalSize: number
|
|
219
|
+
}) => void
|
|
198
220
|
onSeparatorDragStart?: (info: {
|
|
199
221
|
tabId: string
|
|
200
222
|
direction: SplitDirection
|
|
@@ -211,10 +233,13 @@ export function RootView({
|
|
|
211
233
|
contentOrigin,
|
|
212
234
|
localScrollbackEnabled,
|
|
213
235
|
mouseForwardingEnabled,
|
|
236
|
+
onEmbeddedGitResizeStart,
|
|
237
|
+
onGitPaneResizeStart,
|
|
214
238
|
onPaneActivate,
|
|
215
239
|
onSeparatorDrag,
|
|
216
240
|
onSeparatorDragEnd,
|
|
217
241
|
onSeparatorDragStart,
|
|
242
|
+
onSidebarResizeStart,
|
|
218
243
|
onSplitResize,
|
|
219
244
|
onTerminalClick,
|
|
220
245
|
onTerminalMouseEvent,
|
|
@@ -238,7 +263,7 @@ export function RootView({
|
|
|
238
263
|
const gitPaneMode = useAppStore((s) => s.gitPane.mode)
|
|
239
264
|
const gitPaneVisible = useAppStore((s) => s.gitPane.visible)
|
|
240
265
|
const gitPanePosition = useAppStore((s) => s.gitPane.position)
|
|
241
|
-
const gitPaneRatio = useAppStore((s) => s.gitPane.
|
|
266
|
+
const gitPaneRatio = useAppStore((s) => s.gitPane.paneRatio)
|
|
242
267
|
|
|
243
268
|
const activeTab = tabs.find((tab) => tab.id === activeTabId)
|
|
244
269
|
const activeTree = activeTabId ? getTreeForTab(layoutTrees, tabGroupMap, activeTabId) : null
|
|
@@ -254,11 +279,14 @@ export function RootView({
|
|
|
254
279
|
<StatusBar />
|
|
255
280
|
<PendingChordOverlay />
|
|
256
281
|
<ContextMenuOverlay />
|
|
282
|
+
<AIUsagePopover />
|
|
257
283
|
{renderModal(modal, {
|
|
284
|
+
activeAssistant: activeTab?.assistant,
|
|
258
285
|
createSessionFields,
|
|
259
286
|
currentSessionId,
|
|
260
287
|
currentTabCount: tabs.length,
|
|
261
288
|
customCommands,
|
|
289
|
+
focusMode,
|
|
262
290
|
sessions,
|
|
263
291
|
snippetEditorFields,
|
|
264
292
|
snippets,
|
|
@@ -269,12 +297,36 @@ export function RootView({
|
|
|
269
297
|
}
|
|
270
298
|
|
|
271
299
|
return (
|
|
272
|
-
<box
|
|
300
|
+
<box
|
|
301
|
+
flexDirection="column"
|
|
302
|
+
width="100%"
|
|
303
|
+
height="100%"
|
|
304
|
+
backgroundColor={editorBg}
|
|
305
|
+
onMouseDrag={(event) => {
|
|
306
|
+
if (onSeparatorDrag?.(event)) {
|
|
307
|
+
event.preventDefault()
|
|
308
|
+
event.stopPropagation()
|
|
309
|
+
}
|
|
310
|
+
}}
|
|
311
|
+
onMouseUp={() => {
|
|
312
|
+
onSeparatorDragEnd?.()
|
|
313
|
+
}}
|
|
314
|
+
>
|
|
273
315
|
{sessionBarPosition === 'top' && <SessionBar />}
|
|
274
316
|
<box flexDirection="row" gap={0} padding={0} flexGrow={1}>
|
|
275
|
-
<Sidebar
|
|
317
|
+
<Sidebar
|
|
318
|
+
onTabActivate={onPaneActivate}
|
|
319
|
+
onEmbeddedGitResizeStart={onEmbeddedGitResizeStart}
|
|
320
|
+
onResizeDrag={onSeparatorDrag}
|
|
321
|
+
onResizeDragEnd={onSeparatorDragEnd}
|
|
322
|
+
onSidebarResizeStart={onSidebarResizeStart}
|
|
323
|
+
/>
|
|
276
324
|
{gitPaneMode === 'pane' && gitPaneVisible && gitPanePosition === 'left' ? (
|
|
277
|
-
<GitPaneInPaneMode
|
|
325
|
+
<GitPaneInPaneMode
|
|
326
|
+
position="left"
|
|
327
|
+
ratio={gitPaneRatio}
|
|
328
|
+
onGitPaneResizeStart={onGitPaneResizeStart}
|
|
329
|
+
/>
|
|
278
330
|
) : null}
|
|
279
331
|
{activeTree && activeTree.type === 'split' ? (
|
|
280
332
|
<SplitLayout
|
|
@@ -321,7 +373,11 @@ export function RootView({
|
|
|
321
373
|
/>
|
|
322
374
|
)}
|
|
323
375
|
{gitPaneMode === 'pane' && gitPaneVisible && gitPanePosition === 'right' ? (
|
|
324
|
-
<GitPaneInPaneMode
|
|
376
|
+
<GitPaneInPaneMode
|
|
377
|
+
position="right"
|
|
378
|
+
ratio={gitPaneRatio}
|
|
379
|
+
onGitPaneResizeStart={onGitPaneResizeStart}
|
|
380
|
+
/>
|
|
325
381
|
) : null}
|
|
326
382
|
</box>
|
|
327
383
|
{sessionBarPosition === 'bottom' && <SessionBar />}
|
|
@@ -333,6 +389,7 @@ export function RootView({
|
|
|
333
389
|
currentSessionId,
|
|
334
390
|
currentTabCount: tabs.length,
|
|
335
391
|
customCommands,
|
|
392
|
+
focusMode,
|
|
336
393
|
sessions,
|
|
337
394
|
snippetEditorFields,
|
|
338
395
|
snippets,
|
|
@@ -342,14 +399,58 @@ export function RootView({
|
|
|
342
399
|
)
|
|
343
400
|
}
|
|
344
401
|
|
|
345
|
-
function GitPaneInPaneMode({
|
|
402
|
+
function GitPaneInPaneMode({
|
|
403
|
+
onGitPaneResizeStart,
|
|
404
|
+
position,
|
|
405
|
+
ratio,
|
|
406
|
+
}: {
|
|
407
|
+
ratio: number
|
|
408
|
+
position: 'left' | 'right'
|
|
409
|
+
onGitPaneResizeStart?: (info: {
|
|
410
|
+
initialWidth: number
|
|
411
|
+
screenStart: number
|
|
412
|
+
side: 'left' | 'right'
|
|
413
|
+
}) => void
|
|
414
|
+
}) {
|
|
346
415
|
const bg = useBg('elevated')
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
const width =
|
|
416
|
+
const tokens = useTokens()
|
|
417
|
+
const gitPane = useAppStore((s) => s.gitPane)
|
|
418
|
+
const width = getGitPaneWidthFromRatio(ratio)
|
|
419
|
+
const contentWidth = Math.max(1, width - 1)
|
|
420
|
+
const gitPaneMenu = buildGitPaneContextMenu(
|
|
421
|
+
gitPane,
|
|
422
|
+
() => dispatchGlobal({ type: 'toggle-git-pane' }),
|
|
423
|
+
(mode, nextPosition) => {
|
|
424
|
+
dispatchGlobal({ mode, type: 'set-git-pane-mode' })
|
|
425
|
+
dispatchGlobal({ position: nextPosition, type: 'set-git-pane-position' })
|
|
426
|
+
}
|
|
427
|
+
)
|
|
428
|
+
const handle = (
|
|
429
|
+
<box
|
|
430
|
+
width={1}
|
|
431
|
+
flexShrink={0}
|
|
432
|
+
backgroundColor={tokens.border}
|
|
433
|
+
onMouseDown={(event) => {
|
|
434
|
+
event.preventDefault()
|
|
435
|
+
event.stopPropagation()
|
|
436
|
+
onGitPaneResizeStart?.({ initialWidth: width, screenStart: event.x, side: position })
|
|
437
|
+
}}
|
|
438
|
+
/>
|
|
439
|
+
)
|
|
350
440
|
return (
|
|
351
441
|
<box flexDirection="column" width={width} flexShrink={0} backgroundColor={bg} overflow="hidden">
|
|
352
|
-
<
|
|
442
|
+
<box flexDirection="row" flexGrow={1} overflow="hidden">
|
|
443
|
+
{position === 'right' ? handle : null}
|
|
444
|
+
<ContextMenuBox
|
|
445
|
+
width={contentWidth}
|
|
446
|
+
flexGrow={1}
|
|
447
|
+
overflow="hidden"
|
|
448
|
+
rightClickMenu={gitPaneMenu}
|
|
449
|
+
>
|
|
450
|
+
<GitPaneWidget pollingEnabled />
|
|
451
|
+
</ContextMenuBox>
|
|
452
|
+
{position === 'left' ? handle : null}
|
|
453
|
+
</box>
|
|
353
454
|
</box>
|
|
354
455
|
)
|
|
355
456
|
}
|
|
@@ -61,7 +61,7 @@ export function getStatusBarModel(
|
|
|
61
61
|
const currentSession = state.currentSessionId
|
|
62
62
|
? state.sessions.find((session) => session.id === state.currentSessionId)
|
|
63
63
|
: undefined
|
|
64
|
-
const sessionName = currentSession?.name ?? 'no
|
|
64
|
+
const sessionName = currentSession?.name ?? 'no workspace'
|
|
65
65
|
const sessionLabel = currentSession?.projectPath
|
|
66
66
|
? `${sessionName} (${abbreviatePath(currentSession.projectPath)})`
|
|
67
67
|
: sessionName
|