197 lines
5.6 KiB
Python
197 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Add frontmatter to .md files that lack it. One-off agent-loop fix."""
|
|
import re
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
VAULT = Path(__file__).resolve().parent.parent
|
|
|
|
FILES = """
|
|
decisions/2026-04-16-unifi-migration-peredelki.md
|
|
decisions/2026-03-03-mailserver-setup-scenario.md
|
|
decisions/2026-03-04-matrix-niikn-setup.md
|
|
decisions/2026-04-14-niikn-openwrt-awg-fix.md
|
|
decisions/2026-04-17-peredelki-podkop-stability-fix.md
|
|
decisions/2026-02-26-clawdbot-129-cliproxy-fix.md
|
|
decisions/2026-04-14-openclaw-claude-code-pipeline.md
|
|
decisions/2026-04-17-code-server-upgrade.md
|
|
notes/2026-02-26-knowledge-base-setup.md
|
|
notes/2026-02-26-session-summary.md
|
|
notes/2026-02-26-claude-code-session-clawdbot-fix.md
|
|
notes/2026-02-26-full-session-log.md
|
|
projects/unresolved-issues.md
|
|
projects/nextcloud.md
|
|
projects/infrastructure-overview.md
|
|
projects/homelab-proxmox.md
|
|
projects/video-surveillance.md
|
|
projects/bitrix-sites.md
|
|
projects/clawdbot-bots.md
|
|
projects/all-projects-summary.md
|
|
projects/dttb/npm-homelab.md
|
|
projects/dttb/nextcloud.md
|
|
projects/dttb/proxmox-inventory.md
|
|
projects/dttb/server1c.md
|
|
projects/dttb/agentdvr-home.md
|
|
projects/dttb/memory-inventory.md
|
|
projects/dttb/video-surveillance-report.md
|
|
projects/dttb/openclaw.md
|
|
projects/dttb/credentials.md
|
|
projects/dttb/oleg-agent.md
|
|
projects/dttb/netbird-inventory.md
|
|
projects/dttb/clawdbot.md
|
|
projects/dttb/clawdbot-znam.md
|
|
projects/dttb/spaceweb-dns.md
|
|
projects/dttb/npm-proxy-hosts.md
|
|
projects/dttb/gpu-passthrough.md
|
|
projects/dttb/openwrt-router.md
|
|
projects/dttb/gitea.md
|
|
projects/dttb/mailcow-dttb.md
|
|
projects/dttb/videonablyudenie-znam.md
|
|
projects/dttb/matrix-homelab.md
|
|
projects/dttb/homeassistant.md
|
|
projects/dttb/network-topology.md
|
|
projects/glavtorg/instruction-diana-rdp.md
|
|
projects/niikn/mailcow.md
|
|
projects/niikn/NIIKN-Infrastructure.md
|
|
projects/niikn/groupfolders-migration.md
|
|
projects/niikn/changelog.md
|
|
projects/niikn/matrix.md
|
|
projects/niikn/clawdbot-niikn.md
|
|
projects/niikn/proxmox.md
|
|
projects/niikn/NIIKN-ChangeLog.md
|
|
projects/niikn/npm.md
|
|
projects/niikn/mikrotik.md
|
|
projects/niikn/openwrt-bypass.md
|
|
projects/niikn/NC-Talk-Setup.md
|
|
projects/niikn/vpn.md
|
|
projects/mmfb/proxmox-inventory.md
|
|
snippets/proxmox-console-quirks.md
|
|
snippets/clawdbot-cliproxy-config.md
|
|
claude-memory/servicedesk-dttb.md
|
|
claude-memory/benelux.md
|
|
claude-memory/nextcloud-dttb.md
|
|
claude-memory/nvr-fix.md
|
|
claude-memory/videonablyudenie.md
|
|
claude-memory/znamenskoe-home.md
|
|
claude-memory/niikn-nextcloud.md
|
|
claude-memory/krasnogorsk.md
|
|
claude-memory/mas-niikn.md
|
|
claude-memory/MEMORY.md
|
|
""".strip().splitlines()
|
|
|
|
TODAY = "2026-04-18"
|
|
|
|
|
|
def file_date(rel_path: str, full: Path) -> str:
|
|
name = full.name
|
|
m = re.match(r"^(\d{4}-\d{2}-\d{2})", name)
|
|
if m:
|
|
return m.group(1)
|
|
try:
|
|
r = subprocess.run(
|
|
["git", "log", "--diff-filter=A", "--follow", "--format=%ad",
|
|
"--date=short", "--", rel_path],
|
|
cwd=VAULT, capture_output=True, text=True, timeout=10
|
|
)
|
|
lines = [l.strip() for l in r.stdout.splitlines() if l.strip()]
|
|
if lines:
|
|
return lines[-1]
|
|
except Exception:
|
|
pass
|
|
return TODAY
|
|
|
|
|
|
def type_for(rel_path: str) -> str:
|
|
parts = rel_path.split("/")
|
|
if parts[0] == "decisions":
|
|
return "decision"
|
|
if parts[0] == "notes":
|
|
return "note"
|
|
if parts[0] == "daily":
|
|
return "daily"
|
|
if parts[0] == "projects":
|
|
return "project"
|
|
if parts[0] == "snippets":
|
|
return "reference"
|
|
if parts[0] == "claude-memory":
|
|
return "reference"
|
|
if parts[0] == "templates":
|
|
return "template"
|
|
return "note"
|
|
|
|
|
|
def tags_for(rel_path: str) -> list:
|
|
parts = rel_path.split("/")
|
|
tags = []
|
|
if parts[0] == "decisions":
|
|
tags.append("decision")
|
|
elif parts[0] == "notes":
|
|
tags.append("note")
|
|
elif parts[0] == "snippets":
|
|
tags.append("snippet")
|
|
elif parts[0] == "claude-memory":
|
|
tags.append("memory")
|
|
if len(parts) > 1 and parts[0] == "projects":
|
|
proj = parts[1]
|
|
if proj in ("dttb", "niikn", "glavtorg", "mmfb", "krasnogorsk"):
|
|
tags.append(proj)
|
|
lower = rel_path.lower()
|
|
if "nextcloud" in lower:
|
|
tags.append("nextcloud")
|
|
if "matrix" in lower:
|
|
tags.append("matrix")
|
|
if "proxmox" in lower:
|
|
tags.append("proxmox")
|
|
if "npm" in lower:
|
|
tags.append("npm")
|
|
if "dns" in lower:
|
|
tags.append("dns")
|
|
if "mailcow" in lower or "mail" in lower.split("/")[-1]:
|
|
tags.append("mail")
|
|
if "clawdbot" in lower or "openclaw" in lower:
|
|
tags.append("bot")
|
|
if "vpn" in lower or "openwrt" in lower or "netbird" in lower:
|
|
tags.append("network")
|
|
if "video" in lower or "surveillance" in lower or "camera" in lower or "agentdvr" in lower:
|
|
tags.append("video")
|
|
if not tags:
|
|
tags = ["note"]
|
|
seen = set()
|
|
out = []
|
|
for t in tags:
|
|
if t not in seen:
|
|
seen.add(t)
|
|
out.append(t)
|
|
return out
|
|
|
|
|
|
def add_fm(rel_path: str):
|
|
full = VAULT / rel_path
|
|
if not full.is_file():
|
|
print(f"MISSING: {rel_path}")
|
|
return
|
|
text = full.read_text()
|
|
if text.startswith("---\n"):
|
|
print(f"HAS-FM: {rel_path}")
|
|
return
|
|
d = file_date(rel_path, full)
|
|
t = type_for(rel_path)
|
|
tags = tags_for(rel_path)
|
|
fm = (
|
|
"---\n"
|
|
f"date: {d}\n"
|
|
f"type: {t}\n"
|
|
f"tags: [{', '.join(tags)}]\n"
|
|
"---\n\n"
|
|
)
|
|
full.write_text(fm + text)
|
|
print(f"FIXED: {rel_path} (date={d}, type={t}, tags={tags})")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
for line in FILES:
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
add_fm(line)
|