feat: Enhance team skill router with command architecture and role isolation rules

- Added command architecture section to skill router template, detailing role organization and command delegation.
- Updated role router input parsing to reflect new file structure for roles.
- Introduced role isolation rules to enforce strict boundaries on role responsibilities and output tagging.
- Enhanced team configuration section to include role-specific guidelines and message bus requirements.

feat: Improve terminal dashboard with session status indicators

- Integrated terminal status indicators in the session group tree, displaying active, idle, error, paused, and resuming states.
- Updated session click handling to focus on existing panes or assign sessions to available panes.

feat: Add session lifecycle controls in terminal pane

- Implemented restart, pause, and resume functionalities for terminal sessions with loading states.
- Enhanced UI buttons for session control with appropriate loading indicators and tooltips.

i18n: Update terminal dashboard localization for session controls

- Added translations for restart, pause, and resume session actions in English and Chinese.

chore: Create role command template for command file generation

- Established a comprehensive template for generating command files in roles, including sections for strategy, execution steps, and error handling.
- Included pre-built command patterns for common tasks like exploration, analysis, implementation, validation, review, dispatch, and monitoring.
This commit is contained in:
catlog22
2026-02-15 12:38:32 +08:00
parent 731f1ea775
commit a897858c6a
15 changed files with 1818 additions and 182 deletions

View File

@@ -4,7 +4,7 @@
// Single terminal pane = PaneToolbar + TerminalInstance.
// Renders within the TerminalGrid recursive layout.
import { useCallback, useMemo } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { useIntl } from 'react-intl';
import {
SplitSquareHorizontal,
@@ -14,6 +14,10 @@ import {
X,
Terminal,
ChevronDown,
RotateCcw,
Pause,
Play,
Loader2,
} from 'lucide-react';
import { cn } from '@/lib/utils';
import { TerminalInstance } from './TerminalInstance';
@@ -76,6 +80,15 @@ export function TerminalPane({ paneId }: TerminalPaneProps) {
const terminalMetas = useSessionManagerStore(selectTerminalMetas);
const sessions = useCliSessionStore((s) => s.sessions);
// Session lifecycle actions
const pauseSession = useSessionManagerStore((s) => s.pauseSession);
const resumeSession = useSessionManagerStore((s) => s.resumeSession);
const restartSession = useSessionManagerStore((s) => s.restartSession);
// Action loading states
const [isRestarting, setIsRestarting] = useState(false);
const [isTogglingPause, setIsTogglingPause] = useState(false);
// Association chain for linked issue badge
const associationChain = useIssueQueueIntegrationStore(selectAssociationChain);
const linkedIssueId = useMemo(() => {
@@ -133,6 +146,34 @@ export function TerminalPane({ paneId }: TerminalPaneProps) {
}
}, [paneId, sessionId, assignSession]);
const handleRestart = useCallback(async () => {
if (!sessionId || isRestarting) return;
setIsRestarting(true);
try {
await restartSession(sessionId);
} catch (error) {
console.error('[TerminalPane] Restart failed:', error);
} finally {
setIsRestarting(false);
}
}, [sessionId, isRestarting, restartSession]);
const handleTogglePause = useCallback(async () => {
if (!sessionId || isTogglingPause) return;
setIsTogglingPause(true);
try {
if (status === 'paused') {
await resumeSession(sessionId);
} else if (status === 'active' || status === 'idle') {
await pauseSession(sessionId);
}
} catch (error) {
console.error('[TerminalPane] Toggle pause failed:', error);
} finally {
setIsTogglingPause(false);
}
}, [sessionId, isTogglingPause, status, pauseSession, resumeSession]);
return (
<div
className={cn(
@@ -197,13 +238,58 @@ export function TerminalPane({ paneId }: TerminalPaneProps) {
<SplitSquareVertical className="w-3.5 h-3.5" />
</button>
{sessionId && (
<button
onClick={handleClear}
className="p-1 rounded hover:bg-muted transition-colors text-muted-foreground hover:text-foreground"
title={formatMessage({ id: 'terminalDashboard.pane.clearTerminal' })}
>
<Eraser className="w-3.5 h-3.5" />
</button>
<>
{/* Restart button */}
<button
onClick={handleRestart}
disabled={isRestarting}
className={cn(
'p-1 rounded hover:bg-muted transition-colors',
isRestarting ? 'text-muted-foreground/50' : 'text-muted-foreground hover:text-foreground'
)}
title={formatMessage({ id: 'terminalDashboard.pane.restart' })}
>
{isRestarting ? (
<Loader2 className="w-3.5 h-3.5 animate-spin" />
) : (
<RotateCcw className="w-3.5 h-3.5" />
)}
</button>
{/* Pause/Resume toggle button */}
<button
onClick={handleTogglePause}
disabled={isTogglingPause || status === 'resuming'}
className={cn(
'p-1 rounded hover:bg-muted transition-colors',
isTogglingPause || status === 'resuming'
? 'text-muted-foreground/50'
: status === 'paused'
? 'text-yellow-500 hover:text-yellow-600'
: 'text-muted-foreground hover:text-foreground'
)}
title={formatMessage({
id: status === 'paused'
? 'terminalDashboard.pane.resume'
: 'terminalDashboard.pane.pause',
})}
>
{isTogglingPause || status === 'resuming' ? (
<Loader2 className="w-3.5 h-3.5 animate-spin" />
) : status === 'paused' ? (
<Play className="w-3.5 h-3.5" />
) : (
<Pause className="w-3.5 h-3.5" />
)}
</button>
{/* Clear terminal button */}
<button
onClick={handleClear}
className="p-1 rounded hover:bg-muted transition-colors text-muted-foreground hover:text-foreground"
title={formatMessage({ id: 'terminalDashboard.pane.clearTerminal' })}
>
<Eraser className="w-3.5 h-3.5" />
</button>
</>
)}
{alertCount > 0 && (
<span className="flex items-center gap-0.5 px-1 text-destructive">