tmuxclihook 0.3.2 → 0.3.3
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 +2 -0
- package/package.json +1 -1
- package/src/update.js +131 -1
package/README.md
CHANGED
|
@@ -32,6 +32,8 @@ hooks 安装、tmux 集成写入的路径由「source」决定:环境变量 `T
|
|
|
32
32
|
|
|
33
33
|
`tmuxclihook update` 会显示当前版本,通过 `npm view tmuxclihook version` 查询最新版;版本不同时直接执行 `npm install -g tmuxclihook@latest`,版本相同则不做修改。网络查询或安装失败时命令以非零状态退出。
|
|
34
34
|
|
|
35
|
+
安装成功后会做一次生效自检:按 PATH 解析实际会被运行的 `tmuxclihook`,读取其真实版本与最新版比对。若本机使用 volta,`npm install -g` 只会更新 node 工具链目录里的副本、不会更新 volta 的 shim 镜像(实测 volta 2.0.2:shim npm 的全局 prefix 即工具链目录),自检发现这种情况时会自动补执行 `volta install tmuxclihook@latest` 使更新生效并复检;volta 缺失或修正失败时打警告并提示手动命令。`npm install` 始终是标准安装方式,无需因 volta 改变习惯。
|
|
36
|
+
|
|
35
37
|
## 功能
|
|
36
38
|
|
|
37
39
|
| 菜单项 | 说明 |
|
package/package.json
CHANGED
package/src/update.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
1
|
+
import { readFileSync, accessSync, constants as fsConstants, realpathSync } from 'node:fs';
|
|
2
|
+
import { delimiter, dirname, join } from 'node:path';
|
|
2
3
|
import { execa } from 'execa';
|
|
3
4
|
|
|
4
5
|
const PACKAGE_NAME = 'tmuxclihook';
|
|
@@ -6,10 +7,122 @@ const packageJson = JSON.parse(readFileSync(new URL('../package.json', import.me
|
|
|
6
7
|
|
|
7
8
|
export const CURRENT_VERSION = packageJson.version;
|
|
8
9
|
|
|
10
|
+
// —— 生效版本自检 ————————————————————————————————————————————————
|
|
11
|
+
//
|
|
12
|
+
// `npm install -g` 在版本管理器(volta 等)环境下不会更新其管理的 shim:
|
|
13
|
+
// volta 的 `~/.volta/bin` shim 指向 packages/ 镜像,而 npm -g 只写 node
|
|
14
|
+
// 工具链目录,两者互不感知(实测 0.3.0 → 0.3.2 升级时用户命令仍解析到
|
|
15
|
+
// 旧版)。install 成功后按 PATH 解析「用户实际会运行的那份」,尽力读取
|
|
16
|
+
// 真实版本并与 registry latest 比对,无法确认或版本不符时打警告。
|
|
17
|
+
// 验证是尽力而为的提示,不改变 update 的返回值(install 本身已成功)。
|
|
18
|
+
|
|
19
|
+
function findOnPath(name, env) {
|
|
20
|
+
for (const dir of (env.PATH || '').split(delimiter)) {
|
|
21
|
+
if (!dir) continue;
|
|
22
|
+
const candidate = join(dir, name);
|
|
23
|
+
try {
|
|
24
|
+
accessSync(candidate, fsConstants.X_OK);
|
|
25
|
+
return candidate;
|
|
26
|
+
} catch {
|
|
27
|
+
// 无此文件或不可执行,继续找下一个目录
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// npm 布局下入口是 .../lib/node_modules/<pkg>/bin/cli.js(或其 symlink):
|
|
34
|
+
// realpath 后向上最多 3 层找 name 匹配的 package.json 读版本。版本管理器
|
|
35
|
+
// shim 是独立二进制,向上找不到包 → 返回 null。
|
|
36
|
+
function readOwnPackageVersion(entryPath) {
|
|
37
|
+
let real;
|
|
38
|
+
try {
|
|
39
|
+
real = realpathSync(entryPath);
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
let dir = dirname(real);
|
|
44
|
+
for (let i = 0; i < 3; i += 1) {
|
|
45
|
+
try {
|
|
46
|
+
const pkg = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'));
|
|
47
|
+
if (pkg.name === PACKAGE_NAME && typeof pkg.version === 'string') return pkg.version;
|
|
48
|
+
} catch {
|
|
49
|
+
// 该层无 package.json 或不可解析,继续向上
|
|
50
|
+
}
|
|
51
|
+
dir = dirname(dir);
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// PATH 命中的是 shim 时,尝试 volta 的包镜像路径闭环确认(volta 实现细节,
|
|
57
|
+
// 读不到就放弃,不崩)。VOLTA_HOME 未设时用 ~/.volta。
|
|
58
|
+
function readVoltaImageVersion(env) {
|
|
59
|
+
const voltaHome = env.VOLTA_HOME || join(env.HOME || '', '.volta');
|
|
60
|
+
const pkgPath = join(
|
|
61
|
+
voltaHome, 'tools', 'image', 'packages', PACKAGE_NAME,
|
|
62
|
+
'lib', 'node_modules', PACKAGE_NAME, 'package.json',
|
|
63
|
+
);
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(readFileSync(pkgPath, 'utf8')).version || null;
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function verifyEffectiveVersion(latestVersion, env = process.env) {
|
|
72
|
+
const entry = findOnPath(PACKAGE_NAME, env);
|
|
73
|
+
if (!entry) return { status: 'unknown', path: null, version: null };
|
|
74
|
+
|
|
75
|
+
const ownVersion = readOwnPackageVersion(entry);
|
|
76
|
+
if (ownVersion) {
|
|
77
|
+
return { status: ownVersion === latestVersion ? 'ok' : 'mismatch', path: entry, version: ownVersion };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const voltaVersion = readVoltaImageVersion(env);
|
|
81
|
+
if (voltaVersion) {
|
|
82
|
+
return { status: voltaVersion === latestVersion ? 'ok' : 'mismatch', path: entry, version: voltaVersion };
|
|
83
|
+
}
|
|
84
|
+
return { status: 'unknown', path: entry, version: null };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function warnNotEffective(log, result) {
|
|
88
|
+
const where = result.path ? ` (${result.path})` : '';
|
|
89
|
+
log.error(
|
|
90
|
+
`Warning: the tmuxclihook command on your PATH${where} did not reflect the new version` +
|
|
91
|
+
(result.version ? ` (still v${result.version})` : '') + '.',
|
|
92
|
+
);
|
|
93
|
+
log.error(`If you use volta, run: volta install ${PACKAGE_NAME}@latest`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// volta 生效修正:`npm install -g` 只写 node 工具链目录,不更新 volta 的
|
|
97
|
+
// shim 镜像(实测 volta 2.0.2:shim npm 的全局 prefix 就是工具链目录),
|
|
98
|
+
// 用户的命令经 ~/.volta/bin shim 解析时仍是旧版。检测到 volta 可用时自动
|
|
99
|
+
// 补一次 volta install 使更新生效。npm install -g 始终是安装语义本身,
|
|
100
|
+
// volta 只在自检发现未生效时被自动调用,用户无需改变安装习惯。
|
|
101
|
+
export async function repairWithVolta(run, log, env = process.env) {
|
|
102
|
+
const voltaHome = env.VOLTA_HOME || join(env.HOME || '', '.volta');
|
|
103
|
+
const voltaBin = findOnPath('volta', env) || join(voltaHome, 'bin', 'volta');
|
|
104
|
+
try {
|
|
105
|
+
accessSync(voltaBin, fsConstants.X_OK);
|
|
106
|
+
} catch {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
log.log('Detected volta on this machine; applying the update via volta install...');
|
|
110
|
+
try {
|
|
111
|
+
await run('volta', ['install', `${PACKAGE_NAME}@latest`], { stdio: 'inherit' });
|
|
112
|
+
return true;
|
|
113
|
+
} catch (err) {
|
|
114
|
+
log.error(`volta install failed: ${err}`);
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
9
119
|
export async function updatePackage(options = {}) {
|
|
10
120
|
const run = options.run || execa;
|
|
11
121
|
const log = options.log || console;
|
|
12
122
|
const currentVersion = options.currentVersion || CURRENT_VERSION;
|
|
123
|
+
// 显式传 null 跳过自检/修正(测试用);默认真实现
|
|
124
|
+
const verify = options.verify === undefined ? verifyEffectiveVersion : options.verify;
|
|
125
|
+
const repairVolta = options.repairVolta === undefined ? repairWithVolta : options.repairVolta;
|
|
13
126
|
|
|
14
127
|
log.log(`Current version: v${currentVersion}`);
|
|
15
128
|
|
|
@@ -35,5 +148,22 @@ export async function updatePackage(options = {}) {
|
|
|
35
148
|
}
|
|
36
149
|
|
|
37
150
|
log.log(`Done. Updated to v${latestVersion}`);
|
|
151
|
+
|
|
152
|
+
if (verify) {
|
|
153
|
+
let result = await verify(latestVersion);
|
|
154
|
+
if (result.status !== 'ok') {
|
|
155
|
+
// PATH 命中的副本未反映新版本(典型:volta shim 镜像未更新)——
|
|
156
|
+
// 自动走 volta 完成生效步骤,然后复检。
|
|
157
|
+
if (repairVolta && await repairVolta(run, log)) {
|
|
158
|
+
result = await verify(latestVersion);
|
|
159
|
+
}
|
|
160
|
+
if (result.status === 'ok') {
|
|
161
|
+
log.log(`Verified: tmuxclihook on your PATH now resolves to v${latestVersion}.`);
|
|
162
|
+
} else {
|
|
163
|
+
warnNotEffective(log, result);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
38
168
|
return true;
|
|
39
169
|
}
|