Refactor/yaml target manifests#9
Merged
Merged
Conversation
Lay the foundation for moving per-target conventions out of hardcoded Python constants and into declarative YAML manifests. Nothing is wired into the deployer or MCP encoder yet — this commit only adds the new modules alongside the existing code. - target_schema.py: TargetDef / ResourceLayout / McpSpec / TransportSpec dataclasses plus a strict YAML parser. Every per-tool MCP quirk (opencode command-as-array + "environment" rename, copilot explicit "type": "stdio", gemini "httpUrl", codex "http_headers", opt-in type field) is expressible declaratively. - registry.py: loads built-in manifests via importlib.resources so they ship in the wheel. - builtin_targets/*.yml: claude, opencode, codex, cursor, copilot, gemini, windsurf, antigravity. Bug fixes baked in vs the current hardcoded table — codex skills under .codex/, codex agents added, cursor agents removed (fictional), cursor commands added, gemini MCP drops type field and uses httpUrl for HTTP, antigravity gets its own .agents/ + .agent/ namespace, windsurf commands map to workflows. - Wheel build verified to include all eight YAMLs.
Replace the hardcoded per-target constants (SKILL_DIRS, COMMAND_DIRS, AGENT_DIRS, MCP_TARGETS) and the per-target if-branches in the MCP encoder with declarative behavior driven by the YAML target manifests introduced in the previous commit. - mcp.py: single generic encoder reads TransportSpec for type_value, command_format (string vs array), and renamed keys (env→environment, url→httpUrl, headers→http_headers). The opencode and copilot special-cases collapse into manifest config. defaults: applied to the config root so opencode's $schema is now written. - deployer.py: single generic copy helper reads ResourceLayout (directory vs file) instead of looking up target name in a dict. Public API (deploy_skill / deploy_command / deploy_agent / deploy_single_* / DeployResult) preserved. - config.py: VALID_TARGETS frozenset replaced with registry.list_builtins(), so the validation list is sourced from the bundled YAMLs and will auto-update as we add or rename manifests. - cli.py: resolves config.targets to a list[TargetDef] once via the registry, then passes that list everywhere. _sync_resource_type now takes target_defs instead of the full config. - agpack/targets.py: deleted. No remaining references. - tests: test_mcp.py and test_deployer.py keep their existing bodies but go through small adapter shims that resolve name strings to TargetDef. Three tests that called private _merge_*/_remove_from_* helpers are reframed against the public cleanup_mcp_server API (which still handles fuzzy keys when the target is unknown). Two "doesn't support" assertions repointed because cursor now supports commands and codex now supports agents. Behavior change observable to users: the path/encoding bug fixes baked into the built-in YAMLs (codex .codex/skills, cursor .cursor/commands, gemini httpUrl for HTTP, antigravity .agents/, etc.) are now live. The lockfile still records exact deployed paths, so cleanup of files in old (buggy) locations happens naturally on first sync after upgrade. All 313 tests pass; ruff + mypy strict clean; wheel builds.
Let users override built-in target manifests or define brand-new targets inline in agpack.yml, with the same shape used by the bundled YAMLs. Replace semantics — if a name appears in target_definitions, that entry fully supplants the built-in (no deep merge). Precedence chain (highest first): 1. project agpack.yml target_definitions 2. global ~/.config/agpack/agpack.yml target_definitions 3. bundled built-in manifests Project entries win by name during merge_configs; global entries with fresh names are added. - config.py: AgpackConfig and GlobalConfig gain a target_definitions field. _parse_target_definitions injects the mapping key as the entry name (or errors if an explicit name disagrees), then delegates to the existing parse_target_def schema validator. The legacy "Unrecognised target" check at load time is dropped — at parse time we can't yet see global target_definitions, so resolution-time errors do the work instead. - cli.py: _resolve_targets checks target_definitions before falling back to load_builtin; unknown names raise a ClickException that lists both pools and points users at target_definitions. - tests: 6 new unit tests around parsing + merging semantics (replace, not deep-merge), and 3 new integration tests covering an override of a built-in, a brand-new custom target name end-to-end, and the unknown-target CLI error.
Surface the new manifest system to users via two inspection commands and a richer scaffold: - `agpack targets list` shows every available target (built-in and user-defined) with its source and the resource types it supports. User entries that shadow a built-in are flagged. - `agpack targets show <name>` prints the resolved manifest as block YAML, suitable for pasting into `target_definitions:` as a starting point for customization. TransportSpec fields that match defaults are omitted so the output stays clean. - `agpack init` now scaffolds a commented-out `target_definitions:` block showing both override and brand-new patterns, plus a pointer to `agpack targets show`. Both subcommands accept --config and --no-global so they work in project-aware mode (showing user definitions) or standalone (just built-ins) without complaining when agpack.yml is absent. The serializer lives in target_schema.target_def_to_dict so it stays colocated with the parser; a roundtrip test guarantees every shipped built-in survives serialize→parse unchanged. 10 new tests (4 serializer + 6 CLI/integration); 335 pass overall; ruff + mypy strict clean.
Small post-refactor tidy-up — no behavior changes: - tests/test_cli_parallel.py: _make_config returned an AgpackConfig that was passed where _sync_resource_type now expects list[TargetDef]. The mismatch was silent because the mocked deploy_item_fn never touched it. Renamed to _make_targets and resolved to actual TargetDef objects. - tests/test_mcp.py: inlined the two-step _resolve_targets + _known_targets helper into one; dropped a stale comment that referenced the deleted MCP_TARGETS module. - tests/test_target_schema.py, tests/test_integration.py: hoisted in-function `from agpack.* import …` statements up to module-level imports. - agpack/cli.py: _load_user_target_definitions duplicated the global-config-loading logic across an if/elif fork. Collapsed it into a single linear flow that picks up the project's `use_global` setting when present. All 335 tests pass; ruff + mypy strict clean. Net -8 lines.
README updates: - Refresh the target mapping table with the bug-fixed paths (Codex agents, Cursor commands, Gemini httpUrl, Antigravity in .agents/, Windsurf workflows). - Add a 'Customising targets' section walking through the target_definitions block (override + brand-new patterns) and the manifest schema. - Document `agpack targets list` and `agpack targets show` in the Commands reference. - Add an 'Upgrading from 0.3.x' note explaining that the bug fixes ship as bundled YAML edits and that first-sync cleanup of files in old locations happens automatically via the lockfile. Bump __version__ to 0.4.0 to reflect the new target-customisation feature surface and the path/encoding bug fixes.
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.