agent-notes 2.0.4__py3-none-any.whl

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 (162) hide show
  1. agent_notes/VERSION +1 -0
  2. agent_notes/__init__.py +1 -0
  3. agent_notes/__main__.py +4 -0
  4. agent_notes/cli.py +348 -0
  5. agent_notes/commands/__init__.py +27 -0
  6. agent_notes/commands/_install_helpers.py +262 -0
  7. agent_notes/commands/build.py +170 -0
  8. agent_notes/commands/doctor.py +112 -0
  9. agent_notes/commands/info.py +95 -0
  10. agent_notes/commands/install.py +99 -0
  11. agent_notes/commands/list.py +169 -0
  12. agent_notes/commands/memory.py +430 -0
  13. agent_notes/commands/regenerate.py +152 -0
  14. agent_notes/commands/set_role.py +143 -0
  15. agent_notes/commands/uninstall.py +26 -0
  16. agent_notes/commands/update.py +169 -0
  17. agent_notes/commands/validate.py +199 -0
  18. agent_notes/commands/wizard.py +720 -0
  19. agent_notes/config.py +154 -0
  20. agent_notes/data/agents/agents.yaml +352 -0
  21. agent_notes/data/agents/analyst.md +45 -0
  22. agent_notes/data/agents/api-reviewer.md +47 -0
  23. agent_notes/data/agents/architect.md +46 -0
  24. agent_notes/data/agents/coder.md +28 -0
  25. agent_notes/data/agents/database-specialist.md +45 -0
  26. agent_notes/data/agents/debugger.md +47 -0
  27. agent_notes/data/agents/devil.md +47 -0
  28. agent_notes/data/agents/devops.md +38 -0
  29. agent_notes/data/agents/explorer.md +23 -0
  30. agent_notes/data/agents/integrations.md +44 -0
  31. agent_notes/data/agents/lead.md +216 -0
  32. agent_notes/data/agents/performance-profiler.md +44 -0
  33. agent_notes/data/agents/refactorer.md +48 -0
  34. agent_notes/data/agents/reviewer.md +44 -0
  35. agent_notes/data/agents/security-auditor.md +44 -0
  36. agent_notes/data/agents/system-auditor.md +38 -0
  37. agent_notes/data/agents/tech-writer.md +32 -0
  38. agent_notes/data/agents/test-runner.md +36 -0
  39. agent_notes/data/agents/test-writer.md +39 -0
  40. agent_notes/data/cli/claude.yaml +25 -0
  41. agent_notes/data/cli/copilot.yaml +18 -0
  42. agent_notes/data/cli/opencode.yaml +22 -0
  43. agent_notes/data/commands/brainstorm.md +8 -0
  44. agent_notes/data/commands/debug.md +9 -0
  45. agent_notes/data/commands/review.md +10 -0
  46. agent_notes/data/global-claude.md +290 -0
  47. agent_notes/data/global-copilot.md +27 -0
  48. agent_notes/data/global-opencode.md +40 -0
  49. agent_notes/data/hooks/session-context.md.tpl +19 -0
  50. agent_notes/data/models/claude-haiku-4-5.yaml +15 -0
  51. agent_notes/data/models/claude-opus-4-1.yaml +16 -0
  52. agent_notes/data/models/claude-opus-4-5.yaml +16 -0
  53. agent_notes/data/models/claude-opus-4-6.yaml +16 -0
  54. agent_notes/data/models/claude-opus-4-7.yaml +15 -0
  55. agent_notes/data/models/claude-sonnet-4-5.yaml +16 -0
  56. agent_notes/data/models/claude-sonnet-4-6.yaml +15 -0
  57. agent_notes/data/models/claude-sonnet-4.yaml +16 -0
  58. agent_notes/data/pricing.yaml +33 -0
  59. agent_notes/data/roles/orchestrator.yaml +5 -0
  60. agent_notes/data/roles/reasoner.yaml +5 -0
  61. agent_notes/data/roles/scout.yaml +5 -0
  62. agent_notes/data/roles/worker.yaml +5 -0
  63. agent_notes/data/rules/code-quality.md +9 -0
  64. agent_notes/data/rules/safety.md +10 -0
  65. agent_notes/data/scripts/cost-report +211 -0
  66. agent_notes/data/skills/brainstorming/SKILL.md +57 -0
  67. agent_notes/data/skills/code-review/SKILL.md +64 -0
  68. agent_notes/data/skills/debugging-protocol/SKILL.md +51 -0
  69. agent_notes/data/skills/docker-compose/SKILL.md +318 -0
  70. agent_notes/data/skills/docker-compose-advanced/SKILL.md +575 -0
  71. agent_notes/data/skills/docker-dockerfile/SKILL.md +385 -0
  72. agent_notes/data/skills/docker-dockerfile-languages/SKILL.md +293 -0
  73. agent_notes/data/skills/git/SKILL.md +87 -0
  74. agent_notes/data/skills/rails-active-storage/SKILL.md +321 -0
  75. agent_notes/data/skills/rails-broadcasting/SKILL.md +374 -0
  76. agent_notes/data/skills/rails-concerns/SKILL.md +806 -0
  77. agent_notes/data/skills/rails-controllers/SKILL.md +510 -0
  78. agent_notes/data/skills/rails-controllers-advanced/SKILL.md +441 -0
  79. agent_notes/data/skills/rails-helpers/SKILL.md +677 -0
  80. agent_notes/data/skills/rails-initializers/SKILL.md +79 -0
  81. agent_notes/data/skills/rails-javascript/SKILL.md +567 -0
  82. agent_notes/data/skills/rails-jobs/SKILL.md +700 -0
  83. agent_notes/data/skills/rails-kamal/SKILL.md +483 -0
  84. agent_notes/data/skills/rails-lib/SKILL.md +101 -0
  85. agent_notes/data/skills/rails-mailers/SKILL.md +321 -0
  86. agent_notes/data/skills/rails-migrations/SKILL.md +268 -0
  87. agent_notes/data/skills/rails-models/SKILL.md +459 -0
  88. agent_notes/data/skills/rails-models-advanced/SKILL.md +398 -0
  89. agent_notes/data/skills/rails-routes/SKILL.md +804 -0
  90. agent_notes/data/skills/rails-style/SKILL.md +538 -0
  91. agent_notes/data/skills/rails-testing-controllers/SKILL.md +343 -0
  92. agent_notes/data/skills/rails-testing-models/SKILL.md +296 -0
  93. agent_notes/data/skills/rails-testing-system/SKILL.md +375 -0
  94. agent_notes/data/skills/rails-validations/SKILL.md +108 -0
  95. agent_notes/data/skills/rails-view-components/SKILL.md +511 -0
  96. agent_notes/data/skills/rails-view-components-advanced/SKILL.md +376 -0
  97. agent_notes/data/skills/rails-views/SKILL.md +413 -0
  98. agent_notes/data/skills/rails-views-advanced/SKILL.md +450 -0
  99. agent_notes/data/skills/refactoring-protocol/SKILL.md +64 -0
  100. agent_notes/data/skills/tdd/SKILL.md +57 -0
  101. agent_notes/data/templates/__init__.py +1 -0
  102. agent_notes/data/templates/__pycache__/__init__.cpython-314.pyc +0 -0
  103. agent_notes/data/templates/frontmatter/__init__.py +1 -0
  104. agent_notes/data/templates/frontmatter/__pycache__/__init__.cpython-314.pyc +0 -0
  105. agent_notes/data/templates/frontmatter/__pycache__/claude.cpython-314.pyc +0 -0
  106. agent_notes/data/templates/frontmatter/__pycache__/cursor.cpython-314.pyc +0 -0
  107. agent_notes/data/templates/frontmatter/__pycache__/opencode.cpython-314.pyc +0 -0
  108. agent_notes/data/templates/frontmatter/claude.py +44 -0
  109. agent_notes/data/templates/frontmatter/opencode.py +104 -0
  110. agent_notes/doctor_checks.py +189 -0
  111. agent_notes/domain/__init__.py +17 -0
  112. agent_notes/domain/agent.py +34 -0
  113. agent_notes/domain/cli_backend.py +40 -0
  114. agent_notes/domain/diagnostics.py +29 -0
  115. agent_notes/domain/diff.py +44 -0
  116. agent_notes/domain/model.py +27 -0
  117. agent_notes/domain/role.py +13 -0
  118. agent_notes/domain/rule.py +13 -0
  119. agent_notes/domain/skill.py +15 -0
  120. agent_notes/domain/state.py +46 -0
  121. agent_notes/install_state.py +11 -0
  122. agent_notes/registries/__init__.py +16 -0
  123. agent_notes/registries/_base.py +46 -0
  124. agent_notes/registries/agent_registry.py +107 -0
  125. agent_notes/registries/cli_registry.py +89 -0
  126. agent_notes/registries/model_registry.py +85 -0
  127. agent_notes/registries/role_registry.py +64 -0
  128. agent_notes/registries/rule_registry.py +80 -0
  129. agent_notes/registries/skill_registry.py +141 -0
  130. agent_notes/services/__init__.py +8 -0
  131. agent_notes/services/diagnostics/__init__.py +47 -0
  132. agent_notes/services/diagnostics/_checks.py +272 -0
  133. agent_notes/services/diagnostics/_display.py +346 -0
  134. agent_notes/services/diagnostics/_fix.py +169 -0
  135. agent_notes/services/diff.py +349 -0
  136. agent_notes/services/fs.py +195 -0
  137. agent_notes/services/install_state_builder.py +210 -0
  138. agent_notes/services/installer.py +293 -0
  139. agent_notes/services/memory_backend.py +155 -0
  140. agent_notes/services/rendering.py +329 -0
  141. agent_notes/services/session_context.py +23 -0
  142. agent_notes/services/settings_writer.py +79 -0
  143. agent_notes/services/state_store.py +249 -0
  144. agent_notes/services/ui.py +419 -0
  145. agent_notes/services/user_config.py +62 -0
  146. agent_notes/services/validation.py +67 -0
  147. agent_notes/state.py +21 -0
  148. agent_notes-2.0.4.dist-info/METADATA +14 -0
  149. agent_notes-2.0.4.dist-info/RECORD +162 -0
  150. agent_notes-2.0.4.dist-info/WHEEL +5 -0
  151. agent_notes-2.0.4.dist-info/entry_points.txt +2 -0
  152. agent_notes-2.0.4.dist-info/licenses/LICENSE +21 -0
  153. agent_notes-2.0.4.dist-info/top_level.txt +2 -0
  154. tests/conftest.py +20 -0
  155. tests/functional/__init__.py +0 -0
  156. tests/functional/test_build_commands.py +88 -0
  157. tests/functional/test_registries.py +128 -0
  158. tests/integration/__init__.py +0 -0
  159. tests/integration/test_build_output.py +129 -0
  160. tests/plugins/__init__.py +0 -0
  161. tests/plugins/test_agents.py +93 -0
  162. tests/plugins/test_skills.py +77 -0
@@ -0,0 +1,62 @@
1
+ """Load and merge user config for agent role/model overrides and prompt patches."""
2
+ from __future__ import annotations
3
+ from pathlib import Path
4
+ from typing import Optional
5
+ import yaml
6
+
7
+
8
+ def config_path() -> Path:
9
+ xdg = Path.home() / ".config" / "agent-notes" / "config.yaml"
10
+ legacy = Path.home() / ".agent-notes.yaml"
11
+ if xdg.exists():
12
+ return xdg
13
+ if legacy.exists():
14
+ return legacy
15
+ return xdg # canonical write location
16
+
17
+
18
+ def load_user_config(path: Optional[Path] = None) -> dict:
19
+ """Return user config dict. Empty dict if file missing."""
20
+ p = path or config_path()
21
+ if not p.exists():
22
+ return {}
23
+ try:
24
+ data = yaml.safe_load(p.read_text())
25
+ return data or {}
26
+ except yaml.YAMLError as e:
27
+ raise ValueError(f"Invalid YAML in {p}: {e}") from e
28
+
29
+
30
+ def resolve_agent_role(agent_name: str, default_role: str, config: dict) -> str:
31
+ """Return effective role, applying user override if present."""
32
+ return config.get("agent_roles", {}).get(agent_name, default_role)
33
+
34
+
35
+ def resolve_role_model(role: str, backend_name: str, config: dict) -> Optional[str]:
36
+ """Return user-specified model ID for a role+backend, or None."""
37
+ return config.get("role_models", {}).get(backend_name, {}).get(role)
38
+
39
+
40
+ def get_patch(agent_name: str, config: dict) -> Optional[str]:
41
+ """Return patch text to append to agent prompt, or None."""
42
+ return config.get("patches", {}).get(agent_name)
43
+
44
+
45
+ def merge_configs(base: dict, override: dict) -> dict:
46
+ """Merge override on top of base. Nested dicts are merged; patches are concatenated."""
47
+ result = dict(base)
48
+ for key, value in override.items():
49
+ if key == "patches" and key in result:
50
+ # Concatenate patches from both configs
51
+ merged_patches = dict(result[key])
52
+ for agent, patch in value.items():
53
+ if agent in merged_patches:
54
+ merged_patches[agent] = merged_patches[agent].rstrip() + "\n\n" + patch
55
+ else:
56
+ merged_patches[agent] = patch
57
+ result[key] = merged_patches
58
+ elif isinstance(value, dict) and key in result and isinstance(result[key], dict):
59
+ result[key] = {**result[key], **value}
60
+ else:
61
+ result[key] = value
62
+ return result
@@ -0,0 +1,67 @@
1
+ """Validation helpers used by commands/validate.py."""
2
+
3
+ import re
4
+ from pathlib import Path
5
+ from typing import Optional
6
+
7
+
8
+ def has_field(file_path: Path, field: str) -> bool:
9
+ """Check if file has frontmatter field."""
10
+ try:
11
+ content = file_path.read_text()
12
+ return f"{field}:" in content
13
+ except (FileNotFoundError, OSError):
14
+ return False
15
+
16
+
17
+ def get_field(file_path: Path, field: str) -> Optional[str]:
18
+ """Extract frontmatter field value."""
19
+ try:
20
+ content = file_path.read_text()
21
+ lines = content.split('\n')
22
+
23
+ in_frontmatter = False
24
+ for line in lines:
25
+ if line.strip() == "---":
26
+ if not in_frontmatter:
27
+ in_frontmatter = True
28
+ continue
29
+ else:
30
+ break # End of frontmatter
31
+
32
+ if in_frontmatter and line.startswith(f"{field}:"):
33
+ value = line.split(':', 1)[1].strip()
34
+ # Remove quotes
35
+ value = value.strip('"\'')
36
+ return value
37
+
38
+ return None
39
+ except (FileNotFoundError, OSError):
40
+ return None
41
+
42
+
43
+ def line_count(file_path: Path) -> int:
44
+ """Count lines in file."""
45
+ try:
46
+ return len(file_path.read_text().split('\n'))
47
+ except (FileNotFoundError, OSError):
48
+ return 0
49
+
50
+
51
+ def has_frontmatter(file_path: Path) -> bool:
52
+ """Check if file starts with frontmatter."""
53
+ try:
54
+ content = file_path.read_text()
55
+ return content.startswith("---\n")
56
+ except (FileNotFoundError, OSError):
57
+ return False
58
+
59
+
60
+ def check_unclosed_code_blocks(file_path: Path) -> bool:
61
+ """Check for unclosed code blocks."""
62
+ try:
63
+ content = file_path.read_text()
64
+ fence_count = content.count('```')
65
+ return fence_count % 2 == 0 # Even number means all blocks are closed
66
+ except (FileNotFoundError, OSError):
67
+ return True
agent_notes/state.py ADDED
@@ -0,0 +1,21 @@
1
+ """Installation state management."""
2
+
3
+ # Re-export dataclasses from domain
4
+ from .domain.state import State, ScopeState, BackendState, InstalledItem # noqa: F401
5
+
6
+ # Re-export I/O functions from services
7
+ from .services.state_store import (
8
+ state_dir, state_file,
9
+ load_state as load, load_state, # Export both names
10
+ save_state as save, save_state, # Export both names
11
+ clear_state as clear,
12
+ get_scope, set_scope, remove_scope, default_state, sha256_of, now_iso
13
+ )
14
+
15
+ # Backward compatibility aliases
16
+ __all__ = [
17
+ 'State', 'ScopeState', 'BackendState', 'InstalledItem',
18
+ 'state_dir', 'state_file', 'load', 'save', 'clear',
19
+ 'load_state', 'save_state', # Original names too
20
+ 'get_scope', 'set_scope', 'remove_scope', 'default_state', 'sha256_of', 'now_iso'
21
+ ]
@@ -0,0 +1,14 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-notes
3
+ Version: 2.0.4
4
+ Summary: AI agent configuration manager for Claude Code, OpenCode, and Copilot
5
+ Author: Eugene Naumov
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/rubakas/agent-notes
8
+ Project-URL: Repository, https://github.com/rubakas/agent-notes
9
+ Requires-Python: >=3.9
10
+ License-File: LICENSE
11
+ Requires-Dist: pyyaml>=6.0
12
+ Provides-Extra: dev
13
+ Requires-Dist: pytest>=7.0; extra == "dev"
14
+ Dynamic: license-file
@@ -0,0 +1,162 @@
1
+ agent_notes/VERSION,sha256=E39GckECPa36YF2wDmMLJak5TQ_HIycYgSmDuiS5OUU,6
2
+ agent_notes/__init__.py,sha256=nNtT73D8u7W5AqsLodGp6jvsjT-y3kQ74pgToqrZeDw,53
3
+ agent_notes/__main__.py,sha256=EAOa_67LSqh5Jb9obGmEE9Aofyd5yv68mxLMmUGBwgE,88
4
+ agent_notes/cli.py,sha256=tjX1M6XUn-xhemFNdypsy6nOK50UazQA9rvRK7Y2O0U,14504
5
+ agent_notes/config.py,sha256=5wfeXtFy-x6SHwRa9FbfsR6GWWoiS7yihncz6jfCTCk,6414
6
+ agent_notes/doctor_checks.py,sha256=kk5zmpfdpS6A14JqyOuyVzz7_HHbFzRM3zZxCzRcvV8,9020
7
+ agent_notes/install_state.py,sha256=PLY3YePlIiFPaREN7YCeEvfSh8G5Q5beElAc_NRbz_k,486
8
+ agent_notes/state.py,sha256=-LQ045BC0-xBc4ltGzNHJFYwb_C3pvYe_RsIvlfen90,785
9
+ agent_notes/commands/__init__.py,sha256=vM4L4muUwH-VlsKz4CQIPvmIFB6zZdtwefJf9j78vBs,893
10
+ agent_notes/commands/_install_helpers.py,sha256=0ndUq957dzQtUkkfMmNNpVATwJDicKUQfe5xZ-Z5oGo,9625
11
+ agent_notes/commands/build.py,sha256=wAJlXM3n2UkAz84EXQbeGD4rMTZstr3wbV-VqssZzrk,5045
12
+ agent_notes/commands/doctor.py,sha256=4I72UQVQMsn8xKlF2lF6dZezwhGh6zW1oj2i7LNsYz8,3617
13
+ agent_notes/commands/info.py,sha256=mWczDJ6VkagBQkWGBdlFNURnDlxzch-Es911FLXzAvg,3662
14
+ agent_notes/commands/install.py,sha256=3GRqYz6qEIbmyJ8ifxCl_VFJO1ZGkGxVzLoECZrwYFo,3623
15
+ agent_notes/commands/list.py,sha256=7Qe22Cke6ME-u6crbMk0MTquzwUndwFufue8gNM74KU,5816
16
+ agent_notes/commands/memory.py,sha256=omJHHcXEA_whgbl8VgYQdMnFplnQ_DtnOp_6nWqx9pM,13867
17
+ agent_notes/commands/regenerate.py,sha256=jlpBvO3b3B_oZWdBJWOX5-bEpZYCO0RlbAF4qDb76vk,5547
18
+ agent_notes/commands/set_role.py,sha256=OPXKs5071qzO06uapLC8xqYei1M45iQCeS0kkzrPQVg,5389
19
+ agent_notes/commands/uninstall.py,sha256=6f2-ROmsGIFEpfLOyqBhnJQkWLlO0D1tUdnGNeK8nAA,752
20
+ agent_notes/commands/update.py,sha256=C2PwBqkmI80KNMvpuoKcDJSAb2cMYyFyQrI0DyFAvHs,5749
21
+ agent_notes/commands/validate.py,sha256=5YJoO9zez5zQd1y5IAJiiFiLR5D0PO4bBzewK8vdSaw,7104
22
+ agent_notes/commands/wizard.py,sha256=1zHhBdye8e2HjOe2ZFBcEVicJyxcMlbmGqzzORhRXks,30127
23
+ agent_notes/data/global-claude.md,sha256=5mXAvUHe7vnqeDRY2gJ5Ii-weps88GT6GOUbrSGxfBo,15319
24
+ agent_notes/data/global-copilot.md,sha256=a4mLfNZ10im7fHDrQe_bhBQ-5C_IX1lSh9jt2EwfSh8,936
25
+ agent_notes/data/global-opencode.md,sha256=4mAhdI6Hbf3t4YZCGPytGsILI2CSidtVszFr4rd3I8g,1697
26
+ agent_notes/data/pricing.yaml,sha256=_RdzC5tb6J_S_d6EuCzOOyXcxfstO46BBhHMr9Z2pkE,929
27
+ agent_notes/data/agents/agents.yaml,sha256=2fRprOudEgpUEfe5m7kA1V43TIiNgGb5yTosBKTcBHI,11346
28
+ agent_notes/data/agents/analyst.md,sha256=_W3Xw_rHsvWsP8-J722ce1kamkZWFYvNS-gqE5n4YRg,2252
29
+ agent_notes/data/agents/api-reviewer.md,sha256=_ZTKalS6_b1kK7KXqJtv5QRuWxnetamHKzJxbJiyhYs,1784
30
+ agent_notes/data/agents/architect.md,sha256=i_BWeMRwu4cgUAStzqH2vE6BeVMQGzrDMGT8jfg3Fuc,1449
31
+ agent_notes/data/agents/coder.md,sha256=SGi7_rA_9SwDmFYEYXdzSby_BpLlLh0yF8SalSJKbas,1187
32
+ agent_notes/data/agents/database-specialist.md,sha256=od5-eVycRuK1h5Hf2xHWTgwJH1V2Xevq0a8OvB7NkiE,2006
33
+ agent_notes/data/agents/debugger.md,sha256=7nVeAC6tqL9A11fmewDbhQMF50FZ-wCs06-KrHlNFso,1396
34
+ agent_notes/data/agents/devil.md,sha256=g8QkHMhXrk2qB9o6dgcAfYZEroxb1zIrAsEIT5GVzIo,1357
35
+ agent_notes/data/agents/devops.md,sha256=5Zf4iomnARBZfQEItRQwQJ79MVGTFYNLo_aYQelydzE,1513
36
+ agent_notes/data/agents/explorer.md,sha256=MGfuKzMCog_Q1j0a6d7rcjGP5R1h8jgiud40FfyvwkA,948
37
+ agent_notes/data/agents/integrations.md,sha256=3dptJxTG3WP0Q3yPoWtzjKs5Lif282q9CAyFpOp0fvM,1511
38
+ agent_notes/data/agents/lead.md,sha256=89vp1-pSwf3l4q7iWQ8mb286dEy9z-EzM2GGw1jIPiY,9786
39
+ agent_notes/data/agents/performance-profiler.md,sha256=GtohSPwTDUQrLA1sdXpCjVlX4NFRCFnocuW0o0qE1OY,1607
40
+ agent_notes/data/agents/refactorer.md,sha256=HEFEMrozgPZ0_QYmoEag9tHQ15fHk2rTeI0lYFTpsT4,1410
41
+ agent_notes/data/agents/reviewer.md,sha256=pY_Ogj0Rpi4o3FLw20eu3G7FT8nhw0edCSYnl6hQ1TI,1896
42
+ agent_notes/data/agents/security-auditor.md,sha256=BLXPPeoxh7s24SoTKv9IspFwN-WtZxFyCCEUTp9zZIY,2195
43
+ agent_notes/data/agents/system-auditor.md,sha256=otxLGjW7R9iHeKESExtV2sojBtS2MHMTfMVdq3T96mY,1284
44
+ agent_notes/data/agents/tech-writer.md,sha256=QSiCfus2q_gDO3w9WN7UK70MI1KJAwigqSHfhwDB2Ck,1686
45
+ agent_notes/data/agents/test-runner.md,sha256=5J4YXK48OF2aQfImYOabOCuFEHurSE4C44uYjcCtklA,1400
46
+ agent_notes/data/agents/test-writer.md,sha256=ThLLLrJTkCIWraEaPxh-4oKnVFhmFX-pnrYWS40lZEs,2048
47
+ agent_notes/data/cli/claude.yaml,sha256=ubWCU37SlFzpf4rMn7vDDcVvOS4NTwccCV6vYhA4e6g,521
48
+ agent_notes/data/cli/copilot.yaml,sha256=qBMev0yYIf_26mqwStjcf_zWEOPAoRCLf4rcqACD0ww,378
49
+ agent_notes/data/cli/opencode.yaml,sha256=UtKoknnua3c7Yr9QErVSOjee_hhcYM5b35-gPnpzSAA,516
50
+ agent_notes/data/commands/brainstorm.md,sha256=da0St-n9LKvI1IPddB8INI2N4_sIvX7NBWvTg78s3y8,379
51
+ agent_notes/data/commands/debug.md,sha256=pPAUBdaYV2eM6WG3JfkODp2g_yGgjjkU9F9QNu57nMs,461
52
+ agent_notes/data/commands/review.md,sha256=MRHI36lxRn7eVhRvDdWpQyDnpTmWMmgRhYC9DeKvnwY,510
53
+ agent_notes/data/hooks/session-context.md.tpl,sha256=y1rGR3WiIHRomulTT1CPLvitgPVDReRvQKiwjrJIflM,648
54
+ agent_notes/data/models/claude-haiku-4-5.yaml,sha256=zmaIU23bBqIWLlejGu3B2kkrPR6sB6YGJUTVtk-KrXo,277
55
+ agent_notes/data/models/claude-opus-4-1.yaml,sha256=Yi7oGZkRJkYVtFkJk_hTuzZTc0X4lv0VKx59MzZ_D0Q,303
56
+ agent_notes/data/models/claude-opus-4-5.yaml,sha256=Q9dy8nbA7xebCyxOB0TOLX-BtNMz677j-Afe6KOuCbs,302
57
+ agent_notes/data/models/claude-opus-4-6.yaml,sha256=GLrJhva6UKii26NWr1Hj3f5dY0vdA2pojUvlnm1_CGk,300
58
+ agent_notes/data/models/claude-opus-4-7.yaml,sha256=nYRI9AU41u34x-qbbTnxsLe8P5mzLoCypVnGyd6hlPM,272
59
+ agent_notes/data/models/claude-sonnet-4-5.yaml,sha256=GJrwD4O_dm7_2KpKFu5QThxOJ0x3hNflK2L4A-hubS8,312
60
+ agent_notes/data/models/claude-sonnet-4-6.yaml,sha256=N_Y2GJiGHhii9i1eekA2D6XRJOgYBo7zVyPLDCwd7Xg,283
61
+ agent_notes/data/models/claude-sonnet-4.yaml,sha256=bEDxxljgNAFF6B8xT579Oz366gJ_fyLRZfgb6NtAsUs,311
62
+ agent_notes/data/roles/orchestrator.yaml,sha256=0DnJv45m3Yb7wiA6FlLVWYBlzNIzemKxdH5o4c-nGPA,166
63
+ agent_notes/data/roles/reasoner.yaml,sha256=G82eJyuL1ny3ZHbuSrznDofZOMs1otggYTu0AnfoDP0,150
64
+ agent_notes/data/roles/scout.yaml,sha256=lpQn0CJ5cRljuBlLyIMAhXKdJu0Cf-eRWTx_ejF3czE,135
65
+ agent_notes/data/roles/worker.yaml,sha256=r4LxfECkFpV2bdsCCCZXo_edoqChR-xubDJLRUwsXT0,143
66
+ agent_notes/data/rules/code-quality.md,sha256=CX4UIVWCny4gv7pWAX45dfj9L2eabdCc-RhSwhB5ZOU,483
67
+ agent_notes/data/rules/safety.md,sha256=I9HGLlVpP3dcDDS6jXqloXcgW8-IVJMyl8V_tbamkj8,559
68
+ agent_notes/data/scripts/cost-report,sha256=TLO_D1u8SlRXISEWZggLTWhDE9SX58d09yKV5kua3fk,6918
69
+ agent_notes/data/skills/brainstorming/SKILL.md,sha256=d2-zf-zrY6vzDCj5Z1Bv4TG16IM0ZpxUDGKBUrKBb7Y,2282
70
+ agent_notes/data/skills/code-review/SKILL.md,sha256=nvNX2d4yGXe3ZV12TyhQconDVcTwG9cHd8jKADeVIng,2362
71
+ agent_notes/data/skills/debugging-protocol/SKILL.md,sha256=cNY8_69juFgAg8Kxc2bj97zqfFWxJXgVsoJzCMmmQSM,2106
72
+ agent_notes/data/skills/docker-compose/SKILL.md,sha256=FxVR5qvIkJYBTRwEDW3Ag7cy5YzhRycaXCuN1J_ViKc,7886
73
+ agent_notes/data/skills/docker-compose-advanced/SKILL.md,sha256=WfbfcX7wcudPwATAbMn5zjU0DtoI3t2ZP4SXNmB6udM,12587
74
+ agent_notes/data/skills/docker-dockerfile/SKILL.md,sha256=n5GcRZsiwBdMO69d6IxrqJoTAEMqVgGgaPuNNgs0Lmw,10205
75
+ agent_notes/data/skills/docker-dockerfile-languages/SKILL.md,sha256=EqOqq2Pe-ceU8ZDVOyZiYjf4DRLV-KiMtrn9qtTW59M,6515
76
+ agent_notes/data/skills/git/SKILL.md,sha256=OT3b-2TzwmCRYAhYzAFTSqzbh7PnfOiihSH_Z4y1SR8,1944
77
+ agent_notes/data/skills/rails-active-storage/SKILL.md,sha256=SKkp67EVRUGuKq1sqh_orIiUAeQtex2o1WAfL-3m9Lc,6963
78
+ agent_notes/data/skills/rails-broadcasting/SKILL.md,sha256=8JbPrSZ8rDZ658Gz2b534uPXScfkkKspBnOHkifJDok,7667
79
+ agent_notes/data/skills/rails-concerns/SKILL.md,sha256=4yQCdU8Gy0yYPCkUNIF96UUGZEhj4I2_5aL8ZrM673M,16165
80
+ agent_notes/data/skills/rails-controllers/SKILL.md,sha256=xwqcXlntzrnD6VZsVFo06OU91XDFpHCnLp07jXjTieA,11293
81
+ agent_notes/data/skills/rails-controllers-advanced/SKILL.md,sha256=5OXgdhnWyd5rclZn21xb-DnRR3Tr64I-DMxsp6r803E,8728
82
+ agent_notes/data/skills/rails-helpers/SKILL.md,sha256=3TEooNjzujQJOnYhnLtuha1JGbXN3pyl8e2i_QkOcc8,16349
83
+ agent_notes/data/skills/rails-initializers/SKILL.md,sha256=YcwmpTv1lQ9Kuwe__p49bV3Khc3BbM52VeisinYyJFE,1572
84
+ agent_notes/data/skills/rails-javascript/SKILL.md,sha256=EtSVLbo2Ux-dTFIb3JjPk5lwVwpw1t4KwicyCjX5g8s,12173
85
+ agent_notes/data/skills/rails-jobs/SKILL.md,sha256=Fi9ucRWFZ-_HvBKOJxDB4Z9RHxT4UppzyFHtoJxbX3A,13559
86
+ agent_notes/data/skills/rails-kamal/SKILL.md,sha256=HBRspZ1tX6KL5oAj6THdZgjCX-UFN9V11pZvUfZQnuY,7732
87
+ agent_notes/data/skills/rails-lib/SKILL.md,sha256=cAJhQ9Wp48twlfPqscWiWt3m5MO4fbwyOalOKI5Yxg4,1952
88
+ agent_notes/data/skills/rails-mailers/SKILL.md,sha256=aUNJWgIfX4yH5if1pJXYto4vlQvR6oEZtVukoWVg8AA,5922
89
+ agent_notes/data/skills/rails-migrations/SKILL.md,sha256=wbE7QPjknk-nKET-pdIRg33wnPz9PNStOVsbiI0T7eg,4773
90
+ agent_notes/data/skills/rails-models/SKILL.md,sha256=hmejzvAUmzMGl1aDlO8yxQqXdbu2LtD0TJnzCJ3K0gY,11025
91
+ agent_notes/data/skills/rails-models-advanced/SKILL.md,sha256=8MoGewmt29GB3ykzdivfPuLj6qjZWKjztzfxIY0KhFQ,7745
92
+ agent_notes/data/skills/rails-routes/SKILL.md,sha256=udfFxBk-exQlIMXYEnJ2zy4GH5wlUsFX-K0SQ0Z4-e0,15682
93
+ agent_notes/data/skills/rails-style/SKILL.md,sha256=jibISwJ67aTuyBKm-nGt1t8vk_mQL9Frof3sJjDzbx0,10867
94
+ agent_notes/data/skills/rails-testing-controllers/SKILL.md,sha256=Y8dcGFRkwqW00JdsDWrCepca2yQCIU6T5GbZ16Y6Cyc,6640
95
+ agent_notes/data/skills/rails-testing-models/SKILL.md,sha256=Y2RYjeef2p4e5iDrvtfyRSJc03T3Us3aZ776sksu6Vo,6055
96
+ agent_notes/data/skills/rails-testing-system/SKILL.md,sha256=V3dU55_2i4a2oT6Qir7_EqvRYPJ9ExDh2RAuiMdnPEA,7204
97
+ agent_notes/data/skills/rails-validations/SKILL.md,sha256=Wo0MHxidY4gtrYd__BimS_FBsMy5-jj5KPiDhW9PUlo,2063
98
+ agent_notes/data/skills/rails-view-components/SKILL.md,sha256=PT5jdMYE0q9AhdCVHM14coacxDgxJxJw73ISITdig2U,10971
99
+ agent_notes/data/skills/rails-view-components-advanced/SKILL.md,sha256=DxaaP69Jaif7-TxghPc4LzByWAO4ANHgeftbBk5MP9s,8019
100
+ agent_notes/data/skills/rails-views/SKILL.md,sha256=VwBwB3OXUGawiwaqH4PeH67R58fSWB1UxdtTPR6wloE,8583
101
+ agent_notes/data/skills/rails-views-advanced/SKILL.md,sha256=wnRPv_3K0xghfQXsCtjhMuYHisxXhFS5ilBRCqYtBko,9045
102
+ agent_notes/data/skills/refactoring-protocol/SKILL.md,sha256=Wy0jGMk3vYfX0Di6rpmrwrXKHx-yV559viWJg-mLdxw,3065
103
+ agent_notes/data/skills/tdd/SKILL.md,sha256=DsYGXDS1rz-RARqV2NlVmeHngdbcJ8hhHy3dAjYPQ-Q,2106
104
+ agent_notes/data/templates/__init__.py,sha256=NpGBytOwk_ywSOqKt9Ub-SSUNkDYR2uez4UVbOAEwUM,41
105
+ agent_notes/data/templates/__pycache__/__init__.cpython-314.pyc,sha256=3aE_8ZRVK3HmgW1q41V4WDbJ_MLA6ktGBTXyROI5fkI,223
106
+ agent_notes/data/templates/frontmatter/__init__.py,sha256=SlCC0jmmvVxtEE4T8zC3vjPOB3UK6Vjkpy3SjWesD_s,52
107
+ agent_notes/data/templates/frontmatter/claude.py,sha256=8UlcD85cu7kSeEaxSNNtPBX9zGGf6Jkk8og-DRYpQDQ,1448
108
+ agent_notes/data/templates/frontmatter/opencode.py,sha256=mHxmuKcZXki5OOcsOcKgnRD_Ap6ze2IzNUE25NIKoLY,3285
109
+ agent_notes/data/templates/frontmatter/__pycache__/__init__.cpython-314.pyc,sha256=7YF0z6DTZZGVXL4GuYvZZiY7HOO_YvKyvF5_1i6tx6s,246
110
+ agent_notes/data/templates/frontmatter/__pycache__/claude.cpython-314.pyc,sha256=XKpeqMYF7ZLuv_UnzPo5fE0BPjBDPvMWzQrPSTcCrvw,2397
111
+ agent_notes/data/templates/frontmatter/__pycache__/cursor.cpython-314.pyc,sha256=wfizKrb9TbPALC-er2yN-7zt6u6GWJAcRvd6Pvd0nxA,1787
112
+ agent_notes/data/templates/frontmatter/__pycache__/opencode.cpython-314.pyc,sha256=LpJ3yY1UT32D-6KcY6PkKHwAjjyhBDpkmpn5Q5vOB1k,4590
113
+ agent_notes/domain/__init__.py,sha256=Z0JSvaeG6XFKVDSt5mpsXEEMiy7fBExoy1Fbfgr4J_Y,664
114
+ agent_notes/domain/agent.py,sha256=M9uTvcCo0aduiJhhWv0D7OxuXYKm4aXP8QLhAvS0BRg,1435
115
+ agent_notes/domain/cli_backend.py,sha256=0E_msddRNB6JHvWzTn7aeLAyVmrFnnaOgk5Xxufzlg4,1706
116
+ agent_notes/domain/diagnostics.py,sha256=5UKQvXKivbXkbV4XPGx_TsschRt8-LX3QUO50p-FeD4,739
117
+ agent_notes/domain/diff.py,sha256=1RDmH06bqf_nXqwqbMjq6FrSQYb-LgfXs51OsA4mPUw,1774
118
+ agent_notes/domain/model.py,sha256=Mh5c4jad01HB6jk2MLNSIl-rKpY3uMvDM1owizPUn_4,1183
119
+ agent_notes/domain/role.py,sha256=opLIvu_MluR6GGwr-7yQvlHv1isK2FaFOeC8e3vF86o,263
120
+ agent_notes/domain/rule.py,sha256=h_yLYPBESwMfW3An2fOGSMhTrkjMfn7Gkfx433eJzpE,314
121
+ agent_notes/domain/skill.py,sha256=NNjakUWhcTnn95ZeNfFH_4LFtEl43Wcfw5mvEECEhQw,468
122
+ agent_notes/domain/state.py,sha256=0HnfzJWK82NCkok__82CvId-YthyZi0dNav8G47YcQE,1462
123
+ agent_notes/registries/__init__.py,sha256=3ck4jz8YgqaQBSSfKUkcwrM8Me0_6JvL-_RHvm8iCFw,994
124
+ agent_notes/registries/_base.py,sha256=HDVf-fzwQj-JkqrflIYwX0y2_rv7axrWziczayvxEZc,1611
125
+ agent_notes/registries/agent_registry.py,sha256=eU3ipCOd1LyTAKJFXz7ErmMKMIvLK2uL-bTKmBHw8Wo,3891
126
+ agent_notes/registries/cli_registry.py,sha256=EKHYyQYLLhgc8idSqEZ9IwSWthTqfeMzjqV84DLjTCY,3017
127
+ agent_notes/registries/model_registry.py,sha256=n81nc8IbvHUY_EwjzAYiUFLr3K7dftcjIXJFDLfoQOs,2911
128
+ agent_notes/registries/role_registry.py,sha256=KQvlETHkyYaOlTtS5snKVlL35friMc_gloG4YU-kVQ0,2004
129
+ agent_notes/registries/rule_registry.py,sha256=s81gSHu-hOL5tlq_TeUdIvK_if5wefZktTRXqGCygOY,2252
130
+ agent_notes/registries/skill_registry.py,sha256=w6DVRDebb4IO1s1CX4C8pUMYj6w7fo5Ifh1kSSKUqi4,4487
131
+ agent_notes/services/__init__.py,sha256=yRCXbPVjtkWJZrjmLLKcilHPwHDW7vO5JTeRRbrgd_8,547
132
+ agent_notes/services/diff.py,sha256=XYL3p-8OtdSaUn-ApKNYcmatpzt_tk60gQtMUbEKP60,13913
133
+ agent_notes/services/fs.py,sha256=2qWKCI_W5iitSvKnYk96jbgwdYEsCC39d3pvyS-5-Jw,5839
134
+ agent_notes/services/install_state_builder.py,sha256=8MIbrwnlNb7DGoUFfwKa5lq1afTUOi6kEt67SSkdcZE,8583
135
+ agent_notes/services/installer.py,sha256=gfBMOONcdhDY22F2o7i0m1-DzlbmZz51L5mQ7Ibd04A,10629
136
+ agent_notes/services/memory_backend.py,sha256=OAyZrg1YF7PeHoLH3oG2C9_MogzbErvtt7MAdNzIYGs,5351
137
+ agent_notes/services/rendering.py,sha256=9f7mxXVET7Bep-5Erz8YTVWyayxYGuUnMX5o9YdEw0g,14474
138
+ agent_notes/services/session_context.py,sha256=CEx3dVQ3KlELqURQfj627-UB85ejk8W9xdrEj5LXYrE,815
139
+ agent_notes/services/settings_writer.py,sha256=T6_WetwXWBMq367ARhcp9nYwKX9ogm_Oq4u7fZFFRpY,2620
140
+ agent_notes/services/state_store.py,sha256=E0KHyVCES6uyeGte8bN-zmExtIsV8wcWiHtZdqtXPPg,8062
141
+ agent_notes/services/ui.py,sha256=C6SbUCd3LpPgqwMtUJGwc0Vpwn3Qn8eA_DL0l-c4yn8,13430
142
+ agent_notes/services/user_config.py,sha256=9dD14EkpqdZud26RLpzZOHSdrDLp0j_10rfOu8Z3kUo,2317
143
+ agent_notes/services/validation.py,sha256=9Aru7NiCYU2yKnxY6ROY2q_xAU6sqA4Cnz50OBtwdx4,1947
144
+ agent_notes/services/diagnostics/__init__.py,sha256=oELb_SHuWnqVKBT8IxxyUraRCw9cp89czNuYobTdeIc,980
145
+ agent_notes/services/diagnostics/_checks.py,sha256=16T5JjHt0zRXRyfq3JctdzTr38Rqb2IuD3Vll3rxECY,11931
146
+ agent_notes/services/diagnostics/_display.py,sha256=9VYfVXYDat4isYgRJdJ76ytQ4N1PgpAQ2U09PmZ21sg,13640
147
+ agent_notes/services/diagnostics/_fix.py,sha256=byYGhbBxHs6P8VUKtH0-L5QdzrmSDw8sTKyBMG3tNaY,7519
148
+ agent_notes-2.0.4.dist-info/licenses/LICENSE,sha256=-zkfoVV5cCbXHNJK0qnSSSCvw7hqEIOZ-0yARp5XLrE,1064
149
+ tests/conftest.py,sha256=Ewhhi4cQc7iat4vU1xXCc7Eyuwhle9oZbmyJVKKAGPU,535
150
+ tests/functional/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
151
+ tests/functional/test_build_commands.py,sha256=SO9tJHS1vY1VYXaQrzHFzE7ddfJXWAsFXydI-vc_k4U,3051
152
+ tests/functional/test_registries.py,sha256=nc1DLBD5THTY2wvXQZoXYRNfipODPBV_vJ74_KMCKOw,3551
153
+ tests/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
154
+ tests/integration/test_build_output.py,sha256=ufl7ak-NGFiv7HCfBxPnaN61CiQVTu3-dM1U30jP8fw,3611
155
+ tests/plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
156
+ tests/plugins/test_agents.py,sha256=ITPHZWansWgVXph-ZBM3sFndtjVFfjHPf7XWVbHNTcc,3258
157
+ tests/plugins/test_skills.py,sha256=C5D2fWGsYkS26v1hQ0-g_0WpGxSlVieBZw9oHEhfk1U,2774
158
+ agent_notes-2.0.4.dist-info/METADATA,sha256=eqaiGVy84D0pAYmfy28p0oHBozFQPOZbm_vFrPgjM9c,463
159
+ agent_notes-2.0.4.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
160
+ agent_notes-2.0.4.dist-info/entry_points.txt,sha256=bIfdJBqQoatEtDipiruWiSyHudtnSr4VxUAMJaRJ878,53
161
+ agent_notes-2.0.4.dist-info/top_level.txt,sha256=owterz4f7Vvxrodr57ouqQZ3ejcA-L91LnNmkgcktbI,18
162
+ agent_notes-2.0.4.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ agent-notes = agent_notes.cli:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 rubakas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ agent_notes
2
+ tests
tests/conftest.py ADDED
@@ -0,0 +1,20 @@
1
+ """Shared test fixtures."""
2
+ import subprocess
3
+ import pytest
4
+ from pathlib import Path
5
+
6
+ from agent_notes.config import ROOT, DIST_DIR
7
+
8
+
9
+ @pytest.fixture(scope="session")
10
+ def built_dist():
11
+ """Run the build once per session; skip all dependents if it fails."""
12
+ result = subprocess.run(
13
+ ["python3", "-m", "agent_notes", "build"],
14
+ cwd=ROOT,
15
+ capture_output=True,
16
+ text=True,
17
+ )
18
+ if result.returncode != 0:
19
+ pytest.skip(f"Build failed:\n{result.stdout}\n{result.stderr}")
20
+ return DIST_DIR
File without changes
@@ -0,0 +1,88 @@
1
+ """Tests for individual build command functions in isolation."""
2
+ import importlib
3
+ import json
4
+ import pytest
5
+ from pathlib import Path
6
+ from unittest.mock import patch
7
+
8
+ # Must use importlib because agent_notes.commands exports a `build` function
9
+ # at package level, shadowing the submodule when accessed via attribute lookup.
10
+ _build_mod = importlib.import_module("agent_notes.commands.build")
11
+
12
+
13
+ def test_copy_scripts_replaces_pricing_placeholder(tmp_path):
14
+ """copy_scripts() should replace {{PRICING}} with JSON from pricing.yaml."""
15
+ scripts_src = tmp_path / "scripts"
16
+ scripts_dst = tmp_path / "dist_scripts"
17
+ scripts_src.mkdir()
18
+
19
+ # Write a script file with the placeholder
20
+ script_file = scripts_src / "cost-report"
21
+ script_file.write_text("#!/usr/bin/env python3\nPRICING = {{PRICING}}\n")
22
+
23
+ import agent_notes.config as config_mod
24
+
25
+ with patch.object(config_mod, "SCRIPTS_DIR", scripts_src), \
26
+ patch.object(config_mod, "DIST_SCRIPTS_DIR", scripts_dst):
27
+ copied = _build_mod.copy_scripts()
28
+
29
+ assert len(copied) == 1
30
+ content = copied[0].read_text()
31
+ assert "{{PRICING}}" not in content
32
+ assert '"providers"' in content
33
+
34
+
35
+ def test_copy_scripts_result_is_executable(tmp_path):
36
+ """copy_scripts() should make output files executable."""
37
+ import stat
38
+ scripts_src = tmp_path / "scripts"
39
+ scripts_dst = tmp_path / "dist_scripts"
40
+ scripts_src.mkdir()
41
+
42
+ (scripts_src / "my-script").write_text("#!/bin/sh\necho hi\n")
43
+
44
+ import agent_notes.config as config_mod
45
+
46
+ with patch.object(config_mod, "SCRIPTS_DIR", scripts_src), \
47
+ patch.object(config_mod, "DIST_SCRIPTS_DIR", scripts_dst):
48
+ copied = _build_mod.copy_scripts()
49
+
50
+ assert len(copied) == 1
51
+ mode = copied[0].stat().st_mode
52
+ assert mode & stat.S_IXUSR
53
+
54
+
55
+ def test_copy_skills_copies_all_skill_dirs(tmp_path):
56
+ """copy_skills() should copy every skill directory to dist/skills/."""
57
+ skills_src = tmp_path / "skills"
58
+ skill_a = skills_src / "alpha"
59
+ skill_b = skills_src / "beta"
60
+ skill_a.mkdir(parents=True)
61
+ skill_b.mkdir(parents=True)
62
+ (skill_a / "SKILL.md").write_text("---\nname: alpha\n---\n")
63
+ (skill_b / "SKILL.md").write_text("---\nname: beta\n---\n")
64
+
65
+ dist_dir = tmp_path / "dist"
66
+ dist_dir.mkdir()
67
+
68
+ import agent_notes.config as config_mod
69
+
70
+ def fake_find_skill_dirs():
71
+ return sorted(d for d in skills_src.iterdir() if d.is_dir() and (d / "SKILL.md").exists())
72
+
73
+ with patch.object(_build_mod, "DIST_DIR", dist_dir), \
74
+ patch.object(config_mod, "find_skill_dirs", fake_find_skill_dirs):
75
+ copied = _build_mod.copy_skills()
76
+
77
+ assert len(copied) == 2
78
+ names = {p.name for p in copied}
79
+ assert "alpha" in names
80
+ assert "beta" in names
81
+
82
+
83
+ def test_copy_global_files_returns_list_of_paths(tmp_path):
84
+ """copy_global_files() should return a list of Path objects without error."""
85
+ result = _build_mod.copy_global_files()
86
+ assert isinstance(result, list)
87
+ for item in result:
88
+ assert isinstance(item, Path)
@@ -0,0 +1,128 @@
1
+ """Tests that all 4 registries load correctly from their source files."""
2
+ import pytest
3
+
4
+ from agent_notes.registries.model_registry import load_model_registry
5
+ from agent_notes.registries.role_registry import load_role_registry
6
+ from agent_notes.registries.skill_registry import load_skill_registry
7
+ from agent_notes.registries.agent_registry import load_agent_registry
8
+
9
+
10
+ # --- Model registry ---
11
+
12
+ def test_model_registry_loads():
13
+ registry = load_model_registry()
14
+ assert len(registry.all()) >= 8
15
+
16
+
17
+ def test_model_registry_includes_opus():
18
+ registry = load_model_registry()
19
+ ids = registry.ids()
20
+ assert "claude-opus-4-7" in ids
21
+
22
+
23
+ def test_model_registry_includes_sonnet():
24
+ registry = load_model_registry()
25
+ ids = registry.ids()
26
+ assert "claude-sonnet-4-6" in ids
27
+
28
+
29
+ def test_model_registry_includes_haiku():
30
+ registry = load_model_registry()
31
+ ids = registry.ids()
32
+ assert "claude-haiku-4-5" in ids
33
+
34
+
35
+ def test_model_has_required_fields():
36
+ registry = load_model_registry()
37
+ for model in registry.all():
38
+ assert model.id, f"Model missing id"
39
+ assert model.label, f"Model {model.id} missing label"
40
+ assert model.family, f"Model {model.id} missing family"
41
+ assert model.model_class, f"Model {model.id} missing model_class"
42
+ assert model.aliases is not None, f"Model {model.id} missing aliases"
43
+
44
+
45
+ # --- Role registry ---
46
+
47
+ def test_role_registry_loads():
48
+ registry = load_role_registry()
49
+ assert len(registry.all()) >= 3
50
+
51
+
52
+ def test_role_registry_has_orchestrator():
53
+ registry = load_role_registry()
54
+ names = registry.names()
55
+ assert "orchestrator" in names
56
+
57
+
58
+ def test_role_registry_has_worker():
59
+ registry = load_role_registry()
60
+ names = registry.names()
61
+ assert "worker" in names
62
+
63
+
64
+ def test_role_registry_has_scout():
65
+ registry = load_role_registry()
66
+ names = registry.names()
67
+ assert "scout" in names
68
+
69
+
70
+ def test_role_has_required_fields():
71
+ registry = load_role_registry()
72
+ for role in registry.all():
73
+ assert role.name, f"Role missing name"
74
+ assert role.label, f"Role {role.name} missing label"
75
+
76
+
77
+ # --- Skill registry ---
78
+
79
+ def test_skill_registry_loads():
80
+ registry = load_skill_registry()
81
+ assert len(registry.all()) >= 30
82
+
83
+
84
+ def test_skill_registry_includes_git():
85
+ registry = load_skill_registry()
86
+ assert "git" in registry.names()
87
+
88
+
89
+ def test_skill_registry_includes_brainstorming():
90
+ registry = load_skill_registry()
91
+ assert "brainstorming" in registry.names()
92
+
93
+
94
+ def test_skill_has_required_fields():
95
+ registry = load_skill_registry()
96
+ for skill in registry.all():
97
+ assert skill.name, f"Skill missing name"
98
+ assert skill.description, f"Skill {skill.name} missing description"
99
+ assert skill.group, f"Skill {skill.name} missing group"
100
+
101
+
102
+ # --- Agent registry ---
103
+
104
+ def test_agent_registry_loads():
105
+ registry = load_agent_registry()
106
+ assert len(registry.all()) >= 15
107
+
108
+
109
+ def test_agent_registry_includes_coder():
110
+ registry = load_agent_registry()
111
+ assert "coder" in registry.names()
112
+
113
+
114
+ def test_agent_registry_includes_reviewer():
115
+ registry = load_agent_registry()
116
+ assert "reviewer" in registry.names()
117
+
118
+
119
+ def test_agent_registry_includes_explorer():
120
+ registry = load_agent_registry()
121
+ assert "explorer" in registry.names()
122
+
123
+
124
+ def test_agent_has_required_fields():
125
+ registry = load_agent_registry()
126
+ for agent in registry.all():
127
+ assert agent.name, f"Agent missing name (id)"
128
+ assert agent.description, f"Agent {agent.name} missing description"
File without changes