@jaychang1989/dsh-webchat 0.5.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -19,6 +19,8 @@ But the desktop shell keeps a door open for **approved browser guests**: the ren
19
19
 
20
20
  So the page is **not an iframe** — it is a native guest owned by the host, which is why `frame-ancestors` does not apply to it. It also means the desktop app is what makes it possible.
21
21
 
22
+ The sidebar row and the page are both standard DSH **slots** (`sidebar.panellist` and `main`, joined by one shared id), so the shell owns the button and the panel switching. That is why this plugin injects nothing into anyone else's DOM and never has to guess when to step aside.
23
+
22
24
  Where that bridge is absent (a plain `dsh web` profile) the plugin **falls back** to opening a window, so the entry always does something.
23
25
 
24
26
  ## Install
@@ -40,9 +42,9 @@ dsh plugin --profile desktop add github:jaychang1989/dsh-webchat
40
42
  ## Use
41
43
 
42
44
  1. Click the "DeepSeek 网页 / DeepSeek Web" entry — the page loads in the center column; there is no second click.
43
- 2. Sign in to DeepSeek once; that holds for the rest of the run.
45
+ 2. Sign in to DeepSeek once — the plugin keeps that login across restarts (see below).
44
46
 
45
- Click again to collapse the panel. The guest stays mounted while the panel is closed, so reopening neither reloads the page nor drops the session. Clicking **any other sidebar row** — Plugins, Automation Tasks, the task board, a session, a workspace — hands the center column back, because those pages are rendered there by the shell and this plugin does not hold their seat.
47
+ Click again to collapse the panel. Switching to another panel (Plugins, Automation Tasks, the task board, a session …) only hides the guest, never unmounts it, so coming back neither reloads the page nor drops the session.
46
48
 
47
49
  ## Requirements
48
50
 
@@ -50,20 +52,30 @@ Click again to collapse the panel. The guest stays mounted while the panel is cl
50
52
  - Node.js >= 22
51
53
  - The desktop app: only it provides the native guest bridge; plain `dsh web` uses the window fallback
52
54
 
55
+ ## Staying signed in
56
+
57
+ The host hands browser guests a **process-lifetime** partition (a fresh random name per run, with no `persist:` prefix), so cookies and site storage would die with the app — DSH's own side-card browser behaves the same way. This plugin takes that over: its host half runs inside the **Electron main process**, which is the only place a partition's cookies can be read (**HttpOnly ones included**; a renderer can never see them). It snapshots the cookies and the page's localStorage while you use the page, and puts them back **before** the page loads on the next run.
58
+
59
+ - Location: `%USERPROFILE%\.dsh\dsh-webchat\session.json`
60
+ - **Deleting that file logs the plugin's guest out** — it keeps nothing else behind.
61
+ - The file holds live session credentials in **plain text**. It sits in your own profile directory (user-private by default), but it is not as protected as a browser's encrypted cookie store.
62
+ - If DeepSeek changes how it stores the session you may have to sign in once more; the snapshot is then taken again automatically.
63
+
53
64
  ## Known limitations
54
65
 
55
- - **Restarting the desktop app means signing in to DeepSeek again.** The host hands out a **process-lifetime** guest partition (a fresh random name per run, with no `persist:` prefix), so the session is not written to disk. That is the host's mechanism, not a choice this plugin makes.
56
- - The DeepSeek web front end has its own rate limiting and sign-in flow; the plugin only hosts it and does not mediate its requests.
66
+ - The DeepSeek web front end has its own rate limiting and sign-in flow; the plugin only hosts it and keeps the session, and does not mediate its requests.
57
67
  - Links the page opens are handled inside the guest; the plugin adds no navigation policy of its own.
58
68
 
59
69
  ## Troubleshooting
60
70
 
61
71
  | Symptom | Cause / fix |
62
72
  | --- | --- |
63
- | The entry is missing | Check that `@jaychang1989/dsh-webchat` is in the profile's `dsh.profile.bundles`, then restart the desktop app |
73
+ | No "DeepSeek Web" row in the sidebar | Check that `@jaychang1989/dsh-webchat` is in the profile's `dsh.profile.bundles`, then restart the desktop app |
64
74
  | The center column says "载入失败:…" | The host refused the guest (the bridge threw). The text carries the host's reason |
65
- | Clicking the entry opened a browser window instead | This renderer had no `dshDesktop.browser` (a plain web profile, for instance), so the fallback ran |
66
- | It asks for a login again after a restart | See the limitations above — it is the host's partition behaviour |
75
+ | The row opens a browser window instead of a panel | This renderer had no `dshDesktop.browser` (a plain web profile, for instance), so the fallback ran |
76
+ | The row opens but the center column is blank | The panel fills the cell the shell allocates; in a very small window, or with the sidebar dragged extremely narrow, that cell can have no area |
77
+ | It asks for a login again after a restart | Check `session` in `GET /api/dsh-webchat/state`: an `electron` value other than `ready` means the host half cannot reach Electron (so nothing can be saved), and `saved: null` means no snapshot exists yet. Use the page for a moment and look again ~30s later |
78
+ | You want to sign out for good | Delete `%USERPROFILE%\.dsh\dsh-webchat\session.json` |
67
79
  | The page shows "Abnormal usage environment" | DeepSeek's front end checks `navigator.userAgent` for the string `electron` — which the desktop default carries — and then recommends its official product. Since 0.5.2 the guest presents a plain Chrome user agent and the dialog no longer appears |
68
80
 
69
81
  ## Development and tests
@@ -72,7 +84,7 @@ Click again to collapse the panel. The guest stays mounted while the panel is cl
72
84
  node --test
73
85
  ```
74
86
 
75
- Fourteen cases, and the browser half really executes against a DOM stand-in: in a desktop environment it checks that the entry mounts, that clicking reserves a lease, that the webview is built the way the host requires (`about:blank#<lease>`), that navigation happens on `dom-ready`, and that closing and reopening reuses the same guest; without a bridge it checks the window fallback and its reporting.
87
+ Thirty-four cases. The host half is driven through a fake context, fake request/response objects and injectable Electron/cookie stand-ins: the snapshot round-trip through disk, cookie capture and restore (HttpOnly included, one refused cookie not aborting the rest), the session routes' method guards and partition validation, and a host without Electron reporting why without hurting the page. The browser half really executes against a thin React test double plus a DOM stand-in: the slot contract (one shared id, order, the label thunk, the icon honouring the requested size), the lease and the `about:blank#<lease>` webview, the user agent landing before navigation, **hiding the guest without detaching it on unmount and reusing it on remount**, the login restore writing storage once and reloading once, snapshots while in use and on disposal, and the window fallback.
76
88
 
77
89
  There is no build step — `lib/index.js` and `lib/client.js` are the hand-written runtime, and the package has **zero runtime dependencies**. The guest mechanism is written up in [MAINTAINING.md](./MAINTAINING.md) (Chinese).
78
90
 
package/README.md CHANGED
@@ -19,6 +19,8 @@ iframe 和 `<webview>` 常规路径确实都被封死了:
19
19
 
20
20
  所以这个页面**不是嵌在 iframe 里**,而是宿主的原生访客——`frame-ancestors` 管不到它。这也解释了为什么它必须由 DSH 桌面端承载。
21
21
 
22
+ 而「侧边栏那一行」和「中栏那一页」都是 DSH 的**标准槽位**(`sidebar.panellist` 与 `main`,同一个 id 关联),按钮和面板切换都由 shell 自己掌管——所以这个插件不往别人的 DOM 里塞东西,也不需要去猜什么时候该让位。
23
+
22
24
  在没有该桥接的环境(纯 `dsh web`,非桌面端)会**自动降级**为打开一个窗口,保证入口永远有反应。
23
25
 
24
26
  ## 安装
@@ -42,7 +44,7 @@ dsh plugin --profile desktop add github:jaychang1989/dsh-webchat
42
44
  1. 点侧边栏的「DeepSeek 网页」入口 —— 页面直接在中栏载入,不需要第二次点击;
43
45
  2. 在里面登录一次 DeepSeek,当前这次运行内一直有效。
44
46
 
45
- 再点一次入口收起面板;面板关闭后访客保持挂载,重新打开不会重新加载、也不会掉登录。点侧边栏里**任何其它行**(插件、自动化任务、任务看板、会话、工作区)都会把中栏让回去——那些页面由 shell 渲染在中栏,本插件不占用它们的席位。
47
+ 再点一次入口收起面板。切换去别的面板(插件、自动化任务、任务看板、会话……)时访客只是被隐藏、从不被卸载,所以切回来不会重新加载、也不会掉登录。
46
48
 
47
49
  ## 环境要求
48
50
 
@@ -50,20 +52,30 @@ dsh plugin --profile desktop add github:jaychang1989/dsh-webchat
50
52
  - Node.js >= 22
51
53
  - 桌面端(DSH Desktop):只有它提供原生访客桥接;纯 `dsh web` 会走窗口降级
52
54
 
55
+ ## 登录状态
56
+
57
+ 桌面端给浏览器访客的分区是**进程内**的(每次运行随机命名、不带 `persist:`),所以 cookie 和站点存储本来会随退出一起消失——DSH 自带的侧栏浏览器也是这样。本插件把这个接管了:宿主半区运行在 **Electron 主进程里**,因此能读到该分区的 cookie(**含 HttpOnly**,渲染进程永远看不到),它会在你使用过程中把 cookie 与页面的 localStorage 快照下来,下次启动时**先回灌、再加载页面**。
58
+
59
+ - 文件位置:`%USERPROFILE%\.dsh\dsh-webchat\session.json`
60
+ - **删掉这个文件就等于退出登录**(本插件不会再有别的残留)。
61
+ - 文件里是**明文**会话凭据。它在你自己的用户目录下(默认只有你的账户可读),但确实不如浏览器那种加密 cookie 库。
62
+ - 若 DeepSeek 更换登录态的存储方式,可能要重新登录一次——之后会自动重新快照。
63
+
53
64
  ## 已知限制
54
65
 
55
- - **重启桌面端后需要重新登录 DeepSeek。** 宿主给访客分配的是**进程内**分区(每次运行随机命名、不带 `persist:`),登录态不落盘。这是宿主的机制,插件无法改变。
56
- - 官方网页端有自己的风控与登录流程,插件只负责把它承载起来,不介入其请求。
66
+ - 官方网页端有自己的风控与登录流程,插件只负责把它承载起来并保留登录态,不介入其请求。
57
67
  - 页面里指向外部的链接在访客内处理;插件不追加自己的导航策略。
58
68
 
59
69
  ## 排查
60
70
 
61
71
  | 现象 | 原因 / 处理 |
62
72
  | --- | --- |
63
- | 入口没出现 | 确认 profile 的 `dsh.profile.bundles` 里有 `@jaychang1989/dsh-webchat`,然后重启桌面端 |
73
+ | 侧边栏没出现「DeepSeek 网页」这一行 | 确认 profile 的 `dsh.profile.bundles` 里有 `@jaychang1989/dsh-webchat`,然后重启桌面端 |
64
74
  | 中栏提示「载入失败:…」 | 宿主拒绝了访客(桥接返回异常)。文本里带着宿主给的原因 |
65
- | 点了入口却弹出一个浏览器窗口 | 说明当前渲染进程拿不到 `dshDesktop.browser`(例如在纯 web 环境),插件走了降级路径 |
66
- | 重启后要求重新登录 | 见上面的「已知限制」,属于宿主分区机制 |
75
+ | 这一行点了但中栏没有页面,反而弹出浏览器窗口 | 说明当前渲染进程拿不到 `dshDesktop.browser`(例如在纯 web 环境),插件走了降级路径 |
76
+ | 这一行点了但中栏是空白 | 面板显示的空间是 shell 分配的那个格子;若窗口极小或侧栏被拖到极窄,格子可能没有面积 |
77
+ | 重启后要求重新登录 | 先看 `GET /api/dsh-webchat/state` 的 `session`:`electron` 不是 `ready` 说明宿主半区拿不到 Electron(登录态无法保存),`saved` 为 `null` 说明还没产生过快照。正常情况下用一次、等 30 秒再看,文件就会出现 |
78
+ | 想彻底退出登录 | 删掉 `%USERPROFILE%\.dsh\dsh-webchat\session.json` |
67
79
  | 页面弹出「使用环境异常」 | DeepSeek 前端会检查 `navigator.userAgent` 里是否含 `electron`(桌面端默认 UA 就含),命中就提示"建议使用官方产品"。0.5.2 起访客改用普通 Chrome UA,不再触发 |
68
80
 
69
81
  ## 开发与测试
@@ -72,9 +84,9 @@ dsh plugin --profile desktop add github:jaychang1989/dsh-webchat
72
84
  node --test
73
85
  ```
74
86
 
75
- 14 个用例,其中浏览器半区在 DOM 桩里**真实执行**:桌面端环境下验证入口挂载、点击后申请租约、按宿主约定生成 `about:blank#<lease>` 的 webview、`dom-ready` 后导航到目标地址、关闭重开复用同一个访客;无桥接环境下验证降级为请求宿主开窗并如实提示结果。
87
+ 34 个用例。宿主半区用假 context、假 request/response 与可注入的 Electron/cookie 替身驱动:快照落盘往返、cookie 捕获与回灌(含 `HttpOnly`、拒绝一个不合法 cookie 不影响其余)、两条会话路由的方法守卫与分区校验、无 Electron 时如实报错而不影响页面加载。浏览器半区用一层薄的 React 测试替身 + DOM 桩**真实执行**:槽位注册契约(同一个 id、order、label thunk、按 size 出图标)、租约与 `about:blank#<lease>` 的 webview、`dom-ready` 后先改 UA 再导航、**卸载只隐藏不摘除 / 重挂复用同一访客 / 只申请一次租约**、登录态恢复只回灌一次并只刷新一次、使用中与卸载时的快照、无桥接时的降级。
76
88
 
77
- 没有构建步骤——`lib/index.js` 与 `lib/client.js` 就是手写的运行时代码,包内**零运行时依赖**。访客机制的来龙去脉见 [MAINTAINING.md](./MAINTAINING.md)。
89
+ 没有构建步骤——`lib/index.js` 与 `lib/client.js` 就是手写的运行时代码(React 取自浏览器的模块表),包内**零运行时依赖**。访客机制、槽位契约与登录态保存见 [MAINTAINING.md](./MAINTAINING.md)。
78
90
 
79
91
  ## 来源与许可
80
92