ada-pc: 2026-06-16 20:13:30 | 8
Affected files: 99 System/Export/agent-tools/AGENT_TOOLS.md 99 System/Export/agent-tools/vault_audit.py 99 System/Export/agent-tools/vault_common.py 99 System/Export/agent-tools/vault_frontmatter.py 99 System/Export/agent-tools/vault_index.py 99 System/Export/agent-tools/vault_ingest.py 99 System/INDEX.md AGENTS.md
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
from vault_common import (
|
||||
REQUIRED_FRONTMATTER,
|
||||
ROOT,
|
||||
VALID_STATUS,
|
||||
VALID_TYPE,
|
||||
all_records,
|
||||
as_list,
|
||||
json_print,
|
||||
note_record,
|
||||
note_files,
|
||||
rel,
|
||||
split_frontmatter,
|
||||
)
|
||||
|
||||
|
||||
def resolve_paths(paths: list[str]) -> list[Path]:
|
||||
if not paths:
|
||||
return note_files()
|
||||
result = []
|
||||
for item in paths:
|
||||
path = Path(item)
|
||||
if not path.is_absolute():
|
||||
path = ROOT / path
|
||||
result.append(path)
|
||||
return result
|
||||
|
||||
|
||||
def validate_record(record: dict[str, object]) -> list[str]:
|
||||
fm = record["frontmatter"]
|
||||
issues = []
|
||||
|
||||
if not record["has_frontmatter"]:
|
||||
issues.append("missing_frontmatter")
|
||||
|
||||
for field in sorted(REQUIRED_FRONTMATTER):
|
||||
if field not in fm or fm[field] in (None, ""):
|
||||
issues.append(f"missing_{field}")
|
||||
|
||||
if fm.get("status") and str(fm["status"]) not in VALID_STATUS:
|
||||
issues.append("invalid_status")
|
||||
if fm.get("type") and str(fm["type"]) not in VALID_TYPE:
|
||||
issues.append("invalid_type")
|
||||
if "tags" in fm and not isinstance(fm["tags"], list):
|
||||
issues.append("tags_not_list")
|
||||
if "aliases" in fm and fm["aliases"] not in (None, "") and not isinstance(fm["aliases"], list):
|
||||
issues.append("aliases_not_list")
|
||||
|
||||
return issues
|
||||
|
||||
|
||||
def check(paths: list[Path]) -> list[dict[str, object]]:
|
||||
results = []
|
||||
for path in paths:
|
||||
record = note_record(path)
|
||||
issues = validate_record(record)
|
||||
if issues:
|
||||
results.append({"path": rel(path), "issues": issues})
|
||||
return results
|
||||
|
||||
|
||||
def yaml_list(values: list[str]) -> list[str]:
|
||||
if not values:
|
||||
return ["[]"]
|
||||
return [""] + [f" - {value}" for value in values]
|
||||
|
||||
|
||||
def normalize(path: Path) -> dict[str, object]:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
fm, body, _ = split_frontmatter(text)
|
||||
title = fm.get("title") or path.stem
|
||||
status = fm.get("status") if fm.get("status") in VALID_STATUS else "seed"
|
||||
note_type = fm.get("type") if fm.get("type") in VALID_TYPE else "concept"
|
||||
tags = as_list(fm.get("tags"))
|
||||
aliases = as_list(fm.get("aliases"))
|
||||
created = fm.get("created") or date.today().isoformat()
|
||||
updated = date.today().isoformat()
|
||||
|
||||
lines = [
|
||||
"---",
|
||||
f"title: {title}",
|
||||
f"status: {status}",
|
||||
f"type: {note_type}",
|
||||
"tags:" + ("\n".join(yaml_list(tags)) if tags else " []"),
|
||||
f"created: {created}",
|
||||
f"updated: {updated}",
|
||||
"aliases:" + ("\n".join(yaml_list(aliases)) if aliases else " []"),
|
||||
]
|
||||
|
||||
for key, value in fm.items():
|
||||
if key in {"title", "status", "type", "tags", "created", "updated", "aliases"}:
|
||||
continue
|
||||
if isinstance(value, list):
|
||||
lines.append(f"{key}:")
|
||||
lines.extend(f" - {item}" for item in value)
|
||||
elif value in (None, ""):
|
||||
lines.append(f"{key}:")
|
||||
else:
|
||||
lines.append(f"{key}: {value}")
|
||||
|
||||
lines.extend(["---", "", body.lstrip("\n")])
|
||||
path.write_text("\n".join(lines), encoding="utf-8")
|
||||
return {"path": rel(path), "written": True}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Agent-facing frontmatter helper")
|
||||
sub = parser.add_subparsers(dest="command", required=True)
|
||||
|
||||
check_cmd = sub.add_parser("check")
|
||||
check_cmd.add_argument("paths", nargs="*")
|
||||
|
||||
normalize_cmd = sub.add_parser("normalize")
|
||||
normalize_cmd.add_argument("paths", nargs="+")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.command == "check":
|
||||
issues = check(resolve_paths(args.paths))
|
||||
json_print({"ok": True, "issues": issues, "total_with_issues": len(issues)})
|
||||
elif args.command == "normalize":
|
||||
written = [normalize(path) for path in resolve_paths(args.paths)]
|
||||
json_print({"ok": True, "written": written})
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user