agentbundle 0.6.0__tar.gz → 0.7.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.
- {agentbundle-0.6.0 → agentbundle-0.7.0}/PKG-INFO +32 -18
- {agentbundle-0.6.0 → agentbundle-0.7.0}/README.md +31 -17
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/_data/adapter.toml +8 -1
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/_data/pack.schema.json +19 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_adapter_cursor.py +4 -3
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_adapter_gemini.py +3 -3
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_adapter_kiro_ide.py +4 -4
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_contract.py +7 -7
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_pack_schema.py +79 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/cli.py +57 -14
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/_common.py +48 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/install.py +290 -8
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/reconcile.py +5 -12
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/uninstall.py +80 -13
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/upgrade.py +95 -6
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/version.py +1 -1
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle.egg-info/PKG-INFO +32 -18
- {agentbundle-0.6.0 → agentbundle-0.7.0}/pyproject.toml +1 -1
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/__init__.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/__main__.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/_data/adapter.schema.json +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/_data/install-marker.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/_data/plugin-manifest.derived.schema.json +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/_data/plugin-manifest.schema.json +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/_data/profile.schema.json +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/__init__.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/__main__.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/adapter_root_bins.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/adapters/__init__.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/adapters/claude_code.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/adapters/codex.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/adapters/copilot.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/adapters/cursor.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/adapters/gemini.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/adapters/kiro.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/adapters/kiro_cli.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/adapters/kiro_ide.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/contract.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/lint_packs.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/main.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/phase_order.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/projections/__init__.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/projections/codex_agent_toml.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/projections/copilot_agent_md.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/projections/copilot_hooks_json.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/projections/direct_directory.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/projections/gemini_command_toml.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/projections/hook_id.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/projections/kiro_ide_hook.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/projections/merge_into_agent_json.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/projections/merge_json.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/projections/user_merge_json.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/scope_rails.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/self_host.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/shared_libs.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/target_resolver.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/__init__.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_adapter_claude_code.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_adapter_codex.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_adapter_copilot.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_adapter_kiro.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_adapter_kiro_alias.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_adapter_kiro_cli.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_adapter_root_bins_projection.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_architect_design_reviewer_projection.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_architect_design_reviewer_rubric_parity.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_build_ships_seeds.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_contract_scope.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_contract_v07.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_contract_v08.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_direct_directory_cleanup.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_end_to_end_build.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_lint_agents_md_diataxis_block.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_lint_agents_md_legacy_block.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_lint_agents_md_risk_block.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_lint_packs.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_load_pack_hook_wiring_safely.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_pack_schema_allowed_adapters.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_pack_schema_install.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_pipeline.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_plugin_manifest_schema.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_projectable_subset.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_projections_merge_json.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_scope_rails.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_security.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_self_host_check.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_shared_libs_projection.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_shipped_packs_v07_declarations.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_shipped_packs_v08_declarations.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_user_libs_projection.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/tests/test_validate.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/user_libs.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/build/validate.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/catalogue.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/categories.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/__init__.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/_drop_warning.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/adapt.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/config.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/diff.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/init_state.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/list_packs.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/list_profiles.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/list_targets.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/profile.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/render.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/scaffold.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/commands/validate.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/config.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/render.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/safety.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/scope.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle/user_config.py +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle.egg-info/SOURCES.txt +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle.egg-info/dependency_links.txt +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle.egg-info/entry_points.txt +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/agentbundle.egg-info/top_level.txt +0 -0
- {agentbundle-0.6.0 → agentbundle-0.7.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: agentbundle
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.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
|
|
@@ -22,43 +22,57 @@ Description-Content-Type: text/markdown
|
|
|
22
22
|
[](https://pypi.org/project/agentbundle/)
|
|
23
23
|
[](https://github.com/eugenelim/agent-ready-repo#license)
|
|
24
24
|
|
|
25
|
-
**The installer for [agent-ready-repo](https://github.com/eugenelim/agent-ready-repo).** Think npm, but for the skills, subagents, and hooks your coding agent runs on.
|
|
25
|
+
**The installer for [agent-ready-repo](https://github.com/eugenelim/agent-ready-repo).** Think npm, but for the skills, subagents, and hooks your coding agent runs on. One pack, one command, every major agent — Claude Code, Codex, Cursor, Copilot, Gemini, and Kiro (both the CLI and the IDE).
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
## Quick start
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
pip install agentbundle
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Install into a repo** — so everyone who clones it gets the pack. `core` is the flagship pack, the loop itself:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
31
36
|
agentbundle install --pack core git+https://github.com/eugenelim/agent-ready-repo
|
|
32
37
|
```
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
It lands in the repo's agent config — subagents and skills included — and you commit it like any other project file. This is the default scope: the pack belongs to the project and the whole team.
|
|
35
40
|
|
|
36
|
-
|
|
41
|
+
**Install for yourself, everywhere** — so a pack follows you across every project, with no per-repo setup:
|
|
37
42
|
|
|
38
43
|
```bash
|
|
39
|
-
|
|
40
|
-
|
|
44
|
+
agentbundle install --pack research git+https://github.com/eugenelim/agent-ready-repo --scope user
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
User-scope packs land in your home directory, not the repo — they're yours, not the team's, and they're there in every project you open.
|
|
48
|
+
|
|
49
|
+
A catalogue is a git URL or a local path, and the install auto-detects your agent (`--adapter` overrides).
|
|
41
50
|
|
|
42
|
-
|
|
51
|
+
## More commands
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# See what a catalogue offers
|
|
55
|
+
agentbundle list-packs git+https://github.com/eugenelim/agent-ready-repo
|
|
43
56
|
agentbundle list-profiles git+https://github.com/eugenelim/agent-ready-repo
|
|
44
57
|
|
|
45
58
|
# Install a whole curated profile — a single-scope set of packs — in one command
|
|
46
59
|
agentbundle install --profile inception git+https://github.com/eugenelim/agent-ready-repo
|
|
47
60
|
|
|
48
|
-
#
|
|
49
|
-
agentbundle install --pack core git+https://github.com/eugenelim/agent-ready-repo
|
|
50
|
-
|
|
51
|
-
# Install a pack at user scope, so it follows you across every project
|
|
52
|
-
agentbundle install --pack research git+https://github.com/eugenelim/agent-ready-repo --scope user
|
|
53
|
-
|
|
54
|
-
# Preview an install without writing a file
|
|
61
|
+
# Preview any install without writing a file
|
|
55
62
|
agentbundle install --pack core git+https://github.com/eugenelim/agent-ready-repo --dry-run
|
|
56
63
|
|
|
57
|
-
# Upgrade
|
|
58
|
-
agentbundle upgrade --pack core
|
|
64
|
+
# Upgrade to the version the catalogue ships — shows installed → target, asks first
|
|
65
|
+
agentbundle upgrade --pack core git+https://github.com/eugenelim/agent-ready-repo
|
|
66
|
+
agentbundle upgrade --pack core git+https://github.com/eugenelim/agent-ready-repo --yes # skip the prompt (CI)
|
|
67
|
+
|
|
68
|
+
# Uninstall — previews remove (Tier-1) vs keep (your edits), asks first
|
|
69
|
+
agentbundle uninstall --pack core --dry-run
|
|
70
|
+
agentbundle uninstall --pack core --yes
|
|
59
71
|
```
|
|
60
72
|
|
|
61
|
-
A
|
|
73
|
+
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. **Upgrade takes no version** — the target is whatever the catalogue you point at declares; to pin a past version, point the catalogue at that git ref. Install a pack that's **already there** and `agentbundle` offers to `upgrade` it instead (`--yes` runs it straight away).
|
|
74
|
+
|
|
75
|
+
**Mutating commands ask first.** `uninstall`, the `--force` cleanup, and the upgrade offer all preview what they'll do and confirm before touching anything; `--dry-run` previews without writing, and `--yes` skips the prompt for non-interactive / CI use (where, without it, they refuse rather than hang).
|
|
62
76
|
|
|
63
77
|
## Build your own catalogue
|
|
64
78
|
|
|
@@ -4,43 +4,57 @@
|
|
|
4
4
|
[](https://pypi.org/project/agentbundle/)
|
|
5
5
|
[](https://github.com/eugenelim/agent-ready-repo#license)
|
|
6
6
|
|
|
7
|
-
**The installer for [agent-ready-repo](https://github.com/eugenelim/agent-ready-repo).** Think npm, but for the skills, subagents, and hooks your coding agent runs on.
|
|
7
|
+
**The installer for [agent-ready-repo](https://github.com/eugenelim/agent-ready-repo).** Think npm, but for the skills, subagents, and hooks your coding agent runs on. One pack, one command, every major agent — Claude Code, Codex, Cursor, Copilot, Gemini, and Kiro (both the CLI and the IDE).
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Quick start
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
pip install agentbundle
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Install into a repo** — so everyone who clones it gets the pack. `core` is the flagship pack, the loop itself:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
13
18
|
agentbundle install --pack core git+https://github.com/eugenelim/agent-ready-repo
|
|
14
19
|
```
|
|
15
20
|
|
|
16
|
-
|
|
21
|
+
It lands in the repo's agent config — subagents and skills included — and you commit it like any other project file. This is the default scope: the pack belongs to the project and the whole team.
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
**Install for yourself, everywhere** — so a pack follows you across every project, with no per-repo setup:
|
|
19
24
|
|
|
20
25
|
```bash
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
agentbundle install --pack research git+https://github.com/eugenelim/agent-ready-repo --scope user
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
User-scope packs land in your home directory, not the repo — they're yours, not the team's, and they're there in every project you open.
|
|
30
|
+
|
|
31
|
+
A catalogue is a git URL or a local path, and the install auto-detects your agent (`--adapter` overrides).
|
|
23
32
|
|
|
24
|
-
|
|
33
|
+
## More commands
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# See what a catalogue offers
|
|
37
|
+
agentbundle list-packs git+https://github.com/eugenelim/agent-ready-repo
|
|
25
38
|
agentbundle list-profiles git+https://github.com/eugenelim/agent-ready-repo
|
|
26
39
|
|
|
27
40
|
# Install a whole curated profile — a single-scope set of packs — in one command
|
|
28
41
|
agentbundle install --profile inception git+https://github.com/eugenelim/agent-ready-repo
|
|
29
42
|
|
|
30
|
-
#
|
|
31
|
-
agentbundle install --pack core git+https://github.com/eugenelim/agent-ready-repo
|
|
32
|
-
|
|
33
|
-
# Install a pack at user scope, so it follows you across every project
|
|
34
|
-
agentbundle install --pack research git+https://github.com/eugenelim/agent-ready-repo --scope user
|
|
35
|
-
|
|
36
|
-
# Preview an install without writing a file
|
|
43
|
+
# Preview any install without writing a file
|
|
37
44
|
agentbundle install --pack core git+https://github.com/eugenelim/agent-ready-repo --dry-run
|
|
38
45
|
|
|
39
|
-
# Upgrade
|
|
40
|
-
agentbundle upgrade --pack core
|
|
46
|
+
# Upgrade to the version the catalogue ships — shows installed → target, asks first
|
|
47
|
+
agentbundle upgrade --pack core git+https://github.com/eugenelim/agent-ready-repo
|
|
48
|
+
agentbundle upgrade --pack core git+https://github.com/eugenelim/agent-ready-repo --yes # skip the prompt (CI)
|
|
49
|
+
|
|
50
|
+
# Uninstall — previews remove (Tier-1) vs keep (your edits), asks first
|
|
51
|
+
agentbundle uninstall --pack core --dry-run
|
|
52
|
+
agentbundle uninstall --pack core --yes
|
|
41
53
|
```
|
|
42
54
|
|
|
43
|
-
A
|
|
55
|
+
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. **Upgrade takes no version** — the target is whatever the catalogue you point at declares; to pin a past version, point the catalogue at that git ref. Install a pack that's **already there** and `agentbundle` offers to `upgrade` it instead (`--yes` runs it straight away).
|
|
56
|
+
|
|
57
|
+
**Mutating commands ask first.** `uninstall`, the `--force` cleanup, and the upgrade offer all preview what they'll do and confirm before touching anything; `--dry-run` previews without writing, and `--yes` skips the prompt for non-interactive / CI use (where, without it, they refuse rather than hang).
|
|
44
58
|
|
|
45
59
|
## Build your own catalogue
|
|
46
60
|
|
|
@@ -77,7 +77,14 @@
|
|
|
77
77
|
# the default agent's `.kiro/skills` auto-discovery (RFC-0022 E4; kiro
|
|
78
78
|
# #6887/#6888/#4993). Additive `inject-resources` on BOTH the kiro-cli and
|
|
79
79
|
# kiro-ide agent projections (CLI → agent JSON, IDE → quoted .md frontmatter).
|
|
80
|
-
|
|
80
|
+
# RFC-0040 / ADR-0030 / docs/specs/consolidated-pack-layout (v0.16): pack.toml
|
|
81
|
+
# gains an optional scope-keyed [pack.layout] table (optional .repo / .user
|
|
82
|
+
# sub-tables, each a `parent` base and/or a within-pack template-path) naming
|
|
83
|
+
# where a consuming pack's durable output lands. Consumed by the new installer
|
|
84
|
+
# `_append_layout_section` step (append-if-exists / never-create / never-
|
|
85
|
+
# overwrite) into an adopter-owned `agentbundle-layout.toml`. Additive +
|
|
86
|
+
# optional — packs pinned below v0.16 build and validate unchanged.
|
|
87
|
+
version = "0.16"
|
|
81
88
|
|
|
82
89
|
# Sibling schemas this contract references — pack metadata and the
|
|
83
90
|
# per-pack Claude-plugin manifest. Defined by spec AC #3 + #4.
|
|
@@ -131,6 +131,25 @@
|
|
|
131
131
|
"type": "string",
|
|
132
132
|
"pattern": "^[^/].*"
|
|
133
133
|
}
|
|
134
|
+
},
|
|
135
|
+
"layout": {
|
|
136
|
+
"type": "object",
|
|
137
|
+
"properties": {
|
|
138
|
+
"repo": {
|
|
139
|
+
"type": "object",
|
|
140
|
+
"properties": {
|
|
141
|
+
"parent": {"type": "string"},
|
|
142
|
+
"template": {"type": "string"}
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"user": {
|
|
146
|
+
"type": "object",
|
|
147
|
+
"properties": {
|
|
148
|
+
"parent": {"type": "string"},
|
|
149
|
+
"template": {"type": "string"}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
134
153
|
}
|
|
135
154
|
},
|
|
136
155
|
"if": {
|
|
@@ -53,10 +53,11 @@ 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
|
-
0.14 (docs/specs/enriched-pack-manifest),
|
|
57
|
-
(docs/specs/kiro-cli-agent-skill-resources).
|
|
56
|
+
0.14 (docs/specs/enriched-pack-manifest), 0.15
|
|
57
|
+
(docs/specs/kiro-cli-agent-skill-resources), then 0.16
|
|
58
|
+
(docs/specs/consolidated-pack-layout).
|
|
58
59
|
Name preserved to keep the diff small."""
|
|
59
|
-
self.assertEqual(self.contract["contract"]["version"], "0.
|
|
60
|
+
self.assertEqual(self.contract["contract"]["version"], "0.16")
|
|
60
61
|
|
|
61
62
|
def test_cursor_block_projects_five_primitives(self) -> None:
|
|
62
63
|
"""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.
|
|
155
|
-
bumped it from
|
|
156
|
-
self.assertEqual(self.contract["contract"]["version"], "0.
|
|
154
|
+
"""Contract version is 0.16 (docs/specs/consolidated-pack-layout
|
|
155
|
+
bumped it from kiro-cli-agent-skill-resources' 0.15). Name preserved."""
|
|
156
|
+
self.assertEqual(self.contract["contract"]["version"], "0.16")
|
|
157
157
|
|
|
158
158
|
def test_gemini_block_projects_five_primitives(self) -> None:
|
|
159
159
|
"""AC2 — five standard primitives with their gemini targets."""
|
|
@@ -172,13 +172,13 @@ class KiroIdeAdapterTests(unittest.TestCase):
|
|
|
172
172
|
self.assertIn(".kiro.hook", target_repo)
|
|
173
173
|
|
|
174
174
|
def test_contract_version_is_0_9(self) -> None:
|
|
175
|
-
"""Contract version is 0.
|
|
176
|
-
atop
|
|
175
|
+
"""Contract version is 0.16 (docs/specs/consolidated-pack-layout,
|
|
176
|
+
atop kiro-cli-agent-skill-resources' 0.15 and enriched-pack-manifest's 0.14).
|
|
177
177
|
Name preserved to keep the diff small."""
|
|
178
178
|
self.assertEqual(
|
|
179
179
|
self.contract["contract"]["version"],
|
|
180
|
-
"0.
|
|
181
|
-
"adapter.toml [contract] version must be '0.
|
|
180
|
+
"0.16",
|
|
181
|
+
"adapter.toml [contract] version must be '0.16' after consolidated-pack-layout",
|
|
182
182
|
)
|
|
183
183
|
|
|
184
184
|
def test_kiro_ide_hook_projects_with_flat_prefix_path(self) -> None:
|
|
@@ -452,16 +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.
|
|
456
|
-
(bumped from
|
|
457
|
-
docs/specs/
|
|
458
|
-
|
|
459
|
-
|
|
455
|
+
"""tomllib.loads of adapter.toml returns contract.version == "0.16"
|
|
456
|
+
(bumped from kiro-cli-agent-skill-resources' "0.15" by
|
|
457
|
+
docs/specs/consolidated-pack-layout: pack.toml gains an optional
|
|
458
|
+
scope-keyed [pack.layout] table). Class/method names preserved to
|
|
459
|
+
avoid churn.
|
|
460
460
|
"""
|
|
461
461
|
self.assertEqual(
|
|
462
462
|
self.contract["contract"]["version"],
|
|
463
|
-
"0.
|
|
464
|
-
"adapter.toml [contract] version must be '0.
|
|
463
|
+
"0.16",
|
|
464
|
+
"adapter.toml [contract] version must be '0.16' after consolidated-pack-layout",
|
|
465
465
|
)
|
|
466
466
|
|
|
467
467
|
def test_claude_code_install_routes_includes_apm(self) -> None:
|
|
@@ -399,6 +399,85 @@ description = "Core skills."
|
|
|
399
399
|
self.assertEqual(errors, [], "\n".join(errors))
|
|
400
400
|
|
|
401
401
|
|
|
402
|
+
class PackSchemaLayoutTests(unittest.TestCase):
|
|
403
|
+
"""consolidated-pack-layout T1: optional scope-keyed [pack.layout] table.
|
|
404
|
+
|
|
405
|
+
pack.schema.json gains an optional `[pack.layout]` table with optional
|
|
406
|
+
`.repo` / `.user` sub-tables, each carrying a `parent` base and/or a
|
|
407
|
+
within-pack `template` path. Every field is optional and the change is
|
|
408
|
+
additive — a manifest omitting it must still validate (legacy invariance),
|
|
409
|
+
and a pack may declare only `.repo` (the three current consumers do, since
|
|
410
|
+
their output is per-repo and they have no sensible absolute user default).
|
|
411
|
+
"""
|
|
412
|
+
|
|
413
|
+
def test_accepts_layout_with_repo_and_user(self) -> None:
|
|
414
|
+
"""A manifest carrying [pack.layout.repo] and [pack.layout.user] validates."""
|
|
415
|
+
from agentbundle.build.validate import validate
|
|
416
|
+
|
|
417
|
+
schema = _load_schema()
|
|
418
|
+
toml_text = """
|
|
419
|
+
[pack]
|
|
420
|
+
name = "research"
|
|
421
|
+
version = "0.5.0"
|
|
422
|
+
|
|
423
|
+
[pack.layout.repo]
|
|
424
|
+
parent = ".context/research"
|
|
425
|
+
|
|
426
|
+
[pack.layout.user]
|
|
427
|
+
parent = "~/research-projects"
|
|
428
|
+
template = "references/agentbundle-layout.toml"
|
|
429
|
+
"""
|
|
430
|
+
instance = _parse_toml(toml_text)
|
|
431
|
+
errors = validate(instance, schema)
|
|
432
|
+
self.assertEqual(errors, [], "\n".join(errors))
|
|
433
|
+
|
|
434
|
+
def test_accepts_layout_repo_only(self) -> None:
|
|
435
|
+
"""A pack may declare only [pack.layout.repo] — the consumer shape."""
|
|
436
|
+
from agentbundle.build.validate import validate
|
|
437
|
+
|
|
438
|
+
schema = _load_schema()
|
|
439
|
+
toml_text = """
|
|
440
|
+
[pack]
|
|
441
|
+
name = "product-engineering"
|
|
442
|
+
version = "0.5.0"
|
|
443
|
+
|
|
444
|
+
[pack.layout.repo]
|
|
445
|
+
parent = "docs/product"
|
|
446
|
+
"""
|
|
447
|
+
instance = _parse_toml(toml_text)
|
|
448
|
+
errors = validate(instance, schema)
|
|
449
|
+
self.assertEqual(errors, [], "\n".join(errors))
|
|
450
|
+
|
|
451
|
+
def test_accepts_manifest_omitting_layout(self) -> None:
|
|
452
|
+
"""Optionality: a manifest with no [pack.layout] validates (legacy invariance)."""
|
|
453
|
+
from agentbundle.build.validate import validate
|
|
454
|
+
|
|
455
|
+
schema = _load_schema()
|
|
456
|
+
toml_text = """
|
|
457
|
+
[pack]
|
|
458
|
+
name = "core"
|
|
459
|
+
version = "0.4.0"
|
|
460
|
+
"""
|
|
461
|
+
instance = _parse_toml(toml_text)
|
|
462
|
+
errors = validate(instance, schema)
|
|
463
|
+
self.assertEqual(errors, [], "\n".join(errors))
|
|
464
|
+
|
|
465
|
+
def test_rejects_non_string_parent(self) -> None:
|
|
466
|
+
"""[pack.layout.repo].parent must be a string; a non-string is rejected."""
|
|
467
|
+
from agentbundle.build.validate import validate
|
|
468
|
+
|
|
469
|
+
schema = _load_schema()
|
|
470
|
+
instance = {
|
|
471
|
+
"pack": {
|
|
472
|
+
"name": "core",
|
|
473
|
+
"version": "0.1.0",
|
|
474
|
+
"layout": {"repo": {"parent": 42}},
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
errors = validate(instance, schema)
|
|
478
|
+
self.assertTrue(errors, "schema accepted a non-string layout.repo.parent")
|
|
479
|
+
|
|
480
|
+
|
|
402
481
|
class PackSchemaLoadsTests(unittest.TestCase):
|
|
403
482
|
"""Smoke test: the schema file loads and has the expected top-level shape."""
|
|
404
483
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""`agentbundle` CLI dispatcher — argparse over the
|
|
1
|
+
"""`agentbundle` CLI dispatcher — argparse over the F-cli subcommands.
|
|
2
2
|
|
|
3
3
|
Subcommand order on the parser matches the canonical install-workflow order
|
|
4
4
|
from the spec (discovery-first): `list-packs`, `list-profiles`, `list-targets`,
|
|
@@ -11,9 +11,12 @@ Each subcommand's `run(args) -> int` lives under `agentbundle.commands.*`;
|
|
|
11
11
|
this module wires `argparse` and prints `--version`. No business logic here.
|
|
12
12
|
|
|
13
13
|
RFC-0004 surface additions:
|
|
14
|
-
- `--scope {repo,user}` on install, uninstall, upgrade, diff, init-state
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
- `--scope {repo,user}` on install, uninstall, upgrade, diff, init-state
|
|
15
|
+
(the spec § *Install-scope dimension* subcommands). The original RFC-0004
|
|
16
|
+
set also listed `list-targets`, and `reconcile` carried a single-value
|
|
17
|
+
`--scope user`; both were dead (parsed-but-never-read / only-legal-value-
|
|
18
|
+
equals-default) and dropped in the CLI-hygiene sweep, so passing `--scope`
|
|
19
|
+
to either now surfaces `unknown flag for <verb>: --scope`.
|
|
17
20
|
- `--force` on install only (cross-scope conflict bypass; see
|
|
18
21
|
spec § *Dual-scope install conflict*).
|
|
19
22
|
- Forbidden flags on the five excluded subcommands surface with the
|
|
@@ -202,12 +205,11 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
202
205
|
sp.add_argument("catalogue", help="Catalogue URI (local path or git+https://...).")
|
|
203
206
|
sp.set_defaults(func=_lazy("list_profiles"))
|
|
204
207
|
|
|
205
|
-
# --- list-targets --- (
|
|
208
|
+
# --- list-targets --- (no flags; queries the adapter registry)
|
|
206
209
|
sp = subparsers.add_parser(
|
|
207
210
|
"list-targets",
|
|
208
211
|
help="List adapter targets the CLI supports (claude-code, kiro-ide, kiro-cli, kiro (deprecated → kiro-ide), copilot, codex).",
|
|
209
212
|
)
|
|
210
|
-
sp.add_argument("--scope", choices=("repo", "user"))
|
|
211
213
|
sp.set_defaults(func=_lazy("list_targets"))
|
|
212
214
|
|
|
213
215
|
# --- scaffold --- (no --scope; always repo-targeted)
|
|
@@ -309,6 +311,17 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
309
311
|
"successful preview, even with Tier-2 collisions present."
|
|
310
312
|
),
|
|
311
313
|
)
|
|
314
|
+
sp.add_argument(
|
|
315
|
+
"--yes",
|
|
316
|
+
action="store_true",
|
|
317
|
+
help=(
|
|
318
|
+
"Answer yes to install's interactive confirmations: the --force "
|
|
319
|
+
"destructive-cleanup prompt (removing leftover files), and the "
|
|
320
|
+
"offer to upgrade a pack already installed at the requested scope. "
|
|
321
|
+
"Required for non-interactive use of those paths; without it they "
|
|
322
|
+
"prompt on a TTY and refuse rather than block on a non-TTY."
|
|
323
|
+
),
|
|
324
|
+
)
|
|
312
325
|
sp.set_defaults(func=_lazy("install"))
|
|
313
326
|
|
|
314
327
|
# --- validate --- (no --scope; schema + rails A/B/C)
|
|
@@ -374,15 +387,28 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
374
387
|
help="Upgrade a pack or a single primitive within a pack.",
|
|
375
388
|
)
|
|
376
389
|
sp.add_argument("--pack", required=True)
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
sp.
|
|
382
|
-
|
|
390
|
+
# The five per-primitive flags are mutually exclusive: a pack-version
|
|
391
|
+
# upgrade is for the whole pack or exactly one named primitive, never two
|
|
392
|
+
# at once. Grouping them lets argparse reject `--skill a --agent b` rather
|
|
393
|
+
# than silently upgrading only the first.
|
|
394
|
+
prim_group = sp.add_mutually_exclusive_group()
|
|
395
|
+
prim_group.add_argument("--skill")
|
|
396
|
+
prim_group.add_argument("--agent")
|
|
397
|
+
prim_group.add_argument("--hook")
|
|
398
|
+
prim_group.add_argument("--seed")
|
|
399
|
+
prim_group.add_argument("--command")
|
|
383
400
|
sp.add_argument("catalogue", help="Catalogue URI to fetch the new version from.")
|
|
384
401
|
sp.add_argument("--root", default=".")
|
|
385
402
|
sp.add_argument("--scope", choices=("repo", "user"))
|
|
403
|
+
sp.add_argument(
|
|
404
|
+
"--yes",
|
|
405
|
+
action="store_true",
|
|
406
|
+
help=(
|
|
407
|
+
"Skip the upgrade confirmation prompt. Required for non-interactive "
|
|
408
|
+
"use (CI, pipes); without it the upgrade asks before writing, and "
|
|
409
|
+
"refuses rather than blocking when stdin is not a TTY."
|
|
410
|
+
),
|
|
411
|
+
)
|
|
386
412
|
sp.add_argument(
|
|
387
413
|
"--dry-run",
|
|
388
414
|
action="store_true",
|
|
@@ -402,6 +428,24 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
402
428
|
sp.add_argument("--pack", required=True)
|
|
403
429
|
sp.add_argument("--root", default=".")
|
|
404
430
|
sp.add_argument("--scope", choices=("repo", "user"))
|
|
431
|
+
sp.add_argument(
|
|
432
|
+
"--yes",
|
|
433
|
+
action="store_true",
|
|
434
|
+
help=(
|
|
435
|
+
"Skip the uninstall confirmation prompt. Required for non-interactive "
|
|
436
|
+
"use (CI, pipes); without it the uninstall asks before removing any "
|
|
437
|
+
"file, and refuses rather than blocking when stdin is not a TTY."
|
|
438
|
+
),
|
|
439
|
+
)
|
|
440
|
+
sp.add_argument(
|
|
441
|
+
"--dry-run",
|
|
442
|
+
action="store_true",
|
|
443
|
+
help=(
|
|
444
|
+
"Preview the per-file plan (remove tier-1 / keep tier-2) without "
|
|
445
|
+
"removing anything — no file removed, no hook-wiring unproject, no "
|
|
446
|
+
"state change. Exits 0."
|
|
447
|
+
),
|
|
448
|
+
)
|
|
405
449
|
sp.set_defaults(func=_lazy("uninstall"))
|
|
406
450
|
|
|
407
451
|
# --- init-state --- (--scope selector; --migrate flag)
|
|
@@ -453,10 +497,9 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
453
497
|
"RFC-0005: read-only orphan reporter — walks Claude Code "
|
|
454
498
|
"settings.json and Kiro agent JSONs named in user-scope state, "
|
|
455
499
|
"reports entries the file/state pair disagrees on. Read-only; "
|
|
456
|
-
"no --apply flag."
|
|
500
|
+
"no --apply flag. User-scope only; no --scope flag."
|
|
457
501
|
),
|
|
458
502
|
)
|
|
459
|
-
sp.add_argument("--scope", choices=("user",), default="user")
|
|
460
503
|
sp.set_defaults(func=_lazy("reconcile"))
|
|
461
504
|
|
|
462
505
|
return parser
|
|
@@ -243,3 +243,51 @@ def summarize_plan(actions: list[str]) -> str:
|
|
|
243
243
|
]
|
|
244
244
|
body = ", ".join(parts) if parts else "no files"
|
|
245
245
|
return f"dry-run: {len(actions)} file(s) — {body}. Nothing written."
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
# ---------------------------------------------------------------------------
|
|
249
|
+
# Destructive-confirmation mechanics (shared by `uninstall`, `install --force`,
|
|
250
|
+
# the `install`→`upgrade` offer, and `upgrade`)
|
|
251
|
+
# ---------------------------------------------------------------------------
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def confirm_or_refuse(
|
|
255
|
+
*,
|
|
256
|
+
yes: bool,
|
|
257
|
+
question: str,
|
|
258
|
+
refuse_message: str,
|
|
259
|
+
abort_message: str,
|
|
260
|
+
) -> bool:
|
|
261
|
+
"""Decide whether a destructive command may proceed.
|
|
262
|
+
|
|
263
|
+
The single home for the confirm / non-TTY-refuse / ``--yes`` mechanics first
|
|
264
|
+
introduced for ``upgrade`` in PR #374, so ``uninstall``, ``install --force``,
|
|
265
|
+
and the ``install``→``upgrade`` offer share one implementation:
|
|
266
|
+
|
|
267
|
+
- ``yes`` (the ``--yes`` flag) → return ``True`` without touching stdin.
|
|
268
|
+
- non-interactive stdin (``not sys.stdin.isatty()``) → print
|
|
269
|
+
``refuse_message`` to stderr and return ``False`` (never block on
|
|
270
|
+
``input()``).
|
|
271
|
+
- interactive stdin → prompt with ``question``; return ``True`` only when
|
|
272
|
+
the reply is ``y``/``yes`` (case-insensitive, stripped). Any other reply
|
|
273
|
+
— including EOF — prints ``abort_message`` to stderr and returns
|
|
274
|
+
``False``.
|
|
275
|
+
|
|
276
|
+
The caller owns the ``--dry-run`` short-circuit (a dry run writes nothing, so
|
|
277
|
+
it must return *before* calling this), and owns every command-specific
|
|
278
|
+
message string passed in here — so each call site preserves its own exact
|
|
279
|
+
stderr contract.
|
|
280
|
+
"""
|
|
281
|
+
if yes:
|
|
282
|
+
return True
|
|
283
|
+
if not sys.stdin.isatty():
|
|
284
|
+
print(refuse_message, file=sys.stderr)
|
|
285
|
+
return False
|
|
286
|
+
try:
|
|
287
|
+
reply = input(question)
|
|
288
|
+
except EOFError:
|
|
289
|
+
reply = ""
|
|
290
|
+
if reply.strip().lower() not in ("y", "yes"):
|
|
291
|
+
print(abort_message, file=sys.stderr)
|
|
292
|
+
return False
|
|
293
|
+
return True
|