aboutsummaryrefslogtreecommitdiffhomepage
AgeCommit message (Collapse)Author
2026-05-16archiveHEADmainnsfisis
2026-05-11chore(lint): add Ruby linter scripts and apply rulesnsfisis
Adds scripts/lint with linters for mod.rs naming, contiguous use blocks, use-as aliasing, sorted Cargo dependencies, std::collections maps, and workspace dependency requirements. Renames mod.rs files, reorders use statements, drops unnecessary import aliases, and sorts Cargo.toml entries to satisfy the new rules.
2026-05-11feat(config): parse and merge top-level repositories fieldnsfisis
Mirrors Composer\Config's repositories handling: name/positional keys, `false` to disable, BC `packagist` alias, and auto-disable of the default packagist.org entry when redefined.
2026-05-11test(commands): remove per-command testsnsfisis
2026-05-11refactor(package): rename traits and switch dep maps to IndexMapnsfisis
Rename Package/CompletePackage to PackageInterface/CompletePackageInterface to mirror Composer's interface names, and split each into its own module under crates/mozart-core/src/package/. Switch dependency-link and metadata maps from BTreeMap to indexmap::IndexMap so serialized JSON preserves the original key ordering rather than sorting alphabetically — matching PHP associative-array semantics. The --sort-packages behaviour in `require` is preserved via sort_unstable_keys.
2026-05-10refactor(downloader): turn DownloadManager into downloader registrynsfisis
Reshape DownloadManager from a hard-coded VCS match into a registry of DownloaderInterface instances keyed by source type, mirroring Composer's DownloadManager — with prefer-source/dist preferences, an IO handle, and a files cache. ArchiveManager now resolves dist sources through a shared DownloadManager instead of calling download_dist directly, and Composer::require / try_load take an IO so it flows through the factory wiring.
2026-05-10refactor(downloader): introduce top-level downloader modulensfisis
Move VCS downloaders and DownloadManager out of vcs/repository into a new top-level downloader module mirroring Composer\Downloader, and add stub types for the remaining Composer downloader hierarchy (file, archive variants, path, perforce, fossil, exceptions, interfaces) so future ports have a home.
2026-05-10refactor(vcs): move VCS drivers under repository modulensfisis
Mirror Composer's structure where VCS drivers live under Repository/Vcs/. Rename VcsDriver trait to VcsDriverInterface and BitbucketDriver to GitBitbucketDriver to match Composer naming, and add stubs for FossilDriver, PerforceDriver, and the VcsDriver base.
2026-05-10refactor(package): move version guesser and array dumper under package modulensfisis
Mirror Composer's namespace layout: VersionGuesser/VersionParser move from vcs/ to package/version/, and ArrayDumper is extracted out of the status command into package/dumper/, matching Composer\Package\Version and Composer\Package\Dumper.
2026-05-10refactor(clippy): deny clippy::unused_trait_namesnsfisis
2026-05-10refactor(io): introduce IoInterface trait mirroring Composer IOInterfacensfisis
Add an `IoInterface` trait in mozart-core::console that mirrors `\Composer\IO\IOInterface`, implement it for `Console`, and switch commands, the auditor, and the suggested-packages reporter to accept the abstracted IO (typically `Arc<Mutex<Box<dyn IoInterface>>>` at the command boundary, `&dyn IoInterface` deeper down) instead of `&Console`. The console_writeln\!/write\! macros now go through `IoInterface::verbosity()` via the lock so any implementor works.
2026-05-10refactor(advisory): split advisory.rs into focused submodulesnsfisis
Move AuditConfig, AuditFormat/AbandonedHandling enums, and stub types (SecurityAdvisory, PartialSecurityAdvisory, IgnoredSecurityAdvisory) into their own files under advisory/. Public API is preserved via wildcard re-exports. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-10refactor(package): port RootPackageLoader into RootPackageData::from_rawnsfisis
Mirrors Composer\Package\Loader\RootPackageLoader::load(): converts the parsed RawPackageData into fully typed RootPackageData with Link objects, defaulted fields, and trait-based accessors. Composer::package() now returns RootPackageData instead of RawPackageData, eliminating the pre-normalised JSON workaround noted in the previous comment.
2026-05-10refactor(workspace): consolidate crates into mozart-corensfisis
Merged mozart-archiver, mozart-autoload, mozart-registry, mozart-sat-resolver, and mozart-vcs into mozart-core to align the source layout with Composer's structure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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