From 6e321e67617ebf9d5ca2a11338346527d3cd28f0 Mon Sep 17 00:00:00 2001 From: macanderson Date: Sun, 26 Jul 2026 12:42:38 -0700 Subject: [PATCH] chore: move the pnpm tooling into website/, where the only package is MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The repo root carried a `package.json`, `pnpm-workspace.yaml`, and `pnpm-lock.yaml` describing a workspace that never linked anything. The root importer was empty (`.: {}`), there were no `workspace:` dependencies, no catalogs, no overrides, no patches, and exactly one member — `website/`. It was one package with a workspace wrapped around it. Nothing was ever shared across the two toolchains. The Rust crates are not pnpm packages, no `build.rs` shells out to node, there is no wasm/napi bridge, and stella ships no npm channel (binaries, Homebrew, `curl | sh`). The one thing that genuinely crosses between Rust and the site is the brand palette, and its generator is Python: `docs/brand/build.py` writes both `stella-tui/src/palette.rs` and `website/src/app/tokens.css` and never touches node. So the tooling moves to the package it describes: - `pnpm-lock.yaml` → `website/pnpm-lock.yaml`, with its sole importer promoted from `website:` to `.`. That is the entire lockfile diff — three lines, no resolved version changes, verified by `pnpm install --frozen-lockfile` succeeding against it unchanged. - `packageManager` and `engines` → `website/package.json`. - `allowBuilds`, `minimumReleaseAge`, and `minimumReleaseAgeExclude` → `website/pnpm-workspace.yaml`. The file keeps its name because pnpm 10+ reads those policy settings from it rather than from `.npmrc`; it no longer declares a `packages:` list, because there is nothing to list. - The root `package.json` is deleted outright. Its `dev`/`build`/`typecheck` scripts only forwarded to `pnpm --filter website`, and its `rust:*` and `gate` aliases had no caller anywhere in the repo. `docs.yml` gains `defaults.run.working-directory: website` and loses the root-manifest hop. Two `uses:` steps need explicit paths, since `working-directory` does not apply to them: `pnpm/action-setup` reads `packageManager` via `package_json_file`, and `setup-node` hashes the lockfile via `cache-dependency-path`. Both workflows' path filters drop the three root filenames — `website/**` already covers their new home. Requires one setting change outside this repo: Vercel's Root Directory must be `website`. Noted in the PR and in `website/README.md`. --- .github/workflows/ci.yml | 6 ----- .github/workflows/docs.yml | 21 ++++++++++++------ CONTRIBUTING.md | 3 ++- README.md | 15 ++++++++----- package.json | 22 ------------------- website/README.md | 9 ++++++-- website/package.json | 6 ++++- pnpm-lock.yaml => website/pnpm-lock.yaml | 4 +--- .../pnpm-workspace.yaml | 21 +++++++++++------- 9 files changed, 52 insertions(+), 55 deletions(-) delete mode 100644 package.json rename pnpm-lock.yaml => website/pnpm-lock.yaml (99%) rename pnpm-workspace.yaml => website/pnpm-workspace.yaml (54%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8db29eb8..60b17a6e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,9 +13,6 @@ on: - "docs/**" - "*.md" - ".github/ISSUE_TEMPLATE/**" - - "package.json" - - "pnpm-workspace.yaml" - - "pnpm-lock.yaml" push: branches: [main] paths-ignore: @@ -23,9 +20,6 @@ on: - "docs/**" - "*.md" - ".github/ISSUE_TEMPLATE/**" - - "package.json" - - "pnpm-workspace.yaml" - - "pnpm-lock.yaml" # Merge queue: GitHub tests each queued PR against the current queue tip # before it lands, so two individually-green PRs can't combine into a red # `main` (see #306). The queue evaluates the required checks on the diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 19152825..09992e99 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -8,17 +8,11 @@ on: pull_request: paths: - "website/**" - - "package.json" - - "pnpm-workspace.yaml" - - "pnpm-lock.yaml" - ".github/workflows/docs.yml" push: branches: [main] paths: - "website/**" - - "package.json" - - "pnpm-workspace.yaml" - - "pnpm-lock.yaml" - ".github/workflows/docs.yml" workflow_dispatch: @@ -35,16 +29,29 @@ jobs: name: typecheck + build runs-on: ubuntu-latest timeout-minutes: 15 + # Every step runs inside the package. The site's manifest, lockfile and + # pnpm settings all live in `website/` now — there is no root package to + # hop through, so the scripts are invoked where they are defined. + defaults: + run: + working-directory: website steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6 - # Version comes from the root package.json's packageManager field. + with: + # `defaults.run.working-directory` does not apply to `uses:` steps, + # so the action needs the manifest path spelled out to read + # `packageManager` from it. + package_json_file: website/package.json - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 with: node-version: 22 cache: pnpm + # Likewise: the cache key is hashed from the lockfile, which no + # longer sits at the repo root. + cache-dependency-path: website/pnpm-lock.yaml - name: pnpm install run: pnpm install --frozen-lockfile diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 40eed064..58aa613a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -103,7 +103,8 @@ under `website/content/docs/`, published at nothing else; you never have to build Rust to fix a docs page: ```bash -pnpm install # once, from the repo root +cd website # the site owns its own manifest and lockfile +pnpm install # once pnpm dev # the site at http://localhost:3400 pnpm typecheck && pnpm build # what the docs CI job runs ``` diff --git a/README.md b/README.md index bb7ff0e3..a62e8680 100644 --- a/README.md +++ b/README.md @@ -645,11 +645,15 @@ extending it. | [`stella-serve`](stella-serve/README.md) | A separate headless binary (not part of the `stella` CLI): drives the engine over a wire protocol so a host process runs the Rust core, remoting every model and tool call back — the engine holds no ambient authority | | Context Graph Protocol | Its own project now: [macanderson/context-graph-protocol](https://github.com/macanderson/context-graph-protocol) — wire types, host runtime, and the public conformance suite. Stella is its reference host and depends on it via git. | -The repo is a **monorepo**: alongside the Rust workspace, the documentation -site ([stella.oxagen.sh](https://stella.oxagen.sh)) lives at `website/` -(Next.js + Fumadocs), orchestrated by a pnpm workspace at the root. Rust -crates are deliberately *not* pnpm packages — cargo remains their build -system; the root `package.json` only bridges convenience scripts. +Alongside the Rust workspace, the documentation site +([stella.oxagen.sh](https://stella.oxagen.sh)) lives at `website/` (Next.js + +Fumadocs) as a **self-contained** package: its own `package.json`, +`pnpm-lock.yaml`, and pnpm settings all sit in that directory, and the repo +root is pure cargo. The two toolchains share no code — the only thing that +crosses between them is the brand palette, and that is generated by +`docs/brand/build.py` (`make brand`), which writes both +`stella-tui/src/palette.rs` and `website/src/app/tokens.css` and needs Python, +not Node. ## Development @@ -663,6 +667,7 @@ cargo run -p stella-cli -- models ### The docs site ```bash +cd website # the site is self-contained; the repo root is pure cargo pnpm install # once (Node ≥ 20, pnpm 11) pnpm dev # serve the docs at http://localhost:3400 pnpm build # production build (what docs.yml CI runs) diff --git a/package.json b/package.json deleted file mode 100644 index 32ee77eb..00000000 --- a/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "stella-monorepo", - "private": true, - "description": "The stella monorepo \u2014 the Rust workspace for the stella CLI plus the docs site (website/). Rust builds stay pure cargo; pnpm orchestrates the web packages and bridges common tasks.", - "packageManager": "pnpm@11.13.0", - "engines": { - "node": ">=20" - }, - "scripts": { - "dev": "pnpm --filter website dev", - "build": "pnpm --filter website build", - "start": "pnpm --filter website start", - "typecheck": "pnpm --filter website typecheck", - "docs:dev": "pnpm --filter website dev", - "docs:build": "pnpm --filter website build", - "rust:build": "cargo build --workspace", - "rust:test": "cargo test --workspace", - "rust:lint": "cargo clippy --workspace --all-targets -- -D warnings", - "rust:fmt": "cargo fmt --all", - "gate": "make gate" - } -} diff --git a/website/README.md b/website/README.md index fe941cb0..56bcd8ac 100644 --- a/website/README.md +++ b/website/README.md @@ -23,6 +23,10 @@ generated file directly, because the next `make brand` overwrites it. ## Develop +Every command here runs from this directory — the site owns its own +`package.json`, `pnpm-lock.yaml`, and pnpm settings, and the repo root is +pure cargo. + ```bash pnpm install pnpm dev # http://localhost:3400 @@ -99,8 +103,9 @@ src/mdx-components.tsx # MDX component map ## Deploy Deploys as a standard Next.js app. On Vercel, the project auto-detects Next.js + pnpm; set -the production domain to `stella.oxagen.sh`. `pnpm-workspace.yaml` approves the `esbuild` / -`sharp` build scripts so `pnpm install` exits cleanly in CI. +the production domain to `stella.oxagen.sh` and the **Root Directory to `website`**, since +that is where the manifest and lockfile live. `pnpm-workspace.yaml` (in this directory) +approves the `esbuild` / `sharp` build scripts so `pnpm install` exits cleanly in CI. **No deploy step lives in this repository.** `.github/workflows/docs.yml` typechecks and builds the site on every PR that touches it, but nothing diff --git a/website/package.json b/website/package.json index 9bce7c45..48e9781a 100644 --- a/website/package.json +++ b/website/package.json @@ -3,7 +3,11 @@ "version": "0.1.0", "private": true, "type": "module", - "description": "Documentation site for the Stella CLI \u2014 stella.oxagen.sh", + "description": "Documentation site for the Stella CLI — stella.oxagen.sh", + "packageManager": "pnpm@11.13.0", + "engines": { + "node": ">=20" + }, "scripts": { "dev": "next dev --port 3400", "build": "NODE_ENV=production next build", diff --git a/pnpm-lock.yaml b/website/pnpm-lock.yaml similarity index 99% rename from pnpm-lock.yaml rename to website/pnpm-lock.yaml index 48bd6b96..9e86893c 100644 --- a/pnpm-lock.yaml +++ b/website/pnpm-lock.yaml @@ -6,9 +6,7 @@ settings: importers: - .: {} - - website: + .: dependencies: fumadocs-core: specifier: 16.9.3 diff --git a/pnpm-workspace.yaml b/website/pnpm-workspace.yaml similarity index 54% rename from pnpm-workspace.yaml rename to website/pnpm-workspace.yaml index 065e0fbb..7bfd0ea0 100644 --- a/pnpm-workspace.yaml +++ b/website/pnpm-workspace.yaml @@ -1,8 +1,12 @@ -# The pnpm workspace for the stella monorepo's web packages. Rust crates are -# NOT pnpm packages — cargo remains their build system and source of truth -# (see the root package.json's rust:* scripts for the pnpm-side bridge). -packages: - - website +# pnpm settings for the docs site. Not a workspace list — `website/` is a +# single, standalone package — but pnpm 10+ reads these policy settings from +# this file rather than from `.npmrc`, so it has to exist for them to apply. +# +# It used to live at the repo root, where it declared `packages: [website]`. +# That workspace never linked anything: the root importer was empty, and there +# were no `workspace:` dependencies, catalogs, overrides, or patches — one +# package with a workspace wrapped around it. The Rust crates were never pnpm +# packages, so nothing was ever shared across the two toolchains. # pnpm 11 reads build-script approvals from here. Both deps ship prebuilt # platform binaries via optional deps, so approving their build scripts just @@ -15,9 +19,10 @@ allowBuilds: # Supply-chain policy: refuse any version published less than this many minutes # ago. A compromised release is typically yanked within hours, so waiting a day # before anything enters the lockfile is most of the protection for none of the -# cost. This lives here — not in each developer's global pnpm config — so devs -# and CI resolve under the same rule; docs.yml's `pnpm install --frozen-lockfile` -# previously ran under whatever policy the runner happened to have. +# cost. This lives in the repo — not in each developer's global pnpm config — +# so devs and CI resolve under the same rule; docs.yml's `pnpm install +# --frozen-lockfile` previously ran under whatever policy the runner happened +# to have. minimumReleaseAge: 1440 # baseline-browser-mapping is exempt. Next depends on it as `^2.9.19`, and it is