@oversk7/pi-web-dsh-style 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/THIRD_PARTY_NOTICES.md +32 -3
- package/package.json +4 -1
- package/server.ts +194 -18
- package/web/app.css +9 -1
- package/web/app.js +16 -4
- package/web/assets/fonts/KaTeX_AMS-Regular.ttf +0 -0
- package/web/assets/fonts/KaTeX_AMS-Regular.woff +0 -0
- package/web/assets/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
- package/web/assets/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
- package/web/assets/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
- package/web/assets/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
- package/web/assets/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
- package/web/assets/fonts/KaTeX_Fraktur-Bold.woff +0 -0
- package/web/assets/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
- package/web/assets/fonts/KaTeX_Fraktur-Regular.woff +0 -0
- package/web/assets/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Main-Bold.ttf +0 -0
- package/web/assets/fonts/KaTeX_Main-Bold.woff +0 -0
- package/web/assets/fonts/KaTeX_Main-Bold.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
- package/web/assets/fonts/KaTeX_Main-BoldItalic.woff +0 -0
- package/web/assets/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Main-Italic.ttf +0 -0
- package/web/assets/fonts/KaTeX_Main-Italic.woff +0 -0
- package/web/assets/fonts/KaTeX_Main-Italic.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Main-Regular.ttf +0 -0
- package/web/assets/fonts/KaTeX_Main-Regular.woff +0 -0
- package/web/assets/fonts/KaTeX_Main-Regular.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
- package/web/assets/fonts/KaTeX_Math-BoldItalic.woff +0 -0
- package/web/assets/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Math-Italic.ttf +0 -0
- package/web/assets/fonts/KaTeX_Math-Italic.woff +0 -0
- package/web/assets/fonts/KaTeX_Math-Italic.woff2 +0 -0
- package/web/assets/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
- package/web/assets/fonts/KaTeX_SansSerif-Bold.woff +0 -0
- package/web/assets/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/web/assets/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
- package/web/assets/fonts/KaTeX_SansSerif-Italic.woff +0 -0
- package/web/assets/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/web/assets/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
- package/web/assets/fonts/KaTeX_SansSerif-Regular.woff +0 -0
- package/web/assets/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Script-Regular.ttf +0 -0
- package/web/assets/fonts/KaTeX_Script-Regular.woff +0 -0
- package/web/assets/fonts/KaTeX_Script-Regular.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Size1-Regular.ttf +0 -0
- package/web/assets/fonts/KaTeX_Size1-Regular.woff +0 -0
- package/web/assets/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Size2-Regular.ttf +0 -0
- package/web/assets/fonts/KaTeX_Size2-Regular.woff +0 -0
- package/web/assets/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Size3-Regular.ttf +0 -0
- package/web/assets/fonts/KaTeX_Size3-Regular.woff +0 -0
- package/web/assets/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Size4-Regular.ttf +0 -0
- package/web/assets/fonts/KaTeX_Size4-Regular.woff +0 -0
- package/web/assets/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- package/web/assets/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
- package/web/assets/fonts/KaTeX_Typewriter-Regular.woff +0 -0
- package/web/assets/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/web/assets/katex.min.css +1 -0
- package/web/assets/markdown.LICENSE.txt +78 -0
- package/web/assets/markdown.js +536 -21
- package/web/assets/mermaid/chunks/abnfDiagram-YUKMZFIV-FZYDJU67.js +1 -0
- package/web/assets/mermaid/chunks/architecture-WOLXFQ4H-BZVX64AA.js +1 -0
- package/web/assets/mermaid/chunks/architectureDiagram-47P4ROYG-2BMC2Z7S.js +36 -0
- package/web/assets/mermaid/chunks/blockDiagram-E7TT5TSB-FH6ZULKF.js +140 -0
- package/web/assets/mermaid/chunks/c4Diagram-CRA5TL53-OG62EAHM.js +38 -0
- package/web/assets/mermaid/chunks/chunk-22D53RF2.js +2 -0
- package/web/assets/mermaid/chunks/chunk-25KVF5ZE.js +1 -0
- package/web/assets/mermaid/chunks/chunk-4HYFSIZT.js +1 -0
- package/web/assets/mermaid/chunks/chunk-4W4OQ3QY.js +1 -0
- package/web/assets/mermaid/chunks/chunk-5TQRX2ND.js +1 -0
- package/web/assets/mermaid/chunks/chunk-64OFLKGX.js +322 -0
- package/web/assets/mermaid/chunks/chunk-64OFLKGX.js.LEGAL.txt +17 -0
- package/web/assets/mermaid/chunks/chunk-6UFWKTSA.js +1 -0
- package/web/assets/mermaid/chunks/chunk-6ZAAIG6Q.js +10 -0
- package/web/assets/mermaid/chunks/chunk-76QEHT4T.js +1 -0
- package/web/assets/mermaid/chunks/chunk-A7665WVC.js +1 -0
- package/web/assets/mermaid/chunks/chunk-AECJS4LP.js +130 -0
- package/web/assets/mermaid/chunks/chunk-AECJS4LP.js.LEGAL.txt +5 -0
- package/web/assets/mermaid/chunks/chunk-ATQQWCXO.js +2 -0
- package/web/assets/mermaid/chunks/chunk-DQVO43GU.js +1 -0
- package/web/assets/mermaid/chunks/chunk-DSKRGV6V.js +1 -0
- package/web/assets/mermaid/chunks/chunk-EIBFAW37.js +1 -0
- package/web/assets/mermaid/chunks/chunk-FBC3PYSO.js +1 -0
- package/web/assets/mermaid/chunks/chunk-FQ5IIL54.js +88 -0
- package/web/assets/mermaid/chunks/chunk-GZYY6JMP.js +1 -0
- package/web/assets/mermaid/chunks/chunk-HIGPS4L2.js +1 -0
- package/web/assets/mermaid/chunks/chunk-HP75Y56I.js +2 -0
- package/web/assets/mermaid/chunks/chunk-JRAHLUQM.js +32 -0
- package/web/assets/mermaid/chunks/chunk-KNYDPLLK.js +1 -0
- package/web/assets/mermaid/chunks/chunk-L465623K.js +136 -0
- package/web/assets/mermaid/chunks/chunk-L7BMR7WL.js +1 -0
- package/web/assets/mermaid/chunks/chunk-LLGPMHB6.js +1 -0
- package/web/assets/mermaid/chunks/chunk-NBH7YOBD.js +15 -0
- package/web/assets/mermaid/chunks/chunk-NCOVM3YF.js +1 -0
- package/web/assets/mermaid/chunks/chunk-PHKIAKHS.js +1 -0
- package/web/assets/mermaid/chunks/chunk-PM2IFX5O.js +1 -0
- package/web/assets/mermaid/chunks/chunk-PN62QGJW.js +72 -0
- package/web/assets/mermaid/chunks/chunk-QHMFFOZZ.js +1 -0
- package/web/assets/mermaid/chunks/chunk-QQZBUVKZ.js +1 -0
- package/web/assets/mermaid/chunks/chunk-RV7WQMNL.js +1 -0
- package/web/assets/mermaid/chunks/chunk-STBOPOHX.js +1 -0
- package/web/assets/mermaid/chunks/chunk-T3FZWEYV.js +1 -0
- package/web/assets/mermaid/chunks/chunk-TMMWB6NQ.js +1 -0
- package/web/assets/mermaid/chunks/chunk-TPW5CADB.js +1 -0
- package/web/assets/mermaid/chunks/chunk-TSOLLCID.js +2 -0
- package/web/assets/mermaid/chunks/chunk-TWGPYWIY.js +1 -0
- package/web/assets/mermaid/chunks/chunk-WGMEMLED.js +1 -0
- package/web/assets/mermaid/chunks/chunk-XC2LKMMW.js +1 -0
- package/web/assets/mermaid/chunks/chunk-XHVVPFJ5.js +1 -0
- package/web/assets/mermaid/chunks/chunk-YIN5CSIF.js +2 -0
- package/web/assets/mermaid/chunks/chunk-YIN5CSIF.js.LEGAL.txt +12 -0
- package/web/assets/mermaid/chunks/chunk-YORIST7Z.js +1 -0
- package/web/assets/mermaid/chunks/chunk-YPXVLPXW.js +3 -0
- package/web/assets/mermaid/chunks/chunk-Z4WODCD2.js +213 -0
- package/web/assets/mermaid/chunks/chunk-ZAERIUBF.js +1 -0
- package/web/assets/mermaid/chunks/chunk-ZDOBOOWG.js +62 -0
- package/web/assets/mermaid/chunks/classDiagram-v2-K4WV4PDN-HXQD675C.js +217 -0
- package/web/assets/mermaid/chunks/cose-bilkent-JH36ORCC-3VHNHM7I.js +1 -0
- package/web/assets/mermaid/chunks/cynefin-EF2NZ3EQ-ZO5PPXJG.js +1 -0
- package/web/assets/mermaid/chunks/cynefinDiagram-3GCD6N5R-LFWDWE4E.js +62 -0
- package/web/assets/mermaid/chunks/dagre-W4DXFKR2-SDBBVBGG.js +4 -0
- package/web/assets/mermaid/chunks/diagram-2UJZ2QOL-YCKW3WNJ.js +200 -0
- package/web/assets/mermaid/chunks/diagram-OVF4WLC6-62NNPE34.js +24 -0
- package/web/assets/mermaid/chunks/diagram-PFPMY2P6-7RR2GTZ5.js +30 -0
- package/web/assets/mermaid/chunks/diagram-UMYRVEAY-Q4I25SMR.js +24 -0
- package/web/assets/mermaid/chunks/diagram-YEKJPTXX-VNUTOPRK.js +41 -0
- package/web/assets/mermaid/chunks/diagram-ZIFT7M5P-KALXX5CE.js +3 -0
- package/web/assets/mermaid/chunks/ebnfDiagram-VR2GEFS7-WIFBISHL.js +1 -0
- package/web/assets/mermaid/chunks/elk-IJKZMXRS-LGG232IL.js +27 -0
- package/web/assets/mermaid/chunks/erDiagram-O2IAPWRE-KWX2J2TX.js +99 -0
- package/web/assets/mermaid/chunks/eventmodeling-K75KTNOO-3JNV4VSP.js +1 -0
- package/web/assets/mermaid/chunks/flowDiagram-OXPTDLAJ-CUMOBDC3.js +1 -0
- package/web/assets/mermaid/chunks/ganttDiagram-R7TSEDQI-GCS3MRFX.js +292 -0
- package/web/assets/mermaid/chunks/gitGraph-VSP46ZUC-HSAXKLAG.js +1 -0
- package/web/assets/mermaid/chunks/gitGraphDiagram-XJZIOB7I-FB763ROZ.js +106 -0
- package/web/assets/mermaid/chunks/info-OHQRW6UA-C4R2B34T.js +1 -0
- package/web/assets/mermaid/chunks/infoDiagram-5W2HQ5XZ-XCQU5T5D.js +2 -0
- package/web/assets/mermaid/chunks/ishikawaDiagram-K3B6WC7H-UWYT66G7.js +70 -0
- package/web/assets/mermaid/chunks/journeyDiagram-COXZFDF6-DOW66RYW.js +139 -0
- package/web/assets/mermaid/chunks/kanban-definition-P3RFRI5V-K55BXDLO.js +89 -0
- package/web/assets/mermaid/chunks/katex-5AUD5AJN.js +257 -0
- package/web/assets/mermaid/chunks/mindmap-definition-LZFPQGKD-WG3FIZ5U.js +96 -0
- package/web/assets/mermaid/chunks/packet-JDAUHWVQ-SFUSDIUN.js +1 -0
- package/web/assets/mermaid/chunks/pegDiagram-BGZESJAR-MQOH3WII.js +1 -0
- package/web/assets/mermaid/chunks/pie-XZMESJXO-M76QC4CD.js +1 -0
- package/web/assets/mermaid/chunks/pieDiagram-CAPJLFHJ-V3WNR4Y2.js +39 -0
- package/web/assets/mermaid/chunks/quadrantDiagram-GDMTTRAM-DJLTATHS.js +7 -0
- package/web/assets/mermaid/chunks/radar-ABXABTNO-HSBJ6SSD.js +1 -0
- package/web/assets/mermaid/chunks/railroad-I3PHUGI6-4QJMJ7LG.js +1 -0
- package/web/assets/mermaid/chunks/railroad-abnf-LNEFI6M7-ZLNZ5ZRH.js +1 -0
- package/web/assets/mermaid/chunks/railroad-ebnf-DWYD2UWJ-EBV6ZOUW.js +1 -0
- package/web/assets/mermaid/chunks/railroad-peg-JR7BVNR7-X3E47TO7.js +1 -0
- package/web/assets/mermaid/chunks/railroadDiagram-SM67HX2B-ZHEERYJS.js +1 -0
- package/web/assets/mermaid/chunks/requirementDiagram-X7JNWC4A-TVHJNPPI.js +84 -0
- package/web/assets/mermaid/chunks/sankeyDiagram-UM26HJRW-FXHWY3MM.js +40 -0
- package/web/assets/mermaid/chunks/sequenceDiagram-ZO4K6R2Y-OP7DCVPK.js +169 -0
- package/web/assets/mermaid/chunks/sizeCapture-INFHLROL-2GUJIKNX.js +1 -0
- package/web/assets/mermaid/chunks/stateDiagram-v2-TBUQTH76-R26D6XHK.js +291 -0
- package/web/assets/mermaid/chunks/swimlanes-N4OXWK64-FPGACWHE.js +1 -0
- package/web/assets/mermaid/chunks/swimlanesDiagram-K3J5GTZL-YMNX34Q2.js +8 -0
- package/web/assets/mermaid/chunks/timeline-definition-YOQAKGHF-R2U2UR4K.js +120 -0
- package/web/assets/mermaid/chunks/treeView-D4JQ5SDB-3BQHZUCI.js +1 -0
- package/web/assets/mermaid/chunks/treemap-SAJKECNS-6NJPJ5NM.js +1 -0
- package/web/assets/mermaid/chunks/usecaseDiagram-VIAY4XPW-BCEIGXDX.js +370 -0
- package/web/assets/mermaid/chunks/vennDiagram-BLWOH2XV-DOV5W2IV.js +34 -0
- package/web/assets/mermaid/chunks/wardley-7MLQ67FV-ITOM4KQ2.js +1 -0
- package/web/assets/mermaid/chunks/wardleyDiagram-YMQ3BMBF-CGJ7AG4L.js +78 -0
- package/web/assets/mermaid/chunks/xychartDiagram-TAQBALBS-2MTP7IBV.js +7 -0
- package/web/assets/mermaid/mermaid.js +11 -0
- package/web/assets/mermaid/mermaid.js.LEGAL.txt +7 -0
- package/web/index.html +1 -0
- package/web/markdown-diagrams.js +147 -0
- package/web/markdown.ts +50 -4
- package/web/slash-commands.js +1 -0
- package/web/themes.css +46 -0
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ A browser interface for [Pi Coding Agent](https://pi.dev), inspired by DeepSeek
|
|
|
16
16
|
|
|
17
17
|
## English
|
|
18
18
|
|
|
19
|
-
Pi Web brings your Pi sessions to desktop and mobile browsers. Run multiple workspaces and sessions, inspect streaming replies and tool calls, preview files, revisit conversation branches, and use models, slash commands, extensions and skills. Pi and its tools keep running on your own computer. Choose light or dark themes and a custom chat background.
|
|
19
|
+
Pi Web brings your Pi sessions to desktop and mobile browsers. Run multiple workspaces and sessions, inspect streaming replies and tool calls, preview files, revisit conversation branches, and use models, slash commands, extensions and skills. Pi and its tools keep running on your own computer. Choose light or dark themes and a custom chat background. Replies and Markdown file previews render mathematical formulas and Mermaid diagrams, with diagram modules loaded on demand.
|
|
20
20
|
|
|
21
21
|
### Requirements
|
|
22
22
|
|
|
@@ -61,7 +61,7 @@ npm run verify
|
|
|
61
61
|
|
|
62
62
|
## 简体中文
|
|
63
63
|
|
|
64
|
-
Pi Web 为 [Pi Coding Agent](https://pi.dev) 提供浏览器界面,灵感来自 DeepSeek Harness。在桌面或手机上切换多个工作区与会话,查看流式回答、工具调用和文件预览,浏览会话分支,并使用模型、斜杠命令、扩展与技能。Pi
|
|
64
|
+
Pi Web 为 [Pi Coding Agent](https://pi.dev) 提供浏览器界面,灵感来自 DeepSeek Harness。在桌面或手机上切换多个工作区与会话,查看流式回答、工具调用和文件预览,浏览会话分支,并使用模型、斜杠命令、扩展与技能。Pi 和工具仍运行在自己的电脑上。支持明暗主题和自定义聊天背景。回答和 Markdown 文件预览支持数学公式与 Mermaid 图表,图表模块按需加载。
|
|
65
65
|
|
|
66
66
|
### 系统要求
|
|
67
67
|
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
This package contains adapted web UI styles and bundled font assets from the
|
|
4
4
|
projects below. Their licenses are reproduced here as required.
|
|
5
5
|
|
|
6
|
-
The browser Markdown renderer
|
|
7
|
-
|
|
8
|
-
`web/assets/markdown.LICENSE.txt
|
|
6
|
+
The browser Markdown renderer bundles markdown-it, highlight.js, KaTeX,
|
|
7
|
+
markdown-it-texmath, and Mermaid. Their license texts are included in
|
|
8
|
+
`web/assets/markdown.LICENSE.txt`. Mermaid dependency notices are also included
|
|
9
|
+
alongside the entry and chunks under `web/assets/mermaid/` as `.LEGAL.txt` files.
|
|
9
10
|
|
|
10
11
|
## DeepSeek Harness
|
|
11
12
|
|
|
@@ -92,3 +93,31 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
|
92
93
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
93
94
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
94
95
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
96
|
+
|
|
97
|
+
## Oh Pi Themes — Tokyo Night
|
|
98
|
+
|
|
99
|
+
Source: https://github.com/ifiokjr/oh-pi/tree/main/packages/themes
|
|
100
|
+
|
|
101
|
+
The chat palette in `web/themes.css` adapts the Tokyo Night semantic colors.
|
|
102
|
+
|
|
103
|
+
MIT License
|
|
104
|
+
|
|
105
|
+
Copyright (c) 2025 Ifiok Jr.
|
|
106
|
+
|
|
107
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
108
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
109
|
+
in the Software without restriction, including without limitation the rights
|
|
110
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
111
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
112
|
+
furnished to do so, subject to the following conditions:
|
|
113
|
+
|
|
114
|
+
The above copyright notice and this permission notice shall be included in all
|
|
115
|
+
copies or substantial portions of the Software.
|
|
116
|
+
|
|
117
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
118
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
119
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
120
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
121
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
122
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
123
|
+
SOFTWARE.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oversk7/pi-web-dsh-style",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3",
|
|
4
4
|
"description": "An unofficial DSH-styled Windows browser UI for pi coding agent with configurable LAN and native frp relay access",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -87,7 +87,10 @@
|
|
|
87
87
|
"fast-xml-parser": "^5.11.1",
|
|
88
88
|
"fflate": "^0.8.3",
|
|
89
89
|
"highlight.js": "^11.12.0",
|
|
90
|
+
"katex": "^0.19.0",
|
|
90
91
|
"markdown-it": "^15.0.2",
|
|
92
|
+
"markdown-it-texmath": "^1.0.0",
|
|
93
|
+
"mermaid": "^12.1.0",
|
|
91
94
|
"pdfjs-dist": "^6.3.289"
|
|
92
95
|
}
|
|
93
96
|
}
|
package/server.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type { ServerResponse } from "node:http";
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
2
|
import { createServer } from "node:http";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
|
-
import { randomUUID } from "node:crypto";
|
|
4
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import { brotliCompress, constants as zlibConstants, gzip } from "node:zlib";
|
|
5
7
|
import { existsSync } from "node:fs";
|
|
6
8
|
import { chmod, mkdir, mkdtemp, readFile, readdir, rm, stat, unlink } from "node:fs/promises";
|
|
7
9
|
import { homedir, platform, tmpdir } from "node:os";
|
|
@@ -242,6 +244,8 @@ let heartbeat: ReturnType<typeof setInterval> | undefined;
|
|
|
242
244
|
const MAX_IDLE_PROCESSES = 1;
|
|
243
245
|
const modelInfoCache = new Map<string, ModelInfo>();
|
|
244
246
|
const modelCatalogRefreshes = new Map<string, Promise<ModelCatalog>>();
|
|
247
|
+
const recentModelCatalogs = new Map<string, { catalog: ModelCatalog; refreshedAt: number }>();
|
|
248
|
+
const MODEL_CATALOG_REUSE_MS = 30_000;
|
|
245
249
|
const commandCache = new Map<string, SlashCommandInfo[]>();
|
|
246
250
|
const exportDownloads = new Map<string, ExportDownload>();
|
|
247
251
|
const attachments = new AttachmentStore();
|
|
@@ -517,13 +521,23 @@ function isImmediateExtensionCommand(record: RuntimeSession, message: string): b
|
|
|
517
521
|
|
|
518
522
|
function debounce<A extends unknown[]>(fn: (...args: A) => void, ms: number) {
|
|
519
523
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
520
|
-
|
|
524
|
+
const schedule = (...args: A) => {
|
|
521
525
|
if (timer) clearTimeout(timer);
|
|
522
|
-
timer = setTimeout(() =>
|
|
526
|
+
timer = setTimeout(() => {
|
|
527
|
+
timer = undefined;
|
|
528
|
+
fn(...args);
|
|
529
|
+
}, ms);
|
|
523
530
|
};
|
|
531
|
+
return Object.assign(schedule, {
|
|
532
|
+
cancel() {
|
|
533
|
+
if (timer) clearTimeout(timer);
|
|
534
|
+
timer = undefined;
|
|
535
|
+
},
|
|
536
|
+
});
|
|
524
537
|
}
|
|
525
538
|
|
|
526
539
|
const scheduleSave = debounce(() => {
|
|
540
|
+
if (shuttingDown) return;
|
|
527
541
|
stateSaveChain = stateSaveChain.then(saveStateNow).catch(() => {});
|
|
528
542
|
}, 120);
|
|
529
543
|
|
|
@@ -545,6 +559,7 @@ async function loadState(): Promise<void> {
|
|
|
545
559
|
}) ?? { version: 1, workspaces: [], sessions: [] };
|
|
546
560
|
sessions = new Map();
|
|
547
561
|
modelInfoCache.clear();
|
|
562
|
+
recentModelCatalogs.clear();
|
|
548
563
|
commandCache.clear();
|
|
549
564
|
if (state.modelCache) {
|
|
550
565
|
for (const [cwd, cached] of Object.entries(state.modelCache)) {
|
|
@@ -917,12 +932,26 @@ async function discoverFreshModelCatalog(cwd: string): Promise<ModelCatalog> {
|
|
|
917
932
|
})();
|
|
918
933
|
modelCatalogRefreshes.set(key, task);
|
|
919
934
|
try {
|
|
920
|
-
|
|
935
|
+
const catalog = await task;
|
|
936
|
+
recentModelCatalogs.set(key, { catalog, refreshedAt: Date.now() });
|
|
937
|
+
return catalog;
|
|
921
938
|
} finally {
|
|
922
939
|
modelCatalogRefreshes.delete(key);
|
|
923
940
|
}
|
|
924
941
|
}
|
|
925
942
|
|
|
943
|
+
async function modelCatalogForNewSession(cwd: string, preferredModel?: unknown): Promise<ModelCatalog> {
|
|
944
|
+
const key = normalizePath(cwd);
|
|
945
|
+
const refreshing = modelCatalogRefreshes.get(key);
|
|
946
|
+
if (refreshing) return refreshing;
|
|
947
|
+
const recent = recentModelCatalogs.get(key);
|
|
948
|
+
if (recent && Date.now() - recent.refreshedAt < MODEL_CATALOG_REUSE_MS
|
|
949
|
+
&& (!preferredModel || findCatalogModel(recent.catalog.models, preferredModel))) {
|
|
950
|
+
return recent.catalog;
|
|
951
|
+
}
|
|
952
|
+
return discoverFreshModelCatalog(cwd);
|
|
953
|
+
}
|
|
954
|
+
|
|
926
955
|
function applyModelInfo(record: RuntimeSession, info: ModelInfo): void {
|
|
927
956
|
record.models = info.models;
|
|
928
957
|
record.thinkingLevels = info.thinkingLevels;
|
|
@@ -1591,7 +1620,7 @@ async function createSession(
|
|
|
1591
1620
|
const ws = state.workspaces.find((w) => w.id === workspaceId);
|
|
1592
1621
|
if (!ws) throw new Error("workspace not found");
|
|
1593
1622
|
const info = modelInfoFromCatalog(
|
|
1594
|
-
await
|
|
1623
|
+
await modelCatalogForNewSession(ws.path, preferences.model),
|
|
1595
1624
|
preferences.model,
|
|
1596
1625
|
preferences.thinkingLevel,
|
|
1597
1626
|
);
|
|
@@ -2041,19 +2070,161 @@ function filePathFromUrl(url: string): string {
|
|
|
2041
2070
|
return path;
|
|
2042
2071
|
}
|
|
2043
2072
|
|
|
2044
|
-
|
|
2073
|
+
type StaticEncoding = "br" | "gzip" | "identity";
|
|
2074
|
+
interface StaticAsset {
|
|
2075
|
+
metadata: string;
|
|
2076
|
+
data: Buffer;
|
|
2077
|
+
etag: string;
|
|
2078
|
+
bytes: number;
|
|
2079
|
+
compressed: Partial<Record<"br" | "gzip", Buffer>>;
|
|
2080
|
+
compressing: Partial<Record<"br" | "gzip", Promise<Buffer>>>;
|
|
2081
|
+
}
|
|
2082
|
+
|
|
2083
|
+
const STATIC_CACHE_LIMIT = 32 * 1024 * 1024;
|
|
2084
|
+
const STATIC_ENTRY_LIMIT = 8 * 1024 * 1024;
|
|
2085
|
+
const staticAssets = new Map<string, StaticAsset>();
|
|
2086
|
+
const staticReads = new Map<string, Promise<StaticAsset>>();
|
|
2087
|
+
let staticCacheBytes = 0;
|
|
2088
|
+
const compressBrotliStatic = promisify(brotliCompress);
|
|
2089
|
+
const compressStatic = {
|
|
2090
|
+
br: (data: Buffer) => compressBrotliStatic(data, { params: { [zlibConstants.BROTLI_PARAM_QUALITY]: 4 } }),
|
|
2091
|
+
gzip: promisify(gzip),
|
|
2092
|
+
};
|
|
2093
|
+
|
|
2094
|
+
function evictStaticAsset(path: string): void {
|
|
2095
|
+
const entry = staticAssets.get(path);
|
|
2096
|
+
if (entry) staticCacheBytes -= entry.bytes;
|
|
2097
|
+
staticAssets.delete(path);
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
function trimStaticCache(): void {
|
|
2101
|
+
while (staticCacheBytes > STATIC_CACHE_LIMIT || staticAssets.size > 256) {
|
|
2102
|
+
evictStaticAsset(staticAssets.keys().next().value!);
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
function staticMetadata(info: Awaited<ReturnType<typeof stat>>): string {
|
|
2107
|
+
return `${info.dev}:${info.ino}:${info.size}:${info.mtimeMs}:${info.ctimeMs}`;
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
async function loadStaticAsset(path: string): Promise<StaticAsset> {
|
|
2111
|
+
// Revalidate metadata even for cached entries so local rebuilds are visible immediately.
|
|
2112
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
2113
|
+
const info = await stat(path);
|
|
2114
|
+
if (!info.isFile()) throw new Error("not a file");
|
|
2115
|
+
const metadata = staticMetadata(info);
|
|
2116
|
+
const cached = staticAssets.get(path);
|
|
2117
|
+
if (cached?.metadata === metadata) {
|
|
2118
|
+
staticAssets.delete(path);
|
|
2119
|
+
staticAssets.set(path, cached);
|
|
2120
|
+
return cached;
|
|
2121
|
+
}
|
|
2122
|
+
evictStaticAsset(path);
|
|
2123
|
+
const key = `${path}\0${metadata}`;
|
|
2124
|
+
let reading = staticReads.get(key);
|
|
2125
|
+
if (!reading) {
|
|
2126
|
+
reading = (async () => {
|
|
2127
|
+
const data = await readFile(path);
|
|
2128
|
+
if (staticMetadata(await stat(path)) !== metadata) throw new Error("static asset changed during read");
|
|
2129
|
+
const entry: StaticAsset = {
|
|
2130
|
+
metadata, data, etag: `W/"${createHash("sha256").update(data).digest("hex")}"`,
|
|
2131
|
+
bytes: data.length, compressed: {}, compressing: {},
|
|
2132
|
+
};
|
|
2133
|
+
if (entry.bytes <= STATIC_ENTRY_LIMIT) {
|
|
2134
|
+
evictStaticAsset(path);
|
|
2135
|
+
staticAssets.set(path, entry);
|
|
2136
|
+
staticCacheBytes += entry.bytes;
|
|
2137
|
+
trimStaticCache();
|
|
2138
|
+
}
|
|
2139
|
+
return entry;
|
|
2140
|
+
})();
|
|
2141
|
+
staticReads.set(key, reading);
|
|
2142
|
+
}
|
|
2143
|
+
try {
|
|
2144
|
+
return await reading;
|
|
2145
|
+
} catch (error) {
|
|
2146
|
+
if (attempt === 2) throw error;
|
|
2147
|
+
} finally {
|
|
2148
|
+
if (staticReads.get(key) === reading) staticReads.delete(key);
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
throw new Error("unable to read static asset");
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
function staticEncoding(header: string | undefined, compressible: boolean): StaticEncoding | undefined {
|
|
2155
|
+
if (!header?.trim()) return "identity";
|
|
2156
|
+
const qualities = new Map<string, number>();
|
|
2157
|
+
for (const part of header.split(",")) {
|
|
2158
|
+
const [name, ...parameters] = part.trim().toLowerCase().split(";");
|
|
2159
|
+
if (!name) continue;
|
|
2160
|
+
const q = parameters.map((parameter) => parameter.trim()).find((parameter) => parameter.startsWith("q="));
|
|
2161
|
+
const value = q === undefined ? 1 : Number(q.slice(2));
|
|
2162
|
+
qualities.set(name, Number.isFinite(value) && value >= 0 && value <= 1 ? value : 0);
|
|
2163
|
+
}
|
|
2164
|
+
const quality = (encoding: StaticEncoding): number => qualities.get(encoding)
|
|
2165
|
+
?? (encoding === "identity" ? (qualities.get("*") === 0 ? 0 : 1) : (qualities.get("*") ?? 0));
|
|
2166
|
+
const encodings: StaticEncoding[] = compressible ? ["br", "gzip", "identity"] : ["identity"];
|
|
2167
|
+
return encodings.filter((encoding) => quality(encoding) > 0)
|
|
2168
|
+
.sort((a, b) => quality(b) - quality(a))[0];
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
async function staticRepresentation(path: string, entry: StaticAsset, encoding: StaticEncoding): Promise<Buffer> {
|
|
2172
|
+
if (encoding === "identity") return entry.data;
|
|
2173
|
+
const cached = entry.compressed[encoding];
|
|
2174
|
+
if (cached) return cached;
|
|
2175
|
+
let compressing = entry.compressing[encoding];
|
|
2176
|
+
if (!compressing) {
|
|
2177
|
+
compressing = compressStatic[encoding](entry.data).then((data) => {
|
|
2178
|
+
if (staticAssets.get(path) === entry && entry.bytes + data.length <= STATIC_ENTRY_LIMIT) {
|
|
2179
|
+
entry.compressed[encoding] = data;
|
|
2180
|
+
entry.bytes += data.length;
|
|
2181
|
+
staticCacheBytes += data.length;
|
|
2182
|
+
trimStaticCache();
|
|
2183
|
+
}
|
|
2184
|
+
return data;
|
|
2185
|
+
}).finally(() => { delete entry.compressing[encoding]; });
|
|
2186
|
+
entry.compressing[encoding] = compressing;
|
|
2187
|
+
}
|
|
2188
|
+
return compressing;
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
function staticEtagMatches(header: string | undefined, etag: string): boolean {
|
|
2192
|
+
return Boolean(header?.split(",").some((candidate) => {
|
|
2193
|
+
const tag = candidate.trim();
|
|
2194
|
+
return tag === "*" || tag.replace(/^W\//, "") === etag.replace(/^W\//, "");
|
|
2195
|
+
}));
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
async function serveStatic(req: IncomingMessage, res: ServerResponse, url: string): Promise<void> {
|
|
2045
2199
|
const filePath = filePathFromUrl(url);
|
|
2046
2200
|
try {
|
|
2047
|
-
const
|
|
2201
|
+
const entry = await loadStaticAsset(filePath);
|
|
2048
2202
|
const ext = extname(filePath).toLowerCase();
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
})
|
|
2053
|
-
|
|
2203
|
+
const encoding = staticEncoding(req.headers["accept-encoding"], /^(?:\.(?:js|css|html|json|svg|txt|wasm|woff2?|ttf|otf))$/.test(ext));
|
|
2204
|
+
const relative = filePath.slice(WEB_DIR.length + 1).split(sep).join("/");
|
|
2205
|
+
res.setHeader("content-type", MIME[ext] ?? "application/octet-stream");
|
|
2206
|
+
res.setHeader("cache-control", /^assets\/mermaid\/chunks\/[^/]+-[a-zA-Z0-9]{8}\.js$/.test(relative)
|
|
2207
|
+
? "public, max-age=31536000, immutable" : "no-cache");
|
|
2208
|
+
res.setHeader("vary", "Accept-Encoding");
|
|
2209
|
+
res.setHeader("etag", entry.etag);
|
|
2210
|
+
if (!encoding) {
|
|
2211
|
+
res.writeHead(406, { "content-length": 0 });
|
|
2212
|
+
res.end();
|
|
2213
|
+
return;
|
|
2214
|
+
}
|
|
2215
|
+
if (encoding !== "identity") res.setHeader("content-encoding", encoding);
|
|
2216
|
+
if ((req.method === "GET" || req.method === "HEAD") && staticEtagMatches(req.headers["if-none-match"], entry.etag)) {
|
|
2217
|
+
res.writeHead(304);
|
|
2218
|
+
res.end();
|
|
2219
|
+
return;
|
|
2220
|
+
}
|
|
2221
|
+
const data = await staticRepresentation(filePath, entry, encoding);
|
|
2222
|
+
res.setHeader("content-length", data.length);
|
|
2223
|
+
res.writeHead(200);
|
|
2224
|
+
res.end(req.method === "HEAD" ? undefined : data);
|
|
2054
2225
|
} catch {
|
|
2055
|
-
res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
|
|
2056
|
-
res.end("not found");
|
|
2226
|
+
res.writeHead(404, { "content-type": "text/plain; charset=utf-8", "content-length": 9 });
|
|
2227
|
+
res.end(req.method === "HEAD" ? undefined : "not found");
|
|
2057
2228
|
}
|
|
2058
2229
|
}
|
|
2059
2230
|
|
|
@@ -2343,7 +2514,10 @@ async function handleApi(req: import("node:http").IncomingMessage, res: ServerRe
|
|
|
2343
2514
|
const workspace = workspaceId ? state.workspaces.find((item) => item.id === workspaceId) : undefined;
|
|
2344
2515
|
if (sessionId && !session) return sendJson(res, 404, { error: "session not found" });
|
|
2345
2516
|
if (workspaceId && !workspace) return sendJson(res, 404, { error: "workspace not found" });
|
|
2346
|
-
const
|
|
2517
|
+
const activeSession = !sessionId && !workspaceId && state.currentSessionId ? sessions.get(state.currentSessionId) : undefined;
|
|
2518
|
+
const activeWorkspace = !sessionId && !workspaceId
|
|
2519
|
+
? state.workspaces.find((item) => item.id === (activeSession?.workspaceId ?? state.currentWorkspaceId)) : undefined;
|
|
2520
|
+
const target = normalizePath(resolve(session?.cwd ?? workspace?.path ?? activeWorkspace?.path ?? activeSession?.cwd ?? process.cwd(), input));
|
|
2347
2521
|
const info = await stat(target);
|
|
2348
2522
|
if (!info.isFile()) return sendJson(res, 400, { error: "path is not a file" });
|
|
2349
2523
|
const image = url.searchParams.get("format") === "image";
|
|
@@ -3296,7 +3470,6 @@ async function shutdownServer(): Promise<void> {
|
|
|
3296
3470
|
await attachments.close();
|
|
3297
3471
|
if (heartbeat) clearInterval(heartbeat);
|
|
3298
3472
|
heartbeat = undefined;
|
|
3299
|
-
await saveStateNow().catch(() => {});
|
|
3300
3473
|
const activeServer = server;
|
|
3301
3474
|
server = undefined;
|
|
3302
3475
|
serverUrl = undefined;
|
|
@@ -3309,6 +3482,9 @@ async function shutdownServer(): Promise<void> {
|
|
|
3309
3482
|
activeServer.close(() => resolveClose());
|
|
3310
3483
|
});
|
|
3311
3484
|
}
|
|
3485
|
+
scheduleSave.cancel();
|
|
3486
|
+
await stateSaveChain;
|
|
3487
|
+
await saveStateNow().catch(() => {});
|
|
3312
3488
|
process.off("exit", exitHook);
|
|
3313
3489
|
process.off("SIGINT", sigintHook);
|
|
3314
3490
|
process.off("SIGTERM", sigintHook);
|
|
@@ -3382,7 +3558,7 @@ export async function startWebServer(options: {
|
|
|
3382
3558
|
if (!handled) sendJson(res, 404, { error: "not found" });
|
|
3383
3559
|
return;
|
|
3384
3560
|
}
|
|
3385
|
-
await serveStatic(res, url.pathname);
|
|
3561
|
+
await serveStatic(req, res, url.pathname);
|
|
3386
3562
|
} catch (error) {
|
|
3387
3563
|
if (!res.headersSent) sendJson(res, 500, { error: error instanceof Error ? error.message : String(error) });
|
|
3388
3564
|
else res.end();
|
package/web/app.css
CHANGED
|
@@ -284,6 +284,14 @@ body[data-workspace-dragging] .YDXeBa_projectRow[draggable=true]{cursor:grabbing
|
|
|
284
284
|
._markdown_1nba0_5 .md-code-container>.md-code-block{border:0;border-radius:0;margin:0}
|
|
285
285
|
._markdown_1nba0_5 .md-code-block code{font:inherit;white-space:inherit}
|
|
286
286
|
._markdown_1nba0_5 .md-table-wrap{max-width:100%;overflow-x:auto}
|
|
287
|
+
._markdown_1nba0_5 .katex{font-size:1.1em;overflow-wrap:normal;word-break:normal}
|
|
288
|
+
._markdown_1nba0_5 .katex-display{max-width:100%;margin:16px 0;padding:4px 0;overflow:auto hidden;overscroll-behavior-inline:contain}
|
|
289
|
+
._markdown_1nba0_5 .md-mermaid{min-width:0;max-width:100%;margin:16px 0;overflow-x:auto;overscroll-behavior-inline:contain}
|
|
290
|
+
._markdown_1nba0_5 .md-mermaid>svg{display:block;max-width:100%;height:auto;margin:0 auto}
|
|
291
|
+
._markdown_1nba0_5 .md-mermaid pre{margin:0}
|
|
292
|
+
._markdown_1nba0_5 eq{display:inline}
|
|
293
|
+
._markdown_1nba0_5 .eqno{display:flex;align-items:center;gap:12px;max-width:100%}
|
|
294
|
+
._markdown_1nba0_5 eqn{display:block;min-width:0;flex:1}
|
|
287
295
|
[data-chat-flow-kind=assistant-text] .md-table-wrap{max-width:100%;margin:18px 0;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-base);overflow-x:auto;overscroll-behavior-inline:contain}
|
|
288
296
|
[data-chat-flow-kind=assistant-text] .md-table-wrap table{width:max-content;min-width:100%;border-collapse:separate;border-spacing:0;font-size:14px;line-height:1.55}
|
|
289
297
|
[data-chat-flow-kind=assistant-text] .md-table-wrap :is(th,td){box-sizing:border-box;min-width:112px;max-width:360px;padding:9px 12px;text-align:left;vertical-align:top;border-right:1px solid var(--dsw-alias-border-l2);border-bottom:1px solid var(--dsw-alias-border-l2);overflow-wrap:anywhere}
|
|
@@ -730,7 +738,7 @@ body[data-ds-dark-theme] :is(.pi-filePreview,._markdown_1nba0_5) .hljs-meta,body
|
|
|
730
738
|
.pi-loginCard .pi-settingsAction{width:100%;min-height:44px}
|
|
731
739
|
.pi-lanUrl{box-sizing:border-box;width:100%;min-width:0;padding:8px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);font:12px/20px var(--ds-font-family-code)}
|
|
732
740
|
.pi-copyField{box-sizing:border-box;width:100%;min-height:160px;max-height:40vh;margin:12px 0;padding:10px;resize:vertical;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);font:16px/24px var(--dsw-font-family)}
|
|
733
|
-
@media(pointer:coarse){
|
|
741
|
+
@media(max-width:640px),(pointer:coarse){
|
|
734
742
|
#root{box-sizing:border-box;position:fixed;top:var(--pi-viewport-top,0px);left:0;right:0;height:var(--pi-viewport-height,100dvh);padding:env(safe-area-inset-top) env(safe-area-inset-right) 0 env(safe-area-inset-left)}
|
|
735
743
|
.wSkVaW_root,.wSkVaW_composerSeat{--dsh-composer-text-max-height:min(200px,calc(var(--pi-viewport-height,100dvh) * .3))}
|
|
736
744
|
.wSkVaW_composerSeat{padding-bottom:env(safe-area-inset-bottom)}
|
package/web/app.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { markdown } from "./assets/markdown.js";
|
|
3
|
+
import { markdown as renderMarkdown } from "./assets/markdown.js";
|
|
4
|
+
import { observeMarkdownDiagrams } from "./markdown-diagrams.js";
|
|
5
|
+
|
|
6
|
+
observeMarkdownDiagrams();
|
|
4
7
|
import { webSlashCommands, unsupportedSlashCommands, parseSlashCommand } from "./slash-commands.js";
|
|
5
8
|
import { getLanguage, setLanguage, t, translateUi, observeUi } from "./i18n.js";
|
|
6
9
|
|
|
@@ -274,6 +277,14 @@ function snapshotFor(id) {
|
|
|
274
277
|
return S.snapshots.get(id) || { session: null, state: null, stats: null, models: [], thinkingLevels: [], thinkingLevelsByModel: {}, commands: [], extensionStatuses: {}, messages: [], pendingQueue: { steering: [], followUp: [] }, dialogs: [] };
|
|
275
278
|
}
|
|
276
279
|
|
|
280
|
+
function markdown(text) {
|
|
281
|
+
const session = S.currentSessionId ? S.snapshots.get(S.currentSessionId)?.session : null;
|
|
282
|
+
const workspace = S.currentSessionId
|
|
283
|
+
? S.workspaces.find((item) => item.sessions?.some((entry) => entry.id === S.currentSessionId))
|
|
284
|
+
: S.workspaces.find((item) => item.id === S.currentWorkspaceId);
|
|
285
|
+
return renderMarkdown(text, { cwd: session?.cwd || workspace?.path });
|
|
286
|
+
}
|
|
287
|
+
|
|
277
288
|
function currentWorkspace() {
|
|
278
289
|
return S.workspaces.find((w) => w.id === S.currentWorkspaceId) || S.workspaces[0] || null;
|
|
279
290
|
}
|
|
@@ -429,7 +440,6 @@ function usesMobileFilePreview() {
|
|
|
429
440
|
|
|
430
441
|
function updateViewport() {
|
|
431
442
|
const viewport = window.visualViewport;
|
|
432
|
-
if (viewport && viewport.scale !== 1) return;
|
|
433
443
|
document.documentElement.style.setProperty("--pi-viewport-height", `${viewport?.height || window.innerHeight}px`);
|
|
434
444
|
document.documentElement.style.setProperty("--pi-viewport-top", `${viewport?.offsetTop || 0}px`);
|
|
435
445
|
}
|
|
@@ -5259,7 +5269,9 @@ function connectEvents() {
|
|
|
5259
5269
|
if (!event.sessionId) return;
|
|
5260
5270
|
S.snapshots.set(event.sessionId, { ...snapshotFor(event.sessionId), ...event });
|
|
5261
5271
|
const current = event.sessionId === S.currentSessionId;
|
|
5262
|
-
|
|
5272
|
+
// Settings do not depend on session snapshots. Rebuilding the panel on
|
|
5273
|
+
// every streamed chunk replaces controls between pointerdown and click.
|
|
5274
|
+
queueRender(false, { sidebar: false, conversation: current, overlay: false });
|
|
5263
5275
|
return;
|
|
5264
5276
|
}
|
|
5265
5277
|
if (event.type === "workspaces") {
|
|
@@ -5282,7 +5294,7 @@ function connectEvents() {
|
|
|
5282
5294
|
}
|
|
5283
5295
|
}
|
|
5284
5296
|
if (unchanged && !conversationChanged) return;
|
|
5285
|
-
queueRender(false, { sidebar: true, conversation: conversationChanged, overlay:
|
|
5297
|
+
queueRender(false, { sidebar: true, conversation: conversationChanged, overlay: false });
|
|
5286
5298
|
}
|
|
5287
5299
|
} catch {
|
|
5288
5300
|
// ignore malformed event
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|