@mndrk/agx 2.0.36 → 2.0.39

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 (765) hide show
  1. package/cloud-runtime/standalone/.next/BUILD_ID +1 -1
  2. package/cloud-runtime/standalone/.next/build-manifest.json +4 -4
  3. package/cloud-runtime/standalone/.next/prerender-manifest.json +3 -3
  4. package/cloud-runtime/standalone/.next/required-server-files.json +4 -7
  5. package/cloud-runtime/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
  6. package/cloud-runtime/standalone/.next/server/app/_global-error.html +2 -2
  7. package/cloud-runtime/standalone/.next/server/app/_global-error.rsc +1 -1
  8. package/cloud-runtime/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  9. package/cloud-runtime/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  10. package/cloud-runtime/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  11. package/cloud-runtime/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  12. package/cloud-runtime/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/cloud-runtime/standalone/.next/server/app/_not-found/page/build-manifest.json +2 -2
  14. package/cloud-runtime/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  15. package/cloud-runtime/standalone/.next/server/app/_not-found.html +2 -2
  16. package/cloud-runtime/standalone/.next/server/app/_not-found.rsc +4 -4
  17. package/cloud-runtime/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  18. package/cloud-runtime/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  19. package/cloud-runtime/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  20. package/cloud-runtime/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  21. package/cloud-runtime/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  22. package/cloud-runtime/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  23. package/cloud-runtime/standalone/.next/server/app/agents/[id]/page/build-manifest.json +2 -2
  24. package/cloud-runtime/standalone/.next/server/app/agents/[id]/page_client-reference-manifest.js +1 -1
  25. package/cloud-runtime/standalone/.next/server/app/agents/page/build-manifest.json +2 -2
  26. package/cloud-runtime/standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  27. package/cloud-runtime/standalone/.next/server/app/agents.html +2 -2
  28. package/cloud-runtime/standalone/.next/server/app/agents.rsc +5 -5
  29. package/cloud-runtime/standalone/.next/server/app/agents.segments/_full.segment.rsc +5 -5
  30. package/cloud-runtime/standalone/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  31. package/cloud-runtime/standalone/.next/server/app/agents.segments/_index.segment.rsc +4 -4
  32. package/cloud-runtime/standalone/.next/server/app/agents.segments/_tree.segment.rsc +1 -1
  33. package/cloud-runtime/standalone/.next/server/app/agents.segments/agents/__PAGE__.segment.rsc +2 -2
  34. package/cloud-runtime/standalone/.next/server/app/agents.segments/agents.segment.rsc +1 -1
  35. package/cloud-runtime/standalone/.next/server/app/api/agent-specs/route.js +3 -3
  36. package/cloud-runtime/standalone/.next/server/app/api/agent-specs/route.js.nft.json +1 -1
  37. package/cloud-runtime/standalone/.next/server/app/api/agents/[id]/messages/route.js +1 -1
  38. package/cloud-runtime/standalone/.next/server/app/api/agents/[id]/messages/route.js.nft.json +1 -1
  39. package/cloud-runtime/standalone/.next/server/app/api/agents/[id]/profile/route.js +3 -3
  40. package/cloud-runtime/standalone/.next/server/app/api/agents/[id]/profile/route.js.nft.json +1 -1
  41. package/cloud-runtime/standalone/.next/server/app/api/agents/export/route.js +3 -3
  42. package/cloud-runtime/standalone/.next/server/app/api/agents/export/route.js.nft.json +1 -1
  43. package/cloud-runtime/standalone/.next/server/app/api/attachments/[id]/route.js +1 -1
  44. package/cloud-runtime/standalone/.next/server/app/api/attachments/[id]/route.js.nft.json +1 -1
  45. package/cloud-runtime/standalone/.next/server/app/api/automations/create/route.js +3 -3
  46. package/cloud-runtime/standalone/.next/server/app/api/automations/create/route.js.nft.json +1 -1
  47. package/cloud-runtime/standalone/.next/server/app/api/automations/route.js +1 -1
  48. package/cloud-runtime/standalone/.next/server/app/api/automations/route.js.nft.json +1 -1
  49. package/cloud-runtime/standalone/.next/server/app/api/chat/route.js +4 -4
  50. package/cloud-runtime/standalone/.next/server/app/api/chat/route.js.nft.json +1 -1
  51. package/cloud-runtime/standalone/.next/server/app/api/chat-runs/[id]/route.js +1 -1
  52. package/cloud-runtime/standalone/.next/server/app/api/chat-runs/[id]/route.js.nft.json +1 -1
  53. package/cloud-runtime/standalone/.next/server/app/api/chat-runs/[id]/signal/route.js +1 -1
  54. package/cloud-runtime/standalone/.next/server/app/api/chat-runs/[id]/signal/route.js.nft.json +1 -1
  55. package/cloud-runtime/standalone/.next/server/app/api/chat-runs/route.js +1 -1
  56. package/cloud-runtime/standalone/.next/server/app/api/chat-runs/route.js.nft.json +1 -1
  57. package/cloud-runtime/standalone/.next/server/app/api/daemon/route.js +1 -1
  58. package/cloud-runtime/standalone/.next/server/app/api/daemon/route.js.nft.json +1 -1
  59. package/cloud-runtime/standalone/.next/server/app/api/file-search/route.js.nft.json +1 -1
  60. package/cloud-runtime/standalone/.next/server/app/api/graphs/[graphId]/nodes/[nodeId]/route.js +1 -1
  61. package/cloud-runtime/standalone/.next/server/app/api/graphs/[graphId]/nodes/[nodeId]/route.js.nft.json +1 -1
  62. package/cloud-runtime/standalone/.next/server/app/api/health/route.js +3 -3
  63. package/cloud-runtime/standalone/.next/server/app/api/health/route.js.nft.json +1 -1
  64. package/cloud-runtime/standalone/.next/server/app/api/history/route.js +1 -1
  65. package/cloud-runtime/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  66. package/cloud-runtime/standalone/.next/server/app/api/history/status/route.js +1 -1
  67. package/cloud-runtime/standalone/.next/server/app/api/history/status/route.js.nft.json +1 -1
  68. package/cloud-runtime/standalone/.next/server/app/api/knowledge-notes/route.js +2 -2
  69. package/cloud-runtime/standalone/.next/server/app/api/knowledge-notes/route.js.nft.json +1 -1
  70. package/cloud-runtime/standalone/.next/server/app/api/learnings/route.js +3 -3
  71. package/cloud-runtime/standalone/.next/server/app/api/learnings/route.js.nft.json +1 -1
  72. package/cloud-runtime/standalone/.next/server/app/api/logs/route.js +1 -1
  73. package/cloud-runtime/standalone/.next/server/app/api/logs/route.js.nft.json +1 -1
  74. package/cloud-runtime/standalone/.next/server/app/api/logs/stream/route.js +1 -1
  75. package/cloud-runtime/standalone/.next/server/app/api/logs/stream/route.js.nft.json +1 -1
  76. package/cloud-runtime/standalone/.next/server/app/api/memories/route.js +2 -2
  77. package/cloud-runtime/standalone/.next/server/app/api/memories/route.js.nft.json +1 -1
  78. package/cloud-runtime/standalone/.next/server/app/api/messages/[id]/route.js +1 -1
  79. package/cloud-runtime/standalone/.next/server/app/api/messages/[id]/route.js.nft.json +1 -1
  80. package/cloud-runtime/standalone/.next/server/app/api/migrate/teams-to-projects/route.js +1 -1
  81. package/cloud-runtime/standalone/.next/server/app/api/migrate/teams-to-projects/route.js.nft.json +1 -1
  82. package/cloud-runtime/standalone/.next/server/app/api/migrate/workspaces-to-projects/route.js +1 -1
  83. package/cloud-runtime/standalone/.next/server/app/api/migrate/workspaces-to-projects/route.js.nft.json +1 -1
  84. package/cloud-runtime/standalone/.next/server/app/api/orchestrator/tasks/[taskId]/cancel/route.js +2 -2
  85. package/cloud-runtime/standalone/.next/server/app/api/orchestrator/tasks/[taskId]/cancel/route.js.nft.json +1 -1
  86. package/cloud-runtime/standalone/.next/server/app/api/orchestrator/tasks/[taskId]/signal/route.js +2 -2
  87. package/cloud-runtime/standalone/.next/server/app/api/orchestrator/tasks/[taskId]/signal/route.js.nft.json +1 -1
  88. package/cloud-runtime/standalone/.next/server/app/api/orchestrator/tasks/[taskId]/start/route.js +4 -4
  89. package/cloud-runtime/standalone/.next/server/app/api/orchestrator/tasks/[taskId]/start/route.js.nft.json +1 -1
  90. package/cloud-runtime/standalone/.next/server/app/api/orchestrator/tasks/[taskId]/status/route.js +3 -3
  91. package/cloud-runtime/standalone/.next/server/app/api/orchestrator/tasks/[taskId]/status/route.js.nft.json +1 -1
  92. package/cloud-runtime/standalone/.next/server/app/api/participants/route.js +1 -1
  93. package/cloud-runtime/standalone/.next/server/app/api/participants/route.js.nft.json +1 -1
  94. package/cloud-runtime/standalone/.next/server/app/api/processes/route.js +1 -1
  95. package/cloud-runtime/standalone/.next/server/app/api/processes/route.js.nft.json +1 -1
  96. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/agents/route.js +4 -4
  97. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/agents/route.js.nft.json +1 -1
  98. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/memory/route.js +4 -4
  99. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/memory/route.js.nft.json +1 -1
  100. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/migrate-v1/route.js +2 -2
  101. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/migrate-v1/route.js.nft.json +1 -1
  102. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/migrate-v2/route.js +2 -2
  103. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/migrate-v2/route.js.nft.json +1 -1
  104. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/route.js +3 -3
  105. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/route.js.nft.json +1 -1
  106. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/skills/route.js +4 -4
  107. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/skills/route.js.nft.json +1 -1
  108. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/threads/route.js +4 -4
  109. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/threads/route.js.nft.json +1 -1
  110. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/variables/route.js +4 -4
  111. package/cloud-runtime/standalone/.next/server/app/api/projects/[id]/variables/route.js.nft.json +1 -1
  112. package/cloud-runtime/standalone/.next/server/app/api/projects/route.js +3 -3
  113. package/cloud-runtime/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  114. package/cloud-runtime/standalone/.next/server/app/api/prompt-jobs/[id]/cancel/route.js +4 -4
  115. package/cloud-runtime/standalone/.next/server/app/api/prompt-jobs/[id]/cancel/route.js.nft.json +1 -1
  116. package/cloud-runtime/standalone/.next/server/app/api/prompt-jobs/[id]/route.js +4 -4
  117. package/cloud-runtime/standalone/.next/server/app/api/prompt-jobs/[id]/route.js.nft.json +1 -1
  118. package/cloud-runtime/standalone/.next/server/app/api/prompt-jobs/[id]/runs/route.js +4 -4
  119. package/cloud-runtime/standalone/.next/server/app/api/prompt-jobs/[id]/runs/route.js.nft.json +1 -1
  120. package/cloud-runtime/standalone/.next/server/app/api/prompt-jobs/agents/route.js +4 -4
  121. package/cloud-runtime/standalone/.next/server/app/api/prompt-jobs/agents/route.js.nft.json +1 -1
  122. package/cloud-runtime/standalone/.next/server/app/api/prompt-jobs/poll/route.js +4 -4
  123. package/cloud-runtime/standalone/.next/server/app/api/prompt-jobs/poll/route.js.nft.json +1 -1
  124. package/cloud-runtime/standalone/.next/server/app/api/prompt-jobs/route.js +4 -4
  125. package/cloud-runtime/standalone/.next/server/app/api/prompt-jobs/route.js.nft.json +1 -1
  126. package/cloud-runtime/standalone/.next/server/app/api/queue/complete/route.js +3 -3
  127. package/cloud-runtime/standalone/.next/server/app/api/queue/complete/route.js.nft.json +1 -1
  128. package/cloud-runtime/standalone/.next/server/app/api/queue/route.js +3 -3
  129. package/cloud-runtime/standalone/.next/server/app/api/queue/route.js.nft.json +1 -1
  130. package/cloud-runtime/standalone/.next/server/app/api/reactions/route.js +1 -1
  131. package/cloud-runtime/standalone/.next/server/app/api/reactions/route.js.nft.json +1 -1
  132. package/cloud-runtime/standalone/.next/server/app/api/repos/[id]/knowledge/route.js +1 -1
  133. package/cloud-runtime/standalone/.next/server/app/api/repos/[id]/knowledge/route.js.nft.json +1 -1
  134. package/cloud-runtime/standalone/.next/server/app/api/schedules/debug/route.js +2 -2
  135. package/cloud-runtime/standalone/.next/server/app/api/schedules/debug/route.js.nft.json +1 -1
  136. package/cloud-runtime/standalone/.next/server/app/api/schedules/poll/route.js +1 -1
  137. package/cloud-runtime/standalone/.next/server/app/api/schedules/poll/route.js.nft.json +1 -1
  138. package/cloud-runtime/standalone/.next/server/app/api/schedules/route.js +2 -2
  139. package/cloud-runtime/standalone/.next/server/app/api/schedules/route.js.nft.json +1 -1
  140. package/cloud-runtime/standalone/.next/server/app/api/search/route.js +1 -1
  141. package/cloud-runtime/standalone/.next/server/app/api/search/route.js.nft.json +1 -1
  142. package/cloud-runtime/standalone/.next/server/app/api/skills/assign/route.js +1 -1
  143. package/cloud-runtime/standalone/.next/server/app/api/skills/assign/route.js.nft.json +1 -1
  144. package/cloud-runtime/standalone/.next/server/app/api/skills/available/route.js +2 -2
  145. package/cloud-runtime/standalone/.next/server/app/api/skills/available/route.js.nft.json +1 -1
  146. package/cloud-runtime/standalone/.next/server/app/api/skills/detail/route.js +2 -2
  147. package/cloud-runtime/standalone/.next/server/app/api/skills/detail/route.js.nft.json +1 -1
  148. package/cloud-runtime/standalone/.next/server/app/api/skills/history/route.js +2 -2
  149. package/cloud-runtime/standalone/.next/server/app/api/skills/history/route.js.nft.json +1 -1
  150. package/cloud-runtime/standalone/.next/server/app/api/skills/learn/route.js +2 -2
  151. package/cloud-runtime/standalone/.next/server/app/api/skills/learn/route.js.nft.json +1 -1
  152. package/cloud-runtime/standalone/.next/server/app/api/skills/route.js +2 -2
  153. package/cloud-runtime/standalone/.next/server/app/api/skills/route.js.nft.json +1 -1
  154. package/cloud-runtime/standalone/.next/server/app/api/skills/unlearn/route.js +2 -2
  155. package/cloud-runtime/standalone/.next/server/app/api/skills/unlearn/route.js.nft.json +1 -1
  156. package/cloud-runtime/standalone/.next/server/app/api/summarize/route.js +3 -3
  157. package/cloud-runtime/standalone/.next/server/app/api/summarize/route.js.nft.json +1 -1
  158. package/cloud-runtime/standalone/.next/server/app/api/system/db-status/route.js +1 -1
  159. package/cloud-runtime/standalone/.next/server/app/api/system/db-status/route.js.nft.json +1 -1
  160. package/cloud-runtime/standalone/.next/server/app/api/task-drafts/route.js +1 -1
  161. package/cloud-runtime/standalone/.next/server/app/api/task-drafts/route.js.nft.json +1 -1
  162. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/comments/[commentId]/route.js +4 -4
  163. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/comments/[commentId]/route.js.nft.json +1 -1
  164. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/comments/route.js +2 -2
  165. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/comments/route.js.nft.json +1 -1
  166. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/costs/route.js +3 -3
  167. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/costs/route.js.nft.json +1 -1
  168. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/dependencies/route.js +1 -1
  169. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/dependencies/route.js.nft.json +1 -1
  170. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/events/route.js +3 -3
  171. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/events/route.js.nft.json +1 -1
  172. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/history/route.js +2 -2
  173. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/history/route.js.nft.json +1 -1
  174. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/metrics/route.js +2 -2
  175. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/metrics/route.js.nft.json +1 -1
  176. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/pause/route.js +1 -1
  177. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/pause/route.js.nft.json +1 -1
  178. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/replan/route.js +4 -4
  179. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/replan/route.js.nft.json +1 -1
  180. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/restart/route.js +3 -3
  181. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/restart/route.js.nft.json +1 -1
  182. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/resume/route.js +3 -3
  183. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/resume/route.js.nft.json +1 -1
  184. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/rollback/route.js +4 -4
  185. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/rollback/route.js.nft.json +1 -1
  186. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/route.js +4 -4
  187. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/route.js.nft.json +1 -1
  188. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/schedule/route.js +4 -4
  189. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/schedule/route.js.nft.json +1 -1
  190. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/start/route.js +3 -3
  191. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/start/route.js.nft.json +1 -1
  192. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/stop/route.js +1 -1
  193. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/graph/stop/route.js.nft.json +1 -1
  194. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/heartbeat/route.js +1 -1
  195. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/heartbeat/route.js.nft.json +1 -1
  196. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/history/route.js +3 -3
  197. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/history/route.js.nft.json +1 -1
  198. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/logs/route.js +4 -4
  199. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/logs/route.js.nft.json +1 -1
  200. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/logs/stream/route.js +1 -1
  201. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/logs/stream/route.js.nft.json +1 -1
  202. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/comments/route.js +2 -2
  203. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/comments/route.js.nft.json +1 -1
  204. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/complete/route.js +5 -5
  205. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/complete/route.js.nft.json +1 -1
  206. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/fail/route.js +5 -5
  207. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/fail/route.js.nft.json +1 -1
  208. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/resume/route.js +5 -5
  209. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/resume/route.js.nft.json +1 -1
  210. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/start/route.js +5 -5
  211. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/start/route.js.nft.json +1 -1
  212. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/stop/route.js +5 -5
  213. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/stop/route.js.nft.json +1 -1
  214. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/verify/route.js +6 -6
  215. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/nodes/[nodeId]/verify/route.js.nft.json +1 -1
  216. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/route.js +4 -4
  217. package/cloud-runtime/standalone/.next/server/app/api/tasks/[id]/route.js.nft.json +1 -1
  218. package/cloud-runtime/standalone/.next/server/app/api/tasks/assign-orphans/route.js +3 -3
  219. package/cloud-runtime/standalone/.next/server/app/api/tasks/assign-orphans/route.js.nft.json +1 -1
  220. package/cloud-runtime/standalone/.next/server/app/api/tasks/extract/route.js +3 -3
  221. package/cloud-runtime/standalone/.next/server/app/api/tasks/extract/route.js.nft.json +1 -1
  222. package/cloud-runtime/standalone/.next/server/app/api/tasks/route.js +4 -4
  223. package/cloud-runtime/standalone/.next/server/app/api/tasks/route.js.nft.json +1 -1
  224. package/cloud-runtime/standalone/.next/server/app/api/tasks/stream/route.js +1 -1
  225. package/cloud-runtime/standalone/.next/server/app/api/tasks/stream/route.js.nft.json +1 -1
  226. package/cloud-runtime/standalone/.next/server/app/api/thread-repos/route.js +1 -1
  227. package/cloud-runtime/standalone/.next/server/app/api/thread-repos/route.js.nft.json +1 -1
  228. package/cloud-runtime/standalone/.next/server/app/api/threads/knowledge/route.js +3 -3
  229. package/cloud-runtime/standalone/.next/server/app/api/threads/knowledge/route.js.nft.json +1 -1
  230. package/cloud-runtime/standalone/.next/server/app/api/threads/route.js +3 -3
  231. package/cloud-runtime/standalone/.next/server/app/api/threads/route.js.nft.json +1 -1
  232. package/cloud-runtime/standalone/.next/server/app/api/upload/[id]/route.js +1 -1
  233. package/cloud-runtime/standalone/.next/server/app/api/upload/[id]/route.js.nft.json +1 -1
  234. package/cloud-runtime/standalone/.next/server/app/api/upload/route.js +1 -1
  235. package/cloud-runtime/standalone/.next/server/app/api/upload/route.js.nft.json +1 -1
  236. package/cloud-runtime/standalone/.next/server/app/api/user-settings/route.js +3 -3
  237. package/cloud-runtime/standalone/.next/server/app/api/user-settings/route.js.nft.json +1 -1
  238. package/cloud-runtime/standalone/.next/server/app/automations/page/build-manifest.json +2 -2
  239. package/cloud-runtime/standalone/.next/server/app/automations/page_client-reference-manifest.js +1 -1
  240. package/cloud-runtime/standalone/.next/server/app/automations.html +2 -2
  241. package/cloud-runtime/standalone/.next/server/app/automations.rsc +5 -5
  242. package/cloud-runtime/standalone/.next/server/app/automations.segments/_full.segment.rsc +5 -5
  243. package/cloud-runtime/standalone/.next/server/app/automations.segments/_head.segment.rsc +1 -1
  244. package/cloud-runtime/standalone/.next/server/app/automations.segments/_index.segment.rsc +4 -4
  245. package/cloud-runtime/standalone/.next/server/app/automations.segments/_tree.segment.rsc +1 -1
  246. package/cloud-runtime/standalone/.next/server/app/automations.segments/automations/__PAGE__.segment.rsc +2 -2
  247. package/cloud-runtime/standalone/.next/server/app/automations.segments/automations.segment.rsc +1 -1
  248. package/cloud-runtime/standalone/.next/server/app/board/page/build-manifest.json +2 -2
  249. package/cloud-runtime/standalone/.next/server/app/board/page_client-reference-manifest.js +1 -1
  250. package/cloud-runtime/standalone/.next/server/app/board.html +2 -2
  251. package/cloud-runtime/standalone/.next/server/app/board.rsc +4 -4
  252. package/cloud-runtime/standalone/.next/server/app/board.segments/_full.segment.rsc +4 -4
  253. package/cloud-runtime/standalone/.next/server/app/board.segments/_head.segment.rsc +1 -1
  254. package/cloud-runtime/standalone/.next/server/app/board.segments/_index.segment.rsc +4 -4
  255. package/cloud-runtime/standalone/.next/server/app/board.segments/_tree.segment.rsc +1 -1
  256. package/cloud-runtime/standalone/.next/server/app/board.segments/board/__PAGE__.segment.rsc +1 -1
  257. package/cloud-runtime/standalone/.next/server/app/board.segments/board.segment.rsc +1 -1
  258. package/cloud-runtime/standalone/.next/server/app/execution-graph/page/build-manifest.json +2 -2
  259. package/cloud-runtime/standalone/.next/server/app/execution-graph/page_client-reference-manifest.js +1 -1
  260. package/cloud-runtime/standalone/.next/server/app/execution-graph.html +2 -2
  261. package/cloud-runtime/standalone/.next/server/app/execution-graph.rsc +5 -5
  262. package/cloud-runtime/standalone/.next/server/app/execution-graph.segments/_full.segment.rsc +5 -5
  263. package/cloud-runtime/standalone/.next/server/app/execution-graph.segments/_head.segment.rsc +1 -1
  264. package/cloud-runtime/standalone/.next/server/app/execution-graph.segments/_index.segment.rsc +4 -4
  265. package/cloud-runtime/standalone/.next/server/app/execution-graph.segments/_tree.segment.rsc +1 -1
  266. package/cloud-runtime/standalone/.next/server/app/execution-graph.segments/execution-graph/__PAGE__.segment.rsc +2 -2
  267. package/cloud-runtime/standalone/.next/server/app/execution-graph.segments/execution-graph.segment.rsc +1 -1
  268. package/cloud-runtime/standalone/.next/server/app/index.html +2 -2
  269. package/cloud-runtime/standalone/.next/server/app/index.rsc +5 -5
  270. package/cloud-runtime/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  271. package/cloud-runtime/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  272. package/cloud-runtime/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  273. package/cloud-runtime/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  274. package/cloud-runtime/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  275. package/cloud-runtime/standalone/.next/server/app/page/build-manifest.json +2 -2
  276. package/cloud-runtime/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  277. package/cloud-runtime/standalone/.next/server/app/projects/[slug]/automations/page/build-manifest.json +2 -2
  278. package/cloud-runtime/standalone/.next/server/app/projects/[slug]/automations/page_client-reference-manifest.js +1 -1
  279. package/cloud-runtime/standalone/.next/server/app/projects/[slug]/graph/[taskId]/page/build-manifest.json +2 -2
  280. package/cloud-runtime/standalone/.next/server/app/projects/[slug]/graph/[taskId]/page_client-reference-manifest.js +1 -1
  281. package/cloud-runtime/standalone/.next/server/app/projects/[slug]/knowledge/page/build-manifest.json +2 -2
  282. package/cloud-runtime/standalone/.next/server/app/projects/[slug]/knowledge/page_client-reference-manifest.js +1 -1
  283. package/cloud-runtime/standalone/.next/server/app/projects/[slug]/page/build-manifest.json +2 -2
  284. package/cloud-runtime/standalone/.next/server/app/projects/[slug]/page_client-reference-manifest.js +1 -1
  285. package/cloud-runtime/standalone/.next/server/app/projects/[slug]/thread/[threadId]/page/build-manifest.json +2 -2
  286. package/cloud-runtime/standalone/.next/server/app/projects/[slug]/thread/[threadId]/page_client-reference-manifest.js +1 -1
  287. package/cloud-runtime/standalone/.next/server/app/projects/orphans/page/build-manifest.json +2 -2
  288. package/cloud-runtime/standalone/.next/server/app/projects/orphans/page_client-reference-manifest.js +1 -1
  289. package/cloud-runtime/standalone/.next/server/app/projects/orphans.html +2 -2
  290. package/cloud-runtime/standalone/.next/server/app/projects/orphans.rsc +5 -5
  291. package/cloud-runtime/standalone/.next/server/app/projects/orphans.segments/_full.segment.rsc +5 -5
  292. package/cloud-runtime/standalone/.next/server/app/projects/orphans.segments/_head.segment.rsc +1 -1
  293. package/cloud-runtime/standalone/.next/server/app/projects/orphans.segments/_index.segment.rsc +4 -4
  294. package/cloud-runtime/standalone/.next/server/app/projects/orphans.segments/_tree.segment.rsc +1 -1
  295. package/cloud-runtime/standalone/.next/server/app/projects/orphans.segments/projects/orphans/__PAGE__.segment.rsc +2 -2
  296. package/cloud-runtime/standalone/.next/server/app/projects/orphans.segments/projects/orphans.segment.rsc +1 -1
  297. package/cloud-runtime/standalone/.next/server/app/projects/orphans.segments/projects.segment.rsc +1 -1
  298. package/cloud-runtime/standalone/.next/server/app/projects/page/build-manifest.json +2 -2
  299. package/cloud-runtime/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  300. package/cloud-runtime/standalone/.next/server/app/projects.html +2 -2
  301. package/cloud-runtime/standalone/.next/server/app/projects.rsc +5 -5
  302. package/cloud-runtime/standalone/.next/server/app/projects.segments/_full.segment.rsc +5 -5
  303. package/cloud-runtime/standalone/.next/server/app/projects.segments/_head.segment.rsc +1 -1
  304. package/cloud-runtime/standalone/.next/server/app/projects.segments/_index.segment.rsc +4 -4
  305. package/cloud-runtime/standalone/.next/server/app/projects.segments/_tree.segment.rsc +1 -1
  306. package/cloud-runtime/standalone/.next/server/app/projects.segments/projects/__PAGE__.segment.rsc +2 -2
  307. package/cloud-runtime/standalone/.next/server/app/projects.segments/projects.segment.rsc +1 -1
  308. package/cloud-runtime/standalone/.next/server/app/settings/page/build-manifest.json +2 -2
  309. package/cloud-runtime/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  310. package/cloud-runtime/standalone/.next/server/app/settings.html +2 -2
  311. package/cloud-runtime/standalone/.next/server/app/settings.rsc +5 -5
  312. package/cloud-runtime/standalone/.next/server/app/settings.segments/_full.segment.rsc +5 -5
  313. package/cloud-runtime/standalone/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  314. package/cloud-runtime/standalone/.next/server/app/settings.segments/_index.segment.rsc +4 -4
  315. package/cloud-runtime/standalone/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  316. package/cloud-runtime/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +2 -2
  317. package/cloud-runtime/standalone/.next/server/app/settings.segments/settings.segment.rsc +1 -1
  318. package/cloud-runtime/standalone/.next/server/app/skills/page/build-manifest.json +2 -2
  319. package/cloud-runtime/standalone/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  320. package/cloud-runtime/standalone/.next/server/app/skills.html +2 -2
  321. package/cloud-runtime/standalone/.next/server/app/skills.rsc +5 -5
  322. package/cloud-runtime/standalone/.next/server/app/skills.segments/_full.segment.rsc +5 -5
  323. package/cloud-runtime/standalone/.next/server/app/skills.segments/_head.segment.rsc +1 -1
  324. package/cloud-runtime/standalone/.next/server/app/skills.segments/_index.segment.rsc +4 -4
  325. package/cloud-runtime/standalone/.next/server/app/skills.segments/_tree.segment.rsc +1 -1
  326. package/cloud-runtime/standalone/.next/server/app/skills.segments/skills/__PAGE__.segment.rsc +2 -2
  327. package/cloud-runtime/standalone/.next/server/app/skills.segments/skills.segment.rsc +1 -1
  328. package/cloud-runtime/standalone/.next/server/app/status/page/build-manifest.json +2 -2
  329. package/cloud-runtime/standalone/.next/server/app/status/page_client-reference-manifest.js +1 -1
  330. package/cloud-runtime/standalone/.next/server/app/status.html +2 -2
  331. package/cloud-runtime/standalone/.next/server/app/status.rsc +5 -5
  332. package/cloud-runtime/standalone/.next/server/app/status.segments/_full.segment.rsc +5 -5
  333. package/cloud-runtime/standalone/.next/server/app/status.segments/_head.segment.rsc +1 -1
  334. package/cloud-runtime/standalone/.next/server/app/status.segments/_index.segment.rsc +4 -4
  335. package/cloud-runtime/standalone/.next/server/app/status.segments/_tree.segment.rsc +1 -1
  336. package/cloud-runtime/standalone/.next/server/app/status.segments/status/__PAGE__.segment.rsc +2 -2
  337. package/cloud-runtime/standalone/.next/server/app/status.segments/status.segment.rsc +1 -1
  338. package/cloud-runtime/standalone/.next/server/app/thread/[id]/page/build-manifest.json +2 -2
  339. package/cloud-runtime/standalone/.next/server/app/thread/[id]/page_client-reference-manifest.js +1 -1
  340. package/cloud-runtime/standalone/.next/server/app/welcome/page/build-manifest.json +2 -2
  341. package/cloud-runtime/standalone/.next/server/app/welcome/page_client-reference-manifest.js +1 -1
  342. package/cloud-runtime/standalone/.next/server/app/welcome.html +2 -2
  343. package/cloud-runtime/standalone/.next/server/app/welcome.rsc +5 -5
  344. package/cloud-runtime/standalone/.next/server/app/welcome.segments/_full.segment.rsc +5 -5
  345. package/cloud-runtime/standalone/.next/server/app/welcome.segments/_head.segment.rsc +1 -1
  346. package/cloud-runtime/standalone/.next/server/app/welcome.segments/_index.segment.rsc +4 -4
  347. package/cloud-runtime/standalone/.next/server/app/welcome.segments/_tree.segment.rsc +1 -1
  348. package/cloud-runtime/standalone/.next/server/app/welcome.segments/welcome/__PAGE__.segment.rsc +2 -2
  349. package/cloud-runtime/standalone/.next/server/app/welcome.segments/welcome.segment.rsc +1 -1
  350. package/cloud-runtime/standalone/.next/server/chunks/{[externals]__cf9f18a6._.js → [externals]__986fcdb7._.js} +1 -1
  351. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__01cd082e._.js +13 -0
  352. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__0936925d._.js +3 -0
  353. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__0c3dd73b._.js +13 -0
  354. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__0cc3f3b7._.js +18 -0
  355. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__d4126e05._.js → [root-of-the-server]__1b0bb735._.js} +3 -3
  356. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__4d865017._.js → [root-of-the-server]__1c86bf6e._.js} +6 -6
  357. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__1dce6c15._.js +3 -0
  358. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__0bb52353._.js → [root-of-the-server]__20c58b41._.js} +18 -18
  359. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__2126c763._.js +42 -0
  360. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__255b11f2._.js +3 -0
  361. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__26817611._.js +3 -0
  362. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__277ed37d._.js +3 -0
  363. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__294fceef._.js +3 -0
  364. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__2f06f568._.js +46 -0
  365. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__30bd0c87._.js +13 -0
  366. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__314d5c41._.js +3 -0
  367. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__352dad6d._.js +3 -0
  368. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__374cd94c._.js +42 -0
  369. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__3785024c._.js +80 -0
  370. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__379604d4._.js +13 -0
  371. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__3c8f1de6._.js +15 -0
  372. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__3d0df5a8._.js +8 -0
  373. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__0b3b6a47._.js → [root-of-the-server]__4014ed70._.js} +20 -20
  374. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__42fcb81c._.js +52 -0
  375. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__4a3cd6ac._.js +13 -0
  376. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__4a4265e0._.js +22 -0
  377. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__4bce7db7._.js +101 -0
  378. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__4c5c536d._.js +18 -0
  379. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__4e522535._.js +6 -0
  380. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__50c24784._.js +3 -0
  381. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__50ddd3ce._.js +1 -1
  382. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__529a6e1c._.js +80 -0
  383. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__59d1cdd8._.js +3 -0
  384. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__5a1fd688._.js +3 -0
  385. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__5d359afa._.js +18 -18
  386. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__628d686b._.js +3 -0
  387. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__005b3c82._.js → [root-of-the-server]__644e6285._.js} +8 -8
  388. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__65755104._.js +7 -0
  389. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__068b4f08._.js → [root-of-the-server]__73c20995._.js} +3 -3
  390. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__762ab29c._.js +51 -0
  391. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__981d92dd._.js → [root-of-the-server]__8125bbc3._.js} +19 -19
  392. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__85275b88._.js +3 -0
  393. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__89666394._.js +8 -0
  394. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__8c0fb154._.js +13 -0
  395. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__8f5cac13._.js +46 -0
  396. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__91b22098._.js +8 -0
  397. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__92924218._.js +13 -0
  398. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__94bd7f65._.js +3 -0
  399. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__96ae701e._.js +1 -1
  400. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__9746d1f5._.js +18 -0
  401. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__98ce983b._.js +3 -0
  402. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__ee6511a0._.js → [root-of-the-server]__9a9fd39f._.js} +10 -10
  403. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__9ad4e385._.js +3 -0
  404. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__9b69f93e._.js +18 -0
  405. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__a01ddd0b._.js +46 -0
  406. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__8ac0286e._.js → [root-of-the-server]__a099c992._.js} +20 -20
  407. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__a9b949c3._.js +7 -0
  408. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__ab7343c8._.js +3 -0
  409. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__af7a73fd._.js +3 -0
  410. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__bd43017b._.js +3 -0
  411. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__bf6fb108._.js +80 -0
  412. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__c0a18648._.js +10 -10
  413. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__7ee9b7b6._.js → [root-of-the-server]__c122c54a._.js} +3 -3
  414. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__c4ea4921._.js +3 -0
  415. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__8b0ab82f._.js → [root-of-the-server]__c4ed5d83._.js} +7 -7
  416. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__c695a5f2._.js +18 -0
  417. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__c8b49077._.js +10 -10
  418. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__d57e800e._.js +13 -0
  419. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__d8b615bf._.js +34 -0
  420. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__d9bd6334._.js +3 -0
  421. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__543ba6c4._.js → [root-of-the-server]__da3a1ce7._.js} +2 -2
  422. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__db469f1b._.js +3 -0
  423. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__de2a1e43._.js +3 -0
  424. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__5031f8d4._.js → [root-of-the-server]__dec3e1b7._.js} +11 -11
  425. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__f1147a4a._.js +15 -0
  426. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__f5597fea._.js +13 -0
  427. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__f8c94cb3._.js +8 -0
  428. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__ceb02db8._.js → [root-of-the-server]__f9cff4b0._.js} +2 -2
  429. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__f9f7f2df._.js +4 -0
  430. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__fa79d53f._.js +46 -0
  431. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__fb14cd4a._.js +3 -0
  432. package/cloud-runtime/standalone/.next/server/chunks/{[root-of-the-server]__a55c16a5._.js → [root-of-the-server]__fc27a898._.js} +31 -31
  433. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__fcf0b40a._.js +3 -0
  434. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__ffb21023._.js +80 -0
  435. package/cloud-runtime/standalone/.next/server/chunks/_05fa3b89._.js +18 -18
  436. package/cloud-runtime/standalone/.next/server/chunks/_17e53c87._.js +3 -0
  437. package/cloud-runtime/standalone/.next/server/chunks/_4190f170._.js +18 -18
  438. package/cloud-runtime/standalone/.next/server/chunks/_42e9c8d5._.js +18 -18
  439. package/cloud-runtime/standalone/.next/server/chunks/_5ca51127._.js +3 -3
  440. package/cloud-runtime/standalone/.next/server/chunks/_5fd6af5d._.js +3 -3
  441. package/cloud-runtime/standalone/.next/server/chunks/_8b9fde82._.js +20 -20
  442. package/cloud-runtime/standalone/.next/server/chunks/_994414cd._.js +3 -3
  443. package/cloud-runtime/standalone/.next/server/chunks/_99b78daf._.js +18 -18
  444. package/cloud-runtime/standalone/.next/server/chunks/_affbdbb0._.js +18 -18
  445. package/cloud-runtime/standalone/.next/server/chunks/_d22934ab._.js +20 -20
  446. package/cloud-runtime/standalone/.next/server/chunks/_efc73784._.js +18 -18
  447. package/cloud-runtime/standalone/.next/server/chunks/lib_a5adca60._.js +15 -15
  448. package/cloud-runtime/standalone/.next/server/chunks/lib_check-node-version_ts_ef89bf83._.js +3 -0
  449. package/cloud-runtime/standalone/.next/server/chunks/lib_ea45fe73._.js +18 -18
  450. package/cloud-runtime/standalone/.next/server/chunks/lib_history-store_ts_2e721df2._.js +39 -39
  451. package/cloud-runtime/standalone/.next/server/chunks/lib_history-store_ts_74d1c060._.js +39 -39
  452. package/cloud-runtime/standalone/.next/server/chunks/lib_sqlite-query-adapter_ts_3ea4d849._.js +18 -18
  453. package/cloud-runtime/standalone/.next/server/chunks/lib_sqlite-query-adapter_ts_b0b1a9b2._.js +19 -19
  454. package/cloud-runtime/standalone/.next/server/chunks/src_graph_14067235._.js +18 -18
  455. package/cloud-runtime/standalone/.next/server/chunks/src_graph_b63e2d39._.js +18 -18
  456. package/cloud-runtime/standalone/.next/server/chunks/ssr/_0c5c111f._.js +1 -1
  457. package/cloud-runtime/standalone/.next/server/chunks/ssr/_314f4c49._.js +1 -1
  458. package/cloud-runtime/standalone/.next/server/chunks/ssr/components_thread_WorkspaceSidebar_tsx_e660301b._.js +1 -1
  459. package/cloud-runtime/standalone/.next/server/instrumentation.js +1 -1
  460. package/cloud-runtime/standalone/.next/server/middleware-build-manifest.js +2 -2
  461. package/cloud-runtime/standalone/.next/server/middleware-manifest.json +5 -5
  462. package/cloud-runtime/standalone/.next/server/pages/404.html +2 -2
  463. package/cloud-runtime/standalone/.next/server/pages/500.html +2 -2
  464. package/cloud-runtime/standalone/.next/server/server-reference-manifest.js +1 -1
  465. package/cloud-runtime/standalone/.next/server/server-reference-manifest.json +1 -1
  466. package/cloud-runtime/standalone/.next/static/chunks/{47f22a56011af8d3.js → 5c0819dcc4bfec85.js} +1 -1
  467. package/cloud-runtime/standalone/.next/static/chunks/{25c9ac515cfe5635.js → 9bde80696400d2ff.js} +2 -2
  468. package/cloud-runtime/standalone/.next/static/chunks/ac9a7d8cf17b5d75.js +1 -0
  469. package/cloud-runtime/standalone/.next/static/chunks/{dfff51033c303fc7.js → ee5f1457fbc593e1.js} +1 -1
  470. package/cloud-runtime/standalone/.next/static/chunks/{turbopack-22475f0dd0c18f92.js → turbopack-e1d640f2fbe4fa5e.js} +1 -1
  471. package/cloud-runtime/standalone/app/api/agents/[id]/messages/route.ts +4 -3
  472. package/cloud-runtime/standalone/app/api/agents/[id]/profile/route.ts +1 -1
  473. package/cloud-runtime/standalone/app/api/automations/route.ts +1 -1
  474. package/cloud-runtime/standalone/app/api/chat/route.ts +2 -2
  475. package/cloud-runtime/standalone/app/api/memories/route.ts +2 -2
  476. package/cloud-runtime/standalone/app/api/prompt-jobs/[id]/route.ts +9 -1
  477. package/cloud-runtime/standalone/app/api/system/db-status/route.ts +12 -11
  478. package/cloud-runtime/standalone/components/PromptJobBoard.tsx +12 -1
  479. package/cloud-runtime/standalone/components/errors/StartupGuard.tsx +1 -1
  480. package/cloud-runtime/standalone/components/errors/StartupGuardWrapper.tsx +1 -1
  481. package/cloud-runtime/standalone/components/thread/WorkspaceSidebar.tsx +1 -1
  482. package/cloud-runtime/standalone/coverage/clover.xml +1208 -0
  483. package/cloud-runtime/standalone/coverage/coverage-final.json +29 -0
  484. package/cloud-runtime/standalone/coverage/lcov-report/app/api/audit/index.html +116 -0
  485. package/cloud-runtime/standalone/coverage/lcov-report/app/api/audit/route.ts.html +208 -0
  486. package/cloud-runtime/standalone/coverage/lcov-report/app/api/auth/[...nextauth]/index.html +116 -0
  487. package/cloud-runtime/standalone/coverage/lcov-report/app/api/auth/[...nextauth]/route.ts.html +166 -0
  488. package/cloud-runtime/standalone/coverage/lcov-report/app/api/auth/daemon-secret/index.html +116 -0
  489. package/cloud-runtime/standalone/coverage/lcov-report/app/api/auth/daemon-secret/route.ts.html +532 -0
  490. package/cloud-runtime/standalone/coverage/lcov-report/app/api/auth/status/index.html +116 -0
  491. package/cloud-runtime/standalone/coverage/lcov-report/app/api/auth/status/route.ts.html +178 -0
  492. package/cloud-runtime/standalone/coverage/lcov-report/app/api/learnings/index.html +116 -0
  493. package/cloud-runtime/standalone/coverage/lcov-report/app/api/learnings/route.ts.html +262 -0
  494. package/cloud-runtime/standalone/coverage/lcov-report/app/api/logs/stream/index.html +116 -0
  495. package/cloud-runtime/standalone/coverage/lcov-report/app/api/logs/stream/route.ts.html +448 -0
  496. package/cloud-runtime/standalone/coverage/lcov-report/app/api/queue/complete/index.html +116 -0
  497. package/cloud-runtime/standalone/coverage/lcov-report/app/api/queue/complete/route.ts.html +331 -0
  498. package/cloud-runtime/standalone/coverage/lcov-report/app/api/queue/index.html +116 -0
  499. package/cloud-runtime/standalone/coverage/lcov-report/app/api/queue/route.ts.html +505 -0
  500. package/cloud-runtime/standalone/coverage/lcov-report/app/api/stage-prompts/index.html +116 -0
  501. package/cloud-runtime/standalone/coverage/lcov-report/app/api/stage-prompts/route.ts.html +412 -0
  502. package/cloud-runtime/standalone/coverage/lcov-report/app/api/tasks/[id]/advance/index.html +116 -0
  503. package/cloud-runtime/standalone/coverage/lcov-report/app/api/tasks/[id]/advance/route.ts.html +304 -0
  504. package/cloud-runtime/standalone/coverage/lcov-report/app/api/tasks/[id]/index.html +116 -0
  505. package/cloud-runtime/standalone/coverage/lcov-report/app/api/tasks/[id]/logs/index.html +116 -0
  506. package/cloud-runtime/standalone/coverage/lcov-report/app/api/tasks/[id]/logs/route.ts.html +202 -0
  507. package/cloud-runtime/standalone/coverage/lcov-report/app/api/tasks/[id]/route.ts.html +373 -0
  508. package/cloud-runtime/standalone/coverage/lcov-report/app/api/tasks/index.html +116 -0
  509. package/cloud-runtime/standalone/coverage/lcov-report/app/api/tasks/route.ts.html +499 -0
  510. package/cloud-runtime/standalone/coverage/lcov-report/app/api/tasks/stream/index.html +116 -0
  511. package/cloud-runtime/standalone/coverage/lcov-report/app/api/tasks/stream/route.ts.html +349 -0
  512. package/cloud-runtime/standalone/coverage/lcov-report/base.css +224 -0
  513. package/cloud-runtime/standalone/coverage/lcov-report/block-navigation.js +87 -0
  514. package/cloud-runtime/standalone/coverage/lcov-report/components/AuthProvider.tsx.html +259 -0
  515. package/cloud-runtime/standalone/coverage/lcov-report/components/ChatInterface.tsx.html +1228 -0
  516. package/cloud-runtime/standalone/coverage/lcov-report/components/KanbanBoard.tsx.html +1024 -0
  517. package/cloud-runtime/standalone/coverage/lcov-report/components/Layout.tsx.html +211 -0
  518. package/cloud-runtime/standalone/coverage/lcov-report/components/LearningsPanel.tsx.html +535 -0
  519. package/cloud-runtime/standalone/coverage/lcov-report/components/LogTimeline.tsx.html +415 -0
  520. package/cloud-runtime/standalone/coverage/lcov-report/components/SortableTaskCard.tsx.html +358 -0
  521. package/cloud-runtime/standalone/coverage/lcov-report/components/StagePills.tsx.html +439 -0
  522. package/cloud-runtime/standalone/coverage/lcov-report/components/TaskCard.tsx.html +514 -0
  523. package/cloud-runtime/standalone/coverage/lcov-report/components/TaskCardOverlay.tsx.html +256 -0
  524. package/cloud-runtime/standalone/coverage/lcov-report/components/TaskDetail.tsx.html +622 -0
  525. package/cloud-runtime/standalone/coverage/lcov-report/components/TaskList.tsx.html +253 -0
  526. package/cloud-runtime/standalone/coverage/lcov-report/components/index.html +281 -0
  527. package/cloud-runtime/standalone/coverage/lcov-report/favicon.png +0 -0
  528. package/cloud-runtime/standalone/coverage/lcov-report/hooks/index.html +116 -0
  529. package/cloud-runtime/standalone/coverage/lcov-report/hooks/useTasks.ts.html +1042 -0
  530. package/cloud-runtime/standalone/coverage/lcov-report/index.html +341 -0
  531. package/cloud-runtime/standalone/coverage/lcov-report/lib/auth-client.ts.html +202 -0
  532. package/cloud-runtime/standalone/coverage/lcov-report/lib/auth-server.ts.html +172 -0
  533. package/cloud-runtime/standalone/coverage/lcov-report/lib/auth.ts.html +265 -0
  534. package/cloud-runtime/standalone/coverage/lcov-report/lib/db.ts.html +1252 -0
  535. package/cloud-runtime/standalone/coverage/lcov-report/lib/index.html +131 -0
  536. package/cloud-runtime/standalone/coverage/lcov-report/lib/orchestrator.ts.html +409 -0
  537. package/cloud-runtime/standalone/coverage/lcov-report/lib/security.ts.html +1165 -0
  538. package/cloud-runtime/standalone/coverage/lcov-report/lib/supabase-server.ts.html +175 -0
  539. package/cloud-runtime/standalone/coverage/lcov-report/lib/supabase.ts.html +157 -0
  540. package/cloud-runtime/standalone/coverage/lcov-report/prettify.css +1 -0
  541. package/cloud-runtime/standalone/coverage/lcov-report/prettify.js +2 -0
  542. package/cloud-runtime/standalone/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  543. package/cloud-runtime/standalone/coverage/lcov-report/sorter.js +210 -0
  544. package/cloud-runtime/standalone/coverage/lcov.info +2386 -0
  545. package/cloud-runtime/standalone/docs/LIMITS.md +63 -0
  546. package/cloud-runtime/standalone/docs/architecture/ADR-001-hybrid-to-full-sqlite.md +345 -0
  547. package/cloud-runtime/standalone/docs/baseline/baseline-report.json +1009 -0
  548. package/cloud-runtime/standalone/docs/baseline/critical-queries.md +105 -0
  549. package/cloud-runtime/standalone/docs/baseline/lock-metrics.json +21 -0
  550. package/cloud-runtime/standalone/docs/baseline/read-latency.json +146 -0
  551. package/cloud-runtime/standalone/docs/baseline/restore-time.json +10 -0
  552. package/cloud-runtime/standalone/docs/baseline/write-metrics.json +803 -0
  553. package/cloud-runtime/standalone/docs/decisions/sqlite-migration-adr.md +327 -0
  554. package/cloud-runtime/standalone/docs/error-code-mapping.md +74 -0
  555. package/cloud-runtime/standalone/docs/migration-plan.md +120 -0
  556. package/cloud-runtime/standalone/docs/migration-spec.md +345 -0
  557. package/cloud-runtime/standalone/docs/pg-sqlite-compatibility-matrix.md +554 -0
  558. package/cloud-runtime/standalone/docs/project-agent-migration-status.md +229 -0
  559. package/cloud-runtime/standalone/docs/runbook-shadow-read.md +66 -0
  560. package/cloud-runtime/standalone/docs/runbook.md +155 -0
  561. package/cloud-runtime/standalone/docs/specs/cli-postgres-removal.md +69 -0
  562. package/cloud-runtime/standalone/docs/specs/thread-mentions.md +53 -0
  563. package/cloud-runtime/standalone/docs/superpowers/plans/2026-04-01-prompt-scheduler.md +1907 -0
  564. package/cloud-runtime/standalone/docs/superpowers/plans/2026-04-02-sqlite-migration.md +1047 -0
  565. package/cloud-runtime/standalone/docs/transcript.txt +282 -0
  566. package/cloud-runtime/standalone/docs/ux/GlobalChatFlow.storyboard +23 -0
  567. package/cloud-runtime/standalone/docs/ux/assistant-chat-cli.md +32 -0
  568. package/cloud-runtime/standalone/hooks/usePromptJobs.ts +9 -18
  569. package/cloud-runtime/standalone/instrumentation.ts +33 -0
  570. package/cloud-runtime/standalone/lib/agent-process-registry.ts +10 -9
  571. package/cloud-runtime/standalone/lib/attachment-store.ts +6 -5
  572. package/cloud-runtime/standalone/lib/check-node-version.ts +12 -0
  573. package/cloud-runtime/standalone/lib/db-adapter.interface.ts +1 -1
  574. package/cloud-runtime/standalone/lib/history-store.ts +46 -46
  575. package/cloud-runtime/standalone/lib/knowledge-store.ts +2 -1
  576. package/cloud-runtime/standalone/lib/participants-store.ts +9 -8
  577. package/cloud-runtime/standalone/lib/queue/sqlite-adapter.ts +12 -11
  578. package/cloud-runtime/standalone/lib/repo-knowledge.ts +6 -5
  579. package/cloud-runtime/standalone/lib/sqlite-compat.ts +75 -0
  580. package/cloud-runtime/standalone/lib/sqlite-query-adapter.ts +15 -14
  581. package/cloud-runtime/standalone/lib/sqlite_writer.ts +10 -9
  582. package/cloud-runtime/standalone/lib/startup.ts +18 -19
  583. package/cloud-runtime/standalone/lib/thread-knowledge-runs.ts +2 -1
  584. package/cloud-runtime/standalone/lib/workspaces-to-projects-migration.ts +19 -18
  585. package/cloud-runtime/standalone/mcp/dist/constants.js +66 -0
  586. package/cloud-runtime/standalone/mcp/dist/db.js +220 -0
  587. package/cloud-runtime/standalone/mcp/dist/index.js +7 -0
  588. package/cloud-runtime/standalone/mcp/dist/security.js +18 -0
  589. package/cloud-runtime/standalone/mcp/dist/server.js +240 -0
  590. package/cloud-runtime/standalone/mcp/dist/task-context.js +287 -0
  591. package/cloud-runtime/standalone/mcp/dist/test-client.js +82 -0
  592. package/cloud-runtime/standalone/mcp/dist/tools/audit.js +69 -0
  593. package/cloud-runtime/standalone/mcp/dist/tools/learnings.js +88 -0
  594. package/cloud-runtime/standalone/mcp/dist/tools/queue.js +312 -0
  595. package/cloud-runtime/standalone/mcp/dist/tools/tasks.js +244 -0
  596. package/cloud-runtime/standalone/mcp/dist/types.js +74 -0
  597. package/cloud-runtime/standalone/mcp/package-lock.json +3 -147
  598. package/cloud-runtime/standalone/mcp/package.json +1 -1
  599. package/cloud-runtime/standalone/mcp/src/check-node-version.ts +8 -0
  600. package/cloud-runtime/standalone/mcp/src/db.ts +4 -5
  601. package/cloud-runtime/standalone/mcp/src/index.ts +1 -0
  602. package/cloud-runtime/standalone/next.config.ts +0 -1
  603. package/cloud-runtime/standalone/node_modules/@img/sharp-darwin-arm64/lib/sharp-darwin-arm64.node +0 -0
  604. package/cloud-runtime/standalone/node_modules/@img/{sharp-linux-x64 → sharp-darwin-arm64}/package.json +7 -13
  605. package/cloud-runtime/standalone/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/README.md +2 -2
  606. package/cloud-runtime/standalone/node_modules/@img/{sharp-libvips-linuxmusl-x64 → sharp-libvips-darwin-arm64}/lib/glib-2.0/include/glibconfig.h +8 -9
  607. package/cloud-runtime/standalone/node_modules/@img/{sharp-libvips-linux-x64/lib/libvips-cpp.so.8.17.3 → sharp-libvips-darwin-arm64/lib/libvips-cpp.8.17.3.dylib} +0 -0
  608. package/cloud-runtime/standalone/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/package.json +5 -11
  609. package/cloud-runtime/standalone/notes/comments-context-demo.md +141 -0
  610. package/cloud-runtime/standalone/notes/comments-context-plan.md +119 -0
  611. package/cloud-runtime/standalone/notes/context-audit.md +21 -0
  612. package/cloud-runtime/standalone/notes/project-layer-plan.md +30 -0
  613. package/cloud-runtime/standalone/notes/project-layer.md +123 -0
  614. package/cloud-runtime/standalone/notes/temporal-migration-design.md +199 -0
  615. package/cloud-runtime/standalone/package-lock.json +9 -413
  616. package/cloud-runtime/standalone/package.json +3 -2
  617. package/cloud-runtime/standalone/playwright-report/data/00d55996f37c1506b90144c85493dd85032c13e5.png +0 -0
  618. package/cloud-runtime/standalone/playwright-report/data/0b9d409e57237ae111d7ba258d3dfe64dc368456.png +0 -0
  619. package/cloud-runtime/standalone/playwright-report/data/b33d5e80a15bd1deda4415b9d318ef73f581c950.png +0 -0
  620. package/cloud-runtime/standalone/playwright-report/data/b55684161aa440d0614595e13c91338f0420abbb.md +131 -0
  621. package/cloud-runtime/standalone/playwright-report/data/b9913957ae07e7565c38ddd71215be79b1ceb017.png +0 -0
  622. package/cloud-runtime/standalone/playwright-report/data/c3538be8ebbebc9fe4a7df8f12f04483af4a0d91.png +0 -0
  623. package/cloud-runtime/standalone/playwright-report/data/fe638f64ff5e36f1c30325564565662d3f57da87.md +180 -0
  624. package/cloud-runtime/standalone/playwright-report/index.html +85 -0
  625. package/cloud-runtime/standalone/scripts/bench-queue.ts +5 -4
  626. package/cloud-runtime/standalone/server.js +1 -1
  627. package/cloud-runtime/standalone/src/db/backup.ts +12 -11
  628. package/cloud-runtime/standalone/src/db/checks.ts +3 -3
  629. package/cloud-runtime/standalone/src/db/init.ts +13 -12
  630. package/cloud-runtime/standalone/src/graph/schedule-runner.ts +1 -1
  631. package/cloud-runtime/standalone/src/graph/store.ts +14 -13
  632. package/cloud-runtime/standalone/src/prompt-scheduler/get-store.ts +19 -3
  633. package/cloud-runtime/standalone/src/prompt-scheduler/store.ts +9 -9
  634. package/cloud-runtime/standalone/test/adapters/sqlite.ts +7 -6
  635. package/cloud-runtime/standalone/test-results/auth-Authentication-Flow-S-aff25-sion-across-page-navigation-chromium/test-failed-1.png +0 -0
  636. package/cloud-runtime/standalone/test-results/comments-Task-comments-add-4dc59-nd-persists-it-for-the-task-chromium/error-context.md +131 -0
  637. package/cloud-runtime/standalone/test-results/comments-Task-comments-add-4dc59-nd-persists-it-for-the-task-chromium/test-failed-1.png +0 -0
  638. package/cloud-runtime/standalone/test-results/kanban-Kanban-Board-Stage--4082a-er-planning-after-ideation--chromium/error-context.md +180 -0
  639. package/cloud-runtime/standalone/test-results/kanban-Kanban-Board-Stage--4082a-er-planning-after-ideation--chromium/test-failed-1.png +0 -0
  640. package/cloud-runtime/standalone/test-results/kanban-Kanban-Board-Stage-Columns-displays-all-9-SDLC-stages-chromium/error-context.md +180 -0
  641. package/cloud-runtime/standalone/test-results/kanban-Kanban-Board-Stage-Columns-displays-all-9-SDLC-stages-chromium/test-failed-1.png +0 -0
  642. package/cloud-runtime/standalone/test-results/kanban-Kanban-Board-Task-D-b6d98-ys-tasks-in-correct-columns-chromium/error-context.md +180 -0
  643. package/cloud-runtime/standalone/test-results/kanban-Kanban-Board-Task-D-b6d98-ys-tasks-in-correct-columns-chromium/test-failed-1.png +0 -0
  644. package/cloud-runtime/standalone/test-results/kanban-Kanban-Board-Task-Display-shows-task-count-per-column-chromium/test-failed-1.png +0 -0
  645. package/cloud-runtime/standalone/test-results/kanban-Task-Lifecycle-can-advance-task-through-all-stages-chromium/test-failed-1.png +0 -0
  646. package/cloud-runtime/standalone/tsconfig.json +1 -2
  647. package/cloud-runtime/standalone/tsconfig.tsbuildinfo +1 -0
  648. package/cloud-runtime/standalone/worker/index.js +110 -823
  649. package/cloud-runtime/standalone/worker/index.ts +1 -0
  650. package/package.json +1 -1
  651. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__017f03c3._.js +0 -13
  652. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__056d94e4._.js +0 -3
  653. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__06634853._.js +0 -80
  654. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__0f580808._.js +0 -13
  655. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__164a80ba._.js +0 -18
  656. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__16dd1fd7._.js +0 -13
  657. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__1a8e0957._.js +0 -7
  658. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__1cc2fe7f._.js +0 -3
  659. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__23ad03bf._.js +0 -3
  660. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__241a8bcf._.js +0 -3
  661. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__29419d66._.js +0 -42
  662. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__2948f712._.js +0 -3
  663. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__32ef6623._.js +0 -3
  664. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__34cb1b98._.js +0 -3
  665. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__3c1567b6._.js +0 -3
  666. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__3c37453e._.js +0 -3
  667. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__3faa64cd._.js +0 -4
  668. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__4041bb93._.js +0 -18
  669. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__42497c7b._.js +0 -80
  670. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__49c03d66._.js +0 -3
  671. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__4a8d14c1._.js +0 -3
  672. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__4c50f159._.js +0 -18
  673. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__4c861686._.js +0 -46
  674. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__588b6ab0._.js +0 -46
  675. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__596d0e81._.js +0 -42
  676. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__59b5d4e5._.js +0 -3
  677. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__61c99680._.js +0 -52
  678. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__64712846._.js +0 -3
  679. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__707c32af._.js +0 -15
  680. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__7370bb86._.js +0 -8
  681. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__749af50f._.js +0 -8
  682. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__74b97f0a._.js +0 -3
  683. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__75cedecf._.js +0 -6
  684. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__7e79d86a._.js +0 -3
  685. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__8b461158._.js +0 -3
  686. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__918f0106._.js +0 -80
  687. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__922eb7cd._.js +0 -80
  688. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__927cfc20._.js +0 -3
  689. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__952af4b3._.js +0 -22
  690. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__98b352f7._.js +0 -13
  691. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__a44db634._.js +0 -8
  692. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__a67cd108._.js +0 -51
  693. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__ab2bf82d._.js +0 -13
  694. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__abb032c1._.js +0 -34
  695. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__b4931ee1._.js +0 -3
  696. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__b4d05543._.js +0 -3
  697. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__b500f1bf._.js +0 -3
  698. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__b707e701._.js +0 -3
  699. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__b9e41767._.js +0 -3
  700. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__be4ad4b5._.js +0 -46
  701. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__bf5803eb._.js +0 -13
  702. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__c99509c2._.js +0 -101
  703. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__ccd4846e._.js +0 -13
  704. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__d7e839a8._.js +0 -18
  705. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__d908c9ea._.js +0 -8
  706. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__da20a0aa._.js +0 -18
  707. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__dcdeee3d._.js +0 -3
  708. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__e069c0a3._.js +0 -3
  709. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__e1e51c02._.js +0 -7
  710. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__e3a4fd97._.js +0 -13
  711. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__e4a87984._.js +0 -15
  712. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__ef82dda1._.js +0 -3
  713. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__fa0ebee3._.js +0 -13
  714. package/cloud-runtime/standalone/.next/server/chunks/[root-of-the-server]__fee58db1._.js +0 -46
  715. package/cloud-runtime/standalone/.next/server/chunks/_d225c04f._.js +0 -3
  716. package/cloud-runtime/standalone/.next/static/chunks/d73f1cc3ebc9993b.js +0 -1
  717. package/cloud-runtime/standalone/node_modules/@img/sharp-libvips-linux-x64/lib/glib-2.0/include/glibconfig.h +0 -221
  718. package/cloud-runtime/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md +0 -46
  719. package/cloud-runtime/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js +0 -1
  720. package/cloud-runtime/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.3 +0 -0
  721. package/cloud-runtime/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +0 -42
  722. package/cloud-runtime/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json +0 -30
  723. package/cloud-runtime/standalone/node_modules/@img/sharp-linux-x64/lib/sharp-linux-x64.node +0 -0
  724. package/cloud-runtime/standalone/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node +0 -0
  725. package/cloud-runtime/standalone/node_modules/@img/sharp-linuxmusl-x64/package.json +0 -46
  726. package/cloud-runtime/standalone/node_modules/better-sqlite3/build/Release/better_sqlite3.node +0 -0
  727. package/cloud-runtime/standalone/node_modules/better-sqlite3/lib/database.js +0 -90
  728. package/cloud-runtime/standalone/node_modules/better-sqlite3/lib/index.js +0 -3
  729. package/cloud-runtime/standalone/node_modules/better-sqlite3/lib/methods/aggregate.js +0 -43
  730. package/cloud-runtime/standalone/node_modules/better-sqlite3/lib/methods/backup.js +0 -67
  731. package/cloud-runtime/standalone/node_modules/better-sqlite3/lib/methods/function.js +0 -31
  732. package/cloud-runtime/standalone/node_modules/better-sqlite3/lib/methods/inspect.js +0 -7
  733. package/cloud-runtime/standalone/node_modules/better-sqlite3/lib/methods/pragma.js +0 -12
  734. package/cloud-runtime/standalone/node_modules/better-sqlite3/lib/methods/serialize.js +0 -16
  735. package/cloud-runtime/standalone/node_modules/better-sqlite3/lib/methods/table.js +0 -189
  736. package/cloud-runtime/standalone/node_modules/better-sqlite3/lib/methods/transaction.js +0 -78
  737. package/cloud-runtime/standalone/node_modules/better-sqlite3/lib/methods/wrappers.js +0 -54
  738. package/cloud-runtime/standalone/node_modules/better-sqlite3/lib/sqlite-error.js +0 -20
  739. package/cloud-runtime/standalone/node_modules/better-sqlite3/lib/util.js +0 -12
  740. package/cloud-runtime/standalone/node_modules/better-sqlite3/package.json +0 -59
  741. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/build/Release/better_sqlite3.node +0 -0
  742. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/lib/database.js +0 -90
  743. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/lib/index.js +0 -3
  744. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/lib/methods/aggregate.js +0 -43
  745. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/lib/methods/backup.js +0 -67
  746. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/lib/methods/function.js +0 -31
  747. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/lib/methods/inspect.js +0 -7
  748. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/lib/methods/pragma.js +0 -12
  749. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/lib/methods/serialize.js +0 -16
  750. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/lib/methods/table.js +0 -189
  751. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/lib/methods/transaction.js +0 -78
  752. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/lib/methods/wrappers.js +0 -54
  753. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/lib/sqlite-error.js +0 -20
  754. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/lib/util.js +0 -12
  755. package/cloud-runtime/standalone/node_modules/better-sqlite3-90e2652d1716b047/package.json +0 -59
  756. package/cloud-runtime/standalone/node_modules/bindings/bindings.js +0 -221
  757. package/cloud-runtime/standalone/node_modules/bindings/package.json +0 -28
  758. package/cloud-runtime/standalone/node_modules/file-uri-to-path/index.js +0 -66
  759. package/cloud-runtime/standalone/node_modules/file-uri-to-path/package.json +0 -32
  760. package/cloud-runtime/standalone/scripts/fix-turbopack-externals.mjs +0 -87
  761. /package/cloud-runtime/standalone/.next/static/{15nzSRnot8KsYYP8yMBe- → 9PXl40CrFxI8nirdJ1A-T}/_buildManifest.js +0 -0
  762. /package/cloud-runtime/standalone/.next/static/{15nzSRnot8KsYYP8yMBe- → 9PXl40CrFxI8nirdJ1A-T}/_clientMiddlewareManifest.json +0 -0
  763. /package/cloud-runtime/standalone/.next/static/{15nzSRnot8KsYYP8yMBe- → 9PXl40CrFxI8nirdJ1A-T}/_ssgManifest.js +0 -0
  764. /package/cloud-runtime/standalone/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/lib/index.js +0 -0
  765. /package/cloud-runtime/standalone/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/versions.json +0 -0
@@ -0,0 +1,1907 @@
1
+ # Prompt Scheduler Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Replace agx-cloud's graph-based automations with a simple prompt+schedule+CLI scheduler, where users create PromptJobs that run on cron schedules via any CLI (claude, codex, gemini, etc.).
6
+
7
+ **Architecture:** The existing graph engine becomes internal plumbing — a PromptJob maps to a single-node execution graph. New `prompt_runs` table tracks every execution. The runner polls for queued runs, shells out to the target CLI, streams output, and checks a cancel flag every 5s. The existing AutomationsBoard UI is replaced with a PromptJob-focused board.
8
+
9
+ **Tech Stack:** Next.js 16 (app router), SQLite (better-sqlite3), React 19, TailwindCSS 4, cron-parser, existing graph engine internals.
10
+
11
+ ---
12
+
13
+ ## File Structure
14
+
15
+ ### New Files
16
+ | File | Responsibility |
17
+ |------|---------------|
18
+ | `src/prompt-scheduler/types.ts` | PromptJob and PromptRun types |
19
+ | `src/prompt-scheduler/cron.ts` | Cron parsing, next-run computation (wraps cron-parser + nl-schedule) |
20
+ | `src/prompt-scheduler/engine.ts` | Core scheduling logic: find due jobs, create runs, compute next tick |
21
+ | `src/prompt-scheduler/runner.ts` | CLI execution: spawn child process, capture output, cancel check |
22
+ | `src/prompt-scheduler/store.ts` | Database operations for prompt_jobs and prompt_runs tables |
23
+ | `db/sqlite/002_prompt_scheduler_schema.sql` | Migration: prompt_jobs + prompt_runs tables |
24
+ | `app/api/prompt-jobs/route.ts` | GET (list) + POST (create) prompt jobs |
25
+ | `app/api/prompt-jobs/[id]/route.ts` | GET (detail) + PATCH (update) + DELETE prompt job |
26
+ | `app/api/prompt-jobs/[id]/runs/route.ts` | GET runs for a job |
27
+ | `app/api/prompt-jobs/[id]/cancel/route.ts` | POST cancel current run |
28
+ | `app/api/prompt-jobs/poll/route.ts` | POST poll for due jobs and execute |
29
+ | `components/PromptJobBoard.tsx` | Main UI: job list, create form, run log, controls |
30
+ | `hooks/usePromptJobs.ts` | Data fetching hook for prompt jobs + runs |
31
+ | `__tests__/prompt-scheduler/cron.test.ts` | Cron parsing tests |
32
+ | `__tests__/prompt-scheduler/engine.test.ts` | Scheduling engine tests |
33
+ | `__tests__/prompt-scheduler/runner.test.ts` | Runner execution tests |
34
+ | `__tests__/prompt-scheduler/store.test.ts` | Store CRUD tests |
35
+ | `__tests__/prompt-scheduler/api.test.ts` | API route integration tests |
36
+
37
+ ### Modified Files
38
+ | File | Change |
39
+ |------|--------|
40
+ | `app/automations/page.tsx` | Replace `AutomationsBoard` with `PromptJobBoard` |
41
+ | `db/sqlite/001_agx_board_schema.sql` | Reference only — no changes, new migration file instead |
42
+
43
+ ### Preserved (internal plumbing, untouched)
44
+ | File | Why |
45
+ |------|-----|
46
+ | `src/graph/schedule.ts` | Still used internally by graph engine for existing tasks |
47
+ | `src/graph/schedule-runner.ts` | Prompt scheduler calls into this for graph-level execution |
48
+ | `src/graph/nl-schedule.ts` | Reused by `src/prompt-scheduler/cron.ts` |
49
+
50
+ ---
51
+
52
+ ## Task 1: Database Schema — prompt_jobs and prompt_runs tables
53
+
54
+ **Files:**
55
+ - Create: `db/sqlite/002_prompt_scheduler_schema.sql`
56
+ - Create: `src/prompt-scheduler/types.ts`
57
+
58
+ - [ ] **Step 1: Define TypeScript types**
59
+
60
+ Create `src/prompt-scheduler/types.ts`:
61
+
62
+ ```typescript
63
+ export type PromptJobState = 'active' | 'paused' | 'stopped';
64
+ export type OverlapPolicy = 'skip' | 'queue' | 'allow';
65
+ export type RunStatus = 'queued' | 'running' | 'success' | 'failed' | 'cancelled';
66
+
67
+ export interface PromptJob {
68
+ id: string;
69
+ name: string;
70
+ prompt: string;
71
+ cli: string;
72
+ cronExpr: string;
73
+ cadence: string;
74
+ state: PromptJobState;
75
+ overlapPolicy: OverlapPolicy;
76
+ cancelCheckSec: number;
77
+ nextRunAt: number | null;
78
+ lastRunAt: number | null;
79
+ lastOutcome: RunStatus | null;
80
+ createdAt: string;
81
+ updatedAt: string;
82
+ }
83
+
84
+ export interface PromptRun {
85
+ id: string;
86
+ jobId: string;
87
+ status: RunStatus;
88
+ output: string | null;
89
+ error: string | null;
90
+ durationMs: number | null;
91
+ startedAt: string | null;
92
+ finishedAt: string | null;
93
+ cancelledAt: string | null;
94
+ createdAt: string;
95
+ }
96
+
97
+ export interface CreatePromptJobInput {
98
+ name: string;
99
+ prompt: string;
100
+ cli: string;
101
+ cadence: string;
102
+ overlapPolicy?: OverlapPolicy;
103
+ cancelCheckSec?: number;
104
+ }
105
+
106
+ export interface UpdatePromptJobInput {
107
+ name?: string;
108
+ prompt?: string;
109
+ cli?: string;
110
+ cadence?: string;
111
+ state?: PromptJobState;
112
+ overlapPolicy?: OverlapPolicy;
113
+ cancelCheckSec?: number;
114
+ }
115
+ ```
116
+
117
+ - [ ] **Step 2: Write the SQL migration**
118
+
119
+ Create `db/sqlite/002_prompt_scheduler_schema.sql`:
120
+
121
+ ```sql
122
+ -- Prompt Scheduler tables
123
+ CREATE TABLE IF NOT EXISTS prompt_jobs (
124
+ id TEXT PRIMARY KEY,
125
+ name TEXT NOT NULL,
126
+ prompt TEXT NOT NULL,
127
+ cli TEXT NOT NULL DEFAULT 'claude',
128
+ cron_expr TEXT NOT NULL,
129
+ cadence TEXT NOT NULL DEFAULT '',
130
+ state TEXT NOT NULL DEFAULT 'active' CHECK (state IN ('active', 'paused', 'stopped')),
131
+ overlap_policy TEXT NOT NULL DEFAULT 'skip' CHECK (overlap_policy IN ('skip', 'queue', 'allow')),
132
+ cancel_check_sec INTEGER NOT NULL DEFAULT 5,
133
+ next_run_at INTEGER,
134
+ last_run_at INTEGER,
135
+ last_outcome TEXT CHECK (last_outcome IS NULL OR last_outcome IN ('queued', 'running', 'success', 'failed', 'cancelled')),
136
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
137
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
138
+ );
139
+
140
+ CREATE INDEX IF NOT EXISTS idx_prompt_jobs_state ON prompt_jobs(state);
141
+ CREATE INDEX IF NOT EXISTS idx_prompt_jobs_next_run_at ON prompt_jobs(next_run_at);
142
+
143
+ CREATE TABLE IF NOT EXISTS prompt_runs (
144
+ id TEXT PRIMARY KEY,
145
+ job_id TEXT NOT NULL REFERENCES prompt_jobs(id) ON DELETE CASCADE,
146
+ status TEXT NOT NULL DEFAULT 'queued' CHECK (status IN ('queued', 'running', 'success', 'failed', 'cancelled')),
147
+ output TEXT,
148
+ error TEXT,
149
+ duration_ms INTEGER,
150
+ started_at TEXT,
151
+ finished_at TEXT,
152
+ cancelled_at TEXT,
153
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
154
+ );
155
+
156
+ CREATE INDEX IF NOT EXISTS idx_prompt_runs_job_id ON prompt_runs(job_id);
157
+ CREATE INDEX IF NOT EXISTS idx_prompt_runs_status ON prompt_runs(status);
158
+ ```
159
+
160
+ - [ ] **Step 3: Commit**
161
+
162
+ ```bash
163
+ git add src/prompt-scheduler/types.ts db/sqlite/002_prompt_scheduler_schema.sql
164
+ git commit -m "feat: add prompt_jobs and prompt_runs schema + types"
165
+ ```
166
+
167
+ ---
168
+
169
+ ## Task 2: Store — CRUD operations for prompt_jobs and prompt_runs
170
+
171
+ **Files:**
172
+ - Create: `src/prompt-scheduler/store.ts`
173
+ - Create: `__tests__/prompt-scheduler/store.test.ts`
174
+
175
+ - [ ] **Step 1: Write failing tests for store operations**
176
+
177
+ Create `__tests__/prompt-scheduler/store.test.ts`:
178
+
179
+ ```typescript
180
+ import Database from 'better-sqlite3';
181
+ import { describe, it, expect, beforeEach } from 'vitest';
182
+ import { PromptJobStore } from '@/src/prompt-scheduler/store';
183
+ import { readFileSync } from 'fs';
184
+ import path from 'path';
185
+
186
+ function createTestDb(): Database.Database {
187
+ const db = new Database(':memory:');
188
+ const boardSchema = readFileSync(
189
+ path.join(__dirname, '../../db/sqlite/001_agx_board_schema.sql'),
190
+ 'utf-8'
191
+ );
192
+ const promptSchema = readFileSync(
193
+ path.join(__dirname, '../../db/sqlite/002_prompt_scheduler_schema.sql'),
194
+ 'utf-8'
195
+ );
196
+ db.exec(boardSchema);
197
+ db.exec(promptSchema);
198
+ return db;
199
+ }
200
+
201
+ describe('PromptJobStore', () => {
202
+ let db: Database.Database;
203
+ let store: PromptJobStore;
204
+
205
+ beforeEach(() => {
206
+ db = createTestDb();
207
+ store = new PromptJobStore(db);
208
+ });
209
+
210
+ describe('createJob', () => {
211
+ it('creates a job and returns it with computed fields', () => {
212
+ const job = store.createJob({
213
+ name: 'Test Job',
214
+ prompt: 'Summarize my inbox',
215
+ cli: 'claude',
216
+ cronExpr: '0 9 * * *',
217
+ cadence: 'Daily at 9am',
218
+ });
219
+ expect(job.id).toBeTruthy();
220
+ expect(job.name).toBe('Test Job');
221
+ expect(job.prompt).toBe('Summarize my inbox');
222
+ expect(job.cli).toBe('claude');
223
+ expect(job.cronExpr).toBe('0 9 * * *');
224
+ expect(job.state).toBe('active');
225
+ expect(job.nextRunAt).toBeGreaterThan(Date.now() - 60000);
226
+ });
227
+ });
228
+
229
+ describe('listJobs', () => {
230
+ it('returns all non-stopped jobs by default', () => {
231
+ store.createJob({ name: 'A', prompt: 'a', cli: 'claude', cronExpr: '0 * * * *', cadence: 'Hourly' });
232
+ store.createJob({ name: 'B', prompt: 'b', cli: 'codex', cronExpr: '0 9 * * *', cadence: 'Daily' });
233
+ const jobs = store.listJobs();
234
+ expect(jobs).toHaveLength(2);
235
+ });
236
+
237
+ it('filters by state', () => {
238
+ const job = store.createJob({ name: 'A', prompt: 'a', cli: 'claude', cronExpr: '0 * * * *', cadence: '' });
239
+ store.updateJob(job.id, { state: 'paused' });
240
+ expect(store.listJobs({ state: 'active' })).toHaveLength(0);
241
+ expect(store.listJobs({ state: 'paused' })).toHaveLength(1);
242
+ });
243
+ });
244
+
245
+ describe('updateJob', () => {
246
+ it('updates fields and bumps updatedAt', () => {
247
+ const job = store.createJob({ name: 'A', prompt: 'a', cli: 'claude', cronExpr: '0 * * * *', cadence: '' });
248
+ const updated = store.updateJob(job.id, { name: 'B', state: 'paused' });
249
+ expect(updated.name).toBe('B');
250
+ expect(updated.state).toBe('paused');
251
+ });
252
+ });
253
+
254
+ describe('deleteJob', () => {
255
+ it('deletes job and its runs', () => {
256
+ const job = store.createJob({ name: 'A', prompt: 'a', cli: 'claude', cronExpr: '0 * * * *', cadence: '' });
257
+ store.createRun(job.id);
258
+ store.deleteJob(job.id);
259
+ expect(store.listJobs()).toHaveLength(0);
260
+ expect(store.listRuns(job.id)).toHaveLength(0);
261
+ });
262
+ });
263
+
264
+ describe('runs', () => {
265
+ it('creates a run in queued status', () => {
266
+ const job = store.createJob({ name: 'A', prompt: 'a', cli: 'claude', cronExpr: '0 * * * *', cadence: '' });
267
+ const run = store.createRun(job.id);
268
+ expect(run.status).toBe('queued');
269
+ expect(run.jobId).toBe(job.id);
270
+ });
271
+
272
+ it('updates run status and output', () => {
273
+ const job = store.createJob({ name: 'A', prompt: 'a', cli: 'claude', cronExpr: '0 * * * *', cadence: '' });
274
+ const run = store.createRun(job.id);
275
+ const updated = store.updateRun(run.id, {
276
+ status: 'success',
277
+ output: 'Done!',
278
+ durationMs: 1500,
279
+ finishedAt: new Date().toISOString(),
280
+ });
281
+ expect(updated.status).toBe('success');
282
+ expect(updated.output).toBe('Done!');
283
+ });
284
+
285
+ it('lists runs for a job ordered by created_at desc', () => {
286
+ const job = store.createJob({ name: 'A', prompt: 'a', cli: 'claude', cronExpr: '0 * * * *', cadence: '' });
287
+ store.createRun(job.id);
288
+ store.createRun(job.id);
289
+ const runs = store.listRuns(job.id);
290
+ expect(runs).toHaveLength(2);
291
+ });
292
+ });
293
+
294
+ describe('getDueJobs', () => {
295
+ it('returns active jobs where nextRunAt <= now', () => {
296
+ const job = store.createJob({ name: 'A', prompt: 'a', cli: 'claude', cronExpr: '0 * * * *', cadence: '' });
297
+ // Force nextRunAt to the past
298
+ db.prepare('UPDATE prompt_jobs SET next_run_at = ? WHERE id = ?').run(Date.now() - 60000, job.id);
299
+ const due = store.getDueJobs();
300
+ expect(due).toHaveLength(1);
301
+ expect(due[0].id).toBe(job.id);
302
+ });
303
+
304
+ it('skips paused jobs', () => {
305
+ const job = store.createJob({ name: 'A', prompt: 'a', cli: 'claude', cronExpr: '0 * * * *', cadence: '' });
306
+ db.prepare('UPDATE prompt_jobs SET next_run_at = ?, state = ? WHERE id = ?').run(Date.now() - 60000, 'paused', job.id);
307
+ expect(store.getDueJobs()).toHaveLength(0);
308
+ });
309
+ });
310
+
311
+ describe('hasRunningRun', () => {
312
+ it('returns true if job has a running run', () => {
313
+ const job = store.createJob({ name: 'A', prompt: 'a', cli: 'claude', cronExpr: '0 * * * *', cadence: '' });
314
+ const run = store.createRun(job.id);
315
+ store.updateRun(run.id, { status: 'running', startedAt: new Date().toISOString() });
316
+ expect(store.hasRunningRun(job.id)).toBe(true);
317
+ });
318
+
319
+ it('returns false if no running runs', () => {
320
+ const job = store.createJob({ name: 'A', prompt: 'a', cli: 'claude', cronExpr: '0 * * * *', cadence: '' });
321
+ expect(store.hasRunningRun(job.id)).toBe(false);
322
+ });
323
+ });
324
+
325
+ describe('isRunCancelled', () => {
326
+ it('returns false for non-cancelled run', () => {
327
+ const job = store.createJob({ name: 'A', prompt: 'a', cli: 'claude', cronExpr: '0 * * * *', cadence: '' });
328
+ const run = store.createRun(job.id);
329
+ expect(store.isRunCancelled(run.id)).toBe(false);
330
+ });
331
+
332
+ it('returns true for cancelled run', () => {
333
+ const job = store.createJob({ name: 'A', prompt: 'a', cli: 'claude', cronExpr: '0 * * * *', cadence: '' });
334
+ const run = store.createRun(job.id);
335
+ store.updateRun(run.id, { status: 'cancelled', cancelledAt: new Date().toISOString() });
336
+ expect(store.isRunCancelled(run.id)).toBe(true);
337
+ });
338
+ });
339
+ });
340
+ ```
341
+
342
+ - [ ] **Step 2: Run tests to verify they fail**
343
+
344
+ ```bash
345
+ cd /Users/mendrika/Projects/Agents/agx-cloud && npx vitest run __tests__/prompt-scheduler/store.test.ts
346
+ ```
347
+
348
+ Expected: FAIL — `Cannot find module '@/src/prompt-scheduler/store'`
349
+
350
+ - [ ] **Step 3: Implement the store**
351
+
352
+ Create `src/prompt-scheduler/store.ts`:
353
+
354
+ ```typescript
355
+ import Database from 'better-sqlite3';
356
+ import { randomUUID } from 'crypto';
357
+ import type { PromptJob, PromptRun, RunStatus } from './types';
358
+ import { computeNextTickFromCron } from '../graph/scheduler';
359
+
360
+ interface CreateJobInput {
361
+ name: string;
362
+ prompt: string;
363
+ cli: string;
364
+ cronExpr: string;
365
+ cadence: string;
366
+ overlapPolicy?: string;
367
+ cancelCheckSec?: number;
368
+ }
369
+
370
+ interface ListJobsFilter {
371
+ state?: string;
372
+ }
373
+
374
+ interface UpdateRunInput {
375
+ status?: RunStatus;
376
+ output?: string;
377
+ error?: string;
378
+ durationMs?: number;
379
+ startedAt?: string;
380
+ finishedAt?: string;
381
+ cancelledAt?: string;
382
+ }
383
+
384
+ function rowToJob(row: Record<string, unknown>): PromptJob {
385
+ return {
386
+ id: row.id as string,
387
+ name: row.name as string,
388
+ prompt: row.prompt as string,
389
+ cli: row.cli as string,
390
+ cronExpr: row.cron_expr as string,
391
+ cadence: row.cadence as string,
392
+ state: row.state as PromptJob['state'],
393
+ overlapPolicy: row.overlap_policy as PromptJob['overlapPolicy'],
394
+ cancelCheckSec: row.cancel_check_sec as number,
395
+ nextRunAt: row.next_run_at as number | null,
396
+ lastRunAt: row.last_run_at as number | null,
397
+ lastOutcome: row.last_outcome as RunStatus | null,
398
+ createdAt: row.created_at as string,
399
+ updatedAt: row.updated_at as string,
400
+ };
401
+ }
402
+
403
+ function rowToRun(row: Record<string, unknown>): PromptRun {
404
+ return {
405
+ id: row.id as string,
406
+ jobId: row.job_id as string,
407
+ status: row.status as RunStatus,
408
+ output: row.output as string | null,
409
+ error: row.error as string | null,
410
+ durationMs: row.duration_ms as number | null,
411
+ startedAt: row.started_at as string | null,
412
+ finishedAt: row.finished_at as string | null,
413
+ cancelledAt: row.cancelled_at as string | null,
414
+ createdAt: row.created_at as string,
415
+ };
416
+ }
417
+
418
+ export class PromptJobStore {
419
+ constructor(private db: Database.Database) {}
420
+
421
+ createJob(input: CreateJobInput): PromptJob {
422
+ const id = randomUUID();
423
+ const now = new Date().toISOString();
424
+ const nextRunAt = computeNextTickFromCron(input.cronExpr);
425
+
426
+ this.db.prepare(`
427
+ INSERT INTO prompt_jobs (id, name, prompt, cli, cron_expr, cadence, state, overlap_policy, cancel_check_sec, next_run_at, created_at, updated_at)
428
+ VALUES (?, ?, ?, ?, ?, ?, 'active', ?, ?, ?, ?, ?)
429
+ `).run(
430
+ id,
431
+ input.name,
432
+ input.prompt,
433
+ input.cli,
434
+ input.cronExpr,
435
+ input.cadence,
436
+ input.overlapPolicy ?? 'skip',
437
+ input.cancelCheckSec ?? 5,
438
+ nextRunAt,
439
+ now,
440
+ now,
441
+ );
442
+
443
+ return this.getJob(id)!;
444
+ }
445
+
446
+ getJob(id: string): PromptJob | null {
447
+ const row = this.db.prepare('SELECT * FROM prompt_jobs WHERE id = ?').get(id) as Record<string, unknown> | undefined;
448
+ return row ? rowToJob(row) : null;
449
+ }
450
+
451
+ listJobs(filter?: ListJobsFilter): PromptJob[] {
452
+ if (filter?.state) {
453
+ return (this.db.prepare('SELECT * FROM prompt_jobs WHERE state = ? ORDER BY created_at DESC').all(filter.state) as Record<string, unknown>[]).map(rowToJob);
454
+ }
455
+ return (this.db.prepare('SELECT * FROM prompt_jobs ORDER BY created_at DESC').all() as Record<string, unknown>[]).map(rowToJob);
456
+ }
457
+
458
+ updateJob(id: string, updates: Record<string, unknown>): PromptJob {
459
+ const sets: string[] = [];
460
+ const values: unknown[] = [];
461
+
462
+ const fieldMap: Record<string, string> = {
463
+ name: 'name',
464
+ prompt: 'prompt',
465
+ cli: 'cli',
466
+ cronExpr: 'cron_expr',
467
+ cadence: 'cadence',
468
+ state: 'state',
469
+ overlapPolicy: 'overlap_policy',
470
+ cancelCheckSec: 'cancel_check_sec',
471
+ nextRunAt: 'next_run_at',
472
+ lastRunAt: 'last_run_at',
473
+ lastOutcome: 'last_outcome',
474
+ };
475
+
476
+ for (const [key, val] of Object.entries(updates)) {
477
+ const col = fieldMap[key];
478
+ if (col) {
479
+ sets.push(`${col} = ?`);
480
+ values.push(val);
481
+ }
482
+ }
483
+
484
+ if (sets.length === 0) return this.getJob(id)!;
485
+
486
+ sets.push("updated_at = datetime('now')");
487
+ values.push(id);
488
+
489
+ this.db.prepare(`UPDATE prompt_jobs SET ${sets.join(', ')} WHERE id = ?`).run(...values);
490
+ return this.getJob(id)!;
491
+ }
492
+
493
+ deleteJob(id: string): void {
494
+ this.db.prepare('DELETE FROM prompt_jobs WHERE id = ?').run(id);
495
+ }
496
+
497
+ getDueJobs(now: number = Date.now()): PromptJob[] {
498
+ return (this.db.prepare(
499
+ "SELECT * FROM prompt_jobs WHERE state = 'active' AND next_run_at IS NOT NULL AND next_run_at <= ?"
500
+ ).all(now) as Record<string, unknown>[]).map(rowToJob);
501
+ }
502
+
503
+ createRun(jobId: string): PromptRun {
504
+ const id = randomUUID();
505
+ const now = new Date().toISOString();
506
+ this.db.prepare(`
507
+ INSERT INTO prompt_runs (id, job_id, status, created_at)
508
+ VALUES (?, ?, 'queued', ?)
509
+ `).run(id, jobId, now);
510
+ return this.getRun(id)!;
511
+ }
512
+
513
+ getRun(id: string): PromptRun | null {
514
+ const row = this.db.prepare('SELECT * FROM prompt_runs WHERE id = ?').get(id) as Record<string, unknown> | undefined;
515
+ return row ? rowToRun(row) : null;
516
+ }
517
+
518
+ listRuns(jobId: string, limit: number = 50): PromptRun[] {
519
+ return (this.db.prepare(
520
+ 'SELECT * FROM prompt_runs WHERE job_id = ? ORDER BY created_at DESC LIMIT ?'
521
+ ).all(jobId, limit) as Record<string, unknown>[]).map(rowToRun);
522
+ }
523
+
524
+ updateRun(id: string, updates: UpdateRunInput): PromptRun {
525
+ const sets: string[] = [];
526
+ const values: unknown[] = [];
527
+
528
+ const fieldMap: Record<string, string> = {
529
+ status: 'status',
530
+ output: 'output',
531
+ error: 'error',
532
+ durationMs: 'duration_ms',
533
+ startedAt: 'started_at',
534
+ finishedAt: 'finished_at',
535
+ cancelledAt: 'cancelled_at',
536
+ };
537
+
538
+ for (const [key, val] of Object.entries(updates)) {
539
+ const col = fieldMap[key];
540
+ if (col) {
541
+ sets.push(`${col} = ?`);
542
+ values.push(val);
543
+ }
544
+ }
545
+
546
+ if (sets.length === 0) return this.getRun(id)!;
547
+ values.push(id);
548
+
549
+ this.db.prepare(`UPDATE prompt_runs SET ${sets.join(', ')} WHERE id = ?`).run(...values);
550
+ return this.getRun(id)!;
551
+ }
552
+
553
+ hasRunningRun(jobId: string): boolean {
554
+ const row = this.db.prepare(
555
+ "SELECT 1 FROM prompt_runs WHERE job_id = ? AND status IN ('queued', 'running') LIMIT 1"
556
+ ).get(jobId);
557
+ return !!row;
558
+ }
559
+
560
+ isRunCancelled(runId: string): boolean {
561
+ const row = this.db.prepare(
562
+ "SELECT 1 FROM prompt_runs WHERE id = ? AND status = 'cancelled'"
563
+ ).get(runId);
564
+ return !!row;
565
+ }
566
+ }
567
+ ```
568
+
569
+ - [ ] **Step 4: Run tests to verify they pass**
570
+
571
+ ```bash
572
+ cd /Users/mendrika/Projects/Agents/agx-cloud && npx vitest run __tests__/prompt-scheduler/store.test.ts
573
+ ```
574
+
575
+ Expected: All tests PASS
576
+
577
+ - [ ] **Step 5: Commit**
578
+
579
+ ```bash
580
+ git add src/prompt-scheduler/store.ts __tests__/prompt-scheduler/store.test.ts
581
+ git commit -m "feat: add PromptJobStore with CRUD for jobs and runs"
582
+ ```
583
+
584
+ ---
585
+
586
+ ## Task 3: Cron Module — parsing and next-run computation
587
+
588
+ **Files:**
589
+ - Create: `src/prompt-scheduler/cron.ts`
590
+ - Create: `__tests__/prompt-scheduler/cron.test.ts`
591
+
592
+ - [ ] **Step 1: Write failing tests**
593
+
594
+ Create `__tests__/prompt-scheduler/cron.test.ts`:
595
+
596
+ ```typescript
597
+ import { describe, it, expect } from 'vitest';
598
+ import { parseCadence, computeNextRun } from '@/src/prompt-scheduler/cron';
599
+
600
+ describe('parseCadence', () => {
601
+ it('parses natural language to cron', () => {
602
+ const result = parseCadence('daily at 9am');
603
+ expect(result).not.toBeNull();
604
+ expect(result!.cronExpr).toBe('0 9 * * *');
605
+ expect(result!.cadence).toBe('Daily at 9:00 AM');
606
+ });
607
+
608
+ it('passes through valid cron expressions', () => {
609
+ const result = parseCadence('*/15 * * * *');
610
+ expect(result).not.toBeNull();
611
+ expect(result!.cronExpr).toBe('*/15 * * * *');
612
+ });
613
+
614
+ it('parses "every 2 hours"', () => {
615
+ const result = parseCadence('every 2 hours');
616
+ expect(result).not.toBeNull();
617
+ expect(result!.cronExpr).toBe('0 */2 * * *');
618
+ });
619
+
620
+ it('parses "weekdays at 3pm"', () => {
621
+ const result = parseCadence('weekdays at 3pm');
622
+ expect(result).not.toBeNull();
623
+ expect(result!.cronExpr).toBe('0 15 * * 1-5');
624
+ });
625
+
626
+ it('returns null for unparseable input', () => {
627
+ expect(parseCadence('whenever the moon is full')).toBeNull();
628
+ });
629
+ });
630
+
631
+ describe('computeNextRun', () => {
632
+ it('returns a future timestamp for a valid cron expression', () => {
633
+ const next = computeNextRun('* * * * *');
634
+ expect(next).toBeGreaterThan(Date.now());
635
+ });
636
+
637
+ it('returns a future timestamp for daily at 9am', () => {
638
+ const next = computeNextRun('0 9 * * *');
639
+ expect(next).toBeGreaterThan(Date.now() - 86400000);
640
+ });
641
+
642
+ it('returns null for invalid cron', () => {
643
+ expect(computeNextRun('not a cron')).toBeNull();
644
+ });
645
+ });
646
+ ```
647
+
648
+ - [ ] **Step 2: Run tests to verify they fail**
649
+
650
+ ```bash
651
+ cd /Users/mendrika/Projects/Agents/agx-cloud && npx vitest run __tests__/prompt-scheduler/cron.test.ts
652
+ ```
653
+
654
+ Expected: FAIL — `Cannot find module '@/src/prompt-scheduler/cron'`
655
+
656
+ - [ ] **Step 3: Implement the cron module**
657
+
658
+ Create `src/prompt-scheduler/cron.ts`:
659
+
660
+ ```typescript
661
+ import { toCronExpr } from '../graph/nl-schedule';
662
+
663
+ export interface ParsedCadence {
664
+ cronExpr: string;
665
+ cadence: string;
666
+ }
667
+
668
+ export function parseCadence(input: string): ParsedCadence | null {
669
+ const trimmed = input.trim();
670
+ if (!trimmed) return null;
671
+
672
+ const nlResult = toCronExpr(trimmed);
673
+ if (nlResult) {
674
+ return { cronExpr: nlResult.cronExpr, cadence: nlResult.cadence };
675
+ }
676
+
677
+ // Try parsing as raw cron (5 fields)
678
+ if (isValidCron(trimmed)) {
679
+ return { cronExpr: trimmed, cadence: trimmed };
680
+ }
681
+
682
+ return null;
683
+ }
684
+
685
+ export function computeNextRun(cronExpr: string, fromMs?: number): number | null {
686
+ try {
687
+ const { parseExpression } = require('cron-parser');
688
+ const interval = parseExpression(cronExpr, {
689
+ currentDate: fromMs ? new Date(fromMs) : new Date(),
690
+ });
691
+ return interval.next().getTime();
692
+ } catch {
693
+ return null;
694
+ }
695
+ }
696
+
697
+ function isValidCron(expr: string): boolean {
698
+ const parts = expr.split(/\s+/);
699
+ if (parts.length !== 5) return false;
700
+ try {
701
+ const { parseExpression } = require('cron-parser');
702
+ parseExpression(expr);
703
+ return true;
704
+ } catch {
705
+ return false;
706
+ }
707
+ }
708
+ ```
709
+
710
+ - [ ] **Step 4: Run tests to verify they pass**
711
+
712
+ ```bash
713
+ cd /Users/mendrika/Projects/Agents/agx-cloud && npx vitest run __tests__/prompt-scheduler/cron.test.ts
714
+ ```
715
+
716
+ Expected: All tests PASS
717
+
718
+ - [ ] **Step 5: Commit**
719
+
720
+ ```bash
721
+ git add src/prompt-scheduler/cron.ts __tests__/prompt-scheduler/cron.test.ts
722
+ git commit -m "feat: add cron parsing module wrapping nl-schedule + cron-parser"
723
+ ```
724
+
725
+ ---
726
+
727
+ ## Task 4: Engine — find due jobs, create runs, advance schedule
728
+
729
+ **Files:**
730
+ - Create: `src/prompt-scheduler/engine.ts`
731
+ - Create: `__tests__/prompt-scheduler/engine.test.ts`
732
+
733
+ - [ ] **Step 1: Write failing tests**
734
+
735
+ Create `__tests__/prompt-scheduler/engine.test.ts`:
736
+
737
+ ```typescript
738
+ import Database from 'better-sqlite3';
739
+ import { describe, it, expect, beforeEach } from 'vitest';
740
+ import { PromptJobStore } from '@/src/prompt-scheduler/store';
741
+ import { pollDueJobs } from '@/src/prompt-scheduler/engine';
742
+ import { readFileSync } from 'fs';
743
+ import path from 'path';
744
+
745
+ function createTestDb(): Database.Database {
746
+ const db = new Database(':memory:');
747
+ db.exec(readFileSync(path.join(__dirname, '../../db/sqlite/001_agx_board_schema.sql'), 'utf-8'));
748
+ db.exec(readFileSync(path.join(__dirname, '../../db/sqlite/002_prompt_scheduler_schema.sql'), 'utf-8'));
749
+ return db;
750
+ }
751
+
752
+ describe('pollDueJobs', () => {
753
+ let db: Database.Database;
754
+ let store: PromptJobStore;
755
+
756
+ beforeEach(() => {
757
+ db = createTestDb();
758
+ store = new PromptJobStore(db);
759
+ });
760
+
761
+ it('creates runs for due jobs and advances nextRunAt', () => {
762
+ const job = store.createJob({ name: 'A', prompt: 'hello', cli: 'claude', cronExpr: '* * * * *', cadence: '' });
763
+ db.prepare('UPDATE prompt_jobs SET next_run_at = ? WHERE id = ?').run(Date.now() - 60000, job.id);
764
+
765
+ const result = pollDueJobs(store);
766
+
767
+ expect(result.queued).toHaveLength(1);
768
+ expect(result.queued[0].jobId).toBe(job.id);
769
+ expect(result.queued[0].status).toBe('queued');
770
+
771
+ const updated = store.getJob(job.id)!;
772
+ expect(updated.nextRunAt).toBeGreaterThan(Date.now() - 1000);
773
+ });
774
+
775
+ it('skips jobs with overlap_policy=skip when a run is active', () => {
776
+ const job = store.createJob({ name: 'A', prompt: 'hello', cli: 'claude', cronExpr: '* * * * *', cadence: '' });
777
+ db.prepare('UPDATE prompt_jobs SET next_run_at = ? WHERE id = ?').run(Date.now() - 60000, job.id);
778
+
779
+ const run = store.createRun(job.id);
780
+ store.updateRun(run.id, { status: 'running', startedAt: new Date().toISOString() });
781
+
782
+ const result = pollDueJobs(store);
783
+ expect(result.queued).toHaveLength(0);
784
+ expect(result.skipped).toHaveLength(1);
785
+ });
786
+
787
+ it('queues jobs with overlap_policy=allow even when running', () => {
788
+ const job = store.createJob({ name: 'A', prompt: 'hello', cli: 'claude', cronExpr: '* * * * *', cadence: '' });
789
+ store.updateJob(job.id, { overlapPolicy: 'allow' });
790
+ db.prepare('UPDATE prompt_jobs SET next_run_at = ? WHERE id = ?').run(Date.now() - 60000, job.id);
791
+
792
+ const run = store.createRun(job.id);
793
+ store.updateRun(run.id, { status: 'running', startedAt: new Date().toISOString() });
794
+
795
+ const result = pollDueJobs(store);
796
+ expect(result.queued).toHaveLength(1);
797
+ });
798
+
799
+ it('returns empty when no jobs are due', () => {
800
+ store.createJob({ name: 'A', prompt: 'hello', cli: 'claude', cronExpr: '0 9 * * *', cadence: '' });
801
+ const result = pollDueJobs(store);
802
+ expect(result.queued).toHaveLength(0);
803
+ expect(result.skipped).toHaveLength(0);
804
+ });
805
+ });
806
+ ```
807
+
808
+ - [ ] **Step 2: Run tests to verify they fail**
809
+
810
+ ```bash
811
+ cd /Users/mendrika/Projects/Agents/agx-cloud && npx vitest run __tests__/prompt-scheduler/engine.test.ts
812
+ ```
813
+
814
+ Expected: FAIL — `Cannot find module '@/src/prompt-scheduler/engine'`
815
+
816
+ - [ ] **Step 3: Implement the engine**
817
+
818
+ Create `src/prompt-scheduler/engine.ts`:
819
+
820
+ ```typescript
821
+ import type { PromptRun } from './types';
822
+ import type { PromptJobStore } from './store';
823
+ import { computeNextRun } from './cron';
824
+
825
+ export interface PollResult {
826
+ queued: PromptRun[];
827
+ skipped: Array<{ jobId: string; reason: string }>;
828
+ }
829
+
830
+ export function pollDueJobs(store: PromptJobStore, now: number = Date.now()): PollResult {
831
+ const dueJobs = store.getDueJobs(now);
832
+ const queued: PromptRun[] = [];
833
+ const skipped: Array<{ jobId: string; reason: string }> = [];
834
+
835
+ for (const job of dueJobs) {
836
+ if (job.overlapPolicy === 'skip' && store.hasRunningRun(job.id)) {
837
+ skipped.push({ jobId: job.id, reason: 'overlap_skip' });
838
+ // Still advance nextRunAt so we don't re-check this tick
839
+ const nextRunAt = computeNextRun(job.cronExpr, now);
840
+ store.updateJob(job.id, { nextRunAt });
841
+ continue;
842
+ }
843
+
844
+ const run = store.createRun(job.id);
845
+ queued.push(run);
846
+
847
+ const nextRunAt = computeNextRun(job.cronExpr, now);
848
+ store.updateJob(job.id, {
849
+ nextRunAt,
850
+ lastRunAt: now,
851
+ });
852
+ }
853
+
854
+ return { queued, skipped };
855
+ }
856
+ ```
857
+
858
+ - [ ] **Step 4: Run tests to verify they pass**
859
+
860
+ ```bash
861
+ cd /Users/mendrika/Projects/Agents/agx-cloud && npx vitest run __tests__/prompt-scheduler/engine.test.ts
862
+ ```
863
+
864
+ Expected: All tests PASS
865
+
866
+ - [ ] **Step 5: Commit**
867
+
868
+ ```bash
869
+ git add src/prompt-scheduler/engine.ts __tests__/prompt-scheduler/engine.test.ts
870
+ git commit -m "feat: add poll engine — finds due jobs, handles overlap, creates runs"
871
+ ```
872
+
873
+ ---
874
+
875
+ ## Task 5: Runner — CLI execution with cancel checking
876
+
877
+ **Files:**
878
+ - Create: `src/prompt-scheduler/runner.ts`
879
+ - Create: `__tests__/prompt-scheduler/runner.test.ts`
880
+
881
+ - [ ] **Step 1: Write failing tests**
882
+
883
+ Create `__tests__/prompt-scheduler/runner.test.ts`:
884
+
885
+ ```typescript
886
+ import { describe, it, expect, vi } from 'vitest';
887
+ import { buildCliCommand, executeRun } from '@/src/prompt-scheduler/runner';
888
+
889
+ describe('buildCliCommand', () => {
890
+ it('builds claude command', () => {
891
+ const { cmd, args } = buildCliCommand('claude', 'summarize inbox');
892
+ expect(cmd).toBe('claude');
893
+ expect(args).toEqual(['-p', 'summarize inbox']);
894
+ });
895
+
896
+ it('builds codex command', () => {
897
+ const { cmd, args } = buildCliCommand('codex', 'fix the bug');
898
+ expect(cmd).toBe('codex');
899
+ expect(args).toEqual(['-p', 'fix the bug']);
900
+ });
901
+
902
+ it('builds gemini command', () => {
903
+ const { cmd, args } = buildCliCommand('gemini', 'review PR');
904
+ expect(cmd).toBe('gemini');
905
+ expect(args).toEqual(['-p', 'review PR']);
906
+ });
907
+
908
+ it('builds custom cli command with {prompt} template', () => {
909
+ const { cmd, args } = buildCliCommand('my-cli run --input {prompt}', 'hello world');
910
+ expect(cmd).toBe('my-cli');
911
+ expect(args).toEqual(['run', '--input', 'hello world']);
912
+ });
913
+ });
914
+
915
+ describe('executeRun', () => {
916
+ it('calls onStart, onComplete callbacks', async () => {
917
+ const onStart = vi.fn();
918
+ const onComplete = vi.fn();
919
+ const isCancelled = vi.fn().mockResolvedValue(false);
920
+
921
+ // Use echo as a simple CLI that exits immediately
922
+ await executeRun({
923
+ cli: 'echo',
924
+ prompt: 'hello',
925
+ cancelCheckSec: 1,
926
+ isCancelled,
927
+ onStart,
928
+ onComplete,
929
+ });
930
+
931
+ expect(onStart).toHaveBeenCalledOnce();
932
+ expect(onComplete).toHaveBeenCalledOnce();
933
+ expect(onComplete).toHaveBeenCalledWith(
934
+ expect.objectContaining({
935
+ status: 'success',
936
+ output: expect.stringContaining('hello'),
937
+ })
938
+ );
939
+ });
940
+
941
+ it('cancels when isCancelled returns true', async () => {
942
+ const onStart = vi.fn();
943
+ const onComplete = vi.fn();
944
+ // Return true on second call to cancel mid-run
945
+ const isCancelled = vi.fn()
946
+ .mockResolvedValueOnce(false)
947
+ .mockResolvedValue(true);
948
+
949
+ await executeRun({
950
+ cli: 'sleep',
951
+ prompt: '10',
952
+ cancelCheckSec: 0.1,
953
+ isCancelled,
954
+ onStart,
955
+ onComplete,
956
+ });
957
+
958
+ expect(onComplete).toHaveBeenCalledWith(
959
+ expect.objectContaining({ status: 'cancelled' })
960
+ );
961
+ });
962
+ });
963
+ ```
964
+
965
+ - [ ] **Step 2: Run tests to verify they fail**
966
+
967
+ ```bash
968
+ cd /Users/mendrika/Projects/Agents/agx-cloud && npx vitest run __tests__/prompt-scheduler/runner.test.ts
969
+ ```
970
+
971
+ Expected: FAIL — `Cannot find module '@/src/prompt-scheduler/runner'`
972
+
973
+ - [ ] **Step 3: Implement the runner**
974
+
975
+ Create `src/prompt-scheduler/runner.ts`:
976
+
977
+ ```typescript
978
+ import { spawn, type ChildProcess } from 'child_process';
979
+
980
+ const KNOWN_CLIS: Record<string, string[]> = {
981
+ claude: ['-p'],
982
+ codex: ['-p'],
983
+ gemini: ['-p'],
984
+ };
985
+
986
+ export function buildCliCommand(cli: string, prompt: string): { cmd: string; args: string[] } {
987
+ const knownFlags = KNOWN_CLIS[cli];
988
+ if (knownFlags) {
989
+ return { cmd: cli, args: [...knownFlags, prompt] };
990
+ }
991
+
992
+ // Custom CLI with {prompt} template
993
+ if (cli.includes('{prompt}')) {
994
+ const parts = cli.replace('{prompt}', prompt).split(/\s+/);
995
+ return { cmd: parts[0], args: parts.slice(1) };
996
+ }
997
+
998
+ // Custom CLI: append prompt as last arg
999
+ const parts = cli.split(/\s+/);
1000
+ return { cmd: parts[0], args: [...parts.slice(1), prompt] };
1001
+ }
1002
+
1003
+ export interface RunResult {
1004
+ status: 'success' | 'failed' | 'cancelled';
1005
+ output: string;
1006
+ error: string;
1007
+ durationMs: number;
1008
+ }
1009
+
1010
+ export interface ExecuteRunOptions {
1011
+ cli: string;
1012
+ prompt: string;
1013
+ cancelCheckSec: number;
1014
+ isCancelled: () => Promise<boolean>;
1015
+ onStart: () => void;
1016
+ onComplete: (result: RunResult) => void;
1017
+ }
1018
+
1019
+ export async function executeRun(opts: ExecuteRunOptions): Promise<void> {
1020
+ const { cli, prompt, cancelCheckSec, isCancelled, onStart, onComplete } = opts;
1021
+ const { cmd, args } = buildCliCommand(cli, prompt);
1022
+ const startTime = Date.now();
1023
+
1024
+ opts.onStart();
1025
+
1026
+ return new Promise<void>((resolve) => {
1027
+ let stdout = '';
1028
+ let stderr = '';
1029
+ let killed = false;
1030
+
1031
+ const child: ChildProcess = spawn(cmd, args, {
1032
+ stdio: ['ignore', 'pipe', 'pipe'],
1033
+ shell: false,
1034
+ });
1035
+
1036
+ child.stdout?.on('data', (data: Buffer) => {
1037
+ stdout += data.toString();
1038
+ });
1039
+
1040
+ child.stderr?.on('data', (data: Buffer) => {
1041
+ stderr += data.toString();
1042
+ });
1043
+
1044
+ const cancelInterval = setInterval(async () => {
1045
+ try {
1046
+ if (await isCancelled()) {
1047
+ killed = true;
1048
+ child.kill('SIGTERM');
1049
+ clearInterval(cancelInterval);
1050
+ }
1051
+ } catch {
1052
+ // ignore cancel check errors
1053
+ }
1054
+ }, cancelCheckSec * 1000);
1055
+
1056
+ child.on('close', (code) => {
1057
+ clearInterval(cancelInterval);
1058
+ const durationMs = Date.now() - startTime;
1059
+
1060
+ if (killed) {
1061
+ onComplete({ status: 'cancelled', output: stdout, error: stderr, durationMs });
1062
+ } else if (code === 0) {
1063
+ onComplete({ status: 'success', output: stdout, error: stderr, durationMs });
1064
+ } else {
1065
+ onComplete({ status: 'failed', output: stdout, error: stderr || `Exit code ${code}`, durationMs });
1066
+ }
1067
+ resolve();
1068
+ });
1069
+
1070
+ child.on('error', (err) => {
1071
+ clearInterval(cancelInterval);
1072
+ const durationMs = Date.now() - startTime;
1073
+ onComplete({ status: 'failed', output: stdout, error: err.message, durationMs });
1074
+ resolve();
1075
+ });
1076
+ });
1077
+ }
1078
+ ```
1079
+
1080
+ - [ ] **Step 4: Run tests to verify they pass**
1081
+
1082
+ ```bash
1083
+ cd /Users/mendrika/Projects/Agents/agx-cloud && npx vitest run __tests__/prompt-scheduler/runner.test.ts
1084
+ ```
1085
+
1086
+ Expected: All tests PASS
1087
+
1088
+ - [ ] **Step 5: Commit**
1089
+
1090
+ ```bash
1091
+ git add src/prompt-scheduler/runner.ts __tests__/prompt-scheduler/runner.test.ts
1092
+ git commit -m "feat: add CLI runner with cancel checking and custom CLI templates"
1093
+ ```
1094
+
1095
+ ---
1096
+
1097
+ ## Task 6: API Routes — CRUD + poll + cancel
1098
+
1099
+ **Files:**
1100
+ - Create: `app/api/prompt-jobs/route.ts`
1101
+ - Create: `app/api/prompt-jobs/[id]/route.ts`
1102
+ - Create: `app/api/prompt-jobs/[id]/runs/route.ts`
1103
+ - Create: `app/api/prompt-jobs/[id]/cancel/route.ts`
1104
+ - Create: `app/api/prompt-jobs/poll/route.ts`
1105
+
1106
+ - [ ] **Step 1: Implement list + create endpoint**
1107
+
1108
+ Create `app/api/prompt-jobs/route.ts`:
1109
+
1110
+ ```typescript
1111
+ import { NextRequest, NextResponse } from 'next/server';
1112
+ import { getPromptJobStore } from '@/src/prompt-scheduler/get-store';
1113
+ import { parseCadence, computeNextRun } from '@/src/prompt-scheduler/cron';
1114
+
1115
+ export async function GET(req: NextRequest) {
1116
+ const store = getPromptJobStore();
1117
+ const state = req.nextUrl.searchParams.get('state') ?? undefined;
1118
+ const jobs = store.listJobs(state ? { state } : undefined);
1119
+ return NextResponse.json({ count: jobs.length, jobs });
1120
+ }
1121
+
1122
+ export async function POST(req: NextRequest) {
1123
+ const body = await req.json();
1124
+ const { name, prompt, cli, cadence, overlapPolicy, cancelCheckSec } = body;
1125
+
1126
+ if (!name || !prompt || !cadence) {
1127
+ return NextResponse.json({ error: 'name, prompt, and cadence are required' }, { status: 400 });
1128
+ }
1129
+
1130
+ const parsed = parseCadence(cadence);
1131
+ if (!parsed) {
1132
+ return NextResponse.json({ error: `Could not parse cadence: "${cadence}"` }, { status: 400 });
1133
+ }
1134
+
1135
+ const store = getPromptJobStore();
1136
+ const job = store.createJob({
1137
+ name,
1138
+ prompt,
1139
+ cli: cli ?? 'claude',
1140
+ cronExpr: parsed.cronExpr,
1141
+ cadence: parsed.cadence,
1142
+ overlapPolicy,
1143
+ cancelCheckSec,
1144
+ });
1145
+
1146
+ return NextResponse.json(job, { status: 201 });
1147
+ }
1148
+ ```
1149
+
1150
+ - [ ] **Step 2: Implement get, update, delete endpoint**
1151
+
1152
+ Create `app/api/prompt-jobs/[id]/route.ts`:
1153
+
1154
+ ```typescript
1155
+ import { NextRequest, NextResponse } from 'next/server';
1156
+ import { getPromptJobStore } from '@/src/prompt-scheduler/get-store';
1157
+ import { parseCadence, computeNextRun } from '@/src/prompt-scheduler/cron';
1158
+
1159
+ export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
1160
+ const { id } = await params;
1161
+ const store = getPromptJobStore();
1162
+ const job = store.getJob(id);
1163
+ if (!job) return NextResponse.json({ error: 'Not found' }, { status: 404 });
1164
+ return NextResponse.json(job);
1165
+ }
1166
+
1167
+ export async function PATCH(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
1168
+ const { id } = await params;
1169
+ const store = getPromptJobStore();
1170
+ const job = store.getJob(id);
1171
+ if (!job) return NextResponse.json({ error: 'Not found' }, { status: 404 });
1172
+
1173
+ const body = await req.json();
1174
+ const updates: Record<string, unknown> = {};
1175
+
1176
+ if (body.name !== undefined) updates.name = body.name;
1177
+ if (body.prompt !== undefined) updates.prompt = body.prompt;
1178
+ if (body.cli !== undefined) updates.cli = body.cli;
1179
+ if (body.state !== undefined) updates.state = body.state;
1180
+ if (body.overlapPolicy !== undefined) updates.overlapPolicy = body.overlapPolicy;
1181
+ if (body.cancelCheckSec !== undefined) updates.cancelCheckSec = body.cancelCheckSec;
1182
+
1183
+ if (body.cadence !== undefined) {
1184
+ const parsed = parseCadence(body.cadence);
1185
+ if (!parsed) return NextResponse.json({ error: `Could not parse cadence: "${body.cadence}"` }, { status: 400 });
1186
+ updates.cronExpr = parsed.cronExpr;
1187
+ updates.cadence = parsed.cadence;
1188
+ updates.nextRunAt = computeNextRun(parsed.cronExpr);
1189
+ }
1190
+
1191
+ const updated = store.updateJob(id, updates);
1192
+ return NextResponse.json(updated);
1193
+ }
1194
+
1195
+ export async function DELETE(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
1196
+ const { id } = await params;
1197
+ const store = getPromptJobStore();
1198
+ store.deleteJob(id);
1199
+ return NextResponse.json({ ok: true });
1200
+ }
1201
+ ```
1202
+
1203
+ - [ ] **Step 3: Implement runs endpoint**
1204
+
1205
+ Create `app/api/prompt-jobs/[id]/runs/route.ts`:
1206
+
1207
+ ```typescript
1208
+ import { NextRequest, NextResponse } from 'next/server';
1209
+ import { getPromptJobStore } from '@/src/prompt-scheduler/get-store';
1210
+
1211
+ export async function GET(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
1212
+ const { id } = await params;
1213
+ const store = getPromptJobStore();
1214
+ const runs = store.listRuns(id);
1215
+ return NextResponse.json({ count: runs.length, runs });
1216
+ }
1217
+ ```
1218
+
1219
+ - [ ] **Step 4: Implement cancel endpoint**
1220
+
1221
+ Create `app/api/prompt-jobs/[id]/cancel/route.ts`:
1222
+
1223
+ ```typescript
1224
+ import { NextRequest, NextResponse } from 'next/server';
1225
+ import { getPromptJobStore } from '@/src/prompt-scheduler/get-store';
1226
+
1227
+ export async function POST(_req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
1228
+ const { id } = await params;
1229
+ const store = getPromptJobStore();
1230
+
1231
+ // Find the active run for this job
1232
+ const runs = store.listRuns(id, 1);
1233
+ const activeRun = runs.find(r => r.status === 'running' || r.status === 'queued');
1234
+ if (!activeRun) {
1235
+ return NextResponse.json({ error: 'No active run to cancel' }, { status: 404 });
1236
+ }
1237
+
1238
+ store.updateRun(activeRun.id, {
1239
+ status: 'cancelled',
1240
+ cancelledAt: new Date().toISOString(),
1241
+ });
1242
+
1243
+ return NextResponse.json({ ok: true, runId: activeRun.id });
1244
+ }
1245
+ ```
1246
+
1247
+ - [ ] **Step 5: Implement poll endpoint**
1248
+
1249
+ Create `app/api/prompt-jobs/poll/route.ts`:
1250
+
1251
+ ```typescript
1252
+ import { NextRequest, NextResponse } from 'next/server';
1253
+ import { getPromptJobStore } from '@/src/prompt-scheduler/get-store';
1254
+ import { pollDueJobs } from '@/src/prompt-scheduler/engine';
1255
+ import { executeRun } from '@/src/prompt-scheduler/runner';
1256
+
1257
+ export async function POST(req: NextRequest) {
1258
+ const store = getPromptJobStore();
1259
+ const body = await req.json().catch(() => ({}));
1260
+ const { jobId } = body as { jobId?: string };
1261
+
1262
+ // If specific job requested, force-queue it
1263
+ if (jobId) {
1264
+ const job = store.getJob(jobId);
1265
+ if (!job) return NextResponse.json({ error: 'Job not found' }, { status: 404 });
1266
+ const run = store.createRun(job.id);
1267
+
1268
+ // Execute async — don't block the response
1269
+ executeRunInBackground(store, job.id, run.id, job.cli, job.prompt, job.cancelCheckSec);
1270
+
1271
+ return NextResponse.json({ queued: [run], skipped: [] });
1272
+ }
1273
+
1274
+ // Normal poll: find due jobs
1275
+ const result = pollDueJobs(store);
1276
+
1277
+ // Execute all queued runs in background
1278
+ for (const run of result.queued) {
1279
+ const job = store.getJob(run.jobId);
1280
+ if (!job) continue;
1281
+ executeRunInBackground(store, job.id, run.id, job.cli, job.prompt, job.cancelCheckSec);
1282
+ }
1283
+
1284
+ return NextResponse.json({
1285
+ queued: result.queued.length,
1286
+ skipped: result.skipped.length,
1287
+ details: result,
1288
+ });
1289
+ }
1290
+
1291
+ function executeRunInBackground(
1292
+ store: ReturnType<typeof getPromptJobStore>,
1293
+ jobId: string,
1294
+ runId: string,
1295
+ cli: string,
1296
+ prompt: string,
1297
+ cancelCheckSec: number,
1298
+ ) {
1299
+ executeRun({
1300
+ cli,
1301
+ prompt,
1302
+ cancelCheckSec,
1303
+ isCancelled: async () => store.isRunCancelled(runId),
1304
+ onStart: () => {
1305
+ store.updateRun(runId, { status: 'running', startedAt: new Date().toISOString() });
1306
+ },
1307
+ onComplete: (result) => {
1308
+ store.updateRun(runId, {
1309
+ status: result.status,
1310
+ output: result.output,
1311
+ error: result.error || undefined,
1312
+ durationMs: result.durationMs,
1313
+ finishedAt: new Date().toISOString(),
1314
+ cancelledAt: result.status === 'cancelled' ? new Date().toISOString() : undefined,
1315
+ });
1316
+ store.updateJob(jobId, { lastOutcome: result.status });
1317
+ },
1318
+ }).catch((err) => {
1319
+ store.updateRun(runId, {
1320
+ status: 'failed',
1321
+ error: `Runner error: ${err.message}`,
1322
+ finishedAt: new Date().toISOString(),
1323
+ });
1324
+ store.updateJob(jobId, { lastOutcome: 'failed' });
1325
+ });
1326
+ }
1327
+ ```
1328
+
1329
+ - [ ] **Step 6: Create store accessor**
1330
+
1331
+ Create `src/prompt-scheduler/get-store.ts`:
1332
+
1333
+ ```typescript
1334
+ import { PromptJobStore } from './store';
1335
+ import { getSQLiteDb } from '@/lib/sqlite-query-adapter';
1336
+ import { readFileSync } from 'fs';
1337
+ import path from 'path';
1338
+
1339
+ let _store: PromptJobStore | null = null;
1340
+
1341
+ export function getPromptJobStore(): PromptJobStore {
1342
+ if (!_store) {
1343
+ const db = getSQLiteDb();
1344
+ // Run migration if prompt_jobs table doesn't exist
1345
+ const tableExists = db.prepare(
1346
+ "SELECT 1 FROM sqlite_master WHERE type='table' AND name='prompt_jobs'"
1347
+ ).get();
1348
+ if (!tableExists) {
1349
+ const migration = readFileSync(
1350
+ path.join(process.cwd(), 'db/sqlite/002_prompt_scheduler_schema.sql'),
1351
+ 'utf-8'
1352
+ );
1353
+ db.exec(migration);
1354
+ }
1355
+ _store = new PromptJobStore(db);
1356
+ }
1357
+ return _store;
1358
+ }
1359
+ ```
1360
+
1361
+ - [ ] **Step 7: Commit**
1362
+
1363
+ ```bash
1364
+ git add app/api/prompt-jobs/ src/prompt-scheduler/get-store.ts
1365
+ git commit -m "feat: add API routes for prompt jobs — CRUD, poll, cancel, runs"
1366
+ ```
1367
+
1368
+ ---
1369
+
1370
+ ## Task 7: UI — PromptJobBoard replacing AutomationsBoard
1371
+
1372
+ **Files:**
1373
+ - Create: `components/PromptJobBoard.tsx`
1374
+ - Create: `hooks/usePromptJobs.ts`
1375
+ - Modify: `app/automations/page.tsx`
1376
+
1377
+ - [ ] **Step 1: Create the data hook**
1378
+
1379
+ Create `hooks/usePromptJobs.ts`:
1380
+
1381
+ ```typescript
1382
+ 'use client';
1383
+
1384
+ import { useState, useEffect, useCallback } from 'react';
1385
+ import type { PromptJob, PromptRun } from '@/src/prompt-scheduler/types';
1386
+
1387
+ export interface UsePromptJobsResult {
1388
+ jobs: PromptJob[];
1389
+ loading: boolean;
1390
+ error: string | null;
1391
+ refresh: () => Promise<void>;
1392
+ createJob: (input: { name: string; prompt: string; cli: string; cadence: string }) => Promise<PromptJob | null>;
1393
+ updateJob: (id: string, updates: Record<string, unknown>) => Promise<boolean>;
1394
+ deleteJob: (id: string) => Promise<boolean>;
1395
+ toggleJob: (job: PromptJob) => Promise<boolean>;
1396
+ runNow: (id: string) => Promise<boolean>;
1397
+ cancelRun: (id: string) => Promise<boolean>;
1398
+ fetchRuns: (jobId: string) => Promise<PromptRun[]>;
1399
+ }
1400
+
1401
+ export function usePromptJobs(): UsePromptJobsResult {
1402
+ const [jobs, setJobs] = useState<PromptJob[]>([]);
1403
+ const [loading, setLoading] = useState(true);
1404
+ const [error, setError] = useState<string | null>(null);
1405
+
1406
+ const refresh = useCallback(async () => {
1407
+ try {
1408
+ const res = await fetch('/api/prompt-jobs');
1409
+ const data = await res.json();
1410
+ setJobs(data.jobs);
1411
+ setError(null);
1412
+ } catch (e) {
1413
+ setError(e instanceof Error ? e.message : 'Failed to fetch');
1414
+ } finally {
1415
+ setLoading(false);
1416
+ }
1417
+ }, []);
1418
+
1419
+ useEffect(() => {
1420
+ refresh();
1421
+ const interval = setInterval(refresh, 10_000);
1422
+ return () => clearInterval(interval);
1423
+ }, [refresh]);
1424
+
1425
+ const createJob = async (input: { name: string; prompt: string; cli: string; cadence: string }) => {
1426
+ try {
1427
+ const res = await fetch('/api/prompt-jobs', {
1428
+ method: 'POST',
1429
+ headers: { 'Content-Type': 'application/json' },
1430
+ body: JSON.stringify(input),
1431
+ });
1432
+ if (!res.ok) {
1433
+ const data = await res.json();
1434
+ setError(data.error || 'Failed to create');
1435
+ return null;
1436
+ }
1437
+ const job = await res.json();
1438
+ await refresh();
1439
+ return job;
1440
+ } catch {
1441
+ return null;
1442
+ }
1443
+ };
1444
+
1445
+ const updateJob = async (id: string, updates: Record<string, unknown>) => {
1446
+ try {
1447
+ const res = await fetch(`/api/prompt-jobs/${id}`, {
1448
+ method: 'PATCH',
1449
+ headers: { 'Content-Type': 'application/json' },
1450
+ body: JSON.stringify(updates),
1451
+ });
1452
+ if (res.ok) { await refresh(); return true; }
1453
+ return false;
1454
+ } catch { return false; }
1455
+ };
1456
+
1457
+ const deleteJob = async (id: string) => {
1458
+ try {
1459
+ const res = await fetch(`/api/prompt-jobs/${id}`, { method: 'DELETE' });
1460
+ if (res.ok) { await refresh(); return true; }
1461
+ return false;
1462
+ } catch { return false; }
1463
+ };
1464
+
1465
+ const toggleJob = async (job: PromptJob) => {
1466
+ const newState = job.state === 'active' ? 'paused' : 'active';
1467
+ return updateJob(job.id, { state: newState });
1468
+ };
1469
+
1470
+ const runNow = async (id: string) => {
1471
+ try {
1472
+ const res = await fetch('/api/prompt-jobs/poll', {
1473
+ method: 'POST',
1474
+ headers: { 'Content-Type': 'application/json' },
1475
+ body: JSON.stringify({ jobId: id }),
1476
+ });
1477
+ if (res.ok) { setTimeout(refresh, 1000); return true; }
1478
+ return false;
1479
+ } catch { return false; }
1480
+ };
1481
+
1482
+ const cancelRun = async (id: string) => {
1483
+ try {
1484
+ const res = await fetch(`/api/prompt-jobs/${id}/cancel`, { method: 'POST' });
1485
+ if (res.ok) { await refresh(); return true; }
1486
+ return false;
1487
+ } catch { return false; }
1488
+ };
1489
+
1490
+ const fetchRuns = async (jobId: string): Promise<PromptRun[]> => {
1491
+ try {
1492
+ const res = await fetch(`/api/prompt-jobs/${jobId}/runs`);
1493
+ const data = await res.json();
1494
+ return data.runs;
1495
+ } catch { return []; }
1496
+ };
1497
+
1498
+ return { jobs, loading, error, refresh, createJob, updateJob, deleteJob, toggleJob, runNow, cancelRun, fetchRuns };
1499
+ }
1500
+ ```
1501
+
1502
+ - [ ] **Step 2: Create the board component**
1503
+
1504
+ Create `components/PromptJobBoard.tsx`:
1505
+
1506
+ ```tsx
1507
+ 'use client';
1508
+
1509
+ import { useState } from 'react';
1510
+ import { usePromptJobs } from '@/hooks/usePromptJobs';
1511
+ import type { PromptJob, PromptRun, PromptJobState } from '@/src/prompt-scheduler/types';
1512
+ import { Play, Pause, Trash2, Plus, X, Clock, Terminal, RefreshCw } from 'lucide-react';
1513
+
1514
+ type FilterState = 'all' | PromptJobState;
1515
+
1516
+ export default function PromptJobBoard() {
1517
+ const { jobs, loading, error, createJob, deleteJob, toggleJob, runNow, cancelRun, fetchRuns, refresh } = usePromptJobs();
1518
+ const [filter, setFilter] = useState<FilterState>('all');
1519
+ const [showCreate, setShowCreate] = useState(false);
1520
+ const [selectedJobId, setSelectedJobId] = useState<string | null>(null);
1521
+ const [runs, setRuns] = useState<PromptRun[]>([]);
1522
+ const [busy, setBusy] = useState<Set<string>>(new Set());
1523
+
1524
+ const filtered = filter === 'all' ? jobs : jobs.filter(j => j.state === filter);
1525
+ const counts = {
1526
+ all: jobs.length,
1527
+ active: jobs.filter(j => j.state === 'active').length,
1528
+ paused: jobs.filter(j => j.state === 'paused').length,
1529
+ stopped: jobs.filter(j => j.state === 'stopped').length,
1530
+ };
1531
+
1532
+ const selectJob = async (id: string) => {
1533
+ setSelectedJobId(id);
1534
+ const r = await fetchRuns(id);
1535
+ setRuns(r);
1536
+ };
1537
+
1538
+ const withBusy = async (id: string, fn: () => Promise<unknown>) => {
1539
+ setBusy(prev => new Set(prev).add(id));
1540
+ try { await fn(); } finally {
1541
+ setBusy(prev => { const next = new Set(prev); next.delete(id); return next; });
1542
+ }
1543
+ };
1544
+
1545
+ if (loading) return <div className="p-8 text-[var(--muted-foreground)]">Loading...</div>;
1546
+
1547
+ return (
1548
+ <div className="flex h-full">
1549
+ {/* Main panel */}
1550
+ <div className="flex-1 p-6 overflow-auto">
1551
+ <div className="flex items-center justify-between mb-6">
1552
+ <h1 className="text-xl font-semibold text-[var(--foreground)]">Prompt Scheduler</h1>
1553
+ <div className="flex gap-2">
1554
+ <button onClick={refresh} className="p-2 rounded hover:bg-[var(--card-bg)]">
1555
+ <RefreshCw size={16} className="text-[var(--muted-foreground)]" />
1556
+ </button>
1557
+ <button onClick={() => setShowCreate(true)} className="flex items-center gap-1.5 px-3 py-1.5 rounded bg-[var(--primary)] text-white text-sm">
1558
+ <Plus size={14} /> New Job
1559
+ </button>
1560
+ </div>
1561
+ </div>
1562
+
1563
+ {error && <div className="mb-4 p-3 rounded bg-red-500/10 text-red-400 text-sm">{error}</div>}
1564
+
1565
+ {/* Filter pills */}
1566
+ <div className="flex gap-2 mb-4">
1567
+ {(['all', 'active', 'paused', 'stopped'] as FilterState[]).map(f => (
1568
+ <button
1569
+ key={f}
1570
+ onClick={() => setFilter(f)}
1571
+ className={`px-3 py-1 rounded-full text-xs font-medium ${filter === f ? 'bg-[var(--primary)] text-white' : 'bg-[var(--card-bg)] text-[var(--muted-foreground)]'}`}
1572
+ >
1573
+ {f} ({counts[f]})
1574
+ </button>
1575
+ ))}
1576
+ </div>
1577
+
1578
+ {/* Job cards */}
1579
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-3">
1580
+ {filtered.map(job => (
1581
+ <div
1582
+ key={job.id}
1583
+ onClick={() => selectJob(job.id)}
1584
+ className={`p-4 rounded-lg border cursor-pointer transition-colors ${selectedJobId === job.id ? 'border-[var(--primary)] bg-[var(--primary)]/5' : 'border-[var(--card-border)] bg-[var(--card-bg)] hover:border-[var(--muted-foreground)]/30'}`}
1585
+ >
1586
+ <div className="flex items-start justify-between mb-2">
1587
+ <div>
1588
+ <h3 className="font-medium text-sm text-[var(--foreground)]">{job.name}</h3>
1589
+ <p className="text-xs text-[var(--muted-foreground)] mt-0.5">{job.cadence || job.cronExpr}</p>
1590
+ </div>
1591
+ <div className="flex items-center gap-1">
1592
+ <span className={`px-2 py-0.5 rounded text-xs font-medium ${
1593
+ job.state === 'active' ? 'bg-green-500/10 text-green-400' :
1594
+ job.state === 'paused' ? 'bg-yellow-500/10 text-yellow-400' :
1595
+ 'bg-gray-500/10 text-gray-400'
1596
+ }`}>
1597
+ {job.state}
1598
+ </span>
1599
+ </div>
1600
+ </div>
1601
+
1602
+ <p className="text-xs text-[var(--muted-foreground)] truncate mb-3">{job.prompt}</p>
1603
+
1604
+ <div className="flex items-center justify-between">
1605
+ <div className="flex items-center gap-2 text-xs text-[var(--muted-foreground)]">
1606
+ <Terminal size={12} />
1607
+ <span>{job.cli}</span>
1608
+ {job.nextRunAt && (
1609
+ <>
1610
+ <Clock size={12} className="ml-2" />
1611
+ <span>{formatNextRun(job.nextRunAt)}</span>
1612
+ </>
1613
+ )}
1614
+ </div>
1615
+ <div className="flex gap-1">
1616
+ <button
1617
+ onClick={(e) => { e.stopPropagation(); withBusy(job.id, () => runNow(job.id)); }}
1618
+ disabled={busy.has(job.id)}
1619
+ className="p-1.5 rounded hover:bg-[var(--background)]"
1620
+ title="Run now"
1621
+ >
1622
+ <Play size={14} className="text-green-400" />
1623
+ </button>
1624
+ <button
1625
+ onClick={(e) => { e.stopPropagation(); withBusy(job.id, () => toggleJob(job)); }}
1626
+ disabled={busy.has(job.id)}
1627
+ className="p-1.5 rounded hover:bg-[var(--background)]"
1628
+ title={job.state === 'active' ? 'Pause' : 'Resume'}
1629
+ >
1630
+ <Pause size={14} className="text-yellow-400" />
1631
+ </button>
1632
+ <button
1633
+ onClick={(e) => { e.stopPropagation(); if (confirm('Delete this job?')) withBusy(job.id, () => deleteJob(job.id)); }}
1634
+ disabled={busy.has(job.id)}
1635
+ className="p-1.5 rounded hover:bg-[var(--background)]"
1636
+ title="Delete"
1637
+ >
1638
+ <Trash2 size={14} className="text-red-400" />
1639
+ </button>
1640
+ </div>
1641
+ </div>
1642
+ </div>
1643
+ ))}
1644
+ </div>
1645
+
1646
+ {filtered.length === 0 && (
1647
+ <div className="text-center py-12 text-[var(--muted-foreground)]">
1648
+ {jobs.length === 0 ? 'No jobs yet. Create one to get started.' : 'No jobs match this filter.'}
1649
+ </div>
1650
+ )}
1651
+ </div>
1652
+
1653
+ {/* Inspector panel */}
1654
+ {selectedJobId && (
1655
+ <InspectorPanel
1656
+ job={jobs.find(j => j.id === selectedJobId)!}
1657
+ runs={runs}
1658
+ onClose={() => setSelectedJobId(null)}
1659
+ onCancel={() => withBusy(selectedJobId, () => cancelRun(selectedJobId))}
1660
+ />
1661
+ )}
1662
+
1663
+ {/* Create modal */}
1664
+ {showCreate && (
1665
+ <CreateJobModal
1666
+ onClose={() => setShowCreate(false)}
1667
+ onCreate={async (input) => {
1668
+ const job = await createJob(input);
1669
+ if (job) setShowCreate(false);
1670
+ }}
1671
+ />
1672
+ )}
1673
+ </div>
1674
+ );
1675
+ }
1676
+
1677
+ function InspectorPanel({ job, runs, onClose, onCancel }: {
1678
+ job: PromptJob;
1679
+ runs: PromptRun[];
1680
+ onClose: () => void;
1681
+ onCancel: () => void;
1682
+ }) {
1683
+ const activeRun = runs.find(r => r.status === 'running' || r.status === 'queued');
1684
+
1685
+ return (
1686
+ <div className="w-80 border-l border-[var(--card-border)] bg-[var(--card-bg)] p-4 overflow-auto">
1687
+ <div className="flex items-center justify-between mb-4">
1688
+ <h2 className="font-medium text-sm text-[var(--foreground)]">{job.name}</h2>
1689
+ <button onClick={onClose} className="p-1 rounded hover:bg-[var(--background)]">
1690
+ <X size={14} className="text-[var(--muted-foreground)]" />
1691
+ </button>
1692
+ </div>
1693
+
1694
+ <div className="space-y-3 text-xs mb-4">
1695
+ <div><span className="text-[var(--muted-foreground)]">CLI:</span> <span className="text-[var(--foreground)]">{job.cli}</span></div>
1696
+ <div><span className="text-[var(--muted-foreground)]">Schedule:</span> <span className="text-[var(--foreground)]">{job.cadence || job.cronExpr}</span></div>
1697
+ <div><span className="text-[var(--muted-foreground)]">Overlap:</span> <span className="text-[var(--foreground)]">{job.overlapPolicy}</span></div>
1698
+ <div><span className="text-[var(--muted-foreground)]">Last outcome:</span> <span className="text-[var(--foreground)]">{job.lastOutcome ?? 'never run'}</span></div>
1699
+ </div>
1700
+
1701
+ <div className="mb-3">
1702
+ <h3 className="text-xs font-medium text-[var(--muted-foreground)] mb-1">Prompt</h3>
1703
+ <pre className="text-xs bg-[var(--background)] p-2 rounded whitespace-pre-wrap text-[var(--foreground)]">{job.prompt}</pre>
1704
+ </div>
1705
+
1706
+ {activeRun && (
1707
+ <button onClick={onCancel} className="w-full mb-4 px-3 py-1.5 rounded bg-red-500/10 text-red-400 text-xs font-medium hover:bg-red-500/20">
1708
+ Cancel Running
1709
+ </button>
1710
+ )}
1711
+
1712
+ <h3 className="text-xs font-medium text-[var(--muted-foreground)] mb-2">Recent Runs</h3>
1713
+ <div className="space-y-2">
1714
+ {runs.slice(0, 10).map(run => (
1715
+ <div key={run.id} className="p-2 rounded bg-[var(--background)] text-xs">
1716
+ <div className="flex justify-between mb-1">
1717
+ <span className={`font-medium ${
1718
+ run.status === 'success' ? 'text-green-400' :
1719
+ run.status === 'failed' ? 'text-red-400' :
1720
+ run.status === 'cancelled' ? 'text-yellow-400' :
1721
+ run.status === 'running' ? 'text-blue-400' :
1722
+ 'text-[var(--muted-foreground)]'
1723
+ }`}>{run.status}</span>
1724
+ {run.durationMs != null && <span className="text-[var(--muted-foreground)]">{(run.durationMs / 1000).toFixed(1)}s</span>}
1725
+ </div>
1726
+ {run.output && <pre className="text-[var(--muted-foreground)] whitespace-pre-wrap truncate max-h-16 overflow-hidden">{run.output.slice(0, 200)}</pre>}
1727
+ {run.error && <pre className="text-red-400 whitespace-pre-wrap truncate max-h-16 overflow-hidden">{run.error.slice(0, 200)}</pre>}
1728
+ </div>
1729
+ ))}
1730
+ {runs.length === 0 && <div className="text-[var(--muted-foreground)]">No runs yet</div>}
1731
+ </div>
1732
+ </div>
1733
+ );
1734
+ }
1735
+
1736
+ function CreateJobModal({ onClose, onCreate }: {
1737
+ onClose: () => void;
1738
+ onCreate: (input: { name: string; prompt: string; cli: string; cadence: string }) => Promise<void>;
1739
+ }) {
1740
+ const [name, setName] = useState('');
1741
+ const [prompt, setPrompt] = useState('');
1742
+ const [cli, setCli] = useState('claude');
1743
+ const [cadence, setCadence] = useState('');
1744
+ const [submitting, setSubmitting] = useState(false);
1745
+
1746
+ const handleSubmit = async (e: React.FormEvent) => {
1747
+ e.preventDefault();
1748
+ setSubmitting(true);
1749
+ await onCreate({ name, prompt, cli, cadence });
1750
+ setSubmitting(false);
1751
+ };
1752
+
1753
+ return (
1754
+ <div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50" onClick={onClose}>
1755
+ <form
1756
+ onClick={e => e.stopPropagation()}
1757
+ onSubmit={handleSubmit}
1758
+ className="bg-[var(--card-bg)] border border-[var(--card-border)] rounded-lg p-6 w-[480px] max-h-[80vh] overflow-auto"
1759
+ >
1760
+ <h2 className="text-lg font-semibold text-[var(--foreground)] mb-4">New Prompt Job</h2>
1761
+
1762
+ <label className="block mb-3">
1763
+ <span className="text-xs text-[var(--muted-foreground)]">Name</span>
1764
+ <input value={name} onChange={e => setName(e.target.value)} required
1765
+ className="mt-1 w-full px-3 py-2 rounded bg-[var(--background)] border border-[var(--card-border)] text-sm text-[var(--foreground)]"
1766
+ placeholder="Daily inbox summary" />
1767
+ </label>
1768
+
1769
+ <label className="block mb-3">
1770
+ <span className="text-xs text-[var(--muted-foreground)]">Prompt</span>
1771
+ <textarea value={prompt} onChange={e => setPrompt(e.target.value)} required rows={4}
1772
+ className="mt-1 w-full px-3 py-2 rounded bg-[var(--background)] border border-[var(--card-border)] text-sm text-[var(--foreground)]"
1773
+ placeholder="Summarize my unread emails from the last 24 hours" />
1774
+ </label>
1775
+
1776
+ <label className="block mb-3">
1777
+ <span className="text-xs text-[var(--muted-foreground)]">CLI</span>
1778
+ <select value={cli} onChange={e => setCli(e.target.value)}
1779
+ className="mt-1 w-full px-3 py-2 rounded bg-[var(--background)] border border-[var(--card-border)] text-sm text-[var(--foreground)]">
1780
+ <option value="claude">claude</option>
1781
+ <option value="codex">codex</option>
1782
+ <option value="gemini">gemini</option>
1783
+ </select>
1784
+ </label>
1785
+
1786
+ <label className="block mb-4">
1787
+ <span className="text-xs text-[var(--muted-foreground)]">Schedule</span>
1788
+ <input value={cadence} onChange={e => setCadence(e.target.value)} required
1789
+ className="mt-1 w-full px-3 py-2 rounded bg-[var(--background)] border border-[var(--card-border)] text-sm text-[var(--foreground)]"
1790
+ placeholder="daily at 9am, every 2 hours, 0 */6 * * *" />
1791
+ </label>
1792
+
1793
+ <div className="flex justify-end gap-2">
1794
+ <button type="button" onClick={onClose} className="px-4 py-2 rounded text-sm text-[var(--muted-foreground)] hover:bg-[var(--background)]">
1795
+ Cancel
1796
+ </button>
1797
+ <button type="submit" disabled={submitting} className="px-4 py-2 rounded bg-[var(--primary)] text-white text-sm disabled:opacity-50">
1798
+ {submitting ? 'Creating...' : 'Create'}
1799
+ </button>
1800
+ </div>
1801
+ </form>
1802
+ </div>
1803
+ );
1804
+ }
1805
+
1806
+ function formatNextRun(epochMs: number): string {
1807
+ const diff = epochMs - Date.now();
1808
+ if (diff < 0) return 'overdue';
1809
+ if (diff < 60_000) return 'in <1m';
1810
+ if (diff < 3_600_000) return `in ${Math.round(diff / 60_000)}m`;
1811
+ if (diff < 86_400_000) return `in ${Math.round(diff / 3_600_000)}h`;
1812
+ return `in ${Math.round(diff / 86_400_000)}d`;
1813
+ }
1814
+ ```
1815
+
1816
+ - [ ] **Step 3: Update the automations page to use new board**
1817
+
1818
+ Modify `app/automations/page.tsx` — replace the import:
1819
+
1820
+ ```typescript
1821
+ // Replace:
1822
+ import AutomationsBoard from '@/components/AutomationsBoard';
1823
+ // With:
1824
+ import PromptJobBoard from '@/components/PromptJobBoard';
1825
+ ```
1826
+
1827
+ And replace the JSX:
1828
+
1829
+ ```tsx
1830
+ // Replace:
1831
+ <AutomationsBoard />
1832
+ // With:
1833
+ <PromptJobBoard />
1834
+ ```
1835
+
1836
+ - [ ] **Step 4: Commit**
1837
+
1838
+ ```bash
1839
+ git add components/PromptJobBoard.tsx hooks/usePromptJobs.ts app/automations/page.tsx
1840
+ git commit -m "feat: add PromptJobBoard UI replacing AutomationsBoard"
1841
+ ```
1842
+
1843
+ ---
1844
+
1845
+ ## Task 8: Integration — wire up migration and smoke test
1846
+
1847
+ **Files:**
1848
+ - Modify: `app/automations/page.tsx` (verify)
1849
+
1850
+ - [ ] **Step 1: Run the schema migration manually to verify**
1851
+
1852
+ ```bash
1853
+ cd /Users/mendrika/Projects/Agents/agx-cloud && sqlite3 agx-board.db < db/sqlite/002_prompt_scheduler_schema.sql
1854
+ ```
1855
+
1856
+ Expected: No errors. Tables `prompt_jobs` and `prompt_runs` created.
1857
+
1858
+ - [ ] **Step 2: Start the dev server**
1859
+
1860
+ ```bash
1861
+ cd /Users/mendrika/Projects/Agents/agx-cloud && npm run dev
1862
+ ```
1863
+
1864
+ - [ ] **Step 3: Smoke test via curl**
1865
+
1866
+ Create a job:
1867
+ ```bash
1868
+ curl -X POST http://localhost:3000/api/prompt-jobs \
1869
+ -H 'Content-Type: application/json' \
1870
+ -d '{"name":"Test Job","prompt":"Say hello","cli":"echo","cadence":"every hour"}'
1871
+ ```
1872
+ Expected: 201 with JSON containing the created job.
1873
+
1874
+ List jobs:
1875
+ ```bash
1876
+ curl http://localhost:3000/api/prompt-jobs
1877
+ ```
1878
+ Expected: 200 with `{ count: 1, jobs: [...] }`.
1879
+
1880
+ Poll (run now):
1881
+ ```bash
1882
+ curl -X POST http://localhost:3000/api/prompt-jobs/poll \
1883
+ -H 'Content-Type: application/json' \
1884
+ -d '{"jobId":"<id from create>"}'
1885
+ ```
1886
+ Expected: 200 with queued run.
1887
+
1888
+ Check runs:
1889
+ ```bash
1890
+ curl http://localhost:3000/api/prompt-jobs/<id>/runs
1891
+ ```
1892
+ Expected: 200 with run entries showing status progression.
1893
+
1894
+ - [ ] **Step 4: Open browser and verify UI**
1895
+
1896
+ Navigate to `http://localhost:3000/automations`:
1897
+ - Verify the PromptJobBoard renders
1898
+ - Verify the test job appears
1899
+ - Click "New Job" and create a job via the form
1900
+ - Click "Run now" on a job and verify run appears in inspector
1901
+
1902
+ - [ ] **Step 5: Commit**
1903
+
1904
+ ```bash
1905
+ git add -A
1906
+ git commit -m "feat: prompt scheduler integration — migration, smoke test passing"
1907
+ ```