Skip to content

Commit fc7344f

Browse files
philbuddenCopilot
andauthored
Fix dtm vault-relative path handling for test-overridden DAILY (#5)
## What changed ## Why ## User impact ## Privacy review - [ ] No personal content, credentials, host paths, or private links are present. - [ ] Publication allowlist and denylist behaviour remains fail-closed. ## Validation Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
1 parent 4e02e53 commit fc7344f

1 file changed

Lines changed: 25 additions & 17 deletions

File tree

framework/tools/dtm.py

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
ROOT = Path(__file__).resolve().parent.parent
1515
DAILY = ROOT / "daily"
16-
DAILY_ARCHIVE = DAILY / "archive"
1716
RECURRENCE = ROOT / "dtm" / "recurring-tasks.json"
1817

1918
SECTIONS = [
@@ -43,6 +42,14 @@ class DTMError(RuntimeError):
4342
"""A safe, user-actionable DTM configuration or lifecycle failure."""
4443

4544

45+
def vault_root() -> Path:
46+
return DAILY.parent
47+
48+
49+
def daily_archive_dir() -> Path:
50+
return DAILY / "archive"
51+
52+
4653
def parse_date(value: str) -> date:
4754
try:
4855
return date.fromisoformat(value)
@@ -55,7 +62,7 @@ def active_note_path(day: date) -> Path:
5562

5663

5764
def archived_note_path(day: date) -> Path:
58-
return DAILY_ARCHIVE / f"{day.isoformat()}.md"
65+
return daily_archive_dir() / f"{day.isoformat()}.md"
5966

6067

6168
def note_path(day: date) -> Path:
@@ -73,7 +80,7 @@ def note_exists(day: date) -> bool:
7380

7481

7582
def note_link(day: date) -> str:
76-
return note_path(day).relative_to(ROOT).with_suffix("").as_posix()
83+
return note_path(day).relative_to(vault_root()).with_suffix("").as_posix()
7784

7885

7986
def active_note_files() -> list[Path]:
@@ -82,7 +89,7 @@ def active_note_files() -> list[Path]:
8289

8390
def all_note_files() -> list[Path]:
8491
active = active_note_files()
85-
archived = sorted(path for path in DAILY_ARCHIVE.glob("*.md") if path.name != "README.md")
92+
archived = sorted(path for path in daily_archive_dir().glob("*.md") if path.name != "README.md")
8693
return active + archived
8794

8895

@@ -322,7 +329,7 @@ def replace_frontmatter_value(text: str, field: str, value: str) -> str:
322329
def close_day(day: date, next_day: date | None = None) -> bool:
323330
path = note_path(day)
324331
if not path.exists():
325-
print(f"No Daily Note to close: {path.relative_to(ROOT)}")
332+
print(f"No Daily Note to close: {path.relative_to(vault_root())}")
326333
return False
327334
text = path.read_text(encoding="utf-8")
328335
changed = replace_frontmatter_value(text, "status", "closed")
@@ -332,21 +339,21 @@ def close_day(day: date, next_day: date | None = None) -> bool:
332339
)
333340
if changed != text:
334341
path.write_text(changed, encoding="utf-8")
335-
print(f"Closed {path.relative_to(ROOT)}")
342+
print(f"Closed {path.relative_to(vault_root())}")
336343
else:
337-
print(f"Already closed {path.relative_to(ROOT)}")
344+
print(f"Already closed {path.relative_to(vault_root())}")
338345
return True
339346

340347

341348
def open_day(day: date) -> bool:
342349
path = active_note_path(day)
343350
if path.exists():
344-
print(f"Already open/present: {path.relative_to(ROOT)}")
351+
print(f"Already open/present: {path.relative_to(vault_root())}")
345352
return False
346353
previous_text = read_note(day - timedelta(days=1))
347354
path.parent.mkdir(parents=True, exist_ok=True)
348355
path.write_text(render_note(day, previous_text), encoding="utf-8")
349-
print(f"Created {path.relative_to(ROOT)}")
356+
print(f"Created {path.relative_to(vault_root())}")
350357
return True
351358

352359

@@ -365,10 +372,10 @@ def append_activity(day: date, actor: str, message: str, timestamp: str | None =
365372
text = path.read_text(encoding="utf-8")
366373
notes_match = re.search(r"^## Notes & Activity\s*$", text, re.M)
367374
if notes_match is None:
368-
raise DTMError(f"{path.relative_to(ROOT)} is missing the Notes & Activity section")
375+
raise DTMError(f"{path.relative_to(vault_root())} is missing the Notes & Activity section")
369376
decisions_match = re.search(r"^## Decisions\s*$", text, re.M)
370377
if decisions_match is None:
371-
raise DTMError(f"{path.relative_to(ROOT)} is missing the Decisions section")
378+
raise DTMError(f"{path.relative_to(vault_root())} is missing the Decisions section")
372379

373380
entry = f"- {time_value}{actor.strip()}{message.strip()}"
374381
notes_heading = "## Notes & Activity"
@@ -381,7 +388,7 @@ def append_activity(day: date, actor: str, message: str, timestamp: str | None =
381388
notes_body = text[notes_end:marker_start]
382389
notes_lines = notes_body.rstrip("\n").splitlines()
383390
if entry in notes_lines:
384-
print(f"Activity already present in {path.relative_to(ROOT)}")
391+
print(f"Activity already present in {path.relative_to(vault_root())}")
385392
return False
386393
if notes_lines and notes_lines[-1].strip():
387394
notes_lines.append(entry)
@@ -391,7 +398,7 @@ def append_activity(day: date, actor: str, message: str, timestamp: str | None =
391398

392399
updated_before = f"{notes_prefix}{notes_heading}\n{chr(10).join(notes_lines)}\n"
393400
path.write_text(f"{updated_before}## Decisions{after}", encoding="utf-8")
394-
print(f"Updated {path.relative_to(ROOT)}")
401+
print(f"Updated {path.relative_to(vault_root())}")
395402
return True
396403

397404

@@ -412,19 +419,20 @@ def archive_notes(keep: int) -> int:
412419
if len(note_files) <= keep:
413420
print(f"No Daily Notes archived; {len(note_files)} active note(s) within keep window {keep}.")
414421
return 0
415-
DAILY_ARCHIVE.mkdir(parents=True, exist_ok=True)
422+
archive_dir = daily_archive_dir()
423+
archive_dir.mkdir(parents=True, exist_ok=True)
416424
to_move = note_files[:-keep]
417425
moved_days: list[date] = []
418426
for path in to_move:
419427
if not DATE_RE.fullmatch(path.stem):
420-
raise DTMError(f"Cannot archive non-date Daily Note {path.relative_to(ROOT)}")
428+
raise DTMError(f"Cannot archive non-date Daily Note {path.relative_to(vault_root())}")
421429
day = date.fromisoformat(path.stem)
422430
target = archived_note_path(day)
423431
if target.exists():
424-
raise DTMError(f"Archive destination already exists: {target.relative_to(ROOT)}")
432+
raise DTMError(f"Archive destination already exists: {target.relative_to(vault_root())}")
425433
path.rename(target)
426434
moved_days.append(day)
427-
print(f"Archived {path.relative_to(ROOT)} -> {target.relative_to(ROOT)}")
435+
print(f"Archived {path.relative_to(vault_root())} -> {target.relative_to(vault_root())}")
428436
affected_days = set(moved_days)
429437
for moved_day in moved_days:
430438
affected_days.add(moved_day - timedelta(days=1))

0 commit comments

Comments
 (0)