@aoagents/ao-web 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +200 -186
- package/.next/app-path-routes-manifest.json +16 -14
- package/.next/build-manifest.json +6 -6
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +19 -19
- package/.next/react-loadable-manifest.json +5 -3
- package/.next/required-server-files.json +4 -5
- package/.next/server/app/_not-found/page.js +2 -2
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +8 -8
- package/.next/server/app/api/backlog/route.js +1 -1
- package/.next/server/app/api/backlog/route.js.nft.json +1 -1
- package/.next/server/app/api/backlog/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/browse-directory/route.js +1 -1
- package/.next/server/app/api/browse-directory/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/filesystem/browse/route.js +1 -1
- package/.next/server/app/api/filesystem/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/issues/route.js +1 -1
- package/.next/server/app/api/issues/route.js.nft.json +1 -1
- package/.next/server/app/api/issues/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/observability/route.js +1 -1
- package/.next/server/app/api/observability/route.js.nft.json +1 -1
- package/.next/server/app/api/observability/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/orchestrators/route.js +1 -1
- package/.next/server/app/api/orchestrators/route.js.nft.json +1 -1
- package/.next/server/app/api/orchestrators/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/projects/[id]/route.js +5 -1
- package/.next/server/app/api/projects/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/projects/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/projects/reload/route.js +1 -1
- package/.next/server/app/api/projects/reload/route.js.nft.json +1 -1
- package/.next/server/app/api/projects/reload/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/projects/route.js +1 -1
- package/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/prs/[id]/merge/route.js +1 -1
- package/.next/server/app/api/prs/[id]/merge/route.js.nft.json +1 -1
- package/.next/server/app/api/prs/[id]/merge/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/runtime/terminal/route.js +1 -1
- package/.next/server/app/api/runtime/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/[id]/kill/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/kill/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/kill/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/[id]/message/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/message/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/message/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/[id]/remap/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/remap/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/remap/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/[id]/restore/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/restore/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/[id]/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/[id]/send/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/patches/route.js +1 -1
- package/.next/server/app/api/sessions/patches/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/patches/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/route.js +1 -1
- package/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/setup-labels/route.js +1 -1
- package/.next/server/app/api/setup-labels/route.js.nft.json +1 -1
- package/.next/server/app/api/setup-labels/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/spawn/route.js +1 -1
- package/.next/server/app/api/spawn/route.js.nft.json +1 -1
- package/.next/server/app/api/spawn/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/update/route.js +1 -0
- package/.next/server/app/api/update/route.js.nft.json +1 -0
- package/.next/server/app/api/update/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/verify/route.js +1 -1
- package/.next/server/app/api/verify/route.js.nft.json +1 -1
- package/.next/server/app/api/verify/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/version/route.js +1 -0
- package/.next/server/app/api/version/route.js.nft.json +1 -0
- package/.next/server/app/api/version/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/webhooks/[...slug]/route.js +1 -1
- package/.next/server/app/api/webhooks/[...slug]/route.js.nft.json +1 -1
- package/.next/server/app/api/webhooks/[...slug]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/apple-icon/route.js +1 -1
- package/.next/server/app/apple-icon/route.js.nft.json +1 -1
- package/.next/server/app/apple-icon/route_client-reference-manifest.js +1 -1
- package/.next/server/app/apple-icon.body +0 -0
- package/.next/server/app/dev/terminal-test/page.js +3 -3
- package/.next/server/app/dev/terminal-test/page.js.nft.json +1 -1
- package/.next/server/app/dev/terminal-test/page_client-reference-manifest.js +1 -1
- package/.next/server/app/dev/terminal-test.html +1 -1
- package/.next/server/app/dev/terminal-test.rsc +9 -9
- package/.next/server/app/icon/route.js +1 -1
- package/.next/server/app/icon/route.js.nft.json +1 -1
- package/.next/server/app/icon/route_client-reference-manifest.js +1 -1
- package/.next/server/app/icon-192/route.js +1 -1
- package/.next/server/app/icon-192/route.js.nft.json +1 -1
- package/.next/server/app/icon-192/route_client-reference-manifest.js +1 -1
- package/.next/server/app/icon-512/route.js +1 -1
- package/.next/server/app/icon-512/route.js.nft.json +1 -1
- package/.next/server/app/icon-512/route_client-reference-manifest.js +1 -1
- package/.next/server/app/icon.body +0 -0
- package/.next/server/app/manifest.webmanifest/route.js +1 -1
- package/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -1
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest.body +1 -1
- package/.next/server/app/orchestrators/page.js +2 -2
- package/.next/server/app/orchestrators/page.js.nft.json +1 -1
- package/.next/server/app/orchestrators/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page.js +2 -2
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/projects/[projectId]/page.js +2 -2
- package/.next/server/app/projects/[projectId]/page.js.nft.json +1 -1
- package/.next/server/app/projects/[projectId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/projects/[projectId]/sessions/[id]/page.js +2 -2
- package/.next/server/app/projects/[projectId]/sessions/[id]/page.js.nft.json +1 -1
- package/.next/server/app/projects/[projectId]/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/projects/[projectId]/settings/page.js +2 -2
- package/.next/server/app/projects/[projectId]/settings/page.js.nft.json +1 -1
- package/.next/server/app/projects/[projectId]/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/prs/page.js +2 -2
- package/.next/server/app/prs/page.js.nft.json +1 -1
- package/.next/server/app/prs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/[id]/page.js +2 -2
- package/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
- package/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/test-direct/page.js +2 -2
- package/.next/server/app/test-direct/page.js.nft.json +1 -1
- package/.next/server/app/test-direct/page_client-reference-manifest.js +1 -1
- package/.next/server/app/test-direct.html +1 -1
- package/.next/server/app/test-direct.rsc +9 -9
- package/.next/server/app-paths-manifest.json +16 -14
- package/.next/server/chunks/1271.js +1 -1
- package/.next/server/chunks/1876.js +2 -2
- package/.next/server/chunks/303.js +3 -0
- package/.next/server/chunks/3714.js +1 -1
- package/.next/server/chunks/4520.js +1 -1
- package/.next/server/chunks/6013.js +884 -0
- package/.next/server/chunks/6848.js +1 -0
- package/.next/server/chunks/7167.js +1 -1
- package/.next/server/chunks/7173.js +1 -1
- package/.next/server/chunks/7227.js +604 -0
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/9nr0fNWbZcuWTqhM2HhrH/_buildManifest.js +1 -0
- package/.next/static/chunks/1654.ac304fc9e36ec94a.js +1 -0
- package/.next/static/chunks/3764.cdef4e76dbc23af8.js +1 -0
- package/.next/static/chunks/3780-7bdc52d8370adf2f.js +1 -0
- package/.next/static/chunks/{5795-b96fd46c8c7344fc.js → 5795-a4dd81606df09bc4.js} +1 -1
- package/.next/static/chunks/6231-57dd9c1e306c7069.js +1 -0
- package/.next/static/chunks/app/_not-found/page-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/backlog/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/browse-directory/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/filesystem/browse/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/issues/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/observability/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/orchestrators/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/projects/[id]/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/projects/reload/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/projects/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/prs/[id]/merge/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/runtime/terminal/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/kill/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/message/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/remap/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/restore/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/send/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/sessions/patches/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/sessions/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/setup-labels/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/spawn/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/update/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/verify/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/version/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/api/webhooks/[...slug]/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/apple-icon/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/dev/terminal-test/{page-59decd1aad4e02ad.js → page-9aa423dfd54c8325.js} +1 -1
- package/.next/static/chunks/app/{error-684a1c5596fa1e14.js → error-65c526052680c0dc.js} +1 -1
- package/.next/static/chunks/app/{global-error-1a79bacfbd9b1ba4.js → global-error-63dcb797b2c3ee60.js} +1 -1
- package/.next/static/chunks/app/icon/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/icon-192/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/icon-512/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/layout-36ab0168ddb22083.js +1 -0
- package/.next/static/chunks/app/loading-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/manifest.webmanifest/route-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/not-found-a693bed1f9e1893f.js +1 -0
- package/.next/static/chunks/app/orchestrators/{page-e3a2c53b57dd8391.js → page-376a92db51deb112.js} +1 -1
- package/.next/static/chunks/app/page-587d546e62c0796f.js +1 -0
- package/.next/static/chunks/app/projects/[projectId]/loading-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/projects/[projectId]/page-bd8fc2a1decb649d.js +1 -0
- package/.next/static/chunks/app/projects/[projectId]/sessions/[id]/page-bd33f6ffda513080.js +1 -0
- package/.next/static/chunks/app/projects/[projectId]/settings/page-11facc471a63de50.js +1 -0
- package/.next/static/chunks/app/prs/page-f34f66ad51106080.js +1 -0
- package/.next/static/chunks/app/sessions/[id]/{error-62e9972b39d9cd16.js → error-df65e7b626bbb713.js} +1 -1
- package/.next/static/chunks/app/sessions/[id]/loading-8b5044bdc951ae98.js +1 -0
- package/.next/static/chunks/app/sessions/[id]/not-found-a693bed1f9e1893f.js +1 -0
- package/.next/static/chunks/app/sessions/[id]/page-3ea4aa79275ea449.js +1 -0
- package/.next/static/chunks/app/test-direct/page-edfc701a9300105b.js +1 -0
- package/.next/static/chunks/main-app-decbc53736801215.js +1 -0
- package/.next/static/chunks/{webpack-83d2d8248a30259c.js → webpack-ecf0988dbb79e19b.js} +1 -1
- package/.next/static/css/b93232cd4a58743d.css +1 -0
- package/dist-server/direct-terminal-ws.js +12 -2
- package/dist-server/mux-websocket.js +270 -70
- package/dist-server/start-all.js +28 -6
- package/dist-server/tmux-utils.js +124 -2
- package/next.config.js +26 -0
- package/package.json +26 -12
- package/.next/server/chunks/1172.js +0 -1
- package/.next/server/chunks/6811.js +0 -3
- package/.next/server/chunks/801.js +0 -658
- package/.next/server/chunks/9223.js +0 -440
- package/.next/static/chunks/1383.8f5f7d4606d356cc.js +0 -1
- package/.next/static/chunks/3764.88619fb0d047cae8.js +0 -1
- package/.next/static/chunks/3780-52c4733ce6591b8d.js +0 -1
- package/.next/static/chunks/4465-17154f7a01abfe85.js +0 -1
- package/.next/static/chunks/app/_not-found/page-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/backlog/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/browse-directory/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/filesystem/browse/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/issues/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/observability/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/orchestrators/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/projects/[id]/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/projects/reload/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/projects/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/prs/[id]/merge/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/runtime/terminal/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/kill/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/message/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/remap/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/restore/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/send/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/sessions/patches/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/sessions/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/setup-labels/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/spawn/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/verify/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/api/webhooks/[...slug]/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/apple-icon/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/icon/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/icon-192/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/icon-512/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/layout-0cda720d75f111b8.js +0 -1
- package/.next/static/chunks/app/loading-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/manifest.webmanifest/route-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/not-found-315f4e5c106b425d.js +0 -1
- package/.next/static/chunks/app/page-e2e589ea11a0780a.js +0 -1
- package/.next/static/chunks/app/projects/[projectId]/loading-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/projects/[projectId]/page-19a6d4cc9951a9e4.js +0 -1
- package/.next/static/chunks/app/projects/[projectId]/sessions/[id]/page-75c536c9755754f7.js +0 -1
- package/.next/static/chunks/app/projects/[projectId]/settings/page-f8c323b91978efff.js +0 -1
- package/.next/static/chunks/app/prs/page-08f17d7dc341b6f1.js +0 -1
- package/.next/static/chunks/app/sessions/[id]/loading-3b8a01e726e988c8.js +0 -1
- package/.next/static/chunks/app/sessions/[id]/not-found-315f4e5c106b425d.js +0 -1
- package/.next/static/chunks/app/sessions/[id]/page-d0b08722dec5a04a.js +0 -1
- package/.next/static/chunks/app/test-direct/page-ee0944bcd355194e.js +0 -1
- package/.next/static/chunks/main-app-b95f197c38e3b0a3.js +0 -1
- package/.next/static/css/cf9226160e230bf4.css +0 -1
- package/.next/static/h0RXs0prE87a8wlbEXQKM/_buildManifest.js +0 -1
- /package/.next/static/{h0RXs0prE87a8wlbEXQKM → 9nr0fNWbZcuWTqhM2HhrH}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
"use strict";exports.id=7227,exports.ids=[7227],exports.modules={97227:(a,b,c)=>{c.d(b,{ix:()=>b_,wp:()=>b1,Z1:()=>bR,uj:()=>b0,g8:()=>bS,Az:()=>bW});var d=c(32285),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_-]+$/;function n(a){return`${a.replace(/\n+$/,"")}
|
|
2
|
+
exec "\${SHELL:-/bin/bash}" -i`}async function o(...a){let{stdout:b}=await l("tmux",a,{timeout:5e3});return b.trimEnd()}let p={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}`);let f=a.environment?.PATH,g=a.launchCommand;f&&(g=`export PATH=$(printf '%s' ${JSON.stringify(f)})
|
|
3
|
+
${g}`);let l=g.length>200?function(a){let b=(0,k.join)((0,j.tmpdir)(),`ao-launch-${(0,h.randomUUID)()}.sh`),c=`#!/usr/bin/env bash
|
|
4
|
+
rm -- "$0" 2>/dev/null || true
|
|
5
|
+
${n(a)}
|
|
6
|
+
`;return(0,i.writeFileSync)(b,c,{encoding:"utf-8",mode:448}),`bash ${(0,d.kct)(b)}`}(g):n(g);await o("new-session","-d","-s",c,"-c",a.workspacePath,...e,l);try{await o("set-option","-t",c,"status","off")}catch(b){try{await o("kill-session","-t",c)}catch{}let a=b instanceof Error?b.message:String(b);throw Error(`Failed to configure or launch session "${c}": ${a}`,{cause:b})}return{id:c,runtimeName:"tmux",data:{createdAt:Date.now(),workspacePath:a.workspacePath}}},async destroy(a){try{await o("kill-session","-t",a.id)}catch{}},async sendMessage(a,b){if(await o("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 o("load-buffer","-b",c,d),await o("paste-buffer","-b",c,"-t",a.id,"-d")}finally{try{(0,i.unlinkSync)(d)}catch{}try{await o("delete-buffer","-b",c)}catch{}}}else await o("send-keys","-t",a.id,"-l",b);await (0,g.setTimeout)(300),await o("send-keys","-t",a.id,"Enter")},async getOutput(a,b=50){try{return await o("capture-pane","-t",a.id,"-p","-S",`-${b}`)}catch{return""}},async isAlive(a){try{return await o("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}`}),async preflight(){try{await l("tmux",["-V"],{timeout:5e3})}catch{let a="darwin"===process.platform?"brew install tmux":"win32"===process.platform?"tmux is not available on Windows. Use WSL: wsl --install, then: sudo apt install tmux":"sudo apt install tmux (Debian/Ubuntu) or sudo dnf install tmux (Fedora)";throw Error(`tmux is not installed. Install it: ${a}`)}}}}};var q=c(73136),r=c(77030);function s(a,b){let c="string"==typeof b?Buffer.from(b,"utf-8"):b,d=Buffer.allocUnsafe(5+c.length);return d.writeUInt8(a,0),d.writeUInt32BE(c.length,1),c.copy(d,5),d}class t{constructor(a){this._buf=Buffer.alloc(0),this._onMessage=a}feed(a){for(this._buf=Buffer.concat([this._buf,a]);this._buf.length>=5;){let a=5+this._buf.readUInt32BE(1);if(this._buf.length<a)break;let b=this._buf.readUInt8(0),c=this._buf.slice(5,a);this._buf=this._buf.slice(a),this._onMessage(b,c)}}}async function u(){let a,[,,b,d,e,f,...g]=process.argv;b&&d&&e&&f||(process.stderr.write("Usage: node pty-host.js <sessionId> <pipePath> <cwd> <shellCmd> [shellArg...]\n"),process.exit(1));let{spawn:h}=await Promise.resolve().then(c.t.bind(c,14566,19)),i=f;"win32"!==process.platform||f.includes("\\")||f.includes("/")||f.endsWith(".exe")||f.endsWith(".cmd")||(i=f+".exe");let j=[],k=new Set,l=h(i,g,{name:"xterm-256color",cols:220,rows:50,cwd:e,env:process.env,encoding:null});process.stdout.write(`READY:${l.pid}
|
|
7
|
+
`);let m="";function n(a){for(let b of k)b.destroyed||b.write(a)}function o(a,b){a.destroyed||a.write(b)}l.onData(a=>{let b="string"==typeof a?Buffer.from(a,"utf-8"):Buffer.from(a),c=(m+b.toString("utf-8")).split("\n");for(let a of(m=c.pop(),c))j.push(a+"\n");j.length>1e3&&j.splice(0,j.length-1e3),n(s(1,b))}),l.onExit(({exitCode:b})=>{a=b,m&&(j.push(m),m=""),n(s(7,JSON.stringify({alive:!1,pid:l.pid,exitCode:b})))});let p=r.createServer(b=>{k.add(b),j.length>0&&o(b,s(1,Buffer.from(j.join(""),"utf-8")));let c=new t((c,d)=>{!function(b,c,d){switch(c){case 2:void 0===a&&l.write(d.toString("utf-8"));break;case 3:if(void 0===a)try{let{cols:a,rows:b}=JSON.parse(d.toString("utf-8"));"number"==typeof a&&"number"==typeof b&&l.resize(a,b)}catch{}break;case 4:{let a=50;try{let b=JSON.parse(d.toString("utf-8"));"number"==typeof b.lines&&(a=b.lines)}catch{}let c=Math.max(0,j.length-a);o(b,s(5,j.slice(c).join("")));break}case 6:{let c=void 0===a,d={alive:c,pid:l.pid};c||(d.exitCode=a),o(b,s(7,JSON.stringify(d)));break}case 8:u("MSG_KILL_REQ")}}(b,c,d)});b.on("data",a=>{c.feed(a)}),b.on("close",()=>{k.delete(b)}),b.on("error",()=>{k.delete(b)})});await new Promise((a,b)=>{p.once("error",b),p.listen(d,()=>{p.removeListener("error",b),a()})});let q=!1;function u(c){if(!q){q=!0;try{if(void 0===a)try{l.kill()}catch{}}catch{}for(let a of k)try{a.destroy()}catch{}k.clear();try{p.close()}catch{}setTimeout(()=>process.exit(0),50).unref(),process.stderr.write(`pty-host [${b}] shutdown: ${c}
|
|
8
|
+
`)}}process.on("SIGTERM",()=>u("SIGTERM")),process.on("SIGINT",()=>u("SIGINT")),process.on("SIGHUP",()=>u("SIGHUP")),process.on("SIGBREAK",()=>u("SIGBREAK")),process.on("beforeExit",()=>u("beforeExit")),process.on("uncaughtException",a=>{process.stderr.write(`pty-host [${b}] uncaught: ${String(a)}
|
|
9
|
+
`),u("uncaughtException")}),process.on("unhandledRejection",a=>{process.stderr.write(`pty-host [${b}] unhandled rejection: ${String(a)}
|
|
10
|
+
`)}),process.on("exit",()=>{try{void 0===a&&l.kill()}catch{}})}function v(a,b=3e3){return new Promise((c,d)=>{let e=!1,f=(0,r.connect)(a),g=setTimeout(()=>{e||(e=!0,f.destroy(),d(Error(`Timed out connecting to pty-host at ${a} (${b}ms)`)))},b);f.once("connect",()=>{e||(e=!0,clearTimeout(g),c(f))}),f.once("error",a=>{e||(e=!0,clearTimeout(g),d(a))})})}function w(a,b){return new Promise((c,d)=>{a.write(b,a=>{a?d(a):c()})})}function x(a){return new Promise(b=>setTimeout(b,a))}async function y(a,b){let c=await v(a);return new Promise((a,d)=>{let e=!1,f=b=>{e||(e=!0,b?(c.destroy(),d(b)):(c.end(),a()))};c.once("error",f),(async()=>{try{for(let a=0;a<b.length;a+=512){let d=b.slice(a,a+512);await w(c,s(2,d)),a+512<b.length&&await x(15)}await x(300),await w(c,s(2,"\r")),f()}catch(a){f(a)}})()})}async function z(a,b=50){let c;try{c=await v(a,3e3)}catch{return""}return new Promise(a=>{let d=!1,e=b=>{d||(d=!0,clearTimeout(f),c.destroy(),a(b))},f=setTimeout(()=>e(""),3e3),g=new t((a,b)=>{5===a&&e(b.toString("utf-8"))});c.on("data",a=>g.feed(a)),c.once("error",()=>e("")),c.once("close",()=>e(""));let h=s(4,JSON.stringify({lines:b}));c.write(h)})}async function A(a){let b;try{b=await v(a,2e3)}catch{return!1}return new Promise(a=>{let c=!1,d=d=>{c||(c=!0,clearTimeout(e),b.destroy(),a(d))},e=setTimeout(()=>d(!1),2e3),f=new t((a,b)=>{if(7===a)try{JSON.parse(b.toString("utf-8")),d(!0)}catch{d(!1)}});b.on("data",a=>f.feed(a)),b.once("error",()=>d(!1)),b.once("close",()=>d(!1)),b.write(s(6,""))})}async function B(a){let b;try{b=await v(a,2e3)}catch{return}await new Promise(a=>{b.once("error",()=>a());let c=s(8,"");b.write(c,()=>{b.end(),a()})})}(process.argv[1]?.endsWith("pty-host.js")||process.argv[1]?.endsWith("pty-host.ts"))&&u();let C=/^[a-zA-Z0-9_-]+$/,D={manifest:{name:"process",slot:"runtime",description:"Runtime plugin: child processes",version:"0.1.0"},create:function(){let a=new Map;return{name:"process",async create(b){let c;var f=b.sessionId;if(!C.test(f))throw Error(`Invalid session ID "${f}": must match ${C}`);let g=b.sessionId;if(a.has(g))throw Error(`Session "${g}" already exists — destroy it before re-creating`);let h={process:null,outputBuffer:[],createdAt:Date.now()};if(a.set(g,h),(0,d.uFH)()){let c=`\\\\.\\pipe\\ao-pty-${g}`,f=(0,d.ry1)(),i=(0,k.resolve)((0,k.dirname)((0,q.fileURLToPath)("file:///tmp/ao-publish-stable/packages/plugins/runtime-process/dist/index.js")),"pty-host.js"),j={...process.env,...b.environment};try{let a=(0,e.spawn)(process.execPath,[i,g,c,b.workspacePath,f.cmd,...f.args(b.launchCommand)],{cwd:b.workspacePath,env:j,stdio:["ignore","pipe","pipe"],detached:!0,windowsHide:!0}),k=await new Promise((b,c)=>{let d=setTimeout(()=>{a.kill(),c(Error("PTY host startup timeout (10s)"))},1e4),e="";a.stdout?.on("data",a=>{let c=(e+=a.toString()).match(/READY:(\d+)/);c&&(clearTimeout(d),b(parseInt(c[1],10)))}),a.stderr?.on("data",a=>{e+=a.toString()}),a.on("error",a=>{clearTimeout(d),c(Error(`PTY host spawn error: ${a.message}`))}),a.on("exit",a=>{clearTimeout(d),c(Error(`PTY host exited during startup with code ${a}: ${e}`))})});if(a.unref(),a.stdout?.destroy(),a.stderr?.destroy(),"number"==typeof a.pid)try{(0,d.YEV)({sessionId:g,ptyHostPid:a.pid,pipePath:c})}catch{}return{id:g,runtimeName:"process",data:{pid:k,ptyHostPid:a.pid,pipePath:c,createdAt:h.createdAt}}}catch(b){throw a.delete(g),b}}let i=(0,d.ry1)();try{c=(0,e.spawn)(i.cmd,i.args(b.launchCommand),{cwd:b.workspacePath,env:{...process.env,...b.environment},stdio:["pipe","pipe","pipe"],detached:!(0,d.uFH)()})}catch(c){a.delete(g);let b=c instanceof Error?c.message:String(c);throw Error(`Failed to spawn process for session ${g}: ${b}`,{cause:c})}function j(){let a="";return b=>{let c=(a+b.toString("utf-8")).split("\n");for(let b of(a=c.pop(),c))h.outputBuffer.push(b);h.outputBuffer.length>1e3&&h.outputBuffer.splice(0,h.outputBuffer.length-1e3)}}h.process=c,c.once("exit",()=>{h.outputBuffer.push(`[process exited with code ${c.exitCode}]`),a.delete(g)}),c.on("error",()=>{}),await new Promise((b,d)=>{let e=b=>{c.removeListener("spawn",f),a.delete(g),d(Error(`Failed to spawn process for session ${g}: ${b.message}`))},f=()=>{c.removeListener("error",e),b()};c.once("error",e),c.once("spawn",f)});let l=j(),m=j();return c.stdout?.on("data",l),c.stderr?.on("data",m),c.once("exit",()=>{l(Buffer.from("\n")),m(Buffer.from("\n"))}),{id:g,runtimeName:"process",data:{pid:c.pid,createdAt:h.createdAt}}},async destroy(b){let c=b.data?.pipePath;if(c){await B(c);let e=b.data?.ptyHostPid;if("number"==typeof e&&e>0){let c=Date.now()+500;for(;Date.now()<c;){try{process.kill(e,0)}catch(c){if("EPERM"===c.code)break;a.delete(b.id);try{(0,d.unregisterWindowsPtyHost)(b.id)}catch{}return}await new Promise(a=>setTimeout(a,25))}await (0,d.g8K)(e,"SIGKILL")}a.delete(b.id);try{(0,d.unregisterWindowsPtyHost)(b.id)}catch{}return}let e=a.get(b.id);if(!e){let a=b.data?.pid;"number"==typeof a&&a>0&&await (0,d.g8K)(a,"SIGKILL");return}let f=e.process;if(!f)return void a.delete(b.id);if(null===f.exitCode&&null===f.signalCode){let a=f.pid,b=new Promise(b=>{let c=setTimeout(()=>{Promise.resolve(null===f.exitCode&&null===f.signalCode?a?(0,d.g8K)(a,"SIGKILL"):void f.kill("SIGKILL"):void 0).catch(()=>{}).finally(b)},5e3);f.once("exit",()=>{clearTimeout(c),b()})});a?await (0,d.g8K)(a,"SIGTERM"):f.kill("SIGTERM"),await b}a.delete(b.id)},async sendMessage(b,c){let d=b.data?.pipePath;if(d)return void await y(d,c);let e=a.get(b.id);if(!e)throw Error(`No process found for session ${b.id}`);let f=e.process;if(!f)throw Error(`Process for session ${b.id} is still spawning`);let g=f.stdin;if(!g||!g.writable)throw Error(`stdin not writable for session ${b.id}`);await new Promise((a,b)=>{let d=!1,e=c=>{d||(d=!0,i(),c?b(c):a())},f=a=>e(a),h=()=>{},i=()=>{g.removeListener("error",f),g.removeListener("drain",h)};g.on("error",f),g.on("drain",h),g.write(c+"\n",a=>e(a??null))})},async getOutput(b,c=50){let d=b.data?.pipePath;if(d)return z(d,c);let e=a.get(b.id);if(!e)return"";let f=e.outputBuffer,g=Math.max(0,f.length-c);return f.slice(g).join("\n")},async isAlive(b){let c=b.data?.pipePath;if(c)return A(c);let d=a.get(b.id);if(!d||!d.process){let a=b.data?.pid;if("number"==typeof a&&a>0)try{return process.kill(a,0),!0}catch(a){if("EPERM"===a.code)return!0}return!1}return null===d.process.exitCode&&null===d.process.signalCode},async getMetrics(b){let c=a.get(b.id),d=c?.createdAt??Date.now();return{uptimeMs:Date.now()-d}},async getAttachInfo(b){let c=b.data?.pipePath;if(c)return await A(c)?{type:"process",target:String(b.data?.pid??""),command:c}:{type:"process",target:"",command:`# process for session ${b.id} is no longer running`};let d=a.get(b.id);return d&&d.process&&null===d.process.exitCode&&null===d.process.signalCode?{type:"process",target:String(d.process.pid)}:{type:"process",target:"",command:`# process for session ${b.id} is no longer running`}}}}};var E=c(51455);let F=(0,f.promisify)(e.execFile),G=`#!/usr/bin/env bash
|
|
11
|
+
# Metadata Updater Hook for Agent Orchestrator
|
|
12
|
+
#
|
|
13
|
+
# This PostToolUse hook automatically updates session metadata when:
|
|
14
|
+
# - gh pr create: extracts PR URL and writes to metadata
|
|
15
|
+
# - git checkout -b / git switch -c: extracts branch name and writes to metadata
|
|
16
|
+
# - gh pr merge: updates status to "merged"
|
|
17
|
+
|
|
18
|
+
set -euo pipefail
|
|
19
|
+
|
|
20
|
+
# Configuration
|
|
21
|
+
AO_DATA_DIR="\${AO_DATA_DIR:-$HOME/.ao-sessions}"
|
|
22
|
+
|
|
23
|
+
# Read hook input from stdin
|
|
24
|
+
input=$(cat)
|
|
25
|
+
|
|
26
|
+
# Extract fields from JSON (using jq if available, otherwise basic parsing)
|
|
27
|
+
if command -v jq &>/dev/null; then
|
|
28
|
+
tool_name=$(echo "$input" | jq -r '.tool_name // empty')
|
|
29
|
+
command=$(echo "$input" | jq -r '.tool_input.command // empty')
|
|
30
|
+
output=$(echo "$input" | jq -r '.tool_response // empty')
|
|
31
|
+
exit_code=$(echo "$input" | jq -r '.exit_code // 0')
|
|
32
|
+
else
|
|
33
|
+
# Fallback: basic JSON parsing without jq
|
|
34
|
+
tool_name=$(echo "$input" | grep -o '"tool_name"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4 || echo "")
|
|
35
|
+
command=$(echo "$input" | grep -o '"command"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4 || echo "")
|
|
36
|
+
output=$(echo "$input" | grep -o '"tool_response"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4 || echo "")
|
|
37
|
+
exit_code=$(echo "$input" | grep -o '"exit_code"[[:space:]]*:[[:space:]]*[0-9]*' | grep -o '[0-9]*$' || echo "0")
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Only process successful commands (exit code 0)
|
|
41
|
+
if [[ "$exit_code" -ne 0 ]]; then
|
|
42
|
+
echo '{}'
|
|
43
|
+
exit 0
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Only process Bash tool calls
|
|
47
|
+
if [[ "$tool_name" != "Bash" ]]; then
|
|
48
|
+
echo '{}' # Empty JSON output
|
|
49
|
+
exit 0
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Validate AO_SESSION is set
|
|
53
|
+
if [[ -z "\${AO_SESSION:-}" ]]; then
|
|
54
|
+
echo '{"systemMessage": "AO_SESSION environment variable not set, skipping metadata update"}'
|
|
55
|
+
exit 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# Construct metadata file path
|
|
59
|
+
# AO_DATA_DIR is already set to the project-specific sessions directory
|
|
60
|
+
# V2 storage uses .json extension
|
|
61
|
+
metadata_file="$AO_DATA_DIR/\${AO_SESSION}.json"
|
|
62
|
+
|
|
63
|
+
# Fallback to bare filename for pre-migration layouts
|
|
64
|
+
if [[ ! -f "$metadata_file" ]]; then
|
|
65
|
+
metadata_file="$AO_DATA_DIR/$AO_SESSION"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# Ensure metadata file exists
|
|
69
|
+
if [[ ! -f "$metadata_file" ]]; then
|
|
70
|
+
echo '{"systemMessage": "Metadata file not found: '"$AO_DATA_DIR/\${AO_SESSION}"'"}'
|
|
71
|
+
exit 0
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
# Detect if metadata file is JSON format
|
|
75
|
+
is_json_metadata() {
|
|
76
|
+
local first_char
|
|
77
|
+
first_char=$(head -c1 "$metadata_file" 2>/dev/null)
|
|
78
|
+
[[ "$first_char" == "{" ]]
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# Update a single key in metadata (handles both JSON and key=value formats)
|
|
82
|
+
update_metadata_key() {
|
|
83
|
+
local key="$1"
|
|
84
|
+
local value="$2"
|
|
85
|
+
local temp_file="\${metadata_file}.tmp"
|
|
86
|
+
|
|
87
|
+
if is_json_metadata; then
|
|
88
|
+
# JSON format
|
|
89
|
+
if command -v jq &>/dev/null; then
|
|
90
|
+
jq --arg k "$key" --arg v "$value" '.[$k] = $v' "$metadata_file" > "$temp_file"
|
|
91
|
+
mv "$temp_file" "$metadata_file"
|
|
92
|
+
else
|
|
93
|
+
# jq unavailable — use node (hard dep) for safe nested JSON update
|
|
94
|
+
node -e "
|
|
95
|
+
const fs = require('fs');
|
|
96
|
+
const d = JSON.parse(fs.readFileSync(process.argv[1], 'utf8'));
|
|
97
|
+
d[process.argv[2]] = process.argv[3];
|
|
98
|
+
fs.writeFileSync(process.argv[4], JSON.stringify(d, null, 2));
|
|
99
|
+
" "$metadata_file" "$key" "$value" "$temp_file"
|
|
100
|
+
mv "$temp_file" "$metadata_file"
|
|
101
|
+
fi
|
|
102
|
+
else
|
|
103
|
+
# Key=value format (legacy)
|
|
104
|
+
local escaped_value=$(echo "$value" | sed 's/[&|\\/]/\\\\&/g')
|
|
105
|
+
if grep -q "^$key=" "$metadata_file" 2>/dev/null; then
|
|
106
|
+
sed "s|^$key=.*|$key=$escaped_value|" "$metadata_file" > "$temp_file"
|
|
107
|
+
else
|
|
108
|
+
cp "$metadata_file" "$temp_file"
|
|
109
|
+
echo "$key=$value" >> "$temp_file"
|
|
110
|
+
fi
|
|
111
|
+
mv "$temp_file" "$metadata_file"
|
|
112
|
+
fi
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# ============================================================================
|
|
116
|
+
# Command Detection and Parsing
|
|
117
|
+
# ============================================================================
|
|
118
|
+
|
|
119
|
+
# Strip leading directory-change prefixes so that commands like
|
|
120
|
+
# cd ~/.worktrees/project && gh pr create ...
|
|
121
|
+
# are correctly detected. Agents frequently cd into a worktree first.
|
|
122
|
+
# Store the regex pattern in a variable for clarity (avoids shell quoting confusion).
|
|
123
|
+
# Uses space-padded (&&|;) to avoid breaking on paths containing & or ; chars.
|
|
124
|
+
cd_prefix_pattern='^[[:space:]]*cd[[:space:]]+.*[[:space:]]+(&&|;)[[:space:]]+(.*)'
|
|
125
|
+
clean_command="$command"
|
|
126
|
+
while [[ "$clean_command" =~ ^[[:space:]]*cd[[:space:]] ]]; do
|
|
127
|
+
if [[ "$clean_command" =~ $cd_prefix_pattern ]]; then
|
|
128
|
+
clean_command="\${BASH_REMATCH[2]}"
|
|
129
|
+
else
|
|
130
|
+
break
|
|
131
|
+
fi
|
|
132
|
+
done
|
|
133
|
+
|
|
134
|
+
# Detect: gh pr create
|
|
135
|
+
if [[ "$clean_command" =~ ^gh[[:space:]]+pr[[:space:]]+create ]]; then
|
|
136
|
+
sanitized_output=$(printf '%s' "$output" | sed -E $'s/\x1b\[[0-9;]*[A-Za-z]//g')
|
|
137
|
+
# Extract PR URL from output
|
|
138
|
+
pr_url=""
|
|
139
|
+
# GitHub PR URLs are whitespace-delimited in gh output after ANSI stripping.
|
|
140
|
+
if [[ "$sanitized_output" =~ (https://github[.]com/[^[:space:]]+/[^[:space:]]+/pull/[0-9]+) ]]; then
|
|
141
|
+
pr_url="\${BASH_REMATCH[1]}"
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
if [[ -n "$pr_url" ]]; then
|
|
145
|
+
update_metadata_key "pr" "$pr_url"
|
|
146
|
+
update_metadata_key "status" "pr_open"
|
|
147
|
+
echo '{"systemMessage": "Updated metadata: PR created at '"$pr_url"'"}'
|
|
148
|
+
exit 0
|
|
149
|
+
fi
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
# Detect: git checkout -b <branch> or git switch -c <branch>
|
|
153
|
+
if [[ "$clean_command" =~ ^git[[:space:]]+checkout[[:space:]]+-b[[:space:]]+([^[:space:]]+) ]] || \\
|
|
154
|
+
[[ "$clean_command" =~ ^git[[:space:]]+switch[[:space:]]+-c[[:space:]]+([^[:space:]]+) ]]; then
|
|
155
|
+
branch="\${BASH_REMATCH[1]}"
|
|
156
|
+
|
|
157
|
+
if [[ -n "$branch" ]]; then
|
|
158
|
+
update_metadata_key "branch" "$branch"
|
|
159
|
+
echo '{"systemMessage": "Updated metadata: branch = '"$branch"'"}'
|
|
160
|
+
exit 0
|
|
161
|
+
fi
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
# Detect: git checkout <branch> (without -b) or git switch <branch> (without -c)
|
|
165
|
+
# Only update if the branch name looks like a feature branch (contains / or -)
|
|
166
|
+
if [[ "$clean_command" =~ ^git[[:space:]]+checkout[[:space:]]+([^[:space:]-]+[/-][^[:space:]]+) ]] || \\
|
|
167
|
+
[[ "$clean_command" =~ ^git[[:space:]]+switch[[:space:]]+([^[:space:]-]+[/-][^[:space:]]+) ]]; then
|
|
168
|
+
branch="\${BASH_REMATCH[1]}"
|
|
169
|
+
|
|
170
|
+
# Avoid updating for checkout of commits/tags
|
|
171
|
+
if [[ -n "$branch" && "$branch" != "HEAD" ]]; then
|
|
172
|
+
update_metadata_key "branch" "$branch"
|
|
173
|
+
echo '{"systemMessage": "Updated metadata: branch = '"$branch"'"}'
|
|
174
|
+
exit 0
|
|
175
|
+
fi
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
# Detect: gh pr merge
|
|
179
|
+
if [[ "$clean_command" =~ ^gh[[:space:]]+pr[[:space:]]+merge ]]; then
|
|
180
|
+
update_metadata_key "status" "merged"
|
|
181
|
+
echo '{"systemMessage": "Updated metadata: status = merged"}'
|
|
182
|
+
exit 0
|
|
183
|
+
fi
|
|
184
|
+
|
|
185
|
+
# No matching command, exit silently
|
|
186
|
+
echo '{}'
|
|
187
|
+
exit 0
|
|
188
|
+
`,H=`#!/usr/bin/env node
|
|
189
|
+
// Metadata Updater Hook for Agent Orchestrator (Node.js — Windows)
|
|
190
|
+
//
|
|
191
|
+
// This PostToolUse hook automatically updates session metadata when:
|
|
192
|
+
// - gh pr create: extracts PR URL and writes to metadata
|
|
193
|
+
// - git checkout -b / git switch -c: extracts branch name and writes to metadata
|
|
194
|
+
// - gh pr merge: updates status to "merged"
|
|
195
|
+
|
|
196
|
+
const { readFileSync, writeFileSync, renameSync, existsSync, realpathSync } = require("node:fs");
|
|
197
|
+
const { join, sep, resolve: resolvePath } = require("node:path");
|
|
198
|
+
const os = require("node:os");
|
|
199
|
+
|
|
200
|
+
const AO_DATA_DIR = process.env.AO_DATA_DIR || join(process.env.HOME || process.env.USERPROFILE || "", ".ao-sessions");
|
|
201
|
+
const AO_SESSION = process.env.AO_SESSION || "";
|
|
202
|
+
|
|
203
|
+
// Read hook input from stdin (fd 0 is cross-platform, no /dev/stdin needed)
|
|
204
|
+
let inputRaw = "";
|
|
205
|
+
try {
|
|
206
|
+
inputRaw = readFileSync(0, "utf-8");
|
|
207
|
+
} catch {
|
|
208
|
+
inputRaw = "";
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let input;
|
|
212
|
+
try {
|
|
213
|
+
input = JSON.parse(inputRaw || "{}");
|
|
214
|
+
} catch {
|
|
215
|
+
process.stdout.write("{}\\n");
|
|
216
|
+
process.exit(0);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const toolName = input.tool_name || "";
|
|
220
|
+
const command = (input.tool_input && input.tool_input.command) || "";
|
|
221
|
+
const output = input.tool_response || "";
|
|
222
|
+
const exitCode = typeof input.exit_code === "number" ? input.exit_code : 0;
|
|
223
|
+
|
|
224
|
+
// Only process successful commands
|
|
225
|
+
if (exitCode !== 0) {
|
|
226
|
+
process.stdout.write("{}\\n");
|
|
227
|
+
process.exit(0);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Only process Bash tool calls
|
|
231
|
+
if (toolName !== "Bash") {
|
|
232
|
+
process.stdout.write("{}\\n");
|
|
233
|
+
process.exit(0);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Validate AO_SESSION is set
|
|
237
|
+
if (!AO_SESSION) {
|
|
238
|
+
process.stdout.write(JSON.stringify({ systemMessage: "AO_SESSION environment variable not set, skipping metadata update" }) + "\\n");
|
|
239
|
+
process.exit(0);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Validate AO_SESSION contains no path traversal components
|
|
243
|
+
if (AO_SESSION.includes("/") || AO_SESSION.includes("\\\\") || AO_SESSION.includes("..")) {
|
|
244
|
+
process.stdout.write(JSON.stringify({ systemMessage: "AO_SESSION contains invalid path characters, skipping metadata update" }) + "\\n");
|
|
245
|
+
process.exit(0);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Validate AO_DATA_DIR is within an allowed base directory (mirrors ao-metadata-helper.sh)
|
|
249
|
+
const home = os.homedir();
|
|
250
|
+
let resolvedAoDir;
|
|
251
|
+
try { resolvedAoDir = realpathSync(AO_DATA_DIR); } catch { resolvedAoDir = resolvePath(AO_DATA_DIR); }
|
|
252
|
+
const allowedBases = [join(home, ".ao"), join(home, ".agent-orchestrator"), os.tmpdir()];
|
|
253
|
+
if (!allowedBases.some((a) => resolvedAoDir === a || resolvedAoDir.startsWith(a + sep))) {
|
|
254
|
+
process.stdout.write(JSON.stringify({ systemMessage: "AO_DATA_DIR is outside allowed directories, skipping metadata update" }) + "\\n");
|
|
255
|
+
process.exit(0);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const metadataFile = join(AO_DATA_DIR, AO_SESSION);
|
|
259
|
+
|
|
260
|
+
if (!existsSync(metadataFile)) {
|
|
261
|
+
process.stdout.write(JSON.stringify({ systemMessage: "Metadata file not found: " + metadataFile }) + "\\n");
|
|
262
|
+
process.exit(0);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Update or append a key=value line in the metadata file (atomic via temp file).
|
|
267
|
+
*/
|
|
268
|
+
function updateMetadataKey(key, value) {
|
|
269
|
+
const lines = readFileSync(metadataFile, "utf-8").split("\\n");
|
|
270
|
+
let found = false;
|
|
271
|
+
const updated = lines.map((line) => {
|
|
272
|
+
if (line.startsWith(key + "=")) {
|
|
273
|
+
found = true;
|
|
274
|
+
return key + "=" + value;
|
|
275
|
+
}
|
|
276
|
+
return line;
|
|
277
|
+
});
|
|
278
|
+
if (!found) {
|
|
279
|
+
// Insert before the trailing empty line (if any) so the file ends cleanly
|
|
280
|
+
updated.push(key + "=" + value);
|
|
281
|
+
}
|
|
282
|
+
const tmpFile = metadataFile + ".tmp." + process.pid;
|
|
283
|
+
writeFileSync(tmpFile, updated.join("\\n"), "utf-8");
|
|
284
|
+
renameSync(tmpFile, metadataFile);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Strip leading cd ... && / cd ... ; prefixes (agents frequently cd into a
|
|
288
|
+
// worktree before running the real command)
|
|
289
|
+
let cleanCommand = command;
|
|
290
|
+
const cdPrefixRe = /^\\s*cd\\s+\\S.*?\\s+(?:&&|;)\\s+(.*)/;
|
|
291
|
+
let m;
|
|
292
|
+
while ((m = cdPrefixRe.exec(cleanCommand)) !== null && /^\\s*cd\\s/.test(cleanCommand)) {
|
|
293
|
+
cleanCommand = m[1];
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Detect: gh pr create
|
|
297
|
+
if (/^gh\\s+pr\\s+create/.test(cleanCommand)) {
|
|
298
|
+
const prMatch = output.match(/https:\\/\\/github[.]com\\/[^/]+\\/[^/]+\\/pull\\/\\d+/);
|
|
299
|
+
if (prMatch) {
|
|
300
|
+
const prUrl = prMatch[0];
|
|
301
|
+
updateMetadataKey("pr", prUrl);
|
|
302
|
+
updateMetadataKey("status", "pr_open");
|
|
303
|
+
process.stdout.write(JSON.stringify({ systemMessage: "Updated metadata: PR created at " + prUrl }) + "\\n");
|
|
304
|
+
process.exit(0);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Detect: git checkout -b <branch> or git switch -c <branch>
|
|
309
|
+
const checkoutNewBranch = cleanCommand.match(/^git\\s+checkout\\s+-b\\s+(\\S+)/) ||
|
|
310
|
+
cleanCommand.match(/^git\\s+switch\\s+-c\\s+(\\S+)/);
|
|
311
|
+
if (checkoutNewBranch) {
|
|
312
|
+
const branch = checkoutNewBranch[1];
|
|
313
|
+
if (branch) {
|
|
314
|
+
updateMetadataKey("branch", branch);
|
|
315
|
+
process.stdout.write(JSON.stringify({ systemMessage: "Updated metadata: branch = " + branch }) + "\\n");
|
|
316
|
+
process.exit(0);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Detect: git checkout <branch> or git switch <branch> (without -b/-c)
|
|
321
|
+
// Only update if branch looks like a feature branch (contains / or -)
|
|
322
|
+
const checkoutBranch = cleanCommand.match(/^git\\s+checkout\\s+([^\\s-]+[/-][^\\s]+)/) ||
|
|
323
|
+
cleanCommand.match(/^git\\s+switch\\s+([^\\s-]+[/-][^\\s]+)/);
|
|
324
|
+
if (checkoutBranch) {
|
|
325
|
+
const branch = checkoutBranch[1];
|
|
326
|
+
if (branch && branch !== "HEAD") {
|
|
327
|
+
updateMetadataKey("branch", branch);
|
|
328
|
+
process.stdout.write(JSON.stringify({ systemMessage: "Updated metadata: branch = " + branch }) + "\\n");
|
|
329
|
+
process.exit(0);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Detect: gh pr merge
|
|
334
|
+
if (/^gh\\s+pr\\s+merge/.test(cleanCommand)) {
|
|
335
|
+
updateMetadataKey("status", "merged");
|
|
336
|
+
process.stdout.write(JSON.stringify({ systemMessage: "Updated metadata: status = merged" }) + "\\n");
|
|
337
|
+
process.exit(0);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// No matching command
|
|
341
|
+
process.stdout.write("{}\\n");
|
|
342
|
+
process.exit(0);
|
|
343
|
+
`;function I(a){return a.replace(/\\/g,"/").replace(/[^a-zA-Z0-9-]/g,"-")}async function J(a){let b;try{b=await (0,E.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,E.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 K(a,b=131072){let c,d;try{let{size:e=0}=await (0,E.stat)(a);if(d=Math.max(0,e-b),0===d)c=await (0,E.readFile)(a,"utf-8");else{let b=await (0,E.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 L=null;async function M(){if((0,d.uFH)())return"";let a=Date.now();if(L&&a-L.timestamp<5e3)return L.promise?L.promise:L.output;let b=F("ps",["-eo","pid,tty,args"],{timeout:5e3}).then(({stdout:a})=>(L?.promise===b&&(L={output:a,timestamp:Date.now()}),a));L={output:"",timestamp:a,promise:b};try{return await b}catch{return L?.promise===b&&(L=null),""}}async function N(a){try{if("tmux"===a.runtimeName&&a.id){let{stdout:b}=await F("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 M();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 O(a){let b,c=(0,k.join)(a,".claude"),e=(0,k.join)(c,"settings.json");try{await (0,E.mkdir)(c,{recursive:!0})}catch{}if((0,d.uFH)()){let a=(0,k.join)(c,"metadata-updater.cjs");await (0,E.writeFile)(a,H,"utf-8"),b="node .claude/metadata-updater.cjs"}else{let a=(0,k.join)(c,"metadata-updater.sh");await (0,E.writeFile)(a,G,"utf-8"),await (0,E.chmod)(a,493),b=".claude/metadata-updater.sh"}let f={};if((0,i.existsSync)(e))try{let a=await (0,E.readFile)(e,"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")||d.command.includes("metadata-updater.js")||d.command.includes("metadata-updater.cjs"))){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,E.writeFile)(e,JSON.stringify(f,null,2)+"\n","utf-8")}let P={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",getLaunchCommand(a){let b=["claude"],c=(0,d.DD3)(a.permissions);if(("permissionless"===c||"auto-edit"===c)&&b.push("--dangerously-skip-permissions"),a.model&&b.push("--model",(0,d.kct)(a.model)),a.systemPromptFile)if((0,d.uFH)()){let c=(0,i.readFileSync)(a.systemPromptFile,"utf-8");b.push("--append-system-prompt",(0,d.kct)(c))}else b.push("--append-system-prompt",`"$(cat ${(0,d.kct)(a.systemPromptFile)})"`);else a.systemPrompt&&b.push("--append-system-prompt",(0,d.kct)(a.systemPrompt));return a.prompt&&b.push("--",(0,d.kct)(a.prompt)),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 N(a),async getActivityState(a,b){let c=b??d.PES,e=new Date;if(!a.runtimeHandle||!await this.isProcessRunning(a.runtimeHandle))return{state:"exited",timestamp:e};if(!a.workspacePath)return null;let f=I(a.workspacePath),g=(0,k.join)((0,j.homedir)(),".claude","projects",f),h=await J(g);if(!h)return{state:"idle",timestamp:a.createdAt};let i=await (0,d.XIc)(h);if(!i)return null;if(a.createdAt&&i.modifiedAt<a.createdAt)return{state:"idle",timestamp:a.createdAt};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=I(a.workspacePath),c=(0,k.join)((0,j.homedir)(),".claude","projects",b),d=await J(c);if(!d)return null;let e=await K(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,metadata:{claudeSessionUuid:f},cost:function(a){let b=0,c=0,d=0,e=0,f=0;for(let g of a)"number"==typeof g.costUSD?f+=g.costUSD:"number"==typeof g.estimatedCostUsd&&(f+=g.estimatedCostUsd),g.usage?(b+=g.usage.input_tokens??0,d+=g.usage.cache_read_input_tokens??0,e+=g.usage.cache_creation_input_tokens??0,c+=g.usage.output_tokens??0):("number"==typeof g.inputTokens&&(b+=g.inputTokens),"number"==typeof g.outputTokens&&(c+=g.outputTokens));if(0!==b||0!==c||0!==f||0!==d||0!==e)return 0===f&&(f=b/1e6*3+c/1e6*15+d/1e6*.3+e/1e6*3.75),{inputTokens:b+d+e,outputTokens:c,estimatedCostUsd:f}}(e)}},async getRestoreCommand(a,b){let c=a.metadata?.claudeSessionUuid?.trim();if(!c){if(!a.workspacePath)return null;let b=I(a.workspacePath),d=(0,k.join)((0,j.homedir)(),".claude","projects",b),e=await J(d);if(!e)return null;c=(0,k.basename)(e,".jsonl")}if(!c)return null;let e=["claude","--resume",(0,d.kct)(c)],f=(0,d.DD3)(b.agentConfig?.permissions);return("permissionless"===f||"auto-edit"===f)&&e.push("--dangerously-skip-permissions"),b.agentConfig?.model&&e.push("--model",(0,d.kct)(b.agentConfig.model)),e.join(" ")},async setupWorkspaceHooks(a,b){await O(a)},async postLaunchSetup(a){}}},detect:function(){try{return(0,e.execFileSync)("claude",["--version"],{stdio:"ignore",shell:(0,d.uFH)(),windowsHide:!0}),!0}catch{return!1}}};var Q=c(46193),R=c(80481);c(78474).EventEmitter;let S=(0,f.promisify)(e.execFile),T=(0,k.join)((0,j.homedir)(),".codex","sessions");function U(a){return a.payload??a}async function V(a,b=0){let c;if(b>4)return[];try{c=await (0,E.readdir)(a)}catch{return[]}let d=[];for(let e of c){let c=(0,k.join)(a,e);if(e.endsWith(".jsonl"))d.push(c);else try{if((await (0,E.lstat)(c)).isDirectory()){let a=await V(c,b+1);d.push(...a)}}catch{}}return d}async function W(a,b){let c=await (0,E.open)(a,"r"),d=[],e="",f=new Q.StringDecoder("utf8");try{for(;d.length<b;){let a=Buffer.allocUnsafe(8192),{bytesRead:g}=await c.read(a,0,a.length,null);if(0===g){let a=(e+=f.end()).trim();a&&d.push(a);break}let h=(e+=f.write(a.subarray(0,g))).indexOf("\n");for(;-1!==h&&d.length<b;){let a=e.slice(0,h).trim();a&&d.push(a),h=(e=e.slice(h+1)).indexOf("\n")}}}finally{await c.close()}return d}function X(a){return a.replace(/\\/g,"/").replace(/^([a-zA-Z]):/,(a,b)=>b.toLowerCase()+":")}async function Y(a,b){let c=X(b);try{for(let b of(await W(a,10)))try{let a=JSON.parse(b);if("object"==typeof a&&null!==a&&!Array.isArray(a)){let b=U(a);if("session_meta"===a.type&&"string"==typeof b.cwd&&X(b.cwd)===c)return!0}}catch{}}catch{}return!1}async function Z(a){let b=await V(T);if(0===b.length)return null;let c=null;for(let d of b)if(await Y(d,a))try{let a=await (0,E.stat)(d);(!c||a.mtimeMs>c.mtime)&&(c={path:d,mtime:a.mtimeMs})}catch{}return c?.path??null}async function $(a){try{let b={model:null,threadId:null,inputTokens:0,outputTokens:0,cachedTokens:0,reasoningTokens:0};for await(let c of(0,R.createInterface)({input:(0,i.createReadStream)(a,{encoding:"utf-8"}),crlfDelay:1/0})){let a=c.trim();if(a)try{let c=JSON.parse(a);if("object"!=typeof c||null===c||Array.isArray(c))continue;let d=U(c);"session_meta"===c.type&&("string"==typeof d.id&&d.id?b.threadId=d.id:"string"==typeof d.threadId&&d.threadId&&(b.threadId=d.threadId)),!b.threadId&&("string"==typeof d.threadId&&d.threadId?b.threadId=d.threadId:"string"==typeof c.threadId&&c.threadId&&(b.threadId=c.threadId)),"turn_context"===c.type&&"string"==typeof d.model&&d.model?b.model=d.model:!b.model&&"string"==typeof d.model&&d.model&&(b.model=d.model);let e=d.info?.total_token_usage;if("number"==typeof e?.input_tokens){b.inputTokens=e.input_tokens,b.outputTokens=e.output_tokens??0;continue}let f=d.info?.last_token_usage;if("number"==typeof f?.input_tokens){b.inputTokens+=f.input_tokens,b.outputTokens+=f.output_tokens??0;continue}if("number"==typeof d.input_tokens){b.inputTokens+=d.input_tokens,b.outputTokens+=d.output_tokens??0;continue}"event_msg"===c.type&&c.msg?.type==="token_count"&&(b.inputTokens+=c.msg.input_tokens??0,b.outputTokens+=c.msg.output_tokens??0,b.cachedTokens+=c.msg.cached_tokens??0,b.reasoningTokens+=c.msg.reasoning_tokens??0)}catch{}}return b}catch{return null}}async function _(){if((0,d.uFH)())return aa();try{let{stdout:a}=await S("which",["codex"],{timeout:1e4}),b=a.trim();if(b)return b}catch{}let a=(0,j.homedir)();for(let b of["/usr/local/bin/codex","/opt/homebrew/bin/codex",(0,k.join)(a,".cargo","bin","codex"),(0,k.join)(a,".npm","bin","codex")])try{return await (0,E.stat)(b),b}catch{}return"codex"}async function aa(){for(let a of["codex.cmd","codex.exe"])try{let{stdout:b}=await S("where.exe",[a],{timeout:1e4,windowsHide:!0}),c=b.split(/\r?\n/).find(a=>a.trim().length>0);if(c)return c.trim()}catch{}let a=process.env.APPDATA,b=(0,j.homedir)();for(let c of[a?(0,k.join)(a,"npm","codex.cmd"):null,a?(0,k.join)(a,"npm","codex.exe"):null,(0,k.join)(b,".cargo","bin","codex.exe")].filter(a=>null!==a))try{return await (0,E.stat)(c),c}catch{}return"codex"}function ab(a,b,c=!0){let e=(0,d.DD3)(b);"permissionless"===e?c?a.push("--dangerously-bypass-approvals-and-sandbox"):a.push("--ask-for-approval","never"):"auto-edit"===e?a.push("--ask-for-approval","never"):"suggest"===e&&a.push("--ask-for-approval","untrusted")}function ac(a,b){b&&(a.push("--model",(0,d.kct)(b)),/^o[34]/i.test(b)&&a.push("-c","model_reasoning_effort=high"))}function ad(a){a.push("-c","check_for_update_on_startup=false")}let ae=new Map;async function af(a){let b=ae.get(a);if(b&&Date.now()<b.expiry)return b.path;let c=await Z(a);return ae.set(a,{path:c,expiry:Date.now()+3e4}),c}function ag(a){let b=a.join(" ");return(0,d.uFH)()?`& ${b}`:b}let ah={manifest:{name:"codex",slot:"agent",description:"Agent plugin: OpenAI Codex CLI",version:"0.1.1",displayName:"OpenAI Codex"},create:function(){let a,b;return a=null,b=null,{name:"codex",processName:"codex",getLaunchCommand(b){let c=a??"codex",e=[(0,d.kct)(c)];return ad(e),ab(e,b.permissions),ac(e,b.model),b.systemPromptFile?e.push("-c",`model_instructions_file=${(0,d.kct)(b.systemPromptFile)}`):b.systemPrompt&&e.push("-c",`developer_instructions=${(0,d.kct)(b.systemPrompt)}`),b.prompt&&e.push("--",(0,d.kct)(b.prompt)),ag(e)},getEnvironment(a){let b={};return b.AO_SESSION_ID=a.sessionId,a.issueId&&(b.AO_ISSUE_ID=a.issueId),b.CODEX_DISABLE_UPDATE_CHECK="1",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/approval required/i.test(d)||/\(y\)es.*\(n\)o/i.test(d)?"waiting_input":"active"},async getActivityState(a,b){let c=b??d.PES,e=new Date;if(!a.runtimeHandle||!await this.isProcessRunning(a.runtimeHandle))return{state:"exited",timestamp:e};if(!a.workspacePath)return null;let f=await af(a.workspacePath);if(f){let a=await (0,d.XIc)(f);if(a){let b=Date.now()-a.modifiedAt.getTime(),e=a.modifiedAt,f=a.payloadType??a.lastType,g=Math.min(d.V1$,c);switch(f){case"approval_request":case"exec_approval_request":case"apply_patch_approval_request":return{state:"waiting_input",timestamp:e};case"error":case"stream_error":return{state:"blocked",timestamp:e};case"task_started":case"agent_reasoning":case"response_item":case"turn_context":case"user_input":case"tool_call":case"exec_command":case"exec_command_begin":case"exec_command_end":default:if(b<=g)return{state:"active",timestamp:e};return{state:b>c?"idle":"ready",timestamp:e};case"task_complete":case"turn_aborted":case"agent_message":case"assistant_message":case"session_meta":case"event_msg":case"compacted":case"token_count":return{state:b>c?"idle":"ready",timestamp:e}}}}let g=await (0,d.Ahw)(a.workspacePath),h=(0,d.Bmx)(g);if(h)return h;let i=Math.min(d.V1$,c),j=(0,d.Vo2)(g,i,c);if(j)return j;if(f)try{let a=await (0,E.stat)(f),b=Date.now()-a.mtimeMs,e=Math.min(d.V1$,c);if(b<=e)return{state:"active",timestamp:a.mtime};if(b<=c)return{state:"ready",timestamp:a.mtime};return{state:"idle",timestamp:a.mtime}}catch{}return null},async recordActivity(a,b){a.workspacePath&&await (0,d.JyZ)(a.workspacePath,b,a=>this.detectActivity(a))},async isProcessRunning(a){try{if("tmux"===a.runtimeName&&a.id){if((0,d.uFH)())return!1;let{stdout:b}=await S("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:e}=await S("ps",["-eo","pid,tty,args"],{timeout:3e4}),f=new Set(c.map(a=>a.replace(/^\/dev\//,""))),g=/(?:^|\/)codex(?:\s|$)/;for(let a of e.split("\n")){let b=a.trimStart().split(/\s+/);if(b.length<3||!f.has(b[1]??""))continue;let c=b.slice(2).join(" ");if(g.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;if(!a.workspacePath)return null;let c=await af(a.workspacePath);if(!c)return null;let d=await $(c);if(!d)return null;let e=(0,k.basename)(c,".jsonl"),f=d.inputTokens+d.cachedTokens;if(f>0||d.outputTokens>0||d.reasoningTokens>0){let a=d.inputTokens/1e6*2.5+d.cachedTokens/1e6*.625+(d.outputTokens+d.reasoningTokens)/1e6*10;b={inputTokens:f,outputTokens:d.outputTokens,estimatedCostUsd:a}}return{summary:d.model?`Codex session (${d.model})`:null,summaryIsFallback:!0,agentSessionId:e,metadata:d.threadId?{codexThreadId:d.threadId,...d.model?{codexModel:d.model}:{}}:void 0,cost:b}},async getRestoreCommand(b,c){let e=b.metadata?.codexThreadId?.trim(),f=b.metadata?.codexModel?.trim()||null;if(!e){if(!b.workspacePath)return null;let a=await af(b.workspacePath);if(!a)return null;let c=await $(a);if(!c?.threadId)return null;e=c.threadId,f=c.model}let g=a??"codex",h=[(0,d.kct)(g),"resume"];return ad(h),ab(h,c.agentConfig?.permissions),ac(h,c.agentConfig?.model??f??void 0),h.push((0,d.kct)(e)),ag(h)},async setupWorkspaceHooks(a,b){},async postLaunchSetup(c){if(!a){b||(b=_());try{a=await b}finally{b=null}}}}},detect:function(){try{return(0,e.execFileSync)("codex",["--version"],{stdio:"ignore",shell:(0,d.uFH)(),windowsHide:!0}),!0}catch{return!1}}},ai=(0,f.promisify)(e.execFile);async function aj(a){try{let b=(0,k.join)(a,".cursor"),c=(0,k.join)(b,"chat.md");if((await (0,E.lstat)(b)).isSymbolicLink())return null;try{if((await (0,E.lstat)(c)).isSymbolicLink())return null;return(await (0,E.stat)(c)).mtime}catch{return await (0,E.access)(b,i.constants.R_OK),(await (0,E.stat)(b)).mtime}}catch{return null}}async function ak(a){try{let b=(0,k.join)(a,".cursor"),c=(0,k.join)(b,"chat.md");try{if((await (0,E.lstat)(b)).isSymbolicLink()||(await (0,E.lstat)(c)).isSymbolicLink())return null;let d=(0,k.resolve)(c),e=(0,k.resolve)(a);if(!d.startsWith(e))return null;for(let a of(await (0,E.readFile)(c,"utf-8")).split("\n")){let b=a.trim();if(b.length>0&&!b.startsWith("#"))return b.length>120?b.substring(0,120)+"...":b}}catch{}}catch{}return null}let al={manifest:{name:"cursor",slot:"agent",description:"Agent plugin: Cursor Agent CLI",version:"0.1.0",displayName:"Cursor"},create:function(){return{name:"cursor",processName:"agent",getLaunchCommand(a){let b=["agent"],c=(0,d.DD3)(a.permissions);if(("permissionless"===c||"auto-edit"===c)&&b.push("--force","--sandbox","disabled","--approve-mcps"),a.model&&b.push("--model",(0,d.kct)(a.model)),a.systemPromptFile)try{if(!(0,i.lstatSync)(a.systemPromptFile).isSymbolicLink())return a.prompt?b.push("--",`"$(cat ${(0,d.kct)(a.systemPromptFile)}; printf '\\n\\n'; printf %s ${(0,d.kct)(a.prompt)})"`):b.push("--",`"$(cat ${(0,d.kct)(a.systemPromptFile)})"`),b.join(" ")}catch{}let e="";return a.systemPrompt&&(e=a.systemPrompt.trim()),a.prompt&&(e=e?e+"\n\n"+a.prompt:a.prompt),e&&b.push("--",(0,d.kct)(e)),b.join(" ")},getEnvironment(a){let b={};return b.AO_SESSION_ID=a.sessionId,a.issueId&&(b.AO_ISSUE_ID=a.issueId),b},detectActivity(a){if(!a.trim())return"idle";let b=a.trim().split("\n"),c=b[b.length-1]?.trim()??"",d=b.slice(-5).join("\n");return/\(Y\)es.*\(N\)o/i.test(d)||/Approve.*changes\?/i.test(d)||/Continue\?/i.test(d)||/\[Yes\].*\[No\]/i.test(d)||/proceed\?/i.test(d)||/Press Enter to continue/i.test(d)?"waiting_input":/^[>$#]\s*$/.test(c)||/^agent>\s*$/.test(c)||/^\[agent\]\s*$/.test(c)?"idle":"active"},async getActivityState(a,b){let c=b??d.PES,e=new Date;if(!a.runtimeHandle||!await this.isProcessRunning(a.runtimeHandle))return{state:"exited",timestamp:e};if(!a.workspacePath)return null;let f=await (0,d.Ahw)(a.workspacePath),g=(0,d.Bmx)(f);if(g)return g;if(await (0,d.Gfo)(a.workspacePath))return{state:"active"};let h=await aj(a.workspacePath);if(h){let a=Date.now()-h.getTime();return a<=Math.min(d.V1$,c)?{state:"active",timestamp:h}:a<=c?{state:"ready",timestamp:h}:{state:"idle",timestamp:h}}let i=Math.min(d.V1$,c),j=(0,d.Vo2)(f,i,c);return j||null},async recordActivity(a,b){a.workspacePath&&await (0,d.JyZ)(a.workspacePath,b,a=>this.detectActivity(a))},async isProcessRunning(a){try{if("tmux"===a.runtimeName&&a.id){let{stdout:b}=await ai("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 ai("ps",["-eo","pid,tty,args"],{timeout:3e4}),e=new Set(c.map(a=>a.replace(/^\/dev\//,""))),f=/(?:^|\/)\.?agent\b(?:\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){if(!a.workspacePath)return null;let b=await ak(a.workspacePath);return b?{summary:b,summaryIsFallback:!0,agentSessionId:null}:null},getRestoreCommand:async(a,b)=>null,async setupWorkspaceHooks(a,b){},async postLaunchSetup(a){}}},detect:function(){try{let a=(0,e.execFileSync)("agent",["--help"],{encoding:"utf-8",stdio:["ignore","pipe","ignore"],shell:(0,d.uFH)(),windowsHide:!0,timeout:5e3}),b=a.includes("Cursor Agent"),c=a.includes("--approve-mcps")&&a.includes("--sandbox");return b||c}catch{return!1}}};function am(){let a=process.env.KIMI_SHARE_DIR;return a&&a.trim().length>0?a:(0,k.join)((0,j.homedir)(),".kimi")}let an=".ao/kimi-baseline.json",ao=".ao/kimi-session-id.json";async function ap(){try{let a=await (0,E.readFile)((0,k.join)(am(),"kimi.json"),"utf-8"),b=JSON.parse(a);if(!b||"object"!=typeof b||Array.isArray(b))return null;return b}catch{return null}}async function aq(a){let b=await ap();if(!b?.work_dirs||!Array.isArray(b.work_dirs))return null;let c=await as(a);for(let a of b.work_dirs)if(a&&"string"==typeof a.path&&await as(a.path)===c)return a;return null}function ar(a){return(0,h.createHash)("md5").update(a).digest("hex")}async function as(a){try{return await (0,E.stat)(a),await (0,E.realpath)(a)}catch{return a}}async function at(a){let b,c,d=(0,k.join)(am(),"sessions");try{b=await (0,E.realpath)(d)}catch{return!1}try{c=await (0,E.realpath)(a)}catch{return!1}let e=b.endsWith(k.sep)?b:b+k.sep;return c===b||c.startsWith(e)}async function au(a){try{return(await (0,E.lstat)(a)).isFile()}catch{return!1}}async function av(a){let b=await Promise.all(["context.jsonl","wire.jsonl"].map(async b=>{try{let c=await (0,E.lstat)((0,k.join)(a,b));return c.isFile()?c:null}catch{return null}})),c=null;for(let a of b)a&&(!c||a.mtimeMs>c.getTime())&&(c=a.mtime);return c}async function aw(a){try{let b=await (0,E.readFile)((0,k.join)(a,an),"utf-8"),c=JSON.parse(b);if(!Array.isArray(c.preExistingUuids))return null;return new Set(c.preExistingUuids)}catch{return null}}async function ax(a){let b=(0,k.join)(a,an);try{await (0,E.stat)(b);return}catch{}let c=await as(a),d=(0,k.join)(am(),"sessions",ar(c)),e=[];try{e=await (0,E.readdir)(d)}catch{}let f={preExistingUuids:e,capturedAt:new Date().toISOString()};try{await (0,E.mkdir)((0,k.join)(a,".ao"),{recursive:!0}),await (0,E.writeFile)(b,JSON.stringify(f),"utf-8")}catch{}}async function ay(a){try{let b=await (0,E.readFile)((0,k.join)(a,ao),"utf-8"),c=JSON.parse(b);if("string"!=typeof c.sessionId||0===c.sessionId.length)return null;return c.sessionId}catch{return null}}async function az(a,b){let c={sessionId:b,pinnedAt:new Date().toISOString()};try{await (0,E.mkdir)((0,k.join)(a,".ao"),{recursive:!0}),await (0,E.writeFile)((0,k.join)(a,ao),JSON.stringify(c),"utf-8")}catch{}}async function aA(a){let b;if(!a.workspacePath)return null;let c=await as(a.workspacePath),d=(0,k.join)(am(),"sessions",ar(c));if(!await at(d))return null;try{b=await (0,E.readdir)(d)}catch{return null}let e=await ay(a.workspacePath),f=null;if(!e){let b=await aq(a.workspacePath);b&&"string"==typeof b.last_session_id&&b.last_session_id.length>0&&(f=b.last_session_id)}let g=await aw(a.workspacePath),h=a.createdAt.getTime()-6e4,i=null,j=null;for(let a of b){let b=(0,k.join)(d,a);if(!await at(b))continue;let c=await av(b);if(!c)continue;if(e){if(a!==e)continue;return{dir:b,sessionId:a,mtime:c}}if(g?.has(a)||c.getTime()<h)continue;if(f&&a===f){j={dir:b,sessionId:a,mtime:c};continue}let l=c.getTime();(!i||l>i.mtimeMs)&&(i={dir:b,sessionId:a,mtime:c,mtimeMs:l})}return e?null:j?(await az(a.workspacePath,j.sessionId),j):i?(await az(a.workspacePath,i.sessionId),{dir:i.dir,sessionId:i.sessionId,mtime:i.mtime}):null}let aB=new Map;async function aC(a){let b=a.workspacePath;if(!b)return null;let c=Date.now(),d=aB.get(b);if(d&&d.expiry>c)return d.match;d&&aB.delete(b);let e=await aA(a),f=e?3e4:2e3;return aB.set(b,{match:e,expiry:c+f}),aB.size>256&&function(a){for(let[b,c]of aB)c.expiry<=a&&aB.delete(b);if(aB.size<=256)return;let b=[...aB.entries()].sort((a,b)=>a[1].expiry-b[1].expiry),c=aB.size-256;for(let a=0;a<c;a++){let c=b[a];c&&aB.delete(c[0])}}(c),e}let aD=(0,f.promisify)(e.execFile);async function aE(a){let b=(0,k.join)(a,"wire.jsonl");if(!await au(b))return null;let c=null;try{let a=(0,R.createInterface)({input:(0,i.createReadStream)(b,{encoding:"utf-8"}),crlfDelay:1/0}),d=0;for await(let b of a){if((d+=b.length)>1e6)break;let a=b.trim();if(a)try{let b=JSON.parse(a);if(!b||"object"!=typeof b||Array.isArray(b))continue;let d=b.message;if(!d||"object"!=typeof d||Array.isArray(d)||"TurnBegin"!==d.type)continue;let e=d.payload;if(!e||"object"!=typeof e||Array.isArray(e))continue;let f=e.user_input;if("string"==typeof f&&f.length>0){c=f.length>120?f.slice(0,120)+"...":f;break}}catch{}}a.close()}catch{return null}return c}function aF(a,b){let c=(0,d.DD3)(b);("permissionless"===c||"auto-edit"===c)&&a.push("--yolo")}function aG(a){let b=a.join(" ");return(0,d.uFH)()?`& ${b}`:b}let aH=/kimi[-_](?:cli|code)|moonshot/i,aI={manifest:{name:"kimicode",slot:"agent",description:"Agent plugin: Kimi Code CLI (MoonshotAI)",version:"0.1.0",displayName:"Kimi Code"},create:function(){return{name:"kimicode",processName:"kimi",getLaunchCommand(a){let b=["kimi"],c=a.workspacePath??a.projectConfig.path;c&&b.push("--work-dir",(0,d.kct)(c)),aF(b,a.permissions),a.model&&b.push("--model",(0,d.kct)(a.model)),a.subagent&&b.push("--agent",(0,d.kct)(a.subagent));let e=a.prompt??"";if(a.systemPromptFile){let b=(0,i.readFileSync)(a.systemPromptFile,"utf-8");e=e?`${b}
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
${e}`:b}return e&&b.push("--prompt",(0,d.kct)(e)),aG(b)},getEnvironment(a){let b={};return b.AO_SESSION_ID=a.sessionId,a.issueId&&(b.AO_ISSUE_ID=a.issueId),b},detectActivity(a){if(!a.trim())return"idle";let b=a.trim().split("\n"),c=b[b.length-1]?.trim()??"",d=b.slice(-6).join("\n");return/\(y\)es.*\(n\)o/i.test(d)||/\[y\/n\]\s*[?:]?\s*$/im.test(d)||/^\s*approve\??\s*$/im.test(d)||/\bapproval required\b/i.test(d)||/^\s*do you want to (proceed|continue)\?\s*$/im.test(d)||/^\s*allow .+\?\s*$/im.test(d)?"waiting_input":/^\s*error:/im.test(d)||/^\s*(?:error:\s*)?failed to (connect|authenticate|load)\b/im.test(d)?"blocked":/^[>$#]\s*$/.test(c)||/^kimi[>:]?\s*$/i.test(c)?"idle":"active"},async getActivityState(a,b){let c=b??d.PES,e=Math.min(d.V1$,c),f=new Date;if(!a.runtimeHandle||!await this.isProcessRunning(a.runtimeHandle))return{state:"exited",timestamp:f};if(!a.workspacePath)return null;let g=await (0,d.Ahw)(a.workspacePath),h=(0,d.Bmx)(g);if(h)return h;let i=await aC(a);if(i){let a=Math.max(0,Date.now()-i.mtime.getTime());return a<=e?{state:"active",timestamp:i.mtime}:a<=c?{state:"ready",timestamp:i.mtime}:{state:"idle",timestamp:i.mtime}}let j=(0,d.Vo2)(g,e,c);return j||null},async recordActivity(a,b){a.workspacePath&&await (0,d.JyZ)(a.workspacePath,b,a=>this.detectActivity(a))},async isProcessRunning(a){try{if("tmux"===a.runtimeName&&a.id){if((0,d.uFH)())return!1;let{stdout:b}=await aD("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:e}=await aD("ps",["-eo","pid,tty,args"],{timeout:3e4}),f=new Set(c.map(a=>a.replace(/^\/dev\//,""))),g=/(?:^|\/)\.?kimi$/,h=/(?:^|\/)(?:uv|python3?|node)$/;for(let a of e.split("\n")){let b=a.trimStart().split(/\s+/);if(b.length<3||!f.has(b[1]??""))continue;let c=b.slice(2),d=c[0]??"";if(g.test(d))return!0;if(h.test(d))for(let a=1;a<c.length;a++){let b=c[a];if(!(!b||b.startsWith("-"))&&"run"!==b&&"tool"!==b&&"-m"!==b){if(g.test(b))return!0;break}}}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){if(!a.workspacePath)return null;let b=await aC(a);return b?{summary:await aE(b.dir),summaryIsFallback:!0,agentSessionId:b.sessionId}:null},async getRestoreCommand(a,b){if(!a.workspacePath)return null;let c=await aC(a);if(!c)return null;let e="string"==typeof b.agentConfig?.model?b.agentConfig.model:void 0,f=["kimi","--resume",(0,d.kct)(c.sessionId)];return aF(f,b.agentConfig?.permissions),e&&f.push("--model",(0,d.kct)(e)),aG(f)},async setupWorkspaceHooks(a,b){await (0,d.J06)(a)},async preLaunchSetup(a){await ax(a)},async postLaunchSetup(a){a.workspacePath&&await (0,d.J06)(a.workspacePath)}}},detect:function(){try{let a=(0,e.execFileSync)("kimi",["info"],{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:1e4,maxBuffer:65536});return aH.test(a)}catch{return!1}}},aJ=(0,f.promisify)(e.execFile);function aK(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 aL(a){try{let b=await (0,d.mKg)();if(a.metadata?.opencodeSessionId){let c=b.find(b=>b.id===a.metadata.opencodeSessionId);if(c)return c}let c=b.filter(b=>b.title===`AO:${a.id}`);if(0===c.length)return null;if(1===c.length)return c[0];return c.reduce((a,b)=>{let c=aK(a.updated)?.getTime()??0;return(aK(b.updated)?.getTime()??0)>c?b:a})}catch{return null}}let aM={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=a.projectConfig.agentConfig,f=(0,d.HrC)(e?.opencodeSessionId);f&&b.push("--session",(0,d.kct)(f));let g=a.subagent;g&&c.push("--agent",(0,d.kct)(g));let h=a.prompt?(0,d.kct)(a.prompt):void 0;if(a.model&&c.push("--model",(0,d.kct)(a.model)),!f){let b=["--format","json","--title",(0,d.kct)(`AO:${a.sessionId}`),...c],e=`
|
|
348
|
+
let buffer = '';
|
|
349
|
+
let captured = null;
|
|
350
|
+
process.stdin.on('data', chunk => {
|
|
351
|
+
buffer += chunk;
|
|
352
|
+
const lines = buffer.split('\\n');
|
|
353
|
+
buffer = lines.pop() || '';
|
|
354
|
+
for (const line of lines) {
|
|
355
|
+
if (captured) continue;
|
|
356
|
+
const trimmed = line.trim();
|
|
357
|
+
if (!trimmed) continue;
|
|
358
|
+
try {
|
|
359
|
+
const obj = JSON.parse(trimmed);
|
|
360
|
+
const sid = (typeof obj.session_id === 'string' && obj.session_id) || (typeof obj.sessionID === 'string' && obj.sessionID);
|
|
361
|
+
if (sid && /^ses_[A-Za-z0-9_-]+$/.test(sid)) {
|
|
362
|
+
captured = sid;
|
|
363
|
+
}
|
|
364
|
+
} catch {}
|
|
365
|
+
}
|
|
366
|
+
}).on('end', () => {
|
|
367
|
+
if (buffer.trim()) {
|
|
368
|
+
try {
|
|
369
|
+
const obj = JSON.parse(buffer.trim());
|
|
370
|
+
const sid = (typeof obj.session_id === 'string' && obj.session_id) || (typeof obj.sessionID === 'string' && obj.sessionID);
|
|
371
|
+
if (sid && /^ses_[A-Za-z0-9_-]+$/.test(sid)) {
|
|
372
|
+
captured = sid;
|
|
373
|
+
}
|
|
374
|
+
} catch {}
|
|
375
|
+
}
|
|
376
|
+
if (captured) {
|
|
377
|
+
process.stdout.write(captured);
|
|
378
|
+
process.exit(0);
|
|
379
|
+
}
|
|
380
|
+
process.exit(1);
|
|
381
|
+
});
|
|
382
|
+
`.trim().replace(/\n/g," ").replace(/\s+/g," "),f=`
|
|
383
|
+
let input = '';
|
|
384
|
+
process.stdin.on('data', c => input += c).on('end', () => {
|
|
385
|
+
const title = process.argv[1];
|
|
386
|
+
let rows;
|
|
387
|
+
try { rows = JSON.parse(input); } catch { process.exit(1); }
|
|
388
|
+
if (!Array.isArray(rows)) process.exit(1);
|
|
389
|
+
const isValidId = id => /^ses_[A-Za-z0-9_-]+$/.test(id);
|
|
390
|
+
const timestamp = value => {
|
|
391
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
392
|
+
if (typeof value === 'string') {
|
|
393
|
+
const parsed = Date.parse(value);
|
|
394
|
+
return Number.isNaN(parsed) ? Number.NEGATIVE_INFINITY : parsed;
|
|
395
|
+
}
|
|
396
|
+
return Number.NEGATIVE_INFINITY;
|
|
397
|
+
};
|
|
398
|
+
const matches = rows
|
|
399
|
+
.filter(r => r && r.title === title && typeof r.id === 'string' && isValidId(r.id))
|
|
400
|
+
.sort((a, b) => {
|
|
401
|
+
const ta = timestamp(a.updated);
|
|
402
|
+
const tb = timestamp(b.updated);
|
|
403
|
+
if (ta === tb) return 0;
|
|
404
|
+
return tb - ta;
|
|
405
|
+
});
|
|
406
|
+
if (matches.length === 0) process.exit(1);
|
|
407
|
+
process.stdout.write(matches[0].id);
|
|
408
|
+
});
|
|
409
|
+
`.trim().replace(/\n/g," ").replace(/\s+/g," "),g=["opencode","run",...b,"--command","true"].join(" "),i=[...h?["--prompt",h]:[],...c],j=i.length>0?` ${i.join(" ")}`:"",k=(0,d.kct)(`failed to discover OpenCode session ID for AO:${a.sessionId}`);return`SES_ID=$(${g} | node -e ${(0,d.kct)(e)}); if [ -z "$SES_ID" ]; then SES_ID=$(opencode session list --format json | node -e ${(0,d.kct)(f)} ${(0,d.kct)(`AO:${a.sessionId}`)}); fi; [ -n "$SES_ID" ] && exec opencode --session "$SES_ID"${j}; echo ${k} >&2; exit 1`}return h&&b.push("--prompt",h),b.push(...c),["opencode",...b].join(" ")},getEnvironment(a){let b={};b.AO_SESSION_ID=a.sessionId,a.issueId&&(b.AO_ISSUE_ID=a.issueId);let c=(0,d.sa4)();return b.TMPDIR=c,b.TMP=c,b.TEMP=c,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.PES,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.Ahw)(a.workspacePath);let b=(0,d.Bmx)(g);if(b)return b}let h=await aL(a);if(h){let a=aK(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.Vo2)(g,e,c);return i||null},async recordActivity(a,b){a.workspacePath&&await (0,d.JyZ)(a.workspacePath,b,a=>this.detectActivity(a))},async isProcessRunning(a){try{if("tmux"===a.runtimeName&&a.id){if((0,d.uFH)())return!1;let{stdout:b}=await aJ("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:e}=await aJ("ps",["-eo","pid,tty,args"],{timeout:3e4}),f=new Set(c.map(a=>a.replace(/^\/dev\//,""))),g=/(?:^|\/)opencode(?:\s|$)/;for(let a of e.split("\n")){let b=a.trimStart().split(/\s+/);if(b.length<3||!f.has(b[1]??""))continue;let c=b.slice(2).join(" ");if(g.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 aL(a);return b?{summary:b.title??null,summaryIsFallback:!0,agentSessionId:b.id}:null},async getRestoreCommand(a,b){let c=(0,d.HrC)(a.metadata?.opencodeSessionId)??(await aL(a))?.id??null;if(!c)return null;let e=["opencode","--session",(0,d.kct)(c)],f=b.agentConfig;return f?.model&&e.push("--model",(0,d.kct)(f.model)),e.join(" ")},async setupWorkspaceHooks(a,b){},async postLaunchSetup(a){}}},detect:function(){try{return(0,e.execFileSync)("opencode",["version"],{stdio:"ignore",shell:(0,d.uFH)(),windowsHide:!0,env:(0,d.RxI)()}),!0}catch{return!1}}},aN=(0,f.promisify)(e.execFile);async function aO(a,...b){let{stdout:c}=await aN("git",b,{cwd:a,windowsHide:!0,timeout:3e4});return c.trimEnd()}function aP(a){return a.replace(/\\/g,"/").replace(/^([a-zA-Z]):/,(a,b)=>b.toLowerCase()+":")}async function aQ(a){let b;if(!(0,d.uFH)())return void(0,i.rmSync)(a,{recursive:!0,force:!0});let c=[0,100,250,500,1e3,2e3];for(let d of c){d>0&&await new Promise(a=>setTimeout(a,d));try{if((0,i.rmSync)(a,{recursive:!0,force:!0}),!(0,i.existsSync)(a))return}catch(a){b=a}}if((0,i.existsSync)(a))throw Error(`Failed to remove "${a}" after ${c.length} attempts (Windows file-handle drain). Last error: ${b instanceof Error?b.message:String(b)}`)}async function aR(a){try{return await aO(a,"remote","get-url","origin"),!0}catch{return!1}}async function aS(a,b){try{return await aO(a,"rev-parse","--verify","--quiet",b),!0}catch{return!1}}async function aT(a,b,c){if(c?.hasOrigin??await aR(a)){if(c?.branch){let b=`origin/${c.branch}`;if(await aS(a,b))return b}let d=`origin/${b}`;if(await aS(a,d))return d}let d=`refs/heads/${b}`;if(await aS(a,d))return d;throw Error(`Unable to resolve base ref for default branch "${b}"`)}async function aU(a,b){try{let c=await aO(a,"worktree","list","--porcelain"),d=aP((0,k.resolve)(b));return c.split("\n").some(a=>a.startsWith("worktree ")&&aP((0,k.resolve)(a.slice(9)))===d)}catch{return!1}}async function aV(a,b){if((0,i.existsSync)(b)){try{await aO(a,"worktree","prune")}catch{}if(await aU(a,b))throw Error(`Worktree path "${b}" already exists and is still registered with git`);(0,i.rmSync)(b,{recursive:!0,force:!0})}}async function aW(a,b){try{await aO(a,"worktree","remove","--force",b)}catch{}if((0,i.existsSync)(b)){if(await aU(a,b))throw Error(`Worktree path "${b}" already exists and is still registered with git`);await aQ(b)}}async function aX(a,b,c){await aW(a,b),await aO(a,"worktree","add",b,c)}async function aY(a,b,c,d,e){await aW(a,b);let f=await aT(a,d,{branch:c,hasOrigin:e});if(!f.startsWith("origin/"))return void await aO(a,"worktree","add","-b",c,b,f);try{await aO(a,"worktree","add","-b",c,b,f)}catch{await aO(a,"worktree","add","-b",c,b,`refs/heads/${d}`)}}let aZ=/^[a-zA-Z0-9_-]+$/;function a$(a,b){if(!aZ.test(a))throw Error(`Invalid ${b} "${a}": must match ${aZ}`)}function a_(a){return a.startsWith("~/")?(0,k.join)((0,j.homedir)(),a.slice(2)):a}let a0={manifest:{name:"worktree",slot:"workspace",description:"Workspace plugin: git worktrees",version:"0.1.0"},create:function(a){let b=a?.worktreeDir?a_(a.worktreeDir):(0,k.join)((0,j.homedir)(),".worktrees");return{name:"worktree",async create(a){a$(a.projectId,"projectId"),a$(a.sessionId,"sessionId");let c=a_(a.project.path),d=a.worktreeDir??b,e=a.worktreeDir?d:(0,k.join)(d,a.projectId),f=(0,k.join)(e,a.sessionId);(0,i.mkdirSync)(e,{recursive:!0}),await aV(c,f);let g=await aR(c);if(g)try{await aO(c,"fetch","origin","--quiet")}catch{}let h=await aT(c,a.project.defaultBranch,{hasOrigin:g});try{await aO(c,"worktree","add","-b",a.branch,f,h)}catch(i){let b=i instanceof Error?i.message:String(i);if(!b.includes("already exists"))throw Error(`Failed to create worktree for branch "${a.branch}": ${b}`,{cause:i});let d=await aO(c,"rev-parse",h),e=`refs/heads/${a.branch}`,g=await aS(c,e)?await aO(c,"rev-parse",e):void 0;try{g===d?await aO(c,"worktree","add",f,a.branch):await aO(c,"worktree","add","-B",a.branch,f,h)}catch(d){try{await aO(c,"worktree","remove","--force",f)}catch{}let b=d instanceof Error?d.message:String(d);throw Error(`Failed to create worktree for branch "${a.branch}": ${b}`,{cause:d})}}return{path:f,branch:a.branch,sessionId:a.sessionId,projectId:a.projectId}},async findManagedWorkspace(a){a$(a.projectId,"projectId"),a$(a.sessionId,"sessionId");let c=a_(a.project.path),d=a.worktreeDir??b,e=a.worktreeDir?d:(0,k.join)(d,a.projectId),f=new Set([(0,k.resolve)((0,k.join)(e,a.sessionId)),(0,k.resolve)((0,k.join)(b,a.projectId,a.sessionId))]),g=(function(a){let b=a.replace(/\r\n/g,"\n").trim();return b?b.split("\n\n").map(a=>{let b="",c=null;for(let d of a.split("\n"))d.startsWith("worktree ")?b=(0,k.resolve)(d.slice(9)):d.startsWith("branch ")&&(c=d.slice(7).replace("refs/heads/",""));return{path:b,branch:c}}).filter(a=>a.path.length>0):[]})(await aO(c,"worktree","list","--porcelain")).filter(b=>b.branch===a.branch&&(0,i.existsSync)(b.path));if(0===g.length)return null;if(g.length>1)throw Error(`Found multiple worktrees for orchestrator branch "${a.branch}". Reuse one workspace or remove the extras before starting the orchestrator.`);let h=g[0];if(!f.has(h.path))throw Error(`Found existing worktree for orchestrator branch "${a.branch}" at "${h.path}", but it is outside AO-managed worktree directories. Reuse it manually or remove it and try again.`);return{path:h.path,branch:a.branch,sessionId:a.sessionId,projectId:a.projectId}},async destroy(a){try{let b=await aO(a,"rev-parse","--path-format=absolute","--git-common-dir"),c=(0,k.resolve)(b,"..");await aO(c,"worktree","remove","--force",a)}catch{(0,i.existsSync)(a)&&await aQ(a)}},async list(a){a$(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 aO(a,"worktree","list","--porcelain");break}catch{continue}if(!e)return[];let f=[],g=e.split("\n\n"),h=aP(c);for(let b of g){let c=b.trim().split("\n"),d="",e="";for(let a of c)a.startsWith("worktree ")?d=a.slice(9):a.startsWith("branch ")&&(e=a.slice(7).replace("refs/heads/",""));let g=d?aP(d):"";if(d&&(g===h||g.startsWith(h+"/"))){let b=(0,k.basename)(d);f.push({path:d,branch:e||"detached",sessionId:b,projectId:a})}}return f},async exists(a){if(!(0,i.existsSync)(a))return!1;try{return await aN("git",["rev-parse","--is-inside-work-tree"],{cwd:a,timeout:3e4,windowsHide:!0}),!0}catch{return!1}},async restore(a,b){let c=a_(a.project.path);try{await aO(c,"worktree","prune")}catch{}let d=await aR(c);if(d)try{await aO(c,"fetch","origin","--quiet")}catch{}try{await aO(c,"worktree","add",b,a.branch)}catch{await aS(c,`refs/heads/${a.branch}`)?await aX(c,b,a.branch):await aY(c,b,a.branch,a.project.defaultBranch,d)}return{path:b,branch:a.branch,sessionId:a.sessionId,projectId:a.projectId}},async postCreate(a,b){let c=a_(b.path);if(b.symlinks)for(let e of b.symlinks){if(e.startsWith("/")||e.includes("..")||/^[a-zA-Z]:[\\/]/.test(e)||e.startsWith("\\\\"))throw Error(`Invalid symlink path "${e}": must be a relative path without ".." segments`);let b=(0,k.join)(c,e),f=(0,k.resolve)(a.path,e),g=(0,k.resolve)(a.path);if(!f.startsWith(g+k.sep)&&f!==g)throw Error(`Symlink target "${e}" resolves outside workspace: ${f}`);if((0,i.existsSync)(b)){try{let a=(0,i.lstatSync)(f);(a.isSymbolicLink()||a.isFile()||a.isDirectory())&&(0,i.rmSync)(f,{recursive:!0,force:!0})}catch{}(0,i.mkdirSync)((0,k.dirname)(f),{recursive:!0});try{(0,i.symlinkSync)(b,f)}catch(a){if((0,d.uFH)()){let a=(()=>{try{return(0,i.statSync)(b).isDirectory()}catch{return!1}})();try{a?(0,i.symlinkSync)(b,f,"junction"):(0,i.linkSync)(b,f)}catch{i.cpSync(b,f,{recursive:!0})}}else throw a}}}if(b.postCreate){let c=(0,d.ry1)();for(let d of b.postCreate)await aN(c.cmd,c.args(d),{cwd:a.path,windowsHide:!0})}}}}};class a1{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 a2=(0,f.promisify)(e.execFile),a3=async(a,b,c)=>(0,d.vQK)(a,{component:"scm-github-batch",operation:c},b),a4={prList:new a1(100),commitStatus:new a1(500),reviewComments:new a1(500)};function a5(a,b,c){a4.prList.set(`${a}/${b}`,c)}function a6(a,b,c,d){a4.commitStatus.set(`${a}/${b}#${c}`,d)}let a7=new a1(200),a8=new a1(200);async function a9(a,b=[],c){let d=[],e=!1,f=new Map;for(let b of a){let a=`${b.owner}/${b.repo}`;f.has(a)||f.set(a,[]);let c=f.get(a);c&&c.push(b)}for(let a of b)f.has(a)||f.set(a,[]);if(0===f.size)return{shouldRefresh:!1,details:["No repos to check"],prListUnchangedRepos:new Set};let g=!1,h=new Set;for(let[a]of f){let[b,f]=a.split("/");await be(b,f,c)?(g=!0,e=!0,d.push(`PR list changed for ${a} (Guard 1)`)):h.add(a)}if(!g)for(let b of a){let a=`${b.owner}/${b.repo}#${b.number}`,f=a7.get(a);if(f&&null===f.headSha){e=!0,d.push(`First time seeing PR #${b.number} (Guard 2: no cached head SHA)`);continue}f&&f.headSha&&await bf(b.owner,b.repo,f.headSha,c)&&(e=!0,d.push(`CI status changed for ${b.owner}/${b.repo}#${b.number} (Guard 2)`))}return{shouldRefresh:e,details:d,prListUnchangedRepos:h}}async function ba(){try{await a2("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}}function bb(a){return/HTTP\/[\d.]+ 304/i.test(a)}function bc(a){let b=("string"==typeof a.stdout?a.stdout:"")+("string"==typeof a.stderr?a.stderr:"");return b.length>0?b:null}function bd(a){let b=a.match(/etag:\s*(.+)/i);return b?b[1].trim():void 0}async function be(a,b,c){let d=`${a}/${b}`,e=a4.prList.get(d),f=["api","--method","GET",`repos/${d}/pulls?state=open&sort=updated&direction=desc&per_page=1`,"-i"];e&&f.push("-H",`If-None-Match: ${e}`);try{let c=await a3(f,1e4,"gh.api.guard-pr-list");if(bb(c)){let d=bd(c);return d&&a5(a,b,d),!1}let d=bd(c);return d&&a5(a,b,d),!0}catch(g){let e=bc(g);if(e&&bb(e)){let c=bd(e);return c&&a5(a,b,c),!1}let f=g instanceof Error?g.message:String(g);if(bb(f))return!1;return c?.log("warn",`[ETag Guard 1] PR list check failed for ${d}: ${f}`),!0}}async function bf(a,b,c,d){let e=`${a}/${b}#${c}`,f=a4.commitStatus.get(e),g=["api","--method","GET",`repos/${a}/${b}/commits/${c}/check-runs?per_page=1`,"-i"];f&&g.push("-H",`If-None-Match: ${f}`);try{let d=await a3(g,1e4,"gh.api.guard-commit-status");if(bb(d)){let e=bd(d);return e&&a6(a,b,c,e),!1}let e=bd(d);return e&&a6(a,b,c,e),!0}catch(h){let f=bc(h);if(f&&bb(f)){let d=bd(f);return d&&a6(a,b,c,d),!1}let g=h instanceof Error?h.message:String(h);if(bb(g))return!1;return d?.log("warn",`[ETag Guard 2] Commit status check failed for ${e}: ${g}`),!0}}async function bg(a,b,c,d){let e=`${a}/${b}#${c}`,f=a4.reviewComments.get(e),g=["api","--method","GET",`repos/${a}/${b}/pulls/${c}/comments`,"-i"];f&&g.push("-H",`If-None-Match: ${f}`);try{let a=await a3(g,1e4,"gh.api.guard-review-comments");if(bb(a)){let b=bd(a);return b&&a4.reviewComments.set(e,b),!1}let b=bd(a);return b&&a4.reviewComments.set(e,b),!0}catch(c){let a=bc(c);if(a&&bb(a)){let b=bd(a);return b&&a4.reviewComments.set(e,b),!1}let b=c instanceof Error?c.message:String(c);if(bb(b))return!1;return d?.log("warn",`[ETag Guard 3] Review comments check failed for ${e}: ${b}`),!0}}let bh=`
|
|
410
|
+
title
|
|
411
|
+
state
|
|
412
|
+
additions
|
|
413
|
+
deletions
|
|
414
|
+
isDraft
|
|
415
|
+
mergeable
|
|
416
|
+
mergeStateStatus
|
|
417
|
+
reviewDecision
|
|
418
|
+
headRefName
|
|
419
|
+
headRefOid
|
|
420
|
+
commits(last: 1) {
|
|
421
|
+
nodes {
|
|
422
|
+
commit {
|
|
423
|
+
statusCheckRollup {
|
|
424
|
+
state
|
|
425
|
+
# 11 keeps per-PR node cost under budget for 25-PR batch queries
|
|
426
|
+
# (total cost ≤5000). Repos with >11 checks lose individual check
|
|
427
|
+
# visibility, but the rollup "state" still reflects all checks —
|
|
428
|
+
# overall pass/fail detection remains correct.
|
|
429
|
+
contexts(first: 11) {
|
|
430
|
+
nodes {
|
|
431
|
+
... on CheckRun {
|
|
432
|
+
name
|
|
433
|
+
status
|
|
434
|
+
conclusion
|
|
435
|
+
detailsUrl
|
|
436
|
+
}
|
|
437
|
+
... on StatusContext {
|
|
438
|
+
context
|
|
439
|
+
state
|
|
440
|
+
targetUrl
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
pageInfo {
|
|
444
|
+
hasNextPage
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
`;async function bi(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(`
|
|
452
|
+
${e}: repository(owner: $${e}Owner, name: $${e}Name) {
|
|
453
|
+
... on Repository {
|
|
454
|
+
pullRequest(number: $${e}Number) { ${bh} }
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
`),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}) {
|
|
458
|
+
${b.join("\n")}
|
|
459
|
+
rateLimit { cost remaining resetAt }
|
|
460
|
+
}`,variables:c}}(a);if(!b||0===a.length)return{};await ba();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","-i",...d,"-f",`query=${b}`],f=3e4+Math.max(0,(a.length-10)*2e3),g=await a3(e,f,"gh.api.graphql-batch"),h=g.indexOf("\r\n\r\n"),i=g.indexOf("\n\n"),j=h>=0&&(i<0||h<i)?h+4:i>=0?i+2:0,k=JSON.parse((j>0?g.slice(j):g).trim());if(k.errors&&k.errors.length>0){let a=k.errors.map(a=>a.message).join("; ");throw Error(`GraphQL query errors: ${a}`)}return k.data??{}}async function bj(a,b,c=[]){let d=new Map,e=await a9(a,c,b);if(b?.reportPRListUnchangedRepos?.(e.prListUnchangedRepos),!e.shouldRefresh){let c=[];for(let b of a){let a=`${b.owner}/${b.repo}#${b.number}`,e=a8.get(a);e?d.set(a,e):c.push(b)}if(0===c.length)return b?.log("info",`[ETag Guard] Skipping GraphQL batch - all ${d.size} PRs cached. Reasons: ${e.details.join(", ")}`),{enrichment:d,prListUnchangedRepos:e.prListUnchangedRepos};b?.log("info",`[ETag Guard] Partial cache: ${d.size} cached, ${c.length} missing. Fetching missing PRs via GraphQL.`),a=c}let f=[];for(let b=0;b<a.length;b+=25)f.push(a.slice(b,b+25));for(let a=0;a<f.length;a++){let c,e=f[a],g=d.size,h=Date.now();try{let i=await bi(e);c=Date.now()-h,e.forEach((a,b)=>{let c=`pr${b}`,e=`${a.owner}/${a.repo}#${a.number}`,f=i[c];if(f?.pullRequest){let a=function(a){if(!a||"object"!=typeof a||void 0===a.state&&void 0===a.title&&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:c}=a;d.set(e,b),a7.set(e,{headSha:c,ciStatus:b.ciStatus}),a8.set(e,b)}}});let j=d.size;if(j>g){let d={batchIndex:a,totalBatches:f.length,prCount:j-g,durationMs:c};b?.recordSuccess(d),b?.log("info",`[GraphQL Batch Success] Batch ${a+1}/${f.length} succeeded: added ${j-g} PRs to cache (${c}ms)`)}}catch(g){c=Date.now()-h;let d=g instanceof Error?g.message:String(g);b?.recordFailure({batchIndex:a,totalBatches:f.length,prCount:e.length,error:d,durationMs:c}),b?.log("error",`[GraphQL Batch] Batch enrichment partially failed: ${d}`)}}return{enrichment:d,prListUnchangedRepos:e.prListUnchangedRepos}}function bk(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 bl(a){if("string"!=typeof a)return;let b=new Date(a);return Number.isNaN(b.getTime())?void 0:b}function bm(a){return"string"!=typeof a||0===a.length?void 0:a.startsWith("refs/heads/")?a.slice(11):a.startsWith("refs/")?void 0:a}let bn=(0,f.promisify)(e.execFile),bo=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 bp(a,b,c){try{let{stdout:d}=await bn(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 bq(a){return(0,d.vQK)(a,{component:"scm-github"},3e4)}async function br(a,b){return(0,d.vQK)(a,{component:"scm-github",cwd:b},3e4)}async function bs(a,b){return bp("git",a,b)}function bt(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 bu(a,b){let[c,d]=bt(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 bv(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 bw(a){let b=JSON.parse(await bq(["pr","view",String(a.number),"--repo",by(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:bv(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 bx(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 by(a){return`${a.owner}/${a.repo}`}function bz(a){if(!a)return new Date(0);let b=new Date(a);return isNaN(b.getTime())?new Date(0):b}let bA={resolvePR:6e4,getPRState:5e3,getPRSummary:5e3,getReviews:1e4,getReviewDecision:1e4,getCIChecks:5e3,getMergeability:5e3,getPendingComments:1e4,detectPR:3e4},bB={manifest:{name:"github",slot:"scm",description:"SCM plugin: GitHub PRs, CI checks, reviews, merge readiness",version:"0.1.0"},create:function(){return function(){let a,b=new Map,c=new Map;function e(a,b,c,d){return`${a}/${b}#${c}:${d}`}function f(a){let c=b.get(a);return c?Date.now()>c.expiresAt?(b.delete(a),null):c.value:null}function g(a,c,d){if(b.size>=1e3){let a=b.keys().next().value;void 0!==a&&b.delete(a)}b.set(a,{value:c,expiresAt:Date.now()+d})}function i(a){let d=`${a.owner}/${a.repo}#${a.number}:`;for(let a of b.keys())a.startsWith(d)&&b.delete(a);b.delete(e(a.owner,a.repo,a.branch,"detectPR")),c.delete(`${a.owner}/${a.repo}#${a.number}`)}async function j(a,b,c,d,h){let i=e(a,b,c,d),j=f(i);if(null!==j)return j;let k=await h();return g(i,k,bA[d]),k}return{name:"github",async verifyWebhook(a,b){let c=bx(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=bk(a.headers,c.eventHeader);if(!d)return{ok:!1,reason:`Missing ${c.eventHeader} header`};let e=bk(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=bk(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=bx(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=bk(a.headers,c.eventHeader);if(!d)return null;let e=bk(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:bl(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?bl(b.review?.submitted_at):bl(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:bl(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:bl(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:bm(a[0]?.name??b.ref),sha:"string"==typeof b.sha?b.sha:void 0,timestamp:bl(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:bm(b.ref),sha:"string"==typeof b.after?b.after:void 0,timestamp:bl(a?.timestamp??b.updated_at),data:b}}return{provider:"github",kind:"unknown",action:g,rawEventType:d,deliveryId:e,repository:f,timestamp:bl(b.updated_at),data:b}}(a,d,c)},async detectPR(a,b){if(!a.branch||!b.repo)return null;bt(b.repo);let[c,d]=b.repo.split("/"),h=e(c??"",d??"",a.branch,"detectPR"),i=f(h);if(null!==i)return i;try{let c=await bq(["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;let e=bu(d[0],b.repo);return g(h,e,bA.detectPR),e}catch{return null}},async resolvePR(a,b){if(!b.repo)throw Error("Cannot resolve PR: project has no repo configured");let c=b.repo,[d,e]=c.split("/");return j(d??"",e??"",`ref=${a}`,"resolvePR",async()=>bu(JSON.parse(await bq(["pr","view",a,"--repo",c,"--json","number,url,title,headRefName,baseRefName,isDraft"])),c))},async assignPRToCurrentUser(a){await bq(["pr","edit",String(a.number),"--repo",by(a),"--add-assignee","@me"]),i(a)},async checkoutPR(a,b){if(await bs(["branch","--show-current"],b)===a.branch)return!1;if(await bs(["status","--porcelain"],b))throw Error(`Workspace has uncommitted changes; cannot switch to PR branch "${a.branch}" safely`);return await br(["pr","checkout",String(a.number),"--repo",by(a)],b),!0},getPRState:async a=>j(a.owner,a.repo,String(a.number),"getPRState",async()=>{let b=JSON.parse(await bq(["pr","view",String(a.number),"--repo",by(a),"--json","state"])).state.toUpperCase();return"MERGED"===b?"merged":"CLOSED"===b?"closed":"open"}),getPRSummary:async a=>j(a.owner,a.repo,String(a.number),"getPRSummary",async()=>{let b=JSON.parse(await bq(["pr","view",String(a.number),"--repo",by(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 bq(["pr","merge",String(a.number),"--repo",by(a),"rebase"===b?"--rebase":"merge"===b?"--merge":"--squash","--delete-branch"]),i(a)},async closePR(a){await bq(["pr","close",String(a.number),"--repo",by(a)]),i(a)},getCIChecks:async a=>j(a.owner,a.repo,String(a.number),"getCIChecks",async()=>{try{let b=await bq(["pr","checks",String(a.number),"--repo",by(a),"--json","name,state,link,startedAt,completedAt"]);return JSON.parse(b).map(a=>{let b=a.state?.toUpperCase();return{name:a.name,status:bv(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 bw(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=>j(a.owner,a.repo,String(a.number),"getReviews",async()=>JSON.parse(await bq(["pr","view",String(a.number),"--repo",by(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:bz(a.submittedAt)}})),getReviewDecision:async a=>j(a.owner,a.repo,String(a.number),"getReviewDecision",async()=>{let b=(JSON.parse(await bq(["pr","view",String(a.number),"--repo",by(a),"--json","reviewDecision"])).reviewDecision??"").toUpperCase();return"APPROVED"===b?"approved":"CHANGES_REQUESTED"===b?"changes_requested":"REVIEW_REQUIRED"===b?"pending":"none"}),getPendingComments:async a=>j(a.owner,a.repo,String(a.number),"getPendingComments",async()=>{try{let b=await bq(["api","graphql","-f",`owner=${a.owner}`,"-f",`name=${a.repo}`,"-F",`number=${a.number}`,"-f",`query=query($owner: String!, $name: String!, $number: Int!) {
|
|
461
|
+
repository(owner: $owner, name: $name) {
|
|
462
|
+
pullRequest(number: $number) {
|
|
463
|
+
reviewThreads(first: 100) {
|
|
464
|
+
nodes {
|
|
465
|
+
id
|
|
466
|
+
isResolved
|
|
467
|
+
comments(first: 1) {
|
|
468
|
+
nodes {
|
|
469
|
+
id
|
|
470
|
+
author { login }
|
|
471
|
+
body
|
|
472
|
+
path
|
|
473
|
+
line
|
|
474
|
+
url
|
|
475
|
+
createdAt
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}`]);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!bo.has(c)}).map(a=>{let b=a.comments.nodes[0];return{id:b.id,threadId:a.id,author:b.author?.login??"unknown",body:b.body,path:b.path||void 0,line:b.line??void 0,isResolved:a.isResolved,createdAt:bz(b.createdAt),url:b.url}})}catch(a){throw Error("Failed to fetch pending comments",{cause:a})}}),async getReviewThreads(b){let d=`${b.owner}/${b.repo}#${b.number}`;if(!await bg(b.owner,b.repo,b.number,a)){let a=c.get(d);if(a)return a}try{let a=(await bq(["api","graphql","-i","-f",`owner=${b.owner}`,"-f",`name=${b.repo}`,"-F",`number=${b.number}`,"-f",`query=query($owner: String!, $name: String!, $number: Int!) {
|
|
483
|
+
repository(owner: $owner, name: $name) {
|
|
484
|
+
pullRequest(number: $number) {
|
|
485
|
+
reviewThreads(last: 100) {
|
|
486
|
+
nodes {
|
|
487
|
+
id
|
|
488
|
+
isResolved
|
|
489
|
+
comments(first: 1) {
|
|
490
|
+
nodes {
|
|
491
|
+
id
|
|
492
|
+
author { login }
|
|
493
|
+
body
|
|
494
|
+
path
|
|
495
|
+
line
|
|
496
|
+
url
|
|
497
|
+
createdAt
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
reviews(last: 5) {
|
|
503
|
+
nodes {
|
|
504
|
+
author { login }
|
|
505
|
+
state
|
|
506
|
+
body
|
|
507
|
+
submittedAt
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
rateLimit { cost remaining resetAt }
|
|
513
|
+
}`])).replace(/^[\s\S]*?\r?\n\r?\n/,""),e=JSON.parse(a),f=e.data.repository.pullRequest.reviewThreads.nodes,g=e.data.repository.pullRequest.reviews.nodes,h=f.filter(a=>!a.isResolved&&!!a.comments.nodes[0]).map(a=>{let b=a.comments.nodes[0],c=b.author?.login??"unknown";return{id:b.id,threadId:a.id,author:c,body:b.body,path:b.path||void 0,line:b.line??void 0,isResolved:a.isResolved,createdAt:bz(b.createdAt),url:b.url,isBot:bo.has(c)}}),i=g.filter(a=>a.body&&a.body.trim().length>0).map(a=>({author:a.author?.login??"unknown",state:a.state,body:a.body,submittedAt:bz(a.submittedAt)})),j={threads:h,reviews:i};return c.set(d,j),j}catch(c){let b=c instanceof Error?c.message:String(c);throw a?.log("warn",`[getReviewThreads] Failed for ${d}: ${b}`),Error("Failed to fetch review threads",{cause:c})}},async getMergeability(a){return j(a.owner,a.repo,String(a.number),"getMergeability",async()=>{let b=[];if("merged"===await this.getPRState(a))return{mergeable:!0,ciPassing:!0,approved:!0,noConflicts:!0,blockers:[]};let c=JSON.parse(await bq(["pr","view",String(a.number),"--repo",by(a),"--json","mergeable,reviewDecision,mergeStateStatus,isDraft"])),e=await this.getCISummary(a),f=e===d.U10.PASSING||e===d.U10.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(b,c,d)=>(c&&(a=c),(await bj(b,c,d)).enrichment),async preflight(a){a.intent.willClaimExistingPR&&await (0,d.TF_)("gh-cli-auth",async()=>{try{await bn("gh",["--version"])}catch{throw Error("GitHub CLI (gh) is not installed. Install it: https://cli.github.com/")}try{await bn("gh",["auth","status"])}catch{throw Error("GitHub CLI is not authenticated. Run: gh auth login")}})}}}()}};async function bC(a){try{return await (0,d.vQK)(a,{component:"tracker-github"},3e4)}catch(b){throw Error(`gh ${a.slice(0,3).join(" ")} failed: ${b.message}`,{cause:b})}}async function bD(){return(0,d.TF_)("gh-cli-auth",async()=>{try{await bC(["--version"])}catch{throw Error("GitHub CLI (gh) is not installed. Install it: https://cli.github.com/")}try{await bC(["auth","status"])}catch{throw Error("GitHub CLI is not authenticated. Run: gh auth login")}})}function bE(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 bF(a,b){let c=bI(b);try{return await bC(["issue","view",a,"--repo",c,"--json","number,title,body,url,state,stateReason,labels,assignees"])}catch(b){if(!bE(b,"stateReason"))throw b;return bC(["issue","view",a,"--repo",c,"--json","number,title,body,url,state,labels,assignees"])}}async function bG(a){let b=[...a,"--json","number,title,body,url,state,stateReason,labels,assignees"];try{return await bC(b)}catch(b){if(!bE(b,"stateReason"))throw b;return bC([...a,"--json","number,title,body,url,state,labels,assignees"])}}function bH(a,b){return"CLOSED"===a.toUpperCase()?b?.toUpperCase()==="NOT_PLANNED"?"cancelled":"closed":"open"}function bI(a){if(!a.repo)throw Error("GitHub tracker requires a 'repo' field in project config");return a.repo}function bJ(a,b){return`${a}#${b.replace(/^#/,"")}`}let bK={manifest:{name:"github",slot:"tracker",description:"Tracker plugin: GitHub Issues",version:"0.1.0"},create:function(){let a=new Map,b=new Map,c={name:"github",async getIssue(c,d){let e=bI(d),f=function(b,c){let d=bJ(b,c),e=a.get(d);return e?Date.now()>e.expiresAt?(a.delete(d),null):e.issue:null}(e,c);if(f)return f;let g=bJ(e,c),h=b.get(g);if(h)return h;let i=(async()=>{let b=JSON.parse(await bF(c,d)),f={id:String(b.number),title:b.title,description:b.body??"",url:b.url,state:bH(b.state,b.stateReason),labels:b.labels.map(a=>a.name),assignee:b.assignees[0]?.login};if(a.size>=500){let b=a.keys().next().value;void 0!==b&&a.delete(b)}return a.set(bJ(e,c),{issue:f,expiresAt:Date.now()+3e5}),f})();b.set(g,i);try{return await i}finally{b.delete(g)}},async isCompleted(a,b){let d=await c.getIssue(a,b);return"closed"===d.state||"cancelled"===d.state},issueUrl(a,b){let c=a.replace(/^#/,"");return`https://github.com/${bI(b)}/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("","The issue title, description, and labels above are current. Fetch comments or linked issues via `gh` only if you need additional context beyond what is provided here.","","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",bI(b),"--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 bG(c)).map(a=>({id:String(a.number),title:a.title,description:a.body??"",url:a.url,state:bH(a.state,a.stateReason),labels:a.labels.map(a=>a.name),assignee:a.assignees[0]?.login}))},async updateIssue(b,c,d){let e=bI(d);a.delete(bJ(e,b)),"closed"===c.state?await bC(["issue","close",b,"--repo",e]):"open"===c.state&&await bC(["issue","reopen",b,"--repo",e]),c.removeLabels&&c.removeLabels.length>0&&await bC(["issue","edit",b,"--repo",e,"--remove-label",c.removeLabels.join(",")]),c.labels&&c.labels.length>0&&await bC(["issue","edit",b,"--repo",e,"--add-label",c.labels.join(",")]),c.assignee&&await bC(["issue","edit",b,"--repo",e,"--add-assignee",c.assignee]),c.comment&&await bC(["issue","comment",b,"--repo",e,"--body",c.comment])},async createIssue(a,b){let d=["issue","create","--repo",bI(b),"--title",a.title,"--body",a.description??""];a.labels&&a.labels.length>0&&d.push("--label",a.labels.join(",")),a.assignee&&d.push("--assignee",a.assignee);let e=await bC(d),f=e.match(/\/issues\/(\d+)/);if(!f)throw Error(`Failed to parse issue URL from gh output: ${e}`);let g=f[1];return c.getIssue(g,b)},async preflight(){await bD()}};return c}};var bL=c(44708);function bM(a){switch(a){case"completed":return"closed";case"canceled":return"cancelled";case"started":return"in_progress";default:return"open"}}let bN=`
|
|
514
|
+
id
|
|
515
|
+
identifier
|
|
516
|
+
title
|
|
517
|
+
description
|
|
518
|
+
url
|
|
519
|
+
priority
|
|
520
|
+
branchName
|
|
521
|
+
state { name type }
|
|
522
|
+
labels { nodes { name } }
|
|
523
|
+
assignee { name displayName }
|
|
524
|
+
team { key }
|
|
525
|
+
`;function bO(a){return{name:"linear",async getIssue(b,c){let d=(await a(`query($id: String!) {
|
|
526
|
+
issue(id: $id) {
|
|
527
|
+
${bN}
|
|
528
|
+
}
|
|
529
|
+
}`,{id:b})).issue;return{id:d.identifier,title:d.title,description:d.description??"",url:d.url,state:bM(d.state.type),labels:d.labels.nodes.map(a=>a.name),assignee:d.assignee?.displayName??d.assignee?.name,priority:d.priority,branchName:d.branchName??void 0}},async isCompleted(b,c){let d=(await a(`query($id: String!) {
|
|
530
|
+
issue(id: $id) {
|
|
531
|
+
state { type }
|
|
532
|
+
}
|
|
533
|
+
}`,{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!) {
|
|
534
|
+
issues(filter: $filter, first: $first) {
|
|
535
|
+
nodes {
|
|
536
|
+
${bN}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}`,e)).issues.nodes.map(a=>({id:a.identifier,title:a.title,description:a.description??"",url:a.url,state:bM(a.state.type),labels:a.labels.nodes.map(a=>a.name),assignee:a.assignee?.displayName??a.assignee?.name,priority:a.priority,branchName:a.branchName??void 0}))},async updateIssue(b,c,d){let e=await a(`query($id: String!) {
|
|
540
|
+
issue(id: $id) {
|
|
541
|
+
id
|
|
542
|
+
team { id }
|
|
543
|
+
}
|
|
544
|
+
}`,{id:b}),f=e.issue.id,g=e.issue.team.id;if(c.state){let b=await a(`query($teamId: ID!) {
|
|
545
|
+
workflowStates(filter: { team: { id: { eq: $teamId } } }) {
|
|
546
|
+
nodes { id name type }
|
|
547
|
+
}
|
|
548
|
+
}`,{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!) {
|
|
549
|
+
issueUpdate(id: $id, input: { stateId: $stateId }) {
|
|
550
|
+
success
|
|
551
|
+
}
|
|
552
|
+
}`,{id:f,stateId:e.id})}if(c.assignee){let b=(await a(`query($filter: UserFilter) {
|
|
553
|
+
users(filter: $filter) {
|
|
554
|
+
nodes { id displayName name }
|
|
555
|
+
}
|
|
556
|
+
}`,{filter:{displayName:{eq:c.assignee}}})).users.nodes[0];b&&await a(`mutation($id: String!, $assigneeId: String!) {
|
|
557
|
+
issueUpdate(id: $id, input: { assigneeId: $assigneeId }) {
|
|
558
|
+
success
|
|
559
|
+
}
|
|
560
|
+
}`,{id:f,assigneeId:b.id})}if(c.labels&&c.labels.length>0){let b=new Set((await a(`query($id: String!) {
|
|
561
|
+
issue(id: $id) {
|
|
562
|
+
labels { nodes { id } }
|
|
563
|
+
}
|
|
564
|
+
}`,{id:f})).issue.labels.nodes.map(a=>a.id)),d=new Map((await a(`query($teamId: ID) {
|
|
565
|
+
issueLabels(filter: { team: { id: { eq: $teamId } } }) {
|
|
566
|
+
nodes { id name }
|
|
567
|
+
}
|
|
568
|
+
}`,{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!]!) {
|
|
569
|
+
issueUpdate(id: $id, input: { labelIds: $labelIds }) {
|
|
570
|
+
success
|
|
571
|
+
}
|
|
572
|
+
}`,{id:f,labelIds:[...b]})}c.comment&&await a(`mutation($issueId: String!, $body: String!) {
|
|
573
|
+
commentCreate(input: { issueId: $issueId, body: $body }) {
|
|
574
|
+
success
|
|
575
|
+
}
|
|
576
|
+
}`,{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) {
|
|
577
|
+
issueCreate(input: {
|
|
578
|
+
title: $title,
|
|
579
|
+
description: $description,
|
|
580
|
+
teamId: $teamId,
|
|
581
|
+
priority: $priority
|
|
582
|
+
}) {
|
|
583
|
+
success
|
|
584
|
+
issue {
|
|
585
|
+
${bN}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}`,e)).issueCreate.issue,g={id:f.identifier,title:f.title,description:f.description??"",url:f.url,state:bM(f.state.type),labels:f.labels.nodes.map(a=>a.name),assignee:f.assignee?.displayName??f.assignee?.name,priority:f.priority,branchName:f.branchName??void 0};if(b.assignee)try{let c=(await a(`query($filter: UserFilter) {
|
|
589
|
+
users(filter: $filter) {
|
|
590
|
+
nodes { id displayName name }
|
|
591
|
+
}
|
|
592
|
+
}`,{filter:{displayName:{eq:b.assignee}}})).users.nodes[0];c&&(await a(`mutation($id: String!, $assigneeId: String!) {
|
|
593
|
+
issueUpdate(id: $id, input: { assigneeId: $assigneeId }) {
|
|
594
|
+
success
|
|
595
|
+
}
|
|
596
|
+
}`,{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) {
|
|
597
|
+
issueLabels(filter: { team: { id: { eq: $teamId } } }) {
|
|
598
|
+
nodes { id name }
|
|
599
|
+
}
|
|
600
|
+
}`,{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!]!) {
|
|
601
|
+
issueUpdate(id: $id, input: { labelIds: $labelIds }) {
|
|
602
|
+
success
|
|
603
|
+
}
|
|
604
|
+
}`,{id:f.id,labelIds:i}),g.labels=h)}catch{}return g}}}let bP={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 bO(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 bO((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,bL.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()})})}},bQ=globalThis;function bR(){if(bQ._aoServices)return Promise.resolve(bQ._aoServices);if(!bQ._aoServicesInit){let a=bQ._aoServicesGeneration??0,b=bT().then(b=>(bQ._aoServicesGeneration??0)!==a?(b.lifecycleManager.stop(),bR()):(bQ._aoServices=b,b)).catch(a=>{throw bQ._aoServicesInit===b&&(bQ._aoServicesInit=void 0),a});bQ._aoServicesInit=b}return bQ._aoServicesInit}function bS(){bQ._aoServicesGeneration=(bQ._aoServicesGeneration??0)+1,bQ._aoServices&&bQ._aoServices.lifecycleManager.stop(),bQ._aoServices=void 0,bQ._aoServicesInit=void 0}async function bT(){let a=function(){let a=(0,d.NoB)();try{return(0,d.Z9L)(a)}catch(a){if(a instanceof Error&&"code"in a&&"ENOENT"===a.code||a instanceof d.kw3)return(0,d.Z9L)();throw a}}(),b=(0,d.RaB)();b.register(p),b.register(D),b.register(P),b.register(ah),b.register(al),b.register(aI),b.register(aM),b.register(a0),b.register(bB),b.register(bK),b.register(bP);let c=(0,d.Qum)({config:a,registry:b}),e=(0,d.C1z)({config:a,registry:b,sessionManager:c});return{config:a,registry:b,sessionManager:c,lifecycleManager:e}}let bU="agent:backlog",bV=globalThis;function bW(){bV._aoBacklogStarted||(bV._aoBacklogStarted=!0,b$(),bV._aoBacklogTimer=setInterval(()=>void b$(),6e4))}let bX=new Set;async function bY(a,b,c){for(let d of a.filter(a=>"merged"===a.lifecycle.pr.state&&a.issueId&&!bX.has(`${a.projectId}:${a.issueId}`))){let a=`${d.projectId}:${d.issueId}`,e=b.projects[d.projectId];if(!e?.tracker?.plugin){bX.add(a);continue}let f=c.get("tracker",e.tracker.plugin);if(!f?.updateIssue){bX.add(a);continue}let g=d.issueId;if(!g){bX.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)}bX.add(a)}}async function bZ(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:[bU],removeLabels:["agent:done"],comment:"Issue reopened — returning to agent backlog."},c),console.log(`[backlog] Relabeled reopened issue ${b.id} → ${bU}`)}catch(a){console.error(`[backlog] Failed to relabel reopened issue ${b.id}:`,a)}}}}async function b$(){try{let{config:a,registry:b,sessionManager:c}=await bR(),e=await c.list();await bY(e,a,b),await bZ(a,b);let f=Object.entries(a.projects).map(([a,b])=>b.sessionPrefix??a),g=e.filter(b=>!(0,d.tTz)(b,a.projects[b.projectId]?.sessionPrefix??b.projectId,f)&&!d.CMu.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[d,e]of Object.entries(a.projects)){let a;if(i<=0)break;if(!e.tracker?.plugin)continue;let f=b.get("tracker",e.tracker.plugin);if(f?.listIssues){try{a=await f.listIssues({state:"open",labels:[bU],limit:10},e)}catch{continue}for(let b of a){if(i<=0)break;if(!h.has(b.id.toLowerCase()))try{await c.spawn({projectId:d,issueId:b.id}),i--,h.add(b.id.toLowerCase()),f.updateIssue&&await f.updateIssue(b.id,{labels:["agent:in-progress"],removeLabels:["agent:backlog"],comment:"Claimed by agent orchestrator — session spawned."},e)}catch(a){console.error(`[backlog] Failed to spawn session for issue ${b.id}:`,a)}}}}}catch(a){console.error("[backlog] Poll failed:",a)}}async function b_(){let a=[];try{let{config:b,registry:c}=await bR();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:[bU],limit:20},e)))a.push({...c,projectId:d})}catch{}}}catch{}return a}async function b0(){let a=[];try{let{config:b,registry:c}=await bR();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 b1(a,b){return b?.scm?.plugin?a.get("scm",b.scm.plugin):null}}};
|