codexapp 0.1.57 → 0.1.58

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/dist/index.html CHANGED
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Codex Web Local</title>
7
- <script type="module" crossorigin src="/assets/index-CeCihVgJ.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-BwkNEgMe.css">
7
+ <script type="module" crossorigin src="/assets/index-6_XI7mdm.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-DDedrRjM.css">
9
9
  </head>
10
10
  <body class="bg-slate-950">
11
11
  <div id="app"></div>
package/dist-cli/index.js CHANGED
@@ -430,6 +430,8 @@ var SKILLS_SYNC_MANIFEST_PATH = "installed-skills.json";
430
430
  var SYNC_UPSTREAM_SKILLS_OWNER = "OpenClawAndroid";
431
431
  var SYNC_UPSTREAM_SKILLS_REPO = "skills";
432
432
  var PRIVATE_SYNC_BRANCH = "main";
433
+ var PUBLIC_UPSTREAM_BRANCH_ANDROID = "android";
434
+ var PUBLIC_UPSTREAM_BRANCH_DEFAULT = "main";
433
435
  var HUB_SKILLS_OWNER = "openclaw";
434
436
  var HUB_SKILLS_REPO = "skills";
435
437
  var startupSkillsSyncInitialized = false;
@@ -559,7 +561,7 @@ function isAndroidLikeRuntime() {
559
561
  return proot.length > 0;
560
562
  }
561
563
  function getPreferredPublicUpstreamBranch() {
562
- return isAndroidLikeRuntime() ? "android" : "main";
564
+ return isAndroidLikeRuntime() ? PUBLIC_UPSTREAM_BRANCH_ANDROID : PUBLIC_UPSTREAM_BRANCH_DEFAULT;
563
565
  }
564
566
  function isUpstreamSkillsRepo(repoOwner, repoName) {
565
567
  return repoOwner.toLowerCase() === SYNC_UPSTREAM_SKILLS_OWNER.toLowerCase() && repoName.toLowerCase() === SYNC_UPSTREAM_SKILLS_REPO.toLowerCase();
@@ -824,25 +826,50 @@ async function syncInstalledSkillsFolderToRepo(token, repoOwner, repoName, _inst
824
826
  async function pushWithNonFastForwardRetry(repoDir2, branch2) {
825
827
  const maxAttempts = 3;
826
828
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
829
+ await runCommand("git", ["fetch", "origin"], { cwd: repoDir2 });
830
+ let hasLatestRemote = false;
831
+ try {
832
+ await runCommand("git", ["merge-base", "--is-ancestor", `origin/${branch2}`, "HEAD"], { cwd: repoDir2 });
833
+ hasLatestRemote = true;
834
+ } catch {
835
+ hasLatestRemote = false;
836
+ }
837
+ if (!hasLatestRemote) {
838
+ try {
839
+ await runCommand("git", ["pull", "--no-rebase", "--no-ff", "origin", branch2], { cwd: repoDir2 });
840
+ } catch {
841
+ await resolveMergeConflictsByNewerCommit(repoDir2, branch2);
842
+ }
843
+ await runCommand("git", ["add", "."], { cwd: repoDir2 });
844
+ const statusAfterReconcile = (await runCommandWithOutput("git", ["status", "--porcelain"], { cwd: repoDir2 })).trim();
845
+ if (statusAfterReconcile) {
846
+ await runCommand("git", ["commit", "-m", "Reconcile skills sync before push retry"], { cwd: repoDir2 });
847
+ }
848
+ }
827
849
  try {
828
850
  await runCommand("git", ["push", "origin", `HEAD:${branch2}`], { cwd: repoDir2 });
851
+ const state = await readSkillsSyncState();
852
+ const pushedHead = await runCommandWithOutput("git", ["rev-parse", "HEAD"], { cwd: repoDir2 });
853
+ await writeSkillsSyncState({
854
+ ...state,
855
+ lastPushCommitSha: pushedHead.trim(),
856
+ lastSyncAttemptCount: attempt,
857
+ lastSyncError: "",
858
+ lastSyncAtIso: (/* @__PURE__ */ new Date()).toISOString()
859
+ });
829
860
  return;
830
861
  } catch (error) {
831
862
  if (!isNonFastForwardPushError(error) || attempt >= maxAttempts) {
863
+ const state = await readSkillsSyncState();
864
+ await writeSkillsSyncState({
865
+ ...state,
866
+ lastSyncAttemptCount: attempt,
867
+ lastSyncError: getErrorMessage(error, "push failed"),
868
+ lastSyncAtIso: (/* @__PURE__ */ new Date()).toISOString()
869
+ });
832
870
  throw error;
833
871
  }
834
872
  }
835
- await runCommand("git", ["fetch", "origin"], { cwd: repoDir2 });
836
- try {
837
- await runCommand("git", ["pull", "--no-rebase", "--no-ff", "origin", branch2], { cwd: repoDir2 });
838
- } catch {
839
- await resolveMergeConflictsByNewerCommit(repoDir2, branch2);
840
- }
841
- await runCommand("git", ["add", "."], { cwd: repoDir2 });
842
- const statusAfterReconcile = (await runCommandWithOutput("git", ["status", "--porcelain"], { cwd: repoDir2 })).trim();
843
- if (statusAfterReconcile) {
844
- await runCommand("git", ["commit", "-m", "Reconcile skills sync before push retry"], { cwd: repoDir2 });
845
- }
846
873
  }
847
874
  throw new Error("Failed to push after non-fast-forward retries");
848
875
  }
@@ -963,9 +990,8 @@ async function ensureCodexAgentsSymlinkToSkillsAgents() {
963
990
  }
964
991
  await symlink(relativeTarget, codexAgentsPath);
965
992
  }
966
- async function initializeSkillsSyncOnStartup(appServer) {
967
- if (startupSkillsSyncInitialized) return;
968
- startupSkillsSyncInitialized = true;
993
+ async function runSkillsSyncStartup(appServer) {
994
+ if (startupSyncStatus.inProgress) return;
969
995
  startupSyncStatus.inProgress = true;
970
996
  startupSyncStatus.lastRunAtIso = (/* @__PURE__ */ new Date()).toISOString();
971
997
  startupSyncStatus.lastError = "";
@@ -1016,6 +1042,11 @@ async function initializeSkillsSyncOnStartup(appServer) {
1016
1042
  startupSyncStatus.inProgress = false;
1017
1043
  }
1018
1044
  }
1045
+ async function initializeSkillsSyncOnStartup(appServer) {
1046
+ if (startupSkillsSyncInitialized) return;
1047
+ startupSkillsSyncInitialized = true;
1048
+ await runSkillsSyncStartup(appServer);
1049
+ }
1019
1050
  async function finalizeGithubLoginAndSync(token, username, appServer) {
1020
1051
  const repoName = DEFAULT_SKILLS_SYNC_REPO_NAME;
1021
1052
  await ensurePrivateForkFromUpstream(token, username, repoName);
@@ -1106,6 +1137,13 @@ async function handleSkillsRoutes(req, res, url, context) {
1106
1137
  repoOwner: state.repoOwner ?? "",
1107
1138
  repoName: state.repoName ?? "",
1108
1139
  configured: Boolean(state.githubToken && state.repoOwner && state.repoName),
1140
+ telemetry: {
1141
+ lastPullCommitSha: state.lastPullCommitSha ?? "",
1142
+ lastPushCommitSha: state.lastPushCommitSha ?? "",
1143
+ lastSyncAttemptCount: state.lastSyncAttemptCount ?? 0,
1144
+ lastSyncError: state.lastSyncError ?? "",
1145
+ lastSyncAtIso: state.lastSyncAtIso ?? ""
1146
+ },
1109
1147
  startup: {
1110
1148
  inProgress: startupSyncStatus.inProgress,
1111
1149
  mode: startupSyncStatus.mode,
@@ -1203,6 +1241,15 @@ async function handleSkillsRoutes(req, res, url, context) {
1203
1241
  }
1204
1242
  return true;
1205
1243
  }
1244
+ if (req.method === "POST" && url.pathname === "/codex-api/skills-sync/startup-sync") {
1245
+ try {
1246
+ await runSkillsSyncStartup(appServer);
1247
+ setJson(res, 200, { ok: true });
1248
+ } catch (error) {
1249
+ setJson(res, 502, { error: getErrorMessage(error, "Failed to run startup sync") });
1250
+ }
1251
+ return true;
1252
+ }
1206
1253
  if (req.method === "POST" && url.pathname === "/codex-api/skills-sync/pull") {
1207
1254
  try {
1208
1255
  const state = await readSkillsSyncState();
@@ -1234,15 +1281,20 @@ async function handleSkillsRoutes(req, res, url, context) {
1234
1281
  const localDir = await detectUserSkillsDir(appServer);
1235
1282
  await pullInstalledSkillsFolderFromRepo(state.githubToken, state.repoOwner, state.repoName);
1236
1283
  const localSkills = await scanInstalledSkillsFromDisk();
1284
+ const missingAfterPull = [];
1237
1285
  for (const skill of remote) {
1238
1286
  const owner = skill.owner || uniqueOwnerByName.get(skill.name) || "";
1239
1287
  if (!owner) continue;
1240
1288
  if (!localSkills.has(skill.name)) {
1289
+ missingAfterPull.push(`${owner}/${skill.name}`);
1241
1290
  continue;
1242
1291
  }
1243
1292
  const skillPath = join2(localDir, skill.name);
1244
1293
  await appServer.rpc("skills/config/write", { path: skillPath, enabled: skill.enabled });
1245
1294
  }
1295
+ if (missingAfterPull.length > 0) {
1296
+ throw new Error(`Missing skill folders after pull: ${missingAfterPull.join(", ")}`);
1297
+ }
1246
1298
  const remoteNames = new Set(remote.map((row) => row.name));
1247
1299
  for (const [name, localInfo] of localSkills.entries()) {
1248
1300
  if (!remoteNames.has(name)) {
@@ -1254,7 +1306,15 @@ async function handleSkillsRoutes(req, res, url, context) {
1254
1306
  const owner = item.owner || uniqueOwnerByName.get(item.name) || "";
1255
1307
  if (owner) nextOwners[item.name] = owner;
1256
1308
  }
1257
- await writeSkillsSyncState({ ...state, installedOwners: nextOwners });
1309
+ const pulledHead = await runCommandWithOutput("git", ["rev-parse", "HEAD"], { cwd: getSkillsInstallDir() }).catch(() => "");
1310
+ await writeSkillsSyncState({
1311
+ ...state,
1312
+ installedOwners: nextOwners,
1313
+ lastPullCommitSha: pulledHead.trim(),
1314
+ lastSyncAttemptCount: 1,
1315
+ lastSyncError: "",
1316
+ lastSyncAtIso: (/* @__PURE__ */ new Date()).toISOString()
1317
+ });
1258
1318
  try {
1259
1319
  await appServer.rpc("skills/list", { forceReload: true });
1260
1320
  } catch {