feat: add specify bundle command#3070
Conversation
Scaffold Spec Kit (--integration copilot) and run the full SDD workflow against the `specify bundle` subcommand feature: - spec.md (4 user stories, 31 FRs, 8 success criteria) + clarifications - plan.md, research.md, data-model.md, contracts/, quickstart.md - tasks.md (43 dependency-ordered tasks, organized by user story) - Spec Kit Constitution v1.0.0 (code quality, testing, UX, performance, dependency/security principles) derived from deep codebase analysis - plan Constitution Check + tasks grounded against the ratified principles Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Implements the Spec Kit Bundler as a `specify bundle ...` subcommand group that calls existing primitive machinery in-process with zero new dependencies, per the v1.0.0 constitution (Principles I-V). Adds the `specify_cli.bundler` package (models, services, lib helpers) and the `commands/bundle` Typer group wiring search, info, list, install, update, remove, validate, build, init, and catalog list/add/remove (with --json and --offline). Includes manifest/catalog schemas, version + integration-clash gating, discovery-only refusal, idempotent install with atomic rollback, non-collateral removal, and offline-first catalog resolution. Ships an 82-test suite (contract/unit/integration), four sample role bundles (product-manager, business-analyst, security-researcher, developer), README "Bundles" docs, and an AGENTS.md pitfall on the test-venv gotcha. Marks tasks T001-T043 complete and records follow-ups T044 (live in-process primitive dispatch) and T045 (install from a local artifact path). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
….venv Add a "Running the full test suite" subsection under Automated checks covering `uv pip install -e ".[test]"` + `.venv/bin/python -m pytest`, with the shared/global editable-install contamination caveat that mirrors the AGENTS.md pitfall. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…t install Closes the two follow-ups left after the initial bundler landing. T044 — DefaultPrimitiveInstaller now performs real installs through existing machinery instead of raising "use the primitive command" errors: - presets/extensions install via their reusable managers (install_from_directory / install_from_zip); bundled assets install fully offline, catalog assets are fetched only when the network is allowed. - workflows/steps delegate to the existing `workflow add` / `workflow step add` command callables in-process (project root as cwd), avoiding any duplicated download/validation logic (Principle I). - `--offline` is threaded through DefaultPrimitiveInstaller(allow_network=…) so network-only kinds refuse with an actionable message rather than silently reaching out. T045 — `specify bundle install` now accepts a local path (a built .zip artifact, a bundle directory, or a bundle.yml) and installs directly without consulting the catalog stack; bundle-ids still resolve via the stack. Adds 13 tests (routing, offline gating, local-source resolution, and an end-to-end offline build → install → list → remove of the bundled agent-context extension). Bundler suite: 95 passing; ruff clean. Marks T044 and T045 complete in tasks.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ran the converge command: assessed the codebase against spec.md, plan.md, tasks.md, and the v1.0.0 constitution. Appended 7 traceable gap-closure tasks (T046–T052) as a new "Phase 8: Convergence" section. Append-only — no existing tasks were modified and no application code was changed. Findings: 1 CRITICAL (Constitution III — bundle group undocumented under docs/reference/), 3 HIGH (FR-005/SC-007 validate references; FR-009/SC-002 info expansion; FR-012 install-time init), 3 MEDIUM (FR-013 integration precedence; FR-020 surface overlaps; FR-028 update refresh). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Close the gaps the converge command found between the bundler spec/plan/ constitution and the code: - T046: add docs/reference/bundles.md documenting the full `specify bundle` command group; link it from docs/reference/overview.md (Constitution III). - T047: wire a reference checker into `bundle validate` (services/references.py); online runs fail and name unresolved component references, offline runs warn. - T048: expand `bundle info` to enumerate the full component set (versions, preset priority/strategy) plus the bundle integration — info == install. - T049/T050: `bundle install`/`bundle init` now scaffold an uninitialized project via the existing `specify init` machinery, choosing the integration by precedence (override → bundle-declared → Copilot + OS default script type). - T051: surface foreseeable component overlaps during info and install. - T052: `bundle update` refreshes already-installed components via a new refresh path in install_bundle, preserving primitive-level overrides. Adds unit/contract/integration coverage (107 tests pass). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Re-run of converge after Phase 8. The seven Phase 8 tasks are verified closed. One residual partial gap remains: the `verified`/trust indicator (FR-010, FR-027) is exposed only in `bundle info --json`, absent from `bundle search` (the primary discovery surface) and `bundle info` text. Appended as a single new task for implement to complete. Append-only; no code changed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
`bundle search` (text + JSON) and `bundle info` (text + JSON) now expose each catalog entry's verification/trust level (verified vs community), so users can judge a bundle's trust before installing, per FR-010 / FR-027. Previously `verified` was only present in `bundle info --json`. Adds contract coverage; 108 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Scaffold Spec Kit (--integration copilot) and run the full SDD workflow against the `specify bundle` subcommand feature: - spec.md (4 user stories, 31 FRs, 8 success criteria) + clarifications - plan.md, research.md, data-model.md, contracts/, quickstart.md - tasks.md (43 dependency-ordered tasks, organized by user story) - Spec Kit Constitution v1.0.0 (code quality, testing, UX, performance, dependency/security principles) derived from deep codebase analysis - plan Constitution Check + tasks grounded against the ratified principles Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Implements the Spec Kit Bundler as a `specify bundle ...` subcommand group that calls existing primitive machinery in-process with zero new dependencies, per the v1.0.0 constitution (Principles I-V). Adds the `specify_cli.bundler` package (models, services, lib helpers) and the `commands/bundle` Typer group wiring search, info, list, install, update, remove, validate, build, init, and catalog list/add/remove (with --json and --offline). Includes manifest/catalog schemas, version + integration-clash gating, discovery-only refusal, idempotent install with atomic rollback, non-collateral removal, and offline-first catalog resolution. Ships an 82-test suite (contract/unit/integration), four sample role bundles (product-manager, business-analyst, security-researcher, developer), README "Bundles" docs, and an AGENTS.md pitfall on the test-venv gotcha. Marks tasks T001-T043 complete and records follow-ups T044 (live in-process primitive dispatch) and T045 (install from a local artifact path). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
….venv Add a "Running the full test suite" subsection under Automated checks covering `uv pip install -e ".[test]"` + `.venv/bin/python -m pytest`, with the shared/global editable-install contamination caveat that mirrors the AGENTS.md pitfall. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…t install Closes the two follow-ups left after the initial bundler landing. T044 — DefaultPrimitiveInstaller now performs real installs through existing machinery instead of raising "use the primitive command" errors: - presets/extensions install via their reusable managers (install_from_directory / install_from_zip); bundled assets install fully offline, catalog assets are fetched only when the network is allowed. - workflows/steps delegate to the existing `workflow add` / `workflow step add` command callables in-process (project root as cwd), avoiding any duplicated download/validation logic (Principle I). - `--offline` is threaded through DefaultPrimitiveInstaller(allow_network=…) so network-only kinds refuse with an actionable message rather than silently reaching out. T045 — `specify bundle install` now accepts a local path (a built .zip artifact, a bundle directory, or a bundle.yml) and installs directly without consulting the catalog stack; bundle-ids still resolve via the stack. Adds 13 tests (routing, offline gating, local-source resolution, and an end-to-end offline build → install → list → remove of the bundled agent-context extension). Bundler suite: 95 passing; ruff clean. Marks T044 and T045 complete in tasks.md. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ran the converge command: assessed the codebase against spec.md, plan.md, tasks.md, and the v1.0.0 constitution. Appended 7 traceable gap-closure tasks (T046–T052) as a new "Phase 8: Convergence" section. Append-only — no existing tasks were modified and no application code was changed. Findings: 1 CRITICAL (Constitution III — bundle group undocumented under docs/reference/), 3 HIGH (FR-005/SC-007 validate references; FR-009/SC-002 info expansion; FR-012 install-time init), 3 MEDIUM (FR-013 integration precedence; FR-020 surface overlaps; FR-028 update refresh). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Close the gaps the converge command found between the bundler spec/plan/ constitution and the code: - T046: add docs/reference/bundles.md documenting the full `specify bundle` command group; link it from docs/reference/overview.md (Constitution III). - T047: wire a reference checker into `bundle validate` (services/references.py); online runs fail and name unresolved component references, offline runs warn. - T048: expand `bundle info` to enumerate the full component set (versions, preset priority/strategy) plus the bundle integration — info == install. - T049/T050: `bundle install`/`bundle init` now scaffold an uninitialized project via the existing `specify init` machinery, choosing the integration by precedence (override → bundle-declared → Copilot + OS default script type). - T051: surface foreseeable component overlaps during info and install. - T052: `bundle update` refreshes already-installed components via a new refresh path in install_bundle, preserving primitive-level overrides. Adds unit/contract/integration coverage (107 tests pass). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Re-run of converge after Phase 8. The seven Phase 8 tasks are verified closed. One residual partial gap remains: the `verified`/trust indicator (FR-010, FR-027) is exposed only in `bundle info --json`, absent from `bundle search` (the primary discovery surface) and `bundle info` text. Appended as a single new task for implement to complete. Append-only; no code changed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
`bundle search` (text + JSON) and `bundle info` (text + JSON) now expose each catalog entry's verification/trust level (verified vs community), so users can judge a bundle's trust before installing, per FR-010 / FR-027. Previously `verified` was only present in `bundle info --json`. Adds contract coverage; 108 tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eat-bundler-spec-dogfood
There was a problem hiding this comment.
Pull request overview
Adds a new Spec Kit Bundler subsystem and wires it into the specify CLI as specify bundle ..., enabling role-based project setup via versioned “bundle” artifacts that compose existing primitives (extensions/presets/steps/workflows). The PR also includes a substantial dogfooding trail (spec artifacts + generated runtime scaffolding) and a comprehensive bundler-focused test suite.
Changes:
- Introduces
src/specify_cli/bundler/**(models/services/lib) implementing manifest validation, catalog stacking, install planning, installation/removal with provenance records, and artifact packaging. - Adds extensive unit/contract/integration tests for offline behavior, security path confinement, and install/update/remove lifecycle.
- Updates documentation and examples to describe/illustrate bundle authoring, discovery, and installation.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_bundler_versioning.py | Unit tests for version parsing/constraints |
| tests/unit/test_bundler_resolver.py | Resolver tests (version gate, integration compatibility) |
| tests/unit/test_bundler_references.py | Reference-checker tests (online vs offline behavior) |
| tests/unit/test_bundler_records.py | Installed-bundle record persistence/removal tests |
| tests/unit/test_bundler_primitives.py | Primitive installer routing/offline gating tests |
| tests/unit/test_bundler_packager.py | Bundle artifact packaging tests |
| tests/unit/test_bundler_conflict.py | Conflict detection tests (integration + overlaps) |
| tests/integration/test_bundler_security_paths.py | Path traversal/symlink confinement security tests |
| tests/integration/test_bundler_offline.py | Offline-first catalog resolution tests |
| tests/integration/test_bundler_local_install.py | Local path/zip install tests + end-to-end offline install |
| tests/integration/test_bundler_install_flow.py | Install/record/remove lifecycle integration tests |
| tests/integration/test_bundler_init_install.py | Init-on-install + integration precedence tests |
| tests/integration/test_bundler_catalog_stack.py | Catalog stack precedence/policy/search integration tests |
| tests/contract/test_manifest_schema.py | Manifest “schema contract” tests via model validation |
| tests/contract/test_catalog_schema.py | Catalog “schema contract” tests + default stack shape |
| tests/bundler_helpers.py | Shared helpers/fakes for bundler tests |
| src/specify_cli/bundler/services/validator.py | Manifest structural + reference validation service |
| src/specify_cli/bundler/services/resolver.py | Manifest → ordered install plan resolver |
| src/specify_cli/bundler/services/references.py | Offline-first component reference resolution |
| src/specify_cli/bundler/services/packager.py | Build bundle zip artifacts from bundle directories |
| src/specify_cli/bundler/services/installer.py | Apply install plans; rollback; provenance record write |
| src/specify_cli/bundler/services/conflict.py | Cross-bundle conflict detection (integration + overlaps) |
| src/specify_cli/bundler/services/catalog_stack.py | Multi-source catalog stack resolution + search |
| src/specify_cli/bundler/services/adapters.py | Concrete fetch/install adapters (network + primitives) |
| src/specify_cli/bundler/services/init.py | Bundler services package init |
| src/specify_cli/bundler/models/records.py | Installed bundle record model + persistence helpers |
| src/specify_cli/bundler/models/manifest.py | Bundle manifest parsing + structural validation |
| src/specify_cli/bundler/models/catalog.py | Catalog source/entry models + stack merge logic |
| src/specify_cli/bundler/models/init.py | Bundler models package init |
| src/specify_cli/bundler/lib/yamlio.py | Confined YAML/JSON IO helpers |
| src/specify_cli/bundler/lib/versioning.py | SemVer + constraint evaluation helpers |
| src/specify_cli/bundler/lib/project.py | Project root detection + active integration lookup |
| src/specify_cli/bundler/lib/init.py | Bundler lib package init |
| src/specify_cli/bundler/commands_impl/catalog_config.py | Project catalog config persistence helpers |
| src/specify_cli/bundler/commands_impl/init.py | Bundler commands-impl package init |
| src/specify_cli/bundler/init.py | Bundler package + BundlerError |
| src/specify_cli/init.py | Registers the new bundle command group on the root CLI |
| specs/001-spec-kit-bundler/research.md | Dogfooding research artifact |
| specs/001-spec-kit-bundler/quickstart.md | Dogfooding quickstart/validation artifact |
| specs/001-spec-kit-bundler/plan.md | Dogfooding implementation plan artifact |
| specs/001-spec-kit-bundler/data-model.md | Dogfooding data model artifact |
| specs/001-spec-kit-bundler/contracts/cli-commands.md | Bundler CLI behavior contract doc |
| specs/001-spec-kit-bundler/contracts/bundle-manifest.schema.md | Bundle manifest contract doc |
| specs/001-spec-kit-bundler/contracts/bundle-catalog.schema.md | Bundle catalog contract doc |
| specs/001-spec-kit-bundler/checklists/requirements.md | Dogfooding requirements checklist |
| README.md | Adds “Bundles” overview + usage examples |
| examples/bundles/security-researcher/README.md | Example bundle documentation |
| examples/bundles/security-researcher/bundle.yml | Example manifest |
| examples/bundles/product-manager/README.md | Example bundle documentation |
| examples/bundles/product-manager/bundle.yml | Example manifest |
| examples/bundles/developer/README.md | Example bundle documentation |
| examples/bundles/developer/bundle.yml | Example manifest |
| examples/bundles/business-analyst/README.md | Example bundle documentation |
| examples/bundles/business-analyst/bundle.yml | Example manifest |
| docs/reference/overview.md | Adds “Bundles” reference entry |
| docs/reference/bundles.md | New Bundles reference documentation |
| CONTRIBUTING.md | Adds guidance for running tests in a local venv reliably |
| AGENTS.md | Markdown formatting fixes + adds test-env gotcha |
| .specify/workflows/workflow-registry.json | Generated workflow registry (dogfooding/runtime) |
| .specify/workflows/speckit/workflow.yml | Generated workflow definition (dogfooding/runtime) |
| .specify/templates/spec-template.md | Generated template (dogfooding/runtime) |
| .specify/templates/plan-template.md | Generated template (dogfooding/runtime) |
| .specify/templates/constitution-template.md | Generated template (dogfooding/runtime) |
| .specify/templates/checklist-template.md | Generated template (dogfooding/runtime) |
| .specify/scripts/bash/setup-tasks.sh | Generated script (dogfooding/runtime) |
| .specify/scripts/bash/setup-plan.sh | Generated script (dogfooding/runtime) |
| .specify/scripts/bash/check-prerequisites.sh | Generated script (dogfooding/runtime) |
| .specify/integrations/speckit.manifest.json | Generated integration manifest (dogfooding/runtime) |
| .specify/integrations/copilot.manifest.json | Generated integration manifest (dogfooding/runtime) |
| .specify/integration.json | Generated runtime integration state (dogfooding/runtime) |
| .specify/init-options.json | Generated init options (dogfooding/runtime) |
| .specify/feature.json | Generated feature pointer (dogfooding/runtime) |
| .specify/extensions/agent-context/scripts/bash/update-agent-context.sh | Generated extension script (dogfooding/runtime) |
| .specify/extensions/agent-context/README.md | Generated extension docs (dogfooding/runtime) |
| .specify/extensions/agent-context/extension.yml | Generated extension manifest (dogfooding/runtime) |
| .specify/extensions/agent-context/commands/speckit.agent-context.update.md | Generated extension command (dogfooding/runtime) |
| .specify/extensions/agent-context/agent-context-config.yml | Generated extension config (dogfooding/runtime) |
| .specify/extensions/.registry | Generated extensions registry (dogfooding/runtime) |
| .specify/extensions.yml | Generated extensions config (dogfooding/runtime) |
| .github/prompts/speckit.taskstoissues.prompt.md | Generated Copilot prompt scaffold (dogfooding/runtime) |
| .github/prompts/speckit.tasks.prompt.md | Generated Copilot prompt scaffold (dogfooding/runtime) |
| .github/prompts/speckit.specify.prompt.md | Generated Copilot prompt scaffold (dogfooding/runtime) |
| .github/prompts/speckit.plan.prompt.md | Generated Copilot prompt scaffold (dogfooding/runtime) |
| .github/prompts/speckit.implement.prompt.md | Generated Copilot prompt scaffold (dogfooding/runtime) |
| .github/prompts/speckit.constitution.prompt.md | Generated Copilot prompt scaffold (dogfooding/runtime) |
| .github/prompts/speckit.clarify.prompt.md | Generated Copilot prompt scaffold (dogfooding/runtime) |
| .github/prompts/speckit.checklist.prompt.md | Generated Copilot prompt scaffold (dogfooding/runtime) |
| .github/prompts/speckit.analyze.prompt.md | Generated Copilot prompt scaffold (dogfooding/runtime) |
| .github/prompts/speckit.agent-context.update.prompt.md | Generated Copilot prompt scaffold (dogfooding/runtime) |
| .github/copilot-instructions.md | Generated Copilot context pointer (dogfooding/runtime) |
| .github/agents/speckit.taskstoissues.agent.md | Generated Copilot agent scaffold (dogfooding/runtime) |
| .github/agents/speckit.plan.agent.md | Generated Copilot agent scaffold (dogfooding/runtime) |
| .github/agents/speckit.constitution.agent.md | Generated Copilot agent scaffold (dogfooding/runtime) |
| .github/agents/speckit.agent-context.update.agent.md | Generated Copilot agent scaffold (dogfooding/runtime) |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 110/110 changed files
- Comments generated: 8
…errors, reproducible builds Resolves automated review feedback on github#3070: - validator: drop redundant string-quoting on ReferenceChecker's `str | None` return so the annotation evaluates as a real union under `from __future__ import annotations`. - adapters: normalize Windows drive-letter paths (e.g. C:\...) to the local-file branch so offline file catalogs resolve on Windows. - adapters: enforce HTTPS (HTTP only for localhost) and require a host on remote catalog URLs before any network call, mirroring specify_cli.catalogs URL validation (MITM/downgrade protection). - adapters: pass `origin` to loads_json for local files and HTTP payloads so JSON parse errors name the real source instead of <string>. - manifest: parse component `priority` defensively, raising an actionable BundlerError on non-integer values instead of a raw ValueError. - packager: write zip members with a fixed timestamp + permissions so identical inputs yield byte-for-byte identical artifacts (genuinely reproducible builds), and strengthen the determinism test accordingly. Adds regression tests for priority validation, plain-HTTP/host rejection, and byte-level artifact reproducibility (111 bundler tests pass; ruff clean). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Thanks for the review. Addressed all seven code findings in
Added regression tests for priority validation, plain-HTTP/missing-host rejection, and byte-level artifact reproducibility. 111 bundler tests pass; ruff clean. The remaining comment on Posted by GitHub Copilot (model: Claude Opus 4.8) on behalf of @mnriem. |
… URLs - packager: when --output points inside the bundle directory, exclude the whole output subtree from collection so previously-built artifacts are never re-packaged (prevents broken reproducibility and unbounded growth). - adapters: resolve file:// catalog URLs via url2pathname and preserve netloc, so Windows file URLs (file:///C:/...) and UNC shares (file://server/share) resolve correctly instead of dropping the host or producing /C:/x. Adds regression tests for nested-output exclusion and file:// resolution (113 bundler tests pass; ruff clean). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Addressed both findings in
Added regression tests for nested-output exclusion and |
Addresses review 4535084048:
- versioning.is_semver: enforce a full MAJOR.MINOR.PATCH SemVer (with optional
pre-release/build) via a dedicated regex, instead of accepting any
packaging.version.Version-parseable string (e.g. "1", "1.0"). This makes
BundleManifest.structural_errors() reject non-semver versions.
- packager: narrow the prior-artifact skip pattern to semver-named zips
(<id>-<x.y.z>.zip) so legitimate assets like <id>-assets.zip are still
packaged.
- primitives (preset + extension install): use an explicit `is None` check so
an intentional priority of 0 is preserved instead of being replaced by the
default.
Adds regressions: non-semver rejection ("1"/"1.0"/"1.2.3.4"), asset-not-
excluded vs semver-artifact-excluded, and priority-0 pass-through.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Addressed review 4535084048 (commit 654e1da).
Added regressions for each. Ran the entire suite in the worktree venv: 4152 passed, 3 skipped; ruff clean. |
…n/priority docs Addresses review 4535132279: - packager: the prior-artifact skip regex now matches semver names carrying both a prerelease and build-metadata segment (e.g. 1.0.0-rc1+build5), so such an existing artifact is excluded rather than re-packaged — keeping builds bounded/deterministic, consistent with is_semver(). - docs/reference/bundles.md: correct the install integration wording. --integration selects the integration when initializing a new project and confirms the target when a pinned bundle's active integration can't be determined; it does NOT override a bundle that targets a specific integration (a mismatch aborts with no changes). - examples/security-researcher README: reword the preset priority note in terms of the numeric comparison (ascending priority order) to avoid inverting the meaning. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Addressed review 4535132279 (commit 70b9292).
Bundler suite: 188 passing; ruff clean. |
… docs Addresses review 4535159341: - bundle install: for an already-initialized project, the project's recorded active integration is now authoritative. --integration no longer overrides it (which let a copilot project install a claude-pinned bundle via `--integration claude`, bypassing the FR-019 clash guard). The override still selects the integration at init time and confirms the target only when the active integration cannot be determined. - docs/reference/bundles.md: reword the install guarantee to match the implementation — no provenance record is written unless the install fully succeeds, and rollback of this run's components is best-effort (removal errors are swallowed, so partial on-disk state may remain). Dropped the inaccurate "atomic / rolls back everything" claim. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Addressed review 4535159341 (commit 3c44029).
Bundler suite: 189 passing; ruff clean. |
Addresses review 4535194606: _component_from_dict now rejects a contributed component whose 'kind' is not a supported component kind or whose 'id' is empty, raising a BundlerError that explicitly flags the records file as corrupt. Previously such a record loaded successfully and only failed later (e.g. in primitive_manager() during bundle remove/update) with a less actionable error. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Addressed review 4535194606 (commit 139ef20).
Added regressions for unknown |
- versioning: tolerate an uppercase `V` prefix in `_normalize_semver` and `is_semver`, mirroring specify_cli._version tag normalization (V -> v) so `V1.2.3` parses and validates consistently. - validator: import BundlerError and narrow the speckit_version constraint except clause to `BundlerError` only, so programming errors are no longer masked behind an "invalid constraint" message. - bundle update: accept `--integration` and thread it through resolve_install_plan the same way `bundle install` does (override used only when the active integration can't be auto-detected), so integration-pinned bundles can be updated where `.specify/integration.json` is missing/unreadable. - bundle validate: fold reference warnings into `report.warnings` so the ValidationReport is the single warning channel at the CLI layer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Addressed review 4535234003 (commit 54b37b2).
Added regressions (uppercase- |
Rich can split the "--integration" option label with ANSI escape codes between the two leading dashes, so the literal substring check failed under CI's terminal settings. Match the un-split option word instead, mirroring how test_bundle_help_lists_all_commands checks bare command names. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
specify bundle command for role-based project setup (dogfooding, scrub generated files before merge)specify bundle command
| # FR-016: SpecKit version gate — refuse incompatible installs. | ||
| if enforce_version and manifest.requires.speckit_version: | ||
| if not satisfies(speckit_version, manifest.requires.speckit_version): | ||
| raise BundlerError( | ||
| f"Bundle '{manifest.bundle.id}' requires Spec Kit " | ||
| f"{manifest.requires.speckit_version}, but this project uses " | ||
| f"{speckit_version}. Update Spec Kit or choose a compatible bundle." | ||
| ) |
| info = zipfile.ZipInfo(filename=arcname, date_time=_FIXED_TIMESTAMP) | ||
| info.compress_type = zipfile.ZIP_DEFLATED | ||
| info.external_attr = 0o644 << 16 | ||
| archive.writestr(info, file_path.read_bytes()) |
| for component in plan.components: | ||
| key = (component.kind, component.id) | ||
| if installer.is_installed(project_root, component): | ||
| # A component is "ours" only when this bundle (or a sibling | ||
| # bundle) already owns it. Independently-installed components | ||
| # are never attributed and — crucially — never refreshed, so | ||
| # ``bundle update`` cannot make collateral changes to things it | ||
| # does not own (FR-022). | ||
| owned = key in prior_ours or key in other_tracked | ||
| if refresh and owned: | ||
| _refresh_component(project_root, installer, component) | ||
| result.refreshed.append(component) | ||
| else: | ||
| result.skipped.append(component) | ||
| if owned: | ||
| contributed.append(component) | ||
| continue |
Summary
Adds a
specify bundlesubcommand group that composes existing Spec Kit primitives — extensions, presets, workflows, and steps — into versioned, installable units ("bundles") for role-based project setup.The command group follows a thin-CLI-over-services design (all logic lives in
src/specify_cli/bundler/services/, the CLI layer just wires arguments and rendering), is offline-first, and ships with a catalog stack for discovery.Commands
specify bundle search— discover bundles in the catalog (with a verified/community trust indicator)specify bundle info <name>— inspect a bundle's full component set + trust levelspecify bundle install <name>— install/compose a bundle into a projectspecify bundle update <name>— re-resolve and refresh installed componentsspecify bundle remove <name>— cleanly uninstallspecify bundle validate/specify bundle build— author-side validation and packagingHighlights: semantic-version resolution, conflict detection, reference/security-path checking, local-artifact installs, and a verified-vs-community trust badge surfaced across
searchandinfo.Dogfooding — submitted in flight
This feature was built using Spec Kit on itself (
specify init --integration copilot, then the full specify → clarify → plan → tasks → constitution → analyze → implement → converge loop). We're intentionally opening the PR with the generated scaffolding still present so the dogfooding is visible while the PR is in review.To scrub before merge (generated — do not merge)
All generated dogfooding scaffolding is removed before merge:
.specify/**(runtime scripts, templates, workflows, integrations, extensions,feature.json,init-options.json,integration.json,extensions.yml) — except.specify/memory/constitution.md, see below.github/agents/speckit.*,.github/prompts/speckit.*,.github/copilot-instructions.mdspecs/001-spec-kit-bundler/**(spec, plan, tasks, research, data-model, contracts, quickstart).gitattributes/ markdownlint exemptions that cover the above generated pathsRetained
.specify/memory/constitution.md— the one dogfooding artifact we carry forward, as the project constitution governing this and future Spec-Driven work.What lands in the tool
src/specify_cli/bundler/**,src/specify_cli/commands/bundle/__init__.py, the bundler test suites (tests/contract,tests/unit,tests/integration,tests/bundler_helpers.py),examples/bundles/**, and docs (docs/reference/bundles.md,overview.md).Testing
Full suite green; the bundler subset (
tests/contract tests/unit tests/integration) passes locally on every push. Verified self-contained in a fresh worktree + venv.