gudong-content-cli 0.0.0-stage → 0.1.0

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.
@@ -0,0 +1,74 @@
1
+ /**
2
+ * 「好内容」云端文章快照 JSON 的 TS 镜像。
3
+ * 协议权威源:content-dong 仓库 intents/20261005-feature-agent-access.md(wire 契约)
4
+ * 与 lib/features/agent/content_snapshot.dart(Dart 实现)。
5
+ * 云端布局:{rootDir}/content-snapshot.json 单文件全量快照,App 唯一写者,CLI 只读。
6
+ *
7
+ * 改字段 = 跨端协议变更,动前先读 App 侧 content_snapshot.dart 的协议注释。
8
+ * wire 纪律:读端忽略未知字段、全字段可缺省(经 parseSnapshot 补默认值)、禁止严格校验。
9
+ */
10
+ export interface HighlightNoteJson {
11
+ id: string;
12
+ content: string;
13
+ /** 毫秒时间戳 */
14
+ createdAt: number;
15
+ updatedAt: number | null;
16
+ }
17
+ export interface ArticleNoteJson {
18
+ id: string;
19
+ content: string;
20
+ /** 毫秒时间戳 */
21
+ createdAt: number;
22
+ updatedAt: number | null;
23
+ }
24
+ export interface HighlightJson {
25
+ id: string;
26
+ /** 划线原文 */
27
+ text: string;
28
+ /** 线型:marker | straight | wavy */
29
+ type: string;
30
+ /** 颜色:red | purple | blue | green | yellow */
31
+ color: string;
32
+ /** 文内进度 0-1 */
33
+ percentage: number;
34
+ createdAt: number;
35
+ updatedAt: number | null;
36
+ /** 挂靠该划线的想法 */
37
+ notes: HighlightNoteJson[];
38
+ }
39
+ export interface ArticleJson {
40
+ id: string;
41
+ title: string;
42
+ author: string;
43
+ url: string;
44
+ /** 来源:wechat | jike | generic | manual | seed | link */
45
+ source: string;
46
+ /** 状态:unread | reading | finished */
47
+ status: string;
48
+ /** 阅读进度 0-1 */
49
+ readProgress: number;
50
+ starred: boolean;
51
+ /** 收录时间(毫秒) */
52
+ savedAt: number;
53
+ lastReadAt: number | null;
54
+ /** 纯文本摘要(App 侧剥 Markdown 后截前 120 字) */
55
+ excerpt: string;
56
+ highlights: HighlightJson[];
57
+ /** 文章级批注 */
58
+ articleNotes: ArticleNoteJson[];
59
+ }
60
+ export interface SnapshotJson {
61
+ kind?: string;
62
+ schemaVersion?: number;
63
+ exportedAt?: number;
64
+ articles?: ArticleJson[];
65
+ }
66
+ /** 解析后带默认值的快照(wire 纪律:缺省字段补默认,未知字段忽略) */
67
+ export interface Snapshot {
68
+ kind: string;
69
+ schemaVersion: number;
70
+ exportedAt: number;
71
+ articles: ArticleJson[];
72
+ }
73
+ /** 应用 wire 默认值;未知枚举值原样透传(读端不做严格校验)。 */
74
+ export declare function parseSnapshot(raw: SnapshotJson): Snapshot;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * 「好内容」云端文章快照 JSON 的 TS 镜像。
3
+ * 协议权威源:content-dong 仓库 intents/20261005-feature-agent-access.md(wire 契约)
4
+ * 与 lib/features/agent/content_snapshot.dart(Dart 实现)。
5
+ * 云端布局:{rootDir}/content-snapshot.json 单文件全量快照,App 唯一写者,CLI 只读。
6
+ *
7
+ * 改字段 = 跨端协议变更,动前先读 App 侧 content_snapshot.dart 的协议注释。
8
+ * wire 纪律:读端忽略未知字段、全字段可缺省(经 parseSnapshot 补默认值)、禁止严格校验。
9
+ */
10
+ function str(v, fallback = '') {
11
+ return typeof v === 'string' ? v : fallback;
12
+ }
13
+ function num(v, fallback = 0) {
14
+ return typeof v === 'number' && Number.isFinite(v) ? v : fallback;
15
+ }
16
+ function ms(v) {
17
+ return typeof v === 'number' && Number.isFinite(v) ? v : null;
18
+ }
19
+ function bool(v, fallback = false) {
20
+ return typeof v === 'boolean' ? v : fallback;
21
+ }
22
+ /** 应用 wire 默认值;未知枚举值原样透传(读端不做严格校验)。 */
23
+ export function parseSnapshot(raw) {
24
+ const articles = (Array.isArray(raw.articles) ? raw.articles : []).map((a) => ({
25
+ id: str(a?.id),
26
+ title: str(a?.title, '未命名文章'),
27
+ author: str(a?.author),
28
+ url: str(a?.url),
29
+ source: str(a?.source, 'generic'),
30
+ status: str(a?.status, 'unread'),
31
+ readProgress: num(a?.readProgress),
32
+ starred: bool(a?.starred),
33
+ savedAt: num(a?.savedAt),
34
+ lastReadAt: ms(a?.lastReadAt),
35
+ excerpt: str(a?.excerpt),
36
+ highlights: (Array.isArray(a?.highlights) ? a.highlights : []).map((h) => ({
37
+ id: str(h?.id),
38
+ text: str(h?.text),
39
+ type: str(h?.type, 'wavy'),
40
+ color: str(h?.color, 'red'),
41
+ percentage: num(h?.percentage),
42
+ createdAt: num(h?.createdAt),
43
+ updatedAt: ms(h?.updatedAt),
44
+ notes: (Array.isArray(h?.notes) ? h.notes : []).map((n) => ({
45
+ id: str(n?.id),
46
+ content: str(n?.content),
47
+ createdAt: num(n?.createdAt),
48
+ updatedAt: ms(n?.updatedAt),
49
+ })),
50
+ })),
51
+ articleNotes: (Array.isArray(a?.articleNotes) ? a.articleNotes : []).map((n) => ({
52
+ id: str(n?.id),
53
+ content: str(n?.content),
54
+ createdAt: num(n?.createdAt),
55
+ updatedAt: ms(n?.updatedAt),
56
+ })),
57
+ }));
58
+ return {
59
+ kind: str(raw?.kind, 'content-snapshot'),
60
+ schemaVersion: num(raw?.schemaVersion, 1),
61
+ exportedAt: num(raw?.exportedAt),
62
+ articles,
63
+ };
64
+ }
65
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/content/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAuEH,SAAS,GAAG,CAAC,CAAU,EAAE,QAAQ,GAAG,EAAE;IACpC,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC9C,CAAC;AAED,SAAS,GAAG,CAAC,CAAU,EAAE,QAAQ,GAAG,CAAC;IACnC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACpE,CAAC;AAED,SAAS,EAAE,CAAC,CAAU;IACpB,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAChE,CAAC;AAED,SAAS,IAAI,CAAC,CAAU,EAAE,QAAQ,GAAG,KAAK;IACxC,OAAO,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC/C,CAAC;AAED,uCAAuC;AACvC,MAAM,UAAU,aAAa,CAAC,GAAiB;IAC7C,MAAM,QAAQ,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7E,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC;QACd,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC;QAC7B,MAAM,EAAE,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC;QACtB,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC;QAChB,MAAM,EAAE,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC;QACjC,MAAM,EAAE,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC;QAChC,YAAY,EAAE,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC;QAClC,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC;QACzB,OAAO,EAAE,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC;QACxB,UAAU,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC;QAC7B,OAAO,EAAE,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC;QACxB,UAAU,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACzE,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC;YACd,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC;YAClB,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC;YAC1B,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC;YAC3B,UAAU,EAAE,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;YAC9B,SAAS,EAAE,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC;YAC5B,SAAS,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC;YAC3B,KAAK,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC1D,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC;gBACd,OAAO,EAAE,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC;gBACxB,SAAS,EAAE,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC;gBAC5B,SAAS,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC;aAC5B,CAAC,CAAC;SACJ,CAAC,CAAC;QACH,YAAY,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC/E,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC;YACd,OAAO,EAAE,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC;YACxB,SAAS,EAAE,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC;YAC5B,SAAS,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC;SAC5B,CAAC,CAAC;KACJ,CAAC,CAAC,CAAC;IAEJ,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,GAAG,EAAE,IAAI,EAAE,kBAAkB,CAAC;QACxC,aAAa,EAAE,GAAG,CAAC,GAAG,EAAE,aAAa,EAAE,CAAC,CAAC;QACzC,UAAU,EAAE,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC;QAChC,QAAQ;KACT,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,307 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs } from 'node:util';
3
+ import { createRequire } from 'node:module';
4
+ import { loadConfig, saveConfig, configExists, getConfigPath, getConfigDir } from './config.js';
5
+ import { createCloudProvider, SNAPSHOT_FILE } from './cloud/factory.js';
6
+ import { SnapshotFetcher, isValidDate } from './content/snapshot.js';
7
+ import { ContentService } from './content/service.js';
8
+ const require = createRequire(import.meta.url);
9
+ const VERSION = require('../package.json').version;
10
+ const STATUSES = ['unread', 'reading', 'finished'];
11
+ const COLORS = ['red', 'purple', 'blue', 'green', 'yellow'];
12
+ function printHelp() {
13
+ const text = `
14
+ gudong-content v${VERSION} — read your Good Content (好内容) article library from the command line.
15
+
16
+ Usage:
17
+ gudong-content articles [--status unread|reading|finished] [--starred] [--limit N]
18
+ gudong-content highlights [--article <id|title>] [--color red|purple|blue|green|yellow]
19
+ [--since yyyy-MM-dd] [--until yyyy-MM-dd] [--limit N]
20
+ gudong-content notes [--article <id|title>] [--limit N]
21
+ gudong-content search --query "关键词" [--limit N]
22
+ gudong-content stats
23
+ gudong-content config init Set up credentials (interactive or via flags)
24
+ gudong-content config show Show current config (secrets masked)
25
+ gudong-content config test Test connection to cloud storage
26
+ gudong-content --version
27
+ gudong-content --help
28
+
29
+ Examples:
30
+ gudong-content articles --status reading
31
+ gudong-content highlights --since 2026-10-01
32
+ gudong-content notes --limit 10
33
+ gudong-content search --query "设计"
34
+
35
+ All commands are READ-ONLY. Article data belongs to the user; never write to the cloud.
36
+ `;
37
+ console.log(text);
38
+ }
39
+ function output(data) {
40
+ console.log(JSON.stringify(data, null, 2));
41
+ }
42
+ function getService() {
43
+ const cfg = loadConfig();
44
+ const cloud = createCloudProvider(cfg);
45
+ const fetcher = new SnapshotFetcher(cloud, { timezone: cfg.timezone, cacheDir: getConfigDir() });
46
+ return { service: new ContentService(fetcher, cfg.timezone), cfg };
47
+ }
48
+ function getArg(args, key) {
49
+ const v = args[key];
50
+ return typeof v === 'string' ? v : undefined;
51
+ }
52
+ function getArgNumber(args, key) {
53
+ const v = args[key];
54
+ if (v === undefined)
55
+ return undefined;
56
+ const n = Number(v);
57
+ if (!Number.isFinite(n) || n <= 0)
58
+ fail(`--${key} must be a positive number, got: ${v}`);
59
+ return Math.floor(n);
60
+ }
61
+ function validateRange(args) {
62
+ for (const key of ['since', 'until']) {
63
+ const v = getArg(args, key);
64
+ if (v && !isValidDate(v))
65
+ fail(`--${key} must be yyyy-MM-dd, got: ${v}`);
66
+ }
67
+ }
68
+ // --- command handlers ---
69
+ async function cmdArticles(args) {
70
+ const status = getArg(args, 'status');
71
+ if (status && !STATUSES.includes(status)) {
72
+ return fail(`--status must be one of ${STATUSES.join('|')}, got: ${status}`);
73
+ }
74
+ const { service } = getService();
75
+ output(await service.articles({
76
+ status,
77
+ starred: args.starred === true,
78
+ limit: getArgNumber(args, 'limit'),
79
+ }));
80
+ }
81
+ async function cmdHighlights(args) {
82
+ validateRange(args);
83
+ const color = getArg(args, 'color');
84
+ if (color && !COLORS.includes(color)) {
85
+ return fail(`--color must be one of ${COLORS.join('|')}, got: ${color}`);
86
+ }
87
+ const { service } = getService();
88
+ output(await service.highlights({
89
+ article: getArg(args, 'article'),
90
+ color,
91
+ since: getArg(args, 'since'),
92
+ until: getArg(args, 'until'),
93
+ limit: getArgNumber(args, 'limit'),
94
+ }));
95
+ }
96
+ async function cmdNotes(args) {
97
+ const { service } = getService();
98
+ output(await service.notes({
99
+ article: getArg(args, 'article'),
100
+ limit: getArgNumber(args, 'limit'),
101
+ }));
102
+ }
103
+ async function cmdSearch(args) {
104
+ const query = getArg(args, 'query');
105
+ if (!query)
106
+ return fail('--query is required');
107
+ const { service } = getService();
108
+ output(await service.search(query, getArgNumber(args, 'limit') ?? 20));
109
+ }
110
+ async function cmdStats() {
111
+ const { service } = getService();
112
+ output(await service.stats());
113
+ }
114
+ // --- config commands ---
115
+ async function cmdConfigInit(args) {
116
+ const cloudType = getArg(args, 'cloud-type') ?? getArg(args, 'cloud_type');
117
+ if (!cloudType) {
118
+ console.log(`
119
+ gudong-content config init
120
+
121
+ Usage:
122
+ gudong-content config init --cloud-type webdav \\
123
+ --url https://dav.jianguoyun.com/dav \\
124
+ --username user \\
125
+ --password pass \\
126
+ [--root-dir GdContent] [--timezone Asia/Shanghai]
127
+
128
+ gudong-content config init --cloud-type s3 \\
129
+ --endpoint https://s3.example.com \\
130
+ --bucket my-bucket \\
131
+ --access-key AKID... \\
132
+ --secret-key SECRET... \\
133
+ [--region cn-south-1] [--force-path-style true] \\
134
+ [--root-dir GdContent] [--timezone Asia/Shanghai]
135
+ `);
136
+ return;
137
+ }
138
+ const rootDir = getArg(args, 'root-dir') ?? getArg(args, 'root_dir') ?? 'GdContent';
139
+ const timezone = getArg(args, 'timezone') ?? 'Asia/Shanghai';
140
+ const cfg = { cloud_type: cloudType, root_dir: rootDir, timezone };
141
+ if (cloudType === 's3') {
142
+ const endpoint = getArg(args, 'endpoint');
143
+ const bucket = getArg(args, 'bucket');
144
+ const accessKey = getArg(args, 'access-key') ?? getArg(args, 'access_key');
145
+ const secretKey = getArg(args, 'secret-key') ?? getArg(args, 'secret_key');
146
+ const region = getArg(args, 'region') ?? 'auto';
147
+ const forcePathStyle = args['force-path-style'] === undefined
148
+ ? true
149
+ : args['force-path-style'] === true || args['force-path-style'] === 'true';
150
+ if (!endpoint)
151
+ return fail('--endpoint is required');
152
+ if (!bucket)
153
+ return fail('--bucket is required');
154
+ if (!accessKey)
155
+ return fail('--access-key is required');
156
+ if (!secretKey)
157
+ return fail('--secret-key is required');
158
+ cfg.s3 = { endpoint, bucket, accessKey, secretKey, region, forcePathStyle };
159
+ }
160
+ else if (cloudType === 'webdav') {
161
+ const url = getArg(args, 'url');
162
+ const username = getArg(args, 'username');
163
+ const password = getArg(args, 'password');
164
+ if (!url)
165
+ return fail('--url is required');
166
+ if (!username)
167
+ return fail('--username is required');
168
+ if (!password)
169
+ return fail('--password is required');
170
+ cfg.webdav = { url, username, password };
171
+ }
172
+ else {
173
+ return fail(`unknown cloud type: ${cloudType}`);
174
+ }
175
+ saveConfig(cfg);
176
+ console.log(`Config saved to ${getConfigPath()}`);
177
+ }
178
+ async function cmdConfigShow() {
179
+ if (!configExists()) {
180
+ console.log('No config found. Run `gudong-content config init` first.');
181
+ return;
182
+ }
183
+ const { readFileSync } = await import('node:fs');
184
+ const cfg = JSON.parse(readFileSync(getConfigPath(), 'utf-8'));
185
+ if (cfg.s3) {
186
+ if (cfg.s3.accessKey)
187
+ cfg.s3.accessKey = mask(cfg.s3.accessKey);
188
+ if (cfg.s3.secretKey)
189
+ cfg.s3.secretKey = '***';
190
+ }
191
+ if (cfg.webdav) {
192
+ if (cfg.webdav.password)
193
+ cfg.webdav.password = '***';
194
+ }
195
+ output(cfg);
196
+ }
197
+ function mask(s) {
198
+ if (s.length <= 4)
199
+ return '***';
200
+ return s.slice(0, 2) + '***' + s.slice(-2);
201
+ }
202
+ async function cmdConfigTest() {
203
+ const { service, cfg } = getService();
204
+ const stats = await service.stats();
205
+ const latest = await service.articles({ limit: 1 });
206
+ const lastSaved = latest.articles[0] ?? null;
207
+ output({
208
+ status: 'ok',
209
+ cloud_type: cfg.cloudType,
210
+ root_dir: cfg.rootDir,
211
+ timezone: cfg.timezone,
212
+ snapshot_file: SNAPSHOT_FILE,
213
+ articles: stats.total_articles,
214
+ highlights: stats.total_highlights,
215
+ notes: stats.total_notes.total,
216
+ last_saved_at: lastSaved?.saved_at ?? null,
217
+ last_saved_date: lastSaved?.saved_date ?? null,
218
+ snapshot_exported_at: stats.snapshot_exported_at,
219
+ });
220
+ }
221
+ function fail(msg) {
222
+ console.error(`[gudong-content] ${msg}`);
223
+ process.exit(1);
224
+ }
225
+ // --- main ---
226
+ function main() {
227
+ const argv = process.argv.slice(2);
228
+ if (argv.length === 0 || argv[0] === '--help' || argv[0] === '-h') {
229
+ printHelp();
230
+ return;
231
+ }
232
+ if (argv[0] === '--version' || argv[0] === '-v') {
233
+ console.log(VERSION);
234
+ return;
235
+ }
236
+ const command = argv[0];
237
+ const rest = argv.slice(1);
238
+ if (command === 'config') {
239
+ const subCmd = rest[0] ?? '';
240
+ const configArgs = rest.slice(1);
241
+ const { values } = parseArgs({
242
+ args: configArgs,
243
+ options: {
244
+ 'cloud-type': { type: 'string' },
245
+ cloud_type: { type: 'string' },
246
+ endpoint: { type: 'string' },
247
+ bucket: { type: 'string' },
248
+ 'access-key': { type: 'string' },
249
+ access_key: { type: 'string' },
250
+ 'secret-key': { type: 'string' },
251
+ secret_key: { type: 'string' },
252
+ region: { type: 'string' },
253
+ 'force-path-style': { type: 'string' },
254
+ url: { type: 'string' },
255
+ username: { type: 'string' },
256
+ password: { type: 'string' },
257
+ 'root-dir': { type: 'string' },
258
+ root_dir: { type: 'string' },
259
+ timezone: { type: 'string' },
260
+ },
261
+ allowNegative: true,
262
+ });
263
+ if (subCmd === 'init') {
264
+ cmdConfigInit(values).catch((e) => fail(e.message));
265
+ }
266
+ else if (subCmd === 'show') {
267
+ cmdConfigShow().catch((e) => fail(e.message));
268
+ }
269
+ else if (subCmd === 'test') {
270
+ cmdConfigTest().catch((e) => fail(e.message));
271
+ }
272
+ else {
273
+ console.log('Usage: gudong-content config <init|show|test>');
274
+ }
275
+ return;
276
+ }
277
+ const { values } = parseArgs({
278
+ args: rest,
279
+ options: {
280
+ status: { type: 'string' },
281
+ starred: { type: 'boolean' },
282
+ article: { type: 'string' },
283
+ color: { type: 'string' },
284
+ limit: { type: 'string' },
285
+ since: { type: 'string' },
286
+ until: { type: 'string' },
287
+ query: { type: 'string' },
288
+ },
289
+ allowNegative: true,
290
+ });
291
+ const handlers = {
292
+ articles: (a) => cmdArticles(a),
293
+ highlights: (a) => cmdHighlights(a),
294
+ notes: (a) => cmdNotes(a),
295
+ search: (a) => cmdSearch(a),
296
+ stats: () => cmdStats(),
297
+ };
298
+ const handler = handlers[command];
299
+ if (!handler) {
300
+ console.error(`Unknown command: ${command}`);
301
+ printHelp();
302
+ process.exit(1);
303
+ }
304
+ handler(values).catch((e) => fail(e.message));
305
+ }
306
+ main();
307
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,51 @@
1
1
  {
2
2
  "name": "gudong-content-cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "CLI tool that lets AI agents read your Good Content (好内容) read-later library from S3/WebDAV. No MCP needed, just a command.",
5
+ "type": "module",
6
+ "bin": {
7
+ "gudong-content": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md",
12
+ "LICENSE",
13
+ "skills"
14
+ ],
15
+ "scripts": {
16
+ "clean": "rm -rf dist",
17
+ "build": "npm run clean && tsc -p tsconfig.json && chmod +x dist/index.js",
18
+ "dev": "tsx src/index.ts",
19
+ "start": "node dist/index.js",
20
+ "test": "vitest run",
21
+ "prepublishOnly": "npm test && npm run build"
22
+ },
23
+ "keywords": [
24
+ "content",
25
+ "read-later",
26
+ "articles",
27
+ "highlights",
28
+ "notes",
29
+ "cli",
30
+ "s3",
31
+ "webdav",
32
+ "local-first",
33
+ "ai",
34
+ "agent"
35
+ ],
36
+ "license": "MIT",
37
+ "engines": {
38
+ "node": ">=20.0.0"
39
+ },
40
+ "dependencies": {
41
+ "@aws-sdk/client-s3": "^3.700.0",
42
+ "webdav": "^5.8.0"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^22.0.0",
46
+ "prettier": "^3.3.0",
47
+ "tsx": "^4.19.0",
48
+ "typescript": "^5.6.0",
49
+ "vitest": "^2.1.0"
50
+ }
51
+ }
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: gudong-content
3
+ slug: gudong-content
4
+ displayName: 好内容文章助手
5
+ summary: 读取用户的「好内容」收藏与精读数据(本地优先稍后读/文章精读 App,云端 WebDAV/S3 快照同步):收藏清单与进度回顾、划线金句回味、想法串联与阅读观察。
6
+ description: 读取用户的「好内容」文章收藏与精读数据(本地优先稍后读/文章精读 App,云端 WebDAV/S3 快照同步)。当用户提到收藏的文章、稍后读清单、文章读到哪了、阅读进度、划线金句、文章想法/批注、收藏回顾、阅读周报、阅读观察时使用此 skill。依赖 gudong-content CLI(npm install -g gudong-content-cli)与用户自备云盘。当前版本全部命令只读。
7
+ license: MIT
8
+ version: 0.1.0
9
+ ---
10
+
11
+ # 好内容(Good Content)文章助手
12
+
13
+ 通过 `gudong-content` 命令行工具读用户的「好内容」收藏与精读数据(本地优先稍后读 App,文章快照通过用户自己的 WebDAV/S3 云盘同步)。收藏与划线想法是用户的私人印记,请严格遵守本文件的安全规则。**当前版本全部命令只读,没有任何写命令。**
14
+
15
+ 用户最常见的诉求是三类,都基于真实数据完成,**绝不编造数字**:
16
+
17
+ 1. **收藏清单与进度回顾**:收了哪些文章、哪些还没读、哪些读到一半、哪些读完了、哪些标了星。
18
+ 2. **划线金句回味**:翻一翻划过的原文,按文章、颜色、时间过滤着看。
19
+ 3. **想法串联与阅读观察**:把想法(划线想法 + 文章批注)串起来看,基于数据做收藏周报与阅读观察。
20
+
21
+ ## 前置检查
22
+
23
+ 首次使用前,先检查 CLI 是否安装、配置是否就绪:
24
+
25
+ ```bash
26
+ gudong-content --version # 确认 CLI 已安装
27
+ gudong-content config show # 查看当前配置(密钥已脱敏)
28
+ ```
29
+
30
+ 如果提示命令找不到或配置不存在,走「安装和配置」流程。
31
+
32
+ ## 命令清单
33
+
34
+ | 操作 | 命令 | 用途 |
35
+ |------|------|------|
36
+ | 文章清单 | `gudong-content articles [--status unread\|reading\|finished] [--starred] [--limit N]` | 标题/来源/进度/星标/计数(收录时间倒序) |
37
+ | 划线 | `gudong-content highlights [--article <id\|标题>] [--color red\|purple\|blue\|green\|yellow] [--since ...] [--until ...] [--limit N]` | 划线原文(时间倒序) |
38
+ | 想法 | `gudong-content notes [--article <id\|标题>] [--limit N]` | 划线想法(带原文)+ 文章批注(时间倒序) |
39
+ | 搜索 | `gudong-content search --query "关键词" [--limit N]` | 标题 + 摘要 + 划线原文 + 想法全文 |
40
+ | 统计 | `gudong-content stats` | 状态分布/划线想法总数/阅读天数/估算时长/积压未读 |
41
+ | 查看配置 | `gudong-content config show` | 密钥已脱敏 |
42
+ | 测试连接 | `gudong-content config test` | 验证云盘连通(附数据概览) |
43
+
44
+ ## 参数速查
45
+
46
+ ### articles
47
+ `--status unread|reading|finished`(可选)、`--starred`(布尔开关,只要标星的)、`--limit`(默认 50)。输出里 `count` 是命中总数,`articles` 是截断后的列表;每条带 `read_progress`、`highlights_count`、`notes_count`(划线想法)、`article_notes_count`(文章批注)、`saved_date`/`last_read_date`。来源 `source` 常见值:wechat / jike / generic / manual / seed / link。
48
+
49
+ ### highlights / notes
50
+ `--article`(可选,id 或标题,支持子串模糊匹配)、`--color`(highlights 专属:red|purple|blue|green|yellow)、`--since`/`--until`(yyyy-MM-dd 闭区间)、`--limit`(默认 50)。
51
+
52
+ notes 是两类想法合一:`kind=highlight_note` 的条目带 `quote_text`(挂靠的划线原文),讲想法时连原文一起引用;`kind=article_note` 是文章级批注,没有挂靠原文。
53
+
54
+ ### search
55
+ `--query` 必填(大小写不敏感子串匹配)。命中项的 `matched_fields` 标明命中字段:文章是 `title`/`excerpt`,划线是 `text`,想法是 `content`。
56
+
57
+ ### stats
58
+ 口径与 App 完全一致:`estimated_hours` 是估算值(finished×0.4h + reading×0.2h + 字数估算),**不是计时数据,汇报时要说「约」**;`days_read` 是有阅读记录的自然日数;`stale_unread` 是收藏超 14 天未读的积压;`snapshot_exported_at` 是快照生成时间。
59
+
60
+ ## 输出格式
61
+
62
+ 所有命令成功时 exit code = 0,stdout 输出 JSON,直接解析。失败 exit 1,stderr 给出错误。没有 exit 2(无写操作就没有冲突语义)。
63
+
64
+ ## 典型任务怎么做
65
+
66
+ **收藏回顾**(用户说「我最近收了些什么」):`articles --limit 20`,按 `saved_date` 归组讲;追问进度就 `articles --status reading`,追问积压就 `stats` 看 `stale_unread`。
67
+
68
+ **金句回味**(用户说「挑几条划线」):`highlights --since ... --until ...` 按时间窗取,或 `--article` 限定单篇;想按主题挑就 `--color` 过滤。引用时用 `text` 原文。
69
+
70
+ **想法串联**(用户说「我最近的想法」):`notes --limit N`,highlight_note 连 `quote_text` 原文一起讲,article_note 单独讲;可以按 `article_title` 归组。
71
+
72
+ **阅读观察**(用户说「给我点观察」):跨 `stats` + `articles` + `highlights` 找事实依据,只陈述数据支持的事。比如「收藏 30 篇只读完 5 篇,还有 8 篇超过两周没碰」「这周划了 12 条金句但只写了 2 条想法」。**没有数据支持的判断不要说。**
73
+
74
+ ## 安全规则(必须遵守)
75
+
76
+ 收藏与划线想法是用户的私人印记。**读取免确认(当前版本也只有读),但隐私红线必须守住:**
77
+
78
+ 1. **绝不编造数字**:所有进度、天数、计数都来自命令输出;命令失败就说失败,不要用想象补齐。
79
+ 2. **隐私不外传**:不把文章标题、划线、想法复述到任何外部渠道(发邮件、发消息、上传文件等)。
80
+ 3. **不打印云盘凭据**:config show 已脱敏,不要尝试读取或展示 ~/.gudong-content/config.json 原文。
81
+ 4. **只读边界**:当前版本没有写命令;如果用户要求「帮我把想法记回文章」,如实说明 App 侧暂未开放,引导用户回到 App 操作。
82
+ 5. 数据可能不是最新:输出里有 `snapshot_exported_at`(快照生成时间),与当前时间差太远时提醒用户「打开好内容让它同步一下」。
83
+
84
+ ## 安装和配置
85
+
86
+ 如果 `gudong-content` 未安装或未配置:
87
+
88
+ ```bash
89
+ # 安装 CLI
90
+ npm install -g gudong-content-cli@latest
91
+
92
+ # 配置(WebDAV 示例——坚果云等)
93
+ gudong-content config init \
94
+ --cloud-type webdav \
95
+ --url https://dav.jianguoyun.com/dav \
96
+ --username user@example.com \
97
+ --password 应用密码 \
98
+ --root-dir GdContent \
99
+ --timezone Asia/Shanghai
100
+
101
+ # 验证
102
+ gudong-content config test
103
+ ```
104
+
105
+ 凭据与「好内容」App「我的 → 多端云同步」里配置的同一套,`root-dir` 与 App 云盘目录一致(家族 Gd 命名规范:默认 `GdContent`,开发包为 `GdContentDebug`;以 `gudong-content config show` 与 App 内目录为准)。配置保存在 `~/.gudong-content/config.json`(chmod 600),也支持环境变量回退(`CONTENT_CLOUD_TYPE`、`CONTENT_WEBDAV_URL` 等)。