mirror of
https://github.com/Ar9av/obsidian-wiki.git
synced 2026-09-14 20:36:34 +08:00
77d74e0261
* feat(config): resolve global config from an XDG-style location (#172) The global config lived at ~/.obsidian-wiki, which isn't XDG-compliant. It now resolves to $XDG_CONFIG_HOME/obsidian-wiki (default ~/.config/obsidian-wiki). Existing installs are unaffected: if ~/.obsidian-wiki is present and the XDG path is not, the legacy directory is used as-is. No migration is required, and nothing moves on upgrade. Once the XDG path exists it wins, so `mv ~/.obsidian-wiki ~/.config/obsidian-wiki` is all a migration takes. Resolution is implemented identically in Python (cli.py), bash (setup.sh, scripts/daily-update.sh, scripts/wiki-notify.sh), and the Config Resolution Protocol that every skill defers to, so vault-scoped state and named `config.<name>` profiles stay in one place. * fix(config): stop setup from wiping user-added config keys `write_config` rewrote the global config with only the three setup-managed keys, so every `obsidian-wiki setup` — including the one a pip upgrade prompts for — silently destroyed anything else in the file: OBSIDIAN_LINK_FORMAT, QMD_WIKI_COLLECTION, WIKI_SKIP_PROJECTS, sync settings, and comments. Setup now owns only OBSIDIAN_VAULT_PATH, OBSIDIAN_WIKI_REPO and OBSIDIAN_WIKI_VERSION, updating those in place and carrying every other line over untouched. Duplicate definitions of a managed key collapse to one. Predates the XDG change (same behavior on main) but is fixed here because this branch already touches config writing, and the XDG work makes re-running setup more likely. Also pins PYTHONPATH in both new test files so they exercise this checkout rather than whatever obsidian_wiki happens to be installed.
131 lines
3.8 KiB
Bash
Executable File
131 lines
3.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# Daily wiki index update — called by launchd or directly.
|
|
# Checks if any history sources are stale and writes vault-scoped state files
|
|
# that the shell prompt reads on terminal open.
|
|
#
|
|
# Config resolution order (mirrors llm-wiki/SKILL.md protocol):
|
|
# 1. Walk up from CWD looking for .env with OBSIDIAN_VAULT_PATH
|
|
# 2. Fall back to the global config (XDG-style; legacy ~/.obsidian-wiki honored)
|
|
# 3. Exit with error if neither found
|
|
|
|
# XDG-style global config dir, with legacy ~/.obsidian-wiki fallback for
|
|
# installs that already have it (see llm-wiki/SKILL.md Config Resolution Protocol).
|
|
_obsidian_wiki_config_dir() {
|
|
local xdg_dir="${XDG_CONFIG_HOME:-$HOME/.config}/obsidian-wiki"
|
|
local legacy_dir="$HOME/.obsidian-wiki"
|
|
if [[ -d "$legacy_dir" && ! -e "$xdg_dir" ]]; then
|
|
echo "$legacy_dir"
|
|
else
|
|
echo "$xdg_dir"
|
|
fi
|
|
}
|
|
|
|
_find_config() {
|
|
local dir="$PWD"
|
|
while [[ "$dir" != "$HOME" && "$dir" != "/" ]]; do
|
|
if [[ -f "$dir/.env" ]] && grep -q "OBSIDIAN_VAULT_PATH" "$dir/.env" 2>/dev/null; then
|
|
echo "$dir/.env"
|
|
return
|
|
fi
|
|
dir="$(dirname "$dir")"
|
|
done
|
|
local global_config
|
|
global_config="$(_obsidian_wiki_config_dir)/config"
|
|
if [[ -f "$global_config" ]]; then
|
|
echo "$global_config"
|
|
return
|
|
fi
|
|
echo ""
|
|
}
|
|
|
|
CONFIG_FILE="$(_find_config)"
|
|
|
|
if [[ -z "$CONFIG_FILE" ]]; then
|
|
echo "[wiki-daily] No config found. Run wiki-setup to initialize your wiki." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# shellcheck source=/dev/null
|
|
source "$CONFIG_FILE"
|
|
|
|
if [[ -z "${OBSIDIAN_VAULT_PATH:-}" ]]; then
|
|
echo "[wiki-daily] OBSIDIAN_VAULT_PATH not set in $CONFIG_FILE — skipping" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Vault-scoped state dir (supports multiple vaults independently)
|
|
VAULT_ID=$(echo "$OBSIDIAN_VAULT_PATH" | md5sum 2>/dev/null | cut -c1-8 || \
|
|
md5 -q - <<< "$OBSIDIAN_VAULT_PATH" 2>/dev/null | cut -c1-8 || \
|
|
echo "default")
|
|
STATE_DIR="$(_obsidian_wiki_config_dir)/state/$VAULT_ID"
|
|
mkdir -p "$STATE_DIR"
|
|
|
|
# Write vault path so wiki-notify.sh can find this state dir
|
|
echo "$OBSIDIAN_VAULT_PATH" > "$STATE_DIR/.vault_path"
|
|
|
|
MANIFEST="$OBSIDIAN_VAULT_PATH/.manifest.json"
|
|
|
|
# Count sources modified after last ingest
|
|
stale_count=0
|
|
if [[ -f "$MANIFEST" ]]; then
|
|
last_updated=$(python3 -c "
|
|
import json, sys
|
|
try:
|
|
d = json.load(open('$MANIFEST'))
|
|
print(d.get('last_updated',''))
|
|
except:
|
|
print('')
|
|
" 2>/dev/null || echo "")
|
|
|
|
if [[ -n "$last_updated" ]]; then
|
|
stale_count=$(MANIFEST="$MANIFEST" OBSIDIAN_VAULT_PATH="$OBSIDIAN_VAULT_PATH" python3 - <<'PYEOF'
|
|
import json, os, sys
|
|
from datetime import datetime, timezone
|
|
|
|
manifest_path = os.environ["MANIFEST"]
|
|
try:
|
|
with open(manifest_path) as f:
|
|
manifest = json.load(f)
|
|
except Exception:
|
|
print(0)
|
|
sys.exit()
|
|
|
|
last_updated_str = manifest.get("last_updated", "")
|
|
try:
|
|
last_updated = datetime.fromisoformat(last_updated_str.replace("Z", "+00:00"))
|
|
except Exception:
|
|
print(0)
|
|
sys.exit()
|
|
if last_updated.tzinfo is None:
|
|
last_updated = last_updated.replace(tzinfo=timezone.utc)
|
|
|
|
vault_path = os.environ.get("OBSIDIAN_VAULT_PATH", "")
|
|
stale = 0
|
|
for path, meta in manifest.get("sources", {}).items():
|
|
expanded = os.path.expanduser(path)
|
|
if not os.path.isabs(expanded) and vault_path:
|
|
expanded = os.path.join(vault_path, expanded)
|
|
if os.path.exists(expanded):
|
|
mtime = datetime.fromtimestamp(os.path.getmtime(expanded), tz=timezone.utc)
|
|
if mtime > last_updated:
|
|
stale += 1
|
|
|
|
print(stale)
|
|
PYEOF
|
|
)
|
|
fi
|
|
fi
|
|
|
|
# Write vault-scoped state
|
|
NOW=$(date +%s)
|
|
echo "$NOW" > "$STATE_DIR/.last_update"
|
|
echo "$stale_count" > "$STATE_DIR/.pending_delta"
|
|
|
|
if [[ "$stale_count" -gt 0 ]]; then
|
|
echo "[wiki-daily] $stale_count source(s) have new content since last ingest. State: $STATE_DIR"
|
|
else
|
|
echo "[wiki-daily] Wiki is up to date. State: $STATE_DIR"
|
|
fi
|