dsh-ui-tweaks 0.10.3 → 0.11.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 +15 -0
- package/README.md +4 -1
- package/lib/client.js +145 -1
- package/lib/client.js.map +1 -1
- package/lib/config.js +5 -1
- package/lib/config.js.map +1 -1
- package/lib/types/client/cachehit.d.ts +30 -0
- package/lib/types/client/cachehit.d.ts.map +1 -0
- package/lib/types/client/index.d.ts +6 -0
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/config.d.ts +11 -0
- package/lib/types/config.d.ts.map +1 -1
- package/package.json +2 -2
package/README.en.md
CHANGED
|
@@ -42,6 +42,7 @@ A [DeepSeek Harness](https://deepseek-harness.github.io/deepseek-harness/) (DSH)
|
|
|
42
42
|
- **System notifications** (Web Notifications API) — desktop-level; **click one to jump straight to that session**; permission is requested from the settings toggle's click gesture; the OS bark and the chime are mutually exclusive so they never double-ring;
|
|
43
43
|
- **Chime** — a two-note WebAudio motif synthesized in-process (rising = done, falling = needs you); no audio assets.
|
|
44
44
|
- "Only when hidden" defaults on (no nagging while you watch the page); the first snapshot only arms the baseline (a page reload never fires a burst); events fire on transitions with a 2s per-session+kind cooldown (reconnect flicker absorbed); subagent child rows are skipped (the parent carries the turn). A **Test** button in Settings previews permission and channels in one click.
|
|
45
|
+
- **Precise cache hit (toggleable, off by default)** — DSH's stats line shows the cache-hit share as a bare integer ("Cache hit 96%"). When enabled, the figure is rewritten to two decimals ("Cache hit 96.35%") and computed from the raw token buckets — cache reads ÷ billed input (uncached input + cache reads + cache writes) — the same source as the stock number, just unrounded; a full hit shows 100.00%, and with no billed input the group is absent anyway. The toggle lives in the Layout settings group; turning it off restores the stock figure.
|
|
45
46
|
|
|
46
47
|
All changes apply **live** — no reload needed. The same values can be hand-edited in the settings document:
|
|
47
48
|
|
|
@@ -55,6 +56,7 @@ ui-tweaks:
|
|
|
55
56
|
archiveManagerEnabled: true # defaults to false (off); set true to show the Archive page
|
|
56
57
|
initCommandEnabled: true # defaults to false (off); set true to register the /init slash command
|
|
57
58
|
whaleIndicatorEnabled: true # defaults to false (off); set true to enable the whale indicator
|
|
59
|
+
preciseCacheHitEnabled: true # defaults to false (off); set true to enable the two-decimal cache-hit figure
|
|
58
60
|
notificationsEnabled: true # defaults to false (off); set true to enable task alerts (event filters & channels are per-item toggles in Settings)
|
|
59
61
|
```
|
|
60
62
|
|
|
@@ -120,6 +122,19 @@ npx -y @deepseek-ai/dsh plugin --profile web add . # bundle install from
|
|
|
120
122
|
column grid and any right-sidebar layout push (`#root` margin-right);
|
|
121
123
|
colors ride DSH theme tokens (`--dsw-alias-*`) for correct light/dark
|
|
122
124
|
rendering.
|
|
125
|
+
- **Precise cache hit** (`src/client/cachehit.tsx`) mounts a null-rendering
|
|
126
|
+
seat in the `conversation.composer.dock` slot (the band hosting the stock
|
|
127
|
+
stats line) and reads the session's token usage through the framework's
|
|
128
|
+
fifth standard hook, `useProjection('tokenUsage')` — the disjoint
|
|
129
|
+
uncached-input / cache-read / cache-write / output buckets. It computes
|
|
130
|
+
`cache reads ÷ (uncached input + cache reads + cache writes)`, formats it
|
|
131
|
+
with `.toFixed(2)`, and rewrites the stats line's "Cache hit N%" /
|
|
132
|
+
「缓存命中 N%」span in place — layout, truncation and tooltip behavior stay
|
|
133
|
+
DSH's own. A MutationObserver on the band re-applies whenever React repaints
|
|
134
|
+
the line (writes are idempotent, so the loop settles immediately); toggling
|
|
135
|
+
off or switching sessions restores the original texts. Registration follows
|
|
136
|
+
the whale's on-demand choreography: mounted only while
|
|
137
|
+
`preciseCacheHitEnabled` is on.
|
|
123
138
|
|
|
124
139
|
## License
|
|
125
140
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# dsh-ui-tweaks
|
|
2
2
|
|
|
3
|
-
[DeepSeek Harness](https://deepseek-harness.github.io/deepseek-harness/)(DSH)Web UI 插件:在设置面板中实时调整对话界面——字体大小、表格样式、对话框宽度、可开关的对话时间线、**GitBar**(输入框工具行内的 git
|
|
3
|
+
[DeepSeek Harness](https://deepseek-harness.github.io/deepseek-harness/)(DSH)Web UI 插件:在设置面板中实时调整对话界面——字体大小、表格样式、对话框宽度、可开关的对话时间线、**GitBar**(输入框工具行内的 git 状态胶囊:分支在权限旁、差异在模型前),可开关的**归档管理**(设置中的「归档」页面:查看、恢复或彻底删除已归档会话),可开关的**任务提醒**(会话完成或需要交互时,通过标签页标题闪烁 / 系统通知 / 提示音把你唤回来),以及**缓存命中率两位小数**(把输入框下方统计条的缓存命中百分比改写为精确值)。
|
|
4
4
|
|
|
5
5
|
## 预览
|
|
6
6
|
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
- **系统通知**(Web Notifications API):桌面级通知,**点击直达对应会话**;权限申请挂在设置开关的点击手势上;系统响铃与自有提示音互斥,绝不双重响;
|
|
46
46
|
- **提示音**:WebAudio 现场合成的双音动机——上行=完成、下行=需要你处理,无音频资源文件。
|
|
47
47
|
- 「仅页面不可见时」默认开启(正盯着页面时不打扰);首帧快照只武装不触发(刷新页面不刷屏);只在跳变沿触发 + 同会话同类事件 2 秒冷却(防重连抖动);子代理子会话不计(父会话承载整轮)。设置里有「测试」按钮,一键预览权限申请与通道效果。
|
|
48
|
+
- **缓存命中率两位小数(可开关,默认关闭)**:DSH 原生统计条里的缓存命中只显示整数百分比(如「缓存命中 96%」)。开启后改写为两位小数(如「缓存命中 96.35%」),且**直接用原始 token 数计算**——缓存读取 ÷ 计费输入(未缓存输入 + 缓存读取 + 缓存写入),与原生数字同源、但不再取整;完全命中显示 100.00%,无计费输入时该组本就不显示。开关位于设置的「布局」区,关闭即恢复原样。
|
|
48
49
|
|
|
49
50
|
所有修改**即时生效**,无需刷新。同一份配置也可以直接在设置文档里手改:
|
|
50
51
|
|
|
@@ -58,6 +59,7 @@ ui-tweaks:
|
|
|
58
59
|
archiveManagerEnabled: true # 默认 false(关闭),设为 true 开启「归档」页面
|
|
59
60
|
initCommandEnabled: true # 默认 false(关闭),设为 true 开启 /init 斜杠命令
|
|
60
61
|
whaleIndicatorEnabled: true # 默认 false(关闭),设为 true 开启鲸鱼指示器
|
|
62
|
+
preciseCacheHitEnabled: true # 默认 false(关闭),设为 true 开启缓存命中率两位小数
|
|
61
63
|
notificationsEnabled: true # 默认 false(关闭),设为 true 开启任务提醒(事件过滤与三个通道在设置里逐项开关)
|
|
62
64
|
# suggestModel: 'provider:model' # 可选:指定生成提交说明的模型
|
|
63
65
|
```
|
|
@@ -111,6 +113,7 @@ npx -y @deepseek-ai/dsh plugin --profile web add . # 从本目录作为 b
|
|
|
111
113
|
- **MCP 管理**(服务端 `src/mcp.ts` + 浏览器端 `src/client/mcp.tsx`):同源路由 `/_dsh/ui-tweaks/mcp`。**列表**枚举 `ctx.loader.entries()` 中 `@deepseek-ai/dsh-mcp-client` 实例(id / config / fiber 状态:active=2、failed=3 等)并按 `mcp__<serverName>__` 前缀从工具注册表统计工具。**重启**调用 `entry.fiber.restart()`(仅运行时)。**添加 / 编辑 / 删除 / 启用停用**通过 `yaml`(eemeli)的 Document API 直接编辑 profile 的 `cordis.patch.yml`(保留注释与未知补丁结构,原子写 tmp+rename),随后由 DSH 内置的 `watchUserPatches` 热重载监视器重新应用补丁——`cordis-plugin-include` 对根组做**增量** `root.update`,因此只有被改动的 MCP 实例会重启,其它不受影响;环境变量值返回给同源浏览器(本机配置编辑需要),YAML 模式在服务端用 `yaml.parse` + 白名单校验。
|
|
112
114
|
- **鲸鱼指示器**(`src/client/whale.tsx`):挂在 `conversation.input.dock`(输入框卡片上方的整行插槽)。dock 行本身比卡片宽(卡片被 InputBar root 以 `--dsh-composer-card-max-width` 封顶居中、两侧留 `--dsh-composer-side-clearance`),因此鲸鱼行**复刻卡片的几何**——同 max-width、同样居中、同样侧留白——再右对齐 + 6px `translateY`,鲸鱼恰好「骑」在卡片右上角(Claude Desktop 小螃蟹位置),自定义对话框宽度时也自动跟随。开关走与 /init 相同的「按需注册」编排——`whaleIndicatorEnabled` 打开时才注册插槽与样式,关闭即卸载。工作状态 = 会话列表 feed 中当前会话的 `running`(`useSyncExternalStore` 直订)∪ 输入机 `phase` 的 claimed/submitting;鲸鱼 SVG 路径内置为常量,挂载时以 `[class*="brandMark"]` 从侧边栏实时徽标尝试刷新(class 前缀是构建哈希,按后缀匹配以抗版本变化),取不到则回退内置几何。
|
|
113
115
|
- **任务提醒**(`src/client/notifier.ts`):纯逻辑模块(无 React),在 `ctx.effect` 中直订 `ctx.sessions.list` 快照流(鲸鱼同款数据源),对全部非空、非子代理会话做前后对比:`running` true→false 且无挂起交互 → 完成事件;`pendingInteraction`('approval' / 'plan-review' / 'question',即侧边栏黄点分类)出现 → 交互事件;后台会话的宿主 `completed` 绿点升沿同样计为完成。三通道各自静默降级——标题闪烁用 `setInterval` 交替写 `document.title`,`focus`/`visibilitychange` 时恢复;系统通知带 `tag` 去重、`onclick` 里 `window.focus()` + `sessionsService.open(id)` 直达会话、`silent` 跟随提示音开关避免双重响铃;提示音由 WebAudio 振荡器现场合成双音包络。防打扰:首帧只武装基线、只在跳变沿触发、同会话同类 2s 冷却;「仅页面不可见时」等开关经 `readState` 每拍重读实时生效,改动无需重装监视器。
|
|
116
|
+
- **缓存命中率两位小数**(`src/client/cachehit.tsx`):挂在 `conversation.composer.dock`(输入框卡片下方承载原生统计条的横条)的**空渲染座位**——组件本身不画任何东西,只通过框架第五标准 hook `useProjection('tokenUsage')` 读取会话的 token 用量投影(未缓存输入 / 缓存读取 / 缓存写入 / 输出四个不相交桶),按 `缓存读取 ÷ (未缓存输入 + 缓存读取 + 缓存写入)` 算出精确占比后 `.toFixed(2)`,再把统计条里匹配「缓存命中 N%」/ "Cache hit N%" 的 span 原地改写为两位小数——布局、截断省略与 tooltip 行为全部保留 DSH 原样。一个 MutationObserver 监听统计条子树,React 重绘统计行时自动重打(写入幂等,改写一次后即收敛);开关关闭或会话切换时恢复原始文本并断开监听。注册编排与鲸鱼一致:`preciseCacheHitEnabled` 打开才挂载,关闭即卸载。
|
|
114
117
|
|
|
115
118
|
## 协议
|
|
116
119
|
|
package/lib/client.js
CHANGED
|
@@ -219,6 +219,112 @@ function ArchiveSection({ controller, t, sessionsService, useSessions, useWorksp
|
|
|
219
219
|
}) })] }) }));
|
|
220
220
|
}
|
|
221
221
|
};
|
|
222
|
+
__modules["./cachehit.js"] = function(module, exports, require, __load_) {
|
|
223
|
+
"use strict";
|
|
224
|
+
/**
|
|
225
|
+
* dsh-ui-tweaks — precise cache-hit readout (browser half).
|
|
226
|
+
*
|
|
227
|
+
* Rewrites the cache-hit figure in the composer stats line under the input
|
|
228
|
+
* box ("缓存命中 96%" / "Cache hit 96%") to two decimal places ("96.35%").
|
|
229
|
+
* DSH rounds the share to an integer before display (adding decimals only to
|
|
230
|
+
* avoid a false 100%); the exact figure needs the raw token buckets, which
|
|
231
|
+
* this seat reads through the framework's per-session projection hook
|
|
232
|
+
* (`useProjection('tokenUsage')`) — the same durable whole-log totals the
|
|
233
|
+
* stock number is computed from.
|
|
234
|
+
*
|
|
235
|
+
* - Mounted in `conversation.composer.dock` (the band under the composer card
|
|
236
|
+
* that hosts the shipped stats line), registered only while the
|
|
237
|
+
* `preciseCacheHitEnabled` toggle is on — off costs nothing. The entry
|
|
238
|
+
* renders nothing itself: it is a live reader that patches the stock span's
|
|
239
|
+
* text in place, so layout, truncation and tooltip behavior stay DSH's own.
|
|
240
|
+
* - A MutationObserver re-applies the precise figure whenever React repaints
|
|
241
|
+
* the line (token updates, group churn); writes are idempotent — a rewrite
|
|
242
|
+
* only happens when the text actually differs — so the loop settles after
|
|
243
|
+
* one pass. Toggling off restores the original texts.
|
|
244
|
+
* @module dsh-ui-tweaks/client/cachehit
|
|
245
|
+
*/
|
|
246
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
247
|
+
exports.PreciseCacheHitEntry = PreciseCacheHitEntry;
|
|
248
|
+
const react_1 = require("react");
|
|
249
|
+
/** Whole-span shape of the stock cache-hit group (zh + en locales). */
|
|
250
|
+
const CACHE_HIT_SPAN_PATTERN = /^\s*(?:缓存命中|Cache hit)\s+\d+(?:\.\d+)?%\s*$/;
|
|
251
|
+
/** The trailing percentage inside that label — the only part rewritten. */
|
|
252
|
+
const PERCENT_IN_SPAN_PATTERN = /\d+(?:\.\d+)?%(?=\s*$)/;
|
|
253
|
+
/**
|
|
254
|
+
* Sum the three disjoint prompt-side billing buckets — DSH's own denominator
|
|
255
|
+
* for the cache-hit share (`uncachedInput + cacheRead + cacheWrite`).
|
|
256
|
+
*/
|
|
257
|
+
function billedInputTokens(usage) {
|
|
258
|
+
return usage.uncachedInputTokens + usage.cacheReadTokens + usage.cacheWriteTokens;
|
|
259
|
+
}
|
|
260
|
+
/** Session-scoped composer-dock seat that keeps the stock cache-hit figure at two decimals. */
|
|
261
|
+
function PreciseCacheHitEntry({ useProjection }) {
|
|
262
|
+
// The raw cumulative usage; undefined until the host's baseline/frame
|
|
263
|
+
// carries the key — exactly when the stock line first shows the group.
|
|
264
|
+
const usage = useProjection('tokenUsage');
|
|
265
|
+
(0, react_1.useEffect)(() => {
|
|
266
|
+
const bands = document.querySelectorAll('[data-slot="conversation.composer.dock"]');
|
|
267
|
+
if (bands.length === 0)
|
|
268
|
+
return;
|
|
269
|
+
/** Original texts of spans we rewrote, restored on cleanup. */
|
|
270
|
+
const patched = new Map();
|
|
271
|
+
/**
|
|
272
|
+
* Two-decimal share over the raw buckets; null while there is nothing
|
|
273
|
+
* precise to show (projection absent, or no billed input — the stock line
|
|
274
|
+
* omits the group in that case too).
|
|
275
|
+
*/
|
|
276
|
+
const precisePercent = () => {
|
|
277
|
+
if (usage === undefined)
|
|
278
|
+
return null;
|
|
279
|
+
const billed = billedInputTokens(usage);
|
|
280
|
+
if (!(billed > 0))
|
|
281
|
+
return null;
|
|
282
|
+
return ((usage.cacheReadTokens / billed) * 100).toFixed(2);
|
|
283
|
+
};
|
|
284
|
+
const apply = () => {
|
|
285
|
+
const precise = precisePercent();
|
|
286
|
+
for (const band of bands) {
|
|
287
|
+
for (const el of band.querySelectorAll('span')) {
|
|
288
|
+
const current = el.textContent ?? '';
|
|
289
|
+
if (!CACHE_HIT_SPAN_PATTERN.test(current))
|
|
290
|
+
continue;
|
|
291
|
+
if (precise === null) {
|
|
292
|
+
// Projection gone (session switch race): undo any rewrite so the
|
|
293
|
+
// stock integer shows again instead of a stale figure.
|
|
294
|
+
const original = patched.get(el);
|
|
295
|
+
if (original !== undefined && original !== current)
|
|
296
|
+
el.textContent = original;
|
|
297
|
+
patched.delete(el);
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
if (!patched.has(el))
|
|
301
|
+
patched.set(el, current);
|
|
302
|
+
const rewritten = current.replace(PERCENT_IN_SPAN_PATTERN, `${precise}%`);
|
|
303
|
+
if (rewritten !== current)
|
|
304
|
+
el.textContent = rewritten;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
apply();
|
|
309
|
+
// React owns these text nodes: every repaint of the line re-triggers us,
|
|
310
|
+
// and our own idempotent write settles after a single extra pass.
|
|
311
|
+
const observer = new MutationObserver(apply);
|
|
312
|
+
for (const band of bands) {
|
|
313
|
+
observer.observe(band, { childList: true, characterData: true, subtree: true });
|
|
314
|
+
}
|
|
315
|
+
return () => {
|
|
316
|
+
observer.disconnect();
|
|
317
|
+
// Toggle-off/unmount must not leave a stale precise figure behind.
|
|
318
|
+
for (const [el, original] of patched) {
|
|
319
|
+
if ((el.textContent ?? '') !== original)
|
|
320
|
+
el.textContent = original;
|
|
321
|
+
}
|
|
322
|
+
patched.clear();
|
|
323
|
+
};
|
|
324
|
+
}, [usage]);
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
222
328
|
__modules["./gitbar.js"] = function(module, exports, require, __load_) {
|
|
223
329
|
"use strict";
|
|
224
330
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -2017,6 +2123,7 @@ const gitbar_tsx_1 = __load_("./gitbar.js");
|
|
|
2017
2123
|
const archive_tsx_1 = __load_("./archive.js");
|
|
2018
2124
|
const mcp_tsx_1 = __load_("./mcp.js");
|
|
2019
2125
|
const whale_tsx_1 = __load_("./whale.js");
|
|
2126
|
+
const cachehit_tsx_1 = __load_("./cachehit.js");
|
|
2020
2127
|
const notifier_ts_1 = __load_("./notifier.js");
|
|
2021
2128
|
const NS = 'ui-tweaks';
|
|
2022
2129
|
const SETTINGS_ROUTE = '/_dsh/ui-tweaks/settings';
|
|
@@ -2129,6 +2236,10 @@ const en = {
|
|
|
2129
2236
|
whaleIndicatorHint: 'A little whale above the input box: translucent while idle, swimming while the model works.',
|
|
2130
2237
|
whaleIndicatorOn: 'On',
|
|
2131
2238
|
whaleIndicatorOff: 'Off',
|
|
2239
|
+
preciseCacheHit: 'Precise cache hit',
|
|
2240
|
+
preciseCacheHitHint: 'Rewrites the cache-hit figure in the stats line under the input box to two decimal places (e.g. 96.35%), computed from the raw cached-read / cached-write / uncached-input token buckets instead of the stock rounded integer.',
|
|
2241
|
+
preciseCacheHitOn: 'On',
|
|
2242
|
+
preciseCacheHitOff: 'Off',
|
|
2132
2243
|
sectionNotifications: 'Task alerts',
|
|
2133
2244
|
notifications: 'Enable alerts',
|
|
2134
2245
|
notificationsHint: 'Call you back while the tab is in the background: a session finishes its turn, or one starts waiting for your approval, plan review or answer. The switches below apply only while this is on.',
|
|
@@ -2330,6 +2441,10 @@ const zh = {
|
|
|
2330
2441
|
whaleIndicatorHint: '输入框上方的小鲸鱼:空闲时半透明静止,模型工作时开始游泳动画。',
|
|
2331
2442
|
whaleIndicatorOn: '开启',
|
|
2332
2443
|
whaleIndicatorOff: '关闭',
|
|
2444
|
+
preciseCacheHit: '缓存命中率两位小数',
|
|
2445
|
+
preciseCacheHitHint: '把输入框下方统计条里的缓存命中百分比改写为两位小数(如 96.35%)——用原始 token 数(缓存读取 ÷ 计费输入)计算,而不是 DSH 取整后的整数。',
|
|
2446
|
+
preciseCacheHitOn: '开启',
|
|
2447
|
+
preciseCacheHitOff: '关闭',
|
|
2333
2448
|
sectionNotifications: '任务提醒',
|
|
2334
2449
|
notifications: '启用提醒',
|
|
2335
2450
|
notificationsHint: '标签页在后台时唤你回来:会话完成了任务,或开始等待你的审批、计划确认或回答。下方开关仅在总开关开启时生效。',
|
|
@@ -2465,6 +2580,7 @@ function resolveValue(value) {
|
|
|
2465
2580
|
mcpManagerEnabled: value?.mcpManagerEnabled ?? false,
|
|
2466
2581
|
initCommandEnabled: value?.initCommandEnabled ?? false,
|
|
2467
2582
|
whaleIndicatorEnabled: value?.whaleIndicatorEnabled ?? false,
|
|
2583
|
+
preciseCacheHitEnabled: value?.preciseCacheHitEnabled ?? false,
|
|
2468
2584
|
notificationsEnabled: value?.notificationsEnabled ?? false,
|
|
2469
2585
|
notifyOnlyWhenHidden: value?.notifyOnlyWhenHidden ?? true,
|
|
2470
2586
|
notifyOnComplete: value?.notifyOnComplete ?? true,
|
|
@@ -2942,6 +3058,9 @@ function SettingsSection({ controller, t }) {
|
|
|
2942
3058
|
const setWhaleIndicator = (value) => {
|
|
2943
3059
|
void controller.set('whaleIndicatorEnabled', value).then(() => { setStatus('applied'); }).catch(() => { setStatus('unavailable'); });
|
|
2944
3060
|
};
|
|
3061
|
+
const setPreciseCacheHit = (value) => {
|
|
3062
|
+
void controller.set('preciseCacheHitEnabled', value).then(() => { setStatus('applied'); }).catch(() => { setStatus('unavailable'); });
|
|
3063
|
+
};
|
|
2945
3064
|
/** Master switch; enabling also asks for notification permission inside this click gesture. */
|
|
2946
3065
|
const setNotifications = (value) => {
|
|
2947
3066
|
if (value)
|
|
@@ -2995,7 +3114,7 @@ function SettingsSection({ controller, t }) {
|
|
|
2995
3114
|
commitFontSize(event.target.value); } }), (0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "+", disabled: !writable || resolved.fontSize >= MAX_FONT_SIZE, onClick: () => { stepFontSize(1); }, children: "+" })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: 'dut-btn' + (resolved.fontSize === DEFAULT_FONT_SIZE ? ' dut-btn-active' : ''), disabled: !writable, onClick: () => { reset('fontSize'); }, children: t('defaultAction') })] })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('lineHeight'), (0, jsx_runtime_1.jsx)(Hint, { text: t('lineHeightHint') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dut-controls", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dut-stepper", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "\u2212", disabled: !writable || resolved.lineHeight <= MIN_LINE_HEIGHT, onClick: () => { stepLineHeight(-2); }, children: "\u2212" }), (0, jsx_runtime_1.jsx)("input", { type: "number", min: MIN_LINE_HEIGHT, max: MAX_LINE_HEIGHT, step: 2, value: lineHeightDraft, disabled: !writable, onChange: (event) => { setLineHeightDraft(event.target.value); }, onBlur: (event) => { commitLineHeight(event.target.value); }, onKeyDown: (event) => { if (event.key === 'Enter')
|
|
2996
3115
|
commitLineHeight(event.target.value); } }), (0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "+", disabled: !writable || resolved.lineHeight >= MAX_LINE_HEIGHT, onClick: () => { stepLineHeight(2); }, children: "+" })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: 'dut-btn' + (resolved.lineHeight === DEFAULT_LINE_HEIGHT ? ' dut-btn-active' : ''), disabled: !writable, onClick: () => { reset('lineHeight'); }, children: t('defaultAction') })] })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('codeFontSize'), (0, jsx_runtime_1.jsx)(Hint, { text: t('codeFontSizeHint') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dut-controls", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dut-stepper", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "\u2212", disabled: !writable || resolved.codeFontSize <= MIN_CODE_FONT_SIZE, onClick: () => { stepCodeSize(-1); }, children: "\u2212" }), (0, jsx_runtime_1.jsx)("input", { type: "number", min: MIN_CODE_FONT_SIZE, max: MAX_CODE_FONT_SIZE, step: 1, value: codeDraft, disabled: !writable, onChange: (event) => { setCodeDraft(event.target.value); }, onBlur: (event) => { commitCodeSize(event.target.value); }, onKeyDown: (event) => { if (event.key === 'Enter')
|
|
2997
3116
|
commitCodeSize(event.target.value); } }), (0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "+", disabled: !writable || resolved.codeFontSize >= MAX_CODE_FONT_SIZE, onClick: () => { stepCodeSize(1); }, children: "+" })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: 'dut-btn' + (resolved.codeFontSize === DEFAULT_CODE_FONT_SIZE ? ' dut-btn-active' : ''), disabled: !writable, onClick: () => { resetCodeSize(); }, children: t('defaultAction') })] })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('tableStyle'), (0, jsx_runtime_1.jsx)(Hint, { text: t('tableStyleHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.tableStyle === 'claude' ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { pickTableStyle('claude'); }, children: t('tableStyleClaude') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.tableStyle === 'default' ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { pickTableStyle('default'); }, children: t('tableStyleDefault') })] }) })] }) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dut-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dut-section-label", children: t('sectionLayout') }), (0, jsx_runtime_1.jsxs)("div", { className: "dut-field", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('dialogWidth'), (0, jsx_runtime_1.jsx)(Hint, { text: t('dialogWidthHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-stepper", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "\u2212", disabled: !writable || resolved.dialogWidth <= MIN_DIALOG_WIDTH, onClick: () => { stepDialogWidth(-20); }, children: "\u2212" }), (0, jsx_runtime_1.jsx)("input", { type: "number", min: MIN_DIALOG_WIDTH, max: MAX_DIALOG_WIDTH, step: 20, value: widthDraft, disabled: !writable, onChange: (event) => { setWidthDraft(event.target.value); }, onBlur: (event) => { commitDialogWidth(event.target.value); }, onKeyDown: (event) => { if (event.key === 'Enter')
|
|
2998
|
-
commitDialogWidth(event.target.value); } }), (0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "+", disabled: !writable || resolved.dialogWidth >= MAX_DIALOG_WIDTH, onClick: () => { stepDialogWidth(20); }, children: "+" })] }) })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-presets", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: resolved.dialogWidth === 880 ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { applyWidthPreset(880); }, children: [t('presetWide'), " \u00B7 880"] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: resolved.dialogWidth === 1024 ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { applyWidthPreset(1024); }, children: [t('presetWideXl'), " \u00B7 1024"] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: resolved.dialogWidth === 748 ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { applyWidthPreset(748); }, children: [t('presetDefault'), " \u00B7 748"] })] }) })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dut-panel dut-grid", children: [(0, jsx_runtime_1.jsx)("div", { className: "dut-section-label", children: t('sectionFeatures') }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('timeline'), (0, jsx_runtime_1.jsx)(Hint, { text: t('timelineHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.timelineEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setTimeline(true); }, children: t('timelineOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.timelineEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setTimeline(false); }, children: t('timelineOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('gitBar'), (0, jsx_runtime_1.jsx)(Hint, { text: t('gitBarHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.gitBarEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setGitBar(true); }, children: t('gitBarOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.gitBarEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setGitBar(false); }, children: t('gitBarOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('archiveManager'), (0, jsx_runtime_1.jsx)(Hint, { text: t('archiveManagerHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.archiveManagerEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setArchiveManager(true); }, children: t('archiveManagerOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.archiveManagerEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setArchiveManager(false); }, children: t('archiveManagerOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('mcpManager'), (0, jsx_runtime_1.jsx)(Hint, { text: t('mcpManagerHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.mcpManagerEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setMcpManager(true); }, children: t('mcpManagerOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.mcpManagerEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setMcpManager(false); }, children: t('mcpManagerOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('initCommand'), (0, jsx_runtime_1.jsx)(Hint, { text: t('initCommandHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.initCommandEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setInitCommand(true); }, children: t('initCommandOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.initCommandEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setInitCommand(false); }, children: t('initCommandOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('whaleIndicator'), (0, jsx_runtime_1.jsx)(Hint, { text: t('whaleIndicatorHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.whaleIndicatorEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setWhaleIndicator(true); }, children: t('whaleIndicatorOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.whaleIndicatorEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setWhaleIndicator(false); }, children: t('whaleIndicatorOff') })] }) })] }) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dut-panel dut-grid dut-grid-half", children: [(0, jsx_runtime_1.jsx)("div", { className: "dut-section-label", children: t('sectionNotifications') }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field dut-span-all", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifications'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notificationsHint') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dut-controls", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notificationsEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setNotifications(true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notificationsEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setNotifications(false); }, children: t('notifyOff') })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "dut-btn", disabled: !resolved.notificationsEnabled, onClick: () => { testNotifications(); }, children: t('notifyTest') })] })] }) }), (0, jsx_runtime_1.jsx)("div", { className: 'dut-field' + (!resolved.notificationsEnabled ? ' dut-sub-off' : ''), children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifyOnComplete'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notifyOnCompleteHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notifyOnComplete ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyOnComplete', true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notifyOnComplete ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyOnComplete', false); }, children: t('notifyOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: 'dut-field' + (!resolved.notificationsEnabled ? ' dut-sub-off' : ''), children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifyOnInteraction'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notifyOnInteractionHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notifyOnInteraction ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyOnInteraction', true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notifyOnInteraction ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyOnInteraction', false); }, children: t('notifyOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: 'dut-field' + (!resolved.notificationsEnabled ? ' dut-sub-off' : ''), children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifyOnlyWhenHidden'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notifyOnlyWhenHiddenHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notifyOnlyWhenHidden ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyOnlyWhenHidden', true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notifyOnlyWhenHidden ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyOnlyWhenHidden', false); }, children: t('notifyOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: 'dut-field' + (!resolved.notificationsEnabled ? ' dut-sub-off' : ''), children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifyTitleFlash'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notifyTitleFlashHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notifyTitleFlash ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyTitleFlash', true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notifyTitleFlash ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyTitleFlash', false); }, children: t('notifyOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: 'dut-field' + (!resolved.notificationsEnabled ? ' dut-sub-off' : ''), children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifySystemNotification'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notifySystemNotificationHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notifySystemNotification ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifySystemNotification', true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notifySystemNotification ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifySystemNotification', false); }, children: t('notifyOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: 'dut-field' + (!resolved.notificationsEnabled ? ' dut-sub-off' : ''), children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifySound'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notifySoundHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notifySound ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifySound', true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notifySound ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifySound', false); }, children: t('notifyOff') })] }) })] }) })] })] }));
|
|
3117
|
+
commitDialogWidth(event.target.value); } }), (0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": "+", disabled: !writable || resolved.dialogWidth >= MAX_DIALOG_WIDTH, onClick: () => { stepDialogWidth(20); }, children: "+" })] }) })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-presets", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: resolved.dialogWidth === 880 ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { applyWidthPreset(880); }, children: [t('presetWide'), " \u00B7 880"] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: resolved.dialogWidth === 1024 ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { applyWidthPreset(1024); }, children: [t('presetWideXl'), " \u00B7 1024"] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: resolved.dialogWidth === 748 ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { applyWidthPreset(748); }, children: [t('presetDefault'), " \u00B7 748"] })] }) })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('preciseCacheHit'), (0, jsx_runtime_1.jsx)(Hint, { text: t('preciseCacheHitHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.preciseCacheHitEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setPreciseCacheHit(true); }, children: t('preciseCacheHitOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.preciseCacheHitEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setPreciseCacheHit(false); }, children: t('preciseCacheHitOff') })] }) })] }) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dut-panel dut-grid", children: [(0, jsx_runtime_1.jsx)("div", { className: "dut-section-label", children: t('sectionFeatures') }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('timeline'), (0, jsx_runtime_1.jsx)(Hint, { text: t('timelineHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.timelineEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setTimeline(true); }, children: t('timelineOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.timelineEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setTimeline(false); }, children: t('timelineOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('gitBar'), (0, jsx_runtime_1.jsx)(Hint, { text: t('gitBarHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.gitBarEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setGitBar(true); }, children: t('gitBarOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.gitBarEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setGitBar(false); }, children: t('gitBarOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('archiveManager'), (0, jsx_runtime_1.jsx)(Hint, { text: t('archiveManagerHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.archiveManagerEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setArchiveManager(true); }, children: t('archiveManagerOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.archiveManagerEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setArchiveManager(false); }, children: t('archiveManagerOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('mcpManager'), (0, jsx_runtime_1.jsx)(Hint, { text: t('mcpManagerHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.mcpManagerEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setMcpManager(true); }, children: t('mcpManagerOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.mcpManagerEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setMcpManager(false); }, children: t('mcpManagerOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('initCommand'), (0, jsx_runtime_1.jsx)(Hint, { text: t('initCommandHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.initCommandEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setInitCommand(true); }, children: t('initCommandOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.initCommandEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setInitCommand(false); }, children: t('initCommandOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('whaleIndicator'), (0, jsx_runtime_1.jsx)(Hint, { text: t('whaleIndicatorHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.whaleIndicatorEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setWhaleIndicator(true); }, children: t('whaleIndicatorOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.whaleIndicatorEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setWhaleIndicator(false); }, children: t('whaleIndicatorOff') })] }) })] }) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dut-panel dut-grid dut-grid-half", children: [(0, jsx_runtime_1.jsx)("div", { className: "dut-section-label", children: t('sectionNotifications') }), (0, jsx_runtime_1.jsx)("div", { className: "dut-field dut-span-all", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifications'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notificationsHint') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dut-controls", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notificationsEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setNotifications(true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notificationsEnabled ? 'dut-seg-active' : '', disabled: !writable, onClick: () => { setNotifications(false); }, children: t('notifyOff') })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "dut-btn", disabled: !resolved.notificationsEnabled, onClick: () => { testNotifications(); }, children: t('notifyTest') })] })] }) }), (0, jsx_runtime_1.jsx)("div", { className: 'dut-field' + (!resolved.notificationsEnabled ? ' dut-sub-off' : ''), children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifyOnComplete'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notifyOnCompleteHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notifyOnComplete ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyOnComplete', true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notifyOnComplete ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyOnComplete', false); }, children: t('notifyOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: 'dut-field' + (!resolved.notificationsEnabled ? ' dut-sub-off' : ''), children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifyOnInteraction'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notifyOnInteractionHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notifyOnInteraction ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyOnInteraction', true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notifyOnInteraction ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyOnInteraction', false); }, children: t('notifyOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: 'dut-field' + (!resolved.notificationsEnabled ? ' dut-sub-off' : ''), children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifyOnlyWhenHidden'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notifyOnlyWhenHiddenHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notifyOnlyWhenHidden ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyOnlyWhenHidden', true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notifyOnlyWhenHidden ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyOnlyWhenHidden', false); }, children: t('notifyOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: 'dut-field' + (!resolved.notificationsEnabled ? ' dut-sub-off' : ''), children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifyTitleFlash'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notifyTitleFlashHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notifyTitleFlash ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyTitleFlash', true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notifyTitleFlash ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifyTitleFlash', false); }, children: t('notifyOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: 'dut-field' + (!resolved.notificationsEnabled ? ' dut-sub-off' : ''), children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifySystemNotification'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notifySystemNotificationHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notifySystemNotification ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifySystemNotification', true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notifySystemNotification ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifySystemNotification', false); }, children: t('notifyOff') })] }) })] }) }), (0, jsx_runtime_1.jsx)("div", { className: 'dut-field' + (!resolved.notificationsEnabled ? ' dut-sub-off' : ''), children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-field-top", children: [(0, jsx_runtime_1.jsxs)("span", { className: "dut-label", children: [t('notifySound'), (0, jsx_runtime_1.jsx)(Hint, { text: t('notifySoundHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dut-controls", children: (0, jsx_runtime_1.jsxs)("div", { className: "dut-seg", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: resolved.notifySound ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifySound', true); }, children: t('notifyOn') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: !resolved.notifySound ? 'dut-seg-active' : '', disabled: !writable || !resolved.notificationsEnabled, onClick: () => { setNotifyField('notifySound', false); }, children: t('notifyOff') })] }) })] }) })] })] }));
|
|
2999
3118
|
}
|
|
3000
3119
|
/**
|
|
3001
3120
|
* The /init bootstrap prompts, submitted verbatim into the current session on
|
|
@@ -3233,6 +3352,31 @@ function apply(ctx) {
|
|
|
3233
3352
|
sync();
|
|
3234
3353
|
return controller.subscribe(sync);
|
|
3235
3354
|
}, 'dsh-ui-tweaks: whale indicator');
|
|
3355
|
+
// Precise cache hit: rewrites the stats line's cache-hit figure to two
|
|
3356
|
+
// decimals from the raw tokenUsage projection. The composer-dock entry
|
|
3357
|
+
// renders nothing itself — it is a live reader that patches the stock span
|
|
3358
|
+
// in place — and it is registered only while the preciseCacheHitEnabled
|
|
3359
|
+
// toggle is on, so off costs nothing and toggling restores the stock text.
|
|
3360
|
+
ctx.effect(() => {
|
|
3361
|
+
let disposeEntry;
|
|
3362
|
+
const sync = () => {
|
|
3363
|
+
const enabled = controller.getSnapshot().value?.preciseCacheHitEnabled === true;
|
|
3364
|
+
if (enabled && disposeEntry === undefined) {
|
|
3365
|
+
disposeEntry = ctx.slots.inject('conversation.composer.dock', () => ctx.slots.register({
|
|
3366
|
+
name: 'conversation.composer.dock',
|
|
3367
|
+
id: 'precise-cache-hit',
|
|
3368
|
+
order: 90,
|
|
3369
|
+
inject: () => ({}),
|
|
3370
|
+
}, cachehit_tsx_1.PreciseCacheHitEntry));
|
|
3371
|
+
}
|
|
3372
|
+
else if (!enabled && disposeEntry !== undefined) {
|
|
3373
|
+
disposeEntry();
|
|
3374
|
+
disposeEntry = undefined;
|
|
3375
|
+
}
|
|
3376
|
+
};
|
|
3377
|
+
sync();
|
|
3378
|
+
return controller.subscribe(sync);
|
|
3379
|
+
}, 'dsh-ui-tweaks: precise cache hit');
|
|
3236
3380
|
// Task notifications: watch every session on the list feed and raise
|
|
3237
3381
|
// tab-title / system-notification / chime alerts when one finishes its turn
|
|
3238
3382
|
// or starts blocking on the user. Registered only while the master toggle
|