codex-relay 1.5.1 → 1.6.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/README.md +14 -1
- package/dist/api-schema.js +2 -2
- package/dist/api-schema2.js +13 -1
- package/dist/paths.js +15 -4
- package/dist/src.js +210 -70
- package/package.json +3 -3
- package/src/api-schema.ts +15 -0
package/README.md
CHANGED
|
@@ -20,7 +20,12 @@ npx codex-relay@latest
|
|
|
20
20
|
|
|
21
21
|
The CLI prints a QR code, a mobile URL, and a `codex-relay://pair...` pairing payload. Scan the QR code from the mobile app. If the relay detects multiple possible network addresses, the QR includes them and the app automatically uses the first address it can reach. If scanning is not available, paste the full pairing payload into the app.
|
|
22
22
|
|
|
23
|
-
When the app shows an approval code,
|
|
23
|
+
When the app shows an approval code, the interactive relay terminal shows the
|
|
24
|
+
same code and asks `Approve? [y/N]`. Check that the codes match, then type `y`
|
|
25
|
+
and press Enter in that terminal. Other input leaves the request unapproved.
|
|
26
|
+
No second terminal is needed.
|
|
27
|
+
|
|
28
|
+
For background relays or non-interactive output, use the approval command:
|
|
24
29
|
|
|
25
30
|
```sh
|
|
26
31
|
npx codex-relay@latest approve XXXX-XXXX
|
|
@@ -28,6 +33,14 @@ npx codex-relay@latest approve XXXX-XXXX
|
|
|
28
33
|
|
|
29
34
|
After approval, the phone can list Codex threads, start new work, stream messages, and handle approval prompts from the local Codex runtime.
|
|
30
35
|
|
|
36
|
+
The thread list shows the 20 most recently active, non-archived root sessions across
|
|
37
|
+
workspaces. This does not delete or archive older sessions. Set
|
|
38
|
+
`CODEX_RELAY_THREAD_LIST_LIMIT=100` before starting the relay to show more history.
|
|
39
|
+
The relay reads Codex's session index so refreshing the list does not repeatedly
|
|
40
|
+
parse large legacy rollout files. An empty index triggers a bounded history lookup;
|
|
41
|
+
legacy files copied into a partially populated index may need to be discovered by
|
|
42
|
+
Codex before they appear in the relay.
|
|
43
|
+
|
|
31
44
|
## Shared Terminal and Mobile Sessions
|
|
32
45
|
|
|
33
46
|
On macOS, Codex Relay prefers Codex's shared Unix socket so terminal and mobile clients can follow the same live sessions. If the shared app-server cannot start or initialize, the relay prints a warning and continues with a private app-server.
|
package/dist/api-schema.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { $ as ResolveApprovalResponseSchema, $t as
|
|
2
|
-
export { AgentSkillSchema, AgentSkillSourceSchema, ApprovalDecisionSchema, ApprovalModeSchema, ArchiveThreadResponseSchema, ChatMessageKindSchema, ChatMessagePromptDetailsSchema, ChatMessageRoleSchema, ChatMessageSchema, ChatMessageStateSchema, CheckoutWorkspaceBranchRequestSchema, CodexModelSchema, CommitPushWorkspaceRequestSchema, ContextWindowUsageSchema, CreateThreadRequestSchema, CreateThreadResponseSchema, EncryptedPayloadSchema, ErrorResponseSchema, ImageAttachmentUploadResponseSchema, InterruptThreadRunResponseSchema, IsoDateTimeSchema, KnownReasoningEffortSchema, ListModelsResponseSchema, ListQueuedThreadInputsResponseSchema, ListSkillsResponseSchema, ListThreadsResponseSchema, ListWorkspaceDirectoriesResponseSchema, ListWorkspaceFilesResponseSchema, PairEncryptedPayloadSchema, PairRequestSchema, PairResponseSchema, PendingInputRequestOptionSchema, PendingInputRequestQuestionSchema, PendingInputRequestSchema, PromptAttachmentSchema, PromptAttachmentSummarySchema, PromptContextInputSchema, PromptContextSchema, PromptSkillSchema, PushNotificationIntentSchema, PushNotificationPreferencesSchema, PushNotificationSettingsResponseSchema, QueuedThreadInputActionResponseSchema, QueuedThreadInputSchema, RateLimitBucketSchema, RateLimitWindowSchema, RateLimitsResponseSchema, ReasoningEffortSchema, RegisterPushNotificationRequestSchema, RenameThreadRequestSchema, RenameThreadResponseSchema, ResolveApprovalRequestSchema, ResolveApprovalResponseSchema, RewindThreadRequestSchema, RunThreadRequestSchema, RunThreadResponseSchema, RuntimeModeSchema, RuntimePreferencesByWorkspacePathSchema, RuntimePreferencesResponseSchema, RuntimePreferencesSchema, SandboxModeSchema, StatusResponseSchema, StreamThreadRunEventSchema, StreamThreadRunRequestSchema, SubmitThreadInputResponseSchema, ThreadCollaborationModeSchema, ThreadContextWindowResponseSchema, ThreadDetailResponseSchema, ThreadGoalResponseSchema, ThreadGoalSchema, ThreadGoalStatusSchema, ThreadMessageDetailFieldSchema, ThreadMessageDetailResponseSchema, ThreadRunOptionsSchema, ThreadStateSchema, ThreadSummarySchema, UpdateRuntimePreferencesRequestSchema, UpdateThreadGoalRequestSchema, UpdateWorkspaceFileContentRequestSchema, VersionResponseSchema, WORKSPACE_PREVIEW_OPEN_PROTOCOL, WORKSPACE_PREVIEW_TAB_VALUES, WebPreviewTargetSchema, WorkspaceChangesResponseSchema, WorkspaceDirectoryEntrySchema, WorkspaceFileContentResponseSchema, WorkspaceFileMentionSchema, WorkspaceGitActionResponseSchema, WorkspaceMarkdownPreviewTargetSchema, WorkspacePreviewNavigationRequestSchema, WorkspacePreviewTabSchema, WorkspaceSelectionRequestSchema, WorkspaceTailscaleServeRequestSchema, WorkspaceTailscaleServeResponseSchema, WorkspaceTerminalInputRequestSchema, WorkspaceTerminalOutputChunkSchema, WorkspaceTerminalOutputResponseSchema, WorkspaceTerminalResizeRequestSchema, WorkspaceTerminalSessionResponseSchema, WorkspaceTerminalStartRequestSchema, apiPaths, chatMessageDetailsFromPromptContext, createOpenApiDocument, isPromptSkillMarkdownMention, normalizePromptContext, promptMarkdownWithSkills, promptSkillDisplayName, promptSkillMentionLabel, promptSkillMentionMarkdown, promptSkillMentionTextCandidates, stripPromptSkillMentions };
|
|
1
|
+
import { $ as ResolveApprovalResponseSchema, $t as promptMarkdownWithSkills, A as PairRequestSchema, At as WorkspaceChangesResponseSchema, B as PushNotificationIntentSchema, Bt as WorkspaceTailscaleServeResponseSchema, C as ListModelsResponseSchema, Ct as UpdateRuntimePreferencesRequestSchema, D as ListWorkspaceDirectoriesResponseSchema, Dt as WORKSPACE_PREVIEW_OPEN_PROTOCOL, E as ListThreadsResponseSchema, Et as VersionResponseSchema, F as PromptAttachmentSchema, Ft as WorkspaceMarkdownPreviewTargetSchema, G as RateLimitBucketSchema, Gt as WorkspaceTerminalSessionResponseSchema, H as PushNotificationSettingsResponseSchema, Ht as WorkspaceTerminalOutputChunkSchema, I as PromptAttachmentSummarySchema, It as WorkspacePreviewNavigationRequestSchema, J as ReasoningEffortSchema, Jt as chatMessageDetailsFromPromptContext, K as RateLimitWindowSchema, Kt as WorkspaceTerminalStartRequestSchema, L as PromptContextInputSchema, Lt as WorkspacePreviewTabSchema, M as PendingInputRequestOptionSchema, Mt as WorkspaceFileContentResponseSchema, N as PendingInputRequestQuestionSchema, Nt as WorkspaceFileMentionSchema, O as ListWorkspaceFilesResponseSchema, Ot as WORKSPACE_PREVIEW_TAB_VALUES, P as PendingInputRequestSchema, Pt as WorkspaceGitActionResponseSchema, Q as ResolveApprovalRequestSchema, Qt as normalizePromptContext, R as PromptContextSchema, Rt as WorkspaceSelectionRequestSchema, S as KnownReasoningEffortSchema, St as ThreadSummarySchema, T as ListSkillsResponseSchema, Tt as UpdateWorkspaceFileContentRequestSchema, U as QueuedThreadInputActionResponseSchema, Ut as WorkspaceTerminalOutputResponseSchema, V as PushNotificationPreferencesSchema, Vt as WorkspaceTerminalInputRequestSchema, W as QueuedThreadInputSchema, Wt as WorkspaceTerminalResizeRequestSchema, X as RenameThreadRequestSchema, Xt as isPromptSkillMarkdownMention, Y as RegisterPushNotificationRequestSchema, Yt as createOpenApiDocument, Z as RenameThreadResponseSchema, Zt as lowestRateLimitRemainingPercent, _ as EncryptedPayloadSchema, _t as ThreadGoalStatusSchema, a as ArchiveThreadResponseSchema, an as stripPromptSkillMentions, at as RuntimePreferencesResponseSchema, b as InterruptThreadRunResponseSchema, bt as ThreadRunOptionsSchema, c as ChatMessageRoleSchema, ct as StatusResponseSchema, d as CheckoutWorkspaceBranchRequestSchema, dt as SubmitThreadInputResponseSchema, en as promptSkillDisplayName, et as RewindThreadRequestSchema, f as CodexModelSchema, ft as ThreadCollaborationModeSchema, g as CreateThreadResponseSchema, gt as ThreadGoalSchema, h as CreateThreadRequestSchema, ht as ThreadGoalResponseSchema, i as ApprovalModeSchema, in as rateLimitRemainingPercent, it as RuntimePreferencesByWorkspacePathSchema, j as PairResponseSchema, jt as WorkspaceDirectoryEntrySchema, k as PairEncryptedPayloadSchema, kt as WebPreviewTargetSchema, l as ChatMessageSchema, lt as StreamThreadRunEventSchema, m as ContextWindowUsageSchema, mt as ThreadDetailResponseSchema, n as AgentSkillSourceSchema, nn as promptSkillMentionMarkdown, nt as RunThreadResponseSchema, o as ChatMessageKindSchema, ot as RuntimePreferencesSchema, p as CommitPushWorkspaceRequestSchema, pt as ThreadContextWindowResponseSchema, q as RateLimitsResponseSchema, qt as apiPaths, r as ApprovalDecisionSchema, rn as promptSkillMentionTextCandidates, rt as RuntimeModeSchema, s as ChatMessagePromptDetailsSchema, st as SandboxModeSchema, t as AgentSkillSchema, tn as promptSkillMentionLabel, tt as RunThreadRequestSchema, u as ChatMessageStateSchema, ut as StreamThreadRunRequestSchema, v as ErrorResponseSchema, vt as ThreadMessageDetailFieldSchema, w as ListQueuedThreadInputsResponseSchema, wt as UpdateThreadGoalRequestSchema, x as IsoDateTimeSchema, xt as ThreadStateSchema, y as ImageAttachmentUploadResponseSchema, yt as ThreadMessageDetailResponseSchema, z as PromptSkillSchema, zt as WorkspaceTailscaleServeRequestSchema } from "./api-schema2.js";
|
|
2
|
+
export { AgentSkillSchema, AgentSkillSourceSchema, ApprovalDecisionSchema, ApprovalModeSchema, ArchiveThreadResponseSchema, ChatMessageKindSchema, ChatMessagePromptDetailsSchema, ChatMessageRoleSchema, ChatMessageSchema, ChatMessageStateSchema, CheckoutWorkspaceBranchRequestSchema, CodexModelSchema, CommitPushWorkspaceRequestSchema, ContextWindowUsageSchema, CreateThreadRequestSchema, CreateThreadResponseSchema, EncryptedPayloadSchema, ErrorResponseSchema, ImageAttachmentUploadResponseSchema, InterruptThreadRunResponseSchema, IsoDateTimeSchema, KnownReasoningEffortSchema, ListModelsResponseSchema, ListQueuedThreadInputsResponseSchema, ListSkillsResponseSchema, ListThreadsResponseSchema, ListWorkspaceDirectoriesResponseSchema, ListWorkspaceFilesResponseSchema, PairEncryptedPayloadSchema, PairRequestSchema, PairResponseSchema, PendingInputRequestOptionSchema, PendingInputRequestQuestionSchema, PendingInputRequestSchema, PromptAttachmentSchema, PromptAttachmentSummarySchema, PromptContextInputSchema, PromptContextSchema, PromptSkillSchema, PushNotificationIntentSchema, PushNotificationPreferencesSchema, PushNotificationSettingsResponseSchema, QueuedThreadInputActionResponseSchema, QueuedThreadInputSchema, RateLimitBucketSchema, RateLimitWindowSchema, RateLimitsResponseSchema, ReasoningEffortSchema, RegisterPushNotificationRequestSchema, RenameThreadRequestSchema, RenameThreadResponseSchema, ResolveApprovalRequestSchema, ResolveApprovalResponseSchema, RewindThreadRequestSchema, RunThreadRequestSchema, RunThreadResponseSchema, RuntimeModeSchema, RuntimePreferencesByWorkspacePathSchema, RuntimePreferencesResponseSchema, RuntimePreferencesSchema, SandboxModeSchema, StatusResponseSchema, StreamThreadRunEventSchema, StreamThreadRunRequestSchema, SubmitThreadInputResponseSchema, ThreadCollaborationModeSchema, ThreadContextWindowResponseSchema, ThreadDetailResponseSchema, ThreadGoalResponseSchema, ThreadGoalSchema, ThreadGoalStatusSchema, ThreadMessageDetailFieldSchema, ThreadMessageDetailResponseSchema, ThreadRunOptionsSchema, ThreadStateSchema, ThreadSummarySchema, UpdateRuntimePreferencesRequestSchema, UpdateThreadGoalRequestSchema, UpdateWorkspaceFileContentRequestSchema, VersionResponseSchema, WORKSPACE_PREVIEW_OPEN_PROTOCOL, WORKSPACE_PREVIEW_TAB_VALUES, WebPreviewTargetSchema, WorkspaceChangesResponseSchema, WorkspaceDirectoryEntrySchema, WorkspaceFileContentResponseSchema, WorkspaceFileMentionSchema, WorkspaceGitActionResponseSchema, WorkspaceMarkdownPreviewTargetSchema, WorkspacePreviewNavigationRequestSchema, WorkspacePreviewTabSchema, WorkspaceSelectionRequestSchema, WorkspaceTailscaleServeRequestSchema, WorkspaceTailscaleServeResponseSchema, WorkspaceTerminalInputRequestSchema, WorkspaceTerminalOutputChunkSchema, WorkspaceTerminalOutputResponseSchema, WorkspaceTerminalResizeRequestSchema, WorkspaceTerminalSessionResponseSchema, WorkspaceTerminalStartRequestSchema, apiPaths, chatMessageDetailsFromPromptContext, createOpenApiDocument, isPromptSkillMarkdownMention, lowestRateLimitRemainingPercent, normalizePromptContext, promptMarkdownWithSkills, promptSkillDisplayName, promptSkillMentionLabel, promptSkillMentionMarkdown, promptSkillMentionTextCandidates, rateLimitRemainingPercent, stripPromptSkillMentions };
|
package/dist/api-schema2.js
CHANGED
|
@@ -107,6 +107,7 @@ const RuntimePreferencesResponseSchema = z.object({
|
|
|
107
107
|
const PushNotificationIntentSchema = z.enum(["turn_terminal", "action_required"]);
|
|
108
108
|
const PushNotificationPreferencesSchema = z.object({
|
|
109
109
|
actionRequired: z.boolean(),
|
|
110
|
+
includeRemainingUsage: z.boolean().default(false),
|
|
110
111
|
turnTerminal: z.boolean()
|
|
111
112
|
});
|
|
112
113
|
const RegisterPushNotificationRequestSchema = z.object({
|
|
@@ -169,6 +170,13 @@ const RateLimitBucketSchema = z.object({
|
|
|
169
170
|
rateLimitReachedType: z.string().nullable().optional()
|
|
170
171
|
});
|
|
171
172
|
const RateLimitsResponseSchema = z.object({ buckets: z.array(RateLimitBucketSchema) });
|
|
173
|
+
function rateLimitRemainingPercent(usedPercent) {
|
|
174
|
+
return 100 - Math.max(0, Math.min(100, usedPercent));
|
|
175
|
+
}
|
|
176
|
+
function lowestRateLimitRemainingPercent(buckets) {
|
|
177
|
+
const remaining = buckets.flatMap((bucket) => [bucket.primary, bucket.secondary].flatMap((window) => window ? [rateLimitRemainingPercent(window.usedPercent)] : []));
|
|
178
|
+
return remaining.length > 0 ? Math.min(...remaining) : void 0;
|
|
179
|
+
}
|
|
172
180
|
const ThreadContextWindowResponseSchema = z.object({
|
|
173
181
|
threadId: z.string().min(1),
|
|
174
182
|
usage: ContextWindowUsageSchema.nullable(),
|
|
@@ -1355,6 +1363,10 @@ function createOpenApiDocument() {
|
|
|
1355
1363
|
required: ["actionRequired", "turnTerminal"],
|
|
1356
1364
|
properties: {
|
|
1357
1365
|
actionRequired: { type: "boolean" },
|
|
1366
|
+
includeRemainingUsage: {
|
|
1367
|
+
type: "boolean",
|
|
1368
|
+
default: false
|
|
1369
|
+
},
|
|
1358
1370
|
turnTerminal: { type: "boolean" }
|
|
1359
1371
|
}
|
|
1360
1372
|
},
|
|
@@ -1867,4 +1879,4 @@ function jsonResponse(schemaName) {
|
|
|
1867
1879
|
};
|
|
1868
1880
|
}
|
|
1869
1881
|
//#endregion
|
|
1870
|
-
export { ResolveApprovalResponseSchema as $,
|
|
1882
|
+
export { ResolveApprovalResponseSchema as $, promptMarkdownWithSkills as $t, PairRequestSchema as A, WorkspaceChangesResponseSchema as At, PushNotificationIntentSchema as B, WorkspaceTailscaleServeResponseSchema as Bt, ListModelsResponseSchema as C, UpdateRuntimePreferencesRequestSchema as Ct, ListWorkspaceDirectoriesResponseSchema as D, WORKSPACE_PREVIEW_OPEN_PROTOCOL as Dt, ListThreadsResponseSchema as E, VersionResponseSchema as Et, PromptAttachmentSchema as F, WorkspaceMarkdownPreviewTargetSchema as Ft, RateLimitBucketSchema as G, WorkspaceTerminalSessionResponseSchema as Gt, PushNotificationSettingsResponseSchema as H, WorkspaceTerminalOutputChunkSchema as Ht, PromptAttachmentSummarySchema as I, WorkspacePreviewNavigationRequestSchema as It, ReasoningEffortSchema as J, chatMessageDetailsFromPromptContext as Jt, RateLimitWindowSchema as K, WorkspaceTerminalStartRequestSchema as Kt, PromptContextInputSchema as L, WorkspacePreviewTabSchema as Lt, PendingInputRequestOptionSchema as M, WorkspaceFileContentResponseSchema as Mt, PendingInputRequestQuestionSchema as N, WorkspaceFileMentionSchema as Nt, ListWorkspaceFilesResponseSchema as O, WORKSPACE_PREVIEW_TAB_VALUES as Ot, PendingInputRequestSchema as P, WorkspaceGitActionResponseSchema as Pt, ResolveApprovalRequestSchema as Q, normalizePromptContext as Qt, PromptContextSchema as R, WorkspaceSelectionRequestSchema as Rt, KnownReasoningEffortSchema as S, ThreadSummarySchema as St, ListSkillsResponseSchema as T, UpdateWorkspaceFileContentRequestSchema as Tt, QueuedThreadInputActionResponseSchema as U, WorkspaceTerminalOutputResponseSchema as Ut, PushNotificationPreferencesSchema as V, WorkspaceTerminalInputRequestSchema as Vt, QueuedThreadInputSchema as W, WorkspaceTerminalResizeRequestSchema as Wt, RenameThreadRequestSchema as X, isPromptSkillMarkdownMention as Xt, RegisterPushNotificationRequestSchema as Y, createOpenApiDocument as Yt, RenameThreadResponseSchema as Z, lowestRateLimitRemainingPercent as Zt, EncryptedPayloadSchema as _, ThreadGoalStatusSchema as _t, ArchiveThreadResponseSchema as a, stripPromptSkillMentions as an, RuntimePreferencesResponseSchema as at, InterruptThreadRunResponseSchema as b, ThreadRunOptionsSchema as bt, ChatMessageRoleSchema as c, StatusResponseSchema as ct, CheckoutWorkspaceBranchRequestSchema as d, SubmitThreadInputResponseSchema as dt, promptSkillDisplayName as en, RewindThreadRequestSchema as et, CodexModelSchema as f, ThreadCollaborationModeSchema as ft, CreateThreadResponseSchema as g, ThreadGoalSchema as gt, CreateThreadRequestSchema as h, ThreadGoalResponseSchema as ht, ApprovalModeSchema as i, rateLimitRemainingPercent as in, RuntimePreferencesByWorkspacePathSchema as it, PairResponseSchema as j, WorkspaceDirectoryEntrySchema as jt, PairEncryptedPayloadSchema as k, WebPreviewTargetSchema as kt, ChatMessageSchema as l, StreamThreadRunEventSchema as lt, ContextWindowUsageSchema as m, ThreadDetailResponseSchema as mt, AgentSkillSourceSchema as n, promptSkillMentionMarkdown as nn, RunThreadResponseSchema as nt, ChatMessageKindSchema as o, RuntimePreferencesSchema as ot, CommitPushWorkspaceRequestSchema as p, ThreadContextWindowResponseSchema as pt, RateLimitsResponseSchema as q, apiPaths as qt, ApprovalDecisionSchema as r, promptSkillMentionTextCandidates as rn, RuntimeModeSchema as rt, ChatMessagePromptDetailsSchema as s, SandboxModeSchema as st, AgentSkillSchema as t, promptSkillMentionLabel as tn, RunThreadRequestSchema as tt, ChatMessageStateSchema as u, StreamThreadRunRequestSchema as ut, ErrorResponseSchema as v, ThreadMessageDetailFieldSchema as vt, ListQueuedThreadInputsResponseSchema as w, UpdateThreadGoalRequestSchema as wt, IsoDateTimeSchema as x, ThreadStateSchema as xt, ImageAttachmentUploadResponseSchema as y, ThreadMessageDetailResponseSchema as yt, PromptSkillSchema as z, WorkspaceTailscaleServeRequestSchema as zt };
|
package/dist/paths.js
CHANGED
|
@@ -130,11 +130,13 @@ async function createTursoPairingSessionStore(path) {
|
|
|
130
130
|
platform TEXT NOT NULL,
|
|
131
131
|
turn_terminal_enabled INTEGER NOT NULL,
|
|
132
132
|
action_required_enabled INTEGER NOT NULL,
|
|
133
|
+
include_remaining_usage_enabled INTEGER NOT NULL DEFAULT 0,
|
|
133
134
|
created_at INTEGER NOT NULL,
|
|
134
135
|
updated_at INTEGER NOT NULL
|
|
135
136
|
);
|
|
136
137
|
`);
|
|
137
138
|
await ensurePairingSessionColumns();
|
|
139
|
+
await ensurePushNotificationSubscriptionColumns();
|
|
138
140
|
async function countActive() {
|
|
139
141
|
const row = await db.prepare("SELECT COUNT(DISTINCT COALESCE(client_session_id, token_hash)) AS count FROM pairing_sessions").get();
|
|
140
142
|
return Number(row?.count ?? 0);
|
|
@@ -250,7 +252,8 @@ async function createTursoPairingSessionStore(path) {
|
|
|
250
252
|
expo_push_token AS expoPushToken,
|
|
251
253
|
platform,
|
|
252
254
|
turn_terminal_enabled AS turnTerminal,
|
|
253
|
-
action_required_enabled AS actionRequired
|
|
255
|
+
action_required_enabled AS actionRequired,
|
|
256
|
+
include_remaining_usage_enabled AS includeRemainingUsage
|
|
254
257
|
FROM push_notification_subscriptions
|
|
255
258
|
WHERE client_session_id = ?`).get(clientSessionId);
|
|
256
259
|
return row ? pushNotificationSubscriptionFromRow(row) : void 0;
|
|
@@ -279,7 +282,8 @@ async function createTursoPairingSessionStore(path) {
|
|
|
279
282
|
subscriptions.expo_push_token AS expoPushToken,
|
|
280
283
|
subscriptions.platform,
|
|
281
284
|
subscriptions.turn_terminal_enabled AS turnTerminal,
|
|
282
|
-
subscriptions.action_required_enabled AS actionRequired
|
|
285
|
+
subscriptions.action_required_enabled AS actionRequired,
|
|
286
|
+
subscriptions.include_remaining_usage_enabled AS includeRemainingUsage
|
|
283
287
|
FROM push_notification_subscriptions AS subscriptions
|
|
284
288
|
INNER JOIN pairing_sessions AS sessions
|
|
285
289
|
ON sessions.client_session_id = subscriptions.client_session_id
|
|
@@ -343,16 +347,18 @@ async function createTursoPairingSessionStore(path) {
|
|
|
343
347
|
platform,
|
|
344
348
|
turn_terminal_enabled,
|
|
345
349
|
action_required_enabled,
|
|
350
|
+
include_remaining_usage_enabled,
|
|
346
351
|
created_at,
|
|
347
352
|
updated_at
|
|
348
353
|
)
|
|
349
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
354
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
350
355
|
ON CONFLICT(client_session_id) DO UPDATE SET
|
|
351
356
|
expo_push_token = excluded.expo_push_token,
|
|
352
357
|
platform = excluded.platform,
|
|
353
358
|
turn_terminal_enabled = excluded.turn_terminal_enabled,
|
|
354
359
|
action_required_enabled = excluded.action_required_enabled,
|
|
355
|
-
|
|
360
|
+
include_remaining_usage_enabled = excluded.include_remaining_usage_enabled,
|
|
361
|
+
updated_at = excluded.updated_at`).run(subscription.clientSessionId, subscription.expoPushToken, subscription.platform, subscription.turnTerminal ? 1 : 0, subscription.actionRequired ? 1 : 0, subscription.includeRemainingUsage ? 1 : 0, now, now);
|
|
356
362
|
}
|
|
357
363
|
};
|
|
358
364
|
async function ensurePairingSessionColumns() {
|
|
@@ -369,6 +375,10 @@ async function createTursoPairingSessionStore(path) {
|
|
|
369
375
|
const pendingRows = await db.prepare("PRAGMA table_info(pending_pairings)").all();
|
|
370
376
|
if (!new Set(resultRows(pendingRows).map((row) => String(row.name))).has("client_session_id")) await db.exec("ALTER TABLE pending_pairings ADD COLUMN client_session_id TEXT");
|
|
371
377
|
}
|
|
378
|
+
async function ensurePushNotificationSubscriptionColumns() {
|
|
379
|
+
const rows = await db.prepare("PRAGMA table_info(push_notification_subscriptions)").all();
|
|
380
|
+
if (!new Set(resultRows(rows).map((row) => String(row.name))).has("include_remaining_usage_enabled")) await db.exec("ALTER TABLE push_notification_subscriptions ADD COLUMN include_remaining_usage_enabled INTEGER NOT NULL DEFAULT 0");
|
|
381
|
+
}
|
|
372
382
|
}
|
|
373
383
|
function encodeSecureSession(session) {
|
|
374
384
|
if (!session) return;
|
|
@@ -397,6 +407,7 @@ function pushNotificationSubscriptionFromRow(row) {
|
|
|
397
407
|
actionRequired: Number(row.actionRequired) === 1,
|
|
398
408
|
clientSessionId: row.clientSessionId,
|
|
399
409
|
expoPushToken: row.expoPushToken,
|
|
410
|
+
includeRemainingUsage: Number(row.includeRemainingUsage) === 1,
|
|
400
411
|
platform,
|
|
401
412
|
turnTerminal: Number(row.turnTerminal) === 1
|
|
402
413
|
};
|
package/dist/src.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as ResolveApprovalResponseSchema, A as PairRequestSchema, At as WorkspaceChangesResponseSchema, Bt as WorkspaceTailscaleServeResponseSchema, C as ListModelsResponseSchema, Ct as UpdateRuntimePreferencesRequestSchema, D as ListWorkspaceDirectoriesResponseSchema, E as ListThreadsResponseSchema, Et as VersionResponseSchema, Gt as WorkspaceTerminalSessionResponseSchema, H as PushNotificationSettingsResponseSchema, J as ReasoningEffortSchema, Jt as chatMessageDetailsFromPromptContext, Kt as WorkspaceTerminalStartRequestSchema, Mt as WorkspaceFileContentResponseSchema, O as ListWorkspaceFilesResponseSchema, Pt as WorkspaceGitActionResponseSchema, Q as ResolveApprovalRequestSchema, Qt as
|
|
1
|
+
import { $ as ResolveApprovalResponseSchema, $t as promptMarkdownWithSkills, A as PairRequestSchema, At as WorkspaceChangesResponseSchema, Bt as WorkspaceTailscaleServeResponseSchema, C as ListModelsResponseSchema, Ct as UpdateRuntimePreferencesRequestSchema, D as ListWorkspaceDirectoriesResponseSchema, E as ListThreadsResponseSchema, Et as VersionResponseSchema, Gt as WorkspaceTerminalSessionResponseSchema, H as PushNotificationSettingsResponseSchema, J as ReasoningEffortSchema, Jt as chatMessageDetailsFromPromptContext, Kt as WorkspaceTerminalStartRequestSchema, Mt as WorkspaceFileContentResponseSchema, O as ListWorkspaceFilesResponseSchema, Pt as WorkspaceGitActionResponseSchema, Q as ResolveApprovalRequestSchema, Qt as normalizePromptContext, S as KnownReasoningEffortSchema, St as ThreadSummarySchema, T as ListSkillsResponseSchema, Tt as UpdateWorkspaceFileContentRequestSchema, U as QueuedThreadInputActionResponseSchema, Ut as WorkspaceTerminalOutputResponseSchema, Vt as WorkspaceTerminalInputRequestSchema, Wt as WorkspaceTerminalResizeRequestSchema, X as RenameThreadRequestSchema, Y as RegisterPushNotificationRequestSchema, Yt as createOpenApiDocument, Z as RenameThreadResponseSchema, Zt as lowestRateLimitRemainingPercent, _ as EncryptedPayloadSchema, _t as ThreadGoalStatusSchema, a as ArchiveThreadResponseSchema, an as stripPromptSkillMentions, at as RuntimePreferencesResponseSchema, b as InterruptThreadRunResponseSchema, ct as StatusResponseSchema, d as CheckoutWorkspaceBranchRequestSchema, dt as SubmitThreadInputResponseSchema, et as RewindThreadRequestSchema, gt as ThreadGoalSchema, h as CreateThreadRequestSchema, ht as ThreadGoalResponseSchema, j as PairResponseSchema, l as ChatMessageSchema, lt as StreamThreadRunEventSchema, m as ContextWindowUsageSchema, mt as ThreadDetailResponseSchema, ot as RuntimePreferencesSchema, p as CommitPushWorkspaceRequestSchema, pt as ThreadContextWindowResponseSchema, q as RateLimitsResponseSchema, qt as apiPaths, tt as RunThreadRequestSchema, ut as StreamThreadRunRequestSchema, vt as ThreadMessageDetailFieldSchema, w as ListQueuedThreadInputsResponseSchema, wt as UpdateThreadGoalRequestSchema, y as ImageAttachmentUploadResponseSchema, yt as ThreadMessageDetailResponseSchema, zt as WorkspaceTailscaleServeRequestSchema } from "./api-schema2.js";
|
|
2
2
|
import { a as getConnectUrlCandidates, c as permanentClientSessionExpiresAt, i as createPairingQrPayload, o as getConnectUrlGuidance, r as legacyCodexRelayDataPath, s as createTursoPairingSessionStore, t as codexRelayDataPath } from "./paths.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import qrcode from "qrcode-terminal";
|
|
@@ -188,34 +188,32 @@ var CodexAppServerClient = class {
|
|
|
188
188
|
initialize() {
|
|
189
189
|
return this.ensureInitialized();
|
|
190
190
|
}
|
|
191
|
-
async listThreads(limit =
|
|
192
|
-
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
} while (cursor);
|
|
218
|
-
return threads;
|
|
191
|
+
async listThreads(limit = Number(process.env.CODEX_RELAY_THREAD_LIST_LIMIT ?? 20)) {
|
|
192
|
+
if (!Number.isSafeInteger(limit) || limit < 1) throw new Error("CODEX_RELAY_THREAD_LIST_LIMIT must be a positive integer.");
|
|
193
|
+
const startedAt = Date.now();
|
|
194
|
+
const params = {
|
|
195
|
+
archived: false,
|
|
196
|
+
limit,
|
|
197
|
+
sortDirection: "desc",
|
|
198
|
+
sortKey: "recency_at",
|
|
199
|
+
sourceKinds: [
|
|
200
|
+
"cli",
|
|
201
|
+
"vscode",
|
|
202
|
+
"exec",
|
|
203
|
+
"appServer"
|
|
204
|
+
]
|
|
205
|
+
};
|
|
206
|
+
let response = await this.request("thread/list", {
|
|
207
|
+
...params,
|
|
208
|
+
useStateDbOnly: true
|
|
209
|
+
});
|
|
210
|
+
if (response.data.length === 0) response = await this.request("thread/list", params);
|
|
211
|
+
relayDebugLog("thread.list.completed", {
|
|
212
|
+
durationMs: Date.now() - startedAt,
|
|
213
|
+
limit,
|
|
214
|
+
count: response.data.length
|
|
215
|
+
});
|
|
216
|
+
return response.data.slice(0, limit);
|
|
219
217
|
}
|
|
220
218
|
async readThread(threadId, options = {}) {
|
|
221
219
|
return (await this.request("thread/read", {
|
|
@@ -1029,24 +1027,25 @@ function createExpoPushNotificationSender(fetchImpl = fetch) {
|
|
|
1029
1027
|
function createPushNotificationDispatcher(input) {
|
|
1030
1028
|
return { async dispatch(event) {
|
|
1031
1029
|
const subscriptions = await input.sessions.listActivePushNotificationSubscriptions();
|
|
1032
|
-
const
|
|
1033
|
-
if (
|
|
1034
|
-
const
|
|
1030
|
+
const selectedSubscriptions = new Map(subscriptions.filter((subscription) => notificationEnabled(subscription, event.intent)).map((subscription) => [subscription.expoPushToken, subscription]));
|
|
1031
|
+
if (selectedSubscriptions.size === 0) return;
|
|
1032
|
+
const remainingUsagePercent = event.intent === "turn_terminal" && [...selectedSubscriptions.values()].some((subscription) => subscription.includeRemainingUsage) ? await input.readRemainingUsagePercent?.().catch(() => void 0) : void 0;
|
|
1033
|
+
const delivery = await input.sender.send([...selectedSubscriptions.values()].map((subscription) => notificationForEvent(subscription.expoPushToken, event, subscription.includeRemainingUsage ? remainingUsagePercent : void 0)));
|
|
1035
1034
|
await Promise.all(delivery.invalidExpoPushTokens.map((expoPushToken) => input.sessions.deletePushNotificationSubscriptionsByExpoPushToken(expoPushToken)));
|
|
1036
1035
|
} };
|
|
1037
1036
|
}
|
|
1038
1037
|
function notificationEnabled(subscription, intent) {
|
|
1039
1038
|
return intent === "action_required" ? subscription.actionRequired : subscription.turnTerminal;
|
|
1040
1039
|
}
|
|
1041
|
-
function notificationForEvent(expoPushToken, event) {
|
|
1040
|
+
function notificationForEvent(expoPushToken, event, remainingUsagePercent) {
|
|
1042
1041
|
return {
|
|
1043
|
-
body: event.intent === "action_required" ? "Codex needs your attention." : "
|
|
1042
|
+
body: event.intent === "action_required" ? "Codex needs your attention." : remainingUsagePercent === void 0 ? "Finished working." : `Finished working. Remaining usage: ${remainingUsagePercent}%`,
|
|
1044
1043
|
data: {
|
|
1045
1044
|
intent: event.intent,
|
|
1046
1045
|
threadId: event.threadId,
|
|
1047
1046
|
...event.turnId ? { turnId: event.turnId } : {}
|
|
1048
1047
|
},
|
|
1049
|
-
title:
|
|
1048
|
+
title: event.threadTitle?.trim() || event.threadId,
|
|
1050
1049
|
to: expoPushToken
|
|
1051
1050
|
};
|
|
1052
1051
|
}
|
|
@@ -1575,7 +1574,7 @@ function shellEnvValue(value) {
|
|
|
1575
1574
|
//#endregion
|
|
1576
1575
|
//#region src/app.ts
|
|
1577
1576
|
const defaultWorkspacePath = process.cwd();
|
|
1578
|
-
const defaultCodexModel = "gpt-
|
|
1577
|
+
const defaultCodexModel = "gpt-6-astra";
|
|
1579
1578
|
const execFileAsync = promisify(execFile);
|
|
1580
1579
|
const IMAGE_ATTACHMENT_MAX_BYTES = 8 * 1024 * 1024;
|
|
1581
1580
|
const WORKSPACE_FILE_PREVIEW_MAX_BYTES = 256 * 1024;
|
|
@@ -1688,6 +1687,7 @@ function createApp(options = {}) {
|
|
|
1688
1687
|
return result;
|
|
1689
1688
|
}
|
|
1690
1689
|
const pushNotificationDispatcher = options.pairing ? createPushNotificationDispatcher({
|
|
1690
|
+
readRemainingUsagePercent: appServer ? async () => lowestRateLimitRemainingPercent(normalizeRateLimitBuckets(await appServer.readRateLimits())) : void 0,
|
|
1691
1691
|
sender: options.pushNotificationSender ?? createExpoPushNotificationSender(),
|
|
1692
1692
|
sessions: options.pairing.sessions
|
|
1693
1693
|
}) : void 0;
|
|
@@ -1924,6 +1924,7 @@ function createApp(options = {}) {
|
|
|
1924
1924
|
const response = PushNotificationSettingsResponseSchema.parse({
|
|
1925
1925
|
preferences: subscription ? {
|
|
1926
1926
|
actionRequired: subscription.actionRequired,
|
|
1927
|
+
includeRemainingUsage: subscription.includeRemainingUsage,
|
|
1927
1928
|
turnTerminal: subscription.turnTerminal
|
|
1928
1929
|
} : defaultPushNotificationPreferences(),
|
|
1929
1930
|
registered: Boolean(subscription)
|
|
@@ -1940,6 +1941,7 @@ function createApp(options = {}) {
|
|
|
1940
1941
|
actionRequired: parsed.data.preferences.actionRequired,
|
|
1941
1942
|
clientSessionId,
|
|
1942
1943
|
expoPushToken: parsed.data.expoPushToken,
|
|
1944
|
+
includeRemainingUsage: parsed.data.preferences.includeRemainingUsage,
|
|
1943
1945
|
platform: parsed.data.platform,
|
|
1944
1946
|
turnTerminal: parsed.data.preferences.turnTerminal
|
|
1945
1947
|
});
|
|
@@ -2173,7 +2175,11 @@ function createApp(options = {}) {
|
|
|
2173
2175
|
app.get(apiPaths.models, async (c) => {
|
|
2174
2176
|
try {
|
|
2175
2177
|
const models = appServer ? await appServer.listModels() : fallbackModels();
|
|
2176
|
-
|
|
2178
|
+
const hasAstra = models.some((model) => model.model === defaultCodexModel);
|
|
2179
|
+
return secureJson(c, options.pairing, secureSessionsByTokenHash, ListModelsResponseSchema.parse({ models: models.map((model) => mapAppServerModel(hasAstra ? {
|
|
2180
|
+
...model,
|
|
2181
|
+
isDefault: model.model === defaultCodexModel
|
|
2182
|
+
} : model)) }));
|
|
2177
2183
|
} catch {
|
|
2178
2184
|
return secureJson(c, options.pairing, secureSessionsByTokenHash, ListModelsResponseSchema.parse({ models: fallbackModels().map(mapAppServerModel) }));
|
|
2179
2185
|
}
|
|
@@ -2400,23 +2406,26 @@ function createApp(options = {}) {
|
|
|
2400
2406
|
const turns = threadBeforeRewind.turns ?? [];
|
|
2401
2407
|
const turnIndex = turns.findIndex((turn) => turn.id === parsed.data.turnId);
|
|
2402
2408
|
if (turnIndex < 0) return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError("not_found", "The selected message is no longer available to rewind."), 404);
|
|
2403
|
-
|
|
2404
|
-
if (threadBeforeRewind.historyMode === "paginated" && typeof appServer.revertThread === "function") try {
|
|
2405
|
-
rolledBackThread = await appServer.revertThread({
|
|
2406
|
-
beforeTurnId: parsed.data.turnId,
|
|
2407
|
-
threadId
|
|
2408
|
-
});
|
|
2409
|
-
} catch (error) {
|
|
2410
|
-
if (!/method not found|unsupported|-32601/i.test(errorMessage(error))) throw error;
|
|
2411
|
-
rolledBackThread = await appServer.rollbackThread({
|
|
2412
|
-
threadId,
|
|
2413
|
-
numTurns: turns.length - turnIndex
|
|
2414
|
-
});
|
|
2415
|
-
}
|
|
2416
|
-
else rolledBackThread = await appServer.rollbackThread({
|
|
2409
|
+
const rollbackThread = () => appServer.rollbackThread({
|
|
2417
2410
|
threadId,
|
|
2418
2411
|
numTurns: turns.length - turnIndex
|
|
2419
2412
|
});
|
|
2413
|
+
let rolledBackThread;
|
|
2414
|
+
try {
|
|
2415
|
+
if (threadBeforeRewind.historyMode === "paginated" && typeof appServer.revertThread === "function") try {
|
|
2416
|
+
rolledBackThread = await appServer.revertThread({
|
|
2417
|
+
beforeTurnId: parsed.data.turnId,
|
|
2418
|
+
threadId
|
|
2419
|
+
});
|
|
2420
|
+
} catch (error) {
|
|
2421
|
+
if (!isMissingAppServerMethodError(error, "thread/revert")) throw error;
|
|
2422
|
+
rolledBackThread = await rollbackThread();
|
|
2423
|
+
}
|
|
2424
|
+
else rolledBackThread = await rollbackThread();
|
|
2425
|
+
} catch (error) {
|
|
2426
|
+
if (!isMissingAppServerMethodError(error, "thread/rollback")) throw error;
|
|
2427
|
+
return secureJson(c, options.pairing, secureSessionsByTokenHash, apiError("rewind_unsupported", "This chat uses Codex's legacy history format, which this Codex version can no longer rewind. Chats started after the update can be rewound."), 409);
|
|
2428
|
+
}
|
|
2420
2429
|
const threadWithTurns = rolledBackThread.turns === void 0 ? await appServer.readThread(threadId, { includeTurns: true }) : rolledBackThread;
|
|
2421
2430
|
const thread = rememberAppServerThread(threads, threadWithTurns, { authoritativeMessageCount: true });
|
|
2422
2431
|
const messages = mapAppServerMessages(threadWithTurns);
|
|
@@ -3080,6 +3089,7 @@ async function pairedClientSessionIdForAuthorization(authorization, pairing) {
|
|
|
3080
3089
|
function defaultPushNotificationPreferences() {
|
|
3081
3090
|
return {
|
|
3082
3091
|
actionRequired: false,
|
|
3092
|
+
includeRemainingUsage: false,
|
|
3083
3093
|
turnTerminal: false
|
|
3084
3094
|
};
|
|
3085
3095
|
}
|
|
@@ -4685,6 +4695,7 @@ function appServerUserMessageDetails(item) {
|
|
|
4685
4695
|
const attachments = item.content.flatMap((content) => {
|
|
4686
4696
|
switch (content.type) {
|
|
4687
4697
|
case "image":
|
|
4698
|
+
if (!content.url) return [];
|
|
4688
4699
|
if (content.url.startsWith("data:image/")) {
|
|
4689
4700
|
const materialized = materializeDataUriImage(content.url);
|
|
4690
4701
|
return materialized ? [materialized] : [];
|
|
@@ -5328,7 +5339,7 @@ function mapAppServerThread(thread, fallbackMessageCount) {
|
|
|
5328
5339
|
return ThreadSummarySchema.parse({
|
|
5329
5340
|
id: thread.id,
|
|
5330
5341
|
parentThreadId: thread.parentThreadId ?? void 0,
|
|
5331
|
-
title:
|
|
5342
|
+
title: appServerThreadTitle(thread),
|
|
5332
5343
|
createdAt,
|
|
5333
5344
|
updatedAt,
|
|
5334
5345
|
state: mappedState,
|
|
@@ -5339,6 +5350,9 @@ function mapAppServerThread(thread, fallbackMessageCount) {
|
|
|
5339
5350
|
lastActivityAt
|
|
5340
5351
|
});
|
|
5341
5352
|
}
|
|
5353
|
+
function appServerThreadTitle(thread) {
|
|
5354
|
+
return thread.name ?? preview(thread.preview || "Untitled thread");
|
|
5355
|
+
}
|
|
5342
5356
|
function rememberAppServerThread(threads, thread, options = {}) {
|
|
5343
5357
|
const existingThread = threads.get(thread.id);
|
|
5344
5358
|
const mappedThread = mapAppServerThread(thread, options.authoritativeMessageCount ? void 0 : existingThread?.messageCount);
|
|
@@ -6202,26 +6216,54 @@ function objectRecord(value) {
|
|
|
6202
6216
|
return value && typeof value === "object" ? value : void 0;
|
|
6203
6217
|
}
|
|
6204
6218
|
function fallbackModels() {
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6219
|
+
const efforts = [
|
|
6220
|
+
"low",
|
|
6221
|
+
"medium",
|
|
6222
|
+
"high",
|
|
6223
|
+
"xhigh",
|
|
6224
|
+
"max"
|
|
6225
|
+
];
|
|
6226
|
+
return [
|
|
6227
|
+
fallbackModel({
|
|
6228
|
+
description: "Frontier intelligence for the most demanding work.",
|
|
6229
|
+
displayName: "GPT-6-Astra",
|
|
6230
|
+
efforts: [...efforts, "ultra"],
|
|
6231
|
+
fastDescription: "2x speed, increased usage",
|
|
6232
|
+
isDefault: true,
|
|
6233
|
+
model: defaultCodexModel
|
|
6234
|
+
}),
|
|
6235
|
+
fallbackModel({
|
|
6236
|
+
description: "Workhorse model for coding and everyday work.",
|
|
6237
|
+
displayName: "GPT-6-Sol",
|
|
6238
|
+
efforts: [...efforts, "ultra"],
|
|
6239
|
+
fastDescription: "1.5x speed",
|
|
6240
|
+
model: "gpt-6-sol"
|
|
6241
|
+
}),
|
|
6242
|
+
fallbackModel({
|
|
6243
|
+
description: "Fast and affordable model for easier tasks.",
|
|
6244
|
+
displayName: "GPT-6-Luna",
|
|
6245
|
+
efforts,
|
|
6246
|
+
fastDescription: "1.5x speed",
|
|
6247
|
+
model: "gpt-6-luna"
|
|
6248
|
+
})
|
|
6249
|
+
];
|
|
6250
|
+
}
|
|
6251
|
+
function fallbackModel({ description, displayName, efforts, fastDescription, isDefault = false, model }) {
|
|
6252
|
+
return {
|
|
6253
|
+
id: model,
|
|
6254
|
+
model,
|
|
6255
|
+
displayName,
|
|
6256
|
+
description,
|
|
6257
|
+
isDefault,
|
|
6211
6258
|
defaultReasoningEffort: "medium",
|
|
6212
|
-
supportedReasoningEfforts:
|
|
6213
|
-
{ reasoningEffort: "low" },
|
|
6214
|
-
{ reasoningEffort: "medium" },
|
|
6215
|
-
{ reasoningEffort: "high" },
|
|
6216
|
-
{ reasoningEffort: "xhigh" }
|
|
6217
|
-
],
|
|
6259
|
+
supportedReasoningEfforts: efforts.map((reasoningEffort) => ({ reasoningEffort })),
|
|
6218
6260
|
additionalSpeedTiers: ["fast"],
|
|
6219
6261
|
serviceTiers: [{
|
|
6220
6262
|
id: "priority",
|
|
6221
6263
|
name: "Fast",
|
|
6222
|
-
description:
|
|
6264
|
+
description: fastDescription
|
|
6223
6265
|
}]
|
|
6224
|
-
}
|
|
6266
|
+
};
|
|
6225
6267
|
}
|
|
6226
6268
|
function mapAppServerThreadState(status, turns) {
|
|
6227
6269
|
if (turns?.some(isAppServerTurnRunning)) return "running";
|
|
@@ -6417,7 +6459,10 @@ function observeAppServerPushNotifications(appServer, dispatcher) {
|
|
|
6417
6459
|
if (dispatchedEventIds.has(eventId)) return;
|
|
6418
6460
|
rememberEventId(eventId);
|
|
6419
6461
|
appServer.readThread(event.threadId, { includeTurns: false }).then((thread) => {
|
|
6420
|
-
if (!isSubagentThread(thread)) return dispatcher.dispatch(
|
|
6462
|
+
if (!isSubagentThread(thread)) return dispatcher.dispatch({
|
|
6463
|
+
...event,
|
|
6464
|
+
threadTitle: appServerThreadTitle(thread)
|
|
6465
|
+
});
|
|
6421
6466
|
}).catch((error) => {
|
|
6422
6467
|
relayDebugLog("push_notification.dispatch_failed", {
|
|
6423
6468
|
error: errorMessage(error),
|
|
@@ -7430,9 +7475,96 @@ function apiError(code, message, issues) {
|
|
|
7430
7475
|
function errorMessage(error) {
|
|
7431
7476
|
return error instanceof Error ? error.message : "Codex run failed.";
|
|
7432
7477
|
}
|
|
7478
|
+
function isMissingAppServerMethodError(error, method) {
|
|
7479
|
+
const message = errorMessage(error);
|
|
7480
|
+
return /method not found|-32601/i.test(message) || message.includes(`unknown variant \`${method}\``);
|
|
7481
|
+
}
|
|
7482
|
+
//#endregion
|
|
7483
|
+
//#region src/terminal-pairing.ts
|
|
7484
|
+
function createTerminalPairingApprover(options) {
|
|
7485
|
+
const queue = [];
|
|
7486
|
+
let active;
|
|
7487
|
+
let reader;
|
|
7488
|
+
let expiry;
|
|
7489
|
+
let answering = false;
|
|
7490
|
+
let closed = false;
|
|
7491
|
+
function print(message) {
|
|
7492
|
+
options.output.write(`${message}\n`);
|
|
7493
|
+
}
|
|
7494
|
+
function close() {
|
|
7495
|
+
closed = true;
|
|
7496
|
+
queue.length = 0;
|
|
7497
|
+
active = void 0;
|
|
7498
|
+
clearTimeout(expiry);
|
|
7499
|
+
reader?.close();
|
|
7500
|
+
}
|
|
7501
|
+
function next() {
|
|
7502
|
+
if (closed || active || answering) return;
|
|
7503
|
+
clearTimeout(expiry);
|
|
7504
|
+
active = queue.shift();
|
|
7505
|
+
while (active && active.expiresAt <= Date.now()) active = queue.shift();
|
|
7506
|
+
if (!active) return;
|
|
7507
|
+
print(`\nPairing request from ${(active.clientName ?? "mobile device").replace(/[\p{Cc}\p{Cf}]/gu, "").slice(0, 80)}. Code: ${active.approvalCode}`);
|
|
7508
|
+
print("Check that this code matches your phone. Approve? [y/N] (then Enter)");
|
|
7509
|
+
expiry = setTimeout(() => {
|
|
7510
|
+
print("Pairing request expired. Open the pairing link again to retry.");
|
|
7511
|
+
active = void 0;
|
|
7512
|
+
next();
|
|
7513
|
+
}, Math.max(1, active.expiresAt - Date.now()));
|
|
7514
|
+
}
|
|
7515
|
+
async function answer(line) {
|
|
7516
|
+
if (!active || answering || closed) return;
|
|
7517
|
+
const pairing = active;
|
|
7518
|
+
active = void 0;
|
|
7519
|
+
answering = true;
|
|
7520
|
+
clearTimeout(expiry);
|
|
7521
|
+
try {
|
|
7522
|
+
if (!/^(y|yes)$/i.test(line.trim())) {
|
|
7523
|
+
print("Not approved. You can still use the approve command for this request.");
|
|
7524
|
+
return;
|
|
7525
|
+
}
|
|
7526
|
+
const approved = await options.sessions.approvePendingPairing(pairing.approvalCode, Date.now());
|
|
7527
|
+
if (approved) options.onApproved(approved);
|
|
7528
|
+
else print("This pairing request expired or was already completed. Open the pairing link again.");
|
|
7529
|
+
} catch {
|
|
7530
|
+
print("Could not approve pairing. Try the approve command or open the pairing link again.");
|
|
7531
|
+
} finally {
|
|
7532
|
+
answering = false;
|
|
7533
|
+
next();
|
|
7534
|
+
}
|
|
7535
|
+
}
|
|
7536
|
+
return {
|
|
7537
|
+
close,
|
|
7538
|
+
async request(approvalCode) {
|
|
7539
|
+
if (closed || !options.input.isTTY || !options.output.isTTY) return;
|
|
7540
|
+
try {
|
|
7541
|
+
const pairing = await options.sessions.getPendingPairing(approvalCode, Date.now());
|
|
7542
|
+
if (!pairing || pairing.approved || closed) return;
|
|
7543
|
+
if (active?.approvalCode === approvalCode || queue.some((item) => item.approvalCode === approvalCode)) return;
|
|
7544
|
+
if (queue.length >= 10) {
|
|
7545
|
+
print("More pairing requests are waiting. Use the approve command for this request.");
|
|
7546
|
+
return;
|
|
7547
|
+
}
|
|
7548
|
+
if (!reader) {
|
|
7549
|
+
reader = createInterface({
|
|
7550
|
+
input: options.input,
|
|
7551
|
+
terminal: false
|
|
7552
|
+
});
|
|
7553
|
+
reader.on("line", (line) => void answer(line));
|
|
7554
|
+
reader.on("close", close);
|
|
7555
|
+
}
|
|
7556
|
+
queue.push(pairing);
|
|
7557
|
+
next();
|
|
7558
|
+
} catch {
|
|
7559
|
+
print("Could not show pairing approval. Use the approve command instead.");
|
|
7560
|
+
}
|
|
7561
|
+
}
|
|
7562
|
+
};
|
|
7563
|
+
}
|
|
7433
7564
|
//#endregion
|
|
7434
7565
|
//#region src/index.ts
|
|
7435
7566
|
const port = Number(process.env.PORT ?? 8787);
|
|
7567
|
+
let activePort = port;
|
|
7436
7568
|
const hostname$1 = process.env.HOST ?? "0.0.0.0";
|
|
7437
7569
|
const dangerouslyAutoApprove = process.env.CODEX_RELAY_DANGEROUSLY_AUTO_APPROVE === "1";
|
|
7438
7570
|
const serverIdentity = await getServerIdentity();
|
|
@@ -7457,6 +7589,12 @@ const color = {
|
|
|
7457
7589
|
};
|
|
7458
7590
|
const npxCommand = "npx codex-relay@latest";
|
|
7459
7591
|
const sessionStore = await createTursoPairingSessionStore(process.env.CODEX_RELAY_AUTH_DB_PATH ?? await prepareCodexRelayDataPath("auth.db", ["auth.db-shm", "auth.db-wal"]));
|
|
7592
|
+
const terminalPairing = createTerminalPairingApprover({
|
|
7593
|
+
input: process.stdin,
|
|
7594
|
+
output: process.stdout,
|
|
7595
|
+
sessions: sessionStore,
|
|
7596
|
+
onApproved: () => logRuntimeEvent("Approved", "Pairing approved. Waiting for your phone to finish connecting.")
|
|
7597
|
+
});
|
|
7460
7598
|
const preferencesStore = createFileRuntimePreferencesStore(process.env.CODEX_RELAY_PREFERENCES_PATH ?? await prepareCodexRelayDataPath("preferences.json"));
|
|
7461
7599
|
const appServerMode = resolveCodexAppServerMode();
|
|
7462
7600
|
const relayAppServer = appServerMode.mode === "socket" ? new CodexAppServerClient({
|
|
@@ -7487,8 +7625,9 @@ serve({
|
|
|
7487
7625
|
onPairAttempt: ({ remoteAddress }) => {
|
|
7488
7626
|
logRuntimeEvent("Pairing", `Handshake received${remoteAddress ? ` from ${remoteAddress}` : ""}.`);
|
|
7489
7627
|
},
|
|
7490
|
-
onPairApprovalRequested: ({ clientName }) => {
|
|
7491
|
-
logRuntimeEvent("Approval", `Pairing approval requested${clientName ? ` from ${clientName}` : ""}.
|
|
7628
|
+
onPairApprovalRequested: ({ approvalCode, clientName }) => {
|
|
7629
|
+
logRuntimeEvent("Approval", `Pairing approval requested${clientName ? ` from ${clientName}` : ""}. Command: ${formatApprovalCommand(approvalCode, activePort)}`);
|
|
7630
|
+
terminalPairing.request(approvalCode);
|
|
7492
7631
|
},
|
|
7493
7632
|
onPairApproved: ({ clientName }) => {
|
|
7494
7633
|
logRuntimeEvent("Approved", `Pairing request approved${clientName ? ` for ${clientName}` : ""}. Waiting for secure session pickup.`);
|
|
@@ -7505,6 +7644,7 @@ serve({
|
|
|
7505
7644
|
hostname: hostname$1,
|
|
7506
7645
|
port
|
|
7507
7646
|
}, (info) => {
|
|
7647
|
+
activePort = info.port;
|
|
7508
7648
|
const listenUrl = `http://${info.address}:${info.port}`;
|
|
7509
7649
|
const connectUrlCandidates = getConnectUrlCandidates({
|
|
7510
7650
|
listenUrl,
|
|
@@ -7589,7 +7729,7 @@ function formatStartupInstructions(details) {
|
|
|
7589
7729
|
` ${color.command(`${npxCommand} approve <code>`)} Approve a device`,
|
|
7590
7730
|
"",
|
|
7591
7731
|
details.dangerouslyAutoApprove ? `${color.prompt("›")} Pairing requests will be auto-approved.` : `${color.prompt("›")} Waiting for pairing requests`,
|
|
7592
|
-
details.dangerouslyAutoApprove ? `${color.prompt("›")} Disable this for normal use.` : `${color.prompt("›")} Approve a device with ${color.command(formatApprovalCommand("<code>", details.port))}`
|
|
7732
|
+
details.dangerouslyAutoApprove ? `${color.prompt("›")} Disable this for normal use.` : process.stdin.isTTY && process.stdout.isTTY ? `${color.prompt("›")} Approve a device here when prompted: type y and press Enter.` : `${color.prompt("›")} Approve a device with ${color.command(formatApprovalCommand("<code>", details.port))}`
|
|
7593
7733
|
],
|
|
7594
7734
|
""
|
|
7595
7735
|
].join("\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codex-relay",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Local Codex Relay CLI bridge for the Codex Relay mobile app.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"@noble/ciphers": "2.2.0",
|
|
42
42
|
"@noble/curves": "2.2.0",
|
|
43
43
|
"@noble/hashes": "2.2.0",
|
|
44
|
-
"@openai/codex": "0.
|
|
45
|
-
"@openai/codex-sdk": "0.
|
|
44
|
+
"@openai/codex": "0.156.1",
|
|
45
|
+
"@openai/codex-sdk": "0.156.1",
|
|
46
46
|
"base64-js": "1.5.1",
|
|
47
47
|
"commander": "^14.0.3",
|
|
48
48
|
"es-git": "^0.6.0",
|
package/src/api-schema.ts
CHANGED
|
@@ -99,6 +99,7 @@ export const PushNotificationIntentSchema = z.enum(["turn_terminal", "action_req
|
|
|
99
99
|
|
|
100
100
|
export const PushNotificationPreferencesSchema = z.object({
|
|
101
101
|
actionRequired: z.boolean(),
|
|
102
|
+
includeRemainingUsage: z.boolean().default(false),
|
|
102
103
|
turnTerminal: z.boolean(),
|
|
103
104
|
});
|
|
104
105
|
|
|
@@ -179,6 +180,19 @@ export const RateLimitsResponseSchema = z.object({
|
|
|
179
180
|
buckets: z.array(RateLimitBucketSchema),
|
|
180
181
|
});
|
|
181
182
|
|
|
183
|
+
export function rateLimitRemainingPercent(usedPercent: number) {
|
|
184
|
+
return 100 - Math.max(0, Math.min(100, usedPercent));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export function lowestRateLimitRemainingPercent(buckets: readonly RateLimitBucket[]) {
|
|
188
|
+
const remaining = buckets.flatMap((bucket) =>
|
|
189
|
+
[bucket.primary, bucket.secondary].flatMap((window) =>
|
|
190
|
+
window ? [rateLimitRemainingPercent(window.usedPercent)] : [],
|
|
191
|
+
),
|
|
192
|
+
);
|
|
193
|
+
return remaining.length > 0 ? Math.min(...remaining) : undefined;
|
|
194
|
+
}
|
|
195
|
+
|
|
182
196
|
export const ThreadContextWindowResponseSchema = z.object({
|
|
183
197
|
threadId: z.string().min(1),
|
|
184
198
|
usage: ContextWindowUsageSchema.nullable(),
|
|
@@ -1636,6 +1650,7 @@ export function createOpenApiDocument() {
|
|
|
1636
1650
|
required: ["actionRequired", "turnTerminal"],
|
|
1637
1651
|
properties: {
|
|
1638
1652
|
actionRequired: { type: "boolean" },
|
|
1653
|
+
includeRemainingUsage: { type: "boolean", default: false },
|
|
1639
1654
|
turnTerminal: { type: "boolean" },
|
|
1640
1655
|
},
|
|
1641
1656
|
},
|