sparkecoder 0.1.16 → 0.1.18

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 (216) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.js +15 -6
  3. package/dist/cli.js.map +1 -1
  4. package/dist/index.js +9 -2
  5. package/dist/index.js.map +1 -1
  6. package/dist/server/index.js +9 -2
  7. package/dist/server/index.js.map +1 -1
  8. package/package.json +1 -1
  9. package/web/.next/BUILD_ID +1 -1
  10. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  11. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  12. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  13. package/web/.next/standalone/web/.next/server/app/(main)/page.js +3 -3
  14. package/web/.next/standalone/web/.next/server/app/(main)/page.js.nft.json +1 -1
  15. package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
  16. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js +3 -3
  17. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
  18. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
  19. package/web/.next/standalone/web/.next/server/app/_global-error/page.js +2 -2
  20. package/web/.next/standalone/web/.next/server/app/_global-error/page.js.nft.json +1 -1
  21. package/web/.next/standalone/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  22. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  23. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  24. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  25. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_not-found/page.js +3 -3
  30. package/web/.next/standalone/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +13 -12
  34. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +13 -12
  35. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +4 -3
  37. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/api/config/route.js +1 -1
  41. package/web/.next/standalone/web/.next/server/app/api/config/route.js.nft.json +1 -1
  42. package/web/.next/standalone/web/.next/server/app/api/health/route.js +1 -1
  43. package/web/.next/standalone/web/.next/server/app/api/health/route.js.nft.json +1 -1
  44. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  45. package/web/.next/standalone/web/.next/server/app/index.rsc +20 -19
  46. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
  47. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
  48. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +20 -19
  49. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +4 -3
  51. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__36edac7c._.js +3 -0
  53. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__74ebc442._.js +3 -0
  54. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_1b669458._.js → 2374f_1d78db71._.js} +1 -1
  55. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_10a13bff._.js → 2374f_30f9df13._.js} +1 -1
  56. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_42ae2ff5._.js → 2374f_378282b1._.js} +1 -1
  57. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_21324e82._.js → 2374f_5de336d2._.js} +1 -1
  58. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_ba57e34a._.js → 2374f_8825dcc9._.js} +1 -1
  59. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_47e888fe._.js → 2374f_9bf3c7f3._.js} +2 -2
  60. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_63823b79._.js → 2374f_bbc99511._.js} +1 -1
  61. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_9c15fcde._.js → 2374f_d94c2b70._.js} +1 -1
  62. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__0f6b5fa7._.js +3 -0
  63. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__e1f2996b._.js → [root-of-the-server]__513c6b45._.js} +2 -2
  64. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__da40fb08._.js → [root-of-the-server]__7f04455b._.js} +2 -2
  65. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__be5e2967._.js +3 -0
  66. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__10aab2ca._.js → [root-of-the-server]__c3a1e22c._.js} +2 -2
  67. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__d2ce4b79._.js +3 -0
  68. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__de58a952._.js +3 -0
  69. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__f18f92f4._.js +10 -0
  70. package/web/.next/standalone/web/.next/server/chunks/ssr/{web_d3c9d897._.js → web_19b6934c._.js} +2 -2
  71. package/web/.next/standalone/web/.next/server/chunks/ssr/web_96bca05b._.js +1 -1
  72. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  73. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  74. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  75. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  76. package/web/.next/standalone/web/.next/static/chunks/25a97bfee12ea1f6.js +1 -0
  77. package/web/.next/standalone/web/.next/static/chunks/2f9f08f6c6276b0f.js +1 -0
  78. package/web/.next/{static/chunks/c7e9604ccdb5cb09.js → standalone/web/.next/static/chunks/5ec82ce8f3aabaf0.js} +3 -3
  79. package/web/.next/standalone/web/.next/static/static/chunks/25a97bfee12ea1f6.js +1 -0
  80. package/web/.next/standalone/web/.next/static/static/chunks/2f9f08f6c6276b0f.js +1 -0
  81. package/web/.next/standalone/web/.next/static/{chunks/c7e9604ccdb5cb09.js → static/chunks/5ec82ce8f3aabaf0.js} +3 -3
  82. package/web/.next/standalone/web/README.md +63 -0
  83. package/web/.next/standalone/web/components.json +22 -0
  84. package/web/.next/standalone/web/eslint.config.mjs +18 -0
  85. package/web/.next/standalone/web/next.config.ts +9 -0
  86. package/web/.next/standalone/web/package-lock.json +15061 -0
  87. package/web/.next/standalone/web/postcss.config.mjs +7 -0
  88. package/web/.next/standalone/web/runtime-config.json +3 -0
  89. package/web/.next/standalone/web/src/app/(main)/layout.tsx +22 -0
  90. package/web/.next/standalone/web/src/app/(main)/page.tsx +230 -0
  91. package/web/.next/standalone/web/src/app/(main)/session/[id]/page.tsx +64 -0
  92. package/web/.next/standalone/web/src/app/api/config/route.ts +106 -0
  93. package/web/.next/standalone/web/src/app/api/health/route.ts +63 -0
  94. package/web/.next/standalone/web/src/app/apple-icon.png +0 -0
  95. package/web/.next/standalone/web/src/app/favicon.ico +0 -0
  96. package/web/.next/standalone/web/src/app/globals.css +311 -0
  97. package/web/.next/standalone/web/src/app/icon.png +0 -0
  98. package/web/.next/standalone/web/src/app/layout.tsx +100 -0
  99. package/web/.next/standalone/web/src/app/opengraph-image.png +0 -0
  100. package/web/.next/standalone/web/src/app/twitter-image.png +0 -0
  101. package/web/.next/standalone/web/src/components/ai-elements/agent.tsx +141 -0
  102. package/web/.next/standalone/web/src/components/ai-elements/artifact.tsx +147 -0
  103. package/web/.next/standalone/web/src/components/ai-elements/attachments.tsx +421 -0
  104. package/web/.next/standalone/web/src/components/ai-elements/audio-player.tsx +231 -0
  105. package/web/.next/standalone/web/src/components/ai-elements/bash-tool.tsx +299 -0
  106. package/web/.next/standalone/web/src/components/ai-elements/canvas.tsx +22 -0
  107. package/web/.next/standalone/web/src/components/ai-elements/chain-of-thought.tsx +231 -0
  108. package/web/.next/standalone/web/src/components/ai-elements/checkpoint.tsx +71 -0
  109. package/web/.next/standalone/web/src/components/ai-elements/code-block.tsx +529 -0
  110. package/web/.next/standalone/web/src/components/ai-elements/commit.tsx +448 -0
  111. package/web/.next/standalone/web/src/components/ai-elements/confirmation.tsx +176 -0
  112. package/web/.next/standalone/web/src/components/ai-elements/connection.tsx +28 -0
  113. package/web/.next/standalone/web/src/components/ai-elements/context.tsx +408 -0
  114. package/web/.next/standalone/web/src/components/ai-elements/controls.tsx +18 -0
  115. package/web/.next/standalone/web/src/components/ai-elements/conversation.tsx +104 -0
  116. package/web/.next/standalone/web/src/components/ai-elements/edge.tsx +140 -0
  117. package/web/.next/standalone/web/src/components/ai-elements/environment-variables.tsx +295 -0
  118. package/web/.next/standalone/web/src/components/ai-elements/file-tree.tsx +258 -0
  119. package/web/.next/standalone/web/src/components/ai-elements/image.tsx +24 -0
  120. package/web/.next/standalone/web/src/components/ai-elements/inline-citation.tsx +287 -0
  121. package/web/.next/standalone/web/src/components/ai-elements/linter-tool.tsx +330 -0
  122. package/web/.next/standalone/web/src/components/ai-elements/load-skill-tool.tsx +215 -0
  123. package/web/.next/standalone/web/src/components/ai-elements/loader.tsx +96 -0
  124. package/web/.next/standalone/web/src/components/ai-elements/message.tsx +421 -0
  125. package/web/.next/standalone/web/src/components/ai-elements/mic-selector.tsx +370 -0
  126. package/web/.next/standalone/web/src/components/ai-elements/model-selector.tsx +211 -0
  127. package/web/.next/standalone/web/src/components/ai-elements/node.tsx +71 -0
  128. package/web/.next/standalone/web/src/components/ai-elements/open-in-chat.tsx +365 -0
  129. package/web/.next/standalone/web/src/components/ai-elements/package-info.tsx +233 -0
  130. package/web/.next/standalone/web/src/components/ai-elements/panel.tsx +15 -0
  131. package/web/.next/standalone/web/src/components/ai-elements/persona.tsx +270 -0
  132. package/web/.next/standalone/web/src/components/ai-elements/plan.tsx +142 -0
  133. package/web/.next/standalone/web/src/components/ai-elements/prompt-input.tsx +1263 -0
  134. package/web/.next/standalone/web/src/components/ai-elements/queue.tsx +274 -0
  135. package/web/.next/standalone/web/src/components/ai-elements/read-file-tool.tsx +251 -0
  136. package/web/.next/standalone/web/src/components/ai-elements/reasoning.tsx +198 -0
  137. package/web/.next/standalone/web/src/components/ai-elements/sandbox.tsx +131 -0
  138. package/web/.next/standalone/web/src/components/ai-elements/schema-display.tsx +458 -0
  139. package/web/.next/standalone/web/src/components/ai-elements/shimmer.tsx +64 -0
  140. package/web/.next/standalone/web/src/components/ai-elements/snippet.tsx +139 -0
  141. package/web/.next/standalone/web/src/components/ai-elements/sources.tsx +77 -0
  142. package/web/.next/standalone/web/src/components/ai-elements/speech-input.tsx +300 -0
  143. package/web/.next/standalone/web/src/components/ai-elements/stack-trace.tsx +482 -0
  144. package/web/.next/standalone/web/src/components/ai-elements/suggestion.tsx +60 -0
  145. package/web/.next/standalone/web/src/components/ai-elements/task.tsx +87 -0
  146. package/web/.next/standalone/web/src/components/ai-elements/terminal.tsx +261 -0
  147. package/web/.next/standalone/web/src/components/ai-elements/test-results.tsx +485 -0
  148. package/web/.next/standalone/web/src/components/ai-elements/todo-panel.tsx +178 -0
  149. package/web/.next/standalone/web/src/components/ai-elements/todo-tool.tsx +246 -0
  150. package/web/.next/standalone/web/src/components/ai-elements/tool.tsx +174 -0
  151. package/web/.next/standalone/web/src/components/ai-elements/toolbar.tsx +16 -0
  152. package/web/.next/standalone/web/src/components/ai-elements/transcription.tsx +124 -0
  153. package/web/.next/standalone/web/src/components/ai-elements/voice-selector.tsx +479 -0
  154. package/web/.next/standalone/web/src/components/ai-elements/web-preview.tsx +263 -0
  155. package/web/.next/standalone/web/src/components/ai-elements/write-file-tool.tsx +368 -0
  156. package/web/.next/standalone/web/src/components/api-init.tsx +21 -0
  157. package/web/.next/standalone/web/src/components/chat-interface.tsx +2074 -0
  158. package/web/.next/standalone/web/src/components/sessions-sidebar.tsx +875 -0
  159. package/web/.next/standalone/web/src/components/ui/accordion.tsx +66 -0
  160. package/web/.next/standalone/web/src/components/ui/alert.tsx +66 -0
  161. package/web/.next/standalone/web/src/components/ui/avatar.tsx +109 -0
  162. package/web/.next/standalone/web/src/components/ui/badge.tsx +48 -0
  163. package/web/.next/standalone/web/src/components/ui/button-group.tsx +83 -0
  164. package/web/.next/standalone/web/src/components/ui/button.tsx +64 -0
  165. package/web/.next/standalone/web/src/components/ui/card.tsx +92 -0
  166. package/web/.next/standalone/web/src/components/ui/carousel.tsx +241 -0
  167. package/web/.next/standalone/web/src/components/ui/collapsible.tsx +33 -0
  168. package/web/.next/standalone/web/src/components/ui/command.tsx +184 -0
  169. package/web/.next/standalone/web/src/components/ui/dialog.tsx +158 -0
  170. package/web/.next/standalone/web/src/components/ui/dropdown-menu.tsx +257 -0
  171. package/web/.next/standalone/web/src/components/ui/hover-card.tsx +44 -0
  172. package/web/.next/standalone/web/src/components/ui/input-group.tsx +170 -0
  173. package/web/.next/standalone/web/src/components/ui/input.tsx +22 -0
  174. package/web/.next/standalone/web/src/components/ui/label.tsx +24 -0
  175. package/web/.next/standalone/web/src/components/ui/popover.tsx +89 -0
  176. package/web/.next/standalone/web/src/components/ui/progress.tsx +31 -0
  177. package/web/.next/standalone/web/src/components/ui/scroll-area.tsx +58 -0
  178. package/web/.next/standalone/web/src/components/ui/select.tsx +190 -0
  179. package/web/.next/standalone/web/src/components/ui/separator.tsx +28 -0
  180. package/web/.next/standalone/web/src/components/ui/sheet.tsx +143 -0
  181. package/web/.next/standalone/web/src/components/ui/sidebar.tsx +726 -0
  182. package/web/.next/standalone/web/src/components/ui/skeleton.tsx +13 -0
  183. package/web/.next/standalone/web/src/components/ui/switch.tsx +35 -0
  184. package/web/.next/standalone/web/src/components/ui/tabs.tsx +91 -0
  185. package/web/.next/standalone/web/src/components/ui/textarea.tsx +18 -0
  186. package/web/.next/standalone/web/src/components/ui/tooltip.tsx +61 -0
  187. package/web/.next/standalone/web/src/hooks/use-mobile.ts +19 -0
  188. package/web/.next/standalone/web/src/hooks/use-sessions.ts +28 -0
  189. package/web/.next/standalone/web/src/lib/api.ts +568 -0
  190. package/web/.next/standalone/web/src/lib/config.ts +178 -0
  191. package/web/.next/standalone/web/src/lib/utils.ts +6 -0
  192. package/web/.next/standalone/web/src/test/api.test.ts +125 -0
  193. package/web/.next/standalone/web/src/test/setup.ts +1 -0
  194. package/web/.next/standalone/web/tsconfig.json +43 -0
  195. package/web/.next/standalone/web/vitest.config.ts +17 -0
  196. package/web/.next/static/chunks/25a97bfee12ea1f6.js +1 -0
  197. package/web/.next/static/chunks/2f9f08f6c6276b0f.js +1 -0
  198. package/web/.next/{standalone/web/.next/static/static/chunks/c7e9604ccdb5cb09.js → static/chunks/5ec82ce8f3aabaf0.js} +3 -3
  199. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__7ba4776a._.js +0 -3
  200. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__d907af4e._.js +0 -3
  201. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__3a7ef2b7._.js +0 -3
  202. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__5369f47d._.js +0 -3
  203. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__c1f0d54f._.js +0 -3
  204. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__fd3d4d25._.js +0 -10
  205. package/web/.next/standalone/web/.next/static/chunks/85dcb2949e032468.js +0 -1
  206. package/web/.next/standalone/web/.next/static/static/chunks/85dcb2949e032468.js +0 -1
  207. package/web/.next/static/chunks/85dcb2949e032468.js +0 -1
  208. /package/web/.next/standalone/web/.next/static/{3Y3VQCOuXe9_MLEdym2IJ → omR5ZCfnSKddq7WtwIK6Y}/_buildManifest.js +0 -0
  209. /package/web/.next/standalone/web/.next/static/{3Y3VQCOuXe9_MLEdym2IJ → omR5ZCfnSKddq7WtwIK6Y}/_clientMiddlewareManifest.json +0 -0
  210. /package/web/.next/standalone/web/.next/static/{3Y3VQCOuXe9_MLEdym2IJ → omR5ZCfnSKddq7WtwIK6Y}/_ssgManifest.js +0 -0
  211. /package/web/.next/standalone/web/.next/static/static/{3Y3VQCOuXe9_MLEdym2IJ → omR5ZCfnSKddq7WtwIK6Y}/_buildManifest.js +0 -0
  212. /package/web/.next/standalone/web/.next/static/static/{3Y3VQCOuXe9_MLEdym2IJ → omR5ZCfnSKddq7WtwIK6Y}/_clientMiddlewareManifest.json +0 -0
  213. /package/web/.next/standalone/web/.next/static/static/{3Y3VQCOuXe9_MLEdym2IJ → omR5ZCfnSKddq7WtwIK6Y}/_ssgManifest.js +0 -0
  214. /package/web/.next/static/{3Y3VQCOuXe9_MLEdym2IJ → omR5ZCfnSKddq7WtwIK6Y}/_buildManifest.js +0 -0
  215. /package/web/.next/static/{3Y3VQCOuXe9_MLEdym2IJ → omR5ZCfnSKddq7WtwIK6Y}/_clientMiddlewareManifest.json +0 -0
  216. /package/web/.next/static/{3Y3VQCOuXe9_MLEdym2IJ → omR5ZCfnSKddq7WtwIK6Y}/_ssgManifest.js +0 -0
@@ -0,0 +1,215 @@
1
+ "use client";
2
+
3
+ import { Badge } from "@/components/ui/badge";
4
+ import { Button } from "@/components/ui/button";
5
+ import { cn } from "@/lib/utils";
6
+ import {
7
+ BookOpenIcon,
8
+ CheckCircleIcon,
9
+ ChevronDownIcon,
10
+ ChevronRightIcon,
11
+ ClockIcon,
12
+ CopyIcon,
13
+ ListIcon,
14
+ SparklesIcon,
15
+ XCircleIcon,
16
+ } from "lucide-react";
17
+ import { useState } from "react";
18
+
19
+ export interface SkillInfo {
20
+ name: string;
21
+ description?: string;
22
+ }
23
+
24
+ export interface LoadSkillInput {
25
+ action: "list" | "load";
26
+ skillName?: string;
27
+ }
28
+
29
+ export interface LoadSkillOutput {
30
+ success?: boolean;
31
+ error?: string;
32
+ action?: string;
33
+ skillCount?: number;
34
+ skills?: SkillInfo[];
35
+ skillName?: string;
36
+ description?: string;
37
+ content?: string;
38
+ contentLength?: number;
39
+ availableSkills?: string[];
40
+ }
41
+
42
+ export interface LoadSkillToolProps {
43
+ input: LoadSkillInput;
44
+ output?: LoadSkillOutput;
45
+ status: "pending" | "streaming" | "running" | "completed" | "rejected" | "error";
46
+ className?: string;
47
+ }
48
+
49
+ export function LoadSkillTool({
50
+ input,
51
+ output,
52
+ status,
53
+ className,
54
+ }: LoadSkillToolProps) {
55
+ const [isExpanded, setIsExpanded] = useState(true);
56
+
57
+ const action = input?.action || "list";
58
+ const skillName = input?.skillName || output?.skillName;
59
+ const isLoading = status === "pending" || status === "streaming" || status === "running";
60
+ const isCompleted = status === "completed";
61
+ const isError = status === "error" || output?.success === false;
62
+
63
+ // Status icon and color
64
+ const StatusIcon = isCompleted && output?.success
65
+ ? CheckCircleIcon
66
+ : isError
67
+ ? XCircleIcon
68
+ : isLoading
69
+ ? ClockIcon
70
+ : BookOpenIcon;
71
+
72
+ const statusColor = isCompleted && output?.success
73
+ ? "text-green-600 dark:text-green-500"
74
+ : isError
75
+ ? "text-red-600 dark:text-red-500"
76
+ : isLoading
77
+ ? "text-muted-foreground animate-pulse"
78
+ : "text-muted-foreground";
79
+
80
+ const headerTitle = action === "load"
81
+ ? skillName ? `Load: ${skillName}` : "Load Skill"
82
+ : "List Skills";
83
+
84
+ return (
85
+ <div className={cn("rounded-lg border overflow-hidden bg-background", className)}>
86
+ {/* Header */}
87
+ <button
88
+ onClick={() => setIsExpanded(!isExpanded)}
89
+ className="flex items-center justify-between w-full px-3 py-2.5 bg-muted/50 hover:bg-muted/70 transition-colors"
90
+ >
91
+ <div className="flex items-center gap-2 min-w-0">
92
+ <StatusIcon className={cn("size-4 shrink-0", statusColor)} />
93
+ {action === "list" ? (
94
+ <ListIcon className="size-3.5 text-muted-foreground" />
95
+ ) : (
96
+ <SparklesIcon className="size-3.5 text-muted-foreground" />
97
+ )}
98
+ <span className="font-medium text-sm truncate">{headerTitle}</span>
99
+ {isLoading && (
100
+ <span className="text-xs text-muted-foreground animate-pulse">loading...</span>
101
+ )}
102
+ </div>
103
+ <div className="flex items-center gap-2 shrink-0">
104
+ {output?.skillCount !== undefined && (
105
+ <Badge variant="secondary" className="text-xs">
106
+ {output.skillCount} skills
107
+ </Badge>
108
+ )}
109
+ {output?.contentLength !== undefined && (
110
+ <Badge variant="secondary" className="text-xs">
111
+ {Math.round(output.contentLength / 1000)}k chars
112
+ </Badge>
113
+ )}
114
+ {isExpanded ? (
115
+ <ChevronDownIcon className="size-4 text-muted-foreground" />
116
+ ) : (
117
+ <ChevronRightIcon className="size-4 text-muted-foreground" />
118
+ )}
119
+ </div>
120
+ </button>
121
+
122
+ {/* Content */}
123
+ {isExpanded && (
124
+ <div className="border-t">
125
+ {/* List of skills */}
126
+ {output?.skills && output.skills.length > 0 && (
127
+ <div className="max-h-[200px] overflow-auto">
128
+ {output.skills.map((skill, i) => (
129
+ <div
130
+ key={skill.name}
131
+ className={cn(
132
+ "px-3 py-2 flex items-start gap-2",
133
+ i < output.skills!.length - 1 && "border-b"
134
+ )}
135
+ >
136
+ <BookOpenIcon className="size-4 mt-0.5 shrink-0 text-muted-foreground" />
137
+ <div className="min-w-0">
138
+ <div className="font-medium text-sm">{skill.name}</div>
139
+ {skill.description && (
140
+ <div className="text-xs text-muted-foreground truncate">
141
+ {skill.description}
142
+ </div>
143
+ )}
144
+ </div>
145
+ </div>
146
+ ))}
147
+ </div>
148
+ )}
149
+
150
+ {/* Loaded skill info */}
151
+ {action === "load" && output?.success && output.skillName && (
152
+ <div className="px-3 py-2 bg-muted/30">
153
+ <div className="flex items-center justify-between">
154
+ <div className="flex items-center gap-2">
155
+ <SparklesIcon className="size-4 text-green-600 dark:text-green-400" />
156
+ <span className="font-medium text-sm">{output.skillName}</span>
157
+ </div>
158
+ {output.content && (
159
+ <Button
160
+ variant="ghost"
161
+ size="icon"
162
+ className="size-6"
163
+ onClick={(e) => {
164
+ e.stopPropagation();
165
+ navigator.clipboard.writeText(output.content!);
166
+ }}
167
+ >
168
+ <CopyIcon className="size-3" />
169
+ </Button>
170
+ )}
171
+ </div>
172
+ {output.description && (
173
+ <p className="text-xs text-muted-foreground mt-1">{output.description}</p>
174
+ )}
175
+ </div>
176
+ )}
177
+
178
+ {/* Skill content preview */}
179
+ {output?.content && (
180
+ <div className="max-h-[150px] overflow-auto border-t">
181
+ <pre className="px-3 py-2 text-xs font-mono text-muted-foreground whitespace-pre-wrap">
182
+ {output.content.slice(0, 500)}
183
+ {output.content.length > 500 && "..."}
184
+ </pre>
185
+ </div>
186
+ )}
187
+
188
+ {/* Available skills hint on error */}
189
+ {output?.availableSkills && output.availableSkills.length > 0 && (
190
+ <div className="px-3 py-2 bg-muted/30 border-t">
191
+ <div className="text-xs text-muted-foreground">
192
+ Available: {output.availableSkills.join(", ")}
193
+ </div>
194
+ </div>
195
+ )}
196
+
197
+ {/* Empty state */}
198
+ {action === "list" && output?.skills?.length === 0 && (
199
+ <div className="px-3 py-4 text-center text-muted-foreground text-sm">
200
+ No skills available
201
+ </div>
202
+ )}
203
+
204
+ {/* Error message */}
205
+ {output?.error && (
206
+ <div className="px-3 py-2 border-t bg-red-500/5 text-red-600 dark:text-red-400 text-xs flex items-start gap-2">
207
+ <XCircleIcon className="size-3.5 mt-0.5 shrink-0" />
208
+ <span>{output.error}</span>
209
+ </div>
210
+ )}
211
+ </div>
212
+ )}
213
+ </div>
214
+ );
215
+ }
@@ -0,0 +1,96 @@
1
+ import { cn } from "@/lib/utils";
2
+ import type { HTMLAttributes } from "react";
3
+
4
+ interface LoaderIconProps {
5
+ size?: number;
6
+ }
7
+
8
+ const LoaderIcon = ({ size = 16 }: LoaderIconProps) => (
9
+ <svg
10
+ height={size}
11
+ strokeLinejoin="round"
12
+ style={{ color: "currentcolor" }}
13
+ viewBox="0 0 16 16"
14
+ width={size}
15
+ >
16
+ <title>Loader</title>
17
+ <g clipPath="url(#clip0_2393_1490)">
18
+ <path d="M8 0V4" stroke="currentColor" strokeWidth="1.5" />
19
+ <path
20
+ d="M8 16V12"
21
+ opacity="0.5"
22
+ stroke="currentColor"
23
+ strokeWidth="1.5"
24
+ />
25
+ <path
26
+ d="M3.29773 1.52783L5.64887 4.7639"
27
+ opacity="0.9"
28
+ stroke="currentColor"
29
+ strokeWidth="1.5"
30
+ />
31
+ <path
32
+ d="M12.7023 1.52783L10.3511 4.7639"
33
+ opacity="0.1"
34
+ stroke="currentColor"
35
+ strokeWidth="1.5"
36
+ />
37
+ <path
38
+ d="M12.7023 14.472L10.3511 11.236"
39
+ opacity="0.4"
40
+ stroke="currentColor"
41
+ strokeWidth="1.5"
42
+ />
43
+ <path
44
+ d="M3.29773 14.472L5.64887 11.236"
45
+ opacity="0.6"
46
+ stroke="currentColor"
47
+ strokeWidth="1.5"
48
+ />
49
+ <path
50
+ d="M15.6085 5.52783L11.8043 6.7639"
51
+ opacity="0.2"
52
+ stroke="currentColor"
53
+ strokeWidth="1.5"
54
+ />
55
+ <path
56
+ d="M0.391602 10.472L4.19583 9.23598"
57
+ opacity="0.7"
58
+ stroke="currentColor"
59
+ strokeWidth="1.5"
60
+ />
61
+ <path
62
+ d="M15.6085 10.4722L11.8043 9.2361"
63
+ opacity="0.3"
64
+ stroke="currentColor"
65
+ strokeWidth="1.5"
66
+ />
67
+ <path
68
+ d="M0.391602 5.52783L4.19583 6.7639"
69
+ opacity="0.8"
70
+ stroke="currentColor"
71
+ strokeWidth="1.5"
72
+ />
73
+ </g>
74
+ <defs>
75
+ <clipPath id="clip0_2393_1490">
76
+ <rect fill="white" height="16" width="16" />
77
+ </clipPath>
78
+ </defs>
79
+ </svg>
80
+ );
81
+
82
+ export type LoaderProps = HTMLAttributes<HTMLDivElement> & {
83
+ size?: number;
84
+ };
85
+
86
+ export const Loader = ({ className, size = 16, ...props }: LoaderProps) => (
87
+ <div
88
+ className={cn(
89
+ "inline-flex animate-spin items-center justify-center",
90
+ className
91
+ )}
92
+ {...props}
93
+ >
94
+ <LoaderIcon size={size} />
95
+ </div>
96
+ );