read-cli 0.2.0__tar.gz

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.
Files changed (55) hide show
  1. read_cli-0.2.0/.gitignore +23 -0
  2. read_cli-0.2.0/ARCHITECTURE.md +574 -0
  3. read_cli-0.2.0/CLAUDE.md +280 -0
  4. read_cli-0.2.0/CONTRIBUTING.md +82 -0
  5. read_cli-0.2.0/LICENSE +21 -0
  6. read_cli-0.2.0/PKG-INFO +218 -0
  7. read_cli-0.2.0/README.md +193 -0
  8. read_cli-0.2.0/REVIEW_REPORT.md +335 -0
  9. read_cli-0.2.0/WHY.md +249 -0
  10. read_cli-0.2.0/agent/HEARTBEAT.md +1 -0
  11. read_cli-0.2.0/agent/IDENTITY.md +36 -0
  12. read_cli-0.2.0/agent/MEMORY.md.template +21 -0
  13. read_cli-0.2.0/agent/OVERVIEW.md +51 -0
  14. read_cli-0.2.0/agent/SOUL.md +164 -0
  15. read_cli-0.2.0/agent/TOOLS.md +96 -0
  16. read_cli-0.2.0/agent/USER.md +27 -0
  17. read_cli-0.2.0/docs/API_REFERENCE.md +349 -0
  18. read_cli-0.2.0/docs/GITHUB_RELEASE.md +85 -0
  19. read_cli-0.2.0/docs/OPENCLAW_TOOLS.md +126 -0
  20. read_cli-0.2.0/docs/PRODUCT_HUNT.md +52 -0
  21. read_cli-0.2.0/docs/TWITTER_POSTS.md +150 -0
  22. read_cli-0.2.0/docs/V2EX_POST.md +109 -0
  23. read_cli-0.2.0/pyproject.toml +54 -0
  24. read_cli-0.2.0/readme.md +193 -0
  25. read_cli-0.2.0/src/read/__init__.py +11 -0
  26. read_cli-0.2.0/src/read/cli.py +138 -0
  27. read_cli-0.2.0/src/read/commands/__init__.py +17 -0
  28. read_cli-0.2.0/src/read/commands/add.py +32 -0
  29. read_cli-0.2.0/src/read/commands/delete.py +49 -0
  30. read_cli-0.2.0/src/read/commands/get.py +32 -0
  31. read_cli-0.2.0/src/read/commands/init.py +12 -0
  32. read_cli-0.2.0/src/read/commands/ls.py +47 -0
  33. read_cli-0.2.0/src/read/commands/search.py +31 -0
  34. read_cli-0.2.0/src/read/config.py +36 -0
  35. read_cli-0.2.0/src/read/const.py +28 -0
  36. read_cli-0.2.0/src/read/core/__init__.py +9 -0
  37. read_cli-0.2.0/src/read/core/client.py +217 -0
  38. read_cli-0.2.0/src/read/core/models.py +80 -0
  39. read_cli-0.2.0/src/read/db/__init__.py +12 -0
  40. read_cli-0.2.0/src/read/db/connection.py +37 -0
  41. read_cli-0.2.0/src/read/db/schema.py +60 -0
  42. read_cli-0.2.0/src/read/db/utils.py +272 -0
  43. read_cli-0.2.0/src/read/mcp/__init__.py +7 -0
  44. read_cli-0.2.0/tests/__init__.py +1 -0
  45. read_cli-0.2.0/tests/conftest.py +39 -0
  46. read_cli-0.2.0/tests/integration/__init__.py +1 -0
  47. read_cli-0.2.0/tests/integration/test_commands.py +132 -0
  48. read_cli-0.2.0/tests/integration/test_workflow.py +95 -0
  49. read_cli-0.2.0/tests/unit/__init__.py +1 -0
  50. read_cli-0.2.0/tests/unit/core/__init__.py +1 -0
  51. read_cli-0.2.0/tests/unit/core/test_client.py +133 -0
  52. read_cli-0.2.0/tests/unit/core/test_models.py +88 -0
  53. read_cli-0.2.0/tests/unit/db/__init__.py +1 -0
  54. read_cli-0.2.0/tests/unit/db/test_connection.py +66 -0
  55. read_cli-0.2.0/tests/unit/db/test_utils.py +178 -0
@@ -0,0 +1,23 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .eggs/
8
+
9
+ # Coverage
10
+ .coverage
11
+ htmlcov/
12
+ .pytest_cache/
13
+
14
+ # Agent workspace (用户数据)
15
+ agent/MEMORY.md
16
+ *.db
17
+
18
+ # OS
19
+ .DS_Store
20
+
21
+ # IDE
22
+ .vscode/
23
+ .idea/
@@ -0,0 +1,574 @@
1
+ # 读咚咚 (Read) - 架构设计文档
2
+
3
+ > 设计日期:2026-03-15
4
+ > 版本:v1.0
5
+
6
+ ---
7
+
8
+ ## 产品定位
9
+
10
+ **读咚咚** 是个人知识数据层,支持多种客户端访问。
11
+
12
+ 本地、私有、可编程的个人知识基础设施。
13
+
14
+ ---
15
+
16
+ ## 核心架构
17
+
18
+ ### 四层架构
19
+
20
+ ```
21
+ ┌─────────────────────────────────────────────────────────────┐
22
+ │ 客户端层 │
23
+ │ (浏览器插件、CLI、Alfred Workflow、快捷指令、GUI...) │
24
+ └────────────────────────────┬────────────────────────────────┘
25
+
26
+ ┌────────▼────────┐
27
+ │ 接口层 │
28
+ │ (CLI/HTTP/MCP) │
29
+ └────────┬────────┘
30
+
31
+ ┌────────▼────────┐
32
+ │ 核心层 │
33
+ │ (Core Library) │
34
+ └────────┬────────┘
35
+
36
+ ┌────────▼────────┐
37
+ │ 数据层 │
38
+ │ (SQLite DB) │
39
+ └─────────────────┘
40
+ ```
41
+
42
+ **核心原则**:
43
+ - **Core Library 是核心资产,不是 CLI**
44
+ - **CLI 是核心接口,不是唯一入口**
45
+ - **数据层只管存储和接口,不管用户交互**
46
+ - **客户端各自优化特定场景的 UX**
47
+ - **统一数据空间,人类和 Agent 可以协作**
48
+
49
+ ### 为什么 Core Library 是核心
50
+
51
+ | 思维方式 | CLI 核心 | Core Library 核心 |
52
+ |----------|----------|-------------------|
53
+ | 产品性质 | 命令行工具 | Python 库 |
54
+ | 核心用户 | 终端用户 | 开发者/Agent |
55
+ | 扩展方式 | 加新命令 | 加新客户端 |
56
+ | 长期价值 | 功能完整性 | 接口稳定性 |
57
+ | 商业模式 | 卖便利性 | 开源核心 + 付费支持 |
58
+
59
+ **如果定位是"数据基础设施",那 Core Library 必须是核心。**
60
+
61
+ 这就像 PostgreSQL:
62
+ - 核心开源(Core Library)
63
+ - 付费企业版(托管服务)
64
+ - 技术支持服务(开发者工具)
65
+
66
+ ---
67
+
68
+ ## 1. 项目目录结构
69
+
70
+ ```
71
+ ReadDongDong/
72
+ ├── readme.md # 产品介绍
73
+ ├── CLAUDE.md # Claude Code 指导文档
74
+ ├── ARCHITECTURE.md # 本文档
75
+ ├── pyproject.toml # 项目配置
76
+
77
+ ├── src/
78
+ │ └── read/ # 主包
79
+ │ ├── __init__.py # version = "0.1.0"
80
+ │ ├── cli.py # Typer 主入口
81
+ │ ├── const.py # 常量定义
82
+ │ │
83
+ │ ├── core/ # 核心库(v0.1 抽离)
84
+ │ │ ├── __init__.py
85
+ │ │ ├── client.py # Python SDK (read.core.Client)
86
+ │ │ └── models.py # 数据模型
87
+ │ │
88
+ │ ├── mcp/ # MCP Server (v0.2,关键验证点)
89
+ │ │ └── server.py # MCP 服务
90
+ │ │
91
+ │ ├── db/ # 数据库层
92
+ │ │ ├── __init__.py
93
+ │ │ ├── connection.py # SQLite 连接管理
94
+ │ │ ├── schema.py # 表结构和初始化
95
+ │ │ └── utils.py # CRUD 操作封装
96
+ │ │
97
+ │ └── commands/ # 命令实现(调用 core)
98
+ │ ├── __init__.py
99
+ │ ├── init.py # read init
100
+ │ ├── add.py # read add
101
+ │ ├── ls.py # read ls
102
+ │ ├── get.py # read get
103
+ │ ├── delete.py # read delete
104
+ │ └── search.py # read search
105
+
106
+ ├── tests/ # 测试
107
+ │ ├── __init__.py
108
+ │ ├── conftest.py
109
+ │ ├── unit/
110
+ │ └── integration/
111
+
112
+ └── .read/ # 数据目录(运行时生成)
113
+ └── read.db
114
+ ```
115
+
116
+ ---
117
+
118
+ ## 2. 数据库层设计
119
+
120
+ ### 2.1 表结构
121
+
122
+ ```sql
123
+ CREATE TABLE items (
124
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
125
+ content TEXT, -- 摘录内容(可选)
126
+ url TEXT, -- 链接(可选)
127
+ source TEXT, -- 来源备注(可选)
128
+ type TEXT DEFAULT 'quote', -- 数据类型:quote/article/code
129
+ metadata TEXT, -- JSON 扩展字段(v0.1 预留)
130
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP,
131
+ updated_at TEXT DEFAULT CURRENT_TIMESTAMP, -- 同步预留(v0.1)
132
+
133
+ -- content 和 url 至少有一个不为空
134
+ CHECK(content IS NOT NULL OR url IS NOT NULL)
135
+ );
136
+
137
+ -- 索引:加速查询
138
+ CREATE INDEX idx_items_created_at ON items(created_at DESC);
139
+ CREATE INDEX idx_items_content ON items(content);
140
+ CREATE INDEX idx_items_url ON items(url);
141
+ CREATE INDEX idx_items_type ON items(type); -- 类型筛选(v0.1 预留)
142
+ ```
143
+
144
+ ### 2.2 字段说明
145
+
146
+ | 字段 | 类型 | 必填 | 说明 |
147
+ |------|------|------|------|
148
+ | id | INTEGER | 是 | 主键,自增 |
149
+ | content | TEXT | 否* | 摘录内容,与 url 至少一个必填 |
150
+ | url | TEXT | 否* | 链接,与 content 至少一个必填 |
151
+ | source | TEXT | 否 | 来源备注(如:微信、书名) |
152
+ | type | TEXT | 否 | 数据类型:quote/article/code(v0.1 预留) |
153
+ | metadata | TEXT | 否 | JSON 扩展字段(v0.1 预留,为 Agent 补充信息) |
154
+ | created_at | TEXT | 是 | 创建时间,ISO 8601 格式 |
155
+ | updated_at | TEXT | 是 | 更新时间,同步预留(v0.1) |
156
+
157
+ ### 2.3 连接管理 (connection.py)
158
+
159
+ ```python
160
+ """职责:
161
+ - 单例模式管理 SQLite 连接
162
+ - 确保数据库目录存在
163
+ - 提供线程安全的连接
164
+ - 提供上下文管理器
165
+ """
166
+
167
+ import sqlite3
168
+ import threading
169
+ from contextlib import contextmanager
170
+ from functools import lru_cache
171
+ from pathlib import Path
172
+ from typing import Iterator
173
+
174
+ _connection: sqlite3.Connection | None = None
175
+ _lock = threading.Lock()
176
+
177
+
178
+ @lru_cache(maxsize=1)
179
+ def get_db_path() -> Path:
180
+ """获取数据库路径"""
181
+ db_path = Path.home() / ".read" / "read.db"
182
+ db_path.parent.mkdir(parents=True, exist_ok=True)
183
+ return db_path
184
+
185
+
186
+ def get_connection() -> sqlite3.Connection:
187
+ """获取连接(单例)"""
188
+ # ...(实现)
189
+
190
+
191
+ @contextmanager
192
+ def get_cursor() -> Iterator[sqlite3.Cursor]:
193
+ """获取游标(自动事务管理)"""
194
+ # ...(实现)
195
+ ```
196
+
197
+ ### 2.4 CRUD 操作 (utils.py)
198
+
199
+ ```python
200
+ """职责:
201
+ - 封装所有数据库操作
202
+ - 提供类型友好的接口
203
+ - 处理业务逻辑验证
204
+ """
205
+
206
+ def add_item(
207
+ content: Optional[str] = None,
208
+ url: Optional[str] = None,
209
+ source: Optional[str] = None,
210
+ ) -> int:
211
+ """添加摘录,返回新 ID"""
212
+
213
+ def list_items(
214
+ limit: int = 20,
215
+ offset: int = 0,
216
+ item_type: Optional[str] = None,
217
+ order: str = "desc",
218
+ ) -> list[dict]:
219
+ """列出摘录"""
220
+
221
+ def get_item(item_id: int) -> Optional[dict]:
222
+ """获取单条"""
223
+
224
+ def delete_item(item_id: int) -> bool:
225
+ """删除单条"""
226
+
227
+ def search_items(
228
+ query: str,
229
+ field: Optional[str] = None,
230
+ limit: int = 20,
231
+ ) -> list[dict]:
232
+ """搜索"""
233
+
234
+ def count_total() -> int:
235
+ """总数"""
236
+ ```
237
+
238
+ ---
239
+
240
+ ## 3. CLI 层设计
241
+
242
+ ### 3.1 统一输出格式 (cli.py)
243
+
244
+ ```python
245
+ """职责:
246
+ - 统一的 JSON 输出
247
+ - 统一的错误处理
248
+ - Typer 应用配置
249
+ """
250
+
251
+ import json
252
+ import typer
253
+ from typing import Any
254
+
255
+ app = typer.Typer(
256
+ name="read",
257
+ help="读咚咚 (Read) - 个人知识数据层的命令行接口",
258
+ no_args_is_help=True,
259
+ add_completion=False,
260
+ )
261
+
262
+
263
+ def output(data: Any, success: bool = True) -> None:
264
+ """输出 JSON 格式"""
265
+ result: dict[str, Any] = {"success": success}
266
+ if success:
267
+ result["data"] = data
268
+ else:
269
+ result["error"] = data
270
+ typer.echo(json.dumps(result, ensure_ascii=False, indent=2))
271
+
272
+
273
+ def handle_error(e: Exception) -> None:
274
+ """处理异常并输出结构化错误"""
275
+ error_info: dict[str, str] = {
276
+ "code": type(e).__name__,
277
+ "message": str(e)
278
+ }
279
+ output(error_info, success=False)
280
+ raise typer.Exit(code=1)
281
+ ```
282
+
283
+ ### 3.2 命令模板
284
+
285
+ 每个命令文件遵循统一结构:
286
+
287
+ ```python
288
+ """命令说明"""
289
+
290
+ import typer
291
+ from read.cli import output, handle_error
292
+ from read.db.utils import add_item
293
+
294
+ def cmd_add(
295
+ content: str = typer.Argument(None, help="摘录内容"),
296
+ url: str = typer.Option(None, "--url", help="链接"),
297
+ source: str = typer.Option(None, "--source", help="来源备注"),
298
+ ):
299
+ """添加摘录或链接"""
300
+ try:
301
+ item_id = add_item(content=content, url=url, source=source)
302
+ item = get_item(item_id)
303
+ output(item)
304
+ except Exception as e:
305
+ handle_error(e)
306
+ ```
307
+
308
+ ---
309
+
310
+ ## 4. 命令详细设计
311
+
312
+ ### 4.1 init - 初始化
313
+
314
+ ```bash
315
+ read init
316
+ ```
317
+
318
+ ```json
319
+ {
320
+ "success": true,
321
+ "data": {
322
+ "message": "Read database initialized",
323
+ "db_path": "/Users/xxx/.read/read.db",
324
+ "version": "0.1.0"
325
+ }
326
+ }
327
+ ```
328
+
329
+ ### 4.2 add - 添加
330
+
331
+ ```bash
332
+ read add "一句话说得真好"
333
+ read add "一句话" --url "https://example.com"
334
+ read add --url "https://mp.weixin.qq.com/s/xxx"
335
+ read add "一句话" --url "..." --source "CLAUDE.md"
336
+ ```
337
+
338
+ **验证规则**:
339
+ - content 和 url 至少一个不为空
340
+ - url 格式基本验证
341
+
342
+ ### 4.3 ls - 列出
343
+
344
+ ```bash
345
+ read ls # 默认 20 条
346
+ read ls --limit 50
347
+ read ls --type content # 只摘录
348
+ read ls --type link # 只链接
349
+ read ls --order asc # 正序
350
+ ```
351
+
352
+ ```json
353
+ {
354
+ "success": true,
355
+ "data": {
356
+ "total": 150,
357
+ "items": [...]
358
+ }
359
+ }
360
+ ```
361
+
362
+ ### 4.4 get - 获取
363
+
364
+ ```bash
365
+ read get 123
366
+ read get 123 --field content
367
+ ```
368
+
369
+ ### 4.5 delete - 删除
370
+
371
+ ```bash
372
+ read delete 123
373
+ read delete 123 124 125
374
+ read delete 123 --force
375
+ ```
376
+
377
+ ### 4.6 search - 搜索
378
+
379
+ ```bash
380
+ read search "AI"
381
+ read search "微信" --field source
382
+ ```
383
+
384
+ ---
385
+
386
+ ## 5. 配置文件
387
+
388
+ ### 5.1 pyproject.toml
389
+
390
+ ```toml
391
+ [project]
392
+ name = "read-cli"
393
+ version = "0.1.0"
394
+ description = "读咚咚 - 个人知识数据层的命令行接口"
395
+ readme = "readme.md"
396
+ requires-python = ">=3.11"
397
+ dependencies = [
398
+ "typer>=0.12.0",
399
+ ]
400
+
401
+ [project.scripts]
402
+ read = "read.cli:app"
403
+
404
+ [build-system]
405
+ requires = ["hatchling"]
406
+ build-backend = "hatchling.build"
407
+
408
+ [tool.hatch.build.targets.wheel]
409
+ packages = ["src/read"]
410
+
411
+ [tool.pytest.ini_options]
412
+ minversion = "7.0"
413
+ testpaths = ["tests"]
414
+ pythonpath = ["src"]
415
+ ```
416
+
417
+ ---
418
+
419
+ ## 6. 设计决策记录
420
+
421
+ ### 6.1 为什么用 SQLite 单文件?
422
+
423
+ - 零配置
424
+ - 适合个人数据量
425
+ - 易于备份(复制一个文件即可)
426
+ - Python 内置支持
427
+
428
+ ### 6.2 为什么不做 tags 表?
429
+
430
+ - 先验证核心需求
431
+ - 够用就行,不过度设计
432
+ - 以后可以通过 source 字段简单实现
433
+
434
+ ### 6.3 为什么不做 status 字段?
435
+
436
+ - 只管收集,不管管理
437
+ - 减少心智负担
438
+ - 如果需要,可以通过 created_at 推断
439
+
440
+ ### 6.4 为什么用 Typer?
441
+
442
+ - 类型提示友好
443
+ - 自动生成帮助信息
444
+ - Click 的现代替代品
445
+
446
+ ---
447
+
448
+ ## 7. 实现顺序
449
+
450
+ 1. **基础设施**
451
+ - [ ] 项目目录结构
452
+ - [ ] pyproject.toml
453
+ - [ ] db/connection.py
454
+ - [ ] db/schema.py
455
+ - [ ] db/utils.py
456
+
457
+ 2. **CLI 入口**
458
+ - [ ] cli.py(统一输出、错误处理)
459
+ - [ ] const.py
460
+
461
+ 3. **核心命令**
462
+ - [ ] init.py
463
+ - [ ] add.py
464
+ - [ ] ls.py
465
+ - [ ] get.py
466
+ - [ ] delete.py
467
+ - [ ] search.py
468
+
469
+ 4. **测试**
470
+ - [ ] 单元测试
471
+ - [ ] 集成测试
472
+
473
+ ---
474
+
475
+ ## 8. 版本规划
476
+
477
+ | 版本 | 核心资产 | 客户端 | 验证目标 | 工期 |
478
+ |------|----------|--------|----------|------|
479
+ | v0.1 | Core Library v0.1 | CLI | 数据模型和 API 稳定性 | 2天 |
480
+ | v0.2 | Core Library v0.1 | **MCP Server** | **Agent 集成价值(关键验证点)** | 1天 |
481
+ | v0.3 | Core Library v0.1 | Python SDK | 开发者体验 | 0.5天 |
482
+ | v0.4 | Core Library v0.1 | Browser Extension | 用户体验 | 1-2天 |
483
+
484
+ **核心原则**:
485
+ 1. **Core Library 的版本号才是产品的主版本号**
486
+ 2. 所有客户端都是 Core Library 的薄封装
487
+ 3. 每一步都是"加一层",不是重构
488
+
489
+ **验证策略**:v0.2 MCP Server 是验证"数据基础设施"定位的关键。如果验证成功,继续推进;如果验证失败,重新定位或暂停。
490
+
491
+ ---
492
+
493
+ ## 9. v0.1 架构约束
494
+
495
+ 为未来版本预留空间,v0.1 开发时必须遵守:
496
+
497
+ ### 9.0 Core Library 优先设计原则
498
+
499
+ **Core Library 必须满足**:
500
+
501
+ | 原则 | 要求 | 验证方式 |
502
+ |------|------|----------|
503
+ | **独立性** | 不依赖任何客户端(CLI/MCP/HTTP) | 可单独 import 使用 |
504
+ | **完整性** | 包含所有数据操作逻辑 | 客户端无需直接访问数据库 |
505
+ | **稳定性** | API 设计考虑向后兼容 | 命名和参数慎重设计 |
506
+ | **可测试性** | 所有逻辑可独立单元测试 | 不依赖 CLI 运行 |
507
+
508
+ **实现约束**:
509
+ - Core Library 代码位于 `src/read/core/`
510
+ - 不得在 Core Library 中 import CLI 相关模块
511
+ - 所有数据库操作必须通过 Core Library 暴露的方法
512
+
513
+ ### 9.1 Core Library 与 CLI 解耦
514
+
515
+ - CLI 不直接操作 SQLite
516
+ - CLI 调用 Core Library 的方法
517
+ - 未来 MCP/SDK 可以复用同一个 Core Library
518
+ - **设计目标**:v0.2 加入 MCP Server 时,只需"加一层",不需重构
519
+
520
+ ### 9.2 错误码统一
521
+
522
+ - 设计一套错误码体系
523
+ - CLI 和未来 HTTP API/MCP 共用
524
+ - 方便客户端统一处理
525
+ - **错误信息人类化**:对开发者友好的错误提示
526
+
527
+ ### 9.3 数据模型稳定
528
+
529
+ - 尽量减少 schema 变更
530
+ - 为扩展字段预留空间
531
+ - 向后兼容
532
+ - **新增字段考虑**:
533
+ - `metadata JSON` — Agent 补充信息
534
+ - `updated_at TEXT` — 同步预留
535
+ - `type TEXT` — 支持多种数据类型
536
+
537
+ ---
538
+
539
+ ## 10. 设计决策记录
540
+
541
+ ### 10.1 为什么用 SQLite 单文件?
542
+
543
+ - 零配置
544
+ - 适合个人数据量
545
+ - 易于备份(复制一个文件即可)
546
+ - Python 内置支持
547
+
548
+ ### 10.2 为什么 CLI 是核心接口而非唯一入口?
549
+
550
+ - CLI 是数据层的命令行接口
551
+ - 人类用户通过浏览器插件等客户端访问
552
+ - Agent 通过 MCP/SDK 访问
553
+ - CLI 主要用于开发和调试
554
+
555
+ ### 10.3 为什么不做 tags 表?
556
+
557
+ - 先验证核心需求
558
+ - 够用就行,不过度设计
559
+ - 以后可以通过 source 字段简单实现
560
+ - 客户端层可以实现标签功能
561
+
562
+ ### 10.4 为什么用 Typer?
563
+
564
+ - 类型提示友好
565
+ - 自动生成帮助信息
566
+ - Click 的现代替代品
567
+
568
+ ---
569
+
570
+ ## 11. 版本记录
571
+
572
+ | 版本 | 日期 | 变更 |
573
+ |------|------|------|
574
+ | v1.0 | 2026-03-15 | 初始版本 |