codexui-android 0.1.107 → 0.1.109

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-aDL62PRZ.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-DvadSfWE.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.13.1";/**
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";/**
1607
1607
  * @license
1608
1608
  * Copyright 2020 Google LLC
1609
1609
  *
@@ -1,4 +1,4 @@
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";/**
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";/**
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.12";/**
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";/**
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.13.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.11.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-7uudGTMH.js"></script>
16
- <link rel="stylesheet" crossorigin href="/assets/index-D3-QOh5C.css">
15
+ <script type="module" crossorigin src="/assets/index-ZXDbBStq.js"></script>
16
+ <link rel="stylesheet" crossorigin href="/assets/index-AFrh-w0S.css">
17
17
  </head>
18
18
  <body class="bg-slate-950">
19
19
  <div id="app"></div>
package/dist-cli/index.js CHANGED
@@ -2047,6 +2047,9 @@ function deriveSkillPathInfo(skillPath, knownPaths = /* @__PURE__ */ new Set())
2047
2047
  function getSkillsInstallDir() {
2048
2048
  return join4(getCodexHomeDir2(), "skills");
2049
2049
  }
2050
+ function getSharedSkillsInstallDir() {
2051
+ return join4(getSkillsInstallDir(), "shared_skills");
2052
+ }
2050
2053
  var DEFAULT_COMMAND_TIMEOUT_MS = 12e4;
2051
2054
  var SKILL_SEARCH_METADATA_LIMIT = 20;
2052
2055
  var SKILL_SEARCH_METADATA_CONCURRENCY = 4;
@@ -2421,9 +2424,8 @@ var startupSyncStatus = {
2421
2424
  lastSuccessAtIso: "",
2422
2425
  lastError: ""
2423
2426
  };
2424
- async function scanInstalledSkillsFromDisk() {
2427
+ async function scanInstalledSkillsFromDir(skillsDir) {
2425
2428
  const map = /* @__PURE__ */ new Map();
2426
- const skillsDir = getSkillsInstallDir();
2427
2429
  try {
2428
2430
  const entries = await readdir(skillsDir, { withFileTypes: true });
2429
2431
  for (const entry of entries) {
@@ -2439,6 +2441,9 @@ async function scanInstalledSkillsFromDisk() {
2439
2441
  }
2440
2442
  return map;
2441
2443
  }
2444
+ async function scanInstalledSkillsFromDisk() {
2445
+ return await scanInstalledSkillsFromDir(getSkillsInstallDir());
2446
+ }
2442
2447
  async function collectInstalledSkillsMap(appServer) {
2443
2448
  const installedMap = await scanInstalledSkillsFromDisk();
2444
2449
  try {
@@ -2700,13 +2705,14 @@ async function writeRemoteSkillsManifest(token, repoOwner, repoName, skills) {
2700
2705
  function toGitHubTokenRemote(repoOwner, repoName, token) {
2701
2706
  return `https://x-access-token:${encodeURIComponent(token)}@github.com/${repoOwner}/${repoName}.git`;
2702
2707
  }
2703
- async function ensureSkillsWorkingTreeRepo(repoUrl, branch) {
2704
- const localDir = getSkillsInstallDir();
2708
+ async function ensureSkillsWorkingTreeRepo(repoUrl, branch, options = {}) {
2709
+ const localDir = options.localDir ?? getSkillsInstallDir();
2705
2710
  await mkdir3(localDir, { recursive: true });
2706
2711
  const gitDir = join4(localDir, ".git");
2707
2712
  let hasGitDir = false;
2708
2713
  try {
2709
- hasGitDir = (await stat3(gitDir)).isDirectory();
2714
+ const gitDirStat = await lstat(gitDir);
2715
+ hasGitDir = gitDirStat.isDirectory() || gitDirStat.isFile();
2710
2716
  } catch {
2711
2717
  hasGitDir = false;
2712
2718
  }
@@ -2726,6 +2732,14 @@ async function ensureSkillsWorkingTreeRepo(repoUrl, branch) {
2726
2732
  await runCommand2("git", ["remote", "set-url", "origin", repoUrl], { cwd: localDir });
2727
2733
  }
2728
2734
  await runGitFetchWithRefLockRetry(localDir);
2735
+ if (options.overwriteLocalFiles) {
2736
+ await runCommand2("git", ["reset", "--hard"], { cwd: localDir });
2737
+ await runCommand2("git", ["clean", "-fd"], { cwd: localDir });
2738
+ await runCommand2("git", ["checkout", "-B", branch, `origin/${branch}`], { cwd: localDir });
2739
+ await runCommand2("git", ["reset", "--hard", `origin/${branch}`], { cwd: localDir });
2740
+ await runCommand2("git", ["clean", "-fd"], { cwd: localDir });
2741
+ return localDir;
2742
+ }
2729
2743
  try {
2730
2744
  await runCommand2("git", ["merge", "--allow-unrelated-histories", "--no-edit", `origin/${branch}`], { cwd: localDir });
2731
2745
  } catch {
@@ -2734,6 +2748,17 @@ async function ensureSkillsWorkingTreeRepo(repoUrl, branch) {
2734
2748
  }
2735
2749
  await runCommand2("git", ["remote", "set-url", "origin", repoUrl], { cwd: localDir });
2736
2750
  await runGitFetchWithRefLockRetry(localDir);
2751
+ if (options.overwriteLocalFiles) {
2752
+ try {
2753
+ await runCommand2("git", ["reset", "--hard"], { cwd: localDir });
2754
+ } catch {
2755
+ }
2756
+ await runCommand2("git", ["clean", "-fd"], { cwd: localDir });
2757
+ await runCommand2("git", ["checkout", "-B", branch, `origin/${branch}`], { cwd: localDir });
2758
+ await runCommand2("git", ["reset", "--hard", `origin/${branch}`], { cwd: localDir });
2759
+ await runCommand2("git", ["clean", "-fd"], { cwd: localDir });
2760
+ return localDir;
2761
+ }
2737
2762
  const hasLocalChangesBeforeSync = await hasLocalUncommittedChanges(localDir);
2738
2763
  const localMtimesBeforeSync = hasLocalChangesBeforeSync ? await snapshotFileMtimes(localDir) : /* @__PURE__ */ new Map();
2739
2764
  await resolveMergeConflictsByNewerCommit(localDir, branch, localMtimesBeforeSync);
@@ -2994,13 +3019,19 @@ async function syncInstalledSkillsFolderToRepo(token, repoOwner, repoName, _inst
2994
3019
  }
2995
3020
  async function pullInstalledSkillsFolderFromRepo(token, repoOwner, repoName) {
2996
3021
  const remoteUrl = toGitHubTokenRemote(repoOwner, repoName, token);
2997
- const branch = PRIVATE_SYNC_BRANCH;
2998
- await ensureSkillsWorkingTreeRepo(remoteUrl, branch);
3022
+ const isUpstream = isUpstreamSkillsRepo(repoOwner, repoName);
3023
+ const branch = isUpstream ? PUBLIC_UPSTREAM_BRANCH_ANDROID : PRIVATE_SYNC_BRANCH;
3024
+ return await ensureSkillsWorkingTreeRepo(remoteUrl, branch, {
3025
+ ...isUpstream ? { localDir: getSharedSkillsInstallDir() } : {},
3026
+ overwriteLocalFiles: isUpstream
3027
+ });
2999
3028
  }
3000
3029
  async function bootstrapSkillsFromUpstreamIntoLocal() {
3001
3030
  const repoUrl = `https://github.com/${SYNC_UPSTREAM_SKILLS_OWNER}/${SYNC_UPSTREAM_SKILLS_REPO}.git`;
3002
- const branch = getPreferredPublicUpstreamBranch();
3003
- await ensureSkillsWorkingTreeRepo(repoUrl, branch);
3031
+ return await ensureSkillsWorkingTreeRepo(repoUrl, PUBLIC_UPSTREAM_BRANCH_ANDROID, {
3032
+ localDir: getSharedSkillsInstallDir(),
3033
+ overwriteLocalFiles: true
3034
+ });
3004
3035
  }
3005
3036
  async function collectLocalSyncedSkills(appServer) {
3006
3037
  const state = await readSkillsSyncState();
@@ -3305,12 +3336,31 @@ async function handleSkillsRoutes(req, res, url, context) {
3305
3336
  try {
3306
3337
  const state = await readSkillsSyncState();
3307
3338
  if (!state.githubToken || !state.repoOwner || !state.repoName) {
3308
- await bootstrapSkillsFromUpstreamIntoLocal();
3339
+ const repoDir = await bootstrapSkillsFromUpstreamIntoLocal();
3340
+ const localSkills2 = await scanInstalledSkillsFromDir(repoDir);
3309
3341
  try {
3310
3342
  await appServer.rpc("skills/list", { forceReload: true });
3311
3343
  } catch {
3312
3344
  }
3313
- setJson3(res, 200, { ok: true, data: { synced: 0, source: "upstream" } });
3345
+ setJson3(res, 200, { ok: true, data: { synced: localSkills2.size, source: "upstream" } });
3346
+ return true;
3347
+ }
3348
+ if (isUpstreamSkillsRepo(state.repoOwner, state.repoName)) {
3349
+ const repoDir = await pullInstalledSkillsFolderFromRepo(state.githubToken, state.repoOwner, state.repoName);
3350
+ const localSkills2 = await scanInstalledSkillsFromDir(repoDir);
3351
+ const pulledHead2 = await runCommandWithOutput("git", ["rev-parse", "HEAD"], { cwd: repoDir }).catch(() => "");
3352
+ await writeSkillsSyncState({
3353
+ ...state,
3354
+ lastPullCommitSha: pulledHead2.trim(),
3355
+ lastSyncAttemptCount: 1,
3356
+ lastSyncError: "",
3357
+ lastSyncAtIso: (/* @__PURE__ */ new Date()).toISOString()
3358
+ });
3359
+ try {
3360
+ await appServer.rpc("skills/list", { forceReload: true });
3361
+ } catch {
3362
+ }
3363
+ setJson3(res, 200, { ok: true, data: { synced: localSkills2.size, source: "upstream" } });
3314
3364
  return true;
3315
3365
  }
3316
3366
  const remote = await readRemoteSkillsManifest(state.githubToken, state.repoOwner, state.repoName);
@@ -5186,6 +5236,7 @@ function shellQuote(value) {
5186
5236
  var COMPOSIO_CONNECTORS_PAGE_LIMIT_MAX = 1e3;
5187
5237
  var PROVIDER_MODELS_FETCH_TIMEOUT_MS = 5e3;
5188
5238
  var THREAD_RESPONSE_TURN_LIMIT = 10;
5239
+ var THREAD_TURN_PAGE_READ_CACHE_TTL_MS = 3e4;
5189
5240
  var THREAD_METHODS_WITH_TURNS = /* @__PURE__ */ new Set(["thread/read", "thread/resume", "thread/fork", "thread/rollback"]);
5190
5241
  var THREAD_SEARCH_FULL_TEXT_THREAD_LIMIT = 100;
5191
5242
  var PROJECTLESS_THREAD_DIRECTORY_MAX_ATTEMPTS = 100;
@@ -5688,11 +5739,13 @@ function trimThreadTurnsInRpcResult(method, result) {
5688
5739
  const thread = asRecord5(record?.thread);
5689
5740
  const turns = Array.isArray(thread?.turns) ? thread.turns : null;
5690
5741
  if (!record || !thread || !turns || turns.length <= THREAD_RESPONSE_TURN_LIMIT) return result;
5742
+ const startTurnIndex = Math.max(0, turns.length - THREAD_RESPONSE_TURN_LIMIT);
5691
5743
  return {
5692
5744
  ...record,
5745
+ threadTurnStartIndex: startTurnIndex,
5693
5746
  thread: {
5694
5747
  ...thread,
5695
- turns: turns.slice(-THREAD_RESPONSE_TURN_LIMIT)
5748
+ turns: turns.slice(startTurnIndex)
5696
5749
  }
5697
5750
  };
5698
5751
  }
@@ -5760,6 +5813,56 @@ async function createProjectlessThreadDirectory(prompt) {
5760
5813
  }
5761
5814
  throw new Error("Unable to create a unique new chat folder");
5762
5815
  }
5816
+ function normalizeGithubCloneUrl(rawUrl) {
5817
+ const trimmedUrl = rawUrl.trim();
5818
+ if (!trimmedUrl) throw new Error("Missing GitHub repository URL");
5819
+ const sshMatch = trimmedUrl.match(/^git@github\.com:([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?$/u);
5820
+ if (sshMatch) {
5821
+ const repoName2 = sshMatch[2];
5822
+ return { url: `git@github.com:${sshMatch[1]}/${repoName2}.git`, repoName: repoName2 };
5823
+ }
5824
+ let parsed;
5825
+ try {
5826
+ parsed = new URL(trimmedUrl);
5827
+ } catch {
5828
+ throw new Error("Enter a valid GitHub repository URL");
5829
+ }
5830
+ if (parsed.hostname.toLowerCase() !== "github.com") {
5831
+ throw new Error("Only github.com repository URLs are supported");
5832
+ }
5833
+ const segments = parsed.pathname.split("/").filter(Boolean);
5834
+ if (segments.length < 2) {
5835
+ throw new Error("Enter a GitHub repository URL with owner and repository name");
5836
+ }
5837
+ const owner = segments[0];
5838
+ const repoName = segments[1].replace(/\.git$/iu, "");
5839
+ if (!/^[A-Za-z0-9_.-]+$/u.test(owner) || !/^[A-Za-z0-9_.-]+$/u.test(repoName)) {
5840
+ throw new Error("GitHub repository owner or name contains unsupported characters");
5841
+ }
5842
+ return { url: `https://github.com/${owner}/${repoName}.git`, repoName };
5843
+ }
5844
+ async function cloneGithubRepositoryIntoBase(rawUrl, rawBasePath) {
5845
+ const basePath = rawBasePath.trim();
5846
+ if (!basePath) throw new Error("Missing clone destination folder");
5847
+ const normalizedBasePath = isAbsolute2(basePath) ? basePath : resolve2(basePath);
5848
+ await ensureRealDirectory(normalizedBasePath, "Clone destination folder");
5849
+ const { url, repoName } = normalizeGithubCloneUrl(rawUrl);
5850
+ const targetPath = join6(normalizedBasePath, repoName);
5851
+ try {
5852
+ await stat4(targetPath);
5853
+ throw new Error(`Destination already exists: ${targetPath}`);
5854
+ } catch (error) {
5855
+ if (error?.code !== "ENOENT") throw error;
5856
+ }
5857
+ try {
5858
+ await runCommand3("git", ["clone", url, targetPath], { cwd: normalizedBasePath, timeoutMs: 5 * 6e4 });
5859
+ } catch (error) {
5860
+ await rm4(targetPath, { recursive: true, force: true }).catch(() => void 0);
5861
+ throw error;
5862
+ }
5863
+ await persistWorkspaceRoot(targetPath, "");
5864
+ return targetPath;
5865
+ }
5763
5866
  function normalizeHeaderValue(value) {
5764
5867
  if (typeof value === "string") {
5765
5868
  const trimmed = value.trim();
@@ -7169,14 +7272,33 @@ async function runCommand3(command, args, options = {}) {
7169
7272
  });
7170
7273
  let stdout = "";
7171
7274
  let stderr = "";
7275
+ let timedOut = false;
7276
+ let closed = false;
7277
+ const timeout = typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? setTimeout(() => {
7278
+ timedOut = true;
7279
+ proc.kill("SIGTERM");
7280
+ setTimeout(() => {
7281
+ if (!closed) proc.kill("SIGKILL");
7282
+ }, 5e3).unref();
7283
+ }, options.timeoutMs) : null;
7284
+ timeout?.unref();
7172
7285
  proc.stdout.on("data", (chunk) => {
7173
7286
  stdout += chunk.toString();
7174
7287
  });
7175
7288
  proc.stderr.on("data", (chunk) => {
7176
7289
  stderr += chunk.toString();
7177
7290
  });
7178
- proc.on("error", reject);
7291
+ proc.on("error", (error) => {
7292
+ if (timeout) clearTimeout(timeout);
7293
+ reject(error);
7294
+ });
7179
7295
  proc.on("close", (code) => {
7296
+ closed = true;
7297
+ if (timeout) clearTimeout(timeout);
7298
+ if (timedOut) {
7299
+ reject(new Error(`Command timed out after ${options.timeoutMs}ms (${command} ${args.join(" ")})`));
7300
+ return;
7301
+ }
7180
7302
  if (code === 0) {
7181
7303
  resolve4();
7182
7304
  return;
@@ -8453,6 +8575,8 @@ var AppServerProcess = class {
8453
8575
  this.appServerArgs = buildAppServerArgs();
8454
8576
  this.streamEventsByThreadId = /* @__PURE__ */ new Map();
8455
8577
  this.lastThreadReadSnapshotByThreadId = /* @__PURE__ */ new Map();
8578
+ this.threadTurnPageReadCacheByThreadId = /* @__PURE__ */ new Map();
8579
+ this.threadTurnPageReadPromiseByThreadId = /* @__PURE__ */ new Map();
8456
8580
  this.capturedItemsByThreadId = /* @__PURE__ */ new Map();
8457
8581
  this.liveStateCache = /* @__PURE__ */ new Map();
8458
8582
  this.chatgptAuthRefreshPromise = null;
@@ -8565,7 +8689,10 @@ var AppServerProcess = class {
8565
8689
  this.recordStreamEvent(notification);
8566
8690
  this.captureItemFromNotification(notification);
8567
8691
  const nThreadId = this.extractThreadIdFromParams(notification.params);
8568
- if (nThreadId) this.invalidateLiveStateCache(nThreadId);
8692
+ if (nThreadId) {
8693
+ this.invalidateLiveStateCache(nThreadId);
8694
+ this.threadTurnPageReadCacheByThreadId.delete(nThreadId);
8695
+ }
8569
8696
  for (const listener of this.notificationListeners) {
8570
8697
  listener(notification);
8571
8698
  }
@@ -8609,10 +8736,33 @@ var AppServerProcess = class {
8609
8736
  }
8610
8737
  storeThreadReadSnapshot(threadId, snapshot) {
8611
8738
  this.lastThreadReadSnapshotByThreadId.set(threadId, snapshot);
8739
+ this.threadTurnPageReadCacheByThreadId.delete(threadId);
8612
8740
  }
8613
8741
  getLastThreadReadSnapshot(threadId) {
8614
8742
  return this.lastThreadReadSnapshotByThreadId.get(threadId) ?? null;
8615
8743
  }
8744
+ async readThreadForTurnPage(threadId) {
8745
+ const now = Date.now();
8746
+ const cached = this.threadTurnPageReadCacheByThreadId.get(threadId);
8747
+ if (cached && cached.expiresAt > now) return cached.result;
8748
+ if (cached) this.threadTurnPageReadCacheByThreadId.delete(threadId);
8749
+ const pending = this.threadTurnPageReadPromiseByThreadId.get(threadId);
8750
+ if (pending) return pending;
8751
+ const promise = this.rpc("thread/read", {
8752
+ threadId,
8753
+ includeTurns: true
8754
+ }).then((result) => {
8755
+ this.threadTurnPageReadCacheByThreadId.set(threadId, {
8756
+ result,
8757
+ expiresAt: Date.now() + THREAD_TURN_PAGE_READ_CACHE_TTL_MS
8758
+ });
8759
+ return result;
8760
+ }).finally(() => {
8761
+ this.threadTurnPageReadPromiseByThreadId.delete(threadId);
8762
+ });
8763
+ this.threadTurnPageReadPromiseByThreadId.set(threadId, promise);
8764
+ return promise;
8765
+ }
8616
8766
  cacheLiveState(threadId, data, turnCount, sessionSize) {
8617
8767
  this.liveStateCache.set(threadId, { data, turnCount, sessionSize });
8618
8768
  }
@@ -9707,6 +9857,61 @@ function createCodexBridgeMiddleware() {
9707
9857
  setJson4(res, 200, { result });
9708
9858
  return;
9709
9859
  }
9860
+ if (req.method === "GET" && url.pathname === "/codex-api/thread-turn-page") {
9861
+ try {
9862
+ const threadId = url.searchParams.get("threadId")?.trim() ?? "";
9863
+ const beforeTurnId = url.searchParams.get("beforeTurnId")?.trim() ?? "";
9864
+ const limitRaw = url.searchParams.get("limit")?.trim() ?? String(THREAD_RESPONSE_TURN_LIMIT);
9865
+ const limit = Math.max(1, Math.min(50, Number.parseInt(limitRaw, 10) || THREAD_RESPONSE_TURN_LIMIT));
9866
+ if (!threadId) {
9867
+ setJson4(res, 400, { error: "Missing threadId" });
9868
+ return;
9869
+ }
9870
+ const threadReadResult = await appServer.readThreadForTurnPage(threadId);
9871
+ const record = asRecord5(threadReadResult);
9872
+ const thread = asRecord5(record?.thread);
9873
+ if (!record || !thread) {
9874
+ setJson4(res, 502, { error: "thread/read returned an invalid thread response" });
9875
+ return;
9876
+ }
9877
+ const turns = Array.isArray(thread.turns) ? thread.turns : [];
9878
+ const beforeIndex = beforeTurnId ? turns.findIndex((turn) => asRecord5(turn)?.id === beforeTurnId) : turns.length;
9879
+ if (beforeTurnId && beforeIndex < 0) {
9880
+ setJson4(res, 200, {
9881
+ result: {
9882
+ ...record,
9883
+ thread: {
9884
+ ...thread,
9885
+ turns: []
9886
+ }
9887
+ },
9888
+ startTurnIndex: 0,
9889
+ hasMoreOlder: false
9890
+ });
9891
+ return;
9892
+ }
9893
+ const endIndex = beforeIndex;
9894
+ const startIndex = Math.max(0, endIndex - limit);
9895
+ const pageTurns = turns.slice(startIndex, endIndex);
9896
+ const pagedResult = {
9897
+ ...record,
9898
+ thread: {
9899
+ ...thread,
9900
+ turns: pageTurns
9901
+ }
9902
+ };
9903
+ const sanitized = await sanitizeThreadTurnsInlinePayloads("thread/read", pagedResult);
9904
+ const result = await mergeSessionSkillInputsIntoThreadResult(sanitized);
9905
+ setJson4(res, 200, {
9906
+ result,
9907
+ startTurnIndex: startIndex,
9908
+ hasMoreOlder: startIndex > 0
9909
+ });
9910
+ } catch (error) {
9911
+ setJson4(res, 500, { error: getErrorMessage5(error, "Failed to load earlier thread messages") });
9912
+ }
9913
+ return;
9914
+ }
9710
9915
  if (req.method === "GET" && url.pathname === "/codex-api/thread-file-change-fallback") {
9711
9916
  const threadId = url.searchParams.get("threadId")?.trim() ?? "";
9712
9917
  if (!threadId) {
@@ -10573,6 +10778,18 @@ function createCodexBridgeMiddleware() {
10573
10778
  setJson4(res, 200, { data: { path: normalizedPath } });
10574
10779
  return;
10575
10780
  }
10781
+ if (req.method === "POST" && url.pathname === "/codex-api/github-clone") {
10782
+ const payload = asRecord5(await readJsonBody2(req));
10783
+ const repoUrl = typeof payload?.url === "string" ? payload.url.trim() : "";
10784
+ const basePath = typeof payload?.basePath === "string" ? payload.basePath.trim() : "";
10785
+ try {
10786
+ const clonedPath = await cloneGithubRepositoryIntoBase(repoUrl, basePath);
10787
+ setJson4(res, 200, { data: { path: clonedPath } });
10788
+ } catch (error) {
10789
+ setJson4(res, 400, { error: error instanceof Error ? error.message : "Failed to clone GitHub repository" });
10790
+ }
10791
+ return;
10792
+ }
10576
10793
  if (req.method === "POST" && url.pathname === "/codex-api/projectless-thread-cwd") {
10577
10794
  const payload = asRecord5(await readJsonBody2(req));
10578
10795
  const prompt = typeof payload?.prompt === "string" ? payload.prompt : null;
@@ -12214,7 +12431,6 @@ async function startServer(options) {
12214
12431
  const server = createServer2(app);
12215
12432
  attachWebSocket(server);
12216
12433
  const port = await listenWithFallback(server, requestedPort);
12217
- process.env.CODEXUI_SERVER_PORT = String(port);
12218
12434
  let tunnelChild = null;
12219
12435
  let tunnelUrl = null;
12220
12436
  if (options.tunnel) {