@kb-labs/rest-api-app 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/.kb/agents/sessions/session-1771531145393-ws3uh6q/turns.json +42 -0
  2. package/.kb/agents/sessions/session-1771548930486-ui6rtvm/turns.json +33 -0
  3. package/.kb/agents/sessions/session-1771549691485-nibqroq/turns.json +133 -0
  4. package/.kb/agents/sessions/session-1771550943182-dkwqdjc/turns.json +130 -0
  5. package/.kb/agents/sessions/session-1771551564182-cr4bwzn/turns.json +349 -0
  6. package/.kb/agents/sessions/session-1771552401370-g4ztwd1/turns.json +206 -0
  7. package/.kb/commit/current/plan.json +248 -0
  8. package/.kb/commit/current/status.json +472 -0
  9. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/health.d.ts +10 -0
  10. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/health.js +215 -0
  11. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/health.js.map +1 -0
  12. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/list.d.ts +10 -0
  13. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/list.js +271 -0
  14. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/list.js.map +1 -0
  15. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/logs.d.ts +10 -0
  16. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/logs.js +230 -0
  17. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/logs.js.map +1 -0
  18. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/metrics.d.ts +10 -0
  19. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/metrics.js +228 -0
  20. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/metrics.js.map +1 -0
  21. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/run.d.ts +11 -0
  22. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/run.js +281 -0
  23. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/run.js.map +1 -0
  24. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/status.d.ts +10 -0
  25. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/status.js +266 -0
  26. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/status.js.map +1 -0
  27. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/workflow-run.d.ts +11 -0
  28. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/workflow-run.js +284 -0
  29. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/commands/workflow-run.js.map +1 -0
  30. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/flags-WLdpSZl4.d.ts +77 -0
  31. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/index.d.ts +2 -0
  32. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/index.js +441 -0
  33. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/index.js.map +1 -0
  34. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/manifest.d.ts +196 -0
  35. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/manifest.js +441 -0
  36. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/manifest.js.map +1 -0
  37. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/cron-list-handler.d.ts +19 -0
  38. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/cron-list-handler.js +48 -0
  39. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/cron-list-handler.js.map +1 -0
  40. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/index.d.ts +6 -0
  41. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/index.js +170 -0
  42. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/index.js.map +1 -0
  43. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-cancel-handler.d.ts +12 -0
  44. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-cancel-handler.js +52 -0
  45. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-cancel-handler.js.map +1 -0
  46. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-detail-handler.d.ts +22 -0
  47. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-detail-handler.js +52 -0
  48. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-detail-handler.js.map +1 -0
  49. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-logs-handler.d.ts +13 -0
  50. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-logs-handler.js +52 -0
  51. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-logs-handler.js.map +1 -0
  52. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-steps-handler.d.ts +9 -0
  53. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-steps-handler.js +43 -0
  54. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/job-steps-handler.js.map +1 -0
  55. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/jobs-list-handler.d.ts +26 -0
  56. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/jobs-list-handler.js +63 -0
  57. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/jobs-list-handler.js.map +1 -0
  58. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/pending-approvals-handler.d.ts +9 -0
  59. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/pending-approvals-handler.js +46 -0
  60. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/pending-approvals-handler.js.map +1 -0
  61. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/resolve-approval-handler.d.ts +16 -0
  62. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/resolve-approval-handler.js +58 -0
  63. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/resolve-approval-handler.js.map +1 -0
  64. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/run-detail-handler.d.ts +9 -0
  65. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/run-detail-handler.js +46 -0
  66. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/run-detail-handler.js.map +1 -0
  67. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/runs-list-handler.d.ts +11 -0
  68. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/runs-list-handler.js +50 -0
  69. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/runs-list-handler.js.map +1 -0
  70. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/stats-handler.d.ts +7 -0
  71. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/stats-handler.js +39 -0
  72. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/stats-handler.js.map +1 -0
  73. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-detail-handler.d.ts +10 -0
  74. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-detail-handler.js +46 -0
  75. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-detail-handler.js.map +1 -0
  76. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-cancel-handler.d.ts +13 -0
  77. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-cancel-handler.js +47 -0
  78. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-cancel-handler.js.map +1 -0
  79. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-handler.d.ts +14 -0
  80. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-handler.js +53 -0
  81. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-run-handler.js.map +1 -0
  82. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-runs-handler.d.ts +13 -0
  83. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-runs-handler.js +54 -0
  84. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflow-runs-handler.js.map +1 -0
  85. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflows-list-handler.d.ts +12 -0
  86. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflows-list-handler.js +51 -0
  87. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/rest/workflows-list-handler.js.map +1 -0
  88. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/logs-channel.d.ts +17 -0
  89. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/logs-channel.js +133 -0
  90. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/logs-channel.js.map +1 -0
  91. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/progress-channel.d.ts +11 -0
  92. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/progress-channel.js +46 -0
  93. package/.kb/runtime/workspaces/ws_94c2deab-4cf9-49cb-94ac-3958062754a1/ws/progress-channel.js.map +1 -0
  94. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/health.d.ts +10 -0
  95. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/health.js +215 -0
  96. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/health.js.map +1 -0
  97. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/list.d.ts +10 -0
  98. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/list.js +271 -0
  99. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/list.js.map +1 -0
  100. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/logs.d.ts +10 -0
  101. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/logs.js +230 -0
  102. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/logs.js.map +1 -0
  103. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/metrics.d.ts +10 -0
  104. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/metrics.js +228 -0
  105. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/metrics.js.map +1 -0
  106. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/run.d.ts +11 -0
  107. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/run.js +281 -0
  108. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/run.js.map +1 -0
  109. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/status.d.ts +10 -0
  110. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/status.js +266 -0
  111. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/status.js.map +1 -0
  112. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/workflow-run.d.ts +11 -0
  113. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/workflow-run.js +284 -0
  114. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/commands/workflow-run.js.map +1 -0
  115. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/flags-WLdpSZl4.d.ts +77 -0
  116. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/index.d.ts +2 -0
  117. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/index.js +441 -0
  118. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/index.js.map +1 -0
  119. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/manifest.d.ts +196 -0
  120. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/manifest.js +441 -0
  121. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/manifest.js.map +1 -0
  122. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/cron-list-handler.d.ts +19 -0
  123. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/cron-list-handler.js +48 -0
  124. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/cron-list-handler.js.map +1 -0
  125. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/index.d.ts +6 -0
  126. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/index.js +170 -0
  127. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/index.js.map +1 -0
  128. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-cancel-handler.d.ts +12 -0
  129. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-cancel-handler.js +52 -0
  130. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-cancel-handler.js.map +1 -0
  131. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-detail-handler.d.ts +22 -0
  132. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-detail-handler.js +52 -0
  133. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-detail-handler.js.map +1 -0
  134. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-logs-handler.d.ts +13 -0
  135. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-logs-handler.js +52 -0
  136. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-logs-handler.js.map +1 -0
  137. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-steps-handler.d.ts +9 -0
  138. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-steps-handler.js +43 -0
  139. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/job-steps-handler.js.map +1 -0
  140. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/jobs-list-handler.d.ts +26 -0
  141. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/jobs-list-handler.js +63 -0
  142. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/jobs-list-handler.js.map +1 -0
  143. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/pending-approvals-handler.d.ts +9 -0
  144. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/pending-approvals-handler.js +46 -0
  145. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/pending-approvals-handler.js.map +1 -0
  146. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/resolve-approval-handler.d.ts +16 -0
  147. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/resolve-approval-handler.js +58 -0
  148. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/resolve-approval-handler.js.map +1 -0
  149. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/run-detail-handler.d.ts +9 -0
  150. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/run-detail-handler.js +46 -0
  151. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/run-detail-handler.js.map +1 -0
  152. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/runs-list-handler.d.ts +11 -0
  153. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/runs-list-handler.js +50 -0
  154. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/runs-list-handler.js.map +1 -0
  155. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/stats-handler.d.ts +7 -0
  156. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/stats-handler.js +39 -0
  157. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/stats-handler.js.map +1 -0
  158. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-detail-handler.d.ts +10 -0
  159. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-detail-handler.js +46 -0
  160. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-detail-handler.js.map +1 -0
  161. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-cancel-handler.d.ts +13 -0
  162. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-cancel-handler.js +47 -0
  163. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-cancel-handler.js.map +1 -0
  164. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-handler.d.ts +14 -0
  165. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-handler.js +53 -0
  166. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-run-handler.js.map +1 -0
  167. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-runs-handler.d.ts +13 -0
  168. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-runs-handler.js +54 -0
  169. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflow-runs-handler.js.map +1 -0
  170. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflows-list-handler.d.ts +12 -0
  171. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflows-list-handler.js +51 -0
  172. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/rest/workflows-list-handler.js.map +1 -0
  173. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/logs-channel.d.ts +17 -0
  174. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/logs-channel.js +133 -0
  175. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/logs-channel.js.map +1 -0
  176. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/progress-channel.d.ts +11 -0
  177. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/progress-channel.js +46 -0
  178. package/.kb/runtime/workspaces/ws_f0f301b8-388d-4dc4-b301-475f2bc95f02/ws/progress-channel.js.map +1 -0
  179. package/README.md +54 -0
  180. package/eslint.config.js +23 -0
  181. package/package.json +72 -0
  182. package/src/.kb/agents/sessions/session-1773470583796-ximqnfk/kpi-baseline.json +17 -0
  183. package/src/.kb/memory/sessions/session-1773470583796-ximqnfk/fact-sheet.json +1 -0
  184. package/src/bootstrap.ts +233 -0
  185. package/src/diagnostics/header-debug.ts +37 -0
  186. package/src/events/hub.ts +60 -0
  187. package/src/events/index.ts +1 -0
  188. package/src/index.ts +13 -0
  189. package/src/manifest.ts +21 -0
  190. package/src/middleware/__tests__/cache.spec.ts +184 -0
  191. package/src/middleware/__tests__/envelope.spec.ts +268 -0
  192. package/src/middleware/__tests__/metrics.redis.spec.ts +64 -0
  193. package/src/middleware/__tests__/rate-limit.spec.ts +283 -0
  194. package/src/middleware/__tests__/request-id.spec.ts +160 -0
  195. package/src/middleware/cache.ts +67 -0
  196. package/src/middleware/envelope.ts +136 -0
  197. package/src/middleware/error-guard.ts +69 -0
  198. package/src/middleware/index.ts +37 -0
  199. package/src/middleware/metrics.ts +810 -0
  200. package/src/middleware/mock-mode.ts +44 -0
  201. package/src/middleware/prom-metrics.ts +284 -0
  202. package/src/middleware/rate-limit-routes.ts +73 -0
  203. package/src/middleware/rate-limit.ts +72 -0
  204. package/src/middleware/request-id.ts +41 -0
  205. package/src/middleware/request-timeout.ts +69 -0
  206. package/src/middleware/security-headers.ts +24 -0
  207. package/src/middleware/startup-guard.ts +107 -0
  208. package/src/observability/service-contract.ts +192 -0
  209. package/src/plugins/index.ts +118 -0
  210. package/src/routes/__tests__/adapters-date-helpers.spec.ts +332 -0
  211. package/src/routes/__tests__/adapters.spec.ts +680 -0
  212. package/src/routes/__tests__/cache.spec.ts +264 -0
  213. package/src/routes/__tests__/events.spec.ts +434 -0
  214. package/src/routes/__tests__/health.spec.ts +414 -0
  215. package/src/routes/__tests__/logs.spec.ts +494 -0
  216. package/src/routes/__tests__/observability.spec.ts +392 -0
  217. package/src/routes/__tests__/plugins.spec.ts +931 -0
  218. package/src/routes/__tests__/workflow-management.spec.ts +698 -0
  219. package/src/routes/__tests__/workflows.spec.ts +204 -0
  220. package/src/routes/adapter-call.ts +220 -0
  221. package/src/routes/adapters.ts +1206 -0
  222. package/src/routes/analytics.ts +328 -0
  223. package/src/routes/cache.ts +104 -0
  224. package/src/routes/debug-routes.ts +95 -0
  225. package/src/routes/events.ts +115 -0
  226. package/src/routes/health.ts +348 -0
  227. package/src/routes/hello.ts +47 -0
  228. package/src/routes/index.ts +395 -0
  229. package/src/routes/jobs.ts +253 -0
  230. package/src/routes/logs.ts +718 -0
  231. package/src/routes/metrics.ts +120 -0
  232. package/src/routes/observability.ts +1388 -0
  233. package/src/routes/openapi.ts +101 -0
  234. package/src/routes/platform.ts +143 -0
  235. package/src/routes/plugins.ts +998 -0
  236. package/src/routes/readiness.ts +83 -0
  237. package/src/routes/workflow-management.ts +469 -0
  238. package/src/routes/workflows.ts +256 -0
  239. package/src/server.ts +203 -0
  240. package/src/services/historical-metrics.ts +496 -0
  241. package/src/services/incident-analyzer.ts +289 -0
  242. package/src/services/incident-detector.ts +691 -0
  243. package/src/services/incident-schema.sql +76 -0
  244. package/src/services/incident-storage.ts +593 -0
  245. package/src/services/system-metrics-collector.ts +244 -0
  246. package/src/types/fastify.d.ts +58 -0
  247. package/src/utils/__tests__/sse-auth.spec.ts +113 -0
  248. package/src/utils/path-helpers.ts +15 -0
  249. package/src/utils/repo.ts +42 -0
  250. package/src/utils/schema.ts +20 -0
  251. package/src/utils/sse-auth.ts +81 -0
  252. package/test-sandbox.sh +105 -0
  253. package/tsconfig.build.json +15 -0
  254. package/tsconfig.json +9 -0
  255. package/tsup.config.ts +18 -0
@@ -0,0 +1,698 @@
1
+ import { beforeEach, describe, expect, it, vi, afterEach } from 'vitest';
2
+ import Fastify from 'fastify';
3
+
4
+ import type { IEntityRegistry } from '@kb-labs/core-registry';
5
+ import type { RestApiConfig } from '@kb-labs/rest-api-core';
6
+ import type { PlatformServices } from '@kb-labs/plugin-contracts';
7
+ import type { WorkflowSpec } from '@kb-labs/workflow-contracts';
8
+ import { registerWorkflowManagementRoutes } from '../workflow-management';
9
+
10
+ // Mock workflow engine dependencies
11
+ const mockRepository = {
12
+ create: vi.fn(),
13
+ get: vi.fn(),
14
+ update: vi.fn(),
15
+ delete: vi.fn(),
16
+ pause: vi.fn(),
17
+ resume: vi.fn(),
18
+ disable: vi.fn(),
19
+ };
20
+
21
+ const mockScanner = {
22
+ scan: vi.fn(),
23
+ };
24
+
25
+ const mockWorkflowService = {
26
+ listAll: vi.fn(),
27
+ get: vi.fn(),
28
+ create: vi.fn(),
29
+ update: vi.fn(),
30
+ delete: vi.fn(),
31
+ pause: vi.fn(),
32
+ resume: vi.fn(),
33
+ disable: vi.fn(),
34
+ getAvailableHandlers: vi.fn(),
35
+ validate: vi.fn(),
36
+ };
37
+
38
+ vi.mock('@kb-labs/workflow-engine', () => ({
39
+ WorkflowRepository: vi.fn(() => mockRepository),
40
+ ManifestScanner: vi.fn(() => mockScanner),
41
+ WorkflowService: vi.fn(() => mockWorkflowService),
42
+ }));
43
+
44
+ const BASE_CONFIG: RestApiConfig = {
45
+ port: 3000,
46
+ basePath: '/api/v1',
47
+ apiVersion: 'test',
48
+ cors: {
49
+ origins: [],
50
+ allowCredentials: true,
51
+ profile: 'dev',
52
+ },
53
+ plugins: [],
54
+ mockMode: false,
55
+ };
56
+
57
+ const mockPlatform: PlatformServices = {
58
+ logger: {
59
+ info: vi.fn(),
60
+ warn: vi.fn(),
61
+ error: vi.fn(),
62
+ debug: vi.fn(),
63
+ },
64
+ } as any;
65
+
66
+ const mockCliApi = {} as IEntityRegistry;
67
+
68
+ function createSampleWorkflowSpec(): WorkflowSpec {
69
+ return {
70
+ name: 'test-workflow',
71
+ version: '1.0.0',
72
+ on: { manual: true },
73
+ jobs: {
74
+ build: {
75
+ runsOn: 'local',
76
+ steps: [
77
+ {
78
+ name: 'echo',
79
+ uses: 'builtin:shell',
80
+ with: { command: 'echo hello' },
81
+ },
82
+ ],
83
+ },
84
+ },
85
+ };
86
+ }
87
+
88
+ function createMockWorkflowRuntime(overrides = {}) {
89
+ return {
90
+ id: 'wf-123',
91
+ name: 'test-workflow',
92
+ version: '1.0.0',
93
+ source: 'standalone',
94
+ status: 'active',
95
+ spec: createSampleWorkflowSpec(),
96
+ createdAt: new Date().toISOString(),
97
+ updatedAt: new Date().toISOString(),
98
+ ...overrides,
99
+ };
100
+ }
101
+
102
+ describe('registerWorkflowManagementRoutes', () => {
103
+ let app: ReturnType<typeof Fastify>;
104
+
105
+ beforeEach(async () => {
106
+ vi.clearAllMocks();
107
+ app = Fastify({ logger: false });
108
+ await registerWorkflowManagementRoutes(app, BASE_CONFIG, mockCliApi, mockPlatform, null, null);
109
+ });
110
+
111
+ afterEach(async () => {
112
+ await app.close();
113
+ });
114
+
115
+ describe('GET /api/v1/workflows', () => {
116
+ it('lists all workflows', async () => {
117
+ const workflows = [
118
+ createMockWorkflowRuntime({ id: 'wf-1', name: 'workflow-1' }),
119
+ createMockWorkflowRuntime({ id: 'wf-2', name: 'workflow-2' }),
120
+ ];
121
+
122
+ mockWorkflowService.listAll.mockResolvedValue(workflows);
123
+
124
+ const response = await app.inject({
125
+ method: 'GET',
126
+ url: '/api/v1/workflows',
127
+ });
128
+
129
+ expect(response.statusCode).toBe(200);
130
+ const payload = response.json();
131
+ expect(payload.workflows).toHaveLength(2);
132
+ expect(payload.total).toBe(2);
133
+ expect(mockWorkflowService.listAll).toHaveBeenCalledWith({
134
+ source: undefined,
135
+ status: undefined,
136
+ });
137
+ });
138
+
139
+ it('filters workflows by source', async () => {
140
+ mockWorkflowService.listAll.mockResolvedValue([]);
141
+
142
+ await app.inject({
143
+ method: 'GET',
144
+ url: '/api/v1/workflows?source=manifest',
145
+ });
146
+
147
+ expect(mockWorkflowService.listAll).toHaveBeenCalledWith({
148
+ source: 'manifest',
149
+ status: undefined,
150
+ });
151
+ });
152
+
153
+ it('filters workflows by status', async () => {
154
+ mockWorkflowService.listAll.mockResolvedValue([]);
155
+
156
+ await app.inject({
157
+ method: 'GET',
158
+ url: '/api/v1/workflows?status=paused',
159
+ });
160
+
161
+ expect(mockWorkflowService.listAll).toHaveBeenCalledWith({
162
+ source: undefined,
163
+ status: 'paused',
164
+ });
165
+ });
166
+
167
+ it('filters workflows by tags', async () => {
168
+ const workflows = [
169
+ createMockWorkflowRuntime({ id: 'wf-1', tags: ['ci', 'build'] }),
170
+ createMockWorkflowRuntime({ id: 'wf-2', tags: ['deploy'] }),
171
+ createMockWorkflowRuntime({ id: 'wf-3', tags: ['ci', 'test'] }),
172
+ ];
173
+
174
+ mockWorkflowService.listAll.mockResolvedValue(workflows);
175
+
176
+ const response = await app.inject({
177
+ method: 'GET',
178
+ url: '/api/v1/workflows?tags=ci',
179
+ });
180
+
181
+ const payload = response.json();
182
+ expect(payload.workflows).toHaveLength(2);
183
+ expect(payload.workflows.map((w: any) => w.id)).toEqual(['wf-1', 'wf-3']);
184
+ });
185
+
186
+ it('filters workflows by search term', async () => {
187
+ const workflows = [
188
+ createMockWorkflowRuntime({
189
+ id: 'wf-1',
190
+ name: 'build-frontend',
191
+ description: 'Build React app',
192
+ }),
193
+ createMockWorkflowRuntime({
194
+ id: 'wf-2',
195
+ name: 'deploy-backend',
196
+ description: 'Deploy Node.js service',
197
+ }),
198
+ ];
199
+
200
+ mockWorkflowService.listAll.mockResolvedValue(workflows);
201
+
202
+ const response = await app.inject({
203
+ method: 'GET',
204
+ url: '/api/v1/workflows?search=frontend',
205
+ });
206
+
207
+ const payload = response.json();
208
+ expect(payload.workflows).toHaveLength(1);
209
+ expect(payload.workflows[0].id).toBe('wf-1');
210
+ });
211
+
212
+ it('combines multiple filters', async () => {
213
+ const workflows = [
214
+ createMockWorkflowRuntime({
215
+ id: 'wf-1',
216
+ name: 'ci-build',
217
+ tags: ['ci'],
218
+ source: 'standalone',
219
+ }),
220
+ createMockWorkflowRuntime({
221
+ id: 'wf-2',
222
+ name: 'deploy',
223
+ tags: ['deploy'],
224
+ source: 'manifest',
225
+ }),
226
+ ];
227
+
228
+ mockWorkflowService.listAll.mockResolvedValue([workflows[0]]);
229
+
230
+ const response = await app.inject({
231
+ method: 'GET',
232
+ url: '/api/v1/workflows?source=standalone&tags=ci&search=build',
233
+ });
234
+
235
+ const payload = response.json();
236
+ expect(payload.workflows).toHaveLength(1);
237
+ expect(payload.workflows[0].id).toBe('wf-1');
238
+ });
239
+ });
240
+
241
+ describe('GET /api/v1/workflows/:id', () => {
242
+ it('returns workflow by id', async () => {
243
+ const workflow = createMockWorkflowRuntime({ id: 'wf-123' });
244
+ mockWorkflowService.get.mockResolvedValue(workflow);
245
+
246
+ const response = await app.inject({
247
+ method: 'GET',
248
+ url: '/api/v1/workflows/wf-123',
249
+ });
250
+
251
+ expect(response.statusCode).toBe(200);
252
+ const payload = response.json();
253
+ expect(payload.workflow.id).toBe('wf-123');
254
+ expect(mockWorkflowService.get).toHaveBeenCalledWith('wf-123');
255
+ });
256
+
257
+ it('returns 404 when workflow not found', async () => {
258
+ mockWorkflowService.get.mockResolvedValue(null);
259
+
260
+ const response = await app.inject({
261
+ method: 'GET',
262
+ url: '/api/v1/workflows/missing',
263
+ });
264
+
265
+ expect(response.statusCode).toBe(404);
266
+ const payload = response.json();
267
+ const errorText = payload.message ?? payload.error ?? '';
268
+ expect(errorText).toContain('not found');
269
+ });
270
+ });
271
+
272
+ describe('POST /api/v1/workflows', () => {
273
+ it('creates new standalone workflow', async () => {
274
+ const spec = createSampleWorkflowSpec();
275
+ const workflow = createMockWorkflowRuntime({ spec });
276
+ mockWorkflowService.create.mockResolvedValue(workflow);
277
+
278
+ const response = await app.inject({
279
+ method: 'POST',
280
+ url: '/api/v1/workflows',
281
+ payload: { spec },
282
+ });
283
+
284
+ expect(response.statusCode).toBe(201);
285
+ const payload = response.json();
286
+ expect(payload.workflow.id).toBe('wf-123');
287
+ expect(mockWorkflowService.create).toHaveBeenCalledWith(spec);
288
+ });
289
+
290
+ it('rejects body without spec field', async () => {
291
+ const response = await app.inject({
292
+ method: 'POST',
293
+ url: '/api/v1/workflows',
294
+ payload: {},
295
+ });
296
+
297
+ // Zod validation error — 400 in production (with envelope middleware), 500 in unit test scope
298
+ expect([400, 500]).toContain(response.statusCode);
299
+ expect(mockWorkflowService.create).not.toHaveBeenCalled();
300
+ });
301
+ });
302
+
303
+ describe('PUT /api/v1/workflows/:id', () => {
304
+ it('updates standalone workflow spec', async () => {
305
+ const existing = createMockWorkflowRuntime({ id: 'wf-123', source: 'standalone' });
306
+ const updated = createMockWorkflowRuntime({
307
+ id: 'wf-123',
308
+ name: 'updated-workflow',
309
+ });
310
+
311
+ mockWorkflowService.get.mockResolvedValueOnce(existing).mockResolvedValueOnce(updated);
312
+ mockWorkflowService.update.mockResolvedValue(updated);
313
+
314
+ const response = await app.inject({
315
+ method: 'PUT',
316
+ url: '/api/v1/workflows/wf-123',
317
+ payload: {
318
+ spec: {
319
+ name: 'updated-workflow',
320
+ },
321
+ },
322
+ });
323
+
324
+ expect(response.statusCode).toBe(200);
325
+ const payload = response.json();
326
+ expect(payload.workflow.name).toBe('updated-workflow');
327
+ expect(mockWorkflowService.update).toHaveBeenCalledWith('wf-123', {
328
+ name: 'updated-workflow',
329
+ });
330
+ });
331
+
332
+ it('updates workflow status', async () => {
333
+ const existing = createMockWorkflowRuntime({ id: 'wf-123', source: 'standalone' });
334
+ const paused = createMockWorkflowRuntime({ id: 'wf-123', status: 'paused' });
335
+
336
+ mockWorkflowService.get.mockResolvedValueOnce(existing).mockResolvedValueOnce(paused);
337
+ mockWorkflowService.pause.mockResolvedValue(paused);
338
+
339
+ const response = await app.inject({
340
+ method: 'PUT',
341
+ url: '/api/v1/workflows/wf-123',
342
+ payload: {
343
+ status: 'paused',
344
+ },
345
+ });
346
+
347
+ expect(response.statusCode).toBe(200);
348
+ const payload = response.json();
349
+ expect(payload.workflow.status).toBe('paused');
350
+ expect(mockWorkflowService.pause).toHaveBeenCalledWith('wf-123');
351
+ });
352
+
353
+ it('updates both spec and status', async () => {
354
+ const existing = createMockWorkflowRuntime({ id: 'wf-123', source: 'standalone' });
355
+ const updated = createMockWorkflowRuntime({ id: 'wf-123', name: 'new-name' });
356
+ const disabled = createMockWorkflowRuntime({
357
+ id: 'wf-123',
358
+ name: 'new-name',
359
+ status: 'disabled',
360
+ });
361
+
362
+ mockWorkflowService.get.mockResolvedValueOnce(existing).mockResolvedValueOnce(disabled);
363
+ mockWorkflowService.update.mockResolvedValue(updated);
364
+ mockWorkflowService.disable.mockResolvedValue(disabled);
365
+
366
+ const response = await app.inject({
367
+ method: 'PUT',
368
+ url: '/api/v1/workflows/wf-123',
369
+ payload: {
370
+ spec: { name: 'new-name' },
371
+ status: 'disabled',
372
+ },
373
+ });
374
+
375
+ expect(response.statusCode).toBe(200);
376
+ expect(mockWorkflowService.update).toHaveBeenCalledWith('wf-123', { name: 'new-name' });
377
+ expect(mockWorkflowService.disable).toHaveBeenCalledWith('wf-123');
378
+ });
379
+
380
+ it('returns 404 when workflow not found', async () => {
381
+ mockWorkflowService.get.mockResolvedValue(null);
382
+
383
+ const response = await app.inject({
384
+ method: 'PUT',
385
+ url: '/api/v1/workflows/missing',
386
+ payload: { spec: { name: 'test' } },
387
+ });
388
+
389
+ expect(response.statusCode).toBe(404);
390
+ });
391
+
392
+ it('rejects updating manifest-based workflows', async () => {
393
+ const manifestWorkflow = createMockWorkflowRuntime({
394
+ id: 'wf-123',
395
+ source: 'manifest',
396
+ });
397
+ mockWorkflowService.get.mockResolvedValue(manifestWorkflow);
398
+
399
+ const response = await app.inject({
400
+ method: 'PUT',
401
+ url: '/api/v1/workflows/wf-123',
402
+ payload: { spec: { name: 'updated' } },
403
+ });
404
+
405
+ expect(response.statusCode).toBe(400);
406
+ const payload = response.json();
407
+ expect(payload.message).toContain('Cannot update manifest-based workflow');
408
+ });
409
+ });
410
+
411
+ describe('DELETE /api/v1/workflows/:id', () => {
412
+ it('deletes standalone workflow', async () => {
413
+ const workflow = createMockWorkflowRuntime({ id: 'wf-123', source: 'standalone' });
414
+ mockWorkflowService.get.mockResolvedValue(workflow);
415
+ mockWorkflowService.delete.mockResolvedValue(undefined);
416
+
417
+ const response = await app.inject({
418
+ method: 'DELETE',
419
+ url: '/api/v1/workflows/wf-123',
420
+ });
421
+
422
+ expect(response.statusCode).toBe(204);
423
+ expect(mockWorkflowService.delete).toHaveBeenCalledWith('wf-123');
424
+ });
425
+
426
+ it('returns 404 when workflow not found', async () => {
427
+ mockWorkflowService.get.mockResolvedValue(null);
428
+
429
+ const response = await app.inject({
430
+ method: 'DELETE',
431
+ url: '/api/v1/workflows/missing',
432
+ });
433
+
434
+ expect(response.statusCode).toBe(404);
435
+ });
436
+
437
+ it('rejects deleting manifest-based workflows', async () => {
438
+ const manifestWorkflow = createMockWorkflowRuntime({
439
+ id: 'wf-123',
440
+ source: 'manifest',
441
+ });
442
+ mockWorkflowService.get.mockResolvedValue(manifestWorkflow);
443
+
444
+ const response = await app.inject({
445
+ method: 'DELETE',
446
+ url: '/api/v1/workflows/wf-123',
447
+ });
448
+
449
+ expect(response.statusCode).toBe(400);
450
+ const payload = response.json();
451
+ expect(payload.message).toContain('Cannot delete manifest-based workflow');
452
+ });
453
+ });
454
+
455
+ describe('POST /api/v1/workflows/:id/schedule', () => {
456
+ it('enables workflow schedule', async () => {
457
+ const workflow = createMockWorkflowRuntime({ id: 'wf-123', source: 'standalone' });
458
+ const scheduled = createMockWorkflowRuntime({
459
+ id: 'wf-123',
460
+ schedule: { cron: '0 0 * * *', enabled: true },
461
+ });
462
+
463
+ mockWorkflowService.get.mockResolvedValue(workflow);
464
+ mockWorkflowService.update.mockResolvedValue(scheduled);
465
+
466
+ const response = await app.inject({
467
+ method: 'POST',
468
+ url: '/api/v1/workflows/wf-123/schedule',
469
+ payload: {
470
+ cron: '0 0 * * *',
471
+ enabled: true,
472
+ timezone: 'America/New_York',
473
+ },
474
+ });
475
+
476
+ expect(response.statusCode).toBe(200);
477
+ const payload = response.json();
478
+ expect(payload.workflow.schedule).toBeDefined();
479
+ expect(mockWorkflowService.update).toHaveBeenCalledWith('wf-123', {
480
+ on: {
481
+ schedule: {
482
+ cron: '0 0 * * *',
483
+ timezone: 'America/New_York',
484
+ },
485
+ },
486
+ });
487
+ });
488
+
489
+ it('validates schedule config schema', async () => {
490
+ const workflow = createMockWorkflowRuntime({ id: 'wf-123', source: 'standalone' });
491
+ mockWorkflowService.get.mockResolvedValue(workflow);
492
+
493
+ const response = await app.inject({
494
+ method: 'POST',
495
+ url: '/api/v1/workflows/wf-123/schedule',
496
+ payload: {
497
+ // Missing required cron and enabled
498
+ timezone: 'UTC',
499
+ },
500
+ });
501
+
502
+ // Zod validation error — 400 in production (with envelope middleware), 500 in unit test scope
503
+ expect([400, 500]).toContain(response.statusCode);
504
+ });
505
+
506
+ it('rejects scheduling manifest-based workflows', async () => {
507
+ const manifestWorkflow = createMockWorkflowRuntime({
508
+ id: 'wf-123',
509
+ source: 'manifest',
510
+ });
511
+ mockWorkflowService.get.mockResolvedValue(manifestWorkflow);
512
+
513
+ const response = await app.inject({
514
+ method: 'POST',
515
+ url: '/api/v1/workflows/wf-123/schedule',
516
+ payload: { cron: '0 0 * * *', enabled: true },
517
+ });
518
+
519
+ expect(response.statusCode).toBe(400);
520
+ const payload = response.json();
521
+ expect(payload.message).toContain('Cannot modify schedule for manifest-based workflow');
522
+ });
523
+ });
524
+
525
+ describe('DELETE /api/v1/workflows/:id/schedule', () => {
526
+ it('disables workflow schedule', async () => {
527
+ const workflow = createMockWorkflowRuntime({
528
+ id: 'wf-123',
529
+ source: 'standalone',
530
+ schedule: { cron: '0 0 * * *', enabled: true },
531
+ });
532
+ const unscheduled = createMockWorkflowRuntime({
533
+ id: 'wf-123',
534
+ schedule: { enabled: false },
535
+ });
536
+
537
+ mockWorkflowService.get.mockResolvedValue(workflow);
538
+ mockWorkflowService.update.mockResolvedValue(unscheduled);
539
+
540
+ const response = await app.inject({
541
+ method: 'DELETE',
542
+ url: '/api/v1/workflows/wf-123/schedule',
543
+ });
544
+
545
+ expect(response.statusCode).toBe(200);
546
+ const payload = response.json();
547
+ expect(payload.workflow.schedule.enabled).toBe(false);
548
+ expect(mockWorkflowService.update).toHaveBeenCalledWith('wf-123', {
549
+ on: { schedule: undefined },
550
+ });
551
+ });
552
+
553
+ it('returns 404 when workflow not found', async () => {
554
+ mockWorkflowService.get.mockResolvedValue(null);
555
+
556
+ const response = await app.inject({
557
+ method: 'DELETE',
558
+ url: '/api/v1/workflows/missing/schedule',
559
+ });
560
+
561
+ expect(response.statusCode).toBe(404);
562
+ });
563
+ });
564
+
565
+ describe('POST /api/v1/workflows/:id/pause', () => {
566
+ it('pauses standalone workflow', async () => {
567
+ const workflow = createMockWorkflowRuntime({ id: 'wf-123', source: 'standalone' });
568
+ const paused = createMockWorkflowRuntime({ id: 'wf-123', status: 'paused' });
569
+
570
+ mockWorkflowService.get.mockResolvedValueOnce(workflow).mockResolvedValueOnce(paused);
571
+ mockWorkflowService.pause.mockResolvedValue(undefined);
572
+
573
+ const response = await app.inject({
574
+ method: 'POST',
575
+ url: '/api/v1/workflows/wf-123/pause',
576
+ });
577
+
578
+ expect(response.statusCode).toBe(200);
579
+ const payload = response.json();
580
+ expect(payload.workflow.status).toBe('paused');
581
+ expect(mockWorkflowService.pause).toHaveBeenCalledWith('wf-123');
582
+ });
583
+
584
+ it('rejects pausing manifest-based workflows', async () => {
585
+ const manifestWorkflow = createMockWorkflowRuntime({
586
+ id: 'wf-123',
587
+ source: 'manifest',
588
+ });
589
+ mockWorkflowService.get.mockResolvedValue(manifestWorkflow);
590
+
591
+ const response = await app.inject({
592
+ method: 'POST',
593
+ url: '/api/v1/workflows/wf-123/pause',
594
+ });
595
+
596
+ expect(response.statusCode).toBe(400);
597
+ });
598
+ });
599
+
600
+ describe('POST /api/v1/workflows/:id/resume', () => {
601
+ it('resumes paused workflow', async () => {
602
+ const paused = createMockWorkflowRuntime({
603
+ id: 'wf-123',
604
+ source: 'standalone',
605
+ status: 'paused',
606
+ });
607
+ const resumed = createMockWorkflowRuntime({ id: 'wf-123', status: 'active' });
608
+
609
+ mockWorkflowService.get.mockResolvedValueOnce(paused).mockResolvedValueOnce(resumed);
610
+ mockWorkflowService.resume.mockResolvedValue(undefined);
611
+
612
+ const response = await app.inject({
613
+ method: 'POST',
614
+ url: '/api/v1/workflows/wf-123/resume',
615
+ });
616
+
617
+ expect(response.statusCode).toBe(200);
618
+ const payload = response.json();
619
+ expect(payload.workflow.status).toBe('active');
620
+ expect(mockWorkflowService.resume).toHaveBeenCalledWith('wf-123');
621
+ });
622
+ });
623
+
624
+ describe('GET /api/v1/workflows/handlers', () => {
625
+ it('lists available workflow handlers', async () => {
626
+ const handlers = [
627
+ {
628
+ id: 'builtin:shell',
629
+ name: 'Shell Command',
630
+ description: 'Run shell commands',
631
+ },
632
+ {
633
+ id: '@kb-labs/ai-review:review',
634
+ name: 'AI Code Review',
635
+ description: 'Review code with LLM',
636
+ },
637
+ ];
638
+
639
+ mockWorkflowService.getAvailableHandlers.mockResolvedValue(handlers);
640
+
641
+ const response = await app.inject({
642
+ method: 'GET',
643
+ url: '/api/v1/workflows/handlers',
644
+ });
645
+
646
+ expect(response.statusCode).toBe(200);
647
+ const payload = response.json();
648
+ expect(payload.handlers).toHaveLength(2);
649
+ expect(payload.total).toBe(2);
650
+ });
651
+ });
652
+
653
+ describe('POST /api/v1/workflows/validate', () => {
654
+ it('validates workflow spec', async () => {
655
+ const spec = createSampleWorkflowSpec();
656
+ const validationResult = {
657
+ valid: true,
658
+ errors: [],
659
+ warnings: [],
660
+ };
661
+
662
+ mockWorkflowService.validate.mockResolvedValue(validationResult);
663
+
664
+ const response = await app.inject({
665
+ method: 'POST',
666
+ url: '/api/v1/workflows/validate',
667
+ payload: { spec },
668
+ });
669
+
670
+ expect(response.statusCode).toBe(200);
671
+ const payload = response.json();
672
+ expect(payload.valid).toBe(true);
673
+ expect(mockWorkflowService.validate).toHaveBeenCalledWith(spec);
674
+ });
675
+
676
+ it('returns validation errors', async () => {
677
+ const invalidSpec = { name: 'test' }; // Missing required fields
678
+ const validationResult = {
679
+ valid: false,
680
+ errors: ['Missing required field: version', 'Missing required field: on'],
681
+ warnings: [],
682
+ };
683
+
684
+ mockWorkflowService.validate.mockResolvedValue(validationResult);
685
+
686
+ const response = await app.inject({
687
+ method: 'POST',
688
+ url: '/api/v1/workflows/validate',
689
+ payload: { spec: invalidSpec },
690
+ });
691
+
692
+ expect(response.statusCode).toBe(200);
693
+ const payload = response.json();
694
+ expect(payload.valid).toBe(false);
695
+ expect(payload.errors).toHaveLength(2);
696
+ });
697
+ });
698
+ });