@getnote/cli 1.5.6 → 1.5.7

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
@@ -35,13 +35,14 @@ getnote auth login
35
35
 
36
36
  或者从 [Releases](https://github.com/iswalle/getnote-cli/releases) 下载对应平台的二进制文件,放到 `$PATH` 里。
37
37
 
38
- **Windows 用户**:推荐直接从 [Releases](https://github.com/iswalle/getnote-cli/releases) 下载 `.exe` 文件,放到 PATH 里。用 `npm install -g` 安装时,如果遇到 `Expand-Archive` 相关报错,可尝试:
38
+ **pnpm 10+ 用户**:pnpm 默认会拦截依赖包的构建脚本。请在工作区的 `pnpm-workspace.yaml` 中允许 `@getnote/cli` 运行安装脚本:
39
39
 
40
- ```bash
41
- npm install -g @getnote/cli --ignore-scripts
40
+ ```yaml
41
+ allowBuilds:
42
+ '@getnote/cli': true
42
43
  ```
43
44
 
44
- 然后手动从 Releases 下载对应平台的二进制文件。
45
+ 然后重新执行 `pnpm install`。也可以直接从 [Releases](https://github.com/iswalle/getnote-cli/releases) 下载对应平台的二进制文件并放入 `$PATH`。
45
46
 
46
47
  ---
47
48
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getnote/cli",
3
- "version": "1.5.6",
3
+ "version": "1.5.7",
4
4
  "description": "CLI tool for 得到大脑(Get笔记) — manage notes and knowledge bases from the terminal",
5
5
  "keywords": [
6
6
  "getnote",
@@ -19,7 +19,8 @@
19
19
  "gnote": "./bin/getnote.js"
20
20
  },
21
21
  "scripts": {
22
- "postinstall": "node scripts/postinstall.js"
22
+ "postinstall": "node scripts/postinstall.js",
23
+ "test": "node --test scripts/postinstall.test.js"
23
24
  },
24
25
  "files": [
25
26
  "bin/getnote.js",
@@ -37,6 +37,45 @@ function getDownloadURL(platform) {
37
37
  return `https://github.com/${REPO}/releases/download/v${VERSION}/${asset}`;
38
38
  }
39
39
 
40
+ function getWindowsExtractArgs(archivePath, destinationPath) {
41
+ return [
42
+ '-NoProfile',
43
+ '-Command',
44
+ '& { Expand-Archive -LiteralPath $args[0] -DestinationPath $args[1] -Force }',
45
+ archivePath,
46
+ destinationPath,
47
+ ];
48
+ }
49
+
50
+ async function installArchive({
51
+ platform,
52
+ binDir,
53
+ binaryName,
54
+ binaryPath,
55
+ url,
56
+ tmpFile,
57
+ downloadFn = download,
58
+ verifyChecksumFn = verifyChecksum,
59
+ runFn = run,
60
+ chmodFn = fs.chmodSync,
61
+ unlinkFn = fs.unlinkSync,
62
+ }) {
63
+ try {
64
+ await downloadFn(url, tmpFile);
65
+ await verifyChecksumFn(url, path.basename(url), tmpFile);
66
+ if (platform.platform === 'windows') {
67
+ runFn('powershell', getWindowsExtractArgs(tmpFile, binDir));
68
+ } else {
69
+ runFn('tar', ['-xzf', tmpFile, '-C', binDir, binaryName]);
70
+ }
71
+
72
+ chmodFn(binaryPath, 0o755);
73
+ console.log(`getnote installed at ${binaryPath}`);
74
+ } finally {
75
+ try { unlinkFn(tmpFile); } catch (_) {}
76
+ }
77
+ }
78
+
40
79
  async function main() {
41
80
  const platform = getPlatform();
42
81
  const binDir = path.join(__dirname, '..', 'bin');
@@ -63,24 +102,7 @@ async function main() {
63
102
 
64
103
  fs.mkdirSync(binDir, { recursive: true });
65
104
 
66
- try {
67
- await download(url, tmpFile);
68
- await verifyChecksum(url, path.basename(url), tmpFile);
69
- if (platform.platform === 'windows') {
70
- run('powershell', ['-NoProfile', '-Command', 'Expand-Archive -LiteralPath $args[0] -DestinationPath $args[1] -Force', tmpFile, binDir]);
71
- } else {
72
- run('tar', ['-xzf', tmpFile, '-C', binDir, binaryName]);
73
- }
74
-
75
- fs.chmodSync(binaryPath, 0o755);
76
- console.log(`getnote installed at ${binaryPath}`);
77
-
78
- } catch (err) {
79
- console.error('Failed to install getnote:', err.message);
80
- process.exit(1);
81
- } finally {
82
- try { fs.unlinkSync(tmpFile); } catch (_) {}
83
- }
105
+ await installArchive({ platform, binDir, binaryName, binaryPath, url, tmpFile });
84
106
  }
85
107
 
86
108
  function run(command, args) {
@@ -128,7 +150,11 @@ async function verifyChecksum(assetURL, assetName, archivePath) {
128
150
  }
129
151
  }
130
152
 
131
- main().catch(err => {
132
- console.error('Failed to install getnote:', err.message);
133
- process.exit(1);
134
- });
153
+ if (require.main === module) {
154
+ main().catch(err => {
155
+ console.error('Failed to install getnote:', err.message);
156
+ process.exitCode = 1;
157
+ });
158
+ }
159
+
160
+ module.exports = { getWindowsExtractArgs, installArchive };
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ const assert = require('node:assert/strict');
4
+ const test = require('node:test');
5
+
6
+ const { getWindowsExtractArgs, installArchive } = require('./postinstall');
7
+
8
+ test('Windows extraction invokes Expand-Archive inside a script block', () => {
9
+ assert.deepEqual(getWindowsExtractArgs('C:\\Temp\\getnote.zip', 'C:\\Program Files\\getnote'), [
10
+ '-NoProfile',
11
+ '-Command',
12
+ '& { Expand-Archive -LiteralPath $args[0] -DestinationPath $args[1] -Force }',
13
+ 'C:\\Temp\\getnote.zip',
14
+ 'C:\\Program Files\\getnote',
15
+ ]);
16
+ });
17
+
18
+ test('temporary archive is removed when installation fails', async () => {
19
+ const removed = [];
20
+ await assert.rejects(
21
+ installArchive({
22
+ platform: { platform: 'windows', arch: 'amd64' },
23
+ binDir: 'C:\\getnote\\bin',
24
+ binaryName: 'getnote.exe',
25
+ binaryPath: 'C:\\getnote\\bin\\getnote.exe',
26
+ url: 'https://example.invalid/getnote.zip',
27
+ tmpFile: 'C:\\Temp\\getnote-download.zip',
28
+ downloadFn: async () => { throw new Error('download failed'); },
29
+ verifyChecksumFn: async () => {},
30
+ runFn: () => {},
31
+ chmodFn: () => {},
32
+ unlinkFn: file => removed.push(file),
33
+ }),
34
+ /download failed/,
35
+ );
36
+ assert.deepEqual(removed, ['C:\\Temp\\getnote-download.zip']);
37
+ });