@akiojin/gwt 2.1.1 → 2.3.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/README.ja.md +4 -4
- package/README.md +4 -4
- package/dist/cli/ui/components/App.d.ts +4 -4
- package/dist/cli/ui/components/App.d.ts.map +1 -1
- package/dist/cli/ui/components/App.js +144 -105
- package/dist/cli/ui/components/App.js.map +1 -1
- package/dist/cli/ui/components/common/Confirm.d.ts +1 -1
- package/dist/cli/ui/components/common/Confirm.d.ts.map +1 -1
- package/dist/cli/ui/components/common/Confirm.js +7 -7
- package/dist/cli/ui/components/common/Confirm.js.map +1 -1
- package/dist/cli/ui/components/common/ErrorBoundary.d.ts +1 -1
- package/dist/cli/ui/components/common/ErrorBoundary.d.ts.map +1 -1
- package/dist/cli/ui/components/common/ErrorBoundary.js +4 -4
- package/dist/cli/ui/components/common/ErrorBoundary.js.map +1 -1
- package/dist/cli/ui/components/common/Input.d.ts +7 -2
- package/dist/cli/ui/components/common/Input.d.ts.map +1 -1
- package/dist/cli/ui/components/common/Input.js +12 -4
- package/dist/cli/ui/components/common/Input.js.map +1 -1
- package/dist/cli/ui/components/common/LoadingIndicator.d.ts +1 -1
- package/dist/cli/ui/components/common/LoadingIndicator.d.ts.map +1 -1
- package/dist/cli/ui/components/common/LoadingIndicator.js +4 -4
- package/dist/cli/ui/components/common/LoadingIndicator.js.map +1 -1
- package/dist/cli/ui/components/common/Select.d.ts +1 -1
- package/dist/cli/ui/components/common/Select.d.ts.map +1 -1
- package/dist/cli/ui/components/common/Select.js +11 -12
- package/dist/cli/ui/components/common/Select.js.map +1 -1
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts +2 -2
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.js +11 -11
- package/dist/cli/ui/components/screens/AIToolSelectorScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts +1 -1
- package/dist/cli/ui/components/screens/BranchCreatorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/BranchCreatorScreen.js +39 -36
- package/dist/cli/ui/components/screens/BranchCreatorScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/BranchListScreen.d.ts +8 -4
- package/dist/cli/ui/components/screens/BranchListScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/BranchListScreen.js +122 -48
- package/dist/cli/ui/components/screens/BranchListScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts +2 -2
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js +25 -25
- package/dist/cli/ui/components/screens/ExecutionModeSelectorScreen.js.map +1 -1
- package/dist/cli/ui/components/screens/PRCleanupScreen.d.ts +2 -2
- package/dist/cli/ui/components/screens/PRCleanupScreen.js +21 -21
- package/dist/cli/ui/components/screens/SessionSelectorScreen.d.ts +1 -1
- package/dist/cli/ui/components/screens/SessionSelectorScreen.js +8 -8
- package/dist/cli/ui/components/screens/WorktreeManagerScreen.d.ts +1 -1
- package/dist/cli/ui/components/screens/WorktreeManagerScreen.js +8 -8
- package/dist/cli/ui/screens/BranchActionSelectorScreen.d.ts.map +1 -1
- package/dist/cli/ui/screens/BranchActionSelectorScreen.js +7 -4
- package/dist/cli/ui/screens/BranchActionSelectorScreen.js.map +1 -1
- package/dist/cli/ui/types.d.ts.map +1 -1
- package/dist/client/assets/{index-V6hDu9KS.js → index-Difv1Hwu.js} +2 -2
- package/dist/client/index.html +1 -1
- package/dist/config/builtin-tools.d.ts +10 -2
- package/dist/config/builtin-tools.d.ts.map +1 -1
- package/dist/config/builtin-tools.js +40 -4
- package/dist/config/builtin-tools.js.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/tools.d.ts.map +1 -1
- package/dist/config/tools.js +4 -3
- package/dist/config/tools.js.map +1 -1
- package/dist/gemini.d.ts +12 -0
- package/dist/gemini.d.ts.map +1 -0
- package/dist/gemini.js +154 -0
- package/dist/gemini.js.map +1 -0
- package/dist/git.d.ts.map +1 -1
- package/dist/git.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -1
- package/dist/qwen.d.ts +12 -0
- package/dist/qwen.d.ts.map +1 -0
- package/dist/qwen.js +154 -0
- package/dist/qwen.js.map +1 -0
- package/dist/services/git.service.d.ts.map +1 -1
- package/dist/services/git.service.js.map +1 -1
- package/dist/web/client/src/components/BranchGraph.d.ts.map +1 -1
- package/dist/web/client/src/components/BranchGraph.js +1 -1
- package/dist/web/client/src/components/BranchGraph.js.map +1 -1
- package/dist/web/client/src/components/EnvEditor.d.ts.map +1 -1
- package/dist/web/client/src/components/EnvEditor.js +7 -4
- package/dist/web/client/src/components/EnvEditor.js.map +1 -1
- package/dist/web/client/src/pages/BranchDetailPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/BranchDetailPage.js +55 -18
- package/dist/web/client/src/pages/BranchDetailPage.js.map +1 -1
- package/dist/web/client/src/pages/BranchListPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/BranchListPage.js +10 -4
- package/dist/web/client/src/pages/BranchListPage.js.map +1 -1
- package/dist/web/client/src/pages/ConfigManagementPage.d.ts.map +1 -1
- package/dist/web/client/src/pages/ConfigManagementPage.js +4 -2
- package/dist/web/client/src/pages/ConfigManagementPage.js.map +1 -1
- package/package.json +2 -1
- package/src/cli/ui/__tests__/acceptance/navigation.acceptance.test.tsx +69 -50
- package/src/cli/ui/__tests__/components/App.protected-branch.test.tsx +67 -45
- package/src/cli/ui/__tests__/components/App.shortcuts.test.tsx +117 -75
- package/src/cli/ui/__tests__/components/App.test.tsx +45 -37
- package/src/cli/ui/__tests__/components/common/Confirm.test.tsx +35 -22
- package/src/cli/ui/__tests__/components/common/ErrorBoundary.test.tsx +22 -22
- package/src/cli/ui/__tests__/components/common/Input.test.tsx +29 -22
- package/src/cli/ui/__tests__/components/common/LoadingIndicator.test.tsx +40 -34
- package/src/cli/ui/__tests__/components/common/Select.memo.test.tsx +57 -66
- package/src/cli/ui/__tests__/components/common/Select.test.tsx +121 -91
- package/src/cli/ui/__tests__/components/parts/Footer.test.tsx +18 -16
- package/src/cli/ui/__tests__/components/parts/Header.test.tsx +13 -13
- package/src/cli/ui/__tests__/components/parts/ScrollableList.test.tsx +20 -20
- package/src/cli/ui/__tests__/components/parts/Stats.test.tsx +38 -26
- package/src/cli/ui/__tests__/components/screens/AIToolSelectorScreen.test.tsx +31 -31
- package/src/cli/ui/__tests__/components/screens/BranchCreatorScreen.test.tsx +73 -37
- package/src/cli/ui/__tests__/components/screens/BranchListScreen.test.tsx +496 -75
- package/src/cli/ui/__tests__/components/screens/ExecutionModeSelectorScreen.test.tsx +38 -32
- package/src/cli/ui/__tests__/components/screens/PRCleanupScreen.test.tsx +39 -39
- package/src/cli/ui/__tests__/components/screens/SessionSelectorScreen.test.tsx +49 -21
- package/src/cli/ui/__tests__/components/screens/WorktreeManagerScreen.test.tsx +52 -28
- package/src/cli/ui/__tests__/integration/edgeCases.test.tsx +84 -48
- package/src/cli/ui/__tests__/integration/navigation.test.tsx +111 -83
- package/src/cli/ui/__tests__/integration/realtimeUpdate.test.tsx +111 -108
- package/src/cli/ui/__tests__/performance/branchList.performance.test.tsx +50 -37
- package/src/cli/ui/__tests__/performance/useMemoOptimization.test.tsx +75 -76
- package/src/cli/ui/components/App.tsx +247 -150
- package/src/cli/ui/components/common/Confirm.tsx +13 -9
- package/src/cli/ui/components/common/ErrorBoundary.tsx +8 -5
- package/src/cli/ui/components/common/Input.tsx +26 -4
- package/src/cli/ui/components/common/LoadingIndicator.tsx +8 -5
- package/src/cli/ui/components/common/Select.tsx +28 -17
- package/src/cli/ui/components/parts/Header.test.tsx +5 -15
- package/src/cli/ui/components/screens/AIToolSelectorScreen.tsx +19 -13
- package/src/cli/ui/components/screens/BranchCreatorScreen.tsx +74 -54
- package/src/cli/ui/components/screens/BranchListScreen.tsx +187 -62
- package/src/cli/ui/components/screens/ExecutionModeSelectorScreen.tsx +35 -28
- package/src/cli/ui/components/screens/PRCleanupScreen.tsx +22 -22
- package/src/cli/ui/components/screens/SessionSelectorScreen.tsx +8 -8
- package/src/cli/ui/components/screens/WorktreeManagerScreen.tsx +8 -8
- package/src/cli/ui/screens/BranchActionSelectorScreen.tsx +9 -4
- package/src/cli/ui/types.ts +8 -1
- package/src/config/builtin-tools.ts +42 -4
- package/src/config/index.ts +2 -12
- package/src/config/tools.ts +16 -6
- package/src/gemini.ts +202 -0
- package/src/git.ts +2 -1
- package/src/index.ts +30 -0
- package/src/qwen.ts +208 -0
- package/src/services/git.service.ts +2 -1
- package/src/web/client/src/components/BranchGraph.tsx +3 -2
- package/src/web/client/src/components/EnvEditor.tsx +44 -11
- package/src/web/client/src/pages/BranchDetailPage.tsx +165 -54
- package/src/web/client/src/pages/BranchListPage.tsx +37 -13
- package/src/web/client/src/pages/ConfigManagementPage.tsx +28 -9
package/README.ja.md
CHANGED
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md)
|
|
4
4
|
|
|
5
|
-
Claude Code / Codex CLI 対応の対話型Gitワークツリーマネージャー(グラフィカルなブランチ選択と高度なワークフロー管理機能付き)
|
|
5
|
+
Claude Code / Codex CLI / Gemini CLI 対応の対話型Gitワークツリーマネージャー(グラフィカルなブランチ選択と高度なワークフロー管理機能付き)
|
|
6
6
|
|
|
7
7
|
## 概要
|
|
8
8
|
|
|
9
|
-
`@akiojin/gwt`は、直感的なインターフェースを通じてGitワークツリー管理を革新する強力なCLIツールです。Claude Code / Codex CLI の開発ワークフローとシームレスに統合し、インテリジェントなブランチ選択、自動ワークツリー作成、包括的なプロジェクト管理機能を提供します。
|
|
9
|
+
`@akiojin/gwt`は、直感的なインターフェースを通じてGitワークツリー管理を革新する強力なCLIツールです。Claude Code / Codex CLI / Gemini CLI の開発ワークフローとシームレスに統合し、インテリジェントなブランチ選択、自動ワークツリー作成、包括的なプロジェクト管理機能を提供します。
|
|
10
10
|
|
|
11
11
|
## ✨ 主要機能
|
|
12
12
|
|
|
13
13
|
- 🎯 **対話型ブランチ選択**: ブランチ種別・ワークツリー・変更状態アイコンに加え配置インジケータ枠(左=L, 右=R, リモートのみ=☁)で所在を示し、リモート名の `origin/` を省いたシンプルなリストで判別しやすく、現在の選択は `>` プレフィックスで強調されるため誤操作を防止
|
|
14
14
|
- 🌟 **スマートブランチ作成**: ガイド付きプロンプトと自動ベースブランチ選択でfeature、bugfix、hotfix、releaseブランチを作成
|
|
15
15
|
- 🔄 **高度なワークツリー管理**: 作成、クリーンアップ、パス最適化を含む完全なライフサイクル管理
|
|
16
|
-
- 🤖 **AIツール選択**: 起動時の対話型ランチャーで Claude Code / Codex CLI を選択
|
|
16
|
+
- 🤖 **AIツール選択**: 起動時の対話型ランチャーで Claude Code / Codex CLI / Gemini CLI を選択
|
|
17
17
|
- 🚀 **AIツール統合**: 選択したツールをワークツリーで起動(Claude Codeは権限設定・変更処理の統合あり)
|
|
18
18
|
- 📊 **GitHub PR統合**: マージされたプルリクエストのブランチとワークツリーの自動クリーンアップ
|
|
19
19
|
- 🛠️ **変更管理**: 開発セッション後のコミット、stash、破棄の内蔵サポート
|
|
@@ -129,7 +129,7 @@ gwt -v
|
|
|
129
129
|
- **Node.js**(任意): Nodeベースの開発ツール利用時は >= 18.0.0 を推奨
|
|
130
130
|
- **pnpm**: >= 8.0.0(CI/CD・Docker環境用 - ハードリンクによるnode_modules効率化)
|
|
131
131
|
- **Git**: ワークツリーサポート付き最新版
|
|
132
|
-
- **AIツール**: 少なくともいずれかが必要(Claude Code
|
|
132
|
+
- **AIツール**: 少なくともいずれかが必要(Claude Code、Codex CLI、または Gemini CLI)
|
|
133
133
|
- **GitHub CLI**: PR クリーンアップ機能に必要(オプション)
|
|
134
134
|
- **Python**: >= 3.11(Spec Kit CLIに必要)
|
|
135
135
|
- **uv**: Pythonパッケージマネージャー(Spec Kit CLIに必要)
|
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[日本語](README.ja.md)
|
|
4
4
|
|
|
5
|
-
Interactive Git worktree manager with AI tool selection (Claude Code / Codex CLI), graphical branch selection, and advanced workflow management.
|
|
5
|
+
Interactive Git worktree manager with AI tool selection (Claude Code / Codex CLI / Gemini CLI), graphical branch selection, and advanced workflow management.
|
|
6
6
|
|
|
7
7
|
## Overview
|
|
8
8
|
|
|
9
|
-
`@akiojin/gwt` is a powerful CLI tool that revolutionizes Git worktree management through an intuitive interface. It seamlessly integrates with Claude Code / Codex CLI workflows, providing intelligent branch selection, automated worktree creation, and comprehensive project management capabilities.
|
|
9
|
+
`@akiojin/gwt` is a powerful CLI tool that revolutionizes Git worktree management through an intuitive interface. It seamlessly integrates with Claude Code / Codex CLI / Gemini CLI workflows, providing intelligent branch selection, automated worktree creation, and comprehensive project management capabilities.
|
|
10
10
|
|
|
11
11
|
## ✨ Key Features
|
|
12
12
|
|
|
@@ -14,7 +14,7 @@ Interactive Git worktree manager with AI tool selection (Claude Code / Codex CLI
|
|
|
14
14
|
- 🖼️ **Full-screen Layout**: Persistent header with statistics, scrollable branch list, and always-visible footer with keyboard shortcuts
|
|
15
15
|
- 🌟 **Smart Branch Creation**: Create feature, bugfix, hotfix, or release branches with guided prompts and automatic base branch selection
|
|
16
16
|
- 🔄 **Advanced Worktree Management**: Complete lifecycle management including creation, cleanup, and path optimization
|
|
17
|
-
- 🤖 **AI Tool Selection**: Choose between Claude Code / Codex CLI through the interactive launcher
|
|
17
|
+
- 🤖 **AI Tool Selection**: Choose between Claude Code / Codex CLI / Gemini CLI through the interactive launcher
|
|
18
18
|
- 🚀 **AI Tool Integration**: Launch the selected tool in the worktree (Claude Code includes permission handling and post-change flow)
|
|
19
19
|
- 🔒 **Worktree Command Restriction**: PreToolUse hooks enforce worktree boundaries, blocking directory navigation, branch switching, and file operations outside the worktree
|
|
20
20
|
- 📊 **GitHub PR Integration**: Automatic cleanup of merged pull request branches and worktrees
|
|
@@ -154,7 +154,7 @@ For technical details, see [specs/SPEC-cff08403/](specs/SPEC-cff08403/).
|
|
|
154
154
|
- **Node.js** (optional): Recommended >= 18.0.0 when working with Node-based tooling
|
|
155
155
|
- **pnpm**: >= 8.0.0 (for CI/CD and Docker environments - uses hardlinked node_modules)
|
|
156
156
|
- **Git**: Latest version with worktree support
|
|
157
|
-
- **AI Tool**: At least one of Claude Code or
|
|
157
|
+
- **AI Tool**: At least one of Claude Code, Codex CLI, or Gemini CLI should be available
|
|
158
158
|
- **GitHub CLI**: Required for PR cleanup features (optional)
|
|
159
159
|
- **Python**: >= 3.11 (for Spec Kit CLI)
|
|
160
160
|
- **uv**: Python package manager (for Spec Kit CLI)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import type { AITool } from
|
|
3
|
-
import type { ExecutionMode } from
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { AITool } from "./screens/AIToolSelectorScreen.js";
|
|
3
|
+
import type { ExecutionMode } from "./screens/ExecutionModeSelectorScreen.js";
|
|
4
4
|
export interface SelectionResult {
|
|
5
5
|
branch: string;
|
|
6
6
|
displayName: string;
|
|
7
|
-
branchType:
|
|
7
|
+
branchType: "local" | "remote";
|
|
8
8
|
remoteBranch?: string;
|
|
9
9
|
tool: AITool;
|
|
10
10
|
mode: ExecutionMode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../src/cli/ui/components/App.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../src/cli/ui/components/App.tsx"],"names":[],"mappings":"AAAA,OAAO,KAMN,MAAM,OAAO,CAAC;AAUf,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0CAA0C,CAAC;AAmC9E,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,aAAa,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,eAAe,KAAK,IAAI,CAAC;IAC3C,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAgB,GAAG,CAAC,EAAE,MAAM,EAAE,qBAA2B,EAAE,EAAE,QAAQ,qBAkzBpE"}
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useMemo, useRef, useState } from
|
|
2
|
-
import { useApp } from
|
|
3
|
-
import { ErrorBoundary } from
|
|
4
|
-
import { BranchListScreen } from
|
|
5
|
-
import { WorktreeManagerScreen } from
|
|
6
|
-
import { BranchCreatorScreen } from
|
|
7
|
-
import { BranchActionSelectorScreen } from
|
|
8
|
-
import { AIToolSelectorScreen } from
|
|
9
|
-
import { SessionSelectorScreen } from
|
|
10
|
-
import { ExecutionModeSelectorScreen } from
|
|
11
|
-
import { useGitData } from
|
|
12
|
-
import { useScreenState } from
|
|
13
|
-
import { formatBranchItems } from
|
|
14
|
-
import { calculateStatistics } from
|
|
15
|
-
import { getRepositoryRoot, deleteBranch } from
|
|
16
|
-
import { createWorktree, generateWorktreePath, getMergedPRWorktrees, isProtectedBranchName, removeWorktree, switchToProtectedBranch, } from
|
|
17
|
-
import { getPackageVersion } from
|
|
18
|
-
import { resolveBaseBranchLabel, resolveBaseBranchRef, } from
|
|
19
|
-
const SPINNER_FRAMES = [
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState, } from "react";
|
|
2
|
+
import { useApp } from "ink";
|
|
3
|
+
import { ErrorBoundary } from "./common/ErrorBoundary.js";
|
|
4
|
+
import { BranchListScreen } from "./screens/BranchListScreen.js";
|
|
5
|
+
import { WorktreeManagerScreen } from "./screens/WorktreeManagerScreen.js";
|
|
6
|
+
import { BranchCreatorScreen } from "./screens/BranchCreatorScreen.js";
|
|
7
|
+
import { BranchActionSelectorScreen } from "../screens/BranchActionSelectorScreen.js";
|
|
8
|
+
import { AIToolSelectorScreen } from "./screens/AIToolSelectorScreen.js";
|
|
9
|
+
import { SessionSelectorScreen } from "./screens/SessionSelectorScreen.js";
|
|
10
|
+
import { ExecutionModeSelectorScreen } from "./screens/ExecutionModeSelectorScreen.js";
|
|
11
|
+
import { useGitData } from "../hooks/useGitData.js";
|
|
12
|
+
import { useScreenState } from "../hooks/useScreenState.js";
|
|
13
|
+
import { formatBranchItems } from "../utils/branchFormatter.js";
|
|
14
|
+
import { calculateStatistics } from "../utils/statisticsCalculator.js";
|
|
15
|
+
import { getRepositoryRoot, deleteBranch } from "../../../git.js";
|
|
16
|
+
import { createWorktree, generateWorktreePath, getMergedPRWorktrees, isProtectedBranchName, removeWorktree, switchToProtectedBranch, } from "../../../worktree.js";
|
|
17
|
+
import { getPackageVersion } from "../../../utils.js";
|
|
18
|
+
import { resolveBaseBranchLabel, resolveBaseBranchRef, } from "../utils/baseBranch.js";
|
|
19
|
+
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧"];
|
|
20
20
|
const COMPLETION_HOLD_DURATION_MS = 3000;
|
|
21
|
-
const PROTECTED_BRANCH_WARNING =
|
|
21
|
+
const PROTECTED_BRANCH_WARNING = "Root branches operate directly in the repository root. Create a new branch if you need a dedicated worktree.";
|
|
22
22
|
const getSpinnerFrame = (index) => {
|
|
23
23
|
const frame = SPINNER_FRAMES[index];
|
|
24
|
-
if (typeof frame ===
|
|
24
|
+
if (typeof frame === "string") {
|
|
25
25
|
return frame;
|
|
26
26
|
}
|
|
27
|
-
return SPINNER_FRAMES[0] ??
|
|
27
|
+
return SPINNER_FRAMES[0] ?? "⠋";
|
|
28
28
|
};
|
|
29
29
|
/**
|
|
30
30
|
* App - Top-level component for Ink.js UI
|
|
@@ -66,7 +66,8 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
66
66
|
return undefined;
|
|
67
67
|
}
|
|
68
68
|
const interval = setInterval(() => {
|
|
69
|
-
spinnerFrameIndexRef.current =
|
|
69
|
+
spinnerFrameIndexRef.current =
|
|
70
|
+
(spinnerFrameIndexRef.current + 1) % SPINNER_FRAMES.length;
|
|
70
71
|
setSpinnerFrameIndex(spinnerFrameIndexRef.current);
|
|
71
72
|
}, 120);
|
|
72
73
|
return () => {
|
|
@@ -83,17 +84,17 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
83
84
|
if (cleanupProcessingBranch) {
|
|
84
85
|
setCleanupIndicators((prev) => {
|
|
85
86
|
const current = prev[cleanupProcessingBranch];
|
|
86
|
-
if (current && current.icon === frame && current.color ===
|
|
87
|
+
if (current && current.icon === frame && current.color === "cyan") {
|
|
87
88
|
return prev;
|
|
88
89
|
}
|
|
89
90
|
const next = {
|
|
90
91
|
...prev,
|
|
91
|
-
[cleanupProcessingBranch]: { icon: frame, color:
|
|
92
|
+
[cleanupProcessingBranch]: { icon: frame, color: "cyan" },
|
|
92
93
|
};
|
|
93
94
|
return next;
|
|
94
95
|
});
|
|
95
96
|
}
|
|
96
|
-
setCleanupFooterMessage({ text: `Processing... ${frame}`, color:
|
|
97
|
+
setCleanupFooterMessage({ text: `Processing... ${frame}`, color: "cyan" });
|
|
97
98
|
}, [cleanupInputLocked, cleanupProcessingBranch, spinnerFrameIndex]);
|
|
98
99
|
useEffect(() => {
|
|
99
100
|
if (!hiddenBranches.length) {
|
|
@@ -113,9 +114,11 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
113
114
|
}, []);
|
|
114
115
|
const visibleBranches = useMemo(() => branches.filter((branch) => !hiddenBranches.includes(branch.name)), [branches, hiddenBranches]);
|
|
115
116
|
// Helper function to create content-based hash for branches
|
|
116
|
-
const branchHash = useMemo(() => visibleBranches
|
|
117
|
+
const branchHash = useMemo(() => visibleBranches
|
|
118
|
+
.map((b) => `${b.name}-${b.type}-${b.isCurrent}`)
|
|
119
|
+
.join(","), [visibleBranches]);
|
|
117
120
|
// Helper function to create content-based hash for worktrees
|
|
118
|
-
const worktreeHash = useMemo(() => worktrees.map((w) => `${w.branch}-${w.path}`).join(
|
|
121
|
+
const worktreeHash = useMemo(() => worktrees.map((w) => `${w.branch}-${w.path}`).join(","), [worktrees]);
|
|
119
122
|
// Format branches to BranchItems (memoized for performance with content-based dependencies)
|
|
120
123
|
const branchItems = useMemo(() => {
|
|
121
124
|
// Build worktreeMap for sorting
|
|
@@ -139,46 +142,48 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
139
142
|
isAccessible: wt.isAccessible ?? true,
|
|
140
143
|
})), [worktrees]);
|
|
141
144
|
const resolveBaseBranch = useCallback(() => {
|
|
142
|
-
const localMain = branches.find((branch) => branch.type ===
|
|
145
|
+
const localMain = branches.find((branch) => branch.type === "local" &&
|
|
146
|
+
(branch.name === "main" || branch.name === "master"));
|
|
143
147
|
if (localMain) {
|
|
144
148
|
return localMain.name;
|
|
145
149
|
}
|
|
146
|
-
const develop = branches.find((branch) => branch.type ===
|
|
150
|
+
const develop = branches.find((branch) => branch.type === "local" &&
|
|
151
|
+
(branch.name === "develop" || branch.name === "dev"));
|
|
147
152
|
if (develop) {
|
|
148
153
|
return develop.name;
|
|
149
154
|
}
|
|
150
|
-
return
|
|
155
|
+
return "main";
|
|
151
156
|
}, [branches]);
|
|
152
157
|
const baseBranchLabel = useMemo(() => resolveBaseBranchLabel(creationSourceBranch, selectedBranch, resolveBaseBranch), [creationSourceBranch, resolveBaseBranch, selectedBranch]);
|
|
153
158
|
// Handle branch selection
|
|
154
159
|
const toLocalBranchName = useCallback((remoteName) => {
|
|
155
|
-
const segments = remoteName.split(
|
|
160
|
+
const segments = remoteName.split("/");
|
|
156
161
|
if (segments.length <= 1) {
|
|
157
162
|
return remoteName;
|
|
158
163
|
}
|
|
159
|
-
return segments.slice(1).join(
|
|
164
|
+
return segments.slice(1).join("/");
|
|
160
165
|
}, []);
|
|
161
166
|
const inferBranchCategory = useCallback((branchName) => {
|
|
162
167
|
const matched = branches.find((branch) => branch.name === branchName);
|
|
163
168
|
if (matched) {
|
|
164
169
|
return matched.branchType;
|
|
165
170
|
}
|
|
166
|
-
if (branchName ===
|
|
167
|
-
return
|
|
171
|
+
if (branchName === "main" || branchName === "master") {
|
|
172
|
+
return "main";
|
|
168
173
|
}
|
|
169
|
-
if (branchName ===
|
|
170
|
-
return
|
|
174
|
+
if (branchName === "develop" || branchName === "dev") {
|
|
175
|
+
return "develop";
|
|
171
176
|
}
|
|
172
|
-
if (branchName.startsWith(
|
|
173
|
-
return
|
|
177
|
+
if (branchName.startsWith("feature/")) {
|
|
178
|
+
return "feature";
|
|
174
179
|
}
|
|
175
|
-
if (branchName.startsWith(
|
|
176
|
-
return
|
|
180
|
+
if (branchName.startsWith("hotfix/")) {
|
|
181
|
+
return "hotfix";
|
|
177
182
|
}
|
|
178
|
-
if (branchName.startsWith(
|
|
179
|
-
return
|
|
183
|
+
if (branchName.startsWith("release/")) {
|
|
184
|
+
return "release";
|
|
180
185
|
}
|
|
181
|
-
return
|
|
186
|
+
return "other";
|
|
182
187
|
}, [branches]);
|
|
183
188
|
const isProtectedSelection = useCallback((branch) => {
|
|
184
189
|
if (!branch) {
|
|
@@ -186,9 +191,11 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
186
191
|
}
|
|
187
192
|
return (isProtectedBranchName(branch.name) ||
|
|
188
193
|
isProtectedBranchName(branch.displayName) ||
|
|
189
|
-
(branch.remoteBranch
|
|
190
|
-
|
|
191
|
-
|
|
194
|
+
(branch.remoteBranch
|
|
195
|
+
? isProtectedBranchName(branch.remoteBranch)
|
|
196
|
+
: false) ||
|
|
197
|
+
branch.branchCategory === "main" ||
|
|
198
|
+
branch.branchCategory === "develop");
|
|
192
199
|
}, [isProtectedBranchName]);
|
|
193
200
|
const protectedBranchInfo = useMemo(() => {
|
|
194
201
|
if (!selectedBranch) {
|
|
@@ -204,18 +211,18 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
204
211
|
};
|
|
205
212
|
}, [selectedBranch, isProtectedSelection]);
|
|
206
213
|
const handleSelect = useCallback((item) => {
|
|
207
|
-
const selection = item.type ===
|
|
214
|
+
const selection = item.type === "remote"
|
|
208
215
|
? {
|
|
209
216
|
name: toLocalBranchName(item.name),
|
|
210
217
|
displayName: item.name,
|
|
211
|
-
branchType:
|
|
218
|
+
branchType: "remote",
|
|
212
219
|
branchCategory: item.branchType,
|
|
213
220
|
remoteBranch: item.name,
|
|
214
221
|
}
|
|
215
222
|
: {
|
|
216
223
|
name: item.name,
|
|
217
224
|
displayName: item.name,
|
|
218
|
-
branchType:
|
|
225
|
+
branchType: "local",
|
|
219
226
|
branchCategory: item.branchType,
|
|
220
227
|
};
|
|
221
228
|
const protectedSelected = isProtectedSelection(selection);
|
|
@@ -225,14 +232,21 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
225
232
|
if (protectedSelected) {
|
|
226
233
|
setCleanupFooterMessage({
|
|
227
234
|
text: PROTECTED_BRANCH_WARNING,
|
|
228
|
-
color:
|
|
235
|
+
color: "yellow",
|
|
229
236
|
});
|
|
230
237
|
}
|
|
231
238
|
else {
|
|
232
239
|
setCleanupFooterMessage(null);
|
|
233
240
|
}
|
|
234
|
-
navigateTo(
|
|
235
|
-
}, [
|
|
241
|
+
navigateTo("branch-action-selector");
|
|
242
|
+
}, [
|
|
243
|
+
isProtectedSelection,
|
|
244
|
+
navigateTo,
|
|
245
|
+
setCleanupFooterMessage,
|
|
246
|
+
setCreationSourceBranch,
|
|
247
|
+
setSelectedTool,
|
|
248
|
+
toLocalBranchName,
|
|
249
|
+
]);
|
|
236
250
|
// Handle navigation
|
|
237
251
|
const handleNavigate = useCallback((screen) => {
|
|
238
252
|
navigateTo(screen);
|
|
@@ -241,14 +255,19 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
241
255
|
setSelectedBranch({
|
|
242
256
|
name: worktree.branch,
|
|
243
257
|
displayName: worktree.branch,
|
|
244
|
-
branchType:
|
|
258
|
+
branchType: "local",
|
|
245
259
|
branchCategory: inferBranchCategory(worktree.branch),
|
|
246
260
|
});
|
|
247
261
|
setSelectedTool(null);
|
|
248
262
|
setCreationSourceBranch(null);
|
|
249
263
|
setCleanupFooterMessage(null);
|
|
250
|
-
navigateTo(
|
|
251
|
-
}, [
|
|
264
|
+
navigateTo("ai-tool-selector");
|
|
265
|
+
}, [
|
|
266
|
+
inferBranchCategory,
|
|
267
|
+
navigateTo,
|
|
268
|
+
setCleanupFooterMessage,
|
|
269
|
+
setCreationSourceBranch,
|
|
270
|
+
]);
|
|
252
271
|
// Handle branch action selection
|
|
253
272
|
const handleProtectedBranchSwitch = useCallback(async () => {
|
|
254
273
|
if (!selectedBranch) {
|
|
@@ -257,12 +276,12 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
257
276
|
try {
|
|
258
277
|
setCleanupFooterMessage({
|
|
259
278
|
text: `Preparing root branch '${selectedBranch.displayName ?? selectedBranch.name}'...`,
|
|
260
|
-
color:
|
|
279
|
+
color: "cyan",
|
|
261
280
|
});
|
|
262
281
|
const repoRoot = await getRepositoryRoot();
|
|
263
282
|
const remoteRef = selectedBranch.remoteBranch ??
|
|
264
|
-
(selectedBranch.branchType ===
|
|
265
|
-
? selectedBranch.displayName ?? selectedBranch.name
|
|
283
|
+
(selectedBranch.branchType === "remote"
|
|
284
|
+
? (selectedBranch.displayName ?? selectedBranch.name)
|
|
266
285
|
: null);
|
|
267
286
|
const result = await switchToProtectedBranch({
|
|
268
287
|
branchName: selectedBranch.name,
|
|
@@ -270,43 +289,43 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
270
289
|
remoteRef: remoteRef ?? null,
|
|
271
290
|
});
|
|
272
291
|
let successMessage = `'${selectedBranch.displayName ?? selectedBranch.name}' will use the repository root.`;
|
|
273
|
-
if (result ===
|
|
292
|
+
if (result === "remote") {
|
|
274
293
|
successMessage = `Created a local tracking branch for '${selectedBranch.displayName ?? selectedBranch.name}' and switched to the protected branch.`;
|
|
275
294
|
}
|
|
276
|
-
else if (result ===
|
|
295
|
+
else if (result === "local") {
|
|
277
296
|
successMessage = `Checked out '${selectedBranch.displayName ?? selectedBranch.name}' in the repository root.`;
|
|
278
297
|
}
|
|
279
298
|
setCleanupFooterMessage({
|
|
280
299
|
text: successMessage,
|
|
281
|
-
color:
|
|
300
|
+
color: "green",
|
|
282
301
|
});
|
|
283
302
|
refresh();
|
|
284
|
-
navigateTo(
|
|
303
|
+
navigateTo("ai-tool-selector");
|
|
285
304
|
}
|
|
286
305
|
catch (error) {
|
|
287
306
|
const message = error instanceof Error ? error.message : String(error);
|
|
288
307
|
setCleanupFooterMessage({
|
|
289
308
|
text: `Failed to switch root branch: ${message}`,
|
|
290
|
-
color:
|
|
309
|
+
color: "red",
|
|
291
310
|
});
|
|
292
|
-
console.error(
|
|
311
|
+
console.error("Failed to switch protected branch:", error);
|
|
293
312
|
}
|
|
294
|
-
}, [
|
|
295
|
-
navigateTo,
|
|
296
|
-
refresh,
|
|
297
|
-
selectedBranch,
|
|
298
|
-
setCleanupFooterMessage,
|
|
299
|
-
]);
|
|
313
|
+
}, [navigateTo, refresh, selectedBranch, setCleanupFooterMessage]);
|
|
300
314
|
const handleUseExistingBranch = useCallback(() => {
|
|
301
315
|
if (selectedBranch && isProtectedSelection(selectedBranch)) {
|
|
302
316
|
void handleProtectedBranchSwitch();
|
|
303
317
|
return;
|
|
304
318
|
}
|
|
305
|
-
navigateTo(
|
|
306
|
-
}, [
|
|
319
|
+
navigateTo("ai-tool-selector");
|
|
320
|
+
}, [
|
|
321
|
+
handleProtectedBranchSwitch,
|
|
322
|
+
isProtectedSelection,
|
|
323
|
+
navigateTo,
|
|
324
|
+
selectedBranch,
|
|
325
|
+
]);
|
|
307
326
|
const handleCreateNewBranch = useCallback(() => {
|
|
308
327
|
setCreationSourceBranch(selectedBranch);
|
|
309
|
-
navigateTo(
|
|
328
|
+
navigateTo("branch-creator");
|
|
310
329
|
}, [navigateTo, selectedBranch]);
|
|
311
330
|
// Handle quit
|
|
312
331
|
const handleQuit = useCallback(() => {
|
|
@@ -332,16 +351,16 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
332
351
|
setSelectedBranch({
|
|
333
352
|
name: branchName,
|
|
334
353
|
displayName: branchName,
|
|
335
|
-
branchType:
|
|
354
|
+
branchType: "local",
|
|
336
355
|
branchCategory: inferBranchCategory(branchName),
|
|
337
356
|
});
|
|
338
357
|
setSelectedTool(null);
|
|
339
358
|
setCleanupFooterMessage(null);
|
|
340
|
-
navigateTo(
|
|
359
|
+
navigateTo("ai-tool-selector");
|
|
341
360
|
}
|
|
342
361
|
catch (error) {
|
|
343
362
|
// On error, go back to branch list
|
|
344
|
-
console.error(
|
|
363
|
+
console.error("Failed to create branch:", error);
|
|
345
364
|
goBack();
|
|
346
365
|
refresh();
|
|
347
366
|
}
|
|
@@ -382,7 +401,10 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
382
401
|
setCleanupInputLocked(true);
|
|
383
402
|
setCleanupIndicators({});
|
|
384
403
|
const initialFrame = getSpinnerFrame(0);
|
|
385
|
-
setCleanupFooterMessage({
|
|
404
|
+
setCleanupFooterMessage({
|
|
405
|
+
text: `Processing... ${initialFrame}`,
|
|
406
|
+
color: "cyan",
|
|
407
|
+
});
|
|
386
408
|
setCleanupProcessingBranch(null);
|
|
387
409
|
spinnerFrameIndexRef.current = 0;
|
|
388
410
|
setSpinnerFrameIndex(0);
|
|
@@ -393,7 +415,7 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
393
415
|
catch (error) {
|
|
394
416
|
const message = error instanceof Error ? error.message : String(error);
|
|
395
417
|
setCleanupIndicators({});
|
|
396
|
-
setCleanupFooterMessage({ text: `❌ ${message}`, color:
|
|
418
|
+
setCleanupFooterMessage({ text: `❌ ${message}`, color: "red" });
|
|
397
419
|
setCleanupInputLocked(false);
|
|
398
420
|
completionTimerRef.current = setTimeout(() => {
|
|
399
421
|
setCleanupFooterMessage(null);
|
|
@@ -403,7 +425,10 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
403
425
|
}
|
|
404
426
|
if (targets.length === 0) {
|
|
405
427
|
setCleanupIndicators({});
|
|
406
|
-
setCleanupFooterMessage({
|
|
428
|
+
setCleanupFooterMessage({
|
|
429
|
+
text: "✅ Nothing to clean up.",
|
|
430
|
+
color: "green",
|
|
431
|
+
});
|
|
407
432
|
setCleanupInputLocked(false);
|
|
408
433
|
completionTimerRef.current = setTimeout(() => {
|
|
409
434
|
setCleanupFooterMessage(null);
|
|
@@ -414,8 +439,8 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
414
439
|
// Reset hidden branches that may already be gone
|
|
415
440
|
setHiddenBranches((prev) => prev.filter((name) => targets.find((t) => t.branch === name) === undefined));
|
|
416
441
|
const initialIndicators = targets.reduce((acc, target, index) => {
|
|
417
|
-
const icon = index === 0 ? getSpinnerFrame(0) :
|
|
418
|
-
const color = index === 0 ?
|
|
442
|
+
const icon = index === 0 ? getSpinnerFrame(0) : "⏳";
|
|
443
|
+
const color = index === 0 ? "cyan" : "yellow";
|
|
419
444
|
acc[target.branch] = { icon, color };
|
|
420
445
|
return acc;
|
|
421
446
|
}, {});
|
|
@@ -424,7 +449,10 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
424
449
|
setCleanupProcessingBranch(firstTarget ? firstTarget.branch : null);
|
|
425
450
|
spinnerFrameIndexRef.current = 0;
|
|
426
451
|
setSpinnerFrameIndex(0);
|
|
427
|
-
setCleanupFooterMessage({
|
|
452
|
+
setCleanupFooterMessage({
|
|
453
|
+
text: `Processing... ${getSpinnerFrame(0)}`,
|
|
454
|
+
color: "cyan",
|
|
455
|
+
});
|
|
428
456
|
for (let index = 0; index < targets.length; index += 1) {
|
|
429
457
|
const currentTarget = targets[index];
|
|
430
458
|
if (!currentTarget) {
|
|
@@ -436,58 +464,69 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
436
464
|
setSpinnerFrameIndex(0);
|
|
437
465
|
setCleanupIndicators((prev) => {
|
|
438
466
|
const updated = { ...prev };
|
|
439
|
-
updated[target.branch] = { icon: getSpinnerFrame(0), color:
|
|
467
|
+
updated[target.branch] = { icon: getSpinnerFrame(0), color: "cyan" };
|
|
440
468
|
for (const pending of targets.slice(index + 1)) {
|
|
441
469
|
const current = updated[pending.branch];
|
|
442
|
-
if (!current || current.icon !==
|
|
443
|
-
updated[pending.branch] = { icon:
|
|
470
|
+
if (!current || current.icon !== "⏳") {
|
|
471
|
+
updated[pending.branch] = { icon: "⏳", color: "yellow" };
|
|
444
472
|
}
|
|
445
473
|
}
|
|
446
474
|
return updated;
|
|
447
475
|
});
|
|
448
476
|
const shouldSkip = target.hasUncommittedChanges ||
|
|
449
477
|
target.hasUnpushedCommits ||
|
|
450
|
-
(target.cleanupType ===
|
|
478
|
+
(target.cleanupType === "worktree-and-branch" &&
|
|
479
|
+
(!target.worktreePath || target.isAccessible === false));
|
|
451
480
|
if (shouldSkip) {
|
|
452
481
|
setCleanupIndicators((prev) => ({
|
|
453
482
|
...prev,
|
|
454
|
-
[target.branch]: { icon:
|
|
483
|
+
[target.branch]: { icon: "⏭️", color: "yellow" },
|
|
455
484
|
}));
|
|
456
485
|
setCleanupProcessingBranch(null);
|
|
457
486
|
continue;
|
|
458
487
|
}
|
|
459
488
|
try {
|
|
460
|
-
if (target.cleanupType ===
|
|
489
|
+
if (target.cleanupType === "worktree-and-branch" &&
|
|
490
|
+
target.worktreePath) {
|
|
461
491
|
await removeWorktree(target.worktreePath, true);
|
|
462
492
|
}
|
|
463
493
|
await deleteBranch(target.branch, true);
|
|
464
494
|
succeededBranches.push(target.branch);
|
|
465
495
|
setCleanupIndicators((prev) => ({
|
|
466
496
|
...prev,
|
|
467
|
-
[target.branch]: { icon:
|
|
497
|
+
[target.branch]: { icon: "✅", color: "green" },
|
|
468
498
|
}));
|
|
469
499
|
}
|
|
470
500
|
catch {
|
|
471
|
-
const icon =
|
|
501
|
+
const icon = "❌";
|
|
472
502
|
setCleanupIndicators((prev) => ({
|
|
473
503
|
...prev,
|
|
474
|
-
[target.branch]: { icon, color:
|
|
504
|
+
[target.branch]: { icon, color: "red" },
|
|
475
505
|
}));
|
|
476
506
|
}
|
|
477
507
|
setCleanupProcessingBranch(null);
|
|
478
508
|
}
|
|
479
509
|
setCleanupProcessingBranch(null);
|
|
480
510
|
setCleanupInputLocked(false);
|
|
481
|
-
setCleanupFooterMessage({
|
|
482
|
-
|
|
511
|
+
setCleanupFooterMessage({
|
|
512
|
+
text: "Cleanup completed. Finalizing...",
|
|
513
|
+
color: "green",
|
|
514
|
+
});
|
|
515
|
+
const holdDuration = typeof process !== "undefined" && process.env?.NODE_ENV === "test"
|
|
483
516
|
? 0
|
|
484
517
|
: COMPLETION_HOLD_DURATION_MS;
|
|
485
518
|
completionTimerRef.current = setTimeout(resetAfterWait, holdDuration);
|
|
486
|
-
}, [
|
|
519
|
+
}, [
|
|
520
|
+
cleanupInputLocked,
|
|
521
|
+
deleteBranch,
|
|
522
|
+
getMergedPRWorktrees,
|
|
523
|
+
refresh,
|
|
524
|
+
removeWorktree,
|
|
525
|
+
]);
|
|
487
526
|
// Handle AI tool selection
|
|
488
527
|
const handleToolSelect = useCallback((tool) => {
|
|
489
528
|
setSelectedTool(tool);
|
|
490
|
-
navigateTo(
|
|
529
|
+
navigateTo("execution-mode-selector");
|
|
491
530
|
}, [navigateTo]);
|
|
492
531
|
// Handle session selection
|
|
493
532
|
const handleSessionSelect = useCallback((_session) => {
|
|
@@ -517,20 +556,20 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
517
556
|
// Render screen based on currentScreen
|
|
518
557
|
const renderScreen = () => {
|
|
519
558
|
switch (currentScreen) {
|
|
520
|
-
case
|
|
559
|
+
case "branch-list":
|
|
521
560
|
return (React.createElement(BranchListScreen, { branches: branchItems, stats: stats, onSelect: handleSelect, onNavigate: handleNavigate, onQuit: handleQuit, onCleanupCommand: handleCleanupCommand, onRefresh: refresh, loading: loading, error: error, lastUpdated: lastUpdated, loadingIndicatorDelay: loadingIndicatorDelay, cleanupUI: {
|
|
522
561
|
indicators: cleanupIndicators,
|
|
523
562
|
footerMessage: cleanupFooterMessage,
|
|
524
563
|
inputLocked: cleanupInputLocked,
|
|
525
564
|
}, version: version, workingDirectory: workingDirectory }));
|
|
526
|
-
case
|
|
565
|
+
case "worktree-manager":
|
|
527
566
|
return (React.createElement(WorktreeManagerScreen, { worktrees: worktreeItems, onBack: goBack, onSelect: handleWorktreeSelect, version: version }));
|
|
528
|
-
case
|
|
567
|
+
case "branch-creator":
|
|
529
568
|
return (React.createElement(BranchCreatorScreen, { onBack: goBack, onCreate: handleCreate, baseBranch: baseBranchLabel, version: version }));
|
|
530
|
-
case
|
|
569
|
+
case "branch-action-selector": {
|
|
531
570
|
const isProtected = Boolean(protectedBranchInfo);
|
|
532
571
|
const baseProps = {
|
|
533
|
-
selectedBranch: selectedBranch?.displayName ??
|
|
572
|
+
selectedBranch: selectedBranch?.displayName ?? "",
|
|
534
573
|
onUseExisting: handleUseExistingBranch,
|
|
535
574
|
onCreateNew: handleCreateNewBranch,
|
|
536
575
|
onBack: goBack,
|
|
@@ -541,12 +580,12 @@ export function App({ onExit, loadingIndicatorDelay = 300 }) {
|
|
|
541
580
|
}
|
|
542
581
|
return React.createElement(BranchActionSelectorScreen, { ...baseProps });
|
|
543
582
|
}
|
|
544
|
-
case
|
|
545
|
-
return React.createElement(AIToolSelectorScreen, { onBack: goBack, onSelect: handleToolSelect, version: version });
|
|
546
|
-
case
|
|
583
|
+
case "ai-tool-selector":
|
|
584
|
+
return (React.createElement(AIToolSelectorScreen, { onBack: goBack, onSelect: handleToolSelect, version: version }));
|
|
585
|
+
case "session-selector":
|
|
547
586
|
// TODO: Implement session data fetching
|
|
548
587
|
return (React.createElement(SessionSelectorScreen, { sessions: [], onBack: goBack, onSelect: handleSessionSelect, version: version }));
|
|
549
|
-
case
|
|
588
|
+
case "execution-mode-selector":
|
|
550
589
|
return (React.createElement(ExecutionModeSelectorScreen, { onBack: goBack, onSelect: handleModeSelect, version: version }));
|
|
551
590
|
default:
|
|
552
591
|
return (React.createElement(BranchListScreen, { branches: branchItems, stats: stats, onSelect: handleSelect, onNavigate: handleNavigate, onQuit: handleQuit, onRefresh: refresh, loading: loading, error: error, lastUpdated: lastUpdated, loadingIndicatorDelay: loadingIndicatorDelay, version: version, workingDirectory: workingDirectory }));
|