beez-rp 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Locates and verifies the package archive prepared for a release, so
3
+ * `publish: "npm"` publishes exactly the artifact the project verified
4
+ * instead of repacking the working tree.
5
+ *
6
+ * Patterns are relative to the repository root, use `/` separators and
7
+ * replace `{version}` and `{name}` (the tarball base name `npm pack` uses, so
8
+ * `@scope/pkg` becomes `scope-pkg`). Inside a single path segment, `*` matches
9
+ * anything and `{sha256}` matches a SHA-256 digest that must equal the
10
+ * archive checksum (for example `releases/{version}-{sha256}/{name}-{version}.tgz`).
11
+ * `{sha256}` may repeat, in one segment or several: every occurrence must
12
+ * declare the same digest.
13
+ *
14
+ * Projects pack with `npm pack --ignore-scripts`, which is reproducible: the same
15
+ * checkout always yields the same bytes. So the archive is verified by comparing
16
+ * its SHA-512 integrity with the one `npm pack --dry-run` reports for the release
17
+ * checkout, and the manifest must not rely on rewrites only pnpm applies when packing.
18
+ * The archive is moved out of the package root during that dry run, so npm never
19
+ * counts it as part of the package it describes.
20
+ *
21
+ * @module create-version/artifact
22
+ */
23
+ export type PreparedArtifact = {
24
+ path: string;
25
+ expectedSha256: string | null;
26
+ };
27
+ export type PackageManifest = Record<string, unknown>;
28
+ /**
29
+ * Replaces the `{version}` and `{name}` placeholders of an artifact pattern; `{sha256}` stays.
30
+ * `{name}` becomes the tarball base name, so scoped packages never add a path separator.
31
+ *
32
+ * @param {string} pattern - Configured pattern.
33
+ * @param {{ version: string, packageName: string }} release - Version and npm package name.
34
+ * @returns {string} Pattern with placeholders replaced.
35
+ */
36
+ export declare function expandArtifactPattern(pattern: string, { version, packageName }: {
37
+ version: string;
38
+ packageName: string;
39
+ }): string;
40
+ /**
41
+ * Finds the newest file that matches an artifact pattern.
42
+ *
43
+ * @param {string} repositoryRoot - Repository root.
44
+ * @param {string} pattern - Configured pattern with `{version}` and optional `{name}`, `*` and `{sha256}`.
45
+ * @param {{ version: string, packageName: string }} release - Version and npm package name.
46
+ * @returns {PreparedArtifact | null} Path relative to the root with `/` separators and the digest its path declares, or `null`.
47
+ * Paths whose segments declare different digests never match.
48
+ */
49
+ export declare function findPreparedArtifact(repositoryRoot: string, pattern: string, release: {
50
+ version: string;
51
+ packageName: string;
52
+ }): PreparedArtifact | null;
53
+ /**
54
+ * Checks that an artifact path can be passed to `npm publish` on a shell command line.
55
+ *
56
+ * @param {string} artifactPath - Relative path found by {@link findPreparedArtifact}.
57
+ * @returns {boolean} Whether the path only uses safe characters.
58
+ */
59
+ export declare function isSafeArtifactPath(artifactPath: string): boolean;
60
+ /**
61
+ * Computes the SHA-256 of a file.
62
+ *
63
+ * @param {string} filePath - Absolute path.
64
+ * @returns {string} Lowercase hexadecimal digest.
65
+ */
66
+ export declare function computeSha256(filePath: string): string;
67
+ /**
68
+ * Computes the npm integrity of a file: the same `sha512-<base64>` string that
69
+ * `npm pack --json` reports for the archive it writes.
70
+ *
71
+ * @param {string} filePath - Absolute path.
72
+ * @returns {string} Subresource-integrity string.
73
+ */
74
+ export declare function computeNpmIntegrity(filePath: string): string;
75
+ /**
76
+ * Lists what a manifest needs from `pnpm pack` and npm would publish as it is: `workspace:`,
77
+ * `catalog:` or `jsr:` specifiers in published dependency maps, and `publishConfig` keys pnpm hoists onto the
78
+ * manifest (such as `exports`, `main` or `bin`; npm only reads `publishConfig` as configuration).
79
+ * Every other `publishConfig` key is npm configuration and is accepted.
80
+ *
81
+ * @param {PackageManifest} manifest - `package.json` of the release checkout.
82
+ * @returns {string[]} Problems in Spanish; empty when npm packs the package as pnpm would.
83
+ */
84
+ export declare function findPnpmPackRewrites(manifest: PackageManifest): string[];
85
+ /**
86
+ * Runs an operation with the prepared archive moved out of the package root, and always puts it
87
+ * back afterwards, also when the operation fails.
88
+ *
89
+ * `npm pack --dry-run` describes every file npm would pack now. When the package has no `files`
90
+ * allowlist and neither `.npmignore` nor `.gitignore` excludes the archive directory, the archive
91
+ * written by `prepare` (for example `releases/pkg-1.0.0.tgz`) would be packed into the package it
92
+ * is compared with, changing the integrity and rejecting a valid artifact. Hiding it reproduces the
93
+ * package root `prepare` packed: a directory left empty is ignored by npm, as it was then.
94
+ *
95
+ * @template T
96
+ * @param {string} repositoryRoot - Package root.
97
+ * @param {string} artifactPath - Archive relative to the root, found by {@link findPreparedArtifact}.
98
+ * @param {() => Promise<T>} operation - Runs while the archive is outside the package root.
99
+ * @param {string} [parentDirectory] - Where the holding directory is created; defaults to the OS temp directory.
100
+ * @returns {Promise<T>} The operation result.
101
+ */
102
+ export declare function withArtifactOutsidePackageRoot<T>(repositoryRoot: string, artifactPath: string, operation: () => Promise<T>, parentDirectory?: string): Promise<T>;
103
+ /**
104
+ * Verifies a prepared archive before publishing it: the SHA-256 its path declares (when the
105
+ * pattern uses `{sha256}`) and the SHA-512 integrity `npm pack --dry-run` reports for the release
106
+ * checkout, so the archive is byte for byte what npm packs from that commit.
107
+ *
108
+ * @param {string} repositoryRoot - Repository root.
109
+ * @param {PreparedArtifact} artifact - Archive found by {@link findPreparedArtifact}.
110
+ * @param {string} expectedIntegrity - `integrity` of `npm pack --dry-run --json --ignore-scripts`.
111
+ * @returns {string[]} Problems in Spanish; empty when the archive can be published.
112
+ */
113
+ export declare function verifyPreparedArtifact(repositoryRoot: string, artifact: PreparedArtifact, expectedIntegrity: string): string[];
@@ -44,6 +44,7 @@ export type CreateVersionConfig = {
44
44
  migrations?: MigrationsAdapter | null;
45
45
  prepare?: string[] | ReleaseHook | null;
46
46
  publish?: "npm" | ReleaseHook | null;
47
+ artifact?: string | null;
47
48
  summary?: string[];
48
49
  };
49
50
  export type ResolvedCreateVersionConfig = {
@@ -59,6 +60,7 @@ export type ResolvedCreateVersionConfig = {
59
60
  migrations: MigrationsAdapter | null;
60
61
  prepare: string[] | ReleaseHook | null;
61
62
  publish: "npm" | ReleaseHook | null;
63
+ artifact: string | null;
62
64
  summary: string[];
63
65
  };
64
66
  /**
@@ -78,6 +80,8 @@ export declare function defineCreateVersionConfig(config: CreateVersionConfig):
78
80
  export declare function resolveCreateVersionConfig(rawConfig: unknown): ResolvedCreateVersionConfig;
79
81
  /**
80
82
  * Imports `beez-rp.config.mjs` or `beez-rp.config.js` from the repository root and validates it.
83
+ * It is imported once per process: after syncing `main` the command stops and asks to run it
84
+ * again, so a new process imports the updated file and everything it imports.
81
85
  *
82
86
  * @param {string} repositoryRoot - Repository root.
83
87
  * @returns {Promise<ResolvedCreateVersionConfig>} Resolved configuration.
@@ -8,10 +8,11 @@
8
8
  *
9
9
  * @module create-version
10
10
  */
11
+ export { computeNpmIntegrity, computeSha256, expandArtifactPattern, findPnpmPackRewrites, findPreparedArtifact, isSafeArtifactPath, verifyPreparedArtifact, withArtifactOutsidePackageRoot, } from "./artifact.js";
11
12
  export { defineCreateVersionConfig, loadCreateVersionConfig, resolveCreateVersionConfig } from "./config.js";
12
13
  export { ReleaseStepError } from "./errors.js";
13
- export { lookupPublishedVersions, publishToNpm } from "./npm.js";
14
+ export { buildNpmAuthConfigLine, buildNpmPublishArguments, buildNpmPublishEnvironment, buildNpmViewArguments, lookupPublishedVersions, parseNpmPackDryRunOutput, publishToNpm, readNpmPackIntegrity, resolvePublishRegistry, withNpmAuthConfig, } from "./npm.js";
14
15
  export { DEFAULT_CAPABILITIES, RELEASE_USAGE, buildReleasePlan, describeFeatureBranchGaps, parseReleaseArguments } from "./plan.js";
15
- export { createGitReader, listCommits, parseCommitLog, readPackageVersionAt, runCaptured, runCommandLine, runInherited } from "./process.js";
16
+ export { createGitReader, listCommits, parseCommitLog, readPackageManifestAt, readPackageVersionAt, runCaptured, runCommandLine, runInherited } from "./process.js";
16
17
  export { createHookContext, runCreateVersion } from "./run.js";
17
18
  export { collectReleaseState, findLastRelease, readChangelogState } from "./state.js";
@@ -1,6 +1,9 @@
1
1
  /**
2
- * npm adapter of `beez-rp create-version`: lists the published versions of a
3
- * package and publishes the working tree with the token referenced by `.npmrc`.
2
+ * npm adapter of `beez-rp create-version`: resolves the registry a package is
3
+ * published to (`publishConfig`, else npm's own config), lists the versions
4
+ * published there (authenticated with `NPM_TOKEN` when available), reads the integrity npm
5
+ * would pack from the release checkout, and publishes the working tree or a
6
+ * prepared archive with `NPM_TOKEN` bound to the publish registry.
4
7
  *
5
8
  * @module create-version/npm
6
9
  */
@@ -9,25 +12,147 @@ export type NpmLookup = {
9
12
  publishedVersions: string[];
10
13
  reason: string | null;
11
14
  };
15
+ export type NpmPackDescription = {
16
+ name: unknown;
17
+ version: unknown;
18
+ integrity: string;
19
+ };
20
+ export type NpmPackResult = {
21
+ pack: NpmPackDescription | null;
22
+ problem: string | null;
23
+ };
24
+ /**
25
+ * Builds the `npm view` arguments that list the published versions of a package on a registry.
26
+ * `npm view` ignores the manifest `publishConfig`, so the registry is always passed explicitly.
27
+ *
28
+ * @param {string} packageName - npm package name, already checked with `NPM_PACKAGE_NAME_PATTERN`.
29
+ * @param {string} registryUrl - Registry resolved by {@link resolvePublishRegistry}.
30
+ * @param {string | null} [userConfigPath] - Temporary npm config from {@link withNpmAuthConfig} that
31
+ * authenticates the query; `null` queries with npm's usual config.
32
+ * @returns {string[]} Arguments that follow `npm`.
33
+ * @throws {Error} When the registry is not a valid http(s) URL or has characters unsafe on the Windows shell.
34
+ */
35
+ export declare function buildNpmViewArguments(packageName: string, registryUrl: string, userConfigPath?: string | null): string[];
12
36
  /**
13
- * @typedef {{ status: string, publishedVersions: string[], reason: string | null }} NpmLookup
37
+ * Loads `NPM_TOKEN` from the ignored `.env` when the environment does not define it.
38
+ *
39
+ * @param {string} repositoryRoot - Repository root holding the optional `.env`.
40
+ * @returns {boolean} Whether `NPM_TOKEN` is available in the environment.
14
41
  */
42
+ export declare function loadNpmToken(repositoryRoot: string): boolean;
15
43
  /**
16
- * Lists the versions of a package published on npm.
44
+ * Lists the versions of a package published on a registry. With `NPM_TOKEN` (environment or `.env`)
45
+ * the query authenticates through the same temporary config the publication uses, so a private
46
+ * package can be diagnosed; without it the registry is queried with npm's usual config.
17
47
  *
18
48
  * @param {string} packageName - npm package name.
19
49
  * @param {string} repositoryRoot - Directory whose `.npmrc` npm reads.
50
+ * @param {string} [registryUrl] - Registry the package is published to, from {@link resolvePublishRegistry};
51
+ * defaults to npm's default registry.
20
52
  * @returns {Promise<NpmLookup>} Published versions; a never-published package has none.
21
53
  */
22
- export declare function lookupPublishedVersions(packageName: string, repositoryRoot: string): Promise<NpmLookup>;
54
+ export declare function lookupPublishedVersions(packageName: string, repositoryRoot: string, registryUrl?: string): Promise<NpmLookup>;
55
+ /**
56
+ * Parses the output of `npm pack --dry-run --json`: an array with one package and its `integrity`.
57
+ *
58
+ * @param {string} output - Standard output of npm.
59
+ * @returns {NpmPackResult} Package name, version and integrity, or why the output is unusable.
60
+ */
61
+ export declare function parseNpmPackDryRunOutput(output: string): NpmPackResult;
62
+ /**
63
+ * Asks npm for the integrity of the archive it would pack from the release checkout, without
64
+ * writing anything nor running lifecycle scripts. The command line is constant, so it is safe
65
+ * on the Windows shell.
66
+ *
67
+ * @param {string} repositoryRoot - Package root, as `prepare` left it.
68
+ * @returns {Promise<NpmPackResult>} npm description, or why npm failed or its output is unusable.
69
+ */
70
+ export declare function readNpmPackIntegrity(repositoryRoot: string): Promise<NpmPackResult>;
71
+ /**
72
+ * Returns the registry `npm publish` sends the package to: `publishConfig["@scope:registry"]` for a
73
+ * scoped package that declares it, else `publishConfig.registry`, else the registry npm's own config
74
+ * resolves (project `.npmrc`, environment, global config; see {@link readNpmConfigRegistry}).
75
+ *
76
+ * @param {Record<string, unknown>} manifest - `package.json` being published.
77
+ * @param {string} repositoryRoot - Package root, where npm reads its project config.
78
+ * @returns {Promise<string>} Registry URL, already checked to be a plain http(s) URL.
79
+ * @throws {Error} When the resolved registry is not a plain http(s) URL or npm cannot report its config.
80
+ */
81
+ export declare function resolvePublishRegistry(manifest: Record<string, unknown>, repositoryRoot: string): Promise<string>;
82
+ /**
83
+ * Describes where a published release can be seen: its npmjs.com page when the registry is the
84
+ * public npm registry, else the registry URL with the package and version.
85
+ *
86
+ * @param {{ registryUrl: string, packageName: string, version: string }} release - Published release.
87
+ * @returns {string} Summary text.
88
+ */
89
+ export declare function describePublishedRelease({ registryUrl, packageName, version }: {
90
+ registryUrl: string;
91
+ packageName: string;
92
+ version: string;
93
+ }): string;
94
+ /**
95
+ * Builds the npm config line that binds `${NPM_TOKEN}` to a registry, in the form npm matches
96
+ * credentials with: `//<host>[:port]<path>/:_authToken=${NPM_TOKEN}` (no protocol, trailing `/`).
97
+ *
98
+ * @param {string} registryUrl - Registry `npm publish` uses.
99
+ * @returns {string} Config line ending with a newline; the token itself is never written.
100
+ * @throws {Error} When the registry is not a plain http(s) URL (credentials, query and fragment are rejected).
101
+ */
102
+ export declare function buildNpmAuthConfigLine(registryUrl: string): string;
103
+ /**
104
+ * Runs an operation with a temporary npm user config outside the repository
105
+ * that only references `${NPM_TOKEN}` for the publish registry: npm expands it
106
+ * from the environment, so the token never reaches the disk or a command line,
107
+ * and no repository needs an `.npmrc` (which pnpm refuses to expand and warns
108
+ * about). The config is always removed afterwards.
109
+ *
110
+ * @template T
111
+ * @param {string} authConfigLine - Line built by {@link buildNpmAuthConfigLine}; an empty line
112
+ * gives npm a user config without credentials, which only replaces `~/.npmrc`.
113
+ * @param {(userConfigPath: string) => Promise<T>} operation - Receives the path for `npm --userconfig`.
114
+ * @param {string} [parentDirectory] - Where the temporary directory is created; defaults to the OS temp directory.
115
+ * @returns {Promise<T>} The operation result.
116
+ */
117
+ export declare function withNpmAuthConfig<T>(authConfigLine: string, operation: (userConfigPath: string) => Promise<T>, parentDirectory?: string): Promise<T>;
118
+ /**
119
+ * Builds the `npm publish` arguments, without the user config. A prepared
120
+ * archive is prefixed with `./` because npm parses a bare relative operand
121
+ * such as `releases/1.9.0-abc/pkg-1.9.0.tgz` as a package spec instead of a file.
122
+ *
123
+ * @param {string | null} [artifactPath] - Archive relative to the root, already checked with `isSafeArtifactPath`; `null` publishes the working tree.
124
+ * @returns {string[]} Arguments that follow `npm`.
125
+ */
126
+ export declare function buildNpmPublishArguments(artifactPath?: string | null): string[];
127
+ /**
128
+ * Builds the environment of `npm publish` without the inherited package
129
+ * manager user agent. npm reads `npm_config_user_agent` as its `user-agent`
130
+ * config, so under `pnpm create-version` its lifecycle scripts would report
131
+ * pnpm and `beez-rp guard-publish` would block beez-rp's own npm publication.
132
+ * Without it npm reports its own user agent (`npm/…`). npm reads its config
133
+ * variables in any case (`NPM_CONFIG_USER_AGENT` too), so every casing is dropped.
134
+ *
135
+ * @param {NodeJS.ProcessEnv} [environment] - Environment to copy; the current process by default.
136
+ * @returns {NodeJS.ProcessEnv} Copy without `npm_config_user_agent` in any casing.
137
+ */
138
+ export declare function buildNpmPublishEnvironment(environment?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
23
139
  /**
24
- * Publishes the working tree to npm. `NPM_TOKEN` comes from the environment or
25
- * the ignored `.env`, and only reaches npm through the environment and `.npmrc`.
140
+ * Publishes the working tree, or a prepared archive, to npm. `NPM_TOKEN` comes
141
+ * from the environment or the ignored `.env` and only reaches npm through the
142
+ * environment and a temporary user config. npm inherits the terminal, so its
143
+ * interactive browser or one-time-password (2FA) confirmation works.
26
144
  *
27
145
  * @param {string} repositoryRoot - Package root.
146
+ * @param {{ authConfigLine: string, artifactPath?: string | null }} publication - Registry credential line from
147
+ * {@link buildNpmAuthConfigLine}, and the archive relative to the root (already checked with `isSafeArtifactPath`);
148
+ * without `artifactPath` the working tree is published.
28
149
  * @returns {Promise<{ exitCode: number, missingToken: boolean }>} npm exit code, or a missing-token result without running npm.
150
+ * @throws {Error} When the temporary config path could break out of its shell quotes.
29
151
  */
30
- export declare function publishToNpm(repositoryRoot: string): Promise<{
152
+ export declare function publishToNpm(repositoryRoot: string, { authConfigLine, artifactPath }: {
153
+ authConfigLine: string;
154
+ artifactPath?: string | null;
155
+ }): Promise<{
31
156
  exitCode: number;
32
157
  missingToken: boolean;
33
158
  }>;
@@ -13,6 +13,7 @@ export type CapturedResult = {
13
13
  export type CommandOptions = {
14
14
  cwd?: string;
15
15
  shell?: boolean;
16
+ env?: NodeJS.ProcessEnv;
16
17
  };
17
18
  export type GitReader = {
18
19
  git: (gitArguments: string[]) => Promise<string>;
@@ -25,7 +26,7 @@ export type CommitRecord = {
25
26
  };
26
27
  /**
27
28
  * @typedef {{ status: number, stdout: string, stderr: string }} CapturedResult
28
- * @typedef {{ cwd?: string, shell?: boolean }} CommandOptions
29
+ * @typedef {{ cwd?: string, shell?: boolean, env?: NodeJS.ProcessEnv }} CommandOptions
29
30
  * @typedef {{ git: (gitArguments: string[]) => Promise<string>, tryGit: (gitArguments: string[]) => Promise<string | null> }} GitReader
30
31
  * @typedef {{ sha: string, subject: string, body: string }} CommitRecord
31
32
  */
@@ -80,6 +81,14 @@ export declare function parseCommitLog(output: string): CommitRecord[];
80
81
  * @returns {Promise<CommitRecord[]>} Commits, newest first.
81
82
  */
82
83
  export declare function listCommits(reader: GitReader, range: string): Promise<CommitRecord[]>;
84
+ /**
85
+ * Reads `package.json` at a revision.
86
+ *
87
+ * @param {GitReader} reader - Git reader.
88
+ * @param {string} revision - Revision such as `HEAD`, `v1.2.0` or `origin/main`.
89
+ * @returns {Promise<Record<string, unknown> | null>} Parsed manifest, or `null` when missing, unreadable or not a JSON object.
90
+ */
91
+ export declare function readPackageManifestAt(reader: GitReader, revision: string): Promise<Record<string, unknown> | null>;
83
92
  /**
84
93
  * Reads the `version` field of `package.json` at a revision.
85
94
  *
@@ -29,6 +29,8 @@ export type ReleaseContext = {
29
29
  pushed: boolean;
30
30
  published: boolean;
31
31
  commitCount: number | null;
32
+ packageName: string;
33
+ registryUrl: string | null;
32
34
  };
33
35
  /**
34
36
  * Creates the context passed to project hooks.
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `prepublishOnly` guard of the Beez packages: they are published with npm by
3
+ * `pnpm create-version`, which verifies the tarball against
4
+ * `npm pack --dry-run`, so a `pnpm publish` (or yarn/bun) is blocked.
5
+ *
6
+ * The guard only blocks package managers it recognizes. Without a user agent,
7
+ * or with an unknown one, the publisher cannot be determined and it allows the
8
+ * publication. It can be bypassed on purpose with `--ignore-scripts`.
9
+ *
10
+ * @module guard-publish
11
+ */
12
+ export type PublishGuardDecision = {
13
+ allowed: boolean;
14
+ packageManager: string | null;
15
+ message: string | null;
16
+ exitCode: number;
17
+ };
18
+ /**
19
+ * @typedef {{ allowed: boolean, packageManager: string | null, message: string | null, exitCode: number }} PublishGuardDecision
20
+ */
21
+ /**
22
+ * Finds the blocked package manager that runs the publication.
23
+ *
24
+ * @param {string | undefined} userAgent - Value of `npm_config_user_agent`.
25
+ * @returns {string | null} Blocked package manager name, or `null` for npm, unknown or missing user agents.
26
+ */
27
+ export declare function findBlockedPublishPackageManager(userAgent: string | undefined): string | null;
28
+ /**
29
+ * Builds the explanation printed when a publication is blocked.
30
+ *
31
+ * @param {string} packageManager - Blocked package manager name.
32
+ * @returns {string} Message in Spanish with what to run instead.
33
+ */
34
+ export declare function buildBlockedPublishMessage(packageManager: string): string;
35
+ /**
36
+ * Decides whether the publication may continue.
37
+ *
38
+ * @param {string | undefined} userAgent - Value of `npm_config_user_agent`.
39
+ * @returns {PublishGuardDecision} Decision, message to print on stderr and exit code.
40
+ */
41
+ export declare function decidePublishGuard(userAgent: string | undefined): PublishGuardDecision;
42
+ /**
43
+ * Decides with the user agent of an environment (the current process by default).
44
+ *
45
+ * @param {NodeJS.ProcessEnv} [environment] - Environment of the lifecycle script.
46
+ * @returns {PublishGuardDecision} Decision for its `npm_config_user_agent`.
47
+ */
48
+ export declare function decidePublishGuardForEnvironment(environment?: NodeJS.ProcessEnv): PublishGuardDecision;
package/types/index.d.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  * - `beez-rp/versions`: stable `X.Y.Z` rules; only the next patch, minor or major is allowed.
5
5
  * - `beez-rp/build-gate`: Vercel `ignoreCommand` decision built on those rules.
6
6
  * - `beez-rp/changelog` and `beez-rp/changelog-ai`: Keep a Changelog release and Codex fill-in.
7
+ * - `beez-rp/guard-publish`: `prepublishOnly` guard that blocks pnpm, yarn and bun publications.
7
8
  * - `beez-rp/terminal-ui`: boxes, spinners and prompts for release commands.
8
9
  * - `beez-rp/testing`: shared version bump fixtures for consumer test suites.
9
10
  * - `beez-rp/constants`: every constant above, grouped by domain.
@@ -13,6 +14,7 @@
13
14
  export * from "./build-gate.js";
14
15
  export * from "./changelog.js";
15
16
  export * from "./changelog-ai.js";
17
+ export * from "./guard-publish.js";
16
18
  export * from "./versions.js";
17
19
  export { ICON, countTerminalRows, formatDuration, getPromptWaitMs, measureActiveMs, paint, print, renderBanner, renderBox, renderRow, renderStepHeader, resolveBoxWidth, resolveNumberKey, select, startSpinner, visibleWidth, wrapStyledLine, } from "./terminal-ui.js";
18
20
  export * from "./constants/index.js";