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,6 +25,7 @@ import {
25
25
  importRows,
26
26
  createImportRecord,
27
27
  } from "@/lib/tables/import";
28
+ import { createEnrichmentWorkflow } from "@/lib/tables/enrichment";
28
29
  import type { ColumnDef } from "@/lib/tables/types";
29
30
 
30
31
  export function tableTools(ctx: ToolContext) {
@@ -301,6 +302,76 @@ export function tableTools(ctx: ToolContext) {
301
302
  }
302
303
  ),
303
304
 
305
+ // ── Bulk row enrichment ──────────────────────────────────────────
306
+
307
+ defineTool(
308
+ "enrich_table",
309
+ `Bulk-enrich rows in a user table by running an agent task per row and writing the result back to a target column. Creates a row-driven loop workflow that fans out one task per matching row.
310
+
311
+ The prompt may reference row fields with {{row.fieldName}} placeholders — they are passed to the agent as JSON context. To skip a row at agent-time, return the literal string "NOT_FOUND". Already-populated rows (target column has a non-empty value) are skipped automatically for idempotency.
312
+
313
+ Returns the workflowId so the caller can poll status, plus the rowCount that will actually be processed.`,
314
+ {
315
+ tableId: z.string().describe("Table ID to enrich"),
316
+ prompt: z
317
+ .string()
318
+ .min(1)
319
+ .max(8192)
320
+ .describe(
321
+ "Per-row prompt template. Use {{row.fieldName}} to reference row fields. Instruct the agent to return NOT_FOUND when no value can be determined."
322
+ ),
323
+ targetColumn: z
324
+ .string()
325
+ .min(1)
326
+ .describe("Column name to write the agent's result into"),
327
+ filter: z
328
+ .object({
329
+ column: z.string(),
330
+ operator: z.enum([
331
+ "eq", "neq", "gt", "gte", "lt", "lte",
332
+ "contains", "starts_with", "in", "is_empty", "is_not_empty",
333
+ ]),
334
+ value: z
335
+ .union([z.string(), z.number(), z.boolean(), z.array(z.string())])
336
+ .optional(),
337
+ })
338
+ .optional()
339
+ .describe(
340
+ "Optional row filter — typically {column: targetColumn, operator: 'is_empty'} to enrich only blank cells"
341
+ ),
342
+ agentProfile: z
343
+ .string()
344
+ .optional()
345
+ .describe("Agent profile to use (defaults to 'sales-researcher')"),
346
+ projectId: z
347
+ .string()
348
+ .optional()
349
+ .describe("Project ID. Omit to use the active project."),
350
+ batchSize: z
351
+ .number()
352
+ .int()
353
+ .min(1)
354
+ .optional()
355
+ .describe("Maximum rows to process in this run (default 50, capped at 200)"),
356
+ },
357
+ async (args) => {
358
+ try {
359
+ const effectiveProjectId = args.projectId ?? ctx.projectId ?? undefined;
360
+ const result = await createEnrichmentWorkflow(args.tableId, {
361
+ prompt: args.prompt,
362
+ targetColumn: args.targetColumn,
363
+ filter: args.filter,
364
+ agentProfile: args.agentProfile,
365
+ projectId: effectiveProjectId,
366
+ batchSize: args.batchSize,
367
+ });
368
+ return ok(result);
369
+ } catch (e) {
370
+ return err(e instanceof Error ? e.message : "Failed to start enrichment");
371
+ }
372
+ }
373
+ ),
374
+
304
375
  // ── Creation operations ──────────────────────────────────────────
305
376
 
306
377
  defineTool(
@@ -3,12 +3,13 @@ import { z } from "zod";
3
3
  import { db } from "@/lib/db";
4
4
  import { tasks } from "@/lib/db/schema";
5
5
  import { eq, and, desc } from "drizzle-orm";
6
- import { ok, err, type ToolContext } from "./helpers";
6
+ import { ok, err, resolveEntityId, type ToolContext } from "./helpers";
7
7
  import {
8
8
  DEFAULT_AGENT_RUNTIME,
9
9
  isAgentRuntimeId,
10
10
  SUPPORTED_AGENT_RUNTIMES,
11
11
  } from "@/lib/agents/runtime/catalog";
12
+ import { getProfile, listProfiles } from "@/lib/agents/profiles/registry";
12
13
 
13
14
  const VALID_TASK_STATUSES = [
14
15
  "planned",
@@ -19,6 +20,25 @@ const VALID_TASK_STATUSES = [
19
20
  "cancelled",
20
21
  ] as const;
21
22
 
23
+ /**
24
+ * Zod refinement shared by create_task and update_task for the agentProfile
25
+ * field. Returns true for valid registered profile IDs. The error message
26
+ * lists a truncated sample of valid IDs from the registry so operators can
27
+ * self-correct without cross-referencing docs.
28
+ */
29
+ function isValidAgentProfile(id: string): boolean {
30
+ return getProfile(id) !== undefined;
31
+ }
32
+
33
+ function agentProfileErrorMessage(invalid: string): string {
34
+ const valid = listProfiles()
35
+ .map((p) => p.id)
36
+ .sort();
37
+ const sample = valid.slice(0, 8).join(", ");
38
+ const more = valid.length > 8 ? `, and ${valid.length - 8} more` : "";
39
+ return `Invalid agentProfile "${invalid}". Valid profiles: ${sample}${more}. Run list_profiles (or inspect ~/.claude/skills/) to see the full set.`;
40
+ }
41
+
22
42
  export function taskTools(ctx: ToolContext) {
23
43
  return [
24
44
  defineTool(
@@ -51,6 +71,14 @@ export function taskTools(ctx: ToolContext) {
51
71
  .orderBy(tasks.priority, desc(tasks.createdAt))
52
72
  .limit(50);
53
73
 
74
+ if (result.length === 0 && effectiveProjectId) {
75
+ return ok({
76
+ tasks: [],
77
+ note: `No tasks found in project ${effectiveProjectId}. ` +
78
+ `Use projectId: null to list tasks from any project, ` +
79
+ `or get_task <id> to look up a specific task directly.`,
80
+ });
81
+ }
54
82
  return ok(result);
55
83
  } catch (e) {
56
84
  return err(e instanceof Error ? e.message : "Failed to list tasks");
@@ -90,13 +118,19 @@ export function taskTools(ctx: ToolContext) {
90
118
  ),
91
119
  agentProfile: z
92
120
  .string()
121
+ .refine(isValidAgentProfile, {
122
+ message: "Invalid agentProfile (not in profile registry). See list_profiles.",
123
+ })
93
124
  .optional()
94
125
  .describe(
95
- "Agent profile ID (e.g. general, code-reviewer, researcher, reddit-researcher)"
126
+ "Agent profile ID (e.g. general, code-reviewer, researcher). Validated against the profile registry."
96
127
  ),
97
128
  },
98
129
  async (args) => {
99
130
  try {
131
+ if (args.agentProfile !== undefined && !isValidAgentProfile(args.agentProfile)) {
132
+ return err(agentProfileErrorMessage(args.agentProfile));
133
+ }
100
134
  if (args.assignedAgent && !isAgentRuntimeId(args.assignedAgent)) {
101
135
  return err(
102
136
  `Invalid runtime "${args.assignedAgent}". Valid: ${SUPPORTED_AGENT_RUNTIMES.join(", ")}`
@@ -162,13 +196,23 @@ export function taskTools(ctx: ToolContext) {
162
196
  ),
163
197
  agentProfile: z
164
198
  .string()
199
+ .refine(isValidAgentProfile, {
200
+ message: "Invalid agentProfile (not in profile registry). See list_profiles.",
201
+ })
165
202
  .optional()
166
203
  .describe(
167
- "Agent profile ID (e.g. general, code-reviewer, researcher, reddit-researcher)"
204
+ "Agent profile ID (e.g. general, code-reviewer, researcher). Validated against the profile registry."
168
205
  ),
169
206
  },
170
207
  async (args) => {
171
208
  try {
209
+ const resolved = await resolveEntityId(tasks, tasks.id, args.taskId);
210
+ if ("error" in resolved) return err(resolved.error);
211
+ const taskId = resolved.id;
212
+
213
+ if (args.agentProfile !== undefined && !isValidAgentProfile(args.agentProfile)) {
214
+ return err(agentProfileErrorMessage(args.agentProfile));
215
+ }
172
216
  if (args.assignedAgent && !isAgentRuntimeId(args.assignedAgent)) {
173
217
  return err(
174
218
  `Invalid runtime "${args.assignedAgent}". Valid: ${SUPPORTED_AGENT_RUNTIMES.join(", ")}`
@@ -178,10 +222,10 @@ export function taskTools(ctx: ToolContext) {
178
222
  const existing = await db
179
223
  .select()
180
224
  .from(tasks)
181
- .where(eq(tasks.id, args.taskId))
225
+ .where(eq(tasks.id, taskId))
182
226
  .get();
183
227
 
184
- if (!existing) return err(`Task not found: ${args.taskId}`);
228
+ if (!existing) return err(`Task not found: ${taskId}`);
185
229
 
186
230
  const updates: Record<string, unknown> = { updatedAt: new Date() };
187
231
  if (args.title !== undefined) updates.title = args.title;
@@ -197,12 +241,12 @@ export function taskTools(ctx: ToolContext) {
197
241
  await db
198
242
  .update(tasks)
199
243
  .set(updates)
200
- .where(eq(tasks.id, args.taskId));
244
+ .where(eq(tasks.id, taskId));
201
245
 
202
246
  const [task] = await db
203
247
  .select()
204
248
  .from(tasks)
205
- .where(eq(tasks.id, args.taskId));
249
+ .where(eq(tasks.id, taskId));
206
250
 
207
251
  ctx.onToolResult?.("update_task", task);
208
252
  return ok(task);
@@ -220,13 +264,17 @@ export function taskTools(ctx: ToolContext) {
220
264
  },
221
265
  async (args) => {
222
266
  try {
267
+ const resolved = await resolveEntityId(tasks, tasks.id, args.taskId);
268
+ if ("error" in resolved) return err(resolved.error);
269
+ const taskId = resolved.id;
270
+
223
271
  const task = await db
224
272
  .select()
225
273
  .from(tasks)
226
- .where(eq(tasks.id, args.taskId))
274
+ .where(eq(tasks.id, taskId))
227
275
  .get();
228
276
 
229
- if (!task) return err(`Task not found: ${args.taskId}`);
277
+ if (!task) return err(`Task not found: ${taskId}`);
230
278
  ctx.onToolResult?.("get_task", task);
231
279
  return ok(task);
232
280
  } catch (e) {
@@ -249,6 +297,10 @@ export function taskTools(ctx: ToolContext) {
249
297
  },
250
298
  async (args) => {
251
299
  try {
300
+ const resolved = await resolveEntityId(tasks, tasks.id, args.taskId);
301
+ if ("error" in resolved) return err(resolved.error);
302
+ const taskId = resolved.id;
303
+
252
304
  if (args.assignedAgent && !isAgentRuntimeId(args.assignedAgent)) {
253
305
  return err(
254
306
  `Invalid runtime "${args.assignedAgent}". Valid: ${SUPPORTED_AGENT_RUNTIMES.join(", ")}`
@@ -258,26 +310,38 @@ export function taskTools(ctx: ToolContext) {
258
310
  const task = await db
259
311
  .select()
260
312
  .from(tasks)
261
- .where(eq(tasks.id, args.taskId))
313
+ .where(eq(tasks.id, taskId))
262
314
  .get();
263
315
 
264
- if (!task) return err(`Task not found: ${args.taskId}`);
316
+ if (!task) return err(`Task not found: ${taskId}`);
265
317
  if (task.status === "running") return err("Task is already running");
266
318
 
267
- const runtimeId = args.assignedAgent ?? task.assignedAgent ?? DEFAULT_AGENT_RUNTIME;
319
+ if (task.agentProfile && !isValidAgentProfile(task.agentProfile)) {
320
+ return err(
321
+ `Task ${taskId} has an invalid agentProfile "${task.agentProfile}" (not in profile registry). ` +
322
+ `Fix with update_task { taskId, agentProfile: "<valid-id>" } before retrying. ` +
323
+ agentProfileErrorMessage(task.agentProfile).split(". ").slice(1).join(". ")
324
+ );
325
+ }
326
+
327
+ const runtimeId = args.assignedAgent ?? task.assignedAgent ?? null;
268
328
 
269
329
  // Set status to queued
270
330
  await db
271
331
  .update(tasks)
272
332
  .set({ status: "queued", assignedAgent: runtimeId, updatedAt: new Date() })
273
- .where(eq(tasks.id, args.taskId));
333
+ .where(eq(tasks.id, taskId));
274
334
 
275
335
  // Fire-and-forget execution
276
336
  const { executeTaskWithAgent } = await import("@/lib/agents/router");
277
- executeTaskWithAgent(args.taskId, runtimeId).catch(() => {});
337
+ executeTaskWithAgent(taskId, runtimeId).catch(() => {});
278
338
 
279
- ctx.onToolResult?.("execute_task", { id: args.taskId, title: task.title });
280
- return ok({ message: "Execution started", taskId: args.taskId, runtime: runtimeId });
339
+ ctx.onToolResult?.("execute_task", { id: taskId, title: task.title });
340
+ return ok({
341
+ message: "Execution started",
342
+ taskId,
343
+ runtime: runtimeId ?? DEFAULT_AGENT_RUNTIME,
344
+ });
281
345
  } catch (e) {
282
346
  return err(e instanceof Error ? e.message : "Failed to execute task");
283
347
  }
@@ -292,17 +356,21 @@ export function taskTools(ctx: ToolContext) {
292
356
  },
293
357
  async (args) => {
294
358
  try {
359
+ const resolved = await resolveEntityId(tasks, tasks.id, args.taskId);
360
+ if ("error" in resolved) return err(resolved.error);
361
+ const taskId = resolved.id;
362
+
295
363
  const task = await db
296
364
  .select()
297
365
  .from(tasks)
298
- .where(eq(tasks.id, args.taskId))
366
+ .where(eq(tasks.id, taskId))
299
367
  .get();
300
368
 
301
- if (!task) return err(`Task not found: ${args.taskId}`);
369
+ if (!task) return err(`Task not found: ${taskId}`);
302
370
  if (task.status !== "running") return err(`Task is not running (status: ${task.status})`);
303
371
 
304
372
  const { getExecution } = await import("@/lib/agents/execution-manager");
305
- const execution = getExecution(args.taskId);
373
+ const execution = getExecution(taskId);
306
374
  if (execution?.abortController) {
307
375
  execution.abortController.abort();
308
376
  }
@@ -310,9 +378,9 @@ export function taskTools(ctx: ToolContext) {
310
378
  await db
311
379
  .update(tasks)
312
380
  .set({ status: "cancelled", updatedAt: new Date() })
313
- .where(eq(tasks.id, args.taskId));
381
+ .where(eq(tasks.id, taskId));
314
382
 
315
- return ok({ message: "Task cancelled", taskId: args.taskId });
383
+ return ok({ message: "Task cancelled", taskId });
316
384
  } catch (e) {
317
385
  return err(e instanceof Error ? e.message : "Failed to cancel task");
318
386
  }