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.
- package/LICENSE +21 -0
- package/README.en.md +144 -0
- package/README.md +142 -0
- package/cordis.patch.yml +9 -0
- package/dist/about.d.ts +77 -0
- package/dist/about.js +179 -0
- package/dist/cli.d.ts +226 -0
- package/dist/cli.js +856 -0
- package/dist/client/AboutPage.d.ts +75 -0
- package/dist/client/ConsolePage.d.ts +79 -0
- package/dist/client/KindsPage.d.ts +21 -0
- package/dist/client/MarketplacePage.d.ts +36 -0
- package/dist/client/OfficialSlots.d.ts +35 -0
- package/dist/client/UpgradeRow.d.ts +108 -0
- package/dist/client/index.d.ts +26 -0
- package/dist/client/locales.d.ts +475 -0
- package/dist/client/pmSelect.d.ts +38 -0
- package/dist/client/shared.d.ts +928 -0
- package/dist/client/upgradeView.d.ts +278 -0
- package/dist/client/wire.d.ts +401 -0
- package/dist/client.js +9194 -0
- package/dist/diagnostics.d.ts +332 -0
- package/dist/diagnostics.js +2631 -0
- package/dist/envManager.d.ts +1047 -0
- package/dist/envManager.js +3214 -0
- package/dist/fix.d.ts +60 -0
- package/dist/fix.js +168 -0
- package/dist/guard.d.ts +133 -0
- package/dist/guard.js +232 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +1150 -0
- package/dist/installSession.d.ts +111 -0
- package/dist/installSession.js +150 -0
- package/dist/kinds.d.ts +464 -0
- package/dist/kinds.js +1029 -0
- package/dist/marketView.d.ts +261 -0
- package/dist/marketView.js +406 -0
- package/dist/marketplace.d.ts +248 -0
- package/dist/marketplace.js +500 -0
- package/dist/match.d.ts +67 -0
- package/dist/match.js +203 -0
- package/dist/net.d.ts +108 -0
- package/dist/net.js +163 -0
- package/dist/official.d.ts +145 -0
- package/dist/official.js +205 -0
- package/dist/paths.d.ts +108 -0
- package/dist/paths.js +236 -0
- package/dist/presets.d.ts +299 -0
- package/dist/presets.js +578 -0
- package/dist/qualityGate.d.ts +66 -0
- package/dist/qualityGate.js +247 -0
- package/dist/rank.d.ts +88 -0
- package/dist/rank.js +164 -0
- package/dist/registry.d.ts +295 -0
- package/dist/registry.js +686 -0
- package/dist/rest.d.ts +122 -0
- package/dist/rest.js +219 -0
- package/dist/scan.d.ts +134 -0
- package/dist/scan.js +396 -0
- package/dist/settings.d.ts +447 -0
- package/dist/settings.js +263 -0
- package/dist/tags.d.ts +119 -0
- package/dist/tags.js +166 -0
- package/dist/tools.d.ts +131 -0
- package/dist/tools.js +377 -0
- package/dist/types.d.ts +651 -0
- package/dist/types.js +13 -0
- package/dist/upgrade.d.ts +428 -0
- package/dist/upgrade.js +1100 -0
- package/dist/upgradeView.d.ts +313 -0
- package/dist/upgradeView.js +273 -0
- package/docs/images/readme/01-console-health.png +0 -0
- package/docs/images/readme/02-console-envs.png +0 -0
- package/docs/images/readme/03-marketplace.png +0 -0
- package/docs/images/readme/04-official-plugin-page.png +0 -0
- package/package.json +104 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 升级引擎(档三):把"升级已装插件"做成真实可执行、且**说清边界**的能力。
|
|
3
|
+
*
|
|
4
|
+
* 归属:A 类·重写(新代码;旧仓库没有升级能力,只有 CLI 的 `update` 把 spec 重写到 @latest)。
|
|
5
|
+
* 官方复用:
|
|
6
|
+
* · 写通道只有一条 —— 官方 `runPluginCommand(['add', '<name>@<version>'])`(绝不自己调 pnpm,
|
|
7
|
+
* 也绝不写 cordis.patch.yml);官方 CLI 的 plugin 子命令与我们走的是同一条通道。
|
|
8
|
+
* · 版本查询走本仓库既有的出网层(net.ts 的 Fetcher),不新造 HTTP 客户端。
|
|
9
|
+
* · 金丝雀复用 task-50/75 的试装引擎:它就是"在 <环境>-dpmc 里装候选再跑两次启动"。
|
|
10
|
+
* 前提检查:旧前提是"官方只有只读清单,升级得自己想办法"。0.1.6 之后官方给了完整写面与
|
|
11
|
+
* `installed` / `removable` 事实,所以本模块只做官方不覆盖的三件事:版本事实(dist-tags)、
|
|
12
|
+
* 三类单元的分类、金丝雀与回滚的盘上核对。
|
|
13
|
+
*
|
|
14
|
+
* 三类单元(必须分开对待,这是本模块的核心诚实点):
|
|
15
|
+
* 1. `profile-dependency`:在 profile 的 dependencies 里 → 可在 profile 内升级;
|
|
16
|
+
* 2. `installation-provided`:只出现在 dsh.profile.bundles 里(官方运行时层 dsh-base / dsh-web-app)
|
|
17
|
+
* → profile 内**升不了**,只检测 + 给命令,不给按钮;
|
|
18
|
+
* 3. `self`:本插件自身 → 可升级,但**正在运行的就是旧代码**,必须走独立 job 并写明"下次启动生效"。
|
|
19
|
+
*
|
|
20
|
+
* 四态:`update-available` / `up-to-date` / `unknown` / `not-upgradable`。
|
|
21
|
+
* 铁律:拿不到版本事实一律 `unknown`(文案"查不到"),**绝不**显示"已是最新"——"没查到"与
|
|
22
|
+
* "确实没有更新"是两个不同的状态,把前者说成后者就是编一个事实。
|
|
23
|
+
*
|
|
24
|
+
* 出网纪律(Lead 定稿):检查时机 = 进入即查 + TTL + 手动常驻,**不做后台轮询**。
|
|
25
|
+
* "每天一次"的语义是"下次进入时若距上次成功检查超过 24h 就查";失败也记时间戳(1 小时内不自动重试,
|
|
26
|
+
* 免得每次进入都等超时);手动按钮永远可用(不受开关、TTL 与负缓存限制)。
|
|
27
|
+
*/
|
|
28
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
29
|
+
import type { PackageResult } from '@deepseek-ai/dsh-plugin-manager/types';
|
|
30
|
+
import type { BootVerification, PluginCommandRunner, TrialInstallOptions, TrialInstallResult } from './envManager.ts';
|
|
31
|
+
/**
|
|
32
|
+
* 试装执行器(测试注入金丝雀结论)。
|
|
33
|
+
*
|
|
34
|
+
* 与 index.ts 里那个 TrialRunner **结构相同、刻意各自定义**:index.ts 要 import 本模块的 op 编排,
|
|
35
|
+
* 本模块再去 import 它的类型就成环了。类型层面结构一致,互相传参没有问题。
|
|
36
|
+
*/
|
|
37
|
+
export type UpgradeTrialRunner = (spec: string, realName: string, options: TrialInstallOptions) => Promise<TrialInstallResult>;
|
|
38
|
+
import { type Fetcher } from './net.ts';
|
|
39
|
+
import { type RegistryRepo } from './registry.ts';
|
|
40
|
+
import { type CompanionConfig } from './settings.ts';
|
|
41
|
+
import type { UpgradeActionResult, UpgradeCanaryReport, UpgradeCheckResult, UpgradeRollbackResult, UpgradeState, UpgradeTag, UpgradeUnitKind } from './types.ts';
|
|
42
|
+
/** 配置留空时的 registry(官方 npm)。 */
|
|
43
|
+
export declare const OFFICIAL_REGISTRY_URL = "https://registry.npmjs.org";
|
|
44
|
+
/** 单次 registry 查询的超时(一个包文档很小,15s 是宽松上限)。 */
|
|
45
|
+
export declare const REGISTRY_TIMEOUT_MS = 15000;
|
|
46
|
+
/** 一次检查里所有出网查询的总预算;超了就停手并如实记账,不拖住页面。 */
|
|
47
|
+
export declare const CHECK_BUDGET_MS = 20000;
|
|
48
|
+
/**
|
|
49
|
+
* 检查失败后的静默期:1 小时内不再自动重试。
|
|
50
|
+
*
|
|
51
|
+
* 存在的理由:registry 挂掉时,每次进入关于页都等一次 15s 超时是折磨;手动按钮不受它限制。
|
|
52
|
+
*/
|
|
53
|
+
export declare const NEGATIVE_TTL_MS: number;
|
|
54
|
+
/** tags 磁盘缓存的格式版本(与 registry 缓存同一纪律:格式不符即视为无缓存)。 */
|
|
55
|
+
export declare const TAGS_CACHE_FORMAT = 1;
|
|
56
|
+
/** tags 磁盘缓存文件名(放在我们自己的缓存目录里,与市场索引缓存同级)。 */
|
|
57
|
+
export declare const TAGS_CACHE_FILE = "upgrade-tags.json";
|
|
58
|
+
/** 一次 dist-tags 查询的入参。 */
|
|
59
|
+
export interface DistTagsQuery {
|
|
60
|
+
/** registry 地址;留空 = 官方 registry。 */
|
|
61
|
+
readonly registryUrl?: string;
|
|
62
|
+
readonly timeoutMs?: number;
|
|
63
|
+
/** 抓取器注入(测试);省略时用 net.ts 的带代理实现。 */
|
|
64
|
+
readonly fetch?: Fetcher;
|
|
65
|
+
}
|
|
66
|
+
/** 一次 dist-tags 查询的结果。 */
|
|
67
|
+
export interface DistTagsAnswer {
|
|
68
|
+
readonly ok: boolean;
|
|
69
|
+
/** tag 名 → 版本;失败时为 null。 */
|
|
70
|
+
readonly tags: Readonly<Record<string, string>> | null;
|
|
71
|
+
/** 失败原因(面向用户;成功时为 undefined)。 */
|
|
72
|
+
readonly reason?: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 包文档 URL。
|
|
76
|
+
*
|
|
77
|
+
* scoped 名必须整体转义(`@scope/name` → `%40scope%2Fname`),否则 `/` 会被当成路径分隔符。
|
|
78
|
+
*
|
|
79
|
+
* @param registryUrl - registry 基地址(可带尾斜杠)。
|
|
80
|
+
* @param name - 包名。
|
|
81
|
+
* @returns 文档 URL。
|
|
82
|
+
*/
|
|
83
|
+
export declare function registryDocumentUrl(registryUrl: string, name: string): string;
|
|
84
|
+
/**
|
|
85
|
+
* 从 registry 文档里取 dist-tags(纯函数,便于用固定载荷测试)。
|
|
86
|
+
*
|
|
87
|
+
* 只认 `dist-tags`;缺字段或值不是字符串时返回 null(**不猜**:把 `versions` 里最大的那个
|
|
88
|
+
* 当成 latest 会与 tag 的真实语义脱钩)。
|
|
89
|
+
*
|
|
90
|
+
* @param payload - 解析后的 JSON。
|
|
91
|
+
* @returns tag 表;拿不到时 null。
|
|
92
|
+
*/
|
|
93
|
+
export declare function parseDistTags(payload: unknown): Record<string, string> | null;
|
|
94
|
+
/**
|
|
95
|
+
* 查一个包的 dist-tags。
|
|
96
|
+
*
|
|
97
|
+
* 失败一律以 `ok: false` + reason 返回(调用方据此显示"查不到"),不抛异常:
|
|
98
|
+
* 一次网络抖动不该让整页检查失败。
|
|
99
|
+
*
|
|
100
|
+
* @param name - 包名。
|
|
101
|
+
* @param query - registry 地址 / 超时 / 抓取器。
|
|
102
|
+
* @returns 结果。
|
|
103
|
+
*/
|
|
104
|
+
export declare function fetchDistTags(name: string, query?: DistTagsQuery): Promise<DistTagsAnswer>;
|
|
105
|
+
/**
|
|
106
|
+
* 一条版本线(major.minor.patch);非法/缺失时 null。
|
|
107
|
+
*
|
|
108
|
+
* "与当前版本同线"= 同 major.minor.patch(例如 0.1.6-alpha.2 与 0.1.6-alpha.9 同线,
|
|
109
|
+
* 与 0.1.7 不同线)。判定只做字符串切分,不假装懂 semver:比较大小交给 match.ts 的 compareVersions。
|
|
110
|
+
*
|
|
111
|
+
* @param version - 版本串。
|
|
112
|
+
* @returns 线,或 null。
|
|
113
|
+
*/
|
|
114
|
+
export declare function versionLine(version: string | null): string | null;
|
|
115
|
+
/**
|
|
116
|
+
* 一个包是不是本地来源(`link:` / `file:` / 相对或绝对路径)。
|
|
117
|
+
*
|
|
118
|
+
* 本地来源也能"升级"到 registry 版本,但那会**改变来源**(不再是本地那份)——必须显式说出来。
|
|
119
|
+
*
|
|
120
|
+
* @param spec - dependencies 里的 spec。
|
|
121
|
+
* @returns 是本地来源时 true。
|
|
122
|
+
*/
|
|
123
|
+
export declare function isLocalSpec(spec: string | undefined): boolean;
|
|
124
|
+
/** 把 dist-tags 折成界面要的列表(含"同线/另一条线"与默认高亮)。 */
|
|
125
|
+
export declare function tagReports(tags: Readonly<Record<string, string>>, currentVersion: string | null): readonly UpgradeTag[];
|
|
126
|
+
/**
|
|
127
|
+
* 默认目标版本:与当前同线的**最新**;没有同线候选(或当前版本未知)时取 `latest`,
|
|
128
|
+
* 再退一步取所有 tag 里版本最大的那个(顺序即优先级,界面据此说"会切到哪条线")。
|
|
129
|
+
*
|
|
130
|
+
* @param tags - tag 表。
|
|
131
|
+
* @param currentVersion - 当前版本。
|
|
132
|
+
* @returns 目标版本与提供它的 tag;没有可用 tag 时 null。
|
|
133
|
+
*/
|
|
134
|
+
export declare function pickTarget(tags: Readonly<Record<string, string>>, currentVersion: string | null): {
|
|
135
|
+
readonly version: string;
|
|
136
|
+
readonly tag: string;
|
|
137
|
+
} | null;
|
|
138
|
+
/** 一个包的缓存条目。 */
|
|
139
|
+
export interface TagsCacheEntry {
|
|
140
|
+
readonly ok: boolean;
|
|
141
|
+
readonly tags: Readonly<Record<string, string>> | null;
|
|
142
|
+
/** 这次查询发生的时刻(epoch ms)。 */
|
|
143
|
+
readonly at: number;
|
|
144
|
+
readonly reason?: string;
|
|
145
|
+
/**
|
|
146
|
+
* 这条事实是在**哪个环境**的检查里取到的。
|
|
147
|
+
*
|
|
148
|
+
* 为什么必须带上它(不是可有可无的记账):dist-tags 本身与环境无关,但"查不到"是
|
|
149
|
+
* **逐环境**的用户体验。实测反例(就是这条红测):A 环境刚查成功,B 环境里同一个包
|
|
150
|
+
* 就再也不出网了——因为全局时间戳把 B 的检查判成"还没到期",于是 B 永远看不到
|
|
151
|
+
* 自己的失败,也就永远拿不到属于它的"查不到 + 重试"。条目只在自己取到的那个环境里
|
|
152
|
+
* 生效,换环境一律重新取。
|
|
153
|
+
*/
|
|
154
|
+
readonly environment: string;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* 一个环境的检查记账。
|
|
158
|
+
*
|
|
159
|
+
* 为什么记账是**逐环境**的(而不是全局一份):TTL 的语义是"这个环境下次进入时要不要出网",
|
|
160
|
+
* 而"查不到"是**逐环境**的用户体验。实测反例(就是这条红测):A 环境刚查成功,
|
|
161
|
+
* 紧接着 B 环境进入时被全局时间戳判成"还没到期"→ B 一次网都不出,于是 B 永远看不到
|
|
162
|
+
* 自己的失败,也永远拿不到属于它的"查不到 + 重试"。全局时间戳把两个环境的账记成了一本。
|
|
163
|
+
*/
|
|
164
|
+
export interface TagsCacheEnvState {
|
|
165
|
+
/** 这个环境上次**成功**拿到版本事实的时刻;从未成功过时 null。 */
|
|
166
|
+
readonly lastCheckAt: number | null;
|
|
167
|
+
/** 这个环境上次**尝试**(含失败)的时刻;用于负缓存。 */
|
|
168
|
+
readonly lastAttemptAt: number | null;
|
|
169
|
+
}
|
|
170
|
+
/** 磁盘缓存文件。 */
|
|
171
|
+
export interface TagsCacheFile {
|
|
172
|
+
/** 逐环境的检查记账(环境名 → 记账)。 */
|
|
173
|
+
readonly environments: Readonly<Record<string, TagsCacheEnvState>>;
|
|
174
|
+
/**
|
|
175
|
+
* 逐包的版本事实。
|
|
176
|
+
*
|
|
177
|
+
* 键是包名,但每条都带 {@link TagsCacheEntry.environment}:条目只在自己取到的那个
|
|
178
|
+
* 环境里生效,换环境一律重新取(见那个字段的注释)。
|
|
179
|
+
*/
|
|
180
|
+
readonly packages: Readonly<Record<string, TagsCacheEntry>>;
|
|
181
|
+
}
|
|
182
|
+
/** 缓存文件路径(我们自己的缓存目录,与市场索引缓存同级)。 */
|
|
183
|
+
export declare function tagsCachePath(): string;
|
|
184
|
+
/**
|
|
185
|
+
* 读缓存;不存在/损坏/格式不符时返回空壳(**不抛**:缓存是可重建的派生物)。
|
|
186
|
+
*
|
|
187
|
+
* @returns 缓存内容。
|
|
188
|
+
*/
|
|
189
|
+
export declare function readTagsCache(): TagsCacheFile;
|
|
190
|
+
/**
|
|
191
|
+
* 写缓存(失败不抛,返回是否写成功)。
|
|
192
|
+
*
|
|
193
|
+
* @param file - 要写的内容。
|
|
194
|
+
* @returns 是否写成功。
|
|
195
|
+
*/
|
|
196
|
+
export declare function writeTagsCache(file: TagsCacheFile): boolean;
|
|
197
|
+
/**
|
|
198
|
+
* 一条缓存是否仍然可用(纯函数,**逐包判定**)。
|
|
199
|
+
*
|
|
200
|
+
* 成功的条目按配置的检查间隔计时;失败的条目按 {@link NEGATIVE_TTL_MS} 计时
|
|
201
|
+
* (失败也要记时间戳,否则每次进入都会重试一次超时)。
|
|
202
|
+
*
|
|
203
|
+
* 为什么判据是**条目自己的** at 而不是全局时间戳:全局时间戳会让一个包的成功
|
|
204
|
+
* 顺带放行另一个包的负缓存。实测反例(就是这条红测):环境 A 的包查成功之后,
|
|
205
|
+
* 同一个环境 B 里刚失败过的包在"1 小时内不自动重试"的窗口里又被查了一次。
|
|
206
|
+
*
|
|
207
|
+
* @param entry - 缓存条目。
|
|
208
|
+
* @param now - 当前时刻。
|
|
209
|
+
* @param ttlMs - 成功条目的有效期;null = 仅手动(此时对成功条目返回 true,
|
|
210
|
+
* 语义是"不因过期而自动查"——真正的自动检查开关由调用方管)。
|
|
211
|
+
* @returns 可直接使用该条目时 true。
|
|
212
|
+
*/
|
|
213
|
+
export declare function tagsCacheUsable(entry: TagsCacheEntry, now: number, ttlMs: number | null): boolean;
|
|
214
|
+
/** 一个升级单元的事实(读盘得来,不含网络)。 */
|
|
215
|
+
export interface UpgradeUnitFact {
|
|
216
|
+
readonly name: string;
|
|
217
|
+
readonly kind: UpgradeUnitKind;
|
|
218
|
+
/** dependencies 里的 spec;安装方提供的层没有这一项。 */
|
|
219
|
+
readonly spec?: string;
|
|
220
|
+
/** spec 是本地来源(升级会改变来源)。 */
|
|
221
|
+
readonly specIsLocal: boolean;
|
|
222
|
+
/** 当前版本(node_modules 里那个包的 version);读不到时 null。 */
|
|
223
|
+
readonly currentVersion: string | null;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* 一个包在当前环境里装着的版本(读 node_modules/<name>/package.json)。
|
|
227
|
+
*
|
|
228
|
+
* 读不到就返回 null(link: 断链、没装、目录不可读都算)——**不猜**,调用方按"当前版本未知"处理。
|
|
229
|
+
*
|
|
230
|
+
* @param environment - 环境名。
|
|
231
|
+
* @param name - 包名。
|
|
232
|
+
* @returns 版本,或 null。
|
|
233
|
+
*/
|
|
234
|
+
export declare function readInstalledVersion(environment: string, name: string): string | null;
|
|
235
|
+
/**
|
|
236
|
+
* 列出这个环境的全部升级单元(三类)。
|
|
237
|
+
*
|
|
238
|
+
* 分类只认**盘上的结构事实**:出现在 dependencies 里 = profile 依赖(可升);只出现在
|
|
239
|
+
* dsh.profile.bundles 里 = 安装方提供的层(profile 内升不了)。这一条与官方 listBundles 的
|
|
240
|
+
* `installed` 字段同源(已核实:dsh-base / dsh-web-app 只在 bundles 里、不在 dependencies 里)。
|
|
241
|
+
*
|
|
242
|
+
* @param environment - 环境名。
|
|
243
|
+
* @param options - 本插件自身包名(默认取常量;测试可覆盖)。
|
|
244
|
+
* @returns 单元清单(按名字排序,顺序稳定便于断言)。
|
|
245
|
+
* @throws {EnvironmentError} 环境名不合法或环境不存在时。
|
|
246
|
+
*/
|
|
247
|
+
export declare function unitFacts(environment: string, options?: {
|
|
248
|
+
readonly ourPackage?: string;
|
|
249
|
+
}): readonly UpgradeUnitFact[];
|
|
250
|
+
/**
|
|
251
|
+
* 安装方提供的层该给什么命令。
|
|
252
|
+
*
|
|
253
|
+
* 刻意**不**给 `dsh plugin add` / `dshpmc update`:那会把这一层变成 profile 的依赖(装出第二份),
|
|
254
|
+
* 是"看起来能修、其实更坏"的建议。真正要做的是升级 dsh 安装本身,而具体命令取决于当初怎么装的,
|
|
255
|
+
* 所以这里只给一种常见形态 + 明确的口径说明。
|
|
256
|
+
*
|
|
257
|
+
* @param name - 包名。
|
|
258
|
+
* @returns 面向用户的命令说明。
|
|
259
|
+
*/
|
|
260
|
+
export declare function installationUpgradeCommand(name: string): string;
|
|
261
|
+
/** 市场索引给出的版本事实。 */
|
|
262
|
+
export interface MarketVersionFact {
|
|
263
|
+
readonly version: string;
|
|
264
|
+
/** 索引的生成时间(ISO);拿不到时为 null。 */
|
|
265
|
+
readonly at: string | null;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* 从**已有的**市场索引缓存里找这个包的最新版本(零网络)。
|
|
269
|
+
*
|
|
270
|
+
* 只用缓存,不触发索引下载:关于页的一次检查不该顺手拉一份几 MB 的索引。
|
|
271
|
+
*
|
|
272
|
+
* @param name - 包名。
|
|
273
|
+
* @param options - 注入索引仓库(测试);省略时读磁盘缓存。
|
|
274
|
+
* @returns 事实,或 null。
|
|
275
|
+
*/
|
|
276
|
+
export declare function marketVersionFact(name: string, options?: {
|
|
277
|
+
readonly repos?: readonly RegistryRepo[];
|
|
278
|
+
}): MarketVersionFact | null;
|
|
279
|
+
/** 检查的选项。 */
|
|
280
|
+
export interface UpgradeCheckOptions {
|
|
281
|
+
readonly environment: string;
|
|
282
|
+
readonly config: CompanionConfig;
|
|
283
|
+
/** 手动检查:无视开关、TTL 与负缓存,强制出网。 */
|
|
284
|
+
readonly refresh?: boolean;
|
|
285
|
+
readonly fetch?: Fetcher;
|
|
286
|
+
readonly now?: () => number;
|
|
287
|
+
readonly ourPackage?: string;
|
|
288
|
+
readonly repos?: readonly RegistryRepo[];
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* 一个单元的四态(纯函数,便于逐态断言)。
|
|
292
|
+
*
|
|
293
|
+
* @param input - 事实与版本来源。
|
|
294
|
+
* @returns 状态。
|
|
295
|
+
*/
|
|
296
|
+
export declare function upgradeStateFor(input: {
|
|
297
|
+
readonly kind: UpgradeUnitKind;
|
|
298
|
+
readonly currentVersion: string | null;
|
|
299
|
+
readonly targetVersion: string | null;
|
|
300
|
+
}): UpgradeState;
|
|
301
|
+
/**
|
|
302
|
+
* 检查一个环境的升级情况(三类单元 × 四态)。
|
|
303
|
+
*
|
|
304
|
+
* 事实来源优先级(Lead 定稿):① 市场索引缓存(零网络)② npm registry dist-tags(受 TTL 与开关约束)。
|
|
305
|
+
* 两条都拿不到 = `unknown`("查不到"),**绝不**显示"已是最新"。
|
|
306
|
+
*
|
|
307
|
+
* @param options - 环境、配置与注入缝。
|
|
308
|
+
* @returns 检查结果。
|
|
309
|
+
*/
|
|
310
|
+
export declare function checkUpgrades(options: UpgradeCheckOptions): Promise<UpgradeCheckResult>;
|
|
311
|
+
/** 升级引擎的共享依赖(全部可注入,测试不碰真 pnpm / 真 registry)。 */
|
|
312
|
+
export interface UpgradeEngineDeps {
|
|
313
|
+
readonly ctx?: Context;
|
|
314
|
+
readonly installAnchor?: string;
|
|
315
|
+
/** 官方运行器覆盖(测试注入)。 */
|
|
316
|
+
readonly runCommand?: PluginCommandRunner;
|
|
317
|
+
/** 试装执行器覆盖(测试注入金丝雀结论)。 */
|
|
318
|
+
readonly trial?: UpgradeTrialRunner;
|
|
319
|
+
/**
|
|
320
|
+
* 无头验证覆盖(测试注入"永远挂载成功/失败")。
|
|
321
|
+
*
|
|
322
|
+
* 为什么这条缝必须存在:金丝雀走**真试装引擎**时,它默认会真起一个 dsh 子进程
|
|
323
|
+
* (15s 超时、约 161 MiB)。单测要验的是"层栈激活"这条逻辑,不是启动器本身,
|
|
324
|
+
* 所以这里透传引擎既有的注入缝(envManager 的 TrialInstallOptions.verify)。
|
|
325
|
+
*/
|
|
326
|
+
readonly verify?: (name: string) => Promise<BootVerification>;
|
|
327
|
+
readonly fetch?: Fetcher;
|
|
328
|
+
readonly now?: () => number;
|
|
329
|
+
/** 清理日志回调(测试注入;生产写 <DSH_HOME>/dpmc-trial-cleanup.log)。 */
|
|
330
|
+
readonly log?: (line: string) => void;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* 走官方通道 `add <spec>`(升级与回滚都是它)。
|
|
334
|
+
*
|
|
335
|
+
* @param environment - 目标环境名。
|
|
336
|
+
* @param spec - 官方 spec(`name@version`、`link:...`、绝对路径…)。
|
|
337
|
+
* @param deps - 共享依赖。
|
|
338
|
+
* @returns 官方结果。
|
|
339
|
+
*/
|
|
340
|
+
export declare function runOfficialAdd(environment: string, spec: string, deps?: UpgradeEngineDeps): Promise<PackageResult>;
|
|
341
|
+
/**
|
|
342
|
+
* 一个包在这个环境里的盘上事实(升级前后各取一次,用来核对"真的变了吗")。
|
|
343
|
+
*
|
|
344
|
+
* @param environment - 环境名。
|
|
345
|
+
* @param name - 包名。
|
|
346
|
+
* @returns 面向用户的多行事实。
|
|
347
|
+
*/
|
|
348
|
+
export declare function installFacts(environment: string, name: string): readonly string[];
|
|
349
|
+
/** 金丝雀清理日志路径(与引擎的测试环境清理共用同一份日志与同一行格式)。 */
|
|
350
|
+
export declare function canaryLogPath(): string;
|
|
351
|
+
/**
|
|
352
|
+
* 金丝雀的"激活"证据:候选装完之后,测试环境的 `dsh.profile.bundles` 里到底有没有它。
|
|
353
|
+
*
|
|
354
|
+
* 为什么这条证据是金丝雀成立的前提(真机缺陷,task-80):官方 reconcile **跳过
|
|
355
|
+
* `beforeDeps` 里已有的依赖**,所以一个**已装插件的新版本**(正是升级场景)装进测试环境后
|
|
356
|
+
* 进不了层栈 → 挂载期从不加载它 → 坏候选也会被判 `passed`(假通过)。
|
|
357
|
+
* 因此"装上了"不等于"验证到了":只有层栈里真的出现它,这次启动验证才算数。
|
|
358
|
+
*/
|
|
359
|
+
export interface CanaryActivation {
|
|
360
|
+
/** 候选包名。 */
|
|
361
|
+
readonly name: string;
|
|
362
|
+
/** 装完候选后测试环境的层栈(读盘事实)。 */
|
|
363
|
+
readonly bundles: readonly string[];
|
|
364
|
+
/** 候选是否真的进了层栈(false = 挂载期不会加载它,这次验证不作数)。 */
|
|
365
|
+
readonly activated: boolean;
|
|
366
|
+
/** 是否为了让候选成为"新装"而先执行了官方 remove。 */
|
|
367
|
+
readonly removedFirst: boolean;
|
|
368
|
+
/** 那一步的结果说明(成功或失败都如实写)。 */
|
|
369
|
+
readonly removeNote: string;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* 跑一次金丝雀:在 `<环境>-dpmc` 里把**新版本**装进快照并跑基线/候选两次启动,然后立刻删掉测试环境。
|
|
373
|
+
*
|
|
374
|
+
* 四条纪律:
|
|
375
|
+
* 1. 复用 task-50/75 的试装引擎(含含 web 层环境读官方就绪行的那套形态),不另造验证器;
|
|
376
|
+
* 2. 候选要先成为"新装"(见 activationFor 的说明),否则升级场景下它永远进不了层栈,
|
|
377
|
+
* 金丝雀就退化成"什么都没验证";
|
|
378
|
+
* 3. `cannot-trial`(没验证)**不是** `passed`:调用方据此拒绝升级;
|
|
379
|
+
* 4. 测试环境是**一次性资产**:用完即删(不留 14 天),删不掉也如实说,并写清理日志。
|
|
380
|
+
*
|
|
381
|
+
* @param environment - 真实环境名。
|
|
382
|
+
* @param spec - 候选 spec(`name@version`)。
|
|
383
|
+
* @param config - 本插件配置(试装段决定深度/基线/联网)。
|
|
384
|
+
* @param deps - 共享依赖(试装执行器可注入)。
|
|
385
|
+
* @returns 金丝雀报告。
|
|
386
|
+
*/
|
|
387
|
+
export declare function runUpgradeCanary(environment: string, spec: string, config: CompanionConfig, deps?: UpgradeEngineDeps): Promise<UpgradeCanaryReport>;
|
|
388
|
+
/** 一次升级的入参。 */
|
|
389
|
+
export interface UpgradeActionInput extends UpgradeEngineDeps {
|
|
390
|
+
readonly environment: string;
|
|
391
|
+
readonly name: string;
|
|
392
|
+
/** 目标版本(来自检查结果的 targetVersion 或用户挑的 tag)。 */
|
|
393
|
+
readonly version: string;
|
|
394
|
+
readonly config: CompanionConfig;
|
|
395
|
+
/** 当前来源(用于判断"升级会改变来源")。 */
|
|
396
|
+
readonly spec?: string;
|
|
397
|
+
/** 显式跳过金丝雀(默认由试装总开关决定)。 */
|
|
398
|
+
readonly canary?: boolean;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* 升级一个已装包:金丝雀通过(或未做金丝雀)→ 官方 add → 盘上核对。
|
|
402
|
+
*
|
|
403
|
+
* 顺序不可颠倒:先验证再动真环境。金丝雀没通过(含 `cannot-trial`)就**不升级**,
|
|
404
|
+
* 并把试装结论原文作为原因返回——"没验证"绝不当成"通过"。
|
|
405
|
+
*
|
|
406
|
+
* @param input - 目标与依赖。
|
|
407
|
+
* @returns 结果(含 before/after 的盘上事实)。
|
|
408
|
+
*/
|
|
409
|
+
export declare function upgradePackage(input: UpgradeActionInput): Promise<UpgradeActionResult>;
|
|
410
|
+
/**
|
|
411
|
+
* 回滚一个包到指定版本(或回滚到原来的本地来源)。
|
|
412
|
+
*
|
|
413
|
+
* 核对按**盘上事实**:依赖行与 node_modules 里的版本都要对上才算干净;对不上就说对不上
|
|
414
|
+
* (沿用 task-23 的教训:不许声称"环境未被改动"而留下残留)。
|
|
415
|
+
*
|
|
416
|
+
* @param input - 目标与依赖。
|
|
417
|
+
* @returns 结果。
|
|
418
|
+
*/
|
|
419
|
+
export declare function rollbackUpgrade(input: UpgradeActionInput): Promise<UpgradeRollbackResult>;
|
|
420
|
+
/**
|
|
421
|
+
* 让某个包的版本事实失效(升级/回滚后必须重新取,不许拿旧事实当新状态)。
|
|
422
|
+
*
|
|
423
|
+
* 只删这一个包的条目,**不动**环境记账:记账说的是"这个环境什么时候查过",
|
|
424
|
+
* 那件事并没有因为一次升级而改变(升级成功只让**这个包**的版本事实过期)。
|
|
425
|
+
*
|
|
426
|
+
* @param name - 包名。
|
|
427
|
+
*/
|
|
428
|
+
export declare function invalidateTagsCache(name: string): void;
|