brainiac-cli 0.20.32__tar.gz → 0.20.34__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {brainiac_cli-0.20.32/src/brainiac_cli.egg-info → brainiac_cli-0.20.34}/PKG-INFO +1 -1
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/pyproject.toml +1 -1
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/AGENTS.md +36 -6
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/scripts/install-brief-mac.sh +119 -12
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/scripts/vm-boundary-probe.sh +67 -16
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_version.py +1 -1
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/alerts.py +61 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/alerts_staging.py +34 -4
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli.py +24 -24
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/index_storage_parser.py +1 -1
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/lifecycle.py +46 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/lifecycle_parser.py +32 -0
- brainiac_cli-0.20.34/src/brain/cli_read_record.py +124 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/config.py +31 -0
- brainiac_cli-0.20.34/src/brain/cowork_leak_artifact.py +24 -0
- brainiac_cli-0.20.34/src/brain/cowork_leak_databases.py +133 -0
- brainiac_cli-0.20.34/src/brain/cowork_leak_notes.py +138 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cowork_leak_scan.py +41 -164
- brainiac_cli-0.20.34/src/brain/cowork_snapshot_guard.py +59 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/doctor.py +6 -5
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/doctor_checks.py +11 -1
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/doctor_context.py +16 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/doctor_mount_leak.py +75 -8
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/doctor_staging.py +16 -97
- brainiac_cli-0.20.34/src/brain/doctor_wiring.py +247 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/draft_drain.py +67 -4
- brainiac_cli-0.20.34/src/brain/draft_update.py +106 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/egress.py +11 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/graph.py +48 -6
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_tools.py +12 -2
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/mcp_mediation.py +21 -13
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/mcp_tools/core_read.py +2 -2
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/mcp_verbs.py +35 -18
- brainiac_cli-0.20.34/src/brain/pathkey.py +143 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/provision.py +138 -77
- brainiac_cli-0.20.34/src/brain/provision_mcp.py +113 -0
- brainiac_cli-0.20.34/src/brain/provision_stage.py +128 -0
- brainiac_cli-0.20.34/src/brain/provision_wire.py +461 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/read_log.py +74 -11
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/remediation.py +21 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/snapshot.py +48 -2
- brainiac_cli-0.20.34/src/brain/sweepdirs.py +294 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/update_channels.py +51 -40
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/workspaces.py +68 -6
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34/src/brainiac_cli.egg-info}/PKG-INFO +1 -1
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brainiac_cli.egg-info/SOURCES.txt +12 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/LICENSE +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/MANIFEST.in +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/README.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/setup.cfg +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/__init__.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/__main__.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/assets/graph-explorer-template.html +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/overlay/template/brand/brand-guide.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/overlay/template/cos/auto-archive.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/overlay/template/cos/browser-lane.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/overlay/template/cos/drafts.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/overlay/template/cos/ingest.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/overlay/template/cos/priorities.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/overlay/template/cos/tenant-domains.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/overlay/template/keywords/glossary.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/overlay/template/people/roster.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/overlay/template/voice/voice-profile.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/routines/manifest.json +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/scripts/brain-brief-mac.plist +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/scripts/brain-brief.sh +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/scripts/brain-synthesis-mac.plist +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/scripts/brain-synthesis.sh +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/scripts/brainiac-alerts.sh +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/scripts/install-brief-windows.ps1 +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/scripts/register_tasks.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/scripts/vm-selftest.sh +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/templates/company.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/templates/concept.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/templates/daily.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/templates/decision.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/templates/deliverable.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/templates/meeting.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/templates/person.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/templates/project.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/templates/state-moc.md +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_browser_scan.mjs +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_cdp_capture.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_contract.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_contract_criteria.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_contract_criteria_2.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_contract_ledger_scan.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_contract_provenance.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_contract_snapshot_shape.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_contract_verdict_clauses.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_driver.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_driver_accounting.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_driver_capture.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_driver_categories.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_driver_cli.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_driver_completeness.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_driver_draw.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_driver_enumeration.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_driver_gate.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_driver_night_records.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_driver_selfcheck.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_driver_transport.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_apply.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_bridge.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_canary.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_cli.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_evidence.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_gates.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_ledger.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_passes.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_plan.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_plan_aged.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_policy.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_rehearsal.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_selfcheck.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_shapes.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_mutate_shapestore.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_reconcile_append.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_reconcile_guard.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_reconcile_metrics.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_reconcile_rows.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_reconcile_steps.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_retro.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/tools/cos_retro_scanners.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/anchor.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/atomic_temp.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/attestation.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/audit.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/audit_chain.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/audit_drift.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/autolink.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/backup.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/brief.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/brief_render.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/capture.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/chunk.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/classification.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/__init__.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/common_parser.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/connect.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/connect_parser.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/cos_capture.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/cos_capture_parser.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/cos_operations.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/cos_operations_parser.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/eval.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/eval_parser.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/index_storage.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/ingest_storage.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/ingest_storage_parser.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/maintenance.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/maintenance_parser.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/navigation.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/navigation_parser.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/owner_workflow.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/owner_workflow_parser.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/presentation.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/presentation_parser.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/retrieval.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/retrieval_parser.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/update.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/update_parser.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/versioning.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_cmds/versioning_parser.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_help.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cli_render.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/config_hostpaths.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/connect.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/context.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/conventions.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/conventions_scan.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/__init__.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/_audit.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/_briefing.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/_capture.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/_capture_staging.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/_cos_facade.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/_durability.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/_health.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/_maintenance.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/_maintenance_state.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/_retrieval.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/_shared.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/_supersession.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/core/_supersession_journal.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/__init__.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_answer_consume.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_approval.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_approval_cleanup.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_attachment_acceptance.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_attachment_anchors.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_attachment_store.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_autocap.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_batch_apply.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_batches.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_behavior.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_claim_binding.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_claim_evaluation.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_claim_sweep.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_claims_state.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_constants.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_consumption.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_corrections.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_criteria.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_evidence.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_facade.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_guards.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_hold_release.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_hold_store.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_hold_undo.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_ingest_claim.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_ingest_sweep.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_ingress.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_io.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_layout.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_layout_setup.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_learning_config.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_learning_ledger.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_ledger_join.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_priority.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_proposal_maintenance.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_proposal_state.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_routing.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_run_manifest_write.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_run_migration.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_runs.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_shared.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_spine.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_standing_approval.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_status.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_taxonomy.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_version_apply.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos/_version_links.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_chips.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_corpus.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_corpus_retention.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_corpus_write.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_deploy.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_echecks.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_echecks_answers.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_echecks_answers_2.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_echecks_delivery.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_echecks_runs.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_alerts.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_checks.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_chipdraw.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_chips.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_contract.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_corpus.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_identity.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_io.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_join.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_ledger.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_metrics.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_planbinding.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_preamble.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_selfeval.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_stamps.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cos_runverify_touch.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/cowork_staging.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/dbretry.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/deliverables_absorb.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/deliverables_apply.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/deliverables_ledger.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/deliverables_materialize.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/deliverables_previous.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/deliverables_readme.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/deliverables_shelf.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/deliverables_sync.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/doctor_desktop.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/doctor_health.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/doctor_plugins.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/doctor_vendor.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/doctor_vm.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/embed.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/embed_backends.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/embed_catalog.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/embed_onnx.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/embed_qwen.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/encryption.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/exceptions_cli.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/exceptions_page.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/exceptions_render.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/exceptions_tray.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/exceptions_verify.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/__init__.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/context.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/cos.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/daily.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/deliverables.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/golden.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/graph.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/intake.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/invariants.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/orchestrator.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/organization.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/preflight.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/publish.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/remediation.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/remediation_bookkeeping.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/reporting.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/retention.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/watchdogs.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/folds/weekly.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/frontmatter.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/golden_ops.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/golden_probe.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/golden_probe_cases.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/graph_hygiene.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/graph_ops.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/graphify.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/graphify_edges.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/graphreport.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/graphreport_sections.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/graphreport_sections_2.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/healthreport.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/healthreport_sections.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/healthreport_unsigned.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/inbox.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/__init__.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_connection.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_families.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_graph.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_identity.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_lifecycle.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_models.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_planning.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_records.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_retirement.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_schema.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_search.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_settings.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_shared.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index/_zones.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index_stages/__init__.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index_stages/connection.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index_stages/diagnostics.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index_stages/duplicate_families.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index_stages/near_duplicates.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index_stages/rebuild.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index_stages/reranking.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index_stages/search.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index_stages/search_finalization.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index_stages/search_identity.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index_stages/search_ranking.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/index_stages/sync.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/__init__.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/deliverables.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/handlers/__init__.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/handlers/base.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/handlers/docx.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/handlers/email.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/handlers/html.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/handlers/image.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/handlers/pdf.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/handlers/pptx.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/handlers/tables.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/handlers/text.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/handlers/xlsx.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/handlers/zip.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/pipeline.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/pipeline_duplicates.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/pipeline_files.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/pipeline_injection.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/pipeline_nested.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/pipeline_run.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/pipeline_stages.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/tierguard.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/tierguard_verdict.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/ingest/transcript.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/init.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/init_import.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/init_samples.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/init_seed.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/init_steps.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/injection_scan.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/invariant_coverage.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/invariant_crosstier.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/invariant_deliverables.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/invariant_floors.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/invariant_ingest_guard.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/invariant_lane_health.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/invariant_reachability.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/invariant_shared.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/invariant_unsigned_notes.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/invariants.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/invariants_metrics.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/language.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/link_targets.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/lock.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_escalation.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_folds.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_folds_2.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_folds_3.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_folds_4.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_golden.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_graphfolds.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_healthlog.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_hotmd.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_invariant_fields.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_notify.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_outcomes.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_recommendations.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_retention.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_sweep.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/maintenance_watchdog.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/mcp_adapter.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/mcp_capture_verbs.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/mcp_housekeeping_verbs.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/mcp_tools/__init__.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/mcp_tools/capture.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/mcp_tools/housekeeping.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/mcp_tools/retrieval.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/multihop.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/notes.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/originals_resolve.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/overlay.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/overlay_rules.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/progress.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/projection.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/provenance.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/querylog.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/querylog_digest.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/querylog_replay.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/querylog_status.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/reexec.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/remediation_answers.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/remediation_branches.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/remediation_exceptions.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/remediation_exceptions_store.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/remediation_extract_retry.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/remediation_folds.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/remediation_questions.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/remediation_routing.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/remediation_schema.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/remediation_state.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/rerank.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/rerank_onnx.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/retrieval_ops.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/retro.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/session_hook.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/spine.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/spine_render.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/status_ops.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/update.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/update_channels_2.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/update_model.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/update_ops.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/update_plugins.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/update_state.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/vectors.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/versionlink.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/versionlink_stages.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/vm_ceiling.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/vmstaging.py +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brainiac_cli.egg-info/dependency_links.txt +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brainiac_cli.egg-info/entry_points.txt +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brainiac_cli.egg-info/requires.txt +0 -0
- {brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brainiac_cli.egg-info/top_level.txt +0 -0
|
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
|
|
|
8
8
|
# check. The IMPORT package stays `brain` and the console script stays
|
|
9
9
|
# `brain` — only the distribution/project name changes.
|
|
10
10
|
name = "brainiac-cli"
|
|
11
|
-
version = "0.20.
|
|
11
|
+
version = "0.20.34"
|
|
12
12
|
description = "Brainiac — local any-LLM second-brain core engine + brain CLI (Markdown truth, derived SQLite index)."
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
license = "Apache-2.0"
|
|
@@ -65,7 +65,9 @@ profile-a-brain/
|
|
|
65
65
|
inbox, routines copy (gitignored). The live
|
|
66
66
|
index.sqlite + audit chain live in the per-user
|
|
67
67
|
app-data dir (`config.index_dir()`); override
|
|
68
|
-
with $BRAIN_INDEX_DIR per vault
|
|
68
|
+
with $BRAIN_INDEX_DIR per vault, or move the
|
|
69
|
+
whole app-data base with $BRAIN_APP_DATA_DIR
|
|
70
|
+
(which keeps the per-vault nesting).
|
|
69
71
|
├── memory/ ← session memory: handoff.md,
|
|
70
72
|
│ hot.md, lessons.md, archive/
|
|
71
73
|
│ (host-only, never indexed — §9)
|
|
@@ -1072,11 +1074,23 @@ Obsidian "five-step retrieval cascade" rule for any harness reading this file.
|
|
|
1072
1074
|
> `brain-mcp` adapter. Full table: `docs/harness-wiring.md`.
|
|
1073
1075
|
>
|
|
1074
1076
|
> **Cowork-Windows VM (PRIMARY surface):** Cowork is Claude Desktop's Linux VM
|
|
1075
|
-
> sandbox execution mode (`docs/glossary.md`).
|
|
1076
|
-
>
|
|
1077
|
-
>
|
|
1078
|
-
> `brain
|
|
1079
|
-
>
|
|
1077
|
+
> sandbox execution mode (`docs/glossary.md`). **Two shapes exist, and which
|
|
1078
|
+
> one a given workspace runs depends on whether it has been through Closed
|
|
1079
|
+
> Stacks s07's cutover (2026-08-27 → 2026-08-30, VULN-3385).** Pre-cutover /
|
|
1080
|
+
> co-located: run `brain --role vm` (or `export BRAIN_ROLE=vm`) — the VM is
|
|
1081
|
+
> **read + draft only**, reading ONLY the published read-only snapshot in
|
|
1082
|
+
> `.brain/snapshot/` (never WAL), capturing via `brain draft-capture` into
|
|
1083
|
+
> `.brain/capture-inbox/`, never resolving a signing key; the host drains +
|
|
1084
|
+
> signs + indexes + republishes the snapshot. **Post-cutover (a relocated
|
|
1085
|
+
> workspace):** the vault is not attached to the VM's mount at all — `brain`
|
|
1086
|
+
> is not on the session's `PATH`, and there is no local snapshot to read —
|
|
1087
|
+
> every read reaches the vault only through the host `brain-mcp` broker,
|
|
1088
|
+
> which applies the same classification filter and now writes a fail-closed
|
|
1089
|
+
> audit record before returning content. The broker's ceiling for this leg is
|
|
1090
|
+
> still the same full-vault default the host itself uses (no per-caller tier
|
|
1091
|
+
> narrowing is configured), so a relocated workspace is a MITIGATION of
|
|
1092
|
+
> VULN-3385, not a closure — full posture and residual:
|
|
1093
|
+
> `docs/install/cowork.md`, `docs/security/vuln-3385-risk-reduction.md`. Install +
|
|
1080
1094
|
> per-session PATH/model re-export: `docs/cowork-windows-install.md`.
|
|
1081
1095
|
>
|
|
1082
1096
|
> **Where the kernel skills live per client:** the ten
|
|
@@ -1217,6 +1231,22 @@ The VM is a **read + draft** surface only; the host is the **only writer**.
|
|
|
1217
1231
|
atomically republishes the read-only, generation-stamped snapshot into
|
|
1218
1232
|
`.brain/snapshot/`. Only now is the note retrievable from the VM.
|
|
1219
1233
|
|
|
1234
|
+
**In-place updates (UPD-01, 2026-08-30).** A duplicate id used to be a dead
|
|
1235
|
+
end: the drain skipped it forever, silently — a Cowork session's rule update
|
|
1236
|
+
sat refused in `capture-inbox/` for 11 days while the session believed it had
|
|
1237
|
+
applied. A draft may now declare an IN-PLACE update of an existing note with
|
|
1238
|
+
two transport-only frontmatter keys: `updates: <id>` (must equal the draft's
|
|
1239
|
+
own id) and `base_sha256: <sha>` (the `sha256` that `brain get` returned for
|
|
1240
|
+
the version the author read). The drain applies it through the same signed
|
|
1241
|
+
`write_note` path ONLY when the live note is untrusted-lane-authored
|
|
1242
|
+
(`provenance.trust: untrusted`) and under `brain/` — the untrusted leg may
|
|
1243
|
+
rewrite what the untrusted lane wrote, never a host-authored note (those skip
|
|
1244
|
+
`update-needs-owner`; apply on the host with `brain write`) and never `raw/`
|
|
1245
|
+
(append-only). A base-hash mismatch skips as `stale-base` instead of
|
|
1246
|
+
clobbering a newer write. The transport keys are dropped before signing, and
|
|
1247
|
+
`brain alerts` now reports any draft still in the inbox after 48h
|
|
1248
|
+
(`stuck-drafts`) — a refusal is never silent again.
|
|
1249
|
+
|
|
1220
1250
|
### VM-request → host-drain vault provisioning (PRV-10, 2026-08-17)
|
|
1221
1251
|
|
|
1222
1252
|
A Cowork session can also create a whole NEW vault, with the same trust
|
{brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/scripts/install-brief-mac.sh
RENAMED
|
@@ -40,9 +40,14 @@ if [ -z "$LABEL" ]; then
|
|
|
40
40
|
LABEL="com.brainiac.nightly.$_h"
|
|
41
41
|
fi
|
|
42
42
|
|
|
43
|
+
# THE SAME override brain.config.nightly_plist_path reads. A test (or a
|
|
44
|
+
# sandboxed install) that redirects one must redirect both, or a test that
|
|
45
|
+
# merges a sweep dir reads, backs up and rewrites the developer's REAL plist --
|
|
46
|
+
# $HOME is not enough, because launchctl talks to the login domain by uid.
|
|
47
|
+
LAUNCH_AGENTS_DIR="${BRAIN_LAUNCH_AGENTS_DIR:-$HOME/Library/LaunchAgents}"
|
|
43
48
|
LEGACY_LABEL="com.profile-a-brain.daily-brief"
|
|
44
|
-
LEGACY_PLIST="$
|
|
45
|
-
PLIST_DST="$
|
|
49
|
+
LEGACY_PLIST="$LAUNCH_AGENTS_DIR/$LEGACY_LABEL.plist"
|
|
50
|
+
PLIST_DST="$LAUNCH_AGENTS_DIR/$LABEL.plist"
|
|
46
51
|
LOGDIR="${BRAIN_LOG_DIR:-$HOME/.brain/logs}"
|
|
47
52
|
|
|
48
53
|
# Audit signing key: the drain resolves it from the macOS Keychain AT RUNTIME
|
|
@@ -53,6 +58,12 @@ LOGDIR="${BRAIN_LOG_DIR:-$HOME/.brain/logs}"
|
|
|
53
58
|
# injected BRAIN_AUDIT_KEY_PEM (custom custody / unattended box) — and the
|
|
54
59
|
# plist is chmod 600 below either way.
|
|
55
60
|
KEYCHAIN_SERVICE="${BRAIN_AUDIT_KEYCHAIN_SERVICE:-profile-a-brain-audit-key}"
|
|
61
|
+
# `set -u` + an unset $USER is a hard abort, not a fallback: launchd, cron and
|
|
62
|
+
# any `env -i` caller hand this script an environment without USER, and both
|
|
63
|
+
# uses below took the script down at line 75 with "USER: unbound variable"
|
|
64
|
+
# BEFORE it could write a plist. Measured 2026-08-30 running
|
|
65
|
+
# `brain provision-local` end to end: wire 1 reported `init: exit 1`.
|
|
66
|
+
KEY_ACCOUNT="${USER:-$(id -un)}"
|
|
56
67
|
AUDIT_KEY="${BRAIN_AUDIT_KEY_PEM:-}"
|
|
57
68
|
|
|
58
69
|
# Managed endpoints (BRAIN_MANAGED=1) resolve the key ONLY from the OS keystore
|
|
@@ -67,14 +78,65 @@ if [ -n "${BRAIN_MANAGED:-}" ] && [ "${BRAIN_MANAGED}" != "0" ] && [ -n "$AUDIT_
|
|
|
67
78
|
fi
|
|
68
79
|
|
|
69
80
|
if [ -z "$AUDIT_KEY" ]; then
|
|
70
|
-
if ! security find-generic-password -s "$KEYCHAIN_SERVICE" -a "$
|
|
81
|
+
if ! security find-generic-password -s "$KEYCHAIN_SERVICE" -a "$KEY_ACCOUNT" >/dev/null 2>&1; then
|
|
71
82
|
echo "WARNING: No Keychain entry for '$KEYCHAIN_SERVICE'." >&2
|
|
72
83
|
echo " Captures will not be signed (drain fails closed). Run 'brain audit-key'" >&2
|
|
73
84
|
echo " (create-if-absent, never rotates) — no reinstall needed after." >&2
|
|
74
85
|
fi
|
|
75
86
|
fi
|
|
76
87
|
|
|
77
|
-
mkdir -p "$LOGDIR" "$
|
|
88
|
+
mkdir -p "$LOGDIR" "$LAUNCH_AGENTS_DIR"
|
|
89
|
+
|
|
90
|
+
# THE PLIST IS THE DURABLE HOME OF THE SWEEP LIST, for every caller.
|
|
91
|
+
# This script re-renders the whole body on every run and reinstalls when it
|
|
92
|
+
# differs, so an UNSET $BRAIN_WORKSPACE_SWEEP_DIRS used to bake an empty string
|
|
93
|
+
# -- and any `brain init --full --apply` from a bare shell (a reinstall, a
|
|
94
|
+
# second vault, an old doc, `brain update`) silently wiped a list somebody had
|
|
95
|
+
# configured. Unset now means "keep what is installed"; an explicitly SET value
|
|
96
|
+
# still wins, including an explicit empty one (the operator's intent).
|
|
97
|
+
if [ -n "${BRAIN_WORKSPACE_SWEEP_DIRS+set}" ]; then
|
|
98
|
+
SWEEP_DIRS="$BRAIN_WORKSPACE_SWEEP_DIRS"
|
|
99
|
+
elif [ -f "$PLIST_DST" ]; then
|
|
100
|
+
SWEEP_DIRS="$(/usr/libexec/PlistBuddy -c \
|
|
101
|
+
"Print :EnvironmentVariables:BRAIN_WORKSPACE_SWEEP_DIRS" \
|
|
102
|
+
"$PLIST_DST" 2>/dev/null || true)"
|
|
103
|
+
else
|
|
104
|
+
SWEEP_DIRS=""
|
|
105
|
+
fi
|
|
106
|
+
# EVERY value substituted into the plist below goes through this, because each
|
|
107
|
+
# one is escaped TWICE over and both stages are load-bearing.
|
|
108
|
+
#
|
|
109
|
+
# 1. The value lands inside an XML <string>, so `&` and `<` in a folder name
|
|
110
|
+
# would render a plist nothing can parse -- and the PlistBuddy round-trip
|
|
111
|
+
# above reads the value back out unescaped, so it would corrupt a little
|
|
112
|
+
# more on every run.
|
|
113
|
+
# 2. ...and THEN it becomes a sed REPLACEMENT, where `\`, `&` and the `|`
|
|
114
|
+
# delimiter are metacharacters of their own. A bare `&` in a replacement
|
|
115
|
+
# means "the whole match", so the `&` stage 1 just wrote as `&`
|
|
116
|
+
# re-inserts the literal placeholder text: probed 2026-08-30,
|
|
117
|
+
# BRAIN_WORKSPACE_SWEEP_DIRS=/tmp/A&B<C rendered as
|
|
118
|
+
# `/tmp/ASWEEP_DIRS_PLACEHOLDERamp;BSWEEP_DIRS_PLACEHOLDERlt;C`, and
|
|
119
|
+
# VAULT=/tmp/A&B<C rendered `<string>/tmp/AVAULT_PATHB<C</string>` --- an
|
|
120
|
+
# unparseable plist from an ORDINARY path (`R&D`, `Smith & Co`).
|
|
121
|
+
#
|
|
122
|
+
# It is a function because doing it for the sweep list alone left the two
|
|
123
|
+
# substitutions directly below it raw (probed 2026-08-30). $AUDIT_KEY needs no
|
|
124
|
+
# metacharacter escaping -- base64 and the PEM header contain none of \ & | < --
|
|
125
|
+
# and $LABEL is `com.brainiac.nightly.<hex8>` by construction. It is NOT used
|
|
126
|
+
# on $AUDIT_KEY, though: a real PEM carries embedded NEWLINES (multi-line,
|
|
127
|
+
# `-----BEGIN...-----\n<body>\n-----END...-----\n`), and a `sed -e` REPLACEMENT
|
|
128
|
+
# cannot hold a raw newline without a `\`-continuation before each one -- an
|
|
129
|
+
# unescaped one is a parse error, not silent corruption. AUDIT_KEY gets its own
|
|
130
|
+
# newline-safe substitution below instead of going through this sed pipeline.
|
|
131
|
+
xml_sed_escape() {
|
|
132
|
+
printf '%s' "$1" | sed -e 's/&/\&/g' -e 's/</\</g' \
|
|
133
|
+
| sed -e 's/[\\&|]/\\&/g'
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
SWEEP_DIRS_SED="$(xml_sed_escape "$SWEEP_DIRS")"
|
|
137
|
+
VAULT_SED="$(xml_sed_escape "$VAULT")"
|
|
138
|
+
HOME_SED="$(xml_sed_escape "$HOME")"
|
|
139
|
+
SCRIPTS_SED="$(xml_sed_escape "$SCRIPTS")"
|
|
78
140
|
|
|
79
141
|
# Render the plist to a scratch file first so we can diff against whatever is
|
|
80
142
|
# already installed — the nightly-diff contract (docs/install/plugin-distribution.md
|
|
@@ -84,18 +146,60 @@ PLIST_NEW="$(mktemp "${TMPDIR:-/tmp}/brain-brief-mac.plist.XXXXXX")"
|
|
|
84
146
|
trap 'rm -f "$PLIST_NEW"' EXIT
|
|
85
147
|
|
|
86
148
|
sed -e "s|LABEL_PLACEHOLDER|$LABEL|g" \
|
|
87
|
-
-e "s|SCRIPTS_DIR|$
|
|
88
|
-
-e "s|VAULT_PATH|$
|
|
89
|
-
-e "s|HOME_DIR|$
|
|
90
|
-
-e "s|
|
|
91
|
-
-e "s|SWEEP_DIRS_PLACEHOLDER|${BRAIN_WORKSPACE_SWEEP_DIRS:-}|g" \
|
|
149
|
+
-e "s|SCRIPTS_DIR|$SCRIPTS_SED|g" \
|
|
150
|
+
-e "s|VAULT_PATH|$VAULT_SED|g" \
|
|
151
|
+
-e "s|HOME_DIR|$HOME_SED|g" \
|
|
152
|
+
-e "s|SWEEP_DIRS_PLACEHOLDER|$SWEEP_DIRS_SED|g" \
|
|
92
153
|
"$PLIST_SRC" > "$PLIST_NEW"
|
|
93
154
|
|
|
155
|
+
# AUDIT_KEY_PEM_PLACEHOLDER: substituted OUTSIDE the sed pipeline above with
|
|
156
|
+
# awk, whose replacement text is an ordinary string (no per-`-e`-argument
|
|
157
|
+
# newline restriction) rather than a sed script fragment --- the same
|
|
158
|
+
# multi-line value that breaks `sed -e "s|X|$AUDIT_KEY|g"` (probed 2026-08-31,
|
|
159
|
+
# running `provision-local` end to end with a synthetic Ed25519 test key:
|
|
160
|
+
# "sed: 1: ...: unescaped newline inside substitute pattern") assigns straight
|
|
161
|
+
# through `ENVIRON["AUDIT_KEY"]` here. Trailing newline(s) are stripped by the
|
|
162
|
+
# `$( )` around printf below (command substitution always strips them),
|
|
163
|
+
# matching what the OLD single-line sed substitution effectively produced too.
|
|
164
|
+
# NOT guarded on a non-empty $AUDIT_KEY. Managed mode (line 74) and a box with
|
|
165
|
+
# no key both set it to "", and the placeholder MUST still be replaced --- by
|
|
166
|
+
# nothing. A guard here skipped the awk and left the literal string
|
|
167
|
+
# `AUDIT_KEY_PEM_PLACEHOLDER` baked into the plist as BRAIN_AUDIT_KEY_PEM
|
|
168
|
+
# (probed 2026-08-31 against the pre-change script, which rendered
|
|
169
|
+
# `<string></string>`), handing every managed endpoint a garbage PEM instead of
|
|
170
|
+
# the empty value that makes the runtime fall back to the Keychain. `split("")`
|
|
171
|
+
# yields no fields, so `pem[1]` is "" and the placeholder collapses to nothing.
|
|
172
|
+
AUDIT_KEY_TRIMMED="$(printf '%s' "$AUDIT_KEY")"
|
|
173
|
+
AUDIT_KEY="$AUDIT_KEY_TRIMMED" awk '
|
|
174
|
+
function xml_awk_escape(s) {
|
|
175
|
+
# Same two-char XML entity escape as xml_sed_escape above --- `&`
|
|
176
|
+
# first, so `<` does not re-encode the `&` that step just wrote.
|
|
177
|
+
# No sub()/gsub()-replacement-side "&" concern here: this gsub
|
|
178
|
+
# RUNS the escape, it is not used as another calls REPLACEMENT
|
|
179
|
+
# argument (that is the substr()-based split below, precisely to
|
|
180
|
+
# avoid needing a second round of escaping on top of this one).
|
|
181
|
+
gsub(/&/, "\\&", s); gsub(/</, "\\<", s); return s
|
|
182
|
+
}
|
|
183
|
+
{
|
|
184
|
+
pos = index($0, "AUDIT_KEY_PEM_PLACEHOLDER")
|
|
185
|
+
if (!pos) { print; next }
|
|
186
|
+
n = split(ENVIRON["AUDIT_KEY"], pem, "\n")
|
|
187
|
+
prefix = substr($0, 1, pos - 1)
|
|
188
|
+
suffix = substr($0, pos + length("AUDIT_KEY_PEM_PLACEHOLDER"))
|
|
189
|
+
# substr()/printf concatenation only, below --- never sub()/gsub()
|
|
190
|
+
# with pem[i] as the REPLACEMENT argument, which would reinterpret
|
|
191
|
+
# any literal "&" the escape above just wrote as "insert match".
|
|
192
|
+
printf "%s%s", prefix, xml_awk_escape(pem[1])
|
|
193
|
+
for (i = 2; i <= n; i++) printf "\n%s", xml_awk_escape(pem[i])
|
|
194
|
+
print suffix
|
|
195
|
+
}
|
|
196
|
+
' "$PLIST_NEW" > "$PLIST_NEW.awk" && mv "$PLIST_NEW.awk" "$PLIST_NEW"
|
|
197
|
+
|
|
94
198
|
# ponytail: real launchctl talks to the login launchd domain by uid, not by
|
|
95
199
|
# $HOME — a sandboxed HOME does NOT sandbox launchctl. BRAIN_LAUNCHD_DRY_RUN=1
|
|
96
200
|
# (or a non-default HOME, detected below) skips the real bootstrap/load calls
|
|
97
201
|
# so test/sandbox runs never touch the real user's launchd domain.
|
|
98
|
-
if [ -z "${BRAIN_LAUNCHD_DRY_RUN:-}" ] && [ "$HOME" != "$(eval echo ~"$
|
|
202
|
+
if [ -z "${BRAIN_LAUNCHD_DRY_RUN:-}" ] && [ "$HOME" != "$(eval echo ~"$KEY_ACCOUNT")" ]; then
|
|
99
203
|
BRAIN_LAUNCHD_DRY_RUN=1
|
|
100
204
|
fi
|
|
101
205
|
|
|
@@ -140,10 +244,13 @@ echo "✓ Installed: $LABEL (hourly umbrella, vault: $VAULT)"
|
|
|
140
244
|
# vault in ~/.brainiac/workspaces.json, so re-running this installer for a
|
|
141
245
|
# second vault just refreshes the same host-level agent. Weekly Sun 08:00.
|
|
142
246
|
SYNTH_SRC="$SCRIPTS/brain-synthesis-mac.plist"
|
|
143
|
-
SYNTH_DST="$
|
|
247
|
+
SYNTH_DST="$LAUNCH_AGENTS_DIR/com.brainiac.synthesis.plist"
|
|
144
248
|
if [ -f "$SYNTH_SRC" ]; then
|
|
145
249
|
SYNTH_NEW="$(mktemp "${TMPDIR:-/tmp}/brain-synthesis-mac.plist.XXXXXX")"
|
|
146
|
-
|
|
250
|
+
# Same two-stage escaping as the nightly block above: a raw $SCRIPTS or
|
|
251
|
+
# $HOME carrying `&`, `<` or `|` corrupts this plist too (see the worked
|
|
252
|
+
# example at the top of the nightly substitution).
|
|
253
|
+
sed -e "s|SCRIPTS_DIR|$SCRIPTS_SED|g" -e "s|HOME_DIR|$HOME_SED|g" \
|
|
147
254
|
"$SYNTH_SRC" > "$SYNTH_NEW"
|
|
148
255
|
if ! cmp -s "$SYNTH_NEW" "$SYNTH_DST" 2>/dev/null; then
|
|
149
256
|
cp "$SYNTH_NEW" "$SYNTH_DST"
|
{brainiac_cli-0.20.32 → brainiac_cli-0.20.34}/src/brain/_assets/scripts/vm-boundary-probe.sh
RENAMED
|
@@ -38,7 +38,13 @@ export PATH="$BRAIN_RUNTIME_DIR:$PATH"
|
|
|
38
38
|
# refusal, whatever the exit code says.
|
|
39
39
|
REFUSAL_RE='is host-broker only|RoleError|role=vm is read\+draft'
|
|
40
40
|
|
|
41
|
-
BREACHED=0 # the boundary itself failed
|
|
41
|
+
BREACHED=0 # the boundary itself failed — the VM did something it must not
|
|
42
|
+
DEGRADED=0 # section D only: the VM cannot do something it legitimately may.
|
|
43
|
+
# Counted SEPARATELY and never printed as BREACHED. These are
|
|
44
|
+
# opposite failures with opposite remediations, and summing them
|
|
45
|
+
# is how a real breach eventually gets ignored (2026-08-30: a
|
|
46
|
+
# cut-over workspace with no local snapshot printed BREACHED
|
|
47
|
+
# while all 27 containment probes passed).
|
|
42
48
|
INVALID=0 # this script asked the wrong question
|
|
43
49
|
OBSERVED=0 # true-but-expected conditions (see section B)
|
|
44
50
|
say(){ echo "$@"; }
|
|
@@ -266,16 +272,53 @@ case "$KEY_OUT" in
|
|
|
266
272
|
esac
|
|
267
273
|
say ""
|
|
268
274
|
|
|
269
|
-
say "### D. the
|
|
275
|
+
say "### D. the things a VM legitimately CAN do must still work"
|
|
270
276
|
say "-- snapshot read"
|
|
277
|
+
# A LOCAL snapshot is no longer the VM's read surface. s06b moved all 14 Cowork
|
|
278
|
+
# skills onto the broker's MCP tools, and s07 ruled `snapshot/` GOES because it
|
|
279
|
+
# carries 3105 non-empty MNPI note bodies — publishing one back onto the mount
|
|
280
|
+
# would re-open the very finding the cutover closed. So its ABSENCE is the fix
|
|
281
|
+
# working, and this probe must not read as a capability loss. Where no snapshot
|
|
282
|
+
# is present the read surface is the broker, which this script cannot exercise.
|
|
271
283
|
# --no-rerank (RK-02 caller policy, 2026-08-04): a liveness check on the
|
|
272
284
|
# snapshot read path — it discards stdout entirely, so paying for BR-03's
|
|
273
285
|
# default-on cross-encoder here buys literally nothing.
|
|
274
|
-
|
|
286
|
+
# ASK `brain status` ONCE, AND KEEP ITS EXIT CODE. Until 2026-08-30 this line
|
|
287
|
+
# read `brain status` inside the test itself, so a status that FAILED --- no
|
|
288
|
+
# engine on PATH, a role refusal, a broken index --- produced empty output and
|
|
289
|
+
# was scored identically to a real absence. That is the "clean because the
|
|
290
|
+
# input was empty" shape the rest of this change set exists to remove, sitting
|
|
291
|
+
# inside the script that reports it.
|
|
292
|
+
_status_out="$(brain status 2>/dev/null)" && _status_rc=0 || _status_rc=$?
|
|
293
|
+
_snap_line="$(printf '%s\n' "$_status_out" | sed -n 's/^snapshot:[[:space:]]*//p')"
|
|
294
|
+
# THREE WAYS TO KNOW NOTHING, AND ONLY ONE OF THEM IS THE DESIGN WORKING.
|
|
295
|
+
# A status that FAILED, a status that answered but never mentions a snapshot,
|
|
296
|
+
# and a status that says `absent` all produced the same empty string once. Only
|
|
297
|
+
# the third is the post-cutover N/A. The first two are the probe failing to
|
|
298
|
+
# ask, and reporting them as N/A is the "clean because the input was empty"
|
|
299
|
+
# all-clear this script exists to catch elsewhere. Both earlier shapes were
|
|
300
|
+
# reproduced against stub interpreters before this was written.
|
|
301
|
+
if [ "$_status_rc" -ne 0 ] || [ -z "$_status_out" ]; then
|
|
302
|
+
say " INCONCLUSIVE — \`brain status\` did not answer (rc=$_status_rc), so"
|
|
303
|
+
say " whether a snapshot is present was never established."
|
|
304
|
+
say " This is NOT the post-cutover N/A below; it is the"
|
|
305
|
+
say " probe failing to ask."
|
|
306
|
+
INVALID=$((INVALID+1))
|
|
307
|
+
elif [ -z "$_snap_line" ]; then
|
|
308
|
+
say " INCONCLUSIVE — \`brain status\` answered but reported no \`snapshot:\`"
|
|
309
|
+
say " line at all, so this probe learned nothing. An older"
|
|
310
|
+
say " or differently-configured engine reads this way; it is"
|
|
311
|
+
say " not evidence that no snapshot exists."
|
|
312
|
+
INVALID=$((INVALID+1))
|
|
313
|
+
elif [ -z "$(printf '%s\n' "$_snap_line" | grep -v '^absent')" ]; then
|
|
314
|
+
say " N/A — no local snapshot on this mount, which is the post-cutover"
|
|
315
|
+
say " design (it carries MNPI bodies). The VM reads through the"
|
|
316
|
+
say " broker's MCP tools instead; exercise that from the session."
|
|
317
|
+
elif brain search "${VM_PROBE_TERM:-project}" --no-rerank --json >/dev/null 2>&1; then
|
|
275
318
|
say " PASS — snapshot search returned"
|
|
276
319
|
else
|
|
277
|
-
say "
|
|
278
|
-
|
|
320
|
+
say " DEGRADED — a snapshot is present but the VM cannot read it"
|
|
321
|
+
DEGRADED=$((DEGRADED+1))
|
|
279
322
|
fi
|
|
280
323
|
say "-- proposal drop (unsigned, into a dir \`sync\` never reads)"
|
|
281
324
|
# This leaves a real file in the drop dir for as long as it takes to delete it.
|
|
@@ -288,7 +331,7 @@ DROP_OUT="$(printf -- '---\nid: %s\ntitle: "VM boundary probe — safe to reject
|
|
|
288
331
|
printf '%s\n' "$DROP_OUT" | sed 's/^/ | /'
|
|
289
332
|
case "$DROP_OUT" in
|
|
290
333
|
*dropped*) say " PASS — unsigned drop accepted, nothing signed";;
|
|
291
|
-
*) say "
|
|
334
|
+
*) say " DEGRADED — the VM cannot even drop a proposal"; DEGRADED=$((DEGRADED+1));;
|
|
292
335
|
esac
|
|
293
336
|
# Delete the file the engine actually reported, not one this script guesses at
|
|
294
337
|
# — a guessed path that has drifted cleans up nothing and says it did.
|
|
@@ -296,25 +339,33 @@ PROBE_FILE="$(printf '%s' "$DROP_OUT" | sed -n 's/.*"proposal"[[:space:]]*:[[:sp
|
|
|
296
339
|
[ -n "$PROBE_FILE" ] || PROBE_FILE="$BRAIN_RUNTIME_DIR/cos/drop/proposal-drop/$PROBE_ID.md"
|
|
297
340
|
rm -f "$PROBE_FILE" 2>/dev/null
|
|
298
341
|
if [ -e "$PROBE_FILE" ]; then
|
|
299
|
-
say "
|
|
300
|
-
say "
|
|
301
|
-
|
|
342
|
+
say " DEGRADED — could not clean up $PROBE_FILE; delete it before the next"
|
|
343
|
+
say " broker fold or it becomes an owner-batch question."
|
|
344
|
+
say " (A Cowork shell has deletion blocked by policy, so this"
|
|
345
|
+
say " is expected there — remove it from the host instead.)"
|
|
346
|
+
DEGRADED=$((DEGRADED+1))
|
|
302
347
|
else
|
|
303
348
|
say " cleanup: probe drop removed ($PROBE_FILE)"
|
|
304
349
|
fi
|
|
305
350
|
say ""
|
|
306
351
|
|
|
307
352
|
say "=== SUMMARY ==="
|
|
308
|
-
say " boundary failures : $BREACHED"
|
|
353
|
+
say " boundary failures : $BREACHED (the VM did something it must not)"
|
|
354
|
+
say " degraded : $DEGRADED (section D: the VM cannot do something it may)"
|
|
309
355
|
say " invalid probes : $INVALID (this script asked the wrong question)"
|
|
310
356
|
say " observations : $OBSERVED (host-private bytes readable over the mount)"
|
|
311
|
-
if [ $BREACHED -
|
|
312
|
-
say "=== VERDICT:
|
|
313
|
-
exit
|
|
357
|
+
if [ $BREACHED -gt 0 ]; then
|
|
358
|
+
say "=== VERDICT: BREACHED — $BREACHED probe(s) failed ==="
|
|
359
|
+
exit 1
|
|
314
360
|
fi
|
|
315
|
-
if [ $
|
|
361
|
+
if [ $INVALID -gt 0 ]; then
|
|
316
362
|
say "=== VERDICT: INCONCLUSIVE — $INVALID probe(s) never reached the gate ==="
|
|
317
363
|
exit 2
|
|
318
364
|
fi
|
|
319
|
-
|
|
320
|
-
|
|
365
|
+
if [ $DEGRADED -gt 0 ]; then
|
|
366
|
+
say "=== VERDICT: BOUNDARY INTACT, DEGRADED — $DEGRADED capability probe(s) failed ==="
|
|
367
|
+
say " The containment held. Something the VM is ALLOWED to do did not work."
|
|
368
|
+
exit 3
|
|
369
|
+
fi
|
|
370
|
+
say "=== VERDICT: BOUNDARY INTACT ==="
|
|
371
|
+
exit 0
|
|
@@ -69,6 +69,14 @@ UPDATE_STATE_MAX_AGE_DAYS = 7
|
|
|
69
69
|
# A weekly task that has not succeeded in longer than this has missed a run.
|
|
70
70
|
SYNTHESIS_STALE_DAYS = 8
|
|
71
71
|
|
|
72
|
+
# The hourly nightly drains capture drafts on every firing, so a draft still
|
|
73
|
+
# sitting in the inbox after this many hours has been REFUSED by the drain
|
|
74
|
+
# (duplicate-id, stale-base, update-needs-owner, ...) and will never promote
|
|
75
|
+
# on its own. Until 2026-08-30 nothing reported this: a 19-Aug rule update
|
|
76
|
+
# sat refused for 11 days while the session that staged it believed it had
|
|
77
|
+
# applied (UPD-01).
|
|
78
|
+
STUCK_DRAFT_HOURS = 48
|
|
79
|
+
|
|
72
80
|
# The feed's `findings[].key` vocabulary is closed (see maintenance_notify.py:
|
|
73
81
|
# "blocked", "synthesis-watchdog", "trend:<metric>", "invariant:<metric>",
|
|
74
82
|
# "branch-escalate:<branch>", "ingest_quarantine*", ...). The dir is on the
|
|
@@ -181,6 +189,22 @@ def synthesis_alerts(home: Path, today: datetime.date) -> list[dict[str, str]]:
|
|
|
181
189
|
return out
|
|
182
190
|
|
|
183
191
|
|
|
192
|
+
def wiring_alerts() -> list[dict[str, str]]:
|
|
193
|
+
"""The ONE push channel for ``doctor``'s non-gating "Vault wiring" row
|
|
194
|
+
(DOC-01): ``brain doctor`` reports it, but nothing was watching it
|
|
195
|
+
between session starts before this. ``check_vault_wiring`` resolves the
|
|
196
|
+
registry from ``$BRAINIAC_HOME`` itself and stays at the same file-reads
|
|
197
|
+
budget (no ``maintain*``/``notify-sent`` file touched), so this needs no
|
|
198
|
+
vault list handed in and covers every registered vault in one line."""
|
|
199
|
+
from . import doctor as _doctor
|
|
200
|
+
from .doctor_wiring import check_vault_wiring
|
|
201
|
+
|
|
202
|
+
warn = sum(1 for row in check_vault_wiring() if row["status"] == _doctor.WARN)
|
|
203
|
+
if not warn:
|
|
204
|
+
return []
|
|
205
|
+
return [_alert("vault-wiring", f"vault wiring: {warn} warn — run `brain doctor`")]
|
|
206
|
+
|
|
207
|
+
|
|
184
208
|
# ---------------------------------------------------------------------------
|
|
185
209
|
# Per-vault sources — on the shared mount, so BOTH roles read them
|
|
186
210
|
# ---------------------------------------------------------------------------
|
|
@@ -201,9 +225,45 @@ def vault_alerts(
|
|
|
201
225
|
|
|
202
226
|
out += exceptions_alerts(vault, today, name, role=role)
|
|
203
227
|
out += degradation_alerts(vault, today, name)
|
|
228
|
+
if role != "vm":
|
|
229
|
+
# Host-only: the capture inbox lives on the host's filesystem
|
|
230
|
+
# (closed-stacks), and the fix the alert names (`brain sync`,
|
|
231
|
+
# `brain write`) is a host action anyway. The VM leg does not read
|
|
232
|
+
# this, and a VM zero would be a fabricated one.
|
|
233
|
+
out += stuck_draft_alerts(vault, name)
|
|
204
234
|
return out
|
|
205
235
|
|
|
206
236
|
|
|
237
|
+
def stuck_draft_alerts(vault: Path, name: str) -> list[dict[str, str]]:
|
|
238
|
+
"""Capture drafts the drain keeps refusing (UPD-01). Pure mtime reads."""
|
|
239
|
+
import time
|
|
240
|
+
|
|
241
|
+
cutoff = time.time() - STUCK_DRAFT_HOURS * 3600
|
|
242
|
+
stuck: list[str] = []
|
|
243
|
+
for d in (_config.capture_inbox_dir(vault), vault / ".brain" / "drafts"):
|
|
244
|
+
try:
|
|
245
|
+
entries = sorted(d.glob("*.md"))
|
|
246
|
+
except OSError:
|
|
247
|
+
continue
|
|
248
|
+
for f in entries:
|
|
249
|
+
try:
|
|
250
|
+
if f.stat().st_mtime < cutoff:
|
|
251
|
+
# Same posture as _FINDING_KEY_RE: a draft filename is
|
|
252
|
+
# untrusted-leg-authored and this line is rendered into
|
|
253
|
+
# the host SessionStart context — never verbatim.
|
|
254
|
+
stuck.append(re.sub(r"[^A-Za-z0-9._-]", "_", f.name)[:64])
|
|
255
|
+
except OSError:
|
|
256
|
+
continue
|
|
257
|
+
if not stuck:
|
|
258
|
+
return []
|
|
259
|
+
shown = ", ".join(stuck[:3]) + ("…" if len(stuck) > 3 else "")
|
|
260
|
+
return [_alert(
|
|
261
|
+
"stuck-drafts",
|
|
262
|
+
f"{len(stuck)} capture draft(s) stuck >{STUCK_DRAFT_HOURS}h ({shown}) — "
|
|
263
|
+
"run `brain sync` and read the skip reasons; an `update-needs-owner` "
|
|
264
|
+
"refusal applies with `brain write`", name)]
|
|
265
|
+
|
|
266
|
+
|
|
207
267
|
def exceptions_alerts(
|
|
208
268
|
vault: Path, today: datetime.date, name: str, *, role: str,
|
|
209
269
|
) -> list[dict[str, str]]:
|
|
@@ -384,6 +444,7 @@ def collect(
|
|
|
384
444
|
alerts += update_alerts(home, today)
|
|
385
445
|
alerts += staging_alerts(home)
|
|
386
446
|
alerts += synthesis_alerts(home, today)
|
|
447
|
+
alerts += wiring_alerts()
|
|
387
448
|
vaults = host_vaults(home)
|
|
388
449
|
if not vaults and vault:
|
|
389
450
|
vaults = [Path(vault)]
|
|
@@ -10,6 +10,8 @@ from __future__ import annotations
|
|
|
10
10
|
|
|
11
11
|
import re
|
|
12
12
|
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
from .cowork_staging import staging_root
|
|
13
15
|
from typing import Any
|
|
14
16
|
|
|
15
17
|
#: What an undeclared key renders as when the registry cannot be loaded AT
|
|
@@ -69,16 +71,44 @@ def _untriaged(key: str) -> bool:
|
|
|
69
71
|
return True
|
|
70
72
|
|
|
71
73
|
|
|
72
|
-
def
|
|
74
|
+
def _root_for(entry: dict, raw: str) -> Path:
|
|
75
|
+
"""The `.brain` staging root this registry row actually stages into.
|
|
76
|
+
|
|
77
|
+
RELOCATION-AWARE since 2026-08-31. This read derived the root as
|
|
78
|
+
`<vault>/.brain`, which is right only while the vault sits inside the
|
|
79
|
+
workspace. On a RELOCATED vault the engine is staged at
|
|
80
|
+
`<workspace>/vault/.brain`, so the old derivation read the vault-side
|
|
81
|
+
LEFTOVER --- frozen at whatever version was current when the vault moved
|
|
82
|
+
--- and reported the workspace permanently stale. `brain update` could
|
|
83
|
+
never clear it: it writes the workspace side.
|
|
84
|
+
|
|
85
|
+
Measured 2026-08-31, minutes after the 0.20.33 restage: the staged engine
|
|
86
|
+
on disk and `brain doctor` both read 0.20.33 while this digest cried
|
|
87
|
+
0.20.32 for both live vaults. Sixth relocation-unaware surface, and the
|
|
88
|
+
first on the digest every session is told to read FIRST. The three doctor
|
|
89
|
+
rows before it went SILENT, which is the milder failure; a permanent false
|
|
90
|
+
alarm teaches sessions to ignore the channel.
|
|
91
|
+
|
|
92
|
+
Never raises: `alerts` reporting nothing is the one outcome this module may
|
|
93
|
+
never produce, so an unresolvable path falls back to the co-located root.
|
|
94
|
+
"""
|
|
95
|
+
try:
|
|
96
|
+
return staging_root(raw, entry.get("workspace_path") or None)
|
|
97
|
+
except (OSError, ValueError):
|
|
98
|
+
return Path(raw) / ".brain"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _staged_versions(root: Path) -> set[str]:
|
|
73
102
|
"""Every version stamp a staged Cowork workspace carries, as file reads.
|
|
74
103
|
|
|
104
|
+
Takes the `.brain` STAGING ROOT, not the vault --- see :func:`_root_for`.
|
|
75
105
|
Two stamp kinds exist: the staged engine's ``_version.py`` and the
|
|
76
106
|
``brain-linux-*.version`` sidecars beside the VM ELFs. A missing stamp
|
|
77
107
|
contributes nothing — absence means "never staged", which is not
|
|
78
108
|
staleness."""
|
|
79
109
|
found: set[str] = set()
|
|
80
110
|
try:
|
|
81
|
-
text = (
|
|
111
|
+
text = (root / "engine" / "brain" / "_version.py").read_text(
|
|
82
112
|
encoding="utf-8")
|
|
83
113
|
m = re.search(r'__version__\s*=\s*"([^"]+)"', text)
|
|
84
114
|
if m:
|
|
@@ -86,7 +116,7 @@ def _staged_versions(vault: Path) -> set[str]:
|
|
|
86
116
|
except OSError:
|
|
87
117
|
pass
|
|
88
118
|
try:
|
|
89
|
-
for stamp in sorted((
|
|
119
|
+
for stamp in sorted((root / "bin").glob("brain-linux-*.version")):
|
|
90
120
|
v = stamp.read_text(encoding="utf-8").strip()
|
|
91
121
|
if v:
|
|
92
122
|
found.add(v)
|
|
@@ -128,7 +158,7 @@ def staging_alerts(home: Path) -> list[dict[str, str]]:
|
|
|
128
158
|
if not raw or raw in seen:
|
|
129
159
|
continue
|
|
130
160
|
seen.add(raw)
|
|
131
|
-
stale = sorted(_staged_versions(
|
|
161
|
+
stale = sorted(_staged_versions(_root_for(entry, raw)) - {running})
|
|
132
162
|
if stale:
|
|
133
163
|
out.append(_alert(
|
|
134
164
|
"staging:stale",
|
|
@@ -118,10 +118,15 @@ def _json_default(o: Any) -> Any:
|
|
|
118
118
|
|
|
119
119
|
def _emit(obj: Any, as_json: bool, human: str | None = None) -> None:
|
|
120
120
|
if as_json:
|
|
121
|
-
json.
|
|
122
|
-
sys.stdout.write("\n")
|
|
121
|
+
text = json.dumps(obj, ensure_ascii=False, indent=2, default=_json_default) + "\n"
|
|
123
122
|
else:
|
|
124
|
-
|
|
123
|
+
text = (human if human is not None else str(obj)) + "\n"
|
|
124
|
+
# Gated content is HELD until its SEC-06 record is written; everything else
|
|
125
|
+
# streams as before. See brain.cli_read_record for why.
|
|
126
|
+
from . import cli_read_record as _crr
|
|
127
|
+
|
|
128
|
+
if not _crr.hold(text):
|
|
129
|
+
sys.stdout.write(text)
|
|
125
130
|
|
|
126
131
|
|
|
127
132
|
def _excluded_note(res: dict[str, Any]) -> str:
|
|
@@ -440,29 +445,24 @@ def _main(argv: list[str] | None = None) -> int:
|
|
|
440
445
|
# a stale count would be attributed to this command. One-shot in the CLI,
|
|
441
446
|
# load-bearing in the long-lived MCP server.
|
|
442
447
|
_egress_reset.take_tally()
|
|
448
|
+
from . import cli_read_record as _crr
|
|
449
|
+
|
|
450
|
+
_crr.begin()
|
|
443
451
|
started = _time.perf_counter()
|
|
444
452
|
try:
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
#
|
|
448
|
-
#
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
cmd=args.cmd,
|
|
459
|
-
max_tier=getattr(args, "max_tier", None),
|
|
460
|
-
tally=_egress.take_tally(),
|
|
461
|
-
latency_ms=(_time.perf_counter() - started) * 1000.0,
|
|
462
|
-
)
|
|
463
|
-
except Exception: # never let logging fail a read
|
|
464
|
-
pass
|
|
465
|
-
|
|
453
|
+
rc = group.run(args, ctx)
|
|
454
|
+
except BaseException:
|
|
455
|
+
# A command that raised still read what it read, so the record is still
|
|
456
|
+
# owed. Its held output is dropped: the caller above renders the error.
|
|
457
|
+
_crr.settle_for(core, role, args, started)
|
|
458
|
+
raise
|
|
459
|
+
withhold, held = _crr.settle_for(core, role, args, started)
|
|
460
|
+
if withhold:
|
|
461
|
+
print(_crr.refusal(args.cmd), file=sys.stderr)
|
|
462
|
+
return _crr.EXIT_RECORD_FAILED
|
|
463
|
+
for chunk in held:
|
|
464
|
+
sys.stdout.write(chunk)
|
|
465
|
+
return rc
|
|
466
466
|
|
|
467
467
|
|
|
468
468
|
# The --help epilog text lives in cli_help.py and the read-surface render
|
|
@@ -8,7 +8,7 @@ from .. import classification as cls
|
|
|
8
8
|
def _add_draft_capture(sub) -> None:
|
|
9
9
|
sp = sub.add_parser(
|
|
10
10
|
"draft-capture",
|
|
11
|
-
help="VM-side capture: stage a candidate note as a plain DRAFT (no sign, no index, no WAL) for the host to drain later",
|
|
11
|
+
help="VM-side capture: stage a candidate note as a plain DRAFT (no sign, no index, no WAL) for the host to drain later. To UPDATE an existing note in place (UPD-01), give the draft the SAME id plus two frontmatter keys: `updates: <id>` and `base_sha256: <the sha256 `brain get` returned for the version you read>` — accepted only when the live note is untrusted-lane-authored and under brain/; a host-authored target needs the owner (`brain write`), and a base mismatch refuses as stale-base",
|
|
12
12
|
)
|
|
13
13
|
sp.add_argument(
|
|
14
14
|
"--id", default=None, help="note id (default: from frontmatter or content hash)"
|