@wascartech/devbot 0.0.0-stage → 2.1.1

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 +150 -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 +438 -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 +158 -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,251 @@
1
+ import { z } from "zod";
2
+ // ---- Webhook payloads -------------------------------------------------------
3
+ const projectSchema = z.object({
4
+ id: z.number().int(),
5
+ path_with_namespace: z.string(),
6
+ git_http_url: z.string().url().refine((u) => /^https?:\/\//i.test(u), "must be http(s)"),
7
+ default_branch: z.string().nullable(),
8
+ web_url: z.string(),
9
+ });
10
+ const userSchema = z.object({
11
+ id: z.number().int(),
12
+ username: z.string(),
13
+ name: z.string(),
14
+ });
15
+ // Work item reference embedded in Note Hook payloads. The JSON key is `issue`
16
+ // (GitLab's wire name — Note Hook only fires for issue-type work items among
17
+ // the work item family; non-issue work item comments do not arrive via Note
18
+ // Hook). We keep the field name `issue` to match the wire; the TS type is
19
+ // named WorkItemRef.
20
+ export const workItemRefSchema = z.object({
21
+ id: z.number().int(),
22
+ iid: z.number().int(),
23
+ title: z.string(),
24
+ // GitLab sends `null` (not "") for a work item created without a
25
+ // description — the REST API does the same. Typed nullable here and
26
+ // normalized to "" by the ingress, matching the GitHub/Gitea adapters.
27
+ description: z.string().nullish(),
28
+ url: z.string().url(),
29
+ });
30
+ // Note Hook: comment on a work item. GitLab's noteable_type is "Issue" for
31
+ // issue-type work items (the only work item type that triggers Note Hook).
32
+ // ponytail: noteable_type literal "Issue" is GitLab's wire value, not our
33
+ // concept. Note Hook does not fire for non-issue work item types (task,
34
+ // epic, etc.); their comments would arrive through different event shapes
35
+ // GitLab does not currently emit. Revisit when GitLab extends Note Hook.
36
+ export const NoteHookPayloadSchema = z.object({
37
+ object_kind: z.literal("note"),
38
+ event_type: z.literal("note"),
39
+ user: userSchema,
40
+ project: projectSchema,
41
+ object_attributes: z.object({
42
+ id: z.number().int(),
43
+ note: z.string(),
44
+ noteable_type: z.literal("Issue"),
45
+ author_id: z.number().int(),
46
+ action: z.enum(["create", "update"]),
47
+ url: z.string(),
48
+ }),
49
+ issue: workItemRefSchema,
50
+ });
51
+ // Work Item Hook: work item created/opened. object_kind is "issue" for issues,
52
+ // "work_item" for all other work item types (task, test_case, epic, ...).
53
+ // object_attributes.type carries the work item type ("Issue", "Task", ...).
54
+ export const WorkItemHookPayloadSchema = z.object({
55
+ object_kind: z.literal("issue").or(z.literal("work_item")),
56
+ event_type: z.literal("issue").or(z.literal("work_item")),
57
+ user: userSchema,
58
+ project: projectSchema,
59
+ object_attributes: z.object({
60
+ id: z.number().int(),
61
+ iid: z.number().int(),
62
+ title: z.string(),
63
+ // Same wire quirk as workItemRefSchema: `null` for an empty description.
64
+ description: z.string().nullish(),
65
+ action: z.enum(["open", "close", "reopen", "update"]),
66
+ url: z.string().url(),
67
+ type: z.string().optional(),
68
+ }),
69
+ });
70
+ // Pipeline Hook: a CI pipeline changes status. Only a terminal `failed` status
71
+ // is interesting to DevBot. `merge_request` is present when the pipeline ran
72
+ // for an MR (not every pipeline does); its source_branch lets the handler match
73
+ // the DevBot-created MR registry without a branch-name convention.
74
+ export const PipelineHookPayloadSchema = z.object({
75
+ object_kind: z.literal("pipeline"),
76
+ user: userSchema.optional(),
77
+ project: projectSchema,
78
+ object_attributes: z.object({
79
+ id: z.number().int(),
80
+ status: z.string(),
81
+ ref: z.string(),
82
+ sha: z.string().optional(),
83
+ }),
84
+ merge_request: z
85
+ .object({
86
+ iid: z.number().int(),
87
+ source_branch: z.string(),
88
+ })
89
+ .optional(),
90
+ });
91
+ // ---- GitLab REST API responses ---------------------------------------------
92
+ export const NoteSchema = z.object({
93
+ id: z.number().int(),
94
+ body: z.string(),
95
+ });
96
+ // Issue note as returned by GET /projects/:id/issues/:iid/notes. Richer than
97
+ // the NoteSchema above (which is the minimal shape for POST's return value):
98
+ // the list response carries author + system + created_at. Fields optional
99
+ // defensively — GitLab has historically omitted fields in some contexts; the
100
+ // bot's logic needs only id, body, author.id.
101
+ export const IssueNoteSchema = z.object({
102
+ id: z.number().int(),
103
+ body: z.string(),
104
+ system: z.boolean().optional(),
105
+ author: z
106
+ .object({
107
+ id: z.number().int(),
108
+ username: z.string(),
109
+ name: z.string(),
110
+ })
111
+ .optional(),
112
+ created_at: z.string().optional(),
113
+ });
114
+ export const MergeRequestSchema = z.object({
115
+ id: z.number().int(),
116
+ iid: z.number().int(),
117
+ source_branch: z.string(),
118
+ target_branch: z.string(),
119
+ state: z.string(),
120
+ web_url: z.string(),
121
+ });
122
+ // GET /projects/:id/members/all/:user_id — inherited membership (resolves
123
+ // group-level roles). Only the fields the trigger-authorization gate needs:
124
+ // the user's effective access_level in the project (10 Guest, 20 Reporter,
125
+ // 30 Developer, 40 Maintainer, 50 Owner). 404 = not a member at all → deny.
126
+ export const ProjectMemberSchema = z.object({
127
+ id: z.number().int(),
128
+ access_level: z.number().int(),
129
+ });
130
+ // GET /users?username=<login> — used to resolve a access rule's username
131
+ // to its stable numeric id at add time. GitLab returns an array; an exact-match
132
+ // entry is picked by the caller.
133
+ export const UserLookupSchema = z.object({
134
+ id: z.number().int(),
135
+ username: z.string(),
136
+ name: z.string(),
137
+ });
138
+ // GET /projects/:id/issues/:iid/discussions — used by findNoteDiscussionId to
139
+ // map a triggering note id → its discussion id (so a Step-0 error reply can be
140
+ // posted in the same thread as the mention). Only the id of each note in a
141
+ // discussion is needed for the lookup.
142
+ const DiscussionNoteRefSchema = z.object({ id: z.number().int() });
143
+ export const DiscussionSchema = z.object({
144
+ id: z.string(),
145
+ notes: z.array(DiscussionNoteRefSchema),
146
+ });
147
+ // Single issue as returned by GET /projects/:id/issues/:iid. Only the fields
148
+ // the reset authorization check needs (author + assignees). GitLab returns
149
+ // `assignees` as an array (multi-assignee); `assignee` singular is deprecated.
150
+ // Not admin-only — works with the bot's project-scoped token.
151
+ export const IssueDetailSchema = z.object({
152
+ id: z.number().int(),
153
+ iid: z.number().int(),
154
+ author: z.object({ id: z.number().int() }),
155
+ assignees: z.array(z.object({ id: z.number().int() })).optional(),
156
+ });
157
+ // ---- MCP tool response schemas ---------------------------------------------
158
+ // Returned by GET /projects/:id/issues (list) and GET /projects/:id/issues/:iid
159
+ // (single). Carry the fields an agent working on a work item needs to triage
160
+ // and act: identity, state, content, links, labels, assignees. Fields optional
161
+ // defensively because GitLab omits some on higher tiers / older instances; the
162
+ // MCP tools only read what's present, never assume a field is set.
163
+ const gitlabUserBrief = z.object({
164
+ id: z.number().int(),
165
+ username: z.string(),
166
+ name: z.string(),
167
+ web_url: z.string().optional(),
168
+ });
169
+ export const IssueListItemSchema = z.object({
170
+ id: z.number().int(),
171
+ iid: z.number().int(),
172
+ title: z.string(),
173
+ description: z.string().nullish(),
174
+ state: z.string(),
175
+ web_url: z.string(),
176
+ labels: z.array(z.string()).optional(),
177
+ assignees: z.array(gitlabUserBrief).optional(),
178
+ author: gitlabUserBrief.optional(),
179
+ created_at: z.string().optional(),
180
+ updated_at: z.string().optional(),
181
+ closed_at: z.string().nullable().optional(),
182
+ due_date: z.string().nullable().optional(),
183
+ milestone: z
184
+ .object({ id: z.number().int(), title: z.string() })
185
+ .nullable()
186
+ .optional(),
187
+ references: z
188
+ .object({ short: z.string(), relative: z.string(), full: z.string() })
189
+ .optional(),
190
+ user_notes_count: z.number().int().optional(),
191
+ confidential: z.boolean().optional(),
192
+ });
193
+ export const MergeRequestListItemSchema = z.object({
194
+ id: z.number().int(),
195
+ iid: z.number().int(),
196
+ title: z.string(),
197
+ description: z.string().optional(),
198
+ state: z.string(),
199
+ web_url: z.string(),
200
+ source_branch: z.string().optional(),
201
+ target_branch: z.string().optional(),
202
+ labels: z.array(z.string()).optional(),
203
+ author: gitlabUserBrief.optional(),
204
+ assignees: z.array(gitlabUserBrief).optional(),
205
+ created_at: z.string().optional(),
206
+ updated_at: z.string().optional(),
207
+ merged_at: z.string().nullable().optional(),
208
+ draft: z.boolean().optional(),
209
+ references: z
210
+ .object({ short: z.string(), relative: z.string(), full: z.string() })
211
+ .optional(),
212
+ user_notes_count: z.number().int().optional(),
213
+ });
214
+ // GET /projects/:id/merge_requests/:iid/discussions — MR discussions include
215
+ // diff-anchored annotations (DiffNote with position), general threads
216
+ // (DiscussionNote), and system notes. Richer than the issue-only DiscussionSchema
217
+ // above (which is minimal on purpose for the note→discussion lookup): this one
218
+ // carries the fields an agent reviewing an MR needs — resolution state, diff
219
+ // position, code suggestions, author. Fields optional defensively because
220
+ // GitLab omits some on higher tiers / older instances (same convention as the
221
+ // list-item schemas). Reuses gitlabUserBrief for author / resolved_by.
222
+ const MergeRequestNoteSchema = z.object({
223
+ id: z.number().int(),
224
+ type: z.string().nullable().optional(),
225
+ body: z.string(),
226
+ system: z.boolean().optional(),
227
+ author: gitlabUserBrief.optional(),
228
+ created_at: z.string().optional(),
229
+ updated_at: z.string().optional(),
230
+ resolvable: z.boolean().optional(),
231
+ resolved: z.boolean().optional(),
232
+ resolved_by: gitlabUserBrief.nullable().optional(),
233
+ resolved_at: z.string().nullable().optional(),
234
+ position: z.record(z.string(), z.unknown()).optional(),
235
+ suggestions: z.array(z.record(z.string(), z.unknown())).optional(),
236
+ });
237
+ export const MergeRequestDiscussionSchema = z.object({
238
+ id: z.string(),
239
+ individual_note: z.boolean().optional(),
240
+ notes: z.array(MergeRequestNoteSchema),
241
+ });
242
+ // Markdown uploads API response (POST /projects/:id/uploads). `markdown` is the
243
+ // server-rendered reference; `full_path` is the host-absolute path.
244
+ export const UploadSchema = z.object({
245
+ id: z.number().int().optional(),
246
+ alt: z.string().optional(),
247
+ url: z.string(),
248
+ full_path: z.string().optional(),
249
+ markdown: z.string(),
250
+ });
251
+ //# sourceMappingURL=schemas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../../src/platform/gitlab/schemas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { createHmac, timingSafeEqual } from "node:crypto";
2
+ // ponytail: 5-minute replay guard. Standard Webhooks spec recommends a
3
+ // tolerance window; 300s is the spec default. Tighten if a clock-skewed
4
+ // GitLab instance delivers legitimately late, loosen if replay attacks
5
+ // matter more. Upgrade path: store seen webhook-id values for the window.
6
+ const MAX_SKEW_SEC = 300;
7
+ function b64decode(s) {
8
+ return Buffer.from(s, "base64");
9
+ }
10
+ export function b64encode(buf) {
11
+ return buf.toString("base64");
12
+ }
13
+ function headerString(headers, name) {
14
+ const v = headers[name.toLowerCase()];
15
+ if (Array.isArray(v))
16
+ return v[0];
17
+ return v;
18
+ }
19
+ export function verifyWebhookSignature(signingToken, headers, rawBody, nowMs) {
20
+ const sigHeader = headerString(headers, "webhook-signature");
21
+ const id = headerString(headers, "webhook-id");
22
+ const ts = headerString(headers, "webhook-timestamp");
23
+ if (!sigHeader || !id || !ts)
24
+ return false;
25
+ const tsNum = Number(ts);
26
+ if (!Number.isFinite(tsNum))
27
+ return false;
28
+ const skew = Math.abs(Math.floor(nowMs / 1000) - tsNum);
29
+ if (skew > MAX_SKEW_SEC)
30
+ return false;
31
+ if (!signingToken.startsWith("whsec_"))
32
+ return false;
33
+ let key;
34
+ try {
35
+ key = b64decode(signingToken.slice("whsec_".length));
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ const message = `${id}.${ts}.${rawBody.toString("utf8")}`;
41
+ const digest = createHmac("sha256", key).update(message).digest();
42
+ const expected = Buffer.from(`v1,${b64encode(digest)}`);
43
+ for (const part of sigHeader.split(" ")) {
44
+ const got = Buffer.from(part);
45
+ // ponytail: length-check-before-compare is accepted per Standard Webhooks
46
+ // spec; the length leak is negligible (expected length is fixed per key).
47
+ if (got.length === expected.length && timingSafeEqual(got, expected))
48
+ return true;
49
+ }
50
+ return false;
51
+ }
52
+ //# sourceMappingURL=signature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.js","sourceRoot":"","sources":["../../../src/platform/gitlab/signature.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE1D,uEAAuE;AACvE,0EAA0E;AAC1E,yEAAyE;AACzE,4EAA4E;AAC5E,MAAM,YAAY,GAAG,GAAG,CAAC;AAEzB,SAAS,SAAS,CAAC,CAAS;IAC1B,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,OAAO,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,YAAY,CAAC,OAAsD,EAAE,IAAY;IACxF,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACtC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,YAAoB,EACpB,OAAsD,EACtD,OAAe,EACf,KAAa;IAEb,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;IAC7D,MAAM,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC/C,MAAM,EAAE,GAAG,YAAY,CAAC,OAAO,EAAE,mBAAmB,CAAC,CAAC;IACtD,IAAI,CAAC,SAAS,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC;IAE3C,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;IACzB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;IACxD,IAAI,IAAI,GAAG,YAAY;QAAE,OAAO,KAAK,CAAC;IAEtC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACrD,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,OAAO,GAAG,GAAG,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;IAC1D,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC;IAClE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAExD,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,0EAA0E;QAC1E,4EAA4E;QAC5E,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,eAAe,CAAC,GAAG,EAAE,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;IACpF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,38 @@
1
+ // Platform factory: returns the singleton driver selected by config.PLATFORM.
2
+ // One DevBot process talks to exactly one forge instance.
3
+ import { config } from "../config.js";
4
+ import { gitlabPlatform } from "./gitlab/index.js";
5
+ import { forgejoPlatform } from "./gitealike/forgejo.js";
6
+ import { giteaPlatform } from "./gitealike/gitea.js";
7
+ import { createGithubPlatform } from "./github/index.js";
8
+ let cached;
9
+ export function getPlatform() {
10
+ if (cached)
11
+ return cached;
12
+ switch (config.PLATFORM) {
13
+ case "forgejo":
14
+ cached = forgejoPlatform;
15
+ break;
16
+ case "gitea":
17
+ cached = giteaPlatform;
18
+ break;
19
+ case "github":
20
+ cached = createGithubPlatform();
21
+ break;
22
+ case "gitlab":
23
+ default:
24
+ cached = gitlabPlatform;
25
+ break;
26
+ }
27
+ return cached;
28
+ }
29
+ /** Test hook: reset the memoized driver. */
30
+ export function resetPlatformForTest() {
31
+ cached = undefined;
32
+ }
33
+ /** Test hook: force a specific driver (e.g. exercise a forge's typed gap in a
34
+ * suite whose PLATFORM env selects a different forge). */
35
+ export function setPlatformForTest(platform) {
36
+ cached = platform;
37
+ }
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/platform/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0DAA0D;AAE1D,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAEzD,IAAI,MAA4B,CAAC;AAEjC,MAAM,UAAU,WAAW;IACzB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,SAAS;YACZ,MAAM,GAAG,eAAe,CAAC;YACzB,MAAM;QACR,KAAK,OAAO;YACV,MAAM,GAAG,aAAa,CAAC;YACvB,MAAM;QACR,KAAK,QAAQ;YACX,MAAM,GAAG,oBAAoB,EAAE,CAAC;YAChC,MAAM;QACR,KAAK,QAAQ,CAAC;QACd;YACE,MAAM,GAAG,cAAc,CAAC;YACxB,MAAM;IACV,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,oBAAoB;IAClC,MAAM,GAAG,SAAS,CAAC;AACrB,CAAC;AAED;2DAC2D;AAC3D,MAAM,UAAU,kBAAkB,CAAC,QAAkB;IACnD,MAAM,GAAG,QAAQ,CAAC;AACpB,CAAC"}
@@ -0,0 +1,26 @@
1
+ // The Platform port: one aggregate interface assembled from capability
2
+ // sub-interfaces. Callers depend on the port (via `getPlatform()`), never on a
3
+ // specific forge. GitLab, ForgeJo and Gitea each implement it.
4
+ export const CAPABILITY_METHODS = {
5
+ ingress: ["eventName", "projectIdFromBody", "deliveryId", "verifySignature", "parseWebhook", "generateWebhookSecret"],
6
+ workItems: [
7
+ "postComment", "replyInThread", "postErrorReply", "listComments", "getWorkItem",
8
+ "getWorkItemStateOrNull", "getMemberPermission", "resolveUser", "searchUsers", "listWorkItems",
9
+ "getWorkItemSummary", "listCommentsFull", "listLabels", "listMilestones",
10
+ ],
11
+ changeRequests: ["list", "create", "update", "get", "listReviewDiscussions", "listNotes"],
12
+ repository: [
13
+ "getRepo", "branchExists", "firstExistingBranch", "listBranches", "listTree", "getFile",
14
+ "listCommits", "getCommit", "compare", "listTags", "listMembers", "listReleases",
15
+ "listWikiPages", "getWikiPage", "searchProject",
16
+ ],
17
+ ci: ["listPipelines", "getPipeline", "listPipelineJobs", "getJobLog"],
18
+ gitAuth: ["gitExtraHeader", "cloneUrl"],
19
+ attachments: ["findRefs", "download", "upload"],
20
+ onboarding: [
21
+ "authorizeUrl", "exchangeCode", "currentUser", "listProjects", "addBot", "removeBot",
22
+ "findOrCreateWebhook", "setWebhookSecret", "ensureCiFailureEvents", "deleteWebhook", "testWebhook",
23
+ ],
24
+ links: ["workItemUrl"],
25
+ };
26
+ //# sourceMappingURL=port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"port.js","sourceRoot":"","sources":["../../src/platform/port.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,+EAA+E;AAC/E,+DAA+D;AAgT/D,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,OAAO,EAAE,CAAC,WAAW,EAAE,mBAAmB,EAAE,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,uBAAuB,CAAC;IACrH,SAAS,EAAE;QACT,aAAa,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,aAAa;QAC/E,wBAAwB,EAAE,qBAAqB,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe;QAC9F,oBAAoB,EAAE,kBAAkB,EAAE,YAAY,EAAE,gBAAgB;KACzE;IACD,cAAc,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,uBAAuB,EAAE,WAAW,CAAC;IACzF,UAAU,EAAE;QACV,SAAS,EAAE,cAAc,EAAE,qBAAqB,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS;QACvF,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc;QAChF,eAAe,EAAE,aAAa,EAAE,eAAe;KAChD;IACD,EAAE,EAAE,CAAC,eAAe,EAAE,aAAa,EAAE,kBAAkB,EAAE,WAAW,CAAC;IACrE,OAAO,EAAE,CAAC,gBAAgB,EAAE,UAAU,CAAC;IACvC,WAAW,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC;IAC/C,UAAU,EAAE;QACV,cAAc,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAE,WAAW;QACpF,qBAAqB,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,eAAe,EAAE,aAAa;KACnG;IACD,KAAK,EAAE,CAAC,aAAa,CAAC;CACkB,CAAC"}
@@ -0,0 +1,80 @@
1
+ // Platform-neutral domain types for the DevBot forge abstraction.
2
+ //
3
+ // Every driver (GitLab, ForgeJo, Gitea) speaks in these shapes. Callers
4
+ // (webhook, runner, MCP tools) depend on these — never on a forge's wire
5
+ // format. The property that names a project-internal work item number is
6
+ // `number` (GitLab calls it `iid`; Gitea/ForgeJo call it `number`).
7
+ /** Stream-side tail accumulator. Retains only the last `maxBytes` bytes seen
8
+ * while counting the total, so a full-read of an over-cap log stays bounded
9
+ * in memory. Used by the drivers' raw fetchers in `overflow: "tail"` mode. */
10
+ export class TailAccumulator {
11
+ maxBytes;
12
+ chunks = [];
13
+ len = 0;
14
+ total = 0;
15
+ constructor(maxBytes) {
16
+ this.maxBytes = maxBytes;
17
+ }
18
+ push(value) {
19
+ this.total += value.byteLength;
20
+ this.chunks.push(Buffer.from(value));
21
+ this.len += value.byteLength;
22
+ // Compact once we hold ~2× the cap so the chunk list cannot grow without
23
+ // bound on a very large stream; keeps the retained window to the last cap.
24
+ if (this.len > this.maxBytes * 2) {
25
+ const merged = Buffer.concat(this.chunks);
26
+ const keep = merged.subarray(Math.max(0, merged.length - this.maxBytes));
27
+ this.chunks = [Buffer.from(keep)];
28
+ this.len = keep.length;
29
+ }
30
+ }
31
+ result() {
32
+ const merged = Buffer.concat(this.chunks);
33
+ const bytes = merged.subarray(Math.max(0, merged.length - this.maxBytes));
34
+ return { bytes, totalBytes: this.total };
35
+ }
36
+ }
37
+ /** Build a FileContent from the raw end-of-stream slice of a larger source.
38
+ * Job logs keep their tail (the failure is at the end); when the source was
39
+ * larger than the slice we prefix an explicit head-omitted marker so the
40
+ * result is never silently empty. `totalBytes` is the size before truncation. */
41
+ export function tailFileContent(tail, totalBytes, contentType, maxBytes) {
42
+ const truncated = totalBytes > maxBytes;
43
+ if (!truncated) {
44
+ return { content: tail.toString("utf8"), truncated: false, bytes: totalBytes, contentType };
45
+ }
46
+ // Callers may pass an already-sliced tail (streaming fetchers) or the whole
47
+ // buffer (GitHub inflates the ZIP first); slice here so both are correct.
48
+ const slice = tail.byteLength > maxBytes ? tail.subarray(tail.byteLength - maxBytes) : tail;
49
+ // The slice boundary can split a multi-byte UTF-8 char; drop the replacement
50
+ // character it produces so the retained tail starts on a clean boundary.
51
+ const text = slice.toString("utf8").replace(/^\uFFFD/, "");
52
+ return {
53
+ content: `[… ${totalBytes - slice.byteLength} bytes omitted from the start …]\n${text}`,
54
+ truncated: true,
55
+ bytes: totalBytes,
56
+ contentType,
57
+ };
58
+ }
59
+ // ---- Errors ----------------------------------------------------------------
60
+ /** HTTP error from a forge, normalized. */
61
+ export class PlatformHttpError extends Error {
62
+ status;
63
+ op;
64
+ body;
65
+ constructor(status, op, body) {
66
+ super(`platform ${status} on ${op}: ${body}`);
67
+ this.name = "PlatformHttpError";
68
+ this.status = status;
69
+ this.op = op;
70
+ this.body = body;
71
+ }
72
+ }
73
+ /** Operation not available on this platform (e.g. CI model differences). */
74
+ export class UnsupportedError extends Error {
75
+ constructor(op) {
76
+ super(`operation '${op}' is not supported on this platform`);
77
+ this.name = "UnsupportedError";
78
+ }
79
+ }
80
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/platform/types.ts"],"names":[],"mappings":"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"}
package/dist/podman.js ADDED
@@ -0,0 +1,119 @@
1
+ import { spawn } from "node:child_process";
2
+ import { log } from "./logger.js";
3
+ import { killContainerByName } from "./opencode.js";
4
+ import { appendPodmanPhase } from "./run-log-sink.js";
5
+ const defaultClient = {
6
+ run(args, opts = {}) {
7
+ return new Promise((resolve) => {
8
+ const child = spawn("podman", args, { stdio: ["pipe", "pipe", "pipe"] });
9
+ const out = [];
10
+ const err = [];
11
+ child.stdout.on("data", (b) => out.push(b));
12
+ child.stderr.on("data", (b) => err.push(b));
13
+ // Optional stdin (used to stream large payloads into a container without
14
+ // hitting the argv size limit). Absent → close stdin immediately so a
15
+ // container reading stdin sees EOF instead of hanging. A write to a child
16
+ // that exits early raises EPIPE; swallow it (the exit code is the signal).
17
+ child.stdin.on("error", () => { });
18
+ if (opts.input !== undefined)
19
+ child.stdin.end(opts.input);
20
+ else
21
+ child.stdin.end();
22
+ let timer;
23
+ if (opts.timeoutMs) {
24
+ timer = setTimeout(() => {
25
+ try {
26
+ child.kill("SIGKILL");
27
+ }
28
+ catch { /* dead */ }
29
+ const i = args.indexOf("--name");
30
+ const cname = i >= 0 && i + 1 < args.length ? args[i + 1] : undefined;
31
+ if (cname)
32
+ killContainerByName(cname);
33
+ }, opts.timeoutMs);
34
+ }
35
+ child.on("error", () => {
36
+ if (timer)
37
+ clearTimeout(timer);
38
+ // ponytail: don't log podman args — they embed secrets via shq(authJson).
39
+ // Log only the container name (non-secret, useful for debugging).
40
+ const nameIdx = args.indexOf("--name");
41
+ const containerName = nameIdx >= 0 && nameIdx + 1 < args.length ? args[nameIdx + 1] : undefined;
42
+ log.error("podman spawn error", { containerName });
43
+ resolve({ code: -1, stdout: "", stderr: "spawn failed" });
44
+ });
45
+ child.on("close", (code) => {
46
+ if (timer)
47
+ clearTimeout(timer);
48
+ resolve({
49
+ code: code ?? -1,
50
+ stdout: Buffer.concat(out).toString("utf8"),
51
+ stderr: Buffer.concat(err).toString("utf8"),
52
+ });
53
+ });
54
+ });
55
+ },
56
+ };
57
+ // ponytail: mutable global. ESM live bindings mean consumers read the current
58
+ // value at access time, so setPodmanClient(mock) before a test takes effect.
59
+ // Upgrade path: per-instance injection if concurrency matters.
60
+ let client = defaultClient;
61
+ export function setPodmanClient(c) {
62
+ client = c;
63
+ }
64
+ export function resetPodmanClient() {
65
+ client = defaultClient;
66
+ }
67
+ // OpenCode can issue parallel MCP tool calls. Helper containers reuse fixed
68
+ // per-work-item names (attachdl/attachread/peersync/gitexclude), so a second
69
+ // launch while the first is live fails with "container name ... already in
70
+ // use" (exit 125). Serialize `podman run` calls that share a --name; different
71
+ // names (and non-run commands) stay concurrent.
72
+ const runChains = new Map();
73
+ function namedContainer(args) {
74
+ const i = args.indexOf("--name");
75
+ return i >= 0 && i + 1 < args.length ? args[i + 1] : undefined;
76
+ }
77
+ // The function every caller uses — reads the live binding.
78
+ export async function podman(args, opts) {
79
+ if (args[0] !== "run") {
80
+ const result = await client.run(args, opts);
81
+ captureRunOutput(args, result);
82
+ return result;
83
+ }
84
+ const name = namedContainer(args);
85
+ if (!name) {
86
+ const result = await client.run(args, opts);
87
+ captureRunOutput(args, result);
88
+ return result;
89
+ }
90
+ const previous = runChains.get(name) ?? Promise.resolve();
91
+ const current = previous.catch(() => { }).then(() => client.run(args, opts));
92
+ runChains.set(name, current);
93
+ try {
94
+ const result = await current;
95
+ captureRunOutput(args, result);
96
+ return result;
97
+ }
98
+ finally {
99
+ if (runChains.get(name) === current)
100
+ runChains.delete(name);
101
+ }
102
+ }
103
+ // Tee a phase container's output into the active run's log sink (work item #61).
104
+ // Only `podman run` is captured — ps/rm/volume housekeeping is not part of a
105
+ // run's transcript. Best-effort: a capture failure never affects the run.
106
+ function captureRunOutput(args, result) {
107
+ if (args[0] !== "run")
108
+ return;
109
+ const name = namedContainer(args);
110
+ if (!name)
111
+ return;
112
+ try {
113
+ appendPodmanPhase(name, result.code, result.stdout, result.stderr);
114
+ }
115
+ catch (e) {
116
+ log.warn("run log capture failed", { err: e });
117
+ }
118
+ }
119
+ //# sourceMappingURL=podman.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"podman.js","sourceRoot":"","sources":["../src/podman.ts"],"names":[],"mappings":"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"}