agentbundle 0.29.4__tar.gz → 0.29.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (200) hide show
  1. {agentbundle-0.29.4 → agentbundle-0.29.6}/PKG-INFO +16 -5
  2. {agentbundle-0.29.4 → agentbundle-0.29.6}/README-pypi.md +15 -4
  3. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/adapter.toml +3 -0
  4. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/catalogue-scaffold/guides/_shared/reference/catalogue-authoring-standards.md +39 -5
  5. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/catalogue-scaffold/manifest.json +2 -2
  6. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/catalogue-scaffold/packs/AGENTS.md +3 -2
  7. agentbundle-0.29.6/agentbundle/_data/marketplace-entry.schema.json +110 -0
  8. agentbundle-0.29.6/agentbundle/_data/plugin-manifest.derived.schema.json +147 -0
  9. agentbundle-0.29.6/agentbundle/_data/plugin-manifest.schema.json +110 -0
  10. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/adapters/claude_code.py +27 -2
  11. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/main.py +88 -16
  12. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_end_to_end_build.py +11 -3
  13. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_pipeline.py +2 -2
  14. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_plugin_manifest_schema.py +4 -4
  15. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_projectable_subset.py +4 -4
  16. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_self_host_check.py +0 -1
  17. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/package.py +84 -28
  18. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/self_host_windows.py +14 -3
  19. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/verify.py +84 -25
  20. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/upgrade.py +1 -1
  21. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/version.py +1 -1
  22. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle.egg-info/PKG-INFO +16 -5
  23. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle.egg-info/SOURCES.txt +1 -0
  24. {agentbundle-0.29.4 → agentbundle-0.29.6}/pyproject.toml +1 -1
  25. agentbundle-0.29.4/agentbundle/_data/plugin-manifest.derived.schema.json +0 -73
  26. agentbundle-0.29.4/agentbundle/_data/plugin-manifest.schema.json +0 -45
  27. {agentbundle-0.29.4 → agentbundle-0.29.6}/README.md +0 -0
  28. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/__init__.py +0 -0
  29. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/__main__.py +0 -0
  30. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/adapter.schema.json +0 -0
  31. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/catalogue-scaffold/guides/_shared/reference/catalogue-ci-contract.md +0 -0
  32. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/catalogue-scaffold/packs/README.md +0 -0
  33. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/catalogue-scaffold/packs/_example/README.md +0 -0
  34. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/catalogue-scaffold/packs/_example/pack.toml +0 -0
  35. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/catalogue-scaffold/profiles/AGENTS.md +0 -0
  36. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/catalogue-scaffold/profiles/README.md +0 -0
  37. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/catalogue-scaffold/profiles/_example/README.md +0 -0
  38. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/catalogue-scaffold/profiles/_example/profile.toml +0 -0
  39. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/catalogue.schema.json +0 -0
  40. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/guide.schema.json +0 -0
  41. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/install-defaults.toml +0 -0
  42. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/install-marker.py +0 -0
  43. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/pack.schema.json +0 -0
  44. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/profile.schema.json +0 -0
  45. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/skill-manifest.schema.json +0 -0
  46. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/skill.schema.json +0 -0
  47. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/_data/target-vocab.toml +0 -0
  48. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/__init__.py +0 -0
  49. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/__main__.py +0 -0
  50. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/adapter_root_bins.py +0 -0
  51. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/adapters/__init__.py +0 -0
  52. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/adapters/codex.py +0 -0
  53. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/adapters/copilot.py +0 -0
  54. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/adapters/cursor.py +0 -0
  55. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/adapters/gemini.py +0 -0
  56. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/adapters/kiro.py +0 -0
  57. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/adapters/kiro_cli.py +0 -0
  58. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/adapters/kiro_ide.py +0 -0
  59. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/contract.py +0 -0
  60. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/lint_packs.py +0 -0
  61. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/phase_order.py +0 -0
  62. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/projections/__init__.py +0 -0
  63. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/projections/codex_agent_toml.py +0 -0
  64. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/projections/copilot_agent_md.py +0 -0
  65. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/projections/copilot_hooks_json.py +0 -0
  66. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/projections/direct_directory.py +0 -0
  67. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/projections/gemini_command_toml.py +0 -0
  68. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/projections/hook_id.py +0 -0
  69. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/projections/kiro_ide_hook.py +0 -0
  70. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/projections/merge_into_agent_json.py +0 -0
  71. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/projections/merge_json.py +0 -0
  72. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/projections/user_merge_json.py +0 -0
  73. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/recipes/composite-agents-md.toml +0 -0
  74. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/recipes/composite-marketplace.toml +0 -0
  75. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/recipes/marketplace.toml +0 -0
  76. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/recipes/per-pack-apm-package.toml +0 -0
  77. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/recipes/per-pack-claude-plugin.toml +0 -0
  78. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/recipes/per-pack-overlay.toml +0 -0
  79. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/recipes/self-host.toml +0 -0
  80. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/scope_rails.py +0 -0
  81. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/self_host.py +0 -0
  82. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/shared_libs.py +0 -0
  83. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/target_resolver.py +0 -0
  84. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/__init__.py +0 -0
  85. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_adapter_claude_code.py +0 -0
  86. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_adapter_codex.py +0 -0
  87. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_adapter_copilot.py +0 -0
  88. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_adapter_cursor.py +0 -0
  89. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_adapter_gemini.py +0 -0
  90. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_adapter_kiro.py +0 -0
  91. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_adapter_kiro_alias.py +0 -0
  92. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_adapter_kiro_cli.py +0 -0
  93. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_adapter_kiro_ide.py +0 -0
  94. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_adapter_root_bins_projection.py +0 -0
  95. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_architect_design_reviewer_projection.py +0 -0
  96. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_architect_design_reviewer_rubric_parity.py +0 -0
  97. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_build_ships_seeds.py +0 -0
  98. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_contract.py +0 -0
  99. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_contract_scope.py +0 -0
  100. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_contract_v07.py +0 -0
  101. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_contract_v08.py +0 -0
  102. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_direct_directory_cleanup.py +0 -0
  103. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_lint_agents_md_diataxis_block.py +0 -0
  104. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_lint_agents_md_legacy_block.py +0 -0
  105. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_lint_agents_md_risk_block.py +0 -0
  106. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_lint_packs.py +0 -0
  107. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_load_pack_hook_wiring_safely.py +0 -0
  108. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_pack_schema.py +0 -0
  109. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_pack_schema_allowed_adapters.py +0 -0
  110. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_pack_schema_install.py +0 -0
  111. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_projections_merge_json.py +0 -0
  112. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_scope_rails.py +0 -0
  113. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_security.py +0 -0
  114. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_self_host_fixture_guard.py +0 -0
  115. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_self_host_recipe_config.py +0 -0
  116. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_shared_libs_projection.py +0 -0
  117. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_shared_prefix_contract.py +0 -0
  118. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_shipped_packs_v07_declarations.py +0 -0
  119. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_shipped_packs_v08_declarations.py +0 -0
  120. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_user_libs_projection.py +0 -0
  121. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_validate.py +0 -0
  122. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_workspace_status_projection.py +0 -0
  123. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/tests/test_writers_emit_lf.py +0 -0
  124. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/user_libs.py +0 -0
  125. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/build/validate.py +0 -0
  126. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue.py +0 -0
  127. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/__init__.py +0 -0
  128. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/archive.py +0 -0
  129. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/build.py +0 -0
  130. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/config.py +0 -0
  131. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/defaults.py +0 -0
  132. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/diagnostics.py +0 -0
  133. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/identity.py +0 -0
  134. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/initialise.py +0 -0
  135. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/initialise_self_hosted.py +0 -0
  136. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/lint.py +0 -0
  137. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/results.py +0 -0
  138. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/self_host.py +0 -0
  139. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/skill_spec_lint.py +0 -0
  140. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/catalogue_tooling/toml_emit.py +0 -0
  141. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/categories.py +0 -0
  142. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/cli.py +0 -0
  143. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/__init__.py +0 -0
  144. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/_common.py +0 -0
  145. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/_drop_warning.py +0 -0
  146. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/adapt.py +0 -0
  147. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/catalogue_build.py +0 -0
  148. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/catalogue_init.py +0 -0
  149. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/catalogue_lint.py +0 -0
  150. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/catalogue_package.py +0 -0
  151. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/catalogue_self_host.py +0 -0
  152. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/catalogue_sync_defaults.py +0 -0
  153. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/catalogue_tooling_stub.py +0 -0
  154. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/catalogue_verify.py +0 -0
  155. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/config.py +0 -0
  156. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/diff.py +0 -0
  157. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/docs.py +0 -0
  158. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/init_state.py +0 -0
  159. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/install.py +0 -0
  160. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/list_installed.py +0 -0
  161. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/list_packs.py +0 -0
  162. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/list_profiles.py +0 -0
  163. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/list_targets.py +0 -0
  164. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/oplog_cmd.py +0 -0
  165. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/pack_config_cmd.py +0 -0
  166. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/pack_evals.py +0 -0
  167. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/package_catalogue.py +0 -0
  168. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/profile.py +0 -0
  169. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/reconcile.py +0 -0
  170. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/render.py +0 -0
  171. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/scaffold.py +0 -0
  172. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/show.py +0 -0
  173. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/uninstall.py +0 -0
  174. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/commands/validate.py +0 -0
  175. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/config.py +0 -0
  176. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/https_catalogue.py +0 -0
  177. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/local_exclude.py +0 -0
  178. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/oplog.py +0 -0
  179. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/pack_inventory.py +0 -0
  180. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/render.py +0 -0
  181. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/safety.py +0 -0
  182. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/scaffold.py +0 -0
  183. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/scope.py +0 -0
  184. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/source_defaults.py +0 -0
  185. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/statelock.py +0 -0
  186. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/user_config.py +0 -0
  187. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle/workspace_mcp.py +0 -0
  188. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle.egg-info/dependency_links.txt +0 -0
  189. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle.egg-info/entry_points.txt +0 -0
  190. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle.egg-info/requires.txt +0 -0
  191. {agentbundle-0.29.4 → agentbundle-0.29.6}/agentbundle.egg-info/top_level.txt +0 -0
  192. {agentbundle-0.29.4 → agentbundle-0.29.6}/setup.cfg +0 -0
  193. {agentbundle-0.29.4 → agentbundle-0.29.6}/tests/test_adapter_permissions_projection.py +0 -0
  194. {agentbundle-0.29.4 → agentbundle-0.29.6}/tests/test_linear_primitive.py +0 -0
  195. {agentbundle-0.29.4 → agentbundle-0.29.6}/tests/test_workspace_mcp_elicit.py +0 -0
  196. {agentbundle-0.29.4 → agentbundle-0.29.6}/tests/test_workspace_mcp_event_bridge.py +0 -0
  197. {agentbundle-0.29.4 → agentbundle-0.29.6}/tests/test_workspace_mcp_git.py +0 -0
  198. {agentbundle-0.29.4 → agentbundle-0.29.6}/tests/test_workspace_mcp_lifecycle.py +0 -0
  199. {agentbundle-0.29.4 → agentbundle-0.29.6}/tests/test_workspace_mcp_stdin.py +0 -0
  200. {agentbundle-0.29.4 → agentbundle-0.29.6}/tests/test_workspace_mcp_tools.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentbundle
3
- Version: 0.29.4
3
+ Version: 0.29.6
4
4
  Summary: npm for your coding agent. Install packs of skills, subagents, and hooks into any repo, for every major agent.
5
5
  Author-email: eugenelim <eugenelim@users.noreply.github.com>
6
6
  License: Apache-2.0 OR MIT
@@ -156,6 +156,13 @@ Produces a deterministic, reproducible gzip archive (versioned) and a mutable ch
156
156
  descriptor JSON (`stable.json`), ready to upload to Artifactory. Identical inputs
157
157
  produce byte-identical archives (honors `SOURCE_DATE_EPOCH`).
158
158
 
159
+ Build residue is excluded, so it does not matter whether you packaged a working
160
+ tree you had just tested or npm-installed in. Pruned at every level of a pack:
161
+ `__pycache__`, `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `.tox`,
162
+ `.hypothesis`, `htmlcov`, `node_modules`, `.venv`, `venv` — plus `*.pyc`,
163
+ `*.pyo`, `.DS_Store`, `coverage.xml` and `.coverage*` shards. The drop is
164
+ silent, so do not name a directory you mean to ship after one of those.
165
+
159
166
  **Source distribution for air-gapped or self-hosted catalogues:**
160
167
 
161
168
  ```bash
@@ -167,7 +174,7 @@ agentbundle catalogue package \
167
174
  --output dist/
168
175
  ```
169
176
 
170
- Produces a `catalogue-source-<release>.tar.gz` from a positive allowlist (packs, profiles, guides, marketplace manifest, legal files). Includes a `self-hosted-source-manifest.json` with per-file SHA-256 digests and provenance fields. `agentbundle install` refuses to install a source archive, preventing accidental misuse.
177
+ Produces a `catalogue-source-<release>.tar.gz` from a positive allowlist (packs, profiles, guides, marketplace manifest, legal files), with the same build-residue exclusions as the default flavour. Includes a `self-hosted-source-manifest.json` with per-file SHA-256 digests and provenance fields. `agentbundle install` refuses to install a source archive, preventing accidental misuse.
171
178
 
172
179
  **Org bootstrap — ship the default channel in your fork:**
173
180
 
@@ -262,7 +269,10 @@ ignore them there; the separation is structural, not incidental.
262
269
  `keywords` once; the build projects the cleanly-mappable subset — plus the
263
270
  pack's `README.md` — into each distribution route's manifest (the `plugin.json`
264
271
  / `marketplace.json` entry), so the catalogue describes each pack richly rather
265
- than with a single sentence. Extra fields stay in `pack.toml`; the projection
272
+ than with a single sentence. A marketplace entry's `source` is a `git-subdir`
273
+ object (`url`, `path`, and one of `ref`/`sha`) pointing at the pack's directory
274
+ on the published distribution branch, and every entry is schema-validated at
275
+ build time against `marketplace-entry.schema.json`. Extra fields stay in `pack.toml`; the projection
266
276
  is deliberately lossy per tool.
267
277
 
268
278
  Point a catalogue URI (a git URL or a local path) at the repo that holds your packs. Then `validate` a pack against the adapter contract, `render` it to preview the projection, and `install` it into a target repo. `scaffold` drops a pack's seeds into a fresh directory to start from. The build pipeline (`agentbundle.build`) is the same engine `make build` runs.
@@ -278,8 +288,9 @@ The org hint fires after the user-config but before the on-disk IDE probe — so
278
288
 
279
289
  **Bundled contracts** — the wheel ships the machine contracts used for offline validation:
280
290
  `pack.schema.json`, `skill.schema.json`, `guide.schema.json`, `skill-manifest.schema.json`,
281
- `profile.schema.json`, `catalogue.schema.json`, `target-vocab.toml`, and the adapter
282
- contract files. All are available without network access via `importlib.resources`.
291
+ `profile.schema.json`, `catalogue.schema.json`, `plugin-manifest.schema.json`,
292
+ `plugin-manifest.derived.schema.json`, `marketplace-entry.schema.json`,
293
+ `target-vocab.toml`, and the adapter contract files. All are available without network access via `importlib.resources`.
283
294
 
284
295
  **Lint your catalogue** — shallow structural checks run without extra dependencies:
285
296
 
@@ -134,6 +134,13 @@ Produces a deterministic, reproducible gzip archive (versioned) and a mutable ch
134
134
  descriptor JSON (`stable.json`), ready to upload to Artifactory. Identical inputs
135
135
  produce byte-identical archives (honors `SOURCE_DATE_EPOCH`).
136
136
 
137
+ Build residue is excluded, so it does not matter whether you packaged a working
138
+ tree you had just tested or npm-installed in. Pruned at every level of a pack:
139
+ `__pycache__`, `.pytest_cache`, `.mypy_cache`, `.ruff_cache`, `.tox`,
140
+ `.hypothesis`, `htmlcov`, `node_modules`, `.venv`, `venv` — plus `*.pyc`,
141
+ `*.pyo`, `.DS_Store`, `coverage.xml` and `.coverage*` shards. The drop is
142
+ silent, so do not name a directory you mean to ship after one of those.
143
+
137
144
  **Source distribution for air-gapped or self-hosted catalogues:**
138
145
 
139
146
  ```bash
@@ -145,7 +152,7 @@ agentbundle catalogue package \
145
152
  --output dist/
146
153
  ```
147
154
 
148
- Produces a `catalogue-source-<release>.tar.gz` from a positive allowlist (packs, profiles, guides, marketplace manifest, legal files). Includes a `self-hosted-source-manifest.json` with per-file SHA-256 digests and provenance fields. `agentbundle install` refuses to install a source archive, preventing accidental misuse.
155
+ Produces a `catalogue-source-<release>.tar.gz` from a positive allowlist (packs, profiles, guides, marketplace manifest, legal files), with the same build-residue exclusions as the default flavour. Includes a `self-hosted-source-manifest.json` with per-file SHA-256 digests and provenance fields. `agentbundle install` refuses to install a source archive, preventing accidental misuse.
149
156
 
150
157
  **Org bootstrap — ship the default channel in your fork:**
151
158
 
@@ -240,7 +247,10 @@ ignore them there; the separation is structural, not incidental.
240
247
  `keywords` once; the build projects the cleanly-mappable subset — plus the
241
248
  pack's `README.md` — into each distribution route's manifest (the `plugin.json`
242
249
  / `marketplace.json` entry), so the catalogue describes each pack richly rather
243
- than with a single sentence. Extra fields stay in `pack.toml`; the projection
250
+ than with a single sentence. A marketplace entry's `source` is a `git-subdir`
251
+ object (`url`, `path`, and one of `ref`/`sha`) pointing at the pack's directory
252
+ on the published distribution branch, and every entry is schema-validated at
253
+ build time against `marketplace-entry.schema.json`. Extra fields stay in `pack.toml`; the projection
244
254
  is deliberately lossy per tool.
245
255
 
246
256
  Point a catalogue URI (a git URL or a local path) at the repo that holds your packs. Then `validate` a pack against the adapter contract, `render` it to preview the projection, and `install` it into a target repo. `scaffold` drops a pack's seeds into a fresh directory to start from. The build pipeline (`agentbundle.build`) is the same engine `make build` runs.
@@ -256,8 +266,9 @@ The org hint fires after the user-config but before the on-disk IDE probe — so
256
266
 
257
267
  **Bundled contracts** — the wheel ships the machine contracts used for offline validation:
258
268
  `pack.schema.json`, `skill.schema.json`, `guide.schema.json`, `skill-manifest.schema.json`,
259
- `profile.schema.json`, `catalogue.schema.json`, `target-vocab.toml`, and the adapter
260
- contract files. All are available without network access via `importlib.resources`.
269
+ `profile.schema.json`, `catalogue.schema.json`, `plugin-manifest.schema.json`,
270
+ `plugin-manifest.derived.schema.json`, `marketplace-entry.schema.json`,
271
+ `target-vocab.toml`, and the adapter contract files. All are available without network access via `importlib.resources`.
261
272
 
262
273
  **Lint your catalogue** — shallow structural checks run without extra dependencies:
263
274
 
@@ -188,12 +188,14 @@ install-routes = ["cli", "claude-plugins", "apm"]
188
188
  primitive = "skill"
189
189
  mode = "direct-directory"
190
190
  target-path = ".claude/skills/"
191
+ plugin-target-path = "skills/"
191
192
  on-conflict = "prompt-then-preserve"
192
193
 
193
194
  [[adapter."claude-code".projection]]
194
195
  primitive = "agent"
195
196
  mode = "direct-file"
196
197
  target-path = ".claude/agents/"
198
+ plugin-target-path = "agents/"
197
199
  on-conflict = "prompt-then-preserve"
198
200
 
199
201
  [[adapter."claude-code".projection]]
@@ -213,6 +215,7 @@ on-conflict = "merge-managed-key-only"
213
215
  primitive = "command"
214
216
  mode = "direct-file"
215
217
  target-path = ".claude/commands/"
218
+ plugin-target-path = "commands/"
216
219
  on-conflict = "prompt-then-preserve"
217
220
 
218
221
  # hook-body — scope-conditional target.
@@ -156,17 +156,51 @@ credentials or private data, prefer synthetic data, stay modest in size, and
156
156
  name their licence when sourced externally. Fuzzing corpora, generated output,
157
157
  coverage reports, and caches are neither committed nor packaged.
158
158
 
159
+ The packager enforces the second half. It prunes these directory names at every
160
+ level of a pack, and never descends into them:
161
+
162
+ ```
163
+ __pycache__ .pytest_cache .mypy_cache .ruff_cache .tox
164
+ .hypothesis htmlcov node_modules .venv venv
165
+ ```
166
+
167
+ plus `*.pyc`, `*.pyo`, `.DS_Store`, `coverage.xml`, and any `.coverage*` shard.
168
+ A directory you mean to ship must not be named one of those — the drop is
169
+ silent. Note this is matched by name at any depth, so it is deliberately *not*
170
+ the same list as the repository-root exclusions.
171
+
159
172
  ### Repository-root tests
160
173
 
161
174
  A test concerning one pack stays inside that pack. Behaviour no single pack
162
175
  owns — the catalogue system, packaging, shared projection machinery, profiles,
163
176
  cross-pack interaction — belongs to the repository, not to a pack.
164
177
 
165
- Where that lives is the repository's call. This catalogue keeps it in the
166
- engine's own suite (`packages/agentbundle/tests/`) rather than a root `tests/`
167
- tree; a catalogue that wants the separate tree can add one. Don't create a
168
- top-level directory for a single test — the ownership rule is what matters,
169
- not the path.
178
+ Where that lives is the repository's call. This catalogue splits it: behaviour
179
+ that exercises the engine keeps to the engine's own suite
180
+ (`packages/agentbundle/tests/`), while cross-pack *lints* — the ones that read
181
+ every pack's tree and belong to no pack — live with the repository's other
182
+ tooling. Neither is a root `tests/` tree; a catalogue that wants the separate
183
+ tree can add one. Don't create a top-level directory for a single test — the
184
+ ownership rule is what matters, not the path.
185
+
186
+ ### One test process per skill
187
+
188
+ Run each skill's suite in its own process. This is a correctness requirement,
189
+ not a performance preference.
190
+
191
+ Skills are independent, so two of them may reasonably ship a `render.py`, and
192
+ their suites may both be called `test_render.py`. Collect them into one pytest
193
+ run and two things break: pytest refuses the duplicate test basenames outright
194
+ (`import file mismatch`), and if it did not, the first `render` module imported
195
+ would serve every suite that expects its own.
196
+
197
+ ```
198
+ pytest packs/<pack>/tests/skills/<skill>/ # one invocation per skill
199
+ ```
200
+
201
+ An invocation that spans two skill test directories is safe only while their
202
+ basenames happen not to collide — which is a property of today's contents, not
203
+ of the layout. Keep the invocations separate and the question never arises.
170
204
 
171
205
  ### Normative summary
172
206
 
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "files": {
3
- "guides/_shared/reference/catalogue-authoring-standards.md": "0d278062872d62d059e322bae9e5af9f573d79bc93ff24ca18fb750705da5cc6",
3
+ "guides/_shared/reference/catalogue-authoring-standards.md": "cec0f7afd7a0bf61d7bedd9facd096b083cb7413679a6fbcd0af28d40bece58c",
4
4
  "guides/_shared/reference/catalogue-ci-contract.md": "fae793ab47989b6dd3c731afcb0b4cda21c7d08bbe7fa40fca6d3abb3d158141",
5
- "packs/AGENTS.md": "7b534acfdaab757079ca678d9290c2257267d7f4e0b4b3c3401d9da22cb4be0b",
5
+ "packs/AGENTS.md": "861a029007741cd7645cdfcc018e5ac85cf218d332f6688115156c9c676381b8",
6
6
  "packs/README.md": "d2de5f9556f4c8e521103474bde74636e02cc805f9bf5312a3a61a1f3eb45d8f",
7
7
  "packs/_example/.apm/skills/example-skill/SKILL.md": "33be8cbf4b2c014a5a63e788b7d0b350ad8061c6c4b2579369a3e984135bf9f1",
8
8
  "packs/_example/.apm/skills/example-skill/evals/eval_queries.json": "f41ecda0834a22f3b4823c81ab02e58b0e4beba610e3b40c185579abff9cfeee",
@@ -6,8 +6,9 @@ Read `packs/AGENTS.local.md` when present — it carries host-specific overrides
6
6
  ## Pack layout
7
7
 
8
8
  The pack is the ownership and test-execution boundary; `.apm/` is the runtime export boundary; a skill is the
9
- evaluation-fixture boundary. Tests go in `packs/<pack>/tests/`, never under `.apm/`. Evals stay skill-local at
10
- `.apm/skills/<skill>/evals/` and project with the skill.
9
+ evaluation-fixture boundary. Tests go in `packs/<pack>/tests/`, never under `.apm/`; evals stay skill-local at
10
+ `.apm/skills/<skill>/evals/` and project with the skill. `tools/lint-pack-test-boundary.py` enforces both across
11
+ every pack, plus one pytest process per skill test dir. Shape: `docs/architecture/pack-layout.md`.
11
12
 
12
13
  | Path | Purpose |
13
14
  |------|---------|
@@ -0,0 +1,110 @@
1
+ {
2
+ "x-spec": "docs/specs/claude-plugins-manifest-correctness",
3
+ "type": "object",
4
+ "required": [
5
+ "name",
6
+ "version",
7
+ "description"
8
+ ],
9
+ "additionalProperties": false,
10
+ "properties": {
11
+ "name": {
12
+ "type": "string"
13
+ },
14
+ "version": {
15
+ "type": "string"
16
+ },
17
+ "description": {
18
+ "type": "string"
19
+ },
20
+ "skills": {
21
+ "type": "array",
22
+ "items": {
23
+ "type": "string"
24
+ }
25
+ },
26
+ "agents": {
27
+ "type": "array",
28
+ "items": {
29
+ "type": "string"
30
+ }
31
+ },
32
+ "author": {
33
+ "type": "object",
34
+ "required": [
35
+ "name"
36
+ ],
37
+ "properties": {
38
+ "name": {
39
+ "type": "string"
40
+ },
41
+ "email": {
42
+ "type": "string"
43
+ }
44
+ }
45
+ },
46
+ "license": {
47
+ "type": "string"
48
+ },
49
+ "homepage": {
50
+ "type": "string"
51
+ },
52
+ "repository": {
53
+ "type": "string"
54
+ },
55
+ "keywords": {
56
+ "type": "array",
57
+ "items": {
58
+ "type": "string"
59
+ }
60
+ },
61
+ "displayName": {
62
+ "type": "string"
63
+ },
64
+ "category": {
65
+ "type": "string"
66
+ },
67
+ "source": {
68
+ "type": "object",
69
+ "required": [
70
+ "source",
71
+ "url",
72
+ "path"
73
+ ],
74
+ "additionalProperties": false,
75
+ "properties": {
76
+ "source": {
77
+ "type": "string",
78
+ "enum": [
79
+ "git-subdir"
80
+ ]
81
+ },
82
+ "url": {
83
+ "type": "string",
84
+ "pattern": "^https://github\\.com/[^/]+/[^/]+\\.git$"
85
+ },
86
+ "path": {
87
+ "type": "string",
88
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
89
+ },
90
+ "ref": {
91
+ "type": "string"
92
+ },
93
+ "sha": {
94
+ "type": "string"
95
+ }
96
+ },
97
+ "if": {
98
+ "required": [
99
+ "ref"
100
+ ]
101
+ },
102
+ "then": {},
103
+ "else": {
104
+ "required": [
105
+ "sha"
106
+ ]
107
+ }
108
+ }
109
+ }
110
+ }
@@ -0,0 +1,147 @@
1
+ {
2
+ "x-spec": "docs/specs/claude-plugins-manifest-correctness",
3
+ "type": "object",
4
+ "required": [
5
+ "name",
6
+ "version",
7
+ "description"
8
+ ],
9
+ "additionalProperties": false,
10
+ "properties": {
11
+ "name": {
12
+ "type": "string"
13
+ },
14
+ "version": {
15
+ "type": "string"
16
+ },
17
+ "description": {
18
+ "type": "string"
19
+ },
20
+ "skills": {
21
+ "type": "array",
22
+ "items": {
23
+ "type": "string"
24
+ }
25
+ },
26
+ "agents": {
27
+ "type": "array",
28
+ "items": {
29
+ "type": "string"
30
+ }
31
+ },
32
+ "author": {
33
+ "type": "object",
34
+ "required": [
35
+ "name"
36
+ ],
37
+ "properties": {
38
+ "name": {
39
+ "type": "string"
40
+ },
41
+ "email": {
42
+ "type": "string"
43
+ }
44
+ }
45
+ },
46
+ "license": {
47
+ "type": "string"
48
+ },
49
+ "homepage": {
50
+ "type": "string"
51
+ },
52
+ "repository": {
53
+ "type": "string"
54
+ },
55
+ "keywords": {
56
+ "type": "array",
57
+ "items": {
58
+ "type": "string"
59
+ }
60
+ },
61
+ "displayName": {
62
+ "type": "string"
63
+ },
64
+ "source": {
65
+ "type": "object",
66
+ "required": [
67
+ "source",
68
+ "url",
69
+ "path"
70
+ ],
71
+ "additionalProperties": false,
72
+ "properties": {
73
+ "source": {
74
+ "type": "string",
75
+ "enum": [
76
+ "git-subdir"
77
+ ]
78
+ },
79
+ "url": {
80
+ "type": "string",
81
+ "pattern": "^https://github\\.com/[^/]+/[^/]+\\.git$"
82
+ },
83
+ "path": {
84
+ "type": "string",
85
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
86
+ },
87
+ "ref": {
88
+ "type": "string"
89
+ },
90
+ "sha": {
91
+ "type": "string"
92
+ }
93
+ },
94
+ "if": {
95
+ "required": [
96
+ "ref"
97
+ ]
98
+ },
99
+ "then": {},
100
+ "else": {
101
+ "required": [
102
+ "sha"
103
+ ]
104
+ }
105
+ },
106
+ "hooks": {
107
+ "type": "object",
108
+ "additionalProperties": false,
109
+ "properties": {
110
+ "SessionStart": {
111
+ "type": "array",
112
+ "items": {
113
+ "type": "object",
114
+ "additionalProperties": false,
115
+ "properties": {
116
+ "hooks": {
117
+ "type": "array",
118
+ "items": {
119
+ "type": "object",
120
+ "required": [
121
+ "type",
122
+ "command"
123
+ ],
124
+ "additionalProperties": false,
125
+ "properties": {
126
+ "type": {
127
+ "type": "string",
128
+ "enum": [
129
+ "command"
130
+ ]
131
+ },
132
+ "command": {
133
+ "type": "string"
134
+ },
135
+ "timeout": {
136
+ "type": "integer"
137
+ }
138
+ }
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
@@ -0,0 +1,110 @@
1
+ {
2
+ "x-spec": "docs/specs/claude-plugins-manifest-correctness",
3
+ "type": "object",
4
+ "required": [
5
+ "name",
6
+ "version",
7
+ "description"
8
+ ],
9
+ "additionalProperties": false,
10
+ "properties": {
11
+ "name": {
12
+ "type": "string"
13
+ },
14
+ "version": {
15
+ "type": "string"
16
+ },
17
+ "description": {
18
+ "type": "string"
19
+ },
20
+ "skills": {
21
+ "type": "array",
22
+ "items": {
23
+ "type": "string"
24
+ }
25
+ },
26
+ "agents": {
27
+ "type": "array",
28
+ "items": {
29
+ "type": "string"
30
+ }
31
+ },
32
+ "author": {
33
+ "type": "object",
34
+ "required": [
35
+ "name"
36
+ ],
37
+ "properties": {
38
+ "name": {
39
+ "type": "string"
40
+ },
41
+ "email": {
42
+ "type": "string"
43
+ }
44
+ }
45
+ },
46
+ "license": {
47
+ "type": "string"
48
+ },
49
+ "homepage": {
50
+ "type": "string"
51
+ },
52
+ "repository": {
53
+ "type": "string"
54
+ },
55
+ "keywords": {
56
+ "type": "array",
57
+ "items": {
58
+ "type": "string"
59
+ }
60
+ },
61
+ "category": {
62
+ "type": "string"
63
+ },
64
+ "displayName": {
65
+ "type": "string"
66
+ },
67
+ "source": {
68
+ "type": "object",
69
+ "required": [
70
+ "source",
71
+ "url",
72
+ "path"
73
+ ],
74
+ "additionalProperties": false,
75
+ "properties": {
76
+ "source": {
77
+ "type": "string",
78
+ "enum": [
79
+ "git-subdir"
80
+ ]
81
+ },
82
+ "url": {
83
+ "type": "string",
84
+ "pattern": "^https://github\\.com/[^/]+/[^/]+\\.git$"
85
+ },
86
+ "path": {
87
+ "type": "string",
88
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
89
+ },
90
+ "ref": {
91
+ "type": "string"
92
+ },
93
+ "sha": {
94
+ "type": "string"
95
+ }
96
+ },
97
+ "if": {
98
+ "required": [
99
+ "ref"
100
+ ]
101
+ },
102
+ "then": {},
103
+ "else": {
104
+ "required": [
105
+ "sha"
106
+ ]
107
+ }
108
+ }
109
+ }
110
+ }
@@ -62,11 +62,33 @@ def project_packs(pack_paths: list[Path], contract: dict, output_root: Path) ->
62
62
  # Mirror of kiro.py:_skill_direct_directory_target — keep in sync.
63
63
  # A shared helper is barred by the spec's `Never do` boundary (no
64
64
  # expansion of projections/direct_directory.py beyond `sweep_orphans`).
65
+ def _resolve_target(output_root: Path, target_path: str) -> Path:
66
+ """Join a contract ``target-path`` onto ``output_root``, confined.
67
+
68
+ ``target-path`` (and its route-scoped sibling ``plugin-target-path``) are
69
+ contract *data*. An absolute value discards the base entirely on join
70
+ (``Path("/a/b") / "/etc/x"`` is ``/etc/x``) and a ``..``-bearing one walks
71
+ out of it — and because the orphan sweep resolves the same value, an
72
+ escaped target becomes the root of a ``shutil.rmtree``. Confine after
73
+ resolution rather than trusting the string (CWE-73, not just CWE-22).
74
+ """
75
+ candidate = output_root / target_path.rstrip("/")
76
+ root_resolved = output_root.resolve()
77
+ try:
78
+ candidate.resolve().relative_to(root_resolved)
79
+ except ValueError:
80
+ raise ValueError(
81
+ f"claude-code: target-path {target_path!r} escapes the output root "
82
+ f"{output_root}"
83
+ ) from None
84
+ return candidate
85
+
86
+
65
87
  def _skill_direct_directory_target(contract: dict, output_root: Path) -> Path | None:
66
88
  adapter_block = contract["adapter"]["claude-code"]
67
89
  for entry in adapter_block.get("projection", []):
68
90
  if entry.get("primitive") == "skill" and entry.get("mode") == "direct-directory":
69
- return output_root / entry["target-path"].rstrip("/")
91
+ return _resolve_target(output_root, entry["target-path"])
70
92
  return None
71
93
 
72
94
 
@@ -128,8 +150,11 @@ def _project_single(pack_path: Path, contract: dict, output_root: Path) -> None:
128
150
  continue
129
151
 
130
152
  if mode == "direct-directory":
131
- _project_direct_directory(source_dir, output_root / rule["target-path"].rstrip("/"))
153
+ _project_direct_directory(
154
+ source_dir, _resolve_target(output_root, rule["target-path"])
155
+ )
132
156
  elif mode == "direct-file":
157
+ _resolve_target(output_root, rule["target-path"]) # confinement check
133
158
  _project_direct_file(source_dir, output_root, rule["target-path"])
134
159
  elif mode == "merge-json":
135
160
  project_merge_json(source_dir, output_root, rule)