pier-setup 0.2.1 → 0.2.2
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 +15 -5
- package/install.mjs +171 -8
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -46,24 +46,34 @@ pier ships as **two halves**, installed separately:
|
|
|
46
46
|
No clone needed — run the npm package directly:
|
|
47
47
|
|
|
48
48
|
```sh
|
|
49
|
-
npx pier-setup # user mode: pi install npm:pi-pier + herdr plugin install
|
|
50
|
-
|
|
49
|
+
npx pier-setup@latest # user mode: pi install npm:pi-pier + herdr plugin install
|
|
50
|
+
npx pier-setup@latest version # local vs npm latest (installer / pi-pier / herdr plugin)
|
|
51
|
+
npx pier-setup@latest update # refresh both halves in place (does not uninstall first)
|
|
52
|
+
npx pier-setup@latest uninstall # --purge also drops boot-config.json
|
|
53
|
+
|
|
54
|
+
npm i -g pier-setup # or install globally, then: pier-setup / version / update
|
|
51
55
|
```
|
|
52
56
|
|
|
57
|
+
Pin `@latest` so npx does not reuse a cached installer. In a clone, `npm install`
|
|
58
|
+
links `node_modules/.bin/pier-setup`, so in-repo `npx pier-setup` runs `./install.mjs`.
|
|
59
|
+
|
|
53
60
|
Dev mode still requires cloning the repo:
|
|
54
61
|
|
|
55
62
|
```sh
|
|
56
63
|
git clone https://github.com/July24/pier && cd pier
|
|
57
64
|
node install.mjs install --dev # local-path pi install + herdr plugin link; code changes are live
|
|
65
|
+
node install.mjs version --dev
|
|
66
|
+
node install.mjs update --dev # rewrite boot-config only; pull the repo yourself
|
|
58
67
|
```
|
|
59
68
|
|
|
60
69
|
The script verifies the environment (node / pi / herdr versions), probes pi's node
|
|
61
70
|
and cli.js absolute paths, generates boot-config.json (user mode stores it in the
|
|
62
71
|
herdr plugin config dir, so reinstalls don't lose it), and registers both halves.
|
|
63
72
|
|
|
64
|
-
|
|
65
|
-
`
|
|
66
|
-
`--pi-spec=` / `--herdr-spec=` (npm publishing or forks).
|
|
73
|
+
`update` re-runs `pi update npm:pi-pier` (falls back to `pi install`) and
|
|
74
|
+
`herdr plugin install … --yes`, then rewrites boot-config. Override sources with
|
|
75
|
+
`--pi-spec=` / `--herdr-spec=` (npm publishing or forks). `pier-setup --help`
|
|
76
|
+
lists every command.
|
|
67
77
|
|
|
68
78
|
### Manual install (equivalent steps)
|
|
69
79
|
|
package/install.mjs
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* pier
|
|
3
|
+
* pier 一键安装/卸载/更新/查版本(跨平台:macOS / Linux / Windows)。
|
|
4
4
|
*
|
|
5
5
|
* 用法:
|
|
6
6
|
* node install.mjs install [--dev] [--hmr-dev] [--force] # 安装(默认命令,可省略 install)
|
|
7
|
+
* node install.mjs update [--dev] [--hmr-dev] # 原地刷新两半区到最新发行(不先卸载)
|
|
8
|
+
* node install.mjs version [--json] # 本地 vs npm latest
|
|
7
9
|
* node install.mjs uninstall [--dev] [--purge] # 卸载;--purge 连 boot-config.json 一起删
|
|
8
|
-
* node install.mjs
|
|
10
|
+
* node install.mjs --prepare # npm prepare:hooksPath + 仓库根 bin 链接
|
|
11
|
+
* node install.mjs --help
|
|
9
12
|
*
|
|
10
13
|
* 模式:
|
|
11
14
|
* 用户模式(默认):pi install npm:pi-pier
|
|
@@ -18,7 +21,7 @@
|
|
|
18
21
|
* 失败语义:每步给出手动等价命令;步骤失败不阻断报告(exitCode=1)。
|
|
19
22
|
*/
|
|
20
23
|
import { execFileSync } from 'node:child_process';
|
|
21
|
-
import { existsSync, mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
|
|
24
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, realpathSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
22
25
|
import { homedir } from 'node:os';
|
|
23
26
|
import { dirname, join, resolve } from 'node:path';
|
|
24
27
|
import { fileURLToPath } from 'node:url';
|
|
@@ -29,10 +32,38 @@ const WB_DIR = join(ROOT, 'packages', 'pier-workbench');
|
|
|
29
32
|
const DEV_BOOT_CONFIG = join(WB_DIR, 'scripts', 'boot-config.json');
|
|
30
33
|
const EXT_PATH = join(EXT_DIR, 'src', 'index.ts');
|
|
31
34
|
const IS_WIN = process.platform === 'win32';
|
|
35
|
+
const COMMANDS = ['install', 'uninstall', 'update', 'version', 'help'];
|
|
36
|
+
|
|
37
|
+
/** Workspace root is named pier-setup but npm does not bin-link it, so
|
|
38
|
+
* `npx pier-setup@version` from the clone runs `sh -c pier-setup` against a
|
|
39
|
+
* missing node_modules/.bin/pier-setup. Published tarball has no packages/. */
|
|
40
|
+
function prepareRepo() {
|
|
41
|
+
if (existsSync(join(ROOT, '.githooks'))) {
|
|
42
|
+
try { execFileSync('git', ['config', 'core.hooksPath', '.githooks'], { stdio: 'ignore' }); } catch { /* not a git checkout */ }
|
|
43
|
+
}
|
|
44
|
+
if (!existsSync(EXT_PATH)) return;
|
|
45
|
+
const binDir = join(ROOT, 'node_modules', '.bin');
|
|
46
|
+
mkdirSync(binDir, { recursive: true });
|
|
47
|
+
const posix = join(binDir, 'pier-setup');
|
|
48
|
+
const cmd = join(binDir, 'pier-setup.cmd');
|
|
49
|
+
rmSync(posix, { force: true });
|
|
50
|
+
rmSync(cmd, { force: true });
|
|
51
|
+
if (IS_WIN) {
|
|
52
|
+
writeFileSync(cmd, '@echo off\r\nnode "%~dp0\\..\\..\\install.mjs" %*\r\n');
|
|
53
|
+
writeFileSync(posix, '#!/bin/sh\nexec node "$(dirname "$0")/../../install.mjs" "$@"\n');
|
|
54
|
+
try { chmodSync(posix, 0o755); } catch { /* git-bash optional */ }
|
|
55
|
+
} else {
|
|
56
|
+
symlinkSync('../../install.mjs', posix);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
32
59
|
|
|
33
60
|
const argv = process.argv.slice(2);
|
|
34
|
-
|
|
35
|
-
|
|
61
|
+
if (argv[0] === '--prepare') {
|
|
62
|
+
prepareRepo();
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
const command = COMMANDS.includes(argv[0]) ? argv.shift() : null;
|
|
66
|
+
const flags = new Set(argv.filter((a) => (a.startsWith('--') && !a.includes('=')) || a === '-h' || a === '-v'));
|
|
36
67
|
const optValue = (name) => argv.find((a) => a.startsWith(`--${name}=`))?.split('=').slice(1).join('=') ?? null;
|
|
37
68
|
const dev = flags.has('--dev');
|
|
38
69
|
const PI_SPEC = optValue('pi-spec') ?? 'npm:pi-pier'; // 用户模式默认 npm 发行版;--pi-spec=git:github.com/July24/pier 可跟随仓库 main
|
|
@@ -75,6 +106,34 @@ function geVersion(v, min) {
|
|
|
75
106
|
return true;
|
|
76
107
|
}
|
|
77
108
|
|
|
109
|
+
function cmpSemver(a, b) {
|
|
110
|
+
const pa = parseVersion(a);
|
|
111
|
+
const pb = parseVersion(b);
|
|
112
|
+
if (!pa || !pb) return 0;
|
|
113
|
+
for (let i = 0; i < 3; i++) {
|
|
114
|
+
if (pa[i] !== pb[i]) return pa[i] < pb[i] ? -1 : 1;
|
|
115
|
+
}
|
|
116
|
+
return 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function readPkgVersion(dir) {
|
|
120
|
+
try {
|
|
121
|
+
return JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')).version ?? null;
|
|
122
|
+
} catch {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function npmLatest(name) {
|
|
128
|
+
try {
|
|
129
|
+
return execFileSync('npm', ['view', name, 'version'], {
|
|
130
|
+
encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 15000,
|
|
131
|
+
}).trim();
|
|
132
|
+
} catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
78
137
|
/** herdr 插件配置目录(用户模式 boot-config 落点;插件已注册才存在路径语义)。 */
|
|
79
138
|
function herdrConfigDir() {
|
|
80
139
|
try { return run('herdr', ['plugin', 'config-dir', 'pier.workbench']); } catch { return null; }
|
|
@@ -217,7 +276,109 @@ function writeBootConfig(hmrDev, force) {
|
|
|
217
276
|
log(` extPath = ${config.extPath}`);
|
|
218
277
|
}
|
|
219
278
|
|
|
220
|
-
|
|
279
|
+
function pkgDirFromExtPath(extPath) {
|
|
280
|
+
let d = dirname(extPath);
|
|
281
|
+
for (let i = 0; i < 5; i++) {
|
|
282
|
+
if (existsSync(join(d, 'package.json'))) return d;
|
|
283
|
+
const parent = dirname(d);
|
|
284
|
+
if (parent === d) break;
|
|
285
|
+
d = parent;
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function herdrPluginInfo() {
|
|
291
|
+
let out;
|
|
292
|
+
try { out = run('herdr', ['plugin', 'list']); } catch { return { installed: false, spec: null, sha: null }; }
|
|
293
|
+
const line = out.split(/\r?\n/).find((l) => l.includes('pier.workbench'));
|
|
294
|
+
if (!line) return { installed: false, spec: null, sha: null };
|
|
295
|
+
const bracket = line.match(/\[([^\]]+)\]/);
|
|
296
|
+
const spec = bracket ? bracket[1] : line.trim();
|
|
297
|
+
const at = spec.lastIndexOf('@');
|
|
298
|
+
const fullSha = at >= 0 && !spec.startsWith('local:') ? spec.slice(at + 1) : null;
|
|
299
|
+
return { installed: true, spec, sha: fullSha ? fullSha.slice(0, 7) : null };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function collectStatus() {
|
|
303
|
+
const installer = readPkgVersion(ROOT);
|
|
304
|
+
const extPath = dev ? (existsSync(EXT_PATH) ? EXT_PATH : null) : resolveUserExtPath();
|
|
305
|
+
const extDir = extPath ? pkgDirFromExtPath(extPath) : null;
|
|
306
|
+
return {
|
|
307
|
+
product: (extDir ? readPkgVersion(extDir) : null) || installer,
|
|
308
|
+
mode: dev ? 'dev' : 'user',
|
|
309
|
+
installer: { name: 'pier-setup', version: installer },
|
|
310
|
+
piExt: { spec: piSource(), version: extDir ? readPkgVersion(extDir) : null, path: extDir },
|
|
311
|
+
herdr: herdrPluginInfo(),
|
|
312
|
+
latest: { 'pier-setup': npmLatest('pier-setup'), 'pi-pier': npmLatest('pi-pier') },
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/* ── 命令 ────────────────────────────────────────────────────────── */
|
|
317
|
+
function usage() {
|
|
318
|
+
log(`pier-setup — install / update / inspect pier (pi-pier + pier.workbench)
|
|
319
|
+
|
|
320
|
+
Usage:
|
|
321
|
+
pier-setup [install] [--dev] [--hmr-dev] [--force]
|
|
322
|
+
pier-setup update [--dev] [--hmr-dev]
|
|
323
|
+
pier-setup version [--json]
|
|
324
|
+
pier-setup uninstall [--dev] [--purge]
|
|
325
|
+
|
|
326
|
+
npx pier-setup@latest # recommended user install
|
|
327
|
+
npx pier-setup@latest update # refresh both halves to newest release
|
|
328
|
+
npx pier-setup@latest version # local vs npm latest
|
|
329
|
+
|
|
330
|
+
--pi-spec= / --herdr-spec= override distribution sources
|
|
331
|
+
--dev local link (clone); update only rewrites boot-config`);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function version() {
|
|
335
|
+
const s = collectStatus();
|
|
336
|
+
if (flags.has('--json')) {
|
|
337
|
+
log(JSON.stringify(s, null, 2));
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
log(`pier ${s.product ?? 'not installed'}${s.mode === 'dev' ? ' (dev, local link)' : ''}`);
|
|
341
|
+
log('');
|
|
342
|
+
log(` installer pier-setup ${s.installer.version ?? 'unknown'} (this CLI)`);
|
|
343
|
+
log(` pi ext ${s.piExt.spec} ${s.piExt.version ?? 'not installed'} ${s.piExt.path ?? ''}`);
|
|
344
|
+
const herdrVer = s.herdr.installed ? (s.herdr.sha ?? s.herdr.spec) : 'not installed';
|
|
345
|
+
log(` herdr pier.workbench ${herdrVer} ${s.herdr.spec ?? ''}`);
|
|
346
|
+
log('');
|
|
347
|
+
const ls = s.latest['pier-setup'] ?? 'unavailable (offline?)';
|
|
348
|
+
const lp = s.latest['pi-pier'] ?? 'unavailable (offline?)';
|
|
349
|
+
log(` npm latest pier-setup ${ls} pi-pier ${lp}`);
|
|
350
|
+
if (s.installer.version && s.piExt.version && s.installer.version !== s.piExt.version) {
|
|
351
|
+
log(`\n⚠ mismatch: installer ${s.installer.version} ≠ pi-pier ${s.piExt.version}`);
|
|
352
|
+
}
|
|
353
|
+
const target = s.latest['pi-pier'];
|
|
354
|
+
if (s.piExt.version && target && cmpSemver(s.piExt.version, target) < 0) {
|
|
355
|
+
log(`\nupdate available → ${target} npx pier-setup@latest update`);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function update() {
|
|
360
|
+
checkEnv();
|
|
361
|
+
const me = readPkgVersion(ROOT);
|
|
362
|
+
const latestSetup = npmLatest('pier-setup');
|
|
363
|
+
if (latestSetup && me && cmpSemver(me, latestSetup) < 0) {
|
|
364
|
+
log(`⚠ installer ${me} < latest ${latestSetup} — re-run: npx pier-setup@latest update`);
|
|
365
|
+
}
|
|
366
|
+
const hmrDev = flags.has('--hmr-dev');
|
|
367
|
+
if (dev) {
|
|
368
|
+
log('dev mode: local link is live; pull the repo yourself. Refreshing boot-config only.');
|
|
369
|
+
writeBootConfig(hmrDev, true);
|
|
370
|
+
} else {
|
|
371
|
+
if (tryRun('pi', ['update', piSource()])) log(`✓ pi extension updated (${piSource()})`);
|
|
372
|
+
else if (tryRun('pi', ['install', piSource()])) log(`✓ pi extension installed (${piSource()})`);
|
|
373
|
+
else { console.error('✗ pi update/install failed'); log(` manual: pi update ${piSource()}`); process.exitCode = 1; }
|
|
374
|
+
if (tryRun('herdr', ['plugin', 'install', HERDR_SPEC, '--yes'])) log(`✓ herdr plugin updated (${HERDR_SPEC})`);
|
|
375
|
+
else { console.error('✗ herdr plugin update failed'); log(` manual: herdr plugin install ${HERDR_SPEC} --yes`); process.exitCode = 1; }
|
|
376
|
+
writeBootConfig(hmrDev, true);
|
|
377
|
+
}
|
|
378
|
+
log('');
|
|
379
|
+
version();
|
|
380
|
+
}
|
|
381
|
+
|
|
221
382
|
function install() {
|
|
222
383
|
const hmrDev = flags.has('--hmr-dev');
|
|
223
384
|
const force = flags.has('--force');
|
|
@@ -264,6 +425,8 @@ function uninstall() {
|
|
|
264
425
|
log(`\npier uninstalled.${purge ? '' : ' (boot-config.json kept; use --purge to remove)'}`);
|
|
265
426
|
}
|
|
266
427
|
|
|
267
|
-
if (command === '
|
|
268
|
-
else if (command === '
|
|
428
|
+
if (command === 'help' || flags.has('--help') || flags.has('-h')) usage();
|
|
429
|
+
else if (command === 'version' || flags.has('--version') || flags.has('-v')) version();
|
|
430
|
+
else if (command === 'uninstall') uninstall();
|
|
431
|
+
else if (command === 'update') update();
|
|
269
432
|
else install();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pier-setup",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "One-shot installer for pier:
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "One-shot installer for pier: install / update / version / uninstall for pi-pier + pier.workbench",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"scripts": {
|
|
34
34
|
"test": "node --test \"packages/*/test/*.test.ts\"",
|
|
35
35
|
"test:mutation": "stryker run",
|
|
36
|
-
"prepare": "
|
|
36
|
+
"prepare": "node ./install.mjs --prepare"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@deepseek-ai/cordis-plugin-group": "^1.0.1",
|