Files
memory-continuity/skills/continuity-guard/scripts/continuity_doctor.py
T

144 lines
4.1 KiB
Python
Executable File

#!/usr/bin/env python3
from __future__ import annotations
import argparse
from pathlib import Path
REQUIRED_SECTIONS = [
'## In Flight',
'## Blocked / Waiting',
'## Recently Finished',
'## Next',
'## Reset Summary',
]
AGENTS_MARKERS = [
'CURRENT_STATE.md - Your Short-Term Workbench',
'Dual reporting protocol',
'Execution agent → main',
'main → Tao',
]
def result(level: str, msg: str) -> tuple[str, str]:
print(f'{level:<5} {msg}')
return level, msg
def line_count(path: Path) -> int:
try:
return len(path.read_text().splitlines())
except Exception:
return 0
def has_sections(path: Path) -> list[str]:
text = path.read_text()
missing = [s for s in REQUIRED_SECTIONS if s not in text]
return missing
def main() -> int:
ap = argparse.ArgumentParser(description='Check continuity/CURRENT_STATE coverage and drift.')
ap.add_argument('--main-workspace', required=True)
ap.add_argument('--agents-root', required=True)
args = ap.parse_args()
main_ws = Path(args.main_workspace)
agents_root = Path(args.agents_root)
failures = 0
warns = 0
print('continuity doctor\n')
# main AGENTS.md
agents_md = main_ws / 'AGENTS.md'
if not agents_md.exists():
failures += 1
result('FAIL', f'missing {agents_md}')
else:
text = agents_md.read_text()
missing = [m for m in AGENTS_MARKERS if m not in text]
if missing:
failures += 1
result('FAIL', f'AGENTS continuity markers missing: {", ".join(missing)}')
else:
result('PASS', 'AGENTS continuity rules present')
# main CURRENT_STATE
main_cs = main_ws / 'memory' / 'CURRENT_STATE.md'
if not main_cs.exists():
failures += 1
result('FAIL', 'main CURRENT_STATE missing')
else:
missing = has_sections(main_cs)
if missing:
failures += 1
result('FAIL', f'main CURRENT_STATE missing sections: {", ".join(missing)}')
else:
result('PASS', 'main CURRENT_STATE sections present')
n = line_count(main_cs)
if n > 50:
warns += 1
result('WARN', f'main CURRENT_STATE too long: {n} lines (cap 50)')
else:
result('PASS', f'main CURRENT_STATE length ok: {n} lines')
# agent workspaces
checked = 0
missing_files = []
missing_sections = []
oversize = []
if agents_root.exists():
for ws in sorted([p for p in agents_root.iterdir() if p.is_dir()]):
checked += 1
cs = ws / 'memory' / 'CURRENT_STATE.md'
if not cs.exists():
missing_files.append(ws.name)
continue
missing = has_sections(cs)
if missing:
missing_sections.append((ws.name, missing))
n = line_count(cs)
if n > 30:
oversize.append((ws.name, n))
if missing_files:
failures += 1
result('FAIL', f'agent CURRENT_STATE missing: {", ".join(missing_files)}')
else:
result('PASS', f'agent CURRENT_STATE files present: {checked}/{checked}')
if missing_sections:
failures += 1
details = '; '.join(f'{name}: {", ".join(m)}' for name, m in missing_sections)
result('FAIL', f'agent CURRENT_STATE missing sections: {details}')
else:
result('PASS', 'agent CURRENT_STATE sections present')
if oversize:
warns += 1
details = '; '.join(f'{name}: {n} lines' for name, n in oversize)
result('WARN', f'agent CURRENT_STATE oversize: {details}')
else:
result('PASS', 'agent CURRENT_STATE length caps respected')
print('\nSummary')
print(f'- failures: {failures}')
print(f'- warnings: {warns}')
if failures:
print('\nSuggested actions:')
print('1. create/restore missing CURRENT_STATE files')
print('2. restore AGENTS continuity section if missing')
print('3. trim oversized CURRENT_STATE files')
print('4. rerun continuity doctor')
return 2
return 0
if __name__ == '__main__':
raise SystemExit(main())