@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/src/cli/ui/App.solid.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
2
|
import { useKeyboard, useRenderer } from "@opentui/solid";
|
|
3
3
|
import {
|
|
4
|
+
batch,
|
|
4
5
|
createEffect,
|
|
5
6
|
createMemo,
|
|
6
7
|
createSignal,
|
|
@@ -35,6 +36,7 @@ import { LoadingIndicatorScreen } from "./screens/solid/LoadingIndicator.js";
|
|
|
35
36
|
import { WorktreeCreateScreen } from "./screens/solid/WorktreeCreateScreen.js";
|
|
36
37
|
import { InputScreen } from "./screens/solid/InputScreen.js";
|
|
37
38
|
import { ConfirmScreen } from "./screens/solid/ConfirmScreen.js";
|
|
39
|
+
import { useTerminalSize } from "./hooks/solid/useTerminalSize.js";
|
|
38
40
|
import { EnvironmentScreen } from "./screens/solid/EnvironmentScreen.js";
|
|
39
41
|
import { ProfileScreen } from "./screens/solid/ProfileScreen.js";
|
|
40
42
|
import { ProfileEnvScreen } from "./screens/solid/ProfileEnvScreen.js";
|
|
@@ -73,12 +75,16 @@ import {
|
|
|
73
75
|
loadSession,
|
|
74
76
|
type ToolSessionEntry,
|
|
75
77
|
} from "../../config/index.js";
|
|
78
|
+
import {
|
|
79
|
+
findLatestBranchSessionsByTool,
|
|
80
|
+
refreshQuickStartEntries,
|
|
81
|
+
} from "./utils/continueSession.js";
|
|
76
82
|
import { getAllCodingAgents } from "../../config/tools.js";
|
|
77
83
|
import {
|
|
78
|
-
|
|
84
|
+
clearLogFiles,
|
|
79
85
|
getTodayLogDate,
|
|
80
|
-
|
|
81
|
-
|
|
86
|
+
readLogLinesForDate,
|
|
87
|
+
resolveLogTarget,
|
|
82
88
|
} from "../../logging/reader.js";
|
|
83
89
|
import { parseLogLines } from "../../logging/formatter.js";
|
|
84
90
|
import { copyToClipboard } from "./utils/clipboard.js";
|
|
@@ -95,9 +101,13 @@ import {
|
|
|
95
101
|
type ProfilesConfig,
|
|
96
102
|
} from "../../types/profiles.js";
|
|
97
103
|
import { BRANCH_PREFIXES } from "../../config/constants.js";
|
|
104
|
+
import { prefetchAgentVersions } from "./utils/versionCache.js";
|
|
105
|
+
import { getBunxAgentIds } from "./utils/versionFetcher.js";
|
|
98
106
|
|
|
99
107
|
export type ExecutionMode = "normal" | "continue" | "resume";
|
|
100
108
|
|
|
109
|
+
const UNSAFE_SELECTION_MESSAGE = "Unsafe branch selected. Select anyway?";
|
|
110
|
+
|
|
101
111
|
export interface SelectionResult {
|
|
102
112
|
branch: string;
|
|
103
113
|
displayName: string;
|
|
@@ -192,6 +202,24 @@ const applyCleanupStatus = (
|
|
|
192
202
|
return worktree ? { ...base, worktree } : base;
|
|
193
203
|
});
|
|
194
204
|
|
|
205
|
+
const buildCleanupSafetyPending = (items: BranchItem[]): Set<string> => {
|
|
206
|
+
const pending = new Set<string>();
|
|
207
|
+
for (const branch of items) {
|
|
208
|
+
if (branch.type === "remote") {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (branch.worktree) {
|
|
212
|
+
pending.add(branch.name);
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (isProtectedBranchName(branch.name)) {
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
pending.add(branch.name);
|
|
219
|
+
}
|
|
220
|
+
return pending;
|
|
221
|
+
};
|
|
222
|
+
|
|
195
223
|
const toLocalBranchName = (name: string): string => {
|
|
196
224
|
const segments = name.split("/");
|
|
197
225
|
if (segments.length <= 1) {
|
|
@@ -208,12 +236,14 @@ const toSelectedBranchState = (branch: BranchItem): SelectedBranchState => {
|
|
|
208
236
|
displayName: branch.name,
|
|
209
237
|
branchType: branch.type,
|
|
210
238
|
branchCategory: branch.branchType,
|
|
239
|
+
worktreePath: branch.worktree?.path ?? null,
|
|
211
240
|
...(isRemote ? { remoteBranch: branch.name } : {}),
|
|
212
241
|
};
|
|
213
242
|
};
|
|
214
243
|
|
|
215
244
|
export function AppSolid(props: AppSolidProps) {
|
|
216
245
|
const renderer = useRenderer();
|
|
246
|
+
const terminal = useTerminalSize();
|
|
217
247
|
let hasExited = false;
|
|
218
248
|
|
|
219
249
|
const exitApp = (result?: SelectionResult) => {
|
|
@@ -239,6 +269,9 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
239
269
|
const [loading, setLoading] = createSignal(!props.branches);
|
|
240
270
|
const [error, setError] = createSignal<Error | null>(null);
|
|
241
271
|
|
|
272
|
+
// ブランチ一覧のカーソル位置(グローバル管理で再マウント時もリセットされない)
|
|
273
|
+
const [branchCursorPosition, setBranchCursorPosition] = createSignal(0);
|
|
274
|
+
|
|
242
275
|
const [toolItems, setToolItems] = createSignal<SelectorItem[]>([]);
|
|
243
276
|
const [toolError, setToolError] = createSignal<Error | null>(null);
|
|
244
277
|
|
|
@@ -257,6 +290,13 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
257
290
|
);
|
|
258
291
|
const [selectedMode, setSelectedMode] = createSignal<ExecutionMode>("normal");
|
|
259
292
|
const [selectedBranches, setSelectedBranches] = createSignal<string[]>([]);
|
|
293
|
+
const [unsafeSelectionConfirmVisible, setUnsafeSelectionConfirmVisible] =
|
|
294
|
+
createSignal(false);
|
|
295
|
+
const [unsafeConfirmInputLocked, setUnsafeConfirmInputLocked] =
|
|
296
|
+
createSignal(false);
|
|
297
|
+
const [unsafeSelectionTarget, setUnsafeSelectionTarget] = createSignal<
|
|
298
|
+
string | null
|
|
299
|
+
>(null);
|
|
260
300
|
const [branchFooterMessage, setBranchFooterMessage] = createSignal<{
|
|
261
301
|
text: string;
|
|
262
302
|
isSpinning?: boolean;
|
|
@@ -270,6 +310,9 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
270
310
|
Map<string, CleanupStatus>
|
|
271
311
|
>(new Map());
|
|
272
312
|
const [cleanupSafetyLoading, setCleanupSafetyLoading] = createSignal(false);
|
|
313
|
+
const [cleanupSafetyPending, setCleanupSafetyPending] = createSignal<
|
|
314
|
+
Set<string>
|
|
315
|
+
>(new Set());
|
|
273
316
|
const [isNewBranch, setIsNewBranch] = createSignal(false);
|
|
274
317
|
const [newBranchBaseRef, setNewBranchBaseRef] = createSignal<string | null>(
|
|
275
318
|
null,
|
|
@@ -284,20 +327,68 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
284
327
|
);
|
|
285
328
|
const [defaultBaseBranch, setDefaultBaseBranch] = createSignal("main");
|
|
286
329
|
|
|
330
|
+
const suppressBranchInputOnce = () => {
|
|
331
|
+
setUnsafeConfirmInputLocked(true);
|
|
332
|
+
queueMicrotask(() => {
|
|
333
|
+
setUnsafeConfirmInputLocked(false);
|
|
334
|
+
});
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const unsafeConfirmBoxWidth = createMemo(() => {
|
|
338
|
+
const columns = terminal().columns || 80;
|
|
339
|
+
return Math.max(1, Math.floor(columns * 0.6));
|
|
340
|
+
});
|
|
341
|
+
const unsafeConfirmContentWidth = createMemo(() =>
|
|
342
|
+
Math.max(0, unsafeConfirmBoxWidth() - 4),
|
|
343
|
+
);
|
|
344
|
+
|
|
287
345
|
// セッション履歴(最終使用エージェントなど)
|
|
288
346
|
const [sessionHistory, setSessionHistory] = createSignal<ToolSessionEntry[]>(
|
|
289
347
|
[],
|
|
290
348
|
);
|
|
349
|
+
const [quickStartHistory, setQuickStartHistory] = createSignal<
|
|
350
|
+
ToolSessionEntry[]
|
|
351
|
+
>([]);
|
|
291
352
|
|
|
292
353
|
// 選択中ブランチの履歴をフィルタリング
|
|
293
354
|
const historyForBranch = createMemo(() => {
|
|
294
355
|
const history = sessionHistory();
|
|
295
356
|
const branch = selectedBranch();
|
|
296
357
|
if (!branch) return [];
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
.
|
|
358
|
+
return findLatestBranchSessionsByTool(
|
|
359
|
+
history,
|
|
360
|
+
branch.name,
|
|
361
|
+
branch.worktreePath ?? null,
|
|
362
|
+
);
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
createEffect(() => {
|
|
366
|
+
setQuickStartHistory(historyForBranch());
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
createEffect(() => {
|
|
370
|
+
const branch = selectedBranch();
|
|
371
|
+
const baseHistory = historyForBranch();
|
|
372
|
+
if (!wizardVisible() || !branch || baseHistory.length === 0) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const worktreePath = branch.worktreePath ?? null;
|
|
377
|
+
if (!worktreePath) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const branchName = branch.name;
|
|
382
|
+
void (async () => {
|
|
383
|
+
const refreshed = await refreshQuickStartEntries(baseHistory, {
|
|
384
|
+
branch: branchName,
|
|
385
|
+
worktreePath,
|
|
386
|
+
});
|
|
387
|
+
if (selectedBranch()?.name !== branchName) {
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
setQuickStartHistory(refreshed);
|
|
391
|
+
})();
|
|
301
392
|
});
|
|
302
393
|
|
|
303
394
|
const [logEntries, setLogEntries] = createSignal<FormattedLogEntry[]>([]);
|
|
@@ -305,13 +396,17 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
305
396
|
const [logError, setLogError] = createSignal<string | null>(null);
|
|
306
397
|
const [logSelectedEntry, setLogSelectedEntry] =
|
|
307
398
|
createSignal<FormattedLogEntry | null>(null);
|
|
308
|
-
const [logSelectedDate,
|
|
399
|
+
const [logSelectedDate, setLogSelectedDate] = createSignal<string | null>(
|
|
309
400
|
getTodayLogDate(),
|
|
310
401
|
);
|
|
311
402
|
const [logNotification, setLogNotification] = createSignal<{
|
|
312
403
|
message: string;
|
|
313
404
|
tone: "success" | "error";
|
|
314
405
|
} | null>(null);
|
|
406
|
+
const [logTailEnabled, setLogTailEnabled] = createSignal(false);
|
|
407
|
+
const [logTargetBranch, setLogTargetBranch] = createSignal<BranchItem | null>(
|
|
408
|
+
null,
|
|
409
|
+
);
|
|
315
410
|
|
|
316
411
|
const [profileItems, setProfileItems] = createSignal<
|
|
317
412
|
{ name: string; displayName?: string; isActive?: boolean }[]
|
|
@@ -342,7 +437,26 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
342
437
|
const [profileConfirmMode, setProfileConfirmMode] =
|
|
343
438
|
createSignal<ProfileConfirmMode>("delete-profile");
|
|
344
439
|
|
|
345
|
-
const
|
|
440
|
+
const logTarget = createMemo(() =>
|
|
441
|
+
resolveLogTarget(logTargetBranch(), workingDirectory()),
|
|
442
|
+
);
|
|
443
|
+
const logBranchLabel = createMemo(() => logTargetBranch()?.label ?? null);
|
|
444
|
+
const logSourceLabel = createMemo(() => {
|
|
445
|
+
const target = logTarget();
|
|
446
|
+
if (!target.sourcePath) {
|
|
447
|
+
return "(none)";
|
|
448
|
+
}
|
|
449
|
+
if (
|
|
450
|
+
target.reason === "current-working-directory" ||
|
|
451
|
+
target.reason === "working-directory"
|
|
452
|
+
) {
|
|
453
|
+
return `${target.sourcePath} (cwd)`;
|
|
454
|
+
}
|
|
455
|
+
if (target.reason === "worktree-inaccessible") {
|
|
456
|
+
return `${target.sourcePath} (inaccessible)`;
|
|
457
|
+
}
|
|
458
|
+
return target.sourcePath;
|
|
459
|
+
});
|
|
346
460
|
const selectedProfileConfig = createMemo(() => {
|
|
347
461
|
const name = selectedProfileName();
|
|
348
462
|
const config = profilesConfig();
|
|
@@ -370,33 +484,62 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
370
484
|
let cleanupSafetyRequestId = 0;
|
|
371
485
|
const refreshCleanupSafety = async () => {
|
|
372
486
|
const requestId = ++cleanupSafetyRequestId;
|
|
373
|
-
|
|
487
|
+
const pendingBranches = buildCleanupSafetyPending(branchItems());
|
|
488
|
+
setCleanupSafetyPending(pendingBranches);
|
|
489
|
+
setCleanupSafetyLoading(pendingBranches.size > 0);
|
|
490
|
+
const statusByBranch = new Map<string, CleanupStatus>();
|
|
491
|
+
const applyProgress = (status: CleanupStatus) => {
|
|
492
|
+
if (requestId !== cleanupSafetyRequestId) {
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
statusByBranch.set(status.branch, status);
|
|
496
|
+
batch(() => {
|
|
497
|
+
setCleanupStatusByBranch(new Map(statusByBranch));
|
|
498
|
+
setBranchItems((items) => applyCleanupStatus(items, statusByBranch));
|
|
499
|
+
setCleanupSafetyPending((prev) => {
|
|
500
|
+
if (!prev.has(status.branch)) {
|
|
501
|
+
return prev;
|
|
502
|
+
}
|
|
503
|
+
const next = new Set(prev);
|
|
504
|
+
next.delete(status.branch);
|
|
505
|
+
return next;
|
|
506
|
+
});
|
|
507
|
+
});
|
|
508
|
+
};
|
|
374
509
|
try {
|
|
375
|
-
const cleanupStatuses = await getCleanupStatus(
|
|
510
|
+
const cleanupStatuses = await getCleanupStatus({
|
|
511
|
+
onProgress: applyProgress,
|
|
512
|
+
});
|
|
376
513
|
if (requestId !== cleanupSafetyRequestId) {
|
|
377
514
|
return;
|
|
378
515
|
}
|
|
379
|
-
|
|
380
|
-
cleanupStatuses.
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
516
|
+
if (cleanupStatuses.length > statusByBranch.size) {
|
|
517
|
+
cleanupStatuses.forEach((status) => {
|
|
518
|
+
if (!statusByBranch.has(status.branch)) {
|
|
519
|
+
applyProgress(status);
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
}
|
|
384
523
|
} catch (err) {
|
|
385
524
|
if (requestId !== cleanupSafetyRequestId) {
|
|
386
525
|
return;
|
|
387
526
|
}
|
|
388
527
|
logger.warn({ err }, "Failed to refresh cleanup safety indicators");
|
|
389
528
|
const empty = new Map<string, CleanupStatus>();
|
|
390
|
-
|
|
391
|
-
|
|
529
|
+
batch(() => {
|
|
530
|
+
setCleanupStatusByBranch(empty);
|
|
531
|
+
setBranchItems((items) => applyCleanupStatus(items, empty));
|
|
532
|
+
});
|
|
392
533
|
} finally {
|
|
393
534
|
if (requestId === cleanupSafetyRequestId) {
|
|
394
535
|
setCleanupSafetyLoading(false);
|
|
536
|
+
setCleanupSafetyPending(new Set<string>());
|
|
395
537
|
}
|
|
396
538
|
}
|
|
397
539
|
};
|
|
398
540
|
|
|
399
541
|
let logNotificationTimer: ReturnType<typeof setTimeout> | null = null;
|
|
542
|
+
let logTailTimer: ReturnType<typeof setInterval> | null = null;
|
|
400
543
|
let branchFooterTimer: ReturnType<typeof setTimeout> | null = null;
|
|
401
544
|
const BRANCH_LOAD_TIMEOUT_MS = 3000;
|
|
402
545
|
const BRANCH_FULL_LOAD_TIMEOUT_MS = 8000;
|
|
@@ -480,9 +623,20 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
480
623
|
setLogLoading(true);
|
|
481
624
|
setLogError(null);
|
|
482
625
|
try {
|
|
483
|
-
const
|
|
484
|
-
|
|
485
|
-
|
|
626
|
+
const target = logTarget();
|
|
627
|
+
if (!target.logDir) {
|
|
628
|
+
setLogEntries([]);
|
|
629
|
+
setLogSelectedDate(targetDate);
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
const result = await readLogLinesForDate(target.logDir, targetDate);
|
|
633
|
+
if (!result) {
|
|
634
|
+
setLogEntries([]);
|
|
635
|
+
setLogSelectedDate(targetDate);
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
setLogSelectedDate(result.date);
|
|
639
|
+
const parsed = parseLogLines(result.lines, { limit: 100 });
|
|
486
640
|
setLogEntries(parsed);
|
|
487
641
|
} catch (err) {
|
|
488
642
|
setLogEntries([]);
|
|
@@ -492,10 +646,40 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
492
646
|
}
|
|
493
647
|
};
|
|
494
648
|
|
|
649
|
+
const clearLogTailTimer = () => {
|
|
650
|
+
if (logTailTimer) {
|
|
651
|
+
clearInterval(logTailTimer);
|
|
652
|
+
logTailTimer = null;
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
const toggleLogTail = () => {
|
|
657
|
+
setLogTailEnabled((prev) => !prev);
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
const resetLogFiles = async () => {
|
|
661
|
+
const target = logTarget();
|
|
662
|
+
if (!target.logDir) {
|
|
663
|
+
showLogNotification("No logs available.", "error");
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
try {
|
|
667
|
+
const cleared = await clearLogFiles(target.logDir);
|
|
668
|
+
if (cleared === 0) {
|
|
669
|
+
showLogNotification("No logs to reset.", "error");
|
|
670
|
+
} else {
|
|
671
|
+
showLogNotification("Logs cleared.", "success");
|
|
672
|
+
}
|
|
673
|
+
await loadLogEntries(logSelectedDate());
|
|
674
|
+
} catch (err) {
|
|
675
|
+
logger.warn({ err }, "Failed to clear log files");
|
|
676
|
+
showLogNotification("Failed to reset logs.", "error");
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
|
|
495
680
|
const refreshBranches = async () => {
|
|
496
681
|
setLoading(true);
|
|
497
682
|
setError(null);
|
|
498
|
-
void refreshCleanupSafety();
|
|
499
683
|
try {
|
|
500
684
|
const repoRoot = await getRepositoryRoot();
|
|
501
685
|
const worktreesPromise = listAdditionalWorktrees();
|
|
@@ -536,6 +720,7 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
536
720
|
);
|
|
537
721
|
setBranchItems(initialItems);
|
|
538
722
|
setStats(buildStats(initialItems));
|
|
723
|
+
void refreshCleanupSafety();
|
|
539
724
|
|
|
540
725
|
void (async () => {
|
|
541
726
|
const [branches, latestWorktrees] = await Promise.all([
|
|
@@ -659,16 +844,37 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
659
844
|
});
|
|
660
845
|
});
|
|
661
846
|
|
|
847
|
+
// FR-028: Prefetch npm versions for all bunx-type agents at startup (background)
|
|
848
|
+
onMount(() => {
|
|
849
|
+
const bunxAgentIds = getBunxAgentIds();
|
|
850
|
+
void prefetchAgentVersions(bunxAgentIds).catch(() => {
|
|
851
|
+
// Silently handle errors - cache will return null and UI will show "latest" only
|
|
852
|
+
});
|
|
853
|
+
});
|
|
854
|
+
|
|
662
855
|
createEffect(() => {
|
|
663
856
|
if (currentScreen() === "log-list") {
|
|
857
|
+
logTarget();
|
|
664
858
|
void loadLogEntries(logSelectedDate());
|
|
665
859
|
}
|
|
666
860
|
});
|
|
667
861
|
|
|
862
|
+
createEffect(() => {
|
|
863
|
+
if (currentScreen() !== "log-list" || !logTailEnabled()) {
|
|
864
|
+
clearLogTailTimer();
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
clearLogTailTimer();
|
|
868
|
+
logTailTimer = setInterval(() => {
|
|
869
|
+
void loadLogEntries(logSelectedDate());
|
|
870
|
+
}, 1500);
|
|
871
|
+
});
|
|
872
|
+
|
|
668
873
|
onCleanup(() => {
|
|
669
874
|
if (logNotificationTimer) {
|
|
670
875
|
clearTimeout(logNotificationTimer);
|
|
671
876
|
}
|
|
877
|
+
clearLogTailTimer();
|
|
672
878
|
if (branchFooterTimer) {
|
|
673
879
|
clearTimeout(branchFooterTimer);
|
|
674
880
|
}
|
|
@@ -784,6 +990,11 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
784
990
|
|
|
785
991
|
// FR-010: クイックスタートからのResume(前回設定で続きから)
|
|
786
992
|
const handleWizardResume = (entry: ToolSessionEntry) => {
|
|
993
|
+
if (!entry.sessionId) {
|
|
994
|
+
handleWizardStartNew(entry);
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
|
|
787
998
|
setWizardVisible(false);
|
|
788
999
|
|
|
789
1000
|
const branch = selectedBranch();
|
|
@@ -915,25 +1126,10 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
915
1126
|
skipCounts.remote += 1;
|
|
916
1127
|
continue;
|
|
917
1128
|
}
|
|
918
|
-
if (isProtectedBranchName(branch.name)) {
|
|
919
|
-
skipCounts.protected += 1;
|
|
920
|
-
continue;
|
|
921
|
-
}
|
|
922
1129
|
if (branch.isCurrent) {
|
|
923
1130
|
skipCounts.current += 1;
|
|
924
1131
|
continue;
|
|
925
1132
|
}
|
|
926
|
-
const hasUncommitted =
|
|
927
|
-
branch.worktree?.hasUncommittedChanges === true;
|
|
928
|
-
const hasUnpushed = branch.hasUnpushedCommits === true;
|
|
929
|
-
if (hasUncommitted || hasUnpushed) {
|
|
930
|
-
skipCounts.unsafe += 1;
|
|
931
|
-
continue;
|
|
932
|
-
}
|
|
933
|
-
if (branch.safeToCleanup !== true) {
|
|
934
|
-
skipCounts.unsafe += 1;
|
|
935
|
-
continue;
|
|
936
|
-
}
|
|
937
1133
|
const worktreePath = branch.worktree?.path ?? null;
|
|
938
1134
|
const cleanupType: CleanupTask["cleanupType"] = worktreePath
|
|
939
1135
|
? "worktree-and-branch"
|
|
@@ -1051,13 +1247,14 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
1051
1247
|
return;
|
|
1052
1248
|
}
|
|
1053
1249
|
|
|
1054
|
-
//
|
|
1250
|
+
// 選択されたローカルブランチのうち、Worktreeを持つものを修復対象とする
|
|
1055
1251
|
const selectionSet = new Set(selection);
|
|
1056
1252
|
const targets = branchItems()
|
|
1057
1253
|
.filter(
|
|
1058
1254
|
(branch) =>
|
|
1059
1255
|
selectionSet.has(branch.name) &&
|
|
1060
|
-
branch.
|
|
1256
|
+
branch.type !== "remote" &&
|
|
1257
|
+
branch.worktreeStatus !== undefined,
|
|
1061
1258
|
)
|
|
1062
1259
|
.map((branch) => branch.name);
|
|
1063
1260
|
|
|
@@ -1309,15 +1506,51 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
1309
1506
|
};
|
|
1310
1507
|
|
|
1311
1508
|
const toggleSelectedBranch = (branchName: string) => {
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
return
|
|
1320
|
-
}
|
|
1509
|
+
if (unsafeSelectionConfirmVisible()) {
|
|
1510
|
+
return;
|
|
1511
|
+
}
|
|
1512
|
+
const currentSelection = new Set(selectedBranches());
|
|
1513
|
+
if (currentSelection.has(branchName)) {
|
|
1514
|
+
currentSelection.delete(branchName);
|
|
1515
|
+
setSelectedBranches(Array.from(currentSelection));
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
const branch = branchItems().find((item) => item.name === branchName);
|
|
1520
|
+
const pending = cleanupSafetyPending();
|
|
1521
|
+
const hasSafetyPending = pending.has(branchName);
|
|
1522
|
+
const hasUncommitted = branch?.worktree?.hasUncommittedChanges === true;
|
|
1523
|
+
const hasUnpushed = branch?.hasUnpushedCommits === true;
|
|
1524
|
+
const isUnmerged = branch?.isUnmerged === true;
|
|
1525
|
+
const safeToCleanup = branch?.safeToCleanup === true;
|
|
1526
|
+
const isRemoteBranch = branch?.type === "remote";
|
|
1527
|
+
const isUnsafe =
|
|
1528
|
+
Boolean(branch) &&
|
|
1529
|
+
!isRemoteBranch &&
|
|
1530
|
+
!hasSafetyPending &&
|
|
1531
|
+
(hasUncommitted || hasUnpushed || isUnmerged || !safeToCleanup);
|
|
1532
|
+
|
|
1533
|
+
if (branch && isUnsafe) {
|
|
1534
|
+
setUnsafeSelectionTarget(branch.name);
|
|
1535
|
+
setUnsafeSelectionConfirmVisible(true);
|
|
1536
|
+
return;
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
currentSelection.add(branchName);
|
|
1540
|
+
setSelectedBranches(Array.from(currentSelection));
|
|
1541
|
+
};
|
|
1542
|
+
|
|
1543
|
+
const confirmUnsafeSelection = (confirmed: boolean) => {
|
|
1544
|
+
suppressBranchInputOnce();
|
|
1545
|
+
const target = unsafeSelectionTarget();
|
|
1546
|
+
setUnsafeSelectionConfirmVisible(false);
|
|
1547
|
+
setUnsafeSelectionTarget(null);
|
|
1548
|
+
if (!confirmed || !target) {
|
|
1549
|
+
return;
|
|
1550
|
+
}
|
|
1551
|
+
setSelectedBranches((prev) =>
|
|
1552
|
+
prev.includes(target) ? prev : [...prev, target],
|
|
1553
|
+
);
|
|
1321
1554
|
};
|
|
1322
1555
|
|
|
1323
1556
|
const handleToolSelect = (item: SelectorItem) => {
|
|
@@ -1371,8 +1604,9 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
1371
1604
|
const cleanupUI = {
|
|
1372
1605
|
indicators: cleanupIndicators(),
|
|
1373
1606
|
footerMessage: branchFooterMessage(),
|
|
1374
|
-
inputLocked: branchInputLocked(),
|
|
1607
|
+
inputLocked: branchInputLocked() || unsafeConfirmInputLocked(),
|
|
1375
1608
|
safetyLoading: cleanupSafetyLoading(),
|
|
1609
|
+
safetyPendingBranches: cleanupSafetyPending(),
|
|
1376
1610
|
};
|
|
1377
1611
|
return (
|
|
1378
1612
|
<BranchListScreen
|
|
@@ -1390,7 +1624,13 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
1390
1624
|
version={version()}
|
|
1391
1625
|
workingDirectory={workingDirectory()}
|
|
1392
1626
|
activeProfile={activeProfile()}
|
|
1393
|
-
onOpenLogs={() =>
|
|
1627
|
+
onOpenLogs={(branch) => {
|
|
1628
|
+
setLogTargetBranch(branch);
|
|
1629
|
+
setLogSelectedEntry(null);
|
|
1630
|
+
setLogSelectedDate(getTodayLogDate());
|
|
1631
|
+
setLogTailEnabled(false);
|
|
1632
|
+
navigateTo("log-list");
|
|
1633
|
+
}}
|
|
1394
1634
|
onOpenProfiles={() => navigateTo("profile")}
|
|
1395
1635
|
selectedBranches={selectedBranches()}
|
|
1396
1636
|
onToggleSelect={toggleSelectedBranch}
|
|
@@ -1398,6 +1638,9 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
1398
1638
|
cleanupUI={cleanupUI}
|
|
1399
1639
|
helpVisible={helpVisible()}
|
|
1400
1640
|
wizardVisible={wizardVisible()}
|
|
1641
|
+
confirmVisible={unsafeSelectionConfirmVisible()}
|
|
1642
|
+
cursorPosition={branchCursorPosition()}
|
|
1643
|
+
onCursorPositionChange={setBranchCursorPosition}
|
|
1401
1644
|
/>
|
|
1402
1645
|
);
|
|
1403
1646
|
}
|
|
@@ -1473,9 +1716,15 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
1473
1716
|
showLogNotification("Failed to copy to clipboard.", "error");
|
|
1474
1717
|
}
|
|
1475
1718
|
}}
|
|
1719
|
+
onReload={() => void loadLogEntries(logSelectedDate())}
|
|
1720
|
+
onToggleTail={toggleLogTail}
|
|
1721
|
+
onReset={() => void resetLogFiles()}
|
|
1476
1722
|
notification={logNotification()}
|
|
1477
1723
|
version={version()}
|
|
1478
1724
|
selectedDate={logSelectedDate()}
|
|
1725
|
+
branchLabel={logBranchLabel()}
|
|
1726
|
+
sourceLabel={logSourceLabel()}
|
|
1727
|
+
tailing={logTailEnabled()}
|
|
1479
1728
|
helpVisible={helpVisible()}
|
|
1480
1729
|
/>
|
|
1481
1730
|
);
|
|
@@ -1742,12 +1991,36 @@ export function AppSolid(props: AppSolidProps) {
|
|
|
1742
1991
|
return (
|
|
1743
1992
|
<>
|
|
1744
1993
|
{renderCurrentScreen()}
|
|
1994
|
+
{unsafeSelectionConfirmVisible() && (
|
|
1995
|
+
<box
|
|
1996
|
+
position="absolute"
|
|
1997
|
+
top="30%"
|
|
1998
|
+
left="20%"
|
|
1999
|
+
width={unsafeConfirmBoxWidth()}
|
|
2000
|
+
zIndex={110}
|
|
2001
|
+
border
|
|
2002
|
+
borderStyle="single"
|
|
2003
|
+
borderColor="yellow"
|
|
2004
|
+
backgroundColor="black"
|
|
2005
|
+
padding={1}
|
|
2006
|
+
>
|
|
2007
|
+
<ConfirmScreen
|
|
2008
|
+
message={UNSAFE_SELECTION_MESSAGE}
|
|
2009
|
+
onConfirm={confirmUnsafeSelection}
|
|
2010
|
+
yesLabel="OK"
|
|
2011
|
+
noLabel="Cancel"
|
|
2012
|
+
defaultNo
|
|
2013
|
+
helpVisible={helpVisible()}
|
|
2014
|
+
width={unsafeConfirmContentWidth()}
|
|
2015
|
+
/>
|
|
2016
|
+
</box>
|
|
2017
|
+
)}
|
|
1745
2018
|
<HelpOverlay visible={helpVisible()} context={currentScreen()} />
|
|
1746
2019
|
{/* FR-044: ウィザードポップアップをレイヤー表示 */}
|
|
1747
2020
|
<WizardController
|
|
1748
2021
|
visible={wizardVisible()}
|
|
1749
2022
|
selectedBranchName={selectedBranch()?.name ?? ""}
|
|
1750
|
-
history={
|
|
2023
|
+
history={quickStartHistory()}
|
|
1751
2024
|
onClose={handleWizardClose}
|
|
1752
2025
|
onComplete={handleWizardComplete}
|
|
1753
2026
|
onResume={handleWizardResume}
|