@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
package/dist/cli/ui/App.solid.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "@opentui/solid/jsx-runtime";
|
|
2
2
|
/** @jsxImportSource @opentui/solid */
|
|
3
3
|
import { useKeyboard, useRenderer } from "@opentui/solid";
|
|
4
|
-
import { createEffect, createMemo, createSignal, onCleanup, onMount, } from "solid-js";
|
|
4
|
+
import { batch, createEffect, createMemo, createSignal, onCleanup, onMount, } from "solid-js";
|
|
5
5
|
import { BranchListScreen } from "./screens/solid/BranchListScreen.js";
|
|
6
6
|
import { HelpOverlay } from "./components/solid/HelpOverlay.js";
|
|
7
7
|
import { WizardController, } from "./components/solid/WizardController.js";
|
|
@@ -13,6 +13,7 @@ import { LoadingIndicatorScreen } from "./screens/solid/LoadingIndicator.js";
|
|
|
13
13
|
import { WorktreeCreateScreen } from "./screens/solid/WorktreeCreateScreen.js";
|
|
14
14
|
import { InputScreen } from "./screens/solid/InputScreen.js";
|
|
15
15
|
import { ConfirmScreen } from "./screens/solid/ConfirmScreen.js";
|
|
16
|
+
import { useTerminalSize } from "./hooks/solid/useTerminalSize.js";
|
|
16
17
|
import { EnvironmentScreen } from "./screens/solid/EnvironmentScreen.js";
|
|
17
18
|
import { ProfileScreen } from "./screens/solid/ProfileScreen.js";
|
|
18
19
|
import { ProfileEnvScreen } from "./screens/solid/ProfileEnvScreen.js";
|
|
@@ -25,14 +26,18 @@ import { resolveBaseBranchLabel, resolveBaseBranchRef, } from "./utils/baseBranc
|
|
|
25
26
|
import { getAllBranches, getCurrentBranch, getLocalBranches, getRepositoryRoot, deleteBranch, } from "../../git.js";
|
|
26
27
|
import { isProtectedBranchName, getCleanupStatus, listAdditionalWorktrees, removeWorktree, repairWorktrees, } from "../../worktree.js";
|
|
27
28
|
import { getConfig, getLastToolUsageMap, loadSession, } from "../../config/index.js";
|
|
29
|
+
import { findLatestBranchSessionsByTool, refreshQuickStartEntries, } from "./utils/continueSession.js";
|
|
28
30
|
import { getAllCodingAgents } from "../../config/tools.js";
|
|
29
|
-
import {
|
|
31
|
+
import { clearLogFiles, getTodayLogDate, readLogLinesForDate, resolveLogTarget, } from "../../logging/reader.js";
|
|
30
32
|
import { parseLogLines } from "../../logging/formatter.js";
|
|
31
33
|
import { copyToClipboard } from "./utils/clipboard.js";
|
|
32
34
|
import { getPackageVersion } from "../../utils.js";
|
|
33
35
|
import { createProfile, deleteProfile, loadProfiles, setActiveProfile, updateProfile, } from "../../config/profiles.js";
|
|
34
36
|
import { isValidProfileName, } from "../../types/profiles.js";
|
|
35
37
|
import { BRANCH_PREFIXES } from "../../config/constants.js";
|
|
38
|
+
import { prefetchAgentVersions } from "./utils/versionCache.js";
|
|
39
|
+
import { getBunxAgentIds } from "./utils/versionFetcher.js";
|
|
40
|
+
const UNSAFE_SELECTION_MESSAGE = "Unsafe branch selected. Select anyway?";
|
|
36
41
|
const DEFAULT_SCREEN = "branch-list";
|
|
37
42
|
const buildStats = (branches) => calculateStatistics(branches);
|
|
38
43
|
const applyCleanupStatus = (items, statusByBranch) => items.map((branch) => {
|
|
@@ -58,6 +63,23 @@ const applyCleanupStatus = (items, statusByBranch) => items.map((branch) => {
|
|
|
58
63
|
};
|
|
59
64
|
return worktree ? { ...base, worktree } : base;
|
|
60
65
|
});
|
|
66
|
+
const buildCleanupSafetyPending = (items) => {
|
|
67
|
+
const pending = new Set();
|
|
68
|
+
for (const branch of items) {
|
|
69
|
+
if (branch.type === "remote") {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
if (branch.worktree) {
|
|
73
|
+
pending.add(branch.name);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (isProtectedBranchName(branch.name)) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
pending.add(branch.name);
|
|
80
|
+
}
|
|
81
|
+
return pending;
|
|
82
|
+
};
|
|
61
83
|
const toLocalBranchName = (name) => {
|
|
62
84
|
const segments = name.split("/");
|
|
63
85
|
if (segments.length <= 1) {
|
|
@@ -73,11 +95,13 @@ const toSelectedBranchState = (branch) => {
|
|
|
73
95
|
displayName: branch.name,
|
|
74
96
|
branchType: branch.type,
|
|
75
97
|
branchCategory: branch.branchType,
|
|
98
|
+
worktreePath: branch.worktree?.path ?? null,
|
|
76
99
|
...(isRemote ? { remoteBranch: branch.name } : {}),
|
|
77
100
|
};
|
|
78
101
|
};
|
|
79
102
|
export function AppSolid(props) {
|
|
80
103
|
const renderer = useRenderer();
|
|
104
|
+
const terminal = useTerminalSize();
|
|
81
105
|
let hasExited = false;
|
|
82
106
|
const exitApp = (result) => {
|
|
83
107
|
if (hasExited)
|
|
@@ -94,6 +118,8 @@ export function AppSolid(props) {
|
|
|
94
118
|
const [stats, setStats] = createSignal(props.stats ?? buildStats(props.branches ?? []));
|
|
95
119
|
const [loading, setLoading] = createSignal(!props.branches);
|
|
96
120
|
const [error, setError] = createSignal(null);
|
|
121
|
+
// ブランチ一覧のカーソル位置(グローバル管理で再マウント時もリセットされない)
|
|
122
|
+
const [branchCursorPosition, setBranchCursorPosition] = createSignal(0);
|
|
97
123
|
const [toolItems, setToolItems] = createSignal([]);
|
|
98
124
|
const [toolError, setToolError] = createSignal(null);
|
|
99
125
|
const [version, setVersion] = createSignal(props.version ?? null);
|
|
@@ -102,11 +128,15 @@ export function AppSolid(props) {
|
|
|
102
128
|
const [selectedTool, setSelectedTool] = createSignal(null);
|
|
103
129
|
const [selectedMode, setSelectedMode] = createSignal("normal");
|
|
104
130
|
const [selectedBranches, setSelectedBranches] = createSignal([]);
|
|
131
|
+
const [unsafeSelectionConfirmVisible, setUnsafeSelectionConfirmVisible] = createSignal(false);
|
|
132
|
+
const [unsafeConfirmInputLocked, setUnsafeConfirmInputLocked] = createSignal(false);
|
|
133
|
+
const [unsafeSelectionTarget, setUnsafeSelectionTarget] = createSignal(null);
|
|
105
134
|
const [branchFooterMessage, setBranchFooterMessage] = createSignal(null);
|
|
106
135
|
const [branchInputLocked, setBranchInputLocked] = createSignal(false);
|
|
107
136
|
const [cleanupIndicators, setCleanupIndicators] = createSignal({});
|
|
108
137
|
const [cleanupStatusByBranch, setCleanupStatusByBranch] = createSignal(new Map());
|
|
109
138
|
const [cleanupSafetyLoading, setCleanupSafetyLoading] = createSignal(false);
|
|
139
|
+
const [cleanupSafetyPending, setCleanupSafetyPending] = createSignal(new Set());
|
|
110
140
|
const [isNewBranch, setIsNewBranch] = createSignal(false);
|
|
111
141
|
const [newBranchBaseRef, setNewBranchBaseRef] = createSignal(null);
|
|
112
142
|
const [creationSource, setCreationSource] = createSignal(null);
|
|
@@ -115,25 +145,61 @@ export function AppSolid(props) {
|
|
|
115
145
|
});
|
|
116
146
|
const [suppressCreateKey, setSuppressCreateKey] = createSignal(null);
|
|
117
147
|
const [defaultBaseBranch, setDefaultBaseBranch] = createSignal("main");
|
|
148
|
+
const suppressBranchInputOnce = () => {
|
|
149
|
+
setUnsafeConfirmInputLocked(true);
|
|
150
|
+
queueMicrotask(() => {
|
|
151
|
+
setUnsafeConfirmInputLocked(false);
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
const unsafeConfirmBoxWidth = createMemo(() => {
|
|
155
|
+
const columns = terminal().columns || 80;
|
|
156
|
+
return Math.max(1, Math.floor(columns * 0.6));
|
|
157
|
+
});
|
|
158
|
+
const unsafeConfirmContentWidth = createMemo(() => Math.max(0, unsafeConfirmBoxWidth() - 4));
|
|
118
159
|
// セッション履歴(最終使用エージェントなど)
|
|
119
160
|
const [sessionHistory, setSessionHistory] = createSignal([]);
|
|
161
|
+
const [quickStartHistory, setQuickStartHistory] = createSignal([]);
|
|
120
162
|
// 選択中ブランチの履歴をフィルタリング
|
|
121
163
|
const historyForBranch = createMemo(() => {
|
|
122
164
|
const history = sessionHistory();
|
|
123
165
|
const branch = selectedBranch();
|
|
124
166
|
if (!branch)
|
|
125
167
|
return [];
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
168
|
+
return findLatestBranchSessionsByTool(history, branch.name, branch.worktreePath ?? null);
|
|
169
|
+
});
|
|
170
|
+
createEffect(() => {
|
|
171
|
+
setQuickStartHistory(historyForBranch());
|
|
172
|
+
});
|
|
173
|
+
createEffect(() => {
|
|
174
|
+
const branch = selectedBranch();
|
|
175
|
+
const baseHistory = historyForBranch();
|
|
176
|
+
if (!wizardVisible() || !branch || baseHistory.length === 0) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const worktreePath = branch.worktreePath ?? null;
|
|
180
|
+
if (!worktreePath) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const branchName = branch.name;
|
|
184
|
+
void (async () => {
|
|
185
|
+
const refreshed = await refreshQuickStartEntries(baseHistory, {
|
|
186
|
+
branch: branchName,
|
|
187
|
+
worktreePath,
|
|
188
|
+
});
|
|
189
|
+
if (selectedBranch()?.name !== branchName) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
setQuickStartHistory(refreshed);
|
|
193
|
+
})();
|
|
130
194
|
});
|
|
131
195
|
const [logEntries, setLogEntries] = createSignal([]);
|
|
132
196
|
const [logLoading, setLogLoading] = createSignal(false);
|
|
133
197
|
const [logError, setLogError] = createSignal(null);
|
|
134
198
|
const [logSelectedEntry, setLogSelectedEntry] = createSignal(null);
|
|
135
|
-
const [logSelectedDate,
|
|
199
|
+
const [logSelectedDate, setLogSelectedDate] = createSignal(getTodayLogDate());
|
|
136
200
|
const [logNotification, setLogNotification] = createSignal(null);
|
|
201
|
+
const [logTailEnabled, setLogTailEnabled] = createSignal(false);
|
|
202
|
+
const [logTargetBranch, setLogTargetBranch] = createSignal(null);
|
|
137
203
|
const [profileItems, setProfileItems] = createSignal([]);
|
|
138
204
|
const [activeProfile, setActiveProfileName] = createSignal(null);
|
|
139
205
|
const [profileError, setProfileError] = createSignal(null);
|
|
@@ -148,7 +214,22 @@ export function AppSolid(props) {
|
|
|
148
214
|
const [profileInputSuppressKey, setProfileInputSuppressKey] = createSignal(null);
|
|
149
215
|
const [profileEnvKey, setProfileEnvKey] = createSignal(null);
|
|
150
216
|
const [profileConfirmMode, setProfileConfirmMode] = createSignal("delete-profile");
|
|
151
|
-
const
|
|
217
|
+
const logTarget = createMemo(() => resolveLogTarget(logTargetBranch(), workingDirectory()));
|
|
218
|
+
const logBranchLabel = createMemo(() => logTargetBranch()?.label ?? null);
|
|
219
|
+
const logSourceLabel = createMemo(() => {
|
|
220
|
+
const target = logTarget();
|
|
221
|
+
if (!target.sourcePath) {
|
|
222
|
+
return "(none)";
|
|
223
|
+
}
|
|
224
|
+
if (target.reason === "current-working-directory" ||
|
|
225
|
+
target.reason === "working-directory") {
|
|
226
|
+
return `${target.sourcePath} (cwd)`;
|
|
227
|
+
}
|
|
228
|
+
if (target.reason === "worktree-inaccessible") {
|
|
229
|
+
return `${target.sourcePath} (inaccessible)`;
|
|
230
|
+
}
|
|
231
|
+
return target.sourcePath;
|
|
232
|
+
});
|
|
152
233
|
const selectedProfileConfig = createMemo(() => {
|
|
153
234
|
const name = selectedProfileName();
|
|
154
235
|
const config = profilesConfig();
|
|
@@ -173,15 +254,42 @@ export function AppSolid(props) {
|
|
|
173
254
|
let cleanupSafetyRequestId = 0;
|
|
174
255
|
const refreshCleanupSafety = async () => {
|
|
175
256
|
const requestId = ++cleanupSafetyRequestId;
|
|
176
|
-
|
|
257
|
+
const pendingBranches = buildCleanupSafetyPending(branchItems());
|
|
258
|
+
setCleanupSafetyPending(pendingBranches);
|
|
259
|
+
setCleanupSafetyLoading(pendingBranches.size > 0);
|
|
260
|
+
const statusByBranch = new Map();
|
|
261
|
+
const applyProgress = (status) => {
|
|
262
|
+
if (requestId !== cleanupSafetyRequestId) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
statusByBranch.set(status.branch, status);
|
|
266
|
+
batch(() => {
|
|
267
|
+
setCleanupStatusByBranch(new Map(statusByBranch));
|
|
268
|
+
setBranchItems((items) => applyCleanupStatus(items, statusByBranch));
|
|
269
|
+
setCleanupSafetyPending((prev) => {
|
|
270
|
+
if (!prev.has(status.branch)) {
|
|
271
|
+
return prev;
|
|
272
|
+
}
|
|
273
|
+
const next = new Set(prev);
|
|
274
|
+
next.delete(status.branch);
|
|
275
|
+
return next;
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
};
|
|
177
279
|
try {
|
|
178
|
-
const cleanupStatuses = await getCleanupStatus(
|
|
280
|
+
const cleanupStatuses = await getCleanupStatus({
|
|
281
|
+
onProgress: applyProgress,
|
|
282
|
+
});
|
|
179
283
|
if (requestId !== cleanupSafetyRequestId) {
|
|
180
284
|
return;
|
|
181
285
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
286
|
+
if (cleanupStatuses.length > statusByBranch.size) {
|
|
287
|
+
cleanupStatuses.forEach((status) => {
|
|
288
|
+
if (!statusByBranch.has(status.branch)) {
|
|
289
|
+
applyProgress(status);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
185
293
|
}
|
|
186
294
|
catch (err) {
|
|
187
295
|
if (requestId !== cleanupSafetyRequestId) {
|
|
@@ -189,16 +297,20 @@ export function AppSolid(props) {
|
|
|
189
297
|
}
|
|
190
298
|
logger.warn({ err }, "Failed to refresh cleanup safety indicators");
|
|
191
299
|
const empty = new Map();
|
|
192
|
-
|
|
193
|
-
|
|
300
|
+
batch(() => {
|
|
301
|
+
setCleanupStatusByBranch(empty);
|
|
302
|
+
setBranchItems((items) => applyCleanupStatus(items, empty));
|
|
303
|
+
});
|
|
194
304
|
}
|
|
195
305
|
finally {
|
|
196
306
|
if (requestId === cleanupSafetyRequestId) {
|
|
197
307
|
setCleanupSafetyLoading(false);
|
|
308
|
+
setCleanupSafetyPending(new Set());
|
|
198
309
|
}
|
|
199
310
|
}
|
|
200
311
|
};
|
|
201
312
|
let logNotificationTimer = null;
|
|
313
|
+
let logTailTimer = null;
|
|
202
314
|
let branchFooterTimer = null;
|
|
203
315
|
const BRANCH_LOAD_TIMEOUT_MS = 3000;
|
|
204
316
|
const BRANCH_FULL_LOAD_TIMEOUT_MS = 8000;
|
|
@@ -263,9 +375,20 @@ export function AppSolid(props) {
|
|
|
263
375
|
setLogLoading(true);
|
|
264
376
|
setLogError(null);
|
|
265
377
|
try {
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
378
|
+
const target = logTarget();
|
|
379
|
+
if (!target.logDir) {
|
|
380
|
+
setLogEntries([]);
|
|
381
|
+
setLogSelectedDate(targetDate);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
const result = await readLogLinesForDate(target.logDir, targetDate);
|
|
385
|
+
if (!result) {
|
|
386
|
+
setLogEntries([]);
|
|
387
|
+
setLogSelectedDate(targetDate);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
setLogSelectedDate(result.date);
|
|
391
|
+
const parsed = parseLogLines(result.lines, { limit: 100 });
|
|
269
392
|
setLogEntries(parsed);
|
|
270
393
|
}
|
|
271
394
|
catch (err) {
|
|
@@ -276,10 +399,39 @@ export function AppSolid(props) {
|
|
|
276
399
|
setLogLoading(false);
|
|
277
400
|
}
|
|
278
401
|
};
|
|
402
|
+
const clearLogTailTimer = () => {
|
|
403
|
+
if (logTailTimer) {
|
|
404
|
+
clearInterval(logTailTimer);
|
|
405
|
+
logTailTimer = null;
|
|
406
|
+
}
|
|
407
|
+
};
|
|
408
|
+
const toggleLogTail = () => {
|
|
409
|
+
setLogTailEnabled((prev) => !prev);
|
|
410
|
+
};
|
|
411
|
+
const resetLogFiles = async () => {
|
|
412
|
+
const target = logTarget();
|
|
413
|
+
if (!target.logDir) {
|
|
414
|
+
showLogNotification("No logs available.", "error");
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
try {
|
|
418
|
+
const cleared = await clearLogFiles(target.logDir);
|
|
419
|
+
if (cleared === 0) {
|
|
420
|
+
showLogNotification("No logs to reset.", "error");
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
showLogNotification("Logs cleared.", "success");
|
|
424
|
+
}
|
|
425
|
+
await loadLogEntries(logSelectedDate());
|
|
426
|
+
}
|
|
427
|
+
catch (err) {
|
|
428
|
+
logger.warn({ err }, "Failed to clear log files");
|
|
429
|
+
showLogNotification("Failed to reset logs.", "error");
|
|
430
|
+
}
|
|
431
|
+
};
|
|
279
432
|
const refreshBranches = async () => {
|
|
280
433
|
setLoading(true);
|
|
281
434
|
setError(null);
|
|
282
|
-
void refreshCleanupSafety();
|
|
283
435
|
try {
|
|
284
436
|
const repoRoot = await getRepositoryRoot();
|
|
285
437
|
const worktreesPromise = listAdditionalWorktrees();
|
|
@@ -303,6 +455,7 @@ export function AppSolid(props) {
|
|
|
303
455
|
const initialItems = applyCleanupStatus(initial.items, cleanupStatusByBranch());
|
|
304
456
|
setBranchItems(initialItems);
|
|
305
457
|
setStats(buildStats(initialItems));
|
|
458
|
+
void refreshCleanupSafety();
|
|
306
459
|
void (async () => {
|
|
307
460
|
const [branches, latestWorktrees] = await Promise.all([
|
|
308
461
|
withTimeout(getAllBranches(repoRoot), BRANCH_FULL_LOAD_TIMEOUT_MS).catch(() => localBranches),
|
|
@@ -400,15 +553,34 @@ export function AppSolid(props) {
|
|
|
400
553
|
setToolError(err instanceof Error ? err : new Error(String(err)));
|
|
401
554
|
});
|
|
402
555
|
});
|
|
556
|
+
// FR-028: Prefetch npm versions for all bunx-type agents at startup (background)
|
|
557
|
+
onMount(() => {
|
|
558
|
+
const bunxAgentIds = getBunxAgentIds();
|
|
559
|
+
void prefetchAgentVersions(bunxAgentIds).catch(() => {
|
|
560
|
+
// Silently handle errors - cache will return null and UI will show "latest" only
|
|
561
|
+
});
|
|
562
|
+
});
|
|
403
563
|
createEffect(() => {
|
|
404
564
|
if (currentScreen() === "log-list") {
|
|
565
|
+
logTarget();
|
|
405
566
|
void loadLogEntries(logSelectedDate());
|
|
406
567
|
}
|
|
407
568
|
});
|
|
569
|
+
createEffect(() => {
|
|
570
|
+
if (currentScreen() !== "log-list" || !logTailEnabled()) {
|
|
571
|
+
clearLogTailTimer();
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
clearLogTailTimer();
|
|
575
|
+
logTailTimer = setInterval(() => {
|
|
576
|
+
void loadLogEntries(logSelectedDate());
|
|
577
|
+
}, 1500);
|
|
578
|
+
});
|
|
408
579
|
onCleanup(() => {
|
|
409
580
|
if (logNotificationTimer) {
|
|
410
581
|
clearTimeout(logNotificationTimer);
|
|
411
582
|
}
|
|
583
|
+
clearLogTailTimer();
|
|
412
584
|
if (branchFooterTimer) {
|
|
413
585
|
clearTimeout(branchFooterTimer);
|
|
414
586
|
}
|
|
@@ -507,6 +679,10 @@ export function AppSolid(props) {
|
|
|
507
679
|
};
|
|
508
680
|
// FR-010: クイックスタートからのResume(前回設定で続きから)
|
|
509
681
|
const handleWizardResume = (entry) => {
|
|
682
|
+
if (!entry.sessionId) {
|
|
683
|
+
handleWizardStartNew(entry);
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
510
686
|
setWizardVisible(false);
|
|
511
687
|
const branch = selectedBranch();
|
|
512
688
|
if (!branch) {
|
|
@@ -605,24 +781,10 @@ export function AppSolid(props) {
|
|
|
605
781
|
skipCounts.remote += 1;
|
|
606
782
|
continue;
|
|
607
783
|
}
|
|
608
|
-
if (isProtectedBranchName(branch.name)) {
|
|
609
|
-
skipCounts.protected += 1;
|
|
610
|
-
continue;
|
|
611
|
-
}
|
|
612
784
|
if (branch.isCurrent) {
|
|
613
785
|
skipCounts.current += 1;
|
|
614
786
|
continue;
|
|
615
787
|
}
|
|
616
|
-
const hasUncommitted = branch.worktree?.hasUncommittedChanges === true;
|
|
617
|
-
const hasUnpushed = branch.hasUnpushedCommits === true;
|
|
618
|
-
if (hasUncommitted || hasUnpushed) {
|
|
619
|
-
skipCounts.unsafe += 1;
|
|
620
|
-
continue;
|
|
621
|
-
}
|
|
622
|
-
if (branch.safeToCleanup !== true) {
|
|
623
|
-
skipCounts.unsafe += 1;
|
|
624
|
-
continue;
|
|
625
|
-
}
|
|
626
788
|
const worktreePath = branch.worktree?.path ?? null;
|
|
627
789
|
const cleanupType = worktreePath
|
|
628
790
|
? "worktree-and-branch"
|
|
@@ -717,11 +879,12 @@ export function AppSolid(props) {
|
|
|
717
879
|
showBranchFooterMessage("No branches selected.", "yellow");
|
|
718
880
|
return;
|
|
719
881
|
}
|
|
720
|
-
//
|
|
882
|
+
// 選択されたローカルブランチのうち、Worktreeを持つものを修復対象とする
|
|
721
883
|
const selectionSet = new Set(selection);
|
|
722
884
|
const targets = branchItems()
|
|
723
885
|
.filter((branch) => selectionSet.has(branch.name) &&
|
|
724
|
-
branch.
|
|
886
|
+
branch.type !== "remote" &&
|
|
887
|
+
branch.worktreeStatus !== undefined)
|
|
725
888
|
.map((branch) => branch.name);
|
|
726
889
|
if (targets.length === 0) {
|
|
727
890
|
showBranchFooterMessage("No worktrees to repair.", "yellow");
|
|
@@ -924,16 +1087,44 @@ export function AppSolid(props) {
|
|
|
924
1087
|
}
|
|
925
1088
|
};
|
|
926
1089
|
const toggleSelectedBranch = (branchName) => {
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1090
|
+
if (unsafeSelectionConfirmVisible()) {
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
const currentSelection = new Set(selectedBranches());
|
|
1094
|
+
if (currentSelection.has(branchName)) {
|
|
1095
|
+
currentSelection.delete(branchName);
|
|
1096
|
+
setSelectedBranches(Array.from(currentSelection));
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
const branch = branchItems().find((item) => item.name === branchName);
|
|
1100
|
+
const pending = cleanupSafetyPending();
|
|
1101
|
+
const hasSafetyPending = pending.has(branchName);
|
|
1102
|
+
const hasUncommitted = branch?.worktree?.hasUncommittedChanges === true;
|
|
1103
|
+
const hasUnpushed = branch?.hasUnpushedCommits === true;
|
|
1104
|
+
const isUnmerged = branch?.isUnmerged === true;
|
|
1105
|
+
const safeToCleanup = branch?.safeToCleanup === true;
|
|
1106
|
+
const isRemoteBranch = branch?.type === "remote";
|
|
1107
|
+
const isUnsafe = Boolean(branch) &&
|
|
1108
|
+
!isRemoteBranch &&
|
|
1109
|
+
!hasSafetyPending &&
|
|
1110
|
+
(hasUncommitted || hasUnpushed || isUnmerged || !safeToCleanup);
|
|
1111
|
+
if (branch && isUnsafe) {
|
|
1112
|
+
setUnsafeSelectionTarget(branch.name);
|
|
1113
|
+
setUnsafeSelectionConfirmVisible(true);
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1116
|
+
currentSelection.add(branchName);
|
|
1117
|
+
setSelectedBranches(Array.from(currentSelection));
|
|
1118
|
+
};
|
|
1119
|
+
const confirmUnsafeSelection = (confirmed) => {
|
|
1120
|
+
suppressBranchInputOnce();
|
|
1121
|
+
const target = unsafeSelectionTarget();
|
|
1122
|
+
setUnsafeSelectionConfirmVisible(false);
|
|
1123
|
+
setUnsafeSelectionTarget(null);
|
|
1124
|
+
if (!confirmed || !target) {
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
setSelectedBranches((prev) => prev.includes(target) ? prev : [...prev, target]);
|
|
937
1128
|
};
|
|
938
1129
|
const handleToolSelect = (item) => {
|
|
939
1130
|
setSelectedTool(item.value);
|
|
@@ -980,10 +1171,17 @@ export function AppSolid(props) {
|
|
|
980
1171
|
const cleanupUI = {
|
|
981
1172
|
indicators: cleanupIndicators(),
|
|
982
1173
|
footerMessage: branchFooterMessage(),
|
|
983
|
-
inputLocked: branchInputLocked(),
|
|
1174
|
+
inputLocked: branchInputLocked() || unsafeConfirmInputLocked(),
|
|
984
1175
|
safetyLoading: cleanupSafetyLoading(),
|
|
1176
|
+
safetyPendingBranches: cleanupSafetyPending(),
|
|
985
1177
|
};
|
|
986
|
-
return (_jsx(BranchListScreen, { branches: branchItems(), stats: stats(), onSelect: handleBranchSelect, onQuit: () => exitApp(undefined), onCleanupCommand: handleCleanupCommand, onRefresh: refreshBranches, onRepairWorktrees: handleRepairWorktrees, loading: loading(), error: error(), loadingIndicatorDelay: props.loadingIndicatorDelay ?? 0, lastUpdated: stats().lastUpdated, version: version(), workingDirectory: workingDirectory(), activeProfile: activeProfile(), onOpenLogs: () =>
|
|
1178
|
+
return (_jsx(BranchListScreen, { branches: branchItems(), stats: stats(), onSelect: handleBranchSelect, onQuit: () => exitApp(undefined), onCleanupCommand: handleCleanupCommand, onRefresh: refreshBranches, onRepairWorktrees: handleRepairWorktrees, loading: loading(), error: error(), loadingIndicatorDelay: props.loadingIndicatorDelay ?? 0, lastUpdated: stats().lastUpdated, version: version(), workingDirectory: workingDirectory(), activeProfile: activeProfile(), onOpenLogs: (branch) => {
|
|
1179
|
+
setLogTargetBranch(branch);
|
|
1180
|
+
setLogSelectedEntry(null);
|
|
1181
|
+
setLogSelectedDate(getTodayLogDate());
|
|
1182
|
+
setLogTailEnabled(false);
|
|
1183
|
+
navigateTo("log-list");
|
|
1184
|
+
}, onOpenProfiles: () => navigateTo("profile"), selectedBranches: selectedBranches(), onToggleSelect: toggleSelectedBranch, onCreateBranch: handleQuickCreate, cleanupUI: cleanupUI, helpVisible: helpVisible(), wizardVisible: wizardVisible(), confirmVisible: unsafeSelectionConfirmVisible(), cursorPosition: branchCursorPosition(), onCursorPositionChange: setBranchCursorPosition }));
|
|
987
1185
|
}
|
|
988
1186
|
if (screen === "tool-select") {
|
|
989
1187
|
if (toolError()) {
|
|
@@ -1016,7 +1214,7 @@ export function AppSolid(props) {
|
|
|
1016
1214
|
catch {
|
|
1017
1215
|
showLogNotification("Failed to copy to clipboard.", "error");
|
|
1018
1216
|
}
|
|
1019
|
-
}, notification: logNotification(), version: version(), selectedDate: logSelectedDate(), helpVisible: helpVisible() }));
|
|
1217
|
+
}, onReload: () => void loadLogEntries(logSelectedDate()), onToggleTail: toggleLogTail, onReset: () => void resetLogFiles(), notification: logNotification(), version: version(), selectedDate: logSelectedDate(), branchLabel: logBranchLabel(), sourceLabel: logSourceLabel(), tailing: logTailEnabled(), helpVisible: helpVisible() }));
|
|
1020
1218
|
}
|
|
1021
1219
|
if (screen === "log-detail") {
|
|
1022
1220
|
return (_jsx(LogDetailScreen, { entry: logSelectedEntry(), onBack: goBack, onCopy: async (entry) => {
|
|
@@ -1143,7 +1341,7 @@ export function AppSolid(props) {
|
|
|
1143
1341
|
}
|
|
1144
1342
|
return (_jsx(ErrorScreen, { error: `Unknown screen: ${screen}`, onBack: goBack, helpVisible: helpVisible() }));
|
|
1145
1343
|
};
|
|
1146
|
-
return (_jsxs(_Fragment, { children: [renderCurrentScreen(), _jsx(HelpOverlay, { visible: helpVisible(), context: currentScreen() }), _jsx(WizardController, { visible: wizardVisible(), selectedBranchName: selectedBranch()?.name ?? "", history:
|
|
1344
|
+
return (_jsxs(_Fragment, { children: [renderCurrentScreen(), unsafeSelectionConfirmVisible() && (_jsx("box", { position: "absolute", top: "30%", left: "20%", width: unsafeConfirmBoxWidth(), zIndex: 110, border: true, borderStyle: "single", borderColor: "yellow", backgroundColor: "black", padding: 1, children: _jsx(ConfirmScreen, { message: UNSAFE_SELECTION_MESSAGE, onConfirm: confirmUnsafeSelection, yesLabel: "OK", noLabel: "Cancel", defaultNo: true, helpVisible: helpVisible(), width: unsafeConfirmContentWidth() }) })), _jsx(HelpOverlay, { visible: helpVisible(), context: currentScreen() }), _jsx(WizardController, { visible: wizardVisible(), selectedBranchName: selectedBranch()?.name ?? "", history: quickStartHistory(), onClose: handleWizardClose, onComplete: handleWizardComplete, onResume: handleWizardResume, onStartNew: handleWizardStartNew })] }));
|
|
1147
1345
|
}
|
|
1148
1346
|
const withTimeout = async (promise, timeoutMs) => new Promise((resolve, reject) => {
|
|
1149
1347
|
const timer = setTimeout(() => {
|