mirror of
https://github.com/dtzp555-max/memory-continuity.git
synced 2026-07-21 21:15:07 +00:00
144 lines
4.1 KiB
Python
Executable File
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())
|