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,133 @@
1
+ "use client";
2
+
3
+ import type { ToolUIPart } from "ai";
4
+ import type { ComponentProps } from "react";
5
+
6
+ import {
7
+ Collapsible,
8
+ CollapsibleContent,
9
+ CollapsibleTrigger,
10
+ } from "@/components/ui/collapsible";
11
+ import {
12
+ Tabs,
13
+ TabsContent,
14
+ TabsList,
15
+ TabsTrigger,
16
+ } from "@/components/ui/tabs";
17
+ import { cn } from "@/lib/utils";
18
+ import { ChevronDownIcon, Code } from "lucide-react";
19
+
20
+ import { getStatusBadge } from "./tool";
21
+
22
+ export type SandboxRootProps = ComponentProps<typeof Collapsible>;
23
+
24
+ export const Sandbox = ({ className, ...props }: SandboxRootProps) => (
25
+ <Collapsible
26
+ className={cn(
27
+ "not-prose group mb-4 w-full overflow-hidden rounded-md border",
28
+ className
29
+ )}
30
+ defaultOpen
31
+ {...props}
32
+ />
33
+ );
34
+
35
+ export interface SandboxHeaderProps {
36
+ title?: string;
37
+ state: ToolUIPart["state"];
38
+ className?: string;
39
+ }
40
+
41
+ export const SandboxHeader = ({
42
+ className,
43
+ title,
44
+ state,
45
+ ...props
46
+ }: SandboxHeaderProps) => (
47
+ <CollapsibleTrigger
48
+ className={cn(
49
+ "flex w-full items-center justify-between gap-4 p-3",
50
+ className
51
+ )}
52
+ {...props}
53
+ >
54
+ <div className="flex items-center gap-2">
55
+ <Code className="size-4 text-muted-foreground" />
56
+ <span className="font-medium text-sm">{title}</span>
57
+ {getStatusBadge(state)}
58
+ </div>
59
+ <ChevronDownIcon className="size-4 text-muted-foreground transition-transform group-data-[state=open]:rotate-180" />
60
+ </CollapsibleTrigger>
61
+ );
62
+
63
+ export type SandboxContentProps = ComponentProps<typeof CollapsibleContent>;
64
+
65
+ export const SandboxContent = ({
66
+ className,
67
+ ...props
68
+ }: SandboxContentProps) => (
69
+ <CollapsibleContent
70
+ className={cn(
71
+ "data-[state=closed]:fade-out-0 data-[state=closed]:slide-out-to-top-2 data-[state=open]:slide-in-from-top-2 outline-none data-[state=closed]:animate-out data-[state=open]:animate-in",
72
+ className
73
+ )}
74
+ {...props}
75
+ />
76
+ );
77
+
78
+ export type SandboxTabsProps = ComponentProps<typeof Tabs>;
79
+
80
+ export const SandboxTabs = ({ className, ...props }: SandboxTabsProps) => (
81
+ <Tabs className={cn("w-full gap-0", className)} {...props} />
82
+ );
83
+
84
+ export type SandboxTabsBarProps = ComponentProps<"div">;
85
+
86
+ export const SandboxTabsBar = ({
87
+ className,
88
+ ...props
89
+ }: SandboxTabsBarProps) => (
90
+ <div
91
+ className={cn(
92
+ "flex w-full items-center border-border border-t border-b",
93
+ className
94
+ )}
95
+ {...props}
96
+ />
97
+ );
98
+
99
+ export type SandboxTabsListProps = ComponentProps<typeof TabsList>;
100
+
101
+ export const SandboxTabsList = ({
102
+ className,
103
+ ...props
104
+ }: SandboxTabsListProps) => (
105
+ <TabsList
106
+ className={cn("h-auto rounded-none border-0 bg-transparent p-0", className)}
107
+ {...props}
108
+ />
109
+ );
110
+
111
+ export type SandboxTabsTriggerProps = ComponentProps<typeof TabsTrigger>;
112
+
113
+ export const SandboxTabsTrigger = ({
114
+ className,
115
+ ...props
116
+ }: SandboxTabsTriggerProps) => (
117
+ <TabsTrigger
118
+ className={cn(
119
+ "rounded-none border-0 border-transparent border-b-2 px-4 py-2 font-medium text-muted-foreground text-sm transition-colors data-[state=active]:border-primary data-[state=active]:bg-transparent data-[state=active]:text-foreground data-[state=active]:shadow-none",
120
+ className
121
+ )}
122
+ {...props}
123
+ />
124
+ );
125
+
126
+ export type SandboxTabContentProps = ComponentProps<typeof TabsContent>;
127
+
128
+ export const SandboxTabContent = ({
129
+ className,
130
+ ...props
131
+ }: SandboxTabContentProps) => (
132
+ <TabsContent className={cn("mt-0 text-sm", className)} {...props} />
133
+ );
@@ -0,0 +1,473 @@
1
+ "use client";
2
+
3
+ import type { ComponentProps, HTMLAttributes } from "react";
4
+
5
+ import { Badge } from "@/components/ui/badge";
6
+ import {
7
+ Collapsible,
8
+ CollapsibleContent,
9
+ CollapsibleTrigger,
10
+ } from "@/components/ui/collapsible";
11
+ import { cn } from "@/lib/utils";
12
+ import { ChevronRightIcon } from "lucide-react";
13
+ import { createContext, useContext, useMemo } from "react";
14
+
15
+ type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
16
+
17
+ interface SchemaParameter {
18
+ name: string;
19
+ type: string;
20
+ required?: boolean;
21
+ description?: string;
22
+ location?: "path" | "query" | "header";
23
+ }
24
+
25
+ interface SchemaProperty {
26
+ name: string;
27
+ type: string;
28
+ required?: boolean;
29
+ description?: string;
30
+ properties?: SchemaProperty[];
31
+ items?: SchemaProperty;
32
+ }
33
+
34
+ interface SchemaDisplayContextType {
35
+ method: HttpMethod;
36
+ path: string;
37
+ description?: string;
38
+ parameters?: SchemaParameter[];
39
+ requestBody?: SchemaProperty[];
40
+ responseBody?: SchemaProperty[];
41
+ }
42
+
43
+ const SchemaDisplayContext = createContext<SchemaDisplayContextType>({
44
+ method: "GET",
45
+ path: "",
46
+ });
47
+
48
+ export type SchemaDisplayProps = HTMLAttributes<HTMLDivElement> & {
49
+ method: HttpMethod;
50
+ path: string;
51
+ description?: string;
52
+ parameters?: SchemaParameter[];
53
+ requestBody?: SchemaProperty[];
54
+ responseBody?: SchemaProperty[];
55
+ };
56
+
57
+ export const SchemaDisplay = ({
58
+ method,
59
+ path,
60
+ description,
61
+ parameters,
62
+ requestBody,
63
+ responseBody,
64
+ className,
65
+ children,
66
+ ...props
67
+ }: SchemaDisplayProps) => {
68
+ const contextValue = useMemo(
69
+ () => ({
70
+ description,
71
+ method,
72
+ parameters,
73
+ path,
74
+ requestBody,
75
+ responseBody,
76
+ }),
77
+ [description, method, parameters, path, requestBody, responseBody]
78
+ );
79
+
80
+ return (
81
+ <SchemaDisplayContext.Provider value={contextValue}>
82
+ <div
83
+ className={cn(
84
+ "overflow-hidden rounded-lg border bg-background",
85
+ className
86
+ )}
87
+ {...props}
88
+ >
89
+ {children ?? (
90
+ <>
91
+ <SchemaDisplayHeader>
92
+ <div className="flex items-center gap-3">
93
+ <SchemaDisplayMethod />
94
+ <SchemaDisplayPath />
95
+ </div>
96
+ </SchemaDisplayHeader>
97
+ {description && <SchemaDisplayDescription />}
98
+ <SchemaDisplayContent>
99
+ {parameters && parameters.length > 0 && (
100
+ <SchemaDisplayParameters />
101
+ )}
102
+ {requestBody && requestBody.length > 0 && (
103
+ <SchemaDisplayRequest />
104
+ )}
105
+ {responseBody && responseBody.length > 0 && (
106
+ <SchemaDisplayResponse />
107
+ )}
108
+ </SchemaDisplayContent>
109
+ </>
110
+ )}
111
+ </div>
112
+ </SchemaDisplayContext.Provider>
113
+ );
114
+ };
115
+
116
+ export type SchemaDisplayHeaderProps = HTMLAttributes<HTMLDivElement>;
117
+
118
+ export const SchemaDisplayHeader = ({
119
+ className,
120
+ children,
121
+ ...props
122
+ }: SchemaDisplayHeaderProps) => (
123
+ <div
124
+ className={cn("flex items-center gap-3 border-b px-4 py-3", className)}
125
+ {...props}
126
+ >
127
+ {children}
128
+ </div>
129
+ );
130
+
131
+ const methodStyles: Record<HttpMethod, string> = {
132
+ DELETE: "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400",
133
+ GET: "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400",
134
+ PATCH:
135
+ "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400",
136
+ POST: "bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400",
137
+ PUT: "bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400",
138
+ };
139
+
140
+ export type SchemaDisplayMethodProps = ComponentProps<typeof Badge>;
141
+
142
+ export const SchemaDisplayMethod = ({
143
+ className,
144
+ children,
145
+ ...props
146
+ }: SchemaDisplayMethodProps) => {
147
+ const { method } = useContext(SchemaDisplayContext);
148
+
149
+ return (
150
+ <Badge
151
+ className={cn("font-mono text-xs", methodStyles[method], className)}
152
+ variant="secondary"
153
+ {...props}
154
+ >
155
+ {children ?? method}
156
+ </Badge>
157
+ );
158
+ };
159
+
160
+ export type SchemaDisplayPathProps = HTMLAttributes<HTMLSpanElement>;
161
+
162
+ export const SchemaDisplayPath = ({
163
+ className,
164
+ children,
165
+ ...props
166
+ }: SchemaDisplayPathProps) => {
167
+ const { path } = useContext(SchemaDisplayContext);
168
+
169
+ // Highlight path parameters
170
+ const highlightedPath = path.replaceAll(
171
+ /\{([^}]+)\}/g,
172
+ '<span class="text-blue-600 dark:text-blue-400">{$1}</span>'
173
+ );
174
+
175
+ return (
176
+ <span
177
+ className={cn("font-mono text-sm", className)}
178
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: "needed for parameter highlighting"
179
+ // oxlint-disable-next-line eslint-plugin-react(no-danger)
180
+ dangerouslySetInnerHTML={{ __html: (children ?? highlightedPath) as string }}
181
+ {...props}
182
+ />
183
+ );
184
+ };
185
+
186
+ export type SchemaDisplayDescriptionProps =
187
+ HTMLAttributes<HTMLParagraphElement>;
188
+
189
+ export const SchemaDisplayDescription = ({
190
+ className,
191
+ children,
192
+ ...props
193
+ }: SchemaDisplayDescriptionProps) => {
194
+ const { description } = useContext(SchemaDisplayContext);
195
+
196
+ return (
197
+ <p
198
+ className={cn(
199
+ "border-b px-4 py-3 text-muted-foreground text-sm",
200
+ className
201
+ )}
202
+ {...props}
203
+ >
204
+ {children ?? description}
205
+ </p>
206
+ );
207
+ };
208
+
209
+ export type SchemaDisplayContentProps = HTMLAttributes<HTMLDivElement>;
210
+
211
+ export const SchemaDisplayContent = ({
212
+ className,
213
+ children,
214
+ ...props
215
+ }: SchemaDisplayContentProps) => (
216
+ <div className={cn("divide-y", className)} {...props}>
217
+ {children}
218
+ </div>
219
+ );
220
+
221
+ export type SchemaDisplayParametersProps = ComponentProps<typeof Collapsible>;
222
+
223
+ export const SchemaDisplayParameters = ({
224
+ className,
225
+ children,
226
+ ...props
227
+ }: SchemaDisplayParametersProps) => {
228
+ const { parameters } = useContext(SchemaDisplayContext);
229
+
230
+ return (
231
+ <Collapsible className={cn(className)} defaultOpen {...props}>
232
+ <CollapsibleTrigger className="group flex w-full items-center gap-2 px-4 py-3 text-left transition-colors hover:bg-muted/50">
233
+ <ChevronRightIcon className="size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-90" />
234
+ <span className="font-medium text-sm">Parameters</span>
235
+ <Badge className="ml-auto text-xs" variant="secondary">
236
+ {parameters?.length}
237
+ </Badge>
238
+ </CollapsibleTrigger>
239
+ <CollapsibleContent>
240
+ <div className="divide-y border-t">
241
+ {children ??
242
+ parameters?.map((param) => (
243
+ <SchemaDisplayParameter key={param.name} {...param} />
244
+ ))}
245
+ </div>
246
+ </CollapsibleContent>
247
+ </Collapsible>
248
+ );
249
+ };
250
+
251
+ export type SchemaDisplayParameterProps = HTMLAttributes<HTMLDivElement> &
252
+ SchemaParameter;
253
+
254
+ export const SchemaDisplayParameter = ({
255
+ name,
256
+ type,
257
+ required,
258
+ description,
259
+ location,
260
+ className,
261
+ ...props
262
+ }: SchemaDisplayParameterProps) => (
263
+ <div className={cn("px-4 py-3 pl-10", className)} {...props}>
264
+ <div className="flex items-center gap-2">
265
+ <span className="font-mono text-sm">{name}</span>
266
+ <Badge className="text-xs" variant="outline">
267
+ {type}
268
+ </Badge>
269
+ {location && (
270
+ <Badge className="text-xs" variant="secondary">
271
+ {location}
272
+ </Badge>
273
+ )}
274
+ {required && (
275
+ <Badge
276
+ className="bg-red-100 text-red-700 text-xs dark:bg-red-900/30 dark:text-red-400"
277
+ variant="secondary"
278
+ >
279
+ required
280
+ </Badge>
281
+ )}
282
+ </div>
283
+ {description && (
284
+ <p className="mt-1 text-muted-foreground text-sm">{description}</p>
285
+ )}
286
+ </div>
287
+ );
288
+
289
+ export type SchemaDisplayRequestProps = ComponentProps<typeof Collapsible>;
290
+
291
+ export const SchemaDisplayRequest = ({
292
+ className,
293
+ children,
294
+ ...props
295
+ }: SchemaDisplayRequestProps) => {
296
+ const { requestBody } = useContext(SchemaDisplayContext);
297
+
298
+ return (
299
+ <Collapsible className={cn(className)} defaultOpen {...props}>
300
+ <CollapsibleTrigger className="group flex w-full items-center gap-2 px-4 py-3 text-left transition-colors hover:bg-muted/50">
301
+ <ChevronRightIcon className="size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-90" />
302
+ <span className="font-medium text-sm">Request Body</span>
303
+ </CollapsibleTrigger>
304
+ <CollapsibleContent>
305
+ <div className="border-t">
306
+ {children ??
307
+ requestBody?.map((prop) => (
308
+ <SchemaDisplayProperty key={prop.name} {...prop} depth={0} />
309
+ ))}
310
+ </div>
311
+ </CollapsibleContent>
312
+ </Collapsible>
313
+ );
314
+ };
315
+
316
+ export type SchemaDisplayResponseProps = ComponentProps<typeof Collapsible>;
317
+
318
+ export const SchemaDisplayResponse = ({
319
+ className,
320
+ children,
321
+ ...props
322
+ }: SchemaDisplayResponseProps) => {
323
+ const { responseBody } = useContext(SchemaDisplayContext);
324
+
325
+ return (
326
+ <Collapsible className={cn(className)} defaultOpen {...props}>
327
+ <CollapsibleTrigger className="group flex w-full items-center gap-2 px-4 py-3 text-left transition-colors hover:bg-muted/50">
328
+ <ChevronRightIcon className="size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-90" />
329
+ <span className="font-medium text-sm">Response</span>
330
+ </CollapsibleTrigger>
331
+ <CollapsibleContent>
332
+ <div className="border-t">
333
+ {children ??
334
+ responseBody?.map((prop) => (
335
+ <SchemaDisplayProperty key={prop.name} {...prop} depth={0} />
336
+ ))}
337
+ </div>
338
+ </CollapsibleContent>
339
+ </Collapsible>
340
+ );
341
+ };
342
+
343
+ export type SchemaDisplayBodyProps = HTMLAttributes<HTMLDivElement>;
344
+
345
+ export const SchemaDisplayBody = ({
346
+ className,
347
+ children,
348
+ ...props
349
+ }: SchemaDisplayBodyProps) => (
350
+ <div className={cn("divide-y", className)} {...props}>
351
+ {children}
352
+ </div>
353
+ );
354
+
355
+ export type SchemaDisplayPropertyProps = HTMLAttributes<HTMLDivElement> &
356
+ SchemaProperty & {
357
+ depth?: number;
358
+ };
359
+
360
+ export const SchemaDisplayProperty = ({
361
+ name,
362
+ type,
363
+ required,
364
+ description,
365
+ properties,
366
+ items,
367
+ depth = 0,
368
+ className,
369
+ ...props
370
+ }: SchemaDisplayPropertyProps) => {
371
+ const hasChildren = properties || items;
372
+ const paddingLeft = 40 + depth * 16;
373
+
374
+ if (hasChildren) {
375
+ return (
376
+ <Collapsible defaultOpen={depth < 2}>
377
+ <CollapsibleTrigger
378
+ className={cn(
379
+ "group flex w-full items-center gap-2 py-3 text-left transition-colors hover:bg-muted/50",
380
+ className
381
+ )}
382
+ style={{ paddingLeft }}
383
+ >
384
+ <ChevronRightIcon className="size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-90" />
385
+ <span className="font-mono text-sm">{name}</span>
386
+ <Badge className="text-xs" variant="outline">
387
+ {type}
388
+ </Badge>
389
+ {required && (
390
+ <Badge
391
+ className="bg-red-100 text-red-700 text-xs dark:bg-red-900/30 dark:text-red-400"
392
+ variant="secondary"
393
+ >
394
+ required
395
+ </Badge>
396
+ )}
397
+ </CollapsibleTrigger>
398
+ {description && (
399
+ <p
400
+ className="pb-2 text-muted-foreground text-sm"
401
+ style={{ paddingLeft: paddingLeft + 24 }}
402
+ >
403
+ {description}
404
+ </p>
405
+ )}
406
+ <CollapsibleContent>
407
+ <div className="divide-y border-t">
408
+ {properties?.map((prop) => (
409
+ <SchemaDisplayProperty
410
+ key={prop.name}
411
+ {...prop}
412
+ depth={depth + 1}
413
+ />
414
+ ))}
415
+ {items && (
416
+ <SchemaDisplayProperty
417
+ {...items}
418
+ depth={depth + 1}
419
+ name={`${name}[]`}
420
+ />
421
+ )}
422
+ </div>
423
+ </CollapsibleContent>
424
+ </Collapsible>
425
+ );
426
+ }
427
+
428
+ return (
429
+ <div
430
+ className={cn("py-3 pr-4", className)}
431
+ style={{ paddingLeft }}
432
+ {...props}
433
+ >
434
+ <div className="flex items-center gap-2">
435
+ {/* Spacer for alignment */}
436
+ <span className="size-4" />
437
+ <span className="font-mono text-sm">{name}</span>
438
+ <Badge className="text-xs" variant="outline">
439
+ {type}
440
+ </Badge>
441
+ {required && (
442
+ <Badge
443
+ className="bg-red-100 text-red-700 text-xs dark:bg-red-900/30 dark:text-red-400"
444
+ variant="secondary"
445
+ >
446
+ required
447
+ </Badge>
448
+ )}
449
+ </div>
450
+ {description && (
451
+ <p className="mt-1 pl-6 text-muted-foreground text-sm">{description}</p>
452
+ )}
453
+ </div>
454
+ );
455
+ };
456
+
457
+ export type SchemaDisplayExampleProps = HTMLAttributes<HTMLPreElement>;
458
+
459
+ export const SchemaDisplayExample = ({
460
+ className,
461
+ children,
462
+ ...props
463
+ }: SchemaDisplayExampleProps) => (
464
+ <pre
465
+ className={cn(
466
+ "mx-4 mb-4 overflow-auto rounded-md bg-muted p-4 font-mono text-sm",
467
+ className
468
+ )}
469
+ {...props}
470
+ >
471
+ {children}
472
+ </pre>
473
+ );
@@ -0,0 +1,78 @@
1
+ "use client";
2
+
3
+ import type { MotionProps } from "motion/react";
4
+ import type { CSSProperties, ElementType, JSX } from "react";
5
+
6
+ import { cn } from "@/lib/utils";
7
+ import { motion } from "motion/react";
8
+ import { memo, useMemo } from "react";
9
+
10
+ type MotionHTMLProps = MotionProps & Record<string, unknown>;
11
+
12
+ // Cache motion components at module level to avoid creating during render
13
+ const motionComponentCache = new Map<
14
+ keyof JSX.IntrinsicElements,
15
+ React.ComponentType<MotionHTMLProps>
16
+ >();
17
+
18
+ const getMotionComponent = (element: keyof JSX.IntrinsicElements) => {
19
+ let component = motionComponentCache.get(element);
20
+ if (!component) {
21
+ component = motion.create(element);
22
+ motionComponentCache.set(element, component);
23
+ }
24
+ return component;
25
+ };
26
+
27
+ export interface TextShimmerProps {
28
+ children: string;
29
+ as?: ElementType;
30
+ className?: string;
31
+ duration?: number;
32
+ spread?: number;
33
+ }
34
+
35
+ const ShimmerComponent = ({
36
+ children,
37
+ as: Component = "p",
38
+ className,
39
+ duration = 2,
40
+ spread = 2,
41
+ }: TextShimmerProps) => {
42
+ const MotionComponent = getMotionComponent(
43
+ Component as keyof JSX.IntrinsicElements
44
+ );
45
+
46
+ const dynamicSpread = useMemo(
47
+ () => (children?.length ?? 0) * spread,
48
+ [children, spread]
49
+ );
50
+
51
+ return (
52
+ <MotionComponent
53
+ animate={{ backgroundPosition: "0% center" }}
54
+ className={cn(
55
+ "relative inline-block bg-[length:250%_100%,auto] bg-clip-text text-transparent",
56
+ "[--bg:linear-gradient(90deg,#0000_calc(50%-var(--spread)),var(--color-background),#0000_calc(50%+var(--spread)))] [background-repeat:no-repeat,padding-box]",
57
+ className
58
+ )}
59
+ initial={{ backgroundPosition: "100% center" }}
60
+ style={
61
+ {
62
+ "--spread": `${dynamicSpread}px`,
63
+ backgroundImage:
64
+ "var(--bg), linear-gradient(var(--color-muted-foreground), var(--color-muted-foreground))",
65
+ } as CSSProperties
66
+ }
67
+ transition={{
68
+ duration,
69
+ ease: "linear",
70
+ repeat: Number.POSITIVE_INFINITY,
71
+ }}
72
+ >
73
+ {children}
74
+ </MotionComponent>
75
+ );
76
+ };
77
+
78
+ export const Shimmer = memo(ShimmerComponent);