From 91017b42f42bfe117f7812e90122464580c187a9 Mon Sep 17 00:00:00 2001 From: gavin09527 Date: Mon, 20 Jul 2026 16:02:00 +0800 Subject: [PATCH 1/2] fix: make SDK_VERSION bundling-safe (hardcoded literal + drift-guard test); 1.0.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.0.0 derived SDK_VERSION via `createRequire(import.meta.url)('../package.json')`. That runtime read does NOT survive bundling: when a consumer inlines the SDK into a self-contained artifact, the call is preserved and tries to resolve `../package.json` relative to the consumer's bundle at load time — which throws when the bundle runs in isolation (surfaced by claude-openmax's self-contained bundle smoke test: `Cannot find module '../package.json'`). - src/index.js: SDK_VERSION is now a hardcoded literal '1.0.1'; dropped the now-unused createRequire import. No runtime package.json read remains in the library source, so nothing breaks when the SDK is bundled. - src/version.test.js: drift guard — asserts SDK_VERSION === package.json.version (reading package.json in a test is safe; tests are never bundled). This keeps the anti-drift guarantee that motivated the original createRequire approach, but enforced at CI time instead of library runtime. - bump to 1.0.1 (patch): the fix is a behavior fix for bundling consumers. npm test 309/309; semgrep 0 findings. Co-Authored-By: Claude Opus 4.8 --- package-lock.json | 4 ++-- package.json | 2 +- src/index.js | 11 +++++++---- src/version.test.js | 15 +++++++++++++++ 4 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 src/version.test.js diff --git a/package-lock.json b/package-lock.json index 8fcc657..0e64660 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@openmaxai/openmax-agent-sdk", - "version": "1.0.0", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@openmaxai/openmax-agent-sdk", - "version": "1.0.0", + "version": "1.0.1", "license": "UNLICENSED", "dependencies": { "ws": "^8.21.0" diff --git a/package.json b/package.json index a5cacd5..802fb23 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@openmaxai/openmax-agent-sdk", - "version": "1.0.0", + "version": "1.0.1", "description": "CWS agent runtime SDK — cws-comm protocol layer (WS/auth/heartbeat/reconnect, sync, message codec, tm/kb/as/comm/core/conn service clients) extracted from zylos-openmax; consumed by runtime adapters.", "type": "module", "main": "src/index.js", diff --git a/src/index.js b/src/index.js index 505cc33..8be8103 100644 --- a/src/index.js +++ b/src/index.js @@ -4,8 +4,6 @@ * Scaffold. Modules are re-exported here as they are extracted from * zylos-openmax (Phase A). Current tranche: providers. */ -import { createRequire } from 'node:module'; - export * from './providers.js'; // ── transport layer (Phase A · milestone 1) ───────────────────────────────── @@ -70,5 +68,10 @@ export * from './identity/self-name-hydration.js'; // createSelfNameHydrator // CLI shells) stays in the adapter behind the injected providers/callbacks. export * from './orchestrator.js'; // CwsAgentBridge -// Sourced from package.json so it never drifts from the released version. -export const SDK_VERSION = createRequire(import.meta.url)('../package.json').version; +// Hardcoded literal, NOT a runtime read of package.json. A `createRequire(...) +// ('../package.json')` here does not survive bundling: when a consumer inlines +// the SDK into a self-contained artifact, that call is preserved and resolves +// `../package.json` relative to the CONSUMER's bundle at runtime — which fails +// when the bundle is loaded in isolation. The `SDK_VERSION` test asserts this +// literal stays in sync with package.json, so it can never silently drift. +export const SDK_VERSION = '1.0.1'; diff --git a/src/version.test.js b/src/version.test.js new file mode 100644 index 0000000..bac3be9 --- /dev/null +++ b/src/version.test.js @@ -0,0 +1,15 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { createRequire } from 'node:module'; +import { SDK_VERSION } from './index.js'; + +// `SDK_VERSION` is a hardcoded literal in src/index.js — deliberately NOT a +// runtime `createRequire('../package.json')`, because that call does not survive +// bundling: a consumer inlining the SDK into a self-contained artifact would +// carry the read into their bundle, where `../package.json` fails to resolve at +// runtime. This test is the drift guard — reading package.json here is safe +// because tests run in-repo (package.json present) and are never bundled. +test('SDK_VERSION matches package.json version', () => { + const pkg = createRequire(import.meta.url)('../package.json'); + assert.equal(SDK_VERSION, pkg.version); +}); From fd805e5c763c31f9d92ad0c5adec8b27a961886f Mon Sep 17 00:00:00 2001 From: gavin09527 Date: Mon, 20 Jul 2026 16:11:00 +0800 Subject: [PATCH 2/2] docs: add RELEASING.md (which files to bump on a version change) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documents the version-bump checklist so future releases stay consistent: - the files that must change (package.json, package-lock.json, the SDK_VERSION literal in src/index.js, README prose) and which are CI-enforced; - the explicit DO-NOT: never revert SDK_VERSION to a runtime package.json read (bundling regression) — keep the literal + drift test; - the tag → release.yml → release-env approval → npm publish flow and the automatic latest/alpha dist-tag rule; - the promote-dist-tag escape hatch. Adds a one-line pointer to it from the README version note. Co-Authored-By: Claude Opus 4.8 --- README.md | 3 +++ RELEASING.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 RELEASING.md diff --git a/README.md b/README.md index 497bfd9..f093623 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,9 @@ npm i @openmaxai/openmax-agent-sdk > resolves it via the `latest` dist-tag. Pre-1.0 alphas remain available under the > `alpha` dist-tag for history. +> Cutting a new version? See **[`RELEASING.md`](./RELEASING.md)** for the exact +> files to bump and the release flow. + **In the SDK** (generic CWS + agent-level concerns): - **transport/** — `WsClient` (auth, heartbeat, client keepalive-ping + frame-watchdog, exponential-backoff reconnect, 4001–4006 close-code handling), HTTP client (native `fetch` + auth), CF-Access headers, token/identity management. diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..72c70ba --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,70 @@ +# Releasing / bumping the SDK version + +This is the checklist for cutting a new version of +`@openmaxai/openmax-agent-sdk`. Follow it exactly — the version string lives in +more than one place on purpose, and CI will fail if they drift. + +## 1. Files to change on every version bump + +| File | What to change | Enforced by | +| --- | --- | --- | +| `package.json` | `version` field | `release.yml` refuses to publish unless the git tag matches this | +| `package-lock.json` | root `version` **and** `packages[""].version` — just run `npm install` to regenerate both | — | +| `src/index.js` | the `SDK_VERSION` **literal** — must equal `package.json` `version` | `src/version.test.js` (CI fails on any mismatch) | +| `README.md` | the "first stable release" note near the top and the release-summary paragraph near the bottom, **if** the human-facing notes change | — (prose; not machine-checked) | + +That's the whole set. A single `npm install` after editing `package.json` +handles the lockfile; the other two are hand edits. + +## 2. Do NOT + +- **Do not turn `SDK_VERSION` back into a runtime read of `package.json`** + (e.g. `createRequire(import.meta.url)('../package.json').version`). It reads + cleanly when the SDK runs from its own installed package, but it does **not + survive bundling**: a consumer that inlines the SDK into a self-contained + artifact carries the read into their bundle, where `../package.json` fails to + resolve at load time. That regression is exactly why `SDK_VERSION` is a + literal today. Keep it a literal; `src/version.test.js` is the drift guard so + you get the anti-drift guarantee without the runtime read. +- **Do not touch these — they are not the package version:** + - `src/orchestrator.js` `reporters.version` (a reporter payload default, + supplied by the host adapter). + - `CONTRACT.md` / `schemas/v1/**` `version` fields — the protocol contract is + versioned **independently** of the npm package. + +## 3. Release steps + +1. Branch off `main`; bump the files in §1. +2. Verify locally: `npm test` (must be green, incl. the `SDK_VERSION` drift + guard) and — if you touched anything the scanners see — the same Semgrep + command CI runs. +3. Push, open a PR. **Required CI must pass**: `test (node 20)`, + `test (node 22)`, `semgrep`, `gitleaks`. Get an approval from **someone + other than the last pusher** (org branch ruleset). Merge to `main`. +4. Tag the merged commit and push the tag: + ```bash + git tag -a vX.Y.Z -m "vX.Y.Z" + git push origin vX.Y.Z + ``` + The tag **must** match `package.json` `version` (release.yml checks this) and + point at a commit contained in protected `main` (release.yml checks this too + — an unmerged commit is refused). +5. Pushing `v*` triggers **`release.yml`**, which pauses at the `release` + environment approval gate. A reviewer approves the deployment, then it runs + `npm publish --provenance`. +6. **dist-tag is automatic** from the version shape: + - stable (no hyphen, e.g. `1.0.1`) → published to **`latest`**; + - prerelease (a hyphen, e.g. `1.1.0-alpha.0`) → published to **`alpha`**, + and `latest` is left untouched (a stable already exists). + +## 4. Fixing a dist-tag after the fact + +Use the **`promote-dist-tag`** workflow (Actions → Run workflow). It moves a +dist-tag (e.g. `latest`) onto an already-published version from CI, gated by the +same `release` environment — no local `npm login` needed. It refuses to point a +tag at a version that was never published. + +## 5. Versioning scheme + +Semver. Prereleases use `-alpha.N`. Patch = fixes (incl. behavior fixes for +consumers, like a bundling fix); minor = additive API; major = breaking changes.