#!/usr/bin/env bash set -Eeuo pipefail SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)" VAULT_NAME="${VAULT_NAME:-content-forge}" VAULT_PATH="${VAULT_PATH:-${PROJECT_ROOT}/content-forge}" readonly SCRIPT_DIR readonly PROJECT_ROOT readonly VAULT_NAME readonly VAULT_PATH log() { printf '[init-vault] %s\n' "$*" } die() { printf '[init-vault] ERROR: %s\n' "$*" >&2 exit 1 } trap 'die "Command failed at line ${LINENO}: ${BASH_COMMAND}"' ERR require_obsidian() { if ! command -v obsidian >/dev/null 2>&1; then die "Missing required command: obsidian. Run the obsidian-setup skill first." fi } register_vault() { # Vault registration writes directly to ~/.config/obsidian/obsidian.json. # The obsidian CLI has no vault-add subcommand; registration is done by # editing the config file (same approach as obsidian-setup/scripts/register_vault.py). local config_path="$HOME/.config/obsidian/obsidian.json" # Use environment variables to avoid command injection export VAULT_PATH CONFIG_PATH="$config_path" python3 -c " import json, os, hashlib, time vault_path = os.environ['VAULT_PATH'] vault_id = hashlib.md5(vault_path.encode()).hexdigest()[:16] config_path = os.environ['CONFIG_PATH'] os.makedirs(os.path.join(vault_path, '.obsidian'), exist_ok=True) if os.path.exists(config_path): with open(config_path) as f: config = json.load(f) else: os.makedirs(os.path.dirname(config_path), exist_ok=True) config = {} config['cli'] = True config.setdefault('vaults', {}) # Check if already registered for vid, vdata in config['vaults'].items(): if vdata.get('path') == vault_path: print(f'Vault already registered: {vault_path} (id: {vid})') exit(0) config['vaults'][vault_id] = {'path': vault_path, 'ts': int(time.time() * 1000)} with open(config_path, 'w') as f: json.dump(config, f, indent=2) print(f'Registered vault: {vault_path} (id: {vault_id})') " } create_directories() { local dirs=( "00-inbox" "01-topics" "02-drafts" "03-review" "04-published" "05-assets" "06-archived" "07-leads" "08-events" "09-viral-examples" "templates" ) local dir for dir in "${dirs[@]}"; do mkdir -p "${VAULT_PATH}/${dir}" done log "Ensured vault directories exist." } create_templates() { local t="${VAULT_PATH}/templates" mkdir -p "${t}" # article template — matches writing-styles.md:tech_blog structure if [[ ! -f "${t}/article.md" ]]; then cat >"${t}/article.md" <<'EOF' --- id: "" title: "" slug: "" status: "topic" content_type: "article" channels: [] language: "zh-CN" source_urls: [] assets: [] cover_image: "" template: "article" owner: "content-forge" created_at: "" updated_at: "" published_at: null --- # 问题背景 # 核心方案 # 实现细节 # 验证结果 # 总结与扩展 EOF log "Created template: article" else log "Template already exists, skip: article" fi # tech-blog template — same frontmatter, tech_blog structure if [[ ! -f "${t}/tech-blog.md" ]]; then cat >"${t}/tech-blog.md" <<'EOF' --- id: "" title: "" slug: "" status: "topic" content_type: "article" channels: [] language: "zh-CN" source_urls: [] assets: [] cover_image: "" template: "tech-blog" owner: "content-forge" created_at: "" updated_at: "" published_at: null --- # 问题背景 # 核心方案 # 实现细节 # 验证结果 # 总结与扩展 EOF log "Created template: tech-blog" else log "Template already exists, skip: tech-blog" fi # social-post template — matches writing-styles.md:social_short structure if [[ ! -f "${t}/social-post.md" ]]; then cat >"${t}/social-post.md" <<'EOF' --- id: "" title: "" slug: "" status: "topic" content_type: "x-post" channels: ["x"] language: "zh-CN" source_urls: [] assets: [] cover_image: "" template: "social-post" owner: "content-forge" created_at: "" updated_at: "" published_at: null --- EOF log "Created template: social-post" else log "Template already exists, skip: social-post" fi # viral-example template — for 09-viral-examples/ collection if [[ ! -f "${t}/viral-example.md" ]]; then cat >"${t}/viral-example.md" <<'EOF' --- id: "" title: "" source_url: "" platform: "" # x | wechat | xiaohongshu | douyin | bilibili | medium | other author: "" author_url: "" published_at: "" collected_at: "" metrics: likes: null comments: null shares: null views: null viral_score: null tags: [] language: "zh-CN" related_topics: [] analysis: null takeaways: [] --- # 原文(或摘要) [原文内容或核心观点摘要] # 为什么火 [你的分析:时机、情绪、表达、平台特性等] # 可复用点 - # 关联选题 - [[01-topics/xxx|相关选题]] EOF log "Created template: viral-example" else log "Template already exists, skip: viral-example" fi } main() { require_obsidian mkdir -p "${VAULT_PATH}" register_vault create_directories create_templates log "Vault initialization complete: ${VAULT_PATH}" } main "$@"