work-agent 0.1.0

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 (245) hide show
  1. package/README.md +234 -0
  2. package/app/(admin)/approvals/page.tsx +16 -0
  3. package/app/(admin)/audit/page.tsx +18 -0
  4. package/app/(admin)/layout.tsx +47 -0
  5. package/app/(admin)/scheduled-tasks/page.tsx +17 -0
  6. package/app/(admin)/settings/page.tsx +46 -0
  7. package/app/(admin)/skills/[name]/page.tsx +378 -0
  8. package/app/(admin)/skills/page.tsx +406 -0
  9. package/app/(admin)/statistics/page.tsx +416 -0
  10. package/app/(admin)/tickets/[id]/page.tsx +348 -0
  11. package/app/(admin)/tickets/new/page.tsx +309 -0
  12. package/app/(admin)/tickets/page.tsx +27 -0
  13. package/app/api/audit/route.ts +30 -0
  14. package/app/api/auth/feishu/callback/route.ts +72 -0
  15. package/app/api/auth/feishu/login/route.ts +17 -0
  16. package/app/api/auth/feishu/sso/route.ts +78 -0
  17. package/app/api/auth/login/route.ts +85 -0
  18. package/app/api/auth/oauth/route.ts +168 -0
  19. package/app/api/config/providers/route.ts +105 -0
  20. package/app/api/config/route.ts +115 -0
  21. package/app/api/config/status/route.ts +56 -0
  22. package/app/api/config/test/route.ts +212 -0
  23. package/app/api/documents/[id]/route.ts +88 -0
  24. package/app/api/documents/route.ts +53 -0
  25. package/app/api/health/route.ts +32 -0
  26. package/app/api/knowledge/[id]/route.ts +152 -0
  27. package/app/api/knowledge/from-session/route.ts +27 -0
  28. package/app/api/knowledge/route.ts +100 -0
  29. package/app/api/market/knowledge/[id]/route.ts +92 -0
  30. package/app/api/market/knowledge/route.ts +130 -0
  31. package/app/api/marketplace/skills/[id]/approve/route.ts +68 -0
  32. package/app/api/marketplace/skills/[id]/certify/route.ts +54 -0
  33. package/app/api/marketplace/skills/[id]/install/route.ts +180 -0
  34. package/app/api/marketplace/skills/[id]/promote-to-system/route.ts +219 -0
  35. package/app/api/marketplace/skills/[id]/rate/route.ts +90 -0
  36. package/app/api/marketplace/skills/[id]/ratings/route.ts +55 -0
  37. package/app/api/marketplace/skills/[id]/reject/route.ts +68 -0
  38. package/app/api/marketplace/skills/[id]/route.ts +177 -0
  39. package/app/api/marketplace/skills/route.ts +235 -0
  40. package/app/api/memory/route.ts +40 -0
  41. package/app/api/my/files/[id]/route.ts +52 -0
  42. package/app/api/my/files/route.ts +230 -0
  43. package/app/api/my/knowledge/route.ts +36 -0
  44. package/app/api/pi-chat/route.ts +443 -0
  45. package/app/api/recommend/route.ts +38 -0
  46. package/app/api/scheduled-tasks/[id]/execute/route.ts +132 -0
  47. package/app/api/scheduled-tasks/[id]/route.ts +165 -0
  48. package/app/api/scheduled-tasks/[id]/toggle/route.ts +53 -0
  49. package/app/api/scheduled-tasks/route.ts +101 -0
  50. package/app/api/sessions/[id]/messages/route.ts +212 -0
  51. package/app/api/sessions/route.ts +101 -0
  52. package/app/api/share/file/[id]/route.ts +37 -0
  53. package/app/api/skills/[name]/execute/route.ts +121 -0
  54. package/app/api/skills/[name]/route.ts +167 -0
  55. package/app/api/skills/create/route.ts +65 -0
  56. package/app/api/skills/generate/route.ts +405 -0
  57. package/app/api/skills/installed/route.ts +151 -0
  58. package/app/api/skills/route.ts +174 -0
  59. package/app/api/skills/translate/route.ts +40 -0
  60. package/app/api/skills/user/[name]/route.ts +159 -0
  61. package/app/api/skills/user/route.ts +90 -0
  62. package/app/api/statistics/route.ts +94 -0
  63. package/app/api/task-executions/[id]/route.ts +34 -0
  64. package/app/api/task-executions/route.ts +29 -0
  65. package/app/api/tickets/[id]/approve/route.ts +129 -0
  66. package/app/api/tickets/[id]/execute/route.ts +201 -0
  67. package/app/api/tickets/[id]/route.ts +127 -0
  68. package/app/api/tickets/route.ts +103 -0
  69. package/app/api/user/skills/route.ts +175 -0
  70. package/app/api/users/route.ts +80 -0
  71. package/app/chat/page.tsx +5 -0
  72. package/app/globals.css +84 -0
  73. package/app/h5/layout.tsx +5 -0
  74. package/app/h5/mobile-approvals-page.tsx +167 -0
  75. package/app/h5/mobile-chat-page.tsx +951 -0
  76. package/app/h5/mobile-profile-page.tsx +147 -0
  77. package/app/h5/mobile-tickets-page.tsx +121 -0
  78. package/app/h5/page.tsx +23 -0
  79. package/app/h5/ticket-action-buttons.tsx +80 -0
  80. package/app/layout.tsx +26 -0
  81. package/app/login/page.tsx +318 -0
  82. package/app/market/knowledge/[id]/page.tsx +77 -0
  83. package/app/market/knowledge/page.tsx +358 -0
  84. package/app/market/layout.tsx +29 -0
  85. package/app/market/page.tsx +18 -0
  86. package/app/market/skills/page.tsx +397 -0
  87. package/app/my/files/page.tsx +511 -0
  88. package/app/my/knowledge/[id]/page.tsx +271 -0
  89. package/app/my/knowledge/new/page.tsx +234 -0
  90. package/app/my/knowledge/page.tsx +248 -0
  91. package/app/my/layout.tsx +32 -0
  92. package/app/my/memory/page.tsx +164 -0
  93. package/app/my/page.tsx +18 -0
  94. package/app/my/scheduled-tasks/[id]/edit/page.tsx +290 -0
  95. package/app/my/scheduled-tasks/[id]/executions/page.tsx +275 -0
  96. package/app/my/scheduled-tasks/[id]/page.tsx +284 -0
  97. package/app/my/scheduled-tasks/new/page.tsx +230 -0
  98. package/app/my/scheduled-tasks/page.tsx +27 -0
  99. package/app/my/skills/[name]/page.tsx +320 -0
  100. package/app/my/skills/new/page.tsx +394 -0
  101. package/app/my/skills/page.tsx +303 -0
  102. package/app/page.tsx +2288 -0
  103. package/app/share/[sessionId]/page.tsx +226 -0
  104. package/app/share/file/[id]/page.tsx +140 -0
  105. package/bin/README.md +63 -0
  106. package/bin/generate-api-system +300 -0
  107. package/bin/postinstall.js +95 -0
  108. package/bin/work-agent.js +173 -0
  109. package/components/ai-elements/agent.tsx +142 -0
  110. package/components/ai-elements/artifact.tsx +149 -0
  111. package/components/ai-elements/attachments.tsx +427 -0
  112. package/components/ai-elements/audio-player.tsx +232 -0
  113. package/components/ai-elements/canvas.tsx +26 -0
  114. package/components/ai-elements/chain-of-thought.tsx +223 -0
  115. package/components/ai-elements/checkpoint.tsx +72 -0
  116. package/components/ai-elements/code-block.tsx +555 -0
  117. package/components/ai-elements/commit.tsx +449 -0
  118. package/components/ai-elements/confirmation.tsx +173 -0
  119. package/components/ai-elements/connection.tsx +28 -0
  120. package/components/ai-elements/context.tsx +410 -0
  121. package/components/ai-elements/controls.tsx +19 -0
  122. package/components/ai-elements/conversation.tsx +167 -0
  123. package/components/ai-elements/edge.tsx +144 -0
  124. package/components/ai-elements/environment-variables.tsx +325 -0
  125. package/components/ai-elements/file-tree.tsx +298 -0
  126. package/components/ai-elements/image.tsx +25 -0
  127. package/components/ai-elements/inline-citation.tsx +294 -0
  128. package/components/ai-elements/jsx-preview.tsx +250 -0
  129. package/components/ai-elements/message.tsx +367 -0
  130. package/components/ai-elements/mic-selector.tsx +372 -0
  131. package/components/ai-elements/model-selector.tsx +214 -0
  132. package/components/ai-elements/node.tsx +72 -0
  133. package/components/ai-elements/open-in-chat.tsx +367 -0
  134. package/components/ai-elements/package-info.tsx +235 -0
  135. package/components/ai-elements/panel.tsx +16 -0
  136. package/components/ai-elements/persona.tsx +280 -0
  137. package/components/ai-elements/plan.tsx +144 -0
  138. package/components/ai-elements/prompt-input.tsx +1341 -0
  139. package/components/ai-elements/queue.tsx +275 -0
  140. package/components/ai-elements/reasoning.tsx +355 -0
  141. package/components/ai-elements/sandbox.tsx +133 -0
  142. package/components/ai-elements/schema-display.tsx +473 -0
  143. package/components/ai-elements/shimmer.tsx +78 -0
  144. package/components/ai-elements/snippet.tsx +141 -0
  145. package/components/ai-elements/sources.tsx +78 -0
  146. package/components/ai-elements/speech-input.tsx +324 -0
  147. package/components/ai-elements/stack-trace.tsx +531 -0
  148. package/components/ai-elements/suggestion.tsx +58 -0
  149. package/components/ai-elements/task.tsx +88 -0
  150. package/components/ai-elements/terminal.tsx +277 -0
  151. package/components/ai-elements/test-results.tsx +497 -0
  152. package/components/ai-elements/tool.tsx +174 -0
  153. package/components/ai-elements/toolbar.tsx +17 -0
  154. package/components/ai-elements/transcription.tsx +126 -0
  155. package/components/ai-elements/voice-selector.tsx +525 -0
  156. package/components/ai-elements/web-preview.tsx +282 -0
  157. package/components/audit-log-list.tsx +114 -0
  158. package/components/chat/EmptyPreviewState.tsx +12 -0
  159. package/components/chat/KnowledgePickerDialog.tsx +464 -0
  160. package/components/chat/KnowledgePreview.tsx +70 -0
  161. package/components/chat/KnowledgePreviewPanel.tsx +86 -0
  162. package/components/chat/MentionInput.tsx +309 -0
  163. package/components/chat/OrganizeDialog.tsx +258 -0
  164. package/components/chat/RecommendationBanner.tsx +94 -0
  165. package/components/chat/SaveToKnowledgeDialog.tsx +193 -0
  166. package/components/chat/SkillSelector.tsx +305 -0
  167. package/components/chat/SkillSwitcher.tsx +163 -0
  168. package/components/client-layout.tsx +15 -0
  169. package/components/knowledge/KnowledgeMetadataPanel.tsx +293 -0
  170. package/components/layout-wrapper.tsx +18 -0
  171. package/components/mobile-layout.tsx +62 -0
  172. package/components/scheduled-task-list.tsx +356 -0
  173. package/components/setup-guide.tsx +484 -0
  174. package/components/sub-nav.tsx +54 -0
  175. package/components/ticket-detail-content.tsx +383 -0
  176. package/components/ticket-list.tsx +366 -0
  177. package/components/top-nav.tsx +132 -0
  178. package/components/ui/accordion.tsx +58 -0
  179. package/components/ui/alert.tsx +59 -0
  180. package/components/ui/avatar.tsx +50 -0
  181. package/components/ui/badge.tsx +36 -0
  182. package/components/ui/button-group.tsx +83 -0
  183. package/components/ui/button.tsx +57 -0
  184. package/components/ui/card.tsx +91 -0
  185. package/components/ui/carousel.tsx +262 -0
  186. package/components/ui/collapsible.tsx +11 -0
  187. package/components/ui/command.tsx +153 -0
  188. package/components/ui/dialog.tsx +122 -0
  189. package/components/ui/dropdown-menu.tsx +200 -0
  190. package/components/ui/hover-card.tsx +29 -0
  191. package/components/ui/input-group.tsx +170 -0
  192. package/components/ui/input.tsx +22 -0
  193. package/components/ui/label.tsx +26 -0
  194. package/components/ui/popover.tsx +31 -0
  195. package/components/ui/progress.tsx +28 -0
  196. package/components/ui/scroll-area.tsx +48 -0
  197. package/components/ui/select.tsx +174 -0
  198. package/components/ui/separator.tsx +31 -0
  199. package/components/ui/spinner.tsx +16 -0
  200. package/components/ui/switch.tsx +29 -0
  201. package/components/ui/table.tsx +120 -0
  202. package/components/ui/tabs.tsx +55 -0
  203. package/components/ui/textarea.tsx +22 -0
  204. package/components/ui/tooltip.tsx +30 -0
  205. package/components/welcome-guide.tsx +182 -0
  206. package/components.json +24 -0
  207. package/lib/command-parser.ts +331 -0
  208. package/lib/dangerous-commands.ts +672 -0
  209. package/lib/db.ts +2250 -0
  210. package/lib/feishu-auth.ts +135 -0
  211. package/lib/file-storage.ts +306 -0
  212. package/lib/file-tool.ts +583 -0
  213. package/lib/knowledge-tool.ts +152 -0
  214. package/lib/knowledge-types.ts +66 -0
  215. package/lib/market-client.ts +313 -0
  216. package/lib/market-db.ts +736 -0
  217. package/lib/market-types.ts +51 -0
  218. package/lib/memory-tool.ts +211 -0
  219. package/lib/memory.ts +197 -0
  220. package/lib/pi-config.ts +436 -0
  221. package/lib/pi-session.ts +799 -0
  222. package/lib/pinyin.ts +13 -0
  223. package/lib/recommendation.ts +227 -0
  224. package/lib/risk-estimator.ts +350 -0
  225. package/lib/scheduled-task-tool.ts +184 -0
  226. package/lib/scheduler-init.ts +43 -0
  227. package/lib/scheduler.ts +416 -0
  228. package/lib/secure-bash-tool.ts +413 -0
  229. package/lib/skill-engine.ts +396 -0
  230. package/lib/skill-generator.ts +269 -0
  231. package/lib/skill-loader.ts +234 -0
  232. package/lib/skill-tool.ts +188 -0
  233. package/lib/skill-types.ts +82 -0
  234. package/lib/skills-init.ts +58 -0
  235. package/lib/ticket-tool.ts +246 -0
  236. package/lib/user-skill-types.ts +30 -0
  237. package/lib/user-skills.ts +362 -0
  238. package/lib/utils.ts +6 -0
  239. package/lib/workflow.ts +154 -0
  240. package/lib/zip-tool.ts +191 -0
  241. package/next.config.js +8 -0
  242. package/package.json +106 -0
  243. package/public/.gitkeep +1 -0
  244. package/public/icon.svg +1 -0
  245. package/tsconfig.json +42 -0
@@ -0,0 +1,378 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState, use } from 'react';
4
+ import Link from 'next/link';
5
+ import { useParams } from 'next/navigation';
6
+ import {
7
+ ArrowLeft,
8
+ Play,
9
+ Copy,
10
+ Check,
11
+ Shield,
12
+ ShieldAlert,
13
+ Terminal as TerminalIcon,
14
+ FileText,
15
+ Code,
16
+ Trash2,
17
+ Settings,
18
+ Eye
19
+ } from 'lucide-react';
20
+ import { Button } from '@/components/ui/button';
21
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
22
+ import { Badge } from '@/components/ui/badge';
23
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
24
+ import { Terminal, TerminalHeader, TerminalTitle, TerminalContent } from '@/components/ai-elements/terminal';
25
+ import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
26
+
27
+ interface Script {
28
+ name: string;
29
+ type: 'read_only' | 'modify';
30
+ description: string;
31
+ method: string;
32
+ path: string;
33
+ }
34
+
35
+ interface Skill {
36
+ name: string;
37
+ displayName?: string;
38
+ description?: string;
39
+ version?: string;
40
+ author?: string;
41
+ categories?: string[];
42
+ readme?: string;
43
+ config?: string;
44
+ scripts: Script[];
45
+ isBuiltIn: boolean;
46
+ skillPath: string;
47
+ }
48
+
49
+ export default function SkillDetailPage({ params }: { params: Promise<{ name: string }> }) {
50
+ const resolvedParams = use(params);
51
+ const [skill, setSkill] = useState<Skill | null>(null);
52
+ const [loading, setLoading] = useState(true);
53
+ const [selectedScript, setSelectedScript] = useState<Script | null>(null);
54
+ const [executing, setExecuting] = useState(false);
55
+ const [output, setOutput] = useState('');
56
+ const [showScriptDialog, setShowScriptDialog] = useState(false);
57
+ const [scriptContent, setScriptContent] = useState('');
58
+ const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
59
+
60
+ const fetchSkill = async () => {
61
+ try {
62
+ const res = await fetch(`/api/skills/${resolvedParams.name}`);
63
+ if (res.ok) {
64
+ const data = await res.json();
65
+ setSkill(data);
66
+ }
67
+ } catch (error) {
68
+ console.error('Failed to fetch skill:', error);
69
+ } finally {
70
+ setLoading(false);
71
+ }
72
+ };
73
+
74
+ useEffect(() => {
75
+ fetchSkill();
76
+ }, [resolvedParams.name]);
77
+
78
+ const handleExecuteScript = async (script: Script) => {
79
+ setSelectedScript(script);
80
+ setExecuting(true);
81
+ setOutput('');
82
+ setMessage(null);
83
+
84
+ try {
85
+ const res = await fetch(`/api/skills/${resolvedParams.name}/execute`, {
86
+ method: 'POST',
87
+ headers: { 'Content-Type': 'application/json' },
88
+ body: JSON.stringify({ scriptName: script.name }),
89
+ });
90
+
91
+ const data = await res.json();
92
+
93
+ if (data.requiresApproval) {
94
+ setMessage({
95
+ type: 'success',
96
+ text: `已创建工单 ${data.ticketId},请前往审批`,
97
+ });
98
+ setOutput(`修改操作需要审批。
99
+
100
+ 工单已创建: ${data.ticketId}
101
+ 状态: pending
102
+
103
+ 请前往 /tickets/${data.ticketId} 审批后执行。`);
104
+ } else {
105
+ setOutput(data.output || data.error || '无输出');
106
+ if (data.hasError) {
107
+ setMessage({ type: 'error', text: '脚本执行出错' });
108
+ }
109
+ }
110
+ } catch (error) {
111
+ setOutput(`执行失败: ${error}`);
112
+ setMessage({ type: 'error', text: '执行失败' });
113
+ } finally {
114
+ setExecuting(false);
115
+ }
116
+ };
117
+
118
+ const handleViewScript = async (script: Script) => {
119
+ try {
120
+ const res = await fetch(`/api/skills/${resolvedParams.name}`);
121
+ if (res.ok) {
122
+ const skillData = await res.json();
123
+ const scriptRes = await fetch(`/api/skills/${resolvedParams.name}/scripts/${script.name}`);
124
+ // For now, just show basic info
125
+ setScriptContent(`# ${script.name}
126
+ # ${script.description}
127
+ # 类型: ${script.type === 'read_only' ? '只读操作' : '修改操作'}
128
+ # API: ${script.method} ${script.path}`);
129
+ setShowScriptDialog(true);
130
+ }
131
+ } catch (error) {
132
+ console.error('Failed to view script:', error);
133
+ }
134
+ };
135
+
136
+ const readOnlyScripts = skill?.scripts.filter(s => s.type === 'read_only') || [];
137
+ const modifyScripts = skill?.scripts.filter(s => s.type === 'modify') || [];
138
+
139
+ if (loading) {
140
+ return (
141
+ <div className="p-6 flex items-center justify-center h-64">
142
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
143
+ </div>
144
+ );
145
+ }
146
+
147
+ if (!skill) {
148
+ return (
149
+ <div className="p-6">
150
+ <div className="max-w-7xl mx-auto text-center py-12">
151
+ <h2 className="text-2xl font-bold mb-4">Skill 不存在</h2>
152
+ <Link href="/skills">
153
+ <Button>返回列表</Button>
154
+ </Link>
155
+ </div>
156
+ </div>
157
+ );
158
+ }
159
+
160
+ return (
161
+ <div className="p-6">
162
+ <div className="max-w-7xl mx-auto">
163
+ <div className="flex items-center gap-4 mb-8">
164
+ <Link href="/skills">
165
+ <Button variant="ghost" size="icon">
166
+ <ArrowLeft className="w-5 h-5" />
167
+ </Button>
168
+ </Link>
169
+ <div className="flex-1">
170
+ <div className="flex items-center gap-3">
171
+ <h1 className="text-2xl font-bold">{skill.displayName || skill.name}</h1>
172
+ {skill.isBuiltIn && (
173
+ <Badge variant="secondary">
174
+ <Shield className="w-3 h-3 mr-1" />
175
+ 内置
176
+ </Badge>
177
+ )}
178
+ </div>
179
+ <p className="text-muted-foreground mt-1">{skill.description}</p>
180
+ </div>
181
+ <div className="text-sm text-muted-foreground">
182
+ v{skill.version} • {skill.skillPath}
183
+ </div>
184
+ </div>
185
+
186
+ {message && (
187
+ <div className={`mb-6 p-4 rounded-lg ${message.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'}`}>
188
+ {message.text}
189
+ </div>
190
+ )}
191
+
192
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
193
+ <div className="lg:col-span-2 space-y-6">
194
+ <Tabs defaultValue="scripts">
195
+ <TabsList>
196
+ <TabsTrigger value="scripts">
197
+ <Code className="w-4 h-4 mr-2" />
198
+ 脚本 ({skill.scripts.length})
199
+ </TabsTrigger>
200
+ <TabsTrigger value="readme">
201
+ <FileText className="w-4 h-4 mr-2" />
202
+ 文档
203
+ </TabsTrigger>
204
+ </TabsList>
205
+
206
+ <TabsContent value="scripts" className="space-y-4 mt-4">
207
+ {readOnlyScripts.length > 0 && (
208
+ <Card>
209
+ <CardHeader>
210
+ <CardTitle className="text-sm font-medium flex items-center gap-2">
211
+ <Shield className="w-4 h-4 text-green-500" />
212
+ 只读操作
213
+ <Badge variant="outline">{readOnlyScripts.length}</Badge>
214
+ </CardTitle>
215
+ </CardHeader>
216
+ <CardContent>
217
+ <div className="grid gap-2">
218
+ {readOnlyScripts.map((script) => (
219
+ <div
220
+ key={script.name}
221
+ className="flex items-center justify-between p-3 rounded-lg border bg-green-50/50"
222
+ >
223
+ <div className="flex-1">
224
+ <div className="flex items-center gap-2">
225
+ <Badge variant="outline" className="font-mono text-xs">
226
+ {script.method}
227
+ </Badge>
228
+ <code className="text-sm">{script.path}</code>
229
+ </div>
230
+ <p className="text-xs text-muted-foreground mt-1">{script.description}</p>
231
+ </div>
232
+ <div className="flex items-center gap-2">
233
+ <Button
234
+ variant="ghost"
235
+ size="icon"
236
+ onClick={() => handleViewScript(script)}
237
+ title="查看"
238
+ >
239
+ <Eye className="w-4 h-4" />
240
+ </Button>
241
+ <Button
242
+ variant="default"
243
+ size="icon"
244
+ onClick={() => handleExecuteScript(script)}
245
+ disabled={executing}
246
+ title="执行"
247
+ >
248
+ <Play className="w-4 h-4" />
249
+ </Button>
250
+ </div>
251
+ </div>
252
+ ))}
253
+ </div>
254
+ </CardContent>
255
+ </Card>
256
+ )}
257
+
258
+ {modifyScripts.length > 0 && (
259
+ <Card>
260
+ <CardHeader>
261
+ <CardTitle className="text-sm font-medium flex items-center gap-2">
262
+ <ShieldAlert className="w-4 h-4 text-amber-500" />
263
+ 修改操作
264
+ <Badge variant="outline">{modifyScripts.length}</Badge>
265
+ </CardTitle>
266
+ </CardHeader>
267
+ <CardContent>
268
+ <div className="grid gap-2">
269
+ {modifyScripts.map((script) => (
270
+ <div
271
+ key={script.name}
272
+ className="flex items-center justify-between p-3 rounded-lg border bg-amber-50/50"
273
+ >
274
+ <div className="flex-1">
275
+ <div className="flex items-center gap-2">
276
+ <Badge variant="outline" className="font-mono text-xs">
277
+ {script.method}
278
+ </Badge>
279
+ <code className="text-sm">{script.path}</code>
280
+ </div>
281
+ <p className="text-xs text-muted-foreground mt-1">{script.description}</p>
282
+ </div>
283
+ <div className="flex items-center gap-2">
284
+ <Button
285
+ variant="ghost"
286
+ size="icon"
287
+ onClick={() => handleViewScript(script)}
288
+ title="查看"
289
+ >
290
+ <Eye className="w-4 h-4" />
291
+ </Button>
292
+ <Button
293
+ variant="default"
294
+ size="icon"
295
+ onClick={() => handleExecuteScript(script)}
296
+ disabled={executing}
297
+ title="执行(需审批)"
298
+ >
299
+ <Play className="w-4 h-4" />
300
+ </Button>
301
+ </div>
302
+ </div>
303
+ ))}
304
+ </div>
305
+ </CardContent>
306
+ </Card>
307
+ )}
308
+
309
+ {skill.scripts.length === 0 && (
310
+ <Card className="border-dashed">
311
+ <CardContent className="py-8 text-center text-muted-foreground">
312
+ 此 Skill 暂无脚本
313
+ </CardContent>
314
+ </Card>
315
+ )}
316
+ </TabsContent>
317
+
318
+ <TabsContent value="readme" className="mt-4">
319
+ <Card>
320
+ <CardContent className="prose prose-sm max-w-none py-4">
321
+ <pre className="whitespace-pre-wrap text-sm">{skill.readme || '暂无文档'}</pre>
322
+ </CardContent>
323
+ </Card>
324
+ </TabsContent>
325
+ </Tabs>
326
+ </div>
327
+
328
+ <div className="space-y-6">
329
+ <Card>
330
+ <CardHeader>
331
+ <CardTitle className="text-base flex items-center gap-2">
332
+ <TerminalIcon className="w-4 h-4" />
333
+ 执行输出
334
+ </CardTitle>
335
+ </CardHeader>
336
+ <CardContent>
337
+ <Terminal output={output} className="min-h-[200px]">
338
+ <TerminalHeader>
339
+ <TerminalTitle>执行结果</TerminalTitle>
340
+ </TerminalHeader>
341
+ <TerminalContent />
342
+ </Terminal>
343
+ </CardContent>
344
+ </Card>
345
+
346
+ {skill.isBuiltIn && (
347
+ <Card className="border-primary/20 bg-primary/5">
348
+ <CardHeader>
349
+ <CardTitle className="text-base">关于内置 Skill</CardTitle>
350
+ </CardHeader>
351
+ <CardContent className="text-sm text-muted-foreground">
352
+ <p>generate-api-system 是系统内置的元 Skill,用于从 Swagger/OpenAPI 规范生成新的 API Skill 系统。</p>
353
+ <p className="mt-2">它不能被卸载,但可以通过创建新的 Skill 来使用。</p>
354
+ </CardContent>
355
+ </Card>
356
+ )}
357
+ </div>
358
+ </div>
359
+
360
+ <Dialog open={showScriptDialog} onOpenChange={setShowScriptDialog}>
361
+ <DialogContent className="max-w-2xl">
362
+ <DialogHeader>
363
+ <DialogTitle>脚本详情: {selectedScript?.name}</DialogTitle>
364
+ </DialogHeader>
365
+ <div className="mt-4">
366
+ <Terminal output={scriptContent} className="min-h-[200px]">
367
+ <TerminalHeader>
368
+ <TerminalTitle>{selectedScript?.name}</TerminalTitle>
369
+ </TerminalHeader>
370
+ <TerminalContent />
371
+ </Terminal>
372
+ </div>
373
+ </DialogContent>
374
+ </Dialog>
375
+ </div>
376
+ </div>
377
+ );
378
+ }