feat: add git worktree session support with improved UI

Implement comprehensive worktree session support allowing users to spawn sessions in temporary git worktrees. Includes backend worktree management, full-stack integration, and refined UI for session type selection.

Backend:
- Add worktree creation/removal utilities with branch management
- Track worktree metadata (basePath, branch, name, path) in session metadata
- Automatic cleanup of worktrees when sessions fail or exit
- Enhanced error handling with stderr tail logging

UI improvements:
- Redesign session type toggle with improved alignment and spacing
- Move worktree description inline with label for cleaner layout
- Add branch name input field that appears when worktree mode selected
- Auto-focus on worktree input when switching modes
- Reduce gap between radio options from gap-3 to gap-1.5
- Update descriptive text and placeholders for clarity

Integration:
- Thread worktree parameters through API client, RPC handlers, and daemon
- Add worktreeEnv utility to read worktree info from environment
- Update session spawning to support both simple and worktree modes
This commit is contained in:
weishu
2025-12-28 13:17:58 +08:00
parent 0eab45c49c
commit c35a5ce827
21 changed files with 605 additions and 69 deletions
+4 -1
View File
@@ -20,6 +20,7 @@ import { initialMachineMetadata } from '@/daemon/run';
import { startHappyServer } from '@/claude/utils/startHappyServer';
import { getHappyCliCommand } from '@/utils/spawnHappyCLI';
import { registerKillSessionHandler } from '@/claude/registerKillSessionHandler';
import { readWorktreeEnv } from '@/utils/worktreeEnv';
function emitReadyIfIdle(props: {
queueSize: () => number;
@@ -56,6 +57,7 @@ export async function runAgentSession(opts: {
controlledByUser: false
};
const worktreeInfo = readWorktreeEnv();
const metadata: Metadata = {
path: process.cwd(),
host: os.hostname(),
@@ -71,7 +73,8 @@ export async function runAgentSession(opts: {
startedBy: opts.startedBy || 'terminal',
lifecycleState: 'running',
lifecycleStateSince: Date.now(),
flavor: opts.agentType
flavor: opts.agentType,
worktree: worktreeInfo ?? undefined
};
const response = await api.getOrCreateSession({ tag: sessionTag, metadata, state });