@michengai/dsh-automation 0.1.55 → 0.1.59
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/CHANGELOG.md +11 -0
- package/CHANGELOG.zh-CN.md +11 -0
- package/lib/client.js +33 -33
- package/lib/client.js.map +2 -2
- package/lib/index.js +131 -30
- package/lib/types/plugin-updater.d.ts +47 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -1655,8 +1655,8 @@ function emoji() {
|
|
|
1655
1655
|
}
|
|
1656
1656
|
var ipv4 = /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/;
|
|
1657
1657
|
var ipv6 = /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:))$/;
|
|
1658
|
-
var mac = (
|
|
1659
|
-
const escapedDelim = escapeRegex(
|
|
1658
|
+
var mac = (delimiter2) => {
|
|
1659
|
+
const escapedDelim = escapeRegex(delimiter2 ?? ":");
|
|
1660
1660
|
return new RegExp(`^(?:[0-9A-F]{2}${escapedDelim}){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}${escapedDelim}){5}[0-9a-f]{2}$`);
|
|
1661
1661
|
};
|
|
1662
1662
|
var cidrv4 = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/([0-9]|[1-2][0-9]|3[0-2])$/;
|
|
@@ -23336,7 +23336,7 @@ import { spawn } from "node:child_process";
|
|
|
23336
23336
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
23337
23337
|
import { readFile } from "node:fs/promises";
|
|
23338
23338
|
import { homedir as homedir2 } from "node:os";
|
|
23339
|
-
import { basename, dirname, isAbsolute, resolve } from "node:path";
|
|
23339
|
+
import { basename, delimiter, dirname, isAbsolute, resolve } from "node:path";
|
|
23340
23340
|
import { fileURLToPath } from "node:url";
|
|
23341
23341
|
var PLUGIN_UPDATE_HEADER = "x-michengai-plugin-update";
|
|
23342
23342
|
var PLUGIN_UPDATE_IPC = "apply-plugin-updates";
|
|
@@ -23353,9 +23353,16 @@ function isTrustedUpdateRequest(request) {
|
|
|
23353
23353
|
if (!isLoopbackAddress(request.socket?.remoteAddress)) return false;
|
|
23354
23354
|
const site = header(request, "sec-fetch-site");
|
|
23355
23355
|
if (site !== void 0 && site !== "same-origin") return false;
|
|
23356
|
-
const origin = header(request, "origin");
|
|
23357
23356
|
const host = header(request, "host");
|
|
23358
|
-
if (
|
|
23357
|
+
if (host === void 0 || host === "") return false;
|
|
23358
|
+
const origin = header(request, "origin");
|
|
23359
|
+
if (origin === void 0 || origin === "") {
|
|
23360
|
+
try {
|
|
23361
|
+
return isLoopbackAddress(new URL(`http://${host}`).hostname);
|
|
23362
|
+
} catch {
|
|
23363
|
+
return false;
|
|
23364
|
+
}
|
|
23365
|
+
}
|
|
23359
23366
|
try {
|
|
23360
23367
|
const url2 = new URL(origin);
|
|
23361
23368
|
return (url2.protocol === "http:" || url2.protocol === "https:") && isLoopbackAddress(url2.hostname) && url2.host === host;
|
|
@@ -23380,14 +23387,14 @@ function isDshCliEntry(entry, manifest, packageRoot) {
|
|
|
23380
23387
|
const bin = typeof value.bin === "string" ? value.bin : typeof value.bin === "object" && value.bin !== null ? value.bin.dsh : void 0;
|
|
23381
23388
|
return typeof bin === "string" && bin !== "" && !isAbsolute(bin) && resolve(packageRoot, bin) === resolve(entry);
|
|
23382
23389
|
}
|
|
23383
|
-
function cliEntry() {
|
|
23384
|
-
const value =
|
|
23390
|
+
function cliEntry(argv = process.argv, cwd = process.cwd(), exists = existsSync2) {
|
|
23391
|
+
const value = argv[1];
|
|
23385
23392
|
if (value === void 0 || value === "") return void 0;
|
|
23386
|
-
const entry = value.startsWith("file:") ? fileURLToPath(value) : resolve(
|
|
23387
|
-
if (!
|
|
23393
|
+
const entry = value.startsWith("file:") ? fileURLToPath(value) : resolve(cwd, value);
|
|
23394
|
+
if (!exists(entry)) return void 0;
|
|
23388
23395
|
for (let directory = dirname(entry); ; ) {
|
|
23389
23396
|
const manifestPath = resolve(directory, "package.json");
|
|
23390
|
-
if (
|
|
23397
|
+
if (exists(manifestPath)) {
|
|
23391
23398
|
try {
|
|
23392
23399
|
if (isDshCliEntry(entry, JSON.parse(readFileSync2(manifestPath, "utf8")), directory)) return entry;
|
|
23393
23400
|
} catch {
|
|
@@ -23398,21 +23405,75 @@ function cliEntry() {
|
|
|
23398
23405
|
directory = parent;
|
|
23399
23406
|
}
|
|
23400
23407
|
}
|
|
23401
|
-
function
|
|
23402
|
-
|
|
23403
|
-
|
|
23408
|
+
function optionalService(ctx, name2) {
|
|
23409
|
+
try {
|
|
23410
|
+
return typeof ctx.get === "function" ? ctx.get(name2) : void 0;
|
|
23411
|
+
} catch {
|
|
23412
|
+
return void 0;
|
|
23413
|
+
}
|
|
23414
|
+
}
|
|
23415
|
+
function isOfficialDesktopHostEntry(entry) {
|
|
23416
|
+
return entry !== void 0 && entry !== "" && entry.replaceAll("\\", "/").includes("/dsh-desktop-host/");
|
|
23417
|
+
}
|
|
23418
|
+
function stringEnvironment(value) {
|
|
23419
|
+
if (value === null || typeof value !== "object") return void 0;
|
|
23420
|
+
const env = {};
|
|
23421
|
+
for (const [key, item] of Object.entries(value)) if (typeof item === "string") env[key] = item;
|
|
23422
|
+
return Object.keys(env).length === 0 ? void 0 : env;
|
|
23423
|
+
}
|
|
23424
|
+
function packageManagerFrom(value) {
|
|
23425
|
+
if (value === null || typeof value !== "object") return void 0;
|
|
23426
|
+
const item = value;
|
|
23427
|
+
if (typeof item.command !== "string" || item.command === "") return void 0;
|
|
23428
|
+
if (!Array.isArray(item.args) || !item.args.every((arg) => typeof arg === "string")) return void 0;
|
|
23429
|
+
const env = stringEnvironment(item.env);
|
|
23430
|
+
return { command: item.command, args: item.args, ...env === void 0 ? {} : { env } };
|
|
23431
|
+
}
|
|
23432
|
+
function packageManagerFromArgv(argv, exists, execPath, pathEnv) {
|
|
23433
|
+
if (!isOfficialDesktopHostEntry(argv[1])) return void 0;
|
|
23434
|
+
const pnpm = argv[5];
|
|
23435
|
+
if (typeof pnpm !== "string" || !isAbsolute(pnpm) || !exists(pnpm)) return void 0;
|
|
23436
|
+
const bin = argv[6];
|
|
23437
|
+
const path = typeof bin === "string" && bin !== "" ? `${bin}${delimiter}${pathEnv ?? ""}` : pathEnv;
|
|
23438
|
+
return { command: execPath, args: ["--expose-internals", pnpm], env: { ELECTRON_RUN_AS_NODE: "1", ...typeof path === "string" && path !== "" ? { PATH: path } : {} } };
|
|
23439
|
+
}
|
|
23440
|
+
function pluginManagerFrom(value) {
|
|
23441
|
+
if (value === null || typeof value !== "object" || typeof value.installBundle !== "function") return void 0;
|
|
23442
|
+
return value;
|
|
23443
|
+
}
|
|
23444
|
+
function resolveUpdateRuntime(ctx, options = {}) {
|
|
23445
|
+
const argv = options.argv ?? process.argv;
|
|
23446
|
+
const env = options.env ?? process.env;
|
|
23447
|
+
const cwd = options.cwd ?? process.cwd();
|
|
23448
|
+
const home = options.homeDir ?? homedir2();
|
|
23449
|
+
const exists = options.exists ?? existsSync2;
|
|
23450
|
+
const execPath = options.execPath ?? process.execPath;
|
|
23451
|
+
const profiles = optionalService(ctx, "desktopProfiles");
|
|
23452
|
+
const desktopPnpm = optionalService(ctx, "desktopPnpm");
|
|
23404
23453
|
if (profiles?.current !== void 0) {
|
|
23405
23454
|
const current = profiles.current;
|
|
23406
|
-
if (!validProfileName(current
|
|
23407
|
-
|
|
23408
|
-
}
|
|
23409
|
-
|
|
23410
|
-
|
|
23411
|
-
const
|
|
23412
|
-
const
|
|
23413
|
-
const
|
|
23414
|
-
const
|
|
23415
|
-
|
|
23455
|
+
if (!validProfileName(current?.name) || typeof current.dir !== "string" || !isAbsolute(current.dir)) throw new Error("\u5F53\u524D Desktop Profile \u4FE1\u606F\u65E0\u6548\uFF0C\u8BF7\u91CD\u542F\u540E\u91CD\u8BD5\u3002");
|
|
23456
|
+
const runnable = typeof desktopPnpm?.runPlugin === "function";
|
|
23457
|
+
return { profileName: current.name, profileDir: resolve(current.dir), officialDesktop: false, canAutoUpdate: runnable, ...runnable ? { desktopPnpm } : {} };
|
|
23458
|
+
}
|
|
23459
|
+
const launched = optionalService(ctx, "profileContext");
|
|
23460
|
+
const official = isOfficialDesktopHostEntry(argv[1]) || launched?.name === "desktop";
|
|
23461
|
+
const launchedDir = typeof launched?.dir === "string" && isAbsolute(launched.dir) ? resolve(launched.dir) : void 0;
|
|
23462
|
+
const projectDir = official && typeof argv[3] === "string" && isAbsolute(argv[3]) ? resolve(argv[3]) : void 0;
|
|
23463
|
+
const cwdProfile = official && exists(resolve(cwd, "package.json")) ? resolve(cwd) : void 0;
|
|
23464
|
+
const profileDir = launchedDir ?? projectDir ?? cwdProfile ?? resolve(env.DSH_PROFILE_DIR ?? resolve(home, ".dsh", "profiles", "web"));
|
|
23465
|
+
const selected = profileNameFromArgv(argv);
|
|
23466
|
+
const profileName = validProfileName(launched?.name) ? launched.name : official ? "desktop" : validProfileName(selected) ? selected : validProfileName(basename(profileDir)) ? basename(profileDir) : "web";
|
|
23467
|
+
const packageManager = official ? packageManagerFrom(launched?.packageManager) ?? packageManagerFromArgv(argv, exists, execPath, env.PATH) : void 0;
|
|
23468
|
+
const pluginManager = official && packageManager === void 0 ? pluginManagerFrom(optionalService(ctx, "pluginManager")) : void 0;
|
|
23469
|
+
const entry = official ? void 0 : cliEntry(argv, cwd, exists);
|
|
23470
|
+
return { profileName, profileDir, officialDesktop: official, canAutoUpdate: packageManager !== void 0 || pluginManager !== void 0 || entry !== void 0, ...packageManager === void 0 ? {} : { packageManager }, ...pluginManager === void 0 ? {} : { pluginManager }, ...entry === void 0 ? {} : { cliEntry: entry } };
|
|
23471
|
+
}
|
|
23472
|
+
function shouldNotifyParent(target, send = process.send) {
|
|
23473
|
+
return target.officialDesktop !== true && target.desktopPnpm === void 0 && target.packageManager === void 0 && typeof send === "function";
|
|
23474
|
+
}
|
|
23475
|
+
function runtime(ctx) {
|
|
23476
|
+
return resolveUpdateRuntime(ctx);
|
|
23416
23477
|
}
|
|
23417
23478
|
function parseSemver(value) {
|
|
23418
23479
|
const match2 = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(value);
|
|
@@ -23478,7 +23539,7 @@ async function status(options, target) {
|
|
|
23478
23539
|
latestCheckFailed: latest === void 0,
|
|
23479
23540
|
updateAvailable: latest !== void 0 && isNewerVersion(current, latest),
|
|
23480
23541
|
profileName: target.profileName,
|
|
23481
|
-
canAutoUpdate: target.
|
|
23542
|
+
canAutoUpdate: target.canAutoUpdate
|
|
23482
23543
|
};
|
|
23483
23544
|
}
|
|
23484
23545
|
async function runCliInstall(target, packageSpec) {
|
|
@@ -23513,10 +23574,50 @@ async function runCliInstall(target, packageSpec) {
|
|
|
23513
23574
|
});
|
|
23514
23575
|
}
|
|
23515
23576
|
async function install(target, packageSpec) {
|
|
23516
|
-
if (target.desktopPnpm
|
|
23517
|
-
|
|
23518
|
-
|
|
23519
|
-
|
|
23577
|
+
if (target.desktopPnpm !== void 0) {
|
|
23578
|
+
const handle = target.desktopPnpm.runPlugin(["add", "--config.minimumReleaseAge=0", packageSpec, "--registry=https://registry.npmjs.org/"], target.profileDir);
|
|
23579
|
+
const result = await handle.done;
|
|
23580
|
+
if (result.exitCode !== 0) throw new Error(`\u66F4\u65B0\u8FDB\u7A0B\u9000\u51FA\u7801 ${String(result.exitCode)}\u3002`);
|
|
23581
|
+
return;
|
|
23582
|
+
}
|
|
23583
|
+
if (target.packageManager !== void 0) {
|
|
23584
|
+
const manager = target.packageManager;
|
|
23585
|
+
await new Promise((resolvePromise, reject) => {
|
|
23586
|
+
const child = spawn(manager.command, [...manager.args, "add", "--config.minimumReleaseAge=0", packageSpec, "--registry=https://registry.npmjs.org/"], {
|
|
23587
|
+
cwd: target.profileDir,
|
|
23588
|
+
windowsHide: true,
|
|
23589
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
23590
|
+
env: { ...process.env, ...manager.env, NO_COLOR: "1" }
|
|
23591
|
+
});
|
|
23592
|
+
let detail = "";
|
|
23593
|
+
child.stdout?.on("data", (chunk) => {
|
|
23594
|
+
detail = (detail + String(chunk)).slice(-4e3);
|
|
23595
|
+
});
|
|
23596
|
+
child.stderr?.on("data", (chunk) => {
|
|
23597
|
+
detail = (detail + String(chunk)).slice(-4e3);
|
|
23598
|
+
});
|
|
23599
|
+
const timer = setTimeout(() => {
|
|
23600
|
+
child.kill();
|
|
23601
|
+
reject(new Error("\u66F4\u65B0\u8D85\u65F6\uFF0C\u8BF7\u6539\u7528\u624B\u5DE5\u66F4\u65B0\u3002"));
|
|
23602
|
+
}, 10 * 6e4);
|
|
23603
|
+
child.once("error", (error51) => {
|
|
23604
|
+
clearTimeout(timer);
|
|
23605
|
+
reject(error51);
|
|
23606
|
+
});
|
|
23607
|
+
child.once("exit", (code) => {
|
|
23608
|
+
clearTimeout(timer);
|
|
23609
|
+
if (code === 0) resolvePromise();
|
|
23610
|
+
else reject(new Error(detail.trim() || `\u66F4\u65B0\u8FDB\u7A0B\u9000\u51FA\u7801 ${String(code)}`));
|
|
23611
|
+
});
|
|
23612
|
+
});
|
|
23613
|
+
return;
|
|
23614
|
+
}
|
|
23615
|
+
if (target.pluginManager !== void 0) {
|
|
23616
|
+
const result = await target.pluginManager.installBundle(packageSpec);
|
|
23617
|
+
if (result.application === "applied" || result.application === "restart-required" || result.application === "overridden") return;
|
|
23618
|
+
throw new Error(result.error?.message || result.packageResult?.output || "\u66F4\u65B0\u5931\u8D25\uFF0C\u8BF7\u67E5\u770B\u670D\u52A1\u7AEF\u65E5\u5FD7\u3002");
|
|
23619
|
+
}
|
|
23620
|
+
return runCliInstall(target, packageSpec);
|
|
23520
23621
|
}
|
|
23521
23622
|
function json3(response, statusCode, value) {
|
|
23522
23623
|
response.writeHead(statusCode, { "content-type": "application/json; charset=utf-8", "cache-control": "no-store" });
|
|
@@ -23569,9 +23670,9 @@ function registerPluginUpdater(ctx, options) {
|
|
|
23569
23670
|
} finally {
|
|
23570
23671
|
installing = false;
|
|
23571
23672
|
}
|
|
23572
|
-
const notifyParent = target
|
|
23673
|
+
const notifyParent = shouldNotifyParent(target);
|
|
23573
23674
|
const autoReload = target.desktopPnpm !== void 0 || notifyParent;
|
|
23574
|
-
json3(response, 200, { ...before, updatedVersion: before.latestVersion, restartRequired: true, autoReload });
|
|
23675
|
+
json3(response, 200, { ...before, updatedVersion: before.latestVersion, restartRequired: true, autoReload, ...target.officialDesktop ? { restartDesktop: true } : {} });
|
|
23575
23676
|
if (notifyParent) setTimeout(() => {
|
|
23576
23677
|
process.send?.(PLUGIN_UPDATE_IPC);
|
|
23577
23678
|
}, 150).unref?.();
|
|
@@ -9,13 +9,60 @@ type HostRequest = {
|
|
|
9
9
|
remoteAddress?: string;
|
|
10
10
|
};
|
|
11
11
|
};
|
|
12
|
+
type DesktopPnpmHandle = {
|
|
13
|
+
done: Promise<{
|
|
14
|
+
exitCode: number | null;
|
|
15
|
+
signal: NodeJS.Signals | null;
|
|
16
|
+
}>;
|
|
17
|
+
cancel(): void;
|
|
18
|
+
};
|
|
19
|
+
type DesktopPnpm = {
|
|
20
|
+
runPlugin(args: readonly string[], invokingDir: string, signal?: AbortSignal): DesktopPnpmHandle;
|
|
21
|
+
};
|
|
22
|
+
type PackageManagerLaunch = {
|
|
23
|
+
command: string;
|
|
24
|
+
args: readonly string[];
|
|
25
|
+
env?: NodeJS.ProcessEnv;
|
|
26
|
+
};
|
|
27
|
+
type PluginManagerInstall = {
|
|
28
|
+
installBundle(spec: string): Promise<{
|
|
29
|
+
application?: string;
|
|
30
|
+
error?: {
|
|
31
|
+
message?: string;
|
|
32
|
+
};
|
|
33
|
+
packageResult?: {
|
|
34
|
+
output?: string;
|
|
35
|
+
};
|
|
36
|
+
}>;
|
|
37
|
+
};
|
|
12
38
|
export type PluginUpdaterOptions = {
|
|
13
39
|
readonly endpoint: string;
|
|
14
40
|
readonly packageName: string;
|
|
15
41
|
readonly manifestUrl: URL;
|
|
16
42
|
};
|
|
43
|
+
type Runtime = {
|
|
44
|
+
profileName: string;
|
|
45
|
+
profileDir: string;
|
|
46
|
+
desktopPnpm?: DesktopPnpm;
|
|
47
|
+
cliEntry?: string;
|
|
48
|
+
packageManager?: PackageManagerLaunch;
|
|
49
|
+
pluginManager?: PluginManagerInstall;
|
|
50
|
+
officialDesktop: boolean;
|
|
51
|
+
canAutoUpdate: boolean;
|
|
52
|
+
};
|
|
17
53
|
export declare function isTrustedUpdateRequest(request: HostRequest): boolean;
|
|
18
54
|
export declare function isDshCliEntry(entry: string, manifest: unknown, packageRoot: string): boolean;
|
|
55
|
+
export declare function resolveUpdateRuntime(ctx: {
|
|
56
|
+
get?: (name: string) => unknown;
|
|
57
|
+
}, options?: {
|
|
58
|
+
argv?: readonly string[];
|
|
59
|
+
env?: NodeJS.ProcessEnv;
|
|
60
|
+
cwd?: string;
|
|
61
|
+
homeDir?: string;
|
|
62
|
+
exists?: (path: string) => boolean;
|
|
63
|
+
execPath?: string;
|
|
64
|
+
}): Runtime;
|
|
65
|
+
export declare function shouldNotifyParent(target: Runtime, send?: unknown): boolean;
|
|
19
66
|
export declare function isNewerVersion(currentValue: string, candidateValue: string): boolean;
|
|
20
67
|
export declare function registerPluginUpdater(ctx: Context, options: PluginUpdaterOptions): () => void;
|
|
21
68
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@michengai/dsh-automation",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.59",
|
|
4
4
|
"description": "DSH Automation — 在独立 DSH Session 中按计划执行和管理编码任务 · Schedule and manage coding tasks in isolated DSH sessions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@11.22.0",
|