@winspan/claude-forge 8.33.0 → 8.33.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +82 -2
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/web/static/assets/AIConfig-Dw13rVtT.js +2 -0
- package/dist/web/static/assets/AIConfig-Dw13rVtT.js.map +1 -0
- package/dist/web/static/assets/Agents-D1p3JhQs.js +2 -0
- package/dist/web/static/assets/Agents-D1p3JhQs.js.map +1 -0
- package/dist/web/static/assets/{Events-BoQ8Fo5k.js → Events-DqzBTrly.js} +2 -2
- package/dist/web/static/assets/{Events-BoQ8Fo5k.js.map → Events-DqzBTrly.js.map} +1 -1
- package/dist/web/static/assets/{ExecutionTrace-sFZ_vHNf.js → ExecutionTrace-Z-zlH0KH.js} +2 -2
- package/dist/web/static/assets/{ExecutionTrace-sFZ_vHNf.js.map → ExecutionTrace-Z-zlH0KH.js.map} +1 -1
- package/dist/web/static/assets/Methodologies-Br5KOWuF.js +5 -0
- package/dist/web/static/assets/Methodologies-Br5KOWuF.js.map +1 -0
- package/dist/web/static/assets/{Sessions-Bjf-Mvwb.js → Sessions-DOd65EkN.js} +2 -2
- package/dist/web/static/assets/{Sessions-Bjf-Mvwb.js.map → Sessions-DOd65EkN.js.map} +1 -1
- package/dist/web/static/assets/Skills-zacj_uSW.js +2 -0
- package/dist/web/static/assets/Skills-zacj_uSW.js.map +1 -0
- package/dist/web/static/assets/auth-Bnf8ZcqN.js +2 -0
- package/dist/web/static/assets/auth-Bnf8ZcqN.js.map +1 -0
- package/dist/web/static/assets/index-BVpUTHdp.js +3 -0
- package/dist/web/static/assets/{index-D23sAOAt.js.map → index-BVpUTHdp.js.map} +1 -1
- package/dist/web/static/index.html +1 -1
- package/package.json +2 -2
- package/dist/web/static/assets/AIConfig-D-vrYoJ3.js +0 -2
- package/dist/web/static/assets/AIConfig-D-vrYoJ3.js.map +0 -1
- package/dist/web/static/assets/Agents-DAGWYsJj.js +0 -2
- package/dist/web/static/assets/Agents-DAGWYsJj.js.map +0 -1
- package/dist/web/static/assets/Methodologies-C0-Keokj.js +0 -5
- package/dist/web/static/assets/Methodologies-C0-Keokj.js.map +0 -1
- package/dist/web/static/assets/Skills-CrLshkrJ.js +0 -2
- package/dist/web/static/assets/Skills-CrLshkrJ.js.map +0 -1
- package/dist/web/static/assets/index-D23sAOAt.js +0 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkFzC,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0J/C"}
|
|
@@ -6,6 +6,9 @@ import { FORGE_HOME, FORGE_PATHS } from '../../core/constants.js';
|
|
|
6
6
|
import { copyHookScripts, backupSettings, injectHooks } from '../init/hook-manager.js';
|
|
7
7
|
import chalk from 'chalk';
|
|
8
8
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
// Fallback if the upstream /v1/models probe fails — keep this in sync with the
|
|
10
|
+
// latest GA opus family release. Bump when Anthropic ships a newer opus.
|
|
11
|
+
const FALLBACK_MODEL = 'claude-opus-4-7';
|
|
9
12
|
function prompt(question) {
|
|
10
13
|
const rl = readline.createInterface({
|
|
11
14
|
input: process.stdin,
|
|
@@ -18,6 +21,63 @@ function prompt(question) {
|
|
|
18
21
|
});
|
|
19
22
|
});
|
|
20
23
|
}
|
|
24
|
+
function rankOpusId(id) {
|
|
25
|
+
// Recognise ids like claude-opus-4-7, claude-opus-4-7-20260101, claude-3-opus-20240229.
|
|
26
|
+
// Return a tuple that sorts highest-first: [major, minor, dateInt].
|
|
27
|
+
const newStyle = /^claude-opus-(\d+)-(\d+)(?:-(\d{8}))?$/.exec(id);
|
|
28
|
+
if (newStyle) {
|
|
29
|
+
const major = parseInt(newStyle[1], 10);
|
|
30
|
+
const minor = parseInt(newStyle[2], 10);
|
|
31
|
+
const date = newStyle[3] ? parseInt(newStyle[3], 10) : 0;
|
|
32
|
+
return [major, minor, date];
|
|
33
|
+
}
|
|
34
|
+
// Legacy `claude-3-opus-YYYYMMDD` gets mapped to (3, 0, date) so it ranks below the 4.x family.
|
|
35
|
+
const legacy = /^claude-(\d+)-opus(?:-(\d{8}))?$/.exec(id);
|
|
36
|
+
if (legacy) {
|
|
37
|
+
return [parseInt(legacy[1], 10), 0, legacy[2] ? parseInt(legacy[2], 10) : 0];
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
async function pickDefaultModel(apiKey, baseUrl) {
|
|
42
|
+
if (!apiKey)
|
|
43
|
+
return FALLBACK_MODEL;
|
|
44
|
+
const modelsUrl = baseUrl.endsWith('/v1')
|
|
45
|
+
? `${baseUrl}/models`
|
|
46
|
+
: `${baseUrl.replace(/\/$/, '')}/v1/models`;
|
|
47
|
+
const controller = new AbortController();
|
|
48
|
+
const timer = setTimeout(() => controller.abort(), 5000);
|
|
49
|
+
try {
|
|
50
|
+
const res = await fetch(modelsUrl, {
|
|
51
|
+
redirect: 'follow',
|
|
52
|
+
signal: controller.signal,
|
|
53
|
+
headers: {
|
|
54
|
+
'Authorization': `Bearer ${apiKey}`,
|
|
55
|
+
'x-api-key': apiKey,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
if (!res.ok)
|
|
59
|
+
return FALLBACK_MODEL;
|
|
60
|
+
const payload = (await res.json());
|
|
61
|
+
const ids = (payload.data ?? []).map((m) => m.id).filter((id) => typeof id === 'string');
|
|
62
|
+
const ranked = ids
|
|
63
|
+
.map((id) => ({ id, rank: rankOpusId(id) }))
|
|
64
|
+
.filter((x) => x.rank !== null)
|
|
65
|
+
.sort((a, b) => {
|
|
66
|
+
for (let i = 0; i < 3; i++) {
|
|
67
|
+
if (a.rank[i] !== b.rank[i])
|
|
68
|
+
return b.rank[i] - a.rank[i];
|
|
69
|
+
}
|
|
70
|
+
return 0;
|
|
71
|
+
});
|
|
72
|
+
return ranked[0]?.id ?? FALLBACK_MODEL;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return FALLBACK_MODEL;
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
clearTimeout(timer);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
21
81
|
export function register(program) {
|
|
22
82
|
program
|
|
23
83
|
.command('init')
|
|
@@ -36,17 +96,37 @@ export function register(program) {
|
|
|
36
96
|
}
|
|
37
97
|
// 2. Interactive configuration
|
|
38
98
|
let apiKey = process.env.ANTHROPIC_API_KEY || '';
|
|
99
|
+
let baseUrl = 'https://api.anthropic.com';
|
|
39
100
|
let webPort = 3721;
|
|
40
101
|
if (!skipPrompts) {
|
|
41
102
|
console.log(chalk.yellow('\n📝 配置选项(直接回车使用默认值)\n'));
|
|
42
103
|
const apiKeyInput = await prompt(`Anthropic API Key (可选,用于 AI 功能) [${apiKey ? '已设置' : '留空'}]: `);
|
|
43
104
|
if (apiKeyInput)
|
|
44
105
|
apiKey = apiKeyInput;
|
|
106
|
+
const baseUrlInput = await prompt(`API Base URL [${baseUrl}]: `);
|
|
107
|
+
if (baseUrlInput)
|
|
108
|
+
baseUrl = baseUrlInput;
|
|
109
|
+
if (baseUrl.startsWith('http://')) {
|
|
110
|
+
baseUrl = 'https://' + baseUrl.slice('http://'.length);
|
|
111
|
+
}
|
|
45
112
|
const portInput = await prompt(`Web 管理后台端口 [${webPort}]: `);
|
|
46
113
|
if (portInput && !isNaN(parseInt(portInput))) {
|
|
47
114
|
webPort = parseInt(portInput);
|
|
48
115
|
}
|
|
49
116
|
}
|
|
117
|
+
// 2b. Resolve default model: try upstream /v1/models, fall back to a recent default
|
|
118
|
+
if (apiKey) {
|
|
119
|
+
process.stdout.write(chalk.gray('→ 正在从 ') + baseUrl + chalk.gray(' 获取最新模型...'));
|
|
120
|
+
}
|
|
121
|
+
const defaultModel = await pickDefaultModel(apiKey, baseUrl);
|
|
122
|
+
if (apiKey) {
|
|
123
|
+
process.stdout.write('\r' +
|
|
124
|
+
chalk.green('✓') +
|
|
125
|
+
' 默认模型:' +
|
|
126
|
+
chalk.cyan(defaultModel) +
|
|
127
|
+
(defaultModel === FALLBACK_MODEL ? chalk.gray('(fallback,未联网拉取)') : '') +
|
|
128
|
+
' \n');
|
|
129
|
+
}
|
|
50
130
|
// 3. Generate config.yaml
|
|
51
131
|
const configPath = FORGE_PATHS.config();
|
|
52
132
|
const configContent = `# Claude Forge 配置文件
|
|
@@ -55,8 +135,8 @@ export function register(program) {
|
|
|
55
135
|
# AI 功能配置(分类器、质量检查、提炼)
|
|
56
136
|
distill:
|
|
57
137
|
api_key: ${apiKey ? `"${apiKey}"` : '"" # 留空则禁用 AI 功能'}
|
|
58
|
-
model: "
|
|
59
|
-
base_url: "
|
|
138
|
+
model: "${defaultModel}"
|
|
139
|
+
base_url: "${baseUrl}"
|
|
60
140
|
|
|
61
141
|
# Web 管理后台
|
|
62
142
|
web:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r as m,j as e}from"./react-vendor-CSp-GLFF.js";import{b as w,u as p,c as y}from"./query-C99w429o.js";import{u as N}from"./index-BVpUTHdp.js";import{a as f}from"./auth-Bnf8ZcqN.js";import{C as k,E as _,w as C,e as P,d as S,q as E,Z as A,v as F}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 q(a,r){const i=new URLSearchParams;a&&i.set("api_key",a),r&&i.set("base_url",r);const o=await fetch(`/api/ai/models?${i.toString()}`);return o.ok?(await o.json()).data||[]:[]}async function K(a){if(!(await f("/api/config/ai",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)})).ok)throw new Error("Failed to save config")}async function T(a){const r=await f("/api/ai/test",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)}),i=await r.json().catch(()=>({}));if(!r.ok)throw new Error(i.error||"Test failed");return i}function J(){const a=w(),r=N(),{data:i,isLoading:o}=p({queryKey:["ai-config"],queryFn:I}),[t,n]=m.useState({api_key:"",base_url:"",model:""}),[u,b]=m.useState(!1),[d,h]=m.useState(null);m.useEffect(()=>{i&&n(i)},[i]);const{data:l,refetch:j,isFetching:g}=p({queryKey:["ai-models",t.api_key,t.base_url],queryFn:()=>q(t.api_key,t.base_url),enabled:!!t.api_key&&!!t.base_url}),x=y({mutationFn:K,onSuccess:()=>{r.success("AI 配置已保存"),a.invalidateQueries({queryKey:["ai-config"]})},onError:s=>r.error(`保存失败: ${s.message}`)}),c=y({mutationFn:T,onSuccess:s=>{const v=(s==null?void 0:s.model)||t.model;h({ok:!0,message:`连接成功!模型: ${v}`}),r.success("API 连接测试通过")},onError:s=>{h({ok:!1,message:s.message}),r.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(k,{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:()=>b(!u),className:"absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600",children:u?e.jsx(_,{className:"h-4 w-4"}):e.jsx(C,{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:()=>j(),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(P,{className:"h-4 w-4 flex-shrink-0 mt-0.5"}):e.jsx(S,{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(E,{className:"h-4 w-4 animate-spin"}):e.jsx(A,{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(F,{className:"h-4 w-4"}),x.isPending?"保存中...":"保存配置"]})]})})]})]})]})}export{J as default};
|
|
2
|
+
//# sourceMappingURL=AIConfig-Dw13rVtT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AIConfig-Dw13rVtT.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'\nimport { authFetch } from '../utils/auth'\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 authFetch('/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 authFetch('/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","authFetch","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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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
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-BVpUTHdp.js";import{a as C}from"./auth-Bnf8ZcqN.js";import{B as j,t as k,u as E,X as F,v as q}from"./lucide-DjB4fWNj.js";import"./vendor-CMMjVdZs.js";import"./syntax-highlighter-44FakypI.js";import"./react-router-I-HqunH7.js";async function S(){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 K(n){const a=await fetch(`/api/agents/${n}`);if(!a.ok)throw new Error("Failed to fetch");return a.json()}async function M(n,a){if(!(await C(`/api/agents/${n}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({content:a})})).ok)throw new Error("Failed to save")}function U(){const n=v(),a=A(),{data:r,isLoading:y}=p({queryKey:["agents"],queryFn:S}),[l,m]=d.useState(null),[g,o]=d.useState(!1),[h,x]=d.useState(""),{data:t}=p({queryKey:["agent-detail",l],queryFn:()=>K(l),enabled:!!l});d.useEffect(()=>{t!=null&&t.content&&x(t.content),o(!1)},[t]);const c=N({mutationFn:s=>M(s.name,s.content),onSuccess:()=>{a.success("Agent 已保存"),o(!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(k,{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),o(!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:()=>{o(!1),x(t.content||"")},className:"inline-flex items-center gap-1 text-xs text-gray-600 hover:text-gray-700",children:[e.jsx(F,{className:"h-3 w-3"}),"取消"]}),e.jsxs("button",{onClick:()=>c.mutate({name:t.name,content:h}),disabled:c.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(q,{className:"h-3 w-3"}),c.isPending?"保存中...":"保存"]})]}):e.jsxs("button",{onClick:()=>o(!0),className:"inline-flex items-center gap-1 text-xs text-indigo-600 hover:text-indigo-700",children:[e.jsx(E,{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||""})}),c.isError&&e.jsxs("div",{className:"text-xs text-red-600 mt-1",children:["保存失败:",c.error.message]})]})]})})]})}export{U as default};
|
|
2
|
+
//# sourceMappingURL=Agents-D1p3JhQs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Agents-D1p3JhQs.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'\nimport { authFetch } from '../utils/auth'\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 authFetch(`/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","authFetch","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,2 +1,2 @@
|
|
|
1
|
-
import{r as n,j as e}from"./react-vendor-CSp-GLFF.js";import{u as N}from"./query-C99w429o.js";import{d as u}from"./vendor-CMMjVdZs.js";import{D as w}from"./Drawer-DeKukfwJ.js";import{C as g}from"./CodeBlock--H53gk46.js";import{S as _,g as k,d as S,a as C}from"./export-CEzDNM66.js";import{u as E}from"./index-
|
|
2
|
-
//# sourceMappingURL=Events-
|
|
1
|
+
import{r as n,j as e}from"./react-vendor-CSp-GLFF.js";import{u as N}from"./query-C99w429o.js";import{d as u}from"./vendor-CMMjVdZs.js";import{D as w}from"./Drawer-DeKukfwJ.js";import{C as g}from"./CodeBlock--H53gk46.js";import{S as _,g as k,d as S,a as C}from"./export-CEzDNM66.js";import{u as E}from"./index-BVpUTHdp.js";import{k as P,D as U,A as T}from"./lucide-DjB4fWNj.js";import{f as y}from"./date-fns-CZ_bHujz.js";import"./syntax-highlighter-44FakypI.js";import"./react-router-I-HqunH7.js";async function D(i){const c=`/api/events?limit=500${i?`&hook_type=${i}`:""}`,r=await fetch(c);if(!r.ok)throw new Error("Failed to fetch events");return r.json()}const H=["","UserPromptSubmit","PreToolUse","PostToolUse","Stop","Notification"];function B(){const[i,c]=n.useState(""),[r,j]=n.useState(""),[s,p]=n.useState(null),[v,m]=n.useState(!1),f=E(),{data:x,isLoading:b}=N({queryKey:["events",i],queryFn:()=>D(i),refetchInterval:5e3}),o=n.useMemo(()=>{if(!x)return[];if(!r.trim())return x;const t=r.toLowerCase();return x.filter(l=>{var d,a;return((d=l.tool_name)==null?void 0:d.toLowerCase().includes(t))||((a=l.user_prompt)==null?void 0:a.toLowerCase().includes(t))||l.session_id.toLowerCase().includes(t)||JSON.stringify(l.tool_input||"").toLowerCase().includes(t)})},[x,r]),h=t=>{const l=k();if(t==="json")S(`events-${l}.json`,o);else{const d=o.map(a=>({event_id:a.event_id,session_id:a.session_id,timestamp:a.timestamp,hook_type:a.hook_type,tool_name:a.tool_name||"",user_prompt:a.user_prompt||"",tool_input:a.tool_input?JSON.stringify(a.tool_input).slice(0,500):""}));C(`events-${l}.csv`,d)}f.success(`已导出 ${o.length} 条事件`),m(!1)};return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4 flex-wrap gap-3",children:[e.jsx("h1",{className:"text-2xl font-bold text-gray-900",children:"事件"}),e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx(_,{value:r,onChange:j,placeholder:"搜索提示/工具/session...",className:"w-64"}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(P,{className:"h-4 w-4 text-gray-500"}),e.jsx("select",{value:i,onChange:t=>c(t.target.value),className:"text-sm border border-gray-300 rounded-md px-2 py-1.5 bg-white",children:H.map(t=>e.jsx("option",{value:t,children:t||"全部类型"},t))})]}),e.jsxs("div",{className:"relative",children:[e.jsxs("button",{onClick:()=>m(t=>!t),disabled:o.length===0,className:"inline-flex items-center gap-1 px-3 py-1.5 text-sm bg-white border border-gray-300 rounded-md hover:bg-gray-50 disabled:opacity-50",children:[e.jsx(U,{className:"h-4 w-4"}),"导出"]}),v&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"fixed inset-0 z-10",onClick:()=>m(!1)}),e.jsxs("div",{className:"absolute right-0 mt-1 bg-white border border-gray-200 rounded-md shadow-lg z-20",children:[e.jsx("button",{onClick:()=>h("json"),className:"block w-full text-left px-4 py-2 text-sm hover:bg-gray-50",children:"导出为 JSON"}),e.jsx("button",{onClick:()=>h("csv"),className:"block w-full text-left px-4 py-2 text-sm hover:bg-gray-50",children:"导出为 CSV"})]})]})]})]})]}),e.jsxs("div",{className:"text-sm text-gray-500 mb-3",children:["显示 ",o.length," 条 ",r&&"(已过滤)"]}),e.jsx("div",{className:"bg-white rounded-lg shadow overflow-hidden",children:b?e.jsx("div",{className:"p-6 text-gray-600",children:"加载中..."}):e.jsxs("table",{className:"min-w-full divide-y divide-gray-200",children:[e.jsx("thead",{className:"bg-gray-50",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"时间"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"类型"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"工具"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"详情"})]})}),e.jsxs("tbody",{className:"bg-white divide-y divide-gray-200",children:[o.map(t=>e.jsxs("tr",{className:"hover:bg-gray-50 cursor-pointer",onClick:()=>p(t),children:[e.jsx("td",{className:"px-4 py-2 whitespace-nowrap text-xs font-mono text-gray-500",children:t.timestamp?y(new Date(t.timestamp),"HH:mm:ss"):"-"}),e.jsx("td",{className:"px-4 py-2 whitespace-nowrap",children:e.jsx("span",{className:u("px-2 py-0.5 text-xs font-medium rounded",t.hook_type==="UserPromptSubmit"&&"bg-purple-100 text-purple-700",t.hook_type==="PreToolUse"&&"bg-blue-100 text-blue-700",t.hook_type==="PostToolUse"&&"bg-green-100 text-green-700",t.hook_type==="Stop"&&"bg-gray-100 text-gray-700",t.hook_type==="Notification"&&"bg-yellow-100 text-yellow-700"),children:t.hook_type})}),e.jsx("td",{className:"px-4 py-2 whitespace-nowrap text-sm text-gray-700",children:t.tool_name||"-"}),e.jsx("td",{className:"px-4 py-2 max-w-xl",children:e.jsx("p",{className:"text-xs text-gray-600 truncate",children:t.user_prompt||(t.tool_input?JSON.stringify(t.tool_input).slice(0,100):"-")})})]},t.event_id)),o.length===0&&e.jsx("tr",{children:e.jsxs("td",{colSpan:4,className:"px-4 py-12 text-center text-gray-500",children:[e.jsx(T,{className:"h-12 w-12 text-gray-300 mx-auto mb-2"}),r?"无匹配结果":"暂无事件"]})})]})]})}),e.jsx(w,{open:s!==null,onClose:()=>p(null),title:"事件详情",children:s&&e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"事件 ID"}),e.jsx("div",{className:"text-sm font-mono text-gray-900",children:s.event_id})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"类型"}),e.jsx("span",{className:u("px-2 py-1 text-xs font-medium rounded",s.hook_type==="UserPromptSubmit"&&"bg-purple-100 text-purple-700",s.hook_type==="PreToolUse"&&"bg-blue-100 text-blue-700",s.hook_type==="PostToolUse"&&"bg-green-100 text-green-700"),children:s.hook_type})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"时间"}),e.jsx("div",{className:"text-sm text-gray-900",children:s.timestamp?y(new Date(s.timestamp),"yyyy-MM-dd HH:mm:ss"):"-"})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"Session"}),e.jsx("div",{className:"text-sm font-mono text-gray-700",children:s.session_id})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"项目路径"}),e.jsx("div",{className:"text-sm font-mono text-gray-700 break-all",children:s.project_path})]}),s.tool_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-900",children:s.tool_name})]}),s.user_prompt&&e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"用户提示"}),e.jsx("div",{className:"bg-purple-50 rounded p-3 text-sm text-gray-800 whitespace-pre-wrap",children:s.user_prompt})]}),s.tool_input&&e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"工具输入"}),e.jsx(g,{data:s.tool_input,language:"json",maxHeight:"300px"})]}),s.tool_output&&e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"工具输出"}),e.jsx(g,{data:s.tool_output,language:typeof s.tool_output=="string"?"text":"json",maxHeight:"400px"})]})]})})]})}export{B as default};
|
|
2
|
+
//# sourceMappingURL=Events-DqzBTrly.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Events-BoQ8Fo5k.js","sources":["../../src/pages/Events.tsx"],"sourcesContent":["import { useQuery } from '@tanstack/react-query'\nimport { useState, useMemo } from 'react'\nimport { format } from 'date-fns'\nimport { Activity, Filter, Download } from 'lucide-react'\nimport clsx from 'clsx'\nimport Drawer from '../components/Drawer'\nimport CodeBlock from '../components/CodeBlock'\nimport SearchInput from '../components/SearchInput'\nimport { downloadJSON, downloadCSV, getTimestamp } from '../utils/export'\nimport { useToast } from '../components/Toast'\n\ninterface Event {\n event_id: string\n session_id: string\n project_path: string\n timestamp: string\n hook_type: string\n tool_name?: string\n tool_input?: any\n tool_output?: any\n user_prompt?: string\n ai_response?: string\n}\n\nasync function fetchEvents(hookType?: string): Promise<Event[]> {\n const url = `/api/events?limit=500${hookType ? `&hook_type=${hookType}` : ''}`\n const res = await fetch(url)\n if (!res.ok) throw new Error('Failed to fetch events')\n return res.json()\n}\n\nconst hookTypes = ['', 'UserPromptSubmit', 'PreToolUse', 'PostToolUse', 'Stop', 'Notification']\n\nexport default function Events() {\n const [filter, setFilter] = useState('')\n const [search, setSearch] = useState('')\n const [selectedEvent, setSelectedEvent] = useState<Event | null>(null)\n const [showExportMenu, setShowExportMenu] = useState(false)\n const toast = useToast()\n\n const { data: events, isLoading } = useQuery({\n queryKey: ['events', filter],\n queryFn: () => fetchEvents(filter),\n refetchInterval: 5000,\n })\n\n // 客户端搜索过滤\n const filteredEvents = useMemo(() => {\n if (!events) return []\n if (!search.trim()) return events\n const q = search.toLowerCase()\n return events.filter(e =>\n e.tool_name?.toLowerCase().includes(q) ||\n e.user_prompt?.toLowerCase().includes(q) ||\n e.session_id.toLowerCase().includes(q) ||\n JSON.stringify(e.tool_input || '').toLowerCase().includes(q)\n )\n }, [events, search])\n\n const handleExport = (exportFormat: 'json' | 'csv') => {\n const ts = getTimestamp()\n if (exportFormat === 'json') {\n downloadJSON(`events-${ts}.json`, filteredEvents)\n } else {\n // CSV 导出扁平化\n const flat = filteredEvents.map(e => ({\n event_id: e.event_id,\n session_id: e.session_id,\n timestamp: e.timestamp,\n hook_type: e.hook_type,\n tool_name: e.tool_name || '',\n user_prompt: e.user_prompt || '',\n tool_input: e.tool_input ? JSON.stringify(e.tool_input).slice(0, 500) : '',\n }))\n downloadCSV(`events-${ts}.csv`, flat)\n }\n toast.success(`已导出 ${filteredEvents.length} 条事件`)\n setShowExportMenu(false)\n }\n\n return (\n <div>\n <div className=\"flex items-center justify-between mb-4 flex-wrap gap-3\">\n <h1 className=\"text-2xl font-bold text-gray-900\">事件</h1>\n <div className=\"flex items-center gap-2 flex-wrap\">\n <SearchInput\n value={search}\n onChange={setSearch}\n placeholder=\"搜索提示/工具/session...\"\n className=\"w-64\"\n />\n <div className=\"flex items-center gap-1\">\n <Filter className=\"h-4 w-4 text-gray-500\" />\n <select\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n className=\"text-sm border border-gray-300 rounded-md px-2 py-1.5 bg-white\"\n >\n {hookTypes.map((t) => (\n <option key={t} value={t}>{t || '全部类型'}</option>\n ))}\n </select>\n </div>\n <div className=\"relative\">\n <button\n onClick={() => setShowExportMenu(v => !v)}\n disabled={filteredEvents.length === 0}\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm bg-white border border-gray-300 rounded-md hover:bg-gray-50 disabled:opacity-50\"\n >\n <Download className=\"h-4 w-4\" />\n 导出\n </button>\n {showExportMenu && (\n <>\n <div className=\"fixed inset-0 z-10\" onClick={() => setShowExportMenu(false)} />\n <div className=\"absolute right-0 mt-1 bg-white border border-gray-200 rounded-md shadow-lg z-20\">\n <button\n onClick={() => handleExport('json')}\n className=\"block w-full text-left px-4 py-2 text-sm hover:bg-gray-50\"\n >\n 导出为 JSON\n </button>\n <button\n onClick={() => handleExport('csv')}\n className=\"block w-full text-left px-4 py-2 text-sm hover:bg-gray-50\"\n >\n 导出为 CSV\n </button>\n </div>\n </>\n )}\n </div>\n </div>\n </div>\n\n <div className=\"text-sm text-gray-500 mb-3\">\n 显示 {filteredEvents.length} 条 {search && `(已过滤)`}\n </div>\n\n <div className=\"bg-white rounded-lg shadow overflow-hidden\">\n {isLoading ? (\n <div className=\"p-6 text-gray-600\">加载中...</div>\n ) : (\n <table className=\"min-w-full divide-y divide-gray-200\">\n <thead className=\"bg-gray-50\">\n <tr>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">时间</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">类型</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">工具</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">详情</th>\n </tr>\n </thead>\n <tbody className=\"bg-white divide-y divide-gray-200\">\n {filteredEvents.map((e) => (\n <tr\n key={e.event_id}\n className=\"hover:bg-gray-50 cursor-pointer\"\n onClick={() => setSelectedEvent(e)}\n >\n <td className=\"px-4 py-2 whitespace-nowrap text-xs font-mono text-gray-500\">\n {e.timestamp ? format(new Date(e.timestamp), 'HH:mm:ss') : '-'}\n </td>\n <td className=\"px-4 py-2 whitespace-nowrap\">\n <span className={clsx(\n 'px-2 py-0.5 text-xs font-medium rounded',\n e.hook_type === 'UserPromptSubmit' && 'bg-purple-100 text-purple-700',\n e.hook_type === 'PreToolUse' && 'bg-blue-100 text-blue-700',\n e.hook_type === 'PostToolUse' && 'bg-green-100 text-green-700',\n e.hook_type === 'Stop' && 'bg-gray-100 text-gray-700',\n e.hook_type === 'Notification' && 'bg-yellow-100 text-yellow-700'\n )}>\n {e.hook_type}\n </span>\n </td>\n <td className=\"px-4 py-2 whitespace-nowrap text-sm text-gray-700\">\n {e.tool_name || '-'}\n </td>\n <td className=\"px-4 py-2 max-w-xl\">\n <p className=\"text-xs text-gray-600 truncate\">\n {e.user_prompt || (e.tool_input ? JSON.stringify(e.tool_input).slice(0, 100) : '-')}\n </p>\n </td>\n </tr>\n ))}\n {filteredEvents.length === 0 && (\n <tr>\n <td colSpan={4} className=\"px-4 py-12 text-center text-gray-500\">\n <Activity className=\"h-12 w-12 text-gray-300 mx-auto mb-2\" />\n {search ? '无匹配结果' : '暂无事件'}\n </td>\n </tr>\n )}\n </tbody>\n </table>\n )}\n </div>\n\n {/* Event Detail Drawer */}\n <Drawer\n open={selectedEvent !== null}\n onClose={() => setSelectedEvent(null)}\n title=\"事件详情\"\n >\n {selectedEvent && (\n <div className=\"space-y-4\">\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">事件 ID</div>\n <div className=\"text-sm font-mono text-gray-900\">{selectedEvent.event_id}</div>\n </div>\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">类型</div>\n <span className={clsx(\n 'px-2 py-1 text-xs font-medium rounded',\n selectedEvent.hook_type === 'UserPromptSubmit' && 'bg-purple-100 text-purple-700',\n selectedEvent.hook_type === 'PreToolUse' && 'bg-blue-100 text-blue-700',\n selectedEvent.hook_type === 'PostToolUse' && 'bg-green-100 text-green-700',\n )}>\n {selectedEvent.hook_type}\n </span>\n </div>\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">时间</div>\n <div className=\"text-sm text-gray-900\">\n {selectedEvent.timestamp ? format(new Date(selectedEvent.timestamp), 'yyyy-MM-dd HH:mm:ss') : '-'}\n </div>\n </div>\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">Session</div>\n <div className=\"text-sm font-mono text-gray-700\">{selectedEvent.session_id}</div>\n </div>\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">项目路径</div>\n <div className=\"text-sm font-mono text-gray-700 break-all\">{selectedEvent.project_path}</div>\n </div>\n {selectedEvent.tool_name && (\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">工具</div>\n <div className=\"text-sm text-gray-900\">{selectedEvent.tool_name}</div>\n </div>\n )}\n {selectedEvent.user_prompt && (\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">用户提示</div>\n <div className=\"bg-purple-50 rounded p-3 text-sm text-gray-800 whitespace-pre-wrap\">\n {selectedEvent.user_prompt}\n </div>\n </div>\n )}\n {selectedEvent.tool_input && (\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">工具输入</div>\n <CodeBlock data={selectedEvent.tool_input} language=\"json\" maxHeight=\"300px\" />\n </div>\n )}\n {selectedEvent.tool_output && (\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">工具输出</div>\n <CodeBlock\n data={selectedEvent.tool_output}\n language={typeof selectedEvent.tool_output === 'string' ? 'text' : 'json'}\n maxHeight=\"400px\"\n />\n </div>\n )}\n </div>\n )}\n </Drawer>\n </div>\n )\n}\n"],"names":["fetchEvents","hookType","url","res","hookTypes","Events","filter","setFilter","useState","search","setSearch","selectedEvent","setSelectedEvent","showExportMenu","setShowExportMenu","toast","useToast","events","isLoading","useQuery","filteredEvents","useMemo","q","e","_a","_b","handleExport","exportFormat","ts","getTimestamp","downloadJSON","flat","downloadCSV","jsxs","jsx","SearchInput","Filter","v","Download","Fragment","format","clsx","Activity","Drawer","CodeBlock"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Events-DqzBTrly.js","sources":["../../src/pages/Events.tsx"],"sourcesContent":["import { useQuery } from '@tanstack/react-query'\nimport { useState, useMemo } from 'react'\nimport { format } from 'date-fns'\nimport { Activity, Filter, Download } from 'lucide-react'\nimport clsx from 'clsx'\nimport Drawer from '../components/Drawer'\nimport CodeBlock from '../components/CodeBlock'\nimport SearchInput from '../components/SearchInput'\nimport { downloadJSON, downloadCSV, getTimestamp } from '../utils/export'\nimport { useToast } from '../components/Toast'\n\ninterface Event {\n event_id: string\n session_id: string\n project_path: string\n timestamp: string\n hook_type: string\n tool_name?: string\n tool_input?: any\n tool_output?: any\n user_prompt?: string\n ai_response?: string\n}\n\nasync function fetchEvents(hookType?: string): Promise<Event[]> {\n const url = `/api/events?limit=500${hookType ? `&hook_type=${hookType}` : ''}`\n const res = await fetch(url)\n if (!res.ok) throw new Error('Failed to fetch events')\n return res.json()\n}\n\nconst hookTypes = ['', 'UserPromptSubmit', 'PreToolUse', 'PostToolUse', 'Stop', 'Notification']\n\nexport default function Events() {\n const [filter, setFilter] = useState('')\n const [search, setSearch] = useState('')\n const [selectedEvent, setSelectedEvent] = useState<Event | null>(null)\n const [showExportMenu, setShowExportMenu] = useState(false)\n const toast = useToast()\n\n const { data: events, isLoading } = useQuery({\n queryKey: ['events', filter],\n queryFn: () => fetchEvents(filter),\n refetchInterval: 5000,\n })\n\n // 客户端搜索过滤\n const filteredEvents = useMemo(() => {\n if (!events) return []\n if (!search.trim()) return events\n const q = search.toLowerCase()\n return events.filter(e =>\n e.tool_name?.toLowerCase().includes(q) ||\n e.user_prompt?.toLowerCase().includes(q) ||\n e.session_id.toLowerCase().includes(q) ||\n JSON.stringify(e.tool_input || '').toLowerCase().includes(q)\n )\n }, [events, search])\n\n const handleExport = (exportFormat: 'json' | 'csv') => {\n const ts = getTimestamp()\n if (exportFormat === 'json') {\n downloadJSON(`events-${ts}.json`, filteredEvents)\n } else {\n // CSV 导出扁平化\n const flat = filteredEvents.map(e => ({\n event_id: e.event_id,\n session_id: e.session_id,\n timestamp: e.timestamp,\n hook_type: e.hook_type,\n tool_name: e.tool_name || '',\n user_prompt: e.user_prompt || '',\n tool_input: e.tool_input ? JSON.stringify(e.tool_input).slice(0, 500) : '',\n }))\n downloadCSV(`events-${ts}.csv`, flat)\n }\n toast.success(`已导出 ${filteredEvents.length} 条事件`)\n setShowExportMenu(false)\n }\n\n return (\n <div>\n <div className=\"flex items-center justify-between mb-4 flex-wrap gap-3\">\n <h1 className=\"text-2xl font-bold text-gray-900\">事件</h1>\n <div className=\"flex items-center gap-2 flex-wrap\">\n <SearchInput\n value={search}\n onChange={setSearch}\n placeholder=\"搜索提示/工具/session...\"\n className=\"w-64\"\n />\n <div className=\"flex items-center gap-1\">\n <Filter className=\"h-4 w-4 text-gray-500\" />\n <select\n value={filter}\n onChange={(e) => setFilter(e.target.value)}\n className=\"text-sm border border-gray-300 rounded-md px-2 py-1.5 bg-white\"\n >\n {hookTypes.map((t) => (\n <option key={t} value={t}>{t || '全部类型'}</option>\n ))}\n </select>\n </div>\n <div className=\"relative\">\n <button\n onClick={() => setShowExportMenu(v => !v)}\n disabled={filteredEvents.length === 0}\n className=\"inline-flex items-center gap-1 px-3 py-1.5 text-sm bg-white border border-gray-300 rounded-md hover:bg-gray-50 disabled:opacity-50\"\n >\n <Download className=\"h-4 w-4\" />\n 导出\n </button>\n {showExportMenu && (\n <>\n <div className=\"fixed inset-0 z-10\" onClick={() => setShowExportMenu(false)} />\n <div className=\"absolute right-0 mt-1 bg-white border border-gray-200 rounded-md shadow-lg z-20\">\n <button\n onClick={() => handleExport('json')}\n className=\"block w-full text-left px-4 py-2 text-sm hover:bg-gray-50\"\n >\n 导出为 JSON\n </button>\n <button\n onClick={() => handleExport('csv')}\n className=\"block w-full text-left px-4 py-2 text-sm hover:bg-gray-50\"\n >\n 导出为 CSV\n </button>\n </div>\n </>\n )}\n </div>\n </div>\n </div>\n\n <div className=\"text-sm text-gray-500 mb-3\">\n 显示 {filteredEvents.length} 条 {search && `(已过滤)`}\n </div>\n\n <div className=\"bg-white rounded-lg shadow overflow-hidden\">\n {isLoading ? (\n <div className=\"p-6 text-gray-600\">加载中...</div>\n ) : (\n <table className=\"min-w-full divide-y divide-gray-200\">\n <thead className=\"bg-gray-50\">\n <tr>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">时间</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">类型</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">工具</th>\n <th className=\"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase\">详情</th>\n </tr>\n </thead>\n <tbody className=\"bg-white divide-y divide-gray-200\">\n {filteredEvents.map((e) => (\n <tr\n key={e.event_id}\n className=\"hover:bg-gray-50 cursor-pointer\"\n onClick={() => setSelectedEvent(e)}\n >\n <td className=\"px-4 py-2 whitespace-nowrap text-xs font-mono text-gray-500\">\n {e.timestamp ? format(new Date(e.timestamp), 'HH:mm:ss') : '-'}\n </td>\n <td className=\"px-4 py-2 whitespace-nowrap\">\n <span className={clsx(\n 'px-2 py-0.5 text-xs font-medium rounded',\n e.hook_type === 'UserPromptSubmit' && 'bg-purple-100 text-purple-700',\n e.hook_type === 'PreToolUse' && 'bg-blue-100 text-blue-700',\n e.hook_type === 'PostToolUse' && 'bg-green-100 text-green-700',\n e.hook_type === 'Stop' && 'bg-gray-100 text-gray-700',\n e.hook_type === 'Notification' && 'bg-yellow-100 text-yellow-700'\n )}>\n {e.hook_type}\n </span>\n </td>\n <td className=\"px-4 py-2 whitespace-nowrap text-sm text-gray-700\">\n {e.tool_name || '-'}\n </td>\n <td className=\"px-4 py-2 max-w-xl\">\n <p className=\"text-xs text-gray-600 truncate\">\n {e.user_prompt || (e.tool_input ? JSON.stringify(e.tool_input).slice(0, 100) : '-')}\n </p>\n </td>\n </tr>\n ))}\n {filteredEvents.length === 0 && (\n <tr>\n <td colSpan={4} className=\"px-4 py-12 text-center text-gray-500\">\n <Activity className=\"h-12 w-12 text-gray-300 mx-auto mb-2\" />\n {search ? '无匹配结果' : '暂无事件'}\n </td>\n </tr>\n )}\n </tbody>\n </table>\n )}\n </div>\n\n {/* Event Detail Drawer */}\n <Drawer\n open={selectedEvent !== null}\n onClose={() => setSelectedEvent(null)}\n title=\"事件详情\"\n >\n {selectedEvent && (\n <div className=\"space-y-4\">\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">事件 ID</div>\n <div className=\"text-sm font-mono text-gray-900\">{selectedEvent.event_id}</div>\n </div>\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">类型</div>\n <span className={clsx(\n 'px-2 py-1 text-xs font-medium rounded',\n selectedEvent.hook_type === 'UserPromptSubmit' && 'bg-purple-100 text-purple-700',\n selectedEvent.hook_type === 'PreToolUse' && 'bg-blue-100 text-blue-700',\n selectedEvent.hook_type === 'PostToolUse' && 'bg-green-100 text-green-700',\n )}>\n {selectedEvent.hook_type}\n </span>\n </div>\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">时间</div>\n <div className=\"text-sm text-gray-900\">\n {selectedEvent.timestamp ? format(new Date(selectedEvent.timestamp), 'yyyy-MM-dd HH:mm:ss') : '-'}\n </div>\n </div>\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">Session</div>\n <div className=\"text-sm font-mono text-gray-700\">{selectedEvent.session_id}</div>\n </div>\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">项目路径</div>\n <div className=\"text-sm font-mono text-gray-700 break-all\">{selectedEvent.project_path}</div>\n </div>\n {selectedEvent.tool_name && (\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">工具</div>\n <div className=\"text-sm text-gray-900\">{selectedEvent.tool_name}</div>\n </div>\n )}\n {selectedEvent.user_prompt && (\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">用户提示</div>\n <div className=\"bg-purple-50 rounded p-3 text-sm text-gray-800 whitespace-pre-wrap\">\n {selectedEvent.user_prompt}\n </div>\n </div>\n )}\n {selectedEvent.tool_input && (\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">工具输入</div>\n <CodeBlock data={selectedEvent.tool_input} language=\"json\" maxHeight=\"300px\" />\n </div>\n )}\n {selectedEvent.tool_output && (\n <div>\n <div className=\"text-xs text-gray-500 mb-1\">工具输出</div>\n <CodeBlock\n data={selectedEvent.tool_output}\n language={typeof selectedEvent.tool_output === 'string' ? 'text' : 'json'}\n maxHeight=\"400px\"\n />\n </div>\n )}\n </div>\n )}\n </Drawer>\n </div>\n )\n}\n"],"names":["fetchEvents","hookType","url","res","hookTypes","Events","filter","setFilter","useState","search","setSearch","selectedEvent","setSelectedEvent","showExportMenu","setShowExportMenu","toast","useToast","events","isLoading","useQuery","filteredEvents","useMemo","q","e","_a","_b","handleExport","exportFormat","ts","getTimestamp","downloadJSON","flat","downloadCSV","jsxs","jsx","SearchInput","Filter","v","Download","Fragment","format","clsx","Activity","Drawer","CodeBlock"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{r as x,j as e}from"./react-vendor-CSp-GLFF.js";import{b as _,u as C}from"./query-C99w429o.js";import{d as S}from"./vendor-CMMjVdZs.js";import{D as k}from"./Drawer-DeKukfwJ.js";import{C as E}from"./CodeBlock--H53gk46.js";import{S as F,g as M,d as O,a as H}from"./export-CEzDNM66.js";import{u as J}from"./index-
|
|
2
|
-
//# sourceMappingURL=ExecutionTrace-
|
|
1
|
+
import{r as x,j as e}from"./react-vendor-CSp-GLFF.js";import{b as _,u as C}from"./query-C99w429o.js";import{d as S}from"./vendor-CMMjVdZs.js";import{D as k}from"./Drawer-DeKukfwJ.js";import{C as E}from"./CodeBlock--H53gk46.js";import{S as F,g as M,d as O,a as H}from"./export-CEzDNM66.js";import{u as J}from"./index-BVpUTHdp.js";import{W as T,l as q,D as L,e as $,d as D,m as Q,A as W}from"./lucide-DjB4fWNj.js";import{f as j}from"./date-fns-CZ_bHujz.js";import"./syntax-highlighter-44FakypI.js";import"./react-router-I-HqunH7.js";async function z(l){let c="/api/routing/events?limit=200";l==="obeyed"?c+="&obeyed=1":l==="refused"?c+="&obeyed=0":l==="unknown"&&(c+="&obeyed=null");const n=await fetch(c);if(!n.ok)throw new Error("Failed to fetch");return n.json()}const A=[{value:"",label:"全部"},{value:"obeyed",label:"✅ 遵守"},{value:"refused",label:"❌ 违抗"},{value:"unknown",label:"? 未判定"}];function ee(){const[l,c]=x.useState(""),[n,f]=x.useState(""),[t,u]=x.useState(null),[v,p]=x.useState(!1),[N,h]=x.useState(!1),b=J(),g=_();x.useEffect(()=>{const s=new EventSource("/api/execution-trace/stream");return s.onopen=()=>p(!0),s.onerror=()=>p(!1),s.onmessage=r=>{try{JSON.parse(r.data).type==="execution-status"&&g.invalidateQueries({queryKey:["routing-events"]})}catch{}},()=>{s.close(),p(!1)}},[g]);const{data:m,isLoading:w}=C({queryKey:["routing-events",l],queryFn:()=>z(l),refetchInterval:1e4}),i=x.useMemo(()=>{if(!m)return[];if(!n.trim())return m;const s=n.toLowerCase();return m.filter(r=>{var o,a,d;return((o=r.prompt)==null?void 0:o.toLowerCase().includes(s))||((a=r.routed_to_name)==null?void 0:a.toLowerCase().includes(s))||((d=r.first_tool_name)==null?void 0:d.toLowerCase().includes(s))})},[m,n]),y=s=>{const r=M();if(s==="json")O(`routing-events-${r}.json`,i);else{const o=i.map(a=>{let d={};try{d=JSON.parse(a.intent_json||"{}")}catch{}return{id:a.id,ts:a.ts?j(a.ts,"yyyy-MM-dd HH:mm:ss"):"",prompt:a.prompt,taskType:d.taskType||"",complexity:d.complexity||"",routed_to:a.routed_to_name||"",obeyed:a.obeyed===1?"yes":a.obeyed===0?"no":"",first_tool:a.first_tool_name||"",duration_ms:a.total_execution_ms||"",refusal_reason:a.refusal_reason||""}});H(`routing-events-${r}.csv`,o)}b.success(`已导出 ${i.length} 条追踪记录`),h(!1)};return e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-4 flex-wrap gap-3",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-gray-900",children:"执行追踪"}),e.jsx("div",{className:"flex items-center gap-2 mt-1",children:v?e.jsxs(e.Fragment,{children:[e.jsx(T,{className:"h-3 w-3 text-green-500"}),e.jsx("span",{className:"text-xs text-green-600",children:"实时流已连接"})]}):e.jsxs(e.Fragment,{children:[e.jsx(q,{className:"h-3 w-3 text-gray-400"}),e.jsx("span",{className:"text-xs text-gray-500",children:"实时流未连接"})]})})]}),e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsx(F,{value:n,onChange:f,placeholder:"搜索 prompt / agent / tool...",className:"w-56"}),e.jsx("div",{className:"flex items-center gap-1",children:A.map(s=>e.jsx("button",{onClick:()=>c(s.value),className:S("px-2.5 py-1.5 text-xs rounded-md",l===s.value?"bg-indigo-100 text-indigo-700":"bg-white text-gray-600 border border-gray-300 hover:bg-gray-50"),children:s.label},s.value))}),e.jsxs("div",{className:"relative",children:[e.jsxs("button",{onClick:()=>h(s=>!s),disabled:i.length===0,className:"inline-flex items-center gap-1 px-3 py-1.5 text-sm bg-white border border-gray-300 rounded-md hover:bg-gray-50 disabled:opacity-50",children:[e.jsx(L,{className:"h-4 w-4"}),"导出"]}),N&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"fixed inset-0 z-10",onClick:()=>h(!1)}),e.jsxs("div",{className:"absolute right-0 mt-1 bg-white border border-gray-200 rounded-md shadow-lg z-20",children:[e.jsx("button",{onClick:()=>y("json"),className:"block w-full text-left px-4 py-2 text-sm hover:bg-gray-50",children:"导出为 JSON"}),e.jsx("button",{onClick:()=>y("csv"),className:"block w-full text-left px-4 py-2 text-sm hover:bg-gray-50",children:"导出为 CSV"})]})]})]})]})]}),e.jsxs("div",{className:"text-sm text-gray-500 mb-3",children:["显示 ",i.length," 条 ",n&&"(已过滤)"]}),e.jsx("div",{className:"bg-white rounded-lg shadow overflow-hidden",children:w?e.jsx("div",{className:"p-6",children:"加载中..."}):e.jsxs("table",{className:"min-w-full divide-y divide-gray-200",children:[e.jsx("thead",{className:"bg-gray-50",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"时间"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"提示"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"路由到"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"遵守"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"首工具"}),e.jsx("th",{className:"px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase",children:"耗时"})]})}),e.jsxs("tbody",{className:"bg-white divide-y divide-gray-200",children:[i.map(s=>{let r={};try{r=JSON.parse(s.intent_json||"{}")}catch{}return e.jsxs("tr",{className:"hover:bg-gray-50 cursor-pointer",onClick:()=>u(s),children:[e.jsx("td",{className:"px-4 py-2 whitespace-nowrap text-xs font-mono text-gray-500",children:j(s.ts,"MM-dd HH:mm:ss")}),e.jsxs("td",{className:"px-4 py-2 max-w-xs",children:[e.jsx("p",{className:"text-xs text-gray-700 truncate",title:s.prompt,children:s.prompt}),e.jsxs("p",{className:"text-xs text-gray-400 mt-0.5",children:[r.taskType," / ",r.complexity]})]}),e.jsx("td",{className:"px-4 py-2 whitespace-nowrap",children:s.routed_to_name?e.jsx("span",{className:"px-2 py-0.5 text-xs font-medium bg-indigo-100 text-indigo-700 rounded",children:s.routed_to_name}):e.jsx("span",{className:"text-xs text-gray-400",children:"未路由"})}),e.jsx("td",{className:"px-4 py-2 whitespace-nowrap",children:s.obeyed===1?e.jsxs("span",{className:"inline-flex items-center gap-1 text-green-600 text-xs",children:[e.jsx($,{className:"h-4 w-4"}),"遵守"]}):s.obeyed===0?e.jsxs("span",{className:"inline-flex items-center gap-1 text-red-600 text-xs",children:[e.jsx(D,{className:"h-4 w-4"}),"违抗"]}):e.jsxs("span",{className:"inline-flex items-center gap-1 text-gray-400 text-xs",children:[e.jsx(Q,{className:"h-4 w-4"}),"?"]})}),e.jsx("td",{className:"px-4 py-2 whitespace-nowrap text-xs text-gray-700",children:s.first_tool_name||"-"}),e.jsx("td",{className:"px-4 py-2 whitespace-nowrap text-xs font-mono text-gray-500",children:s.total_execution_ms?`${(s.total_execution_ms/1e3).toFixed(1)}s`:"-"})]},s.id)}),i.length===0&&e.jsx("tr",{children:e.jsxs("td",{colSpan:6,className:"px-4 py-12 text-center text-gray-500",children:[e.jsx(W,{className:"h-12 w-12 text-gray-300 mx-auto mb-2"}),n?"无匹配结果":"暂无追踪记录"]})})]})]})}),e.jsx(k,{open:t!==null,onClose:()=>u(null),title:"路由决策详情",children:t&&(()=>{let s={};try{s=JSON.parse(t.intent_json||"{}")}catch{}return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"用户提示"}),e.jsx("div",{className:"bg-purple-50 rounded p-3 text-sm text-gray-800 whitespace-pre-wrap",children:t.prompt})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"路由结果"}),e.jsx("div",{className:"text-sm font-medium",children:t.routed_to_name||"未路由"})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"遵守状态"}),e.jsxs("div",{children:[t.obeyed===1&&e.jsx("span",{className:"text-green-600 text-sm",children:"✅ 遵守"}),t.obeyed===0&&e.jsx("span",{className:"text-red-600 text-sm",children:"❌ 违抗"}),t.obeyed===null&&e.jsx("span",{className:"text-gray-400 text-sm",children:"未判定"})]})]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"意图分类"}),e.jsx(E,{data:s,language:"json",maxHeight:"200px"})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-3 text-sm",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"首工具"}),e.jsx("div",{className:"font-mono",children:t.first_tool_name||"-"})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"分类耗时"}),e.jsxs("div",{className:"font-mono",children:[t.classification_ms,"ms"]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"总执行时间"}),e.jsx("div",{className:"font-mono",children:t.total_execution_ms?`${(t.total_execution_ms/1e3).toFixed(2)}s`:"-"})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"完成原因"}),e.jsx("div",{children:t.completion_reason||"-"})]})]}),t.refusal_reason&&e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"违抗原因"}),e.jsx("div",{className:"bg-red-50 rounded p-3 text-sm text-red-700",children:t.refusal_reason})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500 mb-1",children:"Session"}),e.jsx("div",{className:"text-xs font-mono text-gray-700",children:t.session_id})]})]})})()})]})}export{ee as default};
|
|
2
|
+
//# sourceMappingURL=ExecutionTrace-Z-zlH0KH.js.map
|