From 6f25325bc3b4ee028b22cd95606977d9f6cddc2c Mon Sep 17 00:00:00 2001 From: Radu Busuioc Date: Mon, 27 Jul 2026 12:57:44 +0300 Subject: [PATCH] chore(release): publish @robrain/shared to npm; bump to 2.4.9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make `@robrain/shared` a publishable package so consumers (the cloud repo) can install a prebuilt tarball from the registry instead of the git-pin `github:adelinamart/robrain#vX.Y.Z&path:packages/shared`, which forces a full-monorepo download plus a TypeScript compile at install time. packages/shared/package.json: - drop `private: true`; add license/repository/homepage/bugs mirroring the CLI - `files: ["dist", "schema.sql", "README.md", "LICENSE"]` — schema.sql stays at package root because the cloud mounts and resolves it from there - `publishConfig.access: "public"` — scoped packages default to restricted, which the free `@robrain` org cannot host - export `./schema.sql` and `./package.json` so consumers can resolve the schema directly; both additions are backwards compatible Build hygiene. Excluding `src/**/*.test.ts` in tsconfig.json is not enough on its own: `tsc` never cleans its output directory, so a release machine with a populated `dist/` would keep every previously-compiled `*.test.js` and ship it. `prepare` and `prepack` are therefore `rm -rf dist && tsc -p tsconfig.publish.json`. Both hooks are needed because npm runs `prepare` after `prepack`, so `prepare` determines what actually lands in the tarball. tsconfig.publish.json also disables sourceMap/declarationMap: `files` does not ship `src/`, so published `.js.map` / `.d.ts.map` would point at a `../src` that is not in the tarball. Plain `build` keeps maps for local dev, and the new tsconfig.typecheck.json re-includes tests so `pnpm typecheck` still covers them. Root package.json: `publish:npm` builds the CLI and runs verify-release-artifacts.mjs *before* publishing @robrain/shared. Publishing shared first is deliberate — it has no coupling to the Docker image, so a cloud repin should not wait on a CLI publish failure — but the CLI's own prepublishOnly guard runs last in the chain. Without the up-front check, a guard failure there (the 2.3.6/2.3.7 case) would leave @robrain/shared already public with no matching CLI, and npm blocks reusing a version for 24h after an unpublish. The only fix would be bumping to the next patch, orphaning a version the cloud could pin and breaking the lockstep invariant. docs/release.md: document the two-package npm step, the one-time @robrain org creation, the pack preflight, and why the guard runs up front. Version 2.4.9 across the 13 lockstep files — 2.4.8 is already tagged and published from main, so this packaging change takes the next patch. Co-Authored-By: Claude Opus 5 --- Dockerfile | 2 +- docs/release.md | 48 +++++++++++++++++-- package.json | 4 +- packages/cli/package.json | 2 +- packages/cli/src/commands/install.ts | 4 +- packages/cli/src/index.ts | 2 +- packages/eval/package.json | 2 +- packages/perception-self-hosted/package.json | 2 +- packages/sensing-mcp/package.json | 2 +- packages/sensing-mcp/src/server.ts | 2 +- packages/shared/LICENSE | 17 +++++++ packages/shared/README.md | 46 ++++++++++++++++++ packages/shared/package.json | 33 +++++++++++-- packages/shared/tsconfig.json | 6 ++- packages/shared/tsconfig.publish.json | 12 +++++ packages/shared/tsconfig.typecheck.json | 8 ++++ packages/synthesis/package.json | 2 +- .../claude-code/.claude-plugin/plugin.json | 2 +- server.json | 4 +- 19 files changed, 176 insertions(+), 24 deletions(-) create mode 100644 packages/shared/LICENSE create mode 100644 packages/shared/README.md create mode 100644 packages/shared/tsconfig.publish.json create mode 100644 packages/shared/tsconfig.typecheck.json diff --git a/Dockerfile b/Dockerfile index 686b816..f1ec607 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ FROM node:22-alpine # keeps the Glama-introspected surface reproducible. Bump on release. ENV PNPM_HOME=/usr/local/share/pnpm ENV PATH=$PNPM_HOME/bin:$PNPM_HOME:$PATH -RUN corepack enable && pnpm add -g robrain@2.4.8 +RUN corepack enable && pnpm add -g robrain@2.4.9 # stdio MCP transport: the client speaks JSON-RPC over stdin/stdout. ENTRYPOINT ["robrain", "mcp"] diff --git a/docs/release.md b/docs/release.md index 03e42fc..e8a9c24 100644 --- a/docs/release.md +++ b/docs/release.md @@ -108,16 +108,58 @@ git push origin v2.3.8 && gh run watch ### 3. Publish npm -From repo root (release guard runs automatically in `prepublishOnly`): +Two packages ship to npm every release: **`@robrain/shared`** (consumed by the +cloud repo as a normal registry dependency) and **`robrain`** (the CLI). + +> **One-time setup:** the `@robrain` scope is an npm **organization**, created on +> https://www.npmjs.com/org/create with the same account that owns the `robrain` +> CLI package (`npm owner ls robrain`). Orgs cannot be created from the CLI. Use +> the free *Unlimited public packages* plan. Verify with `npm org ls robrain`. +> Scoped packages default to restricted on publish, which a free org cannot +> host — hence `publishConfig.access: "public"` in `packages/shared/package.json` +> **and** `--access public` on the publish command. + +Preflight — confirm the shared tarball has `dist/*` (no `*.test.js`, no +`*.map`), `schema.sql`, `README.md`, `LICENSE`, and `package.json`, and nothing +else: + +```bash +pnpm --filter @robrain/shared exec npm pack --dry-run +``` + +Then from repo root: ```bash pnpm publish:npm -# equivalent: pnpm --filter @robrain/sensing-mcp build && pnpm --filter @robrain/synthesis build && pnpm --filter robrain publish --access public --no-git-checks +# equivalent: pnpm --filter robrain build && node packages/cli/scripts/verify-release-artifacts.mjs && pnpm --filter @robrain/shared publish --access public --no-git-checks && pnpm --filter @robrain/sensing-mcp build && pnpm --filter @robrain/synthesis build && pnpm --filter robrain publish --access public --no-git-checks ``` +With 2FA on the account, npm prompts for an OTP **per package** — two prompts. + +**Why the guard runs up front.** `@robrain/shared` has no coupling to the Docker +image, so the GHCR golden rule does not gate it, and publishing it first means a +cloud repin never waits on a CLI publish failure. But the CLI's own +`prepublishOnly` guard runs *last* in the chain — if it failed there, +`@robrain/shared@X.Y.Z` would already be public with no matching CLI, and npm +blocks reusing a version for 24h after an unpublish. The only way out would be +bumping everything to X.Y.Z+1, leaving an orphan version the cloud could pin and +breaking the lockstep invariant. So `publish:npm` builds the CLI and runs +`verify-release-artifacts.mjs` standalone *before* the first publish. It runs +again in `prepublishOnly`; the second run is a cheap no-op re-check. +`ROBRAIN_SKIP_RELEASE_GUARD=1` still bypasses both. + +**`prepack` cleans `dist/` first.** `tsc` never removes stale output, so the +tsconfig test exclusion alone would leave previously-compiled `*.test.js` in a +release machine's `dist/` and ship them. `prepack` is +`rm -rf dist && tsc --sourceMap false --declarationMap false` — the clean makes +the exclusion real, and dropping the maps avoids shipping `.js.map` / +`.d.ts.map` that point at a `../src` the tarball does not contain. Plain `build` +and `prepare` keep maps, so local dev and the git-pin path are unaffected. + Smoke: ```bash +npm view @robrain/shared version # → X.Y.Z npx robrain@X.Y.Z --version npx robrain@X.Y.Z up # only if no conflicting stack already running (see below) cd packages/cli && pnpm pack:verify @@ -234,7 +276,7 @@ git tag vX.Y.Z → push tag → wait publish-perception-image.yml ✓ ↓ docker pull ghcr.io/.../robrain-perception:X.Y.Z (verify) ↓ -pnpm publish:npm (release guard must pass) +pnpm publish:npm (@robrain/shared, then robrain — release guard must pass) ↓ mcp-publisher publish (login github only if 401) ↓ diff --git a/package.json b/package.json index b7f377e..ac3efea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "robrain-monorepo", - "version": "2.4.8", + "version": "2.4.9", "description": "Institutional memory for AI coding agents \u2014 capture decisions, rejected alternatives, and rationale across sessions", "license": "Apache-2.0", "private": true, @@ -23,7 +23,7 @@ "docker:down": "docker compose -f docker/docker-compose.yml --env-file .env down", "docker:build": "pnpm prepare-env && docker compose -f docker/docker-compose.yml --env-file .env build perception", "docker:up:build": "pnpm prepare-env && docker compose -f docker/docker-compose.yml --env-file .env up -d --build perception", - "publish:npm": "pnpm --filter @robrain/sensing-mcp build && pnpm --filter @robrain/synthesis build && pnpm --filter robrain publish --access public --no-git-checks" + "publish:npm": "pnpm --filter robrain build && node packages/cli/scripts/verify-release-artifacts.mjs && pnpm --filter @robrain/shared publish --access public --no-git-checks && pnpm --filter @robrain/sensing-mcp build && pnpm --filter @robrain/synthesis build && pnpm --filter robrain publish --access public --no-git-checks" }, "devDependencies": { "@types/node": "^20.0.0", diff --git a/packages/cli/package.json b/packages/cli/package.json index fd6454c..be3ccac 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "robrain", - "version": "2.4.8", + "version": "2.4.9", "type": "module", "description": "RoBrain CLI for installation, setup, and memory workflows", "author": "Rory Plans, Inc.", diff --git a/packages/cli/src/commands/install.ts b/packages/cli/src/commands/install.ts index a842e9a..c3d866e 100644 --- a/packages/cli/src/commands/install.ts +++ b/packages/cli/src/commands/install.ts @@ -317,7 +317,7 @@ export async function installCommand(opts: InstallOptions): Promise { // Display only (status) — the thin client never embeds locally. ...(provisioned.embeddingProvider ? { embeddingProvider: provisioned.embeddingProvider } : {}), installedAt: new Date().toISOString(), - version: '2.4.8', + version: '2.4.9', }) spinner.succeed('MCP servers configured') @@ -526,7 +526,7 @@ async function installSelfHosted(opts: InstallOptions): Promise { ...(perceptionKey ? { perceptionKey } : {}), embeddingProvider: provider, installedAt: new Date().toISOString(), - version: '2.4.8', + version: '2.4.9', selfHosted: true, }) diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index fc5600e..4ad2d39 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -32,7 +32,7 @@ import { upCommand, downCommand, DEFAULT_IMAGE_REPO } from './commands/up.js' import { mcpCommand } from './commands/mcp.js' import { installHermesPlugin, resolveHermesHome } from './lib/hermes-plugin.js' -const VERSION = '2.4.8' +const VERSION = '2.4.9' program .name('robrain') diff --git a/packages/eval/package.json b/packages/eval/package.json index 1183410..cd4d82f 100644 --- a/packages/eval/package.json +++ b/packages/eval/package.json @@ -1,6 +1,6 @@ { "name": "@robrain/eval", - "version": "2.4.8", + "version": "2.4.9", "private": true, "type": "module", "main": "./dist/run.js", diff --git a/packages/perception-self-hosted/package.json b/packages/perception-self-hosted/package.json index 33a12fb..6d69503 100644 --- a/packages/perception-self-hosted/package.json +++ b/packages/perception-self-hosted/package.json @@ -1,6 +1,6 @@ { "name": "@robrain/perception-self-hosted", - "version": "2.4.8", + "version": "2.4.9", "private": true, "type": "module", "main": "./dist/index.js", diff --git a/packages/sensing-mcp/package.json b/packages/sensing-mcp/package.json index 2fec0cf..faabb5b 100644 --- a/packages/sensing-mcp/package.json +++ b/packages/sensing-mcp/package.json @@ -1,6 +1,6 @@ { "name": "@robrain/sensing-mcp", - "version": "2.4.8", + "version": "2.4.9", "type": "module", "description": "RoBrain Sensing MCP server \u2014 passive decision capture for AI coding agents", "license": "Apache-2.0", diff --git a/packages/sensing-mcp/src/server.ts b/packages/sensing-mcp/src/server.ts index c06101b..35a56a7 100644 --- a/packages/sensing-mcp/src/server.ts +++ b/packages/sensing-mcp/src/server.ts @@ -48,7 +48,7 @@ function resolveSessionId(raw: string | null | undefined): string { export function buildServer(): McpServer { const server = new McpServer({ name: 'sensing-mcp', - version: '2.4.8', + version: '2.4.9', }) // ───────────────────────────────────────────────────────────── diff --git a/packages/shared/LICENSE b/packages/shared/LICENSE new file mode 100644 index 0000000..14ae236 --- /dev/null +++ b/packages/shared/LICENSE @@ -0,0 +1,17 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +Copyright 2026 Rory Plans, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/packages/shared/README.md b/packages/shared/README.md new file mode 100644 index 0000000..ca0f922 --- /dev/null +++ b/packages/shared/README.md @@ -0,0 +1,46 @@ +# @robrain/shared + +Shared primitives for [RoBrain](https://github.com/adelinamart/robrain) — +database helpers, embedding and LLM providers, secret redaction, trust scoring, +and the canonical Postgres schema. + +This package is published so RoBrain services can depend on a prebuilt tarball +instead of compiling the monorepo at install time. It is not a general-purpose +library: the API tracks RoBrain's needs and moves with the monorepo's lockstep +version. + +## Install + +```bash +npm install @robrain/shared +``` + +No runtime dependencies — everything here imports only Node built-ins. Database +helpers take a structural `PoolLike`, so bring your own `pg` (or compatible) +pool. + +## Usage + +```js +import { scoreMemoryTrust, redactSecrets, embed } from '@robrain/shared' +import { loadEnv } from '@robrain/shared/load-env' +``` + +The Postgres schema ships at the package root and can be resolved directly: + +```js +import { createRequire } from 'node:module' +import { readFileSync } from 'node:fs' + +const require = createRequire(import.meta.url) +const schema = readFileSync(require.resolve('@robrain/shared/schema.sql'), 'utf8') +``` + +## Links + +- [Repository](https://github.com/adelinamart/robrain) (source lives in `packages/shared`) +- [Issues](https://github.com/adelinamart/robrain/issues) + +## License + +Apache-2.0 © Rory Plans, Inc. diff --git a/packages/shared/package.json b/packages/shared/package.json index 03c08e2..543be61 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,7 +1,18 @@ { "name": "@robrain/shared", - "version": "2.4.8", - "private": true, + "version": "2.4.9", + "description": "Shared database, embedding, and trust primitives for RoBrain", + "author": "Rory Plans, Inc.", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "git+https://github.com/adelinamart/robrain.git", + "directory": "packages/shared" + }, + "homepage": "https://github.com/adelinamart/robrain#readme", + "bugs": { + "url": "https://github.com/adelinamart/robrain/issues" + }, "main": "./dist/index.js", "types": "./dist/index.d.ts", "exports": { @@ -12,12 +23,24 @@ "./load-env": { "import": "./dist/load-env.js", "types": "./dist/load-env.d.ts" - } + }, + "./schema.sql": "./schema.sql", + "./package.json": "./package.json" + }, + "files": [ + "dist", + "schema.sql", + "README.md", + "LICENSE" + ], + "publishConfig": { + "access": "public" }, "scripts": { - "prepare": "tsc", + "prepare": "rm -rf dist && tsc -p tsconfig.publish.json", + "prepack": "rm -rf dist && tsc -p tsconfig.publish.json", "build": "tsc", - "typecheck": "tsc --noEmit", + "typecheck": "tsc -p tsconfig.typecheck.json --noEmit", "test": "bun test src" }, "devDependencies": { diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json index d9bb3e8..e8996d8 100644 --- a/packages/shared/tsconfig.json +++ b/packages/shared/tsconfig.json @@ -18,5 +18,9 @@ "rootDir": "./src", "outDir": "./dist" }, - "include": ["src/**/*"] + "include": ["src/**/*"], + // Tests run from source via `bun test src`; keeping them out of the build + // keeps compiled tests out of dist/ and therefore out of the npm tarball. + // `tsconfig.typecheck.json` re-includes them for type checking. + "exclude": ["src/**/*.test.ts"] } diff --git a/packages/shared/tsconfig.publish.json b/packages/shared/tsconfig.publish.json new file mode 100644 index 0000000..0b696e0 --- /dev/null +++ b/packages/shared/tsconfig.publish.json @@ -0,0 +1,12 @@ +{ + // Build config for anything that produces a consumable artifact: the npm + // tarball (`prepack`) and git-path installs (`prepare`). Maps are off because + // `files` does not ship `src/`, so published `.js.map` / `.d.ts.map` would + // point at a `../src` that isn't in the tarball. Local dev uses `build` + // (plain tsconfig.json), which keeps maps. + "extends": "./tsconfig.json", + "compilerOptions": { + "sourceMap": false, + "declarationMap": false + } +} diff --git a/packages/shared/tsconfig.typecheck.json b/packages/shared/tsconfig.typecheck.json new file mode 100644 index 0000000..b0a311d --- /dev/null +++ b/packages/shared/tsconfig.typecheck.json @@ -0,0 +1,8 @@ +{ + // Type checking only: same options as the build, but tests included. + // The build config excludes `src/**/*.test.ts` so compiled tests stay out of + // dist/ (and the published tarball) — they still need to typecheck. + "extends": "./tsconfig.json", + "include": ["src/**/*"], + "exclude": [] +} diff --git a/packages/synthesis/package.json b/packages/synthesis/package.json index 844847b..615f323 100644 --- a/packages/synthesis/package.json +++ b/packages/synthesis/package.json @@ -1,6 +1,6 @@ { "name": "@robrain/synthesis", - "version": "2.4.8", + "version": "2.4.9", "private": true, "type": "module", "main": "./dist/index.js", diff --git a/plugins/claude-code/.claude-plugin/plugin.json b/plugins/claude-code/.claude-plugin/plugin.json index 308e22d..74c4d22 100644 --- a/plugins/claude-code/.claude-plugin/plugin.json +++ b/plugins/claude-code/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "robrain", - "version": "2.4.8", + "version": "2.4.9", "description": "Institutional memory for AI coding agents: deterministic decision capture and pre-task warnings about previously REJECTED approaches, backed by your self-hosted RoBrain stack.", "author": { "name": "Rory Plans", diff --git a/server.json b/server.json index 5458f2f..a2ab882 100644 --- a/server.json +++ b/server.json @@ -6,13 +6,13 @@ "url": "https://github.com/adelinamart/robrain", "source": "github" }, - "version": "2.4.8", + "version": "2.4.9", "packages": [ { "registryType": "npm", "registryBaseUrl": "https://registry.npmjs.org", "identifier": "robrain", - "version": "2.4.8", + "version": "2.4.9", "transport": { "type": "stdio" },