vault backup: 2026-01-31 08:25:19
This commit is contained in:
+3
-381
@@ -44,375 +44,13 @@
|
||||
"thinkingBudget": "off",
|
||||
"permissionMode": "normal",
|
||||
"lastNonPlanPermissionMode": "normal",
|
||||
"permissions": [
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "mkdir -p \"03_Resources/Articles\" \"03_Resources/Books\" \"03_Resources/Concepts\" \"03_Resources/People\" \"03_Resources/Tools\" \"03_Resources/Quotes\" \"03_Resources/Examples\" \"03_Resources/Learning\"",
|
||||
"approvedAt": 1767579982085,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "mkdir -p \"06_Metadata/Reference\" \"06_Metadata/Templates\" \"06_Metadata/Agents\" \"06_Metadata/Workflows\" \"06_Metadata/Archive\"",
|
||||
"approvedAt": 1767580054324,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "if [ -f .gitignore ]; then echo \"EXISTS\"; else echo \"NOT_FOUND\"; fi",
|
||||
"approvedAt": 1767587601599,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "mkdir -p 03_Resources/Prompt-Library",
|
||||
"approvedAt": 1767592134447,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "03_Resources/Prompt-Library/Gemini 图片生成提示词模板.md",
|
||||
"approvedAt": 1767592217296,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "03_Resources/Prompt-Library/README.md",
|
||||
"approvedAt": 1767592256349,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "mv \"01_Projects/AI-Development/Prompt-Library/baibot-system-prompts.md\" \"03_Resources/Prompt-Library/\" && mv \"01_Projects/AI-Development/Prompt-Library/cycling-training-prompt.md\" \"03_Resources/Prompt-Library/\" && mv \"01_Projects/AI-Development/Prompt-Library/dev-engineering-rules.md\" \"03_Resources/Prompt-Library/\" && mv \"01_Projects/AI-Development/Prompt-Library/movie-review-prompt.md\" \"03_Resources/Prompt-Library/\"",
|
||||
"approvedAt": 1767592881054,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "rmdir \"01_Projects/AI-Development/Prompt-Library\"",
|
||||
"approvedAt": 1767592895883,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Edit",
|
||||
"pattern": "03_Resources/Prompt-Library/README.md",
|
||||
"approvedAt": 1767592921581,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "03_Resources/Prompt-Library/baibot-system-prompts.md",
|
||||
"approvedAt": 1767593197954,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "python3 << 'EOF'\nimport os\nimport re\n\nchinese_pattern = re.compile(r'[\\u4e00-\\u9fff]+')\nchinese_files = []\n\nfor root, dirs, files in os.walk('.'):\n # 跳过隐藏目录\n dirs[:] = [d for d in dirs if not d.startswith('.')]\n \n for file in files:\n if chinese_pattern.search(file):\n full_path = os.path.join(root, file)\n chinese_files.append(full_path)\n\nfor f in sorted(chinese_files):\n print(f)\nEOF",
|
||||
"approvedAt": 1767593330771,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "python << 'EOF'\nimport os\nimport re\n\nchinese_pattern = re.compile(r'[\\u4e00-\\u9fff]+')\nchinese_files = []\n\nfor root, dirs, files in os.walk('.'):\n # 跳过隐藏目录\n dirs[:] = [d for d in dirs if not d.startswith('.')]\n \n for file in files:\n if chinese_pattern.search(file):\n full_path = os.path.join(root, file)\n chinese_files.append(full_path)\n\nprint(f\"Found {len(chinese_files)} files with Chinese characters:\\n\")\nfor f in sorted(chinese_files):\n print(f)\nEOF",
|
||||
"approvedAt": 1767593392020,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": ".scripts/scan-vault-para.ps1",
|
||||
"approvedAt": 1767593508230,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": ".scripts/rename-chinese-to-english.ps1",
|
||||
"approvedAt": 1767593891436,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "powershell -ExecutionPolicy Bypass -File \".\\.scripts\\rename-chinese-to-english.ps1\"",
|
||||
"approvedAt": 1767593905094,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": ".scripts/rename-chinese-to-english.py",
|
||||
"approvedAt": 1767594043665,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "python .scripts/rename-chinese-to-english.py",
|
||||
"approvedAt": 1767594060348,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Edit",
|
||||
"pattern": ".scripts/rename-chinese-to-english.py",
|
||||
"approvedAt": 1767594101469,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "python .scripts/rename-chinese-to-english.py --execute",
|
||||
"approvedAt": 1767594252544,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "python .scripts/rename-chinese-to-english.py --execute 2>&1 | grep -E \"^\\[\" | tail -30",
|
||||
"approvedAt": 1767594293947,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "ls 00_Inbox/*.md 2>&1 | head -5",
|
||||
"approvedAt": 1767604467950,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "ls 03_Resources/*.md 2>&1 | head -5",
|
||||
"approvedAt": 1767604961692,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": ".claude/project-instructions.md",
|
||||
"approvedAt": 1767605314357,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Edit",
|
||||
"pattern": "2026-01-05.md",
|
||||
"approvedAt": 1767605423829,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "WebFetch",
|
||||
"pattern": "{\"url\":\"https://silentvoid13.github.io/Templater\",\"prompt\":\"提取Templater插件的主要功能、安装方法、基本使用方式和核心语法\"}",
|
||||
"approvedAt": 1767605778052,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "06_Metadata/Templater使用指南.md",
|
||||
"approvedAt": 1767606555612,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "mkdir -p \"06_Metadata/Templates\"",
|
||||
"approvedAt": 1767606562910,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "06_Metadata/Templates/daily-note.md",
|
||||
"approvedAt": 1767606599739,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "06_Metadata/Templates/project.md",
|
||||
"approvedAt": 1767606602396,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "06_Metadata/Templates/meeting.md",
|
||||
"approvedAt": 1767606604749,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "06_Metadata/Templates/quick-note.md",
|
||||
"approvedAt": 1767606606848,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "06_Metadata/Templates/book-note.md",
|
||||
"approvedAt": 1767606608965,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "06_Metadata/Templates/person.md",
|
||||
"approvedAt": 1767606610745,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "06_Metadata/Templater配置指南.md",
|
||||
"approvedAt": 1767606650610,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "06_Metadata/Templater快速参考.md",
|
||||
"approvedAt": 1767606680611,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "cd 06_Metadata && mv \"Templater使用指南.md\" \"Templater-User-Guide.md\" && mv \"Templater配置指南.md\" \"Templater-Setup-Guide.md\" && mv \"Templater快速参考.md\" \"Templater-Quick-Reference.md\"",
|
||||
"approvedAt": 1767606719668,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "ls -lh 06_Metadata/*.md",
|
||||
"approvedAt": 1767606724364,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Edit",
|
||||
"pattern": "06_Metadata/Templater-Setup-Guide.md",
|
||||
"approvedAt": 1767606758871,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Edit",
|
||||
"pattern": "06_Metadata/Templater-Quick-Reference.md",
|
||||
"approvedAt": 1767606763446,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "06_Metadata/Obsidian-Plugins-Manual.md",
|
||||
"approvedAt": 1767608585967,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "git remote remove origin 2>&1 || echo \"no origin to remove\"",
|
||||
"approvedAt": 1767616810536,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "pnpm install",
|
||||
"approvedAt": 1767616837185,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "mkdir -p 00_Inbox 01_Projects 02_Areas 03_Resources 04_Archive 05_Attachments/Organized 06_Metadata/Reference 06_Metadata/Plans 06_Metadata/Templates && echo \"Folders created successfully\"",
|
||||
"approvedAt": 1767617713953,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "cat > \"01_Projects/README.md\" << 'EOF'\n# Projects\n\n**Purpose:** Time-bound initiatives with clear completion criteria.\n\n## What is a Project?\n\nA project has:\n- A specific goal or deliverable\n- A clear end date or completion criteria\n- Multiple tasks or actions\n\nExamples: Writing a paper, launching a product, planning an event, learning a new skill\n\n## Recommended Structure\n\nFor each project folder, create:\n- `Research/` - Source materials and references\n- `Drafts/` - Work in progress\n- `Output/` - Final deliverables\n- `README.md` - Project objectives, timeline, and status\n\n## Project Lifecycle\n\n1. **Start:** Create folder with subfolders and README\n2. **During:** Keep all related materials in the project folder\n3. **Complete:** Create summary note, then move to `04_Archive/`\n\n## Tips\n\n- Link to relevant Areas and Resources\n- Commit regularly to track progress with git\n- Review weekly to check status and next actions\nEOF\necho \"Created 01_Projects/README.md\"",
|
||||
"approvedAt": 1767618086311,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "cat > \"04_Archive/README.md\" << 'EOF'\n# Archive\n\n**Purpose:** Completed or inactive items from Projects and Areas.\n\n## What Gets Archived\n\n- **Completed projects** - Move entire project folder here\n- **Inactive areas** - Areas you're no longer maintaining\n- **Old resources** - Outdated reference materials (use sparingly)\n\n## Archive Structure\n\nMaintain the same folder structure:\n- `Projects/` - Completed project folders\n- `Areas/` - Inactive areas\n- `Resources/` - Outdated resources (if needed)\n\n## Before Archiving a Project\n\n1. Create a project summary note with:\n - What was accomplished\n - Key learnings\n - Links to important outputs\n2. Update related Area notes\n3. Move the entire project folder here\n\n## Maintenance\n\n- Review quarterly to see what can be deleted\n- Some archived items may be reactivated\n- Keep the archive organized (mirror active structure)\n\n## Tips\n\n- Don't archive too aggressively - keep valuable reference material\n- Use git history to track when things were archived\n- Archived doesn't mean forgotten - you can still search and reference\nEOF\necho \"Created 04_Archive/README.md\"",
|
||||
"approvedAt": 1767618088747,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "cat > \"05_Attachments/README.md\" << 'EOF'\n# Attachments\n\n**Purpose:** Storage for all non-text files (images, PDFs, videos, audio).\n\n## Organization\n\n- **Root (05_Attachments/)** - Unprocessed attachments\n- **Organized/** - Files that have been properly named and referenced\n\n## Naming Convention\n\nUse descriptive names that indicate the related note:\n- `[RelatedNote]_[Description].[ext]`\n- Example: `ProjectAlpha_Architecture_Diagram.png`\n- Example: `BookNotes_Thinking_Fast_Slow_Cover.jpg`\n\n## Helper Scripts\n\n```bash\npnpm attachments:list # List unprocessed files\npnpm attachments:organized # Count organized files\npnpm attachments:orphans # Find unreferenced files\npnpm attachments:update-links # Update links after moving\n```\n\n## Processing Workflow\n\n1. Files initially land in `05_Attachments/`\n2. Rename with descriptive names\n3. Reference in notes using `![[filename.ext]]`\n4. Move to `Organized/` subfolder\n5. Update any links if paths change\n\n## Tips\n\n- Process attachments regularly (don't let them pile up)\n- Use consistent naming patterns\n- Delete duplicates and unused files\n- Consider using Gemini Vision to analyze images\nEOF\necho \"Created 05_Attachments/README.md\"",
|
||||
"approvedAt": 1767618090058,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "cat package.json | grep -A 30 '\"scripts\"'",
|
||||
"approvedAt": 1767618132102,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "mkdir -p .claude && echo '{\"user\":{\"name\":\"\",\"publicProfile\":false},\"organizationMethod\":\"PARA\",\"primaryUses\":[\"research\",\"writing\",\"project-management\",\"daily-notes\"],\"tools\":{\"geminiVision\":false,\"firecrawl\":true},\"weeklyReview\":true,\"importedAt\":\"2026-01-05\",\"lastUpdated\":\"2026-01-05\"}' > .claude/vault-config.json && cat .claude/vault-config.json",
|
||||
"approvedAt": 1767618135787,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "D:\\tmp\\vault\\my-vault\\CLAUDE.md",
|
||||
"approvedAt": 1767618385844,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "D:\\tmp\\vault\\my-vault\\WEEKLY_REVIEW.md",
|
||||
"approvedAt": 1767618388814,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "test -f \"D:\\tmp\\vault\\my-vault\\.gitignore\" && echo \"exists\" || echo \"not found\"",
|
||||
"approvedAt": 1767618406650,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Edit",
|
||||
"pattern": "D:\\tmp\\vault\\my-vault\\.gitignore",
|
||||
"approvedAt": 1767618439421,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "pnpm vault:stats",
|
||||
"approvedAt": 1767618580628,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "git add CLAUDE.md WEEKLY_REVIEW.md .gitignore .claude/vault-config.json 01_Projects/README.md 02_Areas/README.md 03_Resources/README.md 04_Archive/README.md 05_Attachments/README.md pnpm-lock.yaml",
|
||||
"approvedAt": 1767618604305,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "git commit -m \"$(cat <<'EOF'\nInitial vault setup with PARA structure\n\n- Created CLAUDE.md configuration file\n- Created WEEKLY_REVIEW.md template\n- Set up PARA folder structure (Projects, Areas, Resources, Archive)\n- Created README files for each main folder\n- Configured .gitignore for vault files\n- Saved vault configuration to .claude/vault-config.json\n\nGenerated with Claude Code\nCo-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>\nEOF\n)\"",
|
||||
"approvedAt": 1767618611184,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": ".claude/commands/git-commit-msg.md",
|
||||
"approvedAt": 1767619909039,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Edit",
|
||||
"pattern": ".claude/commands/README.md",
|
||||
"approvedAt": 1767619920589,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": ".git-commit-msg-temp.txt",
|
||||
"approvedAt": 1767620317298,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Write",
|
||||
"pattern": "01_Projects/Work/Government-Projects/Municipal-Development-Reform/login.md",
|
||||
"approvedAt": 1767753309725,
|
||||
"scope": "always"
|
||||
},
|
||||
{
|
||||
"toolName": "Bash",
|
||||
"pattern": "git add \"01_Projects/Work/Government-Projects/Municipal-Development-Reform/Server-Credentials.md\" && git commit -m \"Rename: login.md → Server-Credentials.md for better clarity\"",
|
||||
"approvedAt": 1767755418968,
|
||||
"scope": "always"
|
||||
}
|
||||
],
|
||||
"permissions": [],
|
||||
"excludedTags": [],
|
||||
"mediaFolder": "",
|
||||
"mediaFolder": "05_Attachments",
|
||||
"environmentVariables": "",
|
||||
"envSnippets": [],
|
||||
"systemPrompt": "",
|
||||
"allowedExportPaths": [
|
||||
"~/Desktop",
|
||||
"~/Downloads"
|
||||
],
|
||||
"allowedContextPaths": [],
|
||||
@@ -421,21 +59,5 @@
|
||||
"scrollDownKey": "s",
|
||||
"focusInputKey": "i"
|
||||
},
|
||||
"claudeCliPath": "",
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "[ -f FIRST_RUN ] && echo '{\"hookSpecificOutput\":{\"hookEventName\":\"SessionStart\",\"additionalContext\":\"\\n\\n# 🚀 Welcome to Claudesidian!\\n\\n**This appears to be your first time using this vault.**\\n\\n## Quick Start\\n\\nRun the setup wizard:\\n\\n⬇\\n/init-bootstrap\\n⬆\\n\\n## What this will do:\\n\\n✅ Set up your personalized configuration\\n✅ Disconnect from the original repository\\n✅ Help you import any existing Obsidian vault\\n✅ Configure your preferred workflow\\n✅ Create your PARA folder structure\\n\\nThe setup wizard will guide you through everything!\\n\\n\"}}' || true"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"command": "npm run check-updates --silent 2>/dev/null || true"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"claudeCliPath": "/Users/windy/.local/bin/claude"
|
||||
}
|
||||
Vendored
+17
-1
@@ -2,17 +2,33 @@
|
||||
"claudian",
|
||||
"obsidian-local-rest-api",
|
||||
"table-editor-obsidian",
|
||||
"obsidian-git",
|
||||
"templater-obsidian",
|
||||
"obsidian-tasks-plugin",
|
||||
"calendar",
|
||||
"obsidian-kanban",
|
||||
"obsidian-style-settings",
|
||||
"obsidian-icon-folder",
|
||||
"omnisearch",
|
||||
"copilot",
|
||||
"easy-typing-obsidian",
|
||||
"obsidian-advanced-uri",
|
||||
"obsidian-advanced-codeblock",
|
||||
"advanced-canvas",
|
||||
"better-word-count",
|
||||
"dataview",
|
||||
"obsidian-excalidraw-plugin",
|
||||
"obsidian-mind-map",
|
||||
"cm-chs-patch",
|
||||
"quickadd",
|
||||
<<<<<<< HEAD
|
||||
"highlightr-plugin",
|
||||
"obsidian-git"
|
||||
=======
|
||||
"any-block",
|
||||
"obsidian-opencode",
|
||||
"opencode-obsidian",
|
||||
"highlightr-plugin",
|
||||
"code-styler",
|
||||
"note-buddy"
|
||||
>>>>>>> main/main
|
||||
]
|
||||
Vendored
+49908
File diff suppressed because one or more lines are too long
+1169
File diff suppressed because it is too large
Load Diff
Vendored
-523
File diff suppressed because one or more lines are too long
-11
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"id": "mcp-tools",
|
||||
"name": "MCP Tools",
|
||||
"version": "0.2.27",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Securely connect Claude Desktop to your vault with semantic search, templates, and file management capabilities.",
|
||||
"author": "Jack Steam",
|
||||
"authorUrl": "https://github.com/jacksteamdev",
|
||||
"fundingUrl": "https://github.com/sponsors/jacksteamdev",
|
||||
"isDesktopOnly": true
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"dailyMemosHeader": "Memos",
|
||||
"memosAPIVersion": "v0.24.0",
|
||||
"memosAPIURL": "https://memos.windy.me",
|
||||
"memosAPIToken": "eyJhbGciOiJIUzI1NiIsImtpZCI6InYxIiwidHlwIjoiSldUIn0.eyJuYW1lIjoiemhpcWlhbmciLCJpc3MiOiJtZW1vcyIsInN1YiI6IjEiLCJhdWQiOlsidXNlci5hY2Nlc3MtdG9rZW4iXSwiaWF0IjoxNzY3NDA0MzY0fQ.SR4a3nn3myQUiPV3tJGLpKs_XgpFaOM_aK0i2CmNGoY",
|
||||
"attachmentFolder": "Attachments"
|
||||
}
|
||||
Vendored
-23420
File diff suppressed because it is too large
Load Diff
-10
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"id": "memos-sync",
|
||||
"name": "Memos Sync",
|
||||
"version": "0.5.2",
|
||||
"minAppVersion": "1.5.12",
|
||||
"description": "Syncing memos from a [Memos](https://github.com/usememos/memos) server to your daily note. Fully compatible with official Daily Notes plugin, Calendar plugin and Periodic Notes plugin.",
|
||||
"author": "RyoJerryYu",
|
||||
"authorUrl": "https://github.com/RyoJerryYu",
|
||||
"isDesktopOnly": true
|
||||
}
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
/*
|
||||
|
||||
This CSS file will be included with your plugin, and
|
||||
available in the app when your plugin is enabled.
|
||||
|
||||
If your plugin does not need CSS, delete this file.
|
||||
|
||||
*/
|
||||
Vendored
+692
@@ -0,0 +1,692 @@
|
||||
/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository of this plugin
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/main.ts
|
||||
var main_exports = {};
|
||||
__export(main_exports, {
|
||||
default: () => NoteBuddyPlugin
|
||||
});
|
||||
module.exports = __toCommonJS(main_exports);
|
||||
var import_obsidian4 = require("obsidian");
|
||||
|
||||
// src/chat-view.ts
|
||||
var import_obsidian2 = require("obsidian");
|
||||
|
||||
// src/service.ts
|
||||
var import_obsidian = require("obsidian");
|
||||
|
||||
// src/models.ts
|
||||
var defaultSettings = {
|
||||
serviceUrl: "http://127.0.0.1:4096"
|
||||
};
|
||||
var MODELS_CACHE_TTL = 5 * 60 * 1e3;
|
||||
|
||||
// src/service.ts
|
||||
var OpenCodeClient = class _OpenCodeClient {
|
||||
constructor(serviceUrl, defaultModelId, onModelUnavailable) {
|
||||
this.session = null;
|
||||
this.cachedProviders = null;
|
||||
this.providersCacheTime = 0;
|
||||
this.cachedDefaults = null;
|
||||
this.serviceUrl = serviceUrl;
|
||||
this.defaultModelId = defaultModelId;
|
||||
this.onModelUnavailable = onModelUnavailable;
|
||||
}
|
||||
static {
|
||||
this.DEFAULT_REQUEST_TIMEOUT_MS = 1e4;
|
||||
}
|
||||
static {
|
||||
this.MESSAGE_REQUEST_TIMEOUT_MS = 6e4;
|
||||
}
|
||||
async request(options, timeoutMs = _OpenCodeClient.DEFAULT_REQUEST_TIMEOUT_MS) {
|
||||
return await Promise.race([
|
||||
(0, import_obsidian.requestUrl)(options),
|
||||
new Promise(
|
||||
(_, reject) => setTimeout(() => reject(new Error(`Request timeout after ${timeoutMs / 1e3} seconds`)), timeoutMs)
|
||||
)
|
||||
]);
|
||||
}
|
||||
async healthCheck() {
|
||||
const url = `${this.serviceUrl}/global/health`;
|
||||
try {
|
||||
const response = await this.request({
|
||||
url,
|
||||
method: "GET"
|
||||
});
|
||||
if (response.status === 200 && response.json.healthy === true) {
|
||||
return {
|
||||
status: "connected" /* Connected */,
|
||||
lastTestTime: Date.now()
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
status: "disconnected" /* Disconnected */,
|
||||
lastTestTime: Date.now(),
|
||||
lastError: `Service unhealthy or unreachable`
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
const err = error;
|
||||
return {
|
||||
status: "disconnected" /* Disconnected */,
|
||||
lastTestTime: Date.now(),
|
||||
lastError: err.message || "Unknown error"
|
||||
};
|
||||
}
|
||||
}
|
||||
async createSession() {
|
||||
const url = `${this.serviceUrl}/session`;
|
||||
try {
|
||||
const response = await this.request({
|
||||
url,
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({})
|
||||
});
|
||||
if (response.status === 200) {
|
||||
const data = response.json;
|
||||
return {
|
||||
sessionID: data.id,
|
||||
createTime: data.time.created,
|
||||
title: data.title
|
||||
};
|
||||
}
|
||||
if (response.status === 400) {
|
||||
const details = this.formatBadRequest(response.json, response.text);
|
||||
throw new Error(details);
|
||||
}
|
||||
throw new Error(`HTTP ${response.status}: ${response.text}`);
|
||||
} catch (error) {
|
||||
const err = error;
|
||||
throw new Error(`Failed to create session: ${err.message}`);
|
||||
}
|
||||
}
|
||||
formatBadRequest(payload, fallbackText) {
|
||||
if (!payload || typeof payload !== "object") {
|
||||
return `Bad request: ${fallbackText || "Unknown error"}`;
|
||||
}
|
||||
const p = payload;
|
||||
const errText = typeof p.errors === "string" ? p.errors : p.errors ? JSON.stringify(p.errors) : "";
|
||||
const dataText = p.data ? JSON.stringify(p.data) : "";
|
||||
const msg = [errText, dataText].filter(Boolean).join(" ");
|
||||
return msg ? `Bad request: ${msg}` : `Bad request: ${fallbackText || "Unknown error"}`;
|
||||
}
|
||||
formatNotFound(payload, fallbackText) {
|
||||
if (!payload || typeof payload !== "object") {
|
||||
return fallbackText || "Not found";
|
||||
}
|
||||
const p = payload;
|
||||
const name = typeof p.name === "string" ? p.name : "";
|
||||
const data = p.data ? JSON.stringify(p.data) : "";
|
||||
return [name, data].filter(Boolean).join(" ") || fallbackText || "Not found";
|
||||
}
|
||||
async sendMessageInternal(sessionID, message) {
|
||||
const url = `${this.serviceUrl}/session/${sessionID}/message`;
|
||||
try {
|
||||
const response = await this.request(
|
||||
{
|
||||
url,
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify(message)
|
||||
},
|
||||
_OpenCodeClient.MESSAGE_REQUEST_TIMEOUT_MS
|
||||
);
|
||||
if (response.status === 200) {
|
||||
const raw = (response.text ?? "").trim();
|
||||
if (!raw) {
|
||||
throw new Error("Server returned empty response");
|
||||
}
|
||||
let data;
|
||||
try {
|
||||
data = JSON.parse(raw);
|
||||
} catch {
|
||||
throw new Error(`Invalid JSON response: ${raw.slice(0, 50)}${raw.length > 50 ? "..." : ""}`);
|
||||
}
|
||||
if (!data || typeof data !== "object" || !Array.isArray(data.parts)) {
|
||||
throw new Error("Invalid response shape (expected {info, parts[]})");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
if (response.status === 400) {
|
||||
const payload = response.json;
|
||||
throw new Error(this.formatBadRequest(payload, response.text));
|
||||
}
|
||||
if (response.status === 404) {
|
||||
const payload = response.json;
|
||||
throw new Error(`Session not found: ${this.formatNotFound(payload, response.text)}`);
|
||||
}
|
||||
throw new Error(`HTTP ${response.status}: ${response.text}`);
|
||||
} catch (error) {
|
||||
const err = error;
|
||||
throw new Error(`Failed to send message: ${err.message}`);
|
||||
}
|
||||
}
|
||||
async sendMessage(input) {
|
||||
if (!this.session) {
|
||||
this.session = await this.createSession();
|
||||
}
|
||||
const message = {
|
||||
parts: [{ type: "text", text: input }]
|
||||
};
|
||||
if (this.defaultModelId) {
|
||||
const parts = this.defaultModelId.split("/");
|
||||
if (parts.length === 2) {
|
||||
message.model = {
|
||||
providerID: parts[0],
|
||||
modelID: parts[1]
|
||||
};
|
||||
}
|
||||
}
|
||||
let response;
|
||||
try {
|
||||
response = await this.sendMessageInternal(this.session.sessionID, message);
|
||||
} catch (error) {
|
||||
const err = error;
|
||||
if (message.model && this.isLikelyModelError(err)) {
|
||||
console.log("[NoteBuddy] Selected model unavailable, falling back to server default");
|
||||
if (this.onModelUnavailable) {
|
||||
this.onModelUnavailable();
|
||||
}
|
||||
const fallbackMessage = {
|
||||
parts: message.parts
|
||||
};
|
||||
response = await this.sendMessageInternal(this.session.sessionID, fallbackMessage);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
const assistantText = response.parts.filter((part) => part.type === "text").map((part) => part.type === "text" ? part.text : "").filter(Boolean).join("\n");
|
||||
return assistantText;
|
||||
}
|
||||
async sendMessageToSession(sessionID, message) {
|
||||
return await this.sendMessageInternal(sessionID, message);
|
||||
}
|
||||
isModelsCacheValid() {
|
||||
if (!this.cachedProviders) {
|
||||
return false;
|
||||
}
|
||||
const now = Date.now();
|
||||
return now - this.providersCacheTime < MODELS_CACHE_TTL;
|
||||
}
|
||||
clearModelsCache() {
|
||||
this.cachedProviders = null;
|
||||
this.providersCacheTime = 0;
|
||||
this.cachedDefaults = null;
|
||||
}
|
||||
async getCapabilities(forceRefresh = false) {
|
||||
const now = Date.now();
|
||||
if (!forceRefresh && this.cachedProviders && now - this.providersCacheTime < MODELS_CACHE_TTL) {
|
||||
return this.cachedProviders;
|
||||
}
|
||||
const url = `${this.serviceUrl}/config/providers`;
|
||||
try {
|
||||
const response = await this.request({
|
||||
url,
|
||||
method: "GET"
|
||||
});
|
||||
if (response.status === 200) {
|
||||
let data;
|
||||
try {
|
||||
data = response.json;
|
||||
} catch {
|
||||
const preview = (response.text || "").trim().slice(0, 50);
|
||||
if (preview.toLowerCase().startsWith("<!")) {
|
||||
throw new Error(
|
||||
"Server returned HTML instead of JSON. Check the Service URL and ensure the server exposes /config/providers."
|
||||
);
|
||||
}
|
||||
throw new Error(`Invalid JSON response: ${preview}...`);
|
||||
}
|
||||
const raw = data.providers || [];
|
||||
this.cachedDefaults = data.default || {};
|
||||
const providers = raw.map((p) => ({
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
models: Object.entries(p.models || {}).map(([id, m]) => ({ id, name: m?.name ?? id }))
|
||||
}));
|
||||
this.cachedProviders = providers;
|
||||
this.providersCacheTime = now;
|
||||
return providers;
|
||||
} else {
|
||||
throw new Error(`HTTP ${response.status}: ${response.text}`);
|
||||
}
|
||||
} catch (error) {
|
||||
const err = error;
|
||||
throw new Error(`Failed to get capabilities: ${err.message}`);
|
||||
}
|
||||
}
|
||||
isLikelyModelError(err) {
|
||||
const msg = (err.message || "").toLowerCase();
|
||||
return msg.includes("model") && (msg.includes("not found") || msg.includes("invalid") || msg.includes("unknown"));
|
||||
}
|
||||
};
|
||||
|
||||
// src/chat-view.ts
|
||||
var VIEW_TYPE_CHAT = "note-buddy-chat-view";
|
||||
var ChatView = class extends import_obsidian2.ItemView {
|
||||
constructor(leaf, plugin) {
|
||||
super(leaf);
|
||||
this.plugin = plugin;
|
||||
this.messages = [];
|
||||
this.client = new OpenCodeClient(
|
||||
plugin.settings.serviceUrl,
|
||||
plugin.settings.defaultModelId,
|
||||
plugin.onModelUnavailable?.bind(plugin)
|
||||
);
|
||||
}
|
||||
getViewType() {
|
||||
return VIEW_TYPE_CHAT;
|
||||
}
|
||||
getDisplayText() {
|
||||
return "NoteBuddy Chat";
|
||||
}
|
||||
async onOpen() {
|
||||
const container = this.containerEl.children[1];
|
||||
container.empty();
|
||||
const chatContainer = container.createDiv({ cls: "nb-chat-container" });
|
||||
chatContainer.style.cssText = `
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
gap: 1rem;
|
||||
`;
|
||||
const messagesContainer = chatContainer.createDiv({ cls: "nb-messages-container" });
|
||||
this.messagesContainer = messagesContainer;
|
||||
messagesContainer.style.cssText = `
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem;
|
||||
`;
|
||||
this.renderMessages();
|
||||
const welcomeMessage = messagesContainer.createDiv({ cls: "nb-message nb-message-system" });
|
||||
welcomeMessage.createSpan({ text: "Welcome to NoteBuddy! Chat with your notes here." });
|
||||
welcomeMessage.style.cssText = `
|
||||
padding: 0.75rem;
|
||||
background-color: var(--background-secondary);
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-muted);
|
||||
`;
|
||||
const inputContainer = chatContainer.createDiv({ cls: "nb-input-container" });
|
||||
inputContainer.style.cssText = `
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem;
|
||||
border-top: 1px solid var(--background-modifier-border);
|
||||
`;
|
||||
const textarea = inputContainer.createEl("textarea", {
|
||||
cls: "nb-chat-input",
|
||||
attr: { placeholder: "Type your message..." }
|
||||
});
|
||||
textarea.style.cssText = `
|
||||
flex: 1;
|
||||
min-height: 60px;
|
||||
max-height: 150px;
|
||||
padding: 0.5rem;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 0.375rem;
|
||||
background-color: var(--background-primary);
|
||||
color: var(--text-normal);
|
||||
resize: vertical;
|
||||
font-family: inherit;
|
||||
`;
|
||||
const sendButton = inputContainer.createEl("button", {
|
||||
cls: "nb-send-button",
|
||||
text: "Send"
|
||||
});
|
||||
sendButton.style.cssText = `
|
||||
padding: 0.5rem 1rem;
|
||||
background-color: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
border: none;
|
||||
border-radius: 0.375rem;
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
`;
|
||||
const sendMessage = async () => {
|
||||
const message = textarea.value.trim();
|
||||
if (!message) return;
|
||||
this.messages.push({ kind: "userText", text: message });
|
||||
this.renderMessages();
|
||||
textarea.value = "";
|
||||
try {
|
||||
if (!this.plugin.sessionState) {
|
||||
this.plugin.sessionState = await this.client.createSession();
|
||||
}
|
||||
const sendData = {
|
||||
parts: [{ type: "text", text: message }]
|
||||
};
|
||||
if (this.plugin.settings.defaultModelId) {
|
||||
const parts = this.plugin.settings.defaultModelId.split("/");
|
||||
if (parts.length === 2) {
|
||||
sendData.model = {
|
||||
providerID: parts[0],
|
||||
modelID: parts[1]
|
||||
};
|
||||
}
|
||||
}
|
||||
let response;
|
||||
try {
|
||||
response = await this.client.sendMessageToSession(this.plugin.sessionState.sessionID, sendData);
|
||||
} catch (sendError) {
|
||||
const err = sendError;
|
||||
if (err.message.includes("Session not found")) {
|
||||
this.plugin.sessionState = await this.client.createSession();
|
||||
response = await this.client.sendMessageToSession(this.plugin.sessionState.sessionID, sendData);
|
||||
} else {
|
||||
throw sendError;
|
||||
}
|
||||
}
|
||||
for (const part of response.parts) {
|
||||
this.messages.push({ kind: "assistantPart", part });
|
||||
}
|
||||
this.renderMessages();
|
||||
this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight;
|
||||
} catch (error) {
|
||||
console.error("[NoteBuddy] Send failed:", error);
|
||||
new import_obsidian2.Notice(`Failed to send message: ${error.message}`);
|
||||
}
|
||||
};
|
||||
sendButton.onclick = sendMessage;
|
||||
textarea.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter" && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
sendMessage();
|
||||
}
|
||||
});
|
||||
}
|
||||
async onClose() {
|
||||
console.log("[NoteBuddy] Chat view closed");
|
||||
}
|
||||
renderMessages() {
|
||||
this.messagesContainer.empty();
|
||||
if (this.messages.length === 0) {
|
||||
const welcomeMessage = this.messagesContainer.createDiv({ cls: "nb-message nb-message-system" });
|
||||
welcomeMessage.createSpan({ text: "Welcome to NoteBuddy! Chat with your notes here." });
|
||||
welcomeMessage.style.cssText = `
|
||||
padding: 0.75rem;
|
||||
background-color: var(--background-secondary);
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-muted);
|
||||
`;
|
||||
return;
|
||||
}
|
||||
for (const item of this.messages) {
|
||||
if (item.kind === "userText") {
|
||||
const messageEl2 = this.messagesContainer.createDiv({ cls: "nb-message nb-message-user" });
|
||||
messageEl2.createSpan({ text: item.text });
|
||||
messageEl2.style.cssText = `
|
||||
padding: 0.75rem;
|
||||
background-color: var(--background-modifier-accent);
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
align-self: flex-end;
|
||||
max-width: 70%;
|
||||
`;
|
||||
continue;
|
||||
}
|
||||
const part = item.part;
|
||||
const messageEl = this.messagesContainer.createDiv({ cls: "nb-message nb-message-assistant" });
|
||||
messageEl.style.cssText = `
|
||||
padding: 0.75rem;
|
||||
background-color: var(--background-secondary);
|
||||
border-radius: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
align-self: flex-start;
|
||||
max-width: 70%;
|
||||
`;
|
||||
switch (part.type) {
|
||||
case "text":
|
||||
messageEl.createSpan({ text: part.text });
|
||||
break;
|
||||
case "reasoning":
|
||||
messageEl.createSpan({ text: part.text });
|
||||
break;
|
||||
case "tool":
|
||||
messageEl.createEl("strong", { text: `Tool: ${part.tool}` });
|
||||
messageEl.createEl("pre", { text: JSON.stringify(part.state ?? {}, null, 2) });
|
||||
break;
|
||||
case "patch":
|
||||
messageEl.createEl("strong", { text: `Patch: ${part.hash}` });
|
||||
messageEl.createEl("pre", { text: (part.files || []).join("\n") });
|
||||
break;
|
||||
case "file":
|
||||
messageEl.createEl("strong", { text: `File: ${part.filename ?? part.url}` });
|
||||
messageEl.createEl("div", { text: `mime: ${part.mime}` });
|
||||
messageEl.createEl("div", { text: `url: ${part.url}` });
|
||||
break;
|
||||
case "agent":
|
||||
messageEl.createEl("strong", { text: `Agent: ${part.name}` });
|
||||
break;
|
||||
case "step_start":
|
||||
messageEl.createEl("strong", { text: `Step start${part.title ? `: ${part.title}` : ""}` });
|
||||
break;
|
||||
case "step_finish":
|
||||
messageEl.createEl("strong", { text: `Step finish${part.title ? `: ${part.title}` : ""}` });
|
||||
break;
|
||||
case "snapshot":
|
||||
messageEl.createEl("strong", { text: "Snapshot" });
|
||||
messageEl.createEl("pre", { text: JSON.stringify(part, null, 2) });
|
||||
break;
|
||||
case "retry":
|
||||
messageEl.createEl("strong", { text: "Retry" });
|
||||
messageEl.createEl("pre", { text: JSON.stringify(part, null, 2) });
|
||||
break;
|
||||
case "compaction":
|
||||
messageEl.createEl("strong", { text: "Compaction" });
|
||||
messageEl.createEl("pre", { text: JSON.stringify(part, null, 2) });
|
||||
break;
|
||||
case "unknown":
|
||||
messageEl.createEl("strong", {
|
||||
text: `Unsupported part type: ${part.originalType}`
|
||||
});
|
||||
messageEl.createEl("pre", { text: JSON.stringify(part, null, 2) });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// src/settings.ts
|
||||
var import_obsidian3 = require("obsidian");
|
||||
var NoteBuddySettingTab = class extends import_obsidian3.PluginSettingTab {
|
||||
constructor(app, plugin) {
|
||||
super(app, plugin);
|
||||
this.providers = [];
|
||||
this.isLoadingModels = false;
|
||||
this.plugin = plugin;
|
||||
}
|
||||
async display(useCachedProviders) {
|
||||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
containerEl.createEl("h2", { text: "NoteBuddy Settings" });
|
||||
if (!useCachedProviders) {
|
||||
try {
|
||||
await this.loadProviders();
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
new import_obsidian3.Setting(containerEl).setName("Service URL").setDesc("The URL of the OpenCode service (must include protocol, hostname, and port)").addText(
|
||||
(text) => text.setPlaceholder("http://127.0.0.1:4096").setValue(this.plugin.settings.serviceUrl).onChange(async (value) => {
|
||||
if (!value.startsWith("http://") && !value.startsWith("https://")) {
|
||||
new import_obsidian3.Notice("Service URL must start with http:// or https://");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const url = new URL(value);
|
||||
if (!url.hostname || url.hostname === "") {
|
||||
new import_obsidian3.Notice("Service URL must include a valid hostname");
|
||||
return;
|
||||
}
|
||||
if (!url.port || url.port === "") {
|
||||
new import_obsidian3.Notice("Service URL must include a port number");
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
new import_obsidian3.Notice("Service URL must be a valid URL format");
|
||||
return;
|
||||
}
|
||||
this.plugin.settings.serviceUrl = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
new import_obsidian3.Setting(containerEl).setName("Test Connection").setDesc("Test the connection to the service").addButton(
|
||||
(button) => button.setButtonText("Test").setCta().onClick(async () => {
|
||||
const client = new OpenCodeClient(this.plugin.settings.serviceUrl, this.plugin.settings.defaultModelId);
|
||||
const result = await client.healthCheck();
|
||||
if (result.status === "connected") {
|
||||
new import_obsidian3.Notice("Connection successful!");
|
||||
} else {
|
||||
new import_obsidian3.Notice(`Connection failed: ${result.lastError}`);
|
||||
}
|
||||
})
|
||||
);
|
||||
this.displayModelSelection(containerEl);
|
||||
this.displayRefreshButton(containerEl);
|
||||
}
|
||||
async loadProviders(client, forceRefresh) {
|
||||
if (this.isLoadingModels) {
|
||||
return;
|
||||
}
|
||||
this.isLoadingModels = true;
|
||||
try {
|
||||
const c = client ?? new OpenCodeClient(this.plugin.settings.serviceUrl, this.plugin.settings.defaultModelId);
|
||||
this.providers = await c.getCapabilities(forceRefresh ?? false);
|
||||
} catch (error) {
|
||||
this.providers = [];
|
||||
console.error("[NoteBuddy] Failed to load providers:", error);
|
||||
throw error;
|
||||
} finally {
|
||||
this.isLoadingModels = false;
|
||||
}
|
||||
}
|
||||
displayModelSelection(containerEl) {
|
||||
const modelOptions = {};
|
||||
modelOptions[""] = "Use server default";
|
||||
for (const provider of this.providers) {
|
||||
for (const model of provider.models) {
|
||||
const value = `${provider.id}/${model.id}`;
|
||||
modelOptions[value] = `${provider.name} - ${model.name}`;
|
||||
}
|
||||
}
|
||||
const currentValue = this.getCurrentModelSelection();
|
||||
new import_obsidian3.Setting(containerEl).setName("Default Model").setDesc("Select the default AI model to use for conversations").addDropdown(
|
||||
(dropdown) => dropdown.addOptions(modelOptions).setValue(currentValue).onChange(async (value) => {
|
||||
if (value) {
|
||||
this.plugin.settings.defaultModelId = value;
|
||||
} else {
|
||||
this.plugin.settings.defaultModelId = void 0;
|
||||
}
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
}
|
||||
getCurrentModelSelection() {
|
||||
return this.plugin.settings.defaultModelId || "";
|
||||
}
|
||||
displayRefreshButton(container) {
|
||||
new import_obsidian3.Setting(container).setName("Refresh Models").setDesc("Reload the list of available models from the service").addButton(
|
||||
(button) => button.setButtonText("Refresh").onClick(async () => {
|
||||
const client = new OpenCodeClient(this.plugin.settings.serviceUrl, this.plugin.settings.defaultModelId);
|
||||
client.clearModelsCache();
|
||||
try {
|
||||
await this.loadProviders(client, true);
|
||||
new import_obsidian3.Notice("Models refreshed");
|
||||
await this.display(true);
|
||||
} catch (error) {
|
||||
console.error("[NoteBuddy] Failed to load providers:", error);
|
||||
new import_obsidian3.Notice(`Failed to refresh models: ${error.message}`);
|
||||
await this.display(true);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// src/main.ts
|
||||
var DEFAULT_SETTINGS = defaultSettings;
|
||||
var NoteBuddyPlugin = class extends import_obsidian4.Plugin {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.ribbonIconEl = null;
|
||||
}
|
||||
async onload() {
|
||||
console.log("Loading NoteBuddy plugin...");
|
||||
await this.loadSettings();
|
||||
this.registerView(
|
||||
VIEW_TYPE_CHAT,
|
||||
(leaf) => new ChatView(leaf, this)
|
||||
);
|
||||
this.addRibbonIcon("bot", "NoteBuddy", () => {
|
||||
this.activateView();
|
||||
});
|
||||
this.addCommand({
|
||||
id: "open-chat-view",
|
||||
name: "Open NoteBuddy Chat",
|
||||
callback: () => {
|
||||
this.activateView();
|
||||
}
|
||||
});
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
this.activateView();
|
||||
});
|
||||
this.addSettingTab(new NoteBuddySettingTab(this.app, this));
|
||||
}
|
||||
onunload() {
|
||||
console.log("Unloading NoteBuddy plugin...");
|
||||
}
|
||||
async activateView() {
|
||||
const { workspace } = this.app;
|
||||
let leaf = null;
|
||||
const leaves = workspace.getLeavesOfType(VIEW_TYPE_CHAT);
|
||||
if (leaves.length > 0) {
|
||||
leaf = leaves[0];
|
||||
} else {
|
||||
leaf = workspace.getRightLeaf(false);
|
||||
}
|
||||
if (leaf) {
|
||||
await workspace.setActiveLeaf(leaf);
|
||||
await leaf.setViewState({ type: VIEW_TYPE_CHAT, active: true });
|
||||
}
|
||||
}
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
}
|
||||
// Callback for when selected model is unavailable
|
||||
onModelUnavailable() {
|
||||
new import_obsidian4.Notice("Selected model is unavailable. Using server default instead.");
|
||||
}
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
};
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
.note-buddy-chat {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--background-secondary);
|
||||
}
|
||||
|
||||
.note-buddy-chat h2 {
|
||||
margin: 10px;
|
||||
font-size: var(--font-ui-medium);
|
||||
color: var(--text-normal);
|
||||
font-weight: var(--font-semibold);
|
||||
}
|
||||
|
||||
.message-container {
|
||||
background-color: var(--background-primary-alt);
|
||||
border-radius: var(--radius-md);
|
||||
margin: 0 10px 10px 10px;
|
||||
}
|
||||
|
||||
.input-bar textarea {
|
||||
background-color: var(--background-primary);
|
||||
color: var(--text-normal);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: var(--radius-sm);
|
||||
font-family: var(--font-interface);
|
||||
font-size: var(--font-ui-sm);
|
||||
}
|
||||
|
||||
.input-bar textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.input-bar button {
|
||||
background-color: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
font-family: var(--font-interface);
|
||||
font-weight: var(--font-semibold);
|
||||
font-size: var(--font-ui-sm);
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.input-bar button:hover {
|
||||
background-color: var(--interactive-accent-hover);
|
||||
}
|
||||
+6
-6
File diff suppressed because one or more lines are too long
+1
-1
@@ -5,7 +5,7 @@
|
||||
"isDesktopOnly": false,
|
||||
"js": "main.js",
|
||||
"fundingUrl": "https://ko-fi.com/vinzent",
|
||||
"version": "1.46.0",
|
||||
"version": "1.46.1",
|
||||
"author": "Vinzent",
|
||||
"authorUrl": "https://github.com/Vinzent03"
|
||||
}
|
||||
|
||||
+1
-1
@@ -123,7 +123,7 @@
|
||||
"mdBorderColor": "Black",
|
||||
"mdCSS": "",
|
||||
"scriptEngineSettings": {},
|
||||
"previousRelease": "2.19.2",
|
||||
"previousRelease": "2.20.0",
|
||||
"showReleaseNotes": true,
|
||||
"compareManifestToPluginVersion": true,
|
||||
"showNewVersionNotification": true,
|
||||
|
||||
+3
-3
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "2.19.2",
|
||||
"version": "2.20.0",
|
||||
"minAppVersion": "1.5.7",
|
||||
"description": "Sketch Your Mind. An Obsidian plugin to edit and view Excalidraw drawings. Enter the world of 4D Visual PKM.",
|
||||
"author": "Zsolt Viczian",
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+3
-1
@@ -65,7 +65,9 @@
|
||||
"generalSettings": {},
|
||||
"headingOpened": {
|
||||
"核心状态": true,
|
||||
"自定义状态": true
|
||||
"自定义状态": true,
|
||||
"Core Statuses": true,
|
||||
"Custom Statuses": true
|
||||
},
|
||||
"debugSettings": {
|
||||
"ignoreSortInstructions": false,
|
||||
|
||||
Vendored
+48
@@ -0,0 +1,48 @@
|
||||
.note-buddy-chat {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--background-secondary);
|
||||
}
|
||||
|
||||
.note-buddy-chat h2 {
|
||||
margin: 10px;
|
||||
font-size: var(--font-ui-medium);
|
||||
color: var(--text-normal);
|
||||
font-weight: var(--font-semibold);
|
||||
}
|
||||
|
||||
.message-container {
|
||||
background-color: var(--background-primary-alt);
|
||||
border-radius: var(--radius-md);
|
||||
margin: 0 10px 10px 10px;
|
||||
}
|
||||
|
||||
.input-bar textarea {
|
||||
background-color: var(--background-primary);
|
||||
color: var(--text-normal);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: var(--radius-sm);
|
||||
font-family: var(--font-interface);
|
||||
font-size: var(--font-ui-sm);
|
||||
}
|
||||
|
||||
.input-bar textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--interactive-accent);
|
||||
}
|
||||
|
||||
.input-bar button {
|
||||
background-color: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
border: none;
|
||||
border-radius: var(--radius-sm);
|
||||
font-family: var(--font-interface);
|
||||
font-weight: var(--font-semibold);
|
||||
font-size: var(--font-ui-sm);
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.input-bar button:hover {
|
||||
background-color: var(--interactive-accent-hover);
|
||||
}
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
Copyright (C) 2020-2025 by Dynalist Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
-100
File diff suppressed because one or more lines are too long
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"id": "opencode-obsidian",
|
||||
"name": "OpenCode Obsidian",
|
||||
"version": "0.13.1",
|
||||
"minAppVersion": "1.0.0",
|
||||
"description": "OpenCode integration for Obsidian - AI-powered chat interface",
|
||||
"author": "OpenCode Obsidian Team",
|
||||
"authorUrl": "",
|
||||
"fundingUrl": "",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
-475
@@ -1,475 +0,0 @@
|
||||
/* Search highlight */
|
||||
.search-highlight {
|
||||
background-color: var(--text-highlight-bg);
|
||||
color: var(--text-highlight);
|
||||
padding: 0 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* Server Status Styles */
|
||||
.opencode-server-status {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.opencode-server-status-running {
|
||||
color: var(--color-green);
|
||||
}
|
||||
|
||||
.opencode-server-status-stopped {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.opencode-server-status-starting {
|
||||
color: var(--color-blue);
|
||||
}
|
||||
|
||||
.opencode-server-status-error {
|
||||
color: var(--color-red);
|
||||
}
|
||||
|
||||
.opencode-server-status-error-message {
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.opencode-server-control-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.opencode-server-metrics {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.opencode-server-metrics-text {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* Server Start Modal Styles */
|
||||
.opencode-server-start-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: flex-end;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
/* Core view layout */
|
||||
.opencode-obsidian-view {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.opencode-obsidian-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 10px;
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
background-color: var(--background-secondary);
|
||||
}
|
||||
|
||||
.opencode-obsidian-status {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.opencode-obsidian-status.connected {
|
||||
color: var(--text-success);
|
||||
}
|
||||
|
||||
.opencode-obsidian-status.reconnecting,
|
||||
.opencode-obsidian-status.connecting {
|
||||
color: var(--text-warning);
|
||||
}
|
||||
|
||||
.opencode-obsidian-status.disconnected {
|
||||
color: var(--text-error);
|
||||
}
|
||||
|
||||
.opencode-obsidian-controls {
|
||||
margin-left: auto;
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-view-toggle {
|
||||
align-self: flex-start;
|
||||
margin: 8px 10px 0;
|
||||
}
|
||||
|
||||
.opencode-obsidian-search-panel {
|
||||
padding: 6px 10px;
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
|
||||
/* Conversation selector */
|
||||
.opencode-obsidian-conversation-selector {
|
||||
padding: 6px 10px;
|
||||
border-bottom: 1px solid var(--background-modifier-border);
|
||||
}
|
||||
|
||||
.opencode-obsidian-tabs-container {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
overflow-x: auto;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
background-color: var(--background-secondary);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.opencode-obsidian-tab.active {
|
||||
background-color: var(--interactive-accent);
|
||||
border-color: var(--interactive-accent);
|
||||
color: var(--text-on-accent);
|
||||
}
|
||||
|
||||
.opencode-obsidian-tab-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-tab-metadata {
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.opencode-obsidian-tab-close {
|
||||
margin-left: 6px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.opencode-obsidian-tab:hover .opencode-obsidian-tab-close {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.opencode-obsidian-tab-new,
|
||||
.opencode-obsidian-tab-sync {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.opencode-obsidian-tab-disabled {
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.opencode-obsidian-no-conversations {
|
||||
color: var(--text-muted);
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
/* Message list */
|
||||
.opencode-obsidian-messages {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-message {
|
||||
padding: 8px 10px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
background-color: var(--background-secondary);
|
||||
}
|
||||
|
||||
.opencode-obsidian-message-user {
|
||||
align-self: flex-end;
|
||||
background-color: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
.opencode-obsidian-message-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-message-content {
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.opencode-obsidian-message-images img {
|
||||
border-radius: 6px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-message-actions {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-message-action {
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.opencode-obsidian-message-action:hover {
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.opencode-obsidian-empty-messages {
|
||||
color: var(--text-muted);
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.opencode-obsidian-reverted-indicator {
|
||||
padding: 8px 10px;
|
||||
border-radius: 6px;
|
||||
background-color: var(--background-secondary);
|
||||
border: 1px dashed var(--background-modifier-border);
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.opencode-obsidian-unrevert-button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* Input area */
|
||||
.opencode-obsidian-input {
|
||||
border-top: 1px solid var(--background-modifier-border);
|
||||
padding: 8px 10px;
|
||||
background-color: var(--background-secondary);
|
||||
}
|
||||
|
||||
.opencode-obsidian-input-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-input-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-agent-select {
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-input-textarea {
|
||||
width: 100%;
|
||||
min-height: 60px;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.opencode-obsidian-input-status {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.opencode-obsidian-streaming {
|
||||
color: var(--text-accent);
|
||||
}
|
||||
|
||||
.opencode-obsidian-input-buttons {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* Command suggestions */
|
||||
.opencode-obsidian-command-suggestions {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.opencode-obsidian-command-suggestions-list {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: calc(100% + 6px);
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
background-color: var(--background-primary);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
|
||||
display: none;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.opencode-obsidian-command-suggestions.is-visible .opencode-obsidian-command-suggestions-list {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.opencode-obsidian-command-suggestion {
|
||||
padding: 6px 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.opencode-obsidian-command-suggestion.is-selected {
|
||||
background-color: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
.opencode-obsidian-command-suggestion-description {
|
||||
display: block;
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.opencode-obsidian-command-suggestion-empty {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
/* Loading and spinners */
|
||||
.opencode-obsidian-loading-overlay {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.opencode-obsidian-loading-message {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-spinner {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border: 2px solid var(--background-modifier-border);
|
||||
border-top-color: var(--interactive-accent);
|
||||
border-radius: 50%;
|
||||
animation: opencode-obsidian-spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
.opencode-obsidian-spinner-large {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
@keyframes opencode-obsidian-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Context menu */
|
||||
.opencode-obsidian-context-menu {
|
||||
background-color: var(--background-primary);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 6px;
|
||||
padding: 4px;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.opencode-obsidian-context-menu-item {
|
||||
padding: 6px 8px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-context-menu-item:hover {
|
||||
background-color: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
.opencode-obsidian-context-menu-item-danger {
|
||||
color: var(--text-error);
|
||||
}
|
||||
|
||||
/* Todo list */
|
||||
.opencode-obsidian-todo-container {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-todo-header {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.opencode-obsidian-todo-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-todo-item {
|
||||
padding: 8px 10px;
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
border-radius: 8px;
|
||||
background-color: var(--background-secondary);
|
||||
}
|
||||
|
||||
.opencode-obsidian-todo-title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.opencode-obsidian-todo-meta {
|
||||
font-size: 11px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.opencode-obsidian-todo-actions {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-todo-empty {
|
||||
color: var(--text-muted);
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
/* Modals */
|
||||
.opencode-obsidian-drop-zone {
|
||||
border: 1px dashed var(--background-modifier-border);
|
||||
padding: 12px;
|
||||
text-align: center;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-drop-zone-hover {
|
||||
background-color: var(--background-modifier-hover);
|
||||
}
|
||||
|
||||
.opencode-obsidian-permission-buttons {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 8px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.opencode-obsidian-code-preview {
|
||||
font-family: var(--font-monospace);
|
||||
font-size: 12px;
|
||||
background-color: var(--background-secondary);
|
||||
border: 1px solid var(--background-modifier-border);
|
||||
padding: 8px;
|
||||
border-radius: 6px;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
Vendored
+17
-2
@@ -1,10 +1,12 @@
|
||||
{
|
||||
"choices": [],
|
||||
"inputPrompt": "single-line",
|
||||
"persistInputPromptDrafts": true,
|
||||
"useSelectionAsCaptureValue": true,
|
||||
"devMode": false,
|
||||
"templateFolderPath": "06_Metadata/Templates",
|
||||
"announceUpdates": "all",
|
||||
"version": "2.9.4",
|
||||
"version": "2.10.0",
|
||||
"globalVariables": {},
|
||||
"onePageInputEnabled": false,
|
||||
"disableOnlineFeatures": true,
|
||||
@@ -12,6 +14,17 @@
|
||||
"showCaptureNotification": true,
|
||||
"showInputCancellationNotification": false,
|
||||
"enableTemplatePropertyTypes": true,
|
||||
"dateAliases": {
|
||||
"t": "today",
|
||||
"tm": "tomorrow",
|
||||
"yd": "yesterday",
|
||||
"nw": "next week",
|
||||
"nm": "next month",
|
||||
"ny": "next year",
|
||||
"lw": "last week",
|
||||
"lm": "last month",
|
||||
"ly": "last year"
|
||||
},
|
||||
"ai": {
|
||||
"defaultModel": "Ask me",
|
||||
"defaultSystemPrompt": "As an AI assistant within Obsidian, your primary goal is to help users manage their ideas and knowledge more effectively. Format your responses using Markdown syntax. Please use the [[Obsidian]] link format. You can write aliases for the links by writing [[Obsidian|the alias after the pipe symbol]]. To use mathematical notation, use LaTeX syntax. LaTeX syntax for larger equations should be on separate lines, surrounded with double dollar signs ($$). You can also inline math expressions by wrapping it in $ symbols. For example, use $$w_{ij}^{\text{new}}:=w_{ij}^{\text{current}}+etacdotdelta_jcdot x_{ij}$$ on a separate line, but you can write \"($eta$ = learning rate, $delta_j$ = error term, $x_{ij}$ = input)\" inline.",
|
||||
@@ -99,6 +112,8 @@
|
||||
"addDefaultAIProviders": true,
|
||||
"removeMacroIndirection": true,
|
||||
"migrateFileOpeningSettings": true,
|
||||
"setProviderModelDiscoveryMode": true
|
||||
"setProviderModelDiscoveryMode": true,
|
||||
"backfillFileOpeningDefaults": true,
|
||||
"migrateProviderApiKeysToSecretStorage": true
|
||||
}
|
||||
}
|
||||
Vendored
+78
-73
File diff suppressed because one or more lines are too long
+2
-2
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"id": "quickadd",
|
||||
"name": "QuickAdd",
|
||||
"version": "2.9.4",
|
||||
"minAppVersion": "1.6.0",
|
||||
"version": "2.10.0",
|
||||
"minAppVersion": "1.11.4",
|
||||
"description": "Quickly add new pages or content to your vault.",
|
||||
"author": "Christian B. B. Houmann",
|
||||
"authorUrl": "https://bagerbach.com",
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+14
-14
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "templater-obsidian",
|
||||
"name": "Templater",
|
||||
"version": "2.16.4",
|
||||
"version": "2.18.1",
|
||||
"description": "Create and use templates",
|
||||
"minAppVersion": "1.5.0",
|
||||
"author": "SilentVoid",
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# {{date:YYYY-MM-DD}}
|
||||
|
||||
## Capture
|
||||
<!-- Quick thoughts, links, ideas throughout the day -->
|
||||
苹果美国 ID 地址:
|
||||
|
||||
街道 :
|
||||
```
|
||||
42016 Judy Ridge
|
||||
```
|
||||
|
||||
|
||||
城市:
|
||||
```
|
||||
Arlington
|
||||
```
|
||||
|
||||
州:
|
||||
OR
|
||||
|
||||
邮编:
|
||||
```
|
||||
97522
|
||||
```
|
||||
|
||||
电话:
|
||||
```
|
||||
286-382-5866 x0060
|
||||
```
|
||||
|
||||
|
||||
## Questions
|
||||
<!-- What am I curious about today? -->
|
||||
-
|
||||
|
||||
## Insights
|
||||
<!-- What did I learn or realize? -->
|
||||
-
|
||||
|
||||
## Connections
|
||||
<!-- Links to other notes or ideas -->
|
||||
-
|
||||
|
||||
## For Tomorrow
|
||||
<!-- What needs follow-up? -->
|
||||
-
|
||||
|
||||
---
|
||||
*End of day: Ask Claude Code to review and find connections*
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
title: "Welcome to LessWrong! — LessWrong"
|
||||
source: "https://www.lesswrong.com/posts/bJ2haLkcGeLtTWaD5/welcome-to-lesswrong"
|
||||
author:
|
||||
- "[[Ruby]]"
|
||||
published: 2019-06-15
|
||||
created: 2026-01-16
|
||||
description: "The road to wisdom? Well, it's plainand simple to express: • Errand errand err againbut lessand lessand less. • – Piet Hein …"
|
||||
tags:
|
||||
- "clippings"
|
||||
- "webclipper"
|
||||
---
|
||||
> [!info] Source
|
||||
> URL: https://www.lesswrong.com/posts/bJ2haLkcGeLtTWaD5/welcome-to-lesswrong
|
||||
> Title: Welcome to LessWrong! — LessWrong
|
||||
> Clipped:
|
||||
|
||||
| *The road to wisdom? Well, it's plain 通往智慧的道路?好吧,它显而易见* *and simple to express: 且易于表达:* *Err 犯错* *and err 以及犯错的智慧* *and err again 并再次犯错* *but **less** 但更少* *and **less** 越来越少* *and **less**.越少越好* – Piet Hein – 彼得·海恩 |
|
||||
| --- |
|
||||
|
||||
LessWrong is an online forum and community dedicated to improving human reasoning and decision-making. We seek to hold true beliefs and to be effective at accomplishing our goals. Each day, we aim to be less wrong about the world than the day before.
|
||||
LessWrong 是一个致力于提升人类推理与决策能力的在线论坛和社区。我们力求持有正确的信念,并高效实现目标。每一天,我们都努力让自己对世界的认识比前一天更少错误。
|
||||
|
||||
*See also our* [*New User's Guide*](https://www.lesswrong.com/posts/LbbrnRvc9QwjJeics/new-user-s-guide-to-lesswrong)
|
||||
也可参见我们的新用户指南*.*
|
||||
|
||||
## Training Rationality 训练理性
|
||||
|
||||
Rationality has a number of definitions [^1] on LessWrong, but perhaps the most canonical is that the more rational you are, the more likely your reasoning leads you to have accurate beliefs, and by extension, allows you to make decisions that most effectively advance your goals.
|
||||
在 LessWrong 上,理性有多种定义 <sup><span><a href="https://www.lesswrong.com/posts/bJ2haLkcGeLtTWaD5/#fnajdy57uko9d">[1]</a></span></sup> ,但或许最经典的诠释是:你的理性程度越高,你的推理过程就越有可能助你获得准确的信念,进而让你能够做出最有效推动目标达成的决策。
|
||||
|
||||
LessWrong contains a lot of content on this topic. How minds work (both human, artificial, and theoretical ideal), how to reason better, and how to have discussions that are productive. We're very big fans of [Bayes Theorem](https://www.lesswrong.com/w/bayes_rule?l=1zq) and other theories of normatively correct reasoning [^2].
|
||||
LessWrong 包含大量关于此主题的内容,涉及心智如何运作(包括人类心智、人工心智以及理论上的理想心智)、如何更好地推理,以及如何进行富有成效的讨论。我们非常推崇贝叶斯定理和其他规范性正确推理理论。
|
||||
|
||||
To get started improving your Rationality, we recommend reading the background-knowledge text of LessWrong, [Rationality: A-Z](https://www.lesswrong.com/rationality) (aka "The Sequences") or at least [selected highlights](https://www.lesswrong.com/highlights) from it. After that, looking through the Rationality section of the [Concepts Portal](https://www.lesswrong.com/concepts) is a good thing to do.
|
||||
要开始提升你的理性思维,我们建议先阅读 LessWrong 的背景知识文本《理性:从 A 到 Z》(又称“The Sequences”),或者至少阅读其中的精选亮点部分。之后,浏览概念门户的理性部分是很好的下一步。
|
||||
|
||||
## Applying Rationality 运用理性
|
||||
|
||||
You might value Rationality for its own sake, however, many people want to be better reasoners so they can have more accurate beliefs about topics they care about, and make better decisions.
|
||||
您可能因理性本身的价值而珍视它,然而,许多人希望成为更出色的推理者,以便能在他们关心的话题上拥有更准确的信念,并做出更明智的决策。
|
||||
|
||||
Using LessWrong-style reasoning, contributors to LessWrong have written essays on an immense variety of topics on LessWrong, each time approaching the topic with a desire to know what's actually true (not just what's convenient or pleasant to believe), being deliberate about processing the evidence, and avoiding common pitfalls of human reason.
|
||||
在 LessWrong,投稿者运用 LessWrong 风格的推理,针对极其多样的主题撰写了大量文章。每一次探讨主题时,他们都怀有探究真实(而非仅仅相信便捷或令人愉悦的观点)的渴望,审慎地处理证据,并避开人类推理中常见的陷阱。
|
||||
|
||||
Check out the [Concepts Portal](https://www.lesswrong.com/concepts) to find essays on topics such as [artificial intelligence](https://www.lesswrong.com/w/ai), [history](https://www.lesswrong.com/w/history), [philosophy of science](https://www.lesswrong.com/w/practice-and-philosophy-of-science), [language](https://www.lesswrong.com/w/philosophy-of-language), [psychology](https://www.lesswrong.com/w/psychology), [biology](https://www.lesswrong.com/w/biology), [morality](https://www.lesswrong.com/w/ethics-and-morality), [culture](https://www.lesswrong.com/w/social-and-cultural-dynamics), [self-care](https://www.lesswrong.com/w/well-being), [economics](https://www.lesswrong.com/w/economics), [game theory](https://www.lesswrong.com/w/game-theory), [productivity](https://www.lesswrong.com/w/productivity), [art](https://www.lesswrong.com/w/art), [nutrition](https://www.lesswrong.com/w/nutrition), [relationships](https://www.lesswrong.com/w/relationships-interpersonal) and hundreds of other topics broad and narrow.
|
||||
查阅概念门户,探索人工智能、历史、科学哲学、语言、心理学、生物学、道德、文化、自我关怀、经济学、博弈论、生产力、艺术、营养、人际关系以及数百种主题广泛或专精的文章。
|
||||
|
||||
## LessWrong and Artificial Intelligence"少错"社区与人工智能
|
||||
|
||||
For several reasons, LessWrong is a website and community with a strong interest in AI and specifically causing powerful AI systems to be safe and beneficial.
|
||||
出于多种原因,LessWrong 作为一个网站及社群,对人工智能领域抱有浓厚兴趣,尤其关注如何确保强大的人工智能系统安全且有益。
|
||||
|
||||
- AI is a field concerned with how minds and intelligence works, overlapping a lot with rationality.
|
||||
人工智能这一领域探讨意识与智能的运行机制,与理性思维研究存在大量交集。
|
||||
- Historically, LessWrong was seeded by the writings of Eliezer Yudkowsky, an artificial intelligence researcher.
|
||||
回溯历史,LessWrong 最初源自人工智能研究者埃利泽·尤德考斯基的系列著作。
|
||||
- Many members of the LessWrong community are heavily motivated by trying to improve the world as much as possible, and these people were convinced many years ago that AI was a very big deal for the future of humanity. Since then LessWrong has hosted a lot of discussion of AI Alignment/AI Safety, and that's only accelerated recently with further AI capabilities developments.
|
||||
LessWrong 社区中的许多成员都深受改善世界的强烈动机驱动,这些人多年前就已确信人工智能将对人类的未来产生深远影响。自那时起,LessWrong 便承载了大量关于人工智能对齐与安全性的讨论,而随着近期人工智能能力的进一步发展,这一讨论趋势正在加速。
|
||||
- LessWrong is also integrated with the [Alignment Forum](https://www.alignmentforum.org/about)
|
||||
LessWrong 还与 Alignment Forum 紧密集成。
|
||||
- The LessWrong team who maintain and develop the site are predominantly motivated by trying to cause powerful AI outcomes to be good.
|
||||
维护和开发此网站的 LessWrong 团队,主要动力源于努力促使强大的人工智能带来积极成果。
|
||||
|
||||
If you want to see more or less AI content, you can adjust your Frontpage Tag Filters according to taste [^3].
|
||||
若您希望调整人工智能相关内容的显示频率,可根据个人喜好通过首页标签筛选功能进行设置 <sup><span><a href="https://www.lesswrong.com/posts/bJ2haLkcGeLtTWaD5/#fnq85givw8h9">[3]</a></span></sup> 。
|
||||
|
||||
## Getting Started on LessWrong开启 LessWrong 之旅
|
||||
|
||||
The [New User's Guide](https://www.lesswrong.com/posts/LbbrnRvc9QwjJeics/new-user-s-guide-to-lesswrong) is a great place to start.
|
||||
《新手指南》是极佳的入门起点。
|
||||
|
||||
The core background text of LessWrong is the collection of essays, [Rationality: A-Z](https://www.lesswrong.com/rationality) (aka "The Sequences"). Reading these will help you understand the mindset and philosophy that defines the site. Those looking for a quick introduction can start with [The Sequences Highlights](https://www.lesswrong.com/highlights)
|
||||
LessWrong 的核心背景文本是文集《理性:从 A 到 Z》(亦称“序列系列”)。阅读这些文章将帮助您理解定义本网站思维方式与哲学理念。寻求快速入门者可先阅读《序列精选》
|
||||
|
||||
Other top writings include [The Codex](https://www.lesswrong.com/codex) (writings by Scott Alexander) and [Harry Potter & The Methods of Rationality](https://www.lesswrong.com/hpmor). Also see the [Library Page](https://www.lesswrong.com/library) for many curated collections of posts and the [Concepts Portal.](https://www.lesswrong.com/concepts)
|
||||
其他重要作品包括《秘典集》(斯科特·亚历山大文集)与《哈利波特与理性之道》。您亦可通过文库页查阅众多精选文章合集,或浏览概念门户获取系统知识。
|
||||
|
||||
Also, feel free to introduce yourself in the monthly [open and welcome thread](https://www.lesswrong.com/w/open-threads?sortedBy=new)!
|
||||
也欢迎你随时在每月开放欢迎贴中自我介绍!
|
||||
|
||||
Lastly, we do recommend that new contributors (posters or commenters) take time to familiarize themselves with the sites norms and culture to maximize the chances that your contributions are well-received.
|
||||
最后,我们确实建议新贡献者(无论是发布文章还是评论)花时间熟悉本站的规范和文化,这样能最大限度地让你的贡献受到欢迎。
|
||||
|
||||
Thanks for your interest!
|
||||
感谢你的关注!
|
||||
|
||||
\- The LW Team
|
||||
\- LW 团队
|
||||
|
||||
- [**LessWrong FAQ LessWrong 常见问题**](https://www.lesswrong.com/posts/2rWKkWuPrgTMpLRbp/lesswrong-faq)
|
||||
- [**A Brief History of LessWrong
|
||||
LessWrong 简史**](https://www.lesswrong.com/posts/S69ogAGXcc9EQjpcZ/a-brief-history-of-lesswrong)
|
||||
- [**Team 团队**](https://www.lesswrong.com/posts/aG74jJkiPccqdkK3c/the-lesswrong-team-page-under-construction)
|
||||
- [**LessWrong Concepts LessWrong 概念**](https://www.lesswrong.com/concepts)
|
||||
|
||||
x
|
||||
|
||||
[^1]: Definitions of Rationality as used on LessWrong include:
|
||||
LessWrong 中使用的理性定义包括:
|
||||
|
||||
\- Rationality is thinking in ways that systematically arrive at truth.
|
||||
\- 理性是系统性地抵达真理的思维方式。
|
||||
|
||||
\- Rationality is thinking in ways that cause you to systematically achieve your goals.
|
||||
\- 理性是系统性地帮助你达成目标的思维方式。
|
||||
|
||||
\- Rationality is trying to do better on purpose.
|
||||
\- 理性意味着要有意为之,力求做得更好。
|
||||
|
||||
\- Rationality is reasoning well even in the face of massive uncertainty.
|
||||
\- 理性意味着即便面对巨大的不确定性,仍能进行良好的推理。
|
||||
|
||||
\- Rationality is making good decisions even when it’s hard.
|
||||
\- 理性意味着即便在艰难时刻,也能做出明智的决策。
|
||||
|
||||
\-Rationality is being self-aware, understanding how your own mind works, and applying this knowledge to thinking better.
|
||||
\- 理性意味着保持自我觉察,理解自身心智的运作方式,并运用这些知识来更好地思考。
|
||||
|
||||
[^2]: There are in fact laws of thought no less ironclad than the law of physics \[[source](https://www.lesswrong.com/posts/QkX2bAkwG2EpGvNug/the-second-law-of-thermodynamics-and-engines-of-cognition)\].
|
||||
事实上,思维的法则与物理定律同样牢不可破【来源】。
|
||||
|
||||
[^3]: Hover your mouse over the tags to be able to adjust their weighting in your Latest Posts feed.
|
||||
将鼠标悬停在标签上,即可在“最新帖子”动态中调整其权重。
|
||||
@@ -23,3 +23,9 @@ obsidian:
|
||||
sk-ai-v1-82f1a2df15721ca5d5afc633842b91719fea95c6c449cbb78db0dd03f7ed1aa2
|
||||
```
|
||||
|
||||
|
||||
|
||||
Clawdbot:
|
||||
```
|
||||
sk-ai-v1-74be1c7baa2d45efcea213f3b3cfb7defc03c3e44044b26d9c289f32b156a199
|
||||
```
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
---
|
||||
tags:
|
||||
- 火山引擎
|
||||
- 云计算
|
||||
- ByteDance
|
||||
- AI-ML
|
||||
- 开发资源
|
||||
- API
|
||||
---
|
||||
|
||||
Coding key:
|
||||
```
|
||||
478d5a21-7166-491d-8bca-2ea9bac8b4fb
|
||||
```
|
||||
@@ -0,0 +1,11 @@
|
||||
<claude-mem-context>
|
||||
# Recent Activity
|
||||
|
||||
<!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
|
||||
|
||||
### Jan 21, 2026
|
||||
|
||||
| ID | Time | T | Title | Read |
|
||||
|----|------|---|-------|------|
|
||||
| #175 | 3:34 PM | 🔵 | OpenAPI Contract Review for Opencode Client Plugin | ~553 |
|
||||
</claude-mem-context>
|
||||
Reference in New Issue
Block a user