dsh-opencode-palette 2.0.8 → 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.
@@ -1,351 +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/store.js
6
- // AUTO-GENERATED by node packages/dsh-plugin-update/build.mjs — DO NOT EDIT. Source: packages/dsh-plugin-update/src/store.ts
7
- import { createHash, randomUUID } from "node:crypto";
8
- import { mkdir, open, readFile, rename, realpath, stat, unlink, writeFile } from "node:fs/promises";
9
- import { dirname, isAbsolute, join, resolve } from "node:path";
10
- import { installRecipe } from "./commands.js";
11
- import { BACKUP_FILE, LEGACY_PLUGIN_ID, LOCK_FILE, STATE_FILE } from "./config.js";
12
- const LEGACY_SEGMENT = "updates";
13
- const LEGACY_DIR_PLUGIN = LEGACY_PLUGIN_ID;
14
- const JOB_STATES = ["installing", "verifying", "restart-required", "completed", "failed", "interrupted"];
15
- const SNAPSHOT_FILES = ["package.json", "pnpm-lock.yaml", "pnpm-workspace.yaml"];
16
- function fail(code) {
17
- return Object.assign(new Error(code), { code });
18
- }
19
- function shortHash(text) {
20
- try {
21
- return createHash("sha256").update(String(text)).digest("hex").slice(0, 24);
22
- } catch {
23
- return "00000000";
24
- }
25
- }
26
- function pathsForUpdate(homeDir, pluginId, profileDir) {
27
- if (typeof homeDir !== "string" || !homeDir || typeof profileDir !== "string" || !profileDir) return null;
28
- if (typeof pluginId !== "string" || !pluginId) return null;
29
- const directory = join(homeDir, LEGACY_SEGMENT, pluginId, shortHash(profileDir));
30
- return { directory, state: join(directory, STATE_FILE), lock: join(directory, LOCK_FILE), backup: join(directory, BACKUP_FILE) };
31
- }
32
- function legacyPathsForUpdate(homeDir, profileDir) {
33
- if (typeof homeDir !== "string" || !homeDir || typeof profileDir !== "string" || !profileDir) return null;
34
- const directory = join(homeDir, LEGACY_SEGMENT, LEGACY_DIR_PLUGIN, shortHash(profileDir));
35
- return { directory, state: join(directory, STATE_FILE), lock: join(directory, LOCK_FILE), backup: join(directory, BACKUP_FILE) };
36
- }
37
- async function readJsonGuarded(filename, missing) {
38
- try {
39
- if ((await stat(filename)).size > 10 * 1024 * 1024) throw fail("install-failed");
40
- return JSON.parse(await readFile(filename, "utf8"));
41
- } catch (error) {
42
- if (error && error.code === "ENOENT") return missing;
43
- throw error && error.code ? error : fail("install-failed");
44
- }
45
- }
46
- async function writeJsonAtomic(filename, value) {
47
- const temporary = `${filename}.${randomUUID()}.tmp`;
48
- try {
49
- await writeFile(temporary, `${JSON.stringify(value, null, 2)}
50
- `, { mode: 384, flag: "wx" });
51
- await rename(temporary, filename);
52
- } catch {
53
- throw fail("install-failed");
54
- } finally {
55
- await unlink(temporary).catch(() => {
56
- });
57
- }
58
- }
59
- function normalizeJob(job) {
60
- return {
61
- id: typeof job.id === "string" ? job.id : "corrupt",
62
- state: JOB_STATES.includes(String(job.state)) ? job.state : "interrupted",
63
- targetVersion: typeof job.targetVersion === "string" ? job.targetVersion : null,
64
- message: typeof job.message === "string" ? job.message : null,
65
- requestId: typeof job.requestId === "string" ? job.requestId : null
66
- };
67
- }
68
- function createUpdateDiskPorts(homeDir, pluginId, profileDir, deps = {}) {
69
- const paths = pathsForUpdate(homeDir, pluginId, profileDir);
70
- const legacyPaths = pluginId === LEGACY_DIR_PLUGIN ? null : legacyPathsForUpdate(homeDir, profileDir);
71
- const readText = deps.readFileImpl ?? ((filename, encoding) => readFile(filename, encoding));
72
- const statFile = deps.statImpl ?? ((filename) => stat(filename));
73
- async function readAt(p) {
74
- if (!p) return null;
75
- try {
76
- if ((await statFile(p.state)).size > 10 * 1024 * 1024) throw fail("install-failed");
77
- return JSON.parse(await readText(p.state, "utf8"));
78
- } catch (error) {
79
- if (error && error.code === "ENOENT") return null;
80
- throw error && error.code ? error : fail("install-failed");
81
- }
82
- }
83
- async function readJob() {
84
- if (!paths) return null;
85
- const job = await readAt(paths);
86
- if (job) {
87
- if (!JOB_STATES.includes(String(job.state)) || typeof job.id !== "string") {
88
- return { id: "corrupt", state: "interrupted", message: "recovery-required", targetVersion: null, requestId: null };
89
- }
90
- return { requestId: null, message: null, ...job };
91
- }
92
- if (legacyPaths) {
93
- const legacyJob = await readAt(legacyPaths);
94
- if (legacyJob) {
95
- if (!JOB_STATES.includes(String(legacyJob.state)) || typeof legacyJob.id !== "string") {
96
- return { id: "corrupt", state: "interrupted", message: "recovery-required", targetVersion: null, requestId: null };
97
- }
98
- return { requestId: null, message: null, ...legacyJob };
99
- }
100
- }
101
- const lock = await readJsonGuarded(paths.lock, null);
102
- if (lock) return { id: "locked", state: "interrupted", message: "recovery-required", targetVersion: null, requestId: null };
103
- if (legacyPaths) {
104
- const legacyLock = await readJsonGuarded(legacyPaths.lock, null).catch(() => null);
105
- if (legacyLock) return { id: "locked", state: "interrupted", message: "recovery-required", targetVersion: null, requestId: null };
106
- }
107
- return null;
108
- }
109
- async function writeJob(job) {
110
- if (!paths) throw fail("install-failed");
111
- if (job === null) {
112
- await unlink(paths.state).catch((error) => {
113
- if (!error || error.code !== "ENOENT") throw fail("install-failed");
114
- });
115
- return;
116
- }
117
- await mkdir(paths.directory, { recursive: true, mode: 448 });
118
- await writeJsonAtomic(paths.state, job);
119
- }
120
- async function tryAcquireLock(lockId) {
121
- if (!paths) return false;
122
- try {
123
- await mkdir(paths.directory, { recursive: true, mode: 448 });
124
- const handle = await open(paths.lock, "wx", 384);
125
- try {
126
- await handle.writeFile(JSON.stringify({ id: lockId, pid: process.pid, startedAt: Date.now() }));
127
- } finally {
128
- await handle.close();
129
- }
130
- return true;
131
- } catch (error) {
132
- if (!error || error.code !== "EEXIST") return false;
133
- try {
134
- const current = await readJsonGuarded(paths.lock, null);
135
- const job = await readJsonGuarded(paths.state, null);
136
- if (!current || job && job.id === current.id) return false;
137
- await unlink(paths.lock).catch(() => {
138
- });
139
- const handle = await open(paths.lock, "wx", 384);
140
- try {
141
- await handle.writeFile(JSON.stringify({ id: lockId, pid: process.pid, startedAt: Date.now() }));
142
- } finally {
143
- await handle.close();
144
- }
145
- return true;
146
- } catch {
147
- return false;
148
- }
149
- }
150
- }
151
- async function releaseLock(lockId) {
152
- if (!paths) return;
153
- try {
154
- const current = await readJsonGuarded(paths.lock, null);
155
- if (current && current.id === lockId) await unlink(paths.lock).catch(() => {
156
- });
157
- } catch {
158
- }
159
- }
160
- async function backupJob(job) {
161
- if (!paths) throw fail("install-failed");
162
- const files = {};
163
- for (const name of SNAPSHOT_FILES) {
164
- try {
165
- const filename = join(profileDir, name);
166
- if ((await stat(filename)).size > 3 * 1024 * 1024) throw fail("install-failed");
167
- files[name] = await readFile(filename, "utf8");
168
- } catch (error) {
169
- if (!error || error.code !== "ENOENT") throw fail("install-failed");
170
- }
171
- }
172
- await mkdir(paths.directory, { recursive: true, mode: 448 });
173
- await writeJsonAtomic(paths.backup, {
174
- jobId: job.id,
175
- previousVersion: job.previousVersion ?? null,
176
- files
177
- });
178
- }
179
- return { paths, legacyPaths, readJob, writeJob, tryAcquireLock, releaseLock, backupJob };
180
- }
181
- const CLI_PACKAGE_NAME = "@deepseek-ai/dsh";
182
- const INSTALL_STDIO = { stdin: "ignore", stdout: { maxBytes: 64 * 1024 }, stderr: { maxBytes: 64 * 1024 } };
183
- const TERMINATION_GRACE_MS = 3e3;
184
- function part(value) {
185
- return typeof value === "function" ? value() : value;
186
- }
187
- function withExit(error, exitCode) {
188
- if (typeof exitCode === "number") error.exitCode = exitCode;
189
- return error;
190
- }
191
- async function sameDir(a, b) {
192
- if (typeof a !== "string" || typeof b !== "string" || !a || !b) return false;
193
- try {
194
- if (resolve(a) === resolve(b)) return true;
195
- } catch {
196
- return false;
197
- }
198
- try {
199
- const pair = await Promise.all([realpath(a), realpath(b)]);
200
- return pair[0] === pair[1];
201
- } catch {
202
- return false;
203
- }
204
- }
205
- async function readManifestAt(directory) {
206
- try {
207
- return JSON.parse(await readFile(join(directory, "package.json"), "utf8"));
208
- } catch {
209
- return null;
210
- }
211
- }
212
- async function resolveCliEntry(argv1, deps = {}) {
213
- const readAt = typeof deps.readManifest === "function" ? deps.readManifest : readManifestAt;
214
- const realpathImpl = typeof deps.realpath === "function" ? deps.realpath : realpath;
215
- if (typeof argv1 !== "string" || !argv1 || argv1.includes("\0")) return null;
216
- let entry = "";
217
- try {
218
- entry = await realpathImpl(argv1);
219
- } catch {
220
- return null;
221
- }
222
- if (typeof entry !== "string" || !entry) return null;
223
- let directory = dirname(entry);
224
- while (true) {
225
- let manifest = null;
226
- try {
227
- manifest = await Promise.resolve().then(() => readAt(directory)).catch(() => null);
228
- } catch {
229
- manifest = null;
230
- }
231
- if (manifest && manifest.name === CLI_PACKAGE_NAME) {
232
- const bin = manifest.bin;
233
- const declared = typeof bin === "string" ? bin : bin && bin.dsh;
234
- if (typeof declared !== "string" || !declared || isAbsolute(declared) || declared.includes("\0")) return null;
235
- try {
236
- return await realpathImpl(resolve(directory, declared)) === entry ? entry : null;
237
- } catch {
238
- return null;
239
- }
240
- }
241
- const parent = dirname(directory);
242
- if (parent === directory) return null;
243
- directory = parent;
244
- }
245
- }
246
- async function awaitOutcome(handle, timeoutMs) {
247
- const settled = Promise.resolve(handle.done).then(
248
- (value) => ({ exitCode: value && typeof value.exitCode === "number" ? value.exitCode : null, timedOut: false }),
249
- () => ({ exitCode: null, timedOut: true })
250
- );
251
- if (!(typeof timeoutMs === "number" && timeoutMs > 0)) return await settled;
252
- let timer = null;
253
- const deadline = new Promise((settle) => {
254
- timer = setTimeout(() => {
255
- try {
256
- if (handle && typeof handle.terminate === "function") handle.terminate();
257
- } catch {
258
- }
259
- settle({ exitCode: null, timedOut: true });
260
- }, timeoutMs);
261
- });
262
- try {
263
- return await Promise.race([settled, deadline]);
264
- } finally {
265
- if (timer !== null) {
266
- try {
267
- clearTimeout(timer);
268
- } catch {
269
- }
270
- }
271
- }
272
- }
273
- function emitInstall(parts, recipe, ok, exitCode, durationMs) {
274
- const log = parts.log;
275
- if (typeof log !== "function") return;
276
- try {
277
- const pluginId = part(parts.pluginId ?? null);
278
- log("info", "update.install.exec", {
279
- route: recipe ? recipe.route : "none",
280
- ok: ok === true,
281
- exitCode: typeof exitCode === "number" ? exitCode : null,
282
- durationMs,
283
- pluginId: typeof pluginId === "string" ? pluginId : null
284
- });
285
- } catch {
286
- }
287
- }
288
- async function runDesktopService(recipe, parts) {
289
- const service = part(parts.desktopPnpm);
290
- if (!service || typeof service.runPlugin !== "function") throw fail("install-failed");
291
- const profiles = part(parts.desktopProfiles);
292
- const active = profiles && profiles.current ? profiles.current : null;
293
- const profileDir = part(parts.profileDir);
294
- if (!active || !active.dir || !profileDir || !await sameDir(active.dir, profileDir)) throw fail("install-failed");
295
- const handle = service.runPlugin(recipe.pluginArgs, profileDir, void 0);
296
- if (!handle || !handle.done || typeof handle.done.then !== "function") throw fail("install-failed");
297
- const outcome = await handle.done;
298
- const code = outcome && typeof outcome.exitCode === "number" ? outcome.exitCode : null;
299
- if (code !== 0) throw withExit(fail("install-failed"), code);
300
- return code;
301
- }
302
- async function runCliProcess(recipe, parts) {
303
- const executable = part(parts.runtimeExecutable) || (typeof process !== "undefined" ? process.execPath : "");
304
- const execArgs = part(parts.runtimeExecArgs) ?? (typeof process !== "undefined" && Array.isArray(process.execArgv) ? process.execArgv : []);
305
- const entry = part(parts.cliEntry) ?? await resolveCliEntry(typeof process !== "undefined" && process.argv ? process.argv[1] : "");
306
- if (!executable || !entry) throw fail("install-failed");
307
- const argv = [executable, ...execArgs, entry, "plugin", "--profile", recipe.profileName, ...recipe.pluginArgs];
308
- const subprocess = part(parts.subprocess);
309
- if (!subprocess || typeof subprocess.spawn !== "function") throw fail("install-failed");
310
- const handle = subprocess.spawn({
311
- argv,
312
- cwd: part(parts.profileDir) || void 0,
313
- stdio: INSTALL_STDIO,
314
- graceMs: TERMINATION_GRACE_MS
315
- });
316
- if (!handle || !handle.done || typeof handle.done.then !== "function") throw fail("install-failed");
317
- const outcome = await awaitOutcome(handle, recipe.timeoutMs);
318
- if (outcome.timedOut || outcome.exitCode !== 0) throw withExit(fail("install-failed"), outcome.exitCode);
319
- return outcome.exitCode;
320
- }
321
- function createUpdateExecutor(parts = {}) {
322
- return async function runInstall(args = {}) {
323
- const recipe = installRecipe({
324
- profileName: args.profileName ?? part(parts.profileName ?? null),
325
- version: String(args.version ?? ""),
326
- environmentKind: args.environmentKind ?? part(parts.environmentKind ?? "cli"),
327
- targetPackageName: parts.targetPackageName === void 0 ? void 0 : part(parts.targetPackageName),
328
- registryUrl: parts.registryUrl === void 0 ? void 0 : part(parts.registryUrl),
329
- timeoutMs: parts.installTimeoutMs === void 0 ? void 0 : part(parts.installTimeoutMs)
330
- });
331
- const startedAt = Date.now();
332
- let exitCode = null;
333
- try {
334
- if (!recipe) throw fail("install-failed");
335
- exitCode = recipe.route === "desktop-service" ? await runDesktopService(recipe, parts) : await runCliProcess(recipe, parts);
336
- emitInstall(parts, recipe, true, exitCode, Date.now() - startedAt);
337
- } catch (error) {
338
- emitInstall(parts, recipe, false, error?.exitCode ?? exitCode, Date.now() - startedAt);
339
- throw Object.assign(fail("install-failed"), { debug: String(error?.stack || error) });
340
- }
341
- };
342
- }
343
- const __executorInternals = { INSTALL_STDIO, TERMINATION_GRACE_MS, CLI_PACKAGE_NAME };
344
- export {
345
- __executorInternals,
346
- createUpdateDiskPorts,
347
- createUpdateExecutor,
348
- legacyPathsForUpdate,
349
- pathsForUpdate,
350
- resolveCliEntry
351
- };