conductor-oss 0.7.1 → 0.9.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/README.md +173 -134
- package/dist/backend.d.ts.map +1 -1
- package/dist/backend.js +18 -2
- package/dist/backend.js.map +1 -1
- package/dist/commands/dashboard.d.ts.map +1 -1
- package/dist/commands/dashboard.js +13 -7
- package/dist/commands/dashboard.js.map +1 -1
- package/node_modules/@conductor-oss/core/dist/config.d.ts.map +1 -1
- package/node_modules/@conductor-oss/core/dist/config.js +6 -1
- package/node_modules/@conductor-oss/core/dist/config.js.map +1 -1
- package/package.json +8 -6
- package/web/.next/standalone/packages/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/packages/web/.next/app-path-routes-manifest.json +2 -0
- package/web/.next/standalone/packages/web/.next/build-manifest.json +7 -7
- package/web/.next/standalone/packages/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/packages/web/.next/routes-manifest.json +44 -1
- package/web/.next/standalone/packages/web/.next/server/app/_global-error/page/build-manifest.json +5 -5
- package/web/.next/standalone/packages/web/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- 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 +7 -7
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/web/.next/standalone/packages/web/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- 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/build-manifest.json +5 -5
- 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 +2 -2
- 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 +11 -11
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_full.segment.rsc +11 -11
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_index.segment.rsc +6 -6
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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]/feed/stream/route.js +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feed/stream/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/feedback/route.js +2 -2
- 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 +2 -2
- 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 +2 -2
- 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]/keys/route.js +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/keys/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/kill/route.js +2 -2
- 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 +2 -2
- 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]/output/stream/route.js +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/output/stream/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 +2 -2
- 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 +2 -2
- 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]/send/route.js +2 -2
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/send/route.js.nft.json +1 -1
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route/app-paths-manifest.json +3 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route/build-manifest.json +11 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route/server-reference-manifest.json +4 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route.js +10 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route.js.map +5 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route.js.nft.json +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/connection/route_client-reference-manifest.js +2 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/snapshot/route/app-paths-manifest.json +3 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/snapshot/route/build-manifest.json +11 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/snapshot/route/server-reference-manifest.json +4 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/snapshot/route.js +10 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/snapshot/route.js.map +5 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/snapshot/route.js.nft.json +1 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/[id]/terminal/snapshot/route_client-reference-manifest.js +2 -0
- package/web/.next/standalone/packages/web/.next/server/app/api/sessions/route.js +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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/build-manifest.json +5 -5
- package/web/.next/standalone/packages/web/.next/server/app/page/react-loadable-manifest.json +4 -4
- 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 +2 -2
- 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/build-manifest.json +5 -5
- 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 +2 -2
- 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/build-manifest.json +5 -5
- 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/build-manifest.json +5 -5
- package/web/.next/standalone/packages/web/.next/server/app/unlock/page/server-reference-manifest.json +14 -14
- 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 +2 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/26076_server_app_api_sessions_[id]_terminal_connection_route_actions_46c114ee.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/26076_server_app_api_sessions_[id]_terminal_snapshot_route_actions_cfb4de43.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/730ea_web__next-internal_server_app_api_sessions_[id]_restore_route_actions_41a4c356.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__b716459f._.js → [root-of-the-server]__08556fc3._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__624bcdc9._.js → [root-of-the-server]__0e496df1._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__9bf61231._.js → [root-of-the-server]__115b433b._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__70929198._.js → [root-of-the-server]__120a0868._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__17d710ef._.js → [root-of-the-server]__1a623333._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__262e987e._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__31053ac2._.js → [root-of-the-server]__2713bac9._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__8c576b6a._.js → [root-of-the-server]__2798ac7c._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__747e6415._.js → [root-of-the-server]__27b2bd14._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__a4b1a94c._.js → [root-of-the-server]__29d94573._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__732fc06e._.js → [root-of-the-server]__2b59cba9._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__2ce39d51._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__3e507276._.js → [root-of-the-server]__2fea4a4c._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__59635ca5._.js → [root-of-the-server]__36559d88._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__f0ec1021._.js → [root-of-the-server]__4117784b._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__543bc377._.js → [root-of-the-server]__43b35d39._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__ba70a88e._.js → [root-of-the-server]__444bf146._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__fd0a681b._.js → [root-of-the-server]__45483f4b._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__98f4a7bd._.js → [root-of-the-server]__4644a89e._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__4c78886c._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__e7aaee2d._.js → [root-of-the-server]__4cea5dca._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__33494588._.js → [root-of-the-server]__575c7392._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__eae97345._.js → [root-of-the-server]__57605af7._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__be233a9f._.js → [root-of-the-server]__57c8ca1a._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__5e2b35cd._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__8ace49d1._.js → [root-of-the-server]__5f5433df._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__6313c91e._.js +3 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__3dc4c761._.js → [root-of-the-server]__6a8b5dc7._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__3318d8a1._.js → [root-of-the-server]__717081d9._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__ae73aa49._.js → [root-of-the-server]__75668566._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__b4039db5._.js → [root-of-the-server]__7a6210dc._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__34e636e5._.js → [root-of-the-server]__7ca5b93b._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__b53b70e7._.js → [root-of-the-server]__8462ddf1._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__3937a996._.js → [root-of-the-server]__9e363e9c._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__4c5f7cab._.js → [root-of-the-server]__a0467c5b._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__9576223c._.js → [root-of-the-server]__a8d68307._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__82e86bb6._.js → [root-of-the-server]__ac79a67b._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__bcd0c846._.js → [root-of-the-server]__af5be1d9._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__b3cd93ca._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__540ebc7f._.js → [root-of-the-server]__b7314f2a._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__bb2675cd._.js → [root-of-the-server]__bcbc6330._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__fe4c1384._.js → [root-of-the-server]__bfbdd808._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__b00db558._.js → [root-of-the-server]__c205eff4._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__c455995a._.js → [root-of-the-server]__c39ceb71._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__c9cb9ac6._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__cff9ddef._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__7c87a52f._.js → [root-of-the-server]__d65b8403._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__eb6e6bb9._.js → [root-of-the-server]__d7b9cb55._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__53daf5c6._.js → [root-of-the-server]__df103a4a._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/[root-of-the-server]__ea845f9f._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__8ee7749b._.js → [root-of-the-server]__f5a16619._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__9940de77._.js → [root-of-the-server]__f62d8a1f._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__5df70a62._.js → [root-of-the-server]__f7c7ed71._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__520aa408._.js → [root-of-the-server]__fa5bbdc8._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/{[root-of-the-server]__e385846c._.js → [root-of-the-server]__fed9223f._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/_2c837d66._.js +5 -5
- package/web/.next/standalone/packages/web/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_eaad1f33.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__000b8c99._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__4f387f9d._.js → [root-of-the-server]__10a850c6._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__7829c78d._.js → [root-of-the-server]__17f5cb6a._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__29d8d063._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__3ea76517._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__99387ae7._.js → [root-of-the-server]__6647f7ec._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__a509d17d._.js → [root-of-the-server]__9f45b36b._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{[root-of-the-server]__bc8d015f._.js → [root-of-the-server]__f8f50c0b._.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/_230c0c14._.js +4 -4
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_2b5578a1._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{_b6d31783._.js → _532f707d._.js} +3 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_5571204d._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_69e05fca._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_6cfd06c2._.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/{_a4a4deb7._.js → _9e7585e3._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_b214b154._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_b8358e63._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_c0f0e227._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/{_8982bbf3._.js → _de3b7194._.js} +2 -2
- 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_@clerk_nextjs_dist_esm_app-router_743f164d._.js → node_modules_@clerk_nextjs_dist_esm_app-router_a9e633d8._.js} +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_@clerk_nextjs_dist_esm_app-router_f33d83e6._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_@radix-ui_d03fdd57._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_@xterm_addon-fit_lib_addon-fit_mjs_9b7cb17b._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_@xterm_addon-search_lib_addon-search_mjs_8d69d9d7._.js +11 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_@xterm_xterm_lib_xterm_mjs_a1a7b9e9._.js +20 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_afb6e107._.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_refresh-cw_50f1c1e7.js +3 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_next_dist_2df23979._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_cd51dad4.js +2 -2
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/packages_web_src_components_board_WorkspaceKanban_tsx_735b7999._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/packages_web_src_components_sessions_SessionDetail_tsx_5fcad270._.js +6 -0
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/packages_web_src_features_dashboard_DashboardClient_tsx_81ae42b0._.js +1 -1
- package/web/.next/standalone/packages/web/.next/server/functions-config-manifest.json +3 -1
- package/web/.next/standalone/packages/web/.next/server/middleware-build-manifest.js +5 -5
- 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 +15 -15
- package/web/.next/standalone/packages/web/.next/static/chunks/07be250784a6a689.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/0866f5c380851a16.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/0cdc18649f440c71.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/0f7eb6d5a59ee3ae.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/144b356fe7daff8d.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/{c4c79d5d0b280aeb.js → 2f236954d6a65e12.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/3cdf839644f79d43.js +18 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/5a4c4d4d5f30829b.css +3 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/6850a6cda159c98d.js +1 -0
- package/web/.next/{static/chunks/06bdd070b8d25946.js → standalone/packages/web/.next/static/chunks/69be39811437728d.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/6cec31da5f555e99.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/70d1e7a526f0f4e2.js +9 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/{ba2aa8b54e912820.js → 723acbe92d3f9e7e.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/739c6f71243d76d8.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/a6ec1ab37eb7b410.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/af8bfb72187b7cbf.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/b86b8884ddf84717.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/c1b8a2d2c623a0dc.js +6 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/c993a1a4204fce88.js +4 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/ca3e38b4495a3d39.js +1 -0
- package/web/.next/standalone/packages/web/.next/static/chunks/{45bd2451c2b0790c.js → caf02f8136b16992.js} +2 -2
- package/web/.next/standalone/packages/web/.next/static/chunks/d4269c59429734ad.js +1 -0
- package/web/.next/{static/chunks/28eac764d6544827.js → standalone/packages/web/.next/static/chunks/e5bcec03f80af56a.js} +1 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/{turbopack-49f4119854e8206e.js → turbopack-26870d017b23fcf0.js} +1 -1
- package/web/.next/standalone/packages/web/next.config.ts +16 -0
- package/web/.next/standalone/packages/web/package.json +3 -1
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/terminal/connection/route.ts +64 -0
- package/web/.next/standalone/packages/web/src/app/api/sessions/[id]/terminal/snapshot/route.ts +14 -0
- package/web/.next/standalone/packages/web/src/app/globals.css +12 -4
- package/web/.next/standalone/packages/web/src/components/Dashboard.tsx +1 -5
- package/web/.next/standalone/packages/web/src/components/TerminalView.tsx +528 -100
- package/web/.next/standalone/packages/web/src/components/board/WorkspaceKanban.tsx +3 -3
- package/web/.next/standalone/packages/web/src/components/layout/AppShell.tsx +3 -3
- package/web/.next/standalone/packages/web/src/components/layout/Sidebar.tsx +29 -18
- package/web/.next/standalone/packages/web/src/components/layout/TopBar.tsx +3 -3
- package/web/.next/standalone/packages/web/src/components/sessions/ChatPanel.tsx +61 -5
- package/web/.next/standalone/packages/web/src/components/sessions/SessionDetail.tsx +99 -46
- package/web/.next/standalone/packages/web/src/components/sessions/SessionPreview.tsx +231 -233
- package/web/.next/standalone/packages/web/src/components/sessions/SessionTerminal.tsx +1212 -0
- package/web/.next/standalone/packages/web/src/components/sessions/terminalInsert.ts +6 -0
- package/web/.next/standalone/packages/web/src/components/terminal/xtermTheme.ts +70 -0
- package/web/.next/standalone/packages/web/src/components/ui/Tabs.tsx +2 -2
- package/web/.next/standalone/packages/web/src/features/dashboard/DashboardClient.tsx +104 -31
- package/web/.next/standalone/packages/web/src/features/sessions/SessionPageClient.tsx +2 -2
- package/web/.next/standalone/packages/web/src/lib/devPreviewBrowser.ts +15 -3
- package/web/.next/static/chunks/07be250784a6a689.js +1 -0
- package/web/.next/static/chunks/0866f5c380851a16.js +1 -0
- package/web/.next/static/chunks/0cdc18649f440c71.js +1 -0
- package/web/.next/static/chunks/0f7eb6d5a59ee3ae.js +1 -0
- package/web/.next/static/chunks/144b356fe7daff8d.js +1 -0
- package/web/.next/static/chunks/{c4c79d5d0b280aeb.js → 2f236954d6a65e12.js} +1 -1
- package/web/.next/static/chunks/3cdf839644f79d43.js +18 -0
- package/web/.next/static/chunks/5a4c4d4d5f30829b.css +3 -0
- package/web/.next/static/chunks/6850a6cda159c98d.js +1 -0
- package/web/.next/{standalone/packages/web/.next/static/chunks/06bdd070b8d25946.js → static/chunks/69be39811437728d.js} +1 -1
- package/web/.next/static/chunks/6cec31da5f555e99.js +1 -0
- package/web/.next/static/chunks/70d1e7a526f0f4e2.js +9 -0
- package/web/.next/static/chunks/{ba2aa8b54e912820.js → 723acbe92d3f9e7e.js} +1 -1
- package/web/.next/static/chunks/739c6f71243d76d8.js +1 -0
- package/web/.next/static/chunks/a6ec1ab37eb7b410.js +1 -0
- package/web/.next/static/chunks/af8bfb72187b7cbf.js +1 -0
- package/web/.next/static/chunks/b86b8884ddf84717.js +1 -0
- package/web/.next/static/chunks/c1b8a2d2c623a0dc.js +6 -0
- package/web/.next/static/chunks/c993a1a4204fce88.js +4 -0
- package/web/.next/static/chunks/ca3e38b4495a3d39.js +1 -0
- package/web/.next/static/chunks/{45bd2451c2b0790c.js → caf02f8136b16992.js} +2 -2
- package/web/.next/static/chunks/d4269c59429734ad.js +1 -0
- package/web/.next/{standalone/packages/web/.next/static/chunks/28eac764d6544827.js → static/chunks/e5bcec03f80af56a.js} +1 -1
- package/web/.next/static/chunks/{turbopack-49f4119854e8206e.js → turbopack-26870d017b23fcf0.js} +1 -1
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__29091976._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__784e6aef._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__b388693f._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/[root-of-the-server]__d1efcbf0._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/_e1c18705._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_@clerk_nextjs_dist_esm_app-router_2a090a71._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_@radix-ui_02f0d3f0._.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/node_modules_lucide-react_dist_esm_icons_message-square_2e76b8d9.js +0 -3
- package/web/.next/standalone/packages/web/.next/server/chunks/ssr/packages_web_src_components_ui_Tooltip_tsx_6becc8ca._.js +0 -3
- package/web/.next/standalone/packages/web/.next/static/chunks/07f3b9a104ce0ff4.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/1004422d31074d62.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/25afa19789883705.js +0 -6
- package/web/.next/standalone/packages/web/.next/static/chunks/2bc11b604b131190.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/30ababddac1b82dc.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/64f0033534ca1ad3.css +0 -3
- package/web/.next/standalone/packages/web/.next/static/chunks/902a6ba5837e1e57.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/a28bcda8dd6b68ee.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/aabc80195233b4da.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/b6069d0eb07a978f.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/c2caa064748bb0b5.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/c5f8e486166298c2.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/d6a81d2f8b98b4be.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/dfa8ef24e636ca14.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/e9d0e95bbaa0f4fb.js +0 -1
- package/web/.next/standalone/packages/web/.next/static/chunks/ebaa0c535c4135f1.js +0 -1
- package/web/.next/static/chunks/07f3b9a104ce0ff4.js +0 -1
- package/web/.next/static/chunks/1004422d31074d62.js +0 -1
- package/web/.next/static/chunks/25afa19789883705.js +0 -6
- package/web/.next/static/chunks/2bc11b604b131190.js +0 -1
- package/web/.next/static/chunks/30ababddac1b82dc.js +0 -1
- package/web/.next/static/chunks/64f0033534ca1ad3.css +0 -3
- package/web/.next/static/chunks/902a6ba5837e1e57.js +0 -1
- package/web/.next/static/chunks/a28bcda8dd6b68ee.js +0 -1
- package/web/.next/static/chunks/aabc80195233b4da.js +0 -1
- package/web/.next/static/chunks/b6069d0eb07a978f.js +0 -1
- package/web/.next/static/chunks/c2caa064748bb0b5.js +0 -1
- package/web/.next/static/chunks/c5f8e486166298c2.js +0 -1
- package/web/.next/static/chunks/d6a81d2f8b98b4be.js +0 -1
- package/web/.next/static/chunks/dfa8ef24e636ca14.js +0 -1
- package/web/.next/static/chunks/e9d0e95bbaa0f4fb.js +0 -1
- package/web/.next/static/chunks/ebaa0c535c4135f1.js +0 -1
- /package/web/.next/standalone/packages/web/.next/static/{EKHFeqSnbpFbCnV8AGVjm → dzgjDKuem6HLwWyK0KMG4}/_buildManifest.js +0 -0
- /package/web/.next/standalone/packages/web/.next/static/{EKHFeqSnbpFbCnV8AGVjm → dzgjDKuem6HLwWyK0KMG4}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/packages/web/.next/static/{EKHFeqSnbpFbCnV8AGVjm → dzgjDKuem6HLwWyK0KMG4}/_ssgManifest.js +0 -0
- /package/web/.next/static/{EKHFeqSnbpFbCnV8AGVjm → dzgjDKuem6HLwWyK0KMG4}/_buildManifest.js +0 -0
- /package/web/.next/static/{EKHFeqSnbpFbCnV8AGVjm → dzgjDKuem6HLwWyK0KMG4}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{EKHFeqSnbpFbCnV8AGVjm → dzgjDKuem6HLwWyK0KMG4}/_ssgManifest.js +0 -0
|
@@ -31,11 +31,14 @@ import { Card, CardContent, CardHeader } from "@/components/ui/Card";
|
|
|
31
31
|
import { ScrollArea } from "@/components/ui/ScrollArea";
|
|
32
32
|
import { cn } from "@/lib/cn";
|
|
33
33
|
import type {
|
|
34
|
+
PreviewElementSelection,
|
|
34
35
|
PreviewCommandRequest,
|
|
35
36
|
PreviewDomNode,
|
|
36
37
|
PreviewDomResponse,
|
|
38
|
+
PreviewLogEntry,
|
|
37
39
|
PreviewStatusResponse,
|
|
38
40
|
} from "@/lib/previewTypes";
|
|
41
|
+
import type { TerminalInsertRequest } from "./terminalInsert";
|
|
39
42
|
|
|
40
43
|
const STATUS_POLL_INTERVAL_MS = 4_000;
|
|
41
44
|
const AUTO_CONNECT_RETRY_MS = 5_000;
|
|
@@ -62,7 +65,8 @@ const PREVIEW_SPECIAL_KEYS = new Map<string, string>([
|
|
|
62
65
|
|
|
63
66
|
interface SessionPreviewProps {
|
|
64
67
|
sessionId: string;
|
|
65
|
-
|
|
68
|
+
onQueueTerminalInsert: (request: Omit<TerminalInsertRequest, "nonce">) => void;
|
|
69
|
+
onConnectionChange?: (connected: boolean) => void;
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
type PreviewSendTarget = "selection" | "console" | "network";
|
|
@@ -88,57 +92,106 @@ function truncate(value: string, max = 120): string {
|
|
|
88
92
|
return `${value.slice(0, max - 1)}…`;
|
|
89
93
|
}
|
|
90
94
|
|
|
91
|
-
function
|
|
92
|
-
|
|
93
|
-
y: number,
|
|
94
|
-
bounds: { x: number; y: number; width: number; height: number },
|
|
95
|
-
): boolean {
|
|
96
|
-
return x >= bounds.x
|
|
97
|
-
&& x <= bounds.x + bounds.width
|
|
98
|
-
&& y >= bounds.y
|
|
99
|
-
&& y <= bounds.y + bounds.height;
|
|
95
|
+
function normalizeWhitespace(value: string | null | undefined): string {
|
|
96
|
+
return (value ?? "").replace(/\s+/g, " ").trim();
|
|
100
97
|
}
|
|
101
98
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
for (const file of files) {
|
|
108
|
-
formData.append("files", file);
|
|
109
|
-
}
|
|
99
|
+
function quoteInline(value: string | null | undefined, max = 180): string | null {
|
|
100
|
+
const normalized = truncate(normalizeWhitespace(value), max);
|
|
101
|
+
if (!normalized) return null;
|
|
102
|
+
return `"${normalized.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
103
|
+
}
|
|
110
104
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
105
|
+
function buildInlineInsert(parts: Array<string | null | undefined>): string {
|
|
106
|
+
return parts
|
|
107
|
+
.map((part) => part?.trim())
|
|
108
|
+
.filter((part): part is string => Boolean(part))
|
|
109
|
+
.join("; ");
|
|
110
|
+
}
|
|
115
111
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
112
|
+
function buildDraftInsert(title: string, lines: Array<string | null | undefined>): string {
|
|
113
|
+
return [
|
|
114
|
+
`[${title}]`,
|
|
115
|
+
...lines
|
|
116
|
+
.map((line) => line?.trim())
|
|
117
|
+
.filter((line): line is string => Boolean(line)),
|
|
118
|
+
].join("\n");
|
|
119
|
+
}
|
|
119
120
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
function buildSelectionInsert(
|
|
122
|
+
selection: PreviewElementSelection,
|
|
123
|
+
currentUrl: string | null,
|
|
124
|
+
): Omit<TerminalInsertRequest, "nonce"> {
|
|
125
|
+
return {
|
|
126
|
+
inlineText: buildInlineInsert([
|
|
127
|
+
"[Browser selection]",
|
|
128
|
+
`selector=${quoteInline(selection.selector, 220)}`,
|
|
129
|
+
`tag=${selection.tag}`,
|
|
130
|
+
selection.role ? `role=${selection.role}` : null,
|
|
131
|
+
selection.name ? `name=${quoteInline(selection.name, 140)}` : null,
|
|
132
|
+
selection.text ? `text=${quoteInline(selection.text, 180)}` : null,
|
|
133
|
+
selection.frameName ? `frame=${quoteInline(selection.frameName, 120)}` : null,
|
|
134
|
+
currentUrl ? `page=${quoteInline(currentUrl, 220)}` : null,
|
|
135
|
+
]),
|
|
136
|
+
draftText: buildDraftInsert("Browser selection", [
|
|
137
|
+
currentUrl ? `Page: ${currentUrl}` : null,
|
|
138
|
+
`Frame: ${selection.frameName} (${selection.frameUrl})`,
|
|
139
|
+
`Selector: ${selection.selector}`,
|
|
140
|
+
`Tag: ${selection.tag}`,
|
|
141
|
+
selection.role ? `Role: ${selection.role}` : null,
|
|
142
|
+
selection.name ? `Name: ${selection.name}` : null,
|
|
143
|
+
selection.text ? `Text: ${selection.text}` : null,
|
|
144
|
+
selection.htmlPreview ? `HTML preview: ${selection.htmlPreview}` : null,
|
|
145
|
+
]),
|
|
146
|
+
successMessage: "Queued the selected element for terminal input.",
|
|
147
|
+
};
|
|
148
|
+
}
|
|
123
149
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
150
|
+
function buildLogInsert(
|
|
151
|
+
kind: "console" | "network",
|
|
152
|
+
entries: PreviewLogEntry[],
|
|
153
|
+
currentUrl: string | null,
|
|
154
|
+
selectedElement: PreviewElementSelection | null,
|
|
155
|
+
): Omit<TerminalInsertRequest, "nonce"> {
|
|
156
|
+
const title = kind === "console" ? "Browser console logs" : "Browser network logs";
|
|
157
|
+
const recentEntries = entries.slice(kind === "console" ? -8 : -10);
|
|
158
|
+
const inlineEntries = recentEntries.map((entry) => {
|
|
159
|
+
const baseParts = [
|
|
160
|
+
entry.level,
|
|
161
|
+
quoteInline(entry.message, 120),
|
|
130
162
|
];
|
|
131
|
-
|
|
163
|
+
if (kind === "network") {
|
|
164
|
+
baseParts.unshift(entry.method ?? "GET");
|
|
165
|
+
baseParts.push(typeof entry.status === "number" ? String(entry.status) : null);
|
|
166
|
+
baseParts.push(entry.url ? quoteInline(entry.url, 120) : null);
|
|
167
|
+
}
|
|
168
|
+
return baseParts.filter(Boolean).join(" ");
|
|
132
169
|
});
|
|
133
170
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
171
|
+
return {
|
|
172
|
+
inlineText: buildInlineInsert([
|
|
173
|
+
kind === "console" ? "[Browser console]" : "[Browser network]",
|
|
174
|
+
currentUrl ? `page=${quoteInline(currentUrl, 220)}` : null,
|
|
175
|
+
selectedElement ? `selected=${quoteInline(selectedElement.selector, 180)}` : null,
|
|
176
|
+
`entries=${quoteInline(inlineEntries.join(" | "), 520)}`,
|
|
177
|
+
]),
|
|
178
|
+
draftText: buildDraftInsert(title, [
|
|
179
|
+
currentUrl ? `Page: ${currentUrl}` : null,
|
|
180
|
+
selectedElement ? `Selected element: ${selectedElement.selector}` : null,
|
|
181
|
+
...recentEntries.map((entry) => {
|
|
182
|
+
if (kind === "console") {
|
|
183
|
+
return `- ${formatTime(entry.timestamp)} ${entry.level}: ${entry.message}`;
|
|
184
|
+
}
|
|
185
|
+
return `- ${formatTime(entry.timestamp)} ${entry.method ?? "GET"} ${entry.status ?? "-"} ${entry.url ?? entry.message}`;
|
|
186
|
+
}),
|
|
187
|
+
]),
|
|
188
|
+
successMessage: kind === "console"
|
|
189
|
+
? "Queued recent console logs for terminal input."
|
|
190
|
+
: "Queued recent network logs for terminal input.",
|
|
191
|
+
};
|
|
139
192
|
}
|
|
140
193
|
|
|
141
|
-
export function SessionPreview({ sessionId,
|
|
194
|
+
export function SessionPreview({ sessionId, onQueueTerminalInsert, onConnectionChange }: SessionPreviewProps) {
|
|
142
195
|
const [status, setStatus] = useState<PreviewStatusResponse | null>(null);
|
|
143
196
|
const [domNodes, setDomNodes] = useState<PreviewDomNode[]>([]);
|
|
144
197
|
const [domLoading, setDomLoading] = useState(false);
|
|
@@ -152,7 +205,6 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
152
205
|
const [previewMode, setPreviewMode] = useState<PreviewInteractionMode>("navigate");
|
|
153
206
|
const [selectionComposer, setSelectionComposer] = useState<SelectionComposerState | null>(null);
|
|
154
207
|
const [urlInput, setUrlInput] = useState("");
|
|
155
|
-
const [instruction, setInstruction] = useState("");
|
|
156
208
|
const [imageMetrics, setImageMetrics] = useState({
|
|
157
209
|
naturalWidth: 0,
|
|
158
210
|
naturalHeight: 0,
|
|
@@ -163,7 +215,6 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
163
215
|
const autoConnectRef = useRef<{ candidate: string; attemptedAt: number } | null>(null);
|
|
164
216
|
const previewCommandQueueRef = useRef<Promise<void>>(Promise.resolve());
|
|
165
217
|
const imageRef = useRef<HTMLImageElement | null>(null);
|
|
166
|
-
const instructionRef = useRef<HTMLTextAreaElement | null>(null);
|
|
167
218
|
const previewSurfaceRef = useRef<HTMLDivElement | null>(null);
|
|
168
219
|
|
|
169
220
|
const loadStatus = useCallback(async () => {
|
|
@@ -191,7 +242,7 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
191
242
|
});
|
|
192
243
|
}, [sessionId, status?.currentUrl]);
|
|
193
244
|
|
|
194
|
-
const runCommand = useCallback(async (command: PreviewCommandRequest) => {
|
|
245
|
+
const runCommand = useCallback(async (command: PreviewCommandRequest): Promise<PreviewStatusResponse> => {
|
|
195
246
|
setBusy(true);
|
|
196
247
|
setCommandError(null);
|
|
197
248
|
try {
|
|
@@ -214,7 +265,9 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
214
265
|
throw new Error(payload && "error" in payload ? payload.error ?? "Preview command failed" : `Preview command failed: ${response.status}`);
|
|
215
266
|
}
|
|
216
267
|
|
|
217
|
-
|
|
268
|
+
const nextStatus = payload as PreviewStatusResponse;
|
|
269
|
+
setStatus(nextStatus);
|
|
270
|
+
return nextStatus;
|
|
218
271
|
} finally {
|
|
219
272
|
setBusy(false);
|
|
220
273
|
}
|
|
@@ -324,6 +377,10 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
324
377
|
});
|
|
325
378
|
}, [runCommand, status?.candidateUrls, status?.connected]);
|
|
326
379
|
|
|
380
|
+
useEffect(() => {
|
|
381
|
+
onConnectionChange?.(Boolean(status?.connected && status?.screenshotKey));
|
|
382
|
+
}, [onConnectionChange, status?.connected, status?.screenshotKey]);
|
|
383
|
+
|
|
327
384
|
const screenshotUrl = useMemo(() => (
|
|
328
385
|
status?.connected
|
|
329
386
|
? `/api/sessions/${encodeURIComponent(sessionId)}/preview/screenshot?ts=${encodeURIComponent(status.screenshotKey)}`
|
|
@@ -362,26 +419,6 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
362
419
|
};
|
|
363
420
|
}, [imageMetrics, mainFrame, status?.selectedElement]);
|
|
364
421
|
|
|
365
|
-
const selectedElementRenderedBounds = useMemo(() => {
|
|
366
|
-
const bounds = status?.selectedElement?.bounds;
|
|
367
|
-
if (!status?.selectedElement || !bounds || !mainFrame || status.selectedElement.frameId !== mainFrame.id) {
|
|
368
|
-
return null;
|
|
369
|
-
}
|
|
370
|
-
if (!imageMetrics.naturalWidth || !imageMetrics.naturalHeight || !imageMetrics.renderedWidth || !imageMetrics.renderedHeight) {
|
|
371
|
-
return null;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
const scaleX = imageMetrics.renderedWidth / imageMetrics.naturalWidth;
|
|
375
|
-
const scaleY = imageMetrics.renderedHeight / imageMetrics.naturalHeight;
|
|
376
|
-
|
|
377
|
-
return {
|
|
378
|
-
x: bounds.x * scaleX,
|
|
379
|
-
y: bounds.y * scaleY,
|
|
380
|
-
width: Math.max(bounds.width * scaleX, 2),
|
|
381
|
-
height: Math.max(bounds.height * scaleY, 2),
|
|
382
|
-
};
|
|
383
|
-
}, [imageMetrics, mainFrame, status?.selectedElement]);
|
|
384
|
-
|
|
385
422
|
const handleConnect = useCallback(async () => {
|
|
386
423
|
const trimmed = urlInput.trim();
|
|
387
424
|
if (!trimmed) return;
|
|
@@ -455,11 +492,6 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
455
492
|
};
|
|
456
493
|
}, [imageMetrics.renderedHeight, imageMetrics.renderedWidth, selectionComposer]);
|
|
457
494
|
|
|
458
|
-
useEffect(() => {
|
|
459
|
-
if (!selectionComposer || selectionComposer.pending) return;
|
|
460
|
-
instructionRef.current?.focus();
|
|
461
|
-
}, [selectionComposer]);
|
|
462
|
-
|
|
463
495
|
useEffect(() => {
|
|
464
496
|
if (!selectionComposer) return;
|
|
465
497
|
|
|
@@ -475,18 +507,77 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
475
507
|
};
|
|
476
508
|
}, [selectionComposer]);
|
|
477
509
|
|
|
478
|
-
const
|
|
479
|
-
if (!imageRef.current
|
|
510
|
+
const resolveImagePoint = useCallback((event: ReactMouseEvent<HTMLImageElement>) => {
|
|
511
|
+
if (!imageRef.current) {
|
|
512
|
+
return null;
|
|
513
|
+
}
|
|
480
514
|
|
|
481
515
|
const rect = imageRef.current.getBoundingClientRect();
|
|
482
516
|
if (!rect.width || !rect.height || !imageRef.current.naturalWidth || !imageRef.current.naturalHeight) {
|
|
483
|
-
return;
|
|
517
|
+
return null;
|
|
484
518
|
}
|
|
485
519
|
|
|
486
520
|
const anchorX = event.clientX - rect.left;
|
|
487
521
|
const anchorY = event.clientY - rect.top;
|
|
488
|
-
|
|
489
|
-
|
|
522
|
+
return {
|
|
523
|
+
anchorX,
|
|
524
|
+
anchorY,
|
|
525
|
+
x: (anchorX / rect.width) * imageRef.current.naturalWidth,
|
|
526
|
+
y: (anchorY / rect.height) * imageRef.current.naturalHeight,
|
|
527
|
+
};
|
|
528
|
+
}, []);
|
|
529
|
+
|
|
530
|
+
const queueContextInsert = useCallback((request: Omit<TerminalInsertRequest, "nonce">) => {
|
|
531
|
+
onQueueTerminalInsert(request);
|
|
532
|
+
setSendError(null);
|
|
533
|
+
setSendSuccess(request.successMessage);
|
|
534
|
+
}, [onQueueTerminalInsert]);
|
|
535
|
+
|
|
536
|
+
const selectElementAtPoint = useCallback(async (
|
|
537
|
+
x: number,
|
|
538
|
+
y: number,
|
|
539
|
+
anchorX: number,
|
|
540
|
+
anchorY: number,
|
|
541
|
+
): Promise<PreviewStatusResponse> => {
|
|
542
|
+
openSelectionComposer(anchorX, anchorY, true);
|
|
543
|
+
try {
|
|
544
|
+
const nextStatus = await runCommand({ command: "selectAtPoint", x, y });
|
|
545
|
+
openSelectionComposer(anchorX, anchorY, false);
|
|
546
|
+
return nextStatus;
|
|
547
|
+
} catch (error) {
|
|
548
|
+
setSelectionComposer(null);
|
|
549
|
+
throw error;
|
|
550
|
+
}
|
|
551
|
+
}, [openSelectionComposer, runCommand]);
|
|
552
|
+
|
|
553
|
+
const selectDomNode = useCallback(async (
|
|
554
|
+
selector: string,
|
|
555
|
+
frameId?: string | null,
|
|
556
|
+
): Promise<PreviewStatusResponse> => {
|
|
557
|
+
const anchorX = Math.max(imageMetrics.renderedWidth - 44, SELECTION_COMPOSER_MARGIN_PX);
|
|
558
|
+
const anchorY = SELECTION_COMPOSER_MARGIN_PX;
|
|
559
|
+
openSelectionComposer(anchorX, anchorY, true);
|
|
560
|
+
try {
|
|
561
|
+
const nextStatus = await runCommand({
|
|
562
|
+
command: "selectBySelector",
|
|
563
|
+
selector,
|
|
564
|
+
frameId,
|
|
565
|
+
});
|
|
566
|
+
openSelectionComposer(anchorX, anchorY, false);
|
|
567
|
+
return nextStatus;
|
|
568
|
+
} catch (error) {
|
|
569
|
+
setSelectionComposer(null);
|
|
570
|
+
throw error;
|
|
571
|
+
}
|
|
572
|
+
}, [imageMetrics.renderedWidth, openSelectionComposer, runCommand]);
|
|
573
|
+
|
|
574
|
+
const handleImageClick = useCallback(async (event: ReactMouseEvent<HTMLImageElement>) => {
|
|
575
|
+
if (busy) return;
|
|
576
|
+
|
|
577
|
+
const point = resolveImagePoint(event);
|
|
578
|
+
if (!point) {
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
490
581
|
|
|
491
582
|
setSelectionComposer(null);
|
|
492
583
|
setSendError(null);
|
|
@@ -495,7 +586,7 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
495
586
|
if (previewMode === "navigate") {
|
|
496
587
|
previewSurfaceRef.current?.focus({ preventScroll: true });
|
|
497
588
|
try {
|
|
498
|
-
await runCommand({ command: "clickAtPoint", x, y });
|
|
589
|
+
await runCommand({ command: "clickAtPoint", x: point.x, y: point.y });
|
|
499
590
|
} catch (error) {
|
|
500
591
|
setCommandError(error instanceof Error ? error.message : "Failed to interact with preview");
|
|
501
592
|
}
|
|
@@ -504,30 +595,44 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
504
595
|
|
|
505
596
|
if (!canSelectByPoint) return;
|
|
506
597
|
|
|
507
|
-
if (
|
|
508
|
-
selectedElementRenderedBounds
|
|
509
|
-
&& !selectionComposer?.pending
|
|
510
|
-
&& pointWithinBounds(anchorX, anchorY, selectedElementRenderedBounds)
|
|
511
|
-
) {
|
|
512
|
-
openSelectionComposer(anchorX, anchorY, false);
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
|
|
516
598
|
try {
|
|
517
|
-
await
|
|
599
|
+
await selectElementAtPoint(point.x, point.y, point.anchorX, point.anchorY);
|
|
518
600
|
} catch (error) {
|
|
519
601
|
setCommandError(error instanceof Error ? error.message : "Failed to select element");
|
|
520
602
|
}
|
|
521
603
|
}, [
|
|
522
604
|
busy,
|
|
523
605
|
canSelectByPoint,
|
|
524
|
-
openSelectionComposer,
|
|
525
606
|
previewMode,
|
|
607
|
+
resolveImagePoint,
|
|
526
608
|
runCommand,
|
|
527
|
-
|
|
528
|
-
selectionComposer?.pending,
|
|
609
|
+
selectElementAtPoint,
|
|
529
610
|
]);
|
|
530
611
|
|
|
612
|
+
const handleImageDoubleClick = useCallback(async (event: ReactMouseEvent<HTMLImageElement>) => {
|
|
613
|
+
if (busy || previewMode !== "inspect" || !canSelectByPoint) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const point = resolveImagePoint(event);
|
|
618
|
+
if (!point) {
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
setSendError(null);
|
|
623
|
+
setSendSuccess(null);
|
|
624
|
+
|
|
625
|
+
try {
|
|
626
|
+
const nextStatus = await selectElementAtPoint(point.x, point.y, point.anchorX, point.anchorY);
|
|
627
|
+
if (!nextStatus.selectedElement) {
|
|
628
|
+
throw new Error("No element found at the selected point");
|
|
629
|
+
}
|
|
630
|
+
queueContextInsert(buildSelectionInsert(nextStatus.selectedElement, nextStatus.currentUrl));
|
|
631
|
+
} catch (error) {
|
|
632
|
+
setCommandError(error instanceof Error ? error.message : "Failed to queue selected element");
|
|
633
|
+
}
|
|
634
|
+
}, [busy, canSelectByPoint, previewMode, queueContextInsert, resolveImagePoint, selectElementAtPoint]);
|
|
635
|
+
|
|
531
636
|
const handlePreviewKeyDown = useCallback((event: ReactKeyboardEvent<HTMLDivElement>) => {
|
|
532
637
|
if (previewMode !== "navigate" || !status?.connected) {
|
|
533
638
|
return;
|
|
@@ -564,11 +669,7 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
564
669
|
queuePreviewCommand({ command: "typeText", text }, "Failed to paste into preview");
|
|
565
670
|
}, [previewMode, queuePreviewCommand, status?.connected]);
|
|
566
671
|
|
|
567
|
-
const handleSendContext = useCallback(
|
|
568
|
-
if (!projectId) {
|
|
569
|
-
setSendError("Preview attachments require a project-backed session.");
|
|
570
|
-
return;
|
|
571
|
-
}
|
|
672
|
+
const handleSendContext = useCallback((target: PreviewSendTarget) => {
|
|
572
673
|
if (!status) {
|
|
573
674
|
setSendError("Preview state is not loaded yet.");
|
|
574
675
|
return;
|
|
@@ -578,7 +679,7 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
578
679
|
const recentNetworkLogs = status.networkLogs.slice(-80);
|
|
579
680
|
|
|
580
681
|
if (target === "selection" && !status.selectedElement) {
|
|
581
|
-
setSendError("Select an element before
|
|
682
|
+
setSendError("Select an element before queueing preview context for terminal input.");
|
|
582
683
|
return;
|
|
583
684
|
}
|
|
584
685
|
|
|
@@ -595,115 +696,23 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
595
696
|
setSendingTarget(target);
|
|
596
697
|
setSendError(null);
|
|
597
698
|
setSendSuccess(null);
|
|
598
|
-
|
|
599
699
|
try {
|
|
600
|
-
const
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
};
|
|
607
|
-
|
|
608
|
-
const payloadByTarget = {
|
|
609
|
-
selection: {
|
|
610
|
-
...basePreviewPayload,
|
|
611
|
-
recentConsoleLogs,
|
|
612
|
-
recentNetworkLogs,
|
|
613
|
-
},
|
|
614
|
-
console: {
|
|
615
|
-
...basePreviewPayload,
|
|
616
|
-
recentConsoleLogs,
|
|
617
|
-
},
|
|
618
|
-
network: {
|
|
619
|
-
...basePreviewPayload,
|
|
620
|
-
recentNetworkLogs,
|
|
621
|
-
},
|
|
622
|
-
} satisfies Record<PreviewSendTarget, Record<string, unknown>>;
|
|
623
|
-
|
|
624
|
-
const jsonPayload = {
|
|
625
|
-
generatedAt: new Date().toISOString(),
|
|
626
|
-
target,
|
|
627
|
-
preview: payloadByTarget[target],
|
|
628
|
-
};
|
|
629
|
-
|
|
630
|
-
const files: File[] = [
|
|
631
|
-
new File(
|
|
632
|
-
[JSON.stringify(jsonPayload, null, 2)],
|
|
633
|
-
`${sessionId}-preview-${target}.json`,
|
|
634
|
-
{ type: "application/json" },
|
|
635
|
-
),
|
|
636
|
-
];
|
|
637
|
-
|
|
638
|
-
if (screenshotUrl) {
|
|
639
|
-
const screenshotResponse = await fetch(screenshotUrl, { cache: "no-store" });
|
|
640
|
-
if (screenshotResponse.ok) {
|
|
641
|
-
const screenshotBlob = await screenshotResponse.blob();
|
|
642
|
-
files.push(new File([screenshotBlob], `${sessionId}-preview-${target}.png`, { type: "image/png" }));
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
const attachmentPaths = await uploadPreviewAttachments(projectId, files);
|
|
647
|
-
const messageByTarget = {
|
|
648
|
-
selection: [
|
|
649
|
-
"Use the attached preview context JSON and screenshot to update the UI.",
|
|
650
|
-
`Selected element selector: ${status.selectedElement?.selector ?? "n/a"}`,
|
|
651
|
-
`Selected frame: ${status.selectedElement?.frameName ?? "n/a"} (${status.selectedElement?.frameUrl ?? "n/a"})`,
|
|
652
|
-
instruction.trim() || "Apply the requested UI change to the selected element and surrounding layout as needed.",
|
|
653
|
-
],
|
|
654
|
-
console: [
|
|
655
|
-
"Use the attached preview console logs and screenshot to debug the current page state.",
|
|
656
|
-
`Preview URL: ${status.currentUrl ?? "unavailable"}`,
|
|
657
|
-
status.selectedElement ? `Current selected element: ${status.selectedElement.selector}` : null,
|
|
658
|
-
instruction.trim() || "Investigate the console output, identify the root cause, and apply the needed fix.",
|
|
659
|
-
],
|
|
660
|
-
network: [
|
|
661
|
-
"Use the attached preview network logs and screenshot to debug failed or unexpected requests.",
|
|
662
|
-
`Preview URL: ${status.currentUrl ?? "unavailable"}`,
|
|
663
|
-
status.selectedElement ? `Current selected element: ${status.selectedElement.selector}` : null,
|
|
664
|
-
instruction.trim() || "Investigate the network activity, identify the failing request or sequencing issue, and apply the needed fix.",
|
|
665
|
-
],
|
|
666
|
-
} satisfies Record<PreviewSendTarget, Array<string | null>>;
|
|
667
|
-
|
|
668
|
-
const successMessageByTarget = {
|
|
669
|
-
selection: "Preview context sent to the session agent.",
|
|
670
|
-
console: "Console logs sent to the session agent.",
|
|
671
|
-
network: "Network logs sent to the session agent.",
|
|
672
|
-
} satisfies Record<PreviewSendTarget, string>;
|
|
673
|
-
|
|
674
|
-
const elementSummary = messageByTarget[target].filter((line): line is string => Boolean(line)).join("\n");
|
|
675
|
-
|
|
676
|
-
const response = await fetch(`/api/sessions/${encodeURIComponent(sessionId)}/send`, {
|
|
677
|
-
method: "POST",
|
|
678
|
-
headers: {
|
|
679
|
-
"Content-Type": "application/json",
|
|
680
|
-
},
|
|
681
|
-
body: JSON.stringify({
|
|
682
|
-
message: elementSummary,
|
|
683
|
-
attachments: attachmentPaths,
|
|
684
|
-
}),
|
|
685
|
-
});
|
|
686
|
-
|
|
687
|
-
const payload = await response.json().catch(() => null) as { error?: string } | null;
|
|
688
|
-
if (!response.ok) {
|
|
689
|
-
throw new Error(payload?.error ?? `Failed to send preview context: ${response.status}`);
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
setInstruction("");
|
|
700
|
+
const request = target === "selection" && status.selectedElement
|
|
701
|
+
? buildSelectionInsert(status.selectedElement, status.currentUrl)
|
|
702
|
+
: target === "console"
|
|
703
|
+
? buildLogInsert("console", recentConsoleLogs, status.currentUrl, status.selectedElement)
|
|
704
|
+
: buildLogInsert("network", recentNetworkLogs, status.currentUrl, status.selectedElement);
|
|
705
|
+
queueContextInsert(request);
|
|
693
706
|
if (target === "selection") {
|
|
694
707
|
setSelectionComposer(null);
|
|
695
708
|
}
|
|
696
|
-
setSendSuccess(successMessageByTarget[target]);
|
|
697
709
|
} catch (error) {
|
|
698
|
-
setSendError(error instanceof Error ? error.message : "Failed to
|
|
710
|
+
setSendError(error instanceof Error ? error.message : "Failed to queue preview context");
|
|
699
711
|
} finally {
|
|
700
712
|
setSendingTarget(null);
|
|
701
713
|
}
|
|
702
714
|
}, [
|
|
703
|
-
|
|
704
|
-
projectId,
|
|
705
|
-
screenshotUrl,
|
|
706
|
-
sessionId,
|
|
715
|
+
queueContextInsert,
|
|
707
716
|
status,
|
|
708
717
|
]);
|
|
709
718
|
|
|
@@ -842,7 +851,7 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
842
851
|
{previewMode === "navigate"
|
|
843
852
|
? "navigate mode: clicks interact with the page"
|
|
844
853
|
: canSelectByPoint
|
|
845
|
-
? "inspect mode: click once to select,
|
|
854
|
+
? "inspect mode: click once to select, double-click to queue for terminal input"
|
|
846
855
|
: "inspect mode: use DOM list for this frame"}
|
|
847
856
|
</Badge>
|
|
848
857
|
</div>
|
|
@@ -876,6 +885,7 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
876
885
|
: "cursor-default",
|
|
877
886
|
)}
|
|
878
887
|
onClick={(event) => void handleImageClick(event)}
|
|
888
|
+
onDoubleClick={(event) => void handleImageDoubleClick(event)}
|
|
879
889
|
onLoad={(event) => {
|
|
880
890
|
const target = event.currentTarget;
|
|
881
891
|
setImageMetrics({
|
|
@@ -899,9 +909,9 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
899
909
|
>
|
|
900
910
|
<div className="flex items-start justify-between gap-3 border-b border-[var(--vk-border)] px-3 py-3">
|
|
901
911
|
<div className="min-w-0">
|
|
902
|
-
<div className="text-[10px] uppercase tracking-[0.16em] text-[var(--vk-text-muted)]">
|
|
912
|
+
<div className="text-[10px] uppercase tracking-[0.16em] text-[var(--vk-text-muted)]">Terminal input</div>
|
|
903
913
|
<div className="mt-1 text-[13px] font-medium text-[var(--vk-text-normal)]">
|
|
904
|
-
{selectionComposer.pending ? "Selecting element…" : "
|
|
914
|
+
{selectionComposer.pending ? "Selecting element…" : "Queue selection for the terminal"}
|
|
905
915
|
</div>
|
|
906
916
|
</div>
|
|
907
917
|
<div className="flex items-center gap-1">
|
|
@@ -944,17 +954,8 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
944
954
|
{status.selectedElement.selector}
|
|
945
955
|
</div>
|
|
946
956
|
</div>
|
|
947
|
-
<div className="
|
|
948
|
-
|
|
949
|
-
Instruction
|
|
950
|
-
</label>
|
|
951
|
-
<textarea
|
|
952
|
-
ref={instructionRef}
|
|
953
|
-
value={instruction}
|
|
954
|
-
onChange={(event) => setInstruction(event.target.value)}
|
|
955
|
-
placeholder="Describe the change and send it straight to this agent session…"
|
|
956
|
-
className="min-h-[108px] w-full rounded-[6px] border border-[var(--vk-border)] bg-[var(--vk-bg-main)] px-3 py-2 text-[13px] text-[var(--vk-text-normal)] outline-none focus:border-[var(--vk-orange)]"
|
|
957
|
-
/>
|
|
957
|
+
<div className="rounded-[6px] border border-dashed border-[var(--vk-border)] px-3 py-2 text-[12px] text-[var(--vk-text-muted)]">
|
|
958
|
+
Double-click the element in the preview to queue it immediately, or use the button below. The text is inserted into terminal input instead of being sent to the agent, so you can add more context before submitting.
|
|
958
959
|
</div>
|
|
959
960
|
{sendError ? (
|
|
960
961
|
<div className="text-[12px] text-[var(--vk-red)]">{sendError}</div>
|
|
@@ -967,12 +968,12 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
967
968
|
disabled={sending || !status.selectedElement}
|
|
968
969
|
>
|
|
969
970
|
{sendingTarget === "selection" ? <Loader2 className="h-4 w-4 animate-spin" /> : <Send className="h-4 w-4" />}
|
|
970
|
-
|
|
971
|
+
Queue for terminal input
|
|
971
972
|
</Button>
|
|
972
973
|
</>
|
|
973
974
|
) : (
|
|
974
975
|
<div className="rounded-[6px] border border-dashed border-[var(--vk-border)] px-3 py-3 text-[12px] text-[var(--vk-text-muted)]">
|
|
975
|
-
|
|
976
|
+
Single-click an element to inspect it here. Double-click to queue it for terminal input.
|
|
976
977
|
</div>
|
|
977
978
|
)}
|
|
978
979
|
</div>
|
|
@@ -981,7 +982,7 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
981
982
|
</div>
|
|
982
983
|
) : (
|
|
983
984
|
<div className="max-w-md text-center text-[13px] text-[var(--vk-text-muted)]">
|
|
984
|
-
Connect a local dev URL to start the preview browser. In Navigate mode, click the preview first, then type directly into the running app. Switch to Inspect mode to select
|
|
985
|
+
Connect a local dev URL to start the preview browser. In Navigate mode, click the preview first, then type directly into the running app. Switch to Inspect mode to select UI elements and queue browser context into terminal input.
|
|
985
986
|
</div>
|
|
986
987
|
)}
|
|
987
988
|
</div>
|
|
@@ -1050,7 +1051,7 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
1050
1051
|
<div className="space-y-1 p-2">
|
|
1051
1052
|
{previewMode === "navigate" ? (
|
|
1052
1053
|
<div className="rounded-[4px] border border-dashed border-[var(--vk-border)] px-2 py-2 text-[11px] text-[var(--vk-text-muted)]">
|
|
1053
|
-
Switch to Inspect mode to pick DOM nodes
|
|
1054
|
+
Switch to Inspect mode to pick DOM nodes. Single-click selects a node. Double-click queues it for terminal input.
|
|
1054
1055
|
</div>
|
|
1055
1056
|
) : null}
|
|
1056
1057
|
{domLoading ? (
|
|
@@ -1071,31 +1072,28 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
1071
1072
|
)}
|
|
1072
1073
|
disabled={previewMode !== "inspect"}
|
|
1073
1074
|
onClick={() => {
|
|
1074
|
-
if (
|
|
1075
|
-
status?.selectedElement
|
|
1076
|
-
&& status.selectedElement.selector === node.selector
|
|
1077
|
-
&& status.selectedElement.frameId === status.activeFrameId
|
|
1078
|
-
) {
|
|
1079
|
-
openSelectionComposer(
|
|
1080
|
-
Math.max(imageMetrics.renderedWidth - 44, SELECTION_COMPOSER_MARGIN_PX),
|
|
1081
|
-
SELECTION_COMPOSER_MARGIN_PX,
|
|
1082
|
-
false,
|
|
1083
|
-
);
|
|
1084
|
-
return;
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
1075
|
setSelectionComposer(null);
|
|
1088
1076
|
setSendError(null);
|
|
1089
1077
|
setSendSuccess(null);
|
|
1090
|
-
void
|
|
1091
|
-
command: "selectBySelector",
|
|
1092
|
-
selector: node.selector,
|
|
1093
|
-
frameId: status?.activeFrameId,
|
|
1094
|
-
})
|
|
1078
|
+
void selectDomNode(node.selector, status?.activeFrameId)
|
|
1095
1079
|
.catch((error: unknown) => {
|
|
1096
1080
|
setCommandError(error instanceof Error ? error.message : "Failed to select DOM node");
|
|
1097
1081
|
});
|
|
1098
1082
|
}}
|
|
1083
|
+
onDoubleClick={() => {
|
|
1084
|
+
setSendError(null);
|
|
1085
|
+
setSendSuccess(null);
|
|
1086
|
+
void selectDomNode(node.selector, status?.activeFrameId)
|
|
1087
|
+
.then((nextStatus) => {
|
|
1088
|
+
if (!nextStatus.selectedElement) {
|
|
1089
|
+
throw new Error("Failed to resolve the selected DOM node");
|
|
1090
|
+
}
|
|
1091
|
+
queueContextInsert(buildSelectionInsert(nextStatus.selectedElement, nextStatus.currentUrl));
|
|
1092
|
+
})
|
|
1093
|
+
.catch((error: unknown) => {
|
|
1094
|
+
setCommandError(error instanceof Error ? error.message : "Failed to queue DOM node");
|
|
1095
|
+
});
|
|
1096
|
+
}}
|
|
1099
1097
|
>
|
|
1100
1098
|
<div className="flex items-center gap-2">
|
|
1101
1099
|
<span className="font-mono text-[12px] text-[var(--vk-text-normal)]">{node.tag}</span>
|
|
@@ -1139,7 +1137,7 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
1139
1137
|
disabled={sending || !status?.consoleLogs.length}
|
|
1140
1138
|
>
|
|
1141
1139
|
{sendingTarget === "console" ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Send className="h-3.5 w-3.5" />}
|
|
1142
|
-
|
|
1140
|
+
Queue for terminal
|
|
1143
1141
|
</Button>
|
|
1144
1142
|
</CardHeader>
|
|
1145
1143
|
<CardContent>
|
|
@@ -1183,7 +1181,7 @@ export function SessionPreview({ sessionId, projectId }: SessionPreviewProps) {
|
|
|
1183
1181
|
disabled={sending || !status?.networkLogs.length}
|
|
1184
1182
|
>
|
|
1185
1183
|
{sendingTarget === "network" ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Send className="h-3.5 w-3.5" />}
|
|
1186
|
-
|
|
1184
|
+
Queue for terminal
|
|
1187
1185
|
</Button>
|
|
1188
1186
|
</CardHeader>
|
|
1189
1187
|
<CardContent>
|