Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions npm/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# npm distribution wrapper (Rust migration scaffold)
# npm distribution wrapper

> Status: **scaffold** — authored for ADR-0003 / track `rust-rewrite-20260618`
> (T023). Not yet wired into the live publish. The published `@pleaseai/csp`
> package on npm is still produced from the TypeScript build (root `package.json`,
> `dist/cli.mjs`). Cut over to this wrapper only when the Rust binary reaches full
> runtime parity and the Rust release pipeline (`.github/workflows/release-rust.yml`)
> is producing verified `csp-<target>` assets.
> Status: **live** (since v0.1.4). The published `@pleaseai/csp` package is the
> Rust-binary wrapper generated from this directory by
> `scripts/generate-platform-packages.mjs` and published via npm Trusted
> Publishing in `.github/workflows/release-please.yml`. The generator ships the
> repo-root `README.md` + `LICENSE` inside the wrapper so the npm page renders
> docs. This internal note documents the layout; it is not published.

## Goal

Expand Down Expand Up @@ -37,11 +37,13 @@ follows the [Biome](https://github.com/biomejs/biome) distribution model:
per-platform package directories from the built `csp-<target>` assets and the
release version, ready to `npm publish --provenance` each one.

## Release flow (once activated)
## Release flow

1. `release-rust.yml` builds `csp-<target>` binaries + checksums.
2. `node npm/scripts/generate-platform-packages.mjs <version> <assets-dir>`
materializes `npm/dist/<pkg>/` for each platform.
materializes `npm/dist/<pkg>/` for each platform (and the wrapper, with the
repo-root `README.md` + `LICENSE` copied in).
3. Publish each platform package, then the wrapper, with
`npm publish ./<pkg> --provenance --access public` (CI: `id-token: write`).
Per repo policy, use `npm publish` for provenance — not `bun publish`.
`npm publish ./<pkg> --access public` (CI: `id-token: write`). Auth is npm
Trusted Publishing (OIDC) — no token, and provenance is generated
automatically, so no `--provenance` flag is needed.
13 changes: 13 additions & 0 deletions npm/scripts/generate-platform-packages.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ if (!version || !assetsDir) {
const distRoot = join(npmRoot, 'dist')
mkdirSync(distRoot, { recursive: true })

// Repo root holds the README + LICENSE shipped inside the published packages.
const repoRoot = resolve(npmRoot, '..')

const base = JSON.parse(readFileSync(join(npmRoot, 'csp', 'package.json'), 'utf8'))

// Generate a package per target whose asset is present. A missing asset is
Expand Down Expand Up @@ -71,6 +74,10 @@ for (const t of TARGETS) {
const dest = join(outDir, t.binary)
copyFileSync(src, dest)
chmodSync(dest, 0o755)
// Ship LICENSE in each platform package too — these are published
// independently, and license-compliance scanners (FOSSA, Snyk, …) look for a
// LICENSE file in every package directory.
copyFileSync(join(repoRoot, 'LICENSE'), join(outDir, 'LICENSE'))
generated.push(t)
process.stdout.write(`wrote ${t.pkg}@${version} (${t.asset} -> ${t.binary})\n`)
}
Expand All @@ -91,4 +98,10 @@ const wrapperDir = join(distRoot, 'csp')
mkdirSync(join(wrapperDir, 'bin'), { recursive: true })
writeFileSync(join(wrapperDir, 'package.json'), `${JSON.stringify(wrapper, null, 2)}\n`)
copyFileSync(join(npmRoot, 'csp', 'bin', 'csp.js'), join(wrapperDir, 'bin', 'csp.js'))

// Ship the user-facing README + LICENSE in the published wrapper so the npm
// package page renders docs (without these, npm shows "No README data found").
// npm always includes README.md / LICENSE regardless of the `files` allowlist.
copyFileSync(join(repoRoot, 'README.md'), join(wrapperDir, 'README.md'))
copyFileSync(join(repoRoot, 'LICENSE'), join(wrapperDir, 'LICENSE'))
process.stdout.write(`wrote wrapper @pleaseai/csp@${version}\n`)
Loading