stagent 0.9.6 → 0.11.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 (396) hide show
  1. package/README.md +20 -44
  2. package/dist/cli.js +66 -18
  3. package/docs/.coverage-gaps.json +144 -56
  4. package/docs/.last-generated +1 -1
  5. package/docs/features/agent-intelligence.md +12 -2
  6. package/docs/features/chat.md +40 -5
  7. package/docs/features/cost-usage.md +1 -1
  8. package/docs/features/documents.md +5 -2
  9. package/docs/features/inbox-notifications.md +10 -2
  10. package/docs/features/keyboard-navigation.md +12 -3
  11. package/docs/features/provider-runtimes.md +20 -2
  12. package/docs/features/schedules.md +32 -4
  13. package/docs/features/settings.md +28 -5
  14. package/docs/features/shared-components.md +7 -3
  15. package/docs/features/tables.md +11 -2
  16. package/docs/features/tool-permissions.md +6 -2
  17. package/docs/features/workflows.md +14 -4
  18. package/docs/index.md +1 -1
  19. package/docs/journeys/developer.md +39 -2
  20. package/docs/journeys/personal-use.md +32 -8
  21. package/docs/journeys/power-user.md +45 -14
  22. package/docs/journeys/work-use.md +17 -8
  23. package/docs/manifest.json +15 -15
  24. package/docs/superpowers/plans/2026-04-07-instance-bootstrap.md +1691 -0
  25. package/docs/superpowers/plans/2026-04-08-schedule-orchestration.md +2983 -0
  26. package/docs/superpowers/plans/2026-04-11-schedule-maxturns-api-control.md +551 -0
  27. package/docs/superpowers/plans/2026-04-11-task-create-profile-validation.md +864 -0
  28. package/docs/superpowers/plans/2026-04-11-task-runtime-stagent-mcp-injection.md +739 -0
  29. package/docs/superpowers/plans/2026-04-14-chat-command-namespace-refactor.md +1390 -0
  30. package/docs/superpowers/plans/2026-04-14-chat-environment-integration.md +1561 -0
  31. package/docs/superpowers/plans/2026-04-14-chat-polish-bundle-v1.md +1219 -0
  32. package/docs/superpowers/plans/2026-04-14-chat-session-persistence-provider-closeout.md +399 -0
  33. package/docs/superpowers/specs/2026-04-08-chat-sse-resilience-hotfix-design.md +201 -0
  34. package/docs/superpowers/specs/2026-04-08-schedule-orchestration-design.md +371 -0
  35. package/docs/superpowers/specs/2026-04-08-swarm-visibility-design.md +213 -0
  36. package/next.config.mjs +1 -0
  37. package/package.json +3 -2
  38. package/src/__tests__/instrumentation-smoke.test.ts +15 -0
  39. package/src/app/analytics/page.tsx +1 -21
  40. package/src/app/api/chat/conversations/[id]/messages/route.ts +22 -1
  41. package/src/app/api/chat/conversations/[id]/skills/__tests__/activate.test.ts +141 -0
  42. package/src/app/api/chat/conversations/[id]/skills/activate/route.ts +74 -0
  43. package/src/app/api/chat/conversations/[id]/skills/deactivate/route.ts +33 -0
  44. package/src/app/api/chat/export/route.ts +52 -0
  45. package/src/app/api/chat/files/search/route.ts +50 -0
  46. package/src/app/api/diagnostics/chat-streams/route.ts +65 -0
  47. package/src/app/api/environment/rescan-if-stale/__tests__/route.test.ts +45 -0
  48. package/src/app/api/environment/rescan-if-stale/route.ts +23 -0
  49. package/src/app/api/environment/skills/route.ts +13 -0
  50. package/src/app/api/instance/config/route.ts +41 -0
  51. package/src/app/api/instance/init/route.ts +34 -0
  52. package/src/app/api/instance/upgrade/check/route.ts +26 -0
  53. package/src/app/api/instance/upgrade/route.ts +96 -0
  54. package/src/app/api/instance/upgrade/status/route.ts +35 -0
  55. package/src/app/api/memory/route.ts +0 -11
  56. package/src/app/api/notifications/route.ts +4 -2
  57. package/src/app/api/projects/[id]/route.ts +5 -155
  58. package/src/app/api/projects/__tests__/delete-project.test.ts +10 -19
  59. package/src/app/api/schedules/[id]/execute/route.ts +111 -0
  60. package/src/app/api/schedules/[id]/route.ts +9 -1
  61. package/src/app/api/schedules/__tests__/execute-route.test.ts +118 -0
  62. package/src/app/api/schedules/route.ts +3 -12
  63. package/src/app/api/settings/chat/pins/route.ts +94 -0
  64. package/src/app/api/settings/chat/saved-searches/__tests__/route.test.ts +119 -0
  65. package/src/app/api/settings/chat/saved-searches/route.ts +79 -0
  66. package/src/app/api/settings/environment/route.ts +26 -0
  67. package/src/app/api/settings/openai/login/route.ts +22 -0
  68. package/src/app/api/settings/openai/logout/route.ts +7 -0
  69. package/src/app/api/settings/openai/route.ts +21 -1
  70. package/src/app/api/settings/providers/route.ts +35 -8
  71. package/src/app/api/tables/[id]/enrich/__tests__/route.test.ts +153 -0
  72. package/src/app/api/tables/[id]/enrich/plan/route.ts +98 -0
  73. package/src/app/api/tables/[id]/enrich/route.ts +147 -0
  74. package/src/app/api/tables/[id]/enrich/runs/route.ts +25 -0
  75. package/src/app/api/tasks/[id]/execute/route.ts +52 -33
  76. package/src/app/api/tasks/[id]/respond/route.ts +31 -15
  77. package/src/app/api/tasks/[id]/resume/route.ts +24 -3
  78. package/src/app/api/workflows/[id]/resume/route.ts +59 -0
  79. package/src/app/api/workflows/[id]/status/route.ts +22 -8
  80. package/src/app/api/workspace/context/route.ts +2 -0
  81. package/src/app/api/workspace/fix-data-dir/route.ts +81 -0
  82. package/src/app/chat/page.tsx +11 -0
  83. package/src/app/documents/page.tsx +4 -1
  84. package/src/app/inbox/page.tsx +12 -5
  85. package/src/app/layout.tsx +42 -21
  86. package/src/app/page.tsx +0 -2
  87. package/src/app/settings/page.tsx +8 -9
  88. package/src/components/chat/__tests__/capability-banner.test.tsx +38 -0
  89. package/src/components/chat/__tests__/chat-session-provider.test.tsx +573 -0
  90. package/src/components/chat/__tests__/skill-row.test.tsx +91 -0
  91. package/src/components/chat/capability-banner.tsx +68 -0
  92. package/src/components/chat/chat-command-popover.tsx +670 -49
  93. package/src/components/chat/chat-input.tsx +104 -10
  94. package/src/components/chat/chat-message.tsx +12 -3
  95. package/src/components/chat/chat-session-provider.tsx +790 -0
  96. package/src/components/chat/chat-shell.tsx +151 -401
  97. package/src/components/chat/command-tab-bar.tsx +68 -0
  98. package/src/components/chat/conversation-template-picker.tsx +421 -0
  99. package/src/components/chat/help-dialog.tsx +39 -0
  100. package/src/components/chat/skill-composition-conflict-dialog.tsx +96 -0
  101. package/src/components/chat/skill-row.tsx +147 -0
  102. package/src/components/documents/document-browser.tsx +37 -19
  103. package/src/components/instance/__tests__/instance-section.test.tsx +125 -0
  104. package/src/components/instance/instance-section.tsx +382 -0
  105. package/src/components/instance/upgrade-badge.tsx +219 -0
  106. package/src/components/notifications/__tests__/batch-proposal-review.test.tsx +95 -0
  107. package/src/components/notifications/__tests__/notification-item.test.tsx +106 -0
  108. package/src/components/notifications/__tests__/permission-response-actions.test.tsx +70 -0
  109. package/src/components/notifications/batch-proposal-review.tsx +20 -5
  110. package/src/components/notifications/inbox-list.tsx +11 -2
  111. package/src/components/notifications/notification-item.tsx +56 -2
  112. package/src/components/notifications/pending-approval-host.tsx +56 -37
  113. package/src/components/notifications/permission-response-actions.tsx +155 -1
  114. package/src/components/schedules/schedule-create-sheet.tsx +19 -1
  115. package/src/components/schedules/schedule-edit-sheet.tsx +20 -1
  116. package/src/components/schedules/schedule-form.tsx +31 -0
  117. package/src/components/settings/__tests__/providers-runtimes-section.test.tsx +149 -0
  118. package/src/components/settings/auth-method-selector.tsx +19 -4
  119. package/src/components/settings/auth-status-badge.tsx +28 -3
  120. package/src/components/settings/environment-section.tsx +102 -0
  121. package/src/components/settings/openai-chatgpt-auth-control.tsx +278 -0
  122. package/src/components/settings/openai-runtime-section.tsx +7 -1
  123. package/src/components/settings/providers-runtimes-section.tsx +138 -19
  124. package/src/components/shared/__tests__/filter-hint.test.tsx +40 -0
  125. package/src/components/shared/__tests__/saved-searches-manager.test.tsx +147 -0
  126. package/src/components/shared/app-sidebar.tsx +4 -3
  127. package/src/components/shared/command-palette.tsx +266 -7
  128. package/src/components/shared/filter-hint.tsx +70 -0
  129. package/src/components/shared/filter-input.tsx +59 -0
  130. package/src/components/shared/saved-searches-manager.tsx +199 -0
  131. package/src/components/shared/theme-toggle.tsx +5 -24
  132. package/src/components/shared/workspace-indicator.tsx +61 -2
  133. package/src/components/tables/__tests__/table-enrichment-sheet.test.tsx +130 -0
  134. package/src/components/tables/table-create-sheet.tsx +4 -0
  135. package/src/components/tables/table-enrichment-runs.tsx +103 -0
  136. package/src/components/tables/table-enrichment-sheet.tsx +538 -0
  137. package/src/components/tables/table-spreadsheet.tsx +29 -5
  138. package/src/components/tables/table-toolbar.tsx +10 -1
  139. package/src/components/tasks/kanban-board.tsx +1 -0
  140. package/src/components/tasks/kanban-column.tsx +53 -14
  141. package/src/components/tasks/task-bento-grid.tsx +31 -2
  142. package/src/components/tasks/task-card.tsx +29 -3
  143. package/src/components/tasks/task-chip-bar.tsx +54 -1
  144. package/src/components/tasks/task-result-renderer.tsx +1 -1
  145. package/src/components/workflows/delay-step-body.tsx +109 -0
  146. package/src/components/workflows/hooks/use-workflow-status.ts +50 -0
  147. package/src/components/workflows/loop-status-view.tsx +1 -1
  148. package/src/components/workflows/shared/step-result.tsx +78 -0
  149. package/src/components/workflows/shared/workflow-header.tsx +141 -0
  150. package/src/components/workflows/shared/workflow-loading-skeleton.tsx +36 -0
  151. package/src/components/workflows/swarm-dashboard.tsx +2 -15
  152. package/src/components/workflows/views/loop-pattern-view.tsx +137 -0
  153. package/src/components/workflows/views/sequence-pattern-view.tsx +511 -0
  154. package/src/components/workflows/workflow-form-view.tsx +133 -16
  155. package/src/components/workflows/workflow-status-view.tsx +30 -740
  156. package/src/hooks/__tests__/use-chat-autocomplete-tabs.test.ts +47 -0
  157. package/src/hooks/__tests__/use-saved-searches.test.ts +70 -0
  158. package/src/hooks/use-active-skills.ts +110 -0
  159. package/src/hooks/use-chat-autocomplete.ts +120 -7
  160. package/src/hooks/use-enriched-skills.ts +19 -0
  161. package/src/hooks/use-pinned-entries.ts +104 -0
  162. package/src/hooks/use-recent-user-messages.ts +19 -0
  163. package/src/hooks/use-saved-searches.ts +142 -0
  164. package/src/instrumentation-node.ts +94 -0
  165. package/src/instrumentation.ts +4 -48
  166. package/src/lib/agents/__tests__/claude-agent-sdk-options.test.ts +56 -0
  167. package/src/lib/agents/__tests__/claude-agent.test.ts +212 -0
  168. package/src/lib/agents/__tests__/execution-manager.test.ts +1 -27
  169. package/src/lib/agents/__tests__/failure-reason.test.ts +68 -0
  170. package/src/lib/agents/__tests__/learned-context.test.ts +0 -11
  171. package/src/lib/agents/__tests__/learning-session.test.ts +158 -0
  172. package/src/lib/agents/__tests__/pattern-extractor.test.ts +48 -0
  173. package/src/lib/agents/__tests__/task-dispatch.test.ts +166 -0
  174. package/src/lib/agents/__tests__/tool-permissions.test.ts +60 -0
  175. package/src/lib/agents/claude-agent.ts +217 -21
  176. package/src/lib/agents/execution-manager.ts +0 -35
  177. package/src/lib/agents/handoff/bus.ts +2 -2
  178. package/src/lib/agents/learned-context.ts +0 -12
  179. package/src/lib/agents/learning-session.ts +18 -5
  180. package/src/lib/agents/profiles/__tests__/list-fused-profiles.test.ts +110 -0
  181. package/src/lib/agents/profiles/__tests__/registry.test.ts +53 -4
  182. package/src/lib/agents/profiles/builtins/upgrade-assistant/SKILL.md +97 -0
  183. package/src/lib/agents/profiles/builtins/upgrade-assistant/profile.yaml +36 -0
  184. package/src/lib/agents/profiles/list-fused-profiles.ts +104 -0
  185. package/src/lib/agents/profiles/registry.ts +18 -0
  186. package/src/lib/agents/profiles/types.ts +7 -1
  187. package/src/lib/agents/router.ts +3 -6
  188. package/src/lib/agents/runtime/__tests__/catalog.test.ts +130 -0
  189. package/src/lib/agents/runtime/__tests__/execution-target.test.ts +183 -0
  190. package/src/lib/agents/runtime/__tests__/openai-codex-auth.test.ts +118 -0
  191. package/src/lib/agents/runtime/anthropic-direct.ts +8 -0
  192. package/src/lib/agents/runtime/catalog.ts +121 -0
  193. package/src/lib/agents/runtime/claude-sdk.ts +32 -0
  194. package/src/lib/agents/runtime/codex-app-server-client.ts +11 -5
  195. package/src/lib/agents/runtime/execution-target.ts +456 -0
  196. package/src/lib/agents/runtime/index.ts +4 -0
  197. package/src/lib/agents/runtime/launch-failure.ts +101 -0
  198. package/src/lib/agents/runtime/openai-codex-auth.ts +389 -0
  199. package/src/lib/agents/runtime/openai-codex.ts +64 -60
  200. package/src/lib/agents/runtime/openai-direct.ts +8 -0
  201. package/src/lib/agents/runtime/types.ts +8 -0
  202. package/src/lib/agents/task-dispatch.ts +220 -0
  203. package/src/lib/agents/tool-permissions.ts +16 -1
  204. package/src/lib/book/chapter-mapping.ts +11 -0
  205. package/src/lib/book/content.ts +10 -0
  206. package/src/lib/chat/__tests__/active-skill-injection.test.ts +261 -0
  207. package/src/lib/chat/__tests__/active-streams.test.ts +49 -0
  208. package/src/lib/chat/__tests__/clean-filter-input.test.ts +68 -0
  209. package/src/lib/chat/__tests__/command-tabs.test.ts +68 -0
  210. package/src/lib/chat/__tests__/context-builder-files.test.ts +112 -0
  211. package/src/lib/chat/__tests__/dismissals.test.ts +65 -0
  212. package/src/lib/chat/__tests__/engine-sdk-options.test.ts +117 -0
  213. package/src/lib/chat/__tests__/finalize-safety-net.test.ts +139 -0
  214. package/src/lib/chat/__tests__/reconcile.test.ts +137 -0
  215. package/src/lib/chat/__tests__/skill-conflict.test.ts +35 -0
  216. package/src/lib/chat/__tests__/stream-telemetry.test.ts +151 -0
  217. package/src/lib/chat/__tests__/types.test.ts +28 -0
  218. package/src/lib/chat/active-skills.ts +31 -0
  219. package/src/lib/chat/active-streams.ts +27 -0
  220. package/src/lib/chat/clean-filter-input.ts +30 -0
  221. package/src/lib/chat/codex-engine.ts +46 -24
  222. package/src/lib/chat/command-tabs.ts +61 -0
  223. package/src/lib/chat/context-builder.ts +146 -4
  224. package/src/lib/chat/dismissals.ts +73 -0
  225. package/src/lib/chat/engine.ts +159 -18
  226. package/src/lib/chat/files/__tests__/search.test.ts +135 -0
  227. package/src/lib/chat/files/expand-mention.ts +76 -0
  228. package/src/lib/chat/files/search.ts +99 -0
  229. package/src/lib/chat/reconcile.ts +117 -0
  230. package/src/lib/chat/skill-composition.ts +210 -0
  231. package/src/lib/chat/skill-conflict.ts +105 -0
  232. package/src/lib/chat/stagent-tools.ts +7 -19
  233. package/src/lib/chat/stream-telemetry.ts +137 -0
  234. package/src/lib/chat/suggested-prompts.ts +28 -1
  235. package/src/lib/chat/system-prompt.ts +48 -1
  236. package/src/lib/chat/tool-catalog.ts +35 -4
  237. package/src/lib/chat/tools/__tests__/enrich-table-tool.test.ts +127 -0
  238. package/src/lib/chat/tools/__tests__/profile-tools.test.ts +51 -0
  239. package/src/lib/chat/tools/__tests__/schedule-tools.test.ts +261 -0
  240. package/src/lib/chat/tools/__tests__/settings-tools.test.ts +294 -0
  241. package/src/lib/chat/tools/__tests__/skill-tools.test.ts +474 -0
  242. package/src/lib/chat/tools/__tests__/task-tools.test.ts +399 -0
  243. package/src/lib/chat/tools/__tests__/workflow-tools-dedup.test.ts +351 -0
  244. package/src/lib/chat/tools/blueprint-tools.ts +190 -0
  245. package/src/lib/chat/tools/document-tools.ts +29 -13
  246. package/src/lib/chat/tools/helpers.ts +41 -0
  247. package/src/lib/chat/tools/notification-tools.ts +9 -5
  248. package/src/lib/chat/tools/profile-tools.ts +120 -23
  249. package/src/lib/chat/tools/project-tools.ts +33 -0
  250. package/src/lib/chat/tools/schedule-tools.ts +44 -11
  251. package/src/lib/chat/tools/skill-tools.ts +183 -0
  252. package/src/lib/chat/tools/table-tools.ts +71 -0
  253. package/src/lib/chat/tools/task-tools.ts +89 -21
  254. package/src/lib/chat/tools/workflow-tools.ts +275 -32
  255. package/src/lib/chat/types.ts +15 -0
  256. package/src/lib/constants/settings.ts +10 -18
  257. package/src/lib/data/__tests__/clear.test.ts +56 -2
  258. package/src/lib/data/clear.ts +17 -16
  259. package/src/lib/data/delete-project.ts +171 -0
  260. package/src/lib/db/__tests__/bootstrap.test.ts +1 -1
  261. package/src/lib/db/bootstrap.ts +62 -16
  262. package/src/lib/db/index.ts +5 -0
  263. package/src/lib/db/migrations/0009_add_app_instances.sql +25 -0
  264. package/src/lib/db/migrations/0024_add_workflow_resume_at.sql +10 -0
  265. package/src/lib/db/migrations/0025_drop_app_instances.sql +3 -0
  266. package/src/lib/db/migrations/0026_drop_license.sql +3 -0
  267. package/src/lib/db/migrations/meta/_journal.json +21 -0
  268. package/src/lib/db/schema.ts +94 -23
  269. package/src/lib/environment/__tests__/auto-promote.test.ts +132 -0
  270. package/src/lib/environment/__tests__/list-skills-enriched.test.ts +55 -0
  271. package/src/lib/environment/__tests__/skill-enrichment.test.ts +129 -0
  272. package/src/lib/environment/__tests__/skill-recommendations.test.ts +87 -0
  273. package/src/lib/environment/data.ts +9 -0
  274. package/src/lib/environment/list-skills.ts +176 -0
  275. package/src/lib/environment/parsers/__tests__/skill.test.ts +54 -0
  276. package/src/lib/environment/parsers/skill.ts +26 -5
  277. package/src/lib/environment/profile-generator.ts +54 -0
  278. package/src/lib/environment/skill-enrichment.ts +106 -0
  279. package/src/lib/environment/skill-recommendations.ts +66 -0
  280. package/src/lib/environment/workspace-context.ts +13 -1
  281. package/src/lib/filters/__tests__/parse.quoted.test.ts +40 -0
  282. package/src/lib/filters/__tests__/parse.test.ts +135 -0
  283. package/src/lib/filters/parse.ts +86 -0
  284. package/src/lib/import/dedup.ts +4 -54
  285. package/src/lib/instance/__tests__/bootstrap.test.ts +362 -0
  286. package/src/lib/instance/__tests__/detect.test.ts +115 -0
  287. package/src/lib/instance/__tests__/fingerprint.test.ts +48 -0
  288. package/src/lib/instance/__tests__/git-ops.test.ts +95 -0
  289. package/src/lib/instance/__tests__/settings.test.ts +83 -0
  290. package/src/lib/instance/__tests__/upgrade-poller.test.ts +181 -0
  291. package/src/lib/instance/bootstrap.ts +270 -0
  292. package/src/lib/instance/detect.ts +49 -0
  293. package/src/lib/instance/fingerprint.ts +76 -0
  294. package/src/lib/instance/git-ops.ts +95 -0
  295. package/src/lib/instance/settings.ts +61 -0
  296. package/src/lib/instance/types.ts +77 -0
  297. package/src/lib/instance/upgrade-poller.ts +205 -0
  298. package/src/lib/notifications/__tests__/visibility.test.ts +51 -0
  299. package/src/lib/notifications/visibility.ts +33 -0
  300. package/src/lib/schedules/__tests__/collision-check.test.ts +93 -0
  301. package/src/lib/schedules/__tests__/config.test.ts +62 -0
  302. package/src/lib/schedules/__tests__/firing-metrics.test.ts +99 -0
  303. package/src/lib/schedules/__tests__/integration.test.ts +82 -0
  304. package/src/lib/schedules/__tests__/slot-claim.test.ts +242 -0
  305. package/src/lib/schedules/__tests__/tick-scheduler.test.ts +102 -0
  306. package/src/lib/schedules/__tests__/turn-budget.test.ts +228 -0
  307. package/src/lib/schedules/collision-check.ts +105 -0
  308. package/src/lib/schedules/config.ts +53 -0
  309. package/src/lib/schedules/scheduler.ts +236 -17
  310. package/src/lib/schedules/slot-claim.ts +105 -0
  311. package/src/lib/settings/__tests__/openai-auth.test.ts +101 -0
  312. package/src/lib/settings/__tests__/openai-login-manager.test.ts +64 -0
  313. package/src/lib/settings/__tests__/runtime-setup.test.ts +33 -0
  314. package/src/lib/settings/openai-auth.ts +105 -10
  315. package/src/lib/settings/openai-login-manager.ts +260 -0
  316. package/src/lib/settings/runtime-setup.ts +14 -4
  317. package/src/lib/tables/__tests__/enrichment-planner.test.ts +124 -0
  318. package/src/lib/tables/__tests__/enrichment.test.ts +147 -0
  319. package/src/lib/tables/enrichment-planner.ts +454 -0
  320. package/src/lib/tables/enrichment.ts +328 -0
  321. package/src/lib/tables/query-builder.ts +5 -2
  322. package/src/lib/tables/trigger-evaluator.ts +3 -2
  323. package/src/lib/theme.ts +71 -0
  324. package/src/lib/usage/ledger.ts +2 -18
  325. package/src/lib/util/__tests__/similarity.test.ts +106 -0
  326. package/src/lib/util/similarity.ts +77 -0
  327. package/src/lib/utils/format-timestamp.ts +24 -0
  328. package/src/lib/utils/stagent-paths.ts +12 -0
  329. package/src/lib/validators/__tests__/blueprint.test.ts +172 -0
  330. package/src/lib/validators/__tests__/settings.test.ts +10 -0
  331. package/src/lib/validators/blueprint.ts +70 -9
  332. package/src/lib/validators/profile.ts +2 -2
  333. package/src/lib/validators/settings.ts +3 -1
  334. package/src/lib/workflows/__tests__/delay.test.ts +196 -0
  335. package/src/lib/workflows/__tests__/engine.test.ts +8 -0
  336. package/src/lib/workflows/__tests__/loop-executor.test.ts +54 -0
  337. package/src/lib/workflows/__tests__/post-action.test.ts +108 -0
  338. package/src/lib/workflows/blueprints/__tests__/render-prompt.test.ts +124 -0
  339. package/src/lib/workflows/blueprints/instantiator.ts +22 -1
  340. package/src/lib/workflows/blueprints/render-prompt.ts +71 -0
  341. package/src/lib/workflows/blueprints/types.ts +16 -2
  342. package/src/lib/workflows/delay.ts +106 -0
  343. package/src/lib/workflows/engine.ts +212 -7
  344. package/src/lib/workflows/loop-executor.ts +349 -24
  345. package/src/lib/workflows/post-action.ts +91 -0
  346. package/src/lib/workflows/types.ts +166 -1
  347. package/src/test/setup.ts +10 -0
  348. package/src/app/api/license/checkout/route.ts +0 -28
  349. package/src/app/api/license/portal/route.ts +0 -26
  350. package/src/app/api/license/route.ts +0 -89
  351. package/src/app/api/license/usage/route.ts +0 -63
  352. package/src/app/api/marketplace/browse/route.ts +0 -15
  353. package/src/app/api/marketplace/import/route.ts +0 -28
  354. package/src/app/api/marketplace/publish/route.ts +0 -40
  355. package/src/app/api/onboarding/email/route.ts +0 -53
  356. package/src/app/api/settings/telemetry/route.ts +0 -14
  357. package/src/app/api/sync/export/route.ts +0 -54
  358. package/src/app/api/sync/restore/route.ts +0 -37
  359. package/src/app/api/sync/sessions/route.ts +0 -24
  360. package/src/app/auth/callback/route.ts +0 -73
  361. package/src/app/marketplace/page.tsx +0 -19
  362. package/src/components/analytics/analytics-gate-card.tsx +0 -101
  363. package/src/components/marketplace/blueprint-card.tsx +0 -61
  364. package/src/components/marketplace/marketplace-browser.tsx +0 -131
  365. package/src/components/onboarding/email-capture-card.tsx +0 -104
  366. package/src/components/settings/activation-form.tsx +0 -95
  367. package/src/components/settings/cloud-account-section.tsx +0 -147
  368. package/src/components/settings/cloud-sync-section.tsx +0 -155
  369. package/src/components/settings/subscription-section.tsx +0 -410
  370. package/src/components/settings/telemetry-section.tsx +0 -80
  371. package/src/components/shared/premium-gate-overlay.tsx +0 -50
  372. package/src/components/shared/schedule-gate-dialog.tsx +0 -64
  373. package/src/components/shared/upgrade-banner.tsx +0 -112
  374. package/src/hooks/use-supabase-auth.ts +0 -79
  375. package/src/lib/billing/email.ts +0 -54
  376. package/src/lib/billing/products.ts +0 -80
  377. package/src/lib/billing/stripe.ts +0 -101
  378. package/src/lib/cloud/supabase-browser.ts +0 -32
  379. package/src/lib/cloud/supabase-client.ts +0 -56
  380. package/src/lib/license/__tests__/features.test.ts +0 -56
  381. package/src/lib/license/__tests__/key-format.test.ts +0 -88
  382. package/src/lib/license/__tests__/manager.test.ts +0 -64
  383. package/src/lib/license/__tests__/tier-limits.test.ts +0 -79
  384. package/src/lib/license/cloud-validation.ts +0 -60
  385. package/src/lib/license/features.ts +0 -44
  386. package/src/lib/license/key-format.ts +0 -101
  387. package/src/lib/license/limit-check.ts +0 -111
  388. package/src/lib/license/limit-queries.ts +0 -51
  389. package/src/lib/license/manager.ts +0 -345
  390. package/src/lib/license/notifications.ts +0 -59
  391. package/src/lib/license/tier-limits.ts +0 -71
  392. package/src/lib/marketplace/marketplace-client.ts +0 -107
  393. package/src/lib/sync/cloud-sync.ts +0 -235
  394. package/src/lib/telemetry/conversion-events.ts +0 -71
  395. package/src/lib/telemetry/queue.ts +0 -122
  396. package/src/lib/validators/license.ts +0 -33
@@ -25,7 +25,6 @@ import {
25
25
  channelBindings,
26
26
  channelConfigs,
27
27
  agentMessages,
28
- license,
29
28
  workflowDocumentInputs,
30
29
  scheduleDocumentInputs,
31
30
  projectDocumentDefaults,
@@ -43,6 +42,7 @@ import {
43
42
  workflowTableInputs,
44
43
  scheduleTableInputs,
45
44
  workflowExecutionStats,
45
+ scheduleFiringMetrics,
46
46
  } from "@/lib/db/schema";
47
47
  import { readdirSync, unlinkSync, mkdirSync } from "fs";
48
48
  import { join } from "path";
@@ -55,7 +55,8 @@ const screenshotsDir = join(dataDir, "screenshots");
55
55
 
56
56
  /**
57
57
  * Wipe all data tables (FK-safe order) and uploaded files.
58
- * Preserves the settings table (auth config).
58
+ * Preserves the settings table (auth config) — clearing operational
59
+ * data should never silently reset user auth preferences.
59
60
  */
60
61
  export function clearAllData() {
61
62
  const sampleProfilesDeleted = clearSampleProfiles();
@@ -68,7 +69,18 @@ export function clearAllData() {
68
69
  const envScansDeleted = db.delete(environmentScans).run().changes;
69
70
  const envTemplatesDeleted = db.delete(environmentTemplates).run().changes;
70
71
 
71
- // Chat tables (messages before conversations FK safety)
72
+ // Document junction tables delete before documents (they reference documents).
73
+ // Also referenced by projects/workflows/schedules, deleted later.
74
+ const workflowDocInputsDeleted = db.delete(workflowDocumentInputs).run().changes;
75
+ const scheduleDocInputsDeleted = db.delete(scheduleDocumentInputs).run().changes;
76
+ const projectDocDefaultsDeleted = db.delete(projectDocumentDefaults).run().changes;
77
+ // Documents reference conversations (documents.conversation_id) — must delete
78
+ // before conversations to avoid FK violation when chat-attached documents exist.
79
+ const documentsDeleted = db.delete(documents).run().changes;
80
+
81
+ // Chat tables: channel_bindings + chat_messages + documents all reference
82
+ // conversations — delete them before conversations.
83
+ const channelBindingsDeleted = db.delete(channelBindings).run().changes;
72
84
  const chatMessagesDeleted = db.delete(chatMessages).run().changes;
73
85
  const conversationsDeleted = db.delete(conversations).run().changes;
74
86
 
@@ -76,16 +88,10 @@ export function clearAllData() {
76
88
  const bookmarksDeleted = db.delete(bookmarks).run().changes;
77
89
  const readingProgressDeleted = db.delete(readingProgress).run().changes;
78
90
 
79
- // Channel bindings reference channel_configs + conversations — delete before both
80
- const channelBindingsDeleted = db.delete(channelBindings).run().changes;
81
-
82
91
  // Agent messages reference tasks — delete before tasks
83
92
  const agentMessagesDeleted = db.delete(agentMessages).run().changes;
84
93
  const channelConfigsDeleted = db.delete(channelConfigs).run().changes;
85
94
 
86
- // License table — no FK dependencies
87
- const licenseDeleted = db.delete(license).run().changes;
88
-
89
95
  // Snapshots are intentionally preserved — they are backups, not working data
90
96
 
91
97
  const repoImportsDeleted = db.delete(repoImports).run().changes;
@@ -112,17 +118,12 @@ export function clearAllData() {
112
118
  const userTablesDeleted = db.delete(userTables).run().changes;
113
119
  const userTableTemplatesDeleted = db.delete(userTableTemplates).run().changes;
114
120
 
115
- // Document junction tables — delete before documents, workflows, schedules, projects
116
- const workflowDocInputsDeleted = db.delete(workflowDocumentInputs).run().changes;
117
- const scheduleDocInputsDeleted = db.delete(scheduleDocumentInputs).run().changes;
118
- const projectDocDefaultsDeleted = db.delete(projectDocumentDefaults).run().changes;
119
-
120
- const documentsDeleted = db.delete(documents).run().changes;
121
121
  const agentMemoryDeleted = db.delete(agentMemory).run().changes;
122
122
  const learnedContextDeleted = db.delete(learnedContext).run().changes;
123
123
  const executionStatsDeleted = db.delete(workflowExecutionStats).run().changes;
124
124
  const tasksDeleted = db.delete(tasks).run().changes;
125
125
  const workflowsDeleted = db.delete(workflows).run().changes;
126
+ const scheduleFiringMetricsDeleted = db.delete(scheduleFiringMetrics).run().changes;
126
127
  const schedulesDeleted = db.delete(schedules).run().changes;
127
128
  const projectsDeleted = db.delete(projects).run().changes;
128
129
 
@@ -156,6 +157,7 @@ export function clearAllData() {
156
157
  projects: projectsDeleted,
157
158
  tasks: tasksDeleted,
158
159
  workflows: workflowsDeleted,
160
+ scheduleFiringMetrics: scheduleFiringMetricsDeleted,
159
161
  schedules: schedulesDeleted,
160
162
  usageLedger: usageLedgerDeleted,
161
163
  agentLogs: logsDeleted,
@@ -195,7 +197,6 @@ export function clearAllData() {
195
197
  scheduleTableInputs: scheduleTableInputsDeleted,
196
198
  files: filesDeleted,
197
199
  screenshots: screenshotsDeleted,
198
- license: licenseDeleted,
199
200
  workflowExecutionStats: executionStatsDeleted,
200
201
  };
201
202
  }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * FK-safe cascade delete for a project and all its children.
3
+ * Shared by the API DELETE route and the delete_project chat tool.
4
+ */
5
+
6
+ import { db } from "@/lib/db";
7
+ import {
8
+ projects,
9
+ tasks,
10
+ workflows,
11
+ documents,
12
+ schedules,
13
+ agentLogs,
14
+ notifications,
15
+ learnedContext,
16
+ usageLedger,
17
+ environmentSyncOps,
18
+ environmentCheckpoints,
19
+ environmentArtifacts,
20
+ environmentScans,
21
+ chatMessages,
22
+ conversations,
23
+ projectDocumentDefaults,
24
+ userTables,
25
+ userTableColumns,
26
+ userTableRows,
27
+ userTableViews,
28
+ userTableImports,
29
+ userTableRelationships,
30
+ tableDocumentInputs,
31
+ taskTableInputs,
32
+ workflowTableInputs,
33
+ scheduleTableInputs,
34
+ userTableTriggers,
35
+ userTableRowHistory,
36
+ } from "@/lib/db/schema";
37
+ import { eq, inArray } from "drizzle-orm";
38
+
39
+ /**
40
+ * Delete a project and all FK-dependent children in safe order.
41
+ * Returns true if the project existed and was deleted, false if not found.
42
+ */
43
+ export function deleteProjectCascade(projectId: string): boolean {
44
+ const existing = db
45
+ .select({ id: projects.id })
46
+ .from(projects)
47
+ .where(eq(projects.id, projectId))
48
+ .get();
49
+
50
+ if (!existing) return false;
51
+
52
+ // 1. Collect child IDs for nested FK chains
53
+ const taskIds = db
54
+ .select({ id: tasks.id })
55
+ .from(tasks)
56
+ .where(eq(tasks.projectId, projectId))
57
+ .all()
58
+ .map((r) => r.id);
59
+
60
+ const workflowIds = db
61
+ .select({ id: workflows.id })
62
+ .from(workflows)
63
+ .where(eq(workflows.projectId, projectId))
64
+ .all()
65
+ .map((r) => r.id);
66
+
67
+ const conversationIds = db
68
+ .select({ id: conversations.id })
69
+ .from(conversations)
70
+ .where(eq(conversations.projectId, projectId))
71
+ .all()
72
+ .map((r) => r.id);
73
+
74
+ const scanIds = db
75
+ .select({ id: environmentScans.id })
76
+ .from(environmentScans)
77
+ .where(eq(environmentScans.projectId, projectId))
78
+ .all()
79
+ .map((r) => r.id);
80
+
81
+ const checkpointIds = db
82
+ .select({ id: environmentCheckpoints.id })
83
+ .from(environmentCheckpoints)
84
+ .where(eq(environmentCheckpoints.projectId, projectId))
85
+ .all()
86
+ .map((r) => r.id);
87
+
88
+ // 2. Environment tables (deepest children first)
89
+ if (checkpointIds.length > 0) {
90
+ db.delete(environmentSyncOps)
91
+ .where(inArray(environmentSyncOps.checkpointId, checkpointIds))
92
+ .run();
93
+ db.delete(environmentCheckpoints)
94
+ .where(inArray(environmentCheckpoints.id, checkpointIds))
95
+ .run();
96
+ }
97
+ if (scanIds.length > 0) {
98
+ db.delete(environmentArtifacts)
99
+ .where(inArray(environmentArtifacts.scanId, scanIds))
100
+ .run();
101
+ db.delete(environmentScans)
102
+ .where(inArray(environmentScans.id, scanIds))
103
+ .run();
104
+ }
105
+
106
+ // 3. Chat tables (messages before conversations)
107
+ if (conversationIds.length > 0) {
108
+ db.delete(chatMessages)
109
+ .where(inArray(chatMessages.conversationId, conversationIds))
110
+ .run();
111
+ db.delete(conversations)
112
+ .where(inArray(conversations.id, conversationIds))
113
+ .run();
114
+ }
115
+
116
+ // 4. Usage ledger
117
+ db.delete(usageLedger).where(eq(usageLedger.projectId, projectId)).run();
118
+
119
+ // 5. Task children (logs, notifications, documents, learned context)
120
+ if (taskIds.length > 0) {
121
+ db.delete(agentLogs).where(inArray(agentLogs.taskId, taskIds)).run();
122
+ db.delete(notifications)
123
+ .where(inArray(notifications.taskId, taskIds))
124
+ .run();
125
+ db.delete(documents).where(inArray(documents.taskId, taskIds)).run();
126
+ db.delete(learnedContext)
127
+ .where(inArray(learnedContext.sourceTaskId, taskIds))
128
+ .run();
129
+ }
130
+
131
+ // 6. Junction tables
132
+ db.delete(projectDocumentDefaults).where(eq(projectDocumentDefaults.projectId, projectId)).run();
133
+
134
+ // 6b. User-defined tables — cascade-delete children before parent
135
+ const tableIds = db
136
+ .select({ id: userTables.id })
137
+ .from(userTables)
138
+ .where(eq(userTables.projectId, projectId))
139
+ .all()
140
+ .map((r) => r.id);
141
+
142
+ if (tableIds.length > 0) {
143
+ // Junction tables first
144
+ db.delete(tableDocumentInputs).where(inArray(tableDocumentInputs.tableId, tableIds)).run();
145
+ db.delete(taskTableInputs).where(inArray(taskTableInputs.tableId, tableIds)).run();
146
+ db.delete(workflowTableInputs).where(inArray(workflowTableInputs.tableId, tableIds)).run();
147
+ db.delete(scheduleTableInputs).where(inArray(scheduleTableInputs.tableId, tableIds)).run();
148
+ // Children
149
+ db.delete(userTableRowHistory).where(inArray(userTableRowHistory.tableId, tableIds)).run();
150
+ db.delete(userTableTriggers).where(inArray(userTableTriggers.tableId, tableIds)).run();
151
+ db.delete(userTableImports).where(inArray(userTableImports.tableId, tableIds)).run();
152
+ db.delete(userTableViews).where(inArray(userTableViews.tableId, tableIds)).run();
153
+ db.delete(userTableRelationships).where(inArray(userTableRelationships.fromTableId, tableIds)).run();
154
+ db.delete(userTableRows).where(inArray(userTableRows.tableId, tableIds)).run();
155
+ db.delete(userTableColumns).where(inArray(userTableColumns.tableId, tableIds)).run();
156
+ db.delete(userTables).where(inArray(userTables.id, tableIds)).run();
157
+ }
158
+
159
+ // 7. Direct project children
160
+ db.delete(documents).where(eq(documents.projectId, projectId)).run();
161
+ db.delete(tasks).where(eq(tasks.projectId, projectId)).run();
162
+ if (workflowIds.length > 0) {
163
+ db.delete(workflows).where(inArray(workflows.id, workflowIds)).run();
164
+ }
165
+ db.delete(schedules).where(eq(schedules.projectId, projectId)).run();
166
+
167
+ // 8. Finally delete the project
168
+ db.delete(projects).where(eq(projects.id, projectId)).run();
169
+
170
+ return true;
171
+ }
@@ -50,7 +50,7 @@ describe("database bootstrap recovery", () => {
50
50
  const migrationCount = migratedDb
51
51
  .prepare("SELECT COUNT(*) AS count FROM __drizzle_migrations")
52
52
  .get() as { count: number };
53
- expect(migrationCount.count).toBe(9);
53
+ expect(migrationCount.count).toBe(12);
54
54
  migratedDb.close();
55
55
  });
56
56
  });
@@ -45,8 +45,8 @@ const STAGENT_TABLES = [
45
45
  "user_table_triggers",
46
46
  "user_table_row_history",
47
47
  "snapshots",
48
- "license",
49
48
  "workflow_execution_stats",
49
+ "schedule_firing_metrics",
50
50
  ] as const;
51
51
 
52
52
  export function bootstrapStagentDatabase(sqlite: Database.Database): void {
@@ -70,6 +70,9 @@ export function bootstrapStagentDatabase(sqlite: Database.Database): void {
70
70
  status TEXT DEFAULT 'planned' NOT NULL,
71
71
  assigned_agent TEXT,
72
72
  agent_profile TEXT,
73
+ effective_runtime_id TEXT,
74
+ effective_model_id TEXT,
75
+ runtime_fallback_reason TEXT,
73
76
  priority INTEGER DEFAULT 2 NOT NULL,
74
77
  result TEXT,
75
78
  session_id TEXT,
@@ -91,6 +94,7 @@ export function bootstrapStagentDatabase(sqlite: Database.Database): void {
91
94
  status TEXT DEFAULT 'draft' NOT NULL,
92
95
  run_number INTEGER DEFAULT 0 NOT NULL,
93
96
  runtime_id TEXT,
97
+ resume_at INTEGER,
94
98
  created_at INTEGER NOT NULL,
95
99
  updated_at INTEGER NOT NULL,
96
100
  FOREIGN KEY (project_id) REFERENCES projects(id) ON UPDATE NO ACTION ON DELETE NO ACTION
@@ -192,6 +196,32 @@ export function bootstrapStagentDatabase(sqlite: Database.Database): void {
192
196
  CREATE INDEX IF NOT EXISTS idx_schedules_next_fire_at ON schedules(next_fire_at);
193
197
  CREATE INDEX IF NOT EXISTS idx_schedules_project_id ON schedules(project_id);
194
198
 
199
+ -- schedule_firing_metrics is placed here (between schedules indexes and
200
+ -- notifications indexes) to satisfy its foreign-key dependency on schedules.
201
+ -- Future tables with FK dependencies should follow the same "place after
202
+ -- parent table" discipline rather than batching all CREATE TABLE at the top.
203
+ CREATE TABLE IF NOT EXISTS schedule_firing_metrics (
204
+ id TEXT PRIMARY KEY NOT NULL,
205
+ schedule_id TEXT NOT NULL,
206
+ task_id TEXT,
207
+ fired_at INTEGER NOT NULL,
208
+ slot_claimed_at INTEGER,
209
+ completed_at INTEGER,
210
+ slot_wait_ms INTEGER,
211
+ duration_ms INTEGER,
212
+ turn_count INTEGER,
213
+ max_turns_at_firing INTEGER,
214
+ event_loop_lag_ms REAL,
215
+ peak_rss_mb INTEGER,
216
+ chat_streams_active INTEGER,
217
+ concurrent_schedules INTEGER,
218
+ failure_reason TEXT,
219
+ FOREIGN KEY (schedule_id) REFERENCES schedules(id) ON UPDATE NO ACTION ON DELETE NO ACTION,
220
+ FOREIGN KEY (task_id) REFERENCES tasks(id) ON UPDATE NO ACTION ON DELETE NO ACTION
221
+ );
222
+
223
+ CREATE INDEX IF NOT EXISTS idx_sfm_schedule_time ON schedule_firing_metrics(schedule_id, fired_at);
224
+
195
225
  CREATE INDEX IF NOT EXISTS idx_notifications_task_id ON notifications(task_id);
196
226
  CREATE INDEX IF NOT EXISTS idx_notifications_read ON notifications(read);
197
227
  CREATE INDEX IF NOT EXISTS idx_documents_task_id ON documents(task_id);
@@ -260,6 +290,7 @@ export function bootstrapStagentDatabase(sqlite: Database.Database): void {
260
290
 
261
291
  CREATE INDEX IF NOT EXISTS idx_views_surface ON views(surface);
262
292
  CREATE INDEX IF NOT EXISTS idx_views_surface_default ON views(surface, is_default);
293
+
263
294
  `);
264
295
 
265
296
  const addColumnIfMissing = (ddl: string) => {
@@ -275,6 +306,9 @@ export function bootstrapStagentDatabase(sqlite: Database.Database): void {
275
306
 
276
307
  addColumnIfMissing(`ALTER TABLE tasks ADD COLUMN agent_profile TEXT;`);
277
308
  sqlite.exec(`CREATE INDEX IF NOT EXISTS idx_tasks_agent_profile ON tasks(agent_profile);`);
309
+ addColumnIfMissing(`ALTER TABLE tasks ADD COLUMN effective_runtime_id TEXT;`);
310
+ addColumnIfMissing(`ALTER TABLE tasks ADD COLUMN effective_model_id TEXT;`);
311
+ addColumnIfMissing(`ALTER TABLE tasks ADD COLUMN runtime_fallback_reason TEXT;`);
278
312
 
279
313
  addColumnIfMissing(`ALTER TABLE tasks ADD COLUMN workflow_id TEXT REFERENCES workflows(id);`);
280
314
  sqlite.exec(`CREATE INDEX IF NOT EXISTS idx_tasks_workflow_id ON tasks(workflow_id);`);
@@ -305,6 +339,19 @@ export function bootstrapStagentDatabase(sqlite: Database.Database): void {
305
339
  addColumnIfMissing(`ALTER TABLE documents ADD COLUMN source TEXT DEFAULT 'upload';`);
306
340
  addColumnIfMissing(`ALTER TABLE documents ADD COLUMN conversation_id TEXT REFERENCES conversations(id);`);
307
341
  addColumnIfMissing(`ALTER TABLE documents ADD COLUMN message_id TEXT;`);
342
+ // chat-ollama-native-skills: conversation-scoped active skill binding.
343
+ // Ollama can't use the SDK's native skill support, so we inject the
344
+ // selected skill's SKILL.md into Tier 0 of the system prompt on every
345
+ // turn while this column is set. Same machinery is usable from Claude
346
+ // and Codex as a programmatic skill-activation path.
347
+ addColumnIfMissing(`ALTER TABLE conversations ADD COLUMN active_skill_id TEXT;`);
348
+ // chat-skill-composition v1: array of additionally-activated skill IDs
349
+ // beyond the legacy active_skill_id. Default empty JSON array.
350
+ addColumnIfMissing(`ALTER TABLE conversations ADD COLUMN active_skill_ids TEXT DEFAULT '[]';`);
351
+ // Workflow step delays — resume_at for schedule-based delay resumption.
352
+ // The partial index on resume_at is created by migration 0024 for fresh DBs;
353
+ // existing DBs that don't run migrations will do a small table scan instead.
354
+ addColumnIfMissing(`ALTER TABLE workflows ADD COLUMN resume_at INTEGER;`);
308
355
  sqlite.exec(`CREATE INDEX IF NOT EXISTS idx_documents_source ON documents(source);`);
309
356
  sqlite.exec(`CREATE INDEX IF NOT EXISTS idx_documents_conversation_id ON documents(conversation_id);`);
310
357
 
@@ -423,6 +470,8 @@ export function bootstrapStagentDatabase(sqlite: Database.Database): void {
423
470
  status TEXT DEFAULT 'active' NOT NULL,
424
471
  session_id TEXT,
425
472
  context_scope TEXT,
473
+ active_skill_id TEXT,
474
+ active_skill_ids TEXT DEFAULT '[]',
426
475
  created_at INTEGER NOT NULL,
427
476
  updated_at INTEGER NOT NULL,
428
477
  FOREIGN KEY (project_id) REFERENCES projects(id) ON UPDATE NO ACTION ON DELETE NO ACTION
@@ -552,6 +601,18 @@ export function bootstrapStagentDatabase(sqlite: Database.Database): void {
552
601
  addColumnIfMissing(`ALTER TABLE schedules ADD COLUMN last_failure_reason TEXT;`);
553
602
  addColumnIfMissing(`ALTER TABLE channel_configs ADD COLUMN direction TEXT DEFAULT 'outbound' NOT NULL;`);
554
603
 
604
+ // ── Schedule Orchestration columns ───────────────────────────────────────
605
+ addColumnIfMissing(`ALTER TABLE tasks ADD COLUMN slot_claimed_at INTEGER;`);
606
+ addColumnIfMissing(`ALTER TABLE tasks ADD COLUMN lease_expires_at INTEGER;`);
607
+ addColumnIfMissing(`ALTER TABLE tasks ADD COLUMN failure_reason TEXT;`);
608
+ addColumnIfMissing(`ALTER TABLE tasks ADD COLUMN max_turns INTEGER;`);
609
+ addColumnIfMissing(`ALTER TABLE schedules ADD COLUMN max_turns INTEGER;`);
610
+ addColumnIfMissing(`ALTER TABLE schedules ADD COLUMN max_turns_set_at INTEGER;`);
611
+ addColumnIfMissing(`ALTER TABLE schedules ADD COLUMN max_run_duration_sec INTEGER;`);
612
+ addColumnIfMissing(`ALTER TABLE schedules ADD COLUMN turn_budget_breach_streak INTEGER DEFAULT 0 NOT NULL;`);
613
+ // Create the composite index for lease-reaper queries (idempotent)
614
+ sqlite.exec(`CREATE INDEX IF NOT EXISTS idx_tasks_running_scheduled ON tasks(status, source_type, lease_expires_at);`);
615
+
555
616
  // ── Bidirectional Channel Chat ──────────────────────────────────────────
556
617
  sqlite.exec(`
557
618
  CREATE TABLE IF NOT EXISTS channel_bindings (
@@ -856,21 +917,6 @@ export function bootstrapStagentDatabase(sqlite: Database.Database): void {
856
917
  CREATE INDEX IF NOT EXISTS idx_snapshots_type ON snapshots(type);
857
918
  CREATE INDEX IF NOT EXISTS idx_snapshots_created_at ON snapshots(created_at);
858
919
 
859
- CREATE TABLE IF NOT EXISTS license (
860
- id TEXT PRIMARY KEY NOT NULL,
861
- supabase_user_id TEXT,
862
- tier TEXT DEFAULT 'community' NOT NULL,
863
- status TEXT DEFAULT 'inactive' NOT NULL,
864
- email TEXT,
865
- activated_at INTEGER,
866
- expires_at INTEGER,
867
- last_validated_at INTEGER,
868
- grace_period_expires_at INTEGER,
869
- encrypted_token TEXT,
870
- created_at INTEGER NOT NULL,
871
- updated_at INTEGER NOT NULL
872
- );
873
-
874
920
  CREATE TABLE IF NOT EXISTS workflow_execution_stats (
875
921
  id TEXT PRIMARY KEY,
876
922
  pattern TEXT NOT NULL,
@@ -13,6 +13,11 @@ const dbPath = join(dataDir, "stagent.db");
13
13
  const sqlite = new Database(dbPath);
14
14
  sqlite.pragma("journal_mode = WAL");
15
15
  sqlite.pragma("foreign_keys = ON");
16
+
17
+ // Bootstrap creates tables with IF NOT EXISTS + adds columns.
18
+ // Drizzle migrations (DROP TABLE, CREATE INDEX, etc.) run separately
19
+ // at server startup in instrumentation-node.ts to avoid SQLITE_BUSY
20
+ // conflicts during next build.
16
21
  bootstrapStagentDatabase(sqlite);
17
22
 
18
23
  export const db = drizzle(sqlite, { schema });
@@ -0,0 +1,25 @@
1
+ -- Historical migration: app_instances table (removed in 0025).
2
+ -- Kept for Drizzle journal compatibility.
3
+ CREATE TABLE IF NOT EXISTS app_instances (
4
+ id TEXT PRIMARY KEY NOT NULL,
5
+ app_id TEXT NOT NULL,
6
+ name TEXT NOT NULL,
7
+ version TEXT NOT NULL,
8
+ project_id TEXT,
9
+ manifest_json TEXT NOT NULL,
10
+ ui_schema_json TEXT NOT NULL,
11
+ resource_map_json TEXT DEFAULT '{}' NOT NULL,
12
+ status TEXT DEFAULT 'installing' NOT NULL,
13
+ source_type TEXT DEFAULT 'builtin' NOT NULL,
14
+ bootstrap_error TEXT,
15
+ installed_at INTEGER NOT NULL,
16
+ bootstrapped_at INTEGER,
17
+ updated_at INTEGER NOT NULL,
18
+ FOREIGN KEY (project_id) REFERENCES projects(id) ON UPDATE NO ACTION ON DELETE NO ACTION
19
+ );
20
+ --> statement-breakpoint
21
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_app_instances_app_id ON app_instances(app_id);
22
+ --> statement-breakpoint
23
+ CREATE INDEX IF NOT EXISTS idx_app_instances_project_id ON app_instances(project_id);
24
+ --> statement-breakpoint
25
+ CREATE INDEX IF NOT EXISTS idx_app_instances_status ON app_instances(status);
@@ -0,0 +1,10 @@
1
+ -- Workflow Step Delays — Track A.2
2
+ -- Adds resume_at timestamp column to workflows for schedule-based delay resumption.
3
+ -- When a workflow pauses at a delay step, it writes resume_at = now + delayDuration.
4
+ -- The scheduler tick queries WHERE status='paused' AND resume_at <= now() to find due workflows.
5
+ -- Partial index keeps the query cheap: only paused workflows with a pending resume are indexed.
6
+
7
+ ALTER TABLE workflows ADD COLUMN resume_at INTEGER;
8
+ CREATE INDEX IF NOT EXISTS idx_workflows_resume_at
9
+ ON workflows(resume_at)
10
+ WHERE resume_at IS NOT NULL;
@@ -0,0 +1,3 @@
1
+ -- Remove the deprecated app_instances table.
2
+ -- IF EXISTS guards against fresh databases that never had this table.
3
+ DROP TABLE IF EXISTS app_instances;
@@ -0,0 +1,3 @@
1
+ -- Remove the license table (Community Edition simplification).
2
+ -- IF EXISTS guards against fresh databases that never had this table.
3
+ DROP TABLE IF EXISTS license;
@@ -64,6 +64,27 @@
64
64
  "when": 1773705600000,
65
65
  "tag": "0008_add_document_version",
66
66
  "breakpoints": true
67
+ },
68
+ {
69
+ "idx": 9,
70
+ "version": "7",
71
+ "when": 1775779200000,
72
+ "tag": "0009_add_app_instances",
73
+ "breakpoints": true
74
+ },
75
+ {
76
+ "idx": 10,
77
+ "version": "7",
78
+ "when": 1776470400000,
79
+ "tag": "0025_drop_app_instances",
80
+ "breakpoints": true
81
+ },
82
+ {
83
+ "idx": 11,
84
+ "version": "7",
85
+ "when": 1776556800000,
86
+ "tag": "0026_drop_license",
87
+ "breakpoints": true
67
88
  }
68
89
  ]
69
90
  }