acshame
-
-
-
-
- openclaw-android: 在 Android 上以轻量方式运行 OpenClaw 的 Termux 兼容方案
感谢 E5 佬的分享
• 无需安装完整 Linux 发行版,仅通过 glibc 动态链接器即可运行 OpenClaw,显著降低存储占用与部署复杂度
• 一条命令完成 Node.js、路径转换、临时目录、systemd 替代与兼容补丁配置,适合直接在手机上快速落地 AI Agent 环境
• 基于平台插件化架构设计,内置更新、卸载、状态检查与可选工具安装能力,也支持 code-server、OpenCode 和多种 AI CLI 扩展
https://github.com/AidanPark/openclaw-android
#Android #Termux #OpenClaw #AI Agent #Node.js #glibc #移动开发 #开发者工具 #命令行工具 #GitHub - pua — Claude Code Skill
https://pua-skill.pages.dev/ - 📃 Airing 收藏了一篇文章:《cft0808/edict: 🏛️ 三省六部制》via RainDrop - https://github.com/cft0808/edict
Note: 三省六部制 Agent Team,体验自己当皇帝
#bookmark #article -
- 最近在 x 说的多,没有转到频道里,给大家汇总一下 hhhh
1. 关于 Skill 结合业务的一些小心得:https://x.com/polebug/status/2033830964489809978
2. 内部 vibe coding 的小段子:https://x.com/polebug/status/2033476789516050552
3. 最近工作的碎碎念,关于 vibe coding 结合业务工程:
https://x.com/polebug/status/2033432442015777148
https://x.com/polebug/status/2031551329026584831
4. 关于 vibe coding 伤脑的锐评:https://x.com/polebug/status/2031988518394945816
https://x.com/polebug/status/2031919532869288028
---
😭😭😭 糟了,我最近真是班味很重,最近要说点别的,不说工作了 - | 术语 | 定义 |
|------|------|
| Area | JD 顶级分类(00-99) |
| Category | Area 内分类(000-999) |
| ID | Category 内序号(0001-9999) |
| 短 ID | Git 风格的简化 ID(如10.1.15→ `10.001.0015`) |
| Namespace | 资源逻辑分组,对应目录 |
| Frontmatter | Markdown 文件头部 YAML 元数据 |
| GTD | Getting Things Done 方法论 |
| CORE | Capture, Organize, Review, Execute |
| Sidecar Index | SQLite 索引文件(`.synapse/index.db`) |
| Fuzzy Finder | 模糊搜索功能,支持标题匹配 |
| Command Palette | 命令面板,类似 VS CodeCtrl+P|
| Refile | 将资源从 Inbox 移动到目标位置(Emacs Org-mode 术语) |
| Link Refactoring | Refile 时自动更新所有引用该资源的链接 |
| Transaction Rollback | 事务回滚,利用 Git 暂存区实现原子性操作 |
| Hybrid Search | 混合搜索,结合全文(Ripgrep)和元数据(SQLite) |
| Application-Layer Tokenization | 应用层分词,写入/搜索前用 jieba 预处理 |
| Stopword Filtering | 停用词过滤,去除标点和无意义字符 |
| Session Persistence | 会话持久化,记录用户上下文状态 |
| Suspension Context | 暂停上下文,Git 操作期间暂停 watchdog 避免自激 |
| watchdog | Python 文件系统监听库 |
| Textual Workers | Textual 框架的异步任务机制(@work 装饰器) |
---
## 附录 B:参考资源
- [Johnny.Decimal](https://johnnydecimal.com/)
- [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
- [k9s](https://k9scli.io/)
- [GTD](https://gettingthingsdone.com/)
- [GraphRAG](https://github.com/microsoft/graphrag)
- [LiteLLM](https://github.com/BerriAI/litellm)
- [Textual](https://textual.textualize.io/) - Python TUI 框架
- [Ripgrep](https://github.com/BurntSushi/ripgrep) - 高性能搜索工具
- [watchdog](https://github.com/gorakhargosh/watchdog) - Python 文件系统监听
- [jieba](https://github.com/fxsjy/jieba) - 中文分词(FTS5 增强) - | 操作 | 数据源 |
|------|--------|
|syn list,syn search(Frontmatter) | SQLite |
|syn search --content(全文) | Ripgrep → 再查 SQLite 补充元数据 |
|syn show,syn edit| 实际 Markdown 文件 |
### 13.5 混合搜索(Hybrid Search)
**场景**:用户想搜 "Project X"(全文)且 "Status=Todo"(元数据)。
**实现逻辑**:1. Ripgrep 搜索全文 → 返回匹配文件路径列表 2. 用路径列表查询 SQLite → 过滤 Status=Todo 3. 返回最终结果(带完整元数据)
**命令示例**:# 混合搜索:全文包含 "kubernetes" 且状态为 todo syn search "kubernetes" --status todo # 混合搜索:全文包含 "设计" 且标签包含 urgent syn search "设计" --tag urgent # 纯元数据搜索(due-before 基于 due 字段) syn search --type task --priority high --due-before 2024-01-15
**时间筛选参数说明**:
| 参数 | 对应字段 | 说明 |
|------|----------|------|
|--due-before|due| 截止日期早于指定日期的任务 |
|--due-after|due| 截止日期晚于指定日期的任务 |
|--created-before|created| 创建时间早于指定日期 |
|--created-after|created| 创建时间晚于指定日期 |
|--modified-before|modified| 修改时间早于指定日期 |
|--modified-after|modified| 修改时间晚于指定日期 |
**示例**:# 查找本周内到期的任务 syn search --type task --due-after monday --due-before sunday # 查找过去 7 天修改过的笔记 syn search --type note --modified-after "7 days ago"
### 13.6 批量操作与异步机制
针对 10,000+ 文件规模的操作优化:
**SQLite 事务批量写入**:# ❌ 错误:单条插入 1000 次 ≈ 5秒 for item in items: cursor.execute("INSERT INTO resources ...", item) conn.commit() # ✅ 正确:事务批量插入 1000 次 ≈ 0.05秒 cursor.execute("BEGIN TRANSACTION") for item in items: cursor.execute("INSERT INTO resources ...", item) cursor.execute("COMMIT")
**Textual 异步 Workers**:from textual import work class SynapseApp(App): @work(exclusive=True) async def action_batch_update_tags(self, ids: list, add_tag: str): """耗时操作放入后台线程,不阻塞 UI""" self.notify("正在批量更新标签...") # 执行文件 IO 和 DB 更新 await processor.batch_add_tag(ids, add_tag) self.notify(f"✓ 已更新 {len(ids)} 个资源") self.refresh_list()
**进度反馈**:
- 操作耗时 > 500ms 时,TUI 底部状态栏显示 Spinner
- 批量操作(如 Refile 多个文件)显示进度条
---
## 14. 成功标准
1. 快速捕获到 Inbox 并高效处理
2. Johnny.Decimal 编号清晰组织(支持短 ID 和模糊匹配)
3. Git 完整审计追踪(Conventional Commits)
4. k9s 风格 TUI(列表/日历/时间线/图谱视图 + 命令面板)
5. CORE 工作流:捕获 → 组织 → 回顾 → 执行
6. 本地 Hook 优先 + GitHub Actions 远程通知
7. 仅 Markdown,仓库精简(`syn media` 处理附件)
8. Namespace 支持项目级配置
9. 10,000 资源列表 < 500ms(SQLite 索引 + 批量事务)
10. 多端同步无痛(自动 rebase + 智能字段合并)
11. Refile 时链接自动更新,永不断裂
12. 中文全文搜索精准(jieba 应用层分词)
13. 会话状态持久化,随时恢复上下文
---
## 15. 边缘情况处理
| 场景 | 处理方案 |
|------|----------|
| title 修改 | 文件名同步更新(包含 title),但链接仅使用 ID,不受影响 |
| Refile 链接断裂 | 自动全局搜索替换旧 ID → 新 ID(见 5.5) |
| 脏工作区 Refile | 拒绝操作,TUI 提供快捷 Commit/Stash 选项(见 5.5) |
| Refile 中途失败 | 前置检查确保工作区干净后,失败可安全回滚(见 5.5) |
| 短 ID 歧义 | CLI 报错列出候选项,TUI 弹窗二选一(见 3.2) |
| 并发编辑 | watchdog 实时监听 + Hash 检测(见 7.6) |
| watchdog 自激 | Git 操作期间暂停监听(SuspensionContext),避免误报(见 7.6) |
| 多端同步 | 启动 `pull --rebase`,退出 `push`,智能字段合并(见 7.4-7.5) |
| 索引损坏 |syn index rebuild重建 |
| 大文件 |.gitignore排除,`syn media` 上传到外部存储 |
| 耗时操作 | Textual @work 异步执行,底部显示进度(见 13.6) |
| 中文搜索噪音 | 停用词过滤 + 标点清理,减小索引体积(见 13.2) |
---
## 16. 范围外(初始版本)
**优先级低,预留设计的功能**:
- **§8 媒体管理**:初始版本仅支持外部链接,`syn media` 命令预留
- **§10 知识图谱**:初始版本不实现,预留syn graph接口
- **§11 邮件集成**:初始版本仅支持手动创建,API 集成预留
**明确排除的功能**:
- 完整 LLM GraphRAG(仅预留接口)
- 实时协作(多人同时编辑)
- Web/移动端
- 邮件 API 自动集成
- 自定义 FTS5 分词器(使用应用层分词替代)
---
## 附录 A:术语表 - | 协议 | 认证方式 | 说明 |
|------|----------|------|
| Gmail API | OAuth2 | 需要 Google Cloud 项目 |
| IMAP | SSL/TLS | 传统邮箱协议 |
| Microsoft Graph | OAuth2 | Outlook/Office365 |
**凭证配置(预留)**:# config.yaml email: provider: gmail # gmail | imap | microsoft gmail: client_id_env: GMAIL_CLIENT_ID client_secret_env: GMAIL_CLIENT_SECRET imap: server: imap.example.com port: 993 username_env: IMAP_USERNAME password_env: IMAP_PASSWORD
---
## 12. 配置
### 12.1 配置文件示例# ~/.config/synapse/config.yaml workspace: ~/synapse-data default_namespace: personal namespaces: - personal # 1 - work-project # 2 - study # 3 editor: windows: { default: notepad, options: [notepad, typora, code] } linux: { default: vim, options: [vim, typora] } macos: { default: vim, options: [vim, typora] } git: auto_commit: true commit_style: conventional # conventional | simple | llm llm: enabled: false provider: litellm model: gpt-4o-mini api_base: https://api.openai.com/v1 api_key_env: OPENAI_API_KEY remotes: - name: origin url: [email protected]:user/synapse-data.git auto_push: true johnny_decimal: areas: 00: "Inbox" 10: "个人管理" 20: "工作项目" 30: "学习成长" review: daily_time: "08:00" weekly_day: friday weekly_time: "18:00"
---
## 13. 性能与索引机制
### 13.1 性能目标
| 操作 | 目标 | 实现方式 |
|------|------|----------|
| 列表 10,000 资源 | < 500ms | SQLite 索引 |
| 全文搜索 | < 1s | Ripgrep |
| 创建/更新 | < 300ms | 增量索引更新 |
### 13.2 SQLite Sidecar Index
**问题**:10,000 个 Markdown 文件逐个解析 Frontmatter,IO 开销巨大。
**方案**:`.synapse/index.db` 缓存所有元数据。-- 主索引表 CREATE TABLE resources ( id TEXT PRIMARY KEY, -- "10.001.0015" namespace TEXT, area TEXT, -- "10" category TEXT, -- "001" type TEXT, title TEXT, status TEXT, priority TEXT, due DATE, created DATETIME, modified DATETIME, tags TEXT, -- JSON array content_hash TEXT, -- 用于变更检测 file_path TEXT ); -- 全文搜索 (FTS5) - 存储预分词后的内容 CREATE VIRTUAL TABLE resources_fts USING fts5( id, title_tokens, tags_tokens, content_tokens, tokenize = 'simple' -- 使用默认分词器,输入已分词字符串 );
**中文搜索:应用层分词方案**(推荐)
SQLite 原生不支持加载 Python jieba 作为分词器。最佳实践是**应用层分词**:import jieba import re # 停用词表(标点、空格、无意义字符) STOPWORDS = set(['的', '了', '是', '在', '我', '有', '和', '就', '不', '人', '都', '一', '一个', '上', '也', '很', '到', '说', '要', '去', '你', '会', '着', '没有']) class SearchEngine: def _tokenize(self, text: str) -> str: """分词 + 停用词过滤 + 标点清理""" # 1. 移除标点符号和特殊字符 text = re.sub(r'[^\w\s\u4e00-\u9fff]', ' ', text) # 2. jieba 分词 tokens = jieba.cut_for_search(text) # 3. 停用词过滤 + 去除空白 filtered = [t.strip() for t in tokens if t.strip() and t not in STOPWORDS] return " ".join(filtered) def update_index(self, id: str, title: str, content: str): """写入索引前,用 jieba 预处理 + 停用词过滤""" title_tokens = self._tokenize(title) content_tokens = self._tokenize(content) cursor.execute(""" INSERT INTO resources_fts (id, title_tokens, content_tokens) VALUES (?, ?, ?) """, (id, title_tokens, content_tokens)) def search(self, query: str): """搜索时,同样分词处理""" query_tokens = " AND ".join(self._tokenize(query).split()) cursor.execute(""" SELECT id FROM resources_fts WHERE content_tokens MATCH ? """, (query_tokens,))
**停用词过滤的好处**:
- 减小index.db体积(去除 30%+ 无意义词)
- 提高搜索精度(避免"的"、"了"等高频词干扰)
- 加快搜索速度
**工作流程**:
- **写入**:"完成了需求设计!" → 清理标点 → jieba → 过滤停用词 → "完成 需求 设计" → 存入 FTS
- **搜索**:用户搜 "需求" → 同样处理 → "需求" → MATCH 成功
### 13.3 索引更新策略
| 触发时机 | 动作 |
|----------|------|
|syn启动 | 检测 Git 变更,增量更新索引 |
| CRUD 操作 | 实时更新索引 |
| Git hook |post-merge,post-checkout触发重建 |
| 手动 |syn index rebuild强制重建 |
### 13.4 查询路由 -
# config.yaml media: provider: s3 # s3 | github | local # 凭证配置 credentials: # 方式 1:环境变量(推荐) aws_access_key_env: AWS_ACCESS_KEY_ID aws_secret_key_env: AWS_SECRET_ACCESS_KEY # 方式 2:配置文件(不推荐,敏感信息) # aws_access_key: "AKIA..." # aws_secret_key: "..." s3: bucket: your-bucket region: us-east-1 prefix: synapse/ # 存储前缀 # 最终路径:s3://your-bucket/synapse/{resource_id}/{filename} github: repo: user/media branch: main token_env: GITHUB_TOKEN # GitHub Personal Access Token local: path: ~/synapse-media # 本地存储路径(.gitignore 隔离) base_url: file://~/synapse-media
### 8.5 TUI 集成(预留)
在编辑模式下:
-Ctrl+V`:检测剪贴板图片 → 自动调用 `syn media paste→ 插入链接
---
## 9. 自动化工作流
### 9.1 本地自动化(优先)
对于生成类任务,优先使用**本地 Hook**,无需等待网络:# 本地执行,立即生成并打开 syn review daily # → 生成今日回顾,直接打开编辑 syn review weekly # → 生成周报,直接打开编辑 syn review monthly # → 生成月报,直接打开编辑 syn standup # → 生成站会报告 # LLM 辅助生成(可选) syn review daily --llm # → 使用 LLM 生成摘要 syn review weekly --llm # → 使用 LLM 生成周报 syn review monthly --llm # → 使用 LLM 生成月报
#### 9.1.1 Review 资源类型与存储
Review 生成的资源是 note 类型,存储在配置的 review Area/Category 下:personal/ └── 90/ # Area 90: 回顾与复盘 ├── 001/ # Category 001: 每日回顾 │ ├── 90.001.0001-note-2024-01-15-daily-review.md │ └── 90.001.0002-note-2024-01-16-daily-review.md ├── 002/ # Category 002: 每周回顾 │ └── 90.002.0001-note-2024-W03-weekly-review.md ├── 003/ # Category 003: 每月回顾 │ └── 90.003.0001-note-2024-01-monthly-review.md └── 004/ # Category 004: 站会报告 └── 90.004.0001-note-2024-01-15-standup.md
**Frontmatter 示例**:--- jd_number: "90.001.0015" type: note namespace: personal title: "2024-01-15 每日回顾" tags: [review, daily] created: 2024-01-15T18:00:00Z modified: 2024-01-15T18:30:00Z review_type: daily # daily | weekly | monthly | standup review_period: "2024-01-15" llm_generated: false # 是否使用 LLM 生成 ---
**本地 Hook 配置**:# config.yaml hooks: review_daily: command: "python ~/.synapse/hooks/daily_review.py" auto_open: true # 生成后自动打开编辑器 review_weekly: command: "python ~/.synapse/hooks/weekly_review.py" auto_open: true review_monthly: command: "python ~/.synapse/hooks/monthly_review.py" auto_open: true standup: command: "python ~/.synapse/hooks/standup.py" auto_open: true review: area: "90" # Review 存储的 Area daily_category: "001" # syn review daily weekly_category: "002" # syn review weekly monthly_category: "003" # syn review monthly standup_category: "004" # syn standup llm: enabled: true prompt_template: "~/.synapse/prompts/review.md"
### 9.2 GitHub Actions 模板(远程)
用于**跨设备通知**和**长期归档**:
| 模板 | 触发 | 功能 |
|------|------|------|
| daily-standup | 工作日 9:00 | 昨日完成、今日计划、阻塞问题 |
| weekly-review | 周五 18:00 | 周报生成 |
| due-reminder | 每天 8:00 | 到期/逾期提醒 |
| inbox-reminder | 工作日 17:00 | Inbox 清理提醒 |
| monthly-retro | 每月 1 日 | 月度复盘归档 |
| graph-sync | push 触发 | 图谱同步 |
**设计理念**:
- **本地 Hook**:生成类(review, standup)→ 即时响应,无网络依赖
- **GitHub Actions**:通知类、归档类 → 跨设备、定时触发
---
## 10. 知识图谱(优先级低,预留设计)
> ⚠️ 本章节为预留设计,待后续迭代完善。初始版本不实现图谱功能。
### 10.1 预留接口syn graph # 启动图谱视图(TUI) syn graph export # 导出图谱数据 syn graph sync # 同步到 Nebula Graph(如配置)
### 10.2 数据模型(预留)
**节点类型**:Resource, Namespace, Tag, Person, TimePoint, Chunk
**边类型**:RELATED_TO, BELONGS_TO, CREATED_BY, ASSIGNED_TO, TAGGED_WITH, BLOCKED_BY 等
### 10.3 GraphRAG 集成(预留)
- 使用 Nebula Graph 存储知识图谱
- 支持 LLM 驱动的图谱查询和推理
- 自动发现资源间的隐含关系
---
## 11. 邮件集成(优先级低,预留设计)
> ⚠️ 本章节为预留设计,待后续迭代完善。初始版本仅支持手动创建邮件资源。
### 11.1 手动创建(初始版本支持)syn new email --subject "项目进度汇报"
- 支持剪贴板粘贴邮件内容
- 自动解析标题和正文
- 发件人/收件人需手动填写
### 11.2 API 集成(预留) - **字段级合并策略配置**:
# config.yaml git: merge_strategy: # 默认策略:取 modified 最新的一方 (Last Write Wins) default: "take_latest_modified" # 特殊字段策略 fields: # 标签:取并集。A端加了[urgent], B端加了[work] -> [urgent, work] tags: "union" # 关联:取并集 related: "union" # 状态:取最新修改方(或自定义优先级:done > in-progress > todo) status: "take_latest_modified" # 正文内容:标准 Git 文本合并 content: "git_standard"
**冲突安全网**:
- 当 Merge Driver 无法自动解决(如正文同一行被修改):
- 生成.conflict备份文件
- TUI 启动时检测到冲突文件 → 进入"冲突解决向导"模式
- 用户可选择:保留本地 / 保留远程 / 手动合并
### 7.6 并发编辑检测
**场景**:TUI 打开时,用户用 VS Code 编辑同一文件。
**方案 1:Hash 检测**(基础)
1.syn edit前:记录文件 hash
2. 外部编辑器关闭后:检查 hash
3. 如果 hash 变化且非当前进程修改:
- 提示冲突
- 显示 diff
- 用户选择:覆盖 / 合并 / 放弃
**方案 2:watchdog 实时监听**(增强)
使用watchdog库监听文件系统事件,TUI 运行时实时感知外部修改:# 伪代码示意 - 注意线程安全! from watchdog.observers import Observer from watchdog.events import FileSystemEventHandler class SynapseFileWatcher(FileSystemEventHandler): def __init__(self, app): self.app = app # Textual App 实例 def on_modified(self, event): if event.src_path == self.app.current_open_file: # ⚠️ 关键:watchdog 在独立线程,必须用 call_from_thread self.app.call_from_thread( self.app.show_file_modified_warning, event.src_path )
**线程安全注意**:
-watchdog运行在独立线程
- Textual UI 更新必须在主线程
- 必须使用app.call_from_thread()跨线程调用,否则 TUI 会崩溃
**自激抑制(Suspension Context)**:
⚠️ **问题**:当 Synapse 执行git pull或git checkout时,文件系统变化会触发 watchdog,错误地向用户报告"外部修改警告"。class FileWatcher: def __init__(self): self._suspended = False def pause(self): """暂停监听(Git 操作前调用)""" self._suspended = True def resume(self): """恢复监听(Git 操作后调用)""" self._suspended = False def on_modified(self, event): if self._suspended: return # 忽略自身触发的变更 # ... 正常处理外部修改 class SynapseApp: def perform_git_operation(self): self.file_watcher.pause() # 暂停监听 try: git.pull() self.index.refresh() # 主动刷新索引 finally: self.file_watcher.resume() # 恢复监听
**行为**:
- TUI 打开时,自动启动 watchdog **仅监听当前 Namespace 目录**(性能优化)
- 切换 Namespace 时,watchdog 同步切换监听目标
- 检测到当前查看/编辑的文件被外部修改 → 实时弹出警告
- 用户可选择:重新加载 / 忽略 / 查看 diff
- **Git 操作期间自动暂停监听**,避免误报class SynapseFileWatcher: def __init__(self, app): self.app = app self.observer = Observer() self._current_path = None self._started = False def start(self): """启动观察者线程(TUI 启动时调用)""" if not self._started: self.observer.start() self._started = True def stop(self): """停止观察者线程(TUI 退出时调用)""" if self._started: self.observer.stop() self.observer.join() # 等待线程结束 self._started = False def watch_namespace(self, namespace_path: str): """切换监听目标到指定 Namespace""" # 1. 取消之前的监听 if self._current_path: self.observer.unschedule_all() # 2. 调度新的监听目标 self._current_path = namespace_path self.observer.schedule( self, namespace_path, recursive=True # 监听 Namespace 下所有子目录 ) # 3. 确保观察者已启动 self.start()
---
## 8. 媒体管理(优先级低,预留设计)
> ⚠️ 本章节为预留设计,待后续迭代完善。初始版本仅支持外部链接引用媒体。
### 8.1 设计原则
- **仓库纯净**:禁止二进制文件直接入库
- **体验友好**:提供便捷的截图/贴图工作流
### 8.2syn media命令# 从剪贴板上传图片 syn media paste # → 自动上传到配置的存储 → 返回 Markdown 链接 # 上传指定文件 syn media upload /path/to/image.png # 输出示例 
### 8.3 媒体存储目录结构
**建议使用资源 ID 作为目录名**,便于关联和管理:媒体存储根目录/ ├── 10.001.0015/ # 资源 ID 为目录名 │ ├── screenshot-001.png │ └── diagram.svg ├── 10.002.0003/ │ └── meeting-photo.jpg └── _orphan/ # 未关联资源的媒体(待清理) └── temp-upload.png
### 8.4 媒体存储配置 - **TUI 交互**:
┌─────────────────────────────────────────────────────────┐ │ ⚠️ Refile 需要干净的工作区 │ ├─────────────────────────────────────────────────────────┤ │ 检测到以下未提交的修改: │ │ M 10/001/10.001.0005-note-学习笔记.md │ │ M 20/001/20.001.0003-task-开发任务.md │ │ │ │ 请先提交或暂存这些修改: │ │ [C] 快速提交 (commit -m 'WIP') │ │ [S] 暂存 (git stash) │ │ [Q] 取消 Refile │ └─────────────────────────────────────────────────────────┘
**行为**:
- Refile 前**必须检查**工作区状态
- 脏工作区时拒绝操作,提示用户先提交/暂存
- TUI 提供快捷操作:一键 Commit WIP 或 Stash
- 绝不丢失用户的其他修改
**更新的引用类型**:
| 引用形式 | 示例 | 搜索方式 | 更新方式 |
|----------|------|----------|----------|
| Wiki-style 链接 |[[10.001.0001]]| Ripgrep | 字符串替换 |
| Frontmatter related |related: ["10.001.0001"]| SQLite 索引 | 解析 YAML,更新数组 |
设计原则:精确引用更新,避免误改
⚠️ **不进行盲目的全文替换**:只更新明确的引用语法,不替换正文中的裸 ID 字符串。--- related: ["10.001.0001"] # ← YAML 数组,精确更新 ✓ --- # 设计说明 参考 [[10.001.0001]] 的架构思路... # ← Wiki-style 链接,更新 ✓ 任务 10.001.0001 定义了核心接口... # ← 裸 ID,不更新 ✗(可能是历史描述)
为什么不替换裸 ID?
- 裸 ID 可能出现在非引用上下文:`"历史记录显示 10.001.0001 已于 2023 年完成"`
- 格式说明文本:`"ID 格式为 10.001.0001,其中 10 表示 Area..."`
- 盲目替换会导致语义错误和数据损坏
- 用户若需更新裸 ID,可通过--dry-run预览后手动处理
为什么 related 字段仍需 SQLite?related是 YAML 数组格式,直接全文替换可能破坏 YAML 结构:# 原始 related: ["10.001.0001", "10.002.0003"] # Ripgrep 替换后可能出现的问题(如果替换逻辑不够精确) related: ["20.001.0005", "10.002.0003"] # ✓ 正确 related: ["20.001.0005", "20.001.0005"] # ✗ 如果 10.002.0003 也被误改
**SQLite 方案确保**:
- 查询精确定位到related字段
- 解析 JSON 数组后,只替换匹配的元素
- 重新序列化,保证 YAML 格式正确
**Refile 预览模式**:
为避免意外修改,支持--dry-run预览变更:syn inbox move 00.000.0001 --to work-project --dry-run # 输出预览: Will refile: 00.000.0001 → 20.001.0003 Source file: R inbox/00.000.0001-unprocessed-xxx.md → work-project/20/001/20.001.0003-task-xxx.md - Frontmatter: jd_number: "00.000.0001" → "20.001.0003" References to update (2 files): M personal/10/001/10.001.0005-note-设计笔记.md - Line 5: related: ["00.000.0001"] → ["20.001.0003"] - Line 12: [[00.000.0001]] → [[20.001.0003]] M personal/10/002/10.002.0001-task-开发任务.md - Line 15: [[00.000.0001]] → [[20.001.0003]] Skipped (bare IDs not updated): - personal/10/003/10.003.0001-note-历史记录.md - Line 8: "任务 00.000.0001 已于 2023 年完成"(裸 ID,需手动处理) Proceed? [y/N]
> **注意**:预览中的 "Skipped" 部分提示用户哪些裸 ID 不会被自动更新,用户可根据需要手动处理。
---
## 6. 工作流与回顾
### 6.1 回顾类型
| 类型 | 触发 | 内容 |
|------|------|------|
| 每日 |syn review daily| 今日到期、今日会议、昨日未完成 |
| 每周 |syn review weekly| 本周完成、下周计划、项目进度 |
| Inbox |syn inbox process| 处理未分类项目 |
### 6.2 智能提醒
- 任务接近截止日期时高亮显示
- 资源长期未访问时在回顾中提示
- 阻塞任务链识别和提示
---
## 7. 存储与版本控制
### 7.1 Markdown 格式
**文件命名**:`{Area}.{Category}-{resource-type}-{title}.md`
**Frontmatter 示例**:--- jd_number: "10.001.0015" type: task namespace: work-project title: "完成项目设计" status: in-progress priority: high due: 2024-01-15 created: 2024-01-01T10:00:00Z modified: 2024-01-05T14:30:00Z tags: [design, urgent] related: ["10.001.0012", "10.002.0003"] ---
### 7.2 文件约束
- 仅允许.md文件
- 禁止 图片、视频、音频等二进制文件
- 必须 使用外部链接引用媒体资源
-.gitignore配置忽略常见二进制格式
### 7.3 Git 集成
- 自动提交:所有 CRUD 操作
- commit 格式:Conventional Commits
- 支持多远程仓库
- 支持 SSH/HTTPS 认证
### 7.4 Git 同步策略
| 时机 | 动作 |
|------|------|
|syn启动 |git pull --rebase|
| CRUD 操作 |git add+git commit|
|syn退出 /syn sync|git push|
### 7.5 智能冲突合并
**问题**:多端同步时,`modified` 时间戳经常冲突。
**方案**:自定义 Git merge driver + 细粒度字段策略# .gitattributes *.md merge=synapse-frontmatter# .git/config 或全局配置 [merge "synapse-frontmatter"] name = Synapse Frontmatter Merge driver = syn merge-driver %O %A %B %P -
def refile_with_link_update(old_id, new_id, old_path, new_path, workspace): # 0. 前置检查:工作区必须干净 if not is_working_tree_clean(): raise RefileError( "Refile requires a clean working tree.\n" "Please commit or stash your changes first:\n" " syn commit -m 'WIP' 或 git stash" ) try: # 1. 移动源文件(暂存) git_mv(old_path, new_path) # 1b. 更新源文件的 Frontmatter(jd_number 字段) source_content = read_file(new_path) # 文件已移动,从新路径读取 source_fm, source_body = parse_frontmatter(source_content) source_fm['jd_number'] = new_id # 更新 ID source_fm['modified'] = datetime.now().isoformat() # 更新修改时间 write_file(new_path, serialize_frontmatter(source_fm) + source_body) git_add(new_path) # ⚠️ 必须暂存源文件的内容修改(git_mv 只暂存重命名) # 2. 查找并更新所有引用(其他文件) # ⚠️ 顺序重要:先 YAML 精确处理,再全文替换,避免竞态 modified_files = set() files_with_related = set() # 记录有 related 字段的文件 # 2a. 先处理 Frontmatter 中的 related 字段(YAML 精确解析) # 必须先于全文替换,否则 old_id 已被替换,条件判断会失败 related_refs = db_query( "SELECT file_path FROM resources WHERE related LIKE ?", (f'%"{old_id}"%',) # 在 JSON 数组字符串中搜索 ) for (file_path,) in related_refs: content = read_file(file_path) frontmatter, body = parse_frontmatter(content) # 安全检查:确保 related 是非空列表 related = frontmatter.get('related') if isinstance(related, list) and old_id in related: # 精确更新 YAML 数组 frontmatter['related'] = [ new_id if rid == old_id else rid for rid in related ] # 只替换 wiki-style 链接(避免误改非引用上下文) body = body.replace(f"[[{old_id}]]", f"[[{new_id}]]") content = serialize_frontmatter(frontmatter) + body write_file(file_path, content) modified_files.add(file_path) files_with_related.add(file_path) # 2b. 搜索 wiki-style 链接:[[old_id]] # ⚠️ 只更新明确的引用语法,不盲目替换正文中的 ID 字符串 wiki_refs = rg_search(f"\\[\\[{old_id}\\]\\]", workspace) for file_path in wiki_refs: if file_path in files_with_related: continue # 已被 2a 处理,跳过 content = read_file(file_path) content = content.replace(f"[[{old_id}]]", f"[[{new_id}]]") write_file(file_path, content) modified_files.add(file_path) # 3. 暂存所有修改 for f in modified_files: git_add(f) # 4. 提交事务(+1 是源文件本身) git_commit(f"refactor: refile {old_id} → {new_id}, update {len(modified_files) + 1} files") except Exception as e: # 4. 安全回滚(因为工作区干净,此时可以安全 reset) git_reset_hard() logger.error(f"Refile failed, rolled back: {e}") raise RefileError("操作失败,已回滚所有修改") def is_working_tree_clean() -> bool: """检查工作区是否干净""" result = subprocess.run( ["git", "status", "--porcelain"], capture_output=True, text=True ) return len(result.stdout.strip()) == 0
策略 B:智能回滚(复杂场景)
如果必须允许脏工作区 Refile,回滚时需精确还原:def smart_rollback(modified_files: list, old_path: str, new_path: str): """精确回滚,不影响其他未提交修改""" # 1. Unstage 暂存的文件 for f in modified_files: subprocess.run(["git", "reset", "HEAD", f]) # 2. 还原被修改的文件内容 for f in modified_files: subprocess.run(["git", "checkout", "--", f]) # 3. 移回源文件 if os.path.exists(new_path): subprocess.run(["git", "mv", new_path, old_path])