stagent 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 (333) hide show
  1. package/LICENSE +191 -0
  2. package/README.md +399 -0
  3. package/components.json +21 -0
  4. package/dist/cli.js +171 -0
  5. package/drizzle.config.ts +12 -0
  6. package/next.config.mjs +15 -0
  7. package/package.json +114 -0
  8. package/postcss.config.mjs +8 -0
  9. package/public/icon-512.png +0 -0
  10. package/public/icon.svg +13 -0
  11. package/public/readme/home-workspace.png +0 -0
  12. package/public/readme/inbox-approvals.png +0 -0
  13. package/public/readme/workflow-blueprints.png +0 -0
  14. package/public/stagent-s-128.png +0 -0
  15. package/public/stagent-s-64.png +0 -0
  16. package/src/app/api/blueprints/[id]/instantiate/route.ts +27 -0
  17. package/src/app/api/blueprints/[id]/route.ts +39 -0
  18. package/src/app/api/blueprints/import/route.ts +68 -0
  19. package/src/app/api/blueprints/route.ts +29 -0
  20. package/src/app/api/command-palette/recent/route.ts +31 -0
  21. package/src/app/api/data/clear/route.ts +22 -0
  22. package/src/app/api/data/seed/route.ts +22 -0
  23. package/src/app/api/documents/[id]/file/route.ts +44 -0
  24. package/src/app/api/documents/[id]/route.ts +123 -0
  25. package/src/app/api/documents/route.ts +59 -0
  26. package/src/app/api/logs/stream/route.ts +101 -0
  27. package/src/app/api/notifications/[id]/route.ts +36 -0
  28. package/src/app/api/notifications/mark-all-read/route.ts +13 -0
  29. package/src/app/api/notifications/pending-approvals/route.ts +10 -0
  30. package/src/app/api/notifications/pending-approvals/stream/route.ts +101 -0
  31. package/src/app/api/notifications/route.ts +34 -0
  32. package/src/app/api/permissions/route.ts +46 -0
  33. package/src/app/api/profiles/[id]/route.ts +79 -0
  34. package/src/app/api/profiles/[id]/test/route.ts +42 -0
  35. package/src/app/api/profiles/import/route.ts +108 -0
  36. package/src/app/api/profiles/route.ts +50 -0
  37. package/src/app/api/projects/[id]/route.ts +72 -0
  38. package/src/app/api/projects/route.ts +53 -0
  39. package/src/app/api/schedules/[id]/route.ts +185 -0
  40. package/src/app/api/schedules/route.ts +117 -0
  41. package/src/app/api/settings/budgets/route.ts +24 -0
  42. package/src/app/api/settings/openai/route.ts +24 -0
  43. package/src/app/api/settings/route.ts +21 -0
  44. package/src/app/api/settings/test/route.ts +26 -0
  45. package/src/app/api/tasks/[id]/cancel/route.ts +21 -0
  46. package/src/app/api/tasks/[id]/execute/route.ts +90 -0
  47. package/src/app/api/tasks/[id]/logs/route.ts +95 -0
  48. package/src/app/api/tasks/[id]/output/route.ts +47 -0
  49. package/src/app/api/tasks/[id]/respond/route.ts +64 -0
  50. package/src/app/api/tasks/[id]/resume/route.ts +76 -0
  51. package/src/app/api/tasks/[id]/route.ts +77 -0
  52. package/src/app/api/tasks/assist/route.ts +35 -0
  53. package/src/app/api/tasks/route.ts +82 -0
  54. package/src/app/api/uploads/[id]/route.ts +81 -0
  55. package/src/app/api/uploads/cleanup/route.ts +7 -0
  56. package/src/app/api/uploads/route.ts +66 -0
  57. package/src/app/api/workflows/[id]/execute/route.ts +82 -0
  58. package/src/app/api/workflows/[id]/route.ts +133 -0
  59. package/src/app/api/workflows/[id]/status/route.ts +54 -0
  60. package/src/app/api/workflows/[id]/steps/[stepId]/retry/route.ts +22 -0
  61. package/src/app/api/workflows/route.ts +61 -0
  62. package/src/app/apple-icon.tsx +31 -0
  63. package/src/app/costs/page.tsx +256 -0
  64. package/src/app/dashboard/page.tsx +44 -0
  65. package/src/app/documents/[id]/page.tsx +46 -0
  66. package/src/app/documents/page.tsx +45 -0
  67. package/src/app/error.tsx +26 -0
  68. package/src/app/global-error.tsx +23 -0
  69. package/src/app/globals.css +733 -0
  70. package/src/app/icon.tsx +30 -0
  71. package/src/app/inbox/loading.tsx +15 -0
  72. package/src/app/inbox/page.tsx +35 -0
  73. package/src/app/layout.tsx +78 -0
  74. package/src/app/manifest.ts +32 -0
  75. package/src/app/monitor/page.tsx +37 -0
  76. package/src/app/page.tsx +162 -0
  77. package/src/app/profiles/[id]/edit/page.tsx +39 -0
  78. package/src/app/profiles/[id]/page.tsx +33 -0
  79. package/src/app/profiles/new/page.tsx +22 -0
  80. package/src/app/profiles/page.tsx +19 -0
  81. package/src/app/projects/[id]/page.tsx +134 -0
  82. package/src/app/projects/loading.tsx +17 -0
  83. package/src/app/projects/page.tsx +32 -0
  84. package/src/app/schedules/[id]/page.tsx +47 -0
  85. package/src/app/schedules/page.tsx +18 -0
  86. package/src/app/settings/loading.tsx +24 -0
  87. package/src/app/settings/page.tsx +27 -0
  88. package/src/app/tasks/[id]/page.tsx +45 -0
  89. package/src/app/tasks/new/page.tsx +27 -0
  90. package/src/app/workflows/[id]/edit/page.tsx +66 -0
  91. package/src/app/workflows/[id]/page.tsx +37 -0
  92. package/src/app/workflows/blueprints/[id]/page.tsx +40 -0
  93. package/src/app/workflows/blueprints/new/page.tsx +20 -0
  94. package/src/app/workflows/blueprints/page.tsx +11 -0
  95. package/src/app/workflows/new/page.tsx +36 -0
  96. package/src/app/workflows/page.tsx +18 -0
  97. package/src/components/charts/donut-ring.tsx +64 -0
  98. package/src/components/charts/mini-bar.tsx +75 -0
  99. package/src/components/charts/sparkline.tsx +107 -0
  100. package/src/components/costs/cost-dashboard.tsx +877 -0
  101. package/src/components/costs/cost-filters.tsx +179 -0
  102. package/src/components/dashboard/activity-feed.tsx +95 -0
  103. package/src/components/dashboard/greeting.tsx +30 -0
  104. package/src/components/dashboard/priority-queue.tsx +79 -0
  105. package/src/components/dashboard/quick-actions.tsx +62 -0
  106. package/src/components/dashboard/recent-projects.tsx +79 -0
  107. package/src/components/dashboard/stats-cards.tsx +114 -0
  108. package/src/components/documents/document-browser.tsx +235 -0
  109. package/src/components/documents/document-detail-view.tsx +367 -0
  110. package/src/components/documents/document-grid.tsx +78 -0
  111. package/src/components/documents/document-preview.tsx +68 -0
  112. package/src/components/documents/document-table.tsx +119 -0
  113. package/src/components/documents/document-upload-dialog.tsx +153 -0
  114. package/src/components/documents/types.ts +6 -0
  115. package/src/components/documents/utils.ts +57 -0
  116. package/src/components/monitoring/connection-indicator.tsx +14 -0
  117. package/src/components/monitoring/log-entry.tsx +79 -0
  118. package/src/components/monitoring/log-filters.tsx +57 -0
  119. package/src/components/monitoring/log-stream.tsx +144 -0
  120. package/src/components/monitoring/monitor-overview-wrapper.tsx +64 -0
  121. package/src/components/monitoring/monitor-overview.tsx +119 -0
  122. package/src/components/notifications/failure-action.tsx +38 -0
  123. package/src/components/notifications/inbox-list.tsx +165 -0
  124. package/src/components/notifications/message-response.tsx +196 -0
  125. package/src/components/notifications/notification-item.tsx +250 -0
  126. package/src/components/notifications/pending-approval-host.tsx +478 -0
  127. package/src/components/notifications/permission-action.tsx +37 -0
  128. package/src/components/notifications/permission-response-actions.tsx +126 -0
  129. package/src/components/notifications/unread-badge.tsx +35 -0
  130. package/src/components/profiles/profile-browser.tsx +117 -0
  131. package/src/components/profiles/profile-card.tsx +78 -0
  132. package/src/components/profiles/profile-detail-view.tsx +564 -0
  133. package/src/components/profiles/profile-form-view.tsx +480 -0
  134. package/src/components/profiles/profile-import-dialog.tsx +113 -0
  135. package/src/components/projects/project-card.tsx +58 -0
  136. package/src/components/projects/project-create-dialog.tsx +140 -0
  137. package/src/components/projects/project-detail.tsx +68 -0
  138. package/src/components/projects/project-edit-dialog.tsx +219 -0
  139. package/src/components/projects/project-list.tsx +108 -0
  140. package/src/components/schedules/schedule-create-dialog.tsx +403 -0
  141. package/src/components/schedules/schedule-detail-view.tsx +274 -0
  142. package/src/components/schedules/schedule-list.tsx +242 -0
  143. package/src/components/schedules/schedule-status-badge.tsx +16 -0
  144. package/src/components/settings/api-key-form.tsx +141 -0
  145. package/src/components/settings/auth-config-section.tsx +141 -0
  146. package/src/components/settings/auth-method-selector.tsx +67 -0
  147. package/src/components/settings/auth-status-badge.tsx +40 -0
  148. package/src/components/settings/auth-status-dot.tsx +59 -0
  149. package/src/components/settings/budget-guardrails-section.tsx +842 -0
  150. package/src/components/settings/data-management-section.tsx +141 -0
  151. package/src/components/settings/openai-runtime-section.tsx +104 -0
  152. package/src/components/settings/permissions-section.tsx +91 -0
  153. package/src/components/shared/app-sidebar.tsx +123 -0
  154. package/src/components/shared/card-skeleton.tsx +42 -0
  155. package/src/components/shared/command-palette.tsx +250 -0
  156. package/src/components/shared/confirm-dialog.tsx +52 -0
  157. package/src/components/shared/empty-state.tsx +24 -0
  158. package/src/components/shared/error-state.tsx +32 -0
  159. package/src/components/shared/form-section-card.tsx +33 -0
  160. package/src/components/shared/section-heading.tsx +14 -0
  161. package/src/components/shared/stagent-logo.tsx +21 -0
  162. package/src/components/shared/theme-toggle.tsx +46 -0
  163. package/src/components/tasks/ai-assist-panel.tsx +210 -0
  164. package/src/components/tasks/content-preview.tsx +89 -0
  165. package/src/components/tasks/empty-board.tsx +12 -0
  166. package/src/components/tasks/file-upload.tsx +120 -0
  167. package/src/components/tasks/kanban-board.tsx +275 -0
  168. package/src/components/tasks/kanban-column.tsx +75 -0
  169. package/src/components/tasks/skeleton-board.tsx +21 -0
  170. package/src/components/tasks/task-attachments.tsx +114 -0
  171. package/src/components/tasks/task-card.tsx +101 -0
  172. package/src/components/tasks/task-create-panel.tsx +360 -0
  173. package/src/components/tasks/task-detail-view.tsx +356 -0
  174. package/src/components/ui/alert-dialog.tsx +196 -0
  175. package/src/components/ui/badge.tsx +50 -0
  176. package/src/components/ui/button.tsx +71 -0
  177. package/src/components/ui/card.tsx +92 -0
  178. package/src/components/ui/checkbox.tsx +32 -0
  179. package/src/components/ui/command.tsx +184 -0
  180. package/src/components/ui/dialog.tsx +158 -0
  181. package/src/components/ui/dropdown-menu.tsx +257 -0
  182. package/src/components/ui/form.tsx +167 -0
  183. package/src/components/ui/input.tsx +21 -0
  184. package/src/components/ui/label.tsx +24 -0
  185. package/src/components/ui/popover.tsx +89 -0
  186. package/src/components/ui/progress.tsx +31 -0
  187. package/src/components/ui/radio-group.tsx +45 -0
  188. package/src/components/ui/scroll-area.tsx +58 -0
  189. package/src/components/ui/select.tsx +190 -0
  190. package/src/components/ui/separator.tsx +28 -0
  191. package/src/components/ui/sheet.tsx +143 -0
  192. package/src/components/ui/sidebar.tsx +726 -0
  193. package/src/components/ui/skeleton.tsx +13 -0
  194. package/src/components/ui/slider.tsx +63 -0
  195. package/src/components/ui/sonner.tsx +36 -0
  196. package/src/components/ui/switch.tsx +35 -0
  197. package/src/components/ui/table.tsx +116 -0
  198. package/src/components/ui/tabs.tsx +91 -0
  199. package/src/components/ui/textarea.tsx +18 -0
  200. package/src/components/ui/tooltip.tsx +57 -0
  201. package/src/components/workflows/blueprint-editor.tsx +109 -0
  202. package/src/components/workflows/blueprint-gallery.tsx +155 -0
  203. package/src/components/workflows/blueprint-preview.tsx +240 -0
  204. package/src/components/workflows/loop-status-view.tsx +272 -0
  205. package/src/components/workflows/swarm-dashboard.tsx +185 -0
  206. package/src/components/workflows/workflow-form-view.tsx +1376 -0
  207. package/src/components/workflows/workflow-list.tsx +230 -0
  208. package/src/components/workflows/workflow-status-view.tsx +477 -0
  209. package/src/hooks/use-mobile.ts +19 -0
  210. package/src/instrumentation.ts +7 -0
  211. package/src/lib/agents/claude-agent.ts +737 -0
  212. package/src/lib/agents/execution-manager.ts +27 -0
  213. package/src/lib/agents/profiles/assignment-validation.ts +75 -0
  214. package/src/lib/agents/profiles/builtins/code-reviewer/SKILL.md +21 -0
  215. package/src/lib/agents/profiles/builtins/code-reviewer/profile.yaml +28 -0
  216. package/src/lib/agents/profiles/builtins/data-analyst/SKILL.md +25 -0
  217. package/src/lib/agents/profiles/builtins/data-analyst/profile.yaml +27 -0
  218. package/src/lib/agents/profiles/builtins/devops-engineer/SKILL.md +34 -0
  219. package/src/lib/agents/profiles/builtins/devops-engineer/profile.yaml +27 -0
  220. package/src/lib/agents/profiles/builtins/document-writer/SKILL.md +16 -0
  221. package/src/lib/agents/profiles/builtins/document-writer/profile.yaml +27 -0
  222. package/src/lib/agents/profiles/builtins/general/SKILL.md +13 -0
  223. package/src/lib/agents/profiles/builtins/general/profile.yaml +18 -0
  224. package/src/lib/agents/profiles/builtins/health-fitness-coach/SKILL.md +34 -0
  225. package/src/lib/agents/profiles/builtins/health-fitness-coach/profile.yaml +26 -0
  226. package/src/lib/agents/profiles/builtins/learning-coach/SKILL.md +35 -0
  227. package/src/lib/agents/profiles/builtins/learning-coach/profile.yaml +26 -0
  228. package/src/lib/agents/profiles/builtins/project-manager/SKILL.md +26 -0
  229. package/src/lib/agents/profiles/builtins/project-manager/profile.yaml +26 -0
  230. package/src/lib/agents/profiles/builtins/researcher/SKILL.md +15 -0
  231. package/src/lib/agents/profiles/builtins/researcher/profile.yaml +27 -0
  232. package/src/lib/agents/profiles/builtins/shopping-assistant/SKILL.md +34 -0
  233. package/src/lib/agents/profiles/builtins/shopping-assistant/profile.yaml +26 -0
  234. package/src/lib/agents/profiles/builtins/technical-writer/SKILL.md +31 -0
  235. package/src/lib/agents/profiles/builtins/technical-writer/profile.yaml +29 -0
  236. package/src/lib/agents/profiles/builtins/travel-planner/SKILL.md +23 -0
  237. package/src/lib/agents/profiles/builtins/travel-planner/profile.yaml +26 -0
  238. package/src/lib/agents/profiles/builtins/wealth-manager/SKILL.md +24 -0
  239. package/src/lib/agents/profiles/builtins/wealth-manager/profile.yaml +26 -0
  240. package/src/lib/agents/profiles/compatibility.ts +109 -0
  241. package/src/lib/agents/profiles/registry.ts +293 -0
  242. package/src/lib/agents/profiles/test-runner.ts +18 -0
  243. package/src/lib/agents/profiles/test-types.ts +20 -0
  244. package/src/lib/agents/profiles/types.ts +43 -0
  245. package/src/lib/agents/router.ts +56 -0
  246. package/src/lib/agents/runtime/catalog.ts +85 -0
  247. package/src/lib/agents/runtime/claude-sdk.ts +12 -0
  248. package/src/lib/agents/runtime/claude.ts +370 -0
  249. package/src/lib/agents/runtime/codex-app-server-client.ts +289 -0
  250. package/src/lib/agents/runtime/index.ts +167 -0
  251. package/src/lib/agents/runtime/openai-codex.ts +1089 -0
  252. package/src/lib/agents/runtime/task-assist-types.ts +8 -0
  253. package/src/lib/agents/runtime/types.ts +30 -0
  254. package/src/lib/constants/settings.ts +13 -0
  255. package/src/lib/constants/status-colors.ts +44 -0
  256. package/src/lib/constants/task-status.ts +49 -0
  257. package/src/lib/data/clear.ts +63 -0
  258. package/src/lib/data/seed-data/documents.ts +715 -0
  259. package/src/lib/data/seed-data/logs.ts +195 -0
  260. package/src/lib/data/seed-data/notifications.ts +141 -0
  261. package/src/lib/data/seed-data/profiles.ts +175 -0
  262. package/src/lib/data/seed-data/projects.ts +61 -0
  263. package/src/lib/data/seed-data/schedules.ts +108 -0
  264. package/src/lib/data/seed-data/tasks.ts +341 -0
  265. package/src/lib/data/seed-data/usage-ledger.ts +130 -0
  266. package/src/lib/data/seed-data/workflows.ts +213 -0
  267. package/src/lib/data/seed.ts +129 -0
  268. package/src/lib/db/index.ts +221 -0
  269. package/src/lib/db/migrations/0000_aromatic_gargoyle.sql +59 -0
  270. package/src/lib/db/migrations/0001_first_iron_patriot.sql +6 -0
  271. package/src/lib/db/migrations/0002_add_resume_count.sql +1 -0
  272. package/src/lib/db/migrations/0003_add_settings.sql +5 -0
  273. package/src/lib/db/migrations/0004_add_documents.sql +20 -0
  274. package/src/lib/db/migrations/0005_add_document_preprocessing.sql +4 -0
  275. package/src/lib/db/migrations/0006_add_agent_profile.sql +2 -0
  276. package/src/lib/db/migrations/0007_add_usage_metering_ledger.sql +30 -0
  277. package/src/lib/db/migrations/0008_add_document_version.sql +1 -0
  278. package/src/lib/db/migrations/meta/0000_snapshot.json +416 -0
  279. package/src/lib/db/migrations/meta/0001_snapshot.json +461 -0
  280. package/src/lib/db/migrations/meta/0002_snapshot.json +469 -0
  281. package/src/lib/db/migrations/meta/_journal.json +27 -0
  282. package/src/lib/db/schema.ts +227 -0
  283. package/src/lib/documents/cleanup.ts +50 -0
  284. package/src/lib/documents/context-builder.ts +75 -0
  285. package/src/lib/documents/output-scanner.ts +166 -0
  286. package/src/lib/documents/processor.ts +120 -0
  287. package/src/lib/documents/processors/image.ts +21 -0
  288. package/src/lib/documents/processors/office.ts +36 -0
  289. package/src/lib/documents/processors/pdf.ts +12 -0
  290. package/src/lib/documents/processors/spreadsheet.ts +18 -0
  291. package/src/lib/documents/processors/text.ts +8 -0
  292. package/src/lib/documents/registry.ts +25 -0
  293. package/src/lib/notifications/actionable.ts +108 -0
  294. package/src/lib/notifications/permissions.ts +169 -0
  295. package/src/lib/queries/chart-data.ts +184 -0
  296. package/src/lib/schedules/interval-parser.ts +110 -0
  297. package/src/lib/schedules/scheduler.ts +220 -0
  298. package/src/lib/settings/auth.ts +98 -0
  299. package/src/lib/settings/budget-guardrails.ts +590 -0
  300. package/src/lib/settings/helpers.ts +23 -0
  301. package/src/lib/settings/openai-auth.ts +80 -0
  302. package/src/lib/settings/permissions.ts +102 -0
  303. package/src/lib/usage/ledger.ts +489 -0
  304. package/src/lib/usage/pricing.ts +68 -0
  305. package/src/lib/utils/crypto.ts +90 -0
  306. package/src/lib/utils/format-timestamp.ts +46 -0
  307. package/src/lib/utils/session-cleanup.ts +26 -0
  308. package/src/lib/utils/stagent-paths.ts +18 -0
  309. package/src/lib/utils.ts +6 -0
  310. package/src/lib/validators/blueprint.ts +43 -0
  311. package/src/lib/validators/profile.ts +64 -0
  312. package/src/lib/validators/project.ts +17 -0
  313. package/src/lib/validators/settings.ts +57 -0
  314. package/src/lib/validators/task.ts +30 -0
  315. package/src/lib/workflows/blueprints/builtins/code-review-pipeline.yaml +72 -0
  316. package/src/lib/workflows/blueprints/builtins/documentation-generation.yaml +62 -0
  317. package/src/lib/workflows/blueprints/builtins/investment-research.yaml +81 -0
  318. package/src/lib/workflows/blueprints/builtins/meal-planning.yaml +73 -0
  319. package/src/lib/workflows/blueprints/builtins/product-research.yaml +72 -0
  320. package/src/lib/workflows/blueprints/builtins/research-report.yaml +77 -0
  321. package/src/lib/workflows/blueprints/builtins/sprint-planning.yaml +77 -0
  322. package/src/lib/workflows/blueprints/builtins/travel-planning.yaml +80 -0
  323. package/src/lib/workflows/blueprints/instantiator.ts +131 -0
  324. package/src/lib/workflows/blueprints/registry.ts +128 -0
  325. package/src/lib/workflows/blueprints/template.ts +58 -0
  326. package/src/lib/workflows/blueprints/types.ts +38 -0
  327. package/src/lib/workflows/definition-validation.ts +121 -0
  328. package/src/lib/workflows/engine.ts +1113 -0
  329. package/src/lib/workflows/loop-executor.ts +270 -0
  330. package/src/lib/workflows/parallel.ts +55 -0
  331. package/src/lib/workflows/swarm.ts +97 -0
  332. package/src/lib/workflows/types.ts +112 -0
  333. package/tsconfig.json +41 -0
@@ -0,0 +1,250 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState, useCallback, useRef } from "react";
4
+ import { useRouter } from "next/navigation";
5
+ import {
6
+ CommandDialog,
7
+ CommandEmpty,
8
+ CommandGroup,
9
+ CommandInput,
10
+ CommandItem,
11
+ CommandList,
12
+ CommandSeparator,
13
+ CommandShortcut,
14
+ } from "@/components/ui/command";
15
+ import {
16
+ Home,
17
+ LayoutDashboard,
18
+ Inbox,
19
+ Activity,
20
+ FolderKanban,
21
+ GitBranch,
22
+ FileText,
23
+ Bot,
24
+ Clock,
25
+ Wallet,
26
+ Settings,
27
+ Plus,
28
+ Sun,
29
+ Moon,
30
+ CheckCheck,
31
+ Loader2,
32
+ } from "lucide-react";
33
+
34
+ interface RecentProject {
35
+ id: string;
36
+ name: string;
37
+ status: string;
38
+ }
39
+
40
+ interface RecentTask {
41
+ id: string;
42
+ title: string;
43
+ status: string;
44
+ }
45
+
46
+ const navigationItems = [
47
+ { title: "Home", href: "/", icon: Home, keywords: "landing welcome" },
48
+ { title: "Dashboard", href: "/dashboard", icon: LayoutDashboard, keywords: "tasks kanban board" },
49
+ { title: "Inbox", href: "/inbox", icon: Inbox, keywords: "notifications messages" },
50
+ { title: "Monitor", href: "/monitor", icon: Activity, keywords: "logs agents streaming" },
51
+ { title: "Projects", href: "/projects", icon: FolderKanban, keywords: "manage" },
52
+ { title: "Workflows", href: "/workflows", icon: GitBranch, keywords: "automation steps sequence" },
53
+ { title: "Documents", href: "/documents", icon: FileText, keywords: "files uploads attachments" },
54
+ { title: "Profiles", href: "/profiles", icon: Bot, keywords: "agents configuration" },
55
+ { title: "Schedules", href: "/schedules", icon: Clock, keywords: "cron recurring timer" },
56
+ { title: "Cost & Usage", href: "/costs", icon: Wallet, keywords: "spend tokens metering budget analytics" },
57
+ { title: "Settings", href: "/settings", icon: Settings, keywords: "preferences configuration" },
58
+ ];
59
+
60
+ const createItems = [
61
+ { title: "New Task", href: "/dashboard?create=task", keywords: "create add task" },
62
+ { title: "New Project", href: "/projects?create=project", keywords: "create add project" },
63
+ { title: "New Workflow", href: "/workflows/new", keywords: "create add workflow automation" },
64
+ { title: "New Profile", href: "/profiles/new", keywords: "create add agent profile" },
65
+ ];
66
+
67
+ function statusColorClass(status: string): string {
68
+ switch (status) {
69
+ case "running":
70
+ return "text-status-running";
71
+ case "completed":
72
+ return "text-status-completed";
73
+ case "failed":
74
+ return "text-status-failed";
75
+ default:
76
+ return "text-muted-foreground";
77
+ }
78
+ }
79
+
80
+ export function CommandPalette() {
81
+ const [open, setOpen] = useState(false);
82
+ const [recentProjects, setRecentProjects] = useState<RecentProject[]>([]);
83
+ const [recentTasks, setRecentTasks] = useState<RecentTask[]>([]);
84
+ const [loadingRecent, setLoadingRecent] = useState(false);
85
+ const abortRef = useRef<AbortController | null>(null);
86
+ const router = useRouter();
87
+
88
+ useEffect(() => {
89
+ function handleKeyDown(e: KeyboardEvent) {
90
+ if ((e.metaKey || e.ctrlKey) && e.key === "k") {
91
+ e.preventDefault();
92
+ setOpen((prev) => !prev);
93
+ }
94
+ }
95
+ document.addEventListener("keydown", handleKeyDown);
96
+ return () => document.removeEventListener("keydown", handleKeyDown);
97
+ }, []);
98
+
99
+ // Fetch recent items when palette opens
100
+ useEffect(() => {
101
+ if (!open) {
102
+ abortRef.current?.abort();
103
+ abortRef.current = null;
104
+ return;
105
+ }
106
+
107
+ const controller = new AbortController();
108
+ abortRef.current = controller;
109
+ setLoadingRecent(true);
110
+
111
+ fetch("/api/command-palette/recent", { signal: controller.signal })
112
+ .then((res) => (res.ok ? res.json() : null))
113
+ .then((data) => {
114
+ if (data) {
115
+ setRecentProjects(data.projects);
116
+ setRecentTasks(data.tasks);
117
+ }
118
+ })
119
+ .catch(() => {
120
+ // Aborted or failed — ignore
121
+ })
122
+ .finally(() => setLoadingRecent(false));
123
+ }, [open]);
124
+
125
+ const navigate = useCallback(
126
+ (href: string) => {
127
+ setOpen(false);
128
+ router.push(href);
129
+ },
130
+ [router]
131
+ );
132
+
133
+ function toggleTheme() {
134
+ setOpen(false);
135
+ const isDark = document.documentElement.classList.contains("dark");
136
+ document.documentElement.classList.toggle("dark");
137
+ localStorage.setItem("stagent-theme", isDark ? "light" : "dark");
138
+ }
139
+
140
+ async function markAllRead() {
141
+ setOpen(false);
142
+ await fetch("/api/notifications/mark-all-read", { method: "PATCH" });
143
+ router.refresh();
144
+ }
145
+
146
+ const hasRecent = recentProjects.length > 0 || recentTasks.length > 0;
147
+
148
+ return (
149
+ <CommandDialog open={open} onOpenChange={setOpen}>
150
+ <CommandInput placeholder="Type a command or search..." />
151
+ <CommandList>
152
+ <CommandEmpty>No results found.</CommandEmpty>
153
+
154
+ {/* Recent Items */}
155
+ {(loadingRecent || hasRecent) && (
156
+ <CommandGroup heading="Recent">
157
+ {loadingRecent && !hasRecent ? (
158
+ <div className="flex items-center gap-2 px-2 py-3 text-sm text-muted-foreground">
159
+ <Loader2 className="h-4 w-4 animate-spin" />
160
+ Loading recent items...
161
+ </div>
162
+ ) : (
163
+ <>
164
+ {recentProjects.map((project) => (
165
+ <CommandItem
166
+ key={`project-${project.id}`}
167
+ value={`recent-project-${project.name}`}
168
+ onSelect={() => navigate(`/projects/${project.id}`)}
169
+ keywords={["recent", "project"]}
170
+ >
171
+ <FolderKanban className="h-4 w-4" />
172
+ <span className="flex-1 truncate">{project.name}</span>
173
+ <span className={`text-xs ${statusColorClass(project.status)}`}>
174
+ {project.status}
175
+ </span>
176
+ </CommandItem>
177
+ ))}
178
+ {recentTasks.map((task) => (
179
+ <CommandItem
180
+ key={`task-${task.id}`}
181
+ value={`recent-task-${task.title}`}
182
+ onSelect={() => navigate(`/dashboard?task=${task.id}`)}
183
+ keywords={["recent", "task"]}
184
+ >
185
+ <LayoutDashboard className="h-4 w-4" />
186
+ <span className="flex-1 truncate">{task.title}</span>
187
+ <span className={`text-xs ${statusColorClass(task.status)}`}>
188
+ {task.status}
189
+ </span>
190
+ </CommandItem>
191
+ ))}
192
+ </>
193
+ )}
194
+ </CommandGroup>
195
+ )}
196
+
197
+ {hasRecent && <CommandSeparator />}
198
+
199
+ {/* Navigation */}
200
+ <CommandGroup heading="Navigation">
201
+ {navigationItems.map((item) => (
202
+ <CommandItem
203
+ key={item.href}
204
+ value={item.title}
205
+ onSelect={() => navigate(item.href)}
206
+ keywords={[item.keywords]}
207
+ >
208
+ <item.icon className="h-4 w-4" />
209
+ {item.title}
210
+ </CommandItem>
211
+ ))}
212
+ </CommandGroup>
213
+
214
+ <CommandSeparator />
215
+
216
+ {/* Create */}
217
+ <CommandGroup heading="Create">
218
+ {createItems.map((item) => (
219
+ <CommandItem
220
+ key={item.href}
221
+ value={item.title}
222
+ onSelect={() => navigate(item.href)}
223
+ keywords={[item.keywords]}
224
+ >
225
+ <Plus className="h-4 w-4" />
226
+ {item.title}
227
+ </CommandItem>
228
+ ))}
229
+ </CommandGroup>
230
+
231
+ <CommandSeparator />
232
+
233
+ {/* Utility */}
234
+ <CommandGroup heading="Utility">
235
+ <CommandItem onSelect={toggleTheme} value="Toggle Theme" keywords={["dark", "light", "mode"]}>
236
+ <Sun className="h-4 w-4 dark:hidden" />
237
+ <Moon className="h-4 w-4 hidden dark:block" />
238
+ Toggle Theme
239
+ <CommandShortcut>Theme</CommandShortcut>
240
+ </CommandItem>
241
+ <CommandItem onSelect={markAllRead} value="Mark All Notifications Read" keywords={["clear", "inbox", "unread"]}>
242
+ <CheckCheck className="h-4 w-4" />
243
+ Mark All Read
244
+ <CommandShortcut>Inbox</CommandShortcut>
245
+ </CommandItem>
246
+ </CommandGroup>
247
+ </CommandList>
248
+ </CommandDialog>
249
+ );
250
+ }
@@ -0,0 +1,52 @@
1
+ "use client";
2
+
3
+ import {
4
+ AlertDialog,
5
+ AlertDialogAction,
6
+ AlertDialogCancel,
7
+ AlertDialogContent,
8
+ AlertDialogDescription,
9
+ AlertDialogFooter,
10
+ AlertDialogHeader,
11
+ AlertDialogTitle,
12
+ } from "@/components/ui/alert-dialog";
13
+
14
+ interface ConfirmDialogProps {
15
+ open: boolean;
16
+ onOpenChange: (open: boolean) => void;
17
+ title: string;
18
+ description: string;
19
+ confirmLabel?: string;
20
+ onConfirm: () => void;
21
+ destructive?: boolean;
22
+ }
23
+
24
+ export function ConfirmDialog({
25
+ open,
26
+ onOpenChange,
27
+ title,
28
+ description,
29
+ confirmLabel = "Continue",
30
+ onConfirm,
31
+ destructive = false,
32
+ }: ConfirmDialogProps) {
33
+ return (
34
+ <AlertDialog open={open} onOpenChange={onOpenChange}>
35
+ <AlertDialogContent>
36
+ <AlertDialogHeader>
37
+ <AlertDialogTitle>{title}</AlertDialogTitle>
38
+ <AlertDialogDescription>{description}</AlertDialogDescription>
39
+ </AlertDialogHeader>
40
+ <AlertDialogFooter>
41
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
42
+ <AlertDialogAction
43
+ variant={destructive ? "destructive" : "default"}
44
+ onClick={onConfirm}
45
+ >
46
+ {confirmLabel}
47
+ </AlertDialogAction>
48
+ </AlertDialogFooter>
49
+ </AlertDialogContent>
50
+ </AlertDialog>
51
+ );
52
+ }
@@ -0,0 +1,24 @@
1
+ import { Card, CardContent } from "@/components/ui/card";
2
+ import type { LucideIcon } from "lucide-react";
3
+
4
+ interface EmptyStateProps {
5
+ icon: LucideIcon;
6
+ heading: string;
7
+ description: string;
8
+ action?: React.ReactNode;
9
+ }
10
+
11
+ export function EmptyState({ icon: Icon, heading, description, action }: EmptyStateProps) {
12
+ return (
13
+ <Card className="border-dashed">
14
+ <CardContent className="flex flex-col items-center justify-center py-12">
15
+ <Icon className="h-12 w-12 text-muted-foreground mb-4" />
16
+ <h3 className="text-lg font-medium mb-1">{heading}</h3>
17
+ <p className="text-sm text-muted-foreground text-center max-w-sm">
18
+ {description}
19
+ </p>
20
+ {action && <div className="mt-4">{action}</div>}
21
+ </CardContent>
22
+ </Card>
23
+ );
24
+ }
@@ -0,0 +1,32 @@
1
+ import { Card, CardContent } from "@/components/ui/card";
2
+ import { Button } from "@/components/ui/button";
3
+ import { AlertTriangle } from "lucide-react";
4
+
5
+ interface ErrorStateProps {
6
+ heading?: string;
7
+ description: string;
8
+ onRetry?: () => void;
9
+ }
10
+
11
+ export function ErrorState({
12
+ heading = "Something went wrong",
13
+ description,
14
+ onRetry,
15
+ }: ErrorStateProps) {
16
+ return (
17
+ <Card className="border-l-4 border-l-destructive">
18
+ <CardContent className="flex items-start gap-4 py-6">
19
+ <AlertTriangle className="h-8 w-8 text-destructive shrink-0" />
20
+ <div className="flex-1 min-w-0">
21
+ <h3 className="text-sm font-semibold mb-1">{heading}</h3>
22
+ <p className="text-sm text-muted-foreground">{description}</p>
23
+ {onRetry && (
24
+ <Button variant="outline" size="sm" className="mt-3" onClick={onRetry}>
25
+ Try again
26
+ </Button>
27
+ )}
28
+ </div>
29
+ </CardContent>
30
+ </Card>
31
+ );
32
+ }
@@ -0,0 +1,33 @@
1
+ import type { LucideIcon } from "lucide-react";
2
+ import { cn } from "@/lib/utils";
3
+
4
+ interface FormSectionCardProps {
5
+ icon: LucideIcon;
6
+ title: string;
7
+ hint?: string;
8
+ className?: string;
9
+ children: React.ReactNode;
10
+ }
11
+
12
+ export function FormSectionCard({
13
+ icon: Icon,
14
+ title,
15
+ hint,
16
+ className,
17
+ children,
18
+ }: FormSectionCardProps) {
19
+ return (
20
+ <section
21
+ className={cn("surface-card-muted rounded-lg p-4 space-y-3", className)}
22
+ >
23
+ <div className="flex items-center gap-2">
24
+ <Icon className="h-4 w-4 text-muted-foreground" />
25
+ <span className="text-sm font-medium">{title}</span>
26
+ </div>
27
+ {hint && (
28
+ <p className="text-xs text-muted-foreground -mt-1">{hint}</p>
29
+ )}
30
+ {children}
31
+ </section>
32
+ );
33
+ }
@@ -0,0 +1,14 @@
1
+ import { cn } from "@/lib/utils";
2
+
3
+ interface SectionHeadingProps {
4
+ children: React.ReactNode;
5
+ className?: string;
6
+ }
7
+
8
+ export function SectionHeading({ children, className }: SectionHeadingProps) {
9
+ return (
10
+ <h3 className={cn("text-sm font-semibold uppercase tracking-wide text-muted-foreground mb-3", className)}>
11
+ {children}
12
+ </h3>
13
+ );
14
+ }
@@ -0,0 +1,21 @@
1
+ import Image from "next/image";
2
+
3
+ interface StagentLogoProps {
4
+ size?: number;
5
+ className?: string;
6
+ variant?: "icon" | "symbol";
7
+ }
8
+
9
+ export function StagentLogo({ size = 24, className, variant = "icon" }: StagentLogoProps) {
10
+ return (
11
+ <span className={`inline-flex items-center justify-center shrink-0 ${className ?? ""}`}>
12
+ <Image
13
+ src="/stagent-s-64.png"
14
+ alt=""
15
+ width={size}
16
+ height={size}
17
+ aria-hidden="true"
18
+ />
19
+ </span>
20
+ );
21
+ }
@@ -0,0 +1,46 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+ import { Moon, Sun } from "lucide-react";
5
+ import { Button } from "@/components/ui/button";
6
+
7
+ type ResolvedTheme = "light" | "dark";
8
+
9
+ function resolveThemePreference(): ResolvedTheme {
10
+ const stored = localStorage.getItem("stagent-theme");
11
+ if (stored === "dark" || stored === "light") return stored;
12
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
13
+ }
14
+
15
+ function applyTheme(theme: ResolvedTheme) {
16
+ const root = document.documentElement;
17
+ root.classList.toggle("dark", theme === "dark");
18
+ root.dataset.theme = theme;
19
+ root.style.colorScheme = theme;
20
+ root.style.backgroundColor =
21
+ theme === "dark" ? "oklch(0.09 0.02 265)" : "oklch(0.98 0.005 260)";
22
+ localStorage.setItem("stagent-theme", theme);
23
+ document.cookie = `stagent-theme=${theme};path=/;max-age=31536000;SameSite=Lax`;
24
+ }
25
+
26
+ export function ThemeToggle() {
27
+ const [dark, setDark] = useState(false);
28
+
29
+ useEffect(() => {
30
+ const theme = resolveThemePreference();
31
+ applyTheme(theme);
32
+ setDark(theme === "dark");
33
+ }, []);
34
+
35
+ function toggle() {
36
+ const next = !dark;
37
+ applyTheme(next ? "dark" : "light");
38
+ setDark(next);
39
+ }
40
+
41
+ return (
42
+ <Button variant="ghost" size="icon" onClick={toggle} aria-label="Toggle theme">
43
+ {dark ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />}
44
+ </Button>
45
+ );
46
+ }
@@ -0,0 +1,210 @@
1
+ "use client";
2
+
3
+ import { useState } from "react";
4
+ import { Button } from "@/components/ui/button";
5
+ import { Card, CardContent } from "@/components/ui/card";
6
+ import { Badge } from "@/components/ui/badge";
7
+ import { Sparkles, Loader2, Check, X } from "lucide-react";
8
+
9
+ interface TaskSuggestion {
10
+ title: string;
11
+ description: string;
12
+ }
13
+
14
+ interface AssistResult {
15
+ improvedDescription: string;
16
+ breakdown: TaskSuggestion[];
17
+ recommendedPattern: string;
18
+ complexity: string;
19
+ needsCheckpoint: boolean;
20
+ reasoning: string;
21
+ }
22
+
23
+ interface AIAssistPanelProps {
24
+ title: string;
25
+ description: string;
26
+ assignedAgent?: string;
27
+ onApplyDescription: (description: string) => void;
28
+ onCreateSubtasks: (subtasks: TaskSuggestion[]) => void;
29
+ onResultChange?: (hasResult: boolean) => void;
30
+ }
31
+
32
+ const patternLabels: Record<string, string> = {
33
+ single: "Single Task",
34
+ sequence: "Sequence",
35
+ "planner-executor": "Planner → Executor",
36
+ checkpoint: "Human Checkpoint",
37
+ };
38
+
39
+ const complexityColors: Record<string, string> = {
40
+ simple: "text-complexity-simple",
41
+ moderate: "text-complexity-moderate",
42
+ complex: "text-complexity-complex",
43
+ };
44
+
45
+ export function AIAssistPanel({
46
+ title,
47
+ description,
48
+ assignedAgent,
49
+ onApplyDescription,
50
+ onCreateSubtasks,
51
+ onResultChange,
52
+ }: AIAssistPanelProps) {
53
+ const [loading, setLoading] = useState(false);
54
+ const [result, setResult] = useState<AssistResult | null>(null);
55
+ const [error, setError] = useState<string | null>(null);
56
+ const [descriptionApplied, setDescriptionApplied] = useState(false);
57
+
58
+ async function analyze() {
59
+ if (!title.trim() && !description.trim()) return;
60
+ setLoading(true);
61
+ setError(null);
62
+ setResult(null);
63
+ setDescriptionApplied(false);
64
+
65
+ try {
66
+ const res = await fetch("/api/tasks/assist", {
67
+ method: "POST",
68
+ headers: { "Content-Type": "application/json" },
69
+ body: JSON.stringify({ title, description, assignedAgent }),
70
+ });
71
+
72
+ if (!res.ok) {
73
+ const data = await res.json().catch(() => null);
74
+ setError(data?.error ?? "AI assist failed");
75
+ return;
76
+ }
77
+
78
+ const data = await res.json();
79
+ setResult(data);
80
+ onResultChange?.(true);
81
+ } catch {
82
+ setError("Network error");
83
+ } finally {
84
+ setLoading(false);
85
+ }
86
+ }
87
+
88
+ if (!result) {
89
+ return (
90
+ <div className="pt-2">
91
+ <Button
92
+ type="button"
93
+ variant="outline"
94
+ size="sm"
95
+ onClick={analyze}
96
+ disabled={loading || (!title.trim() && !description.trim())}
97
+ className="w-full"
98
+ >
99
+ {loading ? (
100
+ <Loader2 className="h-3 w-3 mr-1 animate-spin" />
101
+ ) : (
102
+ <Sparkles className="h-3 w-3 mr-1" />
103
+ )}
104
+ {loading ? "Analyzing..." : "AI Assist"}
105
+ </Button>
106
+ {error && <p className="text-xs text-destructive mt-1">{error}</p>}
107
+ <p className="text-xs text-muted-foreground text-center mt-1.5">
108
+ Suggests improved descriptions, sub-task breakdowns, and workflow patterns
109
+ </p>
110
+ </div>
111
+ );
112
+ }
113
+
114
+ return (
115
+ <div className="pt-2 space-y-3">
116
+ {/* Header row — full width */}
117
+ <div className="flex items-center gap-2 flex-wrap">
118
+ <Sparkles className="h-4 w-4 text-primary" />
119
+ <span className="text-sm font-medium">AI Suggestions</span>
120
+ <Badge variant="outline" className="text-xs">
121
+ {patternLabels[result.recommendedPattern] ?? result.recommendedPattern}
122
+ </Badge>
123
+ <span className={`text-xs ${complexityColors[result.complexity] ?? ""}`}>
124
+ {result.complexity}
125
+ </span>
126
+ {result.needsCheckpoint && (
127
+ <Badge variant="secondary" className="text-xs">needs checkpoint</Badge>
128
+ )}
129
+ </div>
130
+
131
+ {/* Two-column grid for cards */}
132
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
133
+ {/* Improved description */}
134
+ <Card>
135
+ <CardContent className="p-3">
136
+ <div className="flex items-center justify-between mb-1">
137
+ <span className="text-xs font-medium text-muted-foreground">
138
+ Improved Description
139
+ </span>
140
+ <Button
141
+ type="button"
142
+ variant="ghost"
143
+ size="sm"
144
+ className="h-6 text-xs"
145
+ onClick={() => {
146
+ onApplyDescription(result.improvedDescription);
147
+ setDescriptionApplied(true);
148
+ }}
149
+ disabled={descriptionApplied}
150
+ >
151
+ {descriptionApplied ? (
152
+ <><Check className="h-3 w-3 mr-1" /> Applied</>
153
+ ) : (
154
+ "Apply"
155
+ )}
156
+ </Button>
157
+ </div>
158
+ <p className="text-sm">{result.improvedDescription}</p>
159
+ </CardContent>
160
+ </Card>
161
+
162
+ {/* Task breakdown */}
163
+ {result.breakdown.length > 0 && (
164
+ <Card>
165
+ <CardContent className="p-3">
166
+ <div className="flex items-center justify-between mb-2">
167
+ <span className="text-xs font-medium text-muted-foreground">
168
+ Suggested Breakdown ({result.breakdown.length} sub-tasks)
169
+ </span>
170
+ <Button
171
+ type="button"
172
+ variant="ghost"
173
+ size="sm"
174
+ className="h-6 text-xs"
175
+ onClick={() => onCreateSubtasks(result.breakdown)}
176
+ >
177
+ Create All
178
+ </Button>
179
+ </div>
180
+ <div className="max-h-60 overflow-y-auto space-y-1.5">
181
+ {result.breakdown.map((sub, i) => (
182
+ <div key={i} className="text-sm">
183
+ <span className="font-medium">{sub.title}</span>
184
+ <p className="text-xs text-muted-foreground">{sub.description}</p>
185
+ </div>
186
+ ))}
187
+ </div>
188
+ </CardContent>
189
+ </Card>
190
+ )}
191
+ </div>
192
+
193
+ {/* Reasoning + Dismiss — full width */}
194
+ <p className="text-xs text-muted-foreground">{result.reasoning}</p>
195
+
196
+ <Button
197
+ type="button"
198
+ variant="ghost"
199
+ size="sm"
200
+ onClick={() => {
201
+ setResult(null);
202
+ onResultChange?.(false);
203
+ }}
204
+ className="w-full"
205
+ >
206
+ <X className="h-3 w-3 mr-1" /> Dismiss
207
+ </Button>
208
+ </div>
209
+ );
210
+ }