@akiojin/gwt 4.11.6 → 4.12.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/bin/gwt.js +1 -1
- package/dist/claude.d.ts +1 -0
- package/dist/claude.d.ts.map +1 -1
- package/dist/claude.js +50 -24
- package/dist/claude.js.map +1 -1
- package/dist/cli/ui/App.solid.d.ts.map +1 -1
- package/dist/cli/ui/App.solid.js +247 -49
- package/dist/cli/ui/App.solid.js.map +1 -1
- package/dist/cli/ui/components/solid/QuickStartStep.d.ts.map +1 -1
- package/dist/cli/ui/components/solid/QuickStartStep.js +35 -22
- package/dist/cli/ui/components/solid/QuickStartStep.js.map +1 -1
- package/dist/cli/ui/components/solid/SelectInput.d.ts.map +1 -1
- package/dist/cli/ui/components/solid/SelectInput.js +2 -1
- package/dist/cli/ui/components/solid/SelectInput.js.map +1 -1
- package/dist/cli/ui/components/solid/WizardController.d.ts.map +1 -1
- package/dist/cli/ui/components/solid/WizardController.js +19 -11
- package/dist/cli/ui/components/solid/WizardController.js.map +1 -1
- package/dist/cli/ui/components/solid/WizardSteps.d.ts.map +1 -1
- package/dist/cli/ui/components/solid/WizardSteps.js +26 -69
- package/dist/cli/ui/components/solid/WizardSteps.js.map +1 -1
- package/dist/cli/ui/core/theme.d.ts +9 -0
- package/dist/cli/ui/core/theme.d.ts.map +1 -1
- package/dist/cli/ui/core/theme.js +21 -0
- package/dist/cli/ui/core/theme.js.map +1 -1
- package/dist/cli/ui/screens/solid/BranchListScreen.d.ts +9 -2
- package/dist/cli/ui/screens/solid/BranchListScreen.d.ts.map +1 -1
- package/dist/cli/ui/screens/solid/BranchListScreen.js +101 -28
- package/dist/cli/ui/screens/solid/BranchListScreen.js.map +1 -1
- package/dist/cli/ui/screens/solid/ConfirmScreen.d.ts +2 -1
- package/dist/cli/ui/screens/solid/ConfirmScreen.d.ts.map +1 -1
- package/dist/cli/ui/screens/solid/ConfirmScreen.js +11 -3
- package/dist/cli/ui/screens/solid/ConfirmScreen.js.map +1 -1
- package/dist/cli/ui/screens/solid/EnvironmentScreen.d.ts.map +1 -1
- package/dist/cli/ui/screens/solid/EnvironmentScreen.js +9 -10
- package/dist/cli/ui/screens/solid/EnvironmentScreen.js.map +1 -1
- package/dist/cli/ui/screens/solid/LogScreen.d.ts +7 -1
- package/dist/cli/ui/screens/solid/LogScreen.d.ts.map +1 -1
- package/dist/cli/ui/screens/solid/LogScreen.js +254 -16
- package/dist/cli/ui/screens/solid/LogScreen.js.map +1 -1
- package/dist/cli/ui/screens/solid/ProfileEnvScreen.d.ts.map +1 -1
- package/dist/cli/ui/screens/solid/ProfileEnvScreen.js +8 -5
- package/dist/cli/ui/screens/solid/ProfileEnvScreen.js.map +1 -1
- package/dist/cli/ui/screens/solid/SelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/screens/solid/SelectorScreen.js +12 -4
- package/dist/cli/ui/screens/solid/SelectorScreen.js.map +1 -1
- package/dist/cli/ui/types.d.ts +1 -0
- package/dist/cli/ui/types.d.ts.map +1 -1
- package/dist/cli/ui/utils/branchFormatter.d.ts +1 -0
- package/dist/cli/ui/utils/branchFormatter.d.ts.map +1 -1
- package/dist/cli/ui/utils/branchFormatter.js +29 -7
- package/dist/cli/ui/utils/branchFormatter.js.map +1 -1
- package/dist/cli/ui/utils/continueSession.d.ts +14 -0
- package/dist/cli/ui/utils/continueSession.d.ts.map +1 -1
- package/dist/cli/ui/utils/continueSession.js +61 -3
- package/dist/cli/ui/utils/continueSession.js.map +1 -1
- package/dist/cli/ui/utils/versionCache.d.ts +37 -0
- package/dist/cli/ui/utils/versionCache.d.ts.map +1 -0
- package/dist/cli/ui/utils/versionCache.js +70 -0
- package/dist/cli/ui/utils/versionCache.js.map +1 -0
- package/dist/cli/ui/utils/versionFetcher.d.ts +41 -0
- package/dist/cli/ui/utils/versionFetcher.d.ts.map +1 -0
- package/dist/cli/ui/utils/versionFetcher.js +89 -0
- package/dist/cli/ui/utils/versionFetcher.js.map +1 -0
- package/dist/codex.d.ts +1 -0
- package/dist/codex.d.ts.map +1 -1
- package/dist/codex.js +48 -19
- package/dist/codex.js.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +10 -1
- package/dist/config/index.js.map +1 -1
- package/dist/gemini.d.ts +1 -0
- package/dist/gemini.d.ts.map +1 -1
- package/dist/gemini.js +36 -3
- package/dist/gemini.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -2
- package/dist/index.js.map +1 -1
- package/dist/launcher.d.ts.map +1 -1
- package/dist/launcher.js +43 -8
- package/dist/launcher.js.map +1 -1
- package/dist/logging/agentOutput.d.ts +21 -0
- package/dist/logging/agentOutput.d.ts.map +1 -0
- package/dist/logging/agentOutput.js +164 -0
- package/dist/logging/agentOutput.js.map +1 -0
- package/dist/logging/formatter.d.ts.map +1 -1
- package/dist/logging/formatter.js +18 -4
- package/dist/logging/formatter.js.map +1 -1
- package/dist/logging/logger.d.ts.map +1 -1
- package/dist/logging/logger.js +2 -0
- package/dist/logging/logger.js.map +1 -1
- package/dist/logging/reader.d.ts +21 -0
- package/dist/logging/reader.d.ts.map +1 -1
- package/dist/logging/reader.js +79 -0
- package/dist/logging/reader.js.map +1 -1
- package/dist/opentui/index.solid.js +2306 -653
- package/dist/services/dependency-installer.js +2 -2
- package/dist/services/dependency-installer.js.map +1 -1
- package/dist/utils/session/common.d.ts +8 -0
- package/dist/utils/session/common.d.ts.map +1 -1
- package/dist/utils/session/common.js +22 -0
- package/dist/utils/session/common.js.map +1 -1
- package/dist/utils/session/parsers/claude.d.ts +10 -4
- package/dist/utils/session/parsers/claude.d.ts.map +1 -1
- package/dist/utils/session/parsers/claude.js +64 -18
- package/dist/utils/session/parsers/claude.js.map +1 -1
- package/dist/utils/session/parsers/codex.d.ts.map +1 -1
- package/dist/utils/session/parsers/codex.js +48 -28
- package/dist/utils/session/parsers/codex.js.map +1 -1
- package/dist/utils/session/parsers/gemini.d.ts.map +1 -1
- package/dist/utils/session/parsers/gemini.js +43 -6
- package/dist/utils/session/parsers/gemini.js.map +1 -1
- package/dist/utils/session/parsers/opencode.d.ts.map +1 -1
- package/dist/utils/session/parsers/opencode.js +43 -6
- package/dist/utils/session/parsers/opencode.js.map +1 -1
- package/dist/utils/session/types.d.ts +7 -0
- package/dist/utils/session/types.d.ts.map +1 -1
- package/dist/web/client/src/components/ui/alert.d.ts +1 -1
- package/dist/worktree.d.ts +4 -1
- package/dist/worktree.d.ts.map +1 -1
- package/dist/worktree.js +21 -15
- package/dist/worktree.js.map +1 -1
- package/package.json +2 -1
- package/src/claude.ts +64 -28
- package/src/cli/ui/App.solid.tsx +324 -51
- package/src/cli/ui/__tests__/solid/AppSolid.cleanup.test.tsx +830 -1
- package/src/cli/ui/__tests__/solid/BranchListScreen.test.tsx +105 -5
- package/src/cli/ui/__tests__/solid/ConfirmScreen.test.tsx +77 -0
- package/src/cli/ui/__tests__/solid/LogScreen.test.tsx +351 -0
- package/src/cli/ui/__tests__/solid/components/QuickStartStep.test.tsx +73 -2
- package/src/cli/ui/__tests__/solid/components/WizardSteps.test.tsx +4 -1
- package/src/cli/ui/__tests__/utils/branchFormatter.test.ts +72 -45
- package/src/cli/ui/components/solid/QuickStartStep.tsx +35 -23
- package/src/cli/ui/components/solid/SearchInput.tsx +1 -1
- package/src/cli/ui/components/solid/SelectInput.tsx +4 -0
- package/src/cli/ui/components/solid/WizardController.tsx +20 -11
- package/src/cli/ui/components/solid/WizardSteps.tsx +29 -86
- package/src/cli/ui/core/theme.ts +32 -0
- package/src/cli/ui/hooks/solid/useAsyncOperation.ts +8 -6
- package/src/cli/ui/hooks/solid/useGitOperations.ts +6 -5
- package/src/cli/ui/screens/solid/BranchListScreen.tsx +135 -32
- package/src/cli/ui/screens/solid/ConfirmScreen.tsx +20 -8
- package/src/cli/ui/screens/solid/EnvironmentScreen.tsx +22 -20
- package/src/cli/ui/screens/solid/LogScreen.tsx +364 -35
- package/src/cli/ui/screens/solid/ProfileEnvScreen.tsx +19 -15
- package/src/cli/ui/screens/solid/SelectorScreen.tsx +25 -14
- package/src/cli/ui/screens/solid/SettingsScreen.tsx +5 -3
- package/src/cli/ui/types.ts +1 -0
- package/src/cli/ui/utils/__tests__/branchFormatter.test.ts +53 -6
- package/src/cli/ui/utils/branchFormatter.ts +35 -7
- package/src/cli/ui/utils/continueSession.ts +90 -3
- package/src/cli/ui/utils/versionCache.ts +93 -0
- package/src/cli/ui/utils/versionFetcher.ts +120 -0
- package/src/codex.ts +62 -20
- package/src/config/__tests__/saveSession.test.ts +2 -2
- package/src/config/index.ts +11 -1
- package/src/gemini.ts +50 -4
- package/src/index.test.ts +16 -10
- package/src/index.ts +38 -1
- package/src/launcher.ts +49 -8
- package/src/logging/agentOutput.ts +216 -0
- package/src/logging/formatter.ts +23 -4
- package/src/logging/logger.ts +2 -0
- package/src/logging/reader.ts +117 -0
- package/src/services/__tests__/BatchMergeService.test.ts +34 -14
- package/src/services/dependency-installer.ts +2 -2
- package/src/utils/session/common.ts +28 -0
- package/src/utils/session/parsers/claude.ts +79 -29
- package/src/utils/session/parsers/codex.ts +50 -26
- package/src/utils/session/parsers/gemini.ts +46 -5
- package/src/utils/session/parsers/opencode.ts +46 -5
- package/src/utils/session/types.ts +4 -0
- package/src/worktree.ts +28 -15
|
@@ -5,8 +5,8 @@ import {
|
|
|
5
5
|
createWorktree,
|
|
6
6
|
generateWorktreePath,
|
|
7
7
|
removeWorktree,
|
|
8
|
-
} from "
|
|
9
|
-
import { deleteBranch, getRepositoryRoot } from "
|
|
8
|
+
} from "../../../../worktree.js";
|
|
9
|
+
import { deleteBranch, getRepositoryRoot } from "../../../../git.js";
|
|
10
10
|
|
|
11
11
|
export interface UseGitOperationsResult {
|
|
12
12
|
state: Accessor<AsyncState<unknown>>;
|
|
@@ -36,9 +36,10 @@ export function useGitOperations(): UseGitOperationsResult {
|
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
const isLoading = createMemo(() => state().status === "loading");
|
|
39
|
-
const error = createMemo(() =>
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
const error = createMemo(() => {
|
|
40
|
+
const current = state();
|
|
41
|
+
return current.status === "error" ? current.error : null;
|
|
42
|
+
});
|
|
42
43
|
|
|
43
44
|
const run = async <T>(operation: () => Promise<T>): Promise<T> => {
|
|
44
45
|
setState({ status: "loading" });
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
|
-
import { createEffect, createMemo, createSignal } from "solid-js";
|
|
2
|
+
import { createEffect, createMemo, createSignal, on } from "solid-js";
|
|
3
3
|
import { useKeyboard, useTerminalDimensions } from "@opentui/solid";
|
|
4
4
|
import { TextAttributes } from "@opentui/core";
|
|
5
5
|
import type { BranchItem, BranchViewMode, Statistics } from "../../types.js";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
formatLocalDateTime,
|
|
8
|
+
getLatestActivityTimestamp,
|
|
9
|
+
} from "../../utils/branchFormatter.js";
|
|
7
10
|
import stringWidth from "string-width";
|
|
8
11
|
import { getAgentTerminalColor } from "../../../../utils/coding-agent-colors.js";
|
|
9
12
|
import { Header } from "../../components/solid/Header.js";
|
|
10
|
-
|
|
13
|
+
import { selectionStyle } from "../../core/theme.js";
|
|
14
|
+
type IndicatorColor = "cyan" | "green" | "yellow" | "red" | "brightGreen";
|
|
11
15
|
|
|
12
16
|
interface CleanupIndicator {
|
|
13
17
|
icon: string;
|
|
@@ -26,6 +30,7 @@ interface CleanupUIState {
|
|
|
26
30
|
footerMessage: CleanupFooterMessage | null;
|
|
27
31
|
inputLocked: boolean;
|
|
28
32
|
safetyLoading?: boolean;
|
|
33
|
+
safetyPendingBranches?: Set<string>;
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
export interface BranchListScreenProps {
|
|
@@ -38,7 +43,7 @@ export interface BranchListScreenProps {
|
|
|
38
43
|
onCreateBranch?: (branch: BranchItem | null) => void;
|
|
39
44
|
onRefresh?: () => void;
|
|
40
45
|
onOpenProfiles?: () => void;
|
|
41
|
-
onOpenLogs?: () => void;
|
|
46
|
+
onOpenLogs?: (branch: BranchItem | null) => void;
|
|
42
47
|
loading?: boolean;
|
|
43
48
|
error?: Error | null;
|
|
44
49
|
lastUpdated?: Date | null;
|
|
@@ -52,6 +57,12 @@ export interface BranchListScreenProps {
|
|
|
52
57
|
helpVisible?: boolean;
|
|
53
58
|
/** ウィザードポップアップ表示中は入力を無効化 */
|
|
54
59
|
wizardVisible?: boolean;
|
|
60
|
+
/** 確認ダイアログ表示中は入力を無効化 */
|
|
61
|
+
confirmVisible?: boolean;
|
|
62
|
+
/** カーソル位置(外部から制御する場合) */
|
|
63
|
+
cursorPosition?: number;
|
|
64
|
+
/** カーソル位置変更時のコールバック */
|
|
65
|
+
onCursorPositionChange?: (index: number) => void;
|
|
55
66
|
}
|
|
56
67
|
|
|
57
68
|
const VIEW_MODES: BranchViewMode[] = ["all", "local", "remote"];
|
|
@@ -190,8 +201,8 @@ const fitSegmentsToWidth = (
|
|
|
190
201
|
const applySelectionStyle = (segments: TextSegment[]): TextSegment[] =>
|
|
191
202
|
segments.map((segment) => ({
|
|
192
203
|
text: segment.text,
|
|
193
|
-
fg:
|
|
194
|
-
bg:
|
|
204
|
+
fg: selectionStyle.fg,
|
|
205
|
+
bg: selectionStyle.bg,
|
|
195
206
|
}));
|
|
196
207
|
|
|
197
208
|
const CLEANUP_SPINNER_FRAMES = ["-", "\\", "|", "/"];
|
|
@@ -298,7 +309,21 @@ export function BranchListScreen(props: BranchListScreenProps) {
|
|
|
298
309
|
const [filterQuery, setFilterQuery] = createSignal("");
|
|
299
310
|
const [filterMode, setFilterMode] = createSignal(false);
|
|
300
311
|
const [viewMode, setViewMode] = createSignal<BranchViewMode>("all");
|
|
301
|
-
|
|
312
|
+
|
|
313
|
+
// カーソル位置: 外部制御(props.cursorPosition)が優先、なければ内部状態を使用
|
|
314
|
+
const [internalSelectedIndex, setInternalSelectedIndex] = createSignal(
|
|
315
|
+
props.cursorPosition ?? 0,
|
|
316
|
+
);
|
|
317
|
+
const selectedIndex = () => props.cursorPosition ?? internalSelectedIndex();
|
|
318
|
+
const setSelectedIndex = (
|
|
319
|
+
value: number | ((prev: number) => number),
|
|
320
|
+
): void => {
|
|
321
|
+
const newValue =
|
|
322
|
+
typeof value === "function" ? value(selectedIndex()) : value;
|
|
323
|
+
setInternalSelectedIndex(newValue);
|
|
324
|
+
props.onCursorPositionChange?.(newValue);
|
|
325
|
+
};
|
|
326
|
+
|
|
302
327
|
const [scrollOffset, setScrollOffset] = createSignal(0);
|
|
303
328
|
const [cleanupSpinnerIndex, setCleanupSpinnerIndex] = createSignal(0);
|
|
304
329
|
const [cursorIndex, setCursorIndex] = createSignal(0);
|
|
@@ -345,11 +370,17 @@ export function BranchListScreen(props: BranchListScreenProps) {
|
|
|
345
370
|
() => props.cleanupUI?.footerMessage?.isSpinning ?? false,
|
|
346
371
|
);
|
|
347
372
|
|
|
373
|
+
const safetyPendingActive = createMemo(() => {
|
|
374
|
+
const pending = props.cleanupUI?.safetyPendingBranches;
|
|
375
|
+
if (pending) {
|
|
376
|
+
return pending.size > 0;
|
|
377
|
+
}
|
|
378
|
+
return props.cleanupUI?.safetyLoading === true;
|
|
379
|
+
});
|
|
380
|
+
|
|
348
381
|
const cleanupSpinnerActive = createMemo(
|
|
349
382
|
() =>
|
|
350
|
-
hasSpinningIndicator() ||
|
|
351
|
-
hasSpinningFooter() ||
|
|
352
|
-
props.cleanupUI?.safetyLoading === true,
|
|
383
|
+
hasSpinningIndicator() || hasSpinningFooter() || safetyPendingActive(),
|
|
353
384
|
);
|
|
354
385
|
|
|
355
386
|
createEffect(() => {
|
|
@@ -423,12 +454,18 @@ export function BranchListScreen(props: BranchListScreenProps) {
|
|
|
423
454
|
return maxWidth;
|
|
424
455
|
});
|
|
425
456
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
457
|
+
// FR-037 / FR-037a: filterQueryまたはviewModeが実際に変更されたときのみカーソルをリセット
|
|
458
|
+
// defer: true により初回実行をスキップし、安全状態更新時のリセットを防止
|
|
459
|
+
createEffect(
|
|
460
|
+
on(
|
|
461
|
+
() => [filterQuery(), viewMode()],
|
|
462
|
+
() => {
|
|
463
|
+
setSelectedIndex(0);
|
|
464
|
+
setScrollOffset(0);
|
|
465
|
+
},
|
|
466
|
+
{ defer: true },
|
|
467
|
+
),
|
|
468
|
+
);
|
|
432
469
|
|
|
433
470
|
createEffect(() => {
|
|
434
471
|
const total = filteredBranches().length;
|
|
@@ -489,14 +526,8 @@ export function BranchListScreen(props: BranchListScreenProps) {
|
|
|
489
526
|
return "---";
|
|
490
527
|
}
|
|
491
528
|
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
495
|
-
const day = String(date.getDate()).padStart(2, "0");
|
|
496
|
-
const hours = String(date.getHours()).padStart(2, "0");
|
|
497
|
-
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
498
|
-
|
|
499
|
-
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
|
529
|
+
const formatted = formatLocalDateTime(timestamp * 1000);
|
|
530
|
+
return formatted || "---";
|
|
500
531
|
};
|
|
501
532
|
|
|
502
533
|
useKeyboard((key) => {
|
|
@@ -504,6 +535,9 @@ export function BranchListScreen(props: BranchListScreenProps) {
|
|
|
504
535
|
if (props.wizardVisible) {
|
|
505
536
|
return;
|
|
506
537
|
}
|
|
538
|
+
if (props.confirmVisible) {
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
507
541
|
if (props.helpVisible) {
|
|
508
542
|
return;
|
|
509
543
|
}
|
|
@@ -632,7 +666,8 @@ export function BranchListScreen(props: BranchListScreenProps) {
|
|
|
632
666
|
} else if (key.name === "p" || key.sequence === "p") {
|
|
633
667
|
props.onOpenProfiles?.();
|
|
634
668
|
} else if (key.name === "l" || key.sequence === "l") {
|
|
635
|
-
|
|
669
|
+
const selected = filteredBranches()[selectedIndex()] ?? null;
|
|
670
|
+
props.onOpenLogs?.(selected);
|
|
636
671
|
}
|
|
637
672
|
});
|
|
638
673
|
|
|
@@ -667,13 +702,17 @@ export function BranchListScreen(props: BranchListScreenProps) {
|
|
|
667
702
|
let worktreeColor: IndicatorColor | "gray" = "gray";
|
|
668
703
|
if (branch.worktreeStatus === "active") {
|
|
669
704
|
worktreeIcon = "w";
|
|
670
|
-
worktreeColor = "
|
|
705
|
+
worktreeColor = "brightGreen";
|
|
671
706
|
} else if (branch.worktreeStatus === "inaccessible") {
|
|
672
707
|
worktreeIcon = "x";
|
|
673
708
|
worktreeColor = "red";
|
|
674
709
|
}
|
|
675
710
|
const isRemoteBranch = branch.type === "remote";
|
|
676
711
|
const safetyLoading = props.cleanupUI?.safetyLoading === true;
|
|
712
|
+
const safetyPendingBranches = props.cleanupUI?.safetyPendingBranches;
|
|
713
|
+
const isSafetyPending = safetyPendingBranches
|
|
714
|
+
? safetyPendingBranches.has(branch.name)
|
|
715
|
+
: safetyLoading;
|
|
677
716
|
const spinnerFrame = cleanupSpinnerFrame();
|
|
678
717
|
|
|
679
718
|
let safeIcon = " ";
|
|
@@ -681,6 +720,9 @@ export function BranchListScreen(props: BranchListScreenProps) {
|
|
|
681
720
|
if (isRemoteBranch) {
|
|
682
721
|
safeIcon = " ";
|
|
683
722
|
safeColor = undefined;
|
|
723
|
+
} else if (isSafetyPending) {
|
|
724
|
+
safeIcon = spinnerFrame ?? "-";
|
|
725
|
+
safeColor = undefined;
|
|
684
726
|
} else if (hasUncommitted) {
|
|
685
727
|
safeIcon = "!";
|
|
686
728
|
safeColor = "red";
|
|
@@ -690,12 +732,9 @@ export function BranchListScreen(props: BranchListScreenProps) {
|
|
|
690
732
|
} else if (branch.isUnmerged) {
|
|
691
733
|
safeIcon = "*";
|
|
692
734
|
safeColor = "yellow";
|
|
693
|
-
} else if (safetyLoading) {
|
|
694
|
-
safeIcon = spinnerFrame ?? "-";
|
|
695
|
-
safeColor = undefined;
|
|
696
735
|
} else if (branch.safeToCleanup === true) {
|
|
697
|
-
safeIcon = "
|
|
698
|
-
safeColor =
|
|
736
|
+
safeIcon = "o";
|
|
737
|
+
safeColor = "brightGreen";
|
|
699
738
|
} else {
|
|
700
739
|
safeIcon = "!";
|
|
701
740
|
safeColor = "red";
|
|
@@ -886,6 +925,70 @@ export function BranchListScreen(props: BranchListScreenProps) {
|
|
|
886
925
|
return fitSegmentsToWidth(segments, layoutWidth());
|
|
887
926
|
});
|
|
888
927
|
|
|
928
|
+
const statusLegendSegments = createMemo(() => {
|
|
929
|
+
const segments: TextSegment[] = [];
|
|
930
|
+
const separator = " ";
|
|
931
|
+
|
|
932
|
+
appendSegment(segments, {
|
|
933
|
+
text: "Legend: ",
|
|
934
|
+
attributes: TextAttributes.DIM,
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
appendSegment(segments, {
|
|
938
|
+
text: "o",
|
|
939
|
+
fg: "brightGreen",
|
|
940
|
+
attributes: TextAttributes.BOLD,
|
|
941
|
+
});
|
|
942
|
+
appendSegment(segments, {
|
|
943
|
+
text: " Safe",
|
|
944
|
+
fg: "brightGreen",
|
|
945
|
+
});
|
|
946
|
+
appendSegment(segments, {
|
|
947
|
+
text: separator,
|
|
948
|
+
attributes: TextAttributes.DIM,
|
|
949
|
+
});
|
|
950
|
+
|
|
951
|
+
appendSegment(segments, {
|
|
952
|
+
text: "!",
|
|
953
|
+
fg: "red",
|
|
954
|
+
attributes: TextAttributes.BOLD,
|
|
955
|
+
});
|
|
956
|
+
appendSegment(segments, {
|
|
957
|
+
text: " Uncommitted",
|
|
958
|
+
fg: "red",
|
|
959
|
+
});
|
|
960
|
+
appendSegment(segments, {
|
|
961
|
+
text: separator,
|
|
962
|
+
attributes: TextAttributes.DIM,
|
|
963
|
+
});
|
|
964
|
+
|
|
965
|
+
appendSegment(segments, {
|
|
966
|
+
text: "!",
|
|
967
|
+
fg: "yellow",
|
|
968
|
+
attributes: TextAttributes.BOLD,
|
|
969
|
+
});
|
|
970
|
+
appendSegment(segments, {
|
|
971
|
+
text: " Unpushed",
|
|
972
|
+
fg: "yellow",
|
|
973
|
+
});
|
|
974
|
+
appendSegment(segments, {
|
|
975
|
+
text: separator,
|
|
976
|
+
attributes: TextAttributes.DIM,
|
|
977
|
+
});
|
|
978
|
+
|
|
979
|
+
appendSegment(segments, {
|
|
980
|
+
text: "*",
|
|
981
|
+
fg: "yellow",
|
|
982
|
+
attributes: TextAttributes.BOLD,
|
|
983
|
+
});
|
|
984
|
+
appendSegment(segments, {
|
|
985
|
+
text: " Unmerged",
|
|
986
|
+
fg: "yellow",
|
|
987
|
+
});
|
|
988
|
+
|
|
989
|
+
return fitSegmentsToWidth(segments, layoutWidth());
|
|
990
|
+
});
|
|
991
|
+
|
|
889
992
|
const footerSegments = createMemo(() => {
|
|
890
993
|
const segments: TextSegment[] = [];
|
|
891
994
|
const separator = " ";
|
|
@@ -971,7 +1074,7 @@ export function BranchListScreen(props: BranchListScreenProps) {
|
|
|
971
1074
|
: {})}
|
|
972
1075
|
/>
|
|
973
1076
|
) : (
|
|
974
|
-
|
|
1077
|
+
renderSegmentLine(statusLegendSegments())
|
|
975
1078
|
)}
|
|
976
1079
|
|
|
977
1080
|
{props.error && (
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
|
-
import { TextAttributes } from "@opentui/core";
|
|
3
2
|
import { useKeyboard } from "@opentui/solid";
|
|
4
3
|
import { createSignal } from "solid-js";
|
|
4
|
+
import stringWidth from "string-width";
|
|
5
|
+
import { useTerminalSize } from "../../hooks/solid/useTerminalSize.js";
|
|
6
|
+
import { selectionStyle } from "../../core/theme.js";
|
|
5
7
|
|
|
6
8
|
export interface ConfirmScreenProps {
|
|
7
9
|
message: string;
|
|
@@ -10,6 +12,7 @@ export interface ConfirmScreenProps {
|
|
|
10
12
|
noLabel?: string;
|
|
11
13
|
defaultNo?: boolean;
|
|
12
14
|
helpVisible?: boolean;
|
|
15
|
+
width?: number;
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
export function ConfirmScreen({
|
|
@@ -19,8 +22,16 @@ export function ConfirmScreen({
|
|
|
19
22
|
noLabel = "No",
|
|
20
23
|
defaultNo = false,
|
|
21
24
|
helpVisible = false,
|
|
25
|
+
width,
|
|
22
26
|
}: ConfirmScreenProps) {
|
|
23
27
|
const [selectedIndex, setSelectedIndex] = createSignal(defaultNo ? 1 : 0);
|
|
28
|
+
const terminal = useTerminalSize();
|
|
29
|
+
const contentWidth = () => Math.max(0, width ?? terminal().columns);
|
|
30
|
+
|
|
31
|
+
const padLine = (value: string, width: number) => {
|
|
32
|
+
const padding = Math.max(0, width - stringWidth(value));
|
|
33
|
+
return padding > 0 ? `${value}${" ".repeat(padding)}` : value;
|
|
34
|
+
};
|
|
24
35
|
|
|
25
36
|
const confirm = (confirmed: boolean) => {
|
|
26
37
|
onConfirm(confirmed);
|
|
@@ -54,13 +65,14 @@ export function ConfirmScreen({
|
|
|
54
65
|
}
|
|
55
66
|
});
|
|
56
67
|
|
|
57
|
-
const renderOption = (label: string, isSelected: boolean) =>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
68
|
+
const renderOption = (label: string, isSelected: boolean) =>
|
|
69
|
+
isSelected ? (
|
|
70
|
+
<text fg={selectionStyle.fg} bg={selectionStyle.bg}>
|
|
71
|
+
{padLine(label, contentWidth())}
|
|
72
|
+
</text>
|
|
73
|
+
) : (
|
|
74
|
+
<text>{label}</text>
|
|
75
|
+
);
|
|
64
76
|
|
|
65
77
|
return (
|
|
66
78
|
<box flexDirection="column">
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
|
-
import { TextAttributes } from "@opentui/core";
|
|
3
2
|
import { useKeyboard } from "@opentui/solid";
|
|
4
3
|
import { createMemo } from "solid-js";
|
|
5
4
|
import { Header } from "../../components/solid/Header.js";
|
|
6
5
|
import { Footer } from "../../components/solid/Footer.js";
|
|
7
6
|
import { useTerminalSize } from "../../hooks/solid/useTerminalSize.js";
|
|
8
7
|
import { useScrollableList } from "../../hooks/solid/useScrollableList.js";
|
|
8
|
+
import stringWidth from "string-width";
|
|
9
|
+
import { selectionStyle } from "../../core/theme.js";
|
|
9
10
|
|
|
10
11
|
export interface EnvironmentVariable {
|
|
11
12
|
key: string;
|
|
@@ -33,6 +34,10 @@ export function EnvironmentScreen({
|
|
|
33
34
|
helpVisible = false,
|
|
34
35
|
}: EnvironmentScreenProps) {
|
|
35
36
|
const terminal = useTerminalSize();
|
|
37
|
+
const padLine = (value: string, width: number) => {
|
|
38
|
+
const padding = Math.max(0, width - stringWidth(value));
|
|
39
|
+
return padding > 0 ? `${value}${" ".repeat(padding)}` : value;
|
|
40
|
+
};
|
|
36
41
|
const listHeight = createMemo(() => {
|
|
37
42
|
const headerRows = 2;
|
|
38
43
|
const footerRows = 1;
|
|
@@ -125,27 +130,24 @@ export function EnvironmentScreen({
|
|
|
125
130
|
const absoluteIndex = list.scrollOffset() + index;
|
|
126
131
|
const isSelected = absoluteIndex === list.selectedIndex();
|
|
127
132
|
const isHighlighted = highlightSet().has(variable.key);
|
|
128
|
-
const
|
|
129
|
-
const keyColor = isSelected
|
|
130
|
-
? "cyan"
|
|
131
|
-
: isHighlighted
|
|
132
|
-
? "yellow"
|
|
133
|
-
: undefined;
|
|
134
|
-
const valueColor = isSelected ? "cyan" : undefined;
|
|
133
|
+
const keyColor = isHighlighted ? "yellow" : undefined;
|
|
135
134
|
return (
|
|
136
135
|
<box flexDirection="row">
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
136
|
+
{isSelected ? (
|
|
137
|
+
<text fg={selectionStyle.fg} bg={selectionStyle.bg}>
|
|
138
|
+
{padLine(
|
|
139
|
+
`${variable.key}=${variable.value}`,
|
|
140
|
+
terminal().columns,
|
|
141
|
+
)}
|
|
142
|
+
</text>
|
|
143
|
+
) : (
|
|
144
|
+
<>
|
|
145
|
+
<text {...(keyColor ? { fg: keyColor } : {})}>
|
|
146
|
+
{variable.key}
|
|
147
|
+
</text>
|
|
148
|
+
<text>={variable.value}</text>
|
|
149
|
+
</>
|
|
150
|
+
)}
|
|
149
151
|
</box>
|
|
150
152
|
);
|
|
151
153
|
})}
|