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,90 @@
1
+ import { randomBytes, createCipheriv, createDecipheriv } from "crypto";
2
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync } from "fs";
3
+ import { join } from "path";
4
+ import { homedir } from "os";
5
+
6
+ const ALGORITHM = "aes-256-gcm";
7
+ const IV_LENGTH = 12;
8
+ const AUTH_TAG_LENGTH = 16;
9
+ const KEY_LENGTH = 32;
10
+
11
+ function getKeyfilePath(): string {
12
+ return join(
13
+ process.env.STAGENT_DATA_DIR || join(homedir(), ".stagent"),
14
+ ".keyfile"
15
+ );
16
+ }
17
+
18
+ /**
19
+ * Read or create the encryption keyfile at ~/.stagent/.keyfile.
20
+ * File is 32 random bytes with chmod 0600 (owner-only read/write).
21
+ */
22
+ export function getOrCreateKeyfile(): Buffer {
23
+ const keyfilePath = getKeyfilePath();
24
+
25
+ if (existsSync(keyfilePath)) {
26
+ const key = readFileSync(keyfilePath);
27
+ if (key.length !== KEY_LENGTH) {
28
+ throw new Error(`Invalid keyfile: expected ${KEY_LENGTH} bytes, got ${key.length}`);
29
+ }
30
+ return key;
31
+ }
32
+
33
+ // Create parent directory if needed
34
+ const dir = join(keyfilePath, "..");
35
+ mkdirSync(dir, { recursive: true });
36
+
37
+ const key = randomBytes(KEY_LENGTH);
38
+ writeFileSync(keyfilePath, key, { mode: 0o600 });
39
+ chmodSync(keyfilePath, 0o600);
40
+ return key;
41
+ }
42
+
43
+ /**
44
+ * Encrypt plaintext using AES-256-GCM.
45
+ * Returns base64 string in format: iv:authTag:ciphertext
46
+ */
47
+ export function encrypt(plaintext: string): string {
48
+ const key = getOrCreateKeyfile();
49
+ const iv = randomBytes(IV_LENGTH);
50
+ const cipher = createCipheriv(ALGORITHM, key, iv);
51
+
52
+ const encrypted = Buffer.concat([
53
+ cipher.update(plaintext, "utf8"),
54
+ cipher.final(),
55
+ ]);
56
+ const authTag = cipher.getAuthTag();
57
+
58
+ return [
59
+ iv.toString("base64"),
60
+ authTag.toString("base64"),
61
+ encrypted.toString("base64"),
62
+ ].join(":");
63
+ }
64
+
65
+ /**
66
+ * Decrypt a string previously encrypted with encrypt().
67
+ * Expects base64 format: iv:authTag:ciphertext
68
+ */
69
+ export function decrypt(encrypted: string): string {
70
+ const parts = encrypted.split(":");
71
+ if (parts.length !== 3) {
72
+ throw new Error("Invalid encrypted format: expected iv:authTag:ciphertext");
73
+ }
74
+
75
+ const [ivB64, authTagB64, ciphertextB64] = parts;
76
+ const key = getOrCreateKeyfile();
77
+ const iv = Buffer.from(ivB64, "base64");
78
+ const authTag = Buffer.from(authTagB64, "base64");
79
+ const ciphertext = Buffer.from(ciphertextB64, "base64");
80
+
81
+ const decipher = createDecipheriv(ALGORITHM, key, iv);
82
+ decipher.setAuthTag(authTag);
83
+
84
+ const decrypted = Buffer.concat([
85
+ decipher.update(ciphertext),
86
+ decipher.final(),
87
+ ]);
88
+
89
+ return decrypted.toString("utf8");
90
+ }
@@ -0,0 +1,46 @@
1
+ const MINUTE = 60_000;
2
+ const HOUR = 3_600_000;
3
+ const DAY = 86_400_000;
4
+
5
+ /**
6
+ * Formats a timestamp with relative time for recent items
7
+ * and a full date for older ones.
8
+ */
9
+ export function formatTimestamp(date: string | Date): string {
10
+ const d = typeof date === "string" ? new Date(date) : date;
11
+ const now = Date.now();
12
+ const diff = now - d.getTime();
13
+
14
+ if (diff < MINUTE) return "just now";
15
+ if (diff < HOUR) {
16
+ const mins = Math.floor(diff / MINUTE);
17
+ return `${mins}m ago`;
18
+ }
19
+ if (diff < DAY) {
20
+ const hours = Math.floor(diff / HOUR);
21
+ return `${hours}h ago`;
22
+ }
23
+ if (diff < 7 * DAY) {
24
+ const days = Math.floor(diff / DAY);
25
+ return `${days}d ago`;
26
+ }
27
+
28
+ return d.toLocaleDateString("en-US", {
29
+ month: "short",
30
+ day: "numeric",
31
+ year: d.getFullYear() !== new Date().getFullYear() ? "numeric" : undefined,
32
+ });
33
+ }
34
+
35
+ /**
36
+ * Formats a timestamp as HH:MM:SS for log entries.
37
+ */
38
+ export function formatTime(date: string | Date): string {
39
+ const d = typeof date === "string" ? new Date(date) : date;
40
+ return d.toLocaleTimeString("en-US", {
41
+ hour12: false,
42
+ hour: "2-digit",
43
+ minute: "2-digit",
44
+ second: "2-digit",
45
+ });
46
+ }
@@ -0,0 +1,26 @@
1
+ import { db } from "@/lib/db";
2
+ import { tasks } from "@/lib/db/schema";
3
+ import { eq, and, lt, isNotNull, inArray } from "drizzle-orm";
4
+
5
+ /**
6
+ * Nullify sessionId on completed/failed tasks older than retention period.
7
+ * Manual utility — not auto-scheduled.
8
+ */
9
+ export function cleanupOldSessions(retentionDays = 7): number {
10
+ const cutoff = new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1000);
11
+
12
+ const result = db
13
+ .update(tasks)
14
+ .set({ sessionId: null })
15
+ .where(
16
+ and(
17
+ isNotNull(tasks.sessionId),
18
+ inArray(tasks.status, ["completed", "failed"]),
19
+ lt(tasks.updatedAt, cutoff)
20
+ )
21
+ )
22
+ .returning()
23
+ .all();
24
+
25
+ return result.length;
26
+ }
@@ -0,0 +1,18 @@
1
+ import { homedir } from "os";
2
+ import { join } from "path";
3
+
4
+ export function getStagentDataDir(): string {
5
+ return process.env.STAGENT_DATA_DIR || join(homedir(), ".stagent");
6
+ }
7
+
8
+ export function getStagentDbPath(): string {
9
+ return join(getStagentDataDir(), "stagent.db");
10
+ }
11
+
12
+ export function getStagentUploadsDir(): string {
13
+ return join(getStagentDataDir(), "uploads");
14
+ }
15
+
16
+ export function getStagentBlueprintsDir(): string {
17
+ return join(getStagentDataDir(), "blueprints");
18
+ }
@@ -0,0 +1,6 @@
1
+ import { type ClassValue, clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -0,0 +1,43 @@
1
+ import { z } from "zod";
2
+
3
+ export const BlueprintVariableSchema = z.object({
4
+ id: z.string(),
5
+ type: z.enum(["text", "textarea", "select", "number", "boolean", "file"]),
6
+ label: z.string(),
7
+ description: z.string().optional(),
8
+ required: z.boolean(),
9
+ default: z.unknown().optional(),
10
+ placeholder: z.string().optional(),
11
+ options: z
12
+ .array(z.object({ value: z.string(), label: z.string() }))
13
+ .optional(),
14
+ min: z.number().optional(),
15
+ max: z.number().optional(),
16
+ });
17
+
18
+ export const BlueprintStepSchema = z.object({
19
+ name: z.string(),
20
+ profileId: z.string(),
21
+ promptTemplate: z.string(),
22
+ requiresApproval: z.boolean(),
23
+ expectedOutput: z.string().optional(),
24
+ condition: z.string().optional(),
25
+ });
26
+
27
+ export const BlueprintSchema = z.object({
28
+ id: z.string(),
29
+ name: z.string(),
30
+ description: z.string(),
31
+ version: z.string().regex(/^\d+\.\d+\.\d+$/),
32
+ domain: z.enum(["work", "personal"]),
33
+ tags: z.array(z.string()),
34
+ pattern: z.enum(["sequence", "planner-executor", "checkpoint"]),
35
+ variables: z.array(BlueprintVariableSchema),
36
+ steps: z.array(BlueprintStepSchema).min(1),
37
+ author: z.string().optional(),
38
+ source: z.string().url().optional(),
39
+ estimatedDuration: z.string().optional(),
40
+ difficulty: z.enum(["beginner", "intermediate", "advanced"]).optional(),
41
+ });
42
+
43
+ export type BlueprintConfig = z.infer<typeof BlueprintSchema>;
@@ -0,0 +1,64 @@
1
+ import { z } from "zod";
2
+ import { SUPPORTED_AGENT_RUNTIMES } from "@/lib/agents/runtime/catalog";
3
+
4
+ const runtimeIdSchema = z.enum(SUPPORTED_AGENT_RUNTIMES);
5
+
6
+ const profileTestsSchema = z.array(
7
+ z.object({
8
+ task: z.string(),
9
+ expectedKeywords: z.array(z.string()),
10
+ })
11
+ );
12
+
13
+ const canUseToolPolicySchema = z.object({
14
+ autoApprove: z.array(z.string()).optional(),
15
+ autoDeny: z.array(z.string()).optional(),
16
+ });
17
+
18
+ const profileRuntimeOverrideSchema = z.object({
19
+ instructions: z.string().min(1).optional(),
20
+ allowedTools: z.array(z.string()).optional(),
21
+ mcpServers: z.record(z.string(), z.unknown()).optional(),
22
+ canUseToolPolicy: canUseToolPolicySchema.optional(),
23
+ tests: profileTestsSchema.optional(),
24
+ });
25
+
26
+ export const ProfileConfigSchema = z.object({
27
+ id: z.string().min(1),
28
+ name: z.string().min(1),
29
+ version: z.string().regex(/^\d+\.\d+\.\d+$/),
30
+ domain: z.enum(["work", "personal"]),
31
+ tags: z.array(z.string()),
32
+ allowedTools: z.array(z.string()).optional(),
33
+ mcpServers: z.record(z.string(), z.unknown()).optional(),
34
+ canUseToolPolicy: canUseToolPolicySchema.optional(),
35
+ hooks: z
36
+ .object({
37
+ preToolCall: z.array(z.string()).optional(),
38
+ postToolCall: z.array(z.string()).optional(),
39
+ })
40
+ .optional(),
41
+ temperature: z.number().min(0).max(1).optional(),
42
+ maxTurns: z.number().positive().optional(),
43
+ outputFormat: z.string().optional(),
44
+ author: z.string().optional(),
45
+ source: z.string().url().optional(),
46
+ tests: profileTestsSchema.optional(),
47
+ supportedRuntimes: z.array(runtimeIdSchema).optional(),
48
+ runtimeOverrides: z
49
+ .object(
50
+ Object.fromEntries(
51
+ SUPPORTED_AGENT_RUNTIMES.map((runtimeId) => [
52
+ runtimeId,
53
+ profileRuntimeOverrideSchema.optional(),
54
+ ])
55
+ ) as Record<
56
+ (typeof SUPPORTED_AGENT_RUNTIMES)[number],
57
+ z.ZodOptional<typeof profileRuntimeOverrideSchema>
58
+ >
59
+ )
60
+ .partial()
61
+ .optional(),
62
+ });
63
+
64
+ export type ProfileConfig = z.infer<typeof ProfileConfigSchema>;
@@ -0,0 +1,17 @@
1
+ import { z } from "zod";
2
+
3
+ export const createProjectSchema = z.object({
4
+ name: z.string().min(1, "Name is required").max(100),
5
+ description: z.string().max(500).optional(),
6
+ workingDirectory: z.string().max(500).optional(),
7
+ });
8
+
9
+ export const updateProjectSchema = z.object({
10
+ name: z.string().min(1).max(100).optional(),
11
+ description: z.string().max(500).optional(),
12
+ workingDirectory: z.string().max(500).optional(),
13
+ status: z.enum(["active", "paused", "completed"]).optional(),
14
+ });
15
+
16
+ export type CreateProjectInput = z.infer<typeof createProjectSchema>;
17
+ export type UpdateProjectInput = z.infer<typeof updateProjectSchema>;
@@ -0,0 +1,57 @@
1
+ import { z } from "zod";
2
+ import { SUPPORTED_AGENT_RUNTIMES } from "@/lib/agents/runtime/catalog";
3
+
4
+ export const updateAuthSettingsSchema = z.object({
5
+ method: z.enum(["api_key", "oauth"]),
6
+ apiKey: z
7
+ .string()
8
+ .startsWith("sk-ant-", "API key must start with sk-ant-")
9
+ .optional(),
10
+ });
11
+
12
+ export type UpdateAuthSettingsInput = z.infer<typeof updateAuthSettingsSchema>;
13
+
14
+ export const updateOpenAISettingsSchema = z.object({
15
+ apiKey: z
16
+ .string()
17
+ .startsWith("sk-", "API key must start with sk-"),
18
+ });
19
+
20
+ export type UpdateOpenAISettingsInput = z.infer<typeof updateOpenAISettingsSchema>;
21
+
22
+ const nullablePositiveNumber = z.preprocess((value) => {
23
+ if (value === "" || value == null) return null;
24
+ if (typeof value === "string") return Number(value);
25
+ return value;
26
+ }, z.number().finite().positive().nullable());
27
+
28
+ const nullablePositiveInteger = z.preprocess((value) => {
29
+ if (value === "" || value == null) return null;
30
+ if (typeof value === "string") return Number(value);
31
+ return value;
32
+ }, z.number().int().positive().nullable());
33
+
34
+ export const runtimeBudgetPolicySchema = z.object({
35
+ dailySpendCapUsd: nullablePositiveNumber,
36
+ monthlySpendCapUsd: nullablePositiveNumber,
37
+ dailyTokenCap: nullablePositiveInteger,
38
+ monthlyTokenCap: nullablePositiveInteger,
39
+ });
40
+
41
+ export const budgetPolicySchema = z.object({
42
+ overall: z.object({
43
+ dailySpendCapUsd: nullablePositiveNumber,
44
+ monthlySpendCapUsd: nullablePositiveNumber,
45
+ }),
46
+ runtimes: z.object(
47
+ Object.fromEntries(
48
+ SUPPORTED_AGENT_RUNTIMES.map((runtimeId) => [runtimeId, runtimeBudgetPolicySchema])
49
+ ) as Record<(typeof SUPPORTED_AGENT_RUNTIMES)[number], typeof runtimeBudgetPolicySchema>
50
+ ),
51
+ });
52
+
53
+ export const updateBudgetPolicySchema = budgetPolicySchema;
54
+
55
+ export type RuntimeBudgetPolicy = z.infer<typeof runtimeBudgetPolicySchema>;
56
+ export type BudgetPolicy = z.infer<typeof budgetPolicySchema>;
57
+ export type UpdateBudgetPolicyInput = z.infer<typeof updateBudgetPolicySchema>;
@@ -0,0 +1,30 @@
1
+ import { z } from "zod";
2
+ import { SUPPORTED_AGENT_RUNTIMES } from "@/lib/agents/runtime/catalog";
3
+
4
+ const assignedAgentSchema = z.enum(SUPPORTED_AGENT_RUNTIMES);
5
+
6
+ export const createTaskSchema = z.object({
7
+ title: z.string().min(1, "Title is required").max(200),
8
+ description: z.string().max(2000).optional(),
9
+ projectId: z.string().optional(),
10
+ priority: z.number().min(0).max(3).default(2),
11
+ assignedAgent: assignedAgentSchema.optional(),
12
+ agentProfile: z.string().optional(),
13
+ fileIds: z.array(z.string()).optional(),
14
+ });
15
+
16
+ export const updateTaskSchema = z.object({
17
+ title: z.string().min(1).max(200).optional(),
18
+ description: z.string().max(2000).optional(),
19
+ status: z
20
+ .enum(["planned", "queued", "running", "completed", "failed", "cancelled"])
21
+ .optional(),
22
+ priority: z.number().min(0).max(3).optional(),
23
+ assignedAgent: assignedAgentSchema.optional(),
24
+ agentProfile: z.string().optional(),
25
+ result: z.string().optional(),
26
+ sessionId: z.string().optional(),
27
+ });
28
+
29
+ export type CreateTaskInput = z.infer<typeof createTaskSchema>;
30
+ export type UpdateTaskInput = z.infer<typeof updateTaskSchema>;
@@ -0,0 +1,72 @@
1
+ id: code-review-pipeline
2
+ name: Code Review Pipeline
3
+ description: Security scan, quality analysis, and summary report for code changes
4
+ version: "1.0.0"
5
+ domain: work
6
+ tags: [code-review, security, quality, owasp]
7
+ pattern: checkpoint
8
+ estimatedDuration: "10-20 min"
9
+ difficulty: intermediate
10
+ author: stagent
11
+
12
+ variables:
13
+ - id: target
14
+ type: text
15
+ label: Review Target
16
+ description: What to review — file path, PR number, or description of changes
17
+ required: true
18
+ placeholder: "e.g., src/lib/auth/ or PR #42"
19
+ - id: focus
20
+ type: select
21
+ label: Review Focus
22
+ description: Primary focus area for the review
23
+ required: true
24
+ default: balanced
25
+ options:
26
+ - { value: security, label: "Security-focused (OWASP, injection, auth)" }
27
+ - { value: quality, label: "Quality-focused (patterns, duplication, naming)" }
28
+ - { value: balanced, label: "Balanced (security + quality)" }
29
+ - id: context
30
+ type: textarea
31
+ label: Additional Context
32
+ description: Any relevant context about the changes being reviewed
33
+ required: false
34
+ placeholder: "e.g., This is a new authentication module..."
35
+
36
+ steps:
37
+ - name: Security Scan
38
+ profileId: code-reviewer
39
+ promptTemplate: |
40
+ Perform a security-focused code review of: {{target}}
41
+
42
+ Focus: {{focus}}
43
+ {{#if context}}Context: {{context}}{{/if}}
44
+
45
+ Check for OWASP Top 10 vulnerabilities, injection flaws, authentication bypasses,
46
+ and sensitive data exposure. Report each finding with severity, location, and fix.
47
+ requiresApproval: true
48
+ expectedOutput: structured-findings
49
+
50
+ - name: Quality Analysis
51
+ profileId: code-reviewer
52
+ promptTemplate: |
53
+ Perform a code quality analysis of: {{target}}
54
+
55
+ Focus: {{focus}}
56
+ {{#if context}}Context: {{context}}{{/if}}
57
+
58
+ Check for code duplication, naming conventions, error handling patterns,
59
+ test coverage gaps, and performance issues. Report each finding with
60
+ severity (CRITICAL/WARNING/SUGGESTION), location, and recommended fix.
61
+ requiresApproval: false
62
+ expectedOutput: structured-findings
63
+
64
+ - name: Review Summary
65
+ profileId: document-writer
66
+ promptTemplate: |
67
+ Write a concise code review summary for: {{target}}
68
+
69
+ Synthesize the security scan and quality analysis findings from previous steps.
70
+ Structure as: Overview, Critical Issues, Warnings, Suggestions, Verdict (approve/request changes).
71
+ requiresApproval: true
72
+ expectedOutput: markdown-report
@@ -0,0 +1,62 @@
1
+ id: documentation-generation
2
+ name: Documentation Generation
3
+ description: Analyze code, draft documentation, and review for accuracy
4
+ version: "1.0.0"
5
+ domain: work
6
+ tags: [documentation, api-docs, technical-writing, readme]
7
+ pattern: sequence
8
+ estimatedDuration: "10-15 min"
9
+ difficulty: beginner
10
+ author: stagent
11
+
12
+ variables:
13
+ - id: target
14
+ type: text
15
+ label: Documentation Target
16
+ description: What to document — module path, API, or component
17
+ required: true
18
+ placeholder: "e.g., src/lib/agents/ or the REST API endpoints"
19
+ - id: docType
20
+ type: select
21
+ label: Documentation Type
22
+ description: What kind of documentation to produce
23
+ required: true
24
+ default: api-docs
25
+ options:
26
+ - { value: api-docs, label: "API Documentation" }
27
+ - { value: readme, label: "README" }
28
+ - { value: adr, label: "Architecture Decision Record" }
29
+ - { value: guide, label: "User Guide" }
30
+
31
+ steps:
32
+ - name: Code Analysis
33
+ profileId: technical-writer
34
+ promptTemplate: |
35
+ Analyze the codebase at: {{target}}
36
+
37
+ Documentation type: {{docType}}
38
+
39
+ Map the public API surface, key abstractions, data flow, and usage patterns.
40
+ Identify what needs to be documented and the logical structure for the docs.
41
+ requiresApproval: false
42
+ expectedOutput: analysis-notes
43
+
44
+ - name: Draft Documentation
45
+ profileId: technical-writer
46
+ promptTemplate: |
47
+ Write {{docType}} documentation for: {{target}}
48
+
49
+ Use the code analysis from the previous step. Follow standard {{docType}} conventions.
50
+ Include code examples, parameter descriptions, return types, and edge cases.
51
+ requiresApproval: false
52
+ expectedOutput: markdown-report
53
+
54
+ - name: Technical Review
55
+ profileId: code-reviewer
56
+ promptTemplate: |
57
+ Review the drafted {{docType}} documentation for: {{target}}
58
+
59
+ Check for: technical accuracy, completeness, code example correctness,
60
+ missing edge cases, and clarity. Suggest specific improvements.
61
+ requiresApproval: true
62
+ expectedOutput: review-feedback
@@ -0,0 +1,81 @@
1
+ id: investment-research
2
+ name: Investment Research
3
+ description: Gather market data, analyze risk, and produce an investment report with disclaimers
4
+ version: "1.0.0"
5
+ domain: personal
6
+ tags: [finance, investing, research, risk-assessment]
7
+ pattern: checkpoint
8
+ estimatedDuration: "15-30 min"
9
+ difficulty: advanced
10
+ author: stagent
11
+
12
+ variables:
13
+ - id: asset
14
+ type: text
15
+ label: Asset or Topic
16
+ description: What to research — stock, sector, strategy, or investment question
17
+ required: true
18
+ placeholder: "e.g., NVIDIA stock, index fund vs. active management"
19
+ - id: horizon
20
+ type: select
21
+ label: Investment Horizon
22
+ description: Time frame for the investment
23
+ required: true
24
+ default: medium
25
+ options:
26
+ - { value: short, label: "Short-term (< 1 year)" }
27
+ - { value: medium, label: "Medium-term (1-5 years)" }
28
+ - { value: long, label: "Long-term (5+ years)" }
29
+ - id: riskTolerance
30
+ type: select
31
+ label: Risk Tolerance
32
+ description: Your risk comfort level
33
+ required: true
34
+ default: moderate
35
+ options:
36
+ - { value: conservative, label: "Conservative" }
37
+ - { value: moderate, label: "Moderate" }
38
+ - { value: aggressive, label: "Aggressive" }
39
+
40
+ steps:
41
+ - name: Data Gathering
42
+ profileId: researcher
43
+ promptTemplate: |
44
+ Research the following investment topic: {{asset}}
45
+
46
+ Investment horizon: {{horizon}}
47
+ Risk tolerance: {{riskTolerance}}
48
+
49
+ Gather recent financial data, market trends, analyst opinions, and relevant
50
+ news. Focus on fundamentals, competitive position, and macro factors.
51
+ requiresApproval: false
52
+ expectedOutput: research-data
53
+
54
+ - name: Risk Analysis
55
+ profileId: wealth-manager
56
+ promptTemplate: |
57
+ Analyze the investment risks for: {{asset}}
58
+
59
+ Horizon: {{horizon}}
60
+ Risk tolerance: {{riskTolerance}}
61
+
62
+ Evaluate: market risk, liquidity risk, concentration risk, regulatory risk.
63
+ Provide risk-adjusted return expectations and portfolio fit assessment.
64
+ Include appropriate disclaimers about investment advice.
65
+ requiresApproval: true
66
+ expectedOutput: risk-report
67
+
68
+ - name: Investment Report
69
+ profileId: document-writer
70
+ promptTemplate: |
71
+ Write a comprehensive investment research report on: {{asset}}
72
+
73
+ Horizon: {{horizon}}, Risk tolerance: {{riskTolerance}}
74
+
75
+ Synthesize research and risk analysis from previous steps.
76
+ Structure: Executive Summary, Market Analysis, Risk Assessment,
77
+ Recommendation, Key Risks to Monitor.
78
+
79
+ IMPORTANT: Include standard disclaimers that this is not financial advice.
80
+ requiresApproval: true
81
+ expectedOutput: markdown-report