agentbundle 0.4.0__tar.gz → 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. {agentbundle-0.4.0 → agentbundle-0.6.0}/PKG-INFO +9 -3
  2. {agentbundle-0.4.0 → agentbundle-0.6.0}/README.md +8 -2
  3. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/_data/adapter.schema.json +1 -0
  4. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/_data/adapter.toml +22 -1
  5. agentbundle-0.6.0/agentbundle/_data/profile.schema.json +21 -0
  6. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/adapters/kiro.py +10 -0
  7. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/adapters/kiro_ide.py +24 -7
  8. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/scope_rails.py +12 -2
  9. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_adapter_cursor.py +3 -2
  10. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_adapter_gemini.py +3 -3
  11. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_adapter_kiro_cli.py +39 -0
  12. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_adapter_kiro_ide.py +42 -4
  13. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_contract.py +7 -8
  14. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/cli.py +30 -4
  15. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/install.py +410 -25
  16. agentbundle-0.6.0/agentbundle/commands/list_profiles.py +63 -0
  17. agentbundle-0.6.0/agentbundle/commands/profile.py +155 -0
  18. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/uninstall.py +4 -1
  19. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/upgrade.py +21 -6
  20. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/validate.py +16 -5
  21. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/version.py +1 -1
  22. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle.egg-info/PKG-INFO +9 -3
  23. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle.egg-info/SOURCES.txt +3 -0
  24. {agentbundle-0.4.0 → agentbundle-0.6.0}/pyproject.toml +1 -1
  25. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/__init__.py +0 -0
  26. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/__main__.py +0 -0
  27. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/_data/install-marker.py +0 -0
  28. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/_data/pack.schema.json +0 -0
  29. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/_data/plugin-manifest.derived.schema.json +0 -0
  30. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/_data/plugin-manifest.schema.json +0 -0
  31. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/__init__.py +0 -0
  32. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/__main__.py +0 -0
  33. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/adapter_root_bins.py +0 -0
  34. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/adapters/__init__.py +0 -0
  35. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/adapters/claude_code.py +0 -0
  36. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/adapters/codex.py +0 -0
  37. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/adapters/copilot.py +0 -0
  38. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/adapters/cursor.py +0 -0
  39. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/adapters/gemini.py +0 -0
  40. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/adapters/kiro_cli.py +0 -0
  41. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/contract.py +0 -0
  42. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/lint_packs.py +0 -0
  43. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/main.py +0 -0
  44. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/phase_order.py +0 -0
  45. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/projections/__init__.py +0 -0
  46. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/projections/codex_agent_toml.py +0 -0
  47. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/projections/copilot_agent_md.py +0 -0
  48. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/projections/copilot_hooks_json.py +0 -0
  49. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/projections/direct_directory.py +0 -0
  50. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/projections/gemini_command_toml.py +0 -0
  51. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/projections/hook_id.py +0 -0
  52. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/projections/kiro_ide_hook.py +0 -0
  53. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/projections/merge_into_agent_json.py +0 -0
  54. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/projections/merge_json.py +0 -0
  55. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/projections/user_merge_json.py +0 -0
  56. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/self_host.py +0 -0
  57. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/shared_libs.py +0 -0
  58. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/target_resolver.py +0 -0
  59. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/__init__.py +0 -0
  60. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_adapter_claude_code.py +0 -0
  61. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_adapter_codex.py +0 -0
  62. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_adapter_copilot.py +0 -0
  63. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_adapter_kiro.py +0 -0
  64. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_adapter_kiro_alias.py +0 -0
  65. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_adapter_root_bins_projection.py +0 -0
  66. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_architect_design_reviewer_projection.py +0 -0
  67. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_architect_design_reviewer_rubric_parity.py +0 -0
  68. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_build_ships_seeds.py +0 -0
  69. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_contract_scope.py +0 -0
  70. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_contract_v07.py +0 -0
  71. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_contract_v08.py +0 -0
  72. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_direct_directory_cleanup.py +0 -0
  73. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_end_to_end_build.py +0 -0
  74. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_lint_agents_md_diataxis_block.py +0 -0
  75. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_lint_agents_md_legacy_block.py +0 -0
  76. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_lint_agents_md_risk_block.py +0 -0
  77. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_lint_packs.py +0 -0
  78. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_load_pack_hook_wiring_safely.py +0 -0
  79. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_pack_schema.py +0 -0
  80. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_pack_schema_allowed_adapters.py +0 -0
  81. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_pack_schema_install.py +0 -0
  82. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_pipeline.py +0 -0
  83. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_plugin_manifest_schema.py +0 -0
  84. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_projectable_subset.py +0 -0
  85. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_projections_merge_json.py +0 -0
  86. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_scope_rails.py +0 -0
  87. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_security.py +0 -0
  88. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_self_host_check.py +0 -0
  89. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_shared_libs_projection.py +0 -0
  90. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_shipped_packs_v07_declarations.py +0 -0
  91. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_shipped_packs_v08_declarations.py +0 -0
  92. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_user_libs_projection.py +0 -0
  93. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/tests/test_validate.py +0 -0
  94. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/user_libs.py +0 -0
  95. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/build/validate.py +0 -0
  96. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/catalogue.py +0 -0
  97. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/categories.py +0 -0
  98. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/__init__.py +0 -0
  99. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/_common.py +0 -0
  100. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/_drop_warning.py +0 -0
  101. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/adapt.py +0 -0
  102. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/config.py +0 -0
  103. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/diff.py +0 -0
  104. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/init_state.py +0 -0
  105. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/list_packs.py +0 -0
  106. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/list_targets.py +0 -0
  107. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/reconcile.py +0 -0
  108. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/render.py +0 -0
  109. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/commands/scaffold.py +0 -0
  110. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/config.py +0 -0
  111. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/render.py +0 -0
  112. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/safety.py +0 -0
  113. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/scope.py +0 -0
  114. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle/user_config.py +0 -0
  115. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle.egg-info/dependency_links.txt +0 -0
  116. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle.egg-info/entry_points.txt +0 -0
  117. {agentbundle-0.4.0 → agentbundle-0.6.0}/agentbundle.egg-info/top_level.txt +0 -0
  118. {agentbundle-0.4.0 → agentbundle-0.6.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentbundle
3
- Version: 0.4.0
3
+ Version: 0.6.0
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
@@ -31,7 +31,7 @@ pip install agentbundle
31
31
  agentbundle install --pack core git+https://github.com/eugenelim/agent-ready-repo
32
32
  ```
33
33
 
34
- That lands `core`, the flagship pack and the loop itself, in your repo. Claude Code, Codex, Cursor, Copilot, Gemini, and Kiro all read it.
34
+ That lands `core`, the flagship pack and the loop itself, in your repo. Claude Code, Codex, Cursor, Copilot, Gemini, and Kiro — both the CLI and the IDE — all read it, subagents and skills included.
35
35
 
36
36
  ## Common commands
37
37
 
@@ -39,6 +39,12 @@ That lands `core`, the flagship pack and the loop itself, in your repo. Claude C
39
39
  # See what's in a catalogue
40
40
  agentbundle list-packs git+https://github.com/eugenelim/agent-ready-repo
41
41
 
42
+ # See the catalogue's curated install profiles
43
+ agentbundle list-profiles git+https://github.com/eugenelim/agent-ready-repo
44
+
45
+ # Install a whole curated profile — a single-scope set of packs — in one command
46
+ agentbundle install --profile inception git+https://github.com/eugenelim/agent-ready-repo
47
+
42
48
  # Install the flagship loop into this repo
43
49
  agentbundle install --pack core git+https://github.com/eugenelim/agent-ready-repo
44
50
 
@@ -52,7 +58,7 @@ agentbundle install --pack core git+https://github.com/eugenelim/agent-ready-rep
52
58
  agentbundle upgrade --pack core --to 0.4.0 git+https://github.com/eugenelim/agent-ready-repo
53
59
  ```
54
60
 
55
- A catalogue is a git URL or a local path. Installs auto-detect your agent; pass `--adapter` to override.
61
+ A catalogue is a git URL or a local path. Installs auto-detect your agent; pass `--adapter` to override. A **profile** is a catalogue-curated, single-scope set of packs you install in one command — it declares its own scope, so `--scope` doesn't apply.
56
62
 
57
63
  ## Build your own catalogue
58
64
 
@@ -13,7 +13,7 @@ pip install agentbundle
13
13
  agentbundle install --pack core git+https://github.com/eugenelim/agent-ready-repo
14
14
  ```
15
15
 
16
- That lands `core`, the flagship pack and the loop itself, in your repo. Claude Code, Codex, Cursor, Copilot, Gemini, and Kiro all read it.
16
+ That lands `core`, the flagship pack and the loop itself, in your repo. Claude Code, Codex, Cursor, Copilot, Gemini, and Kiro — both the CLI and the IDE — all read it, subagents and skills included.
17
17
 
18
18
  ## Common commands
19
19
 
@@ -21,6 +21,12 @@ That lands `core`, the flagship pack and the loop itself, in your repo. Claude C
21
21
  # See what's in a catalogue
22
22
  agentbundle list-packs git+https://github.com/eugenelim/agent-ready-repo
23
23
 
24
+ # See the catalogue's curated install profiles
25
+ agentbundle list-profiles git+https://github.com/eugenelim/agent-ready-repo
26
+
27
+ # Install a whole curated profile — a single-scope set of packs — in one command
28
+ agentbundle install --profile inception git+https://github.com/eugenelim/agent-ready-repo
29
+
24
30
  # Install the flagship loop into this repo
25
31
  agentbundle install --pack core git+https://github.com/eugenelim/agent-ready-repo
26
32
 
@@ -34,7 +40,7 @@ agentbundle install --pack core git+https://github.com/eugenelim/agent-ready-rep
34
40
  agentbundle upgrade --pack core --to 0.4.0 git+https://github.com/eugenelim/agent-ready-repo
35
41
  ```
36
42
 
37
- A catalogue is a git URL or a local path. Installs auto-detect your agent; pass `--adapter` to override.
43
+ A catalogue is a git URL or a local path. Installs auto-detect your agent; pass `--adapter` to override. A **profile** is a catalogue-curated, single-scope set of packs you install in one command — it declares its own scope, so `--scope` doesn't apply.
38
44
 
39
45
  ## Build your own catalogue
40
46
 
@@ -69,6 +69,7 @@
69
69
  "managed-block-delimiter-end": {"type": "string"},
70
70
  "frontmatter-mapping": {"type": "string"},
71
71
  "frontmatter-default": {"type": "string"},
72
+ "inject-resources": {"type": "array", "items": {"type": "string"}},
72
73
  "info-message": {"type": "string"}
73
74
  }
74
75
  }
@@ -71,7 +71,13 @@
71
71
  # each pack's README. All new fields are optional — packs pinned below v0.14
72
72
  # build and validate unchanged. Declaration + projection only (no @catalogue/pack
73
73
  # resolution, no search, no persisted index).
74
- version = "0.14"
74
+ # docs/specs/kiro-cli-agent-skill-resources (v0.15): kiro-cli agent projection
75
+ # injects a fixed skill-resources glob (both install scopes) so headless
76
+ # `--agent` runs reach the bundle's skills — Kiro custom agents don't inherit
77
+ # the default agent's `.kiro/skills` auto-discovery (RFC-0022 E4; kiro
78
+ # #6887/#6888/#4993). Additive `inject-resources` on BOTH the kiro-cli and
79
+ # kiro-ide agent projections (CLI → agent JSON, IDE → quoted .md frontmatter).
80
+ version = "0.15"
75
81
 
76
82
  # Sibling schemas this contract references — pack metadata and the
77
83
  # per-pack Claude-plugin manifest. Defined by spec AC #3 + #4.
@@ -319,6 +325,13 @@ primitive = "agent"
319
325
  mode = "direct-file"
320
326
  target-path = ".kiro/agents/"
321
327
  frontmatter-mapping = "kiro-ide-agent-frontmatter-v0.9"
328
+ # Skill discovery (RFC-0022 E4): IDE custom agents / subagents do NOT inherit
329
+ # the default agent's `.kiro/skills` auto-discovery either (kiro #6887/#6888,
330
+ # #4993). Inject the same fixed skill-resources glob as kiro-cli; the IDE
331
+ # agent `resources` field is documented and `skill://`-aware, so it does not
332
+ # trip the silent-drop bug (that's for non-schema keys like `hooks`). Emitted
333
+ # into the `.md` YAML frontmatter, quoted. Author override wins.
334
+ inject-resources = ["skill://.kiro/skills/**/SKILL.md", "skill://~/.kiro/skills/**/SKILL.md"]
322
335
  on-conflict = "prompt-then-preserve"
323
336
 
324
337
  [[adapter.kiro-ide.projection]]
@@ -388,6 +401,14 @@ primitive = "agent"
388
401
  mode = "direct-file"
389
402
  target-path = ".kiro/agents/"
390
403
  frontmatter-mapping = "kiro-cli-agent-frontmatter-v1.0"
404
+ # Skill discovery (RFC-0022 E4): Kiro custom agents do NOT inherit the default
405
+ # agent's auto-discovery of `.kiro/skills` (kiro #6887/#6888), so a headless
406
+ # `--agent` run sees zero skills unless the agent declares them. Inject this
407
+ # fixed skill-resources glob (both install scopes) into every projected agent.
408
+ # Skipped when the agent source already declares its own `resources` (author
409
+ # override wins). kiro-ide carries the same field on its own agent projection
410
+ # entry (emitted into `.md` frontmatter rather than JSON).
411
+ inject-resources = ["skill://.kiro/skills/**/SKILL.md", "skill://~/.kiro/skills/**/SKILL.md"]
391
412
  on-conflict = "prompt-then-preserve"
392
413
 
393
414
  [[adapter.kiro-cli.projection]]
@@ -0,0 +1,21 @@
1
+ {
2
+ "type": "object",
3
+ "required": ["scope", "description", "packs"],
4
+ "additionalProperties": false,
5
+ "properties": {
6
+ "scope": {"enum": ["repo", "user"]},
7
+ "description": {"type": "string"},
8
+ "packs": {
9
+ "type": "array",
10
+ "minItems": 1,
11
+ "items": {
12
+ "type": "object",
13
+ "required": ["pack"],
14
+ "additionalProperties": false,
15
+ "properties": {
16
+ "pack": {"type": "string"}
17
+ }
18
+ }
19
+ }
20
+ }
21
+ }
@@ -284,6 +284,16 @@ def _project_agent_as_json(
284
284
  prompt = body.rstrip("\n")
285
285
  if prompt:
286
286
  agent_json["prompt"] = prompt
287
+ # Skill-resources injection (RFC-0022 E4). The agent projection
288
+ # declares `inject-resources` so custom agents reach the bundle's
289
+ # skills — Kiro custom agents don't inherit the default agent's
290
+ # `.kiro/skills` auto-discovery (kiro #6887/#6888). Author-declared
291
+ # `resources` win: only inject when the agent set none. This function
292
+ # handles the CLI (JSON) path; kiro-ide injects the same field in its
293
+ # own `.md` projector (`_project_agent_as_md`).
294
+ inject_resources = rule.get("inject-resources")
295
+ if inject_resources and "resources" not in agent_json:
296
+ agent_json["resources"] = list(inject_resources)
287
297
  destination = target_dir / (entry.stem + ".json")
288
298
  destination.write_text(
289
299
  json.dumps(agent_json, indent=2, sort_keys=False) + "\n",
@@ -244,6 +244,15 @@ def _project_agent_as_md(
244
244
  agent_name = rewritten.get("name") or entry.stem
245
245
  rewritten["name"] = agent_name
246
246
 
247
+ # Skill-resources injection (RFC-0022 E4). Same gap as kiro-cli: IDE
248
+ # custom agents don't inherit the default agent's `.kiro/skills`
249
+ # auto-discovery, so inject the declared glob unless the agent set its
250
+ # own `resources` (author override wins). `resources` is a documented
251
+ # IDE agent field, so it does not trip the silent-drop bug.
252
+ inject_resources = rule.get("inject-resources")
253
+ if inject_resources and "resources" not in rewritten:
254
+ rewritten["resources"] = list(inject_resources)
255
+
247
256
  output_text = _serialize_frontmatter_md(rewritten) + body
248
257
  destination = target_dir / entry.name # preserves .md extension
249
258
  destination.write_text(output_text, encoding="utf-8")
@@ -260,16 +269,24 @@ def _serialize_frontmatter_md(fields: dict[str, Any]) -> str:
260
269
  lines = ["---"]
261
270
  for key, value in fields.items():
262
271
  if isinstance(value, list):
263
- items = ", ".join(str(v) for v in value)
272
+ # Flow sequence. Simple tokens (tool ids like `read_file`) stay
273
+ # unquoted; items with YAML-special chars (e.g. `skill://` URIs
274
+ # with `**` globs) are quoted so the IDE's parser can't misread them.
275
+ items = ", ".join(_yaml_scalar(str(v)) for v in value)
264
276
  lines.append(f"{key}: [{items}]")
265
277
  elif isinstance(value, str):
266
- # Quote strings that contain YAML-special characters.
267
- if any(c in value for c in ':#{}[]|>&*!,\'"'):
268
- escaped = value.replace("\\", "\\\\").replace('"', '\\"')
269
- lines.append(f'{key}: "{escaped}"')
270
- else:
271
- lines.append(f"{key}: {value}")
278
+ lines.append(f"{key}: {_yaml_scalar(value)}")
272
279
  else:
273
280
  lines.append(f"{key}: {value}")
274
281
  lines.append("---")
275
282
  return "\n".join(lines) + "\n"
283
+
284
+
285
+ def _yaml_scalar(value: str) -> str:
286
+ """Render a string as a YAML scalar, double-quoting when it contains a
287
+ YAML-special character (else a plain scalar). Used for both top-level
288
+ values and items inside a `[...]` flow sequence."""
289
+ if any(c in value for c in ':#{}[]|>&*!,\'"'):
290
+ escaped = value.replace("\\", "\\\\").replace('"', '\\"')
291
+ return f'"{escaped}"'
292
+ return value
@@ -299,6 +299,16 @@ def run_all(
299
299
  # ---------------------------------------------------------------------------
300
300
 
301
301
 
302
+ # Adapters whose hook-wiring projects via `merge-into-agent-json` (a
303
+ # pack-owned `.kiro/agents/<attach-to-agent>.json`): the legacy `kiro`
304
+ # block and the `kiro-cli` adapter. The `attach-to-agent` rails below
305
+ # validate that merge target, so they fire for this family. `kiro-ide`
306
+ # (and the `kiro` *install alias*, which routes to kiro-ide) DROPS
307
+ # hook-wiring and is intentionally absent — there is no merge target to
308
+ # validate. Mirrors install.py's merge dispatch.
309
+ _MERGE_INTO_AGENT_JSON_ADAPTERS = frozenset({"kiro", "kiro-cli"})
310
+
311
+
302
312
  def check_kiro_attach_to_agent(
303
313
  pack_name: str,
304
314
  wiring_tomls: dict[str, dict],
@@ -325,7 +335,7 @@ def check_kiro_attach_to_agent(
325
335
  target_adapters: iterable of adapter names the pack is being
326
336
  validated against. No-op when ``kiro`` is absent.
327
337
  """
328
- if "kiro" not in set(target_adapters or ()):
338
+ if not (set(target_adapters or ()) & _MERGE_INTO_AGENT_JSON_ADAPTERS):
329
339
  return None
330
340
  for wiring_name, body in wiring_tomls.items():
331
341
  attach = body.get("attach-to-agent") if isinstance(body, dict) else None
@@ -485,7 +495,7 @@ def check_kiro_wiring(
485
495
  would let a pack reach outside its source tree. A wiring TOML that
486
496
  fails to parse counts as a refusal on its own.
487
497
  """
488
- if "kiro" not in set(target_adapters or ()):
498
+ if not (set(target_adapters or ()) & _MERGE_INTO_AGENT_JSON_ADAPTERS):
489
499
  return None
490
500
 
491
501
  loaded = _load_pack_hook_wiring_safely(pack_path, pack_name)
@@ -53,9 +53,10 @@ class CursorContractTests(unittest.TestCase):
53
53
  def test_contract_version_is_0_11(self) -> None:
54
54
  """AC1 — contract bumped to 0.11 by cursor-full-parity; subsequently
55
55
  0.12 (copilot-skills-and-web), 0.13 (docs/specs/gemini-full-parity),
56
- then 0.14 (docs/specs/enriched-pack-manifest).
56
+ 0.14 (docs/specs/enriched-pack-manifest), then 0.15
57
+ (docs/specs/kiro-cli-agent-skill-resources).
57
58
  Name preserved to keep the diff small."""
58
- self.assertEqual(self.contract["contract"]["version"], "0.14")
59
+ self.assertEqual(self.contract["contract"]["version"], "0.15")
59
60
 
60
61
  def test_cursor_block_projects_five_primitives(self) -> None:
61
62
  """AC2 — the five standard primitives are in the projection array."""
@@ -151,9 +151,9 @@ class GeminiContractTests(unittest.TestCase):
151
151
  cls.contract = load_contract(CONTRACT_PATH)
152
152
 
153
153
  def test_contract_version_is_0_14(self) -> None:
154
- """Contract version is 0.14 (docs/specs/enriched-pack-manifest bumped it
155
- from gemini-full-parity's 0.13). Renamed from the 0_13 method."""
156
- self.assertEqual(self.contract["contract"]["version"], "0.14")
154
+ """Contract version is 0.15 (docs/specs/kiro-cli-agent-skill-resources
155
+ bumped it from enriched-pack-manifest's 0.14). Name preserved."""
156
+ self.assertEqual(self.contract["contract"]["version"], "0.15")
157
157
 
158
158
  def test_gemini_block_projects_five_primitives(self) -> None:
159
159
  """AC2 — five standard primitives with their gemini targets."""
@@ -79,6 +79,45 @@ class KiroCliAdapterTests(unittest.TestCase):
79
79
  self.assertNotIn("grep_search", tools)
80
80
  self.assertNotIn("execute_bash", tools)
81
81
 
82
+ def test_cli_agent_gets_skill_resources(self) -> None:
83
+ """kiro-cli custom agents must declare the skill-resources glob so
84
+ they reach the bundle's skills — Kiro custom agents don't inherit the
85
+ default agent's auto-discovery (RFC-0022 E4; kiro #6887/#6888)."""
86
+ with tempfile.TemporaryDirectory() as tmp:
87
+ tmp_path = Path(tmp)
88
+ pack = _seed_agent_pack(tmp_path)
89
+ out = tmp_path / "out"
90
+ project(pack, self.contract, out)
91
+ data = json.loads(
92
+ (out / ".kiro" / "agents" / "bar.json").read_text(encoding="utf-8")
93
+ )
94
+ self.assertEqual(
95
+ data.get("resources"),
96
+ [
97
+ "skill://.kiro/skills/**/SKILL.md",
98
+ "skill://~/.kiro/skills/**/SKILL.md",
99
+ ],
100
+ "kiro-cli agent JSON must inject both repo- and user-scope skill globs",
101
+ )
102
+
103
+ def test_cli_agent_resources_author_override_wins(self) -> None:
104
+ """An agent that declares its own `resources` keeps it — the default
105
+ does not clobber an author-supplied value."""
106
+ with tempfile.TemporaryDirectory() as tmp:
107
+ tmp_path = Path(tmp)
108
+ pack = tmp_path / "pack"
109
+ (pack / ".apm" / "agents").mkdir(parents=True)
110
+ (pack / ".apm" / "agents" / "bar.md").write_text(
111
+ "---\nname: bar\nresources: [file://README.md]\n---\nbody\n",
112
+ encoding="utf-8",
113
+ )
114
+ out = tmp_path / "out"
115
+ project(pack, self.contract, out)
116
+ data = json.loads(
117
+ (out / ".kiro" / "agents" / "bar.json").read_text(encoding="utf-8")
118
+ )
119
+ self.assertEqual(data.get("resources"), ["file://README.md"])
120
+
82
121
  def test_cli_no_ide_hook_field(self) -> None:
83
122
  """kiro-cli projected agent JSON must not contain ide-event-vocabulary
84
123
  or kiro-ide-hook sections — those are IDE-only fields that cause the
@@ -63,6 +63,44 @@ class KiroIdeAdapterTests(unittest.TestCase):
63
63
  for cli_only in ("hooks", "allowedTools", "toolsSettings", "mcpServers"):
64
64
  self.assertNotIn(cli_only, raw, f"kiro-ide agent .md must not contain {cli_only!r}")
65
65
 
66
+ def test_kiro_ide_gets_skill_resources(self) -> None:
67
+ """kiro-ide custom agents (and IDE subagents) must declare the
68
+ skill-resources glob so they reach skills — IDE custom agents don't
69
+ inherit the default agent's auto-discovery either (RFC-0022 E4)."""
70
+ with tempfile.TemporaryDirectory() as tmp:
71
+ tmp_path = Path(tmp)
72
+ pack = _seed_agent_pack(tmp_path)
73
+ out = tmp_path / "out"
74
+ project(pack, self.contract, out)
75
+ raw = (out / ".kiro" / "agents" / "bar.md").read_text(encoding="utf-8")
76
+ # Assert the exact emitted line: a flow sequence of DOUBLE-QUOTED
77
+ # scalars. Quoting makes the `skill://` URIs / `**` globs
78
+ # unambiguous YAML, guarding the IDE's fail-silent frontmatter
79
+ # parser (kiro #8329). The bytes were confirmed to round-trip
80
+ # through PyYAML to the two-element list during verification; this
81
+ # gate is exact-string (the build tree is stdlib-only — no yaml).
82
+ self.assertIn(
83
+ 'resources: ["skill://.kiro/skills/**/SKILL.md", '
84
+ '"skill://~/.kiro/skills/**/SKILL.md"]',
85
+ raw,
86
+ )
87
+
88
+ def test_kiro_ide_resources_author_override_wins(self) -> None:
89
+ """An IDE agent that declares its own `resources` keeps it."""
90
+ with tempfile.TemporaryDirectory() as tmp:
91
+ tmp_path = Path(tmp)
92
+ pack = tmp_path / "pack"
93
+ (pack / ".apm" / "agents").mkdir(parents=True)
94
+ (pack / ".apm" / "agents" / "bar.md").write_text(
95
+ "---\nname: bar\nresources: [file://README.md]\n---\nbody\n",
96
+ encoding="utf-8",
97
+ )
98
+ out = tmp_path / "out"
99
+ project(pack, self.contract, out)
100
+ raw = (out / ".kiro" / "agents" / "bar.md").read_text(encoding="utf-8")
101
+ self.assertIn("file://README.md", raw)
102
+ self.assertNotIn("skill://", raw)
103
+
66
104
  def test_kiro_ide_tools_use_ide_ids(self) -> None:
67
105
  """kiro-ide uses IDE tool ids (read_file, grep_search) not CLI short-names."""
68
106
  with tempfile.TemporaryDirectory() as tmp:
@@ -134,13 +172,13 @@ class KiroIdeAdapterTests(unittest.TestCase):
134
172
  self.assertIn(".kiro.hook", target_repo)
135
173
 
136
174
  def test_contract_version_is_0_9(self) -> None:
137
- """Contract version is 0.14 (docs/specs/enriched-pack-manifest, atop
138
- gemini-full-parity's 0.13 and copilot-skills-and-web's 0.12).
175
+ """Contract version is 0.15 (docs/specs/kiro-cli-agent-skill-resources,
176
+ atop enriched-pack-manifest's 0.14 and gemini-full-parity's 0.13).
139
177
  Name preserved to keep the diff small."""
140
178
  self.assertEqual(
141
179
  self.contract["contract"]["version"],
142
- "0.14",
143
- "adapter.toml [contract] version must be '0.14' after enriched-pack-manifest",
180
+ "0.15",
181
+ "adapter.toml [contract] version must be '0.15' after kiro-cli-agent-skill-resources",
144
182
  )
145
183
 
146
184
  def test_kiro_ide_hook_projects_with_flat_prefix_path(self) -> None:
@@ -452,17 +452,16 @@ class ContractV05Tests(unittest.TestCase):
452
452
  self.schema = _load_schema()
453
453
 
454
454
  def test_contract_version_is_v05(self) -> None:
455
- """tomllib.loads of adapter.toml returns contract.version == "0.14"
456
- (bumped from gemini-full-parity's "0.13" by
457
- docs/specs/enriched-pack-manifest: pack.toml becomes the rich metadata
458
- source of truth and the build projects the projectable subset + READMEs
459
- into the claude-plugins + apm routes). Class/method names preserved to
460
- avoid churn.
455
+ """tomllib.loads of adapter.toml returns contract.version == "0.15"
456
+ (bumped from enriched-pack-manifest's "0.14" by
457
+ docs/specs/kiro-cli-agent-skill-resources: kiro-cli agents inject a
458
+ skill-resources glob so headless `--agent` runs reach skills).
459
+ Class/method names preserved to avoid churn.
461
460
  """
462
461
  self.assertEqual(
463
462
  self.contract["contract"]["version"],
464
- "0.14",
465
- "adapter.toml [contract] version must be '0.14' after enriched-pack-manifest",
463
+ "0.15",
464
+ "adapter.toml [contract] version must be '0.15' after kiro-cli-agent-skill-resources",
466
465
  )
467
466
 
468
467
  def test_claude_code_install_routes_includes_apm(self) -> None:
@@ -1,9 +1,11 @@
1
1
  """`agentbundle` CLI dispatcher — argparse over the eleven F-cli subcommands.
2
2
 
3
3
  Subcommand order on the parser matches the canonical install-workflow order
4
- from the spec (discovery-first): `list-packs`, `list-targets`, `scaffold`,
5
- `install`, `validate`, `render`, `adapt`, `diff`, `upgrade`, `uninstall`,
6
- `init-state`.
4
+ from the spec (discovery-first): `list-packs`, `list-profiles`, `list-targets`,
5
+ `scaffold`, `install`, `validate`, `render`, `adapt`, `diff`, `upgrade`,
6
+ `uninstall`, `init-state`, `config`, `reconcile`. `list-profiles` (RFC-0034)
7
+ lists the catalogue's curated single-scope install profiles; `install
8
+ --profile <name>` installs one.
7
9
 
8
10
  Each subcommand's `run(args) -> int` lives under `agentbundle.commands.*`;
9
11
  this module wires `argparse` and prints `--version`. No business logic here.
@@ -192,6 +194,14 @@ def _build_parser() -> argparse.ArgumentParser:
192
194
  sp.add_argument("catalogue", help="Catalogue URI (local path or git+https://...).")
193
195
  sp.set_defaults(func=_lazy("list_packs"))
194
196
 
197
+ # --- list-profiles --- (catalogue query; profiles declare their own scope)
198
+ sp = subparsers.add_parser(
199
+ "list-profiles",
200
+ help="List curated install profiles available in a catalogue URI.",
201
+ )
202
+ sp.add_argument("catalogue", help="Catalogue URI (local path or git+https://...).")
203
+ sp.set_defaults(func=_lazy("list_profiles"))
204
+
195
205
  # --- list-targets --- (--scope as read-only filter)
196
206
  sp = subparsers.add_parser(
197
207
  "list-targets",
@@ -215,7 +225,23 @@ def _build_parser() -> argparse.ArgumentParser:
215
225
  "install",
216
226
  help="Install a pack from a catalogue URI into the adopter repo.",
217
227
  )
218
- sp.add_argument("--pack", required=True)
228
+ # pack-profiles: `--pack` and `--profile` are a required mutually-exclusive
229
+ # group. `--pack` was a bare `required=True` arg; making it a member of a
230
+ # required mutex group keeps "exactly one of pack/profile" without losing
231
+ # the requiredness. `--scope` with `--profile` is rejected at the handler
232
+ # (a profile declares its own scope); argparse can't express that mutex
233
+ # because `--scope` is valid alongside `--pack`.
234
+ _pack_or_profile = sp.add_mutually_exclusive_group(required=True)
235
+ _pack_or_profile.add_argument("--pack")
236
+ _pack_or_profile.add_argument(
237
+ "--profile",
238
+ help=(
239
+ "Install a curated single-scope set of packs from "
240
+ "<catalogue>/profiles/<name>.toml in one command (RFC-0034). "
241
+ "Mutually exclusive with --pack; --scope is not allowed (the "
242
+ "profile declares its own scope)."
243
+ ),
244
+ )
219
245
  sp.add_argument("catalogue", help="Catalogue URI (local path or git+https://...).")
220
246
  sp.add_argument("--output", default=".")
221
247
  sp.add_argument("--scope", choices=("repo", "user"))