agent-notes 2.20.0__tar.gz → 2.21.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 (219) hide show
  1. {agent_notes-2.20.0 → agent_notes-2.21.0}/PKG-INFO +1 -1
  2. agent_notes-2.21.0/agent_notes/VERSION +1 -0
  3. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/cli.py +1 -1
  4. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/memory.py +132 -0
  5. agent_notes-2.21.0/agent_notes/data/skills/ingest/SKILL.md +73 -0
  6. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/wiki_backend.py +190 -0
  7. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes.egg-info/PKG-INFO +1 -1
  8. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes.egg-info/SOURCES.txt +1 -0
  9. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/services/test_wiki_backend.py +225 -0
  10. agent_notes-2.20.0/agent_notes/VERSION +0 -1
  11. {agent_notes-2.20.0 → agent_notes-2.21.0}/LICENSE +0 -0
  12. {agent_notes-2.20.0 → agent_notes-2.21.0}/README.md +0 -0
  13. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/__init__.py +0 -0
  14. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/__main__.py +0 -0
  15. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/__init__.py +0 -0
  16. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/_install_helpers.py +0 -0
  17. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/build.py +0 -0
  18. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/config.py +0 -0
  19. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/doctor.py +0 -0
  20. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/info.py +0 -0
  21. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/install.py +0 -0
  22. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/list.py +0 -0
  23. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/regenerate.py +0 -0
  24. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/set_role.py +0 -0
  25. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/uninstall.py +0 -0
  26. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/validate.py +0 -0
  27. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/commands/wizard.py +0 -0
  28. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/config.py +0 -0
  29. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/agents.yaml +0 -0
  30. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/analyst.md +0 -0
  31. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/api-reviewer.md +0 -0
  32. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/architect.md +0 -0
  33. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/coder.md +0 -0
  34. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/database-specialist.md +0 -0
  35. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/debugger.md +0 -0
  36. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/devil.md +0 -0
  37. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/devops.md +0 -0
  38. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/explorer.md +0 -0
  39. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/integrations.md +0 -0
  40. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/lead.md +0 -0
  41. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/performance-profiler.md +0 -0
  42. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/refactorer.md +0 -0
  43. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/reviewer.md +0 -0
  44. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/security-auditor.md +0 -0
  45. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/shared/cost_reporting.md +0 -0
  46. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/shared/execution.md +0 -0
  47. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/shared/guardrails.md +0 -0
  48. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/shared/hard_limits.md +0 -0
  49. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/shared/phase0.md +0 -0
  50. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/shared/pipelines.md +0 -0
  51. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/shared/review.md +0 -0
  52. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/shared/verification.md +0 -0
  53. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/system-auditor.md +0 -0
  54. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/tech-writer.md +0 -0
  55. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/test-runner.md +0 -0
  56. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/agents/test-writer.md +0 -0
  57. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/cli/claude.yaml +0 -0
  58. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/cli/copilot.yaml +0 -0
  59. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/cli/opencode.yaml +0 -0
  60. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/commands/brainstorm.md +0 -0
  61. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/commands/debug.md +0 -0
  62. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/commands/review.md +0 -0
  63. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/global-claude.md +0 -0
  64. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/global-copilot.md +0 -0
  65. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/global-opencode.md +0 -0
  66. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/hooks/session-context.md.tpl +0 -0
  67. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/models/claude-haiku-4-5.yaml +0 -0
  68. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/models/claude-opus-4-1.yaml +0 -0
  69. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/models/claude-opus-4-5.yaml +0 -0
  70. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/models/claude-opus-4-6.yaml +0 -0
  71. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/models/claude-opus-4-7.yaml +0 -0
  72. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/models/claude-sonnet-4-5.yaml +0 -0
  73. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/models/claude-sonnet-4-6.yaml +0 -0
  74. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/models/claude-sonnet-4.yaml +0 -0
  75. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/plugin/claude.yaml +0 -0
  76. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/plugin/opencode-index.js.template +0 -0
  77. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/plugin/opencode.yaml +0 -0
  78. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/pricing.yaml +0 -0
  79. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/roles/orchestrator.yaml +0 -0
  80. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/roles/reasoner.yaml +0 -0
  81. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/roles/scout.yaml +0 -0
  82. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/roles/worker.yaml +0 -0
  83. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/rules/code-quality.md +0 -0
  84. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/rules/safety.md +0 -0
  85. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/brainstorming/SKILL.md +0 -0
  86. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/caveman/SKILL.md +0 -0
  87. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/code-review/SKILL.md +0 -0
  88. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/debugging-protocol/SKILL.md +0 -0
  89. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/docker/SKILL.md +0 -0
  90. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/docker/compose.md +0 -0
  91. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/docker/dockerfile.md +0 -0
  92. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/git/SKILL.md +0 -0
  93. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/grill-me/SKILL.md +0 -0
  94. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/grill-with-docs/SKILL.md +0 -0
  95. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/improve-codebase-architecture/SKILL.md +0 -0
  96. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/obsidian-memory/SKILL.md +0 -0
  97. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/rails/SKILL.md +0 -0
  98. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/rails/controllers.md +0 -0
  99. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/rails/frontend.md +0 -0
  100. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/rails/infra.md +0 -0
  101. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/rails/models.md +0 -0
  102. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/rails/testing.md +0 -0
  103. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/rails/views.md +0 -0
  104. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/refactoring-protocol/SKILL.md +0 -0
  105. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/setup-project-context/SKILL.md +0 -0
  106. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/tdd/SKILL.md +0 -0
  107. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/skills/zoom-out/SKILL.md +0 -0
  108. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/templates/__init__.py +0 -0
  109. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/templates/__pycache__/__init__.cpython-314.pyc +0 -0
  110. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/templates/frontmatter/__init__.py +0 -0
  111. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/templates/frontmatter/__pycache__/__init__.cpython-314.pyc +0 -0
  112. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/templates/frontmatter/__pycache__/claude.cpython-314.pyc +0 -0
  113. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/templates/frontmatter/__pycache__/opencode.cpython-314.pyc +0 -0
  114. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/templates/frontmatter/claude.py +0 -0
  115. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/data/templates/frontmatter/opencode.py +0 -0
  116. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/doctor_checks.py +0 -0
  117. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/domain/__init__.py +0 -0
  118. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/domain/agent.py +0 -0
  119. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/domain/cli_backend.py +0 -0
  120. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/domain/diagnostics.py +0 -0
  121. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/domain/diff.py +0 -0
  122. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/domain/model.py +0 -0
  123. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/domain/role.py +0 -0
  124. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/domain/rule.py +0 -0
  125. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/domain/skill.py +0 -0
  126. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/domain/state.py +0 -0
  127. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/install_state.py +0 -0
  128. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/registries/__init__.py +0 -0
  129. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/registries/_base.py +0 -0
  130. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/registries/agent_registry.py +0 -0
  131. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/registries/cli_registry.py +0 -0
  132. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/registries/model_registry.py +0 -0
  133. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/registries/role_registry.py +0 -0
  134. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/registries/rule_registry.py +0 -0
  135. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/registries/skill_registry.py +0 -0
  136. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/scripts/__init__.py +0 -0
  137. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/scripts/_claude_backend.py +0 -0
  138. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/scripts/_formatting.py +0 -0
  139. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/scripts/_opencode_backend.py +0 -0
  140. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/scripts/_pricing.py +0 -0
  141. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/scripts/cost_report.py +0 -0
  142. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/__init__.py +0 -0
  143. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/counts.py +0 -0
  144. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/credentials.py +0 -0
  145. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/diagnostics/__init__.py +0 -0
  146. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/diagnostics/_checks.py +0 -0
  147. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/diagnostics/_display.py +0 -0
  148. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/diagnostics/_fix.py +0 -0
  149. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/diff.py +0 -0
  150. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/fs.py +0 -0
  151. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/install_state_builder.py +0 -0
  152. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/installer.py +0 -0
  153. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/memory_backend.py +0 -0
  154. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/rendering.py +0 -0
  155. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/session_context.py +0 -0
  156. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/settings_writer.py +0 -0
  157. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/state_store.py +0 -0
  158. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/ui.py +0 -0
  159. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/user_config.py +0 -0
  160. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/services/validation.py +0 -0
  161. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes/state.py +0 -0
  162. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes.egg-info/dependency_links.txt +0 -0
  163. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes.egg-info/entry_points.txt +0 -0
  164. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes.egg-info/requires.txt +0 -0
  165. {agent_notes-2.20.0 → agent_notes-2.21.0}/agent_notes.egg-info/top_level.txt +0 -0
  166. {agent_notes-2.20.0 → agent_notes-2.21.0}/pyproject.toml +0 -0
  167. {agent_notes-2.20.0 → agent_notes-2.21.0}/setup.cfg +0 -0
  168. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/conftest.py +0 -0
  169. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/__init__.py +0 -0
  170. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/commands/__init__.py +0 -0
  171. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/commands/test_config_command.py +0 -0
  172. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/commands/test_doctor_command.py +0 -0
  173. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/commands/test_info_command.py +0 -0
  174. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/commands/test_install_command.py +0 -0
  175. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/commands/test_list_command.py +0 -0
  176. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/commands/test_regenerate_command.py +0 -0
  177. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/commands/test_uninstall_command.py +0 -0
  178. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/commands/test_validate_command.py +0 -0
  179. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/memory/__init__.py +0 -0
  180. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/memory/test_memory_command.py +0 -0
  181. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/scripts/__init__.py +0 -0
  182. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/functional/scripts/test_release_script.py +0 -0
  183. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/integration/__init__.py +0 -0
  184. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/integration/build_output/__init__.py +0 -0
  185. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/integration/build_output/test_build_output.py +0 -0
  186. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/integration/install/__init__.py +0 -0
  187. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/integration/install/test_install_methods.py +0 -0
  188. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/integration/plugin_builders/__init__.py +0 -0
  189. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/integration/plugin_builders/test_plugin_builders.py +0 -0
  190. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/plugins/__init__.py +0 -0
  191. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/plugins/claude/__init__.py +0 -0
  192. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/plugins/claude/test_agents.py +0 -0
  193. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/plugins/test_skills.py +0 -0
  194. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/__init__.py +0 -0
  195. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/commands/__init__.py +0 -0
  196. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/commands/test_cost_report_subcommand.py +0 -0
  197. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/commands/test_count_agents.py +0 -0
  198. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/commands/test_memory_migrate.py +0 -0
  199. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/commands/test_wizard_orchestrator_skip.py +0 -0
  200. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/commands/test_wizard_preflight.py +0 -0
  201. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/registries/__init__.py +0 -0
  202. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/registries/test_registries.py +0 -0
  203. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/scripts/__init__.py +0 -0
  204. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/scripts/test_cost_report.py +0 -0
  205. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/scripts/test_cost_report_scoping.py +0 -0
  206. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/scripts/test_formatting_tty.py +0 -0
  207. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/scripts/test_time_aggregation.py +0 -0
  208. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/services/__init__.py +0 -0
  209. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/services/test_build_functions.py +0 -0
  210. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/services/test_credentials.py +0 -0
  211. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/services/test_fs.py +0 -0
  212. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/services/test_installer_plan.py +0 -0
  213. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/services/test_memory_backend.py +0 -0
  214. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/services/test_memory_backend_io.py +0 -0
  215. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/services/test_rendering_includes.py +0 -0
  216. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/services/test_session_context.py +0 -0
  217. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/services/test_settings_writer.py +0 -0
  218. {agent_notes-2.20.0 → agent_notes-2.21.0}/tests/unit/test_import_health.py +0 -0
  219. {agent_notes-2.20.0 → agent_notes-2.21.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.20.0
3
+ Version: 2.21.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
@@ -0,0 +1 @@
1
+ 2.21.0
@@ -273,7 +273,7 @@ def main():
273
273
  # memory
274
274
  p_memory = subparsers.add_parser("memory", help="Manage agent memory")
275
275
  p_memory.add_argument("action", nargs="?", default="list",
276
- choices=["init", "list", "vault", "index", "add", "size", "show", "reset", "export", "import", "ingest", "query", "lint"],
276
+ choices=["init", "list", "vault", "index", "add", "size", "show", "reset", "export", "import", "ingest", "ingest-file", "ingest-url", "ingest-folder", "query", "lint"],
277
277
  help="Memory action")
278
278
  p_memory.add_argument("name", nargs="?", help="Agent name / note title (for show/reset/add)")
279
279
  p_memory.add_argument("extra", nargs="*", help="Additional args (for add: body [type] [agent] [project])")
@@ -508,6 +508,102 @@ def do_ingest(title: str, body: str, concepts: Optional[list] = None, entities:
508
508
  print(f" entity: {p}")
509
509
 
510
510
 
511
+ def do_ingest_file(file_path: str, title: str = "", body: str = "",
512
+ concepts: Optional[list] = None, entities: Optional[list] = None,
513
+ tags: Optional[list] = None) -> None:
514
+ """Ingest a local file into the wiki backend."""
515
+ backend, path = _load_memory_config()
516
+ if backend != "wiki":
517
+ print("The `ingest-file` subcommand is only available for the wiki backend.")
518
+ return
519
+ if path is None:
520
+ print("Memory path not configured.")
521
+ return
522
+ fp = Path(file_path)
523
+ if not fp.exists():
524
+ print(f"Error: file not found: {file_path}")
525
+ exit(1)
526
+ from ..services.wiki_backend import wiki_ingest_file
527
+ result = wiki_ingest_file(
528
+ path,
529
+ file_path=fp,
530
+ title=title,
531
+ body=body,
532
+ concepts=concepts or [],
533
+ entities=entities or [],
534
+ tags=tags or [],
535
+ )
536
+ _print_ingest_result(result)
537
+
538
+
539
+ def do_ingest_url(url: str, title: str = "", body: str = "",
540
+ concepts: Optional[list] = None, entities: Optional[list] = None,
541
+ tags: Optional[list] = None) -> None:
542
+ """Ingest a URL into the wiki backend."""
543
+ backend, path = _load_memory_config()
544
+ if backend != "wiki":
545
+ print("The `ingest-url` subcommand is only available for the wiki backend.")
546
+ return
547
+ if path is None:
548
+ print("Memory path not configured.")
549
+ return
550
+ from ..services.wiki_backend import wiki_ingest_url
551
+ result = wiki_ingest_url(
552
+ path,
553
+ url=url,
554
+ title=title,
555
+ body=body,
556
+ concepts=concepts or [],
557
+ entities=entities or [],
558
+ tags=tags or [],
559
+ )
560
+ _print_ingest_result(result)
561
+
562
+
563
+ def do_ingest_folder(folder_path: str, title: str = "", body: str = "",
564
+ concepts: Optional[list] = None, entities: Optional[list] = None,
565
+ tags: Optional[list] = None) -> None:
566
+ """Ingest a local folder into the wiki backend."""
567
+ backend, path = _load_memory_config()
568
+ if backend != "wiki":
569
+ print("The `ingest-folder` subcommand is only available for the wiki backend.")
570
+ return
571
+ if path is None:
572
+ print("Memory path not configured.")
573
+ return
574
+ fp = Path(folder_path)
575
+ if not fp.exists():
576
+ print(f"Error: folder not found: {folder_path}")
577
+ exit(1)
578
+ from ..services.wiki_backend import wiki_ingest_folder
579
+ result = wiki_ingest_folder(
580
+ path,
581
+ folder_path=fp,
582
+ title=title,
583
+ body=body,
584
+ concepts=concepts or [],
585
+ entities=entities or [],
586
+ tags=tags or [],
587
+ )
588
+ _print_ingest_result(result)
589
+
590
+
591
+ def _print_ingest_result(result: dict) -> None:
592
+ source_paths = result.get("source", [])
593
+ concept_paths = result.get("concepts", [])
594
+ entity_paths = result.get("entities", [])
595
+ title = ""
596
+ if source_paths:
597
+ title = source_paths[0].stem.replace("-", " ").title()
598
+ print(f"{Color.GREEN}Ingested: {title}{Color.NC}")
599
+ for p in source_paths:
600
+ print(f" source: {p}")
601
+ for p in concept_paths:
602
+ print(f" concept: {p}")
603
+ for p in entity_paths:
604
+ print(f" entity: {p}")
605
+
606
+
511
607
  def do_query(keyword: str) -> None:
512
608
  """Search wiki pages by keyword."""
513
609
  backend, path = _load_memory_config()
@@ -796,6 +892,42 @@ def memory(action: str = "list", name: Optional[str] = None, extra: Optional[lis
796
892
  entities = [e.strip() for e in entities_csv.split(",") if e.strip()] if entities_csv else None
797
893
  tags = [t.strip() for t in tags_csv.split(",") if t.strip()] if tags_csv else None
798
894
  do_ingest(name, body, concepts=concepts, entities=entities, tags=tags)
895
+ elif action == "ingest-file":
896
+ if not name:
897
+ print("Error: ingest-file requires a file path.")
898
+ exit(1)
899
+ body = extra[0] if extra else ""
900
+ concepts_csv = extra[1] if extra and len(extra) > 1 else ""
901
+ entities_csv = extra[2] if extra and len(extra) > 2 else ""
902
+ tags_csv = extra[3] if extra and len(extra) > 3 else ""
903
+ concepts = [c.strip() for c in concepts_csv.split(",") if c.strip()] if concepts_csv else None
904
+ entities = [e.strip() for e in entities_csv.split(",") if e.strip()] if entities_csv else None
905
+ tags = [t.strip() for t in tags_csv.split(",") if t.strip()] if tags_csv else None
906
+ do_ingest_file(name, body=body, concepts=concepts, entities=entities, tags=tags)
907
+ elif action == "ingest-url":
908
+ if not name:
909
+ print("Error: ingest-url requires a URL.")
910
+ exit(1)
911
+ body = extra[0] if extra else ""
912
+ concepts_csv = extra[1] if extra and len(extra) > 1 else ""
913
+ entities_csv = extra[2] if extra and len(extra) > 2 else ""
914
+ tags_csv = extra[3] if extra and len(extra) > 3 else ""
915
+ concepts = [c.strip() for c in concepts_csv.split(",") if c.strip()] if concepts_csv else None
916
+ entities = [e.strip() for e in entities_csv.split(",") if e.strip()] if entities_csv else None
917
+ tags = [t.strip() for t in tags_csv.split(",") if t.strip()] if tags_csv else None
918
+ do_ingest_url(name, body=body, concepts=concepts, entities=entities, tags=tags)
919
+ elif action == "ingest-folder":
920
+ if not name:
921
+ print("Error: ingest-folder requires a folder path.")
922
+ exit(1)
923
+ body = extra[0] if extra else ""
924
+ concepts_csv = extra[1] if extra and len(extra) > 1 else ""
925
+ entities_csv = extra[2] if extra and len(extra) > 2 else ""
926
+ tags_csv = extra[3] if extra and len(extra) > 3 else ""
927
+ concepts = [c.strip() for c in concepts_csv.split(",") if c.strip()] if concepts_csv else None
928
+ entities = [e.strip() for e in entities_csv.split(",") if e.strip()] if entities_csv else None
929
+ tags = [t.strip() for t in tags_csv.split(",") if t.strip()] if tags_csv else None
930
+ do_ingest_folder(name, body=body, concepts=concepts, entities=entities, tags=tags)
799
931
  elif action == "query":
800
932
  if not name:
801
933
  print("Error: query requires a keyword.")
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: ingest
3
+ description: "Ingest a URL, local file, or folder into the wiki brain. Fetches content, extracts concepts and entities with AI analysis, and stores in the wiki. Use when user says 'ingest', provides a URL to study, or wants to add external knowledge."
4
+ group: memory
5
+ ---
6
+
7
+ # Ingest
8
+
9
+ Ingest external sources into the wiki brain for persistent, queryable knowledge.
10
+
11
+ ## Usage
12
+
13
+ The user provides one of:
14
+ - A **URL** (starts with `http://` or `https://`)
15
+ - A **file path** (path to a single file)
16
+ - A **folder path** (path to a directory)
17
+
18
+ ## Workflow
19
+
20
+ ### Step 1 — Fetch the source
21
+
22
+ | Source type | How to read |
23
+ |---|---|
24
+ | URL | Use `WebFetch` tool to retrieve the page content |
25
+ | File | Use `Read` tool to read the file |
26
+ | Folder | Use `Bash` to list files (`find <path> -type f`), then `Read` key files. Skip: `__pycache__`, `.git`, `node_modules`, `.venv`, `dist`, `build`, `.egg-info` |
27
+
28
+ ### Step 2 — AI analysis
29
+
30
+ Analyze the content and extract:
31
+
32
+ 1. **Title** — a concise, descriptive name for this source
33
+ 2. **Summary** — 2-5 sentence overview of what this source contains and why it matters
34
+ 3. **Concepts** — key ideas, patterns, techniques, or abstractions (e.g., "dependency injection", "event sourcing", "fan-out pattern")
35
+ 4. **Entities** — specific named things: tools, libraries, people, projects, APIs (e.g., "PostgreSQL", "Karpathy", "wiki_backend.py")
36
+ 5. **Tags** — categorization labels (e.g., "python", "architecture", "api")
37
+
38
+ ### Step 3 — Ingest via CLI
39
+
40
+ Call the appropriate command:
41
+
42
+ **For a URL:**
43
+ ```bash
44
+ agent-notes memory ingest-url "<url>" "<summary>" "<concepts_csv>" "<entities_csv>" "<tags_csv>"
45
+ ```
46
+
47
+ **For a file:**
48
+ ```bash
49
+ agent-notes memory ingest-file "<file_path>" "<summary>" "<concepts_csv>" "<entities_csv>" "<tags_csv>"
50
+ ```
51
+
52
+ **For a folder:**
53
+ ```bash
54
+ agent-notes memory ingest-folder "<folder_path>" "<summary>" "<concepts_csv>" "<entities_csv>" "<tags_csv>"
55
+ ```
56
+
57
+ The CLI archives the raw content and creates the wiki source page. The AI-extracted concepts and entities are fanned out into their own wiki pages with cross-references.
58
+
59
+ ### Step 4 — Report
60
+
61
+ After ingestion, report to the user:
62
+ - What was ingested (title, source type)
63
+ - Key concepts and entities extracted
64
+ - Number of wiki pages created/updated
65
+
66
+ ## Example
67
+
68
+ User: `/ingest https://karpathy.github.io/2023/01/20/llm-wiki/`
69
+
70
+ 1. Fetch URL with WebFetch
71
+ 2. Analyze: Title="LLM Wiki by Karpathy", Summary="Proposes using LLMs to maintain personal knowledge wikis...", Concepts=["LLM Wiki", "knowledge management", "fan-out pattern"], Entities=["Andrej Karpathy"], Tags=["ai", "knowledge-management"]
72
+ 3. Run: `agent-notes memory ingest-url "https://karpathy.github.io/2023/01/20/llm-wiki/" "Proposes using LLMs to maintain personal knowledge wikis..." "LLM Wiki,knowledge management,fan-out pattern" "Andrej Karpathy" "ai,knowledge-management"`
73
+ 4. Report results
@@ -215,6 +215,196 @@ def wiki_ingest(
215
215
  return result
216
216
 
217
217
 
218
+ # ── Ingest from file ──────────────────────────────────────────────────────────
219
+
220
+ def wiki_ingest_file(
221
+ wiki_root: Path,
222
+ *,
223
+ file_path: Path,
224
+ title: str = "",
225
+ body: str = "",
226
+ concepts: list[str] | None = None,
227
+ entities: list[str] | None = None,
228
+ tags: list[str] | None = None,
229
+ ) -> dict[str, list[Path]]:
230
+ """Ingest a local file into the wiki. Reads content, derives title, delegates to wiki_ingest."""
231
+ if not file_path.is_file():
232
+ raise FileNotFoundError(f"File not found: {file_path}")
233
+ raw_content = file_path.read_text(errors="replace")
234
+ if not title:
235
+ title = file_path.stem.replace("-", " ").replace("_", " ").title()
236
+ if not body:
237
+ body = f"Ingested from local file: {file_path}"
238
+ return wiki_ingest(
239
+ wiki_root,
240
+ title=title,
241
+ body=body,
242
+ raw_content=raw_content,
243
+ raw_filename=file_path.name,
244
+ concepts=concepts,
245
+ entities=entities,
246
+ tags=tags,
247
+ )
248
+
249
+
250
+ # ── Ingest from folder ────────────────────────────────────────────────────────
251
+
252
+ _SKIP_DIRS = {"__pycache__", ".git", "node_modules", ".venv", "dist", "build"}
253
+ _DEFAULT_EXTENSIONS = {".py", ".md", ".yaml", ".yml", ".toml", ".json", ".txt", ".rs", ".ts", ".js", ".rb", ".go", ".java"}
254
+
255
+
256
+ def _parse_gitignore_patterns(gitignore_path: Path) -> list[str]:
257
+ """Return non-empty, non-comment patterns from a .gitignore file."""
258
+ patterns = []
259
+ for line in gitignore_path.read_text(errors="replace").splitlines():
260
+ line = line.rstrip()
261
+ if line and not line.startswith("#"):
262
+ patterns.append(line)
263
+ return patterns
264
+
265
+
266
+ def _matches_gitignore(rel_path: str, patterns: list[str]) -> bool:
267
+ """Return True if rel_path matches any gitignore pattern (simplified fnmatch)."""
268
+ import fnmatch
269
+ parts = rel_path.replace("\\", "/").split("/")
270
+ name = parts[-1]
271
+ for pattern in patterns:
272
+ # Strip leading slash for anchored patterns — treat as simple fnmatch
273
+ clean = pattern.lstrip("/")
274
+ if not clean:
275
+ continue
276
+ if fnmatch.fnmatch(name, clean):
277
+ return True
278
+ if fnmatch.fnmatch(rel_path, clean):
279
+ return True
280
+ if fnmatch.fnmatch(rel_path, f"**/{clean}"):
281
+ return True
282
+ return False
283
+
284
+
285
+ def wiki_ingest_folder(
286
+ wiki_root: Path,
287
+ *,
288
+ folder_path: Path,
289
+ title: str = "",
290
+ body: str = "",
291
+ concepts: list[str] | None = None,
292
+ entities: list[str] | None = None,
293
+ tags: list[str] | None = None,
294
+ extensions: list[str] | None = None,
295
+ respect_gitignore: bool = True,
296
+ ) -> dict[str, list[Path]]:
297
+ """Ingest a local folder recursively into the wiki. Concatenates file contents."""
298
+ if not folder_path.is_dir():
299
+ raise FileNotFoundError(f"Folder not found: {folder_path}")
300
+ allowed_exts = set(extensions) if extensions is not None else _DEFAULT_EXTENSIONS
301
+
302
+ gitignore_patterns: list[str] = []
303
+ if respect_gitignore:
304
+ gitignore_path = folder_path / ".gitignore"
305
+ if gitignore_path.exists():
306
+ gitignore_patterns = _parse_gitignore_patterns(gitignore_path)
307
+
308
+ parts: list[str] = []
309
+ file_count = 0
310
+
311
+ for file in sorted(folder_path.rglob("*")):
312
+ if not file.is_file():
313
+ continue
314
+ # Skip junk directories
315
+ if any(skip in file.parts for skip in _SKIP_DIRS):
316
+ continue
317
+ # Skip files with egg-info in path
318
+ if any(part.endswith(".egg-info") for part in file.parts):
319
+ continue
320
+ # Extension filter
321
+ if file.suffix not in allowed_exts:
322
+ continue
323
+ # Gitignore filter
324
+ rel = str(file.relative_to(folder_path))
325
+ if gitignore_patterns and _matches_gitignore(rel, gitignore_patterns):
326
+ continue
327
+
328
+ try:
329
+ content = file.read_text(errors="replace")
330
+ except OSError:
331
+ continue
332
+
333
+ parts.append(f"\n\n--- FILE: {rel} ---\n\n{content}\n")
334
+ file_count += 1
335
+
336
+ raw_content = "".join(parts).lstrip("\n")
337
+
338
+ if not title:
339
+ title = folder_path.name.replace("-", " ").replace("_", " ").title()
340
+ if not body:
341
+ body = f"Ingested from local folder: {folder_path} ({file_count} files)"
342
+
343
+ raw_filename = f"{_slug(title)}-folder.md"
344
+
345
+ return wiki_ingest(
346
+ wiki_root,
347
+ title=title,
348
+ body=body,
349
+ raw_content=raw_content,
350
+ raw_filename=raw_filename,
351
+ concepts=concepts,
352
+ entities=entities,
353
+ tags=tags,
354
+ )
355
+
356
+
357
+ # ── Ingest from URL ───────────────────────────────────────────────────────────
358
+
359
+ def wiki_ingest_url(
360
+ wiki_root: Path,
361
+ *,
362
+ url: str,
363
+ title: str = "",
364
+ body: str = "",
365
+ concepts: list[str] | None = None,
366
+ entities: list[str] | None = None,
367
+ tags: list[str] | None = None,
368
+ ) -> dict[str, list[Path]]:
369
+ """Fetch a URL and ingest its content into the wiki."""
370
+ import urllib.request
371
+ import urllib.error
372
+ from urllib.parse import urlparse
373
+
374
+ with urllib.request.urlopen(url) as response:
375
+ raw_bytes = response.read()
376
+ try:
377
+ raw_content = raw_bytes.decode("utf-8")
378
+ except UnicodeDecodeError:
379
+ raw_content = raw_bytes.decode("latin-1")
380
+
381
+ if not title:
382
+ m = re.search(r"<title[^>]*>([^<]+)</title>", raw_content, re.IGNORECASE)
383
+ if m:
384
+ title = m.group(1).strip()
385
+ else:
386
+ parsed = urlparse(url)
387
+ title = (parsed.hostname or "") + (parsed.path.rstrip("/") or "")
388
+
389
+ if not body:
390
+ body = f"Ingested from URL: {url}"
391
+
392
+ parsed = urlparse(url)
393
+ url_slug = _slug((parsed.hostname or "") + "-" + parsed.path.strip("/").replace("/", "-"))
394
+ raw_filename = f"{url_slug}.html"
395
+
396
+ return wiki_ingest(
397
+ wiki_root,
398
+ title=title,
399
+ body=body,
400
+ raw_content=raw_content,
401
+ raw_filename=raw_filename,
402
+ concepts=concepts,
403
+ entities=entities,
404
+ tags=tags,
405
+ )
406
+
407
+
218
408
  # ── Query ─────────────────────────────────────────────────────────────────────
219
409
 
220
410
  def wiki_query(wiki_root: Path, keyword: str) -> list[dict]:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agent-notes
3
- Version: 2.20.0
3
+ Version: 2.21.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
@@ -96,6 +96,7 @@ agent_notes/data/skills/git/SKILL.md
96
96
  agent_notes/data/skills/grill-me/SKILL.md
97
97
  agent_notes/data/skills/grill-with-docs/SKILL.md
98
98
  agent_notes/data/skills/improve-codebase-architecture/SKILL.md
99
+ agent_notes/data/skills/ingest/SKILL.md
99
100
  agent_notes/data/skills/obsidian-memory/SKILL.md
100
101
  agent_notes/data/skills/rails/SKILL.md
101
102
  agent_notes/data/skills/rails/controllers.md