brainiac-cli 0.20.45__tar.gz → 0.20.46__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.
Files changed (360) hide show
  1. {brainiac_cli-0.20.45/src/brainiac_cli.egg-info → brainiac_cli-0.20.46}/PKG-INFO +7 -5
  2. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/pyproject.toml +24 -4
  3. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_version.py +1 -1
  4. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/audit_drift.py +2 -1
  5. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/_maintenance_state.py +2 -1
  6. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/exceptions_page.py +3 -2
  7. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/exceptions_verify.py +3 -2
  8. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/intake.py +5 -5
  9. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/graph_ops.py +3 -2
  10. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/deliverables.py +2 -1
  11. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/concealment_pdf.py +4 -1
  12. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/pipeline_files.py +8 -3
  13. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/interview.py +2 -1
  14. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/invariant_coverage.py +2 -1
  15. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_notify.py +2 -1
  16. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/overlay_generated.py +2 -1
  17. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/provision.py +2 -2
  18. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/remediation_exceptions_store.py +2 -1
  19. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/remediation_state.py +2 -1
  20. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/session_hook_settings.py +2 -1
  21. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/update_channels.py +7 -7
  22. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/vmstaging.py +22 -6
  23. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/workspaces.py +2 -1
  24. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46/src/brainiac_cli.egg-info}/PKG-INFO +7 -5
  25. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brainiac_cli.egg-info/requires.txt +12 -2
  26. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/LICENSE +0 -0
  27. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/MANIFEST.in +0 -0
  28. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/README.md +0 -0
  29. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/setup.cfg +0 -0
  30. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/__init__.py +0 -0
  31. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/__main__.py +0 -0
  32. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/AGENTS.md +0 -0
  33. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/assets/graph-explorer-template.html +0 -0
  34. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/overlay/template/brand/brand-guide.md +0 -0
  35. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/overlay/template/keywords/glossary.md +0 -0
  36. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/overlay/template/people/roster.md +0 -0
  37. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/overlay/template/voice/voice-profile.md +0 -0
  38. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/routines/manifest.json +0 -0
  39. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/scripts/brain-brief-mac.plist +0 -0
  40. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/scripts/brain-brief.sh +0 -0
  41. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/scripts/brain-synthesis-mac.plist +0 -0
  42. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/scripts/brain-synthesis.sh +0 -0
  43. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/scripts/brain_synthesis_codex.py +0 -0
  44. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/scripts/brainiac-alerts.sh +0 -0
  45. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/scripts/brainiac-egress-guard.sh +0 -0
  46. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/scripts/install-brief-mac.sh +0 -0
  47. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/scripts/install-brief-windows.ps1 +0 -0
  48. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/scripts/register_tasks.py +0 -0
  49. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/scripts/vm-boundary-probe.sh +0 -0
  50. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/scripts/vm-selftest.sh +0 -0
  51. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/templates/company.md +0 -0
  52. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/templates/concept.md +0 -0
  53. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/templates/daily.md +0 -0
  54. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/templates/decision.md +0 -0
  55. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/templates/deliverable.md +0 -0
  56. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/templates/meeting.md +0 -0
  57. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/templates/person.md +0 -0
  58. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/templates/project.md +0 -0
  59. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_assets/templates/state-moc.md +0 -0
  60. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/_optional.py +0 -0
  61. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/alerts.py +0 -0
  62. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/alerts_render.py +0 -0
  63. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/alerts_staging.py +0 -0
  64. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/anchor.py +0 -0
  65. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/atomic_temp.py +0 -0
  66. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/attestation.py +0 -0
  67. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/audit.py +0 -0
  68. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/audit_chain.py +0 -0
  69. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/autolink.py +0 -0
  70. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/backup.py +0 -0
  71. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/brief.py +0 -0
  72. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/brief_render.py +0 -0
  73. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/capture.py +0 -0
  74. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/chunk.py +0 -0
  75. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/classification.py +0 -0
  76. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli.py +0 -0
  77. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/__init__.py +0 -0
  78. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/common_parser.py +0 -0
  79. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/connect.py +0 -0
  80. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/connect_parser.py +0 -0
  81. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/eval.py +0 -0
  82. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/eval_parser.py +0 -0
  83. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/index_storage.py +0 -0
  84. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/index_storage_parser.py +0 -0
  85. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/ingest_storage.py +0 -0
  86. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/ingest_storage_parser.py +0 -0
  87. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/lifecycle.py +0 -0
  88. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/lifecycle_parser.py +0 -0
  89. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/maintenance.py +0 -0
  90. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/maintenance_parser.py +0 -0
  91. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/navigation.py +0 -0
  92. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/navigation_parser.py +0 -0
  93. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/owner_workflow.py +0 -0
  94. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/owner_workflow_parser.py +0 -0
  95. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/presentation.py +0 -0
  96. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/presentation_parser.py +0 -0
  97. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/retrieval.py +0 -0
  98. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/retrieval_parser.py +0 -0
  99. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/update.py +0 -0
  100. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/update_parser.py +0 -0
  101. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/versioning.py +0 -0
  102. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_cmds/versioning_parser.py +0 -0
  103. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_help.py +0 -0
  104. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_read_record.py +0 -0
  105. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cli_render.py +0 -0
  106. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/config.py +0 -0
  107. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/config_hostpaths.py +0 -0
  108. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/connect.py +0 -0
  109. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/context.py +0 -0
  110. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/conventions.py +0 -0
  111. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/conventions_scan.py +0 -0
  112. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/__init__.py +0 -0
  113. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/_audit.py +0 -0
  114. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/_briefing.py +0 -0
  115. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/_capture.py +0 -0
  116. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/_capture_staging.py +0 -0
  117. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/_durability.py +0 -0
  118. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/_health.py +0 -0
  119. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/_maintenance.py +0 -0
  120. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/_retrieval.py +0 -0
  121. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/_shared.py +0 -0
  122. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/_supersede_batch.py +0 -0
  123. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/_supersession.py +0 -0
  124. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/core/_supersession_journal.py +0 -0
  125. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cowork_leak_artifact.py +0 -0
  126. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cowork_leak_databases.py +0 -0
  127. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cowork_leak_notes.py +0 -0
  128. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cowork_leak_scan.py +0 -0
  129. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cowork_snapshot_guard.py +0 -0
  130. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/cowork_staging.py +0 -0
  131. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/dbretry.py +0 -0
  132. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/deliverables_absorb.py +0 -0
  133. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/deliverables_apply.py +0 -0
  134. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/deliverables_ledger.py +0 -0
  135. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/deliverables_materialize.py +0 -0
  136. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/deliverables_previous.py +0 -0
  137. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/deliverables_readme.py +0 -0
  138. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/deliverables_shelf.py +0 -0
  139. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/deliverables_sync.py +0 -0
  140. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/doctor.py +0 -0
  141. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/doctor_checks.py +0 -0
  142. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/doctor_context.py +0 -0
  143. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/doctor_desktop.py +0 -0
  144. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/doctor_health.py +0 -0
  145. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/doctor_mount_leak.py +0 -0
  146. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/doctor_plugins.py +0 -0
  147. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/doctor_staging.py +0 -0
  148. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/doctor_vendor.py +0 -0
  149. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/doctor_vm.py +0 -0
  150. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/doctor_wiring.py +0 -0
  151. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/draft_drain.py +0 -0
  152. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/draft_update.py +0 -0
  153. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/egress.py +0 -0
  154. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/egress_terms.py +0 -0
  155. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/embed.py +0 -0
  156. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/embed_backends.py +0 -0
  157. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/embed_catalog.py +0 -0
  158. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/embed_onnx.py +0 -0
  159. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/embed_qwen.py +0 -0
  160. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/encryption.py +0 -0
  161. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/exceptions_cli.py +0 -0
  162. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/exceptions_render.py +0 -0
  163. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/exceptions_tray.py +0 -0
  164. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/__init__.py +0 -0
  165. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/context.py +0 -0
  166. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/daily.py +0 -0
  167. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/deliverables.py +0 -0
  168. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/golden.py +0 -0
  169. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/graph.py +0 -0
  170. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/invariants.py +0 -0
  171. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/orchestrator.py +0 -0
  172. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/organization.py +0 -0
  173. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/preflight.py +0 -0
  174. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/publish.py +0 -0
  175. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/remediation.py +0 -0
  176. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/remediation_bookkeeping.py +0 -0
  177. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/reporting.py +0 -0
  178. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/retention.py +0 -0
  179. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/watchdogs.py +0 -0
  180. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/folds/weekly.py +0 -0
  181. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/frontmatter.py +0 -0
  182. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/golden_ops.py +0 -0
  183. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/golden_probe.py +0 -0
  184. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/golden_probe_cases.py +0 -0
  185. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/graph.py +0 -0
  186. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/graph_hygiene.py +0 -0
  187. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/graphify.py +0 -0
  188. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/graphify_edges.py +0 -0
  189. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/graphreport.py +0 -0
  190. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/graphreport_sections.py +0 -0
  191. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/graphreport_sections_2.py +0 -0
  192. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/guard_settings.py +0 -0
  193. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/healthreport.py +0 -0
  194. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/healthreport_sections.py +0 -0
  195. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/healthreport_unsigned.py +0 -0
  196. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/inbox.py +0 -0
  197. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/__init__.py +0 -0
  198. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_connection.py +0 -0
  199. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_families.py +0 -0
  200. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_graph.py +0 -0
  201. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_identity.py +0 -0
  202. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_lifecycle.py +0 -0
  203. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_models.py +0 -0
  204. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_planning.py +0 -0
  205. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_records.py +0 -0
  206. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_retirement.py +0 -0
  207. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_schema.py +0 -0
  208. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_search.py +0 -0
  209. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_settings.py +0 -0
  210. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_shared.py +0 -0
  211. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_tools.py +0 -0
  212. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index/_zones.py +0 -0
  213. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index_stages/__init__.py +0 -0
  214. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index_stages/connection.py +0 -0
  215. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index_stages/diagnostics.py +0 -0
  216. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index_stages/duplicate_families.py +0 -0
  217. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index_stages/near_duplicates.py +0 -0
  218. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index_stages/rebuild.py +0 -0
  219. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index_stages/reranking.py +0 -0
  220. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index_stages/search.py +0 -0
  221. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index_stages/search_finalization.py +0 -0
  222. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index_stages/search_identity.py +0 -0
  223. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index_stages/search_ranking.py +0 -0
  224. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/index_stages/sync.py +0 -0
  225. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/__init__.py +0 -0
  226. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/__init__.py +0 -0
  227. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/base.py +0 -0
  228. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/concealment.py +0 -0
  229. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/concealment_gate.py +0 -0
  230. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/concealment_html.py +0 -0
  231. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/concealment_ledger.py +0 -0
  232. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/concealment_office.py +0 -0
  233. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/docx.py +0 -0
  234. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/email.py +0 -0
  235. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/html.py +0 -0
  236. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/image.py +0 -0
  237. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/ole.py +0 -0
  238. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/pdf.py +0 -0
  239. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/pptx.py +0 -0
  240. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/tables.py +0 -0
  241. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/text.py +0 -0
  242. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/xlsx.py +0 -0
  243. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/handlers/zip.py +0 -0
  244. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/pipeline.py +0 -0
  245. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/pipeline_duplicates.py +0 -0
  246. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/pipeline_injection.py +0 -0
  247. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/pipeline_nested.py +0 -0
  248. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/pipeline_run.py +0 -0
  249. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/pipeline_stages.py +0 -0
  250. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/tierguard.py +0 -0
  251. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/tierguard_verdict.py +0 -0
  252. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/ingest/transcript.py +0 -0
  253. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/init.py +0 -0
  254. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/init_import.py +0 -0
  255. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/init_samples.py +0 -0
  256. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/init_seed.py +0 -0
  257. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/init_steps.py +0 -0
  258. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/injection_fold.py +0 -0
  259. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/injection_scan.py +0 -0
  260. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/interview_apply.py +0 -0
  261. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/interview_detect.py +0 -0
  262. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/invariant_crosstier.py +0 -0
  263. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/invariant_deliverables.py +0 -0
  264. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/invariant_floors.py +0 -0
  265. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/invariant_ingest_guard.py +0 -0
  266. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/invariant_lane_health.py +0 -0
  267. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/invariant_reachability.py +0 -0
  268. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/invariant_shared.py +0 -0
  269. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/invariant_unsigned_notes.py +0 -0
  270. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/invariants.py +0 -0
  271. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/invariants_metrics.py +0 -0
  272. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/language.py +0 -0
  273. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/link_targets.py +0 -0
  274. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/lock.py +0 -0
  275. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance.py +0 -0
  276. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_escalation.py +0 -0
  277. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_folds.py +0 -0
  278. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_folds_2.py +0 -0
  279. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_folds_3.py +0 -0
  280. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_folds_4.py +0 -0
  281. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_golden.py +0 -0
  282. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_graphfolds.py +0 -0
  283. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_healthlog.py +0 -0
  284. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_hotmd.py +0 -0
  285. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_invariant_fields.py +0 -0
  286. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_outcomes.py +0 -0
  287. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_para.py +0 -0
  288. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_recommendations.py +0 -0
  289. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_retention.py +0 -0
  290. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_sweep.py +0 -0
  291. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/maintenance_watchdog.py +0 -0
  292. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/mcp_adapter.py +0 -0
  293. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/mcp_capture_verbs.py +0 -0
  294. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/mcp_housekeeping_verbs.py +0 -0
  295. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/mcp_mediation.py +0 -0
  296. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/mcp_supersede_verbs.py +0 -0
  297. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/mcp_tools/__init__.py +0 -0
  298. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/mcp_tools/capture.py +0 -0
  299. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/mcp_tools/core_read.py +0 -0
  300. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/mcp_tools/housekeeping.py +0 -0
  301. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/mcp_tools/retrieval.py +0 -0
  302. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/mcp_tools/supersession.py +0 -0
  303. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/mcp_verbs.py +0 -0
  304. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/model_slot.py +0 -0
  305. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/multihop.py +0 -0
  306. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/notes.py +0 -0
  307. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/originals_resolve.py +0 -0
  308. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/overlay.py +0 -0
  309. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/overlay_core.py +0 -0
  310. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/overlay_keywords.py +0 -0
  311. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/overlay_rules.py +0 -0
  312. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/pathkey.py +0 -0
  313. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/progress.py +0 -0
  314. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/projection.py +0 -0
  315. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/provenance.py +0 -0
  316. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/provision_mcp.py +0 -0
  317. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/provision_stage.py +0 -0
  318. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/provision_wire.py +0 -0
  319. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/querylog.py +0 -0
  320. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/querylog_digest.py +0 -0
  321. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/querylog_replay.py +0 -0
  322. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/querylog_status.py +0 -0
  323. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/read_log.py +0 -0
  324. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/reexec.py +0 -0
  325. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/remediation.py +0 -0
  326. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/remediation_answers.py +0 -0
  327. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/remediation_branches.py +0 -0
  328. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/remediation_converged.py +0 -0
  329. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/remediation_exceptions.py +0 -0
  330. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/remediation_extract_retry.py +0 -0
  331. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/remediation_folds.py +0 -0
  332. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/remediation_questions.py +0 -0
  333. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/remediation_routing.py +0 -0
  334. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/remediation_schema.py +0 -0
  335. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/rerank.py +0 -0
  336. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/rerank_onnx.py +0 -0
  337. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/retrieval_ops.py +0 -0
  338. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/retro.py +0 -0
  339. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/session_hook.py +0 -0
  340. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/session_hook_spec.py +0 -0
  341. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/snapshot.py +0 -0
  342. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/status_ops.py +0 -0
  343. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/supersede_declared.py +0 -0
  344. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/sweepdirs.py +0 -0
  345. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/update.py +0 -0
  346. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/update_channels_2.py +0 -0
  347. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/update_cos_guard.py +0 -0
  348. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/update_model.py +0 -0
  349. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/update_ops.py +0 -0
  350. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/update_plugins.py +0 -0
  351. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/update_state.py +0 -0
  352. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/update_venv.py +0 -0
  353. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/vectors.py +0 -0
  354. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/versionlink.py +0 -0
  355. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/versionlink_stages.py +0 -0
  356. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brain/vm_ceiling.py +0 -0
  357. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brainiac_cli.egg-info/SOURCES.txt +0 -0
  358. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brainiac_cli.egg-info/dependency_links.txt +0 -0
  359. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brainiac_cli.egg-info/entry_points.txt +0 -0
  360. {brainiac_cli-0.20.45 → brainiac_cli-0.20.46}/src/brainiac_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: brainiac-cli
3
- Version: 0.20.45
3
+ Version: 0.20.46
4
4
  Summary: Brainiac — local any-LLM second-brain core engine + brain CLI (Markdown truth, derived SQLite index).
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Homepage, https://github.com/Autopsias/brainiac
@@ -19,11 +19,12 @@ Requires-Dist: cryptography>=49
19
19
  Requires-Dist: PyYAML>=6
20
20
  Requires-Dist: regex>=2023.0.0
21
21
  Requires-Dist: keyring>=24; sys_platform == "win32"
22
- Requires-Dist: pypdf>=6.15.0
22
+ Requires-Dist: pypdf>=6.21.2
23
23
  Requires-Dist: python-docx>=1.1
24
24
  Requires-Dist: python-pptx>=0.6.23
25
25
  Requires-Dist: openpyxl>=3.1
26
- Requires-Dist: Pillow>=12.3.0
26
+ Requires-Dist: Pillow>=13.0.0; python_version >= "3.11"
27
+ Requires-Dist: Pillow>=12.3.0; python_version < "3.11"
27
28
  Provides-Extra: vec
28
29
  Requires-Dist: sqlite-vec>=0.1.6; extra == "vec"
29
30
  Provides-Extra: audit
@@ -43,11 +44,12 @@ Requires-Dist: PyYAML>=6; extra == "corporate"
43
44
  Provides-Extra: yaml
44
45
  Requires-Dist: PyYAML>=6; extra == "yaml"
45
46
  Provides-Extra: ingest
46
- Requires-Dist: pypdf>=6.15.0; extra == "ingest"
47
+ Requires-Dist: pypdf>=6.21.2; extra == "ingest"
47
48
  Requires-Dist: python-docx>=1.1; extra == "ingest"
48
49
  Requires-Dist: python-pptx>=0.6.23; extra == "ingest"
49
50
  Requires-Dist: openpyxl>=3.1; extra == "ingest"
50
- Requires-Dist: Pillow>=12.3.0; extra == "ingest"
51
+ Requires-Dist: Pillow>=13.0.0; python_version >= "3.11" and extra == "ingest"
52
+ Requires-Dist: Pillow>=12.3.0; python_version < "3.11" and extra == "ingest"
51
53
  Provides-Extra: dev
52
54
  Requires-Dist: pytest>=7; extra == "dev"
53
55
  Requires-Dist: build>=1; extra == "dev"
@@ -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.45"
11
+ version = "0.20.46"
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"
@@ -42,7 +42,7 @@ dependencies = [
42
42
  # because requirements.lock is CI/audit-only -- a plain
43
43
  # `pip install brainiac-cli` reads THIS constraint, and >=4.0 let the
44
44
  # vulnerable 6.14.2 survive an upgrade to 0.20.5 on a real host.
45
- "pypdf>=6.15.0",
45
+ "pypdf>=6.21.2",
46
46
  "python-docx>=1.1",
47
47
  "python-pptx>=0.6.23",
48
48
  "openpyxl>=3.1",
@@ -50,7 +50,10 @@ dependencies = [
50
50
  # binary is present — the pytesseract binding itself stays a fully
51
51
  # OPTIONAL, NOT-a-pip-dependency probe: OCR degrades gracefully absent
52
52
  # it, matching the ADR's "system binaries are never pip deps" rule).
53
- "Pillow>=12.3.0",
53
+ # >=13.0.0 fixes 37 advisories (one a FlashPix heap overflow); 13 needs
54
+ # Python 3.11+, and no fixed 12.x exists, so 3.10 keeps the old floor.
55
+ "Pillow>=13.0.0; python_version >= '3.11'",
56
+ "Pillow>=12.3.0; python_version < '3.11'",
54
57
  ]
55
58
 
56
59
  [project.optional-dependencies]
@@ -94,7 +97,7 @@ yaml = ["PyYAML>=6"]
94
97
  # message hints valid even though a default install already has these. Absent,
95
98
  # `brain ingest` degrades per-handler (reports which extensions are
96
99
  # unavailable) rather than crashing.
97
- ingest = ["pypdf>=6.15.0", "python-docx>=1.1", "python-pptx>=0.6.23", "openpyxl>=3.1", "Pillow>=12.3.0"]
100
+ ingest = ["pypdf>=6.21.2", "python-docx>=1.1", "python-pptx>=0.6.23", "openpyxl>=3.1", "Pillow>=13.0.0; python_version >= '3.11'", "Pillow>=12.3.0; python_version < '3.11'"]
98
101
  # pytest-xdist/-timeout back the documented parallel suite run (AGENTS.md §8,
99
102
  # "Running the test suite"): ~15 min sequential -> ~6 min at `-n 8`. Both are
100
103
  # pytest-dev org, actively maintained. Declared here so a fresh checkout can
@@ -296,3 +299,20 @@ python-platform = "linux"
296
299
  # `_assets` is the generated mirror of tools/ + scripts/ inside src/brain/.
297
300
  include = ["src", "tools", "eval", "scripts", "packaging"]
298
301
  exclude = ["**/_plans", "**/_archive", "**/_evidence", "**/_assets"]
302
+
303
+ [tool.uv]
304
+ # Wait 7 days before resolving a newly published version (a new release can be
305
+ # malicious or broken). shortcut: pypdf 6.21.2, filelock 4.2.4 and certifi
306
+ # 2026.10.23 are security fixes under 7 days old on 2026-10-24, so they are
307
+ # exempt; remove the exemptions after 2026-10-31.
308
+ exclude-newer = "7 days"
309
+ exclude-newer-package = { pypdf = false, filelock = false, certifi = false }
310
+ # fastembed (the optional `embed` extra, not installed by default) caps
311
+ # pillow<13 in every release up to 0.9.0, but pillow 13.0.0 is the first
312
+ # release fixing 37 advisories (one a FlashPix heap overflow). fastembed uses
313
+ # pillow only for IMAGE embeddings; this repo embeds text only.
314
+ # shortcut: drop this once a fastembed release allows pillow>=13.
315
+ override-dependencies = [
316
+ "pillow>=13.0.0; python_version >= '3.11'",
317
+ "pillow>=12.3.0; python_version < '3.11'",
318
+ ]
@@ -9,4 +9,4 @@ pip-installed host, importlib.metadata stays primary; brain/__init__.py reads
9
9
  this file only as the fallback before 0.0.0+unknown.
10
10
  """
11
11
 
12
- __version__ = "0.20.45"
12
+ __version__ = "0.20.46"
@@ -6,6 +6,7 @@ import os
6
6
  from datetime import date
7
7
  from pathlib import Path
8
8
  from typing import TYPE_CHECKING
9
+ from .atomic_temp import atomic_temp_path
9
10
 
10
11
  if TYPE_CHECKING: # annotation-only; a runtime import here would be a cycle
11
12
  from .audit_chain import AuditChain
@@ -32,7 +33,7 @@ def _write_dispositions(path: Path, payload: dict) -> None:
32
33
  turn every explained finding back into an unexplained one. `os.replace` is
33
34
  atomic within a filesystem, so a reader sees the old file or the new one.
34
35
  """
35
- tmp = path.with_name(path.name + ".tmp")
36
+ tmp = atomic_temp_path(path)
36
37
  tmp.write_text(json.dumps(payload, indent=2), encoding="utf-8")
37
38
  os.replace(tmp, path)
38
39
 
@@ -1,5 +1,6 @@
1
1
  """Maintenance state methods for BrainCore."""
2
2
  from __future__ import annotations
3
+ from ..atomic_temp import atomic_temp_path
3
4
 
4
5
  from ._shared import (
5
6
  Any,
@@ -130,7 +131,7 @@ class _MaintenanceStateMixin:
130
131
 
131
132
  path = config.maintain_state_path(self.vault)
132
133
  path.parent.mkdir(parents=True, exist_ok=True)
133
- tmp = path.with_suffix(path.suffix + ".tmp")
134
+ tmp = atomic_temp_path(path)
134
135
  tmp.write_text(_json.dumps(state, indent=2, sort_keys=True), encoding="utf-8")
135
136
  _os.replace(tmp, path)
136
137
  def _note_graphify_build_outcome(
@@ -60,6 +60,7 @@ from . import maintenance as _maintenance
60
60
  from . import maintenance_notify as _notify
61
61
  from . import remediation as _rem
62
62
  from . import remediation_exceptions as _rex
63
+ from .atomic_temp import atomic_temp_path
63
64
  from .exceptions_render import render_page # re-exported: the page's one
64
65
  # renderer, split out on 2026-08-22 when this file hit the 500-line bound.
65
66
 
@@ -287,7 +288,7 @@ def maybe_ping(vault: Path, keys: list[str], full_path: Path) -> str | None:
287
288
  if not str(out or "").startswith("skipped"): # a SKIP defers, never spends
288
289
  try:
289
290
  state_path.parent.mkdir(parents=True, exist_ok=True)
290
- tmp = state_path.with_name(state_path.name + ".tmp")
291
+ tmp = atomic_temp_path(state_path)
291
292
  tmp.write_text(json.dumps({"hash": current_hash}), encoding="utf-8")
292
293
  os.replace(tmp, state_path)
293
294
  except OSError:
@@ -364,6 +365,6 @@ def generate(core: Any, today: datetime.date | None = None) -> dict[str, Any]:
364
365
 
365
366
 
366
367
  def _atomic_write(path: Path, text: str) -> None:
367
- tmp = path.with_name(path.name + ".tmp")
368
+ tmp = atomic_temp_path(path)
368
369
  tmp.write_text(text, encoding="utf-8")
369
370
  os.replace(tmp, path)
@@ -78,6 +78,7 @@ from pathlib import Path
78
78
  from typing import Any
79
79
 
80
80
  from . import config as _config
81
+ from .atomic_temp import atomic_temp_path
81
82
 
82
83
  PINNED_FILENAME = "pinned-verify.json"
83
84
  MOUNT_HTML_FILENAME = "exceptions.html"
@@ -372,7 +373,7 @@ def stage_pin(vault: Path, workspace: Path | None = None) -> dict[str, Any]:
372
373
  data = {"vault_id": vid, "public_key_pem": pem}
373
374
  path = staging_root(vault, workspace) / PINNED_FILENAME
374
375
  path.parent.mkdir(parents=True, exist_ok=True)
375
- tmp = path.with_name(path.name + ".tmp")
376
+ tmp = atomic_temp_path(path)
376
377
  tmp.write_text(json.dumps(data, indent=1, sort_keys=True), encoding="utf-8")
377
378
  os.replace(tmp, path)
378
379
  return data
@@ -413,6 +414,6 @@ def publish_summary(vault: Path, workspace: Path | None = None) -> None:
413
414
  if not src.exists():
414
415
  continue
415
416
  dest = dest_dir / filename
416
- tmp = dest.with_name(dest.name + ".tmp")
417
+ tmp = atomic_temp_path(dest)
417
418
  tmp.write_bytes(src.read_bytes())
418
419
  os.replace(tmp, dest)
@@ -240,12 +240,12 @@ class IntakeFoldsMixin:
240
240
  from .. import cos # noqa: PLC0415
241
241
 
242
242
  ops = cos.run_ops_dir(self.vault)
243
- ledgers = sorted(ops.glob("_cos_ingestion_ledger_*.jsonl"),
243
+ ledgers = sorted(ops.glob(cos.LEDGER_GLOB),
244
244
  key=self._ledger_order)
245
245
  if not ledgers:
246
246
  return
247
247
  latest = ledgers[-1]
248
- run_id = latest.stem[len("_cos_ingestion_ledger_"):]
248
+ run_id = cos.ledger_run_id(latest)
249
249
  rows, seen = [], set()
250
250
  for line in latest.read_text(encoding="utf-8").splitlines():
251
251
  if not line.strip():
@@ -268,7 +268,7 @@ class IntakeFoldsMixin:
268
268
  """Sort key for `_cos_ingestion_ledger_<date>-run<N>.jsonl`: the date
269
269
  as text, then the run number as an INT. A missing or unparseable run
270
270
  number sorts first, which keeps a malformed name from winning."""
271
- stem = path.stem[len("_cos_ingestion_ledger_"):]
271
+ stem = path.stem[len("_cos_ingestion_ledger_"):] # no COS import: this runs unguarded
272
272
  date, _, tail = stem.partition("-run")
273
273
  return (date, int(tail) if tail.isdigit() else -1)
274
274
 
@@ -355,12 +355,12 @@ class IntakeFoldsMixin:
355
355
  from .. import cos # noqa: PLC0415
356
356
 
357
357
  ops = cos.run_ops_dir(self.vault)
358
- ledgers = sorted(ops.glob("_cos_ingestion_ledger_*.jsonl"),
358
+ ledgers = sorted(ops.glob(cos.LEDGER_GLOB),
359
359
  key=self._ledger_order)
360
360
  if not ledgers:
361
361
  return
362
362
  latest = ledgers[-1]
363
- run_id = latest.stem[len("_cos_ingestion_ledger_"):]
363
+ run_id = cos.ledger_run_id(latest)
364
364
  stuck, seen = {}, set()
365
365
  for line in latest.read_text(encoding="utf-8").splitlines():
366
366
  if not line.strip():
@@ -14,6 +14,7 @@ from . import classification, config, egress
14
14
  from . import graphify as graphify_model
15
15
  from .graph import build_graph
16
16
  from .progress import progress_note
17
+ from .atomic_temp import atomic_temp_path
17
18
 
18
19
 
19
20
  @dataclass(frozen=True)
@@ -186,7 +187,7 @@ def _publish_graph_artifact(
186
187
  day: dt.date,
187
188
  ) -> None:
188
189
  """Atomically publish validated graph and manifest files."""
189
- temporary_graph = paths.graph.with_suffix(paths.graph.suffix + ".tmp")
190
+ temporary_graph = atomic_temp_path(paths.graph)
190
191
  temporary_graph.write_text(
191
192
  json.dumps(artifact, indent=2, sort_keys=True), encoding="utf-8"
192
193
  )
@@ -197,7 +198,7 @@ def _publish_graph_artifact(
197
198
  "built_at": day.isoformat(),
198
199
  "notes": manifest,
199
200
  }
200
- temporary_manifest = paths.manifest.with_suffix(paths.manifest.suffix + ".tmp")
201
+ temporary_manifest = atomic_temp_path(paths.manifest)
201
202
  temporary_manifest.write_text(
202
203
  json.dumps(new_state, indent=2, sort_keys=True), encoding="utf-8"
203
204
  )
@@ -49,6 +49,7 @@ from typing import TYPE_CHECKING, Any
49
49
 
50
50
  from .. import classification as CLS
51
51
  from .. import supersede_declared as SUP
52
+ from ..atomic_temp import atomic_temp_path
52
53
 
53
54
  if TYPE_CHECKING: # the stage record; a runtime import here would be a cycle
54
55
  from .pipeline_stages import ClaimRecord
@@ -423,7 +424,7 @@ def _store(vault: Any, pending: dict[str, dict[str, Any]]) -> None:
423
424
  path = journal_path(vault)
424
425
  path.parent.mkdir(parents=True, exist_ok=True)
425
426
  config.secure_file_permissions(path.parent, 0o700)
426
- tmp = path.with_name(path.name + ".tmp")
427
+ tmp = atomic_temp_path(path)
427
428
  tmp.write_text(json.dumps(pending, indent=2, sort_keys=True), encoding="utf-8")
428
429
  config.secure_file_permissions(tmp, 0o600)
429
430
  tmp.replace(path)
@@ -62,7 +62,10 @@ def page_fonts(page: Any) -> dict[str, Any]:
62
62
  """
63
63
  fonts: dict[str, Any] = {}
64
64
  try:
65
- from pypdf._font import Font
65
+ try:
66
+ from pypdf.generic._font import Font # pypdf >= 6.21
67
+ except ImportError: # coverage-audit: older pypdf keeps Font here
68
+ from pypdf._font import Font
66
69
 
67
70
  resources = page.get_inherited("/Resources", None)
68
71
  table = resources.get("/Font") if resources else None
@@ -10,6 +10,7 @@ import shutil
10
10
  import tempfile
11
11
  from pathlib import Path
12
12
  from typing import Any
13
+ from ..atomic_temp import atomic_temp_path
13
14
 
14
15
 
15
16
  def manifest_path(vault: Path) -> Path:
@@ -32,7 +33,7 @@ def load_manifest(vault: Path) -> dict[str, str]:
32
33
  def save_manifest(vault: Path, manifest: dict[str, str]) -> None:
33
34
  path = manifest_path(vault)
34
35
  path.parent.mkdir(parents=True, exist_ok=True)
35
- tmp = path.with_suffix(".tmp")
36
+ tmp = atomic_temp_path(path)
36
37
  tmp.write_text(json.dumps(manifest, indent=2, sort_keys=True), encoding="utf-8")
37
38
  os.replace(tmp, path)
38
39
 
@@ -57,7 +58,7 @@ def load_failures(vault: Path) -> dict[str, int]:
57
58
  def save_failures(vault: Path, failures: dict[str, int]) -> None:
58
59
  path = failures_path(vault)
59
60
  path.parent.mkdir(parents=True, exist_ok=True)
60
- tmp = path.with_suffix(".tmp")
61
+ tmp = atomic_temp_path(path)
61
62
  tmp.write_text(json.dumps(failures, indent=2, sort_keys=True), encoding="utf-8")
62
63
  os.replace(tmp, path)
63
64
 
@@ -88,7 +89,11 @@ def read_nofollow(path: Path, *, max_bytes: int | None = None) -> bytes:
88
89
 
89
90
  if path.is_symlink():
90
91
  raise ReadRefused(f"{path.name} is a symlink — refused")
91
- flags = os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0) | getattr(os, "O_BINARY", 0)
92
+ # O_NONBLOCK: a FIFO planted at the name would otherwise block the open
93
+ # until a writer arrives, before the S_ISREG check below can refuse it
94
+ # (same guard as ``cos._io``). It changes nothing for a regular file.
95
+ flags = (os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0) | getattr(os, "O_BINARY", 0)
96
+ | getattr(os, "O_NONBLOCK", 0))
92
97
  try:
93
98
  fd = os.open(path, flags)
94
99
  except OSError as exc:
@@ -27,6 +27,7 @@ import os
27
27
  import re
28
28
  from pathlib import Path
29
29
  from typing import Any
30
+ from .atomic_temp import atomic_temp_path
30
31
 
31
32
  SCHEMA = "brain-interview/1"
32
33
  STATE_RELPATH = ".brain/interview/state.json"
@@ -103,7 +104,7 @@ def read_state(vault: Any) -> dict[str, Any]:
103
104
  def write_state(vault: Any, state: dict[str, Any]) -> Path:
104
105
  p = state_path(vault)
105
106
  p.parent.mkdir(parents=True, exist_ok=True)
106
- tmp = p.with_suffix(".json.tmp")
107
+ tmp = atomic_temp_path(p)
107
108
  tmp.write_text(json.dumps(state, ensure_ascii=False, sort_keys=True,
108
109
  indent=1) + "\n", encoding="utf-8")
109
110
  os.chmod(tmp, 0o600)
@@ -9,6 +9,7 @@ from pathlib import Path
9
9
  from typing import Any
10
10
 
11
11
  from .invariant_shared import SAMPLE_CAP
12
+ from .atomic_temp import atomic_temp_path
12
13
 
13
14
  # ---------------------------------------------------------------------------
14
15
  # G12 — the exclusion set, defined ONCE here and imported by every consumer
@@ -437,7 +438,7 @@ def write_link_lane(conn: Any, vault: Path, *, limit: int | None = None) -> dict
437
438
  except (OSError, ValueError):
438
439
  previous = None
439
440
  payload.update(lane_consumption(previous, all_ids, payload["generated"]))
440
- tmp = out.with_suffix(".json.tmp")
441
+ tmp = atomic_temp_path(out)
441
442
  tmp.write_text(json.dumps(payload, indent=1), encoding="utf-8")
442
443
  tmp.replace(out)
443
444
  return {"path": str(out), "written": len(payload["candidates"]),
@@ -13,6 +13,7 @@ import os
13
13
  import platform
14
14
  import subprocess
15
15
  import hashlib
16
+ from .atomic_temp import atomic_temp_path
16
17
 
17
18
 
18
19
  # ---------------------------------------------------------------------------
@@ -138,7 +139,7 @@ def record_current_findings(
138
139
  }
139
140
  try:
140
141
  path.parent.mkdir(parents=True, exist_ok=True)
141
- tmp = path.with_name(path.name + ".tmp")
142
+ tmp = atomic_temp_path(path)
142
143
  tmp.write_text(json.dumps(payload, indent=1), encoding="utf-8")
143
144
  os.replace(tmp, path)
144
145
  except OSError:
@@ -64,6 +64,7 @@ from typing import Any, NamedTuple
64
64
 
65
65
  from . import frontmatter
66
66
  from . import overlay as ov
67
+ from .atomic_temp import atomic_temp_path
67
68
 
68
69
  #: Sibling of ``keywords/`` — deliberately NOT inside it. See the module
69
70
  #: docstring: ``keywords/`` drives ingest classification and this does not.
@@ -223,7 +224,7 @@ def _publish(path: Path, text: str) -> None:
223
224
  ``*.md`` glob in :func:`brain.overlay._ring_files` cannot pick a half-written
224
225
  temp file up as a ring file of its own.
225
226
  """
226
- tmp = path.with_name(f".{path.name}.tmp")
227
+ tmp = atomic_temp_path(path)
227
228
  try:
228
229
  tmp.write_text(text, encoding="utf-8")
229
230
  os.replace(tmp, path)
@@ -47,7 +47,7 @@ from datetime import datetime, timezone
47
47
  from pathlib import Path
48
48
  from typing import Any, Callable, Optional
49
49
 
50
- from . import workspaces
50
+ from . import atomic_temp, workspaces
51
51
  # Wire 5 moved to `provision_mcp` (its own module: the Desktop config is a
52
52
  # third-party file with a third party still writing to it). Re-exported here
53
53
  # because this module is the one every caller already imports.
@@ -94,7 +94,7 @@ def write_request(vault: str | os.PathLike[str], *, role: str) -> dict[str, Any]
94
94
  for zone in ("brain", "raw", "inbox"):
95
95
  (vault_p / zone).mkdir(exist_ok=True)
96
96
  payload = {"version": 1, "requested_at": _now_iso(), "role": role}
97
- tmp = marker.with_suffix(".tmp")
97
+ tmp = atomic_temp.atomic_temp_path(marker)
98
98
  tmp.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
99
99
  os.replace(tmp, marker)
100
100
  return {"action": "provision-request", "status": "staged",
@@ -21,6 +21,7 @@ from typing import Any, Mapping
21
21
 
22
22
  from . import remediation_state as _rs
23
23
  from .remediation_answers import unlabelled_ids
24
+ from .atomic_temp import atomic_temp_path
24
25
 
25
26
  #: BUMPED (llm-review, s06 HIGH finding). Behaviour changed under this same
26
27
  #: string once already: an earlier build of THIS feature normalized a pair's
@@ -127,7 +128,7 @@ def _write_proposal(vault: str | os.PathLike[str], meta: Mapping[str, Any]) -> N
127
128
  d = exceptions_dir(vault) / PENDING_DIRNAME
128
129
  d.mkdir(parents=True, exist_ok=True)
129
130
  path = d / f"{meta['id']}.json"
130
- tmp = path.with_name(path.name + ".tmp")
131
+ tmp = atomic_temp_path(path)
131
132
  tmp.write_text(json.dumps(dict(meta), indent=1, sort_keys=True), encoding="utf-8")
132
133
  os.replace(tmp, path)
133
134
 
@@ -52,6 +52,7 @@ from pathlib import Path
52
52
  from typing import Any, Mapping, MutableMapping
53
53
 
54
54
  from . import maintenance_escalation as _escalation
55
+ from .atomic_temp import atomic_temp_path
55
56
 
56
57
  #: The host-private root, under ``config.index_dir(vault)``.
57
58
  DIRNAME = "remediation"
@@ -128,7 +129,7 @@ def write_state(vault: str | os.PathLike[str], state: Mapping[str, Any]) -> bool
128
129
  d = remediation_dir(vault)
129
130
  d.mkdir(parents=True, exist_ok=True)
130
131
  path = d / STATE_FILENAME
131
- tmp = path.with_name(path.name + ".tmp")
132
+ tmp = atomic_temp_path(path)
132
133
  tmp.write_text(json.dumps(payload, indent=1, sort_keys=True), encoding="utf-8")
133
134
  os.replace(tmp, path)
134
135
  return True
@@ -19,10 +19,11 @@ from pathlib import Path
19
19
  from typing import Any
20
20
 
21
21
  from .session_hook_spec import HOOK_EVENT, HOOKS, HookSpec
22
+ from .atomic_temp import atomic_temp_path
22
23
 
23
24
 
24
25
  def _write_json_atomic(path: Path, payload: Any) -> None:
25
- tmp = path.with_name(path.name + ".tmp")
26
+ tmp = atomic_temp_path(path)
26
27
  tmp.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
27
28
  os.replace(tmp, path)
28
29
 
@@ -4,11 +4,11 @@ from __future__ import annotations
4
4
  import os
5
5
  import shutil
6
6
  import subprocess
7
- import sys
8
7
  from dataclasses import dataclass
9
8
  from pathlib import Path
10
9
  from typing import Any, Callable, Optional
11
10
  from .cowork_snapshot_guard import snapshot_lands_on_the_mount
11
+ from .vmstaging import tools_on_path
12
12
  from .doctor import (
13
13
  CHANNEL_EDITABLE,
14
14
  CHANNEL_PIP_USER,
@@ -233,11 +233,11 @@ def stage_engine_and_skills(
233
233
 
234
234
  vendor_status: dict[str, str] = {}
235
235
  try:
236
- sys.path.insert(0, str(engine_src / "tools"))
237
- import vendor_semantic_deps as vendor_deps # type: ignore
236
+ with tools_on_path(engine_src):
237
+ import vendor_semantic_deps as vendor_deps # type: ignore
238
238
 
239
- vendor_deps.write_shim(brain_dir)
240
- vendor_status = vendor_deps.stage_vendor(brain_dir)
239
+ vendor_deps.write_shim(brain_dir)
240
+ vendor_status = vendor_deps.stage_vendor(brain_dir)
241
241
  except Exception as exc:
242
242
  vendor_status = {"error": f"{type(exc).__name__}: {exc}"}
243
243
 
@@ -421,8 +421,8 @@ def restage_workspaces(
421
421
  resolve_model_source: Callable[[], tuple[Path, str]],
422
422
  ) -> list[dict]:
423
423
  """Restage every registered Cowork workspace."""
424
- sys.path.insert(0, str(engine_src / "tools"))
425
- import workspace_registry as workspace_registry_module # type: ignore
424
+ with tools_on_path(engine_src):
425
+ import workspace_registry as workspace_registry_module # type: ignore
426
426
 
427
427
  results: list[dict] = []
428
428
  model_source: tuple[Path, str] | None = None
@@ -29,15 +29,32 @@ marker the host can read WITHOUT executing it, or it cannot be checked at all.
29
29
  """
30
30
  from __future__ import annotations
31
31
 
32
+ import contextlib
32
33
  import hashlib
33
34
  import re
34
35
  import shutil
36
+ import sys
35
37
  from pathlib import Path
36
- from typing import Any
38
+ from typing import Any, Iterator
37
39
 
38
40
  ARCHES = ("x86_64", "aarch64")
39
41
 
40
42
 
43
+ @contextlib.contextmanager
44
+ def tools_on_path(engine_src: Path) -> Iterator[None]:
45
+ """Put ``<engine_src>/tools`` on ``sys.path`` for the block, and ALWAYS take
46
+ it off again, so importing a tools module never leaves the path changed."""
47
+ entry = str(engine_src / "tools")
48
+ sys.path.insert(0, entry)
49
+ try:
50
+ yield
51
+ finally:
52
+ try:
53
+ sys.path.remove(entry)
54
+ except ValueError:
55
+ pass
56
+
57
+
41
58
  def stage_vm_binaries(brain_dir: Path, dist: Path) -> dict:
42
59
  """Copy each frozen ELF, its ``.version`` marker, and rewrite SHA256SUMS.
43
60
 
@@ -94,12 +111,11 @@ def stage_vm_support_files(brain_dir: Path, engine_src: Path, packaged_script) -
94
111
  """
95
112
  vendor_status: dict[str, str] = {}
96
113
  try:
97
- import sys as _sys
98
- _sys.path.insert(0, str(engine_src / "tools"))
99
- import vendor_semantic_deps as _vsd # type: ignore
114
+ with tools_on_path(engine_src):
115
+ import vendor_semantic_deps as _vsd # type: ignore
100
116
 
101
- _vsd.write_shim(brain_dir) # vendored-deps-aware shim
102
- vendor_status = _vsd.stage_vendor(brain_dir) # tokenizers + sqlite-vec per arch
117
+ _vsd.write_shim(brain_dir) # vendored-deps-aware shim
118
+ vendor_status = _vsd.stage_vendor(brain_dir) # tokenizers + sqlite-vec per arch
103
119
  except Exception as exc: # advisory — a networkless host degrades to lexical
104
120
  vendor_status = {"error": f"{type(exc).__name__}: {exc}"}
105
121
 
@@ -49,6 +49,7 @@ from pathlib import Path
49
49
  from typing import Iterator, Optional
50
50
 
51
51
  from .pathkey import real_key
52
+ from .atomic_temp import atomic_temp_path
52
53
 
53
54
  REGISTRY_VERSION = 1
54
55
 
@@ -126,7 +127,7 @@ def _load(path: Path) -> dict:
126
127
 
127
128
  def _write_atomic(path: Path, data: dict) -> None:
128
129
  path.parent.mkdir(parents=True, exist_ok=True)
129
- tmp = path.with_suffix(path.suffix + ".tmp")
130
+ tmp = atomic_temp_path(path)
130
131
  tmp.write_text(json.dumps(data, indent=2, sort_keys=False) + "\n", encoding="utf-8")
131
132
  os.replace(tmp, path)
132
133
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: brainiac-cli
3
- Version: 0.20.45
3
+ Version: 0.20.46
4
4
  Summary: Brainiac — local any-LLM second-brain core engine + brain CLI (Markdown truth, derived SQLite index).
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Homepage, https://github.com/Autopsias/brainiac
@@ -19,11 +19,12 @@ Requires-Dist: cryptography>=49
19
19
  Requires-Dist: PyYAML>=6
20
20
  Requires-Dist: regex>=2023.0.0
21
21
  Requires-Dist: keyring>=24; sys_platform == "win32"
22
- Requires-Dist: pypdf>=6.15.0
22
+ Requires-Dist: pypdf>=6.21.2
23
23
  Requires-Dist: python-docx>=1.1
24
24
  Requires-Dist: python-pptx>=0.6.23
25
25
  Requires-Dist: openpyxl>=3.1
26
- Requires-Dist: Pillow>=12.3.0
26
+ Requires-Dist: Pillow>=13.0.0; python_version >= "3.11"
27
+ Requires-Dist: Pillow>=12.3.0; python_version < "3.11"
27
28
  Provides-Extra: vec
28
29
  Requires-Dist: sqlite-vec>=0.1.6; extra == "vec"
29
30
  Provides-Extra: audit
@@ -43,11 +44,12 @@ Requires-Dist: PyYAML>=6; extra == "corporate"
43
44
  Provides-Extra: yaml
44
45
  Requires-Dist: PyYAML>=6; extra == "yaml"
45
46
  Provides-Extra: ingest
46
- Requires-Dist: pypdf>=6.15.0; extra == "ingest"
47
+ Requires-Dist: pypdf>=6.21.2; extra == "ingest"
47
48
  Requires-Dist: python-docx>=1.1; extra == "ingest"
48
49
  Requires-Dist: python-pptx>=0.6.23; extra == "ingest"
49
50
  Requires-Dist: openpyxl>=3.1; extra == "ingest"
50
- Requires-Dist: Pillow>=12.3.0; extra == "ingest"
51
+ Requires-Dist: Pillow>=13.0.0; python_version >= "3.11" and extra == "ingest"
52
+ Requires-Dist: Pillow>=12.3.0; python_version < "3.11" and extra == "ingest"
51
53
  Provides-Extra: dev
52
54
  Requires-Dist: pytest>=7; extra == "dev"
53
55
  Requires-Dist: build>=1; extra == "dev"
@@ -6,12 +6,17 @@ huggingface-hub>=0.20
6
6
  cryptography>=49
7
7
  PyYAML>=6
8
8
  regex>=2023.0.0
9
- pypdf>=6.15.0
9
+ pypdf>=6.21.2
10
10
  python-docx>=1.1
11
11
  python-pptx>=0.6.23
12
12
  openpyxl>=3.1
13
+
14
+ [:python_version < "3.11"]
13
15
  Pillow>=12.3.0
14
16
 
17
+ [:python_version >= "3.11"]
18
+ Pillow>=13.0.0
19
+
15
20
  [:sys_platform == "win32"]
16
21
  keyring>=24
17
22
 
@@ -45,12 +50,17 @@ numpy>=1.24
45
50
  regex>=2023.0.0
46
51
 
47
52
  [ingest]
48
- pypdf>=6.15.0
53
+ pypdf>=6.21.2
49
54
  python-docx>=1.1
50
55
  python-pptx>=0.6.23
51
56
  openpyxl>=3.1
57
+
58
+ [ingest:python_version < "3.11"]
52
59
  Pillow>=12.3.0
53
60
 
61
+ [ingest:python_version >= "3.11"]
62
+ Pillow>=13.0.0
63
+
54
64
  [mcp]
55
65
  mcp<2,>=1.30.0
56
66
 
File without changes