Compare commits

...

1 Commits

Author SHA1 Message Date
jif-oai
7df70d6500 feat: split SDKs by target for NPM 2026-02-11 19:39:26 +00:00
6 changed files with 159 additions and 14 deletions

View File

@@ -601,6 +601,9 @@ jobs:
"codex-npm-win32-*-${version}.tgz"
"codex-responses-api-proxy-npm-${version}.tgz"
"codex-sdk-npm-${version}.tgz"
"codex-sdk-npm-linux-*-${version}.tgz"
"codex-sdk-npm-darwin-*-${version}.tgz"
"codex-sdk-npm-win32-*-${version}.tgz"
)
for pattern in "${patterns[@]}"; do
gh release download "$tag" \
@@ -638,6 +641,11 @@ jobs:
platform="${platform%-${VERSION}.tgz}"
tag="${prefix}${platform}"
;;
codex-sdk-npm-linux-*-"${VERSION}".tgz|codex-sdk-npm-darwin-*-"${VERSION}".tgz|codex-sdk-npm-win32-*-"${VERSION}".tgz)
platform="${filename#codex-sdk-npm-}"
platform="${platform%-${VERSION}.tgz}"
tag="${prefix}${platform}"
;;
codex-npm-"${VERSION}".tgz|codex-responses-api-proxy-npm-"${VERSION}".tgz|codex-sdk-npm-"${VERSION}".tgz)
tag="${NPM_TAG}"
;;

View File

@@ -18,6 +18,11 @@ When `--package codex` is provided, the staging helper builds the lightweight
`@openai/codex` meta package plus all platform-native `@openai/codex` variants
that are later published under platform-specific dist-tags.
When `--package codex-sdk` is provided, the staging helper now follows the same
pattern: it builds a lightweight `@openai/codex-sdk` meta package plus
platform-native `@openai/codex-sdk` variants published under platform-specific
dist-tags.
If you need to invoke `build_npm_package.py` directly, run
`codex-cli/scripts/install_native_deps.py` first and pass `--vendor-src` pointing to the
directory that contains the populated `vendor/` tree.

View File

@@ -15,6 +15,7 @@ REPO_ROOT = CODEX_CLI_ROOT.parent
RESPONSES_API_PROXY_NPM_ROOT = REPO_ROOT / "codex-rs" / "responses-api-proxy" / "npm"
CODEX_SDK_ROOT = REPO_ROOT / "sdk" / "typescript"
CODEX_NPM_NAME = "@openai/codex"
CODEX_SDK_NPM_NAME = "@openai/codex-sdk"
# `npm_name` is the local optional-dependency alias consumed by `bin/codex.js`.
# The underlying package published to npm is always `@openai/codex`.
@@ -63,8 +64,56 @@ CODEX_PLATFORM_PACKAGES: dict[str, dict[str, str]] = {
},
}
# `npm_name` is the local optional-dependency alias consumed by `sdk/typescript/src/exec.ts`.
# The underlying package published to npm is always `@openai/codex-sdk`.
CODEX_SDK_PLATFORM_PACKAGES: dict[str, dict[str, str]] = {
"codex-sdk-linux-x64": {
"npm_name": "@openai/codex-sdk-linux-x64",
"npm_tag": "linux-x64",
"target_triple": "x86_64-unknown-linux-musl",
"os": "linux",
"cpu": "x64",
},
"codex-sdk-linux-arm64": {
"npm_name": "@openai/codex-sdk-linux-arm64",
"npm_tag": "linux-arm64",
"target_triple": "aarch64-unknown-linux-musl",
"os": "linux",
"cpu": "arm64",
},
"codex-sdk-darwin-x64": {
"npm_name": "@openai/codex-sdk-darwin-x64",
"npm_tag": "darwin-x64",
"target_triple": "x86_64-apple-darwin",
"os": "darwin",
"cpu": "x64",
},
"codex-sdk-darwin-arm64": {
"npm_name": "@openai/codex-sdk-darwin-arm64",
"npm_tag": "darwin-arm64",
"target_triple": "aarch64-apple-darwin",
"os": "darwin",
"cpu": "arm64",
},
"codex-sdk-win32-x64": {
"npm_name": "@openai/codex-sdk-win32-x64",
"npm_tag": "win32-x64",
"target_triple": "x86_64-pc-windows-msvc",
"os": "win32",
"cpu": "x64",
},
"codex-sdk-win32-arm64": {
"npm_name": "@openai/codex-sdk-win32-arm64",
"npm_tag": "win32-arm64",
"target_triple": "aarch64-pc-windows-msvc",
"os": "win32",
"cpu": "arm64",
},
}
PACKAGE_EXPANSIONS: dict[str, list[str]] = {
"codex": ["codex", *CODEX_PLATFORM_PACKAGES],
"codex-sdk": ["codex-sdk", *CODEX_SDK_PLATFORM_PACKAGES],
}
PACKAGE_NATIVE_COMPONENTS: dict[str, list[str]] = {
@@ -76,13 +125,25 @@ PACKAGE_NATIVE_COMPONENTS: dict[str, list[str]] = {
"codex-win32-x64": ["codex", "rg", "codex-windows-sandbox-setup", "codex-command-runner"],
"codex-win32-arm64": ["codex", "rg", "codex-windows-sandbox-setup", "codex-command-runner"],
"codex-responses-api-proxy": ["codex-responses-api-proxy"],
"codex-sdk": ["codex"],
"codex-sdk": [],
"codex-sdk-linux-x64": ["codex"],
"codex-sdk-linux-arm64": ["codex"],
"codex-sdk-darwin-x64": ["codex"],
"codex-sdk-darwin-arm64": ["codex"],
"codex-sdk-win32-x64": ["codex", "codex-windows-sandbox-setup", "codex-command-runner"],
"codex-sdk-win32-arm64": ["codex", "codex-windows-sandbox-setup", "codex-command-runner"],
}
PACKAGE_TARGET_FILTERS: dict[str, str] = {
package_name: package_config["target_triple"]
for package_name, package_config in CODEX_PLATFORM_PACKAGES.items()
}
PACKAGE_TARGET_FILTERS.update(
{
package_name: package_config["target_triple"]
for package_name, package_config in CODEX_SDK_PLATFORM_PACKAGES.items()
}
)
PACKAGE_CHOICES = tuple(PACKAGE_NATIVE_COMPONENTS)
@@ -194,7 +255,7 @@ def main() -> int:
"Verify the responses API proxy:\n"
f" node {staging_dir_str}/bin/codex-responses-api-proxy.js --help\n\n"
)
elif package in CODEX_PLATFORM_PACKAGES:
elif package in CODEX_PLATFORM_PACKAGES or package in CODEX_SDK_PLATFORM_PACKAGES:
print(
f"Staged version {version} for release in {staging_dir_str}\n\n"
"Verify native payload contents:\n"
@@ -205,7 +266,6 @@ def main() -> int:
f"Staged version {version} for release in {staging_dir_str}\n\n"
"Verify the SDK contents:\n"
f" ls {staging_dir_str}/dist\n"
f" ls {staging_dir_str}/vendor\n"
" node -e \"import('./dist/index.js').then(() => console.log('ok'))\"\n\n"
)
else:
@@ -280,6 +340,39 @@ def stage_sources(staging_dir: Path, version: str, package: str) -> None:
package_manager = codex_package_json.get("packageManager")
if isinstance(package_manager, str):
package_json["packageManager"] = package_manager
elif package in CODEX_SDK_PLATFORM_PACKAGES:
platform_package = CODEX_SDK_PLATFORM_PACKAGES[package]
platform_npm_tag = platform_package["npm_tag"]
platform_version = compute_platform_package_version(version, platform_npm_tag)
readme_src = CODEX_SDK_ROOT / "README.md"
if readme_src.exists():
shutil.copy2(readme_src, staging_dir / "README.md")
license_src = REPO_ROOT / "LICENSE"
if license_src.exists():
shutil.copy2(license_src, staging_dir / "LICENSE")
with open(CODEX_SDK_ROOT / "package.json", "r", encoding="utf-8") as fh:
codex_sdk_package_json = json.load(fh)
package_json = {
"name": CODEX_SDK_NPM_NAME,
"version": platform_version,
"license": codex_sdk_package_json.get("license", "Apache-2.0"),
"os": [platform_package["os"]],
"cpu": [platform_package["cpu"]],
"files": ["vendor"],
"repository": codex_sdk_package_json.get("repository"),
}
engines = codex_sdk_package_json.get("engines")
if isinstance(engines, dict):
package_json["engines"] = engines
package_manager = codex_sdk_package_json.get("packageManager")
if isinstance(package_manager, str):
package_json["packageManager"] = package_manager
elif package == "codex-responses-api-proxy":
bin_dir = staging_dir / "bin"
bin_dir.mkdir(parents=True, exist_ok=True)
@@ -318,12 +411,15 @@ def stage_sources(staging_dir: Path, version: str, package: str) -> None:
if isinstance(scripts, dict):
scripts.pop("prepare", None)
files = package_json.get("files")
if isinstance(files, list):
if "vendor" not in files:
files.append("vendor")
else:
package_json["files"] = ["dist", "vendor"]
package_json["files"] = ["dist"]
package_json["optionalDependencies"] = {
CODEX_SDK_PLATFORM_PACKAGES[platform_package]["npm_name"]: (
f"npm:{CODEX_SDK_NPM_NAME}@"
f"{compute_platform_package_version(version, CODEX_SDK_PLATFORM_PACKAGES[platform_package]['npm_tag'])}"
)
for platform_package in PACKAGE_EXPANSIONS["codex-sdk"]
if platform_package != "codex-sdk"
}
with open(staging_dir / "package.json", "w", encoding="utf-8") as out:
json.dump(package_json, out, indent=2)

View File

@@ -27,6 +27,7 @@ _SPEC.loader.exec_module(_BUILD_MODULE)
PACKAGE_NATIVE_COMPONENTS = getattr(_BUILD_MODULE, "PACKAGE_NATIVE_COMPONENTS", {})
PACKAGE_EXPANSIONS = getattr(_BUILD_MODULE, "PACKAGE_EXPANSIONS", {})
CODEX_PLATFORM_PACKAGES = getattr(_BUILD_MODULE, "CODEX_PLATFORM_PACKAGES", {})
CODEX_SDK_PLATFORM_PACKAGES = getattr(_BUILD_MODULE, "CODEX_SDK_PLATFORM_PACKAGES", {})
def parse_args() -> argparse.Namespace:
@@ -134,6 +135,9 @@ def tarball_name_for_package(package: str, version: str) -> str:
if package in CODEX_PLATFORM_PACKAGES:
platform = package.removeprefix("codex-")
return f"codex-npm-{platform}-{version}.tgz"
if package in CODEX_SDK_PLATFORM_PACKAGES:
platform = package.removeprefix("codex-sdk-")
return f"codex-sdk-npm-{platform}-{version}.tgz"
return f"{package}-npm-{version}.tgz"

View File

@@ -11,6 +11,7 @@ npm install @openai/codex-sdk
```
Requires Node.js 18+.
The package installs a platform-specific native Codex binary via optional dependencies.
## Quickstart

View File

@@ -1,4 +1,6 @@
import { spawn } from "node:child_process";
import { existsSync } from "node:fs";
import { createRequire } from "node:module";
import path from "node:path";
import readline from "node:readline";
import { fileURLToPath } from "node:url";
@@ -41,6 +43,7 @@ export type CodexExecArgs = {
const INTERNAL_ORIGINATOR_ENV = "CODEX_INTERNAL_ORIGINATOR_OVERRIDE";
const TYPESCRIPT_SDK_ORIGINATOR = "codex_sdk_ts";
const nodeRequire = createRequire(import.meta.url);
export class CodexExec {
private executablePath: string;
@@ -300,6 +303,14 @@ function isPlainObject(value: unknown): value is CodexConfigObject {
const scriptFileName = fileURLToPath(import.meta.url);
const scriptDirName = path.dirname(scriptFileName);
const PLATFORM_PACKAGE_BY_TARGET = {
"x86_64-unknown-linux-musl": "@openai/codex-sdk-linux-x64",
"aarch64-unknown-linux-musl": "@openai/codex-sdk-linux-arm64",
"x86_64-apple-darwin": "@openai/codex-sdk-darwin-x64",
"aarch64-apple-darwin": "@openai/codex-sdk-darwin-arm64",
"x86_64-pc-windows-msvc": "@openai/codex-sdk-win32-x64",
"aarch64-pc-windows-msvc": "@openai/codex-sdk-win32-arm64",
};
function findCodexPath() {
const { platform, arch } = process;
@@ -351,10 +362,30 @@ function findCodexPath() {
throw new Error(`Unsupported platform: ${platform} (${arch})`);
}
const vendorRoot = path.join(scriptDirName, "..", "vendor");
const archRoot = path.join(vendorRoot, targetTriple);
const codexBinaryName = process.platform === "win32" ? "codex.exe" : "codex";
const binaryPath = path.join(archRoot, "codex", codexBinaryName);
const platformPackage = PLATFORM_PACKAGE_BY_TARGET[targetTriple as keyof typeof PLATFORM_PACKAGE_BY_TARGET];
if (!platformPackage) {
throw new Error(`Unsupported target triple: ${targetTriple}`);
}
return binaryPath;
const codexBinaryName = process.platform === "win32" ? "codex.exe" : "codex";
const localVendorRoot = path.join(scriptDirName, "..", "vendor");
const localBinaryPath = path.join(localVendorRoot, targetTriple, "codex", codexBinaryName);
let vendorRoot: string | null = null;
try {
const packageJsonPath = nodeRequire.resolve(`${platformPackage}/package.json`);
vendorRoot = path.join(path.dirname(packageJsonPath), "vendor");
} catch {
if (existsSync(localBinaryPath)) {
vendorRoot = localVendorRoot;
}
}
if (!vendorRoot) {
throw new Error(
`Missing optional dependency ${platformPackage}. Reinstall @openai/codex-sdk: npm install @openai/codex-sdk`,
);
}
return path.join(vendorRoot, targetTriple, "codex", codexBinaryName);
}