@dsh-enhanced/dsh-rsi-cli 0.1.48

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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +231 -0
  3. package/bin/dsh-rsi.js +11 -0
  4. package/lib/backup.d.ts +16 -0
  5. package/lib/backup.d.ts.map +1 -0
  6. package/lib/backup.js +27 -0
  7. package/lib/backup.js.map +1 -0
  8. package/lib/diagnose.d.ts +33 -0
  9. package/lib/diagnose.d.ts.map +1 -0
  10. package/lib/diagnose.js +145 -0
  11. package/lib/diagnose.js.map +1 -0
  12. package/lib/index.d.ts +46 -0
  13. package/lib/index.d.ts.map +1 -0
  14. package/lib/index.js +592 -0
  15. package/lib/index.js.map +1 -0
  16. package/lib/install.d.ts +33 -0
  17. package/lib/install.d.ts.map +1 -0
  18. package/lib/install.js +64 -0
  19. package/lib/install.js.map +1 -0
  20. package/lib/paths.d.ts +61 -0
  21. package/lib/paths.d.ts.map +1 -0
  22. package/lib/paths.js +168 -0
  23. package/lib/paths.js.map +1 -0
  24. package/lib/process-guard.d.ts +51 -0
  25. package/lib/process-guard.d.ts.map +1 -0
  26. package/lib/process-guard.js +143 -0
  27. package/lib/process-guard.js.map +1 -0
  28. package/lib/purge.d.ts +58 -0
  29. package/lib/purge.d.ts.map +1 -0
  30. package/lib/purge.js +204 -0
  31. package/lib/purge.js.map +1 -0
  32. package/lib/run.d.ts +27 -0
  33. package/lib/run.d.ts.map +1 -0
  34. package/lib/run.js +53 -0
  35. package/lib/run.js.map +1 -0
  36. package/lib/secrets.d.ts +22 -0
  37. package/lib/secrets.d.ts.map +1 -0
  38. package/lib/secrets.js +107 -0
  39. package/lib/secrets.js.map +1 -0
  40. package/lib/services.d.ts +89 -0
  41. package/lib/services.d.ts.map +1 -0
  42. package/lib/services.js +339 -0
  43. package/lib/services.js.map +1 -0
  44. package/lib/update.d.ts +59 -0
  45. package/lib/update.d.ts.map +1 -0
  46. package/lib/update.js +160 -0
  47. package/lib/update.js.map +1 -0
  48. package/lib/version.d.ts +2 -0
  49. package/lib/version.d.ts.map +1 -0
  50. package/lib/version.js +2 -0
  51. package/lib/version.js.map +1 -0
  52. package/lib/weburl.d.ts +36 -0
  53. package/lib/weburl.d.ts.map +1 -0
  54. package/lib/weburl.js +106 -0
  55. package/lib/weburl.js.map +1 -0
  56. package/package.json +54 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 dsh-enhanced contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,231 @@
1
+ # @dsh-enhanced/dsh-rsi-cli — 全局 `dsh-rsi` 命令
2
+
3
+ DSH enhanced 插件集合的安装 / 控制 / 诊断 / 彻底卸载工具。安装插件集合(npm cohort 或本地 checkout 形态)后,安装器会同时把本包装成全局 `dsh-rsi` 命令;也可单独安装:
4
+
5
+ ```bash
6
+ npm install --global @dsh-enhanced/dsh-rsi-cli
7
+ ```
8
+
9
+ 零运行时依赖(仅用 Node.js 内置模块),要求 Node.js `^22.19.0 || >=24.0.0`,支持 macOS 与 Linux。
10
+
11
+ ## 命令
12
+
13
+ ```
14
+ dsh-rsi [全局选项] <命令>
15
+ ```
16
+
17
+ | 命令 | 说明 |
18
+ | --- | --- |
19
+ | `status`(默认) | 列出 DSH home、各 profile 与安装形态(npm 实体副本 / local 符号链接)、全局 host 版本、launchd / systemd 受管服务状态、外部凭据条目数、生命周期事务/锁残留。**只读**。 |
20
+ | `doctor` | 在 `status` 基础上扫描各 profile 的 `*-host.error.log`,识别已知崩溃模式(如旧版 event-support oracle 拒绝注册)并给出升级/重建建议。**只读**。 |
21
+ | `start` / `stop` / `restart` | 切换已注册受管常驻服务的运行状态。**只改运行状态**,不新建/改写/删除 launchd plist 或 systemd unit;未注册时报错并给出注册指引。 |
22
+ | `logs` | 查看各 profile 的受管 `*-host.log` / `*-host.error.log` 尾部(默认末 200 行)。**只读**。 |
23
+ | `web-url` | 从运行中受管服务的 journal(Linux)或 `*-host.log`(macOS)解析最近一次 `dsh web:` 行,输出带 token 的完整 Web 授权 URL。**只读**,不关闭或绕过 Web 认证;服务未运行时提示先 `dsh-rsi start`。 |
24
+ | `update` | 升级全局 dsh-rsi 自身;加 `--all` 再把插件集合交给安装器 `--operation upgrade` **原地升级**(保留 patch、凭据、Session、Goal)。 |
25
+ | `install` | 安装/修复插件集合:npm 形态下载与本 dsh-rsi 同版本的官方安装器执行,`--local <dir>` 执行 checkout 内安装器;其余参数原样透传。 |
26
+ | `reinstall` | 先 `purge`(默认先备份、同样的安全门控)再立即 `install`,用于干净重装。 |
27
+ | `purge` | 彻底卸载:进程静止检查 → 停服注销 → tar.gz 备份 → 删除 profile / DSH home / 生命周期残留 → 清理外部凭据。 |
28
+ | `version` | 打印版本。 |
29
+
30
+ 全局选项:
31
+
32
+ - `--dsh-home <path>`:指定 DSH home(默认取 `$DSH_HOME`,否则 `~/.dsh`;install 经 `DSH_HOME` 环境变量传给安装器)
33
+ - `--profile <name>`:仅操作单个 profile(`purge` 默认全量;install/reinstall 同时透传给安装器)
34
+ - `--dry-run`:只打印将执行的动作,不做任何修改(install/reinstall 透传给安装器)
35
+ - `--yes`:`purge` / `reinstall` 时跳过交互确认(install/reinstall 透传给安装器)
36
+ - `-h, --help`:无命令位置时显示 dsh-rsi 帮助;`dsh-rsi install --help` 透传展示**安装器**完整参数清单
37
+
38
+ ## install / reinstall(薄委托)
39
+
40
+ `dsh-rsi install` 不复制任何安装逻辑,只做统一入口与引导器版本固定:
41
+
42
+ - **npm 形态(默认)**:下载 `https://raw.githubusercontent.com/22-ai-00/dsh-enhanced/v<本包版本>/scripts/install/install-npm.sh` 到临时目录执行。引导脚本内部会按内嵌 SHA-256 自校验 `common.sh` 等资产,dsh-rsi 不重复 hash 逻辑。**锁定的只是引导脚本与同 tag 的安装器资产,不是插件 cohort 版本**:安装器默认把 `@dsh-enhanced/personal-assistant@latest` 解析为精确版本,再以该版本安装整套 `@dsh-enhanced/*` bundle;要锁定插件版本需透传 `--plugin-version <x.y.z|dist-tag>` 或预设 `DSH_ENHANCED_VERSION`。安装器尾部还会执行 `npm install --global @dsh-enhanced/dsh-rsi-cli@<cohort 版本>`,可能因此把全局 dsh-rsi 升降级到该 cohort 版本。
43
+ - **local 形态**:`--local <checkout 目录>`,直接执行该目录下 `scripts/install/install-local.sh`,并从该 checkout 的 packages/dsh-rsi-cli 全局安装(本地开发 / 无网救机)。
44
+ - 安装器 stdio 与终端直连(交互提示照常),退出码原样透传。
45
+
46
+ ```bash
47
+ # npm 形态安装 core 场景(其余安装器参数任意透传)
48
+ dsh-rsi install --scenario core --yes
49
+
50
+ # local checkout 形态
51
+ dsh-rsi install --local ~/work/github/dsh-enhanced --scenario web
52
+
53
+ # 查看安装器支持的全部参数
54
+ dsh-rsi install --help
55
+
56
+ # 干净重装:先备份+purge,再按相同形态重新安装
57
+ dsh-rsi reinstall --yes
58
+ dsh-rsi reinstall --profile web --yes
59
+ ```
60
+
61
+ `reinstall` 支持的 rsi 侧选项与 `purge` 一致(`--no-backup` / `--keep-keychain` / `--remove-host` / `--profile`);只有既未加 `--yes` 也未加 `--dry-run` 时才需输入 `purge` 确认——`reinstall --dry-run` 全程无交互、无修改:先打印 purge 计划,再以 `--dry-run` 透传演练安装器(`--dry-run` 同时作用于 purge 与安装两个阶段)。重装阶段默认走 npm 形态;local 重装加 `--local <dir>`。
62
+
63
+ ## update(升级自身 / 升级整套)
64
+
65
+ ```bash
66
+ # 只升级全局 dsh-rsi 自身(默认 latest)
67
+ dsh-rsi update
68
+
69
+ # 先看会装哪个版本
70
+ dsh-rsi update --dry-run
71
+
72
+ # 指定精确版本或 dist-tag
73
+ dsh-rsi update --version 0.1.38
74
+ dsh-rsi update --version next
75
+
76
+ # 自身 + 整套插件集合原地升级;受管 Linux 服务由事务停服/恢复,额外 Host 会被拒绝
77
+ dsh-rsi update --all --yes
78
+ ```
79
+
80
+ `update` 选项:
81
+
82
+ - `--all`:自身升级成功后,自动确认目标 profile 没有运行中 Host,再把插件集合交给同一目标版本的安装器原地升级。用户无需传 `--confirm-dsh-home-stopped` 或重复声明 `--scenario`;安装器从 effective/composed profile 自动识别场景。
83
+ - `--version <v|tag>`:dsh-rsi 自身的目标版本或 dist-tag(默认 `latest`)。只接受精确版本 `x.y.z`(可带预发布后缀)或纯字母 dist-tag;范围表达式如 `>=0.1.0` 会被拒绝。
84
+ - `--dry-run`:解析出目标版本并打印将执行的命令,不做任何安装。
85
+ - 其余参数在 `--all` 下原样透传给安装器;`--local <dir>` 走 local 形态。显式 `--scenario` 仍可作为一致性断言,但不再是必填项。
86
+
87
+ ### 三条语义边界
88
+
89
+ - **自身先行,失败即止**。`--all` 下先升级 dsh-rsi 自身,失败就**不**继续升级 cohort —— 避免用旧版 rsi 的判断去驱动一轮新的 cohort 升级。
90
+ - **同版本闭环**。自身升级固定写回当前 `dsh-rsi` 实际所属的 npm prefix,不受当前目录 `.npmrc` 或沙箱 prefix 影响;`--all` 使用 registry 解析出的精确版本 tag 下载安装器,无法确定精确版本时停止,绝不回退到旧进程版本。
91
+ - **已是目标版本则跳过自身安装,但继续 `--all`**。先用 `npm view` 把 selector 解析为精确版本,与自身版本相同时不重复安装 CLI;`--all` 仍继续升级 profile。registry 无法解析 dist-tag 时可单独升级 CLI,但整体升级会 fail-closed,避免 CLI 与安装器 tag 错配。
92
+
93
+ ### 与 install / reinstall 的区别
94
+
95
+ | | `update --all` | `install` | `reinstall` |
96
+ | --- | --- | --- | --- |
97
+ | 语义 | 原地升级已装的 cohort | 安装 / 修复 | **先 purge 再装** |
98
+ | 保留 patch、凭据、Session、Goal | 是 | 是 | **否**(purge 阶段删除) |
99
+ | 新增场景能力 | 否(只升当前已装的顶层依赖) | 是 | 是 |
100
+ | 升级 dsh-rsi 自身 | 是(本命令的主职责) | 顺带(安装器尾部按 cohort 版本装) | 同 install |
101
+
102
+ ## 日常运维:start / stop / restart / logs
103
+
104
+ ```bash
105
+ # 改完配置或升级插件后让 profile 生效
106
+ dsh-rsi restart --profile web
107
+
108
+ # 停掉全部 profile 的常驻服务(服务定义与数据都保留,可再 start)
109
+ dsh-rsi stop
110
+
111
+ # 先看会执行什么,再真正动手
112
+ dsh-rsi restart --dry-run
113
+
114
+ # 看日志尾部
115
+ dsh-rsi logs --profile web --lines 100
116
+ dsh-rsi logs --errors-only
117
+ ```
118
+
119
+ 不带 `--profile` 时作用于 DSH home 下的**全部真实 profile**。枚举以 `profiles/<name>/package.json` 为 profile 身份锚点;共享的 `profiles/node_modules`、缓存目录、无 manifest 的暂存目录和符号链接不会被当成 profile,也不会生成 `ai.deepseek.dsh.profile.node_modules` 之类的错误服务目标。
120
+
121
+ `logs` 选项:
122
+
123
+ - `--lines <n>`:每个日志文件显示的尾部行数(默认 200,范围 1..10000;非法值报错退出 2,不静默回落)
124
+ - `--errors-only`:只显示 `*-host.error.log`
125
+
126
+ ### 与 purge 的职责分界
127
+
128
+ 这三个运维命令和 `purge` 的停服步骤刻意分开:
129
+
130
+ | | start / stop / restart | purge |
131
+ | --- | --- | --- |
132
+ | 改变运行状态 | 是 | 是 |
133
+ | 删除 plist / unit 定义 | **否** | 是 |
134
+ | 删除 profile 数据 | **否** | 是 |
135
+ | 服务未注册时 | 报错并给出注册指引 | 视作已停止,继续删数据 |
136
+
137
+ `stop` 之后服务定义仍在,所以可以再 `start` 起来;`purge` 的停服会连定义一起注销。
138
+
139
+ ### 安全门控
140
+
141
+ - **不隐式注册服务**:服务定义文件不存在时**不会**顺手装一个(那会绕过安装器的归属、路径与凭据校验)。`core` / `web` 场景默认没有常驻服务,这是正常状态;命令会提供可直接复制的 `dsh-rsi install --profile <p> --scenario lark` / `--scenario supervised`,并以退出码 1 结束。`dsh-rsi-setup` 是插件包内的专用工具,不保证作为全局命令存在,因此不再把它作为用户修复入口。
142
+ - **归属 fail-closed**:同名文件存在但内容不属受管(人工改写或被第三方占用)时拒绝操作、原样保留文件,并说明需人工确认归属。判定依据与 purge 一致 —— Linux 要求 unit 同时含 `DeepSeek Harness profile`、对应 `--profile <p>`、`--no-open`;macOS 要求 plist 的 `Label` 为 `ai.deepseek.dsh.profile.<p>` 且 `ProgramArguments` 含 `--profile <p>` 与 `--no-open`。
143
+ - **dry-run 措辞与实际执行严格区分**:`--dry-run` 下不执行任何命令,结论行为「将启动/将停止/将重启」;只有真正执行过才输出「已…」。
144
+ - **多 profile 部分失败即非零**:任一 profile 出错,命令整体以退出码 1 结束,便于脚本判定;其余 profile 的处理结果照常打印。
145
+ - 仅支持 macOS(launchd)与 Linux(systemd --user),其它平台明确报错而非静默成功。
146
+
147
+ ## status / doctor
148
+
149
+ ```bash
150
+ dsh-rsi status
151
+ dsh-rsi --profile web status
152
+ dsh-rsi doctor
153
+ DSH_HOME=/custom/.dsh dsh-rsi doctor
154
+ ```
155
+
156
+ 两个命令都不修改任何文件,适合在升级、报障或怀疑安装损坏时先跑一遍。
157
+
158
+ ## purge(彻底卸载)
159
+
160
+ ```bash
161
+ # 先看计划(强烈建议)
162
+ dsh-rsi purge --dry-run
163
+
164
+ # 全量 purge(交互时需输入 purge 确认)
165
+ dsh-rsi purge --yes
166
+
167
+ # 只清单个 profile,保留兄弟 profile 与共享 DSH home
168
+ dsh-rsi purge --profile web --yes
169
+
170
+ # 连同全局 @deepseek-ai/dsh host 一起卸载(仅限全量)
171
+ dsh-rsi purge --yes --remove-host
172
+
173
+ # 不备份、保留外部凭据
174
+ dsh-rsi purge --yes --no-backup --keep-keychain
175
+ ```
176
+
177
+ purge 选项:
178
+
179
+ - `--no-backup`:删除前不生成 `~/dsh-purge-backup-<UTC时间戳>.tar.gz`(默认备份,权限 0600)
180
+ - `--keep-keychain`:保留 macOS Keychain / Linux Secret Service 中的受管凭据
181
+ - `--remove-host`:同时 `npm uninstall -g @deepseek-ai/dsh`(仅限全量;默认保留 host)
182
+
183
+ ### purge 会删除 / 保留什么
184
+
185
+ **删除:**
186
+
187
+ - 全量:整个 DSH home(profiles、logs、uninstalled-profiles、home 内锁文件),以及 home 外的生命周期事务目录、失败诊断目录、home 锁与 `/tmp` rendezvous 锁
188
+ - 单 profile:`profiles/<name>`、对应的两份 host 日志、归属该 profile 的失败诊断目录
189
+ - 受管常驻服务:macOS `launchctl bootout` + 删除 `~/Library/LaunchAgents/ai.deepseek.dsh.profile.<p>.plist`;Linux `systemctl --user disable --now` + `reset-failed` + 删除受管 unit 文件
190
+ - 外部凭据:按各 profile 的 setup journal / cleanup 记录**权威反查** service 前缀为 `dsh/` 的条目,逐条从 Keychain(`security delete-generic-password`)或 Secret Service(`secret-tool clear`)删除;home 内的 protected-file 凭据随 home 一起删除
191
+
192
+ **保留:**
193
+
194
+ - 本地 checkout 源码:local 形态在 `node_modules/@dsh-enhanced/` 下是指向 checkout 的符号链接,purge 只随 profile 目录删除链接本身,**绝不删除 checkout**;报告中会列出 checkout 路径,确认无用后可自行 `rm -rf`
195
+ - 全局 `@deepseek-ai/dsh` host(除非加 `--remove-host`)
196
+ - 外部凭据(加 `--keep-keychain` 时)
197
+
198
+ ### 安全门控
199
+
200
+ - **进程静止检查**:Linux 已注册受管服务的精确 systemd MainPID 会交给 installer 的 service-aware 事务停服、屏蔽、升级和恢复;其它同 profile 的手工/测试 Host 仍会拒绝执行并列出 PID,不会被自动 kill。macOS 及无受管服务场景仍要求调用前保持整个目标 Home 静止。
201
+ - **systemd unit 归属 fail-closed**:仅当 unit 文件内容同时包含受管标记(`DeepSeek Harness profile`、对应 `--profile <p>`、`--no-open`)才删除;归属不明的同名文件只报告、保留。
202
+ - **locator 先扫描、文件先删除、凭据后清理**:删文件前先扫描各 profile 的 setup journal / cleanup 记录(journal 位于 DSH home 内,必须在删除前扫出凭据 locator);随后**先删除文件**,再按预扫描的 locator 逐条删除外部凭据。单条凭据删除失败不会回滚已删文件,而是以「文件已删除,但以下凭据条目清理失败,请手工删除:…」报错并以退出码 1 结束。默认的 tar.gz 备份内含完整 journal,可解包后据此复查、手工补删;`--no-backup` 下文件与 journal 均不可恢复,只剩错误消息中列出的 service/account 可供定位。
203
+ - 单 profile 与 `--remove-host` 互斥;仅支持 macOS / Linux。
204
+
205
+ ### 与安装器 `--operation uninstall` 的区别
206
+
207
+ 安装器的 `uninstall` 是**保留数据的归档**:把旧 profile 移到 `$DSH_HOME/uninstalled-profiles/` 并重建干净基础 profile,凭据 / Session / Goal 等状态保留。`dsh-rsi purge` 是**彻底删除**:删除 DSH home 与生命周期残留(默认先打 tar.gz 备份),用于崩溃救机、报废环境或干净重装。
208
+
209
+ ## 崩溃机器上的单文件救机脚本
210
+
211
+ 机器上没有 `dsh-rsi` 时(host 已损坏或全局命令被删),可直接运行仓库中的自包含脚本;它会优先委托 `dsh-rsi`,找不到时使用等价的内联精简实现:
212
+
213
+ ```bash
214
+ curl -fsSL https://raw.githubusercontent.com/22-ai-00/dsh-enhanced/main/scripts/install/purge.sh \
215
+ | bash -s -- --yes
216
+ ```
217
+
218
+ 该脚本是 mutable-main 运维脚本(非供应链引导路径),参数与 `dsh-rsi purge` 一致。
219
+
220
+ ## 退出码
221
+
222
+ | 退出码 | 含义 |
223
+ | --- | --- |
224
+ | 0 | 成功。含 dry-run 与多数幂等场景:外部凭据条目本不存在、服务未注册、`rm --force` 删除已不存在的路径等 |
225
+ | 1 | update:selector 非法、`npm install --global` 失败(`--all` 下自身升级失败则不再委托安装器);start/stop/restart:服务未注册、归属不明被拒、或底层 `systemctl`/`launchctl` 失败(多 profile 下任一失败即 1);logs:DSH home 下没有任何 profile;purge 执行失败(活动进程、服务/凭据错误、备份失败等);install 下载/委托失败。两个非幂等边界:① 默认备份下全量 purge 不存在的 DSH home,`tar` 因源目录不存在以退出码 2 失败、rsi 退出 1(`--no-backup` 同场景为 0);② `purge --profile <不存在的名字>`(含 dry-run)直接报「profile 不存在」退出 1。单文件 `purge.sh` 的内联实现对不存在的 home 统一退出 0,在此边界上与 dsh-rsi 不一致 |
226
+ | 2 | 参数错误 |
227
+ | 其它非 0 | `install` / `reinstall` 安装器的退出码原样透传 |
228
+
229
+ ## License
230
+
231
+ MIT
package/bin/dsh-rsi.js ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ // dsh-rsi 全局命令入口:实现位于 lib/index.js(TypeScript 源码在 src/index.ts)。
3
+ import { main } from '../lib/index.js'
4
+
5
+ main().then(
6
+ code => process.exitCode = code,
7
+ error => {
8
+ process.stderr.write(`dsh-rsi 致命错误:${error?.stack ?? error}\n`)
9
+ process.exitCode = 1
10
+ },
11
+ )
@@ -0,0 +1,16 @@
1
+ import type { CommandRunner } from './run.ts';
2
+ export interface BackupResult {
3
+ archivePath: string;
4
+ /** tar 输出(成功时通常为空)。 */
5
+ detail: string;
6
+ }
7
+ /**
8
+ * 用系统 tar 把整个 DSH home 打包为 tar.gz。
9
+ * `-C <home 父目录> <home 名>` 保证归档内路径是相对的 .dsh/。
10
+ * BSD tar(macOS)与 GNU tar(Linux)均支持这些参数。
11
+ * 成功后将归档权限收紧为 0600 并校验非空。
12
+ */
13
+ export declare function createHomeBackup(dshHome: string, archivePath: string, runner: CommandRunner): BackupResult;
14
+ /** 校验归档存在、是普通文件且非空;返回字节数。 */
15
+ export declare function verifyBackup(archivePath: string): Promise<number>;
16
+ //# sourceMappingURL=backup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.d.ts","sourceRoot":"","sources":["../src/backup.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE7C,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAA;IACnB,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,aAAa,GACpB,YAAY,CAQd;AAED,6BAA6B;AAC7B,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAOvE"}
package/lib/backup.js ADDED
@@ -0,0 +1,27 @@
1
+ import { chmod, stat } from 'node:fs/promises';
2
+ import { dirname, basename } from 'node:path';
3
+ /**
4
+ * 用系统 tar 把整个 DSH home 打包为 tar.gz。
5
+ * `-C <home 父目录> <home 名>` 保证归档内路径是相对的 .dsh/。
6
+ * BSD tar(macOS)与 GNU tar(Linux)均支持这些参数。
7
+ * 成功后将归档权限收紧为 0600 并校验非空。
8
+ */
9
+ export function createHomeBackup(dshHome, archivePath, runner) {
10
+ const parent = dirname(dshHome.replace(/\/$/u, ''));
11
+ const name = basename(dshHome);
12
+ const result = runner('tar', ['-czf', archivePath, '-C', parent, name]);
13
+ if (result.status !== 0) {
14
+ throw new Error(`备份失败(tar 退出码 ${result.status ?? 'null'}):${result.stderr.trim() || result.stdout.trim()}`);
15
+ }
16
+ return { archivePath, detail: result.stderr.trim() || result.stdout.trim() };
17
+ }
18
+ /** 校验归档存在、是普通文件且非空;返回字节数。 */
19
+ export async function verifyBackup(archivePath) {
20
+ const metadata = await stat(archivePath);
21
+ if (!metadata.isFile() || metadata.size <= 0) {
22
+ throw new Error(`备份归档校验失败(不存在或为空):${archivePath}`);
23
+ }
24
+ await chmod(archivePath, 0o600);
25
+ return metadata.size;
26
+ }
27
+ //# sourceMappingURL=backup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup.js","sourceRoot":"","sources":["../src/backup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAS7C;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAe,EACf,WAAmB,EACnB,MAAqB;IAErB,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAA;IACnD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAA;IAC9B,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;IACvE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,gBAAgB,MAAM,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IAC7G,CAAC;IACD,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAA;AAC9E,CAAC;AAED,6BAA6B;AAC7B,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,WAAmB;IACpD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,CAAA;IACxC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,QAAQ,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,oBAAoB,WAAW,EAAE,CAAC,CAAA;IACpD,CAAC;IACD,MAAM,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAA;IAC/B,OAAO,QAAQ,CAAC,IAAI,CAAA;AACtB,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { type CommandRunner } from './run.ts';
2
+ export interface ProfileStatus {
3
+ name: string;
4
+ npmPlugins: string[];
5
+ localPlugins: {
6
+ name: string;
7
+ target: string;
8
+ }[];
9
+ serviceInstalled: boolean;
10
+ serviceActive: boolean;
11
+ }
12
+ export interface StatusSnapshot {
13
+ dshHome: string;
14
+ homeExists: boolean;
15
+ hostVersion?: string;
16
+ hostError?: string;
17
+ profiles: ProfileStatus[];
18
+ credentialCount: number;
19
+ residuals: string[];
20
+ }
21
+ /** 只读状态:安装形态、host 版本、服务注册、凭据条目数、生命周期残留。 */
22
+ export declare function collectStatus(dshHome: string, home: string, platform: NodeJS.Platform, runner?: CommandRunner): Promise<StatusSnapshot>;
23
+ export declare function formatStatus(snapshot: StatusSnapshot): string;
24
+ export interface DoctorFinding {
25
+ profile: string;
26
+ logPath: string;
27
+ pattern: string;
28
+ advice: string;
29
+ }
30
+ /** 扫描各 profile 最近的 *-host.error.log 尾部,匹配已知崩溃模式。 */
31
+ export declare function runDoctor(dshHome: string): Promise<DoctorFinding[]>;
32
+ export declare function formatFindings(findings: readonly DoctorFinding[]): string;
33
+ //# sourceMappingURL=diagnose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnose.d.ts","sourceRoot":"","sources":["../src/diagnose.ts"],"names":[],"mappings":"AAaA,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,UAAU,CAAA;AAE5D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,YAAY,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAChD,gBAAgB,EAAE,OAAO,CAAA;IACzB,aAAa,EAAE,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,OAAO,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,aAAa,EAAE,CAAA;IACzB,eAAe,EAAE,MAAM,CAAA;IACvB,SAAS,EAAE,MAAM,EAAE,CAAA;CACpB;AAqBD,2CAA2C;AAC3C,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,CAAC,QAAQ,EACzB,MAAM,GAAE,aAA6B,GACpC,OAAO,CAAC,cAAc,CAAC,CAqCzB;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,cAAc,GAAG,MAAM,CAqB7D;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;CACf;AAcD,oDAAoD;AACpD,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAqCzE;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,GAAG,MAAM,CAIzE"}
@@ -0,0 +1,145 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { open, readdir, stat } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { launchAgentTargets, listLifecycleResiduals, listProfiles, listProfilePlugins, logsDirectory, systemdUnitName, systemdUserDirectory, } from "./paths.js";
5
+ import { scanCredentialLocators } from "./secrets.js";
6
+ import { defaultRunner } from "./run.js";
7
+ async function serviceState(platform, home, profile, runner) {
8
+ if (platform === 'darwin') {
9
+ const { label, plistPath } = launchAgentTargets(home, profile);
10
+ const installed = existsSync(plistPath);
11
+ const shown = runner('launchctl', ['print', `gui/${process.getuid?.() ?? process.env.UID}/${label}`]);
12
+ return { installed, active: installed && shown.status === 0 };
13
+ }
14
+ const unit = systemdUnitName(profile);
15
+ const installed = existsSync(join(systemdUserDirectory(home), unit));
16
+ const shown = runner('systemctl', ['--user', 'is-active', unit]);
17
+ // is-active 对 inactive 输出 inactive 并退出码 3。
18
+ return { installed, active: shown.stdout.trim() === 'active' };
19
+ }
20
+ /** 只读状态:安装形态、host 版本、服务注册、凭据条目数、生命周期残留。 */
21
+ export async function collectStatus(dshHome, home, platform, runner = defaultRunner) {
22
+ const homeExists = existsSync(dshHome);
23
+ const profiles = await listProfiles(dshHome);
24
+ const profileStatus = [];
25
+ for (const name of profiles) {
26
+ const plugins = await listProfilePlugins(dshHome, name);
27
+ const service = await serviceState(platform, home, name, runner);
28
+ profileStatus.push({
29
+ name,
30
+ npmPlugins: plugins.filter(plugin => plugin.kind === 'npm').map(plugin => plugin.name),
31
+ localPlugins: plugins
32
+ .filter(plugin => plugin.kind === 'local')
33
+ .map(plugin => ({ name: plugin.name, target: plugin.linkTarget ?? '' })),
34
+ serviceInstalled: service.installed,
35
+ serviceActive: service.active,
36
+ });
37
+ }
38
+ const host = runner('dsh', ['--version']);
39
+ const credentials = await scanCredentialLocators(dshHome).catch(() => []);
40
+ const parent = dshHome.slice(0, dshHome.lastIndexOf('/')) || '/';
41
+ const [parentEntries, tmpEntries] = await Promise.all([
42
+ readdir(parent).catch(() => []),
43
+ readdir('/tmp').catch(() => []),
44
+ ]);
45
+ const residuals = homeExists
46
+ ? await listLifecycleResiduals(dshHome, parentEntries, tmpEntries)
47
+ : [];
48
+ return {
49
+ dshHome,
50
+ homeExists,
51
+ ...(host.status === 0
52
+ ? { hostVersion: host.stdout.trim() }
53
+ : { hostError: host.stderr.trim() || host.stdout.trim() || '未找到全局 dsh 命令' }),
54
+ profiles: profileStatus,
55
+ credentialCount: credentials.length,
56
+ residuals,
57
+ };
58
+ }
59
+ export function formatStatus(snapshot) {
60
+ const lines = [];
61
+ lines.push(`DSH home:${snapshot.dshHome}(${snapshot.homeExists ? '存在' : '不存在'})`);
62
+ lines.push(`全局 host:${snapshot.hostVersion ? `dsh ${snapshot.hostVersion}` : snapshot.hostError ?? '未知'}`);
63
+ lines.push(`外部凭据条目:${snapshot.credentialCount}`);
64
+ if (snapshot.profiles.length === 0) {
65
+ lines.push('profiles:(无)');
66
+ }
67
+ else {
68
+ lines.push('profiles:');
69
+ for (const profile of snapshot.profiles) {
70
+ const service = profile.serviceActive ? '运行中' : profile.serviceInstalled ? '已安装/未运行' : '无受管服务';
71
+ lines.push(` - ${profile.name}(服务:${service})`);
72
+ for (const plugin of profile.npmPlugins)
73
+ lines.push(` npm ${plugin}`);
74
+ for (const plugin of profile.localPlugins)
75
+ lines.push(` local ${plugin.name} -> ${plugin.target}`);
76
+ }
77
+ }
78
+ if (snapshot.residuals.length > 0) {
79
+ lines.push('生命周期残留:');
80
+ for (const residual of snapshot.residuals)
81
+ lines.push(` ! ${residual}`);
82
+ }
83
+ return lines.join('\n');
84
+ }
85
+ /**
86
+ * 已知崩溃模式与处置建议。
87
+ * 旧版 assistant-policy(≤0.1.31)在 JSONL 持久化后端上 fail-closed 拒绝注册。
88
+ */
89
+ const KNOWN_LOG_PATTERNS = [
90
+ {
91
+ pattern: /event-support oracle|refusing unproven registration|does not expose the supported PersistenceCoordinator/iu,
92
+ label: '旧版 assistant-policy event-support oracle 不兼容(≤0.1.31 与全局 JSONL host 契约错配)',
93
+ advice: '升级插件集合到 ≥0.1.32(npm:重跑 install-npm.sh --operation upgrade;local:checkout 切到最新 release tag 后 pnpm install --frozen-lockfile && pnpm build),再重启 profile。',
94
+ },
95
+ ];
96
+ /** 扫描各 profile 最近的 *-host.error.log 尾部,匹配已知崩溃模式。 */
97
+ export async function runDoctor(dshHome) {
98
+ const findings = [];
99
+ const logDirectory = logsDirectory(dshHome);
100
+ let entries;
101
+ try {
102
+ entries = await readdir(logDirectory);
103
+ }
104
+ catch {
105
+ return findings;
106
+ }
107
+ for (const entry of entries) {
108
+ if (!entry.endsWith('-host.error.log'))
109
+ continue;
110
+ const profile = entry.slice(0, -'-host.error.log'.length);
111
+ const path = join(logDirectory, entry);
112
+ let metadata;
113
+ try {
114
+ metadata = await stat(path);
115
+ }
116
+ catch {
117
+ continue;
118
+ }
119
+ if (!metadata.isFile() || metadata.size === 0)
120
+ continue;
121
+ // 只读尾部 256 KiB,覆盖最近一次启动的崩溃栈。
122
+ const length = Math.min(metadata.size, 256 * 1024);
123
+ const buffer = Buffer.alloc(length);
124
+ const file = await open(path, 'r');
125
+ try {
126
+ await file.read(buffer, 0, length, metadata.size - length);
127
+ }
128
+ finally {
129
+ await file.close();
130
+ }
131
+ const tail = buffer.toString('utf8');
132
+ for (const known of KNOWN_LOG_PATTERNS) {
133
+ if (known.pattern.test(tail)) {
134
+ findings.push({ profile, logPath: path, pattern: known.label, advice: known.advice });
135
+ }
136
+ }
137
+ }
138
+ return findings;
139
+ }
140
+ export function formatFindings(findings) {
141
+ if (findings.length === 0)
142
+ return 'doctor:未发现已知崩溃模式。';
143
+ return findings.map(finding => `doctor:[${finding.profile}] ${finding.pattern}\n 日志:${finding.logPath}\n 建议:${finding.advice}`).join('\n');
144
+ }
145
+ //# sourceMappingURL=diagnose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnose.js","sourceRoot":"","sources":["../src/diagnose.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,46 @@
1
+ import { runPurge } from './purge.ts';
2
+ import { runInstall } from './install.ts';
3
+ import { findRunningProfiles } from './run.ts';
4
+ import { runSelfUpdate } from './update.ts';
5
+ import { managedServiceProcessIds } from './services.ts';
6
+ export { runPurge, PurgeError } from './purge.ts';
7
+ export { runInstall } from './install.ts';
8
+ export { collectStatus, runDoctor, formatStatus, formatFindings } from './diagnose.ts';
9
+ export { formatSelfUpdateReport, runSelfUpdate, RSI_CLI_PACKAGE } from './update.ts';
10
+ export { collectLogs, controlManagedService, formatLogs, formatServiceOutcomes, inspectManagedService, managedServiceProcessIds, resolveTargetProfiles, tailLogFile, } from './services.ts';
11
+ export { extractWebUrlFromText, formatWebUrlResult, resolveManagedWebUrl } from './weburl.ts';
12
+ export { resolveDshHome } from './paths.ts';
13
+ export { version } from './version.ts';
14
+ interface ParsedArgs {
15
+ command: string;
16
+ dshHome: string;
17
+ profile?: string;
18
+ dryRun: boolean;
19
+ yes: boolean;
20
+ backup: boolean;
21
+ keepKeychain: boolean;
22
+ removeHost: boolean;
23
+ help: boolean;
24
+ local?: string;
25
+ /** logs:每个文件显示的尾部行数。 */
26
+ lines: number;
27
+ /** logs:只显示 *-host.error.log。 */
28
+ errorsOnly: boolean;
29
+ /** update:同时升级插件集合(自动检查静止状态并继承现有场景)。 */
30
+ all: boolean;
31
+ /** update:dsh-rsi 自身的目标版本或 dist-tag。 */
32
+ targetVersion?: string;
33
+ /** install/reinstall:原样透传给安装器的参数。 */
34
+ passthrough: string[];
35
+ }
36
+ export declare function parseArgs(argv: readonly string[], env?: NodeJS.ProcessEnv): ParsedArgs;
37
+ /** main 的依赖面,仅供测试注入(默认执行真实 purge/install/self-update)。 */
38
+ export interface MainDeps {
39
+ purge?: typeof runPurge;
40
+ install?: typeof runInstall;
41
+ selfUpdate?: typeof runSelfUpdate;
42
+ findRunning?: typeof findRunningProfiles;
43
+ managedServicePids?: typeof managedServiceProcessIds;
44
+ }
45
+ export declare function main(argv?: readonly string[], env?: NodeJS.ProcessEnv, deps?: MainDeps): Promise<number>;
46
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAgC,MAAM,YAAY,CAAA;AAGnE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAC9C,OAAO,EAA0B,aAAa,EAAE,MAAM,aAAa,CAAA;AAEnE,OAAO,EAKL,wBAAwB,EAIzB,MAAM,eAAe,CAAA;AAGtB,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACtF,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AACpF,OAAO,EACL,WAAW,EACX,qBAAqB,EACrB,UAAU,EACV,qBAAqB,EACrB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,WAAW,GACZ,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAC7F,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAgFtC,UAAU,UAAU;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,OAAO,CAAA;IACf,GAAG,EAAE,OAAO,CAAA;IACZ,MAAM,EAAE,OAAO,CAAA;IACf,YAAY,EAAE,OAAO,CAAA;IACrB,UAAU,EAAE,OAAO,CAAA;IACnB,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,iCAAiC;IACjC,UAAU,EAAE,OAAO,CAAA;IACnB,wCAAwC;IACxC,GAAG,EAAE,OAAO,CAAA;IACZ,wCAAwC;IACxC,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,qCAAqC;IACrC,WAAW,EAAE,MAAM,EAAE,CAAA;CACtB;AA+BD,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,UAAU,CAwFnG;AAsJD,0DAA0D;AAC1D,MAAM,WAAW,QAAQ;IACvB,KAAK,CAAC,EAAE,OAAO,QAAQ,CAAA;IACvB,OAAO,CAAC,EAAE,OAAO,UAAU,CAAA;IAC3B,UAAU,CAAC,EAAE,OAAO,aAAa,CAAA;IACjC,WAAW,CAAC,EAAE,OAAO,mBAAmB,CAAA;IACxC,kBAAkB,CAAC,EAAE,OAAO,wBAAwB,CAAA;CACrD;AAED,wBAAsB,IAAI,CACxB,IAAI,GAAE,SAAS,MAAM,EAA0B,EAC/C,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,IAAI,GAAE,QAAa,GAClB,OAAO,CAAC,MAAM,CAAC,CAwLjB"}