@akiojin/gwt 4.11.6 → 4.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/gwt.js +36 -10
- package/dist/claude.d.ts +1 -0
- package/dist/claude.d.ts.map +1 -1
- package/dist/claude.js +81 -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 +280 -50
- 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 +67 -13
- package/dist/cli/ui/components/solid/WizardController.js.map +1 -1
- package/dist/cli/ui/components/solid/WizardSteps.d.ts +5 -0
- package/dist/cli/ui/components/solid/WizardSteps.d.ts.map +1 -1
- package/dist/cli/ui/components/solid/WizardSteps.js +50 -70
- 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/installedVersionCache.d.ts +33 -0
- package/dist/cli/ui/utils/installedVersionCache.d.ts.map +1 -0
- package/dist/cli/ui/utils/installedVersionCache.js +59 -0
- package/dist/cli/ui/utils/installedVersionCache.js.map +1 -0
- package/dist/cli/ui/utils/modelOptions.d.ts.map +1 -1
- package/dist/cli/ui/utils/modelOptions.js +16 -0
- package/dist/cli/ui/utils/modelOptions.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 +95 -25
- 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 +35 -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 +22 -0
- package/dist/logging/reader.d.ts.map +1 -1
- package/dist/logging/reader.js +116 -1
- package/dist/logging/reader.js.map +1 -1
- package/dist/opentui/index.solid.js +2575 -888
- package/dist/services/codingAgentResolver.d.ts.map +1 -1
- package/dist/services/codingAgentResolver.js +8 -6
- package/dist/services/codingAgentResolver.js.map +1 -1
- package/dist/services/dependency-installer.js +2 -2
- package/dist/services/dependency-installer.js.map +1 -1
- package/dist/shared/codingAgentConstants.d.ts +3 -0
- package/dist/shared/codingAgentConstants.d.ts.map +1 -1
- package/dist/shared/codingAgentConstants.js +66 -0
- package/dist/shared/codingAgentConstants.js.map +1 -1
- package/dist/utils/bun-runtime.d.ts +12 -0
- package/dist/utils/bun-runtime.d.ts.map +1 -0
- package/dist/utils/bun-runtime.js +13 -0
- package/dist/utils/bun-runtime.js.map +1 -0
- 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 +47 -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 +99 -28
- package/src/cli/ui/App.solid.tsx +373 -51
- package/src/cli/ui/__tests__/solid/AppSolid.cleanup.test.tsx +921 -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/WizardController.test.tsx +71 -0
- package/src/cli/ui/__tests__/solid/components/WizardSteps.test.tsx +95 -2
- 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 +85 -12
- package/src/cli/ui/components/solid/WizardSteps.tsx +78 -90
- 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/__tests__/installedVersionCache.test.ts +46 -0
- package/src/cli/ui/utils/branchFormatter.ts +35 -7
- package/src/cli/ui/utils/continueSession.ts +90 -3
- package/src/cli/ui/utils/installedVersionCache.ts +84 -0
- package/src/cli/ui/utils/modelOptions.test.ts +6 -0
- package/src/cli/ui/utils/modelOptions.ts +16 -0
- package/src/cli/ui/utils/versionCache.ts +93 -0
- package/src/cli/ui/utils/versionFetcher.ts +120 -0
- package/src/codex.ts +124 -26
- 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 +41 -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 +165 -1
- package/src/services/__tests__/BatchMergeService.test.ts +34 -14
- package/src/services/codingAgentResolver.ts +12 -5
- package/src/services/dependency-installer.ts +2 -2
- package/src/shared/codingAgentConstants.ts +73 -0
- package/src/utils/bun-runtime.ts +29 -0
- package/src/utils/session/common.ts +28 -0
- package/src/utils/session/parsers/claude.ts +79 -29
- package/src/utils/session/parsers/codex.ts +49 -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
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** @jsxImportSource @opentui/solid */
|
|
2
|
+
import { describe, expect, it, mock } from "bun:test";
|
|
3
|
+
import { testRender } from "@opentui/solid";
|
|
4
|
+
import type { ToolSessionEntry } from "../../../../config/index.js";
|
|
5
|
+
|
|
6
|
+
mock.module("../../../utils/versionFetcher.js", () => ({
|
|
7
|
+
fetchInstalledVersionForAgent: mock(async () => null),
|
|
8
|
+
createInstalledOption: (version: string) => ({
|
|
9
|
+
label: `installed (${version})`,
|
|
10
|
+
value: "installed",
|
|
11
|
+
}),
|
|
12
|
+
versionInfoToSelectItem: (v: { version: string }) => ({
|
|
13
|
+
label: v.version,
|
|
14
|
+
value: v.version,
|
|
15
|
+
}),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
describe("WizardController", () => {
|
|
19
|
+
it("keeps version selection visible after agent select", async () => {
|
|
20
|
+
const history: ToolSessionEntry[] = [];
|
|
21
|
+
|
|
22
|
+
const { WizardController } =
|
|
23
|
+
await import("../../../components/solid/WizardController.js");
|
|
24
|
+
|
|
25
|
+
const testSetup = await testRender(
|
|
26
|
+
() => (
|
|
27
|
+
<WizardController
|
|
28
|
+
visible
|
|
29
|
+
selectedBranchName="feature/test"
|
|
30
|
+
history={history}
|
|
31
|
+
onClose={() => {}}
|
|
32
|
+
onComplete={() => {}}
|
|
33
|
+
onResume={() => {}}
|
|
34
|
+
onStartNew={() => {}}
|
|
35
|
+
/>
|
|
36
|
+
),
|
|
37
|
+
{ width: 80, height: 24 },
|
|
38
|
+
);
|
|
39
|
+
await testSetup.renderOnce();
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
let frame = testSetup.captureCharFrame();
|
|
43
|
+
expect(frame).toContain("What would you like to do?");
|
|
44
|
+
|
|
45
|
+
await new Promise((resolve) => setTimeout(resolve, 60));
|
|
46
|
+
await testSetup.renderOnce();
|
|
47
|
+
|
|
48
|
+
// Open existing worktree
|
|
49
|
+
testSetup.mockInput.pressEnter();
|
|
50
|
+
await testSetup.renderOnce();
|
|
51
|
+
|
|
52
|
+
frame = testSetup.captureCharFrame();
|
|
53
|
+
expect(frame).toContain("Select coding agent:");
|
|
54
|
+
|
|
55
|
+
await new Promise((resolve) => setTimeout(resolve, 60));
|
|
56
|
+
await testSetup.renderOnce();
|
|
57
|
+
|
|
58
|
+
// Select default agent (Enter)
|
|
59
|
+
testSetup.mockInput.pressEnter();
|
|
60
|
+
await testSetup.renderOnce();
|
|
61
|
+
await new Promise((resolve) => setTimeout(resolve, 60));
|
|
62
|
+
await testSetup.renderOnce();
|
|
63
|
+
|
|
64
|
+
frame = testSetup.captureCharFrame();
|
|
65
|
+
expect(frame).toContain("Select version:");
|
|
66
|
+
expect(frame).not.toContain("Select Model:");
|
|
67
|
+
} finally {
|
|
68
|
+
testSetup.renderer.destroy();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
@@ -1,15 +1,24 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
|
-
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { beforeEach, describe, expect, it } from "bun:test";
|
|
3
3
|
import { testRender } from "@opentui/solid";
|
|
4
4
|
import {
|
|
5
5
|
BranchTypeStep,
|
|
6
6
|
BranchNameStep,
|
|
7
7
|
AgentSelectStep,
|
|
8
|
+
VersionSelectStep,
|
|
8
9
|
ModelSelectStep,
|
|
9
10
|
ReasoningLevelStep,
|
|
10
11
|
ExecutionModeStep,
|
|
11
12
|
SkipPermissionsStep,
|
|
12
13
|
} from "../../../components/solid/WizardSteps.js";
|
|
14
|
+
import {
|
|
15
|
+
clearInstalledVersionCache,
|
|
16
|
+
setInstalledVersionCache,
|
|
17
|
+
} from "../../../utils/installedVersionCache.js";
|
|
18
|
+
import {
|
|
19
|
+
clearVersionCache,
|
|
20
|
+
setVersionCache,
|
|
21
|
+
} from "../../../utils/versionCache.js";
|
|
13
22
|
|
|
14
23
|
// T405: ブランチタイプ選択ステップのテスト
|
|
15
24
|
describe("BranchTypeStep", () => {
|
|
@@ -128,6 +137,65 @@ describe("AgentSelectStep", () => {
|
|
|
128
137
|
});
|
|
129
138
|
});
|
|
130
139
|
|
|
140
|
+
// T407a: バージョン選択ステップのテスト
|
|
141
|
+
describe("VersionSelectStep", () => {
|
|
142
|
+
beforeEach(() => {
|
|
143
|
+
clearInstalledVersionCache();
|
|
144
|
+
clearVersionCache();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("renders installed option from cache", async () => {
|
|
148
|
+
setInstalledVersionCache("claude-code", {
|
|
149
|
+
version: "1.2.3",
|
|
150
|
+
path: "/usr/local/bin/claude",
|
|
151
|
+
});
|
|
152
|
+
setVersionCache("claude-code", []);
|
|
153
|
+
|
|
154
|
+
const testSetup = await testRender(
|
|
155
|
+
() => (
|
|
156
|
+
<VersionSelectStep
|
|
157
|
+
agentId="claude-code"
|
|
158
|
+
onSelect={() => {}}
|
|
159
|
+
onBack={() => {}}
|
|
160
|
+
/>
|
|
161
|
+
),
|
|
162
|
+
{ width: 60, height: 20 },
|
|
163
|
+
);
|
|
164
|
+
await testSetup.renderOnce();
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
const frame = testSetup.captureCharFrame();
|
|
168
|
+
expect(frame).toContain("Select version");
|
|
169
|
+
expect(frame).toContain("installed@1.2.3");
|
|
170
|
+
expect(frame).toContain("latest");
|
|
171
|
+
} finally {
|
|
172
|
+
testSetup.renderer.destroy();
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("does not render installed option when cache is empty", async () => {
|
|
177
|
+
const testSetup = await testRender(
|
|
178
|
+
() => (
|
|
179
|
+
<VersionSelectStep
|
|
180
|
+
agentId="claude-code"
|
|
181
|
+
onSelect={() => {}}
|
|
182
|
+
onBack={() => {}}
|
|
183
|
+
/>
|
|
184
|
+
),
|
|
185
|
+
{ width: 60, height: 20 },
|
|
186
|
+
);
|
|
187
|
+
await testSetup.renderOnce();
|
|
188
|
+
|
|
189
|
+
try {
|
|
190
|
+
const frame = testSetup.captureCharFrame();
|
|
191
|
+
expect(frame).toContain("latest");
|
|
192
|
+
expect(frame).not.toContain("installed@");
|
|
193
|
+
} finally {
|
|
194
|
+
testSetup.renderer.destroy();
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
|
|
131
199
|
// T408: モデル選択ステップのテスト
|
|
132
200
|
describe("ModelSelectStep", () => {
|
|
133
201
|
it("renders model options for Claude Code", async () => {
|
|
@@ -150,6 +218,28 @@ describe("ModelSelectStep", () => {
|
|
|
150
218
|
testSetup.renderer.destroy();
|
|
151
219
|
}
|
|
152
220
|
});
|
|
221
|
+
|
|
222
|
+
it("renders model options for OpenCode", async () => {
|
|
223
|
+
const testSetup = await testRender(
|
|
224
|
+
() => (
|
|
225
|
+
<ModelSelectStep
|
|
226
|
+
agentId="opencode"
|
|
227
|
+
onSelect={() => {}}
|
|
228
|
+
onBack={() => {}}
|
|
229
|
+
/>
|
|
230
|
+
),
|
|
231
|
+
{ width: 60, height: 20 },
|
|
232
|
+
);
|
|
233
|
+
await testSetup.renderOnce();
|
|
234
|
+
|
|
235
|
+
try {
|
|
236
|
+
const frame = testSetup.captureCharFrame();
|
|
237
|
+
expect(frame).toContain("Default (Auto)");
|
|
238
|
+
expect(frame).toContain("Custom");
|
|
239
|
+
} finally {
|
|
240
|
+
testSetup.renderer.destroy();
|
|
241
|
+
}
|
|
242
|
+
});
|
|
153
243
|
});
|
|
154
244
|
|
|
155
245
|
// T409: 推論レベル選択ステップ(Codexのみ)のテスト
|
|
@@ -230,7 +320,10 @@ describe("SkipPermissionsStep", () => {
|
|
|
230
320
|
// Enterキーで選択(デフォルトはYes)
|
|
231
321
|
testSetup.mockInput.pressEnter();
|
|
232
322
|
await testSetup.renderOnce();
|
|
233
|
-
|
|
323
|
+
if (selected === null) {
|
|
324
|
+
throw new Error("Expected selection");
|
|
325
|
+
}
|
|
326
|
+
expect(selected === true).toBe(true);
|
|
234
327
|
} finally {
|
|
235
328
|
testSetup.renderer.destroy();
|
|
236
329
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
1
2
|
import { describe, it, expect } from "bun:test";
|
|
2
3
|
import {
|
|
3
4
|
formatBranchItem,
|
|
@@ -5,6 +6,31 @@ import {
|
|
|
5
6
|
} from "../../utils/branchFormatter.js";
|
|
6
7
|
import type { BranchInfo } from "../../types.js";
|
|
7
8
|
|
|
9
|
+
const LOCAL_DATE_TIME_FORMATTER = new Intl.DateTimeFormat(undefined, {
|
|
10
|
+
year: "numeric",
|
|
11
|
+
month: "2-digit",
|
|
12
|
+
day: "2-digit",
|
|
13
|
+
hour: "2-digit",
|
|
14
|
+
minute: "2-digit",
|
|
15
|
+
hour12: false,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const formatLocalDateTime = (timestampMs: number): string => {
|
|
19
|
+
const date = new Date(timestampMs);
|
|
20
|
+
const parts = LOCAL_DATE_TIME_FORMATTER.formatToParts(date);
|
|
21
|
+
const get = (type: Intl.DateTimeFormatPartTypes) =>
|
|
22
|
+
parts.find((part) => part.type === type)?.value;
|
|
23
|
+
const year = get("year");
|
|
24
|
+
const month = get("month");
|
|
25
|
+
const day = get("day");
|
|
26
|
+
const hour = get("hour");
|
|
27
|
+
const minute = get("minute");
|
|
28
|
+
if (!year || !month || !day || !hour || !minute) {
|
|
29
|
+
return LOCAL_DATE_TIME_FORMATTER.format(date);
|
|
30
|
+
}
|
|
31
|
+
return `${year}-${month}-${day} ${hour}:${minute}`;
|
|
32
|
+
};
|
|
33
|
+
|
|
8
34
|
describe("branchFormatter", () => {
|
|
9
35
|
describe("formatBranchItem", () => {
|
|
10
36
|
it("should format a branch without icons", () => {
|
|
@@ -46,8 +72,9 @@ describe("branchFormatter", () => {
|
|
|
46
72
|
|
|
47
73
|
const result = formatBranchItem(branchInfo);
|
|
48
74
|
|
|
49
|
-
expect(result.lastToolUsageLabel).
|
|
50
|
-
|
|
75
|
+
expect(result.lastToolUsageLabel).toBe(
|
|
76
|
+
`Codex@latest | ${formatLocalDateTime(branchInfo.lastToolUsage.timestamp)}`,
|
|
77
|
+
);
|
|
51
78
|
});
|
|
52
79
|
|
|
53
80
|
it("should set lastToolUsageLabel to null when no usage exists", () => {
|
|
@@ -156,13 +183,13 @@ describe("branchFormatter", () => {
|
|
|
156
183
|
|
|
157
184
|
expect(results).toHaveLength(3);
|
|
158
185
|
// Current branch (main) should be first
|
|
159
|
-
expect(results[0]
|
|
160
|
-
expect(results[0]
|
|
186
|
+
expect(results[0]!.name).toBe("main");
|
|
187
|
+
expect(results[0]!.isCurrent).toBe(true);
|
|
161
188
|
// origin/main is also main branch, so it comes second
|
|
162
|
-
expect(results[1]
|
|
163
|
-
expect(results[1]
|
|
189
|
+
expect(results[1]!.name).toBe("origin/main");
|
|
190
|
+
expect(results[1]!.type).toBe("remote");
|
|
164
191
|
// feature/test comes last
|
|
165
|
-
expect(results[2]
|
|
192
|
+
expect(results[2]!.name).toBe("feature/test");
|
|
166
193
|
});
|
|
167
194
|
|
|
168
195
|
it("should handle empty array", () => {
|
|
@@ -189,8 +216,8 @@ describe("branchFormatter", () => {
|
|
|
189
216
|
|
|
190
217
|
const results = formatBranchItems(branches);
|
|
191
218
|
|
|
192
|
-
expect(results[0]
|
|
193
|
-
expect(results[1]
|
|
219
|
+
expect(results[0]!.name).toBe("a-branch");
|
|
220
|
+
expect(results[1]!.name).toBe("z-branch");
|
|
194
221
|
});
|
|
195
222
|
});
|
|
196
223
|
|
|
@@ -219,8 +246,8 @@ describe("branchFormatter", () => {
|
|
|
219
246
|
|
|
220
247
|
const results = formatBranchItems(branches);
|
|
221
248
|
|
|
222
|
-
expect(results[0]
|
|
223
|
-
expect(results[0]
|
|
249
|
+
expect(results[0]!.name).toBe("feature/current");
|
|
250
|
+
expect(results[0]!.isCurrent).toBe(true);
|
|
224
251
|
});
|
|
225
252
|
|
|
226
253
|
it("should prioritize main branch as second (after current)", () => {
|
|
@@ -247,8 +274,8 @@ describe("branchFormatter", () => {
|
|
|
247
274
|
|
|
248
275
|
const results = formatBranchItems(branches);
|
|
249
276
|
|
|
250
|
-
expect(results[0]
|
|
251
|
-
expect(results[1]
|
|
277
|
+
expect(results[0]!.name).toBe("main");
|
|
278
|
+
expect(results[1]!.name).toBe("develop");
|
|
252
279
|
});
|
|
253
280
|
|
|
254
281
|
it("should prioritize develop branch after main (when main exists)", () => {
|
|
@@ -275,9 +302,9 @@ describe("branchFormatter", () => {
|
|
|
275
302
|
|
|
276
303
|
const results = formatBranchItems(branches);
|
|
277
304
|
|
|
278
|
-
expect(results[0]
|
|
279
|
-
expect(results[1]
|
|
280
|
-
expect(results[2]
|
|
305
|
+
expect(results[0]!.name).toBe("main");
|
|
306
|
+
expect(results[1]!.name).toBe("develop");
|
|
307
|
+
expect(results[2]!.name).toBe("feature/test");
|
|
281
308
|
});
|
|
282
309
|
|
|
283
310
|
it("should NOT prioritize develop branch when main does not exist", () => {
|
|
@@ -305,9 +332,9 @@ describe("branchFormatter", () => {
|
|
|
305
332
|
const results = formatBranchItems(branches);
|
|
306
333
|
|
|
307
334
|
// develop should be sorted alphabetically, not prioritized
|
|
308
|
-
expect(results[0]
|
|
309
|
-
expect(results[1]
|
|
310
|
-
expect(results[2]
|
|
335
|
+
expect(results[0]!.name).toBe("develop");
|
|
336
|
+
expect(results[1]!.name).toBe("feature/a");
|
|
337
|
+
expect(results[2]!.name).toBe("feature/z");
|
|
311
338
|
});
|
|
312
339
|
|
|
313
340
|
it("should prioritize branches with worktree", () => {
|
|
@@ -346,8 +373,8 @@ describe("branchFormatter", () => {
|
|
|
346
373
|
|
|
347
374
|
const results = formatBranchItems(branches, worktreeMap);
|
|
348
375
|
|
|
349
|
-
expect(results[0]
|
|
350
|
-
expect(results[1]
|
|
376
|
+
expect(results[0]!.name).toBe("feature/with-worktree");
|
|
377
|
+
expect(results[1]!.name).toBe("feature/no-worktree");
|
|
351
378
|
});
|
|
352
379
|
|
|
353
380
|
it("should sort branches with worktree by latest commit timestamp", () => {
|
|
@@ -403,8 +430,8 @@ describe("branchFormatter", () => {
|
|
|
403
430
|
|
|
404
431
|
const results = formatBranchItems(branches, worktreeMap);
|
|
405
432
|
|
|
406
|
-
expect(results[0]
|
|
407
|
-
expect(results[1]
|
|
433
|
+
expect(results[0]!.name).toBe("feature/recent");
|
|
434
|
+
expect(results[1]!.name).toBe("feature/older");
|
|
408
435
|
});
|
|
409
436
|
|
|
410
437
|
it("should prioritize local branches over remote branches", () => {
|
|
@@ -425,10 +452,10 @@ describe("branchFormatter", () => {
|
|
|
425
452
|
|
|
426
453
|
const results = formatBranchItems(branches);
|
|
427
454
|
|
|
428
|
-
expect(results[0]
|
|
429
|
-
expect(results[0]
|
|
430
|
-
expect(results[1]
|
|
431
|
-
expect(results[1]
|
|
455
|
+
expect(results[0]!.name).toBe("feature/local");
|
|
456
|
+
expect(results[0]!.type).toBe("local");
|
|
457
|
+
expect(results[1]!.name).toBe("origin/feature/remote");
|
|
458
|
+
expect(results[1]!.type).toBe("remote");
|
|
432
459
|
});
|
|
433
460
|
|
|
434
461
|
it("should sort by latest commit timestamp when worktree status matches", () => {
|
|
@@ -451,8 +478,8 @@ describe("branchFormatter", () => {
|
|
|
451
478
|
|
|
452
479
|
const results = formatBranchItems(branches);
|
|
453
480
|
|
|
454
|
-
expect(results[0]
|
|
455
|
-
expect(results[1]
|
|
481
|
+
expect(results[0]!.name).toBe("origin/feature/newer");
|
|
482
|
+
expect(results[1]!.name).toBe("feature/local-older");
|
|
456
483
|
});
|
|
457
484
|
|
|
458
485
|
it("should apply all sorting rules in correct priority order", () => {
|
|
@@ -528,13 +555,13 @@ describe("branchFormatter", () => {
|
|
|
528
555
|
// 4. Branches with worktree
|
|
529
556
|
// 5. Local branches (alphabetically)
|
|
530
557
|
// 6. Remote branches
|
|
531
|
-
expect(results[0]
|
|
532
|
-
expect(results[1]
|
|
533
|
-
expect(results[2]
|
|
534
|
-
expect(results[3]
|
|
535
|
-
expect(results[4]
|
|
536
|
-
expect(results[5]
|
|
537
|
-
expect(results[6]
|
|
558
|
+
expect(results[0]!.name).toBe("feature/current");
|
|
559
|
+
expect(results[1]!.name).toBe("main");
|
|
560
|
+
expect(results[2]!.name).toBe("develop");
|
|
561
|
+
expect(results[3]!.name).toBe("feature/with-worktree");
|
|
562
|
+
expect(results[4]!.name).toBe("feature/a-local-no-worktree");
|
|
563
|
+
expect(results[5]!.name).toBe("feature/z-local-no-worktree");
|
|
564
|
+
expect(results[6]!.name).toBe("origin/feature/z-remote");
|
|
538
565
|
});
|
|
539
566
|
|
|
540
567
|
it("should handle release and hotfix branches without special priority", () => {
|
|
@@ -562,9 +589,9 @@ describe("branchFormatter", () => {
|
|
|
562
589
|
const results = formatBranchItems(branches);
|
|
563
590
|
|
|
564
591
|
// Should be sorted alphabetically (no special priority)
|
|
565
|
-
expect(results[0]
|
|
566
|
-
expect(results[1]
|
|
567
|
-
expect(results[2]
|
|
592
|
+
expect(results[0]!.name).toBe("feature/test");
|
|
593
|
+
expect(results[1]!.name).toBe("hotfix/urgent");
|
|
594
|
+
expect(results[2]!.name).toBe("release/v1.0");
|
|
568
595
|
});
|
|
569
596
|
|
|
570
597
|
it("should sort by latest activity time (max of git commit and tool usage)", () => {
|
|
@@ -604,8 +631,8 @@ describe("branchFormatter", () => {
|
|
|
604
631
|
// Both have same latest activity time (1_800_000_000), so alphabetical
|
|
605
632
|
// feature/git-newer: max(1_800_000_000, 1_700_000_000) = 1_800_000_000
|
|
606
633
|
// feature/tool-newer: max(1_700_000_000, 1_800_000_000) = 1_800_000_000
|
|
607
|
-
expect(results[0]
|
|
608
|
-
expect(results[1]
|
|
634
|
+
expect(results[0]!.name).toBe("feature/git-newer");
|
|
635
|
+
expect(results[1]!.name).toBe("feature/tool-newer");
|
|
609
636
|
});
|
|
610
637
|
|
|
611
638
|
it("should prioritize branch with tool usage over branch with only git commit when tool is newer", () => {
|
|
@@ -636,8 +663,8 @@ describe("branchFormatter", () => {
|
|
|
636
663
|
const results = formatBranchItems(branches);
|
|
637
664
|
|
|
638
665
|
// feature/with-tool has newer activity (tool usage at 1_800_000_000)
|
|
639
|
-
expect(results[0]
|
|
640
|
-
expect(results[1]
|
|
666
|
+
expect(results[0]!.name).toBe("feature/with-tool");
|
|
667
|
+
expect(results[1]!.name).toBe("feature/git-only");
|
|
641
668
|
});
|
|
642
669
|
|
|
643
670
|
it("should prioritize branch with newer git commit over branch with older tool usage", () => {
|
|
@@ -668,8 +695,8 @@ describe("branchFormatter", () => {
|
|
|
668
695
|
const results = formatBranchItems(branches);
|
|
669
696
|
|
|
670
697
|
// feature/new-git has newer activity (git commit at 1_800_000_000)
|
|
671
|
-
expect(results[0]
|
|
672
|
-
expect(results[1]
|
|
698
|
+
expect(results[0]!.name).toBe("feature/new-git");
|
|
699
|
+
expect(results[1]!.name).toBe("feature/old-tool");
|
|
673
700
|
});
|
|
674
701
|
});
|
|
675
702
|
});
|
|
@@ -42,40 +42,52 @@ export function QuickStartStep(props: QuickStartStepProps) {
|
|
|
42
42
|
}
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
const buildSettingsDescription = (entry: ToolSessionEntry): string => {
|
|
46
|
+
const parts: string[] = [];
|
|
47
|
+
if (entry.toolLabel) {
|
|
48
|
+
parts.push(entry.toolLabel);
|
|
49
|
+
} else if (entry.toolId) {
|
|
50
|
+
parts.push(entry.toolId);
|
|
51
|
+
}
|
|
52
|
+
if (entry.model) {
|
|
53
|
+
parts.push(entry.model);
|
|
54
|
+
}
|
|
55
|
+
if (entry.toolId === "codex-cli" && entry.reasoningLevel) {
|
|
56
|
+
parts.push(entry.reasoningLevel);
|
|
57
|
+
}
|
|
58
|
+
return parts.join(", ");
|
|
59
|
+
};
|
|
48
60
|
|
|
49
61
|
const items = createMemo<QuickStartItem[]>(() => {
|
|
50
62
|
const result: QuickStartItem[] = [];
|
|
51
|
-
const entry = latestEntry();
|
|
52
|
-
|
|
53
|
-
if (entry) {
|
|
54
|
-
const reasoningInfo = entry.reasoningLevel
|
|
55
|
-
? `, ${entry.reasoningLevel}`
|
|
56
|
-
: "";
|
|
57
|
-
const versionInfo = entry.toolVersion ? `@${entry.toolVersion}` : "";
|
|
58
|
-
const settingsDesc = `${entry.toolLabel}${versionInfo}, ${entry.model}${reasoningInfo}`;
|
|
59
|
-
const resumeDesc = entry.sessionId
|
|
60
|
-
? `${settingsDesc}, session ${entry.sessionId}`
|
|
61
|
-
: settingsDesc;
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
64
|
+
props.history.forEach((entry, index) => {
|
|
65
|
+
if (!entry) return;
|
|
66
|
+
const settingsDesc = buildSettingsDescription(entry);
|
|
67
|
+
const sessionId =
|
|
68
|
+
entry.sessionId && entry.sessionId.trim().length > 0
|
|
69
|
+
? entry.sessionId.trim()
|
|
70
|
+
: null;
|
|
71
|
+
const suffix = `${entry.toolId ?? "tool"}-${index}`;
|
|
72
|
+
|
|
73
|
+
if (sessionId) {
|
|
74
|
+
result.push({
|
|
75
|
+
label: "Resume session (previous settings)",
|
|
76
|
+
value: `resume-${suffix}`,
|
|
77
|
+
description: `${settingsDesc} | Session: ${sessionId}`,
|
|
78
|
+
action: "resume",
|
|
79
|
+
entry,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
70
82
|
|
|
71
83
|
result.push({
|
|
72
84
|
label: "Start new (previous settings)",
|
|
73
|
-
value: `start-new-${
|
|
85
|
+
value: `start-new-${suffix}`,
|
|
74
86
|
description: settingsDesc,
|
|
75
87
|
action: "start-new",
|
|
76
88
|
entry,
|
|
77
89
|
});
|
|
78
|
-
}
|
|
90
|
+
});
|
|
79
91
|
|
|
80
92
|
// Add "Choose different settings..." at the end
|
|
81
93
|
result.push({
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** @jsxImportSource @opentui/solid */
|
|
2
2
|
import type { SelectOption, SelectRenderable } from "@opentui/core";
|
|
3
3
|
import type { Ref } from "solid-js";
|
|
4
|
+
import { selectionStyle } from "../../core/theme.js";
|
|
4
5
|
|
|
5
6
|
export interface SelectInputItem {
|
|
6
7
|
label: string;
|
|
@@ -69,6 +70,9 @@ export function SelectInput(props: SelectInputProps) {
|
|
|
69
70
|
<select
|
|
70
71
|
options={options()}
|
|
71
72
|
height={computedHeight()}
|
|
73
|
+
selectedBackgroundColor={selectionStyle.bg}
|
|
74
|
+
selectedTextColor={selectionStyle.fg}
|
|
75
|
+
selectedDescriptionColor={selectionStyle.fg}
|
|
72
76
|
{...(props.selectedIndex !== undefined && {
|
|
73
77
|
selectedIndex: props.selectedIndex,
|
|
74
78
|
})}
|