@fractary/codex-cli 0.10.20 → 0.10.22

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/cli.cjs CHANGED
@@ -956,6 +956,23 @@ function getEnvironmentBranch(config, env) {
956
956
  };
957
957
  return envMap[env] || env;
958
958
  }
959
+ async function commitAndPushToCodex(codexRepoPath, projectName, syncedCount) {
960
+ try {
961
+ const { RepoManager } = await import('@fractary/core/repo');
962
+ const repoManager = new RepoManager({ platform: "github" }, codexRepoPath);
963
+ repoManager.stageAll();
964
+ if (repoManager.isClean()) {
965
+ return { pushed: false, message: "No changes to push - codex is already up to date" };
966
+ }
967
+ repoManager.commit({
968
+ message: `Sync ${syncedCount} files from ${projectName}`
969
+ });
970
+ repoManager.push({});
971
+ return { pushed: true, message: "Changes pushed to codex repository" };
972
+ } catch (error) {
973
+ return { pushed: false, message: error.message };
974
+ }
975
+ }
959
976
  function syncCommand() {
960
977
  const cmd = new commander.Command("sync");
961
978
  cmd.description("Sync single project with codex repository").argument("[name]", "Project name (auto-detected if not provided)").option("--env <env>", "Target environment (dev/test/staging/prod)", "prod").option("--dry-run", "Show what would sync without executing").option("--direction <dir>", "Sync direction (to-codex/from-codex/bidirectional)", "bidirectional").option("--include <pattern>", "Include files matching pattern (can be used multiple times)", (val, prev) => prev.concat([val]), []).option("--exclude <pattern>", "Exclude files matching pattern (can be used multiple times)", (val, prev) => prev.concat([val]), []).option("--force", "Force sync without checking timestamps").option("--json", "Output as JSON").option("--work-id <id>", "GitHub issue number or URL to scope sync to").action(async (name, options) => {
@@ -1126,12 +1143,33 @@ function syncCommand() {
1126
1143
  console.error(chalk10__default.default.dim(` ${error.message}`));
1127
1144
  process.exit(1);
1128
1145
  }
1146
+ const codexProjectDir = path3__namespace.join(codexRepoPath, "projects", projectName);
1147
+ let existingCodexFiles = [];
1148
+ try {
1149
+ const codexGlobMatches = await globSync("**/*", {
1150
+ cwd: codexProjectDir,
1151
+ dot: true,
1152
+ nodir: true
1153
+ });
1154
+ const fsPromises = await import('fs/promises');
1155
+ existingCodexFiles = await Promise.all(
1156
+ codexGlobMatches.map(async (filePath) => {
1157
+ const fullPath = path3__namespace.join(codexProjectDir, filePath);
1158
+ const stats = await fsPromises.stat(fullPath);
1159
+ return {
1160
+ path: filePath,
1161
+ size: stats.size,
1162
+ mtime: stats.mtimeMs
1163
+ };
1164
+ })
1165
+ );
1166
+ } catch {
1167
+ }
1129
1168
  plan = await syncManager.createPlan(
1130
1169
  config.organization,
1131
1170
  projectName,
1132
1171
  sourceDir,
1133
- [],
1134
- // Empty target - treat all files as creates
1172
+ existingCodexFiles,
1135
1173
  syncOptions
1136
1174
  );
1137
1175
  plan.source = sourceDir;
@@ -1183,6 +1221,10 @@ function syncCommand() {
1183
1221
  return;
1184
1222
  }
1185
1223
  const result2 = await syncManager.executePlan(plan, syncOptions);
1224
+ let pushResult;
1225
+ if (direction === "to-codex" && codexRepoPath && result2.synced > 0) {
1226
+ pushResult = await commitAndPushToCodex(codexRepoPath, projectName, result2.synced);
1227
+ }
1186
1228
  let status;
1187
1229
  if (!result2.success && result2.synced === 0) {
1188
1230
  status = "failure";
@@ -1201,7 +1243,8 @@ function syncCommand() {
1201
1243
  skipped: result2.skipped,
1202
1244
  duration: result2.duration,
1203
1245
  errors: result2.errors
1204
- }
1246
+ },
1247
+ ...pushResult ? { pushed: pushResult.pushed, pushMessage: pushResult.message } : {}
1205
1248
  }, null, 2));
1206
1249
  return;
1207
1250
  }
@@ -1270,28 +1313,12 @@ Total: ${plan.totalFiles} files (${codex.formatBytes(plan.totalBytes)})`));
1270
1313
  const result = await syncManager.executePlan(plan, syncOptions);
1271
1314
  const duration = Date.now() - startTime;
1272
1315
  if (direction === "to-codex" && codexRepoPath && result.synced > 0) {
1273
- try {
1274
- if (!options.json) {
1275
- console.log(chalk10__default.default.blue("Committing and pushing to codex..."));
1276
- }
1277
- const { RepoManager } = await import('@fractary/core/repo');
1278
- const repoManager = new RepoManager({ platform: "github" }, codexRepoPath);
1279
- repoManager.stageAll();
1280
- if (repoManager.isClean()) {
1281
- if (!options.json) {
1282
- console.log(chalk10__default.default.dim(" No changes to push - codex is already up to date"));
1283
- }
1284
- } else {
1285
- repoManager.commit({
1286
- message: `Sync ${result.synced} files from ${projectName}`
1287
- });
1288
- repoManager.push({});
1289
- if (!options.json) {
1290
- console.log(chalk10__default.default.dim(" Changes pushed to codex repository"));
1291
- }
1292
- }
1293
- } catch (error) {
1294
- console.error(chalk10__default.default.red("Error pushing to codex:"), error.message);
1316
+ console.log(chalk10__default.default.blue("Committing and pushing to codex..."));
1317
+ const pushResult = await commitAndPushToCodex(codexRepoPath, projectName, result.synced);
1318
+ if (pushResult.pushed) {
1319
+ console.log(chalk10__default.default.dim(` ${pushResult.message}`));
1320
+ } else {
1321
+ console.log(chalk10__default.default.dim(` ${pushResult.message}`));
1295
1322
  }
1296
1323
  }
1297
1324
  console.log("");