@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,71 @@
1
+ import { getGlobalSettings } from "./global-settings-store.js";
2
+ import { log } from "./logger.js";
3
+ import { getPlatform } from "./platform/index.js";
4
+ import { getProjectSettings } from "./settings-store.js";
5
+ function skipped(projectId, username, reason) {
6
+ log.warn("mr assignee skipped", { projectId, username, reason });
7
+ return {
8
+ warning: reason === "not-a-member"
9
+ ? `⚠️ Assignee not set: @${username} is not a member of this project.`
10
+ : reason === "unresolved"
11
+ ? `⚠️ Assignee not set: @${username} could not be resolved on this forge.`
12
+ : `⚠️ Assignee not set: could not verify @${username} on this forge.`,
13
+ };
14
+ }
15
+ // Resolution order: project "none" (deliberate, no warning) -> project username
16
+ // -> global username -> nobody. The membership gate runs before creation.
17
+ export async function resolveMrAssignee(projectId) {
18
+ let username;
19
+ try {
20
+ const projectValue = getProjectSettings(projectId)?.assignee ?? "";
21
+ if (projectValue === "none")
22
+ return {};
23
+ username = projectValue || getGlobalSettings().assignee;
24
+ if (!username)
25
+ return {};
26
+ }
27
+ catch (e) {
28
+ log.warn("mr assignee settings unreadable", { projectId, err: e });
29
+ return {};
30
+ }
31
+ try {
32
+ const user = await getPlatform().workItems.resolveUser(username);
33
+ if (!user)
34
+ return skipped(projectId, username, "unresolved");
35
+ const permission = await getPlatform().workItems.getMemberPermission(projectId, {
36
+ id: user.id,
37
+ username: user.username,
38
+ });
39
+ if (permission === "none")
40
+ return skipped(projectId, username, "not-a-member");
41
+ return { assignee: { id: user.id, username: user.username } };
42
+ }
43
+ catch {
44
+ return skipped(projectId, username, "forge-error");
45
+ }
46
+ }
47
+ // Create the MR with the resolved assignee. Creation errors propagate to the
48
+ // runner's existing MR-failure handling: the pre-flight resolution/membership
49
+ // gate is the only assignee-related best-effort layer.
50
+ export async function createChangeRequestWithAssignee(projectId, input) {
51
+ const resolved = await resolveMrAssignee(projectId);
52
+ const mr = await getPlatform().changeRequests.create(projectId, resolved.assignee ? { ...input, assignee: resolved.assignee } : input);
53
+ return {
54
+ mr,
55
+ note: `✅ Merge request created: ${mr.webUrl}${resolved.warning ? `\n\n${resolved.warning}` : ""}`,
56
+ ...(resolved.warning ? { warning: resolved.warning } : {}),
57
+ };
58
+ }
59
+ // Settings-route trust boundary: a non-empty username must exist on the forge.
60
+ // Membership is deliberately not checked here (C2) — it can change later.
61
+ export async function validateAssigneeUsername(username) {
62
+ if (!username)
63
+ return "ok";
64
+ try {
65
+ return (await getPlatform().workItems.resolveUser(username)) ? "ok" : "unknown";
66
+ }
67
+ catch {
68
+ return "error";
69
+ }
70
+ }
71
+ //# sourceMappingURL=mr-assignee.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mr-assignee.js","sourceRoot":"","sources":["../src/mr-assignee.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAazD,SAAS,OAAO,CAAC,SAAiB,EAAE,QAAgB,EAAE,MAA0B;IAC9E,GAAG,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,OAAO;QACL,OAAO,EACL,MAAM,KAAK,cAAc;YACvB,CAAC,CAAC,yBAAyB,QAAQ,mCAAmC;YACtE,CAAC,CAAC,MAAM,KAAK,YAAY;gBACvB,CAAC,CAAC,yBAAyB,QAAQ,uCAAuC;gBAC1E,CAAC,CAAC,0CAA0C,QAAQ,iBAAiB;KAC5E,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,SAAiB;IACvD,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,kBAAkB,CAAC,SAAS,CAAC,EAAE,QAAQ,IAAI,EAAE,CAAC;QACnE,IAAI,YAAY,KAAK,MAAM;YAAE,OAAO,EAAE,CAAC;QACvC,QAAQ,GAAG,YAAY,IAAI,iBAAiB,EAAE,CAAC,QAAQ,CAAC;QACxD,IAAI,CAAC,QAAQ;YAAE,OAAO,EAAE,CAAC;IAC3B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,IAAI,CAAC,iCAAiC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,CAAU,EAAE,CAAC,CAAC;QAC5E,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,WAAW,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QACjE,IAAI,CAAC,IAAI;YAAE,OAAO,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;QAC7D,MAAM,UAAU,GAAG,MAAM,WAAW,EAAE,CAAC,SAAS,CAAC,mBAAmB,CAAC,SAAS,EAAE;YAC9E,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,QAAQ,EAAE,IAAI,CAAC,QAAQ;SACxB,CAAC,CAAC;QACH,IAAI,UAAU,KAAK,MAAM;YAAE,OAAO,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;QAC/E,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;IACrD,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,8EAA8E;AAC9E,uDAAuD;AACvD,MAAM,CAAC,KAAK,UAAU,+BAA+B,CACnD,SAAiB,EACjB,KAA2C;IAE3C,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,SAAS,CAAC,CAAC;IACpD,MAAM,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC,cAAc,CAAC,MAAM,CAClD,SAAS,EACT,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,CACtE,CAAC;IAEF,OAAO;QACL,EAAE;QACF,IAAI,EAAE,4BAA4B,EAAE,CAAC,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;QACjG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC;AAID,+EAA+E;AAC/E,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,QAAgB;IAC7D,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3B,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,WAAW,EAAE,CAAC,SAAS,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IAClF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC"}
@@ -0,0 +1,90 @@
1
+ // Pure parser for the agent-authored MR/PR content block. The build-mode agent
2
+ // ends its reply with a fenced ```mr block carrying `title:` and `description:`
3
+ // lines; devbot extracts it, strips it from the note text, and feeds it to
4
+ // createMergeRequest / updateMergeRequest. Falls back to the historical
5
+ // defaults (`Resolves #<number>` / `Generated by devbot.`) when the block is
6
+ // absent or malformed — a malformed block never blocks the MR/PR.
7
+ //
8
+ // Format (documented in the build-mode prompt suffix in runner.ts):
9
+ // ```mr
10
+ // title: <single-line Conventional Commit summary, end with (#<number>)>
11
+ // description:
12
+ // <Markdown body — structured as ## Summary / ## Changes / ## Rationale
13
+ // sections, ending with `Resolves #<number>`; transported to the forge verbatim>
14
+ // ```
15
+ //
16
+ // The block must be the LAST fenced ```mr block in the reply. All such blocks
17
+ // are stripped from the note text posted to the work item (the metadata block
18
+ // is internal transport, not user-facing prose).
19
+ const DEFAULT_TITLE = (workItemNumber) => `Resolves #${workItemNumber}`;
20
+ const DEFAULT_DESCRIPTION = "Generated by devbot.";
21
+ const TITLE_MAX = 255;
22
+ const DESCRIPTION_MAX = 8000;
23
+ const MR_BLOCK = /```mr\s*\n([\s\S]*?)```/g;
24
+ // Strip any trailing (#<digits>) suffix from the title and append the correct
25
+ // work-item number anchor. Idempotent: a title already ending in (#<number>)
26
+ // is returned unchanged; a title with a wrong/old number is normalized to the
27
+ // correct one; re-runs don't grow the title. Slice to 255 AFTER the suffix
28
+ // is added so the anchor is never truncated away.
29
+ function normalizeTitle(raw, workItemNumber) {
30
+ // Strip ALL trailing (#<digits>) suffixes (handles double/multiple from
31
+ // re-runs), then append the correct one. Idempotent: a title already
32
+ // ending in (#<number>) is returned unchanged after strip+re-add.
33
+ const stripped = raw.trim().replace(/(?:\s*\(#\d+\))+\s*$/, "");
34
+ // Slice the body to leave room for the suffix, so the anchor is never
35
+ // truncated away. Then append.
36
+ const suffix = ` (#${workItemNumber})`;
37
+ const maxBody = TITLE_MAX - suffix.length;
38
+ return `${stripped.slice(0, maxBody)}${suffix}`;
39
+ }
40
+ export function parseMrContent(reply, workItemNumber) {
41
+ const matches = [...reply.matchAll(MR_BLOCK)];
42
+ const replyStripped = matches.reduce((acc, m) => acc.replace(m[0], "").trim(), reply);
43
+ const defaults = {
44
+ title: DEFAULT_TITLE(workItemNumber),
45
+ description: DEFAULT_DESCRIPTION,
46
+ };
47
+ if (matches.length === 0)
48
+ return { reply, mr: defaults };
49
+ const last = matches[matches.length - 1];
50
+ const body = (last[1] ?? "").trim();
51
+ if (!body)
52
+ return { reply: replyStripped, mr: defaults };
53
+ let title = "";
54
+ let description = "";
55
+ let sawTitle = false;
56
+ let sawDescription = false;
57
+ const descLines = [];
58
+ for (const line of body.split("\n")) {
59
+ if (!sawDescription) {
60
+ const tMatch = line.match(/^title:\s*(.*)$/);
61
+ if (tMatch) {
62
+ title = (tMatch[1] ?? "").trim();
63
+ sawTitle = true;
64
+ continue;
65
+ }
66
+ const dMatch = line.match(/^description:\s*(.*)$/);
67
+ if (dMatch) {
68
+ description = (dMatch[1] ?? "").trim();
69
+ sawDescription = true;
70
+ continue;
71
+ }
72
+ }
73
+ else {
74
+ descLines.push(line);
75
+ }
76
+ }
77
+ if (sawDescription && descLines.length > 0) {
78
+ const joined = description ? `${description}\n${descLines.join("\n")}` : descLines.join("\n");
79
+ description = joined.trim();
80
+ }
81
+ const mr = {
82
+ title: sawTitle && title ? normalizeTitle(title, workItemNumber) : defaults.title,
83
+ description: sawDescription ? (description || defaults.description) : defaults.description,
84
+ };
85
+ if (mr.description.length > DESCRIPTION_MAX) {
86
+ mr.description = mr.description.slice(0, DESCRIPTION_MAX);
87
+ }
88
+ return { reply: replyStripped, mr };
89
+ }
90
+ //# sourceMappingURL=mr-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mr-content.js","sourceRoot":"","sources":["../src/mr-content.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { logReq } from "./http-util.js";
3
+ import { config } from "./config.js";
4
+ import { getPlatform } from "./platform/index.js";
5
+ import { isOnboardingAllowed } from "./onboarding-allowlist.js";
6
+ import { signCookie, cookieOptions, SESSION_COOKIE, STATE_COOKIE, } from "./cookie.js";
7
+ export function mountOauthRoutes(app) {
8
+ const platform = getPlatform();
9
+ app.get("/oauth/start", (_req, res) => {
10
+ const state = randomBytes(16).toString("hex");
11
+ res.cookie(STATE_COOKIE, state, cookieOptions(600));
12
+ return res.redirect(302, platform.onboarding.authorizeUrl(state));
13
+ });
14
+ app.get("/oauth/callback", async (req, res) => {
15
+ const code = req.query.code;
16
+ const state = req.query.state;
17
+ const cookies = req.cookies;
18
+ const expectedState = cookies?.[STATE_COOKIE];
19
+ if (!code || !state || state !== expectedState) {
20
+ logReq(req, "warn", "oauth invalid state", {
21
+ hasCode: !!code,
22
+ stateType: typeof state,
23
+ hasExpectedState: !!expectedState,
24
+ match: typeof state === "string" && state === expectedState,
25
+ cookieHeaderPresent: !!req.headers.cookie,
26
+ cookieKeys: Object.keys(req.cookies ?? {}),
27
+ });
28
+ return res.status(403).send("invalid state");
29
+ }
30
+ // ponytail: clear state cookie immediately after validation — single-use
31
+ // CSRF token, consumed whether the callback succeeds or fails.
32
+ res.clearCookie(STATE_COOKIE, { path: "/" });
33
+ try {
34
+ const { accessToken } = await platform.onboarding.exchangeCode(String(code));
35
+ const user = await platform.onboarding.currentUser(accessToken);
36
+ // The allowlist is the single authorization gate for all drivers —
37
+ // per-forge admin status is no longer checked. Fails closed when
38
+ // ONBOARDING_USERS is empty.
39
+ if (!isOnboardingAllowed(user.username, config.ONBOARDING_USERS)) {
40
+ logReq(req, "warn", "oauth user not allowlisted", { userId: user.id, username: user.username });
41
+ return res.status(403).send("user not authorized to onboard");
42
+ }
43
+ const exp = Math.floor(Date.now() / 1000) + 3600;
44
+ const cookie = signCookie({ accessToken, userId: user.id, username: user.username, exp });
45
+ res.cookie(SESSION_COOKIE, cookie, cookieOptions(3600));
46
+ return res.redirect(302, "/");
47
+ }
48
+ catch (e) {
49
+ logReq(req, "error", "oauth callback failed", { err: e });
50
+ return res.status(500).send("oauth failed");
51
+ }
52
+ });
53
+ }
54
+ //# sourceMappingURL=oauth-routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth-routes.js","sourceRoot":"","sources":["../src/oauth-routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ // WebUI onboarding authorization gate.
2
+ //
3
+ // A single, platform-neutral allowlist replaces the per-forge instance-admin
4
+ // check: the operator lists the forge usernames allowed to complete onboarding
5
+ // in ONBOARDING_USERS (comma-separated). This is required because github.com
6
+ // has no instance-admin concept, and keeping one gate for every driver makes
7
+ // GitLab/ForgeJo/Gitea behave exactly like GitHub. The gate FAILS CLOSED: an
8
+ // unset/empty allowlist denies everyone, so a misconfigured deploy cannot be
9
+ // onboarded by an arbitrary user.
10
+ /** Parse the raw env value into a normalized, de-duplicated username set. */
11
+ export function parseOnboardingUsers(raw) {
12
+ const set = new Set();
13
+ if (!raw)
14
+ return set;
15
+ for (const part of raw.split(",")) {
16
+ const username = part.trim().toLowerCase();
17
+ if (username)
18
+ set.add(username);
19
+ }
20
+ return set;
21
+ }
22
+ /**
23
+ * True when `username` is permitted to onboard. Forge usernames are treated
24
+ * case-insensitively, so both sides are lowercased. An empty allowlist denies
25
+ * everyone (fail closed).
26
+ */
27
+ export function isOnboardingAllowed(username, raw) {
28
+ if (!username)
29
+ return false;
30
+ return parseOnboardingUsers(raw).has(username.trim().toLowerCase());
31
+ }
32
+ //# sourceMappingURL=onboarding-allowlist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboarding-allowlist.js","sourceRoot":"","sources":["../src/onboarding-allowlist.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,6EAA6E;AAC7E,6EAA6E;AAC7E,6EAA6E;AAC7E,6EAA6E;AAC7E,kCAAkC;AAElC,6EAA6E;AAC7E,MAAM,UAAU,oBAAoB,CAAC,GAA8B;IACjE,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,IAAI,CAAC,GAAG;QAAE,OAAO,GAAG,CAAC;IACrB,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC3C,IAAI,QAAQ;YAAE,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAmC,EAAE,GAA8B;IACrG,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5B,OAAO,oBAAoB,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AACtE,CAAC"}
@@ -0,0 +1,291 @@
1
+ import { spawn, spawnSync } from "node:child_process";
2
+ import { log } from "./logger.js";
3
+ import { redact } from "./redact.js";
4
+ import { OpencodeEventSchema, EventWithPartSchema, TextPartSchema, ErrorEventSchema, StepFinishPartSchema, } from "./types/opencode.js";
5
+ export function zeroUsage() {
6
+ return { input: 0, output: 0, reasoning: 0, cacheRead: 0, cacheWrite: 0, costUsd: 0 };
7
+ }
8
+ // Sum the step-finish parts of a run's NDJSON events. Pure; a malformed part is
9
+ // skipped so a bad upstream shape can never inject NaN into the totals.
10
+ export function extractUsage(events) {
11
+ const total = zeroUsage();
12
+ for (const raw of events) {
13
+ const ev = OpencodeEventSchema.safeParse(raw);
14
+ if (!ev.success)
15
+ continue;
16
+ const withPart = EventWithPartSchema.safeParse(ev.data);
17
+ if (!withPart.success)
18
+ continue;
19
+ const part = StepFinishPartSchema.safeParse(withPart.data.part);
20
+ if (!part.success)
21
+ continue;
22
+ const t = part.data.tokens;
23
+ total.input += t?.input ?? 0;
24
+ total.output += t?.output ?? 0;
25
+ total.reasoning += t?.reasoning ?? 0;
26
+ total.cacheRead += t?.cache?.read ?? 0;
27
+ total.cacheWrite += t?.cache?.write ?? 0;
28
+ total.costUsd += part.data.cost ?? 0;
29
+ }
30
+ return total;
31
+ }
32
+ function isTextPart(p) {
33
+ return TextPartSchema.safeParse(p).success;
34
+ }
35
+ function truncate(s, max = 2000) {
36
+ return s.length > max ? s.slice(0, max) + "…[truncated]" : s;
37
+ }
38
+ export function extractText(events) {
39
+ const texts = [];
40
+ for (const raw of events) {
41
+ const parsed = OpencodeEventSchema.safeParse(raw);
42
+ if (!parsed.success)
43
+ continue;
44
+ const errorEvent = ErrorEventSchema.safeParse(parsed.data);
45
+ if (errorEvent.success) {
46
+ const msg = errorEvent.data.error.data?.message ?? errorEvent.data.error.message;
47
+ if (msg)
48
+ texts.push(`⚠️ ${msg}`);
49
+ continue;
50
+ }
51
+ const withPart = EventWithPartSchema.safeParse(parsed.data);
52
+ if (!withPart.success)
53
+ continue;
54
+ if (isTextPart(withPart.data.part))
55
+ texts.push(withPart.data.part.text);
56
+ }
57
+ // ponytail: post only the last text/error entry to the forge (one note per run,
58
+ // not the whole transcript). Upgrade to a richer formatter if summaries
59
+ // ever need multi-part composition.
60
+ return texts.at(-1) ?? "";
61
+ }
62
+ // ponytail: spawnSync blocks the loop briefly on timeout (error path only).
63
+ // If many concurrent timeouts fire, switch to async spawn fire-and-forget.
64
+ export function killContainerByName(name) {
65
+ try {
66
+ spawnSync("podman", ["rm", "-f", name], { stdio: "ignore" });
67
+ }
68
+ catch {
69
+ /* best-effort; container may already be gone */
70
+ }
71
+ }
72
+ function containerNameFromArgs(args) {
73
+ const i = args.indexOf("--name");
74
+ return i >= 0 && i + 1 < args.length ? args[i + 1] : undefined;
75
+ }
76
+ export function runPodmanCapture(opts) {
77
+ return new Promise((resolve) => {
78
+ const child = spawn("podman", opts.args, {
79
+ cwd: opts.cwd,
80
+ env: { ...process.env, ...opts.env },
81
+ stdio: ["ignore", "pipe", "pipe"],
82
+ });
83
+ const stderrChunks = [];
84
+ const stdoutChunks = [];
85
+ const events = [];
86
+ const rawStdout = () => redact(Buffer.concat(stdoutChunks).toString("utf8"));
87
+ let lineBuf = "";
88
+ let timedOut = false;
89
+ let stalled = false;
90
+ let settled = false;
91
+ let lastOutputAt = Date.now();
92
+ const timer = setTimeout(() => {
93
+ timedOut = true;
94
+ try {
95
+ child.kill("SIGKILL");
96
+ }
97
+ catch { /* already dead */ }
98
+ const cname = containerNameFromArgs(opts.args);
99
+ if (cname)
100
+ killContainerByName(cname);
101
+ }, opts.timeoutMs);
102
+ // Inactivity watchdog (work item #96): a fully silent run is killed early
103
+ // instead of sitting "running" until timeoutMs. Checked a few times per
104
+ // stall window (bounded) so the kill lands promptly without busy-polling.
105
+ const stallMs = opts.stallMs ?? 0;
106
+ const stallTimer = stallMs > 0
107
+ ? setInterval(() => {
108
+ if (settled || stalled)
109
+ return;
110
+ if (Date.now() - lastOutputAt < stallMs)
111
+ return;
112
+ stalled = true;
113
+ try {
114
+ child.kill("SIGKILL");
115
+ }
116
+ catch { /* already dead */ }
117
+ const cname = containerNameFromArgs(opts.args);
118
+ if (cname)
119
+ killContainerByName(cname);
120
+ }, Math.max(1_000, Math.min(30_000, Math.floor(stallMs / 4))))
121
+ : undefined;
122
+ const clearTimers = () => {
123
+ clearTimeout(timer);
124
+ if (stallTimer)
125
+ clearInterval(stallTimer);
126
+ };
127
+ // ponytail: log each event as it arrives so a long run is observable in
128
+ // realtime. One log line per event across all part types — upgrade to
129
+ // debounce/batch or a LOG_OPENCODE_* flag if a chatty model floods.
130
+ function handleLine(raw) {
131
+ const trimmed = raw.trim();
132
+ if (!trimmed)
133
+ return;
134
+ let parsed;
135
+ try {
136
+ parsed = JSON.parse(trimmed);
137
+ }
138
+ catch {
139
+ return;
140
+ }
141
+ events.push(parsed);
142
+ const ev = OpencodeEventSchema.safeParse(parsed);
143
+ if (!ev.success)
144
+ return;
145
+ const errEv = ErrorEventSchema.safeParse(ev.data);
146
+ if (errEv.success) {
147
+ const msg = errEv.data.error.data?.message ?? errEv.data.error.message;
148
+ if (msg)
149
+ log.warn("opencode error event", { ...opts.context, msg });
150
+ return;
151
+ }
152
+ const withPart = EventWithPartSchema.safeParse(ev.data);
153
+ if (!withPart.success)
154
+ return;
155
+ const p = withPart.data.part;
156
+ // ponytail: log every part type as it arrives — previously only text/error
157
+ // were logged and every other part (tools, steps, reasoning, files, …)
158
+ // was silently dropped in realtime (the raw stdout dump at run end was
159
+ // the only record, at debug level, post-exit). One log line per event;
160
+ // add a LOG_OPENCODE_* flag if a chatty model floods.
161
+ switch (p.type) {
162
+ case "text":
163
+ log.debug("opencode text", { ...opts.context, text: p.text });
164
+ break;
165
+ case "tool": {
166
+ const st = p.state;
167
+ log.debug("opencode tool", {
168
+ ...opts.context,
169
+ tool: p.tool,
170
+ status: st?.status,
171
+ input: st?.input,
172
+ output: st?.output ? truncate(st.output) : undefined,
173
+ error: st?.error,
174
+ });
175
+ break;
176
+ }
177
+ case "step-start":
178
+ log.debug("opencode step-start", { ...opts.context });
179
+ break;
180
+ case "step-finish": {
181
+ const sf = StepFinishPartSchema.safeParse(p);
182
+ log.debug("opencode step-finish", {
183
+ ...opts.context,
184
+ reason: p.reason,
185
+ tokens: sf.success ? sf.data.tokens : undefined,
186
+ cost: sf.success ? sf.data.cost : undefined,
187
+ });
188
+ break;
189
+ }
190
+ case "reasoning":
191
+ log.debug("opencode reasoning", { ...opts.context, text: p.text });
192
+ break;
193
+ case "file":
194
+ log.debug("opencode file", { ...opts.context, mime: p.mime, filename: p.filename, url: p.url });
195
+ break;
196
+ case "subtask":
197
+ log.debug("opencode subtask", { ...opts.context, agent: p.agent, description: p.description });
198
+ break;
199
+ case "agent":
200
+ log.debug("opencode agent", { ...opts.context, name: p.name });
201
+ break;
202
+ case "retry":
203
+ log.warn("opencode retry", { ...opts.context, attempt: p.attempt, error: p.error });
204
+ break;
205
+ case "compaction":
206
+ log.debug("opencode compaction", { ...opts.context, auto: p.auto });
207
+ break;
208
+ case "snapshot":
209
+ log.debug("opencode snapshot", { ...opts.context });
210
+ break;
211
+ case "patch":
212
+ log.debug("opencode patch", { ...opts.context, files: p.files });
213
+ break;
214
+ default:
215
+ // ponytail: unknown part type — log the FULL body (not truncated) so
216
+ // no part is ever silently dropped again. Large if a future version
217
+ // emits a big-blob unknown type; that's the cost of completeness.
218
+ log.debug("opencode part", { ...opts.context, type: p.type, part: p });
219
+ }
220
+ }
221
+ child.stdout.on("data", (b) => {
222
+ lastOutputAt = Date.now();
223
+ stdoutChunks.push(b);
224
+ opts.onChunk?.("stdout", b.toString("utf8"));
225
+ lineBuf += b.toString("utf8");
226
+ let nl;
227
+ while ((nl = lineBuf.indexOf("\n")) >= 0) {
228
+ handleLine(lineBuf.slice(0, nl));
229
+ lineBuf = lineBuf.slice(nl + 1);
230
+ }
231
+ });
232
+ child.stderr.on("data", (b) => {
233
+ lastOutputAt = Date.now();
234
+ stderrChunks.push(b);
235
+ opts.onChunk?.("stderr", b.toString("utf8"));
236
+ });
237
+ child.on("error", (err) => {
238
+ if (settled)
239
+ return;
240
+ settled = true;
241
+ clearTimers();
242
+ log.error("podman spawn error", { ...opts.context, err: err.message });
243
+ resolve({ text: `⚠️ Failed to start container: ${err.message}`, error: true, exitCode: -1, kind: "spawn", rawOutput: rawStdout(), stderrTail: "", usage: zeroUsage() });
244
+ });
245
+ child.on("close", (code) => {
246
+ if (settled)
247
+ return;
248
+ settled = true;
249
+ clearTimers();
250
+ const exitCode = code ?? -1;
251
+ if (timedOut || stalled) {
252
+ const text = stalled
253
+ ? `⚠️ Run stalled — no output for ${Math.floor(stallMs / 60_000)}min, killed`
254
+ : `⚠️ Run timed out after ${Math.floor(opts.timeoutMs / 60_000)}min`;
255
+ log.warn(stalled ? "opencode stalled" : "opencode timed out", { ...opts.context, stallMs, timeoutMs: opts.timeoutMs });
256
+ resolve({
257
+ text,
258
+ error: true,
259
+ exitCode,
260
+ kind: "timeout",
261
+ rawOutput: rawStdout(),
262
+ stderrTail: redact(Buffer.concat(stderrChunks).toString("utf8")),
263
+ usage: extractUsage(events),
264
+ });
265
+ return;
266
+ }
267
+ const stderr = Buffer.concat(stderrChunks).toString("utf8");
268
+ // Flush any trailing partial line (opencode may exit without a final \n).
269
+ if (lineBuf.length > 0)
270
+ handleLine(lineBuf);
271
+ const stderrTail = redact(stderr.length > 1024 ? stderr.slice(-1024) : stderr);
272
+ const text = extractText(events);
273
+ if (exitCode !== 0 || (text.length === 0 && events.length === 0)) {
274
+ log.warn("opencode run failed", { ...opts.context, exitCode, eventCount: events.length, stderrTail });
275
+ resolve({
276
+ text: text.length > 0 ? text : `⚠️ opencode exited (${exitCode})\n\`\`\`\n${stderrTail}\n\`\`\``,
277
+ error: true,
278
+ exitCode,
279
+ kind: "exit",
280
+ rawOutput: redact(Buffer.concat(stdoutChunks).toString("utf8")),
281
+ stderrTail,
282
+ usage: extractUsage(events),
283
+ });
284
+ return;
285
+ }
286
+ log.debug("opencode ok", { ...opts.context, exitCode, eventCount: events.length });
287
+ resolve({ text: text || "✅ Done (no text output)", error: false, exitCode, kind: "ok", rawOutput: "", stderrTail: "", usage: extractUsage(events) });
288
+ });
289
+ });
290
+ }
291
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../src/opencode.ts"],"names":[],"mappings":"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"}