shellbrain 0.1.26__tar.gz → 0.1.27__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 (225) hide show
  1. {shellbrain-0.1.26 → shellbrain-0.1.27}/PKG-INFO +1 -1
  2. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/cli/main.py +12 -7
  3. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/metrics/artifacts.py +18 -1
  4. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/metrics/render_html.py +260 -16
  5. {shellbrain-0.1.26 → shellbrain-0.1.27}/pyproject.toml +1 -1
  6. {shellbrain-0.1.26 → shellbrain-0.1.27}/shellbrain.egg-info/PKG-INFO +1 -1
  7. {shellbrain-0.1.26 → shellbrain-0.1.27}/README.md +0 -0
  8. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/__init__.py +0 -0
  9. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/__main__.py +0 -0
  10. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/__init__.py +0 -0
  11. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/_dsn_resolution.py +0 -0
  12. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/admin_db.py +0 -0
  13. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/config.py +0 -0
  14. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/create_policy.py +0 -0
  15. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/db.py +0 -0
  16. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/embeddings.py +0 -0
  17. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/home.py +0 -0
  18. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/migrations.py +0 -0
  19. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/read_policy.py +0 -0
  20. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/repos.py +0 -0
  21. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/retrieval.py +0 -0
  22. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/thresholds.py +0 -0
  23. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/update_policy.py +0 -0
  24. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/boot/use_cases.py +0 -0
  25. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/config/__init__.py +0 -0
  26. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/config/defaults/create_policy.yaml +0 -0
  27. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/config/defaults/read_policy.yaml +0 -0
  28. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/config/defaults/runtime.yaml +0 -0
  29. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/config/defaults/thresholds.yaml +0 -0
  30. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/config/defaults/update_policy.yaml +0 -0
  31. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/config/loader.py +0 -0
  32. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/__init__.py +0 -0
  33. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/contracts/__init__.py +0 -0
  34. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/contracts/concepts.py +0 -0
  35. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/contracts/errors.py +0 -0
  36. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/contracts/requests.py +0 -0
  37. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/contracts/responses.py +0 -0
  38. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/entities/__init__.py +0 -0
  39. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/entities/associations.py +0 -0
  40. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/entities/concepts.py +0 -0
  41. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/entities/episodes.py +0 -0
  42. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/entities/evidence.py +0 -0
  43. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/entities/facts.py +0 -0
  44. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/entities/guidance.py +0 -0
  45. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/entities/identity.py +0 -0
  46. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/entities/memory.py +0 -0
  47. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/entities/runtime_context.py +0 -0
  48. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/entities/session_state.py +0 -0
  49. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/entities/telemetry.py +0 -0
  50. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/entities/utility.py +0 -0
  51. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/interfaces/__init__.py +0 -0
  52. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/interfaces/clock.py +0 -0
  53. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/interfaces/config.py +0 -0
  54. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/interfaces/embeddings.py +0 -0
  55. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/interfaces/idgen.py +0 -0
  56. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/interfaces/repos.py +0 -0
  57. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/interfaces/retrieval.py +0 -0
  58. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/interfaces/session_state_store.py +0 -0
  59. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/interfaces/unit_of_work.py +0 -0
  60. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/__init__.py +0 -0
  61. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/_shared/__init__.py +0 -0
  62. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/_shared/executor.py +0 -0
  63. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/_shared/side_effects.py +0 -0
  64. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/create_policy/__init__.py +0 -0
  65. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/create_policy/pipeline.py +0 -0
  66. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/read_policy/__init__.py +0 -0
  67. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/read_policy/bm25.py +0 -0
  68. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/read_policy/context_pack_builder.py +0 -0
  69. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/read_policy/expansion.py +0 -0
  70. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/read_policy/fusion_rrf.py +0 -0
  71. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/read_policy/lexical_query.py +0 -0
  72. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/read_policy/pipeline.py +0 -0
  73. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/read_policy/scoring.py +0 -0
  74. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/read_policy/seed_retrieval.py +0 -0
  75. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/update_policy/__init__.py +0 -0
  76. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/policies/update_policy/pipeline.py +0 -0
  77. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/use_cases/__init__.py +0 -0
  78. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/use_cases/build_guidance.py +0 -0
  79. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/use_cases/create_memory.py +0 -0
  80. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/use_cases/manage_concepts.py +0 -0
  81. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/use_cases/manage_session_state.py +0 -0
  82. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/use_cases/read_concepts.py +0 -0
  83. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/use_cases/read_memory.py +0 -0
  84. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/use_cases/record_episode_sync_telemetry.py +0 -0
  85. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/use_cases/record_model_usage_telemetry.py +0 -0
  86. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/use_cases/record_operation_telemetry.py +0 -0
  87. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/use_cases/sync_episode.py +0 -0
  88. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/core/use_cases/update_memory.py +0 -0
  89. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/__init__.py +0 -0
  90. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/env.py +0 -0
  91. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260226_0001_initial_schema.py +0 -0
  92. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260312_0002_add_hard_invariants.py +0 -0
  93. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260312_0003_drop_create_confidence.py +0 -0
  94. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260313_0004_episode_sync_hardening.py +0 -0
  95. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260313_0005_evidence_episode_event_refs.py +0 -0
  96. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260318_0006_usage_telemetry_schema.py +0 -0
  97. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260319_0007_identity_session_guidance.py +0 -0
  98. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260320_0008_instance_metadata_and_backup_safety.py +0 -0
  99. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260410_0009_frontier_memory_family.py +0 -0
  100. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260414_0010_model_usage_telemetry.py +0 -0
  101. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260414_0011_usage_problem_tokens_multi_solution_metrics.py +0 -0
  102. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260415_0012_read_pack_cost_and_read_roi.py +0 -0
  103. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260421_0013_concept_context_graph.py +0 -0
  104. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260422_0014_concept_read_telemetry.py +0 -0
  105. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/20260422_0015_problem_runs.py +0 -0
  106. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/migrations/versions/__init__.py +0 -0
  107. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/__init__.py +0 -0
  108. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/claude/CLAUDE.md +0 -0
  109. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/claude/skills/shellbrain-session-start/SKILL.md +0 -0
  110. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/claude/skills/shellbrain-usage-review/SKILL.md +0 -0
  111. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/codex/AGENTS.md +0 -0
  112. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/codex/shellbrain-session-start/SKILL.md +0 -0
  113. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/codex/shellbrain-session-start/agents/openai.yaml +0 -0
  114. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/codex/shellbrain-session-start/assets/shellbrain-large.svg +0 -0
  115. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/codex/shellbrain-session-start/assets/shellbrain-small.svg +0 -0
  116. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/codex/shellbrain-session-start/assets/shellbrain_logo.png +0 -0
  117. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/codex/shellbrain-session-start/references/request-shapes.md +0 -0
  118. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/codex/shellbrain-session-start/references/session-workflow.md +0 -0
  119. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/codex/shellbrain-usage-review/SKILL.md +0 -0
  120. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/codex/shellbrain-usage-review/agents/openai.yaml +0 -0
  121. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/codex/shellbrain-usage-review/assets/shellbrain-small.svg +0 -0
  122. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/codex/shellbrain-usage-review/assets/shellbrain_logo.png +0 -0
  123. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/cursor/skills/shellbrain-session-start/SKILL.md +0 -0
  124. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/onboarding_assets/cursor/skills/shellbrain-usage-review/SKILL.md +0 -0
  125. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/__init__.py +0 -0
  126. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/__init__.py +0 -0
  127. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/agent_behavior_analysis.py +0 -0
  128. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/analytics.py +0 -0
  129. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/analytics_diagnostics.py +0 -0
  130. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/analytics_queries.py +0 -0
  131. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/backup.py +0 -0
  132. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/destructive_guard.py +0 -0
  133. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/doctor.py +0 -0
  134. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/external_runtime.py +0 -0
  135. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/init.py +0 -0
  136. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/init_errors.py +0 -0
  137. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/instance_guard.py +0 -0
  138. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/machine_state.py +0 -0
  139. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/managed_runtime.py +0 -0
  140. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/model_usage_backfill.py +0 -0
  141. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/privileges.py +0 -0
  142. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/repo_state.py +0 -0
  143. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/restore.py +0 -0
  144. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/storage_setup.py +0 -0
  145. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/admin/upgrade.py +0 -0
  146. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/cli/__init__.py +0 -0
  147. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/cli/handlers.py +0 -0
  148. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/cli/hydration.py +0 -0
  149. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/cli/presenter_json.py +0 -0
  150. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/cli/schema_validation.py +0 -0
  151. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/__init__.py +0 -0
  152. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/engine.py +0 -0
  153. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/__init__.py +0 -0
  154. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/associations.py +0 -0
  155. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/concepts.py +0 -0
  156. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/episodes.py +0 -0
  157. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/evidence.py +0 -0
  158. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/experiences.py +0 -0
  159. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/instance_metadata.py +0 -0
  160. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/memories.py +0 -0
  161. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/metadata.py +0 -0
  162. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/problem_runs.py +0 -0
  163. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/registry.py +0 -0
  164. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/telemetry.py +0 -0
  165. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/utility.py +0 -0
  166. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/models/views.py +0 -0
  167. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/__init__.py +0 -0
  168. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/relational/__init__.py +0 -0
  169. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/relational/associations_repo.py +0 -0
  170. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/relational/concepts_repo.py +0 -0
  171. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/relational/episodes_repo.py +0 -0
  172. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/relational/evidence_repo.py +0 -0
  173. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/relational/experiences_repo.py +0 -0
  174. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/relational/memories_repo.py +0 -0
  175. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/relational/read_policy_repo.py +0 -0
  176. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/relational/telemetry_repo.py +0 -0
  177. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/relational/utility_repo.py +0 -0
  178. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/semantic/__init__.py +0 -0
  179. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/semantic/keyword_retrieval_repo.py +0 -0
  180. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/repos/semantic/semantic_retrieval_repo.py +0 -0
  181. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/session.py +0 -0
  182. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/db/uow.py +0 -0
  183. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/embeddings/__init__.py +0 -0
  184. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/embeddings/local_provider.py +0 -0
  185. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/embeddings/query_vector_search.py +0 -0
  186. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/episodes/__init__.py +0 -0
  187. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/episodes/claude_code.py +0 -0
  188. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/episodes/codex.py +0 -0
  189. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/episodes/cursor.py +0 -0
  190. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/episodes/launcher.py +0 -0
  191. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/episodes/model_usage.py +0 -0
  192. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/episodes/normalization.py +0 -0
  193. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/episodes/poller.py +0 -0
  194. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/episodes/poller_lock.py +0 -0
  195. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/episodes/source_discovery.py +0 -0
  196. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/episodes/tool_filter.py +0 -0
  197. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/identity/__init__.py +0 -0
  198. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/identity/claude_hook_install.py +0 -0
  199. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/identity/claude_runtime.py +0 -0
  200. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/identity/codex_runtime.py +0 -0
  201. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/identity/compatibility.py +0 -0
  202. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/identity/cursor_statusline.py +0 -0
  203. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/identity/resolver.py +0 -0
  204. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/metrics/__init__.py +0 -0
  205. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/metrics/browser.py +0 -0
  206. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/metrics/pager.py +0 -0
  207. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/metrics/queries.py +0 -0
  208. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/metrics/service.py +0 -0
  209. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/onboarding/__init__.py +0 -0
  210. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/onboarding/host_assets.py +0 -0
  211. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/session_state/__init__.py +0 -0
  212. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/session_state/file_store.py +0 -0
  213. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/telemetry/__init__.py +0 -0
  214. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/telemetry/operation_summary.py +0 -0
  215. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/telemetry/session_selection.py +0 -0
  216. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/telemetry/sync_summary.py +0 -0
  217. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/validation/__init__.py +0 -0
  218. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/validation/integrity_validation.py +0 -0
  219. {shellbrain-0.1.26 → shellbrain-0.1.27}/app/periphery/validation/semantic_validation.py +0 -0
  220. {shellbrain-0.1.26 → shellbrain-0.1.27}/setup.cfg +0 -0
  221. {shellbrain-0.1.26 → shellbrain-0.1.27}/shellbrain.egg-info/SOURCES.txt +0 -0
  222. {shellbrain-0.1.26 → shellbrain-0.1.27}/shellbrain.egg-info/dependency_links.txt +0 -0
  223. {shellbrain-0.1.26 → shellbrain-0.1.27}/shellbrain.egg-info/entry_points.txt +0 -0
  224. {shellbrain-0.1.26 → shellbrain-0.1.27}/shellbrain.egg-info/requires.txt +0 -0
  225. {shellbrain-0.1.26 → shellbrain-0.1.27}/shellbrain.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shellbrain
3
- Version: 0.1.26
3
+ Version: 0.1.27
4
4
  Summary: Repo-scoped Shellbrain CLI with explicit evidence-backed writes.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -260,7 +260,7 @@ _BACKFILL_TOKEN_USAGE_HELP = dedent(
260
260
 
261
261
  _METRICS_HELP = dedent(
262
262
  """\
263
- Generate lightweight metrics snapshots, write local artifacts, and browse repos with arrow keys.
263
+ Generate lightweight metrics snapshots, write local artifacts, and open one browser dashboard that switches repos with arrow keys.
264
264
 
265
265
  Example:
266
266
  shellbrain metrics
@@ -385,7 +385,7 @@ def build_parser() -> argparse.ArgumentParser:
385
385
  metrics_parser = subparsers.add_parser(
386
386
  "metrics",
387
387
  help="Browse Shellbrain metrics across repos.",
388
- description="Generate local metrics snapshots and browse one repo at a time in the terminal.",
388
+ description="Generate local metrics snapshots and open one browser dashboard for all repos.",
389
389
  epilog=_METRICS_HELP,
390
390
  formatter_class=_HelpFormatter,
391
391
  )
@@ -869,10 +869,9 @@ def _run_metrics_command(args: argparse.Namespace) -> int:
869
869
  from app.boot.admin_db import get_optional_admin_db_dsn
870
870
  from app.boot.db import get_optional_db_dsn
871
871
  from app.periphery.db.engine import get_engine
872
- from app.periphery.metrics.artifacts import write_metrics_artifacts
872
+ from app.periphery.metrics.artifacts import write_metrics_artifacts, write_metrics_index_artifact
873
873
  from app.periphery.metrics.browser import open_metrics_dashboard
874
- from app.periphery.metrics.pager import present_metrics_repo_pager
875
- from app.periphery.metrics.render_html import render_metrics_dashboard
874
+ from app.periphery.metrics.render_html import render_metrics_browser_dashboard, render_metrics_dashboard
876
875
  from app.periphery.metrics.service import build_metrics_snapshot, list_metrics_repo_ids
877
876
 
878
877
  if bool(getattr(args, "repo_id", None) or getattr(args, "repo_root", None) or getattr(args, "no_sync", False)):
@@ -901,11 +900,17 @@ def _run_metrics_command(args: argparse.Namespace) -> int:
901
900
  paths = write_metrics_artifacts(repo_id=repo_id, snapshot=snapshot, html=html)
902
901
  entries.append({"snapshot": snapshot, "paths": paths})
903
902
 
903
+ overview_path = write_metrics_index_artifact(
904
+ html=render_metrics_browser_dashboard([entry["snapshot"] for entry in entries])
905
+ )
906
+ opened_dashboard = bool(open_metrics_dashboard(overview_path))
904
907
  print(f"Generated Shellbrain metrics for {len(entries)} repos")
905
908
  print(f"Window: last {window_days} days")
906
909
  print("Artifacts: updated in place")
907
- print("Browser: press 'o' in the viewer to open the current dashboard")
908
- present_metrics_repo_pager(entries=entries, open_dashboard=open_metrics_dashboard)
910
+ if opened_dashboard:
911
+ print("Browser: opened dashboard; use left/right arrow keys in the browser to switch repos")
912
+ else:
913
+ print(f"Browser: could not open automatically; open {overview_path}")
909
914
  return 0
910
915
  except (RuntimeError, ValueError) as exc:
911
916
  print(str(exc), file=sys.stderr)
@@ -14,12 +14,18 @@ from app.boot.home import get_shellbrain_home
14
14
  _NON_ALNUM = re.compile(r"[^a-z0-9]+")
15
15
 
16
16
 
17
+ def get_metrics_root_dir() -> Path:
18
+ """Return the machine-owned root directory for metrics browser artifacts."""
19
+
20
+ return get_shellbrain_home() / "reports" / "metrics"
21
+
22
+
17
23
  def get_metrics_artifact_dir(*, repo_id: str) -> Path:
18
24
  """Return the machine-owned artifact directory for one repo's metrics outputs."""
19
25
 
20
26
  normalized = _NON_ALNUM.sub("-", repo_id.lower()).strip("-") or "repo"
21
27
  digest = hashlib.sha1(repo_id.encode("utf-8")).hexdigest()[:8]
22
- return get_shellbrain_home() / "reports" / "metrics" / f"{normalized}-{digest}"
28
+ return get_metrics_root_dir() / f"{normalized}-{digest}"
23
29
 
24
30
 
25
31
  def write_metrics_artifacts(*, repo_id: str, snapshot: dict[str, Any], html: str) -> dict[str, Path]:
@@ -42,3 +48,14 @@ def write_metrics_artifacts(*, repo_id: str, snapshot: dict[str, Any], html: str
42
48
  "md_path": md_path,
43
49
  "html_path": html_path,
44
50
  }
51
+
52
+
53
+ def write_metrics_index_artifact(*, html: str) -> Path:
54
+ """Write the combined browser dashboard for all repo metrics snapshots."""
55
+
56
+ artifact_dir = get_metrics_root_dir()
57
+ artifact_dir.mkdir(parents=True, exist_ok=True)
58
+
59
+ html_path = artifact_dir / "index.html"
60
+ html_path.write_text(html, encoding="utf-8")
61
+ return html_path
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from html import escape
6
- from typing import Any
6
+ from typing import Any, Sequence
7
7
 
8
8
 
9
9
  _PAGE_CSS = """
@@ -220,9 +220,266 @@ body {
220
220
  """
221
221
 
222
222
 
223
+ _BROWSER_CSS = """
224
+ .browser-shell {
225
+ max-width: 1440px;
226
+ margin: 0 auto;
227
+ padding: 24px 28px 64px;
228
+ }
229
+
230
+ .browser-masthead {
231
+ display: flex;
232
+ justify-content: space-between;
233
+ gap: 24px;
234
+ align-items: flex-end;
235
+ padding-bottom: 18px;
236
+ border-bottom: 1px solid var(--border);
237
+ }
238
+
239
+ .browser-masthead h1 {
240
+ font-size: 28px;
241
+ font-weight: 700;
242
+ letter-spacing: -0.03em;
243
+ }
244
+
245
+ .browser-meta {
246
+ display: flex;
247
+ gap: 8px;
248
+ align-items: center;
249
+ flex-wrap: wrap;
250
+ }
251
+
252
+ .browser-keyhint {
253
+ margin-top: 12px;
254
+ color: var(--muted);
255
+ font-size: 12px;
256
+ }
257
+
258
+ .repo-tab-row {
259
+ margin-top: 18px;
260
+ display: flex;
261
+ gap: 8px;
262
+ flex-wrap: wrap;
263
+ }
264
+
265
+ .repo-tab {
266
+ appearance: none;
267
+ border: 1px solid var(--border);
268
+ border-radius: 999px;
269
+ background: var(--surface);
270
+ color: var(--text-dim);
271
+ padding: 8px 12px;
272
+ font: inherit;
273
+ font-size: 12px;
274
+ cursor: pointer;
275
+ transition: background 140ms ease, color 140ms ease, border-color 140ms ease;
276
+ }
277
+
278
+ .repo-tab.is-active {
279
+ background: var(--accent);
280
+ border-color: var(--accent);
281
+ color: white;
282
+ }
283
+
284
+ .repo-browser {
285
+ margin-top: 20px;
286
+ }
287
+
288
+ .repo-panel[hidden] {
289
+ display: none !important;
290
+ }
291
+ """
292
+
293
+
294
+ _BROWSER_SCRIPT = """
295
+ <script>
296
+ (() => {
297
+ const panels = Array.from(document.querySelectorAll(".repo-panel"));
298
+ const tabs = Array.from(document.querySelectorAll(".repo-tab"));
299
+ const position = document.getElementById("repo-position");
300
+ const status = document.getElementById("repo-status");
301
+ if (!panels.length) {
302
+ return;
303
+ }
304
+
305
+ let index = 0;
306
+
307
+ const show = (nextIndex) => {
308
+ index = (nextIndex + panels.length) % panels.length;
309
+ panels.forEach((panel, panelIndex) => {
310
+ const active = panelIndex === index;
311
+ panel.hidden = !active;
312
+ panel.setAttribute("aria-hidden", active ? "false" : "true");
313
+ });
314
+ tabs.forEach((tab, tabIndex) => {
315
+ const active = tabIndex === index;
316
+ tab.classList.toggle("is-active", active);
317
+ tab.setAttribute("aria-pressed", active ? "true" : "false");
318
+ tab.tabIndex = active ? 0 : -1;
319
+ });
320
+
321
+ const activePanel = panels[index];
322
+ const repoId = activePanel.dataset.repoId || "";
323
+ const tone = activePanel.dataset.tone || "neutral";
324
+ const statusText = activePanel.dataset.status || "unknown";
325
+
326
+ if (position) {
327
+ position.textContent = `${index + 1} / ${panels.length}`;
328
+ }
329
+ if (status) {
330
+ status.className = `pill ${tone}`;
331
+ status.textContent = statusText.replaceAll("_", " ");
332
+ status.setAttribute("aria-label", `${repoId} status ${statusText}`);
333
+ }
334
+ document.title = `Shellbrain Metrics - ${repoId}`;
335
+ if (window.history && window.history.replaceState) {
336
+ window.history.replaceState(null, "", `#repo-${index + 1}`);
337
+ }
338
+ };
339
+
340
+ document.addEventListener("keydown", (event) => {
341
+ if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey) {
342
+ return;
343
+ }
344
+
345
+ const target = event.target;
346
+ const tagName = target && target.tagName ? target.tagName.toLowerCase() : "";
347
+ if (tagName === "input" || tagName === "textarea" || tagName === "select") {
348
+ return;
349
+ }
350
+ if (target && target.isContentEditable) {
351
+ return;
352
+ }
353
+
354
+ if (event.key === "ArrowRight") {
355
+ event.preventDefault();
356
+ show(index + 1);
357
+ }
358
+ if (event.key === "ArrowLeft") {
359
+ event.preventDefault();
360
+ show(index - 1);
361
+ }
362
+ });
363
+
364
+ tabs.forEach((tab, tabIndex) => {
365
+ tab.addEventListener("click", () => show(tabIndex));
366
+ });
367
+
368
+ const hashMatch = window.location.hash.match(/^#repo-(\\d+)$/);
369
+ if (hashMatch) {
370
+ const parsed = Number(hashMatch[1]);
371
+ if (!Number.isNaN(parsed) && parsed >= 1 && parsed <= panels.length) {
372
+ index = parsed - 1;
373
+ }
374
+ }
375
+
376
+ show(index);
377
+ })();
378
+ </script>
379
+ """
380
+
381
+
223
382
  def render_metrics_dashboard(snapshot: dict[str, Any]) -> str:
224
383
  """Render one self-contained HTML dashboard from a metrics snapshot."""
225
384
 
385
+ return f"""<!DOCTYPE html>
386
+ <html lang="en">
387
+ <head>
388
+ <meta charset="UTF-8">
389
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
390
+ <title>Shellbrain Metrics</title>
391
+ <link rel="icon" href="data:,">
392
+ <style>{_PAGE_CSS}</style>
393
+ </head>
394
+ <body>
395
+ <div class="shell">
396
+ {_render_snapshot_content(snapshot)}
397
+ </div>
398
+ </body>
399
+ </html>
400
+ """
401
+
402
+
403
+ def render_metrics_browser_dashboard(snapshots: Sequence[dict[str, Any]]) -> str:
404
+ """Render one browser dashboard that switches repos with in-page arrow-key navigation."""
405
+
406
+ normalized = [snapshot for snapshot in snapshots if isinstance(snapshot, dict)]
407
+ if not normalized:
408
+ return """<!DOCTYPE html>
409
+ <html lang="en">
410
+ <head>
411
+ <meta charset="UTF-8">
412
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
413
+ <title>Shellbrain Metrics</title>
414
+ <link rel="icon" href="data:,">
415
+ <style>body{font-family:system-ui,sans-serif;padding:24px}</style>
416
+ </head>
417
+ <body><p>No metrics snapshots are available.</p></body>
418
+ </html>
419
+ """
420
+
421
+ first_snapshot = normalized[0]
422
+ tabs = "".join(
423
+ f"<button type=\"button\" class=\"repo-tab{' is-active' if index == 0 else ''}\" aria-pressed=\"{'true' if index == 0 else 'false'}\">{escape(str(snapshot['repo_id']))}</button>"
424
+ for index, snapshot in enumerate(normalized)
425
+ )
426
+ panels = "".join(
427
+ _render_browser_panel(snapshot=snapshot, index=index)
428
+ for index, snapshot in enumerate(normalized)
429
+ )
430
+ first_tone = _tone_for_status(str(first_snapshot["status"]))
431
+
432
+ return f"""<!DOCTYPE html>
433
+ <html lang="en">
434
+ <head>
435
+ <meta charset="UTF-8">
436
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
437
+ <title>Shellbrain Metrics - {escape(str(first_snapshot["repo_id"]))}</title>
438
+ <link rel="icon" href="data:,">
439
+ <style>{_PAGE_CSS}{_BROWSER_CSS}</style>
440
+ </head>
441
+ <body>
442
+ <div class="browser-shell">
443
+ <header class="browser-masthead">
444
+ <div>
445
+ <p class="eyebrow">Shellbrain Metrics</p>
446
+ <h1>All Repos</h1>
447
+ <div class="subtle">Opened automatically. Use the left and right arrow keys in this page to switch repos.</div>
448
+ </div>
449
+ <div class="browser-meta">
450
+ <span id="repo-position" class="pill neutral">1 / {len(normalized)}</span>
451
+ <span id="repo-status" class="pill {first_tone}">{escape(str(first_snapshot["status"]).replace("_", " "))}</span>
452
+ </div>
453
+ </header>
454
+ <div class="browser-keyhint">Left/Right arrow keys switch repos in this page. No terminal input is required.</div>
455
+ <nav class="repo-tab-row" aria-label="Tracked repos">
456
+ {tabs}
457
+ </nav>
458
+ <main class="repo-browser">
459
+ {panels}
460
+ </main>
461
+ </div>
462
+ {_BROWSER_SCRIPT}
463
+ </body>
464
+ </html>
465
+ """
466
+
467
+
468
+ def _render_browser_panel(*, snapshot: dict[str, Any], index: int) -> str:
469
+ """Render one repo panel for the multi-repo browser dashboard."""
470
+
471
+ tone = _tone_for_status(str(snapshot["status"]))
472
+ hidden_attr = "" if index == 0 else " hidden"
473
+ return f"""
474
+ <section class="repo-panel" data-repo-id="{escape(str(snapshot["repo_id"]))}" data-status="{escape(str(snapshot["status"]))}" data-tone="{tone}" aria-hidden="{'false' if index == 0 else 'true'}"{hidden_attr}>
475
+ {_render_snapshot_content(snapshot)}
476
+ </section>
477
+ """
478
+
479
+
480
+ def _render_snapshot_content(snapshot: dict[str, Any]) -> str:
481
+ """Render the shared snapshot content used by single-repo and multi-repo dashboards."""
482
+
226
483
  status_tone = _tone_for_status(str(snapshot["status"]))
227
484
  alert_html = ""
228
485
  if snapshot["alerts"]:
@@ -238,17 +495,7 @@ def render_metrics_dashboard(snapshot: dict[str, Any]) -> str:
238
495
  generated_at = escape(str(snapshot["generated_at"]).replace("T", " ").replace("+00:00", " UTC"))
239
496
  current_window = snapshot["current_window"]
240
497
 
241
- return f"""<!DOCTYPE html>
242
- <html lang="en">
243
- <head>
244
- <meta charset="UTF-8">
245
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
246
- <title>Shellbrain Metrics</title>
247
- <link rel="icon" href="data:,">
248
- <style>{_PAGE_CSS}</style>
249
- </head>
250
- <body>
251
- <div class="shell">
498
+ return f"""
252
499
  <section class="status-strip {status_tone}">
253
500
  <div>
254
501
  <p class="eyebrow">Shellbrain Metrics</p>
@@ -279,10 +526,7 @@ def render_metrics_dashboard(snapshot: dict[str, Any]) -> str:
279
526
  {metric_cards}
280
527
  </section>
281
528
  </main>
282
- </div>
283
- </body>
284
- </html>
285
- """
529
+ """
286
530
 
287
531
 
288
532
  def _render_metric_card(metric: dict[str, Any]) -> str:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "shellbrain"
7
- version = "0.1.26"
7
+ version = "0.1.27"
8
8
  description = "Repo-scoped Shellbrain CLI with explicit evidence-backed writes."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shellbrain
3
- Version: 0.1.26
3
+ Version: 0.1.27
4
4
  Summary: Repo-scoped Shellbrain CLI with explicit evidence-backed writes.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
File without changes
File without changes
File without changes
File without changes