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,32 @@
1
+ import { db } from "@/lib/db";
2
+ import { projects, tasks } from "@/lib/db/schema";
3
+ import { eq, count } from "drizzle-orm";
4
+ import { ProjectList } from "@/components/projects/project-list";
5
+
6
+ export const dynamic = "force-dynamic";
7
+
8
+ export default async function ProjectsPage() {
9
+ const result = await db
10
+ .select({
11
+ id: projects.id,
12
+ name: projects.name,
13
+ description: projects.description,
14
+ workingDirectory: projects.workingDirectory,
15
+ status: projects.status,
16
+ createdAt: projects.createdAt,
17
+ updatedAt: projects.updatedAt,
18
+ taskCount: count(tasks.id),
19
+ })
20
+ .from(projects)
21
+ .leftJoin(tasks, eq(tasks.projectId, projects.id))
22
+ .groupBy(projects.id)
23
+ .orderBy(projects.createdAt);
24
+
25
+ return (
26
+ <div className="gradient-ocean-mist min-h-screen p-4 sm:p-6">
27
+ <div className="surface-page surface-page-shell mx-auto min-h-[calc(100dvh-2rem)] max-w-6xl rounded-[30px] p-5 sm:p-6 lg:p-7">
28
+ <ProjectList initialProjects={result} />
29
+ </div>
30
+ </div>
31
+ );
32
+ }
@@ -0,0 +1,47 @@
1
+ import { notFound } from "next/navigation";
2
+ import Link from "next/link";
3
+ import { db } from "@/lib/db";
4
+ import { schedules } from "@/lib/db/schema";
5
+ import { eq } from "drizzle-orm";
6
+ import { Button } from "@/components/ui/button";
7
+ import { ArrowLeft } from "lucide-react";
8
+ import { ScheduleDetailView } from "@/components/schedules/schedule-detail-view";
9
+
10
+ export const dynamic = "force-dynamic";
11
+
12
+ export default async function ScheduleDetailPage({
13
+ params,
14
+ }: {
15
+ params: Promise<{ id: string }>;
16
+ }) {
17
+ const { id } = await params;
18
+
19
+ const [schedule] = await db
20
+ .select()
21
+ .from(schedules)
22
+ .where(eq(schedules.id, id));
23
+
24
+ if (!schedule) notFound();
25
+
26
+ // Serialize Date timestamps and add firing history placeholder for client component
27
+ const initialSchedule = {
28
+ ...schedule,
29
+ createdAt: schedule.createdAt instanceof Date ? schedule.createdAt.toISOString() : String(schedule.createdAt),
30
+ expiresAt: schedule.expiresAt instanceof Date ? schedule.expiresAt.toISOString() : schedule.expiresAt ? String(schedule.expiresAt) : null,
31
+ lastFiredAt: schedule.lastFiredAt instanceof Date ? schedule.lastFiredAt.toISOString() : schedule.lastFiredAt ? String(schedule.lastFiredAt) : null,
32
+ nextFireAt: schedule.nextFireAt instanceof Date ? schedule.nextFireAt.toISOString() : schedule.nextFireAt ? String(schedule.nextFireAt) : null,
33
+ firingHistory: [] as Array<{ id: string; title: string; status: string; createdAt: string; result: string | null }>,
34
+ };
35
+
36
+ return (
37
+ <div className="gradient-ocean-mist min-h-screen p-6">
38
+ <Link href="/schedules">
39
+ <Button variant="ghost" size="sm" className="mb-4">
40
+ <ArrowLeft className="h-4 w-4 mr-1" />
41
+ Back to Schedules
42
+ </Button>
43
+ </Link>
44
+ <ScheduleDetailView scheduleId={id} initialSchedule={initialSchedule} />
45
+ </div>
46
+ );
47
+ }
@@ -0,0 +1,18 @@
1
+ import { db } from "@/lib/db";
2
+ import { projects } from "@/lib/db/schema";
3
+ import { ScheduleList } from "@/components/schedules/schedule-list";
4
+
5
+ export const dynamic = "force-dynamic";
6
+
7
+ export default async function SchedulesPage() {
8
+ const allProjects = await db
9
+ .select({ id: projects.id, name: projects.name })
10
+ .from(projects)
11
+ .orderBy(projects.name);
12
+
13
+ return (
14
+ <div className="gradient-ocean-mist min-h-screen p-6">
15
+ <ScheduleList projects={allProjects} />
16
+ </div>
17
+ );
18
+ }
@@ -0,0 +1,24 @@
1
+ import { Skeleton } from "@/components/ui/skeleton";
2
+ import { Card, CardContent, CardHeader } from "@/components/ui/card";
3
+
4
+ export default function SettingsLoading() {
5
+ return (
6
+ <div className="p-6 max-w-2xl space-y-6">
7
+ <div className="space-y-2">
8
+ <Skeleton className="h-8 w-32" />
9
+ <Skeleton className="h-4 w-56" />
10
+ </div>
11
+ <Card>
12
+ <CardHeader>
13
+ <Skeleton className="h-5 w-40" />
14
+ <Skeleton className="h-4 w-64" />
15
+ </CardHeader>
16
+ <CardContent className="space-y-4">
17
+ <Skeleton className="h-10 w-full" />
18
+ <Skeleton className="h-10 w-full" />
19
+ <Skeleton className="h-8 w-32" />
20
+ </CardContent>
21
+ </Card>
22
+ </div>
23
+ );
24
+ }
@@ -0,0 +1,27 @@
1
+ import { AuthConfigSection } from "@/components/settings/auth-config-section";
2
+ import { OpenAIRuntimeSection } from "@/components/settings/openai-runtime-section";
3
+ import { PermissionsSection } from "@/components/settings/permissions-section";
4
+ import { DataManagementSection } from "@/components/settings/data-management-section";
5
+ import { BudgetGuardrailsSection } from "@/components/settings/budget-guardrails-section";
6
+
7
+ export const dynamic = "force-dynamic";
8
+
9
+ export default function SettingsPage() {
10
+ return (
11
+ <div className="gradient-sunset-glow min-h-screen">
12
+ <div className="max-w-3xl mx-auto p-6 space-y-6">
13
+ <div>
14
+ <h1 className="text-2xl font-bold tracking-tight">Settings</h1>
15
+ <p className="text-muted-foreground">
16
+ Manage your Stagent configuration
17
+ </p>
18
+ </div>
19
+ <AuthConfigSection />
20
+ <OpenAIRuntimeSection />
21
+ <BudgetGuardrailsSection />
22
+ <PermissionsSection />
23
+ <DataManagementSection />
24
+ </div>
25
+ </div>
26
+ );
27
+ }
@@ -0,0 +1,45 @@
1
+ import { notFound } from "next/navigation";
2
+ import Link from "next/link";
3
+ import { db } from "@/lib/db";
4
+ import { tasks } from "@/lib/db/schema";
5
+ import { eq } from "drizzle-orm";
6
+ import { Button } from "@/components/ui/button";
7
+ import { ArrowLeft } from "lucide-react";
8
+ import { TaskDetailView } from "@/components/tasks/task-detail-view";
9
+
10
+ export const dynamic = "force-dynamic";
11
+
12
+ export default async function TaskDetailPage({
13
+ params,
14
+ }: {
15
+ params: Promise<{ id: string }>;
16
+ }) {
17
+ const { id } = await params;
18
+
19
+ const [task] = await db
20
+ .select()
21
+ .from(tasks)
22
+ .where(eq(tasks.id, id));
23
+
24
+ if (!task) notFound();
25
+
26
+ // Serialize Date timestamps to ISO strings for client component
27
+ const initialTask = {
28
+ ...task,
29
+ createdAt: task.createdAt instanceof Date ? task.createdAt.toISOString() : String(task.createdAt),
30
+ updatedAt: task.updatedAt instanceof Date ? task.updatedAt.toISOString() : String(task.updatedAt),
31
+ projectName: undefined,
32
+ };
33
+
34
+ return (
35
+ <div className="gradient-morning-sky min-h-screen p-6">
36
+ <Link href="/dashboard">
37
+ <Button variant="ghost" size="sm" className="mb-4">
38
+ <ArrowLeft className="h-4 w-4 mr-1" />
39
+ Back to Dashboard
40
+ </Button>
41
+ </Link>
42
+ <TaskDetailView taskId={id} initialTask={initialTask} />
43
+ </div>
44
+ );
45
+ }
@@ -0,0 +1,27 @@
1
+ import Link from "next/link";
2
+ import { db } from "@/lib/db";
3
+ import { projects } from "@/lib/db/schema";
4
+ import { Button } from "@/components/ui/button";
5
+ import { ArrowLeft } from "lucide-react";
6
+ import { TaskCreatePanel } from "@/components/tasks/task-create-panel";
7
+
8
+ export const dynamic = "force-dynamic";
9
+
10
+ export default async function NewTaskPage() {
11
+ const allProjects = await db
12
+ .select({ id: projects.id, name: projects.name })
13
+ .from(projects)
14
+ .orderBy(projects.name);
15
+
16
+ return (
17
+ <div className="gradient-morning-sky min-h-screen p-6">
18
+ <Link href="/dashboard">
19
+ <Button variant="ghost" size="sm" className="mb-4">
20
+ <ArrowLeft className="h-4 w-4 mr-1" />
21
+ Back to Dashboard
22
+ </Button>
23
+ </Link>
24
+ <TaskCreatePanel projects={allProjects} />
25
+ </div>
26
+ );
27
+ }
@@ -0,0 +1,66 @@
1
+ import { notFound } from "next/navigation";
2
+ import Link from "next/link";
3
+ import { db } from "@/lib/db";
4
+ import { projects, workflows } from "@/lib/db/schema";
5
+ import { eq } from "drizzle-orm";
6
+ import { Button } from "@/components/ui/button";
7
+ import { ArrowLeft } from "lucide-react";
8
+ import { WorkflowFormView } from "@/components/workflows/workflow-form-view";
9
+ import { listProfiles } from "@/lib/agents/profiles/registry";
10
+
11
+ export const dynamic = "force-dynamic";
12
+
13
+ export default async function EditWorkflowPage({
14
+ params,
15
+ searchParams,
16
+ }: {
17
+ params: Promise<{ id: string }>;
18
+ searchParams: Promise<{ clone?: string }>;
19
+ }) {
20
+ const { id } = await params;
21
+ const { clone } = await searchParams;
22
+
23
+ const [workflow] = await db
24
+ .select()
25
+ .from(workflows)
26
+ .where(eq(workflows.id, id));
27
+
28
+ if (!workflow) notFound();
29
+
30
+ const allProjects = await db
31
+ .select({ id: projects.id, name: projects.name })
32
+ .from(projects)
33
+ .orderBy(projects.name);
34
+
35
+ const profiles = listProfiles().map((p) => ({
36
+ id: p.id,
37
+ name: p.name,
38
+ supportedRuntimes: p.supportedRuntimes,
39
+ }));
40
+
41
+ const workflowData = {
42
+ id: workflow.id,
43
+ name: workflow.name,
44
+ projectId: workflow.projectId,
45
+ definition: workflow.definition,
46
+ };
47
+
48
+ return (
49
+ <div className="gradient-ocean-mist min-h-screen p-6">
50
+ <div className="max-w-6xl mx-auto">
51
+ <Link href={clone === "true" ? "/workflows" : `/workflows/${id}`}>
52
+ <Button variant="ghost" size="sm" className="mb-4">
53
+ <ArrowLeft className="h-4 w-4 mr-1" />
54
+ {clone === "true" ? "Back to Workflows" : "Back to Workflow"}
55
+ </Button>
56
+ </Link>
57
+ <WorkflowFormView
58
+ workflow={workflowData}
59
+ projects={allProjects}
60
+ profiles={profiles}
61
+ clone={clone === "true"}
62
+ />
63
+ </div>
64
+ </div>
65
+ );
66
+ }
@@ -0,0 +1,37 @@
1
+ import { notFound } from "next/navigation";
2
+ import Link from "next/link";
3
+ import { db } from "@/lib/db";
4
+ import { workflows } from "@/lib/db/schema";
5
+ import { eq } from "drizzle-orm";
6
+ import { Button } from "@/components/ui/button";
7
+ import { ArrowLeft } from "lucide-react";
8
+ import { WorkflowStatusView } from "@/components/workflows/workflow-status-view";
9
+
10
+ export const dynamic = "force-dynamic";
11
+
12
+ export default async function WorkflowDetailPage({
13
+ params,
14
+ }: {
15
+ params: Promise<{ id: string }>;
16
+ }) {
17
+ const { id } = await params;
18
+
19
+ const [workflow] = await db
20
+ .select()
21
+ .from(workflows)
22
+ .where(eq(workflows.id, id));
23
+
24
+ if (!workflow) notFound();
25
+
26
+ return (
27
+ <div className="gradient-ocean-mist min-h-screen p-6">
28
+ <Link href="/workflows">
29
+ <Button variant="ghost" size="sm" className="mb-4">
30
+ <ArrowLeft className="h-4 w-4 mr-1" />
31
+ Back to Workflows
32
+ </Button>
33
+ </Link>
34
+ <WorkflowStatusView workflowId={id} />
35
+ </div>
36
+ );
37
+ }
@@ -0,0 +1,40 @@
1
+ import Link from "next/link";
2
+ import { db } from "@/lib/db";
3
+ import { projects } from "@/lib/db/schema";
4
+ import { Button } from "@/components/ui/button";
5
+ import { ArrowLeft } from "lucide-react";
6
+ import { BlueprintPreview } from "@/components/workflows/blueprint-preview";
7
+ import { getBlueprint } from "@/lib/workflows/blueprints/registry";
8
+ import { notFound } from "next/navigation";
9
+
10
+ export const dynamic = "force-dynamic";
11
+
12
+ interface Props {
13
+ params: Promise<{ id: string }>;
14
+ }
15
+
16
+ export default async function BlueprintDetailPage({ params }: Props) {
17
+ const { id } = await params;
18
+ const blueprint = getBlueprint(id);
19
+
20
+ if (!blueprint) {
21
+ notFound();
22
+ }
23
+
24
+ const allProjects = await db
25
+ .select({ id: projects.id, name: projects.name })
26
+ .from(projects)
27
+ .orderBy(projects.name);
28
+
29
+ return (
30
+ <div className="gradient-ocean-mist min-h-screen p-6">
31
+ <Link href="/workflows/blueprints">
32
+ <Button variant="ghost" size="sm" className="mb-4">
33
+ <ArrowLeft className="h-4 w-4 mr-1" />
34
+ Back to Blueprints
35
+ </Button>
36
+ </Link>
37
+ <BlueprintPreview blueprint={blueprint} projects={allProjects} />
38
+ </div>
39
+ );
40
+ }
@@ -0,0 +1,20 @@
1
+ import Link from "next/link";
2
+ import { Button } from "@/components/ui/button";
3
+ import { ArrowLeft } from "lucide-react";
4
+ import { BlueprintEditor } from "@/components/workflows/blueprint-editor";
5
+
6
+ export const dynamic = "force-dynamic";
7
+
8
+ export default function NewBlueprintPage() {
9
+ return (
10
+ <div className="gradient-ocean-mist min-h-screen p-6">
11
+ <Link href="/workflows/blueprints">
12
+ <Button variant="ghost" size="sm" className="mb-4">
13
+ <ArrowLeft className="h-4 w-4 mr-1" />
14
+ Back to Blueprints
15
+ </Button>
16
+ </Link>
17
+ <BlueprintEditor />
18
+ </div>
19
+ );
20
+ }
@@ -0,0 +1,11 @@
1
+ import { BlueprintGallery } from "@/components/workflows/blueprint-gallery";
2
+
3
+ export const dynamic = "force-dynamic";
4
+
5
+ export default function BlueprintsPage() {
6
+ return (
7
+ <div className="gradient-ocean-mist min-h-screen p-6">
8
+ <BlueprintGallery />
9
+ </div>
10
+ );
11
+ }
@@ -0,0 +1,36 @@
1
+ import Link from "next/link";
2
+ import { db } from "@/lib/db";
3
+ import { projects } from "@/lib/db/schema";
4
+ import { Button } from "@/components/ui/button";
5
+ import { ArrowLeft } from "lucide-react";
6
+ import { WorkflowFormView } from "@/components/workflows/workflow-form-view";
7
+ import { listProfiles } from "@/lib/agents/profiles/registry";
8
+
9
+ export const dynamic = "force-dynamic";
10
+
11
+ export default async function NewWorkflowPage() {
12
+ const allProjects = await db
13
+ .select({ id: projects.id, name: projects.name })
14
+ .from(projects)
15
+ .orderBy(projects.name);
16
+
17
+ const profiles = listProfiles().map((p) => ({
18
+ id: p.id,
19
+ name: p.name,
20
+ supportedRuntimes: p.supportedRuntimes,
21
+ }));
22
+
23
+ return (
24
+ <div className="gradient-ocean-mist min-h-screen p-6">
25
+ <div className="max-w-6xl mx-auto">
26
+ <Link href="/workflows">
27
+ <Button variant="ghost" size="sm" className="mb-4">
28
+ <ArrowLeft className="h-4 w-4 mr-1" />
29
+ Back to Workflows
30
+ </Button>
31
+ </Link>
32
+ <WorkflowFormView projects={allProjects} profiles={profiles} />
33
+ </div>
34
+ </div>
35
+ );
36
+ }
@@ -0,0 +1,18 @@
1
+ import { db } from "@/lib/db";
2
+ import { projects } from "@/lib/db/schema";
3
+ import { WorkflowList } from "@/components/workflows/workflow-list";
4
+
5
+ export const dynamic = "force-dynamic";
6
+
7
+ export default async function WorkflowsPage() {
8
+ const allProjects = await db
9
+ .select({ id: projects.id, name: projects.name })
10
+ .from(projects)
11
+ .orderBy(projects.name);
12
+
13
+ return (
14
+ <div className="gradient-ocean-mist min-h-screen p-6">
15
+ <WorkflowList projects={allProjects} />
16
+ </div>
17
+ );
18
+ }
@@ -0,0 +1,64 @@
1
+ interface DonutRingProps {
2
+ value: number; // 0–100
3
+ size?: number;
4
+ strokeWidth?: number;
5
+ color?: string;
6
+ trackColor?: string;
7
+ label?: string;
8
+ className?: string;
9
+ }
10
+
11
+ export function DonutRing({
12
+ value,
13
+ size = 32,
14
+ strokeWidth = 3,
15
+ color = "var(--chart-1)",
16
+ trackColor = "var(--muted)",
17
+ label,
18
+ className,
19
+ }: DonutRingProps) {
20
+ const clamped = Math.max(0, Math.min(100, value));
21
+ const radius = (size - strokeWidth) / 2;
22
+ const circumference = 2 * Math.PI * radius;
23
+ const offset = circumference - (clamped / 100) * circumference;
24
+ const center = size / 2;
25
+ const ariaLabel = label ?? `${clamped}% complete`;
26
+
27
+ return (
28
+ <svg
29
+ width={size}
30
+ height={size}
31
+ viewBox={`0 0 ${size} ${size}`}
32
+ role="img"
33
+ aria-label={ariaLabel}
34
+ className={className}
35
+ >
36
+ <title>{ariaLabel}</title>
37
+ {/* Track */}
38
+ <circle
39
+ cx={center}
40
+ cy={center}
41
+ r={radius}
42
+ fill="none"
43
+ stroke={trackColor}
44
+ strokeWidth={strokeWidth}
45
+ opacity={0.3}
46
+ />
47
+ {/* Progress arc */}
48
+ {clamped > 0 && (
49
+ <circle
50
+ cx={center}
51
+ cy={center}
52
+ r={radius}
53
+ fill="none"
54
+ stroke={color}
55
+ strokeWidth={strokeWidth}
56
+ strokeLinecap="round"
57
+ strokeDasharray={circumference}
58
+ strokeDashoffset={offset}
59
+ transform={`rotate(-90 ${center} ${center})`}
60
+ />
61
+ )}
62
+ </svg>
63
+ );
64
+ }
@@ -0,0 +1,75 @@
1
+ interface BarDatum {
2
+ value: number;
3
+ color?: string;
4
+ label?: string;
5
+ }
6
+
7
+ interface MiniBarProps {
8
+ data: BarDatum[];
9
+ width?: number;
10
+ height?: number;
11
+ gap?: number;
12
+ defaultColor?: string;
13
+ label?: string;
14
+ className?: string;
15
+ }
16
+
17
+ export function MiniBar({
18
+ data,
19
+ width = 200,
20
+ height = 32,
21
+ gap = 1,
22
+ defaultColor = "var(--chart-1)",
23
+ label = "Bar chart",
24
+ className,
25
+ }: MiniBarProps) {
26
+ if (data.length === 0) {
27
+ return (
28
+ <svg
29
+ width={width}
30
+ height={height}
31
+ viewBox={`0 0 ${width} ${height}`}
32
+ role="img"
33
+ aria-label={label}
34
+ className={className}
35
+ >
36
+ <title>{label}</title>
37
+ </svg>
38
+ );
39
+ }
40
+
41
+ const max = Math.max(...data.map((d) => d.value));
42
+ const barWidth = (width - gap * (data.length - 1)) / data.length;
43
+ const padding = 2;
44
+ const chartHeight = height - padding;
45
+
46
+ return (
47
+ <svg
48
+ width={width}
49
+ height={height}
50
+ viewBox={`0 0 ${width} ${height}`}
51
+ role="img"
52
+ aria-label={label}
53
+ className={className}
54
+ >
55
+ <title>{label}</title>
56
+ {data.map((d, i) => {
57
+ const barHeight = max > 0 ? (d.value / max) * chartHeight : 0;
58
+ const x = i * (barWidth + gap);
59
+ const y = height - barHeight;
60
+ return (
61
+ <rect
62
+ key={i}
63
+ x={x}
64
+ y={y}
65
+ width={barWidth}
66
+ height={Math.max(barHeight, 1)}
67
+ rx={1}
68
+ fill={d.color ?? defaultColor}
69
+ opacity={barHeight > 0 ? 0.8 : 0.15}
70
+ />
71
+ );
72
+ })}
73
+ </svg>
74
+ );
75
+ }