@aoagents/ao-web 0.2.3 → 0.2.5

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 (265) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +228 -221
  3. package/.next/app-path-routes-manifest.json +7 -6
  4. package/.next/build-manifest.json +14 -14
  5. package/.next/next-minimal-server.js.nft.json +1 -1
  6. package/.next/next-server.js.nft.json +1 -1
  7. package/.next/prerender-manifest.json +31 -31
  8. package/.next/react-loadable-manifest.json +14 -14
  9. package/.next/required-server-files.json +7 -4
  10. package/.next/server/app/_not-found/page.js +2 -2
  11. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  12. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  13. package/.next/server/app/_not-found.html +1 -1
  14. package/.next/server/app/_not-found.rsc +15 -15
  15. package/.next/server/app/api/backlog/route.js +1 -1
  16. package/.next/server/app/api/backlog/route.js.nft.json +1 -1
  17. package/.next/server/app/api/backlog/route_client-reference-manifest.js +1 -1
  18. package/.next/server/app/api/events/route.js +2 -2
  19. package/.next/server/app/api/events/route.js.nft.json +1 -1
  20. package/.next/server/app/api/events/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/issues/route.js +1 -1
  22. package/.next/server/app/api/issues/route.js.nft.json +1 -1
  23. package/.next/server/app/api/issues/route_client-reference-manifest.js +1 -1
  24. package/.next/server/app/api/observability/route.js +1 -1
  25. package/.next/server/app/api/observability/route.js.nft.json +1 -1
  26. package/.next/server/app/api/observability/route_client-reference-manifest.js +1 -1
  27. package/.next/server/app/api/orchestrators/route.js +1 -1
  28. package/.next/server/app/api/orchestrators/route.js.nft.json +1 -1
  29. package/.next/server/app/api/orchestrators/route_client-reference-manifest.js +1 -1
  30. package/.next/server/app/api/projects/route.js +1 -1
  31. package/.next/server/app/api/projects/route.js.nft.json +1 -1
  32. package/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/prs/[id]/merge/route.js +1 -1
  34. package/.next/server/app/api/prs/[id]/merge/route.js.nft.json +1 -1
  35. package/.next/server/app/api/prs/[id]/merge/route_client-reference-manifest.js +1 -1
  36. package/.next/server/app/api/runtime/terminal/route.js +1 -1
  37. package/.next/server/app/api/runtime/terminal/route.js.nft.json +1 -1
  38. package/.next/server/app/api/runtime/terminal/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/sessions/[id]/kill/route.js +1 -1
  40. package/.next/server/app/api/sessions/[id]/kill/route.js.nft.json +1 -1
  41. package/.next/server/app/api/sessions/[id]/kill/route_client-reference-manifest.js +1 -1
  42. package/.next/server/app/api/sessions/[id]/message/route.js +1 -1
  43. package/.next/server/app/api/sessions/[id]/message/route.js.nft.json +1 -1
  44. package/.next/server/app/api/sessions/[id]/message/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/sessions/[id]/remap/route.js +1 -1
  46. package/.next/server/app/api/sessions/[id]/remap/route.js.nft.json +1 -1
  47. package/.next/server/app/api/sessions/[id]/remap/route_client-reference-manifest.js +1 -1
  48. package/.next/server/app/api/sessions/[id]/restore/route.js +1 -1
  49. package/.next/server/app/api/sessions/[id]/restore/route.js.nft.json +1 -1
  50. package/.next/server/app/api/sessions/[id]/restore/route_client-reference-manifest.js +1 -1
  51. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  52. package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
  53. package/.next/server/app/api/sessions/[id]/route_client-reference-manifest.js +1 -1
  54. package/.next/server/app/api/sessions/[id]/send/route.js +1 -1
  55. package/.next/server/app/api/sessions/[id]/send/route.js.nft.json +1 -1
  56. package/.next/server/app/api/sessions/[id]/send/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/sessions/patches/route.js +1 -0
  58. package/.next/server/app/api/sessions/patches/route.js.nft.json +1 -0
  59. package/.next/server/app/api/sessions/patches/route_client-reference-manifest.js +1 -0
  60. package/.next/server/app/api/sessions/route.js +1 -1
  61. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  62. package/.next/server/app/api/sessions/route_client-reference-manifest.js +1 -1
  63. package/.next/server/app/api/setup-labels/route.js +1 -1
  64. package/.next/server/app/api/setup-labels/route.js.nft.json +1 -1
  65. package/.next/server/app/api/setup-labels/route_client-reference-manifest.js +1 -1
  66. package/.next/server/app/api/spawn/route.js +1 -1
  67. package/.next/server/app/api/spawn/route.js.nft.json +1 -1
  68. package/.next/server/app/api/spawn/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/verify/route.js +1 -1
  70. package/.next/server/app/api/verify/route.js.nft.json +1 -1
  71. package/.next/server/app/api/verify/route_client-reference-manifest.js +1 -1
  72. package/.next/server/app/api/webhooks/[...slug]/route.js +1 -1
  73. package/.next/server/app/api/webhooks/[...slug]/route.js.nft.json +1 -1
  74. package/.next/server/app/api/webhooks/[...slug]/route_client-reference-manifest.js +1 -1
  75. package/.next/server/app/apple-icon/route.js +1 -1
  76. package/.next/server/app/apple-icon/route.js.nft.json +1 -1
  77. package/.next/server/app/apple-icon/route_client-reference-manifest.js +1 -1
  78. package/.next/server/app/dev/terminal-test/page.js +3 -3
  79. package/.next/server/app/dev/terminal-test/page.js.nft.json +1 -1
  80. package/.next/server/app/dev/terminal-test/page_client-reference-manifest.js +1 -1
  81. package/.next/server/app/dev/terminal-test.html +1 -1
  82. package/.next/server/app/dev/terminal-test.rsc +17 -17
  83. package/.next/server/app/icon/route.js +1 -1
  84. package/.next/server/app/icon/route.js.nft.json +1 -1
  85. package/.next/server/app/icon/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/icon-192/route.js +1 -1
  87. package/.next/server/app/icon-192/route.js.nft.json +1 -1
  88. package/.next/server/app/icon-192/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/icon-512/route.js +1 -1
  90. package/.next/server/app/icon-512/route.js.nft.json +1 -1
  91. package/.next/server/app/icon-512/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/manifest.webmanifest/route.js +2 -2
  93. package/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -1
  94. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/manifest.webmanifest.body +1 -1
  96. package/.next/server/app/orchestrators/page.js +2 -2
  97. package/.next/server/app/orchestrators/page.js.nft.json +1 -1
  98. package/.next/server/app/orchestrators/page_client-reference-manifest.js +1 -1
  99. package/.next/server/app/page.js +2 -2
  100. package/.next/server/app/page.js.nft.json +1 -1
  101. package/.next/server/app/page_client-reference-manifest.js +1 -1
  102. package/.next/server/app/prs/page.js +2 -2
  103. package/.next/server/app/prs/page.js.nft.json +1 -1
  104. package/.next/server/app/prs/page_client-reference-manifest.js +1 -1
  105. package/.next/server/app/sessions/[id]/page.js +5 -5
  106. package/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
  107. package/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
  108. package/.next/server/app/test-direct/page.js +2 -2
  109. package/.next/server/app/test-direct/page.js.nft.json +1 -1
  110. package/.next/server/app/test-direct/page_client-reference-manifest.js +1 -1
  111. package/.next/server/app/test-direct.html +1 -1
  112. package/.next/server/app/test-direct.rsc +17 -17
  113. package/.next/server/app-paths-manifest.json +7 -6
  114. package/.next/server/chunks/100.js +1 -0
  115. package/.next/server/chunks/106.js +1 -0
  116. package/.next/server/chunks/172.js +9 -0
  117. package/.next/server/chunks/180.js +25 -0
  118. package/.next/server/chunks/333.js +1 -0
  119. package/.next/server/chunks/367.js +3 -0
  120. package/.next/server/chunks/561.js +22 -0
  121. package/.next/server/chunks/627.js +380 -363
  122. package/.next/server/chunks/803.js +6 -0
  123. package/.next/server/chunks/886.js +384 -0
  124. package/.next/server/chunks/907.js +1 -0
  125. package/.next/server/middleware-build-manifest.js +1 -1
  126. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  127. package/.next/server/next-font-manifest.js +1 -1
  128. package/.next/server/next-font-manifest.json +1 -1
  129. package/.next/server/pages/404.html +1 -1
  130. package/.next/server/pages/500.html +1 -1
  131. package/.next/server/pages/_app.js +1 -1
  132. package/.next/server/pages/_app.js.nft.json +1 -1
  133. package/.next/server/pages/_document.js +1 -1
  134. package/.next/server/pages/_document.js.nft.json +1 -1
  135. package/.next/server/pages/_error.js +3 -3
  136. package/.next/server/pages/_error.js.nft.json +1 -1
  137. package/.next/server/server-reference-manifest.json +1 -1
  138. package/.next/static/OyzSw2fQpoJHXyoBWoZ2X/_buildManifest.js +1 -0
  139. package/.next/static/chunks/1461-af7c54935f21d56d.js +1 -0
  140. package/.next/static/chunks/{9393.acf1934a190d793b.js → 2529.32352c1ce5253e3e.js} +1 -1
  141. package/.next/static/chunks/{7411.ecda44797fb514a0.js → 5491.fd98884d48631149.js} +1 -1
  142. package/.next/static/chunks/6923-ef8434dfec6f2a3c.js +1 -0
  143. package/.next/static/chunks/7097.fc904e5f313c4994.js +1 -0
  144. package/.next/static/chunks/7317.685aa5231218e8d3.js +1 -0
  145. package/.next/static/chunks/8713-d3d663f55dc00e48.js +1 -0
  146. package/.next/static/chunks/8785-6b4b3ff260617997.js +1 -0
  147. package/.next/static/chunks/88a6fc35-f836b4b72df5eafa.js +1 -0
  148. package/.next/static/chunks/9478.656c9c263bc55893.js +1 -0
  149. package/.next/static/chunks/app/_not-found/page-019391920005654f.js +1 -0
  150. package/.next/static/chunks/app/api/backlog/route-019391920005654f.js +1 -0
  151. package/.next/static/chunks/app/api/events/route-019391920005654f.js +1 -0
  152. package/.next/static/chunks/app/api/issues/route-019391920005654f.js +1 -0
  153. package/.next/static/chunks/app/api/observability/route-019391920005654f.js +1 -0
  154. package/.next/static/chunks/app/api/orchestrators/route-019391920005654f.js +1 -0
  155. package/.next/static/chunks/app/api/projects/route-019391920005654f.js +1 -0
  156. package/.next/static/chunks/app/api/prs/[id]/merge/route-019391920005654f.js +1 -0
  157. package/.next/static/chunks/app/api/runtime/terminal/route-019391920005654f.js +1 -0
  158. package/.next/static/chunks/app/api/sessions/[id]/kill/route-019391920005654f.js +1 -0
  159. package/.next/static/chunks/app/api/sessions/[id]/message/route-019391920005654f.js +1 -0
  160. package/.next/static/chunks/app/api/sessions/[id]/remap/route-019391920005654f.js +1 -0
  161. package/.next/static/chunks/app/api/sessions/[id]/restore/route-019391920005654f.js +1 -0
  162. package/.next/static/chunks/app/api/sessions/[id]/route-019391920005654f.js +1 -0
  163. package/.next/static/chunks/app/api/sessions/[id]/send/route-019391920005654f.js +1 -0
  164. package/.next/static/chunks/app/api/sessions/patches/route-019391920005654f.js +1 -0
  165. package/.next/static/chunks/app/api/sessions/route-019391920005654f.js +1 -0
  166. package/.next/static/chunks/app/api/setup-labels/route-019391920005654f.js +1 -0
  167. package/.next/static/chunks/app/api/spawn/route-019391920005654f.js +1 -0
  168. package/.next/static/chunks/app/api/verify/route-019391920005654f.js +1 -0
  169. package/.next/static/chunks/app/api/webhooks/[...slug]/route-019391920005654f.js +1 -0
  170. package/.next/static/chunks/app/apple-icon/route-019391920005654f.js +1 -0
  171. package/.next/static/chunks/app/dev/terminal-test/page-4912fa9e6459f124.js +1 -0
  172. package/.next/static/chunks/app/error-670f1d8bf2b6859c.js +1 -0
  173. package/.next/static/chunks/app/{global-error-7b5c8ae45329c659.js → global-error-ca06d2b1be2d4ae0.js} +1 -1
  174. package/.next/static/chunks/app/icon/route-019391920005654f.js +1 -0
  175. package/.next/static/chunks/app/icon-192/route-019391920005654f.js +1 -0
  176. package/.next/static/chunks/app/icon-512/route-019391920005654f.js +1 -0
  177. package/.next/static/chunks/app/layout-ddf79478d9a673bb.js +1 -0
  178. package/.next/static/chunks/app/loading-019391920005654f.js +1 -0
  179. package/.next/static/chunks/app/manifest.webmanifest/route-019391920005654f.js +1 -0
  180. package/.next/static/chunks/app/{not-found-3772c2e09c29d80f.js → not-found-824d5d3c6e296eeb.js} +1 -1
  181. package/.next/static/chunks/app/orchestrators/page-4da04720a09483d2.js +1 -0
  182. package/.next/static/chunks/app/page-abf3e3c98cac072f.js +1 -0
  183. package/.next/static/chunks/app/prs/page-46455c406183ffbf.js +1 -0
  184. package/.next/static/chunks/app/sessions/[id]/error-eb0973907da68a37.js +1 -0
  185. package/.next/static/chunks/app/sessions/[id]/loading-019391920005654f.js +1 -0
  186. package/.next/static/chunks/app/sessions/[id]/{not-found-3772c2e09c29d80f.js → not-found-824d5d3c6e296eeb.js} +1 -1
  187. package/.next/static/chunks/app/sessions/[id]/page-7eb67fd32f39b15f.js +1 -0
  188. package/.next/static/chunks/app/test-direct/page-1fd63edb9a9ca8be.js +1 -0
  189. package/.next/static/chunks/{df4ed4d4.6a752eba3933e9a8.js → df4ed4d4.b6997d8b8ce9d79b.js} +1 -1
  190. package/.next/static/chunks/framework-7060e2ac4971c604.js +1 -0
  191. package/.next/static/chunks/main-app-690acf9d5d2050c9.js +1 -0
  192. package/.next/static/chunks/main-ed1610689fbd6f0d.js +1 -0
  193. package/.next/static/chunks/pages/_app-f4baf4dbe88f6f54.js +1 -0
  194. package/.next/static/chunks/pages/_error-a7f6723f42093f29.js +1 -0
  195. package/.next/static/chunks/{webpack-e12ceebeb7a1cc7e.js → webpack-ab6c08c78ffc8113.js} +1 -1
  196. package/.next/static/css/a5398483e6b75ad3.css +1 -0
  197. package/LICENSE +21 -0
  198. package/dist-server/direct-terminal-ws.js +33 -236
  199. package/dist-server/mux-websocket.js +516 -0
  200. package/dist-server/start-all.js +0 -2
  201. package/next.config.js +1 -0
  202. package/package.json +27 -27
  203. package/.next/server/chunks/27.js +0 -438
  204. package/.next/server/chunks/377.js +0 -1
  205. package/.next/server/chunks/393.js +0 -1
  206. package/.next/server/chunks/639.js +0 -6
  207. package/.next/server/chunks/693.js +0 -1
  208. package/.next/server/chunks/705.js +0 -22
  209. package/.next/server/chunks/787.js +0 -29
  210. package/.next/server/chunks/796.js +0 -1
  211. package/.next/server/chunks/934.js +0 -1
  212. package/.next/server/chunks/956.js +0 -9
  213. package/.next/static/chunks/1250-e7cf6b069fbb03ed.js +0 -1
  214. package/.next/static/chunks/2205.498806f73783aa54.js +0 -1
  215. package/.next/static/chunks/3698-9c12c45b8184022c.js +0 -1
  216. package/.next/static/chunks/6381.1541d5695a727108.js +0 -1
  217. package/.next/static/chunks/7505-2d2422d31862995f.js +0 -1
  218. package/.next/static/chunks/8597-1385f90ec1cebf47.js +0 -1
  219. package/.next/static/chunks/8762.f3d526855363db16.js +0 -1
  220. package/.next/static/chunks/a51c26f2-a21e680a5df6764e.js +0 -1
  221. package/.next/static/chunks/app/_not-found/page-2224bc1d3dce1b3e.js +0 -1
  222. package/.next/static/chunks/app/api/backlog/route-2224bc1d3dce1b3e.js +0 -1
  223. package/.next/static/chunks/app/api/events/route-2224bc1d3dce1b3e.js +0 -1
  224. package/.next/static/chunks/app/api/issues/route-2224bc1d3dce1b3e.js +0 -1
  225. package/.next/static/chunks/app/api/observability/route-2224bc1d3dce1b3e.js +0 -1
  226. package/.next/static/chunks/app/api/orchestrators/route-2224bc1d3dce1b3e.js +0 -1
  227. package/.next/static/chunks/app/api/projects/route-2224bc1d3dce1b3e.js +0 -1
  228. package/.next/static/chunks/app/api/prs/[id]/merge/route-2224bc1d3dce1b3e.js +0 -1
  229. package/.next/static/chunks/app/api/runtime/terminal/route-2224bc1d3dce1b3e.js +0 -1
  230. package/.next/static/chunks/app/api/sessions/[id]/kill/route-2224bc1d3dce1b3e.js +0 -1
  231. package/.next/static/chunks/app/api/sessions/[id]/message/route-2224bc1d3dce1b3e.js +0 -1
  232. package/.next/static/chunks/app/api/sessions/[id]/remap/route-2224bc1d3dce1b3e.js +0 -1
  233. package/.next/static/chunks/app/api/sessions/[id]/restore/route-2224bc1d3dce1b3e.js +0 -1
  234. package/.next/static/chunks/app/api/sessions/[id]/route-2224bc1d3dce1b3e.js +0 -1
  235. package/.next/static/chunks/app/api/sessions/[id]/send/route-2224bc1d3dce1b3e.js +0 -1
  236. package/.next/static/chunks/app/api/sessions/route-2224bc1d3dce1b3e.js +0 -1
  237. package/.next/static/chunks/app/api/setup-labels/route-2224bc1d3dce1b3e.js +0 -1
  238. package/.next/static/chunks/app/api/spawn/route-2224bc1d3dce1b3e.js +0 -1
  239. package/.next/static/chunks/app/api/verify/route-2224bc1d3dce1b3e.js +0 -1
  240. package/.next/static/chunks/app/api/webhooks/[...slug]/route-2224bc1d3dce1b3e.js +0 -1
  241. package/.next/static/chunks/app/apple-icon/route-2224bc1d3dce1b3e.js +0 -1
  242. package/.next/static/chunks/app/dev/terminal-test/page-ac0ce5b046fcad82.js +0 -1
  243. package/.next/static/chunks/app/error-4896c9d3b7681a80.js +0 -1
  244. package/.next/static/chunks/app/icon/route-2224bc1d3dce1b3e.js +0 -1
  245. package/.next/static/chunks/app/icon-192/route-2224bc1d3dce1b3e.js +0 -1
  246. package/.next/static/chunks/app/icon-512/route-2224bc1d3dce1b3e.js +0 -1
  247. package/.next/static/chunks/app/layout-023f2083204e4f68.js +0 -1
  248. package/.next/static/chunks/app/loading-2224bc1d3dce1b3e.js +0 -1
  249. package/.next/static/chunks/app/manifest.webmanifest/route-2224bc1d3dce1b3e.js +0 -1
  250. package/.next/static/chunks/app/orchestrators/page-df85236df674fc5a.js +0 -1
  251. package/.next/static/chunks/app/page-e97da633b7ef25f2.js +0 -1
  252. package/.next/static/chunks/app/prs/page-8cc0fce584d238c5.js +0 -1
  253. package/.next/static/chunks/app/sessions/[id]/error-90bc99b777fecabf.js +0 -1
  254. package/.next/static/chunks/app/sessions/[id]/loading-2224bc1d3dce1b3e.js +0 -1
  255. package/.next/static/chunks/app/sessions/[id]/page-c9c95a8604786cff.js +0 -1
  256. package/.next/static/chunks/app/test-direct/page-16ceeb9f7664394a.js +0 -1
  257. package/.next/static/chunks/framework-f8b8ba0f71d38056.js +0 -1
  258. package/.next/static/chunks/main-2bc85c765bf1fc49.js +0 -1
  259. package/.next/static/chunks/main-app-93fb36c3bd1a6739.js +0 -1
  260. package/.next/static/chunks/pages/_app-a0b975794f15bd68.js +0 -1
  261. package/.next/static/chunks/pages/_error-5f4e3b5eea57917d.js +0 -1
  262. package/.next/static/css/908f93fdd7ffba42.css +0 -1
  263. package/.next/static/oB_TdR1wCu7ot1D0AG_cw/_buildManifest.js +0 -1
  264. package/dist-server/terminal-websocket.js +0 -375
  265. /package/.next/static/{oB_TdR1wCu7ot1D0AG_cw → OyzSw2fQpoJHXyoBWoZ2X}/_ssgManifest.js +0 -0
@@ -1,391 +1,408 @@
1
- "use strict";exports.id=627,exports.ids=[627],exports.modules={78627:(a,b,c)=>{c.d(b,{ix:()=>aK,wp:()=>aM,Z1:()=>aB,uj:()=>aL,Az:()=>aF});var d=c(18699),e=c(31421),f=c(57975),g=c(58500),h=c(77598),i=c(73024),j=c(48161),k=c(76760);let l=(0,f.promisify)(e.execFile),m=/^[a-zA-Z0-9_-]+$/;async function n(...a){let{stdout:b}=await l("tmux",a,{timeout:5e3});return b.trimEnd()}let o={manifest:{name:"tmux",slot:"runtime",description:"Runtime plugin: tmux sessions",version:"0.1.0"},create:function(){return{name:"tmux",async create(a){var b=a.sessionId;if(!m.test(b))throw Error(`Invalid session ID "${b}": must match ${m}`);let c=a.sessionId,e=[];for(let[b,c]of Object.entries(a.environment??{}))e.push("-e",`${b}=${c}`);await n("new-session","-d","-s",c,"-c",a.workspacePath,...e);try{if(a.launchCommand.length>200){let b=function(a){let b=(0,k.join)((0,j.tmpdir)(),`ao-launch-${(0,h.randomUUID)()}.sh`),c=`#!/usr/bin/env bash
2
- rm -- "$0" 2>/dev/null || true
3
- ${a}
4
- `;return(0,i.writeFileSync)(b,c,{encoding:"utf-8",mode:448}),`bash ${(0,d.TQ)(b)}`}(a.launchCommand);await n("send-keys","-t",c,"-l",b),await (0,g.setTimeout)(300),await n("send-keys","-t",c,"Enter")}else await n("send-keys","-t",c,a.launchCommand,"Enter")}catch(b){try{await n("kill-session","-t",c)}catch{}let a=b instanceof Error?b.message:String(b);throw Error(`Failed to send launch command to session "${c}": ${a}`,{cause:b})}return{id:c,runtimeName:"tmux",data:{createdAt:Date.now(),workspacePath:a.workspacePath}}},async destroy(a){try{await n("kill-session","-t",a.id)}catch{}},async sendMessage(a,b){if(await n("send-keys","-t",a.id,"C-u"),b.includes("\n")||b.length>200){let c=`ao-${(0,h.randomUUID)()}`,d=(0,k.join)((0,j.tmpdir)(),`ao-send-${(0,h.randomUUID)()}.txt`);(0,i.writeFileSync)(d,b,{encoding:"utf-8",mode:384});try{await n("load-buffer","-b",c,d),await n("paste-buffer","-b",c,"-t",a.id,"-d")}finally{try{(0,i.unlinkSync)(d)}catch{}try{await n("delete-buffer","-b",c)}catch{}}}else await n("send-keys","-t",a.id,"-l",b);await (0,g.setTimeout)(300),await n("send-keys","-t",a.id,"Enter")},async getOutput(a,b=50){try{return await n("capture-pane","-t",a.id,"-p","-S",`-${b}`)}catch{return""}},async isAlive(a){try{return await n("has-session","-t",a.id),!0}catch{return!1}},async getMetrics(a){let b=a.data.createdAt??Date.now();return{uptimeMs:Date.now()-b}},getAttachInfo:async a=>({type:"tmux",target:a.id,command:`tmux attach -t ${a.id}`})}}};var p=c(51455);let q=(0,f.promisify)(e.execFile),r=`#!/usr/bin/env bash
5
- # Metadata Updater Hook for Agent Orchestrator
6
- #
7
- # This PostToolUse hook automatically updates session metadata when:
8
- # - gh pr create: extracts PR URL and writes to metadata
9
- # - git checkout -b / git switch -c: extracts branch name and writes to metadata
10
- # - gh pr merge: updates status to "merged"
11
-
12
- set -euo pipefail
13
-
14
- # Configuration
15
- AO_DATA_DIR="\${AO_DATA_DIR:-$HOME/.ao-sessions}"
16
-
17
- # Read hook input from stdin
18
- input=$(cat)
19
-
20
- # Extract fields from JSON (using jq if available, otherwise basic parsing)
21
- if command -v jq &>/dev/null; then
22
- tool_name=$(echo "$input" | jq -r '.tool_name // empty')
23
- command=$(echo "$input" | jq -r '.tool_input.command // empty')
24
- output=$(echo "$input" | jq -r '.tool_response // empty')
25
- exit_code=$(echo "$input" | jq -r '.exit_code // 0')
26
- else
27
- # Fallback: basic JSON parsing without jq
28
- tool_name=$(echo "$input" | grep -o '"tool_name"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4 || echo "")
29
- command=$(echo "$input" | grep -o '"command"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4 || echo "")
30
- output=$(echo "$input" | grep -o '"tool_response"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4 || echo "")
31
- exit_code=$(echo "$input" | grep -o '"exit_code"[[:space:]]*:[[:space:]]*[0-9]*' | grep -o '[0-9]*$' || echo "0")
32
- fi
1
+ exports.id=627,exports.ids=[627],exports.modules={15407:(a,b,c)=>{"use strict";c.d(b,{Ag:()=>t,CK:()=>s,CM:()=>h,D8:()=>r,DD:()=>p,Fx:()=>q,N_:()=>j,PE:()=>e,SB:()=>g,U1:()=>o,V1:()=>f,bz:()=>n,kw:()=>u,qX:()=>l,tT:()=>m,u3:()=>d,zi:()=>k});let d={ACTIVE:"active",READY:"ready",IDLE:"idle",WAITING_INPUT:"waiting_input",BLOCKED:"blocked",EXITED:"exited"},e=3e5,f=3e4,g={SPAWNING:"spawning",WORKING:"working",PR_OPEN:"pr_open",CI_FAILED:"ci_failed",REVIEW_PENDING:"review_pending",CHANGES_REQUESTED:"changes_requested",APPROVED:"approved",MERGEABLE:"mergeable",MERGED:"merged",CLEANUP:"cleanup",NEEDS_INPUT:"needs_input",STUCK:"stuck",ERRORED:"errored",IDLE:"idle",KILLED:"killed",DONE:"done",TERMINATED:"terminated"},h=new Set(["killed","terminated","done","cleanup","errored","merged"]),i=new Set(["exited"]),j=new Set(["merged"]);function k(a){return h.has(a.status)||null!==a.activity&&i.has(a.activity)}function l(a){return k(a)&&!j.has(a.status)}function m(a,b,c){if(a.metadata?.role==="orchestrator"||a.id.endsWith("-orchestrator"))return!0;if(!b)return!1;let d=b.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");if(!RegExp(`^${d}-orchestrator-\\d+$`).test(a.id))return!1;if(c){for(let d of c)if(d!==b&&RegExp(`^${d.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}-\\d+$`).test(a.id))return!1}return!0}let n={OPEN:"open",MERGED:"merged",CLOSED:"closed"},o={PENDING:"pending",PASSING:"passing",FAILING:"failing",NONE:"none"};function p(a){if(a)return"permissionless"!==a&&"default"!==a&&"auto-edit"!==a&&"suggest"!==a?"skip"===a?"permissionless":void 0:a}function q(a){if(!a||"object"!=typeof a)return!1;let b=a.message?.toLowerCase()||"";return b.includes("issue")&&(b.includes("not found")||b.includes("does not exist"))||b.includes("no issue found")||b.includes("could not find issue")||b.includes("could not resolve to an issue")||b.includes("no issue with identifier")||b.includes("invalid issue format")}class r extends Error{constructor(a,b){super(`Session ${a} cannot be restored: ${b}`),this.sessionId=a,this.reason=b,this.name="SessionNotRestorableError"}}class s extends Error{constructor(a,b){super(`Workspace missing at ${a}${b?`: ${b}`:""}`),this.path=a,this.detail=b,this.name="WorkspaceMissingError"}}class t extends Error{constructor(a){super(`Session not found: ${a}`),this.sessionId=a,this.name="SessionNotFoundError"}}class u extends Error{constructor(a){super(a??"No agent-orchestrator.yaml found. Run `ao start` to create one."),this.name="ConfigNotFoundError"}}},24507:a=>{function b(a){return Promise.resolve().then(()=>{var b=Error("Cannot find module '"+a+"'");throw b.code="MODULE_NOT_FOUND",b})}b.keys=()=>[],b.resolve=b,b.id=24507,a.exports=b},26785:()=>{},43851:(a,b,c)=>{"use strict";c.d(b,{u3:()=>d.u3,U1:()=>d.U1,V1:()=>d.V1,PE:()=>d.PE,C3:()=>a1,Ag:()=>d.Ag,D8:()=>d.D8,CM:()=>d.CM,CK:()=>d.CK,Hr:()=>ag,Te:()=>a4,Bm:()=>aZ,Gf:()=>aM,C1:()=>aU,R:()=>Q,Sk:()=>aN,Qu:()=>aD,yA:()=>aV,cc:()=>m,Vo:()=>a$,tT:()=>d.tT,Z9:()=>J,DD:()=>d.DD,Ah:()=>aY,XI:()=>ao,gi:()=>aO,Jy:()=>a_,fz:()=>ap,J0:()=>ba,TQ:()=>am});var d=c(15407),e=c(73024),f=c(76760),g=c(48161),h=c(61096),i=c(76620),j=c(48863),k=c(77598);function l(a){let b=(0,e.realpathSync)(a),c=(0,f.dirname)(b);return(0,k.createHash)("sha256").update(c).digest("hex").slice(0,12)}function m(a){if(a.length<=4)return a.toLowerCase();let b=a.match(/[A-Z]/g);if(b&&b.length>1)return b.join("").toLowerCase();if(a.includes("-")||a.includes("_")){let b=a.includes("-")?"-":"_";return a.split(b).map(a=>a[0]).join("").toLowerCase()}return a.slice(0,3).toLowerCase()}function n(a,b){let c=function(a,b){let c=l(a),d=(0,f.basename)(b);return`${c}-${d}`}(a,b);return(0,f.join)(q("~/.agent-orchestrator"),c)}function o(a,b){return(0,f.join)(n(a,b),"sessions")}function p(a,b,c){let d=l(a);return`${d}-${b}-${c}`}function q(a){return a.startsWith("~/")?(0,f.join)((0,g.homedir)(),a.slice(2)):a}function r(a,b){let c=(0,f.join)(n(a,b),".origin"),d=(0,e.realpathSync)(a);if((0,e.existsSync)(c)){let f=(0,e.readFileSync)(c,"utf-8").trim();if(f!==d)throw Error(`Hash collision detected!
2
+ Directory: ${n(a,b)}
3
+ Expected config: ${d}
4
+ Actual config: ${f}
5
+ This is a rare hash collision. Please move one of the configs to a different directory.`)}else{let f=n(a,b);(0,e.mkdirSync)(f,{recursive:!0}),(0,e.writeFileSync)(c,d,"utf-8")}}function s(a,b,c){a.plugin||a.package||a.path||b.addIssue({code:i.eq.custom,message:`${c} config requires either 'plugin' (for built-ins) or 'package'/'path' (for external plugins)`}),a.package&&a.path&&b.addIssue({code:i.eq.custom,message:`${c} config cannot have both 'package' and 'path' - use one or the other`})}let t=j.Ik({auto:j.zM().default(!0),action:j.k5(["send-to-agent","notify","auto-merge"]).default("notify"),message:j.Yj().optional(),priority:j.k5(["urgent","action","warning","info"]).optional(),retries:j.ai().optional(),escalateAfter:j.KC([j.ai(),j.Yj()]).optional(),threshold:j.Yj().optional(),includeSummary:j.zM().optional()}),u=j.Ik({plugin:j.Yj().optional(),package:j.Yj().optional(),path:j.Yj().optional()}).passthrough().superRefine((a,b)=>s(a,b,"Tracker")),v=j.Ik({plugin:j.Yj().optional(),package:j.Yj().optional(),path:j.Yj().optional(),webhook:j.Ik({enabled:j.zM().default(!0),path:j.Yj().optional(),secretEnvVar:j.Yj().optional(),signatureHeader:j.Yj().optional(),eventHeader:j.Yj().optional(),deliveryHeader:j.Yj().optional(),maxBodyBytes:j.ai().int().positive().optional()}).optional()}).passthrough().superRefine((a,b)=>s(a,b,"SCM")),w=j.Ik({plugin:j.Yj().optional(),package:j.Yj().optional(),path:j.Yj().optional()}).passthrough().superRefine((a,b)=>s(a,b,"Notifier")),x=j.k5(["permissionless","default","auto-edit","suggest","skip"]).default("permissionless").transform(a=>"skip"===a?"permissionless":a),y=j.Ik({permissions:x,model:j.Yj().optional(),orchestratorModel:j.Yj().optional(),opencodeSessionId:j.Yj().optional()}).passthrough(),z=j.Ik({permissions:j.KC([j.k5(["permissionless","default","auto-edit","suggest"]),j.eu("skip")]).optional(),model:j.Yj().optional(),orchestratorModel:j.Yj().optional(),opencodeSessionId:j.Yj().optional()}).passthrough(),A=j.Ik({agent:j.Yj().optional()}).optional(),B=j.Ik({agent:j.Yj().optional(),agentConfig:z.optional()}).optional(),C=j.Ik({name:j.Yj().optional(),repo:j.Yj(),path:j.Yj(),defaultBranch:j.Yj().default("main"),sessionPrefix:j.Yj().regex(/^[a-zA-Z0-9_-]+$/,"sessionPrefix must match [a-zA-Z0-9_-]+").optional(),runtime:j.Yj().optional(),agent:j.Yj().optional(),workspace:j.Yj().optional(),tracker:u.optional(),scm:v.optional(),symlinks:j.YO(j.Yj()).optional(),postCreate:j.YO(j.Yj()).optional(),agentConfig:y.default({}),orchestrator:B,worker:B,reactions:j.g1(t.partial()).optional(),agentRules:j.Yj().optional(),agentRulesFile:j.Yj().optional(),orchestratorRules:j.Yj().optional(),orchestratorSessionStrategy:j.k5(["reuse","delete","ignore","delete-new","ignore-new","kill-previous"]).optional(),opencodeIssueSessionStrategy:j.k5(["reuse","delete","ignore"]).optional()}),D=j.Ik({runtime:j.Yj().default("tmux"),agent:j.Yj().default("claude-code"),workspace:j.Yj().default("worktree"),notifiers:j.YO(j.Yj()).default([]),orchestrator:A,worker:A}),E=j.Ik({name:j.Yj(),source:j.k5(["registry","npm","local"]),package:j.Yj().optional(),version:j.Yj().optional(),path:j.Yj().optional(),enabled:j.zM().default(!0)}).superRefine((a,b)=>{"local"!==a.source||a.path||b.addIssue({code:i.eq.custom,path:["path"],message:"Local plugins require a path"}),"registry"!==a.source&&"npm"!==a.source||a.package||b.addIssue({code:i.eq.custom,path:["package"],message:"Registry and npm plugins require a package name"})}),F=j.Ik({port:j.ai().default(3e3),terminalPort:j.ai().optional(),directTerminalPort:j.ai().optional(),readyThresholdMs:j.ai().nonnegative().default(3e5),defaults:D.default({}),plugins:j.YO(E).default([]),projects:j.g1(j.Yj().regex(/^[a-zA-Z0-9_-]+$/,"Project ID must match [a-zA-Z0-9_-]+ (no dots, slashes, or special characters)"),C),notifiers:j.g1(w).default({}),notificationRouting:j.g1(j.YO(j.Yj())).default({}),reactions:j.g1(t).default({})});function G(a){return a.startsWith("~/")?(0,f.join)((0,g.homedir)(),a.slice(2)):a}function H(a,b){if(a){let b=a.split("/"),c=b[b.length-1]??a,d=c.match(/^ao-plugin-(?:runtime|agent|workspace|tracker|scm|notifier|terminal)-(.+)$/);return d?.[1]?d[1]:c}if(b){let a=b.split("/").filter(a=>a&&"."!==a&&".."!==a);return a[a.length-1]??b}return"unknown"}function I(a,b,c,d){if(!a.package&&!a.path)return null;a.path&&(a.path=G(a.path));let e=a.plugin;return a.plugin||(a.plugin=H(a.package,a.path)),{source:b,location:c,slot:d,package:a.package,path:a.path,expectedPluginName:e}}function J(a){let b=a??function(a){if(process.env.AO_CONFIG_PATH){let a=(0,f.resolve)(process.env.AO_CONFIG_PATH);if((0,e.existsSync)(a))return a}let b=a=>{for(let b of["agent-orchestrator.yaml","agent-orchestrator.yml"]){let c=(0,f.resolve)(a,b);if((0,e.existsSync)(c))return c}let c=(0,f.resolve)(a,"..");return c===a?null:b(c)},c=b(process.cwd());if(c)return c;for(let a of[(0,f.resolve)((0,g.homedir)(),".agent-orchestrator.yaml"),(0,f.resolve)((0,g.homedir)(),".agent-orchestrator.yml"),(0,f.resolve)((0,g.homedir)(),".config","agent-orchestrator","config.yaml")])if((0,e.existsSync)(a))return a;return null}();if(!b)throw new d.kw;let c=(0,e.readFileSync)(b,"utf-8"),i=function(a){var b;let c=F.parse(a);(b=c=function(a){for(let[b,c]of Object.entries(a.projects)){if(c.name||(c.name=b),!c.sessionPrefix){let a=(0,f.basename)(c.path);c.sessionPrefix=m(a)}let a=function(a){if("gitlab"===a.scm?.plugin)return"gitlab";let b=a.scm?.host;if("string"==typeof b&&b.toLowerCase().includes("gitlab")||"gitlab"===a.tracker?.plugin)return"gitlab";let c=a.tracker?.host;return"string"==typeof c&&c.toLowerCase().includes("gitlab")?"gitlab":"github"}(c);!c.scm&&c.repo.includes("/")&&(c.scm={plugin:a}),c.tracker||(c.tracker={plugin:a})}return a}(c=function(a){for(let b of Object.values(a.projects))b.path=G(b.path);for(let b of a.plugins??[])b.path&&(b.path=G(b.path));return a}(c))).reactions={"ci-failed":{auto:!0,action:"send-to-agent",message:"CI is failing on your PR. Run `gh pr checks` to see the failures, fix them, and push.",retries:2,escalateAfter:2},"changes-requested":{auto:!0,action:"send-to-agent",message:"There are review comments on your PR. Check with `gh pr view --comments` and `gh api` for inline comments. Address each one, push fixes, and reply.",escalateAfter:"30m"},"bugbot-comments":{auto:!0,action:"send-to-agent",message:"Automated review comments found on your PR. Fix the issues flagged by the bot.",escalateAfter:"30m"},"merge-conflicts":{auto:!0,action:"send-to-agent",message:"Your branch has merge conflicts. Rebase on the default branch and resolve them.",escalateAfter:"15m"},"approved-and-green":{auto:!1,action:"notify",priority:"action",message:"PR is ready to merge"},"agent-idle":{auto:!0,action:"send-to-agent",message:"You appear to be idle. If your task is not complete, continue working — write the code, commit, push, and create a PR. If you are blocked, explain what is blocking you.",retries:2,escalateAfter:"15m"},"agent-stuck":{auto:!0,action:"notify",priority:"urgent",threshold:"10m"},"agent-needs-input":{auto:!0,action:"notify",priority:"urgent"},"agent-exited":{auto:!0,action:"notify",priority:"urgent"},"all-complete":{auto:!0,action:"notify",priority:"info",includeSummary:!0},...b.reactions};let d=function(a){let b=[];for(let[c,d]of Object.entries(a.projects)){if(d.tracker){let a=I(d.tracker,`projects.${c}.tracker`,{kind:"project",projectId:c,configType:"tracker"},"tracker");a&&b.push(a)}if(d.scm){let a=I(d.scm,`projects.${c}.scm`,{kind:"project",projectId:c,configType:"scm"},"scm");a&&b.push(a)}}for(let[c,d]of Object.entries(a.notifiers??{}))if(d){let a=I(d,`notifiers.${c}`,{kind:"notifier",notifierId:c},"notifier");a&&b.push(a)}return b}(c=b);return d.length>0&&(c.plugins=function(a,b){let c=[...a??[]],d=new Set;for(let a of c)a.package&&d.add(`package:${a.package}`),a.path&&d.add(`path:${a.path}`);for(let a of b){let b=a.package?`package:${a.package}`:`path:${a.path}`;if(d.has(b)){let b=c.find(b=>a.package&&b.package===a.package||a.path&&b.path===a.path);b&&!1===b.enabled&&(b.enabled=!0);continue}d.add(b);let e=a.expectedPluginName??H(a.package,a.path);c.push({name:e,source:a.package?"npm":"local",package:a.package,path:a.path,enabled:!0})}return c}(c.plugins,d),c._externalPluginEntries=d),!function(a){let b=new Set,c={};for(let[d,e]of Object.entries(a.projects)){let a=(0,f.basename)(e.path);if(c[a]||(c[a]=[]),c[a].push(e.path),b.has(a)){let b=c[a].join(", ");throw Error(`Duplicate project ID detected: "${a}"
6
+ Multiple projects have the same directory basename:
7
+ ${b}
33
8
 
34
- # Only process successful commands (exit code 0)
35
- if [[ "$exit_code" -ne 0 ]]; then
36
- echo '{}'
37
- exit 0
38
- fi
9
+ To fix this, ensure each project path has a unique directory name.
10
+ Alternatively, you can use the config key as a unique identifier.`)}b.add(a)}let d=new Set,e={};for(let[b,c]of Object.entries(a.projects)){let g=(0,f.basename)(c.path),h=c.sessionPrefix||m(g);if(d.has(h)){let d=e[h],f=a.projects[d];throw Error(`Duplicate session prefix detected: "${h}"
11
+ Projects "${d}" and "${b}" would generate the same prefix.
39
12
 
40
- # Only process Bash tool calls
41
- if [[ "$tool_name" != "Bash" ]]; then
42
- echo '{}' # Empty JSON output
43
- exit 0
44
- fi
13
+ To fix this, add an explicit sessionPrefix to one of these projects:
45
14
 
46
- # Validate AO_SESSION is set
47
- if [[ -z "\${AO_SESSION:-}" ]]; then
48
- echo '{"systemMessage": "AO_SESSION environment variable not set, skipping metadata update"}'
49
- exit 0
50
- fi
15
+ projects:
16
+ ${d}:
17
+ path: ${f?.path}
18
+ sessionPrefix: ${h}1 # Add explicit prefix
19
+ ${b}:
20
+ path: ${c.path}
21
+ sessionPrefix: ${h}2 # Add explicit prefix
22
+ `)}d.add(h),e[h]=b}}(c),c}((0,h.qg)(c));return i.configPath=b,i}var K=c(73136);let L=["dist/index.js","index.js"],M=[{slot:"runtime",name:"tmux",pkg:"@aoagents/ao-plugin-runtime-tmux"},{slot:"runtime",name:"process",pkg:"@aoagents/ao-plugin-runtime-process"},{slot:"agent",name:"claude-code",pkg:"@aoagents/ao-plugin-agent-claude-code"},{slot:"agent",name:"codex",pkg:"@aoagents/ao-plugin-agent-codex"},{slot:"agent",name:"aider",pkg:"@aoagents/ao-plugin-agent-aider"},{slot:"agent",name:"cursor",pkg:"@aoagents/ao-plugin-agent-cursor"},{slot:"agent",name:"opencode",pkg:"@aoagents/ao-plugin-agent-opencode"},{slot:"workspace",name:"worktree",pkg:"@aoagents/ao-plugin-workspace-worktree"},{slot:"workspace",name:"clone",pkg:"@aoagents/ao-plugin-workspace-clone"},{slot:"tracker",name:"github",pkg:"@aoagents/ao-plugin-tracker-github"},{slot:"tracker",name:"linear",pkg:"@aoagents/ao-plugin-tracker-linear"},{slot:"tracker",name:"gitlab",pkg:"@aoagents/ao-plugin-tracker-gitlab"},{slot:"scm",name:"github",pkg:"@aoagents/ao-plugin-scm-github"},{slot:"scm",name:"gitlab",pkg:"@aoagents/ao-plugin-scm-gitlab"},{slot:"notifier",name:"composio",pkg:"@aoagents/ao-plugin-notifier-composio"},{slot:"notifier",name:"desktop",pkg:"@aoagents/ao-plugin-notifier-desktop"},{slot:"notifier",name:"discord",pkg:"@aoagents/ao-plugin-notifier-discord"},{slot:"notifier",name:"openclaw",pkg:"@aoagents/ao-plugin-notifier-openclaw"},{slot:"notifier",name:"slack",pkg:"@aoagents/ao-plugin-notifier-slack"},{slot:"notifier",name:"webhook",pkg:"@aoagents/ao-plugin-notifier-webhook"},{slot:"terminal",name:"iterm2",pkg:"@aoagents/ao-plugin-terminal-iterm2"},{slot:"terminal",name:"web",pkg:"@aoagents/ao-plugin-terminal-web"}];function N(a,b,c){let d=c.plugin;return"string"==typeof d&&d.length>0?d===a:b===a}function O(a){return!!a&&"object"==typeof a&&!!(a.manifest&&"function"==typeof a.create)}function P(a){if(O(a))return a;if(a&&"object"==typeof a&&"default"in a){let b=a.default;if(O(b))return b}return null}function Q(){let a=new Map;function b(b,c,d,e){a.set(`${b}:${c}`,{manifest:d,instance:e})}function d(a,c,e=!1){let{manifest:f}=a,g=function(a,b,c=!1){let d=new Map,e=Object.entries(b.notifiers??{}),f=b.notifiers?.[a];for(let[b,c]of(f&&"object"==typeof f&&N(a,a,f)&&d.set(a,f),e))c&&"object"==typeof c&&N(a,b,c)&&d.set(b,c);return[...d.entries()].map(([d,e])=>({registrationName:d,config:function(a,b,c,d,e,f=!1){if("package"in d&&"path"in d)throw Error(`In ${a} "${c}": both "package" and "path" are specified. Use "package" for npm plugins or "path" for local plugins, not both.`);let g=!f&&M.some(c=>c.slot===a&&c.name===b);if((d.package||g)&&"path"in d){let e=d.package?`npm package "${d.package}"`:`built-in plugin "${b}"`;throw Error(`In ${a} "${c}": "path" field conflicts with reserved plugin loading field. You're loading via ${e}, but also have a "path" field which would be stripped. Rename your configuration field to something else (e.g., "apiPath", "webhookPath").`)}let{plugin:h,package:i,path:j,...k}=d;return e?{...k,configPath:e}:k}("notifier",a,d,e,b.configPath,c)}))}(f.name,c,e);if(0===g.length)return void b(f.slot,f.name,f,a.create(void 0));for(let[c,d]of g.entries()){let e=a.create(d.config);b(f.slot,d.registrationName,f,e),0===c&&d.registrationName!==f.name&&b(f.slot,f.name,f,e)}}return{register(a,c){let{manifest:d}=a,e=a.create(c);b(d.slot,d.name,d,e)},get(b,c){let d=a.get(`${b}:${c}`);return d?d.instance:null},list(b){let c=new Map;for(let[d,e]of a)d.startsWith(`${b}:`)&&!c.has(e.manifest.name)&&c.set(e.manifest.name,e.manifest);return[...c.values()]},async loadBuiltins(a,b){let e=b??(a=>c(24507)(a));for(let b of M){let c;try{c=P(await e(b.pkg))}catch{continue}if(c)try{a&&"notifier"===c.manifest.slot?d(c,a):this.register(c)}catch(a){process.stderr.write(`[plugin-registry] Failed to load built-in plugin "${b.name}": ${a}
23
+ `)}}},async loadFromConfig(a,b){await this.loadBuiltins(a,b);let g=b??(a=>c(24507)(a)),h=function(a){let b=new Map;if(!a)return b;for(let c of a){let a=c.package?`package:${c.package}`:`path:${c.path}`,d=b.get(a);d?d.push(c):b.set(a,[c])}return b}(a._externalPluginEntries);for(let b of a.plugins??[]){if(!1===b.enabled)continue;let c=function(a,b){switch(a.source){case"local":{if(!a.path)return null;let c=function(a){let b;if(!(0,e.existsSync)(a))return null;try{b=(0,e.statSync)(a)}catch{return null}if(b.isFile())return a;if(!b.isDirectory())return null;let c=(0,f.join)(a,"package.json");if((0,e.existsSync)(c))try{let b=(0,e.readFileSync)(c,"utf-8"),d=JSON.parse(b),g=function(a){if("string"==typeof a)return a;if(!a||"object"!=typeof a)return null;let b=a["."];if("string"==typeof b)return b;if(b&&"object"==typeof b){let a=b.import;if("string"==typeof a)return a;let c=b.default;if("string"==typeof c)return c}let c=a.import;if("string"==typeof c)return c;let d=a.default;return"string"==typeof d?d:null}(d.exports);if(g){let b=(0,f.resolve)(a,g);if((0,e.existsSync)(b))return b}if("string"==typeof d.module){let b=(0,f.resolve)(a,d.module);if((0,e.existsSync)(b))return b}if("string"==typeof d.main){let b=(0,f.resolve)(a,d.main);if((0,e.existsSync)(b))return b}}catch{}for(let b of L){let c=(0,f.join)(a,b);if((0,e.existsSync)(c))return c}return null}(function(a,b){if((0,f.isAbsolute)(a))return a;let c=b?(0,f.dirname)(b):process.cwd();return(0,f.resolve)(c,a)}(a.path,b.configPath));return c?(0,K.pathToFileURL)(c).href:null}case"registry":case"npm":var c;return a.package??(!(c=a.name)||c.startsWith(".")||c.startsWith("/")?null:c.startsWith("@")||c.includes("/")?c:null);default:return null}}(b,a);if(!c){process.stderr.write(`[plugin-registry] Could not resolve specifier for plugin "${b.name}" (source: ${b.source})
24
+ `);continue}try{let e=P(await g(c));if(!e)continue;for(let d of b.package?h.get(`package:${b.package}`)??[]:b.path?h.get(`path:${b.path}`)??[]:[])try{var i=e.manifest;if(d.expectedPluginName&&d.expectedPluginName!==i.name){let a=d.package?"package":"path";throw Error(`Plugin manifest.name mismatch at ${d.source}: expected "${d.expectedPluginName}" but ${a} "${c}" has manifest.name "${i.name}". Either update the 'plugin' field to match the actual manifest.name, or remove it to auto-infer.`)}!function(a,b,c){let{location:d,slot:e,source:f}=b;if("project"===d.kind){let{projectId:b,configType:e}=d,f=c.projects[b];f?.[e]&&(f[e].plugin=a.name)}else if("notifier"===d.kind){let{notifierId:b}=d,e=c.notifiers[b];e&&(e.plugin=a.name)}a.slot!==e&&process.stderr.write(`[plugin-registry] Plugin at ${f} has slot "${a.slot}" but was configured as "${e}". The plugin will be registered under its declared slot "${a.slot}".
25
+ `)}(e.manifest,d,a)}catch(a){process.stderr.write(`[plugin-registry] Config validation failed for ${d.source}: ${a}
26
+ `)}"notifier"===e.manifest.slot?d(e,a,!0):this.register(e)}catch(a){process.stderr.write(`[plugin-registry] Failed to load plugin "${c}": ${a}
27
+ `)}}}}}function R(a,b){let c=`${a}.tmp.${process.pid}.${Date.now()}`;(0,e.writeFileSync)(c,b,"utf-8"),(0,e.renameSync)(c,a)}function S(a){let b={};for(let c of a.split("\n")){let a=c.trim();if(!a||a.startsWith("#"))continue;let d=a.indexOf("=");if(-1===d)continue;let e=a.slice(0,d).trim(),f=a.slice(d+1).trim();e&&(b[e]=f)}return b}function T(a){return Object.entries(a).filter(([,a])=>void 0!==a&&""!==a).map(([a,b])=>`${a}=${b.replace(/[\r\n]/g," ")}`).join("\n")+"\n"}let U=/^[a-zA-Z0-9_-]+$/;function V(a){if(!U.test(a))throw Error(`Invalid session ID: ${a}`)}function W(a,b){return V(b),(0,f.join)(a,b)}function X(a,b){let c=W(a,b);return(0,e.existsSync)(c)?S((0,e.readFileSync)(c,"utf-8")):null}function Y(a,b,c){let d=W(a,b);(0,e.mkdirSync)((0,f.dirname)(d),{recursive:!0});let g={worktree:c.worktree,branch:c.branch,status:c.status};c.tmuxName&&(g.tmuxName=c.tmuxName),c.issue&&(g.issue=c.issue),c.pr&&(g.pr=c.pr),c.prAutoDetect&&(g.prAutoDetect=c.prAutoDetect),c.summary&&(g.summary=c.summary),c.project&&(g.project=c.project),c.agent&&(g.agent=c.agent),c.createdAt&&(g.createdAt=c.createdAt),c.runtimeHandle&&(g.runtimeHandle=c.runtimeHandle),c.restoredAt&&(g.restoredAt=c.restoredAt),c.role&&(g.role=c.role),void 0!==c.dashboardPort&&(g.dashboardPort=String(c.dashboardPort)),void 0!==c.terminalWsPort&&(g.terminalWsPort=String(c.terminalWsPort)),void 0!==c.directTerminalWsPort&&(g.directTerminalWsPort=String(c.directTerminalWsPort)),c.opencodeSessionId&&(g.opencodeSessionId=c.opencodeSessionId),c.pinnedSummary&&(g.pinnedSummary=c.pinnedSummary),c.userPrompt&&(g.userPrompt=c.userPrompt),R(d,T(g))}function Z(a,b,c){let d=W(a,b),g={};for(let[a,b]of((0,e.existsSync)(d)&&(g=S((0,e.readFileSync)(d,"utf-8"))),Object.entries(c)))if(void 0!==b)if(""===b){let{[a]:b,...c}=g;g=c}else g[a]=b;(0,e.mkdirSync)((0,f.dirname)(d),{recursive:!0}),R(d,T(g))}function $(a,b,c=!0){let d=W(a,b);if((0,e.existsSync)(d)){if(c){let c=(0,f.join)(a,"archive");(0,e.mkdirSync)(c,{recursive:!0});let g=new Date().toISOString().replace(/[:.]/g,"-"),h=(0,f.join)(c,`${b}_${g}`);(0,e.writeFileSync)(h,(0,e.readFileSync)(d,"utf-8"))}(0,e.unlinkSync)(d)}}function _(a,b){V(b);let c=(0,f.join)(a,"archive");if(!(0,e.existsSync)(c))return null;let d=`${b}_`,g=null;for(let a of(0,e.readdirSync)(c)){if(!a.startsWith(d))continue;let b=a[d.length];!b||b<"0"||b>"9"||(!g||a>g)&&(g=a)}if(!g)return null;try{return S((0,e.readFileSync)((0,f.join)(c,g),"utf-8"))}catch{return null}}function aa(a){return(0,e.existsSync)(a)?(0,e.readdirSync)(a).filter(b=>{if("archive"===b||b.startsWith(".")||!U.test(b))return!1;try{return(0,e.statSync)((0,f.join)(a,b)).isFile()}catch{return!1}}):[]}function ab(a,b){let c=W(a,b);(0,e.mkdirSync)((0,f.dirname)(c),{recursive:!0});try{let a=(0,e.openSync)(c,e.constants.O_WRONLY|e.constants.O_CREAT|e.constants.O_EXCL);return(0,e.closeSync)(a),!0}catch{return!1}}var ac=c(31421),ad=c(57975);let ae=`You are an AI coding agent managed by the Agent Orchestrator (ao).
51
28
 
52
- # Construct metadata file path
53
- # AO_DATA_DIR is already set to the project-specific sessions directory
54
- metadata_file="$AO_DATA_DIR/$AO_SESSION"
29
+ ## Session Lifecycle
30
+ - You are running inside a managed session. Focus on the assigned task.
31
+ - When you finish your work, create a PR and push it. The orchestrator will handle CI monitoring and review routing.
32
+ - If you're told to take over or continue work on an existing PR, run \`ao session claim-pr <pr-number-or-url>\` from inside this session before making changes.
33
+ - If CI fails, the orchestrator will send you the failures — fix them and push again.
34
+ - If reviewers request changes, the orchestrator will forward their comments — address each one, push fixes, and reply to the comments.
55
35
 
56
- # Ensure metadata file exists
57
- if [[ ! -f "$metadata_file" ]]; then
58
- echo '{"systemMessage": "Metadata file not found: '"$metadata_file"'"}'
59
- exit 0
60
- fi
36
+ ## Git Workflow
37
+ - Always create a feature branch from the default branch (never commit directly to it).
38
+ - Use conventional commit messages (feat:, fix:, chore:, etc.).
39
+ - Push your branch and create a PR when the implementation is ready.
40
+ - Keep PRs focused — one issue per PR.
41
+
42
+ ## PR Best Practices
43
+ - Write a clear PR title and description explaining what changed and why.
44
+ - Link the issue in the PR description so it auto-closes when merged.
45
+ - If the repo has CI checks, make sure they pass before requesting review.
46
+ - Respond to every review comment, even if just to acknowledge it.`,af=/^ses_[A-Za-z0-9_-]+$/;function ag(a){if("string"!=typeof a)return;let b=a.trim();if(0!==b.length)return af.test(b)?b:void 0}let ah=/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)/,ai=/\/(\d+)$/,aj=new Set(["spawning","working","pr_open","ci_failed","review_pending","changes_requested","approved","mergeable","merged","cleanup","needs_input","stuck","errored","killed","done","terminated"]);function ak(a){try{return JSON.parse(a)}catch{return null}}var al=c(51455);function am(a){return"'"+a.replace(/'/g,"'\\''")+"'"}async function an(a){let b=await (0,al.open)(a,"r");try{let{size:a}=await b.stat();if(0===a)return null;let c=[],d=0,e=a;for(;e>0;){let a=Math.min(4096,e);e-=a;let f=Buffer.alloc(a);await b.read(f,0,a,e),c.unshift(f),d+=a;let g=Buffer.concat(c,d).toString("utf-8").split("\n");for(let a=g.length-1;a>=0;a--){let b=g[a].trim();if(b&&(a>0||0===e))return b}}return Buffer.concat(c,d).toString("utf-8").trim()||null}finally{await b.close()}}async function ao(a){try{let[b,c]=await Promise.all([an(a),(0,al.stat)(a)]);if(!b)return null;let d=JSON.parse(b);if("object"==typeof d&&null!==d&&!Array.isArray(d))return{lastType:"string"==typeof d.type?d.type:null,modifiedAt:c.mtime};return{lastType:null,modifiedAt:c.mtime}}catch{return null}}function ap(a,b){for(let[c,d]of Object.entries(a.projects)){let a=d.sessionPrefix;if(b===a||b.startsWith(`${a}-`))return c}}function aq(a,b,c,e){return(0,d.tT)({id:a,metadata:b},c,e)?"orchestrator":"worker"}function ar(a){let{role:b,project:c,defaults:e,persistedAgent:f,spawnAgentOverride:g}=a,h="orchestrator"===b?c.orchestrator:c.worker,i="orchestrator"===b?e.orchestrator:e.worker,j=c.agentConfig??{},k=h?.agentConfig??{},l=f||("worker"===b?g??h?.agent??c.agent??i?.agent??e.agent:h?.agent??c.agent??i?.agent??e.agent),m={...j};for(let[a,b]of Object.entries(k))void 0!==b&&(m[a]=b);let n="orchestrator"===b?k.orchestratorModel??k.model??j.orchestratorModel??j.model:k.model??j.model;void 0!==n&&(m.model=n);let o=(0,d.DD)("string"==typeof m.permissions?m.permissions:void 0);void 0!==o&&(m.permissions=o);let p="string"==typeof m.subagent?m.subagent:void 0;return{role:b,agentName:l,agentConfig:m,model:n,permissions:o,subagent:p}}let as=(0,ad.promisify)(ac.execFile);async function at(a){let b,c=ag(a);if(c){for(let a of[0,200,600]){a>0&&await new Promise(b=>setTimeout(b,a));try{await as("opencode",["session","delete",c],{timeout:3e4});return}catch(a){if(function(a){if(!(a instanceof Error))return!1;let b=[a.message,a.stderr,a.stdout].filter(Boolean).join("\n");return/session not found/i.test(b)}(a))return;b=a}}throw b instanceof Error?b:Error(String(b))}}async function au(a=1e4){try{let{stdout:b}=await as("opencode",["session","list","--format","json"],{timeout:a}),c=ak(b);if(!Array.isArray(c))return[];return c.flatMap(a=>{let b;if(!a||"object"!=typeof a)return[];let c="string"==typeof a.title?a.title:"",d=ag(a.id);if(!d)return[];let e=a.updated;if("number"==typeof e&&Number.isFinite(e))b=e;else if("string"==typeof e){let a=Date.parse(e);Number.isNaN(a)||(b=a)}return[{id:d,title:c,...void 0!==b?{updatedAt:b}:{}}]})}catch{return[]}}async function av(a,b=1e4,c){let d=await (c??au(b)),e=`AO:${a}`;return d.filter(a=>a.title===e).sort((a,b)=>{let c=a.updatedAt??-1/0,d=b.updatedAt??-1/0;return c===d?0:d-c}).map(a=>a.id)}async function aw(a,b,c){return(await av(a,b,c))[0]}function ax(a){return a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}let ay=new Set(["pr_open","ci_failed","review_pending","changes_requested","approved","mergeable"]),az=new Set([...ay,"merged"]);function aA(a){return new Promise(b=>setTimeout(b,a))}async function aB(a){try{let{stdout:b}=await as("tmux",["display-message","-p","-t",a,"#{pane_current_command}"],{timeout:5e3}),c=b.trim();return c.length>0?c:null}catch{return null}}function aC(a,b,c,d,e){return function(a,b,c={}){var d;return{id:a,projectId:b.project??c.projectId??"",status:c.status??("starting"===(d=b.status)?"working":d&&aj.has(d)?d:"spawning"),activity:c.activity??null,branch:b.branch||null,issueId:b.issue||null,pr:b.pr?(()=>{let a=function(a){let b=a.match(ah);if(b){let[,c,d,e]=b;return{owner:c,repo:d,number:parseInt(e,10),url:a}}let c=a.match(ai);return c?{owner:"",repo:"",number:parseInt(c[1],10),url:a}:null}(b.pr);return{number:a?.number??0,url:b.pr,title:"",owner:a?.owner??"",repo:a?.repo??"",branch:b.branch??"",baseBranch:"",isDraft:!1}})():null,workspacePath:b.worktree||null,runtimeHandle:void 0!==c.runtimeHandle?c.runtimeHandle:b.runtimeHandle?ak(b.runtimeHandle):null,agentInfo:b.summary?{summary:b.summary,agentSessionId:null}:null,createdAt:b.createdAt?new Date(b.createdAt):c.createdAt??new Date,lastActivityAt:c.lastActivityAt??new Date,restoredAt:c.restoredAt??(b.restoredAt?new Date(b.restoredAt):void 0),metadata:b}}(a,b,{projectId:c,createdAt:d,lastActivityAt:e??new Date})}function aD(a){let{config:b,registry:c}=a;function h(a){return o(b.configPath,a.path)}function i(a){return(0,f.resolve)(a).replace(/\/$/,"")}function j(a,c,d){return!!a&&i(d)!==i(a.path)&&(function(a,c){var d,e;let h=[(d=b.configPath,e=a.path,(0,f.join)(n(d,e),"worktrees"))],i=new Set;for(let b of(c&&i.add(c),i.add((0,f.basename)(a.path)),i))h.push((0,f.join)((0,g.homedir)(),".worktrees",b));return h})(a,c).some(a=>(function(a,b){let c=i(a),d=i(b);return c===d||c.startsWith(`${d}/`)})(d,a))}function k(a){let b=(0,f.join)(a,"archive");if(!(0,e.existsSync)(b))return[];let c=new Set;for(let a of(0,e.readdirSync)(b)){let b=a.match(/^([a-zA-Z0-9_-]+)_\d/);b?.[1]&&c.add(b[1])}return[...c]}function l(a,b,c){return!!b&&(!!("orchestrator"===b.role||a.endsWith("-orchestrator"))||!!c&&RegExp(`^${ax(c)}-orchestrator-\\d+$`).test(a))}function m(a,b,c){return l(b,c??{},a.sessionPrefix)}function q(a,b){let c={...a};for(let[a,d]of Object.entries(b))if(void 0!==d){if(""===d){let{[a]:b,...d}=c;c=d;continue}c[a]=d}return c}function s(a,b,c,d){let g=(0,f.join)(a,b),h=d;if(!h)try{h=(0,e.statSync)(g).mtime}catch{h=void 0}if(Z(a,b,c),h)try{(0,e.utimesSync)(g,h,h)}catch{}}function t(a,b,c){let d={...b,raw:{...b.raw}};if(!l(d.sessionName,d.raw,c))return d;let e={};return"orchestrator"!==d.raw.role&&(e.role="orchestrator"),d.raw.pr&&(e.pr=""),"off"!==d.raw.prAutoDetect&&(e.prAutoDetect="off"),az.has(d.raw.status??"")&&(e.status="working"),Object.keys(e).length>0&&(s(a,d.sessionName,e,d.modifiedAt),d.raw=q(d.raw,e)),d}function u(a){let b=Date.parse(a.raw.restoredAt??a.raw.createdAt??"");return a.modifiedAt?a.modifiedAt.getTime():Number.isNaN(b)?0:b}function v(a){let b=h(a);if(!(0,e.existsSync)(b))return[];let c=aa(b).flatMap(a=>{let c,d=X(b,a);if(!d)return[];try{c=(0,e.statSync)((0,f.join)(b,a)).mtime}catch{}return[{sessionName:a,raw:d,modifiedAt:c}]});return function(a,b,c){let d=b.map(a=>({...a,raw:{...a.raw}})),e=new Map;for(let b of d){if(l(b.sessionName,b.raw,c)){b.raw=t(a,b,c).raw;continue}let d=b.raw.pr;if(!d)continue;let f=e.get(d)??[];f.push(b),e.set(d,f)}for(let b of e.values()){if(b.length<2)continue;let[c,...d]=[...b].sort((a,b)=>{let c=Number(ay.has(b.raw.status??""))-Number(ay.has(a.raw.status??""));if(0!==c)return c;let d=u(b)-u(a);return 0!==d?d:b.sessionName.localeCompare(a.sessionName)});for(let b of d){let c={pr:"",prAutoDetect:"off",...ay.has(b.raw.status??"")?{status:"working"}:{}};s(a,b.sessionName,c,b.modifiedAt),b.raw=q(b.raw,c)}}return d}(b,c,a.sessionPrefix)}function w(a,b){!function(a,b,c){let d;V(b);let g=(0,f.join)(a,"archive");if(!(0,e.existsSync)(g))return;let h=`${b}_`,i=null;for(let a of(0,e.readdirSync)(g)){if(!a.startsWith(h))continue;let b=a[h.length];!b||b<"0"||b>"9"||(!i||a>i)&&(i=a)}if(!i)return;let j=(0,f.join)(g,i);try{d=S((0,e.readFileSync)(j,"utf-8"))}catch{return!1}for(let[a,b]of Object.entries(c))if(void 0!==b)if(""===b){let{[a]:b,...c}=d;d=c}else d[a]=b;R(j,T(d))}(a,b,{opencodeSessionId:"",opencodeCleanedAt:new Date().toISOString()})}function x(a){let b=a=>{let b=a.match(/-(\d+)$/);if(!b)return;let c=Number.parseInt(b[1],10);return Number.isNaN(c)?void 0:c};return[...a].sort((a,c)=>{let d=b(a),e=b(c);return void 0!==d&&void 0!==e&&d!==e?e-d:void 0!==d&&void 0===e?-1:void 0===d&&void 0!==e?1:c.localeCompare(a)})}async function y(a){let{sessionsDir:b,criteria:c,strategy:d,includeTitleDiscoveryForSessionId:e=!1}=a;if("ignore"===d)return;let f=function(a,b){let c=[],d=(a,d)=>{if(!d||"opencode"!==d.agent||void 0!==b.issueId&&d.issue!==b.issueId||void 0!==b.sessionId&&a!==b.sessionId)return;let e=ag(d?.opencodeSessionId);e&&c.push(e)};for(let b of x(aa(a)))d(b,X(a,b));for(let b of x(k(a)))d(b,_(a,b));return b.sessionId&&d(b.sessionId,_(a,b.sessionId)),[...new Set(c)]}(b,c);if("delete"===d){for(let a of(e&&c.sessionId&&(f=[...f,...await av(c.sessionId)]),[...new Set(f)]))await at(a);return}return 0===f.length&&c.sessionId&&(f=await av(c.sessionId)),f[0]}async function z(a){try{let{stdout:b}=await as("git",["ls-remote","--heads","origin",`session/${a.sessionPrefix}-*`],{cwd:a.path,timeout:5e3});return b.split("\n").flatMap(b=>{let c=b.trim();if(!c)return[];let d=(c.split(/\s+/)[1]??"").match(RegExp(`refs/heads/session/${ax(a.sessionPrefix)}-(\\d+)$`));if(!d)return[];let e=Number.parseInt(d[1],10);return Number.isNaN(e)?[]:[e]}).filter((a,b,c)=>c.indexOf(a)===b)}catch{return[]}}async function A(a,c){let d=new Set;for(let b of[...aa(c),...k(c)]){let c=function(a,b){let c=a.match(RegExp(`^${ax(b)}-(\\d+)$`));if(!c)return;let d=Number.parseInt(c[1],10);return Number.isNaN(d)?void 0:d}(b,a.sessionPrefix);void 0!==c&&d.add(c)}for(let b of(await z(a)))d.add(b);let e=function(a,b){let c=0,d=RegExp(`^${ax(b)}-(\\d+)$`);for(let b of a){let a=b.match(d);if(a){let b=parseInt(a[1],10);b>c&&(c=b)}}return c+1}([...d].map(b=>`${a.sessionPrefix}-${b}`),a.sessionPrefix);for(let f=0;f<1e4;f++){let f=`${a.sessionPrefix}-${e}`,g=b.configPath?p(b.configPath,a.sessionPrefix,e):void 0;if(!d.has(e)&&ab(c,f))return{num:e,sessionId:f,tmuxName:g};d.add(e),e+=1}throw Error(`Failed to reserve session ID after 10000 attempts (prefix: ${a.sessionPrefix})`)}function B(a,d){let e=c.get("runtime",a.runtime??b.defaults.runtime),f=c.get("agent",d??a.agent??b.defaults.agent),g=c.get("workspace",a.workspace??b.defaults.workspace);return{runtime:e,agent:f,workspace:g,tracker:a.tracker?.plugin?c.get("tracker",a.tracker.plugin):null,scm:a.scm?.plugin?c.get("scm",a.scm.plugin):null}}function C(a,c,d){return ar({role:aq(c,d,a.sessionPrefix,Object.values(b.projects).map(a=>a.sessionPrefix)),project:a,defaults:b.defaults,persistedAgent:d.agent})}async function D(a,b,c,d,e){if("opencode"!==d||ag(a.metadata.opencodeSessionId))return;let f=await aw(b,1e4,e);f&&(a.metadata.opencodeSessionId=f,Z(c,b,{opencodeSessionId:f}))}function E(a){for(let[c,d]of Object.entries(b.projects)){let b,g=h(d),i=X(g,a);if(i){try{b=(0,e.statSync)((0,f.join)(g,a)).mtime}catch{b=void 0}return{raw:t(g,{sessionName:a,raw:i,modifiedAt:b},d.sessionPrefix).raw,sessionsDir:g,project:d,projectId:c}}}return null}function F(a){let b=E(a);if(!b)throw new d.Ag(a);return b}async function G(a,c,d,e,f,g,h){await D(a,c,d,f,h);let i=a.metadata.tmuxName?.trim(),j="string"==typeof i&&i.length>0,k=null!==a.runtimeHandle||j;k?!a.runtimeHandle&&j&&(a.runtimeHandle={id:i,runtimeName:e.runtime??b.defaults.runtime,data:{}}):a.runtimeHandle={id:c,runtimeName:e.runtime??b.defaults.runtime,data:{}},await I(a,g,k)}let H=new Set(["killed","done","merged","terminated","cleanup"]);async function I(a,c,d){if(d&&a.runtimeHandle&&c.runtime)try{if(!await c.runtime.isAlive(a.runtimeHandle)){H.has(a.status)||(a.status="killed"),a.activity="exited";return}}catch{}if(c.agent){try{let d=await c.agent.getActivityState(a,b.readyThresholdMs);null!==d&&(a.activity=d.state,d.timestamp&&d.timestamp>a.lastActivityAt&&(a.lastActivityAt=d.timestamp))}catch{}try{let b=await c.agent.getSessionInfo(a);b&&(a.agentInfo=b)}catch{}}}async function J(a){let c,d=Object.entries(b.projects).flatMap(([b,c])=>a&&b!==a?[]:v(c).map(a=>({sessionName:a.sessionName,projectId:b,raw:a.raw}))).map(async({sessionName:a,projectId:d,raw:g})=>{let i,j,k=b.projects[d];if(!k)return null;let l=h(k);try{let b=(0,f.join)(l,a),c=(0,e.statSync)(b);i=c.birthtime,j=c.mtime}catch{}let m=aC(a,g,d,i,j),n=C(k,a,g).agentName,o=B(k,n),p="opencode"===n?c??=au():void 0,q=null,r=new Promise(a=>{q=setTimeout(a,12e3)}),s=G(m,a,l,k,n,o,p).catch(()=>{});try{await Promise.race([s,r])}finally{q&&clearTimeout(q)}return m});return(await Promise.all(d)).filter(a=>null!==a)}async function K(a){for(let[c,d]of Object.entries(b.projects)){let b,g,i=h(d),j=X(i,a);if(!j)continue;try{let c=(0,f.join)(i,a),d=(0,e.statSync)(c);b=d.birthtime,g=d.mtime}catch{}let k=t(i,{sessionName:a,raw:j,modifiedAt:g},d.sessionPrefix),l=aC(a,k.raw,c,b,g),m=C(d,a,k.raw).agentName,n=B(d,m);return await G(l,a,i,d,m,n),l}return null}async function L(a,d){let{raw:e,sessionsDir:f,project:g,projectId:h}=F(a),i=C(g,a,e).agentName;if(e.runtimeHandle){let a=ak(e.runtimeHandle);if(a){let d=c.get("runtime",a.runtimeName??(g?g.runtime??b.defaults.runtime:b.defaults.runtime));if(d)try{await d.destroy(a)}catch{}}}let k=e.worktree;if(k&&j(g,h,k)){let a=g?B(g).workspace:c.get("workspace",b.defaults.workspace);if(a)try{await a.destroy(k)}catch{}}let l=!1;if(d?.purgeOpenCode===!0&&"opencode"===i){let b=ag(e.opencodeSessionId)??await aw(a,1e4);if(b)try{await at(b),l=!0}catch{}}$(f,a,!0),l&&w(f,a)}async function M(a,c){let e={killed:[],skipped:[],errors:[]},f=await J(a),g=new Set(f.map(a=>`${a.projectId}:${a.id}`)),i=new Set,j=new Set,l=(a,b)=>`${a}:${b}`,n=a=>{let b=a.indexOf(":");return -1===b?{projectId:"",id:a}:{projectId:a.slice(0,b),id:a.slice(b+1)}},o=(a,b)=>{let c=l(a,b);j.delete(c),i.add(c)},p=(a,b)=>{let c=l(a,b);i.has(c)||j.add(c)},q=c?.purgeOpenCode!==!1;for(let a of f)try{let e=b.projects[a.projectId];if(!e||m(e,a.id,a.metadata)){p(a.projectId,a.id);continue}let f=B(e),g=!1;if(a.pr&&f.scm)try{let b=await f.scm.getPRState(a.pr);(b===d.bz.MERGED||b===d.bz.CLOSED)&&(g=!0)}catch{}if(!g&&a.issueId&&f.tracker)try{await f.tracker.isCompleted(a.issueId,e)&&(g=!0)}catch{}if(!g&&a.runtimeHandle&&f.runtime)try{await f.runtime.isAlive(a.runtimeHandle)||(g=!0)}catch{}g?(c?.dryRun||await L(a.id,{purgeOpenCode:q}),o(a.projectId,a.id)):p(a.projectId,a.id)}catch(b){e.errors.push({sessionId:a.id,error:b instanceof Error?b.message:String(b)})}for(let[d,f]of Object.entries(b.projects)){if(a&&d!==a)continue;let b=h(f);for(let a of k(b)){if(g.has(`${d}:${a}`))continue;let h=_(b,a);if(!h)continue;if(m(f,a,h)){p(d,a);continue}let i=C(f,a,h).agentName,j=ag(h.opencodeSessionId);if("opencode"===i&&h.opencodeCleanedAt){p(d,a);continue}if("opencode"===i&&j&&q){if(!c?.dryRun)try{await at(j),w(b,a)}catch(b){e.errors.push({sessionId:a,error:`Failed to delete OpenCode session ${j}: ${b instanceof Error?b.message:String(b)}`});continue}o(d,a)}else p(d,a)}}let r=[...i,...j],s=new Map;for(let a of r){let{id:b}=n(a);s.set(b,(s.get(b)??0)+1)}let t=a=>{let{projectId:b,id:c}=n(a);return(s.get(c)??0)>1?`${b}:${c}`:c};return e.killed=[...i].map(t),e.skipped=[...j].map(t),e}async function N(a,e){let{raw:f,sessionsDir:g,project:h}=F(a),i=C(h,a,f).agentName;if("opencode"===i&&!ag(f.opencodeSessionId)){let b=await aw(a,1e4);b&&(f.opencodeSessionId=b,Z(g,a,{opencodeSessionId:b}))}let j=f.runtimeHandle?ak(f.runtimeHandle):null,k=j?.runtimeName??h.runtime??b.defaults.runtime,l=c.get("runtime",k);if(!l)throw Error(`No runtime plugin for session ${a}`);let m=c.get("agent",i);if(!m)throw Error(`No agent plugin for session ${a}`);let n=async a=>{try{return await l.getOutput(a,20)??""}catch{return""}},o=a=>{if(!a)return null;try{return m.detectActivity(a)}catch{return null}},p=a=>a.includes("Press up to edit queued messages"),q=async()=>{let a=ag(f.opencodeSessionId);if("opencode"!==i||!a)return;let b=await au(1e4);return b.find(b=>b.id===a)?.updatedAt},r=async(a,b)=>{let c=a.runtimeHandle;if(!c)return;let d=Date.now()+b,e=null,f=0;for(;;){let[a,b,g,h]=await Promise.all([l.isAlive(c).catch(()=>!0),m.isProcessRunning(c).catch(()=>!0),n(c),"tmux"===c.runtimeName?aB(c.id):Promise.resolve(m.processName)]),i=g.trim().length>0,j=null===h||h===m.processName,k=i?g.trimEnd():null,o=null!==k&&k===e;if(a&&b&&j&&(p(g)||o)){if((f+=1)>=2)return}else f=0;if(e=k,Date.now()>=d)return;await aA(500)}},s=async a=>{let b=a.runtimeHandle;if(!b)return;let c=Date.now()+5e3;for(;;){let[a,d,e,f]=await Promise.all([l.isAlive(b).catch(()=>!0),m.isProcessRunning(b).catch(()=>!0),n(b),"tmux"===b.runtimeName?aB(b.id):Promise.resolve(m.processName)]),g=null===f||f===m.processName;if(a&&g&&(d||e.trim().length>0)||Date.now()>=c)return;await aA(500)}},t=async(b,c)=>{if(d.N_.has(c.status))throw Error(`Cannot send to session ${a}: ${b}`);try{let b=await O(a);return await s(b),b}catch(d){let c=d instanceof Error?d.message:String(d);throw Error(`Cannot send to session ${a}: ${b} (${c})`,{cause:d})}},u=async(b=!1)=>{let c=await K(a);if(!c)throw new d.Ag(a);let e=c.runtimeHandle??{id:a,runtimeName:k,data:{}},f=c.runtimeHandle?c:{...c,runtimeHandle:e};if(b||(0,d.qX)(f))return t(b?"session needed to be restarted before delivery":"session is not running",f);let[g,h]=await Promise.all([l.isAlive(e).catch(()=>!0),m.isProcessRunning(e).catch(()=>!0)]);return("spawning"===f.status&&g&&(await r(f,2e4),[g,h]=await Promise.all([l.isAlive(e).catch(()=>!0),m.isProcessRunning(e).catch(()=>!0)])),g&&h)?f:t(g?"agent process is not running":"runtime is not alive",f)},v=async b=>{let c=b.runtimeHandle;if(!c)throw Error(`Session ${a} has no runtime handle`);let d=await n(c),f=o(d)??b.activity,g=await q();await l.sendMessage(c,e);for(let a=1;a<=6;a++){await aA(500);let a=await n(c),e=o(a)??b.activity,h=await q();if(void 0!==g&&void 0!==h&&h>g||p(a)||a.length>0&&a!==d||"active"!==f&&"active"===e||"waiting_input"!==f&&"waiting_input"===e)break}},w=await u();try{await v(w)}catch(a){if(!(void 0===w.restoredAt&&!d.N_.has(w.status))){if(a instanceof Error)throw a;throw Error(String(a),{cause:a})}w=await u(!0);try{await v(w)}catch(a){if(a instanceof Error)throw a;throw Error(String(a),{cause:a})}}}async function O(a){let c,f,g,i=null,j=null,k=!1,l=E(a);if(l&&(i=l.raw,j=l.sessionsDir,c=l.project,f=l.projectId),!i)for(let[d,e]of Object.entries(b.projects)){let b=h(e),g=_(b,a);if(g){i=g,j=b,c=e,f=d,k=!0;break}}if(!i||!j||!c||!f)throw new d.Ag(a);let m=C(c,a,i);if("opencode"===m.agentName&&!ag(i.opencodeSessionId)){let b=await aw(a,1e4);if(!b)throw new d.D8(a,"OpenCode session mapping is missing");i={...i,opencodeSessionId:b},k||Z(j,a,{opencodeSessionId:b})}let n=aC(a,i,f),o=B(c,m.agentName);if(await I(n,o,!0),!(0,d.qX)(n)){if(d.N_.has(n.status))throw new d.D8(a,`status is "${n.status}"`);throw new d.D8(a,"session is not in a terminal state")}if(k&&Y(j,a,{worktree:i.worktree??"",branch:i.branch??"",status:i.status??"killed",role:i.role,tmuxName:i.tmuxName,issue:i.issue,pr:i.pr,prAutoDetect:"off"===i.prAutoDetect?"off":"on"===i.prAutoDetect?"on":void 0,summary:i.summary,project:i.project,agent:i.agent,createdAt:i.createdAt,runtimeHandle:i.runtimeHandle,opencodeSessionId:i.opencodeSessionId,pinnedSummary:i.pinnedSummary}),!o.runtime)throw Error(`Runtime plugin '${c.runtime??b.defaults.runtime}' not found`);if(!o.agent)throw Error(`Agent plugin '${m.agentName}' not found`);let p=i.worktree||c.path;if(!(o.workspace?.exists?await o.workspace.exists(p):(0,e.existsSync)(p))){if(!o.workspace?.restore)throw new d.CK(p,"workspace plugin does not support restore");if(!n.branch)throw new d.CK(p,"branch metadata is missing");try{let b=await o.workspace.restore({projectId:f,project:c,sessionId:a,branch:n.branch},p);o.workspace.postCreate&&await o.workspace.postCreate(b,c)}catch(a){throw new d.CK(p,`restore failed: ${a instanceof Error?a.message:String(a)}`)}}if(n.runtimeHandle)try{await o.runtime.destroy(n.runtimeHandle)}catch{}let q={sessionId:a,projectConfig:{...c,agentConfig:{...m.agentConfig,..."orchestrator"===m.role?{permissions:"permissionless"}:{},...n.metadata?.opencodeSessionId?{opencodeSessionId:n.metadata.opencodeSessionId}:{}}},issueId:n.issueId??void 0,permissions:"orchestrator"===m.role?"permissionless":m.permissions,model:m.model,subagent:m.subagent};g=o.agent.getRestoreCommand?await o.agent.getRestoreCommand(n,c)??o.agent.getLaunchCommand(q):o.agent.getLaunchCommand(q);let r=o.agent.getEnvironment(q),s=i.tmuxName,t=await o.runtime.create({sessionId:s??a,workspacePath:p,launchCommand:g,environment:{...r,AO_SESSION:a,AO_DATA_DIR:j,AO_SESSION_NAME:a,...s&&{AO_TMUX_NAME:s},AO_CALLER_TYPE:"agent",...f&&{AO_PROJECT_ID:f},AO_CONFIG_PATH:b.configPath,...void 0!==b.port&&null!==b.port&&{AO_PORT:String(b.port)}}}),u=new Date().toISOString();Z(j,a,{status:"spawning",runtimeHandle:JSON.stringify(t),restoredAt:u});let v={...n,status:"spawning",activity:"active",workspacePath:p,runtimeHandle:t,restoredAt:new Date(u)};if(o.agent.postLaunchSetup)try{let b={...v.metadata??{}};await o.agent.postLaunchSetup(v);let c=v.metadata??{},d=Object.fromEntries(Object.entries(c).filter(([a,c])=>b[a]!==c));Object.keys(d).length>0&&Z(j,a,d)}catch{}return v}return{spawn:async function(a){let c,g,i,k,l=b.projects[a.projectId];if(!l)throw Error(`Unknown project: ${a.projectId}`);let m=ar({role:"worker",project:l,defaults:b.defaults,spawnAgentOverride:a.agent}),n=B(l,m.agentName);if(!n.runtime)throw Error(`Runtime plugin '${l.runtime??b.defaults.runtime}' not found`);if(!n.agent)throw Error(`Agent plugin '${m.agentName}' not found`);if(a.issueId&&n.tracker)try{c=await n.tracker.getIssue(a.issueId,l)}catch(b){if((0,d.Fx)(b));else throw Error(`Failed to fetch issue ${a.issueId}: ${b}`,{cause:b})}let o=h(l);b.configPath&&r(b.configPath,l.path);let{sessionId:p,tmuxName:q}=await A(l,o);if(a.branch)g=a.branch;else if(a.issueId&&n.tracker&&c){let b=c.branchName;g=b&&function(a){if(!a||"@"===a||a.startsWith(".")||a.endsWith(".")||a.endsWith("/")||a.endsWith(".lock")||a.includes("..")||a.includes("//")||a.includes("/.")||a.includes("@{")||a.startsWith("/"))return!1;for(let b=0;b<a.length;b++){let c=a.charCodeAt(b);if(c<=31||127===c)return!1}return!/[\s~^:?*[\\]/.test(a)}(b)?b:n.tracker.branchName(a.issueId,l)}else if(a.issueId){let b=a.issueId,c=/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(b)&&!b.includes("..")?b:b.toLowerCase().replace(/[^a-z0-9]+/g,"-").slice(0,60).replace(/^-+|-+$/g,"");g=`feat/${c||p}`}else g=`session/${p}`;let s=l.path;if(n.workspace)try{let b=await n.workspace.create({projectId:a.projectId,project:l,sessionId:p,branch:g});if(s=b.path,n.workspace.postCreate)try{await n.workspace.postCreate(b,l)}catch(b){if(j(l,a.projectId,s))try{await n.workspace.destroy(s)}catch{}throw b}}catch(a){try{$(o,p,!1)}catch{}throw a}if(a.issueId&&n.tracker&&c)try{i=await n.tracker.generatePrompt(a.issueId,l)}catch{}let t=function(a){let b=function(a){let b=[];if(a.agentRules&&b.push(a.agentRules),a.agentRulesFile){let c=(0,f.resolve)(a.path,a.agentRulesFile);try{let a=(0,e.readFileSync)(c,"utf-8").trim();a&&b.push(a)}catch{}}return b.length>0?b.join("\n\n"):null}(a.project),c=[];return c.push(ae),c.push(function(a){let{project:b,projectId:c,issueId:d,issueContext:e}=a,f=[];if(f.push("## Project Context"),f.push(`- Project: ${b.name??c}`),f.push(`- Repository: ${b.repo}`),f.push(`- Default branch: ${b.defaultBranch}`),b.tracker&&f.push(`- Tracker: ${b.tracker.plugin}`),d&&(f.push(`
47
+ ## Task`),f.push(`Work on issue: ${d}`),f.push(`Create a branch named so that it auto-links to the issue tracker (e.g. feat/${d}).`)),e&&(f.push(`
48
+ ## Issue Details`),f.push(e)),b.reactions){let a=[];for(let[c,d]of Object.entries(b.reactions))d.auto&&"send-to-agent"===d.action&&a.push(`- ${c}: auto-handled (you'll receive instructions)`);a.length>0&&(f.push(`
49
+ ## Automated Reactions`),f.push("The orchestrator will automatically handle these events:"),f.push(...a))}return f.join("\n")}(a)),b&&c.push(`## Project Rules
50
+ ${b}`),a.userPrompt&&c.push(`## Additional Instructions
51
+ ${a.userPrompt}`),c.join("\n\n")}({project:l,projectId:a.projectId,issueId:a.issueId,issueContext:i,userPrompt:a.prompt}),u=l.opencodeIssueSessionStrategy??"reuse",v="opencode"===n.agent.name&&a.issueId?await y({sessionsDir:o,criteria:{issueId:a.issueId},strategy:u}):void 0,w={sessionId:p,projectConfig:{...l,agentConfig:{...m.agentConfig,...v?{opencodeSessionId:v}:{}}},issueId:a.issueId,prompt:t,permissions:m.permissions,model:m.model,subagent:a.subagent??m.subagent};try{let c=n.agent.getLaunchCommand(w),d=n.agent.getEnvironment(w);k=await n.runtime.create({sessionId:q??p,workspacePath:s,launchCommand:c,environment:{...d,AO_SESSION:p,AO_DATA_DIR:o,AO_SESSION_NAME:p,...q&&{AO_TMUX_NAME:q},AO_CALLER_TYPE:"agent",AO_PROJECT_ID:a.projectId,AO_CONFIG_PATH:b.configPath,...void 0!==b.port&&null!==b.port&&{AO_PORT:String(b.port)}}})}catch(b){if(n.workspace&&j(l,a.projectId,s))try{await n.workspace.destroy(s)}catch{}try{$(o,p,!1)}catch{}throw b}let x={id:p,projectId:a.projectId,status:"spawning",activity:"active",branch:g,issueId:a.issueId??null,pr:null,workspacePath:s,runtimeHandle:k,agentInfo:null,createdAt:new Date,lastActivityAt:new Date,metadata:{...v?{opencodeSessionId:v}:{},...a.prompt?{userPrompt:a.prompt}:{}}};try{if(Y(o,p,{worktree:s,branch:g,status:"spawning",tmuxName:q,issue:a.issueId,project:a.projectId,agent:m.agentName,createdAt:new Date().toISOString(),runtimeHandle:JSON.stringify(k),opencodeSessionId:v,userPrompt:a.prompt}),n.agent.postLaunchSetup&&await n.agent.postLaunchSetup(x),"opencode"===n.agent.name&&"reuse"===u&&!x.metadata.opencodeSessionId){let a=await aw(p,1e4);a&&(x.metadata.opencodeSessionId=a)}Object.keys(x.metadata||{}).length>0&&Z(o,p,x.metadata)}catch(b){try{await n.runtime.destroy(k)}catch{}if(n.workspace&&j(l,a.projectId,s))try{await n.workspace.destroy(s)}catch{}try{$(o,p,!1)}catch{}throw b}let z=!1;if("post-launch"===n.agent.promptDelivery&&w.prompt){let a;for(let b=1;b<=3;b++)try{await new Promise(a=>setTimeout(a,3e3*b)),await n.runtime.sendMessage(k,w.prompt),z=!0;break}catch(c){a=c instanceof Error?c:Error(String(c)),console.error(`[session-manager] Prompt delivery attempt ${b}/3 failed: ${a.message}`)}z||console.error(`[session-manager] FAILED to deliver prompt to session ${p} after 3 attempts. User must send manually with 'ao send'. Last error: ${a?.message}`),x.metadata.promptDelivered=String(z)}else w.prompt&&(x.metadata.promptDelivered="true");return x.metadata.promptDelivered&&Z(o,p,x.metadata),x},spawnOrchestrator:async function(a){var c;let d,g,i,j,l=b.projects[a.projectId];if(!l)throw Error(`Unknown project: ${a.projectId}`);let m=ar({role:"orchestrator",project:l,defaults:b.defaults}),o=B(l,m.agentName);if(!o.runtime)throw Error(`Runtime plugin '${l.runtime??b.defaults.runtime}' not found`);if(!o.agent)throw Error(`Agent plugin '${m.agentName}' not found`);let q="kill-previous"===(c=l.orchestratorSessionStrategy)||"delete-new"===c?"delete":"ignore-new"===c?"ignore":c??"reuse",s=h(l);b.configPath&&r(b.configPath,l.path);let t=function(a,c){let d=`${a.sessionPrefix}-orchestrator`,e=new Set,f=RegExp(`^${ax(d)}-(\\d+)$`);for(let a of[...aa(c),...k(c)]){let b=a.match(f);if(b){let a=Number.parseInt(b[1],10);Number.isNaN(a)||e.add(a)}}for(let[c,e]of Object.entries(b.projects)){let b=e.sessionPrefix??c;if(b!==a.sessionPrefix&&b===d)throw Error(`Cannot spawn orchestrator for project "${a.sessionPrefix}": the orchestrator ID prefix "${d}" conflicts with the session prefix of project "${c}" ("${b}"). Rename one of the project sessionPrefix values to avoid this overlap.`)}let g=1;for(let a=0;a<1e4;a++){if(!e.has(g)){let a=`${d}-${g}`,e=b.configPath?p(b.configPath,d,g):void 0;if(ab(c,a))return{num:g,sessionId:a,tmuxName:e}}g+=1}throw Error(`Failed to reserve orchestrator session ID after 10000 attempts (prefix: ${d})`)}(l,s),u=t.sessionId,v=t.tmuxName,w=`orchestrator/${u}`;if(!o.workspace){try{$(s,u,!1)}catch{}throw Error(`spawnOrchestrator requires a workspace plugin but none is configured for project '${a.projectId}'`)}try{d=(await o.workspace.create({projectId:a.projectId,project:l,sessionId:u,branch:w})).path}catch(a){try{$(s,u,!1)}catch{}throw a}let x=async a=>{try{await o.workspace.destroy(d)}catch{}try{$(s,u,!1)}catch{}if(a)try{(0,e.unlinkSync)(a)}catch{}};try{o.agent.setupWorkspaceHooks&&await o.agent.setupWorkspaceHooks(d,{dataDir:s})}catch(a){throw await x(),a}if(a.systemPrompt)try{let c=n(b.configPath,l.path);(0,e.mkdirSync)(c,{recursive:!0}),g=(0,f.join)(c,`orchestrator-prompt-${u}.md`),(0,e.writeFileSync)(g,a.systemPrompt,"utf-8")}catch(a){throw await x(g),a}try{i="opencode"===o.agent.name&&"reuse"===q?await y({sessionsDir:s,criteria:{sessionId:u},strategy:"reuse"}):void 0,"opencode"===o.agent.name&&"delete"===q&&await y({sessionsDir:s,criteria:{sessionId:u},strategy:"delete",includeTitleDiscoveryForSessionId:!0})}catch(a){throw await x(g),a}let z={sessionId:u,projectConfig:{...l,agentConfig:{...m.agentConfig,permissions:"permissionless",...i?{opencodeSessionId:i}:{}}},permissions:"permissionless",model:m.model,systemPromptFile:g,subagent:m.subagent},A=o.agent.getLaunchCommand(z),C=o.agent.getEnvironment(z);try{j=await o.runtime.create({sessionId:v??u,workspacePath:d,launchCommand:A,environment:{...C,AO_SESSION:u,AO_DATA_DIR:s,AO_SESSION_NAME:u,...v&&{AO_TMUX_NAME:v},AO_CALLER_TYPE:"orchestrator",AO_PROJECT_ID:a.projectId,AO_CONFIG_PATH:b.configPath,...void 0!==b.port&&null!==b.port&&{AO_PORT:String(b.port)}}})}catch(a){throw await x(g),a}let D={id:u,projectId:a.projectId,status:"working",activity:"active",branch:w,issueId:null,pr:null,workspacePath:d,runtimeHandle:j,agentInfo:null,createdAt:new Date,lastActivityAt:new Date,metadata:{...i?{opencodeSessionId:i}:{}}};try{if(Y(s,u,{worktree:d,branch:w,status:"working",role:"orchestrator",tmuxName:v,project:a.projectId,agent:m.agentName,createdAt:new Date().toISOString(),runtimeHandle:JSON.stringify(j),opencodeSessionId:i}),o.agent.postLaunchSetup&&await o.agent.postLaunchSetup(D),"opencode"===o.agent.name&&"reuse"===q&&!D.metadata.opencodeSessionId){let a=await aw(u,1e4);a&&(D.metadata.opencodeSessionId=a)}Object.keys(D.metadata||{}).length>0&&Z(s,u,D.metadata)}catch(a){try{await o.runtime.destroy(j)}catch{}throw await x(g),a}return D},restore:O,list:J,get:K,kill:L,cleanup:M,send:N,claimPR:async function(a,b,c){let e,f=b.trim();if(!f)throw Error("PR reference is required");let{raw:g,sessionsDir:h,project:i,projectId:j}=F(a);if(l(a,g,i.sessionPrefix))throw Error(`Session ${a} is an orchestrator session and cannot claim PRs`);let k=B(i,C(i,a,g).agentName).scm;if(!k?.resolvePR||!k.checkoutPR)throw Error(`SCM plugin ${i.scm?.plugin?`"${i.scm.plugin}" `:""}does not support claiming existing PRs`);let m=await k.resolvePR(f,i),n=await k.getPRState(m);if(n!==d.bz.OPEN)throw Error(`Cannot claim PR #${m.number} because it is ${n}`);let o=new Set;for(let{sessionName:b,raw:c}of v(i).filter(b=>b.sessionName!==a)){if(!c||l(b,c,i.sessionPrefix))continue;let a=c.pr===m.url,d=c.branch===m.branch&&(c.prAutoDetect??"on")!=="off";(a||d)&&o.add(b)}let p=[...o],q=g.worktree;if(!q)throw Error(`Session ${a} has no workspace to check out PR #${m.number}`);let r=await k.checkoutPR(m,q);for(let b of(Z(h,a,{pr:m.url,status:"pr_open",branch:m.branch,prAutoDetect:""}),p)){let a=X(h,b);a&&Z(h,b,{pr:"",prAutoDetect:"off",...ay.has(a.status??"")?{status:"working"}:{}})}let s=!1;if(c?.assignOnGithub)if(k.assignPRToCurrentUser)try{await k.assignPRToCurrentUser(m),s=!0}catch(a){e=a instanceof Error?a.message:String(a)}else e=`SCM plugin "${k.name}" does not support assigning PRs`;return{sessionId:a,projectId:j,pr:m,branchChanged:r,githubAssigned:s,githubAssignmentError:e,takenOverFrom:p}},remap:async function(a,b=!1){let{raw:c,sessionsDir:d,project:e}=F(a);if("opencode"!==C(e,a,c).agentName)throw Error(`Session ${a} is not using the opencode agent`);let f=ag(c.opencodeSessionId),g=b?await aw(a,1e4):f??await aw(a,1e4);if(!g)throw Error(`OpenCode session mapping is missing for ${a}`);return Z(d,a,{opencodeSessionId:g}),g}}}let aE={debug:10,info:20,warn:30,error:40};function aF(){return new Date().toISOString()}function aG(a){return a.replace(/[^a-zA-Z0-9_-]+/g,"-").replace(/^-+|-+$/g,"")||"component"}function aH(a,b){aE[b]>=aE[function(){let a=process.env.AO_LOG_LEVEL?.trim().toLowerCase();return"debug"===a||"info"===a||"warn"===a||"error"===a?a:"warn"}()]&&process.stderr.write(`${JSON.stringify({...a,level:b})}
52
+ `)}function aI(a){let b=(0,f.join)(function(a){let b=l(a);return(0,f.join)(q("~/.agent-orchestrator"),`${b}-observability`)}(a.configPath),"processes");return(0,e.mkdirSync)(b,{recursive:!0}),b}function aJ(a,b){return(0,f.join)(aI(a),`${aG(b)}-${process.pid}.json`)}function aK(a,b){return b.localeCompare(a)}function aL(a){switch(a){case"error":return 3;case"warn":return 2;default:return 1}}function aM(a="ao"){return`${a}-${(0,k.randomUUID)()}`}function aN(a,b){let c=aG(b);function d(b,d){try{let f=aJ(a,c),g=function(a,b){if(!(0,e.existsSync)(a))return{version:1,component:b,pid:process.pid,updatedAt:aF(),metrics:{},traces:[],sessions:{},health:{}};try{let c=JSON.parse((0,e.readFileSync)(a,"utf-8"));return{version:1,component:b,pid:process.pid,updatedAt:"string"==typeof c.updatedAt?c.updatedAt:aF(),metrics:c.metrics&&"object"==typeof c.metrics?c.metrics:{},traces:Array.isArray(c.traces)?c.traces:[],sessions:c.sessions&&"object"==typeof c.sessions?c.sessions:{},health:c.health&&"object"==typeof c.health?c.health:{}}}catch{return{version:1,component:b,pid:process.pid,updatedAt:aF(),metrics:{},traces:[],sessions:{},health:{}}}}(f,c);b(g);let h=aJ(a,g.component);g.updatedAt=aF();let i=`${h}.tmp.${process.pid}.${Date.now()}`;(0,e.writeFileSync)(i,`${JSON.stringify(g,null,2)}
53
+ `,"utf-8"),(0,e.renameSync)(i,h),d&&aH(d.payload,d.level)}catch(a){aH({source:"ao-observability",component:c,outcome:"failure",operation:"observability.write",reason:a instanceof Error?a.message:String(a)},"error")}}return{component:c,recordOperation(a){let b=aF(),e=a.operation??a.metric,f=a.level??("failure"===a.outcome?"error":"info"),g={id:(0,k.randomUUID)(),timestamp:b,component:c,operation:e,outcome:a.outcome,correlationId:a.correlationId,projectId:a.projectId,sessionId:a.sessionId,path:a.path,reason:a.reason,durationMs:a.durationMs,data:a.data};d(c=>{var d,f;let h=(d=a.metric,f=a.projectId,`${f??"unknown"}::${d}`),i=c.metrics[h]??{total:0,success:0,failure:0};if(i.total+=1,i.lastAt=b,"success"===a.outcome?(i.success+=1,i.lastSuccessAt=b):(i.failure+=1,i.lastFailureAt=b,i.lastFailureReason=a.reason),c.metrics[h]=i,c.traces=[g,...c.traces].sort((a,b)=>aK(a.timestamp,b.timestamp)).slice(0,80),a.sessionId){c.sessions[a.sessionId]={sessionId:a.sessionId,projectId:a.projectId,correlationId:a.correlationId,operation:e,outcome:a.outcome,updatedAt:b,reason:a.reason};let d=Object.entries(c.sessions).sort(([,a],[,b])=>aK(a.updatedAt,b.updatedAt));c.sessions=Object.fromEntries(d.slice(0,200))}},{level:f,payload:{source:"ao-observability",component:c,metric:a.metric,operation:e,outcome:a.outcome,correlationId:a.correlationId,projectId:a.projectId,sessionId:a.sessionId,reason:a.reason,durationMs:a.durationMs,path:a.path,data:a.data}})},setHealth(a){let b=aF();d(d=>{d.health[a.surface]={surface:a.surface,status:a.status,updatedAt:b,component:c,projectId:a.projectId,correlationId:a.correlationId,reason:a.reason,details:a.details}},{level:"error"===a.status?"error":"warn"===a.status?"warn":"info",payload:{source:"ao-observability",component:c,surface:a.surface,status:a.status,projectId:a.projectId,correlationId:a.correlationId,reason:a.reason,details:a.details}})}}}function aO(a){let b=aI(a),c={};for(let a of(0,e.readdirSync)(b)){let d;if(!a.endsWith(".json"))continue;let g=(0,f.join)(b,a);try{d=JSON.parse((0,e.readFileSync)(g,"utf-8"))}catch{continue}if(d&&"object"==typeof d){for(let[a,b]of Object.entries(d.metrics??{})){let{projectId:e,metric:f}=function(a){let b=a.indexOf("::");if(-1===b)return{metric:a};let c=a.slice(0,b);return{projectId:"unknown"===c?void 0:c,metric:a.slice(b+2)}}(a);if(!e)continue;let g=c[e]??(c[e]={projectId:e,updatedAt:d.updatedAt,metrics:{},health:{},recentTraces:[],sessions:{}});g.metrics[f]=function(a,b){let c={total:(a?.total??0)+(b.total??0),success:(a?.success??0)+(b.success??0),failure:(a?.failure??0)+(b.failure??0),lastAt:a?.lastAt,lastSuccessAt:a?.lastSuccessAt,lastFailureAt:a?.lastFailureAt,lastFailureReason:a?.lastFailureReason};return b.lastAt&&(!c.lastAt||b.lastAt>c.lastAt)&&(c.lastAt=b.lastAt),b.lastSuccessAt&&(!c.lastSuccessAt||b.lastSuccessAt>c.lastSuccessAt)&&(c.lastSuccessAt=b.lastSuccessAt),b.lastFailureAt&&(!c.lastFailureAt||b.lastFailureAt>c.lastFailureAt)&&(c.lastFailureAt=b.lastFailureAt,c.lastFailureReason=b.lastFailureReason),c}(g.metrics[f],b),d.updatedAt>g.updatedAt&&(g.updatedAt=d.updatedAt)}for(let a of d.traces??[]){if(!a.projectId)continue;let b=c[a.projectId]??(c[a.projectId]={projectId:a.projectId,updatedAt:a.timestamp,metrics:{},health:{},recentTraces:[],sessions:{}});b.recentTraces.push(a),a.timestamp>b.updatedAt&&(b.updatedAt=a.timestamp)}for(let a of Object.values(d.health??{})){let b=a.projectId;if(!b)continue;let d=c[b]??(c[b]={projectId:b,updatedAt:a.updatedAt,metrics:{},health:{},recentTraces:[],sessions:{}}),e=d.health[a.surface];(!e||a.updatedAt>=e.updatedAt)&&(d.health[a.surface]=a),a.updatedAt>d.updatedAt&&(d.updatedAt=a.updatedAt)}for(let a of Object.values(d.sessions??{})){if(!a.projectId)continue;let b=c[a.projectId]??(c[a.projectId]={projectId:a.projectId,updatedAt:a.updatedAt,metrics:{},health:{},recentTraces:[],sessions:{}}),d=b.sessions[a.sessionId];(!d||a.updatedAt>=d.updatedAt)&&(b.sessions[a.sessionId]=a),a.updatedAt>b.updatedAt&&(b.updatedAt=a.updatedAt)}}}let d="ok";for(let a of Object.values(c))for(let b of(a.recentTraces=a.recentTraces.sort((a,b)=>aK(a.timestamp,b.timestamp)).slice(0,80),Object.values(a.health)))aL(b.status)>aL(d)&&(d=b.status);return{generatedAt:aF(),overallStatus:d,projects:c}}function aP(a){let b=a.match(/^(\d+)(s|m|h)$/);if(!b)return 0;let c=parseInt(b[1],10);switch(b[2]){case"s":return 1e3*c;case"m":return 6e4*c;case"h":return 36e5*c;default:return 0}}function aQ(a){return a.includes("stuck")||a.includes("needs_input")||a.includes("errored")?"urgent":a.startsWith("summary.")?"info":a.includes("approved")||a.includes("ready")||a.includes("merged")||a.includes("completed")?"action":a.includes("fail")||a.includes("changes_requested")||a.includes("conflicts")?"warning":"info"}function aR(a,b){return{id:(0,k.randomUUID)(),type:a,priority:b.priority??aQ(a),sessionId:b.sessionId,projectId:b.projectId,timestamp:new Date,message:b.message,data:b.data??{}}}function aS(a,b){switch(b){case"working":return"session.working";case"pr_open":return"pr.created";case"ci_failed":return"ci.failing";case"review_pending":return"review.pending";case"changes_requested":return"review.changes_requested";case"approved":return"review.approved";case"mergeable":return"merge.ready";case"merged":return"merge.completed";case"needs_input":return"session.needs_input";case"stuck":return"session.stuck";case"errored":return"session.errored";case"killed":return"session.killed";default:return null}}function aT(a){switch(a){case"ci.failing":return"ci-failed";case"review.changes_requested":return"changes-requested";case"automated_review.found":return"bugbot-comments";case"merge.conflicts":return"merge-conflicts";case"merge.ready":return"approved-and-green";case"session.stuck":return"agent-stuck";case"session.needs_input":return"agent-needs-input";case"session.killed":return"agent-exited";case"summary.all_complete":return"all-complete";default:return null}}function aU(a){let{config:b,registry:c,sessionManager:e,projectId:f}=a,g=aN(b,"lifecycle-manager"),h=new Map,i=new Map,j=null,k=!1,l=!1,m=new Map,n=new Map;async function p(a){m.clear();let d=Array.from(new Map(a.map(a=>a.pr).filter(a=>null!==a).map(a=>[`${a.owner}/${a.repo}#${a.number}`,a])).values());if(0===d.length)return;let e=new Map;for(let a of d){let c=Object.values(b.projects).find(b=>{let[c,d]=b.repo.split("/");return c===a.owner&&d===a.repo});if(!c?.scm?.plugin)continue;let d=c.scm.plugin;e.has(d)||e.set(d,[]);let f=e.get(d);f&&f.push(a)}for(let[a,b]of e){let d=c.get("scm",a);if(!d?.enrichSessionsPRBatch)continue;let e=Date.now();try{for(let[c,h]of(await d.enrichSessionsPRBatch(b,{recordSuccess(c){let d=Date.now()-e;g?.recordOperation({metric:"graphql_batch",operation:"batch_enrichment",correlationId:aM("graphql-batch"),outcome:"success",projectId:f,durationMs:d,data:{plugin:a,prCount:b.length,prKeys:b.map(a=>`${a.owner}/${a.repo}#${a.number}`)},level:"info"})},recordFailure(c){let d=Date.now()-e;g?.recordOperation({metric:"graphql_batch",operation:"batch_enrichment",correlationId:aM("graphql-batch"),outcome:"failure",reason:c.error,level:"warn",data:{plugin:a,prCount:b.length,error:c.error,durationMs:d}})},log(b,c){process.stderr.write(JSON.stringify({source:"ao-graphql-batch",level:b,message:c,plugin:a,timestamp:new Date().toISOString()})+"\n")}})))m.set(c,h)}catch(e){let c=e instanceof Error?e.message:String(e),d=aM("batch-enrichment");g?.recordOperation?.({metric:"lifecycle_poll",operation:"batch_enrichment",correlationId:d,outcome:"failure",reason:c,level:"warn",data:{plugin:a,prCount:b.length}})}}}function q(a,b){let c=u(a,"agent-stuck"),d=c?.threshold;if("string"!=typeof d)return!1;let e=aP(d);return!(e<=0)&&Date.now()-b.getTime()>e}async function r(a){let e=b.projects[a.projectId];if(!e)return a.status;let f=ar({role:aq(a.id,a.metadata,e.sessionPrefix,Object.values(b.projects).map(a=>a.sessionPrefix)),project:e,defaults:b.defaults,persistedAgent:a.metadata.agent}).agentName,g=c.get("agent",f),h=e.scm?.plugin?c.get("scm",e.scm.plugin):null,i=null,j="string"==typeof a.metadata.runtimeHandle||"string"==typeof a.metadata.tmuxName||a.status!==d.SB.SPAWNING;if(a.runtimeHandle&&j){let d=c.get("runtime",e.runtime??b.defaults.runtime);if(d&&!await d.isAlive(a.runtimeHandle).catch(()=>!0))return"killed"}if(g&&(a.runtimeHandle||a.workspacePath))try{if(g.recordActivity&&a.workspacePath&&a.runtimeHandle&&j)try{let d=c.get("runtime",e.runtime??b.defaults.runtime),f=d?await d.getOutput(a.runtimeHandle,10):"";f&&await g.recordActivity(a,f)}catch{}let d=await g.getActivityState(a,b.readyThresholdMs);if(d){if("waiting_input"===d.state)return"needs_input";if("exited"===d.state)return"killed";("idle"===d.state||"blocked"===d.state)&&d.timestamp&&(i=d.timestamp)}else if(a.runtimeHandle&&j){let d=c.get("runtime",e.runtime??b.defaults.runtime),f=d?await d.getOutput(a.runtimeHandle,10):"";if(f){let b=g.detectActivity(f);if("waiting_input"===b)return"needs_input";if(!await g.isProcessRunning(a.runtimeHandle))return"killed"}}}catch{if(a.status===d.SB.STUCK||a.status===d.SB.NEEDS_INPUT)return a.status}if(!a.pr&&h&&a.branch&&"off"!==a.metadata.prAutoDetect&&"orchestrator"!==a.metadata.role&&!a.id.endsWith("-orchestrator"))try{let c=await h.detectPR(a,e);if(c){a.pr=c;let d=o(b.configPath,e.path);Z(d,a.id,{pr:c.url})}}catch{}if(a.pr&&h)try{let b=`${a.pr.owner}/${a.pr.repo}#${a.pr.number}`,c=m.get(b);if(c){if(c.state===d.bz.MERGED)return"merged";if(c.state===d.bz.CLOSED)return"killed";if(c.ciStatus===d.U1.FAILING)return"ci_failed";if("changes_requested"===c.reviewDecision)return"changes_requested";if("approved"===c.reviewDecision||"none"===c.reviewDecision){if(c.mergeable)return"mergeable";if("approved"===c.reviewDecision)return"approved"}if("pending"===c.reviewDecision)return"review_pending";if(i&&q(a,i))return"stuck";return"pr_open"}let e=await h.getPRState(a.pr);if(e===d.bz.MERGED)return"merged";if(e===d.bz.CLOSED)return"killed";if(await h.getCISummary(a.pr)===d.U1.FAILING)return"ci_failed";let f=await h.getReviewDecision(a.pr);if("changes_requested"===f)return"changes_requested";if("approved"===f||"none"===f){if((await h.getMergeability(a.pr)).mergeable)return"mergeable";if("approved"===f)return"approved"}if("pending"===f)return"review_pending";if(i&&q(a,i))return"stuck";return"pr_open"}catch{}return i&&q(a,i)?"stuck":"spawning"===a.status||a.status===d.SB.STUCK||a.status===d.SB.NEEDS_INPUT?"working":a.status}async function s(a,b,c,d){let f=`${a}:${c}`,g=i.get(f);g||(g={attempts:0,firstTriggered:new Date},i.set(f,g)),g.attempts++;let h=d.retries??1/0,j=d.escalateAfter,k=!1;if(g.attempts>h&&(k=!0),"string"==typeof j){let a=aP(j);a>0&&Date.now()-g.firstTriggered.getTime()>a&&(k=!0)}if("number"==typeof j&&g.attempts>j&&(k=!0),k){let e=aR("reaction.escalated",{sessionId:a,projectId:b,message:`Reaction '${c}' escalated after ${g.attempts} attempts`,data:{reactionKey:c,attempts:g.attempts}});return await A(e,d.priority??"urgent"),{reactionType:c,success:!0,action:"escalated",escalated:!0}}let l=d.action??"notify";switch(l){case"send-to-agent":if(d.message)try{return await e.send(a,d.message),{reactionType:c,success:!0,action:"send-to-agent",message:d.message,escalated:!1}}catch{return{reactionType:c,success:!1,action:"send-to-agent",escalated:!1}}break;case"notify":{let e=aR("reaction.triggered",{sessionId:a,projectId:b,message:`Reaction '${c}' triggered notification`,data:{reactionKey:c}});return await A(e,d.priority??"info"),{reactionType:c,success:!0,action:"notify",escalated:!1}}case"auto-merge":{let d=aR("reaction.triggered",{sessionId:a,projectId:b,message:`Reaction '${c}' triggered auto-merge`,data:{reactionKey:c}});return await A(d,"action"),{reactionType:c,success:!0,action:"auto-merge",escalated:!1}}}return{reactionType:c,success:!1,action:l,escalated:!1}}function t(a,b){i.delete(`${a}:${b}`)}function u(a,c){let d=b.projects[a.projectId],e=b.reactions[c],f=d?.reactions?.[c];return(f?{...e,...f}:e)||null}function v(a,c){let d=b.projects[a.projectId];if(!d)return;Z(o(b.configPath,d.path),a.id,c);let e=Object.fromEntries(Object.entries(a.metadata).filter(([a])=>{let b=c[a];return void 0===b||""!==b}));for(let[a,b]of Object.entries(c))void 0!==b&&""!==b&&(e[a]=b);a.metadata=e}function w(a){return[...a].sort().join(",")}async function x(a,e,f,g){let h=b.projects[a.projectId];if(!h||!a.pr)return;let i=h.scm?.plugin?c.get("scm",h.scm.plugin):null;if(!i)return;let j="changes-requested",k="bugbot-comments";if(d.CM.has(f)){t(a.id,j),t(a.id,k),n.delete(a.id),v(a,{lastPendingReviewFingerprint:"",lastPendingReviewDispatchHash:"",lastPendingReviewDispatchAt:"",lastAutomatedReviewFingerprint:"",lastAutomatedReviewDispatchHash:"",lastAutomatedReviewDispatchAt:""});return}if(g?.key!==j&&g?.key!==k){let b=n.get(a.id)??0;if(Date.now()-b<12e4)return}n.set(a.id,Date.now());let[l,m]=await Promise.allSettled([i.getPendingComments(a.pr),i.getAutomatedComments(a.pr)]),o="fulfilled"===l.status&&Array.isArray(l.value)?l.value:null,p="fulfilled"===m.status&&Array.isArray(m.value)?m.value:null;if(null!==o){let b=w(o.map(a=>a.id)),c=a.metadata.lastPendingReviewFingerprint??"",d=a.metadata.lastPendingReviewDispatchHash??"";if(b!==c&&g?.key!==j&&t(a.id,j),b!==c&&v(a,{lastPendingReviewFingerprint:b}),b){if(g?.key===j&&g.result?.success)d!==b&&v(a,{lastPendingReviewDispatchHash:b,lastPendingReviewDispatchAt:new Date().toISOString()});else if((e===f||"changes_requested"!==f)&&b!==d){let c=u(a,j);c&&c.action&&(!1!==c.auto||"notify"===c.action)&&(await s(a.id,a.projectId,j,c)).success&&v(a,{lastPendingReviewDispatchHash:b,lastPendingReviewDispatchAt:new Date().toISOString()})}}else t(a.id,j),v(a,{lastPendingReviewFingerprint:"",lastPendingReviewDispatchHash:"",lastPendingReviewDispatchAt:""})}if(null!==p){let b=w(p.map(a=>a.id)),c=a.metadata.lastAutomatedReviewFingerprint??"",d=a.metadata.lastAutomatedReviewDispatchHash??"";if(b!==c&&(t(a.id,k),v(a,{lastAutomatedReviewFingerprint:b})),b){if(b!==d){let c=u(a,k);c&&c.action&&(!1!==c.auto||"notify"===c.action)&&(await s(a.id,a.projectId,k,c)).success&&v(a,{lastAutomatedReviewDispatchHash:b,lastAutomatedReviewDispatchAt:new Date().toISOString()})}}else t(a.id,k),v(a,{lastAutomatedReviewFingerprint:"",lastAutomatedReviewDispatchHash:"",lastAutomatedReviewDispatchAt:""})}}async function y(a,d,f,g){let h,i=b.projects[a.projectId];if(!i||!a.pr)return;let j=i.scm?.plugin?c.get("scm",i.scm.plugin):null;if(!j)return;let k="ci-failed";if("merged"===f||"killed"===f){t(a.id,k),v(a,{lastCIFailureFingerprint:"",lastCIFailureDispatchHash:"",lastCIFailureDispatchAt:""});return}if("ci_failed"!==f){a.metadata.lastCIFailureFingerprint&&(t(a.id,k),v(a,{lastCIFailureFingerprint:"",lastCIFailureDispatchHash:"",lastCIFailureDispatchAt:""}));return}let l=`${a.pr.owner}/${a.pr.repo}#${a.pr.number}`,n=m.get(l);if(n?.ciChecks!==void 0)h=n.ciChecks;else try{h=await j.getCIChecks(a.pr)}catch{return}let o=h.filter(a=>"failed"===a.status||a.conclusion?.toUpperCase()==="FAILURE");if(0===o.length)return;let p=w(o.map(a=>`${a.name}:${a.status}:${a.conclusion??""}`)),q=a.metadata.lastCIFailureFingerprint??"",r=a.metadata.lastCIFailureDispatchHash??"";if(p!==q&&g?.key!==k&&t(a.id,k),p!==q&&v(a,{lastCIFailureFingerprint:p}),g?.key===k&&g.result?.success||p===r)return;let s=u(a,k);if(s&&s.action&&(!1!==s.auto||"notify"===s.action)){let b=function(a){let b=["CI checks are failing on your PR. Here are the failed checks:",""];for(let c of a){let a=c.conclusion??c.status,d=c.url?` — ${c.url}`:"";b.push(`- **${c.name}**: ${a}${d}`)}return b.push("","Investigate the failures, fix the issues, and push again."),b.join("\n")}(o);try{if("send-to-agent"===s.action)await e.send(a.id,b);else{let c=aR("ci.failing",{sessionId:a.id,projectId:a.projectId,message:b,data:{failedChecks:o.map(a=>a.name)}});await A(c,s.priority??"warning")}v(a,{lastCIFailureDispatchHash:p,lastCIFailureDispatchAt:new Date().toISOString()})}catch{}}}async function z(a,d){let f,g=b.projects[a.projectId];if(!g||!a.pr)return;let h=g.scm?.plugin?c.get("scm",g.scm.plugin):null;if(!h)return;let i="merge-conflicts";if("merged"===d||"killed"===d){t(a.id,i),v(a,{lastMergeConflictDispatched:""});return}if("pr_open"!==d&&"ci_failed"!==d&&"review_pending"!==d&&"changes_requested"!==d&&"approved"!==d&&"mergeable"!==d)return;let j=`${a.pr.owner}/${a.pr.repo}#${a.pr.number}`,k=m.get(j);if(k)f=k.hasConflicts??!1;else try{f=!(await h.getMergeability(a.pr)).noConflicts}catch{return}let l=a.metadata.lastMergeConflictDispatched??"";if(f){if("true"===l)return;let b=u(a,i);if(b&&b.action&&(!1!==b.auto||"notify"===b.action))try{if("send-to-agent"===b.action){let c=b.message??"Your branch has merge conflicts. Rebase on the default branch and resolve them.";await e.send(a.id,c)}else{let c=aR("merge.conflicts",{sessionId:a.id,projectId:a.projectId,message:`${a.id}: PR has merge conflicts`});await A(c,b.priority??"warning")}v(a,{lastMergeConflictDispatched:"true"})}catch{}}else"true"===l&&(t(a.id,i),v(a,{lastMergeConflictDispatched:""}))}async function A(a,d){let e={...a,priority:d};for(let a of b.notificationRouting[d]??b.defaults.notifiers){let d=function(a,b){let c=a.notifiers?.[b];return c?.plugin?{reference:b,pluginName:c.plugin}:{reference:b,pluginName:b}}(b,a),f=c.get("notifier",d.reference)??c.get("notifier",d.pluginName);if(f)try{await f.notify(e)}catch{}}}async function B(a){let b,c=h.get(a.id)??(a.metadata?.status||a.status),e=await r(a);if(e!==c){let f=aM("lifecycle-transition");h.set(a.id,e),v(a,{status:e}),g.recordOperation({metric:"lifecycle_poll",operation:"lifecycle.transition",outcome:"success",correlationId:f,projectId:a.projectId,sessionId:a.id,data:{oldStatus:c,newStatus:e},level:function(a){let b=aS(void 0,a);if(!b)return"info";let c=aQ(b);return"urgent"===c?"error":"warning"===c?"warn":"info"}(e)}),d.CM.has(e)||(l=!1);let i=aS(void 0,c);if(i){let b=aT(i);b&&t(a.id,b)}let j=aS(c,e);if(j){let d=!1,f=aT(j);if(f){let c=u(a,f);if(c&&c.action&&(!1!==c.auto||"notify"===c.action)){let e=await s(a.id,a.projectId,f,c);b={key:f,result:e},d=!0}}if(!d){let b=aQ(j),d=aR(j,{sessionId:a.id,projectId:a.projectId,message:`${a.id}: ${c} → ${e}`,data:{oldStatus:c,newStatus:e}});await A(d,b)}}}else h.set(a.id,e);if(a.agentInfo?.summary&&!a.agentInfo.summaryIsFallback&&!a.metadata.pinnedSummary){let b=a.agentInfo.summary.replace(/[\n\r]/g," ").trim();if(b.length>=5)try{v(a,{pinnedSummary:b})}catch{}}await Promise.allSettled([x(a,c,e,b),y(a,c,e,b),z(a,e)])}async function C(){let a=aM("lifecycle-poll"),c=Date.now();if(!k){k=!0;try{let j=await e.list(f),k=j.filter(a=>{if(!d.CM.has(a.status))return!0;let b=h.get(a.id);return void 0!==b&&b!==a.status});await p(k),await Promise.allSettled(k.map(a=>B(a)));let m=new Set(j.map(a=>a.id));for(let a of h.keys())m.has(a)||h.delete(a);for(let a of i.keys()){let b=a.split(":")[0];b&&!m.has(b)&&i.delete(a)}for(let a of n.keys())m.has(a)||n.delete(a);let o=j.filter(a=>!d.CM.has(a.status));if(j.length>0&&0===o.length&&!l){l=!0;let a=aT("summary.all_complete");if(a){let c=b.reactions[a];c&&c.action&&(!1!==c.auto||"notify"===c.action)&&await s("system","all",a,c)}}f&&(g.recordOperation({metric:"lifecycle_poll",operation:"lifecycle.poll",outcome:"success",correlationId:a,projectId:f,durationMs:Date.now()-c,data:{sessionCount:j.length,activeSessionCount:o.length},level:"info"}),g.setHealth({surface:"lifecycle.worker",status:"ok",projectId:f,correlationId:a,details:{projectId:f,sessionCount:j.length,activeSessionCount:o.length}}))}catch(d){let b=d instanceof Error?d.message:String(d);g.recordOperation({metric:"lifecycle_poll",operation:"lifecycle.poll",outcome:"failure",correlationId:a,projectId:f,durationMs:Date.now()-c,reason:b,level:"error"}),g.setHealth({surface:"lifecycle.worker",status:"error",projectId:f,correlationId:a,reason:b,details:f?{projectId:f}:{projectScope:"all"}})}finally{k=!1}}}return{start(a=3e4){j||(j=setInterval(()=>void C(),a),C())},stop(){j&&(clearInterval(j),j=null)},getStates:()=>new Map(h),async check(a){let b=await e.get(a);if(!b)throw Error(`Session ${a} not found`);await B(b)}}}function aV(a){let{config:b,projectId:c,project:d}=a,e=[];if(e.push(`# ${d.name} Orchestrator
54
+
55
+ You are the **orchestrator agent** for the ${d.name} project.
56
+
57
+ Your role is to coordinate and manage worker agent sessions. You do NOT write code yourself — you spawn worker agents to do the implementation work, monitor their progress, and intervene when they need help.`),e.push(`## Non-Negotiable Rules
58
+
59
+ - Investigations from the orchestrator session are **read-only**. Inspect status, logs, metadata, PR state, and worker output, but do not edit repository files or implement fixes from the orchestrator session.
60
+ - Any code change, test run tied to implementation, git branch work, or PR takeover must be delegated to a **worker session**.
61
+ - The orchestrator session must never own a PR. Never claim a PR into the orchestrator session, and never treat the orchestrator as the worker responsible for implementation.
62
+ - If an investigation discovers follow-up work, either spawn a worker session or direct an existing worker session with clear instructions.
63
+ - **Always use \`ao send\` to communicate with sessions** — never use raw \`tmux send-keys\` or \`tmux capture-pane\`. Direct tmux access bypasses busy detection, retry logic, and input sanitization, and breaks multi-line input for some agents (e.g. Codex).
64
+ - When a session might be busy, use \`ao send --no-wait <session> <message>\` to send without waiting for the session to become idle.`),e.push(`## Project Info
65
+
66
+ - **Name**: ${d.name}
67
+ - **Repository**: ${d.repo}
68
+ - **Default Branch**: ${d.defaultBranch}
69
+ - **Session Prefix**: ${d.sessionPrefix}
70
+ - **Local Path**: ${d.path}
71
+ - **Dashboard Port**: ${b.port??3e3}`),e.push(`## Quick Start
72
+
73
+ \`\`\`bash
74
+ # See all sessions at a glance
75
+ ao status
76
+
77
+ # Spawn sessions for issues (GitHub: #123, Linear: INT-1234, etc.)
78
+ ao spawn INT-1234
79
+ ao spawn --claim-pr 123
80
+ ao batch-spawn INT-1 INT-2 INT-3
81
+
82
+ # Spawn a session without a tracker issue (prompt-driven)
83
+ ao spawn --prompt "Refactor the auth module to use JWT"
84
+
85
+ # List sessions
86
+ ao session ls -p ${c}
87
+
88
+ # Send message to a session
89
+ ao send ${d.sessionPrefix}-1 "Your message here"
90
+
91
+ # Claim an existing PR for a worker session
92
+ ao session claim-pr 123 ${d.sessionPrefix}-1
93
+
94
+ # Kill a session
95
+ ao session kill ${d.sessionPrefix}-1
96
+
97
+ # Open all sessions in terminal tabs
98
+ ao open ${c}
99
+ \`\`\``),e.push(`## Available Commands
100
+
101
+ | Command | Description |
102
+ |---------|-------------|
103
+ | \`ao status\` | Show all sessions with PR/CI/review status |
104
+ | \`ao spawn [issue] [--prompt <text>] [--claim-pr <pr>]\` | Spawn a worker session; use issue ID or --prompt for freeform tasks |
105
+ | \`ao batch-spawn <issues...>\` | Spawn multiple sessions in parallel (project auto-detected) |
106
+ | \`ao session ls [-p project]\` | List all sessions (optionally filter by project) |
107
+ | \`ao session claim-pr <pr> [session]\` | Attach an existing PR to a worker session |
108
+ | \`ao session attach <session>\` | Attach to a session's tmux window |
109
+ | \`ao session kill <session>\` | Kill a specific session |
110
+ | \`ao session cleanup [-p project]\` | Kill completed/merged sessions |
111
+ | \`ao send <session> <message>\` | Send a message to a running session |
112
+ | \`ao send --no-wait <session> <message>\` | Send without waiting for session to become idle |
113
+ | \`ao dashboard\` | Start the web dashboard (http://localhost:${b.port??3e3}) |
114
+ | \`ao open <project>\` | Open all project sessions in terminal tabs |`),e.push(`## Session Management
115
+
116
+ ### Spawning Sessions
117
+
118
+ When you spawn a session:
119
+ 1. A git worktree is created from \`${d.defaultBranch}\`
120
+ 2. A feature branch is created (e.g., \`feat/INT-1234\` for issues, \`session/<id>\` for prompt-driven)
121
+ 3. A tmux session is started (e.g., \`${d.sessionPrefix}-1\`)
122
+ 4. The agent is launched with context about the issue or prompt
123
+ 5. Metadata is written to the project-specific sessions directory
124
+
125
+ A tracker issue is **not required**. Use \`--prompt\` to spawn freeform sessions:
126
+ \`\`\`bash
127
+ ao spawn --prompt "Add rate limiting to the /api/upload endpoint"
128
+ \`\`\`
129
+
130
+ ### Monitoring Progress
131
+
132
+ Use \`ao status\` to see:
133
+ - Current session status (working, pr_open, review_pending, etc.)
134
+ - PR state (open/merged/closed)
135
+ - CI status (passing/failing/pending)
136
+ - Review decision (approved/changes_requested/pending)
137
+ - Unresolved comments count
138
+
139
+ ### Sending Messages
140
+
141
+ Send instructions to a running agent:
142
+ \`\`\`bash
143
+ ao send ${d.sessionPrefix}-1 "Please address the review comments on your PR"
144
+ \`\`\`
145
+
146
+ ### PR Takeover
147
+
148
+ If a worker session needs to continue work on an existing PR:
149
+ \`\`\`bash
150
+ ao session claim-pr 123 ${d.sessionPrefix}-1
151
+ # or do it at spawn time
152
+ ao spawn --claim-pr 123
153
+ \`\`\`
154
+
155
+ This updates AO metadata, switches the worker worktree onto the PR branch, and lets lifecycle reactions keep routing CI and review feedback to that worker session.
156
+
157
+ Never claim a PR into \`${d.sessionPrefix}-orchestrator\`. If a PR needs implementation or takeover, delegate it to a worker session instead.
158
+
159
+ ### Investigation Workflow
160
+
161
+ When debugging or triaging from the orchestrator session:
162
+ 1. Inspect with read-only commands such as \`ao status\`, \`ao session ls\`, \`ao session attach\`, and SCM/tracker lookups.
163
+ 2. Decide whether a worker already owns the work or a new worker is needed.
164
+ 3. Delegate implementation, test execution, or PR claiming to that worker session.
165
+ 4. Return to monitoring and coordination once the worker has the task.
166
+
167
+ ### Cleanup
168
+
169
+ Remove completed sessions:
170
+ \`\`\`bash
171
+ ao session cleanup -p ${c} # Kill sessions where PR is merged or issue is closed
172
+ \`\`\``),e.push(`## Dashboard
173
+
174
+ The web dashboard runs at **http://localhost:${b.port??3e3}**.
175
+
176
+ Features:
177
+ - Live session cards with activity status
178
+ - PR table with CI checks and review state
179
+ - Attention zones (merge ready, needs response, working, done)
180
+ - One-click actions (send message, kill, merge PR)
181
+ - Real-time updates via Server-Sent Events`),d.reactions&&Object.keys(d.reactions).length>0){let a=[];for(let[b,c]of Object.entries(d.reactions))c.auto&&"send-to-agent"===c.action?a.push(`- **${b}**: Auto-sends instruction to agent (retries: ${c.retries??"none"}, escalates after: ${c.escalateAfter??"never"})`):c.auto&&"notify"===c.action&&a.push(`- **${b}**: Notifies human (priority: ${c.priority??"info"})`);a.length>0&&e.push(`## Automated Reactions
182
+
183
+ The system automatically handles these events:
184
+
185
+ ${a.join("\n")}`)}return e.push(`## Common Workflows
61
186
 
62
- # Update a single key in metadata
63
- update_metadata_key() {
64
- local key="$1"
65
- local value="$2"
187
+ ### Bulk Issue Processing
188
+ 1. Get list of issues from tracker (GitHub/Linear/etc.)
189
+ 2. Use \`ao batch-spawn\` to spawn sessions for each issue
190
+ 3. Monitor with \`ao status\` or the dashboard
191
+ 4. Agents will fetch, implement, test, PR, and respond to reviews
192
+ 5. Use \`ao session cleanup\` when PRs are merged
66
193
 
67
- # Create temp file
68
- local temp_file="\${metadata_file}.tmp"
194
+ ### Handling Stuck Agents
195
+ 1. Check \`ao status\` for sessions in "stuck" or "needs_input" state
196
+ 2. Attach with \`ao session attach <session>\` to see what they're doing
197
+ 3. Send clarification or instructions with \`ao send <session> '...'\`
198
+ 4. Or kill and respawn with fresh context if needed
69
199
 
70
- # Escape special sed characters in value (& | / \\)
71
- local escaped_value=$(echo "$value" | sed 's/[&|\\/]/\\\\&/g')
200
+ ### PR Review Flow
201
+ 1. Agent creates PR and pushes
202
+ 2. CI runs automatically
203
+ 3. If CI fails: reaction auto-sends fix instructions to agent
204
+ 4. If reviewers request changes: reaction auto-sends comments to agent
205
+ 5. When approved + green: notify human to merge (unless auto-merge enabled)
72
206
 
73
- # Check if key already exists
74
- if grep -q "^$key=" "$metadata_file" 2>/dev/null; then
75
- # Update existing key
76
- sed "s|^$key=.*|$key=$escaped_value|" "$metadata_file" > "$temp_file"
207
+ ### Manual Intervention
208
+ When an agent needs human judgment:
209
+ 1. You'll get a notification (desktop/slack/webhook)
210
+ 2. Check the dashboard or \`ao status\` for details
211
+ 3. Attach to the session if needed: \`ao session attach <session>\`
212
+ 4. Send instructions: \`ao send <session> '...'\`
213
+ 5. Or handle the human-only action yourself (merge PR, close issue, etc.) while keeping implementation in worker sessions.`),e.push(`## Tips
214
+
215
+ 1. **Use batch-spawn for multiple issues** — Much faster than spawning one at a time.
216
+
217
+ 2. **Check status before spawning** — Avoid creating duplicate sessions for issues already being worked on.
218
+
219
+ 3. **Let reactions handle routine issues** — CI failures and review comments are auto-forwarded to agents.
220
+
221
+ 4. **Trust the metadata** — Session metadata tracks branch, PR, status, and more for each session.
222
+
223
+ 5. **Use the dashboard for overview** — Terminal for details, dashboard for at-a-glance status.
224
+
225
+ 6. **Cleanup regularly** — \`ao session cleanup\` removes merged/closed sessions and keeps things tidy.
226
+
227
+ 7. **Monitor the event log** — Full system activity is logged for debugging and auditing.
228
+
229
+ 8. **Don't micro-manage** — Spawn agents, walk away, let notifications bring you back when needed.`),d.orchestratorRules&&e.push(`## Project-Specific Rules
230
+
231
+ ${d.orchestratorRules}`),e.join("\n\n")}function aW(a){return(0,f.join)(a,".ao","activity.jsonl")}async function aX(a,b,c,d){let e=aW(a);await (0,al.mkdir)((0,f.dirname)(e),{recursive:!0});let g={ts:new Date().toISOString(),state:b,source:c,...void 0!==d&&("waiting_input"===b||"blocked"===b)&&{trigger:d}};await (0,al.appendFile)(e,JSON.stringify(g)+"\n","utf-8")}async function aY(a){let b=aW(a);try{let{open:a}=await Promise.resolve().then(c.t.bind(c,51455,19)),d=await a(b,"r");try{let a=await d.stat();if(0===a.size)return null;let b=Math.min(a.size,4096),c=Math.max(0,a.size-b),e=Buffer.alloc(b),{bytesRead:f}=await d.read(e,0,b,c);if(0===f)return null;let g=e.subarray(0,f).toString("utf-8").split("\n").filter(a=>a.trim());if(c>0&&g.length>1&&(g=g.slice(1)),0===g.length)return null;let h=null;for(let a=g.length-1;a>=0;a--)try{h=JSON.parse(g[a]);break}catch{continue}if(null===h||"object"!=typeof h||null===h||Array.isArray(h))return null;let i=h,j=new Set(["active","ready","idle","waiting_input","blocked","exited"]),k=new Set(["terminal","native"]);if("string"!=typeof i.ts||"string"!=typeof i.state||"string"!=typeof i.source||!j.has(i.state)||!k.has(i.source))return null;return{entry:{ts:i.ts,state:i.state,source:i.source,..."string"==typeof i.trigger&&{trigger:i.trigger}},modifiedAt:a.mtime}}finally{await d.close()}}catch{return null}}function aZ(a){if(!a)return null;let{entry:b}=a;if("waiting_input"===b.state||"blocked"===b.state){let a=new Date(b.ts);if(Number.isNaN(a.getTime()))return null;if(Date.now()-a.getTime()<=3e5)return{state:b.state,timestamp:a}}return null}function a$(a,b,c){let d;if(!a)return null;let{entry:e}=a,f=new Date(e.ts);if(Number.isNaN(f.getTime()))return null;if("waiting_input"===e.state||"blocked"===e.state)return Date.now()-f.getTime()<=3e5?{state:e.state,timestamp:f}:{state:"idle",timestamp:f};let g=Math.max(0,Date.now()-f.getTime());d=g<=b?"active":g<=c?"ready":"idle";let h={active:0,ready:1,idle:2},i=h[e.state]??2;return{state:(h[d]??2)>=i?d:e.state,timestamp:f}}async function a_(a,b,c){let{state:d,trigger:e}=function(a,b){let c=b(a),d="waiting_input"===c||"blocked"===c?a.trim().split("\n").slice(-3).join("\n"):void 0;return{state:c,trigger:d}}(b,c);if("waiting_input"!==d&&"blocked"!==d){let b=await aY(a);if(b&&b.entry.state===d&&Date.now()-b.modifiedAt.getTime()<2e4)return}await aX(a,d,"terminal",e)}let a0="/usr/local/bin",a1=`${a0}/gh`;function a2(){return(0,f.join)((0,g.homedir)(),".ao","bin")}let a3="0.2.0";function a4(a){let b=(a??"/usr/bin:/bin").split(":").filter(Boolean),c=[],d=new Set,e=a=>{!a||d.has(a)||(c.push(a),d.add(a))};for(let a of(e(a2()),e(a0),b))e(a);return c.join(":")}let a5=`#!/usr/bin/env bash
232
+ # ao-metadata-helper — shared by gh/git wrappers
233
+ # Provides: update_ao_metadata <key> <value>
234
+
235
+ update_ao_metadata() {
236
+ local key="$1" value="$2"
237
+ local ao_dir="\${AO_DATA_DIR:-}"
238
+ local ao_session="\${AO_SESSION:-}"
239
+
240
+ [[ -z "$ao_dir" || -z "$ao_session" ]] && return 0
241
+
242
+ # Validate: session name must not contain path separators or traversal
243
+ case "$ao_session" in
244
+ */* | *..*) return 0 ;;
245
+ esac
246
+
247
+ # Validate: ao_dir must be an absolute path under known ao directories or /tmp
248
+ case "$ao_dir" in
249
+ "$HOME"/.ao/* | "$HOME"/.agent-orchestrator/* | /tmp/*) ;;
250
+ *) return 0 ;;
251
+ esac
252
+
253
+ local metadata_file="$ao_dir/$ao_session"
254
+
255
+ # Resolve symlinks and verify canonicalized paths are still within trusted roots
256
+ local real_dir real_ao_dir
257
+ real_ao_dir="$(cd "$ao_dir" 2>/dev/null && pwd -P)" || return 0
258
+ real_dir="$(cd "$(dirname "$metadata_file")" 2>/dev/null && pwd -P)" || return 0
259
+
260
+ # Re-validate real_ao_dir against trusted roots after canonicalization
261
+ # (prevents /tmp/../../home/user from escaping the allowlist)
262
+ case "$real_ao_dir" in
263
+ "$HOME"/.ao/* | "$HOME"/.ao | "$HOME"/.agent-orchestrator/* | "$HOME"/.agent-orchestrator | /tmp/*) ;;
264
+ *) return 0 ;;
265
+ esac
266
+
267
+ [[ "$real_dir" == "$real_ao_dir"* ]] || return 0
268
+
269
+ [[ -f "$metadata_file" ]] || return 0
270
+
271
+ # Validate key — only allow alphanumeric, underscore, hyphen (prevents sed injection)
272
+ [[ "$key" =~ ^[a-zA-Z0-9_-]+$ ]] || return 0
273
+
274
+ local temp_file="\${metadata_file}.tmp.$$"
275
+
276
+ # Strip newlines from value to prevent metadata line injection
277
+ local clean_value="$(printf '%s' "$value" | tr -d '\\n')"
278
+
279
+ # Escape sed metacharacters in value (& expands to matched text, | breaks delimiter)
280
+ local escaped_value="$(printf '%s' "$clean_value" | sed 's/[&|\\\\]/\\\\&/g')"
281
+
282
+ if grep -q "^\${key}=" "$metadata_file" 2>/dev/null; then
283
+ sed "s|^\${key}=.*|\${key}=\${escaped_value}|" "$metadata_file" > "$temp_file"
77
284
  else
78
- # Append new key
79
285
  cp "$metadata_file" "$temp_file"
80
- echo "$key=$value" >> "$temp_file"
286
+ printf '%s=%s\\n' "$key" "$clean_value" >> "$temp_file"
81
287
  fi
82
288
 
83
- # Atomic replace
84
289
  mv "$temp_file" "$metadata_file"
85
290
  }
291
+ `,a6=`#!/usr/bin/env bash
292
+ # ao gh wrapper — auto-updates session metadata on PR operations
86
293
 
87
- # ============================================================================
88
- # Command Detection and Parsing
89
- # ============================================================================
90
-
91
- # Strip leading directory-change prefixes so that commands like
92
- # cd ~/.worktrees/project && gh pr create ...
93
- # are correctly detected. Agents frequently cd into a worktree first.
94
- # Store the regex pattern in a variable for clarity (avoids shell quoting confusion).
95
- # Uses space-padded (&&|;) to avoid breaking on paths containing & or ; chars.
96
- cd_prefix_pattern='^[[:space:]]*cd[[:space:]]+.*[[:space:]]+(&&|;)[[:space:]]+(.*)'
97
- clean_command="$command"
98
- while [[ "$clean_command" =~ ^[[:space:]]*cd[[:space:]] ]]; do
99
- if [[ "$clean_command" =~ $cd_prefix_pattern ]]; then
100
- clean_command="\${BASH_REMATCH[2]}"
101
- else
102
- break
103
- fi
104
- done
105
-
106
- # Detect: gh pr create
107
- if [[ "$clean_command" =~ ^gh[[:space:]]+pr[[:space:]]+create ]]; then
108
- # Extract PR URL from output
109
- pr_url=$(echo "$output" | grep -Eo 'https://github[.]com/[^/]+/[^/]+/pull/[0-9]+' | head -1)
110
-
111
- if [[ -n "$pr_url" ]]; then
112
- update_metadata_key "pr" "$pr_url"
113
- update_metadata_key "status" "pr_open"
114
- echo '{"systemMessage": "Updated metadata: PR created at '"$pr_url"'"}'
115
- exit 0
294
+ # Find real gh by removing our wrapper directory from PATH
295
+ ao_bin_dir="$(cd "$(dirname "$0")" && pwd)"
296
+ clean_path="$(echo "$PATH" | tr ':' '\\n' | grep -Fxv "$ao_bin_dir" | grep . | tr '\\n' ':')"
297
+ clean_path="\${clean_path%:}"
298
+ real_gh=""
299
+
300
+ # Prefer explicit gh path when provided by AO environment.
301
+ # Guard against recursive self-reference to the wrapper in ~/.ao/bin.
302
+ if [[ -n "\${GH_PATH:-}" && -x "$GH_PATH" ]]; then
303
+ gh_dir="$(cd "$(dirname "$GH_PATH")" 2>/dev/null && pwd)"
304
+ if [[ "$gh_dir" != "$ao_bin_dir" ]]; then
305
+ real_gh="$GH_PATH"
116
306
  fi
117
307
  fi
118
308
 
119
- # Detect: git checkout -b <branch> or git switch -c <branch>
120
- if [[ "$clean_command" =~ ^git[[:space:]]+checkout[[:space:]]+-b[[:space:]]+([^[:space:]]+) ]] || \\
121
- [[ "$clean_command" =~ ^git[[:space:]]+switch[[:space:]]+-c[[:space:]]+([^[:space:]]+) ]]; then
122
- branch="\${BASH_REMATCH[1]}"
309
+ if [[ -z "$real_gh" ]]; then
310
+ real_gh="$(PATH="$clean_path" command -v gh 2>/dev/null)"
311
+ fi
123
312
 
124
- if [[ -n "$branch" ]]; then
125
- update_metadata_key "branch" "$branch"
126
- echo '{"systemMessage": "Updated metadata: branch = '"$branch"'"}'
127
- exit 0
128
- fi
313
+ if [[ -z "$real_gh" ]]; then
314
+ echo "ao-wrapper: gh not found in PATH" >&2
315
+ exit 127
129
316
  fi
130
317
 
131
- # Detect: git checkout <branch> (without -b) or git switch <branch> (without -c)
132
- # Only update if the branch name looks like a feature branch (contains / or -)
133
- if [[ "$clean_command" =~ ^git[[:space:]]+checkout[[:space:]]+([^[:space:]-]+[/-][^[:space:]]+) ]] || \\
134
- [[ "$clean_command" =~ ^git[[:space:]]+switch[[:space:]]+([^[:space:]-]+[/-][^[:space:]]+) ]]; then
135
- branch="\${BASH_REMATCH[1]}"
136
-
137
- # Avoid updating for checkout of commits/tags
138
- if [[ -n "$branch" && "$branch" != "HEAD" ]]; then
139
- update_metadata_key "branch" "$branch"
140
- echo '{"systemMessage": "Updated metadata: branch = '"$branch"'"}'
141
- exit 0
142
- fi
318
+ # Source the metadata helper
319
+ source "$ao_bin_dir/ao-metadata-helper.sh" 2>/dev/null || true
320
+
321
+ # Only capture output for commands we need to parse (pr/create, pr/merge).
322
+ # All other commands pass through transparently without stream merging.
323
+ case "$1/$2" in
324
+ pr/create|pr/merge)
325
+ tmpout="$(mktemp)"
326
+ trap 'rm -f "$tmpout"' EXIT
327
+
328
+ "$real_gh" "$@" 2>&1 | tee "$tmpout"
329
+ exit_code=\${PIPESTATUS[0]}
330
+
331
+ if [[ $exit_code -eq 0 ]]; then
332
+ output="$(cat "$tmpout")"
333
+ case "$1/$2" in
334
+ pr/create)
335
+ pr_url="$(echo "$output" | grep -Eo 'https://github\\.com/[^/]+/[^/]+/pull/[0-9]+' | head -1)"
336
+ if [[ -n "$pr_url" ]]; then
337
+ update_ao_metadata pr "$pr_url"
338
+ update_ao_metadata status pr_open
339
+ fi
340
+ ;;
341
+ pr/merge)
342
+ update_ao_metadata status merged
343
+ ;;
344
+ esac
345
+ fi
346
+
347
+ exit $exit_code
348
+ ;;
349
+ *)
350
+ exec "$real_gh" "$@"
351
+ ;;
352
+ esac
353
+ `,a7=`#!/usr/bin/env bash
354
+ # ao git wrapper — auto-updates session metadata on branch operations
355
+
356
+ # Find real git by removing our wrapper directory from PATH
357
+ ao_bin_dir="$(cd "$(dirname "$0")" && pwd)"
358
+ clean_path="$(echo "$PATH" | tr ':' '\\n' | grep -Fxv "$ao_bin_dir" | grep . | tr '\\n' ':')"
359
+ clean_path="\${clean_path%:}"
360
+ real_git="$(PATH="$clean_path" command -v git 2>/dev/null)"
361
+
362
+ if [[ -z "$real_git" ]]; then
363
+ echo "ao-wrapper: git not found in PATH" >&2
364
+ exit 127
143
365
  fi
144
366
 
145
- # Detect: gh pr merge
146
- if [[ "$clean_command" =~ ^gh[[:space:]]+pr[[:space:]]+merge ]]; then
147
- update_metadata_key "status" "merged"
148
- echo '{"systemMessage": "Updated metadata: status = merged"}'
149
- exit 0
367
+ # Source the metadata helper
368
+ source "$ao_bin_dir/ao-metadata-helper.sh" 2>/dev/null || true
369
+
370
+ # Run real git
371
+ "$real_git" "$@"
372
+ exit_code=$?
373
+
374
+ # Only update metadata on success
375
+ if [[ $exit_code -eq 0 ]]; then
376
+ case "$1/$2" in
377
+ checkout/-b)
378
+ update_ao_metadata branch "$3"
379
+ ;;
380
+ switch/-c)
381
+ update_ao_metadata branch "$3"
382
+ ;;
383
+ checkout/*|switch/*)
384
+ # Existing branch switch — only track feature-looking branches (contain / or -)
385
+ # Skip flags (e.g. -B), HEAD, tags, commit hashes, and simple names like "main"
386
+ branch="$2"
387
+ # If $2 is a flag, the actual branch name is in $3
388
+ if [[ "$branch" == -* ]]; then branch="$3"; fi
389
+ if [[ -n "$branch" && "$branch" != "HEAD" && "$branch" != -* && "$branch" == *[/-]* ]]; then
390
+ update_ao_metadata branch "$branch"
391
+ fi
392
+ ;;
393
+ esac
150
394
  fi
151
395
 
152
- # No matching command, exit silently
153
- echo '{}'
154
- exit 0
155
- `;function s(a){return a.replace(/\\/g,"/").replace(/:/g,"").replace(/[/.]/g,"-")}async function t(a){let b;try{b=await (0,p.readdir)(a)}catch{return null}let c=b.filter(a=>a.endsWith(".jsonl")&&!a.startsWith("agent-"));if(0===c.length)return null;let d=await Promise.all(c.map(async b=>{let c=(0,k.join)(a,b);try{let a=await (0,p.stat)(c);return{path:c,mtime:a.mtimeMs}}catch{return{path:c,mtime:0}}}));return d.sort((a,b)=>b.mtime-a.mtime),d[0]?.path??null}async function u(a,b=131072){let c,d;try{let{size:e=0}=await (0,p.stat)(a);if(d=Math.max(0,e-b),0===d)c=await (0,p.readFile)(a,"utf-8");else{let b=await (0,p.open)(a,"r");try{let a=e-d,f=Buffer.allocUnsafe(a);await b.read(f,0,a,d),c=f.toString("utf-8")}finally{await b.close()}}}catch{return[]}let e=c.indexOf("\n"),f=d>0&&e>=0?c.slice(e+1):c,g=[];for(let a of f.split("\n")){let b=a.trim();if(b)try{let a=JSON.parse(b);"object"!=typeof a||null===a||Array.isArray(a)||g.push(a)}catch{}}return g}let v=null;async function w(){let a=Date.now();if(v&&a-v.timestamp<5e3)return v.promise?v.promise:v.output;let b=q("ps",["-eo","pid,tty,args"],{timeout:5e3}).then(({stdout:a})=>(v?.promise===b&&(v={output:a,timestamp:Date.now()}),a));v={output:"",timestamp:a,promise:b};try{return await b}catch{return v?.promise===b&&(v=null),""}}async function x(a){try{if("tmux"===a.runtimeName&&a.id){let{stdout:b}=await q("tmux",["list-panes","-t",a.id,"-F","#{pane_tty}"],{timeout:5e3}),c=b.trim().split("\n").map(a=>a.trim()).filter(Boolean);if(0===c.length)return null;let d=await w();if(!d)return null;let e=new Set(c.map(a=>a.replace(/^\/dev\//,""))),f=/(?:^|\/)claude(?:\s|$)/;for(let a of d.split("\n")){let b=a.trimStart().split(/\s+/);if(b.length<3||!e.has(b[1]??""))continue;let c=b.slice(2).join(" ");if(f.test(c))return parseInt(b[0]??"0",10)}return null}let b=a.data.pid,c="number"==typeof b?b:Number(b);if(Number.isFinite(c)&&c>0)try{return process.kill(c,0),c}catch(a){if(a instanceof Error&&"code"in a&&"EPERM"===a.code)return c}return null}catch{return null}}async function y(a,b){let c=(0,k.join)(a,".claude"),d=(0,k.join)(c,"settings.json"),e=(0,k.join)(c,"metadata-updater.sh");try{await (0,p.mkdir)(c,{recursive:!0})}catch{}await (0,p.writeFile)(e,r,"utf-8"),await (0,p.chmod)(e,493);let f={};if((0,i.existsSync)(d))try{let a=await (0,p.readFile)(d,"utf-8");f=JSON.parse(a)}catch{}let g=f.hooks??{},h=g.PostToolUse??[],j=-1,l=-1;for(let a=0;a<h.length;a++){let b=h[a];if("object"!=typeof b||null===b||Array.isArray(b))continue;let c=b.hooks;if(Array.isArray(c)){for(let b=0;b<c.length;b++){let d=c[b];if(!("object"!=typeof d||null===d||Array.isArray(d))&&"string"==typeof d.command&&d.command.includes("metadata-updater.sh")){j=a,l=b;break}}if(j>=0)break}}-1===j?h.push({matcher:"Bash",hooks:[{type:"command",command:b,timeout:5e3}]}):h[j].hooks[l].command=b,g.PostToolUse=h,f.hooks=g,await (0,p.writeFile)(d,JSON.stringify(f,null,2)+"\n","utf-8")}let z={manifest:{name:"claude-code",slot:"agent",description:"Agent plugin: Claude Code CLI",version:"0.1.0",displayName:"Claude Code"},create:function(){return{name:"claude-code",processName:"claude",promptDelivery:"post-launch",getLaunchCommand(a){let b=["claude"],c=(0,d.DD)(a.permissions);return("permissionless"===c||"auto-edit"===c)&&b.push("--dangerously-skip-permissions"),a.model&&b.push("--model",(0,d.TQ)(a.model)),a.systemPromptFile?b.push("--append-system-prompt",`"$(cat ${(0,d.TQ)(a.systemPromptFile)})"`):a.systemPrompt&&b.push("--append-system-prompt",(0,d.TQ)(a.systemPrompt)),b.join(" ")},getEnvironment(a){let b={};return b.CLAUDECODE="",b.AO_SESSION_ID=a.sessionId,a.issueId&&(b.AO_ISSUE_ID=a.issueId),b},detectActivity:a=>(function(a){if(!a.trim())return"idle";let b=a.trim().split("\n"),c=b[b.length-1]?.trim()??"";if(/^[❯>$#]\s*$/.test(c))return"idle";let d=b.slice(-5).join("\n");return/Do you want to proceed\?/i.test(d)||/\(Y\)es.*\(N\)o/i.test(d)||/bypass.*permissions/i.test(d)?"waiting_input":"active"})(a),isProcessRunning:async a=>null!==await x(a),async getActivityState(a,b){let c=b??d.PE,e=new Date;if(!a.runtimeHandle||!await this.isProcessRunning(a.runtimeHandle))return{state:"exited",timestamp:e};if(!a.workspacePath)return null;let f=s(a.workspacePath),g=(0,k.join)((0,j.homedir)(),".claude","projects",f),h=await t(g);if(!h)return{state:"idle",timestamp:a.createdAt};let i=await (0,d.XI)(h);if(!i)return null;let l=Date.now()-i.modifiedAt.getTime(),m=i.modifiedAt,n=Math.min(d.V1,c);switch(i.lastType){case"user":case"tool_use":case"progress":default:if(l<=n)return{state:"active",timestamp:m};return{state:l>c?"idle":"ready",timestamp:m};case"assistant":case"system":case"summary":case"result":return{state:l>c?"idle":"ready",timestamp:m};case"permission_request":return{state:"waiting_input",timestamp:m};case"error":return{state:"blocked",timestamp:m}}},async getSessionInfo(a){if(!a.workspacePath)return null;let b=s(a.workspacePath),c=(0,k.join)((0,j.homedir)(),".claude","projects",b),d=await t(c);if(!d)return null;let e=await u(d);if(0===e.length)return null;let f=(0,k.basename)(d,".jsonl"),g=function(a){for(let b=a.length-1;b>=0;b--){let c=a[b];if(c?.type==="summary"&&c.summary)return{summary:c.summary,isFallback:!1}}for(let b of a)if(b?.type==="user"&&b.message?.content&&"string"==typeof b.message.content){let a=b.message.content.trim();if(a.length>0)return{summary:a.length>120?a.substring(0,120)+"...":a,isFallback:!0}}return null}(e);return{summary:g?.summary??null,summaryIsFallback:g?.isFallback,agentSessionId:f,cost:function(a){let b=0,c=0,d=0;for(let e of a)"number"==typeof e.costUSD?d+=e.costUSD:"number"==typeof e.estimatedCostUsd&&(d+=e.estimatedCostUsd),e.usage?(b+=e.usage.input_tokens??0,b+=e.usage.cache_read_input_tokens??0,b+=e.usage.cache_creation_input_tokens??0,c+=e.usage.output_tokens??0):("number"==typeof e.inputTokens&&(b+=e.inputTokens),"number"==typeof e.outputTokens&&(c+=e.outputTokens));if(0!==b||0!==c||0!==d)return 0===d&&(b>0||c>0)&&(d=b/1e6*3+c/1e6*15),{inputTokens:b,outputTokens:c,estimatedCostUsd:d}}(e)}},async getRestoreCommand(a,b){if(!a.workspacePath)return null;let c=s(a.workspacePath),e=(0,k.join)((0,j.homedir)(),".claude","projects",c),f=await t(e);if(!f)return null;let g=(0,k.basename)(f,".jsonl");if(!g)return null;let h=["claude","--resume",(0,d.TQ)(g)],i=(0,d.DD)(b.agentConfig?.permissions);return("permissionless"===i||"auto-edit"===i)&&h.push("--dangerously-skip-permissions"),b.agentConfig?.model&&h.push("--model",(0,d.TQ)(b.agentConfig.model)),h.join(" ")},async setupWorkspaceHooks(a,b){await y(a,".claude/metadata-updater.sh")},async postLaunchSetup(a){a.workspacePath&&await y(a.workspacePath,".claude/metadata-updater.sh")}}},detect:function(){try{return(0,e.execFileSync)("claude",["--version"],{stdio:"ignore"}),!0}catch{return!1}}},A=(0,f.promisify)(e.execFile);function B(a){if("number"==typeof a){if(!Number.isFinite(a))return null;let b=new Date(a);return Number.isNaN(b.getTime())?null:b}if("string"!=typeof a)return null;let b=a.trim();if(0===b.length)return null;if(/^\d+$/.test(b)){let a=Number(b);if(!Number.isFinite(a))return null;let c=new Date(a);return Number.isNaN(c.getTime())?null:c}let c=Date.parse(b);return Number.isFinite(c)?new Date(c):null}async function C(a){try{let{stdout:b}=await A("opencode",["session","list","--format","json"],{timeout:3e4}),c=function(a){let b;try{b=JSON.parse(a)}catch{return[]}return Array.isArray(b)?b.filter(a=>!!a&&"object"==typeof a&&void 0!==(0,d.Hr)(a.id)):[]}(b);if(a.metadata?.opencodeSessionId){let b=c.find(b=>b.id===a.metadata.opencodeSessionId);if(b)return b}let e=c.filter(b=>b.title===`AO:${a.id}`);if(0===e.length)return null;if(1===e.length)return e[0];return e.reduce((a,b)=>{let c=B(a.updated)?.getTime()??0;return(B(b.updated)?.getTime()??0)>c?b:a})}catch{return null}}let D={manifest:{name:"opencode",slot:"agent",description:"Agent plugin: OpenCode",version:"0.1.0",displayName:"OpenCode"},create:function(){return{name:"opencode",processName:"opencode",getLaunchCommand(a){let b,c=[],e=[],f=(0,d.Hr)(a.projectConfig.agentConfig?.opencodeSessionId);if(f&&c.push("--session",(0,d.TQ)(f)),a.subagent&&e.push("--agent",(0,d.TQ)(a.subagent)),a.prompt?b=a.systemPromptFile?`"$(cat ${(0,d.TQ)(a.systemPromptFile)}; printf '\\n\\n'; printf %s ${(0,d.TQ)(a.prompt)})"`:a.systemPrompt?(0,d.TQ)(`${a.systemPrompt}
156
-
157
- ${a.prompt}`):(0,d.TQ)(a.prompt):a.systemPromptFile?b=`"$(cat ${(0,d.TQ)(a.systemPromptFile)})"`:a.systemPrompt&&(b=(0,d.TQ)(a.systemPrompt)),a.model&&e.push("--model",(0,d.TQ)(a.model)),!f){let c=["--format","json","--title",(0,d.TQ)(`AO:${a.sessionId}`),...e],f=`
158
- let buffer = '';
159
- let captured = null;
160
- process.stdin.on('data', chunk => {
161
- buffer += chunk;
162
- const lines = buffer.split('\\n');
163
- buffer = lines.pop() || '';
164
- for (const line of lines) {
165
- if (captured) continue;
166
- const trimmed = line.trim();
167
- if (!trimmed) continue;
168
- try {
169
- const obj = JSON.parse(trimmed);
170
- const sid = (typeof obj.session_id === 'string' && obj.session_id) || (typeof obj.sessionID === 'string' && obj.sessionID);
171
- if (sid && /^ses_[A-Za-z0-9_-]+$/.test(sid)) {
172
- captured = sid;
173
- }
174
- } catch {}
175
- }
176
- }).on('end', () => {
177
- if (buffer.trim()) {
178
- try {
179
- const obj = JSON.parse(buffer.trim());
180
- const sid = (typeof obj.session_id === 'string' && obj.session_id) || (typeof obj.sessionID === 'string' && obj.sessionID);
181
- if (sid && /^ses_[A-Za-z0-9_-]+$/.test(sid)) {
182
- captured = sid;
183
- }
184
- } catch {}
185
- }
186
- if (captured) {
187
- process.stdout.write(captured);
188
- process.exit(0);
189
- }
190
- process.exit(1);
191
- });
192
- `.trim().replace(/\n/g," ").replace(/\s+/g," "),g=`
193
- let input = '';
194
- process.stdin.on('data', c => input += c).on('end', () => {
195
- const title = process.argv[1];
196
- let rows;
197
- try { rows = JSON.parse(input); } catch { process.exit(1); }
198
- if (!Array.isArray(rows)) process.exit(1);
199
- const isValidId = id => /^ses_[A-Za-z0-9_-]+$/.test(id);
200
- const timestamp = value => {
201
- if (typeof value === 'number' && Number.isFinite(value)) return value;
202
- if (typeof value === 'string') {
203
- const parsed = Date.parse(value);
204
- return Number.isNaN(parsed) ? Number.NEGATIVE_INFINITY : parsed;
205
- }
206
- return Number.NEGATIVE_INFINITY;
207
- };
208
- const matches = rows
209
- .filter(r => r && r.title === title && typeof r.id === 'string' && isValidId(r.id))
210
- .sort((a, b) => {
211
- const ta = timestamp(a.updated);
212
- const tb = timestamp(b.updated);
213
- if (ta === tb) return 0;
214
- return tb - ta;
215
- });
216
- if (matches.length === 0) process.exit(1);
217
- process.stdout.write(matches[0].id);
218
- });
219
- `.trim().replace(/\n/g," ").replace(/\s+/g," "),h=["opencode","run",...c,"--command","true"].join(" "),i=[...b?["--prompt",b]:[],...e],j=i.length>0?` ${i.join(" ")}`:"",k=(0,d.TQ)(`failed to discover OpenCode session ID for AO:${a.sessionId}`);return`SES_ID=$(${h} | node -e ${(0,d.TQ)(f)}); if [ -z "$SES_ID" ]; then SES_ID=$(opencode session list --format json | node -e ${(0,d.TQ)(g)} ${(0,d.TQ)(`AO:${a.sessionId}`)}); fi; [ -n "$SES_ID" ] && exec opencode --session "$SES_ID"${j}; echo ${k} >&2; exit 1`}return b&&c.push("--prompt",b),c.push(...e),["opencode",...c].join(" ")},getEnvironment(a){let b={};return b.AO_SESSION_ID=a.sessionId,a.issueId&&(b.AO_ISSUE_ID=a.issueId),b.PATH=(0,d.Te)(process.env.PATH),b.GH_PATH=d.C3,b},detectActivity(a){if(!a.trim())return"idle";let b=a.trim().split("\n"),c=b[b.length-1]?.trim()??"";if(/^[>$#]\s*$/.test(c))return"idle";let d=b.slice(-5).join("\n");return/\(Y\)es.*\(N\)o/i.test(d)||/approval required/i.test(d)||/Do you want to proceed\?/i.test(d)||/Allow .+\?/i.test(d)?"waiting_input":"active"},async getActivityState(a,b){let c=b??d.PE,e=Math.min(d.V1,c),f=new Date;if(!a.runtimeHandle||!await this.isProcessRunning(a.runtimeHandle))return{state:"exited",timestamp:f};let g=null;if(a.workspacePath){g=await (0,d.Ah)(a.workspacePath);let b=(0,d.Bm)(g);if(b)return b}let h=await C(a);if(h){let a=B(h.updated);if(a){let b=Math.max(0,Date.now()-a.getTime());return b<=e?{state:"active",timestamp:a}:b<=c?{state:"ready",timestamp:a}:{state:"idle",timestamp:a}}}let i=(0,d.Vo)(g,e,c);return i||null},async recordActivity(a,b){a.workspacePath&&await (0,d.Jy)(a.workspacePath,b,a=>this.detectActivity(a))},async isProcessRunning(a){try{if("tmux"===a.runtimeName&&a.id){let{stdout:b}=await A("tmux",["list-panes","-t",a.id,"-F","#{pane_tty}"],{timeout:3e4}),c=b.trim().split("\n").map(a=>a.trim()).filter(Boolean);if(0===c.length)return!1;let{stdout:d}=await A("ps",["-eo","pid,tty,args"],{timeout:3e4}),e=new Set(c.map(a=>a.replace(/^\/dev\//,""))),f=/(?:^|\/)opencode(?:\s|$)/;for(let a of d.split("\n")){let b=a.trimStart().split(/\s+/);if(b.length<3||!e.has(b[1]??""))continue;let c=b.slice(2).join(" ");if(f.test(c))return!0}return!1}let b=a.data.pid,c="number"==typeof b?b:Number(b);if(Number.isFinite(c)&&c>0)try{return process.kill(c,0),!0}catch(a){if(a instanceof Error&&"code"in a&&"EPERM"===a.code)return!0}return!1}catch{return!1}},async getSessionInfo(a){let b=await C(a);return b?{summary:b.title??null,summaryIsFallback:!0,agentSessionId:b.id}:null},async getRestoreCommand(a,b){let c=(0,d.Hr)(a.metadata?.opencodeSessionId)??(await C(a))?.id??null;if(!c)return null;let e=["opencode","--session",(0,d.TQ)(c)],f=b.agentConfig;return f?.model&&e.push("--model",(0,d.TQ)(f.model)),e.join(" ")},async setupWorkspaceHooks(a,b){await (0,d.J0)(a)},async postLaunchSetup(a){a.workspacePath&&await (0,d.J0)(a.workspacePath)}}},detect:function(){try{return(0,e.execFileSync)("opencode",["version"],{stdio:"ignore"}),!0}catch{return!1}}},E=(0,f.promisify)(e.execFile);async function F(a,...b){let{stdout:c}=await E("git",b,{cwd:a});return c.trimEnd()}async function G(a){try{return await F(a,"remote","get-url","origin"),!0}catch{return!1}}async function H(a,b){try{return await F(a,"rev-parse","--verify","--quiet",b),!0}catch{return!1}}async function I(a,b,c){if(c?.hasOrigin??await G(a)){if(c?.branch){let b=`origin/${c.branch}`;if(await H(a,b))return b}let d=`origin/${b}`;if(await H(a,d))return d}let d=`refs/heads/${b}`;if(await H(a,d))return d;throw Error(`Unable to resolve base ref for default branch "${b}"`)}let J=/^[a-zA-Z0-9_-]+$/;function K(a,b){if(!J.test(a))throw Error(`Invalid ${b} "${a}": must match ${J}`)}function L(a){return a.startsWith("~/")?(0,k.join)((0,j.homedir)(),a.slice(2)):a}let M={manifest:{name:"worktree",slot:"workspace",description:"Workspace plugin: git worktrees",version:"0.1.0"},create:function(a){let b=a?.worktreeDir?L(a.worktreeDir):(0,k.join)((0,j.homedir)(),".worktrees");return{name:"worktree",async create(a){K(a.projectId,"projectId"),K(a.sessionId,"sessionId");let c=L(a.project.path),d=(0,k.join)(b,a.projectId),e=(0,k.join)(d,a.sessionId);(0,i.mkdirSync)(d,{recursive:!0});let f=await G(c);if(f)try{await F(c,"fetch","origin","--quiet")}catch{}let g=await I(c,a.project.defaultBranch,{hasOrigin:f});try{await F(c,"worktree","add","-b",a.branch,e,g)}catch(d){let b=d instanceof Error?d.message:String(d);if(!b.includes("already exists"))throw Error(`Failed to create worktree for branch "${a.branch}": ${b}`,{cause:d});await F(c,"worktree","add",e,g);try{await F(e,"checkout",a.branch)}catch(d){try{await F(c,"worktree","remove","--force",e)}catch{}let b=d instanceof Error?d.message:String(d);throw Error(`Failed to checkout branch "${a.branch}" in worktree: ${b}`,{cause:d})}}return{path:e,branch:a.branch,sessionId:a.sessionId,projectId:a.projectId}},async destroy(a){try{let b=await F(a,"rev-parse","--path-format=absolute","--git-common-dir"),c=(0,k.resolve)(b,"..");await F(c,"worktree","remove","--force",a)}catch{(0,i.existsSync)(a)&&(0,i.rmSync)(a,{recursive:!0,force:!0})}},async list(a){K(a,"projectId");let c=(0,k.join)(b,a);if(!(0,i.existsSync)(c))return[];let d=(0,i.readdirSync)(c,{withFileTypes:!0}).filter(a=>a.isDirectory()).map(a=>(0,k.join)(c,a.name));if(0===d.length)return[];let e="";for(let a of d)try{e=await F(a,"worktree","list","--porcelain");break}catch{continue}if(!e)return[];let f=[];for(let b of e.split("\n\n")){let d=b.trim().split("\n"),e="",g="";for(let a of d)a.startsWith("worktree ")?e=a.slice(9):a.startsWith("branch ")&&(g=a.slice(7).replace("refs/heads/",""));if(e&&(e===c||e.startsWith(c+"/"))){let b=(0,k.basename)(e);f.push({path:e,branch:g||"detached",sessionId:b,projectId:a})}}return f},async exists(a){if(!(0,i.existsSync)(a))return!1;try{return await E("git",["rev-parse","--is-inside-work-tree"],{cwd:a,timeout:3e4}),!0}catch{return!1}},async restore(a,b){let c=L(a.project.path);try{await F(c,"worktree","prune")}catch{}let d=await G(c);if(d)try{await F(c,"fetch","origin","--quiet")}catch{}try{await F(c,"worktree","add",b,a.branch)}catch{let e=await I(c,a.project.defaultBranch,{branch:a.branch,hasOrigin:d});if(e.startsWith("origin/"))try{await F(c,"worktree","add","-b",a.branch,b,e)}catch{await F(c,"worktree","add","-b",a.branch,b,`refs/heads/${a.project.defaultBranch}`)}else await F(c,"worktree","add","-b",a.branch,b,e)}return{path:b,branch:a.branch,sessionId:a.sessionId,projectId:a.projectId}},async postCreate(a,b){let c=L(b.path);if(b.symlinks)for(let d of b.symlinks){if(d.startsWith("/")||d.includes(".."))throw Error(`Invalid symlink path "${d}": must be a relative path without ".." segments`);let b=(0,k.join)(c,d),e=(0,k.resolve)(a.path,d);if(!e.startsWith(a.path+"/")&&e!==a.path)throw Error(`Symlink target "${d}" resolves outside workspace: ${e}`);if((0,i.existsSync)(b)){try{let a=(0,i.lstatSync)(e);(a.isSymbolicLink()||a.isFile()||a.isDirectory())&&(0,i.rmSync)(e,{recursive:!0,force:!0})}catch{}(0,i.mkdirSync)((0,k.dirname)(e),{recursive:!0}),(0,i.symlinkSync)(b,e)}}if(b.postCreate)for(let c of b.postCreate)await E("sh",["-c",c],{cwd:a.path})}}}};class N{constructor(a){if(this.cache=new Map,this.accessOrder=[],this.maxSize=a,a<=0)throw Error("LRUCache maxSize must be greater than 0")}get(a){if(this.cache.has(a))return this.moveToEnd(a),this.cache.get(a)}set(a,b){if(this.cache.has(a)){this.moveToEnd(a),this.cache.set(a,b);return}if(this.cache.set(a,b),this.accessOrder.push(a),this.accessOrder.length>this.maxSize){let a=this.accessOrder.shift();void 0!==a&&this.cache.delete(a)}}delete(a){this.cache.delete(a);let b=this.accessOrder.indexOf(a);-1!==b&&this.accessOrder.splice(b,1)}clear(){this.cache.clear(),this.accessOrder=[]}get size(){return this.cache.size}has(a){return this.cache.has(a)}keys(){return[...this.accessOrder]}moveToEnd(a){let b=this.accessOrder.indexOf(a);-1!==b&&(this.accessOrder.splice(b,1),this.accessOrder.push(a))}toMap(){return new Map(this.cache)}}let O=(0,f.promisify)(e.execFile),P={prList:new N(100),commitStatus:new N(500)},Q=new N(200),R=new N(200);async function S(a){let b=[],c=!1;if(0===a.length)return{shouldRefresh:!1,details:["No PRs to check"]};let d=new Map;for(let b of a){let a=`${b.owner}/${b.repo}`;d.has(a)||d.set(a,[]);let c=d.get(a);c&&c.push(b)}let e=!1;for(let[a]of d){let[d,f]=a.split("/");await U(d,f)&&(e=!0,c=!0,b.push(`PR list changed for ${a} (Guard 1)`))}if(!e)for(let d of a){let a=`${d.owner}/${d.repo}#${d.number}`,e=Q.get(a);if(e&&null===e.headSha){c=!0,b.push(`First time seeing PR #${d.number} (Guard 2: no cached head SHA)`);continue}e&&e.headSha&&await V(d.owner,d.repo,e.headSha)&&(c=!0,b.push(`CI status changed for ${d.owner}/${d.repo}#${d.number} (Guard 2)`))}return{shouldRefresh:c,details:b}}async function T(){try{await O("gh",["--version"],{timeout:5e3})}catch{let a=Error("gh CLI not available or not authenticated. GraphQL batch enrichment requires gh CLI to be installed and configured.");throw a.cause="GH_CLI_UNAVAILABLE",a}}async function U(a,b){let c=`${a}/${b}`,d=P.prList.get(c),e=["api","--method","GET",`repos/${c}/pulls?state=open&sort=updated&direction=desc&per_page=1`,"-i"];d&&e.push("-H",`If-None-Match: ${d}`);try{let{stdout:c}=await O("gh",e,{timeout:1e4}),d=c.trim();if(d.includes("HTTP/1.1 304")||d.includes("HTTP/2 304"))return!1;let f=d.match(/etag:\s*(.+)/i);if(f){let c=f[1].trim();P.prList.set(`${a}/${b}`,c)}return!0}catch(b){let a=b instanceof Error?b.message:String(b);return console.warn(`[ETag Guard 1] PR list check failed for ${c}: ${a}`),!0}}async function V(a,b,c){let d=`${a}/${b}#${c}`,e=P.commitStatus.get(d),f=["api","--method","GET",`repos/${a}/${b}/commits/${c}/status`,"-i"];e&&f.push("-H",`If-None-Match: ${e}`);try{let{stdout:d}=await O("gh",f,{timeout:1e4}),e=d.trim();if(e.includes("HTTP/1.1 304")||e.includes("HTTP/2 304"))return!1;let g=e.match(/etag:\s*(.+)/i);if(g){let d=g[1].trim();P.commitStatus.set(`${a}/${b}#${c}`,d)}return!0}catch(b){let a=b instanceof Error?b.message:String(b);return console.warn(`[ETag Guard 2] Commit status check failed for ${d}: ${a}`),!0}}let W=`
220
- title
221
- state
222
- additions
223
- deletions
224
- isDraft
225
- mergeable
226
- mergeStateStatus
227
- reviewDecision
228
- headRefName
229
- headRefOid
230
- reviews(last: 5) {
231
- nodes {
232
- author { login }
233
- state
234
- submittedAt
235
- }
236
- }
237
- commits(last: 1) {
238
- nodes {
239
- commit {
240
- statusCheckRollup {
241
- state
242
- contexts(first: 20) {
243
- nodes {
244
- ... on CheckRun {
245
- name
246
- status
247
- conclusion
248
- detailsUrl
249
- }
250
- ... on StatusContext {
251
- context
252
- state
253
- targetUrl
254
- }
255
- }
256
- pageInfo {
257
- hasNextPage
258
- }
259
- }
260
- }
261
- }
262
- }
263
- }
264
- `;async function X(a){let{query:b,variables:c}=function(a){if(0===a.length)return{query:"",variables:{}};let b=[],c={};a.forEach((a,d)=>{let e=`pr${d}`;b.push(`
265
- ${e}: repository(owner: $${e}Owner, name: $${e}Name) {
266
- ... on Repository {
267
- pullRequest(number: $${e}Number) { ${W} }
268
- }
269
- }
270
- `),c[`${e}Owner`]=a.owner,c[`${e}Name`]=a.repo,c[`${e}Number`]=a.number});let d=Object.entries(c).map(([a,b])=>`$${a}: ${"number"==typeof b?"Int!":"String!"}`).join(", ");return{query:`query BatchPRs(${d}) {
271
- ${b.join("\n")}
272
- }`,variables:c}}(a);if(!b||0===a.length)return{};await T();let d=[];for(let[a,b]of Object.entries(c))"string"==typeof b?d.push("-f",`${a}=${b}`):d.push("-F",`${a}=${b}`);let e=["api","graphql",...d,"-f",`query=${b}`],f=3e4+Math.max(0,(a.length-10)*2e3),{stdout:g}=await O("gh",e,{maxBuffer:0xa00000,timeout:f}),h=JSON.parse(g.trim());if(h.errors&&h.errors.length>0){let a=h.errors.map(a=>a.message).join("; ");throw Error(`GraphQL query errors: ${a}`)}return h.data??{}}async function Y(a,b){let c=new Map;if(0===a.length)return c;let d=await S(a);if(!d.shouldRefresh){let e=[];for(let b of a){let a=`${b.owner}/${b.repo}#${b.number}`,d=R.get(a);d?c.set(a,d):e.push(b)}if(0===e.length)return b?.log("info",`[ETag Guard] Skipping GraphQL batch - all ${c.size} PRs cached. Reasons: ${d.details.join(", ")}`),c;b?.log("info",`[ETag Guard] Partial cache: ${c.size} cached, ${e.length} missing. Fetching missing PRs via GraphQL.`),a=e}let e=[];for(let b=0;b<a.length;b+=25)e.push(a.slice(b,b+25));for(let a=0;a<e.length;a++){let d,f=e[a],g=c.size,h=Date.now();try{let i=await X(f);d=Date.now()-h,f.forEach((a,b)=>{let d=`pr${b}`,e=`${a.owner}/${a.repo}#${a.number}`,f=i[d];if(f?.pullRequest){let a=function(a){if(!a||"object"!=typeof a||void 0===a.state&&void 0===a.title&&void 0===a.reviews&&void 0===a.commits)return null;let b=function(a){let b="string"==typeof a?a.toUpperCase():"";return"MERGED"===b?"merged":"CLOSED"===b?"closed":"open"}(a.state),c="string"==typeof a.title?a.title:void 0,d="number"==typeof a.additions?a.additions:0,e="number"==typeof a.deletions?a.deletions:0,f=!0===a.isDraft,g="string"==typeof a.headRefOid?a.headRefOid:"string"==typeof a.headSha?a.headSha:null,h=a.mergeable,i="string"==typeof a.mergeStateStatus?a.mergeStateStatus.toUpperCase():"",j="CONFLICTING"===h,k="BEHIND"===i,l=function(a){let b="string"==typeof a?a.toUpperCase():"";return"APPROVED"===b?"approved":"CHANGES_REQUESTED"===b?"changes_requested":"REVIEW_REQUIRED"===b?"pending":"none"}(a.reviewDecision),m=a.commits,n=m?.nodes?.[0]?.commit?.statusCheckRollup,o=n?function(a){if(!a||"object"!=typeof a)return"none";let b="string"==typeof a.state?a.state.toUpperCase():"";return"SUCCESS"===b?"passing":"FAILURE"===b||"ERROR"===b?"failing":"PENDING"===b||"EXPECTED"===b?"pending":"TIMED_OUT"===b||"CANCELLED"===b||"ACTION_REQUIRED"===b?"failing":"QUEUED"===b||"IN_PROGRESS"===b||"WAITING"===b?"pending":"none"}(n):"none",p=n?.contexts,q=p?.pageInfo,r=null!=q&&"object"==typeof q&&!0===q.hasNextPage,s=p&&!r?function(a){if(!a||"object"!=typeof a)return[];let b=a.nodes;if(!Array.isArray(b))return[];let c=[];for(let a of b)if(a&&"object"==typeof a){if("string"==typeof a.name&&"string"==typeof a.status){let b,d=a.status.toUpperCase(),e="string"==typeof a.conclusion?a.conclusion.toUpperCase():null;b="COMPLETED"===d?"SUCCESS"===e?"passed":"SKIPPED"===e||"NEUTRAL"===e||"STALE"===e||"NOT_REQUIRED"===e||"NONE"===e?"skipped":"FAILURE"===e||"TIMED_OUT"===e||"CANCELLED"===e||"ACTION_REQUIRED"===e||"ERROR"===e?"failed":"skipped":"IN_PROGRESS"===d?"running":"pending",c.push({name:a.name,status:b,conclusion:e??void 0,url:"string"==typeof a.detailsUrl?a.detailsUrl:void 0});continue}if("string"==typeof a.context&&"string"==typeof a.state){let b,d=a.state.toUpperCase();b="SUCCESS"===d?"passed":"FAILURE"===d||"ERROR"===d?"failed":"pending",c.push({name:a.context,status:b,conclusion:d,url:"string"==typeof a.targetUrl?a.targetUrl:void 0})}}return c}(p):void 0,t=[];"failing"===o&&t.push("CI is failing"),"changes_requested"===l&&t.push("Changes requested in review"),"pending"===l&&t.push("Review required"),j&&t.push("Merge conflicts"),k&&t.push("Branch is behind base branch"),f&&t.push("PR is still a draft");let u="open"===b&&("passing"===o||"none"===o)&&("approved"===l||"none"===l)&&!j&&!k&&!f;return{data:{state:b,ciStatus:o,reviewDecision:l,mergeable:u,title:c,additions:d,deletions:e,isDraft:f,hasConflicts:j,isBehind:k,blockers:t,...void 0!==s?{ciChecks:s}:{}},headSha:g}}(f.pullRequest);if(a){let{data:b,headSha:d}=a;c.set(e,b),Q.set(e,{headSha:d,ciStatus:b.ciStatus}),R.set(e,b)}}});let j=c.size;if(j>g){let c={batchIndex:a,totalBatches:e.length,prCount:j-g,durationMs:d};b?.recordSuccess(c),b?.log("info",`[GraphQL Batch Success] Batch ${a+1}/${e.length} succeeded: added ${j-g} PRs to cache (${d}ms)`)}}catch(g){d=Date.now()-h;let c=g instanceof Error?g.message:String(g);b?.recordFailure({batchIndex:a,totalBatches:e.length,prCount:f.length,error:c,durationMs:d}),console.error(`[GraphQL Batch Warning] Batch enrichment partially failed: ${c}`)}}return c}function Z(a,b){let c=b.toLowerCase();for(let[b,d]of Object.entries(a))if(b.toLowerCase()===c){if(Array.isArray(d))return d[0];return d}}function $(a){if("string"!=typeof a)return;let b=new Date(a);return Number.isNaN(b.getTime())?void 0:b}function _(a){return"string"!=typeof a||0===a.length?void 0:a.startsWith("refs/heads/")?a.slice(11):a.startsWith("refs/")?void 0:a}let aa=(0,f.promisify)(e.execFile),ab=new Set(["cursor[bot]","github-actions[bot]","codecov[bot]","sonarcloud[bot]","dependabot[bot]","renovate[bot]","codeclimate[bot]","deepsource-autofix[bot]","snyk-bot","lgtm-com[bot]"]);async function ac(a,b,c){try{let{stdout:d}=await aa(a,b,{...c?{cwd:c}:{},maxBuffer:0xa00000,timeout:3e4});return d.trim()}catch(c){throw Error(`${a} ${b.slice(0,3).join(" ")} failed: ${c.message}`,{cause:c})}}async function ad(a){return ac("gh",a)}async function ae(a,b){return ac("gh",a,b)}async function af(a,b){return ac("git",a,b)}function ag(a){let b=a.split("/");if(2!==b.length||!b[0]||!b[1])throw Error(`Invalid repo format "${a}", expected "owner/repo"`);return[b[0],b[1]]}function ah(a,b){let[c,d]=ag(b);return{number:a.number,url:a.url,title:a.title,owner:c,repo:d,branch:a.headRefName,baseBranch:a.baseRefName,isDraft:a.isDraft}}function ai(a){let b=(a??"").toUpperCase();return"IN_PROGRESS"===b?"running":"PENDING"===b||"QUEUED"===b||"REQUESTED"===b||"WAITING"===b||"EXPECTED"===b?"pending":"SUCCESS"===b?"passed":"FAILURE"===b||"TIMED_OUT"===b||"CANCELLED"===b||"ACTION_REQUIRED"===b||"ERROR"===b?"failed":("SKIPPED"===b||"NEUTRAL"===b||"STALE"===b||"NOT_REQUIRED"===b,"skipped")}async function aj(a){let b=JSON.parse(await ad(["pr","view",String(a.number),"--repo",al(a),"--json","statusCheckRollup"]));return(Array.isArray(b.statusCheckRollup)?b.statusCheckRollup:[]).map(a=>{if(!a||"object"!=typeof a)return null;let b="string"==typeof a.name&&a.name||"string"==typeof a.context&&a.context;if(!b)return null;let c="string"==typeof a.conclusion?a.conclusion:"string"==typeof a.state?a.state:"string"==typeof a.status?a.status:void 0,d="string"==typeof a.link&&a.link||"string"==typeof a.detailsUrl&&a.detailsUrl||"string"==typeof a.targetUrl&&a.targetUrl||void 0,e="string"==typeof a.startedAt?a.startedAt:"string"==typeof a.createdAt?a.createdAt:void 0,f="string"==typeof a.completedAt?a.completedAt:void 0,g={name:b,status:ai(c),conclusion:"string"==typeof c?c.toUpperCase():void 0,startedAt:e?new Date(e):void 0,completedAt:f?new Date(f):void 0};return d&&(g.url=d),g}).filter(a=>null!==a)}function ak(a){let b=a.scm?.webhook;return{enabled:b?.enabled!==!1,path:b?.path??"/api/webhooks/github",secretEnvVar:b?.secretEnvVar,signatureHeader:b?.signatureHeader??"x-hub-signature-256",eventHeader:b?.eventHeader??"x-github-event",deliveryHeader:b?.deliveryHeader??"x-github-delivery",maxBodyBytes:b?.maxBodyBytes}}function al(a){return`${a.owner}/${a.repo}`}function am(a){if(!a)return new Date(0);let b=new Date(a);return isNaN(b.getTime())?new Date(0):b}let an={manifest:{name:"github",slot:"scm",description:"SCM plugin: GitHub PRs, CI checks, reviews, merge readiness",version:"0.1.0"},create:function(){return{name:"github",async verifyWebhook(a,b){let c=ak(b);if(!c.enabled)return{ok:!1,reason:"Webhook is disabled for this project"};if("POST"!==a.method.toUpperCase())return{ok:!1,reason:"Webhook requests must use POST"};if(void 0!==c.maxBodyBytes&&Buffer.byteLength(a.body,"utf8")>c.maxBodyBytes)return{ok:!1,reason:"Webhook payload exceeds configured maxBodyBytes"};let d=Z(a.headers,c.eventHeader);if(!d)return{ok:!1,reason:`Missing ${c.eventHeader} header`};let e=Z(a.headers,c.deliveryHeader),f=c.secretEnvVar;if(!f)return{ok:!0,deliveryId:e,eventType:d};let g=process.env[f];if(!g)return{ok:!1,reason:`Webhook secret env var ${f} is not configured`};let i=Z(a.headers,c.signatureHeader);return i?!function(a,b,c){if(!c.startsWith("sha256="))return!1;let d=(0,h.createHmac)("sha256",b).update(a).digest("hex"),e=c.slice(7),f=Buffer.from(d,"hex"),g=Buffer.from(e,"hex");return f.length===g.length&&(0,h.timingSafeEqual)(f,g)}(a.rawBody??a.body,g,i)?{ok:!1,reason:"Webhook signature verification failed",deliveryId:e,eventType:d}:{ok:!0,deliveryId:e,eventType:d}:{ok:!1,reason:`Missing ${c.signatureHeader} header`}},async parseWebhook(a,b){let c=ak(b),d=function(a){let b=JSON.parse(a);if(!b||"object"!=typeof b||Array.isArray(b))throw Error("Webhook payload must be a JSON object");return b}(a.body);return function(a,b,c){let d=Z(a.headers,c.eventHeader);if(!d)return null;let e=Z(a.headers,c.deliveryHeader),f=function(a){let b=a.repository;if(!b||"object"!=typeof b)return;let c=b.owner,d=c&&"object"==typeof c?c.login:void 0,e="string"==typeof d?d:void 0,f="string"==typeof b.name?b.name:void 0;if(e&&f)return{owner:e,name:f}}(b),g="string"==typeof b.action?b.action:d;if("pull_request"===d){let a=b.pull_request;if(!a||"object"!=typeof a)return null;let c=a.head;return{provider:"github",kind:"pull_request",action:g,rawEventType:d,deliveryId:e,repository:f,prNumber:"number"==typeof b.number?b.number:"number"==typeof a.number?a.number:void 0,branch:"string"==typeof c?.ref?c.ref:void 0,sha:"string"==typeof c?.sha?c.sha:void 0,timestamp:$(a.updated_at),data:b}}if("pull_request_review"===d||"pull_request_review_comment"===d){let a=b.pull_request;if(!a||"object"!=typeof a)return null;let c=a.head;return{provider:"github",kind:"pull_request_review"===d?"review":"comment",action:g,rawEventType:d,deliveryId:e,repository:f,prNumber:"number"==typeof b.number?b.number:"number"==typeof a.number?a.number:void 0,branch:"string"==typeof c?.ref?c.ref:void 0,sha:"string"==typeof c?.sha?c.sha:void 0,timestamp:"pull_request_review"===d?$(b.review?.submitted_at):$(b.comment?.updated_at??b.comment?.created_at),data:b}}if("issue_comment"===d){let a=b.issue;return a&&"object"==typeof a&&"pull_request"in a?{provider:"github",kind:"comment",action:g,rawEventType:d,deliveryId:e,repository:f,prNumber:"number"==typeof a.number?a.number:void 0,timestamp:$(b.comment?.updated_at??b.comment?.created_at),data:b}:null}if("check_run"===d||"check_suite"===d){let a=b[d],c=(Array.isArray(a?.pull_requests)?a?.pull_requests:[])[0];return{provider:"github",kind:"ci",action:g,rawEventType:d,deliveryId:e,repository:f,prNumber:"number"==typeof c?.number?c.number:void 0,branch:"string"==typeof a?.head_branch?a.head_branch:"string"==typeof a?.check_suite?.head_branch?(a?.check_suite).head_branch:void 0,sha:"string"==typeof a?.head_sha?a.head_sha:void 0,timestamp:$(a?.updated_at),data:b}}if("status"===d){let a=Array.isArray(b.branches)?b.branches:[];return{provider:"github",kind:"ci",action:"string"==typeof b.state?b.state:g,rawEventType:d,deliveryId:e,repository:f,branch:_(a[0]?.name??b.ref),sha:"string"==typeof b.sha?b.sha:void 0,timestamp:$(b.updated_at),data:b}}if("push"===d){let a=b.head_commit&&"object"==typeof b.head_commit?b.head_commit:void 0;return{provider:"github",kind:"push",action:g,rawEventType:d,deliveryId:e,repository:f,branch:_(b.ref),sha:"string"==typeof b.after?b.after:void 0,timestamp:$(a?.timestamp??b.updated_at),data:b}}return{provider:"github",kind:"unknown",action:g,rawEventType:d,deliveryId:e,repository:f,timestamp:$(b.updated_at),data:b}}(a,d,c)},async detectPR(a,b){if(!a.branch)return null;ag(b.repo);try{let c=await ad(["pr","list","--repo",b.repo,"--head",a.branch,"--json","number,url,title,headRefName,baseRefName,isDraft","--limit","1"]),d=JSON.parse(c);if(0===d.length)return null;return ah(d[0],b.repo)}catch{return null}},resolvePR:async(a,b)=>ah(JSON.parse(await ad(["pr","view",a,"--repo",b.repo,"--json","number,url,title,headRefName,baseRefName,isDraft"])),b.repo),async assignPRToCurrentUser(a){await ad(["pr","edit",String(a.number),"--repo",al(a),"--add-assignee","@me"])},async checkoutPR(a,b){if(await af(["branch","--show-current"],b)===a.branch)return!1;if(await af(["status","--porcelain"],b))throw Error(`Workspace has uncommitted changes; cannot switch to PR branch "${a.branch}" safely`);return await ae(["pr","checkout",String(a.number),"--repo",al(a)],b),!0},async getPRState(a){let b=JSON.parse(await ad(["pr","view",String(a.number),"--repo",al(a),"--json","state"])).state.toUpperCase();return"MERGED"===b?"merged":"CLOSED"===b?"closed":"open"},async getPRSummary(a){let b=JSON.parse(await ad(["pr","view",String(a.number),"--repo",al(a),"--json","state,title,additions,deletions"])),c=b.state.toUpperCase();return{state:"MERGED"===c?"merged":"CLOSED"===c?"closed":"open",title:b.title??"",additions:b.additions??0,deletions:b.deletions??0}},async mergePR(a,b="squash"){await ad(["pr","merge",String(a.number),"--repo",al(a),"rebase"===b?"--rebase":"merge"===b?"--merge":"--squash","--delete-branch"])},async closePR(a){await ad(["pr","close",String(a.number),"--repo",al(a)])},async getCIChecks(a){try{let b=await ad(["pr","checks",String(a.number),"--repo",al(a),"--json","name,state,link,startedAt,completedAt"]);return JSON.parse(b).map(a=>{let b=a.state?.toUpperCase();return{name:a.name,status:ai(b),url:a.link||void 0,conclusion:b||void 0,startedAt:a.startedAt?new Date(a.startedAt):void 0,completedAt:a.completedAt?new Date(a.completedAt):void 0}})}catch(b){if(b instanceof Error&&/pr checks/i.test(b.message)&&/unknown json field/i.test(b.message))return aj(a);throw Error("Failed to fetch CI checks",{cause:b})}},async getCISummary(a){let b;try{b=await this.getCIChecks(a)}catch{try{let b=await this.getPRState(a);if("merged"===b||"closed"===b)return"none"}catch{}return"failing"}return 0===b.length?"none":b.some(a=>"failed"===a.status)?"failing":b.some(a=>"pending"===a.status||"running"===a.status)?"pending":b.some(a=>"passed"===a.status)?"passing":"none"},getReviews:async a=>JSON.parse(await ad(["pr","view",String(a.number),"--repo",al(a),"--json","reviews"])).reviews.map(a=>{let b,c=a.state?.toUpperCase();return b="APPROVED"===c?"approved":"CHANGES_REQUESTED"===c?"changes_requested":"DISMISSED"===c?"dismissed":"PENDING"===c?"pending":"commented",{author:a.author?.login??"unknown",state:b,body:a.body||void 0,submittedAt:am(a.submittedAt)}}),async getReviewDecision(a){let b=(JSON.parse(await ad(["pr","view",String(a.number),"--repo",al(a),"--json","reviewDecision"])).reviewDecision??"").toUpperCase();return"APPROVED"===b?"approved":"CHANGES_REQUESTED"===b?"changes_requested":"REVIEW_REQUIRED"===b?"pending":"none"},async getPendingComments(a){try{let b=await ad(["api","graphql","-f",`owner=${a.owner}`,"-f",`name=${a.repo}`,"-F",`number=${a.number}`,"-f",`query=query($owner: String!, $name: String!, $number: Int!) {
273
- repository(owner: $owner, name: $name) {
274
- pullRequest(number: $number) {
275
- reviewThreads(first: 100) {
276
- nodes {
277
- isResolved
278
- comments(first: 1) {
279
- nodes {
280
- id
281
- author { login }
282
- body
283
- path
284
- line
285
- url
286
- createdAt
287
- }
288
- }
289
- }
290
- }
291
- }
292
- }
293
- }`]);return JSON.parse(b).data.repository.pullRequest.reviewThreads.nodes.filter(a=>{if(a.isResolved)return!1;let b=a.comments.nodes[0];if(!b)return!1;let c=b.author?.login??"";return!ab.has(c)}).map(a=>{let b=a.comments.nodes[0];return{id:b.id,author:b.author?.login??"unknown",body:b.body,path:b.path||void 0,line:b.line??void 0,isResolved:a.isResolved,createdAt:am(b.createdAt),url:b.url}})}catch(a){throw Error("Failed to fetch pending comments",{cause:a})}},async getAutomatedComments(a){try{let b=[];for(let c=1;;c++){let d=await ad(["api","--method","GET",`repos/${al(a)}/pulls/${a.number}/comments?per_page=100&page=${c}`]),e=JSON.parse(d);if(0===e.length||(b.push(...e),e.length<100))break}return b.filter(a=>ab.has(a.user?.login??"")).map(a=>{let b="info",c=a.body.toLowerCase();return c.includes("error")||c.includes("bug")||c.includes("critical")||c.includes("potential issue")?b="error":(c.includes("warning")||c.includes("suggest")||c.includes("consider"))&&(b="warning"),{id:String(a.id),botName:a.user?.login??"unknown",body:a.body,path:a.path||void 0,line:a.line??a.original_line??void 0,severity:b,createdAt:am(a.created_at),url:a.html_url}})}catch(a){throw Error("Failed to fetch automated comments",{cause:a})}},async getMergeability(a){let b=[];if("merged"===await this.getPRState(a))return{mergeable:!0,ciPassing:!0,approved:!0,noConflicts:!0,blockers:[]};let c=JSON.parse(await ad(["pr","view",String(a.number),"--repo",al(a),"--json","mergeable,reviewDecision,mergeStateStatus,isDraft"])),e=await this.getCISummary(a),f=e===d.U1.PASSING||e===d.U1.NONE;f||b.push(`CI is ${e}`);let g=(c.reviewDecision??"").toUpperCase();"CHANGES_REQUESTED"===g?b.push("Changes requested in review"):"REVIEW_REQUIRED"===g&&b.push("Review required");let h=(c.mergeable??"").toUpperCase(),i=(c.mergeStateStatus??"").toUpperCase();return"CONFLICTING"===h?b.push("Merge conflicts"):("UNKNOWN"===h||""===h)&&b.push("Merge status unknown (GitHub is computing)"),"BEHIND"===i?b.push("Branch is behind base branch"):"BLOCKED"===i?b.push("Merge is blocked by branch protection"):"UNSTABLE"===i&&b.push("Required checks are failing"),c.isDraft&&b.push("PR is still a draft"),{mergeable:0===b.length,ciPassing:f,approved:"APPROVED"===g,noConflicts:"MERGEABLE"===h,blockers:b}},enrichSessionsPRBatch:async(a,b)=>Y(a,b)}}},ao=(0,f.promisify)(e.execFile);async function ap(a){try{let{stdout:b}=await ao("gh",a,{maxBuffer:0xa00000,timeout:3e4});return b.trim()}catch(b){throw Error(`gh ${a.slice(0,3).join(" ")} failed: ${b.message}`,{cause:b})}}function aq(a,b){let c=function a(b){if(!(b instanceof Error))return"";let c=[b.message];return"string"==typeof b.stderr&&c.push(b.stderr),"string"==typeof b.stdout&&c.push(b.stdout),b.cause instanceof Error&&c.push(a(b.cause)),c.join("\n").toLowerCase()}(a);return!!c&&(c.includes("unknown json field")||c.includes("unknown field")||c.includes("invalid field"))&&c.includes(b.toLowerCase())}async function ar(a,b){try{return await ap(["issue","view",a,"--repo",b.repo,"--json","number,title,body,url,state,stateReason,labels,assignees"])}catch(c){if(!aq(c,"stateReason"))throw c;return ap(["issue","view",a,"--repo",b.repo,"--json","number,title,body,url,state,labels,assignees"])}}async function as(a){let b=[...a,"--json","number,title,body,url,state,stateReason,labels,assignees"];try{return await ap(b)}catch(b){if(!aq(b,"stateReason"))throw b;return ap([...a,"--json","number,title,body,url,state,labels,assignees"])}}function at(a,b){return"CLOSED"===a.toUpperCase()?b?.toUpperCase()==="NOT_PLANNED"?"cancelled":"closed":"open"}let au={manifest:{name:"github",slot:"tracker",description:"Tracker plugin: GitHub Issues",version:"0.1.0"},create:function(){return{name:"github",async getIssue(a,b){let c=JSON.parse(await ar(a,b));return{id:String(c.number),title:c.title,description:c.body??"",url:c.url,state:at(c.state,c.stateReason),labels:c.labels.map(a=>a.name),assignee:c.assignees[0]?.login}},isCompleted:async(a,b)=>"CLOSED"===JSON.parse(await ap(["issue","view",a,"--repo",b.repo,"--json","state"])).state.toUpperCase(),issueUrl(a,b){let c=a.replace(/^#/,"");return`https://github.com/${b.repo}/issues/${c}`},issueLabel(a,b){let c=a.match(/\/issues\/(\d+)/);if(c)return`#${c[1]}`;let d=a.split("/"),e=d[d.length-1];return e?`#${e}`:a},branchName(a,b){let c=a.replace(/^#/,"");return`feat/issue-${c}`},async generatePrompt(a,b){let c=await this.getIssue(a,b),d=[`You are working on GitHub issue #${c.id}: ${c.title}`,`Issue URL: ${c.url}`,""];return c.labels.length>0&&d.push(`Labels: ${c.labels.join(", ")}`),c.description&&d.push("## Description","",c.description),d.push("","Please implement the changes described in this issue. When done, commit and push your changes."),d.join("\n")},async listIssues(a,b){let c=["issue","list","--repo",b.repo,"--limit",String(a.limit??30)];return"closed"===a.state?c.push("--state","closed"):"all"===a.state?c.push("--state","all"):c.push("--state","open"),a.labels&&a.labels.length>0&&c.push("--label",a.labels.join(",")),a.assignee&&c.push("--assignee",a.assignee),JSON.parse(await as(c)).map(a=>({id:String(a.number),title:a.title,description:a.body??"",url:a.url,state:at(a.state,a.stateReason),labels:a.labels.map(a=>a.name),assignee:a.assignees[0]?.login}))},async updateIssue(a,b,c){"closed"===b.state?await ap(["issue","close",a,"--repo",c.repo]):"open"===b.state&&await ap(["issue","reopen",a,"--repo",c.repo]),b.removeLabels&&b.removeLabels.length>0&&await ap(["issue","edit",a,"--repo",c.repo,"--remove-label",b.removeLabels.join(",")]),b.labels&&b.labels.length>0&&await ap(["issue","edit",a,"--repo",c.repo,"--add-label",b.labels.join(",")]),b.assignee&&await ap(["issue","edit",a,"--repo",c.repo,"--add-assignee",b.assignee]),b.comment&&await ap(["issue","comment",a,"--repo",c.repo,"--body",b.comment])},async createIssue(a,b){let c=["issue","create","--repo",b.repo,"--title",a.title,"--body",a.description??""];a.labels&&a.labels.length>0&&c.push("--label",a.labels.join(",")),a.assignee&&c.push("--assignee",a.assignee);let d=await ap(c),e=d.match(/\/issues\/(\d+)/);if(!e)throw Error(`Failed to parse issue URL from gh output: ${d}`);let f=e[1];return this.getIssue(f,b)}}}};var av=c(44708);function aw(a){switch(a){case"completed":return"closed";case"canceled":return"cancelled";case"started":return"in_progress";default:return"open"}}let ax=`
294
- id
295
- identifier
296
- title
297
- description
298
- url
299
- priority
300
- state { name type }
301
- labels { nodes { name } }
302
- assignee { name displayName }
303
- team { key }
304
- `;function ay(a){return{name:"linear",async getIssue(b,c){let d=(await a(`query($id: String!) {
305
- issue(id: $id) {
306
- ${ax}
307
- }
308
- }`,{id:b})).issue;return{id:d.identifier,title:d.title,description:d.description??"",url:d.url,state:aw(d.state.type),labels:d.labels.nodes.map(a=>a.name),assignee:d.assignee?.displayName??d.assignee?.name,priority:d.priority}},async isCompleted(b,c){let d=(await a(`query($id: String!) {
309
- issue(id: $id) {
310
- state { type }
311
- }
312
- }`,{id:b})).issue.state.type;return"completed"===d||"canceled"===d},issueUrl(a,b){let c=b.tracker?.workspaceSlug;return c?`https://linear.app/${c}/issue/${a}`:`https://linear.app/issue/${a}`},issueLabel(a,b){let c=a.match(/\/issue\/([A-Z]+-\d+)/);if(c)return c[1];let d=a.split("/");return d[d.length-1]||a},branchName:(a,b)=>`feat/${a}`,async generatePrompt(a,b){let c=await this.getIssue(a,b),d=[`You are working on Linear ticket ${c.id}: ${c.title}`,`Issue URL: ${c.url}`,""];return c.labels.length>0&&d.push(`Labels: ${c.labels.join(", ")}`),void 0!==c.priority&&d.push(`Priority: ${{0:"No priority",1:"Urgent",2:"High",3:"Normal",4:"Low"}[c.priority]??String(c.priority)}`),c.description&&d.push("## Description","",c.description),d.push("","Please implement the changes described in this ticket. When done, commit and push your changes."),d.join("\n")},async listIssues(b,c){let d={},e={};"closed"===b.state?d.state={type:{in:["completed","canceled"]}}:"all"!==b.state&&(d.state={type:{nin:["completed","canceled"]}}),b.assignee&&(d.assignee={displayName:{eq:b.assignee}}),b.labels&&b.labels.length>0&&(d.labels={name:{in:b.labels}});let f=c.tracker?.teamId;return f&&(d.team={id:{eq:f}}),e.filter=Object.keys(d).length>0?d:void 0,e.first=b.limit??30,(await a(`query($filter: IssueFilter, $first: Int!) {
313
- issues(filter: $filter, first: $first) {
314
- nodes {
315
- ${ax}
316
- }
317
- }
318
- }`,e)).issues.nodes.map(a=>({id:a.identifier,title:a.title,description:a.description??"",url:a.url,state:aw(a.state.type),labels:a.labels.nodes.map(a=>a.name),assignee:a.assignee?.displayName??a.assignee?.name,priority:a.priority}))},async updateIssue(b,c,d){let e=await a(`query($id: String!) {
319
- issue(id: $id) {
320
- id
321
- team { id }
322
- }
323
- }`,{id:b}),f=e.issue.id,g=e.issue.team.id;if(c.state){let b=await a(`query($teamId: ID!) {
324
- workflowStates(filter: { team: { id: { eq: $teamId } } }) {
325
- nodes { id name type }
326
- }
327
- }`,{teamId:g}),d="closed"===c.state?"completed":"open"===c.state?"unstarted":"started",e=b.workflowStates.nodes.find(a=>a.type===d);if(!e)throw Error(`No workflow state of type "${d}" found for team ${g}`);await a(`mutation($id: String!, $stateId: String!) {
328
- issueUpdate(id: $id, input: { stateId: $stateId }) {
329
- success
330
- }
331
- }`,{id:f,stateId:e.id})}if(c.assignee){let b=(await a(`query($filter: UserFilter) {
332
- users(filter: $filter) {
333
- nodes { id displayName name }
334
- }
335
- }`,{filter:{displayName:{eq:c.assignee}}})).users.nodes[0];b&&await a(`mutation($id: String!, $assigneeId: String!) {
336
- issueUpdate(id: $id, input: { assigneeId: $assigneeId }) {
337
- success
338
- }
339
- }`,{id:f,assigneeId:b.id})}if(c.labels&&c.labels.length>0){let b=new Set((await a(`query($id: String!) {
340
- issue(id: $id) {
341
- labels { nodes { id } }
342
- }
343
- }`,{id:f})).issue.labels.nodes.map(a=>a.id)),d=new Map((await a(`query($teamId: ID) {
344
- issueLabels(filter: { team: { id: { eq: $teamId } } }) {
345
- nodes { id name }
346
- }
347
- }`,{teamId:g})).issueLabels.nodes.map(a=>[a.name,a.id]));for(let a of c.labels){let c=d.get(a);c&&b.add(c)}await a(`mutation($id: String!, $labelIds: [String!]!) {
348
- issueUpdate(id: $id, input: { labelIds: $labelIds }) {
349
- success
350
- }
351
- }`,{id:f,labelIds:[...b]})}c.comment&&await a(`mutation($issueId: String!, $body: String!) {
352
- commentCreate(input: { issueId: $issueId, body: $body }) {
353
- success
354
- }
355
- }`,{issueId:f,body:c.comment})},async createIssue(b,c){let d=c.tracker?.teamId;if(!d)throw Error("Linear tracker requires 'teamId' in project tracker config");let e={title:b.title,description:b.description??"",teamId:d};void 0!==b.priority&&(e.priority=b.priority);let f=(await a(`mutation($title: String!, $description: String!, $teamId: String!, $priority: Int) {
356
- issueCreate(input: {
357
- title: $title,
358
- description: $description,
359
- teamId: $teamId,
360
- priority: $priority
361
- }) {
362
- success
363
- issue {
364
- ${ax}
365
- }
366
- }
367
- }`,e)).issueCreate.issue,g={id:f.identifier,title:f.title,description:f.description??"",url:f.url,state:aw(f.state.type),labels:f.labels.nodes.map(a=>a.name),assignee:f.assignee?.displayName??f.assignee?.name,priority:f.priority};if(b.assignee)try{let c=(await a(`query($filter: UserFilter) {
368
- users(filter: $filter) {
369
- nodes { id displayName name }
370
- }
371
- }`,{filter:{displayName:{eq:b.assignee}}})).users.nodes[0];c&&(await a(`mutation($id: String!, $assigneeId: String!) {
372
- issueUpdate(id: $id, input: { assigneeId: $assigneeId }) {
373
- success
374
- }
375
- }`,{id:f.id,assigneeId:c.id}),g.assignee=b.assignee)}catch{}if(b.labels&&b.labels.length>0)try{let c=await a(`query($teamId: ID) {
376
- issueLabels(filter: { team: { id: { eq: $teamId } } }) {
377
- nodes { id name }
378
- }
379
- }`,{teamId:d}),e=new Map(c.issueLabels.nodes.map(a=>[a.name,a.id])),h=[],i=[];for(let a of b.labels){let b=e.get(a);b&&(i.push(b),h.push(a))}i.length>0&&(await a(`mutation($id: String!, $labelIds: [String!]!) {
380
- issueUpdate(id: $id, input: { labelIds: $labelIds }) {
381
- success
382
- }
383
- }`,{id:f.id,labelIds:i}),g.labels=h)}catch{}return g}}}let az={manifest:{name:"linear",slot:"tracker",description:"Tracker plugin: Linear issue tracker",version:"0.1.0"},create:function(){let a=process.env.COMPOSIO_API_KEY;if(a){let b,c=process.env.COMPOSIO_ENTITY_ID??"default";return ay(async(d,e)=>{let f,g=(await (!b&&(b=(async()=>{try{let{Composio:b}=await Promise.resolve().then(function(){var a=Error("Cannot find module '@composio/core'");throw a.code="MODULE_NOT_FOUND",a});return new b({apiKey:a}).tools}catch(b){let a=b instanceof Error?b.message:String(b);if(a.includes("Cannot find module")||a.includes("Cannot find package")||a.includes("ERR_MODULE_NOT_FOUND"))throw Error("Composio SDK (@composio/core) is not installed. Install it with: pnpm add @composio/core",{cause:b});throw b}})()),b)).execute("LINEAR_RUN_QUERY_OR_MUTATION",{entityId:c,arguments:{query_or_mutation:d,variables:e?JSON.stringify(e):"{}"}}),h=new Promise((a,b)=>{f=setTimeout(()=>{b(Error("Composio Linear API request timed out after 30s"))},3e4)});g.catch(()=>{}),h.catch(()=>{});try{let a=await Promise.race([g,h]);if(!a.successful)throw Error(`Composio Linear API error: ${a.error??"unknown error"}`);if(!a.data)throw Error("Composio Linear API returned no data");return a.data}finally{clearTimeout(f)}})}return ay((a,b)=>{let c=function(){let a=process.env.LINEAR_API_KEY;if(!a)throw Error("LINEAR_API_KEY environment variable is required for the Linear tracker plugin");return a}(),d=JSON.stringify({query:a,variables:b});return new Promise((a,b)=>{let e=new URL("https://api.linear.app/graphql"),f=!1,g=a=>{f||(f=!0,a())},h=(0,av.request)({hostname:e.hostname,path:e.pathname,method:"POST",headers:{"Content-Type":"application/json",Authorization:c,"Content-Length":Buffer.byteLength(d)}},c=>{let d=[];c.on("error",a=>g(()=>b(a))),c.on("data",a=>d.push(a)),c.on("end",()=>{g(()=>{try{let e=Buffer.concat(d).toString("utf-8"),f=c.statusCode??0;if(f<200||f>=300)return void b(Error(`Linear API returned HTTP ${f}: ${e.slice(0,200)}`));let g=JSON.parse(e);if(g.errors&&g.errors.length>0)return void b(Error(`Linear API error: ${g.errors[0].message}`));if(!g.data)return void b(Error("Linear API returned no data"));a(g.data)}catch(a){b(a)}})})});h.setTimeout(3e4,()=>{g(()=>{h.destroy(),b(Error("Linear API request timed out after 30s"))})}),h.on("error",a=>g(()=>b(a))),h.write(d),h.end()})})}},aA=globalThis;function aB(){return aA._aoServices?Promise.resolve(aA._aoServices):(aA._aoServicesInit||(aA._aoServicesInit=aC().catch(a=>{throw aA._aoServicesInit=void 0,a})),aA._aoServicesInit)}async function aC(){let a=(0,d.Z9)(),b=(0,d.R)();b.register(o),b.register(z),b.register(D),b.register(M),b.register(an),b.register(au),b.register(az);let c=(0,d.Qu)({config:a,registry:b}),e=(0,d.C1)({config:a,registry:b,sessionManager:c});e.start(3e4);let f={config:a,registry:b,sessionManager:c,lifecycleManager:e};return aA._aoServices=f,f}let aD="agent:backlog",aE=globalThis;function aF(){aE._aoBacklogStarted||(aE._aoBacklogStarted=!0,aJ(),aE._aoBacklogTimer=setInterval(()=>void aJ(),6e4))}let aG=new Set;async function aH(a,b,c){for(let d of a.filter(a=>"merged"===a.status&&a.issueId&&!aG.has(`${a.projectId}:${a.issueId}`))){let a=`${d.projectId}:${d.issueId}`,e=b.projects[d.projectId];if(!e?.tracker?.plugin){aG.add(a);continue}let f=c.get("tracker",e.tracker.plugin);if(!f?.updateIssue){aG.add(a);continue}let g=d.issueId;if(!g){aG.add(a);continue}try{await f.updateIssue(g,{labels:["merged-unverified"],removeLabels:["agent:backlog","agent:in-progress"],comment:"PR merged. Issue awaiting human verification on staging."},e)}catch(a){console.error(`[backlog] Failed to close issue ${d.issueId}:`,a)}aG.add(a)}}async function aI(a,b){for(let[,c]of Object.entries(a.projects)){let a;if(!c.tracker?.plugin)continue;let d=b.get("tracker",c.tracker.plugin);if(d?.listIssues&&d.updateIssue){try{a=await d.listIssues({state:"open",labels:["agent:done"],limit:20},c)}catch{continue}for(let b of a)try{await d.updateIssue(b.id,{labels:[aD],removeLabels:["agent:done"],comment:"Issue reopened — returning to agent backlog."},c),console.log(`[backlog] Relabeled reopened issue ${b.id} → ${aD}`)}catch(a){console.error(`[backlog] Failed to relabel reopened issue ${b.id}:`,a)}}}}async function aJ(){try{let{config:a,registry:b,sessionManager:c}=await aB(),e=await c.list();await aH(e,a,b),await aI(a,b);let f=Object.entries(a.projects).map(([a,b])=>b.sessionPrefix??a),g=e.filter(b=>!(0,d.tT)(b,a.projects[b.projectId]?.sessionPrefix??b.projectId,f)&&!d.CM.has(b.status)),h=new Set(g.map(a=>a.issueId?.toLowerCase()).filter(a=>!!a)),i=5-g.length;if(i<=0)return;for(let[e,f]of Object.entries(a.projects)){let a;if(i<=0)break;if(!f.tracker?.plugin)continue;let g=b.get("tracker",f.tracker.plugin);if(g?.listIssues){try{a=await g.listIssues({state:"open",labels:[aD],limit:10},f)}catch{continue}for(let b of a){if(i<=0)break;if(!h.has(b.id.toLowerCase()))try{let a=f.decomposer;if(a?.enabled){let h=`${b.title}
384
-
385
- ${b.description}`,j={...d.$J,...a};console.log(`[backlog] Decomposing issue ${b.id}: "${b.title}"`);let k=await (0,d.o)(h,j),l=(0,d.Lg)(k.tree);if(l.length<=1)await c.spawn({projectId:e,issueId:b.id}),i--;else if(j.requireApproval){let a=(0,d.Pp)(k.tree);g.updateIssue&&await g.updateIssue(b.id,{comment:`## Decomposition Plan
396
+ exit $exit_code
397
+ `,a8=`
398
+ ## Agent Orchestrator (ao) Session
386
399
 
387
- \`\`\`
388
- ${a}
389
- \`\`\`
400
+ You are running inside an Agent Orchestrator managed workspace.
401
+ Session metadata is updated automatically via shell wrappers.
390
402
 
391
- ${l.length} subtasks identified. Remove \`agent:backlog\` and add \`agent:decompose-approved\` to execute.`,labels:["agent:decompose-pending"],removeLabels:["agent:backlog"]},f),console.log(`[backlog] Posted decomposition plan for ${b.id} (${l.length} subtasks, awaiting approval)`);continue}else for(let a of(console.log(`[backlog] Auto-executing decomposition for ${b.id} (${l.length} subtasks)`),l)){if(i<=0)break;let f=(0,d.A7)(k.tree,a.id);await c.spawn({projectId:e,issueId:b.id,lineage:a.lineage,siblings:f}),i--}}else await c.spawn({projectId:e,issueId:b.id}),i--;h.add(b.id.toLowerCase()),g.updateIssue&&await g.updateIssue(b.id,{labels:["agent:in-progress"],removeLabels:["agent:backlog"],comment:"Claimed by agent orchestrator — session spawned."},f)}catch(a){console.error(`[backlog] Failed to spawn session for issue ${b.id}:`,a)}}}}}catch(a){console.error("[backlog] Poll failed:",a)}}async function aK(){let a=[];try{let{config:b,registry:c}=await aB();for(let[d,e]of Object.entries(b.projects)){if(!e.tracker?.plugin)continue;let b=c.get("tracker",e.tracker.plugin);if(b?.listIssues)try{for(let c of(await b.listIssues({state:"open",labels:[aD],limit:20},e)))a.push({...c,projectId:d})}catch{}}}catch{}return a}async function aL(){let a=[];try{let{config:b,registry:c}=await aB();for(let[d,e]of Object.entries(b.projects)){if(!e.tracker?.plugin)continue;let b=c.get("tracker",e.tracker.plugin);if(b?.listIssues)try{for(let c of(await b.listIssues({state:"open",labels:["merged-unverified"],limit:20},e)))a.push({...c,projectId:d})}catch{}}}catch{}return a}function aM(a,b){return b?.scm?.plugin?a.get("scm",b.scm.plugin):null}}};
403
+ If automatic updates fail, you can manually update metadata:
404
+ \`\`\`bash
405
+ ~/.ao/bin/ao-metadata-helper.sh # sourced automatically
406
+ # Then call: update_ao_metadata <key> <value>
407
+ \`\`\`
408
+ `;async function a9(a,b,c){let d=(0,k.randomBytes)(6).toString("hex"),e=`${a}.tmp.${d}`;await (0,al.writeFile)(e,b,{encoding:"utf-8",mode:c}),await (0,al.rename)(e,a)}async function ba(a){await (0,al.mkdir)(a2(),{recursive:!0});let b=(0,f.join)(a2(),".ao-version"),c=!0;try{(await (0,al.readFile)(b,"utf-8")).trim()===a3&&(c=!1)}catch{}c&&(await a9((0,f.join)(a2(),"ao-metadata-helper.sh"),a5,493),await a9((0,f.join)(a2(),"gh"),a6,493),await a9((0,f.join)(a2(),"git"),a7,493),await a9(b,a3,420));let d=(0,f.join)(a,".ao","AGENTS.md");await (0,al.mkdir)((0,f.join)(a,".ao"),{recursive:!0}),await (0,al.writeFile)(d,a8.trimStart(),"utf-8")}let bb={BUG_REPORT:"bug_report",IMPROVEMENT_SUGGESTION:"improvement_suggestion"},bc=j.Yj().transform(a=>a.trim().replace(/\s+/g," ")).pipe(j.Yj().min(1));j.Ik({title:bc,body:bc,evidence:j.YO(bc).min(1),session:bc,source:bc,confidence:j.ai().finite().min(0).max(1)}).strict(),bb.BUG_REPORT,bb.IMPROVEMENT_SUGGESTION,j.Yj().regex(/^report_[A-Za-z0-9_-]+$/),j.Yj().datetime({offset:!0}),j.Yj().regex(/^[a-f0-9]{16}$/)},90337:()=>{}};