refactor: add upm application facade and module api
This commit is contained in:
parent
005d6ebfdb
commit
e2a01d3095
36 changed files with 1058 additions and 607 deletions
|
|
@ -2,27 +2,92 @@
|
|||
|
||||
## Workspace Shape
|
||||
|
||||
`upm` is a Rust workspace with three main crates:
|
||||
`upm` is a Rust workspace with three main crates today and a fourth planned frontend:
|
||||
|
||||
- `crates/upm-core`: source normalization, add/update orchestration, registry persistence, install policies, desktop integration, and the provider-composition seam.
|
||||
- `crates/upm`: argument parsing, config loading, terminal UX, prompting, progress reporting, summary rendering, and provider assembly.
|
||||
- `crates/upm-appimage`: AppImageHub transport, search-provider behavior, and exact add-resolution for AppImage-backed installs.
|
||||
- `crates/upm-core`: the application layer for `upm`. It owns command orchestration, module contracts, module registry and composition, registry persistence, install policies, desktop integration, and the unified frontend-facing API that both the CLI and a future GUI will call.
|
||||
- `crates/upm`: the CLI frontend over `upm-core`. It handles argument parsing, config loading, terminal UX, prompting, progress reporting, summary rendering, and config-driven module presentation.
|
||||
- `crates/upm-appimage`: the AppImage package-manager module. It should own AppImage-specific acquisition backends, artifact selection, and install-resolution behavior.
|
||||
- `crates/upm-ui` (planned): a GUI frontend over `upm-core`, not a second application layer.
|
||||
|
||||
The split keeps frontend-agnostic logic in `upm-core`, while concrete package-source behavior is composed at the CLI boundary. That keeps the headless layer reusable for future frontends without making provider behavior a permanent core dependency.
|
||||
The intended split is strict:
|
||||
|
||||
- `upm-core` is effectively the application
|
||||
- `upm` is one frontend over that application
|
||||
- `upm-ui` will be another frontend over that application
|
||||
- package-manager modules own their own implementation detail and speak to `upm-core` through normalized traits
|
||||
|
||||
That keeps frontend-agnostic logic in `upm-core`, makes a future GUI a first-class consumer instead of a later retrofit, and prevents frontend layers from accumulating package-manager-specific behavior.
|
||||
|
||||
## Application Boundary
|
||||
|
||||
The architectural boundary is:
|
||||
|
||||
- `upm` may know which modules exist for configuration, enablement, disablement, priority, and display
|
||||
- `upm-ui` should operate under the same rule as the CLI: it talks to `upm-core`, not directly to modules
|
||||
- `upm` must not talk directly to a package-manager module or implement module-specific logic
|
||||
- `upm-core` owns the unified application interface used by the CLI now and a GUI later
|
||||
- `upm-core` owns module registration, composition, enablement checks, and request fan-out
|
||||
- `upm-core` fans requests out to enabled modules and aggregates normalized results
|
||||
- each module owns its own internal backends, source quirks, artifact selection, and provider-specific rules
|
||||
|
||||
In practical terms, `upm-core` is where the product behavior lives. The CLI should remain replaceable.
|
||||
|
||||
## Public API Shape
|
||||
|
||||
`upm-core` should expose one high-level application facade to frontend crates.
|
||||
|
||||
- the public boundary should be an application-facing type such as `UpmApp`
|
||||
- the facade should present operations like search, add, show, update, remove, and config management in product terms
|
||||
- frontends should not compose lower-level orchestration services themselves
|
||||
|
||||
That public facade should stay thin. The internal implementation in `upm-core` can and should be split into smaller services such as:
|
||||
|
||||
- module registry and module loading
|
||||
- search orchestration
|
||||
- add planning and execution
|
||||
- show resolution
|
||||
- update planning and execution
|
||||
- configuration and state services
|
||||
|
||||
This gives both frontends one stable application boundary without turning the facade into a god object. The orchestration depth stays inside `upm-core`, where it belongs.
|
||||
|
||||
## Module Tree
|
||||
|
||||
The intended tree is:
|
||||
|
||||
- `upm-core`
|
||||
- public application facade
|
||||
- internal orchestration services
|
||||
- module registry and composition
|
||||
- normalized contracts for package-manager modules
|
||||
- frontend crates
|
||||
- `upm` for CLI concerns only
|
||||
- `upm-ui` for GUI concerns only
|
||||
- module crates
|
||||
- `upm-appimage`
|
||||
- AppImageHub backend
|
||||
- GitHub-backed AppImage acquisition
|
||||
- GitLab-backed AppImage acquisition
|
||||
- SourceForge-backed AppImage acquisition
|
||||
- direct AppImage URL handling
|
||||
- AppImage-specific artifact and metadata rules
|
||||
|
||||
The important constraint is that the top layer understands package-manager modules, not the inner mechanics of how each module finds or resolves artifacts.
|
||||
|
||||
## Core Flow
|
||||
|
||||
The main execution path is:
|
||||
|
||||
1. Parse CLI input and load runtime config in `upm`.
|
||||
2. Assemble a `ProviderRegistry` in `crates/upm/src/providers.rs`.
|
||||
3. Resolve the query into a normalized source in `upm-core`.
|
||||
4. Build an add or update plan through core orchestration plus any registered external providers.
|
||||
4. Download the selected AppImage into a staged path.
|
||||
5. Verify integrity metadata when available.
|
||||
6. Commit the payload into the managed install location.
|
||||
7. Write desktop integration artifacts and refresh helper caches.
|
||||
8. Persist registry state atomically.
|
||||
2. Call the unified application facade in `upm-core`.
|
||||
3. Let `upm-core` route the request into internal orchestration services.
|
||||
4. Let those services select enabled modules and fan the request out through normalized module traits.
|
||||
5. Aggregate normalized results into an add, show, update, search, or remove flow.
|
||||
6. Download the selected AppImage into a staged path when the chosen module requires it.
|
||||
7. Verify integrity metadata when available.
|
||||
8. Commit the payload into the managed install location.
|
||||
9. Write desktop integration artifacts and refresh helper caches.
|
||||
10. Persist registry state atomically.
|
||||
|
||||
## Source And Provider Model
|
||||
|
||||
|
|
@ -35,7 +100,9 @@ Supported source classes currently include:
|
|||
- direct URLs
|
||||
- local file imports
|
||||
|
||||
Core source normalization and orchestration live in `crates/upm-core`. AppImageHub-specific transport and provider behavior live in `crates/upm-appimage` and are injected through `ProviderRegistry` rather than hardcoded into core entrypoints.
|
||||
Core orchestration and normalized module contracts live in `crates/upm-core`. Package-manager-specific behavior belongs in module crates.
|
||||
|
||||
For the AppImage module, that means `crates/upm-appimage` is the package-manager boundary and should grow to own AppImage-specific backing sources internally. `upm-core` should coordinate the module through normalized traits, not absorb AppImageHub, GitHub-backed AppImage discovery, GitLab-backed AppImage discovery, SourceForge-backed AppImage discovery, or direct AppImage URL handling as first-class application concepts.
|
||||
|
||||
## Runtime Interface
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
## Direction
|
||||
|
||||
The project is evolving from a focused AppImage manager into `upm`, a modular universal package manager. The target system manages multiple package sources through a shared headless core, keeps the CLI thin, and leaves room for future GUI frontends.
|
||||
The project is evolving from a focused AppImage manager into `upm`, a modular universal package manager. The target system manages multiple package-manager modules through a shared headless application core, keeps frontend crates thin, and leaves room for future GUI frontends.
|
||||
|
||||
The initial rename-and-extraction slice has now landed as a hard cutover: the runtime surface is `upm`, the shared core is `upm-core`, and AppImage support is composed through `upm-appimage` instead of being embedded directly into the core.
|
||||
The initial rename-and-extraction slice has now landed as a hard cutover: the runtime surface is `upm`, the shared core is `upm-core`, and AppImage support is beginning its transition into `upm-appimage` instead of remaining embedded directly into the core.
|
||||
|
||||
The near-term goal is a Linux-first platform with honest cross-platform architecture. Phase 2 will implement Linux package sources while establishing the abstractions needed for later macOS support and possible Windows support.
|
||||
|
||||
|
|
@ -14,7 +14,8 @@ The near-term goal is a Linux-first platform with honest cross-platform architec
|
|||
- `aim-core` stops being the all-in-one backend and is split.
|
||||
- AppImage support becomes an installable module named `upm-appimage`.
|
||||
- Shared orchestration, config, state, resolution, ranking, and frontend-facing APIs move into `upm-core`.
|
||||
- The `upm` crate becomes a thin CLI client over `upm-core`.
|
||||
- The `upm` crate becomes a thin CLI frontend over `upm-core`.
|
||||
- A future `upm-ui` crate will become a GUI frontend over the same `upm-core` application boundary.
|
||||
- The rename is a hard cutover. Legacy `AIM_*` runtime interfaces are removed rather than preserved.
|
||||
- The declarative package file starts in a hybrid mode and is intended to become the source of truth over time.
|
||||
- Every `upm` invocation should detect drift between declared state and observed system state, then auto-sync metadata as needed.
|
||||
|
|
@ -29,9 +30,10 @@ The near-term goal is a Linux-first platform with honest cross-platform architec
|
|||
The intended workspace shape after the initial refactor is:
|
||||
|
||||
- `upm`: thin CLI frontend, ratatui config UI, command routing, presentation.
|
||||
- `upm-core`: headless application layer, provider registry, resolution pipeline, state model, declarative sync engine, ranking, policies, and frontend-agnostic APIs.
|
||||
- `upm-appimage`: AppImage provider module extracted from the current `aim-core` implementation.
|
||||
- future provider modules: `upm-pacman`, `upm-aur`, `upm-flatpak`, `upm-cargo`, `upm-npm`, and later macOS or Windows-specific modules.
|
||||
- `upm-ui`: future GUI frontend over the same application core.
|
||||
- `upm-core`: headless application layer, public application facade, internal orchestration services, module registry, state model, declarative sync engine, ranking, policies, and frontend-agnostic APIs.
|
||||
- `upm-appimage`: AppImage package-manager module extracted from the current `aim-core` implementation.
|
||||
- future module crates: `upm-pacman`, `upm-aur`, `upm-flatpak`, `upm-cargo`, `upm-npm`, and later macOS or Windows-specific modules.
|
||||
|
||||
### Module Model
|
||||
|
||||
|
|
@ -42,7 +44,9 @@ UPM should stay modular in both code and packaging:
|
|||
- distro packaging can offer grouped installs such as `upm-full`
|
||||
- lighter installs can ship only the core and selected modules
|
||||
|
||||
This means provider capabilities, discovery, search, install, remove, inspect, and sync behavior need stable interfaces in `upm-core` rather than provider-specific branching in the CLI.
|
||||
This means module capabilities, discovery, search, install, remove, inspect, and sync behavior need stable interfaces in `upm-core` rather than package-manager-specific branching in the CLI or GUI.
|
||||
|
||||
The public API shape should be one application facade in `upm-core`, backed by smaller internal services. Frontends should call the facade; they should not compose lower-level services or talk directly to modules.
|
||||
|
||||
### State Model
|
||||
|
||||
|
|
@ -65,7 +69,7 @@ Goals:
|
|||
- create `upm-core` by extracting reusable infrastructure from `aim-core`
|
||||
- reduce the CLI crate to a frontend over headless APIs
|
||||
- isolate current AppImage-specific logic into `upm-appimage`
|
||||
- compose provider behavior in the CLI through `ProviderRegistry` rather than hardcoded AppImage paths in `upm-core`
|
||||
- remove direct AppImage composition from the CLI and move module composition into `upm-core`
|
||||
- preserve current AppImage functionality and tests during the move
|
||||
|
||||
Exit criteria:
|
||||
|
|
@ -76,18 +80,20 @@ Exit criteria:
|
|||
|
||||
### Milestone 1: AppImage On The New Core
|
||||
|
||||
Make the current AppImage implementation the first real module on the modular architecture.
|
||||
Make the current AppImage implementation the first real package-manager module on the modular architecture.
|
||||
|
||||
Goals:
|
||||
|
||||
- validate the provider module contract using AppImage as the reference implementation
|
||||
- move search, add, install, update, show, and remove behaviors behind core provider APIs
|
||||
- prove the CLI can treat AppImage as just one enabled source
|
||||
- establish `upm-core` as the sole application boundary for CLI and future GUI frontends
|
||||
- validate the module contract using AppImage as the reference implementation
|
||||
- move AppImage-specific acquisition backends behind `upm-appimage`
|
||||
- prove the CLI can treat AppImage as just one enabled module
|
||||
|
||||
Exit criteria:
|
||||
|
||||
- AppImage support is no longer special-cased as the whole product
|
||||
- provider registration and capability discovery exist in `upm-core`
|
||||
- CLI command paths run through the `upm-core` application facade
|
||||
- AppImage acquisition minutia no longer lives as top-level application concepts in `upm-core`
|
||||
|
||||
### Milestone 2: Linux Native Sources
|
||||
|
||||
|
|
@ -175,8 +181,8 @@ Exit criteria:
|
|||
|
||||
The following are explicitly not required to complete Phase 2:
|
||||
|
||||
- full macOS provider implementation
|
||||
- Windows provider implementation
|
||||
- full macOS module implementation
|
||||
- Windows module implementation
|
||||
- GUI frontend delivery
|
||||
- forcing strict config-authoritative reconciliation before provider behavior is stable
|
||||
- shipping every conceivable Linux package manager in the first expansion
|
||||
|
|
@ -199,7 +205,7 @@ That means:
|
|||
Implementation plans should follow this order:
|
||||
|
||||
1. rename and crate extraction
|
||||
2. provider API definition and AppImage migration onto `upm-core`
|
||||
2. application facade definition and AppImage migration behind a real module boundary
|
||||
3. Linux provider onboarding in a stable order, likely `pacman` then `Flatpak`, then `AUR`, then `cargo`, then `npm`
|
||||
4. ratatui configuration and ranking UX
|
||||
5. declarative state model, drift detection, and `update` sync behavior
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue