@steinscheng/zhaotongkuan 0.8.9 → 0.8.10
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/README.md
CHANGED
|
@@ -17,6 +17,24 @@ npx @steinscheng/zhaotongkuan@latest install \
|
|
|
17
17
|
|
|
18
18
|
`--stop-after-check` 必须与 `--start` 同时使用;成功结果不会留下本地服务进程。
|
|
19
19
|
|
|
20
|
+
已有安装可直接使用同一个 npm 引导器升级,无需手动准备 ZIP 或 SHA-256:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx @steinscheng/zhaotongkuan@latest update --start --json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`update` 会读取标准安装目录中的 `config/installation.json`,复用原来的业务数据目录和安装根目录,并把经过内置 SHA-256 校验的发行包交给同一事务安装器。若原安装使用了自定义目录,请显式传入 `--data-dir`,必要时同时传入 `--install-root`:
|
|
27
|
+
|
|
28
|
+
```powershell
|
|
29
|
+
npx @steinscheng/zhaotongkuan@latest update `
|
|
30
|
+
--data-dir "C:\Users\Alice\AppData\Local\找同款" `
|
|
31
|
+
--install-root "C:\Users\Alice\AppData\Local\找同款\installation" `
|
|
32
|
+
--start `
|
|
33
|
+
--json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
更新前应停止正在运行的任务。更新器不会切换数据目录、不会删除激活或浏览器资料;更新失败会返回 JSON 并回滚。`update` 不支持找不到安装记录的全新机器,此时使用 `install`。
|
|
37
|
+
|
|
20
38
|
私有 GitHub Release 会优先使用已登录的 `gh` CLI 下载;引导器不读取、保存或输出 GitHub Token。也可以安装发行方通过其他可信渠道交付的本地 ZIP:
|
|
21
39
|
|
|
22
40
|
```bash
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { createReadStream, createWriteStream, existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
3
3
|
import { copyFile, lstat, mkdir, realpath } from "node:fs/promises";
|
|
4
4
|
import { get as httpsGet } from "node:https";
|
|
5
|
-
import { tmpdir } from "node:os";
|
|
5
|
+
import { homedir, tmpdir } from "node:os";
|
|
6
6
|
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import { spawnSync } from "node:child_process";
|
|
@@ -126,6 +126,43 @@ export function parseArgs(argv) {
|
|
|
126
126
|
return result;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
function defaultDataDir(platform = process.platform, env = process.env) {
|
|
130
|
+
const configured = String(env.ZTK_DATA_DIR || "").trim();
|
|
131
|
+
if (configured) return resolve(configured);
|
|
132
|
+
if (platform === "win32") {
|
|
133
|
+
return resolve(env.LOCALAPPDATA || join(homedir(), "AppData", "Local"), "找同款");
|
|
134
|
+
}
|
|
135
|
+
if (platform === "darwin") return resolve(join(homedir(), "Library", "Application Support", "找同款"));
|
|
136
|
+
return resolve(env.XDG_DATA_HOME || join(homedir(), ".local", "share"), "zhaotongkuan");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function discoverExistingInstall(options, platform = process.platform, env = process.env) {
|
|
140
|
+
const requestedDataDir = options.dataDir ? resolve(options.dataDir) : defaultDataDir(platform, env);
|
|
141
|
+
const installRoot = resolve(options.installRoot || join(requestedDataDir, "installation"));
|
|
142
|
+
const pluginRoot = join(installRoot, "plugins", "zhaotongkuan");
|
|
143
|
+
const configPath = join(pluginRoot, "config", "installation.json");
|
|
144
|
+
if (!existsSync(configPath)) {
|
|
145
|
+
throw new BootstrapError(
|
|
146
|
+
"could not find an existing managed installation; pass --data-dir and --install-root if it uses custom paths",
|
|
147
|
+
"existing_installation_missing",
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
let config;
|
|
151
|
+
try {
|
|
152
|
+
config = JSON.parse(readFileSync(configPath, "utf8"));
|
|
153
|
+
} catch {
|
|
154
|
+
throw new BootstrapError("existing installation metadata is invalid", "existing_installation_invalid");
|
|
155
|
+
}
|
|
156
|
+
const recordedDataDir = config && typeof config.data_dir === "string" ? resolve(config.data_dir) : null;
|
|
157
|
+
if (!recordedDataDir) {
|
|
158
|
+
throw new BootstrapError("existing installation metadata has no valid data directory", "existing_installation_invalid");
|
|
159
|
+
}
|
|
160
|
+
if (options.dataDir && requestedDataDir !== recordedDataDir) {
|
|
161
|
+
throw new BootstrapError("--data-dir does not match the existing installation", "data_dir_mismatch");
|
|
162
|
+
}
|
|
163
|
+
return { dataDir: recordedDataDir, installRoot };
|
|
164
|
+
}
|
|
165
|
+
|
|
129
166
|
export function loadChannel() {
|
|
130
167
|
const channel = JSON.parse(readFileSync(CHANNEL_PATH, "utf8"));
|
|
131
168
|
if (channel.schema_version !== 1 || !channel.repository || !channel.version) {
|
|
@@ -371,7 +408,7 @@ export function sanitizeForJson(value, key = "", depth = 0) {
|
|
|
371
408
|
}
|
|
372
409
|
|
|
373
410
|
function help() {
|
|
374
|
-
return `Usage:\n npx @steinscheng/zhaotongkuan@latest install [options]\n\nSupported hosts:\n Windows, macOS, or Linux on x64/arm64\n\nOptions:\n --archive <path-or-https-url> Install an explicit release archive\n --expected-sha256 <digest> Trusted SHA-256 (required with --archive)\n --dry-run Validate without writing\n --start Start and health-check the service\n --stop-after-check Stop after a successful startup health check\n --data-dir <path> Preserve business data outside the program\n --install-root <path> Override managed program directory\n --codex-bin <path> Use an explicit Codex CLI\n --python <path> Use an explicit Python 3.10+ executable\n --json Emit one JSON object\n`;
|
|
411
|
+
return `Usage:\n npx @steinscheng/zhaotongkuan@latest install [options]\n npx @steinscheng/zhaotongkuan@latest update [options]\n\nSupported hosts:\n Windows, macOS, or Linux on x64/arm64\n\nOptions:\n --archive <path-or-https-url> Install an explicit release archive\n --expected-sha256 <digest> Trusted SHA-256 (required with --archive)\n --dry-run Validate without writing\n --start Start and health-check the service\n --stop-after-check Stop after a successful startup health check\n --data-dir <path> Preserve business data outside the program\n --install-root <path> Override managed program directory\n --codex-bin <path> Use an explicit Codex CLI\n --python <path> Use an explicit Python 3.10+ executable\n --json Emit one JSON object\n\nThe update command discovers the existing managed installation and reuses its data directory and install root.\n`;
|
|
375
412
|
}
|
|
376
413
|
|
|
377
414
|
function emitError(error, jsonMode) {
|
|
@@ -403,7 +440,13 @@ export async function main(argv) {
|
|
|
403
440
|
process.stdout.write(`${PACKAGE_JSON.version}\n`);
|
|
404
441
|
return 0;
|
|
405
442
|
}
|
|
406
|
-
if (
|
|
443
|
+
if (!["install", "update"].includes(options.command)) {
|
|
444
|
+
throw new BootstrapError(`unknown command: ${options.command}`, "invalid_argument");
|
|
445
|
+
}
|
|
446
|
+
if (options.command === "update") {
|
|
447
|
+
const existing = discoverExistingInstall(options);
|
|
448
|
+
options = { ...options, ...existing };
|
|
449
|
+
}
|
|
407
450
|
|
|
408
451
|
const release = resolveRelease(options);
|
|
409
452
|
const python = findPython(options.python);
|
|
@@ -446,6 +489,7 @@ export async function main(argv) {
|
|
|
446
489
|
release_version: release.version,
|
|
447
490
|
target: `${release.target.platform}-${release.target.arch}`,
|
|
448
491
|
checksum_verified: true,
|
|
492
|
+
operation: options.command,
|
|
449
493
|
},
|
|
450
494
|
};
|
|
451
495
|
process.stdout.write(`${JSON.stringify(output)}\n`);
|
package/src/release-channel.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": 1,
|
|
3
3
|
"repository": "SchengSteins/zhaotongkuan",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.10",
|
|
5
5
|
"artifacts": {
|
|
6
6
|
"any": {
|
|
7
|
-
"url": "https://github.com/SchengSteins/zhaotongkuan/releases/download/v0.8.
|
|
8
|
-
"sha256": "
|
|
7
|
+
"url": "https://github.com/SchengSteins/zhaotongkuan/releases/download/v0.8.10/zhaotongkuan-0.8.10.zip",
|
|
8
|
+
"sha256": "22dc69e85afd4cc475663cc9b45b8bdcb7615d28d15796a0c789205f9856452f"
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
}
|
|
index a1f341a..c109526 100644
|
|
|
Binary file
|