dsh-retrace 0.4.30 → 0.4.32
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 +56 -27
- package/README.zh.md +40 -18
- package/lib/client.bundle.js +505 -52
- package/lib/client.js +180 -21
- package/lib/close-guard-client.js +381 -2
- package/lib/close-guard.js +57 -0
- package/lib/dynamic-client.js +505 -52
- package/lib/dynamic-host.js +7 -7
- package/lib/http.js +20 -2
- package/lib/identity/shortcode.js +49 -10
- package/lib/index.js +191 -74
- package/lib/llm-summary.js +1 -1
- package/lib/marker-carrier.js +7 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -360,7 +360,7 @@ Read it before filing an issue.
|
|
|
360
360
|
### Upgrading
|
|
361
361
|
|
|
362
362
|
```bash
|
|
363
|
-
dsh plugin --profile desktop add dsh-retrace@0.4.
|
|
363
|
+
dsh plugin --profile desktop add dsh-retrace@0.4.32
|
|
364
364
|
# then restart DSH — plugins are not hot-reloaded
|
|
365
365
|
```
|
|
366
366
|
|
|
@@ -385,7 +385,7 @@ whole tree down, so recover first and diagnose second:
|
|
|
385
385
|
|
|
386
386
|
### Pinning
|
|
387
387
|
|
|
388
|
-
Pin an exact plugin version (`dsh-retrace@0.4.
|
|
388
|
+
Pin an exact plugin version (`dsh-retrace@0.4.32`) and let `dsh-log-contract` resolve to
|
|
389
389
|
`>=0.3.12`. Do not rely on `^0.4` across a host upgrade: compatibility here is decided by
|
|
390
390
|
the **host surface**, not by semver alone.
|
|
391
391
|
|
|
@@ -439,34 +439,63 @@ the **host surface**, not by semver alone.
|
|
|
439
439
|
| 🛡️ | **Running-work detection** | every session is scanned for live work: agent running, queued inbox items, background jobs, unclosed turns |
|
|
440
440
|
| 📋 | **Running banner** | sessions with live work show a persistent in-page banner (short session code + reasons), so you can see it before quitting |
|
|
441
441
|
| ⚠️ | **Exit prompt** | on plugin dispose (app exit / reload) a Chinese notice lists each running session and why it is considered busy — it only warns, it never cancels your running agent |
|
|
442
|
-
| 🔒 | **Page-close interception
|
|
442
|
+
| 🔒 | **Page-close interception** | **Does not arm the host's native confirm dialog**; uses a **page-drawn confirm gate** instead: it draws the box and **verifies visibility synchronously** before blocking (`preventDefault`); if it cannot draw, is not visible, or the page is hidden ⇒ **lets the close through immediately**; the dialog waits for your choice (**Esc = cancel**); a **Web-Worker watchdog** (immune to background throttling) is only the *last* resort; turning the setting off returns to the official behaviour (**no restart**) |
|
|
443
443
|
| 🔎 | **Query surface** | `retrace.runningState` (host RPC) + `GET|POST /api/plugins/retrace/runningState` (HTTP) — same shape on both transports; the all-sessions shape also carries the host-reported page surface (`surface` / `quitVeto`) |
|
|
444
444
|
|
|
445
|
-
> Desktop
|
|
446
|
-
>
|
|
447
|
-
>
|
|
448
|
-
>
|
|
449
|
-
>
|
|
450
|
-
>
|
|
451
|
-
>
|
|
452
|
-
> arms the native gate; it relies on the running banner plus the dispose notice. The gate is
|
|
453
|
-
> armed only where the host reports that the page really surfaces a native dialog
|
|
454
|
-
> (`quitVeto: true`, i.e. browser pages).
|
|
445
|
+
> Desktop wording (corrected 2026-09-20): **desktop never arms the host's native confirm dialog** —
|
|
446
|
+
> quit entry points differ **by version/platform**, and the native dialog either does not exist on a
|
|
447
|
+
> desktop shell or is swallowed: the 2.0.9 shell we inspected has no `will-prevent-unload` handler
|
|
448
|
+
> (0 hits across the packaged `app.asar`) and routes the tray item through
|
|
449
|
+
> `requestQuit(0) → window.destroy() → app.exit(0)`; on the external report's DSH Desktop 0.9.0 /
|
|
450
|
+
> Windows the entry **does reach** the page `beforeunload` (0.9.0), but the veto is **swallowed
|
|
451
|
+
> silently** (no dialog, no feedback — the exit just looks stuck).
|
|
455
452
|
>
|
|
456
|
-
>
|
|
457
|
-
>
|
|
458
|
-
>
|
|
459
|
-
>
|
|
460
|
-
>
|
|
461
|
-
>
|
|
462
|
-
>
|
|
463
|
-
>
|
|
464
|
-
>
|
|
465
|
-
>
|
|
466
|
-
>
|
|
467
|
-
>
|
|
468
|
-
>
|
|
469
|
-
>
|
|
453
|
+
> What actually protects on desktop is the **page-drawn confirm gate** (finalised 2026-09-19):
|
|
454
|
+
> it **does call `preventDefault`** — but only after it has **drawn the box and verified it is
|
|
455
|
+
> visible, synchronously**; a `visibilityState` pre-check lets the close through immediately when the
|
|
456
|
+
> box cannot be drawn / is not visible / the page is hidden; the dialog waits for your choice
|
|
457
|
+
> (**Esc = cancel**); a **Web-Worker watchdog** (immune to background throttling) is only the
|
|
458
|
+
> **last** resort.
|
|
459
|
+
>
|
|
460
|
+
> **Both criteria must hold** (2026-09-18, second round): the host side is only a *non-objection*
|
|
461
|
+
> (`quitVeto: true`), and the client keeps a **veto** — if this page's `navigator.userAgent`
|
|
462
|
+
> contains `Electron`, or the page URL contains `dsh-desktop-` (the external report's shell puts its
|
|
463
|
+
> desktop marker in the query string), the native gate is **never** armed. The host-side criteria
|
|
464
|
+
> were widened to four request-level facts: the `x-dsh-desktop-renderer` capability header, a
|
|
465
|
+
> request `User-Agent` containing `Electron`, or a request URL **or `Referer`** containing
|
|
466
|
+
> `dsh-desktop-` — **any one** of them classifies the page as a desktop page. (Our own polling URL
|
|
467
|
+
> carries no query string, so the page marker is in practice read from `Referer`, which a
|
|
468
|
+
> same-origin `fetch` sends by default.) That covers the hosts that expose no desktop evidence at
|
|
469
|
+
> all (the reporter's: a pure-Node harness plus an Electron renderer, where all three older criteria
|
|
470
|
+
> were false, and the old code filed "no evidence at all" as a browser page ⇒ the gate was still
|
|
471
|
+
> armed ⇒ the exit still hung).
|
|
472
|
+
>
|
|
473
|
+
> **Known limitation (stated plainly)**: some desktop shells route quit **around the page entirely**
|
|
474
|
+
> (e.g. `requestQuit → destroy → app.exit`, or the X button merely hides the window) ⇒ on those
|
|
475
|
+
> shells a plugin **cannot** show a confirm dialog at quit time; it **needs a shell seam**
|
|
476
|
+
> (a `will-prevent-unload` handler, or a pre-quit prompt hook). If Desktop cannot quit, turning off
|
|
477
|
+
> "Exit confirmation (close guard)" in settings recovers immediately (no restart).
|
|
478
|
+
|
|
479
|
+
**Session badge & display name** (**planned / off by default**) — badges are for human
|
|
480
|
+
collaboration; **identity is still decided by the session id**. The transports
|
|
481
|
+
(`sessionBadge` / `setBadgeTitle` / `initBadgeTitles` / `badgeMap`, on both HTTP and harness),
|
|
482
|
+
the resolver and the write guards are **in place**, but the **automatic startup path that writes
|
|
483
|
+
titles is off by default** (after three distinct on-device failures it moves to the **scripting
|
|
484
|
+
layer T3**, which is not implemented yet) — set `__DSH_RETRACE_BADGE_BOOTSTRAP = true` to enable it:
|
|
485
|
+
|
|
486
|
+
- A session title renders as `[badge] original title` (shape placeholder: `[opxxxopxxx] original title`); the badge
|
|
487
|
+
shape is **`opxxxopxxx`** and comes from the **real table** `codes.json` (workspace + sequence +
|
|
488
|
+
parent-chain semantics — **not a hash**).
|
|
489
|
+
- Sessions with **no `session/title` event are left blank on purpose** (the title shows just
|
|
490
|
+
`[badge]`) — **no project-name fallback, no fabricated name**.
|
|
491
|
+
- If the table / resolver is unavailable it falls back to the **raw session id as a placeholder**,
|
|
492
|
+
and **never** to FNV.
|
|
493
|
+
- The sidebar row, the running banner and the checkpoint view share **one source**: the same badge
|
|
494
|
+
map the host hands down (host op `badgeMap`).
|
|
495
|
+
|
|
496
|
+
> **Planned (not shipped)**: the scripting-layer T3 is not implemented yet (the badge/name
|
|
497
|
+
> **automatic title-writing startup path** is blocked on it); the agent business-layer plan (runtime guard,
|
|
498
|
+
> interruption governance, ecosystem-facing interfaces) is a **plan**, not a shipped capability.
|
|
470
499
|
|
|
471
500
|
> Command surface: `retrace.runningState` (host RPC) + `GET|POST /api/plugins/retrace/runningState` (HTTP).
|
|
472
501
|
|
package/README.zh.md
CHANGED
|
@@ -271,7 +271,7 @@ Client 半区会依据包内 `dsh.client` 元数据被自动打包进 Web 客户
|
|
|
271
271
|
### 升级
|
|
272
272
|
|
|
273
273
|
```bash
|
|
274
|
-
dsh plugin --profile desktop add dsh-retrace@0.4.
|
|
274
|
+
dsh plugin --profile desktop add dsh-retrace@0.4.32
|
|
275
275
|
# 然后重启 DSH —— 插件不会热重载
|
|
276
276
|
```
|
|
277
277
|
|
|
@@ -285,7 +285,7 @@ dsh plugin --profile desktop add dsh-retrace@0.4.26
|
|
|
285
285
|
|
|
286
286
|
### 版本固定建议
|
|
287
287
|
|
|
288
|
-
请固定到确切版本(`dsh-retrace@0.4.
|
|
288
|
+
请固定到确切版本(`dsh-retrace@0.4.32`),并让 `dsh-log-contract` 解析到 `>=0.3.12`。
|
|
289
289
|
**不要在跨宿主升级时依赖 `^0.4` 这种范围**:这里的兼容性由**宿主的面**决定,光看 semver 不够。
|
|
290
290
|
|
|
291
291
|
---
|
|
@@ -326,25 +326,47 @@ dsh plugin --profile desktop add dsh-retrace@0.4.26
|
|
|
326
326
|
| 🛡️ | **运行中检测** | 逐会话扫描运行中工作:agent 正在跑 / inbox 排队 / 后台 jobs / 未闭合轮 |
|
|
327
327
|
| 📋 | **运行中横幅** | 有运行中工作的会话显示页面常驻横幅(会话短码 + 原因),退出前可见 |
|
|
328
328
|
| ⚠️ | **退出提示** | 插件 dispose(应用退出/重载)时中文提示列出每个运行中会话与原因——只提示,绝不代你取消 agent |
|
|
329
|
-
| 🔒 |
|
|
329
|
+
| 🔒 | **页面关闭拦截** | **不武装宿主原生确认框**;改用**页面自绘确认门**:先画框并**同步校验可见**才拦(`preventDefault`),画不出 / 不可见 / 页面不可见 ⇒ **当场放行**;确认框一直等你选择(Esc = 取消);**看门狗(Web Worker 计时器,不受后台节流)**只作最后一道;关掉设置项即退回官方形态(免重启) |
|
|
330
330
|
| 🔎 | **查询面** | `retrace.runningState`(host RPC)+ `GET|POST /api/plugins/retrace/runningState`(HTTP),两入口同形状;全会话形状另带宿主判定的承载面(`surface` / `quitVeto`) |
|
|
331
331
|
|
|
332
|
-
>
|
|
333
|
-
>
|
|
334
|
-
>
|
|
335
|
-
>
|
|
336
|
-
> `
|
|
337
|
-
> 自己属于哪一类,因此**桌面端一律不武装**原生门,保护由运行中横幅 + dispose 提示承担;
|
|
338
|
-
> 只有宿主回报"这个页面会弹原生确认框"(`quitVeto: true`,即普通浏览器页)时才武装。
|
|
332
|
+
> **桌面端口径(2026-09-20 更正)**:**桌面端一律不武装宿主原生确认框** —— **退出入口随版本/平台而变**,
|
|
333
|
+
> 而原生确认框在桌面壳上要么不存在、要么被静默吞掉:我们检查的 2.0.9 壳没有处理
|
|
334
|
+
> `will-prevent-unload`(打包 `app.asar` 全文检索 0 命中),托盘项走
|
|
335
|
+
> `requestQuit(0) → window.destroy() → app.exit(0)`;外部报告那套 DSH Desktop 0.9.0 / Windows
|
|
336
|
+
> 上虽然**会走到页面** `beforeunload`,但页面否决被**静默吞掉**(不弹界面、不给反馈,表现为退出卡住)。
|
|
339
337
|
>
|
|
340
|
-
>
|
|
341
|
-
>
|
|
342
|
-
>
|
|
343
|
-
>
|
|
344
|
-
>
|
|
345
|
-
>
|
|
346
|
-
>
|
|
347
|
-
>
|
|
338
|
+
> **桌面端真正生效的是页面自绘确认门**(2026-09-19 收尾):它**确实会调用 `preventDefault`** ——
|
|
339
|
+
> 但只在"**先画出来 + 同步可见性校验通过**"之后才拦;`visibilityState` 前置检查,框画不出来 /
|
|
340
|
+
> 不可见 / 页面不可见 ⇒ **当场放行**;确认框一直等你选择(**Esc = 取消**);
|
|
341
|
+
> **看门狗用 Web Worker 计时器**(不受后台节流)只作**最后一道**分流。
|
|
342
|
+
>
|
|
343
|
+
> 武装**宿主原生门**的判据:**两道判据都成立才武装**(2026-09-18 第二轮)—— 宿主那条只是"不反对"
|
|
344
|
+
> (`quitVeto: true`),客户端还有**一票否决**:本页 `navigator.userAgent` 含 `Electron`,
|
|
345
|
+
> 或页面 URL 含 `dsh-desktop-`(外部报告那套壳把桌面标记放在查询串里)⇒ 一律不武装。
|
|
346
|
+
> 宿主侧判据补成**四条请求级证据**:能力头 `x-dsh-desktop-renderer` / 请求 UA 含 `Electron` /
|
|
347
|
+
> 请求 URL **或 `Referer`** 含 `dsh-desktop-`(我们自己的轮询 URL 没有 query,所以页面标记
|
|
348
|
+
> 实际是从 `Referer` 读到的),**任一成立**即判桌面页面。这样"壳什么桌面痕迹都不给"的宿主
|
|
349
|
+
> (报告人那台:纯 Node 跑 harness + Electron 渲染页,三条旧判据全不成立,旧实现把
|
|
350
|
+
> "**完全没有证据**"归成了浏览器页 ⇒ 照旧武装 ⇒ 仍退不掉)也不会再把退出卡住。
|
|
351
|
+
>
|
|
352
|
+
> **已知限制(照实写)**:某些桌面壳的退出口径**根本不经过页面**(如
|
|
353
|
+
> `requestQuit → destroy → app.exit`,或点 X 只是隐藏窗口)⇒ 那类壳上"退出时弹确认"
|
|
354
|
+
> **插件侧做不到**,需要**壳提供 seam**(`will-prevent-unload` 处理,或退出前的询问钩子)。
|
|
355
|
+
> **桌面端退不掉时**,把设置里的「退出确认(关闭守卫)」关掉即退回官方形态(**不用重启**)。
|
|
356
|
+
|
|
357
|
+
**会话短码与显示名**(**计划 / 默认关闭**)—— 人机协作用短码,**身份判定仍以 session id 为准**。
|
|
358
|
+
通道(`sessionBadge` / `setBadgeTitle` / `initBadgeTitles` / `badgeMap`,HTTP + harness 两入口)与
|
|
359
|
+
解析器、写护栏**均已就位**;但**启动自动写标题那条路默认关闭**(真机上三次不同失败后按
|
|
360
|
+
「文件/脚本优先」改走**脚本层 T3**,T3 尚未实现)—— 需要时置 `__DSH_RETRACE_BADGE_BOOTSTRAP = true` 打开:
|
|
361
|
+
|
|
362
|
+
- 会话标题显示为 `[短码] 原标题`(形态占位:`[opxxxopxxx] 原标题`),短码形态 **`opxxxopxxx`**,
|
|
363
|
+
由**真表** `codes.json` 解析(工作区 + 序号 + 父链语义,**不是 hash**)。
|
|
364
|
+
- **没有 `session/title` 事件的会话如实留空**(标题只显示 `[短码]`)—— **不回落项目名、不伪造名字**。
|
|
365
|
+
- 拿不到短码表 / 解析器不可用时退回**原始 session id 占位**,**绝不回落 FNV**。
|
|
366
|
+
- 侧栏会话行、运行中横幅、读档点视图的短码**同源**:都取宿主下发的**同一份**映射(宿主 op `badgeMap`)。
|
|
367
|
+
|
|
368
|
+
> **计划(未上线)**:脚本层 T3 尚未实现(短码/名字的**启动自动写标题**即卡在这里);业务层规划
|
|
369
|
+
> (运行时守护、中断治理、生态开放接口)见下节,属**计划**而非已上线能力。
|
|
348
370
|
|
|
349
371
|
**未来计划**——agent 业务层规划(运行时守护、中断治理、生态开放接口)**尚未发布**,此节是**计划**而非已上线能力。本 README 描述的是**开发线(main)**,可能领先于 npm 上最新发布版。
|
|
350
372
|
|