mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-09 03:13:19 +08:00
162 lines
6.7 KiB
Python
162 lines
6.7 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
import datetime as dt
|
|
from pathlib import Path
|
|
|
|
|
|
def _now_date() -> dt.date:
|
|
return dt.date.today()
|
|
|
|
|
|
def _iso_week_label(day: dt.date) -> str:
|
|
year, week, _weekday = day.isocalendar()
|
|
return f"{year}-W{week:02d}"
|
|
|
|
|
|
def _ensure_dirs(base_dir: Path) -> None:
|
|
for name in ("Projects", "Areas", "Resources", "Archives", "Inbox", "runs"):
|
|
(base_dir / name).mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
def _count_notes(path: Path) -> int:
|
|
if not path.exists():
|
|
return 0
|
|
count = 0
|
|
for item in path.rglob("*.md"):
|
|
if item.name.lower() == "readme.md":
|
|
continue
|
|
if "templates" in item.parts or "runs" in item.parts:
|
|
continue
|
|
count += 1
|
|
return count
|
|
|
|
|
|
def _recommend_new_cards(inbox_count: int, backlog_count: int, fresh_resources: int) -> int:
|
|
target = 10
|
|
if backlog_count > 0:
|
|
target -= min(6, backlog_count // 20)
|
|
if inbox_count > 20:
|
|
target -= 2
|
|
if fresh_resources >= 5 and backlog_count < 20:
|
|
target += 1
|
|
return max(3, min(10, target))
|
|
|
|
|
|
def _build_focus_order(projects: int, areas: int, resources: int) -> list[str]:
|
|
ranked = [("Projects", projects * 3), ("Areas", areas * 2), ("Resources", resources)]
|
|
ranked.sort(key=lambda x: x[1], reverse=True)
|
|
return [name for name, score in ranked if score > 0][:3]
|
|
|
|
|
|
def _parse_date(text: str | None) -> dt.date:
|
|
if not text:
|
|
return _now_date()
|
|
return dt.date.fromisoformat(text)
|
|
|
|
|
|
def _cmd_memory_status(args: argparse.Namespace) -> int:
|
|
base = Path(args.base_dir).resolve()
|
|
_ensure_dirs(base)
|
|
projects = _count_notes(base / "Projects")
|
|
areas = _count_notes(base / "Areas")
|
|
resources = _count_notes(base / "Resources")
|
|
archives = _count_notes(base / "Archives")
|
|
inbox = _count_notes(base / "Inbox")
|
|
suggested = _recommend_new_cards(inbox, int(args.review_backlog), resources)
|
|
focus = _build_focus_order(projects, areas, resources)
|
|
print(f"base_dir={base}")
|
|
print(f"projects={projects} areas={areas} resources={resources} archives={archives} inbox={inbox}")
|
|
print(f"suggested_new_cards_per_day={suggested}")
|
|
print("focus_topics=" + (",".join(focus) if focus else "Resources"))
|
|
return 0
|
|
|
|
|
|
def _cmd_memory_daily(args: argparse.Namespace) -> int:
|
|
base = Path(args.base_dir).resolve()
|
|
_ensure_dirs(base)
|
|
day = _parse_date(args.date)
|
|
projects = _count_notes(base / "Projects")
|
|
areas = _count_notes(base / "Areas")
|
|
resources = _count_notes(base / "Resources")
|
|
inbox = _count_notes(base / "Inbox")
|
|
suggested = _recommend_new_cards(inbox, int(args.review_backlog), resources)
|
|
focus = _build_focus_order(projects, areas, resources)
|
|
focus_topic = args.focus or (focus[0] if focus else "Resources")
|
|
out = base / "runs" / f"daily-{day.isoformat()}.md"
|
|
text = (
|
|
f"# Daily Memory Run ({day.isoformat()})\n\n"
|
|
f"- Focus topic: `{focus_topic}`\n"
|
|
f"- Suggested new cards today: `{suggested}`\n"
|
|
f"- Current inbox notes: `{inbox}`\n"
|
|
f"- Review backlog input: `{int(args.review_backlog)}`\n\n"
|
|
"## Auto Steps\n\n"
|
|
"1. Capture 3-5 high-value items into `Inbox`.\n"
|
|
"2. Distill 1-3 items into atomic notes under `Resources`.\n"
|
|
"3. Convert notes into Q/A or cloze cards (respect suggested limit).\n"
|
|
"4. Produce one output (summary/answer/code note).\n\n"
|
|
"## Smart Suggestions\n\n"
|
|
f"- Priority order now: `{', '.join(focus) if focus else 'Resources'}`\n"
|
|
"- If reviews feel overloaded, reduce new cards before skipping due reviews.\n"
|
|
"- If inbox keeps growing for 2+ days, process inbox first before new captures.\n"
|
|
)
|
|
out.write_text(text, encoding="utf-8")
|
|
print(f"created={out}")
|
|
return 0
|
|
|
|
|
|
def _cmd_memory_weekly(args: argparse.Namespace) -> int:
|
|
base = Path(args.base_dir).resolve()
|
|
_ensure_dirs(base)
|
|
day = _parse_date(args.date)
|
|
week_label = _iso_week_label(day)
|
|
projects = _count_notes(base / "Projects")
|
|
areas = _count_notes(base / "Areas")
|
|
resources = _count_notes(base / "Resources")
|
|
archives = _count_notes(base / "Archives")
|
|
inbox = _count_notes(base / "Inbox")
|
|
suggested = _recommend_new_cards(inbox, int(args.review_backlog), resources)
|
|
focus = _build_focus_order(projects, areas, resources)
|
|
out = base / "runs" / f"weekly-{week_label}.md"
|
|
text = (
|
|
f"# Weekly Memory Review ({week_label})\n\n"
|
|
f"- Run date: `{day.isoformat()}`\n"
|
|
f"- Suggested next-week new cards/day: `{suggested}`\n\n"
|
|
"## Snapshot\n\n"
|
|
f"- Projects notes: `{projects}`\n"
|
|
f"- Areas notes: `{areas}`\n"
|
|
f"- Resources notes: `{resources}`\n"
|
|
f"- Archives notes: `{archives}`\n"
|
|
f"- Inbox notes: `{inbox}`\n\n"
|
|
"## Fixed Review Checklist\n\n"
|
|
"- [ ] Inbox zero\n- [ ] Linking/backlinks completion\n- [ ] Move inactive notes to Archives\n- [ ] Tune next-week card load\n\n"
|
|
"## Auto Focus for Next Week\n\n"
|
|
f"- Top topics: `{', '.join(focus) if focus else 'Resources'}`\n"
|
|
"- Keep new cards within 3-10/day and adjust by real review pressure.\n"
|
|
)
|
|
out.write_text(text, encoding="utf-8")
|
|
print(f"created={out}")
|
|
return 0
|
|
|
|
|
|
def register_memory_parser(root_sub: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
|
|
memory = root_sub.add_parser("memory", help="Memory system automation")
|
|
memory_sub = memory.add_subparsers(dest="memory_cmd", required=True)
|
|
|
|
status = memory_sub.add_parser("status", help="Show memory workload status")
|
|
status.add_argument("--base-dir", default="docs/memory-system", help="Memory system base directory")
|
|
status.add_argument("--review-backlog", type=int, default=0, help="Current due review backlog")
|
|
status.set_defaults(func=_cmd_memory_status)
|
|
|
|
daily = memory_sub.add_parser("daily", help="Generate today's automated memory run")
|
|
daily.add_argument("--base-dir", default="docs/memory-system", help="Memory system base directory")
|
|
daily.add_argument("--date", default=None, help="Run date in YYYY-MM-DD")
|
|
daily.add_argument("--focus", default=None, help="Override focus topic")
|
|
daily.add_argument("--review-backlog", type=int, default=0, help="Current due review backlog")
|
|
daily.set_defaults(func=_cmd_memory_daily)
|
|
|
|
weekly = memory_sub.add_parser("weekly", help="Generate weekly review run sheet")
|
|
weekly.add_argument("--base-dir", default="docs/memory-system", help="Memory system base directory")
|
|
weekly.add_argument("--date", default=None, help="Run date in YYYY-MM-DD")
|
|
weekly.add_argument("--review-backlog", type=int, default=0, help="Current due review backlog")
|
|
weekly.set_defaults(func=_cmd_memory_weekly)
|