stagent 0.6.2 → 0.7.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 (176) hide show
  1. package/README.md +21 -2
  2. package/dist/cli.js +272 -1
  3. package/docs/.coverage-gaps.json +66 -16
  4. package/docs/.last-generated +1 -1
  5. package/docs/features/dashboard-kanban.md +13 -7
  6. package/docs/features/settings.md +15 -3
  7. package/docs/features/tables.md +122 -0
  8. package/docs/index.md +3 -2
  9. package/docs/journeys/developer.md +26 -16
  10. package/docs/journeys/personal-use.md +23 -9
  11. package/docs/journeys/power-user.md +40 -14
  12. package/docs/journeys/work-use.md +43 -15
  13. package/docs/manifest.json +27 -17
  14. package/package.json +3 -2
  15. package/src/app/api/chat/entities/search/route.ts +12 -3
  16. package/src/app/api/documents/[id]/route.ts +5 -1
  17. package/src/app/api/documents/[id]/versions/route.ts +53 -0
  18. package/src/app/api/documents/route.ts +5 -1
  19. package/src/app/api/projects/[id]/documents/route.ts +124 -0
  20. package/src/app/api/projects/[id]/route.ts +72 -3
  21. package/src/app/api/projects/__tests__/delete-project.test.ts +13 -0
  22. package/src/app/api/schedules/route.ts +19 -1
  23. package/src/app/api/snapshots/[id]/restore/route.ts +62 -0
  24. package/src/app/api/snapshots/[id]/route.ts +44 -0
  25. package/src/app/api/snapshots/route.ts +54 -0
  26. package/src/app/api/snapshots/settings/route.ts +67 -0
  27. package/src/app/api/tables/[id]/charts/[chartId]/route.ts +89 -0
  28. package/src/app/api/tables/[id]/charts/route.ts +72 -0
  29. package/src/app/api/tables/[id]/columns/route.ts +70 -0
  30. package/src/app/api/tables/[id]/export/route.ts +94 -0
  31. package/src/app/api/tables/[id]/history/route.ts +15 -0
  32. package/src/app/api/tables/[id]/import/route.ts +111 -0
  33. package/src/app/api/tables/[id]/route.ts +86 -0
  34. package/src/app/api/tables/[id]/rows/[rowId]/history/route.ts +32 -0
  35. package/src/app/api/tables/[id]/rows/[rowId]/route.ts +51 -0
  36. package/src/app/api/tables/[id]/rows/route.ts +101 -0
  37. package/src/app/api/tables/[id]/triggers/[triggerId]/route.ts +65 -0
  38. package/src/app/api/tables/[id]/triggers/route.ts +122 -0
  39. package/src/app/api/tables/route.ts +65 -0
  40. package/src/app/api/tables/templates/route.ts +92 -0
  41. package/src/app/api/tasks/[id]/route.ts +37 -2
  42. package/src/app/api/tasks/[id]/siblings/route.ts +48 -0
  43. package/src/app/api/tasks/route.ts +8 -9
  44. package/src/app/api/workflows/[id]/documents/route.ts +209 -0
  45. package/src/app/api/workflows/[id]/execute/route.ts +6 -2
  46. package/src/app/api/workflows/[id]/route.ts +16 -3
  47. package/src/app/api/workflows/[id]/status/route.ts +18 -2
  48. package/src/app/api/workflows/route.ts +13 -2
  49. package/src/app/documents/page.tsx +5 -1
  50. package/src/app/layout.tsx +0 -1
  51. package/src/app/manifest.ts +3 -3
  52. package/src/app/projects/[id]/page.tsx +62 -2
  53. package/src/app/settings/page.tsx +2 -0
  54. package/src/app/tables/[id]/page.tsx +67 -0
  55. package/src/app/tables/page.tsx +21 -0
  56. package/src/app/tables/templates/page.tsx +19 -0
  57. package/src/components/chat/chat-table-result.tsx +139 -0
  58. package/src/components/documents/document-browser.tsx +1 -1
  59. package/src/components/documents/document-chip-bar.tsx +17 -1
  60. package/src/components/documents/document-detail-view.tsx +51 -0
  61. package/src/components/documents/document-grid.tsx +5 -0
  62. package/src/components/documents/document-table.tsx +4 -0
  63. package/src/components/documents/types.ts +3 -0
  64. package/src/components/projects/project-form-sheet.tsx +109 -2
  65. package/src/components/schedules/schedule-form.tsx +91 -1
  66. package/src/components/settings/data-management-section.tsx +17 -12
  67. package/src/components/settings/database-snapshots-section.tsx +469 -0
  68. package/src/components/shared/app-sidebar.tsx +2 -0
  69. package/src/components/shared/document-picker-sheet.tsx +486 -0
  70. package/src/components/tables/table-browser.tsx +234 -0
  71. package/src/components/tables/table-cell-editor.tsx +226 -0
  72. package/src/components/tables/table-chart-builder.tsx +288 -0
  73. package/src/components/tables/table-chart-view.tsx +146 -0
  74. package/src/components/tables/table-column-header.tsx +103 -0
  75. package/src/components/tables/table-column-sheet.tsx +331 -0
  76. package/src/components/tables/table-create-sheet.tsx +240 -0
  77. package/src/components/tables/table-detail-sheet.tsx +144 -0
  78. package/src/components/tables/table-detail-tabs.tsx +278 -0
  79. package/src/components/tables/table-grid.tsx +61 -0
  80. package/src/components/tables/table-history-tab.tsx +148 -0
  81. package/src/components/tables/table-import-wizard.tsx +542 -0
  82. package/src/components/tables/table-list-table.tsx +95 -0
  83. package/src/components/tables/table-relation-combobox.tsx +217 -0
  84. package/src/components/tables/table-spreadsheet.tsx +499 -0
  85. package/src/components/tables/table-template-gallery.tsx +162 -0
  86. package/src/components/tables/table-template-preview.tsx +219 -0
  87. package/src/components/tables/table-toolbar.tsx +79 -0
  88. package/src/components/tables/table-triggers-tab.tsx +446 -0
  89. package/src/components/tables/types.ts +6 -0
  90. package/src/components/tables/use-spreadsheet-keys.ts +171 -0
  91. package/src/components/tables/utils.ts +29 -0
  92. package/src/components/tasks/task-card.tsx +8 -1
  93. package/src/components/tasks/task-create-panel.tsx +111 -14
  94. package/src/components/tasks/task-detail-view.tsx +47 -0
  95. package/src/components/tasks/task-edit-dialog.tsx +103 -2
  96. package/src/components/workflows/workflow-form-view.tsx +207 -7
  97. package/src/components/workflows/workflow-kanban-card.tsx +8 -1
  98. package/src/components/workflows/workflow-list.tsx +90 -45
  99. package/src/components/workflows/workflow-status-view.tsx +168 -23
  100. package/src/instrumentation.ts +3 -0
  101. package/src/lib/__tests__/npx-process-cwd.test.ts +17 -2
  102. package/src/lib/agents/__tests__/claude-agent.test.ts +5 -1
  103. package/src/lib/agents/claude-agent.ts +3 -1
  104. package/src/lib/agents/profiles/registry.ts +6 -3
  105. package/src/lib/agents/runtime/anthropic-direct.ts +29 -0
  106. package/src/lib/agents/runtime/openai-direct.ts +29 -0
  107. package/src/lib/book/__tests__/chapter-slugs.test.ts +80 -0
  108. package/src/lib/book/chapter-generator.ts +4 -19
  109. package/src/lib/book/chapter-mapping.ts +17 -0
  110. package/src/lib/book/content.ts +5 -16
  111. package/src/lib/book/update-detector.ts +3 -16
  112. package/src/lib/chat/engine.ts +1 -0
  113. package/src/lib/chat/stagent-tools.ts +2 -0
  114. package/src/lib/chat/system-prompt.ts +9 -1
  115. package/src/lib/chat/tool-catalog.ts +35 -0
  116. package/src/lib/chat/tools/settings-tools.ts +109 -0
  117. package/src/lib/chat/tools/table-tools.ts +955 -0
  118. package/src/lib/chat/tools/workflow-tools.ts +145 -2
  119. package/src/lib/constants/table-status.ts +68 -0
  120. package/src/lib/data/__tests__/clear.test.ts +1 -1
  121. package/src/lib/data/clear.ts +57 -0
  122. package/src/lib/data/seed-data/__tests__/profiles.test.ts +28 -23
  123. package/src/lib/data/seed-data/conversations.ts +350 -42
  124. package/src/lib/data/seed-data/documents.ts +564 -591
  125. package/src/lib/data/seed-data/learned-context.ts +101 -22
  126. package/src/lib/data/seed-data/notifications.ts +344 -70
  127. package/src/lib/data/seed-data/profile-test-results.ts +92 -11
  128. package/src/lib/data/seed-data/profiles.ts +144 -46
  129. package/src/lib/data/seed-data/projects.ts +50 -18
  130. package/src/lib/data/seed-data/repo-imports.ts +28 -13
  131. package/src/lib/data/seed-data/schedules.ts +208 -41
  132. package/src/lib/data/seed-data/table-templates.ts +234 -0
  133. package/src/lib/data/seed-data/tasks.ts +614 -116
  134. package/src/lib/data/seed-data/usage-ledger.ts +182 -103
  135. package/src/lib/data/seed-data/user-tables.ts +203 -0
  136. package/src/lib/data/seed-data/views.ts +52 -7
  137. package/src/lib/data/seed-data/workflows.ts +231 -84
  138. package/src/lib/data/seed.ts +55 -14
  139. package/src/lib/data/tables.ts +417 -0
  140. package/src/lib/db/bootstrap.ts +275 -0
  141. package/src/lib/db/index.ts +9 -0
  142. package/src/lib/db/migrations/0016_add_workflow_document_inputs.sql +13 -0
  143. package/src/lib/db/migrations/0017_add_document_picker_tables.sql +25 -0
  144. package/src/lib/db/migrations/0018_add_workflow_run_number.sql +2 -0
  145. package/src/lib/db/migrations/0019_add_tables_feature.sql +160 -0
  146. package/src/lib/db/migrations/0020_add_table_triggers.sql +19 -0
  147. package/src/lib/db/migrations/0021_add_row_history.sql +15 -0
  148. package/src/lib/db/schema.ts +445 -0
  149. package/src/lib/docs/reader.ts +2 -3
  150. package/src/lib/documents/context-builder.ts +75 -2
  151. package/src/lib/documents/document-resolver.ts +119 -0
  152. package/src/lib/documents/processors/spreadsheet.ts +2 -1
  153. package/src/lib/schedules/scheduler.ts +31 -1
  154. package/src/lib/snapshots/auto-backup.ts +132 -0
  155. package/src/lib/snapshots/retention.ts +64 -0
  156. package/src/lib/snapshots/snapshot-manager.ts +429 -0
  157. package/src/lib/tables/computed.ts +61 -0
  158. package/src/lib/tables/context-builder.ts +139 -0
  159. package/src/lib/tables/formula-engine.ts +415 -0
  160. package/src/lib/tables/history.ts +115 -0
  161. package/src/lib/tables/import.ts +343 -0
  162. package/src/lib/tables/query-builder.ts +152 -0
  163. package/src/lib/tables/trigger-evaluator.ts +146 -0
  164. package/src/lib/tables/types.ts +141 -0
  165. package/src/lib/tables/validation.ts +119 -0
  166. package/src/lib/utils/app-root.ts +20 -0
  167. package/src/lib/utils/stagent-paths.ts +20 -0
  168. package/src/lib/validators/__tests__/task.test.ts +43 -10
  169. package/src/lib/validators/task.ts +7 -1
  170. package/src/lib/workflows/blueprints/registry.ts +3 -3
  171. package/src/lib/workflows/engine.ts +24 -8
  172. package/src/lib/workflows/types.ts +14 -0
  173. package/tsconfig.json +3 -1
  174. package/public/icon.svg +0 -13
  175. package/src/components/tasks/file-upload.tsx +0 -120
  176. /package/docs/features/{playbook.md → user-guide.md} +0 -0
@@ -15,6 +15,12 @@ export interface ScheduleSeed {
15
15
  expiresAt: Date | null;
16
16
  lastFiredAt: Date | null;
17
17
  nextFireAt: Date | null;
18
+ type: "scheduled" | "heartbeat";
19
+ heartbeatChecklist: string | null;
20
+ activeHoursStart: number | null;
21
+ activeHoursEnd: number | null;
22
+ activeTimezone: string | null;
23
+ deliveryChannels: string | null;
18
24
  createdAt: Date;
19
25
  updatedAt: Date;
20
26
  }
@@ -23,85 +29,246 @@ export function createSchedules(projectIds: string[]): ScheduleSeed[] {
23
29
  const now = Date.now();
24
30
  const DAY = 86_400_000;
25
31
  const HOUR = 3_600_000;
26
- const [investmentProject, launchProject, leadGenProject, , taxProject] =
27
- projectIds;
32
+ const [
33
+ launchProject,
34
+ contentProject,
35
+ csProject,
36
+ tvpProject,
37
+ greenleafProject,
38
+ medreachProject,
39
+ revopsProject,
40
+ complianceProject,
41
+ ] = projectIds;
28
42
 
29
- const weekdayPortfolioCron = "0 9 * * 1-5";
30
- const dailyLaunchCron = "0 9 * * *";
31
- const everySixHoursCron = "0 */6 * * *";
32
- const taxReminderCron = "0 9 * * *";
43
+ const daily8am = "0 8 * * *";
44
+ const mwf9am = "0 9 * * 1,3,5";
45
+ const every6h = "0 */6 * * *";
46
+ const weeklyMon7am = "0 7 * * 1";
47
+ const every4h = "0 */4 * * *";
48
+ const daily6am = "0 6 * * *";
49
+ const every8h = "0 */8 * * *";
50
+ const monthly1st = "0 9 1 * *";
33
51
 
34
52
  return [
53
+ // 1. Launch Metrics Digest — daily, Slack delivery
35
54
  {
36
55
  id: crypto.randomUUID(),
37
- projectId: investmentProject,
38
- name: "Weekday Portfolio Digest",
56
+ projectId: launchProject,
57
+ name: "Launch Metrics Digest",
58
+ prompt:
59
+ "Pull yesterday's launch metrics: landing page visits, signup conversions, email open rates, and social engagement. Highlight any metric that moved >10% and flag channels underperforming targets.",
60
+ cronExpression: daily8am,
61
+ agentProfile: SAMPLE_PROFILE_IDS[0], // GTM Launch Strategist
62
+ recurs: true,
63
+ status: "active",
64
+ maxFirings: null,
65
+ firingCount: 12,
66
+ expiresAt: null,
67
+ lastFiredAt: new Date(now - 16 * HOUR),
68
+ nextFireAt: computeNextFireTime(daily8am, new Date(now)),
69
+ type: "scheduled",
70
+ heartbeatChecklist: null,
71
+ activeHoursStart: null,
72
+ activeHoursEnd: null,
73
+ activeTimezone: null,
74
+ deliveryChannels: JSON.stringify(["slack"]),
75
+ createdAt: new Date(now - 18 * DAY),
76
+ updatedAt: new Date(now - 1 * HOUR),
77
+ },
78
+
79
+ // 2. Content Calendar Check-In — MWF, Content Editor
80
+ {
81
+ id: crypto.randomUUID(),
82
+ projectId: contentProject,
83
+ name: "Content Calendar Check-In",
84
+ prompt:
85
+ "Review the editorial calendar for this week. Confirm articles in progress have outlines approved, flag any pieces behind schedule, and suggest topic swaps if a trending topic emerged overnight.",
86
+ cronExpression: mwf9am,
87
+ agentProfile: SAMPLE_PROFILE_IDS[1], // Content Production Editor
88
+ recurs: true,
89
+ status: "active",
90
+ maxFirings: null,
91
+ firingCount: 8,
92
+ expiresAt: null,
93
+ lastFiredAt: new Date(now - 2 * DAY),
94
+ nextFireAt: computeNextFireTime(mwf9am, new Date(now)),
95
+ type: "scheduled",
96
+ heartbeatChecklist: null,
97
+ activeHoursStart: null,
98
+ activeHoursEnd: null,
99
+ activeTimezone: null,
100
+ deliveryChannels: null,
101
+ createdAt: new Date(now - 15 * DAY),
102
+ updatedAt: new Date(now - 2 * DAY),
103
+ },
104
+
105
+ // 3. Churn Risk Heartbeat — intelligence-driven, every 6h
106
+ {
107
+ id: crypto.randomUUID(),
108
+ projectId: csProject,
109
+ name: "Churn Risk Heartbeat",
110
+ prompt:
111
+ "Evaluate the customer health checklist. Only take action if a signal fires — otherwise suppress and log. When action is needed, draft the intervention and notify via Slack and email.",
112
+ cronExpression: every6h,
113
+ agentProfile: SAMPLE_PROFILE_IDS[2], // Customer Success Analyst
114
+ recurs: true,
115
+ status: "active",
116
+ maxFirings: null,
117
+ firingCount: 22,
118
+ expiresAt: null,
119
+ lastFiredAt: new Date(now - 4 * HOUR),
120
+ nextFireAt: computeNextFireTime(every6h, new Date(now)),
121
+ type: "heartbeat",
122
+ heartbeatChecklist: JSON.stringify([
123
+ "Any account NPS dropped below 30?",
124
+ "Any account usage declined >40% week-over-week?",
125
+ "Any account filed >3 support tickets this week?",
126
+ "Any enterprise renewal within 60 days with no CSM touchpoint?",
127
+ ]),
128
+ activeHoursStart: 8,
129
+ activeHoursEnd: 20,
130
+ activeTimezone: "America/Los_Angeles",
131
+ deliveryChannels: JSON.stringify(["slack", "email"]),
132
+ createdAt: new Date(now - 14 * DAY),
133
+ updatedAt: new Date(now - 4 * HOUR),
134
+ },
135
+
136
+ // 4. Portfolio KPI Tracker — weekly Monday 7am
137
+ {
138
+ id: crypto.randomUUID(),
139
+ projectId: tvpProject,
140
+ name: "Portfolio KPI Tracker",
141
+ prompt:
142
+ "Pull the weekly KPI snapshot for all 4 portfolio companies: MRR, burn rate, net retention, and headcount. Flag any company with MRR growth <5% or burn rate acceleration >15%. Format as a board-ready summary.",
143
+ cronExpression: weeklyMon7am,
144
+ agentProfile: SAMPLE_PROFILE_IDS[3], // Due Diligence Analyst
145
+ recurs: true,
146
+ status: "active",
147
+ maxFirings: null,
148
+ firingCount: 3,
149
+ expiresAt: null,
150
+ lastFiredAt: new Date(now - 5 * DAY),
151
+ nextFireAt: computeNextFireTime(weeklyMon7am, new Date(now)),
152
+ type: "scheduled",
153
+ heartbeatChecklist: null,
154
+ activeHoursStart: null,
155
+ activeHoursEnd: null,
156
+ activeTimezone: null,
157
+ deliveryChannels: JSON.stringify(["slack"]),
158
+ createdAt: new Date(now - 12 * DAY),
159
+ updatedAt: new Date(now - 5 * DAY),
160
+ },
161
+
162
+ // 5. Review Sentiment Heartbeat — every 4h, e-commerce monitoring
163
+ {
164
+ id: crypto.randomUUID(),
165
+ projectId: greenleafProject,
166
+ name: "Review Sentiment Heartbeat",
39
167
  prompt:
40
- "Before market open, summarize allocation drift, overnight movers, and any watchlist actions for the investment portfolio.",
41
- cronExpression: weekdayPortfolioCron,
42
- agentProfile: SAMPLE_PROFILE_IDS[2],
168
+ "Check the product review feeds for new negative reviews, competitor price changes, and inventory alerts. Only act when a signal fires — draft a response template for 1-2 star reviews and alert the client.",
169
+ cronExpression: every4h,
170
+ agentProfile: "general",
43
171
  recurs: true,
44
172
  status: "active",
45
173
  maxFirings: null,
46
- firingCount: 0,
174
+ firingCount: 35,
47
175
  expiresAt: null,
48
- lastFiredAt: null,
49
- nextFireAt: computeNextFireTime(weekdayPortfolioCron, new Date(now)),
176
+ lastFiredAt: new Date(now - 2 * HOUR),
177
+ nextFireAt: computeNextFireTime(every4h, new Date(now)),
178
+ type: "heartbeat",
179
+ heartbeatChecklist: JSON.stringify([
180
+ "New 1-star or 2-star product review?",
181
+ "Competitor price drop >10% on a tracked SKU?",
182
+ "Inventory below reorder threshold for top 10 SKUs?",
183
+ ]),
184
+ activeHoursStart: 6,
185
+ activeHoursEnd: 22,
186
+ activeTimezone: "America/New_York",
187
+ deliveryChannels: null,
50
188
  createdAt: new Date(now - 10 * DAY),
51
189
  updatedAt: new Date(now - 2 * HOUR),
52
190
  },
191
+
192
+ // 6. Compliance Scan — daily 6am, paused (client paused)
53
193
  {
54
194
  id: crypto.randomUUID(),
55
- projectId: launchProject,
56
- name: "CTA Experiment Check-In",
195
+ projectId: medreachProject,
196
+ name: "HIPAA Compliance Scan",
57
197
  prompt:
58
- "Each morning, compare yesterday's CTA variant performance and suggest the next headline or proof point to test on the landing page.",
59
- cronExpression: dailyLaunchCron,
60
- agentProfile: SAMPLE_PROFILE_IDS[1],
198
+ "Scan all pending marketing content for HIPAA violations, unsubstantiated health claims, and missing disclaimers. Generate a compliance scorecard and route flagged items to legal.",
199
+ cronExpression: daily6am,
200
+ agentProfile: "general",
61
201
  recurs: true,
62
202
  status: "paused",
63
203
  maxFirings: null,
64
- firingCount: 0,
204
+ firingCount: 6,
65
205
  expiresAt: null,
66
- lastFiredAt: null,
206
+ lastFiredAt: new Date(now - 5 * DAY),
67
207
  nextFireAt: null,
68
- createdAt: new Date(now - 6 * DAY),
69
- updatedAt: new Date(now - 1 * DAY),
208
+ type: "scheduled",
209
+ heartbeatChecklist: null,
210
+ activeHoursStart: null,
211
+ activeHoursEnd: null,
212
+ activeTimezone: null,
213
+ deliveryChannels: JSON.stringify(["email"]),
214
+ createdAt: new Date(now - 9 * DAY),
215
+ updatedAt: new Date(now - 4 * DAY),
70
216
  },
217
+
218
+ // 7. Deal Stall Heartbeat — every 8h, RevOps
71
219
  {
72
220
  id: crypto.randomUUID(),
73
- projectId: leadGenProject,
74
- name: "Prospect Pipeline Pulse",
221
+ projectId: revopsProject,
222
+ name: "Deal Stall Heartbeat",
75
223
  prompt:
76
- "Every six hours, roll up new prospects, stalled outreach, and reply-rate changes into a short GTM update with owner follow-ups.",
77
- cronExpression: everySixHoursCron,
78
- agentProfile: SAMPLE_PROFILE_IDS[0],
224
+ "Evaluate stalled deal checklist. When a signal fires, draft a coaching note for the rep and suggest a specific unblocking action. Deliver via Slack to the #revenue-ops channel.",
225
+ cronExpression: every8h,
226
+ agentProfile: SAMPLE_PROFILE_IDS[4], // Revenue Ops Analyst
79
227
  recurs: true,
80
228
  status: "active",
81
229
  maxFirings: null,
82
- firingCount: 0,
230
+ firingCount: 14,
83
231
  expiresAt: null,
84
- lastFiredAt: null,
85
- nextFireAt: computeNextFireTime(everySixHoursCron, new Date(now)),
86
- createdAt: new Date(now - 5 * DAY),
87
- updatedAt: new Date(now - 90 * 60_000),
232
+ lastFiredAt: new Date(now - 6 * HOUR),
233
+ nextFireAt: computeNextFireTime(every8h, new Date(now)),
234
+ type: "heartbeat",
235
+ heartbeatChecklist: JSON.stringify([
236
+ "Any deal stalled >5 business days with no activity?",
237
+ "Any deal missing a defined next step?",
238
+ "Any champion gone dark (no email open in 7 days)?",
239
+ "Any deal pushed close date more than twice?",
240
+ ]),
241
+ activeHoursStart: 7,
242
+ activeHoursEnd: 19,
243
+ activeTimezone: "America/Chicago",
244
+ deliveryChannels: JSON.stringify(["slack"]),
245
+ createdAt: new Date(now - 7 * DAY),
246
+ updatedAt: new Date(now - 6 * HOUR),
88
247
  },
248
+
249
+ // 8. Monthly Audit Run — 1st of month, expired
89
250
  {
90
251
  id: crypto.randomUUID(),
91
- projectId: taxProject,
92
- name: "Missing Tax Form Reminder",
252
+ projectId: complianceProject,
253
+ name: "Monthly Compliance Audit",
93
254
  prompt:
94
- "Send a one-time reminder to chase any missing tax documents, update the checklist, and flag anything that could block the CPA handoff.",
95
- cronExpression: taxReminderCron,
96
- agentProfile: "project-manager",
255
+ "Run the full monthly compliance audit: gather execution logs, analyze against SOC 2 controls, generate the report, and prepare the executive brief. Deliver to the compliance-reviews channel.",
256
+ cronExpression: monthly1st,
257
+ agentProfile: "general",
97
258
  recurs: false,
98
259
  status: "expired",
99
260
  maxFirings: 1,
100
- firingCount: 0,
261
+ firingCount: 1,
101
262
  expiresAt: new Date(now - 1 * DAY),
102
- lastFiredAt: null,
263
+ lastFiredAt: new Date(now - 3 * DAY),
103
264
  nextFireAt: null,
104
- createdAt: new Date(now - 4 * DAY),
265
+ type: "scheduled",
266
+ heartbeatChecklist: null,
267
+ activeHoursStart: null,
268
+ activeHoursEnd: null,
269
+ activeTimezone: null,
270
+ deliveryChannels: JSON.stringify(["slack", "email"]),
271
+ createdAt: new Date(now - 5 * DAY),
105
272
  updatedAt: new Date(now - 1 * DAY),
106
273
  },
107
274
  ];
@@ -0,0 +1,234 @@
1
+ import { randomUUID } from "crypto";
2
+ import { db } from "@/lib/db";
3
+ import { userTableTemplates } from "@/lib/db/schema";
4
+ import { eq, and } from "drizzle-orm";
5
+
6
+ interface TemplateSeed {
7
+ name: string;
8
+ description: string;
9
+ category: "business" | "personal" | "pm" | "finance" | "content";
10
+ icon: string;
11
+ columns: Array<{
12
+ name: string;
13
+ displayName: string;
14
+ dataType: string;
15
+ config?: Record<string, unknown>;
16
+ }>;
17
+ sampleData?: Record<string, unknown>[];
18
+ }
19
+
20
+ const TEMPLATES: TemplateSeed[] = [
21
+ // ── Business ───────────────────────────────────────────────────────
22
+ {
23
+ name: "Customer List",
24
+ description: "Track customers with contact info and status",
25
+ category: "business",
26
+ icon: "Building2",
27
+ columns: [
28
+ { name: "name", displayName: "Name", dataType: "text" },
29
+ { name: "email", displayName: "Email", dataType: "email" },
30
+ { name: "company", displayName: "Company", dataType: "text" },
31
+ { name: "status", displayName: "Status", dataType: "select", config: { options: ["Lead", "Active", "Churned"] } },
32
+ { name: "notes", displayName: "Notes", dataType: "text" },
33
+ ],
34
+ sampleData: [
35
+ { name: "Alice Johnson", email: "alice@example.com", company: "Acme Corp", status: "Active", notes: "" },
36
+ { name: "Bob Smith", email: "bob@example.com", company: "Widget Inc", status: "Lead", notes: "Follow up next week" },
37
+ ],
38
+ },
39
+ {
40
+ name: "Product Inventory",
41
+ description: "Track products, quantities, and pricing",
42
+ category: "business",
43
+ icon: "Package",
44
+ columns: [
45
+ { name: "product", displayName: "Product", dataType: "text" },
46
+ { name: "sku", displayName: "SKU", dataType: "text" },
47
+ { name: "quantity", displayName: "Quantity", dataType: "number" },
48
+ { name: "price", displayName: "Price", dataType: "number" },
49
+ { name: "category", displayName: "Category", dataType: "select", config: { options: ["Electronics", "Clothing", "Food", "Other"] } },
50
+ ],
51
+ },
52
+ {
53
+ name: "Meeting Notes",
54
+ description: "Log meetings with attendees and action items",
55
+ category: "business",
56
+ icon: "Users",
57
+ columns: [
58
+ { name: "date", displayName: "Date", dataType: "date" },
59
+ { name: "title", displayName: "Title", dataType: "text" },
60
+ { name: "attendees", displayName: "Attendees", dataType: "text" },
61
+ { name: "notes", displayName: "Notes", dataType: "text" },
62
+ { name: "action_items", displayName: "Action Items", dataType: "text" },
63
+ ],
64
+ },
65
+
66
+ // ── Personal ───────────────────────────────────────────────────────
67
+ {
68
+ name: "Reading List",
69
+ description: "Books and articles to read",
70
+ category: "personal",
71
+ icon: "BookOpen",
72
+ columns: [
73
+ { name: "title", displayName: "Title", dataType: "text" },
74
+ { name: "author", displayName: "Author", dataType: "text" },
75
+ { name: "status", displayName: "Status", dataType: "select", config: { options: ["To Read", "Reading", "Finished"] } },
76
+ { name: "rating", displayName: "Rating", dataType: "number" },
77
+ { name: "notes", displayName: "Notes", dataType: "text" },
78
+ ],
79
+ },
80
+ {
81
+ name: "Habit Tracker",
82
+ description: "Daily habits and streaks",
83
+ category: "personal",
84
+ icon: "Target",
85
+ columns: [
86
+ { name: "habit", displayName: "Habit", dataType: "text" },
87
+ { name: "frequency", displayName: "Frequency", dataType: "select", config: { options: ["Daily", "Weekly", "Monthly"] } },
88
+ { name: "streak", displayName: "Streak", dataType: "number" },
89
+ { name: "completed", displayName: "Completed Today", dataType: "boolean" },
90
+ ],
91
+ },
92
+
93
+ // ── Project Management ─────────────────────────────────────────────
94
+ {
95
+ name: "Sprint Board",
96
+ description: "Track sprint tasks with points and assignees",
97
+ category: "pm",
98
+ icon: "KanbanSquare",
99
+ columns: [
100
+ { name: "task", displayName: "Task", dataType: "text" },
101
+ { name: "assignee", displayName: "Assignee", dataType: "text" },
102
+ { name: "status", displayName: "Status", dataType: "select", config: { options: ["Backlog", "In Progress", "Review", "Done"] } },
103
+ { name: "points", displayName: "Points", dataType: "number" },
104
+ { name: "due_date", displayName: "Due Date", dataType: "date" },
105
+ ],
106
+ },
107
+ {
108
+ name: "Bug Tracker",
109
+ description: "Track bugs with severity and reproduction steps",
110
+ category: "pm",
111
+ icon: "Bug",
112
+ columns: [
113
+ { name: "title", displayName: "Title", dataType: "text" },
114
+ { name: "severity", displayName: "Severity", dataType: "select", config: { options: ["Critical", "High", "Medium", "Low"] } },
115
+ { name: "status", displayName: "Status", dataType: "select", config: { options: ["Open", "In Progress", "Fixed", "Closed"] } },
116
+ { name: "reported_by", displayName: "Reported By", dataType: "text" },
117
+ { name: "steps", displayName: "Steps to Reproduce", dataType: "text" },
118
+ ],
119
+ },
120
+ {
121
+ name: "Feature Requests",
122
+ description: "Collect and prioritize feature ideas",
123
+ category: "pm",
124
+ icon: "Lightbulb",
125
+ columns: [
126
+ { name: "feature", displayName: "Feature", dataType: "text" },
127
+ { name: "requester", displayName: "Requester", dataType: "text" },
128
+ { name: "priority", displayName: "Priority", dataType: "select", config: { options: ["P0", "P1", "P2", "P3"] } },
129
+ { name: "votes", displayName: "Votes", dataType: "number" },
130
+ { name: "status", displayName: "Status", dataType: "select", config: { options: ["Proposed", "Approved", "Building", "Shipped"] } },
131
+ ],
132
+ },
133
+
134
+ // ── Finance ────────────────────────────────────────────────────────
135
+ {
136
+ name: "Expense Tracker",
137
+ description: "Log expenses with categories and receipts",
138
+ category: "finance",
139
+ icon: "Receipt",
140
+ columns: [
141
+ { name: "date", displayName: "Date", dataType: "date" },
142
+ { name: "description", displayName: "Description", dataType: "text" },
143
+ { name: "amount", displayName: "Amount", dataType: "number" },
144
+ { name: "category", displayName: "Category", dataType: "select", config: { options: ["Food", "Transport", "Software", "Office", "Other"] } },
145
+ { name: "receipt_url", displayName: "Receipt", dataType: "url" },
146
+ ],
147
+ },
148
+ {
149
+ name: "Invoice Log",
150
+ description: "Track invoices and payment status",
151
+ category: "finance",
152
+ icon: "FileText",
153
+ columns: [
154
+ { name: "invoice_number", displayName: "Invoice #", dataType: "text" },
155
+ { name: "client", displayName: "Client", dataType: "text" },
156
+ { name: "amount", displayName: "Amount", dataType: "number" },
157
+ { name: "issued_date", displayName: "Issued", dataType: "date" },
158
+ { name: "status", displayName: "Status", dataType: "select", config: { options: ["Draft", "Sent", "Paid", "Overdue"] } },
159
+ ],
160
+ },
161
+
162
+ // ── Content ────────────────────────────────────────────────────────
163
+ {
164
+ name: "Content Calendar",
165
+ description: "Plan and schedule content across channels",
166
+ category: "content",
167
+ icon: "Calendar",
168
+ columns: [
169
+ { name: "title", displayName: "Title", dataType: "text" },
170
+ { name: "channel", displayName: "Channel", dataType: "select", config: { options: ["Blog", "Twitter", "LinkedIn", "Newsletter", "YouTube"] } },
171
+ { name: "publish_date", displayName: "Publish Date", dataType: "date" },
172
+ { name: "status", displayName: "Status", dataType: "select", config: { options: ["Idea", "Drafting", "Review", "Scheduled", "Published"] } },
173
+ { name: "url", displayName: "URL", dataType: "url" },
174
+ ],
175
+ },
176
+ {
177
+ name: "Research Notes",
178
+ description: "Organize research with sources and tags",
179
+ category: "content",
180
+ icon: "Search",
181
+ columns: [
182
+ { name: "topic", displayName: "Topic", dataType: "text" },
183
+ { name: "source", displayName: "Source", dataType: "url" },
184
+ { name: "key_findings", displayName: "Key Findings", dataType: "text" },
185
+ { name: "relevance", displayName: "Relevance", dataType: "select", config: { options: ["High", "Medium", "Low"] } },
186
+ { name: "date_added", displayName: "Date Added", dataType: "date" },
187
+ ],
188
+ },
189
+ ];
190
+
191
+ /**
192
+ * Seed system templates if not already present.
193
+ * Idempotent — checks for existing templates by name + scope='system'.
194
+ */
195
+ export async function seedTableTemplates(): Promise<number> {
196
+ let created = 0;
197
+ const now = new Date();
198
+
199
+ for (const t of TEMPLATES) {
200
+ const existing = db
201
+ .select()
202
+ .from(userTableTemplates)
203
+ .where(
204
+ and(
205
+ eq(userTableTemplates.name, t.name),
206
+ eq(userTableTemplates.scope, "system")
207
+ )
208
+ )
209
+ .get();
210
+
211
+ if (existing) continue;
212
+
213
+ const columnsWithPositions = t.columns.map((col, i) => ({
214
+ ...col,
215
+ position: i,
216
+ }));
217
+
218
+ await db.insert(userTableTemplates).values({
219
+ id: randomUUID(),
220
+ name: t.name,
221
+ description: t.description,
222
+ category: t.category,
223
+ columnSchema: JSON.stringify(columnsWithPositions),
224
+ sampleData: t.sampleData ? JSON.stringify(t.sampleData) : null,
225
+ scope: "system",
226
+ icon: t.icon,
227
+ createdAt: now,
228
+ updatedAt: now,
229
+ });
230
+ created++;
231
+ }
232
+
233
+ return created;
234
+ }