@made-by-moonlight/athene-web 0.9.2
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 -0
- package/.next/app-build-manifest.json +448 -0
- package/.next/app-path-routes-manifest.json +47 -0
- package/.next/build-manifest.json +33 -0
- package/.next/export-marker.json +6 -0
- package/.next/images-manifest.json +58 -0
- package/.next/next-minimal-server.js.nft.json +1 -0
- package/.next/next-server.js.nft.json +1 -0
- package/.next/package.json +1 -0
- package/.next/prerender-manifest.json +172 -0
- package/.next/react-loadable-manifest.json +61 -0
- package/.next/required-server-files.json +335 -0
- package/.next/routes-manifest.json +234 -0
- package/.next/server/app/_not-found/page.js +2 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/.next/server/app/_not-found.html +1 -0
- package/.next/server/app/_not-found.meta +8 -0
- package/.next/server/app/_not-found.rsc +24 -0
- package/.next/server/app/api/backlog/route.js +1 -0
- package/.next/server/app/api/backlog/route.js.nft.json +1 -0
- package/.next/server/app/api/backlog/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/browse-directory/route.js +1 -0
- package/.next/server/app/api/browse-directory/route.js.nft.json +1 -0
- package/.next/server/app/api/browse-directory/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/filesystem/browse/route.js +1 -0
- package/.next/server/app/api/filesystem/browse/route.js.nft.json +1 -0
- package/.next/server/app/api/filesystem/browse/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/issues/route.js +1 -0
- package/.next/server/app/api/issues/route.js.nft.json +1 -0
- package/.next/server/app/api/issues/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/observability/route.js +1 -0
- package/.next/server/app/api/observability/route.js.nft.json +1 -0
- package/.next/server/app/api/observability/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/orchestrators/route.js +1 -0
- package/.next/server/app/api/orchestrators/route.js.nft.json +1 -0
- package/.next/server/app/api/orchestrators/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/projects/[id]/route.js +5 -0
- package/.next/server/app/api/projects/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/projects/[id]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/projects/reload/route.js +1 -0
- package/.next/server/app/api/projects/reload/route.js.nft.json +1 -0
- package/.next/server/app/api/projects/reload/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/projects/route.js +1 -0
- package/.next/server/app/api/projects/route.js.nft.json +1 -0
- package/.next/server/app/api/projects/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/prs/[id]/merge/route.js +1 -0
- package/.next/server/app/api/prs/[id]/merge/route.js.nft.json +1 -0
- package/.next/server/app/api/prs/[id]/merge/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/reviews/execute/route.js +1 -0
- package/.next/server/app/api/reviews/execute/route.js.nft.json +1 -0
- package/.next/server/app/api/reviews/execute/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/reviews/findings/route.js +1 -0
- package/.next/server/app/api/reviews/findings/route.js.nft.json +1 -0
- package/.next/server/app/api/reviews/findings/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/reviews/route.js +1 -0
- package/.next/server/app/api/reviews/route.js.nft.json +1 -0
- package/.next/server/app/api/reviews/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/reviews/send/route.js +1 -0
- package/.next/server/app/api/reviews/send/route.js.nft.json +1 -0
- package/.next/server/app/api/reviews/send/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/runtime/terminal/route.js +1 -0
- package/.next/server/app/api/runtime/terminal/route.js.nft.json +1 -0
- package/.next/server/app/api/runtime/terminal/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/[id]/kill/route.js +1 -0
- package/.next/server/app/api/sessions/[id]/kill/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/kill/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/[id]/message/route.js +1 -0
- package/.next/server/app/api/sessions/[id]/message/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/message/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/[id]/remap/route.js +1 -0
- package/.next/server/app/api/sessions/[id]/remap/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/remap/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/[id]/restore/route.js +1 -0
- package/.next/server/app/api/sessions/[id]/restore/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/restore/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/[id]/route.js +1 -0
- package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/[id]/send/route.js +1 -0
- package/.next/server/app/api/sessions/[id]/send/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/send/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/patches/route.js +1 -0
- package/.next/server/app/api/sessions/patches/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/patches/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/route.js +1 -0
- package/.next/server/app/api/sessions/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/setup-labels/route.js +1 -0
- package/.next/server/app/api/setup-labels/route.js.nft.json +1 -0
- package/.next/server/app/api/setup-labels/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/spawn/route.js +1 -0
- package/.next/server/app/api/spawn/route.js.nft.json +1 -0
- package/.next/server/app/api/spawn/route_client-reference-manifest.js +1 -0
- 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 -0
- package/.next/server/app/api/verify/route.js.nft.json +1 -0
- package/.next/server/app/api/verify/route_client-reference-manifest.js +1 -0
- 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 -0
- package/.next/server/app/api/webhooks/[...slug]/route.js.nft.json +1 -0
- package/.next/server/app/api/webhooks/[...slug]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/apple-icon/route.js +1 -0
- package/.next/server/app/apple-icon/route.js.nft.json +1 -0
- package/.next/server/app/apple-icon/route_client-reference-manifest.js +1 -0
- package/.next/server/app/apple-icon.body +0 -0
- package/.next/server/app/apple-icon.meta +1 -0
- package/.next/server/app/dev/terminal-test/page.js +15 -0
- package/.next/server/app/dev/terminal-test/page.js.nft.json +1 -0
- package/.next/server/app/dev/terminal-test/page_client-reference-manifest.js +1 -0
- package/.next/server/app/dev/terminal-test.html +1 -0
- package/.next/server/app/dev/terminal-test.meta +7 -0
- package/.next/server/app/dev/terminal-test.rsc +28 -0
- package/.next/server/app/icon/route.js +1 -0
- package/.next/server/app/icon/route.js.nft.json +1 -0
- package/.next/server/app/icon/route_client-reference-manifest.js +1 -0
- package/.next/server/app/icon-192/route.js +1 -0
- package/.next/server/app/icon-192/route.js.nft.json +1 -0
- package/.next/server/app/icon-192/route_client-reference-manifest.js +1 -0
- package/.next/server/app/icon-512/route.js +1 -0
- package/.next/server/app/icon-512/route.js.nft.json +1 -0
- package/.next/server/app/icon-512/route_client-reference-manifest.js +1 -0
- package/.next/server/app/icon.body +0 -0
- package/.next/server/app/icon.meta +1 -0
- package/.next/server/app/manifest.webmanifest/route.js +16 -0
- package/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -0
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -0
- package/.next/server/app/manifest.webmanifest.body +1 -0
- package/.next/server/app/manifest.webmanifest.meta +1 -0
- package/.next/server/app/page.js +2 -0
- package/.next/server/app/page.js.nft.json +1 -0
- package/.next/server/app/page_client-reference-manifest.js +1 -0
- package/.next/server/app/projects/[projectId]/page.js +2 -0
- package/.next/server/app/projects/[projectId]/page.js.nft.json +1 -0
- package/.next/server/app/projects/[projectId]/page_client-reference-manifest.js +1 -0
- package/.next/server/app/projects/[projectId]/sessions/[id]/page.js +2 -0
- package/.next/server/app/projects/[projectId]/sessions/[id]/page.js.nft.json +1 -0
- package/.next/server/app/projects/[projectId]/sessions/[id]/page_client-reference-manifest.js +1 -0
- package/.next/server/app/projects/[projectId]/settings/page.js +2 -0
- package/.next/server/app/projects/[projectId]/settings/page.js.nft.json +1 -0
- package/.next/server/app/projects/[projectId]/settings/page_client-reference-manifest.js +1 -0
- package/.next/server/app/prs/page.js +2 -0
- package/.next/server/app/prs/page.js.nft.json +1 -0
- package/.next/server/app/prs/page_client-reference-manifest.js +1 -0
- package/.next/server/app/review/page.js +2 -0
- package/.next/server/app/review/page.js.nft.json +1 -0
- package/.next/server/app/review/page_client-reference-manifest.js +1 -0
- package/.next/server/app/reviews/page.js +2 -0
- package/.next/server/app/reviews/page.js.nft.json +1 -0
- package/.next/server/app/reviews/page_client-reference-manifest.js +1 -0
- package/.next/server/app/sessions/[id]/page.js +2 -0
- package/.next/server/app/sessions/[id]/page.js.nft.json +1 -0
- package/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -0
- package/.next/server/app/test-direct/page.js +2 -0
- package/.next/server/app/test-direct/page.js.nft.json +1 -0
- package/.next/server/app/test-direct/page_client-reference-manifest.js +1 -0
- package/.next/server/app/test-direct.html +1 -0
- package/.next/server/app/test-direct.meta +7 -0
- package/.next/server/app/test-direct.rsc +28 -0
- package/.next/server/app-paths-manifest.json +47 -0
- package/.next/server/chunks/1215.js +1 -0
- package/.next/server/chunks/1271.js +1 -0
- package/.next/server/chunks/2106.js +1 -0
- package/.next/server/chunks/2347.js +3 -0
- package/.next/server/chunks/2899.js +1 -0
- package/.next/server/chunks/2914.js +1 -0
- package/.next/server/chunks/4033.js +1 -0
- package/.next/server/chunks/4148.js +942 -0
- package/.next/server/chunks/4422.js +32 -0
- package/.next/server/chunks/5053.js +1 -0
- package/.next/server/chunks/5689.js +1 -0
- package/.next/server/chunks/6148.js +9 -0
- package/.next/server/chunks/6582.js +25 -0
- package/.next/server/chunks/7002.js +1 -0
- package/.next/server/chunks/7486.js +9 -0
- package/.next/server/chunks/8803.js +6 -0
- package/.next/server/chunks/9472.js +847 -0
- package/.next/server/chunks/9493.js +1 -0
- package/.next/server/chunks/9561.js +22 -0
- package/.next/server/chunks/966.js +1 -0
- package/.next/server/functions-config-manifest.json +4 -0
- package/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -0
- package/.next/server/middleware-manifest.json +6 -0
- package/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/.next/server/next-font-manifest.js +1 -0
- package/.next/server/next-font-manifest.json +1 -0
- package/.next/server/pages/404.html +1 -0
- package/.next/server/pages/500.html +1 -0
- package/.next/server/pages/_app.js +1 -0
- package/.next/server/pages/_app.js.nft.json +1 -0
- package/.next/server/pages/_document.js +1 -0
- package/.next/server/pages/_document.js.nft.json +1 -0
- package/.next/server/pages/_error.js +19 -0
- package/.next/server/pages/_error.js.nft.json +1 -0
- package/.next/server/pages-manifest.json +6 -0
- package/.next/server/server-reference-manifest.js +1 -0
- package/.next/server/server-reference-manifest.json +1 -0
- package/.next/server/webpack-runtime.js +1 -0
- package/.next/static/chunks/0f200859.359176a445d2791f.js +10 -0
- package/.next/static/chunks/1089-c6d7995c7c19039a.js +1 -0
- package/.next/static/chunks/1461-af7c54935f21d56d.js +1 -0
- package/.next/static/chunks/2073-4192de0bb00cc993.js +1 -0
- package/.next/static/chunks/3764.4c736d9a181489a4.js +1 -0
- package/.next/static/chunks/4115-1a4fa80ec67a29d3.js +1 -0
- package/.next/static/chunks/4751.6c71bfc0c4520627.js +1 -0
- package/.next/static/chunks/503.f7ff284457dd9c40.js +1 -0
- package/.next/static/chunks/5204.7de7e266895bced7.js +1 -0
- package/.next/static/chunks/6835.7a29fa4b665b7c2f.js +1 -0
- package/.next/static/chunks/7008-0d9bee1bf4bfcbea.js +1 -0
- package/.next/static/chunks/7317.685aa5231218e8d3.js +1 -0
- package/.next/static/chunks/8204-7c7837ed694da99c.js +1 -0
- package/.next/static/chunks/8713-d3d663f55dc00e48.js +1 -0
- package/.next/static/chunks/8759-490573536f93f85c.js +1 -0
- package/.next/static/chunks/88a6fc35-f836b4b72df5eafa.js +1 -0
- package/.next/static/chunks/9531-a5175e55fa0db48d.js +1 -0
- package/.next/static/chunks/9876-de0c5a1a319b4e8e.js +1 -0
- package/.next/static/chunks/app/_not-found/page-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/backlog/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/browse-directory/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/filesystem/browse/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/issues/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/observability/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/orchestrators/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/projects/[id]/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/projects/reload/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/projects/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/prs/[id]/merge/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/reviews/execute/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/reviews/findings/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/reviews/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/reviews/send/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/runtime/terminal/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/kill/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/message/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/remap/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/restore/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/send/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/patches/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/setup-labels/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/spawn/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/update/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/verify/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/version/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/api/webhooks/[...slug]/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/apple-icon/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/dev/terminal-test/page-d0132109f9d8524e.js +1 -0
- package/.next/static/chunks/app/error-d632d0714b987864.js +1 -0
- package/.next/static/chunks/app/global-error-f6bef179169bcdae.js +1 -0
- package/.next/static/chunks/app/icon/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/icon-192/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/icon-512/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/layout-5cac6fe817194d7a.js +1 -0
- package/.next/static/chunks/app/loading-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/manifest.webmanifest/route-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/not-found-cba3f587e1f98dcb.js +1 -0
- package/.next/static/chunks/app/page-cf7bccb75990950d.js +1 -0
- package/.next/static/chunks/app/projects/[projectId]/layout-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/projects/[projectId]/loading-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/projects/[projectId]/page-039a93b16089ed57.js +1 -0
- package/.next/static/chunks/app/projects/[projectId]/sessions/[id]/page-043b525bedb8f0f7.js +1 -0
- package/.next/static/chunks/app/projects/[projectId]/settings/page-63572555892d7a61.js +1 -0
- package/.next/static/chunks/app/projects/layout-d43b2e38d46221bd.js +1 -0
- package/.next/static/chunks/app/prs/page-e447852fbe0c6ee4.js +1 -0
- package/.next/static/chunks/app/review/page-022b2d2c326ff413.js +1 -0
- package/.next/static/chunks/app/reviews/page-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/sessions/[id]/error-67c0d27f977a1cc1.js +1 -0
- package/.next/static/chunks/app/sessions/[id]/loading-6add9dacf1870b4b.js +1 -0
- package/.next/static/chunks/app/sessions/[id]/not-found-cba3f587e1f98dcb.js +1 -0
- package/.next/static/chunks/app/sessions/[id]/page-863cf8dd2c76d06d.js +1 -0
- package/.next/static/chunks/app/test-direct/page-8b80ed180c0f2f42.js +1 -0
- package/.next/static/chunks/e12b4bb0.8742134e1ac0263f.js +58 -0
- package/.next/static/chunks/framework-7060e2ac4971c604.js +1 -0
- package/.next/static/chunks/main-app-162601c3f1c01b19.js +1 -0
- package/.next/static/chunks/main-ed1610689fbd6f0d.js +1 -0
- package/.next/static/chunks/pages/_app-f4baf4dbe88f6f54.js +1 -0
- package/.next/static/chunks/pages/_error-a7f6723f42093f29.js +1 -0
- package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/.next/static/chunks/webpack-f9566aaa604a1b07.js +1 -0
- package/.next/static/css/0c9b7451c2ce7c02.css +1 -0
- package/.next/static/css/7ca4e3753c1c7833.css +1 -0
- package/.next/static/css/b4a15f23f468892a.css +1 -0
- package/.next/static/css/d06ee45019116677.css +1 -0
- package/.next/static/media/91601dd83defba07-s.p.woff2 +0 -0
- package/.next/static/media/aa8291c31d4e9e54-s.p.woff2 +0 -0
- package/.next/static/pROr0laPuZIdA4NYNygMD/_buildManifest.js +1 -0
- package/.next/static/pROr0laPuZIdA4NYNygMD/_ssgManifest.js +1 -0
- package/LICENSE +22 -0
- package/dist-server/direct-terminal-ws.js +109 -0
- package/dist-server/mux-websocket.js +1162 -0
- package/dist-server/single-port-server.js +305 -0
- package/dist-server/start-all.js +150 -0
- package/dist-server/terminal-observability.js +16 -0
- package/dist-server/tmux-utils.js +301 -0
- package/next.config.js +71 -0
- package/package.json +97 -0
|
@@ -0,0 +1,847 @@
|
|
|
1
|
+
"use strict";exports.id=9472,exports.ids=[9472],exports.modules={49472:(a,b,c)=>{c.d(b,{ix:()=>cz,wp:()=>cB,Z1:()=>cp,uj:()=>cA,g8:()=>cq,Az:()=>cu});var d=c(43780),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:///home/slievr/proj/Athene/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);function G(a){return a.replace(/\\/g,"/").replace(/[^a-zA-Z0-9-]/g,"-")}async function H(a){try{return await (0,E.realpath)(a)}catch{return a}}let I=new Set;async function J(a,b){let c;if(b){let c=(0,k.join)(a,`${b}.jsonl`);try{return await (0,E.stat)(c),c}catch{}}try{c=await (0,E.readdir)(a)}catch(b){if(b instanceof Error&&"code"in b&&"ENOENT"!==b.code&&!I.has(a)){I.add(a);let c=b.code;console.warn(`[claude-code] failed to read ${a} (${c}): ${b.message}. Session activity will fall back to AO JSONL only. (This warning is shown once per path for the process lifetime.)`)}return null}let d=c.filter(a=>a.endsWith(".jsonl")&&!a.startsWith("agent-"));if(0===d.length)return null;let e=await Promise.all(d.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 e.sort((a,b)=>b.mtime-a.mtime),e[0]?.path??null}let K=null;async function L(){if((0,d.uFH)())return"";let a=Date.now();if(K&&a-K.timestamp<5e3)return K.promise?K.promise:K.output;let b=F("ps",["-eo","pid,tty,args"],{timeout:3e4}).then(({stdout:a})=>(K?.promise===b&&(K={output:a||d.HkR,timestamp:Date.now()}),a||d.HkR)).catch(()=>(K?.promise===b&&(K={output:d.HkR,timestamp:Date.now()}),d.HkR));return K={output:"",timestamp:a,promise:b},b}async function M(a){try{if("tmux"===a.runtimeName&&a.id){if((0,d.uFH)())return null;let{stdout:b}=await F("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 null;let e=await L();if(e===d.HkR)return d.HkR;let f=new Set(c.map(a=>a.replace(/^\/dev\//,""))),g=/(?:^|\/)(?:\.)?claude(?:[-.][\w-]+)*(?:[\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 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 d.HkR}}async function N(a){let b=await M(a);return b===d.HkR?d.HkR:null!==b}let O=new Set(["permission-mode","ai-title","agent-color","agent-name","custom-title","pr-link"]);async function P(a,b,c=N){let e=b??d.PES,f=new Date;if(!a.runtimeHandle)return{state:"exited",timestamp:f};let g=await c(a.runtimeHandle);if(g===d.HkR)return null;if(!g)return{state:"exited",timestamp:f};if(!a.workspacePath)return null;let h=G(await H(a.workspacePath)),i=(0,k.join)((0,j.homedir)(),".claude","projects",h),l=a.metadata?.claudeSessionUuid,m="string"==typeof l&&l.trim()?l.trim():void 0,n=await J(i,m),o=null;if(n){let b=await (0,d.XIc)(n);if(b)if(a.createdAt&&b.modifiedAt<a.createdAt)o={state:"idle",timestamp:a.createdAt};else if(b.lastType&&O.has(b.lastType))o={state:"idle",timestamp:a.createdAt};else{let a=Date.now()-b.modifiedAt.getTime(),c=b.modifiedAt,f=Math.min(d.V1$,e);switch(b.lastType){case"user":case"progress":default:if(a<=f)return{state:"active",timestamp:c};return{state:a>e?"idle":"ready",timestamp:c};case"system":if("api_error"===b.lastSubtype&&"error"===b.lastLevel)return{state:"blocked",timestamp:c};return{state:a>e?"idle":"ready",timestamp:c};case"assistant":case"summary":case"file-history-snapshot":case"attachment":case"queue-operation":case"last-prompt":return{state:a>e?"idle":"ready",timestamp:c}}}}let p=await (0,d.Ahw)(a.workspacePath),q=(0,d.Bmx)(p);if(q)return q;let r=Math.min(d.V1$,e),s=(0,d.Vo2)(p,r,e);return s||o||null}let Q=`#!/usr/bin/env bash
|
|
11
|
+
# Metadata Updater Hook for Athene
|
|
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
|
+
# Append to prs field (comma-separated list of all PR URLs for this session).
|
|
147
|
+
# Supports multiple PRs per session — same repo or different repos.
|
|
148
|
+
existing_prs=""
|
|
149
|
+
if is_json_metadata; then
|
|
150
|
+
if command -v jq &>/dev/null; then
|
|
151
|
+
existing_prs=$(jq -r '.prs // empty' "$metadata_file" 2>/dev/null || echo "")
|
|
152
|
+
else
|
|
153
|
+
existing_prs=$(node -e "
|
|
154
|
+
const fs = require('fs');
|
|
155
|
+
const d = JSON.parse(fs.readFileSync(process.argv[1], 'utf8'));
|
|
156
|
+
process.stdout.write(d.prs || '');
|
|
157
|
+
" "$metadata_file" 2>/dev/null || echo "")
|
|
158
|
+
fi
|
|
159
|
+
else
|
|
160
|
+
existing_prs=$(grep '^prs=' "$metadata_file" 2>/dev/null | cut -d'=' -f2- || echo "")
|
|
161
|
+
fi
|
|
162
|
+
if [[ -z "$existing_prs" ]]; then
|
|
163
|
+
new_prs="$pr_url"
|
|
164
|
+
else
|
|
165
|
+
# Only append if not already present (exact comma-delimited match to avoid /pull/1 matching /pull/10)
|
|
166
|
+
if ! echo ",$existing_prs," | grep -qF ",$pr_url,"; then
|
|
167
|
+
new_prs="$existing_prs,$pr_url"
|
|
168
|
+
else
|
|
169
|
+
new_prs="$existing_prs"
|
|
170
|
+
fi
|
|
171
|
+
fi
|
|
172
|
+
update_metadata_key "prs" "$new_prs"
|
|
173
|
+
update_metadata_key "status" "pr_open"
|
|
174
|
+
echo '{"systemMessage": "Updated metadata: PR created at '"$pr_url"'"}'
|
|
175
|
+
exit 0
|
|
176
|
+
fi
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
# Detect: git checkout -b <branch> or git switch -c <branch>
|
|
180
|
+
if [[ "$clean_command" =~ ^git[[:space:]]+checkout[[:space:]]+-b[[:space:]]+([^[:space:]]+) ]] || \\
|
|
181
|
+
[[ "$clean_command" =~ ^git[[:space:]]+switch[[:space:]]+-c[[:space:]]+([^[:space:]]+) ]]; then
|
|
182
|
+
branch="\${BASH_REMATCH[1]}"
|
|
183
|
+
|
|
184
|
+
if [[ -n "$branch" ]]; then
|
|
185
|
+
update_metadata_key "branch" "$branch"
|
|
186
|
+
echo '{"systemMessage": "Updated metadata: branch = '"$branch"'"}'
|
|
187
|
+
exit 0
|
|
188
|
+
fi
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
# Detect: git checkout <branch> (without -b) or git switch <branch> (without -c)
|
|
192
|
+
# Only update if the branch name looks like a feature branch (contains / or -)
|
|
193
|
+
if [[ "$clean_command" =~ ^git[[:space:]]+checkout[[:space:]]+([^[:space:]-]+[/-][^[:space:]]+) ]] || \\
|
|
194
|
+
[[ "$clean_command" =~ ^git[[:space:]]+switch[[:space:]]+([^[:space:]-]+[/-][^[:space:]]+) ]]; then
|
|
195
|
+
branch="\${BASH_REMATCH[1]}"
|
|
196
|
+
|
|
197
|
+
# Avoid updating for checkout of commits/tags
|
|
198
|
+
if [[ -n "$branch" && "$branch" != "HEAD" ]]; then
|
|
199
|
+
update_metadata_key "branch" "$branch"
|
|
200
|
+
echo '{"systemMessage": "Updated metadata: branch = '"$branch"'"}'
|
|
201
|
+
exit 0
|
|
202
|
+
fi
|
|
203
|
+
fi
|
|
204
|
+
|
|
205
|
+
# Detect: gh pr merge
|
|
206
|
+
if [[ "$clean_command" =~ ^gh[[:space:]]+pr[[:space:]]+merge ]]; then
|
|
207
|
+
update_metadata_key "status" "merged"
|
|
208
|
+
echo '{"systemMessage": "Updated metadata: status = merged"}'
|
|
209
|
+
exit 0
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
# No matching command, exit silently
|
|
213
|
+
echo '{}'
|
|
214
|
+
exit 0
|
|
215
|
+
`,R=`#!/usr/bin/env node
|
|
216
|
+
// Metadata Updater Hook for Athene (Node.js — Windows)
|
|
217
|
+
//
|
|
218
|
+
// This PostToolUse hook automatically updates session metadata when:
|
|
219
|
+
// - gh pr create: extracts PR URL and writes to metadata
|
|
220
|
+
// - git checkout -b / git switch -c: extracts branch name and writes to metadata
|
|
221
|
+
// - gh pr merge: updates status to "merged"
|
|
222
|
+
|
|
223
|
+
const { readFileSync, writeFileSync, renameSync, existsSync, realpathSync } = require("node:fs");
|
|
224
|
+
const { join, sep, resolve: resolvePath } = require("node:path");
|
|
225
|
+
const os = require("node:os");
|
|
226
|
+
|
|
227
|
+
const AO_DATA_DIR = process.env.AO_DATA_DIR || join(process.env.HOME || process.env.USERPROFILE || "", ".ao-sessions");
|
|
228
|
+
const AO_SESSION = process.env.AO_SESSION || "";
|
|
229
|
+
|
|
230
|
+
// Read hook input from stdin (fd 0 is cross-platform, no /dev/stdin needed)
|
|
231
|
+
let inputRaw = "";
|
|
232
|
+
try {
|
|
233
|
+
inputRaw = readFileSync(0, "utf-8");
|
|
234
|
+
} catch {
|
|
235
|
+
inputRaw = "";
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
let input;
|
|
239
|
+
try {
|
|
240
|
+
input = JSON.parse(inputRaw || "{}");
|
|
241
|
+
} catch {
|
|
242
|
+
process.stdout.write("{}\\n");
|
|
243
|
+
process.exit(0);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const toolName = input.tool_name || "";
|
|
247
|
+
const command = (input.tool_input && input.tool_input.command) || "";
|
|
248
|
+
const output = input.tool_response || "";
|
|
249
|
+
const exitCode = typeof input.exit_code === "number" ? input.exit_code : 0;
|
|
250
|
+
|
|
251
|
+
// Only process successful commands
|
|
252
|
+
if (exitCode !== 0) {
|
|
253
|
+
process.stdout.write("{}\\n");
|
|
254
|
+
process.exit(0);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Only process Bash tool calls
|
|
258
|
+
if (toolName !== "Bash") {
|
|
259
|
+
process.stdout.write("{}\\n");
|
|
260
|
+
process.exit(0);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Validate AO_SESSION is set
|
|
264
|
+
if (!AO_SESSION) {
|
|
265
|
+
process.stdout.write(JSON.stringify({ systemMessage: "AO_SESSION environment variable not set, skipping metadata update" }) + "\\n");
|
|
266
|
+
process.exit(0);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Validate AO_SESSION contains no path traversal components
|
|
270
|
+
if (AO_SESSION.includes("/") || AO_SESSION.includes("\\\\") || AO_SESSION.includes("..")) {
|
|
271
|
+
process.stdout.write(JSON.stringify({ systemMessage: "AO_SESSION contains invalid path characters, skipping metadata update" }) + "\\n");
|
|
272
|
+
process.exit(0);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Validate AO_DATA_DIR is within an allowed base directory (mirrors ao-metadata-helper.sh)
|
|
276
|
+
const home = os.homedir();
|
|
277
|
+
let resolvedAoDir;
|
|
278
|
+
try { resolvedAoDir = realpathSync(AO_DATA_DIR); } catch { resolvedAoDir = resolvePath(AO_DATA_DIR); }
|
|
279
|
+
const allowedBases = [join(home, ".ao"), join(home, ".agent-orchestrator"), os.tmpdir()];
|
|
280
|
+
if (!allowedBases.some((a) => resolvedAoDir === a || resolvedAoDir.startsWith(a + sep))) {
|
|
281
|
+
process.stdout.write(JSON.stringify({ systemMessage: "AO_DATA_DIR is outside allowed directories, skipping metadata update" }) + "\\n");
|
|
282
|
+
process.exit(0);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const metadataFile = join(AO_DATA_DIR, AO_SESSION);
|
|
286
|
+
|
|
287
|
+
if (!existsSync(metadataFile)) {
|
|
288
|
+
process.stdout.write(JSON.stringify({ systemMessage: "Metadata file not found: " + metadataFile }) + "\\n");
|
|
289
|
+
process.exit(0);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Update or append a key=value line in the metadata file (atomic via temp file).
|
|
294
|
+
*/
|
|
295
|
+
function updateMetadataKey(key, value) {
|
|
296
|
+
const lines = readFileSync(metadataFile, "utf-8").split("\\n");
|
|
297
|
+
let found = false;
|
|
298
|
+
const updated = lines.map((line) => {
|
|
299
|
+
if (line.startsWith(key + "=")) {
|
|
300
|
+
found = true;
|
|
301
|
+
return key + "=" + value;
|
|
302
|
+
}
|
|
303
|
+
return line;
|
|
304
|
+
});
|
|
305
|
+
if (!found) {
|
|
306
|
+
// Insert before the trailing empty line (if any) so the file ends cleanly
|
|
307
|
+
updated.push(key + "=" + value);
|
|
308
|
+
}
|
|
309
|
+
const tmpFile = metadataFile + ".tmp." + process.pid;
|
|
310
|
+
writeFileSync(tmpFile, updated.join("\\n"), "utf-8");
|
|
311
|
+
renameSync(tmpFile, metadataFile);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Strip leading cd ... && / cd ... ; prefixes (agents frequently cd into a
|
|
315
|
+
// worktree before running the real command)
|
|
316
|
+
let cleanCommand = command;
|
|
317
|
+
const cdPrefixRe = /^\\s*cd\\s+\\S.*?\\s+(?:&&|;)\\s+(.*)/;
|
|
318
|
+
let m;
|
|
319
|
+
while ((m = cdPrefixRe.exec(cleanCommand)) !== null && /^\\s*cd\\s/.test(cleanCommand)) {
|
|
320
|
+
cleanCommand = m[1];
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Detect: gh pr create
|
|
324
|
+
if (/^gh\\s+pr\\s+create/.test(cleanCommand)) {
|
|
325
|
+
const prMatch = output.match(/https:\\/\\/github[.]com\\/[^/]+\\/[^/]+\\/pull\\/\\d+/);
|
|
326
|
+
if (prMatch) {
|
|
327
|
+
const prUrl = prMatch[0];
|
|
328
|
+
let existingPrs = "";
|
|
329
|
+
try {
|
|
330
|
+
const raw = readFileSync(metadataFile, "utf-8");
|
|
331
|
+
if (metadataFile.endsWith(".json")) {
|
|
332
|
+
existingPrs = JSON.parse(raw).prs || "";
|
|
333
|
+
} else {
|
|
334
|
+
const prsLine = raw.split("\\n").find((l) => l.startsWith("prs="));
|
|
335
|
+
existingPrs = prsLine ? prsLine.slice(4) : "";
|
|
336
|
+
}
|
|
337
|
+
} catch {}
|
|
338
|
+
const newPrs = !existingPrs
|
|
339
|
+
? prUrl
|
|
340
|
+
: existingPrs.split(",").map((u) => u.trim()).includes(prUrl)
|
|
341
|
+
? existingPrs
|
|
342
|
+
: existingPrs + "," + prUrl;
|
|
343
|
+
updateMetadataKey("pr", prUrl);
|
|
344
|
+
updateMetadataKey("prs", newPrs);
|
|
345
|
+
updateMetadataKey("status", "pr_open");
|
|
346
|
+
process.stdout.write(JSON.stringify({ systemMessage: "Updated metadata: PR created at " + prUrl }) + "\\n");
|
|
347
|
+
process.exit(0);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Detect: git checkout -b <branch> or git switch -c <branch>
|
|
352
|
+
const checkoutNewBranch = cleanCommand.match(/^git\\s+checkout\\s+-b\\s+(\\S+)/) ||
|
|
353
|
+
cleanCommand.match(/^git\\s+switch\\s+-c\\s+(\\S+)/);
|
|
354
|
+
if (checkoutNewBranch) {
|
|
355
|
+
const branch = checkoutNewBranch[1];
|
|
356
|
+
if (branch) {
|
|
357
|
+
updateMetadataKey("branch", branch);
|
|
358
|
+
process.stdout.write(JSON.stringify({ systemMessage: "Updated metadata: branch = " + branch }) + "\\n");
|
|
359
|
+
process.exit(0);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Detect: git checkout <branch> or git switch <branch> (without -b/-c)
|
|
364
|
+
// Only update if branch looks like a feature branch (contains / or -)
|
|
365
|
+
const checkoutBranch = cleanCommand.match(/^git\\s+checkout\\s+([^\\s-]+[/-][^\\s]+)/) ||
|
|
366
|
+
cleanCommand.match(/^git\\s+switch\\s+([^\\s-]+[/-][^\\s]+)/);
|
|
367
|
+
if (checkoutBranch) {
|
|
368
|
+
const branch = checkoutBranch[1];
|
|
369
|
+
if (branch && branch !== "HEAD") {
|
|
370
|
+
updateMetadataKey("branch", branch);
|
|
371
|
+
process.stdout.write(JSON.stringify({ systemMessage: "Updated metadata: branch = " + branch }) + "\\n");
|
|
372
|
+
process.exit(0);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Detect: gh pr merge
|
|
377
|
+
if (/^gh\\s+pr\\s+merge/.test(cleanCommand)) {
|
|
378
|
+
updateMetadataKey("status", "merged");
|
|
379
|
+
process.stdout.write(JSON.stringify({ systemMessage: "Updated metadata: status = merged" }) + "\\n");
|
|
380
|
+
process.exit(0);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// No matching command
|
|
384
|
+
process.stdout.write("{}\\n");
|
|
385
|
+
process.exit(0);
|
|
386
|
+
`,S=`#!/usr/bin/env bash
|
|
387
|
+
# Activity Updater Hook for Athene
|
|
388
|
+
#
|
|
389
|
+
# Records Claude Code lifecycle events to {workspace}/.ao/activity.jsonl so
|
|
390
|
+
# the dashboard / lifecycle reducer derives activity state from authoritative
|
|
391
|
+
# platform events instead of regex over rendered terminal output. (#1941)
|
|
392
|
+
|
|
393
|
+
set -uo pipefail
|
|
394
|
+
|
|
395
|
+
input=$(cat)
|
|
396
|
+
|
|
397
|
+
if command -v jq &>/dev/null; then
|
|
398
|
+
event=$(printf '%s' "$input" | jq -r '.hook_event_name // empty')
|
|
399
|
+
notif_type=$(printf '%s' "$input" | jq -r '.notification_type // empty')
|
|
400
|
+
tool_name=$(printf '%s' "$input" | jq -r '.tool_name // empty')
|
|
401
|
+
error_type=$(printf '%s' "$input" | jq -r '.error_type // empty')
|
|
402
|
+
else
|
|
403
|
+
event=$(printf '%s' "$input" | grep -o '"hook_event_name"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4)
|
|
404
|
+
notif_type=$(printf '%s' "$input" | grep -o '"notification_type"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4)
|
|
405
|
+
tool_name=$(printf '%s' "$input" | grep -o '"tool_name"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4)
|
|
406
|
+
error_type=$(printf '%s' "$input" | grep -o '"error_type"[[:space:]]*:[[:space:]]*"[^"]*"' | cut -d'"' -f4)
|
|
407
|
+
fi
|
|
408
|
+
|
|
409
|
+
state=""
|
|
410
|
+
trigger=""
|
|
411
|
+
case "$event" in
|
|
412
|
+
SessionStart|Stop|SubagentStop)
|
|
413
|
+
state="ready"
|
|
414
|
+
trigger="$event"
|
|
415
|
+
;;
|
|
416
|
+
UserPromptSubmit|PreToolUse|PostToolUse|PostToolUseFailure|PreCompact|PostCompact|SubagentStart|PostToolBatch)
|
|
417
|
+
state="active"
|
|
418
|
+
trigger="$event"
|
|
419
|
+
;;
|
|
420
|
+
PermissionRequest)
|
|
421
|
+
state="waiting_input"
|
|
422
|
+
if [[ -n "$tool_name" ]]; then
|
|
423
|
+
trigger="PermissionRequest ($tool_name)"
|
|
424
|
+
else
|
|
425
|
+
trigger="PermissionRequest"
|
|
426
|
+
fi
|
|
427
|
+
;;
|
|
428
|
+
Notification)
|
|
429
|
+
if [[ "$notif_type" == "permission_prompt" || "$notif_type" == "idle_prompt" ]]; then
|
|
430
|
+
state="waiting_input"
|
|
431
|
+
trigger="Notification ($notif_type)"
|
|
432
|
+
else
|
|
433
|
+
# auth_success / elicitation_* / unrecognized — not an activity transition
|
|
434
|
+
echo '{}'
|
|
435
|
+
exit 0
|
|
436
|
+
fi
|
|
437
|
+
;;
|
|
438
|
+
StopFailure)
|
|
439
|
+
state="blocked"
|
|
440
|
+
if [[ -n "$error_type" ]]; then
|
|
441
|
+
trigger="StopFailure ($error_type)"
|
|
442
|
+
else
|
|
443
|
+
trigger="StopFailure"
|
|
444
|
+
fi
|
|
445
|
+
;;
|
|
446
|
+
*)
|
|
447
|
+
echo '{}'
|
|
448
|
+
exit 0
|
|
449
|
+
;;
|
|
450
|
+
esac
|
|
451
|
+
|
|
452
|
+
workspace="\${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
453
|
+
log_dir="$workspace/.ao"
|
|
454
|
+
log_file="$log_dir/activity.jsonl"
|
|
455
|
+
|
|
456
|
+
mkdir -p "$log_dir" 2>/dev/null || { echo '{}'; exit 0; }
|
|
457
|
+
|
|
458
|
+
# Node is a hard runtime dep of Claude Code, so node -p is always available
|
|
459
|
+
# and gives millisecond-precision ISO timestamps matching the rest of the
|
|
460
|
+
# activity-JSONL log. Fall back to seconds-precision date for the unlikely
|
|
461
|
+
# case where node is unavailable (still valid ISO 8601).
|
|
462
|
+
ts=$(node -p 'new Date().toISOString()' 2>/dev/null || date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
463
|
+
|
|
464
|
+
# Escape JSON-special characters in the trigger value. Triggers are bounded
|
|
465
|
+
# today to event/tool/error names (no control chars in practice) but escape
|
|
466
|
+
# defensively — \\ and " for content, plus the five common control chars
|
|
467
|
+
# (\\n \\r \\t \\b \\f) so the JSONL line stays parseable for any future
|
|
468
|
+
# trigger source. Matches what Node's JSON.stringify produces in the .cjs
|
|
469
|
+
# variant so both implementations stay in lockstep.
|
|
470
|
+
escape_json() {
|
|
471
|
+
local s="$1"
|
|
472
|
+
s="\${s//\\\\/\\\\\\\\}"
|
|
473
|
+
s="\${s//\\"/\\\\\\"}"
|
|
474
|
+
s="\${s//$'\\n'/\\\\n}"
|
|
475
|
+
s="\${s//$'\\r'/\\\\r}"
|
|
476
|
+
s="\${s//$'\\t'/\\\\t}"
|
|
477
|
+
s="\${s//$'\\b'/\\\\b}"
|
|
478
|
+
s="\${s//$'\\f'/\\\\f}"
|
|
479
|
+
printf '%s' "$s"
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if [[ "$state" == "waiting_input" || "$state" == "blocked" ]]; then
|
|
483
|
+
esc_trigger=$(escape_json "$trigger")
|
|
484
|
+
printf '{"ts":"%s","state":"%s","source":"hook","trigger":"%s"}\\n' "$ts" "$state" "$esc_trigger" >> "$log_file"
|
|
485
|
+
else
|
|
486
|
+
printf '{"ts":"%s","state":"%s","source":"hook"}\\n' "$ts" "$state" >> "$log_file"
|
|
487
|
+
fi
|
|
488
|
+
|
|
489
|
+
echo '{}'
|
|
490
|
+
exit 0
|
|
491
|
+
`,T=`#!/usr/bin/env node
|
|
492
|
+
// Activity Updater Hook for Athene (Node.js — Windows). See
|
|
493
|
+
// ACTIVITY_UPDATER_SCRIPT for the canonical bash version. (#1941)
|
|
494
|
+
|
|
495
|
+
const { appendFileSync, mkdirSync, readFileSync } = require("node:fs");
|
|
496
|
+
const { join } = require("node:path");
|
|
497
|
+
|
|
498
|
+
let inputRaw = "";
|
|
499
|
+
try {
|
|
500
|
+
inputRaw = readFileSync(0, "utf-8");
|
|
501
|
+
} catch {
|
|
502
|
+
process.stdout.write("{}\\n");
|
|
503
|
+
process.exit(0);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
let payload;
|
|
507
|
+
try {
|
|
508
|
+
payload = JSON.parse(inputRaw || "{}");
|
|
509
|
+
} catch {
|
|
510
|
+
process.stdout.write("{}\\n");
|
|
511
|
+
process.exit(0);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const event = typeof payload.hook_event_name === "string" ? payload.hook_event_name : "";
|
|
515
|
+
const notifType = typeof payload.notification_type === "string" ? payload.notification_type : "";
|
|
516
|
+
const toolName = typeof payload.tool_name === "string" ? payload.tool_name : "";
|
|
517
|
+
const errorType = typeof payload.error_type === "string" ? payload.error_type : "";
|
|
518
|
+
|
|
519
|
+
let state = "";
|
|
520
|
+
let trigger = "";
|
|
521
|
+
switch (event) {
|
|
522
|
+
case "SessionStart":
|
|
523
|
+
case "Stop":
|
|
524
|
+
case "SubagentStop":
|
|
525
|
+
state = "ready";
|
|
526
|
+
trigger = event;
|
|
527
|
+
break;
|
|
528
|
+
case "UserPromptSubmit":
|
|
529
|
+
case "PreToolUse":
|
|
530
|
+
case "PostToolUse":
|
|
531
|
+
case "PostToolUseFailure":
|
|
532
|
+
case "PreCompact":
|
|
533
|
+
case "PostCompact":
|
|
534
|
+
case "SubagentStart":
|
|
535
|
+
case "PostToolBatch":
|
|
536
|
+
state = "active";
|
|
537
|
+
trigger = event;
|
|
538
|
+
break;
|
|
539
|
+
case "PermissionRequest":
|
|
540
|
+
state = "waiting_input";
|
|
541
|
+
trigger = toolName ? \`PermissionRequest (\${toolName})\` : "PermissionRequest";
|
|
542
|
+
break;
|
|
543
|
+
case "Notification":
|
|
544
|
+
if (notifType === "permission_prompt" || notifType === "idle_prompt") {
|
|
545
|
+
state = "waiting_input";
|
|
546
|
+
trigger = \`Notification (\${notifType})\`;
|
|
547
|
+
} else {
|
|
548
|
+
process.stdout.write("{}\\n");
|
|
549
|
+
process.exit(0);
|
|
550
|
+
}
|
|
551
|
+
break;
|
|
552
|
+
case "StopFailure":
|
|
553
|
+
state = "blocked";
|
|
554
|
+
trigger = errorType ? \`StopFailure (\${errorType})\` : "StopFailure";
|
|
555
|
+
break;
|
|
556
|
+
default:
|
|
557
|
+
process.stdout.write("{}\\n");
|
|
558
|
+
process.exit(0);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
const workspace = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
562
|
+
const logDir = join(workspace, ".ao");
|
|
563
|
+
const logFile = join(logDir, "activity.jsonl");
|
|
564
|
+
|
|
565
|
+
try {
|
|
566
|
+
mkdirSync(logDir, { recursive: true });
|
|
567
|
+
} catch {
|
|
568
|
+
process.stdout.write("{}\\n");
|
|
569
|
+
process.exit(0);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
const ts = new Date().toISOString();
|
|
573
|
+
const entry =
|
|
574
|
+
state === "waiting_input" || state === "blocked"
|
|
575
|
+
? { ts, state, source: "hook", trigger }
|
|
576
|
+
: { ts, state, source: "hook" };
|
|
577
|
+
|
|
578
|
+
try {
|
|
579
|
+
appendFileSync(logFile, JSON.stringify(entry) + "\\n", "utf-8");
|
|
580
|
+
} catch {
|
|
581
|
+
// Best-effort — never block Claude on log append failure
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
process.stdout.write("{}\\n");
|
|
585
|
+
process.exit(0);
|
|
586
|
+
`;async function U(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}async function V(a){let b,c,e=(0,k.join)(a,".claude"),f=(0,k.join)(e,"settings.json");try{await (0,E.mkdir)(e,{recursive:!0})}catch{}if((0,d.uFH)()){let a=(0,k.join)(e,"metadata-updater.cjs"),d=(0,k.join)(e,"activity-updater.cjs");await (0,E.writeFile)(a,R,"utf-8"),await (0,E.writeFile)(d,T,"utf-8"),b="node .claude/metadata-updater.cjs",c="node .claude/activity-updater.cjs"}else{let a=(0,k.join)(e,"metadata-updater.sh"),d=(0,k.join)(e,"activity-updater.sh");await (0,E.writeFile)(a,Q,"utf-8"),await (0,E.writeFile)(d,S,"utf-8"),await (0,E.chmod)(a,493),await (0,E.chmod)(d,493),b=".claude/metadata-updater.sh",c=".claude/activity-updater.sh"}let g={};if((0,i.existsSync)(f))try{let a=await (0,E.readFile)(f,"utf-8");g=JSON.parse(a)}catch{}let h=g.hooks??{};for(let a of function(a,b){let c=["activity-updater.sh","activity-updater.cjs"],d=[{event:"PostToolUse",matcher:"Bash",command:a,timeout:5e3,identifiers:["metadata-updater.sh","metadata-updater.cjs","metadata-updater.js"]}];for(let a of["SessionStart","UserPromptSubmit","PreToolUse","PostToolUse","PostToolUseFailure","PostToolBatch","Notification","PermissionRequest","Stop","StopFailure","SubagentStart","SubagentStop","PreCompact","PostCompact"])d.push({event:a,matcher:"",command:b,timeout:2e3,identifiers:c});return d}(b,c))!function(a,b){let c=a[b.event],d=Array.isArray(c)?c:[],e=-1,f=-1;for(let a=0;a<d.length;a++){let c=d[a];if("object"!=typeof c||null===c||Array.isArray(c))continue;let g=c.hooks;if(Array.isArray(g)){for(let c=0;c<g.length;c++){let d=g[c];if("object"!=typeof d||null===d||Array.isArray(d))continue;let h=d.command;if("string"==typeof h&&b.identifiers.some(a=>h.includes(a))){e=a,f=c;break}}if(e>=0)break}}if(-1===e)d.push({matcher:b.matcher,hooks:[{type:"command",command:b.command,timeout:b.timeout}]});else{let a=d[e],c=a.hooks;c[f].command=b.command,c[f].timeout=b.timeout,1===c.length&&(a.matcher=b.matcher)}a[b.event]=d}(h,a);g.hooks=h,await (0,E.writeFile)(f,JSON.stringify(g,null,2)+"\n","utf-8")}let W={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=>"idle",isProcessRunning:async a=>N(a),async getActivityState(a,b){return P(a,b,a=>this.isProcessRunning(a))},async getSessionInfo(a){if(!a.workspacePath)return null;let b=G(await H(a.workspacePath)),c=(0,k.join)((0,j.homedir)(),".claude","projects",b),d=await J(c);if(!d)return null;let e=await U(d);if(0===e.length)return null;let f=(0,k.basename)(d,".jsonl"),g=function(a){for(let b=a.length-1;b>=0;b--){let c=a[b];if(c?.type==="summary"&&c.summary)return{summary:c.summary,isFallback:!1}}for(let b of a)if(b?.type==="user"&&b.message?.content&&"string"==typeof b.message.content){let a=b.message.content.trim();if(a.length>0)return{summary:a.length>120?a.substring(0,120)+"...":a,isFallback:!0}}return null}(e);return{summary:g?.summary??null,summaryIsFallback:g?.isFallback,agentSessionId:f,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=G(await H(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 V(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 X=c(46193),Y=c(80481);c(78474).EventEmitter;let Z=(0,f.promisify)(e.execFile),$=(0,k.join)((0,j.homedir)(),".codex","sessions");function _(a){return a.payload??a}async function aa(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 aa(c,b+1);d.push(...a)}}catch{}}return d}async function ab(a,b){let c=await (0,E.open)(a,"r"),d=[],e="",f=new X.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 ac(a){return a.replace(/\\/g,"/").replace(/^([a-zA-Z]):/,(a,b)=>b.toLowerCase()+":")}async function ad(a,b){let c=ac(b);try{for(let b of(await ab(a,10)))try{let a=JSON.parse(b);if("object"==typeof a&&null!==a&&!Array.isArray(a)){let b=_(a);if("session_meta"===a.type&&"string"==typeof b.cwd&&ac(b.cwd)===c)return!0}}catch{}}catch{}return!1}async function ae(a,b){if(0===(b??=await aa($)).length)return null;let c=null;for(let d of b)if(await ad(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 af(a,b){let c=(b??=await aa($)).filter(b=>(0,k.basename)(b).endsWith(`-${a}.jsonl`));if(0===c.length)return null;if(1===c.length)return c[0]??null;let d=null,e=null;for(let a of c){e??=a;try{let b=await (0,E.stat)(a);(!d||b.mtimeMs>d.mtime)&&(d={path:a,mtime:b.mtimeMs})}catch{}}return d?.path??e}async function ag(a){let b=null,c=null;try{let d={model:null,threadId:null,inputTokens:0,outputTokens:0,cachedTokens:0,reasoningTokens:0};for await(let e of(b=(0,i.createReadStream)(a,{encoding:"utf-8"}),c=(0,Y.createInterface)({input:b,crlfDelay:1/0}))){let a=e.trim();if(a)try{let b=JSON.parse(a);if("object"!=typeof b||null===b||Array.isArray(b))continue;let c=_(b);"session_meta"===b.type&&("string"==typeof c.id&&c.id?d.threadId=c.id:"string"==typeof c.threadId&&c.threadId&&(d.threadId=c.threadId)),!d.threadId&&("string"==typeof c.threadId&&c.threadId?d.threadId=c.threadId:"string"==typeof b.threadId&&b.threadId&&(d.threadId=b.threadId)),"turn_context"===b.type&&"string"==typeof c.model&&c.model?d.model=c.model:!d.model&&"string"==typeof c.model&&c.model&&(d.model=c.model);let e=c.info?.total_token_usage;if("number"==typeof e?.input_tokens){d.inputTokens=e.input_tokens,d.outputTokens=e.output_tokens??0;continue}let f=c.info?.last_token_usage;if("number"==typeof f?.input_tokens){d.inputTokens+=f.input_tokens,d.outputTokens+=f.output_tokens??0;continue}if("number"==typeof c.input_tokens){d.inputTokens+=c.input_tokens,d.outputTokens+=c.output_tokens??0;continue}"event_msg"===b.type&&b.msg?.type==="token_count"&&(d.inputTokens+=b.msg.input_tokens??0,d.outputTokens+=b.msg.output_tokens??0,d.cachedTokens+=b.msg.cached_tokens??0,d.reasoningTokens+=b.msg.reasoning_tokens??0)}catch{}}return d}catch{return null}finally{c?.close(),b?.destroy()}}async function ah(){if((0,d.uFH)())return ai();try{let{stdout:a}=await Z("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 ai(){for(let a of["codex.cmd","codex.exe"])try{let{stdout:b}=await Z("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 aj(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 ak(a,b){b&&(a.push("--model",(0,d.kct)(b)),/^o[34]/i.test(b)&&a.push("-c","model_reasoning_effort=high"))}function al(a){a.push("-c","check_for_update_on_startup=false")}let am=new Map;function an(a,b){let c=a.metadata?.[b];return"string"==typeof c&&c.trim()?c.trim():null}async function ao(a,b){let c=am.get(a);if(c&&Date.now()<c.expiry)return c.path;let d=await b();return am.set(a,{path:d,expiry:Date.now()+3e4}),d}async function ap(a){let b=null,c=async()=>b??=await aa($),d=an(a,"codexThreadId");if(d){let a=await ao(`thread:${d}`,async()=>af(d,await c()));if(a)return a}return a.workspacePath?ao(`cwd:${ac(a.workspacePath)}`,async()=>ae(a.workspacePath,await c())):null}function aq(a){let b=a.join(" ");return(0,d.uFH)()?`& ${b}`:b}let ar={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 al(e),aj(e,b.permissions),ak(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)),aq(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)return{state:"exited",timestamp:e};let f=await this.isProcessRunning(a.runtimeHandle);if(f===d.HkR)return null;if(!f)return{state:"exited",timestamp:e};if(!a.workspacePath&&!an(a,"codexThreadId"))return null;let g=await ap(a);if(g){let a=await (0,d.XIc)(g);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 h=a.workspacePath?await (0,d.Ahw)(a.workspacePath):null,i=(0,d.Bmx)(h);if(i)return i;let j=Math.min(d.V1$,c),k=(0,d.Vo2)(h,j,c);if(k)return k;if(g)try{let a=await (0,E.stat)(g),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 Z("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 Z("ps",["-eo","pid,tty,args"],{timeout:3e4});if(!e)return d.HkR;let 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 d.HkR}},async getSessionInfo(a){let b,c=await ap(a);if(!c)return null;let d=await ag(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=an(b,"codexThreadId"),f=an(b,"codexModel");if(!e){if(!b.workspacePath)return null;let a=await ap(b);if(!a)return null;let c=await ag(a);if(!c?.threadId)return null;e=c.threadId,f=c.model}let g=a??"codex",h=[(0,d.kct)(g),"resume"];return al(h),aj(h,c.agentConfig?.permissions),ak(h,c.agentConfig?.model??f??void 0),h.push((0,d.kct)(e)),aq(h)},async setupWorkspaceHooks(a,b){},async postLaunchSetup(c){if(!a){b||(b=ah());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}}},as=(0,f.promisify)(e.execFile);async function at(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 au(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 av={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 at(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 as("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 as("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 au(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 aw(){let a=process.env.KIMI_SHARE_DIR;return a&&a.trim().length>0?a:(0,k.join)((0,j.homedir)(),".kimi")}let ax=".ao/kimi-baseline.json",ay=".ao/kimi-session-id.json";async function az(){try{let a=await (0,E.readFile)((0,k.join)(aw(),"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 aA(a){let b=await az();if(!b?.work_dirs||!Array.isArray(b.work_dirs))return null;let c=await aC(a);for(let a of b.work_dirs)if(a&&"string"==typeof a.path&&await aC(a.path)===c)return a;return null}function aB(a){return(0,h.createHash)("md5").update(a).digest("hex")}async function aC(a){try{return await (0,E.stat)(a),await (0,E.realpath)(a)}catch{return a}}async function aD(a){let b,c,d=(0,k.join)(aw(),"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 aE(a){try{return(await (0,E.lstat)(a)).isFile()}catch{return!1}}async function aF(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 aG(a){try{let b=await (0,E.readFile)((0,k.join)(a,ax),"utf-8"),c=JSON.parse(b);if(!Array.isArray(c.preExistingUuids))return null;return new Set(c.preExistingUuids)}catch{return null}}async function aH(a){let b=(0,k.join)(a,ax);try{await (0,E.stat)(b);return}catch{}let c=await aC(a),d=(0,k.join)(aw(),"sessions",aB(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 aI(a){try{let b=await (0,E.readFile)((0,k.join)(a,ay),"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 aJ(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,ay),JSON.stringify(c),"utf-8")}catch{}}async function aK(a){let b;if(!a.workspacePath)return null;let c=await aC(a.workspacePath),d=(0,k.join)(aw(),"sessions",aB(c));if(!await aD(d))return null;try{b=await (0,E.readdir)(d)}catch{return null}let e=await aI(a.workspacePath),f=null;if(!e){let b=await aA(a.workspacePath);b&&"string"==typeof b.last_session_id&&b.last_session_id.length>0&&(f=b.last_session_id)}let g=await aG(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 aD(b))continue;let c=await aF(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 aJ(a.workspacePath,j.sessionId),j):i?(await aJ(a.workspacePath,i.sessionId),{dir:i.dir,sessionId:i.sessionId,mtime:i.mtime}):null}let aL=new Map;async function aM(a){let b=a.workspacePath;if(!b)return null;let c=Date.now(),d=aL.get(b);if(d&&d.expiry>c)return d.match;d&&aL.delete(b);let e=await aK(a),f=e?3e4:2e3;return aL.set(b,{match:e,expiry:c+f}),aL.size>256&&function(a){for(let[b,c]of aL)c.expiry<=a&&aL.delete(b);if(aL.size<=256)return;let b=[...aL.entries()].sort((a,b)=>a[1].expiry-b[1].expiry),c=aL.size-256;for(let a=0;a<c;a++){let c=b[a];c&&aL.delete(c[0])}}(c),e}let aN=(0,f.promisify)(e.execFile);async function aO(a){let b=(0,k.join)(a,"wire.jsonl");if(!await aE(b))return null;let c=null,d=null,e=null;try{d=(0,i.createReadStream)(b,{encoding:"utf-8"}),e=(0,Y.createInterface)({input:d,crlfDelay:1/0});let a=0;for await(let b of e){if((a+=b.length)>1e6)break;let d=b.trim();if(d)try{let a=JSON.parse(d);if(!a||"object"!=typeof a||Array.isArray(a))continue;let b=a.message;if(!b||"object"!=typeof b||Array.isArray(b)||"TurnBegin"!==b.type)continue;let e=b.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{}}}catch{return null}finally{e?.close(),d?.destroy()}return c}function aP(a,b){let c=(0,d.DD3)(b);("permissionless"===c||"auto-edit"===c)&&a.push("--yolo")}function aQ(a){let b=a.join(" ");return(0,d.uFH)()?`& ${b}`:b}let aR=/kimi[-_](?:cli|code)|moonshot/i,aS={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)),aP(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}
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
${e}`:b}return e&&b.push("--prompt",(0,d.kct)(e)),aQ(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 aM(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 aN("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 aN("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 aM(a);return b?{summary:await aO(b.dir),summaryIsFallback:!0,agentSessionId:b.sessionId}:null},async getRestoreCommand(a,b){if(!a.workspacePath)return null;let c=await aM(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 aP(f,b.agentConfig?.permissions),e&&f.push("--model",(0,d.kct)(e)),aQ(f)},async setupWorkspaceHooks(a,b){await (0,d.J06)(a)},async preLaunchSetup(a){await aH(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 aR.test(a)}catch{return!1}}};var aT=c(72649);let aU=JSON.parse('{"UU":"@made-by-moonlight/athene-plugin-agent-grok","rE":"0.1.3","h_":"Agent plugin: Grok"}'),aV="@made-by-moonlight/athene-plugin-agent-",aW=aU.UU.startsWith(aV)?aU.UU.slice(aV.length):aU.UU,aX=(0,f.promisify)(e.execFile),aY="grok",aZ=RegExp(`(?:[@-Z\\-_]|\\[[0-?]*[ -/]*[@-~])`,"g"),a$=/(?:allow|approve|do you want to continue|continue anyway|proceed).*(?:y\/n|yes\/no|\[[YyNn]\/ ?[YyNn]\]|\([YyNn]\/ ?[YyNn]\)|\?)\s*:?$/i,a_=/(?:sign in with grok|open this url to sign in|oauth2\/authorize)/i;function a0(a){if("string"!=typeof a)return null;let b=a.trim();return!b||/\p{C}/u.test(b)?null:b.length<=512?b:null}function a1(a,b){let c=b??a0(a.projectConfig.agentConfig?.grokSessionId),e=[aY,"--no-alt-screen"];c||e.push("--worktree");let f=function(a){let b=a.model??a.projectConfig.agentConfig?.model;return"string"==typeof b&&b.trim()?b.trim():null}(a);return f&&e.push("--model",(0,d.kct)(f)),a.systemPromptFile?e.push("--rules",(0,d.kct)(`@${a.systemPromptFile}`)):a.systemPrompt&&e.push("--rules",(0,d.kct)(a.systemPrompt)),c&&e.push("--resume",(0,d.kct)(c)),e.join(" ")}async function a2(a){let{stdout:b}=await aX("tmux",["capture-pane","-t",a.id,"-p","-S","-120"],{timeout:5e3});return b}async function a3(a){let b=a.runtimeHandle;if(!b||"tmux"!==b.runtimeName||!b.id||(0,d.uFH)()||a0(a.metadata?.grokSessionId))return;let c=Date.now();for(;Date.now()-c<3e4;){let a=await a2(b);if(/Worktree ready:/i.test(a))return;await (0,g.setTimeout)(500)}}function a4(a){let b=a.replaceAll(aZ,"").trim();if(!b)return"idle";let c=b.split("\n").map(a=>a.trim()),d=c[c.length-1]??"",e=[...c].reverse().find(Boolean)??"";return/^[>$#›]\s*$/.test(d)?"idle":a_.test(b)||a$.test(e)?"waiting_input":/\b(error|failed|exception|not authenticated|device not configured)\b/i.test(d)?"blocked":"active"}let a5={manifest:{name:aW,slot:"agent",description:aU.h_,version:aU.rE,displayName:"Grok"},create:function(){return{name:aW,processName:aW,promptDelivery:"post-launch",getLaunchCommand:a=>a1(a),getEnvironment(a){let b={};b.AO_SESSION_ID=a.sessionId,a.issueId&&(b.AO_ISSUE_ID=a.issueId);let c=function(a){let b=a.projectConfig.agentConfig?.grokSandbox;return"string"==typeof b&&b.trim()?b.trim():null}(a);return c&&(b.GROK_SANDBOX=c),b},detectActivity:a=>a4(a),async getActivityState(a,b){let c=b??d.PES,e=Math.min(d.V1$,c),f=new Date;if(!a.runtimeHandle||!1===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=(0,d.Vo2)(g,e,c);return h||null},async recordActivity(a,b){a.workspacePath&&await (0,d.JyZ)(a.workspacePath,b,a=>a4(a))},async isProcessRunning(a){try{if("tmux"===a.runtimeName&&a.id){if((0,d.uFH)())return d.HkR;let{stdout:b}=await aX("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 aX("ps",["-eo","pid,tty,args"],{timeout:3e4}),f=new Set(c.map(a=>a.replace(/^\/dev\//,""))),g=/(?:^|[\s/])\.?grok(?:\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&&"EPERM"===a.code)return!0;if(a instanceof Error&&"ESRCH"===a.code)return!1;return d.HkR}return!1}catch{return d.HkR}},async getSessionInfo(a){let b=a0(a.metadata?.grokSessionId);return b?{agentSessionId:b,summary:null}:null},async getRestoreCommand(a,b){let c=a0(a.metadata?.grokSessionId);return c?a1({sessionId:a.id,projectConfig:b,workspacePath:a.workspacePath??void 0,issueId:a.issueId??void 0},c):null},async setupWorkspaceHooks(a,b){await (0,d.J06)(a)},async postLaunchSetup(a){a.workspacePath&&await (0,d.J06)(a.workspacePath),await a3(a)}}},detect:function(){try{return!!aT.sync(aY)}catch{return!1}}},a6=(0,f.promisify)(e.execFile);function a7(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 a8(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=a7(a.updated)?.getTime()??0;return(a7(b.updated)?.getTime()??0)>c?b:a})}catch{return null}}let a9={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=`
|
|
591
|
+
let buffer = '';
|
|
592
|
+
let captured = null;
|
|
593
|
+
process.stdin.on('data', chunk => {
|
|
594
|
+
buffer += chunk;
|
|
595
|
+
const lines = buffer.split('\\n');
|
|
596
|
+
buffer = lines.pop() || '';
|
|
597
|
+
for (const line of lines) {
|
|
598
|
+
if (captured) continue;
|
|
599
|
+
const trimmed = line.trim();
|
|
600
|
+
if (!trimmed) continue;
|
|
601
|
+
try {
|
|
602
|
+
const obj = JSON.parse(trimmed);
|
|
603
|
+
const sid = (typeof obj.session_id === 'string' && obj.session_id) || (typeof obj.sessionID === 'string' && obj.sessionID);
|
|
604
|
+
if (sid && /^ses_[A-Za-z0-9_-]+$/.test(sid)) {
|
|
605
|
+
captured = sid;
|
|
606
|
+
}
|
|
607
|
+
} catch {}
|
|
608
|
+
}
|
|
609
|
+
}).on('end', () => {
|
|
610
|
+
if (buffer.trim()) {
|
|
611
|
+
try {
|
|
612
|
+
const obj = JSON.parse(buffer.trim());
|
|
613
|
+
const sid = (typeof obj.session_id === 'string' && obj.session_id) || (typeof obj.sessionID === 'string' && obj.sessionID);
|
|
614
|
+
if (sid && /^ses_[A-Za-z0-9_-]+$/.test(sid)) {
|
|
615
|
+
captured = sid;
|
|
616
|
+
}
|
|
617
|
+
} catch {}
|
|
618
|
+
}
|
|
619
|
+
if (captured) {
|
|
620
|
+
process.stdout.write(captured);
|
|
621
|
+
process.exit(0);
|
|
622
|
+
}
|
|
623
|
+
process.exit(1);
|
|
624
|
+
});
|
|
625
|
+
`.trim().replace(/\n/g," ").replace(/\s+/g," "),f=`
|
|
626
|
+
let input = '';
|
|
627
|
+
process.stdin.on('data', c => input += c).on('end', () => {
|
|
628
|
+
const title = process.argv[1];
|
|
629
|
+
let rows;
|
|
630
|
+
try { rows = JSON.parse(input); } catch { process.exit(1); }
|
|
631
|
+
if (!Array.isArray(rows)) process.exit(1);
|
|
632
|
+
const isValidId = id => /^ses_[A-Za-z0-9_-]+$/.test(id);
|
|
633
|
+
const timestamp = value => {
|
|
634
|
+
if (typeof value === 'number' && Number.isFinite(value)) return value;
|
|
635
|
+
if (typeof value === 'string') {
|
|
636
|
+
const parsed = Date.parse(value);
|
|
637
|
+
return Number.isNaN(parsed) ? Number.NEGATIVE_INFINITY : parsed;
|
|
638
|
+
}
|
|
639
|
+
return Number.NEGATIVE_INFINITY;
|
|
640
|
+
};
|
|
641
|
+
const matches = rows
|
|
642
|
+
.filter(r => r && r.title === title && typeof r.id === 'string' && isValidId(r.id))
|
|
643
|
+
.sort((a, b) => {
|
|
644
|
+
const ta = timestamp(a.updated);
|
|
645
|
+
const tb = timestamp(b.updated);
|
|
646
|
+
if (ta === tb) return 0;
|
|
647
|
+
return tb - ta;
|
|
648
|
+
});
|
|
649
|
+
if (matches.length === 0) process.exit(1);
|
|
650
|
+
process.stdout.write(matches[0].id);
|
|
651
|
+
});
|
|
652
|
+
`.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)return{state:"exited",timestamp:f};let g=await this.isProcessRunning(a.runtimeHandle);if(g===d.HkR)return null;if(!g)return{state:"exited",timestamp:f};let h=null;if(a.workspacePath){h=await (0,d.Ahw)(a.workspacePath);let b=(0,d.Bmx)(h);if(b)return b}let i=await a8(a);if(i){let a=a7(i.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 j=(0,d.Vo2)(h,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 a6("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 a6("ps",["-eo","pid,tty,args"],{timeout:3e4});if(!e)return d.HkR;let 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 d.HkR}},async getSessionInfo(a){let b=await a8(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 a8(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}}},ba=(0,f.promisify)(e.execFile);async function bb(a,...b){let{stdout:c}=await ba("git",b,{cwd:a,windowsHide:!0,timeout:3e4});return c.trimEnd()}function bc(a){return a.replace(/\\/g,"/").replace(/^([a-zA-Z]):/,(a,b)=>b.toLowerCase()+":")}async function bd(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 be(a){try{return await bb(a,"remote","get-url","origin"),!0}catch{return!1}}async function bf(a,b){try{return await bb(a,"rev-parse","--verify","--quiet",b),!0}catch{return!1}}async function bg(a,b,c){if(c?.hasOrigin??await be(a)){if(c?.branch){let b=`origin/${c.branch}`;if(await bf(a,b))return b}let d=`origin/${b}`;if(await bf(a,d))return d}let d=`refs/heads/${b}`;if(await bf(a,d))return d;throw Error(`Unable to resolve base ref for default branch "${b}"`)}async function bh(a,b){try{let c=await bb(a,"worktree","list","--porcelain"),d=bc((0,k.resolve)(b));return c.split("\n").some(a=>a.startsWith("worktree ")&&bc((0,k.resolve)(a.slice(9)))===d)}catch{return!1}}async function bi(a,b){if((0,i.existsSync)(b)){try{await bb(a,"worktree","prune")}catch{}if(await bh(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 bj(a,b){try{await bb(a,"worktree","remove","--force",b)}catch{}if((0,i.existsSync)(b)){if(await bh(a,b))throw Error(`Worktree path "${b}" already exists and is still registered with git`);await bd(b)}}async function bk(a,b,c){await bj(a,b),await bb(a,"worktree","add",b,c)}async function bl(a,b,c,d,e){await bj(a,b);let f=await bg(a,d,{branch:c,hasOrigin:e});if(!f.startsWith("origin/"))return void await bb(a,"worktree","add","-b",c,b,f);try{await bb(a,"worktree","add","-b",c,b,f)}catch{await bb(a,"worktree","add","-b",c,b,`refs/heads/${d}`)}}let bm=/^[a-zA-Z0-9_-]+$/;function bn(a,b){if(!bm.test(a))throw Error(`Invalid ${b} "${a}": must match ${bm}`)}function bo(a){return a.startsWith("~/")?(0,k.join)((0,j.homedir)(),a.slice(2)):a}let bp={manifest:{name:"worktree",slot:"workspace",description:"Workspace plugin: git worktrees",version:"0.1.0"},create:function(a){let b=a?.worktreeDir?bo(a.worktreeDir):(0,k.join)((0,j.homedir)(),".worktrees");return{name:"worktree",async create(a){bn(a.projectId,"projectId"),bn(a.sessionId,"sessionId");let c=bo(a.project.path),e=a.worktreeDir??b,f=a.worktreeDir?e:(0,k.join)(e,a.projectId),g=(0,k.join)(f,a.sessionId);(0,i.mkdirSync)(f,{recursive:!0}),await bi(c,g);let h=await be(c);if(h)try{await bb(c,"fetch","origin","--quiet")}catch{}let j=await bg(c,a.project.defaultBranch,{hasOrigin:h});try{await bb(c,"worktree","add","-b",a.branch,g,j)}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});(0,d.plx)({projectId:a.projectId,sessionId:a.sessionId,source:"workspace",kind:"workspace.branch_collision",level:"warn",summary:`branch "${a.branch}" already exists; falling back to worktree recovery`,data:{plugin:"workspace-worktree",branch:a.branch,errorMessage:b}});let e=await bb(c,"rev-parse",j),f=`refs/heads/${a.branch}`,h=await bf(c,f)?await bb(c,"rev-parse",f):void 0;try{h===e?await bb(c,"worktree","add",g,a.branch):await bb(c,"worktree","add","-B",a.branch,g,j)}catch(d){try{await bb(c,"worktree","remove","--force",g)}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:g,branch:a.branch,sessionId:a.sessionId,projectId:a.projectId}},async findManagedWorkspace(a){bn(a.projectId,"projectId"),bn(a.sessionId,"sessionId");let c=bo(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 bb(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 bb(a,"rev-parse","--path-format=absolute","--git-common-dir"),c=(0,k.resolve)(b,"..");await bb(c,"worktree","remove","--force",a)}catch(c){let b=c instanceof Error?c.message:String(c);(0,d.plx)({source:"workspace",kind:"workspace.destroy_fell_back",level:"warn",summary:"destroy fell back to rmSync; git worktree metadata may be stale",data:{plugin:"workspace-worktree",workspacePath:a,errorMessage:b}}),(0,i.existsSync)(a)&&await bd(a)}},async list(a){bn(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 bb(a,"worktree","list","--porcelain");break}catch{continue}if(!e)return[];let f=[],g=e.split("\n\n"),h=bc(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?bc(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 ba("git",["rev-parse","--is-inside-work-tree"],{cwd:a,timeout:3e4,windowsHide:!0}),!0}catch{return!1}},async restore(a,b){let c=bo(a.project.path);try{await bb(c,"worktree","prune")}catch{}let d=await be(c);if(d)try{await bb(c,"fetch","origin","--quiet")}catch{}try{await bb(c,"worktree","add",b,a.branch)}catch{await bf(c,`refs/heads/${a.branch}`)?await bk(c,b,a.branch):await bl(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=bo(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 e of b.postCreate)try{await ba(c.cmd,c.args(e),{cwd:a.path,windowsHide:!0})}catch(c){let b=c instanceof Error?c.message:String(c);throw(0,d.plx)({projectId:a.projectId,sessionId:a.sessionId,source:"workspace",kind:"workspace.post_create_failed",level:"error",summary:`postCreate command failed for session ${a.sessionId}`,data:{plugin:"workspace-worktree",command:e,errorMessage:b}}),c}}}}}};class bq{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 br=(0,f.promisify)(e.execFile),bs=async(a,b,c)=>(0,d.vQK)(a,{component:"scm-github-batch",operation:c},b),bt={prList:new bq(100),commitStatus:new bq(500),reviewComments:new bq(500)};function bu(a,b,c){bt.prList.set(`${a}/${b}`,c)}function bv(a,b,c,d){bt.commitStatus.set(`${a}/${b}#${c}`,d)}let bw=new bq(200),bx=new bq(200);async function by(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 bF(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=bw.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 bG(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}}let bz=!1,bA=new Set;async function bB(){try{await br("gh",["--version"],{timeout:5e3})}catch(b){if(!bz){bz=!0;let a=b instanceof Error?b.message:String(b);(0,d.plx)({source:"scm",kind:"scm.gh_unavailable",level:"error",summary:"gh CLI not available or not authenticated",data:{plugin:"scm-github",errorMessage:a}})}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 bC(a){return/HTTP\/[\d.]+ 304/i.test(a)}function bD(a){let b=("string"==typeof a.stdout?a.stdout:"")+("string"==typeof a.stderr?a.stderr:"");return b.length>0?b:null}function bE(a){let b=a.match(/etag:\s*(.+)/i);return b?b[1].trim():void 0}async function bF(a,b,c){let d=`${a}/${b}`,e=bt.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 bs(f,1e4,"gh.api.guard-pr-list");if(bC(c)){let d=bE(c);return d&&bu(a,b,d),!1}let d=bE(c);return d&&bu(a,b,d),!0}catch(g){let e=bD(g);if(e&&bC(e)){let c=bE(e);return c&&bu(a,b,c),!1}let f=g instanceof Error?g.message:String(g);if(bC(f))return!1;return c?.log("warn",`[ETag Guard 1] PR list check failed for ${d}: ${f}`),!0}}async function bG(a,b,c,d){let e=`${a}/${b}#${c}`,f=bt.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 bs(g,1e4,"gh.api.guard-commit-status");if(bC(d)){let e=bE(d);return e&&bv(a,b,c,e),!1}let e=bE(d);return e&&bv(a,b,c,e),!0}catch(h){let f=bD(h);if(f&&bC(f)){let d=bE(f);return d&&bv(a,b,c,d),!1}let g=h instanceof Error?h.message:String(h);if(bC(g))return!1;return d?.log("warn",`[ETag Guard 2] Commit status check failed for ${e}: ${g}`),!0}}async function bH(a,b,c,d){let e=`${a}/${b}#${c}`,f=bt.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 bs(g,1e4,"gh.api.guard-review-comments");if(bC(a)){let b=bE(a);return b&&bt.reviewComments.set(e,b),!1}let b=bE(a);return b&&bt.reviewComments.set(e,b),!0}catch(c){let a=bD(c);if(a&&bC(a)){let b=bE(a);return b&&bt.reviewComments.set(e,b),!1}let b=c instanceof Error?c.message:String(c);if(bC(b))return!1;return d?.log("warn",`[ETag Guard 3] Review comments check failed for ${e}: ${b}`),!0}}let bI=`
|
|
653
|
+
title
|
|
654
|
+
state
|
|
655
|
+
additions
|
|
656
|
+
deletions
|
|
657
|
+
isDraft
|
|
658
|
+
mergeable
|
|
659
|
+
mergeStateStatus
|
|
660
|
+
reviewDecision
|
|
661
|
+
headRefName
|
|
662
|
+
headRefOid
|
|
663
|
+
commits(last: 1) {
|
|
664
|
+
nodes {
|
|
665
|
+
commit {
|
|
666
|
+
statusCheckRollup {
|
|
667
|
+
state
|
|
668
|
+
# 11 keeps per-PR node cost under budget for 25-PR batch queries
|
|
669
|
+
# (total cost ≤5000). Repos with >11 checks lose individual check
|
|
670
|
+
# visibility, but the rollup "state" still reflects all checks —
|
|
671
|
+
# overall pass/fail detection remains correct.
|
|
672
|
+
contexts(first: 11) {
|
|
673
|
+
nodes {
|
|
674
|
+
... on CheckRun {
|
|
675
|
+
name
|
|
676
|
+
status
|
|
677
|
+
conclusion
|
|
678
|
+
detailsUrl
|
|
679
|
+
}
|
|
680
|
+
... on StatusContext {
|
|
681
|
+
context
|
|
682
|
+
state
|
|
683
|
+
targetUrl
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
pageInfo {
|
|
687
|
+
hasNextPage
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
`;async function bJ(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(`
|
|
695
|
+
${e}: repository(owner: $${e}Owner, name: $${e}Name) {
|
|
696
|
+
... on Repository {
|
|
697
|
+
pullRequest(number: $${e}Number) { ${bI} }
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
`),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}) {
|
|
701
|
+
${b.join("\n")}
|
|
702
|
+
rateLimit { cost remaining resetAt }
|
|
703
|
+
}`,variables:c}}(a);if(!b||0===a.length)return{};await bB();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 bs(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 bK(a,b,c=[]){let e=new Map,f=await by(a,c,b);if(b?.reportPRListUnchangedRepos?.(f.prListUnchangedRepos),!f.shouldRefresh){let c=[];for(let b of a){let a=`${b.owner}/${b.repo}#${b.number}`,d=bx.get(a);d?e.set(a,d):c.push(b)}if(0===c.length)return b?.log("info",`[ETag Guard] Skipping GraphQL batch - all ${e.size} PRs cached. Reasons: ${f.details.join(", ")}`),{enrichment:e,prListUnchangedRepos:f.prListUnchangedRepos};b?.log("info",`[ETag Guard] Partial cache: ${e.size} cached, ${c.length} missing. Fetching missing PRs via GraphQL.`),a=c}let g=[];for(let b=0;b<a.length;b+=25)g.push(a.slice(b,b+25));for(let a=0;a<g.length;a++){let c,f=g[a],h=e.size,i=Date.now();try{let j=await bJ(f);c=Date.now()-i,f.forEach((a,b)=>{let c=`pr${b}`,f=`${a.owner}/${a.repo}#${a.number}`,g=j[c];if(g?.pullRequest){let b=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}}(g.pullRequest);if(b){let{data:a,headSha:c}=b;e.set(f,a),bw.set(f,{headSha:c,ciStatus:a.ciStatus}),bx.set(f,a)}else bA.has(f)||(bA.add(f),(0,d.plx)({source:"scm",kind:"scm.batch_enrich_pr_failed",level:"warn",summary:`batch enrich extraction failed for PR #${a.number}`,data:{plugin:"scm-github",prNumber:a.number,prOwner:a.owner,prRepo:a.repo}}))}});let k=e.size;if(k>h){let d={batchIndex:a,totalBatches:g.length,prCount:k-h,durationMs:c};b?.recordSuccess(d),b?.log("info",`[GraphQL Batch Success] Batch ${a+1}/${g.length} succeeded: added ${k-h} PRs to cache (${c}ms)`)}}catch(e){c=Date.now()-i;let d=e instanceof Error?e.message:String(e);b?.recordFailure({batchIndex:a,totalBatches:g.length,prCount:f.length,error:d,durationMs:c}),b?.log("error",`[GraphQL Batch] Batch enrichment partially failed: ${d}`)}}return{enrichment:e,prListUnchangedRepos:f.prListUnchangedRepos}}function bL(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 bM(a){if("string"!=typeof a)return;let b=new Date(a);return Number.isNaN(b.getTime())?void 0:b}function bN(a){return"string"!=typeof a||0===a.length?void 0:a.startsWith("refs/heads/")?a.slice(11):a.startsWith("refs/")?void 0:a}let bO=(0,f.promisify)(e.execFile),bP=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]"]),bQ=new Set;async function bR(a,b,c){try{let{stdout:d}=await bO(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 bS(a){return(0,d.vQK)(a,{component:"scm-github"},3e4)}async function bT(a,b){return(0,d.vQK)(a,{component:"scm-github",cwd:b},3e4)}async function bU(a,b){return bR("git",a,b)}function bV(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 bW(a,b){let[c,d]=bV(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 bX(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")}function bY(a){return"failed"===a.status||a.conclusion?.toUpperCase()==="FAILURE"}function bZ(a){return a.length>0&&[...a].every(a=>a>="0"&&a<="9")}async function b$(a,b){try{return await bS(["run","view",b.runId,"--repo",b1(a),"--log-failed",...b.jobId?["--job",b.jobId]:[]])}catch(c){if(!b.jobId)throw c;return bS(["api",`repos/${a.owner}/${a.repo}/actions/jobs/${b.jobId}/logs`])}}async function b_(a){let b=JSON.parse(await bS(["pr","view",String(a.number),"--repo",b1(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:bX(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 b0(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 b1(a){return`${a.owner}/${a.repo}`}function b2(a){if(!a)return new Date(0);let b=new Date(a);return isNaN(b.getTime())?new Date(0):b}let b3={resolvePR:6e4,getPRState:5e3,getPRSummary:5e3,getReviews:1e4,getReviewDecision:1e4,getCIChecks:5e3,getMergeability:5e3,getPendingComments:1e4,detectPR:3e4},b4={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,b3[d]),k}return{name:"github",async verifyWebhook(a,b){let c=b0(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=bL(a.headers,c.eventHeader);if(!d)return{ok:!1,reason:`Missing ${c.eventHeader} header`};let e=bL(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=bL(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=b0(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=bL(a.headers,c.eventHeader);if(!d)return null;let e=bL(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:bM(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?bM(b.review?.submitted_at):bM(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:bM(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:bM(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:bN(a[0]?.name??b.ref),sha:"string"==typeof b.sha?b.sha:void 0,timestamp:bM(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:bN(b.ref),sha:"string"==typeof b.after?b.after:void 0,timestamp:bM(a?.timestamp??b.updated_at),data:b}}return{provider:"github",kind:"unknown",action:g,rawEventType:d,deliveryId:e,repository:f,timestamp:bM(b.updated_at),data:b}}(a,d,c)},async detectPR(a,b){if(!a.branch||!b.repo)return null;bV(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 bS(["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=bW(d[0],b.repo);return g(h,e,b3.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()=>bW(JSON.parse(await bS(["pr","view",a,"--repo",c,"--json","number,url,title,headRefName,baseRefName,isDraft"])),c))},async assignPRToCurrentUser(a){await bS(["pr","edit",String(a.number),"--repo",b1(a),"--add-assignee","@me"]),i(a)},async checkoutPR(a,b){if(await bU(["branch","--show-current"],b)===a.branch)return!1;if(await bU(["status","--porcelain"],b))throw Error(`Workspace has uncommitted changes; cannot switch to PR branch "${a.branch}" safely`);return await bT(["pr","checkout",String(a.number),"--repo",b1(a)],b),!0},getPRState:async a=>j(a.owner,a.repo,String(a.number),"getPRState",async()=>{let b=JSON.parse(await bS(["pr","view",String(a.number),"--repo",b1(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 bS(["pr","view",String(a.number),"--repo",b1(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 bS(["pr","merge",String(a.number),"--repo",b1(a),"rebase"===b?"--rebase":"merge"===b?"--merge":"--squash","--delete-branch"]),i(a)},async closePR(a){await bS(["pr","close",String(a.number),"--repo",b1(a)]),i(a)},getCIChecks:async a=>j(a.owner,a.repo,String(a.number),"getCIChecks",async()=>{try{let b=await bS(["pr","checks",String(a.number),"--repo",b1(a),"--json","name,state,link,startedAt,completedAt"]);return JSON.parse(b).map(a=>{let b=a.state?.toUpperCase();return{name:a.name,status:bX(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 b_(a);throw Error("Failed to fetch CI checks",{cause:b})}}),async getCIFailureSummary(a,b){try{let c=(b??await this.getCIChecks(a)).filter(bY);if(0===c.length)return null;let d=[],e=new Set;for(let b of c){let c=function(a){let b;if(!a.url)return null;try{b=new URL(a.url).pathname.split("/").filter(Boolean)}catch{return null}let c=b.findIndex((a,c)=>"actions"===a&&"runs"===b[c+1]),d=c>=0?b[c+2]:void 0;if(!d||!bZ(d))return null;let e=b.findIndex((a,b)=>b>c&&"job"===a),f=e>=0?b[e+1]:void 0;return{runId:d,...f&&bZ(f)?{jobId:f}:{},runUrl:a.url}}(b);if(!c)continue;let f=`${c.runId}:${c.jobId??""}`;if(e.has(f))continue;e.add(f);let g=await b$(a,c),h={name:b.name,runUrl:c.runUrl},i=function(a){let b;for(let c of a.split(/\r?\n/)){let a=c.split(" "),d=a.length>=3?a[1]?.trim():void 0;d&&(b=d)}return b}(g);i&&(h.failedStep=i);let j=function(a,b){let c=a.split(/\r?\n/).slice(-120).join("\n").trimEnd();return c.length>0?c:void 0}(g,0);j&&(h.logTail=j),d.push(h)}return d.length>0?{failedJobs:d}:null}catch{return null}},async getCISummary(a){let b;try{b=await this.getCIChecks(a)}catch(c){try{let b=await this.getPRState(a);if("merged"===b||"closed"===b)return"none"}catch{}let b=`${b1(a)}#${a.number}`;if(!bQ.has(b)){bQ.add(b);let e=c instanceof Error?c.message:String(c);(0,d.plx)({source:"scm",kind:"scm.ci_summary_failclosed",level:"warn",summary:`getCISummary failed-closed for PR #${a.number}`,data:{plugin:"scm-github",prNumber:a.number,prOwner:a.owner,prRepo:a.repo,errorMessage:e}})}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 bS(["pr","view",String(a.number),"--repo",b1(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:b2(a.submittedAt)}})),getReviewDecision:async a=>j(a.owner,a.repo,String(a.number),"getReviewDecision",async()=>{let b=(JSON.parse(await bS(["pr","view",String(a.number),"--repo",b1(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 bS(["api","graphql","-f",`owner=${a.owner}`,"-f",`name=${a.repo}`,"-F",`number=${a.number}`,"-f",`query=query($owner: String!, $name: String!, $number: Int!) {
|
|
704
|
+
repository(owner: $owner, name: $name) {
|
|
705
|
+
pullRequest(number: $number) {
|
|
706
|
+
reviewThreads(first: 100) {
|
|
707
|
+
nodes {
|
|
708
|
+
id
|
|
709
|
+
isResolved
|
|
710
|
+
comments(first: 1) {
|
|
711
|
+
nodes {
|
|
712
|
+
id
|
|
713
|
+
author { login }
|
|
714
|
+
body
|
|
715
|
+
path
|
|
716
|
+
line
|
|
717
|
+
url
|
|
718
|
+
createdAt
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}`]);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!bP.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:b2(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 bH(b.owner,b.repo,b.number,a)){let a=c.get(d);if(a)return a}try{let a=(await bS(["api","graphql","-i","-f",`owner=${b.owner}`,"-f",`name=${b.repo}`,"-F",`number=${b.number}`,"-f",`query=query($owner: String!, $name: String!, $number: Int!) {
|
|
726
|
+
repository(owner: $owner, name: $name) {
|
|
727
|
+
pullRequest(number: $number) {
|
|
728
|
+
reviewThreads(last: 100) {
|
|
729
|
+
nodes {
|
|
730
|
+
id
|
|
731
|
+
isResolved
|
|
732
|
+
comments(first: 1) {
|
|
733
|
+
nodes {
|
|
734
|
+
id
|
|
735
|
+
author { login }
|
|
736
|
+
body
|
|
737
|
+
path
|
|
738
|
+
line
|
|
739
|
+
url
|
|
740
|
+
createdAt
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
reviews(last: 5) {
|
|
746
|
+
nodes {
|
|
747
|
+
author { login }
|
|
748
|
+
state
|
|
749
|
+
body
|
|
750
|
+
submittedAt
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
rateLimit { cost remaining resetAt }
|
|
756
|
+
}`])).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:b2(b.createdAt),url:b.url,isBot:bP.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:b2(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 bS(["pr","view",String(a.number),"--repo",b1(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 bK(b,c,d)).enrichment),async preflight(a){a.intent.willClaimExistingPR&&await (0,d.TF_)("gh-cli-auth",async()=>{try{await bO("gh",["--version"])}catch{throw Error("GitHub CLI (gh) is not installed. Install it: https://cli.github.com/")}try{await bO("gh",["auth","status"])}catch{throw Error("GitHub CLI is not authenticated. Run: gh auth login")}})}}}()}};async function b5(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 b6(){return(0,d.TF_)("gh-cli-auth",async()=>{try{await b5(["--version"])}catch{throw Error("GitHub CLI (gh) is not installed. Install it: https://cli.github.com/")}try{await b5(["auth","status"])}catch{throw Error("GitHub CLI is not authenticated. Run: gh auth login")}})}function b7(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 b8(a,b){let c=cb(b);try{return await b5(["issue","view",a,"--repo",c,"--json","number,title,body,url,state,stateReason,labels,assignees"])}catch(b){if(!b7(b,"stateReason"))throw b;return b5(["issue","view",a,"--repo",c,"--json","number,title,body,url,state,labels,assignees"])}}async function b9(a){let b=[...a,"--json","number,title,body,url,state,stateReason,labels,assignees"];try{return await b5(b)}catch(b){if(!b7(b,"stateReason"))throw b;return b5([...a,"--json","number,title,body,url,state,labels,assignees"])}}function ca(a,b){return"CLOSED"===a.toUpperCase()?b?.toUpperCase()==="NOT_PLANNED"?"cancelled":"closed":"open"}function cb(a){if(!a.repo)throw Error("GitHub tracker requires a 'repo' field in project config");return a.repo}function cc(a,b){return`${a}#${b.replace(/^#/,"")}`}let cd={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=cb(d),f=function(b,c){let d=cc(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=cc(e,c),h=b.get(g);if(h)return h;let i=(async()=>{let b=JSON.parse(await b8(c,d)),f={id:String(b.number),title:b.title,description:b.body??"",url:b.url,state:ca(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(cc(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/${cb(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",cb(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 b9(c)).map(a=>({id:String(a.number),title:a.title,description:a.body??"",url:a.url,state:ca(a.state,a.stateReason),labels:a.labels.map(a=>a.name),assignee:a.assignees[0]?.login}))},async updateIssue(b,c,d){let e=cb(d);a.delete(cc(e,b)),"closed"===c.state?await b5(["issue","close",b,"--repo",e]):"open"===c.state&&await b5(["issue","reopen",b,"--repo",e]),c.removeLabels&&c.removeLabels.length>0&&await b5(["issue","edit",b,"--repo",e,"--remove-label",c.removeLabels.join(",")]),c.labels&&c.labels.length>0&&await b5(["issue","edit",b,"--repo",e,"--add-label",c.labels.join(",")]),c.assignee&&await b5(["issue","edit",b,"--repo",e,"--add-assignee",c.assignee]),c.comment&&await b5(["issue","comment",b,"--repo",e,"--body",c.comment])},async createIssue(a,b){let d=["issue","create","--repo",cb(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 b5(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 b6()}};return c}};var ce=c(44708);let cf=!1;function cg(a){try{(0,d.plx)(a)}catch{}}class ch extends Error{constructor(a,b){super(`Linear API returned HTTP ${a}: ${b.slice(0,200)}`),this.status=a}get transient(){return 408===this.status||429===this.status||this.status>=500}}class ci extends Error{constructor(a){super(`Linear API network error: ${a}`)}}class cj extends Error{constructor(){super("Linear API request timed out after 30s")}}function ck(a){switch(a){case"completed":return"closed";case"canceled":return"cancelled";case"started":return"in_progress";default:return"open"}}let cl=`
|
|
757
|
+
id
|
|
758
|
+
identifier
|
|
759
|
+
title
|
|
760
|
+
description
|
|
761
|
+
url
|
|
762
|
+
priority
|
|
763
|
+
branchName
|
|
764
|
+
state { name type }
|
|
765
|
+
labels { nodes { name } }
|
|
766
|
+
assignee { name displayName }
|
|
767
|
+
team { key }
|
|
768
|
+
`;function cm(a){return{name:"linear",async getIssue(b,c){let d=(await a(`query($id: String!) {
|
|
769
|
+
issue(id: $id) {
|
|
770
|
+
${cl}
|
|
771
|
+
}
|
|
772
|
+
}`,{id:b})).issue;return{id:d.identifier,title:d.title,description:d.description??"",url:d.url,state:ck(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!) {
|
|
773
|
+
issue(id: $id) {
|
|
774
|
+
state { type }
|
|
775
|
+
}
|
|
776
|
+
}`,{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!) {
|
|
777
|
+
issues(filter: $filter, first: $first) {
|
|
778
|
+
nodes {
|
|
779
|
+
${cl}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
}`,e)).issues.nodes.map(a=>({id:a.identifier,title:a.title,description:a.description??"",url:a.url,state:ck(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!) {
|
|
783
|
+
issue(id: $id) {
|
|
784
|
+
id
|
|
785
|
+
team { id }
|
|
786
|
+
}
|
|
787
|
+
}`,{id:b}),f=e.issue.id,g=e.issue.team.id;if(c.state){let b=await a(`query($teamId: ID!) {
|
|
788
|
+
workflowStates(filter: { team: { id: { eq: $teamId } } }) {
|
|
789
|
+
nodes { id name type }
|
|
790
|
+
}
|
|
791
|
+
}`,{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!) {
|
|
792
|
+
issueUpdate(id: $id, input: { stateId: $stateId }) {
|
|
793
|
+
success
|
|
794
|
+
}
|
|
795
|
+
}`,{id:f,stateId:e.id})}if(c.assignee){let b=(await a(`query($filter: UserFilter) {
|
|
796
|
+
users(filter: $filter) {
|
|
797
|
+
nodes { id displayName name }
|
|
798
|
+
}
|
|
799
|
+
}`,{filter:{displayName:{eq:c.assignee}}})).users.nodes[0];b&&await a(`mutation($id: String!, $assigneeId: String!) {
|
|
800
|
+
issueUpdate(id: $id, input: { assigneeId: $assigneeId }) {
|
|
801
|
+
success
|
|
802
|
+
}
|
|
803
|
+
}`,{id:f,assigneeId:b.id})}if(c.labels&&c.labels.length>0){let b=new Set((await a(`query($id: String!) {
|
|
804
|
+
issue(id: $id) {
|
|
805
|
+
labels { nodes { id } }
|
|
806
|
+
}
|
|
807
|
+
}`,{id:f})).issue.labels.nodes.map(a=>a.id)),d=new Map((await a(`query($teamId: ID) {
|
|
808
|
+
issueLabels(filter: { team: { id: { eq: $teamId } } }) {
|
|
809
|
+
nodes { id name }
|
|
810
|
+
}
|
|
811
|
+
}`,{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!]!) {
|
|
812
|
+
issueUpdate(id: $id, input: { labelIds: $labelIds }) {
|
|
813
|
+
success
|
|
814
|
+
}
|
|
815
|
+
}`,{id:f,labelIds:[...b]})}c.comment&&await a(`mutation($issueId: String!, $body: String!) {
|
|
816
|
+
commentCreate(input: { issueId: $issueId, body: $body }) {
|
|
817
|
+
success
|
|
818
|
+
}
|
|
819
|
+
}`,{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) {
|
|
820
|
+
issueCreate(input: {
|
|
821
|
+
title: $title,
|
|
822
|
+
description: $description,
|
|
823
|
+
teamId: $teamId,
|
|
824
|
+
priority: $priority
|
|
825
|
+
}) {
|
|
826
|
+
success
|
|
827
|
+
issue {
|
|
828
|
+
${cl}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}`,e)).issueCreate.issue,g={id:f.identifier,title:f.title,description:f.description??"",url:f.url,state:ck(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) {
|
|
832
|
+
users(filter: $filter) {
|
|
833
|
+
nodes { id displayName name }
|
|
834
|
+
}
|
|
835
|
+
}`,{filter:{displayName:{eq:b.assignee}}})).users.nodes[0];c&&(await a(`mutation($id: String!, $assigneeId: String!) {
|
|
836
|
+
issueUpdate(id: $id, input: { assigneeId: $assigneeId }) {
|
|
837
|
+
success
|
|
838
|
+
}
|
|
839
|
+
}`,{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) {
|
|
840
|
+
issueLabels(filter: { team: { id: { eq: $teamId } } }) {
|
|
841
|
+
nodes { id name }
|
|
842
|
+
}
|
|
843
|
+
}`,{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!]!) {
|
|
844
|
+
issueUpdate(id: $id, input: { labelIds: $labelIds }) {
|
|
845
|
+
success
|
|
846
|
+
}
|
|
847
|
+
}`,{id:f.id,labelIds:i}),g.labels=h)}catch{}return g}}}let cn={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,e=process.env.COMPOSIO_ENTITY_ID??"default";return cm(async(f,g)=>{let h,i=(await (!b&&(b=(async()=>{try{let{Composio:b}=await c.e(4422).then(c.bind(c,64422));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 cf||(cf=!0,(0,d.plx)({source:"tracker",kind:"tracker.dep_missing",level:"error",summary:"Composio SDK (@composio/core) is not installed",data:{plugin:"tracker-linear",package:"@composio/core",installHint:"pnpm add @composio/core"}})),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:e,arguments:{query_or_mutation:f,variables:g?JSON.stringify(g):"{}"}}),j=new Promise((a,b)=>{h=setTimeout(()=>{cg({source:"tracker",kind:"tracker.api_timeout",level:"warn",summary:"Composio Linear API request timed out after 30s",data:{plugin:"tracker-linear",transport:"composio",timeoutMs:3e4}}),b(Error("Composio Linear API request timed out after 30s"))},3e4)});i.catch(()=>{}),j.catch(()=>{});try{let a=await Promise.race([i,j]);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(h)}})}return cm(async(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}),e=()=>new Promise((a,b)=>{let e=new URL("https://api.linear.app/graphql"),f=!1,g=a=>{f||(f=!0,a())},h=(0,ce.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(new ci(a.message)))),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(new ch(f,e));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(),cg({source:"tracker",kind:"tracker.api_timeout",level:"warn",summary:"Linear API request timed out after 30s",data:{plugin:"tracker-linear",transport:"direct",timeoutMs:3e4}}),b(new cj)})}),h.on("error",a=>g(()=>b(new ci(a.message)))),h.write(d),h.end()});for(let a=1;a<=3;a++)try{return await e()}catch(b){if(!((b instanceof ch?b.transient:b instanceof cj||b instanceof ci)&&a<3))throw b;await function(a){return new Promise(b=>setTimeout(b,a))}(500*a)}throw Error("unreachable")})}},co=globalThis;function cp(){if(co._aoServices)return Promise.resolve(co._aoServices);if(!co._aoServicesInit){let a=co._aoServicesGeneration??0,b=cr().then(b=>(co._aoServicesGeneration??0)!==a?(b.lifecycleManager.stop(),cp()):(co._aoServices=b,b)).catch(a=>{throw co._aoServicesInit===b&&(co._aoServicesInit=void 0),a});co._aoServicesInit=b}return co._aoServicesInit}function cq(){co._aoServicesGeneration=(co._aoServicesGeneration??0)+1,co._aoServices&&co._aoServices.lifecycleManager.stop(),co._aoServices=void 0,co._aoServicesInit=void 0}async function cr(){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(W),b.register(ar),b.register(av),b.register(aS),b.register(a5),b.register(a9),b.register(bp),b.register(b4),b.register(cd),b.register(cn);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 cs="agent:backlog",ct=globalThis;function cu(){ct._aoBacklogStarted||(ct._aoBacklogStarted=!0,cy(),ct._aoBacklogTimer=setInterval(()=>void cy(),6e4))}let cv=new Set;async function cw(a,b,c){for(let d of a.filter(a=>"merged"===a.lifecycle.pr.state&&a.issueId&&!cv.has(`${a.projectId}:${a.issueId}`))){let a=`${d.projectId}:${d.issueId}`,e=b.projects[d.projectId];if(!e?.tracker?.plugin){cv.add(a);continue}let f=c.get("tracker",e.tracker.plugin);if(!f?.updateIssue){cv.add(a);continue}let g=d.issueId;if(!g){cv.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)}cv.add(a)}}async function cx(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:[cs],removeLabels:["agent:done"],comment:"Issue reopened — returning to agent backlog."},c),console.log(`[backlog] Relabeled reopened issue ${b.id} → ${cs}`)}catch(a){console.error(`[backlog] Failed to relabel reopened issue ${b.id}:`,a)}}}}async function cy(){try{let{config:a,registry:b,sessionManager:c}=await cp(),e=await c.list();await cw(e,a,b),await cx(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:[cs],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 cz(){let a=[];try{let{config:b,registry:c}=await cp();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:[cs],limit:20},e)))a.push({...c,projectId:d})}catch{}}}catch{}return a}async function cA(){let a=[];try{let{config:b,registry:c}=await cp();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 cB(a,b){return b?.scm?.plugin?a.get("scm",b.scm.plugin):null}}};
|