@alivault/pico 0.12.0 → 0.14.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/.output/nitro.json +1 -1
- package/.output/public/assets/addon-fit-CMMXLNsg.js +1 -0
- package/.output/public/assets/{index-DQLwecED.js → index-DBVxXDtw.js} +11 -10
- package/.output/public/assets/routes-yUxD2q-l.js +2194 -0
- package/.output/public/assets/styles-CUVz7jV9.css +2 -0
- package/.output/public/assets/xterm-CCMwI7sy.js +36 -0
- package/.output/public/screenshots/pico-ios-dark.png +0 -0
- package/.output/public/screenshots/pico-ios-light.png +0 -0
- package/.output/public/screenshots/pico-macos-dark.jpg +0 -0
- package/.output/public/screenshots/pico-macos-light.jpg +0 -0
- package/.output/server/_chunks/ssr-renderer.mjs +3 -3
- package/.output/server/_libs/crossws.mjs +2929 -0
- package/.output/server/_libs/h3+rou3+srvx.mjs +7 -1
- package/.output/server/_libs/lucide-react.mjs +20 -1
- package/.output/server/_libs/unctx.mjs +1 -1
- package/.output/server/_libs/xterm__addon-fit.mjs +44 -0
- package/.output/server/_libs/xterm__xterm.mjs +10234 -0
- package/.output/server/_routes/api/terminal/[id]/ws.mjs +8874 -0
- package/.output/server/_ssr/{router-D36lUq7O.mjs → router-CN4JMm2A.mjs} +1605 -314
- package/.output/server/_ssr/{routes-C8qT6Oju.mjs → routes-BsQ26pbY.mjs} +2377 -730
- package/.output/server/_ssr/{routes-9nZumcXQ.mjs → routes-DbjuMLFI.mjs} +176 -26
- package/.output/server/_ssr/ssr.mjs +3 -3
- package/.output/server/_ssr/start-jIczsXlR.mjs +4 -0
- package/.output/server/{_tanstack-start-manifest_v-Cd2ypHmK.mjs → _tanstack-start-manifest_v-Bs4g_j1_.mjs} +8 -4
- package/.output/server/index.mjs +594 -501
- package/.output/server/node_modules/node-pty/LICENSE +69 -0
- package/.output/server/node_modules/node-pty/README.md +165 -0
- package/.output/server/node_modules/node-pty/binding.gyp +111 -0
- package/.output/server/node_modules/node-pty/build/Makefile +369 -0
- package/.output/server/node_modules/node-pty/build/Release/pty.node +0 -0
- package/.output/server/node_modules/node-pty/build/binding.Makefile +6 -0
- package/.output/server/node_modules/node-pty/build/pty.target.mk +168 -0
- package/.output/server/node_modules/node-pty/deps/.editorconfig +2 -0
- package/.output/server/node_modules/node-pty/deps/winpty/.drone.yml +17 -0
- package/.output/server/node_modules/node-pty/deps/winpty/.gitattributes +19 -0
- package/.output/server/node_modules/node-pty/deps/winpty/LICENSE +21 -0
- package/.output/server/node_modules/node-pty/deps/winpty/Makefile +166 -0
- package/.output/server/node_modules/node-pty/deps/winpty/README.md +151 -0
- package/.output/server/node_modules/node-pty/deps/winpty/RELEASES.md +280 -0
- package/.output/server/node_modules/node-pty/deps/winpty/VERSION.txt +1 -0
- package/.output/server/node_modules/node-pty/deps/winpty/configure +167 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/BufferResizeTests.cc +90 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/ChangeScreenBuffer.cc +53 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/ClearConsole.cc +72 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/ConinMode.cc +117 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/ConinMode.ps1 +116 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/ConoutMode.cc +113 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/DebugClient.py +42 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/DebugServer.py +63 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/DumpLines.py +5 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/EnableExtendedFlags.txt +46 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Font-Report-June2016/CP437-Consolas.txt +528 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Font-Report-June2016/CP437-Lucida.txt +633 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Font-Report-June2016/CP932.txt +630 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Font-Report-June2016/CP936.txt +630 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Font-Report-June2016/CP949.txt +630 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Font-Report-June2016/CP950.txt +630 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Font-Report-June2016/MinimumWindowWidths.txt +16 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Font-Report-June2016/Results.txt +4 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Font-Report-June2016/Windows10SetFontBugginess.txt +144 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/FontSurvey.cc +100 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/FormatChar.h +21 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/FreezePerfTest.cc +62 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/GetCh.cc +20 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/GetConsolePos.cc +41 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/GetFont.cc +261 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/IdentifyConsoleWindow.ps1 +51 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/IsNewConsole.cc +87 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/MouseInputNotes.txt +90 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/MoveConsoleWindow.cc +34 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Notes.txt +219 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/OSVersion.cc +27 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/ScreenBufferFreezeInactive.cc +101 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/ScreenBufferTest.cc +671 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/ScreenBufferTest2.cc +151 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/SelectAllTest.cc +45 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/SetBufferSize.cc +32 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/SetCursorPos.cc +10 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/SetFont.cc +145 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/SetWindowRect.cc +36 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/ShowArgv.cc +12 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/ShowConsoleInput.cc +40 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Spew.py +5 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/TestUtil.cc +172 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/UnicodeDoubleWidthTest.cc +102 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/UnicodeWideTest1.cc +246 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/UnicodeWideTest2.cc +130 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/UnixEcho.cc +89 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Utf16Echo.cc +46 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/VeryLargeRead.cc +122 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/VkEscapeTest.cc +56 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Win10ResizeWhileFrozen.cc +52 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Win10WrapTest1.cc +57 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Win10WrapTest2.cc +30 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Win32Echo1.cc +26 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Win32Echo2.cc +19 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Win32Test1.cc +46 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Win32Test2.cc +70 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Win32Test3.cc +78 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/Win32Write1.cc +44 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/WindowsBugCrashReader.cc +27 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/WriteConsole.cc +106 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/build32.sh +9 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/build64.sh +9 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/color-test.sh +212 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/font-notes.txt +300 -0
- package/.output/server/node_modules/node-pty/deps/winpty/misc/winbug-15048.cc +201 -0
- package/.output/server/node_modules/node-pty/deps/winpty/ship/build-pty4j-libpty.bat +36 -0
- package/.output/server/node_modules/node-pty/deps/winpty/ship/common_ship.py +53 -0
- package/.output/server/node_modules/node-pty/deps/winpty/ship/make_msvc_package.py +165 -0
- package/.output/server/node_modules/node-pty/deps/winpty/ship/ship.py +108 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/Agent.cc +613 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/Agent.h +103 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/AgentCreateDesktop.cc +84 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/AgentCreateDesktop.h +28 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/ConsoleFont.cc +632 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/ConsoleFont.h +28 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/ConsoleInput.cc +852 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/ConsoleInput.h +109 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/ConsoleInputReencoding.cc +121 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/ConsoleInputReencoding.h +36 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/ConsoleLine.cc +152 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/ConsoleLine.h +41 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/Coord.h +87 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/DebugShowInput.cc +239 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/DebugShowInput.h +32 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/DefaultInputMap.cc +422 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/DefaultInputMap.h +28 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/DsrSender.h +30 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/EventLoop.cc +99 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/EventLoop.h +47 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/InputMap.cc +246 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/InputMap.h +114 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/LargeConsoleRead.cc +71 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/LargeConsoleRead.h +68 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/NamedPipe.cc +378 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/NamedPipe.h +125 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/Scraper.cc +699 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/Scraper.h +103 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/SimplePool.h +75 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/SmallRect.h +143 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/Terminal.cc +535 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/Terminal.h +69 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/UnicodeEncoding.h +157 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/UnicodeEncodingTest.cc +189 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/Win32Console.cc +107 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/Win32Console.h +67 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/Win32ConsoleBuffer.cc +193 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/Win32ConsoleBuffer.h +99 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/main.cc +114 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/agent/subdir.mk +61 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/configurations.gypi +60 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/debugserver/DebugServer.cc +117 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/debugserver/subdir.mk +41 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/include/winpty.h +242 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/include/winpty_constants.h +131 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/libwinpty/AgentLocation.cc +75 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/libwinpty/AgentLocation.h +28 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/libwinpty/LibWinptyException.h +54 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/libwinpty/WinptyInternal.h +72 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/libwinpty/subdir.mk +46 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/libwinpty/winpty.cc +970 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/AgentMsg.h +38 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/BackgroundDesktop.cc +122 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/BackgroundDesktop.h +73 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/Buffer.cc +103 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/Buffer.h +102 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/DebugClient.cc +187 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/DebugClient.h +38 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/GenRandom.cc +138 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/GenRandom.h +55 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/GetCommitHash.bat +13 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/Mutex.h +54 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/OsModule.h +63 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/OwnedHandle.cc +36 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/OwnedHandle.h +45 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/PrecompiledHeader.h +43 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/StringBuilder.h +227 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/StringBuilderTest.cc +114 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/StringUtil.cc +55 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/StringUtil.h +80 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/TimeMeasurement.h +63 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/UnixCtrlChars.h +45 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/UpdateGenVersion.bat +20 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/WindowsSecurity.cc +460 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/WindowsSecurity.h +104 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/WindowsVersion.cc +252 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/WindowsVersion.h +29 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/WinptyAssert.cc +55 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/WinptyAssert.h +64 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/WinptyException.cc +57 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/WinptyException.h +43 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/WinptyVersion.cc +42 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/WinptyVersion.h +27 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/shared/winpty_snprintf.h +99 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/subdir.mk +5 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/tests/subdir.mk +28 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/tests/trivial_test.cc +158 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/unix-adapter/InputHandler.cc +114 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/unix-adapter/InputHandler.h +56 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/unix-adapter/OutputHandler.cc +80 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/unix-adapter/OutputHandler.h +53 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/unix-adapter/Util.cc +86 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/unix-adapter/Util.h +31 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/unix-adapter/WakeupFd.cc +70 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/unix-adapter/WakeupFd.h +42 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/unix-adapter/main.cc +729 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/unix-adapter/subdir.mk +41 -0
- package/.output/server/node_modules/node-pty/deps/winpty/src/winpty.gyp +234 -0
- package/.output/server/node_modules/node-pty/deps/winpty/vcbuild.bat +83 -0
- package/.output/server/node_modules/node-pty/lib/conpty_console_list_agent.js +16 -0
- package/.output/server/node_modules/node-pty/lib/conpty_console_list_agent.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/eventEmitter2.js +47 -0
- package/.output/server/node_modules/node-pty/lib/eventEmitter2.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/eventEmitter2.test.js +30 -0
- package/.output/server/node_modules/node-pty/lib/eventEmitter2.test.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/index.js +52 -0
- package/.output/server/node_modules/node-pty/lib/index.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/interfaces.js +7 -0
- package/.output/server/node_modules/node-pty/lib/interfaces.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/shared/conout.js +11 -0
- package/.output/server/node_modules/node-pty/lib/shared/conout.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/terminal.js +190 -0
- package/.output/server/node_modules/node-pty/lib/terminal.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/terminal.test.js +139 -0
- package/.output/server/node_modules/node-pty/lib/terminal.test.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/testUtils.test.js +28 -0
- package/.output/server/node_modules/node-pty/lib/testUtils.test.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/types.js +7 -0
- package/.output/server/node_modules/node-pty/lib/types.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/unixTerminal.js +346 -0
- package/.output/server/node_modules/node-pty/lib/unixTerminal.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/unixTerminal.test.js +351 -0
- package/.output/server/node_modules/node-pty/lib/unixTerminal.test.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/utils.js +39 -0
- package/.output/server/node_modules/node-pty/lib/utils.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/windowsConoutConnection.js +125 -0
- package/.output/server/node_modules/node-pty/lib/windowsConoutConnection.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/windowsPtyAgent.js +320 -0
- package/.output/server/node_modules/node-pty/lib/windowsPtyAgent.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/windowsPtyAgent.test.js +90 -0
- package/.output/server/node_modules/node-pty/lib/windowsPtyAgent.test.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/windowsTerminal.js +199 -0
- package/.output/server/node_modules/node-pty/lib/windowsTerminal.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/windowsTerminal.test.js +219 -0
- package/.output/server/node_modules/node-pty/lib/windowsTerminal.test.js.map +1 -0
- package/.output/server/node_modules/node-pty/lib/worker/conoutSocketWorker.js +22 -0
- package/.output/server/node_modules/node-pty/lib/worker/conoutSocketWorker.js.map +1 -0
- package/.output/server/node_modules/node-pty/package.json +64 -0
- package/.output/server/node_modules/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/darwin-x64/pty.node +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-arm64/conpty.pdb +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-arm64/conpty_console_list.pdb +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-arm64/pty.node +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-arm64/pty.pdb +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-arm64/winpty-agent.exe +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-arm64/winpty-agent.pdb +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-arm64/winpty.dll +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-arm64/winpty.pdb +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-x64/conpty.node +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-x64/conpty.pdb +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-x64/conpty_console_list.pdb +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-x64/pty.node +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-x64/pty.pdb +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-x64/winpty-agent.exe +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-x64/winpty-agent.pdb +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-x64/winpty.dll +0 -0
- package/.output/server/node_modules/node-pty/prebuilds/win32-x64/winpty.pdb +0 -0
- package/.output/server/node_modules/node-pty/scripts/gen-compile-commands.js +8 -0
- package/.output/server/node_modules/node-pty/scripts/increment-version.js +54 -0
- package/.output/server/node_modules/node-pty/scripts/post-install.js +80 -0
- package/.output/server/node_modules/node-pty/scripts/prebuild.js +34 -0
- package/.output/server/node_modules/node-pty/src/conpty_console_list_agent.ts +15 -0
- package/.output/server/node_modules/node-pty/src/eventEmitter2.test.ts +30 -0
- package/.output/server/node_modules/node-pty/src/eventEmitter2.ts +48 -0
- package/.output/server/node_modules/node-pty/src/index.ts +52 -0
- package/.output/server/node_modules/node-pty/src/interfaces.ts +130 -0
- package/.output/server/node_modules/node-pty/src/native.d.ts +54 -0
- package/.output/server/node_modules/node-pty/src/shared/conout.ts +15 -0
- package/.output/server/node_modules/node-pty/src/terminal.test.ts +119 -0
- package/.output/server/node_modules/node-pty/src/terminal.ts +211 -0
- package/.output/server/node_modules/node-pty/src/testUtils.test.ts +23 -0
- package/.output/server/node_modules/node-pty/src/tsconfig.json +22 -0
- package/.output/server/node_modules/node-pty/src/types.ts +15 -0
- package/.output/server/node_modules/node-pty/src/unix/pty.cc +799 -0
- package/.output/server/node_modules/node-pty/src/unix/spawn-helper.cc +23 -0
- package/.output/server/node_modules/node-pty/src/unixTerminal.test.ts +367 -0
- package/.output/server/node_modules/node-pty/src/unixTerminal.ts +388 -0
- package/.output/server/node_modules/node-pty/src/utils.ts +29 -0
- package/.output/server/node_modules/node-pty/src/win/conpty.cc +583 -0
- package/.output/server/node_modules/node-pty/src/win/conpty.h +41 -0
- package/.output/server/node_modules/node-pty/src/win/conpty_console_list.cc +44 -0
- package/.output/server/node_modules/node-pty/src/win/path_util.cc +95 -0
- package/.output/server/node_modules/node-pty/src/win/path_util.h +26 -0
- package/.output/server/node_modules/node-pty/src/win/winpty.cc +333 -0
- package/.output/server/node_modules/node-pty/src/windowsConoutConnection.ts +82 -0
- package/.output/server/node_modules/node-pty/src/windowsPtyAgent.test.ts +94 -0
- package/.output/server/node_modules/node-pty/src/windowsPtyAgent.ts +321 -0
- package/.output/server/node_modules/node-pty/src/windowsTerminal.test.ts +229 -0
- package/.output/server/node_modules/node-pty/src/windowsTerminal.ts +203 -0
- package/.output/server/node_modules/node-pty/src/worker/conoutSocketWorker.ts +22 -0
- package/.output/server/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-arm64/OpenConsole.exe +0 -0
- package/.output/server/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-arm64/conpty.dll +0 -0
- package/.output/server/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-x64/OpenConsole.exe +0 -0
- package/.output/server/node_modules/node-pty/third_party/conpty/1.23.251008001/win10-x64/conpty.dll +0 -0
- package/.output/server/node_modules/node-pty/typings/node-pty.d.ts +211 -0
- package/.output/server/package.json +1 -0
- package/README.md +68 -6
- package/bin/pico.mjs +103 -1
- package/package.json +14 -7
- package/public/screenshots/pico-ios-dark.png +0 -0
- package/public/screenshots/pico-ios-light.png +0 -0
- package/public/screenshots/pico-macos-dark.jpg +0 -0
- package/public/screenshots/pico-macos-light.jpg +0 -0
- package/.output/public/assets/routes-DynLhCvj.js +0 -2195
- package/.output/public/assets/styles-DJ9ubgcc.css +0 -2
- package/.output/server/_ssr/start-Captdpmb.mjs +0 -4
- package/scripts/patch-react-jsx-dev-runtime.mjs +0 -93
- /package/.output/public/assets/{wasm-CEUrWlVz.js → wasm-D_MQmneJ.js} +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { i as __toESM } from "../_runtime.mjs";
|
|
2
2
|
import { $ as require_react, A as TabsTab, B as Input, C as MenuPositioner, D as MenuGroupLabel, E as MenuItem, F as DialogPopup, H as useRender, I as DialogDescription$1, L as DialogClose$1, M as DialogTitle$1, N as DialogRoot, O as MenuGroup, P as DialogPortal$1, Q as require_jsx_runtime, R as DialogBackdrop, S as MenuRoot, T as MenuPopup, V as Button, Y as mergeProps, _ as AccordionItem$1, a as ContextMenuRoot, b as MenuTrigger, c as CollapsibleRoot, d as PopoverPortal, f as PopoverTrigger$1, g as AccordionHeader, h as AccordionTrigger$1, i as ContextMenuTrigger$1, j as TabsRoot, k as TabsList$1, l as PopoverPopup, m as AccordionPanel, n as ToggleGroup, o as CollapsiblePanel, p as PopoverRoot, r as Toggle, s as CollapsibleTrigger$1, t as AlertDialogRoot, u as PopoverPositioner, v as AccordionRoot, w as MenuPortal, x as MenuSubmenuRoot, y as MenuSubmenuTrigger, z as Separator } from "../_libs/@base-ui/react+[...].mjs";
|
|
3
3
|
import { t as cva } from "../_libs/class-variance-authority+clsx.mjs";
|
|
4
|
-
import { A as
|
|
5
|
-
import { $ as
|
|
4
|
+
import { A as Folder, B as ChevronsUpDown, C as ListStart, D as GitPullRequestArrow, E as ImagePlus, F as EllipsisVertical, G as Check, I as Download, J as ArrowUpRight, K as ArrowUp, L as Copy, M as FileDiff, N as ExternalLink, O as GitBranch, P as Ellipsis, R as Command, S as Maximize2, U as ChevronRight, V as ChevronsDownUp, W as ChevronDown, X as ArrowLeft, Z as ArrowDown, _ as PanelLeftClose, a as TriangleAlert, b as Minus, c as Square, d as Settings2, f as Search, g as PanelLeftOpen, h as PanelLeft, i as Undo2, j as FolderPlus, k as GitCommitHorizontal, l as SquareTerminal, m as PanelRight, n as WandSparkles, o as Trash2, p as Plus, q as ArrowUpToLine, r as Upload, s as Tag, t as X, u as SquarePen, w as ListEnd, x as Minimize2, y as OctagonX } from "../_libs/lucide-react.mjs";
|
|
5
|
+
import { $ as normalizeSessionSelectionKeys, A as THEME_STORAGE_KEY, At as themeFamilyDescription, B as buildItemsFromSync, C as SESSION_DONE_SOUND_ENABLED_STORAGE_KEY, Ct as rememberStoredPromptDraft, D as TERMINAL_PANEL_OPEN_STORAGE_KEY, Dt as sameContextUsage, E as TERMINAL_PANEL_HEIGHT_STORAGE_KEY, Et as safeLocalStorageSetItem, F as TooltipTrigger, Ft as thinkingSummaryText, G as exploreShellCommandNameFromTool, I as VIEWER_CONTEXT_STORAGE_KEY, It as toolArgsAreIncompleteJsonObject, L as appliedThemeClass, Lt as toolCategoryFromTool, M as Tooltip$1, Mt as themeFamilyKeywords, N as TooltipContent, Nt as themeFamilyLabel, O as THEME_COLOR_MODE_STORAGE_KEY, Ot as sessionListEntryKey, Pt as themeFamilySupportsColorMode, Q as normalizePromptImage, R as appliedThemeClassColorMode, Rt as toolCouldBecomeExploreFromTool, S as SESSION_DONE_DESKTOP_NOTIFICATIONS_ENABLED_STORAGE_KEY, St as readStoredThemeColorMode, T as Spinner, Tt as safeLocalStorageGetItem, U as createContextId, V as cn, W as createInitialSessionState, X as getSessionTitle, Y as flattenTree, _ as RIGHT_SIDEBAR_HISTORY_HEIGHT_STORAGE_KEY, _t as readStoredSessionDoneSoundEnabled, a as COLLAPSED_DIRECTORIES_STORAGE_KEY, at as promptDraftKeyMatchesOwner, b as RIGHT_SIDEBAR_WIDTHS_STORAGE_KEY, bt as readStoredTerminalTabs, c as Kbd, ct as readStoredCenterMessages, d as PICO_DIFF_SHIKI_THEMES, dt as readStoredHideToolBlocks, et as normalizeStoredDirectoryList, f as PICO_SHIKI_VARIABLE_DEFAULTS, ft as readStoredPinnedSessionKeys, g as RIGHT_SIDEBAR_FILE_TREE_WIDTH_STORAGE_KEY, gt as readStoredSessionDoneDesktopNotificationsEnabled, h as RIGHT_SIDEBAR_ACTIVE_TAB_STORAGE_KEY, ht as readStoredRightSidebarOpen, i as CENTER_MESSAGES_STORAGE_KEY, it as promptDraftKey, j as TitleTooltip, jt as themeFamilyFixedMode, k as THEME_FAMILIES, kt as themeColorModeLabel, l as KeyboardShortcutContent, lt as readStoredCollapsedDirectories, m as RECENT_DIRECTORIES_STORAGE_KEY, mt as readStoredRecentDirectories, n as APPLIED_THEME_STORAGE_KEY, nt as normalizeThemeFamily, o as DRAFT_DIRECTORY_STORAGE_KEY, ot as rawShellCommandTextFromTool, p as PINNED_SESSIONS_STORAGE_KEY, pt as readStoredPromptDraft, r as AUTO_SCROLL_ENABLED_STORAGE_KEY, rt as previewUrlForImage, s as HIDE_TOOL_BLOCKS_STORAGE_KEY, st as readStoredAutoScrollEnabled, tt as normalizeThemeColorMode, ut as readStoredDraftDirectory, v as RIGHT_SIDEBAR_HISTORY_TAB_STORAGE_KEY, vt as readStoredSidebarDirectories, w as SIDEBAR_DIRECTORIES_STORAGE_KEY, wt as rememberStoredTerminalTabs, x as Route, xt as readStoredTheme, y as RIGHT_SIDEBAR_OPEN_STORAGE_KEY, yt as readStoredTerminalPanelOpen } from "./routes-DbjuMLFI.mjs";
|
|
6
6
|
import { i as useQuery, n as useIsMutating, o as useQueryClient, r as useIsFetching, t as useMutation } from "../_libs/tanstack__react-query.mjs";
|
|
7
7
|
import { t as useHotkeys } from "../_libs/tanstack__react-hotkeys.mjs";
|
|
8
8
|
import { a as matchesKeyboardEvent, i as batch, o as formatForDisplay, r as createStore } from "../_libs/@tanstack/hotkeys+[...].mjs";
|
|
@@ -22,7 +22,7 @@ import { t as remarkGfm } from "../_libs/remark-gfm.mjs";
|
|
|
22
22
|
import { a as getBuiltInSpriteSheet, i as getBuiltInFileIconColor, n as FileTree, r as createFileTreeIconResolver, t as useFileTree } from "../_libs/@pierre/trees+[...].mjs";
|
|
23
23
|
import { a as closestCenter, c as useDraggable, d as useSensors, f as CSS$1, i as PointerSensor, n as DragOverlay, t as DndContext, u as useSensor } from "../_libs/@dnd-kit/core+[...].mjs";
|
|
24
24
|
import { a as verticalListSortingStrategy, i as useSortable, n as arrayMove, r as horizontalListSortingStrategy, t as SortableContext } from "../_libs/dnd-kit__sortable.mjs";
|
|
25
|
-
//#region node_modules/.nitro/vite/services/ssr/assets/routes-
|
|
25
|
+
//#region node_modules/.nitro/vite/services/ssr/assets/routes-BsQ26pbY.js
|
|
26
26
|
var import_react = /* @__PURE__ */ __toESM(require_react());
|
|
27
27
|
var import_jsx_runtime = require_jsx_runtime();
|
|
28
28
|
var MOBILE_BREAKPOINT = 768;
|
|
@@ -503,8 +503,9 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange: set
|
|
|
503
503
|
window.addEventListener("keydown", handleKeyDown);
|
|
504
504
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
505
505
|
}, [toggleSidebarRef]);
|
|
506
|
+
const state = open ? "expanded" : "collapsed";
|
|
506
507
|
const contextValue = {
|
|
507
|
-
state
|
|
508
|
+
state,
|
|
508
509
|
open,
|
|
509
510
|
setOpen,
|
|
510
511
|
isMobile,
|
|
@@ -522,6 +523,7 @@ function SidebarProvider({ defaultOpen = true, open: openProp, onOpenChange: set
|
|
|
522
523
|
value: contextValue,
|
|
523
524
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
524
525
|
"data-slot": "sidebar-wrapper",
|
|
526
|
+
"data-sidebar-state": state,
|
|
525
527
|
style: {
|
|
526
528
|
...style,
|
|
527
529
|
"--sidebar-width": sidebarWidth,
|
|
@@ -1096,7 +1098,7 @@ function directoryDialogHasExactMatch(directoryPaths, normalizedQuery) {
|
|
|
1096
1098
|
return normalizedPath === normalizedQuery || normalizedDisplayPath === normalizedQuery;
|
|
1097
1099
|
});
|
|
1098
1100
|
}
|
|
1099
|
-
function splitDisplayPath
|
|
1101
|
+
function splitDisplayPath(value) {
|
|
1100
1102
|
if (!value) return {
|
|
1101
1103
|
leading: "",
|
|
1102
1104
|
trailing: ""
|
|
@@ -1119,7 +1121,7 @@ function splitDisplayPath$1(value) {
|
|
|
1119
1121
|
}
|
|
1120
1122
|
function DirectoryPathLabel$1({ path, prefix }) {
|
|
1121
1123
|
const displayPath = formatDirectoryDisplayPath(path);
|
|
1122
|
-
const { leading, trailing } = splitDisplayPath
|
|
1124
|
+
const { leading, trailing } = splitDisplayPath(displayPath);
|
|
1123
1125
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
1124
1126
|
className: "flex min-w-0 items-center text-foreground",
|
|
1125
1127
|
children: [
|
|
@@ -2427,7 +2429,7 @@ function formatShortcutLabel(hotkey) {
|
|
|
2427
2429
|
function matchesShortcutEvent(event, hotkey) {
|
|
2428
2430
|
return matchesKeyboardEvent(event, hotkey);
|
|
2429
2431
|
}
|
|
2430
|
-
function tildePath
|
|
2432
|
+
function tildePath(value) {
|
|
2431
2433
|
return value.replace(/^\/Users\/[^/]+(?=\/|$)/, "~").replace(/^\/home\/[^/]+(?=\/|$)/, "~");
|
|
2432
2434
|
}
|
|
2433
2435
|
function normalizeDirectories(directories) {
|
|
@@ -2645,6 +2647,8 @@ function AppShellSessionsDialog(props) {
|
|
|
2645
2647
|
}
|
|
2646
2648
|
function useAppShellSessionsDialogView({ open, onOpenChange, viewerContextId, currentDirectory, knownDirectories, directorySessionsByPath, sessionStatusByKey, activeSessionId, activeSessionPath, onSelectSession, onRenameSession, onDeleteSession, onError }) {
|
|
2647
2649
|
const isMobile = useIsMobile();
|
|
2650
|
+
const [isGeneratingName, setIsGeneratingName] = import_react.useState(false);
|
|
2651
|
+
const [generatedNamePath, setGeneratedNamePath] = import_react.useState("");
|
|
2648
2652
|
const [state, dispatch] = import_react.useReducer(sessionsDialogReducer, initialSessionsDialogState);
|
|
2649
2653
|
const { query, scope, stage, selectedSessionKey, renameValue, localSessionNames, loadedSessionsByPath, loadingByPath } = state;
|
|
2650
2654
|
const normalizedCurrentDirectory = currentDirectory.trim();
|
|
@@ -2673,6 +2677,7 @@ function useAppShellSessionsDialogView({ open, onOpenChange, viewerContextId, cu
|
|
|
2673
2677
|
})));
|
|
2674
2678
|
const sortedSessionItems = flatSessions.toSorted((left, right) => sessionActivityTime(right.entry) - sessionActivityTime(left.entry));
|
|
2675
2679
|
const selectedSession = selectedSessionKey ? flatSessions.find((session) => session.key === selectedSessionKey)?.entry : void 0;
|
|
2680
|
+
const canGenerateSelectedSessionName = Boolean(selectedSession?.path && !selectedSession.name?.trim() && generatedNamePath !== selectedSession.path);
|
|
2676
2681
|
const loading = visibleGroups.some((group) => group.loading);
|
|
2677
2682
|
const browseInputRef = import_react.useRef(null);
|
|
2678
2683
|
const deletePanelRef = import_react.useRef(null);
|
|
@@ -2753,6 +2758,7 @@ function useAppShellSessionsDialogView({ open, onOpenChange, viewerContextId, cu
|
|
|
2753
2758
|
};
|
|
2754
2759
|
const renameSelectedSession = () => {
|
|
2755
2760
|
if (!selectedSession?.path) return;
|
|
2761
|
+
setGeneratedNamePath("");
|
|
2756
2762
|
dispatch({
|
|
2757
2763
|
type: "renameRequested",
|
|
2758
2764
|
value: selectedSession.title
|
|
@@ -2769,6 +2775,28 @@ function useAppShellSessionsDialogView({ open, onOpenChange, viewerContextId, cu
|
|
|
2769
2775
|
name: nextName
|
|
2770
2776
|
});
|
|
2771
2777
|
};
|
|
2778
|
+
const generateSelectedSessionName = async () => {
|
|
2779
|
+
const targetPath = selectedSession?.path;
|
|
2780
|
+
if (!targetPath || isGeneratingName || !canGenerateSelectedSessionName) return;
|
|
2781
|
+
setIsGeneratingName(true);
|
|
2782
|
+
try {
|
|
2783
|
+
const response = await fetchJson(buildRequestUrl("/api/session/name", { contextId: viewerContextId }), {
|
|
2784
|
+
method: "POST",
|
|
2785
|
+
headers: { "content-type": "application/json" },
|
|
2786
|
+
body: JSON.stringify({ path: targetPath })
|
|
2787
|
+
});
|
|
2788
|
+
dispatch({
|
|
2789
|
+
type: "renameValueChanged",
|
|
2790
|
+
value: response.name
|
|
2791
|
+
});
|
|
2792
|
+
setGeneratedNamePath(targetPath);
|
|
2793
|
+
if (response.source === "heuristic" && response.reason) toast.info("Using heuristic session name", { description: response.reason });
|
|
2794
|
+
} catch (error) {
|
|
2795
|
+
onError?.(error);
|
|
2796
|
+
} finally {
|
|
2797
|
+
setIsGeneratingName(false);
|
|
2798
|
+
}
|
|
2799
|
+
};
|
|
2772
2800
|
const deleteSelectedSession = () => {
|
|
2773
2801
|
if (!selectedSession?.path) return;
|
|
2774
2802
|
dispatch({ type: "deleteRequested" });
|
|
@@ -2853,7 +2881,7 @@ function useAppShellSessionsDialogView({ open, onOpenChange, viewerContextId, cu
|
|
|
2853
2881
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CommandList, {
|
|
2854
2882
|
className: "max-h-none min-h-0 flex-1 md:max-h-[min(70vh,32rem)]",
|
|
2855
2883
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommandEmpty, { children: loading ? "Loading sessions…" : "No sessions found." }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CommandGroup, {
|
|
2856
|
-
heading: `${scope === "all" ? "All sessions" : `Current directory: ${tildePath
|
|
2884
|
+
heading: `${scope === "all" ? "All sessions" : `Current directory: ${tildePath(currentDirectories[0] || "")}`}${loading ? " · loading" : ""}`,
|
|
2857
2885
|
children: [loading && sortedSessionItems.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(CommandItem, {
|
|
2858
2886
|
value: "loading:sessions",
|
|
2859
2887
|
disabled: true,
|
|
@@ -2889,7 +2917,7 @@ function useAppShellSessionsDialogView({ open, onOpenChange, viewerContextId, cu
|
|
|
2889
2917
|
children: entry.title
|
|
2890
2918
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
2891
2919
|
className: "line-clamp-1 text-xs text-muted-foreground",
|
|
2892
|
-
children: tildePath
|
|
2920
|
+
children: tildePath(entry.cwd || directory)
|
|
2893
2921
|
})]
|
|
2894
2922
|
}),
|
|
2895
2923
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
@@ -2939,25 +2967,37 @@ function useAppShellSessionsDialogView({ open, onOpenChange, viewerContextId, cu
|
|
|
2939
2967
|
children: [
|
|
2940
2968
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2941
2969
|
className: "flex items-center gap-2 border-b border-border/70 px-3 py-2",
|
|
2942
|
-
children: [
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
className: "
|
|
2955
|
-
children: "
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2970
|
+
children: [
|
|
2971
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
2972
|
+
type: "button",
|
|
2973
|
+
variant: "ghost",
|
|
2974
|
+
size: "icon-sm",
|
|
2975
|
+
onClick: () => {
|
|
2976
|
+
dispatch({ type: "browseRequested" });
|
|
2977
|
+
},
|
|
2978
|
+
"aria-label": "Back to sessions",
|
|
2979
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowLeft, {})
|
|
2980
|
+
}),
|
|
2981
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2982
|
+
className: "min-w-0 flex-1",
|
|
2983
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2984
|
+
className: "truncate text-sm font-medium",
|
|
2985
|
+
children: "Rename session"
|
|
2986
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2987
|
+
className: "truncate text-xs text-muted-foreground",
|
|
2988
|
+
children: selectedSession?.title || "Selected session"
|
|
2989
|
+
})]
|
|
2990
|
+
}),
|
|
2991
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
|
|
2992
|
+
type: "button",
|
|
2993
|
+
variant: "ghost",
|
|
2994
|
+
disabled: isGeneratingName || !canGenerateSelectedSessionName,
|
|
2995
|
+
onClick: () => {
|
|
2996
|
+
generateSelectedSessionName();
|
|
2997
|
+
},
|
|
2998
|
+
children: [isGeneratingName ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WandSparkles, {}), "Generate"]
|
|
2999
|
+
})
|
|
3000
|
+
]
|
|
2961
3001
|
}),
|
|
2962
3002
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
2963
3003
|
className: "flex min-h-0 flex-1 items-center p-3",
|
|
@@ -2976,6 +3016,12 @@ function useAppShellSessionsDialogView({ open, onOpenChange, viewerContextId, cu
|
|
|
2976
3016
|
dispatch({ type: "browseRequested" });
|
|
2977
3017
|
return;
|
|
2978
3018
|
}
|
|
3019
|
+
if (matchesShortcutEvent(event.nativeEvent, "Control+G")) {
|
|
3020
|
+
event.preventDefault();
|
|
3021
|
+
event.stopPropagation();
|
|
3022
|
+
generateSelectedSessionName();
|
|
3023
|
+
return;
|
|
3024
|
+
}
|
|
2979
3025
|
if (event.key !== "Enter" || event.nativeEvent.isComposing) return;
|
|
2980
3026
|
event.preventDefault();
|
|
2981
3027
|
event.stopPropagation();
|
|
@@ -2987,13 +3033,20 @@ function useAppShellSessionsDialogView({ open, onOpenChange, viewerContextId, cu
|
|
|
2987
3033
|
}),
|
|
2988
3034
|
isMobile ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
2989
3035
|
className: "hidden flex-wrap items-center gap-x-3 gap-y-1 border-t border-border/70 px-3 py-2 text-xs text-muted-foreground md:flex",
|
|
2990
|
-
children: [
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
3036
|
+
children: [
|
|
3037
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
3038
|
+
className: "inline-flex items-center gap-1",
|
|
3039
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FooterKbd$1, { children: formatShortcutLabel("Control+G") }), " Generate"]
|
|
3040
|
+
}),
|
|
3041
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
3042
|
+
className: "inline-flex items-center gap-1",
|
|
3043
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FooterKbd$1, { children: "Enter" }), " Save"]
|
|
3044
|
+
}),
|
|
3045
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
3046
|
+
className: "inline-flex items-center gap-1",
|
|
3047
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FooterKbd$1, { children: "Esc" }), " Back"]
|
|
3048
|
+
})
|
|
3049
|
+
]
|
|
2997
3050
|
})
|
|
2998
3051
|
]
|
|
2999
3052
|
});
|
|
@@ -7576,7 +7629,7 @@ function GitCommitDialogController({ viewerContextId, cwd, openStateRef, ref })
|
|
|
7576
7629
|
function FooterKbd({ children }) {
|
|
7577
7630
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Kbd, { children });
|
|
7578
7631
|
}
|
|
7579
|
-
function RenameSessionDialog({ open, onOpenChange, renameValue, onRenameValueChange, onRenameSession }) {
|
|
7632
|
+
function RenameSessionDialog({ open, onOpenChange, renameValue, generatingName, canGenerateName, onRenameValueChange, onGenerateSessionName, onRenameSession }) {
|
|
7580
7633
|
const isMobile = useIsMobile();
|
|
7581
7634
|
const renameInputRef = import_react.useRef(null);
|
|
7582
7635
|
import_react.useEffect(() => {
|
|
@@ -7593,13 +7646,22 @@ function RenameSessionDialog({ open, onOpenChange, renameValue, onRenameValueCha
|
|
|
7593
7646
|
className: "flex min-h-0 flex-1 flex-col",
|
|
7594
7647
|
children: [
|
|
7595
7648
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
7596
|
-
className: "border-b border-border/70 px-3 py-2",
|
|
7597
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.
|
|
7598
|
-
className: "
|
|
7599
|
-
children: "
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7649
|
+
className: "flex items-center gap-2 border-b border-border/70 px-3 py-2",
|
|
7650
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
7651
|
+
className: "min-w-0 flex-1",
|
|
7652
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
7653
|
+
className: "truncate text-sm font-medium",
|
|
7654
|
+
children: "Rename session"
|
|
7655
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
7656
|
+
className: "truncate text-xs text-muted-foreground",
|
|
7657
|
+
children: "Update the display name shown in the sidebar."
|
|
7658
|
+
})]
|
|
7659
|
+
}), isMobile ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
|
|
7660
|
+
type: "button",
|
|
7661
|
+
variant: "ghost",
|
|
7662
|
+
disabled: generatingName || !canGenerateName,
|
|
7663
|
+
onClick: onGenerateSessionName,
|
|
7664
|
+
children: [generatingName ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WandSparkles, {}), "Generate"]
|
|
7603
7665
|
})]
|
|
7604
7666
|
}),
|
|
7605
7667
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
@@ -7615,6 +7677,12 @@ function RenameSessionDialog({ open, onOpenChange, renameValue, onRenameValueCha
|
|
|
7615
7677
|
onOpenChange(false);
|
|
7616
7678
|
return;
|
|
7617
7679
|
}
|
|
7680
|
+
if (event.ctrlKey && event.key.toLowerCase() === "g") {
|
|
7681
|
+
event.preventDefault();
|
|
7682
|
+
event.stopPropagation();
|
|
7683
|
+
onGenerateSessionName();
|
|
7684
|
+
return;
|
|
7685
|
+
}
|
|
7618
7686
|
if (event.key !== "Enter" || event.nativeEvent.isComposing) return;
|
|
7619
7687
|
event.preventDefault();
|
|
7620
7688
|
event.stopPropagation();
|
|
@@ -7626,13 +7694,24 @@ function RenameSessionDialog({ open, onOpenChange, renameValue, onRenameValueCha
|
|
|
7626
7694
|
}),
|
|
7627
7695
|
isMobile ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
7628
7696
|
className: "hidden flex-wrap items-center gap-x-3 gap-y-1 border-t border-border/70 px-3 py-2 text-xs text-muted-foreground md:flex",
|
|
7629
|
-
children: [
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7697
|
+
children: [
|
|
7698
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
7699
|
+
className: "inline-flex items-center gap-1",
|
|
7700
|
+
children: [
|
|
7701
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FooterKbd, { children: "Ctrl" }),
|
|
7702
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FooterKbd, { children: "G" }),
|
|
7703
|
+
" Generate"
|
|
7704
|
+
]
|
|
7705
|
+
}),
|
|
7706
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
7707
|
+
className: "inline-flex items-center gap-1",
|
|
7708
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FooterKbd, { children: "Enter" }), " Save"]
|
|
7709
|
+
}),
|
|
7710
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
7711
|
+
className: "inline-flex items-center gap-1",
|
|
7712
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FooterKbd, { children: "Esc" }), " Cancel"]
|
|
7713
|
+
})
|
|
7714
|
+
]
|
|
7636
7715
|
})
|
|
7637
7716
|
]
|
|
7638
7717
|
});
|
|
@@ -7650,14 +7729,23 @@ function RenameSessionDialog({ open, onOpenChange, renameValue, onRenameValueCha
|
|
|
7650
7729
|
}),
|
|
7651
7730
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DrawerFooter, {
|
|
7652
7731
|
className: "border-t border-border/70",
|
|
7653
|
-
children: [
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7732
|
+
children: [
|
|
7733
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
|
|
7734
|
+
variant: "outline",
|
|
7735
|
+
disabled: generatingName || !canGenerateName,
|
|
7736
|
+
onClick: onGenerateSessionName,
|
|
7737
|
+
children: [generatingName ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WandSparkles, {}), "Generate"]
|
|
7738
|
+
}),
|
|
7739
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
7740
|
+
variant: "outline",
|
|
7741
|
+
onClick: () => onOpenChange(false),
|
|
7742
|
+
children: "Cancel"
|
|
7743
|
+
}),
|
|
7744
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
7745
|
+
onClick: onRenameSession,
|
|
7746
|
+
children: "Save"
|
|
7747
|
+
})
|
|
7748
|
+
]
|
|
7661
7749
|
})
|
|
7662
7750
|
]
|
|
7663
7751
|
})
|
|
@@ -7672,9 +7760,11 @@ function RenameSessionDialog({ open, onOpenChange, renameValue, onRenameValueCha
|
|
|
7672
7760
|
children: body
|
|
7673
7761
|
});
|
|
7674
7762
|
}
|
|
7675
|
-
function RenameSessionDialogController({ ref, openStateRef, onRenameSession }) {
|
|
7763
|
+
function RenameSessionDialogController({ ref, openStateRef, viewerContextId, onRenameSession }) {
|
|
7676
7764
|
const [open, setOpen] = import_react.useState(false);
|
|
7677
7765
|
const [renameValue, setRenameValue] = import_react.useState("");
|
|
7766
|
+
const [isGeneratingName, setIsGeneratingName] = import_react.useState(false);
|
|
7767
|
+
const [canGenerateName, setCanGenerateName] = import_react.useState(false);
|
|
7678
7768
|
const targetPathRef = import_react.useRef("");
|
|
7679
7769
|
const openRef = import_react.useRef(open);
|
|
7680
7770
|
const setOpenState = (nextOpen) => {
|
|
@@ -7687,8 +7777,27 @@ function RenameSessionDialogController({ ref, openStateRef, onRenameSession }) {
|
|
|
7687
7777
|
if (!nextPath) return;
|
|
7688
7778
|
targetPathRef.current = nextPath;
|
|
7689
7779
|
setRenameValue(target.title);
|
|
7780
|
+
setCanGenerateName(!target.hasGeneratedName);
|
|
7690
7781
|
setOpenState(true);
|
|
7691
7782
|
};
|
|
7783
|
+
const generateSessionName = async () => {
|
|
7784
|
+
if (!viewerContextId || !targetPathRef.current || isGeneratingName || !canGenerateName) return;
|
|
7785
|
+
setIsGeneratingName(true);
|
|
7786
|
+
try {
|
|
7787
|
+
const response = await fetchJson(buildRequestUrl("/api/session/name", { contextId: viewerContextId }), {
|
|
7788
|
+
method: "POST",
|
|
7789
|
+
headers: { "content-type": "application/json" },
|
|
7790
|
+
body: JSON.stringify({ path: targetPathRef.current })
|
|
7791
|
+
});
|
|
7792
|
+
setRenameValue(response.name);
|
|
7793
|
+
setCanGenerateName(false);
|
|
7794
|
+
if (response.source === "heuristic" && response.reason) toast.info("Using heuristic session name", { description: response.reason });
|
|
7795
|
+
} catch (error) {
|
|
7796
|
+
toast.error(error instanceof Error ? error.message : "Failed to generate session name");
|
|
7797
|
+
} finally {
|
|
7798
|
+
setIsGeneratingName(false);
|
|
7799
|
+
}
|
|
7800
|
+
};
|
|
7692
7801
|
const submitRename = async () => {
|
|
7693
7802
|
if (await onRenameSession(targetPathRef.current, renameValue) === false) return;
|
|
7694
7803
|
setOpenState(false);
|
|
@@ -7699,7 +7808,8 @@ function RenameSessionDialogController({ ref, openStateRef, onRenameSession }) {
|
|
|
7699
7808
|
if (!entry.path) return;
|
|
7700
7809
|
openTarget({
|
|
7701
7810
|
path: entry.path,
|
|
7702
|
-
title: entry.title || ""
|
|
7811
|
+
title: entry.title || "",
|
|
7812
|
+
hasGeneratedName: Boolean(entry.name?.trim())
|
|
7703
7813
|
});
|
|
7704
7814
|
},
|
|
7705
7815
|
close: () => {
|
|
@@ -7713,7 +7823,12 @@ function RenameSessionDialogController({ ref, openStateRef, onRenameSession }) {
|
|
|
7713
7823
|
setOpenState(nextOpen);
|
|
7714
7824
|
},
|
|
7715
7825
|
renameValue,
|
|
7826
|
+
generatingName: isGeneratingName,
|
|
7827
|
+
canGenerateName: canGenerateName && Boolean(viewerContextId && targetPathRef.current),
|
|
7716
7828
|
onRenameValueChange: setRenameValue,
|
|
7829
|
+
onGenerateSessionName: () => {
|
|
7830
|
+
generateSessionName();
|
|
7831
|
+
},
|
|
7717
7832
|
onRenameSession: () => {
|
|
7718
7833
|
submitRename();
|
|
7719
7834
|
}
|
|
@@ -7817,19 +7932,22 @@ function DeleteSessionsDialog({ open, onOpenChange, title, description, targets,
|
|
|
7817
7932
|
})
|
|
7818
7933
|
]
|
|
7819
7934
|
});
|
|
7820
|
-
if (isMobile) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
7935
|
+
if (isMobile) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dialog$1, {
|
|
7821
7936
|
open,
|
|
7822
7937
|
onOpenChange,
|
|
7823
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
7824
|
-
className: "max-h-[90svh] overflow-hidden",
|
|
7938
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogContent, {
|
|
7939
|
+
className: "max-h-[90svh] overflow-hidden p-0",
|
|
7825
7940
|
children: [
|
|
7826
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
7941
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogHeader, {
|
|
7942
|
+
className: "sr-only",
|
|
7943
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogTitle, { children: title }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogDescription, { children: description })]
|
|
7944
|
+
}),
|
|
7827
7945
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
7828
|
-
className: "flex min-h-0 flex-1 flex-col overflow-hidden
|
|
7946
|
+
className: "flex min-h-0 flex-1 flex-col overflow-hidden",
|
|
7829
7947
|
children: body
|
|
7830
7948
|
}),
|
|
7831
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
7832
|
-
className: "border-t border-border/70",
|
|
7949
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogFooter, {
|
|
7950
|
+
className: "flex-col-reverse gap-2 border-t border-border/70 p-3 sm:flex-row",
|
|
7833
7951
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
7834
7952
|
variant: "outline",
|
|
7835
7953
|
onClick: () => onOpenChange(false),
|
|
@@ -8368,10 +8486,11 @@ var AppShellMoveSessionDirectoryDialogHost = import_react.memo(function AppShell
|
|
|
8368
8486
|
})
|
|
8369
8487
|
});
|
|
8370
8488
|
});
|
|
8371
|
-
var AppShellRenameSessionDialogHost = import_react.memo(function AppShellRenameSessionDialogHost({ renameDialogRef, renameOpenRef, renameSessionPath }) {
|
|
8489
|
+
var AppShellRenameSessionDialogHost = import_react.memo(function AppShellRenameSessionDialogHost({ renameDialogRef, renameOpenRef, renameSessionPath, viewerContextId }) {
|
|
8372
8490
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RenameSessionDialogController, {
|
|
8373
8491
|
ref: renameDialogRef,
|
|
8374
8492
|
openStateRef: renameOpenRef,
|
|
8493
|
+
viewerContextId,
|
|
8375
8494
|
onRenameSession: renameSessionPath
|
|
8376
8495
|
});
|
|
8377
8496
|
});
|
|
@@ -8513,7 +8632,8 @@ var AppShellFloatingControllers = import_react.memo(function AppShellFloatingCon
|
|
|
8513
8632
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppShellRenameSessionDialogHost, {
|
|
8514
8633
|
renameDialogRef,
|
|
8515
8634
|
renameOpenRef,
|
|
8516
|
-
renameSessionPath
|
|
8635
|
+
renameSessionPath,
|
|
8636
|
+
viewerContextId
|
|
8517
8637
|
}),
|
|
8518
8638
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppShellDeleteSessionsDialogHost, {
|
|
8519
8639
|
deleteDialogRef,
|
|
@@ -8859,7 +8979,7 @@ function pendingMessageEditReducer(state, action) {
|
|
|
8859
8979
|
};
|
|
8860
8980
|
}
|
|
8861
8981
|
}
|
|
8862
|
-
var ComposerPendingMessages = import_react.memo(function ComposerPendingMessages({ currentPendingMessages, onEditPendingMessage, onRemovePendingMessage, onReorderPending }) {
|
|
8982
|
+
var ComposerPendingMessages = import_react.memo(function ComposerPendingMessages({ currentPendingMessages, canStartQueue, onEditPendingMessage, onRemovePendingMessage, onReorderPending, onStartPendingQueue }) {
|
|
8863
8983
|
const [editState, dispatchEditState] = import_react.useReducer(pendingMessageEditReducer, EMPTY_PENDING_MESSAGE_EDIT_STATE);
|
|
8864
8984
|
const [openSections, setOpenSections] = import_react.useState([]);
|
|
8865
8985
|
const { editingPendingId, editText, editError } = editState;
|
|
@@ -8898,19 +9018,26 @@ var ComposerPendingMessages = import_react.memo(function ComposerPendingMessages
|
|
|
8898
9018
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(AccordionItem, {
|
|
8899
9019
|
value: "pending-prompts",
|
|
8900
9020
|
className: "border-0",
|
|
8901
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.
|
|
8902
|
-
className: "min-h-10 items-center gap-
|
|
8903
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.
|
|
8904
|
-
className: "
|
|
8905
|
-
children:
|
|
8906
|
-
className: "
|
|
8907
|
-
children: "
|
|
8908
|
-
|
|
8909
|
-
|
|
8910
|
-
|
|
8911
|
-
|
|
8912
|
-
|
|
8913
|
-
|
|
9021
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
9022
|
+
className: "flex min-h-10 items-center gap-2 px-3 py-2",
|
|
9023
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AccordionTrigger, {
|
|
9024
|
+
className: "min-h-0 flex-1 p-0 hover:no-underline",
|
|
9025
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
9026
|
+
className: "flex min-w-0 items-center gap-2 text-sm font-medium",
|
|
9027
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
9028
|
+
className: "truncate",
|
|
9029
|
+
children: "Queue"
|
|
9030
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
|
|
9031
|
+
variant: "outline",
|
|
9032
|
+
className: "shrink-0",
|
|
9033
|
+
children: currentPendingMessages.length
|
|
9034
|
+
})]
|
|
9035
|
+
})
|
|
9036
|
+
}), canStartQueue ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
9037
|
+
size: "sm",
|
|
9038
|
+
onClick: onStartPendingQueue,
|
|
9039
|
+
children: "Start"
|
|
9040
|
+
}) : null]
|
|
8914
9041
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AccordionContent, {
|
|
8915
9042
|
className: "p-0",
|
|
8916
9043
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
@@ -10618,10 +10745,9 @@ var PICO_DIFF_COLOR_CSS = `
|
|
|
10618
10745
|
--diffs-bg-deletion-emphasis-override: color-mix(in lab, var(--diffs-bg) 42%, var(--diffs-deletion-base));
|
|
10619
10746
|
}
|
|
10620
10747
|
|
|
10621
|
-
|
|
10622
|
-
|
|
10623
|
-
|
|
10624
|
-
}
|
|
10748
|
+
[data-overflow="wrap"] [data-annotation-content] {
|
|
10749
|
+
inline-size: var(--diffs-column-content-width, auto);
|
|
10750
|
+
max-inline-size: min(100%, calc(100vw - 1rem));
|
|
10625
10751
|
}
|
|
10626
10752
|
|
|
10627
10753
|
[data-line-type="change-addition"]:is(
|
|
@@ -10712,7 +10838,7 @@ function assistantBlockKey(block) {
|
|
|
10712
10838
|
case "text": return `text:${block.text}`;
|
|
10713
10839
|
case "thinking": return `thinking:${block.text}`;
|
|
10714
10840
|
case "tool": return `tool:${block.callId || block.name || "tool"}:${toolArgsKey(block.args)}`;
|
|
10715
|
-
case "compaction": return `compaction:${block.tokensBefore}:${block.summary}`;
|
|
10841
|
+
case "compaction": return `compaction:${block.tokensBefore}:${block.estimatedTokensAfter ?? ""}:${block.summary}`;
|
|
10716
10842
|
default: return "block";
|
|
10717
10843
|
}
|
|
10718
10844
|
}
|
|
@@ -10813,22 +10939,7 @@ function formatToolArgString(value) {
|
|
|
10813
10939
|
return trimmed;
|
|
10814
10940
|
}
|
|
10815
10941
|
function rawShellCommandText(block) {
|
|
10816
|
-
|
|
10817
|
-
if (typeof block.args === "string") {
|
|
10818
|
-
const trimmed = block.args.trim();
|
|
10819
|
-
if (!trimmed) return "";
|
|
10820
|
-
try {
|
|
10821
|
-
const parsed = JSON.parse(trimmed);
|
|
10822
|
-
if (parsed && typeof parsed === "object" && "command" in parsed) {
|
|
10823
|
-
const command = parsed.command;
|
|
10824
|
-
return typeof command === "string" ? command.trim() : trimmed;
|
|
10825
|
-
}
|
|
10826
|
-
} catch {
|
|
10827
|
-
return trimmed;
|
|
10828
|
-
}
|
|
10829
|
-
return trimmed;
|
|
10830
|
-
}
|
|
10831
|
-
return getToolArgText(normalizeToolArgs(block.args), "command") || toolCommandPreview(block);
|
|
10942
|
+
return block.type === "tool" ? rawShellCommandTextFromTool(block.name, block.args) : "";
|
|
10832
10943
|
}
|
|
10833
10944
|
function toolCallText(block) {
|
|
10834
10945
|
if (block.type !== "tool") return "";
|
|
@@ -10862,64 +10973,12 @@ function toolOutputText(block) {
|
|
|
10862
10973
|
if (block.isError) return "Tool failed with no output.";
|
|
10863
10974
|
return "No output available.";
|
|
10864
10975
|
}
|
|
10865
|
-
var EXPLORE_TOOL_NAMES = new Set([
|
|
10866
|
-
"read",
|
|
10867
|
-
"grep",
|
|
10868
|
-
"glob",
|
|
10869
|
-
"find",
|
|
10870
|
-
"ls",
|
|
10871
|
-
"list",
|
|
10872
|
-
"rg"
|
|
10873
|
-
]);
|
|
10874
|
-
var EXPLORE_SHELL_COMMAND_NAMES = new Set([
|
|
10875
|
-
"find",
|
|
10876
|
-
"grep",
|
|
10877
|
-
"ls",
|
|
10878
|
-
"rg"
|
|
10879
|
-
]);
|
|
10880
|
-
var SKIPPABLE_SHELL_COMMAND_NAMES = new Set([
|
|
10881
|
-
"cd",
|
|
10882
|
-
"export",
|
|
10883
|
-
"pwd",
|
|
10884
|
-
"set"
|
|
10885
|
-
]);
|
|
10886
|
-
var SHELL_COMMAND_WRAPPER_NAMES = new Set([
|
|
10887
|
-
"command",
|
|
10888
|
-
"env",
|
|
10889
|
-
"noglob",
|
|
10890
|
-
"sudo",
|
|
10891
|
-
"time"
|
|
10892
|
-
]);
|
|
10893
|
-
function shellCommandNameFromSegment(segment) {
|
|
10894
|
-
let text = segment.trim();
|
|
10895
|
-
while (text) {
|
|
10896
|
-
const assignmentMatch = text.match(/^[A-Za-z_][A-Za-z0-9_]*=\S+\s+/);
|
|
10897
|
-
if (assignmentMatch) {
|
|
10898
|
-
text = text.slice(assignmentMatch[0].length).trimStart();
|
|
10899
|
-
continue;
|
|
10900
|
-
}
|
|
10901
|
-
const commandMatch = text.match(/^([./A-Za-z0-9_-]+)\b/);
|
|
10902
|
-
if (!commandMatch) return "";
|
|
10903
|
-
const commandPath = commandMatch[1] || "";
|
|
10904
|
-
const commandName = pathBaseName$1(commandPath);
|
|
10905
|
-
if (!SHELL_COMMAND_WRAPPER_NAMES.has(commandName)) return commandName;
|
|
10906
|
-
text = text.slice(commandPath.length).trimStart();
|
|
10907
|
-
}
|
|
10908
|
-
return "";
|
|
10909
|
-
}
|
|
10910
10976
|
function exploreShellCommandName(block) {
|
|
10911
|
-
|
|
10912
|
-
const segments = rawShellCommandText(block).split(/(?:&&|\|\||;)/);
|
|
10913
|
-
for (const segment of segments) {
|
|
10914
|
-
const commandName = shellCommandNameFromSegment(segment);
|
|
10915
|
-
if (!commandName || SKIPPABLE_SHELL_COMMAND_NAMES.has(commandName)) continue;
|
|
10916
|
-
return EXPLORE_SHELL_COMMAND_NAMES.has(commandName) ? commandName : "";
|
|
10917
|
-
}
|
|
10918
|
-
return "";
|
|
10977
|
+
return block.type === "tool" ? exploreShellCommandNameFromTool(block.name, block.args) : "";
|
|
10919
10978
|
}
|
|
10920
10979
|
function matchesExploreToolBlock(block) {
|
|
10921
10980
|
if (block.type !== "tool") return false;
|
|
10922
|
-
return block.category === "explore" ||
|
|
10981
|
+
return block.category === "explore" || toolCategoryFromTool(block.name, block.args) === "explore";
|
|
10923
10982
|
}
|
|
10924
10983
|
function isExploreToolBlock(block) {
|
|
10925
10984
|
return matchesExploreToolBlock(block);
|
|
@@ -10927,7 +10986,10 @@ function isExploreToolBlock(block) {
|
|
|
10927
10986
|
function isPendingUnclassifiedToolBlock(block) {
|
|
10928
10987
|
if (block.type !== "tool" || !block.running || matchesExploreToolBlock(block)) return false;
|
|
10929
10988
|
if (!block.name) return true;
|
|
10930
|
-
if (block.name === "bash")
|
|
10989
|
+
if (block.name === "bash") {
|
|
10990
|
+
const category = toolCategoryFromTool(block.name, block.args);
|
|
10991
|
+
return !rawShellCommandText(block) || category !== "explore" && (toolArgsAreIncompleteJsonObject(block.args) || toolCouldBecomeExploreFromTool(block.name, block.args));
|
|
10992
|
+
}
|
|
10931
10993
|
return false;
|
|
10932
10994
|
}
|
|
10933
10995
|
function getToolArgNumber(args, key) {
|
|
@@ -11078,7 +11140,7 @@ function sameAssistantBlock(left, right) {
|
|
|
11078
11140
|
return left.callId === right.callId && left.name === right.name && left.category === right.category && left.output === right.output && left.isError === right.isError && left.running === right.running && sameUnknownValue(left.args, right.args) && sameUnknownValue(left.details, right.details);
|
|
11079
11141
|
case "compaction":
|
|
11080
11142
|
if (right.type !== "compaction") return false;
|
|
11081
|
-
return left.summary === right.summary && left.tokensBefore === right.tokensBefore;
|
|
11143
|
+
return left.summary === right.summary && left.tokensBefore === right.tokensBefore && left.estimatedTokensAfter === right.estimatedTokensAfter;
|
|
11082
11144
|
default: return false;
|
|
11083
11145
|
}
|
|
11084
11146
|
}
|
|
@@ -11415,7 +11477,8 @@ function useAssistantToolGroupBodyBlocks(store, keys, enabled) {
|
|
|
11415
11477
|
}
|
|
11416
11478
|
function compactionTriggerText(block) {
|
|
11417
11479
|
if (block.type !== "compaction") return "Compaction";
|
|
11418
|
-
|
|
11480
|
+
if (block.tokensBefore <= 0) return "Compaction";
|
|
11481
|
+
return block.estimatedTokensAfter && block.estimatedTokensAfter > 0 ? `Compaction: ${block.tokensBefore.toLocaleString()} → ~${block.estimatedTokensAfter.toLocaleString()} tokens` : `Compaction: Compacted from ${block.tokensBefore.toLocaleString()} tokens`;
|
|
11419
11482
|
}
|
|
11420
11483
|
var ANSI_16_COLORS = [
|
|
11421
11484
|
"#3f3f46",
|
|
@@ -11725,7 +11788,7 @@ function PlainToolOutput({ isError = false, text }) {
|
|
|
11725
11788
|
children: text
|
|
11726
11789
|
});
|
|
11727
11790
|
}
|
|
11728
|
-
function scrollDistanceFromBottom(element) {
|
|
11791
|
+
function scrollDistanceFromBottom$1(element) {
|
|
11729
11792
|
return element.scrollHeight - element.clientHeight - element.scrollTop;
|
|
11730
11793
|
}
|
|
11731
11794
|
function scrollElementToBottom(element) {
|
|
@@ -11749,7 +11812,7 @@ function useRunningToolAutoScroll({ contentKey, enabled }) {
|
|
|
11749
11812
|
}, [contentKey, enabled]);
|
|
11750
11813
|
const handleScroll = (event) => {
|
|
11751
11814
|
if (!enabled) return;
|
|
11752
|
-
autoScrollRef.current = scrollDistanceFromBottom(event.currentTarget) < 1;
|
|
11815
|
+
autoScrollRef.current = scrollDistanceFromBottom$1(event.currentTarget) < 1;
|
|
11753
11816
|
};
|
|
11754
11817
|
return {
|
|
11755
11818
|
onScroll: handleScroll,
|
|
@@ -12055,53 +12118,67 @@ var UserMessageCard = import_react.memo(function UserMessageCard({ item }) {
|
|
|
12055
12118
|
const selectedImage = selectedImageIndex === null ? null : item.images[selectedImageIndex] ?? null;
|
|
12056
12119
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12057
12120
|
className: "mr-2 ml-auto w-fit max-w-[80%]",
|
|
12058
|
-
children: [
|
|
12059
|
-
|
|
12060
|
-
|
|
12061
|
-
|
|
12062
|
-
|
|
12063
|
-
|
|
12064
|
-
|
|
12065
|
-
|
|
12066
|
-
|
|
12067
|
-
|
|
12068
|
-
|
|
12069
|
-
|
|
12070
|
-
|
|
12071
|
-
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
|
|
12075
|
-
|
|
12076
|
-
|
|
12077
|
-
|
|
12078
|
-
|
|
12079
|
-
|
|
12080
|
-
|
|
12081
|
-
|
|
12082
|
-
|
|
12083
|
-
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
|
|
12087
|
-
|
|
12088
|
-
|
|
12089
|
-
|
|
12090
|
-
|
|
12091
|
-
|
|
12092
|
-
|
|
12093
|
-
|
|
12094
|
-
|
|
12095
|
-
|
|
12096
|
-
|
|
12097
|
-
|
|
12098
|
-
|
|
12099
|
-
|
|
12100
|
-
|
|
12101
|
-
|
|
12102
|
-
|
|
12121
|
+
children: [
|
|
12122
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12123
|
+
className: "relative rounded-3xl bg-primary px-5 py-2.5 text-primary-foreground before:absolute before:-right-1.75 before:bottom-0 before:h-5.5 before:w-4 before:rounded-bl-[16px_14px] before:bg-primary before:content-[''] after:absolute after:-right-6.5 after:bottom-0 after:h-6.25 after:w-6.5 after:rounded-bl-[10px] after:bg-background after:content-['']",
|
|
12124
|
+
children: [
|
|
12125
|
+
labelText ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12126
|
+
className: "mb-2 flex items-center gap-2",
|
|
12127
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Badge, {
|
|
12128
|
+
variant: "outline",
|
|
12129
|
+
className: "border-primary-foreground/35 bg-primary-foreground/10 text-primary-foreground",
|
|
12130
|
+
children: labelText
|
|
12131
|
+
})
|
|
12132
|
+
}) : null,
|
|
12133
|
+
item.text ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12134
|
+
className: "text-sm break-words whitespace-pre-wrap text-primary-foreground",
|
|
12135
|
+
children: item.text
|
|
12136
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12137
|
+
className: "text-sm text-primary-foreground/80",
|
|
12138
|
+
children: "Image prompt"
|
|
12139
|
+
}),
|
|
12140
|
+
item.images.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12141
|
+
className: "mt-3 flex flex-wrap gap-3",
|
|
12142
|
+
children: item.images.map((image, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", {
|
|
12143
|
+
type: "button",
|
|
12144
|
+
className: "max-w-full cursor-zoom-in overflow-hidden rounded-lg border border-primary-foreground/20 bg-primary-foreground/10 p-0 transition hover:opacity-90 focus-visible:ring-2 focus-visible:ring-primary-foreground/70 focus-visible:ring-offset-2 focus-visible:ring-offset-primary focus-visible:outline-none",
|
|
12145
|
+
onClick: () => setSelectedImageIndex(index),
|
|
12146
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", {
|
|
12147
|
+
src: image.previewUrl,
|
|
12148
|
+
alt: "Prompt upload",
|
|
12149
|
+
className: "block h-28 max-w-full object-cover"
|
|
12150
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12151
|
+
className: "sr-only",
|
|
12152
|
+
children: "Open prompt upload"
|
|
12153
|
+
})]
|
|
12154
|
+
}, `${promptImageKey(image)}:${index}`))
|
|
12155
|
+
}) : null
|
|
12156
|
+
]
|
|
12157
|
+
}),
|
|
12158
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(UserMessageFooter, { copyText: item.text }),
|
|
12159
|
+
selectedImage ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ImageLightbox, {
|
|
12160
|
+
open: true,
|
|
12161
|
+
onOpenChange: (open) => {
|
|
12162
|
+
if (!open) setSelectedImageIndex(null);
|
|
12163
|
+
},
|
|
12164
|
+
imageSrc: selectedImage.previewUrl,
|
|
12165
|
+
imageAlt: "Prompt upload",
|
|
12166
|
+
title: "Prompt upload preview",
|
|
12167
|
+
description: "Expanded preview of an image attached to a user message."
|
|
12168
|
+
}) : null
|
|
12169
|
+
]
|
|
12103
12170
|
});
|
|
12104
12171
|
});
|
|
12172
|
+
function UserMessageFooter({ copyText }) {
|
|
12173
|
+
if (!copyText.trim()) return null;
|
|
12174
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
12175
|
+
className: "mt-1 flex justify-end gap-1.5 text-xs font-medium text-muted-foreground",
|
|
12176
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MessageFooterCopyButton, {
|
|
12177
|
+
idleLabel: "Copy user message",
|
|
12178
|
+
text: copyText
|
|
12179
|
+
})
|
|
12180
|
+
});
|
|
12181
|
+
}
|
|
12105
12182
|
function assistantBlockIsVisible({ block, hideThinking, hideToolBlocks }) {
|
|
12106
12183
|
switch (block.type) {
|
|
12107
12184
|
case "text": return Boolean(block.text.trim());
|
|
@@ -12200,7 +12277,7 @@ function AssistantBlockGroupsView({ anchorBlockKey, store, streaming }) {
|
|
|
12200
12277
|
streaming
|
|
12201
12278
|
}, descriptor.key)) });
|
|
12202
12279
|
}
|
|
12203
|
-
function
|
|
12280
|
+
function MessageFooterCopyButton({ className, idleLabel, text }) {
|
|
12204
12281
|
const [copyState, setCopyState] = import_react.useState("idle");
|
|
12205
12282
|
const canCopy = Boolean(text.trim());
|
|
12206
12283
|
const copyMessage = async () => {
|
|
@@ -12214,13 +12291,13 @@ function AssistantMessageFooterCopyButton({ text }) {
|
|
|
12214
12291
|
window.setTimeout(() => setCopyState("idle"), 1400);
|
|
12215
12292
|
}
|
|
12216
12293
|
};
|
|
12217
|
-
const label = copyState === "copied" ? "Copied" : copyState === "error" ? "Retry copy" :
|
|
12294
|
+
const label = copyState === "copied" ? "Copied" : copyState === "error" ? "Retry copy" : idleLabel;
|
|
12218
12295
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
12219
12296
|
title: label,
|
|
12220
12297
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
12221
12298
|
variant: "ghost",
|
|
12222
12299
|
size: "icon-xs",
|
|
12223
|
-
className: "
|
|
12300
|
+
className: cn("text-muted-foreground", className),
|
|
12224
12301
|
disabled: !canCopy,
|
|
12225
12302
|
"aria-label": label,
|
|
12226
12303
|
onClick: copyMessage,
|
|
@@ -12234,7 +12311,11 @@ function AssistantMessageFooter({ copyText, modelLabel, streaming }) {
|
|
|
12234
12311
|
if (!showCopyButton && !modelLabel) return null;
|
|
12235
12312
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12236
12313
|
className: "-mt-2 flex items-center gap-1.5 text-xs font-medium text-muted-foreground",
|
|
12237
|
-
children: [showCopyButton ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
12314
|
+
children: [showCopyButton ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MessageFooterCopyButton, {
|
|
12315
|
+
className: "-ml-2",
|
|
12316
|
+
idleLabel: "Copy assistant message",
|
|
12317
|
+
text: copyText
|
|
12318
|
+
}) : null, modelLabel ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
12238
12319
|
className: "truncate",
|
|
12239
12320
|
children: modelLabel
|
|
12240
12321
|
}) : null]
|
|
@@ -12264,7 +12345,7 @@ function AssistantMessagesStoreCard({ className, hideFooter = false, store }) {
|
|
|
12264
12345
|
store
|
|
12265
12346
|
]);
|
|
12266
12347
|
const shellSnapshot = import_react.useSyncExternalStore(shellStore.subscribe, shellStore.getSnapshot, shellStore.getSnapshot);
|
|
12267
|
-
const showFooter = Boolean(!hideFooter && !shellSnapshot.
|
|
12348
|
+
const showFooter = Boolean(!hideFooter && !shellSnapshot.working && shellSnapshot.hasFooter);
|
|
12268
12349
|
if (!shellSnapshot.hasBlocks && !showFooter) return null;
|
|
12269
12350
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12270
12351
|
className: cn("flex flex-col gap-4", className),
|
|
@@ -12765,7 +12846,7 @@ function getClipboardImageFiles(data) {
|
|
|
12765
12846
|
if (itemFiles.length > 0) return itemFiles;
|
|
12766
12847
|
return Array.from(data.files).filter((file) => file.type.startsWith("image/"));
|
|
12767
12848
|
}
|
|
12768
|
-
function ComposerPanel({ activeSessionId, currentPendingMessages, composerDiffLineComments, composerImages, composerText, composerSkill, composerSyncNonce, centerMessages, contextUsageStore, displaySettingsStore, sessionStore, isSubmitting, isStreaming, awaitingFirstTurn, disabled = false, flush = false, topContent, viewerContextId, fileInputRef, onComposerTextChange, onPickImages, onRemoveComposerDiffLineComment, onRemoveComposerImage, onSubmitPrompt, onAbort, onEditPendingMessage, onRemovePendingMessage, onReorderPending, onRunBuiltinSlashCommand, onSelectModel, onSelectThinkingLevel, requestPathCompletions, requestFileCompletions, ref }) {
|
|
12849
|
+
function ComposerPanel({ activeSessionId, currentPendingMessages, composerDiffLineComments, composerImages, composerText, composerSkill, composerSyncNonce, canStartPendingQueue, centerMessages, contextUsageStore, displaySettingsStore, sessionStore, isSubmitting, isCompacting, isStreaming, awaitingFirstTurn, disabled = false, flush = false, topContent, viewerContextId, fileInputRef, onComposerTextChange, onPickImages, onRemoveComposerDiffLineComment, onRemoveComposerImage, onSubmitPrompt, onAbort, onEditPendingMessage, onRemovePendingMessage, onReorderPending, onStartPendingQueue, onRunBuiltinSlashCommand, onSelectModel, onSelectThinkingLevel, requestPathCompletions, requestFileCompletions, ref }) {
|
|
12769
12850
|
const promptRef = import_react.useRef(null);
|
|
12770
12851
|
const [pickerState, dispatchPickerState] = import_react.useReducer(composerPickerReducer, INITIAL_COMPOSER_PICKER_STATE);
|
|
12771
12852
|
const { modelPickerOpen, thinkingPickerOpen, modelQuery } = pickerState;
|
|
@@ -12792,9 +12873,11 @@ function ComposerPanel({ activeSessionId, currentPendingMessages, composerDiffLi
|
|
|
12792
12873
|
topContent,
|
|
12793
12874
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ComposerPendingMessages, {
|
|
12794
12875
|
currentPendingMessages,
|
|
12876
|
+
canStartQueue: canStartPendingQueue,
|
|
12795
12877
|
onEditPendingMessage,
|
|
12796
12878
|
onRemovePendingMessage,
|
|
12797
|
-
onReorderPending
|
|
12879
|
+
onReorderPending,
|
|
12880
|
+
onStartPendingQueue
|
|
12798
12881
|
}),
|
|
12799
12882
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
12800
12883
|
className: "overflow-visible rounded-[18px] border bg-card",
|
|
@@ -12805,6 +12888,7 @@ function ComposerPanel({ activeSessionId, currentPendingMessages, composerDiffLi
|
|
|
12805
12888
|
composerSkill,
|
|
12806
12889
|
composerSyncNonce,
|
|
12807
12890
|
isSubmitting,
|
|
12891
|
+
isCompacting,
|
|
12808
12892
|
isStreaming,
|
|
12809
12893
|
awaitingFirstTurn,
|
|
12810
12894
|
disabled,
|
|
@@ -12888,7 +12972,7 @@ var ComposerAttachments = import_react.memo(function ComposerAttachments({ image
|
|
|
12888
12972
|
}, promptImageKey(image)))
|
|
12889
12973
|
});
|
|
12890
12974
|
});
|
|
12891
|
-
var ComposerPromptEditor = import_react.memo(function ComposerPromptEditor({ composerDiffLineComments, composerImages, composerText, composerSkill, composerSyncNonce, isSubmitting, isStreaming, awaitingFirstTurn, disabled = false, fileInputRef, promptRef, displaySettingsStore, sessionStore, onComposerTextChange, onPickImages, onRemoveComposerDiffLineComment, onRemoveComposerImage, onSubmitPrompt, onAbort, onRunBuiltinSlashCommand, requestPathCompletions, requestFileCompletions }) {
|
|
12975
|
+
var ComposerPromptEditor = import_react.memo(function ComposerPromptEditor({ composerDiffLineComments, composerImages, composerText, composerSkill, composerSyncNonce, isSubmitting, isCompacting, isStreaming, awaitingFirstTurn, disabled = false, fileInputRef, promptRef, displaySettingsStore, sessionStore, onComposerTextChange, onPickImages, onRemoveComposerDiffLineComment, onRemoveComposerImage, onSubmitPrompt, onAbort, onRunBuiltinSlashCommand, requestPathCompletions, requestFileCompletions }) {
|
|
12892
12976
|
const slashCommands = useComposerSlashCommands({
|
|
12893
12977
|
displaySettingsStore,
|
|
12894
12978
|
sessionStore
|
|
@@ -12976,7 +13060,7 @@ var ComposerPromptEditor = import_react.memo(function ComposerPromptEditor({ com
|
|
|
12976
13060
|
promptRef
|
|
12977
13061
|
]);
|
|
12978
13062
|
const hasSubmittableContent = hasDraftText || composerDiffLineComments.length > 0 || composerImages.length > 0;
|
|
12979
|
-
const responseInFlight = isStreaming || awaitingFirstTurn || isSubmitting;
|
|
13063
|
+
const responseInFlight = isStreaming || isCompacting || awaitingFirstTurn || isSubmitting;
|
|
12980
13064
|
const acceptFollowUps = responseInFlight;
|
|
12981
13065
|
const setAssistPointerSelectionSuppressedValue = (next) => {
|
|
12982
13066
|
assistPointerSelectionSuppressedRef.current = next;
|
|
@@ -13609,6 +13693,10 @@ var AppShellComposerController = import_react.memo(function AppShellComposerCont
|
|
|
13609
13693
|
if (actionsRef.current.reorderPendingDraftFollowUp(pendingId, direction)) return;
|
|
13610
13694
|
actionsRef.current.reorderPending(pendingId, direction);
|
|
13611
13695
|
});
|
|
13696
|
+
const onStartPendingQueue = useStableEvent(() => {
|
|
13697
|
+
if (snapshotRef.current.disabled) return;
|
|
13698
|
+
actionsRef.current.startPendingQueue();
|
|
13699
|
+
});
|
|
13612
13700
|
const onRunBuiltinSlashCommand = useStableEvent((name, args) => {
|
|
13613
13701
|
if (snapshotRef.current.disabled) return;
|
|
13614
13702
|
actionsRef.current.runBuiltinSlashCommand(name, args);
|
|
@@ -13659,11 +13747,13 @@ var AppShellComposerController = import_react.memo(function AppShellComposerCont
|
|
|
13659
13747
|
composerText: snapshot.composerText,
|
|
13660
13748
|
composerSkill: snapshot.composerSkill,
|
|
13661
13749
|
composerSyncNonce: snapshot.composerSyncNonce,
|
|
13750
|
+
canStartPendingQueue: snapshot.canStartPendingQueue,
|
|
13662
13751
|
centerMessages,
|
|
13663
13752
|
contextUsageStore,
|
|
13664
13753
|
displaySettingsStore,
|
|
13665
13754
|
sessionStore,
|
|
13666
13755
|
isSubmitting: snapshot.isSubmitting,
|
|
13756
|
+
isCompacting: snapshot.isCompacting,
|
|
13667
13757
|
isStreaming: snapshot.isStreaming,
|
|
13668
13758
|
awaitingFirstTurn: snapshot.awaitingFirstTurn,
|
|
13669
13759
|
disabled: snapshot.disabled,
|
|
@@ -13680,6 +13770,7 @@ var AppShellComposerController = import_react.memo(function AppShellComposerCont
|
|
|
13680
13770
|
onEditPendingMessage,
|
|
13681
13771
|
onRemovePendingMessage,
|
|
13682
13772
|
onReorderPending,
|
|
13773
|
+
onStartPendingQueue,
|
|
13683
13774
|
onRunBuiltinSlashCommand,
|
|
13684
13775
|
onSelectModel,
|
|
13685
13776
|
onSelectThinkingLevel,
|
|
@@ -14593,6 +14684,78 @@ function useAppShellMessageScroll({ autoScrollEnabled, isSessionViewLoading, ses
|
|
|
14593
14684
|
syncAfterConversationChange
|
|
14594
14685
|
};
|
|
14595
14686
|
}
|
|
14687
|
+
var DEFAULT_SCROLL_GRADIENT_MAX_HEIGHT = 4;
|
|
14688
|
+
var EMPTY_SCROLL_GRADIENT_STATE = {
|
|
14689
|
+
bottomHeight: 0,
|
|
14690
|
+
topHeight: 0
|
|
14691
|
+
};
|
|
14692
|
+
function scrollDistanceFromBottom(element) {
|
|
14693
|
+
return Math.max(0, element.scrollHeight - element.scrollTop - element.clientHeight);
|
|
14694
|
+
}
|
|
14695
|
+
function scrollGradientHeight(distanceFromEdge, maxHeight) {
|
|
14696
|
+
return Math.min(maxHeight, Math.max(0, distanceFromEdge));
|
|
14697
|
+
}
|
|
14698
|
+
function scrollGradientState(element, maxHeight) {
|
|
14699
|
+
if (!element) return EMPTY_SCROLL_GRADIENT_STATE;
|
|
14700
|
+
return {
|
|
14701
|
+
bottomHeight: scrollGradientHeight(scrollDistanceFromBottom(element), maxHeight),
|
|
14702
|
+
topHeight: scrollGradientHeight(element.scrollTop, maxHeight)
|
|
14703
|
+
};
|
|
14704
|
+
}
|
|
14705
|
+
function setScrollGradientState(setState, nextState) {
|
|
14706
|
+
setState((currentState) => currentState.bottomHeight === nextState.bottomHeight && currentState.topHeight === nextState.topHeight ? currentState : nextState);
|
|
14707
|
+
}
|
|
14708
|
+
function useScrollGradients({ disabled = false, maxHeight = DEFAULT_SCROLL_GRADIENT_MAX_HEIGHT } = {}) {
|
|
14709
|
+
const elementRef = import_react.useRef(null);
|
|
14710
|
+
const [state, setState] = import_react.useState(EMPTY_SCROLL_GRADIENT_STATE);
|
|
14711
|
+
const syncScrollGradients = import_react.useCallback((element = elementRef.current) => {
|
|
14712
|
+
setScrollGradientState(setState, disabled ? EMPTY_SCROLL_GRADIENT_STATE : scrollGradientState(element, maxHeight));
|
|
14713
|
+
}, [disabled, maxHeight]);
|
|
14714
|
+
const setScrollElement = import_react.useCallback((element) => {
|
|
14715
|
+
elementRef.current = element;
|
|
14716
|
+
syncScrollGradients(element);
|
|
14717
|
+
}, [syncScrollGradients]);
|
|
14718
|
+
const onScroll = import_react.useCallback((event) => {
|
|
14719
|
+
syncScrollGradients(event.currentTarget);
|
|
14720
|
+
}, [syncScrollGradients]);
|
|
14721
|
+
import_react.useLayoutEffect(() => {
|
|
14722
|
+
const element = elementRef.current;
|
|
14723
|
+
syncScrollGradients(element);
|
|
14724
|
+
if (!element || typeof ResizeObserver === "undefined") return;
|
|
14725
|
+
let animationFrame = 0;
|
|
14726
|
+
const scheduleSync = () => {
|
|
14727
|
+
window.cancelAnimationFrame(animationFrame);
|
|
14728
|
+
animationFrame = window.requestAnimationFrame(() => {
|
|
14729
|
+
animationFrame = 0;
|
|
14730
|
+
syncScrollGradients(elementRef.current);
|
|
14731
|
+
});
|
|
14732
|
+
};
|
|
14733
|
+
const resizeObserver = new ResizeObserver(scheduleSync);
|
|
14734
|
+
resizeObserver.observe(element);
|
|
14735
|
+
const content = element.firstElementChild;
|
|
14736
|
+
if (content instanceof HTMLElement) resizeObserver.observe(content);
|
|
14737
|
+
return () => {
|
|
14738
|
+
window.cancelAnimationFrame(animationFrame);
|
|
14739
|
+
resizeObserver.disconnect();
|
|
14740
|
+
};
|
|
14741
|
+
}, [syncScrollGradients]);
|
|
14742
|
+
return {
|
|
14743
|
+
bottomHeight: state.bottomHeight,
|
|
14744
|
+
onScroll,
|
|
14745
|
+
setScrollElement,
|
|
14746
|
+
syncScrollGradients,
|
|
14747
|
+
topHeight: state.topHeight
|
|
14748
|
+
};
|
|
14749
|
+
}
|
|
14750
|
+
function ScrollGradientOverlays({ bottomClassName, bottomHeight, className, topClassName, topHeight }) {
|
|
14751
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
14752
|
+
className: cn("pointer-events-none absolute inset-x-0 top-0 z-10 bg-gradient-to-b from-black/10 to-transparent transition-[height,opacity] duration-150", topHeight > 0 ? "opacity-100" : "opacity-0", className, topClassName),
|
|
14753
|
+
style: { height: topHeight }
|
|
14754
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
14755
|
+
className: cn("pointer-events-none absolute inset-x-0 bottom-0 z-10 bg-gradient-to-t from-black/10 to-transparent transition-[height,opacity] duration-150", bottomHeight > 0 ? "opacity-100" : "opacity-0", className, bottomClassName),
|
|
14756
|
+
style: { height: bottomHeight }
|
|
14757
|
+
})] });
|
|
14758
|
+
}
|
|
14596
14759
|
function ConversationLatestMessageButton({ conversationItemsStore, draft, onClick, scrollStateStore }) {
|
|
14597
14760
|
const hasMessages = useConversationHasMessages(conversationItemsStore);
|
|
14598
14761
|
const isDisabled = useMessageScrollValue(scrollStateStore, (snapshot) => draft || !hasMessages || snapshot.isMessagesNearBottom);
|
|
@@ -14659,6 +14822,11 @@ function AppShellConversationFrame({ autoScrollEnabled, children, centerMessages
|
|
|
14659
14822
|
isSessionViewLoading,
|
|
14660
14823
|
sessionState
|
|
14661
14824
|
});
|
|
14825
|
+
const { bottomHeight: conversationScrollBottomGradientHeight, onScroll: onConversationScrollGradientScroll, setScrollElement: setConversationScrollGradientElement, topHeight: conversationScrollTopGradientHeight } = useScrollGradients({ disabled: isSessionViewLoading });
|
|
14826
|
+
const setMessagesScrollAreaElement = import_react.useCallback((element) => {
|
|
14827
|
+
messagesScrollAreaRef.current = element;
|
|
14828
|
+
setConversationScrollGradientElement(element);
|
|
14829
|
+
}, [messagesScrollAreaRef, setConversationScrollGradientElement]);
|
|
14662
14830
|
import_react.useImperativeHandle(ref, () => ({
|
|
14663
14831
|
jumpToNextMessage,
|
|
14664
14832
|
jumpToPreviousMessage,
|
|
@@ -14672,39 +14840,47 @@ function AppShellConversationFrame({ autoScrollEnabled, children, centerMessages
|
|
|
14672
14840
|
]);
|
|
14673
14841
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
14674
14842
|
className: "relative min-h-0 flex-1",
|
|
14675
|
-
children: [
|
|
14676
|
-
|
|
14677
|
-
|
|
14678
|
-
|
|
14679
|
-
|
|
14680
|
-
|
|
14681
|
-
|
|
14682
|
-
|
|
14683
|
-
|
|
14684
|
-
|
|
14685
|
-
|
|
14686
|
-
|
|
14687
|
-
|
|
14688
|
-
|
|
14689
|
-
|
|
14690
|
-
|
|
14691
|
-
|
|
14692
|
-
|
|
14693
|
-
|
|
14694
|
-
|
|
14695
|
-
|
|
14696
|
-
|
|
14697
|
-
|
|
14698
|
-
|
|
14699
|
-
|
|
14700
|
-
|
|
14701
|
-
|
|
14702
|
-
|
|
14703
|
-
|
|
14704
|
-
|
|
14705
|
-
|
|
14706
|
-
|
|
14707
|
-
|
|
14843
|
+
children: [
|
|
14844
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
14845
|
+
ref: setMessagesScrollAreaElement,
|
|
14846
|
+
"data-conversation-viewport": "true",
|
|
14847
|
+
tabIndex: 0,
|
|
14848
|
+
role: "region",
|
|
14849
|
+
"aria-label": "Conversation messages",
|
|
14850
|
+
className: "h-full overflow-x-hidden overflow-y-auto overscroll-contain px-4 outline-none [overflow-anchor:none]",
|
|
14851
|
+
onScroll: onConversationScrollGradientScroll,
|
|
14852
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
14853
|
+
ref: messagesContentRef,
|
|
14854
|
+
className: "flex min-h-full flex-col",
|
|
14855
|
+
children: [
|
|
14856
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConversationScrollRevisionObserver, {
|
|
14857
|
+
conversationItemsStore,
|
|
14858
|
+
disabled: isSessionViewLoading,
|
|
14859
|
+
onRevisionChange: syncAfterConversationChange
|
|
14860
|
+
}),
|
|
14861
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConversationContentChangeContext.Provider, {
|
|
14862
|
+
value: syncAfterConversationChange,
|
|
14863
|
+
children
|
|
14864
|
+
}),
|
|
14865
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: bottomRef })
|
|
14866
|
+
]
|
|
14867
|
+
})
|
|
14868
|
+
}),
|
|
14869
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollGradientOverlays, {
|
|
14870
|
+
bottomHeight: conversationScrollBottomGradientHeight,
|
|
14871
|
+
topHeight: conversationScrollTopGradientHeight
|
|
14872
|
+
}),
|
|
14873
|
+
!isSessionViewLoading ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConversationLatestMessageButton, {
|
|
14874
|
+
conversationItemsStore,
|
|
14875
|
+
draft: sessionState.draft,
|
|
14876
|
+
onClick: scrollConversationToBottom,
|
|
14877
|
+
scrollStateStore
|
|
14878
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConversationPreviousMessageButton, {
|
|
14879
|
+
centerMessages,
|
|
14880
|
+
onClick: jumpToPreviousMessage,
|
|
14881
|
+
scrollStateStore
|
|
14882
|
+
})] }) : null
|
|
14883
|
+
]
|
|
14708
14884
|
});
|
|
14709
14885
|
}
|
|
14710
14886
|
function AppShellWorkingIndicatorLabel({ fallbackLabel, hiddenThinkingPreviewStore, useHiddenThinkingPreview }) {
|
|
@@ -16762,6 +16938,7 @@ function GitRepositorySummary({ viewerContextId, cwd, active, onBranchClick }) {
|
|
|
16762
16938
|
}
|
|
16763
16939
|
function GitPanelToolbar({ viewerContextId, cwd, active }) {
|
|
16764
16940
|
const queryClient = useQueryClient();
|
|
16941
|
+
const isMobile = useIsMobile();
|
|
16765
16942
|
const normalizedCwd = normalizeCwd(cwd);
|
|
16766
16943
|
const [branchDialogOpen, setBranchDialogOpen] = import_react.useState(false);
|
|
16767
16944
|
const [commitDialogOpen, setCommitDialogOpen] = import_react.useState(false);
|
|
@@ -16875,6 +17052,7 @@ function GitPanelToolbar({ viewerContextId, cwd, active }) {
|
|
|
16875
17052
|
kbd: formatShortcutLabel("Control+C"),
|
|
16876
17053
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
|
|
16877
17054
|
variant: "outline",
|
|
17055
|
+
size: isMobile ? "default" : "sm",
|
|
16878
17056
|
onClick: () => {
|
|
16879
17057
|
setCommitDialogOpen(true);
|
|
16880
17058
|
},
|
|
@@ -16886,6 +17064,7 @@ function GitPanelToolbar({ viewerContextId, cwd, active }) {
|
|
|
16886
17064
|
kbd: formatShortcutLabel("Control+P"),
|
|
16887
17065
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
|
|
16888
17066
|
variant: "outline",
|
|
17067
|
+
size: isMobile ? "default" : "sm",
|
|
16889
17068
|
disabled: gitActionBusy,
|
|
16890
17069
|
onClick: () => {
|
|
16891
17070
|
gitActionMutation.mutate("push");
|
|
@@ -16898,6 +17077,7 @@ function GitPanelToolbar({ viewerContextId, cwd, active }) {
|
|
|
16898
17077
|
kbd: formatShortcutLabel("Control+Shift+P"),
|
|
16899
17078
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
|
|
16900
17079
|
variant: "outline",
|
|
17080
|
+
size: isMobile ? "default" : "sm",
|
|
16901
17081
|
disabled: gitActionBusy,
|
|
16902
17082
|
onClick: () => {
|
|
16903
17083
|
gitActionMutation.mutate("force-push");
|
|
@@ -16910,6 +17090,7 @@ function GitPanelToolbar({ viewerContextId, cwd, active }) {
|
|
|
16910
17090
|
kbd: formatShortcutLabel("Alt+P"),
|
|
16911
17091
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
|
|
16912
17092
|
variant: "outline",
|
|
17093
|
+
size: isMobile ? "default" : "sm",
|
|
16913
17094
|
disabled: gitActionBusy,
|
|
16914
17095
|
onClick: () => {
|
|
16915
17096
|
gitActionMutation.mutate("pull");
|
|
@@ -17018,26 +17199,6 @@ function AlertDialogCancel({ className, variant = "outline", size = "default", .
|
|
|
17018
17199
|
...props
|
|
17019
17200
|
});
|
|
17020
17201
|
}
|
|
17021
|
-
function setDerivedScrollState(setState, nextState) {
|
|
17022
|
-
setState((current) => Object.is(current, nextState) ? current : nextState);
|
|
17023
|
-
}
|
|
17024
|
-
function hasScrolledContent(scrollElement) {
|
|
17025
|
-
return Boolean(scrollElement && scrollElement.scrollTop > 0);
|
|
17026
|
-
}
|
|
17027
|
-
function hasRemainingScrollContent(scrollElement) {
|
|
17028
|
-
if (!scrollElement) return false;
|
|
17029
|
-
return scrollElement.scrollHeight - scrollElement.clientHeight - scrollElement.scrollTop > 1;
|
|
17030
|
-
}
|
|
17031
|
-
function getStuckScrollTriggerValue({ getValue, scrollElement, selector }) {
|
|
17032
|
-
if (!scrollElement || scrollElement.scrollTop <= 0) return "";
|
|
17033
|
-
const containerTop = scrollElement.getBoundingClientRect().top;
|
|
17034
|
-
const triggers = Array.from(scrollElement.querySelectorAll(selector));
|
|
17035
|
-
for (const trigger of triggers) {
|
|
17036
|
-
const rect = trigger.getBoundingClientRect();
|
|
17037
|
-
if (rect.top <= containerTop + 1 && rect.bottom > containerTop + 1) return getValue(trigger);
|
|
17038
|
-
}
|
|
17039
|
-
return "";
|
|
17040
|
-
}
|
|
17041
17202
|
function GitSection({ title, meta, controls, className, bodyClassName, children }) {
|
|
17042
17203
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
17043
17204
|
className: cn("overflow-hidden rounded-xl border border-border/80 bg-card/50", className),
|
|
@@ -17081,10 +17242,7 @@ var initialGitCommitRowState = {
|
|
|
17081
17242
|
formDialog: null,
|
|
17082
17243
|
confirmDialog: null,
|
|
17083
17244
|
contextMenuOpen: false,
|
|
17084
|
-
contextMenuKey: 0
|
|
17085
|
-
scrollValue: "",
|
|
17086
|
-
commitBodyHeaderShadowed: false,
|
|
17087
|
-
commitBodyFooterShadowed: false
|
|
17245
|
+
contextMenuKey: 0
|
|
17088
17246
|
};
|
|
17089
17247
|
function gitCommitRowReducer(state, action) {
|
|
17090
17248
|
switch (action.type) {
|
|
@@ -17132,18 +17290,10 @@ function gitCommitRowReducer(state, action) {
|
|
|
17132
17290
|
contextMenuOpen: false,
|
|
17133
17291
|
contextMenuKey: state.contextMenuKey + 1
|
|
17134
17292
|
};
|
|
17135
|
-
case "set-scroll-shadows":
|
|
17136
|
-
if (state.scrollValue === action.value && state.commitBodyHeaderShadowed === action.headerShadowed && state.commitBodyFooterShadowed === action.footerShadowed) return state;
|
|
17137
|
-
return {
|
|
17138
|
-
...state,
|
|
17139
|
-
scrollValue: action.value,
|
|
17140
|
-
commitBodyHeaderShadowed: action.headerShadowed,
|
|
17141
|
-
commitBodyFooterShadowed: action.footerShadowed
|
|
17142
|
-
};
|
|
17143
17293
|
}
|
|
17144
17294
|
}
|
|
17145
17295
|
function gitGraphLaneColor(index, active = false) {
|
|
17146
|
-
if (active) return "
|
|
17296
|
+
if (active) return "var(--warning)";
|
|
17147
17297
|
return GIT_GRAPH_LANE_COLORS[index % GIT_GRAPH_LANE_COLORS.length];
|
|
17148
17298
|
}
|
|
17149
17299
|
var GitCommitGraphBranch = class {
|
|
@@ -17768,8 +17918,8 @@ function useGitCommitRowView({ viewerContextId, cwd, graphWidth, line, value, on
|
|
|
17768
17918
|
const [rowState, dispatchRow] = import_react.useReducer(gitCommitRowReducer, initialGitCommitRowState);
|
|
17769
17919
|
const hashCopiedResetRef = import_react.useRef(void 0);
|
|
17770
17920
|
const messageCopiedResetRef = import_react.useRef(void 0);
|
|
17771
|
-
const commitBodyScrollRef = import_react.useRef(null);
|
|
17772
17921
|
const contextMenuActionsRef = import_react.useRef(null);
|
|
17922
|
+
const { bottomHeight: commitBodyBottomGradientHeight, onScroll: onCommitBodyGradientScroll, setScrollElement: setCommitBodyGradientElement, topHeight: commitBodyTopGradientHeight } = useScrollGradients();
|
|
17773
17923
|
const title = parsed.subject.trim();
|
|
17774
17924
|
const time = formatGitCommitDetailTime(parsed.relativeDate);
|
|
17775
17925
|
const fullTime = formatGitCommitFullDate(parsed.fullDate);
|
|
@@ -17778,19 +17928,6 @@ function useGitCommitRowView({ viewerContextId, cwd, graphWidth, line, value, on
|
|
|
17778
17928
|
const shortHash = parsed.hash || parsed.fullHash.slice(0, 7);
|
|
17779
17929
|
const canRunCommitAction = Boolean(viewerContextId && cwd && parsed.fullHash);
|
|
17780
17930
|
const { hashCopied, messageCopied, formDialog, confirmDialog, contextMenuOpen, contextMenuKey } = rowState;
|
|
17781
|
-
const commitBodyHeaderShadowed = rowState.scrollValue === value && rowState.commitBodyHeaderShadowed;
|
|
17782
|
-
const commitBodyFooterShadowed = rowState.scrollValue === value && rowState.commitBodyFooterShadowed;
|
|
17783
|
-
const updateCommitBodyScrollShadows = (scrollElement) => {
|
|
17784
|
-
dispatchRow({
|
|
17785
|
-
type: "set-scroll-shadows",
|
|
17786
|
-
value,
|
|
17787
|
-
headerShadowed: hasScrolledContent(scrollElement),
|
|
17788
|
-
footerShadowed: hasRemainingScrollContent(scrollElement)
|
|
17789
|
-
});
|
|
17790
|
-
};
|
|
17791
|
-
import_react.useLayoutEffect(() => {
|
|
17792
|
-
updateCommitBodyScrollShadows(commitBodyScrollRef.current);
|
|
17793
|
-
});
|
|
17794
17931
|
import_react.useEffect(() => {
|
|
17795
17932
|
return () => {
|
|
17796
17933
|
if (typeof hashCopiedResetRef.current === "number") window.clearTimeout(hashCopiedResetRef.current);
|
|
@@ -17957,7 +18094,7 @@ function useGitCommitRowView({ viewerContextId, cwd, graphWidth, line, value, on
|
|
|
17957
18094
|
});
|
|
17958
18095
|
};
|
|
17959
18096
|
if (!parsed.hash && !parsed.subject) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
17960
|
-
className: "flex h-8 max-w-full min-w-0 items-center
|
|
18097
|
+
className: "flex h-8 max-w-full min-w-0 items-center text-[13px] leading-5",
|
|
17961
18098
|
children: parsed.subject ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
17962
18099
|
className: "min-w-0 flex-1 truncate text-foreground",
|
|
17963
18100
|
children: parsed.subject
|
|
@@ -17965,7 +18102,7 @@ function useGitCommitRowView({ viewerContextId, cwd, graphWidth, line, value, on
|
|
|
17965
18102
|
});
|
|
17966
18103
|
const trigger = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AccordionTrigger, {
|
|
17967
18104
|
headerClassName: "min-w-0",
|
|
17968
|
-
className: cn("h-8 min-h-8 w-full items-center gap-2 rounded-none px-1.5 py-0
|
|
18105
|
+
className: cn("h-8 min-h-8 w-full items-center gap-2 rounded-none px-1.5 py-0 text-[13px] leading-5 font-normal transition-[background-color,box-shadow,color] hover:no-underline focus-visible:ring-0 aria-expanded:bg-muted/50 **:data-[slot=accordion-trigger-icon]:size-4"),
|
|
17969
18106
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
17970
18107
|
className: "min-w-0 flex-1 truncate pr-8 text-foreground",
|
|
17971
18108
|
style: { paddingLeft: graphWidth },
|
|
@@ -18107,122 +18244,119 @@ function useGitCommitRowView({ viewerContextId, cwd, graphWidth, line, value, on
|
|
|
18107
18244
|
}),
|
|
18108
18245
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(AccordionContent, {
|
|
18109
18246
|
className: "relative h-[200px] border-b border-border/70 bg-muted/50 p-0",
|
|
18110
|
-
children: [
|
|
18111
|
-
|
|
18112
|
-
|
|
18113
|
-
|
|
18114
|
-
|
|
18115
|
-
|
|
18116
|
-
},
|
|
18117
|
-
children:
|
|
18118
|
-
|
|
18119
|
-
|
|
18120
|
-
|
|
18121
|
-
|
|
18122
|
-
|
|
18123
|
-
|
|
18247
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
18248
|
+
ref: setCommitBodyGradientElement,
|
|
18249
|
+
className: "h-full overflow-y-auto pr-2 pb-2",
|
|
18250
|
+
onScroll: onCommitBodyGradientScroll,
|
|
18251
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18252
|
+
className: "grid content-start gap-1.5 pt-1 text-xs leading-4",
|
|
18253
|
+
style: { paddingLeft: graphWidth },
|
|
18254
|
+
children: [
|
|
18255
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18256
|
+
className: "flex min-w-0 flex-wrap items-center gap-1.5 font-sans",
|
|
18257
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
|
|
18258
|
+
type: "button",
|
|
18259
|
+
size: "xs",
|
|
18260
|
+
variant: "outline",
|
|
18261
|
+
disabled: !canRunCommitAction,
|
|
18262
|
+
onClick: () => openDiff("commit"),
|
|
18263
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(FileDiff, {}), "View diff"]
|
|
18264
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitCommitActionsMenu, { ...commitActionProps })]
|
|
18265
|
+
}),
|
|
18266
|
+
parsed.author || time || parsed.fullHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18267
|
+
className: "flex max-w-full flex-wrap items-center gap-x-2 gap-y-1 text-muted-foreground",
|
|
18268
|
+
children: [
|
|
18269
|
+
parsed.author ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: parsed.author }) : null,
|
|
18270
|
+
parsed.author && time ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18271
|
+
"aria-hidden": true,
|
|
18272
|
+
children: "·"
|
|
18273
|
+
}) : null,
|
|
18274
|
+
time ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
18275
|
+
title: fullTime,
|
|
18276
|
+
side: "top",
|
|
18277
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: time })
|
|
18278
|
+
}) : null,
|
|
18279
|
+
(parsed.author || time) && parsed.fullHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18280
|
+
"aria-hidden": true,
|
|
18281
|
+
children: "·"
|
|
18282
|
+
}) : null,
|
|
18283
|
+
parsed.fullHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
18284
|
+
className: "inline-flex min-w-0 items-center gap-1.5",
|
|
18285
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18286
|
+
className: "min-w-0 truncate",
|
|
18287
|
+
children: shortHash
|
|
18288
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
18289
|
+
title: hashCopied ? "Copied" : "Copy full commit hash",
|
|
18290
|
+
side: "top",
|
|
18291
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
18292
|
+
type: "button",
|
|
18293
|
+
"aria-label": "Copy full commit hash",
|
|
18294
|
+
className: "inline-flex size-5 shrink-0 items-center justify-center rounded-sm text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
18295
|
+
onClick: (event) => {
|
|
18296
|
+
event.preventDefault();
|
|
18297
|
+
event.stopPropagation();
|
|
18298
|
+
copyFullHashInline();
|
|
18299
|
+
},
|
|
18300
|
+
children: hashCopied ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "size-3.5 text-emerald-500" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Copy, { className: "size-3.5" })
|
|
18301
|
+
})
|
|
18302
|
+
})]
|
|
18303
|
+
}) : null
|
|
18304
|
+
]
|
|
18305
|
+
}) : null,
|
|
18306
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18307
|
+
className: "max-w-full break-words whitespace-normal text-foreground",
|
|
18308
|
+
children: [title || "No commit message", title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
18309
|
+
title: messageCopied ? "Copied" : "Copy commit message",
|
|
18310
|
+
side: "top",
|
|
18311
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
18124
18312
|
type: "button",
|
|
18125
|
-
|
|
18126
|
-
|
|
18127
|
-
|
|
18128
|
-
|
|
18129
|
-
|
|
18130
|
-
|
|
18131
|
-
|
|
18132
|
-
|
|
18133
|
-
|
|
18313
|
+
"aria-label": "Copy commit message",
|
|
18314
|
+
className: "ml-1 inline-flex size-4 items-center justify-center rounded-sm align-middle text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
18315
|
+
onClick: (event) => {
|
|
18316
|
+
event.preventDefault();
|
|
18317
|
+
event.stopPropagation();
|
|
18318
|
+
copyCommitMessageInline();
|
|
18319
|
+
},
|
|
18320
|
+
children: messageCopied ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "size-3.5 text-emerald-500" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Copy, { className: "size-3.5" })
|
|
18321
|
+
})
|
|
18322
|
+
}) : null]
|
|
18323
|
+
}),
|
|
18324
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
18325
|
+
className: "flex min-w-0 flex-wrap items-center gap-x-3 gap-y-1",
|
|
18326
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
18327
|
+
className: "text-emerald-500",
|
|
18134
18328
|
children: [
|
|
18135
|
-
|
|
18136
|
-
|
|
18137
|
-
|
|
18138
|
-
|
|
18139
|
-
}) : null,
|
|
18140
|
-
time ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
18141
|
-
title: fullTime,
|
|
18142
|
-
side: "top",
|
|
18143
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: time })
|
|
18144
|
-
}) : null,
|
|
18145
|
-
(parsed.author || time) && parsed.fullHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18146
|
-
"aria-hidden": true,
|
|
18147
|
-
children: "·"
|
|
18148
|
-
}) : null,
|
|
18149
|
-
parsed.fullHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
18150
|
-
className: "inline-flex min-w-0 items-center gap-1.5",
|
|
18151
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
18152
|
-
className: "min-w-0 truncate",
|
|
18153
|
-
children: shortHash
|
|
18154
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
18155
|
-
title: hashCopied ? "Copied" : "Copy full commit hash",
|
|
18156
|
-
side: "top",
|
|
18157
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
18158
|
-
type: "button",
|
|
18159
|
-
"aria-label": "Copy full commit hash",
|
|
18160
|
-
className: "inline-flex size-5 shrink-0 items-center justify-center rounded-sm text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
|
|
18161
|
-
onClick: (event) => {
|
|
18162
|
-
event.preventDefault();
|
|
18163
|
-
event.stopPropagation();
|
|
18164
|
-
copyFullHashInline();
|
|
18165
|
-
},
|
|
18166
|
-
children: hashCopied ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Check, { className: "size-3.5 text-emerald-500" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Copy, { className: "size-3.5" })
|
|
18167
|
-
})
|
|
18168
|
-
})]
|
|
18169
|
-
}) : null
|
|
18329
|
+
"+",
|
|
18330
|
+
insertions,
|
|
18331
|
+
" addition",
|
|
18332
|
+
insertions === 1 ? "" : "s"
|
|
18170
18333
|
]
|
|
18171
|
-
})
|
|
18172
|
-
|
|
18173
|
-
|
|
18174
|
-
|
|
18175
|
-
|
|
18176
|
-
|
|
18177
|
-
|
|
18178
|
-
|
|
18179
|
-
|
|
18180
|
-
|
|
18181
|
-
|
|
18182
|
-
|
|
18183
|
-
|
|
18184
|
-
|
|
18185
|
-
|
|
18186
|
-
|
|
18187
|
-
|
|
18188
|
-
|
|
18189
|
-
|
|
18190
|
-
|
|
18191
|
-
|
|
18192
|
-
|
|
18193
|
-
|
|
18194
|
-
|
|
18195
|
-
|
|
18196
|
-
|
|
18197
|
-
" addition",
|
|
18198
|
-
insertions === 1 ? "" : "s"
|
|
18199
|
-
]
|
|
18200
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
18201
|
-
className: "text-red-400",
|
|
18202
|
-
children: [
|
|
18203
|
-
"-",
|
|
18204
|
-
deletions,
|
|
18205
|
-
" deletion",
|
|
18206
|
-
deletions === 1 ? "" : "s"
|
|
18207
|
-
]
|
|
18208
|
-
})]
|
|
18209
|
-
}),
|
|
18210
|
-
parsed.fullHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitCommitFilesList, {
|
|
18211
|
-
viewerContextId,
|
|
18212
|
-
cwd,
|
|
18213
|
-
commit: parsed.fullHash,
|
|
18214
|
-
shortHash,
|
|
18215
|
-
previousShortHash: parsed.parents[0]?.slice(0, 7) || "",
|
|
18216
|
-
subject: title,
|
|
18217
|
-
disabled: !canRunCommitAction,
|
|
18218
|
-
onOpenCommitDiff
|
|
18219
|
-
}) : null
|
|
18220
|
-
]
|
|
18221
|
-
})
|
|
18222
|
-
}),
|
|
18223
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn("pointer-events-none absolute inset-x-0 top-0 h-1 bg-gradient-to-b from-black/10 to-transparent transition-opacity duration-150", commitBodyHeaderShadowed ? "opacity-100" : "opacity-0") }),
|
|
18224
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: cn("pointer-events-none absolute inset-x-0 bottom-0 h-1 bg-gradient-to-t from-black/10 to-transparent transition-opacity duration-150", commitBodyFooterShadowed ? "opacity-100" : "opacity-0") })
|
|
18225
|
-
]
|
|
18334
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
18335
|
+
className: "text-red-400",
|
|
18336
|
+
children: [
|
|
18337
|
+
"-",
|
|
18338
|
+
deletions,
|
|
18339
|
+
" deletion",
|
|
18340
|
+
deletions === 1 ? "" : "s"
|
|
18341
|
+
]
|
|
18342
|
+
})]
|
|
18343
|
+
}),
|
|
18344
|
+
parsed.fullHash ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitCommitFilesList, {
|
|
18345
|
+
viewerContextId,
|
|
18346
|
+
cwd,
|
|
18347
|
+
commit: parsed.fullHash,
|
|
18348
|
+
shortHash,
|
|
18349
|
+
previousShortHash: parsed.parents[0]?.slice(0, 7) || "",
|
|
18350
|
+
subject: title,
|
|
18351
|
+
disabled: !canRunCommitAction,
|
|
18352
|
+
onOpenCommitDiff
|
|
18353
|
+
}) : null
|
|
18354
|
+
]
|
|
18355
|
+
})
|
|
18356
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollGradientOverlays, {
|
|
18357
|
+
bottomHeight: commitBodyBottomGradientHeight,
|
|
18358
|
+
topHeight: commitBodyTopGradientHeight
|
|
18359
|
+
})]
|
|
18226
18360
|
}),
|
|
18227
18361
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dialog$1, {
|
|
18228
18362
|
open: formDialog !== null,
|
|
@@ -18473,6 +18607,22 @@ function GitCommitsSection({ viewerContextId, cwd, active, onOpenCommitDiff, onR
|
|
|
18473
18607
|
children: content
|
|
18474
18608
|
});
|
|
18475
18609
|
}
|
|
18610
|
+
function setDerivedScrollState(setState, nextState) {
|
|
18611
|
+
setState((current) => Object.is(current, nextState) ? current : nextState);
|
|
18612
|
+
}
|
|
18613
|
+
function hasScrolledContent(scrollElement) {
|
|
18614
|
+
return Boolean(scrollElement && scrollElement.scrollTop > 0);
|
|
18615
|
+
}
|
|
18616
|
+
function getStuckScrollTriggerValue({ getValue, scrollElement, selector }) {
|
|
18617
|
+
if (!scrollElement || scrollElement.scrollTop <= 0) return "";
|
|
18618
|
+
const containerTop = scrollElement.getBoundingClientRect().top;
|
|
18619
|
+
const triggers = Array.from(scrollElement.querySelectorAll(selector));
|
|
18620
|
+
for (const trigger of triggers) {
|
|
18621
|
+
const rect = trigger.getBoundingClientRect();
|
|
18622
|
+
if (rect.top <= containerTop + 1 && rect.bottom > containerTop + 1) return getValue(trigger);
|
|
18623
|
+
}
|
|
18624
|
+
return "";
|
|
18625
|
+
}
|
|
18476
18626
|
function GitFileStatus({ status }) {
|
|
18477
18627
|
const [indexCharacter, worktreeCharacter] = gitFileStatusCharacters(status);
|
|
18478
18628
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
@@ -18576,7 +18726,7 @@ function ReviewDiffPendingLineComment({ comment }) {
|
|
|
18576
18726
|
comment.onSubmit(normalizedText);
|
|
18577
18727
|
};
|
|
18578
18728
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", {
|
|
18579
|
-
className: "m-2 w-[
|
|
18729
|
+
className: "m-2 w-[calc(100%_-_1rem)] max-w-[38rem] rounded-lg border border-border/70 bg-background p-2 shadow-sm",
|
|
18580
18730
|
onPointerDown: (event) => event.stopPropagation(),
|
|
18581
18731
|
onSubmit: (event) => {
|
|
18582
18732
|
event.preventDefault();
|
|
@@ -18776,6 +18926,11 @@ function useFileReviewContentView({ viewerContextId, cwd, active, diffLineCommen
|
|
|
18776
18926
|
});
|
|
18777
18927
|
};
|
|
18778
18928
|
const changesScrollRef = import_react.useRef(null);
|
|
18929
|
+
const { bottomHeight: changesScrollBottomGradientHeight, onScroll: onChangesScrollGradientScroll, setScrollElement: setChangesScrollGradientElement, topHeight: changesScrollTopGradientHeight } = useScrollGradients();
|
|
18930
|
+
const setChangesScrollElement = import_react.useCallback((element) => {
|
|
18931
|
+
changesScrollRef.current = element;
|
|
18932
|
+
setChangesScrollGradientElement(element);
|
|
18933
|
+
}, [setChangesScrollGradientElement]);
|
|
18779
18934
|
const reviewContentRef = import_react.useRef(null);
|
|
18780
18935
|
const historyPanelRef = import_react.useRef(null);
|
|
18781
18936
|
const historyScrollRef = import_react.useRef(null);
|
|
@@ -18974,7 +19129,7 @@ function useFileReviewContentView({ viewerContextId, cwd, active, diffLineCommen
|
|
|
18974
19129
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DropdownMenu, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DropdownMenuTrigger, {
|
|
18975
19130
|
render: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
18976
19131
|
variant: "outline",
|
|
18977
|
-
size: "icon",
|
|
19132
|
+
size: isMobile ? "icon" : "icon-sm",
|
|
18978
19133
|
"aria-label": "Diff actions",
|
|
18979
19134
|
disabled: bulkActionDisabled
|
|
18980
19135
|
}),
|
|
@@ -19012,7 +19167,7 @@ function useFileReviewContentView({ viewerContextId, cwd, active, diffLineCommen
|
|
|
19012
19167
|
title: hasOpenFile ? "Collapse all" : "Expand all",
|
|
19013
19168
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
19014
19169
|
variant: "outline",
|
|
19015
|
-
size: "icon",
|
|
19170
|
+
size: isMobile ? "icon" : "icon-sm",
|
|
19016
19171
|
"aria-label": hasOpenFile ? "Collapse all" : "Expand all",
|
|
19017
19172
|
disabled: changedFiles.length === 0,
|
|
19018
19173
|
onClick: toggleAll,
|
|
@@ -19021,6 +19176,7 @@ function useFileReviewContentView({ viewerContextId, cwd, active, diffLineCommen
|
|
|
19021
19176
|
}),
|
|
19022
19177
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToggleGroup$1, {
|
|
19023
19178
|
variant: "outline",
|
|
19179
|
+
size: isMobile ? "default" : "sm",
|
|
19024
19180
|
value: [diffStyle],
|
|
19025
19181
|
onValueChange: (values) => {
|
|
19026
19182
|
const value = values[0];
|
|
@@ -19037,54 +19193,61 @@ function useFileReviewContentView({ viewerContextId, cwd, active, diffLineCommen
|
|
|
19037
19193
|
]
|
|
19038
19194
|
})]
|
|
19039
19195
|
}),
|
|
19040
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
19041
|
-
|
|
19042
|
-
|
|
19043
|
-
|
|
19044
|
-
|
|
19045
|
-
|
|
19046
|
-
|
|
19047
|
-
|
|
19048
|
-
children: "No directory selected."
|
|
19049
|
-
}) : !viewerContextId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitSectionNote, {
|
|
19050
|
-
className: "px-3 py-2.5",
|
|
19051
|
-
children: "Waiting for viewer context…"
|
|
19052
|
-
}) : filesQuery.isPending && typeof files === "undefined" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(GitSectionNote, {
|
|
19053
|
-
className: "px-3 py-2.5",
|
|
19054
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}), " Loading changes…"]
|
|
19055
|
-
}) : filesQuery.error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitSectionNote, {
|
|
19056
|
-
tone: "destructive",
|
|
19057
|
-
className: "px-3 py-2.5",
|
|
19058
|
-
children: getErrorMessage(filesQuery.error, "Failed to load changes")
|
|
19059
|
-
}) : files === null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitSectionNote, {
|
|
19060
|
-
className: "px-3 py-2.5",
|
|
19061
|
-
children: "No git repository detected."
|
|
19062
|
-
}) : changedFiles.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Accordion$1, {
|
|
19063
|
-
multiple: true,
|
|
19064
|
-
value: openFiles,
|
|
19065
|
-
onValueChange: (nextOpenFiles) => {
|
|
19066
|
-
dispatch({
|
|
19067
|
-
type: "openFilesChanged",
|
|
19068
|
-
openFiles: nextOpenFiles
|
|
19069
|
-
});
|
|
19196
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19197
|
+
className: "relative min-h-0 flex-1",
|
|
19198
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19199
|
+
ref: setChangesScrollElement,
|
|
19200
|
+
className: "h-full overflow-auto",
|
|
19201
|
+
onScroll: (event) => {
|
|
19202
|
+
updateStickyReviewFileHeader(event.currentTarget);
|
|
19203
|
+
onChangesScrollGradientScroll(event);
|
|
19070
19204
|
},
|
|
19071
|
-
|
|
19072
|
-
|
|
19073
|
-
|
|
19074
|
-
|
|
19075
|
-
|
|
19076
|
-
|
|
19077
|
-
|
|
19078
|
-
|
|
19079
|
-
|
|
19080
|
-
|
|
19081
|
-
|
|
19082
|
-
|
|
19083
|
-
|
|
19084
|
-
|
|
19085
|
-
|
|
19086
|
-
|
|
19087
|
-
|
|
19205
|
+
children: !normalizedCwd ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitSectionNote, {
|
|
19206
|
+
className: "px-3 py-2.5",
|
|
19207
|
+
children: "No directory selected."
|
|
19208
|
+
}) : !viewerContextId ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitSectionNote, {
|
|
19209
|
+
className: "px-3 py-2.5",
|
|
19210
|
+
children: "Waiting for viewer context…"
|
|
19211
|
+
}) : filesQuery.isPending && typeof files === "undefined" ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(GitSectionNote, {
|
|
19212
|
+
className: "px-3 py-2.5",
|
|
19213
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}), " Loading changes…"]
|
|
19214
|
+
}) : filesQuery.error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitSectionNote, {
|
|
19215
|
+
tone: "destructive",
|
|
19216
|
+
className: "px-3 py-2.5",
|
|
19217
|
+
children: getErrorMessage(filesQuery.error, "Failed to load changes")
|
|
19218
|
+
}) : files === null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitSectionNote, {
|
|
19219
|
+
className: "px-3 py-2.5",
|
|
19220
|
+
children: "No git repository detected."
|
|
19221
|
+
}) : changedFiles.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Accordion$1, {
|
|
19222
|
+
multiple: true,
|
|
19223
|
+
value: openFiles,
|
|
19224
|
+
onValueChange: (nextOpenFiles) => {
|
|
19225
|
+
dispatch({
|
|
19226
|
+
type: "openFilesChanged",
|
|
19227
|
+
openFiles: nextOpenFiles
|
|
19228
|
+
});
|
|
19229
|
+
},
|
|
19230
|
+
className: "border-b border-border/80",
|
|
19231
|
+
children: changedFiles.map((file) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReviewFileAccordionItem, {
|
|
19232
|
+
viewerContextId,
|
|
19233
|
+
cwd: normalizedCwd,
|
|
19234
|
+
active,
|
|
19235
|
+
diffLineComments,
|
|
19236
|
+
diffStyle,
|
|
19237
|
+
file,
|
|
19238
|
+
open: openFiles.includes(reviewFileValue(file)),
|
|
19239
|
+
stuck: stickyReviewFileValue === reviewFileValue(file),
|
|
19240
|
+
onAddDiffLineComment,
|
|
19241
|
+
onOpenFile
|
|
19242
|
+
}, reviewFileValue(file)))
|
|
19243
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitSectionNote, {
|
|
19244
|
+
className: "px-3 py-2.5",
|
|
19245
|
+
children: "Working tree clean."
|
|
19246
|
+
})
|
|
19247
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollGradientOverlays, {
|
|
19248
|
+
bottomHeight: changesScrollBottomGradientHeight,
|
|
19249
|
+
topHeight: changesScrollTopGradientHeight
|
|
19250
|
+
})]
|
|
19088
19251
|
}),
|
|
19089
19252
|
showEmbeddedHistory && normalizedCwd && viewerContextId && files !== null && !filesQuery.error ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
19090
19253
|
ref: historyPanelRef,
|
|
@@ -19235,6 +19398,7 @@ function ReviewFileAccordionItem({ viewerContextId, cwd, active, diffLineComment
|
|
|
19235
19398
|
} : {};
|
|
19236
19399
|
const themeOptions = usePicoDiffThemeOptions();
|
|
19237
19400
|
const canStage = gitFileCanStage(file);
|
|
19401
|
+
const canUnstage = gitFileCanUnstage(file);
|
|
19238
19402
|
const invalidateChangedFileQueries = async () => {
|
|
19239
19403
|
await invalidateGitQueries({
|
|
19240
19404
|
queryClient,
|
|
@@ -19243,26 +19407,27 @@ function ReviewFileAccordionItem({ viewerContextId, cwd, active, diffLineComment
|
|
|
19243
19407
|
});
|
|
19244
19408
|
};
|
|
19245
19409
|
const stageMutation = useMutation({
|
|
19246
|
-
mutationFn: async () => await fetchJson(buildRequestUrl("/api/git-stage", { contextId: viewerContextId }), {
|
|
19410
|
+
mutationFn: async (action) => await fetchJson(buildRequestUrl("/api/git-stage", { contextId: viewerContextId }), {
|
|
19247
19411
|
method: "POST",
|
|
19248
19412
|
headers: { "content-type": "application/json" },
|
|
19249
19413
|
body: JSON.stringify({
|
|
19414
|
+
action,
|
|
19250
19415
|
cwd: normalizedCwd,
|
|
19251
19416
|
path: file.path,
|
|
19252
19417
|
previousPath: file.previousPath
|
|
19253
19418
|
})
|
|
19254
19419
|
}),
|
|
19255
|
-
onSuccess: async () => {
|
|
19420
|
+
onSuccess: async (_response, action) => {
|
|
19256
19421
|
await queryClient.invalidateQueries({
|
|
19257
19422
|
queryKey: picoQueryKeys.gitStatus(viewerContextId, normalizedCwd),
|
|
19258
19423
|
exact: true,
|
|
19259
19424
|
refetchType: "active"
|
|
19260
19425
|
});
|
|
19261
19426
|
await invalidateChangedFileQueries();
|
|
19262
|
-
toast.success("Staged changes", { description: file.path });
|
|
19427
|
+
toast.success(action === "unstage" ? "Unstaged changes" : "Staged changes", { description: file.path });
|
|
19263
19428
|
},
|
|
19264
|
-
onError: (error) => {
|
|
19265
|
-
toast.error(getErrorMessage(error, "Failed to stage changes"));
|
|
19429
|
+
onError: (error, action) => {
|
|
19430
|
+
toast.error(getErrorMessage(error, action === "unstage" ? "Failed to unstage changes" : "Failed to stage changes"));
|
|
19266
19431
|
}
|
|
19267
19432
|
});
|
|
19268
19433
|
const discardMutation = useMutation({
|
|
@@ -19299,6 +19464,9 @@ function ReviewFileAccordionItem({ viewerContextId, cwd, active, diffLineComment
|
|
|
19299
19464
|
oldContent,
|
|
19300
19465
|
newContent
|
|
19301
19466
|
]);
|
|
19467
|
+
const gitActionDisabled = actionPending || !viewerContextId || !normalizedCwd;
|
|
19468
|
+
const stagePending = stageMutation.isPending && stageMutation.variables === "stage";
|
|
19469
|
+
const unstagePending = stageMutation.isPending && stageMutation.variables === "unstage";
|
|
19302
19470
|
const openFile = (event) => {
|
|
19303
19471
|
event?.stopPropagation();
|
|
19304
19472
|
onOpenFile?.(file.path, { pin: true });
|
|
@@ -19309,50 +19477,81 @@ function ReviewFileAccordionItem({ viewerContextId, cwd, active, diffLineComment
|
|
|
19309
19477
|
};
|
|
19310
19478
|
const stageFileChanges = (event) => {
|
|
19311
19479
|
event?.stopPropagation();
|
|
19312
|
-
stageMutation.mutate();
|
|
19480
|
+
stageMutation.mutate("stage");
|
|
19481
|
+
};
|
|
19482
|
+
const unstageFileChanges = (event) => {
|
|
19483
|
+
event?.stopPropagation();
|
|
19484
|
+
stageMutation.mutate("unstage");
|
|
19313
19485
|
};
|
|
19486
|
+
const trigger = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(AccordionTrigger$1, {
|
|
19487
|
+
"data-review-file-trigger": true,
|
|
19488
|
+
"data-review-file-value": value,
|
|
19489
|
+
className: "group/review-file-trigger relative flex min-h-10 min-w-0 flex-1 items-center justify-between gap-3 rounded-none border border-transparent bg-background px-3 py-2 text-left text-[13px] font-medium transition-all outline-none hover:no-underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground",
|
|
19490
|
+
children: [
|
|
19491
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
19492
|
+
className: "grid min-w-0 flex-1 grid-cols-[auto_auto_minmax(0,1fr)_auto] items-center gap-2",
|
|
19493
|
+
children: [
|
|
19494
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitFileStatus, { status: file.status }),
|
|
19495
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProjectFileTypeIcon, { path: file.path }),
|
|
19496
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19497
|
+
className: "min-w-0 truncate text-left",
|
|
19498
|
+
children: file.previousPath ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
19499
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19500
|
+
className: "text-muted-foreground",
|
|
19501
|
+
children: file.previousPath
|
|
19502
|
+
}),
|
|
19503
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19504
|
+
className: "text-muted-foreground/70",
|
|
19505
|
+
children: " → "
|
|
19506
|
+
}),
|
|
19507
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: file.path })
|
|
19508
|
+
] }) : file.path
|
|
19509
|
+
}),
|
|
19510
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitFileDiff, { file })
|
|
19511
|
+
]
|
|
19512
|
+
}),
|
|
19513
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronRight, {
|
|
19514
|
+
"data-slot": "accordion-trigger-icon",
|
|
19515
|
+
className: "pointer-events-none size-4 shrink-0 group-aria-expanded/review-file-trigger:hidden"
|
|
19516
|
+
}),
|
|
19517
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, {
|
|
19518
|
+
"data-slot": "accordion-trigger-icon",
|
|
19519
|
+
className: "pointer-events-none hidden size-4 shrink-0 group-aria-expanded/review-file-trigger:inline"
|
|
19520
|
+
})
|
|
19521
|
+
]
|
|
19522
|
+
});
|
|
19314
19523
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(AccordionItem, {
|
|
19315
19524
|
value,
|
|
19316
19525
|
className: "border-border/70",
|
|
19317
19526
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(AccordionHeader, {
|
|
19318
19527
|
className: cn("group/review-file-header sticky top-0 z-20 flex bg-background transition-shadow", stuck && "shadow-sm"),
|
|
19319
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
19320
|
-
"
|
|
19321
|
-
"data-review-file-value": value,
|
|
19322
|
-
className: "group/review-file-trigger relative flex min-h-10 min-w-0 flex-1 items-center justify-between gap-3 rounded-none border border-transparent bg-background px-3 py-2 text-left font-mono text-[13px] font-medium transition-all outline-none hover:no-underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground",
|
|
19528
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ContextMenu$1, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuTrigger, { render: trigger }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ContextMenuContent, {
|
|
19529
|
+
className: "w-48",
|
|
19323
19530
|
children: [
|
|
19324
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
19325
|
-
|
|
19326
|
-
|
|
19327
|
-
|
|
19328
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ProjectFileTypeIcon, { path: file.path }),
|
|
19329
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19330
|
-
className: "min-w-0 truncate text-left",
|
|
19331
|
-
children: file.previousPath ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
19332
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19333
|
-
className: "text-muted-foreground",
|
|
19334
|
-
children: file.previousPath
|
|
19335
|
-
}),
|
|
19336
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
19337
|
-
className: "text-muted-foreground/70",
|
|
19338
|
-
children: " → "
|
|
19339
|
-
}),
|
|
19340
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: file.path })
|
|
19341
|
-
] }) : file.path
|
|
19342
|
-
}),
|
|
19343
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitFileDiff, { file })
|
|
19344
|
-
]
|
|
19531
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ContextMenuItem, {
|
|
19532
|
+
disabled: !onOpenFile,
|
|
19533
|
+
onClick: openFile,
|
|
19534
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArrowUpRight, {}), "Open file"]
|
|
19345
19535
|
}),
|
|
19346
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
19347
|
-
|
|
19348
|
-
|
|
19536
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ContextMenuSeparator, {}),
|
|
19537
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ContextMenuItem, {
|
|
19538
|
+
disabled: gitActionDisabled || !canStage,
|
|
19539
|
+
onClick: stageFileChanges,
|
|
19540
|
+
children: [stagePending ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, { size: "xs" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Plus, {}), "Stage changes"]
|
|
19349
19541
|
}),
|
|
19350
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
19351
|
-
|
|
19352
|
-
|
|
19542
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ContextMenuItem, {
|
|
19543
|
+
disabled: gitActionDisabled || !canUnstage,
|
|
19544
|
+
onClick: unstageFileChanges,
|
|
19545
|
+
children: [unstagePending ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, { size: "xs" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Minus, {}), "Unstage changes"]
|
|
19546
|
+
}),
|
|
19547
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ContextMenuItem, {
|
|
19548
|
+
variant: "destructive",
|
|
19549
|
+
disabled: gitActionDisabled,
|
|
19550
|
+
onClick: discardFileChanges,
|
|
19551
|
+
children: [discardMutation.isPending ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, { size: "xs" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Undo2, {}), "Discard changes"]
|
|
19353
19552
|
})
|
|
19354
19553
|
]
|
|
19355
|
-
})
|
|
19554
|
+
})] })
|
|
19356
19555
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(AccordionContent, {
|
|
19357
19556
|
className: "bg-background p-0",
|
|
19358
19557
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
@@ -19597,7 +19796,7 @@ function assignClassName(element, className) {
|
|
|
19597
19796
|
}
|
|
19598
19797
|
function renderPendingCommitDiffLineComment(pendingComment) {
|
|
19599
19798
|
const form = document.createElement("form");
|
|
19600
|
-
assignClassName(form, "m-2 w-[
|
|
19799
|
+
assignClassName(form, "m-2 w-[calc(100%_-_1rem)] max-w-[38rem] rounded-lg border border-border/70 bg-background p-2 shadow-sm");
|
|
19601
19800
|
const header = document.createElement("div");
|
|
19602
19801
|
assignClassName(header, "mb-2 flex min-w-0 items-center justify-between gap-2 text-xs text-muted-foreground");
|
|
19603
19802
|
const label = document.createElement("span");
|
|
@@ -19740,7 +19939,7 @@ function CommitFileDiffAccordionItem({ comments, diffStyle, fileDiff, index, onS
|
|
|
19740
19939
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(AccordionTrigger$1, {
|
|
19741
19940
|
"data-commit-file-trigger": true,
|
|
19742
19941
|
"data-commit-file-value": value,
|
|
19743
|
-
className: "group/commit-file-trigger relative flex min-h-10 min-w-0 flex-1 items-center justify-between gap-3 rounded-none border border-transparent bg-background px-3 py-2 text-left
|
|
19942
|
+
className: "group/commit-file-trigger relative flex min-h-10 min-w-0 flex-1 items-center justify-between gap-3 rounded-none border border-transparent bg-background px-3 py-2 text-left text-[13px] font-medium transition-all outline-none hover:no-underline focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground",
|
|
19744
19943
|
children: [
|
|
19745
19944
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", {
|
|
19746
19945
|
className: "grid min-w-0 flex-1 grid-cols-[minmax(0,1fr)_auto] items-baseline gap-3",
|
|
@@ -19878,8 +20077,14 @@ function CommitDiffHeaderTitle({ tab }) {
|
|
|
19878
20077
|
function CommitDiffContent({ viewerContextId, cwd, active, diffLineComments, onAddDiffLineComment, tab }) {
|
|
19879
20078
|
const [diffStyle, setDiffStyle] = import_react.useState("unified");
|
|
19880
20079
|
const [stickyCommitFileValue, setStickyCommitFileValue] = import_react.useState("");
|
|
20080
|
+
const isMobile = useIsMobile();
|
|
19881
20081
|
const [commentTarget, setCommentTarget] = import_react.useState(null);
|
|
19882
20082
|
const diffScrollRef = import_react.useRef(null);
|
|
20083
|
+
const { bottomHeight: diffScrollBottomGradientHeight, onScroll: onDiffScrollGradientScroll, setScrollElement: setDiffScrollGradientElement, topHeight: diffScrollTopGradientHeight } = useScrollGradients();
|
|
20084
|
+
const setDiffScrollElement = import_react.useCallback((element) => {
|
|
20085
|
+
diffScrollRef.current = element;
|
|
20086
|
+
setDiffScrollGradientElement(element);
|
|
20087
|
+
}, [setDiffScrollGradientElement]);
|
|
19883
20088
|
const updateStickyCommitFileHeader = (scrollElement) => {
|
|
19884
20089
|
setDerivedScrollState(setStickyCommitFileValue, getStuckScrollTriggerValue({
|
|
19885
20090
|
getValue: (trigger) => trigger.dataset.commitFileValue || "",
|
|
@@ -19945,6 +20150,7 @@ function CommitDiffContent({ viewerContextId, cwd, active, diffLineComments, onA
|
|
|
19945
20150
|
className: "flex min-h-10 shrink-0 items-center justify-between gap-2 border-b border-border/70 bg-background p-2",
|
|
19946
20151
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommitDiffHeaderTitle, { tab }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(ToggleGroup$1, {
|
|
19947
20152
|
variant: "outline",
|
|
20153
|
+
size: isMobile ? "default" : "sm",
|
|
19948
20154
|
value: [diffStyle],
|
|
19949
20155
|
onValueChange: (values) => {
|
|
19950
20156
|
const value = values[0];
|
|
@@ -19958,41 +20164,48 @@ function CommitDiffContent({ viewerContextId, cwd, active, diffLineComments, onA
|
|
|
19958
20164
|
children: "Split"
|
|
19959
20165
|
})]
|
|
19960
20166
|
})]
|
|
19961
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.
|
|
19962
|
-
|
|
19963
|
-
|
|
19964
|
-
|
|
19965
|
-
|
|
19966
|
-
|
|
19967
|
-
|
|
19968
|
-
|
|
19969
|
-
|
|
19970
|
-
|
|
19971
|
-
|
|
19972
|
-
|
|
19973
|
-
|
|
19974
|
-
|
|
20167
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
20168
|
+
className: "relative min-h-0 flex-1",
|
|
20169
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
20170
|
+
ref: setDiffScrollElement,
|
|
20171
|
+
className: "h-full overflow-auto",
|
|
20172
|
+
onScroll: (event) => {
|
|
20173
|
+
updateStickyCommitFileHeader(event.currentTarget);
|
|
20174
|
+
onDiffScrollGradientScroll(event);
|
|
20175
|
+
},
|
|
20176
|
+
children: diffQuery.isPending && !diffQuery.data ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
20177
|
+
className: "p-4",
|
|
20178
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(GitSectionNote, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}), " Loading commit diff…"] })
|
|
20179
|
+
}) : diffQuery.error ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
20180
|
+
className: "p-4",
|
|
20181
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitSectionNote, {
|
|
20182
|
+
tone: "destructive",
|
|
20183
|
+
children: getErrorMessage(diffQuery.error, "Failed to load commit diff")
|
|
20184
|
+
})
|
|
20185
|
+
}) : diffQuery.data?.patch && tab.path ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommitSingleFileDiff, {
|
|
20186
|
+
comments: commentsForTab.filter((comment) => {
|
|
20187
|
+
if (!tab.path) return true;
|
|
20188
|
+
return comment.path === tab.path || comment.path === tab.previousPath;
|
|
20189
|
+
}),
|
|
20190
|
+
diffStyle,
|
|
20191
|
+
onStartComment: startLineComment,
|
|
20192
|
+
patch: diffQuery.data.patch,
|
|
20193
|
+
pendingComment
|
|
20194
|
+
}) : diffQuery.data?.patch ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommitPatchDiffs, {
|
|
20195
|
+
comments: commentsForTab,
|
|
20196
|
+
diffStyle,
|
|
20197
|
+
onStartComment: startLineComment,
|
|
20198
|
+
patch: diffQuery.data.patch,
|
|
20199
|
+
pendingComment,
|
|
20200
|
+
stuckFileValue: stickyCommitFileValue
|
|
20201
|
+
}, `${diffQuery.data.commit}:${diffQuery.data.mode}`) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
20202
|
+
className: "p-4",
|
|
20203
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitSectionNote, { children: "No line changes." })
|
|
19975
20204
|
})
|
|
19976
|
-
})
|
|
19977
|
-
|
|
19978
|
-
|
|
19979
|
-
|
|
19980
|
-
}),
|
|
19981
|
-
diffStyle,
|
|
19982
|
-
onStartComment: startLineComment,
|
|
19983
|
-
patch: diffQuery.data.patch,
|
|
19984
|
-
pendingComment
|
|
19985
|
-
}) : diffQuery.data?.patch ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CommitPatchDiffs, {
|
|
19986
|
-
comments: commentsForTab,
|
|
19987
|
-
diffStyle,
|
|
19988
|
-
onStartComment: startLineComment,
|
|
19989
|
-
patch: diffQuery.data.patch,
|
|
19990
|
-
pendingComment,
|
|
19991
|
-
stuckFileValue: stickyCommitFileValue
|
|
19992
|
-
}, `${diffQuery.data.commit}:${diffQuery.data.mode}`) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
19993
|
-
className: "p-4",
|
|
19994
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitSectionNote, { children: "No line changes." })
|
|
19995
|
-
})
|
|
20205
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ScrollGradientOverlays, {
|
|
20206
|
+
bottomHeight: diffScrollBottomGradientHeight,
|
|
20207
|
+
topHeight: diffScrollTopGradientHeight
|
|
20208
|
+
})]
|
|
19996
20209
|
})]
|
|
19997
20210
|
});
|
|
19998
20211
|
}
|
|
@@ -20249,43 +20462,848 @@ function RightSidebar({ viewerContextId, cwd, active, activeFilePath = "", activ
|
|
|
20249
20462
|
})]
|
|
20250
20463
|
});
|
|
20251
20464
|
}
|
|
20252
|
-
|
|
20253
|
-
|
|
20254
|
-
|
|
20255
|
-
|
|
20256
|
-
|
|
20257
|
-
|
|
20258
|
-
|
|
20465
|
+
var TERMINAL_ANSI_THEMES = {
|
|
20466
|
+
dark: {
|
|
20467
|
+
black: "#484f58",
|
|
20468
|
+
red: "#ff7b72",
|
|
20469
|
+
green: "#3fb950",
|
|
20470
|
+
yellow: "#d29922",
|
|
20471
|
+
blue: "#58a6ff",
|
|
20472
|
+
magenta: "#bc8cff",
|
|
20473
|
+
cyan: "#39c5cf",
|
|
20474
|
+
white: "#b1bac4",
|
|
20475
|
+
brightBlack: "#6e7681",
|
|
20476
|
+
brightRed: "#ffa198",
|
|
20477
|
+
brightGreen: "#56d364",
|
|
20478
|
+
brightYellow: "#e3b341",
|
|
20479
|
+
brightBlue: "#79c0ff",
|
|
20480
|
+
brightMagenta: "#d2a8ff",
|
|
20481
|
+
brightCyan: "#56d4dd",
|
|
20482
|
+
brightWhite: "#f0f6fc"
|
|
20483
|
+
},
|
|
20484
|
+
light: {
|
|
20485
|
+
black: "#24292f",
|
|
20486
|
+
red: "#cf222e",
|
|
20487
|
+
green: "#116329",
|
|
20488
|
+
yellow: "#953800",
|
|
20489
|
+
blue: "#0969da",
|
|
20490
|
+
magenta: "#8250df",
|
|
20491
|
+
cyan: "#1b7c83",
|
|
20492
|
+
white: "#6e7781",
|
|
20493
|
+
brightBlack: "#57606a",
|
|
20494
|
+
brightRed: "#a40e26",
|
|
20495
|
+
brightGreen: "#1a7f37",
|
|
20496
|
+
brightYellow: "#9a6700",
|
|
20497
|
+
brightBlue: "#218bff",
|
|
20498
|
+
brightMagenta: "#a475f9",
|
|
20499
|
+
brightCyan: "#3192aa",
|
|
20500
|
+
brightWhite: "#24292f"
|
|
20501
|
+
}
|
|
20502
|
+
};
|
|
20503
|
+
var terminalTabCounter = 0;
|
|
20504
|
+
function createTerminalTabId() {
|
|
20505
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return `terminal-tab-${crypto.randomUUID()}`;
|
|
20506
|
+
terminalTabCounter += 1;
|
|
20507
|
+
return `terminal-tab-${Date.now()}-${terminalTabCounter}`;
|
|
20259
20508
|
}
|
|
20260
|
-
function
|
|
20261
|
-
|
|
20262
|
-
|
|
20509
|
+
function createTerminalTab(id = createTerminalTabId()) {
|
|
20510
|
+
return {
|
|
20511
|
+
id,
|
|
20512
|
+
status: { type: "idle" },
|
|
20513
|
+
terminalId: null
|
|
20514
|
+
};
|
|
20263
20515
|
}
|
|
20264
|
-
function
|
|
20516
|
+
function createTerminalTabsState(scopeKey) {
|
|
20517
|
+
const storedTabs = readStoredTerminalTabs(scopeKey);
|
|
20518
|
+
const tabs = storedTabs.tabs.map((id) => createTerminalTab(id));
|
|
20265
20519
|
return {
|
|
20266
|
-
|
|
20267
|
-
|
|
20268
|
-
|
|
20269
|
-
fileTabs: [],
|
|
20270
|
-
fileTreeCollapsed: false
|
|
20520
|
+
activeTabId: storedTabs.activeTabId ?? tabs[0]?.id ?? null,
|
|
20521
|
+
scopeKey,
|
|
20522
|
+
tabs
|
|
20271
20523
|
};
|
|
20272
20524
|
}
|
|
20273
|
-
function
|
|
20274
|
-
|
|
20525
|
+
function rememberTerminalTabsState(state) {
|
|
20526
|
+
rememberStoredTerminalTabs(state.scopeKey, {
|
|
20527
|
+
activeTabId: state.activeTabId,
|
|
20528
|
+
tabs: state.tabs.map((tab) => tab.id)
|
|
20529
|
+
});
|
|
20275
20530
|
}
|
|
20276
|
-
function
|
|
20277
|
-
|
|
20531
|
+
function terminalStatusText(status) {
|
|
20532
|
+
switch (status.type) {
|
|
20533
|
+
case "idle": return "Idle";
|
|
20534
|
+
case "connecting": return "Connecting…";
|
|
20535
|
+
case "connected": return status.shell ? `Running ${status.shell}` : "Connected";
|
|
20536
|
+
case "exited": return `Exited ${status.exitCode}`;
|
|
20537
|
+
case "error": return "Terminal error";
|
|
20538
|
+
}
|
|
20278
20539
|
}
|
|
20279
|
-
function
|
|
20280
|
-
|
|
20281
|
-
|
|
20282
|
-
|
|
20283
|
-
|
|
20284
|
-
|
|
20285
|
-
|
|
20286
|
-
}
|
|
20540
|
+
function terminalStatusDetail(status) {
|
|
20541
|
+
switch (status.type) {
|
|
20542
|
+
case "idle": return "This terminal has not started yet.";
|
|
20543
|
+
case "connecting": return "Pico is connecting to the terminal process.";
|
|
20544
|
+
case "connected": return status.shell ? `The terminal is connected and running ${status.shell}.` : "The terminal is connected.";
|
|
20545
|
+
case "exited": return typeof status.signal === "number" ? `The terminal process exited with code ${status.exitCode} and signal ${status.signal}.` : `The terminal process exited with code ${status.exitCode}.`;
|
|
20546
|
+
case "error": return status.message;
|
|
20547
|
+
}
|
|
20287
20548
|
}
|
|
20288
|
-
function
|
|
20549
|
+
function terminalTabLabel(tab, index) {
|
|
20550
|
+
if (tab.status.type === "connected" && tab.status.shell) return `${index + 1}: ${tab.status.shell}`;
|
|
20551
|
+
return `Terminal ${index + 1}`;
|
|
20552
|
+
}
|
|
20553
|
+
function statusDotClassName(status) {
|
|
20554
|
+
switch (status.type) {
|
|
20555
|
+
case "connected": return "bg-success";
|
|
20556
|
+
case "connecting": return "bg-warning";
|
|
20557
|
+
case "error":
|
|
20558
|
+
case "exited": return "bg-destructive";
|
|
20559
|
+
case "idle": return "bg-muted-foreground/50";
|
|
20560
|
+
}
|
|
20561
|
+
}
|
|
20562
|
+
function cssVariable(name, fallback) {
|
|
20563
|
+
return window.getComputedStyle(document.documentElement).getPropertyValue(name).trim() || fallback;
|
|
20564
|
+
}
|
|
20565
|
+
function resolveTerminalThemeMode() {
|
|
20566
|
+
for (const className of document.documentElement.classList) {
|
|
20567
|
+
const mode = appliedThemeClassColorMode(className);
|
|
20568
|
+
if (mode) return mode;
|
|
20569
|
+
}
|
|
20570
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
20571
|
+
}
|
|
20572
|
+
function terminalAnsiTheme() {
|
|
20573
|
+
const fallback = TERMINAL_ANSI_THEMES[resolveTerminalThemeMode()];
|
|
20574
|
+
return {
|
|
20575
|
+
black: cssVariable("--terminal-ansi-black", fallback.black),
|
|
20576
|
+
red: cssVariable("--terminal-ansi-red", fallback.red),
|
|
20577
|
+
green: cssVariable("--terminal-ansi-green", fallback.green),
|
|
20578
|
+
yellow: cssVariable("--terminal-ansi-yellow", fallback.yellow),
|
|
20579
|
+
blue: cssVariable("--terminal-ansi-blue", fallback.blue),
|
|
20580
|
+
magenta: cssVariable("--terminal-ansi-magenta", fallback.magenta),
|
|
20581
|
+
cyan: cssVariable("--terminal-ansi-cyan", fallback.cyan),
|
|
20582
|
+
white: cssVariable("--terminal-ansi-white", fallback.white),
|
|
20583
|
+
brightBlack: cssVariable("--terminal-ansi-bright-black", fallback.brightBlack),
|
|
20584
|
+
brightRed: cssVariable("--terminal-ansi-bright-red", fallback.brightRed),
|
|
20585
|
+
brightGreen: cssVariable("--terminal-ansi-bright-green", fallback.brightGreen),
|
|
20586
|
+
brightYellow: cssVariable("--terminal-ansi-bright-yellow", fallback.brightYellow),
|
|
20587
|
+
brightBlue: cssVariable("--terminal-ansi-bright-blue", fallback.brightBlue),
|
|
20588
|
+
brightMagenta: cssVariable("--terminal-ansi-bright-magenta", fallback.brightMagenta),
|
|
20589
|
+
brightCyan: cssVariable("--terminal-ansi-bright-cyan", fallback.brightCyan),
|
|
20590
|
+
brightWhite: cssVariable("--terminal-ansi-bright-white", fallback.brightWhite)
|
|
20591
|
+
};
|
|
20592
|
+
}
|
|
20593
|
+
function createTerminalTheme() {
|
|
20594
|
+
const ansiTheme = terminalAnsiTheme();
|
|
20595
|
+
return {
|
|
20596
|
+
...ansiTheme,
|
|
20597
|
+
background: cssVariable("--terminal-background", cssVariable("--background", "#111111")),
|
|
20598
|
+
cursor: cssVariable("--terminal-cursor", cssVariable("--primary", "#7aa2f7")),
|
|
20599
|
+
foreground: cssVariable("--terminal-foreground", cssVariable("--foreground", ansiTheme.brightWhite)),
|
|
20600
|
+
selectionBackground: cssVariable("--terminal-selection-background", cssVariable("--code-selection", "#334155"))
|
|
20601
|
+
};
|
|
20602
|
+
}
|
|
20603
|
+
function createTerminalFontFamily() {
|
|
20604
|
+
return cssVariable("--font-mono", "Menlo, ui-monospace, SFMono-Regular, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace");
|
|
20605
|
+
}
|
|
20606
|
+
function errorMessage(error) {
|
|
20607
|
+
if (error instanceof Error && error.message.trim()) return error.message;
|
|
20608
|
+
if (typeof error === "string" && error.trim()) return error;
|
|
20609
|
+
return "Unknown terminal error";
|
|
20610
|
+
}
|
|
20611
|
+
function buildTerminalWebSocketUrl(path, options) {
|
|
20612
|
+
const url = new URL(buildRequestUrl(path, options));
|
|
20613
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
20614
|
+
return url.toString();
|
|
20615
|
+
}
|
|
20616
|
+
function exitedStatus(event) {
|
|
20617
|
+
return typeof event.signal === "number" && event.signal > 0 ? {
|
|
20618
|
+
type: "exited",
|
|
20619
|
+
exitCode: event.exitCode,
|
|
20620
|
+
signal: event.signal
|
|
20621
|
+
} : {
|
|
20622
|
+
type: "exited",
|
|
20623
|
+
exitCode: event.exitCode
|
|
20624
|
+
};
|
|
20625
|
+
}
|
|
20626
|
+
function isTerminalToggleEvent(event) {
|
|
20627
|
+
return event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey && (event.key === "`" || event.code === "Backquote");
|
|
20628
|
+
}
|
|
20629
|
+
function TerminalStatusDot({ status }) {
|
|
20630
|
+
if (status.type === "connecting") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {
|
|
20631
|
+
size: "xs",
|
|
20632
|
+
className: "shrink-0"
|
|
20633
|
+
});
|
|
20634
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
20635
|
+
"aria-hidden": "true",
|
|
20636
|
+
className: cn("size-2 shrink-0 rounded-full", statusDotClassName(status))
|
|
20637
|
+
});
|
|
20638
|
+
}
|
|
20639
|
+
function TerminalStatusDialog({ cwd, index, onOpenChange, open, tab }) {
|
|
20640
|
+
const status = tab?.status ?? { type: "idle" };
|
|
20641
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dialog$1, {
|
|
20642
|
+
open,
|
|
20643
|
+
onOpenChange,
|
|
20644
|
+
focusPromptOnClose: false,
|
|
20645
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogContent, {
|
|
20646
|
+
className: "max-w-sm",
|
|
20647
|
+
children: [
|
|
20648
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogHeader, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(DialogTitle, { children: [tab ? terminalTabLabel(tab, index) : "Terminal", " status"] }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogDescription, { children: terminalStatusDetail(status) })] }),
|
|
20649
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("dl", {
|
|
20650
|
+
className: "grid gap-3 text-sm",
|
|
20651
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
20652
|
+
className: "grid gap-1",
|
|
20653
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
|
|
20654
|
+
className: "text-xs font-medium text-muted-foreground",
|
|
20655
|
+
children: "Status"
|
|
20656
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", { children: terminalStatusText(status) })]
|
|
20657
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
20658
|
+
className: "grid gap-1",
|
|
20659
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("dt", {
|
|
20660
|
+
className: "text-xs font-medium text-muted-foreground",
|
|
20661
|
+
children: "Working directory"
|
|
20662
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("dd", {
|
|
20663
|
+
className: "break-all",
|
|
20664
|
+
children: cwd
|
|
20665
|
+
})]
|
|
20666
|
+
})]
|
|
20667
|
+
}),
|
|
20668
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(DialogFooter, { showCloseButton: true })
|
|
20669
|
+
]
|
|
20670
|
+
})
|
|
20671
|
+
});
|
|
20672
|
+
}
|
|
20673
|
+
function TerminalTabPane({ active, cwd, onStatusChange, onTerminalIdChange, selected, sessionId, tabId, viewerContextId }) {
|
|
20674
|
+
const terminalElementRef = import_react.useRef(null);
|
|
20675
|
+
const terminalRef = import_react.useRef(null);
|
|
20676
|
+
const terminalIdRef = import_react.useRef(null);
|
|
20677
|
+
const activeRef = import_react.useRef(active);
|
|
20678
|
+
const fitAndResizeRef = import_react.useRef(() => {});
|
|
20679
|
+
const onStatusChangeRef = import_react.useRef(onStatusChange);
|
|
20680
|
+
const onTerminalIdChangeRef = import_react.useRef(onTerminalIdChange);
|
|
20681
|
+
const [status, setStatus] = import_react.useState({ type: "idle" });
|
|
20682
|
+
import_react.useLayoutEffect(() => {
|
|
20683
|
+
activeRef.current = active;
|
|
20684
|
+
}, [active]);
|
|
20685
|
+
import_react.useEffect(() => {
|
|
20686
|
+
onStatusChangeRef.current = onStatusChange;
|
|
20687
|
+
}, [onStatusChange]);
|
|
20688
|
+
import_react.useEffect(() => {
|
|
20689
|
+
onTerminalIdChangeRef.current = onTerminalIdChange;
|
|
20690
|
+
}, [onTerminalIdChange]);
|
|
20691
|
+
import_react.useEffect(() => {
|
|
20692
|
+
if (!cwd) {
|
|
20693
|
+
setStatus({ type: "idle" });
|
|
20694
|
+
onStatusChangeRef.current(tabId, { type: "idle" });
|
|
20695
|
+
return;
|
|
20696
|
+
}
|
|
20697
|
+
const terminalElement = terminalElementRef.current;
|
|
20698
|
+
if (!terminalElement) return;
|
|
20699
|
+
let disposed = false;
|
|
20700
|
+
let websocket = null;
|
|
20701
|
+
let inputDisposable = null;
|
|
20702
|
+
let fitAddon = null;
|
|
20703
|
+
let resizeObserver = null;
|
|
20704
|
+
let inputFlushTimer = null;
|
|
20705
|
+
let pingTimer = null;
|
|
20706
|
+
let reconnectTimer = null;
|
|
20707
|
+
let resizeFrame = null;
|
|
20708
|
+
let inputBuffer = "";
|
|
20709
|
+
let lastResizeKey = "";
|
|
20710
|
+
let lastOutputSeq = 0;
|
|
20711
|
+
let nextInputSeq = 1;
|
|
20712
|
+
let reconnectAttempt = 0;
|
|
20713
|
+
let terminalExited = false;
|
|
20714
|
+
let terminalTransportReady = false;
|
|
20715
|
+
const pendingInputs = /* @__PURE__ */ new Map();
|
|
20716
|
+
const requestOptions = sessionId ? {
|
|
20717
|
+
contextId: viewerContextId,
|
|
20718
|
+
sessionId
|
|
20719
|
+
} : { contextId: viewerContextId };
|
|
20720
|
+
const publishStatus = (nextStatus) => {
|
|
20721
|
+
if (disposed) return;
|
|
20722
|
+
setStatus(nextStatus);
|
|
20723
|
+
onStatusChangeRef.current(tabId, nextStatus);
|
|
20724
|
+
};
|
|
20725
|
+
const postJson = async (path, body) => {
|
|
20726
|
+
return await fetchJson(buildRequestUrl(path, requestOptions), {
|
|
20727
|
+
body: JSON.stringify(body),
|
|
20728
|
+
headers: { "content-type": "application/json" },
|
|
20729
|
+
method: "POST"
|
|
20730
|
+
});
|
|
20731
|
+
};
|
|
20732
|
+
const sendTerminalMessage = (message) => {
|
|
20733
|
+
if (!websocket || websocket.readyState !== WebSocket.OPEN) return false;
|
|
20734
|
+
try {
|
|
20735
|
+
websocket.send(JSON.stringify(message));
|
|
20736
|
+
return true;
|
|
20737
|
+
} catch (error) {
|
|
20738
|
+
publishStatus({
|
|
20739
|
+
type: "error",
|
|
20740
|
+
message: errorMessage(error)
|
|
20741
|
+
});
|
|
20742
|
+
return false;
|
|
20743
|
+
}
|
|
20744
|
+
};
|
|
20745
|
+
const sendPendingInputs = () => {
|
|
20746
|
+
if (!terminalTransportReady) return;
|
|
20747
|
+
for (const [inputSeq, data] of [...pendingInputs.entries()].sort(([left], [right]) => left - right)) if (!sendTerminalMessage({
|
|
20748
|
+
type: "input",
|
|
20749
|
+
data,
|
|
20750
|
+
inputSeq
|
|
20751
|
+
})) return;
|
|
20752
|
+
};
|
|
20753
|
+
const flushInput = () => {
|
|
20754
|
+
inputFlushTimer = null;
|
|
20755
|
+
if (!terminalIdRef.current || !inputBuffer || !terminalTransportReady) return;
|
|
20756
|
+
const data = inputBuffer;
|
|
20757
|
+
const inputSeq = nextInputSeq;
|
|
20758
|
+
nextInputSeq += 1;
|
|
20759
|
+
inputBuffer = "";
|
|
20760
|
+
pendingInputs.set(inputSeq, data);
|
|
20761
|
+
sendPendingInputs();
|
|
20762
|
+
};
|
|
20763
|
+
const scheduleInputFlush = () => {
|
|
20764
|
+
if (inputFlushTimer !== null) return;
|
|
20765
|
+
inputFlushTimer = window.setTimeout(flushInput, 12);
|
|
20766
|
+
};
|
|
20767
|
+
const fitAndResize = () => {
|
|
20768
|
+
const terminal = terminalRef.current;
|
|
20769
|
+
if (!terminal || !fitAddon) return;
|
|
20770
|
+
try {
|
|
20771
|
+
fitAddon.fit();
|
|
20772
|
+
} catch {
|
|
20773
|
+
return;
|
|
20774
|
+
}
|
|
20775
|
+
if (!terminalIdRef.current || !terminalTransportReady) return;
|
|
20776
|
+
const resizeKey = `${terminal.cols}x${terminal.rows}`;
|
|
20777
|
+
if (resizeKey === lastResizeKey) return;
|
|
20778
|
+
if (!sendTerminalMessage({
|
|
20779
|
+
type: "resize",
|
|
20780
|
+
cols: terminal.cols,
|
|
20781
|
+
rows: terminal.rows
|
|
20782
|
+
})) return;
|
|
20783
|
+
lastResizeKey = resizeKey;
|
|
20784
|
+
};
|
|
20785
|
+
const scheduleFitAndResize = () => {
|
|
20786
|
+
if (resizeFrame !== null) return;
|
|
20787
|
+
resizeFrame = window.requestAnimationFrame(() => {
|
|
20788
|
+
resizeFrame = null;
|
|
20789
|
+
fitAndResize();
|
|
20790
|
+
});
|
|
20791
|
+
};
|
|
20792
|
+
fitAndResizeRef.current = scheduleFitAndResize;
|
|
20793
|
+
const clearPingTimer = () => {
|
|
20794
|
+
if (pingTimer === null) return;
|
|
20795
|
+
window.clearInterval(pingTimer);
|
|
20796
|
+
pingTimer = null;
|
|
20797
|
+
};
|
|
20798
|
+
const startPingTimer = () => {
|
|
20799
|
+
clearPingTimer();
|
|
20800
|
+
pingTimer = window.setInterval(() => {
|
|
20801
|
+
sendTerminalMessage({ type: "ping" });
|
|
20802
|
+
}, 2e4);
|
|
20803
|
+
};
|
|
20804
|
+
const scheduleWebSocketReconnect = () => {
|
|
20805
|
+
if (disposed || terminalExited || reconnectTimer !== null) return;
|
|
20806
|
+
terminalTransportReady = false;
|
|
20807
|
+
clearPingTimer();
|
|
20808
|
+
reconnectAttempt += 1;
|
|
20809
|
+
const delay = Math.min(1e4, 500 * 2 ** (reconnectAttempt - 1));
|
|
20810
|
+
reconnectTimer = window.setTimeout(() => {
|
|
20811
|
+
reconnectTimer = null;
|
|
20812
|
+
const id = terminalIdRef.current;
|
|
20813
|
+
if (!id || disposed || terminalExited) return;
|
|
20814
|
+
publishStatus({ type: "connecting" });
|
|
20815
|
+
connectTerminalWebSocket(id);
|
|
20816
|
+
}, delay);
|
|
20817
|
+
};
|
|
20818
|
+
const handleTerminalEvent = (event) => {
|
|
20819
|
+
const terminal = terminalRef.current;
|
|
20820
|
+
if (!terminal) return;
|
|
20821
|
+
if (event.type === "output") {
|
|
20822
|
+
if (typeof event.seq === "number") {
|
|
20823
|
+
if (event.seq <= lastOutputSeq) return;
|
|
20824
|
+
lastOutputSeq = event.seq;
|
|
20825
|
+
}
|
|
20826
|
+
terminal.write(event.data);
|
|
20827
|
+
return;
|
|
20828
|
+
}
|
|
20829
|
+
if (event.type === "reset") {
|
|
20830
|
+
lastOutputSeq = Math.max(0, event.firstSeq - 1);
|
|
20831
|
+
terminal.clear();
|
|
20832
|
+
terminal.writeln("Terminal output replay gap; showing retained output.");
|
|
20833
|
+
return;
|
|
20834
|
+
}
|
|
20835
|
+
if (event.type === "ready") {
|
|
20836
|
+
terminalTransportReady = true;
|
|
20837
|
+
reconnectAttempt = 0;
|
|
20838
|
+
nextInputSeq = Math.max(nextInputSeq, event.nextInputSeq ?? 1);
|
|
20839
|
+
publishStatus({
|
|
20840
|
+
type: "connected",
|
|
20841
|
+
shell: event.shell
|
|
20842
|
+
});
|
|
20843
|
+
startPingTimer();
|
|
20844
|
+
sendPendingInputs();
|
|
20845
|
+
flushInput();
|
|
20846
|
+
lastResizeKey = "";
|
|
20847
|
+
scheduleFitAndResize();
|
|
20848
|
+
return;
|
|
20849
|
+
}
|
|
20850
|
+
if (event.type === "input_ack") {
|
|
20851
|
+
pendingInputs.delete(event.inputSeq);
|
|
20852
|
+
return;
|
|
20853
|
+
}
|
|
20854
|
+
if (event.type === "pong") return;
|
|
20855
|
+
if (event.type === "exit") {
|
|
20856
|
+
terminalExited = true;
|
|
20857
|
+
terminalTransportReady = false;
|
|
20858
|
+
clearPingTimer();
|
|
20859
|
+
publishStatus(exitedStatus(event));
|
|
20860
|
+
return;
|
|
20861
|
+
}
|
|
20862
|
+
if (event.type === "error") publishStatus({
|
|
20863
|
+
type: "error",
|
|
20864
|
+
message: event.error
|
|
20865
|
+
});
|
|
20866
|
+
};
|
|
20867
|
+
function connectTerminalWebSocket(id) {
|
|
20868
|
+
if (websocket) {
|
|
20869
|
+
websocket.onclose = null;
|
|
20870
|
+
websocket.onerror = null;
|
|
20871
|
+
websocket.onmessage = null;
|
|
20872
|
+
websocket.close();
|
|
20873
|
+
}
|
|
20874
|
+
terminalTransportReady = false;
|
|
20875
|
+
const nextWebSocket = new WebSocket(buildTerminalWebSocketUrl(`/api/terminal/${encodeURIComponent(id)}/ws`, {
|
|
20876
|
+
...requestOptions,
|
|
20877
|
+
searchParams: { lastSeq: lastOutputSeq || void 0 }
|
|
20878
|
+
}));
|
|
20879
|
+
websocket = nextWebSocket;
|
|
20880
|
+
nextWebSocket.onmessage = (message) => {
|
|
20881
|
+
if (disposed || websocket !== nextWebSocket) return;
|
|
20882
|
+
try {
|
|
20883
|
+
handleTerminalEvent(JSON.parse(message.data));
|
|
20884
|
+
} catch (error) {
|
|
20885
|
+
publishStatus({
|
|
20886
|
+
type: "error",
|
|
20887
|
+
message: errorMessage(error)
|
|
20888
|
+
});
|
|
20889
|
+
}
|
|
20890
|
+
};
|
|
20891
|
+
nextWebSocket.onclose = () => {
|
|
20892
|
+
if (websocket !== nextWebSocket) return;
|
|
20893
|
+
websocket = null;
|
|
20894
|
+
terminalTransportReady = false;
|
|
20895
|
+
scheduleWebSocketReconnect();
|
|
20896
|
+
};
|
|
20897
|
+
nextWebSocket.onerror = () => {
|
|
20898
|
+
if (websocket !== nextWebSocket) return;
|
|
20899
|
+
terminalTransportReady = false;
|
|
20900
|
+
nextWebSocket.close();
|
|
20901
|
+
};
|
|
20902
|
+
}
|
|
20903
|
+
const startTerminal = async () => {
|
|
20904
|
+
try {
|
|
20905
|
+
publishStatus({ type: "connecting" });
|
|
20906
|
+
terminalElement.textContent = "";
|
|
20907
|
+
const [{ Terminal }, { FitAddon }] = await Promise.all([import("../_libs/xterm__xterm.mjs").then((n) => n.t), import("../_libs/xterm__addon-fit.mjs").then((n) => n.t)]);
|
|
20908
|
+
if (disposed) return;
|
|
20909
|
+
const terminal = new Terminal({
|
|
20910
|
+
allowTransparency: true,
|
|
20911
|
+
convertEol: false,
|
|
20912
|
+
cursorBlink: true,
|
|
20913
|
+
fontFamily: createTerminalFontFamily(),
|
|
20914
|
+
fontSize: 12,
|
|
20915
|
+
letterSpacing: 0,
|
|
20916
|
+
lineHeight: 1.2,
|
|
20917
|
+
scrollback: 5e3,
|
|
20918
|
+
theme: createTerminalTheme()
|
|
20919
|
+
});
|
|
20920
|
+
fitAddon = new FitAddon();
|
|
20921
|
+
terminal.loadAddon(fitAddon);
|
|
20922
|
+
terminal.open(terminalElement);
|
|
20923
|
+
terminalRef.current = terminal;
|
|
20924
|
+
inputDisposable = terminal.onData((data) => {
|
|
20925
|
+
if (!activeRef.current) return;
|
|
20926
|
+
inputBuffer += data;
|
|
20927
|
+
scheduleInputFlush();
|
|
20928
|
+
});
|
|
20929
|
+
scheduleFitAndResize();
|
|
20930
|
+
const terminalResponse = await postJson("/api/terminal", {
|
|
20931
|
+
clientKey: tabId,
|
|
20932
|
+
cols: terminal.cols,
|
|
20933
|
+
rows: terminal.rows
|
|
20934
|
+
});
|
|
20935
|
+
if (disposed) return;
|
|
20936
|
+
terminalIdRef.current = terminalResponse.id;
|
|
20937
|
+
onTerminalIdChangeRef.current(tabId, terminalResponse.id);
|
|
20938
|
+
connectTerminalWebSocket(terminalResponse.id);
|
|
20939
|
+
resizeObserver = new ResizeObserver(scheduleFitAndResize);
|
|
20940
|
+
resizeObserver.observe(terminalElement);
|
|
20941
|
+
scheduleFitAndResize();
|
|
20942
|
+
} catch (error) {
|
|
20943
|
+
if (disposed) return;
|
|
20944
|
+
const message = errorMessage(error);
|
|
20945
|
+
publishStatus({
|
|
20946
|
+
type: "error",
|
|
20947
|
+
message
|
|
20948
|
+
});
|
|
20949
|
+
terminalRef.current?.writeln(`\r\n${message}`);
|
|
20950
|
+
}
|
|
20951
|
+
};
|
|
20952
|
+
startTerminal();
|
|
20953
|
+
return () => {
|
|
20954
|
+
disposed = true;
|
|
20955
|
+
if (inputFlushTimer !== null) window.clearTimeout(inputFlushTimer);
|
|
20956
|
+
if (resizeFrame !== null) window.cancelAnimationFrame(resizeFrame);
|
|
20957
|
+
if (reconnectTimer !== null) window.clearTimeout(reconnectTimer);
|
|
20958
|
+
clearPingTimer();
|
|
20959
|
+
flushInput();
|
|
20960
|
+
resizeObserver?.disconnect();
|
|
20961
|
+
if (websocket) {
|
|
20962
|
+
websocket.onclose = null;
|
|
20963
|
+
websocket.onerror = null;
|
|
20964
|
+
websocket.onmessage = null;
|
|
20965
|
+
websocket.close();
|
|
20966
|
+
}
|
|
20967
|
+
inputDisposable?.dispose();
|
|
20968
|
+
terminalRef.current?.dispose();
|
|
20969
|
+
terminalRef.current = null;
|
|
20970
|
+
terminalIdRef.current = null;
|
|
20971
|
+
fitAndResizeRef.current = () => {};
|
|
20972
|
+
};
|
|
20973
|
+
}, [
|
|
20974
|
+
cwd,
|
|
20975
|
+
sessionId,
|
|
20976
|
+
tabId,
|
|
20977
|
+
viewerContextId
|
|
20978
|
+
]);
|
|
20979
|
+
import_react.useEffect(() => {
|
|
20980
|
+
const applyTheme = () => {
|
|
20981
|
+
const terminal = terminalRef.current;
|
|
20982
|
+
if (!terminal) return;
|
|
20983
|
+
terminal.options.theme = createTerminalTheme();
|
|
20984
|
+
terminal.options.fontFamily = createTerminalFontFamily();
|
|
20985
|
+
};
|
|
20986
|
+
const observer = new MutationObserver(applyTheme);
|
|
20987
|
+
observer.observe(document.documentElement, {
|
|
20988
|
+
attributeFilter: ["class", "data-pico-theme-mode"],
|
|
20989
|
+
attributes: true
|
|
20990
|
+
});
|
|
20991
|
+
applyTheme();
|
|
20992
|
+
return () => observer.disconnect();
|
|
20993
|
+
}, []);
|
|
20994
|
+
import_react.useEffect(() => {
|
|
20995
|
+
if (!active) {
|
|
20996
|
+
terminalRef.current?.blur();
|
|
20997
|
+
return;
|
|
20998
|
+
}
|
|
20999
|
+
const frame = window.requestAnimationFrame(() => {
|
|
21000
|
+
fitAndResizeRef.current();
|
|
21001
|
+
terminalRef.current?.focus();
|
|
21002
|
+
});
|
|
21003
|
+
return () => window.cancelAnimationFrame(frame);
|
|
21004
|
+
}, [active, status]);
|
|
21005
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
21006
|
+
"aria-hidden": !selected,
|
|
21007
|
+
"data-terminal-tab": tabId,
|
|
21008
|
+
className: cn("absolute inset-0 min-h-0 w-full overflow-hidden bg-background", selected ? "z-10 opacity-100" : "pointer-events-none z-0 opacity-0"),
|
|
21009
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
21010
|
+
ref: terminalElementRef,
|
|
21011
|
+
className: "h-full min-h-0 w-full"
|
|
21012
|
+
})
|
|
21013
|
+
});
|
|
21014
|
+
}
|
|
21015
|
+
function TerminalPanel({ active, className, cwd, onClose, sessionId, showCloseButton = true, viewerContextId }) {
|
|
21016
|
+
const normalizedCwd = cwd?.trim() || "";
|
|
21017
|
+
const scopeKey = `${viewerContextId}:${sessionId ?? "no-session"}:${normalizedCwd}`;
|
|
21018
|
+
const [tabsState, setTabsState] = import_react.useState(() => createTerminalTabsState(scopeKey));
|
|
21019
|
+
const [statusDialogTabId, setStatusDialogTabId] = import_react.useState(null);
|
|
21020
|
+
const tabs = tabsState.scopeKey === scopeKey ? tabsState.tabs : [];
|
|
21021
|
+
const selectedTabId = tabsState.scopeKey === scopeKey ? tabsState.activeTabId ?? tabs[0]?.id ?? null : null;
|
|
21022
|
+
import_react.useEffect(() => {
|
|
21023
|
+
if (tabsState.scopeKey === scopeKey) return;
|
|
21024
|
+
setTabsState(createTerminalTabsState(scopeKey));
|
|
21025
|
+
}, [scopeKey, tabsState.scopeKey]);
|
|
21026
|
+
import_react.useEffect(() => {
|
|
21027
|
+
if (!active || !normalizedCwd || tabs.length > 0 || tabsState.scopeKey !== scopeKey) return;
|
|
21028
|
+
const tab = createTerminalTab();
|
|
21029
|
+
const nextState = {
|
|
21030
|
+
activeTabId: tab.id,
|
|
21031
|
+
scopeKey,
|
|
21032
|
+
tabs: [tab]
|
|
21033
|
+
};
|
|
21034
|
+
rememberTerminalTabsState(nextState);
|
|
21035
|
+
setTabsState(nextState);
|
|
21036
|
+
}, [
|
|
21037
|
+
active,
|
|
21038
|
+
normalizedCwd,
|
|
21039
|
+
scopeKey,
|
|
21040
|
+
tabs.length,
|
|
21041
|
+
tabsState.scopeKey
|
|
21042
|
+
]);
|
|
21043
|
+
const activeStatus = tabs.find((tab) => tab.id === selectedTabId)?.status ?? { type: "idle" };
|
|
21044
|
+
const activeError = activeStatus.type === "error" ? activeStatus.message : void 0;
|
|
21045
|
+
const statusDialogTab = tabs.find((tab) => tab.id === statusDialogTabId);
|
|
21046
|
+
const statusDialogTabIndex = statusDialogTab ? tabs.indexOf(statusDialogTab) : 0;
|
|
21047
|
+
const requestOptions = sessionId ? {
|
|
21048
|
+
contextId: viewerContextId,
|
|
21049
|
+
sessionId
|
|
21050
|
+
} : { contextId: viewerContextId };
|
|
21051
|
+
const addTerminalTab = () => {
|
|
21052
|
+
if (!normalizedCwd) return;
|
|
21053
|
+
const tab = createTerminalTab();
|
|
21054
|
+
setTabsState((current) => {
|
|
21055
|
+
const nextState = current.scopeKey !== scopeKey ? {
|
|
21056
|
+
activeTabId: tab.id,
|
|
21057
|
+
scopeKey,
|
|
21058
|
+
tabs: [tab]
|
|
21059
|
+
} : {
|
|
21060
|
+
...current,
|
|
21061
|
+
activeTabId: tab.id,
|
|
21062
|
+
tabs: [...current.tabs, tab]
|
|
21063
|
+
};
|
|
21064
|
+
rememberTerminalTabsState(nextState);
|
|
21065
|
+
return nextState;
|
|
21066
|
+
});
|
|
21067
|
+
};
|
|
21068
|
+
const closeServerTerminal = (terminalId) => {
|
|
21069
|
+
if (!terminalId) return;
|
|
21070
|
+
fetchJson(buildRequestUrl(`/api/terminal/${encodeURIComponent(terminalId)}/close`, requestOptions), { method: "POST" }).catch(() => {});
|
|
21071
|
+
};
|
|
21072
|
+
const closeTerminalTab = (tabId) => {
|
|
21073
|
+
if (tabs.length <= 0) return;
|
|
21074
|
+
closeServerTerminal(tabs.find((tab) => tab.id === tabId)?.terminalId ?? null);
|
|
21075
|
+
setTabsState((current) => {
|
|
21076
|
+
if (current.scopeKey !== scopeKey || current.tabs.length <= 0) return current;
|
|
21077
|
+
const closingIndex = current.tabs.findIndex((tab) => tab.id === tabId);
|
|
21078
|
+
const nextTabs = current.tabs.filter((tab) => tab.id !== tabId);
|
|
21079
|
+
const nextActiveTabId = current.activeTabId === tabId ? nextTabs[Math.min(Math.max(closingIndex, 0), nextTabs.length - 1)]?.id ?? null : current.activeTabId;
|
|
21080
|
+
const nextState = {
|
|
21081
|
+
...current,
|
|
21082
|
+
activeTabId: nextActiveTabId,
|
|
21083
|
+
tabs: nextTabs
|
|
21084
|
+
};
|
|
21085
|
+
rememberTerminalTabsState(nextState);
|
|
21086
|
+
return nextState;
|
|
21087
|
+
});
|
|
21088
|
+
};
|
|
21089
|
+
const updateTabStatus = (tabId, status) => {
|
|
21090
|
+
setTabsState((current) => {
|
|
21091
|
+
if (current.scopeKey !== scopeKey) return current;
|
|
21092
|
+
return {
|
|
21093
|
+
...current,
|
|
21094
|
+
tabs: current.tabs.map((tab) => tab.id === tabId ? {
|
|
21095
|
+
...tab,
|
|
21096
|
+
status
|
|
21097
|
+
} : tab)
|
|
21098
|
+
};
|
|
21099
|
+
});
|
|
21100
|
+
};
|
|
21101
|
+
const updateTabTerminalId = (tabId, terminalId) => {
|
|
21102
|
+
setTabsState((current) => {
|
|
21103
|
+
if (current.scopeKey !== scopeKey) return current;
|
|
21104
|
+
return {
|
|
21105
|
+
...current,
|
|
21106
|
+
tabs: current.tabs.map((tab) => tab.id === tabId ? {
|
|
21107
|
+
...tab,
|
|
21108
|
+
terminalId
|
|
21109
|
+
} : tab)
|
|
21110
|
+
};
|
|
21111
|
+
});
|
|
21112
|
+
};
|
|
21113
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", {
|
|
21114
|
+
"data-terminal-panel": "true",
|
|
21115
|
+
className: cn("pico-terminal-panel flex h-full min-h-0 w-full min-w-0 flex-col bg-background", className),
|
|
21116
|
+
onKeyDownCapture: (event) => {
|
|
21117
|
+
if (!isTerminalToggleEvent(event) || !onClose) return;
|
|
21118
|
+
event.preventDefault();
|
|
21119
|
+
event.stopPropagation();
|
|
21120
|
+
event.nativeEvent.stopImmediatePropagation();
|
|
21121
|
+
onClose();
|
|
21122
|
+
},
|
|
21123
|
+
children: [
|
|
21124
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
21125
|
+
className: "flex min-h-10 shrink-0 items-center gap-2 border-b border-border/70 px-2",
|
|
21126
|
+
children: [
|
|
21127
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
21128
|
+
className: "hidden max-w-56 min-w-0 flex-col gap-0 px-1 sm:flex",
|
|
21129
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
21130
|
+
className: "truncate text-xs font-medium",
|
|
21131
|
+
children: "Terminal"
|
|
21132
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
21133
|
+
className: "flex min-w-0 items-center gap-1 truncate text-[11px] text-muted-foreground",
|
|
21134
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TerminalStatusDot, { status: activeStatus }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
21135
|
+
className: "truncate",
|
|
21136
|
+
children: normalizedCwd ? formatDisplayPath$1(normalizedCwd) : "No cwd"
|
|
21137
|
+
})]
|
|
21138
|
+
})]
|
|
21139
|
+
}),
|
|
21140
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
21141
|
+
className: "flex min-w-0 flex-1 items-center gap-1 overflow-x-auto py-1",
|
|
21142
|
+
children: [tabs.map((tab, index) => {
|
|
21143
|
+
const selected = tab.id === selectedTabId;
|
|
21144
|
+
const label = terminalTabLabel(tab, index);
|
|
21145
|
+
const statusText = terminalStatusText(tab.status);
|
|
21146
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
21147
|
+
className: cn("group flex h-7 max-w-48 shrink-0 items-center overflow-hidden rounded-md border text-xs", selected ? "border-border bg-muted text-foreground" : "border-transparent bg-transparent text-muted-foreground hover:bg-muted/60 hover:text-foreground"),
|
|
21148
|
+
children: [
|
|
21149
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
21150
|
+
title: `${label} · ${statusText}`,
|
|
21151
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
21152
|
+
type: "button",
|
|
21153
|
+
className: "flex h-full w-7 shrink-0 items-center justify-center outline-hidden focus-visible:ring-1 focus-visible:ring-ring",
|
|
21154
|
+
"aria-label": `Show ${label} status`,
|
|
21155
|
+
onClick: (event) => {
|
|
21156
|
+
event.stopPropagation();
|
|
21157
|
+
setStatusDialogTabId(tab.id);
|
|
21158
|
+
},
|
|
21159
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TerminalStatusDot, { status: tab.status })
|
|
21160
|
+
})
|
|
21161
|
+
}),
|
|
21162
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
21163
|
+
title: `${label} · ${statusText}`,
|
|
21164
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
21165
|
+
type: "button",
|
|
21166
|
+
className: "flex h-full min-w-0 flex-1 items-center px-1 text-left outline-hidden focus-visible:ring-1 focus-visible:ring-ring",
|
|
21167
|
+
onClick: () => {
|
|
21168
|
+
setTabsState((current) => {
|
|
21169
|
+
if (current.scopeKey !== scopeKey) return current;
|
|
21170
|
+
const nextState = {
|
|
21171
|
+
...current,
|
|
21172
|
+
activeTabId: tab.id
|
|
21173
|
+
};
|
|
21174
|
+
rememberTerminalTabsState(nextState);
|
|
21175
|
+
return nextState;
|
|
21176
|
+
});
|
|
21177
|
+
},
|
|
21178
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
21179
|
+
className: "truncate",
|
|
21180
|
+
children: label
|
|
21181
|
+
})
|
|
21182
|
+
})
|
|
21183
|
+
}),
|
|
21184
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
21185
|
+
title: `Close ${label}`,
|
|
21186
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
21187
|
+
type: "button",
|
|
21188
|
+
className: "flex h-full w-6 shrink-0 items-center justify-center text-muted-foreground opacity-70 outline-hidden group-hover:opacity-100 hover:bg-muted hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-30",
|
|
21189
|
+
"aria-label": `Close ${label}`,
|
|
21190
|
+
onClick: (event) => {
|
|
21191
|
+
event.stopPropagation();
|
|
21192
|
+
closeTerminalTab(tab.id);
|
|
21193
|
+
},
|
|
21194
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X, { className: "size-3" })
|
|
21195
|
+
})
|
|
21196
|
+
})
|
|
21197
|
+
]
|
|
21198
|
+
}, tab.id);
|
|
21199
|
+
}), normalizedCwd ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
21200
|
+
title: "New terminal tab",
|
|
21201
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
21202
|
+
size: "icon",
|
|
21203
|
+
variant: "ghost",
|
|
21204
|
+
className: "size-7 shrink-0",
|
|
21205
|
+
"aria-label": "New terminal tab",
|
|
21206
|
+
onClick: addTerminalTab,
|
|
21207
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Plus, { className: "size-4" })
|
|
21208
|
+
})
|
|
21209
|
+
}) : null]
|
|
21210
|
+
}),
|
|
21211
|
+
activeError ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
21212
|
+
title: activeError,
|
|
21213
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
21214
|
+
className: "hidden max-w-48 truncate text-[11px] text-destructive sm:inline",
|
|
21215
|
+
children: activeError
|
|
21216
|
+
})
|
|
21217
|
+
}) : null,
|
|
21218
|
+
onClose && showCloseButton ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
21219
|
+
title: "Hide terminal",
|
|
21220
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
21221
|
+
size: "icon",
|
|
21222
|
+
variant: "ghost",
|
|
21223
|
+
className: "size-8 shrink-0",
|
|
21224
|
+
"aria-label": "Hide terminal",
|
|
21225
|
+
onClick: onClose,
|
|
21226
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(X, {})
|
|
21227
|
+
})
|
|
21228
|
+
}) : null
|
|
21229
|
+
]
|
|
21230
|
+
}),
|
|
21231
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TerminalStatusDialog, {
|
|
21232
|
+
cwd: normalizedCwd,
|
|
21233
|
+
index: statusDialogTabIndex,
|
|
21234
|
+
open: statusDialogTab !== void 0,
|
|
21235
|
+
tab: statusDialogTab,
|
|
21236
|
+
onOpenChange: (open) => {
|
|
21237
|
+
if (!open) setStatusDialogTabId(null);
|
|
21238
|
+
}
|
|
21239
|
+
}),
|
|
21240
|
+
normalizedCwd ? tabs.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
21241
|
+
className: "relative min-h-0 flex-1 overflow-hidden bg-background",
|
|
21242
|
+
children: tabs.map((tab) => {
|
|
21243
|
+
const selected = tab.id === selectedTabId;
|
|
21244
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TerminalTabPane, {
|
|
21245
|
+
active: active && selected,
|
|
21246
|
+
cwd: normalizedCwd,
|
|
21247
|
+
onStatusChange: updateTabStatus,
|
|
21248
|
+
onTerminalIdChange: updateTabTerminalId,
|
|
21249
|
+
selected,
|
|
21250
|
+
sessionId,
|
|
21251
|
+
tabId: tab.id,
|
|
21252
|
+
viewerContextId
|
|
21253
|
+
}, tab.id);
|
|
21254
|
+
})
|
|
21255
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
21256
|
+
className: "flex min-h-0 flex-1 flex-col items-center justify-center gap-3 p-6 text-sm text-muted-foreground",
|
|
21257
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: "No terminal tabs are open." }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Button$1, {
|
|
21258
|
+
size: "sm",
|
|
21259
|
+
variant: "outline",
|
|
21260
|
+
onClick: addTerminalTab,
|
|
21261
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Plus, { className: "size-4" }), "New terminal tab"]
|
|
21262
|
+
})]
|
|
21263
|
+
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
21264
|
+
className: "flex min-h-0 flex-1 items-center justify-center p-6 text-sm text-muted-foreground",
|
|
21265
|
+
children: "Open a session before starting a terminal."
|
|
21266
|
+
})
|
|
21267
|
+
]
|
|
21268
|
+
});
|
|
21269
|
+
}
|
|
21270
|
+
function readStoredRightSidebarActiveTab() {
|
|
21271
|
+
const stored = safeLocalStorageGetItem(RIGHT_SIDEBAR_ACTIVE_TAB_STORAGE_KEY);
|
|
21272
|
+
return stored === "files" || stored === "review" ? stored : "review";
|
|
21273
|
+
}
|
|
21274
|
+
function storeRightSidebarActiveTab(tab) {
|
|
21275
|
+
if (tab === "commit-diff" || tab === "history") return;
|
|
21276
|
+
safeLocalStorageSetItem(RIGHT_SIDEBAR_ACTIVE_TAB_STORAGE_KEY, tab);
|
|
21277
|
+
}
|
|
21278
|
+
function setRightSidebarActiveTab(store, tab) {
|
|
21279
|
+
setStoreField(store, "activeTab", tab);
|
|
21280
|
+
storeRightSidebarActiveTab(tab);
|
|
21281
|
+
}
|
|
21282
|
+
function createInitialRightSidebarState() {
|
|
21283
|
+
return {
|
|
21284
|
+
activeTab: readStoredRightSidebarActiveTab(),
|
|
21285
|
+
fileActivePath: "",
|
|
21286
|
+
filePreviewPath: "",
|
|
21287
|
+
fileTabs: [],
|
|
21288
|
+
fileTreeCollapsed: false
|
|
21289
|
+
};
|
|
21290
|
+
}
|
|
21291
|
+
function selectRightSidebarVisibleFileTabs(state) {
|
|
21292
|
+
return state.filePreviewPath && !state.fileTabs.includes(state.filePreviewPath) ? [...state.fileTabs, state.filePreviewPath] : state.fileTabs;
|
|
21293
|
+
}
|
|
21294
|
+
function selectRightSidebarHasVisibleFiles(state) {
|
|
21295
|
+
return selectRightSidebarVisibleFileTabs(state).length > 0;
|
|
21296
|
+
}
|
|
21297
|
+
function resetRightSidebarFiles(store) {
|
|
21298
|
+
setStoreState(store, (state) => ({
|
|
21299
|
+
...state,
|
|
21300
|
+
fileActivePath: "",
|
|
21301
|
+
filePreviewPath: "",
|
|
21302
|
+
fileTabs: [],
|
|
21303
|
+
fileTreeCollapsed: false
|
|
21304
|
+
}));
|
|
21305
|
+
}
|
|
21306
|
+
function openRightSidebarFile(store, path, options) {
|
|
20289
21307
|
if (!path) return;
|
|
20290
21308
|
storeRightSidebarActiveTab("files");
|
|
20291
21309
|
setStoreState(store, (state) => {
|
|
@@ -20363,22 +21381,33 @@ function reorderRightSidebarFiles(store, paths) {
|
|
|
20363
21381
|
fileTabs: uniquePaths
|
|
20364
21382
|
}));
|
|
20365
21383
|
}
|
|
21384
|
+
function shallowTerminalSession(left, right) {
|
|
21385
|
+
return left.cwd === right.cwd && left.sessionId === right.sessionId;
|
|
21386
|
+
}
|
|
20366
21387
|
function AppShellTabsList({ sessionStore, viewerContextId }) {
|
|
20367
21388
|
const cwd = useSelector(sessionStore, (sessionState) => sessionState.cwd);
|
|
20368
21389
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(TabsList, {
|
|
20369
21390
|
className: "w-full gap-2 rounded-none border-b border-border/70 bg-background p-2 group-data-horizontal/tabs:h-auto md:hidden",
|
|
20370
|
-
children: [
|
|
20371
|
-
|
|
20372
|
-
|
|
20373
|
-
|
|
20374
|
-
|
|
20375
|
-
|
|
20376
|
-
|
|
20377
|
-
|
|
20378
|
-
|
|
20379
|
-
|
|
21391
|
+
children: [
|
|
21392
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabsTrigger, {
|
|
21393
|
+
value: "session",
|
|
21394
|
+
className: "h-8 data-active:bg-muted dark:data-active:bg-muted",
|
|
21395
|
+
children: "Session"
|
|
21396
|
+
}),
|
|
21397
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabsTrigger, {
|
|
21398
|
+
value: "git",
|
|
21399
|
+
className: "h-8 data-active:bg-muted dark:data-active:bg-muted",
|
|
21400
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GitTabStatusText, {
|
|
21401
|
+
viewerContextId,
|
|
21402
|
+
cwd
|
|
21403
|
+
})
|
|
21404
|
+
}),
|
|
21405
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TabsTrigger, {
|
|
21406
|
+
value: "terminal",
|
|
21407
|
+
className: "h-8 data-active:bg-muted dark:data-active:bg-muted",
|
|
21408
|
+
children: "Terminal"
|
|
20380
21409
|
})
|
|
20381
|
-
|
|
21410
|
+
]
|
|
20382
21411
|
});
|
|
20383
21412
|
}
|
|
20384
21413
|
var AppShellGitPanelController = import_react.memo(function AppShellGitPanelController({ active, composerDiffLineComments, onAddDiffLineComment, onCloseAllFiles, onCloseFile, onCloseFilesToRight, onCloseOtherFiles, onOpenFile, onReorderFiles, rightSidebarStore, sessionStore, viewerContextId }) {
|
|
@@ -20457,6 +21486,10 @@ var DESKTOP_DEFAULT_GIT_PANEL_WIDTH = 320;
|
|
|
20457
21486
|
var DESKTOP_MIN_SESSION_WIDTH = 320;
|
|
20458
21487
|
var DESKTOP_MIN_SIDE_PANEL_WIDTH = 260;
|
|
20459
21488
|
var DESKTOP_MAX_STORED_SIDE_PANEL_WIDTH = 1600;
|
|
21489
|
+
var DESKTOP_DEFAULT_TERMINAL_PANEL_HEIGHT = 280;
|
|
21490
|
+
var DESKTOP_MIN_TERMINAL_PANEL_HEIGHT = 160;
|
|
21491
|
+
var DESKTOP_MIN_TOP_PANEL_HEIGHT = 220;
|
|
21492
|
+
var DESKTOP_MAX_STORED_TERMINAL_PANEL_HEIGHT = 1200;
|
|
20460
21493
|
function defaultDesktopSidePanelWidths() {
|
|
20461
21494
|
return {
|
|
20462
21495
|
fileViewWidth: DESKTOP_DEFAULT_FILE_VIEW_WIDTH,
|
|
@@ -20491,6 +21524,18 @@ function storeDesktopSidePanelWidths(widths) {
|
|
|
20491
21524
|
function sameDesktopSidePanelWidths(left, right) {
|
|
20492
21525
|
return left.fileViewWidth === right.fileViewWidth && left.gitPanelWidth === right.gitPanelWidth;
|
|
20493
21526
|
}
|
|
21527
|
+
function clampStoredDesktopTerminalPanelHeight(value) {
|
|
21528
|
+
if (value == null || value === "") return DESKTOP_DEFAULT_TERMINAL_PANEL_HEIGHT;
|
|
21529
|
+
const height = typeof value === "number" ? value : Number(value);
|
|
21530
|
+
if (!Number.isFinite(height)) return DESKTOP_DEFAULT_TERMINAL_PANEL_HEIGHT;
|
|
21531
|
+
return Math.round(Math.min(DESKTOP_MAX_STORED_TERMINAL_PANEL_HEIGHT, Math.max(DESKTOP_MIN_TERMINAL_PANEL_HEIGHT, height)));
|
|
21532
|
+
}
|
|
21533
|
+
function readStoredDesktopTerminalPanelHeight() {
|
|
21534
|
+
return clampStoredDesktopTerminalPanelHeight(safeLocalStorageGetItem(TERMINAL_PANEL_HEIGHT_STORAGE_KEY));
|
|
21535
|
+
}
|
|
21536
|
+
function storeDesktopTerminalPanelHeight(height) {
|
|
21537
|
+
safeLocalStorageSetItem(TERMINAL_PANEL_HEIGHT_STORAGE_KEY, String(clampStoredDesktopTerminalPanelHeight(height)));
|
|
21538
|
+
}
|
|
20494
21539
|
function clampDesktopPanelSize(value, min, max) {
|
|
20495
21540
|
if (!Number.isFinite(value)) return min;
|
|
20496
21541
|
if (max <= min) return Math.max(0, max);
|
|
@@ -20535,7 +21580,86 @@ function fitDesktopSidePanelWidths({ availableWidth, fileOpen, fileWidth, gitOpe
|
|
|
20535
21580
|
sideWidth: nextFileWidth + nextGitWidth
|
|
20536
21581
|
};
|
|
20537
21582
|
}
|
|
20538
|
-
function AppShellDesktopResizeHandle({ label, max, min, onResize, onResizeEnd, onResizeStart, size }) {
|
|
21583
|
+
function AppShellDesktopResizeHandle({ label, max, min, onResize, onResizeEnd, onResizeStart, size }) {
|
|
21584
|
+
const propsRef = useLatestRef({
|
|
21585
|
+
max,
|
|
21586
|
+
min,
|
|
21587
|
+
onResize,
|
|
21588
|
+
onResizeEnd,
|
|
21589
|
+
onResizeStart,
|
|
21590
|
+
size
|
|
21591
|
+
});
|
|
21592
|
+
const [horizontalResizeCursor, setHorizontalResizeCursor] = import_react.useState("col-resize");
|
|
21593
|
+
const [resizeTargetMinimumSize, setResizeTargetMinimumSize] = import_react.useState(10);
|
|
21594
|
+
import_react.useEffect(() => {
|
|
21595
|
+
const updateResizeTarget = () => {
|
|
21596
|
+
setResizeTargetMinimumSize(getSidebarResizeTargetMinimumSize());
|
|
21597
|
+
};
|
|
21598
|
+
const coarsePointerQuery = window.matchMedia("(pointer:coarse)");
|
|
21599
|
+
setHorizontalResizeCursor(getSidebarHorizontalResizeCursor());
|
|
21600
|
+
updateResizeTarget();
|
|
21601
|
+
coarsePointerQuery.addEventListener("change", updateResizeTarget);
|
|
21602
|
+
return () => {
|
|
21603
|
+
coarsePointerQuery.removeEventListener("change", updateResizeTarget);
|
|
21604
|
+
};
|
|
21605
|
+
}, []);
|
|
21606
|
+
const horizontalResizeCursorClass = horizontalResizeCursor === "ew-resize" ? "cursor-ew-resize" : "cursor-col-resize";
|
|
21607
|
+
const resizeTo = (nextSize) => {
|
|
21608
|
+
const current = propsRef.current;
|
|
21609
|
+
current.onResize(clampDesktopPanelSize(nextSize, current.min, current.max));
|
|
21610
|
+
};
|
|
21611
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
21612
|
+
role: "separator",
|
|
21613
|
+
"aria-label": label,
|
|
21614
|
+
"aria-orientation": "vertical",
|
|
21615
|
+
tabIndex: 0,
|
|
21616
|
+
style: {
|
|
21617
|
+
"--resize-target-width": `${resizeTargetMinimumSize}px`,
|
|
21618
|
+
cursor: horizontalResizeCursor
|
|
21619
|
+
},
|
|
21620
|
+
className: `absolute inset-y-0 left-0 z-20 w-(--resize-target-width) -translate-x-1/2 touch-none bg-transparent outline-hidden after:absolute after:inset-y-0 after:left-1/2 after:w-px after:bg-transparent focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 ${resizeRailPrimaryInteractiveClass} ${horizontalResizeCursorClass}`,
|
|
21621
|
+
onKeyDown: (event) => {
|
|
21622
|
+
if (event.key !== "ArrowLeft" && event.key !== "ArrowRight") return;
|
|
21623
|
+
event.preventDefault();
|
|
21624
|
+
const delta = event.shiftKey ? 48 : 16;
|
|
21625
|
+
resizeTo(propsRef.current.size + (event.key === "ArrowLeft" ? delta : -delta));
|
|
21626
|
+
},
|
|
21627
|
+
onPointerDown: (event) => {
|
|
21628
|
+
if (event.button !== 0) return;
|
|
21629
|
+
event.preventDefault();
|
|
21630
|
+
const current = propsRef.current;
|
|
21631
|
+
const startX = event.clientX;
|
|
21632
|
+
const startSize = current.size;
|
|
21633
|
+
const cursor = getSidebarHorizontalResizeCursor();
|
|
21634
|
+
const previousCursor = document.body.style.cursor;
|
|
21635
|
+
const previousUserSelect = document.body.style.userSelect;
|
|
21636
|
+
const cleanupGlobalResizeCursor = installGlobalResizeCursor(cursor);
|
|
21637
|
+
current.onResizeStart?.();
|
|
21638
|
+
Object.assign(document.body.style, {
|
|
21639
|
+
userSelect: "none",
|
|
21640
|
+
cursor
|
|
21641
|
+
});
|
|
21642
|
+
const handlePointerMove = (moveEvent) => {
|
|
21643
|
+
resizeTo(startSize + startX - moveEvent.clientX);
|
|
21644
|
+
};
|
|
21645
|
+
const handlePointerUp = () => {
|
|
21646
|
+
cleanupGlobalResizeCursor();
|
|
21647
|
+
Object.assign(document.body.style, {
|
|
21648
|
+
userSelect: previousUserSelect,
|
|
21649
|
+
cursor: previousCursor
|
|
21650
|
+
});
|
|
21651
|
+
document.removeEventListener("pointermove", handlePointerMove);
|
|
21652
|
+
document.removeEventListener("pointerup", handlePointerUp);
|
|
21653
|
+
document.removeEventListener("pointercancel", handlePointerUp);
|
|
21654
|
+
propsRef.current.onResizeEnd?.();
|
|
21655
|
+
};
|
|
21656
|
+
document.addEventListener("pointermove", handlePointerMove);
|
|
21657
|
+
document.addEventListener("pointerup", handlePointerUp);
|
|
21658
|
+
document.addEventListener("pointercancel", handlePointerUp);
|
|
21659
|
+
}
|
|
21660
|
+
});
|
|
21661
|
+
}
|
|
21662
|
+
function AppShellDesktopVerticalResizeHandle({ label, max, min, onResize, onResizeEnd, onResizeStart, size }) {
|
|
20539
21663
|
const propsRef = useLatestRef({
|
|
20540
21664
|
max,
|
|
20541
21665
|
min,
|
|
@@ -20544,21 +21668,21 @@ function AppShellDesktopResizeHandle({ label, max, min, onResize, onResizeEnd, o
|
|
|
20544
21668
|
onResizeStart,
|
|
20545
21669
|
size
|
|
20546
21670
|
});
|
|
20547
|
-
const [
|
|
21671
|
+
const [verticalResizeCursor, setVerticalResizeCursor] = import_react.useState("row-resize");
|
|
20548
21672
|
const [resizeTargetMinimumSize, setResizeTargetMinimumSize] = import_react.useState(10);
|
|
20549
21673
|
import_react.useEffect(() => {
|
|
20550
21674
|
const updateResizeTarget = () => {
|
|
20551
21675
|
setResizeTargetMinimumSize(getSidebarResizeTargetMinimumSize());
|
|
20552
21676
|
};
|
|
20553
21677
|
const coarsePointerQuery = window.matchMedia("(pointer:coarse)");
|
|
20554
|
-
|
|
21678
|
+
setVerticalResizeCursor(getSidebarVerticalResizeCursor());
|
|
20555
21679
|
updateResizeTarget();
|
|
20556
21680
|
coarsePointerQuery.addEventListener("change", updateResizeTarget);
|
|
20557
21681
|
return () => {
|
|
20558
21682
|
coarsePointerQuery.removeEventListener("change", updateResizeTarget);
|
|
20559
21683
|
};
|
|
20560
21684
|
}, []);
|
|
20561
|
-
const
|
|
21685
|
+
const verticalResizeCursorClass = verticalResizeCursor === "ns-resize" ? "cursor-ns-resize" : "cursor-row-resize";
|
|
20562
21686
|
const resizeTo = (nextSize) => {
|
|
20563
21687
|
const current = propsRef.current;
|
|
20564
21688
|
current.onResize(clampDesktopPanelSize(nextSize, current.min, current.max));
|
|
@@ -20566,26 +21690,26 @@ function AppShellDesktopResizeHandle({ label, max, min, onResize, onResizeEnd, o
|
|
|
20566
21690
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
20567
21691
|
role: "separator",
|
|
20568
21692
|
"aria-label": label,
|
|
20569
|
-
"aria-orientation": "
|
|
21693
|
+
"aria-orientation": "horizontal",
|
|
20570
21694
|
tabIndex: 0,
|
|
20571
21695
|
style: {
|
|
20572
|
-
"--resize-target-
|
|
20573
|
-
cursor:
|
|
21696
|
+
"--resize-target-height": `${resizeTargetMinimumSize}px`,
|
|
21697
|
+
cursor: verticalResizeCursor
|
|
20574
21698
|
},
|
|
20575
|
-
className: `absolute inset-
|
|
21699
|
+
className: `absolute inset-x-0 top-0 z-20 h-(--resize-target-height) -translate-y-1/2 touch-none bg-transparent outline-hidden after:absolute after:inset-x-0 after:top-1/2 after:h-px after:bg-transparent focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 ${resizeRailPrimaryInteractiveClass} ${verticalResizeCursorClass}`,
|
|
20576
21700
|
onKeyDown: (event) => {
|
|
20577
|
-
if (event.key !== "
|
|
21701
|
+
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
|
|
20578
21702
|
event.preventDefault();
|
|
20579
21703
|
const delta = event.shiftKey ? 48 : 16;
|
|
20580
|
-
resizeTo(propsRef.current.size + (event.key === "
|
|
21704
|
+
resizeTo(propsRef.current.size + (event.key === "ArrowUp" ? delta : -delta));
|
|
20581
21705
|
},
|
|
20582
21706
|
onPointerDown: (event) => {
|
|
20583
21707
|
if (event.button !== 0) return;
|
|
20584
21708
|
event.preventDefault();
|
|
20585
21709
|
const current = propsRef.current;
|
|
20586
|
-
const
|
|
21710
|
+
const startY = event.clientY;
|
|
20587
21711
|
const startSize = current.size;
|
|
20588
|
-
const cursor =
|
|
21712
|
+
const cursor = getSidebarVerticalResizeCursor();
|
|
20589
21713
|
const previousCursor = document.body.style.cursor;
|
|
20590
21714
|
const previousUserSelect = document.body.style.userSelect;
|
|
20591
21715
|
const cleanupGlobalResizeCursor = installGlobalResizeCursor(cursor);
|
|
@@ -20595,7 +21719,7 @@ function AppShellDesktopResizeHandle({ label, max, min, onResize, onResizeEnd, o
|
|
|
20595
21719
|
cursor
|
|
20596
21720
|
});
|
|
20597
21721
|
const handlePointerMove = (moveEvent) => {
|
|
20598
|
-
resizeTo(startSize +
|
|
21722
|
+
resizeTo(startSize + startY - moveEvent.clientY);
|
|
20599
21723
|
};
|
|
20600
21724
|
const handlePointerUp = () => {
|
|
20601
21725
|
cleanupGlobalResizeCursor();
|
|
@@ -20617,18 +21741,24 @@ function AppShellDesktopResizeHandle({ label, max, min, onResize, onResizeEnd, o
|
|
|
20617
21741
|
function AppShellTabsController(props) {
|
|
20618
21742
|
return useAppShellTabsControllerView(props);
|
|
20619
21743
|
}
|
|
20620
|
-
function useAppShellTabsControllerView({ actionsRef, appUiStore, awaitingFirstTurn, composerDiffLineComments, composerPanelRef, contextUsageStore, conversationFrameRef, conversationItemsStore, defaultNewSessionDirectory, displaySettingsStore, fileInputRef, gitPanelOpen, hiddenThinkingPreviewStore, isSessionViewLoading, isSubmitting, isMobile, newSessionDirectoryOptions, onCancelCompaction, onCreateSession, onOpenAddDirectoryDialog, onCloseAllFileViewTabs, onCloseFileViewTab, onCloseFileViewTabsToRight, onCloseOtherFileViewTabs, onAddDiffLineComment, onOpenFileViewTab, onReorderFileViewTabs, onValueChange, rightSidebarStore, sessionStore, store, viewerContextId, workingStateStore }) {
|
|
21744
|
+
function useAppShellTabsControllerView({ actionsRef, appUiStore, awaitingFirstTurn, composerDiffLineComments, composerPanelRef, contextUsageStore, conversationFrameRef, conversationItemsStore, defaultNewSessionDirectory, displaySettingsStore, fileInputRef, gitPanelOpen, terminalPanelOpen, hiddenThinkingPreviewStore, isSessionViewLoading, isSubmitting, isMobile, newSessionDirectoryOptions, onCancelCompaction, onCreateSession, onOpenAddDirectoryDialog, onCloseAllFileViewTabs, onCloseFileViewTab, onCloseFileViewTabsToRight, onCloseOtherFileViewTabs, onCloseTerminalPanel, onAddDiffLineComment, onOpenFileViewTab, onReorderFileViewTabs, onValueChange, rightSidebarStore, sessionStore, store, viewerContextId, workingStateStore }) {
|
|
20621
21745
|
const currentTab = useSelector(appUiStore, (state) => state.currentTab);
|
|
20622
21746
|
const isDraftSession = useSelector(sessionStore, (sessionState) => sessionState.draft);
|
|
21747
|
+
const terminalSession = useSelector(sessionStore, (sessionState) => ({
|
|
21748
|
+
cwd: sessionState.cwd,
|
|
21749
|
+
sessionId: sessionState.sessionId
|
|
21750
|
+
}), { compare: shallowTerminalSession });
|
|
20623
21751
|
const showTabsList = isMobile || !isDraftSession || isSessionViewLoading;
|
|
20624
|
-
const sessionVisibleClassName = currentTab === "
|
|
21752
|
+
const sessionVisibleClassName = currentTab === "session" ? "flex min-h-0 flex-1 flex-col" : "hidden min-h-0 flex-1 flex-col md:flex";
|
|
20625
21753
|
const mobileGitClassName = currentTab === "git" ? "min-h-0 flex-1 overflow-hidden md:hidden" : "hidden";
|
|
21754
|
+
const mobileTerminalClassName = currentTab === "terminal" ? "min-h-0 flex-1 overflow-hidden md:hidden" : "hidden";
|
|
20626
21755
|
const rightSidebarHasVisibleFiles = useSelector(rightSidebarStore, selectRightSidebarHasVisibleFiles);
|
|
20627
21756
|
const desktopGitPanelOpen = !isMobile && gitPanelOpen;
|
|
20628
21757
|
const desktopFileViewOpen = !isMobile && gitPanelOpen && rightSidebarHasVisibleFiles;
|
|
20629
21758
|
const desktopSideWorkspaceOpen = desktopFileViewOpen || desktopGitPanelOpen;
|
|
20630
21759
|
const desktopLayoutRef = import_react.useRef(null);
|
|
20631
21760
|
const [desktopLayoutWidth, setDesktopLayoutWidth] = import_react.useState(0);
|
|
21761
|
+
const [desktopLayoutHeight, setDesktopLayoutHeight] = import_react.useState(0);
|
|
20632
21762
|
const [desktopSidePanelWidths, setDesktopSidePanelWidthsState] = import_react.useState(() => defaultDesktopSidePanelWidths());
|
|
20633
21763
|
const desktopSidePanelWidthsLoadedRef = import_react.useRef(false);
|
|
20634
21764
|
const desktopSidePanelWidthsRef = import_react.useRef(desktopSidePanelWidths);
|
|
@@ -20656,12 +21786,30 @@ function useAppShellTabsControllerView({ actionsRef, appUiStore, awaitingFirstTu
|
|
|
20656
21786
|
}));
|
|
20657
21787
|
};
|
|
20658
21788
|
const [desktopGitPanelMounted, setDesktopGitPanelMounted] = import_react.useState(desktopGitPanelOpen);
|
|
21789
|
+
const [desktopTerminalPanelHeight, setDesktopTerminalPanelHeightState] = import_react.useState(() => DESKTOP_DEFAULT_TERMINAL_PANEL_HEIGHT);
|
|
21790
|
+
const desktopTerminalPanelHeightLoadedRef = import_react.useRef(false);
|
|
21791
|
+
const desktopTerminalPanelHeightRef = import_react.useRef(desktopTerminalPanelHeight);
|
|
21792
|
+
desktopTerminalPanelHeightRef.current = desktopTerminalPanelHeight;
|
|
21793
|
+
const [desktopTerminalPanelMounted, setDesktopTerminalPanelMounted] = import_react.useState(!isMobile && terminalPanelOpen);
|
|
20659
21794
|
const [desktopPanelResizing, setDesktopPanelResizing] = import_react.useState(false);
|
|
21795
|
+
const [desktopTerminalResizing, setDesktopTerminalResizing] = import_react.useState(false);
|
|
21796
|
+
const setDesktopTerminalPanelHeight = (action) => {
|
|
21797
|
+
const current = desktopTerminalPanelHeightRef.current;
|
|
21798
|
+
const next = clampStoredDesktopTerminalPanelHeight(applyStoreAction(current, action));
|
|
21799
|
+
if (current === next) return;
|
|
21800
|
+
desktopTerminalPanelHeightRef.current = next;
|
|
21801
|
+
setDesktopTerminalPanelHeightState(next);
|
|
21802
|
+
if (desktopTerminalPanelHeightLoadedRef.current) storeDesktopTerminalPanelHeight(next);
|
|
21803
|
+
};
|
|
20660
21804
|
import_react.useEffect(() => {
|
|
20661
21805
|
const storedWidths = readStoredDesktopSidePanelWidths();
|
|
21806
|
+
const storedTerminalPanelHeight = readStoredDesktopTerminalPanelHeight();
|
|
20662
21807
|
desktopSidePanelWidthsLoadedRef.current = true;
|
|
21808
|
+
desktopTerminalPanelHeightLoadedRef.current = true;
|
|
20663
21809
|
desktopSidePanelWidthsRef.current = storedWidths;
|
|
21810
|
+
desktopTerminalPanelHeightRef.current = storedTerminalPanelHeight;
|
|
20664
21811
|
setDesktopSidePanelWidthsState((current) => sameDesktopSidePanelWidths(current, storedWidths) ? current : storedWidths);
|
|
21812
|
+
setDesktopTerminalPanelHeightState((current) => current === storedTerminalPanelHeight ? current : storedTerminalPanelHeight);
|
|
20665
21813
|
}, []);
|
|
20666
21814
|
const sessionPane = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
20667
21815
|
className: "flex h-full min-h-0 min-w-0 flex-1 flex-col overflow-hidden",
|
|
@@ -20689,7 +21837,7 @@ function useAppShellTabsControllerView({ actionsRef, appUiStore, awaitingFirstTu
|
|
|
20689
21837
|
viewerContextId,
|
|
20690
21838
|
workingStateStore
|
|
20691
21839
|
})
|
|
20692
|
-
}), isMobile ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
21840
|
+
}), isMobile ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
20693
21841
|
className: mobileGitClassName,
|
|
20694
21842
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppShellGitPanelController, {
|
|
20695
21843
|
viewerContextId,
|
|
@@ -20705,32 +21853,50 @@ function useAppShellTabsControllerView({ actionsRef, appUiStore, awaitingFirstTu
|
|
|
20705
21853
|
onOpenFile: onOpenFileViewTab,
|
|
20706
21854
|
onReorderFiles: onReorderFileViewTabs
|
|
20707
21855
|
})
|
|
20708
|
-
})
|
|
21856
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
21857
|
+
className: mobileTerminalClassName,
|
|
21858
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TerminalPanel, {
|
|
21859
|
+
active: currentTab === "terminal",
|
|
21860
|
+
cwd: terminalSession.cwd,
|
|
21861
|
+
onClose: onCloseTerminalPanel,
|
|
21862
|
+
sessionId: terminalSession.sessionId,
|
|
21863
|
+
showCloseButton: false,
|
|
21864
|
+
viewerContextId
|
|
21865
|
+
})
|
|
21866
|
+
})] }) : null]
|
|
20709
21867
|
});
|
|
20710
21868
|
import_react.useLayoutEffect(() => {
|
|
20711
21869
|
if (isMobile) {
|
|
20712
21870
|
setDesktopGitPanelMounted(false);
|
|
21871
|
+
setDesktopTerminalPanelMounted(false);
|
|
20713
21872
|
return;
|
|
20714
21873
|
}
|
|
20715
21874
|
if (desktopSideWorkspaceOpen) setDesktopGitPanelMounted(true);
|
|
20716
|
-
|
|
21875
|
+
if (terminalPanelOpen) setDesktopTerminalPanelMounted(true);
|
|
21876
|
+
}, [
|
|
21877
|
+
desktopSideWorkspaceOpen,
|
|
21878
|
+
isMobile,
|
|
21879
|
+
terminalPanelOpen
|
|
21880
|
+
]);
|
|
20717
21881
|
import_react.useLayoutEffect(() => {
|
|
20718
21882
|
if (isMobile) return;
|
|
20719
21883
|
const element = desktopLayoutRef.current;
|
|
20720
21884
|
if (!element) return;
|
|
20721
|
-
const
|
|
21885
|
+
const updateSize = () => {
|
|
20722
21886
|
setDesktopLayoutWidth(element.clientWidth);
|
|
21887
|
+
setDesktopLayoutHeight(element.clientHeight);
|
|
20723
21888
|
};
|
|
20724
|
-
|
|
21889
|
+
updateSize();
|
|
20725
21890
|
if (typeof ResizeObserver === "undefined") {
|
|
20726
|
-
window.addEventListener("resize",
|
|
20727
|
-
return () => window.removeEventListener("resize",
|
|
21891
|
+
window.addEventListener("resize", updateSize);
|
|
21892
|
+
return () => window.removeEventListener("resize", updateSize);
|
|
20728
21893
|
}
|
|
20729
|
-
const observer = new ResizeObserver(
|
|
21894
|
+
const observer = new ResizeObserver(updateSize);
|
|
20730
21895
|
observer.observe(element);
|
|
20731
21896
|
return () => observer.disconnect();
|
|
20732
21897
|
}, [isMobile]);
|
|
20733
21898
|
const desktopAvailableWidth = desktopLayoutWidth || (typeof window === "undefined" ? 1200 : window.innerWidth);
|
|
21899
|
+
const desktopAvailableHeight = desktopLayoutHeight || (typeof window === "undefined" ? 800 : window.innerHeight);
|
|
20734
21900
|
const desktopGitPanelRendered = desktopSideWorkspaceOpen || desktopGitPanelMounted || desktopGitPanelOpen;
|
|
20735
21901
|
const desktopFittedWidths = fitDesktopSidePanelWidths({
|
|
20736
21902
|
availableWidth: desktopAvailableWidth,
|
|
@@ -20741,14 +21907,25 @@ function useAppShellTabsControllerView({ actionsRef, appUiStore, awaitingFirstTu
|
|
|
20741
21907
|
});
|
|
20742
21908
|
const desktopSideWorkspaceRendered = desktopSideWorkspaceOpen || desktopGitPanelMounted;
|
|
20743
21909
|
const desktopSideWorkspaceWidth = desktopSideWorkspaceOpen ? desktopFittedWidths.sideWidth : 0;
|
|
20744
|
-
const
|
|
20745
|
-
const
|
|
21910
|
+
const desktopTerminalOpen = !isMobile && terminalPanelOpen;
|
|
21911
|
+
const desktopTerminalRendered = desktopTerminalOpen || desktopTerminalPanelMounted;
|
|
21912
|
+
const desktopTerminalMaxHeight = Math.max(DESKTOP_MIN_TERMINAL_PANEL_HEIGHT, desktopAvailableHeight - DESKTOP_MIN_TOP_PANEL_HEIGHT);
|
|
21913
|
+
const desktopFittedTerminalPanelHeight = clampDesktopPanelSize(desktopTerminalPanelHeight, Math.min(DESKTOP_MIN_TERMINAL_PANEL_HEIGHT, desktopTerminalMaxHeight), desktopTerminalMaxHeight);
|
|
21914
|
+
const desktopTerminalVisibleHeight = desktopTerminalOpen ? desktopFittedTerminalPanelHeight : 0;
|
|
21915
|
+
const desktopTransitionClassName = !desktopPanelResizing && !desktopTerminalResizing ? "transition-[width,height] duration-200 ease-linear" : "";
|
|
21916
|
+
const desktopPanelGroupClassName = "relative flex min-h-0 w-full shrink-0 overflow-hidden";
|
|
20746
21917
|
const desktopResizeStart = () => {
|
|
20747
21918
|
setDesktopPanelResizing(true);
|
|
20748
21919
|
};
|
|
20749
21920
|
const desktopResizeEnd = () => {
|
|
20750
21921
|
setDesktopPanelResizing(false);
|
|
20751
21922
|
};
|
|
21923
|
+
const desktopTerminalResizeStart = () => {
|
|
21924
|
+
setDesktopTerminalResizing(true);
|
|
21925
|
+
};
|
|
21926
|
+
const desktopTerminalResizeEnd = () => {
|
|
21927
|
+
setDesktopTerminalResizing(false);
|
|
21928
|
+
};
|
|
20752
21929
|
const desktopSideWorkspaceMaxWidth = Math.max(0, desktopAvailableWidth - DESKTOP_MIN_SESSION_WIDTH);
|
|
20753
21930
|
const setDesktopSideWorkspaceWidth = (nextSize) => {
|
|
20754
21931
|
if (!desktopFileViewOpen) {
|
|
@@ -20757,6 +21934,9 @@ function useAppShellTabsControllerView({ actionsRef, appUiStore, awaitingFirstTu
|
|
|
20757
21934
|
}
|
|
20758
21935
|
setDesktopFileViewWidth(Math.max(DESKTOP_MIN_SIDE_PANEL_WIDTH, nextSize - desktopGitPanelWidth));
|
|
20759
21936
|
};
|
|
21937
|
+
const setDesktopTerminalHeight = (nextSize) => {
|
|
21938
|
+
setDesktopTerminalPanelHeight(clampDesktopPanelSize(nextSize, Math.min(DESKTOP_MIN_TERMINAL_PANEL_HEIGHT, desktopTerminalMaxHeight), desktopTerminalMaxHeight));
|
|
21939
|
+
};
|
|
20760
21940
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Tabs$1, {
|
|
20761
21941
|
value: currentTab,
|
|
20762
21942
|
onValueChange,
|
|
@@ -20769,54 +21949,83 @@ function useAppShellTabsControllerView({ actionsRef, appUiStore, awaitingFirstTu
|
|
|
20769
21949
|
children: sessionPane
|
|
20770
21950
|
}) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
20771
21951
|
ref: desktopLayoutRef,
|
|
20772
|
-
className:
|
|
20773
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.
|
|
20774
|
-
|
|
20775
|
-
|
|
20776
|
-
|
|
20777
|
-
|
|
20778
|
-
|
|
20779
|
-
|
|
20780
|
-
|
|
20781
|
-
|
|
20782
|
-
|
|
20783
|
-
|
|
20784
|
-
|
|
20785
|
-
|
|
20786
|
-
|
|
20787
|
-
className: `relative h-full min-h-0 min-w-0 shrink-0 overflow-visible ${desktopTransitionClassName}`,
|
|
21952
|
+
className: "flex min-h-0 flex-1 flex-col overflow-hidden",
|
|
21953
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
21954
|
+
className: desktopPanelGroupClassName,
|
|
21955
|
+
style: { height: desktopTerminalOpen ? `calc(100% - ${desktopTerminalVisibleHeight}px)` : "100%" },
|
|
21956
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
21957
|
+
"data-desktop-panel": "session",
|
|
21958
|
+
className: `h-full min-h-0 min-w-0 shrink-0 overflow-hidden max-md:w-full! ${desktopTransitionClassName}`,
|
|
21959
|
+
style: { width: desktopSideWorkspaceOpen ? `calc(100% - ${desktopSideWorkspaceWidth}px)` : "100%" },
|
|
21960
|
+
children: sessionPane
|
|
21961
|
+
}), desktopSideWorkspaceRendered ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("aside", {
|
|
21962
|
+
"aria-label": "Desktop side workspace",
|
|
21963
|
+
"aria-hidden": !desktopSideWorkspaceOpen,
|
|
21964
|
+
"data-state": desktopSideWorkspaceOpen ? "open" : "closed",
|
|
21965
|
+
"data-desktop-panel": "side-workspace",
|
|
21966
|
+
className: `hidden h-full min-h-0 min-w-0 shrink-0 overflow-visible bg-background data-[state=closed]:pointer-events-none md:flex ${desktopTransitionClassName}`,
|
|
20788
21967
|
style: { width: `${desktopSideWorkspaceWidth}px` },
|
|
20789
|
-
children:
|
|
20790
|
-
|
|
20791
|
-
|
|
20792
|
-
|
|
20793
|
-
|
|
20794
|
-
|
|
20795
|
-
|
|
20796
|
-
|
|
20797
|
-
|
|
20798
|
-
|
|
20799
|
-
|
|
20800
|
-
|
|
20801
|
-
|
|
20802
|
-
|
|
20803
|
-
|
|
20804
|
-
|
|
20805
|
-
|
|
20806
|
-
|
|
20807
|
-
|
|
20808
|
-
|
|
20809
|
-
|
|
20810
|
-
|
|
20811
|
-
|
|
20812
|
-
|
|
20813
|
-
|
|
20814
|
-
|
|
21968
|
+
children: desktopGitPanelRendered ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
21969
|
+
"data-desktop-panel": "git",
|
|
21970
|
+
className: `relative h-full min-h-0 min-w-0 shrink-0 overflow-visible ${desktopTransitionClassName}`,
|
|
21971
|
+
style: { width: `${desktopSideWorkspaceWidth}px` },
|
|
21972
|
+
children: [desktopGitPanelOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppShellDesktopResizeHandle, {
|
|
21973
|
+
label: "Resize right sidebar",
|
|
21974
|
+
min: Math.min(DESKTOP_MIN_SIDE_PANEL_WIDTH, desktopSideWorkspaceMaxWidth),
|
|
21975
|
+
max: desktopSideWorkspaceMaxWidth,
|
|
21976
|
+
size: desktopSideWorkspaceWidth,
|
|
21977
|
+
onResize: setDesktopSideWorkspaceWidth,
|
|
21978
|
+
onResizeStart: desktopResizeStart,
|
|
21979
|
+
onResizeEnd: desktopResizeEnd
|
|
21980
|
+
}) : null, /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
21981
|
+
className: "h-full min-h-0 min-w-0 overflow-hidden",
|
|
21982
|
+
children: desktopGitPanelRendered ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppShellDesktopGitPanel, {
|
|
21983
|
+
viewerContextId,
|
|
21984
|
+
sessionStore,
|
|
21985
|
+
active: desktopGitPanelOpen,
|
|
21986
|
+
composerDiffLineComments,
|
|
21987
|
+
rightSidebarStore,
|
|
21988
|
+
onAddDiffLineComment,
|
|
21989
|
+
onCloseAllFiles: onCloseAllFileViewTabs,
|
|
21990
|
+
onCloseFile: onCloseFileViewTab,
|
|
21991
|
+
onCloseFilesToRight: onCloseFileViewTabsToRight,
|
|
21992
|
+
onCloseOtherFiles: onCloseOtherFileViewTabs,
|
|
21993
|
+
onOpenFile: onOpenFileViewTab,
|
|
21994
|
+
onReorderFiles: onReorderFileViewTabs
|
|
21995
|
+
}) : null
|
|
21996
|
+
})]
|
|
21997
|
+
}) : null
|
|
21998
|
+
}) : null]
|
|
21999
|
+
}), desktopTerminalRendered ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", {
|
|
22000
|
+
"aria-label": "Terminal",
|
|
22001
|
+
"aria-hidden": !desktopTerminalOpen,
|
|
22002
|
+
"data-state": desktopTerminalOpen ? "open" : "closed",
|
|
22003
|
+
"data-desktop-panel": "terminal",
|
|
22004
|
+
className: `relative hidden min-h-0 w-full shrink-0 overflow-visible border-t border-border/70 bg-background data-[state=closed]:pointer-events-none data-[state=closed]:border-transparent md:flex ${desktopTransitionClassName}`,
|
|
22005
|
+
style: { height: `${desktopTerminalVisibleHeight}px` },
|
|
22006
|
+
children: [desktopTerminalOpen ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AppShellDesktopVerticalResizeHandle, {
|
|
22007
|
+
label: "Resize terminal",
|
|
22008
|
+
min: Math.min(DESKTOP_MIN_TERMINAL_PANEL_HEIGHT, desktopTerminalMaxHeight),
|
|
22009
|
+
max: desktopTerminalMaxHeight,
|
|
22010
|
+
size: desktopTerminalVisibleHeight,
|
|
22011
|
+
onResize: setDesktopTerminalHeight,
|
|
22012
|
+
onResizeStart: desktopTerminalResizeStart,
|
|
22013
|
+
onResizeEnd: desktopTerminalResizeEnd
|
|
22014
|
+
}) : null, /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
22015
|
+
className: "h-full min-h-0 w-full min-w-0 overflow-hidden",
|
|
22016
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TerminalPanel, {
|
|
22017
|
+
active: desktopTerminalOpen,
|
|
22018
|
+
cwd: terminalSession.cwd,
|
|
22019
|
+
onClose: onCloseTerminalPanel,
|
|
22020
|
+
sessionId: terminalSession.sessionId,
|
|
22021
|
+
viewerContextId
|
|
22022
|
+
})
|
|
22023
|
+
})]
|
|
20815
22024
|
}) : null]
|
|
20816
22025
|
})]
|
|
20817
22026
|
});
|
|
20818
22027
|
}
|
|
20819
|
-
var AppShellSessionHeader = import_react.memo(function AppShellSessionHeader({ actionsRef, defaultNewSessionDirectory, displaySessionCwd, gitPanelOpen, loadingDisplaySessionTitle, currentSessionPinned, displaySettingsStore, isSessionViewLoading, newSessionDirectoryOptions, onToggleGitPanel, sessionStore, viewerContextId }) {
|
|
22028
|
+
var AppShellSessionHeader = import_react.memo(function AppShellSessionHeader({ actionsRef, defaultNewSessionDirectory, displaySessionCwd, gitPanelOpen, terminalPanelOpen, loadingDisplaySessionTitle, currentSessionPinned, displaySettingsStore, isSessionViewLoading, newSessionDirectoryOptions, onToggleGitPanel, onToggleTerminalPanel, sessionStore, viewerContextId }) {
|
|
20820
22029
|
const sessionHeaderState = useSelector(sessionStore, (sessionState) => ({
|
|
20821
22030
|
firstMessage: sessionState.firstMessage,
|
|
20822
22031
|
hideThinkingBlock: sessionState.hideThinkingBlock,
|
|
@@ -20825,8 +22034,6 @@ var AppShellSessionHeader = import_react.memo(function AppShellSessionHeader({ a
|
|
|
20825
22034
|
sessionStreaming: sessionState.streaming
|
|
20826
22035
|
}), { compare: shallowRecordEqual });
|
|
20827
22036
|
const hideToolBlocks = useSelector(displaySettingsStore, (settings) => settings.hideToolBlocks);
|
|
20828
|
-
const { isMobile: sidebarIsMobile, openMobile: sidebarOpenMobile, state: sidebarState } = useSidebar();
|
|
20829
|
-
const showCollapsedNewSessionButton = !(sidebarIsMobile ? sidebarOpenMobile : sidebarState === "expanded");
|
|
20830
22037
|
const displaySessionTitle = isSessionViewLoading ? loadingDisplaySessionTitle : getCurrentSessionTitleFromState(sessionHeaderState);
|
|
20831
22038
|
const moveSessionDirectoryOptions = newSessionDirectoryOptions.filter((option) => option.path !== displaySessionCwd);
|
|
20832
22039
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
@@ -20835,25 +22042,26 @@ var AppShellSessionHeader = import_react.memo(function AppShellSessionHeader({ a
|
|
|
20835
22042
|
className: "relative flex w-full items-center gap-1",
|
|
20836
22043
|
children: [
|
|
20837
22044
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(SidebarTrigger, { className: "shrink-0" }),
|
|
20838
|
-
|
|
22045
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
20839
22046
|
title: defaultNewSessionDirectory ? `Create a new session in ${formatDisplayPath$1(defaultNewSessionDirectory)}` : "Create a new session",
|
|
20840
22047
|
kbd: formatShortcutLabel("Control+N"),
|
|
20841
22048
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
20842
22049
|
size: "icon",
|
|
20843
22050
|
variant: "ghost",
|
|
20844
|
-
className: "shrink-0",
|
|
22051
|
+
className: "shrink-0 md:group-data-[sidebar-state=expanded]/sidebar-wrapper:hidden",
|
|
20845
22052
|
"aria-label": "Create a new session",
|
|
20846
22053
|
onClick: () => {
|
|
20847
22054
|
actionsRef.current.createSession();
|
|
20848
22055
|
},
|
|
20849
22056
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SquarePen, {})
|
|
20850
22057
|
})
|
|
20851
|
-
})
|
|
22058
|
+
}),
|
|
20852
22059
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
20853
22060
|
className: "absolute left-1/2 flex w-max max-w-[calc(100%-4rem)] -translate-x-1/2 flex-col items-center justify-center gap-0 text-center",
|
|
20854
22061
|
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
20855
22062
|
className: "flex max-w-full min-w-0 items-center justify-center gap-1.5",
|
|
20856
22063
|
children: [!isSessionViewLoading && sessionHeaderState.sessionStreaming ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {
|
|
22064
|
+
size: "xs",
|
|
20857
22065
|
className: "shrink-0",
|
|
20858
22066
|
"aria-label": "Session streaming"
|
|
20859
22067
|
}) : null, /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
@@ -20864,7 +22072,7 @@ var AppShellSessionHeader = import_react.memo(function AppShellSessionHeader({ a
|
|
|
20864
22072
|
})
|
|
20865
22073
|
})]
|
|
20866
22074
|
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
20867
|
-
className: "flex max-w-full min-w-0 items-center justify-center gap-x-
|
|
22075
|
+
className: "flex max-w-full min-w-0 items-center justify-center gap-x-2",
|
|
20868
22076
|
children: [displaySessionCwd ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
20869
22077
|
className: "inline-flex min-w-0 items-center text-xs text-muted-foreground",
|
|
20870
22078
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
@@ -21002,6 +22210,19 @@ var AppShellSessionHeader = import_react.memo(function AppShellSessionHeader({ a
|
|
|
21002
22210
|
})
|
|
21003
22211
|
]
|
|
21004
22212
|
})] }),
|
|
22213
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
22214
|
+
title: "Toggle terminal",
|
|
22215
|
+
kbd: formatShortcutLabel("Control+`"),
|
|
22216
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Button$1, {
|
|
22217
|
+
size: "icon",
|
|
22218
|
+
variant: "ghost",
|
|
22219
|
+
className: "hidden md:inline-flex",
|
|
22220
|
+
"aria-pressed": terminalPanelOpen,
|
|
22221
|
+
"aria-label": "Toggle terminal panel",
|
|
22222
|
+
onClick: onToggleTerminalPanel,
|
|
22223
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SquareTerminal, {})
|
|
22224
|
+
})
|
|
22225
|
+
}),
|
|
21005
22226
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
21006
22227
|
title: "Toggle right sidebar",
|
|
21007
22228
|
kbd: formatShortcutLabel("Control+\\"),
|
|
@@ -21046,45 +22267,10 @@ function useDelayedTrue(value, delayMs) {
|
|
|
21046
22267
|
}, [delayMs, value]);
|
|
21047
22268
|
return delayedValue;
|
|
21048
22269
|
}
|
|
21049
|
-
function tildePath(value) {
|
|
21050
|
-
return value.replace(/^\/Users\/[^/]+(?=\/|$)/, "~").replace(/^\/home\/[^/]+(?=\/|$)/, "~");
|
|
21051
|
-
}
|
|
21052
|
-
function splitDisplayPath(value) {
|
|
21053
|
-
if (!value) return {
|
|
21054
|
-
leading: "",
|
|
21055
|
-
trailing: ""
|
|
21056
|
-
};
|
|
21057
|
-
const trimmed = value.replace(/[\\/]+$/, "");
|
|
21058
|
-
if (!trimmed) return {
|
|
21059
|
-
leading: "",
|
|
21060
|
-
trailing: value
|
|
21061
|
-
};
|
|
21062
|
-
const suffix = value.slice(trimmed.length);
|
|
21063
|
-
const separatorIndex = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
|
|
21064
|
-
if (separatorIndex < 0 || separatorIndex === trimmed.length - 1) return {
|
|
21065
|
-
leading: "",
|
|
21066
|
-
trailing: `${trimmed}${suffix}`
|
|
21067
|
-
};
|
|
21068
|
-
return {
|
|
21069
|
-
leading: trimmed.slice(0, separatorIndex + 1),
|
|
21070
|
-
trailing: `${trimmed.slice(separatorIndex + 1)}${suffix}`
|
|
21071
|
-
};
|
|
21072
|
-
}
|
|
21073
22270
|
function DirectoryPathLabel({ path }) {
|
|
21074
|
-
const displayPath = tildePath(path);
|
|
21075
|
-
const { leading, trailing } = splitDisplayPath(displayPath);
|
|
21076
22271
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
21077
|
-
className: "block min-w-0 text-sm text-sidebar-foreground",
|
|
21078
|
-
children:
|
|
21079
|
-
className: "flex min-w-0 items-center",
|
|
21080
|
-
children: [leading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
21081
|
-
className: "truncate text-sidebar-foreground/60",
|
|
21082
|
-
children: leading
|
|
21083
|
-
}) : null, /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
21084
|
-
className: "shrink-0 font-medium",
|
|
21085
|
-
children: trailing || displayPath
|
|
21086
|
-
})]
|
|
21087
|
-
})
|
|
22272
|
+
className: "block min-w-0 truncate text-sm font-medium text-sidebar-foreground",
|
|
22273
|
+
children: formatFolderName$1(path) || path
|
|
21088
22274
|
});
|
|
21089
22275
|
}
|
|
21090
22276
|
var EMPTY_DIRECTORY_SESSION_KEYS = [];
|
|
@@ -21324,7 +22510,7 @@ function SidebarSessionItem({ entryKey, directorySessionsStore, activeSessionSto
|
|
|
21324
22510
|
const timestamp = entry.lastMessageAt || entry.modified || entry.lastUserMessageAt;
|
|
21325
22511
|
const hasTimestamp = isValidSidebarTimestamp(timestamp);
|
|
21326
22512
|
const lastMessagePreview = entry.lastMessagePreview?.trim() || "";
|
|
21327
|
-
const pinnedDirectoryLabel = isPinned ?
|
|
22513
|
+
const pinnedDirectoryLabel = isPinned ? formatFolderName$1(entry.cwd?.trim() || entry.path?.trim() || "") : "";
|
|
21328
22514
|
const exactTimestamp = hasTimestamp && timestamp ? new Date(timestamp).toLocaleString() : void 0;
|
|
21329
22515
|
const showUnread = Boolean(entry.unread) && !entry.streaming;
|
|
21330
22516
|
const isOptimisticSession = Boolean(entry.optimistic || entry.id?.startsWith("optimistic:") && !entry.path);
|
|
@@ -21347,7 +22533,10 @@ function SidebarSessionItem({ entryKey, directorySessionsStore, activeSessionSto
|
|
|
21347
22533
|
},
|
|
21348
22534
|
children: [entry.streaming ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
21349
22535
|
className: "absolute top-2.5 left-2 flex size-4 items-center justify-center",
|
|
21350
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {
|
|
22536
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {
|
|
22537
|
+
size: "xs",
|
|
22538
|
+
"aria-label": "Session streaming"
|
|
22539
|
+
})
|
|
21351
22540
|
}) : showUnread ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
21352
22541
|
className: "absolute top-2.5 left-2 flex size-4 items-center justify-center",
|
|
21353
22542
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
@@ -21524,7 +22713,10 @@ var DirectorySessionGroup = import_react.memo(function DirectorySessionGroup({ d
|
|
|
21524
22713
|
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DirectoryPathLabel, { path: directory })
|
|
21525
22714
|
}),
|
|
21526
22715
|
!searchActive && !overlay ? collapsed ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronRight, { className: "size-4 shrink-0 opacity-0 transition-opacity group-hover/directory-label:opacity-100 group-focus-visible/directory-label:opacity-100" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChevronDown, { className: "size-4 shrink-0 opacity-0 transition-opacity group-hover/directory-label:opacity-100 group-focus-visible/directory-label:opacity-100" }) : null,
|
|
21527
|
-
showHeaderLoadingSpinner ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {
|
|
22716
|
+
showHeaderLoadingSpinner ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {
|
|
22717
|
+
size: "xs",
|
|
22718
|
+
className: "shrink-0"
|
|
22719
|
+
}) : null
|
|
21528
22720
|
]
|
|
21529
22721
|
}),
|
|
21530
22722
|
onCreateSessionInDirectory && !overlay && !isMobile ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TitleTooltip, {
|
|
@@ -21594,7 +22786,7 @@ var DirectorySessionGroup = import_react.memo(function DirectorySessionGroup({ d
|
|
|
21594
22786
|
]
|
|
21595
22787
|
})] }) : directoryHeader, !overlay ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CollapsibleContent, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SidebarGroupContent, { children: showLoadingState ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
21596
22788
|
className: "flex items-center gap-2 p-2 text-sm text-sidebar-foreground/70",
|
|
21597
|
-
children: [showLoadingSpinner ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
22789
|
+
children: [showLoadingSpinner ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, { size: "xs" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
21598
22790
|
className: "size-4",
|
|
21599
22791
|
"aria-hidden": "true"
|
|
21600
22792
|
}), "Loading sessions…"]
|
|
@@ -22912,12 +24104,13 @@ function sameComposerPendingMessages(left, right) {
|
|
|
22912
24104
|
return true;
|
|
22913
24105
|
}
|
|
22914
24106
|
function sameAppShellComposerSnapshot(left, right) {
|
|
22915
|
-
return left.activeSessionId === right.activeSessionId && left.awaitingFirstTurn === right.awaitingFirstTurn && left.centerMessages === right.centerMessages && sameComposerDiffLineComments(left.composerDiffLineComments, right.composerDiffLineComments) && left.composerSkill === right.composerSkill && left.composerSyncNonce === right.composerSyncNonce && left.composerText === right.composerText && left.disabled === right.disabled && left.isStreaming === right.isStreaming && left.isSubmitting === right.isSubmitting && left.viewerContextId === right.viewerContextId && sameComposerPromptImages(left.composerImages, right.composerImages) && sameComposerPendingMessages(left.currentPendingMessages, right.currentPendingMessages);
|
|
24107
|
+
return left.activeSessionId === right.activeSessionId && left.awaitingFirstTurn === right.awaitingFirstTurn && left.canStartPendingQueue === right.canStartPendingQueue && left.centerMessages === right.centerMessages && sameComposerDiffLineComments(left.composerDiffLineComments, right.composerDiffLineComments) && left.composerSkill === right.composerSkill && left.composerSyncNonce === right.composerSyncNonce && left.composerText === right.composerText && left.disabled === right.disabled && left.isCompacting === right.isCompacting && left.isStreaming === right.isStreaming && left.isSubmitting === right.isSubmitting && left.viewerContextId === right.viewerContextId && sameComposerPromptImages(left.composerImages, right.composerImages) && sameComposerPendingMessages(left.currentPendingMessages, right.currentPendingMessages);
|
|
22916
24108
|
}
|
|
22917
24109
|
function createInitialAppShellComposerSnapshot(viewerContextId) {
|
|
22918
24110
|
return {
|
|
22919
24111
|
activeSessionId: void 0,
|
|
22920
24112
|
awaitingFirstTurn: false,
|
|
24113
|
+
canStartPendingQueue: false,
|
|
22921
24114
|
centerMessages: false,
|
|
22922
24115
|
composerDiffLineComments: EMPTY_COMPOSER_DIFF_LINE_COMMENTS,
|
|
22923
24116
|
composerImages: EMPTY_COMPOSER_IMAGES,
|
|
@@ -22926,6 +24119,7 @@ function createInitialAppShellComposerSnapshot(viewerContextId) {
|
|
|
22926
24119
|
composerText: "",
|
|
22927
24120
|
currentPendingMessages: EMPTY_COMPOSER_PENDING_MESSAGES,
|
|
22928
24121
|
disabled: false,
|
|
24122
|
+
isCompacting: false,
|
|
22929
24123
|
isStreaming: false,
|
|
22930
24124
|
isSubmitting: false,
|
|
22931
24125
|
viewerContextId
|
|
@@ -22988,6 +24182,143 @@ function createPicoLatestThrottler(options) {
|
|
|
22988
24182
|
cancel: () => throttler.cancel()
|
|
22989
24183
|
};
|
|
22990
24184
|
}
|
|
24185
|
+
var OFFLINE_PROMPT_DB_NAME = "pico-offline-prompts";
|
|
24186
|
+
var OFFLINE_PROMPT_DB_VERSION = 1;
|
|
24187
|
+
var OFFLINE_PROMPT_STORE_NAME = "prompts";
|
|
24188
|
+
var OFFLINE_PROMPT_FALLBACK_STORAGE_KEY = "pico-offline-prompts";
|
|
24189
|
+
var dbPromise;
|
|
24190
|
+
function hasIndexedDb() {
|
|
24191
|
+
return typeof indexedDB !== "undefined";
|
|
24192
|
+
}
|
|
24193
|
+
function openOfflinePromptDb() {
|
|
24194
|
+
if (!hasIndexedDb()) return Promise.resolve(null);
|
|
24195
|
+
dbPromise ??= new Promise((resolve) => {
|
|
24196
|
+
const request = indexedDB.open(OFFLINE_PROMPT_DB_NAME, OFFLINE_PROMPT_DB_VERSION);
|
|
24197
|
+
request.onupgradeneeded = () => {
|
|
24198
|
+
const db = request.result;
|
|
24199
|
+
if (!db.objectStoreNames.contains(OFFLINE_PROMPT_STORE_NAME)) db.createObjectStore(OFFLINE_PROMPT_STORE_NAME, { keyPath: "id" });
|
|
24200
|
+
};
|
|
24201
|
+
request.onerror = () => resolve(null);
|
|
24202
|
+
request.onsuccess = () => resolve(request.result);
|
|
24203
|
+
});
|
|
24204
|
+
return dbPromise;
|
|
24205
|
+
}
|
|
24206
|
+
function fallbackItems() {
|
|
24207
|
+
try {
|
|
24208
|
+
const raw = window.localStorage.getItem(OFFLINE_PROMPT_FALLBACK_STORAGE_KEY);
|
|
24209
|
+
if (!raw) return [];
|
|
24210
|
+
const parsed = JSON.parse(raw);
|
|
24211
|
+
return Array.isArray(parsed) ? normalizeItems(parsed) : [];
|
|
24212
|
+
} catch {
|
|
24213
|
+
return [];
|
|
24214
|
+
}
|
|
24215
|
+
}
|
|
24216
|
+
function rememberFallbackItems(items) {
|
|
24217
|
+
try {
|
|
24218
|
+
window.localStorage.setItem(OFFLINE_PROMPT_FALLBACK_STORAGE_KEY, JSON.stringify(items));
|
|
24219
|
+
} catch {}
|
|
24220
|
+
}
|
|
24221
|
+
function normalizeImage(value) {
|
|
24222
|
+
if (!value || typeof value !== "object") return null;
|
|
24223
|
+
const rawImage = value;
|
|
24224
|
+
if (typeof rawImage.mimeType !== "string") return null;
|
|
24225
|
+
if (typeof rawImage.data !== "string") return null;
|
|
24226
|
+
return {
|
|
24227
|
+
type: "image",
|
|
24228
|
+
mimeType: rawImage.mimeType,
|
|
24229
|
+
data: rawImage.data
|
|
24230
|
+
};
|
|
24231
|
+
}
|
|
24232
|
+
function normalizeItem(value) {
|
|
24233
|
+
if (!value || typeof value !== "object") return null;
|
|
24234
|
+
const rawItem = value;
|
|
24235
|
+
if (typeof rawItem.id !== "string" || !rawItem.id) return null;
|
|
24236
|
+
if (typeof rawItem.contextId !== "string" || !rawItem.contextId) return null;
|
|
24237
|
+
if (typeof rawItem.message !== "string") return null;
|
|
24238
|
+
if (typeof rawItem.clientRequestId !== "string") return null;
|
|
24239
|
+
const images = Array.isArray(rawItem.images) ? rawItem.images.flatMap((image) => {
|
|
24240
|
+
const normalizedImage = normalizeImage(image);
|
|
24241
|
+
return normalizedImage ? [normalizedImage] : [];
|
|
24242
|
+
}) : [];
|
|
24243
|
+
return {
|
|
24244
|
+
id: rawItem.id,
|
|
24245
|
+
contextId: rawItem.contextId,
|
|
24246
|
+
createdAt: typeof rawItem.createdAt === "number" && Number.isFinite(rawItem.createdAt) ? rawItem.createdAt : Date.now(),
|
|
24247
|
+
sessionId: typeof rawItem.sessionId === "string" ? rawItem.sessionId : void 0,
|
|
24248
|
+
targetSessionKey: typeof rawItem.targetSessionKey === "string" ? rawItem.targetSessionKey : void 0,
|
|
24249
|
+
message: rawItem.message,
|
|
24250
|
+
images,
|
|
24251
|
+
streamingBehavior: rawItem.streamingBehavior === "followUp" || rawItem.streamingBehavior === "steer" ? rawItem.streamingBehavior : void 0,
|
|
24252
|
+
pendingId: typeof rawItem.pendingId === "string" ? rawItem.pendingId : void 0,
|
|
24253
|
+
clientRequestId: rawItem.clientRequestId,
|
|
24254
|
+
thinkingLevel: typeof rawItem.thinkingLevel === "string" ? rawItem.thinkingLevel : void 0,
|
|
24255
|
+
draftOwnerKey: typeof rawItem.draftOwnerKey === "string" ? rawItem.draftOwnerKey : void 0,
|
|
24256
|
+
draftCwd: typeof rawItem.draftCwd === "string" ? rawItem.draftCwd : void 0
|
|
24257
|
+
};
|
|
24258
|
+
}
|
|
24259
|
+
function normalizeItems(values) {
|
|
24260
|
+
return values.flatMap((value) => {
|
|
24261
|
+
const normalizedItem = normalizeItem(value);
|
|
24262
|
+
return normalizedItem ? [normalizedItem] : [];
|
|
24263
|
+
}).sort((left, right) => left.createdAt - right.createdAt);
|
|
24264
|
+
}
|
|
24265
|
+
async function enqueueOfflinePrompt(item) {
|
|
24266
|
+
const db = await openOfflinePromptDb();
|
|
24267
|
+
if (!db) {
|
|
24268
|
+
const items = fallbackItems().filter((entry) => entry.id !== item.id);
|
|
24269
|
+
items.push(item);
|
|
24270
|
+
rememberFallbackItems(normalizeItems(items));
|
|
24271
|
+
return;
|
|
24272
|
+
}
|
|
24273
|
+
await new Promise((resolve, reject) => {
|
|
24274
|
+
const transaction = db.transaction(OFFLINE_PROMPT_STORE_NAME, "readwrite");
|
|
24275
|
+
const request = transaction.objectStore(OFFLINE_PROMPT_STORE_NAME).put(item);
|
|
24276
|
+
request.onerror = () => reject(request.error);
|
|
24277
|
+
transaction.oncomplete = () => resolve();
|
|
24278
|
+
transaction.onerror = () => reject(transaction.error);
|
|
24279
|
+
});
|
|
24280
|
+
}
|
|
24281
|
+
async function readOfflinePrompts(contextId) {
|
|
24282
|
+
const db = await openOfflinePromptDb();
|
|
24283
|
+
if (!db) {
|
|
24284
|
+
const items = fallbackItems();
|
|
24285
|
+
return contextId ? items.filter((item) => item.contextId === contextId) : items;
|
|
24286
|
+
}
|
|
24287
|
+
const items = await new Promise((resolve, reject) => {
|
|
24288
|
+
const transaction = db.transaction(OFFLINE_PROMPT_STORE_NAME, "readonly");
|
|
24289
|
+
const request = transaction.objectStore(OFFLINE_PROMPT_STORE_NAME).getAll();
|
|
24290
|
+
request.onerror = () => reject(request.error);
|
|
24291
|
+
request.onsuccess = () => resolve(normalizeItems(request.result));
|
|
24292
|
+
transaction.onerror = () => reject(transaction.error);
|
|
24293
|
+
});
|
|
24294
|
+
return contextId ? items.filter((item) => item.contextId === contextId) : items;
|
|
24295
|
+
}
|
|
24296
|
+
async function removeOfflinePrompt(id) {
|
|
24297
|
+
const db = await openOfflinePromptDb();
|
|
24298
|
+
if (!db) {
|
|
24299
|
+
rememberFallbackItems(fallbackItems().filter((item) => item.id !== id));
|
|
24300
|
+
return;
|
|
24301
|
+
}
|
|
24302
|
+
await new Promise((resolve, reject) => {
|
|
24303
|
+
const transaction = db.transaction(OFFLINE_PROMPT_STORE_NAME, "readwrite");
|
|
24304
|
+
const request = transaction.objectStore(OFFLINE_PROMPT_STORE_NAME).delete(id);
|
|
24305
|
+
request.onerror = () => reject(request.error);
|
|
24306
|
+
transaction.oncomplete = () => resolve();
|
|
24307
|
+
transaction.onerror = () => reject(transaction.error);
|
|
24308
|
+
});
|
|
24309
|
+
}
|
|
24310
|
+
function pendingMessagesFromResponse(response) {
|
|
24311
|
+
if (!("ok" in response) || !response.ok) return null;
|
|
24312
|
+
return response.pendingMessages.map((message) => ({
|
|
24313
|
+
pendingId: message.pendingId,
|
|
24314
|
+
text: message.text,
|
|
24315
|
+
images: message.images.flatMap((image) => {
|
|
24316
|
+
const normalizedImage = normalizePromptImage(image);
|
|
24317
|
+
return normalizedImage ? [normalizedImage] : [];
|
|
24318
|
+
}),
|
|
24319
|
+
streamingBehavior: message.streamingBehavior === "steer" ? "steer" : "followUp"
|
|
24320
|
+
}));
|
|
24321
|
+
}
|
|
22991
24322
|
function samePromptMutationSessionSnapshot(left, right) {
|
|
22992
24323
|
return left.assistantOutputSignature === right.assistantOutputSignature && left.cwd === right.cwd && left.draft === right.draft && left.sessionFile === right.sessionFile && left.sessionId === right.sessionId && left.sessionKey === right.sessionKey && left.streaming === right.streaming;
|
|
22993
24324
|
}
|
|
@@ -23027,7 +24358,20 @@ function createLocalPendingId() {
|
|
|
23027
24358
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return `optimistic:${crypto.randomUUID()}`;
|
|
23028
24359
|
return `optimistic:${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
23029
24360
|
}
|
|
23030
|
-
function
|
|
24361
|
+
function createClientPromptRequestId() {
|
|
24362
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") return `prompt:${crypto.randomUUID()}`;
|
|
24363
|
+
return `prompt:${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
24364
|
+
}
|
|
24365
|
+
function isOfflinePromptSubmissionError(error) {
|
|
24366
|
+
if (typeof navigator !== "undefined" && navigator.onLine === false) return true;
|
|
24367
|
+
const message = error instanceof Error ? error.message.toLowerCase() : "";
|
|
24368
|
+
return message === "failed to fetch" || message === "load failed" || message.includes("networkerror") || message.includes("network error");
|
|
24369
|
+
}
|
|
24370
|
+
function buildCurrentSessionRequestUrl(path, { contextId, sessionState, fallbackSessionId, targetSessionKey }) {
|
|
24371
|
+
if (targetSessionKey) return buildRequestUrl(path, {
|
|
24372
|
+
contextId,
|
|
24373
|
+
searchParams: { sessionKey: targetSessionKey }
|
|
24374
|
+
});
|
|
23031
24375
|
const sessionKey = sessionState.sessionKey && !sessionState.sessionKey.startsWith("optimistic:") ? sessionState.sessionKey : void 0;
|
|
23032
24376
|
const shouldUseSessionKey = Boolean(sessionKey && (sessionState.draft || !sessionState.sessionId));
|
|
23033
24377
|
return buildRequestUrl(path, {
|
|
@@ -23036,6 +24380,25 @@ function buildCurrentSessionRequestUrl(path, { contextId, sessionState, fallback
|
|
|
23036
24380
|
searchParams: shouldUseSessionKey ? { sessionKey } : void 0
|
|
23037
24381
|
});
|
|
23038
24382
|
}
|
|
24383
|
+
function buildOfflinePromptRequestUrl(item) {
|
|
24384
|
+
return buildRequestUrl("/api/prompt", {
|
|
24385
|
+
contextId: item.contextId,
|
|
24386
|
+
sessionId: item.targetSessionKey ? void 0 : item.sessionId,
|
|
24387
|
+
searchParams: item.targetSessionKey ? { sessionKey: item.targetSessionKey } : void 0
|
|
24388
|
+
});
|
|
24389
|
+
}
|
|
24390
|
+
function buildOfflinePromptBody(item) {
|
|
24391
|
+
return {
|
|
24392
|
+
message: item.message,
|
|
24393
|
+
images: item.images,
|
|
24394
|
+
streamingBehavior: item.streamingBehavior,
|
|
24395
|
+
pendingId: item.pendingId,
|
|
24396
|
+
clientRequestId: item.clientRequestId,
|
|
24397
|
+
thinkingLevel: item.thinkingLevel,
|
|
24398
|
+
draftOwnerKey: item.draftOwnerKey,
|
|
24399
|
+
draftCwd: item.draftCwd
|
|
24400
|
+
};
|
|
24401
|
+
}
|
|
23039
24402
|
function isPendingPromptNotFoundError(error) {
|
|
23040
24403
|
return error instanceof Error && error.message.toLowerCase().includes("pending prompt not found");
|
|
23041
24404
|
}
|
|
@@ -23088,13 +24451,14 @@ function movePendingComposerMessage(messages, pendingId, direction) {
|
|
|
23088
24451
|
function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultNewSessionDirectory, sessionStore, sessionStateRef, draftSessionLoadingOwnerKey, pendingDraftPrompt, pendingDraftFollowUps, awaitingFirstTurn, pendingMessages, composerDiffLineCommentsRef, composerImagesRef, composerTextRef, composerSkillRef, replaceComposerDraft, lastSyncedEditorTextRef, rememberRecentDirectory, prefetchDirectorySessionsIndex, addOptimisticUserMessage, removeOptimisticUserMessage, addOptimisticSidebarSession, removeOptimisticSidebarSession, updateOptimisticSidebarSessionPreview, setSidebarDirectories, setStoredDraftDirectory, setDraftSessionLoadingOwnerKey, setPendingDraftPrompt, setPendingDraftFollowUps, setPendingMessages, setAwaitingFirstTurn, setIsSubmitting, setComposerDiffLineComments, setComposerImages }) {
|
|
23089
24452
|
const queryClient = useQueryClient();
|
|
23090
24453
|
const draftSessionLoadingOwnerKeyRef = import_react.useRef(draftSessionLoadingOwnerKey);
|
|
24454
|
+
const pendingNewSessionPromptTargetRef = import_react.useRef(null);
|
|
24455
|
+
const newSessionRequestNonceRef = import_react.useRef(0);
|
|
23091
24456
|
const pendingDraftPromptRef = import_react.useRef(pendingDraftPrompt);
|
|
23092
24457
|
const pendingDraftFollowUpsRef = import_react.useRef(pendingDraftFollowUps);
|
|
23093
24458
|
const pendingMessagesRef = import_react.useRef(pendingMessages);
|
|
23094
24459
|
const awaitingFirstTurnRef = import_react.useRef(awaitingFirstTurn);
|
|
23095
24460
|
const awaitingFirstTurnAssistantOutputSignatureRef = import_react.useRef(null);
|
|
23096
24461
|
const sessionSnapshot = usePromptMutationSessionSnapshot(sessionStore);
|
|
23097
|
-
const sessionStreamingRef = import_react.useRef(sessionSnapshot.streaming);
|
|
23098
24462
|
const flushPendingDraftPromptRef = import_react.useRef(async () => false);
|
|
23099
24463
|
import_react.useEffect(() => {
|
|
23100
24464
|
draftSessionLoadingOwnerKeyRef.current = draftSessionLoadingOwnerKey;
|
|
@@ -23111,9 +24475,6 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23111
24475
|
import_react.useEffect(() => {
|
|
23112
24476
|
awaitingFirstTurnRef.current = awaitingFirstTurn;
|
|
23113
24477
|
}, [awaitingFirstTurn]);
|
|
23114
|
-
import_react.useEffect(() => {
|
|
23115
|
-
sessionStreamingRef.current = sessionSnapshot.streaming;
|
|
23116
|
-
}, [sessionSnapshot.streaming]);
|
|
23117
24478
|
const updatePendingMessages = import_react.useCallback((updater) => {
|
|
23118
24479
|
setPendingMessages((current) => {
|
|
23119
24480
|
const next = updater(current);
|
|
@@ -23168,6 +24529,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23168
24529
|
removeOptimisticUserMessage(nextPrompt.optimisticId);
|
|
23169
24530
|
removeOptimisticSidebarSession(nextPrompt.optimisticSidebarSessionId);
|
|
23170
24531
|
for (const followUp of pendingDraftFollowUpsRef.current) removeOptimisticUserMessage(followUp.optimisticId);
|
|
24532
|
+
pendingNewSessionPromptTargetRef.current = null;
|
|
23171
24533
|
pendingDraftPromptRef.current = null;
|
|
23172
24534
|
pendingDraftFollowUpsRef.current = [];
|
|
23173
24535
|
setPendingDraftPrompt(null);
|
|
@@ -23240,17 +24602,32 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23240
24602
|
const ownerKey = promptDraftKey({ cwd: nextCwd });
|
|
23241
24603
|
draftSessionLoadingOwnerKeyRef.current = ownerKey;
|
|
23242
24604
|
setDraftSessionLoadingOwnerKey(ownerKey);
|
|
24605
|
+
awaitingFirstTurnAssistantOutputSignatureRef.current = null;
|
|
24606
|
+
awaitingFirstTurnRef.current = false;
|
|
24607
|
+
setAwaitingFirstTurn(false);
|
|
24608
|
+
pendingMessagesRef.current = [];
|
|
24609
|
+
setPendingMessages((current) => current.length === 0 ? current : []);
|
|
24610
|
+
const requestNonce = newSessionRequestNonceRef.current + 1;
|
|
24611
|
+
newSessionRequestNonceRef.current = requestNonce;
|
|
23243
24612
|
try {
|
|
23244
|
-
await createSessionRequest({ cwd: nextCwd });
|
|
24613
|
+
const response = await createSessionRequest({ cwd: nextCwd });
|
|
24614
|
+
if (newSessionRequestNonceRef.current !== requestNonce) return true;
|
|
24615
|
+
pendingNewSessionPromptTargetRef.current = {
|
|
24616
|
+
ownerKey,
|
|
24617
|
+
sessionKey: response.sessionKey,
|
|
24618
|
+
cwd: response.cwd
|
|
24619
|
+
};
|
|
23245
24620
|
if (draftSessionLoadingOwnerKeyRef.current === ownerKey) {
|
|
23246
24621
|
draftSessionLoadingOwnerKeyRef.current = null;
|
|
23247
24622
|
setDraftSessionLoadingOwnerKey((current) => current === ownerKey ? null : current);
|
|
23248
24623
|
}
|
|
23249
|
-
if (pendingDraftPromptRef.current?.ownerKey === ownerKey) flushPendingDraftPromptRef.current(ownerKey);
|
|
24624
|
+
if (pendingDraftPromptRef.current?.ownerKey === ownerKey) flushPendingDraftPromptRef.current(ownerKey, response.sessionKey);
|
|
23250
24625
|
return true;
|
|
23251
24626
|
} catch (error) {
|
|
24627
|
+
if (newSessionRequestNonceRef.current !== requestNonce) return true;
|
|
23252
24628
|
if (draftSessionLoadingOwnerKeyRef.current === ownerKey) draftSessionLoadingOwnerKeyRef.current = null;
|
|
23253
24629
|
setDraftSessionLoadingOwnerKey((current) => current === ownerKey ? null : current);
|
|
24630
|
+
if (pendingNewSessionPromptTargetRef.current?.ownerKey === ownerKey) pendingNewSessionPromptTargetRef.current = null;
|
|
23254
24631
|
restorePendingDraftPrompt(ownerKey);
|
|
23255
24632
|
toast.error(error instanceof Error ? error.message : "Failed to create session");
|
|
23256
24633
|
return false;
|
|
@@ -23261,12 +24638,14 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23261
24638
|
rememberRecentDirectory,
|
|
23262
24639
|
restorePendingDraftPrompt,
|
|
23263
24640
|
sessionStateRef,
|
|
24641
|
+
setAwaitingFirstTurn,
|
|
23264
24642
|
setDraftSessionLoadingOwnerKey,
|
|
24643
|
+
setPendingMessages,
|
|
23265
24644
|
setStoredDraftDirectory,
|
|
23266
24645
|
viewerContextId
|
|
23267
24646
|
]);
|
|
23268
|
-
const queuePendingDraftPrompt = import_react.useCallback((streamingBehavior) => {
|
|
23269
|
-
const ownerKey = draftSessionLoadingOwnerKeyRef.current;
|
|
24647
|
+
const queuePendingDraftPrompt = import_react.useCallback((streamingBehavior, ownerKeyOverride) => {
|
|
24648
|
+
const ownerKey = ownerKeyOverride || draftSessionLoadingOwnerKeyRef.current;
|
|
23270
24649
|
if (!ownerKey) return false;
|
|
23271
24650
|
const message = buildComposerPromptMessage({
|
|
23272
24651
|
text: composerTextRef.current,
|
|
@@ -23282,6 +24661,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23282
24661
|
ownerKey,
|
|
23283
24662
|
message,
|
|
23284
24663
|
images,
|
|
24664
|
+
streamingBehavior,
|
|
23285
24665
|
optimisticId: addOptimisticUserMessage({
|
|
23286
24666
|
message,
|
|
23287
24667
|
images,
|
|
@@ -23332,12 +24712,13 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23332
24712
|
updateOptimisticSidebarSessionPreview
|
|
23333
24713
|
]);
|
|
23334
24714
|
const promptMutation = useMutation({
|
|
23335
|
-
mutationFn: async ({ message, images, streamingBehavior, pendingId, thinkingLevel }) => {
|
|
24715
|
+
mutationFn: async ({ message, images, streamingBehavior, pendingId, clientRequestId, thinkingLevel, targetSessionKey, draftTarget }) => {
|
|
23336
24716
|
if (!viewerContextId) throw new Error("Viewer context unavailable");
|
|
23337
24717
|
return await fetchJson(buildCurrentSessionRequestUrl("/api/prompt", {
|
|
23338
24718
|
contextId: viewerContextId,
|
|
23339
24719
|
sessionState: sessionStateRef.current,
|
|
23340
|
-
fallbackSessionId: activeSessionId
|
|
24720
|
+
fallbackSessionId: activeSessionId,
|
|
24721
|
+
targetSessionKey
|
|
23341
24722
|
}), {
|
|
23342
24723
|
method: "POST",
|
|
23343
24724
|
headers: { "content-type": "application/json" },
|
|
@@ -23346,7 +24727,10 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23346
24727
|
images,
|
|
23347
24728
|
streamingBehavior,
|
|
23348
24729
|
pendingId,
|
|
23349
|
-
|
|
24730
|
+
clientRequestId,
|
|
24731
|
+
thinkingLevel,
|
|
24732
|
+
draftOwnerKey: draftTarget?.ownerKey,
|
|
24733
|
+
draftCwd: draftTarget?.cwd
|
|
23350
24734
|
})
|
|
23351
24735
|
});
|
|
23352
24736
|
},
|
|
@@ -23357,6 +24741,58 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23357
24741
|
});
|
|
23358
24742
|
}
|
|
23359
24743
|
});
|
|
24744
|
+
const offlinePromptFlushInFlightRef = import_react.useRef(false);
|
|
24745
|
+
const offlinePromptFailureToastIdsRef = import_react.useRef(/* @__PURE__ */ new Set());
|
|
24746
|
+
const flushOfflinePromptQueue = import_react.useCallback(async () => {
|
|
24747
|
+
if (!viewerContextId || offlinePromptFlushInFlightRef.current) return;
|
|
24748
|
+
if (typeof navigator !== "undefined" && navigator.onLine === false) return;
|
|
24749
|
+
offlinePromptFlushInFlightRef.current = true;
|
|
24750
|
+
try {
|
|
24751
|
+
const queuedPrompts = await readOfflinePrompts(viewerContextId);
|
|
24752
|
+
if (queuedPrompts.length === 0) return;
|
|
24753
|
+
let flushedCount = 0;
|
|
24754
|
+
for (const item of queuedPrompts) try {
|
|
24755
|
+
await fetchJson(buildOfflinePromptRequestUrl(item), {
|
|
24756
|
+
method: "POST",
|
|
24757
|
+
headers: { "content-type": "application/json" },
|
|
24758
|
+
body: JSON.stringify(buildOfflinePromptBody(item))
|
|
24759
|
+
});
|
|
24760
|
+
await removeOfflinePrompt(item.id);
|
|
24761
|
+
offlinePromptFailureToastIdsRef.current.delete(item.id);
|
|
24762
|
+
flushedCount += 1;
|
|
24763
|
+
} catch (error) {
|
|
24764
|
+
if (isOfflinePromptSubmissionError(error)) break;
|
|
24765
|
+
if (!offlinePromptFailureToastIdsRef.current.has(item.id)) {
|
|
24766
|
+
offlinePromptFailureToastIdsRef.current.add(item.id);
|
|
24767
|
+
toast.error(error instanceof Error ? `Failed to send queued prompt: ${error.message}` : "Failed to send queued prompt");
|
|
24768
|
+
}
|
|
24769
|
+
break;
|
|
24770
|
+
}
|
|
24771
|
+
if (flushedCount > 0) {
|
|
24772
|
+
toast.success(flushedCount === 1 ? "Sent queued prompt" : `Sent ${flushedCount.toLocaleString()} queued prompts`);
|
|
24773
|
+
await queryClient.invalidateQueries({ refetchType: "active" });
|
|
24774
|
+
}
|
|
24775
|
+
} finally {
|
|
24776
|
+
offlinePromptFlushInFlightRef.current = false;
|
|
24777
|
+
}
|
|
24778
|
+
}, [queryClient, viewerContextId]);
|
|
24779
|
+
import_react.useEffect(() => {
|
|
24780
|
+
if (!viewerContextId) return;
|
|
24781
|
+
const flush = () => {
|
|
24782
|
+
flushOfflinePromptQueue();
|
|
24783
|
+
};
|
|
24784
|
+
window.addEventListener("online", flush);
|
|
24785
|
+
window.addEventListener("focus", flush);
|
|
24786
|
+
document.addEventListener("visibilitychange", flush);
|
|
24787
|
+
const timer = window.setInterval(flush, 3e4);
|
|
24788
|
+
flush();
|
|
24789
|
+
return () => {
|
|
24790
|
+
window.removeEventListener("online", flush);
|
|
24791
|
+
window.removeEventListener("focus", flush);
|
|
24792
|
+
document.removeEventListener("visibilitychange", flush);
|
|
24793
|
+
window.clearInterval(timer);
|
|
24794
|
+
};
|
|
24795
|
+
}, [flushOfflinePromptQueue, viewerContextId]);
|
|
23360
24796
|
const submitPrompt = import_react.useCallback(async (streamingBehavior, options) => {
|
|
23361
24797
|
if (!viewerContextId) return false;
|
|
23362
24798
|
if (draftSessionLoadingOwnerKeyRef.current) return queuePendingDraftPrompt(streamingBehavior);
|
|
@@ -23367,13 +24803,29 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23367
24803
|
diffLineComments: submittedDiffLineComments
|
|
23368
24804
|
}).trim();
|
|
23369
24805
|
if (!message && composerImagesRef.current.length === 0) return false;
|
|
23370
|
-
const
|
|
24806
|
+
const currentSessionState = sessionStateRef.current;
|
|
24807
|
+
const pendingNewSessionPromptTarget = pendingNewSessionPromptTargetRef.current;
|
|
24808
|
+
const currentDraftOwnerKey = currentSessionState.draft ? promptDraftKey(currentSessionState) : "";
|
|
24809
|
+
const implicitTargetSessionKey = !options?.targetSessionKey && currentSessionState.draft && pendingNewSessionPromptTarget && promptDraftKeyMatchesOwner(currentDraftOwnerKey, pendingNewSessionPromptTarget.ownerKey) ? pendingNewSessionPromptTarget.sessionKey : void 0;
|
|
24810
|
+
const targetSessionKey = options?.targetSessionKey || implicitTargetSessionKey;
|
|
24811
|
+
const targetDraft = currentSessionState.draft ? {
|
|
24812
|
+
ownerKey: options?.targetDraftOwnerKey || (targetSessionKey && pendingNewSessionPromptTarget?.sessionKey === targetSessionKey ? pendingNewSessionPromptTarget.ownerKey : currentDraftOwnerKey),
|
|
24813
|
+
cwd: options?.targetDraftCwd || (targetSessionKey && pendingNewSessionPromptTarget?.sessionKey === targetSessionKey ? pendingNewSessionPromptTarget.cwd || currentSessionState.cwd : currentSessionState.cwd)
|
|
24814
|
+
} : void 0;
|
|
24815
|
+
if (currentSessionState.draft && currentSessionState.sessionKey?.startsWith("optimistic:") && !targetSessionKey) {
|
|
24816
|
+
if (!draftSessionLoadingOwnerKeyRef.current && currentDraftOwnerKey) {
|
|
24817
|
+
draftSessionLoadingOwnerKeyRef.current = currentDraftOwnerKey;
|
|
24818
|
+
setDraftSessionLoadingOwnerKey(currentDraftOwnerKey);
|
|
24819
|
+
}
|
|
24820
|
+
return queuePendingDraftPrompt(streamingBehavior, currentDraftOwnerKey);
|
|
24821
|
+
}
|
|
24822
|
+
const treatAsQueuedPrompt = options?.forceFirstPrompt ? false : Boolean(currentSessionState.streaming || currentSessionState.compacting || awaitingFirstTurnRef.current);
|
|
23371
24823
|
const normalizedStreamingBehavior = treatAsQueuedPrompt ? normalizeQueuedStreamingBehavior(streamingBehavior) : void 0;
|
|
23372
24824
|
const submittedImages = composerImagesRef.current.map((image) => ({ ...image }));
|
|
23373
24825
|
const sidebarPreview = promptSidebarPreview(message, submittedImages);
|
|
23374
24826
|
const queuedPendingId = treatAsQueuedPrompt ? createLocalPendingId() : void 0;
|
|
23375
24827
|
if (!treatAsQueuedPrompt) {
|
|
23376
|
-
awaitingFirstTurnAssistantOutputSignatureRef.current = sessionAssistantOutputSignature(
|
|
24828
|
+
awaitingFirstTurnAssistantOutputSignatureRef.current = sessionAssistantOutputSignature(currentSessionState.items);
|
|
23377
24829
|
awaitingFirstTurnRef.current = true;
|
|
23378
24830
|
setAwaitingFirstTurn(true);
|
|
23379
24831
|
}
|
|
@@ -23382,7 +24834,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23382
24834
|
images: submittedImages,
|
|
23383
24835
|
queued: false
|
|
23384
24836
|
}));
|
|
23385
|
-
const optimisticSidebarSessionId = options?.optimisticSidebarSessionId ?? (!treatAsQueuedPrompt &&
|
|
24837
|
+
const optimisticSidebarSessionId = options?.optimisticSidebarSessionId ?? (!treatAsQueuedPrompt && currentSessionState.draft ? addOptimisticSidebarSession({ lastMessagePreview: sidebarPreview }) : void 0);
|
|
23386
24838
|
updateOptimisticSidebarSessionPreview({
|
|
23387
24839
|
...optimisticSidebarSessionId ? { optimisticSidebarSessionId } : {},
|
|
23388
24840
|
preview: sidebarPreview
|
|
@@ -23393,6 +24845,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23393
24845
|
images: submittedImages.map((image) => ({ ...image })),
|
|
23394
24846
|
streamingBehavior: normalizedStreamingBehavior
|
|
23395
24847
|
});
|
|
24848
|
+
const clientRequestId = createClientPromptRequestId();
|
|
23396
24849
|
setIsSubmitting(true);
|
|
23397
24850
|
replaceComposerDraft("", void 0, { forceSync: true });
|
|
23398
24851
|
setComposerDiffLineComments([]);
|
|
@@ -23404,11 +24857,48 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23404
24857
|
images: submittedImages,
|
|
23405
24858
|
streamingBehavior: normalizedStreamingBehavior,
|
|
23406
24859
|
pendingId: queuedPendingId,
|
|
23407
|
-
|
|
24860
|
+
clientRequestId,
|
|
24861
|
+
thinkingLevel: currentSessionState.thinkingLevel,
|
|
24862
|
+
targetSessionKey,
|
|
24863
|
+
draftTarget: targetDraft
|
|
23408
24864
|
});
|
|
23409
24865
|
if (queuedPendingId && "queued" in response && (!response.queued || response.canceled)) removeOptimisticPendingMessage(queuedPendingId);
|
|
24866
|
+
if (targetSessionKey && pendingNewSessionPromptTargetRef.current?.sessionKey === targetSessionKey) pendingNewSessionPromptTargetRef.current = null;
|
|
23410
24867
|
return true;
|
|
23411
24868
|
} catch (error) {
|
|
24869
|
+
const queueSessionKey = targetSessionKey || (currentSessionState.sessionKey && !currentSessionState.sessionKey.startsWith("optimistic:") && (currentSessionState.draft || !currentSessionState.sessionId) ? currentSessionState.sessionKey : void 0);
|
|
24870
|
+
const queueSessionId = queueSessionKey ? void 0 : currentSessionState.sessionId ?? activeSessionId;
|
|
24871
|
+
if (isOfflinePromptSubmissionError(error) && (queueSessionKey || queueSessionId)) {
|
|
24872
|
+
await enqueueOfflinePrompt({
|
|
24873
|
+
id: clientRequestId,
|
|
24874
|
+
contextId: viewerContextId,
|
|
24875
|
+
createdAt: Date.now(),
|
|
24876
|
+
sessionId: queueSessionId,
|
|
24877
|
+
targetSessionKey: queueSessionKey,
|
|
24878
|
+
message,
|
|
24879
|
+
images: submittedImages.map((image) => ({
|
|
24880
|
+
type: "image",
|
|
24881
|
+
mimeType: image.mimeType,
|
|
24882
|
+
data: image.data
|
|
24883
|
+
})),
|
|
24884
|
+
streamingBehavior: normalizedStreamingBehavior,
|
|
24885
|
+
pendingId: queuedPendingId,
|
|
24886
|
+
clientRequestId,
|
|
24887
|
+
thinkingLevel: currentSessionState.thinkingLevel,
|
|
24888
|
+
draftOwnerKey: targetDraft?.ownerKey,
|
|
24889
|
+
draftCwd: targetDraft?.cwd
|
|
24890
|
+
});
|
|
24891
|
+
if (queuedPendingId) removeOptimisticPendingMessage(queuedPendingId);
|
|
24892
|
+
removeOptimisticUserMessage(optimisticId);
|
|
24893
|
+
removeOptimisticSidebarSession(optimisticSidebarSessionId);
|
|
24894
|
+
if (!treatAsQueuedPrompt) {
|
|
24895
|
+
awaitingFirstTurnAssistantOutputSignatureRef.current = null;
|
|
24896
|
+
awaitingFirstTurnRef.current = false;
|
|
24897
|
+
setAwaitingFirstTurn(false);
|
|
24898
|
+
}
|
|
24899
|
+
toast.info("Prompt queued locally and will send when reconnected");
|
|
24900
|
+
return true;
|
|
24901
|
+
}
|
|
23412
24902
|
if (queuedPendingId) removeOptimisticPendingMessage(queuedPendingId);
|
|
23413
24903
|
removeOptimisticUserMessage(optimisticId);
|
|
23414
24904
|
removeOptimisticSidebarSession(optimisticSidebarSessionId);
|
|
@@ -23431,6 +24921,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23431
24921
|
setIsSubmitting(false);
|
|
23432
24922
|
}
|
|
23433
24923
|
}, [
|
|
24924
|
+
activeSessionId,
|
|
23434
24925
|
addOptimisticPendingMessage,
|
|
23435
24926
|
addOptimisticSidebarSession,
|
|
23436
24927
|
addOptimisticUserMessage,
|
|
@@ -23449,11 +24940,12 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23449
24940
|
setAwaitingFirstTurn,
|
|
23450
24941
|
setComposerDiffLineComments,
|
|
23451
24942
|
setComposerImages,
|
|
24943
|
+
setDraftSessionLoadingOwnerKey,
|
|
23452
24944
|
setIsSubmitting,
|
|
23453
24945
|
updateOptimisticSidebarSessionPreview,
|
|
23454
24946
|
viewerContextId
|
|
23455
24947
|
]);
|
|
23456
|
-
const flushPendingDraftFollowUps = import_react.useCallback(async () => {
|
|
24948
|
+
const flushPendingDraftFollowUps = import_react.useCallback(async (targetSessionKey, draftTarget) => {
|
|
23457
24949
|
if (draftSessionLoadingOwnerKeyRef.current) return false;
|
|
23458
24950
|
const pendingFollowUps = pendingDraftFollowUpsRef.current;
|
|
23459
24951
|
if (pendingFollowUps.length === 0) return false;
|
|
@@ -23474,7 +24966,10 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23474
24966
|
images: followUp.images,
|
|
23475
24967
|
streamingBehavior: followUp.streamingBehavior,
|
|
23476
24968
|
pendingId: followUp.optimisticId,
|
|
23477
|
-
|
|
24969
|
+
clientRequestId: createClientPromptRequestId(),
|
|
24970
|
+
thinkingLevel: sessionStateRef.current.thinkingLevel,
|
|
24971
|
+
targetSessionKey,
|
|
24972
|
+
draftTarget
|
|
23478
24973
|
});
|
|
23479
24974
|
} catch (error) {
|
|
23480
24975
|
for (const unsentFollowUp of followUps.slice(index)) removeOptimisticUserMessage(unsentFollowUp.optimisticId);
|
|
@@ -23497,24 +24992,35 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23497
24992
|
setComposerImages,
|
|
23498
24993
|
setPendingDraftFollowUps
|
|
23499
24994
|
]);
|
|
23500
|
-
const flushPendingDraftPrompt = import_react.useCallback(async (ownerKey) => {
|
|
24995
|
+
const flushPendingDraftPrompt = import_react.useCallback(async (ownerKey, targetSessionKey) => {
|
|
23501
24996
|
const nextPrompt = pendingDraftPromptRef.current;
|
|
23502
24997
|
if (!nextPrompt || nextPrompt.ownerKey !== ownerKey || draftSessionLoadingOwnerKeyRef.current) return false;
|
|
24998
|
+
const pendingTarget = pendingNewSessionPromptTargetRef.current;
|
|
24999
|
+
const resolvedTargetSessionKey = targetSessionKey || (pendingTarget?.ownerKey === ownerKey ? pendingTarget.sessionKey : void 0);
|
|
25000
|
+
const resolvedDraftTarget = {
|
|
25001
|
+
ownerKey,
|
|
25002
|
+
cwd: pendingTarget?.cwd || sessionStateRef.current.cwd
|
|
25003
|
+
};
|
|
23503
25004
|
pendingDraftPromptRef.current = null;
|
|
23504
25005
|
setPendingDraftPrompt(null);
|
|
23505
25006
|
applyPendingDraftPromptToComposer(nextPrompt);
|
|
23506
25007
|
if (!await submitPrompt(nextPrompt.streamingBehavior, {
|
|
23507
25008
|
forceFirstPrompt: true,
|
|
23508
25009
|
optimisticId: nextPrompt.optimisticId,
|
|
23509
|
-
optimisticSidebarSessionId: nextPrompt.optimisticSidebarSessionId
|
|
25010
|
+
optimisticSidebarSessionId: nextPrompt.optimisticSidebarSessionId,
|
|
25011
|
+
targetSessionKey: resolvedTargetSessionKey,
|
|
25012
|
+
targetDraftOwnerKey: resolvedDraftTarget.ownerKey,
|
|
25013
|
+
targetDraftCwd: resolvedDraftTarget.cwd
|
|
23510
25014
|
})) {
|
|
23511
25015
|
removeOptimisticSidebarSession(nextPrompt.optimisticSidebarSessionId);
|
|
23512
25016
|
for (const followUp of pendingDraftFollowUpsRef.current) removeOptimisticUserMessage(followUp.optimisticId);
|
|
23513
25017
|
pendingDraftFollowUpsRef.current = [];
|
|
23514
25018
|
setPendingDraftFollowUps([]);
|
|
25019
|
+
if (pendingNewSessionPromptTargetRef.current?.ownerKey === ownerKey) pendingNewSessionPromptTargetRef.current = null;
|
|
23515
25020
|
return false;
|
|
23516
25021
|
}
|
|
23517
|
-
await flushPendingDraftFollowUps();
|
|
25022
|
+
await flushPendingDraftFollowUps(resolvedTargetSessionKey, resolvedDraftTarget);
|
|
25023
|
+
if (pendingNewSessionPromptTargetRef.current?.ownerKey === ownerKey) pendingNewSessionPromptTargetRef.current = null;
|
|
23518
25024
|
return true;
|
|
23519
25025
|
}, [
|
|
23520
25026
|
applyPendingDraftPromptToComposer,
|
|
@@ -23532,9 +25038,15 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23532
25038
|
if (currentSessionState.sessionKey?.startsWith("optimistic:")) return;
|
|
23533
25039
|
const currentOwnerKey = promptDraftKey(currentSessionState);
|
|
23534
25040
|
if (!currentSessionState.draft || !promptDraftKeyMatchesOwner(currentOwnerKey, draftSessionLoadingOwnerKey)) return;
|
|
25041
|
+
const targetSessionKey = currentSessionState.sessionKey?.startsWith("optimistic:") ? void 0 : currentSessionState.sessionKey;
|
|
25042
|
+
if (targetSessionKey) pendingNewSessionPromptTargetRef.current = {
|
|
25043
|
+
ownerKey: draftSessionLoadingOwnerKey,
|
|
25044
|
+
sessionKey: targetSessionKey,
|
|
25045
|
+
cwd: currentSessionState.cwd
|
|
25046
|
+
};
|
|
23535
25047
|
draftSessionLoadingOwnerKeyRef.current = null;
|
|
23536
25048
|
setDraftSessionLoadingOwnerKey(null);
|
|
23537
|
-
if (pendingDraftPromptRef.current?.ownerKey === draftSessionLoadingOwnerKey) flushPendingDraftPrompt(draftSessionLoadingOwnerKey);
|
|
25049
|
+
if (pendingDraftPromptRef.current?.ownerKey === draftSessionLoadingOwnerKey) flushPendingDraftPrompt(draftSessionLoadingOwnerKey, targetSessionKey);
|
|
23538
25050
|
}, [
|
|
23539
25051
|
draftSessionLoadingOwnerKey,
|
|
23540
25052
|
flushPendingDraftPrompt,
|
|
@@ -23632,6 +25144,41 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23632
25144
|
updatePendingMessages,
|
|
23633
25145
|
viewerContextId
|
|
23634
25146
|
]);
|
|
25147
|
+
const startPendingQueueMutation = useMutation({
|
|
25148
|
+
mutationFn: async () => {
|
|
25149
|
+
if (!viewerContextId) throw new Error("Viewer context unavailable");
|
|
25150
|
+
return await fetchJson(buildCurrentSessionRequestUrl("/api/pending-messages/start", {
|
|
25151
|
+
contextId: viewerContextId,
|
|
25152
|
+
sessionState: sessionStateRef.current,
|
|
25153
|
+
fallbackSessionId: activeSessionId
|
|
25154
|
+
}), { method: "POST" });
|
|
25155
|
+
},
|
|
25156
|
+
onSuccess: async () => {
|
|
25157
|
+
await queryClient.invalidateQueries({
|
|
25158
|
+
queryKey: picoQueryKeys.sessionTree(viewerContextId, picoSessionScopeKey(sessionStateRef.current)),
|
|
25159
|
+
refetchType: "active"
|
|
25160
|
+
});
|
|
25161
|
+
}
|
|
25162
|
+
});
|
|
25163
|
+
const startPendingQueue = import_react.useCallback(async () => {
|
|
25164
|
+
if (!viewerContextId) return;
|
|
25165
|
+
if (pendingMessagesRef.current.length === 0) return;
|
|
25166
|
+
setIsSubmitting(true);
|
|
25167
|
+
try {
|
|
25168
|
+
const nextPendingMessages = pendingMessagesFromResponse(await startPendingQueueMutation.mutateAsync());
|
|
25169
|
+
if (nextPendingMessages) updatePendingMessages(() => nextPendingMessages);
|
|
25170
|
+
} catch (error) {
|
|
25171
|
+
toast.error(error instanceof Error ? error.message : "Failed to start queue");
|
|
25172
|
+
} finally {
|
|
25173
|
+
setIsSubmitting(false);
|
|
25174
|
+
}
|
|
25175
|
+
}, [
|
|
25176
|
+
pendingMessagesRef,
|
|
25177
|
+
setIsSubmitting,
|
|
25178
|
+
startPendingQueueMutation,
|
|
25179
|
+
updatePendingMessages,
|
|
25180
|
+
viewerContextId
|
|
25181
|
+
]);
|
|
23635
25182
|
const removePendingMessageMutation = useMutation({
|
|
23636
25183
|
mutationFn: async (pendingId) => {
|
|
23637
25184
|
if (!viewerContextId) throw new Error("Viewer context unavailable");
|
|
@@ -23693,6 +25240,7 @@ function useAppShellPromptMutations({ viewerContextId, activeSessionId, defaultN
|
|
|
23693
25240
|
updatePendingMessages,
|
|
23694
25241
|
viewerContextId
|
|
23695
25242
|
]),
|
|
25243
|
+
startPendingQueue,
|
|
23696
25244
|
submitPrompt
|
|
23697
25245
|
};
|
|
23698
25246
|
}
|
|
@@ -24294,7 +25842,7 @@ function useAppShellSessionMutations({ viewerContextId, activeSessionId, session
|
|
|
24294
25842
|
});
|
|
24295
25843
|
return {
|
|
24296
25844
|
cycleThinkingLevel,
|
|
24297
|
-
deleteSessions: import_react.useCallback(
|
|
25845
|
+
deleteSessions: import_react.useCallback((targets) => {
|
|
24298
25846
|
if (!viewerContextId || targets.length === 0) return false;
|
|
24299
25847
|
const orderedTargets = [...targets.filter((target) => target.path && target.path !== sessionStateRef.current.sessionFile), ...targets.filter((target) => target.path && target.path === sessionStateRef.current.sessionFile)];
|
|
24300
25848
|
const orderedPaths = [];
|
|
@@ -24363,6 +25911,26 @@ function useAppShellSessionMutations({ viewerContextId, activeSessionId, session
|
|
|
24363
25911
|
}
|
|
24364
25912
|
var RESUME_RECONNECT_AFTER_MS = 3e4;
|
|
24365
25913
|
var COMPACT_WORKING_LABEL = "Compacting context...";
|
|
25914
|
+
var EVENT_SOURCE_LAST_ID_STORAGE_PREFIX = "pico-events-last-id:";
|
|
25915
|
+
function eventsLastIdStorageKey(viewerContextId) {
|
|
25916
|
+
return `${EVENT_SOURCE_LAST_ID_STORAGE_PREFIX}${viewerContextId}`;
|
|
25917
|
+
}
|
|
25918
|
+
function readStoredEventsLastId(viewerContextId) {
|
|
25919
|
+
try {
|
|
25920
|
+
return window.sessionStorage.getItem(eventsLastIdStorageKey(viewerContextId));
|
|
25921
|
+
} catch {
|
|
25922
|
+
return null;
|
|
25923
|
+
}
|
|
25924
|
+
}
|
|
25925
|
+
function rememberStoredEventsLastId(viewerContextId, lastEventId) {
|
|
25926
|
+
try {
|
|
25927
|
+
window.sessionStorage.setItem(eventsLastIdStorageKey(viewerContextId), lastEventId);
|
|
25928
|
+
} catch {}
|
|
25929
|
+
}
|
|
25930
|
+
function normalizeEventSourceLastId(value) {
|
|
25931
|
+
const normalized = typeof value === "string" ? value.trim() : "";
|
|
25932
|
+
return /^\d+$/.test(normalized) ? normalized : void 0;
|
|
25933
|
+
}
|
|
24366
25934
|
function normalizePendingMessages(payload) {
|
|
24367
25935
|
if (!isStateSyncEvent(payload)) return;
|
|
24368
25936
|
if (!Array.isArray(payload.pendingUserMessages)) return;
|
|
@@ -24376,6 +25944,9 @@ function normalizePendingMessages(payload) {
|
|
|
24376
25944
|
streamingBehavior: message.streamingBehavior === "steer" ? "steer" : "followUp"
|
|
24377
25945
|
}));
|
|
24378
25946
|
}
|
|
25947
|
+
function autoSessionNamingErrorDescription(payload) {
|
|
25948
|
+
return payload.refinementReason || payload.heuristicReason || payload.promptPreview || "The server could not generate a session name.";
|
|
25949
|
+
}
|
|
24379
25950
|
function sameStringArray(left = [], right = []) {
|
|
24380
25951
|
if (left.length !== right.length) return false;
|
|
24381
25952
|
for (let index = 0; index < left.length; index += 1) if (left[index] !== right[index]) return false;
|
|
@@ -24463,7 +26034,7 @@ function sameSessionsEvent(left, right) {
|
|
|
24463
26034
|
function visibleAssistantBlockKey(block, options) {
|
|
24464
26035
|
switch (block.type) {
|
|
24465
26036
|
case "text": return block.text.trim() ? `text:${block.text}` : "";
|
|
24466
|
-
case "compaction": return `compaction:${block.tokensBefore}:${block.summary}`;
|
|
26037
|
+
case "compaction": return `compaction:${block.tokensBefore}:${block.estimatedTokensAfter ?? ""}:${block.summary}`;
|
|
24467
26038
|
case "thinking": return options.hideThinking ? "" : `thinking:${block.summaryLabel || ""}:${block.text}`;
|
|
24468
26039
|
case "tool": return options.hideToolBlocks ? "" : `tool:${block.callId || ""}:${block.name || ""}:${JSON.stringify(block.args ?? null)}:${block.output}:${JSON.stringify(block.details ?? null)}:${block.isError ? "1" : "0"}:${block.running ? "1" : "0"}`;
|
|
24469
26040
|
default: return "";
|
|
@@ -24540,6 +26111,7 @@ function useAppShellSessionSync({ viewerContextId, sessionId, draftSessionLoadin
|
|
|
24540
26111
|
const currentSessionIdRef = import_react.useRef(sessionId);
|
|
24541
26112
|
const draftSessionLoadingOwnerKeyRef = import_react.useRef(draftSessionLoadingOwnerKey);
|
|
24542
26113
|
const currentSourceRef = import_react.useRef(null);
|
|
26114
|
+
const eventsLastIdRef = import_react.useRef(void 0);
|
|
24543
26115
|
const hasReceivedStateSyncRef = import_react.useRef(false);
|
|
24544
26116
|
const [hasReceivedStateSync, setHasReceivedStateSync] = import_react.useState(false);
|
|
24545
26117
|
const backgroundedAtRef = import_react.useRef(null);
|
|
@@ -24551,6 +26123,9 @@ function useAppShellSessionSync({ viewerContextId, sessionId, draftSessionLoadin
|
|
|
24551
26123
|
import_react.useEffect(() => {
|
|
24552
26124
|
draftSessionLoadingOwnerKeyRef.current = draftSessionLoadingOwnerKey;
|
|
24553
26125
|
}, [draftSessionLoadingOwnerKey]);
|
|
26126
|
+
import_react.useEffect(() => {
|
|
26127
|
+
eventsLastIdRef.current = normalizeEventSourceLastId(readStoredEventsLastId(viewerContextId));
|
|
26128
|
+
}, [viewerContextId]);
|
|
24554
26129
|
import_react.useEffect(() => {
|
|
24555
26130
|
if (currentSourceRef.current) return;
|
|
24556
26131
|
initialEventsSessionIdRef.current = sessionId;
|
|
@@ -24666,6 +26241,11 @@ function useAppShellSessionSync({ viewerContextId, sessionId, draftSessionLoadin
|
|
|
24666
26241
|
]);
|
|
24667
26242
|
const handleEventSourceMessage = import_react.useCallback((source, gitInvalidationBatcher, event) => {
|
|
24668
26243
|
if (currentSourceRef.current !== source) return;
|
|
26244
|
+
const lastEventId = normalizeEventSourceLastId(event.lastEventId);
|
|
26245
|
+
if (lastEventId) {
|
|
26246
|
+
eventsLastIdRef.current = lastEventId;
|
|
26247
|
+
rememberStoredEventsLastId(viewerContextId, lastEventId);
|
|
26248
|
+
}
|
|
24669
26249
|
const payload = JSON.parse(event.data);
|
|
24670
26250
|
if (isStateSyncEvent(payload)) {
|
|
24671
26251
|
const activationRevision = payload.activationRevision;
|
|
@@ -24764,6 +26344,11 @@ function useAppShellSessionSync({ viewerContextId, sessionId, draftSessionLoadin
|
|
|
24764
26344
|
});
|
|
24765
26345
|
return;
|
|
24766
26346
|
}
|
|
26347
|
+
if (payload.type === "auto_session_naming_error") {
|
|
26348
|
+
console.warn("[pico] auto session naming failed", payload);
|
|
26349
|
+
toast.warning("Could not name session", { description: autoSessionNamingErrorDescription(payload) });
|
|
26350
|
+
return;
|
|
26351
|
+
}
|
|
24767
26352
|
if (payload.type === "request_error") {
|
|
24768
26353
|
toast.error(payload.error || "Request failed");
|
|
24769
26354
|
return;
|
|
@@ -24804,7 +26389,8 @@ function useAppShellSessionSync({ viewerContextId, sessionId, draftSessionLoadin
|
|
|
24804
26389
|
setSessionDoneEvents,
|
|
24805
26390
|
setSessionState,
|
|
24806
26391
|
setSessionsEvent,
|
|
24807
|
-
setWorkingState
|
|
26392
|
+
setWorkingState,
|
|
26393
|
+
viewerContextId
|
|
24808
26394
|
]);
|
|
24809
26395
|
import_react.useEffect(() => {
|
|
24810
26396
|
if (!viewerContextId) return;
|
|
@@ -24856,7 +26442,10 @@ function useAppShellSessionSync({ viewerContextId, sessionId, draftSessionLoadin
|
|
|
24856
26442
|
const source = new EventSource(buildRequestUrl("/events", {
|
|
24857
26443
|
contextId: viewerContextId,
|
|
24858
26444
|
sessionId: initialEventsSessionIdRef.current,
|
|
24859
|
-
searchParams: {
|
|
26445
|
+
searchParams: {
|
|
26446
|
+
lastEventId: eventsLastIdRef.current,
|
|
26447
|
+
sidebarDirectory: bootstrapSidebarDirectories
|
|
26448
|
+
}
|
|
24860
26449
|
}));
|
|
24861
26450
|
currentSourceRef.current = source;
|
|
24862
26451
|
source.onopen = () => {
|
|
@@ -24941,10 +26530,13 @@ function useAppShellSessionSync({ viewerContextId, sessionId, draftSessionLoadin
|
|
|
24941
26530
|
]);
|
|
24942
26531
|
}
|
|
24943
26532
|
var DOUBLE_ESCAPE_INTERVAL_MS = 500;
|
|
26533
|
+
function isTerminalTarget(target) {
|
|
26534
|
+
return target instanceof HTMLElement && target.closest("[data-terminal-panel=\"true\"]") !== null;
|
|
26535
|
+
}
|
|
24944
26536
|
function isEditableTarget(target) {
|
|
24945
26537
|
if (!(target instanceof HTMLElement)) return false;
|
|
24946
26538
|
const tagName = target.tagName.toLowerCase();
|
|
24947
|
-
return target.isContentEditable || tagName === "input" || tagName === "textarea" || target.closest("[contenteditable=\"true\"]") !== null;
|
|
26539
|
+
return target.isContentEditable || isTerminalTarget(target) || tagName === "input" || tagName === "textarea" || target.closest("[contenteditable=\"true\"]") !== null;
|
|
24948
26540
|
}
|
|
24949
26541
|
function isPromptTextareaTarget(target) {
|
|
24950
26542
|
return target instanceof HTMLTextAreaElement && target.name === "prompt";
|
|
@@ -24984,7 +26576,7 @@ function useAppShellShortcuts({ addDirectoryOpenRef, commandPaletteOpenRef, comp
|
|
|
24984
26576
|
};
|
|
24985
26577
|
const handleEscape = (event) => {
|
|
24986
26578
|
const context = getShortcutContext(event);
|
|
24987
|
-
if (event.repeat || context.modalOpen || event.defaultPrevented) return;
|
|
26579
|
+
if (event.repeat || context.modalOpen || event.defaultPrevented || isTerminalTarget(event.target)) return;
|
|
24988
26580
|
const now = Date.now();
|
|
24989
26581
|
if (now - lastEscapeKeyDownAtRef.current <= DOUBLE_ESCAPE_INTERVAL_MS) {
|
|
24990
26582
|
lastEscapeKeyDownAtRef.current = 0;
|
|
@@ -25023,7 +26615,7 @@ function useAppShellShortcuts({ addDirectoryOpenRef, commandPaletteOpenRef, comp
|
|
|
25023
26615
|
};
|
|
25024
26616
|
const handleFocusPrompt = (event) => {
|
|
25025
26617
|
const context = getShortcutContext(event);
|
|
25026
|
-
if (context.blockingModalOpen || event.defaultPrevented) return;
|
|
26618
|
+
if (context.blockingModalOpen || event.defaultPrevented || isTerminalTarget(event.target)) return;
|
|
25027
26619
|
event.preventDefault();
|
|
25028
26620
|
closeCommandPaletteForShortcut(context.commandPaletteOpen);
|
|
25029
26621
|
shortcutActionsRef.current.focusPrompt();
|
|
@@ -25050,12 +26642,19 @@ function useAppShellShortcuts({ addDirectoryOpenRef, commandPaletteOpenRef, comp
|
|
|
25050
26642
|
const key = event.altKey && event.code.startsWith("Key") ? event.code.slice(3).toLowerCase() : event.key.toLowerCase();
|
|
25051
26643
|
const context = getShortcutContext(event);
|
|
25052
26644
|
if (context.blockingModalOpen || event.defaultPrevented) return;
|
|
26645
|
+
if (isTerminalTarget(event.target) && !context.commandPaletteOpen && key !== "`") return;
|
|
25053
26646
|
if (key === "\\") {
|
|
25054
26647
|
event.preventDefault();
|
|
25055
26648
|
closeCommandPaletteForShortcut(context.commandPaletteOpen);
|
|
25056
26649
|
shortcutActionsRef.current.toggleGitPanel();
|
|
25057
26650
|
return;
|
|
25058
26651
|
}
|
|
26652
|
+
if (key === "`") {
|
|
26653
|
+
event.preventDefault();
|
|
26654
|
+
closeCommandPaletteForShortcut(context.commandPaletteOpen);
|
|
26655
|
+
shortcutActionsRef.current.toggleTerminalPanel();
|
|
26656
|
+
return;
|
|
26657
|
+
}
|
|
25059
26658
|
if (key === "k") {
|
|
25060
26659
|
event.preventDefault();
|
|
25061
26660
|
shortcutActionsRef.current.openCommandPalette();
|
|
@@ -25227,6 +26826,7 @@ function useAppShellShortcuts({ addDirectoryOpenRef, commandPaletteOpenRef, comp
|
|
|
25227
26826
|
})),
|
|
25228
26827
|
...[
|
|
25229
26828
|
{ key: "\\" },
|
|
26829
|
+
{ key: "`" },
|
|
25230
26830
|
{ key: "K" },
|
|
25231
26831
|
{ key: "P" },
|
|
25232
26832
|
{
|
|
@@ -25295,6 +26895,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
25295
26895
|
if (!appUiStoreRef.current) appUiStoreRef.current = createPicoStore({
|
|
25296
26896
|
currentTab: "session",
|
|
25297
26897
|
gitPanelOpen: false,
|
|
26898
|
+
terminalPanelOpen: false,
|
|
25298
26899
|
initialLoadingSessionId: sessionId || null,
|
|
25299
26900
|
loadingSessionId: null
|
|
25300
26901
|
}, shallowRecordEqual);
|
|
@@ -25310,6 +26911,11 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
25310
26911
|
setStoreField(appUiStore, "gitPanelOpen", nextOpen);
|
|
25311
26912
|
safeLocalStorageSetItem(RIGHT_SIDEBAR_OPEN_STORAGE_KEY, nextOpen ? "1" : "0");
|
|
25312
26913
|
}, [appUiStore]);
|
|
26914
|
+
const setTerminalPanelOpen = import_react.useCallback((action) => {
|
|
26915
|
+
const nextOpen = applyStoreAction(appUiStore.state.terminalPanelOpen, action);
|
|
26916
|
+
setStoreField(appUiStore, "terminalPanelOpen", nextOpen);
|
|
26917
|
+
safeLocalStorageSetItem(TERMINAL_PANEL_OPEN_STORAGE_KEY, nextOpen ? "1" : "0");
|
|
26918
|
+
}, [appUiStore]);
|
|
25313
26919
|
const setLoadingSessionId = import_react.useCallback((action) => {
|
|
25314
26920
|
setStoreField(appUiStore, "loadingSessionId", action);
|
|
25315
26921
|
}, [appUiStore]);
|
|
@@ -25735,6 +27341,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
25735
27341
|
sessionKey: currentSessionState.sessionKey
|
|
25736
27342
|
}), { compare: shallowRecordEqual });
|
|
25737
27343
|
const gitPanelOpen = useSelector(appUiStore, (state) => state.gitPanelOpen);
|
|
27344
|
+
const terminalPanelOpen = useSelector(appUiStore, (state) => state.terminalPanelOpen);
|
|
25738
27345
|
const openFileViewTab = (path, options) => {
|
|
25739
27346
|
if (!path) return;
|
|
25740
27347
|
batch(() => {
|
|
@@ -25831,7 +27438,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
25831
27438
|
} : currentSession : { draft: true }, sessionId);
|
|
25832
27439
|
setStoreState(appUiStore, (current) => ({
|
|
25833
27440
|
...current,
|
|
25834
|
-
currentTab: current.currentTab === "git" ? "session" : current.currentTab,
|
|
27441
|
+
currentTab: current.currentTab === "git" || current.currentTab === "terminal" ? "session" : current.currentTab,
|
|
25835
27442
|
initialLoadingSessionId: sessionId ? current.initialLoadingSessionId : null,
|
|
25836
27443
|
loadingSessionId: sessionId && sessionStateRef.current.sessionId !== sessionId ? sessionId : null
|
|
25837
27444
|
}));
|
|
@@ -25843,7 +27450,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
25843
27450
|
]);
|
|
25844
27451
|
import_react.useEffect(() => {
|
|
25845
27452
|
if (isMobile) return;
|
|
25846
|
-
setCurrentTab((tab) => tab === "git" ? "session" : tab);
|
|
27453
|
+
setCurrentTab((tab) => tab === "git" || tab === "terminal" ? "session" : tab);
|
|
25847
27454
|
}, [isMobile, setCurrentTab]);
|
|
25848
27455
|
const syncComposerDraft = (value, target = sessionStateRef.current) => {
|
|
25849
27456
|
const parsed = parseComposerSkillMessage(value);
|
|
@@ -25887,6 +27494,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
25887
27494
|
const applyStoredClientPreferences = () => {
|
|
25888
27495
|
batch(() => {
|
|
25889
27496
|
setGitPanelOpen(readStoredRightSidebarOpen());
|
|
27497
|
+
setTerminalPanelOpen(readStoredTerminalPanelOpen());
|
|
25890
27498
|
setStoredDraftDirectory(readStoredDraftDirectory() || "");
|
|
25891
27499
|
setSessionDoneSoundEnabled(readStoredSessionDoneSoundEnabled());
|
|
25892
27500
|
setSessionDoneDesktopNotificationsEnabled(readStoredSessionDoneDesktopNotificationsEnabled());
|
|
@@ -26050,12 +27658,27 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
26050
27658
|
}
|
|
26051
27659
|
setGitPanelOpen((open) => !open);
|
|
26052
27660
|
};
|
|
27661
|
+
const toggleTerminalPanel = () => {
|
|
27662
|
+
if (isMobile) {
|
|
27663
|
+
setCurrentTab((tab) => tab === "terminal" ? "session" : "terminal");
|
|
27664
|
+
return;
|
|
27665
|
+
}
|
|
27666
|
+
setTerminalPanelOpen((open) => !open);
|
|
27667
|
+
};
|
|
27668
|
+
const closeTerminalPanel = () => {
|
|
27669
|
+
if (isMobile) {
|
|
27670
|
+
setCurrentTab((tab) => tab === "terminal" ? "session" : tab);
|
|
27671
|
+
return;
|
|
27672
|
+
}
|
|
27673
|
+
setTerminalPanelOpen(false);
|
|
27674
|
+
};
|
|
26053
27675
|
const openRenameDialog = () => {
|
|
26054
27676
|
const currentState = sessionStateRef.current;
|
|
26055
27677
|
if (!currentState.sessionFile) return;
|
|
26056
27678
|
renameDialogRef.current?.open({
|
|
26057
27679
|
path: currentState.sessionFile,
|
|
26058
|
-
title: currentState.sessionName || getCurrentSessionTitleFromState(currentState)
|
|
27680
|
+
title: currentState.sessionName || getCurrentSessionTitleFromState(currentState),
|
|
27681
|
+
hasGeneratedName: Boolean(currentState.sessionName?.trim())
|
|
26059
27682
|
});
|
|
26060
27683
|
};
|
|
26061
27684
|
const openRenameDialogForEntry = (entry) => {
|
|
@@ -26448,7 +28071,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
26448
28071
|
const pendingDraftPrompt = pendingDraftPromptStore.state;
|
|
26449
28072
|
const pendingDraftFollowUps = pendingDraftFollowUpsStore.state;
|
|
26450
28073
|
const pendingMessages = pendingMessagesStore.state;
|
|
26451
|
-
const { abortSession, addDirectoryPath, createSession: requestCreateSession, editPendingMessage, removePendingMessage, reorderPending, submitPrompt } = useAppShellPromptMutations({
|
|
28074
|
+
const { abortSession, addDirectoryPath, createSession: requestCreateSession, editPendingMessage, removePendingMessage, reorderPending, startPendingQueue, submitPrompt } = useAppShellPromptMutations({
|
|
26452
28075
|
viewerContextId,
|
|
26453
28076
|
activeSessionId,
|
|
26454
28077
|
defaultNewSessionDirectory,
|
|
@@ -26528,10 +28151,6 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
26528
28151
|
const createSessionPromise = requestCreateSession(nextCwd);
|
|
26529
28152
|
handleSelectSession(void 0);
|
|
26530
28153
|
clearSelectedSidebarSelection();
|
|
26531
|
-
if (shouldCloseMobileSidebar) {
|
|
26532
|
-
pendingMobileSidebarPromptFocusRef.current = true;
|
|
26533
|
-
setOpenMobile(false);
|
|
26534
|
-
} else focusPrompt();
|
|
26535
28154
|
setAwaitingFirstTurn(false);
|
|
26536
28155
|
setPendingMessages((current) => current.length === 0 ? current : []);
|
|
26537
28156
|
const nextState = createOptimisticDraftSessionState({
|
|
@@ -26542,6 +28161,10 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
26542
28161
|
sessionStateRef.current = nextState;
|
|
26543
28162
|
conversationItemsStore.setItems(nextState.items);
|
|
26544
28163
|
setSessionState(nextState);
|
|
28164
|
+
if (shouldCloseMobileSidebar) {
|
|
28165
|
+
pendingMobileSidebarPromptFocusRef.current = true;
|
|
28166
|
+
setOpenMobile(false);
|
|
28167
|
+
} else focusPrompt();
|
|
26545
28168
|
if (await createSessionPromise) return;
|
|
26546
28169
|
if (sessionStateRef.current.sessionKey !== optimisticSessionKey) return;
|
|
26547
28170
|
sessionStateRef.current = previousState;
|
|
@@ -26887,6 +28510,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
26887
28510
|
const composerSnapshot = {
|
|
26888
28511
|
activeSessionId,
|
|
26889
28512
|
awaitingFirstTurn: composerDisabled ? false : awaitingFirstTurn,
|
|
28513
|
+
canStartPendingQueue: !composerDisabled && pendingMessages.length > 0 && !sessionStateRef.current.streaming && !sessionStateRef.current.compacting && !awaitingFirstTurn && !isSubmitting,
|
|
26890
28514
|
centerMessages: displaySettingsRef.current.centerMessages,
|
|
26891
28515
|
composerDiffLineComments: displayedDiffLineComments,
|
|
26892
28516
|
composerImages: displayedComposerImages,
|
|
@@ -26895,6 +28519,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
26895
28519
|
composerText: displayedComposerText,
|
|
26896
28520
|
currentPendingMessages: displayedPendingMessages,
|
|
26897
28521
|
disabled: composerDisabled,
|
|
28522
|
+
isCompacting: composerDisabled ? false : sessionStateRef.current.compacting,
|
|
26898
28523
|
isStreaming: composerDisabled ? false : sessionStateRef.current.streaming,
|
|
26899
28524
|
isSubmitting: composerDisabled ? false : isSubmitting,
|
|
26900
28525
|
viewerContextId
|
|
@@ -26917,6 +28542,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
26917
28542
|
removePendingMessage,
|
|
26918
28543
|
reorderPending,
|
|
26919
28544
|
reorderPendingDraftFollowUp,
|
|
28545
|
+
startPendingQueue,
|
|
26920
28546
|
runBuiltinSlashCommand,
|
|
26921
28547
|
setModel,
|
|
26922
28548
|
setThinkingLevel,
|
|
@@ -26928,7 +28554,8 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
26928
28554
|
hasAvailableModels: sessionStateRef.current.availableModels.length > 0,
|
|
26929
28555
|
isMobile,
|
|
26930
28556
|
selectedSidebarSessions,
|
|
26931
|
-
sessionFile: sessionState.sessionFile
|
|
28557
|
+
sessionFile: sessionState.sessionFile,
|
|
28558
|
+
terminalPanelOpen
|
|
26932
28559
|
});
|
|
26933
28560
|
const buildCommandPaletteCommands = () => {
|
|
26934
28561
|
const commandState = commandPaletteStateRef.current;
|
|
@@ -26979,6 +28606,21 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
26979
28606
|
],
|
|
26980
28607
|
onSelect: toggleGitPanel
|
|
26981
28608
|
},
|
|
28609
|
+
{
|
|
28610
|
+
id: "toggle-terminal",
|
|
28611
|
+
group: "Workspace",
|
|
28612
|
+
title: commandState.isMobile ? "Toggle terminal tab" : commandState.terminalPanelOpen ? "Close terminal" : "Open terminal",
|
|
28613
|
+
description: commandState.isMobile ? "Switch the mobile terminal tab on or off" : "Toggle the bottom terminal panel",
|
|
28614
|
+
shortcut: formatShortcutLabel("Control+`"),
|
|
28615
|
+
keywords: [
|
|
28616
|
+
"terminal",
|
|
28617
|
+
"shell",
|
|
28618
|
+
"console",
|
|
28619
|
+
"bottom",
|
|
28620
|
+
"panel"
|
|
28621
|
+
],
|
|
28622
|
+
onSelect: toggleTerminalPanel
|
|
28623
|
+
},
|
|
26982
28624
|
{
|
|
26983
28625
|
id: "commit-changes",
|
|
26984
28626
|
group: "Git",
|
|
@@ -27343,6 +28985,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
27343
28985
|
conversationFrameRef.current?.scrollConversationToTop();
|
|
27344
28986
|
},
|
|
27345
28987
|
toggleGitPanel,
|
|
28988
|
+
toggleTerminalPanel,
|
|
27346
28989
|
toggleHideThinking,
|
|
27347
28990
|
toggleHideToolBlocks,
|
|
27348
28991
|
cycleThinkingLevel
|
|
@@ -27483,12 +29126,14 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
27483
29126
|
defaultNewSessionDirectory,
|
|
27484
29127
|
displaySessionCwd,
|
|
27485
29128
|
gitPanelOpen,
|
|
29129
|
+
terminalPanelOpen,
|
|
27486
29130
|
loadingDisplaySessionTitle,
|
|
27487
29131
|
currentSessionPinned,
|
|
27488
29132
|
displaySettingsStore,
|
|
27489
29133
|
isSessionViewLoading,
|
|
27490
29134
|
newSessionDirectoryOptions,
|
|
27491
29135
|
onToggleGitPanel: toggleGitPanel,
|
|
29136
|
+
onToggleTerminalPanel: toggleTerminalPanel,
|
|
27492
29137
|
sessionStore,
|
|
27493
29138
|
viewerContextId
|
|
27494
29139
|
}),
|
|
@@ -27508,6 +29153,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
27508
29153
|
displaySettingsStore,
|
|
27509
29154
|
fileInputRef,
|
|
27510
29155
|
gitPanelOpen,
|
|
29156
|
+
terminalPanelOpen,
|
|
27511
29157
|
hiddenThinkingPreviewStore,
|
|
27512
29158
|
isSessionViewLoading,
|
|
27513
29159
|
isSubmitting,
|
|
@@ -27525,6 +29171,7 @@ function useAppShellSessionWorkspaceView({ viewerContextId, sessionId, onSelectS
|
|
|
27525
29171
|
onAddDiffLineComment: addComposerDiffLineComment,
|
|
27526
29172
|
onOpenFileViewTab: openFileViewTab,
|
|
27527
29173
|
onReorderFileViewTabs: reorderFileViewTabs,
|
|
29174
|
+
onCloseTerminalPanel: closeTerminalPanel,
|
|
27528
29175
|
rightSidebarStore,
|
|
27529
29176
|
sessionStore,
|
|
27530
29177
|
store: composerStore,
|