@kindgi/api 0.0.0-bootstrap.0 → 0.1.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 (505) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +216 -1
  3. package/dist/adapter-binding.d.ts +177 -0
  4. package/dist/adapter-binding.d.ts.map +1 -0
  5. package/dist/adapter-binding.js +12 -0
  6. package/dist/adapter-binding.js.map +1 -0
  7. package/dist/agent-binding.d.ts +207 -0
  8. package/dist/agent-binding.d.ts.map +1 -0
  9. package/dist/agent-binding.js +4 -0
  10. package/dist/agent-binding.js.map +1 -0
  11. package/dist/app.d.ts +770 -0
  12. package/dist/app.d.ts.map +1 -0
  13. package/dist/app.js +396 -0
  14. package/dist/app.js.map +1 -0
  15. package/dist/capability-binding.d.ts +76 -0
  16. package/dist/capability-binding.d.ts.map +1 -0
  17. package/dist/capability-binding.js +4 -0
  18. package/dist/capability-binding.js.map +1 -0
  19. package/dist/cost-binding.d.ts +175 -0
  20. package/dist/cost-binding.d.ts.map +1 -0
  21. package/dist/cost-binding.js +13 -0
  22. package/dist/cost-binding.js.map +1 -0
  23. package/dist/deployment-binding.d.ts +201 -0
  24. package/dist/deployment-binding.d.ts.map +1 -0
  25. package/dist/deployment-binding.js +4 -0
  26. package/dist/deployment-binding.js.map +1 -0
  27. package/dist/env-binding.d.ts +132 -0
  28. package/dist/env-binding.d.ts.map +1 -0
  29. package/dist/env-binding.js +4 -0
  30. package/dist/env-binding.js.map +1 -0
  31. package/dist/errors.d.ts +37 -0
  32. package/dist/errors.d.ts.map +1 -0
  33. package/dist/errors.js +264 -0
  34. package/dist/errors.js.map +1 -0
  35. package/dist/eval-run-binding.d.ts +196 -0
  36. package/dist/eval-run-binding.d.ts.map +1 -0
  37. package/dist/eval-run-binding.js +16 -0
  38. package/dist/eval-run-binding.js.map +1 -0
  39. package/dist/eval-run-dispatcher.d.ts +131 -0
  40. package/dist/eval-run-dispatcher.d.ts.map +1 -0
  41. package/dist/eval-run-dispatcher.js +368 -0
  42. package/dist/eval-run-dispatcher.js.map +1 -0
  43. package/dist/eval-suite-binding.d.ts +227 -0
  44. package/dist/eval-suite-binding.d.ts.map +1 -0
  45. package/dist/eval-suite-binding.js +24 -0
  46. package/dist/eval-suite-binding.js.map +1 -0
  47. package/dist/event-bus-binding.d.ts +107 -0
  48. package/dist/event-bus-binding.d.ts.map +1 -0
  49. package/dist/event-bus-binding.js +5 -0
  50. package/dist/event-bus-binding.js.map +1 -0
  51. package/dist/flow-binding.d.ts +194 -0
  52. package/dist/flow-binding.d.ts.map +1 -0
  53. package/dist/flow-binding.js +4 -0
  54. package/dist/flow-binding.js.map +1 -0
  55. package/dist/guardrail-binding.d.ts +138 -0
  56. package/dist/guardrail-binding.d.ts.map +1 -0
  57. package/dist/guardrail-binding.js +4 -0
  58. package/dist/guardrail-binding.js.map +1 -0
  59. package/dist/handler-binding.d.ts +126 -0
  60. package/dist/handler-binding.d.ts.map +1 -0
  61. package/dist/handler-binding.js +4 -0
  62. package/dist/handler-binding.js.map +1 -0
  63. package/dist/hitl-binding.d.ts +115 -0
  64. package/dist/hitl-binding.d.ts.map +1 -0
  65. package/dist/hitl-binding.js +4 -0
  66. package/dist/hitl-binding.js.map +1 -0
  67. package/dist/identity-directory-binding.d.ts +116 -0
  68. package/dist/identity-directory-binding.d.ts.map +1 -0
  69. package/dist/identity-directory-binding.js +4 -0
  70. package/dist/identity-directory-binding.js.map +1 -0
  71. package/dist/identity-provider-binding.d.ts +184 -0
  72. package/dist/identity-provider-binding.d.ts.map +1 -0
  73. package/dist/identity-provider-binding.js +4 -0
  74. package/dist/identity-provider-binding.js.map +1 -0
  75. package/dist/image-registry-binding.d.ts +165 -0
  76. package/dist/image-registry-binding.d.ts.map +1 -0
  77. package/dist/image-registry-binding.js +4 -0
  78. package/dist/image-registry-binding.js.map +1 -0
  79. package/dist/index.d.ts +72 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +26 -0
  82. package/dist/index.js.map +1 -0
  83. package/dist/key-management-binding.d.ts +101 -0
  84. package/dist/key-management-binding.d.ts.map +1 -0
  85. package/dist/key-management-binding.js +4 -0
  86. package/dist/key-management-binding.js.map +1 -0
  87. package/dist/mcp-endpoint-binding.d.ts +312 -0
  88. package/dist/mcp-endpoint-binding.d.ts.map +1 -0
  89. package/dist/mcp-endpoint-binding.js +12 -0
  90. package/dist/mcp-endpoint-binding.js.map +1 -0
  91. package/dist/memory-binding.d.ts +209 -0
  92. package/dist/memory-binding.d.ts.map +1 -0
  93. package/dist/memory-binding.js +4 -0
  94. package/dist/memory-binding.js.map +1 -0
  95. package/dist/middleware/auth.d.ts +168 -0
  96. package/dist/middleware/auth.d.ts.map +1 -0
  97. package/dist/middleware/auth.js +247 -0
  98. package/dist/middleware/auth.js.map +1 -0
  99. package/dist/middleware/authorize.d.ts +26 -0
  100. package/dist/middleware/authorize.d.ts.map +1 -0
  101. package/dist/middleware/authorize.js +65 -0
  102. package/dist/middleware/authorize.js.map +1 -0
  103. package/dist/middleware/error-mapper.d.ts +13 -0
  104. package/dist/middleware/error-mapper.d.ts.map +1 -0
  105. package/dist/middleware/error-mapper.js +32 -0
  106. package/dist/middleware/error-mapper.js.map +1 -0
  107. package/dist/middleware/idempotency.d.ts +43 -0
  108. package/dist/middleware/idempotency.d.ts.map +1 -0
  109. package/dist/middleware/idempotency.js +118 -0
  110. package/dist/middleware/idempotency.js.map +1 -0
  111. package/dist/middleware/principal.d.ts +4 -0
  112. package/dist/middleware/principal.d.ts.map +1 -0
  113. package/dist/middleware/principal.js +42 -0
  114. package/dist/middleware/principal.js.map +1 -0
  115. package/dist/middleware/public-run-routes.d.ts +16 -0
  116. package/dist/middleware/public-run-routes.d.ts.map +1 -0
  117. package/dist/middleware/public-run-routes.js +43 -0
  118. package/dist/middleware/public-run-routes.js.map +1 -0
  119. package/dist/middleware/request-id.d.ts +14 -0
  120. package/dist/middleware/request-id.d.ts.map +1 -0
  121. package/dist/middleware/request-id.js +24 -0
  122. package/dist/middleware/request-id.js.map +1 -0
  123. package/dist/middleware/sigv4-verify.d.ts +64 -0
  124. package/dist/middleware/sigv4-verify.d.ts.map +1 -0
  125. package/dist/middleware/sigv4-verify.js +286 -0
  126. package/dist/middleware/sigv4-verify.js.map +1 -0
  127. package/dist/middleware/sigv4.d.ts +25 -0
  128. package/dist/middleware/sigv4.d.ts.map +1 -0
  129. package/dist/middleware/sigv4.js +120 -0
  130. package/dist/middleware/sigv4.js.map +1 -0
  131. package/dist/openapi/generate.d.ts +15 -0
  132. package/dist/openapi/generate.d.ts.map +1 -0
  133. package/dist/openapi/generate.js +241 -0
  134. package/dist/openapi/generate.js.map +1 -0
  135. package/dist/openapi/operations.d.ts +70 -0
  136. package/dist/openapi/operations.d.ts.map +1 -0
  137. package/dist/openapi/operations.js +5051 -0
  138. package/dist/openapi/operations.js.map +1 -0
  139. package/dist/openapi/schemas.d.ts +590 -0
  140. package/dist/openapi/schemas.d.ts.map +1 -0
  141. package/dist/openapi/schemas.js +5820 -0
  142. package/dist/openapi/schemas.js.map +1 -0
  143. package/dist/provenance-binding.d.ts +116 -0
  144. package/dist/provenance-binding.d.ts.map +1 -0
  145. package/dist/provenance-binding.js +31 -0
  146. package/dist/provenance-binding.js.map +1 -0
  147. package/dist/provider-binding.d.ts +174 -0
  148. package/dist/provider-binding.d.ts.map +1 -0
  149. package/dist/provider-binding.js +4 -0
  150. package/dist/provider-binding.js.map +1 -0
  151. package/dist/public-run-token.d.ts +97 -0
  152. package/dist/public-run-token.d.ts.map +1 -0
  153. package/dist/public-run-token.js +167 -0
  154. package/dist/public-run-token.js.map +1 -0
  155. package/dist/retention-binding.d.ts +69 -0
  156. package/dist/retention-binding.d.ts.map +1 -0
  157. package/dist/retention-binding.js +4 -0
  158. package/dist/retention-binding.js.map +1 -0
  159. package/dist/reviewer-binding.d.ts +84 -0
  160. package/dist/reviewer-binding.d.ts.map +1 -0
  161. package/dist/reviewer-binding.js +4 -0
  162. package/dist/reviewer-binding.js.map +1 -0
  163. package/dist/rotation-status-store.d.ts +96 -0
  164. package/dist/rotation-status-store.d.ts.map +1 -0
  165. package/dist/rotation-status-store.js +106 -0
  166. package/dist/rotation-status-store.js.map +1 -0
  167. package/dist/routes/adapters.d.ts +29 -0
  168. package/dist/routes/adapters.d.ts.map +1 -0
  169. package/dist/routes/adapters.js +230 -0
  170. package/dist/routes/adapters.js.map +1 -0
  171. package/dist/routes/agents.d.ts +17 -0
  172. package/dist/routes/agents.d.ts.map +1 -0
  173. package/dist/routes/agents.js +342 -0
  174. package/dist/routes/agents.js.map +1 -0
  175. package/dist/routes/approvals.d.ts +37 -0
  176. package/dist/routes/approvals.d.ts.map +1 -0
  177. package/dist/routes/approvals.js +551 -0
  178. package/dist/routes/approvals.js.map +1 -0
  179. package/dist/routes/artifacts.d.ts +25 -0
  180. package/dist/routes/artifacts.d.ts.map +1 -0
  181. package/dist/routes/artifacts.js +265 -0
  182. package/dist/routes/artifacts.js.map +1 -0
  183. package/dist/routes/audit.d.ts +6 -0
  184. package/dist/routes/audit.d.ts.map +1 -0
  185. package/dist/routes/audit.js +162 -0
  186. package/dist/routes/audit.js.map +1 -0
  187. package/dist/routes/auth.d.ts +47 -0
  188. package/dist/routes/auth.d.ts.map +1 -0
  189. package/dist/routes/auth.js +630 -0
  190. package/dist/routes/auth.js.map +1 -0
  191. package/dist/routes/capabilities.d.ts +14 -0
  192. package/dist/routes/capabilities.d.ts.map +1 -0
  193. package/dist/routes/capabilities.js +62 -0
  194. package/dist/routes/capabilities.js.map +1 -0
  195. package/dist/routes/compliance.d.ts +37 -0
  196. package/dist/routes/compliance.d.ts.map +1 -0
  197. package/dist/routes/compliance.js +321 -0
  198. package/dist/routes/compliance.js.map +1 -0
  199. package/dist/routes/conversations.d.ts +13 -0
  200. package/dist/routes/conversations.d.ts.map +1 -0
  201. package/dist/routes/conversations.js +295 -0
  202. package/dist/routes/conversations.js.map +1 -0
  203. package/dist/routes/cost.d.ts +24 -0
  204. package/dist/routes/cost.d.ts.map +1 -0
  205. package/dist/routes/cost.js +243 -0
  206. package/dist/routes/cost.js.map +1 -0
  207. package/dist/routes/deployments.d.ts +122 -0
  208. package/dist/routes/deployments.d.ts.map +1 -0
  209. package/dist/routes/deployments.js +1036 -0
  210. package/dist/routes/deployments.js.map +1 -0
  211. package/dist/routes/env.d.ts +62 -0
  212. package/dist/routes/env.d.ts.map +1 -0
  213. package/dist/routes/env.js +311 -0
  214. package/dist/routes/env.js.map +1 -0
  215. package/dist/routes/eval-runs.d.ts +28 -0
  216. package/dist/routes/eval-runs.d.ts.map +1 -0
  217. package/dist/routes/eval-runs.js +479 -0
  218. package/dist/routes/eval-runs.js.map +1 -0
  219. package/dist/routes/eval-suites.d.ts +24 -0
  220. package/dist/routes/eval-suites.d.ts.map +1 -0
  221. package/dist/routes/eval-suites.js +381 -0
  222. package/dist/routes/eval-suites.js.map +1 -0
  223. package/dist/routes/event-triggers.d.ts +12 -0
  224. package/dist/routes/event-triggers.d.ts.map +1 -0
  225. package/dist/routes/event-triggers.js +218 -0
  226. package/dist/routes/event-triggers.js.map +1 -0
  227. package/dist/routes/flows.d.ts +23 -0
  228. package/dist/routes/flows.d.ts.map +1 -0
  229. package/dist/routes/flows.js +344 -0
  230. package/dist/routes/flows.js.map +1 -0
  231. package/dist/routes/guardrails.d.ts +33 -0
  232. package/dist/routes/guardrails.d.ts.map +1 -0
  233. package/dist/routes/guardrails.js +236 -0
  234. package/dist/routes/guardrails.js.map +1 -0
  235. package/dist/routes/identity.d.ts +39 -0
  236. package/dist/routes/identity.d.ts.map +1 -0
  237. package/dist/routes/identity.js +138 -0
  238. package/dist/routes/identity.js.map +1 -0
  239. package/dist/routes/mcp.d.ts +23 -0
  240. package/dist/routes/mcp.d.ts.map +1 -0
  241. package/dist/routes/mcp.js +727 -0
  242. package/dist/routes/mcp.js.map +1 -0
  243. package/dist/routes/memory.d.ts +16 -0
  244. package/dist/routes/memory.d.ts.map +1 -0
  245. package/dist/routes/memory.js +353 -0
  246. package/dist/routes/memory.js.map +1 -0
  247. package/dist/routes/observations.d.ts +19 -0
  248. package/dist/routes/observations.d.ts.map +1 -0
  249. package/dist/routes/observations.js +135 -0
  250. package/dist/routes/observations.js.map +1 -0
  251. package/dist/routes/orgs.d.ts +24 -0
  252. package/dist/routes/orgs.d.ts.map +1 -0
  253. package/dist/routes/orgs.js +208 -0
  254. package/dist/routes/orgs.js.map +1 -0
  255. package/dist/routes/pagination.d.ts +18 -0
  256. package/dist/routes/pagination.d.ts.map +1 -0
  257. package/dist/routes/pagination.js +35 -0
  258. package/dist/routes/pagination.js.map +1 -0
  259. package/dist/routes/policies.d.ts +23 -0
  260. package/dist/routes/policies.d.ts.map +1 -0
  261. package/dist/routes/policies.js +314 -0
  262. package/dist/routes/policies.js.map +1 -0
  263. package/dist/routes/projects.d.ts +45 -0
  264. package/dist/routes/projects.d.ts.map +1 -0
  265. package/dist/routes/projects.js +485 -0
  266. package/dist/routes/projects.js.map +1 -0
  267. package/dist/routes/proposals.d.ts +24 -0
  268. package/dist/routes/proposals.d.ts.map +1 -0
  269. package/dist/routes/proposals.js +581 -0
  270. package/dist/routes/proposals.js.map +1 -0
  271. package/dist/routes/provenance.d.ts +34 -0
  272. package/dist/routes/provenance.d.ts.map +1 -0
  273. package/dist/routes/provenance.js +274 -0
  274. package/dist/routes/provenance.js.map +1 -0
  275. package/dist/routes/providers.d.ts +32 -0
  276. package/dist/routes/providers.d.ts.map +1 -0
  277. package/dist/routes/providers.js +490 -0
  278. package/dist/routes/providers.js.map +1 -0
  279. package/dist/routes/public-run-tokens.d.ts +17 -0
  280. package/dist/routes/public-run-tokens.d.ts.map +1 -0
  281. package/dist/routes/public-run-tokens.js +69 -0
  282. package/dist/routes/public-run-tokens.js.map +1 -0
  283. package/dist/routes/retention.d.ts +19 -0
  284. package/dist/routes/retention.d.ts.map +1 -0
  285. package/dist/routes/retention.js +152 -0
  286. package/dist/routes/retention.js.map +1 -0
  287. package/dist/routes/reviewers.d.ts +5 -0
  288. package/dist/routes/reviewers.d.ts.map +1 -0
  289. package/dist/routes/reviewers.js +161 -0
  290. package/dist/routes/reviewers.js.map +1 -0
  291. package/dist/routes/runs.d.ts +34 -0
  292. package/dist/routes/runs.d.ts.map +1 -0
  293. package/dist/routes/runs.js +773 -0
  294. package/dist/routes/runs.js.map +1 -0
  295. package/dist/routes/s3.d.ts +31 -0
  296. package/dist/routes/s3.d.ts.map +1 -0
  297. package/dist/routes/s3.js +433 -0
  298. package/dist/routes/s3.js.map +1 -0
  299. package/dist/routes/schedules.d.ts +20 -0
  300. package/dist/routes/schedules.d.ts.map +1 -0
  301. package/dist/routes/schedules.js +234 -0
  302. package/dist/routes/schedules.js.map +1 -0
  303. package/dist/routes/scope-params.d.ts +57 -0
  304. package/dist/routes/scope-params.d.ts.map +1 -0
  305. package/dist/routes/scope-params.js +105 -0
  306. package/dist/routes/scope-params.js.map +1 -0
  307. package/dist/routes/secret-ref.d.ts +20 -0
  308. package/dist/routes/secret-ref.d.ts.map +1 -0
  309. package/dist/routes/secret-ref.js +42 -0
  310. package/dist/routes/secret-ref.js.map +1 -0
  311. package/dist/routes/secrets.d.ts +53 -0
  312. package/dist/routes/secrets.d.ts.map +1 -0
  313. package/dist/routes/secrets.js +715 -0
  314. package/dist/routes/secrets.js.map +1 -0
  315. package/dist/routes/signing-keys.d.ts +23 -0
  316. package/dist/routes/signing-keys.d.ts.map +1 -0
  317. package/dist/routes/signing-keys.js +212 -0
  318. package/dist/routes/signing-keys.js.map +1 -0
  319. package/dist/routes/sse.d.ts +58 -0
  320. package/dist/routes/sse.d.ts.map +1 -0
  321. package/dist/routes/sse.js +92 -0
  322. package/dist/routes/sse.js.map +1 -0
  323. package/dist/routes/teams.d.ts +30 -0
  324. package/dist/routes/teams.d.ts.map +1 -0
  325. package/dist/routes/teams.js +443 -0
  326. package/dist/routes/teams.js.map +1 -0
  327. package/dist/routes/tenant.d.ts +57 -0
  328. package/dist/routes/tenant.d.ts.map +1 -0
  329. package/dist/routes/tenant.js +352 -0
  330. package/dist/routes/tenant.js.map +1 -0
  331. package/dist/routes/tokens.d.ts +14 -0
  332. package/dist/routes/tokens.d.ts.map +1 -0
  333. package/dist/routes/tokens.js +231 -0
  334. package/dist/routes/tokens.js.map +1 -0
  335. package/dist/routes/tools.d.ts +33 -0
  336. package/dist/routes/tools.d.ts.map +1 -0
  337. package/dist/routes/tools.js +380 -0
  338. package/dist/routes/tools.js.map +1 -0
  339. package/dist/routes/webhook-endpoints.d.ts +10 -0
  340. package/dist/routes/webhook-endpoints.d.ts.map +1 -0
  341. package/dist/routes/webhook-endpoints.js +407 -0
  342. package/dist/routes/webhook-endpoints.js.map +1 -0
  343. package/dist/routes/webhooks.d.ts +21 -0
  344. package/dist/routes/webhooks.d.ts.map +1 -0
  345. package/dist/routes/webhooks.js +228 -0
  346. package/dist/routes/webhooks.js.map +1 -0
  347. package/dist/s3-credential-binding.d.ts +54 -0
  348. package/dist/s3-credential-binding.d.ts.map +1 -0
  349. package/dist/s3-credential-binding.js +4 -0
  350. package/dist/s3-credential-binding.js.map +1 -0
  351. package/dist/secrets-binding.d.ts +281 -0
  352. package/dist/secrets-binding.d.ts.map +1 -0
  353. package/dist/secrets-binding.js +10 -0
  354. package/dist/secrets-binding.js.map +1 -0
  355. package/dist/secrets-provider-binding.d.ts +164 -0
  356. package/dist/secrets-provider-binding.d.ts.map +1 -0
  357. package/dist/secrets-provider-binding.js +4 -0
  358. package/dist/secrets-provider-binding.js.map +1 -0
  359. package/dist/session-store-binding.d.ts +148 -0
  360. package/dist/session-store-binding.d.ts.map +1 -0
  361. package/dist/session-store-binding.js +4 -0
  362. package/dist/session-store-binding.js.map +1 -0
  363. package/dist/signing-key-binding.d.ts +210 -0
  364. package/dist/signing-key-binding.d.ts.map +1 -0
  365. package/dist/signing-key-binding.js +4 -0
  366. package/dist/signing-key-binding.js.map +1 -0
  367. package/dist/state-store-binding.d.ts +53 -0
  368. package/dist/state-store-binding.d.ts.map +1 -0
  369. package/dist/state-store-binding.js +38 -0
  370. package/dist/state-store-binding.js.map +1 -0
  371. package/dist/supervisor-binding.d.ts +526 -0
  372. package/dist/supervisor-binding.d.ts.map +1 -0
  373. package/dist/supervisor-binding.js +4 -0
  374. package/dist/supervisor-binding.js.map +1 -0
  375. package/dist/tenant-host-access.d.ts +41 -0
  376. package/dist/tenant-host-access.d.ts.map +1 -0
  377. package/dist/tenant-host-access.js +42 -0
  378. package/dist/tenant-host-access.js.map +1 -0
  379. package/dist/token-admin.d.ts +99 -0
  380. package/dist/token-admin.d.ts.map +1 -0
  381. package/dist/token-admin.js +4 -0
  382. package/dist/token-admin.js.map +1 -0
  383. package/dist/tool-binding.d.ts +247 -0
  384. package/dist/tool-binding.d.ts.map +1 -0
  385. package/dist/tool-binding.js +4 -0
  386. package/dist/tool-binding.js.map +1 -0
  387. package/dist/trigger-binding.d.ts +13 -0
  388. package/dist/trigger-binding.d.ts.map +1 -0
  389. package/dist/trigger-binding.js +4 -0
  390. package/dist/trigger-binding.js.map +1 -0
  391. package/dist/types.d.ts +71 -0
  392. package/dist/types.d.ts.map +1 -0
  393. package/dist/types.js +4 -0
  394. package/dist/types.js.map +1 -0
  395. package/dist/webhook-endpoint-binding.d.ts +230 -0
  396. package/dist/webhook-endpoint-binding.d.ts.map +1 -0
  397. package/dist/webhook-endpoint-binding.js +12 -0
  398. package/dist/webhook-endpoint-binding.js.map +1 -0
  399. package/dist/xml.d.ts +79 -0
  400. package/dist/xml.d.ts.map +1 -0
  401. package/dist/xml.js +115 -0
  402. package/dist/xml.js.map +1 -0
  403. package/openapi.json +29659 -0
  404. package/package.json +76 -4
  405. package/scripts/emit-openapi.mjs +44 -0
  406. package/src/adapter-binding.ts +204 -0
  407. package/src/agent-binding.ts +231 -0
  408. package/src/app.ts +1285 -0
  409. package/src/capability-binding.ts +83 -0
  410. package/src/cost-binding.ts +213 -0
  411. package/src/deployment-binding.ts +225 -0
  412. package/src/env-binding.ts +140 -0
  413. package/src/errors.ts +291 -0
  414. package/src/eval-run-binding.ts +209 -0
  415. package/src/eval-run-dispatcher.ts +497 -0
  416. package/src/eval-suite-binding.ts +257 -0
  417. package/src/event-bus-binding.ts +127 -0
  418. package/src/flow-binding.ts +213 -0
  419. package/src/guardrail-binding.ts +151 -0
  420. package/src/handler-binding.ts +132 -0
  421. package/src/hitl-binding.ts +172 -0
  422. package/src/identity-directory-binding.ts +128 -0
  423. package/src/identity-provider-binding.ts +203 -0
  424. package/src/image-registry-binding.ts +193 -0
  425. package/src/index.ts +606 -0
  426. package/src/key-management-binding.ts +91 -0
  427. package/src/mcp-endpoint-binding.ts +311 -0
  428. package/src/memory-binding.ts +239 -0
  429. package/src/middleware/auth.ts +437 -0
  430. package/src/middleware/authorize.ts +125 -0
  431. package/src/middleware/error-mapper.ts +37 -0
  432. package/src/middleware/idempotency.ts +160 -0
  433. package/src/middleware/principal.ts +64 -0
  434. package/src/middleware/public-run-routes.ts +50 -0
  435. package/src/middleware/request-id.ts +28 -0
  436. package/src/middleware/sigv4-verify.ts +374 -0
  437. package/src/middleware/sigv4.ts +165 -0
  438. package/src/openapi/generate.ts +307 -0
  439. package/src/openapi/operations.ts +5445 -0
  440. package/src/openapi/schemas.ts +6363 -0
  441. package/src/provenance-binding.ts +169 -0
  442. package/src/provider-binding.ts +196 -0
  443. package/src/public-run-token.ts +263 -0
  444. package/src/retention-binding.ts +78 -0
  445. package/src/reviewer-binding.ts +99 -0
  446. package/src/rotation-status-store.ts +209 -0
  447. package/src/routes/adapters.ts +319 -0
  448. package/src/routes/agents.ts +424 -0
  449. package/src/routes/approvals.ts +759 -0
  450. package/src/routes/artifacts.ts +317 -0
  451. package/src/routes/audit.ts +219 -0
  452. package/src/routes/auth.ts +806 -0
  453. package/src/routes/capabilities.ts +79 -0
  454. package/src/routes/compliance.ts +482 -0
  455. package/src/routes/conversations.ts +369 -0
  456. package/src/routes/cost.ts +327 -0
  457. package/src/routes/deployments.ts +1493 -0
  458. package/src/routes/env.ts +429 -0
  459. package/src/routes/eval-runs.ts +631 -0
  460. package/src/routes/eval-suites.ts +490 -0
  461. package/src/routes/event-triggers.ts +283 -0
  462. package/src/routes/flows.ts +423 -0
  463. package/src/routes/guardrails.ts +320 -0
  464. package/src/routes/identity.ts +203 -0
  465. package/src/routes/mcp.ts +940 -0
  466. package/src/routes/memory.ts +430 -0
  467. package/src/routes/observations.ts +175 -0
  468. package/src/routes/orgs.ts +273 -0
  469. package/src/routes/pagination.ts +51 -0
  470. package/src/routes/policies.ts +413 -0
  471. package/src/routes/projects.ts +634 -0
  472. package/src/routes/proposals.ts +719 -0
  473. package/src/routes/provenance.ts +406 -0
  474. package/src/routes/providers.ts +624 -0
  475. package/src/routes/public-run-tokens.ts +104 -0
  476. package/src/routes/retention.ts +193 -0
  477. package/src/routes/reviewers.ts +209 -0
  478. package/src/routes/runs.ts +981 -0
  479. package/src/routes/s3.ts +519 -0
  480. package/src/routes/schedules.ts +300 -0
  481. package/src/routes/scope-params.ts +133 -0
  482. package/src/routes/secret-ref.ts +52 -0
  483. package/src/routes/secrets.ts +975 -0
  484. package/src/routes/signing-keys.ts +259 -0
  485. package/src/routes/sse.ts +148 -0
  486. package/src/routes/teams.ts +584 -0
  487. package/src/routes/tenant.ts +530 -0
  488. package/src/routes/tokens.ts +285 -0
  489. package/src/routes/tools.ts +491 -0
  490. package/src/routes/webhook-endpoints.ts +534 -0
  491. package/src/routes/webhooks.ts +296 -0
  492. package/src/s3-credential-binding.ts +58 -0
  493. package/src/secrets-binding.ts +308 -0
  494. package/src/secrets-provider-binding.ts +167 -0
  495. package/src/session-store-binding.ts +163 -0
  496. package/src/signing-key-binding.ts +235 -0
  497. package/src/state-store-binding.ts +84 -0
  498. package/src/supervisor-binding.ts +554 -0
  499. package/src/tenant-host-access.ts +62 -0
  500. package/src/token-admin.ts +104 -0
  501. package/src/tool-binding.ts +274 -0
  502. package/src/trigger-binding.ts +38 -0
  503. package/src/types.ts +74 -0
  504. package/src/webhook-endpoint-binding.ts +246 -0
  505. package/src/xml.ts +196 -0
@@ -0,0 +1,981 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+
4
+ import { Hono } from 'hono';
5
+
6
+ import type { AgentId } from '@kindgi/agents';
7
+ import type { KernelRunRecord, ListRunsInput, RunBinding } from '@kindgi/runtime';
8
+ import type { FlowId, OrgId, ProjectId, RunId, Semver, TenantId } from '@kindgi/types';
9
+
10
+ import { ref } from '@kindgi/authz';
11
+
12
+ import { type WireErrorBody, statusFor, toWireError } from '../errors.js';
13
+ import type { EventBusBinding, EventPayload, Subscription } from '../event-bus-binding.js';
14
+ import type {
15
+ RunHandlerBinding,
16
+ RunHandlerFailure,
17
+ RunHandlerOutcome,
18
+ } from '../handler-binding.js';
19
+ import type { Authorizer } from '../middleware/authorize.js';
20
+ import type { MintPublicRunTokenResult } from '../public-run-token.js';
21
+ import type { AppEnv } from '../types.js';
22
+ import type { DecodedCursor } from './pagination.js';
23
+ import { clampLimit, decodeCursor } from './pagination.js';
24
+ import { type ParseScopeParamsOutcome, parseScopeParams } from './scope-params.js';
25
+ import {
26
+ formatSseFrame,
27
+ isTerminalWireKind,
28
+ parseLastEventId,
29
+ projectJournalEntry,
30
+ toRunProgressEvent,
31
+ } from './sse.js';
32
+
33
+ const KERNEL_RUN_CHANNEL_PREFIX = 'kernel:run:';
34
+
35
+ /** Options for `runsRouter`. */
36
+ export interface RunsRouterOptions {
37
+ /**
38
+ * Optional push-based event bus. When present, `GET /:runId/stream`
39
+ * subscribes on `kernel:run:<runId>` and delivers events
40
+ * push-mode. When absent, the route polls the run's journal every
41
+ * 200 ms — wire shape identical either way.
42
+ */
43
+ readonly eventBus?: EventBusBinding;
44
+ /**
45
+ * Issue public run tokens: `POST /` adds a `publicAccessToken` for the
46
+ * new run, for its progress routes.
47
+ */
48
+ readonly publicRunTokens?: {
49
+ readonly mint: (tenantId: TenantId, runIds: readonly RunId[]) => MintPublicRunTokenResult;
50
+ };
51
+ }
52
+
53
+ /** How far up the parent chain a public token's grant reaches. */
54
+ const MAX_RUN_ANCESTRY = 16;
55
+
56
+ /**
57
+ * Runs resource routes (per `docs/API-ROUTE-CONVENTIONS.md` §7).
58
+ *
59
+ * Routes: `POST /` (start), `GET /:runId`, `GET /` (list),
60
+ * `POST /:runId/cancel`, `POST /:runId/resume`, `GET /:runId/stream`
61
+ * (SSE), `GET /:runId/journal`.
62
+ */
63
+ export function runsRouter(
64
+ binding: RunHandlerBinding,
65
+ runBinding: RunBinding,
66
+ options: RunsRouterOptions = {},
67
+ authorizer?: Authorizer,
68
+ ): Hono<AppEnv> {
69
+ const r = new Hono<AppEnv>();
70
+ const eventBus = options.eventBus;
71
+
72
+ // Authorization — a run inherits its permissions from its project.
73
+ // Each check resolves the run's project (by run id) and asks the
74
+ // authorizer about that project:
75
+ //
76
+ // POST / — no route-level check; `execute` on the agent
77
+ // or flow is up to the run handler binding.
78
+ // GET /:runId — read on the run's project
79
+ // POST /:runId/cancel — write on the run's project
80
+ // POST /:runId/resume — execute on the run's project
81
+ // GET /:runId/journal — read on the run's project
82
+ // GET /:runId/stream — read on the run's project
83
+ // GET / — list; tenant-scoped, the scope filter narrows
84
+ // further (rows are not filtered per permission)
85
+ if (authorizer !== undefined) {
86
+ const projectFromRun = async (c: import('hono').Context<AppEnv>) => {
87
+ const tenantId = c.get('tenantId') as TenantId;
88
+ const runId = c.req.param('runId') ?? '';
89
+ if (runId.length === 0) return ref('tenant', tenantId as unknown as string);
90
+ const row = await runBinding.getRun(tenantId, runId as RunId);
91
+ if (row === null) {
92
+ // Fall back to tenant so the underlying handler surfaces
93
+ // 404 rather than the middleware masking it as 403.
94
+ return ref('tenant', tenantId as unknown as string);
95
+ }
96
+ return ref('project', row.projectId as unknown as string);
97
+ };
98
+ r.use('/:runId', async (c, next) => {
99
+ if (c.req.method !== 'GET') return next();
100
+ const mw = authorizer.authorize('read', projectFromRun);
101
+ return mw(c, next);
102
+ });
103
+ r.use('/:runId/journal', async (c, next) => {
104
+ const mw = authorizer.authorize('read', projectFromRun);
105
+ return mw(c, next);
106
+ });
107
+ r.use('/:runId/stream', async (c, next) => {
108
+ const mw = authorizer.authorize('read', projectFromRun);
109
+ return mw(c, next);
110
+ });
111
+ // Progress: `read` for API tokens. A public run token has no
112
+ // principal; the handlers check that its grant covers the run.
113
+ const progressAuth = async (c: import('hono').Context<AppEnv>, next: import('hono').Next) => {
114
+ if (c.get('tokenKind') === 'public-run') return next();
115
+ const mw = authorizer.authorize('read', projectFromRun);
116
+ return mw(c, next);
117
+ };
118
+ r.use('/:runId/progress', progressAuth);
119
+ r.use('/:runId/progress/stream', progressAuth);
120
+ r.use('/:runId/cancel', async (c, next) => {
121
+ const mw = authorizer.authorize('write', projectFromRun);
122
+ return mw(c, next);
123
+ });
124
+ r.use('/:runId/resume', async (c, next) => {
125
+ const mw = authorizer.authorize('execute', projectFromRun);
126
+ return mw(c, next);
127
+ });
128
+ }
129
+
130
+ // ---------- POST / (start a run — agent | flow) ----------
131
+ r.post('/', async (c) => {
132
+ const requestId = c.get('requestId');
133
+ const tenantId = c.get('tenantId') as TenantId;
134
+
135
+ let body: unknown;
136
+ try {
137
+ body = await c.req.json();
138
+ } catch {
139
+ c.status(statusFor('bad-input') as never);
140
+ return c.json(
141
+ toWireError({ code: 'bad-input', message: 'Request body must be valid JSON' }, requestId),
142
+ );
143
+ }
144
+ const parsed = parseStartRunBody(body);
145
+ if (parsed.kind === 'err') {
146
+ c.status(statusFor(parsed.error.code) as never);
147
+ return c.json(toWireError(parsed.error, requestId));
148
+ }
149
+
150
+ const invocation = await invokeFromBody(binding, tenantId, parsed.value);
151
+
152
+ if (invocation.kind === 'err') {
153
+ c.status(statusFor(invocation.error.code) as never);
154
+ return c.json(runFailureToWire(invocation.error, requestId));
155
+ }
156
+
157
+ const runId = invocation.runId;
158
+ const loaded = await runBinding.getRun(tenantId, runId);
159
+ if (loaded === null) {
160
+ c.status(statusFor('journal-error') as never);
161
+ return c.json(
162
+ toWireError(
163
+ { code: 'journal-error', message: `Run ${runId} started but row not readable` },
164
+ requestId,
165
+ ),
166
+ );
167
+ }
168
+ // `wait: false` → the binding handed the run id back before the
169
+ // run finished: 202, and the caller polls `GET /v1/runs/:runId`.
170
+ c.status(parsed.value.wait === false ? 202 : 201);
171
+ const minted = options.publicRunTokens?.mint(tenantId, [runId]);
172
+ return c.json({
173
+ ...serializeRun(loaded, { output: true }),
174
+ ...(minted?.kind === 'ok' && {
175
+ publicAccessToken: minted.token,
176
+ publicAccessTokenExpiresAt: minted.expiresAt.toISOString(),
177
+ }),
178
+ });
179
+ });
180
+
181
+ // ---------- GET /:runId ----------
182
+ r.get('/:runId', async (c) => {
183
+ const requestId = c.get('requestId');
184
+ const runId = c.req.param('runId') as RunId;
185
+
186
+ const loaded = await runBinding.getRun(c.get('tenantId') as TenantId, runId);
187
+ if (loaded === null) {
188
+ c.status(statusFor('run-not-found') as never);
189
+ return c.json(
190
+ toWireError({ code: 'run-not-found', message: `No run with id ${runId}` }, requestId),
191
+ );
192
+ }
193
+ return c.json(serializeRun(loaded, { output: true }));
194
+ });
195
+
196
+ // ---------- GET /:runId/progress ----------
197
+ r.get('/:runId/progress', async (c) => {
198
+ const requestId = c.get('requestId');
199
+ const runId = c.req.param('runId') as RunId;
200
+ const loaded = await readableRun(runBinding, c, runId);
201
+ if (loaded === null) {
202
+ c.status(statusFor('run-not-found') as never);
203
+ return c.json(
204
+ toWireError({ code: 'run-not-found', message: `No run with id ${runId}` }, requestId),
205
+ );
206
+ }
207
+ return c.json(serializeRunProgress(loaded));
208
+ });
209
+
210
+ // ---------- GET / (list, cursor-paginated) ----------
211
+ //
212
+ // Content-scoped list; scope filter threaded via `parseScopeParams`.
213
+ // Every run belongs to exactly one project; `scope.kind === 'project'`
214
+ // narrows to that project, `scope.kind === 'org'` to the org's
215
+ // projects, and tenant / undefined behave as documented in
216
+ // scope-params.ts.
217
+ r.get('/', async (c) => {
218
+ const requestId = c.get('requestId');
219
+ const tenantId = c.get('tenantId') as TenantId;
220
+ const limit = clampLimit(c.req.query('limit'));
221
+
222
+ let cursorFilter: DecodedCursor | null = null;
223
+ const rawCursor = c.req.query('cursor');
224
+ if (rawCursor !== undefined && rawCursor.length > 0) {
225
+ const decoded = decodeCursor(rawCursor);
226
+ if (decoded === null) {
227
+ c.status(statusFor('bad-input') as never);
228
+ return c.json(
229
+ toWireError({ code: 'bad-input', message: '`cursor` is malformed' }, requestId),
230
+ );
231
+ }
232
+ cursorFilter = decoded;
233
+ }
234
+
235
+ const scopeParsed = parseScopeParams(c.req.query(), { tenantId });
236
+ if (scopeParsed.kind === 'err') {
237
+ c.status(statusFor('scope-invalid') as never);
238
+ return c.json(
239
+ toWireError({ code: 'scope-invalid', message: scopeParsed.message }, requestId),
240
+ );
241
+ }
242
+ const listFilter = parseRunListFilter(c.req.query());
243
+ if (listFilter.kind === 'err') {
244
+ c.status(statusFor('bad-input') as never);
245
+ return c.json(toWireError({ code: 'bad-input', message: listFilter.message }, requestId));
246
+ }
247
+ const includeOutput = listFilter.value.includeOutput;
248
+
249
+ const page = await runBinding.listRuns(
250
+ listRunsInput({
251
+ tenantId,
252
+ scope: scopeParsed.scope,
253
+ limit,
254
+ cursor: cursorFilter,
255
+ filter: listFilter.value,
256
+ }),
257
+ );
258
+ return c.json({
259
+ data: page.data.map((row) => serializeRun(row, { output: includeOutput })),
260
+ hasMore: page.nextCursor !== undefined,
261
+ ...(page.nextCursor !== undefined && { nextCursor: page.nextCursor as unknown as string }),
262
+ });
263
+ });
264
+
265
+ // ---------- POST /:runId/cancel ----------
266
+ r.post('/:runId/cancel', async (c) => {
267
+ const requestId = c.get('requestId');
268
+ const tenantId = c.get('tenantId') as TenantId;
269
+ const runId = c.req.param('runId') as RunId;
270
+
271
+ const cancelled = await runBinding.cancelRun(tenantId, runId, eventBus);
272
+ if (cancelled.kind === 'err') {
273
+ const err = cancelled.error;
274
+ c.status(statusFor(err.code) as never);
275
+ return c.json(toWireError(err as never, requestId));
276
+ }
277
+
278
+ // Re-read to return the updated row.
279
+ const reloaded = await runBinding.getRun(tenantId, runId);
280
+ if (reloaded === null) {
281
+ c.status(statusFor('journal-error') as never);
282
+ return c.json(
283
+ toWireError(
284
+ {
285
+ code: 'journal-error',
286
+ message: 'Cancelled OK but failed to reload run row',
287
+ },
288
+ requestId,
289
+ ),
290
+ );
291
+ }
292
+ return c.json(serializeRun(reloaded, { output: true }));
293
+ });
294
+
295
+ // ---------- POST /:runId/resume ----------
296
+ r.post('/:runId/resume', async (c) => {
297
+ const requestId = c.get('requestId');
298
+ const tenantId = c.get('tenantId') as TenantId;
299
+ const runId = c.req.param('runId') as RunId;
300
+
301
+ let body: unknown = {};
302
+ const hasBody =
303
+ (c.req.header('content-type') ?? '').includes('json') ||
304
+ (c.req.header('content-length') !== undefined && c.req.header('content-length') !== '0');
305
+ if (hasBody) {
306
+ try {
307
+ const text = await c.req.text();
308
+ body = text.length > 0 ? JSON.parse(text) : {};
309
+ } catch {
310
+ c.status(statusFor('bad-input') as never);
311
+ return c.json(
312
+ toWireError({ code: 'bad-input', message: 'Request body must be valid JSON' }, requestId),
313
+ );
314
+ }
315
+ }
316
+ const parsed = parseResumeBody(body);
317
+ if (parsed.kind === 'err') {
318
+ c.status(statusFor(parsed.error.code) as never);
319
+ return c.json(toWireError(parsed.error, requestId));
320
+ }
321
+
322
+ // Resume completes a waitpoint (`completeToken`) and then drives the
323
+ // run on. Resuming without a `waitpointId` is not supported.
324
+ if (parsed.value.waitpointId === undefined) {
325
+ c.status(statusFor('bad-input') as never);
326
+ return c.json(
327
+ toWireError(
328
+ {
329
+ code: 'bad-input',
330
+ message:
331
+ 'Programmatic resume without `waitpointId` is not supported yet — supply a waitpoint id to complete a wait token.',
332
+ },
333
+ requestId,
334
+ ),
335
+ );
336
+ }
337
+
338
+ const completed = await runBinding.completeToken(
339
+ tenantId,
340
+ runId,
341
+ parsed.value.waitpointId,
342
+ parsed.value.value,
343
+ eventBus,
344
+ );
345
+ if (completed.kind === 'err') {
346
+ const err = completed.error;
347
+ c.status(statusFor(err.code) as never);
348
+ return c.json(toWireError(err as never, requestId));
349
+ }
350
+
351
+ // Drive the run on in the same request, as approvals do. Soft on
352
+ // failure: the token completion is already durable, so the run is
353
+ // resumable later; the response shows the status it reached.
354
+ await binding.resumeRun({ tenantId, runId }).catch(() => undefined);
355
+
356
+ const reloaded = await runBinding.getRun(tenantId, runId);
357
+ if (reloaded === null) {
358
+ c.status(statusFor('run-not-found') as never);
359
+ return c.json(
360
+ toWireError({ code: 'run-not-found', message: `No run with id ${runId}` }, requestId),
361
+ );
362
+ }
363
+ return c.json(serializeRun(reloaded, { output: true }));
364
+ });
365
+
366
+ // ---------- GET /:runId/stream and /:runId/progress/stream (SSE) ----------
367
+ // One stream, two views: every event in full, or progress only (no
368
+ // payloads), which a public run token may follow.
369
+ const streamRun = async (c: import('hono').Context<AppEnv>, view: 'full' | 'progress') => {
370
+ const requestId = c.get('requestId');
371
+ const tenantId = c.get('tenantId') as TenantId;
372
+ const runId = c.req.param('runId') as RunId;
373
+ const since = parseLastEventId(c.req.header('last-event-id'));
374
+
375
+ // Verify the run belongs to this tenant before opening the stream —
376
+ // otherwise a cross-tenant probe learns run existence via the stream
377
+ // hanging vs 404-ing.
378
+ const run = await readableRun(runBinding, c, runId);
379
+ if (run === null) {
380
+ c.status(statusFor('run-not-found') as never);
381
+ return c.json(
382
+ toWireError({ code: 'run-not-found', message: `No run with id ${runId}` }, requestId),
383
+ );
384
+ }
385
+
386
+ const encoder = new TextEncoder();
387
+ let lastEmittedSeq = since ?? -1;
388
+ const POLL_MS = 200;
389
+ const MAX_WAIT_MS = 5 * 60_000;
390
+
391
+ const body = new ReadableStream<Uint8Array>({
392
+ async start(controller) {
393
+ const startedAt = Date.now();
394
+ let closed = false;
395
+ const close = (): void => {
396
+ if (closed) return;
397
+ closed = true;
398
+ try {
399
+ controller.close();
400
+ } catch {
401
+ /* already closed */
402
+ }
403
+ };
404
+
405
+ // Shared projection helper: emit one journal-entry-shaped
406
+ // record to the stream. Returns true iff the entry was a
407
+ // terminal wire kind so the caller can close.
408
+ const emitEntry = (entry: {
409
+ sequence: number;
410
+ kind: string;
411
+ nodeId?: string;
412
+ payload?: unknown;
413
+ timestamp: string;
414
+ }): boolean => {
415
+ if (entry.sequence <= lastEmittedSeq) return false;
416
+ const projected = projectJournalEntry(
417
+ {
418
+ sequence: entry.sequence,
419
+ kind: entry.kind as never,
420
+ ...(entry.nodeId !== undefined && { nodeId: entry.nodeId as never }),
421
+ ...(entry.payload !== undefined && { payload: entry.payload }),
422
+ timestamp: entry.timestamp as never,
423
+ },
424
+ runId,
425
+ tenantId,
426
+ );
427
+ lastEmittedSeq = entry.sequence;
428
+ if (projected === null) return false;
429
+ controller.enqueue(
430
+ encoder.encode(
431
+ formatSseFrame({
432
+ id: projected.event.eventId,
433
+ event: projected.wireKind,
434
+ data: view === 'progress' ? toRunProgressEvent(projected.event) : projected.event,
435
+ }),
436
+ ),
437
+ );
438
+ return isTerminalWireKind(projected.wireKind);
439
+ };
440
+
441
+ // Push-mode: prefer the event bus when wired. The bus delivers
442
+ // journal entries as `doc` payloads; we backfill via journal
443
+ // reads from `since` first so `Last-Event-Id` resumes work
444
+ // whether we're on the push or poll path.
445
+ if (eventBus !== undefined) {
446
+ const abortCtrl = new AbortController();
447
+ let subscription: Subscription | null = null;
448
+ let fallBackToPoll = false;
449
+ try {
450
+ // Backfill: read persisted journal up to now first, so a
451
+ // reconnect with `Last-Event-Id` doesn't miss events that
452
+ // landed while the client was disconnected. Then subscribe
453
+ // for the tail push-side.
454
+ const backfill = await runBinding.readJournal(tenantId, runId);
455
+ if (backfill.kind === 'err') {
456
+ controller.enqueue(
457
+ encoder.encode(
458
+ formatSseFrame({
459
+ id: `${runId}:error`,
460
+ event: 'error',
461
+ data: {
462
+ code: 'journal-error',
463
+ message: backfill.error.message,
464
+ requestId,
465
+ },
466
+ }),
467
+ ),
468
+ );
469
+ close();
470
+ return;
471
+ }
472
+ let sawTerminal = false;
473
+ for (const entry of backfill.value) {
474
+ if (
475
+ emitEntry({
476
+ sequence: entry.sequence,
477
+ kind: entry.kind,
478
+ ...(entry.nodeId !== undefined && { nodeId: entry.nodeId as string }),
479
+ ...(entry.payload !== undefined && { payload: entry.payload }),
480
+ timestamp: entry.timestamp as string,
481
+ })
482
+ ) {
483
+ sawTerminal = true;
484
+ }
485
+ }
486
+ if (sawTerminal) {
487
+ close();
488
+ return;
489
+ }
490
+ const subOutcome = await eventBus.subscribe(
491
+ tenantId,
492
+ `${KERNEL_RUN_CHANNEL_PREFIX}${runId}`,
493
+ (payload: EventPayload) => {
494
+ const doc = payload.doc as
495
+ | {
496
+ sequence?: unknown;
497
+ kind?: unknown;
498
+ nodeId?: unknown;
499
+ payload?: unknown;
500
+ timestamp?: unknown;
501
+ }
502
+ | null
503
+ | undefined;
504
+ if (doc === null || doc === undefined) return;
505
+ if (typeof doc.sequence !== 'number' || typeof doc.kind !== 'string') return;
506
+ if (typeof doc.timestamp !== 'string') return;
507
+ const wasTerminal = emitEntry({
508
+ sequence: doc.sequence,
509
+ kind: doc.kind,
510
+ ...(typeof doc.nodeId === 'string' && { nodeId: doc.nodeId }),
511
+ ...('payload' in doc && doc.payload !== undefined && { payload: doc.payload }),
512
+ timestamp: doc.timestamp,
513
+ });
514
+ if (wasTerminal) {
515
+ abortCtrl.abort();
516
+ close();
517
+ }
518
+ },
519
+ abortCtrl.signal,
520
+ { sinceSeq: lastEmittedSeq < 0 ? 0 : lastEmittedSeq },
521
+ );
522
+ if (subOutcome.kind === 'err') {
523
+ // Subscription setup failed. Not fatal: leave the stream
524
+ // open and continue with the poll path below.
525
+ fallBackToPoll = true;
526
+ } else {
527
+ subscription = subOutcome.value;
528
+ // Wait until close or max-wait window elapses. We rely
529
+ // on the subscription callback to write frames.
530
+ await new Promise<void>((resolve) => {
531
+ const timer = setTimeout(() => resolve(), MAX_WAIT_MS);
532
+ const onDone = (): void => {
533
+ clearTimeout(timer);
534
+ resolve();
535
+ };
536
+ abortCtrl.signal.addEventListener('abort', onDone, { once: true });
537
+ });
538
+ return;
539
+ }
540
+ } finally {
541
+ abortCtrl.abort();
542
+ if (subscription !== null) {
543
+ try {
544
+ await subscription.unsubscribe();
545
+ } catch {
546
+ /* cleanup best-effort */
547
+ }
548
+ }
549
+ if (!fallBackToPoll) close();
550
+ }
551
+ }
552
+
553
+ // Poll mode: no event bus wired, or subscribing failed. Poll the
554
+ // journal every 200 ms until a terminal entry or the max-wait
555
+ // window elapses.
556
+ const pollEmit = async (): Promise<{ terminal: boolean }> => {
557
+ const journal = await runBinding.readJournal(tenantId, runId);
558
+ if (journal.kind === 'err') {
559
+ const frame = formatSseFrame({
560
+ id: `${runId}:error`,
561
+ event: 'error',
562
+ data: {
563
+ code: 'journal-error',
564
+ message: journal.error.message,
565
+ requestId,
566
+ },
567
+ });
568
+ controller.enqueue(encoder.encode(frame));
569
+ return { terminal: true };
570
+ }
571
+ let sawTerminal = false;
572
+ for (const entry of journal.value) {
573
+ if (
574
+ emitEntry({
575
+ sequence: entry.sequence,
576
+ kind: entry.kind,
577
+ ...(entry.nodeId !== undefined && { nodeId: entry.nodeId as string }),
578
+ ...(entry.payload !== undefined && { payload: entry.payload }),
579
+ timestamp: entry.timestamp as string,
580
+ })
581
+ ) {
582
+ sawTerminal = true;
583
+ }
584
+ }
585
+ return { terminal: sawTerminal };
586
+ };
587
+ try {
588
+ const first = await pollEmit();
589
+ if (first.terminal) {
590
+ close();
591
+ return;
592
+ }
593
+ while (Date.now() - startedAt < MAX_WAIT_MS) {
594
+ await new Promise((r) => setTimeout(r, POLL_MS));
595
+ const step = await pollEmit();
596
+ if (step.terminal) break;
597
+ }
598
+ } finally {
599
+ close();
600
+ }
601
+ },
602
+ });
603
+
604
+ return new Response(body, {
605
+ status: 200,
606
+ headers: {
607
+ 'Content-Type': 'text/event-stream; charset=utf-8',
608
+ 'Cache-Control': 'no-cache',
609
+ Connection: 'keep-alive',
610
+ 'X-Request-Id': requestId,
611
+ },
612
+ });
613
+ };
614
+ r.get('/:runId/stream', (c) => streamRun(c, 'full'));
615
+ r.get('/:runId/progress/stream', (c) => streamRun(c, 'progress'));
616
+
617
+ // ---------- GET /:runId/journal ----------
618
+ r.get('/:runId/journal', async (c) => {
619
+ const requestId = c.get('requestId');
620
+ const tenantId = c.get('tenantId') as TenantId;
621
+ const runId = c.req.param('runId') as RunId;
622
+ const sinceRaw = c.req.query('since');
623
+ const since = sinceRaw !== undefined ? Number.parseInt(sinceRaw, 10) : undefined;
624
+
625
+ const journal = await runBinding.readJournal(tenantId, runId);
626
+ if (journal.kind === 'err') {
627
+ const err = journal.error;
628
+ c.status(statusFor(err.code) as never);
629
+ return c.json(toWireError(err as never, requestId));
630
+ }
631
+
632
+ const filtered =
633
+ since !== undefined && Number.isFinite(since)
634
+ ? journal.value.filter((e) => e.sequence > since)
635
+ : journal.value;
636
+ return c.json({
637
+ data: filtered,
638
+ hasMore: false,
639
+ });
640
+ });
641
+
642
+ return r;
643
+ }
644
+
645
+ /**
646
+ * Wire body for a binding failure. `RunHandlerFailure.details` become
647
+ * the wire error's `details` (not nested under `details.details`);
648
+ * any other field a binding attaches rides along, and `code` /
649
+ * `message` always come from the failure itself.
650
+ */
651
+ function runFailureToWire(failure: RunHandlerFailure, requestId: string): WireErrorBody {
652
+ const { details, ...rest } = failure as RunHandlerFailure & Readonly<Record<string, unknown>>;
653
+ return toWireError({ ...details, ...rest }, requestId);
654
+ }
655
+
656
+ /** Hand a parsed start body to the binding: an agent turn or a flow run. */
657
+ function invokeFromBody(
658
+ binding: RunHandlerBinding,
659
+ tenantId: TenantId,
660
+ body: ParsedStartRunBody,
661
+ ): Promise<RunHandlerOutcome> {
662
+ const common = {
663
+ tenantId,
664
+ ...(body.projectId !== undefined && { projectId: body.projectId }),
665
+ input: body.input,
666
+ ...(body.dryRun !== undefined && { dryRun: body.dryRun }),
667
+ ...(body.wait !== undefined && { wait: body.wait }),
668
+ };
669
+ return body.kind === 'agent'
670
+ ? binding.invokeAgent({
671
+ ...common,
672
+ agentId: body.agentId,
673
+ ...(body.agentVersion !== undefined && { agentVersion: body.agentVersion }),
674
+ })
675
+ : binding.invokeFlow({
676
+ ...common,
677
+ flowId: body.flowId,
678
+ ...(body.flowVersion !== undefined && { flowVersion: body.flowVersion }),
679
+ });
680
+ }
681
+
682
+ /**
683
+ * Wire row for a run. `output` is the run's output once it completed;
684
+ * single-run responses carry it, lists only with `?include=output`
685
+ * (outputs can be large). Child runs carry their parent's run + node.
686
+ */
687
+ function serializeRun(
688
+ row: KernelRunRecord,
689
+ opts: { readonly output: boolean },
690
+ ): Record<string, unknown> {
691
+ return {
692
+ id: row.runId as unknown as string,
693
+ tenantId: row.tenantId as unknown as string,
694
+ projectId: row.projectId as unknown as string,
695
+ flowId: row.flowId,
696
+ flowVersion: row.flowVersion,
697
+ status: row.status,
698
+ dryRun: row.dryRun,
699
+ createdAt: row.createdAt as unknown as string,
700
+ updatedAt: row.updatedAt as unknown as string,
701
+ completedAt: row.completedAt ?? undefined,
702
+ failureMessage: row.failureMessage ?? undefined,
703
+ ...(opts.output && row.output !== undefined && { output: row.output }),
704
+ ...(row.parentRunId != null && { parentRunId: row.parentRunId as unknown as string }),
705
+ ...(row.parentNodeId != null && { parentNodeId: row.parentNodeId as unknown as string }),
706
+ };
707
+ }
708
+
709
+ /** A run's progress: status and timing, no data. */
710
+ function serializeRunProgress(row: KernelRunRecord): Record<string, unknown> {
711
+ return {
712
+ id: row.runId as unknown as string,
713
+ flowId: row.flowId,
714
+ flowVersion: row.flowVersion,
715
+ status: row.status,
716
+ createdAt: row.createdAt as unknown as string,
717
+ updatedAt: row.updatedAt as unknown as string,
718
+ ...(row.completedAt != null && { completedAt: row.completedAt as unknown as string }),
719
+ ...(row.parentRunId != null && { parentRunId: row.parentRunId as unknown as string }),
720
+ };
721
+ }
722
+
723
+ /**
724
+ * The run when the caller may read it: any run of the tenant for an API
725
+ * token; for a public run token, a run the token names or a descendant
726
+ * of one. `null` otherwise, which the routes answer as 404 so a token
727
+ * learns nothing about other runs.
728
+ */
729
+ async function readableRun(
730
+ runBinding: RunBinding,
731
+ c: import('hono').Context<AppEnv>,
732
+ runId: RunId,
733
+ ): Promise<KernelRunRecord | null> {
734
+ const tenantId = c.get('tenantId') as TenantId;
735
+ const row = await runBinding.getRun(tenantId, runId);
736
+ if (row === null || c.get('tokenKind') !== 'public-run') return row;
737
+ const granted = c.get('publicRunIds') ?? [];
738
+ let current: KernelRunRecord | null = row;
739
+ for (let depth = 0; current !== null && depth < MAX_RUN_ANCESTRY; depth += 1) {
740
+ if (granted.includes(current.runId)) return row;
741
+ if (current.parentRunId == null) return null;
742
+ current = await runBinding.getRun(tenantId, current.parentRunId);
743
+ }
744
+ return null;
745
+ }
746
+
747
+ /** The binding query for `GET /v1/runs`: scope, page, and the parent filters. */
748
+ function listRunsInput(input: {
749
+ readonly tenantId: TenantId;
750
+ readonly scope: Extract<ParseScopeParamsOutcome, { kind: 'ok' }>['scope'];
751
+ readonly limit: number;
752
+ readonly cursor: DecodedCursor | null;
753
+ readonly filter: RunListFilter;
754
+ }): ListRunsInput {
755
+ const { tenantId, scope, limit, cursor, filter } = input;
756
+ return {
757
+ tenantId,
758
+ ...(scope?.kind === 'project' && {
759
+ scope: { kind: 'project' as const, projectId: scope.projectId as ProjectId },
760
+ }),
761
+ ...(scope?.kind === 'org' && {
762
+ scope: { kind: 'org' as const, orgId: scope.orgId as unknown as OrgId },
763
+ }),
764
+ limit,
765
+ ...(cursor !== null && {
766
+ cursor: { createdAt: cursor.createdAt as never, id: cursor.id as RunId },
767
+ }),
768
+ ...(filter.parentRunId !== undefined && { parent: { runId: filter.parentRunId } }),
769
+ ...(filter.topLevelOnly && { topLevelOnly: true }),
770
+ };
771
+ }
772
+
773
+ /** Waitpoint ids the runtime reserves for a parent waiting on a child run. */
774
+ const RESERVED_WAITPOINT_PREFIX = 'child:';
775
+
776
+ interface RunListFilter {
777
+ readonly parentRunId?: RunId;
778
+ readonly topLevelOnly: boolean;
779
+ readonly includeOutput: boolean;
780
+ }
781
+
782
+ /** `?parentRunId=` (children of a run), `?topLevel=true`, `?include=output`. */
783
+ function parseRunListFilter(
784
+ query: Readonly<Record<string, string>>,
785
+ ): { kind: 'ok'; value: RunListFilter } | { kind: 'err'; message: string } {
786
+ const { parentRunId, topLevel, include } = query;
787
+ if (topLevel !== undefined && topLevel !== 'true' && topLevel !== 'false') {
788
+ return { kind: 'err', message: '`topLevel` must be `true` or `false`' };
789
+ }
790
+ const topLevelOnly = topLevel === 'true';
791
+ if (parentRunId !== undefined && parentRunId.length === 0) {
792
+ return { kind: 'err', message: '`parentRunId` must be a run id' };
793
+ }
794
+ if (parentRunId !== undefined && topLevelOnly) {
795
+ return { kind: 'err', message: '`parentRunId` and `topLevel=true` cannot be combined' };
796
+ }
797
+ const includes = include === undefined ? [] : include.split(',').map((i) => i.trim());
798
+ const unknown = includes.filter((i) => i !== 'output');
799
+ if (unknown.length > 0) {
800
+ return { kind: 'err', message: `Unknown \`include\` value(s): ${unknown.join(', ')}` };
801
+ }
802
+ return {
803
+ kind: 'ok',
804
+ value: {
805
+ ...(parentRunId !== undefined && { parentRunId: parentRunId as RunId }),
806
+ topLevelOnly,
807
+ includeOutput: includes.includes('output'),
808
+ },
809
+ };
810
+ }
811
+
812
+ function parseResumeBody(
813
+ body: unknown,
814
+ ):
815
+ | { kind: 'ok'; value: { waitpointId?: string; value?: unknown } }
816
+ | { kind: 'err'; error: { code: string; message: string } } {
817
+ if (body === null || typeof body !== 'object') {
818
+ return { kind: 'err', error: { code: 'bad-input', message: 'Request body must be an object' } };
819
+ }
820
+ const b = body as Record<string, unknown>;
821
+ const waitpointId = b.waitpointId;
822
+ if (waitpointId !== undefined && (typeof waitpointId !== 'string' || waitpointId.length === 0)) {
823
+ return {
824
+ kind: 'err',
825
+ error: {
826
+ code: 'bad-input',
827
+ message: '`waitpointId` must be a non-empty string when supplied',
828
+ },
829
+ };
830
+ }
831
+ if (typeof waitpointId === 'string' && waitpointId.startsWith(RESERVED_WAITPOINT_PREFIX)) {
832
+ return {
833
+ kind: 'err',
834
+ error: {
835
+ code: 'bad-input',
836
+ message: `Waitpoint ids starting with "${RESERVED_WAITPOINT_PREFIX}" belong to the runtime (a parent waiting on a child run) and cannot be completed by a caller.`,
837
+ },
838
+ };
839
+ }
840
+ return {
841
+ kind: 'ok',
842
+ value: {
843
+ ...(waitpointId !== undefined && { waitpointId: waitpointId as string }),
844
+ ...('value' in b && { value: b.value }),
845
+ },
846
+ };
847
+ }
848
+
849
+ /** `options` of a start body: `dryRun?`, `wait?` (booleans). */
850
+ function parseStartOptions(
851
+ raw: unknown,
852
+ ):
853
+ | { kind: 'ok'; value: { readonly dryRun?: boolean; readonly wait?: boolean } }
854
+ | { kind: 'err'; error: { code: string; message: string } } {
855
+ const options = (raw ?? {}) as Record<string, unknown>;
856
+ if (typeof options !== 'object' || options === null) {
857
+ return {
858
+ kind: 'err',
859
+ error: { code: 'bad-input', message: '`options` must be an object when supplied' },
860
+ };
861
+ }
862
+ for (const key of ['dryRun', 'wait'] as const) {
863
+ if (options[key] !== undefined && typeof options[key] !== 'boolean') {
864
+ return {
865
+ kind: 'err',
866
+ error: { code: 'bad-input', message: `\`options.${key}\` must be a boolean` },
867
+ };
868
+ }
869
+ }
870
+ const { dryRun, wait } = options as { dryRun?: boolean; wait?: boolean };
871
+ return {
872
+ kind: 'ok',
873
+ value: { ...(dryRun !== undefined && { dryRun }), ...(wait !== undefined && { wait }) },
874
+ };
875
+ }
876
+
877
+ type ParsedStartRunBody =
878
+ | {
879
+ readonly kind: 'agent';
880
+ readonly agentId: AgentId;
881
+ readonly agentVersion?: Semver;
882
+ readonly projectId?: ProjectId;
883
+ readonly input: unknown;
884
+ readonly dryRun?: boolean;
885
+ readonly wait?: boolean;
886
+ }
887
+ | {
888
+ readonly kind: 'flow';
889
+ readonly flowId: FlowId;
890
+ readonly flowVersion?: Semver;
891
+ readonly projectId?: ProjectId;
892
+ readonly input: unknown;
893
+ readonly dryRun?: boolean;
894
+ readonly wait?: boolean;
895
+ };
896
+
897
+ function parseStartRunBody(
898
+ body: unknown,
899
+ ):
900
+ | { kind: 'ok'; value: ParsedStartRunBody }
901
+ | { kind: 'err'; error: { code: string; message: string } } {
902
+ if (body === null || typeof body !== 'object') {
903
+ return { kind: 'err', error: { code: 'bad-input', message: 'Request body must be an object' } };
904
+ }
905
+ const b = body as Record<string, unknown>;
906
+ const hasAgent = typeof b.agent === 'string' && b.agent.length > 0;
907
+ const hasGraph = typeof b.flow === 'string' && b.flow.length > 0;
908
+ if (hasAgent && hasGraph) {
909
+ return {
910
+ kind: 'err',
911
+ error: { code: 'bad-input', message: 'Provide exactly one of `agent` or `flow`, not both' },
912
+ };
913
+ }
914
+ if (!hasAgent && !hasGraph) {
915
+ return {
916
+ kind: 'err',
917
+ error: { code: 'bad-input', message: 'Request body must include `agent` or `flow`' },
918
+ };
919
+ }
920
+ if (!('input' in b)) {
921
+ return { kind: 'err', error: { code: 'bad-input', message: '`input` is required' } };
922
+ }
923
+
924
+ const options = parseStartOptions(b.options);
925
+ if (options.kind === 'err') return options;
926
+ const { dryRun, wait } = options.value;
927
+ if (hasAgent) {
928
+ const agentVersion = b.agentVersion;
929
+ if (agentVersion !== undefined && typeof agentVersion !== 'string') {
930
+ return {
931
+ kind: 'err',
932
+ error: { code: 'bad-input', message: '`agentVersion` must be a string when supplied' },
933
+ };
934
+ }
935
+ const agentProjectIdRaw = b.projectId;
936
+ if (agentProjectIdRaw !== undefined && typeof agentProjectIdRaw !== 'string') {
937
+ return {
938
+ kind: 'err',
939
+ error: { code: 'bad-input', message: '`projectId` must be a string when supplied' },
940
+ };
941
+ }
942
+ return {
943
+ kind: 'ok',
944
+ value: {
945
+ kind: 'agent',
946
+ agentId: b.agent as AgentId,
947
+ ...(agentVersion !== undefined && { agentVersion: agentVersion as Semver }),
948
+ ...(agentProjectIdRaw !== undefined && { projectId: agentProjectIdRaw as ProjectId }),
949
+ input: b.input,
950
+ ...(dryRun !== undefined && { dryRun }),
951
+ ...(wait !== undefined && { wait }),
952
+ },
953
+ };
954
+ }
955
+ const flowVersion = b.flowVersion;
956
+ if (flowVersion !== undefined && typeof flowVersion !== 'string') {
957
+ return {
958
+ kind: 'err',
959
+ error: { code: 'bad-input', message: '`flowVersion` must be a string when supplied' },
960
+ };
961
+ }
962
+ const projectId = b.projectId;
963
+ if (projectId !== undefined && typeof projectId !== 'string') {
964
+ return {
965
+ kind: 'err',
966
+ error: { code: 'bad-input', message: '`projectId` must be a string when supplied' },
967
+ };
968
+ }
969
+ return {
970
+ kind: 'ok',
971
+ value: {
972
+ kind: 'flow',
973
+ flowId: b.flow as FlowId,
974
+ ...(flowVersion !== undefined && { flowVersion: flowVersion as Semver }),
975
+ ...(projectId !== undefined && { projectId: projectId as ProjectId }),
976
+ input: b.input,
977
+ ...(dryRun !== undefined && { dryRun }),
978
+ ...(wait !== undefined && { wait }),
979
+ },
980
+ };
981
+ }