114 lines
5.9 KiB
Markdown
114 lines
5.9 KiB
Markdown
# ADR 0010: ccpm Package Manager
|
|
|
|
## Status
|
|
|
|
Accepted
|
|
|
|
## Date
|
|
|
|
2026-06-08
|
|
|
|
## Context
|
|
|
|
The previous install flow (a `LIST_FILES` table inside `install.lua` and a single flat
|
|
`manifest.json` read by `wget`) was all-or-nothing. There was no way to install just
|
|
networking or just the UI, and no way to add or remove pieces of the OS after the
|
|
initial install. The project also outgrew the "Trap's ComputerCraft APIs" framing into
|
|
a small in-game OS — TrapOS — with a name, a version, a boot banner, and a persisted
|
|
beta channel; that motion is preserved here even though the original install
|
|
mechanism is fully replaced.
|
|
|
|
We want a package manager, `ccpm` ("ComputerCraft Package Manager"), installed first
|
|
as a standalone user-facing step. After that, a machine can `ccpm update`,
|
|
`ccpm install trapos`, `ccpm install trapos-net`, `ccpm uninstall trapos-ui`, and manage
|
|
where packages come from. TrapOS itself is installed through a `trapos` meta-package;
|
|
the `wget run .../install-ccpm.lua` bootstrap exists only to install `ccpm`.
|
|
|
|
## Decision
|
|
|
|
### Packages are descriptors over the existing tree
|
|
|
|
Source files stay where they are (`apis/`, `programs/`, `servers/`, `startup/`); their
|
|
install targets remain the same absolute CC paths, so `require` paths and the dev
|
|
mounts are unchanged. A package is a descriptor that *references* those files:
|
|
`packages/<name>/ccpm.json` with `{ name, version, description, dependencies, files,
|
|
autostart }`. `packages/index.json` lists the packages a registry offers (for
|
|
`ccpm search`). There is no `ccpm.json` at the repo root.
|
|
|
|
The split is finer-grained than the install examples imply:
|
|
|
|
| package | contents | deps |
|
|
|----------|-----------------------------------------------------------------|----------|
|
|
| trapos-core | ccpm, libccpm, eventloop, upgrade, events | — |
|
|
| trapos-test | libtest, runtest | trapos-core |
|
|
| trapos-boot | motd, servers (startup) | trapos-core |
|
|
| trapos-net | net, router, ping, ping-server | trapos-core |
|
|
| trapos-ui | libtui, tuidemo | trapos-core |
|
|
| trapos-ai | AI client for opencode serve | trapos-core |
|
|
| trapos | full TrapOS meta-package | trapos-boot, trapos-net, trapos-ui, trapos-test, trapos-ai |
|
|
|
|
### Two files for ccpm, "manifest" reserved for the OS
|
|
|
|
To avoid colliding with the OS `manifest.json`, ccpm never uses the word "manifest".
|
|
Local state lives under `/trapos`:
|
|
|
|
- `ccpm.json` — ordered registry list `{ registries = { { name, type, branch } } }`.
|
|
`type` is `gitea` (resolves to `git.trapcloud.fr/<name>/raw/branch/<branch>/`, the
|
|
default seeded by the bootstrap), `github` (resolves to
|
|
`raw.githubusercontent.com/<name>/<branch>/`, deprecated but still supported), or
|
|
`http`/`https` (the `name` is a base URL).
|
|
- `ccpm.lock.json` — installed packages `{ packages = { <name> = { version, registry,
|
|
files, dependencies, autostart } } }`, used by `ls`, `uninstall`, and `reinstall`.
|
|
- `ccpm.cache.json` — packages advertised by configured registries, written by
|
|
`ccpm update` from each registry's `packages/index.json`, used by `ccpm search`,
|
|
`ccpm available`, and `ccpm upgrade`.
|
|
|
|
`apis/libccpm.lua` is the testable core (a factory; `http`/`stateDir`/`installRoot`
|
|
are injectable for tests). `programs/ccpm.lua` is a thin CLI over it.
|
|
|
|
### The bootstrap installs only ccpm
|
|
|
|
`install-ccpm.lua` resolves only the `trapos-core` package descriptor (pulling any future
|
|
dependencies), downloads its files, and writes:
|
|
|
|
- `/trapos/manifest.json` — the aggregated `{ name, version, branch, files, autostart }`
|
|
still consumed by `startup/motd.lua` and `startup/servers.lua` after boot packages
|
|
are installed. This is the surviving piece of the previous manifest-driven install:
|
|
it is no longer the install source of truth (each package's `ccpm.json` is), but it
|
|
is still the local system state used at boot for the colored `TrapOS v<version>`
|
|
banner and to read the `autostart` list. `branch` is the persisted beta opt-in
|
|
(a single confirmed `--beta` install switches subsequent `ccpm upgrade` runs to
|
|
`next` with no flag needed; `--stable` is the symmetric opt-out);
|
|
- `/trapos/ccpm.lock.json` — so right after a fresh install `ccpm install trapos-core`
|
|
correctly reports "already installed";
|
|
- `/trapos/ccpm.json` — seeding/refreshing the default `guillaumearm/cc-libs` registry
|
|
to track the install branch.
|
|
|
|
The install path is:
|
|
|
|
- `wget run .../install-ccpm.lua` — install `ccpm` (`trapos-core`) and seed the default
|
|
registry.
|
|
- `ccpm update` — refresh the local package cache.
|
|
- `ccpm install trapos` — install the full OS. During beta, `trapos` includes
|
|
`trapos-test` by default.
|
|
|
|
On a subsequent `upgrade`, `programs/upgrade.lua` delegates to `ccpm upgrade`, which
|
|
upgrades installed packages using `/trapos/ccpm.cache.json`. Users run `ccpm update`
|
|
first to refresh available versions.
|
|
|
|
## Consequences
|
|
|
|
- The repo gains a `packages/` descriptor tree; the flat source layout is untouched.
|
|
- `just trapos` (formerly `just craftos`; see [ADR-0005](adr-0005-craftos-pc-harness-and-probes.md)) no longer derives mounts
|
|
from `manifest.json .files` (it is now `.packages`); it mounts a fixed list of
|
|
top-level dirs instead. `just test` was already on fixed mounts and is unaffected.
|
|
- ccpm logic is covered by `tests/ccpm.lua` (URL resolution, dependency ordering,
|
|
cycle/missing detection, already-installed, registry CRUD, cache update, available
|
|
status, upgrade, uninstall dependency guard) with an injected `http` stub — no
|
|
network in tests.
|
|
|
|
## Future Work
|
|
|
|
- Version ranges (today a single pinned version per package).
|
|
- http/https registries beyond a plain base URL (auth, caching).
|