@tianyulinfeng1/dsh-plugin-deepseek-chat 1.1.1 → 1.1.5

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
@@ -1,166 +1,189 @@
1
- # dsh-plugin-deepseek-chat
2
-
3
- English | [中文](README.md)
4
-
5
- > **Current version: v1.1.1** | Targets DSH **0.2.2-rc.1**
6
-
7
- Adds a **DeepSeek Chat** entry to the **DeepSeek Harness (DSH) desktop** sidebar. Clicking it opens `chat.deepseek.com` full-width in the main area, remembers the last conversation, and shows the current DSH account state.
8
-
9
- > Repository: [GitHub](https://github.com/sweet560/dsh-plugin-deepseek-chat) | [Gitee mirror](https://gitee.com/wtt520wyl/dsh-plugin-deepseek-chat)
10
-
11
- ![panel screenshot](docs/screenshot.png)
12
-
13
- ## Features
14
-
15
- - Sidebar icon entry, placed between **Plugins** and **Scheduled tasks**.
16
- - Full-width embedded `https://chat.deepseek.com/` (Electron `<webview>` through the desktop guest-lease bridge `window.dshDesktop.browser`).
17
- - **Last-conversation memory**: switching panels/sessions or restarting the app reopens the conversation you left, not a new chat.
18
- - Auth pages never overwrite that memory; a dead conversation falls back to the site root.
19
- - **Stable login session (fixed in v1.1.1)**: the guest partition is the constant `panel:deepseek-chat`; switching panels/sessions back no longer rebuilds the partition or asks for a fresh QR scan.
20
- - **DSH account status**: a strip shows "Synced with the DSH account · name" / "No account" / "Account state unavailable" via the official `ctx.remote.account` Remote. **Display only — it never participates in the guest lifecycle.**
21
- - **Crash containment**: if the embedded page's process dies, is destroyed, or never starts, the panel shows a Retry card — the app window no longer goes blank (fixed in v0.4.0).
22
- - Inert on the plain Web surface (`dsh web`): the site sends `frame-ancestors 'none'`, so an iframe cannot carry it, and the guest bridge only exists in the desktop shell.
23
-
24
- ## Requirements
25
-
26
- | Item | Requirement |
27
- |---|---|
28
- | DSH | Desktop `0.2.2-rc.1` or newer |
29
- | Platform | Windows / macOS / Linux desktop shell |
30
- | git | Only for the GitHub install route (pnpm fetches the repository) |
31
-
32
- ## Install
33
-
34
- npm package: **`@tianyulinfeng1/dsh-plugin-deepseek-chat`** (the GitHub repository is still named `dsh-plugin-deepseek-chat`).
35
-
36
- ### Option 1 — npm (recommended)
37
-
38
- ```powershell
39
- dsh plugin --profile desktop add @tianyulinfeng1/dsh-plugin-deepseek-chat
40
- ```
41
-
42
- You can also enter the package name `@tianyulinfeng1/dsh-plugin-deepseek-chat` in the Plugins page.
43
-
44
- ### Option 2 — Plugins page (GitHub)
45
-
46
- 1. Open DSH desktop and click **Plugins** in the sidebar.
47
- 2. Click **Install a third-party plugin** above the list.
48
- 3. Enter:
49
-
50
- ```
51
- github:sweet560/dsh-plugin-deepseek-chat
52
- ```
53
-
54
- `https://github.com/sweet560/dsh-plugin-deepseek-chat` works too.
55
- 4. Click **Install** and wait for pnpm to finish.
56
- 5. The plugin is enabled automatically; **DeepSeek Chat** appears in the sidebar.
57
-
58
- ### Option 3 — CLI (GitHub)
59
-
60
- ```powershell
61
- dsh plugin --profile desktop add github:sweet560/dsh-plugin-deepseek-chat
62
- ```
63
-
64
- Then open **Plugins → Installed plugins** and make sure **DeepSeek Chat** is switched on (the CLI only installs the package).
65
-
66
- ### Option 4 — local checkout (development)
67
-
68
- ```powershell
69
- dsh plugin --profile desktop add file:"<absolute path to this repository>"
70
- ```
71
-
72
- ## Why the web chat cannot reuse the DSH sign-in
73
-
74
- **A pure plugin cannot make chat.deepseek.com reuse the already-signed-in DSH account.** This is an architecture limit of DSH 0.2.2-rc.1, verified against its source:
75
-
76
- | | DSH desktop account | chat.deepseek.com web |
77
- |---|---|---|
78
- | Credential | platform.deepseek.com `x-dsh-auth-token` (Host-only `getPlatformSession()`) | the site's own Token (`api/v0/users/current` returns `40002 Missing Token` without it) |
79
- | Storage | Host credential store | httpOnly cookie in the guest session |
80
- | Exchange | **None** — zero `chat.deepseek.com` references, no SSO, no cookie injection in the whole archive | — |
81
-
82
- - The renderer bridge `globalThis.dshDesktop` exposes only `browser.acquire/release/onOpenRequested` etc. — **no** `getAuthToken`, cookie write, or "open Platform to fetch token" API. `getAuthToken()` exists only in the desktop shell's embedded Platform view (`usage` / `top_up`) preload, main-frame + origin restricted.
83
- - The `browserAcquire` IPC only allocates a partition/lease by workspace string; `configureSession()` sets permissions and download interception, **it injects no credentials**. The guest is forced to `sandbox / contextIsolation / webSecurity`.
84
- - So the DSH account state can only be **displayed**; it cannot become a web-session login. One manual QR sign-in is still required.
85
-
86
- **What went wrong in v1.1.0 (fixed in v1.1.1)**: the guest partition had been keyed to the asynchronous account probe. DSH's `getState()` can transiently fail during a reconnect or session switch; changing the partition hands the panel a brand-new cookie jar → a fresh QR scan every time you switched back. Now:
87
-
88
- - `acquire()`'s workspace is the constant `panel:deepseek-chat`, and the conversation key is the constant `dsh-plugin-deepseek-chat:last-url`;
89
- - account state changes only update the strip — no epoch, no guest rebuild, no partition change;
90
- - a transient `unknown` is ignored; only a confirmed `signed-out` updates the display;
91
- - the guest starts on mount immediately, without waiting for the async Remote (a failed probe never blocks chat);
92
- - popup navigation is allowlisted to `chat.deepseek.com` and `platform.deepseek.com` (HTTPS, default port).
93
-
94
- > To also avoid re-scanning **after restarting DSH**, run [scripts/patch-dsh-persistent-partition.cjs](scripts/patch-dsh-persistent-partition.cjs) per [docs/login-persistence.md](docs/login-persistence.md) to change DSH's random in-memory partition into a deterministic `persist:` one (an `app.asar` edit — modifying the installed app, at your own risk). **It also syncs the per-file SHA256 ASAR integrity required by 0.2.2-rc.1** — a byte-only replacement (the deprecated `.mjs` script) would crash DSH on restart. It requires fully exiting DSH first. That patch preserves web cookies across restarts; it does not make the web chat reuse the DSH token.
95
-
96
- ## Usage
97
-
98
- - The first visit shows the chat.deepseek.com sign-in page; sign in once.
99
- - Within one app run, switching panels or sessions keeps you signed in (fixed partition since v1.1.1).
100
- - **Sign in again after restarting DSH**: DSH currently gives embedded browsers a random in-memory partition (`dsh-sidebar-browser-<uuid>`, no `persist:` prefix), so cookies are dropped when the process exits. This plugin does not modify DSH's installation files; to sign in once and stay signed in, apply the equal-length byte patch described in **[docs/login-persistence.md](docs/login-persistence.md)**.
101
- - The conversation URL is stored under the fixed key `dsh-plugin-deepseek-chat:last-url`, so the last conversation is restored after a restart (while signed in and while it still exists).
102
-
103
- ## Persistent login (optional)
104
-
105
- DSH hands embedded browsers an **in-memory partition** (`dsh-sidebar-browser-${randomUUID()}`, no `persist:` prefix), so every app restart drops the cookies. To sign in once and stay signed in, replace that partition with a fixed `persist:` one inside `resources/app.asar` — the two statements are the same length, so the archive can be patched byte-for-byte in place.
106
-
107
- Cause, script, verification, rollback and per-platform paths:
108
-
109
- **→ [docs/login-persistence.md](docs/login-persistence.md)**
110
-
111
- Note: this modifies the installed application and is outside DSH's support; a DSH update overwrites `app.asar` and the patch must be re-applied (the `Partitions` data survives). Back up first and proceed at your own risk.
112
-
113
- ## Known limitations
114
-
115
- - chat.deepseek.com detects the Electron embedding and occasionally shows a "usage environment is abnormal" notice. That is site-side behaviour, unrelated to this plugin.
116
- - Desktop only; `dsh web` in a browser shows no entry.
117
- - If the site changes its conversation URL scheme (currently `/a/chat/s/<id>`), the memory falls back to the site root.
118
- - The DSH account status is display-only; it cannot turn the DSH OAuth token into a chat.deepseek.com web session, so the web chat still needs one manual sign-in on first use.
119
- - `getProfile()` is used only for the display name. If it is temporarily unavailable the strip may lag briefly, but it **never** affects the guest or the login state.
120
- - Restarting DSH still requires a fresh web sign-in unless the persistent-partition patch in [docs/login-persistence.md](docs/login-persistence.md) is applied.
121
-
122
- ## Crash containment (v0.4.0)
123
-
124
- Earlier versions could leave the whole app a blank window a second or two after opening the panel, with no crash dialog and no `crash-*.log`.
125
-
126
- Root cause: React runs effect cleanups after it has removed the DOM, and Electron's `<webview>` throws from `getURL()` once detached. DSH treats any uncaught plugin error as `slot entry crashed in 'root'` and unmounts the root slot — the entire UI.
127
-
128
- The current implementation guards every guest call behind an `isConnected` check and `try/catch`, reads the URL before removing the element, wraps every event handler, puts a React error boundary around the panel, listens for `render-process-gone` / `destroyed` / `did-fail-load`, and has a 15-second start watchdog. On failure the dead guest element is removed **before** the Retry card, so retrying cannot stack webviews; a listener-registration failure never starts a guest, and popup URLs are allowlisted (v1.1.0).
129
-
130
- ## Version history
131
-
132
- | Version | Changes |
133
- |---|---|
134
- | **1.1.1** | **Fixes the "scan the QR code again on every panel switch" regression**: the guest partition and conversation key are constants; account state is display-only and never touches the guest lifecycle; a transient `unknown` is ignored; the guest no longer waits for the async probe; self-check now asserts a fixed partition and no rebuild on state churn (35 cases). Documents why a pure plugin cannot reuse the DSH token. |
135
- | 1.1.0 | DSH `0.2.2-rc.1`: DSH account status strip; correct generated Remote envelope parsing; stricter conversation and popup URL validation; dead guest removal on failure. **This release keyed the partition to account state and broke login persistence (fixed in 1.1.1).** |
136
- | 1.0.0 | First local release: sidebar entry, full-width chat, conversation memory, crash containment. |
137
-
138
- ## Development
139
-
140
- ```powershell
141
- git clone https://github.com/sweet560/dsh-plugin-deepseek-chat.git
142
- cd dsh-plugin-deepseek-chat
143
- node test/check-client.mjs
144
- ```
145
-
146
- `test/check-client.mjs` loads `lib/client.js` in a `node:vm` sandbox with fake React/DOM/bridge objects and checks registration, Remote envelope parsing, a fixed partition/key, no rebuild on account-state churn, partition reuse across panel switches, conversation memory, lease release, popup allowlisting and crash containment.
147
-
148
- ```
149
- lib/index.js host half (empty; it only gives the client bundle a Loader entry)
150
- lib/client.js browser half: entry, panel, account status strip, webview lifecycle, crash containment
151
- cordis.patch.yml bundle patch that inserts this plugin's Loader row
152
- locale/{zh,en}.json Plugins-page title/description
153
- icon.svg Plugins-page icon
154
- docs/login-persistence.md optional byte patch for DSH's in-memory browser partition
155
- test/check-client.mjs offline self-check
156
- ```
157
-
158
- ## Uninstall
159
-
160
- ```powershell
161
- dsh plugin --profile desktop remove @tianyulinfeng1/dsh-plugin-deepseek-chat
162
- ```
163
-
164
- ## License
165
-
166
- [MIT](LICENSE)
1
+ # dsh-plugin-deepseek-chat
2
+
3
+ English | [中文](README.md)
4
+
5
+ > **Current version: v1.1.5** | Targets DSH **0.2.2-rc.1**
6
+
7
+ Adds **DeepSeek Chat** to the **DeepSeek Harness (DSH) desktop**: a sidebar icon entry and a conversation-header tab (default name **DeepSeek Chat**, configurable). Clicking either opens `chat.deepseek.com` filling the conversation area and remembers the last conversation. A **settings page** (with plugin metadata and a "Check for updates" button) lets you show/hide the header tab and rename it. The panel is **pure web chat** — no account status strip.
8
+
9
+ > Repository: [GitHub](https://github.com/sweet560/dsh-plugin-deepseek-chat) | [Gitee mirror](https://gitee.com/wtt520wyl/dsh-plugin-deepseek-chat)
10
+
11
+ ![panel screenshot](docs/screenshot.png)
12
+
13
+ ## Features
14
+
15
+ - **Two entries coexist**:
16
+ - A sidebar icon, placed between **Plugins** and **Scheduled tasks**, opening the full main area;
17
+ - A tab in the conversation-header tab row ("Dialogue / Trajectory / Context / Compression / Team / Stats"), registered through the official `conversation.view` slot (`id: deepseek-chat-view`, `order: 100`), **default label "DeepSeek Chat"**.
18
+ - **Settings page (v1.1.4)**: registered through the official `settings.section` slot (a "DeepSeek Chat" page in the Settings dialog). Two settings:
19
+ - **Show header tab** (default on): turning it off removes the header tab, leaving only the sidebar entry;
20
+ - **Header tab name** (default `DeepSeek Chat`): the field is **empty by default** and shows the default name only as a grey placeholder; click into it and type a new name directly (no need to delete the default text first). Empty falls back to the default, capped at 40 characters.
21
+ - Settings are persisted in `localStorage` under `dsh-plugin-deepseek-chat:config` and take effect immediately (the tab row re-registers).
22
+ - **About this plugin (v1.1.5)**: the Settings page shows the plugin version, author (`sweet560`), a short description, the open-source license (`MIT`), and two `https` links to the npm package page and the GitHub repository (opened by the desktop shell in the system browser).
23
+ - **Check for updates (v1.1.5)**: the Settings page adds a "Check for updates" button that reads the latest published version from two public JSON endpoints — **npm first, GitHub as a fallback** (npm `dist-tags.latest`, `raw.githubusercontent.com` `package.json`). Versions are compared segment-by-segment numerically: up to date / new version available / check failed all produce a text status with npm/GitHub jump links. Repeated clicks are ignored while checking; network failures and both-source failures are handled gracefully. No Host route is added.
24
+ - **Fills the conversation area (v1.1.4)**: while the header tab is selected, the web chat now fills the whole conversation area and covers DSH's own message list and bottom composer. Switching back to "Dialogue" restores them. The header entry uses an opaque absolutely-positioned overlay (`inset: 0`, `z-index: 50`) over the conversation body; the tab row in the header stays above it and remains clickable.
25
+ - Both entries **share the same chat component** (the header entry wraps it in the full-area overlay) and the same constant partition `panel:deepseek-chat`, so login state and conversation memory are common to both; switching away from the tab releases the lease and re-entering re-acquires the same partition.
26
+ - Full-width embedded `https://chat.deepseek.com/` (Electron `<webview>` through the desktop guest-lease bridge `window.dshDesktop.browser`).
27
+ - **Last-conversation memory**: switching panels/sessions or restarting the app reopens the conversation you left, not a new chat.
28
+ - Auth pages never overwrite that memory; a dead conversation falls back to the site root.
29
+ - **Stable login session (fixed in v1.1.1)**: the guest partition is the constant `panel:deepseek-chat`; switching panels/sessions back no longer rebuilds the partition or asks for a fresh QR scan.
30
+ - **Crash containment**: if the embedded page's process dies, is destroyed, or never starts, the panel shows a Retry card — the app window no longer goes blank (fixed in v0.4.0).
31
+ - **Pure web chat (v1.1.3)**: the account status strip, account probe, 5-second polling and account-sync store are entirely removed. The panel acquires its lease and starts on mount, with no asynchronous account flow.
32
+ - Inert on the plain Web surface (`dsh web`): the site sends `frame-ancestors 'none'`, so an iframe cannot carry it, and the guest bridge only exists in the desktop shell.
33
+
34
+ > **v1.1.2 web boot crash fix**: v1.1.1 renamed the npm package to the scoped `@tianyulinfeng1/dsh-plugin-deepseek-chat`, but the client-bundle factory id in `lib/client.js` stayed the old short name `dsh-plugin-deepseek-chat`. That mismatch made the DSH Host re-execute the same bundle and throw `duplicate factory registration`, ending in `web boot: 1 entry did not activate` and a failed page boot. v1.1.2 aligns the factory id with the full package name and adds a regression assertion that the factory id must equal `package.json`'s `name`. See [docs/RELEASE_NOTES_v1.1.2.md](docs/RELEASE_NOTES_v1.1.2.md).
35
+
36
+ > **v1.1.3**: removes the account status display and adds the conversation-header "Web Chat" tab, as requested. The old main / sidebar.panellist injections, previously wrapped in one try/catch, are now three independent try/catch blocks so a single failure no longer suppresses the other entries.
37
+
38
+ > **v1.1.4**: adds a settings page (show/hide the header tab + a custom tab name, default "DeepSeek Chat"); fixes the header tab not filling the conversation area (DSH's composer was still visible below the web chat). The red-boxed title chip in the user's second screenshot is a chat.deepseek.com page element; per the user's confirmation it is left untouched — the plugin does not modify the third-party page.
39
+
40
+ > **v1.1.5 (this release)**: adds an About block to Settings (version / author / description / license / npm & GitHub links) and a "Check for updates" button (npm first, GitHub fallback, numeric semver comparison, text status + jump links, timeout and failure fallback). The empty Host half is untouched.
41
+
42
+ ## Requirements
43
+
44
+ | Item | Requirement |
45
+ |---|---|
46
+ | DSH | Desktop `0.2.2-rc.1` or newer |
47
+ | Platform | Windows / macOS / Linux desktop shell |
48
+ | git | Only for the GitHub install route (pnpm fetches the repository) |
49
+
50
+ ## Install
51
+
52
+ npm package: **`@tianyulinfeng1/dsh-plugin-deepseek-chat`** (the GitHub repository is still named `dsh-plugin-deepseek-chat`).
53
+
54
+ ### Option 1 — npm (recommended)
55
+
56
+ ```powershell
57
+ dsh plugin --profile desktop add @tianyulinfeng1/dsh-plugin-deepseek-chat
58
+ ```
59
+
60
+ You can also enter the package name `@tianyulinfeng1/dsh-plugin-deepseek-chat` in the Plugins page.
61
+
62
+ ### Option 2 — Plugins page (GitHub)
63
+
64
+ 1. Open DSH desktop and click **Plugins** in the sidebar.
65
+ 2. Click **Install a third-party plugin** above the list.
66
+ 3. Enter:
67
+
68
+ ```
69
+ github:sweet560/dsh-plugin-deepseek-chat
70
+ ```
71
+
72
+ `https://github.com/sweet560/dsh-plugin-deepseek-chat` works too.
73
+ 4. Click **Install** and wait for pnpm to finish.
74
+ 5. The plugin is enabled automatically; **DeepSeek Chat** appears in the sidebar.
75
+
76
+ ### Option 3 — CLI (GitHub)
77
+
78
+ ```powershell
79
+ dsh plugin --profile desktop add github:sweet560/dsh-plugin-deepseek-chat
80
+ ```
81
+
82
+ Then open **Plugins → Installed plugins** and make sure **DeepSeek Chat** is switched on (the CLI only installs the package).
83
+
84
+ ### Option 4 — local checkout (development)
85
+
86
+ ```powershell
87
+ dsh plugin --profile desktop add file:"<absolute path to this repository>"
88
+ ```
89
+
90
+ ## Why the web chat cannot reuse the DSH sign-in
91
+
92
+ **A pure plugin cannot make chat.deepseek.com reuse the already-signed-in DSH account.** This is an architecture limit of DSH 0.2.2-rc.1, verified against its source:
93
+
94
+ | | DSH desktop account | chat.deepseek.com web |
95
+ |---|---|---|
96
+ | Credential | platform.deepseek.com `x-dsh-auth-token` (Host-only `getPlatformSession()`) | the site's own Token (`api/v0/users/current` returns `40002 Missing Token` without it) |
97
+ | Storage | Host credential store | httpOnly cookie in the guest session |
98
+ | Exchange | **None** — zero `chat.deepseek.com` references, no SSO, no cookie injection in the whole archive | — |
99
+
100
+ - The renderer bridge `globalThis.dshDesktop` exposes only `browser.acquire/release/onOpenRequested` etc. — **no** `getAuthToken`, cookie write, or "open Platform to fetch token" API. `getAuthToken()` exists only in the desktop shell's embedded Platform view (`usage` / `top_up`) preload, main-frame + origin restricted.
101
+ - The `browserAcquire` IPC only allocates a partition/lease by workspace string; `configureSession()` sets permissions and download interception, **it injects no credentials**. The guest is forced to `sandbox / contextIsolation / webSecurity`.
102
+ - So the DSH account and the web session are unrelated; one manual QR sign-in is still required. **Since v1.1.3 even the account-status display is gone** — the panel is pure web chat.
103
+
104
+ **What went wrong in v1.1.0 (fixed in v1.1.1, account logic removed entirely in v1.1.3)**: the guest partition had been keyed to the asynchronous account probe. DSH's `getState()` can transiently fail during a reconnect or session switch; changing the partition hands the panel a brand-new cookie jar → a fresh QR scan every time you switched back. Now:
105
+
106
+ - `acquire()`'s workspace is the constant `panel:deepseek-chat`, and the conversation key is the constant `dsh-plugin-deepseek-chat:last-url`;
107
+ - no account probe, polling, state subscription or strip participates in the guest lifecycle at all;
108
+ - the guest starts on mount immediately, without waiting for any async Remote;
109
+ - popup navigation is allowlisted to `chat.deepseek.com` and `platform.deepseek.com` (HTTPS, default port).
110
+
111
+ > To also avoid re-scanning **after restarting DSH**, run [scripts/patch-dsh-persistent-partition.cjs](scripts/patch-dsh-persistent-partition.cjs) per [docs/login-persistence.md](docs/login-persistence.md) to change DSH's random in-memory partition into a deterministic `persist:` one (an `app.asar` edit — modifying the installed app, at your own risk). **It also syncs the per-file SHA256 ASAR integrity required by 0.2.2-rc.1** — a byte-only replacement (the deprecated `.mjs` script) would crash DSH on restart. It requires fully exiting DSH first. That patch preserves web cookies across restarts; it does not make the web chat reuse the DSH token.
112
+
113
+ ## Usage
114
+
115
+ - The first visit shows the chat.deepseek.com sign-in page; sign in once.
116
+ - Within one app run, switching panels or sessions keeps you signed in (fixed partition since v1.1.1).
117
+ - **Sign in again after restarting DSH**: DSH currently gives embedded browsers a random in-memory partition (`dsh-sidebar-browser-<uuid>`, no `persist:` prefix), so cookies are dropped when the process exits. This plugin does not modify DSH's installation files; to sign in once and stay signed in, apply the equal-length byte patch described in **[docs/login-persistence.md](docs/login-persistence.md)**.
118
+ - The conversation URL is stored under the fixed key `dsh-plugin-deepseek-chat:last-url`, so the last conversation is restored after a restart (while signed in and while it still exists).
119
+ - The header tab (default **"DeepSeek Chat"**) and the sidebar icon are the same web chat; switching to another tab unmounts this plugin's guest and releases the lease, and switching back reloads it (same partition, login state and conversation memory preserved).
120
+ - **Settings page**: open the DSH **Settings** dialog → "DeepSeek Chat" in the left navigation. Toggle **Show header tab** and edit **Header tab name**. The name field is empty by default, showing "DeepSeek Chat" only as a grey placeholder; click into it and type directly without deleting any default text. Turning the tab off removes the header entry but keeps the sidebar icon; leaving the name empty restores the default "DeepSeek Chat". Settings apply immediately and are stored locally.
121
+ - While the header tab is selected the web chat fills the conversation area and covers DSH's own messages/composer; clicking back to "Dialogue" restores them without losing conversation content.
122
+
123
+ ## Persistent login (optional)
124
+
125
+ DSH hands embedded browsers an **in-memory partition** (`dsh-sidebar-browser-${randomUUID()}`, no `persist:` prefix), so every app restart drops the cookies. To sign in once and stay signed in, replace that partition with a fixed `persist:` one inside `resources/app.asar` — the two statements are the same length, so the archive can be patched byte-for-byte in place.
126
+
127
+ Cause, script, verification, rollback and per-platform paths:
128
+
129
+ **→ [docs/login-persistence.md](docs/login-persistence.md)**
130
+
131
+ Note: this modifies the installed application and is outside DSH's support; a DSH update overwrites `app.asar` and the patch must be re-applied (the `Partitions` data survives). Back up first and proceed at your own risk.
132
+
133
+ ## Known limitations
134
+
135
+ - chat.deepseek.com detects the Electron embedding and occasionally shows a "usage environment is abnormal" notice. That is site-side behaviour, unrelated to this plugin.
136
+ - Desktop only; `dsh web` in a browser shows no entry.
137
+ - If the site changes its conversation URL scheme (currently `/a/chat/s/<id>`), the memory falls back to the site root.
138
+ - A pure plugin cannot reuse the DSH token, so the web chat still needs one manual sign-in on first use (see above). **Since v1.1.3 the panel shows no account status at all.**
139
+ - Restarting DSH still requires a fresh web sign-in unless the persistent-partition patch in [docs/login-persistence.md](docs/login-persistence.md) is applied.
140
+
141
+ ## Crash containment (v0.4.0)
142
+
143
+ Earlier versions could leave the whole app a blank window a second or two after opening the panel, with no crash dialog and no `crash-*.log`.
144
+
145
+ Root cause: React runs effect cleanups after it has removed the DOM, and Electron's `<webview>` throws from `getURL()` once detached. DSH treats any uncaught plugin error as `slot entry crashed in 'root'` and unmounts the root slot — the entire UI.
146
+
147
+ The current implementation guards every guest call behind an `isConnected` check and `try/catch`, reads the URL before removing the element, wraps every event handler, puts a React error boundary around the panel, listens for `render-process-gone` / `destroyed` / `did-fail-load`, and has a 15-second start watchdog. On failure the dead guest element is removed **before** the Retry card, so retrying cannot stack webviews; a listener-registration failure never starts a guest, and popup URLs are allowlisted (v1.1.0).
148
+
149
+ ## Version history
150
+
151
+ | Version | Changes |
152
+ |---|---|
153
+ | **1.1.5** | **Adds About info + Check for updates to Settings**: plugin version / author / description / license / npm & GitHub links, plus a "Check for updates" button (npm `dist-tags` first, GitHub `raw` fallback, numeric segment-by-segment version comparison, text status + jump links, 8-second timeout and failure fallbacks). Metadata constants are asserted equal to `package.json`; offline self-check passes fully (`RESULT: PASS`). |
154
+ | **1.1.4** | **Adds a settings page + makes the header tab configurable + fills the conversation area**: a `settings.section` page (show/hide header tab, custom tab name default "DeepSeek Chat", localStorage persistence, immediate re-registration for the tab row); the header entry uses an opaque absolute overlay to fill the conversation body and cover the composer. The red-boxed in-page title chip is left untouched per user confirmation. Four slot registrations, offline self-check passes fully (`RESULT: PASS`). |
155
+ | **1.1.3** | **Removes the account status display + adds a conversation-header tab**: deletes the account status strip, probe, 5-second polling and account-sync store; adds a `conversation.view` "Web Chat" header tab sharing the component and fixed partition with the sidebar/full-area entries; three slot registrations now use independent try/catch blocks. Offline self-check passes fully (`RESULT: PASS`). |
156
+ | **1.1.2** | **Fixes the v1.1.1 web boot crash (highlight)**: the client-bundle factory id did not match the npm package name, so DSH re-executed the same bundle, threw `duplicate factory registration`, and failed with `1 entry did not activate` — the whole page would not boot. The factory id in `lib/client.js` is now aligned to `@tianyulinfeng1/dsh-plugin-deepseek-chat`, with a new regression assertion that it must equal `package.json`'s `name`; 35/35 offline checks pass and all 30 client bundles scan with 0 mismatches. See [docs/RELEASE_NOTES_v1.1.2.md](docs/RELEASE_NOTES_v1.1.2.md). |
157
+ | **1.1.1** | **Fixes the "scan the QR code again on every panel switch" regression**: the guest partition and conversation key are constants; account state is display-only and never touches the guest lifecycle; a transient `unknown` is ignored; the guest no longer waits for the async probe; self-check now asserts a fixed partition and no rebuild on state churn (35 cases). Documents why a pure plugin cannot reuse the DSH token. |
158
+ | 1.1.0 | DSH `0.2.2-rc.1`: DSH account status strip; correct generated Remote envelope parsing; stricter conversation and popup URL validation; dead guest removal on failure. **This release keyed the partition to account state and broke login persistence (fixed in 1.1.1).** |
159
+ | 1.0.0 | First local release: sidebar entry, full-width chat, conversation memory, crash containment. |
160
+
161
+ ## Development
162
+
163
+ ```powershell
164
+ git clone https://github.com/sweet560/dsh-plugin-deepseek-chat.git
165
+ cd dsh-plugin-deepseek-chat
166
+ node test/check-client.mjs
167
+ ```
168
+
169
+ `test/check-client.mjs` loads `lib/client.js` in a `node:vm` sandbox with fake React/DOM/bridge objects and checks four slot registrations (sidebar / full-area panel / header tab / settings page), the config layer (defaults, type validation, persistence, subscription, dynamic re-injection), the header overlay's fill styling, factory id equals package name, Web-surface inertness, shared fixed partition across both entries, pure web chat with no account strip, URL allowlisting, conversation memory, lease release, popup allowlisting and crash containment; a mock fetch verifies metadata constants against `package.json`, semver comparison, update-payload parsing, npm/GitHub fallback, all update-state branches, and the Settings-page click flow.
170
+
171
+ ```
172
+ lib/index.js host half (empty; it only gives the client bundle a Loader entry)
173
+ lib/client.js browser half: entries, web-chat panel, full-area header overlay, settings page + config layer, about info / check-for-updates, webview lifecycle, crash containment
174
+ cordis.patch.yml bundle patch that inserts this plugin's Loader row
175
+ locale/{zh,en}.json Plugins-page title/description
176
+ icon.svg Plugins-page icon
177
+ docs/login-persistence.md optional byte patch for DSH's in-memory browser partition
178
+ test/check-client.mjs offline self-check
179
+ ```
180
+
181
+ ## Uninstall
182
+
183
+ ```powershell
184
+ dsh plugin --profile desktop remove @tianyulinfeng1/dsh-plugin-deepseek-chat
185
+ ```
186
+
187
+ ## License
188
+
189
+ [MIT](LICENSE)