@winspan/claude-forge 8.33.0 → 8.33.3

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.
Files changed (35) hide show
  1. package/dist/cli/commands/daemon.d.ts.map +1 -1
  2. package/dist/cli/commands/daemon.js +32 -11
  3. package/dist/cli/commands/daemon.js.map +1 -1
  4. package/dist/cli/commands/init.d.ts.map +1 -1
  5. package/dist/cli/commands/init.js +82 -2
  6. package/dist/cli/commands/init.js.map +1 -1
  7. package/dist/web/static/assets/AIConfig-Dw13rVtT.js +2 -0
  8. package/dist/web/static/assets/AIConfig-Dw13rVtT.js.map +1 -0
  9. package/dist/web/static/assets/Agents-D1p3JhQs.js +2 -0
  10. package/dist/web/static/assets/Agents-D1p3JhQs.js.map +1 -0
  11. package/dist/web/static/assets/{Events-BoQ8Fo5k.js → Events-DqzBTrly.js} +2 -2
  12. package/dist/web/static/assets/{Events-BoQ8Fo5k.js.map → Events-DqzBTrly.js.map} +1 -1
  13. package/dist/web/static/assets/{ExecutionTrace-sFZ_vHNf.js → ExecutionTrace-Z-zlH0KH.js} +2 -2
  14. package/dist/web/static/assets/{ExecutionTrace-sFZ_vHNf.js.map → ExecutionTrace-Z-zlH0KH.js.map} +1 -1
  15. package/dist/web/static/assets/Methodologies-Br5KOWuF.js +5 -0
  16. package/dist/web/static/assets/Methodologies-Br5KOWuF.js.map +1 -0
  17. package/dist/web/static/assets/{Sessions-Bjf-Mvwb.js → Sessions-DOd65EkN.js} +2 -2
  18. package/dist/web/static/assets/{Sessions-Bjf-Mvwb.js.map → Sessions-DOd65EkN.js.map} +1 -1
  19. package/dist/web/static/assets/Skills-zacj_uSW.js +2 -0
  20. package/dist/web/static/assets/Skills-zacj_uSW.js.map +1 -0
  21. package/dist/web/static/assets/auth-Bnf8ZcqN.js +2 -0
  22. package/dist/web/static/assets/auth-Bnf8ZcqN.js.map +1 -0
  23. package/dist/web/static/assets/index-BVpUTHdp.js +3 -0
  24. package/dist/web/static/assets/{index-D23sAOAt.js.map → index-BVpUTHdp.js.map} +1 -1
  25. package/dist/web/static/index.html +1 -1
  26. package/package.json +2 -2
  27. package/dist/web/static/assets/AIConfig-D-vrYoJ3.js +0 -2
  28. package/dist/web/static/assets/AIConfig-D-vrYoJ3.js.map +0 -1
  29. package/dist/web/static/assets/Agents-DAGWYsJj.js +0 -2
  30. package/dist/web/static/assets/Agents-DAGWYsJj.js.map +0 -1
  31. package/dist/web/static/assets/Methodologies-C0-Keokj.js +0 -5
  32. package/dist/web/static/assets/Methodologies-C0-Keokj.js.map +0 -1
  33. package/dist/web/static/assets/Skills-CrLshkrJ.js +0 -2
  34. package/dist/web/static/assets/Skills-CrLshkrJ.js.map +0 -1
  35. package/dist/web/static/assets/index-D23sAOAt.js +0 -3
@@ -1 +1 @@
1
- {"version":3,"mappings":"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","names":["sections","LayoutDashboard","MessageSquare","Activity","TrendingUp","GitBranch","Bot","BookOpen","Network","Cpu","Layout","location","useLocation","sidebarOpen","setSidebarOpen","useState","renderNav","onClick","jsx","Fragment","section","jsxs","item","Icon","isActive","Link","clsx","X","Menu","Outlet","Dashboard","lazy","Sessions","SessionDetail","Events","ExecutionTrace","Methodologies","MethodologyDetail","Agents","Skills","Routing","AIConfig","PageFallback","App","Routes","Route","Navigate","Suspense","ToastContext","createContext","useToast","ctx","useContext","nextId","ToastProvider","children","toasts","setToasts","remove","useCallback","id","prev","t","show","type","message","value","msg","ToastItem","toast","onClose","icons","CheckCircle","XCircle","AlertCircle","Info","borderColors","ConfirmContext","useConfirm","ConfirmProvider","state","setState","confirm","options","resolve","handleClose","result","variant","_a","iconColor","btnColor","AlertTriangle","queryClient","QueryClient","ReactDOM","React","QueryClientProvider","BrowserRouter"],"ignoreList":[],"sources":["../../src/components/Layout.tsx","../../src/App.tsx","../../src/components/Toast.tsx","../../src/components/Confirm.tsx","../../src/main.tsx"],"sourcesContent":["import { Outlet, Link, useLocation } from 'react-router-dom'\nimport {\n LayoutDashboard,\n MessageSquare,\n Activity,\n GitBranch,\n Menu,\n X,\n Bot,\n BookOpen,\n Network,\n Cpu,\n TrendingUp,\n} from 'lucide-react'\nimport { useState } from 'react'\nimport clsx from 'clsx'\n\ninterface NavItem {\n name: string\n href: string\n icon: any\n}\n\ninterface NavSection {\n title: string\n items: NavItem[]\n}\n\nconst sections: NavSection[] = [\n {\n title: '总览',\n items: [\n { name: '仪表盘', href: '/dashboard', icon: LayoutDashboard },\n ],\n },\n {\n title: '活动',\n items: [\n { name: '会话', href: '/sessions', icon: MessageSquare },\n { name: '事件', href: '/events', icon: Activity },\n { name: '执行追踪', href: '/execution-trace', icon: TrendingUp },\n { name: '方法论执行', href: '/methodologies', icon: GitBranch },\n ],\n },\n {\n title: '配置',\n items: [\n { name: 'Agent 管理', href: '/agents', icon: Bot },\n { name: 'Skill 管理', href: '/skills', icon: BookOpen },\n { name: 'Agent 路由', href: '/routing', icon: Network },\n { name: 'AI 配置', href: '/ai-config', icon: Cpu },\n ],\n },\n]\n\nexport default function Layout() {\n const location = useLocation()\n const [sidebarOpen, setSidebarOpen] = useState(false)\n\n const renderNav = (onClick?: () => void) => (\n <>\n {sections.map((section) => (\n <div key={section.title} className=\"mb-4\">\n <div className=\"px-3 py-2 text-xs font-semibold text-gray-400 uppercase tracking-wider\">\n {section.title}\n </div>\n {section.items.map((item) => {\n const Icon = item.icon\n const isActive = location.pathname === item.href || location.pathname.startsWith(item.href + '/')\n return (\n <Link\n key={item.name}\n to={item.href}\n onClick={onClick}\n className={clsx(\n 'group flex items-center px-3 py-2 text-sm font-medium rounded-md mb-0.5',\n isActive\n ? 'bg-indigo-50 text-indigo-600'\n : 'text-gray-700 hover:bg-gray-50'\n )}\n >\n <Icon className={clsx('mr-3 h-4 w-4', isActive ? 'text-indigo-600' : 'text-gray-400')} />\n {item.name}\n </Link>\n )\n })}\n </div>\n ))}\n </>\n )\n\n return (\n <div className=\"min-h-screen bg-gray-50\">\n {/* Mobile sidebar */}\n <div className={clsx('fixed inset-0 z-40 lg:hidden', sidebarOpen ? 'block' : 'hidden')}>\n <div className=\"fixed inset-0 bg-gray-600 bg-opacity-75\" onClick={() => setSidebarOpen(false)} />\n <div className=\"fixed inset-y-0 left-0 flex w-64 flex-col bg-white\">\n <div className=\"flex items-center justify-between px-4 py-4 border-b\">\n <div className=\"flex items-center gap-2\">\n <div className=\"w-8 h-8 rounded-lg bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center text-white font-bold text-sm\">\n CF\n </div>\n <h1 className=\"text-base font-bold text-gray-900\">Claude Forge</h1>\n </div>\n <button onClick={() => setSidebarOpen(false)} className=\"text-gray-500\">\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n <nav className=\"flex-1 overflow-y-auto px-2 py-4\">\n {renderNav(() => setSidebarOpen(false))}\n </nav>\n </div>\n </div>\n\n {/* Desktop sidebar */}\n <div className=\"hidden lg:fixed lg:inset-y-0 lg:flex lg:w-64 lg:flex-col\">\n <div className=\"flex flex-col flex-grow border-r border-gray-200 bg-white\">\n <div className=\"flex items-center gap-2 px-4 py-4 border-b\">\n <div className=\"w-8 h-8 rounded-lg bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center text-white font-bold text-sm\">\n CF\n </div>\n <h1 className=\"text-base font-bold text-gray-900\">Claude Forge</h1>\n </div>\n <nav className=\"flex-1 overflow-y-auto px-2 py-4\">{renderNav()}</nav>\n </div>\n </div>\n\n {/* Main content */}\n <div className=\"lg:pl-64\">\n <div className=\"sticky top-0 z-10 flex h-14 flex-shrink-0 bg-white border-b border-gray-200 lg:hidden\">\n <button\n onClick={() => setSidebarOpen(true)}\n className=\"px-4 text-gray-500 focus:outline-none\"\n >\n <Menu className=\"h-5 w-5\" />\n </button>\n <div className=\"flex flex-1 items-center px-4\">\n <h1 className=\"text-base font-semibold text-gray-900\">Claude Forge</h1>\n </div>\n </div>\n <main className=\"py-6\">\n <div className=\"mx-auto max-w-7xl px-4 sm:px-6 lg:px-8\">\n <Outlet />\n </div>\n </main>\n </div>\n </div>\n )\n}\n","import { lazy, Suspense } from 'react'\nimport { Routes, Route, Navigate } from 'react-router-dom'\nimport Layout from './components/Layout'\n\n// 路由级代码分割:按需加载 page 组件,缩小主 bundle\nconst Dashboard = lazy(() => import('./pages/Dashboard'))\nconst Sessions = lazy(() => import('./pages/Sessions'))\nconst SessionDetail = lazy(() => import('./pages/SessionDetail'))\nconst Events = lazy(() => import('./pages/Events'))\nconst ExecutionTrace = lazy(() => import('./pages/ExecutionTrace'))\nconst Methodologies = lazy(() => import('./pages/Methodologies'))\nconst MethodologyDetail = lazy(() => import('./pages/MethodologyDetail'))\nconst Agents = lazy(() => import('./pages/Agents'))\nconst Skills = lazy(() => import('./pages/Skills'))\nconst Routing = lazy(() => import('./pages/Routing'))\nconst AIConfig = lazy(() => import('./pages/AIConfig'))\n\nfunction PageFallback() {\n return (\n <div className=\"flex items-center justify-center h-full py-16\">\n <div className=\"flex items-center gap-3 text-sm text-gray-500\">\n <div className=\"w-4 h-4 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin\" />\n 加载中...\n </div>\n </div>\n )\n}\n\nexport default function App() {\n return (\n <Routes>\n <Route path=\"/\" element={<Layout />}>\n <Route\n index\n element={<Navigate to=\"/dashboard\" replace />}\n />\n <Route\n path=\"dashboard\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Dashboard />\n </Suspense>\n }\n />\n <Route\n path=\"sessions\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Sessions />\n </Suspense>\n }\n />\n <Route\n path=\"sessions/:id\"\n element={\n <Suspense fallback={<PageFallback />}>\n <SessionDetail />\n </Suspense>\n }\n />\n <Route\n path=\"events\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Events />\n </Suspense>\n }\n />\n <Route\n path=\"execution-trace\"\n element={\n <Suspense fallback={<PageFallback />}>\n <ExecutionTrace />\n </Suspense>\n }\n />\n <Route\n path=\"methodologies\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Methodologies />\n </Suspense>\n }\n />\n <Route\n path=\"methodologies/:id\"\n element={\n <Suspense fallback={<PageFallback />}>\n <MethodologyDetail />\n </Suspense>\n }\n />\n <Route\n path=\"agents\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Agents />\n </Suspense>\n }\n />\n <Route\n path=\"skills\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Skills />\n </Suspense>\n }\n />\n <Route\n path=\"routing\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Routing />\n </Suspense>\n }\n />\n <Route\n path=\"ai-config\"\n element={\n <Suspense fallback={<PageFallback />}>\n <AIConfig />\n </Suspense>\n }\n />\n </Route>\n </Routes>\n )\n}\n","import { createContext, useContext, useState, useCallback, ReactNode } from 'react'\nimport { CheckCircle, XCircle, AlertCircle, Info, X } from 'lucide-react'\nimport clsx from 'clsx'\n\ntype ToastType = 'success' | 'error' | 'warning' | 'info'\n\ninterface Toast {\n id: number\n type: ToastType\n message: string\n}\n\ninterface ToastContextValue {\n show: (type: ToastType, message: string) => void\n success: (message: string) => void\n error: (message: string) => void\n warning: (message: string) => void\n info: (message: string) => void\n}\n\nconst ToastContext = createContext<ToastContextValue | null>(null)\n\nexport function useToast() {\n const ctx = useContext(ToastContext)\n if (!ctx) throw new Error('useToast must be used within ToastProvider')\n return ctx\n}\n\nlet nextId = 1\n\nexport function ToastProvider({ children }: { children: ReactNode }) {\n const [toasts, setToasts] = useState<Toast[]>([])\n\n const remove = useCallback((id: number) => {\n setToasts(prev => prev.filter(t => t.id !== id))\n }, [])\n\n const show = useCallback((type: ToastType, message: string) => {\n const id = nextId++\n setToasts(prev => [...prev, { id, type, message }])\n setTimeout(() => remove(id), 4000)\n }, [remove])\n\n const value: ToastContextValue = {\n show,\n success: (msg) => show('success', msg),\n error: (msg) => show('error', msg),\n warning: (msg) => show('warning', msg),\n info: (msg) => show('info', msg),\n }\n\n return (\n <ToastContext.Provider value={value}>\n {children}\n <div className=\"fixed top-4 right-4 z-[9999] space-y-2 max-w-md\">\n {toasts.map(t => (\n <ToastItem key={t.id} toast={t} onClose={() => remove(t.id)} />\n ))}\n </div>\n </ToastContext.Provider>\n )\n}\n\nfunction ToastItem({ toast, onClose }: { toast: Toast; onClose: () => void }) {\n const icons = {\n success: <CheckCircle className=\"h-5 w-5 text-green-500\" />,\n error: <XCircle className=\"h-5 w-5 text-red-500\" />,\n warning: <AlertCircle className=\"h-5 w-5 text-yellow-500\" />,\n info: <Info className=\"h-5 w-5 text-blue-500\" />,\n }\n const borderColors = {\n success: 'border-green-200',\n error: 'border-red-200',\n warning: 'border-yellow-200',\n info: 'border-blue-200',\n }\n\n return (\n <div\n className={clsx(\n 'bg-white shadow-lg rounded-lg border px-4 py-3 flex items-start gap-3 animate-in slide-in-from-right',\n borderColors[toast.type]\n )}\n >\n {icons[toast.type]}\n <div className=\"flex-1 text-sm text-gray-800\">{toast.message}</div>\n <button onClick={onClose} className=\"text-gray-400 hover:text-gray-600\">\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n )\n}\n","import { createContext, useContext, useState, useCallback, ReactNode } from 'react'\nimport { AlertTriangle } from 'lucide-react'\n\ninterface ConfirmOptions {\n title: string\n message: string\n confirmText?: string\n cancelText?: string\n variant?: 'danger' | 'warning' | 'info'\n}\n\ninterface ConfirmContextValue {\n confirm: (options: ConfirmOptions) => Promise<boolean>\n}\n\nconst ConfirmContext = createContext<ConfirmContextValue | null>(null)\n\nexport function useConfirm() {\n const ctx = useContext(ConfirmContext)\n if (!ctx) throw new Error('useConfirm must be used within ConfirmProvider')\n return ctx.confirm\n}\n\nexport function ConfirmProvider({ children }: { children: ReactNode }) {\n const [state, setState] = useState<{\n open: boolean\n options: ConfirmOptions | null\n resolve: ((value: boolean) => void) | null\n }>({ open: false, options: null, resolve: null })\n\n const confirm = useCallback((options: ConfirmOptions): Promise<boolean> => {\n return new Promise((resolve) => {\n setState({ open: true, options, resolve })\n })\n }, [])\n\n const handleClose = (result: boolean) => {\n if (state.resolve) state.resolve(result)\n setState({ open: false, options: null, resolve: null })\n }\n\n const variant = state.options?.variant || 'danger'\n const iconColor = {\n danger: 'text-red-600',\n warning: 'text-yellow-600',\n info: 'text-blue-600',\n }[variant]\n const btnColor = {\n danger: 'bg-red-600 hover:bg-red-700',\n warning: 'bg-yellow-600 hover:bg-yellow-700',\n info: 'bg-indigo-600 hover:bg-indigo-700',\n }[variant]\n\n return (\n <ConfirmContext.Provider value={{ confirm }}>\n {children}\n {state.open && state.options && (\n <div className=\"fixed inset-0 z-[9999] flex items-center justify-center\">\n <div\n className=\"absolute inset-0 bg-black bg-opacity-50\"\n onClick={() => handleClose(false)}\n />\n <div className=\"relative bg-white rounded-lg shadow-xl max-w-md w-full mx-4 p-6\">\n <div className=\"flex items-start gap-4\">\n <div className={`flex-shrink-0 ${iconColor}`}>\n <AlertTriangle className=\"h-6 w-6\" />\n </div>\n <div className=\"flex-1\">\n <h3 className=\"text-lg font-semibold text-gray-900 mb-2\">\n {state.options.title}\n </h3>\n <p className=\"text-sm text-gray-600 whitespace-pre-wrap\">\n {state.options.message}\n </p>\n </div>\n </div>\n <div className=\"flex justify-end gap-2 mt-6\">\n <button\n onClick={() => handleClose(false)}\n className=\"px-4 py-2 text-sm text-gray-700 bg-white border border-gray-300 rounded hover:bg-gray-50\"\n >\n {state.options.cancelText || '取消'}\n </button>\n <button\n onClick={() => handleClose(true)}\n className={`px-4 py-2 text-sm text-white rounded ${btnColor}`}\n >\n {state.options.confirmText || '确定'}\n </button>\n </div>\n </div>\n </div>\n )}\n </ConfirmContext.Provider>\n )\n}\n","import React from 'react'\nimport ReactDOM from 'react-dom/client'\nimport { BrowserRouter } from 'react-router-dom'\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport App from './App'\nimport { ToastProvider } from './components/Toast'\nimport { ConfirmProvider } from './components/Confirm'\nimport './index.css'\n\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n refetchOnWindowFocus: false,\n retry: 1,\n },\n },\n})\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <QueryClientProvider client={queryClient}>\n <ToastProvider>\n <ConfirmProvider>\n <BrowserRouter>\n <App />\n </BrowserRouter>\n </ConfirmProvider>\n </ToastProvider>\n </QueryClientProvider>\n </React.StrictMode>,\n)\n"],"file":"assets/index-D23sAOAt.js"}
1
+ {"version":3,"mappings":"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","names":["sections","LayoutDashboard","MessageSquare","Activity","TrendingUp","GitBranch","Bot","BookOpen","Network","Cpu","Layout","location","useLocation","sidebarOpen","setSidebarOpen","useState","renderNav","onClick","jsx","Fragment","section","jsxs","item","Icon","isActive","Link","clsx","X","Menu","Outlet","Dashboard","lazy","Sessions","SessionDetail","Events","ExecutionTrace","Methodologies","MethodologyDetail","Agents","Skills","Routing","AIConfig","PageFallback","App","Routes","Route","Navigate","Suspense","ToastContext","createContext","useToast","ctx","useContext","nextId","ToastProvider","children","toasts","setToasts","remove","useCallback","id","prev","t","show","type","message","value","msg","ToastItem","toast","onClose","icons","CheckCircle","XCircle","AlertCircle","Info","borderColors","ConfirmContext","useConfirm","ConfirmProvider","state","setState","confirm","options","resolve","handleClose","result","variant","_a","iconColor","btnColor","AlertTriangle","queryClient","QueryClient","ReactDOM","React","QueryClientProvider","BrowserRouter"],"ignoreList":[],"sources":["../../src/components/Layout.tsx","../../src/App.tsx","../../src/components/Toast.tsx","../../src/components/Confirm.tsx","../../src/main.tsx"],"sourcesContent":["import { Outlet, Link, useLocation } from 'react-router-dom'\nimport {\n LayoutDashboard,\n MessageSquare,\n Activity,\n GitBranch,\n Menu,\n X,\n Bot,\n BookOpen,\n Network,\n Cpu,\n TrendingUp,\n} from 'lucide-react'\nimport { useState } from 'react'\nimport clsx from 'clsx'\n\ninterface NavItem {\n name: string\n href: string\n icon: any\n}\n\ninterface NavSection {\n title: string\n items: NavItem[]\n}\n\nconst sections: NavSection[] = [\n {\n title: '总览',\n items: [\n { name: '仪表盘', href: '/dashboard', icon: LayoutDashboard },\n ],\n },\n {\n title: '活动',\n items: [\n { name: '会话', href: '/sessions', icon: MessageSquare },\n { name: '事件', href: '/events', icon: Activity },\n { name: '执行追踪', href: '/execution-trace', icon: TrendingUp },\n { name: '方法论执行', href: '/methodologies', icon: GitBranch },\n ],\n },\n {\n title: '配置',\n items: [\n { name: 'Agent 管理', href: '/agents', icon: Bot },\n { name: 'Skill 管理', href: '/skills', icon: BookOpen },\n { name: 'Agent 路由', href: '/routing', icon: Network },\n { name: 'AI 配置', href: '/ai-config', icon: Cpu },\n ],\n },\n]\n\nexport default function Layout() {\n const location = useLocation()\n const [sidebarOpen, setSidebarOpen] = useState(false)\n\n const renderNav = (onClick?: () => void) => (\n <>\n {sections.map((section) => (\n <div key={section.title} className=\"mb-4\">\n <div className=\"px-3 py-2 text-xs font-semibold text-gray-400 uppercase tracking-wider\">\n {section.title}\n </div>\n {section.items.map((item) => {\n const Icon = item.icon\n const isActive = location.pathname === item.href || location.pathname.startsWith(item.href + '/')\n return (\n <Link\n key={item.name}\n to={item.href}\n onClick={onClick}\n className={clsx(\n 'group flex items-center px-3 py-2 text-sm font-medium rounded-md mb-0.5',\n isActive\n ? 'bg-indigo-50 text-indigo-600'\n : 'text-gray-700 hover:bg-gray-50'\n )}\n >\n <Icon className={clsx('mr-3 h-4 w-4', isActive ? 'text-indigo-600' : 'text-gray-400')} />\n {item.name}\n </Link>\n )\n })}\n </div>\n ))}\n </>\n )\n\n return (\n <div className=\"min-h-screen bg-gray-50\">\n {/* Mobile sidebar */}\n <div className={clsx('fixed inset-0 z-40 lg:hidden', sidebarOpen ? 'block' : 'hidden')}>\n <div className=\"fixed inset-0 bg-gray-600 bg-opacity-75\" onClick={() => setSidebarOpen(false)} />\n <div className=\"fixed inset-y-0 left-0 flex w-64 flex-col bg-white\">\n <div className=\"flex items-center justify-between px-4 py-4 border-b\">\n <div className=\"flex items-center gap-2\">\n <div className=\"w-8 h-8 rounded-lg bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center text-white font-bold text-sm\">\n CF\n </div>\n <h1 className=\"text-base font-bold text-gray-900\">Claude Forge</h1>\n </div>\n <button onClick={() => setSidebarOpen(false)} className=\"text-gray-500\">\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n <nav className=\"flex-1 overflow-y-auto px-2 py-4\">\n {renderNav(() => setSidebarOpen(false))}\n </nav>\n </div>\n </div>\n\n {/* Desktop sidebar */}\n <div className=\"hidden lg:fixed lg:inset-y-0 lg:flex lg:w-64 lg:flex-col\">\n <div className=\"flex flex-col flex-grow border-r border-gray-200 bg-white\">\n <div className=\"flex items-center gap-2 px-4 py-4 border-b\">\n <div className=\"w-8 h-8 rounded-lg bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center text-white font-bold text-sm\">\n CF\n </div>\n <h1 className=\"text-base font-bold text-gray-900\">Claude Forge</h1>\n </div>\n <nav className=\"flex-1 overflow-y-auto px-2 py-4\">{renderNav()}</nav>\n </div>\n </div>\n\n {/* Main content */}\n <div className=\"lg:pl-64\">\n <div className=\"sticky top-0 z-10 flex h-14 flex-shrink-0 bg-white border-b border-gray-200 lg:hidden\">\n <button\n onClick={() => setSidebarOpen(true)}\n className=\"px-4 text-gray-500 focus:outline-none\"\n >\n <Menu className=\"h-5 w-5\" />\n </button>\n <div className=\"flex flex-1 items-center px-4\">\n <h1 className=\"text-base font-semibold text-gray-900\">Claude Forge</h1>\n </div>\n </div>\n <main className=\"py-6\">\n <div className=\"mx-auto max-w-7xl px-4 sm:px-6 lg:px-8\">\n <Outlet />\n </div>\n </main>\n </div>\n </div>\n )\n}\n","import { lazy, Suspense } from 'react'\nimport { Routes, Route, Navigate } from 'react-router-dom'\nimport Layout from './components/Layout'\n\n// 路由级代码分割:按需加载 page 组件,缩小主 bundle\nconst Dashboard = lazy(() => import('./pages/Dashboard'))\nconst Sessions = lazy(() => import('./pages/Sessions'))\nconst SessionDetail = lazy(() => import('./pages/SessionDetail'))\nconst Events = lazy(() => import('./pages/Events'))\nconst ExecutionTrace = lazy(() => import('./pages/ExecutionTrace'))\nconst Methodologies = lazy(() => import('./pages/Methodologies'))\nconst MethodologyDetail = lazy(() => import('./pages/MethodologyDetail'))\nconst Agents = lazy(() => import('./pages/Agents'))\nconst Skills = lazy(() => import('./pages/Skills'))\nconst Routing = lazy(() => import('./pages/Routing'))\nconst AIConfig = lazy(() => import('./pages/AIConfig'))\n\nfunction PageFallback() {\n return (\n <div className=\"flex items-center justify-center h-full py-16\">\n <div className=\"flex items-center gap-3 text-sm text-gray-500\">\n <div className=\"w-4 h-4 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin\" />\n 加载中...\n </div>\n </div>\n )\n}\n\nexport default function App() {\n return (\n <Routes>\n <Route path=\"/\" element={<Layout />}>\n <Route\n index\n element={<Navigate to=\"/dashboard\" replace />}\n />\n <Route\n path=\"dashboard\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Dashboard />\n </Suspense>\n }\n />\n <Route\n path=\"sessions\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Sessions />\n </Suspense>\n }\n />\n <Route\n path=\"sessions/:id\"\n element={\n <Suspense fallback={<PageFallback />}>\n <SessionDetail />\n </Suspense>\n }\n />\n <Route\n path=\"events\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Events />\n </Suspense>\n }\n />\n <Route\n path=\"execution-trace\"\n element={\n <Suspense fallback={<PageFallback />}>\n <ExecutionTrace />\n </Suspense>\n }\n />\n <Route\n path=\"methodologies\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Methodologies />\n </Suspense>\n }\n />\n <Route\n path=\"methodologies/:id\"\n element={\n <Suspense fallback={<PageFallback />}>\n <MethodologyDetail />\n </Suspense>\n }\n />\n <Route\n path=\"agents\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Agents />\n </Suspense>\n }\n />\n <Route\n path=\"skills\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Skills />\n </Suspense>\n }\n />\n <Route\n path=\"routing\"\n element={\n <Suspense fallback={<PageFallback />}>\n <Routing />\n </Suspense>\n }\n />\n <Route\n path=\"ai-config\"\n element={\n <Suspense fallback={<PageFallback />}>\n <AIConfig />\n </Suspense>\n }\n />\n </Route>\n </Routes>\n )\n}\n","import { createContext, useContext, useState, useCallback, ReactNode } from 'react'\nimport { CheckCircle, XCircle, AlertCircle, Info, X } from 'lucide-react'\nimport clsx from 'clsx'\n\ntype ToastType = 'success' | 'error' | 'warning' | 'info'\n\ninterface Toast {\n id: number\n type: ToastType\n message: string\n}\n\ninterface ToastContextValue {\n show: (type: ToastType, message: string) => void\n success: (message: string) => void\n error: (message: string) => void\n warning: (message: string) => void\n info: (message: string) => void\n}\n\nconst ToastContext = createContext<ToastContextValue | null>(null)\n\nexport function useToast() {\n const ctx = useContext(ToastContext)\n if (!ctx) throw new Error('useToast must be used within ToastProvider')\n return ctx\n}\n\nlet nextId = 1\n\nexport function ToastProvider({ children }: { children: ReactNode }) {\n const [toasts, setToasts] = useState<Toast[]>([])\n\n const remove = useCallback((id: number) => {\n setToasts(prev => prev.filter(t => t.id !== id))\n }, [])\n\n const show = useCallback((type: ToastType, message: string) => {\n const id = nextId++\n setToasts(prev => [...prev, { id, type, message }])\n setTimeout(() => remove(id), 4000)\n }, [remove])\n\n const value: ToastContextValue = {\n show,\n success: (msg) => show('success', msg),\n error: (msg) => show('error', msg),\n warning: (msg) => show('warning', msg),\n info: (msg) => show('info', msg),\n }\n\n return (\n <ToastContext.Provider value={value}>\n {children}\n <div className=\"fixed top-4 right-4 z-[9999] space-y-2 max-w-md\">\n {toasts.map(t => (\n <ToastItem key={t.id} toast={t} onClose={() => remove(t.id)} />\n ))}\n </div>\n </ToastContext.Provider>\n )\n}\n\nfunction ToastItem({ toast, onClose }: { toast: Toast; onClose: () => void }) {\n const icons = {\n success: <CheckCircle className=\"h-5 w-5 text-green-500\" />,\n error: <XCircle className=\"h-5 w-5 text-red-500\" />,\n warning: <AlertCircle className=\"h-5 w-5 text-yellow-500\" />,\n info: <Info className=\"h-5 w-5 text-blue-500\" />,\n }\n const borderColors = {\n success: 'border-green-200',\n error: 'border-red-200',\n warning: 'border-yellow-200',\n info: 'border-blue-200',\n }\n\n return (\n <div\n className={clsx(\n 'bg-white shadow-lg rounded-lg border px-4 py-3 flex items-start gap-3 animate-in slide-in-from-right',\n borderColors[toast.type]\n )}\n >\n {icons[toast.type]}\n <div className=\"flex-1 text-sm text-gray-800\">{toast.message}</div>\n <button onClick={onClose} className=\"text-gray-400 hover:text-gray-600\">\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n )\n}\n","import { createContext, useContext, useState, useCallback, ReactNode } from 'react'\nimport { AlertTriangle } from 'lucide-react'\n\ninterface ConfirmOptions {\n title: string\n message: string\n confirmText?: string\n cancelText?: string\n variant?: 'danger' | 'warning' | 'info'\n}\n\ninterface ConfirmContextValue {\n confirm: (options: ConfirmOptions) => Promise<boolean>\n}\n\nconst ConfirmContext = createContext<ConfirmContextValue | null>(null)\n\nexport function useConfirm() {\n const ctx = useContext(ConfirmContext)\n if (!ctx) throw new Error('useConfirm must be used within ConfirmProvider')\n return ctx.confirm\n}\n\nexport function ConfirmProvider({ children }: { children: ReactNode }) {\n const [state, setState] = useState<{\n open: boolean\n options: ConfirmOptions | null\n resolve: ((value: boolean) => void) | null\n }>({ open: false, options: null, resolve: null })\n\n const confirm = useCallback((options: ConfirmOptions): Promise<boolean> => {\n return new Promise((resolve) => {\n setState({ open: true, options, resolve })\n })\n }, [])\n\n const handleClose = (result: boolean) => {\n if (state.resolve) state.resolve(result)\n setState({ open: false, options: null, resolve: null })\n }\n\n const variant = state.options?.variant || 'danger'\n const iconColor = {\n danger: 'text-red-600',\n warning: 'text-yellow-600',\n info: 'text-blue-600',\n }[variant]\n const btnColor = {\n danger: 'bg-red-600 hover:bg-red-700',\n warning: 'bg-yellow-600 hover:bg-yellow-700',\n info: 'bg-indigo-600 hover:bg-indigo-700',\n }[variant]\n\n return (\n <ConfirmContext.Provider value={{ confirm }}>\n {children}\n {state.open && state.options && (\n <div className=\"fixed inset-0 z-[9999] flex items-center justify-center\">\n <div\n className=\"absolute inset-0 bg-black bg-opacity-50\"\n onClick={() => handleClose(false)}\n />\n <div className=\"relative bg-white rounded-lg shadow-xl max-w-md w-full mx-4 p-6\">\n <div className=\"flex items-start gap-4\">\n <div className={`flex-shrink-0 ${iconColor}`}>\n <AlertTriangle className=\"h-6 w-6\" />\n </div>\n <div className=\"flex-1\">\n <h3 className=\"text-lg font-semibold text-gray-900 mb-2\">\n {state.options.title}\n </h3>\n <p className=\"text-sm text-gray-600 whitespace-pre-wrap\">\n {state.options.message}\n </p>\n </div>\n </div>\n <div className=\"flex justify-end gap-2 mt-6\">\n <button\n onClick={() => handleClose(false)}\n className=\"px-4 py-2 text-sm text-gray-700 bg-white border border-gray-300 rounded hover:bg-gray-50\"\n >\n {state.options.cancelText || '取消'}\n </button>\n <button\n onClick={() => handleClose(true)}\n className={`px-4 py-2 text-sm text-white rounded ${btnColor}`}\n >\n {state.options.confirmText || '确定'}\n </button>\n </div>\n </div>\n </div>\n )}\n </ConfirmContext.Provider>\n )\n}\n","import React from 'react'\nimport ReactDOM from 'react-dom/client'\nimport { BrowserRouter } from 'react-router-dom'\nimport { QueryClient, QueryClientProvider } from '@tanstack/react-query'\nimport App from './App'\nimport { ToastProvider } from './components/Toast'\nimport { ConfirmProvider } from './components/Confirm'\nimport './index.css'\n\nconst queryClient = new QueryClient({\n defaultOptions: {\n queries: {\n refetchOnWindowFocus: false,\n retry: 1,\n },\n },\n})\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <QueryClientProvider client={queryClient}>\n <ToastProvider>\n <ConfirmProvider>\n <BrowserRouter>\n <App />\n </BrowserRouter>\n </ConfirmProvider>\n </ToastProvider>\n </QueryClientProvider>\n </React.StrictMode>,\n)\n"],"file":"assets/index-BVpUTHdp.js"}
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Claude Forge 管理后台</title>
8
- <script type="module" crossorigin src="/assets/index-D23sAOAt.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-BVpUTHdp.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/react-vendor-CSp-GLFF.js">
10
10
  <link rel="modulepreload" crossorigin href="/assets/vendor-CMMjVdZs.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/react-router-I-HqunH7.js">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@winspan/claude-forge",
3
- "version": "8.33.0",
3
+ "version": "8.33.3",
4
4
  "description": "SDLC intelligent orchestration engine for Claude Code",
5
5
  "main": "dist/cli/index.js",
6
6
  "type": "module",
@@ -29,7 +29,7 @@
29
29
  "build": "tsc && mkdir -p dist/hooks && cp -r src/hooks/* dist/hooks/ && chmod +x dist/hooks/*.sh && cp src/core/storage/schema.sql dist/core/storage/schema.sql && mkdir -p dist/web/static && cp -r web/dist/* dist/web/static/ 2>/dev/null || cp src/web/static/index.html dist/web/static/ && cp -r src/web/static/vendor dist/web/static/ 2>/dev/null || true && mkdir -p dist/engine/conventions && cp src/engine/conventions/*.yaml dist/engine/conventions/ && mkdir -p dist/capability/methodologies && cp src/capability/methodologies/*.yaml dist/capability/methodologies/",
30
30
  "build:web": "cd web && npm run build",
31
31
  "build:all": "npm run build:web && npm run build",
32
- "prepublishOnly": "npm run build",
32
+ "prepublishOnly": "npm run build:all",
33
33
  "dev": "tsx src/cli/index.ts",
34
34
  "dev:daemon": "tsx src/daemon/index.ts",
35
35
  "dev:web": "tsx scripts/dev-web.ts",
@@ -1,2 +0,0 @@
1
- import{r as m,j as e}from"./react-vendor-CSp-GLFF.js";import{b as v,u as p,c as y}from"./query-C99w429o.js";import{u as w}from"./index-D23sAOAt.js";import{C as N,E as k,w as _,e as C,d as P,q as S,Z as E,v as A}from"./lucide-DjB4fWNj.js";import"./react-router-I-HqunH7.js";import"./vendor-CMMjVdZs.js";import"./syntax-highlighter-44FakypI.js";async function I(){const a=await fetch("/api/config/ai");if(!a.ok)throw new Error("Failed to fetch config");return a.json()}async function F(a,i){const r=new URLSearchParams;a&&r.set("api_key",a),i&&r.set("base_url",i);const o=await fetch(`/api/ai/models?${r.toString()}`);return o.ok?(await o.json()).data||[]:[]}async function q(a){if(!(await fetch("/api/config/ai",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)})).ok)throw new Error("Failed to save config")}async function K(a){const i=await fetch("/api/ai/test",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)}),r=await i.json().catch(()=>({}));if(!i.ok)throw new Error(r.error||"Test failed");return r}function U(){const a=v(),i=w(),{data:r,isLoading:o}=p({queryKey:["ai-config"],queryFn:I}),[t,n]=m.useState({api_key:"",base_url:"",model:""}),[u,f]=m.useState(!1),[d,h]=m.useState(null);m.useEffect(()=>{r&&n(r)},[r]);const{data:l,refetch:b,isFetching:g}=p({queryKey:["ai-models",t.api_key,t.base_url],queryFn:()=>F(t.api_key,t.base_url),enabled:!!t.api_key&&!!t.base_url}),x=y({mutationFn:q,onSuccess:()=>{i.success("AI 配置已保存"),a.invalidateQueries({queryKey:["ai-config"]})},onError:s=>i.error(`保存失败: ${s.message}`)}),c=y({mutationFn:K,onSuccess:s=>{const j=(s==null?void 0:s.model)||t.model;h({ok:!0,message:`连接成功!模型: ${j}`}),i.success("API 连接测试通过")},onError:s=>{h({ok:!1,message:s.message}),i.error("API 连接测试失败")}});return o?e.jsx("div",{className:"bg-white rounded-lg shadow p-6",children:"加载中..."}):e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-gray-900 mb-6",children:"AI 配置"}),e.jsxs("div",{className:"bg-white rounded-lg shadow p-6 max-w-2xl",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-6",children:[e.jsx(N,{className:"h-5 w-5 text-indigo-600"}),e.jsx("h3",{className:"text-lg font-semibold text-gray-900",children:"Anthropic API 配置"})]}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 mb-1",children:"API Key"}),e.jsxs("div",{className:"relative",children:[e.jsx("input",{type:u?"text":"password",value:t.api_key||"",onChange:s=>n({...t,api_key:s.target.value}),placeholder:"sk-...",className:"w-full px-3 py-2 pr-10 border border-gray-300 rounded-md text-sm font-mono"}),e.jsx("button",{type:"button",onClick:()=>f(!u),className:"absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600",children:u?e.jsx(k,{className:"h-4 w-4"}):e.jsx(_,{className:"h-4 w-4"})})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 mb-1",children:"Base URL"}),e.jsx("input",{type:"text",value:t.base_url||"",onChange:s=>n({...t,base_url:s.target.value}),placeholder:"https://api.anthropic.com",className:"w-full px-3 py-2 border border-gray-300 rounded-md text-sm"})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-1",children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700",children:"主模型 (Distill / QualityGate)"}),e.jsx("button",{type:"button",onClick:()=>b(),disabled:!t.api_key||!t.base_url||g,className:"text-xs text-indigo-600 hover:text-indigo-700 disabled:text-gray-400",children:g?"加载中...":"🔄 刷新模型列表"})]}),l&&l.length>0?e.jsxs("select",{value:t.model||"",onChange:s=>n({...t,model:s.target.value}),className:"w-full px-3 py-2 border border-gray-300 rounded-md text-sm bg-white",children:[e.jsx("option",{value:"",children:"-- 选择模型 --"}),l.map(s=>e.jsxs("option",{value:s.id,children:[s.id," ",s.owned_by&&`(${s.owned_by})`]},s.id))]}):e.jsx("input",{type:"text",value:t.model||"",onChange:s=>n({...t,model:s.target.value}),placeholder:"claude-sonnet-4-6",className:"w-full px-3 py-2 border border-gray-300 rounded-md text-sm"}),e.jsx("p",{className:"text-xs text-gray-500 mt-1",children:l&&l.length>0?`发现 ${l.length} 个可用模型`:"填入 API Key 和 Base URL 后可自动发现模型"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 mb-1",children:"分类器模型(可选,便宜+快的模型)"}),l&&l.length>0?e.jsxs("select",{value:t.classifier_model||"",onChange:s=>n({...t,classifier_model:s.target.value}),className:"w-full px-3 py-2 border border-gray-300 rounded-md text-sm bg-white",children:[e.jsx("option",{value:"",children:"-- 不指定 (使用主模型) --"}),l.map(s=>e.jsx("option",{value:s.id,children:s.id},s.id))]}):e.jsx("input",{type:"text",value:t.classifier_model||"",onChange:s=>n({...t,classifier_model:s.target.value}),placeholder:"claude-haiku-4-5-20251001",className:"w-full px-3 py-2 border border-gray-300 rounded-md text-sm"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 mb-1",children:"分类器超时 (ms)"}),e.jsx("input",{type:"number",value:t.classifier_timeout||1e4,onChange:s=>n({...t,classifier_timeout:parseInt(s.target.value)}),className:"w-full px-3 py-2 border border-gray-300 rounded-md text-sm"})]}),d&&e.jsxs("div",{className:`flex items-start gap-2 p-3 rounded text-sm ${d.ok?"bg-green-50 text-green-800":"bg-red-50 text-red-800"}`,children:[d.ok?e.jsx(C,{className:"h-4 w-4 flex-shrink-0 mt-0.5"}):e.jsx(P,{className:"h-4 w-4 flex-shrink-0 mt-0.5"}),e.jsx("div",{className:"flex-1 break-all",children:d.message})]}),e.jsx("div",{className:"flex items-center justify-end pt-4 border-t",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsxs("button",{onClick:()=>c.mutate({api_key:t.api_key,base_url:t.base_url,model:t.model}),disabled:c.isPending||!t.api_key||!t.model,className:"inline-flex items-center gap-2 px-4 py-2 bg-gray-100 text-gray-700 text-sm font-medium rounded-md hover:bg-gray-200 disabled:bg-gray-50 disabled:text-gray-400",children:[c.isPending?e.jsx(S,{className:"h-4 w-4 animate-spin"}):e.jsx(E,{className:"h-4 w-4"}),c.isPending?"测试中...":"测试连接"]}),e.jsxs("button",{onClick:()=>x.mutate(t),disabled:x.isPending,className:"inline-flex items-center gap-2 px-4 py-2 bg-indigo-600 text-white text-sm font-medium rounded-md hover:bg-indigo-700 disabled:bg-gray-400",children:[e.jsx(A,{className:"h-4 w-4"}),x.isPending?"保存中...":"保存配置"]})]})})]})]})]})}export{U as default};
2
- //# sourceMappingURL=AIConfig-D-vrYoJ3.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AIConfig-D-vrYoJ3.js","sources":["../../src/pages/AIConfig.tsx"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport { useState, useEffect } from 'react'\nimport { Save, Eye, EyeOff, Cpu, Zap, CheckCircle, XCircle, Loader2 } from 'lucide-react'\nimport { useToast } from '../components/Toast'\n\ninterface AIConfig {\n api_key: string\n base_url: string\n model: string\n provider?: string\n classifier_model?: string\n classifier_timeout?: number\n}\n\ninterface ModelOption {\n id: string\n owned_by?: string\n}\n\nasync function fetchConfig(): Promise<AIConfig> {\n const res = await fetch('/api/config/ai')\n if (!res.ok) throw new Error('Failed to fetch config')\n return res.json()\n}\n\nasync function fetchModels(api_key?: string, base_url?: string): Promise<ModelOption[]> {\n const params = new URLSearchParams()\n if (api_key) params.set('api_key', api_key)\n if (base_url) params.set('base_url', base_url)\n const res = await fetch(`/api/ai/models?${params.toString()}`)\n if (!res.ok) return []\n const data = await res.json()\n return data.data || []\n}\n\nasync function saveConfig(config: AIConfig): Promise<void> {\n const res = await fetch('/api/config/ai', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(config),\n })\n if (!res.ok) throw new Error('Failed to save config')\n}\n\nasync function testConnection(config: { api_key: string; base_url: string; model: string }): Promise<any> {\n const res = await fetch('/api/ai/test', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(config),\n })\n const data = await res.json().catch(() => ({}))\n if (!res.ok) throw new Error(data.error || 'Test failed')\n return data\n}\n\nexport default function AIConfig() {\n const queryClient = useQueryClient()\n const toast = useToast()\n const { data: config, isLoading } = useQuery({\n queryKey: ['ai-config'],\n queryFn: fetchConfig,\n })\n\n const [form, setForm] = useState<AIConfig>({\n api_key: '',\n base_url: '',\n model: '',\n })\n const [showKey, setShowKey] = useState(false)\n const [testResult, setTestResult] = useState<{ ok: boolean; message: string } | null>(null)\n\n useEffect(() => {\n if (config) setForm(config)\n }, [config])\n\n const { data: models, refetch: refetchModels, isFetching: loadingModels } = useQuery({\n queryKey: ['ai-models', form.api_key, form.base_url],\n queryFn: () => fetchModels(form.api_key, form.base_url),\n enabled: !!form.api_key && !!form.base_url,\n })\n\n const saveMutation = useMutation({\n mutationFn: saveConfig,\n onSuccess: () => {\n toast.success('AI 配置已保存')\n queryClient.invalidateQueries({ queryKey: ['ai-config'] })\n },\n onError: (e: Error) => toast.error(`保存失败: ${e.message}`),\n })\n\n const testMutation = useMutation({\n mutationFn: testConnection,\n onSuccess: (data) => {\n const modelName = data?.model || form.model\n setTestResult({ ok: true, message: `连接成功!模型: ${modelName}` })\n toast.success('API 连接测试通过')\n },\n onError: (err: Error) => {\n setTestResult({ ok: false, message: err.message })\n toast.error('API 连接测试失败')\n },\n })\n\n if (isLoading) {\n return <div className=\"bg-white rounded-lg shadow p-6\">加载中...</div>\n }\n\n return (\n <div>\n <h1 className=\"text-2xl font-bold text-gray-900 mb-6\">AI 配置</h1>\n\n <div className=\"bg-white rounded-lg shadow p-6 max-w-2xl\">\n <div className=\"flex items-center gap-2 mb-6\">\n <Cpu className=\"h-5 w-5 text-indigo-600\" />\n <h3 className=\"text-lg font-semibold text-gray-900\">Anthropic API 配置</h3>\n </div>\n\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">API Key</label>\n <div className=\"relative\">\n <input\n type={showKey ? 'text' : 'password'}\n value={form.api_key || ''}\n onChange={(e) => setForm({ ...form, api_key: e.target.value })}\n placeholder=\"sk-...\"\n className=\"w-full px-3 py-2 pr-10 border border-gray-300 rounded-md text-sm font-mono\"\n />\n <button\n type=\"button\"\n onClick={() => setShowKey(!showKey)}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600\"\n >\n {showKey ? <EyeOff className=\"h-4 w-4\" /> : <Eye className=\"h-4 w-4\" />}\n </button>\n </div>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">Base URL</label>\n <input\n type=\"text\"\n value={form.base_url || ''}\n onChange={(e) => setForm({ ...form, base_url: e.target.value })}\n placeholder=\"https://api.anthropic.com\"\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm\"\n />\n </div>\n\n <div>\n <div className=\"flex items-center justify-between mb-1\">\n <label className=\"block text-sm font-medium text-gray-700\">主模型 (Distill / QualityGate)</label>\n <button\n type=\"button\"\n onClick={() => refetchModels()}\n disabled={!form.api_key || !form.base_url || loadingModels}\n className=\"text-xs text-indigo-600 hover:text-indigo-700 disabled:text-gray-400\"\n >\n {loadingModels ? '加载中...' : '🔄 刷新模型列表'}\n </button>\n </div>\n {models && models.length > 0 ? (\n <select\n value={form.model || ''}\n onChange={(e) => setForm({ ...form, model: e.target.value })}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm bg-white\"\n >\n <option value=\"\">-- 选择模型 --</option>\n {models.map((m) => (\n <option key={m.id} value={m.id}>\n {m.id} {m.owned_by && `(${m.owned_by})`}\n </option>\n ))}\n </select>\n ) : (\n <input\n type=\"text\"\n value={form.model || ''}\n onChange={(e) => setForm({ ...form, model: e.target.value })}\n placeholder=\"claude-sonnet-4-6\"\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm\"\n />\n )}\n <p className=\"text-xs text-gray-500 mt-1\">\n {models && models.length > 0\n ? `发现 ${models.length} 个可用模型`\n : '填入 API Key 和 Base URL 后可自动发现模型'}\n </p>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">分类器模型(可选,便宜+快的模型)</label>\n {models && models.length > 0 ? (\n <select\n value={form.classifier_model || ''}\n onChange={(e) => setForm({ ...form, classifier_model: e.target.value })}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm bg-white\"\n >\n <option value=\"\">-- 不指定 (使用主模型) --</option>\n {models.map((m) => (\n <option key={m.id} value={m.id}>{m.id}</option>\n ))}\n </select>\n ) : (\n <input\n type=\"text\"\n value={form.classifier_model || ''}\n onChange={(e) => setForm({ ...form, classifier_model: e.target.value })}\n placeholder=\"claude-haiku-4-5-20251001\"\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm\"\n />\n )}\n </div>\n\n <div>\n <label className=\"block text-sm font-medium text-gray-700 mb-1\">分类器超时 (ms)</label>\n <input\n type=\"number\"\n value={form.classifier_timeout || 10000}\n onChange={(e) => setForm({ ...form, classifier_timeout: parseInt(e.target.value) })}\n className=\"w-full px-3 py-2 border border-gray-300 rounded-md text-sm\"\n />\n </div>\n\n {/* Test result */}\n {testResult && (\n <div className={`flex items-start gap-2 p-3 rounded text-sm ${\n testResult.ok ? 'bg-green-50 text-green-800' : 'bg-red-50 text-red-800'\n }`}>\n {testResult.ok ? (\n <CheckCircle className=\"h-4 w-4 flex-shrink-0 mt-0.5\" />\n ) : (\n <XCircle className=\"h-4 w-4 flex-shrink-0 mt-0.5\" />\n )}\n <div className=\"flex-1 break-all\">{testResult.message}</div>\n </div>\n )}\n\n <div className=\"flex items-center justify-end pt-4 border-t\">\n <div className=\"flex items-center gap-2\">\n <button\n onClick={() => testMutation.mutate({ api_key: form.api_key, base_url: form.base_url, model: form.model })}\n disabled={testMutation.isPending || !form.api_key || !form.model}\n className=\"inline-flex items-center gap-2 px-4 py-2 bg-gray-100 text-gray-700 text-sm font-medium rounded-md hover:bg-gray-200 disabled:bg-gray-50 disabled:text-gray-400\"\n >\n {testMutation.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Zap className=\"h-4 w-4\" />\n )}\n {testMutation.isPending ? '测试中...' : '测试连接'}\n </button>\n <button\n onClick={() => saveMutation.mutate(form)}\n disabled={saveMutation.isPending}\n className=\"inline-flex items-center gap-2 px-4 py-2 bg-indigo-600 text-white text-sm font-medium rounded-md hover:bg-indigo-700 disabled:bg-gray-400\"\n >\n <Save className=\"h-4 w-4\" />\n {saveMutation.isPending ? '保存中...' : '保存配置'}\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n )\n}\n"],"names":["fetchConfig","res","fetchModels","api_key","base_url","params","saveConfig","config","testConnection","data","AIConfig","queryClient","useQueryClient","toast","useToast","isLoading","useQuery","form","setForm","useState","showKey","setShowKey","testResult","setTestResult","useEffect","models","refetchModels","loadingModels","saveMutation","useMutation","e","testMutation","modelName","err","jsx","jsxs","Cpu","EyeOff","Eye","m","CheckCircle","XCircle","Loader2","Zap","Save"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{r as d,j as e}from"./react-vendor-CSp-GLFF.js";import{b as v,u as p,c as N}from"./query-C99w429o.js";import{D as w}from"./Drawer-DeKukfwJ.js";import{M as b}from"./MarkdownRenderer-CCIz1MOz.js";import{u as A}from"./index-D23sAOAt.js";import{B as j,t as C,u as k,X as E,v as F}from"./lucide-DjB4fWNj.js";import"./vendor-CMMjVdZs.js";import"./syntax-highlighter-44FakypI.js";import"./react-router-I-HqunH7.js";async function q(){const n=await fetch("/api/agents");if(!n.ok)throw new Error("Failed to fetch agents");const a=await n.json();return Array.isArray(a)?a:[...a.official||[],...a.user||[]]}async function S(n){const a=await fetch(`/api/agents/${n}`);if(!a.ok)throw new Error("Failed to fetch");return a.json()}async function K(n,a){if(!(await fetch(`/api/agents/${n}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:a})})).ok)throw new Error("Failed to save")}function L(){const n=v(),a=A(),{data:r,isLoading:y}=p({queryKey:["agents"],queryFn:q}),[l,m]=d.useState(null),[g,c]=d.useState(!1),[h,x]=d.useState(""),{data:t}=p({queryKey:["agent-detail",l],queryFn:()=>S(l),enabled:!!l});d.useEffect(()=>{t!=null&&t.content&&x(t.content),c(!1)},[t]);const o=N({mutationFn:s=>K(s.name,s.content),onSuccess:()=>{a.success("Agent 已保存"),c(!1),n.invalidateQueries({queryKey:["agent-detail",l]}),n.invalidateQueries({queryKey:["agents"]})},onError:s=>a.error(`保存失败: ${s.message}`)}),u=s=>s?typeof s=="string"?s.split(",").map(i=>i.trim()):s:[];return y?e.jsx("div",{className:"bg-white rounded-lg shadow p-6",children:"加载中..."}):e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-6",children:[e.jsx("h1",{className:"text-2xl font-bold text-gray-900",children:"Agent 管理"}),e.jsxs("div",{className:"text-sm text-gray-500",children:["共 ",(r==null?void 0:r.length)||0," 个 Agent"]})]}),e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:r==null?void 0:r.map(s=>{const i=u(s.tools);return e.jsxs("div",{className:"bg-white rounded-lg shadow p-5 hover:shadow-md transition-shadow cursor-pointer",onClick:()=>m(s.name),children:[e.jsxs("div",{className:"flex items-start gap-3 mb-3",children:[e.jsx("div",{className:"w-10 h-10 rounded-lg bg-indigo-100 flex items-center justify-center flex-shrink-0",children:e.jsx(j,{className:"h-5 w-5 text-indigo-600"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h3",{className:"font-semibold text-gray-900 truncate",children:s.name}),e.jsx("p",{className:"text-xs text-gray-500 mt-1 line-clamp-2",children:s.description||"(无描述)"})]})]}),i.length>0&&e.jsxs("div",{className:"mt-3 pt-3 border-t border-gray-100",children:[e.jsxs("div",{className:"flex items-center gap-1 text-xs text-gray-500 mb-2",children:[e.jsx(C,{className:"h-3 w-3"}),"可用工具 (",i.length,")"]}),e.jsxs("div",{className:"flex flex-wrap gap-1",children:[i.slice(0,5).map(f=>e.jsx("span",{className:"px-2 py-0.5 text-xs bg-gray-100 text-gray-700 rounded",children:f},f)),i.length>5&&e.jsxs("span",{className:"text-xs text-gray-400",children:["+",i.length-5]})]})]})]},s.name)})}),e.jsx(w,{open:l!==null,onClose:()=>{m(null),c(!1)},title:`Agent: ${l}`,width:"w-[800px]",children:t&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(j,{className:"h-5 w-5 text-indigo-600"}),e.jsx("h3",{className:"text-lg font-semibold text-gray-900",children:t.name}),t.version&&e.jsxs("span",{className:"text-xs text-gray-500",children:["v",t.version]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"描述"}),e.jsx("div",{className:"text-sm text-gray-800",children:t.description})]}),t.tools&&e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"可用工具"}),e.jsx("div",{className:"flex flex-wrap gap-1",children:u(t.tools).map(s=>e.jsx("span",{className:"px-2 py-0.5 text-xs bg-gray-100 text-gray-700 rounded",children:s},s))})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("div",{className:"text-xs text-gray-500",children:"完整内容 (Markdown)"}),e.jsx("div",{className:"flex items-center gap-2",children:g?e.jsxs(e.Fragment,{children:[e.jsxs("button",{onClick:()=>{c(!1),x(t.content||"")},className:"inline-flex items-center gap-1 text-xs text-gray-600 hover:text-gray-700",children:[e.jsx(E,{className:"h-3 w-3"}),"取消"]}),e.jsxs("button",{onClick:()=>o.mutate({name:t.name,content:h}),disabled:o.isPending,className:"inline-flex items-center gap-1 text-xs bg-indigo-600 text-white px-2 py-1 rounded hover:bg-indigo-700 disabled:bg-gray-400",children:[e.jsx(F,{className:"h-3 w-3"}),o.isPending?"保存中...":"保存"]})]}):e.jsxs("button",{onClick:()=>c(!0),className:"inline-flex items-center gap-1 text-xs text-indigo-600 hover:text-indigo-700",children:[e.jsx(k,{className:"h-3 w-3"}),"编辑"]})})]}),g?e.jsx("textarea",{value:h,onChange:s=>x(s.target.value),className:"w-full font-mono text-xs bg-gray-50 rounded p-3 border border-gray-300 focus:border-indigo-500 focus:outline-none",rows:20}):e.jsx("div",{className:"bg-white rounded p-3 border border-gray-200 max-h-[500px] overflow-y-auto",children:e.jsx(b,{content:t.content||""})}),o.isError&&e.jsxs("div",{className:"text-xs text-red-600 mt-1",children:["保存失败:",o.error.message]})]})]})})]})}export{L as default};
2
- //# sourceMappingURL=Agents-DAGWYsJj.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Agents-DAGWYsJj.js","sources":["../../src/pages/Agents.tsx"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport { useState, useEffect } from 'react'\nimport { Bot, FileCode, Edit2, Save, X } from 'lucide-react'\nimport Drawer from '../components/Drawer'\nimport MarkdownRenderer from '../components/MarkdownRenderer'\nimport { useToast } from '../components/Toast'\n\ninterface Agent {\n name: string\n description: string\n tools?: string | string[]\n content?: string\n version?: string\n category?: string\n source?: string\n}\n\ninterface AgentsResponse {\n official?: Agent[]\n user?: Agent[]\n}\n\nasync function fetchAgents(): Promise<Agent[]> {\n const res = await fetch('/api/agents')\n if (!res.ok) throw new Error('Failed to fetch agents')\n const data: AgentsResponse | Agent[] = await res.json()\n // API 可能返回 { official: [...], user: [...] } 或直接返回数组\n if (Array.isArray(data)) return data\n return [...(data.official || []), ...(data.user || [])]\n}\n\nasync function fetchAgentDetail(name: string): Promise<Agent> {\n const res = await fetch(`/api/agents/${name}`)\n if (!res.ok) throw new Error('Failed to fetch')\n return res.json()\n}\n\nasync function saveAgent(name: string, content: string): Promise<void> {\n const res = await fetch(`/api/agents/${name}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ content }),\n })\n if (!res.ok) throw new Error('Failed to save')\n}\n\nexport default function Agents() {\n const queryClient = useQueryClient()\n const toast = useToast()\n const { data: agents, isLoading } = useQuery({\n queryKey: ['agents'],\n queryFn: fetchAgents,\n })\n\n const [selectedAgent, setSelectedAgent] = useState<string | null>(null)\n const [editing, setEditing] = useState(false)\n const [editContent, setEditContent] = useState('')\n\n const { data: detail } = useQuery({\n queryKey: ['agent-detail', selectedAgent],\n queryFn: () => fetchAgentDetail(selectedAgent!),\n enabled: !!selectedAgent,\n })\n\n useEffect(() => {\n if (detail?.content) setEditContent(detail.content)\n setEditing(false)\n }, [detail])\n\n const mutation = useMutation({\n mutationFn: (vars: { name: string; content: string }) => saveAgent(vars.name, vars.content),\n onSuccess: () => {\n toast.success('Agent 已保存')\n setEditing(false)\n queryClient.invalidateQueries({ queryKey: ['agent-detail', selectedAgent] })\n queryClient.invalidateQueries({ queryKey: ['agents'] })\n },\n onError: (e: Error) => toast.error(`保存失败: ${e.message}`),\n })\n\n const renderTools = (tools?: string | string[]) => {\n if (!tools) return []\n if (typeof tools === 'string') return tools.split(',').map(t => t.trim())\n return tools\n }\n\n if (isLoading) {\n return <div className=\"bg-white rounded-lg shadow p-6\">加载中...</div>\n }\n\n return (\n <div>\n <div className=\"flex items-center justify-between mb-6\">\n <h1 className=\"text-2xl font-bold text-gray-900\">Agent 管理</h1>\n <div className=\"text-sm text-gray-500\">共 {agents?.length || 0} 个 Agent</div>\n </div>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {agents?.map((agent) => {\n const tools = renderTools(agent.tools)\n return (\n <div\n key={agent.name}\n className=\"bg-white rounded-lg shadow p-5 hover:shadow-md transition-shadow cursor-pointer\"\n onClick={() => setSelectedAgent(agent.name)}\n >\n <div className=\"flex items-start gap-3 mb-3\">\n <div className=\"w-10 h-10 rounded-lg bg-indigo-100 flex items-center justify-center flex-shrink-0\">\n <Bot className=\"h-5 w-5 text-indigo-600\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"font-semibold text-gray-900 truncate\">{agent.name}</h3>\n <p className=\"text-xs text-gray-500 mt-1 line-clamp-2\">\n {agent.description || '(无描述)'}\n </p>\n </div>\n </div>\n\n {tools.length > 0 && (\n <div className=\"mt-3 pt-3 border-t border-gray-100\">\n <div className=\"flex items-center gap-1 text-xs text-gray-500 mb-2\">\n <FileCode className=\"h-3 w-3\" />可用工具 ({tools.length})\n </div>\n <div className=\"flex flex-wrap gap-1\">\n {tools.slice(0, 5).map((tool) => (\n <span key={tool} className=\"px-2 py-0.5 text-xs bg-gray-100 text-gray-700 rounded\">\n {tool}\n </span>\n ))}\n {tools.length > 5 && (\n <span className=\"text-xs text-gray-400\">+{tools.length - 5}</span>\n )}\n </div>\n </div>\n )}\n </div>\n )\n })}\n </div>\n\n {/* Agent Detail Drawer */}\n <Drawer\n open={selectedAgent !== null}\n onClose={() => { setSelectedAgent(null); setEditing(false) }}\n title={`Agent: ${selectedAgent}`}\n width=\"w-[800px]\"\n >\n {detail && (\n <div className=\"space-y-4\">\n <div className=\"flex items-center gap-2 mb-2\">\n <Bot className=\"h-5 w-5 text-indigo-600\" />\n <h3 className=\"text-lg font-semibold text-gray-900\">{detail.name}</h3>\n {detail.version && (\n <span className=\"text-xs text-gray-500\">v{detail.version}</span>\n )}\n </div>\n\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">描述</div>\n <div className=\"text-sm text-gray-800\">{detail.description}</div>\n </div>\n\n {detail.tools && (\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">可用工具</div>\n <div className=\"flex flex-wrap gap-1\">\n {renderTools(detail.tools).map(tool => (\n <span key={tool} className=\"px-2 py-0.5 text-xs bg-gray-100 text-gray-700 rounded\">\n {tool}\n </span>\n ))}\n </div>\n </div>\n )}\n\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <div className=\"text-xs text-gray-500\">完整内容 (Markdown)</div>\n <div className=\"flex items-center gap-2\">\n {!editing ? (\n <button\n onClick={() => setEditing(true)}\n className=\"inline-flex items-center gap-1 text-xs text-indigo-600 hover:text-indigo-700\"\n >\n <Edit2 className=\"h-3 w-3\" />编辑\n </button>\n ) : (\n <>\n <button\n onClick={() => { setEditing(false); setEditContent(detail.content || '') }}\n className=\"inline-flex items-center gap-1 text-xs text-gray-600 hover:text-gray-700\"\n >\n <X className=\"h-3 w-3\" />取消\n </button>\n <button\n onClick={() => mutation.mutate({ name: detail.name, content: editContent })}\n disabled={mutation.isPending}\n className=\"inline-flex items-center gap-1 text-xs bg-indigo-600 text-white px-2 py-1 rounded hover:bg-indigo-700 disabled:bg-gray-400\"\n >\n <Save className=\"h-3 w-3\" />\n {mutation.isPending ? '保存中...' : '保存'}\n </button>\n </>\n )}\n </div>\n </div>\n {editing ? (\n <textarea\n value={editContent}\n onChange={(e) => setEditContent(e.target.value)}\n className=\"w-full font-mono text-xs bg-gray-50 rounded p-3 border border-gray-300 focus:border-indigo-500 focus:outline-none\"\n rows={20}\n />\n ) : (\n <div className=\"bg-white rounded p-3 border border-gray-200 max-h-[500px] overflow-y-auto\">\n <MarkdownRenderer content={detail.content || ''} />\n </div>\n )}\n {mutation.isError && (\n <div className=\"text-xs text-red-600 mt-1\">保存失败:{(mutation.error as Error).message}</div>\n )}\n </div>\n </div>\n )}\n </Drawer>\n </div>\n )\n}\n"],"names":["fetchAgents","res","data","fetchAgentDetail","name","saveAgent","content","Agents","queryClient","useQueryClient","toast","useToast","agents","isLoading","useQuery","selectedAgent","setSelectedAgent","useState","editing","setEditing","editContent","setEditContent","detail","useEffect","mutation","useMutation","vars","e","renderTools","tools","t","jsx","jsxs","agent","Bot","FileCode","tool","Drawer","Fragment","X","Save","Edit2","MarkdownRenderer"],"mappings":"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"}
@@ -1,5 +0,0 @@
1
- import{r as b,j as e}from"./react-vendor-CSp-GLFF.js";import{b as P,u as C,c as E}from"./query-C99w429o.js";import{b as q,L as M}from"./react-router-I-HqunH7.js";import{d as p}from"./vendor-CMMjVdZs.js";import{u as $,a as D}from"./index-D23sAOAt.js";import{P as K,G as I,C as _,n as T,g as F,c as Q,e as O,d as R,o as H,p as B,f as S}from"./lucide-DjB4fWNj.js";import{a as L,z as U}from"./date-fns-CZ_bHujz.js";import"./syntax-highlighter-44FakypI.js";async function X(){const t=await fetch("/api/methodology-executions?limit=50");if(!t.ok)throw new Error("Failed to fetch");return t.json()}async function z(){const t=await fetch("/api/methodologies");if(!t.ok)throw new Error("Failed to fetch methodologies");return t.json()}async function G(){const t=await fetch("/api/worker-auth-status");if(!t.ok)throw new Error("Failed to fetch worker auth status");return t.json()}async function J(t){const a=await fetch(`/api/methodology-executions/${t}/cancel`,{method:"POST"});if(!a.ok){const l=await a.json().catch(()=>({}));throw new Error(l.error||"Cancel failed")}}async function Y(t){if(!(await fetch(`/api/methodology-executions/${t}`,{method:"DELETE"})).ok)throw new Error("Delete failed")}async function W(t){const a=await fetch("/api/methodology-executions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!a.ok){const l=await a.json().catch(()=>({})),i=new Error(l.error||`Start failed (HTTP ${a.status})`);throw typeof l.code=="string"&&(i.code=l.code),i}return a.json()}const V={"harness-engineering":"Harness Engineering",bmad:"BMad (敏捷开发)"};function ie(){const t=P(),a=$(),l=D(),i=q(),[j,d]=b.useState(!1),{data:r,isLoading:g,error:f}=C({queryKey:["methodology-executions"],queryFn:X,refetchInterval:5e3}),{data:c}=C({queryKey:["methodologies"],queryFn:z}),{data:N}=C({queryKey:["worker-auth-status"],queryFn:G,staleTime:3e4}),m=E({mutationFn:J,onSuccess:()=>{a.success("方法论执行已取消"),t.invalidateQueries({queryKey:["methodology-executions"]})},onError:s=>a.error(`取消失败: ${s.message}`)}),y=E({mutationFn:Y,onSuccess:()=>{a.success("记录已删除"),t.invalidateQueries({queryKey:["methodology-executions"]})},onError:s=>a.error(`删除失败: ${s.message}`)}),x=E({mutationFn:W,onSuccess:s=>{a.success(`已启动执行 #${s.id}`),d(!1),t.invalidateQueries({queryKey:["methodology-executions"]}),t.invalidateQueries({queryKey:["worker-auth-status"]})},onError:async s=>{const o=s.message||"";if(s.code==="AUTH_REQUIRED"||o.includes("Background mode requires")||o.includes("AUTH_REQUIRED")){t.invalidateQueries({queryKey:["worker-auth-status"]}),await l({title:"需要配置 Claude API",message:`后台模式需要 Claude API 认证(ANTHROPIC_API_KEY 或 OAuth)。
2
- 请先在 AI 配置页设置后再启动执行。
3
-
4
- 详细信息:${o}`,confirmText:"去 AI 配置",cancelText:"留在此页",variant:"warning"})&&(d(!1),i("/ai-config"));return}a.error(`启动失败: ${o}`)}}),h=async s=>{await l({title:"取消方法论执行",message:"确定要取消这个运行中的方法论吗?已完成的阶段不会受影响,但当前进行中的阶段将停止。",confirmText:"确认取消",variant:"warning"})&&m.mutate(s)},w=async s=>{await l({title:"删除执行记录",message:"确定要删除这条方法论执行记录吗?此操作不可恢复。",confirmText:"删除",variant:"danger"})&&y.mutate(s)};if(g)return e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-gray-900 mb-6",children:"方法论执行"}),e.jsx("div",{className:"bg-white rounded-lg shadow p-6",children:e.jsx("p",{className:"text-gray-600",children:"加载中..."})})]});if(f)return e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-gray-900 mb-6",children:"方法论执行"}),e.jsx("div",{className:"bg-white rounded-lg shadow p-6",children:e.jsxs("p",{className:"text-red-600",children:["加载失败: ",f.message]})})]});const u=(r==null?void 0:r.filter(s=>s.status==="running").length)||0,n=(r==null?void 0:r.filter(s=>s.status==="completed").length)||0;return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-6",children:[e.jsx("h1",{className:"text-2xl font-bold text-gray-900",children:"方法论执行"}),e.jsxs("div",{className:"flex items-center gap-4 text-sm",children:[e.jsxs("span",{className:"text-gray-500",children:["共 ",(r==null?void 0:r.length)||0," 个实例"]}),u>0&&e.jsxs("span",{className:"text-blue-600",children:["· 运行中 ",u]}),n>0&&e.jsxs("span",{className:"text-green-600",children:["· 已完成 ",n]}),e.jsxs("button",{onClick:()=>d(!0),className:"ml-3 inline-flex items-center gap-1 px-3 py-1.5 text-sm bg-indigo-600 text-white rounded-md hover:bg-indigo-700",children:[e.jsx(K,{className:"h-4 w-4"})," 新建执行"]})]})]}),j&&e.jsx(Z,{methodologies:c??[],authStatus:N??null,onCancel:()=>d(!1),onSubmit:s=>x.mutate(s),onGoToAIConfig:()=>{d(!1),i("/ai-config")},submitting:x.isPending}),e.jsxs("div",{className:"space-y-4",children:[r==null?void 0:r.map(s=>{const o=JSON.parse(s.plan_json),v=o.phases[s.current_phase_index],A=s.status==="completed"?100:Math.round(s.current_phase_index/o.phases.length*100);return e.jsx("div",{className:"bg-white rounded-lg shadow",children:e.jsxs("div",{className:"p-6 flex items-start justify-between gap-4",children:[e.jsxs(M,{to:`/methodologies/${s.id}`,className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-3 mb-2",children:[e.jsx(I,{className:"h-5 w-5 text-indigo-600 flex-shrink-0"}),e.jsx("h3",{className:"text-lg font-semibold text-gray-900",children:V[s.methodology_id]||s.methodology_id}),e.jsxs("span",{className:p("px-2 py-1 text-xs font-medium rounded-full",s.status==="running"&&"bg-blue-100 text-blue-700",s.status==="completed"&&"bg-green-100 text-green-700",s.status==="failed"&&"bg-red-100 text-red-700",s.status==="cancelled"&&"bg-gray-100 text-gray-600"),children:[s.status==="running"&&"运行中",s.status==="completed"&&"已完成",s.status==="failed"&&"失败",s.status==="cancelled"&&"已取消"]}),s.mode&&e.jsxs("span",{className:p("inline-flex items-center gap-1 px-2 py-1 text-xs font-medium rounded-full",s.mode==="background"?"bg-purple-100 text-purple-700":"bg-sky-100 text-sky-700"),title:s.mode==="background"?"独立 claude -p 子进程":"主会话内执行",children:[s.mode==="background"?e.jsx(_,{className:"h-3 w-3"}):e.jsx(T,{className:"h-3 w-3"}),s.mode==="background"?"后台":"前台"]})]}),e.jsxs("p",{className:"text-sm text-gray-600 mb-3 font-mono",children:["Session: ",s.session_id.slice(0,12),"..."]}),e.jsx("div",{className:"w-full bg-gray-200 rounded-full h-1.5 mb-3",children:e.jsx("div",{className:p("h-1.5 rounded-full transition-all",s.status==="completed"?"bg-green-500":s.status==="cancelled"?"bg-gray-400":"bg-indigo-600"),style:{width:`${A}%`}})}),e.jsxs("div",{className:"flex items-center gap-4 text-sm text-gray-500",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(F,{className:"h-4 w-4"}),L(s.started_at,{addSuffix:!0,locale:U})]}),s.status==="running"&&v&&e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Q,{className:"h-4 w-4"}),"Phase ",s.current_phase_index+1,"/",o.phases.length,": ",v.id]}),s.status==="completed"&&e.jsxs("div",{className:"flex items-center gap-1 text-green-600",children:[e.jsx(O,{className:"h-4 w-4"}),"完成 ",o.phases.length," 个阶段"]}),s.status==="cancelled"&&e.jsxs("div",{className:"flex items-center gap-1 text-gray-500",children:[e.jsx(R,{className:"h-4 w-4"}),"已取消于 Phase ",s.current_phase_index+1]})]})]}),e.jsxs("div",{className:"flex items-center gap-1 flex-shrink-0",children:[s.status==="running"&&e.jsx("button",{onClick:k=>{k.preventDefault(),h(s.id)},className:"p-2 text-orange-600 hover:bg-orange-50 rounded-md",title:"取消执行",children:e.jsx(H,{className:"h-4 w-4"})}),s.status!=="running"&&e.jsx("button",{onClick:k=>{k.preventDefault(),w(s.id)},className:"p-2 text-gray-500 hover:bg-red-50 hover:text-red-600 rounded-md",title:"删除记录",children:e.jsx(B,{className:"h-4 w-4"})})]})]})},s.id)}),(!r||r.length===0)&&e.jsxs("div",{className:"bg-white rounded-lg shadow p-12 text-center",children:[e.jsx(I,{className:"h-12 w-12 text-gray-400 mx-auto mb-4"}),e.jsx("p",{className:"text-gray-600",children:"暂无方法论执行记录"}),e.jsx("p",{className:"text-xs text-gray-500 mt-2",children:'当你输入复杂任务(如"重构 XXX 模块")时,系统会自动匹配方法论并生成执行计划'})]})]})]})}function Z({methodologies:t,authStatus:a,submitting:l,onSubmit:i,onCancel:j,onGoToAIConfig:d}){var u;const r=`manual-${Date.now().toString(36)}`,[g,f]=b.useState(r),[c,N]=b.useState(((u=t[0])==null?void 0:u.id)??""),[m,y]=b.useState("background"),x=a!==null&&a.available===!1,h=x&&m==="background",w=n=>{n.preventDefault(),!(!g.trim()||!c)&&(h||i({session_id:g.trim(),methodology_id:c,mode:m}))};return e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",children:e.jsxs("form",{onSubmit:w,className:"w-full max-w-md bg-white rounded-lg shadow-xl border border-gray-200",children:[e.jsxs("div",{className:"px-5 py-4 border-b border-gray-100",children:[e.jsx("h2",{className:"text-lg font-semibold text-gray-900",children:"新建方法论执行"}),e.jsx("p",{className:"text-xs text-gray-500 mt-0.5",children:"选择方法论模板和执行模式"})]}),e.jsxs("div",{className:"px-5 py-4 space-y-4 text-sm",children:[e.jsxs("label",{className:"block",children:[e.jsx("span",{className:"text-gray-700",children:"方法论"}),e.jsxs("select",{className:"mt-1 w-full border border-gray-300 rounded-md px-2 py-1.5",value:c,onChange:n=>N(n.target.value),required:!0,children:[t.length===0&&e.jsx("option",{value:"",children:"(未发现方法论)"}),t.map(n=>e.jsx("option",{value:n.id,children:n.name||n.id},n.id))]})]}),e.jsxs("label",{className:"block",children:[e.jsx("span",{className:"text-gray-700",children:"Session ID"}),e.jsx("input",{type:"text",className:"mt-1 w-full border border-gray-300 rounded-md px-2 py-1.5 font-mono text-xs",value:g,onChange:n=>f(n.target.value),required:!0}),e.jsx("span",{className:"mt-1 block text-xs text-gray-500",children:"后台模式下用于追踪;建议保留默认或自定义一个可识别值"})]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-gray-700",children:"执行模式"}),e.jsxs("div",{className:"mt-2 grid grid-cols-2 gap-2",children:[e.jsxs("button",{type:"button",onClick:()=>y("background"),className:p("rounded-md border px-3 py-2 text-left",m==="background"?"border-indigo-500 bg-indigo-50":"border-gray-200 hover:border-gray-300",x&&"ring-1 ring-amber-200"),children:[e.jsxs("div",{className:"flex items-center gap-2 font-medium text-gray-900",children:[e.jsx(_,{className:"h-4 w-4 text-purple-600"})," 后台",x&&e.jsx("span",{className:"ml-auto text-[10px] font-normal text-amber-700 bg-amber-100 px-1.5 py-0.5 rounded",children:"需先配置 API"})]}),e.jsx("p",{className:"text-xs text-gray-500 mt-1",children:"独立 claude -p 子进程,无需用户在主会话输入"})]}),e.jsxs("button",{type:"button",onClick:()=>y("foreground"),className:p("rounded-md border px-3 py-2 text-left",m==="foreground"?"border-indigo-500 bg-indigo-50":"border-gray-200 hover:border-gray-300"),children:[e.jsxs("div",{className:"flex items-center gap-2 font-medium text-gray-900",children:[e.jsx(T,{className:"h-4 w-4 text-sky-600"})," 前台"]}),e.jsxs("p",{className:"text-xs text-amber-700 mt-1 flex items-start gap-1",children:[e.jsx(S,{className:"h-3.5 w-3.5 mt-0.5 shrink-0"}),e.jsxs("span",{children:["需要你在主会话里输入任意内容才会推进;期间可用 ",e.jsx("code",{className:"px-1 rounded bg-amber-50",children:"/forge methodology status"})," 查看"]})]})]})]})]}),h&&e.jsx("div",{className:"rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-xs text-amber-800",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(S,{className:"h-4 w-4 mt-0.5 shrink-0 text-amber-600"}),e.jsxs("div",{className:"flex-1 space-y-1",children:[e.jsx("div",{className:"font-medium",children:"后台模式需要 Claude API 认证"}),e.jsxs("div",{className:"text-amber-700",children:["未检测到 ",e.jsx("code",{className:"px-1 rounded bg-amber-100",children:"ANTHROPIC_API_KEY"})," 或 OAuth 凭据",a!=null&&a.message?`(${a.message})`:"","。 请先在 AI 配置页完成设置,或切换到前台模式。"]}),e.jsx("button",{type:"button",onClick:d,className:"mt-1 inline-flex items-center gap-1 px-2 py-1 text-xs font-medium text-white bg-amber-600 rounded hover:bg-amber-700",children:"去 AI 配置"})]})]})})]}),e.jsxs("div",{className:"px-5 py-3 border-t border-gray-100 flex justify-end gap-2",children:[e.jsx("button",{type:"button",onClick:j,className:"px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-100 rounded-md",children:"取消"}),e.jsx("button",{type:"submit",disabled:l||!c||h,title:h?"后台模式需要先配置 Claude API":void 0,className:"inline-flex items-center gap-1 px-3 py-1.5 text-sm bg-indigo-600 text-white rounded-md hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed",children:l?"启动中...":"启动"})]})]})})}export{ie as default};
5
- //# sourceMappingURL=Methodologies-C0-Keokj.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Methodologies-C0-Keokj.js","sources":["../../src/pages/Methodologies.tsx"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport { Link, useNavigate } from 'react-router-dom'\nimport { useState } from 'react'\nimport { formatDistanceToNow } from 'date-fns'\nimport { zhCN } from 'date-fns/locale'\nimport { GitBranch, Clock, CheckCircle, AlertCircle, XCircle, Trash2, StopCircle, Plus, Monitor, Cpu, AlertTriangle } from 'lucide-react'\nimport clsx from 'clsx'\nimport { useToast } from '../components/Toast'\nimport { useConfirm } from '../components/Confirm'\n\ninterface MethodologyExecution {\n id: number\n session_id: string\n methodology_id: string\n plan_json: string\n current_phase_index: number\n status: 'running' | 'completed' | 'failed' | 'cancelled'\n mode?: 'foreground' | 'background'\n worker_pid?: number | null\n worker_session_id?: string | null\n started_at: number\n completed_at: number | null\n}\n\ninterface MethodologyMeta {\n id: string\n name: string\n description?: string\n}\n\ninterface WorkerAuthStatus {\n available: boolean\n method: 'api-key-env' | 'oauth-token' | 'keychain' | 'unknown' | 'none'\n message: string\n}\n\nasync function fetchMethodologyExecutions(): Promise<MethodologyExecution[]> {\n const res = await fetch('/api/methodology-executions?limit=50')\n if (!res.ok) throw new Error('Failed to fetch')\n return res.json()\n}\n\nasync function fetchMethodologies(): Promise<MethodologyMeta[]> {\n const res = await fetch('/api/methodologies')\n if (!res.ok) throw new Error('Failed to fetch methodologies')\n return res.json()\n}\n\nasync function fetchWorkerAuthStatus(): Promise<WorkerAuthStatus> {\n const res = await fetch('/api/worker-auth-status')\n if (!res.ok) throw new Error('Failed to fetch worker auth status')\n return res.json()\n}\n\nasync function cancelExecution(id: number): Promise<void> {\n const res = await fetch(`/api/methodology-executions/${id}/cancel`, { method: 'POST' })\n if (!res.ok) {\n const data = await res.json().catch(() => ({}))\n throw new Error(data.error || 'Cancel failed')\n }\n}\n\nasync function deleteExecution(id: number): Promise<void> {\n const res = await fetch(`/api/methodology-executions/${id}`, { method: 'DELETE' })\n if (!res.ok) throw new Error('Delete failed')\n}\n\nasync function startExecution(payload: {\n session_id: string\n methodology_id: string\n mode: 'foreground' | 'background'\n}): Promise<{ id: number }> {\n const res = await fetch('/api/methodology-executions', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n })\n if (!res.ok) {\n const data = await res.json().catch(() => ({}))\n const err = new Error(data.error || `Start failed (HTTP ${res.status})`) as Error & { code?: string }\n if (typeof data.code === 'string') err.code = data.code\n throw err\n }\n return res.json()\n}\n\nconst methodologyNames: Record<string, string> = {\n 'harness-engineering': 'Harness Engineering',\n 'bmad': 'BMad (敏捷开发)',\n}\n\nexport default function Methodologies() {\n const queryClient = useQueryClient()\n const toast = useToast()\n const confirm = useConfirm()\n const navigate = useNavigate()\n const [showStart, setShowStart] = useState(false)\n\n const { data: executions, isLoading, error } = useQuery({\n queryKey: ['methodology-executions'],\n queryFn: fetchMethodologyExecutions,\n refetchInterval: 5000,\n })\n\n const { data: methodologies } = useQuery({\n queryKey: ['methodologies'],\n queryFn: fetchMethodologies,\n })\n\n const { data: authStatus } = useQuery({\n queryKey: ['worker-auth-status'],\n queryFn: fetchWorkerAuthStatus,\n // 只在打开 Modal 时或进入页面时查一次;后续可手动刷新\n staleTime: 30_000,\n })\n\n const cancelMutation = useMutation({\n mutationFn: cancelExecution,\n onSuccess: () => {\n toast.success('方法论执行已取消')\n queryClient.invalidateQueries({ queryKey: ['methodology-executions'] })\n },\n onError: (e: Error) => toast.error(`取消失败: ${e.message}`),\n })\n\n const deleteMutation = useMutation({\n mutationFn: deleteExecution,\n onSuccess: () => {\n toast.success('记录已删除')\n queryClient.invalidateQueries({ queryKey: ['methodology-executions'] })\n },\n onError: (e: Error) => toast.error(`删除失败: ${e.message}`),\n })\n\n const startMutation = useMutation({\n mutationFn: startExecution,\n onSuccess: (data) => {\n toast.success(`已启动执行 #${data.id}`)\n setShowStart(false)\n queryClient.invalidateQueries({ queryKey: ['methodology-executions'] })\n // 成功启动后顺手刷新 auth 状态(虽然理论上没变,但保持一致)\n queryClient.invalidateQueries({ queryKey: ['worker-auth-status'] })\n },\n onError: async (e: Error & { code?: string }) => {\n const msg = e.message || ''\n const isAuthError =\n e.code === 'AUTH_REQUIRED' ||\n msg.includes('Background mode requires') ||\n msg.includes('AUTH_REQUIRED')\n if (isAuthError) {\n // 提前刷一下认证状态,确保 Modal 下次打开时 banner 即时更新\n queryClient.invalidateQueries({ queryKey: ['worker-auth-status'] })\n const go = await confirm({\n title: '需要配置 Claude API',\n message:\n '后台模式需要 Claude API 认证(ANTHROPIC_API_KEY 或 OAuth)。\\n' +\n '请先在 AI 配置页设置后再启动执行。\\n\\n' +\n `详细信息:${msg}`,\n confirmText: '去 AI 配置',\n cancelText: '留在此页',\n variant: 'warning',\n })\n if (go) {\n setShowStart(false)\n navigate('/ai-config')\n }\n return\n }\n toast.error(`启动失败: ${msg}`)\n },\n })\n\n const handleCancel = async (id: number) => {\n const ok = await confirm({\n title: '取消方法论执行',\n message: '确定要取消这个运行中的方法论吗?已完成的阶段不会受影响,但当前进行中的阶段将停止。',\n confirmText: '确认取消',\n variant: 'warning',\n })\n if (ok) cancelMutation.mutate(id)\n }\n\n const handleDelete = async (id: number) => {\n const ok = await confirm({\n title: '删除执行记录',\n message: '确定要删除这条方法论执行记录吗?此操作不可恢复。',\n confirmText: '删除',\n variant: 'danger',\n })\n if (ok) deleteMutation.mutate(id)\n }\n\n if (isLoading) {\n return (\n <div>\n <h1 className=\"text-2xl font-bold text-gray-900 mb-6\">方法论执行</h1>\n <div className=\"bg-white rounded-lg shadow p-6\">\n <p className=\"text-gray-600\">加载中...</p>\n </div>\n </div>\n )\n }\n\n if (error) {\n return (\n <div>\n <h1 className=\"text-2xl font-bold text-gray-900 mb-6\">方法论执行</h1>\n <div className=\"bg-white rounded-lg shadow p-6\">\n <p className=\"text-red-600\">加载失败: {(error as Error).message}</p>\n </div>\n </div>\n )\n }\n\n const runningCount = executions?.filter(e => e.status === 'running').length || 0\n const completedCount = executions?.filter(e => e.status === 'completed').length || 0\n\n return (\n <div>\n <div className=\"flex items-center justify-between mb-6\">\n <h1 className=\"text-2xl font-bold text-gray-900\">方法论执行</h1>\n <div className=\"flex items-center gap-4 text-sm\">\n <span className=\"text-gray-500\">共 {executions?.length || 0} 个实例</span>\n {runningCount > 0 && <span className=\"text-blue-600\">· 运行中 {runningCount}</span>}\n {completedCount > 0 && <span className=\"text-green-600\">· 已完成 {completedCount}</span>}\n <button\n onClick={() => setShowStart(true)}\n className=\"ml-3 inline-flex items-center gap-1 px-3 py-1.5 text-sm bg-indigo-600 text-white rounded-md hover:bg-indigo-700\"\n >\n <Plus className=\"h-4 w-4\" /> 新建执行\n </button>\n </div>\n </div>\n\n {showStart && (\n <StartExecutionModal\n methodologies={methodologies ?? []}\n authStatus={authStatus ?? null}\n onCancel={() => setShowStart(false)}\n onSubmit={(payload) => startMutation.mutate(payload)}\n onGoToAIConfig={() => {\n setShowStart(false)\n navigate('/ai-config')\n }}\n submitting={startMutation.isPending}\n />\n )}\n\n <div className=\"space-y-4\">\n {executions?.map((execution) => {\n const plan = JSON.parse(execution.plan_json)\n const currentPhase = plan.phases[execution.current_phase_index]\n const progress = execution.status === 'completed'\n ? 100\n : Math.round((execution.current_phase_index / plan.phases.length) * 100)\n\n return (\n <div key={execution.id} className=\"bg-white rounded-lg shadow\">\n <div className=\"p-6 flex items-start justify-between gap-4\">\n <Link to={`/methodologies/${execution.id}`} className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-3 mb-2\">\n <GitBranch className=\"h-5 w-5 text-indigo-600 flex-shrink-0\" />\n <h3 className=\"text-lg font-semibold text-gray-900\">\n {methodologyNames[execution.methodology_id] || execution.methodology_id}\n </h3>\n <span className={clsx(\n 'px-2 py-1 text-xs font-medium rounded-full',\n execution.status === 'running' && 'bg-blue-100 text-blue-700',\n execution.status === 'completed' && 'bg-green-100 text-green-700',\n execution.status === 'failed' && 'bg-red-100 text-red-700',\n execution.status === 'cancelled' && 'bg-gray-100 text-gray-600'\n )}>\n {execution.status === 'running' && '运行中'}\n {execution.status === 'completed' && '已完成'}\n {execution.status === 'failed' && '失败'}\n {execution.status === 'cancelled' && '已取消'}\n </span>\n {execution.mode && (\n <span\n className={clsx(\n 'inline-flex items-center gap-1 px-2 py-1 text-xs font-medium rounded-full',\n execution.mode === 'background'\n ? 'bg-purple-100 text-purple-700'\n : 'bg-sky-100 text-sky-700'\n )}\n title={execution.mode === 'background' ? '独立 claude -p 子进程' : '主会话内执行'}\n >\n {execution.mode === 'background' ? <Cpu className=\"h-3 w-3\" /> : <Monitor className=\"h-3 w-3\" />}\n {execution.mode === 'background' ? '后台' : '前台'}\n </span>\n )}\n </div>\n\n <p className=\"text-sm text-gray-600 mb-3 font-mono\">\n Session: {execution.session_id.slice(0, 12)}...\n </p>\n\n {/* Progress bar */}\n <div className=\"w-full bg-gray-200 rounded-full h-1.5 mb-3\">\n <div\n className={clsx(\n 'h-1.5 rounded-full transition-all',\n execution.status === 'completed' ? 'bg-green-500' :\n execution.status === 'cancelled' ? 'bg-gray-400' : 'bg-indigo-600'\n )}\n style={{ width: `${progress}%` }}\n />\n </div>\n\n <div className=\"flex items-center gap-4 text-sm text-gray-500\">\n <div className=\"flex items-center gap-1\">\n <Clock className=\"h-4 w-4\" />\n {formatDistanceToNow(execution.started_at, { addSuffix: true, locale: zhCN })}\n </div>\n {execution.status === 'running' && currentPhase && (\n <div className=\"flex items-center gap-1\">\n <AlertCircle className=\"h-4 w-4\" />\n Phase {execution.current_phase_index + 1}/{plan.phases.length}: {currentPhase.id}\n </div>\n )}\n {execution.status === 'completed' && (\n <div className=\"flex items-center gap-1 text-green-600\">\n <CheckCircle className=\"h-4 w-4\" />\n 完成 {plan.phases.length} 个阶段\n </div>\n )}\n {execution.status === 'cancelled' && (\n <div className=\"flex items-center gap-1 text-gray-500\">\n <XCircle className=\"h-4 w-4\" />\n 已取消于 Phase {execution.current_phase_index + 1}\n </div>\n )}\n </div>\n </Link>\n\n {/* Actions */}\n <div className=\"flex items-center gap-1 flex-shrink-0\">\n {execution.status === 'running' && (\n <button\n onClick={(e) => {\n e.preventDefault()\n handleCancel(execution.id)\n }}\n className=\"p-2 text-orange-600 hover:bg-orange-50 rounded-md\"\n title=\"取消执行\"\n >\n <StopCircle className=\"h-4 w-4\" />\n </button>\n )}\n {execution.status !== 'running' && (\n <button\n onClick={(e) => { e.preventDefault(); handleDelete(execution.id) }}\n className=\"p-2 text-gray-500 hover:bg-red-50 hover:text-red-600 rounded-md\"\n title=\"删除记录\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n )}\n </div>\n </div>\n </div>\n )\n })}\n\n {(!executions || executions.length === 0) && (\n <div className=\"bg-white rounded-lg shadow p-12 text-center\">\n <GitBranch className=\"h-12 w-12 text-gray-400 mx-auto mb-4\" />\n <p className=\"text-gray-600\">暂无方法论执行记录</p>\n <p className=\"text-xs text-gray-500 mt-2\">\n 当你输入复杂任务(如\"重构 XXX 模块\")时,系统会自动匹配方法论并生成执行计划\n </p>\n </div>\n )}\n </div>\n </div>\n )\n}\n\ninterface StartExecutionModalProps {\n methodologies: MethodologyMeta[]\n authStatus: WorkerAuthStatus | null\n submitting: boolean\n onSubmit: (payload: { session_id: string; methodology_id: string; mode: 'foreground' | 'background' }) => void\n onCancel: () => void\n onGoToAIConfig: () => void\n}\n\nfunction StartExecutionModal({ methodologies, authStatus, submitting, onSubmit, onCancel, onGoToAIConfig }: StartExecutionModalProps) {\n const defaultSession = `manual-${Date.now().toString(36)}`\n const [sessionId, setSessionId] = useState(defaultSession)\n const [methodologyId, setMethodologyId] = useState(methodologies[0]?.id ?? '')\n const [mode, setMode] = useState<'foreground' | 'background'>('background')\n\n const authMissing = authStatus !== null && authStatus.available === false\n const blockedByAuth = authMissing && mode === 'background'\n\n const submit = (e: React.FormEvent) => {\n e.preventDefault()\n if (!sessionId.trim() || !methodologyId) return\n if (blockedByAuth) return\n onSubmit({ session_id: sessionId.trim(), methodology_id: methodologyId, mode })\n }\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\">\n <form\n onSubmit={submit}\n className=\"w-full max-w-md bg-white rounded-lg shadow-xl border border-gray-200\"\n >\n <div className=\"px-5 py-4 border-b border-gray-100\">\n <h2 className=\"text-lg font-semibold text-gray-900\">新建方法论执行</h2>\n <p className=\"text-xs text-gray-500 mt-0.5\">选择方法论模板和执行模式</p>\n </div>\n\n <div className=\"px-5 py-4 space-y-4 text-sm\">\n <label className=\"block\">\n <span className=\"text-gray-700\">方法论</span>\n <select\n className=\"mt-1 w-full border border-gray-300 rounded-md px-2 py-1.5\"\n value={methodologyId}\n onChange={(e) => setMethodologyId(e.target.value)}\n required\n >\n {methodologies.length === 0 && <option value=\"\">(未发现方法论)</option>}\n {methodologies.map(m => (\n <option key={m.id} value={m.id}>{m.name || m.id}</option>\n ))}\n </select>\n </label>\n\n <label className=\"block\">\n <span className=\"text-gray-700\">Session ID</span>\n <input\n type=\"text\"\n className=\"mt-1 w-full border border-gray-300 rounded-md px-2 py-1.5 font-mono text-xs\"\n value={sessionId}\n onChange={(e) => setSessionId(e.target.value)}\n required\n />\n <span className=\"mt-1 block text-xs text-gray-500\">\n 后台模式下用于追踪;建议保留默认或自定义一个可识别值\n </span>\n </label>\n\n <div>\n <span className=\"text-gray-700\">执行模式</span>\n <div className=\"mt-2 grid grid-cols-2 gap-2\">\n <button\n type=\"button\"\n onClick={() => setMode('background')}\n className={clsx(\n 'rounded-md border px-3 py-2 text-left',\n mode === 'background'\n ? 'border-indigo-500 bg-indigo-50'\n : 'border-gray-200 hover:border-gray-300',\n authMissing && 'ring-1 ring-amber-200'\n )}\n >\n <div className=\"flex items-center gap-2 font-medium text-gray-900\">\n <Cpu className=\"h-4 w-4 text-purple-600\" /> 后台\n {authMissing && (\n <span className=\"ml-auto text-[10px] font-normal text-amber-700 bg-amber-100 px-1.5 py-0.5 rounded\">\n 需先配置 API\n </span>\n )}\n </div>\n <p className=\"text-xs text-gray-500 mt-1\">\n 独立 claude -p 子进程,无需用户在主会话输入\n </p>\n </button>\n <button\n type=\"button\"\n onClick={() => setMode('foreground')}\n className={clsx(\n 'rounded-md border px-3 py-2 text-left',\n mode === 'foreground'\n ? 'border-indigo-500 bg-indigo-50'\n : 'border-gray-200 hover:border-gray-300'\n )}\n >\n <div className=\"flex items-center gap-2 font-medium text-gray-900\">\n <Monitor className=\"h-4 w-4 text-sky-600\" /> 前台\n </div>\n <p className=\"text-xs text-amber-700 mt-1 flex items-start gap-1\">\n <AlertTriangle className=\"h-3.5 w-3.5 mt-0.5 shrink-0\" />\n <span>需要你在主会话里输入任意内容才会推进;期间可用 <code className=\"px-1 rounded bg-amber-50\">/forge methodology status</code> 查看</span>\n </p>\n </button>\n </div>\n </div>\n\n {blockedByAuth && (\n <div className=\"rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-xs text-amber-800\">\n <div className=\"flex items-start gap-2\">\n <AlertTriangle className=\"h-4 w-4 mt-0.5 shrink-0 text-amber-600\" />\n <div className=\"flex-1 space-y-1\">\n <div className=\"font-medium\">后台模式需要 Claude API 认证</div>\n <div className=\"text-amber-700\">\n 未检测到 <code className=\"px-1 rounded bg-amber-100\">ANTHROPIC_API_KEY</code> 或 OAuth 凭据\n {authStatus?.message ? `(${authStatus.message})` : ''}。\n 请先在 AI 配置页完成设置,或切换到前台模式。\n </div>\n <button\n type=\"button\"\n onClick={onGoToAIConfig}\n className=\"mt-1 inline-flex items-center gap-1 px-2 py-1 text-xs font-medium text-white bg-amber-600 rounded hover:bg-amber-700\"\n >\n 去 AI 配置\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n\n <div className=\"px-5 py-3 border-t border-gray-100 flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"px-3 py-1.5 text-sm text-gray-700 hover:bg-gray-100 rounded-md\"\n >\n 取消\n </button>\n <button\n type=\"submit\"\n disabled={submitting || !methodologyId || blockedByAuth}\n title={blockedByAuth ? '后台模式需要先配置 Claude API' : undefined}\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm bg-indigo-600 text-white rounded-md hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {submitting ? '启动中...' : '启动'}\n </button>\n </div>\n </form>\n </div>\n )\n}\n"],"names":["fetchMethodologyExecutions","res","fetchMethodologies","fetchWorkerAuthStatus","cancelExecution","id","data","deleteExecution","startExecution","payload","err","methodologyNames","Methodologies","queryClient","useQueryClient","toast","useToast","confirm","useConfirm","navigate","useNavigate","showStart","setShowStart","useState","executions","isLoading","error","useQuery","methodologies","authStatus","cancelMutation","useMutation","e","deleteMutation","startMutation","msg","handleCancel","handleDelete","jsx","jsxs","runningCount","completedCount","Plus","StartExecutionModal","execution","plan","currentPhase","progress","Link","GitBranch","clsx","Cpu","Monitor","Clock","formatDistanceToNow","zhCN","AlertCircle","CheckCircle","XCircle","StopCircle","Trash2","submitting","onSubmit","onCancel","onGoToAIConfig","defaultSession","sessionId","setSessionId","methodologyId","setMethodologyId","_a","mode","setMode","authMissing","blockedByAuth","submit","m","AlertTriangle"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{r as c,j as e}from"./react-vendor-CSp-GLFF.js";import{b as p,u,c as j}from"./query-C99w429o.js";import{D as y}from"./Drawer-DeKukfwJ.js";import{M as w}from"./MarkdownRenderer-CCIz1MOz.js";import{u as v}from"./index-D23sAOAt.js";import{b as g,u as b,X as N,v as k}from"./lucide-DjB4fWNj.js";import"./vendor-CMMjVdZs.js";import"./syntax-highlighter-44FakypI.js";import"./react-router-I-HqunH7.js";async function S(){const i=await fetch("/api/skills");if(!i.ok)throw new Error("Failed to fetch skills");const s=await i.json();return Array.isArray(s)?s:s.skills||[]}async function C(i){const s=await fetch(`/api/skills/${i}`);if(!s.ok)throw new Error("Failed to fetch");return s.json()}async function E(i,s){if(!(await fetch(`/api/skills/${i}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:s})})).ok)throw new Error("Failed to save")}function A(){const i=p(),s=v(),{data:n,isLoading:f}=u({queryKey:["skills"],queryFn:S}),[r,x]=c.useState(null),[m,l]=c.useState(!1),[h,d]=c.useState(""),{data:t}=u({queryKey:["skill-detail",r],queryFn:()=>C(r),enabled:!!r});c.useEffect(()=>{t!=null&&t.content&&d(t.content),l(!1)},[t]);const o=j({mutationFn:a=>E(a.name,a.content),onSuccess:()=>{s.success("Skill 已保存"),l(!1),i.invalidateQueries({queryKey:["skill-detail",r]}),i.invalidateQueries({queryKey:["skills"]})},onError:a=>s.error(`保存失败: ${a.message}`)});return f?e.jsx("div",{className:"bg-white rounded-lg shadow p-6",children:"加载中..."}):e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-6",children:[e.jsx("h1",{className:"text-2xl font-bold text-gray-900",children:"Skill 管理"}),e.jsxs("div",{className:"text-sm text-gray-500",children:["共 ",(n==null?void 0:n.length)||0," 个 Skill"]})]}),e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4",children:n==null?void 0:n.map(a=>e.jsx("div",{className:"bg-white rounded-lg shadow p-5 hover:shadow-md transition-shadow cursor-pointer",onClick:()=>x(a.name),children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"w-10 h-10 rounded-lg bg-purple-100 flex items-center justify-center flex-shrink-0",children:e.jsx(g,{className:"h-5 w-5 text-purple-600"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("h3",{className:"font-semibold text-gray-900 truncate",children:a.name}),e.jsx("p",{className:"text-xs text-gray-500 mt-1 line-clamp-3",children:a.description||"(无描述)"})]})]})},a.name))}),e.jsx(y,{open:r!==null,onClose:()=>{x(null),l(!1)},title:`Skill: ${r}`,width:"w-[800px]",children:t&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx(g,{className:"h-5 w-5 text-purple-600"}),e.jsx("h3",{className:"text-lg font-semibold text-gray-900",children:t.name})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"描述"}),e.jsx("div",{className:"text-sm text-gray-800",children:t.description})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("div",{className:"text-xs text-gray-500",children:"完整内容 (Markdown)"}),e.jsx("div",{className:"flex items-center gap-2",children:m?e.jsxs(e.Fragment,{children:[e.jsxs("button",{onClick:()=>{l(!1),d(t.content||"")},className:"inline-flex items-center gap-1 text-xs text-gray-600 hover:text-gray-700",children:[e.jsx(N,{className:"h-3 w-3"}),"取消"]}),e.jsxs("button",{onClick:()=>o.mutate({name:t.name,content:h}),disabled:o.isPending,className:"inline-flex items-center gap-1 text-xs bg-indigo-600 text-white px-2 py-1 rounded hover:bg-indigo-700 disabled:bg-gray-400",children:[e.jsx(k,{className:"h-3 w-3"}),o.isPending?"保存中...":"保存"]})]}):e.jsxs("button",{onClick:()=>l(!0),className:"inline-flex items-center gap-1 text-xs text-indigo-600 hover:text-indigo-700",children:[e.jsx(b,{className:"h-3 w-3"}),"编辑"]})})]}),m?e.jsx("textarea",{value:h,onChange:a=>d(a.target.value),className:"w-full font-mono text-xs bg-gray-50 rounded p-3 border border-gray-300 focus:border-indigo-500 focus:outline-none",rows:20}):e.jsx("div",{className:"bg-white rounded p-3 border border-gray-200 max-h-[500px] overflow-y-auto",children:e.jsx(w,{content:t.content||""})}),o.isError&&e.jsxs("div",{className:"text-xs text-red-600 mt-1",children:["保存失败:",o.error.message]})]})]})})]})}export{A as default};
2
- //# sourceMappingURL=Skills-CrLshkrJ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Skills-CrLshkrJ.js","sources":["../../src/pages/Skills.tsx"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'\nimport { useState, useEffect } from 'react'\nimport { BookOpen, Edit2, Save, X } from 'lucide-react'\nimport Drawer from '../components/Drawer'\nimport MarkdownRenderer from '../components/MarkdownRenderer'\nimport { useToast } from '../components/Toast'\n\ninterface Skill {\n name: string\n description: string\n content?: string\n}\n\ninterface SkillsResponse {\n skills?: Skill[]\n}\n\nasync function fetchSkills(): Promise<Skill[]> {\n const res = await fetch('/api/skills')\n if (!res.ok) throw new Error('Failed to fetch skills')\n const data: SkillsResponse | Skill[] = await res.json()\n if (Array.isArray(data)) return data\n return data.skills || []\n}\n\nasync function fetchSkillDetail(name: string): Promise<Skill> {\n const res = await fetch(`/api/skills/${name}`)\n if (!res.ok) throw new Error('Failed to fetch')\n return res.json()\n}\n\nasync function saveSkill(name: string, content: string): Promise<void> {\n const res = await fetch(`/api/skills/${name}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ content }),\n })\n if (!res.ok) throw new Error('Failed to save')\n}\n\nexport default function Skills() {\n const queryClient = useQueryClient()\n const toast = useToast()\n const { data: skills, isLoading } = useQuery({\n queryKey: ['skills'],\n queryFn: fetchSkills,\n })\n\n const [selectedSkill, setSelectedSkill] = useState<string | null>(null)\n const [editing, setEditing] = useState(false)\n const [editContent, setEditContent] = useState('')\n\n const { data: detail } = useQuery({\n queryKey: ['skill-detail', selectedSkill],\n queryFn: () => fetchSkillDetail(selectedSkill!),\n enabled: !!selectedSkill,\n })\n\n useEffect(() => {\n if (detail?.content) setEditContent(detail.content)\n setEditing(false)\n }, [detail])\n\n const mutation = useMutation({\n mutationFn: (vars: { name: string; content: string }) => saveSkill(vars.name, vars.content),\n onSuccess: () => {\n toast.success('Skill 已保存')\n setEditing(false)\n queryClient.invalidateQueries({ queryKey: ['skill-detail', selectedSkill] })\n queryClient.invalidateQueries({ queryKey: ['skills'] })\n },\n onError: (e: Error) => toast.error(`保存失败: ${e.message}`),\n })\n\n if (isLoading) {\n return <div className=\"bg-white rounded-lg shadow p-6\">加载中...</div>\n }\n\n return (\n <div>\n <div className=\"flex items-center justify-between mb-6\">\n <h1 className=\"text-2xl font-bold text-gray-900\">Skill 管理</h1>\n <div className=\"text-sm text-gray-500\">共 {skills?.length || 0} 个 Skill</div>\n </div>\n\n <div className=\"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4\">\n {skills?.map((skill) => (\n <div\n key={skill.name}\n className=\"bg-white rounded-lg shadow p-5 hover:shadow-md transition-shadow cursor-pointer\"\n onClick={() => setSelectedSkill(skill.name)}\n >\n <div className=\"flex items-start gap-3\">\n <div className=\"w-10 h-10 rounded-lg bg-purple-100 flex items-center justify-center flex-shrink-0\">\n <BookOpen className=\"h-5 w-5 text-purple-600\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <h3 className=\"font-semibold text-gray-900 truncate\">{skill.name}</h3>\n <p className=\"text-xs text-gray-500 mt-1 line-clamp-3\">\n {skill.description || '(无描述)'}\n </p>\n </div>\n </div>\n </div>\n ))}\n </div>\n\n {/* Skill Detail Drawer */}\n <Drawer\n open={selectedSkill !== null}\n onClose={() => { setSelectedSkill(null); setEditing(false) }}\n title={`Skill: ${selectedSkill}`}\n width=\"w-[800px]\"\n >\n {detail && (\n <div className=\"space-y-4\">\n <div className=\"flex items-center gap-2 mb-2\">\n <BookOpen className=\"h-5 w-5 text-purple-600\" />\n <h3 className=\"text-lg font-semibold text-gray-900\">{detail.name}</h3>\n </div>\n\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">描述</div>\n <div className=\"text-sm text-gray-800\">{detail.description}</div>\n </div>\n\n <div>\n <div className=\"flex items-center justify-between mb-2\">\n <div className=\"text-xs text-gray-500\">完整内容 (Markdown)</div>\n <div className=\"flex items-center gap-2\">\n {!editing ? (\n <button\n onClick={() => setEditing(true)}\n className=\"inline-flex items-center gap-1 text-xs text-indigo-600 hover:text-indigo-700\"\n >\n <Edit2 className=\"h-3 w-3\" />编辑\n </button>\n ) : (\n <>\n <button\n onClick={() => { setEditing(false); setEditContent(detail.content || '') }}\n className=\"inline-flex items-center gap-1 text-xs text-gray-600 hover:text-gray-700\"\n >\n <X className=\"h-3 w-3\" />取消\n </button>\n <button\n onClick={() => mutation.mutate({ name: detail.name, content: editContent })}\n disabled={mutation.isPending}\n className=\"inline-flex items-center gap-1 text-xs bg-indigo-600 text-white px-2 py-1 rounded hover:bg-indigo-700 disabled:bg-gray-400\"\n >\n <Save className=\"h-3 w-3\" />\n {mutation.isPending ? '保存中...' : '保存'}\n </button>\n </>\n )}\n </div>\n </div>\n {editing ? (\n <textarea\n value={editContent}\n onChange={(e) => setEditContent(e.target.value)}\n className=\"w-full font-mono text-xs bg-gray-50 rounded p-3 border border-gray-300 focus:border-indigo-500 focus:outline-none\"\n rows={20}\n />\n ) : (\n <div className=\"bg-white rounded p-3 border border-gray-200 max-h-[500px] overflow-y-auto\">\n <MarkdownRenderer content={detail.content || ''} />\n </div>\n )}\n {mutation.isError && (\n <div className=\"text-xs text-red-600 mt-1\">保存失败:{(mutation.error as Error).message}</div>\n )}\n </div>\n </div>\n )}\n </Drawer>\n </div>\n )\n}\n"],"names":["fetchSkills","res","data","fetchSkillDetail","name","saveSkill","content","Skills","queryClient","useQueryClient","toast","useToast","skills","isLoading","useQuery","selectedSkill","setSelectedSkill","useState","editing","setEditing","editContent","setEditContent","detail","useEffect","mutation","useMutation","vars","e","jsx","jsxs","skill","BookOpen","Drawer","Fragment","X","Save","Edit2","MarkdownRenderer"],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Dashboard-qUCxXFSI.js","assets/react-vendor-CSp-GLFF.js","assets/query-C99w429o.js","assets/react-router-I-HqunH7.js","assets/vendor-CMMjVdZs.js","assets/lucide-DjB4fWNj.js","assets/charts-CLrM0_uM.js","assets/Sessions-Bjf-Mvwb.js","assets/Drawer-DeKukfwJ.js","assets/date-fns-CZ_bHujz.js","assets/export-CEzDNM66.js","assets/syntax-highlighter-44FakypI.js","assets/SessionDetail-DzTue2xK.js","assets/Events-BoQ8Fo5k.js","assets/CodeBlock--H53gk46.js","assets/ExecutionTrace-sFZ_vHNf.js","assets/Methodologies-C0-Keokj.js","assets/MethodologyDetail-Do1taSKM.js","assets/Agents-DAGWYsJj.js","assets/MarkdownRenderer-CCIz1MOz.js","assets/Skills-CrLshkrJ.js","assets/Routing-CFmM7JuB.js","assets/AIConfig-D-vrYoJ3.js"])))=>i.map(i=>d[i]);
2
- import{r as s,j as e,e as y,d as v}from"./react-vendor-CSp-GLFF.js";import{u as N,O as w,L as _,R as C,a as c,N as k,B as E}from"./react-router-I-HqunH7.js";import{Q as P,a as T}from"./query-C99w429o.js";import{_ as x}from"./syntax-highlighter-44FakypI.js";import{d as f}from"./vendor-CMMjVdZs.js";import{X as p,M as O,L as A,a as S,A as L,T as I,G as R,B as z,b as D,N as V,C as F,I as B,c as M,d as q,e as Q,f as G}from"./lucide-DjB4fWNj.js";(function(){const i=document.createElement("link").relList;if(i&&i.supports&&i.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))l(r);new MutationObserver(r=>{for(const n of r)if(n.type==="childList")for(const t of n.addedNodes)t.tagName==="LINK"&&t.rel==="modulepreload"&&l(t)}).observe(document,{childList:!0,subtree:!0});function a(r){const n={};return r.integrity&&(n.integrity=r.integrity),r.referrerPolicy&&(n.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?n.credentials="include":r.crossOrigin==="anonymous"?n.credentials="omit":n.credentials="same-origin",n}function l(r){if(r.ep)return;r.ep=!0;const n=a(r);fetch(r.href,n)}})();const W=[{title:"总览",items:[{name:"仪表盘",href:"/dashboard",icon:A}]},{title:"活动",items:[{name:"会话",href:"/sessions",icon:S},{name:"事件",href:"/events",icon:L},{name:"执行追踪",href:"/execution-trace",icon:I},{name:"方法论执行",href:"/methodologies",icon:R}]},{title:"配置",items:[{name:"Agent 管理",href:"/agents",icon:z},{name:"Skill 管理",href:"/skills",icon:D},{name:"Agent 路由",href:"/routing",icon:V},{name:"AI 配置",href:"/ai-config",icon:F}]}];function X(){const o=N(),[i,a]=s.useState(!1),l=r=>e.jsx(e.Fragment,{children:W.map(n=>e.jsxs("div",{className:"mb-4",children:[e.jsx("div",{className:"px-3 py-2 text-xs font-semibold text-gray-400 uppercase tracking-wider",children:n.title}),n.items.map(t=>{const u=t.icon,m=o.pathname===t.href||o.pathname.startsWith(t.href+"/");return e.jsxs(_,{to:t.href,onClick:r,className:f("group flex items-center px-3 py-2 text-sm font-medium rounded-md mb-0.5",m?"bg-indigo-50 text-indigo-600":"text-gray-700 hover:bg-gray-50"),children:[e.jsx(u,{className:f("mr-3 h-4 w-4",m?"text-indigo-600":"text-gray-400")}),t.name]},t.name)})]},n.title))});return e.jsxs("div",{className:"min-h-screen bg-gray-50",children:[e.jsxs("div",{className:f("fixed inset-0 z-40 lg:hidden",i?"block":"hidden"),children:[e.jsx("div",{className:"fixed inset-0 bg-gray-600 bg-opacity-75",onClick:()=>a(!1)}),e.jsxs("div",{className:"fixed inset-y-0 left-0 flex w-64 flex-col bg-white",children:[e.jsxs("div",{className:"flex items-center justify-between px-4 py-4 border-b",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-8 h-8 rounded-lg bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center text-white font-bold text-sm",children:"CF"}),e.jsx("h1",{className:"text-base font-bold text-gray-900",children:"Claude Forge"})]}),e.jsx("button",{onClick:()=>a(!1),className:"text-gray-500",children:e.jsx(p,{className:"h-5 w-5"})})]}),e.jsx("nav",{className:"flex-1 overflow-y-auto px-2 py-4",children:l(()=>a(!1))})]})]}),e.jsx("div",{className:"hidden lg:fixed lg:inset-y-0 lg:flex lg:w-64 lg:flex-col",children:e.jsxs("div",{className:"flex flex-col flex-grow border-r border-gray-200 bg-white",children:[e.jsxs("div",{className:"flex items-center gap-2 px-4 py-4 border-b",children:[e.jsx("div",{className:"w-8 h-8 rounded-lg bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center text-white font-bold text-sm",children:"CF"}),e.jsx("h1",{className:"text-base font-bold text-gray-900",children:"Claude Forge"})]}),e.jsx("nav",{className:"flex-1 overflow-y-auto px-2 py-4",children:l()})]})}),e.jsxs("div",{className:"lg:pl-64",children:[e.jsxs("div",{className:"sticky top-0 z-10 flex h-14 flex-shrink-0 bg-white border-b border-gray-200 lg:hidden",children:[e.jsx("button",{onClick:()=>a(!0),className:"px-4 text-gray-500 focus:outline-none",children:e.jsx(O,{className:"h-5 w-5"})}),e.jsx("div",{className:"flex flex-1 items-center px-4",children:e.jsx("h1",{className:"text-base font-semibold text-gray-900",children:"Claude Forge"})})]}),e.jsx("main",{className:"py-6",children:e.jsx("div",{className:"mx-auto max-w-7xl px-4 sm:px-6 lg:px-8",children:e.jsx(w,{})})})]})]})}const $=s.lazy(()=>x(()=>import("./Dashboard-qUCxXFSI.js"),__vite__mapDeps([0,1,2,3,4,5,6]))),K=s.lazy(()=>x(()=>import("./Sessions-Bjf-Mvwb.js"),__vite__mapDeps([7,1,2,8,4,5,9,10,3,11]))),U=s.lazy(()=>x(()=>import("./SessionDetail-DzTue2xK.js"),__vite__mapDeps([12,1,3,4,2,5,9]))),H=s.lazy(()=>x(()=>import("./Events-BoQ8Fo5k.js"),__vite__mapDeps([13,1,2,4,8,5,14,11,10,9,3]))),J=s.lazy(()=>x(()=>import("./ExecutionTrace-sFZ_vHNf.js"),__vite__mapDeps([15,1,2,4,8,5,14,11,10,9,3]))),Y=s.lazy(()=>x(()=>import("./Methodologies-C0-Keokj.js"),__vite__mapDeps([16,1,2,3,4,5,9,11]))),Z=s.lazy(()=>x(()=>import("./MethodologyDetail-Do1taSKM.js"),__vite__mapDeps([17,1,3,4,2,5,9]))),ee=s.lazy(()=>x(()=>import("./Agents-DAGWYsJj.js"),__vite__mapDeps([18,1,2,8,4,5,19,11,3]))),se=s.lazy(()=>x(()=>import("./Skills-CrLshkrJ.js"),__vite__mapDeps([20,1,2,8,4,5,19,11,3]))),te=s.lazy(()=>x(()=>import("./Routing-CFmM7JuB.js"),__vite__mapDeps([21,1,2,3,4,5]))),re=s.lazy(()=>x(()=>import("./AIConfig-D-vrYoJ3.js"),__vite__mapDeps([22,1,2,5,3,4,11])));function d(){return e.jsx("div",{className:"flex items-center justify-center h-full py-16",children:e.jsxs("div",{className:"flex items-center gap-3 text-sm text-gray-500",children:[e.jsx("div",{className:"w-4 h-4 border-2 border-gray-300 border-t-blue-500 rounded-full animate-spin"}),"加载中..."]})})}function ne(){return e.jsx(C,{children:e.jsxs(c,{path:"/",element:e.jsx(X,{}),children:[e.jsx(c,{index:!0,element:e.jsx(k,{to:"/dashboard",replace:!0})}),e.jsx(c,{path:"dashboard",element:e.jsx(s.Suspense,{fallback:e.jsx(d,{}),children:e.jsx($,{})})}),e.jsx(c,{path:"sessions",element:e.jsx(s.Suspense,{fallback:e.jsx(d,{}),children:e.jsx(K,{})})}),e.jsx(c,{path:"sessions/:id",element:e.jsx(s.Suspense,{fallback:e.jsx(d,{}),children:e.jsx(U,{})})}),e.jsx(c,{path:"events",element:e.jsx(s.Suspense,{fallback:e.jsx(d,{}),children:e.jsx(H,{})})}),e.jsx(c,{path:"execution-trace",element:e.jsx(s.Suspense,{fallback:e.jsx(d,{}),children:e.jsx(J,{})})}),e.jsx(c,{path:"methodologies",element:e.jsx(s.Suspense,{fallback:e.jsx(d,{}),children:e.jsx(Y,{})})}),e.jsx(c,{path:"methodologies/:id",element:e.jsx(s.Suspense,{fallback:e.jsx(d,{}),children:e.jsx(Z,{})})}),e.jsx(c,{path:"agents",element:e.jsx(s.Suspense,{fallback:e.jsx(d,{}),children:e.jsx(ee,{})})}),e.jsx(c,{path:"skills",element:e.jsx(s.Suspense,{fallback:e.jsx(d,{}),children:e.jsx(se,{})})}),e.jsx(c,{path:"routing",element:e.jsx(s.Suspense,{fallback:e.jsx(d,{}),children:e.jsx(te,{})})}),e.jsx(c,{path:"ai-config",element:e.jsx(s.Suspense,{fallback:e.jsx(d,{}),children:e.jsx(re,{})})})]})})}const g=s.createContext(null);function pe(){const o=s.useContext(g);if(!o)throw new Error("useToast must be used within ToastProvider");return o}let ie=1;function oe({children:o}){const[i,a]=s.useState([]),l=s.useCallback(t=>{a(u=>u.filter(m=>m.id!==t))},[]),r=s.useCallback((t,u)=>{const m=ie++;a(h=>[...h,{id:m,type:t,message:u}]),setTimeout(()=>l(m),4e3)},[l]),n={show:r,success:t=>r("success",t),error:t=>r("error",t),warning:t=>r("warning",t),info:t=>r("info",t)};return e.jsxs(g.Provider,{value:n,children:[o,e.jsx("div",{className:"fixed top-4 right-4 z-[9999] space-y-2 max-w-md",children:i.map(t=>e.jsx(ae,{toast:t,onClose:()=>l(t.id)},t.id))})]})}function ae({toast:o,onClose:i}){const a={success:e.jsx(Q,{className:"h-5 w-5 text-green-500"}),error:e.jsx(q,{className:"h-5 w-5 text-red-500"}),warning:e.jsx(M,{className:"h-5 w-5 text-yellow-500"}),info:e.jsx(B,{className:"h-5 w-5 text-blue-500"})},l={success:"border-green-200",error:"border-red-200",warning:"border-yellow-200",info:"border-blue-200"};return e.jsxs("div",{className:f("bg-white shadow-lg rounded-lg border px-4 py-3 flex items-start gap-3 animate-in slide-in-from-right",l[o.type]),children:[a[o.type],e.jsx("div",{className:"flex-1 text-sm text-gray-800",children:o.message}),e.jsx("button",{onClick:i,className:"text-gray-400 hover:text-gray-600",children:e.jsx(p,{className:"h-4 w-4"})})]})}const j=s.createContext(null);function ge(){const o=s.useContext(j);if(!o)throw new Error("useConfirm must be used within ConfirmProvider");return o.confirm}function le({children:o}){var m;const[i,a]=s.useState({open:!1,options:null,resolve:null}),l=s.useCallback(h=>new Promise(b=>{a({open:!0,options:h,resolve:b})}),[]),r=h=>{i.resolve&&i.resolve(h),a({open:!1,options:null,resolve:null})},n=((m=i.options)==null?void 0:m.variant)||"danger",t={danger:"text-red-600",warning:"text-yellow-600",info:"text-blue-600"}[n],u={danger:"bg-red-600 hover:bg-red-700",warning:"bg-yellow-600 hover:bg-yellow-700",info:"bg-indigo-600 hover:bg-indigo-700"}[n];return e.jsxs(j.Provider,{value:{confirm:l},children:[o,i.open&&i.options&&e.jsxs("div",{className:"fixed inset-0 z-[9999] flex items-center justify-center",children:[e.jsx("div",{className:"absolute inset-0 bg-black bg-opacity-50",onClick:()=>r(!1)}),e.jsxs("div",{className:"relative bg-white rounded-lg shadow-xl max-w-md w-full mx-4 p-6",children:[e.jsxs("div",{className:"flex items-start gap-4",children:[e.jsx("div",{className:`flex-shrink-0 ${t}`,children:e.jsx(G,{className:"h-6 w-6"})}),e.jsxs("div",{className:"flex-1",children:[e.jsx("h3",{className:"text-lg font-semibold text-gray-900 mb-2",children:i.options.title}),e.jsx("p",{className:"text-sm text-gray-600 whitespace-pre-wrap",children:i.options.message})]})]}),e.jsxs("div",{className:"flex justify-end gap-2 mt-6",children:[e.jsx("button",{onClick:()=>r(!1),className:"px-4 py-2 text-sm text-gray-700 bg-white border border-gray-300 rounded hover:bg-gray-50",children:i.options.cancelText||"取消"}),e.jsx("button",{onClick:()=>r(!0),className:`px-4 py-2 text-sm text-white rounded ${u}`,children:i.options.confirmText||"确定"})]})]})]})]})}const ce=new P({defaultOptions:{queries:{refetchOnWindowFocus:!1,retry:1}}});y.createRoot(document.getElementById("root")).render(e.jsx(v.StrictMode,{children:e.jsx(T,{client:ce,children:e.jsx(oe,{children:e.jsx(le,{children:e.jsx(E,{children:e.jsx(ne,{})})})})})}));export{ge as a,pe as u};
3
- //# sourceMappingURL=index-D23sAOAt.js.map