@arshdelight/practi 0.9.3 → 0.9.4

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,12 +1,30 @@
1
1
  import fs from 'node:fs';
2
+ import os from 'node:os';
2
3
  import path from 'node:path';
3
4
  import { spawn, spawnSync } from 'node:child_process';
4
5
  import { CLI_VERSION } from '../version.js';
5
6
  const PKG = '@arshdelight/practi';
6
- /** Windows npm npm.cmd(.cmd 必须免 shell 调用,否则触发 DEP0190 */
7
+ /** npm.cmd only as a fallback — .cmd files need shell:true on modern Node (DEP0190) */
7
8
  const NPM = process.platform === 'win32' ? 'npm.cmd' : 'npm';
9
+ /**
10
+ * How to invoke npm from this Node: DEP0190 (node ≥18.20/20.12) makes spawning
11
+ * .cmd/.bat without shell:true throw EINVAL, so on Windows we bypass the shim
12
+ * entirely and run the npm-cli.js that ships inside process.execPath's Node —
13
+ * exactly what the npm.cmd shim does internally. Non-standard layouts without
14
+ * that file fall back to npm.cmd with shell:true.
15
+ */
16
+ export function npmInvocation() {
17
+ if (process.platform === 'win32') {
18
+ const cli = path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js');
19
+ if (fs.existsSync(cli))
20
+ return { cmd: process.execPath, prefixArgs: [cli], shell: false };
21
+ return { cmd: NPM, prefixArgs: [], shell: true };
22
+ }
23
+ return { cmd: NPM, prefixArgs: [], shell: false };
24
+ }
8
25
  function npmOut(args) {
9
- const r = spawnSync(NPM, args, { encoding: 'utf8' });
26
+ const { cmd, prefixArgs, shell } = npmInvocation();
27
+ const r = spawnSync(cmd, [...prefixArgs, ...args], { encoding: 'utf8', shell });
10
28
  return (r.stdout ?? '').trim();
11
29
  }
12
30
  /** 点分数值比较:a>b 返回 1,a<b 返回 -1,相等返回 0 */
@@ -23,6 +41,9 @@ function cmpSemver(a, b) {
23
41
  /**
24
42
  * practi update:向 registry 查 latest,比当前新就 npm install -g 自更新。
25
43
  * dev 安装(npm link 的符号链接)会被 registry 安装覆盖——检测到时先警告。
44
+ * Windows 的安装是脱钩的后台进程:调用方 shell 正解释执行 practi 的 bin
45
+ * shim(句柄开着),原地 npm 重写必失败;后台进程等本命令链退出后落盘,
46
+ * 输出追加到临时目录日志(detached 进程不再共享 console,时序也不可靠)。
26
47
  */
27
48
  export async function runUpdate(_opts) {
28
49
  const registry = npmOut(['config', 'get', 'registry']) || 'https://registry.npmjs.org';
@@ -48,21 +69,27 @@ export async function runUpdate(_opts) {
48
69
  console.error(`warning: ${installedDir} is a linked development install — updating replaces the link with a registry install`);
49
70
  }
50
71
  console.log(`updating: ${CLI_VERSION} → ${latest}`);
72
+ const { cmd, prefixArgs, shell } = npmInvocation();
73
+ const installArgs = [...prefixArgs, 'install', '-g', `${PKG}@${latest}`];
51
74
  if (process.platform === 'win32') {
52
- // Windows 自更新死锁:bin shim(practi.cmd/.ps1)正被调用方 shell 解释执行、
53
- // 句柄开着(.js 无执行锁,锁的是 shim),npm 原地重写必 EPERM。脱钩一个后台
54
- // npm 等本命令链退出后落盘——spawn 到 npm 实际写文件隔着 registry 往返(>1s),
55
- // 而本进程链退出在百毫秒级,竞态余量充足。stdio 继承 console 句柄(conhost
56
- // 进程组共享,父退出后 npm 输出仍可见)。
57
- const child = spawn(NPM, ['install', '-g', `${PKG}@${latest}`], {
58
- detached: true,
59
- stdio: 'inherit',
60
- });
61
- child.unref();
62
- console.log(`installing ${latest} in the background — verify with: practi --version`);
75
+ const log = path.join(os.tmpdir(), 'practi-update.log');
76
+ const out = fs.openSync(log, 'a');
77
+ try {
78
+ const child = spawn(cmd, installArgs, { detached: true, stdio: ['ignore', out, out], shell });
79
+ child.unref();
80
+ }
81
+ catch (e) {
82
+ fs.closeSync(out);
83
+ console.error(`error: could not start the background installer — ${e.message}`);
84
+ console.error(`run it manually: npm install -g ${PKG}@${latest}`);
85
+ return 1;
86
+ }
87
+ fs.closeSync(out);
88
+ console.log(`installing ${latest} in the background — log: ${log}`);
89
+ console.log(`verify with: practi --version`);
63
90
  return 0;
64
91
  }
65
- const r = spawnSync(NPM, ['install', '-g', `${PKG}@${latest}`], { stdio: 'inherit' });
92
+ const r = spawnSync(cmd, installArgs, { stdio: 'inherit', shell });
66
93
  if (r.status !== 0) {
67
94
  console.error('error: npm install failed — run it manually:');
68
95
  console.error(` npm install -g ${PKG}@${latest}`);
@@ -1 +1 @@
1
- {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/cmd/update.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/cmd/update.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arshdelight/practi",
3
- "version": "0.9.3",
3
+ "version": "0.9.4",
4
4
  "description": "Local registry CLI for POP (Protocol of Practice): manage a personal, content-addressed collection of practice documents on top of @arshdelight/pop-sdk. Syncs to PractiHub.",
5
5
  "type": "module",
6
6
  "bin": {