From 5ee7a93a1d3538fc9b625be23c9aa3d719674488 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Fri, 25 Sep 2026 21:20:33 -0700 Subject: [PATCH 1/4] chore: add the CLA --- .github/workflows/cla.yml | 53 ++++++++++++++++++++++++++++++++ CLA.md | 64 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 .github/workflows/cla.yml create mode 100644 CLA.md diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml new file mode 100644 index 0000000..a03ad39 --- /dev/null +++ b/.github/workflows/cla.yml @@ -0,0 +1,53 @@ +name: CLA Assistant + +on: + issue_comment: + types: [created] + pull_request_target: + types: [opened, synchronize] + +permissions: + actions: write + contents: write + pull-requests: write + statuses: write + +concurrency: + group: cla-${{ github.event.pull_request.number || github.event.issue.number || github.run_id }} + cancel-in-progress: true + +jobs: + cla: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Maintainer fast path + if: >- + github.event_name == 'pull_request_target' && + (contains(fromJSON('["TheGreatAxios","brianjfox"]'), github.event.pull_request.user.login) || + endsWith(github.event.pull_request.user.login, '[bot]')) + run: echo "Maintainer or bot pull request; CLA not required." + - name: CLA Assistant + if: >- + ((github.event.comment.body == 'recreate-signatures' || + github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || + github.event_name == 'pull_request_target') && + !(github.event_name == 'pull_request_target' && + (contains(fromJSON('["TheGreatAxios","brianjfox"]'), github.event.pull_request.user.login) || + endsWith(github.event.pull_request.user.login, '[bot]'))) + # corbitsdev/cla-assistant-action v2.6.1-node24: upstream v2.6.1 on node24. + uses: corbitsdev/cla-assistant-action@ef6d3e51db8232fe93090810f13bde30497c1d74 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + path-to-document: "https://github.com/${{ github.repository }}/blob/main/CLA.md" + path-to-signatures: "signatures/version1/cla.json" + branch: "cla-signatures" + allowlist: TheGreatAxios,brianjfox,*[bot] + custom-notsigned-prcomment: >- + Thank you for your contribution. Before it can be merged, please read our + [Contributor License Agreement](https://github.com/${{ github.repository }}/blob/main/CLA.md) + and sign it by posting a new comment on this pull request containing + exactly the line below (nothing else): + custom-pr-sign-comment: "I have read the CLA Document and I hereby sign the CLA" + custom-allsigned-prcomment: "All contributors have signed the CLA." diff --git a/CLA.md b/CLA.md new file mode 100644 index 0000000..201eec8 --- /dev/null +++ b/CLA.md @@ -0,0 +1,64 @@ +# Contributor License Agreement (CLA) + +Version 1.0 + +This Contributor License Agreement ("Agreement") is entered into between the contributor ("Contributor") and ABK Labs, Inc. ("Maintainer"). + +By submitting any Contribution to a project maintained by Maintainer, the Contributor agrees to the following terms. + +## 1. Definitions + +"Contribution" means any source code, object code, documentation, test cases, designs, specifications, bug fixes, enhancements, comments, pull requests, commits, issues containing code, or other materials intentionally submitted to a project maintained by Maintainer. + +## 2. Copyright Ownership + +The Contributor retains ownership of the Contributor's copyrights in the Contribution. + +No transfer of copyright ownership is required by this Agreement. + +## 3. License Grant to Maintainer + +The Contributor grants Maintainer a perpetual, worldwide, non-exclusive, irrevocable, royalty-free license to: + +- use, reproduce, modify, distribute, display, perform, and sublicense the Contribution; +- combine the Contribution with other software and works; +- distribute the Contribution under the project's current license; +- distribute the Contribution under future versions of the project's license; +- distribute the Contribution under alternative open-source, source-available, commercial, proprietary, or dual-license terms. + +## 4. License Grant to the Public + +The Contributor agrees that the Contribution may be distributed as part of the applicable project under the project's then-current license terms, including LGPL-2.1 or any successor license adopted by Maintainer. + +## 5. Contributor Representations + +The Contributor represents and warrants that: + +1. The Contributor created the Contribution or otherwise has sufficient rights to submit it. +2. The Contributor has the legal authority to grant the rights described in this Agreement. +3. To the best of the Contributor's knowledge, the Contribution does not knowingly infringe the intellectual property rights of any third party. +4. Any third-party material included in the Contribution has been properly disclosed and is compatible with the rights granted under this Agreement. + +## 6. Corporate Contributions + +If a Contribution is submitted on behalf of an employer or other legal entity, the person accepting this Agreement represents that they are authorized to bind that entity to this Agreement. + +## 7. No Obligation + +Maintainer is not obligated to use, distribute, maintain, support, or accept any Contribution. + +## 8. Disclaimer + +Except as expressly stated in this Agreement, the Contribution is provided "AS IS" without warranties or conditions of any kind. + +## 9. Electronic Acceptance + +The Contributor agrees that electronic acceptance of this Agreement, including acceptance through a website, source-control platform, click-through process, pull-request workflow, or similar mechanism, shall have the same force and effect as a handwritten signature. + +## 10. Governing Law + +This Agreement shall be governed by the laws of the State of California, excluding its conflict-of-law provisions. + +--- + +By submitting a Contribution, the Contributor acknowledges that they have read and agree to this Agreement. From c51e3871bc3c8e4aceafef3001cc7487a2d8e902 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Fri, 25 Sep 2026 21:20:33 -0700 Subject: [PATCH 2/4] build: align package.json and tsconfig with the package standard --- .gitignore | 6 ++++-- package.json | 25 ++++++++++++++++--------- tsconfig.build.json | 6 ++---- tsconfig.json | 7 +++---- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 2f6a620..6f17218 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ node_modules/ dist/ -.corbits/ -.DS_Store +*.tsbuildinfo +*.tgz +coverage/ .env .env.* +.DS_Store diff --git a/package.json b/package.json index 10c6eb8..12d5219 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,17 @@ { "name": "@corbits/xai-provider", - "version": "0.1.0", + "version": "0.1.1", "description": "xAI (Grok) OAuth config, token mapping, and a Responses adapter configured for xAI's CLI chat proxy.", - "homepage": "https://github.com/corbitsdev/corbits-xai-provider", + "keywords": [ + "corbits", + "grok", + "inference", + "interchange", + "oauth", + "responses", + "xai" + ], + "homepage": "https://github.com/corbitsdev/corbits-xai-provider#readme", "bugs": { "url": "https://github.com/corbitsdev/corbits-xai-provider/issues" }, @@ -19,8 +28,6 @@ ], "type": "module", "sideEffects": false, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", "exports": { ".": { "types": "./dist/index.d.ts", @@ -31,15 +38,15 @@ "access": "public" }, "scripts": { - "typecheck": "tsc --noEmit", - "build": "tsc -p tsconfig.build.json", + "build": "rm -rf dist && tsc -p tsconfig.build.json", "prepack": "bun run build", + "typecheck": "tsc --noEmit", "lint": "oxlint", "format": "oxfmt", "format:check": "oxfmt --check", - "test": "bun test src", - "check": "bun run typecheck && bun run lint && bun run format:check && bun run test", - "test:e2e": "bun test e2e" + "test": "bun test src --pass-with-no-tests", + "test:e2e": "bun test e2e", + "check": "bun run typecheck && bun run lint && bun run format:check && bun run test" }, "dependencies": { "arktype": "^2.2.3" diff --git a/tsconfig.build.json b/tsconfig.build.json index ba50fe1..af6694f 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,14 +1,12 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "allowImportingTsExtensions": false, - "composite": false, - "module": "NodeNext", - "moduleResolution": "NodeNext", "noEmit": false, "declaration": true, "declarationMap": false, "sourceMap": false, + "module": "NodeNext", + "moduleResolution": "NodeNext", "outDir": "dist", "rootDir": "src" }, diff --git a/tsconfig.json b/tsconfig.json index b883ac9..dda942c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,17 +3,16 @@ "esModuleInterop": true, "skipLibCheck": true, "target": "ESNext", - "allowJs": true, - "resolveJsonModule": true, + "module": "ESNext", + "moduleResolution": "bundler", "moduleDetection": "force", "isolatedModules": true, "verbatimModuleSyntax": true, - "moduleResolution": "bundler", + "resolveJsonModule": true, "strict": true, "noUncheckedIndexedAccess": true, "noImplicitOverride": true, "exactOptionalPropertyTypes": true, - "module": "ESNext", "noEmit": true, "lib": ["ESNext"], "types": ["bun"] From c8ba5355f3ee262464ef44809336dbe595a1d98a Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Fri, 25 Sep 2026 21:20:33 -0700 Subject: [PATCH 3/4] ci: run check and a Node pack smoke --- .github/workflows/ci.yml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3fe655f..49bbc54 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,22 +1,27 @@ -name: CI +name: ci on: - push: - branches: [main] pull_request: + push: branches: [main] jobs: check: runs-on: ubuntu-latest - strategy: - matrix: - node-version: [24] + timeout-minutes: 15 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: actions/setup-node@v4 with: - node-version: ${{ matrix.node-version }} + node-version: 24 - uses: oven-sh/setup-bun@v2 - run: bun install --frozen-lockfile - run: bun run check + - name: node consumer smoke + run: | + set -euo pipefail + TARBALL="$PWD/$(npm pack --silent)" + mkdir -p "$RUNNER_TEMP/c" && cd "$RUNNER_TEMP/c" + npm init -y >/dev/null && npm pkg set type=module >/dev/null + npm install "$TARBALL" + node -e 'import("@corbits/xai-provider").then((m) => { for (const n of ["createXaiResponsesAdapter", "exchangeXaiCode", "refreshXaiTokens", "xaiUserIdFromAccessToken"]) if (typeof m[n] !== "function") throw new Error("missing export: " + n); })' From afb3c0911dc4ac7f102d9bab53ca160b293eae68 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Fri, 25 Sep 2026 21:20:34 -0700 Subject: [PATCH 4/4] docs: trim CONTRIBUTING and AGENTS.md --- AGENTS.md | 31 ++++++++----------------------- CONTRIBUTING.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 23 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/AGENTS.md b/AGENTS.md index b500b42..b5389a8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,41 +13,26 @@ reimplementing OAuth or the Responses wire protocol. - `src/oauth.ts` — `xaiOAuthConfig`, token-response mapping (`idToken` carry-through), and JWT user-id decoding. - `src/responses-adapter.ts` — `xaiResponsesQuirks` and `createXaiResponsesAdapter`, xAI's config for `@corbits/openai-responses`. - `src/index.ts` — the public surface; nothing else is imported by consumers. +- `src/*.test.ts` — unit tests, excluded from the build. +- `e2e/live.test.ts` — the opt-in live suite (`XAI_LIVE_ACCESS_TOKEN`). ## Rules -- Consume `@intx/*` and the two `@corbits/*` packages (all peer dependencies) as packages only — never vendor or fork them. +- Consume `@intx/*` (`^0.4.0`) and the two `@corbits/*` packages (`^0.1.0`) as peer dependencies, pinned exactly in `devDependencies` — never vendor or fork them. - Parse every trust boundary with arktype (JWT payload); never `as T` untrusted input. - `exactOptionalPropertyTypes` is on: omit optional keys, never assign `undefined` to them. - No product strings baked in; the x-grok-\* headers and user-agent are xAI wire requirements, not branding. - Tests exist only for load-bearing risk: the exact wire request shape the proxy accepts, and JWT user-id decode that must not throw on garbage. +- Relative imports in `src/` carry explicit `.js` suffixes so the emitted ESM runs under Node; never add a build-time rewrite script or a bundler. - Time, randomness, and `fetch` stay injectable so callers can test without patching globals. ## Local development ```sh -bun install -bun run check # typecheck + lint + format:check + test +bun install && bun run check ``` -`@corbits/oauth-core` and `@corbits/openai-responses` are peer dependencies -(`^0.1.0`) — the host provides them. `devDependencies` mirrors the same -`^0.1.0` npm ranges so installs are git-free. The siblings are still -unpublished, so local `bun run check` verification temporarily swaps in -`file:` stand-ins and reverts before commit — never commit stand-in paths or -the lockfile churn they cause. To work against an unpushed local checkout of -either, `bun link` it here. - -## Distribution - -The package ships compiled output: `bun run build` (`tsc -p -tsconfig.build.json`, NodeNext, no sourcemaps) emits `dist/` (JS + -declarations, tests excluded), and `prepack` rebuilds `dist/` on every pack. -`exports` maps `.` to `dist` via the types/default pair (`main` agrees), so -both Bun >= 1.2 and native Node >= 24 load the compiled output — no -source-consumption condition. Only `dist` ships (`files` is dist-only). The -two `@corbits/*` peers resolve from npm (`^0.1.0`), so installs are git-free. -Relative imports in `src/` carry explicit `.js` suffixes so the emitted ESM -runs under Node without a rewrite step — never add a build-time rewrite -script or a bundler. +To work against an unpushed local checkout of `@corbits/oauth-core` or +`@corbits/openai-responses`, `bun link` it here; never commit a lockfile +written against the link. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e1633d7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,42 @@ +# Contributing + +## Development + +```sh +bun install +bun run check +``` + +`bun run check` runs typecheck, lint, format check and unit tests. `bun run format` rewrites the tree. + +Contributors sign the [CLA](CLA.md) on their first PR; the CLA bot explains how. + +Unit tests sit next to the code in `src/`; end-to-end tests live in `e2e/`. +`e2e/live.test.ts` calls xAI's CLI chat proxy and runs only when +`XAI_LIVE_ACCESS_TOKEN` is set: + +```sh +XAI_LIVE_ACCESS_TOKEN= bun run test:e2e +``` + +`XAI_LIVE_MODEL` is optional (default: the first of `XAI_DEFAULT_MODELS`). + +## Commit messages + +Commit subjects and PR titles follow [Conventional Commits](https://www.conventionalcommits.org): `feat`, `fix`, `refactor`, `test`, `docs`, `build`, `ci`, `perf`, and `chore(release): x.y.z` for releases. +Add `!` only for public API breaks: removed or renamed exports, changed signatures, newly required params. Peer and dependency range changes are `build(deps):` with no `!`. +Keep subjects imperative, lowercase after the colon, 72 characters or less, and free of ticket IDs. +Every PR links its issue with a `Closes ` line in the PR body. + +## Releasing + +Releases are manual. On a clean, up-to-date `main`: + +```sh +npm version -m "chore(release): %s" +git push --follow-tags +gh release create "v$(node -p 'require("./package.json").version')" --generate-notes +npm publish +``` + +Bump minor only for breaking API changes; everything else is a patch. `prepack` builds `dist/` from the tagged commit.