@getnote/cli 1.5.7 → 1.5.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
@@ -44,6 +44,16 @@ allowBuilds:
44
44
 
45
45
  然后重新执行 `pnpm install`。也可以直接从 [Releases](https://github.com/iswalle/getnote-cli/releases) 下载对应平台的二进制文件并放入 `$PATH`。
46
46
 
47
+ ### 安装机制说明
48
+
49
+ 从 v1.5.10 起,npm 包**内置所有平台的二进制文件**(macOS/Linux/Windows,x64/ARM64),安装时**不再依赖 GitHub**。
50
+
51
+ 安装时由 postinstall 从 npm 包内的 prebuilt/ 目录复制当前平台二进制,不会访问 GitHub。
52
+
53
+ **中国大陆用户**:只需配置 npm Registry 镜像(例如 npmmirror),即可获取完整 npm 包;不需要额外配置二进制下载地址。
54
+
55
+ **包大小**:压缩后 ~22MB,解压后 ~55MB(包含 6 个平台二进制)。
56
+
47
57
  ---
48
58
 
49
59
  ## 使用要求
@@ -138,8 +148,9 @@ getnote search "产品设计" --kb vnrOAaGY
138
148
 
139
149
  **场景 3:管理知识库**
140
150
  ```bash
141
- # 列出所有知识库
151
+ # 列出默认知识库;特殊类型使用 --scope
142
152
  getnote kbs
153
+ getnote kbs --scope BOOKSPACE
143
154
 
144
155
  # 查看某个知识库的笔记
145
156
  getnote kb vnrOAaGY --all
@@ -280,7 +291,8 @@ getnote tag list <note_id> 查看笔记的所有标签
280
291
  ### 知识库
281
292
 
282
293
  ```
283
- getnote kbs 列出所有可访问知识库(DEFAULT / BOOKSPACE / CUSTOMER / TEAMSPACE)
294
+ getnote kbs 列出 DEFAULT 知识库
295
+ --scope <scope> 指定 DEFAULT / BOOKSPACE / CUSTOMER / TEAMSPACE
284
296
 
285
297
  getnote kb <topic_id> 知识库内的笔记
286
298
  --limit <n>
@@ -300,7 +312,9 @@ getnote kb directory-delete <topic_id> <id> --yes 删除空文件夹
300
312
  getnote kb blogger-follow <topic_id> <抖音链接> 订阅抖音博主
301
313
  getnote kb live-follow <topic_id> <url> 订阅得到直播课,直播结束后 AI 摘要自动入库
302
314
 
303
- getnote kbs-sub 获取我订阅的知识库列表
315
+ getnote kbs [--scope DEFAULT] 获取我创建/管理的知识库,默认只返回 DEFAULT
316
+ getnote kbs-sub [--scope DEFAULT] 获取我订阅的知识库,默认只返回 DEFAULT
317
+ # --scope 可选:DEFAULT、CUSTOMER、BOOKSPACE、TEAMSPACE
304
318
  ```
305
319
 
306
320
  常用目录命令提供短别名,旧命令继续兼容:
@@ -392,6 +406,7 @@ $ getnote search "工作日志" --limit 7 -o json
392
406
 
393
407
  | 日期 | 版本 | 新能力 | 适合怎么用 |
394
408
  |------|------|--------|------------|
409
+ | 2026-09-02 | **v1.5.8** | 1. `kbs` 与 `kbs-sub` 默认只返回 `DEFAULT` 知识库<br>2. 新增 `--scope`,可按 `CUSTOMER`、`BOOKSPACE`、`TEAMSPACE` 精确读取<br>3. 订阅列表不再混入自己创建的知识库 | 避免书籍库和自有库挤占订阅列表分页;需要特殊知识库时显式选择 scope |
395
410
  | 2026-08-19 | **v1.5.6** | 1. `getnote update` 默认升级 CLI、同步五个领域 Skill 并运行诊断<br>2. capabilities 2.2 提供机器可读的安装、更新、验证与平台托管边界<br>3. 移除失效的 `install.sh` 引导 | 用户只说“安装”或“更新”即可,AI Agent 无需让用户选择内部组件,并能按统一成功条件完成验收 |
396
411
  | 2026-08-19 | **v1.5.5** | 1. 一键安装自动识别本机 AI Agent,并按平台显示安装结果<br>2. 新增 GitHub Copilot、Gemini CLI、Windsurf、OpenCode 和 Cline 自动安装<br>3. OpenClaw(小龙虾)和 QClaw 仅在检测到时提供 ClawHub 确认入口<br>4. 保留 `SKILLS` 品牌开场,隐藏底层安装术语<br>5. `doctor` 按平台真实目录检查 Skill 状态 | 用户只需运行一次安装命令;AI 能根据结构化结果判断安装状态并给出明确修复动作 |
397
412
  | 2026-08-17 | **v1.5.3** | 1. `doctor` 新增稳定问题码、阻断级别、修复动作、平台 Skill 状态和在线/离线就绪语义<br>2. 诊断失败提供可靠退出码,JSON 保持单一、可解析<br>3. npm 与独立二进制采用匹配的升级路径,Release 下载增加 SHA-256 校验<br>4. WorkBuddy Skills 整套预检并支持失败回滚<br>5. 严格校验输出格式与多余参数 | 让技术用户和 AI 都能准确判断环境是否真正可用,并根据结构化结果完成修复;同时避免版本分裂、半安装和未校验更新包 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getnote/cli",
3
- "version": "1.5.7",
3
+ "version": "1.5.10",
4
4
  "description": "CLI tool for 得到大脑(Get笔记) — manage notes and knowledge bases from the terminal",
5
5
  "keywords": [
6
6
  "getnote",
@@ -11,21 +11,24 @@
11
11
  "homepage": "https://github.com/iswalle/getnote-cli",
12
12
  "repository": {
13
13
  "type": "git",
14
- "url": "https://github.com/iswalle/getnote-cli.git"
14
+ "url": "git+https://github.com/iswalle/getnote-cli.git"
15
15
  },
16
16
  "license": "MIT",
17
17
  "bin": {
18
- "getnote": "./bin/getnote.js",
19
- "gnote": "./bin/getnote.js"
18
+ "getnote": "bin/getnote.js",
19
+ "gnote": "bin/getnote.js"
20
20
  },
21
21
  "scripts": {
22
22
  "postinstall": "node scripts/postinstall.js",
23
- "test": "node --test scripts/postinstall.test.js"
23
+ "test": "node --test scripts/postinstall.test.js",
24
+ "prepare-package": "bash scripts/prepare-package.sh",
25
+ "prepack": "bash scripts/prepare-package.sh"
24
26
  },
25
27
  "files": [
26
28
  "bin/getnote.js",
27
29
  "scripts/",
28
30
  "skills/",
31
+ "prebuilt/",
29
32
  "README.md"
30
33
  ]
31
34
  }
Binary file
Binary file
Binary file
Binary file
@@ -1,160 +1,60 @@
1
1
  #!/usr/bin/env node
2
- // postinstall.js — downloads the getnote binary for the current platform.
3
-
2
+ // Install the platform binary bundled in this npm package.
3
+ // Installation is local-only; no network request is made here.
4
4
  'use strict';
5
5
 
6
- const fs = require('fs');
7
- const path = require('path');
8
- const os = require('os');
9
- const https = require('https');
10
- const crypto = require('crypto');
11
- const { spawnSync } = require('child_process');
12
-
13
- const pkg = require('../package.json');
14
- const VERSION = pkg.version;
15
- const REPO = 'iswalle/getnote-cli';
16
-
17
- function getPlatform() {
18
- const platform = os.platform();
19
- const arch = os.arch();
6
+ const fs = require('node:fs');
7
+ const os = require('node:os');
8
+ const path = require('node:path');
9
+ const { spawnSync } = require('node:child_process');
10
+ const { version } = require('../package.json');
20
11
 
21
- const platformMap = { darwin: 'darwin', linux: 'linux', win32: 'windows' };
22
- const archMap = { x64: 'amd64', arm64: 'arm64' };
12
+ const platformNames = { darwin: 'darwin', linux: 'linux', win32: 'windows' };
13
+ const archNames = { x64: 'amd64', arm64: 'arm64' };
23
14
 
24
- const p = platformMap[platform];
25
- const a = archMap[arch];
26
- if (!p || !a) throw new Error(`Unsupported platform: ${platform}/${arch}`);
27
- return { platform: p, arch: a };
15
+ function getPlatform(platform = os.platform(), arch = os.arch()) {
16
+ const name = platformNames[platform];
17
+ const cpu = archNames[arch];
18
+ if (!name || !cpu) throw new Error(`Unsupported platform: ${platform}/${arch}`);
19
+ return { platform: name, arch: cpu };
28
20
  }
29
21
 
30
22
  function getBinaryName(platform) {
31
23
  return platform.platform === 'windows' ? 'getnote.exe' : 'getnote';
32
24
  }
33
25
 
34
- function getDownloadURL(platform) {
35
- const ext = platform.platform === 'windows' ? '.zip' : '.tar.gz';
36
- const asset = `getnote-cli_${VERSION}_${platform.platform}_${platform.arch}${ext}`;
37
- return `https://github.com/${REPO}/releases/download/v${VERSION}/${asset}`;
38
- }
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
- ];
26
+ function getPrebuiltPath(platform) {
27
+ return path.join(__dirname, '..', 'prebuilt', `${platform.platform}-${platform.arch}`, getBinaryName(platform));
48
28
  }
49
29
 
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 (_) {}
30
+ function installFromPrebuilt(platform, binDir) {
31
+ const source = getPrebuiltPath(platform);
32
+ const destination = path.join(binDir, getBinaryName(platform));
33
+ if (!fs.existsSync(source)) {
34
+ throw new Error(`Bundled binary is missing: ${path.relative(path.join(__dirname, '..'), source)}. Install a newer @getnote/cli package.`);
76
35
  }
36
+ fs.mkdirSync(binDir, { recursive: true });
37
+ fs.copyFileSync(source, destination);
38
+ if (platform.platform !== 'windows') fs.chmodSync(destination, 0o755);
39
+ console.log(`getnote v${version} installed from the npm package`);
77
40
  }
78
41
 
79
- async function main() {
42
+ function main() {
80
43
  const platform = getPlatform();
81
44
  const binDir = path.join(__dirname, '..', 'bin');
82
- const binaryName = getBinaryName(platform);
83
- const binaryPath = path.join(binDir, binaryName);
84
- const url = getDownloadURL(platform);
85
- const tmpFile = path.join(os.tmpdir(), `getnote-download-${Date.now()}`);
86
-
87
- // Skip download if binary already matches current version
45
+ const binaryPath = path.join(binDir, getBinaryName(platform));
88
46
  if (fs.existsSync(binaryPath)) {
89
- try {
90
- const result = spawnSync(binaryPath, ['version'], { encoding: 'utf8' });
91
- const fallback = result.status === 0 ? result : spawnSync(binaryPath, ['--version'], { encoding: 'utf8' });
92
- const out = (fallback.stdout || '').trim();
93
- if (out.includes(VERSION)) {
94
- console.log(`getnote v${VERSION} already installed, skipping download.`);
95
- return;
96
- }
97
- } catch (_) { /* binary exists but can't run (wrong arch etc.), re-download */ }
98
- }
99
-
100
- console.log(`Downloading getnote v${VERSION} for ${platform.platform}/${platform.arch}...`);
101
- console.log(`URL: ${url}`);
102
-
103
- fs.mkdirSync(binDir, { recursive: true });
104
-
105
- await installArchive({ platform, binDir, binaryName, binaryPath, url, tmpFile });
106
- }
107
-
108
- function run(command, args) {
109
- const result = spawnSync(command, args, { stdio: 'inherit' });
110
- if (result.error) throw result.error;
111
- if (result.status !== 0) throw new Error(`${command} exited with status ${result.status}`);
112
- }
113
-
114
- function download(url, destination, redirects = 0) {
115
- if (redirects > 5) return Promise.reject(new Error('Too many redirects'));
116
- return new Promise((resolve, reject) => {
117
- const request = https.get(url, { headers: { 'User-Agent': '@getnote/cli installer' } }, response => {
118
- if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
119
- response.resume();
120
- return resolve(download(new URL(response.headers.location, url).toString(), destination, redirects + 1));
121
- }
122
- if (response.statusCode !== 200) {
123
- response.resume();
124
- return reject(new Error(`HTTP ${response.statusCode}: ${url}`));
125
- }
126
- const output = fs.createWriteStream(destination, { mode: 0o600 });
127
- response.pipe(output);
128
- output.on('finish', () => output.close(resolve));
129
- output.on('error', reject);
130
- });
131
- request.on('error', reject);
132
- });
133
- }
134
-
135
- async function verifyChecksum(assetURL, assetName, archivePath) {
136
- const checksumPath = `${archivePath}.checksums`;
137
- try {
138
- await download(new URL('checksums.txt', assetURL).toString(), checksumPath);
139
- const line = fs.readFileSync(checksumPath, 'utf8').split(/\r?\n/).find(value => {
140
- const fields = value.trim().split(/\s+/);
141
- return fields.length === 2 && fields[1].replace(/^\*/, '') === assetName;
142
- });
143
- if (!line) throw new Error(`Checksum for ${assetName} is missing`);
144
- const expected = line.trim().split(/\s+/)[0].toLowerCase();
145
- if (!/^[a-f0-9]{64}$/.test(expected)) throw new Error(`Checksum for ${assetName} is invalid`);
146
- const actual = crypto.createHash('sha256').update(fs.readFileSync(archivePath)).digest('hex');
147
- if (actual !== expected) throw new Error(`Checksum mismatch for ${assetName}`);
148
- } finally {
149
- try { fs.unlinkSync(checksumPath); } catch (_) {}
47
+ const result = spawnSync(binaryPath, ['version'], { encoding: 'utf8' });
48
+ if (result.status === 0 && (result.stdout || '').includes(version)) return;
150
49
  }
50
+ installFromPrebuilt(platform, binDir);
151
51
  }
152
52
 
153
53
  if (require.main === module) {
154
- main().catch(err => {
155
- console.error('Failed to install getnote:', err.message);
54
+ try { main(); } catch (error) {
55
+ console.error(`Failed to install getnote: ${error.message}`);
156
56
  process.exitCode = 1;
157
- });
57
+ }
158
58
  }
159
59
 
160
- module.exports = { getWindowsExtractArgs, installArchive };
60
+ module.exports = { getPlatform, getBinaryName, getPrebuiltPath, installFromPrebuilt };
@@ -1,37 +1,15 @@
1
1
  'use strict';
2
-
3
2
  const assert = require('node:assert/strict');
4
3
  const test = require('node:test');
4
+ const { getPlatform, getBinaryName, getPrebuiltPath } = require('./postinstall');
5
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
- ]);
6
+ test('maps Windows architectures to bundled executable paths', () => {
7
+ assert.deepEqual(getPlatform('win32', 'x64'), { platform: 'windows', arch: 'amd64' });
8
+ assert.deepEqual(getPlatform('win32', 'arm64'), { platform: 'windows', arch: 'arm64' });
9
+ assert.equal(getBinaryName({ platform: 'windows' }), 'getnote.exe');
10
+ assert.match(getPrebuiltPath({ platform: 'windows', arch: 'amd64' }), /prebuilt[\\/]windows-amd64[\\/]getnote\.exe$/);
16
11
  });
17
12
 
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']);
13
+ test('uses a package-local binary path', () => {
14
+ assert.doesNotMatch(getPrebuiltPath({ platform: 'windows', arch: 'amd64' }), /^https?:/);
37
15
  });
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env bash
2
+ # Build every supported binary into the npm package's prebuilt/ directory.
3
+ # Uses npm naming convention (x64 instead of amd64) for consistency.
4
+ set -euo pipefail
5
+
6
+ VERSION="${1:-$(node -p "require('./package.json').version")}"
7
+ VERSION="${VERSION% }"
8
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
9
+ cd "$ROOT"
10
+
11
+ echo "==> Preparing package for version ${VERSION}"
12
+ echo "==> Cleaning prebuilt directory..."
13
+ rm -rf prebuilt
14
+
15
+ echo "==> Creating platform directories..."
16
+ mkdir -p prebuilt/darwin-amd64 prebuilt/darwin-arm64 prebuilt/linux-amd64 prebuilt/linux-arm64 prebuilt/windows-amd64 prebuilt/windows-arm64
17
+
18
+ LDFLAGS="-s -w -X github.com/iswalle/getnote-cli/internal/version.Version=${VERSION}"
19
+
20
+ echo "==> Building binaries..."
21
+ echo " - macOS x64..."
22
+ GOOS=darwin GOARCH=amd64 go build -ldflags "$LDFLAGS" -o prebuilt/darwin-amd64/getnote .
23
+
24
+ echo " - macOS ARM64..."
25
+ GOOS=darwin GOARCH=arm64 go build -ldflags "$LDFLAGS" -o prebuilt/darwin-arm64/getnote .
26
+
27
+ echo " - Linux x64..."
28
+ GOOS=linux GOARCH=amd64 go build -ldflags "$LDFLAGS" -o prebuilt/linux-amd64/getnote .
29
+
30
+ echo " - Linux ARM64..."
31
+ GOOS=linux GOARCH=arm64 go build -ldflags "$LDFLAGS" -o prebuilt/linux-arm64/getnote .
32
+
33
+ echo " - Windows x64..."
34
+ GOOS=windows GOARCH=amd64 go build -ldflags "$LDFLAGS" -o prebuilt/windows-amd64/getnote.exe .
35
+
36
+ echo " - Windows ARM64..."
37
+ GOOS=windows GOARCH=arm64 go build -ldflags "$LDFLAGS" -o prebuilt/windows-arm64/getnote.exe .
38
+
39
+ echo "==> Verifying prebuilt binaries..."
40
+ find prebuilt -type f -exec ls -lh {} \; | awk '{print $5, $9}'
41
+
42
+ TOTAL_SIZE=$(du -sh prebuilt | awk '{print $1}')
43
+ echo "==> Total prebuilt size: ${TOTAL_SIZE}"
44
+
45
+ echo "==> Package preparation complete!"
46
+ echo ""
47
+ echo "Next steps:"
48
+ echo " 1. Test with: npm pack --dry-run"
49
+ echo " 2. Verify with: tar -tzf getnote-cli-${VERSION}.tgz | grep prebuilt"
50
+ echo " 3. Test install: npm install -g ./getnote-cli-${VERSION}.tgz"
51
+ echo " 4. Publish with: npm publish"
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ // Test local installation without network access
3
+
4
+ const { execSync } = require('child_process');
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const os = require('os');
8
+
9
+ const VERSION = require('../package.json').version;
10
+ const tmpDir = path.join(os.tmpdir(), `getnote-test-${Date.now()}`);
11
+
12
+ console.log('==> Testing local installation...');
13
+ console.log(`Version: ${VERSION}`);
14
+ console.log(`Test directory: ${tmpDir}`);
15
+ console.log('');
16
+
17
+ // Create test environment
18
+ fs.mkdirSync(tmpDir, { recursive: true });
19
+
20
+ try {
21
+ // Pack the package
22
+ console.log('1. Creating package tarball...');
23
+ const tarball = path.resolve(`getnote-cli-${VERSION}.tgz`);
24
+
25
+ if (!fs.existsSync(tarball)) {
26
+ console.error(`✗ Tarball not found: ${tarball}`);
27
+ console.error(' Run: npm pack');
28
+ process.exit(1);
29
+ }
30
+
31
+ console.log(` ✓ Found: ${tarball}`);
32
+
33
+ // Install globally in test directory
34
+ console.log('');
35
+ console.log('2. Installing package...');
36
+
37
+ const npmPrefix = path.join(tmpDir, 'npm-global');
38
+ fs.mkdirSync(npmPrefix, { recursive: true });
39
+
40
+ execSync(`npm install --prefix "${npmPrefix}" "${tarball}"`, {
41
+ stdio: 'inherit',
42
+ env: {
43
+ ...process.env,
44
+ npm_config_offline: 'true', // Force offline mode
45
+ npm_config_prefer_offline: 'true'
46
+ }
47
+ });
48
+
49
+ console.log(' ✓ Package installed');
50
+
51
+ // Verify binary exists
52
+ console.log('');
53
+ console.log('3. Verifying installation...');
54
+
55
+ const platform = os.platform();
56
+ const binaryName = platform === 'win32' ? 'getnote.exe' : 'getnote';
57
+ const binaryPath = path.join(
58
+ npmPrefix,
59
+ 'node_modules',
60
+ '@getnote',
61
+ 'cli',
62
+ 'bin',
63
+ binaryName
64
+ );
65
+
66
+ if (!fs.existsSync(binaryPath)) {
67
+ console.error(` ✗ Binary not found: ${binaryPath}`);
68
+ process.exit(1);
69
+ }
70
+
71
+ console.log(` ✓ Binary exists: ${binaryPath}`);
72
+
73
+ // Test binary execution
74
+ const result = execSync(`"${binaryPath}" --version`, { encoding: 'utf8' });
75
+ console.log(` ✓ Binary runs: ${result.trim()}`);
76
+
77
+ if (!result.includes(VERSION)) {
78
+ console.error(` ✗ Version mismatch: expected ${VERSION}, got ${result.trim()}`);
79
+ process.exit(1);
80
+ }
81
+
82
+ console.log('');
83
+ console.log('==> ✓ All tests passed!');
84
+ console.log('');
85
+ console.log('Installation succeeded without network access.');
86
+ console.log('The package includes all platform binaries and does not depend on GitHub.');
87
+
88
+ } catch (err) {
89
+ console.error('');
90
+ console.error('==> ✗ Test failed:');
91
+ console.error(err.message);
92
+ process.exit(1);
93
+ } finally {
94
+ // Cleanup
95
+ console.log('');
96
+ console.log('Cleaning up...');
97
+ fs.rmSync(tmpDir, { recursive: true, force: true });
98
+ console.log('Done.');
99
+ }
@@ -13,8 +13,8 @@ description: 查看和管理得到大脑的默认知识库、书籍、客户档
13
13
 
14
14
  | 意图 | 命令入口 |
15
15
  |---|---|
16
- | 自有/可管理知识库 | `getnote kbs` |
17
- | 我订阅的知识库 | `getnote kbs-sub` |
16
+ | 自有/可管理知识库 | `getnote kbs --scope <scope>` |
17
+ | 我订阅的知识库 | `getnote kbs-sub --scope <scope>` |
18
18
  | 知识库笔记 | `getnote kb <topic_id>` |
19
19
  | 新建个人知识库 | `getnote kb create` |
20
20
  | 加入笔记 | `getnote kb add` |
@@ -35,8 +35,8 @@ description: 查看和管理得到大脑的默认知识库、书籍、客户档
35
35
 
36
36
  ## 选择知识库和权限
37
37
 
38
- 1. 用户问“我管理的/我的知识库”时执行 `getnote kbs -o json`;问“所有能访问的知识库”时还要执行 `getnote kbs-sub -o json`,分别标明自有/可管理与已订阅,按各自 `has_more` 翻完页,不能混成同一种权限。
39
- 2. `getnote kbs` 必须保留接口实际返回的全部 Scope,例如 `DEFAULT`、`BOOKSPACE`、`CUSTOMER`、`TEAMSPACE`,不能只返回默认知识库,也不能虚构未返回的 Scope。
38
+ 1. `getnote kbs` 和 `getnote kbs-sub` 默认只查询 `DEFAULT`。用户明确要书籍、客户档案或团队知识库时,分别传 `--scope BOOKSPACE`、`--scope CUSTOMER`、`--scope TEAMSPACE`;不能把多个 Scope 混在同一分页结果里。
39
+ 2. 用户问“我管理的/我的知识库”时执行 `getnote kbs --scope <scope> -o json`;问“我订阅的知识库”时执行 `getnote kbs-sub --scope <scope> -o json`。订阅列表只包含他人创建且当前账号真实订阅的知识库,分别按 `has_more` 翻完页。
40
40
  3. 按名称和 `scope` 匹配;同名或用户意图不明确时让用户选择,不猜 `topic_id`。目标名称既可能是知识库也可能是文件夹时,先问清楚。
41
41
  4. 订阅知识库通常只读。若列表结果明确返回角色或可写标记,按真实字段判断;当前 CLI 契约未保证权限字段时,不得声称已经预检为 owner/admin,可在用户明确授权后尝试写入,并忠实处理权限失败。
42
42
  5. 普通成员写入失败时明确说明权限不足,不尝试绕过。当前不代替用户新建团队知识库。
@@ -59,8 +59,8 @@ description: 查看和管理得到大脑的默认知识库、书籍、客户档
59
59
 
60
60
  | 命令 | 成功结果必须包含 | 回复规则 |
61
61
  |---|---|---|
62
- | `getnote kbs -o json` | `success=true`、`data.topics[].topic_id/name/scope/stats`、`has_more/total` | 展示全部真实 Scope,不只展示默认知识库。 |
63
- | `getnote kbs-sub -o json` | `success=true`、`data.topics[].topic_id/name`、`has_more/total` | 订阅知识库通常只读,不能把它当作可写知识库。 |
62
+ | `getnote kbs --scope <scope> -o json` | `success=true`、`data.topics[].topic_id/name/scope/stats`、`has_more/total` | 默认 scope 为 `DEFAULT`;特殊类型必须显式传 scope。 |
63
+ | `getnote kbs-sub --scope <scope> -o json` | `success=true`、`data.topics[].topic_id/name/scope`、`has_more/total` | 只返回该 scope 下真实订阅的他人知识库,通常只读。 |
64
64
  | `getnote kb <topic_id> -o json` | `success=true`、`data.notes[].note_id/title/note_type`、`has_more/total` | 返回知识库内真实笔记;需要链接时再用 `note` 读取详情。 |
65
65
  | `getnote kb create <name> -o json` | `success=true`、`data?` | 仅创建个人知识库;不得在没有返回 ID 时虚构 `topic_id`。 |
66
66
  | `getnote kb add <topic_id> <note_id…> -o json` | `success=true`、`data?` | 最多 20 条;需要确认最终目录归属时重新读取目录。 |
@@ -16,7 +16,7 @@ description: 在得到大脑的全部笔记或指定知识库中按自然语言
16
16
  ## 执行步骤
17
17
 
18
18
  1. 用户没有指定知识库时,直接执行 `getnote search <query> --limit <1-10> -o json`。默认上限是 10,不能自行放大。
19
- 2. 用户指定知识库名称时,先执行 `getnote kbs -o json`,用返回的真实 `topic_id` 和 `scope` 匹配;同名、多个团队知识库或意图不明确时必须让用户选择。
19
+ 2. 用户指定知识库名称时,先按其类型执行 `getnote kbs --scope <scope> -o json`;默认查 `DEFAULT`,书籍、客户档案和团队知识库分别使用 `BOOKSPACE`、`CUSTOMER`、`TEAMSPACE`。用返回的真实 `topic_id` 和 `scope` 匹配;同名或意图不明确时必须让用户选择。
20
20
  3. 已确认知识库后执行 `getnote search <query> --kb <topic_id> --limit <1-10> -o json`。
21
21
  4. 只从返回值读取标题、摘要、字符串 `note_id` 和真实 `note_url`。没有 `note_id/note_url` 的非笔记结果可以展示内容,但不能伪造“打开笔记”链接。
22
22
  5. 同一篇笔记可能因命中多个片段出现多次。面向用户列“几篇笔记”时必须按字符串 `note_id` 去重;若去重后不足用户要求的数量,可在上限 10 内增大 `--limit` 重搜,仍不足时如实返回实际数量。