From a137646ff8d0e018498920040d85fe38bf58c49b Mon Sep 17 00:00:00 2001 From: Jason Hull Date: Wed, 17 Jun 2026 15:15:46 +0200 Subject: [PATCH] feat(corepack): added corepack alias for direct package manager version pinning --- docs/shell.md | 14 ++++++++++++++ internal/shell/shell.go | 1 + internal/shell/shell_test.go | 4 ++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/shell.md b/docs/shell.md index cd6fe0f..f218556 100644 --- a/docs/shell.md +++ b/docs/shell.md @@ -23,13 +23,27 @@ Your prompt gains a `(frank)` prefix so you always know aliases are active. Run | `php` | `docker compose exec app php` | | `tinker` | `docker compose exec app php artisan tinker` | | `npm` | `docker compose exec app npm` | +| `pnpm` | `docker compose exec app pnpm` | | `bun` | `docker compose exec app bun` | +| `corepack` | `docker compose exec app corepack` | | `psql` | `docker compose exec db psql …` *(pgsql only)* | | `mysql` | `docker compose exec db mysql …` *(mysql/mariadb only)* | | `redis-cli` | `docker compose exec redis redis-cli` *(redis only)* | The database aliases are only added when the matching service is configured, so `psql` won't appear in a MySQL project and vice versa. +## Pinning the package manager + +By default the container's `npm`/`pnpm` resolve to whatever [corepack](https://nodejs.org/api/corepack.html) fetches on first use — i.e. the latest published version. To pin an exact, integrity-verified version, run `corepack use` once inside the project: + +```sh +corepack use pnpm@11 # or: frank exec corepack use pnpm@11 +``` + +This stamps the `packageManager` field in your `package.json` (e.g. `pnpm@11.2.1+sha256.`). From then on every install is hash-verified and reproducible. `package.json` is the source of truth — Frank does not track the version, so this is the standard corepack workflow, nothing Frank-specific. + +> **Note:** corepack manages `npm` and `pnpm`. `bun`'s version comes from the image build, not corepack — `corepack use bun@…` has no effect. + ## Custom Aliases You can define your own aliases in `frank.yaml` under the `aliases` key. Two forms are supported: diff --git a/internal/shell/shell.go b/internal/shell/shell.go index 47e9b6f..09ea6a3 100644 --- a/internal/shell/shell.go +++ b/internal/shell/shell.go @@ -29,6 +29,7 @@ var aliasTable = []struct { {"npm", execSail + " npm", ""}, {"pnpm", execSail + " pnpm", ""}, {"bun", execSail + " bun", ""}, + {"corepack", execSail + " corepack", ""}, // pin pkg mgr: `corepack use pnpm@11` stamps package.json // Service-conditional aliases {"psql", dc + " exec pgsql psql -U sail", "pgsql"}, {"mysql", dc + " exec db mysql -u root -proot", "mysql"}, diff --git a/internal/shell/shell_test.go b/internal/shell/shell_test.go index 79a2b67..0cb4f4a 100644 --- a/internal/shell/shell_test.go +++ b/internal/shell/shell_test.go @@ -16,7 +16,7 @@ func TestActivate(t *testing.T) { cfg := testConfig("pgsql", "mailpit") output := Activate(cfg) - for _, name := range []string{"artisan", "composer", "php", "tinker", "npm", "bun"} { + for _, name := range []string{"artisan", "composer", "php", "tinker", "npm", "bun", "corepack"} { if !strings.Contains(output, "alias "+name+"=") { t.Errorf("expected core alias %q in output:\n%s", name, output) } @@ -96,7 +96,7 @@ func TestActivate_FRANK_ALIASES(t *testing.T) { end := strings.Index(output[start:], `"`) aliasLine := output[start : start+end] - for _, name := range []string{"artisan", "composer", "php", "tinker", "npm", "bun", "psql", "pest"} { + for _, name := range []string{"artisan", "composer", "php", "tinker", "npm", "bun", "corepack", "psql", "pest"} { if !strings.Contains(aliasLine, name) { t.Errorf("_FRANK_ALIASES missing %q, got: %s", name, aliasLine) }