Skip to content

Commit 4dc0359

Browse files
committed
chore: release v0.14.0
1 parent faf90d1 commit 4dc0359

File tree

9 files changed

+110
-24
lines changed

9 files changed

+110
-24
lines changed

CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,20 @@
11
# Changelog
22

3+
## [0.14.0] - 2025-11-10
4+
### 🚀 Enhancements
5+
- Added `createHeadlessCodex()` helper that auto-registers the adapter and returns a coder, reducing the boilerplate needed in most server runtimes.
6+
- Codex adapter now enforces a Node-only runtime, guards worker spawns, and exposes the worker path via `new URL('./worker.js', import.meta.url)` so bundlers have a deterministic asset to copy.
7+
- README docs call out the server-only requirement and provide lazy-loading snippets for frameworks like Next.js.
8+
9+
### 🛠 DX
10+
- Added runtime guards/warnings that keep browser bundlers from crashing by tree-shaking the `child_process` fork when it’s unreachable.
11+
312
## [0.13.1] - 2025-11-10
413
### ✨ Packaging & DX
514
- Core and every adapter now emit real entry points via `tsup`, producing both ESM (`dist/*.js`) and CommonJS (`dist/*.cjs`) bundles with colocated typings, so downstream apps can import the declared exports without diving into `dist/*/src` internals.
615
- Updated exports maps to expose `factory`, `types`, adapter workers, and `package.json`, unlocking better metadata discovery and `require()` support.
716
- Codex adapter gained a README that documents the worker co-location requirement, plus LICENSE files were added to every publishable package for npm completeness.
8-
- Bumped `@openai/codex-sdk` to `0.57.0` and refreshed peer dependency ranges to `^0.13.0` across the adapters.
17+
- Bumped `@openai/codex-sdk` to `0.57.0` and refreshed peer dependency ranges to `^0.14.0` across the adapters.
918

1019
### 🧪 Tooling
1120
- Added `npm run smoke`, which builds, packs, and installs the tarballs into a throwaway project to verify both CommonJS and ESM consumers and assert that the Codex worker ships beside the entry point.

README.md

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,9 @@ npm i @headless-coder-sdk/core @headless-coder-sdk/codex-adapter
3838
```
3939

4040
```ts
41-
import { registerAdapter, createCoder } from '@headless-coder-sdk/core';
42-
import { CODER_NAME as CODEX, createAdapter as createCodex } from '@headless-coder-sdk/codex-adapter';
41+
import { createHeadlessCodex } from '@headless-coder-sdk/codex-adapter';
4342

44-
registerAdapter(CODEX, createCodex);
45-
46-
const coder = createCoder(CODEX);
43+
const coder = createHeadlessCodex({ workingDirectory: process.cwd() });
4744
const thread = await coder.startThread();
4845
const result = await thread.run('Write a hello world script');
4946
console.log(result.text);
@@ -239,6 +236,38 @@ In this workflow two reviewers (Claude, Codex) analyze the same commit in parall
239236

240237
---
241238

239+
## ⚠️ Codex Adapter Runtime
240+
241+
- The Codex adapter forks worker processes via Node’s `child_process` API and **must run on the server**. It is safe to import in build tooling, but gate runtime usage to environments where `process.versions.node` exists.
242+
- A convenience helper, `createHeadlessCodex`, registers the adapter and returns a coder in one call:
243+
244+
```ts
245+
import { createHeadlessCodex } from '@headless-coder-sdk/codex-adapter';
246+
247+
if (typeof window !== 'undefined') {
248+
throw new Error('Codex adapter is server-only');
249+
}
250+
251+
const codex = createHeadlessCodex({ workingDirectory: process.cwd() });
252+
```
253+
254+
- In frameworks like Next.js, lazy-load the helper inside server components or API routes to avoid bundling it client-side:
255+
256+
```ts
257+
export async function POST() {
258+
if (typeof window !== 'undefined') {
259+
throw new Error('Codex must run on the server');
260+
}
261+
const { createHeadlessCodex } = await import('@headless-coder-sdk/codex-adapter');
262+
const coder = createHeadlessCodex({ workingDirectory: process.cwd() });
263+
const thread = await coder.startThread();
264+
const result = await thread.run('List recent commits');
265+
return Response.json({ text: result.text });
266+
}
267+
```
268+
269+
---
270+
242271
## ⚙️ Development
243272

244273
**Install**
@@ -299,6 +328,7 @@ Open an [issue](https://github.com/OhadAssulin/headless-coder-sdk/issues) or sub
299328
## 📦 Distribution Notes
300329

301330
- Every workspace now emits flattened entry points at `dist/*.js` (ESM) and `dist/*.cjs` (CommonJS), with `.d.ts` files sitting beside them for better editor support.
331+
- You can import `createCoder` or helper utilities directly from `@headless-coder-sdk/core` and `@headless-coder-sdk/codex-adapter` without deep `dist/*/src` paths—the `main`/`module` fields now point at those root files.
302332
- `package.json` is exposed via the exports map (`import '@headless-coder-sdk/core/package.json'`) for tooling that needs to inspect versions at runtime.
303333
- `@headless-coder-sdk/codex-adapter` forks a worker via `fileURLToPath(new URL('./worker.js', import.meta.url))`; keep `dist/worker.js` adjacent when rebundling so that child processes can spawn correctly.
304334

packages/claude-adapter/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@headless-coder-sdk/claude-adapter",
3-
"version": "0.13.0",
3+
"version": "0.14.0",
44
"type": "module",
55
"main": "./dist/index.cjs",
66
"module": "./dist/index.js",
@@ -19,7 +19,7 @@
1919
},
2020
"peerDependencies": {
2121
"@anthropic-ai/claude-agent-sdk": "*",
22-
"@headless-coder-sdk/core": "^0.13.0"
22+
"@headless-coder-sdk/core": "^0.14.0"
2323
},
2424
"devDependencies": {
2525
"typescript": "^5.4.0",

packages/codex-adapter/README.md

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,37 @@ npm install @headless-coder-sdk/core @headless-coder-sdk/codex-adapter
1111
## Usage
1212

1313
```ts
14-
import { registerAdapter, createCoder } from '@headless-coder-sdk/core';
15-
import { CODER_NAME as CODEX, createAdapter } from '@headless-coder-sdk/codex-adapter';
14+
import { createHeadlessCodex } from '@headless-coder-sdk/codex-adapter';
1615

17-
registerAdapter(CODEX, createAdapter);
18-
const coder = createCoder(CODEX, { workingDirectory: process.cwd() });
16+
if (typeof window !== 'undefined') {
17+
throw new Error('Codex adapter is server-only');
18+
}
19+
20+
const coder = createHeadlessCodex({ workingDirectory: process.cwd() });
1921
const thread = await coder.startThread();
2022
const turn = await thread.run('Write unit tests for the git helper.');
2123
console.log(turn.text);
2224
```
2325

26+
`createHeadlessCodex` registers the adapter (if necessary) and returns a coder in one call so you no longer have to wire up `registerAdapter` manually.
27+
28+
## Next.js / server frameworks
29+
30+
The adapter forks worker processes via Node’s `child_process`, so keep it on the server:
31+
32+
```ts
33+
export async function POST() {
34+
if (typeof window !== 'undefined') {
35+
throw new Error('Codex adapter must run on the server');
36+
}
37+
const { createHeadlessCodex } = await import('@headless-coder-sdk/codex-adapter');
38+
const coder = createHeadlessCodex({ workingDirectory: process.cwd() });
39+
const thread = await coder.startThread();
40+
const result = await thread.run('List open pull requests');
41+
return Response.json({ text: result.text });
42+
}
43+
```
44+
2445
## Worker placement
2546

2647
- The adapter forks a worker via `fileURLToPath(new URL('./worker.js', import.meta.url))`.

packages/codex-adapter/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@headless-coder-sdk/codex-adapter",
3-
"version": "0.13.0",
3+
"version": "0.14.0",
44
"type": "module",
55
"main": "./dist/index.cjs",
66
"module": "./dist/index.js",
@@ -27,7 +27,7 @@
2727
"build": "tsup --config tsup.config.ts"
2828
},
2929
"peerDependencies": {
30-
"@headless-coder-sdk/core": "^0.13.0",
30+
"@headless-coder-sdk/core": "^0.14.0",
3131
"@openai/codex-sdk": "^0.57.0"
3232
},
3333
"devDependencies": {

packages/codex-adapter/src/index.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@
55

66
import { fork, ChildProcess } from 'node:child_process';
77
import path from 'node:path';
8-
import { fileURLToPath } from 'node:url';
9-
import { now } from '@headless-coder-sdk/core';
8+
import { fileURLToPath, pathToFileURL } from 'node:url';
9+
import {
10+
now,
11+
registerAdapter,
12+
getAdapterFactory,
13+
createCoder,
14+
} from '@headless-coder-sdk/core';
1015
import type {
1116
AdapterFactory,
1217
HeadlessCoder,
@@ -20,19 +25,38 @@ import type {
2025
Provider,
2126
} from '@headless-coder-sdk/core';
2227

23-
const moduleFilename = typeof __filename === 'string' ? __filename : fileURLToPath(import.meta.url);
24-
const WORKER_PATH = path.join(path.dirname(moduleFilename), 'worker.js');
28+
const moduleUrl =
29+
typeof __filename === 'string' ? pathToFileURL(__filename).href : import.meta.url;
30+
const workerUrl = new URL('./worker.js', moduleUrl);
31+
const WORKER_PATH = fileURLToPath(workerUrl);
2532
const SOFT_KILL_DELAY_MS = 250;
2633
const HARD_KILL_DELAY_MS = 1500;
2734
const DONE = Symbol('stream-done');
2835
const STDERR_BUFFER_LIMIT = 64 * 1024;
36+
const isNodeRuntime = typeof process !== 'undefined' && !!process.versions?.node;
37+
38+
function ensureNodeRuntime(action: string): void {
39+
if (!isNodeRuntime) {
40+
throw new Error(
41+
`@headless-coder-sdk/codex-adapter can only ${action} inside a Node.js runtime.`,
42+
);
43+
}
44+
}
2945

3046
export const CODER_NAME: Provider = 'codex';
3147
export function createAdapter(defaults?: StartOpts): HeadlessCoder {
3248
return new CodexAdapter(defaults);
3349
}
3450
(createAdapter as AdapterFactory).coderName = CODER_NAME;
3551

52+
export function createHeadlessCodex(defaults?: StartOpts): HeadlessCoder {
53+
if (!getAdapterFactory(CODER_NAME)) {
54+
registerAdapter(createAdapter as AdapterFactory);
55+
}
56+
ensureNodeRuntime('create a Codex coder');
57+
return createCoder(CODER_NAME, defaults);
58+
}
59+
3660
interface CodexThreadOptions {
3761
model?: string;
3862
sandboxMode?: 'read-only' | 'workspace-write' | 'danger-full-access';
@@ -174,6 +198,7 @@ export class CodexAdapter implements HeadlessCoder {
174198
}
175199

176200
private launchRunWorker(state: CodexThreadState, input: string, opts?: RunOpts) {
201+
ensureNodeRuntime('spawn a Codex worker');
177202
const child = fork(WORKER_PATH, { stdio: ['inherit', 'inherit', 'pipe', 'ipc'] });
178203
const stderr = collectChildStderr(child);
179204
const abortController = new AbortController();
@@ -278,6 +303,7 @@ export class CodexAdapter implements HeadlessCoder {
278303
input: string,
279304
opts?: RunOpts,
280305
): EventIterator {
306+
ensureNodeRuntime('stream Codex events');
281307
const child = fork(WORKER_PATH, { stdio: ['inherit', 'inherit', 'pipe', 'ipc'] });
282308
const stderr = collectChildStderr(child);
283309
const abortController = new AbortController();

packages/core/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@headless-coder-sdk/core",
3-
"version": "0.13.0",
3+
"version": "0.14.0",
44
"description": "Unified SDK for headless AI coders (Codex, Claude, Gemini) with standardized threading, streaming, and sandboxing.",
55
"type": "module",
66
"main": "./dist/index.cjs",

packages/gemini-adapter/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@headless-coder-sdk/gemini-adapter",
3-
"version": "0.13.0",
3+
"version": "0.14.0",
44
"type": "module",
55
"main": "./dist/index.cjs",
66
"module": "./dist/index.js",
@@ -18,7 +18,7 @@
1818
"build": "tsup --config tsup.config.ts"
1919
},
2020
"peerDependencies": {
21-
"@headless-coder-sdk/core": "^0.13.0"
21+
"@headless-coder-sdk/core": "^0.14.0"
2222
},
2323
"devDependencies": {
2424
"typescript": "^5.4.0",

pnpm-lock.yaml

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)