feat: Add orchestrator template and roles for executor and planner

- Created a new orchestrator template for Codex skill design, detailing structure and execution phases.
- Introduced the executor role with responsibilities for task execution, including routing to backends and handling implementation.
- Added the planner role for requirement breakdown, issue creation, and task dispatching, ensuring a structured planning process.
This commit is contained in:
catlog22
2026-02-16 00:17:15 +08:00
parent dc03862ca7
commit a4fff6a591
36 changed files with 4168 additions and 2589 deletions

View File

@@ -11,6 +11,7 @@ import {
AlertCircle,
ListChecks,
Info,
FolderOpen,
LayoutGrid,
Columns2,
Rows2,
@@ -47,7 +48,7 @@ import { CliConfigModal, type CliSessionConfig } from './CliConfigModal';
// ========== Types ==========
export type PanelId = 'issues' | 'queue' | 'inspector';
export type PanelId = 'issues' | 'queue' | 'inspector' | 'files';
interface DashboardToolbarProps {
activePanel: PanelId | null;
@@ -292,6 +293,12 @@ export function DashboardToolbar({ activePanel, onTogglePanel }: DashboardToolba
onClick={() => onTogglePanel('inspector')}
dot={hasChain}
/>
<ToolbarButton
icon={FolderOpen}
label={formatMessage({ id: 'terminalDashboard.toolbar.files', defaultMessage: 'Files' })}
isActive={activePanel === 'files'}
onClick={() => onTogglePanel('files')}
/>
{/* Separator */}
<div className="w-px h-5 bg-border mx-1" />

View File

@@ -20,6 +20,7 @@ export interface FloatingFileBrowserProps {
rootPath: string;
onInsertPath?: (path: string) => void;
initialSelectedPath?: string | null;
width?: number | string;
}
export function FloatingFileBrowser({
@@ -28,6 +29,7 @@ export function FloatingFileBrowser({
rootPath,
onInsertPath,
initialSelectedPath = null,
width = 400,
}: FloatingFileBrowserProps) {
const { formatMessage } = useIntl();
@@ -89,7 +91,7 @@ export function FloatingFileBrowser({
onClose={onClose}
title={formatMessage({ id: 'terminalDashboard.fileBrowser.title' })}
side="right"
width={400}
width={width}
>
<div className="flex flex-col h-full">
{/* Toolbar */}
@@ -148,7 +150,7 @@ export function FloatingFileBrowser({
{/* Body */}
<div className="flex-1 min-h-0 flex overflow-hidden">
{/* Tree */}
<div className="w-[180px] shrink-0 border-r border-border overflow-y-auto">
<div className="w-[240px] shrink-0 border-r border-border overflow-y-auto">
{isLoading ? (
<div className="flex items-center justify-center py-8 text-muted-foreground">
<Loader2 className="w-5 h-5 animate-spin" />

View File

@@ -15,7 +15,7 @@ interface FloatingPanelProps {
onClose: () => void;
title: string;
side?: 'left' | 'right';
width?: number;
width?: number | string;
children: React.ReactNode;
}
@@ -77,7 +77,7 @@ export function FloatingPanel({
style={{
top: '40px', // Below toolbar
height: 'calc(100vh - 40px)', // Full height below toolbar
width: `${width}px`,
width: typeof width === 'number' ? `${width}px` : width,
}}
>
{/* Panel header */}

View File

@@ -82,8 +82,9 @@ function IssueItem({
);
return (
<button
type="button"
<div
role="button"
tabIndex={0}
className={cn(
'w-full text-left px-2.5 py-1.5 rounded-md transition-colors',
'hover:bg-muted/60 focus:outline-none focus:ring-1 focus:ring-primary/30',
@@ -91,6 +92,7 @@ function IssueItem({
isHighlighted && !isSelected && 'bg-accent/50'
)}
onClick={onSelect}
onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onSelect(); } }}
>
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2 min-w-0">
@@ -129,7 +131,7 @@ function IssueItem({
</>
)}
</div>
</button>
</div>
);
}

View File

@@ -73,6 +73,7 @@
"issues": "Issues",
"queue": "Queue",
"inspector": "Inspector",
"files": "Files",
"layoutSingle": "Single",
"layoutSplitH": "Split Horizontal",
"layoutSplitV": "Split Vertical",

View File

@@ -73,6 +73,7 @@
"issues": "问题",
"queue": "队列",
"inspector": "检查器",
"files": "文件",
"layoutSingle": "单窗格",
"layoutSplitH": "左右分割",
"layoutSplitV": "上下分割",

View File

@@ -18,6 +18,10 @@ import { AgentList } from '@/components/terminal-dashboard/AgentList';
import { IssuePanel } from '@/components/terminal-dashboard/IssuePanel';
import { QueuePanel } from '@/components/terminal-dashboard/QueuePanel';
import { InspectorContent } from '@/components/terminal-dashboard/BottomInspector';
import { FloatingFileBrowser } from '@/components/terminal-dashboard/FloatingFileBrowser';
import { useWorkflowStore, selectProjectPath } from '@/stores/workflowStore';
import { useTerminalGridStore, selectTerminalGridFocusedPaneId } from '@/stores/terminalGridStore';
import { sendCliSessionText } from '@/lib/api';
// ========== Main Page Component ==========
@@ -25,6 +29,10 @@ export function TerminalDashboardPage() {
const { formatMessage } = useIntl();
const [activePanel, setActivePanel] = useState<PanelId | null>(null);
const projectPath = useWorkflowStore(selectProjectPath);
const focusedPaneId = useTerminalGridStore(selectTerminalGridFocusedPaneId);
const panes = useTerminalGridStore((s) => s.panes);
const togglePanel = useCallback((panelId: PanelId) => {
setActivePanel((prev) => (prev === panelId ? null : panelId));
}, []);
@@ -33,6 +41,20 @@ export function TerminalDashboardPage() {
setActivePanel(null);
}, []);
const handleInsertPath = useCallback(
(path: string) => {
if (!focusedPaneId) return;
const sessionId = panes[focusedPaneId]?.sessionId;
if (!sessionId) return;
sendCliSessionText(
sessionId,
{ text: path, appendNewline: false },
projectPath ?? undefined
).catch((err) => console.error('[TerminalDashboard] insert path failed:', err));
},
[focusedPaneId, panes, projectPath]
);
return (
<div className="-m-4 md:-m-6 flex flex-col h-[calc(100vh-56px)] overflow-hidden">
<AssociationHighlightProvider>
@@ -90,6 +112,15 @@ export function TerminalDashboardPage() {
>
<InspectorContent />
</FloatingPanel>
{/* File browser (half screen, right side) */}
<FloatingFileBrowser
isOpen={activePanel === 'files'}
onClose={closePanel}
rootPath={projectPath ?? '/'}
onInsertPath={focusedPaneId ? handleInsertPath : undefined}
width="50vw"
/>
</AssociationHighlightProvider>
</div>
);

View File

@@ -235,6 +235,10 @@ export const useConfigStore = create<ConfigStore>()(
secondaryModel: t.secondaryModel || '',
tags: t.tags || [],
type: t.type || 'builtin',
// Load additional fields from backend (fixes cross-browser config sync)
envFile: t.envFile,
settingsFile: t.settingsFile,
availableModels: t.availableModels,
};
}
if (Object.keys(cliTools).length > 0) {