@aoagents/ao-web 0.2.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +296 -223
- package/.next/app-path-routes-manifest.json +16 -8
- package/.next/build-manifest.json +14 -14
- package/.next/next-minimal-server.js.nft.json +1 -1
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +31 -31
- package/.next/react-loadable-manifest.json +18 -18
- package/.next/required-server-files.json +9 -4
- package/.next/routes-manifest.json +33 -0
- package/.next/server/app/_not-found/page.js +2 -2
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +15 -15
- package/.next/server/app/api/backlog/route.js +1 -1
- package/.next/server/app/api/backlog/route.js.nft.json +1 -1
- package/.next/server/app/api/backlog/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/browse-directory/route.js +1 -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/events/route.js +3 -3
- package/.next/server/app/api/events/route.js.nft.json +1 -1
- package/.next/server/app/api/events/route_client-reference-manifest.js +1 -1
- 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 -1
- package/.next/server/app/api/issues/route.js.nft.json +1 -1
- package/.next/server/app/api/issues/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/observability/route.js +1 -1
- package/.next/server/app/api/observability/route.js.nft.json +1 -1
- package/.next/server/app/api/observability/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/orchestrators/route.js +1 -1
- package/.next/server/app/api/orchestrators/route.js.nft.json +1 -1
- package/.next/server/app/api/orchestrators/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/projects/[id]/route.js +1 -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 -1
- package/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/prs/[id]/merge/route.js +1 -1
- package/.next/server/app/api/prs/[id]/merge/route.js.nft.json +1 -1
- package/.next/server/app/api/prs/[id]/merge/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/runtime/terminal/route.js +1 -1
- package/.next/server/app/api/runtime/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/runtime/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/[id]/kill/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/kill/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/kill/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/[id]/message/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/message/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/message/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/[id]/remap/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/remap/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/remap/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/[id]/restore/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/restore/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/[id]/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/[id]/send/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sessions/patches/route.js +1 -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 -1
- package/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/setup-labels/route.js +1 -1
- package/.next/server/app/api/setup-labels/route.js.nft.json +1 -1
- package/.next/server/app/api/setup-labels/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/spawn/route.js +1 -1
- package/.next/server/app/api/spawn/route.js.nft.json +1 -1
- package/.next/server/app/api/spawn/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verify/route.js +1 -1
- package/.next/server/app/api/verify/route.js.nft.json +1 -1
- package/.next/server/app/api/verify/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/webhooks/[...slug]/route.js +1 -1
- package/.next/server/app/api/webhooks/[...slug]/route.js.nft.json +1 -1
- package/.next/server/app/api/webhooks/[...slug]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/apple-icon/route.js +1 -1
- package/.next/server/app/apple-icon/route.js.nft.json +1 -1
- package/.next/server/app/apple-icon/route_client-reference-manifest.js +1 -1
- package/.next/server/app/dev/terminal-test/page.js +3 -3
- package/.next/server/app/dev/terminal-test/page.js.nft.json +1 -1
- package/.next/server/app/dev/terminal-test/page_client-reference-manifest.js +1 -1
- package/.next/server/app/dev/terminal-test.html +1 -1
- package/.next/server/app/dev/terminal-test.rsc +17 -17
- package/.next/server/app/icon/route.js +1 -1
- package/.next/server/app/icon/route.js.nft.json +1 -1
- package/.next/server/app/icon/route_client-reference-manifest.js +1 -1
- package/.next/server/app/icon-192/route.js +1 -1
- package/.next/server/app/icon-192/route.js.nft.json +1 -1
- package/.next/server/app/icon-192/route_client-reference-manifest.js +1 -1
- package/.next/server/app/icon-512/route.js +1 -1
- package/.next/server/app/icon-512/route.js.nft.json +1 -1
- package/.next/server/app/icon-512/route_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest/route.js +2 -2
- package/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -1
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest.body +1 -1
- package/.next/server/app/orchestrators/page.js +2 -2
- package/.next/server/app/orchestrators/page.js.nft.json +1 -1
- package/.next/server/app/orchestrators/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page.js +2 -2
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/projects/[projectId]/page.js +2 -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 -2
- package/.next/server/app/prs/page.js.nft.json +1 -1
- package/.next/server/app/prs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/[id]/page.js +2 -12
- package/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
- package/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/test-direct/page.js +2 -2
- package/.next/server/app/test-direct/page.js.nft.json +1 -1
- package/.next/server/app/test-direct/page_client-reference-manifest.js +1 -1
- package/.next/server/app/test-direct.html +1 -1
- package/.next/server/app/test-direct.rsc +17 -17
- package/.next/server/app-paths-manifest.json +16 -8
- package/.next/server/chunks/1172.js +1 -0
- package/.next/server/chunks/1271.js +1 -0
- package/.next/server/chunks/2106.js +1 -0
- package/.next/server/chunks/252.js +11 -0
- package/.next/server/chunks/2810.js +1 -0
- package/.next/server/chunks/3602.js +382 -0
- package/.next/server/chunks/3667.js +277 -0
- package/.next/server/chunks/3714.js +1 -0
- package/.next/server/chunks/4520.js +1 -0
- package/.next/server/chunks/6086.js +25 -0
- package/.next/server/chunks/6172.js +9 -0
- package/.next/server/chunks/8367.js +3 -0
- package/.next/server/chunks/8386.js +1 -0
- package/.next/server/chunks/8803.js +6 -0
- package/.next/server/chunks/9561.js +22 -0
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/next-font-manifest.js +1 -1
- package/.next/server/next-font-manifest.json +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/pages/_app.js +1 -1
- package/.next/server/pages/_app.js.nft.json +1 -1
- package/.next/server/pages/_document.js +1 -1
- package/.next/server/pages/_document.js.nft.json +1 -1
- package/.next/server/pages/_error.js +3 -3
- package/.next/server/pages/_error.js.nft.json +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/server/webpack-runtime.js +1 -1
- package/.next/static/chunks/1461-af7c54935f21d56d.js +1 -0
- package/.next/static/chunks/1d2d5650.1ef8611b5325bd83.js +18 -0
- package/.next/static/chunks/{9393.acf1934a190d793b.js → 2529.32352c1ce5253e3e.js} +1 -1
- package/.next/static/chunks/3697.4d6d86c5f0caf73e.js +1 -0
- package/.next/static/chunks/4465-aaba60a6355de914.js +1 -0
- package/.next/static/chunks/{7411.ecda44797fb514a0.js → 5491.fd98884d48631149.js} +1 -1
- package/.next/static/chunks/6078.47ce88bee96cfaee.js +1 -0
- package/.next/static/chunks/6607-405ce4d15e595f4a.js +1 -0
- package/.next/static/chunks/7008-71ebb186f0549f41.js +1 -0
- package/.next/static/chunks/7317.685aa5231218e8d3.js +1 -0
- package/.next/static/chunks/8713-d3d663f55dc00e48.js +1 -0
- package/.next/static/chunks/88a6fc35-f836b4b72df5eafa.js +1 -0
- package/.next/static/chunks/9331-fcdd652218ac6f68.js +1 -0
- package/.next/static/chunks/app/_not-found/page-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/backlog/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/browse-directory/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/events/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/filesystem/browse/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/issues/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/observability/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/orchestrators/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/projects/[id]/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/projects/reload/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/projects/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/prs/[id]/merge/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/runtime/terminal/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/kill/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/message/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/remap/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/restore/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/send/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/sessions/patches/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/sessions/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/setup-labels/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/spawn/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/verify/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/api/webhooks/[...slug]/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/apple-icon/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/dev/terminal-test/page-5765f0465db56fed.js +1 -0
- package/.next/static/chunks/app/error-670f1d8bf2b6859c.js +1 -0
- package/.next/static/chunks/app/{global-error-7b5c8ae45329c659.js → global-error-ca06d2b1be2d4ae0.js} +1 -1
- package/.next/static/chunks/app/icon/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/icon-192/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/icon-512/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/layout-ddf79478d9a673bb.js +1 -0
- package/.next/static/chunks/app/loading-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/manifest.webmanifest/route-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/{not-found-3772c2e09c29d80f.js → not-found-824d5d3c6e296eeb.js} +1 -1
- package/.next/static/chunks/app/orchestrators/page-4c190484788aaaa3.js +1 -0
- package/.next/static/chunks/app/page-d3b83ad5f09b6ec7.js +1 -0
- package/.next/static/chunks/app/projects/[projectId]/loading-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/projects/[projectId]/page-9f3dfbea006747cf.js +1 -0
- package/.next/static/chunks/app/projects/[projectId]/sessions/[id]/page-a7090a06948f9a6b.js +1 -0
- package/.next/static/chunks/app/projects/[projectId]/settings/page-219df6dcbc6d1107.js +1 -0
- package/.next/static/chunks/app/prs/page-a285e930235a23af.js +1 -0
- package/.next/static/chunks/app/sessions/[id]/error-eb0973907da68a37.js +1 -0
- package/.next/static/chunks/app/sessions/[id]/loading-e2dea9178b4af8db.js +1 -0
- package/.next/static/chunks/app/sessions/[id]/{not-found-3772c2e09c29d80f.js → not-found-824d5d3c6e296eeb.js} +1 -1
- package/.next/static/chunks/app/sessions/[id]/page-98f398b822092218.js +1 -0
- package/.next/static/chunks/app/test-direct/page-f9bff7d7b4dfe728.js +1 -0
- package/.next/static/chunks/framework-7060e2ac4971c604.js +1 -0
- package/.next/static/chunks/main-app-690acf9d5d2050c9.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/{webpack-e12ceebeb7a1cc7e.js → webpack-d4ff5ed5e153ca3e.js} +1 -1
- package/.next/static/css/577ea7f5ad4f0576.css +1 -0
- package/.next/static/css/659eccb5db697b76.css +1 -0
- package/.next/static/q6yh3n8jgvyI9JIbexzuH/_buildManifest.js +1 -0
- package/dist-server/direct-terminal-ws.js +33 -236
- package/dist-server/mux-websocket.js +516 -0
- package/dist-server/start-all.js +0 -2
- package/next.config.js +5 -0
- package/package.json +18 -15
- package/.next/server/chunks/27.js +0 -438
- package/.next/server/chunks/377.js +0 -1
- package/.next/server/chunks/393.js +0 -1
- package/.next/server/chunks/627.js +0 -391
- package/.next/server/chunks/639.js +0 -6
- package/.next/server/chunks/693.js +0 -1
- package/.next/server/chunks/705.js +0 -22
- package/.next/server/chunks/787.js +0 -29
- package/.next/server/chunks/796.js +0 -1
- package/.next/server/chunks/934.js +0 -1
- package/.next/server/chunks/956.js +0 -9
- package/.next/static/WS8DHHp9haunZGhtE8L33/_buildManifest.js +0 -1
- package/.next/static/chunks/1250-e7cf6b069fbb03ed.js +0 -1
- package/.next/static/chunks/2205.498806f73783aa54.js +0 -1
- package/.next/static/chunks/3698-9c12c45b8184022c.js +0 -1
- package/.next/static/chunks/6381.1541d5695a727108.js +0 -1
- package/.next/static/chunks/7505-2d2422d31862995f.js +0 -1
- package/.next/static/chunks/8597-1385f90ec1cebf47.js +0 -1
- package/.next/static/chunks/8762.f3d526855363db16.js +0 -1
- package/.next/static/chunks/a51c26f2-a21e680a5df6764e.js +0 -1
- package/.next/static/chunks/app/_not-found/page-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/backlog/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/events/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/issues/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/observability/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/orchestrators/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/projects/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/prs/[id]/merge/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/runtime/terminal/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/kill/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/message/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/remap/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/restore/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/send/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/sessions/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/setup-labels/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/spawn/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/verify/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/api/webhooks/[...slug]/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/apple-icon/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/dev/terminal-test/page-ac0ce5b046fcad82.js +0 -1
- package/.next/static/chunks/app/error-4896c9d3b7681a80.js +0 -1
- package/.next/static/chunks/app/icon/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/icon-192/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/icon-512/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/layout-023f2083204e4f68.js +0 -1
- package/.next/static/chunks/app/loading-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/manifest.webmanifest/route-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/orchestrators/page-df85236df674fc5a.js +0 -1
- package/.next/static/chunks/app/page-e97da633b7ef25f2.js +0 -1
- package/.next/static/chunks/app/prs/page-8cc0fce584d238c5.js +0 -1
- package/.next/static/chunks/app/sessions/[id]/error-90bc99b777fecabf.js +0 -1
- package/.next/static/chunks/app/sessions/[id]/loading-2224bc1d3dce1b3e.js +0 -1
- package/.next/static/chunks/app/sessions/[id]/page-c9c95a8604786cff.js +0 -1
- package/.next/static/chunks/app/test-direct/page-16ceeb9f7664394a.js +0 -1
- package/.next/static/chunks/df4ed4d4.6a752eba3933e9a8.js +0 -3
- package/.next/static/chunks/framework-f8b8ba0f71d38056.js +0 -1
- package/.next/static/chunks/main-2bc85c765bf1fc49.js +0 -1
- package/.next/static/chunks/main-app-93fb36c3bd1a6739.js +0 -1
- package/.next/static/chunks/pages/_app-a0b975794f15bd68.js +0 -1
- package/.next/static/chunks/pages/_error-5f4e3b5eea57917d.js +0 -1
- package/.next/static/css/6ef2fa08dd043252.css +0 -1
- package/.next/static/css/908f93fdd7ffba42.css +0 -1
- package/dist-server/terminal-websocket.js +0 -375
- /package/.next/static/{WS8DHHp9haunZGhtE8L33 → q6yh3n8jgvyI9JIbexzuH}/_ssgManifest.js +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,::backdrop,:after,:before{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial}}}@layer theme{:host,:root{--font-sans:var(--font-geist-sans),"SF Pro Text",-apple-system,system-ui,sans-serif;--font-mono:var(--font-jetbrains-mono),"SF Mono","Menlo","Consolas",monospace;--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-3xl:48rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25/1.875);--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-normal:0em;--tracking-wide:.025em;--tracking-wider:.05em;--leading-snug:1.375;--leading-relaxed:1.625;--radius-lg:8px;--radius-2xl:1rem;--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,::backdrop,:after,:before{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}:host,html{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}menu,ol,ul{list-style:none}audio,canvas,embed,iframe,img,object,svg,video{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,optgroup,select,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:calc(var(--spacing)*0)}.top-0{top:calc(var(--spacing)*0)}.top-\[calc\(100\%\+0\.5rem\)\]{top:calc(100% + .5rem)}.right-0{right:calc(var(--spacing)*0)}.z-10{z-index:10}.z-50{z-index:50}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.mx-2{margin-inline:calc(var(--spacing)*2)}.mx-auto{margin-inline:auto}.my-2{margin-block:calc(var(--spacing)*2)}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-1\.5{margin-top:calc(var(--spacing)*1.5)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-5{margin-top:calc(var(--spacing)*5)}.mt-6{margin-top:calc(var(--spacing)*6)}.mt-8{margin-top:calc(var(--spacing)*8)}.mt-auto{margin-top:auto}.mr-1{margin-right:calc(var(--spacing)*1)}.mr-2{margin-right:calc(var(--spacing)*2)}.mb-0\.5{margin-bottom:calc(var(--spacing)*.5)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-2\.5{margin-bottom:calc(var(--spacing)*2.5)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-5{margin-bottom:calc(var(--spacing)*5)}.mb-6{margin-bottom:calc(var(--spacing)*6)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-2{margin-left:calc(var(--spacing)*2)}.ml-3{margin-left:calc(var(--spacing)*3)}.ml-5{margin-left:calc(var(--spacing)*5)}.ml-6{margin-left:calc(var(--spacing)*6)}.ml-auto{margin-left:auto}.\[display\:-webkit-box\]{display:-webkit-box}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.h-1\.5{height:calc(var(--spacing)*1.5)}.h-2{height:calc(var(--spacing)*2)}.h-2\.5{height:calc(var(--spacing)*2.5)}.h-3{height:calc(var(--spacing)*3)}.h-3\.5{height:calc(var(--spacing)*3.5)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-7{height:calc(var(--spacing)*7)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-14{height:calc(var(--spacing)*14)}.h-\[7px\]{height:7px}.h-\[14px\]{height:14px}.h-\[18px\]{height:18px}.h-\[440px\]{height:440px}.h-full{height:100%}.h-screen{height:100vh}.min-h-0{min-height:calc(var(--spacing)*0)}.min-h-\[calc\(100vh-4rem\)\]{min-height:calc(100vh - 4rem)}.min-h-screen{min-height:100vh}.w-0\.5{width:calc(var(--spacing)*.5)}.w-1\.5{width:calc(var(--spacing)*1.5)}.w-2{width:calc(var(--spacing)*2)}.w-2\.5{width:calc(var(--spacing)*2.5)}.w-3{width:calc(var(--spacing)*3)}.w-3\.5{width:calc(var(--spacing)*3.5)}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-7{width:calc(var(--spacing)*7)}.w-8{width:calc(var(--spacing)*8)}.w-9{width:calc(var(--spacing)*9)}.w-10{width:calc(var(--spacing)*10)}.w-12{width:calc(var(--spacing)*12)}.w-14{width:calc(var(--spacing)*14)}.w-16{width:calc(var(--spacing)*16)}.w-\[7px\]{width:7px}.w-\[18px\]{width:18px}.w-\[56px\]{width:56px}.w-\[244px\]{width:244px}.w-full{width:100%}.w-px{width:1px}.max-w-3xl{max-width:var(--container-3xl)}.max-w-7xl{max-width:var(--container-7xl)}.max-w-\[34rem\]{max-width:34rem}.max-w-\[36rem\]{max-width:36rem}.max-w-\[40ch\]{max-width:40ch}.max-w-\[420px\]{max-width:420px}.max-w-\[900px\]{max-width:900px}.max-w-\[1180px\]{max-width:1180px}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-\[78px\]{min-width:78px}.min-w-\[220px\]{min-width:220px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.border-collapse{border-collapse:collapse}.rotate-90{rotate:90deg}.animate-\[activity-pulse_2s_ease-in-out_infinite\]{animation:activity-pulse 2s ease-in-out infinite}.animate-\[pulse_1\.5s_ease-in-out_infinite\]{animation:pulse 1.5s ease-in-out infinite}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-2\.5{gap:calc(var(--spacing)*2.5)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1.5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1.5)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}.gap-x-3{column-gap:calc(var(--spacing)*3)}.gap-y-1{row-gap:calc(var(--spacing)*1)}.truncate{text-overflow:ellipsis;white-space:nowrap}.overflow-hidden,.truncate{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-\[2px\]{border-radius:2px}.rounded-\[28px\]{border-radius:28px}.rounded-full{border-radius:3.40282e+38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-none{border-radius:0}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-\[color-mix\(in_srgb\,var\(--color-accent\)_35\%\,transparent\)\]{border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.border-\[color-mix\(in_srgb\,var\(--color-accent\)_35\%\,transparent\)\]{border-color:color-mix(in srgb,var(--color-accent)35%,transparent)}}.border-\[color-mix\(in_srgb\,var\(--color-status-attention\)_25\%\,transparent\)\]{border-color:var(--color-status-attention)}@supports (color:color-mix(in lab,red,red)){.border-\[color-mix\(in_srgb\,var\(--color-status-attention\)_25\%\,transparent\)\]{border-color:color-mix(in srgb,var(--color-status-attention)25%,transparent)}}.border-\[color-mix\(in_srgb\,var\(--color-status-error\)_35\%\,transparent\)\]{border-color:var(--color-status-error)}@supports (color:color-mix(in lab,red,red)){.border-\[color-mix\(in_srgb\,var\(--color-status-error\)_35\%\,transparent\)\]{border-color:color-mix(in srgb,var(--color-status-error)35%,transparent)}}.border-\[color-mix\(in_srgb\,var\(--color-status-ready\)_30\%\,transparent\)\]{border-color:var(--color-status-ready)}@supports (color:color-mix(in lab,red,red)){.border-\[color-mix\(in_srgb\,var\(--color-status-ready\)_30\%\,transparent\)\]{border-color:color-mix(in srgb,var(--color-status-ready)30%,transparent)}}.border-\[rgba\(63\,185\,80\,0\.25\)\]{border-color:#3fb95040}.border-\[var\(--color-accent\)\]{border-color:var(--color-accent)}.border-\[var\(--color-accent-blue\)\]{border-color:var(--color-accent-blue)}.border-\[var\(--color-accent-orange\)\]{border-color:var(--color-accent-orange)}.border-\[var\(--color-accent-red\)\]{border-color:var(--color-accent-red)}.border-\[var\(--color-border-default\)\]{border-color:var(--color-border-default)}.border-\[var\(--color-border-muted\)\]{border-color:var(--color-border-muted)}.border-\[var\(--color-border-strong\)\]{border-color:var(--color-border-strong)}.border-\[var\(--color-border-subtle\)\]{border-color:var(--color-border-subtle)}.bg-\[\#0a0a0f\]{background-color:#0a0a0f}.bg-\[\#3fb950\]{background-color:#3fb950}.bg-\[\#d29922\]{background-color:#d29922}.bg-\[\#f85149\]{background-color:#f85149}.bg-\[\#fafafa\]{background-color:#fafafa}.bg-\[rgba\(63\,185\,80\,0\.1\)\]{background-color:#3fb9501a}.bg-\[rgba\(63\,185\,80\,0\.07\)\]{background-color:#3fb95012}.bg-\[rgba\(125\,133\,144\,0\.08\)\]{background-color:#7d859014}.bg-\[rgba\(210\,153\,34\,0\.1\)\]{background-color:#d299221a}.bg-\[rgba\(248\,81\,73\,0\.15\)\]{background-color:#f8514926}.bg-\[var\(--color-accent\)\]{background-color:var(--color-accent)}.bg-\[var\(--color-accent-blue\)\]{background-color:var(--color-accent-blue)}.bg-\[var\(--color-accent-green\)\]{background-color:var(--color-accent-green)}.bg-\[var\(--color-accent-red\)\]{background-color:var(--color-accent-red)}.bg-\[var\(--color-alert-changes-bg\)\]{background-color:var(--color-alert-changes-bg)}.bg-\[var\(--color-alert-ci-bg\)\]{background-color:var(--color-alert-ci-bg)}.bg-\[var\(--color-alert-comment-bg\)\]{background-color:var(--color-alert-comment-bg)}.bg-\[var\(--color-alert-conflict-bg\)\]{background-color:var(--color-alert-conflict-bg)}.bg-\[var\(--color-alert-review-bg\)\]{background-color:var(--color-alert-review-bg)}.bg-\[var\(--color-bg-base\)\]{background-color:var(--color-bg-base)}.bg-\[var\(--color-bg-elevated\)\]{background-color:var(--color-bg-elevated)}.bg-\[var\(--color-bg-primary\)\]{background-color:var(--color-bg-primary)}.bg-\[var\(--color-bg-secondary\)\]{background-color:var(--color-bg-secondary)}.bg-\[var\(--color-bg-subtle\)\]{background-color:var(--color-bg-subtle)}.bg-\[var\(--color-bg-surface\)\]{background-color:var(--color-bg-surface)}.bg-\[var\(--color-bg-tertiary\)\]{background-color:var(--color-bg-tertiary)}.bg-\[var\(--color-border-subtle\)\]{background-color:var(--color-border-subtle)}.bg-\[var\(--color-chip-bg\)\]{background-color:var(--color-chip-bg)}.bg-\[var\(--color-status-attention\)\]{background-color:var(--color-status-attention)}.bg-\[var\(--color-status-error\)\]{background-color:var(--color-status-error)}.bg-\[var\(--color-status-ready\)\]{background-color:var(--color-status-ready)}.bg-\[var\(--color-tint-red\)\]{background-color:var(--color-tint-red)}.bg-\[var\(--color-tint-yellow\)\]{background-color:var(--color-tint-yellow)}.bg-black{background-color:var(--color-black)}.p-1\.5{padding:calc(var(--spacing)*1.5)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.p-8{padding:calc(var(--spacing)*8)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-2\.5{padding-inline:calc(var(--spacing)*2.5)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-3\.5{padding-inline:calc(var(--spacing)*3.5)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-5{padding-inline:calc(var(--spacing)*5)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-3\.5{padding-block:calc(var(--spacing)*3.5)}.py-4{padding-block:calc(var(--spacing)*4)}.py-5{padding-block:calc(var(--spacing)*5)}.py-6{padding-block:calc(var(--spacing)*6)}.py-8{padding-block:calc(var(--spacing)*8)}.py-10{padding-block:calc(var(--spacing)*10)}.py-24{padding-block:calc(var(--spacing)*24)}.py-\[6px\]{padding-block:6px}.py-\[9px\]{padding-block:9px}.py-px{padding-block:1px}.pt-0\.5{padding-top:calc(var(--spacing)*.5)}.pt-3{padding-top:calc(var(--spacing)*3)}.pt-4{padding-top:calc(var(--spacing)*4)}.pt-5{padding-top:calc(var(--spacing)*5)}.pt-6{padding-top:calc(var(--spacing)*6)}.pr-2{padding-right:calc(var(--spacing)*2)}.pb-1\.5{padding-bottom:calc(var(--spacing)*1.5)}.pb-2{padding-bottom:calc(var(--spacing)*2)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.pl-3{padding-left:calc(var(--spacing)*3)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[17px\]{font-size:17px}.text-\[18px\]{font-size:18px}.text-\[22px\]{font-size:22px}.text-\[24px\]{font-size:24px}.leading-5{--tw-leading:calc(var(--spacing)*5);line-height:calc(var(--spacing)*5)}.leading-6{--tw-leading:calc(var(--spacing)*6);line-height:calc(var(--spacing)*6)}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.font-\[var\(--font-mono\)\]{--tw-font-weight:var(--font-mono);font-weight:var(--font-mono)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[-0\.03em\]{--tw-tracking:-.03em;letter-spacing:-.03em}.tracking-\[-0\.04em\]{--tw-tracking:-.04em;letter-spacing:-.04em}.tracking-\[0\.1em\]{--tw-tracking:.1em;letter-spacing:.1em}.tracking-\[0\.06em\]{--tw-tracking:.06em;letter-spacing:.06em}.tracking-\[0\.08em\]{--tw-tracking:.08em;letter-spacing:.08em}.tracking-\[0\.10em\]{--tw-tracking:.1em;letter-spacing:.1em}.tracking-\[0\.22em\]{--tw-tracking:.22em;letter-spacing:.22em}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[var\(--color-accent\)\]{color:var(--color-accent)}.text-\[var\(--color-accent-blue\)\]{color:var(--color-accent-blue)}.text-\[var\(--color-accent-green\)\]{color:var(--color-accent-green)}.text-\[var\(--color-accent-orange\)\]{color:var(--color-accent-orange)}.text-\[var\(--color-accent-red\)\]{color:var(--color-accent-red)}.text-\[var\(--color-accent-yellow\)\]{color:var(--color-accent-yellow)}.text-\[var\(--color-border-default\)\]{color:var(--color-border-default)}.text-\[var\(--color-border-strong\)\]{color:var(--color-border-strong)}.text-\[var\(--color-status-attention\)\]{color:var(--color-status-attention)}.text-\[var\(--color-status-error\)\]{color:var(--color-status-error)}.text-\[var\(--color-status-ready\)\]{color:var(--color-status-ready)}.text-\[var\(--color-text-muted\)\]{color:var(--color-text-muted)}.text-\[var\(--color-text-primary\)\]{color:var(--color-text-primary)}.text-\[var\(--color-text-secondary\)\]{color:var(--color-text-secondary)}.text-\[var\(--color-text-tertiary\)\]{color:var(--color-text-tertiary)}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,)var(--tw-slashed-zero,)var(--tw-numeric-figure,)var(--tw-numeric-spacing,)var(--tw-numeric-fraction,)}.\!underline{text-decoration-line:underline!important}.no-underline{text-decoration-line:none}.\[text-underline-offset\:2px\],.underline-offset-2{text-underline-offset:2px}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-25{opacity:.25}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.shadow-\[0_18px_40px_rgba\(0\,0\,0\,0\.18\)\]{--tw-shadow:0 18px 40px var(--tw-shadow-color,#0000002e);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.\[-webkit-box-orient\:vertical\]{-webkit-box-orient:vertical}.\[-webkit-line-clamp\:2\]{-webkit-line-clamp:2}.\[text-decoration-skip-ink\:none\]{-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}.group-open\:rotate-90:is(:where(.group):is([open],:popover-open,:open) *){rotate:90deg}@media (hover:hover){.hover\:border-\[var\(--color-accent\)\]:hover{border-color:var(--color-accent)}.hover\:border-\[var\(--color-border-default\)\]:hover{border-color:var(--color-border-default)}.hover\:border-\[var\(--color-border-strong\)\]:hover{border-color:var(--color-border-strong)}.hover\:border-\[var\(--color-status-error\)\]:hover{border-color:var(--color-status-error)}.hover\:bg-\[rgba\(88\,166\,255\,0\.03\)\]:hover{background-color:#58a6ff08}.hover\:bg-\[rgba\(255\,255\,255\,0\.04\)\]:hover{background-color:#ffffff0a}.hover\:bg-\[var\(--color-bg-elevated-hover\)\]:hover{background-color:var(--color-bg-elevated-hover)}.hover\:bg-\[var\(--color-bg-hover\)\]:hover{background-color:var(--color-bg-hover)}.hover\:bg-\[var\(--color-bg-secondary\)\]:hover{background-color:var(--color-bg-secondary)}.hover\:bg-\[var\(--color-bg-subtle\)\]:hover{background-color:var(--color-bg-subtle)}.hover\:bg-\[var\(--color-tint-blue\)\]:hover{background-color:var(--color-tint-blue)}.hover\:bg-\[var\(--color-tint-red\)\]:hover{background-color:var(--color-tint-red)}.hover\:text-\[var\(--color-accent\)\]:hover{color:var(--color-accent)}.hover\:text-\[var\(--color-text-primary\)\]:hover{color:var(--color-text-primary)}.hover\:text-\[var\(--color-text-secondary\)\]:hover{color:var(--color-text-secondary)}.hover\:no-underline:hover{text-decoration-line:none}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}.hover\:opacity-90:hover{opacity:.9}.hover\:opacity-100:hover{opacity:1}.hover\:shadow-sm:hover{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.hover\:brightness-110:hover{--tw-brightness:brightness(110%)}.hover\:brightness-110:hover,.hover\:brightness-125:hover{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.hover\:brightness-125:hover{--tw-brightness:brightness(125%)}}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:cursor-wait:disabled{cursor:wait}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-70:disabled{opacity:.7}@media (min-width:40rem){.sm\:flex-row{flex-direction:row}.sm\:items-start{align-items:flex-start}.sm\:p-8{padding:calc(var(--spacing)*8)}}@media (min-width:48rem){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:px-7{padding-inline:calc(var(--spacing)*7)}.md\:py-6{padding-block:calc(var(--spacing)*6)}}@media (min-width:64rem){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:justify-end{justify-content:flex-end}.lg\:px-8{padding-inline:calc(var(--spacing)*8)}}@media (min-width:80rem){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}}:root{--color-bg-base:#f5f5f7;--color-bg-surface:#fff;--color-bg-elevated:#fff;--color-bg-elevated-hover:#f7f7f8;--color-bg-subtle:#f0f0f2;--color-bg-primary:var(--color-bg-base);--color-bg-secondary:var(--color-bg-surface);--color-bg-tertiary:var(--color-bg-elevated);--color-border-subtle:#e7e7ec;--color-border-default:#d9d9de;--color-border-strong:#c9c9d2;--color-border-muted:var(--color-border-subtle);--color-border-emphasis:var(--color-border-strong);--color-text-primary:#1b1b1f;--color-text-secondary:#5e5e66;--color-text-tertiary:#8e8e96;--color-text-muted:#8e8e96;--color-text-inverse:#fff;--color-accent:#5b7ef8;--color-accent-hover:#7a96ff;--color-accent-subtle:#5b7ef81f;--color-status-working:#16a34a;--color-status-ready:#5e6ad2;--color-status-respond:#ca8a04;--color-status-review:#0891b2;--color-status-attention:#9a6700;--color-status-idle:#8b949e;--color-status-done:#d0d7de;--color-status-error:#dc2626;--color-accent-blue:#5b7ef8;--color-accent-green:#16a34a;--color-accent-yellow:#9a6700;--color-accent-orange:#bc4c00;--color-accent-red:#dc2626;--color-accent-violet:#5b7ef8;--color-accent-purple:#5b7ef8;--color-tint-blue:#5b7ef814;--color-tint-green:#16a34a14;--color-tint-yellow:#9a670014;--color-tint-red:#dc262614;--color-tint-violet:#5b7ef814;--color-tint-orange:#bc4c0014;--color-tint-neutral:#0000000a;--color-chip-bg:#f2f2f2;--color-hover-overlay:#f7f7f8;--color-scrollbar:#00000014;--color-scrollbar-hover:#00000026;--color-scrollbar-active:#00000040;--color-body-gradient-blue:transparent;--color-body-gradient-violet:transparent;--color-nav-bg:#fff;--card-bg:#fff;--card-merge-bg:#f6fbf8;--card-expanded-bg:#f7f7f8;--card-shadow:none;--card-shadow-hover:0 2px 6px #00000014;--card-inset:none;--card-border:#d5d7de;--card-done-bg:#fafafa;--card-done-border:#e8e8ec;--done-pill-exited-bg:#f2f2f2;--done-pill-exited-color:#8b8b93;--done-pill-merged-bg:#1a7f3714;--done-pill-merged-color:#1a7f37;--done-pill-killed-bg:#cf222e0f;--done-pill-killed-color:#cf222e;--done-meta-chip-bg:#f2f2f2;--done-meta-chip-border:#e8e8ec;--done-section-border:#ececf0;--done-title-color:#5e5e66;--done-restore-bg:#0969da0f;--done-restore-border:#0969da33;--done-restore-hover-bg:#0969da1f;--detail-card-bg:#fff;--detail-card-shadow:0 1px 3px #00000014,0 1px 2px #0000000a;--btn-shadow:0 1px 2px #0000000f;--btn-shadow-hover:0 2px 4px #0000001a;--btn-inset:none;--color-column-bg:#f4f5f7;--color-column-header:transparent;--color-alert-ci:#6366f1;--color-alert-ci-bg:#4f46e5;--color-alert-ci-unknown:#9a6700;--color-alert-review:#1a7f37;--color-alert-review-bg:#1a7f37;--color-alert-changes:#5b7ef8;--color-alert-changes-bg:#5b7ef8;--color-alert-conflict:#9a6700;--color-alert-conflict-bg:#92400e;--color-alert-comment:#bc4c00;--color-alert-comment-bg:#c2410c}.dark{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;--color-bg-base:#0a0d12;--color-bg-surface:#11161d;--color-bg-elevated:#171d26;--color-bg-elevated-hover:#1c2430;--color-bg-subtle:#b1ceff0d;--color-border-subtle:#a0beff14;--color-border-default:#a0beff24;--color-border-strong:#b9d6ff3d;--color-text-primary:#eef3ff;--color-text-secondary:#a5afc4;--color-text-tertiary:#6f7c94;--color-text-muted:#6f7c94;--color-text-inverse:#0a0d12;--color-accent:#5b7ef8;--color-accent-hover:#7a96ff;--color-accent-subtle:#5b7ef81f;--color-status-working:#22c55e;--color-status-ready:#5b7ef8;--color-status-respond:#f1be64;--color-status-review:#06b6d4;--color-status-attention:#f1be64;--color-status-idle:#293142;--color-status-done:#3a4252;--color-status-error:#ef4444;--color-accent-blue:#5b7ef8;--color-accent-green:#22c55e;--color-accent-yellow:#f1be64;--color-accent-orange:#ff9d57;--color-accent-red:#ef4444;--color-accent-violet:#5b7ef8;--color-accent-purple:#5b7ef8;--color-tint-blue:#5b7ef81f;--color-tint-green:#22c55e1f;--color-tint-yellow:#f1be641f;--color-tint-red:#ef44441f;--color-tint-violet:#5b7ef81f;--color-tint-orange:#ff9d571f;--color-tint-neutral:#ffffff0d;--color-chip-bg:#ffffff0f;--color-hover-overlay:#8fb4ff0d;--color-scrollbar:#ffffff14;--color-scrollbar-hover:#ffffff26;--color-scrollbar-active:#ffffff40;--color-body-gradient-blue:#6e8fff33;--color-body-gradient-violet:#5b7ef814;--color-nav-bg:#0a0d12d1;--card-bg:linear-gradient(180deg,#161c25fa,#10151dfa);--card-merge-bg:#11171ffa;--card-expanded-bg:linear-gradient(180deg,#1a222dfa,#121821fa);--card-shadow:0 18px 36px #02060c3d;--card-shadow-hover:0 24px 54px #02060c57;--card-inset:inset 0 1px 0 #ffffff0a;--card-border:#a6bee22e;--card-done-bg:linear-gradient(180deg,#121821b8,#0e131bb8);--card-done-border:#a0beff1a;--done-pill-exited-bg:#8fb4ff14;--done-pill-exited-color:#8a9ab6;--done-pill-merged-bg:#5fd39a24;--done-pill-merged-color:#5fd39a;--done-pill-killed-bg:#ff7b721f;--done-pill-killed-color:#ff7b72;--done-meta-chip-bg:#8fb4ff0d;--done-meta-chip-border:#a0beff1a;--done-section-border:#a0beff14;--done-title-color:#9ba8bf;--done-restore-bg:#8fb4ff1a;--done-restore-border:#8fb4ff3d;--done-restore-hover-bg:#8fb4ff2e;--detail-card-bg:linear-gradient(180deg,#141a23fa,#0e131bfa);--detail-card-shadow:0 18px 42px #00000047;--btn-shadow:0 10px 24px #223f7429;--btn-shadow-hover:0 16px 34px #223f7438;--btn-inset:inset 0 1px 0 #ffffff14;--color-column-bg:#0d1218;--color-column-header:transparent;--color-alert-ci:#7b85e0;--color-alert-ci-bg:#5e6ad240;--color-alert-ci-unknown:#d4a72c;--color-alert-review:#4dab6e;--color-alert-review-bg:#4dab6e40;--color-alert-changes:#5b7ef8;--color-alert-changes-bg:#5b7ef840;--color-alert-conflict:#d4a72c;--color-alert-conflict-bg:#d4a72c40;--color-alert-comment:#c88a2e;--color-alert-comment-bg:#c88a2e40}:root{--space-1:4px;--space-2:8px;--space-3:12px;--space-4:16px;--space-5:20px;--space-6:24px;--space-8:32px;--space-10:40px;--space-12:48px;--space-16:64px;--z-base:0;--z-raised:10;--z-nav:100;--z-modal:200;--z-bottom-nav:250;--z-overlay:300;--z-toast:400;--z-connection-bar:500;--font-size-xs:10px;--font-size-sm:11px;--font-size-base:13px;--font-size-lg:15px;--font-size-xl:17px;--box-shadow-sm:0 1px 2px #0009;--box-shadow-md:0 1px 3px #0009,inset 0 1px 0 #ffffff0d;--box-shadow-lg:0 1px 2px #000000e6,0 3px 10px #0000008c,inset 0 1px 0 #ffffff12;--box-shadow-xl:0 4px 8px #000000d9,0 14px 36px #0000008c,inset 0 1px 0 #ffffff1a;--gradient-session-card:linear-gradient(175deg,#1e1e23,#17171b);--gradient-session-card-expanded:linear-gradient(175deg,#26262c,#1e1e23);--gradient-session-card-merge:linear-gradient(175deg,#171d19,#111613);--gradient-detail-card:linear-gradient(175deg,#1e1e23,#17171b);--gradient-orchestrator-btn:linear-gradient(175deg,#5e6ad21f,#5e6ad20f);--gradient-orchestrator-btn-hover:linear-gradient(175deg,#5e6ad22e,#5e6ad21a);--gradient-status-strip:linear-gradient(180deg,#5e6ad20a 0%,transparent)}html{-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%}body{font-family:var(--font-sans);color:var(--color-text-primary);letter-spacing:-.011em;min-height:100dvh}body,html:not(.dark) body{background:var(--color-bg-base)}.dark body{background:radial-gradient(ellipse 70% 40% at 15% 0,var(--color-body-gradient-blue)0,transparent 60%),radial-gradient(ellipse 50% 30% at 85% 90%,var(--color-body-gradient-violet)0,transparent 60%),linear-gradient(180deg,#ffffff04 0,transparent 28%),var(--color-bg-base)}a{color:var(--color-accent);text-decoration:none}a:hover{text-decoration:underline}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:var(--color-scrollbar);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--color-scrollbar-hover)}::-webkit-scrollbar-thumb:active{background:var(--color-scrollbar-active)}.xterm .xterm-viewport{overflow-y:overlay!important}.xterm .xterm-viewport::-webkit-scrollbar{width:5px}.xterm .xterm-viewport::-webkit-scrollbar-track{background:0 0}.xterm .xterm-viewport::-webkit-scrollbar-thumb{background:#fff0;border-radius:2.5px;transition:background .3s}.xterm .xterm-viewport:active::-webkit-scrollbar-thumb,.xterm .xterm-viewport:hover::-webkit-scrollbar-thumb{background:#ffffff1f}.xterm .xterm-viewport:hover::-webkit-scrollbar-thumb:hover{background:#ffffff38}.xterm .xterm-viewport:hover::-webkit-scrollbar-thumb:active{background:#ffffff59}html.light .xterm .xterm-viewport::-webkit-scrollbar-thumb{background:0 0;transition:background .3s}html.light .xterm .xterm-viewport:active::-webkit-scrollbar-thumb,html.light .xterm .xterm-viewport:hover::-webkit-scrollbar-thumb{background:#00000026}html.light .xterm .xterm-viewport:hover::-webkit-scrollbar-thumb:hover{background:#00000047}html.light .xterm .xterm-viewport:hover::-webkit-scrollbar-thumb:active{background:#0006}@keyframes progress-shimmer{0%{transform:translate(-200%)}to{transform:translate(500%)}}@keyframes activity-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.72;transform:scale(1.16)}}@keyframes spin{to{transform:rotate(1turn)}}@keyframes pulse{50%{opacity:.5}}@keyframes slide-up{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes dot-ring{0%{opacity:.5;transform:scale(.8)}to{opacity:0;transform:scale(1.3)}}@keyframes ready-dot-pulse{0%,to{opacity:.95;transform:scale(1)}50%{opacity:1;transform:scale(1.22)}}.dot-pulse{position:relative}.dot-pulse:after{content:"";border-radius:inherit;background:inherit;will-change:transform,opacity;animation:dot-ring 2s ease-in-out infinite;position:absolute;inset:-3px}.kanban-card-enter{animation:slide-up .2s cubic-bezier(.16,1,.3,1) forwards}.orchestrator-btn{color:var(--color-accent);background:linear-gradient(175deg,var(--color-accent)0,var(--color-accent)100%);border-radius:2px}@supports (color:color-mix(in lab,red,red)){.orchestrator-btn{background:linear-gradient(175deg,color-mix(in srgb,var(--color-accent)12%,transparent)0,color-mix(in srgb,var(--color-accent)6%,transparent)100%)}}.orchestrator-btn{border:1px solid var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.orchestrator-btn{border:1px solid color-mix(in srgb,var(--color-accent)25%,transparent)}}.orchestrator-btn{box-shadow:var(--btn-shadow);transition:transform .16s ease-out,box-shadow .12s,background .12s,border-color .12s}.orchestrator-btn:hover{background:linear-gradient(175deg,var(--color-accent)0,var(--color-accent)100%);transform:translateY(-1px)}@supports (color:color-mix(in lab,red,red)){.orchestrator-btn:hover{background:linear-gradient(175deg,color-mix(in srgb,var(--color-accent)18%,transparent)0,color-mix(in srgb,var(--color-accent)10%,transparent)100%)}}.orchestrator-btn:hover{border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.orchestrator-btn:hover{border-color:color-mix(in srgb,var(--color-accent)45%,transparent)}}.orchestrator-btn:hover{box-shadow:var(--btn-shadow-hover)}.orchestrator-btn:active,.orchestrator-btn:hover:active{transform:scale(.97)}.nav-glass{background:var(--color-nav-bg);-webkit-backdrop-filter:blur(12px)}.dashboard-main,.dashboard-shell{position:relative}.dashboard-main:before{content:"";pointer-events:none;background:linear-gradient(#ffffff04,#0000);height:140px;position:absolute;inset:0 0 auto}.dashboard-hero{border:1px solid var(--color-border-default);background:var(--color-bg-surface);box-shadow:var(--card-shadow);border-radius:2px;position:relative;overflow:visible}.dashboard-hero__backdrop{display:none}.dashboard-hero__content{flex-wrap:wrap;gap:14px;padding:14px 18px;position:relative}.dashboard-hero__content,.dashboard-hero__primary{justify-content:space-between;align-items:flex-start;display:flex}.dashboard-hero__primary{flex:720px;gap:18px}.dashboard-hero__heading{flex-direction:column;gap:8px;min-width:0;max-width:760px;display:flex}.dashboard-eyebrow{border:1px solid var(--color-accent);align-items:center;gap:8px;width:fit-content;padding:4px 8px;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.dashboard-eyebrow{border:1px solid color-mix(in srgb,var(--color-accent)18%,var(--color-border-default))}}.dashboard-eyebrow{background:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.dashboard-eyebrow{background:color-mix(in srgb,var(--color-accent)8%,transparent)}}.dashboard-eyebrow{color:var(--color-accent);letter-spacing:.14em;text-transform:uppercase;font-size:9px;font-weight:700}.dashboard-eyebrow__dot{background:currentColor;border-radius:999px;width:6px;height:6px}.dashboard-title{letter-spacing:-.05em;color:var(--color-text-primary);font-size:clamp(22px,2.8vw,32px);font-weight:600;line-height:1}.dashboard-subtitle{max-width:56ch;color:var(--color-text-muted);margin-top:3px;font-size:11px;line-height:1.4}.dashboard-hero__meta{flex-direction:row;flex:none;gap:10px}.dashboard-hero__meta,.dashboard-stat-cards{align-items:center;margin-left:auto;display:flex}.dashboard-stat-cards{flex-wrap:wrap;flex-shrink:0;gap:8px;max-width:none}.dashboard-stat-card{border:1px solid var(--color-border-default);flex-direction:row;align-items:baseline;gap:6px;min-width:0;min-height:0;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.dashboard-stat-card{border:1px solid color-mix(in srgb,var(--color-border-default)88%,transparent)}}.dashboard-stat-card{background:var(--color-bg-base);border-radius:0}@supports (color:color-mix(in lab,red,red)){.dashboard-stat-card{background:color-mix(in srgb,var(--color-bg-base)72%,transparent)}}.dashboard-stat-card{box-shadow:none;padding:6px 9px}.dashboard-stat-card--empty{max-width:180px}.dashboard-stat-card__value{letter-spacing:-.05em;font-variant-numeric:tabular-nums;font-size:18px;font-weight:600;line-height:1}.dashboard-stat-card__label{letter-spacing:.08em;text-transform:uppercase;color:var(--color-text-secondary);font-size:10px;font-weight:700}.dashboard-stat-card__meta{color:var(--color-text-muted);display:none}.dashboard-alert,.detail-card{box-shadow:var(--detail-card-shadow);border-radius:2px}.detail-card{background:var(--detail-card-bg)}.session-detail-page{background:radial-gradient(circle at top right,var(--color-accent),transparent 28%),var(--color-bg-base)}@supports (color:color-mix(in lab,red,red)){.session-detail-page{background:radial-gradient(circle at top right,color-mix(in srgb,var(--color-accent)6%,transparent),transparent 28%),var(--color-bg-base)}}.session-page-header{border:1px solid var(--color-border-default);background:var(--detail-card-bg);box-shadow:var(--detail-card-shadow);border-radius:2px;grid-template-columns:minmax(0,1fr);gap:10px;padding:14px 16px;display:grid}@media (min-width:900px){.session-page-header{gap:12px}}.session-page-header__crumbs{border-bottom:1px solid var(--color-border-subtle);flex-wrap:wrap;align-items:center;gap:8px;padding-bottom:10px;display:flex}.session-page-header__mode{border:1px solid var(--color-accent);padding:2px 8px}@supports (color:color-mix(in lab,red,red)){.session-page-header__mode{border:1px solid color-mix(in srgb,var(--color-accent)20%,transparent)}}.session-page-header__mode{color:var(--color-accent);background:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.session-page-header__mode{background:color-mix(in srgb,var(--color-accent)10%,transparent)}}.session-page-header__mode{letter-spacing:.05em;font-size:10px;font-weight:600}.session-page-header__main{gap:12px;display:grid}.session-page-header__identity{min-width:0}.session-page-header__meta{flex-wrap:wrap;gap:8px;margin-top:10px;display:flex}.session-page-header__side{flex-wrap:wrap;align-items:center;gap:12px;display:flex}@media (min-width:1100px){.session-page-header__main{grid-template-columns:minmax(0,1fr) auto;align-items:center}.session-page-header__side{justify-content:flex-end}}.session-detail-link-pill{border:1px solid var(--color-border-subtle);background:var(--color-bg-elevated);border-radius:2px;align-items:center;min-height:28px;padding:0 10px;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.session-detail-link-pill{background:color-mix(in srgb,var(--color-bg-elevated)88%,transparent)}}.session-detail-link-pill{color:var(--color-text-secondary);font-size:11px;font-weight:500;transition:border-color .14s,color .14s,background .14s}.session-detail-link-pill--link{color:var(--color-accent-blue);border-color:var(--color-accent-blue)}@supports (color:color-mix(in lab,red,red)){.session-detail-link-pill--link{border-color:color-mix(in srgb,var(--color-accent-blue)22%,var(--color-border-subtle))}}.session-detail-link-pill--link{background:var(--color-accent-blue)}@supports (color:color-mix(in lab,red,red)){.session-detail-link-pill--link{background:color-mix(in srgb,var(--color-accent-blue)9%,transparent)}}.session-detail-link-pill--link{text-decoration:none;box-shadow:inset 0 1px #ffffff29}.session-detail-link-pill:hover{border-color:var(--color-border-strong);color:var(--color-text-primary)}.session-detail-link-pill--link:hover{border-color:var(--color-accent-blue)}@supports (color:color-mix(in lab,red,red)){.session-detail-link-pill--link:hover{border-color:color-mix(in srgb,var(--color-accent-blue)44%,var(--color-border-strong))}}.session-detail-link-pill--link:hover{color:var(--color-accent-blue);background:var(--color-accent-blue)}@supports (color:color-mix(in lab,red,red)){.session-detail-link-pill--link:hover{background:color-mix(in srgb,var(--color-accent-blue)13%,transparent)}}.session-detail-link-pill--accent{color:var(--color-accent);border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.session-detail-link-pill--accent{border-color:color-mix(in srgb,var(--color-accent)20%,var(--color-border-subtle))}}.session-detail-link-pill--accent{background:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.session-detail-link-pill--accent{background:color-mix(in srgb,var(--color-accent)8%,transparent)}}.session-detail-link-pill--link.session-detail-link-pill--accent{color:var(--color-accent);border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.session-detail-link-pill--link.session-detail-link-pill--accent{border-color:color-mix(in srgb,var(--color-accent)28%,var(--color-border-subtle))}}.session-detail-link-pill--link.session-detail-link-pill--accent{background:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.session-detail-link-pill--link.session-detail-link-pill--accent{background:color-mix(in srgb,var(--color-accent)10%,transparent)}}.session-detail-link-pill--link.session-detail-link-pill--accent:hover{border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.session-detail-link-pill--link.session-detail-link-pill--accent:hover{border-color:color-mix(in srgb,var(--color-accent)46%,var(--color-border-strong))}}.session-detail-link-pill--link.session-detail-link-pill--accent:hover{color:var(--color-accent);background:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.session-detail-link-pill--link.session-detail-link-pill--accent:hover{background:color-mix(in srgb,var(--color-accent)14%,transparent)}}.session-detail-status-pill{transition:transform .16s ease-out,opacity .16s ease-out,background .16s ease-out,border-color .16s ease-out;position:relative;overflow:hidden;box-shadow:inset 0 1px #ffffff29}.session-detail-status-pill__dot{z-index:1;position:relative}.session-detail-status-pill--active{animation:session-status-active-breathe 2.8s ease-in-out infinite}.session-detail-status-pill--active .session-detail-status-pill__dot{animation:session-status-dot-pulse 1.8s ease-in-out infinite}.session-detail-status-pill--ready{animation:session-status-ready-breathe 3.2s ease-in-out infinite}.session-detail-status-pill--ready .session-detail-status-pill__dot{animation:session-status-dot-pulse 2.2s ease-in-out infinite}.session-detail-status-pill--idle{opacity:.92}.session-detail-status-pill--waiting{animation:session-status-waiting-breathe 3s ease-in-out infinite}@keyframes session-status-dot-pulse{0%,to{opacity:.88;transform:scale(1)}50%{opacity:1;transform:scale(1.18)}}@keyframes session-status-active-breathe{0%,to{opacity:.96;transform:translateY(0)}50%{opacity:1;transform:translateY(-1px)}}@keyframes session-status-ready-breathe{0%,to{opacity:.96;transform:translateY(0)}50%{opacity:1;transform:translateY(-1px)}}@keyframes session-status-waiting-breathe{0%,to{opacity:.95;transform:translateY(0)}50%{opacity:1;transform:translateY(-1px)}}.dark .detail-card{--color-text-secondary:#9898a0;--color-text-muted:#5c5c66;--color-text-tertiary:#5c5c66}.session-card{background:var(--card-bg);border-color:var(--card-border);contain:layout style paint;border-radius:2px;transition:transform .12s,border-color .12s,background .12s,box-shadow .12s;box-shadow:inset 0 1px #ffffff0a,0 10px 20px #00000014}.session-card--fixed{flex-direction:column;min-height:242px;display:flex;overflow:hidden}.session-card--alert-frame,.session-card--merge-frame{flex-direction:column;height:auto;display:flex;overflow:hidden}.session-card--alert-frame{min-height:292px}.session-card--merge-frame{min-height:264px}.dark .session-card{--color-text-secondary:#9898a0;--color-text-muted:#5c5c66;--color-text-tertiary:#5c5c66;box-shadow:inset 0 1px #ffffff0d,0 14px 30px #00000057}.dark .kanban-column [class*=font-semibold]{font-weight:500}.dark .kanban-column [class*=font-bold]{font-weight:600}.dark .session-card-done .done-status-pill{font-weight:500}.dark .session-card-done .done-detail-heading{font-weight:600}.session-card:hover{border-color:var(--color-border-strong);transform:translateY(-1px);box-shadow:inset 0 1px #ffffff0d,0 18px 34px #00000017}.session-card__actions,.session-card__header,.session-card__meta,.session-card__title-wrap{z-index:1;position:relative}.session-card__title-wrap:after{display:none}.session-card__title{-webkit-line-clamp:2}.session-card__secondary{-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.45;display:-webkit-box;overflow:hidden}.session-card__alert-grid{flex-wrap:wrap;gap:6px;display:flex}.session-card__alert-pill{max-width:100%}.session-card__footer{background:var(--color-bg-base);min-height:34px;margin-top:auto}@supports (color:color-mix(in lab,red,red)){.session-card__footer{background:color-mix(in srgb,var(--color-bg-base)35%,transparent)}}.session-card__control{box-sizing:border-box;white-space:nowrap;height:28px;padding-left:10px;padding-right:10px}.session-card__control-icon{flex-shrink:0;width:12px;height:12px}.session-card__terminate{border-radius:0;padding-left:8px;padding-right:8px;line-height:1}.session-card__merge-control{border-color:var(--color-status-ready)}@supports (color:color-mix(in lab,red,red)){.session-card__merge-control{border-color:color-mix(in srgb,var(--color-status-ready)68%,transparent)}}.session-card__merge-control{background:linear-gradient(180deg,var(--color-status-ready)0,var(--color-status-ready)100%)}@supports (color:color-mix(in lab,red,red)){.session-card__merge-control{background:linear-gradient(180deg,color-mix(in srgb,var(--color-status-ready)34%,transparent)0,color-mix(in srgb,var(--color-status-ready)18%,transparent)100%)}}.session-card__merge-control{color:var(--color-status-ready);letter-spacing:.01em;box-shadow:inset 0 1px 0 #ffffff42,0 8px 18px var(--color-status-ready);font-weight:600;text-decoration:none}@supports (color:color-mix(in lab,red,red)){.session-card__merge-control{box-shadow:inset 0 1px 0 #ffffff42,0 8px 18px color-mix(in srgb,var(--color-status-ready)16%,transparent)}}.session-card__merge-control:hover{border-color:var(--color-status-ready);background:linear-gradient(180deg,var(--color-status-ready)0,var(--color-status-ready)100%)}@supports (color:color-mix(in lab,red,red)){.session-card__merge-control:hover{background:linear-gradient(180deg,color-mix(in srgb,var(--color-status-ready)46%,transparent)0,color-mix(in srgb,var(--color-status-ready)24%,transparent)100%)}}.session-card__merge-control:hover{box-shadow:inset 0 1px 0 #ffffff4d,0 10px 22px var(--color-status-ready);text-decoration:none;transform:translateY(-1px)}@supports (color:color-mix(in lab,red,red)){.session-card__merge-control:hover{box-shadow:inset 0 1px 0 #ffffff4d,0 10px 22px color-mix(in srgb,var(--color-status-ready)20%,transparent)}}.session-card__merge-control .session-card__control-icon{transition:transform .14s}.session-card__merge-control:hover .session-card__control-icon{transform:translate(2px)}.session-card.card-merge-ready{background:linear-gradient(180deg,var(--color-status-ready)0,var(--color-status-ready)28%,var(--color-status-ready)100%);position:relative}@supports (color:color-mix(in lab,red,red)){.session-card.card-merge-ready{background:linear-gradient(180deg,color-mix(in srgb,var(--color-status-ready)10%,var(--card-merge-bg))0,color-mix(in srgb,var(--color-status-ready)6%,var(--card-merge-bg))28%,color-mix(in srgb,var(--color-status-ready)3%,var(--card-merge-bg))100%)}}.session-card.card-merge-ready{border-color:var(--color-status-ready)}@supports (color:color-mix(in lab,red,red)){.session-card.card-merge-ready{border-color:color-mix(in srgb,var(--color-status-ready)30%,var(--color-border-default))}}.session-card.card-merge-ready{box-shadow:inset 0 1px 0 #ffffff0a,0 22px 40px var(--color-status-ready)}@supports (color:color-mix(in lab,red,red)){.session-card.card-merge-ready{box-shadow:inset 0 1px 0 #ffffff0a,0 22px 40px color-mix(in srgb,var(--color-status-ready)18%,transparent)}}.session-card.card-merge-ready:before{display:none}.session-card.card-merge-ready:after{content:"";pointer-events:none;z-index:0;background:radial-gradient(ellipse at 50% 100%,var(--color-status-ready)0,var(--color-status-ready)42%,transparent 72%),radial-gradient(ellipse at 50% 0,var(--color-status-ready)0,transparent 58%);position:absolute;inset:-14px -10px -18px}@supports (color:color-mix(in lab,red,red)){.session-card.card-merge-ready:after{background:radial-gradient(ellipse at 50% 100%,color-mix(in srgb,var(--color-status-ready)18%,transparent)0,color-mix(in srgb,var(--color-status-ready)8%,transparent)42%,transparent 72%),radial-gradient(ellipse at 50% 0,color-mix(in srgb,var(--color-status-ready)10%,transparent)0,transparent 58%)}}.session-card.card-merge-ready:after{filter:blur(10px);opacity:.9}.session-card.card-merge-ready>*{z-index:1;position:relative}.dark .session-card.card-merge-ready:after{background:radial-gradient(ellipse at 50% 100%,var(--color-status-ready)0,var(--color-status-ready)44%,transparent 72%),radial-gradient(ellipse at 50% 0,var(--color-status-ready)0,transparent 58%)}@supports (color:color-mix(in lab,red,red)){.dark .session-card.card-merge-ready:after{background:radial-gradient(ellipse at 50% 100%,color-mix(in srgb,var(--color-status-ready)24%,transparent)0,color-mix(in srgb,var(--color-status-ready)10%,transparent)44%,transparent 72%),radial-gradient(ellipse at 50% 0,color-mix(in srgb,var(--color-status-ready)12%,transparent)0,transparent 58%)}}.dark .session-card.card-merge-ready:after{opacity:.75}.session-card.card-merge-ready:hover:after{opacity:1;filter:blur(12px);background:radial-gradient(ellipse at 50% 100%,var(--color-status-ready)0,var(--color-status-ready)44%,transparent 74%),radial-gradient(ellipse at 50% 0,var(--color-status-ready)0,transparent 58%)}@supports (color:color-mix(in lab,red,red)){.session-card.card-merge-ready:hover:after{background:radial-gradient(ellipse at 50% 100%,color-mix(in srgb,var(--color-status-ready)24%,transparent)0,color-mix(in srgb,var(--color-status-ready)10%,transparent)44%,transparent 74%),radial-gradient(ellipse at 50% 0,color-mix(in srgb,var(--color-status-ready)12%,transparent)0,transparent 58%)}}.dark .session-card.card-merge-ready:hover:after{background:radial-gradient(ellipse at 50% 100%,var(--color-status-ready)0,var(--color-status-ready)44%,transparent 74%),radial-gradient(ellipse at 50% 0,var(--color-status-ready)0,transparent 58%)}@supports (color:color-mix(in lab,red,red)){.dark .session-card.card-merge-ready:hover:after{background:radial-gradient(ellipse at 50% 100%,color-mix(in srgb,var(--color-status-ready)28%,transparent)0,color-mix(in srgb,var(--color-status-ready)12%,transparent)44%,transparent 74%),radial-gradient(ellipse at 50% 0,color-mix(in srgb,var(--color-status-ready)14%,transparent)0,transparent 58%)}}.session-card.card-merge-ready:after{transition:opacity .18s,filter .18s,background .18s}.session-card.card-merge-ready:hover{border-color:var(--color-status-ready);transform:translateY(-2px)}@supports (color:color-mix(in lab,red,red)){.session-card.card-merge-ready:hover{border-color:color-mix(in srgb,var(--color-status-ready)42%,var(--color-border-strong))}}.session-card.card-merge-ready:hover{box-shadow:inset 0 1px 0 #ffffff0f,0 28px 52px var(--color-status-ready)}@supports (color:color-mix(in lab,red,red)){.session-card.card-merge-ready:hover{box-shadow:inset 0 1px 0 #ffffff0f,0 28px 52px color-mix(in srgb,var(--color-status-ready)22%,transparent)}}.session-card.card-merge-ready .session-card__header>span:first-child>span:first-child{animation:ready-dot-pulse 2.8s ease-in-out infinite}.quick-reply{border-top:1px solid var(--color-border-default);flex-direction:column;gap:8px;padding:10px 12px;display:flex}.quick-reply__summary{-webkit-line-clamp:2;color:var(--color-text-secondary);-webkit-box-orient:vertical;margin:0;font-size:12px;line-height:1.5;display:-webkit-box;overflow:hidden}.quick-reply__presets{gap:6px;display:flex}.quick-reply__preset-btn{border:1px solid var(--color-border-default);background:var(--color-bg-subtle);min-height:44px;color:var(--color-text-secondary);font-family:var(--font-sans);cursor:pointer;padding:0 14px;font-size:12px;transition:border-color .12s,color .12s,background .12s}.quick-reply__preset-btn:hover{border-color:var(--color-accent);color:var(--color-accent);background:var(--color-tint-blue)}.quick-reply__input{border:1px solid var(--color-border-default);background:var(--color-bg-subtle);height:44px;min-height:44px;color:var(--color-text-primary);font-family:var(--font-sans);resize:none;box-sizing:border-box;width:100%;padding:12px;font-size:13px;transition:height .15s,border-color .12s;overflow:hidden}.quick-reply__input::placeholder{color:var(--color-text-muted)}.quick-reply__input:focus{border-color:var(--color-accent);outline:none;height:80px;overflow:auto}@media (min-width:768px){.quick-reply__preset-btn{min-height:32px;padding:0 10px;font-size:11px}.quick-reply__input{height:32px;min-height:32px;padding:8px 10px}.quick-reply__input:focus{height:60px}}.session-card-done{background:var(--card-done-bg);border:1px solid var(--card-done-border);cursor:pointer;border-radius:0;transition:border-color .15s,background .15s,box-shadow .15s;overflow:hidden}.session-card-done:hover{border-color:var(--color-border-strong);box-shadow:0 1px 4px #0000000f}.dark .session-card-done:hover{box-shadow:none}.session-card-done.done-expanded{border-color:var(--color-border-strong)}.done-status-pill{letter-spacing:.02em;border-radius:0;align-items:center;gap:4px;padding:2px 8px;font-size:10px;font-weight:600;line-height:1.4;display:inline-flex}.done-status-pill--exited{background:var(--done-pill-exited-bg);color:var(--done-pill-exited-color)}.done-status-pill--merged{background:var(--done-pill-merged-bg);color:var(--done-pill-merged-color)}.done-status-pill--killed{background:var(--done-pill-killed-bg);color:var(--done-pill-killed-color)}.done-meta-chip{background:var(--done-meta-chip-bg);border:1px solid var(--done-meta-chip-border);color:var(--color-text-muted);border-radius:0;gap:3px;padding:2px 7px;font-size:10px}.done-meta-chip,.done-restore-btn{align-items:center;font-weight:500;display:inline-flex}.done-restore-btn{border:1px solid var(--done-restore-border);background:var(--done-restore-bg);color:var(--color-accent);cursor:pointer;border-radius:0;gap:4px;padding:2px 8px;font-size:11px;transition:background .12s,border-color .12s}.done-restore-btn:hover{background:var(--done-restore-hover-bg);border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.done-restore-btn:hover{border-color:color-mix(in srgb,var(--color-accent)40%,transparent)}}.done-expand-section{border-top:1px solid var(--done-section-border);animation:done-slide-in .15s ease-out}@keyframes done-slide-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.done-detail-heading{text-transform:uppercase;letter-spacing:.06em;color:var(--color-text-tertiary);align-items:center;gap:5px;margin-bottom:6px;font-size:10px;font-weight:700;display:flex}.done-detail-heading svg{opacity:.6;width:11px;height:11px}.project-sidebar nav::-webkit-scrollbar{width:4px}.project-sidebar nav::-webkit-scrollbar-track{background:0 0}.project-sidebar nav::-webkit-scrollbar-thumb{background:var(--color-scrollbar);border-radius:2px}.project-sidebar{border-right:1px solid var(--color-border-subtle);background:linear-gradient(180deg,var(--color-bg-elevated)0,var(--color-bg-base)100%)}@supports (color:color-mix(in lab,red,red)){.project-sidebar{background:linear-gradient(180deg,color-mix(in srgb,var(--color-bg-elevated)92%,black 8%)0,color-mix(in srgb,var(--color-bg-base)90%,black 10%)100%)}}.project-sidebar--collapsed{align-items:center}.project-sidebar__header{border-bottom:1px solid var(--color-border-subtle);background:linear-gradient(180deg,var(--color-accent)0,transparent 100%)}@supports (color:color-mix(in lab,red,red)){.project-sidebar__header{background:linear-gradient(180deg,color-mix(in srgb,var(--color-accent)4%,transparent)0,transparent 100%)}}.project-sidebar__eyebrow{letter-spacing:.16em;text-transform:uppercase;color:var(--color-accent);font-size:10px}.project-sidebar__title-row{justify-content:space-between;align-items:flex-start;gap:12px;margin-top:6px;display:flex}.project-sidebar__title{letter-spacing:-.02em;color:var(--color-text-primary);font-size:13px;font-weight:600;line-height:1.1}.project-sidebar__subtitle{max-width:18ch;color:var(--color-text-muted);margin-top:3px;font-size:10px;line-height:1.4}.project-sidebar__badge{border:1px solid var(--color-border-default);background:var(--color-bg-base);justify-content:center;align-items:center;min-width:22px;height:22px;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.project-sidebar__badge{background:color-mix(in srgb,var(--color-bg-base)42%,transparent)}}.project-sidebar__badge{color:var(--color-text-primary);font-variant-numeric:tabular-nums;font-size:10px;font-weight:600}.project-sidebar__summary{grid-template-columns:repeat(3,minmax(0,1fr));gap:6px;margin-top:10px;display:grid}.project-sidebar__metric{border:1px solid var(--color-border-subtle);background:var(--color-bg-base);flex-direction:column;gap:2px;padding:6px 6px 5px;display:flex}@supports (color:color-mix(in lab,red,red)){.project-sidebar__metric{background:color-mix(in srgb,var(--color-bg-base)40%,transparent)}}.project-sidebar__metric-value{letter-spacing:-.03em;color:var(--color-text-primary);font-variant-numeric:tabular-nums;font-size:13px;font-weight:600;line-height:1}.project-sidebar__metric-label{letter-spacing:.1em;text-transform:uppercase;color:var(--color-text-muted);font-size:9px}.project-sidebar__divider{border-top:1px solid var(--color-border-subtle)}.project-sidebar__item{background:0 0;border:1px solid #0000;position:relative}.project-sidebar__item:hover{background:var(--color-hover-overlay);border-color:var(--color-border-subtle)}.project-sidebar__item--active{border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.project-sidebar__item--active{border-color:color-mix(in srgb,var(--color-accent)24%,var(--color-border-default))}}.project-sidebar__item--active{background:linear-gradient(90deg,var(--color-accent),transparent 90%)}@supports (color:color-mix(in lab,red,red)){.project-sidebar__item--active{background:linear-gradient(90deg,color-mix(in srgb,var(--color-accent)16%,transparent),transparent 90%)}}.project-sidebar__count{border:1px solid var(--color-border-subtle);background:var(--color-bg-base)}@supports (color:color-mix(in lab,red,red)){.project-sidebar__count{background:color-mix(in srgb,var(--color-bg-base)40%,transparent)}}.project-sidebar__children{border-left:1px solid var(--color-border-subtle);margin-top:4px;position:relative}@supports (color:color-mix(in lab,red,red)){.project-sidebar__children{border-left:1px solid color-mix(in srgb,var(--color-border-subtle)82%,transparent)}}.project-sidebar__session{background:0 0;border:1px solid #0000;margin:2px 0 2px 8px;position:relative}.project-sidebar__session:hover{border-color:var(--color-border-subtle);background:linear-gradient(90deg,var(--color-hover-overlay),transparent 100%)}@supports (color:color-mix(in lab,red,red)){.project-sidebar__session:hover{background:linear-gradient(90deg,color-mix(in srgb,var(--color-hover-overlay)90%,transparent),transparent 100%)}}.project-sidebar__session--active{border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.project-sidebar__session--active{border-color:color-mix(in srgb,var(--color-accent)18%,var(--color-border-subtle))}}.project-sidebar__session--active{background:linear-gradient(90deg,var(--color-accent),transparent 88%)}@supports (color:color-mix(in lab,red,red)){.project-sidebar__session--active{background:linear-gradient(90deg,color-mix(in srgb,var(--color-accent)12%,transparent),transparent 88%)}}.project-sidebar__session--active{box-shadow:inset 2px 0 0 var(--color-accent)}.project-sidebar__session:before{content:"";background:var(--color-border-subtle);width:8px;height:1px;position:absolute;top:50%;left:-9px;transform:translateY(-50%)}.project-sidebar__session-tone{border:1px solid var(--color-border-subtle);background:var(--color-bg-base);flex-shrink:0;padding:2px 6px}@supports (color:color-mix(in lab,red,red)){.project-sidebar__session-tone{background:color-mix(in srgb,var(--color-bg-base)40%,transparent)}}.project-sidebar__session-tone{letter-spacing:.1em;text-transform:uppercase;color:var(--color-text-muted);font-size:9px;font-weight:700}.project-sidebar__session-id{opacity:0;color:var(--color-text-tertiary);transition:opacity .15s,color .15s}.project-sidebar__session--active .project-sidebar__session-id,.project-sidebar__session:hover .project-sidebar__session-id{opacity:.75}.project-sidebar__session--active .project-sidebar__session-tone{border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.project-sidebar__session--active .project-sidebar__session-tone{border-color:color-mix(in srgb,var(--color-accent)24%,var(--color-border-subtle))}}.project-sidebar__session--active .project-sidebar__session-tone{background:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.project-sidebar__session--active .project-sidebar__session-tone{background:color-mix(in srgb,var(--color-accent)10%,transparent)}}.project-sidebar__session--active .project-sidebar__session-tone{color:var(--color-accent)}.project-sidebar__collapse-btn,.project-sidebar__collapsed-toggle{border:1px solid var(--color-border-subtle);background:var(--color-bg-base);justify-content:center;align-items:center;gap:8px;width:100%;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.project-sidebar__collapse-btn,.project-sidebar__collapsed-toggle{background:color-mix(in srgb,var(--color-bg-base)40%,transparent)}}.project-sidebar__collapse-btn,.project-sidebar__collapsed-toggle{color:var(--color-text-secondary);font-size:11px;font-weight:600;transition:border-color .12s,background .12s,color .12s}.project-sidebar__collapse-btn{padding:9px 10px}.project-sidebar__collapsed-toggle{width:36px;height:36px}.project-sidebar__collapse-btn:hover,.project-sidebar__collapsed-toggle:hover{border-color:var(--color-border-default);background:var(--color-hover-overlay);color:var(--color-text-primary)}.project-sidebar__collapsed-project{border:1px solid var(--color-border-subtle);background:var(--color-bg-surface);cursor:pointer;border-radius:8px;justify-content:center;align-items:center;width:36px;height:36px;transition:border-color .15s,background .15s,box-shadow .15s;display:inline-flex;position:relative}.project-sidebar__collapsed-project:hover{border-color:var(--color-border-default);background:var(--color-bg-elevated);box-shadow:0 2px 8px #0000000f}.project-sidebar__collapsed-project--active{border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.project-sidebar__collapsed-project--active{border-color:color-mix(in srgb,var(--color-accent)35%,var(--color-border-default))}}.project-sidebar__collapsed-project--active{background:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.project-sidebar__collapsed-project--active{background:color-mix(in srgb,var(--color-accent)8%,var(--color-bg-elevated))}}.project-sidebar__collapsed-project--active{box-shadow:0 0 0 1px var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.project-sidebar__collapsed-project--active{box-shadow:0 0 0 1px color-mix(in srgb,var(--color-accent)12%,transparent)}}.project-sidebar__avatar{color:var(--color-text-secondary);-webkit-user-select:none;user-select:none;font-size:13px;font-weight:600;line-height:1}.project-sidebar__collapsed-project--active .project-sidebar__avatar{color:var(--color-accent)}.project-sidebar__health-indicator{border:1.5px solid var(--color-bg-surface);box-sizing:content-box;border-radius:50%;width:7px;height:7px;position:absolute;top:-2px;right:-2px}.kanban-board{gap:8px;height:calc(100dvh - 280px);padding-bottom:8px;display:flex;overflow-x:auto}.kanban-board-wrap{margin-top:12px;position:relative}.board-section-head{flex-wrap:wrap;justify-content:space-between;align-items:flex-end;gap:14px;margin-bottom:16px;display:flex}.board-section-head__title{letter-spacing:.16em;text-transform:uppercase;color:var(--color-text-secondary);font-size:12px;font-weight:700}.board-section-head__subtitle{color:var(--color-text-muted);margin-top:5px;font-size:12px}.board-section-head__legend{flex-wrap:wrap;gap:8px;display:flex}.board-legend-item{border:1px solid var(--color-border-subtle);background:var(--color-bg-elevated);border-radius:0;align-items:center;gap:8px;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.board-legend-item{background:color-mix(in srgb,var(--color-bg-elevated)88%,transparent)}}.board-legend-item{color:var(--color-text-secondary);padding:6px 10px;font-size:11px}.board-legend-item__dot{border-radius:999px;width:7px;height:7px}.kanban-column{border:1px solid var(--color-border-default);background:var(--color-column-bg);border-radius:0;flex-direction:column;flex:1 0 260px;min-width:260px;max-width:420px;padding:4px;display:flex;box-shadow:inset 0 1px #ffffff05,0 16px 34px #0000000d}.kanban-column[data-level=merge]{background:linear-gradient(180deg,var(--color-status-ready)0,var(--color-column-bg)100%)}@supports (color:color-mix(in lab,red,red)){.kanban-column[data-level=merge]{background:linear-gradient(180deg,color-mix(in srgb,var(--color-status-ready)4%,var(--color-column-bg))0,var(--color-column-bg)100%)}}.dark .kanban-column{border-color:#aac3e624;box-shadow:inset 0 1px #ffffff05,0 18px 42px #0000003d}.dark .kanban-column[data-level=merge]{background:linear-gradient(180deg,var(--color-status-ready)0,var(--color-column-bg)100%)}@supports (color:color-mix(in lab,red,red)){.dark .kanban-column[data-level=merge]{background:linear-gradient(180deg,color-mix(in srgb,var(--color-status-ready)7%,var(--color-column-bg))0,var(--color-column-bg)100%)}}.kanban-column__header{margin-bottom:14px;padding:2px 2px 0}.kanban-column__title-row{align-items:center;gap:10px;display:flex}.kanban-column__dot{border-radius:999px;width:8px;height:8px}.kanban-column__title{letter-spacing:normal;text-transform:none;color:var(--color-text-primary);font-size:20px;font-weight:600}.kanban-column__count{border:1px solid var(--color-border-subtle);background:var(--color-bg-base);border-radius:0;min-width:28px;margin-left:auto;padding:4px 8px}@supports (color:color-mix(in lab,red,red)){.kanban-column__count{background:color-mix(in srgb,var(--color-bg-base)72%,transparent)}}.kanban-column__count{color:var(--color-text-secondary);font-variant-numeric:tabular-nums;text-align:center;font-size:11px;font-weight:700;line-height:1}.kanban-column__caption{color:var(--color-text-muted);margin-top:7px;font-size:12px;line-height:1.5;display:block}.kanban-column-body{flex:1;padding:2px;overflow-y:auto}.kanban-column-body::-webkit-scrollbar{width:4px}.kanban-column-body::-webkit-scrollbar-track{background:0 0}.kanban-column-body::-webkit-scrollbar-thumb{background:var(--color-scrollbar);border-radius:2px}.done-bar__toggle{cursor:pointer;letter-spacing:.16em;text-transform:uppercase;width:100%;color:var(--color-text-muted);background:0 0;border:none;align-items:center;gap:8px;padding:8px 0;font-size:12px;font-weight:700;transition:color .15s;display:flex}.done-bar__toggle:hover{color:var(--color-text-secondary)}.done-bar__chevron{flex-shrink:0;width:14px;height:14px;transition:transform .15s}.done-bar__chevron--open{transform:rotate(90deg)}.done-bar__count{min-width:18px;height:18px;color:var(--color-text-muted);border-radius:999px;flex-shrink:0;justify-content:center;align-items:center;padding:0 5px;font-size:10px;font-weight:700;display:inline-flex}.done-bar__count,.done-bar__rule{background:var(--color-border-subtle)}.done-bar__rule{flex:1;height:1px}.done-bar__cards{grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:8px;margin-top:10px;display:grid}.kanban-column__empty{border:1px dashed var(--color-border-default);justify-content:center;align-items:center;min-height:132px;display:flex}@supports (color:color-mix(in lab,red,red)){.kanban-column__empty{border:1px dashed color-mix(in srgb,var(--color-border-default)82%,transparent)}}.kanban-column__empty{background:linear-gradient(180deg,var(--color-bg-base)0,transparent 100%);border-radius:0}@supports (color:color-mix(in lab,red,red)){.kanban-column__empty{background:linear-gradient(180deg,color-mix(in srgb,var(--color-bg-base)28%,transparent)0,transparent 100%)}}.kanban-column__empty-label{letter-spacing:.08em;text-transform:none;color:var(--color-text-tertiary);font-size:12px}@media (max-width:960px){.dashboard-hero__content{padding:12px 14px}.dashboard-hero__primary{flex-direction:column;gap:10px;width:100%}.dashboard-hero__meta{justify-content:space-between;align-items:flex-start;width:100%}.dashboard-stat-cards{width:100%}.kanban-board{height:auto;min-height:calc(100vh - 280px)}.session-card--fixed{min-height:232px}.session-card--alert-frame{min-height:280px}.session-card--merge-frame{min-height:252px}}@media (max-width:640px){.dashboard-title{font-size:26px}.dashboard-stat-cards{gap:6px}.kanban-column{min-width:min(86vw,320px)}.session-card--fixed{min-height:224px}.session-card--alert-frame{min-height:268px}.session-card--merge-frame{min-height:244px}}.mobile-menu-toggle{border:1px solid var(--color-border-default);background:var(--color-bg-surface);width:44px;height:44px;color:var(--color-text-secondary);cursor:pointer;flex-shrink:0;justify-content:center;align-items:center;transition:border-color .12s,background .12s,color .12s;display:none}.mobile-menu-toggle:hover{border-color:var(--color-border-strong);background:var(--color-hover-overlay);color:var(--color-text-primary)}.mobile-bottom-nav{display:none}@media (max-width:767px){.dashboard-prs-link{display:none}.mobile-menu-toggle{display:inline-flex}.project-sidebar,.project-sidebar.project-sidebar--collapsed{z-index:var(--z-overlay);width:280px;height:100dvh;padding-top:env(safe-area-inset-top,0);padding-bottom:env(safe-area-inset-bottom,0);padding-left:env(safe-area-inset-left,0);transition:transform .25s;position:fixed;top:0;left:0;transform:translate(-100%)}.project-sidebar.project-sidebar--mobile-open{transform:translate(0)}.sidebar-mobile-backdrop{z-index:calc(var(--z-overlay) - 1);-webkit-backdrop-filter:blur(2px);background:#00000080;position:fixed;inset:0}.dashboard-main{padding:12px max(12px,env(safe-area-inset-right,0px)) calc(84px + env(safe-area-inset-bottom,0px)) max(12px,env(safe-area-inset-left,0px))}.dashboard-hero{box-shadow:none;background:0 0;border:none;margin-bottom:8px}.dashboard-hero__content{grid-template-columns:36px minmax(0,1fr) 36px;align-items:center;gap:8px;min-height:0;padding:0;display:grid}.dashboard-hero__primary{min-height:0;display:block}.dashboard-hero__copy,.dashboard-hero__heading{min-width:0}.dashboard-title{letter-spacing:-.04em;max-width:none;margin:0;font-size:19px;line-height:1}.dashboard-stat-cards,.dashboard-subtitle{display:none}.dashboard-stat-cards--persist-mobile{display:flex}.dashboard-hero__meta{justify-content:flex-end;align-items:center;display:flex}.dashboard-hero__meta>div{gap:0}.dashboard-hero__meta button{box-shadow:none;padding:0}.dashboard-hero__meta button,.mobile-menu-toggle{width:36px;height:36px;color:var(--color-text-secondary);background:0 0;border:none}.mobile-menu-toggle:hover{color:var(--color-text-primary);background:0 0;border:none}.mobile-bottom-nav{z-index:var(--z-bottom-nav);border-top:1px solid var(--color-border-default);background:var(--color-bg-surface);grid-auto-columns:1fr;grid-auto-flow:column;gap:0;display:grid;position:fixed;bottom:0;left:0;right:0}@supports (color:color-mix(in lab,red,red)){.mobile-bottom-nav{background:color-mix(in srgb,var(--color-bg-surface)92%,transparent)}}.mobile-bottom-nav{-webkit-backdrop-filter:blur(14px);padding:8px max(12px,env(safe-area-inset-right,0px))calc(8px + env(safe-area-inset-bottom,0px))max(12px,env(safe-area-inset-left,0px))}.mobile-bottom-nav__item{min-height:44px;color:var(--color-text-secondary);cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;gap:6px;font-size:11px;font-weight:600;text-decoration:none;display:inline-flex}.mobile-bottom-nav__item svg{flex-shrink:0;width:16px;height:16px}.mobile-bottom-nav__item[data-active=true]{color:var(--color-text-primary)}.mobile-bottom-nav__item[aria-current=page]{color:var(--color-accent)}.mobile-bottom-nav__item:disabled{color:var(--color-text-tertiary);cursor:default}.mobile-action-strip{-webkit-overflow-scrolling:touch;scrollbar-width:none;flex-wrap:nowrap;align-items:center;gap:8px;min-width:0;padding-top:2px;display:flex;overflow-x:auto}.mobile-priority-row{grid-template-columns:minmax(0,1fr);gap:6px;min-width:0;margin-bottom:14px;display:grid}.mobile-priority-row__label{letter-spacing:.1em;text-transform:uppercase;color:var(--color-text-tertiary);font-size:10px;font-weight:600}.mobile-filter-row{-webkit-overflow-scrolling:touch;scrollbar-width:none;align-items:center;gap:8px;margin-bottom:16px;padding-bottom:2px;display:flex;overflow-x:auto}.mobile-filter-row::-webkit-scrollbar{display:none}.mobile-filter-chip{border:1px solid var(--color-border-default);background:var(--color-bg-surface);justify-content:center;align-items:center;min-height:32px;padding:0 12px;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.mobile-filter-chip{background:color-mix(in srgb,var(--color-bg-surface)88%,transparent)}}.mobile-filter-chip{color:var(--color-text-secondary);white-space:nowrap;cursor:pointer;font-size:11px;font-weight:600;transition:border-color .12s,background .12s,color .12s}.mobile-filter-chip[data-active=true]{border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.mobile-filter-chip[data-active=true]{border-color:color-mix(in srgb,var(--color-accent)28%,var(--color-border-default))}}.mobile-filter-chip[data-active=true]{background:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.mobile-filter-chip[data-active=true]{background:color-mix(in srgb,var(--color-accent)10%,transparent)}}.mobile-filter-chip[data-active=true]{color:var(--color-accent)}.mobile-action-strip::-webkit-scrollbar{display:none}.mobile-action-strip--all-good{align-items:center}.mobile-action-strip__all-good{color:var(--color-text-tertiary);white-space:nowrap;font-size:11px}.mobile-action-pill{border:1px solid var(--color-border-default);background:var(--color-bg-surface);align-items:center;gap:6px;padding:0 12px;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.mobile-action-pill{background:color-mix(in srgb,var(--color-bg-surface)86%,transparent)}}.mobile-action-pill{cursor:pointer;white-space:nowrap;min-height:36px;transition:background .12s,border-color .12s}.mobile-action-pill:active,.mobile-action-pill:hover{background:var(--color-bg-hover);border-color:var(--color-border-strong)}.mobile-action-pill:focus-visible{outline:2px solid var(--color-accent-blue);outline-offset:2px}.mobile-action-pill__dot{border-radius:999px;flex-shrink:0;width:7px;height:7px}.mobile-action-pill__count{font-variant-numeric:tabular-nums;font-size:13px;font-weight:600;line-height:1}.mobile-action-pill__label{color:var(--color-text-secondary);font-size:11px;font-weight:500}.kanban-board{flex-direction:column;gap:12px;height:auto;min-height:auto;overflow-x:visible}.kanban-column{flex:none;width:100%;min-width:0;max-width:none}.kanban-column-body{max-height:400px}.board-section-head{display:none}.board-section-head__legend{flex-wrap:wrap}.session-card--fixed{height:auto;min-height:180px}.session-card--alert-frame{min-height:220px}.session-card--merge-frame{min-height:200px}.done-restore-btn,.session-card__control,.session-card__merge-control,.session-card__terminate{min-width:44px;min-height:44px}.session-card__footer{min-height:44px}.session-card__footer a,.session-card__footer button{align-items:center;min-height:44px;display:inline-flex}.session-detail-page .mx-auto{padding-left:12px;padding-right:12px}.session-detail-page{background:var(--color-bg-base)}.session-page-header{box-shadow:none;background:0 0;border:none;gap:6px;padding:6px 0 8px}.session-page-header__main{gap:6px}.session-page-header__crumbs{border-bottom:none;gap:6px;padding-bottom:0;font-size:11px}.session-page-header__mode{letter-spacing:.08em;background:0 0;border:none;padding:0;font-size:10px}.session-page-header__meta{flex-direction:row;gap:6px;margin-top:6px}.session-page-header__side{gap:8px}.session-page-header h1{letter-spacing:-.04em;-webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:16px;line-height:1.12;display:-webkit-box;overflow:hidden}.session-page-header--mobile .session-page-header__identity{gap:0;display:grid}.session-detail-link-pill{min-height:28px;padding:0 8px;font-size:10px}.session-page-header__side .flex.items-baseline{gap:4px;margin-right:0}.session-page-header__side .text-\[22px\]{font-size:15px}.session-page-header__side .text-\[11px\]{font-size:10px}.session-page-header__side .h-5{display:none}.session-page-header__side>div:last-child{flex-wrap:wrap;gap:6px;width:100%;display:flex}.session-page-header__side>div:last-child>div{align-items:center;min-height:26px;padding:0 8px}.session-page-header__side>div:last-child>div span:first-child{font-size:12px}.session-page-header__side>div:last-child>div span:last-child{letter-spacing:.04em;text-transform:uppercase;font-size:9px}.session-detail-page section.mt-5{margin-top:6px}.board-legend-item,.orchestrator-btn{min-height:44px}.project-sidebar__item,.project-sidebar__session{align-items:center;min-height:44px;display:flex}.mx-auto.max-w-\[900px\]{-webkit-overflow-scrolling:touch;overflow-x:auto}.dashboard-alert{padding:10px 12px;font-size:11px}input,select,textarea{font-size:16px}.accordion-board{flex-direction:column;gap:0;margin-top:0;scroll-margin-top:56px;display:flex}.accordion-section{border:1px solid var(--color-border-subtle)}@supports (color:color-mix(in lab,red,red)){.accordion-section{border:1px solid color-mix(in srgb,var(--color-border-subtle)58%,transparent)}}.accordion-section{background:var(--color-bg-surface)}@supports (color:color-mix(in lab,red,red)){.accordion-section{background:color-mix(in srgb,var(--color-bg-surface)78%,var(--color-bg-base))}}.accordion-section{overflow:visible}.accordion-section+.accordion-section{border-top:none;margin-top:18px;padding-top:0}.accordion-section--expanded{border-color:var(--color-border-default)}@supports (color:color-mix(in lab,red,red)){.accordion-section--expanded{border-color:color-mix(in srgb,var(--color-border-default)82%,transparent)}}.accordion-section--expanded{background:var(--color-bg-surface)}@supports (color:color-mix(in lab,red,red)){.accordion-section--expanded{background:color-mix(in srgb,var(--color-bg-surface)88%,var(--color-bg-base))}}.mobile-session-list{border-top:1px solid var(--color-border-default);flex-direction:column;display:flex}@supports (color:color-mix(in lab,red,red)){.mobile-session-list{border-top:1px solid color-mix(in srgb,var(--color-border-default)68%,transparent)}}.mobile-session-row{background:var(--color-bg-surface);grid-template-columns:minmax(0,1fr) auto;align-items:start;gap:10px;width:100%;min-width:0;min-height:58px;padding:11px 12px;display:grid}@supports (color:color-mix(in lab,red,red)){.mobile-session-row{background:color-mix(in srgb,var(--color-bg-surface)96%,transparent)}}.mobile-session-row{border:none;border-top:1px solid var(--color-border-subtle)}@supports (color:color-mix(in lab,red,red)){.mobile-session-row{border-top:1px solid color-mix(in srgb,var(--color-border-subtle)70%,transparent)}}.mobile-session-row{text-align:left;transition:background .12s}.mobile-session-row:first-child{border-top:none}.mobile-session-row:active{background:var(--color-bg-hover)}@supports (color:color-mix(in lab,red,red)){.mobile-session-row:active{background:color-mix(in srgb,var(--color-bg-hover)82%,var(--color-bg-surface))}}.mobile-session-row__preview{text-align:left;cursor:pointer;background:0 0;border:none;flex-direction:column;flex:1;gap:5px;min-width:0;padding:0;display:flex;overflow:hidden}.mobile-session-row__line{grid-template-columns:auto minmax(0,1fr);align-items:start;gap:8px;width:100%;min-width:0;display:grid;overflow:hidden}.mobile-session-row__dot{border-radius:999px;flex-shrink:0;width:7px;height:7px;margin-top:5px}.mobile-session-row__title{min-width:0;max-width:100%;color:var(--color-text-primary);letter-spacing:-.02em;font-size:13px;font-weight:600;line-height:1.2;display:block}.mobile-session-row__chip,.mobile-session-row__title{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.mobile-session-row__chip{border:1px solid var(--color-border-default);flex-shrink:0;justify-content:flex-end;align-items:center;max-width:min(14ch,28vw);min-height:16px;padding:0 6px;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.mobile-session-row__chip{border:1px solid color-mix(in srgb,var(--color-border-default)88%,transparent)}}.mobile-session-row__chip{background:var(--color-bg-surface)}@supports (color:color-mix(in lab,red,red)){.mobile-session-row__chip{background:color-mix(in srgb,var(--color-bg-surface)92%,var(--color-bg-subtle))}}.mobile-session-row__chip{text-align:right;text-transform:uppercase;letter-spacing:.08em;color:var(--color-text-secondary);font-size:10px;font-weight:600;line-height:1}.mobile-session-row__meta{text-overflow:ellipsis;white-space:nowrap;color:var(--color-text-muted);letter-spacing:.01em;padding-left:15px;font-size:10px;line-height:1.2;overflow:hidden}.mobile-session-row__side{flex-shrink:0;grid-template-columns:max-content 44px;justify-content:end;align-self:start;align-items:start;gap:10px;display:grid}.mobile-session-row__open{width:44px;min-width:44px;height:44px;min-height:44px;color:var(--color-accent);border:1px solid var(--color-accent);flex-shrink:0;justify-content:center;align-self:start;align-items:center;padding:0;text-decoration:none;display:inline-flex}@supports (color:color-mix(in lab,red,red)){.mobile-session-row__open{border:1px solid color-mix(in srgb,var(--color-accent)26%,var(--color-border-default))}}.mobile-session-row__open{background:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.mobile-session-row__open{background:color-mix(in srgb,var(--color-accent)8%,var(--color-bg-surface))}}.mobile-session-row__open{transition:background .12s,border-color .12s,color .12s,transform .12s}.mobile-session-row__open:hover{border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.mobile-session-row__open:hover{border-color:color-mix(in srgb,var(--color-accent)44%,var(--color-border-default))}}.mobile-session-row__open:hover{background:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.mobile-session-row__open:hover{background:color-mix(in srgb,var(--color-accent)12%,var(--color-bg-surface))}}.mobile-session-row__open:focus-visible{border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.mobile-session-row__open:focus-visible{border-color:color-mix(in srgb,var(--color-accent)44%,var(--color-border-default))}}.mobile-session-row__open:focus-visible{background:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.mobile-session-row__open:focus-visible{background:color-mix(in srgb,var(--color-accent)12%,var(--color-bg-surface))}}.mobile-session-row__open:focus-visible{outline:2px solid var(--color-accent);outline-offset:-2px}.mobile-session-row__open:active{background:var(--color-accent);transform:translateY(1px)}@supports (color:color-mix(in lab,red,red)){.mobile-session-row__open:active{background:color-mix(in srgb,var(--color-accent)16%,var(--color-bg-hover))}}.mobile-session-row__open-icon{flex-shrink:0;width:16px;height:16px}.mobile-session-list__view-all{border:none;border-top:1px solid var(--color-border-subtle);background:0 0;min-height:44px;padding:0 0 0 15px}@supports (color:color-mix(in lab,red,red)){.mobile-session-list__view-all{border-top:1px solid color-mix(in srgb,var(--color-border-subtle)84%,transparent)}}.mobile-session-list__view-all{text-align:left;color:var(--color-accent);cursor:pointer;font-size:12px;font-weight:600}.mobile-session-list__empty{min-height:44px;color:var(--color-text-muted);align-items:center;padding:0 12px 0 15px;font-size:12px;display:flex}.accordion-header{cursor:pointer;text-align:left;width:100%;min-height:0;color:var(--color-text-primary);background:0 0;border:none;align-items:center;gap:8px;padding:10px 12px;display:flex}.accordion-header__dot{border-radius:999px;flex-shrink:0;width:8px;height:8px}.accordion-header__label{color:var(--color-text-muted);letter-spacing:-.03em;flex:1;font-size:16px;font-weight:600}.accordion-section--expanded .accordion-header__label{color:var(--color-text-primary)}.accordion-section--collapsed .accordion-header{background:var(--color-bg-surface)}@supports (color:color-mix(in lab,red,red)){.accordion-section--collapsed .accordion-header{background:color-mix(in srgb,var(--color-bg-surface)72%,var(--color-bg-base))}}.accordion-section--expanded .accordion-header{background:var(--color-bg-surface)}@supports (color:color-mix(in lab,red,red)){.accordion-section--expanded .accordion-header{background:color-mix(in srgb,var(--color-bg-surface)92%,var(--color-bg-base))}}.accordion-header__count{text-align:center;min-width:0;color:var(--color-text-tertiary);font-variant-numeric:tabular-nums;background:0 0;padding:0;font-size:13px;font-weight:600}.accordion-header__chevron{color:var(--color-text-tertiary);flex-shrink:0;font-size:9px;transition:transform .25s}.accordion-section:not(.accordion-section--collapsed) .accordion-header__chevron{transform:rotate(90deg)}.accordion-body{grid-template-rows:1fr;transition:grid-template-rows .25s;display:grid}.accordion-section--collapsed .accordion-body{grid-template-rows:0fr}.accordion-section--collapsed .accordion-body>*{overflow:hidden}.mobile-pr-list{border:1px solid var(--color-border-default);flex-direction:column;display:flex}@supports (color:color-mix(in lab,red,red)){.mobile-pr-list{border:1px solid color-mix(in srgb,var(--color-border-default)82%,transparent)}}.mobile-pr-list{background:var(--color-bg-surface)}.mobile-pr-card{border-top:1px solid var(--color-border-subtle);color:var(--color-text-primary);flex-direction:column;gap:5px;padding:11px 12px;text-decoration:none;display:flex}.mobile-pr-card:first-child{border-top:none}.mobile-pr-card__line{align-items:center;gap:8px;min-width:0;display:flex}.mobile-pr-card__number{font-family:var(--font-mono);color:var(--color-accent);flex-shrink:0;font-size:11px;font-weight:700}.mobile-pr-card__title{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-size:12px;font-weight:600;overflow:hidden}.mobile-pr-card__size{border:1px solid var(--color-border-default);background:var(--color-bg-subtle);color:var(--color-text-secondary);flex-shrink:0;padding:1px 6px;font-size:10px;font-weight:700}.mobile-pr-card__meta{color:var(--color-text-muted);flex-wrap:wrap;gap:8px;font-size:10px;display:flex}.mx-auto.max-w-\[900px\]>h2{color:var(--color-text-secondary);letter-spacing:.12em;margin-bottom:8px;padding-left:0;font-size:11px}}@media (max-width:480px){.dashboard-title{font-size:20px}.dashboard-stat-cards{flex-direction:column}.dashboard-stat-card{width:100%}.kanban-column-body{max-height:300px}.kanban-column__title{font-size:16px}.session-page-header h1{font-size:15px}.session-detail-page .mx-auto{padding-left:8px;padding-right:8px}}@media (display-mode:standalone){body{padding-top:env(safe-area-inset-top,0)}}@keyframes toast-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes toast-out{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(8px)}}.toast-container{bottom:calc(env(safe-area-inset-bottom,0px) + 16px);z-index:var(--z-toast);pointer-events:none;flex-direction:column;align-items:center;display:flex;position:fixed;left:50%;transform:translate(-50%)}@media (max-width:767px){.toast-container{bottom:calc(env(safe-area-inset-bottom,0px) + 76px)}}.toast{pointer-events:auto;background:var(--color-bg-elevated);border:1px solid var(--color-border-default);color:var(--color-text-primary);border-radius:6px;align-items:center;gap:8px;max-width:340px;padding:10px 16px;font-size:13px;line-height:1.4;animation:toast-in .2s forwards;display:flex;box-shadow:0 4px 12px #00000026}.toast__icon{background:var(--color-text-secondary);border-radius:50%;flex-shrink:0;width:8px;height:8px}.toast--success .toast__icon{background:var(--color-status-working)}.toast--error .toast__icon{background:var(--color-status-error)}.toast--info .toast__icon{background:var(--color-text-secondary)}.toast__message{flex:1}@keyframes sheet-in{0%{transform:translateY(100%)}to{transform:translateY(0)}}.bottom-sheet-backdrop{z-index:calc(var(--z-overlay) + 20);background:#00000080;position:fixed;inset:0}.bottom-sheet{background:var(--color-bg-surface);border-top:1px solid var(--color-border-default);padding:16px 20px calc(12px + env(safe-area-inset-bottom,0px));z-index:calc(var(--z-overlay) + 21);border-bottom:none;animation:sheet-in .25s forwards;position:fixed;bottom:0;left:0;right:0;transform:translateY(0)}.bottom-sheet__handle{background:var(--color-border-default);border-radius:2px;width:36px;height:4px;margin:0 auto 16px}.bottom-sheet__header{margin-bottom:16px}.bottom-sheet__title{color:var(--color-text-primary);margin:0 0 4px;font-size:15px;font-weight:600}.bottom-sheet__subtitle{color:var(--color-text-secondary);margin:0;font-size:12px}.bottom-sheet__session-info{background:var(--color-bg-subtle);border:1px solid var(--color-border-subtle);margin-bottom:20px;padding:10px 12px}.bottom-sheet__session-name{color:var(--color-text-primary);white-space:nowrap;text-overflow:ellipsis;margin-bottom:4px;font-size:13px;font-weight:500;overflow:hidden}.bottom-sheet__session-meta{flex-wrap:wrap;gap:8px;display:flex}.bottom-sheet__tag{border:1px solid var(--color-border-default);background:var(--color-bg-surface);letter-spacing:.04em;text-transform:uppercase;min-height:24px;color:var(--color-text-secondary);align-items:center;padding:0 8px;font-size:10px;font-weight:600;display:inline-flex}.bottom-sheet__tag--accent{color:var(--color-accent);border-color:var(--color-accent)}@supports (color:color-mix(in lab,red,red)){.bottom-sheet__tag--accent{border-color:color-mix(in srgb,var(--color-accent)24%,var(--color-border-default))}}.bottom-sheet__tag--mono{font-family:var(--font-mono);text-transform:none;letter-spacing:0}.bottom-sheet__summary{color:var(--color-text-secondary);-webkit-line-clamp:1;-webkit-box-orient:vertical;margin:10px 0 0;font-size:12px;line-height:1.5;display:-webkit-box;overflow:hidden}.bottom-sheet__actions{gap:10px;display:flex}.bottom-sheet__btn{cursor:pointer;border:1px solid var(--color-border-default);flex:1;justify-content:center;align-items:center;gap:8px;min-height:44px;font-size:14px;font-weight:500;transition:opacity .15s;display:inline-flex}.bottom-sheet__btn-icon{flex-shrink:0;width:14px;height:14px}.bottom-sheet__btn:active{opacity:.75}.bottom-sheet__btn--cancel{color:var(--color-text-secondary);background:0 0}.bottom-sheet__btn--cancel:hover{background:var(--color-bg-subtle)}.bottom-sheet__btn--danger{background:var(--color-status-error);border-color:var(--color-status-error);color:#fff}.bottom-sheet__btn--danger:hover{opacity:.9}.bottom-sheet__btn--primary{background:var(--color-accent);border-color:var(--color-accent);color:#fff;justify-content:center;align-items:center;text-decoration:none;display:inline-flex}.bottom-sheet__btn--primary:hover{opacity:.92}.bottom-sheet__btn--secondary{color:var(--color-text-primary);background:0 0}.bottom-sheet__btn--secondary:hover{background:var(--color-bg-subtle)}.connection-bar{z-index:var(--z-connection-bar,500);justify-content:center;align-items:center;height:0;font-size:13px;font-weight:500;transition:height .2s,opacity .3s;display:flex;position:fixed;top:0;left:0;right:0;overflow:hidden}.connection-bar--reconnecting{background:#d4a017;height:4px;animation:connection-pulse 1.5s ease-in-out infinite}.connection-bar--disconnected{background:var(--color-status-error);color:#fff;cursor:pointer;height:32px}@keyframes connection-pulse{0%,to{opacity:1}50%{opacity:.4}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}
|
|
@@ -1,375 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Terminal server that manages ttyd instances for tmux sessions.
|
|
3
|
-
*
|
|
4
|
-
* Runs alongside Next.js. Spawns a ttyd process per session on demand,
|
|
5
|
-
* each on a unique port. The dashboard embeds ttyd via iframe.
|
|
6
|
-
*
|
|
7
|
-
* ttyd handles all the hard parts: xterm.js, WebSocket, ANSI rendering,
|
|
8
|
-
* cursor positioning, resize, input — battle-tested and correct.
|
|
9
|
-
*
|
|
10
|
-
* TODO: Add authentication middleware to verify:
|
|
11
|
-
* - User is authenticated
|
|
12
|
-
* - User owns the requested session
|
|
13
|
-
* - Rate limiting for terminal access
|
|
14
|
-
*/
|
|
15
|
-
import { spawn } from "node:child_process";
|
|
16
|
-
import { createServer, request } from "node:http";
|
|
17
|
-
import { createCorrelationId } from "@aoagents/ao-core";
|
|
18
|
-
import { findTmux, resolveTmuxSession, validateSessionId } from "./tmux-utils.js";
|
|
19
|
-
import { createObserverContext, inferProjectId } from "./terminal-observability.js";
|
|
20
|
-
/** Cached full path to tmux binary */
|
|
21
|
-
const TMUX = findTmux();
|
|
22
|
-
console.log(`[Terminal] Using tmux: ${TMUX}`);
|
|
23
|
-
const instances = new Map();
|
|
24
|
-
const metrics = {
|
|
25
|
-
activeInstances: 0,
|
|
26
|
-
totalSpawns: 0,
|
|
27
|
-
totalErrors: 0,
|
|
28
|
-
totalReused: 0,
|
|
29
|
-
};
|
|
30
|
-
const availablePorts = new Set(); // Pool of recycled ports
|
|
31
|
-
let nextPort = 7800; // Start ttyd instances from port 7800
|
|
32
|
-
const MAX_PORT = 7900; // Prevent unbounded port allocation
|
|
33
|
-
const { config: observabilityConfig, observer } = createObserverContext("terminal-websocket");
|
|
34
|
-
function recordWebsocketMetric(input) {
|
|
35
|
-
if (!observer) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
const correlationId = createCorrelationId("ws");
|
|
39
|
-
observer.recordOperation({
|
|
40
|
-
metric: input.metric,
|
|
41
|
-
operation: `terminal.websocket.${input.metric}`,
|
|
42
|
-
outcome: input.outcome,
|
|
43
|
-
correlationId,
|
|
44
|
-
projectId: input.sessionId ? inferProjectId(observabilityConfig, input.sessionId) : undefined,
|
|
45
|
-
sessionId: input.sessionId,
|
|
46
|
-
reason: input.reason,
|
|
47
|
-
data: input.data,
|
|
48
|
-
level: input.outcome === "failure" ? "error" : "info",
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Check if ttyd is ready to accept connections by making a test request.
|
|
53
|
-
* Returns a promise that resolves when ttyd is ready or rejects after timeout.
|
|
54
|
-
* Properly cancels pending timeouts and requests to prevent memory leaks.
|
|
55
|
-
*/
|
|
56
|
-
function waitForTtyd(port, sessionId, timeoutMs = 3000) {
|
|
57
|
-
const startTime = Date.now();
|
|
58
|
-
let timeoutId = null;
|
|
59
|
-
let pendingReq = null;
|
|
60
|
-
let settled = false;
|
|
61
|
-
return new Promise((resolve, reject) => {
|
|
62
|
-
const cleanup = () => {
|
|
63
|
-
settled = true;
|
|
64
|
-
if (timeoutId) {
|
|
65
|
-
clearTimeout(timeoutId);
|
|
66
|
-
timeoutId = null;
|
|
67
|
-
}
|
|
68
|
-
if (pendingReq) {
|
|
69
|
-
pendingReq.destroy();
|
|
70
|
-
pendingReq = null;
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
const checkReady = () => {
|
|
74
|
-
if (settled)
|
|
75
|
-
return;
|
|
76
|
-
if (Date.now() - startTime > timeoutMs) {
|
|
77
|
-
cleanup();
|
|
78
|
-
reject(new Error(`ttyd did not become ready within ${timeoutMs}ms`));
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
const req = request({
|
|
82
|
-
hostname: "localhost",
|
|
83
|
-
port,
|
|
84
|
-
path: `/${sessionId}/`,
|
|
85
|
-
method: "GET",
|
|
86
|
-
timeout: 500,
|
|
87
|
-
}, (_res) => {
|
|
88
|
-
// Any response (even 404) means ttyd is listening
|
|
89
|
-
cleanup();
|
|
90
|
-
resolve();
|
|
91
|
-
});
|
|
92
|
-
pendingReq = req;
|
|
93
|
-
req.on("timeout", () => {
|
|
94
|
-
if (settled)
|
|
95
|
-
return;
|
|
96
|
-
req.destroy();
|
|
97
|
-
pendingReq = null;
|
|
98
|
-
// Schedule retry but track the timeout ID
|
|
99
|
-
timeoutId = setTimeout(checkReady, 100);
|
|
100
|
-
});
|
|
101
|
-
req.on("error", () => {
|
|
102
|
-
if (settled)
|
|
103
|
-
return;
|
|
104
|
-
pendingReq = null;
|
|
105
|
-
// Connection refused or other error - ttyd not ready yet, retry
|
|
106
|
-
timeoutId = setTimeout(checkReady, 100);
|
|
107
|
-
});
|
|
108
|
-
req.end();
|
|
109
|
-
};
|
|
110
|
-
checkReady();
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Spawn or reuse a ttyd instance for a tmux session.
|
|
115
|
-
*
|
|
116
|
-
* @param sessionId - User-facing session ID (used for base-path and URL)
|
|
117
|
-
* @param tmuxSessionName - Actual tmux session name (may be hash-prefixed)
|
|
118
|
-
*/
|
|
119
|
-
function getOrSpawnTtyd(sessionId, tmuxSessionName) {
|
|
120
|
-
const existing = instances.get(sessionId);
|
|
121
|
-
if (existing) {
|
|
122
|
-
metrics.totalReused += 1;
|
|
123
|
-
recordWebsocketMetric({
|
|
124
|
-
metric: "websocket_connect",
|
|
125
|
-
outcome: "success",
|
|
126
|
-
sessionId,
|
|
127
|
-
data: { reused: true, port: existing.port },
|
|
128
|
-
});
|
|
129
|
-
return existing;
|
|
130
|
-
}
|
|
131
|
-
// Allocate port: reuse from pool if available, otherwise increment
|
|
132
|
-
let port;
|
|
133
|
-
if (availablePorts.size > 0) {
|
|
134
|
-
// Reuse a recycled port
|
|
135
|
-
port = availablePorts.values().next().value;
|
|
136
|
-
availablePorts.delete(port);
|
|
137
|
-
}
|
|
138
|
-
else {
|
|
139
|
-
// Allocate new port
|
|
140
|
-
if (nextPort >= MAX_PORT) {
|
|
141
|
-
throw new Error(`Port exhaustion: reached maximum of ${MAX_PORT - 7800} terminal instances`);
|
|
142
|
-
}
|
|
143
|
-
port = nextPort++;
|
|
144
|
-
}
|
|
145
|
-
console.log(`[Terminal] Spawning ttyd for ${tmuxSessionName} on port ${port}`);
|
|
146
|
-
metrics.totalSpawns += 1;
|
|
147
|
-
metrics.lastSpawnAt = new Date().toISOString();
|
|
148
|
-
// Enable mouse mode for scrollback support
|
|
149
|
-
const mouseProc = spawn(TMUX, ["set-option", "-t", tmuxSessionName, "mouse", "on"]);
|
|
150
|
-
mouseProc.on("error", (err) => {
|
|
151
|
-
console.error(`[Terminal] Failed to set mouse mode for ${tmuxSessionName}:`, err.message);
|
|
152
|
-
});
|
|
153
|
-
// Hide the green status bar for cleaner appearance
|
|
154
|
-
const statusProc = spawn(TMUX, ["set-option", "-t", tmuxSessionName, "status", "off"]);
|
|
155
|
-
statusProc.on("error", (err) => {
|
|
156
|
-
console.error(`[Terminal] Failed to hide status bar for ${tmuxSessionName}:`, err.message);
|
|
157
|
-
});
|
|
158
|
-
// Use user-facing sessionId for base-path (matches URL the dashboard uses)
|
|
159
|
-
// Use tmuxSessionName for tmux attach (may be hash-prefixed)
|
|
160
|
-
const proc = spawn("ttyd", [
|
|
161
|
-
"--writable",
|
|
162
|
-
"--port",
|
|
163
|
-
String(port),
|
|
164
|
-
"--base-path",
|
|
165
|
-
`/${sessionId}`,
|
|
166
|
-
TMUX,
|
|
167
|
-
"attach-session",
|
|
168
|
-
"-t",
|
|
169
|
-
tmuxSessionName,
|
|
170
|
-
], {
|
|
171
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
172
|
-
});
|
|
173
|
-
proc.stdout?.on("data", (data) => {
|
|
174
|
-
console.log(`[Terminal] ttyd ${sessionId}: ${data.toString().trim()}`);
|
|
175
|
-
});
|
|
176
|
-
proc.stderr?.on("data", (data) => {
|
|
177
|
-
console.log(`[Terminal] ttyd ${sessionId}: ${data.toString().trim()}`);
|
|
178
|
-
});
|
|
179
|
-
// Use once() for cleanup handlers to prevent race condition when both exit and error fire
|
|
180
|
-
proc.once("exit", (code) => {
|
|
181
|
-
console.log(`[Terminal] ttyd ${sessionId} exited with code ${code}`);
|
|
182
|
-
// Only delete if this is still the current instance (prevents race with error handler)
|
|
183
|
-
const current = instances.get(sessionId);
|
|
184
|
-
if (current?.process === proc) {
|
|
185
|
-
instances.delete(sessionId);
|
|
186
|
-
metrics.activeInstances = instances.size;
|
|
187
|
-
// Only recycle port on clean exit (code 0), not on errors
|
|
188
|
-
// Failed ttyd processes may leave ports in TIME_WAIT state
|
|
189
|
-
if (code === 0) {
|
|
190
|
-
availablePorts.add(port);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
recordWebsocketMetric({
|
|
194
|
-
metric: "websocket_disconnect",
|
|
195
|
-
outcome: code === 0 ? "success" : "failure",
|
|
196
|
-
sessionId,
|
|
197
|
-
reason: `ttyd_exit:${code}`,
|
|
198
|
-
data: { port },
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
proc.once("error", (err) => {
|
|
202
|
-
console.error(`[Terminal] ttyd ${sessionId} error:`, err.message);
|
|
203
|
-
// Only delete if this is still the current instance (prevents race with exit handler)
|
|
204
|
-
const current = instances.get(sessionId);
|
|
205
|
-
if (current?.process === proc) {
|
|
206
|
-
instances.delete(sessionId);
|
|
207
|
-
metrics.activeInstances = instances.size;
|
|
208
|
-
// Don't recycle port on error - may still be in use or TIME_WAIT
|
|
209
|
-
}
|
|
210
|
-
metrics.totalErrors += 1;
|
|
211
|
-
metrics.lastErrorAt = new Date().toISOString();
|
|
212
|
-
metrics.lastErrorReason = err.message;
|
|
213
|
-
recordWebsocketMetric({
|
|
214
|
-
metric: "websocket_error",
|
|
215
|
-
outcome: "failure",
|
|
216
|
-
sessionId,
|
|
217
|
-
reason: err.message,
|
|
218
|
-
data: { port },
|
|
219
|
-
});
|
|
220
|
-
// Kill any running process
|
|
221
|
-
try {
|
|
222
|
-
proc.kill();
|
|
223
|
-
}
|
|
224
|
-
catch {
|
|
225
|
-
// Ignore kill errors if process already dead
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
const instance = { sessionId, port, process: proc };
|
|
229
|
-
instances.set(sessionId, instance);
|
|
230
|
-
metrics.activeInstances = instances.size;
|
|
231
|
-
recordWebsocketMetric({
|
|
232
|
-
metric: "websocket_connect",
|
|
233
|
-
outcome: "success",
|
|
234
|
-
sessionId,
|
|
235
|
-
data: { reused: false, port },
|
|
236
|
-
});
|
|
237
|
-
return instance;
|
|
238
|
-
}
|
|
239
|
-
// Simple HTTP API for the dashboard to request terminal URLs
|
|
240
|
-
const server = createServer(async (req, res) => {
|
|
241
|
-
const url = new URL(req.url ?? "/", "http://localhost");
|
|
242
|
-
// CORS for dashboard - allow requests from the same host as the dashboard
|
|
243
|
-
// TODO: Replace with proper session-based authentication
|
|
244
|
-
const origin = req.headers.origin;
|
|
245
|
-
if (origin && origin !== "null") {
|
|
246
|
-
// Extract hostname from origin and compare with request host
|
|
247
|
-
try {
|
|
248
|
-
const originUrl = new URL(origin);
|
|
249
|
-
const requestHost = req.headers.host;
|
|
250
|
-
// Allow if origin hostname matches request host (supports remote deployments)
|
|
251
|
-
if (requestHost && originUrl.hostname === requestHost.split(":")[0]) {
|
|
252
|
-
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
catch {
|
|
256
|
-
// Invalid origin URL, don't set CORS header
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
// Allow null origin (file:// or local HTML files)
|
|
261
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
262
|
-
}
|
|
263
|
-
res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
|
|
264
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
265
|
-
if (req.method === "OPTIONS") {
|
|
266
|
-
res.writeHead(204);
|
|
267
|
-
res.end();
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
// GET /terminal?session=ao-1 → returns { url, port }
|
|
271
|
-
if (url.pathname === "/terminal") {
|
|
272
|
-
const sessionId = url.searchParams.get("session");
|
|
273
|
-
if (!sessionId) {
|
|
274
|
-
res.writeHead(400, { "Content-Type": "application/json" });
|
|
275
|
-
res.end(JSON.stringify({ error: "Missing session parameter" }));
|
|
276
|
-
recordWebsocketMetric({
|
|
277
|
-
metric: "websocket_error",
|
|
278
|
-
outcome: "failure",
|
|
279
|
-
reason: "Missing session parameter",
|
|
280
|
-
});
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
// Validate session ID to prevent path traversal and injection
|
|
284
|
-
if (!validateSessionId(sessionId)) {
|
|
285
|
-
res.writeHead(400, { "Content-Type": "application/json" });
|
|
286
|
-
res.end(JSON.stringify({ error: "Invalid session ID" }));
|
|
287
|
-
recordWebsocketMetric({
|
|
288
|
-
metric: "websocket_error",
|
|
289
|
-
outcome: "failure",
|
|
290
|
-
sessionId,
|
|
291
|
-
reason: "Invalid session ID",
|
|
292
|
-
});
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
// Resolve tmux session name: try exact match first, then suffix match
|
|
296
|
-
// (hash-prefixed sessions like "8474d6f29887-ao-15" are accessed by user-facing ID "ao-15")
|
|
297
|
-
const tmuxSessionId = resolveTmuxSession(sessionId, TMUX);
|
|
298
|
-
if (!tmuxSessionId) {
|
|
299
|
-
res.writeHead(404, { "Content-Type": "application/json" });
|
|
300
|
-
res.end(JSON.stringify({ error: "Session not found" }));
|
|
301
|
-
recordWebsocketMetric({
|
|
302
|
-
metric: "websocket_error",
|
|
303
|
-
outcome: "failure",
|
|
304
|
-
sessionId,
|
|
305
|
-
reason: "Session not found",
|
|
306
|
-
});
|
|
307
|
-
return;
|
|
308
|
-
}
|
|
309
|
-
// Spawn ttyd and wait for it to be ready (catch port exhaustion and startup failures)
|
|
310
|
-
try {
|
|
311
|
-
const instance = getOrSpawnTtyd(sessionId, tmuxSessionId);
|
|
312
|
-
await waitForTtyd(instance.port, sessionId);
|
|
313
|
-
// Use the request host to construct the terminal URL (supports remote access)
|
|
314
|
-
const host = req.headers.host ?? "localhost";
|
|
315
|
-
const protocol = req.headers["x-forwarded-proto"] ?? "http";
|
|
316
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
317
|
-
res.end(JSON.stringify({
|
|
318
|
-
url: `${protocol}://${host.split(":")[0]}:${instance.port}/${sessionId}/`,
|
|
319
|
-
port: instance.port,
|
|
320
|
-
sessionId,
|
|
321
|
-
}));
|
|
322
|
-
}
|
|
323
|
-
catch (err) {
|
|
324
|
-
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
325
|
-
console.error(`[Terminal] Failed to start terminal for ${sessionId}:`, errorMsg);
|
|
326
|
-
metrics.totalErrors += 1;
|
|
327
|
-
metrics.lastErrorAt = new Date().toISOString();
|
|
328
|
-
metrics.lastErrorReason = errorMsg;
|
|
329
|
-
recordWebsocketMetric({
|
|
330
|
-
metric: "websocket_error",
|
|
331
|
-
outcome: "failure",
|
|
332
|
-
sessionId,
|
|
333
|
-
reason: errorMsg,
|
|
334
|
-
});
|
|
335
|
-
res.writeHead(503, { "Content-Type": "application/json" });
|
|
336
|
-
res.end(JSON.stringify({ error: "Failed to start terminal" }));
|
|
337
|
-
}
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
// GET /health
|
|
341
|
-
if (url.pathname === "/health") {
|
|
342
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
343
|
-
res.end(JSON.stringify({
|
|
344
|
-
instances: Object.fromEntries([...instances.entries()].map(([id, inst]) => [id, { port: inst.port }])),
|
|
345
|
-
metrics,
|
|
346
|
-
}));
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
res.writeHead(404);
|
|
350
|
-
res.end("Not found");
|
|
351
|
-
});
|
|
352
|
-
const PORT = parseInt(process.env.TERMINAL_PORT ?? "14800", 10);
|
|
353
|
-
server.listen(PORT, () => {
|
|
354
|
-
console.log(`[Terminal] Server listening on port ${PORT}`);
|
|
355
|
-
});
|
|
356
|
-
// Graceful shutdown — kill all ttyd instances
|
|
357
|
-
function shutdown(signal) {
|
|
358
|
-
console.log(`[Terminal] Received ${signal}, shutting down...`);
|
|
359
|
-
for (const [, instance] of instances) {
|
|
360
|
-
instance.process.kill();
|
|
361
|
-
}
|
|
362
|
-
server.close(() => {
|
|
363
|
-
console.log("[Terminal] Server closed");
|
|
364
|
-
process.exit(0);
|
|
365
|
-
});
|
|
366
|
-
// Force exit after 5s if graceful shutdown hangs
|
|
367
|
-
// Use unref() so this timer doesn't prevent process exit if server closes quickly
|
|
368
|
-
const forceExitTimer = setTimeout(() => {
|
|
369
|
-
console.error("[Terminal] Forced shutdown after timeout");
|
|
370
|
-
process.exit(1);
|
|
371
|
-
}, 5000);
|
|
372
|
-
forceExitTimer.unref();
|
|
373
|
-
}
|
|
374
|
-
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
375
|
-
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
File without changes
|