pi-openai-codex-compat 0.0.21 → 0.0.22
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 +16 -0
- package/README.md +23 -23
- package/extensions/openai-codex-compat/apply-patch-render.ts +4 -0
- package/extensions/openai-codex-compat/codex-tool-surface.ts +4 -1
- package/extensions/openai-codex-compat/codex-transport/codex-transport-request-headers.ts +8 -7
- package/extensions/openai-codex-compat/command-output.ts +20 -4
- package/extensions/openai-codex-compat/command-render.ts +3 -0
- package/extensions/openai-codex-compat/image-generation-render.ts +3 -0
- package/extensions/openai-codex-compat/output-limit-continuation.ts +10 -3
- package/extensions/openai-codex-compat/pi-runtime.ts +3 -3
- package/extensions/openai-codex-compat/web-run-render.ts +3 -0
- package/package.json +15 -16
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.0.22 - 2026-10-08
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Create command-output temporary files with owner-only permissions and refuse
|
|
10
|
+
to overwrite existing files or follow symlinks. Failed creation leaves
|
|
11
|
+
existing files intact.
|
|
12
|
+
- Preserve explicit `originator` and `User-Agent` overrides without changing
|
|
13
|
+
the default Pi identity.
|
|
14
|
+
- Honor Pi's horizontal output padding setting in Codex tool calls and results.
|
|
15
|
+
- Do not restart output-limit recovery after the user cancels the Pi run.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Require Pi `>=1.1.0 <1.2.0`. Restart Pi after upgrading its runtime.
|
|
20
|
+
|
|
5
21
|
## 0.0.21 - 2026-10-02
|
|
6
22
|
|
|
7
23
|
### Fixed
|
package/README.md
CHANGED
|
@@ -22,19 +22,19 @@ Pi provides the Codex OAuth flow and model catalog. At session start, this packa
|
|
|
22
22
|
## Requirements
|
|
23
23
|
|
|
24
24
|
- Node.js 22.19 or newer
|
|
25
|
-
- Pi `>=1.
|
|
25
|
+
- Pi `>=1.1.0 <1.2.0`
|
|
26
26
|
- An OpenAI Codex login in Pi
|
|
27
27
|
|
|
28
28
|
Restart Pi after upgrading its runtime. `/reload` reloads extensions but cannot
|
|
29
29
|
upgrade the running Pi process. At load time, the extension requires the host's
|
|
30
30
|
transcript APIs, the Pi 0.99 APIs `SessionManager.getEntryCount()` and
|
|
31
|
-
`ExtensionAPI.getSettings()`, and a reported Pi version of at least 1.
|
|
31
|
+
`ExtensionAPI.getSettings()`, and a reported Pi version of at least 1.1.0. It
|
|
32
32
|
refuses to load otherwise. The load check does not reject newer releases: the
|
|
33
|
-
`<1.
|
|
33
|
+
`<1.2.0` bound is the package's peer range, which Pi does not enforce when it
|
|
34
34
|
installs packages. `PI_PACKAGE_DIR` can point an older executable at
|
|
35
35
|
newer package metadata, so the reported version alone does not establish
|
|
36
36
|
compatibility. The API checks detect missing capabilities from before Pi 0.99.
|
|
37
|
-
They do not distinguish a Pi 0.99 executable from Pi 1.
|
|
37
|
+
They do not distinguish a Pi 0.99 executable from Pi 1.1.0 when its metadata
|
|
38
38
|
points at the newer installation.
|
|
39
39
|
|
|
40
40
|
Authenticate through Pi if needed:
|
|
@@ -662,19 +662,18 @@ Both namespace tools are accepted only from the fixed extension-owned allowlist.
|
|
|
662
662
|
```bash
|
|
663
663
|
mise trust
|
|
664
664
|
mise install
|
|
665
|
-
|
|
665
|
+
mise run init
|
|
666
666
|
mise run check
|
|
667
667
|
npm run pack:dry
|
|
668
668
|
```
|
|
669
669
|
|
|
670
670
|
`mise run check` runs the linters, formatters, type checks, and the offline
|
|
671
|
-
test suite; `
|
|
672
|
-
`
|
|
673
|
-
that load Pi in-process read this repository's Pi
|
|
674
|
-
|
|
675
|
-
outside these tasks are unaffected. Offline tests also exercise
|
|
671
|
+
test suite; `npm test` runs only the offline suite. `npm test` and
|
|
672
|
+
`npm run test:live:codex` remove an inherited `PI_PACKAGE_DIR` from their test
|
|
673
|
+
processes, so tests that load Pi in-process read this repository's Pi
|
|
674
|
+
resources. Ordinary `pi` launches are unaffected. Offline tests also exercise
|
|
676
675
|
`scripts/release.ts` with every child process mocked: they never run Git, npm,
|
|
677
|
-
|
|
676
|
+
or provider calls.
|
|
678
677
|
|
|
679
678
|
Run the credentialed Pi/Codex integration tests separately. They load the real
|
|
680
679
|
extension into headless Pi sessions, use the real WebSocket service, and ask
|
|
@@ -682,13 +681,14 @@ the model to report all prior history markers after each text and tool
|
|
|
682
681
|
continuation:
|
|
683
682
|
|
|
684
683
|
```bash
|
|
685
|
-
|
|
684
|
+
npm run test:live:codex
|
|
686
685
|
```
|
|
687
686
|
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
687
|
+
`scripts/test-live.ts` first runs the offline packaged terminal tests. It then
|
|
688
|
+
obtains the local Codex bearer token through the repository Pi and runs the
|
|
689
|
+
tests with `gpt-5.6-luna`, `gpt-6-sol`, `gpt-6-luna`, and `gpt-6.1-sol` at
|
|
690
|
+
medium reasoning effort. It also packs the extension and loads that archive through the shipped Pi
|
|
691
|
+
CLI. Ordinary Responses and Responses Lite tests exercise tool calls,
|
|
692
692
|
prompt reload, native compaction, and persisted-session resume against Codex.
|
|
693
693
|
SDK tests verify Responses Lite
|
|
694
694
|
WebSocket history, prewarming, continuation, and the built-in read tool.
|
|
@@ -710,12 +710,12 @@ The packaged-CLI test selects its archive and executable as follows:
|
|
|
710
710
|
existing regular file that `tar` can list, and an empty, missing, directory,
|
|
711
711
|
or invalid value fails the test instead of falling back to a fresh pack.
|
|
712
712
|
- `PI_CODEX_CLI_PATH` selects another Pi `cli.js`; the default is this
|
|
713
|
-
repository's Pi
|
|
714
|
-
executable
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
metadata.
|
|
713
|
+
repository's Pi development dependency. The live test asserts that the
|
|
714
|
+
selected executable has the development dependency's version, the only Pi
|
|
715
|
+
version releases are validated against. The supported range is
|
|
716
|
+
`>=1.1.0 <1.2.0`.
|
|
717
|
+
- Each Pi child process resolves its own package directory, so the runtime
|
|
718
|
+
under test reads its own metadata.
|
|
719
719
|
|
|
720
720
|
The public package entrypoint is `extensions/index.ts`; implementation modules remain under
|
|
721
721
|
`extensions/openai-codex-compat/`. The focused Pi AI serializer copy lives under
|
|
@@ -748,7 +748,7 @@ The release command runs these steps in order:
|
|
|
748
748
|
only those two files.
|
|
749
749
|
3. Check out the staged index into a temporary directory, run
|
|
750
750
|
`npm ci --ignore-scripts` and `npm pack` there, validate the package
|
|
751
|
-
identity, file list, and manifest, then run `
|
|
751
|
+
identity, file list, and manifest, then run `npm run test:live:codex` in
|
|
752
752
|
the repository with `PI_CODEX_PACKAGE_ARCHIVE` set to that archive. This is
|
|
753
753
|
the exact archive release gate: the live CLI tests load that archive and
|
|
754
754
|
nothing else. A live process that cannot start, a nonzero exit, or a failed
|
|
@@ -17,6 +17,7 @@ type ApplyPatchArgs = {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
type ApplyPatchRenderContext = {
|
|
20
|
+
outputPad: number;
|
|
20
21
|
cwd: string;
|
|
21
22
|
isPartial: boolean;
|
|
22
23
|
expanded: boolean;
|
|
@@ -132,6 +133,7 @@ export function renderApplyPatchCall(
|
|
|
132
133
|
|
|
133
134
|
return new CodexToolSurfaceComponent(container, theme, {
|
|
134
135
|
background: resolveBackground,
|
|
136
|
+
outputPad: context.outputPad,
|
|
135
137
|
status: context.isPartial ? "pending" : context.isError ? "error" : "success",
|
|
136
138
|
top: true,
|
|
137
139
|
bottom: context.isPartial,
|
|
@@ -163,6 +165,7 @@ export function renderApplyPatchResult(
|
|
|
163
165
|
theme,
|
|
164
166
|
{
|
|
165
167
|
background: resolveBackground,
|
|
168
|
+
outputPad: context.outputPad,
|
|
166
169
|
status: context.isError ? "error" : "success",
|
|
167
170
|
top: true,
|
|
168
171
|
bottom: true,
|
|
@@ -176,6 +179,7 @@ export function renderApplyPatchResult(
|
|
|
176
179
|
theme,
|
|
177
180
|
{
|
|
178
181
|
background: resolveBackground,
|
|
182
|
+
outputPad: context.outputPad,
|
|
179
183
|
status: "error",
|
|
180
184
|
top: true,
|
|
181
185
|
bottom: true,
|
|
@@ -155,6 +155,7 @@ export class CodexToolSurfaceComponent implements Component {
|
|
|
155
155
|
private readonly status: CodexToolSurfaceStatus;
|
|
156
156
|
private readonly topPadding: boolean;
|
|
157
157
|
private readonly bottomPadding: boolean;
|
|
158
|
+
private readonly outputPad: number;
|
|
158
159
|
private renderCache:
|
|
159
160
|
| {
|
|
160
161
|
width: number;
|
|
@@ -172,6 +173,7 @@ export class CodexToolSurfaceComponent implements Component {
|
|
|
172
173
|
status: CodexToolSurfaceStatus;
|
|
173
174
|
top: boolean;
|
|
174
175
|
bottom: boolean;
|
|
176
|
+
outputPad: number;
|
|
175
177
|
},
|
|
176
178
|
) {
|
|
177
179
|
this.component = component;
|
|
@@ -180,12 +182,13 @@ export class CodexToolSurfaceComponent implements Component {
|
|
|
180
182
|
this.status = options.status;
|
|
181
183
|
this.topPadding = options.top;
|
|
182
184
|
this.bottomPadding = options.bottom;
|
|
185
|
+
this.outputPad = options.outputPad;
|
|
183
186
|
}
|
|
184
187
|
|
|
185
188
|
render(width: number): string[] {
|
|
186
189
|
const effectiveWidth = Math.max(1, width);
|
|
187
190
|
const background = surfaceBackground(this.theme, this.resolveBackground(), this.status);
|
|
188
|
-
const horizontalPadding = effectiveWidth
|
|
191
|
+
const horizontalPadding = Math.min(this.outputPad, Math.floor((effectiveWidth - 1) / 2));
|
|
189
192
|
const contentWidth = Math.max(1, effectiveWidth - horizontalPadding * 2);
|
|
190
193
|
const componentLines = this.component.render(contentWidth);
|
|
191
194
|
const cached = this.renderCache;
|
|
@@ -164,19 +164,20 @@ export function baseHeaders(
|
|
|
164
164
|
accountId: string,
|
|
165
165
|
token: string,
|
|
166
166
|
): Headers {
|
|
167
|
-
const
|
|
167
|
+
const os = nodeOs();
|
|
168
|
+
const headers = new Headers({
|
|
169
|
+
originator: "pi",
|
|
170
|
+
"User-Agent": os ? `pi (${os.platform()} ${os.release()}; ${os.arch()})` : "pi (browser)",
|
|
171
|
+
});
|
|
172
|
+
for (const [name, value] of Object.entries(modelHeaders ?? {})) {
|
|
173
|
+
headers.set(name, value);
|
|
174
|
+
}
|
|
168
175
|
for (const [name, value] of Object.entries(additionalHeaders ?? {})) {
|
|
169
176
|
if (value === null) headers.delete(name);
|
|
170
177
|
else headers.set(name, value);
|
|
171
178
|
}
|
|
172
179
|
headers.set("Authorization", `Bearer ${token}`);
|
|
173
180
|
headers.set("chatgpt-account-id", accountId);
|
|
174
|
-
headers.set("originator", "pi");
|
|
175
|
-
const os = nodeOs();
|
|
176
|
-
headers.set(
|
|
177
|
-
"User-Agent",
|
|
178
|
-
os ? `pi (${os.platform()} ${os.release()}; ${os.arch()})` : "pi (browser)",
|
|
179
|
-
);
|
|
180
181
|
return headers;
|
|
181
182
|
}
|
|
182
183
|
|
|
@@ -134,6 +134,7 @@ export class CommandOutputAccumulator {
|
|
|
134
134
|
private hasOpenLine = false;
|
|
135
135
|
private finished = false;
|
|
136
136
|
private tempFilePath: string | undefined;
|
|
137
|
+
private tempFileCreated = false;
|
|
137
138
|
private tempFileStream: WriteStream | undefined;
|
|
138
139
|
private tempFileError: Error | undefined;
|
|
139
140
|
private readonly retainCompleteOutput: boolean;
|
|
@@ -230,6 +231,8 @@ export class CommandOutputAccumulator {
|
|
|
230
231
|
|
|
231
232
|
const stream = this.tempFileStream;
|
|
232
233
|
this.tempFileStream = undefined;
|
|
234
|
+
const previousError = this.tempFileError;
|
|
235
|
+
if (previousError) throw previousError;
|
|
233
236
|
await new Promise<void>((resolve, reject) => {
|
|
234
237
|
const onError = (error: Error): void => {
|
|
235
238
|
stream.off("finish", onFinish);
|
|
@@ -256,8 +259,9 @@ export class CommandOutputAccumulator {
|
|
|
256
259
|
? error
|
|
257
260
|
: new Error("Could not close discarded command output.", { cause: error });
|
|
258
261
|
}
|
|
259
|
-
if (this.tempFilePath !== undefined) {
|
|
262
|
+
if (this.tempFileCreated && this.tempFilePath !== undefined) {
|
|
260
263
|
await rm(this.tempFilePath, { force: true });
|
|
264
|
+
this.tempFileCreated = false;
|
|
261
265
|
}
|
|
262
266
|
if (closeError) throw closeError;
|
|
263
267
|
}
|
|
@@ -325,7 +329,10 @@ export class CommandOutputAccumulator {
|
|
|
325
329
|
private ensureTempFile(): void {
|
|
326
330
|
if (this.tempFilePath) return;
|
|
327
331
|
this.tempFilePath = tempFilePath(this.tempFilePrefix);
|
|
328
|
-
const stream = createWriteStream(this.tempFilePath);
|
|
332
|
+
const stream = createWriteStream(this.tempFilePath, { mode: 0o600, flags: "wx" });
|
|
333
|
+
stream.once("open", () => {
|
|
334
|
+
this.tempFileCreated = true;
|
|
335
|
+
});
|
|
329
336
|
stream.on("error", (error) => {
|
|
330
337
|
this.tempFileError = error;
|
|
331
338
|
});
|
|
@@ -344,6 +351,7 @@ export class CommandOutputSpool {
|
|
|
344
351
|
private readonly tempFilePrefix: string;
|
|
345
352
|
private totalBytes = 0;
|
|
346
353
|
private tempFilePath: string | undefined;
|
|
354
|
+
private tempFileCreated = false;
|
|
347
355
|
private tempFileStream: WriteStream | undefined;
|
|
348
356
|
private tempFileError: Error | undefined;
|
|
349
357
|
private finishing: Promise<void> | undefined;
|
|
@@ -390,8 +398,9 @@ export class CommandOutputSpool {
|
|
|
390
398
|
? error
|
|
391
399
|
: new Error("Could not finish disposable command output.", { cause: error });
|
|
392
400
|
}
|
|
393
|
-
if (this.tempFilePath !== undefined) {
|
|
401
|
+
if (this.tempFileCreated && this.tempFilePath !== undefined) {
|
|
394
402
|
await rm(this.tempFilePath, { force: true });
|
|
403
|
+
this.tempFileCreated = false;
|
|
395
404
|
}
|
|
396
405
|
if (finishError) throw finishError;
|
|
397
406
|
}
|
|
@@ -400,6 +409,10 @@ export class CommandOutputSpool {
|
|
|
400
409
|
if (this.finishing) return this.finishing;
|
|
401
410
|
const stream = this.tempFileStream;
|
|
402
411
|
this.tempFileStream = undefined;
|
|
412
|
+
if (this.tempFileError) {
|
|
413
|
+
this.finishing = Promise.reject(this.tempFileError);
|
|
414
|
+
return this.finishing;
|
|
415
|
+
}
|
|
403
416
|
if (!stream) {
|
|
404
417
|
this.finishing = Promise.resolve();
|
|
405
418
|
return this.finishing;
|
|
@@ -423,7 +436,10 @@ export class CommandOutputSpool {
|
|
|
423
436
|
private ensureTempFile(): void {
|
|
424
437
|
if (this.tempFilePath) return;
|
|
425
438
|
this.tempFilePath = tempFilePath(this.tempFilePrefix);
|
|
426
|
-
const stream = createWriteStream(this.tempFilePath);
|
|
439
|
+
const stream = createWriteStream(this.tempFilePath, { mode: 0o600, flags: "wx" });
|
|
440
|
+
stream.once("open", () => {
|
|
441
|
+
this.tempFileCreated = true;
|
|
442
|
+
});
|
|
427
443
|
stream.on("error", (error) => {
|
|
428
444
|
this.tempFileError = error;
|
|
429
445
|
});
|
|
@@ -9,6 +9,7 @@ import { DEFAULT_CONFIG } from "./config.ts";
|
|
|
9
9
|
export type CommandRenderContext = {
|
|
10
10
|
isError: boolean;
|
|
11
11
|
isPartial: boolean;
|
|
12
|
+
outputPad: number;
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
export type CommandCallRenderContext = CommandRenderContext & {
|
|
@@ -223,6 +224,7 @@ export function renderCommandCall(
|
|
|
223
224
|
theme,
|
|
224
225
|
{
|
|
225
226
|
background: resolveBackground,
|
|
227
|
+
outputPad: context.outputPad,
|
|
226
228
|
status: context.isPartial ? "pending" : context.isError ? "error" : "success",
|
|
227
229
|
top: true,
|
|
228
230
|
bottom: context.isPartial && !context.executionStarted,
|
|
@@ -243,6 +245,7 @@ export function renderCommandResult(
|
|
|
243
245
|
theme,
|
|
244
246
|
{
|
|
245
247
|
background: resolveBackground,
|
|
248
|
+
outputPad: context.outputPad,
|
|
246
249
|
status: context.isPartial ? "pending" : context.isError ? "error" : "success",
|
|
247
250
|
top: output.length > 0,
|
|
248
251
|
bottom: true,
|
|
@@ -25,6 +25,7 @@ export const IMAGE_GENERATION_DETAILS_SCHEMA = {
|
|
|
25
25
|
export type ImageGenerationDetails = Static<typeof IMAGE_GENERATION_DETAILS_SCHEMA>;
|
|
26
26
|
|
|
27
27
|
type ImageGenerationRenderContext = {
|
|
28
|
+
outputPad: number;
|
|
28
29
|
args: ImageGenerationParameters;
|
|
29
30
|
isPartial: boolean;
|
|
30
31
|
expanded: boolean;
|
|
@@ -150,6 +151,7 @@ export function renderImageGenerationCall(
|
|
|
150
151
|
const summary = theme.fg("muted", describeImageCall(args));
|
|
151
152
|
return new CodexToolSurfaceComponent(new Text(`${title} ${summary}`, 0, 0), theme, {
|
|
152
153
|
background: resolveBackground,
|
|
154
|
+
outputPad: context.outputPad,
|
|
153
155
|
status: context.isPartial ? "pending" : context.isError ? "error" : "success",
|
|
154
156
|
top: true,
|
|
155
157
|
bottom: context.isPartial,
|
|
@@ -171,6 +173,7 @@ export function renderImageGenerationResult(
|
|
|
171
173
|
theme,
|
|
172
174
|
{
|
|
173
175
|
background: resolveBackground,
|
|
176
|
+
outputPad: context.outputPad,
|
|
174
177
|
status: context.isError ? "error" : "success",
|
|
175
178
|
top: false,
|
|
176
179
|
bottom: true,
|
|
@@ -36,9 +36,14 @@ export type OutputLimitContinuationLifecycleHandler = (
|
|
|
36
36
|
ctx: OutputLimitContinuationContext,
|
|
37
37
|
) => Promise<void> | void;
|
|
38
38
|
|
|
39
|
+
export type OutputLimitContinuationSettledHandler = (
|
|
40
|
+
event: { aborted: boolean },
|
|
41
|
+
ctx: OutputLimitContinuationContext,
|
|
42
|
+
) => Promise<void> | void;
|
|
43
|
+
|
|
39
44
|
export type OutputLimitContinuationApi = {
|
|
40
45
|
onAgentEnd: (handler: OutputLimitContinuationAgentEndHandler) => void;
|
|
41
|
-
onAgentSettled: (handler:
|
|
46
|
+
onAgentSettled: (handler: OutputLimitContinuationSettledHandler) => void;
|
|
42
47
|
onSessionBeforeCompact: (handler: OutputLimitContinuationCompactionHandler) => void;
|
|
43
48
|
onSessionCompact: (handler: OutputLimitContinuationLifecycleHandler) => void;
|
|
44
49
|
onSessionShutdown: (handler: OutputLimitContinuationLifecycleHandler) => void;
|
|
@@ -66,7 +71,8 @@ export function outputLimitContinuationApi(pi: ExtensionAPI): OutputLimitContinu
|
|
|
66
71
|
return {
|
|
67
72
|
onAgentEnd: (handler) =>
|
|
68
73
|
pi.on("agent_end", (event, ctx) => handler({ messages: event.messages }, context(ctx))),
|
|
69
|
-
onAgentSettled: (handler) =>
|
|
74
|
+
onAgentSettled: (handler) =>
|
|
75
|
+
pi.on("agent_settled", (event, ctx) => handler({ aborted: event.aborted }, context(ctx))),
|
|
70
76
|
onSessionBeforeCompact: (handler) =>
|
|
71
77
|
pi.on("session_before_compact", (event, ctx) =>
|
|
72
78
|
handler({ signal: event.signal }, context(ctx)),
|
|
@@ -181,7 +187,7 @@ export default function registerOutputLimitContinuation(pi: OutputLimitContinuat
|
|
|
181
187
|
if (recovery?.compaction === "started") recovery.compaction = "completed";
|
|
182
188
|
});
|
|
183
189
|
|
|
184
|
-
pi.onAgentSettled((ctx) => {
|
|
190
|
+
pi.onAgentSettled((event, ctx) => {
|
|
185
191
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
186
192
|
const recovery = pendingRecoveries.get(sessionId);
|
|
187
193
|
if (!recovery) return;
|
|
@@ -189,6 +195,7 @@ export default function registerOutputLimitContinuation(pi: OutputLimitContinuat
|
|
|
189
195
|
|
|
190
196
|
const compactionFailed = recovery.compaction === "started";
|
|
191
197
|
if (
|
|
198
|
+
event.aborted ||
|
|
192
199
|
recovery.cancelled ||
|
|
193
200
|
compactionFailed ||
|
|
194
201
|
!ctx.isIdle() ||
|
|
@@ -31,7 +31,7 @@ export const SESSION_APIS = ["buildSessionProjection"] as const;
|
|
|
31
31
|
*/
|
|
32
32
|
export const PI_099_APIS = ["SessionManager.getEntryCount", "ExtensionAPI.getSettings"] as const;
|
|
33
33
|
|
|
34
|
-
export const MINIMUM_PI_VERSION = "1.
|
|
34
|
+
export const MINIMUM_PI_VERSION = "1.1.0";
|
|
35
35
|
export const REQUIRED_PI = `Pi ${MINIMUM_PI_VERSION} or later`;
|
|
36
36
|
|
|
37
37
|
function isFunction(value: unknown): boolean {
|
|
@@ -62,9 +62,9 @@ export function atLeastVersion(version: unknown, minimum: string): boolean {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
* Require the Pi 0.99 host surface and a reported version of at least 1.
|
|
65
|
+
* Require the Pi 0.99 host surface and a reported version of at least 1.1.0. The version comes
|
|
66
66
|
* from package metadata. The API checks detect missing capabilities, but cannot distinguish
|
|
67
|
-
* a Pi 0.99 executable pointed at Pi 1.
|
|
67
|
+
* a Pi 0.99 executable pointed at Pi 1.1.0 metadata through `PI_PACKAGE_DIR`.
|
|
68
68
|
*/
|
|
69
69
|
export function requirePiRuntime(
|
|
70
70
|
transcriptApi: Record<string, unknown>,
|
|
@@ -36,6 +36,7 @@ type NullishOptionalProperties<Value> = Value extends readonly (infer Item)[]
|
|
|
36
36
|
export type WebRunRenderCommands = NullishOptionalProperties<WebRunCommands>;
|
|
37
37
|
|
|
38
38
|
type WebRunRenderContext = {
|
|
39
|
+
outputPad: number;
|
|
39
40
|
args: WebRunRenderCommands;
|
|
40
41
|
isPartial: boolean;
|
|
41
42
|
expanded: boolean;
|
|
@@ -683,6 +684,7 @@ export function renderWebRunCall(
|
|
|
683
684
|
const summary = theme.fg("muted", describeWebRunCall(args));
|
|
684
685
|
return new CodexToolSurfaceComponent(new Text(`${title} ${summary}`, 0, 0), theme, {
|
|
685
686
|
background: resolveBackground,
|
|
687
|
+
outputPad: context.outputPad,
|
|
686
688
|
status: context.isPartial ? "pending" : context.isError ? "error" : "success",
|
|
687
689
|
top: true,
|
|
688
690
|
bottom: context.isPartial,
|
|
@@ -702,6 +704,7 @@ export function renderWebRunResult(
|
|
|
702
704
|
theme,
|
|
703
705
|
{
|
|
704
706
|
background: resolveBackground,
|
|
707
|
+
outputPad: context.outputPad,
|
|
705
708
|
status: context.isError ? "error" : "success",
|
|
706
709
|
top: false,
|
|
707
710
|
bottom: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-openai-codex-compat",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.22",
|
|
4
4
|
"description": "OpenAI Codex compatibility for Pi with native compaction, fast mode, and Codex-optimized capabilities",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package"
|
|
@@ -34,9 +34,8 @@
|
|
|
34
34
|
],
|
|
35
35
|
"type": "module",
|
|
36
36
|
"scripts": {
|
|
37
|
-
"
|
|
38
|
-
"test": "node
|
|
39
|
-
"test:live:codex": "PI_CODEX_LIVE_TEST=1 node --test --test-concurrency=1 test/codex-host.live.test.ts test/codex-cli.live.test.ts test/command-render-cli.test.ts",
|
|
37
|
+
"test": "env -u PI_PACKAGE_DIR node --test --test-concurrency=4 test/*.test.ts",
|
|
38
|
+
"test:live:codex": "node scripts/test-live.ts",
|
|
40
39
|
"pack:dry": "npm pack --dry-run --allow-directory=all",
|
|
41
40
|
"release": "node scripts/release.ts",
|
|
42
41
|
"fmt": "oxfmt",
|
|
@@ -49,22 +48,22 @@
|
|
|
49
48
|
"tree-sitter-bash": "0.25.1"
|
|
50
49
|
},
|
|
51
50
|
"devDependencies": {
|
|
52
|
-
"@2h2d/oxlint-config": "0.1.
|
|
51
|
+
"@2h2d/oxlint-config": "0.1.2",
|
|
53
52
|
"@2h2d/ts-config": "0.0.1",
|
|
54
|
-
"@earendil-works/pi-ai": "1.
|
|
55
|
-
"@earendil-works/pi-coding-agent": "1.
|
|
56
|
-
"@earendil-works/pi-tui": "1.
|
|
57
|
-
"@types/node": "22.20.
|
|
58
|
-
"oxfmt": "0.
|
|
59
|
-
"oxlint": "1.
|
|
60
|
-
"oxlint-tsgolint": "7.0.
|
|
61
|
-
"typebox": "1.3.
|
|
53
|
+
"@earendil-works/pi-ai": "1.1.0",
|
|
54
|
+
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
55
|
+
"@earendil-works/pi-tui": "1.1.0",
|
|
56
|
+
"@types/node": "22.20.4",
|
|
57
|
+
"oxfmt": "0.70.0",
|
|
58
|
+
"oxlint": "1.85.0",
|
|
59
|
+
"oxlint-tsgolint": "7.0.2003",
|
|
60
|
+
"typebox": "1.3.34",
|
|
62
61
|
"typescript": "7.0.2"
|
|
63
62
|
},
|
|
64
63
|
"peerDependencies": {
|
|
65
|
-
"@earendil-works/pi-ai": ">=1.
|
|
66
|
-
"@earendil-works/pi-coding-agent": ">=1.
|
|
67
|
-
"@earendil-works/pi-tui": ">=1.
|
|
64
|
+
"@earendil-works/pi-ai": ">=1.1.0 <1.2.0",
|
|
65
|
+
"@earendil-works/pi-coding-agent": ">=1.1.0 <1.2.0",
|
|
66
|
+
"@earendil-works/pi-tui": ">=1.1.0 <1.2.0",
|
|
68
67
|
"typebox": "*"
|
|
69
68
|
},
|
|
70
69
|
"engines": {
|