@oversk7/pi-web-dsh-style 1.3.2 → 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 +190 -17
- package/web/app.css +9 -1
- package/web/app.js +7 -3
- 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 +41 -2
- 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
|
|
|
@@ -3299,7 +3470,6 @@ async function shutdownServer(): Promise<void> {
|
|
|
3299
3470
|
await attachments.close();
|
|
3300
3471
|
if (heartbeat) clearInterval(heartbeat);
|
|
3301
3472
|
heartbeat = undefined;
|
|
3302
|
-
await saveStateNow().catch(() => {});
|
|
3303
3473
|
const activeServer = server;
|
|
3304
3474
|
server = undefined;
|
|
3305
3475
|
serverUrl = undefined;
|
|
@@ -3312,6 +3482,9 @@ async function shutdownServer(): Promise<void> {
|
|
|
3312
3482
|
activeServer.close(() => resolveClose());
|
|
3313
3483
|
});
|
|
3314
3484
|
}
|
|
3485
|
+
scheduleSave.cancel();
|
|
3486
|
+
await stateSaveChain;
|
|
3487
|
+
await saveStateNow().catch(() => {});
|
|
3315
3488
|
process.off("exit", exitHook);
|
|
3316
3489
|
process.off("SIGINT", sigintHook);
|
|
3317
3490
|
process.off("SIGTERM", sigintHook);
|
|
@@ -3385,7 +3558,7 @@ export async function startWebServer(options: {
|
|
|
3385
3558
|
if (!handled) sendJson(res, 404, { error: "not found" });
|
|
3386
3559
|
return;
|
|
3387
3560
|
}
|
|
3388
|
-
await serveStatic(res, url.pathname);
|
|
3561
|
+
await serveStatic(req, res, url.pathname);
|
|
3389
3562
|
} catch (error) {
|
|
3390
3563
|
if (!res.headersSent) sendJson(res, 500, { error: error instanceof Error ? error.message : String(error) });
|
|
3391
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
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
|
|
|
@@ -437,7 +440,6 @@ function usesMobileFilePreview() {
|
|
|
437
440
|
|
|
438
441
|
function updateViewport() {
|
|
439
442
|
const viewport = window.visualViewport;
|
|
440
|
-
if (viewport && viewport.scale !== 1) return;
|
|
441
443
|
document.documentElement.style.setProperty("--pi-viewport-height", `${viewport?.height || window.innerHeight}px`);
|
|
442
444
|
document.documentElement.style.setProperty("--pi-viewport-top", `${viewport?.offsetTop || 0}px`);
|
|
443
445
|
}
|
|
@@ -5267,7 +5269,9 @@ function connectEvents() {
|
|
|
5267
5269
|
if (!event.sessionId) return;
|
|
5268
5270
|
S.snapshots.set(event.sessionId, { ...snapshotFor(event.sessionId), ...event });
|
|
5269
5271
|
const current = event.sessionId === S.currentSessionId;
|
|
5270
|
-
|
|
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 });
|
|
5271
5275
|
return;
|
|
5272
5276
|
}
|
|
5273
5277
|
if (event.type === "workspaces") {
|
|
@@ -5290,7 +5294,7 @@ function connectEvents() {
|
|
|
5290
5294
|
}
|
|
5291
5295
|
}
|
|
5292
5296
|
if (unchanged && !conversationChanged) return;
|
|
5293
|
-
queueRender(false, { sidebar: true, conversation: conversationChanged, overlay:
|
|
5297
|
+
queueRender(false, { sidebar: true, conversation: conversationChanged, overlay: false });
|
|
5294
5298
|
}
|
|
5295
5299
|
} catch {
|
|
5296
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
|