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,179 @@
1
+ "use client";
2
+
3
+ import { useTransition } from "react";
4
+ import { usePathname, useRouter, useSearchParams } from "next/navigation";
5
+ import { ListFilter, Loader2, RotateCcw } from "lucide-react";
6
+ import { Button } from "@/components/ui/button";
7
+ import {
8
+ Select,
9
+ SelectContent,
10
+ SelectItem,
11
+ SelectTrigger,
12
+ SelectValue,
13
+ } from "@/components/ui/select";
14
+
15
+ interface RuntimeOption {
16
+ id: string;
17
+ label: string;
18
+ }
19
+
20
+ interface CostFiltersProps {
21
+ dateRange: string;
22
+ runtimeId: string;
23
+ status: string;
24
+ activityType: string;
25
+ runtimeOptions: RuntimeOption[];
26
+ }
27
+
28
+ const DATE_RANGE_OPTIONS = [
29
+ { value: "7d", label: "Last 7 days" },
30
+ { value: "30d", label: "Last 30 days" },
31
+ { value: "90d", label: "Last 90 days" },
32
+ { value: "all", label: "All time" },
33
+ ];
34
+
35
+ const STATUS_OPTIONS = [
36
+ { value: "all", label: "All statuses" },
37
+ { value: "completed", label: "Completed" },
38
+ { value: "failed", label: "Failed" },
39
+ { value: "cancelled", label: "Cancelled" },
40
+ { value: "blocked", label: "Blocked" },
41
+ { value: "unknown_pricing", label: "Unknown pricing" },
42
+ ];
43
+
44
+ const ACTIVITY_OPTIONS = [
45
+ { value: "all", label: "All activities" },
46
+ { value: "task_run", label: "Task runs" },
47
+ { value: "task_resume", label: "Task resumes" },
48
+ { value: "workflow_step", label: "Workflow steps" },
49
+ { value: "scheduled_firing", label: "Scheduled firings" },
50
+ { value: "task_assist", label: "Task assist" },
51
+ { value: "profile_test", label: "Profile tests" },
52
+ ];
53
+
54
+ export function CostFilters({
55
+ dateRange,
56
+ runtimeId,
57
+ status,
58
+ activityType,
59
+ runtimeOptions,
60
+ }: CostFiltersProps) {
61
+ const pathname = usePathname();
62
+ const router = useRouter();
63
+ const searchParams = useSearchParams();
64
+ const [isPending, startTransition] = useTransition();
65
+
66
+ function replaceFilters(next: URLSearchParams) {
67
+ const href = next.size > 0 ? `${pathname}?${next.toString()}` : pathname;
68
+ startTransition(() => {
69
+ router.replace(href, { scroll: false });
70
+ });
71
+ }
72
+
73
+ function setFilter(
74
+ key: "range" | "runtime" | "status" | "activity",
75
+ value: string
76
+ ) {
77
+ const next = new URLSearchParams(searchParams.toString());
78
+ const defaultValue = key === "range" ? "30d" : "all";
79
+ if (value === defaultValue) {
80
+ next.delete(key);
81
+ } else {
82
+ next.set(key, value);
83
+ }
84
+ replaceFilters(next);
85
+ }
86
+
87
+ function resetFilters() {
88
+ replaceFilters(new URLSearchParams());
89
+ }
90
+
91
+ const hasCustomFilters =
92
+ dateRange !== "30d" ||
93
+ runtimeId !== "all" ||
94
+ status !== "all" ||
95
+ activityType !== "all";
96
+
97
+ return (
98
+ <div className="surface-panel flex flex-col gap-3 rounded-2xl p-4">
99
+ <div className="flex items-center justify-between gap-3">
100
+ <div className="flex items-center gap-2 text-xs font-semibold uppercase tracking-[0.16em] text-muted-foreground">
101
+ <ListFilter className="h-3.5 w-3.5" />
102
+ <span>Audit Filters</span>
103
+ </div>
104
+ <div className="flex items-center gap-2">
105
+ {isPending ? (
106
+ <span className="inline-flex items-center gap-1 text-xs text-muted-foreground">
107
+ <Loader2 className="h-3.5 w-3.5 animate-spin" />
108
+ Updating
109
+ </span>
110
+ ) : null}
111
+ {hasCustomFilters ? (
112
+ <Button variant="ghost" size="sm" onClick={resetFilters}>
113
+ <RotateCcw className="h-3.5 w-3.5" />
114
+ Reset
115
+ </Button>
116
+ ) : null}
117
+ </div>
118
+ </div>
119
+
120
+ <div className="flex flex-col gap-3 lg:flex-row lg:flex-wrap">
121
+ <Select value={dateRange} onValueChange={(value) => setFilter("range", value)}>
122
+ <SelectTrigger className="surface-control w-full justify-between lg:w-[170px]">
123
+ <SelectValue placeholder="Date range" />
124
+ </SelectTrigger>
125
+ <SelectContent>
126
+ {DATE_RANGE_OPTIONS.map((option) => (
127
+ <SelectItem key={option.value} value={option.value}>
128
+ {option.label}
129
+ </SelectItem>
130
+ ))}
131
+ </SelectContent>
132
+ </Select>
133
+
134
+ <Select value={runtimeId} onValueChange={(value) => setFilter("runtime", value)}>
135
+ <SelectTrigger className="surface-control w-full justify-between lg:w-[210px]">
136
+ <SelectValue placeholder="All runtimes" />
137
+ </SelectTrigger>
138
+ <SelectContent>
139
+ <SelectItem value="all">All runtimes</SelectItem>
140
+ {runtimeOptions.map((runtime) => (
141
+ <SelectItem key={runtime.id} value={runtime.id}>
142
+ {runtime.label}
143
+ </SelectItem>
144
+ ))}
145
+ </SelectContent>
146
+ </Select>
147
+
148
+ <Select value={status} onValueChange={(value) => setFilter("status", value)}>
149
+ <SelectTrigger className="surface-control w-full justify-between lg:w-[180px]">
150
+ <SelectValue placeholder="All statuses" />
151
+ </SelectTrigger>
152
+ <SelectContent>
153
+ {STATUS_OPTIONS.map((option) => (
154
+ <SelectItem key={option.value} value={option.value}>
155
+ {option.label}
156
+ </SelectItem>
157
+ ))}
158
+ </SelectContent>
159
+ </Select>
160
+
161
+ <Select
162
+ value={activityType}
163
+ onValueChange={(value) => setFilter("activity", value)}
164
+ >
165
+ <SelectTrigger className="surface-control w-full justify-between lg:w-[190px]">
166
+ <SelectValue placeholder="All activities" />
167
+ </SelectTrigger>
168
+ <SelectContent>
169
+ {ACTIVITY_OPTIONS.map((option) => (
170
+ <SelectItem key={option.value} value={option.value}>
171
+ {option.label}
172
+ </SelectItem>
173
+ ))}
174
+ </SelectContent>
175
+ </Select>
176
+ </div>
177
+ </div>
178
+ );
179
+ }
@@ -0,0 +1,95 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
5
+ import { Button } from "@/components/ui/button";
6
+ import { ArrowRight } from "lucide-react";
7
+ import { MiniBar } from "@/components/charts/mini-bar";
8
+
9
+ export interface ActivityEntry {
10
+ id: string;
11
+ event: string;
12
+ payload: string | null;
13
+ timestamp: string;
14
+ taskTitle?: string;
15
+ }
16
+
17
+ interface ActivityFeedProps {
18
+ entries: ActivityEntry[];
19
+ hourlyActivity?: number[];
20
+ }
21
+
22
+ const eventColors: Record<string, string> = {
23
+ tool_start: "bg-status-running",
24
+ content_start: "bg-status-completed",
25
+ content_delta: "bg-status-completed/70",
26
+ completed: "bg-status-completed",
27
+ error: "bg-status-failed",
28
+ };
29
+
30
+ export function ActivityFeed({ entries, hourlyActivity }: ActivityFeedProps) {
31
+ return (
32
+ <Card className="surface-card">
33
+ <CardHeader className="pb-3">
34
+ <CardTitle className="text-sm font-semibold uppercase tracking-wide text-muted-foreground">
35
+ Live Agent Activity
36
+ </CardTitle>
37
+ </CardHeader>
38
+ <CardContent>
39
+ {hourlyActivity && hourlyActivity.some((v) => v > 0) && (
40
+ <div className="mb-3 pb-3 border-b border-border/50">
41
+ <p className="text-[10px] text-muted-foreground mb-1.5">24h activity</p>
42
+ <MiniBar
43
+ data={hourlyActivity.map((value) => ({ value }))}
44
+ width={200}
45
+ height={28}
46
+ defaultColor="var(--chart-1)"
47
+ label="Agent activity over last 24 hours"
48
+ className="w-full"
49
+ />
50
+ </div>
51
+ )}
52
+ {entries.length === 0 ? (
53
+ <p
54
+ className="text-sm text-muted-foreground py-4 text-center"
55
+ aria-live="polite"
56
+ >
57
+ No recent agent activity.
58
+ </p>
59
+ ) : (
60
+ <div className="space-y-1" aria-live="polite">
61
+ {entries.map((entry) => (
62
+ <div
63
+ key={entry.id}
64
+ className="flex items-start gap-3 py-2.5 border-b border-border/50 last:border-b-0"
65
+ >
66
+ <div
67
+ className={`h-2 w-2 rounded-full mt-1.5 flex-shrink-0 ${eventColors[entry.event] ?? "bg-muted-foreground"}`}
68
+ />
69
+ <div className="flex-1 min-w-0">
70
+ <p className="text-sm truncate">
71
+ <span className="font-medium">{entry.event}</span>
72
+ {entry.taskTitle && (
73
+ <span className="text-muted-foreground"> — {entry.taskTitle}</span>
74
+ )}
75
+ </p>
76
+ <p className="text-xs text-muted-foreground">
77
+ {new Date(entry.timestamp).toLocaleTimeString()}
78
+ {entry.payload && ` · ${entry.payload.slice(0, 60)}${entry.payload.length > 60 ? "..." : ""}`}
79
+ </p>
80
+ </div>
81
+ </div>
82
+ ))}
83
+ </div>
84
+ )}
85
+ <div className="mt-3">
86
+ <Link href="/monitor">
87
+ <Button variant="outline" size="sm" className="w-full">
88
+ Open monitor <ArrowRight className="h-3 w-3 ml-1" />
89
+ </Button>
90
+ </Link>
91
+ </div>
92
+ </CardContent>
93
+ </Card>
94
+ );
95
+ }
@@ -0,0 +1,30 @@
1
+ interface GreetingProps {
2
+ runningCount: number;
3
+ awaitingCount: number;
4
+ failedCount: number;
5
+ }
6
+
7
+ function getGreeting(): string {
8
+ const hour = new Date().getHours();
9
+ if (hour < 12) return "Good morning";
10
+ if (hour < 18) return "Good afternoon";
11
+ return "Good evening";
12
+ }
13
+
14
+ export function Greeting({ runningCount, awaitingCount, failedCount }: GreetingProps) {
15
+ const parts: string[] = [];
16
+ if (runningCount > 0) parts.push(`${runningCount} task${runningCount !== 1 ? "s" : ""} running`);
17
+ if (awaitingCount > 0) parts.push(`${awaitingCount} awaiting your review`);
18
+ if (failedCount > 0) parts.push(`${failedCount} failed task${failedCount !== 1 ? "s" : ""} to address`);
19
+
20
+ const summary = parts.length > 0
21
+ ? `You have ${parts.join(", ")}.`
22
+ : "All clear — no tasks need your attention.";
23
+
24
+ return (
25
+ <div className="glass-card rounded-xl p-5 mb-6">
26
+ <h2 className="text-xl font-bold">{getGreeting()}</h2>
27
+ <p className="text-sm text-muted-foreground mt-1">{summary}</p>
28
+ </div>
29
+ );
30
+ }
@@ -0,0 +1,79 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { Badge } from "@/components/ui/badge";
5
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
6
+ import { Button } from "@/components/ui/button";
7
+ import { AlertTriangle, Clock, Shield, ArrowRight } from "lucide-react";
8
+ import { taskStatusVariant } from "@/lib/constants/status-colors";
9
+
10
+ export interface PriorityTask {
11
+ id: string;
12
+ title: string;
13
+ status: string;
14
+ priority: number;
15
+ projectName?: string;
16
+ }
17
+
18
+ interface PriorityQueueProps {
19
+ tasks: PriorityTask[];
20
+ }
21
+
22
+ const statusIcon: Record<string, typeof AlertTriangle> = {
23
+ failed: AlertTriangle,
24
+ running: Clock,
25
+ };
26
+
27
+ const priorityColors = ["text-priority-critical", "text-priority-high", "text-status-warning", "text-muted-foreground"];
28
+
29
+ export function PriorityQueue({ tasks }: PriorityQueueProps) {
30
+ return (
31
+ <Card className="surface-card">
32
+ <CardHeader className="pb-3">
33
+ <CardTitle className="text-sm font-semibold uppercase tracking-wide text-muted-foreground">
34
+ Needs Attention
35
+ </CardTitle>
36
+ </CardHeader>
37
+ <CardContent>
38
+ {tasks.length === 0 ? (
39
+ <p
40
+ className="text-sm text-muted-foreground py-4 text-center"
41
+ aria-live="polite"
42
+ >
43
+ No tasks need attention right now.
44
+ </p>
45
+ ) : (
46
+ <div className="space-y-1" aria-live="polite">
47
+ {tasks.map((task) => {
48
+ const Icon = statusIcon[task.status] ?? Shield;
49
+ return (
50
+ <div
51
+ key={task.id}
52
+ className="flex items-center gap-3 py-2.5 border-b border-border/50 last:border-b-0"
53
+ >
54
+ <Icon className={`h-4 w-4 flex-shrink-0 ${priorityColors[task.priority] ?? priorityColors[3]}`} />
55
+ <div className="flex-1 min-w-0">
56
+ <p className="text-sm font-medium truncate">{task.title}</p>
57
+ {task.projectName && (
58
+ <p className="text-xs text-muted-foreground">{task.projectName}</p>
59
+ )}
60
+ </div>
61
+ <Badge variant={taskStatusVariant[task.status] ?? "secondary"} className="text-xs">
62
+ {task.status}
63
+ </Badge>
64
+ </div>
65
+ );
66
+ })}
67
+ </div>
68
+ )}
69
+ <div className="mt-3">
70
+ <Link href="/dashboard">
71
+ <Button variant="outline" size="sm" className="w-full">
72
+ View all tasks <ArrowRight className="h-3 w-3 ml-1" />
73
+ </Button>
74
+ </Link>
75
+ </div>
76
+ </CardContent>
77
+ </Card>
78
+ );
79
+ }
@@ -0,0 +1,62 @@
1
+ "use client";
2
+
3
+ import { useRouter } from "next/navigation";
4
+ import { Card, CardContent } from "@/components/ui/card";
5
+ import { Plus, FolderPlus, Inbox, Activity } from "lucide-react";
6
+ import { SectionHeading } from "@/components/shared/section-heading";
7
+
8
+ export function QuickActions() {
9
+ const router = useRouter();
10
+
11
+ const actions = [
12
+ {
13
+ label: "New Task",
14
+ description: "Create & queue an agent task",
15
+ icon: Plus,
16
+ onClick: () => router.push("/tasks/new"),
17
+ },
18
+ {
19
+ label: "New Project",
20
+ description: "Organize tasks into a project",
21
+ icon: FolderPlus,
22
+ onClick: () => router.push("/projects"),
23
+ },
24
+ {
25
+ label: "Open Inbox",
26
+ description: "Review pending notifications",
27
+ icon: Inbox,
28
+ onClick: () => router.push("/inbox"),
29
+ },
30
+ {
31
+ label: "Open Monitor",
32
+ description: "Watch live agent logs",
33
+ icon: Activity,
34
+ onClick: () => router.push("/monitor"),
35
+ },
36
+ ];
37
+
38
+ return (
39
+ <div className="mb-6">
40
+ <SectionHeading>Quick Actions</SectionHeading>
41
+ <div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
42
+ {actions.map((action) => (
43
+ <Card
44
+ key={action.label}
45
+ tabIndex={0}
46
+ className="surface-card cursor-pointer transition-colors hover:bg-accent/50 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-xl"
47
+ onClick={action.onClick}
48
+ onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); action.onClick(); } }}
49
+ >
50
+ <CardContent className="flex flex-col items-center justify-center py-5 gap-2">
51
+ <action.icon className="h-8 w-8 text-muted-foreground" />
52
+ <span className="text-sm font-medium">{action.label}</span>
53
+ <span className="text-xs text-muted-foreground text-center">
54
+ {action.description}
55
+ </span>
56
+ </CardContent>
57
+ </Card>
58
+ ))}
59
+ </div>
60
+ </div>
61
+ );
62
+ }
@@ -0,0 +1,79 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
5
+ import { Button } from "@/components/ui/button";
6
+ import { Progress } from "@/components/ui/progress";
7
+ import { FolderPlus } from "lucide-react";
8
+ import { SectionHeading } from "@/components/shared/section-heading";
9
+ import { DonutRing } from "@/components/charts/donut-ring";
10
+
11
+ export interface RecentProject {
12
+ id: string;
13
+ name: string;
14
+ totalTasks: number;
15
+ completedTasks: number;
16
+ }
17
+
18
+ interface RecentProjectsProps {
19
+ projects: RecentProject[];
20
+ }
21
+
22
+ export function RecentProjects({ projects }: RecentProjectsProps) {
23
+ if (projects.length === 0) {
24
+ return (
25
+ <div>
26
+ <SectionHeading>Recent Projects</SectionHeading>
27
+ <Card className="surface-card p-6 text-center">
28
+ <FolderPlus className="h-8 w-8 mx-auto text-muted-foreground mb-2" />
29
+ <p className="text-sm text-muted-foreground mb-3">No active projects yet.</p>
30
+ <Link href="/projects">
31
+ <Button variant="outline" size="sm">Create your first project</Button>
32
+ </Link>
33
+ </Card>
34
+ </div>
35
+ );
36
+ }
37
+
38
+ return (
39
+ <div>
40
+ <div className="flex items-baseline justify-between mb-3">
41
+ <SectionHeading className="mb-0">Recent Projects</SectionHeading>
42
+ <Link href="/projects" className="text-xs text-muted-foreground underline hover:text-foreground">
43
+ View all
44
+ </Link>
45
+ </div>
46
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
47
+ {projects.map((project) => {
48
+ const pct = project.totalTasks > 0
49
+ ? Math.round((project.completedTasks / project.totalTasks) * 100)
50
+ : 0;
51
+ return (
52
+ <Link key={project.id} href={`/projects/${project.id}`}>
53
+ <Card className="surface-card cursor-pointer transition-colors hover:bg-accent/50 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-xl">
54
+ <CardHeader className="pb-2">
55
+ <div className="flex items-center gap-2">
56
+ <DonutRing
57
+ value={pct}
58
+ size={28}
59
+ strokeWidth={3}
60
+ color="var(--chart-2)"
61
+ label={`${project.name}: ${pct}% complete`}
62
+ />
63
+ <CardTitle className="text-base font-medium">{project.name}</CardTitle>
64
+ </div>
65
+ </CardHeader>
66
+ <CardContent>
67
+ <Progress value={pct} className="h-1.5 mb-2" />
68
+ <p className="text-xs text-muted-foreground">
69
+ {project.completedTasks}/{project.totalTasks} tasks completed
70
+ </p>
71
+ </CardContent>
72
+ </Card>
73
+ </Link>
74
+ );
75
+ })}
76
+ </div>
77
+ </div>
78
+ );
79
+ }
@@ -0,0 +1,114 @@
1
+ "use client";
2
+
3
+ import Link from "next/link";
4
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
5
+ import { Activity, CheckCircle, MessageSquare, FolderKanban } from "lucide-react";
6
+ import { Sparkline } from "@/components/charts/sparkline";
7
+
8
+ interface StatsCardsProps {
9
+ runningCount: number;
10
+ completedToday: number;
11
+ completedAllTime: number;
12
+ awaitingReview: number;
13
+ activeProjects: number;
14
+ sparklines?: {
15
+ completions: number[];
16
+ creations: number[];
17
+ projects: number[];
18
+ notifications: number[];
19
+ };
20
+ }
21
+
22
+ export function StatsCards({
23
+ runningCount,
24
+ completedToday,
25
+ completedAllTime,
26
+ awaitingReview,
27
+ activeProjects,
28
+ sparklines,
29
+ }: StatsCardsProps) {
30
+ const stats = [
31
+ {
32
+ title: "Tasks Running",
33
+ value: runningCount,
34
+ subtitle: "Currently active",
35
+ icon: Activity,
36
+ color: "text-status-running",
37
+ chartColor: "var(--chart-1)",
38
+ href: "/monitor",
39
+ destination: "Monitor",
40
+ sparklineData: sparklines?.creations,
41
+ },
42
+ {
43
+ title: "Completed Today",
44
+ value: completedToday,
45
+ subtitle: `All-time: ${completedAllTime}`,
46
+ icon: CheckCircle,
47
+ color: "text-status-completed",
48
+ chartColor: "var(--chart-2)",
49
+ href: "/dashboard",
50
+ destination: "Dashboard",
51
+ sparklineData: sparklines?.completions,
52
+ },
53
+ {
54
+ title: "Awaiting Review",
55
+ value: awaitingReview,
56
+ subtitle: "Human-loop pending",
57
+ icon: MessageSquare,
58
+ color: "text-status-warning",
59
+ chartColor: "var(--chart-3)",
60
+ href: "/inbox",
61
+ destination: "Inbox",
62
+ sparklineData: sparklines?.notifications,
63
+ },
64
+ {
65
+ title: "Active Projects",
66
+ value: activeProjects,
67
+ subtitle: "In progress",
68
+ icon: FolderKanban,
69
+ color: "text-primary",
70
+ chartColor: "var(--chart-4)",
71
+ href: "/projects",
72
+ destination: "Projects",
73
+ sparklineData: sparklines?.projects,
74
+ },
75
+ ];
76
+
77
+ return (
78
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
79
+ {stats.map((s) => (
80
+ <Link key={s.title} href={s.href}>
81
+ <Card className="surface-card glass-shimmer cursor-pointer transition-colors hover:bg-accent/50 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-xl">
82
+ <CardHeader className="flex flex-row items-center justify-between pb-2">
83
+ <CardTitle className="text-sm font-medium text-muted-foreground">
84
+ {s.title}
85
+ </CardTitle>
86
+ <s.icon className={`h-4 w-4 ${s.color}`} />
87
+ </CardHeader>
88
+ <CardContent>
89
+ <div className="text-2xl font-bold">{s.value}</div>
90
+ {s.sparklineData && (
91
+ <div className="hidden sm:block mt-1">
92
+ <Sparkline
93
+ data={s.sparklineData}
94
+ width={100}
95
+ height={24}
96
+ color={s.chartColor}
97
+ label={`${s.title} 7-day trend`}
98
+ className="w-full"
99
+ />
100
+ </div>
101
+ )}
102
+ <p className="text-xs text-muted-foreground mt-1">{s.subtitle}</p>
103
+ {s.destination && (
104
+ <p className="text-[10px] text-muted-foreground/60 mt-0.5">
105
+ → {s.destination}
106
+ </p>
107
+ )}
108
+ </CardContent>
109
+ </Card>
110
+ </Link>
111
+ ))}
112
+ </div>
113
+ );
114
+ }