dsh-plugin-manager-companion 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +144 -0
  3. package/README.md +142 -0
  4. package/cordis.patch.yml +9 -0
  5. package/dist/about.d.ts +77 -0
  6. package/dist/about.js +179 -0
  7. package/dist/cli.d.ts +226 -0
  8. package/dist/cli.js +856 -0
  9. package/dist/client/AboutPage.d.ts +75 -0
  10. package/dist/client/ConsolePage.d.ts +79 -0
  11. package/dist/client/KindsPage.d.ts +21 -0
  12. package/dist/client/MarketplacePage.d.ts +36 -0
  13. package/dist/client/OfficialSlots.d.ts +35 -0
  14. package/dist/client/UpgradeRow.d.ts +108 -0
  15. package/dist/client/index.d.ts +26 -0
  16. package/dist/client/locales.d.ts +475 -0
  17. package/dist/client/pmSelect.d.ts +38 -0
  18. package/dist/client/shared.d.ts +928 -0
  19. package/dist/client/upgradeView.d.ts +278 -0
  20. package/dist/client/wire.d.ts +401 -0
  21. package/dist/client.js +9194 -0
  22. package/dist/diagnostics.d.ts +332 -0
  23. package/dist/diagnostics.js +2631 -0
  24. package/dist/envManager.d.ts +1047 -0
  25. package/dist/envManager.js +3214 -0
  26. package/dist/fix.d.ts +60 -0
  27. package/dist/fix.js +168 -0
  28. package/dist/guard.d.ts +133 -0
  29. package/dist/guard.js +232 -0
  30. package/dist/index.d.ts +121 -0
  31. package/dist/index.js +1150 -0
  32. package/dist/installSession.d.ts +111 -0
  33. package/dist/installSession.js +150 -0
  34. package/dist/kinds.d.ts +464 -0
  35. package/dist/kinds.js +1029 -0
  36. package/dist/marketView.d.ts +261 -0
  37. package/dist/marketView.js +406 -0
  38. package/dist/marketplace.d.ts +248 -0
  39. package/dist/marketplace.js +500 -0
  40. package/dist/match.d.ts +67 -0
  41. package/dist/match.js +203 -0
  42. package/dist/net.d.ts +108 -0
  43. package/dist/net.js +163 -0
  44. package/dist/official.d.ts +145 -0
  45. package/dist/official.js +205 -0
  46. package/dist/paths.d.ts +108 -0
  47. package/dist/paths.js +236 -0
  48. package/dist/presets.d.ts +299 -0
  49. package/dist/presets.js +578 -0
  50. package/dist/qualityGate.d.ts +66 -0
  51. package/dist/qualityGate.js +247 -0
  52. package/dist/rank.d.ts +88 -0
  53. package/dist/rank.js +164 -0
  54. package/dist/registry.d.ts +295 -0
  55. package/dist/registry.js +686 -0
  56. package/dist/rest.d.ts +122 -0
  57. package/dist/rest.js +219 -0
  58. package/dist/scan.d.ts +134 -0
  59. package/dist/scan.js +396 -0
  60. package/dist/settings.d.ts +447 -0
  61. package/dist/settings.js +263 -0
  62. package/dist/tags.d.ts +119 -0
  63. package/dist/tags.js +166 -0
  64. package/dist/tools.d.ts +131 -0
  65. package/dist/tools.js +377 -0
  66. package/dist/types.d.ts +651 -0
  67. package/dist/types.js +13 -0
  68. package/dist/upgrade.d.ts +428 -0
  69. package/dist/upgrade.js +1100 -0
  70. package/dist/upgradeView.d.ts +313 -0
  71. package/dist/upgradeView.js +273 -0
  72. package/docs/images/readme/01-console-health.png +0 -0
  73. package/docs/images/readme/02-console-envs.png +0 -0
  74. package/docs/images/readme/03-marketplace.png +0 -0
  75. package/docs/images/readme/04-official-plugin-page.png +0 -0
  76. package/package.json +104 -0
@@ -0,0 +1,651 @@
1
+ /**
2
+ * dsh-plugin-manager-companion — host/client 的 wire 契约。
3
+ *
4
+ * 归属:A 类·重写(旧 src/types.ts 仅作字段意图参考,未复制代码)。
5
+ * 官方复用:官方 pluginManager/types 的类型直接 re-export,不重复定义。
6
+ * 前提检查:旧类型里有大量为自建 REST + 自建 patch 写入设计的形状
7
+ * (MutationResult/CommandResult/UpdateInfo 等),前提已消失——
8
+ * 当前 profile 的写操作全部走官方 Remote,本文件只描述官方不覆盖的部分:
9
+ * 跨环境管理、深度诊断、市场、技能与预设。
10
+ *
11
+ * 全部类型必须 JSON-safe(跨 wire 传输)。
12
+ */
13
+ import type { BootVerdict, SnapshotDepth, TrialConclusion } from './envManager.ts';
14
+ export type { BundleInfo, BundleRowInfo, ChangeResult, ManagementError, PluginEntryId, PluginInfo, PluginInstallFailureKind, PluginInstallLogChunk, PluginInstallProgress, PluginInstallRequestId, PluginSpecInspection, ReadOnlyReason, } from '@deepseek-ai/dsh-plugin-manager/types';
15
+ export type { PluginFiberPhase, PluginInventoryEntry, PluginInventorySnapshot, } from '@deepseek-ai/dsh-host-plugin-inventory/types';
16
+ /**
17
+ * 我们**从 manifest 派生**、且可能读不出来的字段名(闭集)。
18
+ *
19
+ * 为什么是联合类型而不是 string[]:裸字符串数组只能靠约定,谁报一个新名字都不会在
20
+ * review 里被注意到。闭集让"新增一种读不懂的字段"变成一次**看得见的契约变更**——
21
+ * 要同时改这里、读取器、以及客户端是否渲染;客户端写 includes('bundles') 也能被类型检查。
22
+ */
23
+ export type ManifestField = 'bundles' | 'dependencies';
24
+ /** 一个 profile 目录的只读事实。 */
25
+ export interface EnvironmentInfo {
26
+ /** profile 目录名,即 profile 名。 */
27
+ readonly name: string;
28
+ /** 绝对路径。 */
29
+ readonly dir: string;
30
+ /** 是否为本进程正在运行的环境。 */
31
+ readonly current: boolean;
32
+ /** 官方内置环境(web/headless 等),只读不可删。 */
33
+ readonly builtin: boolean;
34
+ /** `dsh.profile.bundles` 的层栈;读不懂时为空数组,**必须**配合 unknownFields / bundlesKnown 判断。 */
35
+ readonly bundles: readonly string[];
36
+ /**
37
+ * 这份 manifest 里我们**读不出来**的派生字段(缺省 = 全部读得出来)。
38
+ *
39
+ * 为什么按字段列:官方改字段名/类型时,受影响的往往只是其中一个字段;
40
+ * 一个笼统的"manifest 读不懂"会让调用方不知道该少说哪句话。
41
+ */
42
+ readonly unknownFields?: readonly ManifestField[];
43
+ /** 读不出来的原因(面向用户);全部读得出来时为 undefined。 */
44
+ readonly unknownReason?: string;
45
+ /** 直接依赖名列表;读不懂时为空数组,**必须**配合 unknownFields 判断。 */
46
+ readonly dependencies: readonly string[];
47
+ /**
48
+ * 层栈是不是确定的事实(等价于 unknownFields 里含 'bundles')。
49
+ *
50
+ * 单独留一个派生谓词,是因为层栈是**界面上唯一直接渲染的派生字段**:显示
51
+ * `0 个组合包` 就是把"我不知道"说成"这个环境没有层栈"。其余字段判断未知请读 unknownFields。
52
+ */
53
+ readonly bundlesKnown?: boolean;
54
+ /** 进程表扫描到的运行实例;**空数组 + runsKnown !== false 才表示未运行**。 */
55
+ readonly runs: readonly EnvironmentRun[];
56
+ /**
57
+ * 运行实例是不是**确定**的事实(缺省等价 true)。
58
+ *
59
+ * 与 unknownFields / bundlesKnown **不是一个来源**:那两个来自环境自己的 package.json
60
+ * (同一份 manifest),本字段来自**进程表读取**(/proc、ps 或 powershell CIM)—— 另一个源、
61
+ * 另一种失败方式。所以这一对单独存在是刻意的,**不要**并进 ManifestField:合并会让
62
+ * 「manifest 读不懂」与「进程事实读不到」共用一种表达,调用方就分不清该少说哪句话。
63
+ *
64
+ * `runs: []` 且 runsKnown === false 时**不代表「未运行」**,而是「我不知道」。
65
+ */
66
+ readonly runsKnown?: boolean;
67
+ /** 进程事实读不到的原因(面向用户);可读时为 undefined。 */
68
+ readonly runsUnknownReason?: string;
69
+ }
70
+ /** 一个运行中的环境实例。 */
71
+ export interface EnvironmentRun {
72
+ readonly pid: number;
73
+ /** 监听端口;未知时为 null。 */
74
+ readonly port: number | null;
75
+ /** 启动命令行,用于展示与诊断。 */
76
+ readonly command: string;
77
+ }
78
+ /**
79
+ * 诊断层级。每层有独立数据源,越靠上越可靠(静态可证),越靠下越贴近现实
80
+ * (运行时事实)。
81
+ */
82
+ export type DiagnosticLayer =
83
+ /** L1 依赖:package.json 声明与 import 图的对照。 */
84
+ 'dependency'
85
+ /** L2 组合:patch 层栈与行 id 的组合正确性。 */
86
+ | 'composition'
87
+ /** L3 运行时:loader fiber 相位与注册表冲突。 */
88
+ | 'runtime'
89
+ /** L4 一致性:官方 inventory 与本地产物的对照。 */
90
+ | 'consistency'
91
+ /** L5 生态:市场索引的更新与风险信息。 */
92
+ | 'ecosystem';
93
+ /**
94
+ * 处置等级。决定 UI 给什么按钮,以及能否自动执行。
95
+ * - `safe-fix`:可安全自动修复,有明确唯一解
96
+ * - `confirm-fix`:需用户确认,存在多种取舍
97
+ * - `report-only`:只报告,不提供自动修复
98
+ */
99
+ export type DiagnosticSeverity = 'safe-fix' | 'confirm-fix' | 'report-only';
100
+ /** 一个可执行的修复动作。 */
101
+ export interface DiagnosticFix {
102
+ /** 稳定动作标识,host 端据此分派。 */
103
+ readonly action: string;
104
+ /** 动作参数(JSON-safe)。 */
105
+ readonly target?: string;
106
+ /** 面向用户的一句话说明。 */
107
+ readonly summary: string;
108
+ }
109
+ /**
110
+ * 一条诊断发现。
111
+ *
112
+ * 设计原则:证据可溯——`evidence` 必须能指回具体文件/行/运行时对象,
113
+ * 让用户能自己核实,而不是接受黑盒判断。
114
+ */
115
+ export interface DiagnosticIssue {
116
+ /** 稳定 id(同一次分析内唯一),用于 UI 折叠与修复定位。 */
117
+ readonly id: string;
118
+ readonly layer: DiagnosticLayer;
119
+ readonly severity: DiagnosticSeverity;
120
+ /** 机器可读的问题类别,如 `missing-import` / `duplicate-row-id`。 */
121
+ readonly code: string;
122
+ /** 一句话标题。 */
123
+ readonly title: string;
124
+ /** 详细说明(含影响与建议)。 */
125
+ readonly detail: string;
126
+ /** 涉及的对象:包名、行 id、服务名等。 */
127
+ readonly subjects: readonly string[];
128
+ /** 证据链,每条都可指回源。 */
129
+ readonly evidence: readonly DiagnosticEvidence[];
130
+ /** 可执行的修复;`report-only` 时为 undefined。 */
131
+ readonly fix?: DiagnosticFix;
132
+ /** 归属包名;无法归属时为空串。 */
133
+ readonly scope?: string;
134
+ }
135
+ /**
136
+ * 一条发现的作用域:它归属哪个包。
137
+ *
138
+ * 用于把同一 code 的大量命中聚合成可折叠的组——干净环境不该出现,但真出问题时
139
+ * 163 条同类命中必须能被读懂。缺省为空串(无法归属时)。
140
+ * @deprecated 用 DiagnosticIssue.scope(每条发现自带)。
141
+ */
142
+ /** 一条证据:指回文件行或运行时对象。 */
143
+ export interface DiagnosticEvidence {
144
+ readonly kind: 'file' | 'runtime' | 'official';
145
+ /** 人类可读的位置描述,如 `package.json:12` 或 `loader entry "foo"`。 */
146
+ readonly at: string;
147
+ /** 说明这条证据证明了什么。 */
148
+ readonly note: string;
149
+ }
150
+ /**
151
+ * 一组同类发现的聚合视图。
152
+ *
153
+ * 设计意图:逐条 `issues` **一条不少**(证据与行号都留着),`groups` 只提供
154
+ * 可折叠的计数与来源说明——折了信息但不丢信息。界面默认展开组、按需下钻到条目。
155
+ */
156
+ export interface DiagnosticGroup {
157
+ /** 稳定组键:层级 + 类别 + 严重级别 + 作用域。 */
158
+ readonly key: string;
159
+ readonly layer: DiagnosticLayer;
160
+ readonly code: string;
161
+ readonly severity: DiagnosticSeverity;
162
+ /** 该组的命中条数。 */
163
+ readonly count: number;
164
+ /** 组内命中的包及各自条数(判定不出归属的发现不计入)。 */
165
+ readonly scopes: readonly DiagnosticScopeCount[];
166
+ /** 组内涉及的对象(去重、有上限)。 */
167
+ readonly subjects: readonly string[];
168
+ /** 组内第一条的标题,供折叠态展示。 */
169
+ readonly exampleTitle?: string;
170
+ }
171
+ /** 一个作用域在某一组里的命中条数。 */
172
+ export interface DiagnosticScopeCount {
173
+ readonly scope: string;
174
+ readonly count: number;
175
+ }
176
+ /** 一次完整诊断的结果。 */
177
+ export interface DiagnosticReport {
178
+ /** 被诊断的环境名。 */
179
+ readonly environment: string;
180
+ /** 生成时间(ISO 8601)。 */
181
+ readonly generatedAt: string;
182
+ /** 各层的问题数,便于 UI 直接渲染总览。 */
183
+ readonly counts: Readonly<Record<DiagnosticLayer, number>>;
184
+ readonly issues: readonly DiagnosticIssue[];
185
+ /**
186
+ * 同类发现的聚合组(层级+类别+严重级别+作用域)。
187
+ *
188
+ * 各组 `count` 之和恒等于 `issues.length`——折了信息但不丢信息。
189
+ */
190
+ readonly groups?: readonly DiagnosticGroup[];
191
+ /** 诊断过程中跳过的检查及原因(能力缺失时如实告知,不假装健康)。 */
192
+ readonly skipped: readonly DiagnosticSkip[];
193
+ }
194
+ /** 一项因能力缺失而跳过的检查。 */
195
+ export interface DiagnosticSkip {
196
+ readonly check: string;
197
+ readonly reason: string;
198
+ /**
199
+ * 这次跳过让**哪些层**根本没查成(空/缺省 = 不是层级跳过)。
200
+ *
201
+ * 存在的理由:UI 要如实区分「这一层查过且没问题」与「这一层根本没查」,而后者绝不能画成 0
202
+ * (把没查画成没问题)。层归属是引擎的事实,不能靠客户端去猜 check 字符串的形状——那是约定
203
+ * 耦合,改名就会静默退化成"显示 0"。
204
+ *
205
+ * 用数组而不是单值:有些能力缺失会同时废掉多层(Loader 不可用 → runtime 与 consistency 都没跑;
206
+ * 环境目录不存在 → 五层都没有输入)。单值会漏标另一层,而漏标出来的正是"查过且没问题"。
207
+ *
208
+ * 非层级检查(install-anchor / dependency-scan / composition-official / ecosystem-index 等)
209
+ * **不设**本字段:它们只说明某一层的结论不完整,不代表整层没查。
210
+ */
211
+ readonly layers?: readonly DiagnosticLayer[];
212
+ }
213
+ /** 跨环境操作的统一结果。 */
214
+ export interface EnvironmentResult {
215
+ readonly ok: boolean;
216
+ /** 面向用户的输出(含命令回显与诊断)。 */
217
+ readonly output: string;
218
+ /** 失败时的稳定错误码。 */
219
+ readonly code?: string;
220
+ }
221
+ /**
222
+ * 市场条目的安装来源类型。
223
+ *
224
+ * 用 `cordis-plugin` 而非 `plugin`:这是官方与生态的一致术语(官方预设就叫 cordis,
225
+ * 检测出的仓库类型是"一个 cordis 插件")。词汇必须全局统一,否则 registry 的
226
+ * 安装路径分派与 kinds 的检测结果会对不上。
227
+ */
228
+ export type MarketItemKind = 'cordis-plugin' | 'skill' | 'agent-preset' | 'unknown';
229
+ /**
230
+ * 上游的可装性标记(索引 installable 字段,原样透传)。
231
+ *
232
+ * - `manual`:上游判定它不能走一键安装(724/13,998 条,其中 646 条确实没有 npm 包名)
233
+ * - `non-plugin`:上游判定它**不是插件**(1,018 条,样本里有 96,949★ 的蹭话题仓库)
234
+ *
235
+ * 只呈现上游结论:我们既不猜原因,也不在 host 侧过滤(过滤是展示决策,见 marketView.filterInstallable)。
236
+ */
237
+ export type MarketInstallable = 'manual' | 'non-plugin';
238
+ /**
239
+ * 上游静态扫描的风险等级(索引 risk_tier 字段)。
240
+ * 覆盖全部条目:safe 13,794 / caution 133 / risk 71。我们只展示,不折算、不重新分级。
241
+ */
242
+ export type MarketRiskTier = 'safe' | 'caution' | 'risk';
243
+ /** 一条上游风险明细(索引 risk_flags 的元素):原样展示 id + severity + 类别,不翻译成我们的结论。 */
244
+ export interface MarketRiskFlag {
245
+ readonly id: string;
246
+ readonly severity: string;
247
+ readonly category: string;
248
+ }
249
+ /** 一条市场条目(host 聚合后交给 client 渲染)。 */
250
+ export interface MarketItem {
251
+ /** owner/repo。 */
252
+ readonly repo: string;
253
+ readonly name: string;
254
+ readonly description: string;
255
+ /** 星数;未知时 null。 */
256
+ readonly stars: number | null;
257
+ /** 最后更新时间(ISO 8601);未知时 null。 */
258
+ readonly updatedAt: string | null;
259
+ readonly topics: readonly string[];
260
+ /** 上游分类 id。 */
261
+ readonly category?: string;
262
+ /** 是否已在本环境安装。 */
263
+ readonly installed?: boolean;
264
+ /** 已安装时的版本。 */
265
+ readonly installedVersion?: string;
266
+ /** 检测到可更新时的新版本。 */
267
+ readonly latestVersion?: string;
268
+ /** 安装来源形态,供 UI 选择安装路径。 */
269
+ readonly kind?: MarketItemKind;
270
+ /** 索引采集到的 npm 包名(pkg_name / npm_pkg_name);没有时缺省。 */
271
+ readonly packageName?: string;
272
+ /**
273
+ * 安装 spec:**host 侧决定**,客户端只负责原样送给 install op。
274
+ *
275
+ * 为什么不让客户端拼:spec 的合法形态由官方的 parseInstallSpec 定义(registry 名 / 绝对路径 /
276
+ * git URL / tarball),客户端自己拼就是把这套规则复制一份——一处改动要改两处,而且必然漂移。
277
+ * host 用 marketplace.installSpecFor() 决定(npm 包名优先,否则 github: 前缀的仓库地址),
278
+ * 索引字段变了只改那一个函数。契约上可选:老载荷没有这个字段时客户端不会瞎猜(见 shared.ts)。
279
+ */
280
+ readonly installSpec?: string;
281
+ /**
282
+ * 上游可装性标记(installable)。缺省 = 上游没有标记(12,256 条),不代表"可一键安装"。
283
+ */
284
+ readonly installable?: MarketInstallable;
285
+ /**
286
+ * 上游风险等级(risk_tier)。可选:老载荷没有这个字段时**不显示风险徽标**,
287
+ * 而不是默认成 safe——"没扫过"与"扫过是安全"是两回事。
288
+ */
289
+ readonly riskTier?: MarketRiskTier;
290
+ /** 上游风险明细(risk_flags),仅详情展示(卡片只放结论 riskTier)。 */
291
+ readonly riskFlags?: readonly MarketRiskFlag[];
292
+ /** 上游独立验证报告外链(reportUrl);与 verdict/verifiedBy/verifiedAt 同属一个证据簇。 */
293
+ readonly reportUrl?: string;
294
+ /** 上游收录标记(market_tags):community-pick 是编辑推荐,verified-install 是另一套收录标记。 */
295
+ readonly marketTags?: readonly string[];
296
+ /** 仓库是否已归档(archived)。 */
297
+ readonly archived?: boolean;
298
+ /** 近 7 天 star 增量(stars_delta_7d);只用于"热度"排序,不做徽标(60% 为 0)。 */
299
+ readonly starsDelta7d?: number;
300
+ /** 仓库许可证(SPDX id;88% 有值、其中 78.8% 是 MIT)——按政策进详情,不做徽标。 */
301
+ readonly license?: string;
302
+ /**
303
+ * 独立校验证据:verdict=pass 时上游给出"谁在何时验的"。
304
+ *
305
+ * 必须与 verified-install 收录标记**分开呈现**:两者交集只有 2 条(政策 §2.2),
306
+ * 合并成一个"已验证"会让同一插件在两个徽标上自相矛盾。
307
+ */
308
+ readonly verifiedBy?: string;
309
+ /** 独立校验时间(ISO 日期)。 */
310
+ readonly verifiedAt?: string;
311
+ }
312
+ /** 市场查询结果。 */
313
+ export interface MarketplaceResult {
314
+ readonly items: readonly MarketItem[];
315
+ /** 索引生成时间;索引不可用且无缓存时为空串(UI 显示"未知"而不是伪造一个时间)。 */
316
+ readonly generatedAt: string;
317
+ /** 本次结果是否来自缓存。 */
318
+ readonly cached: boolean;
319
+ /** 上游分类计数,供筛选器渲染。 */
320
+ readonly categories: Readonly<Record<string, number>>;
321
+ /**
322
+ * 数据来源标识:network:<跳> / cache / cache-stale / empty。
323
+ * 存在的理由:只给 cached 布尔值时,「拿到的是新鲜索引」「用的是三天前的缓存」「六跳全失败」三者
324
+ * 在界面上长得一模一样,用户会把"索引不可用"读成"市场里没有这个插件"。
325
+ */
326
+ readonly source?: string;
327
+ /** 数据是否已过期(来自过期缓存,或全部来源失败)。 */
328
+ readonly stale?: boolean;
329
+ /** 逐跳失败原因(有上限);UI 如实展示,不把失败画成"空结果"。 */
330
+ readonly notes?: readonly string[];
331
+ }
332
+ /** 本插件安装过的非插件资源记录。 */
333
+ export interface InstalledKind {
334
+ readonly kind: MarketItemKind;
335
+ /** owner/repo。 */
336
+ readonly repo: string;
337
+ /** 落地目录绝对路径。 */
338
+ readonly dir: string;
339
+ /** 安装时间(ISO 8601)。 */
340
+ readonly installedAt: string;
341
+ /** 安装时的 commit,供更新检测。 */
342
+ readonly commit?: string;
343
+ }
344
+ /** 技能与预设页面数据。 */
345
+ export interface KindListResult {
346
+ readonly records: readonly InstalledKind[];
347
+ /** 磁盘上存在但无安装记录的目录(用户手工放的)。 */
348
+ readonly orphans: readonly string[];
349
+ }
350
+ /**
351
+ * 备份文档的格式标识字面量。
352
+ *
353
+ * 这里只声明**类型**(types.ts 不放运行期代码);运行期常量在 envManager.ts,
354
+ * 由它的类型断言与本字面量绑定,改一处漏另一处会编译失败。
355
+ */
356
+ export type BackupFormat = 'dsh-plugin-manager-companion/environment-backup';
357
+ /**
358
+ * 一次导出的环境备份。
359
+ *
360
+ * 刻意只包含重装所需的事实 —— 依赖的来源 spec 与 bundle 层栈。node_modules 实体、
361
+ * 凭据、缓存、以及用户的 cordis.patch.yml 都不进来:备份的价值是**可重放**,不是复制数据;
362
+ * 而补丁层是用户亲手写的状态,盲目覆盖它比不备份更危险。
363
+ */
364
+ export interface EnvironmentBackup {
365
+ readonly format: BackupFormat;
366
+ readonly version: 1;
367
+ readonly exportedAt: string;
368
+ readonly environment: string;
369
+ readonly bundles: readonly string[];
370
+ /** 包名到安装来源 spec(pnpm 记录的原样值)。 */
371
+ readonly dependencies: Readonly<Record<string, string>>;
372
+ }
373
+ /** 一条需要重装的依赖。 */
374
+ export interface BackupMissingEntry {
375
+ readonly name: string;
376
+ /** 可直接交给官方 add 的 spec(本地来源已解析成绝对路径)。 */
377
+ readonly source: string;
378
+ }
379
+ /** 备份与目标环境的差异,分五类。 */
380
+ export interface EnvironmentBackupDiff {
381
+ /** 没有不可恢复条目时为 true。 */
382
+ readonly ok: boolean;
383
+ /** 需要重装的依赖。 */
384
+ readonly missing: readonly BackupMissingEntry[];
385
+ /** 目标环境已装、无需处理的依赖名。 */
386
+ readonly already: readonly string[];
387
+ /** 目标环境目录不存在(备份里有、本机没有的环境名)。 */
388
+ readonly missingProfiles: readonly string[];
389
+ /** 来源已消失或非法的条目说明(重装也不可能成功)。 */
390
+ readonly unrestorable: readonly string[];
391
+ /** 备份里有、目标环境当前层栈里没有的 bundle。 */
392
+ readonly bundlesMissing: readonly string[];
393
+ }
394
+ /**
395
+ * 一次试装(质量门第二步)在**这次安装**里的处置。
396
+ *
397
+ * 词汇表(结论、深度、挂载判定)单一事实来源在 envManager(试装引擎),这里只做类型引用:
398
+ * 类型导入不产生运行期依赖,因此不会和 envManager → types 的既有方向形成运行期环。
399
+ */
400
+ export type TrialPolicyOutcome =
401
+ /** 试装通过(或试装未开启),安装照常。 */
402
+ 'passed'
403
+ /** 试装未通过且策略是 block:已回滚,没有装。 */
404
+ | 'blocked'
405
+ /** 试装未通过但策略是 warn:装了,结论如实带在结果里。 */
406
+ | 'warned'
407
+ /** 试装已开启但这次没执行(质量门整体关闭 / 包在豁免名单里)。 */
408
+ | 'skipped';
409
+ /** 试装结论的摘要(JSON-safe,给界面渲染用;完整证据在 output 里)。 */
410
+ export interface GatedInstallTrial {
411
+ /** 结论(passed / baseline-broken / candidate-broken / cannot-trial)。 */
412
+ readonly conclusion: TrialConclusion;
413
+ /** 这次结论对安装的处置。 */
414
+ readonly policy: TrialPolicyOutcome;
415
+ /** 结论实际基于哪种快照深度;试装没执行/没物化快照时为 undefined。 */
416
+ readonly depth?: SnapshotDepth;
417
+ /** 是否发生过 shallow → full 的升级。 */
418
+ readonly escalated: boolean;
419
+ /** 浅快照不给力的原因(升级时)。 */
420
+ readonly escalationReason?: string;
421
+ /** 基线启动判定形态;未做基线启动时为 null。 */
422
+ readonly baseline: BootVerdictKind | null;
423
+ /** 装完候选包后的启动判定形态;没走到这一步时为 null。 */
424
+ readonly candidate: BootVerdictKind | null;
425
+ readonly elapsedMs: number;
426
+ /** 面向用户的完整说明(含根因链、指纹、构建)。 */
427
+ readonly output: string;
428
+ /** 处置的一句话依据(例如"按 warn 模式放行"、"已回滚";跳过时是跳过的原因)。 */
429
+ readonly policyNote: string;
430
+ }
431
+ /** 挂载判定的形态(不含根因链,摘要用);从引擎的三态判定派生,避免两处漂移。 */
432
+ export type BootVerdictKind = BootVerdict['kind'];
433
+ /** 一次受质量门保护的安装结果。 */
434
+ export interface GatedInstallResult {
435
+ /** 是否最终装成功(含通过质量门并激活)。 */
436
+ readonly ok: boolean;
437
+ /** 面向用户的输出。 */
438
+ readonly output: string;
439
+ /** 安装的包名;未装成时 undefined。 */
440
+ readonly packageName?: string;
441
+ /** 质量门发现的问题;通过时为空数组。 */
442
+ readonly gateIssues: readonly string[];
443
+ /** 失败时是否已回滚。 */
444
+ readonly rolledBack?: boolean;
445
+ /** 试装(第二步)的结果;试装关闭时为 undefined。 */
446
+ readonly trial?: GatedInstallTrial;
447
+ }
448
+ /**
449
+ * 一个"升级单元"的种类。三类必须分开对待,这是升级这件事的核心诚实点。
450
+ */
451
+ export type UpgradeUnitKind =
452
+ /** profile 的 dependencies 里声明着 → 可以在 profile 内升级(走官方 add)。 */
453
+ 'profile-dependency'
454
+ /** 只出现在 dsh.profile.bundles 里(安装方提供的层,如 dsh-base / dsh-web-app)→ profile 内升不了。 */
455
+ | 'installation-provided'
456
+ /** 本插件自身 → 可升级,但正在运行的是旧代码:下次启动生效。 */
457
+ | 'self';
458
+ /** 四态(界面直接渲染,不要自己推断)。 */
459
+ export type UpgradeState =
460
+ /** 有比当前更新的版本。 */
461
+ 'update-available'
462
+ /** 已知没有更新的版本(**必须真的有版本事实**才算,查不到不是这个态)。 */
463
+ | 'up-to-date'
464
+ /** 查不到版本事实(没有 registry 事实、也没到检查时间、registry 不可用…)。 */
465
+ | 'unknown'
466
+ /** 结构上就升不了(安装方提供的层)。 */
467
+ | 'not-upgradable';
468
+ /** 一条 dist-tag(版本线)。 */
469
+ export interface UpgradeTag {
470
+ /** dist-tag 名(latest / next / beta …)。 */
471
+ readonly tag: string;
472
+ readonly version: string;
473
+ /** 与当前版本是不是同一条线(同 major.minor.patch);当前版本未知时是 'unknown'。 */
474
+ readonly line: 'same-line' | 'other-line' | 'unknown';
475
+ /** 同线里最新的那一个(界面默认高亮它);没有同线候选时为 false。 */
476
+ readonly preferred: boolean;
477
+ }
478
+ /** 一个升级单元的检测结果。 */
479
+ export interface UpgradeUnitReport {
480
+ readonly name: string;
481
+ readonly kind: UpgradeUnitKind;
482
+ readonly state: UpgradeState;
483
+ /** 当前版本(读盘:node_modules/<name>/package.json);读不到时 null。 */
484
+ readonly currentVersion: string | null;
485
+ /** 当前版本的线(major.minor.patch);读不到时 null。 */
486
+ readonly currentLine: string | null;
487
+ /** 当前声明来源(dependencies 里的 spec);安装方提供的层没有这一项。 */
488
+ readonly spec?: string;
489
+ /** 目标版本(默认 = 与当前同线的最新;没有同线候选时取 latest)。 */
490
+ readonly targetVersion: string | null;
491
+ /** 目标版本来自哪个 dist-tag。 */
492
+ readonly targetTag: string | null;
493
+ /** 目标版本的线;与 currentLine 不同表示"升级会切到另一条线"。 */
494
+ readonly targetLine: string | null;
495
+ /** 全部 dist-tags;拿不到时为 null(那时 tagsReason 说明为什么)。 */
496
+ readonly tags: readonly UpgradeTag[] | null;
497
+ /** 版本事实的来源与时间(界面必须标出来)。 */
498
+ readonly source?: 'market-index' | 'registry';
499
+ readonly at?: string;
500
+ /** 面向用户的原因(查不到/不可升级/为什么是这个目标)。 */
501
+ readonly reason?: string;
502
+ /** 升级会把来源从本地路径/link 换成 registry 版本。 */
503
+ readonly changesSource?: boolean;
504
+ /** 第 2 类(安装方提供的层)只给这条命令,不给按钮。 */
505
+ readonly command?: string;
506
+ }
507
+ /** 升级检查的结果(op: upgradeCheck)。 */
508
+ export interface UpgradeCheckResult {
509
+ readonly environment: string;
510
+ readonly units: readonly UpgradeUnitReport[];
511
+ /** 本次是否真的出网查了 registry(false = 用了缓存/市场索引/未到间隔)。 */
512
+ readonly checked: boolean;
513
+ /** 上次成功检查的时刻(ISO);从未成功过时 null。 */
514
+ readonly lastCheckAt: string | null;
515
+ /** 降级与边界事实(用户可见的 notes)。 */
516
+ readonly notes: readonly string[];
517
+ }
518
+ /** 一次升级的金丝雀(试装)结论。 */
519
+ export interface UpgradeCanaryReport {
520
+ /** 是否真的跑了试装(关掉试装总开关时为 false,此时必须如实说"未验证")。 */
521
+ readonly ran: boolean;
522
+ readonly conclusion?: TrialConclusion;
523
+ readonly depth?: SnapshotDepth;
524
+ readonly escalated?: boolean;
525
+ readonly elapsedMs?: number;
526
+ /** 试装结论原文(给人读的完整证据)。 */
527
+ readonly output?: string;
528
+ /** 没跑金丝雀的原因。 */
529
+ readonly skippedReason?: string;
530
+ /** 用完即删的结局(一次性资产:删掉了 / 删不掉并给出原因)。 */
531
+ readonly cleanup: string;
532
+ /**
533
+ * 激活证据:候选到底有没有进测试环境的层栈(dsh.profile.bundles)。
534
+ *
535
+ * 升级场景下这条证据是金丝雀成立的前提:候选已在源环境 dependencies 里时,
536
+ * 官方 reconcile 会跳过"既有依赖",候选进不了层栈 → 挂载期不加载它 →
537
+ * 旧代码照样启动成功 → 假通过。没拿到证据时为 undefined(不假装有)。
538
+ */
539
+ readonly activation?: {
540
+ readonly name: string;
541
+ readonly bundles: readonly string[];
542
+ readonly activated: boolean;
543
+ readonly removedFirst: boolean;
544
+ readonly removeNote: string;
545
+ };
546
+ }
547
+ /** 一次升级的结果。 */
548
+ export interface UpgradeActionResult extends EnvironmentResult {
549
+ readonly name: string;
550
+ readonly fromVersion: string | null;
551
+ readonly toVersion: string;
552
+ /** 本次用的 spec(官方 add 收到的那个)。 */
553
+ readonly spec: string;
554
+ readonly canary: UpgradeCanaryReport;
555
+ /** 升级后按盘核对的事实(依赖行 / node_modules / 版本)。 */
556
+ readonly diskFacts: readonly string[];
557
+ /** 是否要重启才生效(官方口径;本插件自身一定是 true)。 */
558
+ readonly restartRequired: boolean;
559
+ }
560
+ /** 一次回滚的结果。 */
561
+ export interface UpgradeRollbackResult extends EnvironmentResult {
562
+ readonly name: string;
563
+ /** 回滚前的版本。 */
564
+ readonly fromVersion: string | null;
565
+ /** 回滚到的版本。 */
566
+ readonly toVersion: string;
567
+ readonly diskFacts: readonly string[];
568
+ /** 盘上核对是否一致(false = 有残留或没到位,如实说,不许声称"环境未被改动")。 */
569
+ readonly clean: boolean;
570
+ }
571
+ /**
572
+ * 一个测试环境(`<真实环境名>-dpmc`)的只读事实。
573
+ *
574
+ * 全部读盘得来(不读内存台账):测试环境不参与诊断结论,也不是真值来源,
575
+ * 因此这里只回答"它在不在、多大、多旧、还在跑吗"。
576
+ */
577
+ export interface TrialEnvironmentInfo {
578
+ /** 测试环境名(`<真实环境名>-dpmc`)。 */
579
+ readonly name: string;
580
+ /** 归属的真实环境名(由名字形态推出)。 */
581
+ readonly owner: string;
582
+ /** 归属的真实环境是否还在(false = 孤儿测试环境,同样可删)。 */
583
+ readonly ownerExists: boolean;
584
+ /** 绝对路径。 */
585
+ readonly dir: string;
586
+ /** 是否正在运行;进程事实读不到时按 true 处理(保守:不删)。 */
587
+ readonly running: boolean;
588
+ /** 快照物化时间(目录 mtime,epoch 毫秒)。 */
589
+ readonly modifiedAtMs: number;
590
+ /** 同上的 ISO 字符串(界面直接用)。 */
591
+ readonly modifiedAt: string;
592
+ /** 距今天数(保留期判定用同一个口径)。 */
593
+ readonly ageDays: number;
594
+ /** 占地(apparent 字节合计);统计被截断或读不到时为 null。 */
595
+ readonly bytes: number | null;
596
+ /** 统计到的文件数。 */
597
+ readonly files: number;
598
+ /** nlink>1 的文件数(pnpm store 硬链接;这些文件的实际独占磁盘远小于 bytes)。 */
599
+ readonly sharedFiles: number;
600
+ /** bytes 为 null 时的原因(面向用户)。 */
601
+ readonly bytesReason?: string;
602
+ /**
603
+ * 快照清单是否仍与真实环境一致(三件套 hash 比对);真实环境已不存在时为 null。
604
+ * false 表示下次试装会重新物化(§5.4 第二步的即时物化),不是错误。
605
+ */
606
+ readonly snapshotMatchesOwner: boolean | null;
607
+ }
608
+ /** 试装环境查询的结果(op: trialEnvironments)。 */
609
+ export interface TrialEnvironmentReport {
610
+ readonly environments: readonly TrialEnvironmentInfo[];
611
+ /** 进程事实是否可读;false 时 running 一律按 true 报(不删的保守面)。 */
612
+ readonly factsReadable: boolean;
613
+ /** 进程事实不可读的原因。 */
614
+ readonly factsReason?: string;
615
+ readonly totals: {
616
+ readonly count: number;
617
+ readonly running: number;
618
+ /** 已知占地合计;有环境统计不出来时只是"已知部分"。 */
619
+ readonly bytes: number;
620
+ /** 统计不出来的环境数(bytes 不等于总占地时看它)。 */
621
+ readonly unknownBytes: number;
622
+ };
623
+ /** 当前生效的保留策略(从配置读;UI 直接显示,不要自己拼默认值)。 */
624
+ readonly retention: {
625
+ /** 保留天数。 */
626
+ readonly days: number;
627
+ readonly autoCleanup: boolean;
628
+ /** 上限;0 = 不限。 */
629
+ readonly maxKept: number;
630
+ };
631
+ /** 下次清理会删谁、留谁(纯计划;这个 op 不删任何东西)。 */
632
+ readonly plan: {
633
+ readonly remove: readonly {
634
+ readonly name: string;
635
+ readonly reason: string;
636
+ }[];
637
+ readonly keep: readonly {
638
+ readonly name: string;
639
+ readonly reason: string;
640
+ }[];
641
+ };
642
+ /** 是否已达到/超过保留上限(达到上限时新的一轮试装会拒绝执行)。 */
643
+ readonly overCap: boolean;
644
+ /** 降级/不可读事实(用户可见)。 */
645
+ readonly notes: readonly string[];
646
+ }
647
+ /** 一次试装环境清理的结果(op: trialCleanup)。 */
648
+ export interface TrialCleanupResult extends EnvironmentResult {
649
+ /** 实际删掉的测试环境名。 */
650
+ readonly removed: readonly string[];
651
+ }
package/dist/types.js ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * dsh-plugin-manager-companion — host/client 的 wire 契约。
3
+ *
4
+ * 归属:A 类·重写(旧 src/types.ts 仅作字段意图参考,未复制代码)。
5
+ * 官方复用:官方 pluginManager/types 的类型直接 re-export,不重复定义。
6
+ * 前提检查:旧类型里有大量为自建 REST + 自建 patch 写入设计的形状
7
+ * (MutationResult/CommandResult/UpdateInfo 等),前提已消失——
8
+ * 当前 profile 的写操作全部走官方 Remote,本文件只描述官方不覆盖的部分:
9
+ * 跨环境管理、深度诊断、市场、技能与预设。
10
+ *
11
+ * 全部类型必须 JSON-safe(跨 wire 传输)。
12
+ */
13
+ export {};