@wascartech/devbot 0.0.0-stage → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +638 -2
  3. package/dist/access-grant-store.js +99 -0
  4. package/dist/access-grant-store.js.map +1 -0
  5. package/dist/access-resolve.js +11 -0
  6. package/dist/access-resolve.js.map +1 -0
  7. package/dist/access-rule-store.js +99 -0
  8. package/dist/access-rule-store.js.map +1 -0
  9. package/dist/admin/access-routes.js +73 -0
  10. package/dist/admin/access-routes.js.map +1 -0
  11. package/dist/admin/access-rule-routes.js +107 -0
  12. package/dist/admin/access-rule-routes.js.map +1 -0
  13. package/dist/admin/custom-repos-routes.js +93 -0
  14. package/dist/admin/custom-repos-routes.js.map +1 -0
  15. package/dist/admin/env-routes.js +74 -0
  16. package/dist/admin/env-routes.js.map +1 -0
  17. package/dist/admin/global-settings-routes.js +254 -0
  18. package/dist/admin/global-settings-routes.js.map +1 -0
  19. package/dist/admin/mcp-cleanup.js +12 -0
  20. package/dist/admin/mcp-cleanup.js.map +1 -0
  21. package/dist/admin/mcp-routes.js +169 -0
  22. package/dist/admin/mcp-routes.js.map +1 -0
  23. package/dist/admin/query-params.js +80 -0
  24. package/dist/admin/query-params.js.map +1 -0
  25. package/dist/admin/routes.js +150 -0
  26. package/dist/admin/routes.js.map +1 -0
  27. package/dist/admin/run-history-routes.js +44 -0
  28. package/dist/admin/run-history-routes.js.map +1 -0
  29. package/dist/admin/run-routes.js +99 -0
  30. package/dist/admin/run-routes.js.map +1 -0
  31. package/dist/admin/settings-routes.js +119 -0
  32. package/dist/admin/settings-routes.js.map +1 -0
  33. package/dist/admin/stats-routes.js +51 -0
  34. package/dist/admin/stats-routes.js.map +1 -0
  35. package/dist/admin/task-routes.js +213 -0
  36. package/dist/admin/task-routes.js.map +1 -0
  37. package/dist/admin/test-routes.js +38 -0
  38. package/dist/admin/test-routes.js.map +1 -0
  39. package/dist/admin/volume-routes.js +82 -0
  40. package/dist/admin/volume-routes.js.map +1 -0
  41. package/dist/admin/webhook-routes.js +174 -0
  42. package/dist/admin/webhook-routes.js.map +1 -0
  43. package/dist/agents.js +48 -0
  44. package/dist/agents.js.map +1 -0
  45. package/dist/assignee-value.js +6 -0
  46. package/dist/assignee-value.js.map +1 -0
  47. package/dist/attachments.js +76 -0
  48. package/dist/attachments.js.map +1 -0
  49. package/dist/auto-commands.js +88 -0
  50. package/dist/auto-commands.js.map +1 -0
  51. package/dist/auto-features.js +32 -0
  52. package/dist/auto-features.js.map +1 -0
  53. package/dist/base-branch-store.js +40 -0
  54. package/dist/base-branch-store.js.map +1 -0
  55. package/dist/base-branches.js +9 -0
  56. package/dist/base-branches.js.map +1 -0
  57. package/dist/build-workflow.js +116 -0
  58. package/dist/build-workflow.js.map +1 -0
  59. package/dist/change-request-lifecycle.js +16 -0
  60. package/dist/change-request-lifecycle.js.map +1 -0
  61. package/dist/change-request-store.js +72 -0
  62. package/dist/change-request-store.js.map +1 -0
  63. package/dist/ci-failure.js +80 -0
  64. package/dist/ci-failure.js.map +1 -0
  65. package/dist/cli.js +3 -0
  66. package/dist/cli.js.map +1 -0
  67. package/dist/config.js +17 -0
  68. package/dist/config.js.map +1 -0
  69. package/dist/conflict-fix.js +178 -0
  70. package/dist/conflict-fix.js.map +1 -0
  71. package/dist/cookie.js +70 -0
  72. package/dist/cookie.js.map +1 -0
  73. package/dist/crypto-util.js +40 -0
  74. package/dist/crypto-util.js.map +1 -0
  75. package/dist/custom-repos-store.js +90 -0
  76. package/dist/custom-repos-store.js.map +1 -0
  77. package/dist/custom-repos-sync.js +118 -0
  78. package/dist/custom-repos-sync.js.map +1 -0
  79. package/dist/db.js +12 -0
  80. package/dist/db.js.map +1 -0
  81. package/dist/devbot-scripts.js +18 -0
  82. package/dist/devbot-scripts.js.map +1 -0
  83. package/dist/devcontainer.js +141 -0
  84. package/dist/devcontainer.js.map +1 -0
  85. package/dist/env-config-store.js +132 -0
  86. package/dist/env-config-store.js.map +1 -0
  87. package/dist/error-log-store.js +193 -0
  88. package/dist/error-log-store.js.map +1 -0
  89. package/dist/git.js +605 -0
  90. package/dist/git.js.map +1 -0
  91. package/dist/global-queue.js +127 -0
  92. package/dist/global-queue.js.map +1 -0
  93. package/dist/global-settings-store.js +307 -0
  94. package/dist/global-settings-store.js.map +1 -0
  95. package/dist/help.js +41 -0
  96. package/dist/help.js.map +1 -0
  97. package/dist/http-csp.js +15 -0
  98. package/dist/http-csp.js.map +1 -0
  99. package/dist/http-util.js +40 -0
  100. package/dist/http-util.js.map +1 -0
  101. package/dist/idempotency.js +50 -0
  102. package/dist/idempotency.js.map +1 -0
  103. package/dist/lifecycle.js +234 -0
  104. package/dist/lifecycle.js.map +1 -0
  105. package/dist/logger.js +33 -0
  106. package/dist/logger.js.map +1 -0
  107. package/dist/lsp-servers.js +81 -0
  108. package/dist/lsp-servers.js.map +1 -0
  109. package/dist/mcp/auth.js +62 -0
  110. package/dist/mcp/auth.js.map +1 -0
  111. package/dist/mcp/effective-mcp.js +42 -0
  112. package/dist/mcp/effective-mcp.js.map +1 -0
  113. package/dist/mcp/oauth-refresh.js +138 -0
  114. package/dist/mcp/oauth-refresh.js.map +1 -0
  115. package/dist/mcp/peer-sync.js +109 -0
  116. package/dist/mcp/peer-sync.js.map +1 -0
  117. package/dist/mcp/registry.js +54 -0
  118. package/dist/mcp/registry.js.map +1 -0
  119. package/dist/mcp/runner-bridge.js +93 -0
  120. package/dist/mcp/runner-bridge.js.map +1 -0
  121. package/dist/mcp/server.js +173 -0
  122. package/dist/mcp/server.js.map +1 -0
  123. package/dist/mcp/tools/_helpers.js +88 -0
  124. package/dist/mcp/tools/_helpers.js.map +1 -0
  125. package/dist/mcp/tools/attachments.js +117 -0
  126. package/dist/mcp/tools/attachments.js.map +1 -0
  127. package/dist/mcp/tools/cicd.js +105 -0
  128. package/dist/mcp/tools/cicd.js.map +1 -0
  129. package/dist/mcp/tools/discovery.js +34 -0
  130. package/dist/mcp/tools/discovery.js.map +1 -0
  131. package/dist/mcp/tools/issues.js +56 -0
  132. package/dist/mcp/tools/issues.js.map +1 -0
  133. package/dist/mcp/tools/merge_requests.js +67 -0
  134. package/dist/mcp/tools/merge_requests.js.map +1 -0
  135. package/dist/mcp/tools/metadata.js +127 -0
  136. package/dist/mcp/tools/metadata.js.map +1 -0
  137. package/dist/mcp/tools/peer_sync.js +43 -0
  138. package/dist/mcp/tools/peer_sync.js.map +1 -0
  139. package/dist/mcp/tools/repository.js +178 -0
  140. package/dist/mcp/tools/repository.js.map +1 -0
  141. package/dist/mcp/tools/work_tracking.js +125 -0
  142. package/dist/mcp/tools/work_tracking.js.map +1 -0
  143. package/dist/mcp/tools/workitems.js +30 -0
  144. package/dist/mcp/tools/workitems.js.map +1 -0
  145. package/dist/mcp/volume-files.js +187 -0
  146. package/dist/mcp/volume-files.js.map +1 -0
  147. package/dist/mcp-auth-store.js +134 -0
  148. package/dist/mcp-auth-store.js.map +1 -0
  149. package/dist/mcp-config-store.js +83 -0
  150. package/dist/mcp-config-store.js.map +1 -0
  151. package/dist/mention.js +512 -0
  152. package/dist/mention.js.map +1 -0
  153. package/dist/migrate.js +73 -0
  154. package/dist/migrate.js.map +1 -0
  155. package/dist/mr-assignee.js +71 -0
  156. package/dist/mr-assignee.js.map +1 -0
  157. package/dist/mr-content.js +90 -0
  158. package/dist/mr-content.js.map +1 -0
  159. package/dist/oauth-routes.js +54 -0
  160. package/dist/oauth-routes.js.map +1 -0
  161. package/dist/onboarding-allowlist.js +32 -0
  162. package/dist/onboarding-allowlist.js.map +1 -0
  163. package/dist/opencode.js +291 -0
  164. package/dist/opencode.js.map +1 -0
  165. package/dist/outbound-webhook-store.js +229 -0
  166. package/dist/outbound-webhook-store.js.map +1 -0
  167. package/dist/outbound-webhook.js +314 -0
  168. package/dist/outbound-webhook.js.map +1 -0
  169. package/dist/path-sandbox.js +200 -0
  170. package/dist/path-sandbox.js.map +1 -0
  171. package/dist/platform/git-auth.js +34 -0
  172. package/dist/platform/git-auth.js.map +1 -0
  173. package/dist/platform/gitealike/attachments.js +62 -0
  174. package/dist/platform/gitealike/attachments.js.map +1 -0
  175. package/dist/platform/gitealike/base.js +935 -0
  176. package/dist/platform/gitealike/base.js.map +1 -0
  177. package/dist/platform/gitealike/forgejo.js +16 -0
  178. package/dist/platform/gitealike/forgejo.js.map +1 -0
  179. package/dist/platform/gitealike/gitea.js +16 -0
  180. package/dist/platform/gitealike/gitea.js.map +1 -0
  181. package/dist/platform/gitealike/http.js +152 -0
  182. package/dist/platform/gitealike/http.js.map +1 -0
  183. package/dist/platform/gitealike/schemas.js +284 -0
  184. package/dist/platform/gitealike/schemas.js.map +1 -0
  185. package/dist/platform/github/attachments.js +52 -0
  186. package/dist/platform/github/attachments.js.map +1 -0
  187. package/dist/platform/github/http.js +153 -0
  188. package/dist/platform/github/http.js.map +1 -0
  189. package/dist/platform/github/index.js +936 -0
  190. package/dist/platform/github/index.js.map +1 -0
  191. package/dist/platform/github/schemas.js +308 -0
  192. package/dist/platform/github/schemas.js.map +1 -0
  193. package/dist/platform/github/zip.js +85 -0
  194. package/dist/platform/github/zip.js.map +1 -0
  195. package/dist/platform/gitlab/admin.js +105 -0
  196. package/dist/platform/gitlab/admin.js.map +1 -0
  197. package/dist/platform/gitlab/api.js +229 -0
  198. package/dist/platform/gitlab/api.js.map +1 -0
  199. package/dist/platform/gitlab/attachments.js +79 -0
  200. package/dist/platform/gitlab/attachments.js.map +1 -0
  201. package/dist/platform/gitlab/http.js +165 -0
  202. package/dist/platform/gitlab/http.js.map +1 -0
  203. package/dist/platform/gitlab/index.js +630 -0
  204. package/dist/platform/gitlab/index.js.map +1 -0
  205. package/dist/platform/gitlab/oauth.js +58 -0
  206. package/dist/platform/gitlab/oauth.js.map +1 -0
  207. package/dist/platform/gitlab/read.js +182 -0
  208. package/dist/platform/gitlab/read.js.map +1 -0
  209. package/dist/platform/gitlab/schemas-read.js +274 -0
  210. package/dist/platform/gitlab/schemas-read.js.map +1 -0
  211. package/dist/platform/gitlab/schemas.js +251 -0
  212. package/dist/platform/gitlab/schemas.js.map +1 -0
  213. package/dist/platform/gitlab/signature.js +52 -0
  214. package/dist/platform/gitlab/signature.js.map +1 -0
  215. package/dist/platform/index.js +38 -0
  216. package/dist/platform/index.js.map +1 -0
  217. package/dist/platform/port.js +26 -0
  218. package/dist/platform/port.js.map +1 -0
  219. package/dist/platform/types.js +80 -0
  220. package/dist/platform/types.js.map +1 -0
  221. package/dist/podman.js +119 -0
  222. package/dist/podman.js.map +1 -0
  223. package/dist/project-sync.js +69 -0
  224. package/dist/project-sync.js.map +1 -0
  225. package/dist/prompt.js +47 -0
  226. package/dist/prompt.js.map +1 -0
  227. package/dist/queue-store.js +236 -0
  228. package/dist/queue-store.js.map +1 -0
  229. package/dist/queue.js +129 -0
  230. package/dist/queue.js.map +1 -0
  231. package/dist/redact.js +23 -0
  232. package/dist/redact.js.map +1 -0
  233. package/dist/run-files.js +297 -0
  234. package/dist/run-files.js.map +1 -0
  235. package/dist/run-filters.js +54 -0
  236. package/dist/run-filters.js.map +1 -0
  237. package/dist/run-history-store.js +229 -0
  238. package/dist/run-history-store.js.map +1 -0
  239. package/dist/run-log-sink.js +270 -0
  240. package/dist/run-log-sink.js.map +1 -0
  241. package/dist/run-log.js +97 -0
  242. package/dist/run-log.js.map +1 -0
  243. package/dist/run-usage.js +29 -0
  244. package/dist/run-usage.js.map +1 -0
  245. package/dist/run-view.js +112 -0
  246. package/dist/run-view.js.map +1 -0
  247. package/dist/runner.js +1094 -0
  248. package/dist/runner.js.map +1 -0
  249. package/dist/runtime-apply.js +26 -0
  250. package/dist/runtime-apply.js.map +1 -0
  251. package/dist/runtime-settings.js +71 -0
  252. package/dist/runtime-settings.js.map +1 -0
  253. package/dist/runtime-state.js +19 -0
  254. package/dist/runtime-state.js.map +1 -0
  255. package/dist/server.js +119 -0
  256. package/dist/server.js.map +1 -0
  257. package/dist/settings-store.js +320 -0
  258. package/dist/settings-store.js.map +1 -0
  259. package/dist/status.js +121 -0
  260. package/dist/status.js.map +1 -0
  261. package/dist/stop.js +56 -0
  262. package/dist/stop.js.map +1 -0
  263. package/dist/sweeps.js +87 -0
  264. package/dist/sweeps.js.map +1 -0
  265. package/dist/task-log.js +279 -0
  266. package/dist/task-log.js.map +1 -0
  267. package/dist/task-view.js +62 -0
  268. package/dist/task-view.js.map +1 -0
  269. package/dist/token-store.js +68 -0
  270. package/dist/token-store.js.map +1 -0
  271. package/dist/types/access.js +74 -0
  272. package/dist/types/access.js.map +1 -0
  273. package/dist/types/custom-repos.js +28 -0
  274. package/dist/types/custom-repos.js.map +1 -0
  275. package/dist/types/env-config.js +25 -0
  276. package/dist/types/env-config.js.map +1 -0
  277. package/dist/types/env.js +190 -0
  278. package/dist/types/env.js.map +1 -0
  279. package/dist/types/global-settings.js +178 -0
  280. package/dist/types/global-settings.js.map +1 -0
  281. package/dist/types/lsp-servers.js +145 -0
  282. package/dist/types/lsp-servers.js.map +1 -0
  283. package/dist/types/mcp-config.js +77 -0
  284. package/dist/types/mcp-config.js.map +1 -0
  285. package/dist/types/opencode.js +59 -0
  286. package/dist/types/opencode.js.map +1 -0
  287. package/dist/types/outbound-webhook.js +56 -0
  288. package/dist/types/outbound-webhook.js.map +1 -0
  289. package/dist/types/project-settings.js +114 -0
  290. package/dist/types/project-settings.js.map +1 -0
  291. package/dist/types/provider-registry.js +37 -0
  292. package/dist/types/provider-registry.js.map +1 -0
  293. package/dist/types/runtime-settings.js +78 -0
  294. package/dist/types/runtime-settings.js.map +1 -0
  295. package/dist/usage-stats.js +159 -0
  296. package/dist/usage-stats.js.map +1 -0
  297. package/dist/version.js +19 -0
  298. package/dist/version.js.map +1 -0
  299. package/dist/volume-gc.js +193 -0
  300. package/dist/volume-gc.js.map +1 -0
  301. package/dist/volume-manage.js +191 -0
  302. package/dist/volume-manage.js.map +1 -0
  303. package/dist/volume-store.js +122 -0
  304. package/dist/volume-store.js.map +1 -0
  305. package/dist/webhook.js +1106 -0
  306. package/dist/webhook.js.map +1 -0
  307. package/dist/work-item-auto-store.js +75 -0
  308. package/dist/work-item-auto-store.js.map +1 -0
  309. package/dist/work-item-branch-store.js +37 -0
  310. package/dist/work-item-branch-store.js.map +1 -0
  311. package/migrations/0001_initial.sql +59 -0
  312. package/migrations/0002_queue_status.sql +15 -0
  313. package/migrations/0003_work_item_base_branch.sql +14 -0
  314. package/migrations/0004_project_settings.sql +15 -0
  315. package/migrations/0005_global_settings.sql +34 -0
  316. package/migrations/0006_model_variants.sql +8 -0
  317. package/migrations/0007_container_error_logs.sql +21 -0
  318. package/migrations/0008_project_access_grants.sql +16 -0
  319. package/migrations/0009_drop_imported_legacy.sql +4 -0
  320. package/migrations/0010_container_error_log_model.sql +6 -0
  321. package/migrations/0011_container_error_log_title.sql +5 -0
  322. package/migrations/0012_pending_task_cancel.sql +6 -0
  323. package/migrations/0013_builder_image.sql +6 -0
  324. package/migrations/0014_build_workflow.sql +7 -0
  325. package/migrations/0015_access_rules.sql +24 -0
  326. package/migrations/0016_trigger_policy.sql +17 -0
  327. package/migrations/0017_attachment_upload.sql +8 -0
  328. package/migrations/0018_work_item_branch.sql +11 -0
  329. package/migrations/0019_auto_push_mr.sql +18 -0
  330. package/migrations/0020_outbound_webhooks.sql +47 -0
  331. package/migrations/0021_runtime_settings.sql +12 -0
  332. package/migrations/0022_auto_resolve_conflicts.sql +17 -0
  333. package/migrations/0023_ci_fail_auto_report.sql +27 -0
  334. package/migrations/0024_work_item_auto_override.sql +22 -0
  335. package/migrations/0025_run_history.sql +37 -0
  336. package/migrations/0026_run_history_task_seq.sql +6 -0
  337. package/migrations/0027_custom_repos.sql +11 -0
  338. package/migrations/0028_run_usage.sql +14 -0
  339. package/migrations/0029_drop_ocr_langs.sql +6 -0
  340. package/migrations/0030_mr_assignee.sql +9 -0
  341. package/migrations/0031_lsp_servers.sql +14 -0
  342. package/opencode-config/managed/devbot-agent-policy.md +61 -0
  343. package/opencode-config/managed/opencode.json +77 -0
  344. package/opencode-config/opencode.json +211 -0
  345. package/opencode-config/plugins/devbot-path-guard.js +224 -0
  346. package/package.json +157 -4
  347. package/public/assets/DashboardSidebarCollapse-rIuzCmVm.js +1 -0
  348. package/public/assets/DashboardToolbar-DFCUqZ4Z.js +1 -0
  349. package/public/assets/ErrorLogModal.vue_vue_type_script_setup_true_lang-BCyNIf1E.js +1 -0
  350. package/public/assets/ErrorLogsPage-DyYK2Rop.js +1 -0
  351. package/public/assets/LogSlideover.vue_vue_type_script_setup_true_lang-33xie7TE.js +1 -0
  352. package/public/assets/OverviewPage-CFfa0uwg.js +1 -0
  353. package/public/assets/PageGrid-CBROIU87.js +1 -0
  354. package/public/assets/PeriodRangePicker.vue_vue_type_script_setup_true_lang-DiFUNem7.js +1 -0
  355. package/public/assets/ProjectDetailPage-CreyvUit.js +1 -0
  356. package/public/assets/ProjectsPage-CFx8-elJ.js +1 -0
  357. package/public/assets/RunDetailSlideover.vue_vue_type_script_setup_true_lang-DopYYmCT.js +1 -0
  358. package/public/assets/RunsPage-CRnnXU4P.js +1 -0
  359. package/public/assets/Select-Bvx32Diz.js +1 -0
  360. package/public/assets/SelectMenu-BjMxc4VB.js +1 -0
  361. package/public/assets/SettingsPage-Bb6LM3wO.js +60 -0
  362. package/public/assets/TimeCell.vue_vue_type_script_setup_true_lang-DW_UB0Fu.js +1 -0
  363. package/public/assets/UsagePage-BLMDEsv-.js +332 -0
  364. package/public/assets/UsagePage-DodEeAjB.css +1 -0
  365. package/public/assets/VolumesPage-CxcLc3L2.js +1 -0
  366. package/public/assets/WebhookConfigPanel.vue_vue_type_script_setup_true_lang-B2V2GF6b.js +1 -0
  367. package/public/assets/WorkItemCell.vue_vue_type_script_setup_true_lang-BQn6vTjd.js +1 -0
  368. package/public/assets/index-BMbMibyb.js +4 -0
  369. package/public/assets/index-C5RBBrPj.js +30 -0
  370. package/public/assets/index-CgX29UgC.css +1 -0
  371. package/public/assets/usage-format-jsb31_O8.js +1 -0
  372. package/public/assets/useManagedProjects-8rtjRqVJ.js +1 -0
  373. package/public/assets/useRouteTab-DfwrcMic.js +1 -0
  374. package/public/favicon.ico +0 -0
  375. package/public/favicon.png +0 -0
  376. package/public/index.html +15 -0
@@ -0,0 +1,150 @@
1
+ import { z } from "zod";
2
+ import { logReq, requireSession } from "../http-util.js";
3
+ import { config } from "../config.js";
4
+ import { APP_VERSION } from "../version.js";
5
+ import { SESSION_COOKIE } from "../cookie.js";
6
+ import { getPlatform } from "../platform/index.js";
7
+ import { listTokens, countTokens, getToken, getProject, upsertToken, deleteToken } from "../token-store.js";
8
+ import { refreshManagedProjectPaths, MANAGED_REFRESH_DEADLINE_MS } from "../project-sync.js";
9
+ import { deleteAllMcpServers, deleteAllMcpAuth, deleteAllEnvVars, deleteAllProjectSettings, deleteAllAccessGrantsForProject, deleteAllAccessRulesForProject, deleteAllOutboundWebhooksForProject, deleteAllCustomRepos } from "./mcp-cleanup.js";
10
+ import { parseLimit, parseOffset, parseQuery } from "./query-params.js";
11
+ const OnboardBodySchema = z.object({
12
+ projects: z
13
+ .array(z.object({
14
+ id: z.number().int().positive(),
15
+ // Neutral project path from the Platform port's CandidateProject
16
+ // (`path`): GitLab path_with_namespace / Gitea full_name / GitHub
17
+ // owner/name. Matches `onboarding.*`'s `{ id, path }` signature.
18
+ path: z.string().min(1).max(255),
19
+ }))
20
+ .min(1)
21
+ .max(100),
22
+ });
23
+ export function mountAdminRoutes(app) {
24
+ app.get("/api/session", requireSession((req, res) => {
25
+ logReq(req, "debug", "session ok", { userId: req.session.userId });
26
+ return res.json({
27
+ user: { id: req.session.userId, username: req.session.username },
28
+ version: APP_VERSION,
29
+ });
30
+ }));
31
+ app.post("/api/logout", (req, res) => {
32
+ // ponytail: no session check — logout must work even if the cookie expired,
33
+ // so a stale session still clears itself.
34
+ res.clearCookie(SESSION_COOKIE, { path: "/" });
35
+ logReq(req, "info", "logout");
36
+ return res.status(204).end();
37
+ });
38
+ app.get("/api/projects", requireSession(async (req, res) => {
39
+ const q = req.query.q ?? "";
40
+ try {
41
+ const projects = await getPlatform().onboarding.listProjects(req.session.accessToken, q);
42
+ logReq(req, "debug", "list projects", { count: projects.length, q });
43
+ return res.json({ projects });
44
+ }
45
+ catch (e) {
46
+ logReq(req, "error", "list projects failed", { err: e, q });
47
+ return res.status(500).json({ error: "failed to list projects" });
48
+ }
49
+ }));
50
+ app.get("/api/managed", requireSession(async (req, res) => {
51
+ // Reconcile forge-side renames before rendering the list. The short deadline
52
+ // keeps a slow/unreachable forge from stalling the page; refresh never
53
+ // throws, so the list is always served (possibly with stale paths).
54
+ const limit = parseLimit(req.query.limit, 15, 100);
55
+ const offset = parseOffset(req.query.offset);
56
+ const q = parseQuery(req.query.q);
57
+ await refreshManagedProjectPaths({ deadlineMs: MANAGED_REFRESH_DEADLINE_MS });
58
+ const projects = listTokens(limit, offset, q);
59
+ const total = countTokens(q);
60
+ logReq(req, "debug", "list managed", { count: projects.length, total, limit, offset, q });
61
+ return res.json({ projects, total });
62
+ }));
63
+ app.post("/api/onboard", requireSession(async (req, res) => {
64
+ const parsed = OnboardBodySchema.safeParse(req.body);
65
+ if (!parsed.success) {
66
+ logReq(req, "warn", "onboard bad input", { issues: parsed.error.issues });
67
+ return res.status(400).json({ error: "bad request", issues: parsed.error.issues });
68
+ }
69
+ const results = [];
70
+ const platform = getPlatform();
71
+ for (const p of parsed.data.projects) {
72
+ try {
73
+ await platform.onboarding.addBot(req.session.accessToken, { id: p.id, path: p.path });
74
+ // Reuse the stored token so re-onboarding keeps the secret that the
75
+ // hook was created with. Forges that ignore secret updates
76
+ // (ForgeJo/Gitea) cannot be repaired later, so the persisted value and
77
+ // the forge's value must stay in lockstep.
78
+ const signingToken = getToken(p.id)?.signingToken ?? platform.ingress.generateWebhookSecret();
79
+ const { id: webhookId, created } = await platform.onboarding.findOrCreateWebhook(req.session.accessToken, { id: p.id, path: p.path }, `${config.PUBLIC_URL}/webhook`, signingToken);
80
+ // Created hooks already carry the secret; an existing hook needs an
81
+ // update. Drivers whose forge cannot change a secret after creation
82
+ // no-op with a warning (see docs/platforms.md).
83
+ if (!created) {
84
+ await platform.onboarding.setWebhookSecret(req.session.accessToken, { id: p.id, path: p.path }, webhookId, signingToken);
85
+ }
86
+ upsertToken({ projectId: p.id, projectPath: p.path, signingToken, webhookId });
87
+ try {
88
+ await platform.onboarding.testWebhook(req.session.accessToken, { id: p.id, path: p.path }, webhookId);
89
+ }
90
+ catch (e) {
91
+ logReq(req, "debug", "test webhook trigger failed", { projectId: p.id, err: e });
92
+ }
93
+ results.push({ ok: true, projectPath: p.path, created });
94
+ }
95
+ catch (e) {
96
+ // ponytail: generic error to client — forge error bodies can leak internal
97
+ // hostnames/paths; keep the full message server-side only.
98
+ logReq(req, "warn", "onboard project failed", { projectId: p.id, err: e });
99
+ results.push({ ok: false, projectPath: p.path, error: "forge request failed" });
100
+ }
101
+ }
102
+ const okCount = results.filter((r) => r.ok).length;
103
+ logReq(req, "info", "onboard", { count: results.length, okCount });
104
+ return res.json({ results });
105
+ }));
106
+ app.post("/api/revoke/:id", requireSession(async (req, res) => {
107
+ const projectId = Number(req.params.id ?? "");
108
+ if (!Number.isFinite(projectId) || !Number.isInteger(projectId) || projectId <= 0) {
109
+ logReq(req, "warn", "revoke bad id", { id: req.params.id });
110
+ return res.status(400).json({ error: "invalid project id" });
111
+ }
112
+ const project = getProject(projectId);
113
+ if (!project) {
114
+ logReq(req, "warn", "revoke not managed", { projectId });
115
+ return res.status(404).json({ error: "not managed" });
116
+ }
117
+ let ok = true;
118
+ let error;
119
+ try {
120
+ await getPlatform().onboarding.deleteWebhook(req.session.accessToken, { id: projectId, path: project.projectPath }, project.webhookId);
121
+ await getPlatform().onboarding.removeBot(req.session.accessToken, { id: projectId, path: project.projectPath });
122
+ }
123
+ catch (e) {
124
+ ok = false;
125
+ // ponytail: generic error to client — forge error bodies can leak internal
126
+ // hostnames/paths; keep the full message server-side only.
127
+ logReq(req, "warn", "revoke forge calls failed", { projectId, err: e });
128
+ error = "forge request failed";
129
+ }
130
+ finally {
131
+ // ponytail: delete token in finally so a half-revoked state still clears the
132
+ // local row; re-running revoke completes cleanup via the 404-as-success
133
+ // paths in deleteWebhook/removeBotFromProject.
134
+ deleteToken(projectId);
135
+ deleteAllMcpServers(projectId);
136
+ deleteAllMcpAuth(projectId);
137
+ deleteAllEnvVars(projectId);
138
+ deleteAllProjectSettings(projectId);
139
+ deleteAllAccessGrantsForProject(projectId);
140
+ deleteAllAccessRulesForProject(projectId);
141
+ deleteAllOutboundWebhooksForProject(projectId);
142
+ deleteAllCustomRepos(projectId);
143
+ }
144
+ logReq(req, "info", "revoke", { projectId, ok });
145
+ return res.json(ok
146
+ ? { ok: true, projectPath: project.projectPath, note: "revoked" }
147
+ : { ok: false, projectPath: project.projectPath, error: error ?? "unknown error" });
148
+ }));
149
+ }
150
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/admin/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { logReq, requireSession } from "../http-util.js";
2
+ import { getRunHistory } from "../run-history-store.js";
3
+ import { readArchivedLog } from "../run-log.js";
4
+ import { getProject } from "../token-store.js";
5
+ import { getPlatform } from "../platform/index.js";
6
+ // Run-history detail endpoint for the WebUI Runs page (work item #61). The list
7
+ // now comes from the unified GET /api/runs; this route serves one settled run's
8
+ // archived container log (a file on disk, referenced by run_history.log_file)
9
+ // rendered by the shared formatter. Session-gated like the other /api routes.
10
+ function projectWorkItemUrl(projectId, workItemNumber) {
11
+ return getPlatform().links.workItemUrl(getProject(projectId)?.projectPath ?? "", workItemNumber);
12
+ }
13
+ function parseIdParam(raw) {
14
+ const n = Number(Array.isArray(raw) ? raw[0] : raw);
15
+ return Number.isFinite(n) && Number.isInteger(n) && n > 0 ? n : null;
16
+ }
17
+ export function mountRunHistoryRoutes(app) {
18
+ app.get("/api/run-history/:id", requireSession((req, res) => {
19
+ const id = parseIdParam(req.params.id ?? "");
20
+ if (!id) {
21
+ logReq(req, "warn", "run history bad id", { id: req.params.id });
22
+ return res.status(400).json({ error: "invalid id" });
23
+ }
24
+ const row = getRunHistory(id);
25
+ if (!row) {
26
+ logReq(req, "debug", "run history not found", { id });
27
+ return res.status(404).json({ error: "not found" });
28
+ }
29
+ const archived = readArchivedLog(row.logFile);
30
+ logReq(req, "debug", "run history detail", { id, available: archived.available, reason: archived.reason });
31
+ return res.json({
32
+ run: {
33
+ ...row,
34
+ workItemUrl: projectWorkItemUrl(row.projectId, row.workItemIid),
35
+ projectPath: getProject(row.projectId)?.projectPath ?? "",
36
+ logs: archived.text,
37
+ truncated: archived.truncated,
38
+ logAvailable: archived.available,
39
+ logReason: archived.reason,
40
+ },
41
+ });
42
+ }));
43
+ }
44
+ //# sourceMappingURL=run-history-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-history-routes.js","sourceRoot":"","sources":["../../src/admin/run-history-routes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,gFAAgF;AAChF,gFAAgF;AAChF,8EAA8E;AAC9E,8EAA8E;AAE9E,SAAS,kBAAkB,CAAC,SAAiB,EAAE,cAAsB;IACnE,OAAO,WAAW,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,WAAW,IAAI,EAAE,EAAE,cAAc,CAAC,CAAC;AACnG,CAAC;AAED,SAAS,YAAY,CAAC,GAAY;IAChC,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,GAAoB;IACxD,GAAG,CAAC,GAAG,CAAC,sBAAsB,EAAE,cAAc,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC1D,MAAM,EAAE,GAAG,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,oBAAoB,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;YACjE,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,MAAM,GAAG,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;QAC9B,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,uBAAuB,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YACtD,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,oBAAoB,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC3G,OAAO,GAAG,CAAC,IAAI,CAAC;YACd,GAAG,EAAE;gBACH,GAAG,GAAG;gBACN,WAAW,EAAE,kBAAkB,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,WAAW,CAAC;gBAC/D,WAAW,EAAE,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,WAAW,IAAI,EAAE;gBACzD,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,SAAS,EAAE,QAAQ,CAAC,SAAS;gBAC7B,YAAY,EAAE,QAAQ,CAAC,SAAS;gBAChC,SAAS,EAAE,QAAQ,CAAC,MAAM;aAC3B;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,99 @@
1
+ import { logReq, requireSession } from "../http-util.js";
2
+ import { listInFlightDesc } from "../queue-store.js";
3
+ import { getProject } from "../token-store.js";
4
+ import { buildTaskViews, buildTaskQuota } from "../task-view.js";
5
+ import { globalQueueDepth, globalQueueMax, globalQueuePosition } from "../global-queue.js";
6
+ import { listRunHistoryBySeq, countRunHistory, listRunHistoryFilterOptions, } from "../run-history-store.js";
7
+ import { taskViewToRunView, historyToRunView, mergeRunViews, MAX_MERGE_WINDOW, } from "../run-view.js";
8
+ import { resolveModelForMode, resolveVariantForMode } from "../settings-store.js";
9
+ import { getPlatform } from "../platform/index.js";
10
+ import { resolveUsageWindow } from "../usage-stats.js";
11
+ import { matchesActiveRun, historyFilter, mergeFilterOptions, } from "../run-filters.js";
12
+ import { parseDateWindow, parseLimit, parseOffset, parsePositiveInt, parseQuery, parseString } from "./query-params.js";
13
+ // Unified runs listing for the WebUI Runs page (work item #61), with filters and
14
+ // work-item-title search (work item #88). One endpoint serves the in-flight
15
+ // queue, the settled run history, or both, merged on the shared task seq
16
+ // (seq DESC). `GET /api/tasks` and `GET /api/run-history` remain for the
17
+ // Overview recent-list and the existing clients.
18
+ function projectWorkItemUrl(projectId, workItemNumber) {
19
+ return getPlatform().links.workItemUrl(getProject(projectId)?.projectPath ?? "", workItemNumber);
20
+ }
21
+ function parseStatus(raw) {
22
+ const v = Array.isArray(raw) ? raw[0] : raw;
23
+ return v === "active" || v === "settled" || v === "errored" || v === "cancelled" ? v : "all";
24
+ }
25
+ // Build the TaskView projection once for either list function. Kept as a local
26
+ // so both the active and merged paths share the resolver wiring.
27
+ function viewsFor(rows) {
28
+ return buildTaskViews(rows, (projectId) => getProject(projectId)?.projectPath ?? "", (projectId, mode) => {
29
+ if (mode !== "plan" && mode !== "build")
30
+ return { model: "", variant: "" };
31
+ return {
32
+ model: resolveModelForMode(projectId, mode),
33
+ variant: resolveVariantForMode(projectId, mode),
34
+ };
35
+ }, projectWorkItemUrl, globalQueuePosition);
36
+ }
37
+ // A settled history row decorated with its project path + work item link.
38
+ function settledView(r) {
39
+ const v = historyToRunView(r);
40
+ v.projectPath = getProject(r.projectId)?.projectPath ?? "";
41
+ v.workItemUrl = projectWorkItemUrl(r.projectId, r.workItemIid);
42
+ return v;
43
+ }
44
+ export function mountRunRoutes(app) {
45
+ app.get("/api/runs", requireSession((req, res) => {
46
+ const status = parseStatus(req.query.status);
47
+ const limit = parseLimit(req.query.limit);
48
+ const offset = parseOffset(req.query.offset);
49
+ const quota = buildTaskQuota(globalQueueDepth(), globalQueueMax());
50
+ const projectId = parsePositiveInt(req.query.projectId);
51
+ const model = parseString(req.query.model);
52
+ const mode = parseString(req.query.mode);
53
+ const title = parseQuery(req.query.q);
54
+ const { days, from, to } = parseDateWindow(req.query);
55
+ const window = resolveUsageWindow({ days, ...(from !== undefined ? { from } : {}), ...(to !== undefined ? { to } : {}) }, Date.now());
56
+ const filters = {
57
+ ...(projectId !== undefined ? { projectId } : {}),
58
+ ...(model !== undefined ? { model } : {}),
59
+ ...(mode !== undefined ? { mode } : {}),
60
+ ...(title !== undefined ? { title } : {}),
61
+ window: { start: window.windowStart, end: window.windowEnd },
62
+ };
63
+ // In-flight rows are few (bounded by the queue); build them once for both
64
+ // the active listing and the filter-option union.
65
+ const activeViews = viewsFor(listInFlightDesc()).map(taskViewToRunView);
66
+ const filterOptions = mergeFilterOptions(listRunHistoryFilterOptions(), activeViews);
67
+ const projectPaths = {};
68
+ for (const p of filterOptions.projects)
69
+ projectPaths[String(p)] = getProject(p)?.projectPath ?? `#${p}`;
70
+ let runs;
71
+ let total;
72
+ if (status === "active") {
73
+ // Filters need the full set before slicing; build the views, filter, page.
74
+ const filtered = activeViews.filter((v) => matchesActiveRun(v, filters));
75
+ total = filtered.length;
76
+ runs = filtered.slice(offset, offset + limit);
77
+ }
78
+ else if (status === "settled" || status === "errored" || status === "cancelled") {
79
+ const hf = historyFilter(filters, status);
80
+ runs = listRunHistoryBySeq(limit, offset, hf).map(settledView);
81
+ total = countRunHistory(hf);
82
+ }
83
+ else {
84
+ // Merged: filter each source first (settled in SQL, active in memory),
85
+ // then merge. A seq can appear in both during the settle race, so the
86
+ // reachable total is the merged length, not the naive sum. Fetched within
87
+ // the capped merge window, then sliced.
88
+ const cap = MAX_MERGE_WINDOW;
89
+ const settled = listRunHistoryBySeq(cap, 0, historyFilter(filters, "all")).map(settledView);
90
+ const active = activeViews.filter((v) => matchesActiveRun(v, filters)).slice(0, cap);
91
+ const mergedAll = mergeRunViews(active, settled, cap, 0);
92
+ total = mergedAll.length;
93
+ runs = mergedAll.slice(offset, offset + limit);
94
+ }
95
+ logReq(req, "debug", "list runs", { status, count: runs.length, total, limit, offset });
96
+ return res.json({ runs, total, quota, filterOptions, projectPaths });
97
+ }));
98
+ }
99
+ //# sourceMappingURL=run-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-routes.js","sourceRoot":"","sources":["../../src/admin/run-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ import { logReq, requireSession } from "../http-util.js";
2
+ import { getProject } from "../token-store.js";
3
+ import { getProjectSettings, upsertProjectSettings } from "../settings-store.js";
4
+ import { ProjectSettingsSchema } from "../types/project-settings.js";
5
+ import { getGlobalSettings } from "../global-settings-store.js";
6
+ import { DEFAULT_BUILD_WORKFLOW_TEMPLATE, DEFAULT_MR_DESCRIPTION_TEMPLATE } from "../build-workflow.js";
7
+ import { config } from "../config.js";
8
+ import { getPlatform } from "../platform/index.js";
9
+ import { log } from "../logger.js";
10
+ import { validateAssigneeUsername } from "../mr-assignee.js";
11
+ // Merge the forge's CI-failure webhook event into the project's hook when the
12
+ // toggle is switched on. Best-effort: a forge failure must not block the
13
+ // settings save, but the caller surfaces the warning so the admin can re-onboard.
14
+ async function enableCiFailureEvents(req, projectId) {
15
+ const project = getProject(projectId);
16
+ const accessToken = req.session.accessToken;
17
+ if (!project || !accessToken)
18
+ return "not managed or no session";
19
+ try {
20
+ await getPlatform().onboarding.ensureCiFailureEvents(accessToken, { id: projectId, path: project.projectPath }, project.webhookId);
21
+ return undefined;
22
+ }
23
+ catch (e) {
24
+ log.warn("ensureCiFailureEvents failed", { projectId, err: e });
25
+ return "could not update the forge webhook — re-onboard the project to enable CI events";
26
+ }
27
+ }
28
+ function parseProjectIdParam(raw) {
29
+ const id = Number(Array.isArray(raw) ? raw[0] : raw);
30
+ return Number.isFinite(id) && Number.isInteger(id) && id > 0 ? id : null;
31
+ }
32
+ // Global defaults shown as placeholders in the panel. builderImage falls back to
33
+ // the BUILDER_IMAGE env var when the global setting is unset, so the placeholder
34
+ // always shows the image a run would actually use. buildWorkflow/mrDescription
35
+ // fall back to the built-in templates so "Load default" always yields usable text.
36
+ function globalDefaults() {
37
+ const g = getGlobalSettings();
38
+ return {
39
+ planModel: g.planModel,
40
+ buildModel: g.buildModel,
41
+ planVariant: g.planVariant,
42
+ buildVariant: g.buildVariant,
43
+ plugins: g.plugins,
44
+ baseBranches: g.baseBranches,
45
+ builderImage: g.builderImage || config.BUILDER_IMAGE,
46
+ assignee: g.assignee,
47
+ buildWorkflow: g.buildWorkflow || DEFAULT_BUILD_WORKFLOW_TEMPLATE,
48
+ mrDescription: g.mrDescription || DEFAULT_MR_DESCRIPTION_TEMPLATE,
49
+ minRole: g.minRole,
50
+ requireAuthorOrAssignee: g.requireAuthorOrAssignee ? "true" : "false",
51
+ autoPush: g.autoPush ? "true" : "false",
52
+ autoMr: g.autoMr ? "true" : "false",
53
+ autoResolveConflicts: g.autoResolveConflicts ? "true" : "false",
54
+ ciFailAutoReport: g.ciFailAutoReport ? "true" : "false",
55
+ lspServers: g.lspServers.join(","),
56
+ lspDisabled: "",
57
+ };
58
+ }
59
+ export function mountSettingsRoutes(app) {
60
+ // GET /api/projects/:id/settings — effective values + global defaults.
61
+ app.get("/api/projects/:id/settings", requireSession((req, res) => {
62
+ const projectId = parseProjectIdParam(req.params.id ?? "");
63
+ if (!projectId) {
64
+ logReq(req, "warn", "settings route bad id", { id: req.params.id });
65
+ return res.status(400).json({ error: "invalid project id" });
66
+ }
67
+ if (!getProject(projectId)) {
68
+ logReq(req, "warn", "settings route not managed", { projectId });
69
+ return res.status(404).json({ error: "not managed" });
70
+ }
71
+ const settings = getProjectSettings(projectId) ?? {
72
+ planModel: "", buildModel: "", planVariant: "", buildVariant: "", plugins: "", baseBranches: "", lspServers: "", lspDisabled: "", builderImage: "", buildWorkflow: "", mrDescription: "", minRole: "", requireAuthorOrAssignee: "", autoPush: "", autoMr: "", autoResolveConflicts: "", ciFailAutoReport: "", assignee: "",
73
+ };
74
+ logReq(req, "debug", "get settings", { projectId });
75
+ return res.json({ settings, defaults: globalDefaults() });
76
+ }));
77
+ // PUT /api/projects/:id/settings — whole-object upsert. "" = inherit.
78
+ app.put("/api/projects/:id/settings", requireSession(async (req, res) => {
79
+ const projectId = parseProjectIdParam(req.params.id ?? "");
80
+ if (!projectId) {
81
+ logReq(req, "warn", "settings route bad id", { id: req.params.id });
82
+ return res.status(400).json({ error: "invalid project id" });
83
+ }
84
+ if (!getProject(projectId)) {
85
+ logReq(req, "warn", "settings route not managed", { projectId });
86
+ return res.status(404).json({ error: "not managed" });
87
+ }
88
+ const parsed = ProjectSettingsSchema.safeParse(req.body);
89
+ if (!parsed.success) {
90
+ logReq(req, "warn", "settings put bad body", { projectId, issues: parsed.error.issues });
91
+ return res.status(400).json({ error: "bad request", issues: parsed.error.issues });
92
+ }
93
+ if (parsed.data.assignee && parsed.data.assignee !== "none") {
94
+ const check = await validateAssigneeUsername(parsed.data.assignee);
95
+ if (check !== "ok") {
96
+ logReq(req, "warn", "settings put bad assignee", { projectId, assignee: parsed.data.assignee, check });
97
+ return res.status(check === "unknown" ? 400 : 502).json(check === "unknown"
98
+ ? { error: "bad request", issues: [{ path: ["assignee"], message: `unknown forge user @${parsed.data.assignee}` }] }
99
+ : { error: "forge lookup failed" });
100
+ }
101
+ }
102
+ upsertProjectSettings(projectId, parsed.data);
103
+ // When the CI-failure toggle is explicitly turned on, make sure the forge
104
+ // webhook is subscribed to CI events. The bot token cannot manage hooks, so
105
+ // this uses the signed-in user's OAuth token. Best-effort: a warning is
106
+ // returned rather than failing the save.
107
+ let ciEventsWarning;
108
+ if (parsed.data.ciFailAutoReport === "true") {
109
+ ciEventsWarning = await enableCiFailureEvents(req, projectId);
110
+ }
111
+ logReq(req, "info", "upsert settings", { projectId, ciEventsWarning });
112
+ return res.json({
113
+ ok: true,
114
+ settings: parsed.data,
115
+ ...(ciEventsWarning ? { warnings: { ciFailAutoReport: ciEventsWarning } } : {}),
116
+ });
117
+ }));
118
+ }
119
+ //# sourceMappingURL=settings-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-routes.js","sourceRoot":"","sources":["../../src/admin/settings-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { logReq, requireSession } from "../http-util.js";
2
+ import { listUsageRows } from "../run-history-store.js";
3
+ import { computeUsageStats, resolveUsageWindow } from "../usage-stats.js";
4
+ import { getProject } from "../token-store.js";
5
+ import { parseDateWindow, parseLimit, parseOffset, parsePositiveInt, parseString } from "./query-params.js";
6
+ // Token-usage dashboard endpoint (work item #66). Reads settled-run usage from
7
+ // run_history, aggregates in a pure module, and returns totals, a daily series,
8
+ // breakdowns, and the filter option lists the page's dropdowns need.
9
+ export function mountStatsRoutes(app) {
10
+ app.get("/api/stats/usage", requireSession((req, res) => {
11
+ const projectId = parsePositiveInt(req.query.projectId);
12
+ const model = parseString(req.query.model);
13
+ const mode = parseString(req.query.mode);
14
+ // A custom range (#77) needs both ends; otherwise fall back to `days`.
15
+ const { days, from, to } = parseDateWindow(req.query);
16
+ const filters = {
17
+ days,
18
+ ...(from !== undefined ? { from } : {}),
19
+ ...(to !== undefined ? { to } : {}),
20
+ ...(projectId !== undefined ? { projectId } : {}),
21
+ ...(model !== undefined ? { model } : {}),
22
+ ...(mode !== undefined ? { mode } : {}),
23
+ };
24
+ const now = Date.now();
25
+ // Fetch the previous window too so period-over-period deltas can be computed
26
+ // in the same pass.
27
+ const prevStart = resolveUsageWindow(filters, now).prevStart;
28
+ const rows = listUsageRows(prevStart);
29
+ const stats = computeUsageStats(rows, filters, now);
30
+ // Paginate the three list sections server-side. The aggregate already
31
+ // carried full totals (recentTotal/byModelTotal/byProjectTotal) before we
32
+ // slice, so the UI can size its pagers. `byMode` stays un-paginated.
33
+ const recentLimit = parseLimit(req.query.recentLimit);
34
+ const recentOffset = parseOffset(req.query.recentOffset);
35
+ const byModelLimit = parseLimit(req.query.byModelLimit);
36
+ const byModelOffset = parseOffset(req.query.byModelOffset);
37
+ const byProjectLimit = parseLimit(req.query.byProjectLimit);
38
+ const byProjectOffset = parseOffset(req.query.byProjectOffset);
39
+ stats.recent = stats.recent.slice(recentOffset, recentOffset + recentLimit);
40
+ stats.byModel = stats.byModel.slice(byModelOffset, byModelOffset + byModelLimit);
41
+ stats.byProject = stats.byProject.slice(byProjectOffset, byProjectOffset + byProjectLimit);
42
+ // A display-name map for the breakdown/recent tables; the aggregator stays
43
+ // free of token-store imports so it remains unit-testable.
44
+ const projectPaths = {};
45
+ for (const p of stats.filterOptions.projects)
46
+ projectPaths[String(p)] = getProject(p)?.projectPath ?? `#${p}`;
47
+ logReq(req, "debug", "usage stats", { days, projectId: filters.projectId, runs: stats.totals.runs });
48
+ return res.json({ stats, projectPaths });
49
+ }));
50
+ }
51
+ //# sourceMappingURL=stats-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats-routes.js","sourceRoot":"","sources":["../../src/admin/stats-routes.ts"],"names":[],"mappings":"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"}