@brimveyn/aimux 1.8.0 → 1.9.1
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 +2 -2
- package/src/app-runtime/side-effects.ts +6 -1
- package/src/app.tsx +20 -16
- package/src/input/keymap/describe-bindings.ts +63 -2
- package/src/input/modes/bridge.ts +1 -0
- package/src/input/modes/transitions.ts +3 -1
- package/src/input/modes/types.ts +1 -0
- package/src/pty/terminal-snapshot.ts +7 -5
- package/src/services/ai-usage/adapters/claude.ts +102 -26
- package/src/services/ai-usage/adapters/codex.ts +83 -32
- package/src/services/ai-usage/cache.ts +60 -0
- package/src/services/ai-usage/pace.ts +79 -0
- package/src/services/ai-usage/provider.ts +43 -20
- package/src/services/ai-usage/types.ts +31 -0
- package/src/state/ai-usage-store.ts +10 -3
- package/src/state/reducers/git-mode-state.ts +58 -0
- package/src/state/reducers/modal-state.ts +13 -0
- package/src/state/types.ts +18 -6
- package/src/ui/breaking-update-screen.tsx +2 -2
- package/src/ui/components/git/diff-renderer/build-rows.ts +467 -0
- package/src/ui/components/{diff-renderer → git/diff-renderer}/fold-strip.tsx +1 -1
- package/src/ui/components/git/diff-renderer/highlight.ts +102 -0
- package/src/ui/components/{diff-renderer → git/diff-renderer}/pierre-diff.tsx +23 -15
- package/src/ui/components/git/diff-renderer/prepare-diff.ts +62 -0
- package/src/ui/components/{diff-renderer → git/diff-renderer}/split-view.tsx +122 -47
- package/src/ui/components/{diff-renderer → git/diff-renderer}/stacked-view.tsx +106 -35
- package/src/ui/components/{diff-renderer → git/diff-renderer}/use-diff-prefetch.ts +8 -17
- package/src/ui/components/git/diff-renderer/use-diff-preparation.ts +240 -0
- package/src/ui/components/git/diff-renderer/use-segment-virtualization.ts +95 -0
- package/src/ui/components/{git-panel.tsx → git/git-panel.tsx} +9 -5
- package/src/ui/components/{git-view.tsx → git/git-view.tsx} +70 -37
- package/src/ui/components/{git-pane-context-menu.ts → git/pane/git-pane-context-menu.ts} +2 -2
- package/src/ui/components/{git-pane-widget.tsx → git/pane/git-pane-widget.tsx} +4 -4
- package/src/ui/components/{session-bar.tsx → layout/session-bar.tsx} +36 -13
- package/src/ui/components/{sidebar-group-metadata.ts → layout/sidebar/sidebar-group-metadata.ts} +2 -2
- package/src/ui/components/{sidebar.tsx → layout/sidebar/sidebar.tsx} +6 -6
- package/src/ui/components/{tab-item.tsx → layout/sidebar/tab-item.tsx} +5 -5
- package/src/ui/components/{use-sidebar-branch.ts → layout/sidebar/use-sidebar-branch.ts} +1 -1
- package/src/ui/components/{split-layout.tsx → layout/split-layout.tsx} +5 -5
- package/src/ui/components/{status-bar.tsx → layout/status-bar.tsx} +7 -7
- package/src/ui/components/{terminal-pane.tsx → layout/terminal-pane.tsx} +8 -8
- package/src/ui/components/modals/app/ai-usage-modal.tsx +190 -0
- package/src/ui/components/{help-modal.tsx → modals/app/help-modal.tsx} +6 -6
- package/src/ui/components/{update-available-modal.tsx → modals/app/update-available-modal.tsx} +4 -4
- package/src/ui/components/{git-commit-modal.tsx → modals/git/git-commit-modal.tsx} +8 -8
- package/src/ui/components/modals/sessions/create-session-modal.tsx +79 -0
- package/src/ui/components/modals/sessions/session-name-modal.tsx +10 -0
- package/src/ui/components/{session-picker-modal.tsx → modals/sessions/session-picker-modal.tsx} +8 -8
- package/src/ui/components/modals/shared/form.tsx +164 -0
- package/src/ui/components/{modal-keybinds-overlay.tsx → modals/shared/modal-keybinds-overlay.tsx} +7 -7
- package/src/ui/components/{modal-shell.tsx → modals/shared/modal-shell.tsx} +1 -1
- package/src/ui/components/{picker.tsx → modals/shared/picker.tsx} +3 -3
- package/src/ui/components/modals/snippets/snippet-editor-modal.tsx +30 -0
- package/src/ui/components/{snippet-picker-modal.tsx → modals/snippets/snippet-picker-modal.tsx} +6 -6
- package/src/ui/components/{new-tab-modal.tsx → modals/tabs/new-tab-modal.tsx} +17 -20
- package/src/ui/components/{theme-picker-modal.tsx → modals/themes/theme-picker-modal.tsx} +6 -6
- package/src/ui/components/{ai-usage-indicator.tsx → overlays/ai-usage/ai-usage-indicator.tsx} +56 -24
- package/src/ui/components/{context-menu-box.tsx → overlays/context-menu/context-menu-box.tsx} +1 -1
- package/src/ui/components/{context-menu-overlay.tsx → overlays/context-menu/context-menu-overlay.tsx} +3 -3
- package/src/ui/components/{pending-chord-overlay.tsx → overlays/pending-chord-overlay.tsx} +6 -6
- package/src/ui/components/{bare-input.tsx → primitives/bare-input.tsx} +2 -2
- package/src/ui/components/{input-field.tsx → primitives/input-field.tsx} +2 -2
- package/src/ui/components/{list-item.tsx → primitives/list-item.tsx} +1 -1
- package/src/ui/components/{surface.tsx → primitives/surface.tsx} +1 -1
- package/src/ui/root.tsx +26 -23
- package/src/ui/theme-store.ts +30 -26
- package/src/ui/themes.ts +1 -0
- package/src/ui/ai-usage/controller.ts +0 -35
- package/src/ui/components/ai-usage-popover.tsx +0 -152
- package/src/ui/components/create-session-modal.tsx +0 -96
- package/src/ui/components/diff-renderer/build-rows.ts +0 -349
- package/src/ui/components/diff-renderer/highlight.ts +0 -44
- package/src/ui/components/diff-renderer/prepare-diff.ts +0 -65
- package/src/ui/components/diff-renderer/use-diff-preparation.ts +0 -106
- package/src/ui/components/session-name-modal.tsx +0 -11
- package/src/ui/components/snippet-editor-modal.tsx +0 -40
- /package/src/ui/components/{diff-renderer → git/diff-renderer}/filetype.ts +0 -0
- /package/src/ui/components/{diff-renderer → git/diff-renderer}/index.ts +0 -0
- /package/src/ui/components/{sidebar-scroll.ts → layout/sidebar/sidebar-scroll.ts} +0 -0
- /package/src/ui/components/{use-sidebar-auto-scroll.ts → layout/sidebar/use-sidebar-auto-scroll.ts} +0 -0
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import type { ThemedToken } from 'shiki'
|
|
2
|
-
|
|
3
|
-
import { useEffect, useMemo, useState } from 'react'
|
|
4
|
-
|
|
5
|
-
import type { FileDiffMetadata } from '../../../diff-parser'
|
|
6
|
-
|
|
7
|
-
import { useAppStore } from '../../../state/app-store'
|
|
8
|
-
import { dispatchGlobal } from '../../../state/dispatch-ref'
|
|
9
|
-
import { getHighlightsTokens, getParsedFile } from '../../../state/types'
|
|
10
|
-
import { prepareDiff } from './prepare-diff'
|
|
11
|
-
|
|
12
|
-
export interface DiffPreparation {
|
|
13
|
-
file: FileDiffMetadata | null
|
|
14
|
-
highlights: { add: ThemedToken[][]; del: ThemedToken[][] }
|
|
15
|
-
/** True while prepare is running for this cache key + hash. */
|
|
16
|
-
preparing: boolean
|
|
17
|
-
/** Available once either cache or prepare has produced a valid hash. */
|
|
18
|
-
ready: boolean
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const EMPTY_HIGHLIGHTS = { add: [] as ThemedToken[][], del: [] as ThemedToken[][] }
|
|
22
|
-
|
|
23
|
-
// Consults the parsed + highlight caches first, then falls back to an off-thread
|
|
24
|
-
// prepareDiff that dispatches results into the store. Deduplicates in-flight
|
|
25
|
-
// preparation per cacheKey+hash by hashing the diff string once.
|
|
26
|
-
export function useDiffPreparation(
|
|
27
|
-
cacheKey: string,
|
|
28
|
-
diff: string,
|
|
29
|
-
path: string,
|
|
30
|
-
themeId: string
|
|
31
|
-
): DiffPreparation {
|
|
32
|
-
const cachedParsed = useAppStore((s) => s.gitMode.parsedFiles[cacheKey])
|
|
33
|
-
const highlightKey = `${cacheKey}|${themeId}`
|
|
34
|
-
const cachedHighlights = useAppStore((s) => s.gitMode.highlights[highlightKey])
|
|
35
|
-
|
|
36
|
-
const [preparing, setPreparing] = useState(false)
|
|
37
|
-
const [localFile, setLocalFile] = useState<FileDiffMetadata | null>(null)
|
|
38
|
-
const [localHighlights, setLocalHighlights] = useState(EMPTY_HIGHLIGHTS)
|
|
39
|
-
const [localHash, setLocalHash] = useState<string | null>(null)
|
|
40
|
-
|
|
41
|
-
const { file, highlights, ready } = useMemo(() => {
|
|
42
|
-
const parsedFile = cachedParsed ? getParsedFile(cachedParsed) : null
|
|
43
|
-
const parsedMatches = !!cachedParsed
|
|
44
|
-
const tokens = cachedHighlights ? getHighlightsTokens(cachedHighlights) : null
|
|
45
|
-
const hlMatches = !!cachedHighlights && cachedHighlights.hash === cachedParsed?.hash
|
|
46
|
-
|
|
47
|
-
if (parsedMatches && hlMatches && tokens) {
|
|
48
|
-
return { file: parsedFile, highlights: tokens, ready: true }
|
|
49
|
-
}
|
|
50
|
-
if (parsedMatches && !hlMatches) {
|
|
51
|
-
return {
|
|
52
|
-
file: parsedFile,
|
|
53
|
-
highlights: tokens ?? EMPTY_HIGHLIGHTS,
|
|
54
|
-
ready: true,
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
if (localHash && localFile) {
|
|
58
|
-
return { file: localFile, highlights: localHighlights, ready: true }
|
|
59
|
-
}
|
|
60
|
-
return { file: null, highlights: EMPTY_HIGHLIGHTS, ready: false }
|
|
61
|
-
}, [cachedParsed, cachedHighlights, localFile, localHighlights, localHash])
|
|
62
|
-
|
|
63
|
-
useEffect(() => {
|
|
64
|
-
// If caches already cover both parsed and highlights for this theme, bail.
|
|
65
|
-
const parsedOk = !!cachedParsed
|
|
66
|
-
const hlOk = !!cachedHighlights && cachedParsed && cachedHighlights.hash === cachedParsed.hash
|
|
67
|
-
if (parsedOk && hlOk) return
|
|
68
|
-
|
|
69
|
-
const controller = new AbortController()
|
|
70
|
-
setPreparing(true)
|
|
71
|
-
void prepareDiff(diff, path, { signal: controller.signal })
|
|
72
|
-
.then((result) => {
|
|
73
|
-
if (controller.signal.aborted) return
|
|
74
|
-
setLocalFile(result.file)
|
|
75
|
-
setLocalHighlights(result.highlights)
|
|
76
|
-
setLocalHash(result.hash)
|
|
77
|
-
dispatchGlobal({
|
|
78
|
-
file: result.file,
|
|
79
|
-
hash: result.hash,
|
|
80
|
-
key: cacheKey,
|
|
81
|
-
type: 'git-mode-set-parsed',
|
|
82
|
-
})
|
|
83
|
-
dispatchGlobal({
|
|
84
|
-
add: result.highlights.add,
|
|
85
|
-
del: result.highlights.del,
|
|
86
|
-
hash: result.hash,
|
|
87
|
-
key: cacheKey,
|
|
88
|
-
themeId,
|
|
89
|
-
type: 'git-mode-set-highlights',
|
|
90
|
-
})
|
|
91
|
-
})
|
|
92
|
-
.catch((err: unknown) => {
|
|
93
|
-
if (err instanceof Error && err.name === 'AbortError') return
|
|
94
|
-
// Swallow — the UI falls back to "(could not parse diff)" when file stays null.
|
|
95
|
-
})
|
|
96
|
-
.finally(() => {
|
|
97
|
-
if (!controller.signal.aborted) setPreparing(false)
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
return () => {
|
|
101
|
-
controller.abort()
|
|
102
|
-
}
|
|
103
|
-
}, [cacheKey, diff, path, themeId, cachedParsed, cachedHighlights])
|
|
104
|
-
|
|
105
|
-
return { file, highlights, preparing, ready }
|
|
106
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { uiTokens } from '../ui-tokens'
|
|
2
|
-
import { InputField } from './input-field'
|
|
3
|
-
import { ModalShell } from './modal-shell'
|
|
4
|
-
|
|
5
|
-
export function SessionNameModal({ title, value }: { title: string; value: string }) {
|
|
6
|
-
return (
|
|
7
|
-
<ModalShell title={title} keybindsModeId="modal.session-name" width={uiTokens.modalWidth.md}>
|
|
8
|
-
<InputField active value={value} />
|
|
9
|
-
</ModalShell>
|
|
10
|
-
)
|
|
11
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { useTokens } from '../theme'
|
|
2
|
-
import { uiTokens } from '../ui-tokens'
|
|
3
|
-
import { InputField } from './input-field'
|
|
4
|
-
import { ModalShell } from './modal-shell'
|
|
5
|
-
|
|
6
|
-
interface SnippetEditorModalProps {
|
|
7
|
-
activeField: 'name' | 'content'
|
|
8
|
-
snippetName: string
|
|
9
|
-
snippetContent: string
|
|
10
|
-
isEditing: boolean
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function SnippetEditorModal({
|
|
14
|
-
activeField,
|
|
15
|
-
isEditing,
|
|
16
|
-
snippetContent,
|
|
17
|
-
snippetName,
|
|
18
|
-
}: SnippetEditorModalProps) {
|
|
19
|
-
const t = useTokens()
|
|
20
|
-
const nameActive = activeField === 'name'
|
|
21
|
-
const contentActive = activeField === 'content'
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<ModalShell
|
|
25
|
-
title={isEditing ? 'Edit snippet' : 'Create snippet'}
|
|
26
|
-
keybindsModeId="modal.snippet-editor"
|
|
27
|
-
width={uiTokens.modalWidth.xl}
|
|
28
|
-
>
|
|
29
|
-
<box flexDirection="column">
|
|
30
|
-
<text fg={nameActive ? t.palette.ink : t.muted}>Name</text>
|
|
31
|
-
<InputField active={nameActive} value={snippetName} />
|
|
32
|
-
</box>
|
|
33
|
-
|
|
34
|
-
<box flexDirection="column">
|
|
35
|
-
<text fg={contentActive ? t.palette.ink : t.muted}>Content</text>
|
|
36
|
-
<InputField active={contentActive} value={snippetContent} />
|
|
37
|
-
</box>
|
|
38
|
-
</ModalShell>
|
|
39
|
-
)
|
|
40
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/src/ui/components/{use-sidebar-auto-scroll.ts → layout/sidebar/use-sidebar-auto-scroll.ts}
RENAMED
|
File without changes
|