pi-openai-codex-compat 0.0.5 → 0.0.7-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ### Security
6
+
7
+ - Require npm releases to match a locally built SHA-256 recorded in an SSH-signed release commit before trusted publishing can stage the package.
8
+
9
+ ## 0.0.6 - 2026-08-10
10
+
11
+ ### Added
12
+
13
+ - Add `npm run pack:dry` to inspect the npm package contents before release.
14
+
15
+ ### Changed
16
+
17
+ - Require Pi 0.84.x, use Pi 0.84.1 as the development integration baseline, and preserve Pi 0.84 header removals across Codex tools and native compaction.
18
+
19
+ ### Fixed
20
+
21
+ - Support Pi 0.84's subscription-aware default footer without crashing during startup.
22
+
5
23
  ## 0.0.5 - 2026-08-07
6
24
 
7
25
  ### Fixed
package/README.md CHANGED
@@ -20,7 +20,7 @@ Pi provides the Codex OAuth flow and model catalog. At session start, this packa
20
20
  ## Requirements
21
21
 
22
22
  - Node.js 22.19 or newer
23
- - Pi `>=0.83.0 <0.84.0`
23
+ - Pi `>=0.84.0 <0.85.0`
24
24
  - An OpenAI Codex login in Pi
25
25
 
26
26
  Authenticate through Pi if needed:
@@ -379,6 +379,7 @@ mise install
379
379
  npm install
380
380
  npm run check
381
381
  npm test
382
+ npm run pack:dry
382
383
  ```
383
384
 
384
385
  Run the credentialed Pi/Codex integration tests separately. They load the real
@@ -403,7 +404,13 @@ search, and compaction continuation.
403
404
 
404
405
  ## Release staging
405
406
 
406
- The GitHub Actions workflow stages npm releases when a `v*` tag is pushed. The tag must match the `package.json` version, point at a commit whose subject is `release: v<version>`, and be a lightweight tag. Create it with `git tag v<version>`; do not use `git tag -a`, `git tag -s`, `git tag -m`, or `cog bump --annotated`.
407
+ 1. Run `npm run release -- X.Y.Z` from a clean, synchronized `main`.
408
+ 2. The command builds the exact package locally, records its SHA-256 in an SSH-signed release commit, proves a clean rebuild is reproducible, and creates a lightweight tag.
409
+ 3. Inspect the result, then push atomically with `git push --atomic origin main vX.Y.Z`.
410
+ 4. A read-only GitHub Actions job validates and packs the package. A separate GitHub-owned job verifies the signature and signed digest before attesting and staging that exact archive through npm trusted publishing.
411
+ 5. Approve the staged package on npmjs.com, or with `npm stage approve <stage-id>`.
412
+
413
+ Stable releases use `latest`; prereleases derive their npm dist-tag from the first prerelease identifier.
407
414
 
408
415
  ## Acknowledgements
409
416
 
@@ -1,4 +1,4 @@
1
- import { calculateCost, type Model, type Usage } from "@earendil-works/pi-ai";
1
+ import { calculateCost, type Model, type ProviderHeaders, type Usage } from "@earendil-works/pi-ai";
2
2
 
3
3
  export const REMOTE_COMPACTION_BETA = "remote_compaction_v2";
4
4
  export const RETAINED_CONTEXT_BUDGET = 64_000;
@@ -327,10 +327,14 @@ function accountIdFromToken(token: string): string {
327
327
 
328
328
  export function remoteCompactionHeaders(options: {
329
329
  token: string;
330
- providerHeaders?: Record<string, string> | undefined;
330
+ providerHeaders?: ProviderHeaders | undefined;
331
331
  sessionId: string;
332
332
  }): Headers {
333
- const headers = new Headers(options.providerHeaders);
333
+ const headers = new Headers();
334
+ for (const [name, value] of Object.entries(options.providerHeaders ?? {})) {
335
+ if (value === null) headers.delete(name);
336
+ else headers.set(name, value);
337
+ }
334
338
  headers.set("authorization", `Bearer ${options.token}`);
335
339
  headers.set("chatgpt-account-id", accountIdFromToken(options.token));
336
340
  headers.set("originator", "pi");
@@ -14,7 +14,7 @@ import { isObject, type JsonRecord } from "./codex-protocol.ts";
14
14
  import { CODEX_NAMESPACED_TOOL_NAMES, namespacedToolCallName } from "./namespaced-tools.ts";
15
15
 
16
16
  /**
17
- * Focused adaptation of @earendil-works/pi-ai@0.83.0
17
+ * Focused adaptation of @earendil-works/pi-ai@0.84.1
18
18
  * src/api/openai-responses-shared.ts stream processing.
19
19
  */
20
20
 
@@ -21,7 +21,7 @@ import { normalizeReplayItem, stableResponsesJson } from "./responses-replay.ts"
21
21
  import { applyResponsesLiteHeaders, responsesLiteSsePayload } from "./responses-lite.ts";
22
22
 
23
23
  /**
24
- * Focused adaptation of @earendil-works/pi-ai@0.83.0
24
+ * Focused adaptation of @earendil-works/pi-ai@0.84.1
25
25
  * src/api/openai-codex-responses.ts transport behavior.
26
26
  */
27
27
 
@@ -59,6 +59,15 @@ function footerSession(ctx: ExtensionContext, resolveConfig: ConfigResolver): Fo
59
59
  model && model.provider === provider && ctx.modelRegistry.isUsingOAuth(model),
60
60
  );
61
61
  },
62
+ isUsingSubscription(provider: string) {
63
+ const model = ctx.model;
64
+ return Boolean(
65
+ model &&
66
+ model.provider === provider &&
67
+ ctx.modelRegistry.isUsingOAuth(model) &&
68
+ ctx.modelRegistry.getProvider(provider)?.auth.oauth?.isSubscription === true,
69
+ );
70
+ },
62
71
  },
63
72
  } as unknown as FooterSession;
64
73
  }
@@ -6,7 +6,7 @@ import type {
6
6
  SessionEntry,
7
7
  ToolInfo,
8
8
  } from "@earendil-works/pi-coding-agent";
9
- import type { Model, OpenAICodexResponsesOptions } from "@earendil-works/pi-ai";
9
+ import type { Model, OpenAICodexResponsesOptions, ProviderHeaders } from "@earendil-works/pi-ai";
10
10
  import { addRemoteCompactionFeature, type JsonRecord } from "./codex-protocol.ts";
11
11
  import {
12
12
  activeResponsesTools,
@@ -40,12 +40,10 @@ function appendFeatureHeader(headers: Record<string, string | null>): void {
40
40
  else headers["x-codex-beta-features"] = addRemoteCompactionFeature(undefined);
41
41
  }
42
42
 
43
- function featureHeaders(headers: Record<string, string> | undefined): Record<string, string> {
44
- const result: Record<string, string | null> = { ...headers };
43
+ function featureHeaders(headers: ProviderHeaders | undefined): ProviderHeaders {
44
+ const result: ProviderHeaders = { ...headers };
45
45
  appendFeatureHeader(result);
46
- return Object.fromEntries(
47
- Object.entries(result).filter((entry): entry is [string, string] => entry[1] !== null),
48
- );
46
+ return result;
49
47
  }
50
48
 
51
49
  function markerSummary(): string {
@@ -1,5 +1,5 @@
1
1
  import type { ExtensionAPI, ExtensionContext, SessionEntry } from "@earendil-works/pi-coding-agent";
2
- import type { Model } from "@earendil-works/pi-ai";
2
+ import type { Model, ProviderHeaders } from "@earendil-works/pi-ai";
3
3
  import { providerHistory } from "./compaction-checkpoint.ts";
4
4
  import type { ImageDetail } from "./config.ts";
5
5
  import type { ResponsesItem } from "./codex-protocol.ts";
@@ -7,7 +7,7 @@ import type { ResponsesItem } from "./codex-protocol.ts";
7
7
  export async function codexToolAuthentication(
8
8
  ctx: ExtensionContext,
9
9
  model: Model<any>,
10
- ): Promise<{ apiKey: string; headers?: Record<string, string> }> {
10
+ ): Promise<{ apiKey: string; headers?: ProviderHeaders }> {
11
11
  const authentication = await ctx.modelRegistry.getApiKeyAndHeaders(model);
12
12
  if (!authentication.ok) throw new Error(authentication.error);
13
13
  if (!authentication.apiKey) throw new Error("OpenAI Codex authentication is unavailable.");
@@ -2,7 +2,7 @@
2
2
 
3
3
  This directory intentionally contains only the Pi AI methods needed to serialize checkpoint and native replay history for OpenAI's Responses API. It does not contain Pi AI's complete source dependency graph.
4
4
 
5
- [`openai-responses-serialization.ts`](openai-responses-serialization.ts) adapts the relevant methods from `@earendil-works/pi-ai@0.83.0`. Its header lists the upstream source files. Keep the behavioral equivalence test in [`test/pi-ai-serialization.test.ts`](../../../../test/pi-ai-serialization.test.ts) passing when updating the Pi dependencies.
5
+ [`openai-responses-serialization.ts`](openai-responses-serialization.ts) adapts the relevant methods from `@earendil-works/pi-ai@0.84.1`. Its header lists the upstream source files. Keep the behavioral equivalence test in [`test/pi-ai-serialization.test.ts`](../../../../test/pi-ai-serialization.test.ts) passing when updating the Pi dependencies.
6
6
 
7
7
  The optional `namespacedToolNames`, `textContentItemToolResultNames`, and `toolResultImageDetail` paths are extension-owned additions. Without those options, serialization must continue to match Pi AI. `namespacedToolNames` groups only the fixed Codex allowlist into native Responses namespaces and replays namespace/member call identities. `textContentItemToolResultNames` preserves Codex tools such as `web.run` whose successful text output is transported as an `input_text` content-item array instead of Pi's usual plain string. `toolResultImageDetail` overrides the otherwise canonical `auto` detail used for image tool-result content.
8
8
 
@@ -13,7 +13,7 @@ import type {
13
13
 
14
14
  /**
15
15
  * Focused copies of the methods used to serialize Pi messages for OpenAI's
16
- * Responses API. Adapted from @earendil-works/pi-ai@0.83.0:
16
+ * Responses API. Adapted from @earendil-works/pi-ai@0.84.1:
17
17
  *
18
18
  * - src/api/openai-responses-shared.ts
19
19
  * - src/api/transform-messages.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-openai-codex-compat",
3
- "version": "0.0.5",
3
+ "version": "0.0.7-alpha.0",
4
4
  "description": "OpenAI Codex compatibility for Pi with native compaction, fast mode, and Codex-optimized capabilities",
5
5
  "keywords": [
6
6
  "pi-package"
@@ -32,14 +32,16 @@
32
32
  "check": "hk check --all --check",
33
33
  "test": "node --test --test-concurrency=1 test/*.test.ts",
34
34
  "test:live:codex": "PI_CODEX_LIVE_TEST=1 node --test --test-concurrency=1 test/codex-host.live.test.ts",
35
+ "pack:dry": "npm pack --dry-run --allow-directory=all",
36
+ "release": "node scripts/release.ts",
35
37
  "fmt": "oxfmt",
36
38
  "lint": "oxlint",
37
39
  "lint:fix": "oxlint --fix"
38
40
  },
39
41
  "devDependencies": {
40
- "@earendil-works/pi-ai": "0.83.0",
41
- "@earendil-works/pi-coding-agent": "0.83.0",
42
- "@earendil-works/pi-tui": "0.83.0",
42
+ "@earendil-works/pi-ai": "0.84.1",
43
+ "@earendil-works/pi-coding-agent": "0.84.1",
44
+ "@earendil-works/pi-tui": "0.84.1",
43
45
  "@types/node": "22.20.1",
44
46
  "oxfmt": "0.60.0",
45
47
  "oxlint": "1.75.0",
@@ -48,9 +50,9 @@
48
50
  "typescript": "7.0.2"
49
51
  },
50
52
  "peerDependencies": {
51
- "@earendil-works/pi-ai": ">=0.83.0 <0.84.0",
52
- "@earendil-works/pi-coding-agent": ">=0.83.0 <0.84.0",
53
- "@earendil-works/pi-tui": ">=0.83.0 <0.84.0",
53
+ "@earendil-works/pi-ai": ">=0.84.0 <0.85.0",
54
+ "@earendil-works/pi-coding-agent": ">=0.84.0 <0.85.0",
55
+ "@earendil-works/pi-tui": ">=0.84.0 <0.85.0",
54
56
  "typebox": "*"
55
57
  },
56
58
  "engines": {