agent-notes 2.15.1__tar.gz → 2.16.0__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 (235) hide show
  1. {agent_notes-2.15.1 → agent_notes-2.16.0}/PKG-INFO +1 -2
  2. {agent_notes-2.15.1 → agent_notes-2.16.0}/README.md +0 -1
  3. agent_notes-2.16.0/agent_notes/VERSION +1 -0
  4. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/cli.py +0 -18
  5. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/__init__.py +1 -2
  6. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/doctor.py +40 -5
  7. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/wizard.py +23 -17
  8. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/config.py +43 -53
  9. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/hooks/session-context.md.tpl +1 -1
  10. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/doctor_checks.py +8 -0
  11. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/domain/state.py +1 -0
  12. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/scripts/cost_report.py +2 -2
  13. agent_notes-2.16.0/agent_notes/services/counts.py +67 -0
  14. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/diagnostics/_checks.py +33 -49
  15. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/diagnostics/_display.py +11 -42
  16. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/install_state_builder.py +2 -0
  17. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/installer.py +4 -1
  18. agent_notes-2.16.0/agent_notes/services/session_context.py +36 -0
  19. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/state_store.py +2 -0
  20. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes.egg-info/PKG-INFO +1 -2
  21. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes.egg-info/SOURCES.txt +3 -2
  22. agent_notes-2.16.0/tests/functional/commands/test_doctor_command.py +404 -0
  23. agent_notes-2.16.0/tests/unit/services/test_session_context.py +132 -0
  24. agent_notes-2.16.0/tests/unit/test_import_health.py +260 -0
  25. agent_notes-2.15.1/agent_notes/VERSION +0 -1
  26. agent_notes-2.15.1/agent_notes/commands/update.py +0 -169
  27. agent_notes-2.15.1/agent_notes/services/session_context.py +0 -23
  28. agent_notes-2.15.1/tests/functional/commands/test_doctor_command.py +0 -150
  29. agent_notes-2.15.1/tests/functional/commands/test_update_command.py +0 -110
  30. {agent_notes-2.15.1 → agent_notes-2.16.0}/LICENSE +0 -0
  31. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/__init__.py +0 -0
  32. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/__main__.py +0 -0
  33. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/_install_helpers.py +0 -0
  34. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/build.py +0 -0
  35. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/config.py +0 -0
  36. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/info.py +0 -0
  37. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/install.py +0 -0
  38. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/list.py +0 -0
  39. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/memory.py +0 -0
  40. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/regenerate.py +0 -0
  41. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/set_role.py +0 -0
  42. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/uninstall.py +0 -0
  43. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/commands/validate.py +0 -0
  44. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/agents.yaml +0 -0
  45. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/analyst.md +0 -0
  46. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/api-reviewer.md +0 -0
  47. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/architect.md +0 -0
  48. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/coder.md +0 -0
  49. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/database-specialist.md +0 -0
  50. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/debugger.md +0 -0
  51. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/devil.md +0 -0
  52. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/devops.md +0 -0
  53. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/explorer.md +0 -0
  54. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/integrations.md +0 -0
  55. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/lead.md +0 -0
  56. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/performance-profiler.md +0 -0
  57. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/refactorer.md +0 -0
  58. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/reviewer.md +0 -0
  59. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/security-auditor.md +0 -0
  60. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/shared/cost_reporting.md +0 -0
  61. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/shared/phase0.md +0 -0
  62. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/system-auditor.md +0 -0
  63. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/tech-writer.md +0 -0
  64. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/test-runner.md +0 -0
  65. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/agents/test-writer.md +0 -0
  66. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/cli/claude.yaml +0 -0
  67. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/cli/copilot.yaml +0 -0
  68. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/cli/opencode.yaml +0 -0
  69. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/commands/brainstorm.md +0 -0
  70. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/commands/debug.md +0 -0
  71. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/commands/review.md +0 -0
  72. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/global-claude.md +0 -0
  73. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/global-copilot.md +0 -0
  74. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/global-opencode.md +0 -0
  75. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/models/claude-haiku-4-5.yaml +0 -0
  76. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/models/claude-opus-4-1.yaml +0 -0
  77. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/models/claude-opus-4-5.yaml +0 -0
  78. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/models/claude-opus-4-6.yaml +0 -0
  79. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/models/claude-opus-4-7.yaml +0 -0
  80. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/models/claude-sonnet-4-5.yaml +0 -0
  81. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/models/claude-sonnet-4-6.yaml +0 -0
  82. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/models/claude-sonnet-4.yaml +0 -0
  83. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/plugin/claude.yaml +0 -0
  84. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/plugin/opencode-index.js.template +0 -0
  85. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/plugin/opencode.yaml +0 -0
  86. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/pricing.yaml +0 -0
  87. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/roles/orchestrator.yaml +0 -0
  88. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/roles/reasoner.yaml +0 -0
  89. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/roles/scout.yaml +0 -0
  90. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/roles/worker.yaml +0 -0
  91. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/rules/code-quality.md +0 -0
  92. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/rules/safety.md +0 -0
  93. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/brainstorming/SKILL.md +0 -0
  94. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/caveman/SKILL.md +0 -0
  95. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/code-review/SKILL.md +0 -0
  96. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/debugging-protocol/SKILL.md +0 -0
  97. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/docker-compose/SKILL.md +0 -0
  98. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/docker-compose-advanced/SKILL.md +0 -0
  99. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/docker-dockerfile/SKILL.md +0 -0
  100. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/docker-dockerfile-languages/SKILL.md +0 -0
  101. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/git/SKILL.md +0 -0
  102. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/grill-me/SKILL.md +0 -0
  103. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/grill-with-docs/SKILL.md +0 -0
  104. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/improve-codebase-architecture/SKILL.md +0 -0
  105. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/obsidian-memory/SKILL.md +0 -0
  106. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-active-storage/SKILL.md +0 -0
  107. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-broadcasting/SKILL.md +0 -0
  108. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-concerns/SKILL.md +0 -0
  109. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-controllers/SKILL.md +0 -0
  110. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-controllers-advanced/SKILL.md +0 -0
  111. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-helpers/SKILL.md +0 -0
  112. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-initializers/SKILL.md +0 -0
  113. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-javascript/SKILL.md +0 -0
  114. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-jobs/SKILL.md +0 -0
  115. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-kamal/SKILL.md +0 -0
  116. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-lib/SKILL.md +0 -0
  117. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-mailers/SKILL.md +0 -0
  118. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-migrations/SKILL.md +0 -0
  119. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-models/SKILL.md +0 -0
  120. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-models-advanced/SKILL.md +0 -0
  121. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-routes/SKILL.md +0 -0
  122. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-style/SKILL.md +0 -0
  123. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-testing-controllers/SKILL.md +0 -0
  124. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-testing-models/SKILL.md +0 -0
  125. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-testing-system/SKILL.md +0 -0
  126. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-validations/SKILL.md +0 -0
  127. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-view-components/SKILL.md +0 -0
  128. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-view-components-advanced/SKILL.md +0 -0
  129. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-views/SKILL.md +0 -0
  130. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/rails-views-advanced/SKILL.md +0 -0
  131. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/refactoring-protocol/SKILL.md +0 -0
  132. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/setup-project-context/SKILL.md +0 -0
  133. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/tdd/SKILL.md +0 -0
  134. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/skills/zoom-out/SKILL.md +0 -0
  135. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/templates/__init__.py +0 -0
  136. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/templates/__pycache__/__init__.cpython-314.pyc +0 -0
  137. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/templates/frontmatter/__init__.py +0 -0
  138. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/templates/frontmatter/__pycache__/__init__.cpython-314.pyc +0 -0
  139. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/templates/frontmatter/__pycache__/claude.cpython-314.pyc +0 -0
  140. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/templates/frontmatter/__pycache__/opencode.cpython-314.pyc +0 -0
  141. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/templates/frontmatter/claude.py +0 -0
  142. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/data/templates/frontmatter/opencode.py +0 -0
  143. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/domain/__init__.py +0 -0
  144. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/domain/agent.py +0 -0
  145. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/domain/cli_backend.py +0 -0
  146. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/domain/diagnostics.py +0 -0
  147. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/domain/diff.py +0 -0
  148. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/domain/model.py +0 -0
  149. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/domain/role.py +0 -0
  150. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/domain/rule.py +0 -0
  151. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/domain/skill.py +0 -0
  152. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/install_state.py +0 -0
  153. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/registries/__init__.py +0 -0
  154. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/registries/_base.py +0 -0
  155. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/registries/agent_registry.py +0 -0
  156. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/registries/cli_registry.py +0 -0
  157. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/registries/model_registry.py +0 -0
  158. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/registries/role_registry.py +0 -0
  159. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/registries/rule_registry.py +0 -0
  160. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/registries/skill_registry.py +0 -0
  161. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/scripts/__init__.py +0 -0
  162. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/scripts/_claude_backend.py +0 -0
  163. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/scripts/_formatting.py +0 -0
  164. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/scripts/_opencode_backend.py +0 -0
  165. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/scripts/_pricing.py +0 -0
  166. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/__init__.py +0 -0
  167. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/credentials.py +0 -0
  168. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/diagnostics/__init__.py +0 -0
  169. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/diagnostics/_fix.py +0 -0
  170. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/diff.py +0 -0
  171. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/fs.py +0 -0
  172. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/memory_backend.py +0 -0
  173. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/rendering.py +0 -0
  174. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/settings_writer.py +0 -0
  175. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/ui.py +0 -0
  176. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/user_config.py +0 -0
  177. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/validation.py +0 -0
  178. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/services/wiki_backend.py +0 -0
  179. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes/state.py +0 -0
  180. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes.egg-info/dependency_links.txt +0 -0
  181. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes.egg-info/entry_points.txt +0 -0
  182. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes.egg-info/requires.txt +0 -0
  183. {agent_notes-2.15.1 → agent_notes-2.16.0}/agent_notes.egg-info/top_level.txt +0 -0
  184. {agent_notes-2.15.1 → agent_notes-2.16.0}/pyproject.toml +0 -0
  185. {agent_notes-2.15.1 → agent_notes-2.16.0}/setup.cfg +0 -0
  186. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/conftest.py +0 -0
  187. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/functional/__init__.py +0 -0
  188. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/functional/commands/__init__.py +0 -0
  189. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/functional/commands/test_config_command.py +0 -0
  190. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/functional/commands/test_info_command.py +0 -0
  191. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/functional/commands/test_install_command.py +0 -0
  192. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/functional/commands/test_list_command.py +0 -0
  193. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/functional/commands/test_regenerate_command.py +0 -0
  194. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/functional/commands/test_uninstall_command.py +0 -0
  195. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/functional/commands/test_validate_command.py +0 -0
  196. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/functional/memory/__init__.py +0 -0
  197. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/functional/memory/test_memory_command.py +0 -0
  198. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/functional/scripts/__init__.py +0 -0
  199. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/functional/scripts/test_release_script.py +0 -0
  200. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/integration/__init__.py +0 -0
  201. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/integration/build_output/__init__.py +0 -0
  202. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/integration/build_output/test_build_output.py +0 -0
  203. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/integration/install/__init__.py +0 -0
  204. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/integration/install/test_install_methods.py +0 -0
  205. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/integration/plugin_builders/__init__.py +0 -0
  206. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/integration/plugin_builders/test_plugin_builders.py +0 -0
  207. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/plugins/__init__.py +0 -0
  208. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/plugins/claude/__init__.py +0 -0
  209. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/plugins/claude/test_agents.py +0 -0
  210. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/plugins/test_skills.py +0 -0
  211. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/__init__.py +0 -0
  212. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/commands/__init__.py +0 -0
  213. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/commands/test_cost_report_subcommand.py +0 -0
  214. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/commands/test_count_agents.py +0 -0
  215. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/commands/test_memory_migrate.py +0 -0
  216. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/commands/test_wizard_orchestrator_skip.py +0 -0
  217. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/commands/test_wizard_preflight.py +0 -0
  218. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/registries/__init__.py +0 -0
  219. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/registries/test_registries.py +0 -0
  220. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/scripts/__init__.py +0 -0
  221. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/scripts/test_cost_report.py +0 -0
  222. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/scripts/test_cost_report_scoping.py +0 -0
  223. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/scripts/test_formatting_tty.py +0 -0
  224. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/scripts/test_time_aggregation.py +0 -0
  225. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/services/__init__.py +0 -0
  226. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/services/test_build_functions.py +0 -0
  227. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/services/test_credentials.py +0 -0
  228. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/services/test_fs.py +0 -0
  229. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/services/test_installer_plan.py +0 -0
  230. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/services/test_memory_backend.py +0 -0
  231. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/services/test_memory_backend_io.py +0 -0
  232. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/services/test_rendering_includes.py +0 -0
  233. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/services/test_settings_writer.py +0 -0
  234. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/services/test_wiki_backend.py +0 -0
  235. {agent_notes-2.15.1 → agent_notes-2.16.0}/tests/unit/test_memory_dir_for_backend.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-notes
3
- Version: 2.15.1
3
+ Version: 2.16.0
4
4
  Summary: AI agent configuration manager for Claude Code, OpenCode, and Copilot
5
5
  Author-email: Eugene Naumov <min.verkligheten@gmail.com>
6
6
  License-Expression: MIT
@@ -115,7 +115,6 @@ agent-notes <command> [options]
115
115
  |---------|-------------|
116
116
  | `install [--local] [--copy]` | Interactive wizard or direct install |
117
117
  | `uninstall [--local]` | Remove installed components |
118
- | `update` | Pull latest, rebuild, reinstall |
119
118
  | `doctor [--local] [--fix]` | Check installation health |
120
119
  | `info` | Show status and component counts |
121
120
  | `list [clis\|models\|roles\|agents\|skills\|rules\|all]` | List engine components or installed |
@@ -85,7 +85,6 @@ agent-notes <command> [options]
85
85
  |---------|-------------|
86
86
  | `install [--local] [--copy]` | Interactive wizard or direct install |
87
87
  | `uninstall [--local]` | Remove installed components |
88
- | `update` | Pull latest, rebuild, reinstall |
89
88
  | `doctor [--local] [--fix]` | Check installation health |
90
89
  | `info` | Show status and component counts |
91
90
  | `list [clis\|models\|roles\|agents\|skills\|rules\|all]` | List engine components or installed |
@@ -0,0 +1 @@
1
+ 2.16.0
@@ -237,15 +237,6 @@ def main():
237
237
  p_uninstall = subparsers.add_parser("uninstall", help="Remove installed components")
238
238
  p_uninstall.add_argument("--local", action="store_true", help="Remove from current project")
239
239
 
240
- # update
241
- p_update = subparsers.add_parser("update", help="Pull latest, show diff, reinstall")
242
- p_update.add_argument("--dry-run", action="store_true", help="Show diff only, do not reinstall")
243
- p_update.add_argument("-y", "--yes", action="store_true", help="Skip confirmation prompt")
244
- p_update.add_argument("--only", action="append", choices=["agents","skills","rules","commands","config","settings"],
245
- help="Filter diff to these component types (repeatable)")
246
- p_update.add_argument("--since", help="Override 'before' commit label (cosmetic only for now)")
247
- p_update.add_argument("--skip-pull", action="store_true", help="Skip git pull")
248
-
249
240
  # doctor
250
241
  p_doctor = subparsers.add_parser("doctor", help="Check installation health")
251
242
  p_doctor.add_argument("--local", action="store_true", help="Check local installation")
@@ -325,15 +316,6 @@ def main():
325
316
  elif args.command == "uninstall":
326
317
  from .commands.install import uninstall
327
318
  uninstall(local=args.local)
328
- elif args.command == "update":
329
- from .commands.update import update
330
- update(
331
- dry_run=args.dry_run,
332
- yes=args.yes,
333
- only=args.only,
334
- since=args.since,
335
- skip_pull=args.skip_pull,
336
- )
337
319
  elif args.command == "doctor":
338
320
  from .commands.doctor import doctor
339
321
  doctor(local=args.local, fix=args.fix)
@@ -14,14 +14,13 @@ from . import uninstall
14
14
  from . import build
15
15
  from . import doctor
16
16
  from . import validate
17
- from . import update
18
17
  from . import regenerate
19
18
  from . import list as list_cmd
20
19
  from . import memory as memory_cmd
21
20
 
22
21
  __all__ = [
23
22
  "install", "uninstall", "show_info",
24
- "build", "doctor", "validate", "update",
23
+ "build", "doctor", "validate",
25
24
  "regenerate", "set_role", "interactive_install",
26
25
  "list_cmd", "memory_cmd",
27
26
  ]
@@ -62,25 +62,60 @@ def _check_session_hook(scope: str, issues: list) -> None:
62
62
  ))
63
63
 
64
64
 
65
+ def check_version_drift(scope: str, issues: list, fix_actions: list) -> None:
66
+ """Check if the installed package version matches the current running version."""
67
+ from .. import install_state
68
+ from ..config import get_version
69
+ from ..domain.diagnostics import Issue, FixAction
70
+ from ..services.state_store import get_scope
71
+ from pathlib import Path
72
+
73
+ state = install_state.load_current_state()
74
+ if state is None:
75
+ return
76
+
77
+ project_path = Path.cwd() if scope == "local" else None
78
+ scope_state = get_scope(state, scope, project_path)
79
+ if scope_state is None:
80
+ return
81
+
82
+ installed_version = scope_state.installed_version
83
+ if not installed_version:
84
+ return
85
+
86
+ current_version = get_version()
87
+ if installed_version != current_version:
88
+ issues.append(Issue(
89
+ "version_drift",
90
+ "state.json",
91
+ f"Installed with v{installed_version} but running v{current_version}. "
92
+ "Run `agent-notes doctor --fix` or `agent-notes install` to update.",
93
+ ))
94
+ fix_actions.append(FixAction("_TRIGGER_INSTALL", "state.json", "reinstall to update"))
95
+
96
+
65
97
  def diagnose(scope: str, fix: bool = False) -> bool:
66
98
  """Run all diagnostic checks and optionally apply fixes."""
67
99
  from .. import install_state
68
-
100
+
69
101
  print_summary(scope)
70
-
102
+
71
103
  issues = []
72
104
  fix_actions = []
73
-
105
+
74
106
  # Run checks
75
107
  check_stale_files(scope, issues, fix_actions)
76
- check_broken_symlinks(scope, issues, fix_actions)
108
+ check_broken_symlinks(scope, issues, fix_actions)
77
109
  check_shadowed_files(scope, issues, fix_actions)
78
110
  check_missing_files(scope, issues, fix_actions)
79
111
  check_content_drift(scope, issues, fix_actions)
80
-
112
+
81
113
  # Build freshness check (scope-independent)
82
114
  check_build_freshness(issues, fix_actions)
83
115
 
116
+ # Version drift check
117
+ check_version_drift(scope, issues, fix_actions)
118
+
84
119
  # SessionStart hook check (Claude Code only)
85
120
  _check_session_hook(scope, issues)
86
121
 
@@ -8,6 +8,7 @@ from .build import build
8
8
  from ._install_helpers import (
9
9
  count_agents, count_global, count_skills
10
10
  )
11
+ from ..services.counts import count_rules_total as _count_rules_total
11
12
  from ..services.fs import place_file, place_dir_contents
12
13
  from ..services.ui import (
13
14
  _can_interactive, _safe_input, _checkbox_select, _radio_select,
@@ -79,22 +80,7 @@ def _get_skill_groups() -> Dict[str, List[str]]:
79
80
 
80
81
  def _count_rules() -> int:
81
82
  """Count rule files."""
82
- # For testing, allow bypassing the registry
83
- import os
84
- if os.environ.get('_WIZARD_TEST_MODE'):
85
- if not DIST_RULES_DIR.exists():
86
- return 0
87
- return len(list(DIST_RULES_DIR.glob("*.md")))
88
- else:
89
- try:
90
- from ..registries import default_rule_registry
91
- registry = default_rule_registry()
92
- return len(registry.all())
93
- except Exception:
94
- # Fallback to old behavior if registry fails
95
- if not DIST_RULES_DIR.exists():
96
- return 0
97
- return len(list(DIST_RULES_DIR.glob("*.md")))
83
+ return _count_rules_total()
98
84
 
99
85
 
100
86
  def _select_cli(step: int = 0, total: int = 0, version: str = '') -> Set[str]:
@@ -629,7 +615,27 @@ def _interactive_install() -> None:
629
615
  print(f"{Color.RED}Build failed: {e}{Color.NC}")
630
616
  return
631
617
 
632
- # Execute installation
618
+ _execute_install(
619
+ clis=clis,
620
+ scope=scope,
621
+ copy_mode=copy_mode,
622
+ selected_skills=selected_skills,
623
+ role_models=role_models,
624
+ memory_backend=memory_backend,
625
+ memory_path=memory_path,
626
+ )
627
+
628
+
629
+ def _execute_install(
630
+ clis: Set[str],
631
+ scope: str,
632
+ copy_mode: bool,
633
+ selected_skills: List[str],
634
+ role_models: Dict[str, Dict[str, str]],
635
+ memory_backend: str,
636
+ memory_path: str,
637
+ ) -> None:
638
+ """Run all installation steps after parameters have been collected and the build is done."""
633
639
  print(f"\nInstalling ({scope}, {'copy' if copy_mode else 'symlink'}) ...\n")
634
640
 
635
641
  from ..services import fs as _fs
@@ -91,56 +91,46 @@ def global_output_path(backend) -> Optional[Path]:
91
91
  return dist_dir_for(backend) / backend.layout["config"]
92
92
 
93
93
 
94
- # === Backward compatibility - lazy evaluation of old constants ===
95
- def _lazy_backend_attr(backend_name: str, attr_func):
96
- """Helper for creating lazy attributes that depend on registry.
97
-
98
- Note: at initial config-module import time, ``agent_notes.cli_backend`` is
99
- NOT safe to import (circular). In that case we fall back to hardcoded
100
- values that match the shipped YAMLs. Later callers who import these
101
- constants after initial module load get the correct values via this same
102
- function (the registry is then importable).
103
- """
104
- def get_attr():
105
- try:
106
- from .registries.cli_registry import default_registry
107
- backend = default_registry().get(backend_name)
108
- return attr_func(backend)
109
- except (ImportError, KeyError):
110
- # Fallback to hardcoded values if registry not available (e.g. circular
111
- # import at initial module-load time). These match the shipped YAMLs.
112
- fallbacks = {
113
- 'claude': {'home': Path.home() / ".claude", 'template': "global-claude.md", 'dist': "claude"},
114
- 'opencode': {'home': Path.home() / ".config" / "opencode", 'template': "global-opencode.md", 'dist': "opencode"},
115
- 'copilot': {'home': Path.home() / ".github", 'template': "global-copilot.md", 'dist': "github"},
116
- }
117
- fb = fallbacks.get(backend_name, {})
118
- # Match by the attr_func's role — we encode intent via __name__ for named
119
- # functions, or by returning the generic dist/home/template via the lambdas
120
- # below (see DIST_*/GLOBAL_*/*_HOME assignments).
121
- name = attr_func.__name__
122
- if name == 'global_home' or name == '_fb_home':
123
- return fb.get('home')
124
- elif name == 'template_path' or name == '_fb_template':
125
- return DATA_DIR / fb.get('template', '')
126
- elif name == 'dist_dir' or name == '_fb_dist':
127
- return DIST_DIR / fb.get('dist', backend_name)
128
- return get_attr
129
-
130
-
131
- # Create backward-compatibility constants. We give the lambdas named stand-ins
132
- # so the fallback branch in _lazy_backend_attr can classify them correctly even
133
- # when the registry isn't importable yet (circular import during config init).
134
- def _fb_home(b): return b.global_home
135
- def _fb_dist(b): return dist_dir_for(b)
136
- def _fb_template(b): return global_template_path(b)
137
-
138
- CLAUDE_HOME = _lazy_backend_attr('claude', _fb_home)()
139
- OPENCODE_HOME = _lazy_backend_attr('opencode', _fb_home)()
140
- GITHUB_HOME = _lazy_backend_attr('copilot', _fb_home)()
141
- DIST_CLAUDE_DIR = _lazy_backend_attr('claude', _fb_dist)()
142
- DIST_OPENCODE_DIR = _lazy_backend_attr('opencode', _fb_dist)()
143
- DIST_GITHUB_DIR = _lazy_backend_attr('copilot', _fb_dist)()
144
- GLOBAL_CLAUDE_MD = _lazy_backend_attr('claude', _fb_template)()
145
- GLOBAL_OPENCODE_MD = _lazy_backend_attr('opencode', _fb_template)()
146
- GLOBAL_COPILOT_MD = _lazy_backend_attr('copilot', _fb_template)()
94
+ # === Backward compatibility constants ===
95
+ # Hardcoded fallbacks match the shipped YAMLs and protect against circular
96
+ # imports if this module is ever imported very early in the load sequence.
97
+ _FALLBACKS = {
98
+ 'claude': {'home': Path.home() / ".claude", 'template': "global-claude.md", 'dist': "claude"},
99
+ 'opencode': {'home': Path.home() / ".config" / "opencode", 'template': "global-opencode.md", 'dist': "opencode"},
100
+ 'copilot': {'home': Path.home() / ".github", 'template': "global-copilot.md", 'dist': "github"},
101
+ }
102
+
103
+
104
+ def _backend_home(name: str) -> Path:
105
+ try:
106
+ from .registries.cli_registry import default_registry
107
+ return default_registry().get(name).global_home
108
+ except (ImportError, KeyError):
109
+ return _FALLBACKS[name]['home']
110
+
111
+
112
+ def _backend_dist(name: str) -> Path:
113
+ try:
114
+ from .registries.cli_registry import default_registry
115
+ return dist_dir_for(default_registry().get(name))
116
+ except (ImportError, KeyError):
117
+ return DIST_DIR / _FALLBACKS[name]['dist']
118
+
119
+
120
+ def _backend_template(name: str) -> Path:
121
+ try:
122
+ from .registries.cli_registry import default_registry
123
+ return global_template_path(default_registry().get(name))
124
+ except (ImportError, KeyError):
125
+ return DATA_DIR / _FALLBACKS[name]['template']
126
+
127
+
128
+ CLAUDE_HOME = _backend_home('claude')
129
+ OPENCODE_HOME = _backend_home('opencode')
130
+ GITHUB_HOME = _backend_home('copilot')
131
+ DIST_CLAUDE_DIR = _backend_dist('claude')
132
+ DIST_OPENCODE_DIR = _backend_dist('opencode')
133
+ DIST_GITHUB_DIR = _backend_dist('copilot')
134
+ GLOBAL_CLAUDE_MD = _backend_template('claude')
135
+ GLOBAL_OPENCODE_MD = _backend_template('opencode')
136
+ GLOBAL_COPILOT_MD = _backend_template('copilot')
@@ -16,4 +16,4 @@ You have a specialized agent team installed. Delegate work to them — do not tr
16
16
  - Docs → tech-writer
17
17
  - Infrastructure → devops
18
18
 
19
- **Slash commands:** /plan /review /debug /brainstorm
19
+ {{skills_catalog}}
@@ -1,6 +1,14 @@
1
1
  """Scoped health checks for agent-notes — only touches files we own."""
2
2
 
3
3
  from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "expected_paths_for_install",
7
+ "check_missing",
8
+ "check_broken",
9
+ "check_drift",
10
+ "check_stale",
11
+ ]
4
12
  from pathlib import Path
5
13
  from typing import Optional
6
14
 
@@ -33,6 +33,7 @@ class ScopeState:
33
33
  installed_at: str = ""
34
34
  updated_at: str = ""
35
35
  mode: str = "symlink"
36
+ installed_version: str = ""
36
37
  clis: dict[str, BackendState] = field(default_factory=dict)
37
38
 
38
39
 
@@ -5,6 +5,7 @@ from datetime import datetime, timezone
5
5
  from pathlib import Path
6
6
 
7
7
  from . import _claude_backend, _opencode_backend
8
+ from ._opencode_backend import DB as _OPENCODE_DB
8
9
 
9
10
 
10
11
  def _opencode_active() -> bool:
@@ -21,8 +22,7 @@ def _by_recency(since: float | None = None, session_id: str | None = None) -> in
21
22
  if jsonls:
22
23
  claude_mtime = max(f.stat().st_mtime for f in jsonls)
23
24
 
24
- opencode_db = Path.home() / ".local" / "share" / "opencode" / "opencode.db"
25
- opencode_mtime = opencode_db.stat().st_mtime if opencode_db.exists() else 0.0
25
+ opencode_mtime = _OPENCODE_DB.stat().st_mtime if _OPENCODE_DB.exists() else 0.0
26
26
 
27
27
  if claude_mtime == 0.0 and opencode_mtime == 0.0:
28
28
  print("No session data found (no Claude Code transcripts or OpenCode database).")
@@ -0,0 +1,67 @@
1
+ """Shared counting helpers for installed components."""
2
+
3
+ import os
4
+
5
+
6
+ def count_rules_total() -> int:
7
+ """Count total available rule files (for wizard display).
8
+
9
+ Uses the rule registry when available; falls back to counting .md files
10
+ directly from the dist rules directory.
11
+ """
12
+ from ..config import DIST_RULES_DIR
13
+
14
+ if os.environ.get('_WIZARD_TEST_MODE'):
15
+ if not DIST_RULES_DIR.exists():
16
+ return 0
17
+ return len(list(DIST_RULES_DIR.glob("*.md")))
18
+
19
+ try:
20
+ from ..registries import default_rule_registry
21
+ registry = default_rule_registry()
22
+ return len(registry.all())
23
+ except Exception:
24
+ if not DIST_RULES_DIR.exists():
25
+ return 0
26
+ return len(list(DIST_RULES_DIR.glob("*.md")))
27
+
28
+
29
+ def count_skills(backend, scope: str) -> tuple:
30
+ """Count (installed, expected) skills for a CLI backend. Excludes broken symlinks."""
31
+ from . import installer
32
+ from ..config import DIST_SKILLS_DIR
33
+
34
+ if not backend.supports("skills"):
35
+ return 0, 0
36
+
37
+ skills_dir = installer.target_dir_for(backend, "skills", scope)
38
+ if skills_dir and skills_dir.exists():
39
+ installed = len([d for d in skills_dir.iterdir() if d.is_dir() and d.exists()])
40
+ else:
41
+ installed = 0
42
+
43
+ expected = (
44
+ len([d for d in DIST_SKILLS_DIR.iterdir() if d.is_dir()])
45
+ if DIST_SKILLS_DIR and DIST_SKILLS_DIR.exists()
46
+ else 0
47
+ )
48
+ return installed, expected
49
+
50
+
51
+ def count_rules(backend, scope: str) -> tuple:
52
+ """Count (installed, expected) rules for a CLI backend."""
53
+ from . import installer
54
+ from ..config import DIST_RULES_DIR
55
+
56
+ if not backend.supports("rules"):
57
+ return 0, 0
58
+
59
+ rules_dir = installer.target_dir_for(backend, "rules", scope)
60
+ installed = len(list(rules_dir.glob("*.md"))) if rules_dir and rules_dir.exists() else 0
61
+
62
+ expected = (
63
+ len(list(DIST_RULES_DIR.glob("*.md")))
64
+ if DIST_RULES_DIR and DIST_RULES_DIR.exists()
65
+ else 0
66
+ )
67
+ return installed, expected
@@ -7,20 +7,30 @@ from typing import List, Optional
7
7
  from ...domain.diagnostics import Issue, FixAction
8
8
 
9
9
 
10
- def check_stale_files(scope: str, issues: List[Issue], fix_actions: List[FixAction]):
11
- """Check for installed files without matching source - DELEGATED to doctor_checks."""
12
- # This function is kept for backwards compatibility but delegates to the new module
13
- from ...cli_backend import load_registry
14
- from ... import install_state, doctor_checks
10
+ def _load_scope_state(scope: str):
11
+ """Load registry and scope state for a given scope.
12
+
13
+ Returns (registry, scope_state) where scope_state may be None if no
14
+ state file exists.
15
+ """
16
+ from ...registries.cli_registry import load_registry
17
+ from ... import install_state
15
18
  from ...state import get_scope
16
19
 
17
20
  registry = load_registry()
18
21
  state = install_state.load_current_state()
19
22
  if state is None:
20
- scope_state = None
21
- else:
22
- project_path = Path.cwd() if scope == "local" else None
23
- scope_state = get_scope(state, scope, project_path)
23
+ return registry, None
24
+ project_path = Path.cwd() if scope == "local" else None
25
+ scope_state = get_scope(state, scope, project_path)
26
+ return registry, scope_state
27
+
28
+
29
+ def check_stale_files(scope: str, issues: List[Issue], fix_actions: List[FixAction]):
30
+ """Check for installed files without matching source - DELEGATED to doctor_checks."""
31
+ from ... import doctor_checks
32
+
33
+ registry, scope_state = _load_scope_state(scope)
24
34
  doctor_checks.check_stale(scope, scope_state, registry, issues, fix_actions)
25
35
 
26
36
 
@@ -30,7 +40,7 @@ def _find_dist_source(symlink: Path, scope: str) -> Optional[Path]:
30
40
  Iterates all registered backends; returns first dist source whose
31
41
  component and filename match the given symlink.
32
42
  """
33
- from ...cli_backend import load_registry
43
+ from ...registries.cli_registry import load_registry
34
44
  from ... import installer
35
45
  registry = load_registry()
36
46
 
@@ -75,35 +85,17 @@ def _find_dist_source(symlink: Path, scope: str) -> Optional[Path]:
75
85
 
76
86
  def check_broken_symlinks(scope: str, issues: List[Issue], fix_actions: List[FixAction]):
77
87
  """Check for symlinks with non-existent targets - DELEGATED to doctor_checks."""
78
- # This function is kept for backwards compatibility but delegates to the new module
79
- from ...cli_backend import load_registry
80
- from ... import install_state, doctor_checks
81
- from ...state import get_scope
88
+ from ... import doctor_checks
82
89
 
83
- registry = load_registry()
84
- state = install_state.load_current_state()
85
- if state is None:
86
- scope_state = None
87
- else:
88
- project_path = Path.cwd() if scope == "local" else None
89
- scope_state = get_scope(state, scope, project_path)
90
+ registry, scope_state = _load_scope_state(scope)
90
91
  doctor_checks.check_broken(scope, registry, issues, fix_actions, scope_state)
91
92
 
92
93
 
93
94
  def check_shadowed_files(scope: str, issues: List[Issue], fix_actions: List[FixAction]):
94
95
  """Check for regular files where symlinks are expected - TARGETED check only."""
95
- from ...cli_backend import load_registry
96
- from ... import install_state, doctor_checks
97
- from ...state import get_scope
96
+ from ... import doctor_checks
98
97
 
99
- # Get expected paths and check each one individually
100
- registry = load_registry()
101
- state = install_state.load_current_state()
102
- if state is None:
103
- scope_state = None
104
- else:
105
- project_path = Path.cwd() if scope == "local" else None
106
- scope_state = get_scope(state, scope, project_path)
98
+ registry, scope_state = _load_scope_state(scope)
107
99
 
108
100
  # Only check paths we know should exist
109
101
  for src, dst, backend_name, component in doctor_checks.expected_paths_for_install(registry, scope):
@@ -119,13 +111,14 @@ def check_shadowed_files(scope: str, issues: List[Issue], fix_actions: List[FixA
119
111
 
120
112
  def check_missing_files(scope: str, issues: List[Issue], fix_actions: List[FixAction]):
121
113
  """Check for source files that aren't installed - DELEGATED to doctor_checks."""
122
- # This function is kept for backwards compatibility but delegates to the new module
123
- from ...cli_backend import load_registry
124
- from ... import doctor_checks, install_state
114
+ from ... import doctor_checks
115
+ from ...registries.cli_registry import load_registry
116
+ from ... import install_state
125
117
  from ...state import get_scope
126
118
 
127
119
  registry = load_registry()
128
120
  # Pass scope state so opted-out backends aren't flagged as "missing".
121
+ # Use a try/except here since local scope resolution can raise ValueError/KeyError.
129
122
  state = install_state.load_current_state()
130
123
  scope_state = None
131
124
  if state is not None:
@@ -144,18 +137,9 @@ def check_missing_files(scope: str, issues: List[Issue], fix_actions: List[FixAc
144
137
 
145
138
  def check_content_drift(scope: str, issues: List[Issue], fix_actions: List[FixAction]):
146
139
  """Check for copied files that differ from source - DELEGATED to doctor_checks."""
147
- # This function is kept for backwards compatibility but delegates to the new module
148
- from ...cli_backend import load_registry
149
- from ... import install_state, doctor_checks
150
- from ...state import get_scope
140
+ from ... import doctor_checks
151
141
 
152
- registry = load_registry()
153
- state = install_state.load_current_state()
154
- if state is None:
155
- scope_state = None
156
- else:
157
- project_path = Path.cwd() if scope == "local" else None
158
- scope_state = get_scope(state, scope, project_path)
142
+ registry, scope_state = _load_scope_state(scope)
159
143
  doctor_checks.check_drift(scope, registry, issues, fix_actions, scope_state)
160
144
 
161
145
 
@@ -167,7 +151,7 @@ def check_build_freshness(issues: List[Issue], fix_actions: List[FixAction]):
167
151
  # Check agents.yaml vs generated agents
168
152
  if agents_yaml.exists():
169
153
  source_time = agents_yaml.stat().st_mtime
170
- from ...cli_backend import load_registry
154
+ from ...registries.cli_registry import load_registry
171
155
  from ...config import dist_dir_for
172
156
 
173
157
  registry = load_registry()
@@ -184,7 +168,7 @@ def check_build_freshness(issues: List[Issue], fix_actions: List[FixAction]):
184
168
  # Check individual source agents
185
169
  source_agents_dir = AGENTS_DIR
186
170
  if source_agents_dir.exists():
187
- from ...cli_backend import load_registry
171
+ from ...registries.cli_registry import load_registry
188
172
  from ...config import dist_dir_for
189
173
 
190
174
  registry = load_registry()
@@ -202,7 +186,7 @@ def check_build_freshness(issues: List[Issue], fix_actions: List[FixAction]):
202
186
  fix_actions.append(FixAction("BUILD", str(gen_file), "regenerate from source"))
203
187
 
204
188
  # Check global source files
205
- from ...cli_backend import load_registry
189
+ from ...registries.cli_registry import load_registry
206
190
  from ...config import global_template_path, global_output_path
207
191
 
208
192
  registry = load_registry()
@@ -1,9 +1,16 @@
1
1
  """Display and summary functions for agent-notes diagnostics."""
2
2
 
3
+ __all__ = [
4
+ "count_stale",
5
+ "print_summary",
6
+ "print_issues",
7
+ ]
8
+
3
9
  from pathlib import Path
4
10
  from typing import List, Dict
5
11
 
6
12
  from ...domain.diagnostics import Issue
13
+ from ..counts import count_skills as _count_skills_impl, count_rules as _count_rules_impl
7
14
 
8
15
 
9
16
  def _cli_base_dir(backend, scope: str) -> Path:
@@ -34,50 +41,12 @@ def _count_agents(backend, scope: str) -> tuple:
34
41
 
35
42
  def _count_skills(backend, scope: str) -> tuple:
36
43
  """Count (installed, expected) skills for a CLI backend. Excludes broken symlinks."""
37
- from ... import installer
38
-
39
- # Helper to get DIST_SKILLS_DIR
40
- def _get_dist_skills_dir():
41
- from ...config import DIST_SKILLS_DIR
42
- return DIST_SKILLS_DIR
43
-
44
- if not backend.supports("skills"):
45
- return 0, 0
46
-
47
- # Count installed
48
- skills_dir = installer.target_dir_for(backend, "skills", scope)
49
- if skills_dir and skills_dir.exists():
50
- installed = len([d for d in skills_dir.iterdir() if d.is_dir() and d.exists()])
51
- else:
52
- installed = 0
53
-
54
- # Count expected (universal skills)
55
- dist_skills_dir = _get_dist_skills_dir()
56
- expected = len([d for d in dist_skills_dir.iterdir() if d.is_dir()]) if dist_skills_dir and dist_skills_dir.exists() else 0
57
- return installed, expected
58
-
44
+ return _count_skills_impl(backend, scope)
59
45
 
60
46
 
61
47
  def _count_rules(backend, scope: str) -> tuple:
62
48
  """Count (installed, expected) rules for a CLI backend."""
63
- from ... import installer
64
-
65
- # Helper to get DIST_RULES_DIR
66
- def _get_dist_rules_dir():
67
- from ...config import DIST_RULES_DIR
68
- return DIST_RULES_DIR
69
-
70
- if not backend.supports("rules"):
71
- return 0, 0
72
-
73
- # Count installed
74
- rules_dir = installer.target_dir_for(backend, "rules", scope)
75
- installed = len(list(rules_dir.glob("*.md"))) if rules_dir and rules_dir.exists() else 0
76
-
77
- # Count expected
78
- dist_rules_dir = _get_dist_rules_dir()
79
- expected = len(list(dist_rules_dir.glob("*.md"))) if dist_rules_dir and dist_rules_dir.exists() else 0
80
- return installed, expected
49
+ return _count_rules_impl(backend, scope)
81
50
 
82
51
 
83
52
  def _check_config(backend, scope: str) -> tuple:
@@ -101,9 +70,9 @@ def _check_config(backend, scope: str) -> tuple:
101
70
 
102
71
  def _check_role_models(state):
103
72
  """Display role→model assignments and check compatibility."""
104
- from ...model_registry import load_model_registry
73
+ from ...registries.model_registry import load_model_registry
105
74
  from ...registries.cli_registry import load_registry
106
- from ...role_registry import load_role_registry
75
+ from ...registries.role_registry import load_role_registry
107
76
  from ...config import Color
108
77
 
109
78
  model_registry = load_model_registry()