@brimveyn/aimux 1.9.3 → 1.9.5
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",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.5",
|
|
4
4
|
"description": "A terminal multiplexer for AI CLIs. Run Claude, Codex, OpenCode side-by-side with tabbed navigation, split panes, and persistent sessions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"bump": "bun run scripts/bump.ts"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@brimveyn/aimux-config": "0.5.
|
|
63
|
+
"@brimveyn/aimux-config": "0.5.5",
|
|
64
64
|
"@opentui/core": "^0.1.90",
|
|
65
65
|
"@opentui/react": "^0.1.90",
|
|
66
66
|
"@xterm/headless": "^6.0.0",
|
|
@@ -548,6 +548,16 @@ export function executeSideEffect(effect: SideEffect, ctx: SideEffectContext): v
|
|
|
548
548
|
)
|
|
549
549
|
return
|
|
550
550
|
}
|
|
551
|
+
case 'git-stage-all': {
|
|
552
|
+
const paths = ctx.state.gitPanel.files.map((f) => f.path)
|
|
553
|
+
void enqueueGitOp(() => runGitActionAll(ctx, ['add', '-A'], paths))
|
|
554
|
+
return
|
|
555
|
+
}
|
|
556
|
+
case 'git-unstage-all': {
|
|
557
|
+
const paths = ctx.state.gitPanel.files.map((f) => f.path)
|
|
558
|
+
void enqueueGitOp(() => runGitActionAll(ctx, ['reset'], paths))
|
|
559
|
+
return
|
|
560
|
+
}
|
|
551
561
|
case 'git-restore': {
|
|
552
562
|
void enqueueGitOp(() => runGitAction(ctx, ['restore', '--', effect.path], effect.path))
|
|
553
563
|
return
|
|
@@ -670,6 +680,25 @@ async function runGitAction(
|
|
|
670
680
|
}
|
|
671
681
|
}
|
|
672
682
|
|
|
683
|
+
async function runGitActionAll(
|
|
684
|
+
ctx: SideEffectContext,
|
|
685
|
+
args: string[],
|
|
686
|
+
pathsToInvalidate: string[]
|
|
687
|
+
): Promise<void> {
|
|
688
|
+
const cwd = ctx.getCurrentSessionProjectPath()
|
|
689
|
+
if (!cwd) return
|
|
690
|
+
const result = await $`git -C ${cwd} ${args}`.quiet().nothrow()
|
|
691
|
+
if (result.exitCode !== 0) {
|
|
692
|
+
const stderr = result.stderr.toString().trim()
|
|
693
|
+
ctx.dispatch({ message: stderr || 'git action failed', type: 'git-mode-set-message' })
|
|
694
|
+
return
|
|
695
|
+
}
|
|
696
|
+
ctx.dispatch({ message: null, type: 'git-mode-set-message' })
|
|
697
|
+
if (pathsToInvalidate.length > 0) {
|
|
698
|
+
ctx.dispatch({ paths: pathsToInvalidate, type: 'git-mode-invalidate-diffs' })
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
673
702
|
async function runGitRm(ctx: SideEffectContext, path: string): Promise<void> {
|
|
674
703
|
const repoPath = ctx.state.gitPanel.files.find((f) => f.path === path)?.repoPath
|
|
675
704
|
const cwd = repoPath ?? ctx.getCurrentSessionProjectPath()
|
package/src/input/modes/types.ts
CHANGED
|
@@ -55,6 +55,8 @@ export type SideEffect =
|
|
|
55
55
|
| { type: 'persist-git-tree-compaction'; enabled: boolean }
|
|
56
56
|
| { type: 'git-stage'; path: string }
|
|
57
57
|
| { type: 'git-unstage'; path: string }
|
|
58
|
+
| { type: 'git-stage-all' }
|
|
59
|
+
| { type: 'git-unstage-all' }
|
|
58
60
|
| { type: 'git-restore'; path: string }
|
|
59
61
|
| { type: 'git-rm'; path: string }
|
|
60
62
|
| { type: 'git-commit'; title: string; body: string }
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { PreparedParsedDiff } from '../../ui/components/git/diff-renderer/prepare-diff'
|
|
2
2
|
|
|
3
|
+
import { collectFoldables } from '../../ui/components/git/diff-renderer/build-rows'
|
|
3
4
|
import {
|
|
4
5
|
getSelectedGitRow,
|
|
5
6
|
gitFileKey,
|
|
@@ -7,6 +8,14 @@ import {
|
|
|
7
8
|
moveGitSelection,
|
|
8
9
|
reconcileSelectedGitEntryKey,
|
|
9
10
|
} from '../git-tree'
|
|
11
|
+
import {
|
|
12
|
+
type AppAction,
|
|
13
|
+
type AppState,
|
|
14
|
+
type FoldState,
|
|
15
|
+
getParsedPayload,
|
|
16
|
+
type GitFileEntry,
|
|
17
|
+
type GitModeState,
|
|
18
|
+
} from '../types'
|
|
10
19
|
import { clearDiffCacheForPath, clearDiffCacheForPaths } from './diff-cache'
|
|
11
20
|
import { sortFilesBySection } from './git-panel-state'
|
|
12
21
|
|
|
@@ -439,6 +448,29 @@ export function reduceGitModeState(state: AppState, action: AppAction): AppState
|
|
|
439
448
|
const bottom = Math.max(0, action.bottom)
|
|
440
449
|
return applyFold(state, action.key, action.foldId, { bottom, top })
|
|
441
450
|
}
|
|
451
|
+
case 'git-mode-fold-toggle-all': {
|
|
452
|
+
const parsed = getParsedPayload<PreparedParsedDiff>(state.gitMode.parsedFiles[action.key])
|
|
453
|
+
const file = parsed?.file
|
|
454
|
+
if (!file || !Array.isArray(file.hunks)) return state
|
|
455
|
+
const foldables = collectFoldables(file)
|
|
456
|
+
if (foldables.length === 0) return state
|
|
457
|
+
const current = state.gitMode.folds[action.key] ?? {}
|
|
458
|
+
const allExpanded = foldables.every(({ foldId, middle }) => {
|
|
459
|
+
const fs = current[foldId] ?? { bottom: 0, top: 0 }
|
|
460
|
+
return fs.top + fs.bottom >= middle
|
|
461
|
+
})
|
|
462
|
+
const nextFolds = { ...state.gitMode.folds }
|
|
463
|
+
if (allExpanded) {
|
|
464
|
+
delete nextFolds[action.key]
|
|
465
|
+
} else {
|
|
466
|
+
const perPath: Record<string, FoldState> = {}
|
|
467
|
+
for (const { foldId, middle } of foldables) {
|
|
468
|
+
perPath[foldId] = { bottom: 0, top: middle }
|
|
469
|
+
}
|
|
470
|
+
nextFolds[action.key] = perPath
|
|
471
|
+
}
|
|
472
|
+
return { ...state, gitMode: { ...state.gitMode, folds: nextFolds } }
|
|
473
|
+
}
|
|
442
474
|
case 'git-mode-optimistic-move': {
|
|
443
475
|
const currentKey = state.gitMode.selectedEntryKey
|
|
444
476
|
const files = state.gitPanel.files
|
package/src/state/types.ts
CHANGED
|
@@ -650,6 +650,7 @@ export type GitModeAction =
|
|
|
650
650
|
delta: number
|
|
651
651
|
}
|
|
652
652
|
| { type: 'git-mode-fold-set'; key: string; foldId: string; top: number; bottom: number }
|
|
653
|
+
| { type: 'git-mode-fold-toggle-all'; key: string }
|
|
653
654
|
| {
|
|
654
655
|
type: 'git-mode-optimistic-move'
|
|
655
656
|
path: string
|
|
@@ -181,6 +181,27 @@ function contextNeighbors(
|
|
|
181
181
|
return { hasChangeAfter, hasChangeBefore }
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
export interface Foldable {
|
|
185
|
+
foldId: string
|
|
186
|
+
middle: number
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export function collectFoldables(file: FileDiffMetadata): Foldable[] {
|
|
190
|
+
const result: Foldable[] = []
|
|
191
|
+
for (const [hIdx, hunk] of file.hunks.entries()) {
|
|
192
|
+
for (const [cIdx, content] of hunk.hunkContent.entries()) {
|
|
193
|
+
if (content.type !== 'context') continue
|
|
194
|
+
const { hasChangeAfter, hasChangeBefore } = contextNeighbors(hunk.hunkContent, cIdx)
|
|
195
|
+
const preKeep = hasChangeBefore ? Math.min(KEEP_CONTEXT, content.lines) : 0
|
|
196
|
+
const postKeep = hasChangeAfter ? Math.min(KEEP_CONTEXT, content.lines - preKeep) : 0
|
|
197
|
+
const middle = content.lines - preKeep - postKeep
|
|
198
|
+
if (middle < MIN_FOLD_SIZE) continue
|
|
199
|
+
result.push({ foldId: `${hIdx}:${cIdx}`, middle })
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return result
|
|
203
|
+
}
|
|
204
|
+
|
|
184
205
|
export function buildDiffSegments(file: FileDiffMetadata, folds: FoldMap = {}): DiffSegmentBuild {
|
|
185
206
|
const segments: DiffSegment[] = []
|
|
186
207
|
let offset = 0
|