Skill: jirboy/obsidian-manager (version 1.0.0)

--- name: obsidian-manager description: [已整合] Obsidian 笔记管理已整合到 knowledge 统一入口技能 argument-hint: "[操作] [参数]" --- # ⚠️ 已整合 - 请使用 knowledge 统一入口 > **本技能保留用于向后兼容，功能已整合到 `knowledge` 统一入口技能** > > **推荐使用：** `knowledge obsidian [操作]` 或直接使用本技能（自动转发） --- # Obsidian Manager（兼容层） Obsidian 知识笔记管理技能，支持笔记创建、检索、双向链接。 ## 迁移指南 **新用法：** ``` knowledge obsidian create 标题 方向 knowledge obsidian search 关键词 knowledge obsidian link 笔记 A 笔记 B knowledge obsidian list 方向 ``` **旧用法（仍然可用）：** ``` obsidian create 标题 方向 ``` ## 研究方向目录 | 编号 | 研究方向 | 目录路径 | |------|---------|---------| | 01 | 振动台控制技术 | research/01-振动台控制技术 | | 02 | RTHS 子结构试验 | research/02-RTHS 子结构试验 | | 03 | 文物隔震 | research/03-文物隔震 | | 04 | 粉末阻尼 | research/04-粉末阻尼 | | 05 | 超材料隔震 | research/05-超材料隔震 | | 06 | NTMD 减振 | research/06-NTMD 减振 | | 07 | 地震预测 | research/07-地震预测 | ## 核心功能 - ✅ 笔记创建（带模板） - ✅ 全文搜索 - ✅ 双向链接 - ✅ 知识图谱 ## 注意事项 - ✅ 本地文件，无需配置 - ❌ 不要存储在 C 盘（Shadow Defender 保护）

path: obsidian_new.py
content: #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Obsidian 笔记创建工具

用法:
    python obsidian_new.py --title "笔记标题" --direction "01-振动台控制技术"
    python obsidian_new.py --title "笔记标题" --template "literature"
"""

import argparse
import os
import sys
from datetime import datetime
from pathlib import Path


# 研究方向映射
DIRECTIONS = {
    '01': '01-振动台控制技术',
    '02': '02-RTHS 子结构试验',
    '03': '03-文物隔震',
    '04': '04-粉末阻尼',
    '05': '05-超材料隔震',
    '06': '06-NTMD 减振',
    '07': '07-地震预测',
    '08': '08-爆破模拟地震',
    '09': '09-实验室管理',
    '10': '10-研究生培养'
}

# 笔记模板
TEMPLATES = {
    'default': '''# {title}

**创建时间：** {date}  
**标签：** {tags}

---

## 概述

待填充

---

## 核心内容

待填充

---

## 相关笔记

[[INDEX|返回总索引]]

---

**备注：** 本笔记待填充。
''',
    
    'literature': '''---
title: {title}
authors: {authors}
year: {year}
journal: {journal}
tags: [文献，{direction}]
zotero-link: {zotero_link}
created: {date}
---

# {title}

## 核心贡献

待填充

---

## 研究方法

待填充

---

## 主要结论

待填充

---

## 我的思考

待填充

---

## 相关研究
[[相关笔记链接]]

---

**备注：** 本笔记待填充。
''',
    
    'topic': '''---
title: {title}
tags: [主题，{direction}]
created: {date}
---

# {title}

## 概述

待填充

---

## 核心概念

待填充

---

## 关键文献
- [[文献笔记 1]]
- [[文献笔记 2]]

---

## 研究进展

待填充

---

## 待解决问题

待填充

---

**备注：** 本笔记待填充。
''',
    
    'experiment': '''---
title: {title}
date: {date}
tags: [实验，{direction}]
---

# {title}

## 实验目的

待填充

---

## 实验设备

待填充

---

## 实验步骤

待填充

---

## 实验数据

待填充

---

## 结果分析

待填充

---

## 下一步计划

待填充

---

**备注：** 本笔记待填充。
'''
}


def get_research_base_path():
    """获取 research 基础路径"""
    base = Path(__file__).parent.parent / 'research'
    if not base.exists():
        # 尝试其他可能路径
        base = Path(r'D:\Personal\OpenClaw\research')
    return base


def get_direction_path(direction):
    """获取研究方向目录路径"""
    base = get_research_base_path()
    
    # 如果 direction 是编号（如"01"），转换为完整名称
    if direction in DIRECTIONS:
        direction = DIRECTIONS[direction]
    
    dir_path = base / direction
    if not dir_path.exists():
        print(f"错误：研究方向目录不存在：{dir_path}")
        print(f"可用方向：{', '.join(DIRECTIONS.values())}")
        return None
    
    return dir_path


def create_note(title, direction='01', template='default', authors='', year='', journal='', zotero_link=''):
    """创建笔记"""
    # 获取目录路径
    dir_path = get_direction_path(direction)
    if not dir_path:
        return None
    
    # 生成文件名
    filename = f"{title}.md"
    file_path = dir_path / filename
    
    # 检查文件是否已存在
    if file_path.exists():
        print(f"警告：文件已存在：{file_path}")
        overwrite = input("是否覆盖？(y/n): ")
        if overwrite.lower() != 'y':
            print("已取消")
            return None
    
    # 获取方向名称
    direction_name = direction
    for k, v in DIRECTIONS.items():
        if v == direction:
            direction_name = v
            break
    
    # 准备模板参数
    params = {
        'title': title,
        'date': datetime.now().strftime('%Y-%m-%d %H:%M'),
        'tags': direction,
        'direction': direction_name,
        'authors': authors,
        'year': year,
        'journal': journal,
        'zotero_link': zotero_link
    }
    
    # 获取模板
    template_content = TEMPLATES.get(template, TEMPLATES['default'])
    
    # 填充模板
    content = template_content.format(**params)
    
    # 写入文件
    with open(file_path, 'w', encoding='utf-8') as f:
        f.write(content)
    
    return file_path


def main():
    parser = argparse.ArgumentParser(description='Obsidian 笔记创建工具')
    parser.add_argument('--title', '-t', type=str, required=True, help='笔记标题')
    parser.add_argument('--direction', '-d', type=str, default='01', 
                       help='研究方向（编号或名称）')
    parser.add_argument('--template', '-tpl', type=str, default='default',
                       choices=['default', 'literature', 'topic', 'experiment'],
                       help='笔记模板类型')
    parser.add_argument('--authors', type=str, default='', help='作者（文献笔记用）')
    parser.add_argument('--year', type=str, default='', help='年份（文献笔记用）')
    parser.add_argument('--journal', type=str, default='', help='期刊（文献笔记用）')
    parser.add_argument('--zotero-link', type=str, default='', help='Zotero 链接（文献笔记用）')
    
    args = parser.parse_args()
    
    print(f"创建笔记：{args.title}")
    print(f"研究方向：{args.direction}")
    print(f"模板类型：{args.template}")
    print("-" * 60)
    
    # 创建笔记
    file_path = create_note(
        title=args.title,
        direction=args.direction,
        template=args.template,
        authors=args.authors,
        year=args.year,
        journal=args.journal,
        zotero_link=args.zotero_link
    )
    
    if file_path:
        print(f"\n✅ 笔记创建成功")
        print(f"   文件：{file_path}")
        print(f"   链接：[[{args.direction}/{args.title}]]")
        print(f"\n提示：可以用 Obsidian 打开并编辑笔记")
    else:
        print("\n❌ 笔记创建失败")
        sys.exit(1)


if __name__ == '__main__':
    main()


path: obsidian_search.py
content: #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Obsidian 笔记搜索工具

用法:
    python obsidian_search.py --query "RTHS" --limit 10
    python obsidian_search.py --direction "02-RTHS" --tag "文献"
"""

import argparse
import json
import re
import sys
from datetime import datetime
from pathlib import Path


def get_research_base_path():
    """获取 research 基础路径"""
    base = Path(__file__).parent.parent / 'research'
    if not base.exists():
        base = Path(r'D:\Personal\OpenClaw\research')
    return base


def search_notes(query, limit=10, direction=None, tag=None):
    """搜索笔记"""
    base = get_research_base_path()
    results = []
    
    # 确定搜索目录
    search_dirs = [base]
    if direction:
        direction_dir = base / direction
        if direction_dir.exists():
            search_dirs = [direction_dir]
        else:
            print(f"警告：研究方向目录不存在：{direction}")
    
    # 遍历所有 markdown 文件
    for search_dir in search_dirs:
        for md_file in search_dir.rglob('*.md'):
            # 跳过模板文件
            if md_file.name == 'template.md':
                continue
            
            try:
                with open(md_file, 'r', encoding='utf-8') as f:
                    content = f.read()
                
                # 标签过滤
                if tag:
                    if f'tags:' not in content or tag not in content:
                        continue
                
                # 关键词搜索（标题或内容）
                if query:
                    # 检查标题
                    title_match = re.search(r'^#\s+(.+)$', content, re.MULTILINE)
                    title = title_match.group(1) if title_match else md_file.stem
                    
                    # 检查内容是否包含关键词
                    if query.lower() not in content.lower() and query.lower() not in title.lower():
                        continue
                else:
                    title = md_file.stem
                
                # 提取元数据
                frontmatter = {}
                frontmatter_match = re.search(r'^---\n(.*?)\n---', content, re.DOTALL)
                if frontmatter_match:
                    fm_text = frontmatter_match.group(1)
                    for line in fm_text.split('\n'):
                        if ':' in line:
                            key, value = line.split(':', 1)
                            frontmatter[key.strip()] = value.strip()
                
                # 创建结果
                result = {
                    'title': title,
                    'file': str(md_file),
                    'relative_path': str(md_file.relative_to(base)),
                    'direction': md_file.parent.name,
                    'created': frontmatter.get('created', frontmatter.get('date', '')),
                    'tags': frontmatter.get('tags', ''),
                    'snippet': get_snippet(content, query)
                }
                results.append(result)
                
            except Exception as e:
                print(f"读取文件失败 {md_file}: {e}")
                continue
    
    # 按创建时间排序（最新的在前）
    results.sort(key=lambda x: x.get('created', ''), reverse=True)
    
    return results[:limit]


def get_snippet(content, query, context=50):
    """获取包含关键词的摘要"""
    if not query:
        return ""
    
    # 查找关键词位置
    content_lower = content.lower()
    query_lower = query.lower()
    pos = content_lower.find(query_lower)
    
    if pos == -1:
        return ""
    
    # 获取上下文
    start = max(0, pos - context)
    end = min(len(content), pos + len(query) + context)
    
    snippet = content[start:end]
    snippet = snippet.replace('\n', ' ').strip()
    
    if start > 0:
        snippet = "..." + snippet
    if end < len(content):
        snippet = snippet + "..."
    
    return snippet


def format_results(results, json_output=False):
    """格式化搜索结果"""
    if json_output:
        return json.dumps(results, ensure_ascii=False, indent=2)
    
    output = []
    for i, item in enumerate(results, 1):
        output.append(f"\n[{i}] **{item['title']}**")
        output.append(f"    路径：{item['relative_path']}")
        if item['created']:
            output.append(f"    创建：{item['created']}")
        if item['tags']:
            output.append(f"    标签：{item['tags']}")
        if item['snippet']:
            output.append(f"    摘要：{item['snippet']}")
    
    return '\n'.join(output)


def list_notes(direction=None):
    """列出指定方向的所有笔记"""
    base = get_research_base_path()
    
    if direction:
        direction_dir = base / direction
        if not direction_dir.exists():
            print(f"错误：研究方向目录不存在：{direction}")
            return []
        
        md_files = list(direction_dir.glob('*.md'))
        return [{'title': f.stem, 'file': str(f), 'direction': direction} for f in md_files]
    else:
        # 列出所有方向的笔记
        all_notes = []
        for direction_name in sorted(os.listdir(base)):
            direction_dir = base / direction_name
            if direction_dir.is_dir():
                md_files = list(direction_dir.glob('*.md'))
                for f in md_files:
                    all_notes.append({
                        'title': f.stem,
                        'file': str(f),
                        'direction': direction_name
                    })
        return all_notes


def main():
    parser = argparse.ArgumentParser(description='Obsidian 笔记搜索工具')
    parser.add_argument('--query', '-q', type=str, help='搜索关键词')
    parser.add_argument('--direction', '-d', type=str, help='研究方向')
    parser.add_argument('--tag', '-t', type=str, help='标签过滤')
    parser.add_argument('--limit', '-l', type=int, default=10, help='返回结果数量')
    parser.add_argument('--list', action='store_true', help='列出笔记（不搜索）')
    parser.add_argument('--json', action='store_true', help='以 JSON 格式输出')
    
    args = parser.parse_args()
    
    if not args.query and not args.list and not args.direction:
        print("错误：请指定 --query、--list 或 --direction")
        parser.print_help()
        sys.exit(1)
    
    print(f"搜索：{args.query or '全部笔记'}")
    if args.direction:
        print(f"研究方向：{args.direction}")
    if args.tag:
        print(f"标签：{args.tag}")
    print("-" * 60)
    
    # 搜索或列出
    if args.list or (not args.query and args.direction):
        results = list_notes(args.direction)
    else:
        results = search_notes(
            query=args.query or '',
            limit=args.limit,
            direction=args.direction,
            tag=args.tag
        )
    
    # 输出结果
    if args.json:
        print(json.dumps(results, ensure_ascii=False, indent=2))
    else:
        if results:
            print(format_results(results, args.json))
            print(f"\n共找到 {len(results)} 篇笔记")
        else:
            print("未找到匹配的笔记")


if __name__ == '__main__':
    import os
    main()


path: package.json
content: license: MIT
version: 1.0.0
description: Obsidian 笔记管理技能
name: obsidian-manager
author: OpenClaw Community

path: README.md
content: # Obsidian Manager 鎶€鑳?
**鐗堟湰锛?* v0.1  
**鍒涘缓鏃堕棿锛?* 2026 骞?3 鏈?26 鏃? 
**鐘舵€侊細** 馃攧 寮€鍙戜腑

---

## 馃摑 鍔熻兘

- 鉁?绗旇鍒涘缓锛堟敮鎸佹ā鏉匡級
- 鉁?绗旇鎼滅储锛堝叏鏂囨绱級
- 鈴?鍙屽悜閾炬帴绠＄悊
- 鈴?绗旇鍒楄〃

---

## 馃殌 蹇€熷紑濮?
### 鏃犻渶閰嶇疆

Obsidian 浠撳簱宸查厤缃湪锛歚D:\Personal\OpenClaw\research\`

鐩存帴浣跨敤鍗冲彲銆?
---

## 馃摉 浣跨敤绀轰緥

### 鍒涘缓绗旇

```bash
cd skills/obsidian-manager

# 鍒涘缓涓婚绗旇
python obsidian_new.py -t "鎸姩鍙版帶鍒剁郴缁熸灦鏋? -d "01-鎸姩鍙版帶鍒舵妧鏈?

# 鍒涘缓鏂囩尞绗旇
python obsidian_new.py -t "RTHS 鏈€鏂拌繘灞? -d "02-RTHS" --template literature --authors "寮犱笁" --year "2024"

# 鍒涘缓瀹為獙璁板綍
python obsidian_new.py -t "鎸姩鍙版爣瀹氬疄楠? -d "01-鎸姩鍙版帶鍒舵妧鏈? --template experiment
```

### 鎼滅储绗旇

```bash
# 鍏抽敭璇嶆悳绱?python obsidian_search.py -q "RTHS" -l 10

# 鎸夋柟鍚戞悳绱?python obsidian_search.py -d "02-RTHS" -q "娣峰悎璇曢獙"

# 鎸夋爣绛炬悳绱?python obsidian_search.py -t "鏂囩尞" -d "01-鎸姩鍙版帶鍒舵妧鏈?

# 鍒楀嚭鎵€鏈夌瑪璁?python obsidian_search.py --list -d "02-RTHS"
```

---

## 馃搧 鏂囦欢缁撴瀯

```
skills/obsidian-manager/
鈹溾攢鈹€ SKILL.md                 # 鎶€鑳藉畾涔?鈹溾攢鈹€ README.md                # 浣跨敤璇存槑锛堟湰鏂囦欢锛?鈹溾攢鈹€ obsidian_new.py          # 绗旇鍒涘缓
鈹溾攢鈹€ obsidian_search.py       # 绗旇鎼滅储
鈹溾攢鈹€ obsidian_link.py         # 鍙屽悜閾炬帴锛堝緟寮€鍙戯級
鈹斺攢鈹€ obsidian_list.py         # 绗旇鍒楄〃锛堝緟寮€鍙戯級
```

---

## 馃搳 鐮旂┒鏂瑰悜

| 缂栧彿 | 鐮旂┒鏂瑰悜 | 鐩綍 |
|------|----------|------|
| 01 | 鎸姩鍙版帶鍒舵妧鏈?| research/01-鎸姩鍙版帶鍒舵妧鏈?|
| 02 | RTHS 瀛愮粨鏋勮瘯楠?| research/02-RTHS 瀛愮粨鏋勮瘯楠?|
| 03 | 鏂囩墿闅旈渿 | research/03-鏂囩墿闅旈渿 |
| 04 | 绮夋湯闃诲凹 | research/04-绮夋湯闃诲凹 |
| 05 | 瓒呮潗鏂欓殧闇?| research/05-瓒呮潗鏂欓殧闇?|
| 06 | NTMD 鍑忔尟 | research/06-NTMD 鍑忔尟 |
| 07 | 鍦伴渿棰勬祴 | research/07-鍦伴渿棰勬祴 |
| 08 | 鐖嗙牬妯℃嫙鍦伴渿 | research/08-鐖嗙牬妯℃嫙鍦伴渿 |
| 09 | 瀹為獙瀹ょ鐞?| research/09-瀹為獙瀹ょ鐞?|
| 10 | 鐮旂┒鐢熷煿鍏?| research/10-鐮旂┒鐢熷煿鍏?|

---

## 馃摑 绗旇妯℃澘

### 1. 榛樿妯℃澘
閫氱敤绗旇锛岄€傜敤浜庝竴鑸富棰樸€?
### 2. 鏂囩尞绗旇妯℃澘
鐢ㄤ簬璁板綍闃呰鏂囩尞鐨勭瑪璁帮紝鍖呭惈浣滆€呫€佸勾浠姐€佹湡鍒婄瓑鍏冩暟鎹€?
### 3. 涓婚绗旇妯℃澘
鐢ㄤ簬鏁寸悊鏌愪釜鐮旂┒涓婚鐨勭患杩版€х瑪璁般€?
### 4. 瀹為獙璁板綍妯℃澘
鐢ㄤ簬璁板綍瀹為獙杩囩▼銆佹暟鎹拰缁撴灉銆?
---

## 馃敡 寰呭紑鍙戝姛鑳?
- [ ] `obsidian_link.py` - 鍙屽悜閾炬帴绠＄悊
  - 娣诲姞绗旇闂撮摼鎺?  - 妫€鏌ユ柇瑁傞摼鎺?  - 鐢熸垚閾炬帴鍥捐氨

- [ ] `obsidian_list.py` - 绗旇鍒楄〃
  - 鎸夋柟鍚戝垪鍑?  - 鎸夋爣绛惧垪鍑?  - 鎸夋椂闂存帓搴?
- [ ] 鐭ヨ瘑鍥捐氨鐢熸垚
  - 鍙鍖栫瑪璁板叧绯?  - 缁熻绗旇鏁伴噺

---

## 馃敆 涓?Zotero 闆嗘垚

鍒涘缓鏂囩尞绗旇鏃讹紝鍙互鍏宠仈 Zotero 鏂囩尞锛?
```bash
python obsidian_new.py -t "RTHS 缁艰堪" -d "02-RTHS" \
  --template literature \
  --authors "寮犱笁锛屾潕鍥? \
  --year "2024" \
  --journal "鍦伴渿宸ョ▼涓庡伐绋嬫尟鍔? \
  --zotero-link "zotero://select/items/1_ABCD1234"
```

---

## 馃挕 鏈€浣冲疄璺?
### 绗旇鍛藉悕
- 浣跨敤绠€娲佹槑浜嗙殑鏍囬
- 閬垮厤鐗规畩瀛楃锛? \ : * ? " < > |锛?- 涓枃鏍囬鍗冲彲

### 鏍囩浣跨敤
- 缁熶竴浣跨敤鐮旂┒鏂瑰悜鏍囩
- 鍙坊鍔犵被鍨嬫爣绛撅紙鏂囩尞銆佷富棰樸€佸疄楠岋級
- 绀轰緥锛歚tags: [鏂囩尞锛?2-RTHS]`

### 鍙屽悜閾炬帴
- 鐩稿叧绗旇涔嬮棿娣诲姞 `[[绗旇鏍囬]]` 閾炬帴
- 浣跨敤 Obsidian 鐨勫叧绯诲浘璋辨煡鐪嬮摼鎺?
---

## 馃摓 闂鍙嶉

閬囧埌闂璇锋鏌ワ細
1. research 鐩綍鏄惁瀛樺湪
2. 鐮旂┒鏂瑰悜鐩綍鏄惁姝ｇ‘
3. 鏂囦欢鏉冮檺鏄惁姝ｅ父

---

**涓嬩竴姝ワ細** 寮€鍙?knowledge-orchestrator锛堜笁骞冲彴鍗忚皟鍣級



Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)