dsh-opencode-palette 2.0.7 → 2.0.9
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/lib/client.js +18 -7
- package/lib/index.js +25 -14
- package/package.json +4 -2
- package/lib/vendor/dsh-plugin-update/client.js +0 -30
- package/lib/vendor/dsh-plugin-update/commands.js +0 -85
- package/lib/vendor/dsh-plugin-update/config.js +0 -102
- package/lib/vendor/dsh-plugin-update/gate.js +0 -120
- package/lib/vendor/dsh-plugin-update/host.js +0 -284
- package/lib/vendor/dsh-plugin-update/ports.js +0 -10
- package/lib/vendor/dsh-plugin-update/reader.js +0 -198
- package/lib/vendor/dsh-plugin-update/service.js +0 -360
- package/lib/vendor/dsh-plugin-update/store.js +0 -351
package/lib/client.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dsh-opencode-palette v2.0.
|
|
2
|
+
* dsh-opencode-palette v2.0.9 — 浏览器半(构建产物,勿手改)
|
|
3
3
|
* 数据驱动管线:opencode v1.18.12 官方主题 JSON → 颜色解析 → DSH 适配注入
|
|
4
|
-
* 面板「检查更新」:dsh-plugin-update
|
|
4
|
+
* 面板「检查更新」:dsh-plugin-update 客户端入口经构建期内联(宿主半走真依赖)
|
|
5
5
|
* 源:src/engine/* + runtime/*.mjs + npm 包 dsh-log / dsh-plugin-update 的客户端入口
|
|
6
6
|
*/
|
|
7
7
|
window.__ModuleLoader__.load({
|
|
@@ -12,7 +12,7 @@ window.__ModuleLoader__.load({
|
|
|
12
12
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" })
|
|
13
13
|
var __mods = {};
|
|
14
14
|
(function () {
|
|
15
|
-
// AUTO-GENERATED by node
|
|
15
|
+
// AUTO-GENERATED by node build.mjs — DO NOT EDIT. Source: src/config.ts
|
|
16
16
|
const DEFAULT_PREFIX = "wf";
|
|
17
17
|
const PHONE_ACTIONS = ["updateStatus", "updateCheck", "updateInstall"];
|
|
18
18
|
const DEFAULT_TARGET_PACKAGE = "dsh-mattpocock-skills-deck";
|
|
@@ -91,9 +91,10 @@ __mods["upd-config"] = { BACKUP_FILE, DEFAULT_CHECK_TIMEOUT_MS, DEFAULT_CONFIRMA
|
|
|
91
91
|
|
|
92
92
|
})();
|
|
93
93
|
(function () {
|
|
94
|
-
// AUTO-GENERATED by node
|
|
94
|
+
// AUTO-GENERATED by node build.mjs — DO NOT EDIT. Source: src/commands.ts
|
|
95
95
|
const PACKAGE_NAME = "dsh-mattpocock-skills-deck";
|
|
96
96
|
const NPM_REGISTRY = "https://registry.npmjs.org/";
|
|
97
|
+
const MANAGER_TARGET_RE = /^(?:@[a-z0-9][a-z0-9._~-]*\/)?[a-z0-9][a-z0-9._~-]*$/;
|
|
97
98
|
const INSTALL_TIMEOUT_MS = 15 * 6e4;
|
|
98
99
|
function validVersion(v) {
|
|
99
100
|
return typeof v === "string" && /^\d+\.\d+\.\d+$/.test(v);
|
|
@@ -132,11 +133,21 @@ function installRecipe(input) {
|
|
|
132
133
|
const version = input?.version;
|
|
133
134
|
if (!name || !validVersion(version)) return null;
|
|
134
135
|
const kind = input?.environmentKind;
|
|
135
|
-
if (kind !== "desktop" && kind !== "cli") return null;
|
|
136
|
+
if (kind !== "desktop" && kind !== "desktop-manager" && kind !== "cli") return null;
|
|
136
137
|
const targetName = input?.targetPackageName ?? PACKAGE_NAME;
|
|
137
138
|
const registry = input?.registryUrl ?? NPM_REGISTRY;
|
|
138
139
|
const timeoutMs = input?.timeoutMs ?? INSTALL_TIMEOUT_MS;
|
|
139
140
|
if (!targetName || !registry) return null;
|
|
141
|
+
if (kind === "desktop-manager") {
|
|
142
|
+
if (!MANAGER_TARGET_RE.test(targetName)) return null;
|
|
143
|
+
return {
|
|
144
|
+
route: "desktop-manager",
|
|
145
|
+
profileName: name,
|
|
146
|
+
version,
|
|
147
|
+
pluginArgs: ["add", `${targetName}@${version}`],
|
|
148
|
+
timeoutMs
|
|
149
|
+
};
|
|
150
|
+
}
|
|
140
151
|
return {
|
|
141
152
|
route: kind === "desktop" ? "desktop-service" : "cli-process",
|
|
142
153
|
profileName: name,
|
|
@@ -170,7 +181,7 @@ __mods["upd-commands"] = { INSTALL_TIMEOUT_MS, installRecipe, manualCommand };
|
|
|
170
181
|
|
|
171
182
|
})();
|
|
172
183
|
(function () {
|
|
173
|
-
// AUTO-GENERATED by node
|
|
184
|
+
// AUTO-GENERATED by node build.mjs — DO NOT EDIT. Source: src/client.ts
|
|
174
185
|
const { buildPhoneNames, DEFAULT_PANEL_POLL_MS, MIN_PANEL_POLL_MS } = __mods["upd-config"];
|
|
175
186
|
const { buildPhoneName, buildPhoneNames: buildPhoneNames2 } = __mods["upd-config"];
|
|
176
187
|
const { manualCommand: manualCommand2 } = __mods["upd-commands"];
|
|
@@ -10090,7 +10101,7 @@ const STORAGE_KEY = 'dsh.opencode-palette.v2'
|
|
|
10090
10101
|
const LEGACY_STORAGE_KEY = 'dsh.opencode-tui-theme.v2'
|
|
10091
10102
|
const DEFAULT_STATE = { enabled: true, theme: 'opencode', mode: 'mono', size: 13, fontKey: 'JetBrains Mono' }
|
|
10092
10103
|
// 构建时由 scripts/build-client.mjs 替换为 package.json 版本(面板底部署小字)
|
|
10093
|
-
const PALETTE_VERSION = '2.0.
|
|
10104
|
+
const PALETTE_VERSION = '2.0.9'
|
|
10094
10105
|
|
|
10095
10106
|
function getReact() {
|
|
10096
10107
|
if (typeof require === 'function') { try { return require('react') } catch (e) { /* 动态版无 require */ } }
|
package/lib/index.js
CHANGED
|
@@ -11,13 +11,12 @@
|
|
|
11
11
|
* 走 DSH 公开的 /api 载体:宿主 connection.fetch.register 注册精确路由,客户端
|
|
12
12
|
* connection.rpc.call('/api', 'opencode-palette', { method, payload })——与 deck、im-companion 同构。
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* vendor 副本由构建从 npm 包复制(见 scripts/build-client.mjs),门禁断言与 npm 包逐字节一致。
|
|
14
|
+
* 更新包以**普通依赖形态**接入(`import { createHostUpdate } from 'dsh-plugin-update'`,见 package.json
|
|
15
|
+
* 的 `dependencies`)。0.1.x 曾被迫把它的 dist vendor 进本包:那时它用 containingPackage(import.meta.url, …)
|
|
16
|
+
* 从【自己的文件位置】往上找目标包,以依赖形态安装时永远找不到本包 → unknown-profile,且
|
|
17
|
+
* sameLoadedPackage 恒假 → installation-changed → 一键升级永远不可用。
|
|
18
|
+
* 0.2.0 起改为**按包名解析**(清单直解 → 入口反查 → node_modules 步行 → 自锚定兜底),依赖形态直接可用,
|
|
19
|
+
* 于是 vendor 全部删除。历史决策与推翻过程见 docs/adr/0001-vendor-dsh-plugin-update.md。
|
|
21
20
|
*/
|
|
22
21
|
import { existsSync, readFileSync } from 'node:fs'
|
|
23
22
|
import { mkdir, readdir, readFile, unlink, writeFile } from 'node:fs/promises'
|
|
@@ -25,10 +24,12 @@ import { homedir } from 'node:os'
|
|
|
25
24
|
import { dirname, join } from 'node:path'
|
|
26
25
|
import { fileURLToPath } from 'node:url'
|
|
27
26
|
import { createHostLog, registerHostLogPhones } from 'dsh-log/host'
|
|
28
|
-
import { createHostUpdate } from '
|
|
29
|
-
import { buildPhoneNames, DEFAULT_REGISTRY } from './vendor/dsh-plugin-update/config.js'
|
|
27
|
+
import { createHostUpdate } from 'dsh-plugin-update'
|
|
30
28
|
import { PLUGIN_ID, PHONE_PREFIX, ROUTE_PATH, TARGET_PACKAGE_NAME } from './channel.mjs'
|
|
31
29
|
|
|
30
|
+
/** 官方源。更新包不导出这个常量(它的默认值也是它),探针自用,故本地声明一次。 */
|
|
31
|
+
const DEFAULT_REGISTRY = 'https://registry.npmjs.org/'
|
|
32
|
+
|
|
32
33
|
export const name = PLUGIN_ID
|
|
33
34
|
// 通道要 connection;subprocess / desktopProfiles / desktopPnpm 由更新包自己按需取(它内部注入),
|
|
34
35
|
// 不写进顶层 inject:普通 DSH 没有 desktop* 服务,写进顶层会让插件在普通宿主里装配失败。
|
|
@@ -295,8 +296,18 @@ export function wrapUpdateCheck(handler, deps) {
|
|
|
295
296
|
}
|
|
296
297
|
}
|
|
297
298
|
|
|
298
|
-
/** 宿主半装配入口:建日志库 → 建更新电话 → 合成电话表 → 注册通道。
|
|
299
|
-
|
|
299
|
+
/** 宿主半装配入口:建日志库 → 建更新电话 → 合成电话表 → 注册通道。
|
|
300
|
+
*
|
|
301
|
+
* 第二个参数只给测试用:`{ readerOverrides }` 会与默认的 `{ runningVersion }` 合并后
|
|
302
|
+
* 交给更新包。生产环境永远不传(更新包按包名自动解析目标包与使用范围);
|
|
303
|
+
* 只有自动解析对不上时(开发态 checkout、hoisted、多副本)才显式给
|
|
304
|
+
* `targetPackageDir`——更新包 README §6.13 的逃生口,冒烟测试用它搭假使用范围。
|
|
305
|
+
* 绝不传 `environmentKind` / `profileDir` / `profileName`:那两处会挡住自动探测,
|
|
306
|
+
* 传了升级就要改代码(更新包 README「升级本包」一节)。 */
|
|
307
|
+
export function apply(ctx, opts) {
|
|
308
|
+
const extraOverrides = (opts && opts.readerOverrides && typeof opts.readerOverrides === 'object')
|
|
309
|
+
? opts.readerOverrides
|
|
310
|
+
: {}
|
|
300
311
|
const homeDir = dshHomeDir(process.env, homedir())
|
|
301
312
|
const eventList = readEventList()
|
|
302
313
|
|
|
@@ -323,14 +334,14 @@ export function apply(ctx) {
|
|
|
323
334
|
}
|
|
324
335
|
|
|
325
336
|
const update = createHostUpdate(
|
|
326
|
-
{ ctx: ctx, logCtx: { fire: function (level, event, fields) { return hostLog.store.log(level, event, fields) } }, readerOverrides: { runningVersion: runningVersion } },
|
|
337
|
+
{ ctx: ctx, logCtx: { fire: function (level, event, fields) { return hostLog.store.log(level, event, fields) } }, readerOverrides: Object.assign({ runningVersion: runningVersion }, extraOverrides) },
|
|
327
338
|
{ pluginId: PLUGIN_ID, prefix: PHONE_PREFIX, targetPackageName: TARGET_PACKAGE_NAME }
|
|
328
339
|
)
|
|
329
340
|
for (const phoneName of Object.keys(update.handlers)) registry.set(phoneName, update.handlers[phoneName])
|
|
330
341
|
|
|
331
342
|
// 查更新外面再包一层:失败重试一次,仍失败就跑探针把真实原因落日志。
|
|
332
|
-
//
|
|
333
|
-
const updateCheckPhone =
|
|
343
|
+
// 电话名从更新包的返回值读(update.phoneNames),不自己拼字符串 —— 拼法与包内同一份真源。
|
|
344
|
+
const updateCheckPhone = update.phoneNames.updateCheck
|
|
334
345
|
const rawUpdateCheck = registry.get(updateCheckPhone)
|
|
335
346
|
if (typeof rawUpdateCheck === 'function') {
|
|
336
347
|
registry.set(updateCheckPhone, wrapUpdateCheck(rawUpdateCheck, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-opencode-palette",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.9",
|
|
4
4
|
"description": "让 DeepSeek Harness 穿上 38 款经典皮肤——东京的霓虹夜色、德古拉的暗红月光、复古工坊的暖黄灯火、黑客帝国的数字雨、玫瑰松林间的风……一键换肤,即点即换,重启不丢。38 legendary skins for DeepSeek Harness — tokyonight's neon dusk, dracula's crimson moon, gruvbox's retro glow, the matrix's digital rain, rose-pine's rosewood calm… one click, instant, persisted.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -33,9 +33,11 @@
|
|
|
33
33
|
"url": "https://github.com/FeatherHunter/dsh-opencode-palette/issues"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"dsh-log": "0.2.1"
|
|
36
|
+
"dsh-log": "0.2.1",
|
|
37
|
+
"dsh-plugin-update": "^0.2.0"
|
|
37
38
|
},
|
|
38
39
|
"engines": {
|
|
40
|
+
"node": ">=22",
|
|
39
41
|
"dsh": ">=0.2.0-rc.1"
|
|
40
42
|
},
|
|
41
43
|
"dsh": {
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
// 派生文件(构建生成,人手不改):由 npm 包 dsh-plugin-update@0.1.1 的 dist/ 原样复制。
|
|
2
|
-
// 为什么必须放进本包:更新包的读取器用 containingPackage(import.meta.url, 目标包名) 从自己的文件位置
|
|
3
|
-
// 往上找目标包;以 npm 依赖形态安装时它住在别的目录,会抛 unknown-profile 且环境判定恒为 installation-changed。
|
|
4
|
-
// 门禁:tests/update-panel.test.mjs 断言本副本与 npm 包逐字节一致(除本头部)。
|
|
5
|
-
// vendor-source: dsh-plugin-update@0.1.1 dist/client.js
|
|
6
|
-
// AUTO-GENERATED by node packages/dsh-plugin-update/build.mjs — DO NOT EDIT. Source: packages/dsh-plugin-update/src/client.ts
|
|
7
|
-
import { buildPhoneNames, DEFAULT_PANEL_POLL_MS, MIN_PANEL_POLL_MS } from "./config.js";
|
|
8
|
-
import { buildPhoneName, buildPhoneNames as buildPhoneNames2 } from "./config.js";
|
|
9
|
-
import { manualCommand as manualCommand2 } from "./commands.js";
|
|
10
|
-
const CLIENT_POLL = {
|
|
11
|
-
defaultMs: DEFAULT_PANEL_POLL_MS,
|
|
12
|
-
minMs: MIN_PANEL_POLL_MS
|
|
13
|
-
};
|
|
14
|
-
function buildClientPhoneNames(prefix) {
|
|
15
|
-
return buildPhoneNames(prefix);
|
|
16
|
-
}
|
|
17
|
-
function assertPollInterval(ms) {
|
|
18
|
-
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < MIN_PANEL_POLL_MS) {
|
|
19
|
-
throw new Error("[dsh-plugin-update] \u9762\u677F\u8F6E\u8BE2\u95F4\u9694\u975E\u6CD5\uFF1A\u4E0D\u5F97\u5C0F\u4E8E 250 \u6BEB\u79D2\uFF08\u6536\u5230 " + JSON.stringify(ms) + "\uFF09");
|
|
20
|
-
}
|
|
21
|
-
return ms;
|
|
22
|
-
}
|
|
23
|
-
export {
|
|
24
|
-
CLIENT_POLL,
|
|
25
|
-
assertPollInterval,
|
|
26
|
-
buildClientPhoneNames,
|
|
27
|
-
buildPhoneName,
|
|
28
|
-
buildPhoneNames2 as buildPhoneNames,
|
|
29
|
-
manualCommand2 as manualCommand
|
|
30
|
-
};
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
// 派生文件(构建生成,人手不改):由 npm 包 dsh-plugin-update@0.1.1 的 dist/ 原样复制。
|
|
2
|
-
// 为什么必须放进本包:更新包的读取器用 containingPackage(import.meta.url, 目标包名) 从自己的文件位置
|
|
3
|
-
// 往上找目标包;以 npm 依赖形态安装时它住在别的目录,会抛 unknown-profile 且环境判定恒为 installation-changed。
|
|
4
|
-
// 门禁:tests/update-panel.test.mjs 断言本副本与 npm 包逐字节一致(除本头部)。
|
|
5
|
-
// vendor-source: dsh-plugin-update@0.1.1 dist/commands.js
|
|
6
|
-
// AUTO-GENERATED by node packages/dsh-plugin-update/build.mjs — DO NOT EDIT. Source: packages/dsh-plugin-update/src/commands.ts
|
|
7
|
-
const PACKAGE_NAME = "dsh-mattpocock-skills-deck";
|
|
8
|
-
const NPM_REGISTRY = "https://registry.npmjs.org/";
|
|
9
|
-
const INSTALL_TIMEOUT_MS = 15 * 6e4;
|
|
10
|
-
function validVersion(v) {
|
|
11
|
-
return typeof v === "string" && /^\d+\.\d+\.\d+$/.test(v);
|
|
12
|
-
}
|
|
13
|
-
function parseTriple(v) {
|
|
14
|
-
const parts = String(v).split(".");
|
|
15
|
-
if (parts.length > 3) return null;
|
|
16
|
-
const nums = [];
|
|
17
|
-
for (const p of parts) {
|
|
18
|
-
if (!/^\d+$/.test(p)) return null;
|
|
19
|
-
const n = Number(p);
|
|
20
|
-
if (!Number.isSafeInteger(n)) return null;
|
|
21
|
-
nums.push(n);
|
|
22
|
-
}
|
|
23
|
-
while (nums.length < 3) nums.push(0);
|
|
24
|
-
return [nums[0], nums[1], nums[2]];
|
|
25
|
-
}
|
|
26
|
-
function compareVersions(a, b) {
|
|
27
|
-
const pa = parseTriple(a);
|
|
28
|
-
const pb = parseTriple(b);
|
|
29
|
-
if (!pa || !pb) throw new Error("invalid-release");
|
|
30
|
-
for (let i = 0; i < 3; i++) {
|
|
31
|
-
if (pa[i] < pb[i]) return -1;
|
|
32
|
-
if (pa[i] > pb[i]) return 1;
|
|
33
|
-
}
|
|
34
|
-
return 0;
|
|
35
|
-
}
|
|
36
|
-
function usableProfileName(raw) {
|
|
37
|
-
const name = typeof raw === "string" ? raw.trim() : "";
|
|
38
|
-
if (!name || name.length > 255 || name.startsWith("-")) return null;
|
|
39
|
-
if ([".", "..", "node_modules"].includes(name)) return null;
|
|
40
|
-
return name;
|
|
41
|
-
}
|
|
42
|
-
function installRecipe(input) {
|
|
43
|
-
const name = usableProfileName(input?.profileName);
|
|
44
|
-
const version = input?.version;
|
|
45
|
-
if (!name || !validVersion(version)) return null;
|
|
46
|
-
const kind = input?.environmentKind;
|
|
47
|
-
if (kind !== "desktop" && kind !== "cli") return null;
|
|
48
|
-
const targetName = input?.targetPackageName ?? PACKAGE_NAME;
|
|
49
|
-
const registry = input?.registryUrl ?? NPM_REGISTRY;
|
|
50
|
-
const timeoutMs = input?.timeoutMs ?? INSTALL_TIMEOUT_MS;
|
|
51
|
-
if (!targetName || !registry) return null;
|
|
52
|
-
return {
|
|
53
|
-
route: kind === "desktop" ? "desktop-service" : "cli-process",
|
|
54
|
-
profileName: name,
|
|
55
|
-
version,
|
|
56
|
-
// 参数数组原样交给命令行工具:使用范围名不做引号包裹、不按空格拆分。
|
|
57
|
-
pluginArgs: ["add", "--save-exact", `${targetName}@${version}`, `--registry=${registry}`],
|
|
58
|
-
timeoutMs
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
function manualCommand(input) {
|
|
62
|
-
if (input.sourceInstall || input.blockedReason === "source-install" || input.blockedReason === "unknown-profile") return null;
|
|
63
|
-
const name = usableProfileName(input.profileName);
|
|
64
|
-
if (!name) return null;
|
|
65
|
-
const targetName = input.targetPackageName ?? PACKAGE_NAME;
|
|
66
|
-
const registry = input.registryUrl ?? NPM_REGISTRY;
|
|
67
|
-
if (!targetName || !registry) return null;
|
|
68
|
-
const arg = /^[A-Za-z0-9_.-]+$/.test(name) ? name : JSON.stringify(name);
|
|
69
|
-
const picks = [input.latestVersion, input.jobTargetVersion, input.installedVersion].filter(validVersion);
|
|
70
|
-
let version = picks.length > 0 ? picks[0] : "latest";
|
|
71
|
-
try {
|
|
72
|
-
const ranked = picks.filter((v) => compareVersions(v, input.runningVersion) >= 0);
|
|
73
|
-
if (ranked.length > 0) {
|
|
74
|
-
version = ranked[0];
|
|
75
|
-
for (const v of ranked) if (compareVersions(v, version) === 1) version = v;
|
|
76
|
-
}
|
|
77
|
-
} catch {
|
|
78
|
-
}
|
|
79
|
-
return `dsh plugin --profile ${arg} add --save-exact ${targetName}@${version} --registry=${registry}`;
|
|
80
|
-
}
|
|
81
|
-
export {
|
|
82
|
-
INSTALL_TIMEOUT_MS,
|
|
83
|
-
installRecipe,
|
|
84
|
-
manualCommand
|
|
85
|
-
};
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
// 派生文件(构建生成,人手不改):由 npm 包 dsh-plugin-update@0.1.1 的 dist/ 原样复制。
|
|
2
|
-
// 为什么必须放进本包:更新包的读取器用 containingPackage(import.meta.url, 目标包名) 从自己的文件位置
|
|
3
|
-
// 往上找目标包;以 npm 依赖形态安装时它住在别的目录,会抛 unknown-profile 且环境判定恒为 installation-changed。
|
|
4
|
-
// 门禁:tests/update-panel.test.mjs 断言本副本与 npm 包逐字节一致(除本头部)。
|
|
5
|
-
// vendor-source: dsh-plugin-update@0.1.1 dist/config.js
|
|
6
|
-
// AUTO-GENERATED by node packages/dsh-plugin-update/build.mjs — DO NOT EDIT. Source: packages/dsh-plugin-update/src/config.ts
|
|
7
|
-
const DEFAULT_PREFIX = "wf";
|
|
8
|
-
const PHONE_ACTIONS = ["updateStatus", "updateCheck", "updateInstall"];
|
|
9
|
-
const DEFAULT_TARGET_PACKAGE = "dsh-mattpocock-skills-deck";
|
|
10
|
-
const DEFAULT_REGISTRY = "https://registry.npmjs.org/";
|
|
11
|
-
const LEGACY_PLUGIN_ID = "dsh-mattpocock-skills-deck";
|
|
12
|
-
const LEGACY_DIR_SEGMENT = "updates";
|
|
13
|
-
const STATE_FILE = "state.json";
|
|
14
|
-
const LOCK_FILE = "install.lock";
|
|
15
|
-
const BACKUP_FILE = "before.json";
|
|
16
|
-
const DEFAULT_CHECK_TIMEOUT_MS = 1e4;
|
|
17
|
-
const DEFAULT_CONFIRMATION_TTL_MS = 10 * 6e4;
|
|
18
|
-
const DEFAULT_INSTALL_TIMEOUT_MS = 15 * 6e4;
|
|
19
|
-
const DEFAULT_PANEL_POLL_MS = 1e3;
|
|
20
|
-
const RECHECK_WINDOW_MS = 2e3;
|
|
21
|
-
const MIN_PANEL_POLL_MS = 250;
|
|
22
|
-
function assertPluginId(value) {
|
|
23
|
-
if (typeof value !== "string" || value.length === 0) {
|
|
24
|
-
throw new Error("[dsh-plugin-update] \u63D2\u4EF6\u6807\u8BC6 pluginId \u5FC5\u586B\uFF1A\u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32\uFF08\u6536\u5230 " + JSON.stringify(value) + "\uFF09");
|
|
25
|
-
}
|
|
26
|
-
if (value.includes("/") || value.includes("\\") || value.includes("\0")) {
|
|
27
|
-
throw new Error("[dsh-plugin-update] \u63D2\u4EF6\u6807\u8BC6 pluginId \u975E\u6CD5\uFF1A\u4E0D\u5F97\u542B\u6709\u8DEF\u5F84\u5206\u9694\u7B26\uFF08\u6536\u5230 " + JSON.stringify(value) + "\uFF09");
|
|
28
|
-
}
|
|
29
|
-
return value;
|
|
30
|
-
}
|
|
31
|
-
function assertPrefix(value, role) {
|
|
32
|
-
if (typeof value !== "string" || value.length === 0) {
|
|
33
|
-
throw new Error("[dsh-plugin-update] " + role + " \u975E\u6CD5\uFF1A\u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32\uFF08\u6536\u5230 " + JSON.stringify(value) + "\uFF09");
|
|
34
|
-
}
|
|
35
|
-
if (value.includes(".") || value.includes("/") || value.includes("\\") || /\s/.test(value)) {
|
|
36
|
-
throw new Error("[dsh-plugin-update] " + role + " \u975E\u6CD5\uFF1A\u4E0D\u5F97\u542B\u6709\u70B9\u3001\u8DEF\u5F84\u5206\u9694\u7B26\u6216\u7A7A\u767D\uFF08\u6536\u5230 " + JSON.stringify(value) + "\uFF09");
|
|
37
|
-
}
|
|
38
|
-
return value;
|
|
39
|
-
}
|
|
40
|
-
function assertPositiveFinite(value, role) {
|
|
41
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
42
|
-
throw new Error("[dsh-plugin-update] " + role + " \u975E\u6CD5\uFF1A\u987B\u4E3A\u6709\u9650\u5927\u4E8E 0 \u7684\u6570\uFF08\u6536\u5230 " + JSON.stringify(value) + "\uFF09");
|
|
43
|
-
}
|
|
44
|
-
return value;
|
|
45
|
-
}
|
|
46
|
-
function resolveUpdateConfig(input) {
|
|
47
|
-
if (!input || typeof input !== "object") {
|
|
48
|
-
throw new Error("[dsh-plugin-update] \u5EFA\u66F4\u65B0\u80FD\u529B\u7F3A\u5C11\u914D\u7F6E\uFF1A\u63D2\u4EF6\u6807\u8BC6 pluginId \u5FC5\u586B");
|
|
49
|
-
}
|
|
50
|
-
const pluginId = assertPluginId(input.pluginId);
|
|
51
|
-
const prefix = input.prefix === void 0 ? DEFAULT_PREFIX : assertPrefix(input.prefix, "\u7535\u8BDD\u540D\u524D\u7F00 prefix");
|
|
52
|
-
const targetPackageName = input.targetPackageName === void 0 ? DEFAULT_TARGET_PACKAGE : String(input.targetPackageName);
|
|
53
|
-
if (!targetPackageName) {
|
|
54
|
-
throw new Error("[dsh-plugin-update] \u76EE\u6807\u5305\u540D targetPackageName \u975E\u6CD5\uFF1A\u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32");
|
|
55
|
-
}
|
|
56
|
-
const registryUrl = input.registryUrl === void 0 ? DEFAULT_REGISTRY : String(input.registryUrl);
|
|
57
|
-
if (!registryUrl) {
|
|
58
|
-
throw new Error("[dsh-plugin-update] \u5B98\u65B9\u6E90 registryUrl \u975E\u6CD5\uFF1A\u987B\u4E3A\u975E\u7A7A\u5B57\u7B26\u4E32");
|
|
59
|
-
}
|
|
60
|
-
const homeDir = input.homeDir === void 0 ? null : String(input.homeDir);
|
|
61
|
-
const checkTimeoutMs = input.checkTimeoutMs === void 0 ? DEFAULT_CHECK_TIMEOUT_MS : assertPositiveFinite(input.checkTimeoutMs, "\u8054\u7F51\u8D85\u65F6 checkTimeoutMs");
|
|
62
|
-
const confirmationTtlMs = input.confirmationTtlMs === void 0 ? DEFAULT_CONFIRMATION_TTL_MS : assertPositiveFinite(input.confirmationTtlMs, "\u51ED\u8BC1\u6709\u6548\u671F confirmationTtlMs");
|
|
63
|
-
const installTimeoutMs = input.installTimeoutMs === void 0 ? DEFAULT_INSTALL_TIMEOUT_MS : assertPositiveFinite(input.installTimeoutMs, "\u5B89\u88C5\u65F6\u9650 installTimeoutMs");
|
|
64
|
-
const panelPollMs = input.panelPollMs === void 0 ? DEFAULT_PANEL_POLL_MS : assertPositiveFinite(input.panelPollMs, "\u9762\u677F\u8F6E\u8BE2 panelPollMs");
|
|
65
|
-
if (panelPollMs < MIN_PANEL_POLL_MS) {
|
|
66
|
-
throw new Error("[dsh-plugin-update] \u9762\u677F\u8F6E\u8BE2 panelPollMs \u975E\u6CD5\uFF1A\u4E0D\u5F97\u5C0F\u4E8E 250 \u6BEB\u79D2\uFF08\u6536\u5230 " + JSON.stringify(input.panelPollMs) + "\uFF09");
|
|
67
|
-
}
|
|
68
|
-
return { pluginId, prefix, targetPackageName, registryUrl, homeDir, checkTimeoutMs, confirmationTtlMs, installTimeoutMs, panelPollMs };
|
|
69
|
-
}
|
|
70
|
-
function buildPhoneNames(prefix) {
|
|
71
|
-
const checked = assertPrefix(prefix, "\u7535\u8BDD\u540D\u524D\u7F00 prefix");
|
|
72
|
-
return {
|
|
73
|
-
updateStatus: checked + ".updateStatus",
|
|
74
|
-
updateCheck: checked + ".updateCheck",
|
|
75
|
-
updateInstall: checked + ".updateInstall"
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
function buildPhoneName(prefix, action) {
|
|
79
|
-
return buildPhoneNames(prefix)[action];
|
|
80
|
-
}
|
|
81
|
-
export {
|
|
82
|
-
BACKUP_FILE,
|
|
83
|
-
DEFAULT_CHECK_TIMEOUT_MS,
|
|
84
|
-
DEFAULT_CONFIRMATION_TTL_MS,
|
|
85
|
-
DEFAULT_INSTALL_TIMEOUT_MS,
|
|
86
|
-
DEFAULT_PANEL_POLL_MS,
|
|
87
|
-
DEFAULT_PREFIX,
|
|
88
|
-
DEFAULT_REGISTRY,
|
|
89
|
-
DEFAULT_TARGET_PACKAGE,
|
|
90
|
-
LEGACY_DIR_SEGMENT,
|
|
91
|
-
LEGACY_PLUGIN_ID,
|
|
92
|
-
LOCK_FILE,
|
|
93
|
-
MIN_PANEL_POLL_MS,
|
|
94
|
-
PHONE_ACTIONS,
|
|
95
|
-
RECHECK_WINDOW_MS,
|
|
96
|
-
STATE_FILE,
|
|
97
|
-
assertPluginId,
|
|
98
|
-
assertPrefix,
|
|
99
|
-
buildPhoneName,
|
|
100
|
-
buildPhoneNames,
|
|
101
|
-
resolveUpdateConfig
|
|
102
|
-
};
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// 派生文件(构建生成,人手不改):由 npm 包 dsh-plugin-update@0.1.1 的 dist/ 原样复制。
|
|
2
|
-
// 为什么必须放进本包:更新包的读取器用 containingPackage(import.meta.url, 目标包名) 从自己的文件位置
|
|
3
|
-
// 往上找目标包;以 npm 依赖形态安装时它住在别的目录,会抛 unknown-profile 且环境判定恒为 installation-changed。
|
|
4
|
-
// 门禁:tests/update-panel.test.mjs 断言本副本与 npm 包逐字节一致(除本头部)。
|
|
5
|
-
// vendor-source: dsh-plugin-update@0.1.1 dist/gate.js
|
|
6
|
-
// AUTO-GENERATED by node packages/dsh-plugin-update/build.mjs — DO NOT EDIT. Source: packages/dsh-plugin-update/src/gate.ts
|
|
7
|
-
import { assertPluginId } from "./config.js";
|
|
8
|
-
const EVENT_LEVELS = ["error", "warn", "info", "debug"];
|
|
9
|
-
const EVENT_KINDS = ["resident", "ondemand", "selfmon"];
|
|
10
|
-
function isNonEmptyString(value) {
|
|
11
|
-
return typeof value === "string" && value.length > 0;
|
|
12
|
-
}
|
|
13
|
-
function assertStringArray(value, what) {
|
|
14
|
-
if (!Array.isArray(value)) throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1A" + what + " \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4");
|
|
15
|
-
const seen = [];
|
|
16
|
-
for (const item of value) {
|
|
17
|
-
if (!isNonEmptyString(item)) throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1A" + what + " \u91CC\u6709\u7A7A\u5B57\u6BB5\u540D");
|
|
18
|
-
if (seen.indexOf(item) >= 0) throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1A" + what + " \u91CC\u5B57\u6BB5\u540D\u91CD\u590D\uFF1A" + item);
|
|
19
|
-
seen.push(item);
|
|
20
|
-
}
|
|
21
|
-
return seen;
|
|
22
|
-
}
|
|
23
|
-
function parseEventListManifest(value) {
|
|
24
|
-
if (typeof value === "string") {
|
|
25
|
-
throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1A\u8DEF\u5F84\u5F62\u5F0F\u8BF7\u8C03\u7528\u65B9\u81EA\u5DF1\u8BFB\u6210\u5BF9\u8C61\u518D\u4F20\u5165\uFF0C\u66F4\u65B0\u5305\u4E0D\u8BFB\u76D8");
|
|
26
|
-
}
|
|
27
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
28
|
-
throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1A\u53EA\u6536\u5BF9\u8C61\u5F62\u5F0F\uFF08\u7A7A\u6A21\u677F\u89C1\u5305\u5185\u7684 event-list.template.json\uFF09");
|
|
29
|
-
}
|
|
30
|
-
const input = value;
|
|
31
|
-
if (input["version"] !== 1) {
|
|
32
|
-
throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1Aversion \u73B0\u5728\u53EA\u8BA4 1\uFF08\u6536\u5230 " + JSON.stringify(input["version"]) + "\uFF09");
|
|
33
|
-
}
|
|
34
|
-
const pluginId = assertPluginId(input["pluginId"]);
|
|
35
|
-
const countsRaw = input["counts"];
|
|
36
|
-
if (!countsRaw || typeof countsRaw !== "object" || Array.isArray(countsRaw)) {
|
|
37
|
-
throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1Acounts \u5FC5\u987B\u662F\u542B\u4E09\u7C7B\u8BA1\u6570\u7684\u5BF9\u8C61");
|
|
38
|
-
}
|
|
39
|
-
const countsRecord = countsRaw;
|
|
40
|
-
const counts = { resident: 0, ondemand: 0, selfmon: 0 };
|
|
41
|
-
for (const kind of EVENT_KINDS) {
|
|
42
|
-
const n = countsRecord[kind];
|
|
43
|
-
if (typeof n !== "number" || !isFinite(n) || Math.floor(n) !== n || n < 0) {
|
|
44
|
-
throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1Acounts." + kind + " \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570");
|
|
45
|
-
}
|
|
46
|
-
counts[kind] = n;
|
|
47
|
-
}
|
|
48
|
-
const eventsRaw = input["events"];
|
|
49
|
-
if (!eventsRaw || typeof eventsRaw !== "object" || Array.isArray(eventsRaw)) {
|
|
50
|
-
throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1Aevents \u5FC5\u987B\u662F\u4E8B\u4EF6\u540D\u5230\u6761\u76EE\u7684\u5BF9\u8C61");
|
|
51
|
-
}
|
|
52
|
-
const events = {};
|
|
53
|
-
for (const name of Object.keys(eventsRaw)) {
|
|
54
|
-
events[name] = parseEventEntry(name, eventsRaw[name]);
|
|
55
|
-
}
|
|
56
|
-
return { version: 1, pluginId, counts, events };
|
|
57
|
-
}
|
|
58
|
-
function parseEventEntry(name, value) {
|
|
59
|
-
if (!isNonEmptyString(name)) throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1A\u4E8B\u4EF6\u540D\u4E0D\u80FD\u4E3A\u7A7A");
|
|
60
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
61
|
-
throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1A\u4E8B\u4EF6 " + name + " \u5FC5\u987B\u662F\u5BF9\u8C61");
|
|
62
|
-
}
|
|
63
|
-
const input = value;
|
|
64
|
-
if (EVENT_LEVELS.indexOf(input["level"]) < 0) {
|
|
65
|
-
throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1A\u4E8B\u4EF6 " + name + " \u7684 level \u53EA\u8BB8 error\u3001warn\u3001info\u3001debug");
|
|
66
|
-
}
|
|
67
|
-
if (EVENT_KINDS.indexOf(input["kind"]) < 0) {
|
|
68
|
-
throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1A\u4E8B\u4EF6 " + name + " \u7684 kind \u53EA\u8BB8 resident\u3001ondemand\u3001selfmon");
|
|
69
|
-
}
|
|
70
|
-
for (const key of Object.keys(input)) {
|
|
71
|
-
if (["level", "kind", "fields", "codes", "rules", "guard"].indexOf(key) < 0) {
|
|
72
|
-
throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1A\u4E8B\u4EF6 " + name + " \u6709\u4E0D\u8BA4\u8BC6\u7684\u952E " + key);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
const entry = {
|
|
76
|
-
level: input["level"],
|
|
77
|
-
kind: input["kind"],
|
|
78
|
-
fields: assertStringArray(input["fields"], "\u4E8B\u4EF6 " + name + " \u7684 fields")
|
|
79
|
-
};
|
|
80
|
-
if (input["codes"] !== void 0) entry.codes = assertStringArray(input["codes"], "\u4E8B\u4EF6 " + name + " \u7684 codes");
|
|
81
|
-
if (input["rules"] !== void 0) entry.rules = assertStringArray(input["rules"], "\u4E8B\u4EF6 " + name + " \u7684 rules");
|
|
82
|
-
if (input["guard"] !== void 0) {
|
|
83
|
-
if (typeof input["guard"] !== "string") {
|
|
84
|
-
throw new Error("[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355 eventList \u975E\u6CD5\uFF1A\u4E8B\u4EF6 " + name + " \u7684 guard \u5FC5\u987B\u662F\u5B57\u7B26\u4E32");
|
|
85
|
-
}
|
|
86
|
-
entry.guard = input["guard"];
|
|
87
|
-
}
|
|
88
|
-
return entry;
|
|
89
|
-
}
|
|
90
|
-
function checkEventFields(manifest, eventName, fieldNames) {
|
|
91
|
-
const entry = manifest.events[eventName];
|
|
92
|
-
if (!entry) return { ok: false, unknownEvent: true, unknownFields: [] };
|
|
93
|
-
const allowed = new Set(entry.fields);
|
|
94
|
-
const unknownFields = (Array.isArray(fieldNames) ? fieldNames : []).filter(
|
|
95
|
-
(field) => !allowed.has(field)
|
|
96
|
-
);
|
|
97
|
-
return { ok: unknownFields.length === 0, unknownEvent: false, unknownFields };
|
|
98
|
-
}
|
|
99
|
-
function checkEventCounts(manifest) {
|
|
100
|
-
const actual = { resident: 0, ondemand: 0, selfmon: 0 };
|
|
101
|
-
for (const name of Object.keys(manifest.events)) {
|
|
102
|
-
actual[manifest.events[name].kind] += 1;
|
|
103
|
-
}
|
|
104
|
-
const problems = [];
|
|
105
|
-
for (const kind of EVENT_KINDS) {
|
|
106
|
-
if (actual[kind] !== manifest.counts[kind]) {
|
|
107
|
-
problems.push(
|
|
108
|
-
"[dsh-plugin-update] \u4E8B\u4EF6\u6E05\u5355\u8BA1\u6570\u5BF9\u4E0D\u4E0A\uFF1A" + kind + " \u7C7B\u5B9E\u9645 " + actual[kind] + " \u6761\uFF0C\u6E05\u5355\u81EA\u62A5 " + manifest.counts[kind] + " \u6761"
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return { ok: problems.length === 0, problems };
|
|
113
|
-
}
|
|
114
|
-
export {
|
|
115
|
-
EVENT_KINDS,
|
|
116
|
-
EVENT_LEVELS,
|
|
117
|
-
checkEventCounts,
|
|
118
|
-
checkEventFields,
|
|
119
|
-
parseEventListManifest
|
|
120
|
-
};
|