abse/museair-usb

USB-C–powered ESP32-C3 controller board with AP63203 buck conversion, AP2112K 3.3V regulation, I²C SEN62 sensor interface, status LED, buttons, UART/I²C headers, and extensive decoupling.

Version
0.5.7
License
unset
Stars
0

scripts/package-handoff.py

"""Package the full current board/context for a selected cloud destination."""
from pathlib import Path
import datetime,hashlib,json,zipfile
root=Path(__file__).resolve().parent.parent
excluded_dirs={'node_modules','.tscircuit','.claude','__pycache__','.git'}
excluded_files={'HANDOFF-MANIFEST.json','dist/index/raw.kicad_pcb'}
files=sorted(p for p in root.rglob('*') if p.is_file() and not p.is_symlink()
    and not excluded_dirs.intersection(p.relative_to(root).parts)
    and str(p.relative_to(root)) not in excluded_files and p.name!='.DS_Store'
    and p.suffix not in {'.kicad_prl','.pyc','.lck'})
chat=json.loads((root/'docs/CHAT-TRANSCRIPT.json').read_text())
audit=json.loads((root/'validation/production-audit.json').read_text())
assert audit['status']=='pass'
for rel,digest in audit['sha256'].items():
    assert hashlib.sha256((root/rel).read_bytes()).hexdigest()==digest,rel
manifest={
 'project':'MuseAir USB','package_version':'0.5.5','prepared_for_client_date':'2026-10-06',
 'generated_at_utc':datetime.datetime.now(datetime.timezone.utc).isoformat(),
 'migration_status':'Prepared locally; destination cloud receipt is not confirmed',
 'local_original_retained':True,'source_private_registry':'https://tscircuit.com/abse/museair-usb',
 'history':{k:chat[k] for k in ['thread_id','thread_title','history_pagination_complete','turns','user_messages','assistant_messages','attachment_limit'] if k!='turns'},
 'history_turn_count':len(chat['turns']),
 'excluded':'Machine-specific dependency symlink, caches, credentials, raw uncorrected KiCad export, temporary files and unrelated/superseded scratch dependencies',
 'files':{str(p.relative_to(root)):{'bytes':p.stat().st_size,'sha256':hashlib.sha256(p.read_bytes()).hexdigest()} for p in files}
}
mp=root/'HANDOFF-MANIFEST.json';mp.write_text(json.dumps(manifest,indent=2)+'\n')
files.append(mp)
out=root.parent/'museair-cloud-handoff.zip'
with zipfile.ZipFile(out,'w',zipfile.ZIP_DEFLATED) as z:
    for p in files:z.write(p,'museair-usb/'+str(p.relative_to(root)))
with zipfile.ZipFile(out) as z:
    assert z.testzip() is None
    assert len(z.namelist())==len(files)
    for rel,record in manifest['files'].items():
        assert hashlib.sha256(z.read('museair-usb/'+rel)).hexdigest()==record['sha256'],rel
(root.parent/(out.name+'.sha256')).write_text(hashlib.sha256(out.read_bytes()).hexdigest()+'  '+out.name+'\n')
print(f'Saved {out.name}: {len(files)} files, {out.stat().st_size:,} bytes; full context included')