@evermore.work/server 2026.509.0-canary.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 (1045) hide show
  1. package/dist/adapters/builtin-adapter-types.d.ts +5 -0
  2. package/dist/adapters/builtin-adapter-types.d.ts.map +1 -0
  3. package/dist/adapters/builtin-adapter-types.js +17 -0
  4. package/dist/adapters/builtin-adapter-types.js.map +1 -0
  5. package/dist/adapters/codex-models.d.ts +5 -0
  6. package/dist/adapters/codex-models.d.ts.map +1 -0
  7. package/dist/adapters/codex-models.js +105 -0
  8. package/dist/adapters/codex-models.js.map +1 -0
  9. package/dist/adapters/cursor-models.d.ts +13 -0
  10. package/dist/adapters/cursor-models.d.ts.map +1 -0
  11. package/dist/adapters/cursor-models.js +148 -0
  12. package/dist/adapters/cursor-models.js.map +1 -0
  13. package/dist/adapters/http/execute.d.ts +3 -0
  14. package/dist/adapters/http/execute.d.ts.map +1 -0
  15. package/dist/adapters/http/execute.js +51 -0
  16. package/dist/adapters/http/execute.js.map +1 -0
  17. package/dist/adapters/http/execute.test.d.ts +2 -0
  18. package/dist/adapters/http/execute.test.d.ts.map +1 -0
  19. package/dist/adapters/http/execute.test.js +40 -0
  20. package/dist/adapters/http/execute.test.js.map +1 -0
  21. package/dist/adapters/http/index.d.ts +3 -0
  22. package/dist/adapters/http/index.d.ts.map +1 -0
  23. package/dist/adapters/http/index.js +20 -0
  24. package/dist/adapters/http/index.js.map +1 -0
  25. package/dist/adapters/http/test.d.ts +3 -0
  26. package/dist/adapters/http/test.d.ts.map +1 -0
  27. package/dist/adapters/http/test.js +106 -0
  28. package/dist/adapters/http/test.js.map +1 -0
  29. package/dist/adapters/index.d.ts +4 -0
  30. package/dist/adapters/index.d.ts.map +1 -0
  31. package/dist/adapters/index.js +3 -0
  32. package/dist/adapters/index.js.map +1 -0
  33. package/dist/adapters/plugin-loader.d.ts +28 -0
  34. package/dist/adapters/plugin-loader.d.ts.map +1 -0
  35. package/dist/adapters/plugin-loader.js +196 -0
  36. package/dist/adapters/plugin-loader.js.map +1 -0
  37. package/dist/adapters/process/execute.d.ts +3 -0
  38. package/dist/adapters/process/execute.d.ts.map +1 -0
  39. package/dist/adapters/process/execute.js +70 -0
  40. package/dist/adapters/process/execute.js.map +1 -0
  41. package/dist/adapters/process/index.d.ts +3 -0
  42. package/dist/adapters/process/index.d.ts.map +1 -0
  43. package/dist/adapters/process/index.js +23 -0
  44. package/dist/adapters/process/index.js.map +1 -0
  45. package/dist/adapters/process/test.d.ts +3 -0
  46. package/dist/adapters/process/test.d.ts.map +1 -0
  47. package/dist/adapters/process/test.js +77 -0
  48. package/dist/adapters/process/test.js.map +1 -0
  49. package/dist/adapters/registry.d.ts +69 -0
  50. package/dist/adapters/registry.d.ts.map +1 -0
  51. package/dist/adapters/registry.js +566 -0
  52. package/dist/adapters/registry.js.map +1 -0
  53. package/dist/adapters/types.d.ts +2 -0
  54. package/dist/adapters/types.d.ts.map +1 -0
  55. package/dist/adapters/types.js +2 -0
  56. package/dist/adapters/types.js.map +1 -0
  57. package/dist/adapters/utils.d.ts +43 -0
  58. package/dist/adapters/utils.d.ts.map +1 -0
  59. package/dist/adapters/utils.js +52 -0
  60. package/dist/adapters/utils.js.map +1 -0
  61. package/dist/agent-auth-jwt.d.ts +14 -0
  62. package/dist/agent-auth-jwt.d.ts.map +1 -0
  63. package/dist/agent-auth-jwt.js +117 -0
  64. package/dist/agent-auth-jwt.js.map +1 -0
  65. package/dist/app.d.ts +43 -0
  66. package/dist/app.d.ts.map +1 -0
  67. package/dist/app.js +373 -0
  68. package/dist/app.js.map +1 -0
  69. package/dist/attachment-types.d.ts +23 -0
  70. package/dist/attachment-types.d.ts.map +1 -0
  71. package/dist/attachment-types.js +91 -0
  72. package/dist/attachment-types.js.map +1 -0
  73. package/dist/auth/better-auth.d.ts +33 -0
  74. package/dist/auth/better-auth.d.ts.map +1 -0
  75. package/dist/auth/better-auth.js +133 -0
  76. package/dist/auth/better-auth.js.map +1 -0
  77. package/dist/board-claim.d.ts +23 -0
  78. package/dist/board-claim.d.ts.map +1 -0
  79. package/dist/board-claim.js +115 -0
  80. package/dist/board-claim.js.map +1 -0
  81. package/dist/config-file.d.ts +3 -0
  82. package/dist/config-file.d.ts.map +1 -0
  83. package/dist/config-file.js +16 -0
  84. package/dist/config-file.js.map +1 -0
  85. package/dist/config.d.ts +44 -0
  86. package/dist/config.d.ts.map +1 -0
  87. package/dist/config.js +226 -0
  88. package/dist/config.js.map +1 -0
  89. package/dist/dev-runner-worktree.d.ts +15 -0
  90. package/dist/dev-runner-worktree.d.ts.map +1 -0
  91. package/dist/dev-runner-worktree.js +68 -0
  92. package/dist/dev-runner-worktree.js.map +1 -0
  93. package/dist/dev-server-status.d.ts +27 -0
  94. package/dist/dev-server-status.d.ts.map +1 -0
  95. package/dist/dev-server-status.js +74 -0
  96. package/dist/dev-server-status.js.map +1 -0
  97. package/dist/dev-watch-ignore.d.ts +2 -0
  98. package/dist/dev-watch-ignore.d.ts.map +1 -0
  99. package/dist/dev-watch-ignore.js +36 -0
  100. package/dist/dev-watch-ignore.js.map +1 -0
  101. package/dist/errors.d.ts +12 -0
  102. package/dist/errors.d.ts.map +1 -0
  103. package/dist/errors.js +28 -0
  104. package/dist/errors.js.map +1 -0
  105. package/dist/home-paths.d.ts +17 -0
  106. package/dist/home-paths.d.ts.map +1 -0
  107. package/dist/home-paths.js +75 -0
  108. package/dist/home-paths.js.map +1 -0
  109. package/dist/index.d.ts +10 -0
  110. package/dist/index.d.ts.map +1 -0
  111. package/dist/index.js +753 -0
  112. package/dist/index.js.map +1 -0
  113. package/dist/lib/join-request-dedupe.d.ts +11 -0
  114. package/dist/lib/join-request-dedupe.d.ts.map +1 -0
  115. package/dist/lib/join-request-dedupe.js +49 -0
  116. package/dist/lib/join-request-dedupe.js.map +1 -0
  117. package/dist/log-redaction.d.ts +11 -0
  118. package/dist/log-redaction.d.ts.map +1 -0
  119. package/dist/log-redaction.js +122 -0
  120. package/dist/log-redaction.js.map +1 -0
  121. package/dist/middleware/auth.d.ts +12 -0
  122. package/dist/middleware/auth.d.ts.map +1 -0
  123. package/dist/middleware/auth.js +302 -0
  124. package/dist/middleware/auth.js.map +1 -0
  125. package/dist/middleware/board-mutation-guard.d.ts +3 -0
  126. package/dist/middleware/board-mutation-guard.d.ts.map +1 -0
  127. package/dist/middleware/board-mutation-guard.js +67 -0
  128. package/dist/middleware/board-mutation-guard.js.map +1 -0
  129. package/dist/middleware/error-handler.d.ts +17 -0
  130. package/dist/middleware/error-handler.d.ts.map +1 -0
  131. package/dist/middleware/error-handler.js +45 -0
  132. package/dist/middleware/error-handler.js.map +1 -0
  133. package/dist/middleware/http-log-policy.d.ts +2 -0
  134. package/dist/middleware/http-log-policy.d.ts.map +1 -0
  135. package/dist/middleware/http-log-policy.js +52 -0
  136. package/dist/middleware/http-log-policy.js.map +1 -0
  137. package/dist/middleware/index.d.ts +4 -0
  138. package/dist/middleware/index.d.ts.map +1 -0
  139. package/dist/middleware/index.js +4 -0
  140. package/dist/middleware/index.js.map +1 -0
  141. package/dist/middleware/logger.d.ts +4 -0
  142. package/dist/middleware/logger.d.ts.map +1 -0
  143. package/dist/middleware/logger.js +92 -0
  144. package/dist/middleware/logger.js.map +1 -0
  145. package/dist/middleware/private-hostname-guard.d.ts +11 -0
  146. package/dist/middleware/private-hostname-guard.d.ts.map +1 -0
  147. package/dist/middleware/private-hostname-guard.js +78 -0
  148. package/dist/middleware/private-hostname-guard.js.map +1 -0
  149. package/dist/middleware/validate.d.ts +4 -0
  150. package/dist/middleware/validate.d.ts.map +1 -0
  151. package/dist/middleware/validate.js +7 -0
  152. package/dist/middleware/validate.js.map +1 -0
  153. package/dist/onboarding-assets/ceo/AGENTS.md +59 -0
  154. package/dist/onboarding-assets/ceo/HEARTBEAT.md +85 -0
  155. package/dist/onboarding-assets/ceo/SOUL.md +33 -0
  156. package/dist/onboarding-assets/ceo/TOOLS.md +3 -0
  157. package/dist/onboarding-assets/default/AGENTS.md +17 -0
  158. package/dist/paths.d.ts +3 -0
  159. package/dist/paths.d.ts.map +1 -0
  160. package/dist/paths.js +31 -0
  161. package/dist/paths.js.map +1 -0
  162. package/dist/realtime/live-events-ws.d.ts +28 -0
  163. package/dist/realtime/live-events-ws.d.ts.map +1 -0
  164. package/dist/realtime/live-events-ws.js +187 -0
  165. package/dist/realtime/live-events-ws.js.map +1 -0
  166. package/dist/redaction.d.ts +5 -0
  167. package/dist/redaction.d.ts.map +1 -0
  168. package/dist/redaction.js +98 -0
  169. package/dist/redaction.js.map +1 -0
  170. package/dist/routes/access.d.ts +82 -0
  171. package/dist/routes/access.d.ts.map +1 -0
  172. package/dist/routes/access.js +3411 -0
  173. package/dist/routes/access.js.map +1 -0
  174. package/dist/routes/activity.d.ts +3 -0
  175. package/dist/routes/activity.d.ts.map +1 -0
  176. package/dist/routes/activity.js +90 -0
  177. package/dist/routes/activity.js.map +1 -0
  178. package/dist/routes/adapters.d.ts +16 -0
  179. package/dist/routes/adapters.d.ts.map +1 -0
  180. package/dist/routes/adapters.js +527 -0
  181. package/dist/routes/adapters.js.map +1 -0
  182. package/dist/routes/agents.d.ts +6 -0
  183. package/dist/routes/agents.d.ts.map +1 -0
  184. package/dist/routes/agents.js +2753 -0
  185. package/dist/routes/agents.js.map +1 -0
  186. package/dist/routes/approvals.d.ts +6 -0
  187. package/dist/routes/approvals.d.ts.map +1 -0
  188. package/dist/routes/approvals.js +300 -0
  189. package/dist/routes/approvals.js.map +1 -0
  190. package/dist/routes/assets.d.ts +4 -0
  191. package/dist/routes/assets.d.ts.map +1 -0
  192. package/dist/routes/assets.js +309 -0
  193. package/dist/routes/assets.js.map +1 -0
  194. package/dist/routes/auth.d.ts +3 -0
  195. package/dist/routes/auth.d.ts.map +1 -0
  196. package/dist/routes/auth.js +82 -0
  197. package/dist/routes/auth.js.map +1 -0
  198. package/dist/routes/authz.d.ts +19 -0
  199. package/dist/routes/authz.d.ts.map +1 -0
  200. package/dist/routes/authz.js +75 -0
  201. package/dist/routes/authz.js.map +1 -0
  202. package/dist/routes/companies.d.ts +4 -0
  203. package/dist/routes/companies.d.ts.map +1 -0
  204. package/dist/routes/companies.js +359 -0
  205. package/dist/routes/companies.js.map +1 -0
  206. package/dist/routes/company-skills.d.ts +3 -0
  207. package/dist/routes/company-skills.d.ts.map +1 -0
  208. package/dist/routes/company-skills.js +258 -0
  209. package/dist/routes/company-skills.js.map +1 -0
  210. package/dist/routes/costs.d.ts +11 -0
  211. package/dist/routes/costs.d.ts.map +1 -0
  212. package/dist/routes/costs.js +285 -0
  213. package/dist/routes/costs.js.map +1 -0
  214. package/dist/routes/dashboard.d.ts +3 -0
  215. package/dist/routes/dashboard.d.ts.map +1 -0
  216. package/dist/routes/dashboard.js +15 -0
  217. package/dist/routes/dashboard.js.map +1 -0
  218. package/dist/routes/environment-selection.d.ts +13 -0
  219. package/dist/routes/environment-selection.d.ts.map +1 -0
  220. package/dist/routes/environment-selection.js +30 -0
  221. package/dist/routes/environment-selection.js.map +1 -0
  222. package/dist/routes/environments.d.ts +6 -0
  223. package/dist/routes/environments.d.ts.map +1 -0
  224. package/dist/routes/environments.js +401 -0
  225. package/dist/routes/environments.js.map +1 -0
  226. package/dist/routes/execution-workspaces.d.ts +3 -0
  227. package/dist/routes/execution-workspaces.d.ts.map +1 -0
  228. package/dist/routes/execution-workspaces.js +536 -0
  229. package/dist/routes/execution-workspaces.js.map +1 -0
  230. package/dist/routes/goals.d.ts +3 -0
  231. package/dist/routes/goals.d.ts.map +1 -0
  232. package/dist/routes/goals.js +101 -0
  233. package/dist/routes/goals.js.map +1 -0
  234. package/dist/routes/health.d.ts +9 -0
  235. package/dist/routes/health.d.ts.map +1 -0
  236. package/dist/routes/health.js +114 -0
  237. package/dist/routes/health.js.map +1 -0
  238. package/dist/routes/inbox-dismissals.d.ts +3 -0
  239. package/dist/routes/inbox-dismissals.d.ts.map +1 -0
  240. package/dist/routes/inbox-dismissals.js +58 -0
  241. package/dist/routes/inbox-dismissals.js.map +1 -0
  242. package/dist/routes/index.d.ts +22 -0
  243. package/dist/routes/index.d.ts.map +1 -0
  244. package/dist/routes/index.js +22 -0
  245. package/dist/routes/index.js.map +1 -0
  246. package/dist/routes/instance-database-backups.d.ts +15 -0
  247. package/dist/routes/instance-database-backups.d.ts.map +1 -0
  248. package/dist/routes/instance-database-backups.js +12 -0
  249. package/dist/routes/instance-database-backups.js.map +1 -0
  250. package/dist/routes/instance-settings.d.ts +3 -0
  251. package/dist/routes/instance-settings.d.ts.map +1 -0
  252. package/dist/routes/instance-settings.js +110 -0
  253. package/dist/routes/instance-settings.js.map +1 -0
  254. package/dist/routes/issue-tree-control.d.ts +3 -0
  255. package/dist/routes/issue-tree-control.d.ts.map +1 -0
  256. package/dist/routes/issue-tree-control.js +363 -0
  257. package/dist/routes/issue-tree-control.js.map +1 -0
  258. package/dist/routes/issues-checkout-wakeup.d.ts +9 -0
  259. package/dist/routes/issues-checkout-wakeup.d.ts.map +1 -0
  260. package/dist/routes/issues-checkout-wakeup.js +12 -0
  261. package/dist/routes/issues-checkout-wakeup.js.map +1 -0
  262. package/dist/routes/issues.d.ts +23 -0
  263. package/dist/routes/issues.d.ts.map +1 -0
  264. package/dist/routes/issues.js +3886 -0
  265. package/dist/routes/issues.js.map +1 -0
  266. package/dist/routes/llms.d.ts +3 -0
  267. package/dist/routes/llms.d.ts.map +1 -0
  268. package/dist/routes/llms.js +80 -0
  269. package/dist/routes/llms.js.map +1 -0
  270. package/dist/routes/org-chart-svg.d.ts +25 -0
  271. package/dist/routes/org-chart-svg.d.ts.map +1 -0
  272. package/dist/routes/org-chart-svg.js +656 -0
  273. package/dist/routes/org-chart-svg.js.map +1 -0
  274. package/dist/routes/plugin-ui-static.d.ts +69 -0
  275. package/dist/routes/plugin-ui-static.d.ts.map +1 -0
  276. package/dist/routes/plugin-ui-static.js +411 -0
  277. package/dist/routes/plugin-ui-static.js.map +1 -0
  278. package/dist/routes/plugins.d.ts +121 -0
  279. package/dist/routes/plugins.d.ts.map +1 -0
  280. package/dist/routes/plugins.js +2192 -0
  281. package/dist/routes/plugins.js.map +1 -0
  282. package/dist/routes/projects.d.ts +3 -0
  283. package/dist/routes/projects.d.ts.map +1 -0
  284. package/dist/routes/projects.js +566 -0
  285. package/dist/routes/projects.js.map +1 -0
  286. package/dist/routes/routines.d.ts +6 -0
  287. package/dist/routes/routines.d.ts.map +1 -0
  288. package/dist/routes/routines.js +417 -0
  289. package/dist/routes/routines.js.map +1 -0
  290. package/dist/routes/secrets.d.ts +3 -0
  291. package/dist/routes/secrets.d.ts.map +1 -0
  292. package/dist/routes/secrets.js +128 -0
  293. package/dist/routes/secrets.js.map +1 -0
  294. package/dist/routes/sidebar-badges.d.ts +3 -0
  295. package/dist/routes/sidebar-badges.d.ts.map +1 -0
  296. package/dist/routes/sidebar-badges.js +68 -0
  297. package/dist/routes/sidebar-badges.js.map +1 -0
  298. package/dist/routes/sidebar-preferences.d.ts +3 -0
  299. package/dist/routes/sidebar-preferences.d.ts.map +1 -0
  300. package/dist/routes/sidebar-preferences.js +63 -0
  301. package/dist/routes/sidebar-preferences.js.map +1 -0
  302. package/dist/routes/user-profiles.d.ts +3 -0
  303. package/dist/routes/user-profiles.d.ts.map +1 -0
  304. package/dist/routes/user-profiles.js +337 -0
  305. package/dist/routes/user-profiles.js.map +1 -0
  306. package/dist/routes/workspace-command-authz.d.ts +14 -0
  307. package/dist/routes/workspace-command-authz.d.ts.map +1 -0
  308. package/dist/routes/workspace-command-authz.js +83 -0
  309. package/dist/routes/workspace-command-authz.js.map +1 -0
  310. package/dist/routes/workspace-runtime-service-authz.d.ts +12 -0
  311. package/dist/routes/workspace-runtime-service-authz.d.ts.map +1 -0
  312. package/dist/routes/workspace-runtime-service-authz.js +96 -0
  313. package/dist/routes/workspace-runtime-service-authz.js.map +1 -0
  314. package/dist/runtime-api.d.ts +19 -0
  315. package/dist/runtime-api.d.ts.map +1 -0
  316. package/dist/runtime-api.js +137 -0
  317. package/dist/runtime-api.js.map +1 -0
  318. package/dist/secrets/external-stub-providers.d.ts +5 -0
  319. package/dist/secrets/external-stub-providers.d.ts.map +1 -0
  320. package/dist/secrets/external-stub-providers.js +21 -0
  321. package/dist/secrets/external-stub-providers.js.map +1 -0
  322. package/dist/secrets/local-encrypted-provider.d.ts +3 -0
  323. package/dist/secrets/local-encrypted-provider.d.ts.map +1 -0
  324. package/dist/secrets/local-encrypted-provider.js +116 -0
  325. package/dist/secrets/local-encrypted-provider.js.map +1 -0
  326. package/dist/secrets/provider-registry.d.ts +5 -0
  327. package/dist/secrets/provider-registry.d.ts.map +1 -0
  328. package/dist/secrets/provider-registry.js +20 -0
  329. package/dist/secrets/provider-registry.js.map +1 -0
  330. package/dist/secrets/types.d.ts +21 -0
  331. package/dist/secrets/types.d.ts.map +1 -0
  332. package/dist/secrets/types.js +2 -0
  333. package/dist/secrets/types.js.map +1 -0
  334. package/dist/services/access.d.ts +171 -0
  335. package/dist/services/access.d.ts.map +1 -0
  336. package/dist/services/access.js +522 -0
  337. package/dist/services/access.js.map +1 -0
  338. package/dist/services/activity-log.d.ts +19 -0
  339. package/dist/services/activity-log.d.ts.map +1 -0
  340. package/dist/services/activity-log.js +99 -0
  341. package/dist/services/activity-log.js.map +1 -0
  342. package/dist/services/activity.d.ts +462 -0
  343. package/dist/services/activity.d.ts.map +1 -0
  344. package/dist/services/activity.js +443 -0
  345. package/dist/services/activity.js.map +1 -0
  346. package/dist/services/adapter-plugin-store.d.ts +36 -0
  347. package/dist/services/adapter-plugin-store.d.ts.map +1 -0
  348. package/dist/services/adapter-plugin-store.js +154 -0
  349. package/dist/services/adapter-plugin-store.js.map +1 -0
  350. package/dist/services/agent-instructions.d.ts +91 -0
  351. package/dist/services/agent-instructions.d.ts.map +1 -0
  352. package/dist/services/agent-instructions.js +580 -0
  353. package/dist/services/agent-instructions.js.map +1 -0
  354. package/dist/services/agent-permissions.d.ts +6 -0
  355. package/dist/services/agent-permissions.d.ts.map +1 -0
  356. package/dist/services/agent-permissions.js +18 -0
  357. package/dist/services/agent-permissions.js.map +1 -0
  358. package/dist/services/agent-start-lock.d.ts +2 -0
  359. package/dist/services/agent-start-lock.d.ts.map +1 -0
  360. package/dist/services/agent-start-lock.js +43 -0
  361. package/dist/services/agent-start-lock.js.map +1 -0
  362. package/dist/services/agents.d.ts +2253 -0
  363. package/dist/services/agents.d.ts.map +1 -0
  364. package/dist/services/agents.js +609 -0
  365. package/dist/services/agents.js.map +1 -0
  366. package/dist/services/approvals.d.ts +546 -0
  367. package/dist/services/approvals.d.ts.map +1 -0
  368. package/dist/services/approvals.js +212 -0
  369. package/dist/services/approvals.js.map +1 -0
  370. package/dist/services/assets.d.ts +33 -0
  371. package/dist/services/assets.d.ts.map +1 -0
  372. package/dist/services/assets.js +17 -0
  373. package/dist/services/assets.js.map +1 -0
  374. package/dist/services/board-auth.d.ts +239 -0
  375. package/dist/services/board-auth.d.ts.map +1 -0
  376. package/dist/services/board-auth.js +300 -0
  377. package/dist/services/board-auth.js.map +1 -0
  378. package/dist/services/budgets.d.ts +38 -0
  379. package/dist/services/budgets.d.ts.map +1 -0
  380. package/dist/services/budgets.js +784 -0
  381. package/dist/services/budgets.js.map +1 -0
  382. package/dist/services/companies.d.ts +154 -0
  383. package/dist/services/companies.d.ts.map +1 -0
  384. package/dist/services/companies.js +267 -0
  385. package/dist/services/companies.js.map +1 -0
  386. package/dist/services/company-export-readme.d.ts +17 -0
  387. package/dist/services/company-export-readme.d.ts.map +1 -0
  388. package/dist/services/company-export-readme.js +148 -0
  389. package/dist/services/company-export-readme.js.map +1 -0
  390. package/dist/services/company-member-roles.d.ts +9 -0
  391. package/dist/services/company-member-roles.d.ts.map +1 -0
  392. package/dist/services/company-member-roles.js +46 -0
  393. package/dist/services/company-member-roles.js.map +1 -0
  394. package/dist/services/company-portability.d.ts +24 -0
  395. package/dist/services/company-portability.d.ts.map +1 -0
  396. package/dist/services/company-portability.js +4076 -0
  397. package/dist/services/company-portability.js.map +1 -0
  398. package/dist/services/company-search-rate-limit.d.ts +22 -0
  399. package/dist/services/company-search-rate-limit.d.ts.map +1 -0
  400. package/dist/services/company-search-rate-limit.js +38 -0
  401. package/dist/services/company-search-rate-limit.js.map +1 -0
  402. package/dist/services/company-search.d.ts +8 -0
  403. package/dist/services/company-search.d.ts.map +1 -0
  404. package/dist/services/company-search.js +626 -0
  405. package/dist/services/company-search.js.map +1 -0
  406. package/dist/services/company-skills.d.ts +77 -0
  407. package/dist/services/company-skills.d.ts.map +1 -0
  408. package/dist/services/company-skills.js +2120 -0
  409. package/dist/services/company-skills.js.map +1 -0
  410. package/dist/services/costs.d.ts +127 -0
  411. package/dist/services/costs.d.ts.map +1 -0
  412. package/dist/services/costs.js +409 -0
  413. package/dist/services/costs.js.map +1 -0
  414. package/dist/services/cron.d.ts +80 -0
  415. package/dist/services/cron.d.ts.map +1 -0
  416. package/dist/services/cron.js +300 -0
  417. package/dist/services/cron.js.map +1 -0
  418. package/dist/services/dashboard.d.ts +34 -0
  419. package/dist/services/dashboard.d.ts.map +1 -0
  420. package/dist/services/dashboard.js +142 -0
  421. package/dist/services/dashboard.js.map +1 -0
  422. package/dist/services/default-agent-instructions.d.ts +9 -0
  423. package/dist/services/default-agent-instructions.d.ts.map +1 -0
  424. package/dist/services/default-agent-instructions.js +20 -0
  425. package/dist/services/default-agent-instructions.js.map +1 -0
  426. package/dist/services/documents.d.ts +199 -0
  427. package/dist/services/documents.d.ts.map +1 -0
  428. package/dist/services/documents.js +411 -0
  429. package/dist/services/documents.js.map +1 -0
  430. package/dist/services/environment-config.d.ts +43 -0
  431. package/dist/services/environment-config.d.ts.map +1 -0
  432. package/dist/services/environment-config.js +388 -0
  433. package/dist/services/environment-config.js.map +1 -0
  434. package/dist/services/environment-execution-target.d.ts +21 -0
  435. package/dist/services/environment-execution-target.d.ts.map +1 -0
  436. package/dist/services/environment-execution-target.js +119 -0
  437. package/dist/services/environment-execution-target.js.map +1 -0
  438. package/dist/services/environment-probe.d.ts +9 -0
  439. package/dist/services/environment-probe.d.ts.map +1 -0
  440. package/dist/services/environment-probe.js +106 -0
  441. package/dist/services/environment-probe.js.map +1 -0
  442. package/dist/services/environment-run-orchestrator.d.ts +124 -0
  443. package/dist/services/environment-run-orchestrator.d.ts.map +1 -0
  444. package/dist/services/environment-run-orchestrator.js +392 -0
  445. package/dist/services/environment-run-orchestrator.js.map +1 -0
  446. package/dist/services/environment-runtime.d.ts +90 -0
  447. package/dist/services/environment-runtime.d.ts.map +1 -0
  448. package/dist/services/environment-runtime.js +934 -0
  449. package/dist/services/environment-runtime.js.map +1 -0
  450. package/dist/services/environments.d.ts +36 -0
  451. package/dist/services/environments.d.ts.map +1 -0
  452. package/dist/services/environments.js +260 -0
  453. package/dist/services/environments.js.map +1 -0
  454. package/dist/services/execution-workspace-policy.d.ts +30 -0
  455. package/dist/services/execution-workspace-policy.d.ts.map +1 -0
  456. package/dist/services/execution-workspace-policy.js +195 -0
  457. package/dist/services/execution-workspace-policy.js.map +1 -0
  458. package/dist/services/execution-workspaces.d.ts +30 -0
  459. package/dist/services/execution-workspaces.d.ts.map +1 -0
  460. package/dist/services/execution-workspaces.js +635 -0
  461. package/dist/services/execution-workspaces.js.map +1 -0
  462. package/dist/services/feedback-redaction.d.ts +23 -0
  463. package/dist/services/feedback-redaction.d.ts.map +1 -0
  464. package/dist/services/feedback-redaction.js +150 -0
  465. package/dist/services/feedback-redaction.js.map +1 -0
  466. package/dist/services/feedback-share-client.d.ts +9 -0
  467. package/dist/services/feedback-share-client.d.ts.map +1 -0
  468. package/dist/services/feedback-share-client.js +46 -0
  469. package/dist/services/feedback-share-client.js.map +1 -0
  470. package/dist/services/feedback.d.ts +93 -0
  471. package/dist/services/feedback.d.ts.map +1 -0
  472. package/dist/services/feedback.js +1717 -0
  473. package/dist/services/feedback.js.map +1 -0
  474. package/dist/services/finance.d.ts +93 -0
  475. package/dist/services/finance.d.ts.map +1 -0
  476. package/dist/services/finance.js +120 -0
  477. package/dist/services/finance.js.map +1 -0
  478. package/dist/services/github-fetch.d.ts +4 -0
  479. package/dist/services/github-fetch.d.ts.map +1 -0
  480. package/dist/services/github-fetch.js +23 -0
  481. package/dist/services/github-fetch.js.map +1 -0
  482. package/dist/services/goals.d.ts +433 -0
  483. package/dist/services/goals.d.ts.map +1 -0
  484. package/dist/services/goals.js +54 -0
  485. package/dist/services/goals.js.map +1 -0
  486. package/dist/services/heartbeat-run-summary.d.ts +7 -0
  487. package/dist/services/heartbeat-run-summary.d.ts.map +1 -0
  488. package/dist/services/heartbeat-run-summary.js +84 -0
  489. package/dist/services/heartbeat-run-summary.js.map +1 -0
  490. package/dist/services/heartbeat-stop-metadata.d.ts +28 -0
  491. package/dist/services/heartbeat-stop-metadata.d.ts.map +1 -0
  492. package/dist/services/heartbeat-stop-metadata.js +86 -0
  493. package/dist/services/heartbeat-stop-metadata.js.map +1 -0
  494. package/dist/services/heartbeat-stop-metadata.test.d.ts +2 -0
  495. package/dist/services/heartbeat-stop-metadata.test.d.ts.map +1 -0
  496. package/dist/services/heartbeat-stop-metadata.test.js +93 -0
  497. package/dist/services/heartbeat-stop-metadata.test.js.map +1 -0
  498. package/dist/services/heartbeat.d.ts +1484 -0
  499. package/dist/services/heartbeat.d.ts.map +1 -0
  500. package/dist/services/heartbeat.js +7557 -0
  501. package/dist/services/heartbeat.js.map +1 -0
  502. package/dist/services/hire-hook.d.ts +14 -0
  503. package/dist/services/hire-hook.d.ts.map +1 -0
  504. package/dist/services/hire-hook.js +85 -0
  505. package/dist/services/hire-hook.js.map +1 -0
  506. package/dist/services/inbox-dismissals.d.ts +22 -0
  507. package/dist/services/inbox-dismissals.d.ts.map +1 -0
  508. package/dist/services/inbox-dismissals.js +33 -0
  509. package/dist/services/inbox-dismissals.js.map +1 -0
  510. package/dist/services/index.d.ts +44 -0
  511. package/dist/services/index.d.ts.map +1 -0
  512. package/dist/services/index.js +44 -0
  513. package/dist/services/index.js.map +1 -0
  514. package/dist/services/instance-settings.d.ts +11 -0
  515. package/dist/services/instance-settings.d.ts.map +1 -0
  516. package/dist/services/instance-settings.js +138 -0
  517. package/dist/services/instance-settings.js.map +1 -0
  518. package/dist/services/invite-grants.d.ts +15 -0
  519. package/dist/services/invite-grants.d.ts.map +1 -0
  520. package/dist/services/invite-grants.js +50 -0
  521. package/dist/services/invite-grants.js.map +1 -0
  522. package/dist/services/issue-approvals.d.ts +56 -0
  523. package/dist/services/issue-approvals.d.ts.map +1 -0
  524. package/dist/services/issue-approvals.js +153 -0
  525. package/dist/services/issue-approvals.js.map +1 -0
  526. package/dist/services/issue-assignment-wakeup.d.ts +29 -0
  527. package/dist/services/issue-assignment-wakeup.d.ts.map +1 -0
  528. package/dist/services/issue-assignment-wakeup.js +22 -0
  529. package/dist/services/issue-assignment-wakeup.js.map +1 -0
  530. package/dist/services/issue-continuation-summary.d.ts +66 -0
  531. package/dist/services/issue-continuation-summary.d.ts.map +1 -0
  532. package/dist/services/issue-continuation-summary.js +212 -0
  533. package/dist/services/issue-continuation-summary.js.map +1 -0
  534. package/dist/services/issue-execution-policy.d.ts +93 -0
  535. package/dist/services/issue-execution-policy.d.ts.map +1 -0
  536. package/dist/services/issue-execution-policy.js +838 -0
  537. package/dist/services/issue-execution-policy.js.map +1 -0
  538. package/dist/services/issue-goal-fallback.d.ts +18 -0
  539. package/dist/services/issue-goal-fallback.d.ts.map +1 -0
  540. package/dist/services/issue-goal-fallback.js +33 -0
  541. package/dist/services/issue-goal-fallback.js.map +1 -0
  542. package/dist/services/issue-liveness.d.ts +3 -0
  543. package/dist/services/issue-liveness.d.ts.map +1 -0
  544. package/dist/services/issue-liveness.js +2 -0
  545. package/dist/services/issue-liveness.js.map +1 -0
  546. package/dist/services/issue-references.d.ts +21 -0
  547. package/dist/services/issue-references.d.ts.map +1 -0
  548. package/dist/services/issue-references.js +318 -0
  549. package/dist/services/issue-references.js.map +1 -0
  550. package/dist/services/issue-thread-interactions.d.ts +76 -0
  551. package/dist/services/issue-thread-interactions.d.ts.map +1 -0
  552. package/dist/services/issue-thread-interactions.js +923 -0
  553. package/dist/services/issue-thread-interactions.js.map +1 -0
  554. package/dist/services/issue-thread-interactions.test.d.ts +2 -0
  555. package/dist/services/issue-thread-interactions.test.d.ts.map +1 -0
  556. package/dist/services/issue-thread-interactions.test.js +195 -0
  557. package/dist/services/issue-thread-interactions.test.js.map +1 -0
  558. package/dist/services/issue-tree-control.d.ts +89 -0
  559. package/dist/services/issue-tree-control.d.ts.map +1 -0
  560. package/dist/services/issue-tree-control.js +933 -0
  561. package/dist/services/issue-tree-control.js.map +1 -0
  562. package/dist/services/issues.d.ts +710 -0
  563. package/dist/services/issues.d.ts.map +1 -0
  564. package/dist/services/issues.js +3199 -0
  565. package/dist/services/issues.js.map +1 -0
  566. package/dist/services/json-schema-secret-refs.d.ts +5 -0
  567. package/dist/services/json-schema-secret-refs.d.ts.map +1 -0
  568. package/dist/services/json-schema-secret-refs.js +67 -0
  569. package/dist/services/json-schema-secret-refs.js.map +1 -0
  570. package/dist/services/live-events.d.ts +17 -0
  571. package/dist/services/live-events.d.ts.map +1 -0
  572. package/dist/services/live-events.js +33 -0
  573. package/dist/services/live-events.js.map +1 -0
  574. package/dist/services/local-service-supervisor.d.ts +56 -0
  575. package/dist/services/local-service-supervisor.d.ts.map +1 -0
  576. package/dist/services/local-service-supervisor.js +284 -0
  577. package/dist/services/local-service-supervisor.js.map +1 -0
  578. package/dist/services/plugin-capability-validator.d.ts +108 -0
  579. package/dist/services/plugin-capability-validator.d.ts.map +1 -0
  580. package/dist/services/plugin-capability-validator.js +313 -0
  581. package/dist/services/plugin-capability-validator.js.map +1 -0
  582. package/dist/services/plugin-config-validator.d.ts +26 -0
  583. package/dist/services/plugin-config-validator.d.ts.map +1 -0
  584. package/dist/services/plugin-config-validator.js +41 -0
  585. package/dist/services/plugin-config-validator.js.map +1 -0
  586. package/dist/services/plugin-database.d.ts +49 -0
  587. package/dist/services/plugin-database.d.ts.map +1 -0
  588. package/dist/services/plugin-database.js +440 -0
  589. package/dist/services/plugin-database.js.map +1 -0
  590. package/dist/services/plugin-dev-watcher.d.ts +30 -0
  591. package/dist/services/plugin-dev-watcher.d.ts.map +1 -0
  592. package/dist/services/plugin-dev-watcher.js +241 -0
  593. package/dist/services/plugin-dev-watcher.js.map +1 -0
  594. package/dist/services/plugin-environment-driver.d.ts +124 -0
  595. package/dist/services/plugin-environment-driver.d.ts.map +1 -0
  596. package/dist/services/plugin-environment-driver.js +224 -0
  597. package/dist/services/plugin-environment-driver.js.map +1 -0
  598. package/dist/services/plugin-event-bus.d.ts +149 -0
  599. package/dist/services/plugin-event-bus.d.ts.map +1 -0
  600. package/dist/services/plugin-event-bus.js +258 -0
  601. package/dist/services/plugin-event-bus.js.map +1 -0
  602. package/dist/services/plugin-host-service-cleanup.d.ts +14 -0
  603. package/dist/services/plugin-host-service-cleanup.d.ts.map +1 -0
  604. package/dist/services/plugin-host-service-cleanup.js +37 -0
  605. package/dist/services/plugin-host-service-cleanup.js.map +1 -0
  606. package/dist/services/plugin-host-services.d.ts +17 -0
  607. package/dist/services/plugin-host-services.d.ts.map +1 -0
  608. package/dist/services/plugin-host-services.js +1861 -0
  609. package/dist/services/plugin-host-services.js.map +1 -0
  610. package/dist/services/plugin-job-coordinator.d.ts +81 -0
  611. package/dist/services/plugin-job-coordinator.d.ts.map +1 -0
  612. package/dist/services/plugin-job-coordinator.js +172 -0
  613. package/dist/services/plugin-job-coordinator.js.map +1 -0
  614. package/dist/services/plugin-job-scheduler.d.ts +163 -0
  615. package/dist/services/plugin-job-scheduler.d.ts.map +1 -0
  616. package/dist/services/plugin-job-scheduler.js +454 -0
  617. package/dist/services/plugin-job-scheduler.js.map +1 -0
  618. package/dist/services/plugin-job-store.d.ts +208 -0
  619. package/dist/services/plugin-job-store.d.ts.map +1 -0
  620. package/dist/services/plugin-job-store.js +350 -0
  621. package/dist/services/plugin-job-store.js.map +1 -0
  622. package/dist/services/plugin-lifecycle.d.ts +203 -0
  623. package/dist/services/plugin-lifecycle.d.ts.map +1 -0
  624. package/dist/services/plugin-lifecycle.js +476 -0
  625. package/dist/services/plugin-lifecycle.js.map +1 -0
  626. package/dist/services/plugin-loader.d.ts +445 -0
  627. package/dist/services/plugin-loader.d.ts.map +1 -0
  628. package/dist/services/plugin-loader.js +1273 -0
  629. package/dist/services/plugin-loader.js.map +1 -0
  630. package/dist/services/plugin-local-folders.d.ts +48 -0
  631. package/dist/services/plugin-local-folders.d.ts.map +1 -0
  632. package/dist/services/plugin-local-folders.js +461 -0
  633. package/dist/services/plugin-local-folders.js.map +1 -0
  634. package/dist/services/plugin-log-retention.d.ts +20 -0
  635. package/dist/services/plugin-log-retention.d.ts.map +1 -0
  636. package/dist/services/plugin-log-retention.js +63 -0
  637. package/dist/services/plugin-log-retention.js.map +1 -0
  638. package/dist/services/plugin-managed-agents.d.ts +15 -0
  639. package/dist/services/plugin-managed-agents.d.ts.map +1 -0
  640. package/dist/services/plugin-managed-agents.js +414 -0
  641. package/dist/services/plugin-managed-agents.js.map +1 -0
  642. package/dist/services/plugin-managed-routines.d.ts +41 -0
  643. package/dist/services/plugin-managed-routines.d.ts.map +1 -0
  644. package/dist/services/plugin-managed-routines.js +416 -0
  645. package/dist/services/plugin-managed-routines.js.map +1 -0
  646. package/dist/services/plugin-manifest-validator.d.ts +79 -0
  647. package/dist/services/plugin-manifest-validator.d.ts.map +1 -0
  648. package/dist/services/plugin-manifest-validator.js +84 -0
  649. package/dist/services/plugin-manifest-validator.js.map +1 -0
  650. package/dist/services/plugin-registry.d.ts +2550 -0
  651. package/dist/services/plugin-registry.d.ts.map +1 -0
  652. package/dist/services/plugin-registry.js +581 -0
  653. package/dist/services/plugin-registry.js.map +1 -0
  654. package/dist/services/plugin-runtime-sandbox.d.ts +40 -0
  655. package/dist/services/plugin-runtime-sandbox.d.ts.map +1 -0
  656. package/dist/services/plugin-runtime-sandbox.js +154 -0
  657. package/dist/services/plugin-runtime-sandbox.js.map +1 -0
  658. package/dist/services/plugin-secrets-handler.d.ts +81 -0
  659. package/dist/services/plugin-secrets-handler.d.ts.map +1 -0
  660. package/dist/services/plugin-secrets-handler.js +231 -0
  661. package/dist/services/plugin-secrets-handler.js.map +1 -0
  662. package/dist/services/plugin-state-store.d.ts +92 -0
  663. package/dist/services/plugin-state-store.d.ts.map +1 -0
  664. package/dist/services/plugin-state-store.js +190 -0
  665. package/dist/services/plugin-state-store.js.map +1 -0
  666. package/dist/services/plugin-stream-bus.d.ts +29 -0
  667. package/dist/services/plugin-stream-bus.d.ts.map +1 -0
  668. package/dist/services/plugin-stream-bus.js +48 -0
  669. package/dist/services/plugin-stream-bus.js.map +1 -0
  670. package/dist/services/plugin-tool-dispatcher.d.ts +180 -0
  671. package/dist/services/plugin-tool-dispatcher.d.ts.map +1 -0
  672. package/dist/services/plugin-tool-dispatcher.js +224 -0
  673. package/dist/services/plugin-tool-dispatcher.js.map +1 -0
  674. package/dist/services/plugin-tool-registry.d.ts +192 -0
  675. package/dist/services/plugin-tool-registry.d.ts.map +1 -0
  676. package/dist/services/plugin-tool-registry.js +224 -0
  677. package/dist/services/plugin-tool-registry.js.map +1 -0
  678. package/dist/services/plugin-worker-manager.d.ts +262 -0
  679. package/dist/services/plugin-worker-manager.d.ts.map +1 -0
  680. package/dist/services/plugin-worker-manager.js +836 -0
  681. package/dist/services/plugin-worker-manager.js.map +1 -0
  682. package/dist/services/productivity-review.d.ts +83 -0
  683. package/dist/services/productivity-review.d.ts.map +1 -0
  684. package/dist/services/productivity-review.js +652 -0
  685. package/dist/services/productivity-review.js.map +1 -0
  686. package/dist/services/project-workspace-runtime-config.d.ts +4 -0
  687. package/dist/services/project-workspace-runtime-config.d.ts.map +1 -0
  688. package/dist/services/project-workspace-runtime-config.js +54 -0
  689. package/dist/services/project-workspace-runtime-config.js.map +1 -0
  690. package/dist/services/projects.d.ts +99 -0
  691. package/dist/services/projects.d.ts.map +1 -0
  692. package/dist/services/projects.js +879 -0
  693. package/dist/services/projects.js.map +1 -0
  694. package/dist/services/quota-windows.d.ts +9 -0
  695. package/dist/services/quota-windows.d.ts.map +1 -0
  696. package/dist/services/quota-windows.js +56 -0
  697. package/dist/services/quota-windows.js.map +1 -0
  698. package/dist/services/recovery/index.d.ts +10 -0
  699. package/dist/services/recovery/index.d.ts.map +1 -0
  700. package/dist/services/recovery/index.js +6 -0
  701. package/dist/services/recovery/index.js.map +1 -0
  702. package/dist/services/recovery/issue-graph-liveness.d.ts +85 -0
  703. package/dist/services/recovery/issue-graph-liveness.d.ts.map +1 -0
  704. package/dist/services/recovery/issue-graph-liveness.js +343 -0
  705. package/dist/services/recovery/issue-graph-liveness.js.map +1 -0
  706. package/dist/services/recovery/model-profile-hint.d.ts +8 -0
  707. package/dist/services/recovery/model-profile-hint.d.ts.map +1 -0
  708. package/dist/services/recovery/model-profile-hint.js +11 -0
  709. package/dist/services/recovery/model-profile-hint.js.map +1 -0
  710. package/dist/services/recovery/origins.d.ts +36 -0
  711. package/dist/services/recovery/origins.d.ts.map +1 -0
  712. package/dist/services/recovery/origins.js +45 -0
  713. package/dist/services/recovery/origins.js.map +1 -0
  714. package/dist/services/recovery/pause-hold-guard.d.ts +6 -0
  715. package/dist/services/recovery/pause-hold-guard.d.ts.map +1 -0
  716. package/dist/services/recovery/pause-hold-guard.js +6 -0
  717. package/dist/services/recovery/pause-hold-guard.js.map +1 -0
  718. package/dist/services/recovery/run-liveness-continuations.d.ts +50 -0
  719. package/dist/services/recovery/run-liveness-continuations.d.ts.map +1 -0
  720. package/dist/services/recovery/run-liveness-continuations.js +117 -0
  721. package/dist/services/recovery/run-liveness-continuations.js.map +1 -0
  722. package/dist/services/recovery/service.d.ts +195 -0
  723. package/dist/services/recovery/service.d.ts.map +1 -0
  724. package/dist/services/recovery/service.js +2210 -0
  725. package/dist/services/recovery/service.js.map +1 -0
  726. package/dist/services/recovery/successful-run-handoff.d.ts +87 -0
  727. package/dist/services/recovery/successful-run-handoff.d.ts.map +1 -0
  728. package/dist/services/recovery/successful-run-handoff.js +297 -0
  729. package/dist/services/recovery/successful-run-handoff.js.map +1 -0
  730. package/dist/services/recovery/successful-run-handoff.test.d.ts +2 -0
  731. package/dist/services/recovery/successful-run-handoff.test.d.ts.map +1 -0
  732. package/dist/services/recovery/successful-run-handoff.test.js +267 -0
  733. package/dist/services/recovery/successful-run-handoff.test.js.map +1 -0
  734. package/dist/services/routines.d.ts +166 -0
  735. package/dist/services/routines.d.ts.map +1 -0
  736. package/dist/services/routines.js +1937 -0
  737. package/dist/services/routines.js.map +1 -0
  738. package/dist/services/run-continuations.d.ts +3 -0
  739. package/dist/services/run-continuations.d.ts.map +1 -0
  740. package/dist/services/run-continuations.js +2 -0
  741. package/dist/services/run-continuations.js.map +1 -0
  742. package/dist/services/run-liveness.d.ts +46 -0
  743. package/dist/services/run-liveness.d.ts.map +1 -0
  744. package/dist/services/run-liveness.js +275 -0
  745. package/dist/services/run-liveness.js.map +1 -0
  746. package/dist/services/run-log-store.d.ts +34 -0
  747. package/dist/services/run-log-store.d.ts.map +1 -0
  748. package/dist/services/run-log-store.js +111 -0
  749. package/dist/services/run-log-store.js.map +1 -0
  750. package/dist/services/sandbox-provider-runtime.d.ts +132 -0
  751. package/dist/services/sandbox-provider-runtime.d.ts.map +1 -0
  752. package/dist/services/sandbox-provider-runtime.js +216 -0
  753. package/dist/services/sandbox-provider-runtime.js.map +1 -0
  754. package/dist/services/secrets.d.ts +515 -0
  755. package/dist/services/secrets.d.ts.map +1 -0
  756. package/dist/services/secrets.js +290 -0
  757. package/dist/services/secrets.js.map +1 -0
  758. package/dist/services/sidebar-badges.d.ts +14 -0
  759. package/dist/services/sidebar-badges.d.ts.map +1 -0
  760. package/dist/services/sidebar-badges.js +48 -0
  761. package/dist/services/sidebar-badges.js.map +1 -0
  762. package/dist/services/sidebar-preferences.d.ts +9 -0
  763. package/dist/services/sidebar-preferences.d.ts.map +1 -0
  764. package/dist/services/sidebar-preferences.js +82 -0
  765. package/dist/services/sidebar-preferences.js.map +1 -0
  766. package/dist/services/work-products.d.ts +14 -0
  767. package/dist/services/work-products.d.ts.map +1 -0
  768. package/dist/services/work-products.js +100 -0
  769. package/dist/services/work-products.js.map +1 -0
  770. package/dist/services/workspace-operation-log-store.d.ts +33 -0
  771. package/dist/services/workspace-operation-log-store.d.ts.map +1 -0
  772. package/dist/services/workspace-operation-log-store.js +110 -0
  773. package/dist/services/workspace-operation-log-store.js.map +1 -0
  774. package/dist/services/workspace-operations.d.ts +44 -0
  775. package/dist/services/workspace-operations.d.ts.map +1 -0
  776. package/dist/services/workspace-operations.js +211 -0
  777. package/dist/services/workspace-operations.js.map +1 -0
  778. package/dist/services/workspace-realization.d.ts +33 -0
  779. package/dist/services/workspace-realization.d.ts.map +1 -0
  780. package/dist/services/workspace-realization.js +221 -0
  781. package/dist/services/workspace-realization.js.map +1 -0
  782. package/dist/services/workspace-runtime-read-model.d.ts +92 -0
  783. package/dist/services/workspace-runtime-read-model.d.ts.map +1 -0
  784. package/dist/services/workspace-runtime-read-model.js +67 -0
  785. package/dist/services/workspace-runtime-read-model.js.map +1 -0
  786. package/dist/services/workspace-runtime.d.ts +238 -0
  787. package/dist/services/workspace-runtime.d.ts.map +1 -0
  788. package/dist/services/workspace-runtime.js +2388 -0
  789. package/dist/services/workspace-runtime.js.map +1 -0
  790. package/dist/startup-banner.d.ts +32 -0
  791. package/dist/startup-banner.d.ts.map +1 -0
  792. package/dist/startup-banner.js +118 -0
  793. package/dist/startup-banner.js.map +1 -0
  794. package/dist/storage/index.d.ts +6 -0
  795. package/dist/storage/index.d.ts.map +1 -0
  796. package/dist/storage/index.js +29 -0
  797. package/dist/storage/index.js.map +1 -0
  798. package/dist/storage/local-disk-provider.d.ts +3 -0
  799. package/dist/storage/local-disk-provider.d.ts.map +1 -0
  800. package/dist/storage/local-disk-provider.js +79 -0
  801. package/dist/storage/local-disk-provider.js.map +1 -0
  802. package/dist/storage/provider-registry.d.ts +4 -0
  803. package/dist/storage/provider-registry.d.ts.map +1 -0
  804. package/dist/storage/provider-registry.js +15 -0
  805. package/dist/storage/provider-registry.js.map +1 -0
  806. package/dist/storage/s3-provider.d.ts +11 -0
  807. package/dist/storage/s3-provider.d.ts.map +1 -0
  808. package/dist/storage/s3-provider.js +123 -0
  809. package/dist/storage/s3-provider.js.map +1 -0
  810. package/dist/storage/service.d.ts +3 -0
  811. package/dist/storage/service.d.ts.map +1 -0
  812. package/dist/storage/service.js +120 -0
  813. package/dist/storage/service.js.map +1 -0
  814. package/dist/storage/types.d.ts +55 -0
  815. package/dist/storage/types.d.ts.map +1 -0
  816. package/dist/storage/types.js +2 -0
  817. package/dist/storage/types.js.map +1 -0
  818. package/dist/telemetry.d.ts +6 -0
  819. package/dist/telemetry.d.ts.map +1 -0
  820. package/dist/telemetry.js +20 -0
  821. package/dist/telemetry.js.map +1 -0
  822. package/dist/ui-branding.d.ts +13 -0
  823. package/dist/ui-branding.d.ts.map +1 -0
  824. package/dist/ui-branding.js +187 -0
  825. package/dist/ui-branding.js.map +1 -0
  826. package/dist/version.d.ts +2 -0
  827. package/dist/version.d.ts.map +1 -0
  828. package/dist/version.js +5 -0
  829. package/dist/version.js.map +1 -0
  830. package/dist/vite-html-renderer.d.ts +18 -0
  831. package/dist/vite-html-renderer.d.ts.map +1 -0
  832. package/dist/vite-html-renderer.js +61 -0
  833. package/dist/vite-html-renderer.js.map +1 -0
  834. package/dist/worktree-config.d.ts +19 -0
  835. package/dist/worktree-config.d.ts.map +1 -0
  836. package/dist/worktree-config.js +368 -0
  837. package/dist/worktree-config.js.map +1 -0
  838. package/package.json +90 -0
  839. package/skills/diagnose-why-work-stopped/SKILL.md +161 -0
  840. package/skills/evermore/SKILL.md +366 -0
  841. package/skills/evermore/references/api-reference.md +899 -0
  842. package/skills/evermore/references/company-skills.md +193 -0
  843. package/skills/evermore/references/issue-workspaces.md +80 -0
  844. package/skills/evermore/references/routines.md +187 -0
  845. package/skills/evermore/references/workflows.md +141 -0
  846. package/skills/evermore-converting-plans-to-tasks/SKILL.md +42 -0
  847. package/skills/evermore-create-agent/SKILL.md +163 -0
  848. package/skills/evermore-create-agent/references/agent-instruction-templates.md +123 -0
  849. package/skills/evermore-create-agent/references/agents/coder.md +64 -0
  850. package/skills/evermore-create-agent/references/agents/qa.md +88 -0
  851. package/skills/evermore-create-agent/references/agents/securityengineer.md +135 -0
  852. package/skills/evermore-create-agent/references/agents/uxdesigner.md +115 -0
  853. package/skills/evermore-create-agent/references/api-reference.md +110 -0
  854. package/skills/evermore-create-agent/references/baseline-role-guide.md +168 -0
  855. package/skills/evermore-create-agent/references/draft-review-checklist.md +95 -0
  856. package/skills/evermore-create-plugin/SKILL.md +101 -0
  857. package/skills/evermore-dev/SKILL.md +267 -0
  858. package/skills/para-memory-files/SKILL.md +104 -0
  859. package/skills/para-memory-files/references/schemas.md +35 -0
  860. package/skills/terminal-bench-loop/SKILL.md +236 -0
  861. package/ui-dist/android-chrome-192x192.png +0 -0
  862. package/ui-dist/android-chrome-512x512.png +0 -0
  863. package/ui-dist/apple-touch-icon.png +0 -0
  864. package/ui-dist/assets/_basePickBy-Ds9oHp1_.js +1 -0
  865. package/ui-dist/assets/_baseUniq-CHYwQyJ_.js +1 -0
  866. package/ui-dist/assets/apl-B4CMkyY2.js +1 -0
  867. package/ui-dist/assets/arc-CiUKtBzk.js +1 -0
  868. package/ui-dist/assets/architectureDiagram-VXUJARFQ-CAW2b6pT.js +36 -0
  869. package/ui-dist/assets/asciiarmor-Df11BRmG.js +1 -0
  870. package/ui-dist/assets/asn1-EdZsLKOL.js +1 -0
  871. package/ui-dist/assets/asterisk-B-8jnY81.js +1 -0
  872. package/ui-dist/assets/blockDiagram-VD42YOAC-1Rk6YCcn.js +122 -0
  873. package/ui-dist/assets/brainfuck-C4LP7Hcl.js +1 -0
  874. package/ui-dist/assets/c4Diagram-YG6GDRKO-DF5RJtyZ.js +10 -0
  875. package/ui-dist/assets/channel-D7SqxhNi.js +1 -0
  876. package/ui-dist/assets/chunk-4BX2VUAB-BSZDJAxk.js +1 -0
  877. package/ui-dist/assets/chunk-55IACEB6-DgVOW-V3.js +1 -0
  878. package/ui-dist/assets/chunk-B4BG7PRW-C1sGAq6t.js +165 -0
  879. package/ui-dist/assets/chunk-DI55MBZ5-DZyfq3VK.js +220 -0
  880. package/ui-dist/assets/chunk-FMBD7UC4-D6K9nYXi.js +15 -0
  881. package/ui-dist/assets/chunk-QN33PNHL-BJ0Ni2l9.js +1 -0
  882. package/ui-dist/assets/chunk-QZHKN3VN-Cwjr0vxG.js +1 -0
  883. package/ui-dist/assets/chunk-TZMSLE5B-C2RGCkyV.js +1 -0
  884. package/ui-dist/assets/classDiagram-2ON5EDUG-Cx1PlXXb.js +1 -0
  885. package/ui-dist/assets/classDiagram-v2-WZHVMYZB-Cx1PlXXb.js +1 -0
  886. package/ui-dist/assets/clike-B9uivgTg.js +1 -0
  887. package/ui-dist/assets/clojure-BMjYHr_A.js +1 -0
  888. package/ui-dist/assets/clone-5ZE-SRxk.js +1 -0
  889. package/ui-dist/assets/cmake-BQqOBYOt.js +1 -0
  890. package/ui-dist/assets/cobol-CWcv1MsR.js +1 -0
  891. package/ui-dist/assets/coffeescript-S37ZYGWr.js +1 -0
  892. package/ui-dist/assets/commonlisp-DBKNyK5s.js +1 -0
  893. package/ui-dist/assets/cose-bilkent-S5V4N54A-CW0Mh3DC.js +1 -0
  894. package/ui-dist/assets/crystal-SjHAIU92.js +1 -0
  895. package/ui-dist/assets/css-BnMrqG3P.js +1 -0
  896. package/ui-dist/assets/cypher-C_CwsFkJ.js +1 -0
  897. package/ui-dist/assets/cytoscape.esm-jbPEKk2Y.js +321 -0
  898. package/ui-dist/assets/d-pRatUO7H.js +1 -0
  899. package/ui-dist/assets/dagre-6UL2VRFP-BXDbyGyw.js +4 -0
  900. package/ui-dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  901. package/ui-dist/assets/diagram-PSM6KHXK-BHW-b3P9.js +24 -0
  902. package/ui-dist/assets/diagram-QEK2KX5R-vjGsaMmX.js +43 -0
  903. package/ui-dist/assets/diagram-S2PKOQOG-BHVhRqBj.js +24 -0
  904. package/ui-dist/assets/diff-DbItnlRl.js +1 -0
  905. package/ui-dist/assets/dockerfile-BKs6k2Af.js +1 -0
  906. package/ui-dist/assets/dtd-DF_7sFjM.js +1 -0
  907. package/ui-dist/assets/dylan-DwRh75JA.js +1 -0
  908. package/ui-dist/assets/ebnf-CDyGwa7X.js +1 -0
  909. package/ui-dist/assets/ecl-Cabwm37j.js +1 -0
  910. package/ui-dist/assets/eiffel-CnydiIhH.js +1 -0
  911. package/ui-dist/assets/elm-vLlmbW-K.js +1 -0
  912. package/ui-dist/assets/erDiagram-Q2GNP2WA-DwsdEDB2.js +60 -0
  913. package/ui-dist/assets/erlang-BNw1qcRV.js +1 -0
  914. package/ui-dist/assets/factor-kuTfRLto.js +1 -0
  915. package/ui-dist/assets/fcl-Kvtd6kyn.js +1 -0
  916. package/ui-dist/assets/flowDiagram-NV44I4VS-Bv7drkZu.js +162 -0
  917. package/ui-dist/assets/forth-Ffai-XNe.js +1 -0
  918. package/ui-dist/assets/fortran-DYz_wnZ1.js +1 -0
  919. package/ui-dist/assets/ganttDiagram-JELNMOA3-DyYAGyjV.js +267 -0
  920. package/ui-dist/assets/gas-Bneqetm1.js +1 -0
  921. package/ui-dist/assets/gherkin-heZmZLOM.js +1 -0
  922. package/ui-dist/assets/gitGraphDiagram-V2S2FVAM-DmKJJ2X0.js +65 -0
  923. package/ui-dist/assets/graph-BI12oqz9.js +1 -0
  924. package/ui-dist/assets/groovy-D9Dt4D0W.js +1 -0
  925. package/ui-dist/assets/haskell-Cw1EW3IL.js +1 -0
  926. package/ui-dist/assets/haxe-H-WmDvRZ.js +1 -0
  927. package/ui-dist/assets/http-DBlCnlav.js +1 -0
  928. package/ui-dist/assets/idl-BEugSyMb.js +1 -0
  929. package/ui-dist/assets/index-B1YmgKZD.js +1 -0
  930. package/ui-dist/assets/index-B5EG1mbW.js +1 -0
  931. package/ui-dist/assets/index-B63DPkk7.js +2 -0
  932. package/ui-dist/assets/index-BAalUM2u.js +1 -0
  933. package/ui-dist/assets/index-BCyQqUEQ.js +1 -0
  934. package/ui-dist/assets/index-BSRsyahM.js +1 -0
  935. package/ui-dist/assets/index-B_Iu4zUd.js +1 -0
  936. package/ui-dist/assets/index-C-BdZUIH.js +1 -0
  937. package/ui-dist/assets/index-CGgUnSQj.js +6 -0
  938. package/ui-dist/assets/index-COTIEysQ.js +1 -0
  939. package/ui-dist/assets/index-ChSqseHR.js +1 -0
  940. package/ui-dist/assets/index-Ckf1hADU.js +534 -0
  941. package/ui-dist/assets/index-D4M1TSCO.js +3 -0
  942. package/ui-dist/assets/index-DCTk2CN-.js +7 -0
  943. package/ui-dist/assets/index-DI-wyUUr.js +1 -0
  944. package/ui-dist/assets/index-DNtLqZ-D.js +1 -0
  945. package/ui-dist/assets/index-DSRR_614.css +1 -0
  946. package/ui-dist/assets/index-DarmgkJv.js +1 -0
  947. package/ui-dist/assets/index-DdcxF71a.js +1 -0
  948. package/ui-dist/assets/index-DfwWaMga.js +1 -0
  949. package/ui-dist/assets/index-SzUviW57.js +13 -0
  950. package/ui-dist/assets/index-VjZhELb6.js +1 -0
  951. package/ui-dist/assets/index-mEcmy8wG.js +1 -0
  952. package/ui-dist/assets/index-q7ldlDv6.js +1 -0
  953. package/ui-dist/assets/infoDiagram-HS3SLOUP-CqAxMRbC.js +2 -0
  954. package/ui-dist/assets/init-Gi6I4Gst.js +1 -0
  955. package/ui-dist/assets/javascript-iXu5QeM3.js +1 -0
  956. package/ui-dist/assets/journeyDiagram-XKPGCS4Q-DUJiudtY.js +139 -0
  957. package/ui-dist/assets/julia-DuME0IfC.js +1 -0
  958. package/ui-dist/assets/kanban-definition-3W4ZIXB7-CiRgJ4X2.js +89 -0
  959. package/ui-dist/assets/katex-B95LWT_Q.js +261 -0
  960. package/ui-dist/assets/layout-DJ8V2pqt.js +1 -0
  961. package/ui-dist/assets/linear-BwnNUuyZ.js +1 -0
  962. package/ui-dist/assets/livescript-BwQOo05w.js +1 -0
  963. package/ui-dist/assets/lua-BgMRiT3U.js +1 -0
  964. package/ui-dist/assets/mathematica-DTrFuWx2.js +1 -0
  965. package/ui-dist/assets/mbox-CNhZ1qSd.js +1 -0
  966. package/ui-dist/assets/mermaid.core-DLCiCWj4.js +250 -0
  967. package/ui-dist/assets/mindmap-definition-VGOIOE7T-epIiGA01.js +68 -0
  968. package/ui-dist/assets/mirc-CjQqDB4T.js +1 -0
  969. package/ui-dist/assets/mllike-CXdrOF99.js +1 -0
  970. package/ui-dist/assets/modelica-Dc1JOy9r.js +1 -0
  971. package/ui-dist/assets/mscgen-BA5vi2Kp.js +1 -0
  972. package/ui-dist/assets/mumps-BT43cFF4.js +1 -0
  973. package/ui-dist/assets/nginx-DdIZxoE0.js +1 -0
  974. package/ui-dist/assets/nsis-LdVXkNf5.js +1 -0
  975. package/ui-dist/assets/ntriples-BfvgReVJ.js +1 -0
  976. package/ui-dist/assets/octave-Ck1zUtKM.js +1 -0
  977. package/ui-dist/assets/ordinal-Cboi1Yqb.js +1 -0
  978. package/ui-dist/assets/oz-BzwKVEFT.js +1 -0
  979. package/ui-dist/assets/pascal--L3eBynH.js +1 -0
  980. package/ui-dist/assets/perl-CdXCOZ3F.js +1 -0
  981. package/ui-dist/assets/pieDiagram-ADFJNKIX-CHx4pJ9Y.js +30 -0
  982. package/ui-dist/assets/pig-CevX1Tat.js +1 -0
  983. package/ui-dist/assets/powershell-CFHJl5sT.js +1 -0
  984. package/ui-dist/assets/properties-C78fOPTZ.js +1 -0
  985. package/ui-dist/assets/protobuf-ChK-085T.js +1 -0
  986. package/ui-dist/assets/pug-DeIclll2.js +1 -0
  987. package/ui-dist/assets/puppet-DMA9R1ak.js +1 -0
  988. package/ui-dist/assets/python-BuPzkPfP.js +1 -0
  989. package/ui-dist/assets/q-pXgVlZs6.js +1 -0
  990. package/ui-dist/assets/quadrantDiagram-AYHSOK5B-D0tXmGxE.js +7 -0
  991. package/ui-dist/assets/r-B6wPVr8A.js +1 -0
  992. package/ui-dist/assets/requirementDiagram-UZGBJVZJ-BgFc9Xc4.js +64 -0
  993. package/ui-dist/assets/rpm-CTu-6PCP.js +1 -0
  994. package/ui-dist/assets/ruby-B2Rjki9n.js +1 -0
  995. package/ui-dist/assets/sankeyDiagram-TZEHDZUN-DqntX5wV.js +10 -0
  996. package/ui-dist/assets/sas-B4kiWyti.js +1 -0
  997. package/ui-dist/assets/scheme-C41bIUwD.js +1 -0
  998. package/ui-dist/assets/sequenceDiagram-WL72ISMW-BfIJeGAT.js +145 -0
  999. package/ui-dist/assets/shell-CjFT_Tl9.js +1 -0
  1000. package/ui-dist/assets/sieve-C3Gn_uJK.js +1 -0
  1001. package/ui-dist/assets/simple-mode-GW_nhZxv.js +1 -0
  1002. package/ui-dist/assets/smalltalk-CnHTOXQT.js +1 -0
  1003. package/ui-dist/assets/solr-DehyRSwq.js +1 -0
  1004. package/ui-dist/assets/sparql-DkYu6x3z.js +1 -0
  1005. package/ui-dist/assets/spreadsheet-BCZA_wO0.js +1 -0
  1006. package/ui-dist/assets/sql-D0XecflT.js +1 -0
  1007. package/ui-dist/assets/stateDiagram-FKZM4ZOC-CBlsmcoW.js +1 -0
  1008. package/ui-dist/assets/stateDiagram-v2-4FDKWEC3-DJtH2tCS.js +1 -0
  1009. package/ui-dist/assets/stex-C3f8Ysf7.js +1 -0
  1010. package/ui-dist/assets/stylus-B533Al4x.js +1 -0
  1011. package/ui-dist/assets/swift-BzpIVaGY.js +1 -0
  1012. package/ui-dist/assets/tcl-DVfN8rqt.js +1 -0
  1013. package/ui-dist/assets/textile-CnDTJFAw.js +1 -0
  1014. package/ui-dist/assets/tiddlywiki-DO-Gjzrf.js +1 -0
  1015. package/ui-dist/assets/tiki-DGYXhP31.js +1 -0
  1016. package/ui-dist/assets/timeline-definition-IT6M3QCI-C2XyT4Lo.js +61 -0
  1017. package/ui-dist/assets/toml-Bm5Em-hy.js +1 -0
  1018. package/ui-dist/assets/treemap-GDKQZRPO-DvTrxs0e.js +154 -0
  1019. package/ui-dist/assets/troff-wAsdV37c.js +1 -0
  1020. package/ui-dist/assets/ttcn-CfJYG6tj.js +1 -0
  1021. package/ui-dist/assets/ttcn-cfg-B9xdYoR4.js +1 -0
  1022. package/ui-dist/assets/turtle-B1tBg_DP.js +1 -0
  1023. package/ui-dist/assets/vb-CmGdzxic.js +1 -0
  1024. package/ui-dist/assets/vbscript-BuJXcnF6.js +1 -0
  1025. package/ui-dist/assets/velocity-D8B20fx6.js +1 -0
  1026. package/ui-dist/assets/verilog-C6RDOZhf.js +1 -0
  1027. package/ui-dist/assets/vhdl-lSbBsy5d.js +1 -0
  1028. package/ui-dist/assets/webidl-ZXfAyPTL.js +1 -0
  1029. package/ui-dist/assets/xquery-DzFWVndE.js +1 -0
  1030. package/ui-dist/assets/xychartDiagram-PRI3JC2R-pTizTbG0.js +7 -0
  1031. package/ui-dist/assets/yacas-BJ4BC0dw.js +1 -0
  1032. package/ui-dist/assets/z80-Hz9HOZM7.js +1 -0
  1033. package/ui-dist/brands/opencode-logo-dark-square.svg +18 -0
  1034. package/ui-dist/brands/opencode-logo-light-square.svg +18 -0
  1035. package/ui-dist/favicon-16x16.png +0 -0
  1036. package/ui-dist/favicon-32x32.png +0 -0
  1037. package/ui-dist/favicon.ico +0 -0
  1038. package/ui-dist/favicon.svg +9 -0
  1039. package/ui-dist/index.html +49 -0
  1040. package/ui-dist/site.webmanifest +30 -0
  1041. package/ui-dist/sw.js +42 -0
  1042. package/ui-dist/worktree-favicon-16x16.png +0 -0
  1043. package/ui-dist/worktree-favicon-32x32.png +0 -0
  1044. package/ui-dist/worktree-favicon.ico +0 -0
  1045. package/ui-dist/worktree-favicon.svg +9 -0
@@ -0,0 +1,2753 @@
1
+ import { Router } from "express";
2
+ import { generateKeyPairSync, randomUUID } from "node:crypto";
3
+ import path from "node:path";
4
+ import { agents as agentsTable, companies, heartbeatRuns, issues as issuesTable } from "@evermore.work/db";
5
+ import { and, desc, eq, inArray, not, sql } from "drizzle-orm";
6
+ import { agentSkillSyncSchema, agentMineInboxQuerySchema, AGENT_DEFAULT_MAX_CONCURRENT_RUNS, createAgentKeySchema, createAgentHireSchema, createAgentSchema, deriveAgentUrlKey, isUuidLike, normalizeIssueIdentifier, resetAgentSessionSchema, testAdapterEnvironmentSchema, upsertAgentInstructionsFileSchema, updateAgentInstructionsBundleSchema, updateAgentPermissionsSchema, updateAgentInstructionsPathSchema, wakeAgentSchema, updateAgentSchema, supportedEnvironmentDriversForAdapter, } from "@evermore.work/shared";
7
+ import { readEvermoreSkillSyncPreference, writeEvermoreSkillSyncPreference, } from "@evermore.work/adapter-utils/server-utils";
8
+ import { trackAgentCreated } from "@evermore.work/shared/telemetry";
9
+ import { validate } from "../middleware/validate.js";
10
+ import { agentService, agentInstructionsService, accessService, approvalService, companySkillService, budgetService, heartbeatService, ISSUE_LIST_DEFAULT_LIMIT, issueApprovalService, issueService, logActivity, syncInstructionsBundleConfigFromFilePath, workspaceOperationService, } from "../services/index.js";
11
+ import { conflict, forbidden, notFound, unprocessable } from "../errors.js";
12
+ import { assertBoard, assertCompanyAccess, assertInstanceAdmin, getActorInfo } from "./authz.js";
13
+ import { assertNoAgentHostWorkspaceCommandMutation, collectAgentAdapterWorkspaceCommandPaths, } from "./workspace-command-authz.js";
14
+ import { environmentService } from "../services/environments.js";
15
+ import { resolveEnvironmentExecutionTarget } from "../services/environment-execution-target.js";
16
+ import { environmentRuntimeService } from "../services/environment-runtime.js";
17
+ import { secretService } from "../services/secrets.js";
18
+ import { detectAdapterModel, findActiveServerAdapter, findServerAdapter, listAdapterModels, listAdapterModelProfiles, refreshAdapterModels, requireServerAdapter, } from "../adapters/index.js";
19
+ import { redactEventPayload } from "../redaction.js";
20
+ import { redactCurrentUserValue } from "../log-redaction.js";
21
+ import { renderOrgChartSvg, renderOrgChartPng, ORG_CHART_STYLES } from "./org-chart-svg.js";
22
+ import { instanceSettingsService } from "../services/instance-settings.js";
23
+ import { runClaudeLogin } from "@evermore.work/adapter-claude-local/server";
24
+ import { DEFAULT_ACPX_LOCAL_AGENT, DEFAULT_ACPX_LOCAL_MODE, DEFAULT_ACPX_LOCAL_NON_INTERACTIVE_PERMISSIONS, DEFAULT_ACPX_LOCAL_PERMISSION_MODE, } from "@evermore.work/adapter-acpx-local";
25
+ import { DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX, DEFAULT_CODEX_LOCAL_MODEL, } from "@evermore.work/adapter-codex-local";
26
+ import { DEFAULT_CURSOR_LOCAL_MODEL } from "@evermore.work/adapter-cursor-local";
27
+ import { DEFAULT_GEMINI_LOCAL_MODEL } from "@evermore.work/adapter-gemini-local";
28
+ import { DEFAULT_OPENCODE_LOCAL_MODEL } from "@evermore.work/adapter-opencode-local";
29
+ import { requireOpenCodeModelId } from "@evermore.work/adapter-opencode-local/server";
30
+ import { loadDefaultAgentInstructionsBundle, resolveDefaultAgentInstructionsBundleRole, } from "../services/default-agent-instructions.js";
31
+ import { getTelemetryClient } from "../telemetry.js";
32
+ import { assertEnvironmentSelectionForCompany } from "./environment-selection.js";
33
+ import { recoveryService } from "../services/recovery/service.js";
34
+ const RUN_LOG_DEFAULT_LIMIT_BYTES = 256_000;
35
+ const RUN_LOG_MAX_LIMIT_BYTES = 1024 * 1024;
36
+ function readRunLogLimitBytes(value) {
37
+ const parsed = Number(value ?? RUN_LOG_DEFAULT_LIMIT_BYTES);
38
+ if (!Number.isFinite(parsed))
39
+ return RUN_LOG_DEFAULT_LIMIT_BYTES;
40
+ return Math.max(1, Math.min(RUN_LOG_MAX_LIMIT_BYTES, Math.trunc(parsed)));
41
+ }
42
+ function readLiveRunsQueryInt(value, max, fallback = 0) {
43
+ const parsed = Number(value);
44
+ if (!Number.isFinite(parsed))
45
+ return fallback;
46
+ if (parsed <= 0)
47
+ return fallback;
48
+ return Math.min(max, Math.trunc(parsed));
49
+ }
50
+ export function agentRoutes(db, options = {}) {
51
+ // Legacy hardcoded maps — used as fallback when adapter module does not
52
+ // declare capability flags explicitly.
53
+ const DEFAULT_INSTRUCTIONS_PATH_KEYS = {
54
+ acpx_local: "instructionsFilePath",
55
+ claude_local: "instructionsFilePath",
56
+ codex_local: "instructionsFilePath",
57
+ droid_local: "instructionsFilePath",
58
+ gemini_local: "instructionsFilePath",
59
+ hermes_local: "instructionsFilePath",
60
+ opencode_local: "instructionsFilePath",
61
+ cursor: "instructionsFilePath",
62
+ pi_local: "instructionsFilePath",
63
+ };
64
+ const DEFAULT_MANAGED_INSTRUCTIONS_ADAPTER_TYPES = new Set(Object.keys(DEFAULT_INSTRUCTIONS_PATH_KEYS));
65
+ /** Check if an adapter supports the managed instructions bundle. */
66
+ function adapterSupportsInstructionsBundle(adapterType) {
67
+ const adapter = findActiveServerAdapter(adapterType);
68
+ if (adapter?.supportsInstructionsBundle !== undefined)
69
+ return adapter.supportsInstructionsBundle;
70
+ return DEFAULT_MANAGED_INSTRUCTIONS_ADAPTER_TYPES.has(adapterType);
71
+ }
72
+ /** Resolve the adapter config key for the instructions file path. */
73
+ function resolveInstructionsPathKey(adapterType) {
74
+ const adapter = findActiveServerAdapter(adapterType);
75
+ if (adapter?.instructionsPathKey)
76
+ return adapter.instructionsPathKey;
77
+ if (adapter?.supportsInstructionsBundle === true)
78
+ return "instructionsFilePath";
79
+ if (adapter?.supportsInstructionsBundle === false)
80
+ return null;
81
+ return DEFAULT_INSTRUCTIONS_PATH_KEYS[adapterType] ?? null;
82
+ }
83
+ const KNOWN_INSTRUCTIONS_PATH_KEYS = new Set(["instructionsFilePath", "agentsMdPath"]);
84
+ const KNOWN_INSTRUCTIONS_BUNDLE_KEYS = [
85
+ "instructionsBundleMode",
86
+ "instructionsRootPath",
87
+ "instructionsEntryFile",
88
+ "instructionsFilePath",
89
+ "agentsMdPath",
90
+ ];
91
+ const router = Router();
92
+ const svc = agentService(db);
93
+ const access = accessService(db);
94
+ const approvalsSvc = approvalService(db);
95
+ const budgets = budgetService(db);
96
+ const environmentsSvc = environmentService(db);
97
+ const environmentRuntime = environmentRuntimeService(db, {
98
+ pluginWorkerManager: options.pluginWorkerManager,
99
+ });
100
+ const heartbeat = heartbeatService(db, {
101
+ pluginWorkerManager: options.pluginWorkerManager,
102
+ });
103
+ const recovery = recoveryService(db, { enqueueWakeup: heartbeat.wakeup });
104
+ const issueApprovalsSvc = issueApprovalService(db);
105
+ const secretsSvc = secretService(db);
106
+ const instructions = agentInstructionsService();
107
+ const companySkills = companySkillService(db);
108
+ const workspaceOperations = workspaceOperationService(db);
109
+ const instanceSettings = instanceSettingsService(db);
110
+ const strictSecretsMode = process.env.EVERMORE_SECRETS_STRICT_MODE === "true";
111
+ async function assertAgentEnvironmentSelection(companyId, adapterType, environmentId) {
112
+ if (environmentId === undefined || environmentId === null)
113
+ return;
114
+ await assertEnvironmentSelectionForCompany(environmentService(db), companyId, environmentId, {
115
+ allowedDrivers: allowedEnvironmentDriversForAgent(adapterType),
116
+ });
117
+ }
118
+ /**
119
+ * Resolve the execution target the adapter should run its test probes against.
120
+ *
121
+ * - No environmentId / local environment → returns a local target so the
122
+ * adapter probes the Evermore host (legacy behavior).
123
+ * - SSH environment → builds an SSH execution target from the environment
124
+ * config so the adapter probes the remote box. No lease is required:
125
+ * the SSH spec is fully derived from the saved environment config.
126
+ * - Sandbox / plugin environments → acquires an ad-hoc lease, realizes the
127
+ * workspace, and resolves a sandbox execution target wired to the runtime
128
+ * so the adapter probe runs inside the sandbox the same way a heartbeat
129
+ * would. The returned `release` callback rolls the lease back when the
130
+ * route is done.
131
+ *
132
+ * The caller MUST always invoke `release()` (typically in a `finally` block).
133
+ */
134
+ async function resolveAdapterTestExecutionContext(input) {
135
+ const noopRelease = async () => { };
136
+ if (!input.environmentId) {
137
+ return {
138
+ executionTarget: null,
139
+ environmentName: null,
140
+ fallbackChecks: [],
141
+ release: noopRelease,
142
+ };
143
+ }
144
+ const environment = await environmentsSvc.getById(input.environmentId);
145
+ if (!environment || environment.companyId !== input.companyId) {
146
+ return {
147
+ executionTarget: null,
148
+ environmentName: null,
149
+ fallbackChecks: [
150
+ {
151
+ code: "environment_not_found",
152
+ level: "warn",
153
+ message: "Selected environment was not found. The test did not run.",
154
+ },
155
+ ],
156
+ release: noopRelease,
157
+ };
158
+ }
159
+ if (environment.driver === "local") {
160
+ return {
161
+ executionTarget: null,
162
+ environmentName: environment.name,
163
+ fallbackChecks: [],
164
+ release: noopRelease,
165
+ };
166
+ }
167
+ if (environment.driver === "ssh") {
168
+ try {
169
+ const target = await resolveEnvironmentExecutionTarget({
170
+ db,
171
+ companyId: input.companyId,
172
+ adapterType: input.adapterType,
173
+ environment: {
174
+ id: environment.id,
175
+ driver: environment.driver,
176
+ config: environment.config ?? null,
177
+ },
178
+ leaseMetadata: null,
179
+ });
180
+ if (target) {
181
+ return {
182
+ executionTarget: target,
183
+ environmentName: environment.name,
184
+ fallbackChecks: [],
185
+ release: noopRelease,
186
+ };
187
+ }
188
+ return {
189
+ executionTarget: null,
190
+ environmentName: environment.name,
191
+ fallbackChecks: [
192
+ {
193
+ code: "environment_target_unavailable",
194
+ level: "warn",
195
+ message: `Could not resolve an execution target for environment "${environment.name}". The test did not run.`,
196
+ },
197
+ ],
198
+ release: noopRelease,
199
+ };
200
+ }
201
+ catch (err) {
202
+ return {
203
+ executionTarget: null,
204
+ environmentName: environment.name,
205
+ fallbackChecks: [
206
+ {
207
+ code: "environment_target_failed",
208
+ level: "warn",
209
+ message: `Could not connect to environment "${environment.name}" to run the test.`,
210
+ detail: err instanceof Error ? err.message : String(err),
211
+ },
212
+ ],
213
+ release: noopRelease,
214
+ };
215
+ }
216
+ }
217
+ // sandbox / plugin / other remote drivers: spin up an ad-hoc lease, realize
218
+ // the workspace inside the box, and run the same probe SSH uses against
219
+ // a sandbox execution target wired to the environment runtime.
220
+ //
221
+ // We pass `heartbeatRunId: null` because there's no heartbeat run for an
222
+ // operator-initiated `Test` invocation — the leases table FKs heartbeat
223
+ // run id to heartbeat_runs.id, and we don't want to manufacture a fake
224
+ // run row. Cleanup goes through the driver's `releaseRunLease` directly
225
+ // (by lease record), since the batch helper queries by heartbeatRunId.
226
+ let leaseRecord;
227
+ try {
228
+ leaseRecord = await environmentRuntime.acquireRunLease({
229
+ companyId: input.companyId,
230
+ environment,
231
+ issueId: null,
232
+ heartbeatRunId: null,
233
+ persistedExecutionWorkspace: null,
234
+ });
235
+ }
236
+ catch (err) {
237
+ return {
238
+ executionTarget: null,
239
+ environmentName: environment.name,
240
+ fallbackChecks: [
241
+ {
242
+ code: "environment_lease_acquire_failed",
243
+ level: "error",
244
+ message: `Could not acquire a lease for environment "${environment.name}".`,
245
+ detail: err instanceof Error ? err.message : String(err),
246
+ hint: "Check the environment's provider credentials and quota.",
247
+ },
248
+ ],
249
+ release: noopRelease,
250
+ };
251
+ }
252
+ const driver = environmentRuntime.getDriver(environment.driver);
253
+ const releaseLease = async (status = "released") => {
254
+ try {
255
+ if (driver) {
256
+ await driver.releaseRunLease({
257
+ environment,
258
+ lease: leaseRecord.lease,
259
+ status,
260
+ });
261
+ }
262
+ else {
263
+ await environmentsSvc.releaseLease(leaseRecord.lease.id, status);
264
+ }
265
+ }
266
+ catch (err) {
267
+ // Cleanup failures must not mask the test result.
268
+ // eslint-disable-next-line no-console
269
+ console.warn(`[adapter-test] Failed to release lease ${leaseRecord.lease.id}: ${err instanceof Error ? err.message : String(err)}`);
270
+ }
271
+ };
272
+ let realizedCwd = null;
273
+ try {
274
+ const realized = await environmentRuntime.realizeWorkspace({
275
+ environment,
276
+ lease: leaseRecord.lease,
277
+ // No host workspace to copy for a Test invocation; sandbox/plugin
278
+ // realize implementations use the lease metadata's remoteCwd to
279
+ // create the working directory inside the box.
280
+ workspace: {},
281
+ });
282
+ realizedCwd =
283
+ typeof realized.cwd === "string" && realized.cwd.trim().length > 0
284
+ ? realized.cwd.trim()
285
+ : null;
286
+ }
287
+ catch (err) {
288
+ await releaseLease("failed");
289
+ return {
290
+ executionTarget: null,
291
+ environmentName: environment.name,
292
+ fallbackChecks: [
293
+ {
294
+ code: "environment_workspace_realize_failed",
295
+ level: "error",
296
+ message: `Could not realize a workspace inside "${environment.name}".`,
297
+ detail: err instanceof Error ? err.message : String(err),
298
+ },
299
+ ],
300
+ release: noopRelease,
301
+ };
302
+ }
303
+ let target;
304
+ try {
305
+ // Prefer the cwd the realize step returned; fall back to lease metadata.
306
+ const leaseMetadataForTarget = realizedCwd
307
+ ? { ...(leaseRecord.lease.metadata ?? {}), remoteCwd: realizedCwd }
308
+ : leaseRecord.lease.metadata ?? null;
309
+ target = await resolveEnvironmentExecutionTarget({
310
+ db,
311
+ companyId: input.companyId,
312
+ adapterType: input.adapterType,
313
+ environment: {
314
+ id: environment.id,
315
+ driver: environment.driver,
316
+ config: environment.config ?? null,
317
+ },
318
+ leaseId: leaseRecord.lease.id,
319
+ leaseMetadata: leaseMetadataForTarget,
320
+ lease: leaseRecord.lease,
321
+ environmentRuntime,
322
+ });
323
+ }
324
+ catch (err) {
325
+ await releaseLease("failed");
326
+ return {
327
+ executionTarget: null,
328
+ environmentName: environment.name,
329
+ fallbackChecks: [
330
+ {
331
+ code: "environment_target_failed",
332
+ level: "error",
333
+ message: `Could not resolve a sandbox execution target for "${environment.name}".`,
334
+ detail: err instanceof Error ? err.message : String(err),
335
+ },
336
+ ],
337
+ release: noopRelease,
338
+ };
339
+ }
340
+ if (!target) {
341
+ await releaseLease("failed");
342
+ return {
343
+ executionTarget: null,
344
+ environmentName: environment.name,
345
+ fallbackChecks: [
346
+ {
347
+ code: "environment_target_unsupported",
348
+ level: "warn",
349
+ message: `Adapter "${input.adapterType}" is not allowed in "${environment.name}" environments.`,
350
+ },
351
+ ],
352
+ release: noopRelease,
353
+ };
354
+ }
355
+ return {
356
+ executionTarget: target,
357
+ environmentName: environment.name,
358
+ fallbackChecks: [],
359
+ release: releaseLease,
360
+ };
361
+ }
362
+ async function getCurrentUserRedactionOptions() {
363
+ return {
364
+ enabled: (await instanceSettings.getGeneral()).censorUsernameInLogs,
365
+ };
366
+ }
367
+ function canCreateAgents(agent) {
368
+ if (!agent.permissions || typeof agent.permissions !== "object")
369
+ return false;
370
+ return Boolean(agent.permissions.canCreateAgents);
371
+ }
372
+ async function buildAgentAccessState(agent) {
373
+ const membership = await access.getMembership(agent.companyId, "agent", agent.id);
374
+ const grants = membership
375
+ ? await access.listPrincipalGrants(agent.companyId, "agent", agent.id)
376
+ : [];
377
+ const hasExplicitTaskAssignGrant = grants.some((grant) => grant.permissionKey === "tasks:assign");
378
+ if (agent.role === "ceo") {
379
+ return {
380
+ canAssignTasks: true,
381
+ taskAssignSource: "ceo_role",
382
+ membership,
383
+ grants,
384
+ };
385
+ }
386
+ if (canCreateAgents(agent)) {
387
+ return {
388
+ canAssignTasks: true,
389
+ taskAssignSource: "agent_creator",
390
+ membership,
391
+ grants,
392
+ };
393
+ }
394
+ if (hasExplicitTaskAssignGrant) {
395
+ return {
396
+ canAssignTasks: true,
397
+ taskAssignSource: "explicit_grant",
398
+ membership,
399
+ grants,
400
+ };
401
+ }
402
+ return {
403
+ canAssignTasks: false,
404
+ taskAssignSource: "none",
405
+ membership,
406
+ grants,
407
+ };
408
+ }
409
+ async function buildAgentDetail(agent, options) {
410
+ const [chainOfCommand, accessState] = await Promise.all([
411
+ svc.getChainOfCommand(agent.id),
412
+ buildAgentAccessState(agent),
413
+ ]);
414
+ return {
415
+ ...(options?.restricted ? redactForRestrictedAgentView(agent) : agent),
416
+ chainOfCommand,
417
+ access: accessState,
418
+ };
419
+ }
420
+ async function applyDefaultAgentTaskAssignGrant(companyId, agentId, grantedByUserId) {
421
+ await access.ensureMembership(companyId, "agent", agentId, "member", "active");
422
+ await access.setPrincipalPermission(companyId, "agent", agentId, "tasks:assign", true, grantedByUserId);
423
+ }
424
+ async function assertCanCreateAgentsForCompany(req, companyId) {
425
+ assertCompanyAccess(req, companyId);
426
+ if (req.actor.type === "board") {
427
+ if (req.actor.source === "local_implicit" || req.actor.isInstanceAdmin)
428
+ return null;
429
+ const allowed = await access.canUser(companyId, req.actor.userId, "agents:create");
430
+ if (!allowed) {
431
+ throw forbidden("Missing permission: agents:create");
432
+ }
433
+ return null;
434
+ }
435
+ if (!req.actor.agentId)
436
+ throw forbidden("Agent authentication required");
437
+ const actorAgent = await svc.getById(req.actor.agentId);
438
+ if (!actorAgent || actorAgent.companyId !== companyId) {
439
+ throw forbidden("Agent key cannot access another company");
440
+ }
441
+ const allowedByGrant = await access.hasPermission(companyId, "agent", actorAgent.id, "agents:create");
442
+ if (!allowedByGrant && !canCreateAgents(actorAgent)) {
443
+ throw forbidden("Missing permission: can create agents");
444
+ }
445
+ return actorAgent;
446
+ }
447
+ async function assertBoardCanManageAgentsForCompany(req, companyId) {
448
+ assertBoard(req);
449
+ assertCompanyAccess(req, companyId);
450
+ if (req.actor.source === "local_implicit" || req.actor.isInstanceAdmin)
451
+ return;
452
+ const allowed = await access.canUser(companyId, req.actor.userId, "agents:create");
453
+ if (!allowed) {
454
+ throw forbidden("Missing permission: agents:create");
455
+ }
456
+ }
457
+ async function assertCanReadConfigurations(req, companyId) {
458
+ return assertCanCreateAgentsForCompany(req, companyId);
459
+ }
460
+ async function getAccessibleAgent(req, res, id) {
461
+ const agent = await svc.getById(id);
462
+ if (!agent) {
463
+ res.status(404).json({ error: "Agent not found" });
464
+ return null;
465
+ }
466
+ assertCompanyAccess(req, agent.companyId);
467
+ if (req.actor.type === "board") {
468
+ await assertBoardCanManageAgentsForCompany(req, agent.companyId);
469
+ }
470
+ return agent;
471
+ }
472
+ async function actorCanReadConfigurationsForCompany(req, companyId) {
473
+ assertCompanyAccess(req, companyId);
474
+ if (req.actor.type === "board") {
475
+ if (req.actor.source === "local_implicit" || req.actor.isInstanceAdmin)
476
+ return true;
477
+ return access.canUser(companyId, req.actor.userId, "agents:create");
478
+ }
479
+ if (!req.actor.agentId)
480
+ return false;
481
+ const actorAgent = await svc.getById(req.actor.agentId);
482
+ if (!actorAgent || actorAgent.companyId !== companyId)
483
+ return false;
484
+ const allowedByGrant = await access.hasPermission(companyId, "agent", actorAgent.id, "agents:create");
485
+ return allowedByGrant || canCreateAgents(actorAgent);
486
+ }
487
+ async function buildSkippedWakeupResponse(agent, payload) {
488
+ const issueId = typeof payload?.issueId === "string" && payload.issueId.trim() ? payload.issueId : null;
489
+ if (!issueId) {
490
+ return {
491
+ status: "skipped",
492
+ reason: "wakeup_skipped",
493
+ message: "Wakeup was skipped.",
494
+ issueId: null,
495
+ executionRunId: null,
496
+ executionAgentId: null,
497
+ executionAgentName: null,
498
+ };
499
+ }
500
+ const issue = await db
501
+ .select({
502
+ id: issuesTable.id,
503
+ executionRunId: issuesTable.executionRunId,
504
+ })
505
+ .from(issuesTable)
506
+ .where(and(eq(issuesTable.id, issueId), eq(issuesTable.companyId, agent.companyId)))
507
+ .then((rows) => rows[0] ?? null);
508
+ if (!issue?.executionRunId) {
509
+ return {
510
+ status: "skipped",
511
+ reason: "wakeup_skipped",
512
+ message: "Wakeup was skipped.",
513
+ issueId,
514
+ executionRunId: null,
515
+ executionAgentId: null,
516
+ executionAgentName: null,
517
+ };
518
+ }
519
+ const executionRun = await heartbeat.getRun(issue.executionRunId);
520
+ if (!executionRun || (executionRun.status !== "queued" && executionRun.status !== "running")) {
521
+ return {
522
+ status: "skipped",
523
+ reason: "wakeup_skipped",
524
+ message: "Wakeup was skipped.",
525
+ issueId,
526
+ executionRunId: issue.executionRunId,
527
+ executionAgentId: null,
528
+ executionAgentName: null,
529
+ };
530
+ }
531
+ const executionAgent = await svc.getById(executionRun.agentId);
532
+ const executionAgentName = executionAgent?.name ?? null;
533
+ return {
534
+ status: "skipped",
535
+ reason: "issue_execution_deferred",
536
+ message: executionAgentName
537
+ ? `Wakeup was deferred because this issue is already being executed by ${executionAgentName}.`
538
+ : "Wakeup was deferred because this issue already has an active execution run.",
539
+ issueId,
540
+ executionRunId: executionRun.id,
541
+ executionAgentId: executionRun.agentId,
542
+ executionAgentName,
543
+ };
544
+ }
545
+ async function assertCanUpdateAgent(req, targetAgent) {
546
+ assertCompanyAccess(req, targetAgent.companyId);
547
+ if (req.actor.type === "board") {
548
+ await assertBoardCanManageAgentsForCompany(req, targetAgent.companyId);
549
+ return;
550
+ }
551
+ if (!req.actor.agentId)
552
+ throw forbidden("Agent authentication required");
553
+ const actorAgent = await svc.getById(req.actor.agentId);
554
+ if (!actorAgent || actorAgent.companyId !== targetAgent.companyId) {
555
+ throw forbidden("Agent key cannot access another company");
556
+ }
557
+ if (actorAgent.id === targetAgent.id)
558
+ return;
559
+ if (actorAgent.role === "ceo")
560
+ return;
561
+ const allowedByGrant = await access.hasPermission(targetAgent.companyId, "agent", actorAgent.id, "agents:create");
562
+ if (allowedByGrant || canCreateAgents(actorAgent))
563
+ return;
564
+ throw forbidden("Only CEO or agent creators can modify other agents");
565
+ }
566
+ async function assertCanReadAgent(req, targetAgent) {
567
+ assertCompanyAccess(req, targetAgent.companyId);
568
+ if (req.actor.type === "board") {
569
+ await assertCanReadConfigurations(req, targetAgent.companyId);
570
+ return;
571
+ }
572
+ if (!req.actor.agentId)
573
+ throw forbidden("Agent authentication required");
574
+ const actorAgent = await svc.getById(req.actor.agentId);
575
+ if (!actorAgent || actorAgent.companyId !== targetAgent.companyId) {
576
+ throw forbidden("Agent key cannot access another company");
577
+ }
578
+ }
579
+ function assertKnownAdapterType(type) {
580
+ const adapterType = typeof type === "string" ? type.trim() : "";
581
+ if (!adapterType) {
582
+ throw unprocessable("Adapter type is required");
583
+ }
584
+ if (!findServerAdapter(adapterType)) {
585
+ throw unprocessable(`Unknown adapter type: ${adapterType}`);
586
+ }
587
+ return adapterType;
588
+ }
589
+ async function assertAgentDefaultEnvironmentSelection(companyId, environmentId, options) {
590
+ if (environmentId === undefined || environmentId === null)
591
+ return;
592
+ const environment = await environmentsSvc.getById(environmentId);
593
+ if (!environment || environment.companyId !== companyId) {
594
+ throw unprocessable("Selected environment must belong to the same company");
595
+ }
596
+ if (options?.allowedDrivers && !options.allowedDrivers.includes(environment.driver)) {
597
+ throw unprocessable(`Environment driver "${environment.driver}" is not allowed here`);
598
+ }
599
+ if (environment.driver === "sandbox" && options?.allowedSandboxProviders) {
600
+ const config = environment.config && typeof environment.config === "object"
601
+ ? environment.config
602
+ : {};
603
+ const provider = typeof config.provider === "string" ? config.provider : "";
604
+ if (provider === "fake") {
605
+ throw unprocessable(`Selected sandbox provider "${provider}" is not supported for agent defaults yet`);
606
+ }
607
+ if (options.allowedSandboxProviders.length > 0 && !options.allowedSandboxProviders.includes(provider)) {
608
+ throw unprocessable(`Selected sandbox provider "${provider || "unknown"}" is not supported for agent defaults yet`);
609
+ }
610
+ }
611
+ }
612
+ function hasOwn(value, key) {
613
+ return Object.hasOwn(value, key);
614
+ }
615
+ function allowedEnvironmentDriversForAgent(adapterType) {
616
+ return supportedEnvironmentDriversForAdapter(adapterType);
617
+ }
618
+ function allowedSandboxProvidersForAgent(adapterType) {
619
+ return supportedEnvironmentDriversForAdapter(adapterType).includes("sandbox") ? [] : [];
620
+ }
621
+ async function resolveCompanyIdForAgentReference(req) {
622
+ const companyIdQuery = req.query.companyId;
623
+ const requestedCompanyId = typeof companyIdQuery === "string" && companyIdQuery.trim().length > 0
624
+ ? companyIdQuery.trim()
625
+ : null;
626
+ if (requestedCompanyId) {
627
+ assertCompanyAccess(req, requestedCompanyId);
628
+ return requestedCompanyId;
629
+ }
630
+ if (req.actor.type === "agent" && req.actor.companyId) {
631
+ return req.actor.companyId;
632
+ }
633
+ return null;
634
+ }
635
+ async function normalizeAgentReference(req, rawId) {
636
+ const raw = rawId.trim();
637
+ if (isUuidLike(raw))
638
+ return raw;
639
+ const companyId = await resolveCompanyIdForAgentReference(req);
640
+ if (!companyId) {
641
+ throw unprocessable("Agent shortname lookup requires companyId query parameter");
642
+ }
643
+ const resolved = await svc.resolveByReference(companyId, raw);
644
+ if (resolved.ambiguous) {
645
+ throw conflict("Agent shortname is ambiguous in this company. Use the agent ID.");
646
+ }
647
+ if (!resolved.agent) {
648
+ throw notFound("Agent not found");
649
+ }
650
+ return resolved.agent.id;
651
+ }
652
+ function parseSourceIssueIds(input) {
653
+ const values = [];
654
+ if (Array.isArray(input.sourceIssueIds))
655
+ values.push(...input.sourceIssueIds);
656
+ if (typeof input.sourceIssueId === "string" && input.sourceIssueId.length > 0) {
657
+ values.push(input.sourceIssueId);
658
+ }
659
+ return Array.from(new Set(values));
660
+ }
661
+ function asRecord(value) {
662
+ if (typeof value !== "object" || value === null || Array.isArray(value))
663
+ return null;
664
+ return value;
665
+ }
666
+ function asNonEmptyString(value) {
667
+ if (typeof value !== "string")
668
+ return null;
669
+ const trimmed = value.trim();
670
+ return trimmed.length > 0 ? trimmed : null;
671
+ }
672
+ function preserveInstructionsBundleConfig(existingAdapterConfig, nextAdapterConfig) {
673
+ const nextKeys = new Set(Object.keys(nextAdapterConfig));
674
+ if (KNOWN_INSTRUCTIONS_BUNDLE_KEYS.some((key) => nextKeys.has(key))) {
675
+ return nextAdapterConfig;
676
+ }
677
+ const merged = { ...nextAdapterConfig };
678
+ for (const key of KNOWN_INSTRUCTIONS_BUNDLE_KEYS) {
679
+ if (merged[key] === undefined && existingAdapterConfig[key] !== undefined) {
680
+ merged[key] = existingAdapterConfig[key];
681
+ }
682
+ }
683
+ return merged;
684
+ }
685
+ function parseBooleanLike(value) {
686
+ if (typeof value === "boolean")
687
+ return value;
688
+ if (typeof value === "number") {
689
+ if (value === 1)
690
+ return true;
691
+ if (value === 0)
692
+ return false;
693
+ return null;
694
+ }
695
+ if (typeof value !== "string")
696
+ return null;
697
+ const normalized = value.trim().toLowerCase();
698
+ if (normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on") {
699
+ return true;
700
+ }
701
+ if (normalized === "false" || normalized === "0" || normalized === "no" || normalized === "off") {
702
+ return false;
703
+ }
704
+ return null;
705
+ }
706
+ function parseNumberLike(value) {
707
+ if (typeof value === "number" && Number.isFinite(value))
708
+ return value;
709
+ if (typeof value !== "string")
710
+ return null;
711
+ const parsed = Number(value.trim());
712
+ return Number.isFinite(parsed) ? parsed : null;
713
+ }
714
+ function parseSchedulerHeartbeatPolicy(runtimeConfig) {
715
+ const heartbeat = asRecord(asRecord(runtimeConfig)?.heartbeat) ?? {};
716
+ return {
717
+ enabled: parseBooleanLike(heartbeat.enabled) ?? false,
718
+ intervalSec: Math.max(0, parseNumberLike(heartbeat.intervalSec) ?? 0),
719
+ };
720
+ }
721
+ function normalizeNewAgentRuntimeConfig(runtimeConfig) {
722
+ const parsedRuntimeConfig = asRecord(runtimeConfig);
723
+ const normalizedRuntimeConfig = parsedRuntimeConfig ? { ...parsedRuntimeConfig } : {};
724
+ const parsedHeartbeat = asRecord(normalizedRuntimeConfig.heartbeat);
725
+ const heartbeat = parsedHeartbeat ? { ...parsedHeartbeat } : {};
726
+ if (parseBooleanLike(heartbeat.enabled) == null) {
727
+ heartbeat.enabled = false;
728
+ }
729
+ if (parseNumberLike(heartbeat.maxConcurrentRuns) == null) {
730
+ heartbeat.maxConcurrentRuns = AGENT_DEFAULT_MAX_CONCURRENT_RUNS;
731
+ }
732
+ normalizedRuntimeConfig.heartbeat = heartbeat;
733
+ return normalizedRuntimeConfig;
734
+ }
735
+ function listRuntimeModelProfileAdapterConfigs(runtimeConfig) {
736
+ const runtimeRecord = asRecord(runtimeConfig);
737
+ const modelProfiles = asRecord(runtimeRecord?.modelProfiles);
738
+ if (!modelProfiles)
739
+ return [];
740
+ const entries = [];
741
+ for (const [profileKey, rawProfile] of Object.entries(modelProfiles)) {
742
+ const profile = asRecord(rawProfile);
743
+ const adapterConfig = asRecord(profile?.adapterConfig);
744
+ if (!profile || !adapterConfig)
745
+ continue;
746
+ entries.push({
747
+ profileKey,
748
+ profile,
749
+ adapterConfig,
750
+ path: `runtimeConfig.modelProfiles.${profileKey}.adapterConfig`,
751
+ });
752
+ }
753
+ return entries;
754
+ }
755
+ function assertNoAgentRuntimeConfigAdapterConfigMutation(req, runtimeConfig) {
756
+ for (const entry of listRuntimeModelProfileAdapterConfigs(runtimeConfig)) {
757
+ assertNoAgentAdapterConfigMutation(req, entry.adapterConfig, entry.path);
758
+ }
759
+ }
760
+ async function normalizeMediatedAdapterConfigForPersistence(input) {
761
+ const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(input.companyId, input.adapterConfig, { strictMode: strictSecretsMode });
762
+ await assertAdapterConfigConstraints(input.adapterType, input.constraintAdapterConfig
763
+ ? { ...input.constraintAdapterConfig, ...normalizedAdapterConfig }
764
+ : normalizedAdapterConfig);
765
+ return normalizedAdapterConfig;
766
+ }
767
+ async function normalizeRuntimeConfigAdapterConfigsForPersistence(companyId, adapterType, runtimeConfig, baseAdapterConfig) {
768
+ const entries = listRuntimeModelProfileAdapterConfigs(runtimeConfig);
769
+ if (entries.length === 0)
770
+ return runtimeConfig;
771
+ const adapterModelProfiles = await listAdapterModelProfiles(adapterType);
772
+ const normalizedRuntimeConfig = { ...runtimeConfig };
773
+ const modelProfiles = asRecord(runtimeConfig.modelProfiles) ?? {};
774
+ const normalizedModelProfiles = { ...modelProfiles };
775
+ normalizedRuntimeConfig.modelProfiles = normalizedModelProfiles;
776
+ for (const entry of entries) {
777
+ const adapterProfile = adapterModelProfiles.find((profile) => profile.key === entry.profileKey);
778
+ const adapterDefaultConfig = asRecord(adapterProfile?.adapterConfig) ?? {};
779
+ const normalizedAdapterConfig = await normalizeMediatedAdapterConfigForPersistence({
780
+ companyId,
781
+ adapterType,
782
+ adapterConfig: entry.adapterConfig,
783
+ constraintAdapterConfig: {
784
+ ...baseAdapterConfig,
785
+ ...adapterDefaultConfig,
786
+ },
787
+ });
788
+ normalizedModelProfiles[entry.profileKey] = {
789
+ ...entry.profile,
790
+ adapterConfig: normalizedAdapterConfig,
791
+ };
792
+ }
793
+ return normalizedRuntimeConfig;
794
+ }
795
+ function generateEd25519PrivateKeyPem() {
796
+ const { privateKey } = generateKeyPairSync("ed25519");
797
+ return privateKey.export({ type: "pkcs8", format: "pem" }).toString();
798
+ }
799
+ function ensureGatewayDeviceKey(adapterType, adapterConfig) {
800
+ if (adapterType !== "openclaw_gateway")
801
+ return adapterConfig;
802
+ const disableDeviceAuth = parseBooleanLike(adapterConfig.disableDeviceAuth) === true;
803
+ if (disableDeviceAuth)
804
+ return adapterConfig;
805
+ if (asNonEmptyString(adapterConfig.devicePrivateKeyPem))
806
+ return adapterConfig;
807
+ return { ...adapterConfig, devicePrivateKeyPem: generateEd25519PrivateKeyPem() };
808
+ }
809
+ function applyCreateDefaultsByAdapterType(adapterType, adapterConfig) {
810
+ const next = { ...adapterConfig };
811
+ if (adapterType === "acpx_local") {
812
+ if (!asNonEmptyString(next.agent)) {
813
+ next.agent = DEFAULT_ACPX_LOCAL_AGENT;
814
+ }
815
+ if (!asNonEmptyString(next.mode)) {
816
+ next.mode = DEFAULT_ACPX_LOCAL_MODE;
817
+ }
818
+ if (!asNonEmptyString(next.permissionMode)) {
819
+ next.permissionMode = DEFAULT_ACPX_LOCAL_PERMISSION_MODE;
820
+ }
821
+ if (!asNonEmptyString(next.nonInteractivePermissions)) {
822
+ next.nonInteractivePermissions = DEFAULT_ACPX_LOCAL_NON_INTERACTIVE_PERMISSIONS;
823
+ }
824
+ return ensureGatewayDeviceKey(adapterType, next);
825
+ }
826
+ if (adapterType === "codex_local") {
827
+ if (!asNonEmptyString(next.model)) {
828
+ next.model = DEFAULT_CODEX_LOCAL_MODEL;
829
+ }
830
+ const hasBypassFlag = typeof next.dangerouslyBypassApprovalsAndSandbox === "boolean" ||
831
+ typeof next.dangerouslyBypassSandbox === "boolean";
832
+ if (!hasBypassFlag) {
833
+ next.dangerouslyBypassApprovalsAndSandbox = DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX;
834
+ }
835
+ return ensureGatewayDeviceKey(adapterType, next);
836
+ }
837
+ if (adapterType === "gemini_local" && !asNonEmptyString(next.model)) {
838
+ next.model = DEFAULT_GEMINI_LOCAL_MODEL;
839
+ return ensureGatewayDeviceKey(adapterType, next);
840
+ }
841
+ if (adapterType === "opencode_local" && !asNonEmptyString(next.model)) {
842
+ next.model = DEFAULT_OPENCODE_LOCAL_MODEL;
843
+ return ensureGatewayDeviceKey(adapterType, next);
844
+ }
845
+ if (adapterType === "cursor" && !asNonEmptyString(next.model)) {
846
+ next.model = DEFAULT_CURSOR_LOCAL_MODEL;
847
+ }
848
+ return ensureGatewayDeviceKey(adapterType, next);
849
+ }
850
+ async function assertAdapterConfigConstraints(adapterType, adapterConfig) {
851
+ if (adapterType !== "opencode_local")
852
+ return;
853
+ try {
854
+ requireOpenCodeModelId(adapterConfig.model);
855
+ }
856
+ catch (err) {
857
+ const reason = err instanceof Error ? err.message : String(err);
858
+ throw unprocessable(`Invalid opencode_local adapterConfig: ${reason}`);
859
+ }
860
+ }
861
+ function resolveInstructionsFilePath(candidatePath, adapterConfig) {
862
+ const trimmed = candidatePath.trim();
863
+ if (path.isAbsolute(trimmed))
864
+ return trimmed;
865
+ const cwd = asNonEmptyString(adapterConfig.cwd);
866
+ if (!cwd) {
867
+ throw unprocessable("Relative instructions path requires adapterConfig.cwd to be set to an absolute path");
868
+ }
869
+ if (!path.isAbsolute(cwd)) {
870
+ throw unprocessable("adapterConfig.cwd must be an absolute path to resolve relative instructions path");
871
+ }
872
+ return path.resolve(cwd, trimmed);
873
+ }
874
+ async function materializeDefaultInstructionsBundleForNewAgent(agent, input) {
875
+ if (!adapterSupportsInstructionsBundle(agent.adapterType)) {
876
+ return agent;
877
+ }
878
+ const adapterConfig = asRecord(agent.adapterConfig) ?? {};
879
+ const hasExplicitInstructionsBundle = Boolean(asNonEmptyString(adapterConfig.instructionsBundleMode))
880
+ || Boolean(asNonEmptyString(adapterConfig.instructionsRootPath))
881
+ || Boolean(asNonEmptyString(adapterConfig.instructionsEntryFile))
882
+ || Boolean(asNonEmptyString(adapterConfig.instructionsFilePath))
883
+ || Boolean(asNonEmptyString(adapterConfig.agentsMdPath));
884
+ if (hasExplicitInstructionsBundle) {
885
+ const nextAdapterConfig = { ...adapterConfig };
886
+ const hadLegacyPrompt = Object.prototype.hasOwnProperty.call(nextAdapterConfig, "promptTemplate")
887
+ || Object.prototype.hasOwnProperty.call(nextAdapterConfig, "bootstrapPromptTemplate");
888
+ delete nextAdapterConfig.promptTemplate;
889
+ delete nextAdapterConfig.bootstrapPromptTemplate;
890
+ if (!hadLegacyPrompt)
891
+ return agent;
892
+ const updated = await svc.update(agent.id, { adapterConfig: nextAdapterConfig });
893
+ return updated ?? { ...agent, adapterConfig: nextAdapterConfig };
894
+ }
895
+ const files = input?.files
896
+ ?? await loadDefaultAgentInstructionsBundle(resolveDefaultAgentInstructionsBundleRole(agent.role));
897
+ const materialized = await instructions.materializeManagedBundle(agent, files, { entryFile: input?.entryFile ?? "AGENTS.md", replaceExisting: false });
898
+ const nextAdapterConfig = { ...materialized.adapterConfig };
899
+ delete nextAdapterConfig.promptTemplate;
900
+ delete nextAdapterConfig.bootstrapPromptTemplate;
901
+ const updated = await svc.update(agent.id, { adapterConfig: nextAdapterConfig });
902
+ return updated ?? { ...agent, adapterConfig: nextAdapterConfig };
903
+ }
904
+ function assertNoNewAgentLegacyPromptTemplate(adapterType, adapterConfig) {
905
+ if (!adapterSupportsInstructionsBundle(adapterType))
906
+ return;
907
+ if (Object.prototype.hasOwnProperty.call(adapterConfig, "promptTemplate")
908
+ || Object.prototype.hasOwnProperty.call(adapterConfig, "bootstrapPromptTemplate")) {
909
+ throw unprocessable("New agents must use instructionsBundle/AGENTS.md instead of adapterConfig.promptTemplate or bootstrapPromptTemplate");
910
+ }
911
+ }
912
+ async function assertCanManageInstructionsPath(req, targetAgent) {
913
+ assertCompanyAccess(req, targetAgent.companyId);
914
+ if (req.actor.type !== "board") {
915
+ throw forbidden("Only board-authenticated callers can manage instructions path or bundle configuration");
916
+ }
917
+ await assertBoardCanManageAgentsForCompany(req, targetAgent.companyId);
918
+ }
919
+ function assertNoAgentInstructionsConfigMutation(req, adapterConfig, path = "adapterConfig") {
920
+ if (req.actor.type !== "agent" || !adapterConfig)
921
+ return;
922
+ const changedSensitiveKeys = KNOWN_INSTRUCTIONS_BUNDLE_KEYS
923
+ .filter((key) => adapterConfig[key] !== undefined)
924
+ .map((key) => `${path}.${key}`);
925
+ if (changedSensitiveKeys.length === 0)
926
+ return;
927
+ throw forbidden(`Agent-authenticated callers cannot modify instructions path or bundle configuration (${changedSensitiveKeys.join(", ")})`);
928
+ }
929
+ function adapterConfigTouchesInstructionsConfig(adapterConfig) {
930
+ return KNOWN_INSTRUCTIONS_BUNDLE_KEYS.some((key) => adapterConfig[key] !== undefined);
931
+ }
932
+ function assertNoAgentAdapterConfigMutation(req, adapterConfig, path = "adapterConfig") {
933
+ assertNoAgentInstructionsConfigMutation(req, adapterConfig, path);
934
+ assertNoAgentHostWorkspaceCommandMutation(req, collectAgentAdapterWorkspaceCommandPaths(adapterConfig, path));
935
+ }
936
+ function summarizeAgentUpdateDetails(patch) {
937
+ const changedTopLevelKeys = Object.keys(patch).sort();
938
+ const details = { changedTopLevelKeys };
939
+ const adapterConfigPatch = asRecord(patch.adapterConfig);
940
+ if (adapterConfigPatch) {
941
+ details.changedAdapterConfigKeys = Object.keys(adapterConfigPatch).sort();
942
+ }
943
+ const runtimeConfigPatch = asRecord(patch.runtimeConfig);
944
+ if (runtimeConfigPatch) {
945
+ details.changedRuntimeConfigKeys = Object.keys(runtimeConfigPatch).sort();
946
+ }
947
+ return details;
948
+ }
949
+ function buildUnsupportedSkillSnapshot(adapterType, desiredSkills = []) {
950
+ return {
951
+ adapterType,
952
+ supported: false,
953
+ mode: "unsupported",
954
+ desiredSkills,
955
+ entries: [],
956
+ warnings: ["This adapter does not implement skill sync yet."],
957
+ };
958
+ }
959
+ // Legacy hardcoded set — used as fallback when adapter module does not
960
+ // declare requiresMaterializedRuntimeSkills explicitly.
961
+ const LEGACY_MATERIALIZED_SKILLS_SET = new Set([
962
+ "cursor",
963
+ "gemini_local",
964
+ "opencode_local",
965
+ "pi_local",
966
+ ]);
967
+ function shouldMaterializeRuntimeSkillsForAdapter(adapterType) {
968
+ const adapter = findActiveServerAdapter(adapterType);
969
+ if (adapter?.requiresMaterializedRuntimeSkills !== undefined) {
970
+ return adapter.requiresMaterializedRuntimeSkills;
971
+ }
972
+ return LEGACY_MATERIALIZED_SKILLS_SET.has(adapterType);
973
+ }
974
+ async function buildRuntimeSkillConfig(companyId, adapterType, config) {
975
+ const runtimeSkillEntries = await companySkills.listRuntimeSkillEntries(companyId, {
976
+ materializeMissing: shouldMaterializeRuntimeSkillsForAdapter(adapterType),
977
+ });
978
+ return {
979
+ ...config,
980
+ evermoreRuntimeSkills: runtimeSkillEntries,
981
+ };
982
+ }
983
+ async function resolveDesiredSkillAssignment(companyId, adapterType, adapterConfig, requestedDesiredSkills) {
984
+ if (!requestedDesiredSkills) {
985
+ return {
986
+ adapterConfig,
987
+ desiredSkills: null,
988
+ runtimeSkillEntries: null,
989
+ };
990
+ }
991
+ const resolvedRequestedSkills = await companySkills.resolveRequestedSkillKeys(companyId, requestedDesiredSkills);
992
+ const runtimeSkillEntries = await companySkills.listRuntimeSkillEntries(companyId, {
993
+ materializeMissing: shouldMaterializeRuntimeSkillsForAdapter(adapterType),
994
+ });
995
+ const requiredSkills = runtimeSkillEntries
996
+ .filter((entry) => entry.required)
997
+ .map((entry) => entry.key);
998
+ const desiredSkills = Array.from(new Set([...requiredSkills, ...resolvedRequestedSkills]));
999
+ return {
1000
+ adapterConfig: writeEvermoreSkillSyncPreference(adapterConfig, desiredSkills),
1001
+ desiredSkills,
1002
+ runtimeSkillEntries,
1003
+ };
1004
+ }
1005
+ function redactForRestrictedAgentView(agent) {
1006
+ if (!agent)
1007
+ return null;
1008
+ return {
1009
+ ...agent,
1010
+ adapterConfig: {},
1011
+ runtimeConfig: {},
1012
+ };
1013
+ }
1014
+ function redactAgentConfiguration(agent) {
1015
+ if (!agent)
1016
+ return null;
1017
+ return {
1018
+ id: agent.id,
1019
+ companyId: agent.companyId,
1020
+ name: agent.name,
1021
+ role: agent.role,
1022
+ title: agent.title,
1023
+ status: agent.status,
1024
+ reportsTo: agent.reportsTo,
1025
+ adapterType: agent.adapterType,
1026
+ adapterConfig: redactEventPayload(agent.adapterConfig),
1027
+ runtimeConfig: redactEventPayload(agent.runtimeConfig),
1028
+ permissions: agent.permissions,
1029
+ updatedAt: agent.updatedAt,
1030
+ };
1031
+ }
1032
+ function redactRevisionSnapshot(snapshot) {
1033
+ if (!snapshot || typeof snapshot !== "object" || Array.isArray(snapshot))
1034
+ return {};
1035
+ const record = snapshot;
1036
+ return {
1037
+ ...record,
1038
+ adapterConfig: redactEventPayload(typeof record.adapterConfig === "object" && record.adapterConfig !== null
1039
+ ? record.adapterConfig
1040
+ : {}),
1041
+ runtimeConfig: redactEventPayload(typeof record.runtimeConfig === "object" && record.runtimeConfig !== null
1042
+ ? record.runtimeConfig
1043
+ : {}),
1044
+ metadata: typeof record.metadata === "object" && record.metadata !== null
1045
+ ? redactEventPayload(record.metadata)
1046
+ : record.metadata ?? null,
1047
+ };
1048
+ }
1049
+ function redactConfigRevision(revision) {
1050
+ return {
1051
+ ...revision,
1052
+ beforeConfig: redactRevisionSnapshot(revision.beforeConfig),
1053
+ afterConfig: redactRevisionSnapshot(revision.afterConfig),
1054
+ };
1055
+ }
1056
+ function toLeanOrgNode(node) {
1057
+ const reports = Array.isArray(node.reports)
1058
+ ? node.reports.map((report) => toLeanOrgNode(report))
1059
+ : [];
1060
+ return {
1061
+ id: String(node.id),
1062
+ name: String(node.name),
1063
+ role: String(node.role),
1064
+ status: String(node.status),
1065
+ reports,
1066
+ };
1067
+ }
1068
+ router.param("id", async (req, _res, next, rawId) => {
1069
+ try {
1070
+ req.params.id = await normalizeAgentReference(req, String(rawId));
1071
+ next();
1072
+ }
1073
+ catch (err) {
1074
+ next(err);
1075
+ }
1076
+ });
1077
+ router.get("/companies/:companyId/adapters/:type/models", async (req, res) => {
1078
+ const companyId = req.params.companyId;
1079
+ assertCompanyAccess(req, companyId);
1080
+ const type = assertKnownAdapterType(req.params.type);
1081
+ const refresh = typeof req.query.refresh === "string"
1082
+ ? ["1", "true", "yes"].includes(req.query.refresh.toLowerCase())
1083
+ : false;
1084
+ const environmentId = asNonEmptyString(req.query.environmentId);
1085
+ const environment = environmentId ? await environmentsSvc.getById(environmentId) : null;
1086
+ if (environmentId && (!environment || environment.companyId !== companyId)) {
1087
+ res.status(404).json({ error: "Environment not found" });
1088
+ return;
1089
+ }
1090
+ if (type === "opencode_local" && environment && environment.driver !== "local") {
1091
+ const adapter = requireServerAdapter(type);
1092
+ res.json(adapter.models ?? []);
1093
+ return;
1094
+ }
1095
+ const models = refresh
1096
+ ? await refreshAdapterModels(type)
1097
+ : await listAdapterModels(type);
1098
+ res.json(models);
1099
+ });
1100
+ router.get("/companies/:companyId/adapters/:type/model-profiles", async (req, res) => {
1101
+ const companyId = req.params.companyId;
1102
+ assertCompanyAccess(req, companyId);
1103
+ const type = assertKnownAdapterType(req.params.type);
1104
+ const profiles = await listAdapterModelProfiles(type);
1105
+ res.json(profiles);
1106
+ });
1107
+ router.get("/companies/:companyId/adapters/:type/detect-model", async (req, res) => {
1108
+ const companyId = req.params.companyId;
1109
+ assertCompanyAccess(req, companyId);
1110
+ const type = assertKnownAdapterType(req.params.type);
1111
+ const detected = await detectAdapterModel(type);
1112
+ res.json(detected);
1113
+ });
1114
+ router.post("/companies/:companyId/adapters/:type/test-environment", validate(testAdapterEnvironmentSchema), async (req, res) => {
1115
+ const companyId = req.params.companyId;
1116
+ const type = assertKnownAdapterType(req.params.type);
1117
+ await assertCanReadConfigurations(req, companyId);
1118
+ const adapter = requireServerAdapter(type);
1119
+ const inputAdapterConfig = (req.body?.adapterConfig ?? {});
1120
+ const requestedEnvironmentId = typeof req.body?.environmentId === "string" && req.body.environmentId.trim().length > 0
1121
+ ? req.body.environmentId
1122
+ : null;
1123
+ const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(companyId, inputAdapterConfig, { strictMode: strictSecretsMode });
1124
+ const { config: runtimeAdapterConfig } = await secretsSvc.resolveAdapterConfigForRuntime(companyId, normalizedAdapterConfig);
1125
+ const { executionTarget, environmentName, fallbackChecks, release } = await resolveAdapterTestExecutionContext({
1126
+ companyId,
1127
+ adapterType: type,
1128
+ environmentId: requestedEnvironmentId,
1129
+ });
1130
+ let releaseStatus = "released";
1131
+ try {
1132
+ // If the caller explicitly selected an environment, never fall back to
1133
+ // probing the host when we couldn't resolve that environment's
1134
+ // execution target. Surface the diagnostic checks instead.
1135
+ if (requestedEnvironmentId && !executionTarget && fallbackChecks.length > 0) {
1136
+ const status = fallbackChecks.some((c) => c.level === "error")
1137
+ ? "fail"
1138
+ : fallbackChecks.some((c) => c.level === "warn")
1139
+ ? "warn"
1140
+ : "pass";
1141
+ if (status === "fail")
1142
+ releaseStatus = "failed";
1143
+ const synthesized = {
1144
+ adapterType: type,
1145
+ status,
1146
+ checks: fallbackChecks,
1147
+ testedAt: new Date().toISOString(),
1148
+ };
1149
+ res.json(synthesized);
1150
+ return;
1151
+ }
1152
+ const result = await adapter.testEnvironment({
1153
+ companyId,
1154
+ adapterType: type,
1155
+ config: runtimeAdapterConfig,
1156
+ executionTarget,
1157
+ environmentName,
1158
+ });
1159
+ if (result.status === "fail")
1160
+ releaseStatus = "failed";
1161
+ res.json(result);
1162
+ }
1163
+ catch (err) {
1164
+ releaseStatus = "failed";
1165
+ throw err;
1166
+ }
1167
+ finally {
1168
+ await release(releaseStatus);
1169
+ }
1170
+ });
1171
+ router.get("/agents/:id/skills", async (req, res) => {
1172
+ const id = req.params.id;
1173
+ const agent = await svc.getById(id);
1174
+ if (!agent) {
1175
+ res.status(404).json({ error: "Agent not found" });
1176
+ return;
1177
+ }
1178
+ await assertCanReadConfigurations(req, agent.companyId);
1179
+ const adapter = findActiveServerAdapter(agent.adapterType);
1180
+ if (!adapter?.listSkills) {
1181
+ const preference = readEvermoreSkillSyncPreference(agent.adapterConfig);
1182
+ const runtimeSkillEntries = await companySkills.listRuntimeSkillEntries(agent.companyId, {
1183
+ materializeMissing: false,
1184
+ });
1185
+ const requiredSkills = runtimeSkillEntries.filter((entry) => entry.required).map((entry) => entry.key);
1186
+ res.json(buildUnsupportedSkillSnapshot(agent.adapterType, Array.from(new Set([...requiredSkills, ...preference.desiredSkills]))));
1187
+ return;
1188
+ }
1189
+ const { config: runtimeConfig } = await secretsSvc.resolveAdapterConfigForRuntime(agent.companyId, agent.adapterConfig);
1190
+ const runtimeSkillConfig = await buildRuntimeSkillConfig(agent.companyId, agent.adapterType, runtimeConfig);
1191
+ const snapshot = await adapter.listSkills({
1192
+ agentId: agent.id,
1193
+ companyId: agent.companyId,
1194
+ adapterType: agent.adapterType,
1195
+ config: runtimeSkillConfig,
1196
+ });
1197
+ res.json(snapshot);
1198
+ });
1199
+ router.post("/agents/:id/skills/sync", validate(agentSkillSyncSchema), async (req, res) => {
1200
+ const id = req.params.id;
1201
+ const agent = await svc.getById(id);
1202
+ if (!agent) {
1203
+ res.status(404).json({ error: "Agent not found" });
1204
+ return;
1205
+ }
1206
+ await assertCanUpdateAgent(req, agent);
1207
+ const requestedSkills = Array.from(new Set(req.body.desiredSkills
1208
+ .map((value) => value.trim())
1209
+ .filter(Boolean)));
1210
+ const { adapterConfig: nextAdapterConfig, desiredSkills, runtimeSkillEntries, } = await resolveDesiredSkillAssignment(agent.companyId, agent.adapterType, agent.adapterConfig, requestedSkills);
1211
+ if (!desiredSkills || !runtimeSkillEntries) {
1212
+ throw unprocessable("Skill sync requires desiredSkills.");
1213
+ }
1214
+ const actor = getActorInfo(req);
1215
+ const updated = await svc.update(agent.id, {
1216
+ adapterConfig: nextAdapterConfig,
1217
+ }, {
1218
+ recordRevision: {
1219
+ createdByAgentId: actor.agentId,
1220
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
1221
+ source: "skill-sync",
1222
+ },
1223
+ });
1224
+ if (!updated) {
1225
+ res.status(404).json({ error: "Agent not found" });
1226
+ return;
1227
+ }
1228
+ const adapter = findActiveServerAdapter(updated.adapterType);
1229
+ const { config: runtimeConfig } = await secretsSvc.resolveAdapterConfigForRuntime(updated.companyId, updated.adapterConfig);
1230
+ const runtimeSkillConfig = {
1231
+ ...runtimeConfig,
1232
+ evermoreRuntimeSkills: runtimeSkillEntries,
1233
+ };
1234
+ const snapshot = adapter?.syncSkills
1235
+ ? await adapter.syncSkills({
1236
+ agentId: updated.id,
1237
+ companyId: updated.companyId,
1238
+ adapterType: updated.adapterType,
1239
+ config: runtimeSkillConfig,
1240
+ }, desiredSkills)
1241
+ : adapter?.listSkills
1242
+ ? await adapter.listSkills({
1243
+ agentId: updated.id,
1244
+ companyId: updated.companyId,
1245
+ adapterType: updated.adapterType,
1246
+ config: runtimeSkillConfig,
1247
+ })
1248
+ : buildUnsupportedSkillSnapshot(updated.adapterType, desiredSkills);
1249
+ await logActivity(db, {
1250
+ companyId: updated.companyId,
1251
+ actorType: actor.actorType,
1252
+ actorId: actor.actorId,
1253
+ action: "agent.skills_synced",
1254
+ entityType: "agent",
1255
+ entityId: updated.id,
1256
+ agentId: actor.agentId,
1257
+ runId: actor.runId,
1258
+ details: {
1259
+ adapterType: updated.adapterType,
1260
+ desiredSkills,
1261
+ mode: snapshot.mode,
1262
+ supported: snapshot.supported,
1263
+ entryCount: snapshot.entries.length,
1264
+ warningCount: snapshot.warnings.length,
1265
+ },
1266
+ });
1267
+ res.json(snapshot);
1268
+ });
1269
+ router.get("/companies/:companyId/agents", async (req, res) => {
1270
+ const companyId = req.params.companyId;
1271
+ assertCompanyAccess(req, companyId);
1272
+ const unsupportedQueryParams = Object.keys(req.query).sort();
1273
+ if (unsupportedQueryParams.length > 0) {
1274
+ res.status(400).json({
1275
+ error: `Unsupported query parameter${unsupportedQueryParams.length === 1 ? "" : "s"}: ${unsupportedQueryParams.join(", ")}`,
1276
+ });
1277
+ return;
1278
+ }
1279
+ const result = await svc.list(companyId);
1280
+ const canReadConfigs = await actorCanReadConfigurationsForCompany(req, companyId);
1281
+ if (canReadConfigs) {
1282
+ res.json(result);
1283
+ return;
1284
+ }
1285
+ res.json(result.map((agent) => redactForRestrictedAgentView(agent)));
1286
+ });
1287
+ router.get("/instance/scheduler-heartbeats", async (req, res) => {
1288
+ assertInstanceAdmin(req);
1289
+ const rows = await db
1290
+ .select({
1291
+ id: agentsTable.id,
1292
+ companyId: agentsTable.companyId,
1293
+ agentName: agentsTable.name,
1294
+ role: agentsTable.role,
1295
+ title: agentsTable.title,
1296
+ status: agentsTable.status,
1297
+ adapterType: agentsTable.adapterType,
1298
+ runtimeConfig: agentsTable.runtimeConfig,
1299
+ lastHeartbeatAt: agentsTable.lastHeartbeatAt,
1300
+ companyName: companies.name,
1301
+ companyIssuePrefix: companies.issuePrefix,
1302
+ })
1303
+ .from(agentsTable)
1304
+ .innerJoin(companies, eq(agentsTable.companyId, companies.id))
1305
+ .orderBy(companies.name, agentsTable.name);
1306
+ const items = rows
1307
+ .map((row) => {
1308
+ const policy = parseSchedulerHeartbeatPolicy(row.runtimeConfig);
1309
+ const statusEligible = row.status !== "paused" &&
1310
+ row.status !== "terminated" &&
1311
+ row.status !== "pending_approval";
1312
+ return {
1313
+ id: row.id,
1314
+ companyId: row.companyId,
1315
+ companyName: row.companyName,
1316
+ companyIssuePrefix: row.companyIssuePrefix,
1317
+ agentName: row.agentName,
1318
+ agentUrlKey: deriveAgentUrlKey(row.agentName, row.id),
1319
+ role: row.role,
1320
+ title: row.title,
1321
+ status: row.status,
1322
+ adapterType: row.adapterType,
1323
+ intervalSec: policy.intervalSec,
1324
+ heartbeatEnabled: policy.enabled,
1325
+ schedulerActive: statusEligible && policy.enabled && policy.intervalSec > 0,
1326
+ lastHeartbeatAt: row.lastHeartbeatAt,
1327
+ };
1328
+ })
1329
+ .filter((item) => item.status !== "paused" &&
1330
+ item.status !== "terminated" &&
1331
+ item.status !== "pending_approval")
1332
+ .sort((left, right) => {
1333
+ if (left.schedulerActive !== right.schedulerActive) {
1334
+ return left.schedulerActive ? -1 : 1;
1335
+ }
1336
+ const companyOrder = left.companyName.localeCompare(right.companyName);
1337
+ if (companyOrder !== 0)
1338
+ return companyOrder;
1339
+ return left.agentName.localeCompare(right.agentName);
1340
+ });
1341
+ res.json(items);
1342
+ });
1343
+ router.get("/companies/:companyId/org", async (req, res) => {
1344
+ const companyId = req.params.companyId;
1345
+ assertCompanyAccess(req, companyId);
1346
+ const tree = await svc.orgForCompany(companyId);
1347
+ const leanTree = tree.map((node) => toLeanOrgNode(node));
1348
+ res.json(leanTree);
1349
+ });
1350
+ router.get("/companies/:companyId/org.svg", async (req, res) => {
1351
+ const companyId = req.params.companyId;
1352
+ assertCompanyAccess(req, companyId);
1353
+ const style = (ORG_CHART_STYLES.includes(req.query.style) ? req.query.style : "warmth");
1354
+ const tree = await svc.orgForCompany(companyId);
1355
+ const leanTree = tree.map((node) => toLeanOrgNode(node));
1356
+ const svg = renderOrgChartSvg(leanTree, style);
1357
+ res.setHeader("Content-Type", "image/svg+xml");
1358
+ res.setHeader("Cache-Control", "no-cache");
1359
+ res.send(svg);
1360
+ });
1361
+ router.get("/companies/:companyId/org.png", async (req, res) => {
1362
+ const companyId = req.params.companyId;
1363
+ assertCompanyAccess(req, companyId);
1364
+ const style = (ORG_CHART_STYLES.includes(req.query.style) ? req.query.style : "warmth");
1365
+ const tree = await svc.orgForCompany(companyId);
1366
+ const leanTree = tree.map((node) => toLeanOrgNode(node));
1367
+ const png = await renderOrgChartPng(leanTree, style);
1368
+ res.setHeader("Content-Type", "image/png");
1369
+ res.setHeader("Cache-Control", "no-cache");
1370
+ res.send(png);
1371
+ });
1372
+ router.get("/companies/:companyId/agent-configurations", async (req, res) => {
1373
+ const companyId = req.params.companyId;
1374
+ await assertCanReadConfigurations(req, companyId);
1375
+ const rows = await svc.list(companyId);
1376
+ res.json(rows.map((row) => redactAgentConfiguration(row)));
1377
+ });
1378
+ router.get("/agents/me", async (req, res) => {
1379
+ if (req.actor.type !== "agent" || !req.actor.agentId) {
1380
+ res.status(401).json({ error: "Agent authentication required" });
1381
+ return;
1382
+ }
1383
+ const agent = await svc.getById(req.actor.agentId);
1384
+ if (!agent) {
1385
+ res.status(404).json({ error: "Agent not found" });
1386
+ return;
1387
+ }
1388
+ res.json(await buildAgentDetail(agent));
1389
+ });
1390
+ router.get("/agents/me/inbox-lite", async (req, res) => {
1391
+ if (req.actor.type !== "agent" || !req.actor.agentId || !req.actor.companyId) {
1392
+ res.status(401).json({ error: "Agent authentication required" });
1393
+ return;
1394
+ }
1395
+ const issuesSvc = issueService(db);
1396
+ const rows = await issuesSvc.list(req.actor.companyId, {
1397
+ assigneeAgentId: req.actor.agentId,
1398
+ status: "todo,in_progress,blocked",
1399
+ includeRoutineExecutions: true,
1400
+ limit: ISSUE_LIST_DEFAULT_LIMIT,
1401
+ });
1402
+ const dependencyReadiness = await issuesSvc.listDependencyReadiness(req.actor.companyId, rows.map((issue) => issue.id));
1403
+ res.json(rows.map((issue) => ({
1404
+ id: issue.id,
1405
+ identifier: issue.identifier,
1406
+ title: issue.title,
1407
+ status: issue.status,
1408
+ priority: issue.priority,
1409
+ projectId: issue.projectId,
1410
+ goalId: issue.goalId,
1411
+ parentId: issue.parentId,
1412
+ updatedAt: issue.updatedAt,
1413
+ activeRun: issue.activeRun,
1414
+ dependencyReady: dependencyReadiness.get(issue.id)?.isDependencyReady ?? true,
1415
+ unresolvedBlockerCount: dependencyReadiness.get(issue.id)?.unresolvedBlockerCount ?? 0,
1416
+ unresolvedBlockerIssueIds: dependencyReadiness.get(issue.id)?.unresolvedBlockerIssueIds ?? [],
1417
+ })));
1418
+ });
1419
+ router.get("/agents/me/inbox/mine", async (req, res) => {
1420
+ if (req.actor.type !== "agent" || !req.actor.agentId || !req.actor.companyId) {
1421
+ res.status(401).json({ error: "Agent authentication required" });
1422
+ return;
1423
+ }
1424
+ const query = agentMineInboxQuerySchema.parse(req.query);
1425
+ const issuesSvc = issueService(db);
1426
+ const rows = await issuesSvc.list(req.actor.companyId, {
1427
+ touchedByUserId: query.userId,
1428
+ inboxArchivedByUserId: query.userId,
1429
+ status: query.status,
1430
+ limit: ISSUE_LIST_DEFAULT_LIMIT,
1431
+ });
1432
+ res.json(rows);
1433
+ });
1434
+ router.get("/agents/:id", async (req, res) => {
1435
+ const id = req.params.id;
1436
+ const agent = await svc.getById(id);
1437
+ if (!agent) {
1438
+ res.status(404).json({ error: "Agent not found" });
1439
+ return;
1440
+ }
1441
+ assertCompanyAccess(req, agent.companyId);
1442
+ const isSelf = req.actor.type === "agent" && req.actor.agentId === id;
1443
+ const canReadSensitiveDetail = isSelf
1444
+ ? true
1445
+ : await actorCanReadConfigurationsForCompany(req, agent.companyId);
1446
+ if (!canReadSensitiveDetail) {
1447
+ res.json(await buildAgentDetail(agent, { restricted: true }));
1448
+ return;
1449
+ }
1450
+ res.json(await buildAgentDetail(agent));
1451
+ });
1452
+ router.get("/agents/:id/configuration", async (req, res) => {
1453
+ const id = req.params.id;
1454
+ const agent = await svc.getById(id);
1455
+ if (!agent) {
1456
+ res.status(404).json({ error: "Agent not found" });
1457
+ return;
1458
+ }
1459
+ await assertCanReadConfigurations(req, agent.companyId);
1460
+ res.json(redactAgentConfiguration(agent));
1461
+ });
1462
+ router.get("/agents/:id/config-revisions", async (req, res) => {
1463
+ const id = req.params.id;
1464
+ const agent = await svc.getById(id);
1465
+ if (!agent) {
1466
+ res.status(404).json({ error: "Agent not found" });
1467
+ return;
1468
+ }
1469
+ await assertCanReadConfigurations(req, agent.companyId);
1470
+ const revisions = await svc.listConfigRevisions(id);
1471
+ res.json(revisions.map((revision) => redactConfigRevision(revision)));
1472
+ });
1473
+ router.get("/agents/:id/config-revisions/:revisionId", async (req, res) => {
1474
+ const id = req.params.id;
1475
+ const revisionId = req.params.revisionId;
1476
+ const agent = await svc.getById(id);
1477
+ if (!agent) {
1478
+ res.status(404).json({ error: "Agent not found" });
1479
+ return;
1480
+ }
1481
+ await assertCanReadConfigurations(req, agent.companyId);
1482
+ const revision = await svc.getConfigRevision(id, revisionId);
1483
+ if (!revision) {
1484
+ res.status(404).json({ error: "Revision not found" });
1485
+ return;
1486
+ }
1487
+ res.json(redactConfigRevision(revision));
1488
+ });
1489
+ router.post("/agents/:id/config-revisions/:revisionId/rollback", async (req, res) => {
1490
+ const id = req.params.id;
1491
+ const revisionId = req.params.revisionId;
1492
+ const existing = await svc.getById(id);
1493
+ if (!existing) {
1494
+ res.status(404).json({ error: "Agent not found" });
1495
+ return;
1496
+ }
1497
+ await assertCanUpdateAgent(req, existing);
1498
+ const actor = getActorInfo(req);
1499
+ const updated = await svc.rollbackConfigRevision(id, revisionId, {
1500
+ agentId: actor.agentId,
1501
+ userId: actor.actorType === "user" ? actor.actorId : null,
1502
+ });
1503
+ if (!updated) {
1504
+ res.status(404).json({ error: "Revision not found" });
1505
+ return;
1506
+ }
1507
+ await logActivity(db, {
1508
+ companyId: updated.companyId,
1509
+ actorType: actor.actorType,
1510
+ actorId: actor.actorId,
1511
+ agentId: actor.agentId,
1512
+ runId: actor.runId,
1513
+ action: "agent.config_rolled_back",
1514
+ entityType: "agent",
1515
+ entityId: updated.id,
1516
+ details: { revisionId },
1517
+ });
1518
+ res.json(updated);
1519
+ });
1520
+ router.get("/agents/:id/runtime-state", async (req, res) => {
1521
+ assertBoard(req);
1522
+ const id = req.params.id;
1523
+ const agent = await svc.getById(id);
1524
+ if (!agent) {
1525
+ res.status(404).json({ error: "Agent not found" });
1526
+ return;
1527
+ }
1528
+ await assertBoardCanManageAgentsForCompany(req, agent.companyId);
1529
+ assertCompanyAccess(req, agent.companyId);
1530
+ const state = await heartbeat.getRuntimeState(id);
1531
+ res.json(state);
1532
+ });
1533
+ router.get("/agents/:id/task-sessions", async (req, res) => {
1534
+ assertBoard(req);
1535
+ const id = req.params.id;
1536
+ const agent = await svc.getById(id);
1537
+ if (!agent) {
1538
+ res.status(404).json({ error: "Agent not found" });
1539
+ return;
1540
+ }
1541
+ await assertBoardCanManageAgentsForCompany(req, agent.companyId);
1542
+ assertCompanyAccess(req, agent.companyId);
1543
+ const sessions = await heartbeat.listTaskSessions(id);
1544
+ res.json(sessions.map((session) => ({
1545
+ ...session,
1546
+ sessionParamsJson: redactEventPayload(session.sessionParamsJson ?? null),
1547
+ })));
1548
+ });
1549
+ router.post("/agents/:id/runtime-state/reset-session", validate(resetAgentSessionSchema), async (req, res) => {
1550
+ assertBoard(req);
1551
+ const id = req.params.id;
1552
+ const agent = await svc.getById(id);
1553
+ if (!agent) {
1554
+ res.status(404).json({ error: "Agent not found" });
1555
+ return;
1556
+ }
1557
+ await assertBoardCanManageAgentsForCompany(req, agent.companyId);
1558
+ assertCompanyAccess(req, agent.companyId);
1559
+ const taskKey = typeof req.body.taskKey === "string" && req.body.taskKey.trim().length > 0
1560
+ ? req.body.taskKey.trim()
1561
+ : null;
1562
+ const state = await heartbeat.resetRuntimeSession(id, { taskKey });
1563
+ await logActivity(db, {
1564
+ companyId: agent.companyId,
1565
+ actorType: "user",
1566
+ actorId: req.actor.userId ?? "board",
1567
+ action: "agent.runtime_session_reset",
1568
+ entityType: "agent",
1569
+ entityId: id,
1570
+ details: { taskKey: taskKey ?? null },
1571
+ });
1572
+ res.json(state);
1573
+ });
1574
+ router.post("/companies/:companyId/agent-hires", validate(createAgentHireSchema), async (req, res) => {
1575
+ const companyId = req.params.companyId;
1576
+ await assertCanCreateAgentsForCompany(req, companyId);
1577
+ const sourceIssueIds = parseSourceIssueIds(req.body);
1578
+ const { desiredSkills: requestedDesiredSkills, instructionsBundle, sourceIssueId: _sourceIssueId, sourceIssueIds: _sourceIssueIds, ...hireInput } = req.body;
1579
+ hireInput.adapterType = assertKnownAdapterType(hireInput.adapterType);
1580
+ const rawHireAdapterConfig = (hireInput.adapterConfig ?? {});
1581
+ assertNoNewAgentLegacyPromptTemplate(hireInput.adapterType, rawHireAdapterConfig);
1582
+ assertNoAgentAdapterConfigMutation(req, rawHireAdapterConfig);
1583
+ assertNoAgentRuntimeConfigAdapterConfigMutation(req, hireInput.runtimeConfig);
1584
+ const requestedAdapterConfig = applyCreateDefaultsByAdapterType(hireInput.adapterType, rawHireAdapterConfig);
1585
+ const desiredSkillAssignment = await resolveDesiredSkillAssignment(companyId, hireInput.adapterType, requestedAdapterConfig, Array.isArray(requestedDesiredSkills) ? requestedDesiredSkills : undefined);
1586
+ const normalizedAdapterConfig = await normalizeMediatedAdapterConfigForPersistence({
1587
+ companyId,
1588
+ adapterType: hireInput.adapterType,
1589
+ adapterConfig: desiredSkillAssignment.adapterConfig,
1590
+ });
1591
+ const normalizedRuntimeConfig = await normalizeRuntimeConfigAdapterConfigsForPersistence(companyId, hireInput.adapterType, normalizeNewAgentRuntimeConfig(hireInput.runtimeConfig), normalizedAdapterConfig);
1592
+ const normalizedHireInput = {
1593
+ ...hireInput,
1594
+ adapterConfig: normalizedAdapterConfig,
1595
+ runtimeConfig: normalizedRuntimeConfig,
1596
+ };
1597
+ const company = await db
1598
+ .select()
1599
+ .from(companies)
1600
+ .where(eq(companies.id, companyId))
1601
+ .then((rows) => rows[0] ?? null);
1602
+ if (!company) {
1603
+ res.status(404).json({ error: "Company not found" });
1604
+ return;
1605
+ }
1606
+ const requiresApproval = company.requireBoardApprovalForNewAgents;
1607
+ const status = requiresApproval ? "pending_approval" : "idle";
1608
+ const createdAgent = await svc.create(companyId, {
1609
+ ...normalizedHireInput,
1610
+ status,
1611
+ spentMonthlyCents: 0,
1612
+ lastHeartbeatAt: null,
1613
+ });
1614
+ const agent = await materializeDefaultInstructionsBundleForNewAgent(createdAgent, instructionsBundle);
1615
+ let approval = null;
1616
+ const actor = getActorInfo(req);
1617
+ if (requiresApproval) {
1618
+ const requestedAdapterType = normalizedHireInput.adapterType ?? agent.adapterType;
1619
+ const requestedAdapterConfig = redactEventPayload((agent.adapterConfig ?? normalizedHireInput.adapterConfig)) ?? {};
1620
+ const requestedRuntimeConfig = redactEventPayload((normalizedHireInput.runtimeConfig ?? agent.runtimeConfig)) ?? {};
1621
+ const requestedMetadata = redactEventPayload((normalizedHireInput.metadata ?? agent.metadata ?? {})) ?? {};
1622
+ approval = await approvalsSvc.create(companyId, {
1623
+ type: "hire_agent",
1624
+ requestedByAgentId: actor.actorType === "agent" ? actor.actorId : null,
1625
+ requestedByUserId: actor.actorType === "user" ? actor.actorId : null,
1626
+ status: "pending",
1627
+ payload: {
1628
+ name: normalizedHireInput.name,
1629
+ role: normalizedHireInput.role,
1630
+ title: normalizedHireInput.title ?? null,
1631
+ icon: normalizedHireInput.icon ?? null,
1632
+ reportsTo: normalizedHireInput.reportsTo ?? null,
1633
+ capabilities: normalizedHireInput.capabilities ?? null,
1634
+ adapterType: requestedAdapterType,
1635
+ adapterConfig: requestedAdapterConfig,
1636
+ runtimeConfig: requestedRuntimeConfig,
1637
+ budgetMonthlyCents: typeof normalizedHireInput.budgetMonthlyCents === "number"
1638
+ ? normalizedHireInput.budgetMonthlyCents
1639
+ : agent.budgetMonthlyCents,
1640
+ desiredSkills: desiredSkillAssignment.desiredSkills,
1641
+ metadata: requestedMetadata,
1642
+ agentId: agent.id,
1643
+ requestedByAgentId: actor.actorType === "agent" ? actor.actorId : null,
1644
+ requestedConfigurationSnapshot: {
1645
+ adapterType: requestedAdapterType,
1646
+ adapterConfig: requestedAdapterConfig,
1647
+ runtimeConfig: requestedRuntimeConfig,
1648
+ desiredSkills: desiredSkillAssignment.desiredSkills,
1649
+ },
1650
+ },
1651
+ decisionNote: null,
1652
+ decidedByUserId: null,
1653
+ decidedAt: null,
1654
+ updatedAt: new Date(),
1655
+ });
1656
+ if (sourceIssueIds.length > 0) {
1657
+ await issueApprovalsSvc.linkManyForApproval(approval.id, sourceIssueIds, {
1658
+ agentId: actor.actorType === "agent" ? actor.actorId : null,
1659
+ userId: actor.actorType === "user" ? actor.actorId : null,
1660
+ });
1661
+ }
1662
+ }
1663
+ await logActivity(db, {
1664
+ companyId,
1665
+ actorType: actor.actorType,
1666
+ actorId: actor.actorId,
1667
+ agentId: actor.agentId,
1668
+ runId: actor.runId,
1669
+ action: "agent.hire_created",
1670
+ entityType: "agent",
1671
+ entityId: agent.id,
1672
+ details: {
1673
+ name: agent.name,
1674
+ role: agent.role,
1675
+ requiresApproval,
1676
+ approvalId: approval?.id ?? null,
1677
+ issueIds: sourceIssueIds,
1678
+ desiredSkills: desiredSkillAssignment.desiredSkills,
1679
+ },
1680
+ });
1681
+ const telemetryClient = getTelemetryClient();
1682
+ if (telemetryClient) {
1683
+ trackAgentCreated(telemetryClient, { agentRole: agent.role, agentId: agent.id });
1684
+ }
1685
+ await applyDefaultAgentTaskAssignGrant(companyId, agent.id, actor.actorType === "user" ? actor.actorId : null);
1686
+ if (approval) {
1687
+ await logActivity(db, {
1688
+ companyId,
1689
+ actorType: actor.actorType,
1690
+ actorId: actor.actorId,
1691
+ agentId: actor.agentId,
1692
+ runId: actor.runId,
1693
+ action: "approval.created",
1694
+ entityType: "approval",
1695
+ entityId: approval.id,
1696
+ details: { type: approval.type, linkedAgentId: agent.id },
1697
+ });
1698
+ }
1699
+ res.status(201).json({ agent, approval });
1700
+ });
1701
+ router.post("/companies/:companyId/agents", validate(createAgentSchema), async (req, res) => {
1702
+ const companyId = req.params.companyId;
1703
+ await assertCanCreateAgentsForCompany(req, companyId);
1704
+ const company = await db
1705
+ .select()
1706
+ .from(companies)
1707
+ .where(eq(companies.id, companyId))
1708
+ .then((rows) => rows[0] ?? null);
1709
+ if (!company) {
1710
+ res.status(404).json({ error: "Company not found" });
1711
+ return;
1712
+ }
1713
+ if (company.requireBoardApprovalForNewAgents) {
1714
+ throw conflict("Direct agent creation requires board approval. Use POST /api/companies/:companyId/agent-hires to create a pending hire approval.");
1715
+ }
1716
+ const { desiredSkills: requestedDesiredSkills, instructionsBundle, ...createInput } = req.body;
1717
+ createInput.adapterType = assertKnownAdapterType(createInput.adapterType);
1718
+ const rawCreateAdapterConfig = (createInput.adapterConfig ?? {});
1719
+ assertNoNewAgentLegacyPromptTemplate(createInput.adapterType, rawCreateAdapterConfig);
1720
+ assertNoAgentAdapterConfigMutation(req, rawCreateAdapterConfig);
1721
+ assertNoAgentRuntimeConfigAdapterConfigMutation(req, createInput.runtimeConfig);
1722
+ const requestedAdapterConfig = applyCreateDefaultsByAdapterType(createInput.adapterType, rawCreateAdapterConfig);
1723
+ const desiredSkillAssignment = await resolveDesiredSkillAssignment(companyId, createInput.adapterType, requestedAdapterConfig, Array.isArray(requestedDesiredSkills) ? requestedDesiredSkills : undefined);
1724
+ const normalizedAdapterConfig = await normalizeMediatedAdapterConfigForPersistence({
1725
+ companyId,
1726
+ adapterType: createInput.adapterType,
1727
+ adapterConfig: desiredSkillAssignment.adapterConfig,
1728
+ });
1729
+ const normalizedRuntimeConfig = await normalizeRuntimeConfigAdapterConfigsForPersistence(companyId, createInput.adapterType, normalizeNewAgentRuntimeConfig(createInput.runtimeConfig), normalizedAdapterConfig);
1730
+ await assertAgentEnvironmentSelection(companyId, createInput.adapterType, createInput.defaultEnvironmentId);
1731
+ await assertAgentDefaultEnvironmentSelection(companyId, createInput.defaultEnvironmentId, {
1732
+ allowedDrivers: allowedEnvironmentDriversForAgent(createInput.adapterType),
1733
+ allowedSandboxProviders: allowedSandboxProvidersForAgent(createInput.adapterType),
1734
+ });
1735
+ const createdAgent = await svc.create(companyId, {
1736
+ ...createInput,
1737
+ adapterConfig: normalizedAdapterConfig,
1738
+ runtimeConfig: normalizedRuntimeConfig,
1739
+ status: "idle",
1740
+ spentMonthlyCents: 0,
1741
+ lastHeartbeatAt: null,
1742
+ });
1743
+ const agent = await materializeDefaultInstructionsBundleForNewAgent(createdAgent, instructionsBundle);
1744
+ const actor = getActorInfo(req);
1745
+ await logActivity(db, {
1746
+ companyId,
1747
+ actorType: actor.actorType,
1748
+ actorId: actor.actorId,
1749
+ agentId: actor.agentId,
1750
+ runId: actor.runId,
1751
+ action: "agent.created",
1752
+ entityType: "agent",
1753
+ entityId: agent.id,
1754
+ details: {
1755
+ name: agent.name,
1756
+ role: agent.role,
1757
+ desiredSkills: desiredSkillAssignment.desiredSkills,
1758
+ },
1759
+ });
1760
+ const telemetryClient = getTelemetryClient();
1761
+ if (telemetryClient) {
1762
+ trackAgentCreated(telemetryClient, { agentRole: agent.role, agentId: agent.id });
1763
+ }
1764
+ await applyDefaultAgentTaskAssignGrant(companyId, agent.id, req.actor.type === "board" ? (req.actor.userId ?? null) : null);
1765
+ if (agent.budgetMonthlyCents > 0) {
1766
+ await budgets.upsertPolicy(companyId, {
1767
+ scopeType: "agent",
1768
+ scopeId: agent.id,
1769
+ amount: agent.budgetMonthlyCents,
1770
+ windowKind: "calendar_month_utc",
1771
+ }, actor.actorType === "user" ? actor.actorId : null);
1772
+ }
1773
+ res.status(201).json(agent);
1774
+ });
1775
+ router.patch("/agents/:id/permissions", validate(updateAgentPermissionsSchema), async (req, res) => {
1776
+ const id = req.params.id;
1777
+ const existing = await svc.getById(id);
1778
+ if (!existing) {
1779
+ res.status(404).json({ error: "Agent not found" });
1780
+ return;
1781
+ }
1782
+ assertCompanyAccess(req, existing.companyId);
1783
+ if (req.actor.type === "agent") {
1784
+ const actorAgent = req.actor.agentId ? await svc.getById(req.actor.agentId) : null;
1785
+ if (!actorAgent || actorAgent.companyId !== existing.companyId) {
1786
+ res.status(403).json({ error: "Forbidden" });
1787
+ return;
1788
+ }
1789
+ if (actorAgent.role !== "ceo") {
1790
+ res.status(403).json({ error: "Only CEO can manage permissions" });
1791
+ return;
1792
+ }
1793
+ }
1794
+ else {
1795
+ await assertBoardCanManageAgentsForCompany(req, existing.companyId);
1796
+ }
1797
+ const agent = await svc.updatePermissions(id, req.body);
1798
+ if (!agent) {
1799
+ res.status(404).json({ error: "Agent not found" });
1800
+ return;
1801
+ }
1802
+ const effectiveCanAssignTasks = agent.role === "ceo" || Boolean(agent.permissions?.canCreateAgents) || req.body.canAssignTasks;
1803
+ await access.ensureMembership(agent.companyId, "agent", agent.id, "member", "active");
1804
+ await access.setPrincipalPermission(agent.companyId, "agent", agent.id, "tasks:assign", effectiveCanAssignTasks, req.actor.type === "board" ? (req.actor.userId ?? null) : null);
1805
+ const actor = getActorInfo(req);
1806
+ await logActivity(db, {
1807
+ companyId: agent.companyId,
1808
+ actorType: actor.actorType,
1809
+ actorId: actor.actorId,
1810
+ agentId: actor.agentId,
1811
+ runId: actor.runId,
1812
+ action: "agent.permissions_updated",
1813
+ entityType: "agent",
1814
+ entityId: agent.id,
1815
+ details: {
1816
+ canCreateAgents: agent.permissions?.canCreateAgents ?? false,
1817
+ canAssignTasks: effectiveCanAssignTasks,
1818
+ },
1819
+ });
1820
+ res.json(await buildAgentDetail(agent));
1821
+ });
1822
+ router.patch("/agents/:id/instructions-path", validate(updateAgentInstructionsPathSchema), async (req, res) => {
1823
+ if (req.actor.type !== "board") {
1824
+ throw forbidden("Only board-authenticated callers can manage instructions path or bundle configuration");
1825
+ }
1826
+ const id = req.params.id;
1827
+ const existing = await svc.getById(id);
1828
+ if (!existing) {
1829
+ res.status(404).json({ error: "Agent not found" });
1830
+ return;
1831
+ }
1832
+ await assertCanManageInstructionsPath(req, existing);
1833
+ const existingAdapterConfig = asRecord(existing.adapterConfig) ?? {};
1834
+ const explicitKey = asNonEmptyString(req.body.adapterConfigKey);
1835
+ const defaultKey = resolveInstructionsPathKey(existing.adapterType);
1836
+ const adapterConfigKey = explicitKey ?? defaultKey;
1837
+ if (!adapterConfigKey) {
1838
+ res.status(422).json({
1839
+ error: `No default instructions path key for adapter type '${existing.adapterType}'. Provide adapterConfigKey.`,
1840
+ });
1841
+ return;
1842
+ }
1843
+ const nextAdapterConfig = { ...existingAdapterConfig };
1844
+ if (req.body.path === null) {
1845
+ delete nextAdapterConfig[adapterConfigKey];
1846
+ }
1847
+ else {
1848
+ nextAdapterConfig[adapterConfigKey] = resolveInstructionsFilePath(req.body.path, existingAdapterConfig);
1849
+ }
1850
+ const syncedAdapterConfig = syncInstructionsBundleConfigFromFilePath(existing, nextAdapterConfig);
1851
+ const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(existing.companyId, syncedAdapterConfig, { strictMode: strictSecretsMode });
1852
+ const actor = getActorInfo(req);
1853
+ const agent = await svc.update(id, { adapterConfig: normalizedAdapterConfig }, {
1854
+ recordRevision: {
1855
+ createdByAgentId: actor.agentId,
1856
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
1857
+ source: "instructions_path_patch",
1858
+ },
1859
+ });
1860
+ if (!agent) {
1861
+ res.status(404).json({ error: "Agent not found" });
1862
+ return;
1863
+ }
1864
+ const updatedAdapterConfig = asRecord(agent.adapterConfig) ?? {};
1865
+ const pathValue = asNonEmptyString(updatedAdapterConfig[adapterConfigKey]);
1866
+ await logActivity(db, {
1867
+ companyId: agent.companyId,
1868
+ actorType: actor.actorType,
1869
+ actorId: actor.actorId,
1870
+ agentId: actor.agentId,
1871
+ runId: actor.runId,
1872
+ action: "agent.instructions_path_updated",
1873
+ entityType: "agent",
1874
+ entityId: agent.id,
1875
+ details: {
1876
+ adapterConfigKey,
1877
+ path: pathValue,
1878
+ cleared: req.body.path === null,
1879
+ },
1880
+ });
1881
+ res.json({
1882
+ agentId: agent.id,
1883
+ adapterType: agent.adapterType,
1884
+ adapterConfigKey,
1885
+ path: pathValue,
1886
+ });
1887
+ });
1888
+ router.get("/agents/:id/instructions-bundle", async (req, res) => {
1889
+ const id = req.params.id;
1890
+ const existing = await svc.getById(id);
1891
+ if (!existing) {
1892
+ res.status(404).json({ error: "Agent not found" });
1893
+ return;
1894
+ }
1895
+ await assertCanReadAgent(req, existing);
1896
+ res.json(await instructions.getBundle(existing));
1897
+ });
1898
+ router.patch("/agents/:id/instructions-bundle", validate(updateAgentInstructionsBundleSchema), async (req, res) => {
1899
+ const id = req.params.id;
1900
+ const existing = await svc.getById(id);
1901
+ if (!existing) {
1902
+ res.status(404).json({ error: "Agent not found" });
1903
+ return;
1904
+ }
1905
+ await assertCanManageInstructionsPath(req, existing);
1906
+ const actor = getActorInfo(req);
1907
+ const { bundle, adapterConfig } = await instructions.updateBundle(existing, req.body);
1908
+ const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(existing.companyId, adapterConfig, { strictMode: strictSecretsMode });
1909
+ await svc.update(id, { adapterConfig: normalizedAdapterConfig }, {
1910
+ recordRevision: {
1911
+ createdByAgentId: actor.agentId,
1912
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
1913
+ source: "instructions_bundle_patch",
1914
+ },
1915
+ });
1916
+ await logActivity(db, {
1917
+ companyId: existing.companyId,
1918
+ actorType: actor.actorType,
1919
+ actorId: actor.actorId,
1920
+ agentId: actor.agentId,
1921
+ runId: actor.runId,
1922
+ action: "agent.instructions_bundle_updated",
1923
+ entityType: "agent",
1924
+ entityId: existing.id,
1925
+ details: {
1926
+ mode: bundle.mode,
1927
+ rootPath: bundle.rootPath,
1928
+ entryFile: bundle.entryFile,
1929
+ clearLegacyPromptTemplate: req.body.clearLegacyPromptTemplate === true,
1930
+ },
1931
+ });
1932
+ res.json(bundle);
1933
+ });
1934
+ router.get("/agents/:id/instructions-bundle/file", async (req, res) => {
1935
+ const id = req.params.id;
1936
+ const existing = await svc.getById(id);
1937
+ if (!existing) {
1938
+ res.status(404).json({ error: "Agent not found" });
1939
+ return;
1940
+ }
1941
+ await assertCanReadAgent(req, existing);
1942
+ const relativePath = typeof req.query.path === "string" ? req.query.path : "";
1943
+ if (!relativePath.trim()) {
1944
+ res.status(422).json({ error: "Query parameter 'path' is required" });
1945
+ return;
1946
+ }
1947
+ res.json(await instructions.readFile(existing, relativePath));
1948
+ });
1949
+ router.put("/agents/:id/instructions-bundle/file", validate(upsertAgentInstructionsFileSchema), async (req, res) => {
1950
+ const id = req.params.id;
1951
+ const existing = await svc.getById(id);
1952
+ if (!existing) {
1953
+ res.status(404).json({ error: "Agent not found" });
1954
+ return;
1955
+ }
1956
+ await assertCanManageInstructionsPath(req, existing);
1957
+ const actor = getActorInfo(req);
1958
+ const result = await instructions.writeFile(existing, req.body.path, req.body.content, {
1959
+ clearLegacyPromptTemplate: req.body.clearLegacyPromptTemplate,
1960
+ });
1961
+ const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(existing.companyId, result.adapterConfig, { strictMode: strictSecretsMode });
1962
+ await svc.update(id, { adapterConfig: normalizedAdapterConfig }, {
1963
+ recordRevision: {
1964
+ createdByAgentId: actor.agentId,
1965
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
1966
+ source: "instructions_bundle_file_put",
1967
+ },
1968
+ });
1969
+ await logActivity(db, {
1970
+ companyId: existing.companyId,
1971
+ actorType: actor.actorType,
1972
+ actorId: actor.actorId,
1973
+ agentId: actor.agentId,
1974
+ runId: actor.runId,
1975
+ action: "agent.instructions_file_updated",
1976
+ entityType: "agent",
1977
+ entityId: existing.id,
1978
+ details: {
1979
+ path: result.file.path,
1980
+ size: result.file.size,
1981
+ clearLegacyPromptTemplate: req.body.clearLegacyPromptTemplate === true,
1982
+ },
1983
+ });
1984
+ res.json(result.file);
1985
+ });
1986
+ router.delete("/agents/:id/instructions-bundle/file", async (req, res) => {
1987
+ const id = req.params.id;
1988
+ const existing = await svc.getById(id);
1989
+ if (!existing) {
1990
+ res.status(404).json({ error: "Agent not found" });
1991
+ return;
1992
+ }
1993
+ await assertCanManageInstructionsPath(req, existing);
1994
+ const relativePath = typeof req.query.path === "string" ? req.query.path : "";
1995
+ if (!relativePath.trim()) {
1996
+ res.status(422).json({ error: "Query parameter 'path' is required" });
1997
+ return;
1998
+ }
1999
+ const actor = getActorInfo(req);
2000
+ const result = await instructions.deleteFile(existing, relativePath);
2001
+ await logActivity(db, {
2002
+ companyId: existing.companyId,
2003
+ actorType: actor.actorType,
2004
+ actorId: actor.actorId,
2005
+ agentId: actor.agentId,
2006
+ runId: actor.runId,
2007
+ action: "agent.instructions_file_deleted",
2008
+ entityType: "agent",
2009
+ entityId: existing.id,
2010
+ details: {
2011
+ path: relativePath,
2012
+ },
2013
+ });
2014
+ res.json(result.bundle);
2015
+ });
2016
+ router.patch("/agents/:id", validate(updateAgentSchema), async (req, res) => {
2017
+ const id = req.params.id;
2018
+ const existing = await svc.getById(id);
2019
+ if (!existing) {
2020
+ res.status(404).json({ error: "Agent not found" });
2021
+ return;
2022
+ }
2023
+ await assertCanUpdateAgent(req, existing);
2024
+ if (hasOwn(req.body, "permissions")) {
2025
+ res.status(422).json({ error: "Use /api/agents/:id/permissions for permission changes" });
2026
+ return;
2027
+ }
2028
+ const patchData = { ...req.body };
2029
+ const replaceAdapterConfig = patchData.replaceAdapterConfig === true;
2030
+ delete patchData.replaceAdapterConfig;
2031
+ if (hasOwn(patchData, "adapterConfig")) {
2032
+ const adapterConfig = asRecord(patchData.adapterConfig);
2033
+ if (!adapterConfig) {
2034
+ res.status(422).json({ error: "adapterConfig must be an object" });
2035
+ return;
2036
+ }
2037
+ assertNoAgentAdapterConfigMutation(req, adapterConfig);
2038
+ const changingInstructionsConfig = adapterConfigTouchesInstructionsConfig(adapterConfig);
2039
+ if (changingInstructionsConfig) {
2040
+ await assertCanManageInstructionsPath(req, existing);
2041
+ }
2042
+ patchData.adapterConfig = adapterConfig;
2043
+ }
2044
+ const requestedAdapterType = hasOwn(patchData, "adapterType")
2045
+ ? assertKnownAdapterType(patchData.adapterType)
2046
+ : existing.adapterType;
2047
+ let requestedRuntimeConfig = null;
2048
+ if (hasOwn(patchData, "runtimeConfig")) {
2049
+ const runtimeConfig = asRecord(patchData.runtimeConfig);
2050
+ if (!runtimeConfig) {
2051
+ res.status(422).json({ error: "runtimeConfig must be an object" });
2052
+ return;
2053
+ }
2054
+ assertNoAgentRuntimeConfigAdapterConfigMutation(req, runtimeConfig);
2055
+ requestedRuntimeConfig = runtimeConfig;
2056
+ }
2057
+ const touchesAdapterConfiguration = hasOwn(patchData, "adapterType") ||
2058
+ hasOwn(patchData, "adapterConfig");
2059
+ if (touchesAdapterConfiguration) {
2060
+ const existingAdapterConfig = asRecord(existing.adapterConfig) ?? {};
2061
+ const changingAdapterType = typeof patchData.adapterType === "string" && patchData.adapterType !== existing.adapterType;
2062
+ const requestedAdapterConfig = hasOwn(patchData, "adapterConfig")
2063
+ ? (asRecord(patchData.adapterConfig) ?? {})
2064
+ : null;
2065
+ if (requestedAdapterConfig
2066
+ && replaceAdapterConfig
2067
+ && KNOWN_INSTRUCTIONS_BUNDLE_KEYS.some((key) => existingAdapterConfig[key] !== undefined && requestedAdapterConfig[key] === undefined)) {
2068
+ await assertCanManageInstructionsPath(req, existing);
2069
+ }
2070
+ let rawEffectiveAdapterConfig = requestedAdapterConfig ?? existingAdapterConfig;
2071
+ if (requestedAdapterConfig && !changingAdapterType && !replaceAdapterConfig) {
2072
+ rawEffectiveAdapterConfig = { ...existingAdapterConfig, ...requestedAdapterConfig };
2073
+ }
2074
+ if (changingAdapterType) {
2075
+ // Preserve adapter-agnostic keys (env, cwd, etc.) from the existing config
2076
+ // when the adapter type changes. Without this, a PATCH that includes
2077
+ // adapterConfig but omits these keys would silently drop them.
2078
+ const ADAPTER_AGNOSTIC_KEYS = [
2079
+ "env", "cwd", "timeoutSec", "graceSec",
2080
+ "promptTemplate", "bootstrapPromptTemplate",
2081
+ ];
2082
+ for (const key of ADAPTER_AGNOSTIC_KEYS) {
2083
+ if (rawEffectiveAdapterConfig[key] === undefined && existingAdapterConfig[key] !== undefined) {
2084
+ rawEffectiveAdapterConfig = { ...rawEffectiveAdapterConfig, [key]: existingAdapterConfig[key] };
2085
+ }
2086
+ }
2087
+ rawEffectiveAdapterConfig = preserveInstructionsBundleConfig(existingAdapterConfig, rawEffectiveAdapterConfig);
2088
+ }
2089
+ const effectiveAdapterConfig = applyCreateDefaultsByAdapterType(requestedAdapterType, rawEffectiveAdapterConfig);
2090
+ const normalizedEffectiveAdapterConfig = await normalizeMediatedAdapterConfigForPersistence({
2091
+ companyId: existing.companyId,
2092
+ adapterType: requestedAdapterType,
2093
+ adapterConfig: effectiveAdapterConfig,
2094
+ });
2095
+ patchData.adapterConfig = syncInstructionsBundleConfigFromFilePath(existing, normalizedEffectiveAdapterConfig);
2096
+ }
2097
+ if (requestedRuntimeConfig) {
2098
+ const baseAdapterConfig = asRecord(patchData.adapterConfig) ?? asRecord(existing.adapterConfig) ?? {};
2099
+ patchData.runtimeConfig = await normalizeRuntimeConfigAdapterConfigsForPersistence(existing.companyId, requestedAdapterType, requestedRuntimeConfig, baseAdapterConfig);
2100
+ }
2101
+ if (touchesAdapterConfiguration || Object.prototype.hasOwnProperty.call(patchData, "defaultEnvironmentId")) {
2102
+ await assertAgentDefaultEnvironmentSelection(existing.companyId, Object.prototype.hasOwnProperty.call(patchData, "defaultEnvironmentId")
2103
+ ? (typeof patchData.defaultEnvironmentId === "string" ? patchData.defaultEnvironmentId : null)
2104
+ : existing.defaultEnvironmentId, {
2105
+ allowedDrivers: allowedEnvironmentDriversForAgent(requestedAdapterType),
2106
+ allowedSandboxProviders: allowedSandboxProvidersForAgent(requestedAdapterType),
2107
+ });
2108
+ }
2109
+ const actor = getActorInfo(req);
2110
+ const agent = await svc.update(id, patchData, {
2111
+ recordRevision: {
2112
+ createdByAgentId: actor.agentId,
2113
+ createdByUserId: actor.actorType === "user" ? actor.actorId : null,
2114
+ source: "patch",
2115
+ },
2116
+ });
2117
+ if (!agent) {
2118
+ res.status(404).json({ error: "Agent not found" });
2119
+ return;
2120
+ }
2121
+ await logActivity(db, {
2122
+ companyId: agent.companyId,
2123
+ actorType: actor.actorType,
2124
+ actorId: actor.actorId,
2125
+ agentId: actor.agentId,
2126
+ runId: actor.runId,
2127
+ action: "agent.updated",
2128
+ entityType: "agent",
2129
+ entityId: agent.id,
2130
+ details: summarizeAgentUpdateDetails(patchData),
2131
+ });
2132
+ res.json(agent);
2133
+ });
2134
+ router.post("/agents/:id/pause", async (req, res) => {
2135
+ assertBoard(req);
2136
+ const id = req.params.id;
2137
+ if (!(await getAccessibleAgent(req, res, id))) {
2138
+ return;
2139
+ }
2140
+ const agent = await svc.pause(id);
2141
+ if (!agent) {
2142
+ res.status(404).json({ error: "Agent not found" });
2143
+ return;
2144
+ }
2145
+ await heartbeat.cancelActiveForAgent(id);
2146
+ await logActivity(db, {
2147
+ companyId: agent.companyId,
2148
+ actorType: "user",
2149
+ actorId: req.actor.userId ?? "board",
2150
+ action: "agent.paused",
2151
+ entityType: "agent",
2152
+ entityId: agent.id,
2153
+ });
2154
+ res.json(agent);
2155
+ });
2156
+ router.post("/agents/:id/resume", async (req, res) => {
2157
+ assertBoard(req);
2158
+ const id = req.params.id;
2159
+ if (!(await getAccessibleAgent(req, res, id))) {
2160
+ return;
2161
+ }
2162
+ const agent = await svc.resume(id);
2163
+ if (!agent) {
2164
+ res.status(404).json({ error: "Agent not found" });
2165
+ return;
2166
+ }
2167
+ await logActivity(db, {
2168
+ companyId: agent.companyId,
2169
+ actorType: "user",
2170
+ actorId: req.actor.userId ?? "board",
2171
+ action: "agent.resumed",
2172
+ entityType: "agent",
2173
+ entityId: agent.id,
2174
+ });
2175
+ res.json(agent);
2176
+ });
2177
+ router.post("/agents/:id/approve", async (req, res) => {
2178
+ assertBoard(req);
2179
+ const id = req.params.id;
2180
+ const existing = await getAccessibleAgent(req, res, id);
2181
+ if (!existing) {
2182
+ return;
2183
+ }
2184
+ if (existing.status !== "pending_approval") {
2185
+ res.status(409).json({ error: "Only pending approval agents can be approved" });
2186
+ return;
2187
+ }
2188
+ const approval = await svc.activatePendingApproval(id);
2189
+ if (!approval) {
2190
+ res.status(404).json({ error: "Agent not found" });
2191
+ return;
2192
+ }
2193
+ if (!approval.activated) {
2194
+ res.status(409).json({ error: "Only pending approval agents can be approved" });
2195
+ return;
2196
+ }
2197
+ const { agent } = approval;
2198
+ await logActivity(db, {
2199
+ companyId: agent.companyId,
2200
+ actorType: "user",
2201
+ actorId: req.actor.userId ?? "board",
2202
+ action: "agent.approved",
2203
+ entityType: "agent",
2204
+ entityId: agent.id,
2205
+ details: { source: "agent_detail" },
2206
+ });
2207
+ res.json(agent);
2208
+ });
2209
+ router.post("/agents/:id/terminate", async (req, res) => {
2210
+ assertBoard(req);
2211
+ const id = req.params.id;
2212
+ if (!(await getAccessibleAgent(req, res, id))) {
2213
+ return;
2214
+ }
2215
+ const agent = await svc.terminate(id);
2216
+ if (!agent) {
2217
+ res.status(404).json({ error: "Agent not found" });
2218
+ return;
2219
+ }
2220
+ await heartbeat.cancelActiveForAgent(id);
2221
+ await logActivity(db, {
2222
+ companyId: agent.companyId,
2223
+ actorType: "user",
2224
+ actorId: req.actor.userId ?? "board",
2225
+ action: "agent.terminated",
2226
+ entityType: "agent",
2227
+ entityId: agent.id,
2228
+ });
2229
+ res.json(agent);
2230
+ });
2231
+ router.delete("/agents/:id", async (req, res) => {
2232
+ assertBoard(req);
2233
+ const id = req.params.id;
2234
+ if (!(await getAccessibleAgent(req, res, id))) {
2235
+ return;
2236
+ }
2237
+ const agent = await svc.remove(id);
2238
+ if (!agent) {
2239
+ res.status(404).json({ error: "Agent not found" });
2240
+ return;
2241
+ }
2242
+ await logActivity(db, {
2243
+ companyId: agent.companyId,
2244
+ actorType: "user",
2245
+ actorId: req.actor.userId ?? "board",
2246
+ action: "agent.deleted",
2247
+ entityType: "agent",
2248
+ entityId: agent.id,
2249
+ });
2250
+ res.json({ ok: true });
2251
+ });
2252
+ router.get("/agents/:id/keys", async (req, res) => {
2253
+ assertBoard(req);
2254
+ const id = req.params.id;
2255
+ const agent = await getAccessibleAgent(req, res, id);
2256
+ if (!agent) {
2257
+ return;
2258
+ }
2259
+ const keys = await svc.listKeys(id);
2260
+ res.json(keys);
2261
+ });
2262
+ router.post("/agents/:id/keys", validate(createAgentKeySchema), async (req, res) => {
2263
+ assertBoard(req);
2264
+ const id = req.params.id;
2265
+ const agent = await getAccessibleAgent(req, res, id);
2266
+ if (!agent) {
2267
+ return;
2268
+ }
2269
+ const key = await svc.createApiKey(id, req.body.name);
2270
+ await logActivity(db, {
2271
+ companyId: agent.companyId,
2272
+ actorType: "user",
2273
+ actorId: req.actor.userId ?? "board",
2274
+ action: "agent.key_created",
2275
+ entityType: "agent",
2276
+ entityId: agent.id,
2277
+ details: { keyId: key.id, name: key.name },
2278
+ });
2279
+ res.status(201).json(key);
2280
+ });
2281
+ router.delete("/agents/:id/keys/:keyId", async (req, res) => {
2282
+ assertBoard(req);
2283
+ const id = req.params.id;
2284
+ const keyId = req.params.keyId;
2285
+ const agent = await getAccessibleAgent(req, res, id);
2286
+ if (!agent) {
2287
+ return;
2288
+ }
2289
+ const key = await svc.getKeyById(keyId);
2290
+ if (!key || key.agentId !== agent.id) {
2291
+ res.status(404).json({ error: "Key not found" });
2292
+ return;
2293
+ }
2294
+ const revoked = await svc.revokeKey(agent.id, keyId);
2295
+ if (!revoked) {
2296
+ res.status(404).json({ error: "Key not found" });
2297
+ return;
2298
+ }
2299
+ await logActivity(db, {
2300
+ companyId: agent.companyId,
2301
+ actorType: "user",
2302
+ actorId: req.actor.userId ?? "board",
2303
+ action: "agent.key_revoked",
2304
+ entityType: "agent",
2305
+ entityId: agent.id,
2306
+ details: { keyId: key.id, name: key.name },
2307
+ });
2308
+ res.json({ ok: true });
2309
+ });
2310
+ const handleWakeupRoute = async (req, res, opts) => {
2311
+ const id = req.params.id;
2312
+ const agent = await svc.getById(id);
2313
+ if (!agent) {
2314
+ res.status(404).json({ error: "Agent not found" });
2315
+ return;
2316
+ }
2317
+ assertCompanyAccess(req, agent.companyId);
2318
+ if (req.actor.type === "agent") {
2319
+ if (req.actor.agentId !== id) {
2320
+ res.status(403).json({ error: "Agent can only invoke itself" });
2321
+ return;
2322
+ }
2323
+ }
2324
+ else {
2325
+ await assertBoardCanManageAgentsForCompany(req, agent.companyId);
2326
+ }
2327
+ const run = await heartbeat.wakeup(id, {
2328
+ source: opts.source,
2329
+ triggerDetail: req.body.triggerDetail ?? "manual",
2330
+ reason: req.body.reason ?? null,
2331
+ payload: req.body.payload ?? null,
2332
+ idempotencyKey: req.body.idempotencyKey ?? null,
2333
+ requestedByActorType: req.actor.type === "agent" ? "agent" : "user",
2334
+ requestedByActorId: req.actor.type === "agent" ? req.actor.agentId ?? null : req.actor.userId ?? null,
2335
+ contextSnapshot: {
2336
+ triggeredBy: req.actor.type,
2337
+ actorId: req.actor.type === "agent" ? req.actor.agentId : req.actor.userId,
2338
+ forceFreshSession: req.body.forceFreshSession === true,
2339
+ },
2340
+ });
2341
+ if (!run) {
2342
+ res.status(202).json(await opts.skippedResponse(agent));
2343
+ return;
2344
+ }
2345
+ const actor = getActorInfo(req);
2346
+ await logActivity(db, {
2347
+ companyId: agent.companyId,
2348
+ actorType: actor.actorType,
2349
+ actorId: actor.actorId,
2350
+ agentId: actor.agentId,
2351
+ runId: actor.runId,
2352
+ action: "heartbeat.invoked",
2353
+ entityType: "heartbeat_run",
2354
+ entityId: run.id,
2355
+ details: { agentId: id },
2356
+ });
2357
+ res.status(202).json(run);
2358
+ };
2359
+ router.post("/agents/:id/wakeup", validate(wakeAgentSchema), async (req, res) => {
2360
+ await handleWakeupRoute(req, res, {
2361
+ source: req.body.source,
2362
+ skippedResponse: (agent) => buildSkippedWakeupResponse(agent, req.body.payload ?? null),
2363
+ });
2364
+ });
2365
+ router.post("/agents/:id/heartbeat/invoke", async (req, res) => {
2366
+ // Legacy endpoint. Hardcodes `source: "on_demand"` (the prior behavior
2367
+ // before the wakeup/invoke convergence). Reads scope fields directly off
2368
+ // the body without `validate(wakeAgentSchema)` because callers — including
2369
+ // the e2e suite — post an empty body, and the schema rejects undefined
2370
+ // / missing bodies. Only forwards fields the caller actually supplied so
2371
+ // an empty body produces the original fixed-arg `heartbeat.invoke()`
2372
+ // shape exactly.
2373
+ const id = req.params.id;
2374
+ const agent = await svc.getById(id);
2375
+ if (!agent) {
2376
+ res.status(404).json({ error: "Agent not found" });
2377
+ return;
2378
+ }
2379
+ assertCompanyAccess(req, agent.companyId);
2380
+ if (req.actor.type === "agent") {
2381
+ if (req.actor.agentId !== id) {
2382
+ res.status(403).json({ error: "Agent can only invoke itself" });
2383
+ return;
2384
+ }
2385
+ }
2386
+ else {
2387
+ await assertBoardCanManageAgentsForCompany(req, agent.companyId);
2388
+ }
2389
+ const body = (req.body ?? {});
2390
+ const contextSnapshot = {
2391
+ triggeredBy: req.actor.type,
2392
+ actorId: req.actor.type === "agent" ? req.actor.agentId : req.actor.userId,
2393
+ };
2394
+ if (body.forceFreshSession === true) {
2395
+ contextSnapshot.forceFreshSession = true;
2396
+ }
2397
+ const wakeOpts = {
2398
+ source: "on_demand",
2399
+ triggerDetail: typeof body.triggerDetail === "string" ? body.triggerDetail : "manual",
2400
+ requestedByActorType: req.actor.type === "agent" ? "agent" : "user",
2401
+ requestedByActorId: req.actor.type === "agent" ? req.actor.agentId ?? null : req.actor.userId ?? null,
2402
+ contextSnapshot,
2403
+ };
2404
+ if (typeof body.reason === "string" && body.reason.length > 0) {
2405
+ wakeOpts.reason = body.reason;
2406
+ }
2407
+ if (body.payload && typeof body.payload === "object" && !Array.isArray(body.payload)) {
2408
+ wakeOpts.payload = body.payload;
2409
+ }
2410
+ if (typeof body.idempotencyKey === "string" && body.idempotencyKey.length > 0) {
2411
+ wakeOpts.idempotencyKey = body.idempotencyKey;
2412
+ }
2413
+ const run = await heartbeat.wakeup(id, wakeOpts);
2414
+ if (!run) {
2415
+ res.status(202).json({ status: "skipped" });
2416
+ return;
2417
+ }
2418
+ const actor = getActorInfo(req);
2419
+ await logActivity(db, {
2420
+ companyId: agent.companyId,
2421
+ actorType: actor.actorType,
2422
+ actorId: actor.actorId,
2423
+ agentId: actor.agentId,
2424
+ runId: actor.runId,
2425
+ action: "heartbeat.invoked",
2426
+ entityType: "heartbeat_run",
2427
+ entityId: run.id,
2428
+ details: { agentId: id },
2429
+ });
2430
+ res.status(202).json(run);
2431
+ });
2432
+ router.post("/agents/:id/claude-login", async (req, res) => {
2433
+ assertBoard(req);
2434
+ const id = req.params.id;
2435
+ const agent = await svc.getById(id);
2436
+ if (!agent) {
2437
+ res.status(404).json({ error: "Agent not found" });
2438
+ return;
2439
+ }
2440
+ await assertBoardCanManageAgentsForCompany(req, agent.companyId);
2441
+ assertCompanyAccess(req, agent.companyId);
2442
+ if (agent.adapterType !== "claude_local") {
2443
+ res.status(400).json({ error: "Login is only supported for claude_local agents" });
2444
+ return;
2445
+ }
2446
+ const config = asRecord(agent.adapterConfig) ?? {};
2447
+ const { config: runtimeConfig } = await secretsSvc.resolveAdapterConfigForRuntime(agent.companyId, config);
2448
+ const result = await runClaudeLogin({
2449
+ runId: `claude-login-${randomUUID()}`,
2450
+ agent: {
2451
+ id: agent.id,
2452
+ companyId: agent.companyId,
2453
+ name: agent.name,
2454
+ adapterType: agent.adapterType,
2455
+ adapterConfig: agent.adapterConfig,
2456
+ },
2457
+ config: runtimeConfig,
2458
+ });
2459
+ res.json(result);
2460
+ });
2461
+ router.get("/companies/:companyId/heartbeat-runs", async (req, res) => {
2462
+ const companyId = req.params.companyId;
2463
+ assertCompanyAccess(req, companyId);
2464
+ const agentId = req.query.agentId;
2465
+ const limitParam = req.query.limit;
2466
+ const limit = limitParam ? Math.max(1, Math.min(1000, parseInt(limitParam, 10) || 200)) : undefined;
2467
+ const runs = await heartbeat.list(companyId, agentId, limit);
2468
+ res.json(runs);
2469
+ });
2470
+ router.get("/companies/:companyId/live-runs", async (req, res) => {
2471
+ const companyId = req.params.companyId;
2472
+ assertCompanyAccess(req, companyId);
2473
+ // `minCount` is a padding floor for callers that want a minimum number of
2474
+ // recent runs to render (e.g. dashboard cards). It must default to 0 so
2475
+ // callers asking for "live runs" get only actually-live runs — otherwise
2476
+ // every caller with no minCount param gets up to 50 historical runs
2477
+ // padded in and renders bogus "live" counts.
2478
+ const minCount = readLiveRunsQueryInt(req.query.minCount, 50, 0);
2479
+ const limit = readLiveRunsQueryInt(req.query.limit, 50, 50);
2480
+ const columns = {
2481
+ id: heartbeatRuns.id,
2482
+ companyId: heartbeatRuns.companyId,
2483
+ status: heartbeatRuns.status,
2484
+ invocationSource: heartbeatRuns.invocationSource,
2485
+ triggerDetail: heartbeatRuns.triggerDetail,
2486
+ contextCommentId: sql `${heartbeatRuns.contextSnapshot} ->> 'commentId'`.as("contextCommentId"),
2487
+ contextWakeCommentId: sql `${heartbeatRuns.contextSnapshot} ->> 'wakeCommentId'`.as("contextWakeCommentId"),
2488
+ startedAt: heartbeatRuns.startedAt,
2489
+ finishedAt: heartbeatRuns.finishedAt,
2490
+ createdAt: heartbeatRuns.createdAt,
2491
+ agentId: heartbeatRuns.agentId,
2492
+ agentName: agentsTable.name,
2493
+ adapterType: agentsTable.adapterType,
2494
+ logBytes: heartbeatRuns.logBytes,
2495
+ livenessState: heartbeatRuns.livenessState,
2496
+ livenessReason: heartbeatRuns.livenessReason,
2497
+ continuationAttempt: heartbeatRuns.continuationAttempt,
2498
+ lastUsefulActionAt: heartbeatRuns.lastUsefulActionAt,
2499
+ nextAction: heartbeatRuns.nextAction,
2500
+ lastOutputAt: heartbeatRuns.lastOutputAt,
2501
+ lastOutputSeq: heartbeatRuns.lastOutputSeq,
2502
+ lastOutputStream: heartbeatRuns.lastOutputStream,
2503
+ lastOutputBytes: heartbeatRuns.lastOutputBytes,
2504
+ processStartedAt: heartbeatRuns.processStartedAt,
2505
+ issueId: sql `${heartbeatRuns.contextSnapshot} ->> 'issueId'`.as("issueId"),
2506
+ };
2507
+ const liveRunsQuery = db
2508
+ .select(columns)
2509
+ .from(heartbeatRuns)
2510
+ .innerJoin(agentsTable, eq(heartbeatRuns.agentId, agentsTable.id))
2511
+ .where(and(eq(heartbeatRuns.companyId, companyId), inArray(heartbeatRuns.status, ["queued", "running"])))
2512
+ .orderBy(desc(heartbeatRuns.createdAt));
2513
+ const liveRuns = await liveRunsQuery.limit(limit);
2514
+ const targetRunCount = Math.min(minCount, limit);
2515
+ if (targetRunCount > 0 && liveRuns.length < targetRunCount) {
2516
+ const activeIds = liveRuns.map((r) => r.id);
2517
+ const recentRuns = await db
2518
+ .select(columns)
2519
+ .from(heartbeatRuns)
2520
+ .innerJoin(agentsTable, eq(heartbeatRuns.agentId, agentsTable.id))
2521
+ .where(and(eq(heartbeatRuns.companyId, companyId), not(inArray(heartbeatRuns.status, ["queued", "running"])), ...(activeIds.length > 0 ? [not(inArray(heartbeatRuns.id, activeIds))] : [])))
2522
+ .orderBy(desc(heartbeatRuns.createdAt))
2523
+ .limit(targetRunCount - liveRuns.length);
2524
+ const rows = [...liveRuns, ...recentRuns];
2525
+ res.json(await Promise.all(rows.map(async (run) => ({
2526
+ ...run,
2527
+ outputSilence: await heartbeat.buildRunOutputSilence(run),
2528
+ }))));
2529
+ return;
2530
+ }
2531
+ res.json(await Promise.all(liveRuns.map(async (run) => ({
2532
+ ...run,
2533
+ outputSilence: await heartbeat.buildRunOutputSilence(run),
2534
+ }))));
2535
+ });
2536
+ router.get("/heartbeat-runs/:runId", async (req, res) => {
2537
+ const runId = req.params.runId;
2538
+ const run = await heartbeat.getRun(runId);
2539
+ if (!run) {
2540
+ res.status(404).json({ error: "Heartbeat run not found" });
2541
+ return;
2542
+ }
2543
+ assertCompanyAccess(req, run.companyId);
2544
+ const retryExhaustedReason = await heartbeat.getRetryExhaustedReason(runId);
2545
+ res.json(redactCurrentUserValue({ ...run, retryExhaustedReason, outputSilence: await heartbeat.buildRunOutputSilence(run) }, await getCurrentUserRedactionOptions()));
2546
+ });
2547
+ router.post("/heartbeat-runs/:runId/cancel", async (req, res) => {
2548
+ assertBoard(req);
2549
+ const runId = req.params.runId;
2550
+ const existing = await heartbeat.getRun(runId);
2551
+ if (existing) {
2552
+ assertCompanyAccess(req, existing.companyId);
2553
+ }
2554
+ const run = await heartbeat.cancelRun(runId);
2555
+ if (run) {
2556
+ await logActivity(db, {
2557
+ companyId: run.companyId,
2558
+ actorType: "user",
2559
+ actorId: req.actor.userId ?? "board",
2560
+ action: "heartbeat.cancelled",
2561
+ entityType: "heartbeat_run",
2562
+ entityId: run.id,
2563
+ details: { agentId: run.agentId },
2564
+ });
2565
+ }
2566
+ res.json(run);
2567
+ });
2568
+ router.post("/heartbeat-runs/:runId/watchdog-decisions", async (req, res) => {
2569
+ const runId = req.params.runId;
2570
+ const existing = await heartbeat.getRun(runId);
2571
+ if (!existing) {
2572
+ res.status(404).json({ error: "Heartbeat run not found" });
2573
+ return;
2574
+ }
2575
+ assertCompanyAccess(req, existing.companyId);
2576
+ const decision = typeof req.body?.decision === "string" ? req.body.decision : "";
2577
+ if (!["snooze", "continue", "dismissed_false_positive"].includes(decision)) {
2578
+ res.status(400).json({ error: "Unsupported watchdog decision" });
2579
+ return;
2580
+ }
2581
+ const evaluationIssueId = typeof req.body?.evaluationIssueId === "string" ? req.body.evaluationIssueId : null;
2582
+ const reason = typeof req.body?.reason === "string" ? req.body.reason.slice(0, 4000) : null;
2583
+ const snoozedUntil = decision === "snooze"
2584
+ ? new Date(String(req.body?.snoozedUntil ?? ""))
2585
+ : null;
2586
+ if (decision === "snooze" && (!snoozedUntil || Number.isNaN(snoozedUntil.getTime()) || snoozedUntil <= new Date())) {
2587
+ res.status(400).json({ error: "snoozedUntil must be a future ISO datetime" });
2588
+ return;
2589
+ }
2590
+ const row = await recovery.recordWatchdogDecision({
2591
+ runId: existing.id,
2592
+ actor: req.actor,
2593
+ decision: decision,
2594
+ evaluationIssueId,
2595
+ reason,
2596
+ snoozedUntil,
2597
+ createdByRunId: req.actor.runId ?? null,
2598
+ });
2599
+ res.json(row);
2600
+ });
2601
+ router.get("/heartbeat-runs/:runId/events", async (req, res) => {
2602
+ const runId = req.params.runId;
2603
+ const run = await heartbeat.getRun(runId);
2604
+ if (!run) {
2605
+ res.status(404).json({ error: "Heartbeat run not found" });
2606
+ return;
2607
+ }
2608
+ assertCompanyAccess(req, run.companyId);
2609
+ const afterSeq = Number(req.query.afterSeq ?? 0);
2610
+ const limit = Number(req.query.limit ?? 200);
2611
+ const events = await heartbeat.listEvents(runId, Number.isFinite(afterSeq) ? afterSeq : 0, Number.isFinite(limit) ? limit : 200);
2612
+ const currentUserRedactionOptions = await getCurrentUserRedactionOptions();
2613
+ const redactedEvents = events.map((event) => redactCurrentUserValue({
2614
+ ...event,
2615
+ payload: redactEventPayload(event.payload),
2616
+ }, currentUserRedactionOptions));
2617
+ res.json(redactedEvents);
2618
+ });
2619
+ router.get("/heartbeat-runs/:runId/log", async (req, res) => {
2620
+ const runId = req.params.runId;
2621
+ const run = await heartbeat.getRunLogAccess(runId);
2622
+ if (!run) {
2623
+ res.status(404).json({ error: "Heartbeat run not found" });
2624
+ return;
2625
+ }
2626
+ assertCompanyAccess(req, run.companyId);
2627
+ const offset = Number(req.query.offset ?? 0);
2628
+ const limitBytes = readRunLogLimitBytes(req.query.limitBytes);
2629
+ const result = await heartbeat.readLog(run, {
2630
+ offset: Number.isFinite(offset) ? offset : 0,
2631
+ limitBytes,
2632
+ });
2633
+ res.set("Cache-Control", "no-cache, no-store");
2634
+ res.json(result);
2635
+ });
2636
+ router.get("/heartbeat-runs/:runId/workspace-operations", async (req, res) => {
2637
+ const runId = req.params.runId;
2638
+ const run = await heartbeat.getRun(runId);
2639
+ if (!run) {
2640
+ res.status(404).json({ error: "Heartbeat run not found" });
2641
+ return;
2642
+ }
2643
+ assertCompanyAccess(req, run.companyId);
2644
+ const context = asRecord(run.contextSnapshot);
2645
+ const executionWorkspaceId = asNonEmptyString(context?.executionWorkspaceId);
2646
+ const operations = await workspaceOperations.listForRun(runId, executionWorkspaceId);
2647
+ res.json(redactCurrentUserValue(operations, await getCurrentUserRedactionOptions()));
2648
+ });
2649
+ router.get("/workspace-operations/:operationId/log", async (req, res) => {
2650
+ const operationId = req.params.operationId;
2651
+ const operation = await workspaceOperations.getById(operationId);
2652
+ if (!operation) {
2653
+ res.status(404).json({ error: "Workspace operation not found" });
2654
+ return;
2655
+ }
2656
+ assertCompanyAccess(req, operation.companyId);
2657
+ const offset = Number(req.query.offset ?? 0);
2658
+ const limitBytes = readRunLogLimitBytes(req.query.limitBytes);
2659
+ const result = await workspaceOperations.readLog(operationId, {
2660
+ offset: Number.isFinite(offset) ? offset : 0,
2661
+ limitBytes,
2662
+ });
2663
+ res.set("Cache-Control", "no-cache, no-store");
2664
+ res.json(result);
2665
+ });
2666
+ router.get("/issues/:issueId/live-runs", async (req, res) => {
2667
+ const rawId = req.params.issueId;
2668
+ const issueSvc = issueService(db);
2669
+ const identifier = normalizeIssueIdentifier(rawId);
2670
+ const issue = identifier ? await issueSvc.getByIdentifier(identifier) : await issueSvc.getById(rawId);
2671
+ if (!issue) {
2672
+ res.status(404).json({ error: "Issue not found" });
2673
+ return;
2674
+ }
2675
+ assertCompanyAccess(req, issue.companyId);
2676
+ const liveRuns = await db
2677
+ .select({
2678
+ id: heartbeatRuns.id,
2679
+ status: heartbeatRuns.status,
2680
+ invocationSource: heartbeatRuns.invocationSource,
2681
+ triggerDetail: heartbeatRuns.triggerDetail,
2682
+ contextCommentId: sql `${heartbeatRuns.contextSnapshot} ->> 'commentId'`.as("contextCommentId"),
2683
+ contextWakeCommentId: sql `${heartbeatRuns.contextSnapshot} ->> 'wakeCommentId'`.as("contextWakeCommentId"),
2684
+ startedAt: heartbeatRuns.startedAt,
2685
+ finishedAt: heartbeatRuns.finishedAt,
2686
+ createdAt: heartbeatRuns.createdAt,
2687
+ agentId: heartbeatRuns.agentId,
2688
+ agentName: agentsTable.name,
2689
+ adapterType: agentsTable.adapterType,
2690
+ logBytes: heartbeatRuns.logBytes,
2691
+ livenessState: heartbeatRuns.livenessState,
2692
+ livenessReason: heartbeatRuns.livenessReason,
2693
+ continuationAttempt: heartbeatRuns.continuationAttempt,
2694
+ lastUsefulActionAt: heartbeatRuns.lastUsefulActionAt,
2695
+ nextAction: heartbeatRuns.nextAction,
2696
+ lastOutputAt: heartbeatRuns.lastOutputAt,
2697
+ lastOutputSeq: heartbeatRuns.lastOutputSeq,
2698
+ lastOutputStream: heartbeatRuns.lastOutputStream,
2699
+ lastOutputBytes: heartbeatRuns.lastOutputBytes,
2700
+ processStartedAt: heartbeatRuns.processStartedAt,
2701
+ })
2702
+ .from(heartbeatRuns)
2703
+ .innerJoin(agentsTable, eq(heartbeatRuns.agentId, agentsTable.id))
2704
+ .where(and(eq(heartbeatRuns.companyId, issue.companyId), inArray(heartbeatRuns.status, ["queued", "running"]), sql `${heartbeatRuns.contextSnapshot} ->> 'issueId' = ${issue.id}`))
2705
+ .orderBy(desc(heartbeatRuns.createdAt));
2706
+ res.json(await Promise.all(liveRuns.map(async (run) => ({
2707
+ ...run,
2708
+ outputSilence: await heartbeat.buildRunOutputSilence({ ...run, companyId: issue.companyId }),
2709
+ }))));
2710
+ });
2711
+ router.get("/issues/:issueId/active-run", async (req, res) => {
2712
+ const rawId = req.params.issueId;
2713
+ const issueSvc = issueService(db);
2714
+ const identifier = normalizeIssueIdentifier(rawId);
2715
+ const issue = identifier ? await issueSvc.getByIdentifier(identifier) : await issueSvc.getById(rawId);
2716
+ if (!issue) {
2717
+ res.status(404).json({ error: "Issue not found" });
2718
+ return;
2719
+ }
2720
+ assertCompanyAccess(req, issue.companyId);
2721
+ let run = issue.executionRunId ? await heartbeat.getRunIssueSummary(issue.executionRunId) : null;
2722
+ if (run &&
2723
+ ((run.status !== "queued" && run.status !== "running") ||
2724
+ run.issueId !== issue.id)) {
2725
+ run = null;
2726
+ }
2727
+ if (!run && issue.assigneeAgentId && issue.status === "in_progress") {
2728
+ const candidateRun = await heartbeat.getActiveRunIssueSummaryForAgent(issue.assigneeAgentId);
2729
+ const candidateIssueId = asNonEmptyString(candidateRun?.issueId);
2730
+ if (candidateRun && candidateIssueId === issue.id) {
2731
+ run = candidateRun;
2732
+ }
2733
+ }
2734
+ if (!run) {
2735
+ res.json(null);
2736
+ return;
2737
+ }
2738
+ const agent = await svc.getById(run.agentId);
2739
+ if (!agent) {
2740
+ res.json(null);
2741
+ return;
2742
+ }
2743
+ res.json({
2744
+ ...run,
2745
+ agentId: agent.id,
2746
+ agentName: agent.name,
2747
+ adapterType: agent.adapterType,
2748
+ outputSilence: await heartbeat.buildRunOutputSilence({ ...run, companyId: issue.companyId }),
2749
+ });
2750
+ });
2751
+ return router;
2752
+ }
2753
+ //# sourceMappingURL=agents.js.map