codexui-android 0.1.109 → 0.1.110

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.
@@ -1,4 +1,4 @@
1
- import{t as te,u as ne,v as J,w as h,x as Be,y as Xe,z as qn,g as I,e as Kt,A as $t,B as Gn,m as zn,C as v,E as Kn,G as $n,S as he,H as Bn,F as Qe,I as Ze,L as jn,J as Bt,K as Yn,M as Jn,N as Xn,O as Qn,i as Tt,P as wt,r as yt,Q as Zn}from"./index.esm-DvadSfWE.js";/**
1
+ import{t as te,u as ne,v as J,w as h,x as Be,y as Xe,z as qn,g as I,e as Kt,A as $t,B as Gn,m as zn,C as v,E as Kn,G as $n,S as he,H as Bn,F as Qe,I as Ze,L as jn,J as Bt,K as Yn,M as Jn,N as Xn,O as Qn,i as Tt,P as wt,r as yt,Q as Zn}from"./index.esm-aDL62PRZ.js";/**
2
2
  * @license
3
3
  * Copyright 2021 Google LLC
4
4
  *
@@ -1603,7 +1603,7 @@ import{t as te,u as ne,v as J,w as h,x as Be,y as Xe,z as qn,g as I,e as Kt,A as
1603
1603
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1604
1604
  * See the License for the specific language governing permissions and
1605
1605
  * limitations under the License.
1606
- */const $e="webStorageSupport";class Us{constructor(){this.eventManagers={},this.iframes={},this.originValidationPromises={},this._redirectPersistence=Nn,this._completeRedirectFn=Un,this._overrideRedirectResult=is}async _openPopup(e,t,i,r){var o;C((o=this.eventManagers[e._key()])==null?void 0:o.manager,"_initialize() not called before _openPopup()");const s=await Wt(e,t,i,ae(),r);return Cs(e,s,Ue())}async _openRedirect(e,t,i,r){await this._originValidation(e);const s=await Wt(e,t,i,ae(),r);return br(s),new Promise(()=>{})}_initialize(e){const t=e._key();if(this.eventManagers[t]){const{manager:r,promise:s}=this.eventManagers[t];return r?Promise.resolve(r):(C(s,"If manager is not set, promise should be"),s)}const i=this.initAndGetManager(e);return this.eventManagers[t]={promise:i},i.catch(()=>{delete this.eventManagers[t]}),i}async initAndGetManager(e){const t=await As(e),i=new cs(e);return t.register("authEvent",r=>(u(r==null?void 0:r.authEvent,e,"invalid-auth-event"),{status:i.onEvent(r.authEvent)?"ACK":"ERROR"}),gapi.iframes.CROSS_ORIGIN_IFRAMES_FILTER),this.eventManagers[e._key()]={manager:i},this.iframes[e._key()]=t,i}_isIframeWebStorageSupported(e,t){this.iframes[e._key()].send($e,{type:$e},r=>{var o;const s=(o=r==null?void 0:r[0])==null?void 0:o[$e];s!==void 0&&t(!!s),y(e,"internal-error")},gapi.iframes.CROSS_ORIGIN_IFRAMES_FILTER)}_originValidation(e){const t=e._key();return this.originValidationPromises[t]||(this.originValidationPromises[t]=fs(e)),this.originValidationPromises[t]}get _shouldInitProactively(){return dn()||sn()||rt()}}const Vs=Us;class xn{constructor(e){this.factorId=e}_process(e,t,i){switch(t.type){case"enroll":return this._finalizeEnroll(e,t.credential,i);case"signin":return this._finalizeSignIn(e,t.credential);default:return P("unexpected MultiFactorSessionType")}}}class It extends xn{constructor(e){super("phone"),this.credential=e}static _fromCredential(e){return new It(e)}_finalizeEnroll(e,t,i){return yr(e,{idToken:t,displayName:i,phoneVerificationInfo:this.credential._makeVerificationRequest()})}_finalizeSignIn(e,t){return qr(e,{mfaPendingCredential:t,phoneVerificationInfo:this.credential._makeVerificationRequest()})}}class Fs{constructor(){}static assertion(e){return It._fromCredential(e)}}Fs.FACTOR_ID="phone";class xs{static assertionForEnrollment(e,t){return de._fromSecret(e,t)}static assertionForSignIn(e,t){return de._fromEnrollmentId(e,t)}static async generateSecret(e){var r;const t=e;u(typeof((r=t.user)==null?void 0:r.auth)<"u","internal-error");const i=await vr(t.user.auth,{idToken:t.credential,totpEnrollmentInfo:{}});return _t._fromStartTotpMfaEnrollmentResponse(i,t.user.auth)}}xs.FACTOR_ID="totp";class de extends xn{constructor(e,t,i){super("totp"),this.otp=e,this.enrollmentId=t,this.secret=i}static _fromSecret(e,t){return new de(t,void 0,e)}static _fromEnrollmentId(e,t){return new de(t,e)}async _finalizeEnroll(e,t,i){return u(typeof this.secret<"u",e,"argument-error"),Ar(e,{idToken:t,displayName:i,totpVerificationInfo:this.secret._makeTotpVerificationInfo(this.otp)})}async _finalizeSignIn(e,t){u(this.enrollmentId!==void 0&&this.otp!==void 0,e,"argument-error");const i={verificationCode:this.otp};return Gr(e,{mfaPendingCredential:t,mfaEnrollmentId:this.enrollmentId,totpVerificationInfo:i})}}class _t{constructor(e,t,i,r,s,o,a){this.sessionInfo=o,this.auth=a,this.secretKey=e,this.hashingAlgorithm=t,this.codeLength=i,this.codeIntervalSeconds=r,this.enrollmentCompletionDeadline=s}static _fromStartTotpMfaEnrollmentResponse(e,t){return new _t(e.totpSessionInfo.sharedSecretKey,e.totpSessionInfo.hashingAlgorithm,e.totpSessionInfo.verificationCodeLength,e.totpSessionInfo.periodSec,new Date(e.totpSessionInfo.finalizeEnrollmentTime).toUTCString(),e.totpSessionInfo.sessionInfo,t)}_makeTotpVerificationInfo(e){return{sessionInfo:this.sessionInfo,verificationCode:e}}generateQrCodeUrl(e,t){var r;let i=!1;return(Te(e)||Te(t))&&(i=!0),i&&(Te(e)&&(e=((r=this.auth.currentUser)==null?void 0:r.email)||"unknownuser"),Te(t)&&(t=this.auth.name)),`otpauth://totp/${t}:${e}?secret=${this.secretKey}&issuer=${t}&algorithm=${this.hashingAlgorithm}&digits=${this.codeLength}`}}function Te(n){return typeof n>"u"||(n==null?void 0:n.length)===0}var qt="@firebase/auth",Gt="1.12.2";/**
1606
+ */const $e="webStorageSupport";class Us{constructor(){this.eventManagers={},this.iframes={},this.originValidationPromises={},this._redirectPersistence=Nn,this._completeRedirectFn=Un,this._overrideRedirectResult=is}async _openPopup(e,t,i,r){var o;C((o=this.eventManagers[e._key()])==null?void 0:o.manager,"_initialize() not called before _openPopup()");const s=await Wt(e,t,i,ae(),r);return Cs(e,s,Ue())}async _openRedirect(e,t,i,r){await this._originValidation(e);const s=await Wt(e,t,i,ae(),r);return br(s),new Promise(()=>{})}_initialize(e){const t=e._key();if(this.eventManagers[t]){const{manager:r,promise:s}=this.eventManagers[t];return r?Promise.resolve(r):(C(s,"If manager is not set, promise should be"),s)}const i=this.initAndGetManager(e);return this.eventManagers[t]={promise:i},i.catch(()=>{delete this.eventManagers[t]}),i}async initAndGetManager(e){const t=await As(e),i=new cs(e);return t.register("authEvent",r=>(u(r==null?void 0:r.authEvent,e,"invalid-auth-event"),{status:i.onEvent(r.authEvent)?"ACK":"ERROR"}),gapi.iframes.CROSS_ORIGIN_IFRAMES_FILTER),this.eventManagers[e._key()]={manager:i},this.iframes[e._key()]=t,i}_isIframeWebStorageSupported(e,t){this.iframes[e._key()].send($e,{type:$e},r=>{var o;const s=(o=r==null?void 0:r[0])==null?void 0:o[$e];s!==void 0&&t(!!s),y(e,"internal-error")},gapi.iframes.CROSS_ORIGIN_IFRAMES_FILTER)}_originValidation(e){const t=e._key();return this.originValidationPromises[t]||(this.originValidationPromises[t]=fs(e)),this.originValidationPromises[t]}get _shouldInitProactively(){return dn()||sn()||rt()}}const Vs=Us;class xn{constructor(e){this.factorId=e}_process(e,t,i){switch(t.type){case"enroll":return this._finalizeEnroll(e,t.credential,i);case"signin":return this._finalizeSignIn(e,t.credential);default:return P("unexpected MultiFactorSessionType")}}}class It extends xn{constructor(e){super("phone"),this.credential=e}static _fromCredential(e){return new It(e)}_finalizeEnroll(e,t,i){return yr(e,{idToken:t,displayName:i,phoneVerificationInfo:this.credential._makeVerificationRequest()})}_finalizeSignIn(e,t){return qr(e,{mfaPendingCredential:t,phoneVerificationInfo:this.credential._makeVerificationRequest()})}}class Fs{constructor(){}static assertion(e){return It._fromCredential(e)}}Fs.FACTOR_ID="phone";class xs{static assertionForEnrollment(e,t){return de._fromSecret(e,t)}static assertionForSignIn(e,t){return de._fromEnrollmentId(e,t)}static async generateSecret(e){var r;const t=e;u(typeof((r=t.user)==null?void 0:r.auth)<"u","internal-error");const i=await vr(t.user.auth,{idToken:t.credential,totpEnrollmentInfo:{}});return _t._fromStartTotpMfaEnrollmentResponse(i,t.user.auth)}}xs.FACTOR_ID="totp";class de extends xn{constructor(e,t,i){super("totp"),this.otp=e,this.enrollmentId=t,this.secret=i}static _fromSecret(e,t){return new de(t,void 0,e)}static _fromEnrollmentId(e,t){return new de(t,e)}async _finalizeEnroll(e,t,i){return u(typeof this.secret<"u",e,"argument-error"),Ar(e,{idToken:t,displayName:i,totpVerificationInfo:this.secret._makeTotpVerificationInfo(this.otp)})}async _finalizeSignIn(e,t){u(this.enrollmentId!==void 0&&this.otp!==void 0,e,"argument-error");const i={verificationCode:this.otp};return Gr(e,{mfaPendingCredential:t,mfaEnrollmentId:this.enrollmentId,totpVerificationInfo:i})}}class _t{constructor(e,t,i,r,s,o,a){this.sessionInfo=o,this.auth=a,this.secretKey=e,this.hashingAlgorithm=t,this.codeLength=i,this.codeIntervalSeconds=r,this.enrollmentCompletionDeadline=s}static _fromStartTotpMfaEnrollmentResponse(e,t){return new _t(e.totpSessionInfo.sharedSecretKey,e.totpSessionInfo.hashingAlgorithm,e.totpSessionInfo.verificationCodeLength,e.totpSessionInfo.periodSec,new Date(e.totpSessionInfo.finalizeEnrollmentTime).toUTCString(),e.totpSessionInfo.sessionInfo,t)}_makeTotpVerificationInfo(e){return{sessionInfo:this.sessionInfo,verificationCode:e}}generateQrCodeUrl(e,t){var r;let i=!1;return(Te(e)||Te(t))&&(i=!0),i&&(Te(e)&&(e=((r=this.auth.currentUser)==null?void 0:r.email)||"unknownuser"),Te(t)&&(t=this.auth.name)),`otpauth://totp/${t}:${e}?secret=${this.secretKey}&issuer=${t}&algorithm=${this.hashingAlgorithm}&digits=${this.codeLength}`}}function Te(n){return typeof n>"u"||(n==null?void 0:n.length)===0}var qt="@firebase/auth",Gt="1.13.1";/**
1607
1607
  * @license
1608
1608
  * Copyright 2020 Google LLC
1609
1609
  *
@@ -1,4 +1,4 @@
1
- import{r as e}from"./index.esm-DvadSfWE.js";import{F as o,S as t,D as n,_,a as v,b as m,c as A,d as g,e as S,f as d,g as b,h as l,i as F,j as c,k as E,l as f,m as C,n as L,o as D,p as N,q as O,s as x}from"./index.esm-DvadSfWE.js";var s="firebase",a="12.11.0";/**
1
+ import{r as e}from"./index.esm-aDL62PRZ.js";import{F as o,S as t,D as n,_,a as v,b as m,c as A,d as g,e as S,f as d,g as b,h as l,i as F,j as c,k as E,l as f,m as C,n as L,o as D,p as N,q as O,s as x}from"./index.esm-aDL62PRZ.js";var s="firebase",a="12.13.0";/**
2
2
  * @license
3
3
  * Copyright 2020 Google LLC
4
4
  *
@@ -208,7 +208,7 @@ const pe=()=>{};var U={};/**
208
208
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
209
209
  * See the License for the specific language governing permissions and
210
210
  * limitations under the License.
211
- */class Xe{constructor(e){this.container=e}getPlatformInfoString(){return this.container.getProviders().map(n=>{if(Qe(n)){const r=n.getImmediate();return`${r.library}/${r.version}`}else return null}).filter(n=>n).join(" ")}}function Qe(t){const e=t.getComponent();return(e==null?void 0:e.type)==="VERSION"}const S="@firebase/app",x="0.14.10";/**
211
+ */class Xe{constructor(e){this.container=e}getPlatformInfoString(){return this.container.getProviders().map(n=>{if(Qe(n)){const r=n.getImmediate();return`${r.library}/${r.version}`}else return null}).filter(n=>n).join(" ")}}function Qe(t){const e=t.getComponent();return(e==null?void 0:e.type)==="VERSION"}const S="@firebase/app",x="0.14.12";/**
212
212
  * @license
213
213
  * Copyright 2019 Google LLC
214
214
  *
@@ -223,7 +223,7 @@ const pe=()=>{};var U={};/**
223
223
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
224
224
  * See the License for the specific language governing permissions and
225
225
  * limitations under the License.
226
- */const d=new Pe("@firebase/app"),Ze="@firebase/app-compat",et="@firebase/analytics-compat",tt="@firebase/analytics",nt="@firebase/app-check-compat",rt="@firebase/app-check",st="@firebase/auth",it="@firebase/auth-compat",ot="@firebase/database",at="@firebase/data-connect",ct="@firebase/database-compat",lt="@firebase/functions",ht="@firebase/functions-compat",ft="@firebase/installations",dt="@firebase/installations-compat",ut="@firebase/messaging",pt="@firebase/messaging-compat",mt="@firebase/performance",gt="@firebase/performance-compat",bt="@firebase/remote-config",yt="@firebase/remote-config-compat",Et="@firebase/storage",vt="@firebase/storage-compat",_t="@firebase/firestore",Ct="@firebase/ai",Dt="@firebase/firestore-compat",wt="firebase",It="12.11.0";/**
226
+ */const d=new Pe("@firebase/app"),Ze="@firebase/app-compat",et="@firebase/analytics-compat",tt="@firebase/analytics",nt="@firebase/app-check-compat",rt="@firebase/app-check",st="@firebase/auth",it="@firebase/auth-compat",ot="@firebase/database",at="@firebase/data-connect",ct="@firebase/database-compat",lt="@firebase/functions",ht="@firebase/functions-compat",ft="@firebase/installations",dt="@firebase/installations-compat",ut="@firebase/messaging",pt="@firebase/messaging-compat",mt="@firebase/performance",gt="@firebase/performance-compat",bt="@firebase/remote-config",yt="@firebase/remote-config-compat",Et="@firebase/storage",vt="@firebase/storage-compat",_t="@firebase/firestore",Ct="@firebase/ai",Dt="@firebase/firestore-compat",wt="firebase",It="12.13.0";/**
227
227
  * @license
228
228
  * Copyright 2019 Google LLC
229
229
  *
package/dist/index.html CHANGED
@@ -12,8 +12,8 @@
12
12
  <link rel="icon" type="image/png" sizes="192x192" href="/icons/pwa-192x192.png" />
13
13
  <link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png" />
14
14
  <title>Codex Web</title>
15
- <script type="module" crossorigin src="/assets/index-ZXDbBStq.js"></script>
16
- <link rel="stylesheet" crossorigin href="/assets/index-AFrh-w0S.css">
15
+ <script type="module" crossorigin src="/assets/index-xzqof2OU.js"></script>
16
+ <link rel="stylesheet" crossorigin href="/assets/index-BZZznPCP.css">
17
17
  </head>
18
18
  <body class="bg-slate-950">
19
19
  <div id="app"></div>
package/dist-cli/index.js CHANGED
@@ -4264,8 +4264,8 @@ function createDefaultOpenCodeZenFreeModeState() {
4264
4264
  providerKeys: {}
4265
4265
  };
4266
4266
  }
4267
- function shouldCreateDefaultFreeModeStateForMissingAuth(current, hasUsableCodexAuth) {
4268
- return current == null && !hasUsableCodexAuth;
4267
+ function shouldCreateDefaultFreeModeStateForMissingAuth(current, hasUsableCodexAuth2) {
4268
+ return current == null && !hasUsableCodexAuth2;
4269
4269
  }
4270
4270
  function getFreeModeEnvVars(state) {
4271
4271
  if (!state.enabled) return {};
@@ -5232,6 +5232,29 @@ function shellQuote(value) {
5232
5232
  return `'${value.replace(/'/g, `'\\''`)}'`;
5233
5233
  }
5234
5234
 
5235
+ // src/pathUtils.ts
5236
+ function stripWindowsDevicePathPrefix(value) {
5237
+ const trimmed = value.trim();
5238
+ if (!trimmed) return "";
5239
+ if (trimmed.startsWith("\\\\?\\UNC\\")) {
5240
+ return `\\\\${trimmed.slice("\\\\?\\UNC\\".length)}`;
5241
+ }
5242
+ if (trimmed.startsWith("\\\\?\\")) {
5243
+ return trimmed.slice("\\\\?\\".length);
5244
+ }
5245
+ return trimmed;
5246
+ }
5247
+ function normalizePathForUi(value) {
5248
+ return stripWindowsDevicePathPrefix(value);
5249
+ }
5250
+ function isWindowsLikePath(value) {
5251
+ return /^[a-z]:[\\/]/iu.test(value) || value.startsWith("\\\\");
5252
+ }
5253
+ function isAbsoluteLikePath(value) {
5254
+ const normalized = normalizePathForUi(value);
5255
+ return normalized.startsWith("/") || isWindowsLikePath(normalized);
5256
+ }
5257
+
5235
5258
  // src/server/codexAppServerBridge.ts
5236
5259
  var COMPOSIO_CONNECTORS_PAGE_LIMIT_MAX = 1e3;
5237
5260
  var PROVIDER_MODELS_FETCH_TIMEOUT_MS = 5e3;
@@ -5763,6 +5786,37 @@ function getErrorMessage5(payload, fallback) {
5763
5786
  }
5764
5787
  return fallback;
5765
5788
  }
5789
+ function isUnauthenticatedRateLimitError(error) {
5790
+ const message = getErrorMessage5(error, "").toLowerCase();
5791
+ return message.includes("authentication required") && message.includes("rate limits");
5792
+ }
5793
+ var warnedCodexAuthReadFailures = /* @__PURE__ */ new Set();
5794
+ function getErrorCode(error) {
5795
+ return typeof error === "object" && error !== null && "code" in error ? String(error.code ?? "") : null;
5796
+ }
5797
+ function getCodexAuthReadErrorMessage(error) {
5798
+ return error instanceof Error && error.message.trim().length > 0 ? error.message : String(error);
5799
+ }
5800
+ function warnCodexAuthReadFailure(authPath, error) {
5801
+ const message = getCodexAuthReadErrorMessage(error);
5802
+ const warningKey = `${authPath}:${message}`;
5803
+ if (warnedCodexAuthReadFailures.has(warningKey)) return;
5804
+ warnedCodexAuthReadFailures.add(warningKey);
5805
+ console.warn("[codex-auth] Unable to read Codex auth state", { path: authPath, error: message });
5806
+ }
5807
+ async function hasUsableCodexAuth() {
5808
+ const authPath = getCodexAuthPath();
5809
+ try {
5810
+ const raw = await readFile3(authPath, "utf8");
5811
+ const auth = JSON.parse(raw);
5812
+ return Boolean(auth.tokens?.access_token?.trim() || auth.tokens?.refresh_token?.trim());
5813
+ } catch (error) {
5814
+ if (getErrorCode(error) !== "ENOENT") {
5815
+ warnCodexAuthReadFailure(authPath, error);
5816
+ }
5817
+ return false;
5818
+ }
5819
+ }
5766
5820
  function setJson4(res, statusCode, payload) {
5767
5821
  res.statusCode = statusCode;
5768
5822
  res.setHeader("Content-Type", "application/json; charset=utf-8");
@@ -7674,23 +7728,70 @@ function readTomlString(value) {
7674
7728
  function serializeTomlString(value) {
7675
7729
  return JSON.stringify(value);
7676
7730
  }
7731
+ function parseTomlStringArray(value) {
7732
+ const trimmed = value.trim();
7733
+ if (!trimmed.startsWith("[") || !trimmed.endsWith("]")) return [];
7734
+ try {
7735
+ const parsed = JSON.parse(trimmed);
7736
+ return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string" && item.trim().length > 0) : [];
7737
+ } catch {
7738
+ return [];
7739
+ }
7740
+ }
7741
+ function serializeTomlStringArray(values) {
7742
+ return `[${values.map((value) => serializeTomlString(value)).join(", ")}]`;
7743
+ }
7677
7744
  function parseAutomationToml(raw) {
7678
7745
  const values = {};
7746
+ const extraTomlLines = [];
7747
+ const knownKeys = /* @__PURE__ */ new Set([
7748
+ "version",
7749
+ "id",
7750
+ "kind",
7751
+ "name",
7752
+ "prompt",
7753
+ "status",
7754
+ "rrule",
7755
+ "target_thread_id",
7756
+ "cwds",
7757
+ "created_at",
7758
+ "updated_at"
7759
+ ]);
7760
+ let isInsideExtraTable = false;
7679
7761
  for (const line of raw.split(/\r?\n/u)) {
7680
7762
  const trimmed = line.trim();
7681
- if (!trimmed || trimmed.startsWith("#") || !trimmed.includes("=")) continue;
7763
+ if (!trimmed || trimmed.startsWith("#")) continue;
7764
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
7765
+ isInsideExtraTable = true;
7766
+ extraTomlLines.push(trimmed);
7767
+ continue;
7768
+ }
7769
+ if (isInsideExtraTable) {
7770
+ extraTomlLines.push(trimmed);
7771
+ continue;
7772
+ }
7773
+ if (!trimmed.includes("=")) {
7774
+ extraTomlLines.push(trimmed);
7775
+ continue;
7776
+ }
7682
7777
  const separatorIndex = trimmed.indexOf("=");
7683
7778
  const key = trimmed.slice(0, separatorIndex).trim();
7684
7779
  const value = trimmed.slice(separatorIndex + 1).trim();
7685
- if (key) values[key] = value;
7780
+ if (!key) continue;
7781
+ if (knownKeys.has(key)) {
7782
+ values[key] = value;
7783
+ } else {
7784
+ extraTomlLines.push(trimmed);
7785
+ }
7686
7786
  }
7687
7787
  const id = readTomlString(values.id ?? "");
7688
- const kindValue = readTomlString(values.kind ?? "heartbeat");
7788
+ const kindValue = readTomlString(values.kind ?? (values.cwds ? "cron" : "heartbeat"));
7689
7789
  const name = readTomlString(values.name ?? "");
7690
7790
  const prompt = readTomlString(values.prompt ?? "");
7691
7791
  const rrule = readTomlString(values.rrule ?? "");
7692
7792
  const statusValue = readTomlString(values.status ?? "ACTIVE");
7693
7793
  const targetThreadId = readTomlString(values.target_thread_id ?? "") || null;
7794
+ const cwds = parseTomlStringArray(values.cwds ?? "");
7694
7795
  const createdAtMs = Number.parseInt(values.created_at ?? "", 10);
7695
7796
  const updatedAtMs = Number.parseInt(values.updated_at ?? "", 10);
7696
7797
  if (!id || !name || !prompt || !rrule) return null;
@@ -7704,6 +7805,8 @@ function parseAutomationToml(raw) {
7704
7805
  rrule,
7705
7806
  status: statusValue,
7706
7807
  targetThreadId,
7808
+ cwds,
7809
+ extraTomlLines,
7707
7810
  createdAtMs: Number.isFinite(createdAtMs) ? createdAtMs : null,
7708
7811
  updatedAtMs: Number.isFinite(updatedAtMs) ? updatedAtMs : null,
7709
7812
  nextRunAtMs: null
@@ -7717,11 +7820,19 @@ function serializeAutomationToml(record) {
7717
7820
  `name = ${serializeTomlString(record.name)}`,
7718
7821
  `prompt = ${serializeTomlString(record.prompt)}`,
7719
7822
  `status = ${serializeTomlString(record.status)}`,
7720
- `rrule = ${serializeTomlString(record.rrule)}`,
7721
- `target_thread_id = ${serializeTomlString(record.targetThreadId ?? "")}`,
7823
+ `rrule = ${serializeTomlString(record.rrule)}`
7824
+ ];
7825
+ if (record.targetThreadId) {
7826
+ lines.push(`target_thread_id = ${serializeTomlString(record.targetThreadId)}`);
7827
+ }
7828
+ if (record.cwds.length > 0) {
7829
+ lines.push(`cwds = ${serializeTomlStringArray(record.cwds)}`);
7830
+ }
7831
+ lines.push(
7722
7832
  `created_at = ${String(record.createdAtMs ?? Date.now())}`,
7723
7833
  `updated_at = ${String(record.updatedAtMs ?? Date.now())}`
7724
- ];
7834
+ );
7835
+ lines.push(...record.extraTomlLines);
7725
7836
  return `${lines.join("\n")}
7726
7837
  `;
7727
7838
  }
@@ -7805,6 +7916,8 @@ async function writeThreadHeartbeatAutomation(input) {
7805
7916
  rrule,
7806
7917
  status: input.status,
7807
7918
  targetThreadId: threadId,
7919
+ cwds: [],
7920
+ extraTomlLines: existing?.extraTomlLines ?? [],
7808
7921
  createdAtMs: existing?.createdAtMs ?? now,
7809
7922
  updatedAtMs: now,
7810
7923
  nextRunAtMs: null
@@ -7833,6 +7946,114 @@ async function deleteThreadHeartbeatAutomation(threadId, automationId = "") {
7833
7946
  await Promise.all(automations.map((automation) => rm4(join6(getCodexAutomationsDir(), automation.id), { recursive: true, force: true })));
7834
7947
  return true;
7835
7948
  }
7949
+ async function listProjectCronAutomations() {
7950
+ const automationRoot = getCodexAutomationsDir();
7951
+ const next = {};
7952
+ let entries;
7953
+ try {
7954
+ entries = await readdir2(automationRoot, { withFileTypes: true });
7955
+ } catch {
7956
+ return next;
7957
+ }
7958
+ for (const entry of entries) {
7959
+ if (!entry.isDirectory()) continue;
7960
+ const automation = await readAutomationRecordFromFile(join6(automationRoot, entry.name, "automation.toml"));
7961
+ if (!automation || automation.kind !== "cron" || automation.cwds.length === 0) continue;
7962
+ for (const cwd of automation.cwds) {
7963
+ next[cwd] = [...next[cwd] ?? [], automation];
7964
+ }
7965
+ }
7966
+ for (const automations of Object.values(next)) {
7967
+ automations.sort((first, second) => {
7968
+ const firstCreatedAt = first.createdAtMs ?? 0;
7969
+ const secondCreatedAt = second.createdAtMs ?? 0;
7970
+ if (firstCreatedAt !== secondCreatedAt) return firstCreatedAt - secondCreatedAt;
7971
+ return first.id.localeCompare(second.id);
7972
+ });
7973
+ }
7974
+ return next;
7975
+ }
7976
+ async function readProjectCronAutomations(projectName) {
7977
+ const all = await listProjectCronAutomations();
7978
+ return all[projectName] ?? [];
7979
+ }
7980
+ async function readProjectCronAutomation(projectName, automationId = "") {
7981
+ const automations = await readProjectCronAutomations(projectName);
7982
+ if (automationId) return automations.find((automation) => automation.id === automationId) ?? null;
7983
+ return automations[0] ?? null;
7984
+ }
7985
+ async function writeProjectCronAutomation(input) {
7986
+ const projectName = input.projectName.trim();
7987
+ const name = input.name.trim();
7988
+ const prompt = input.prompt.trim();
7989
+ const rrule = input.rrule.trim();
7990
+ if (!projectName || !name || !prompt || !rrule) {
7991
+ throw new Error("projectName, name, prompt, and rrule are required");
7992
+ }
7993
+ if (!isAbsoluteLikePath(projectName)) {
7994
+ throw new Error("Project automation cwd must be an absolute path");
7995
+ }
7996
+ const automationRoot = getCodexAutomationsDir();
7997
+ await mkdir4(automationRoot, { recursive: true });
7998
+ const existing = input.id ? await readProjectCronAutomation(projectName, input.id.trim()) : null;
7999
+ const entries = await readdir2(automationRoot, { withFileTypes: true }).catch(() => []);
8000
+ const existingIds = new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
8001
+ const id = existing?.id ?? resolveUniqueAutomationId(existingIds, projectName, name);
8002
+ const automationDir = join6(automationRoot, id);
8003
+ const now = Date.now();
8004
+ const record = {
8005
+ id,
8006
+ kind: "cron",
8007
+ name,
8008
+ prompt,
8009
+ rrule,
8010
+ status: input.status,
8011
+ targetThreadId: null,
8012
+ cwds: Array.from(/* @__PURE__ */ new Set([...existing?.cwds ?? [], projectName])),
8013
+ extraTomlLines: existing?.extraTomlLines ?? [],
8014
+ createdAtMs: existing?.createdAtMs ?? now,
8015
+ updatedAtMs: now,
8016
+ nextRunAtMs: null
8017
+ };
8018
+ await mkdir4(automationDir, { recursive: true });
8019
+ await writeFile4(join6(automationDir, "automation.toml"), serializeAutomationToml(record), "utf8");
8020
+ const memoryPath = join6(automationDir, "memory.md");
8021
+ try {
8022
+ await stat4(memoryPath);
8023
+ } catch {
8024
+ await writeFile4(memoryPath, "", "utf8");
8025
+ }
8026
+ return record;
8027
+ }
8028
+ async function deleteProjectCronAutomation(projectName, automationId = "") {
8029
+ const normalizedProjectName = projectName.trim();
8030
+ const normalizedAutomationId = automationId.trim();
8031
+ if (!normalizedProjectName || !isAbsoluteLikePath(normalizedProjectName)) return false;
8032
+ if (normalizedAutomationId) {
8033
+ const automation = await readProjectCronAutomation(normalizedProjectName, normalizedAutomationId);
8034
+ if (!automation) return false;
8035
+ const remainingCwds = automation.cwds.filter((cwd) => cwd !== normalizedProjectName);
8036
+ if (remainingCwds.length > 0) {
8037
+ const record = { ...automation, cwds: remainingCwds, updatedAtMs: Date.now() };
8038
+ await writeFile4(join6(getCodexAutomationsDir(), automation.id, "automation.toml"), serializeAutomationToml(record), "utf8");
8039
+ } else {
8040
+ await rm4(join6(getCodexAutomationsDir(), automation.id), { recursive: true, force: true });
8041
+ }
8042
+ return true;
8043
+ }
8044
+ const automations = await readProjectCronAutomations(normalizedProjectName);
8045
+ if (automations.length === 0) return false;
8046
+ await Promise.all(automations.map(async (automation) => {
8047
+ const remainingCwds = automation.cwds.filter((cwd) => cwd !== normalizedProjectName);
8048
+ if (remainingCwds.length > 0) {
8049
+ const record = { ...automation, cwds: remainingCwds, updatedAtMs: Date.now() };
8050
+ await writeFile4(join6(getCodexAutomationsDir(), automation.id, "automation.toml"), serializeAutomationToml(record), "utf8");
8051
+ return;
8052
+ }
8053
+ await rm4(join6(getCodexAutomationsDir(), automation.id), { recursive: true, force: true });
8054
+ }));
8055
+ return true;
8056
+ }
7836
8057
  var MAX_THREAD_TITLES = 500;
7837
8058
  var EMPTY_THREAD_TITLE_CACHE = { titles: {}, order: [] };
7838
8059
  var PINNED_THREAD_IDS_KEY = "pinned-thread-ids";
@@ -9842,7 +10063,20 @@ function createCodexBridgeMiddleware() {
9842
10063
  setJson4(res, 400, { error: "Invalid body: expected { method, params? }" });
9843
10064
  return;
9844
10065
  }
9845
- const rpcResult = await callRpcWithArchiveRecovery(appServer, body.method, body.params ?? null);
10066
+ if (body.method === "account/rateLimits/read" && !await hasUsableCodexAuth()) {
10067
+ setJson4(res, 200, { result: null });
10068
+ return;
10069
+ }
10070
+ let rpcResult;
10071
+ try {
10072
+ rpcResult = await callRpcWithArchiveRecovery(appServer, body.method, body.params ?? null);
10073
+ } catch (error) {
10074
+ if (body.method === "account/rateLimits/read" && isUnauthenticatedRateLimitError(error)) {
10075
+ setJson4(res, 200, { result: null });
10076
+ return;
10077
+ }
10078
+ throw error;
10079
+ }
9846
10080
  const trimmedResult = trimThreadTurnsInRpcResult(body.method, rpcResult);
9847
10081
  const sanitizedResult = await sanitizeThreadTurnsInlinePayloads(body.method, trimmedResult);
9848
10082
  const result = THREAD_METHODS_WITH_TURNS.has(body.method) ? await mergeSessionSkillInputsIntoThreadResult(sanitizedResult) : sanitizedResult;
@@ -10918,6 +11152,11 @@ function createCodexBridgeMiddleware() {
10918
11152
  setJson4(res, 200, { data: automationsByThreadId });
10919
11153
  return;
10920
11154
  }
11155
+ if (req.method === "GET" && url.pathname === "/codex-api/project-automations") {
11156
+ const automationsByProjectName = await listProjectCronAutomations();
11157
+ setJson4(res, 200, { data: automationsByProjectName });
11158
+ return;
11159
+ }
10921
11160
  if (req.method === "GET" && url.pathname === "/codex-api/thread-automation") {
10922
11161
  const threadId = url.searchParams.get("threadId")?.trim() ?? "";
10923
11162
  const automationId = url.searchParams.get("automationId")?.trim() ?? "";
@@ -10929,6 +11168,17 @@ function createCodexBridgeMiddleware() {
10929
11168
  setJson4(res, 200, { data: automation });
10930
11169
  return;
10931
11170
  }
11171
+ if (req.method === "GET" && url.pathname === "/codex-api/project-automation") {
11172
+ const projectName = url.searchParams.get("projectName")?.trim() ?? "";
11173
+ const automationId = url.searchParams.get("automationId")?.trim() ?? "";
11174
+ if (!projectName) {
11175
+ setJson4(res, 400, { error: "Missing projectName" });
11176
+ return;
11177
+ }
11178
+ const automation = automationId ? await readProjectCronAutomation(projectName, automationId) : await readProjectCronAutomations(projectName);
11179
+ setJson4(res, 200, { data: automation });
11180
+ return;
11181
+ }
10932
11182
  if (req.method === "POST" && url.pathname === "/codex-api/thread-search") {
10933
11183
  const payload = asRecord5(await readJsonBody2(req));
10934
11184
  const query = typeof payload?.query === "string" ? payload.query.trim() : "";
@@ -10987,6 +11237,26 @@ function createCodexBridgeMiddleware() {
10987
11237
  setJson4(res, 200, { data: automation });
10988
11238
  return;
10989
11239
  }
11240
+ if (req.method === "PUT" && url.pathname === "/codex-api/project-automation") {
11241
+ const payload = asRecord5(await readJsonBody2(req));
11242
+ const projectName = typeof payload?.projectName === "string" ? payload.projectName.trim() : "";
11243
+ const id = typeof payload?.id === "string" ? payload.id.trim() : "";
11244
+ const name = typeof payload?.name === "string" ? payload.name.trim() : "";
11245
+ const prompt = typeof payload?.prompt === "string" ? payload.prompt.trim() : "";
11246
+ const rrule = typeof payload?.rrule === "string" ? payload.rrule.trim() : "";
11247
+ const status = payload?.status === "PAUSED" ? "PAUSED" : "ACTIVE";
11248
+ if (!projectName || !name || !prompt || !rrule) {
11249
+ setJson4(res, 400, { error: "projectName, name, prompt, and rrule are required" });
11250
+ return;
11251
+ }
11252
+ if (!isAbsoluteLikePath(projectName)) {
11253
+ setJson4(res, 400, { error: "Project automation cwd must be an absolute path" });
11254
+ return;
11255
+ }
11256
+ const automation = await writeProjectCronAutomation({ projectName, id, name, prompt, rrule, status });
11257
+ setJson4(res, 200, { data: automation });
11258
+ return;
11259
+ }
10990
11260
  if (req.method === "POST" && url.pathname === "/codex-api/thread-automation/run") {
10991
11261
  const payload = asRecord5(await readJsonBody2(req));
10992
11262
  const threadId = typeof payload?.threadId === "string" ? payload.threadId.trim() : "";
@@ -11016,6 +11286,17 @@ function createCodexBridgeMiddleware() {
11016
11286
  setJson4(res, 200, { data: { removed } });
11017
11287
  return;
11018
11288
  }
11289
+ if (req.method === "DELETE" && url.pathname === "/codex-api/project-automation") {
11290
+ const projectName = url.searchParams.get("projectName")?.trim() ?? "";
11291
+ const automationId = url.searchParams.get("automationId")?.trim() ?? "";
11292
+ if (!projectName) {
11293
+ setJson4(res, 400, { error: "Missing projectName" });
11294
+ return;
11295
+ }
11296
+ const removed = await deleteProjectCronAutomation(projectName, automationId);
11297
+ setJson4(res, 200, { data: { removed } });
11298
+ return;
11299
+ }
11019
11300
  if (req.method === "POST" && url.pathname === "/codex-api/telegram/configure-bot") {
11020
11301
  const payload = asRecord5(await readJsonBody2(req));
11021
11302
  const botToken = typeof payload?.botToken === "string" ? payload.botToken.trim() : "";