Package Manager — MVP
Status: Refined. Scope reduced to git+path dependencies only. Registry deferred.
Order
Recommended implementation order: 5 (after tooling basics are stable).
Goal (MVP)
Provide a minimal package manager for NG that handles git and path dependencies without a registry, lockfile, or publishing workflow.
Motivation
Even without a registry, the ability to depend on git repositories and local paths enables:
- Multi-project code organization
- Sharing code via GitHub without manual copying
- Reproducible builds via pinned commits
Proposed Design
Manifest Format (ng.toml)
[project]
name = "my-app"
version = "0.1.0"
entry = "src/main.ng"
[dependencies]
# Git dependency (branch, tag, or commit)
json = { git = "https://github.com/user/json.ng", tag = "v1.2.0" }
# Path dependency (relative or absolute)
my-lib = { path = "../libs/my-lib" }
# Short form (from default registry — future)
# http = "0.2"Commands
ng init # Create ng.toml interactively
ng install # Download all dependencies
ng build # Build project (resolves deps first)
ng run # Build and run
ng update # Update to latest matching version (git: latest commit on tag)Dependency Resolution Algorithm
Input: ng.toml
Output: resolved dependency graph
1. Parse ng.toml
2. For each dependency:
a. If path: resolve from file system
b. If git: git clone --depth 1 (or fetch if already cached)
3. Check for duplicate package names → error if different sources
4. Build module path order:
- Project root first
- Dependencies in insertion order
5. Write resolved paths to .ngmodules (generated config, not committed)Cache Structure
~/.ng/cache/
├── git/
│ ├── github.com_user_json.ng_v1.2.0/ # Cloned repository
│ │ ├── ng.toml
│ │ └── src/
│ └── github.com_user_http.ng_main/
└── download/ # Future: registry packagesEach git dependency is cloned once and cached by (url + ref). The cache key is a hash of the URL and the git ref.
Lockfile (.ngmodules)
Simple generated file — not a full lockfile:
# Auto-generated by ng install. Do not commit.
[roots]
project = "/Users/user/projects/my-app"
[dependencies]
json = { path = "/Users/user/.ng/cache/git/github.com_user_json.ng_v1.2.0" }
my-lib = { path = "/Users/user/projects/libs/my-lib" }This maps dependency names to absolute paths. It's .gitignore-appropriate (machine-specific).
Module Path Integration
When ng build or ng run executes, it sets NG_MODULE_PATH to include all resolved dependency paths. This leverages the existing module resolution:
NG_MODULE_PATH = [
project_root/src,
/Users/user/.ng/cache/.../json,
/Users/user/projects/libs/my-lib,
]The existing ModuleLoader already supports searching NG_MODULE_PATH. No changes needed to the module system.
Implementation
src/pkg/
├── Manifest.cpp/h # ng.toml parsing
├── Resolver.cpp/h # Dependency resolution
├── Cache.cpp/h # ~/.ng/cache management
├── Git.cpp/h # Git operations
├── CLI.cpp/h # Command-line interface
└── Config.cpp/h # ConfigurationAcceptance Criteria
ng initcreates a validng.tomlwith name and entryng installclones a git dependency and caches itng install [path]copies/links a local dependencyng buildwith dependencies sets correct module paths- Duplicate dependency names produce a clear error
- A project without
ng.tomlstill works (backward compatible)
Effort Estimate
| Component | Effort |
|---|---|
| Manifest parsing (TOML) | 1 week |
| Git integration (clone, fetch, cache) | 2 weeks |
| Path dependency resolution | 0.5 week |
| Module path integration | 0.5 week |
| CLI interface | 1 week |
| Tests | 1 week |
| Total | 6 weeks |
Dependencies
- TOML parser for C++ (vendored:
toml11orcpptoml) - Git CLI integration (can shell out to
gitcommand) - No changes to the existing module system
Out of Scope (MVP)
- Registry / publishing
- SemVer version resolution
- Lockfile with hash verification
- Dependency tree visualization
- Authentication / private repos