Re-resolve and refresh a bundle's components via each primitive's update path.
(
bundle_id: str = typer.Argument(None, help="Bundle id, or omit with --all"),
all_bundles: bool = typer.Option(False, "--all", help="Update every installed bundle"),
integration: str = typer.Option(None, "--integration", help="Override integration"),
offline: bool = typer.Option(False, "--offline", help="Do not access the network"),
)
| 393 | |
| 394 | @bundle_app.command("update") |
| 395 | def bundle_update( |
| 396 | bundle_id: str = typer.Argument(None, help="Bundle id, or omit with --all"), |
| 397 | all_bundles: bool = typer.Option(False, "--all", help="Update every installed bundle"), |
| 398 | integration: str = typer.Option(None, "--integration", help="Override integration"), |
| 399 | offline: bool = typer.Option(False, "--offline", help="Do not access the network"), |
| 400 | ) -> None: |
| 401 | """Re-resolve and refresh a bundle's components via each primitive's update path.""" |
| 402 | try: |
| 403 | project_root = require_project_root() |
| 404 | records = load_records(project_root) |
| 405 | if not all_bundles and not bundle_id: |
| 406 | raise BundlerError("Specify a bundle id or use --all.") |
| 407 | targets = ( |
| 408 | [r.bundle_id for r in records] |
| 409 | if all_bundles |
| 410 | else [bundle_id] |
| 411 | ) |
| 412 | if not targets: |
| 413 | console.print("[yellow]No installed bundles to update.[/yellow]") |
| 414 | return |
| 415 | |
| 416 | stack = _build_stack(project_root, offline=offline) |
| 417 | from ...bundler.services.adapters import DefaultPrimitiveInstaller |
| 418 | from ...bundler.services.installer import install_bundle |
| 419 | from ...bundler.services.resolver import resolve_install_plan |
| 420 | |
| 421 | installer = DefaultPrimitiveInstaller(allow_network=not offline) |
| 422 | for target in targets: |
| 423 | if not any(r.bundle_id == target for r in records): |
| 424 | raise BundlerError(f"Bundle '{target}' is not installed.") |
| 425 | resolved = stack.resolve(target) |
| 426 | if not resolved.install_allowed: |
| 427 | raise BundlerError( |
| 428 | f"Bundle '{target}' resolves only from a discovery-only source " |
| 429 | f"('{resolved.source.id}'); it cannot be updated from there. " |
| 430 | "Update requires an install-allowed source (FR-025)." |
| 431 | ) |
| 432 | manifest = _download_manifest(resolved, offline=offline) |
| 433 | detected = active_integration(project_root) |
| 434 | plan = resolve_install_plan( |
| 435 | manifest, |
| 436 | speckit_version=_speckit_version(), |
| 437 | active_integration=detected if detected is not None else integration, |
| 438 | integration_explicit=bool(integration) and detected is None, |
| 439 | ) |
| 440 | install_bundle(project_root, plan, installer, manifest=manifest, refresh=True) |
| 441 | console.print(f"[green]✓[/green] Updated '{target}' to v{plan.version}.") |
| 442 | except BundlerError as exc: |
| 443 | _fail(str(exc)) |
| 444 | return |
| 445 | |
| 446 | |
| 447 | @bundle_app.command("remove") |
nothing calls this directly
no test coverage detected