yuque-cookie-plugin 0.1.1 → 0.1.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 +25 -2
- package/dist/auth.js +33 -17
- package/dist/cli.js +40 -4
- package/dist/client-cookie.js +45 -0
- package/docs/usage-zh.md +73 -14
- package/package.json +1 -1
- package/skills/yuque-cookie-plugin/SKILL.md +8 -4
- package/skills/yuque-cookie-plugin/commands.yaml +21 -0
- package/skills/yuque-cookie-plugin/reference/agent-spec.md +16 -0
package/README.md
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
## 当前能力
|
|
10
10
|
|
|
11
|
-
- Cookie
|
|
12
|
-
- 读取语雀信息:`book inspect`、`doc inspect`
|
|
11
|
+
- Cookie 登录、清理和登录态检测:`auth login`、`auth logout`、`auth status`
|
|
12
|
+
- 读取语雀信息:`book list`、`book inspect`、`doc inspect`
|
|
13
13
|
- 文档快照和结构对比:`doc snapshot`、`lake diff`
|
|
14
14
|
- Lake 和 Markdown 辅助转换:`lake to-markdown`、`lake serialize`
|
|
15
15
|
- 安全写入:`doc apply-lake`、`doc update-lake`
|
|
@@ -78,6 +78,15 @@ npm run yuque-local -- auth login
|
|
|
78
78
|
|
|
79
79
|
项目目录不会保存真实 Cookie。配置文件会记录保存时间、更新时间、最近成功验证时间和最近失败时间。
|
|
80
80
|
|
|
81
|
+
如果你在同一台电脑上同时做全局 npm 版真实测试和本地源码开发,可以用独立配置目录隔离 Cookie:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
YUQUE_COOKIE_PLUGIN_CONFIG_DIR=/tmp/yuque-plugin-real-test yuque-local auth login
|
|
85
|
+
YUQUE_COOKIE_PLUGIN_CONFIG_DIR=/tmp/yuque-plugin-real-test yuque-local auth status --json
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
这会把配置保存到 `/tmp/yuque-plugin-real-test/config.json`,不会影响默认的 `~/.config/yuque-cookie-plugin/config.json`。
|
|
89
|
+
|
|
81
90
|
也可以用环境变量覆盖本地配置:
|
|
82
91
|
|
|
83
92
|
```bash
|
|
@@ -98,6 +107,12 @@ npm run yuque-local -- auth status https://www.yuque.com/<your-login>/<your-book
|
|
|
98
107
|
yuque-local auth login --manual
|
|
99
108
|
```
|
|
100
109
|
|
|
110
|
+
清理本机保存的 Cookie:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
yuque-local auth logout
|
|
114
|
+
```
|
|
115
|
+
|
|
101
116
|
也可以一次性传入参数,适合本地受控脚本:
|
|
102
117
|
|
|
103
118
|
```bash
|
|
@@ -115,6 +130,12 @@ yuque-local auth login --manual \
|
|
|
115
130
|
npm run yuque-local -- book inspect https://www.yuque.com/<your-login>/<your-book>
|
|
116
131
|
```
|
|
117
132
|
|
|
133
|
+
列出当前账号可访问的知识库:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
yuque-local book list --json
|
|
137
|
+
```
|
|
138
|
+
|
|
118
139
|
下载整个知识库:
|
|
119
140
|
|
|
120
141
|
```bash
|
|
@@ -234,6 +255,7 @@ npm run real:acceptance -- \
|
|
|
234
255
|
## 文档
|
|
235
256
|
|
|
236
257
|
- `docs/usage-zh.md`:中文完整使用指南
|
|
258
|
+
- `docs/ai-dialogue-test-cases.md`:用户和 AI 对话测试用例
|
|
237
259
|
- `docs/real-acceptance.md`:真实语雀验收流程
|
|
238
260
|
- `docs/native-lake-capability.md`:原生 Lake 能力矩阵
|
|
239
261
|
- `docs/development-plan.md`:开发计划和迭代日志
|
|
@@ -246,6 +268,7 @@ npm run real:acceptance -- \
|
|
|
246
268
|
|
|
247
269
|
- 不要把真实 `_yuque_session` 或 `yuque_ctoken` 写入项目文件。
|
|
248
270
|
- 不要提交 `~/.config/yuque-cookie-plugin/config.json`。
|
|
271
|
+
- 需要清理本机凭据时运行 `yuque-local auth logout`。
|
|
249
272
|
- `reports/`、`backups/`、`node_modules/` 已被 `.gitignore` 忽略。
|
|
250
273
|
- 批量写入前先对单篇文档做真实实验。
|
|
251
274
|
- 不确定 Lake 语义时,先 snapshot,再 diff,再实现。
|
package/dist/auth.js
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
import { createServer } from 'node:http';
|
|
2
2
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
-
import { chmod, mkdir, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { chmod, mkdir, rm, writeFile } from 'node:fs/promises';
|
|
4
4
|
import { execFile } from 'node:child_process';
|
|
5
5
|
import { createInterface } from 'node:readline/promises';
|
|
6
6
|
import os from 'node:os';
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import process from 'node:process';
|
|
9
|
-
const
|
|
10
|
-
|
|
9
|
+
export const CONFIG_DIR_ENV = 'YUQUE_COOKIE_PLUGIN_CONFIG_DIR';
|
|
10
|
+
export function getConfigDirPath() {
|
|
11
|
+
const override = process.env[CONFIG_DIR_ENV]?.trim();
|
|
12
|
+
return override ? path.resolve(override) : path.join(os.homedir(), '.config', 'yuque-cookie-plugin');
|
|
13
|
+
}
|
|
11
14
|
export function getConfigFilePath() {
|
|
12
|
-
return
|
|
15
|
+
return path.join(getConfigDirPath(), 'config.json');
|
|
16
|
+
}
|
|
17
|
+
export async function clearSavedCredentials() {
|
|
18
|
+
const configFile = getConfigFilePath();
|
|
19
|
+
const existed = existsSync(configFile);
|
|
20
|
+
await rm(configFile, { force: true });
|
|
21
|
+
return {
|
|
22
|
+
config_file: configFile,
|
|
23
|
+
removed: existed
|
|
24
|
+
};
|
|
13
25
|
}
|
|
14
26
|
export function getCredentials(flags = {}) {
|
|
15
27
|
const envSession = process.env[String(flags.sessionEnv || 'YUQUE_SESSION')];
|
|
@@ -26,9 +38,9 @@ export function getCredentials(flags = {}) {
|
|
|
26
38
|
}
|
|
27
39
|
const saved = readSavedCredentials();
|
|
28
40
|
if (saved?.session && saved?.ctoken) {
|
|
29
|
-
return { ...saved, extraCookies: { ...(saved.extraCookies || {}), ...extraCookies }, source:
|
|
41
|
+
return { ...saved, extraCookies: { ...(saved.extraCookies || {}), ...extraCookies }, source: getConfigFilePath() };
|
|
30
42
|
}
|
|
31
|
-
throw new Error('Missing Yuque credentials. Run "yuque-local login" to configure them in your browser.');
|
|
43
|
+
throw new Error('Missing Yuque credentials. Run "yuque-local auth login" to configure them in your browser.');
|
|
32
44
|
}
|
|
33
45
|
export function getCredentialStatus(flags = {}) {
|
|
34
46
|
const envSession = process.env[String(flags.sessionEnv || 'YUQUE_SESSION')];
|
|
@@ -48,12 +60,12 @@ export function getCredentialStatus(flags = {}) {
|
|
|
48
60
|
if (!saved?.session || !saved?.ctoken) {
|
|
49
61
|
return {
|
|
50
62
|
configured: false,
|
|
51
|
-
source:
|
|
63
|
+
source: getConfigFilePath()
|
|
52
64
|
};
|
|
53
65
|
}
|
|
54
66
|
return {
|
|
55
67
|
configured: true,
|
|
56
|
-
source:
|
|
68
|
+
source: getConfigFilePath(),
|
|
57
69
|
home_url: saved.homeUrl || null,
|
|
58
70
|
saved_at: saved.saved_at || null,
|
|
59
71
|
updated_at: saved.updated_at || null,
|
|
@@ -103,7 +115,7 @@ export async function loginWithBrowser(flags = {}) {
|
|
|
103
115
|
await openBrowser(result.url);
|
|
104
116
|
const credentials = await result.done;
|
|
105
117
|
await saveCredentials(credentials);
|
|
106
|
-
console.log(`Saved Yuque credentials to ${
|
|
118
|
+
console.log(`Saved Yuque credentials to ${getConfigFilePath()}`);
|
|
107
119
|
}
|
|
108
120
|
export async function loginManually(flags = {}) {
|
|
109
121
|
const sessionFromFlag = typeof flags.session === 'string' ? flags.session.trim() : '';
|
|
@@ -116,7 +128,7 @@ export async function loginManually(flags = {}) {
|
|
|
116
128
|
homeUrl: normalizeYuqueHomeUrl(homeUrlFromFlag),
|
|
117
129
|
saved_at: new Date().toISOString()
|
|
118
130
|
});
|
|
119
|
-
console.log(`Saved Yuque credentials to ${
|
|
131
|
+
console.log(`Saved Yuque credentials to ${getConfigFilePath()}`);
|
|
120
132
|
return;
|
|
121
133
|
}
|
|
122
134
|
if (!process.stdin.isTTY) {
|
|
@@ -137,17 +149,18 @@ export async function loginManually(flags = {}) {
|
|
|
137
149
|
homeUrl: normalizeYuqueHomeUrl(homeUrlInput.trim()),
|
|
138
150
|
saved_at: new Date().toISOString()
|
|
139
151
|
});
|
|
140
|
-
console.log(`Saved Yuque credentials to ${
|
|
152
|
+
console.log(`Saved Yuque credentials to ${getConfigFilePath()}`);
|
|
141
153
|
}
|
|
142
154
|
finally {
|
|
143
155
|
rl.close();
|
|
144
156
|
}
|
|
145
157
|
}
|
|
146
158
|
function readSavedCredentials() {
|
|
147
|
-
|
|
159
|
+
const configFile = getConfigFilePath();
|
|
160
|
+
if (!existsSync(configFile))
|
|
148
161
|
return null;
|
|
149
162
|
try {
|
|
150
|
-
return JSON.parse(readFileSync(
|
|
163
|
+
return JSON.parse(readFileSync(configFile, 'utf8'));
|
|
151
164
|
}
|
|
152
165
|
catch {
|
|
153
166
|
return null;
|
|
@@ -155,14 +168,16 @@ function readSavedCredentials() {
|
|
|
155
168
|
}
|
|
156
169
|
async function saveCredentials(credentials) {
|
|
157
170
|
const now = new Date().toISOString();
|
|
171
|
+
const configDir = getConfigDirPath();
|
|
172
|
+
const configFile = getConfigFilePath();
|
|
158
173
|
const data = {
|
|
159
174
|
...credentials,
|
|
160
175
|
saved_at: credentials.saved_at || now,
|
|
161
176
|
updated_at: now
|
|
162
177
|
};
|
|
163
|
-
await mkdir(
|
|
164
|
-
await writeFile(
|
|
165
|
-
await chmod(
|
|
178
|
+
await mkdir(configDir, { recursive: true, mode: 0o700 });
|
|
179
|
+
await writeFile(configFile, `${JSON.stringify(data, null, 2)}\n`, { mode: 0o600 });
|
|
180
|
+
await chmod(configFile, 0o600);
|
|
166
181
|
}
|
|
167
182
|
function ageHours(value) {
|
|
168
183
|
if (!value)
|
|
@@ -318,6 +333,7 @@ function sendHtml(res, html, status = 200) {
|
|
|
318
333
|
res.end(html);
|
|
319
334
|
}
|
|
320
335
|
function loginPage(error = '') {
|
|
336
|
+
const configFile = getConfigFilePath();
|
|
321
337
|
return `<!doctype html>
|
|
322
338
|
<html lang="zh-CN">
|
|
323
339
|
<head>
|
|
@@ -362,7 +378,7 @@ function loginPage(error = '') {
|
|
|
362
378
|
<p>本地保存语雀网页 Session,让 CLI 使用浏览器同款 Cookie 访问语雀。</p>
|
|
363
379
|
</div>
|
|
364
380
|
<div class="facts">
|
|
365
|
-
<div class="fact"><strong>保存位置</strong><span
|
|
381
|
+
<div class="fact"><strong>保存位置</strong><span>${escapeHtml(configFile)}</span></div>
|
|
366
382
|
<div class="fact"><strong>安全边界</strong><span>只写入本机配置,不写入项目仓库。</span></div>
|
|
367
383
|
<div class="fact"><strong>失效处理</strong><span>后续可用 auth-status 检测并提示重新登录。</span></div>
|
|
368
384
|
</div>
|
package/dist/cli.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import process from 'node:process';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import { cp, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { cp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
5
5
|
import { existsSync } from 'node:fs';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { YuqueCookieClient } from "./client-cookie.js";
|
|
8
8
|
import { diffLakeSnapshots } from "./lake-diff.js";
|
|
9
9
|
import { writeJson } from "./fs-utils.js";
|
|
10
|
-
import { getConfigFilePath, getCredentialStatus, getCredentials, loginWithBrowser, recordCredentialValidation } from "./auth.js";
|
|
10
|
+
import { clearSavedCredentials, getConfigFilePath, getCredentialStatus, getCredentials, loginWithBrowser, recordCredentialValidation } from "./auth.js";
|
|
11
11
|
import { serializeHtmlToLake } from "./editor-bridge.js";
|
|
12
12
|
import { snapshotToMarkdown } from "./lake-markdown.js";
|
|
13
13
|
import { downloadBook, downloadDocs } from "./downloader.js";
|
|
@@ -22,9 +22,11 @@ function help() {
|
|
|
22
22
|
Usage:
|
|
23
23
|
yuque-local --version
|
|
24
24
|
yuque-local auth login [--manual]
|
|
25
|
+
yuque-local auth logout [--json]
|
|
25
26
|
yuque-local auth status [doc-or-book-url] [--json]
|
|
26
27
|
yuque-local doctor [--json]
|
|
27
|
-
yuque-local skill install|status [--json]
|
|
28
|
+
yuque-local skill install|status|uninstall [--json]
|
|
29
|
+
yuque-local book list [--json]
|
|
28
30
|
yuque-local book create --name <name> --slug <slug> [--description <text>] [--public]
|
|
29
31
|
yuque-local book download <book-url> [--dist-dir download] [--incremental]
|
|
30
32
|
yuque-local doc create <book-url> --title <title> --markdown-file <file> [--number-headings]
|
|
@@ -131,9 +133,11 @@ function normalizeInvocation(argv) {
|
|
|
131
133
|
const grouped = {
|
|
132
134
|
auth: {
|
|
133
135
|
login: 'login',
|
|
136
|
+
logout: 'logout',
|
|
134
137
|
status: 'auth-status'
|
|
135
138
|
},
|
|
136
139
|
book: {
|
|
140
|
+
list: 'list-books',
|
|
137
141
|
create: 'create-book',
|
|
138
142
|
download: 'download-book',
|
|
139
143
|
inspect: 'inspect'
|
|
@@ -286,9 +290,24 @@ async function commandSkill(action, flags) {
|
|
|
286
290
|
console.log(JSON.stringify(data, null, 2));
|
|
287
291
|
return;
|
|
288
292
|
}
|
|
293
|
+
const source = path.join(PACKAGE_ROOT, 'skills', 'yuque-cookie-plugin');
|
|
294
|
+
if (action === 'uninstall') {
|
|
295
|
+
const targets = skillTargets();
|
|
296
|
+
const removed = [];
|
|
297
|
+
for (const target of targets) {
|
|
298
|
+
const existed = existsSync(path.join(target, 'SKILL.md'));
|
|
299
|
+
await rm(target, { recursive: true, force: true });
|
|
300
|
+
removed.push({ path: target, removed: existed });
|
|
301
|
+
}
|
|
302
|
+
const data = { removed };
|
|
303
|
+
if (flags.json)
|
|
304
|
+
printJsonResult(jsonResult('success', 'skill uninstalled', data));
|
|
305
|
+
else
|
|
306
|
+
console.log(JSON.stringify(data, null, 2));
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
289
309
|
if (action !== 'install')
|
|
290
310
|
throw new Error(`Unknown skill action: ${action}`);
|
|
291
|
-
const source = path.join(PACKAGE_ROOT, 'skills', 'yuque-cookie-plugin');
|
|
292
311
|
if (!existsSync(path.join(source, 'SKILL.md')))
|
|
293
312
|
throw new Error(`Skill source is missing: ${source}`);
|
|
294
313
|
const installed = [];
|
|
@@ -371,6 +390,17 @@ async function main() {
|
|
|
371
390
|
await loginWithBrowser(flags);
|
|
372
391
|
return;
|
|
373
392
|
}
|
|
393
|
+
if (command === 'logout') {
|
|
394
|
+
const result = await clearSavedCredentials();
|
|
395
|
+
printCommandResult({
|
|
396
|
+
ok: true,
|
|
397
|
+
...result,
|
|
398
|
+
note: process.env.YUQUE_SESSION || process.env.YUQUE_CTOKEN
|
|
399
|
+
? 'Environment credentials are still set in the current shell.'
|
|
400
|
+
: undefined
|
|
401
|
+
}, flags, 'auth credentials cleared');
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
374
404
|
if (command === 'doctor') {
|
|
375
405
|
await commandDoctor(flags);
|
|
376
406
|
return;
|
|
@@ -435,6 +465,12 @@ async function main() {
|
|
|
435
465
|
printCommandResult(info, flags, 'inspect completed');
|
|
436
466
|
return;
|
|
437
467
|
}
|
|
468
|
+
if (command === 'list-books') {
|
|
469
|
+
const result = await client.listBooks();
|
|
470
|
+
await recordCredentialValidation(true);
|
|
471
|
+
printCommandResult(result, flags, 'book list completed');
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
438
474
|
if (command === 'snapshot') {
|
|
439
475
|
const [url] = positional;
|
|
440
476
|
if (!url)
|
package/dist/client-cookie.js
CHANGED
|
@@ -54,6 +54,17 @@ export class YuqueCookieClient {
|
|
|
54
54
|
const appData = await this.fetchAppData(url);
|
|
55
55
|
return summarizeAppData(appData);
|
|
56
56
|
}
|
|
57
|
+
async listBooks() {
|
|
58
|
+
const result = await this.requestJson('GET', '/api/mine/books?offset=0&limit=100', undefined, `${this.host}/dashboard`);
|
|
59
|
+
const books = normalizeBookListResponse(result)
|
|
60
|
+
.map((book) => normalizeBookSummary(book, this.host))
|
|
61
|
+
.filter((book) => Boolean(book));
|
|
62
|
+
return {
|
|
63
|
+
ok: true,
|
|
64
|
+
count: books.length,
|
|
65
|
+
books
|
|
66
|
+
};
|
|
67
|
+
}
|
|
57
68
|
async getBookInfo(url) {
|
|
58
69
|
const appData = await this.fetchAppData(url);
|
|
59
70
|
if (!appData.book?.id)
|
|
@@ -490,6 +501,40 @@ function buildDocUrl(host, appData, book, doc) {
|
|
|
490
501
|
return `${host}/${bookSlug}/${docSlug}`;
|
|
491
502
|
return `${host}/api/docs/${doc.id || ''}`;
|
|
492
503
|
}
|
|
504
|
+
function normalizeBookListResponse(result) {
|
|
505
|
+
const data = result.data;
|
|
506
|
+
if (Array.isArray(data))
|
|
507
|
+
return data;
|
|
508
|
+
if (Array.isArray(data?.books))
|
|
509
|
+
return data.books;
|
|
510
|
+
if (Array.isArray(data?.repos))
|
|
511
|
+
return data.repos;
|
|
512
|
+
if (Array.isArray(result.books))
|
|
513
|
+
return result.books;
|
|
514
|
+
if (Array.isArray(result.repos))
|
|
515
|
+
return result.repos;
|
|
516
|
+
return [];
|
|
517
|
+
}
|
|
518
|
+
function normalizeBookSummary(book, host) {
|
|
519
|
+
const slug = typeof book.slug === 'string' ? book.slug : '';
|
|
520
|
+
const login = typeof book.login === 'string'
|
|
521
|
+
? book.login
|
|
522
|
+
: typeof book.user?.login === 'string'
|
|
523
|
+
? book.user.login
|
|
524
|
+
: undefined;
|
|
525
|
+
if (!slug)
|
|
526
|
+
return null;
|
|
527
|
+
return {
|
|
528
|
+
id: typeof book.id === 'number' ? book.id : undefined,
|
|
529
|
+
name: typeof book.name === 'string' ? book.name : slug,
|
|
530
|
+
slug,
|
|
531
|
+
login,
|
|
532
|
+
public: typeof book.public === 'number' || typeof book.public === 'boolean' ? book.public : undefined,
|
|
533
|
+
items_count: typeof book.items_count === 'number' ? book.items_count : undefined,
|
|
534
|
+
updated_at: typeof book.updated_at === 'string' ? book.updated_at : undefined,
|
|
535
|
+
url: login ? `${host}/${login}/${slug}` : `${host}/${slug}`
|
|
536
|
+
};
|
|
537
|
+
}
|
|
493
538
|
function guessContentType(fileName) {
|
|
494
539
|
const ext = extname(fileName).toLowerCase();
|
|
495
540
|
const types = {
|
package/docs/usage-zh.md
CHANGED
|
@@ -17,6 +17,21 @@
|
|
|
17
17
|
|
|
18
18
|
项目目录不会保存真实 Cookie。
|
|
19
19
|
|
|
20
|
+
如果需要把全局 npm 版、源码开发版、Docker 或 AI 真实测试环境隔离开,可以通过 `YUQUE_COOKIE_PLUGIN_CONFIG_DIR` 指定独立配置目录:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
YUQUE_COOKIE_PLUGIN_CONFIG_DIR=/tmp/yuque-plugin-real-test yuque-local auth login
|
|
24
|
+
YUQUE_COOKIE_PLUGIN_CONFIG_DIR=/tmp/yuque-plugin-real-test yuque-local auth status --json
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
指定后,Cookie 会保存到:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
/tmp/yuque-plugin-real-test/config.json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
不会影响默认的 `~/.config/yuque-cookie-plugin/config.json`。
|
|
34
|
+
|
|
20
35
|
## 2. 安装和准备
|
|
21
36
|
|
|
22
37
|
普通用户推荐从 npm 安装:
|
|
@@ -97,6 +112,18 @@ Docker、SSH、远程服务器等无头环境中,推荐使用手动模式,
|
|
|
97
112
|
yuque-local auth login --manual
|
|
98
113
|
```
|
|
99
114
|
|
|
115
|
+
清理本机保存的 Cookie:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
yuque-local auth logout
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
如果你使用了隔离配置目录,清理时也要带上同一个环境变量:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
YUQUE_COOKIE_PLUGIN_CONFIG_DIR=/tmp/yuque-plugin-real-test yuque-local auth logout
|
|
125
|
+
```
|
|
126
|
+
|
|
100
127
|
正常执行 `inspect`、`snapshot`、`download-book`、`download-doc` 等真实语雀命令成功后,也会刷新 `last_validated_at`。如果检测到 401、403、页面无法解析等登录态问题,CLI 会提示重新登录。
|
|
101
128
|
|
|
102
129
|
### 额外 Cookie
|
|
@@ -123,7 +150,38 @@ export YUQUE_EXTRA_COOKIE_VALUE='<cookie-value>'
|
|
|
123
150
|
|
|
124
151
|
额外 Cookie 不会改变本项目的主链路,只用于兼容特殊访问场景。
|
|
125
152
|
|
|
126
|
-
## 4.
|
|
153
|
+
## 4. 列出知识库
|
|
154
|
+
|
|
155
|
+
查看当前账号可访问的语雀知识库:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
yuque-local book list --json
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
这个命令会通过网页 Session 调用语雀列表接口,只输出知识库摘要,不会打印本机配置文件或 Cookie。
|
|
162
|
+
|
|
163
|
+
输出示例:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"status": "success",
|
|
168
|
+
"message": "book list completed",
|
|
169
|
+
"data": {
|
|
170
|
+
"ok": true,
|
|
171
|
+
"count": 2,
|
|
172
|
+
"books": [
|
|
173
|
+
{
|
|
174
|
+
"name": "工控",
|
|
175
|
+
"slug": "ydv5i5",
|
|
176
|
+
"login": "your-login",
|
|
177
|
+
"url": "https://www.yuque.com/your-login/ydv5i5"
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## 5. 下载整个知识库
|
|
127
185
|
|
|
128
186
|
推荐先下载到临时目录验证:
|
|
129
187
|
|
|
@@ -228,7 +286,7 @@ AI 或脚本可以用 `retry.args` 只重试失败文档。
|
|
|
228
286
|
|
|
229
287
|
`resources.files` 只记录本地相对路径和大小,不保存 Cookie。
|
|
230
288
|
|
|
231
|
-
##
|
|
289
|
+
## 6. 创建知识库和文档
|
|
232
290
|
|
|
233
291
|
创建私密测试知识库:
|
|
234
292
|
|
|
@@ -255,7 +313,7 @@ npm run yuque-local -- create-doc https://www.yuque.com/<your-login>/<your-book>
|
|
|
255
313
|
- 不默认修改标题文本。
|
|
256
314
|
- 返回 JSON 中 `format` 表示语雀创建接口的初始格式;如果默认 Lake 写回成功,会额外返回 `final_format: "lake"`。
|
|
257
315
|
|
|
258
|
-
##
|
|
316
|
+
## 7. 上传和插入附件
|
|
259
317
|
|
|
260
318
|
只上传文件,不写入正文:
|
|
261
319
|
|
|
@@ -327,7 +385,7 @@ npm run yuque-local -- create-doc https://www.yuque.com/<your-login>/<your-book>
|
|
|
327
385
|
- 语雀会把 Markdown 创建结果自动转换成 Lake 文档,工具随后会默认写回 Lake,后续修改应按 Lake 链路处理。
|
|
328
386
|
- 当前原生写入能力矩阵见 `docs/native-lake-capability.md`。图片、附件、思维导图、画板属于下一阶段真实探索项,不能在未验证前手写 card。
|
|
329
387
|
|
|
330
|
-
##
|
|
388
|
+
## 8. 上传图片或附件探索
|
|
331
389
|
|
|
332
390
|
只上传本地文件,不写入正文:
|
|
333
391
|
|
|
@@ -386,7 +444,7 @@ npm run yuque-local -- insert-attachment https://www.yuque.com/user/book/doc \
|
|
|
386
444
|
|
|
387
445
|
和图片一样,`insert-attachment --dry-run` 会真实上传附件以获得语雀附件 URL,但不会修改文档正文。
|
|
388
446
|
|
|
389
|
-
##
|
|
447
|
+
## 9. 下载单篇或多篇文档
|
|
390
448
|
|
|
391
449
|
下载单篇:
|
|
392
450
|
|
|
@@ -403,7 +461,7 @@ npm run yuque-local -- download-doc \
|
|
|
403
461
|
--dist-dir /tmp/yuque-doc-test
|
|
404
462
|
```
|
|
405
463
|
|
|
406
|
-
##
|
|
464
|
+
## 10. 本地预览下载结果
|
|
407
465
|
|
|
408
466
|
只生成或检查 VitePress 配置,不启动长驻服务:
|
|
409
467
|
|
|
@@ -435,7 +493,7 @@ http://localhost:5173/
|
|
|
435
493
|
npm run yuque-local -- serve-book /tmp/yuque-download-test/工控 --port 5173 --force
|
|
436
494
|
```
|
|
437
495
|
|
|
438
|
-
##
|
|
496
|
+
## 11. 快照和差异比较
|
|
439
497
|
|
|
440
498
|
抓取语雀文档快照:
|
|
441
499
|
|
|
@@ -455,7 +513,7 @@ npm run yuque-local -- diff-lake /tmp/before.json /tmp/after.json
|
|
|
455
513
|
npm run yuque-local -- lake-to-markdown /tmp/doc.snapshot.json --out /tmp/doc.md
|
|
456
514
|
```
|
|
457
515
|
|
|
458
|
-
##
|
|
516
|
+
## 12. HTML 转语雀 Lake
|
|
459
517
|
|
|
460
518
|
把本地 HTML 交给语雀 Lake editor runtime 序列化:
|
|
461
519
|
|
|
@@ -471,7 +529,7 @@ npm run yuque-local -- editor-serialize --html-file article.html --out article.l
|
|
|
471
529
|
|
|
472
530
|
说明使用的是 vendored Lake editor,而不是 fallback。
|
|
473
531
|
|
|
474
|
-
##
|
|
532
|
+
## 13. 安全写入语雀文档
|
|
475
533
|
|
|
476
534
|
强烈建议先 dry-run:
|
|
477
535
|
|
|
@@ -497,7 +555,7 @@ backups/
|
|
|
497
555
|
reports/
|
|
498
556
|
```
|
|
499
557
|
|
|
500
|
-
##
|
|
558
|
+
## 14. 文章格式化流程
|
|
501
559
|
|
|
502
560
|
本地 HTML 到语雀文档的完整流程:
|
|
503
561
|
|
|
@@ -511,7 +569,7 @@ npm run yuque-local -- format-article https://www.yuque.com/user/book/doc --html
|
|
|
511
569
|
npm run yuque-local -- format-article https://www.yuque.com/user/book/doc --html-file article.html
|
|
512
570
|
```
|
|
513
571
|
|
|
514
|
-
##
|
|
572
|
+
## 15. 常用选项
|
|
515
573
|
|
|
516
574
|
忽略图片下载:
|
|
517
575
|
|
|
@@ -559,15 +617,16 @@ npm run yuque-local -- format-article https://www.yuque.com/user/book/doc --html
|
|
|
559
617
|
|
|
560
618
|
如果需要严格的 JSON 输出,建议加 `--quiet`。
|
|
561
619
|
|
|
562
|
-
##
|
|
620
|
+
## 16. 安全规则
|
|
563
621
|
|
|
564
622
|
- 不要把真实 `_yuque_session` 或 `yuque_ctoken` 写入项目文件。
|
|
565
623
|
- 不要提交 `~/.config/yuque-cookie-plugin/config.json`。
|
|
624
|
+
- 真实测试多个版本时,用 `YUQUE_COOKIE_PLUGIN_CONFIG_DIR` 隔离配置目录。
|
|
566
625
|
- 线上写入必须先 dry-run。
|
|
567
626
|
- 批量写入前先对单篇文档做实验。
|
|
568
627
|
- 章节编号不要直接改标题文本硬塞编号,必须先做 snapshot before/after diff。
|
|
569
628
|
|
|
570
|
-
##
|
|
629
|
+
## 17. 当前已验证场景
|
|
571
630
|
|
|
572
631
|
已真实验证:
|
|
573
632
|
|
|
@@ -578,7 +637,7 @@ npm run yuque-local -- format-article https://www.yuque.com/user/book/doc --html
|
|
|
578
637
|
- 第二次增量下载全部跳过。
|
|
579
638
|
- 导出文件名保留正常空格。
|
|
580
639
|
|
|
581
|
-
##
|
|
640
|
+
## 18. 当前未完全覆盖场景
|
|
582
641
|
|
|
583
642
|
仍需继续补齐:
|
|
584
643
|
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: yuque-cookie-plugin
|
|
3
3
|
description: Use when an AI agent needs to operate Yuque through the local yuque-local CLI with _yuque_session and yuque_ctoken, including login, auth status, inspect, snapshot, download, create, native Lake update, image/PDF insertion, and safe document formatting. This skill is for CLI orchestration, not MCP or Yuque OpenAPI token usage.
|
|
4
4
|
metadata:
|
|
5
|
-
version: "0.1.
|
|
5
|
+
version: "0.1.3"
|
|
6
6
|
author: "c-sunc6"
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -33,8 +33,10 @@ Legacy flat commands such as `yuque-local snapshot` and `yuque-local download-bo
|
|
|
33
33
|
```bash
|
|
34
34
|
yuque-local auth login
|
|
35
35
|
yuque-local auth login --manual
|
|
36
|
+
yuque-local auth logout --json
|
|
36
37
|
yuque-local auth status <doc-or-book-url> --json
|
|
37
38
|
yuque-local doctor --json
|
|
39
|
+
yuque-local book list --json
|
|
38
40
|
yuque-local book download <book-url> --dist-dir download --incremental --quiet --json
|
|
39
41
|
yuque-local doc download <doc-url> --dist-dir download --quiet --json
|
|
40
42
|
yuque-local doc create <book-url> --title "Title" --markdown-file article.md --number-headings --json
|
|
@@ -42,15 +44,17 @@ yuque-local doc snapshot <doc-url> --out /tmp/doc.snapshot.json --json
|
|
|
42
44
|
yuque-local doc apply-lake <doc-url> --lake-file body_asl.html --dry-run --json
|
|
43
45
|
yuque-local doc insert-image <doc-url> --file image.png --after-text "位置" --json
|
|
44
46
|
yuque-local doc insert-attachment <doc-url> --file file.pdf --after-text "附件" --json
|
|
47
|
+
yuque-local skill uninstall --json
|
|
45
48
|
```
|
|
46
49
|
|
|
47
50
|
## Workflow
|
|
48
51
|
|
|
49
52
|
1. Run `yuque-local doctor --json` to inspect local installation and credential state.
|
|
50
53
|
2. If credentials are missing or stale, ask the user to run `yuque-local auth login` or `yuque-local auth login --manual`.
|
|
51
|
-
3. For
|
|
52
|
-
4. For
|
|
53
|
-
5.
|
|
54
|
+
3. For book discovery, use `yuque-local book list --json`; do not read or print the local config file.
|
|
55
|
+
4. For reads and downloads, call the relevant `book` or `doc` command with `--json`.
|
|
56
|
+
5. For writes, snapshot first, prepare the change, run a dry run when available, then apply after user approval.
|
|
57
|
+
6. Save local reports and paths from the CLI result for later audit.
|
|
54
58
|
|
|
55
59
|
## References
|
|
56
60
|
|
|
@@ -14,6 +14,13 @@ auth.status:
|
|
|
14
14
|
example: "yuque-local auth status https://www.yuque.com/user/book --json"
|
|
15
15
|
reference: "reference/agent-spec.md"
|
|
16
16
|
|
|
17
|
+
auth.logout:
|
|
18
|
+
cli: "yuque-local auth logout"
|
|
19
|
+
description: "Remove saved local Yuque cookies from the user config file"
|
|
20
|
+
optional: ["--json"]
|
|
21
|
+
example: "yuque-local auth logout --json"
|
|
22
|
+
reference: "reference/agent-spec.md"
|
|
23
|
+
|
|
17
24
|
doctor:
|
|
18
25
|
cli: "yuque-local doctor"
|
|
19
26
|
description: "Inspect CLI version, runtime, auth config path, and skill install status"
|
|
@@ -28,6 +35,20 @@ skill.install:
|
|
|
28
35
|
example: "yuque-local skill install --json"
|
|
29
36
|
reference: "reference/agent-spec.md"
|
|
30
37
|
|
|
38
|
+
skill.uninstall:
|
|
39
|
+
cli: "yuque-local skill uninstall"
|
|
40
|
+
description: "Remove the installed yuque-cookie-plugin AI skill from local supported agent skill directories"
|
|
41
|
+
optional: ["--json"]
|
|
42
|
+
example: "yuque-local skill uninstall --json"
|
|
43
|
+
reference: "reference/agent-spec.md"
|
|
44
|
+
|
|
45
|
+
book.list:
|
|
46
|
+
cli: "yuque-local book list"
|
|
47
|
+
description: "List Yuque books available to the current cookie-authenticated account without printing local credential files"
|
|
48
|
+
optional: ["--json"]
|
|
49
|
+
example: "yuque-local book list --json"
|
|
50
|
+
reference: "reference/agent-spec.md"
|
|
51
|
+
|
|
31
52
|
book.download:
|
|
32
53
|
cli: "yuque-local book download"
|
|
33
54
|
description: "Download a Yuque knowledge base with resources and reports"
|
|
@@ -38,8 +38,24 @@ For Docker, SSH, or headless terminals:
|
|
|
38
38
|
yuque-local auth login --manual
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
To clear saved local cookies:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
yuque-local auth logout --json
|
|
45
|
+
```
|
|
46
|
+
|
|
41
47
|
Never request raw cookie values in the conversation.
|
|
42
48
|
|
|
49
|
+
## Book Discovery
|
|
50
|
+
|
|
51
|
+
Use the dedicated command:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
yuque-local book list --json
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Do not inspect, print, or copy the local `config.json` file to discover books. The CLI reads credentials internally and returns only book summaries.
|
|
58
|
+
|
|
43
59
|
## Safe Write Flow
|
|
44
60
|
|
|
45
61
|
1. Snapshot the online document.
|