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,226 @@
1
+ 'use client';
2
+
3
+ import { use } from 'react';
4
+ import { useState, useEffect } from 'react';
5
+ import { Bot, User, Loader2, ArrowLeft, Brain } from 'lucide-react';
6
+ import Link from 'next/link';
7
+ import { cn } from '@/lib/utils';
8
+ import { MessageResponse } from '@/components/ai-elements/message';
9
+ import {
10
+ ChainOfThought,
11
+ ChainOfThoughtContent,
12
+ ChainOfThoughtHeader,
13
+ ChainOfThoughtStep,
14
+ } from '@/components/ai-elements/chain-of-thought';
15
+
16
+ interface ToolExecution {
17
+ toolName: string;
18
+ startTime: Date;
19
+ endTime?: Date;
20
+ input?: any;
21
+ output?: any;
22
+ isError?: boolean;
23
+ }
24
+
25
+ interface MessageChainOfThought {
26
+ thinking: string;
27
+ toolExecutions: ToolExecution[];
28
+ }
29
+
30
+ interface SessionMessage {
31
+ id: string;
32
+ role: 'user' | 'assistant' | 'system';
33
+ content: string;
34
+ timestamp: string;
35
+ chainOfThought?: MessageChainOfThought;
36
+ }
37
+
38
+ export default function SharePage({ params }: { params: Promise<{ sessionId: string }> }) {
39
+ const { sessionId } = use(params);
40
+ const [messages, setMessages] = useState<SessionMessage[]>([]);
41
+ const [loading, setLoading] = useState(true);
42
+ const [error, setError] = useState<string | null>(null);
43
+
44
+ useEffect(() => {
45
+ async function loadMessages() {
46
+ try {
47
+ const response = await fetch(`/api/sessions/${sessionId}/messages`);
48
+ if (!response.ok) {
49
+ throw new Error('会话不存在或已过期');
50
+ }
51
+ const data = await response.json();
52
+ setMessages(data.messages || []);
53
+ } catch (e) {
54
+ setError(e instanceof Error ? e.message : '加载失败');
55
+ } finally {
56
+ setLoading(false);
57
+ }
58
+ }
59
+ loadMessages();
60
+ }, [sessionId]);
61
+
62
+ if (loading) {
63
+ return (
64
+ <div className="min-h-screen flex items-center justify-center bg-background">
65
+ <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
66
+ </div>
67
+ );
68
+ }
69
+
70
+ if (error) {
71
+ return (
72
+ <div className="min-h-screen flex items-center justify-center bg-background">
73
+ <div className="text-center">
74
+ <p className="text-destructive mb-4">{error}</p>
75
+ <Link href="/" className="text-primary hover:underline">
76
+ 返回首页
77
+ </Link>
78
+ </div>
79
+ </div>
80
+ );
81
+ }
82
+
83
+ return (
84
+ <div className="min-h-screen bg-background">
85
+ {/* Header */}
86
+ <header className="bg-card border-b sticky top-0 z-10">
87
+ <div className="max-w-4xl mx-auto px-4 py-3">
88
+ <div className="flex items-center justify-between">
89
+ <Link href="/" className="flex items-center gap-2 text-muted-foreground hover:text-foreground">
90
+ <ArrowLeft className="h-4 w-4" />
91
+ <span className="text-sm">返回</span>
92
+ </Link>
93
+ <h1 className="font-medium">会话分享</h1>
94
+ <div className="w-16" />
95
+ </div>
96
+ </div>
97
+ </header>
98
+
99
+ {/* Messages */}
100
+ <div className="max-w-4xl mx-auto px-4 py-8">
101
+ {messages.length === 0 ? (
102
+ <div className="text-center text-muted-foreground py-12">
103
+ 暂无对话内容
104
+ </div>
105
+ ) : (
106
+ <div className="space-y-6">
107
+ {messages.map((message) => (
108
+ <div key={message.id} className={cn('flex gap-3', message.role === 'user' && 'flex-row-reverse')}>
109
+ {/* Avatar */}
110
+ {message.role === 'assistant' && (
111
+ <div className="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0">
112
+ <Bot className="h-5 w-5 text-primary" />
113
+ </div>
114
+ )}
115
+ {message.role === 'user' && (
116
+ <div className="w-8 h-8 rounded-full bg-primary flex items-center justify-center flex-shrink-0">
117
+ <User className="h-5 w-5 text-primary-foreground" />
118
+ </div>
119
+ )}
120
+
121
+ {/* Message content with chain-of-thought */}
122
+ <div
123
+ className={cn(
124
+ 'rounded-2xl px-4 py-3',
125
+ message.role === 'user'
126
+ ? 'max-w-[80%] bg-primary text-primary-foreground'
127
+ : 'w-full bg-muted text-foreground'
128
+ )}
129
+ >
130
+ {message.role === 'assistant' && message.chainOfThought && (
131
+ <ChainOfThought defaultOpen={false}>
132
+ <ChainOfThoughtHeader>思考过程</ChainOfThoughtHeader>
133
+ <ChainOfThoughtContent>
134
+ {/* Thinking Section */}
135
+ {message.chainOfThought.thinking.trim().length > 0 && (
136
+ <ChainOfThoughtStep icon={Brain} label="思考" status="complete">
137
+ <div className="text-muted-foreground whitespace-pre-wrap">
138
+ {message.chainOfThought.thinking}
139
+ </div>
140
+ </ChainOfThoughtStep>
141
+ )}
142
+
143
+ {/* Tool Executions Section */}
144
+ {message.chainOfThought.toolExecutions.map((tool, idx) => (
145
+ <ChainOfThoughtStep
146
+ key={`${message.id}-tool-${idx}`}
147
+ label={tool.toolName === 'bash' && tool.input?.command
148
+ ? `执行: ${tool.input.command}`
149
+ : tool.toolName}
150
+ status={tool.isError ? 'pending' : 'complete'}
151
+ >
152
+ {/* Input for non-bash tools */}
153
+ {tool.toolName !== 'bash' && tool.input && (
154
+ <div className="mt-2 text-xs">
155
+ <strong>输入:</strong>
156
+ <pre className="mt-1 overflow-x-auto bg-muted rounded p-2">
157
+ {typeof tool.input === 'string' ? tool.input : JSON.stringify(tool.input, null, 2)}
158
+ </pre>
159
+ </div>
160
+ )}
161
+
162
+ {/* Output */}
163
+ {tool.output && (
164
+ <div className="mt-2 text-xs">
165
+ <strong>输出:</strong>
166
+ {(() => {
167
+ // Handle pi-coding-agent output format
168
+ if (tool.toolName === 'bash' && typeof tool.output === 'object' && tool.output.content) {
169
+ const textContent = tool.output.content
170
+ ?.filter((item: any) => item?.type === 'text')
171
+ ?.map((item: any) => item?.text || '')
172
+ ?.join('\n') || '';
173
+ const exitCode = tool.output.details?.exitCode ?? 0;
174
+ return (
175
+ <pre className={cn(
176
+ "mt-1 overflow-x-auto rounded p-2 whitespace-pre-wrap break-all",
177
+ exitCode === 0 ? "bg-muted" : "bg-destructive/10"
178
+ )}>
179
+ {textContent || JSON.stringify(tool.output, null, 2)}
180
+ </pre>
181
+ );
182
+ }
183
+ // Handle traditional bash output format
184
+ if (tool.toolName === 'bash' && typeof tool.output === 'object' && tool.output.stdout !== undefined) {
185
+ return (
186
+ <pre className={cn(
187
+ "mt-1 overflow-x-auto rounded p-2 whitespace-pre-wrap break-all",
188
+ tool.output.exitCode === 0 ? "bg-muted" : "bg-destructive/10"
189
+ )}>
190
+ {tool.output.stdout || ''}
191
+ {tool.output.stderr && (
192
+ <div className="text-destructive mt-1">{tool.output.stderr}</div>
193
+ )}
194
+ </pre>
195
+ );
196
+ }
197
+ // Fallback
198
+ return (
199
+ <pre className="mt-1 overflow-x-auto bg-muted rounded p-2">
200
+ {typeof tool.output === 'string' ? tool.output : JSON.stringify(tool.output, null, 2)}
201
+ </pre>
202
+ );
203
+ })()}
204
+ </div>
205
+ )}
206
+ </ChainOfThoughtStep>
207
+ ))}
208
+ </ChainOfThoughtContent>
209
+ </ChainOfThought>
210
+ )}
211
+
212
+ {/* Message Content */}
213
+ {message.role === 'assistant' ? (
214
+ <MessageResponse>{message.content}</MessageResponse>
215
+ ) : (
216
+ <div className="prose prose-sm max-w-none">{message.content}</div>
217
+ )}
218
+ </div>
219
+ </div>
220
+ ))}
221
+ </div>
222
+ )}
223
+ </div>
224
+ </div>
225
+ );
226
+ }
@@ -0,0 +1,140 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useState } from 'react';
4
+ import { useParams } from 'next/navigation';
5
+ import { FileIcon, Download, AlertCircle, Loader2 } from 'lucide-react';
6
+ import { Button } from '@/components/ui/button';
7
+ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
8
+
9
+ interface FileMetadata {
10
+ size: number;
11
+ mimeType: string;
12
+ originalName?: string;
13
+ }
14
+
15
+ interface FileInfo {
16
+ id: string;
17
+ title: string;
18
+ fileMetadata: FileMetadata | null;
19
+ isPublic: boolean;
20
+ createdAt: string;
21
+ }
22
+
23
+ function formatFileSize(bytes: number): string {
24
+ if (bytes === 0) return '0 B';
25
+ const k = 1024;
26
+ const sizes = ['B', 'KB', 'MB', 'GB'];
27
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
28
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
29
+ }
30
+
31
+ function formatDate(dateStr: string): string {
32
+ return new Date(dateStr).toLocaleDateString('zh-CN', {
33
+ year: 'numeric',
34
+ month: 'long',
35
+ day: 'numeric',
36
+ });
37
+ }
38
+
39
+ export default function SharedFilePage() {
40
+ const params = useParams();
41
+ const fileId = params?.id as string;
42
+ const [file, setFile] = useState<FileInfo | null>(null);
43
+ const [loading, setLoading] = useState(true);
44
+ const [error, setError] = useState<string | null>(null);
45
+
46
+ useEffect(() => {
47
+ if (!fileId) return;
48
+
49
+ const fetchFile = async () => {
50
+ try {
51
+ const res = await fetch(`/api/share/file/${fileId}`);
52
+ if (!res.ok) {
53
+ const data = await res.json();
54
+ throw new Error(data.error || '文件未找到');
55
+ }
56
+ const data = await res.json();
57
+ setFile(data.file);
58
+ } catch (err) {
59
+ setError(err instanceof Error ? err.message : '加载失败');
60
+ } finally {
61
+ setLoading(false);
62
+ }
63
+ };
64
+
65
+ fetchFile();
66
+ }, [fileId]);
67
+
68
+ const handleDownload = () => {
69
+ if (!file) return;
70
+ window.open(`/api/my/files/${file.id}?download=true`, '_blank');
71
+ };
72
+
73
+ if (loading) {
74
+ return (
75
+ <div className="min-h-screen flex items-center justify-center bg-gray-50">
76
+ <Loader2 className="h-8 w-8 animate-spin text-gray-400" />
77
+ </div>
78
+ );
79
+ }
80
+
81
+ if (error || !file) {
82
+ return (
83
+ <div className="min-h-screen flex items-center justify-center bg-gray-50 p-4">
84
+ <Card className="w-full max-w-md">
85
+ <CardContent className="py-12 text-center">
86
+ <AlertCircle className="h-12 w-12 mx-auto text-destructive mb-4" />
87
+ <h2 className="text-lg font-semibold mb-2">无法访问文件</h2>
88
+ <p className="text-muted-foreground">{error || '文件不存在或已被删除'}</p>
89
+ </CardContent>
90
+ </Card>
91
+ </div>
92
+ );
93
+ }
94
+
95
+ return (
96
+ <div className="min-h-screen flex items-center justify-center bg-gray-50 p-4">
97
+ <Card className="w-full max-w-md">
98
+ <CardHeader className="text-center">
99
+ <div className="w-16 h-16 rounded-full bg-primary/10 flex items-center justify-center mx-auto mb-4">
100
+ <FileIcon className="h-8 w-8 text-primary" />
101
+ </div>
102
+ <CardTitle className="text-xl">{file.title}</CardTitle>
103
+ </CardHeader>
104
+ <CardContent className="space-y-4">
105
+ {file.fileMetadata && (
106
+ <div className="bg-muted rounded-lg p-4 space-y-2">
107
+ <div className="flex justify-between text-sm">
108
+ <span className="text-muted-foreground">文件大小</span>
109
+ <span>{formatFileSize(file.fileMetadata.size)}</span>
110
+ </div>
111
+ <div className="flex justify-between text-sm">
112
+ <span className="text-muted-foreground">文件类型</span>
113
+ <span>{file.fileMetadata.mimeType}</span>
114
+ </div>
115
+ <div className="flex justify-between text-sm">
116
+ <span className="text-muted-foreground">上传时间</span>
117
+ <span>{formatDate(file.createdAt)}</span>
118
+ </div>
119
+ </div>
120
+ )}
121
+
122
+ {file.fileMetadata?.mimeType.startsWith('image/') && (
123
+ <div className="relative bg-gray-100 rounded-lg overflow-hidden">
124
+ <img
125
+ src={`/api/my/files/${file.id}`}
126
+ alt={file.title}
127
+ className="max-w-full max-h-64 mx-auto object-contain"
128
+ />
129
+ </div>
130
+ )}
131
+
132
+ <Button onClick={handleDownload} className="w-full" size="lg">
133
+ <Download className="h-4 w-4 mr-2" />
134
+ 下载文件
135
+ </Button>
136
+ </CardContent>
137
+ </Card>
138
+ </div>
139
+ );
140
+ }
package/bin/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # Generate API System
2
+
3
+ Generate an API Agent system from Swagger/OpenAPI specification.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Interactive mode
9
+ ./bin/generate-api-system
10
+
11
+ # With parameters
12
+ ./bin/generate-api-system \
13
+ --swagger "https://api.example.com/openapi.json" \
14
+ --name "My API System" \
15
+ --output "./my-api-system" \
16
+ --base-url "https://api.example.com"
17
+ ```
18
+
19
+ ## Options
20
+
21
+ | Option | Description |
22
+ |--------|-------------|
23
+ | `-s, --swagger` | Swagger/OpenAPI URL (required) |
24
+ | `-o, --output` | Output directory |
25
+ | `-n, --name` | System name |
26
+ | `-b, --base-url` | API base URL |
27
+ | `-t, --token` | API token |
28
+
29
+ ## Examples
30
+
31
+ ```bash
32
+ # Factory API
33
+ ./bin/generate-api-system \
34
+ -s "http://xuanwu-factory-next.xuanwu-factory.dev.aimstek.cn/api/open-api/docs" \
35
+ -n "Factory API" \
36
+ -o "./factory-api"
37
+
38
+ # Sim API
39
+ ./bin/generate-api-system \
40
+ -s "http://xuanwu-sim.demo-mxd.dev.aimstek.cn/swagger/Default/swagger.json" \
41
+ -n "Sim API" \
42
+ -o "./sim-api"
43
+ ```
44
+
45
+ ## Output Structure
46
+
47
+ ```
48
+ my-api-system/
49
+ ├── README.md
50
+ ├── SKILL.md ← AI Skill definition
51
+ ├── config.yaml
52
+ ├── APIs/ ← API documentation
53
+ ├── scripts/ ← Executable scripts
54
+ └── curl_examples/ ← curl examples
55
+ ```
56
+
57
+ ## As pi-coding-agent Skill
58
+
59
+ ```yaml
60
+ # .pi/skills/generate-api-system/
61
+ skills:
62
+ - name: generate-api-system
63
+ ```