aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart/src/commands
AgeCommit message (Collapse)Author
2026-05-09refactor(vcs): mirror Composer interfaces; rename get_local_changesnsfisis
- Rename `local_changes` → `get_local_changes` to match Composer's `getLocalChanges` - Add `is_change_report`, `is_vcs_capable_downloader`, `is_dvcs_downloader` trait methods to replace PHP `instanceof` checks - Add `VersionParser` stub to keep `VersionGuesser::new` signature compatible with Composer's constructor - Add `ArrayDumper` in status.rs mirroring `Composer\Package\Dumper\ArrayDumper`; expand `build_package_config` to include all fields that `VersionGuesser` inspects
2026-05-09refactor(composer): move Composer and Factory from mozart-core to mozartnsfisis
Composer needs DownloadManager (from mozart-registry), but mozart-core sits below mozart-registry in the dependency graph — adding the field would create a dependency cycle. Moving Composer and create_composer to the mozart CLI crate breaks the cycle and lets the root state container hold a DownloadManager. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09refactor(commands): consolidate get_platform_requirement_filter into shared ↵nsfisis
module Removes the per-command duplicate implementations of get_platform_requirement_filter from dump_autoload and reinstall, and lifts a single canonical version into commands.rs.
2026-05-09refactor(show): make format field non-optional with default "text"nsfisis
Replace `Option<String>` with `String` + `default_value = "text"` and derive `Default` on `ShowArgs`, eliminating local `as_deref().unwrap_or` bindings. outdated.rs switches to `..Default::default()` for the fields it doesn't set. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09refactor(console): accept format args directly in console_writeln! macrosnsfisis
Eliminate the nested &console_format!(...) boilerplate at every call site by teaching console_writeln!, console_write!, console_writeln_error!, and console_write_error! to accept a format literal + variadic args directly, matching the println!/eprintln! ergonomics. Propagate the format string span into generated code so rustc errors point to the right location. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09refactor(update): Slice A — align update.rs with Composer's UpdateCommand ↵nsfisis
pipeline - Rename ChangeKind::Remove → Uninstall, drop Unchanged variant (propagate to remove.rs / require.rs); mirrors Composer's UninstallOperation naming - Fix magic-keyword mirrors detection: use Composer's count-diff semantic (any keyword triggers mirrors mode) instead of all-are-magic; mutex check now fires correctly for mixed lists like `update foo lock` - Add --patch-only pre-solve lock-presence check (previously missing; Composer throws InvalidArgumentException when no lock exists) - Add --patch-only pre-solve constraint injection: inject >=M.N.P.0,<M.(N+1).0.0 into temporary_constraints before the resolver runs, mirroring UpdateCommand::execute 177-195 - Delegate --bump-after-update to bump::do_bump (mirrors Composer's BumpCommand::doBump delegate); add \!--lock guard per Composer 280-282 - Drop parse_minimum_stability wrapper; call package::Stability::parse directly - Replace is_platform_dep with is_platform_package from mozart_core::platform (the local variant was incomplete: missed hhvm and composer pseudo-packages) - Wrap "Lock file operations" and "Writing lock file" in <info> tags - Update --no-suggest deprecation wording to match Composer 3 message Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09refactor(show): Slice A — align show.rs with Composer's ShowCommand pipelinensfisis
- A3: wire --major-only/--minor-only/--patch-only version constraint filtering in fetch_latest_for_package (mirrors ShowCommand::findLatestPackage 1500-1515) - A4: implement --sort-by-age ordering by release date - A5: add abandoned-package warning after each list row - A6: print color legend before list when --latest is on; ASCII markers (\! ~ =) in non-decorated mode - A7: split list into "Direct dependencies" / "Transitive dependencies" sections when --latest && \!--direct (mirrors Composer 671-695) - A8: replace local is_platform_package with mozart_core::platform::is_platform_package - A9: emit --installed deprecation warning (mirrors Composer 143-145) - A10: apply --strict exit-code check in both installed and locked paths - A11: fetch and display latest: line in single-package detail view - A12: add conflict/provide/replace link sections to detail view - A13: add released/names/support/autoload fields to detail view - A14: use "locked" JSON key for --locked output (was incorrectly "installed") - A15: unify show_installed_package_detail + show_locked_package_detail into a single PackageDetail struct + print_package_detail function Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09refactor(install): Slice A — align install.rs with Composer's ↵nsfisis
InstallCommand pipeline - Match Composer's deprecation wording for --dev and --no-suggest (A1) - Add missing URL to lock-fallback warning (A2) - Reorder arg validation to match InstallCommand::execute order (A3) - Rename collect_install_* helpers to verify_lock_* and consolidate into a single verify_lock() entry point (A4) - Couple classmap_authoritative=true → optimize_autoloader=true, mirroring Composer's setter side-effects (Installer.php 1263-1272) (A5) - Centralise is_platform_package in mozart_core::platform, removing divergent local copies from install.rs and update.rs (A6) - Move compute_operations, topological_sort, alias helpers, and locked_to_installed_entry into mozart-registry::installer_executor:: transaction, re-exported from the parent module (A8) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09fix(config): align with Composer's ConfigCommand pipelinensfisis
- A1: stub auth keys (bitbucket-oauth.X etc.) with actionable error - A2: audit.ignore / audit.ignore-abandoned writers with --json/--merge - A3: scripts.X writer (scalar vs array) and --unset support - A4: top-level --unset fallback for unknown single-segment keys - A5: bare --unset extra / suggest / audit support - A6/A13: disable-tls enable/disable user-visible messages - A7: editor fallback chain (editor/vim/vi/nano/pico/ed) - A8: --editor --auth opens auth.json - A9: silent exit 0 when no setting-key and no --list - A10: cache-files-maxsize regex validation - A11: cafile/capath existence check + "null" clearing - A14: merge_json_values object merge uses existing-wins (PHP `+`) - A16: repositories.<name>.url sub-path support - A17: wording "cannot" → "can not" to match Composer exactly - A19: add_repository normalizes assoc repos, injects name field, strips stale disable entries Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08fix(validate): align with Composer's ValidateCommand pipelinensfisis
- Wire Composer::try_load_from_file so validate uses typed Config.lock instead of a raw JSON read for the should-check-lock decision - Surface LockFile::get_missing_requirement_info in check_lock_freshness, mirroring Composer's locker->getMissingRequirementInfo call - Replace inline per-dep error/warning printing with output_result calls so each dependency gets the same header format as the root file - Switch --with-dependencies to RepositoryManager + InstallationManager; skip metapackages; fall back to vendor walk when Composer unavailable - Move license wrong-type from warnings to errors (divergence #10), matching ValidatingArrayLoader's classification Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08refactor(advisory): fix clippy warningsnsfisis
Implement std::str::FromStr for AuditFormat and AbandonedHandling instead of ad-hoc from_str methods (resolves should_implement_trait). Group Auditor::audit() parameters into AuditOptions to resolve too_many_arguments.
2026-05-08fix(require): align with Composer's RequireCommand pipelinensfisis
- Add mozart-registry::version_selector::VersionSelector mirroring Composer\Package\Version\VersionSelector; wraps find_best_candidate and find_recommended_require_version_string for per-arg resolution - Decompose execute() into named helpers matching Composer's structure: CommandState, revert_composer_file, get_inconsistent_require_keys, get_packages_by_require_key, update_file, update_file_cleanly (stub for PR 3), do_update, update_requirements_after_resolution (stub for PR 2) - Fix firstRequire gating: compute first_require from the original file before applying changes; apply setUpdateAllowList only when !first_require and lock exists (prevents over-pinning on fresh projects) - Add --fixed gate: bail when fixed && !dev && type != "project", matching Composer L173-189 wording verbatim - Wire --no-security-blocking + COMPOSER_NO_SECURITY_BLOCKING env var into block_insecure in ResolveRequest (was always false) - Wire COMPOSER_NO_AUDIT env var to skip audit step (tracked) - Match Composer's revertComposerFile messaging: "deleting <file>" for newly-created, "reverting <file> and <lock> to their" / "to its" for existing files; also removes lock file on newly-created revert - Auto-create "{\n}\n" when composer.json is missing or empty, mirroring Composer L138-152; delete file on dry-run cleanup (finally block) - Add resolution-failure hint: "You can also try re-running mozart require with an explicit version constraint…" for unversioned packages - Update deprecated-flag warnings to stderr (write_error) with Composer-matching wording for --no-suggest Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08fix(audit): align with Composer's AuditCommand pipelinensfisis
- Add mozart-core::advisory::{AuditFormat, AbandonedHandling, AuditConfig} mirroring Composer\Advisory\AuditConfig; reads audit.ignore, audit.ignore-severity, audit.ignore-abandoned, audit.abandoned, audit.block-insecure, audit.block-abandoned, audit.ignore-unreachable from composer.json config with full apply-scope support - Add mozart-registry::advisory::Auditor mirroring Composer\Advisory\Auditor; process_advisories() filters by package name, advisory ID, CVE, source remote ID, and severity; filter_abandoned_packages() respects ignore-abandoned - Add RepositorySet::get_matching_security_advisories() wrapping fetch_security_advisories with version-matching and unreachable-repo tracking - JSON output now includes ignored-advisories and unreachable-repositories keys - --abandoned falls back to audit.abandoned config (was hardcoded to "fail") - --ignore-severity merges with audit.ignore-severity config - --ignore-unreachable ORs with audit.ignore-unreachable config - Move normalize_or_separator into repository/mod.rs alongside version matching Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08fix(repository): align with Composer's RepositoryCommand pipelinensfisis
Introduce JsonConfigSource in mozart-core mirroring Composer's JsonConfigSource fallback logic (add/insert/set-url/remove repository), and BaseConfigContext mirroring BaseConfigCommand's initialize(). Key behaviour fixes: - list: synthesise [packagist.org] <disabled> only when no composer-type repo with a packagist.org host is present (was: always show enabled default) - disable: idempotent via add_repository(false) matching Composer's branch; now requires a name (no silent default to packagist.org) - enable: calls remove_repository only, no extra empty-array cleanup - set-url: preserves assoc-keyed format instead of converting to list - get-url: assoc fast-path + unquoted error message matching Composer - add: use regex pre-check (starts_with '{') instead of trial-parse - error messages reworded to match Composer verbatim (mozart brand kept) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08fix(remove): align with Composer's RemoveCommand pipelinensfisis
- Match exact deprecation wording for --update-with-dependencies and drop the false deprecation warning for -W/--update-with-all-dependencies - Append --with-all-dependencies / --with-dependencies flag suffix to the "Running composer update" echo (mirrors PHP's \$flags variable) - Drop validate_package_name bail so glob-style names fall through to the "not required in your composer.json" warning, matching Composer - Always run the install pipeline after the JSON edit even when nothing changed (removes the if !any_removed short-circuit) - Capture composer_backup before any mutation and restore it on pipeline failure with the "Removal failed, reverting" error message - After install, read vendor/composer/installed.json and return exit 2 if any removed package is still present (mirrors Composer's local-repo query at RemoveCommand.php L303-311) - Fix remove_unused: bail with Composer's exact error when no lock file present; use "No unused packages to remove" (no period) for empty case - Rename raw -> composer, any_removed -> packages_removed to mirror PHP Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08fix(run-script): align with Composer's RunScriptCommand pipelinensfisis
Extract script-event constants into mozart_core::script_events, fix dev_mode to `--dev || \!--no-dev` (PHP wins-on---dev), route the --list header to stderr with empty-list silent return, validate --timeout with ctype_digit semantics, and reorder execute() so the cannot-be-run check runs before requireComposer(). Drops the spurious --no-scripts short-circuit (Composer honors that flag in the dispatcher, not the command).
2026-05-08fix(check-platform-reqs): align with Composer's CheckPlatformReqsCommand flownsfisis
Mirror `CheckPlatformReqsCommand::execute` end-to-end: build an `InstalledRepoLite` from lock/installed plus the root and the real PlatformRepository, ksort the combined `$requires`, and run the candidate matching loop with `findPackagesWithReplacersAndProviders` so an installed package that `provide`s or `replace`s a platform name (e.g. `symfony/polyfill-mbstring` providing `ext-mbstring`) is now recognised as satisfying the requirement. Fixes the JSON output schema to match Composer: `failed_requirement` is the `{source, type, target, constraint}` object (or null), `provider` is the bare "provided by …" string (or null), and `status` is the unwrapped `success`/`failed`/`missing`. Also switches `--format` to a clap `value_parser` and replaces the "No installed packages found" hard error with Composer's warn-then- proceed path so an empty lock yields `[]` and exit 0. Adds `mozart_core::installer::InstalledCandidate` plus `InstalledRepoLite::add_candidate` / `find_with_replacers_and_providers` as the shared substrate for future commands (`depends`, `prohibits`, `audit`) that need the same provider/replacer index.
2026-05-08fix(suggests): align with Composer's SuggestsCommand pipelinensfisis
Port `Composer\Installer\SuggestedPackagesReporter` to `mozart_core::installer` (modes, add_package, add_suggestions_from_package, output, output_minimalistic, escape_output) and slim `commands/suggests.rs` to mirror `SuggestsCommand::execute`. Defines `HasSuggests`, `InstalledRepoLite`, `RootInfo` as the minimal stand-ins for Composer's `PackageInterface` / `InstalledRepository` / `onlyDependentsOf`. Also fixes a latent bug where `provide`/`replace` virtuals were read from `extra_fields` (always empty after a serde round-trip into LockedPackage's typed fields) and moves the "additional suggestions ... --all" hint to fire after the rendered sections, matching Composer's order.
2026-05-08fix(bump): align with Composer's BumpCommand pipelinensfisis
Splits execute() into execute → do_bump → update_file_cleanly mirroring Composer's structure, switches state loading to Composer::require, adds the no-lock fallback to vendor/composer/installed.json, routes warnings and errors through stderr, and matches Composer's wording verbatim. JsonManipulator is deferred — update_file_cleanly always falls back to a full structured rewrite for now, documented in known-incompatibilities. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08fix(create-project): align with Composer's CreateProjectCommand pipelinensfisis
Split the inline 370-line execute() into execute / install_project / install_root_package, mirroring Composer's three-method shape and argument order. Replace the bespoke caret/tilde/wildcard semver helpers with mozart_semver::VersionConstraint, harden stability inference (handle the @stability suffix and reject invalid values), and align user-facing wording ("Creating a ...", "Cannot create project directory ...", "Could not find package ...") with Composer's strings. Add the --ask directory prompt, the interactive VCS-removal prompt, the empty-target-directory bail, and the COMPOSER_ROOT_VERSION / COMPOSER env-var handling that the PHP command does after extraction. Custom repositories, the canonical Installer pathway, the signal handler, and script events are still deferred — see .ken/command_compat_plan/create_project.md.
2026-05-08fix(diagnose): align with Composer's DiagnoseCommand orchestrationnsfisis
Restructures diagnose to mirror Composer's 17-step DiagnoseCommand: adds composer.json schema validation, custom composer-repo connectivity, COMPOSER_IPRESOLVE warning, and the checkConnectivityAndComposerNetworkHttpEnablement preflight; drops Mozart-only extras (cache-dir, lock freshness, trailing summary). Extracts the manifest validator into mozart-core::config_validator so both ValidateCommand and DiagnoseCommand depend on the shared module rather than each other -- the same shape Composer uses with Util\\ConfigValidator. Adds a thin HttpDownloader wrapper in mozart-core::http, shadowing Composer's Util\\HttpDownloader. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08fix(outdated): align with Composer's OutdatedCommand proxynsfisis
Composer's OutdatedCommand (isProxyCommand = true) just remaps options and re-invokes `show --latest [--outdated]`; Mozart's outdated.rs was a ~700-line parallel reimplementation of show's outdated logic with its own classifier, renderer, JSON shape, and platform predicate. Collapse it into a thin proxy that builds a ShowArgs from OutdatedArgs and calls show::execute, mirroring OutdatedCommand::execute field-for-field. This restores show as the single source of truth for rendering, JSON fields, --strict, and the mutual-exclusion checks. Surfaced gaps in show.rs (--major-only/--minor-only/--patch-only filtering, --sort-by-age, JSON enrichment with homepage/source/time/abandoned) are deferred per the plan.
2026-05-08fix(licenses): align with Composer's LicensesCommand pipelinensfisis
Drive the command from Composer::require() and route the (installed | locked) branch through the ported PackageSorter, RepositoryUtils::filterRequiredPackages, and PackageInfo helpers in mozart-core. --no-dev for installed packages now filters via root.require closure instead of dev_package_names membership; text output annotates the name cell with an OSC 8 hyperlink to the view-source/homepage URL; summary ties resolve in first-seen order via IndexMap + stable sort_by_key(Reverse(count)) to mirror PHP's arsort().
2026-05-08fix(reinstall): align with Composer's ReinstallCommand pipelinensfisis
Switch to Composer::require() for the entrypoint, drop the Mozart-only --dry-run / --no-dev flags, mirror selection inline using a port of BasePackage::packageNameToRegexp, read autoloader options from composer.config(), and route the autoload dump through composer.autoload_generator(). Empty-result and unmatched-pattern warnings now emit on stderr with <warning> markup, matching $io->writeError. Plugin/script-event dispatch and Transaction-based operation building remain TODO until the installer_executor lands. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08fix(status): align with Composer's StatusCommand pipelinensfisis
Replace the dist-hash tree-diff implementation with Composer's VCS-level status flow: three buckets (errors / unpushed_changes / vcs_version_changes) populated via ChangeReportInterface / DvcsDownloaderInterface / VcsCapableDownloaderInterface, and a bitfield exit code (1|2|4) instead of always 1. Supporting work: - mozart-semver: add normalize_branch (VersionParser::normalizeBranch). - mozart-vcs: extend VcsDownloader trait with unpushed_changes / vcs_reference; port GitDownloader::getUnpushedChanges (HEAD-ref discovery + git diff --name-status remote...branch + two-pass fetch); fix git status invocation to use --untracked-files=no (Composer parity); add hasMetadataRepository preconditions to git/hg/svn local_changes; port VersionGuesser (git/hg/svn dispatch — Fossil omitted, feature branch detection runs sequentially instead of via async promises). - mozart-core: extend LocalPackage with pretty_version, package_type, installation_source, source, dist, extra; add InstallationSource and PackageReference. factory.rs reads them from installed.json. - mozart-registry: new download_manager mirroring DownloadManager::getDownloaderForPackage. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08fix(fund): align with Composer's FundCommand pipelinensfisis
Mirror Composer's two-pass pipeline: load default-branch metadata from remote repos first, then fall back to installed.json funding only for packages whose default branch had nothing. Also fix the prev-line dedup (was reset inside the inner loop), emit OSC 8 hyperlinks for URLs, route format errors through console.error + bail_silent with Composer's wording, and emit `[]` for empty JSON output to match PHP's json_encode of an empty array. Drop the lockfile-preferred heuristic — Composer reads only installed.json via the local repository.
2026-05-08fix(search): align with Composer's RepositoryInterface::searchnsfisis
Replace the HTTP-only post-filtered implementation with a Repository::search trait dispatch that mirrors ComposerRepository::search semantics for all three modes (FULLTEXT/NAME/VENDOR). --only-name now does an OR-of-tokens regex match against the full Packagist list.json index instead of a substring match against a fulltext page, so e.g. \`mozart search --only-name mono log\` matches \`monolog/monolog\` like Composer does. Other parity fixes: regex::escape on non-fulltext queries, format check before mutex check, 4-space JSON indent, OSC 8 terminal hyperlink emission when a result has a url, <warning>\! Abandoned \!</warning> styling on abandoned rows, and the Mozart-only "No packages found" warning is dropped to match Composer's silent empty-result behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08fix(browse): mirror Composer's HomeCommand semanticsnsfisis
Replace the hand-rolled composer.json -> composer.lock -> Packagist fallback with a BrowseRepos composite that dispatches via a uniform find_packages(name) over the root package, the local installed repository, and the Packagist remote -- matching HomeCommand's initializeRepos() + findPackages() loop. - Extend InstalledPackageEntry with homepage/support so the local repo carries the same fields HomeCommand reads off CompletePackageInterface; propagate them through locked_to_installed_entry. - Collapse three extract_url_from_* helpers into a single handle_package mirror. - Relax is_valid_url to a filter_var(FILTER_VALIDATE_URL) analog (drop the http/https scheme allowlist). - Route warnings and "No package specified" notices to stderr; match HomeCommand's exact wording. - Merge the macOS/Linux open_browser branches; add the literal "web" window-title argument on Windows.
2026-05-08refactor(archiver): extract ArchiveManager from archive commandnsfisis
Move source acquisition (root or remote dist download/extract), composer.json archive metadata reading, filename generation, self- exclusion, filter aggregation, and archive creation from the archive command into a new ArchiveManager in mozart-archiver, mirroring Composer's ArchiveCommand <-> ArchiveManager split. The command becomes a thin wrapper that selects the package and delegates archiving. Adds a one-way mozart-archiver -> mozart-registry dep since ArchiveManager::archive() handles dist downloading internally (the analog of Composer's injected DownloadManager). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08fix(commands): use tryComposer/createConfig idiom for archive and diagnosensfisis
archive and diagnose were not honoring $COMPOSER_HOME/config.json because they bypassed Factory::createConfig() — archive used literal "tar"/"." defaults when no composer.json was present, and diagnose reimplemented cache-dir resolution from environment variables. Mirror Composer's tryComposer + Factory::createConfig() fallback so global config (archive-format, archive-dir, cache-dir) applies in both commands.
2026-05-07fix(exec): align binary listing with Composernsfisis
2026-05-06fix(status): remove conflicting local verbose argnsfisis
The StatusArgs struct redefined `verbose` as bool while Cli defines a global `verbose: u8` with ArgAction::Count. clap's runtime type check panicked on access. Drop the local field and rely on cli.verbose, which matches Composer's StatusCommand treating -v|-vv|-vvv as a single flag. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06feat(core): port Factory::createComposer and AutoloadGenerator::dumpnsfisis
Add the Composer state-container types (LocalRepository, RepositoryManager, InstallationManager, AutoloadGenerator, AutoloadDumpOptions, PlatformRequirementFilter, Locker) plus the factory wiring that builds them from composer.json and vendor/composer/installed.json. AutoloadGenerator::dump lives in mozart-autoload as an extension trait so the orchestrating algorithm sits next to the classmap scanner while the state container stays in mozart-core. Rework dump-autoload to drive both, mirroring $composer->getAutoloadGenerator()->dump(...).
2026-05-06fix(clear-cache): write info messages to stderr to match Composernsfisis
Composer's ClearCacheCommand uses $io->writeError() for the per-cache status lines and the final summary; Mozart was writing them to stdout via console.info(). Switch to console_writeln_error\! so the output stream matches Composer.
2026-05-06refactor(console): rename color helpers and migrate call sites to ↵nsfisis
console_format! The six tag-style color functions (info, comment, error, question, highlight, warning) are pub only so that console_format! can call them from generated code; they are not part of the public API. Rename them to __format_*_message to make that intent visible, add a doc-comment saying not to call them directly, and replace every remaining direct call site with console_format!. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06refactor(console): add write macros and migrate commands to use themnsfisis
2026-05-06fix(cache): mirror Composer no-cache and cache-files-maxsize handlingnsfisis
--no-cache redirects COMPOSER_CACHE_DIR to /dev/null (mirrors Application::doRun). cache_files_maxsize is now u64 with a "300MiB"-style string deserializer. Cache::new() takes readonly instead of enabled; is_usable() detects null devices.
2026-05-05feat(core): port Factory::createConfig() as factory::create_config()nsfisis
Adds crates/mozart-core/src/factory.rs with get_cache_dir(), get_data_dir(), and create_config() — a Rust port of Composer\Factory::createConfig() (auth loading and htaccess creation are out of scope for now). Also fixes a correctness bug on Linux: the previous Config::default() resolved cache-dir to $XDG_CONFIG_HOME/composer/cache via the {$home}/cache placeholder, whereas Composer uses the XDG cache base ($XDG_CACHE_HOME or ~/.cache), giving ~/.cache/composer. Callers updated: - Composer::load() uses create_config() as the global baseline before merging project-level config. - config command execute_read() builds the global baseline with create_config() and overlays local config on top when not --global, matching Composer's actual layering order. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05refactor(core): replace ComposerConfig with typed Config structnsfisis
Config uses serde with kebab-case field mapping; known properties are strongly-typed fields and unknown keys flow into an extra BTreeMap. resolve_references is moved to the new config module.
2026-05-05chore: remove redundant commentsnsfisis
2026-05-05feat(dump-autoload): warn and exit 1 on missing installed packagesnsfisis
Mirror Composer's DumpAutoloadCommand by scanning the local repository for packages whose install path is absent on disk, emitting the same "Not all dependencies are installed" warning, and returning exit code 1 when any are missing. Also reorders the surrounding flow to follow Composer's command sequence.
2026-05-05refactor(commands): consolidate working_dir resolution into Cli methodnsfisis
2026-05-05feat(core): add Composer struct mirroring requireComposer/tryComposernsfisis
Introduce mozart_core::composer::Composer with require()/try_load() constructors and a config() accessor, modelled on PHP Composer's BaseCommand::requireComposer / tryComposer. ComposerConfig and composer_home move into mozart-core so Composer::load can resolve placeholders consistently. Migrate dump-autoload, archive, exec and run-script away from ad-hoc composer.json reads. exec and run-script now fail when composer.json is missing instead of silently falling back to "vendor/bin", matching the upstream requireComposer contract. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05chore(clear-cache): remove verbose type declarationnsfisis
2026-05-05feat(cache): include cache-vcs-dir in clear-cache commandnsfisis
Composer's clear-cache deletes cache-vcs-dir alongside repo/files caches, and GCs it via gcVcsCache (TTL-based, top-level subdir deletion, no size cap). Mozart was silently leaving VCS mirrors on disk forever — every clear-cache run grew the cache monotonically. Add cache_vcs_dir to CacheConfig (default {cache-dir}/vcs, env override COMPOSER_CACHE_VCS_DIR), wire it into clear-cache, and add Cache::gc_vcs mirroring Composer's gcVcsCache semantics.
2026-05-05refactor(depends): share execution path with prohibits via do_executensfisis
Mirror composer's BaseDependencyCommand::doExecute by collapsing the duplicated working-dir/load/lookup/print pipeline in depends.rs and prohibits.rs into a single dependency::do_execute helper driven by an `inverted` flag. The clap arg structs stay in their per-command modules and just forward to the shared entry point. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05refactor(core): centralize version constant in mozart-corensfisis
2026-05-04refactor(spdx-licenses): remove unused functionsnsfisis
2026-05-04feat(show): expand license output with name, OSI flag, and URLnsfisis
Mirror Composer's Command\ShowCommand::printLicenses(): emit one line per license identifier, expanded to "<full name> (<id>) [(OSI approved)] <url>" when the id is in the SPDX database, or just the id otherwise. The URL is built by mozart-spdx-licenses' new LicenseInfo::url() so the construction lives in the SPDX crate, like Composer's SpdxLicenses::getLicenseByIdentifier().
2026-05-04feat(validate): port ValidatingArrayLoader license checksnsfisis
Mirror Composer's Package\Loader\ValidatingArrayLoader::load() license block: warn on non-string/wrong-shape values, validate the SPDX expression with proprietary→MIT substitution, and surface "extra spaces" diagnostics. Validity is gated on the manifest's `time` field (checked only for releases without a date or within the last 8 days), mirroring Composer's strtotime('-8days') window.