dsh-scout 0.9.2 → 0.9.3
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/CHANGELOG.md +38 -1
- package/README.en.md +134 -45
- package/README.md +134 -45
- package/dist/index.d.ts +17 -0
- package/dist/index.js +22 -1
- package/docs/dsh-scout-product-contract.md +20 -1
- package/package.json +1 -1
- package/scripts/check-release.mjs +228 -0
- package/tests/acceptance.test.mjs +62 -2
- package/tests/package.test.mjs +572 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,45 @@
|
|
|
4
4
|
|
|
5
5
|
本文件从 0.9.1 开始记录;0.9.0 及更早版本的变更见仓库的 git tag。
|
|
6
6
|
|
|
7
|
+
## [0.9.3] - 2026-10-13
|
|
8
|
+
|
|
9
|
+
**待发布**:本条目描述冻结为 0.9.3 的工作树;npm 元数据(tarball / shasum / integrity / provenance / git tag)在发布后补记。
|
|
10
|
+
|
|
11
|
+
0.9.3 的主题是**安装体验**,不加功能、不改运行时契约。缘起是一份在真实桌面 App 上完整走完安装的评审:README 的「三条已验证路径」对桌面 App 用户**全部不可用**——桌面版的 `desktop` profile 被 Electron 应用独占,CLI 对它的所有 `dsh plugin` 子命令都按 profile 名硬拒绝(`error: profile "desktop" is managed exclusively by the Electron application`,连兼容性逃生门 `allow-version` 一起拒绝),而桌面 App 恰恰是这类插件最主流的入口。本版把「App 内安装」补成主路径,并给安装补上可执行的判据。
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **README 新增「路径 0:桌面 App」**(README.md / README.en.md 逐段同步):说明 `desktop` profile 的独占拒绝与「这是按 profile 名的硬拒绝、所有 `dsh plugin` 子命令都会命中」,给出**侧边栏 → 插件页**里的安装串 `dsh-scout@0.9.3`,并写明装完无需重启——实测 12 个 `scout_*` 工具即时注入当前会话。
|
|
16
|
+
- **README 新增「装上了吗(成功判据)」**:桌面**四条**判据,且**区分两个 GUI 面**——**侧边栏 → 插件页**的「已安装」里找到 `dsh-scout`、打开**详情页**看 `v0.9.3`(版本号只在这一页)→ **设置 → 内置插件 → 插件列表**看该行**已启用 + 运行中**(不是**已停用**/**启动失败**/**条件启用**;这一页不显示版本号)→ 新开一轮对话出现 12 个 `scout_*` 工具 → `/scout status <caseId>` 命中且输出末尾带 `· dsh-scout 0.9.3`;CLI 用 `dsh --profile <your-profile> --dump-config | grep -A2 'dsh-scout'`,并点明「组合进去 ≠ 运行时挂上了」,最可靠的判据始终是那 12 个工具与 `/scout`。
|
|
17
|
+
- **README 新增「卸载与升级」**:CLI 的 `add dsh-scout@<new-version>` / `remove dsh-scout` 与桌面 App 的**侧边栏 → 插件页**两条写法,并说明安装失败会回滚 profile 清单与 lockfile。
|
|
18
|
+
- **README 补 `compatibility.json` 手动豁免路径**(评审 P2-3):桌面用户拿不到 `allow-version`,文档给出 profile 目录下该文件的平铺 JSON 写法(精确 `package@version` → 精确 DSH 版本数组,示例 `{"dsh-scout@0.9.3": ["0.2.0-rc.2"]}`),并复述同一组边界、`--accept-risk` 风险确认与「写法不合规的记录被忽略并告警」的读取行为。
|
|
19
|
+
- **门禁守护 README 的版本引用**(评审 P2-4):README / README.en.md 里**活的**版本引用——`dsh-scout-<version>.tgz`、安装命令里的 `dsh-scout@<version>` 操作数、`compatibility.json` 的 `"dsh-scout@<version>"` 键、git ref `#v<version>`——必须等于 `package.json` 的 version。守卫同时落在 `tests/package.test.mjs`(每次 `npm test`、CI,毫秒级)与 `scripts/check-release.mjs` 最前面(独立第二实现,README 过期时不必先跑完整套单测与约两分钟的四版本矩阵)。历史提及(实测矩阵、路线图、发布叙述)按设计不在守卫范围。
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- **安装章节上移到「快速上手」之后**,三条 CLI 路径降级为「CLI / 自建 profile 用户适用」;`scout-demo` 这类**虚构** profile 名改为显式占位符 `<your-profile>`,附「怎么知道我的 profile 名」(没有 `dsh profile list` 子命令,直接 `ls ~/.dsh/profiles`)与「照抄示例名不会报错、只会把插件静默装进另一个 profile」的陷阱说明。
|
|
24
|
+
- **git 安装路径保留但降级**到「其他安装方式与取舍」表,标注**不推荐**:仓库不含 `dist/`,`prepare` 会跑 `tsc` 并安装 devDependencies,是三条路径里唯一会执行代码的;只保留「需要未发布提交时」的理由。示例 ref 由不可执行的 `#<commit>` 改为**真实 tag**(`github:MaxHou-infinity/dsh-scout#v0.9.3`;仓库自 `v0.3.0` 起共 10 个 tag,`v0.9.1` 是本地迭代版、未打 tag——评审「git tag 为空」的判断与事实不符)。
|
|
25
|
+
- **主安装命令显式锁版本**(`dsh-scout@0.9.3`,不再是裸包名):pnpm ≥ 11 的最小发布年龄(minimum release age)保护会让刚发布的版本被静默跳过、回退到旧版;该说明从「注意事项」降为路径 0 下的一句注解,现象 / 原因 / `minimumReleaseAgeExclude` 特征全部保留。
|
|
26
|
+
- **Node 要求的适用范围**:「Node ≥ 22.19」只对 CLI / 门禁路径成立;桌面 App 自带 node / pnpm 运行时(实测 node 24.21.0 + pnpm 11.7.0),无需安装 Node。
|
|
27
|
+
- **桌面场景建议绝对 `scoutDir`**:默认 `./dsh-scout` 依赖 cwd,桌面会话的 cwd 语义与 CLI 不同;文档建议在 `~/.dsh/profiles/desktop/cordis.patch.yml` 里给 `id: dsh-scout` 配绝对路径,并提示该文件由 App 维护、手改前先退出 App。
|
|
28
|
+
- **`/scout status <caseId>` 的输出尾部新增 `· dsh-scout 0.9.3`**:纯追加,原有前缀逐字节不变,`status` 之外的子动作不受影响。这是 0.9.3 唯一的**用户可见输出变化**,用途是让桌面用户自证「运行时真正加载的是哪个版本」——桌面既看不到 stderr、也没有运行日志。版本号取自源码常量 `PLUGIN_VERSION`(`src/index.ts`),随发布手动 bump,不从 `package.json` 运行时读取。
|
|
29
|
+
- **加载横幅(评审 §5.3)不做,改为让状态在两个 GUI 面里可读**:取证显示桌面 App 的 stderr 不可见——Electron 主进程的 fd0/fd1/fd2 全部指向 `/dev/null`(host 进程的 fd1/fd2 是通向主进程的管道,主进程再 pipe 到 `/dev/null`),`~/Library/Logs/DeepSeek Harness/` 为空目录、全盘没有 DSH 运行日志,`ctx.logger()` 也没有落盘出口(cordis 只有内存 ring buffer exporter,其 `startupLogs` 只在 `StartupError` 分支挂上)——加一行加载横幅**没有用户看得到**。落点改为文档与验收 checklist 写清 GUI 里**两个各答一个问题**的面:① **侧边栏 → 插件页**(`dsh-client-ui-plugin-manager`)是**管理面**,回答安装 / 启用 / 移除与**装的是哪版**(**详情页**标题旁的 `v{version}`,来自 `BundleInfo.version`;列表卡片只有「实验性 / 异常」状态标签);② **设置 → 内置插件 → 插件列表**(`dsh-client-ui-settings-plugin-inventory`)是**只读检查面**,回答**装没装 / 为什么没生效**——按「会话插件 / 全局插件」分组,用**已启用 / 已停用 / 启动失败 / 条件启用**标签与**运行中 / 启动失败 / 等待依赖 / 未运行**运行状态说话,**不显示版本号**(wire 行只有 `{ entryId, moduleName, meta?, enabled, fiberPhase }`)。关键依据:启动时被禁用的插件行(peer 版本不匹配是其中一种)已被投影到这一页的「已停用」——宿主侧就是 `enabled: !entry.disabled`(`dsh-host-plugin-inventory/lib/index.js:131`)——所以那行被丢进 `/dev/null` 的 stderr,答案早就在 GUI 里;**插件被 disabled 时它自己不可能输出任何东西**,这正是「没有任何报错」在桌面必须去 GUI 查的理由。
|
|
30
|
+
|
|
31
|
+
### Docs
|
|
32
|
+
|
|
33
|
+
- **新增 `docs/install-verification.md`**:把桌面 App 安装固化成可执行的手工验收 checklist(Lane D)——确认运行时版本 → 确认兼容性 → App 内安装 → 生效验证(**侧边栏 → 插件页**看「已安装 + `v0.9.3`」,**设置 → 内置插件 → 插件列表**看「已启用 + 运行中」,辅以 bundle installed+enabled / loader 行 fiber active / 插件总数变化)→ 功能验证(12 个 `scout_*` 工具即时注入、`scout_start` + `scout_report` 真实调用、`/scout status` 输出带版本)——并写明它与现有 CLI 门禁(Lane C:`npm run test:profile` 的六步链)的差异、自动化门禁为什么覆盖不到 Electron 独占 profile、每条 lane 的触发时机,以及一条**如实标注的残差**:GUI 两页只做过源码取证 + profile 组合实测,**没有 GUI 活体验证**,判据标为「待人工点一次确认」。仓库内文档,不在 npm 包内。
|
|
34
|
+
- **安装评审原件入库**:`docs/dsh-scout-install-ux-review.md`(桌面 App 上的完整实测记录),仓库内文档,不在 npm 包内。
|
|
35
|
+
- 产品契约的安装 / 分发段落与 README 的新安装模型对齐(桌面 App 为主路径),并把 `compatibility.json` 的手动豁免路径记进契约的兼容性段落。
|
|
36
|
+
|
|
37
|
+
### Known boundaries
|
|
38
|
+
|
|
39
|
+
- **桌面 App 的 `desktop` profile 只能由 App 管理**:CLI 对它的 `add` / `list` / `allow-version` 等所有子命令都按 profile 名拒绝。这是 DSH 参数解析层的硬编码判断(`rejectElectronProfile`),不是权限或配置问题;0.9.3 不改 DSH,只在文档里如实说明,并给出**侧边栏 → 插件页**安装与手动豁免两条替代路径。
|
|
40
|
+
- **README 版本守卫只覆盖「活的」引用**:历史版本串(实测矩阵里的 `dsh-scout@0.9.2`、路线图条目、发布叙述)按设计不参与断言,所以它防的是「忘改安装串」,不是「历史叙述过期」。
|
|
41
|
+
|
|
7
42
|
## [0.9.2] - 2026-10-13
|
|
8
43
|
|
|
44
|
+
**已发布**(2026-10-13):npm `dsh-scout@0.9.2`(`dist-tags.latest` = `0.9.2`),tarball `https://registry.npmjs.org/dsh-scout/-/dsh-scout-0.9.2.tgz`(**23 个文件**),shasum `bedb4a656709d5d0e77d5f4b410e2173c0b8eb31`,integrity `sha512-UIJOP8KalLqiEBssFB3+sw+cP1+R78nNZzwA/Wg5gT1o/NLOBgWccURdgbqk4fNdJwGKYVyNvbRuy4RZYrusDw==`,带 **Sigstore provenance**(透明日志 `https://search.sigstore.dev/?logIndex=3244828180`),由 GitHub Actions 以 `npm publish --provenance --access public` 发布;git tag `v0.9.2`(annotated,指向 `64138a0`)与 GitHub Release `v0.9.2`(附件 `dsh-scout-0.9.2.tgz`,130,691 B)同批创建;发布 workflow run `38406696598` success(16m59s:四版本 release gate → `pnpm pack` → npm publish → GitHub Release)。发布前验收:`npm test` **118/118**、`test:profile` PASS(六步真实宿主链)、`pnpm pack --dry-run` 干净、`env -u DSH_BIN npm run check:release` **4/4 PASS**;独立验证 [verification-0.9.2.md](docs/verification-0.9.2.md)(仓库文档,不在 npm 包内)判定 **GO**,无新缺陷。
|
|
45
|
+
|
|
9
46
|
0.9.2 是 0.9.1 的收口版本:把 0.9.1 验证报告点名的最大盲区(**U11**)补成真实宿主门禁,清掉三轮独立验证留下的文档税,并关闭 0.9.1 的两个已知边界(**D10**、**O10**)。
|
|
10
47
|
|
|
11
48
|
### Added
|
|
@@ -19,7 +56,7 @@
|
|
|
19
56
|
|
|
20
57
|
### Fixed
|
|
21
58
|
|
|
22
|
-
- **render 整串上限改为由省略号长度推导**(原 O10):0.9.1 的裁切预算是固定余量 `MAX_RENDER_BYTES - 8
|
|
59
|
+
- **render 整串上限改为由省略号长度推导**(原 O10):0.9.1 的裁切预算是固定余量 `MAX_RENDER_BYTES - 8`(1016 B)——裁到 ≤1015 B 再追加 3 B 省略号,含省略号的**精确上界是 1018 B**(实测最坏 1018 B),距 1024 B 预算余 **6 B**;余量只剩 1 B(调用点写 `MAX_RENDER_BYTES - 1`)时上界变成 1025 B,就会越界。现在省略号自身的 UTF-8 长度先从预算里扣掉、再按码元裁切,整串(含省略号)**不超过 1024 B**;对抗性测试把 ASCII 输入推到整整 1024 B,并对 CJK 与 emoji(代理对、UTF-8 变长)断言不超过预算。
|
|
23
60
|
|
|
24
61
|
### Docs
|
|
25
62
|
|
package/README.en.md
CHANGED
|
@@ -103,66 +103,101 @@ The generated report contains:
|
|
|
103
103
|
- **Sources**: URL-linked source list
|
|
104
104
|
- **Interview questions**: suggested questions (untouched dimensions come first)
|
|
105
105
|
|
|
106
|
-
##
|
|
106
|
+
## Install
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|---|---|
|
|
110
|
-
| `scout_start` | Create a due-diligence case |
|
|
111
|
-
| `scout_add_source` | Register a source (with evidence level) |
|
|
112
|
-
| `scout_ingest` | Batch-register collected results (infers source type/evidence level; can draft one claim per item) |
|
|
113
|
-
| `scout_search` | Search through the DSH Web Provider and auto-register result sources (type/evidence inferred per URL) |
|
|
114
|
-
| `scout_add_claim` | Add an evidence-bounded claim |
|
|
115
|
-
| `scout_verify_identity` | Verify the legal entity from an E3 official source |
|
|
116
|
-
| `scout_verify_claim` | Promote a claim with stronger evidence |
|
|
117
|
-
| `scout_report` | Render the current Markdown report |
|
|
118
|
-
| `scout_questions` | Derive a deduplicated, prioritized interview question list (up to 12; case-curated questions keep their quota) |
|
|
119
|
-
| `scout_compare` | Side-by-side comparison of 2–5 cases (decisions/identity/claims/risks/questions) |
|
|
120
|
-
| `scout_export` | Persist the five-file export + completion marker |
|
|
121
|
-
| `scout_import` | Restore a case from an export directory and recompute its decision (tolerates legacy exports, reports `complete`) |
|
|
108
|
+
First decide where you run it — the two entry points install differently, and they must not be mixed:
|
|
122
109
|
|
|
123
|
-
|
|
110
|
+
| Where you run | Target profile | How to install |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| **Desktop app (DeepSeek Harness)** | `desktop` | **In-app install** (the only path — see below) |
|
|
113
|
+
| CLI / headless / your own profile | your profile name | `dsh plugin --profile <your-profile> add …` |
|
|
124
114
|
|
|
125
|
-
|
|
115
|
+
### Path 0: desktop app (recommended)
|
|
126
116
|
|
|
127
|
-
|
|
128
|
-
- `render` is a **compact summary that never exceeds 1 KB as a whole**: decision + this call's delta + unresolved blockers + next steps. The cap is the render budget itself (`MAX_RENDER_BYTES = 1024` B): the ellipsis's own UTF-8 length is subtracted from the budget before cutting, so **the final string including the ellipsis never exceeds 1024 B**;
|
|
129
|
-
- `persist: { persisted, targetDir, error? }` appears **only on the `autoPersist` path of mutating tools** (the key is omitted when no persist was attempted). **A failed persist is no longer silent**: `persist.persisted === false` plus `persist.error`, and no `case_exported` event is recorded. `scout_export` carries **no `persist` key** — it expresses the same thing through **top-level** `persisted` / `complete` / `error`;
|
|
130
|
-
- **Full data still comes from `scout_report` (Markdown) and `scout_export` (files)** — the model sees a summary, not the whole ledger.
|
|
117
|
+
The desktop `desktop` profile is owned exclusively by the Electron application, so the CLI cannot manage it — `dsh plugin --profile desktop list` and `add` are both refused:
|
|
131
118
|
|
|
132
|
-
|
|
119
|
+
```text
|
|
120
|
+
error: profile "desktop" is managed exclusively by the Electron application
|
|
121
|
+
```
|
|
133
122
|
|
|
134
|
-
|
|
123
|
+
That is a hard refusal **by profile name**, so **every** `dsh plugin` subcommand against it is rejected — including `allow-version` in the compatibility section below. Install from the **sidebar → Plugins page** (install, enable, and remove all live there) instead:
|
|
135
124
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
| `scout` Skill | The due-diligence workflow registered by the plugin itself (`ctx.skills.register`, no files, no client bundle): start → search/ingest → claim → verify_identity → report → questions, plus the four evidence disciplines; it disappears on unload |
|
|
125
|
+
```sh
|
|
126
|
+
dsh-scout@0.9.3
|
|
127
|
+
```
|
|
140
128
|
|
|
141
|
-
|
|
129
|
+
> Always pin the exact version. pnpm ≥ 11 enables minimum-release-age supply-chain protection by default, so a bare package name silently skips a just-released version and falls back to an older one (installing right after 0.9.2 shipped resolved to 0.9.0); with an exact version pnpm records it under the profile's `minimumReleaseAgeExclude` (it prints `Added 1 entry to …`).
|
|
142
130
|
|
|
143
|
-
|
|
144
|
-
|
|
131
|
+
No restart is needed: the 12 `scout_*` tools are injected into the current session. A desktop session's cwd differs from the CLI's, so give `scoutDir` an absolute path in the profile's `cordis.patch.yml` (see "Configuration" below).
|
|
132
|
+
|
|
133
|
+
### Path 1: CLI (npm, recommended)
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
# Replace <your-profile> with your own profile name — do not copy the example verbatim
|
|
137
|
+
dsh plugin --profile <your-profile> add dsh-scout@0.9.3
|
|
145
138
|
```
|
|
146
139
|
|
|
147
|
-
|
|
140
|
+
<details>
|
|
141
|
+
<summary>How do I find my profile name?</summary>
|
|
148
142
|
|
|
149
|
-
|
|
143
|
+
There is no `dsh profile list` subcommand (`profile` is parsed as a profile name and errors), so read the directory:
|
|
150
144
|
|
|
151
|
-
|
|
145
|
+
```sh
|
|
146
|
+
ls ~/.dsh/profiles # or $DSH_HOME/profiles
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Every name it lists is a usable profile (e.g. `web`, or one you created). `desktop` is app-owned: any `dsh plugin` subcommand against it is refused.
|
|
150
|
+
</details>
|
|
151
|
+
|
|
152
|
+
**Do not copy an example name** (such as `scout-demo`) verbatim: the CLI creates and uses it without any error, so the plugin lands in a different profile and appears not to work.
|
|
153
|
+
|
|
154
|
+
### Path 2: local tarball (offline / reproducible)
|
|
152
155
|
|
|
153
156
|
```sh
|
|
154
|
-
#
|
|
155
|
-
dsh plugin --profile
|
|
157
|
+
pnpm pack # produces dsh-scout-0.9.3.tgz
|
|
158
|
+
dsh plugin --profile <your-profile> add "file:$PWD/dsh-scout-0.9.3.tgz"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Other install sources, and the trade-off
|
|
162
|
+
|
|
163
|
+
| Source | Ships build output | Runs install scripts | Recommendation |
|
|
164
|
+
|---|---|---|---|
|
|
165
|
+
| npm (path 1) | yes, ships `dist/` | no (`pendingBuilds: []` measured) | **recommended** |
|
|
166
|
+
| local tarball (path 2) | yes (the `pnpm pack` output) | no | offline / self-test |
|
|
167
|
+
| git: `github:MaxHou-infinity/dsh-scout#v0.9.3` | no (`dist/` is not committed) | yes — `prepare` runs `tsc` and installs devDependencies | **not recommended**; only for unreleased commits |
|
|
156
168
|
|
|
157
|
-
|
|
158
|
-
pnpm pack # produces dsh-scout-0.9.2.tgz
|
|
159
|
-
dsh plugin --profile scout-demo add "file:$PWD/dsh-scout-0.9.2.tgz"
|
|
169
|
+
The git ref must be a **real tag or commit**: the repository has 10 tags since `v0.3.0` (`v0.3.0` … `v0.9.2`; `v0.9.1` was a local iteration and was never tagged), and this release creates `v0.9.3`. Git is also the only path that executes code: `dist/` is not committed, so it always builds locally, and pnpm may require an explicit `allowBuilds` entry for `dsh-scout` (only allow a pinned version you have reviewed).
|
|
160
170
|
|
|
161
|
-
|
|
162
|
-
|
|
171
|
+
> The desktop app bundles its own node / pnpm runtime (measured: node 24.21.0 + pnpm 11.7.0), so you do **not** need Node installed; the "Node ≥ 22.19" requirement applies to the CLI / gate paths only.
|
|
172
|
+
|
|
173
|
+
### Did it install? (success criteria)
|
|
174
|
+
|
|
175
|
+
**Desktop app**
|
|
176
|
+
|
|
177
|
+
1. **Sidebar → Plugins page**: `dsh-scout` appears under Installed; **open its detail page** — the title carries a `v0.9.3` tag, and the version lives only on this page (list cards carry only the Experimental / Problem status tags);
|
|
178
|
+
2. **Settings → Built-in plugins → Plugin list**: the `dsh-scout` row carries the **Enabled** tag and the **Running** status — not **Disabled** / **Failed** / **Conditional** (this page shows **no version**);
|
|
179
|
+
3. start a new turn — 12 `scout_*` tools appear in the tool list;
|
|
180
|
+
4. `/scout status <caseId>` resolves and its output ends with the plugin version (`· dsh-scout 0.9.3`) — with no stderr or logs on desktop, this is the surface that proves which version actually loaded.
|
|
181
|
+
|
|
182
|
+
**CLI**
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
# the composed tree should contain the dsh-scout layer
|
|
186
|
+
dsh --profile <your-profile> --dump-config | grep -A2 'dsh-scout'
|
|
163
187
|
```
|
|
164
188
|
|
|
165
|
-
|
|
189
|
+
Being composed is **not** the same as being mounted at runtime: the reliable signal is always whether the 12 `scout_*` tools show up and whether `/scout` resolves.
|
|
190
|
+
|
|
191
|
+
On a runtime mismatch the CLI disables the plugin row and writes exactly one stderr line, `dsh: disabling profile plugin <row>: <reason>` — what you see is "the plugin isn't working", not a loud red error. **The desktop app has no visible stderr** (measured: the Electron main process points fd0/fd1/fd2 at `/dev/null`, `~/Library/Logs/DeepSeek Harness/` is empty, and there is no DSH runtime log anywhere), so on desktop the only place to look is the GUI: **Settings → Built-in plugins → Plugin list** groups rows into Session plugins / Global plugins and answers "is it installed, and why isn't it working?" with the **Enabled / Disabled / Failed / Conditional** tags and the **Running / Failed to start / Waiting for dependencies / Not running** statuses (this page shows **no version**) — a row disabled at startup (a peer mismatch is one cause) shows up there as **disabled**, because the host projects it as `enabled: !entry.disabled`; the stderr line thrown into `/dev/null` already has its answer in the GUI. For which version is installed, open the plugin's detail page on the **sidebar → Plugins page** and read the `v{version}` tag.
|
|
192
|
+
|
|
193
|
+
### Upgrade and uninstall
|
|
194
|
+
|
|
195
|
+
```sh
|
|
196
|
+
dsh plugin --profile <your-profile> add dsh-scout@<new-version> # upgrade: target version, also pinned
|
|
197
|
+
dsh plugin --profile <your-profile> remove dsh-scout # uninstall
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Use the **sidebar → Plugins page** on desktop to upgrade / remove. A failed install rolls back the profile manifest and lockfile.
|
|
166
201
|
|
|
167
202
|
### DSH compatibility
|
|
168
203
|
|
|
@@ -177,7 +212,7 @@ DSH compatibility has **three layers** — do not conflate them:
|
|
|
177
212
|
Three details that matter:
|
|
178
213
|
|
|
179
214
|
1. **Prereleases participate in matching.** The check is `semver.satisfies(runtime, range, { includePrerelease: true })`. The `<0.3.0-0` upper bound exists precisely to exclude `0.3.0-alpha` and later *while* prereleases are included; conversely, **the range depends on that flag** — without it, `0.2.0-rc.2` would be judged incompatible. **When checking this range with other tooling, pass `includePrerelease`**: under default semver semantics (node-semver's prerelease rule accepts a prerelease only through a comparator with the same major.minor.patch tuple), `0.1.2-rc.1` / `0.2.0-rc.2` / `0.2.1-alpha.2` are all judged **unsatisfied** (measured with semver 7.8.5: `0.1.0-rc.6` is true under both semantics; the other three are plain=false / incl=true; `0.3.0-alpha.1` is false under both). **DSH's verdict is the one that counts.**
|
|
180
|
-
2. **The failure mode is "silently not loaded", not an error.** Specs that can be judged up front (adding a registry package) are refused before pnpm runs, with the exemption command printed. Git / tarball specs are judged after installation, and a failure rolls back the profile manifest and lockfile. But a plugin **already in the profile whose mismatch is only discovered at startup** has its row disabled: the process writes exactly one stderr line, `dsh: disabling profile plugin <row>: <reason>`. What the user sees is "the plugin isn't working" (no tools, no `/scout`) — not a loud red error.
|
|
215
|
+
2. **The failure mode is "silently not loaded", not an error.** Specs that can be judged up front (adding a registry package) are refused before pnpm runs, with the exemption command printed. Git / tarball specs are judged after installation, and a failure rolls back the profile manifest and lockfile. But a plugin **already in the profile whose mismatch is only discovered at startup** has its row disabled: the process writes exactly one stderr line, `dsh: disabling profile plugin <row>: <reason>`. What the user sees is "the plugin isn't working" (no tools, no `/scout`) — not a loud red error. **That line is visible to CLI users only**; the desktop app's stderr goes to `/dev/null` and there is no runtime log (see "Did it install?" above), so on desktop the state is only visible in **Settings → Built-in plugins → Plugin list** (the installed version, in turn, only on the **sidebar → Plugins page**).
|
|
181
216
|
3. **That single `@deepseek-ai/dsh-tools` peer carries the entire gate.** Changing the peer range changes the compatibility promise.
|
|
182
217
|
|
|
183
218
|
#### Escape hatch: profile-level exact-version exemptions
|
|
@@ -199,27 +234,80 @@ The exemption lives in the profile's `compatibility.json`, beside `package.json`
|
|
|
199
234
|
|
|
200
235
|
Granting requires explicit risk acceptance (CLI `--accept-risk`, plugin manager `acceptRisk: true`); DSH prints a risk warning before writing — an incompatible plugin may crash or corrupt data.
|
|
201
236
|
|
|
237
|
+
**Desktop app users**: `allow-version` is refused by profile name like every other `dsh plugin` subcommand, so this file must be written by hand. It is a flat JSON object — exact `package@version` → the exact DSH versions it is allowed on; with a desktop runtime of `0.2.0-rc.2`:
|
|
238
|
+
|
|
239
|
+
```json
|
|
240
|
+
{
|
|
241
|
+
"dsh-scout@0.9.3": ["0.2.0-rc.2"]
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
A hand-written grant is bound by the same four boundaries above (exact versions only, one package version paired with one DSH version, no authorization of install scripts, effective on the next composition) and it **bypasses the CLI's `--accept-risk` acknowledgement** — an incompatible plugin may crash or corrupt data. Read the exact runtime version from `desktopVersion` in `~/.dsh/dsh-runtimes/*/runtime.json`; a malformed record is ignored with a warning and never makes the profile unusable.
|
|
246
|
+
|
|
202
247
|
#### Verified version matrix
|
|
203
248
|
|
|
204
|
-
**The 0.9.
|
|
249
|
+
**The `dsh-scout@0.9.3` candidate tarball passed on four exact DSH versions** (before this release, 2026-10-13, isolated profiles, all four binaries fetched from npm rather than the local DSH): covering installation, cold startup, tool mounting, the **six-step real-host gate** (`scout_start` → export → cold restart → lazy rehydration → cross-language import → uninstall, plus the "marker missing / `complete:false`" negative controls), and unload. The full gate runs through `npm run check:release`; measured output:
|
|
205
250
|
|
|
206
251
|
```text
|
|
207
252
|
dsh-scout release gate: PASS (4 DSH versions, >=0.1.0-rc.6 <0.3.0-0)
|
|
208
253
|
```
|
|
209
254
|
|
|
210
|
-
| DSH version | npm channel (checked 2026-10-12) | 0.9.
|
|
255
|
+
| DSH version | npm channel (checked 2026-10-12) | 0.9.3 (candidate tarball) |
|
|
211
256
|
| --- | --- | --- |
|
|
212
257
|
| `0.1.0-rc.6` | Declared lower bound | Pass |
|
|
213
258
|
| `0.1.2-rc.1` | Older release regression | Pass |
|
|
214
259
|
| `0.2.0-rc.2` | `latest` / `next` | Pass |
|
|
215
260
|
| `0.2.1-alpha.2` | `alpha` | Pass |
|
|
216
261
|
|
|
217
|
-
This table previously recorded the **0.9.0** and **0.9.1** candidate tarball results; 0.9.
|
|
262
|
+
This table previously recorded the **0.9.0** and **0.9.1** candidate tarball results; 0.9.3 keeps the identical `peerDependencies` and `engines.dsh` ranges (**unchanged**) — this version changes the install docs and the diagnostic surface (the desktop-app path in the install chapter, the README version-reference guard, and the plugin version in `/scout status`), not dependencies or the runtime contract — and it passed the same gate again on the same four exact versions (4/4), so the table is updated to this version. The npm-channel column is still the 2026-10-12 check; this re-run did not re-check it. The previous release, **0.9.2, is published on npm** (`dist-tags.latest` = `0.9.2`): the release workflow (run `38406696598`) ran the same four-version gate before `pnpm pack`, so the 0.9.2 four-version pass this table recorded at the time is the exact artifact that shipped. The `/scout` command and Skill added in 0.9.1 are optional bindings, skipped silently on hosts without the corresponding services, so they do not affect loading.
|
|
218
263
|
|
|
219
264
|
Future `0.2.x` versions still require runtime verification. The [nightly compatibility workflow](https://github.com/MaxHou-infinity/dsh-scout/actions/workflows/compatibility-nightly.yml) resolves npm's `latest`, `next`, and `alpha` tags to exact versions before running tests and the isolated profile check. The badge shows the latest workflow result; this table records versions already verified.
|
|
220
265
|
|
|
221
266
|
> **A red nightly does not mean the plugin is broken**: it may simply mean the declared range expired (e.g. DSH published `0.3.0-alpha.1`). `check:release` reports "out of declared range (expected)" separately from "in range but failing (regression)" — the former calls for updating the range or using the exact-version exemption above, not for a regression fix.
|
|
222
267
|
|
|
268
|
+
## Tools (12)
|
|
269
|
+
|
|
270
|
+
| Tool | Purpose |
|
|
271
|
+
|---|---|
|
|
272
|
+
| `scout_start` | Create a due-diligence case |
|
|
273
|
+
| `scout_add_source` | Register a source (with evidence level) |
|
|
274
|
+
| `scout_ingest` | Batch-register collected results (infers source type/evidence level; can draft one claim per item) |
|
|
275
|
+
| `scout_search` | Search through the DSH Web Provider and auto-register result sources (type/evidence inferred per URL) |
|
|
276
|
+
| `scout_add_claim` | Add an evidence-bounded claim |
|
|
277
|
+
| `scout_verify_identity` | Verify the legal entity from an E3 official source |
|
|
278
|
+
| `scout_verify_claim` | Promote a claim with stronger evidence |
|
|
279
|
+
| `scout_report` | Render the current Markdown report |
|
|
280
|
+
| `scout_questions` | Derive a deduplicated, prioritized interview question list (up to 12; case-curated questions keep their quota) |
|
|
281
|
+
| `scout_compare` | Side-by-side comparison of 2–5 cases (decisions/identity/claims/risks/questions) |
|
|
282
|
+
| `scout_export` | Persist the five-file export + completion marker |
|
|
283
|
+
| `scout_import` | Restore a case from an export directory and recompute its decision (tolerates legacy exports, reports `complete`) |
|
|
284
|
+
|
|
285
|
+
### Output contract (since 0.9.1)
|
|
286
|
+
|
|
287
|
+
Mutating tools (`scout_start` / `scout_add_source` / `scout_ingest` / `scout_search` / `scout_add_claim` / `scout_verify_identity` / `scout_verify_claim` / `scout_import`, 8 in total) **no longer echo the whole case JSON back to the model**:
|
|
288
|
+
|
|
289
|
+
- `value` is a **structured object**: `{ ok, caseId, decision, identity, counts: { sources, claims, verified, open }, changed: { kind, ids }, nextActions, persist? }`;
|
|
290
|
+
- `render` is a **compact summary that never exceeds 1 KB as a whole**: decision + this call's delta + unresolved blockers + next steps. The cap is the render budget itself (`MAX_RENDER_BYTES = 1024` B): the ellipsis's own UTF-8 length is subtracted from the budget before cutting, so **the final string including the ellipsis never exceeds 1024 B**;
|
|
291
|
+
- `persist: { persisted, targetDir, error? }` appears **only on the `autoPersist` path of mutating tools** (the key is omitted when no persist was attempted). **A failed persist is no longer silent**: `persist.persisted === false` plus `persist.error`, and no `case_exported` event is recorded. `scout_export` carries **no `persist` key** — it expresses the same thing through **top-level** `persisted` / `complete` / `error`;
|
|
292
|
+
- **Full data still comes from `scout_report` (Markdown) and `scout_export` (files)** — the model sees a summary, not the whole ledger.
|
|
293
|
+
|
|
294
|
+
Read-class tools keep their own shapes: `scout_report` → `{ caseId, decision, report, coverage }`; `scout_questions` → `{ caseId, questions }`; `scout_compare` → `{ caseIds, report }`; `scout_export` → `{ caseId, targetDir, files, persisted, complete, error? }`, where `targetDir` is the **resolved absolute path**. `scout_import` reuses the mutating envelope and adds `sourceDir` (the directory it restored from) and `complete` (whether the export was complete).
|
|
295
|
+
|
|
296
|
+
### Commands & Skill (new in 0.9.1)
|
|
297
|
+
|
|
298
|
+
| Entry point | Purpose |
|
|
299
|
+
|---|---|
|
|
300
|
+
| `/scout` command | `status` / `questions` / `report` / `export` sub-actions (reusing the tool logic). The host automatically logs `command/run` + `command/done` around the handler — both names are in the host's known event vocabulary, so the session log stays reconstructable |
|
|
301
|
+
| `scout` Skill | The due-diligence workflow registered by the plugin itself (`ctx.skills.register`, no files, no client bundle): start → search/ingest → claim → verify_identity → report → questions, plus the four evidence disciplines; it disappears on unload |
|
|
302
|
+
|
|
303
|
+
Usage (identical to the implementation):
|
|
304
|
+
|
|
305
|
+
```text
|
|
306
|
+
/scout status <caseId> | /scout questions <caseId> | /scout report <caseId> | /scout export <caseId> [targetDir]
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Both are **optional bindings**: when the host exposes no `commands` / `skills` service they are skipped silently, and plugin loading plus tools are unaffected.
|
|
310
|
+
|
|
223
311
|
## Configuration (optional)
|
|
224
312
|
|
|
225
313
|
Configure `dsh-scout` in the DSH profile's `cordis.patch.yml`:
|
|
@@ -235,6 +323,7 @@ Configure `dsh-scout` in the DSH profile's `cordis.patch.yml`:
|
|
|
235
323
|
```
|
|
236
324
|
|
|
237
325
|
- A relative `scoutDir` resolves against the **session cwd**, not the DSH process cwd;
|
|
326
|
+
- **Desktop app**: the default `scoutDir` (`./dsh-scout`) depends on cwd, and a desktop session's cwd differs from the CLI's, so give `id: dsh-scout` an absolute path in `~/.dsh/profiles/desktop/cordis.patch.yml`; the app maintains that file, so quit the app before editing it, or the write may be overwritten;
|
|
238
327
|
- With `autoPersist: true`, every mutation persists automatically; **failures are visible**: the return value carries `persist.persisted=false` plus `persist.error`, and no `case_exported` event is written;
|
|
239
328
|
- `language` affects the report, interview questions, the comparison report, and the explanatory text that `scout_ingest` writes into auto-drafted claims (`confidenceNote` / `nextAction`); it also aligns case-owned text that is **still at its factory default**, at two different granularities: `decisionObjective` / `role.fitQuestion` are decided **per field** (a field still at its factory default is aligned); curated interview questions are decided **entry by entry, by index** — when the set has the factory length, an entry still equal to its factory slot is replaced by this deployment's default at the same index and **an entry the user edited is kept verbatim**; a set whose length differs from the factory array is taken as fully user-authored and preserved as a whole. The test is "does this entry equal its factory slot", not edit history (editing an entry back to the factory text makes it align). It is a no-op when it matches the case's own language, so the `zh-CN` default changes nothing for existing users. Separately, `language` in `case.json` is the **rendering language of this deployment**, not the language of the file's contents: alignment reads only that label and **never checks whether the label is consistent with the content**, so a hand-edited file whose `language` disagrees with its prose is taken at its word and skipped by the "same language" early return (the normal export / import / upgrade paths are unaffected: a 0.9.0 export always says `zh-CN`, matching its content).
|
|
240
329
|
|
package/README.md
CHANGED
|
@@ -103,66 +103,101 @@ scout_export / scout_import 落盘持久化(五文件 + 完成标记),换
|
|
|
103
103
|
- **Sources**:带 URL 的来源清单(可点击回溯)
|
|
104
104
|
- **Interview questions**:建议的面试反问(未调查维度的问题优先)
|
|
105
105
|
|
|
106
|
-
##
|
|
106
|
+
## 安装
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|---|---|
|
|
110
|
-
| `scout_start` | 创建尽调案例 |
|
|
111
|
-
| `scout_add_source` | 登记信息来源(含证据等级) |
|
|
112
|
-
| `scout_ingest` | 批量登记采集结果(自动推断来源类型/证据等级,可随来源一键登记主张草稿) |
|
|
113
|
-
| `scout_search` | 调用 DSH Web Provider 搜索并自动登记结果来源(type/evidence 按 URL 推断) |
|
|
114
|
-
| `scout_add_claim` | 添加证据受限的主张 |
|
|
115
|
-
| `scout_verify_identity` | 用 E3 官方源核验法定主体 |
|
|
116
|
-
| `scout_verify_claim` | 用更强证据提升主张为 verified |
|
|
117
|
-
| `scout_report` | 渲染当前 Markdown 报告 |
|
|
118
|
-
| `scout_questions` | 从案例派生去重、按优先级排序的面试问题清单(上限 12 条;案例自带的精选问题保留名额) |
|
|
119
|
-
| `scout_compare` | 2–5 个案例的并排对比报告(决策/主体/关键结论/风险/面试问题) |
|
|
120
|
-
| `scout_export` | 持久化五文件导出(case/sources/claims/events/report)+ 完成标记 |
|
|
121
|
-
| `scout_import` | 从导出目录恢复案例并重算决策(容忍旧导出,报 `complete`) |
|
|
108
|
+
先确认你在哪运行——两条入口的安装方式完全不同,**不要混用**:
|
|
122
109
|
|
|
123
|
-
|
|
110
|
+
| 你在哪运行 | 目标 profile | 安装方式 |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| **桌面 App(DeepSeek Harness)** | `desktop` | **App 内安装**(唯一路径,见下) |
|
|
113
|
+
| CLI / headless / 自建 profile | 你自己的 profile 名 | `dsh plugin --profile <your-profile> add …` |
|
|
124
114
|
|
|
125
|
-
|
|
115
|
+
### 路径 0:桌面 App(推荐)
|
|
126
116
|
|
|
127
|
-
|
|
128
|
-
- `render` 是**整串不超过 1 KB 的紧凑摘要**:决策 + 本次增量 + 未核验阻断项 + 下一步。上限就是渲染预算本身(`MAX_RENDER_BYTES = 1024` B):省略号自身的 UTF-8 长度先从预算里扣掉、再按码元裁切,因此**含省略号的整串也不会超过 1024 B**;
|
|
129
|
-
- `persist: { persisted, targetDir, error? }` **只出现在变更类工具的 `autoPersist` 路径**(未尝试落盘时该键省略)。**落盘失败不再静默**:`persist.persisted === false` + `persist.error`,且不会产生 `case_exported` 事件。`scout_export` **不带 `persist` 键**,它用**顶层** `persisted` / `complete` / `error` 表达同一件事;
|
|
130
|
-
- **全量数据仍由 `scout_report`(Markdown 报告)与 `scout_export`(文件)提供**——模型看到的是摘要,不是台账全文。
|
|
117
|
+
桌面版的 `desktop` profile 由 Electron 应用独占,CLI 无法管理它——`dsh plugin --profile desktop list` 与 `add` 都会被直接拒绝:
|
|
131
118
|
|
|
132
|
-
|
|
119
|
+
```text
|
|
120
|
+
error: profile "desktop" is managed exclusively by the Electron application
|
|
121
|
+
```
|
|
133
122
|
|
|
134
|
-
|
|
123
|
+
这是 CLI 里**按 profile 名**的硬拒绝,该 profile 的**所有** `dsh plugin` 子命令都会命中——包括下面兼容性小节里的 `allow-version`。请在**侧边栏 → 插件页**(安装、启用、移除都在这一页)里安装:
|
|
135
124
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
| `scout` Skill | 插件直接注册的尽调工作流(`ctx.skills.register`,不需要落文件、不需要 client bundle):start → search/ingest → claim → verify_identity → report → questions + 四条证据纪律;卸载即消失 |
|
|
125
|
+
```sh
|
|
126
|
+
dsh-scout@0.9.3
|
|
127
|
+
```
|
|
140
128
|
|
|
141
|
-
|
|
129
|
+
> 版本务必显式写死。pnpm ≥ 11 默认启用最小发布年龄(minimum release age)供应链保护,裸包名会让刚发布的版本被静默跳过、回退到旧版(0.9.2 发布后立即安装曾解析到 0.9.0);写上精确版本后 pnpm 会把它记入 profile 的 `minimumReleaseAgeExclude`(输出里打印 `Added 1 entry to …`)。
|
|
142
130
|
|
|
143
|
-
|
|
144
|
-
|
|
131
|
+
装完不需要重启:实测 12 个 `scout_*` 工具即时注入当前会话。桌面会话的 cwd 与 CLI 不同,建议在 profile 的 `cordis.patch.yml` 里给 `scoutDir` 配绝对路径(见下文「配置」)。
|
|
132
|
+
|
|
133
|
+
### 路径 1:CLI(npm,推荐)
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
# 把 <your-profile> 换成你自己的 profile 名,不要照抄示例
|
|
137
|
+
dsh plugin --profile <your-profile> add dsh-scout@0.9.3
|
|
145
138
|
```
|
|
146
139
|
|
|
147
|
-
|
|
140
|
+
<details>
|
|
141
|
+
<summary>怎么知道我的 profile 名?</summary>
|
|
148
142
|
|
|
149
|
-
|
|
143
|
+
`dsh` 没有 `profile list` 子命令(`profile` 会被当成 profile 名解析并报错),直接看目录:
|
|
150
144
|
|
|
151
|
-
|
|
145
|
+
```sh
|
|
146
|
+
ls ~/.dsh/profiles # 或用 $DSH_HOME/profiles
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
列出的每个名字都是可用 profile 名(如 `web`,或你自建的 profile)。`desktop` 由 App 独占,CLI 对它执行任何 `dsh plugin` 子命令都会被拒绝。
|
|
150
|
+
</details>
|
|
151
|
+
|
|
152
|
+
**不要照抄示例名**(例如 `scout-demo`):CLI 会照常创建并使用它、不报任何错——结果是插件装进了另一个 profile,你以为装好了却完全没生效。
|
|
153
|
+
|
|
154
|
+
### 路径 2:本地 tarball(离线 / 可复现)
|
|
152
155
|
|
|
153
156
|
```sh
|
|
154
|
-
#
|
|
155
|
-
dsh plugin --profile
|
|
157
|
+
pnpm pack # 生成 dsh-scout-0.9.3.tgz
|
|
158
|
+
dsh plugin --profile <your-profile> add "file:$PWD/dsh-scout-0.9.3.tgz"
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 其他安装方式与取舍
|
|
162
|
+
|
|
163
|
+
| 来源 | 自带构建产物 | 执行安装脚本 | 建议 |
|
|
164
|
+
|---|---|---|---|
|
|
165
|
+
| npm(路径 1) | ✅ 自带 `dist/` | ❌(实测 `pendingBuilds: []`) | **推荐** |
|
|
166
|
+
| 本地 tarball(路径 2) | ✅(`pnpm pack` 产物) | ❌ | 离线 / 自测 |
|
|
167
|
+
| git:`github:MaxHou-infinity/dsh-scout#v0.9.3` | ❌(仓库不含 `dist/`) | ✅ `prepare` 会跑 `tsc`,并安装 devDependencies | **不推荐**;只在需要未发布提交时使用 |
|
|
156
168
|
|
|
157
|
-
|
|
158
|
-
pnpm pack # 生成 dsh-scout-0.9.2.tgz
|
|
159
|
-
dsh plugin --profile scout-demo add "file:$PWD/dsh-scout-0.9.2.tgz"
|
|
169
|
+
git 路径的 ref 必须是**真实存在的 tag 或 commit**:仓库自 `v0.3.0` 起共 10 个 tag(`v0.3.0` … `v0.9.2`;`v0.9.1` 是本地迭代版、未打 tag),本次发布创建 `v0.9.3`。它也是三条路径里唯一会执行代码的:仓库不含 `dist/`,装完必然在本地构建,pnpm 可能要求为 `dsh-scout` 显式添加 `allowBuilds`(只放行你审查过的固定版本)。
|
|
160
170
|
|
|
161
|
-
|
|
162
|
-
|
|
171
|
+
> 桌面 App 自带 node / pnpm 运行时(实测 node 24.21.0 + pnpm 11.7.0),**无需**安装 Node;「Node ≥ 22.19」只对 CLI / 门禁路径成立。
|
|
172
|
+
|
|
173
|
+
### 装上了吗(成功判据)
|
|
174
|
+
|
|
175
|
+
**桌面 App**
|
|
176
|
+
|
|
177
|
+
1. **侧边栏 → 插件页**:`dsh-scout` 出现在「已安装」里;**打开它的详情页**,标题旁带 `v0.9.3`——版本号只在这一页(列表卡片上只有「实验性 / 异常」状态标签);
|
|
178
|
+
2. **设置 → 内置插件 → 插件列表**:`dsh-scout` 行是 **已启用**、运行状态 **运行中**,不是 **已停用** / **启动失败** / **条件启用**(这一页**不显示版本号**);
|
|
179
|
+
3. 新开一轮对话,工具列表里出现 12 个 `scout_*` 工具;
|
|
180
|
+
4. 输入 `/scout status <caseId>` 能命中命令,且输出末尾带插件版本(`· dsh-scout 0.9.3`)——桌面看不到 stderr 与日志,这是确认运行时真正加载了哪个版本的自证面。
|
|
181
|
+
|
|
182
|
+
**CLI**
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
# 组合树里应出现 dsh-scout 那一层
|
|
186
|
+
dsh --profile <your-profile> --dump-config | grep -A2 'dsh-scout'
|
|
163
187
|
```
|
|
164
188
|
|
|
165
|
-
|
|
189
|
+
但**组合进去 ≠ 运行时挂上了**:最可靠的判据始终是「12 个 `scout_*` 工具是否出现」「`/scout` 是否命中」。
|
|
190
|
+
|
|
191
|
+
CLI 在运行时不兼容时会把插件行置为 disabled,进程只在 stderr 打一行 `dsh: disabling profile plugin <row>: <reason>`——现象是"插件没生效",不是显眼的红色报错。**桌面 App 看不到 stderr**(实测 Electron 主进程的 fd0/fd1/fd2 都指向 `/dev/null`,`~/Library/Logs/DeepSeek Harness/` 为空目录、全盘没有 DSH 运行日志),桌面排障只能走 GUI:**设置 → 内置插件 → 插件列表**按「会话插件 / 全局插件」分组,用 **已启用 / 已停用 / 启动失败 / 条件启用** 标签与 **运行中 / 启动失败 / 等待依赖 / 未运行** 运行状态回答"装没装、为什么没生效"(这一页**没有版本号**)——启动时被禁用的插件行(peer 不匹配是其中一种)会以「已停用」出现在这里,宿主侧的投影就是 `enabled: !entry.disabled`;那行被丢进 `/dev/null` 的 stderr,答案其实已经在 GUI 里。装的是哪一版,去**侧边栏 → 插件页**打开该插件的详情页看 `v{version}`。
|
|
192
|
+
|
|
193
|
+
### 卸载与升级
|
|
194
|
+
|
|
195
|
+
```sh
|
|
196
|
+
dsh plugin --profile <your-profile> add dsh-scout@<new-version> # 升级:换成目标版本,同样写死
|
|
197
|
+
dsh plugin --profile <your-profile> remove dsh-scout # 卸载
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
桌面 App 请在**侧边栏 → 插件页**里升级 / 移除。安装失败会回滚 profile 清单与 lockfile。
|
|
166
201
|
|
|
167
202
|
### DSH 兼容性
|
|
168
203
|
|
|
@@ -177,7 +212,7 @@ DSH 对插件的兼容性有**三个层次**,不要混为一谈:
|
|
|
177
212
|
三个必须知道的细节:
|
|
178
213
|
|
|
179
214
|
1. **预发布版本参与匹配。** 判定用 `semver.satisfies(runtime, range, { includePrerelease: true })`。上界写成 `<0.3.0-0` 正是为了在开启 prerelease 的前提下排除 `0.3.0-alpha` 及以后;反过来说,这条 range 的写法**依赖这个标志位**——去掉它,`0.2.0-rc.2` 会被判成不匹配。**用其它工具核对这条范围时请带上 `includePrerelease`**:按默认 semver 语义(node-semver 的预发布规则——预发布版本只被「同 major.minor.patch 元组且带预发布」的比较器接受),`0.1.2-rc.1` / `0.2.0-rc.2` / `0.2.1-alpha.2` 都会被判为**不满足**(semver 7.8.5 实测:`0.1.0-rc.6` 两种语义均为 true;后三者 plain=false / incl=true;`0.3.0-alpha.1` 两者均为 false)。**以 DSH 的判定为准。**
|
|
180
|
-
2. **失败的形态是「静默不加载」,不是报错。** 安装时能预判的 spec(`add` 一个 registry 包)会在 pnpm 执行前直接拒绝并打印豁免命令;git / tarball spec 在安装后判定,失败会回滚 profile 清单与 lockfile。而**已经在 profile 里、启动时才发现不匹配**的插件行会被置为 disabled,本进程只在 stderr 打一行 `dsh: disabling profile plugin <row>: <reason>`——用户看到的现象是"插件没生效"(工具不在、`/scout`
|
|
215
|
+
2. **失败的形态是「静默不加载」,不是报错。** 安装时能预判的 spec(`add` 一个 registry 包)会在 pnpm 执行前直接拒绝并打印豁免命令;git / tarball spec 在安装后判定,失败会回滚 profile 清单与 lockfile。而**已经在 profile 里、启动时才发现不匹配**的插件行会被置为 disabled,本进程只在 stderr 打一行 `dsh: disabling profile plugin <row>: <reason>`——用户看到的现象是"插件没生效"(工具不在、`/scout` 不在),不是一条显眼的红色报错。**这一行只对 CLI 用户可见**;桌面 App 的 stderr 指向 `/dev/null`、没有运行日志(见上文「装上了吗」),桌面上的状态只能在**设置 → 内置插件 → 插件列表**里看(装在哪个版本则看**侧边栏 → 插件页**)。
|
|
181
216
|
3. **这一条 `@deepseek-ai/dsh-tools` peer 就是全部门禁。** 改 peer 范围等于改兼容承诺。
|
|
182
217
|
|
|
183
218
|
#### 逃生门:profile 级精确版本豁免
|
|
@@ -199,27 +234,80 @@ dsh plugin --profile <name> revoke-version <package>@<version> --dsh-version <ex
|
|
|
199
234
|
|
|
200
235
|
授予豁免需要显式风险确认(CLI 的 `--accept-risk`,插件管理器里是 `acceptRisk: true`),DSH 会在写入前打印风险警告——不兼容的插件可能崩溃或损坏数据。
|
|
201
236
|
|
|
237
|
+
**桌面 App 用户**:`allow-version` 与其它 `dsh plugin` 子命令一样被按 profile 名拒绝,需要手动写这个文件。它是一个平铺的 JSON 对象——精确 `package@version` → 允许的精确 DSH 版本数组,例如桌面 App 的运行时为 `0.2.0-rc.2` 时:
|
|
238
|
+
|
|
239
|
+
```json
|
|
240
|
+
{
|
|
241
|
+
"dsh-scout@0.9.3": ["0.2.0-rc.2"]
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
手写同样受上面四条边界约束(只接受精确版本、只授权「这一个包版本 + 这一个 DSH 版本」这一对、不授权安装脚本、下一次组合生效),并且**绕过了 CLI 的 `--accept-risk` 风险确认**——不兼容的插件可能崩溃或损坏数据。运行时的精确版本可从 `~/.dsh/dsh-runtimes/*/runtime.json` 的 `desktopVersion` 读取;写法不合规的记录会被忽略并给出告警,不会让 profile 不可用。
|
|
246
|
+
|
|
202
247
|
#### 已实测版本矩阵
|
|
203
248
|
|
|
204
|
-
|
|
249
|
+
**`dsh-scout@0.9.3` 候选 tarball 已在四个精确 DSH 版本上实测通过**(2026-10-13 发布前,隔离 profile,四个 binary 均从 npm 真实取用、非本机 DSH):覆盖安装、冷启动、工具挂载、**六步真实宿主门禁**(`scout_start` → 导出 → 冷重启 → 惰性回填 → 跨语言导入 → 卸载,外加「标记缺失 / `complete:false`」两个负向对照)和卸载。完整门禁由 `npm run check:release` 执行,实测输出:
|
|
205
250
|
|
|
206
251
|
```text
|
|
207
252
|
dsh-scout release gate: PASS (4 DSH versions, >=0.1.0-rc.6 <0.3.0-0)
|
|
208
253
|
```
|
|
209
254
|
|
|
210
|
-
| DSH 版本 | npm 渠道(2026-10-12 核对) | 0.9.
|
|
255
|
+
| DSH 版本 | npm 渠道(2026-10-12 核对) | 0.9.3(候选 tarball)结果 |
|
|
211
256
|
| --- | --- | --- |
|
|
212
257
|
| `0.1.0-rc.6` | 兼容范围下界 | 通过 |
|
|
213
258
|
| `0.1.2-rc.1` | 旧版回归 | 通过 |
|
|
214
259
|
| `0.2.0-rc.2` | `latest` / `next` | 通过 |
|
|
215
260
|
| `0.2.1-alpha.2` | `alpha` | 通过 |
|
|
216
261
|
|
|
217
|
-
本表此前记录过 **0.9.0** 与 **0.9.1** 候选 tarball 的结果;0.9.
|
|
262
|
+
本表此前记录过 **0.9.0** 与 **0.9.1** 候选 tarball 的结果;0.9.3 沿用同一 `peerDependencies` 与 `engines.dsh` 范围(**没有变化**):本版改的是安装文档与诊断面——README 安装章节补上桌面 App 主路径、README 版本引用守卫、`/scout status` 输出带插件版本——依赖与运行时契约未动,并用同一道门禁在同样四个精确版本上复跑通过(4/4),故更新为本版本。npm 渠道那一列仍是 2026-10-12 的核对结果,本次复跑未重新核对。上一版 **0.9.2 已发布到 npm**(`dist-tags.latest` = `0.9.2`):发布 workflow(run `38406696598`)在 `pnpm pack` 之前跑了同一道四版本门禁,所以当时这张表记录的 0.9.2 四版本通过,就是最终发布的那份。0.9.1 新增的 `/scout` 命令与 Skill 走可选绑定,宿主没有对应服务时静默跳过,不影响加载。
|
|
218
263
|
|
|
219
264
|
未来的 `0.2.x` 版本虽落在声明范围内,仍需实际验证。[夜间兼容检查](https://github.com/MaxHou-infinity/dsh-scout/actions/workflows/compatibility-nightly.yml)每天解析 npm 的 `latest`、`next`、`alpha` 到精确版本,再运行测试和隔离 profile 检查。徽章显示该工作流最近一次运行结果;以上表格记录已完成的精确版本验证。
|
|
220
265
|
|
|
221
266
|
> **夜间变红不等于插件坏了**:它可能只是声明范围过期(例如 DSH 发布 `0.3.0-alpha.1`)。`check:release` 会把「超出声明范围(预期)」与「范围内但失败(回归)」分开报告——前者应当更新声明范围,或按上面的精确版本豁免处理,而不是当成回归去修。
|
|
222
267
|
|
|
268
|
+
## 工具清单(12 个)
|
|
269
|
+
|
|
270
|
+
| 工具 | 作用 |
|
|
271
|
+
|---|---|
|
|
272
|
+
| `scout_start` | 创建尽调案例 |
|
|
273
|
+
| `scout_add_source` | 登记信息来源(含证据等级) |
|
|
274
|
+
| `scout_ingest` | 批量登记采集结果(自动推断来源类型/证据等级,可随来源一键登记主张草稿) |
|
|
275
|
+
| `scout_search` | 调用 DSH Web Provider 搜索并自动登记结果来源(type/evidence 按 URL 推断) |
|
|
276
|
+
| `scout_add_claim` | 添加证据受限的主张 |
|
|
277
|
+
| `scout_verify_identity` | 用 E3 官方源核验法定主体 |
|
|
278
|
+
| `scout_verify_claim` | 用更强证据提升主张为 verified |
|
|
279
|
+
| `scout_report` | 渲染当前 Markdown 报告 |
|
|
280
|
+
| `scout_questions` | 从案例派生去重、按优先级排序的面试问题清单(上限 12 条;案例自带的精选问题保留名额) |
|
|
281
|
+
| `scout_compare` | 2–5 个案例的并排对比报告(决策/主体/关键结论/风险/面试问题) |
|
|
282
|
+
| `scout_export` | 持久化五文件导出(case/sources/claims/events/report)+ 完成标记 |
|
|
283
|
+
| `scout_import` | 从导出目录恢复案例并重算决策(容忍旧导出,报 `complete`) |
|
|
284
|
+
|
|
285
|
+
### 输出契约(0.9.1 起)
|
|
286
|
+
|
|
287
|
+
变更类工具(`scout_start` / `scout_add_source` / `scout_ingest` / `scout_search` / `scout_add_claim` / `scout_verify_identity` / `scout_verify_claim` / `scout_import`,共 8 个)**不再把整份 case JSON 回吐给模型**:
|
|
288
|
+
|
|
289
|
+
- `value` 是**结构化对象**:`{ ok, caseId, decision, identity, counts: { sources, claims, verified, open }, changed: { kind, ids }, nextActions, persist? }`;
|
|
290
|
+
- `render` 是**整串不超过 1 KB 的紧凑摘要**:决策 + 本次增量 + 未核验阻断项 + 下一步。上限就是渲染预算本身(`MAX_RENDER_BYTES = 1024` B):省略号自身的 UTF-8 长度先从预算里扣掉、再按码元裁切,因此**含省略号的整串也不会超过 1024 B**;
|
|
291
|
+
- `persist: { persisted, targetDir, error? }` **只出现在变更类工具的 `autoPersist` 路径**(未尝试落盘时该键省略)。**落盘失败不再静默**:`persist.persisted === false` + `persist.error`,且不会产生 `case_exported` 事件。`scout_export` **不带 `persist` 键**,它用**顶层** `persisted` / `complete` / `error` 表达同一件事;
|
|
292
|
+
- **全量数据仍由 `scout_report`(Markdown 报告)与 `scout_export`(文件)提供**——模型看到的是摘要,不是台账全文。
|
|
293
|
+
|
|
294
|
+
读类工具各有自己的形状:`scout_report` → `{ caseId, decision, report, coverage }`;`scout_questions` → `{ caseId, questions }`;`scout_compare` → `{ caseIds, report }`;`scout_export` → `{ caseId, targetDir, files, persisted, complete, error? }`,其中 `targetDir` 是**解析后的绝对路径**。`scout_import` 复用变更类信封,并额外带 `sourceDir`(恢复来源目录)与 `complete`(导出是否完整)。
|
|
295
|
+
|
|
296
|
+
### 命令与 Skill(0.9.1 新增)
|
|
297
|
+
|
|
298
|
+
| 入口 | 作用 |
|
|
299
|
+
|---|---|
|
|
300
|
+
| `/scout` 命令 | `status` / `questions` / `report` / `export` 四个子动作(复用工具逻辑)。宿主会在处理前后自动落 `command/run` + `command/done` 事件——两者都在宿主已知事件词表内,所以会话日志天然可重建 |
|
|
301
|
+
| `scout` Skill | 插件直接注册的尽调工作流(`ctx.skills.register`,不需要落文件、不需要 client bundle):start → search/ingest → claim → verify_identity → report → questions + 四条证据纪律;卸载即消失 |
|
|
302
|
+
|
|
303
|
+
命令用法(与实现一致):
|
|
304
|
+
|
|
305
|
+
```text
|
|
306
|
+
/scout status <caseId> | /scout questions <caseId> | /scout report <caseId> | /scout export <caseId> [targetDir]
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
两者都是**可选绑定**:宿主没有 `commands` / `skills` 服务时静默跳过,不影响插件加载与工具使用。
|
|
310
|
+
|
|
223
311
|
## 配置(可选)
|
|
224
312
|
|
|
225
313
|
在 DSH profile 的 `cordis.patch.yml` 中为 `dsh-scout` 配置:
|
|
@@ -235,6 +323,7 @@ dsh-scout release gate: PASS (4 DSH versions, >=0.1.0-rc.6 <0.3.0-0)
|
|
|
235
323
|
```
|
|
236
324
|
|
|
237
325
|
- 相对 `scoutDir` 以**会话的 cwd** 为基准解析,不再落到 DSH 进程的当前目录;
|
|
326
|
+
- **桌面 App**:`scoutDir` 的默认值 `./dsh-scout` 依赖 cwd,而桌面会话的 cwd 语义与 CLI 不同,建议在 `~/.dsh/profiles/desktop/cordis.patch.yml` 里给 `id: dsh-scout` 直接写绝对路径;该文件由 App 维护,手改前先退出 App,避免写入被覆盖;
|
|
238
327
|
- `autoPersist: true` 时,每次变更后自动落盘;**失败可见**:返回值带 `persist.persisted=false` + `persist.error`,且不会写 `case_exported` 事件;
|
|
239
328
|
- `language` 影响报告、面试问题、对比报告,以及 `scout_ingest` 采集草稿自动写入的说明文字(`confidenceNote` / `nextAction`);它还会对齐案例自带、**仍是出厂默认**的文案,判定粒度不同:`decisionObjective` / `role.fitQuestion` 是**逐字段**(该字段仍是出厂默认即对齐);精选面试问题是**按下标逐条**——长度与出厂数组相同时,该下标仍是出厂默认的条目替换为本部署语言的同下标默认值,**用户改过的那条保持原样**;长度与出厂数组不同时,整组视为用户自撰、原样保留。判定依据是「是否等于该下标的出厂默认」,不是编辑历史(把某条改回出厂原文,那条会被对齐)。与案例自带语言相同时是 no-op,默认 `zh-CN` 对既有用户零变化。另外,`case.json` 里的 `language` 是**本部署的渲染语言**,不是文件内容的语言:对齐只按这个标签判定,**不校验标签与内容是否自洽**,所以手工把 `language` 改成与内容不符的值再导入时,插件会按「语言相同」提前返回、不做校正(正常的导出 / 导入 / 升级路径不受影响:0.9.0 旧导出的 `language` 恒为 `zh-CN`,与其内容一致)。
|
|
240
329
|
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,23 @@ import z from '@deepseek-ai/schemastery';
|
|
|
3
3
|
import { type ScoutLanguage } from './i18n.js';
|
|
4
4
|
export declare const name = "dsh-scout";
|
|
5
5
|
export declare const inject: string[];
|
|
6
|
+
/**
|
|
7
|
+
* The version this source tree ships, stated as a literal.
|
|
8
|
+
*
|
|
9
|
+
* It is deliberately never read back from `package.json`. A release checklist
|
|
10
|
+
* anchor only works when the version is asserted in two independent places: the
|
|
11
|
+
* assertion compares this literal against the manifest, so a bump that updates
|
|
12
|
+
* one and forgets the other fails the suite instead of shipping silently.
|
|
13
|
+
* `tests/acceptance.test.mjs` pins this constant, `package.json` and the
|
|
14
|
+
* `/scout status` output to the same string.
|
|
15
|
+
*
|
|
16
|
+
* Where this reaches a user: `runScoutCommand` prints it in `/scout status`.
|
|
17
|
+
* It cannot be printed at load time — a plugin's log output is not visible in
|
|
18
|
+
* any DSH surface (cordis only buffers it in memory), and a plugin that failed
|
|
19
|
+
* to load never runs at all, so "is it loaded, and which version?" is answered
|
|
20
|
+
* by the settings plugin list instead.
|
|
21
|
+
*/
|
|
22
|
+
export declare const PLUGIN_VERSION = "0.9.3";
|
|
6
23
|
export interface Config {
|
|
7
24
|
/** Default directory for case exports; case files land under `<scoutDir>/<caseId>/`. */
|
|
8
25
|
scoutDir?: string;
|