agent-notes 2.26.0__tar.gz → 2.27.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.
- {agent_notes-2.26.0 → agent_notes-2.27.0}/PKG-INFO +1 -1
- agent_notes-2.27.0/agent_notes/VERSION +1 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/doctor.py +41 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/cost_reporting.md +4 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/execution.md +1 -1
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/guardrails.md +2 -4
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/hard_limits.md +0 -1
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/code-review/SKILL.md +4 -2
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/improve-codebase-architecture/SKILL.md +1 -1
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/migrate-memory/SKILL.md +1 -1
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/refactoring-protocol/SKILL.md +1 -1
- agent_notes-2.27.0/agent_notes/data/skills/rsi/SKILL.md +60 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/registries/skill_registry.py +2 -1
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/rendering.py +2 -1
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes.egg-info/PKG-INFO +1 -1
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes.egg-info/SOURCES.txt +1 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/commands/test_doctor_command.py +162 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/plugins/test_skills.py +15 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/registries/test_registries.py +30 -0
- agent_notes-2.27.0/tests/unit/services/test_rendering_includes.py +212 -0
- agent_notes-2.26.0/agent_notes/VERSION +0 -1
- agent_notes-2.26.0/tests/unit/services/test_rendering_includes.py +0 -88
- {agent_notes-2.26.0 → agent_notes-2.27.0}/LICENSE +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/README.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/__main__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/cli.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/_install_helpers.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/build.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/config.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/hook.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/info.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/install.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/list.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/memory/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/memory/_common.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/memory/migrate.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/memory/notes.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/memory/reset.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/memory/transfer.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/memory/vault.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/memory/wiki.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/regenerate.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/set_role.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/uninstall.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/validate.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/_common.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/cost_report.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/execute.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/commands/wizard/orchestrator.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/config.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/constants.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/agents.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/analyst.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/api-reviewer.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/architect.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/coder.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/database-specialist.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/debugger.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/devil.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/devops.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/explorer.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/integrations.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/lead.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/performance-profiler.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/refactorer.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/reviewer.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/security-auditor.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/phase0.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/pipelines.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/review.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/verification.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/shared/wiki_compile.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/system-auditor.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/tech-writer.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/test-runner.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/test-writer.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/agents/wiki-compiler.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/cli/claude.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/cli/copilot.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/cli/opencode.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/commands/brainstorm.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/commands/debug.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/commands/review.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/global-claude.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/global-copilot.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/global-opencode.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/hooks/session-context.md.tpl +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-haiku-4-5.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-1.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-5.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-6.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-7.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-opus-4-8.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-sonnet-4-5.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-sonnet-4-6.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/models/claude-sonnet-4.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/plugin/claude.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/plugin/opencode-index.js.template +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/plugin/opencode.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/pricing.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/roles/orchestrator.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/roles/reasoner.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/roles/scout.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/roles/worker.yaml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/rules/code-quality.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/rules/safety.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/brainstorming/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/caveman/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/debugging-protocol/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/docker/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/docker/compose.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/docker/dockerfile.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/git/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/grill-me/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/grill-with-docs/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/handoff/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/ingest/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/obsidian-memory/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/prototype/LOGIC.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/prototype/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/prototype/UI.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/controllers.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/frontend.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/infra.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/models.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/testing.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/rails/views.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/setup-project-context/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/tdd/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/to-issues/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/to-prd/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/write-a-skill/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/zoom-out/SKILL.md +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/templates/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/templates/__pycache__/__init__.cpython-314.pyc +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/__pycache__/__init__.cpython-314.pyc +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/__pycache__/claude.cpython-314.pyc +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/__pycache__/opencode.cpython-314.pyc +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/claude.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/templates/frontmatter/opencode.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/doctor_checks.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/domain/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/domain/agent.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/domain/cli_backend.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/domain/diagnostics.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/domain/diff.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/domain/model.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/domain/role.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/domain/rule.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/domain/skill.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/domain/state.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/registries/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/registries/_base.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/registries/agent_registry.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/registries/cli_registry.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/registries/model_registry.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/registries/role_registry.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/registries/rule_registry.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/scripts/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/scripts/_claude_backend.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/scripts/_formatting.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/scripts/_opencode_backend.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/scripts/_pricing.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/scripts/cost_report.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/_memory_utils.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/counts.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/credentials.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/diagnostics/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/diagnostics/_checks.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/diagnostics/_display.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/diagnostics/_fix.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/diff.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/fs.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/install_state_builder.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/installer.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/local_backend.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/memory_router.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/migrations/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/obsidian_backend.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/session_context.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/settings_writer.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/state_store.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/ui.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/user_config.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/validation.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/wiki/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/wiki/_wiki_utils.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_index.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_ingest.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_lint.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_query.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/wiki/wiki_storage.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/services/wiki_backend.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes.egg-info/dependency_links.txt +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes.egg-info/entry_points.txt +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes.egg-info/requires.txt +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes.egg-info/top_level.txt +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/pyproject.toml +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/setup.cfg +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/conftest.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/commands/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/commands/test_config_command.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/commands/test_info_command.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/commands/test_install_command.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/commands/test_list_command.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/commands/test_regenerate_command.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/commands/test_uninstall_command.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/commands/test_validate_command.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/memory/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/memory/test_memory_add_local_backend.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/memory/test_memory_command.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/scripts/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/functional/scripts/test_release_script.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/integration/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/integration/build_output/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/integration/build_output/test_build_output.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/integration/install/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/integration/install/test_install_methods.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/integration/plugin_builders/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/integration/plugin_builders/test_plugin_builders.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/plugins/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/plugins/claude/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/plugins/claude/test_agents.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/commands/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/commands/test_cost_report_subcommand.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/commands/test_count_agents.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/commands/test_info.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/commands/test_memory_add_description.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/commands/test_memory_imports.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/commands/test_memory_migrate.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/commands/test_wizard_imports.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/commands/test_wizard_orchestrator_skip.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/commands/test_wizard_preflight.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/commands/test_wizard_steps.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/commands/wizard/test_cost_report_step.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/registries/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/scripts/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/scripts/test_cost_report.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/scripts/test_cost_report_scoping.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/scripts/test_formatting_tty.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/scripts/test_opencode_backend_pricing.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/scripts/test_time_aggregation.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/__init__.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_build_functions.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_credential_filter.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_credentials.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_fs.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_installer_hooks.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_installer_plan.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_local_backend.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_memory_backend.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_memory_backend_io.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_memory_router.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_session_context.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_settings_writer.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_skill_filtering.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_state_store.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_user_config_cost_report.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_validation.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_wiki_backend.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/services/test_wiki_imports.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/test_import_health.py +0 -0
- {agent_notes-2.26.0 → agent_notes-2.27.0}/tests/unit/test_memory_dir_for_backend.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.27.0
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
|
|
5
|
+
from ..registries.skill_registry import load_skill_registry
|
|
6
|
+
|
|
5
7
|
# Re-export for backward compatibility. New code should import from agent_notes.domain.
|
|
6
8
|
from ..domain.diagnostics import Issue, FixAction # noqa: F401
|
|
7
9
|
|
|
@@ -42,6 +44,42 @@ from ..services.fs import (
|
|
|
42
44
|
files_differ
|
|
43
45
|
)
|
|
44
46
|
|
|
47
|
+
# Canonical group vocabulary for skill frontmatter.
|
|
48
|
+
# "process" and "domain" come from the base skills in data/skills/.
|
|
49
|
+
# "rails", "docker", and "kamal" come from the sub-skills that are generated
|
|
50
|
+
# during the release/packaging step and land in data/skills/ of the built
|
|
51
|
+
# package (e.g. rails-models → group: rails, rails-kamal → group: kamal,
|
|
52
|
+
# docker-compose → group: docker). There is no single source-of-truth
|
|
53
|
+
# constant elsewhere in the codebase, so the full vocabulary is listed here.
|
|
54
|
+
_VALID_GROUPS = {"process", "domain", "rails", "docker", "kamal"}
|
|
55
|
+
_VALID_MEMORY_BACKENDS = {"obsidian", "wiki", "local", "none"}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def check_skill_frontmatter(scope: str, issues: list, fix_actions: list, profile_label: str = "") -> None:
|
|
59
|
+
"""Warn (non-fatal) about skill frontmatter violations.
|
|
60
|
+
|
|
61
|
+
Checks every skill for:
|
|
62
|
+
- non-empty name and description
|
|
63
|
+
- group, if present, is in {"process", "domain"}
|
|
64
|
+
- requires_memory tokens, if present, are each in {"obsidian", "wiki", "local", "none"}
|
|
65
|
+
|
|
66
|
+
Violations are printed as advisories and do NOT affect issues/fix_actions or exit code.
|
|
67
|
+
"""
|
|
68
|
+
registry = load_skill_registry()
|
|
69
|
+
for skill in registry.all():
|
|
70
|
+
if not skill.name:
|
|
71
|
+
print(f" [skill-frontmatter] {skill.path.name}: 'name' is empty")
|
|
72
|
+
if not skill.description:
|
|
73
|
+
print(f" [skill-frontmatter] {skill.path.name}: 'description' is empty")
|
|
74
|
+
if skill.group and skill.group not in _VALID_GROUPS:
|
|
75
|
+
print(f" [skill-frontmatter] {skill.name}: 'group' value '{skill.group}' is not in {sorted(_VALID_GROUPS)}")
|
|
76
|
+
if skill.requires_memory:
|
|
77
|
+
for token in skill.requires_memory.split(","):
|
|
78
|
+
token = token.strip()
|
|
79
|
+
if token and token not in _VALID_MEMORY_BACKENDS:
|
|
80
|
+
print(f" [skill-frontmatter] {skill.name}: 'requires_memory' token '{token}' is not in {sorted(_VALID_MEMORY_BACKENDS)}")
|
|
81
|
+
|
|
82
|
+
|
|
45
83
|
def _check_session_hook(scope: str, issues: list) -> None:
|
|
46
84
|
"""Check that the Claude Code SessionStart hook is registered in settings.json."""
|
|
47
85
|
from ..services.settings_writer import has_hook
|
|
@@ -162,6 +200,9 @@ def diagnose(scope: str, fix: bool = False) -> bool:
|
|
|
162
200
|
# SessionStart hook check (Claude Code only)
|
|
163
201
|
_check_session_hook(scope, issues)
|
|
164
202
|
|
|
203
|
+
# Skill frontmatter advisory check (warn-only, non-fatal)
|
|
204
|
+
check_skill_frontmatter(scope, issues, fix_actions)
|
|
205
|
+
|
|
165
206
|
# Print role→model assignments
|
|
166
207
|
state = load_current_state()
|
|
167
208
|
if state is not None:
|
|
@@ -11,3 +11,7 @@ Render every column the `agent-notes cost-report` CLI emits — `agent(model)`,
|
|
|
11
11
|
`Cost report skipped: <one-line reason>`
|
|
12
12
|
|
|
13
13
|
If the command ran but produced an error message, print the error verbatim under the heading instead of a table. Fabricating a table when the CLI did not run is a violation.
|
|
14
|
+
|
|
15
|
+
Cost table: once at end of response, never mid-response.
|
|
16
|
+
|
|
17
|
+
Always include the cost report at the end of every response.
|
|
@@ -86,7 +86,7 @@ Never spawn one agent per bullet point from the user's prompt. Combine related s
|
|
|
86
86
|
|
|
87
87
|
Skip agents for: simple questions (answer directly), single-file edits (coder alone), or two-grep lookups (do it yourself).
|
|
88
88
|
|
|
89
|
-
Give each agent a specific task with all context (paths, criteria).
|
|
89
|
+
Give each agent a specific task with all context (paths, criteria).
|
|
90
90
|
|
|
91
91
|
### Permission pre-check (HARD RULE)
|
|
92
92
|
|
|
@@ -9,10 +9,8 @@
|
|
|
9
9
|
7. "Let me just verify this one thing" followed by 10 reads → if verification needs 10 reads, dispatch.
|
|
10
10
|
8. Breaking tasks into steps so small they have no independent value → group into meaningful chunks.
|
|
11
11
|
9. Writing a plan that only restates the user's words → a plan must include discovery findings, dependency order, and flagged risks.
|
|
12
|
-
10.
|
|
13
|
-
11.
|
|
14
|
-
12. Reporting "done" before tests pass and plan items match → forbidden by Done Gate.
|
|
15
|
-
13. Reporting "done" / "complete" / "shipped" without an `agent-notes memory add ... session lead` call covering this work → forbidden by the Done Gate.
|
|
12
|
+
10. Reporting "done" before tests pass and plan items match → forbidden by Done Gate.
|
|
13
|
+
11. Reporting "done" / "complete" / "shipped" without an `agent-notes memory add ... session lead` call covering this work → forbidden by the Done Gate.
|
|
16
14
|
|
|
17
15
|
## Done Gate (HARD RULE)
|
|
18
16
|
|
|
@@ -25,4 +25,3 @@ Exception: trivial requests (factual questions, conversational replies, single-l
|
|
|
25
25
|
- Plans: structured bullet lists with file paths. No prose paragraphs.
|
|
26
26
|
- Agent briefings: context + task + acceptance criteria. No commentary or justification.
|
|
27
27
|
- Never narrate internal deliberation — report outcomes only.
|
|
28
|
-
- Cost table: once at end of response, never mid-response.
|
|
@@ -47,14 +47,16 @@ Work through these five lenses in order. Report findings grouped by lens, ranked
|
|
|
47
47
|
|
|
48
48
|
## Output format
|
|
49
49
|
|
|
50
|
+
Emit each finding as a record: `severity` (blocking | suggestion) · `file` · `line` · `finding` · `why` · `fix` (if applicable). When the output is consumed by another agent, emit JSON objects with exactly those keys. For a human summary, group by severity:
|
|
51
|
+
|
|
50
52
|
```
|
|
51
53
|
BLOCKING
|
|
52
|
-
- [file:line] [finding] — [why it matters]
|
|
54
|
+
- [file:line] [finding] — [why it matters] → [fix]
|
|
53
55
|
|
|
54
56
|
SUGGESTIONS
|
|
55
57
|
- [file:line] [finding] — [alternative if applicable]
|
|
56
58
|
|
|
57
|
-
APPROVED (
|
|
59
|
+
APPROVED (state explicitly when there are no blocking findings)
|
|
58
60
|
```
|
|
59
61
|
|
|
60
62
|
A BLOCKING finding must be resolved before merge. A SUGGESTION is optional.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: improve-codebase-architecture
|
|
3
|
-
description: "Find deepening opportunities — modules where the interface is nearly as complex as the implementation. Use when user wants to improve architecture, reduce coupling, make code more testable, or says 'clean up the design'."
|
|
3
|
+
description: "Find deepening opportunities — modules where the interface is nearly as complex as the implementation. Use when user wants to improve architecture, reduce coupling, make code more testable, or says 'clean up the design'. For broad code-quality hardening use rsi; for a single safe refactor use refactoring-protocol."
|
|
4
4
|
group: process
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: migrate-memory
|
|
3
3
|
description: "Reconcile the Obsidian vault or Wiki knowledge base to the latest canonical format. Use after upgrading agent-notes or when vault structure looks outdated or inconsistent."
|
|
4
4
|
group: process
|
|
5
|
-
requires_memory: obsidian,
|
|
5
|
+
requires_memory: obsidian,wiki
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Migrate Memory
|
{agent_notes-2.26.0 → agent_notes-2.27.0}/agent_notes/data/skills/refactoring-protocol/SKILL.md
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: refactoring-protocol
|
|
3
|
-
description: "Safe refactoring: green tests first, one extraction at a time, structure OR behavior never both. Use when user wants to refactor code, reduce duplication, or says 'clean this up'."
|
|
3
|
+
description: "Safe refactoring: green tests first, one extraction at a time, structure OR behavior never both. Use when user wants to refactor code, reduce duplication, or says 'clean this up'. For an iterative multi-dimensional cleanup loop use rsi; for module or interface redesign use improve-codebase-architecture."
|
|
4
4
|
group: process
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rsi
|
|
3
|
+
description: "Recursive code-improvement loop: iteratively harden an existing codebase across bugs, performance, quality, consistency/homogeneity, pattern adherence, tests, atomicity, independence, and DRY — strictly without adding functionality. Use when the user wants to improve, clean up, or harden existing code, says 'rsi', or asks to raise code quality without new features. For a single one-shot refactor use refactoring-protocol; for module or interface redesign use improve-codebase-architecture."
|
|
4
|
+
group: process
|
|
5
|
+
argument-hint: "[path or scope, optional]"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# RSI — Recursive Self-Improvement (Code)
|
|
9
|
+
|
|
10
|
+
Iteratively improve EXISTING code until it stops yielding improvements. The lead orchestrates; specialized agents do the work. This is a quality loop, not a feature loop.
|
|
11
|
+
|
|
12
|
+
## Prime invariant
|
|
13
|
+
|
|
14
|
+
- **Behavior-preserving.** NEVER add functionality, new features, new public API, or new config. Only improve what already exists.
|
|
15
|
+
- **Tests green before a pass and after every change.** If the target has no test coverage, write a characterization test FIRST, then improve.
|
|
16
|
+
- **One change = one concern.** Structure OR behavior, never both in the same change.
|
|
17
|
+
|
|
18
|
+
## The loop (lead-orchestrated, loop-until-dry)
|
|
19
|
+
|
|
20
|
+
1. **Scope.** Resolve the target (arg path, or whole project). Identify the test command and confirm the suite is green. If it is red, stop and report — fix the suite before improving.
|
|
21
|
+
2. **Scan — one dimension at a time.** Dispatch read-only agents to produce a ranked list of concrete opportunities:
|
|
22
|
+
- `debugger` / `security-auditor` → bugs, correctness, vulnerabilities
|
|
23
|
+
- `performance-profiler` → hot paths, N+1, redundant work
|
|
24
|
+
- `system-auditor` → duplication, dead code, coupling, inconsistent implementations of one concept
|
|
25
|
+
- `reviewer` → readability, naming, pattern & consistency adherence
|
|
26
|
+
- `test-writer` (read-only pass) → coverage gaps
|
|
27
|
+
|
|
28
|
+
Each opportunity is a **finding record**: `file` · `line` · `dimension` · `severity` (blocker | major | minor) · `why` · `fix` (one-line proposed change). When a downstream agent consumes the scan, emit findings as JSON objects with exactly those keys; otherwise the dashed form `file:line — dimension/severity — why — fix` is fine.
|
|
29
|
+
|
|
30
|
+
3. **Prioritize.** Order: correctness/safety > missing tests on touched code > DRY/duplication > consistency/homogeneity > pattern & convention fit > performance > clarity/naming. Drop anything that changes behavior or adds capability.
|
|
31
|
+
4. **Apply ONE atomic, independent change.** Dispatch `coder` (bugfix) or `refactorer` (behavior-preserving cleanup). Smallest viable diff.
|
|
32
|
+
5. **Verify.** Run affected tests — must stay green. `reviewer` confirms: no behavior change, fits conventions, genuinely improves the dimension. On regression → revert and re-plan.
|
|
33
|
+
6. **Commit (auto, atomic).** One concern per commit, independent and revertable. Use the `git` skill's message format. Then take the next opportunity.
|
|
34
|
+
7. **Repeat passes.** Converge when TWO consecutive full passes surface no new actionable improvement. Then report.
|
|
35
|
+
|
|
36
|
+
## Dimensions rubric
|
|
37
|
+
|
|
38
|
+
Each dimension: what to **hunt**, what to **fix**, what to **leave alone**.
|
|
39
|
+
|
|
40
|
+
- **Bugs & correctness** — off-by-one, nil/None, races, missing error handling, unhandled edge cases. Fix minimally + add a regression test. Don't redesign.
|
|
41
|
+
- **Performance** — measured hot paths, N+1 queries, redundant work, bad complexity, unbounded growth. Don't micro-optimize cold paths or trade clarity for guesswork.
|
|
42
|
+
- **Code quality** — long methods, deep nesting, unclear names, magic values. Extract, apply guard clauses, rename. Don't gold-plate.
|
|
43
|
+
- **Consistency / homogeneity** — the same kind of thing implemented multiple different ways: mixed styles for one object type, divergent shapes for one concept, inconsistent signatures or return types. Converge on one canonical form and reduce needless variation. Distinct from DRY — this targets divergent *expression* of one concept, not duplicated *logic*. Don't force genuinely different things into a false-common shape.
|
|
44
|
+
- **Pattern adherence** — match the project's dominant idioms, structure, and conventions. Align outliers. Don't invent new patterns.
|
|
45
|
+
- **Tests** — cover changed or risky code, fix flaky/slow tests, add missing edge cases. Don't test trivial getters.
|
|
46
|
+
- **Atomicity** — split god-functions and god-classes into single-responsibility units. Don't over-fragment.
|
|
47
|
+
- **Independence** — reduce coupling, remove hidden global state, narrow interfaces. Don't add abstraction layers nobody needs.
|
|
48
|
+
- **DRY** — collapse genuine duplication into one source of truth. Don't DRY accidental similarity (premature abstraction is worse than duplication).
|
|
49
|
+
- **Dead code** — unused functions, variables, imports, branches. Delete after confirming no external use.
|
|
50
|
+
|
|
51
|
+
## Gates (hard)
|
|
52
|
+
|
|
53
|
+
- **Green-before / green-after.** A red suite halts the loop.
|
|
54
|
+
- **No-feature gate.** If a change adds capability, it is out of scope — reject it.
|
|
55
|
+
- **Atomic & independent commits.** Revert on regression with `git revert` — never `reset --hard` or force-push.
|
|
56
|
+
- **Max 2 review rounds per change,** then accept or drop it.
|
|
57
|
+
|
|
58
|
+
## Done
|
|
59
|
+
|
|
60
|
+
Report: improvements grouped by dimension, commits made, tests added, deferrals (with reasons), and anything skipped as out-of-scope (new functionality).
|
|
@@ -86,7 +86,8 @@ def _parse_skill_frontmatter(skill_md_path: Path) -> tuple[str, Optional[str], O
|
|
|
86
86
|
elif key == 'description':
|
|
87
87
|
description = value
|
|
88
88
|
elif key == 'requires_memory':
|
|
89
|
-
|
|
89
|
+
tokens = [t.strip() for t in value.split(",")]
|
|
90
|
+
requires_memory = ",".join(t for t in tokens if t)
|
|
90
91
|
|
|
91
92
|
# If no description in frontmatter, use first non-empty line after frontmatter
|
|
92
93
|
if not description:
|
|
@@ -139,7 +139,8 @@ def generate_agent_files(agents_config: Dict[str, Any], tiers: Dict[str, Any],
|
|
|
139
139
|
|
|
140
140
|
# Expand shared-content include directives (<!-- include: NAME -->)
|
|
141
141
|
# No-op if shared/ directory is absent.
|
|
142
|
-
|
|
142
|
+
_agent_include_skip = set() if user_config.get("cost_report_enabled", False) else {"cost_reporting"}
|
|
143
|
+
prompt_content = expand_includes(prompt_content, AGENTS_DIR / "shared", skip=_agent_include_skip)
|
|
143
144
|
|
|
144
145
|
# Substitute {{MEMORY_PATH}} with the configured vault/memory path.
|
|
145
146
|
_st = _load_state_fn()
|
|
@@ -125,6 +125,7 @@ agent_notes/data/skills/rails/models.md
|
|
|
125
125
|
agent_notes/data/skills/rails/testing.md
|
|
126
126
|
agent_notes/data/skills/rails/views.md
|
|
127
127
|
agent_notes/data/skills/refactoring-protocol/SKILL.md
|
|
128
|
+
agent_notes/data/skills/rsi/SKILL.md
|
|
128
129
|
agent_notes/data/skills/setup-project-context/SKILL.md
|
|
129
130
|
agent_notes/data/skills/tdd/SKILL.md
|
|
130
131
|
agent_notes/data/skills/to-issues/SKILL.md
|
|
@@ -392,6 +392,168 @@ class TestInstalledVersionSerializationRoundTrip:
|
|
|
392
392
|
assert loaded.global_install.installed_version == ""
|
|
393
393
|
|
|
394
394
|
|
|
395
|
+
class TestCheckSkillFrontmatter:
|
|
396
|
+
"""Tests for the warn-only check_skill_frontmatter check."""
|
|
397
|
+
|
|
398
|
+
def _make_skill(self, tmp_path, name, frontmatter_extra=""):
|
|
399
|
+
skill_dir = tmp_path / name
|
|
400
|
+
skill_dir.mkdir()
|
|
401
|
+
fm = f"---\nname: {name}\ndescription: \"A test skill.\"\ngroup: process\n{frontmatter_extra}---\n\n# {name}\n"
|
|
402
|
+
(skill_dir / "SKILL.md").write_text(fm)
|
|
403
|
+
return tmp_path
|
|
404
|
+
|
|
405
|
+
def test_no_warning_with_valid_skills(self, tmp_path, capsys, monkeypatch):
|
|
406
|
+
"""No warnings printed when all skill frontmatter is valid."""
|
|
407
|
+
skills_dir = self._make_skill(tmp_path, "my-skill")
|
|
408
|
+
|
|
409
|
+
from agent_notes.registries.skill_registry import load_skill_registry, SkillRegistry
|
|
410
|
+
monkeypatch.setattr(
|
|
411
|
+
"agent_notes.commands.doctor.load_skill_registry",
|
|
412
|
+
lambda: load_skill_registry(skills_dir=skills_dir),
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
from agent_notes.commands.doctor import check_skill_frontmatter
|
|
416
|
+
issues: list = []
|
|
417
|
+
fix_actions: list = []
|
|
418
|
+
check_skill_frontmatter("global", issues, fix_actions)
|
|
419
|
+
|
|
420
|
+
out = capsys.readouterr().out
|
|
421
|
+
assert "[skill-frontmatter]" not in out
|
|
422
|
+
assert issues == [], "check_skill_frontmatter must not append to issues"
|
|
423
|
+
assert fix_actions == [], "check_skill_frontmatter must not append to fix_actions"
|
|
424
|
+
|
|
425
|
+
def test_warning_on_invalid_group(self, tmp_path, capsys, monkeypatch):
|
|
426
|
+
"""Prints a warning for an invalid group value; does not add to issues."""
|
|
427
|
+
skills_dir = self._make_skill(tmp_path, "bad-group-skill", "group: invalid-group\n")
|
|
428
|
+
# Overwrite the pre-written group: process with invalid-group
|
|
429
|
+
skill_md = skills_dir / "bad-group-skill" / "SKILL.md"
|
|
430
|
+
text = skill_md.read_text().replace("group: process\n", "")
|
|
431
|
+
skill_md.write_text(text)
|
|
432
|
+
# Write skill with invalid group
|
|
433
|
+
skill_md.write_text(
|
|
434
|
+
"---\nname: bad-group-skill\ndescription: \"A test skill.\"\ngroup: invalid-group\n---\n\n# bad-group-skill\n"
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
from agent_notes.registries.skill_registry import load_skill_registry
|
|
438
|
+
monkeypatch.setattr(
|
|
439
|
+
"agent_notes.commands.doctor.load_skill_registry",
|
|
440
|
+
lambda: load_skill_registry(skills_dir=skills_dir),
|
|
441
|
+
)
|
|
442
|
+
|
|
443
|
+
from agent_notes.commands.doctor import check_skill_frontmatter
|
|
444
|
+
issues: list = []
|
|
445
|
+
fix_actions: list = []
|
|
446
|
+
check_skill_frontmatter("global", issues, fix_actions)
|
|
447
|
+
|
|
448
|
+
out = capsys.readouterr().out
|
|
449
|
+
assert "[skill-frontmatter]" in out
|
|
450
|
+
assert "invalid-group" in out
|
|
451
|
+
assert issues == [], "invalid group must NOT add a fatal Issue"
|
|
452
|
+
assert fix_actions == [], "invalid group must NOT add a FixAction"
|
|
453
|
+
|
|
454
|
+
def test_warning_on_invalid_requires_memory_token(self, tmp_path, capsys, monkeypatch):
|
|
455
|
+
"""Prints a warning for an invalid requires_memory token; does not add to issues."""
|
|
456
|
+
skill_dir = tmp_path / "bad-memory-skill"
|
|
457
|
+
skill_dir.mkdir()
|
|
458
|
+
(skill_dir / "SKILL.md").write_text(
|
|
459
|
+
"---\nname: bad-memory-skill\ndescription: \"A test skill.\"\ngroup: process\nrequires_memory: obsidian,notabackend\n---\n\n# bad-memory-skill\n"
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
from agent_notes.registries.skill_registry import load_skill_registry
|
|
463
|
+
monkeypatch.setattr(
|
|
464
|
+
"agent_notes.commands.doctor.load_skill_registry",
|
|
465
|
+
lambda: load_skill_registry(skills_dir=tmp_path),
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
from agent_notes.commands.doctor import check_skill_frontmatter
|
|
469
|
+
issues: list = []
|
|
470
|
+
fix_actions: list = []
|
|
471
|
+
check_skill_frontmatter("global", issues, fix_actions)
|
|
472
|
+
|
|
473
|
+
out = capsys.readouterr().out
|
|
474
|
+
assert "[skill-frontmatter]" in out
|
|
475
|
+
assert "notabackend" in out
|
|
476
|
+
assert issues == [], "invalid requires_memory token must NOT add a fatal Issue"
|
|
477
|
+
assert fix_actions == [], "invalid requires_memory token must NOT add a FixAction"
|
|
478
|
+
|
|
479
|
+
def test_doctor_exit_code_unaffected_by_skill_warning(self, tmp_path, monkeypatch, capsys):
|
|
480
|
+
"""doctor's return value (exit code) is unchanged by skill frontmatter warnings."""
|
|
481
|
+
_patch_state(tmp_path, monkeypatch)
|
|
482
|
+
|
|
483
|
+
skill_dir = tmp_path / "skills" / "bad-skill"
|
|
484
|
+
skill_dir.mkdir(parents=True)
|
|
485
|
+
(skill_dir / "SKILL.md").write_text(
|
|
486
|
+
"---\nname: bad-skill\ndescription: \"A test skill.\"\ngroup: bogus\n---\n\n# bad-skill\n"
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
from agent_notes.registries.skill_registry import load_skill_registry
|
|
490
|
+
monkeypatch.setattr(
|
|
491
|
+
"agent_notes.commands.doctor.load_skill_registry",
|
|
492
|
+
lambda: load_skill_registry(skills_dir=tmp_path / "skills"),
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
with patch("agent_notes.commands.doctor.check_stale_files", _no_op_checks), \
|
|
496
|
+
patch("agent_notes.commands.doctor.check_broken_symlinks", _no_op_checks), \
|
|
497
|
+
patch("agent_notes.commands.doctor.check_shadowed_files", _no_op_checks), \
|
|
498
|
+
patch("agent_notes.commands.doctor.check_missing_files", _no_op_checks), \
|
|
499
|
+
patch("agent_notes.commands.doctor.check_content_drift", _no_op_checks), \
|
|
500
|
+
patch("agent_notes.commands.doctor.check_build_freshness", _no_op_checks), \
|
|
501
|
+
patch("agent_notes.commands.doctor._check_session_hook", _no_op_checks), \
|
|
502
|
+
patch("agent_notes.commands.doctor.print_summary"), \
|
|
503
|
+
patch("agent_notes.commands.doctor._check_role_models"), \
|
|
504
|
+
patch("agent_notes.commands.doctor.print_issues", return_value=True):
|
|
505
|
+
from agent_notes.commands.doctor import doctor
|
|
506
|
+
result = doctor(local=False, fix=False)
|
|
507
|
+
|
|
508
|
+
assert result is True, "skill frontmatter warning must not change doctor's exit result"
|
|
509
|
+
out = capsys.readouterr().out
|
|
510
|
+
assert "[skill-frontmatter]" in out
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
class TestCheckSkillFrontmatterNoFalsePositivesOnRealSkills:
|
|
514
|
+
"""Regression: check_skill_frontmatter must not warn for any skill that ships with the package.
|
|
515
|
+
|
|
516
|
+
This guards against _VALID_GROUPS being too narrow and producing false-positive
|
|
517
|
+
warnings for legitimately-grouped skills (e.g. rails-*, docker-*, kamal skills).
|
|
518
|
+
Each parametrized case loads exactly one real skill in isolation so a future
|
|
519
|
+
regression is pinpointed to the offending skill name.
|
|
520
|
+
"""
|
|
521
|
+
|
|
522
|
+
@staticmethod
|
|
523
|
+
def _real_skill_names():
|
|
524
|
+
"""Return (name, skills_dir) pairs for every skill in the real skill registry."""
|
|
525
|
+
from agent_notes.config import SKILLS_DIR
|
|
526
|
+
from agent_notes.registries.skill_registry import load_skill_registry
|
|
527
|
+
registry = load_skill_registry(skills_dir=SKILLS_DIR)
|
|
528
|
+
return [(s.name, SKILLS_DIR) for s in registry.all()]
|
|
529
|
+
|
|
530
|
+
@pytest.mark.parametrize("skill_name,skills_dir", _real_skill_names.__func__())
|
|
531
|
+
def test_no_warning_for_shipped_skill(self, skill_name, skills_dir, tmp_path, capsys, monkeypatch):
|
|
532
|
+
"""check_skill_frontmatter emits no [skill-frontmatter] warning for a real shipped skill."""
|
|
533
|
+
# Build a skills_dir containing only this one skill so other skills
|
|
534
|
+
# cannot mask or muffle the warning under test.
|
|
535
|
+
src_dir = skills_dir / skill_name
|
|
536
|
+
import shutil
|
|
537
|
+
isolated = tmp_path / "skills"
|
|
538
|
+
isolated.mkdir()
|
|
539
|
+
shutil.copytree(src_dir, isolated / skill_name)
|
|
540
|
+
|
|
541
|
+
from agent_notes.registries.skill_registry import load_skill_registry
|
|
542
|
+
monkeypatch.setattr(
|
|
543
|
+
"agent_notes.commands.doctor.load_skill_registry",
|
|
544
|
+
lambda: load_skill_registry(skills_dir=isolated),
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
from agent_notes.commands.doctor import check_skill_frontmatter
|
|
548
|
+
check_skill_frontmatter("global", [], [])
|
|
549
|
+
|
|
550
|
+
out = capsys.readouterr().out
|
|
551
|
+
assert "[skill-frontmatter]" not in out, (
|
|
552
|
+
f"check_skill_frontmatter produced a false-positive warning for "
|
|
553
|
+
f"real shipped skill '{skill_name}':\n{out}"
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
|
|
395
557
|
class TestUpdateCommandRemoved:
|
|
396
558
|
def test_update_command_module_does_not_exist(self):
|
|
397
559
|
"""The `update` command should have been removed from the commands package."""
|
|
@@ -92,3 +92,18 @@ def test_skill_requires_memory_has_valid_backends(skill_dir):
|
|
|
92
92
|
assert not invalid, (
|
|
93
93
|
f"{skill_dir.name}/SKILL.md has invalid requires_memory backends: {invalid}"
|
|
94
94
|
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@pytest.mark.parametrize("skill_dir", SKILL_DIRS, ids=[d.name for d in SKILL_DIRS])
|
|
98
|
+
def test_skill_requires_memory_canonical_format(skill_dir):
|
|
99
|
+
"""If requires_memory is set, it must use canonical format: comma-separated with no spaces after commas."""
|
|
100
|
+
text = (skill_dir / "SKILL.md").read_text()
|
|
101
|
+
fm = _parse_frontmatter(text)
|
|
102
|
+
requires = fm.get("requires_memory", "")
|
|
103
|
+
if requires:
|
|
104
|
+
tokens = requires.split(",")
|
|
105
|
+
for token in tokens:
|
|
106
|
+
assert token == token.strip(), (
|
|
107
|
+
f"{skill_dir.name}/SKILL.md: requires_memory token '{token}' has leading/trailing whitespace; "
|
|
108
|
+
f"use canonical form 'token1,token2' (no spaces after comma)"
|
|
109
|
+
)
|
|
@@ -108,6 +108,36 @@ def test_ingest_skill_has_requires_memory():
|
|
|
108
108
|
assert "wiki" in backends, "ingest skill requires_memory should include wiki"
|
|
109
109
|
|
|
110
110
|
|
|
111
|
+
def test_requires_memory_normalized_no_spaces():
|
|
112
|
+
"""requires_memory with spaces after commas is normalized to canonical form (no spaces)."""
|
|
113
|
+
from pathlib import Path
|
|
114
|
+
import tempfile, textwrap
|
|
115
|
+
|
|
116
|
+
skill_md_content = textwrap.dedent("""\
|
|
117
|
+
---
|
|
118
|
+
name: test-skill
|
|
119
|
+
description: "A test skill."
|
|
120
|
+
group: process
|
|
121
|
+
requires_memory: obsidian, wiki
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
# Test Skill
|
|
125
|
+
""")
|
|
126
|
+
|
|
127
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
128
|
+
skill_dir = Path(tmpdir) / "test-skill"
|
|
129
|
+
skill_dir.mkdir()
|
|
130
|
+
skill_md = skill_dir / "SKILL.md"
|
|
131
|
+
skill_md.write_text(skill_md_content)
|
|
132
|
+
|
|
133
|
+
registry = load_skill_registry(skills_dir=Path(tmpdir))
|
|
134
|
+
skill = registry.get("test-skill")
|
|
135
|
+
|
|
136
|
+
assert skill.requires_memory == "obsidian,wiki", (
|
|
137
|
+
f"expected 'obsidian,wiki' but got '{skill.requires_memory}'"
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
111
141
|
# --- Agent registry ---
|
|
112
142
|
|
|
113
143
|
def test_agent_registry_loads():
|