knowflow 0.1.0__py3-none-any.whl

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 (35) hide show
  1. knowflow/__init__.py +4 -0
  2. knowflow/__main__.py +3 -0
  3. knowflow/adapters/knowledge/__init__.py +42 -0
  4. knowflow/adapters/knowledge/local.py +43 -0
  5. knowflow/adapters/knowledge/obsidian.py +64 -0
  6. knowflow/adapters/storage/__init__.py +62 -0
  7. knowflow/adapters/storage/git.py +155 -0
  8. knowflow/adapters/storage/local.py +110 -0
  9. knowflow/adapters/storage/quark.py +225 -0
  10. knowflow/adapters/storage/s3.py +118 -0
  11. knowflow/adapters/storage/webdav.py +196 -0
  12. knowflow/cli/__init__.py +265 -0
  13. knowflow/cli/template_manager.py +100 -0
  14. knowflow/core/__init__.py +10 -0
  15. knowflow/core/knowledge.py +85 -0
  16. knowflow/core/pipeline.py +119 -0
  17. knowflow/core/storage.py +167 -0
  18. knowflow/dashboard/__init__.py +355 -0
  19. knowflow/templates/daily-journal/plugin.yaml +21 -0
  20. knowflow/templates/football-prediction/plugin.yaml +22 -0
  21. knowflow/templates/project-wiki/plugin.yaml +20 -0
  22. knowflow/templates/research-notes/plugin.yaml +26 -0
  23. knowflow/templates/stock-analysis/plugin.yaml +22 -0
  24. knowflow/templates/web-monitor/plugin.yaml +20 -0
  25. knowflow/templates/worldcup-tracker/plugin.yaml +18 -0
  26. knowflow/transforms/__init__.py +6 -0
  27. knowflow/transforms/archive.py +87 -0
  28. knowflow/transforms/markdown_export.py +110 -0
  29. knowflow/transforms/profile_index.py +89 -0
  30. knowflow-0.1.0.dist-info/METADATA +264 -0
  31. knowflow-0.1.0.dist-info/RECORD +35 -0
  32. knowflow-0.1.0.dist-info/WHEEL +5 -0
  33. knowflow-0.1.0.dist-info/entry_points.txt +2 -0
  34. knowflow-0.1.0.dist-info/licenses/LICENSE +21 -0
  35. knowflow-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,87 @@
1
+ """
2
+ knowflow/transforms/archive.py — Hot/Warm/Cold data lifecycle
3
+ ===============================================================
4
+ Implements automatic data archiving based on half-life decay model.
5
+ """
6
+ from pathlib import Path
7
+ import tarfile
8
+ import io
9
+ import os
10
+ import time
11
+ from datetime import datetime
12
+ from knowflow.core.pipeline import TransformStage, PipelineContext
13
+
14
+
15
+ class ArchiveStage(TransformStage):
16
+ """Hot → Warm → Cold data archiving"""
17
+
18
+ def __init__(self):
19
+ super().__init__("archive")
20
+ self.hot_days = 30 # Hot retention
21
+ self.cold_months = 12 # Warm retention
22
+
23
+ def process(self, ctx: PipelineContext) -> dict:
24
+ if ctx.dry_run:
25
+ return self._dry_run(ctx)
26
+
27
+ warm_dir = ctx.data_dir.parent.parent / "archive" / ctx.plugin_name
28
+ warm_dir.mkdir(parents=True, exist_ok=True)
29
+
30
+ now = time.time()
31
+ cutoff = now - (self.hot_days * 86400)
32
+ by_month = {}
33
+ freed = 0
34
+
35
+ for root, dirs, files in os.walk(str(ctx.data_dir)):
36
+ for fname in files:
37
+ fpath = Path(root) / fname
38
+ try:
39
+ mtime = fpath.stat().st_mtime
40
+ if mtime < cutoff:
41
+ rel = fpath.relative_to(ctx.data_dir.parent.parent / "data").as_posix()
42
+ month = datetime.fromtimestamp(mtime).strftime("%Y-%m")
43
+ by_month.setdefault(month, []).append((rel, fpath, mtime))
44
+ freed += fpath.stat().st_size
45
+ except OSError:
46
+ continue
47
+
48
+ archives = []
49
+ for month, files in sorted(by_month.items()):
50
+ archive_path = warm_dir / f"{month}.tar.gz"
51
+ with tarfile.open(str(archive_path), "w:gz") as tar:
52
+ for rel, abspath, mtime in files:
53
+ content = abspath.read_bytes()
54
+ info = tarfile.TarInfo(name=rel)
55
+ info.size = len(content)
56
+ info.mtime = mtime
57
+ tar.addfile(info, io.BytesIO(content))
58
+ abspath.unlink()
59
+ archives.append(archive_path.name)
60
+
61
+ return {
62
+ "status": "ok",
63
+ "archives": len(archives),
64
+ "files": sum(len(v) for v in by_month.values()),
65
+ "freed_kb": round(freed / 1024, 1),
66
+ }
67
+
68
+ def _dry_run(self, ctx: PipelineContext) -> dict:
69
+ now = time.time()
70
+ cutoff = now - (self.hot_days * 86400)
71
+ candidates = []
72
+
73
+ for root, dirs, files in os.walk(str(ctx.data_dir)):
74
+ for fname in files:
75
+ fpath = Path(root) / fname
76
+ try:
77
+ if fpath.stat().st_mtime < cutoff:
78
+ rel = fpath.relative_to(ctx.data_dir.parent.parent / "data").as_posix()
79
+ candidates.append(rel)
80
+ except OSError:
81
+ continue
82
+
83
+ return {
84
+ "status": "ok",
85
+ "dry_run": True,
86
+ "candidates": len(candidates),
87
+ }
@@ -0,0 +1,110 @@
1
+ """
2
+ knowflow/transforms/markdown_export.py — JSON → Markdown export
3
+ ================================================================
4
+ Converts structured JSON data into human-readable Markdown.
5
+ """
6
+ from pathlib import Path
7
+ import json
8
+ from datetime import datetime
9
+ from knowflow.core.pipeline import TransformStage, PipelineContext, PipelineError
10
+
11
+
12
+ class MarkdownExport(TransformStage):
13
+ """Convert JSON data files to Markdown documents"""
14
+
15
+ def __init__(self):
16
+ super().__init__("markdown_export")
17
+
18
+ def process(self, ctx: PipelineContext) -> dict:
19
+ data_dir = ctx.data_dir
20
+ output_dir = ctx.output_dir
21
+
22
+ if not data_dir.exists():
23
+ return {"status": "skipped", "reason": "No data directory"}
24
+
25
+ output_dir.mkdir(parents=True, exist_ok=True)
26
+ generated = []
27
+
28
+ for json_file in sorted(data_dir.rglob("*.json")):
29
+ try:
30
+ data = json.loads(json_file.read_text(encoding="utf-8"))
31
+ except (json.JSONDecodeError, UnicodeDecodeError):
32
+ ctx.plugin_config.get("_warnings", []).append(f"Skipped invalid JSON: {json_file.name}")
33
+ continue
34
+
35
+ md = self._to_markdown(data, json_file, ctx.plugin_name)
36
+ if md:
37
+ md_name = json_file.stem + ".md"
38
+ md_rel = json_file.relative_to(data_dir).parent / md_name
39
+ md_path = output_dir / md_rel
40
+ md_path.parent.mkdir(parents=True, exist_ok=True)
41
+ md_path.write_text(md, encoding="utf-8")
42
+ generated.append(str(md_rel))
43
+
44
+ return {
45
+ "status": "ok",
46
+ "generated": len(generated),
47
+ "files": generated[:5],
48
+ }
49
+
50
+ def _to_markdown(self, data: dict, json_path: Path, plugin: str) -> str:
51
+ if not data:
52
+ return None
53
+
54
+ lines = []
55
+ lines.append(f"# {plugin.title()} — {json_path.stem}")
56
+ lines.append("")
57
+ lines.append(f"> 自动生成 {datetime.now().strftime('%Y-%m-%d %H:%M')}")
58
+ lines.append(f"> 源: `{json_path.relative_to(json_path.parent.parent.parent)}`")
59
+ lines.append("")
60
+ lines.append("---")
61
+ lines.append("")
62
+
63
+ self._render(lines, data, 2)
64
+
65
+ return "\n".join(lines)
66
+
67
+ def _render(self, lines: list, data, level: int):
68
+ if isinstance(data, dict):
69
+ for k, v in data.items():
70
+ if isinstance(v, (dict, list)) and not isinstance(v, str):
71
+ h = k.replace("_", " ").title()
72
+ lines.append(f"{'#' * level} {h}")
73
+ lines.append("")
74
+ self._render(lines, v, min(level + 1, 6))
75
+ elif isinstance(v, list) and v and isinstance(v[0], dict):
76
+ h = k.replace("_", " ").title()
77
+ lines.append(f"{'#' * level} {h}")
78
+ lines.append("")
79
+ self._render_table(lines, v)
80
+ else:
81
+ label = k.replace("_", " ").title()
82
+ lines.append(f"- **{label}**: {self._fmt(v)}")
83
+ lines.append("")
84
+ elif isinstance(data, list):
85
+ if data and isinstance(data[0], dict):
86
+ self._render_table(lines, data)
87
+ else:
88
+ for item in data:
89
+ lines.append(f"- {self._fmt(item)}")
90
+ lines.append("")
91
+
92
+ def _render_table(self, lines: list, items: list[dict]):
93
+ if not items:
94
+ return
95
+ keys = list(dict.fromkeys(k for item in items for k in item.keys()
96
+ if not isinstance(item.get(k), (dict, list))))
97
+ if not keys:
98
+ return
99
+ lines.append("| " + " | ".join(k.replace("_", " ").title() for k in keys) + " |")
100
+ lines.append("| " + " | ".join("---" for _ in keys) + " |")
101
+ for item in items:
102
+ row = "| " + " | ".join(str(self._fmt(item.get(k, "")))[:60] for k in keys) + " |"
103
+ lines.append(row)
104
+ lines.append("")
105
+
106
+ def _fmt(self, v) -> str:
107
+ if v is None: return "—"
108
+ if isinstance(v, bool): return "✅" if v else "❌"
109
+ if isinstance(v, float): return f"{v:.2f}"
110
+ return str(v)
@@ -0,0 +1,89 @@
1
+ """
2
+ knowflow/transforms/profile_index.py — Auto-generate PROFILE.md
3
+ ===============================================================
4
+ Creates a human-readable index of all data in the knowledge base.
5
+ """
6
+ from pathlib import Path
7
+ from datetime import datetime
8
+ import os
9
+ from knowflow.core.pipeline import TransformStage, PipelineContext
10
+
11
+
12
+ class ProfileIndex(TransformStage):
13
+ """Generate PROFILE.md index of the knowledge base"""
14
+
15
+ def __init__(self):
16
+ super().__init__("profile_index")
17
+
18
+ def process(self, ctx: PipelineContext) -> dict:
19
+ root = ctx.data_dir.parent.parent # ~/knowflow-data or ~/knowledge
20
+ profile_path = root / "PROFILE.md"
21
+ manifest_path = root / "index" / "manifest.json"
22
+
23
+ plugins = {}
24
+ data_dir = ctx.data_dir.parent # data/
25
+ if data_dir.exists():
26
+ for plugin_dir in sorted(data_dir.iterdir()):
27
+ if plugin_dir.is_dir():
28
+ plugins[plugin_dir.name] = self._scan_dir(plugin_dir)
29
+
30
+ profile = self._build_profile(plugins, ctx.plugin_config)
31
+ profile_path.write_text(profile, encoding="utf-8")
32
+
33
+ import json
34
+ manifest_path.parent.mkdir(parents=True, exist_ok=True)
35
+ manifest_path.write_text(
36
+ json.dumps({
37
+ "generated_at": datetime.now().isoformat(),
38
+ "plugins": list(plugins.keys()),
39
+ }, ensure_ascii=False, indent=2),
40
+ encoding="utf-8"
41
+ )
42
+
43
+ return {
44
+ "status": "ok",
45
+ "profile_size": len(profile),
46
+ "plugins": list(plugins.keys()),
47
+ }
48
+
49
+ def _scan_dir(self, plugin_dir: Path) -> dict:
50
+ count = 0
51
+ size = 0
52
+ latest = 0.0
53
+ for root, dirs, files in os.walk(str(plugin_dir)):
54
+ for f in files:
55
+ try:
56
+ st = (Path(root) / f).stat()
57
+ count += 1
58
+ size += st.st_size
59
+ latest = max(latest, st.st_mtime)
60
+ except OSError:
61
+ continue
62
+ return {
63
+ "files": count,
64
+ "size_kb": round(size / 1024, 1),
65
+ "updated": datetime.fromtimestamp(latest).isoformat() if latest else "—",
66
+ }
67
+
68
+ def _build_profile(self, plugins: dict, config: dict) -> str:
69
+ lines = ["# 🧠 KnowFlow Knowledge Base", "",
70
+ f"自动生成 {datetime.now().strftime('%Y-%m-%d %H:%M')}", "",
71
+ "## 📊 概览", "",
72
+ f"| 指标 | 数值 |",
73
+ f"|------|------|",
74
+ f"| 插件数 | {len(plugins)} |",
75
+ f"| 总文件 | {sum(p['files'] for p in plugins.values())} |",
76
+ f"| 总大小 | {sum(p['size_kb'] for p in plugins.values()):.1f} KB |",
77
+ "", "## 🔌 插件", ""]
78
+
79
+ for name, st in plugins.items():
80
+ icon = {"football": "⚽", "stock": "📈", "worldcup": "🏆"}
81
+ lines.append(f"### {icon.get(name, '📦')} {name.title()}")
82
+ lines.append(f"- 文件: {st['files']}")
83
+ lines.append(f"- 大小: {st['size_kb']} KB")
84
+ lines.append(f"- 更新: {st['updated']}")
85
+ lines.append("")
86
+
87
+ lines.append("---")
88
+ lines.append("> KnowFlow — Agent Knowledge Pipeline")
89
+ return "\n".join(lines)
@@ -0,0 +1,264 @@
1
+ Metadata-Version: 2.4
2
+ Name: knowflow
3
+ Version: 0.1.0
4
+ Summary: Agent Knowledge Pipeline — storage-agnostic, KB-agnostic, plug-and-play pipeline that turns raw agent JSON into versioned, human-readable docs
5
+ Author: qypvip
6
+ Author-email: qypvip <yanpeng898@gmail.com>
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/qypvip/knowflow
9
+ Project-URL: Repository, https://github.com/qypvip/knowflow
10
+ Project-URL: Issues, https://github.com/qypvip/knowflow/issues
11
+ Project-URL: Changelog, https://github.com/qypvip/knowflow/commits/main
12
+ Keywords: agent,ai-agent,knowledge-base,pipeline,llm,markdown,obsidian,automation,data-pipeline,etl
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.8
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Topic :: Text Processing :: Markup :: Markdown
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.8
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: pyyaml>=5.1
30
+ Provides-Extra: s3
31
+ Requires-Dist: boto3; extra == "s3"
32
+ Provides-Extra: notion
33
+ Requires-Dist: notion-client; extra == "notion"
34
+ Provides-Extra: ima
35
+ Requires-Dist: requests; extra == "ima"
36
+ Provides-Extra: webdav
37
+ Requires-Dist: requests; extra == "webdav"
38
+ Provides-Extra: all
39
+ Requires-Dist: boto3; extra == "all"
40
+ Requires-Dist: notion-client; extra == "all"
41
+ Requires-Dist: requests; extra == "all"
42
+ Dynamic: author
43
+ Dynamic: license-file
44
+ Dynamic: requires-python
45
+
46
+ # KnowFlow 🧠
47
+
48
+ **Agent Knowledge Pipeline** — 存储无关、知识库无关、即装即用。
49
+
50
+ 让 AI Agent 产出的数据自动走完:**写入 → 版本控制 → 多端同步 → 人类可读** 的全流程。
51
+
52
+ ![CI](https://github.com/qypvip/knowflow/actions/workflows/ci.yml/badge.svg)
53
+ [![PyPI](https://img.shields.io/pypi/v/knowflow.svg)](https://pypi.org/project/knowflow/)
54
+ [![Python](https://img.shields.io/pypi/pyversions/knowflow.svg)](https://pypi.org/project/knowflow/)
55
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
56
+
57
+ ```bash
58
+ pip install knowflow
59
+
60
+ # 从模板创建新项目
61
+ knowflow init football-prediction --dir my-football-bot
62
+ cd my-football-bot
63
+
64
+ # Agent写入数据 → 自动转 Markdown 文档
65
+ echo '{"match": "巴西vs阿根廷", "prediction": "巴西胜"}' > football/data/prediction.json
66
+ knowflow run
67
+
68
+ # 查看报告
69
+ cat output/football/prediction.md
70
+ ```
71
+
72
+ ## 🤔 这解决什么问题
73
+
74
+ 如果你用 AI Agent 干活,大概率遇到过这三件事:
75
+
76
+ 1. **数据散落** —— Agent 每跑一次就吐几个 JSON,几十次之后你根本找不到“上周三那次分析结果在哪”。
77
+ 2. **机器看得懂,人看不懂** —— JSON 一行行挤在一起,想回顾得自己拼。
78
+ 3. **越用越乱** —— 数据只增不减,几个月后目录里几千个文件,不敢删也不知道删哪个。
79
+
80
+ KnowFlow 干的就是这三件:**Agent 只管往固定目录写 JSON,剩下的(转成人类可读的 Markdown、
81
+ 自动分热/温/冷三层归档、生成索引、Git 记录每次变更)全交给它。**
82
+
83
+ 一句话:**Agent 负责产出,KnowFlow 负责让它留下来还有用。**
84
+
85
+ ## ✨ 特性
86
+
87
+ | 特性 | 说明 | 状态 |
88
+ |------|------|------|
89
+ | 🔌 **存储无关** | Git / 本地 / S3 / 夸克网盘 / WebDAV | ✅ 已实现 |
90
+ | 📚 **知识库无关** | 本地目录 / Obsidian | ✅ 已实现 |
91
+ | 📦 **模板系统** | 足球预测、股票分析、日记、Wiki 等 **7 个** | ✅ 已实现 |
92
+ | 🗄️ **自动归档** | 热→温→冷三层,数据不会无限膨胀 | ✅ 已实现 |
93
+ | 🔄 **版本控制** | Git 后端自动记录每次变更 | ✅ 已实现 |
94
+ | 🧪 **测试** | 68 个单元测试 + GitHub Actions | ✅ 已实现 |
95
+ | 🔓 **开源** | MIT 协议,可商用可二次开发 | ✅ |
96
+
97
+ > 仅依赖 `pyyaml`(非"零依赖");Notion / IMA / MkDocs 后端**尚未实现**,欢迎 PR。
98
+
99
+ ## 🚀 安装
100
+
101
+ ```bash
102
+ pip install knowflow
103
+
104
+ # 可选后端
105
+ pip install "knowflow[s3]" # S3 / MinIO / R2
106
+ pip install "knowflow[all]" # 全部后端
107
+ ```
108
+
109
+ 从源码安装(开发用):
110
+
111
+ ```bash
112
+ git clone https://github.com/qypvip/knowflow.git
113
+ cd knowflow
114
+ pip install -e .
115
+ ```
116
+
117
+ 国内网络拉不动 GitHub 时,可用镜像前缀:
118
+
119
+ ```bash
120
+ git clone https://ghproxy.net/https://github.com/qypvip/knowflow.git
121
+ # 或从 Gitee 克隆
122
+ git clone git@gitee.com:qypvip/knowflow.git
123
+ ```
124
+
125
+ ## ⚡ 快速开始
126
+
127
+ ```bash
128
+ # 查看可用模板
129
+ knowflow list
130
+
131
+ # 初始化项目
132
+ knowflow init daily-journal --dir my-diary
133
+ cd my-diary
134
+
135
+ # 写入一些数据
136
+ mkdir -p diary/data/entries
137
+ cat > diary/data/entries/2026-10-02.json << 'EOF'
138
+ {
139
+ "date": "2026-10-02",
140
+ "title": "今天学习了 KnowFlow",
141
+ "mood": "开心",
142
+ "notes": "终于有了一个统一的知识管理工具"
143
+ }
144
+ EOF
145
+
146
+ # 运行管道(JSON → Markdown → 索引 → 归档)
147
+ knowflow run
148
+
149
+ # 查看输出
150
+ cat output/diary/2026-10-02.md
151
+ ```
152
+
153
+ ## 🧪 开发与测试
154
+
155
+ ```bash
156
+ pip install -e . pytest
157
+ pytest -q # 68 passed
158
+ python -m knowflow list
159
+ ```
160
+
161
+ CI 在 Python 3.9 / 3.11 / 3.12 上跑全量测试,另有一个"零额外依赖"冒烟任务
162
+ 验证核心模块在只装 `pyyaml` 时可 import、CLI 可用。
163
+
164
+ ## 📦 模板
165
+
166
+ | 模板 | 命令 | 适用场景 |
167
+ |------|------|---------|
168
+ | ⚽ football-prediction | `knowflow init football-prediction` | 比赛预测+复盘闭环 |
169
+ | 📈 stock-analysis | `knowflow init stock-analysis` | 多策略股票分析 |
170
+ | 🏆 worldcup-tracker | `knowflow init worldcup-tracker` | 赛事名单追踪 |
171
+ | 📝 daily-journal | `knowflow init daily-journal` | 个人日记+归档 |
172
+ | 📚 project-wiki | `knowflow init project-wiki` | 项目文档自动化 |
173
+ | 🌐 web-monitor | `knowflow init web-monitor` | 网页内容监控 |
174
+ | 🔬 research-notes | `knowflow init research-notes` | 学术笔记管理 |
175
+
176
+ ## 🔌 存储后端
177
+
178
+ | 后端 | 类 | 额外依赖 | 适用场景 |
179
+ |------|----|---------|---------|
180
+ | 🔄 `git`(默认) | `GitStorage` | git CLI | 本地 + 版本历史 |
181
+ | 📁 `local` | `LocalStorage` | 无 | 最简,无版本 |
182
+ | ☁️ `s3` | `S3Storage` | boto3 | AWS / MinIO / R2 |
183
+ | 🅰️ `quark` | `QuarkStorage` | kuake_cli | 夸克网盘 |
184
+ | 🌐 `webdav` | `WebDAVStorage` | requests | NextCloud / NAS |
185
+
186
+ ```bash
187
+ knowflow init football-prediction --storage git
188
+ knowflow init football-prediction --storage local
189
+ ```
190
+
191
+ ## 📚 知识库后端
192
+
193
+ | 后端 | 类 |
194
+ |------|----|
195
+ | 📁 `local`(默认) | `LocalKB` |
196
+ | 📝 `obsidian` | `ObsidianKB` |
197
+
198
+ ```bash
199
+ knowflow init football-prediction --kb obsidian
200
+ ```
201
+
202
+ Python 侧用法:
203
+
204
+ ```python
205
+ from knowflow.adapters.storage import create_storage
206
+ from knowflow.adapters.knowledge import create_knowledge # create_kb 为别名
207
+
208
+ store = create_storage("git", path="~/my-data") # 扁平参数
209
+ store = create_storage("git", config={"path": "~/my-data"}) # 或显式 config
210
+
211
+ kb = create_knowledge("local", path="~/my-output")
212
+ ```
213
+
214
+ ## 🧪 命令行
215
+
216
+ ```bash
217
+ knowflow list # 列出所有模板
218
+ knowflow init <name> # 从模板创建项目
219
+ knowflow run # 运行数据管道
220
+ knowflow status # 查看仓库状态
221
+ knowflow commit "msg" # 手动提交
222
+ knowflow archive # 手动归档旧数据
223
+ knowflow version # 查看版本
224
+ ```
225
+
226
+ ## 🏗️ 架构
227
+
228
+ ```
229
+ Agent写入数据
230
+ ↓
231
+ StorageAdapter ← 可插拔(Git/本地/S3/夸克/WebDAV)
232
+ ↓
233
+ Pipeline (Markdown导出→归档→索引)
234
+ ↓
235
+ KnowledgeAdapter ← 可插拔(本地/Obsidian)
236
+ ```
237
+
238
+ ### 加一个存储后端(两步)
239
+
240
+ ```python
241
+ from knowflow.core.storage import StorageAdapter
242
+
243
+ class MyStorage(StorageAdapter):
244
+ def read(self, path): ...
245
+ def read_binary(self, path): ...
246
+ def write(self, path, content): ...
247
+ def write_binary(self, path, content): ...
248
+ def delete(self, path): ...
249
+ def exists(self, path): ...
250
+ def list(self, prefix=""): ...
251
+ def walk(self, prefix=""): ...
252
+
253
+ from knowflow.adapters.storage import register
254
+ register("mystorage", MyStorage) # 完成
255
+ ```
256
+
257
+ ## 📄 协议
258
+
259
+ MIT
260
+
261
+ ## 🔗 镜像
262
+
263
+ - GitHub: <https://github.com/qypvip/knowflow>
264
+ - Gitee: <https://gitee.com/qypvip/knowflow>
@@ -0,0 +1,35 @@
1
+ knowflow/__init__.py,sha256=k9Io_mfdL-fSR79D6TNViRHVR3fiLNqqo2BAx-rpNjg,110
2
+ knowflow/__main__.py,sha256=WC0Qg2bFvqPawzfhuoxP68tVEpZJT1Aacu_CFXVGl4w,103
3
+ knowflow/adapters/knowledge/__init__.py,sha256=iEQ-Hr1iJvMBLblp8lVSv7A0qScvsAasN3Qq_QFFVdo,1353
4
+ knowflow/adapters/knowledge/local.py,sha256=e4ZjtV_pirYnIRIgOtaw9aUF8oN7IwUAGAtRRS5oYgE,1648
5
+ knowflow/adapters/knowledge/obsidian.py,sha256=ZeDutTVeW94hRN_owbyiUTi40qEzwReVUNT9ji1Wmqs,2549
6
+ knowflow/adapters/storage/__init__.py,sha256=bb6J19_LrmLSp_nCdeN28r-xoopp3QR89yvjBpQXgvw,1874
7
+ knowflow/adapters/storage/git.py,sha256=6iPwtWCY2GDQg0qomOKjOCAgdW-X2PStypUKTmKJGpg,5636
8
+ knowflow/adapters/storage/local.py,sha256=fu3EmeydRLTtoL1HYDk2OL_pPqZiRMYdocbLUCpToVw,3693
9
+ knowflow/adapters/storage/quark.py,sha256=CgyfSjkIcCUa_cfmSX2JRZ6hi2MFKp95CGUS99MofhQ,7755
10
+ knowflow/adapters/storage/s3.py,sha256=NjSsl-ih4jl6XTxcM6JTMAHh18mClB2BWl7yH6X1vu4,4174
11
+ knowflow/adapters/storage/webdav.py,sha256=2t9Nsbce3URfRGI_mAYEju2KynuuRun5KmW_WTotk5g,7182
12
+ knowflow/cli/__init__.py,sha256=8X1bDnZKnPNZ3xJezWwAPS2fDkbJe4VUoCFu5x3RMM0,8411
13
+ knowflow/cli/template_manager.py,sha256=ud57YtwC-USo9Lkv3AvX7QDH0I6uUeAwphyKHJDm7ho,3122
14
+ knowflow/core/__init__.py,sha256=-v8VwB_BQgRY9vigAip-WX38oIljmbzREvp6VuzAuVQ,500
15
+ knowflow/core/knowledge.py,sha256=tXR8G6gsJgLxI9yKZ_mJSE6TrZsVoQjAcl4RWUSzZ8k,2456
16
+ knowflow/core/pipeline.py,sha256=uu3y5sd9t1bYwVdRxyecIQNy2l0YZXounpEZMNTiAfM,3929
17
+ knowflow/core/storage.py,sha256=_7HE4BMBsjPK52APIv2jF9jIzNHFSt7lSxd4cV9L_vM,5868
18
+ knowflow/dashboard/__init__.py,sha256=PHFtuFIqeDPpPW8T23CfoFiHzNE_XCWFSI6bRMjU2AU,14831
19
+ knowflow/templates/daily-journal/plugin.yaml,sha256=6zCXD2eC9rUccMEn99gCbvOct2BmzsSxVc7lTZD2wFI,414
20
+ knowflow/templates/football-prediction/plugin.yaml,sha256=YLafAZuBww1q_4EAcV4PDSIeZD_plcDfjrFDzcZxsyA,514
21
+ knowflow/templates/project-wiki/plugin.yaml,sha256=AxgXMbhkrFhcs6sJFkCs7bPUgwhsgcWDVMNyD4-rKJE,324
22
+ knowflow/templates/research-notes/plugin.yaml,sha256=YylaNcnMX_75CJWfdjz4rxpsrxiM_oh69qJSRgGUgR4,461
23
+ knowflow/templates/stock-analysis/plugin.yaml,sha256=QQrwZBuLhm2xKhinJGl5jTkqWtBHBuBS4Agg3VTE6xY,495
24
+ knowflow/templates/web-monitor/plugin.yaml,sha256=aYxbmX8ZILprBl8t1Q4OMMtf-Dpq0PBB1EP0SJgO2xk,380
25
+ knowflow/templates/worldcup-tracker/plugin.yaml,sha256=GS8uVmZXd3ZyRrDg8LaECIcfJGu1kXwBA-5HWm1hxtc,375
26
+ knowflow/transforms/__init__.py,sha256=YRwAmekjguNAhDE49k7rvhA_MEEBJzycVfcSdfQR9AU,218
27
+ knowflow/transforms/archive.py,sha256=VHKi_SdClSQsAu64vnHY6pWlhzj6gb16IqCb7vlvK8A,3146
28
+ knowflow/transforms/markdown_export.py,sha256=HpKUGQUiyokkxYxllKgQ_R9nv9czcBtuSblTmFarsdo,4337
29
+ knowflow/transforms/profile_index.py,sha256=0YWOMYkyx3DssbVIj1PwZyh0TjSacD1bL0gbddXu-bA,3409
30
+ knowflow-0.1.0.dist-info/licenses/LICENSE,sha256=2zy51WOPBWAZZDgcq84A7tuTWNxoOkDsNDaUMw8R0IU,1078
31
+ knowflow-0.1.0.dist-info/METADATA,sha256=ZCw-PlZpit-l56vnAZELeVMaQjl0tVdbb4akEQHOPiY,8517
32
+ knowflow-0.1.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
33
+ knowflow-0.1.0.dist-info/entry_points.txt,sha256=W6ZiPq6XlqfFLq6KX5ExpDMHwxHZUdi8ds0w38977fw,47
34
+ knowflow-0.1.0.dist-info/top_level.txt,sha256=8R0Q-41X-rzabioEICJyyX4cUAukG98VI-30ATM4Yfw,9
35
+ knowflow-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ knowflow = knowflow.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 KnowFlow Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ knowflow