conductor-oss 0.18.2 → 0.18.4
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/README.md +1 -21
- package/package.json +5 -5
- package/web/.next/standalone/packages/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/packages/web/.next/app-path-routes-manifest.json +1 -3
- package/web/.next/standalone/packages/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/packages/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/packages/web/.next/routes-manifest.json +6 -22
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found/page/server-reference-manifest.json +7 -7
- package/web/.next/standalone/packages/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.rsc +4 -4
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/access/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/agents/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/agents/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/app-update/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/app-update/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/attachments/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/attachments/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/auth/session/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/boards/comments/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/boards/comments/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/boards/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/boards/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/config/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/config/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/context-files/open/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/context-files/open/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/context-files/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/context-files/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/events/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/events/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/executor/health/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/executor/health/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/filesystem/directory/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/filesystem/directory/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/filesystem/pick-directory/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/filesystem/pick-directory/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/github/repos/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/github/repos/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/github/webhook/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/github/webhook/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/health/boards/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/health/boards/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/health/sessions/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/health/sessions/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/notifications/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/preferences/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/preferences/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/remote-access/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/remote-access/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/repositories/[id]/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/repositories/[id]/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/repositories/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/repositories/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/actions/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/actions/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/archive/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/archive/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/checks/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/checks/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/diff/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/diff/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feed/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feed/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feedback/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feedback/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/files/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/files/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/interrupt/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/interrupt/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/kill/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/kill/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/preview/dom/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/preview/dom/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/preview/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/preview/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/preview/screenshot/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/preview/screenshot/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/restore/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/restore/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/snapshot/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/snapshot/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/token/route/app-paths-manifest.json +3 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/token/route.js +10 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/token/route.js.nft.json +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/token/route_client-reference-manifest.js +2 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/spawn/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/spawn/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/branches/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/branches/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/route.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/workspaces/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/page/react-loadable-manifest.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/page/server-reference-manifest.json +7 -7
- package/web/.next/standalone/packages/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/sessions/[id]/page/react-loadable-manifest.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/sessions/[id]/page/server-reference-manifest.json +7 -7
- package/web/.next/standalone/packages/web/.next/server/app/sessions/[id]/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/sign-in/[[...sign-in]]/page/server-reference-manifest.json +7 -7
- package/web/.next/standalone/packages/web/.next/server/app/sign-in/[[...sign-in]]/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/sign-in/[[...sign-in]]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page/server-reference-manifest.json +7 -7
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/app-paths-manifest.json +1 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/26076_server_app_api_sessions_[id]_terminal_token_route_actions_9c4b3c06.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__63017d21._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__f3d09d5c._.js → [root-of-the-server]__9279c912._.js} +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/_2c837d66._.js +80 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__379d412d._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__da08a50a._.js → [root-of-the-server]__443ba186._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__a565f9a3._.js → [root-of-the-server]__742dad30._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__749fe4b2._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__992cdcf8._.js → [root-of-the-server]__a8fa29c1._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_0e1412de._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_532f707d._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_69e05fca._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_80efe193._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{_62d206cc._.js → _9bf43d8d._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_c0f0e227._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_f36ddaa9._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{node_modules_5646ec2d._.js → node_modules_91aa5708._.js} +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_@clerk_nextjs_dist_esm_app-router_3964db17._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_@clerk_nextjs_dist_esm_app-router_5c863a0e._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{node_modules_6d2fa1ea._.js → node_modules_be1275d0._.js} +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/packages_web_src_components_sessions_SessionTerminal_tsx_eaf9458b._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/functions-config-manifest.json +2 -4
- package/web/.next/standalone/packages/web/.next/server/pages/404.html +1 -1
- package/web/.next/standalone/packages/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/packages/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/server-reference-manifest.json +8 -8
- package/web/.next/standalone/packages/web/.next/static/chunks/{c1e720eabb98af26.js → 2037d1500c64fbef.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/{58a9b117e5684e7c.js → 3ad6d404d5657604.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/4d288f280972fd06.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/65bc9229d60adf9f.css +4 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/97e7e5343941de65.js +1 -0
- package/web/.next/{static/chunks/8d05dc3b261207bb.js → standalone/packages/web/.next/static/chunks/ab8cea4266d5034c.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/{655db4d21daaca4d.js → b2b84b9e8ccbeafa.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/b9a43bac36046bf9.js +138 -0
- package/web/.next/{static/chunks/9331c73d4edcd945.js → standalone/packages/web/.next/static/chunks/d1cbb83a98e765b5.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/{301802e8e898dd01.js → f2fea305b6822999.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/f48f57293e98e0d8.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/fe52c44944adc7f2.js +1 -0
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/terminal/token/route.ts +13 -0
- package/web/.next/standalone/packages/web/src/components/sessions/SessionTerminal.tsx +77 -39
- package/web/.next/standalone/packages/web/src/components/sessions/sessionTerminalUtils.test.ts +0 -122
- package/web/.next/standalone/packages/web/src/components/sessions/sessionTerminalUtils.ts +0 -220
- package/web/.next/standalone/packages/web/src/components/sessions/terminal/terminalApi.ts +89 -87
- package/web/.next/standalone/packages/web/src/components/sessions/terminal/terminalCache.ts +2 -73
- package/web/.next/standalone/packages/web/src/components/sessions/terminal/terminalConstants.ts +0 -8
- package/web/.next/standalone/packages/web/src/components/sessions/terminal/terminalTypes.ts +0 -19
- package/web/.next/standalone/packages/web/src/components/sessions/terminal/ttydClient.ts +122 -27
- package/web/.next/standalone/packages/web/src/components/sessions/terminal/useTtydConnection.ts +9 -12
- package/web/.next/standalone/packages/web/src/lib/sessionState.ts +0 -473
- package/web/.next/static/chunks/{c1e720eabb98af26.js → 2037d1500c64fbef.js} +1 -1
- package/web/.next/static/chunks/{58a9b117e5684e7c.js → 3ad6d404d5657604.js} +1 -1
- package/web/.next/static/chunks/4d288f280972fd06.js +1 -0
- package/web/.next/static/chunks/65bc9229d60adf9f.css +4 -0
- package/web/.next/static/chunks/97e7e5343941de65.js +1 -0
- package/web/.next/{standalone/packages/web/.next/static/chunks/8d05dc3b261207bb.js → static/chunks/ab8cea4266d5034c.js} +1 -1
- package/web/.next/static/chunks/{655db4d21daaca4d.js → b2b84b9e8ccbeafa.js} +1 -1
- package/web/.next/static/chunks/b9a43bac36046bf9.js +138 -0
- package/web/.next/{standalone/packages/web/.next/static/chunks/9331c73d4edcd945.js → static/chunks/d1cbb83a98e765b5.js} +1 -1
- package/web/.next/static/chunks/{301802e8e898dd01.js → f2fea305b6822999.js} +1 -1
- package/web/.next/static/chunks/f48f57293e98e0d8.js +1 -0
- package/web/.next/static/chunks/fe52c44944adc7f2.js +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feed/stream/route/app-paths-manifest.json +0 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feed/stream/route.js +0 -10
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feed/stream/route.js.nft.json +0 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feed/stream/route_client-reference-manifest.js +0 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/route/app-paths-manifest.json +0 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/route/build-manifest.json +0 -11
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/route/server-reference-manifest.json +0 -4
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/route.js +0 -10
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/route.js.map +0 -5
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/route.js.nft.json +0 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/route_client-reference-manifest.js +0 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route/app-paths-manifest.json +0 -3
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route/build-manifest.json +0 -11
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route/server-reference-manifest.json +0 -4
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route.js +0 -10
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route.js.map +0 -5
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route.js.nft.json +0 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route_client-reference-manifest.js +0 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/26076_server_app_api_sessions_[id]_terminal_connection_route_actions_46c114ee.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/29f24__next-internal_server_app_api_sessions_[id]_feed_stream_route_actions_1262f517.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/43d70_next-internal_server_app_api_sessions_[id]_output_stream_route_actions_9bfa500e.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__1029f927._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__d74c0f7a._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ddad8d14._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ede5c8ca._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__f56e5b36._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/_24c4e75d._.js +0 -80
- package/web/.next/standalone/packages/web/.next/server/chunks/_3d39aff4._.js +0 -80
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_307d7608._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_3ed93faf._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_@clerk_nextjs_dist_esm_app-router_4f296b1d._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_@clerk_nextjs_dist_esm_app-router_599a1810._.js +0 -3
- package/web/.next/standalone/packages/web/.next/static/chunks/06eb75e40dff98f1.css +0 -4
- package/web/.next/standalone/packages/web/.next/static/chunks/1382eff030c401e3.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/1684a3f76eefe776.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/267e541b481c3c75.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/810a3d36795ae9fd.js +0 -138
- package/web/.next/standalone/packages/web/.next/static/chunks/a8cd591e904d769e.js +0 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/feed/stream/route.ts +0 -80
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/output/stream/route.ts +0 -80
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/terminal/connection/route.test.ts +0 -343
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/terminal/connection/route.ts +0 -120
- package/web/.next/standalone/packages/web/src/components/Dashboard.tsx +0 -3444
- package/web/.next/standalone/packages/web/src/components/TerminalView.tsx +0 -770
- package/web/.next/standalone/packages/web/src/components/sessions/ChatPanel.tsx +0 -2097
- package/web/.next/standalone/packages/web/src/hooks/useSessionFeed.ts +0 -10
- package/web/.next/standalone/packages/web/src/hooks/useSessionOutputStream.ts +0 -166
- package/web/.next/standalone/packages/web/src/lib/chatFeed.ts +0 -196
- package/web/.next/static/chunks/06eb75e40dff98f1.css +0 -4
- package/web/.next/static/chunks/1382eff030c401e3.js +0 -1
- package/web/.next/static/chunks/1684a3f76eefe776.js +0 -1
- package/web/.next/static/chunks/267e541b481c3c75.js +0 -1
- package/web/.next/static/chunks/810a3d36795ae9fd.js +0 -138
- package/web/.next/static/chunks/a8cd591e904d769e.js +0 -1
- /package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/{feed/stream → terminal/token}/route/build-manifest.json +0 -0
- /package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/{feed/stream → terminal/token}/route/server-reference-manifest.json +0 -0
- /package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/{feed/stream → terminal/token}/route.js.map +0 -0
- /package/web/.next/standalone/packages/web/.next/static/{FHjp9qazH2xWUCRt6mqg4 → O7I3Iz18_tPidBRAWeKh8}/_buildManifest.js +0 -0
- /package/web/.next/standalone/packages/web/.next/static/{FHjp9qazH2xWUCRt6mqg4 → O7I3Iz18_tPidBRAWeKh8}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/packages/web/.next/static/{FHjp9qazH2xWUCRt6mqg4 → O7I3Iz18_tPidBRAWeKh8}/_ssgManifest.js +0 -0
- /package/web/.next/static/{FHjp9qazH2xWUCRt6mqg4 → O7I3Iz18_tPidBRAWeKh8}/_buildManifest.js +0 -0
- /package/web/.next/static/{FHjp9qazH2xWUCRt6mqg4 → O7I3Iz18_tPidBRAWeKh8}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{FHjp9qazH2xWUCRt6mqg4 → O7I3Iz18_tPidBRAWeKh8}/_ssgManifest.js +0 -0
package/web/.next/standalone/packages/web/src/components/sessions/sessionTerminalUtils.test.ts
CHANGED
|
@@ -2,24 +2,13 @@ import assert from "node:assert/strict";
|
|
|
2
2
|
import test from "node:test";
|
|
3
3
|
import { TERMINAL_FONT_FAMILY } from "@/components/terminal/xtermTheme";
|
|
4
4
|
import {
|
|
5
|
-
buildTerminalSnapshotPayload,
|
|
6
5
|
calculateMobileTerminalViewportMetrics,
|
|
7
|
-
decodeTerminalBase64Payload,
|
|
8
6
|
detectCompactTerminalChrome,
|
|
9
7
|
detectMobileTerminalInputRail,
|
|
10
8
|
getSessionTerminalViewportOptions,
|
|
11
|
-
normalizeTerminalSnapshot,
|
|
12
|
-
parseTerminalBinaryFrame,
|
|
13
|
-
prependTerminalModes,
|
|
14
9
|
sanitizeRemoteTerminalSnapshot,
|
|
15
|
-
stripBrowserTerminalResponses,
|
|
16
10
|
} from "./sessionTerminalUtils";
|
|
17
11
|
|
|
18
|
-
test("decodeTerminalBase64Payload decodes terminal stream payload bytes", () => {
|
|
19
|
-
const bytes = decodeTerminalBase64Payload("aGVsbG8=");
|
|
20
|
-
assert.deepEqual(Array.from(bytes), [104, 101, 108, 108, 111]);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
12
|
test("detectMobileTerminalInputRail only enables compact touch layouts on narrow viewports", () => {
|
|
24
13
|
assert.equal(detectMobileTerminalInputRail(390, true, 1), true);
|
|
25
14
|
assert.equal(detectMobileTerminalInputRail(390, false, 1), true);
|
|
@@ -42,122 +31,11 @@ test("detectCompactTerminalChrome activates immersive mode below lg breakpoint (
|
|
|
42
31
|
assert.equal(detectCompactTerminalChrome(844, 390, false, 1), true);
|
|
43
32
|
});
|
|
44
33
|
|
|
45
|
-
test("stripBrowserTerminalResponses removes browser-generated device status chatter", () => {
|
|
46
|
-
const raw = "\u001b[Ihello\u001b[12;34R\u001b[?1;2cworld\u001b]11;rgb:0000/0000/0000\u0007";
|
|
47
|
-
assert.equal(stripBrowserTerminalResponses(raw), "helloworld");
|
|
48
|
-
});
|
|
49
|
-
|
|
50
34
|
test("sanitizeRemoteTerminalSnapshot strips ANSI control sequences and normalizes newlines", () => {
|
|
51
35
|
const raw = "\u001b[31merror\u001b[0m\r\nnext\rline\u0000";
|
|
52
36
|
assert.equal(sanitizeRemoteTerminalSnapshot(raw), "error\nnext\nline");
|
|
53
37
|
});
|
|
54
38
|
|
|
55
|
-
test("normalizeTerminalSnapshot converts LF-only snapshots to CRLF for xterm replay", () => {
|
|
56
|
-
assert.equal(normalizeTerminalSnapshot("one\ntwo"), "one\r\ntwo");
|
|
57
|
-
assert.equal(normalizeTerminalSnapshot("one\r\ntwo"), "one\r\ntwo");
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test("buildTerminalSnapshotPayload prefixes mobile/web restore modes before the snapshot bytes", () => {
|
|
61
|
-
const payload = buildTerminalSnapshotPayload("prompt> ", {
|
|
62
|
-
alternateScreen: true,
|
|
63
|
-
applicationKeypad: true,
|
|
64
|
-
applicationCursor: true,
|
|
65
|
-
hideCursor: true,
|
|
66
|
-
bracketedPaste: true,
|
|
67
|
-
mouseProtocolMode: "AnyMotion",
|
|
68
|
-
mouseProtocolEncoding: "Sgr",
|
|
69
|
-
});
|
|
70
|
-
const text = new TextDecoder().decode(payload);
|
|
71
|
-
|
|
72
|
-
assert.match(text, /\u001b\[\?1049h/);
|
|
73
|
-
assert.match(text, /\u001b\[\?2004h/);
|
|
74
|
-
assert.match(text, /\u001b\[\?1003h/);
|
|
75
|
-
assert.match(text, /\u001b\[\?1006h/);
|
|
76
|
-
assert.ok(text.endsWith("prompt> "));
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test("prependTerminalModes keeps stream payload untouched when no modes are available", () => {
|
|
80
|
-
const payload = new TextEncoder().encode("plain");
|
|
81
|
-
assert.deepEqual(prependTerminalModes(payload), payload);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
test("parseTerminalBinaryFrame decodes restore frames with explicit mode metadata", () => {
|
|
85
|
-
const payload = new TextEncoder().encode("prompt> ");
|
|
86
|
-
const frame = new Uint8Array(24 + payload.length);
|
|
87
|
-
frame.set([0x43, 0x54, 0x50, 0x32, 2, 1], 0);
|
|
88
|
-
const view = new DataView(frame.buffer);
|
|
89
|
-
view.setBigUint64(6, 42n, false);
|
|
90
|
-
view.setUint8(14, 1);
|
|
91
|
-
view.setUint8(15, 2);
|
|
92
|
-
view.setUint16(16, 120, false);
|
|
93
|
-
view.setUint16(18, 32, false);
|
|
94
|
-
view.setUint8(20, 0b0001_1101);
|
|
95
|
-
view.setUint8(21, 4);
|
|
96
|
-
view.setUint8(22, 2);
|
|
97
|
-
frame.set(payload, 24);
|
|
98
|
-
|
|
99
|
-
const parsed = parseTerminalBinaryFrame(frame.buffer);
|
|
100
|
-
assert.deepEqual(parsed, {
|
|
101
|
-
kind: "restore",
|
|
102
|
-
sequence: 42,
|
|
103
|
-
snapshotVersion: 1,
|
|
104
|
-
reason: "lagged",
|
|
105
|
-
cols: 120,
|
|
106
|
-
rows: 32,
|
|
107
|
-
modes: {
|
|
108
|
-
alternateScreen: true,
|
|
109
|
-
applicationKeypad: false,
|
|
110
|
-
applicationCursor: true,
|
|
111
|
-
hideCursor: true,
|
|
112
|
-
bracketedPaste: true,
|
|
113
|
-
mouseProtocolMode: "AnyMotion",
|
|
114
|
-
mouseProtocolEncoding: "Sgr",
|
|
115
|
-
},
|
|
116
|
-
payload,
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test("parseTerminalBinaryFrame still accepts legacy restore frames", () => {
|
|
121
|
-
const payload = new TextEncoder().encode("prompt> ");
|
|
122
|
-
const frame = new Uint8Array(20 + payload.length);
|
|
123
|
-
frame.set([0x43, 0x54, 0x50, 0x32, 1, 1], 0);
|
|
124
|
-
const view = new DataView(frame.buffer);
|
|
125
|
-
view.setBigUint64(6, 42n, false);
|
|
126
|
-
view.setUint8(14, 1);
|
|
127
|
-
view.setUint8(15, 2);
|
|
128
|
-
view.setUint16(16, 120, false);
|
|
129
|
-
view.setUint16(18, 32, false);
|
|
130
|
-
frame.set(payload, 20);
|
|
131
|
-
|
|
132
|
-
const parsed = parseTerminalBinaryFrame(frame.buffer);
|
|
133
|
-
assert.deepEqual(parsed, {
|
|
134
|
-
kind: "restore",
|
|
135
|
-
sequence: 42,
|
|
136
|
-
snapshotVersion: 1,
|
|
137
|
-
reason: "lagged",
|
|
138
|
-
cols: 120,
|
|
139
|
-
rows: 32,
|
|
140
|
-
modes: undefined,
|
|
141
|
-
payload,
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
test("parseTerminalBinaryFrame decodes stream frames", () => {
|
|
146
|
-
const payload = new TextEncoder().encode("line\r\n");
|
|
147
|
-
const frame = new Uint8Array(14 + payload.length);
|
|
148
|
-
frame.set([0x43, 0x54, 0x50, 0x32, 2, 2], 0);
|
|
149
|
-
const view = new DataView(frame.buffer);
|
|
150
|
-
view.setBigUint64(6, 7n, false);
|
|
151
|
-
frame.set(payload, 14);
|
|
152
|
-
|
|
153
|
-
const parsed = parseTerminalBinaryFrame(frame.buffer);
|
|
154
|
-
assert.deepEqual(parsed, {
|
|
155
|
-
kind: "stream",
|
|
156
|
-
sequence: 7,
|
|
157
|
-
payload,
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
|
|
161
39
|
test("getSessionTerminalViewportOptions keeps compact fonts for phones and larger fonts for desktop", () => {
|
|
162
40
|
assert.deepEqual(getSessionTerminalViewportOptions(390), {
|
|
163
41
|
fontFamily: "'SF Mono', Menlo, Monaco, monospace",
|
|
@@ -25,228 +25,8 @@ export type TerminalModeState = {
|
|
|
25
25
|
const MOBILE_TERMINAL_INPUT_MAX_WIDTH_PX = 1024;
|
|
26
26
|
/** Must match the Tailwind `lg:` breakpoint (1024px) used in SessionTerminal / SessionDetail. */
|
|
27
27
|
const COMPACT_TERMINAL_CHROME_MAX_WIDTH_PX = 1024;
|
|
28
|
-
const TERMINAL_FRAME_MAGIC = [0x43, 0x54, 0x50, 0x32] as const;
|
|
29
|
-
const TERMINAL_FRAME_PROTOCOL_VERSION = 2;
|
|
30
|
-
const TERMINAL_FRAME_KIND_RESTORE = 1;
|
|
31
|
-
const TERMINAL_FRAME_KIND_STREAM = 2;
|
|
32
|
-
const TERMINAL_STREAM_FRAME_HEADER_BYTES = 14;
|
|
33
|
-
const TERMINAL_RESTORE_FRAME_HEADER_BYTES_V1 = 20;
|
|
34
|
-
const TERMINAL_RESTORE_FRAME_HEADER_BYTES_V2 = 24;
|
|
35
|
-
const BROWSER_TERMINAL_RESPONSE_PATTERNS = [
|
|
36
|
-
/\x1b\[(?:I|O)/g,
|
|
37
|
-
/\x1b\[\d+;\d+R/g,
|
|
38
|
-
/\x1b\[(?:[?>])[\d;]*c/g,
|
|
39
|
-
/\x1b\](?:10|11|12|4;\d+);[\s\S]*?(?:\x07|\x1b\\)/g,
|
|
40
|
-
];
|
|
41
28
|
const ANSI_ESCAPE_PATTERN = /\u001b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~]|\][\s\S]*?(?:\u0007|\u001b\\))/g;
|
|
42
29
|
|
|
43
|
-
export type TerminalBinaryFrame =
|
|
44
|
-
| {
|
|
45
|
-
kind: "restore";
|
|
46
|
-
sequence: number;
|
|
47
|
-
snapshotVersion: number;
|
|
48
|
-
reason: "attach" | "lagged" | "unknown";
|
|
49
|
-
cols: number;
|
|
50
|
-
rows: number;
|
|
51
|
-
modes?: TerminalModeState;
|
|
52
|
-
payload: Uint8Array;
|
|
53
|
-
}
|
|
54
|
-
| {
|
|
55
|
-
kind: "stream";
|
|
56
|
-
sequence: number;
|
|
57
|
-
payload: Uint8Array;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
function decodeTerminalRestoreReason(code: number): "attach" | "lagged" | "unknown" {
|
|
61
|
-
if (code === 1) {
|
|
62
|
-
return "attach";
|
|
63
|
-
}
|
|
64
|
-
if (code === 2) {
|
|
65
|
-
return "lagged";
|
|
66
|
-
}
|
|
67
|
-
return "unknown";
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function decodeTerminalMouseProtocolMode(code: number): string {
|
|
71
|
-
if (code === 1) return "Press";
|
|
72
|
-
if (code === 2) return "PressRelease";
|
|
73
|
-
if (code === 3) return "ButtonMotion";
|
|
74
|
-
if (code === 4) return "AnyMotion";
|
|
75
|
-
return "None";
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function decodeTerminalMouseProtocolEncoding(code: number): string {
|
|
79
|
-
if (code === 1) return "Utf8";
|
|
80
|
-
if (code === 2) return "Sgr";
|
|
81
|
-
if (code === 3) return "Urxvt";
|
|
82
|
-
return "Default";
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function decodeTerminalModes(flags: number, mouseModeCode: number, mouseEncodingCode: number): TerminalModeState {
|
|
86
|
-
return {
|
|
87
|
-
alternateScreen: (flags & (1 << 0)) !== 0,
|
|
88
|
-
applicationKeypad: (flags & (1 << 1)) !== 0,
|
|
89
|
-
applicationCursor: (flags & (1 << 2)) !== 0,
|
|
90
|
-
hideCursor: (flags & (1 << 3)) !== 0,
|
|
91
|
-
bracketedPaste: (flags & (1 << 4)) !== 0,
|
|
92
|
-
mouseProtocolMode: decodeTerminalMouseProtocolMode(mouseModeCode),
|
|
93
|
-
mouseProtocolEncoding: decodeTerminalMouseProtocolEncoding(mouseEncodingCode),
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function concatTerminalPayload(prefix: Uint8Array, payload: Uint8Array): Uint8Array {
|
|
98
|
-
if (prefix.byteLength === 0) {
|
|
99
|
-
return payload;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (payload.byteLength === 0) {
|
|
103
|
-
return prefix;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const merged = new Uint8Array(prefix.byteLength + payload.byteLength);
|
|
107
|
-
merged.set(prefix, 0);
|
|
108
|
-
merged.set(payload, prefix.byteLength);
|
|
109
|
-
return merged;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export function encodeTerminalModesPrefix(modes?: TerminalModeState | null): Uint8Array {
|
|
113
|
-
if (!modes) {
|
|
114
|
-
return new Uint8Array(0);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const sequences = [
|
|
118
|
-
modes.alternateScreen ? "\u001b[?1049h" : "\u001b[?1049l",
|
|
119
|
-
modes.applicationCursor ? "\u001b[?1h" : "\u001b[?1l",
|
|
120
|
-
modes.applicationKeypad ? "\u001b=" : "\u001b>",
|
|
121
|
-
modes.hideCursor ? "\u001b[?25l" : "\u001b[?25h",
|
|
122
|
-
modes.bracketedPaste ? "\u001b[?2004h" : "\u001b[?2004l",
|
|
123
|
-
"\u001b[?1000l\u001b[?1002l\u001b[?1003l\u001b[?1005l\u001b[?1006l\u001b[?1015l",
|
|
124
|
-
];
|
|
125
|
-
|
|
126
|
-
if (modes.mouseProtocolMode === "Press") {
|
|
127
|
-
sequences.push("\u001b[?1000h");
|
|
128
|
-
} else if (modes.mouseProtocolMode === "ButtonMotion") {
|
|
129
|
-
sequences.push("\u001b[?1002h");
|
|
130
|
-
} else if (modes.mouseProtocolMode === "AnyMotion") {
|
|
131
|
-
sequences.push("\u001b[?1003h");
|
|
132
|
-
} else if (modes.mouseProtocolMode === "PressRelease") {
|
|
133
|
-
sequences.push("\u001b[?1000h");
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (modes.mouseProtocolEncoding === "Utf8") {
|
|
137
|
-
sequences.push("\u001b[?1005h");
|
|
138
|
-
} else if (modes.mouseProtocolEncoding === "Sgr") {
|
|
139
|
-
sequences.push("\u001b[?1006h");
|
|
140
|
-
} else if (modes.mouseProtocolEncoding === "Urxvt") {
|
|
141
|
-
sequences.push("\u001b[?1015h");
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return new TextEncoder().encode(sequences.join(""));
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function prependTerminalModes(
|
|
148
|
-
payload: Uint8Array,
|
|
149
|
-
modes?: TerminalModeState | null,
|
|
150
|
-
): Uint8Array {
|
|
151
|
-
return concatTerminalPayload(encodeTerminalModesPrefix(modes), payload);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
export function buildTerminalSnapshotPayload(
|
|
155
|
-
snapshot: string,
|
|
156
|
-
modes?: TerminalModeState | null,
|
|
157
|
-
): Uint8Array {
|
|
158
|
-
return prependTerminalModes(new TextEncoder().encode(normalizeTerminalSnapshot(snapshot)), modes);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export function decodeTerminalBase64Payload(value: string): Uint8Array {
|
|
162
|
-
const normalized = value.trim();
|
|
163
|
-
if (normalized.length === 0) {
|
|
164
|
-
return new Uint8Array(0);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
if (typeof atob === "function") {
|
|
168
|
-
const decoded = atob(normalized);
|
|
169
|
-
const bytes = new Uint8Array(decoded.length);
|
|
170
|
-
for (let index = 0; index < decoded.length; index += 1) {
|
|
171
|
-
bytes[index] = decoded.charCodeAt(index);
|
|
172
|
-
}
|
|
173
|
-
return bytes;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (typeof Buffer !== "undefined") {
|
|
177
|
-
return new Uint8Array(Buffer.from(normalized, "base64"));
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
throw new Error("A base64 decoder is not available in this environment");
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
export function parseTerminalBinaryFrame(buffer: ArrayBuffer): TerminalBinaryFrame {
|
|
184
|
-
const bytes = new Uint8Array(buffer);
|
|
185
|
-
if (bytes.byteLength < TERMINAL_STREAM_FRAME_HEADER_BYTES) {
|
|
186
|
-
throw new Error("Terminal frame was shorter than the stream header");
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
for (let index = 0; index < TERMINAL_FRAME_MAGIC.length; index += 1) {
|
|
190
|
-
if (bytes[index] !== TERMINAL_FRAME_MAGIC[index]) {
|
|
191
|
-
throw new Error("Terminal frame magic did not match the frame protocol");
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const view = new DataView(buffer);
|
|
196
|
-
const version = view.getUint8(4);
|
|
197
|
-
if (version !== 1 && version !== TERMINAL_FRAME_PROTOCOL_VERSION) {
|
|
198
|
-
throw new Error(`Unsupported terminal frame protocol version: ${version}`);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const kind = view.getUint8(5);
|
|
202
|
-
const sequence = Number(view.getBigUint64(6, false));
|
|
203
|
-
if (!Number.isSafeInteger(sequence)) {
|
|
204
|
-
throw new Error("Terminal frame sequence exceeded the safe integer range");
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (kind === TERMINAL_FRAME_KIND_RESTORE) {
|
|
208
|
-
const headerBytes = version >= 2 ? TERMINAL_RESTORE_FRAME_HEADER_BYTES_V2 : TERMINAL_RESTORE_FRAME_HEADER_BYTES_V1;
|
|
209
|
-
if (bytes.byteLength < headerBytes) {
|
|
210
|
-
throw new Error("Terminal restore frame was shorter than the restore header");
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return {
|
|
214
|
-
kind: "restore",
|
|
215
|
-
sequence,
|
|
216
|
-
snapshotVersion: view.getUint8(14),
|
|
217
|
-
reason: decodeTerminalRestoreReason(view.getUint8(15)),
|
|
218
|
-
cols: view.getUint16(16, false),
|
|
219
|
-
rows: view.getUint16(18, false),
|
|
220
|
-
modes: version >= 2
|
|
221
|
-
? decodeTerminalModes(view.getUint8(20), view.getUint8(21), view.getUint8(22))
|
|
222
|
-
: undefined,
|
|
223
|
-
payload: bytes.slice(headerBytes),
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
if (kind === TERMINAL_FRAME_KIND_STREAM) {
|
|
228
|
-
return {
|
|
229
|
-
kind: "stream",
|
|
230
|
-
sequence,
|
|
231
|
-
payload: bytes.slice(TERMINAL_STREAM_FRAME_HEADER_BYTES),
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
throw new Error(`Unsupported terminal frame kind: ${kind}`);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export function normalizeTerminalSnapshot(snapshot: string): string {
|
|
239
|
-
return snapshot.replace(/\r?\n/g, "\r\n");
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
export function stripBrowserTerminalResponses(data: string): string {
|
|
243
|
-
let sanitized = data;
|
|
244
|
-
for (const pattern of BROWSER_TERMINAL_RESPONSE_PATTERNS) {
|
|
245
|
-
sanitized = sanitized.replace(pattern, "");
|
|
246
|
-
}
|
|
247
|
-
return sanitized;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
30
|
export function sanitizeRemoteTerminalSnapshot(snapshot: string): string {
|
|
251
31
|
return snapshot
|
|
252
32
|
.replace(ANSI_ESCAPE_PATTERN, "")
|
|
@@ -1,109 +1,111 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Terminal API utilities.
|
|
3
|
+
* Connection resolution is client-side for the WS URL — the browser builds
|
|
4
|
+
* the ttyd endpoint directly. Authentication still uses a lightweight
|
|
5
|
+
* Next.js proxy to obtain a short-lived terminal token.
|
|
4
6
|
*/
|
|
5
7
|
|
|
6
|
-
import {
|
|
7
|
-
readCachedTerminalConnection,
|
|
8
|
-
storeCachedTerminalConnection,
|
|
9
|
-
} from "./terminalCache";
|
|
10
|
-
import type {
|
|
11
|
-
TerminalConnectionInfo,
|
|
12
|
-
TerminalSnapshot,
|
|
13
|
-
} from "./terminalTypes";
|
|
14
|
-
import type { TerminalModeState } from "../sessionTerminalUtils";
|
|
15
|
-
|
|
16
|
-
export function parseTerminalModes(value: unknown): TerminalModeState | undefined {
|
|
17
|
-
if (!value || typeof value !== "object") {
|
|
18
|
-
return undefined;
|
|
19
|
-
}
|
|
8
|
+
import type { TerminalConnectionInfo } from "./terminalTypes";
|
|
20
9
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
: "None";
|
|
25
|
-
const mouseProtocolEncoding = typeof candidate["mouseProtocolEncoding"] === "string"
|
|
26
|
-
? candidate["mouseProtocolEncoding"]
|
|
27
|
-
: "Default";
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Direct backend URL resolution — no server round-trip
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
28
13
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Resolve the Rust backend origin from the browser.
|
|
16
|
+
*
|
|
17
|
+
* Priority:
|
|
18
|
+
* 1. `NEXT_PUBLIC_CONDUCTOR_BACKEND_URL` (build-time env var)
|
|
19
|
+
* 2. Dev mode heuristic: if the page is served from port 3000 the backend
|
|
20
|
+
* lives on the same hostname at port 4749.
|
|
21
|
+
* 3. Same origin (production: Rust backend serves the dashboard).
|
|
22
|
+
*/
|
|
23
|
+
function resolveBackendOrigin(): string {
|
|
24
|
+
// Build-time env var (NEXT_PUBLIC_ prefix exposes it to the client bundle)
|
|
25
|
+
const envUrl = process.env.NEXT_PUBLIC_CONDUCTOR_BACKEND_URL?.trim();
|
|
26
|
+
if (envUrl) return envUrl;
|
|
39
27
|
|
|
40
|
-
|
|
41
|
-
const cached = readCachedTerminalConnection(sessionId);
|
|
42
|
-
if (cached) {
|
|
43
|
-
return cached;
|
|
44
|
-
}
|
|
28
|
+
if (typeof window === "undefined") return "http://127.0.0.1:4749";
|
|
45
29
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
ptyWsUrl?: string | null;
|
|
52
|
-
interactive?: boolean;
|
|
53
|
-
error?: string;
|
|
54
|
-
}
|
|
55
|
-
| null;
|
|
56
|
-
if (!response.ok) {
|
|
57
|
-
throw new Error(data?.error ?? `Failed to resolve terminal connection: ${response.status}`);
|
|
30
|
+
const { protocol, hostname, port } = window.location;
|
|
31
|
+
|
|
32
|
+
// Dev mode: Next.js dev server on :3000, Rust backend on :4749
|
|
33
|
+
if (port === "3000") {
|
|
34
|
+
return `${protocol}//${hostname}:4749`;
|
|
58
35
|
}
|
|
59
36
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
typeof data?.ptyWsUrl === "string" && data.ptyWsUrl.trim().length > 0
|
|
63
|
-
? data.ptyWsUrl.trim()
|
|
64
|
-
: null,
|
|
65
|
-
interactive: data?.interactive === true,
|
|
66
|
-
};
|
|
67
|
-
storeCachedTerminalConnection(sessionId, connection);
|
|
68
|
-
return connection;
|
|
37
|
+
// Production / standalone: backend serves dashboard at the same origin
|
|
38
|
+
return window.location.origin;
|
|
69
39
|
}
|
|
70
40
|
|
|
71
|
-
|
|
72
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Fetch a terminal token via the Next.js proxy (which handles auth).
|
|
43
|
+
* The token is required by the Rust backend WebSocket endpoint.
|
|
44
|
+
* Fail closed on proxy or backend errors so the browser does not attempt an
|
|
45
|
+
* unauthenticated ttyd websocket with a missing or stale token.
|
|
46
|
+
*/
|
|
47
|
+
type TerminalTokenResult =
|
|
48
|
+
| { interactive: true; token: string | null }
|
|
49
|
+
| { interactive: false; token: null };
|
|
50
|
+
|
|
51
|
+
async function fetchTerminalToken(sessionId: string): Promise<TerminalTokenResult> {
|
|
52
|
+
const res = await fetch(`/api/sessions/${encodeURIComponent(sessionId)}/terminal/token`, {
|
|
73
53
|
cache: "no-store",
|
|
74
54
|
});
|
|
75
|
-
const data = (await
|
|
76
|
-
| {
|
|
55
|
+
const data = (await res.json().catch(() => null)) as
|
|
56
|
+
| { token?: string; required?: boolean; error?: string }
|
|
77
57
|
| null;
|
|
78
|
-
|
|
79
|
-
|
|
58
|
+
|
|
59
|
+
if (res.status === 401 || res.status === 403) {
|
|
60
|
+
return {
|
|
61
|
+
interactive: false,
|
|
62
|
+
token: null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!res.ok) {
|
|
67
|
+
throw new Error(data?.error ?? `Failed to resolve terminal token: ${res.status}`);
|
|
80
68
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
69
|
+
|
|
70
|
+
if (data?.required !== true) {
|
|
71
|
+
return {
|
|
72
|
+
interactive: true,
|
|
73
|
+
token: null,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const token = typeof data?.token === "string" ? data.token.trim() : "";
|
|
78
|
+
if (token.length === 0) {
|
|
79
|
+
throw new Error("Terminal token response did not include a ttyd token");
|
|
80
|
+
}
|
|
81
|
+
|
|
84
82
|
return {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
source: typeof data?.source === "string" ? data.source : "empty",
|
|
88
|
-
live: data?.live === true,
|
|
89
|
-
restored: data?.restored === true,
|
|
90
|
-
sequence: typeof data?.sequence === "number" && Number.isSafeInteger(data.sequence)
|
|
91
|
-
? data.sequence
|
|
92
|
-
: null,
|
|
93
|
-
modes: parseTerminalModes(data?.modes),
|
|
83
|
+
interactive: true,
|
|
84
|
+
token,
|
|
94
85
|
};
|
|
95
86
|
}
|
|
96
87
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Build the direct ttyd WebSocket URL for a session.
|
|
90
|
+
*
|
|
91
|
+
* 1. Fetch a short-lived token via Next.js proxy (one HTTP call, handles auth).
|
|
92
|
+
* 2. Construct the WebSocket URL pointing directly at the Rust backend.
|
|
93
|
+
*
|
|
94
|
+
* The WebSocket stream itself is direct — no middleware in the data path.
|
|
95
|
+
*/
|
|
96
|
+
export async function resolveTerminalConnection(sessionId: string): Promise<TerminalConnectionInfo> {
|
|
97
|
+
const origin = resolveBackendOrigin();
|
|
98
|
+
const wsProtocol = origin.startsWith("https") ? "wss:" : "ws:";
|
|
99
|
+
const url = new URL(origin);
|
|
100
|
+
const auth = await fetchTerminalToken(sessionId);
|
|
101
|
+
if (!auth.interactive) {
|
|
102
|
+
return {
|
|
103
|
+
ptyWsUrl: null,
|
|
104
|
+
interactive: false,
|
|
105
|
+
};
|
|
103
106
|
}
|
|
107
|
+
const tokenParam = auth.token ? `&token=${encodeURIComponent(auth.token)}` : "";
|
|
108
|
+
const ptyWsUrl = `${wsProtocol}//${url.host}/api/sessions/${encodeURIComponent(sessionId)}/terminal/ws?protocol=ttyd${tokenParam}`;
|
|
104
109
|
|
|
105
|
-
|
|
106
|
-
return typeof data?.status === "string" && data.status.trim().length > 0
|
|
107
|
-
? data.status.trim()
|
|
108
|
-
: null;
|
|
110
|
+
return { ptyWsUrl, interactive: true };
|
|
109
111
|
}
|
|
@@ -1,26 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Module-level
|
|
3
|
-
* snapshots, and UI state.
|
|
2
|
+
* Module-level cache and TTL logic for terminal UI state.
|
|
4
3
|
*/
|
|
5
4
|
|
|
6
5
|
import {
|
|
7
|
-
TERMINAL_CONNECTION_CACHE_MAX_TTL_MS,
|
|
8
|
-
TERMINAL_CONNECTION_CACHE_MAX_ENTRIES,
|
|
9
|
-
TERMINAL_SNAPSHOT_CACHE_MAX_ENTRIES,
|
|
10
6
|
TERMINAL_UI_STATE_CACHE_MAX_ENTRIES,
|
|
11
|
-
TERMINAL_SNAPSHOT_CACHE_MAX_AGE_MS,
|
|
12
7
|
TERMINAL_UI_STATE_CACHE_MAX_AGE_MS,
|
|
13
8
|
} from "./terminalConstants";
|
|
14
|
-
import type {
|
|
15
|
-
TerminalConnectionInfo,
|
|
16
|
-
TerminalSnapshot,
|
|
17
|
-
CachedTerminalConnection,
|
|
18
|
-
CachedTerminalSnapshot,
|
|
19
|
-
CachedTerminalUiState,
|
|
20
|
-
} from "./terminalTypes";
|
|
9
|
+
import type { CachedTerminalUiState } from "./terminalTypes";
|
|
21
10
|
|
|
22
|
-
export const terminalConnectionCache = new Map<string, CachedTerminalConnection>();
|
|
23
|
-
export const terminalSnapshotCache = new Map<string, CachedTerminalSnapshot>();
|
|
24
11
|
export const terminalUiStateCache = new Map<string, CachedTerminalUiState>();
|
|
25
12
|
|
|
26
13
|
export function trimTerminalCache(cache: Map<string, unknown>, maxEntries: number): void {
|
|
@@ -33,64 +20,6 @@ export function trimTerminalCache(cache: Map<string, unknown>, maxEntries: numbe
|
|
|
33
20
|
}
|
|
34
21
|
}
|
|
35
22
|
|
|
36
|
-
export function readCachedTerminalConnection(sessionId: string): TerminalConnectionInfo | null {
|
|
37
|
-
const cached = terminalConnectionCache.get(sessionId);
|
|
38
|
-
if (!cached) {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
if (cached.expiresAt <= Date.now()) {
|
|
42
|
-
terminalConnectionCache.delete(sessionId);
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
return cached.value;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function storeCachedTerminalConnection(sessionId: string, value: TerminalConnectionInfo): void {
|
|
49
|
-
terminalConnectionCache.delete(sessionId);
|
|
50
|
-
terminalConnectionCache.set(sessionId, {
|
|
51
|
-
value,
|
|
52
|
-
expiresAt: Date.now() + TERMINAL_CONNECTION_CACHE_MAX_TTL_MS,
|
|
53
|
-
});
|
|
54
|
-
trimTerminalCache(terminalConnectionCache, TERMINAL_CONNECTION_CACHE_MAX_ENTRIES);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function clearCachedTerminalConnection(sessionId: string): void {
|
|
58
|
-
terminalConnectionCache.delete(sessionId);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function readCachedTerminalSnapshot(sessionId: string): TerminalSnapshot | null {
|
|
62
|
-
const cached = terminalSnapshotCache.get(sessionId);
|
|
63
|
-
if (!cached) {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
if (Date.now() - cached.updatedAt > TERMINAL_SNAPSHOT_CACHE_MAX_AGE_MS) {
|
|
67
|
-
terminalSnapshotCache.delete(sessionId);
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
return {
|
|
71
|
-
snapshot: cached.snapshot,
|
|
72
|
-
transcript: cached.transcript,
|
|
73
|
-
source: cached.source,
|
|
74
|
-
live: cached.live,
|
|
75
|
-
restored: cached.restored,
|
|
76
|
-
sequence: cached.sequence,
|
|
77
|
-
modes: cached.modes,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function storeCachedTerminalSnapshot(sessionId: string, snapshot: TerminalSnapshot): void {
|
|
82
|
-
terminalSnapshotCache.delete(sessionId);
|
|
83
|
-
terminalSnapshotCache.set(sessionId, {
|
|
84
|
-
...snapshot,
|
|
85
|
-
updatedAt: Date.now(),
|
|
86
|
-
});
|
|
87
|
-
trimTerminalCache(terminalSnapshotCache, TERMINAL_SNAPSHOT_CACHE_MAX_ENTRIES);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function clearCachedTerminalSnapshot(sessionId: string): void {
|
|
91
|
-
terminalSnapshotCache.delete(sessionId);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
23
|
export function readCachedTerminalUiState(sessionId: string): CachedTerminalUiState | null {
|
|
95
24
|
const cached = terminalUiStateCache.get(sessionId);
|
|
96
25
|
if (!cached) {
|