codexapp 0.1.56 → 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-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
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() ?
|
|
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
|
|
967
|
-
if (
|
|
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();
|
|
@@ -1233,35 +1280,21 @@ async function handleSkillsRoutes(req, res, url, context) {
|
|
|
1233
1280
|
}
|
|
1234
1281
|
const localDir = await detectUserSkillsDir(appServer);
|
|
1235
1282
|
await pullInstalledSkillsFolderFromRepo(state.githubToken, state.repoOwner, state.repoName);
|
|
1236
|
-
const installerScript = resolveSkillInstallerScriptPath(getCodexHomeDir());
|
|
1237
|
-
if (!installerScript) {
|
|
1238
|
-
throw new Error("Skill installer script not found");
|
|
1239
|
-
}
|
|
1240
|
-
const pythonCommand = resolvePythonCommand();
|
|
1241
|
-
if (!pythonCommand) {
|
|
1242
|
-
throw new Error("Python 3 is required to install skills");
|
|
1243
|
-
}
|
|
1244
1283
|
const localSkills = await scanInstalledSkillsFromDisk();
|
|
1284
|
+
const missingAfterPull = [];
|
|
1245
1285
|
for (const skill of remote) {
|
|
1246
1286
|
const owner = skill.owner || uniqueOwnerByName.get(skill.name) || "";
|
|
1247
1287
|
if (!owner) continue;
|
|
1248
1288
|
if (!localSkills.has(skill.name)) {
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
installerScript,
|
|
1252
|
-
"--repo",
|
|
1253
|
-
`${HUB_SKILLS_OWNER}/${HUB_SKILLS_REPO}`,
|
|
1254
|
-
"--path",
|
|
1255
|
-
`skills/${owner}/${skill.name}`,
|
|
1256
|
-
"--dest",
|
|
1257
|
-
localDir,
|
|
1258
|
-
"--method",
|
|
1259
|
-
"git"
|
|
1260
|
-
]);
|
|
1289
|
+
missingAfterPull.push(`${owner}/${skill.name}`);
|
|
1290
|
+
continue;
|
|
1261
1291
|
}
|
|
1262
1292
|
const skillPath = join2(localDir, skill.name);
|
|
1263
1293
|
await appServer.rpc("skills/config/write", { path: skillPath, enabled: skill.enabled });
|
|
1264
1294
|
}
|
|
1295
|
+
if (missingAfterPull.length > 0) {
|
|
1296
|
+
throw new Error(`Missing skill folders after pull: ${missingAfterPull.join(", ")}`);
|
|
1297
|
+
}
|
|
1265
1298
|
const remoteNames = new Set(remote.map((row) => row.name));
|
|
1266
1299
|
for (const [name, localInfo] of localSkills.entries()) {
|
|
1267
1300
|
if (!remoteNames.has(name)) {
|
|
@@ -1273,7 +1306,15 @@ async function handleSkillsRoutes(req, res, url, context) {
|
|
|
1273
1306
|
const owner = item.owner || uniqueOwnerByName.get(item.name) || "";
|
|
1274
1307
|
if (owner) nextOwners[item.name] = owner;
|
|
1275
1308
|
}
|
|
1276
|
-
await
|
|
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
|
+
});
|
|
1277
1318
|
try {
|
|
1278
1319
|
await appServer.rpc("skills/list", { forceReload: true });
|
|
1279
1320
|
} catch {
|
|
@@ -1374,7 +1415,8 @@ async function handleSkillsRoutes(req, res, url, context) {
|
|
|
1374
1415
|
const payload = asRecord(await readJsonBody2(req));
|
|
1375
1416
|
const name = typeof payload?.name === "string" ? payload.name : "";
|
|
1376
1417
|
const path = typeof payload?.path === "string" ? payload.path : "";
|
|
1377
|
-
const
|
|
1418
|
+
const normalizedPath = path.endsWith("/SKILL.md") ? path.slice(0, -"/SKILL.md".length) : path;
|
|
1419
|
+
const target = normalizedPath || (name ? join2(getSkillsInstallDir(), name) : "");
|
|
1378
1420
|
if (!target) {
|
|
1379
1421
|
setJson(res, 400, { error: "Missing name or path" });
|
|
1380
1422
|
return true;
|