@johnnren/dsh-zen 1.0.1 → 1.1.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.md +25 -1
- package/README.zh-CN.md +23 -1
- package/docs/screenshots/e2e-zen-after-altz.png +0 -0
- package/docs/screenshots/e2e-zen-auto.png +0 -0
- package/docs/screenshots/e2e-zen-chat-hide.png +0 -0
- package/docs/screenshots/e2e-zen-reply.png +0 -0
- package/docs/screenshots/e2e-zen-settings.png +0 -0
- package/docs/screenshots/e2e-zen-view.png +0 -0
- package/lib/client.js +45 -13
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -78,11 +78,24 @@ The settings panel also shows your **今日禅 / 本周禅** scores and the curr
|
|
|
78
78
|
npm install
|
|
79
79
|
npm run build # bundle src/client.ts + src/index.ts → lib/, deploy into web profile
|
|
80
80
|
npm run typecheck # tsc --noEmit against the local shims in src/dts-shim.d.ts
|
|
81
|
+
npm run e2e:zen # GUI probe against a disposable dsh-e2e instance (see e2e/)
|
|
81
82
|
```
|
|
82
83
|
|
|
83
84
|
The deploy target is `$DSH_HOME/profiles/web/node_modules` (default `~/.dsh`). Client-only
|
|
84
85
|
changes need a page refresh; host-side changes need a DSH restart.
|
|
85
86
|
|
|
87
|
+
The GUI probe needs a disposable instance started with the provider layer in
|
|
88
|
+
`e2e/profile/e2e-profile.patch.yml`, otherwise agent turns fail with `NO_ADAPTER` and the
|
|
89
|
+
live Chat surfaces cannot be exercised:
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
export CPA_API_KEY=... # cpa gateway key (see ~/.config/api-vault)
|
|
93
|
+
export DSH_E2E_PLAYWRIGHT_CORE=<path to an installed playwright-core entry>
|
|
94
|
+
dsh-e2e start --patch e2e/profile/e2e-profile.patch.yml --wait-ready
|
|
95
|
+
npm run e2e:zen
|
|
96
|
+
dsh-e2e stop
|
|
97
|
+
```
|
|
98
|
+
|
|
86
99
|
### Repository layout
|
|
87
100
|
|
|
88
101
|
```
|
|
@@ -103,8 +116,15 @@ changes need a page refresh; host-side changes need a DSH restart.
|
|
|
103
116
|
## Compatibility
|
|
104
117
|
|
|
105
118
|
- Requires DeepSeek Harness with the Web client module system (default `web` profile).
|
|
119
|
+
- **Verified against DeepSeek Harness `0.2.0-rc.2`** (see
|
|
120
|
+
[docs/issues/261011-dsh-02-compat](docs/issues/261011-dsh-02-compat/261011-dsh-02-compat.summary.md)).
|
|
106
121
|
- Slot contracts used: `conversation.view`, `conversation.session.header.actions`,
|
|
107
|
-
`settings.section`.
|
|
122
|
+
`settings.section`.
|
|
123
|
+
- Client services used: `slots`, `sessions`, `locale`, `uiConversation`.
|
|
124
|
+
- The Zen view reads the Chat target snapshot through
|
|
125
|
+
`ctx.uiConversation.binding(sessionId).target("chat")`; the current Session is derived from
|
|
126
|
+
`sessions.list` main-view retention. Both are 0.2-era contracts — re-verify them against the
|
|
127
|
+
target version's source when upgrading.
|
|
108
128
|
- **Zero permissions**: no network requests, no file system access, no external
|
|
109
129
|
services — the host face is an empty `apply()` and all data stays in browser
|
|
110
130
|
`localStorage` (`dsh.zen.*`). 无网络请求、无文件写入、无外部服务、无遥测。
|
|
@@ -121,3 +141,7 @@ can be cleared by deleting keys prefixed `dsh.zen.`.
|
|
|
121
141
|
## License
|
|
122
142
|
|
|
123
143
|
MIT — see [LICENSE](LICENSE).
|
|
144
|
+
|
|
145
|
+
## Community
|
|
146
|
+
|
|
147
|
+
- Thanks to the [LINUX DO](https://linux.do/) community for providing the discussion environment.
|
package/README.zh-CN.md
CHANGED
|
@@ -70,11 +70,23 @@ dsh plugin --profile web add @johnnren/dsh-zen
|
|
|
70
70
|
npm install
|
|
71
71
|
npm run build # 打包 src/client.ts + src/index.ts → lib/,部署到 web profile
|
|
72
72
|
npm run typecheck # 基于 src/dts-shim.d.ts 本地 shim 做 tsc --noEmit
|
|
73
|
+
npm run e2e:zen # 对一次性 dsh-e2e 实例跑 GUI 探针(见 e2e/)
|
|
73
74
|
```
|
|
74
75
|
|
|
75
76
|
部署目标为 `$DSH_HOME/profiles/web/node_modules`(默认 `~/.dsh`)。仅客户端改动刷新页面即可;
|
|
76
77
|
host 侧改动需要重启 DSH。
|
|
77
78
|
|
|
79
|
+
GUI 探针需要带 provider 层的一次性实例,否则 agent 轮次会以 `NO_ADAPTER` 失败,Zen 的实时
|
|
80
|
+
Chat 面无法被覆盖:
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
export CPA_API_KEY=... # cpa 网关 key(见 ~/.config/api-vault)
|
|
84
|
+
export DSH_E2E_PLAYWRIGHT_CORE=<已安装的 playwright-core 入口路径>
|
|
85
|
+
dsh-e2e start --patch e2e/profile/e2e-profile.patch.yml --wait-ready
|
|
86
|
+
npm run e2e:zen
|
|
87
|
+
dsh-e2e stop
|
|
88
|
+
```
|
|
89
|
+
|
|
78
90
|
### 仓库结构
|
|
79
91
|
|
|
80
92
|
```
|
|
@@ -95,8 +107,14 @@ host 侧改动需要重启 DSH。
|
|
|
95
107
|
## 兼容性
|
|
96
108
|
|
|
97
109
|
- 需要带 Web 客户端模块系统的 DeepSeek Harness(默认 `web` profile)。
|
|
110
|
+
- **已在 DeepSeek Harness `0.2.0-rc.2` 上实测通过**(见
|
|
111
|
+
[docs/issues/261011-dsh-02-compat](docs/issues/261011-dsh-02-compat/261011-dsh-02-compat.summary.md))。
|
|
98
112
|
- 使用的 slot 契约:`conversation.view`、`conversation.session.header.actions`、
|
|
99
|
-
`settings.section
|
|
113
|
+
`settings.section`。
|
|
114
|
+
- 使用的客户端服务:`slots`、`sessions`、`locale`、`uiConversation`。
|
|
115
|
+
- Zen 视图通过 `ctx.uiConversation.binding(sessionId).target("chat")` 读取 Chat 目标快照;
|
|
116
|
+
当前会话由 `sessions.list` 的 main-view 引用推导。二者都是 0.2 时代的契约,升级时请对照
|
|
117
|
+
目标版本源码重新核验。
|
|
100
118
|
- **零权限**:无网络请求、无文件写入、无外部服务——host 面是空的 `apply()`,
|
|
101
119
|
所有数据保存在浏览器 `localStorage`(`dsh.zen.*`),无遥测。
|
|
102
120
|
|
|
@@ -112,3 +130,7 @@ dsh plugin --profile web remove @johnnren/dsh-zen
|
|
|
112
130
|
## License
|
|
113
131
|
|
|
114
132
|
MIT — 见 [LICENSE](LICENSE)。
|
|
133
|
+
|
|
134
|
+
## 社区
|
|
135
|
+
|
|
136
|
+
- 感谢 [LINUX DO](https://linux.do/) 社区提供的交流环境。
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/client.js
CHANGED
|
@@ -919,11 +919,29 @@ function renderMarkdown(MarkdownText, text) {
|
|
|
919
919
|
return import_react.default.createElement("div", { style: { whiteSpace: "pre-wrap", wordBreak: "break-word" } }, text);
|
|
920
920
|
}
|
|
921
921
|
var ZenView = import_react.default.memo(function ZenView2(props) {
|
|
922
|
-
const { useSession, sessionId, t, foregroundStore, MarkdownText, zenSettingsStore } = props;
|
|
922
|
+
const { useSession, sessionId, t, foregroundStore, MarkdownText, zenSettingsStore, bindChat } = props;
|
|
923
923
|
const rawRunning = useSession((s) => s.running);
|
|
924
924
|
const blank = useSession((s) => s.blank);
|
|
925
|
-
const
|
|
926
|
-
|
|
925
|
+
const bindChatRef = import_react.default.useRef(bindChat);
|
|
926
|
+
bindChatRef.current = bindChat;
|
|
927
|
+
const chatSource = import_react.default.useMemo(() => {
|
|
928
|
+
try {
|
|
929
|
+
return bindChatRef.current();
|
|
930
|
+
} catch {
|
|
931
|
+
return null;
|
|
932
|
+
}
|
|
933
|
+
}, [sessionId]);
|
|
934
|
+
const subscribeChat = import_react.default.useCallback(
|
|
935
|
+
(onChange) => chatSource ? chatSource.subscribe(onChange) : () => {
|
|
936
|
+
},
|
|
937
|
+
[chatSource]
|
|
938
|
+
);
|
|
939
|
+
const getChat = import_react.default.useCallback(
|
|
940
|
+
() => chatSource ? chatSource.getSnapshot() : void 0,
|
|
941
|
+
[chatSource]
|
|
942
|
+
);
|
|
943
|
+
const chat = import_react.default.useSyncExternalStore(subscribeChat, getChat);
|
|
944
|
+
const runningCalls = chat?.legacy?.runningCalls;
|
|
927
945
|
const openState = useSession((s) => s?.openState);
|
|
928
946
|
const isLoading = !blank && (openState === "cold" || openState === "loading");
|
|
929
947
|
const [statusRunning, setStatusRunning] = import_react.default.useState(rawRunning);
|
|
@@ -1147,19 +1165,22 @@ body[data-chat-hide="on"] [data-chat-flow-kind="compaction"] { display: none !im
|
|
|
1147
1165
|
body[data-chat-hide="on"] [data-chat-flow-kind="model-retry"] { display: none !important; }
|
|
1148
1166
|
body[data-chat-hide="on"] [data-chat-flow-kind="turn-error"] { display: none !important; }
|
|
1149
1167
|
body[data-chat-hide="on"] [data-chat-flow-kind="turn-max-tokens"] { display: none !important; }
|
|
1168
|
+
/* 0.2 turn-level process disclosure ("\u5DF2\u5904\u7406 N \u6B65") \u2014 hide the control with the rest of the process */
|
|
1169
|
+
body[data-chat-hide="on"] [data-chat-flow-kind="turn-process"] { display: none !important; }
|
|
1150
1170
|
|
|
1151
1171
|
/* Hide reasoning rows inside assistant-step */
|
|
1152
1172
|
body[data-chat-hide="on"] [data-chat-flow-kind="assistant-step"] [data-variant="think"] { display: none !important; }
|
|
1153
1173
|
|
|
1154
|
-
/* Hide assistant-step that only contains think (no reply) \u2014 prevents extra flex gap
|
|
1155
|
-
|
|
1174
|
+
/* Hide assistant-step that only contains think (no reply) \u2014 prevents extra flex gap.
|
|
1175
|
+
Hash-agnostic: CSS-module class names end in _body but their prefix changes per build. */
|
|
1176
|
+
body[data-chat-hide="on"] [data-chat-flow-kind="assistant-step"]:has([class*="_body"] > [data-variant="think"]:only-child) { display: none !important; }
|
|
1156
1177
|
|
|
1157
|
-
/* Collapse context/compaction rows inside user messages (they have padding:2px 0) */
|
|
1158
|
-
body[data-chat-hide="on"]
|
|
1159
|
-
body[data-chat-hide="on"]
|
|
1178
|
+
/* Collapse empty context/compaction rows inside user messages (they have padding:2px 0) */
|
|
1179
|
+
body[data-chat-hide="on"] [class*="_contextRow"]:empty,
|
|
1180
|
+
body[data-chat-hide="on"] [class*="_compactionRow"]:empty { display: none !important; }
|
|
1160
1181
|
|
|
1161
1182
|
/* Zero out gap in AssistantMarkdown body when reasoning hidden */
|
|
1162
|
-
body[data-chat-hide="on"] [data-chat-flow-kind="assistant-step"]
|
|
1183
|
+
body[data-chat-hide="on"] [data-chat-flow-kind="assistant-step"] [class*="_body"]:has([data-variant="think"]) { gap: 0 !important; }
|
|
1163
1184
|
`;
|
|
1164
1185
|
if (typeof document !== "undefined" && !document.querySelector('style[data-plugin-css="dsh-zen/chat-hide"]')) {
|
|
1165
1186
|
const tag = document.createElement("style");
|
|
@@ -1558,14 +1579,21 @@ var ZenSettingsSection = import_react3.default.memo(function ZenSettingsSection2
|
|
|
1558
1579
|
|
|
1559
1580
|
// src/client.ts
|
|
1560
1581
|
var name = "zen";
|
|
1561
|
-
var inject = ["slots", "sessions", "locale"];
|
|
1582
|
+
var inject = ["slots", "sessions", "locale", "uiConversation"];
|
|
1583
|
+
function resolveCurrentSessionId(snap, previousId) {
|
|
1584
|
+
if (previousId && (snap.byId[previousId]?.retainedBy?.mainView ?? 0) > 0) return previousId;
|
|
1585
|
+
for (const row of Object.values(snap.byId)) {
|
|
1586
|
+
if ((row?.retainedBy?.mainView ?? 0) > 0) return row.id;
|
|
1587
|
+
}
|
|
1588
|
+
return null;
|
|
1589
|
+
}
|
|
1562
1590
|
function initAutoZenSwitcher(ctx, zenSettingsStore) {
|
|
1563
1591
|
const sessions = ctx.sessions;
|
|
1564
1592
|
let prevRunning = null;
|
|
1565
1593
|
let prevSessionId = null;
|
|
1566
1594
|
function check() {
|
|
1567
1595
|
const snap = sessions.list.getSnapshot();
|
|
1568
|
-
const currentId = snap
|
|
1596
|
+
const currentId = resolveCurrentSessionId(snap, prevSessionId);
|
|
1569
1597
|
const session = currentId ? snap.byId[currentId] : null;
|
|
1570
1598
|
const running = session?.running ?? false;
|
|
1571
1599
|
if (currentId !== prevSessionId) {
|
|
@@ -1616,10 +1644,14 @@ function apply(ctx) {
|
|
|
1616
1644
|
order: 5,
|
|
1617
1645
|
label: () => t("view.zen"),
|
|
1618
1646
|
locale: NS,
|
|
1619
|
-
inject: (
|
|
1647
|
+
inject: (sessionId) => ({
|
|
1620
1648
|
foregroundStore,
|
|
1621
1649
|
MarkdownText,
|
|
1622
|
-
zenSettingsStore
|
|
1650
|
+
zenSettingsStore,
|
|
1651
|
+
// The Chat target snapshot is an independently activated Conversation
|
|
1652
|
+
// view; subscribing through this source also activates the target, so
|
|
1653
|
+
// Zen keeps reading Chat data while it is the visible view.
|
|
1654
|
+
bindChat: () => ctx.uiConversation.binding(sessionId).target("chat")
|
|
1623
1655
|
})
|
|
1624
1656
|
}, ZenView));
|
|
1625
1657
|
ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@johnnren/dsh-zen",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Zen Mode view tab + foreground time tracker for DeepSeek Harness: a calm minimal surface (status message, latest user message, live activity hints, markdown AI reply, one-line turn stats) while the agent works, with screen-watching time tracking, daily/weekly Zen scores, a chat-hide toggle, auto enter/exit and an Alt+Z shortcut — pure client-side, no network. dsh-zen 禅模式插件:智能体后台运行时提供极简的 Zen 视图标签页(状态文案、用户消息、动态提示、Markdown 最终回复、单行轮次统计),并统计前台盯屏时长、给出每日/每周禅值,支持隐藏中间过程、自动进出禅与 Alt+Z 快捷键——纯前端、无网络请求。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
],
|
|
23
23
|
"scripts": {
|
|
24
24
|
"build": "node build.mjs",
|
|
25
|
-
"typecheck": "tsc --noEmit"
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"e2e:zen": "dsh-e2e run e2e/zen-view.mjs"
|
|
26
27
|
},
|
|
27
28
|
"keywords": [
|
|
28
29
|
"dsh",
|
|
@@ -52,10 +53,10 @@
|
|
|
52
53
|
},
|
|
53
54
|
"client": {
|
|
54
55
|
"inject": [
|
|
55
|
-
"@deepseek-ai/dsh-
|
|
56
|
+
"@deepseek-ai/dsh-api-session-controller",
|
|
57
|
+
"@deepseek-ai/dsh-client-locale",
|
|
56
58
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
57
|
-
"@deepseek-ai/dsh-client-ui-settings"
|
|
58
|
-
"@deepseek-ai/dsh-client-locale"
|
|
59
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
59
60
|
],
|
|
60
61
|
"platform": "web"
|
|
61
62
|
},
|