@fractary/codex-cli 0.10.0 → 0.10.1

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.js CHANGED
@@ -874,7 +874,7 @@ init_esm_shims();
874
874
  function sanitizeForS3BucketName(name) {
875
875
  return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "").replace(/-+/g, "-").substring(0, 63);
876
876
  }
877
- function getDefaultUnifiedConfig(organization, project) {
877
+ function getDefaultUnifiedConfig(organization, project, codexRepo) {
878
878
  const sanitizedProject = sanitizeForS3BucketName(project);
879
879
  return {
880
880
  file: {
@@ -918,6 +918,7 @@ function getDefaultUnifiedConfig(organization, project) {
918
918
  schema_version: "2.0",
919
919
  organization,
920
920
  project,
921
+ codex_repo: codexRepo,
921
922
  dependencies: {}
922
923
  }
923
924
  };
@@ -961,6 +962,7 @@ function mergeUnifiedConfigs(existing, updates) {
961
962
  schema_version: updates.codex?.schema_version || existing.codex?.schema_version || "2.0",
962
963
  organization: updates.codex?.organization || existing.codex?.organization || "default",
963
964
  project: updates.codex?.project || existing.codex?.project || "default",
965
+ codex_repo: updates.codex?.codex_repo || existing.codex?.codex_repo || "",
964
966
  dependencies: {
965
967
  ...existing.codex?.dependencies || {},
966
968
  ...updates.codex?.dependencies || {}
@@ -969,10 +971,10 @@ function mergeUnifiedConfigs(existing, updates) {
969
971
  }
970
972
  return merged;
971
973
  }
972
- async function initializeUnifiedConfig(configPath, organization, project, options) {
974
+ async function initializeUnifiedConfig(configPath, organization, project, codexRepo, options) {
973
975
  const existingConfig = await readUnifiedConfig(configPath);
974
976
  if (existingConfig && !options?.force) {
975
- const defaultConfig = getDefaultUnifiedConfig(organization, project);
977
+ const defaultConfig = getDefaultUnifiedConfig(organization, project, codexRepo);
976
978
  const merged = mergeUnifiedConfigs(existingConfig, defaultConfig);
977
979
  await writeUnifiedConfig(merged, configPath);
978
980
  return {
@@ -981,7 +983,7 @@ async function initializeUnifiedConfig(configPath, organization, project, option
981
983
  config: merged
982
984
  };
983
985
  }
984
- const config = getDefaultUnifiedConfig(organization, project);
986
+ const config = getDefaultUnifiedConfig(organization, project, codexRepo);
985
987
  await writeUnifiedConfig(config, configPath);
986
988
  return {
987
989
  created: true,
@@ -1090,6 +1092,20 @@ async function ensureCachePathIgnored(projectRoot, cachePath) {
1090
1092
  }
1091
1093
 
1092
1094
  // src/commands/config/init.ts
1095
+ function validateNameFormat(name, type) {
1096
+ if (!name || typeof name !== "string") {
1097
+ throw new Error(`${type} name is required`);
1098
+ }
1099
+ if (name.length > 100) {
1100
+ throw new Error(`${type} name too long (max 100 characters)`);
1101
+ }
1102
+ const safePattern = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
1103
+ if (!safePattern.test(name)) {
1104
+ throw new Error(
1105
+ `Invalid ${type} name format: "${name}". Must start with alphanumeric and contain only: a-z, A-Z, 0-9, ., -, _`
1106
+ );
1107
+ }
1108
+ }
1093
1109
  async function getOrgFromGitRemote() {
1094
1110
  try {
1095
1111
  const { execSync } = __require("child_process");
@@ -1101,6 +1117,60 @@ async function getOrgFromGitRemote() {
1101
1117
  return null;
1102
1118
  }
1103
1119
  }
1120
+ async function discoverCodexRepo(org) {
1121
+ try {
1122
+ validateNameFormat(org, "organization");
1123
+ } catch (error) {
1124
+ return { repo: null, error: "unknown", message: error.message };
1125
+ }
1126
+ try {
1127
+ const { execSync } = __require("child_process");
1128
+ try {
1129
+ execSync("gh --version", { encoding: "utf-8", stdio: "pipe" });
1130
+ } catch {
1131
+ return {
1132
+ repo: null,
1133
+ error: "gh_not_installed",
1134
+ message: "GitHub CLI (gh) is not installed. Install from https://cli.github.com/"
1135
+ };
1136
+ }
1137
+ try {
1138
+ execSync("gh auth status", { encoding: "utf-8", stdio: "pipe" });
1139
+ } catch {
1140
+ return {
1141
+ repo: null,
1142
+ error: "auth_failed",
1143
+ message: "GitHub CLI not authenticated. Run: gh auth login"
1144
+ };
1145
+ }
1146
+ const result = execSync(
1147
+ `gh repo list ${org} --json name --jq '.[].name | select(startswith("codex."))' 2>&1`,
1148
+ { encoding: "utf-8" }
1149
+ ).trim();
1150
+ if (result.includes("Could not resolve to an Organization") || result.includes("Not Found")) {
1151
+ return {
1152
+ repo: null,
1153
+ error: "org_not_found",
1154
+ message: `Organization '${org}' not found on GitHub`
1155
+ };
1156
+ }
1157
+ const repos = result.split("\n").filter(Boolean);
1158
+ if (repos.length === 0) {
1159
+ return {
1160
+ repo: null,
1161
+ error: "no_repos_found",
1162
+ message: `No codex.* repositories found in organization '${org}'`
1163
+ };
1164
+ }
1165
+ return { repo: repos[0] };
1166
+ } catch (error) {
1167
+ return {
1168
+ repo: null,
1169
+ error: "unknown",
1170
+ message: error.message || "Unknown error during discovery"
1171
+ };
1172
+ }
1173
+ }
1104
1174
  async function fileExists(filePath) {
1105
1175
  try {
1106
1176
  await fs.access(filePath);
@@ -1111,7 +1181,7 @@ async function fileExists(filePath) {
1111
1181
  }
1112
1182
  function initCommand() {
1113
1183
  const cmd = new Command("init");
1114
- cmd.description("Initialize unified Fractary configuration (.fractary/config.yaml)").option("--org <slug>", 'Organization slug (e.g., "fractary")').option("--project <name>", "Project name (default: derived from directory)").option("--force", "Overwrite existing configuration").action(async (options) => {
1184
+ cmd.description("Initialize unified Fractary configuration (.fractary/config.yaml)").option("--org <slug>", 'Organization slug (e.g., "fractary")').option("--project <name>", "Project name (default: derived from directory)").option("--codex-repo <name>", 'Codex repository name (e.g., "codex.fractary.com")').option("--force", "Overwrite existing configuration").action(async (options) => {
1115
1185
  try {
1116
1186
  console.log(chalk7.blue("Initializing unified Fractary configuration...\n"));
1117
1187
  let org = options.org;
@@ -1135,10 +1205,53 @@ function initCommand() {
1135
1205
  console.log(chalk7.dim(`Organization: ${chalk7.cyan(org)}
1136
1206
  `));
1137
1207
  }
1208
+ try {
1209
+ validateNameFormat(org, "organization");
1210
+ } catch (error) {
1211
+ console.error(chalk7.red("Error:"), error.message);
1212
+ process.exit(1);
1213
+ }
1138
1214
  let project = options.project;
1139
1215
  if (!project) {
1140
1216
  project = path5.basename(process.cwd());
1141
1217
  console.log(chalk7.dim(`Project: ${chalk7.cyan(project)}
1218
+ `));
1219
+ }
1220
+ let codexRepo = options.codexRepo;
1221
+ if (codexRepo) {
1222
+ try {
1223
+ validateNameFormat(codexRepo, "repository");
1224
+ } catch (error) {
1225
+ console.error(chalk7.red("Error:"), error.message);
1226
+ process.exit(1);
1227
+ }
1228
+ console.log(chalk7.dim(`Codex repository: ${chalk7.cyan(codexRepo)}
1229
+ `));
1230
+ } else {
1231
+ const discoveryResult = await discoverCodexRepo(org);
1232
+ if (discoveryResult.repo) {
1233
+ codexRepo = discoveryResult.repo;
1234
+ console.log(chalk7.dim(`Codex repository: ${chalk7.cyan(codexRepo)} (auto-discovered)
1235
+ `));
1236
+ } else {
1237
+ if (discoveryResult.error === "gh_not_installed") {
1238
+ console.log(chalk7.dim(` Note: ${discoveryResult.message}
1239
+ `));
1240
+ } else if (discoveryResult.error === "auth_failed") {
1241
+ console.log(chalk7.dim(` Note: ${discoveryResult.message}
1242
+ `));
1243
+ } else if (discoveryResult.error === "org_not_found") {
1244
+ console.log(chalk7.dim(` Note: ${discoveryResult.message}
1245
+ `));
1246
+ }
1247
+ }
1248
+ }
1249
+ if (!codexRepo) {
1250
+ console.log(chalk7.yellow(`\u26A0 Could not discover codex repository in organization '${org}'`));
1251
+ console.log(chalk7.dim(" Use --codex-repo <name> to specify explicitly"));
1252
+ console.log(chalk7.dim(" Expected naming convention: codex.{org}.{tld} (e.g., codex.fractary.com)\n"));
1253
+ codexRepo = `codex.${org}.com`;
1254
+ console.log(chalk7.dim(` Using default: ${chalk7.cyan(codexRepo)}
1142
1255
  `));
1143
1256
  }
1144
1257
  const configPath = path5.join(process.cwd(), ".fractary", "config.yaml");
@@ -1172,6 +1285,7 @@ function initCommand() {
1172
1285
  configPath,
1173
1286
  org,
1174
1287
  project,
1288
+ codexRepo,
1175
1289
  { force: options.force }
1176
1290
  );
1177
1291
  if (result.created) {
@@ -1183,6 +1297,7 @@ function initCommand() {
1183
1297
  console.log(chalk7.bold("Configuration:"));
1184
1298
  console.log(chalk7.dim(` Organization: ${org}`));
1185
1299
  console.log(chalk7.dim(` Project: ${project}`));
1300
+ console.log(chalk7.dim(` Codex Repository: ${codexRepo}`));
1186
1301
  console.log(chalk7.dim(` Config: .fractary/config.yaml`));
1187
1302
  console.log(chalk7.bold("\nFile plugin sources:"));
1188
1303
  console.log(chalk7.dim(" - specs: .fractary/specs/ \u2192 S3"));
@@ -1190,11 +1305,17 @@ function initCommand() {
1190
1305
  console.log(chalk7.bold("\nCodex plugin:"));
1191
1306
  console.log(chalk7.dim(" - Cache: .fractary/codex/cache/"));
1192
1307
  console.log(chalk7.dim(" - Dependencies: (none configured)"));
1308
+ console.log(chalk7.bold("\nGit Authentication:"));
1309
+ console.log(chalk7.dim(" Codex sync uses your existing git credentials."));
1310
+ console.log(chalk7.dim(" Ensure you have access to the codex repository:"));
1311
+ console.log(chalk7.dim(` gh repo view ${org}/${codexRepo}`));
1312
+ console.log(chalk7.dim(" Or set GITHUB_TOKEN environment variable."));
1193
1313
  console.log(chalk7.bold("\nNext steps:"));
1194
- console.log(chalk7.dim(" 1. Configure AWS credentials for S3 access"));
1195
- console.log(chalk7.dim(" 2. Edit .fractary/config.yaml to add external project dependencies"));
1196
- console.log(chalk7.dim(" 3. Access current project files: codex://specs/SPEC-001.md"));
1197
- console.log(chalk7.dim(" 4. Access external projects: codex://org/project/docs/README.md"));
1314
+ console.log(chalk7.dim(" 1. Verify codex repository access: gh repo view " + org + "/" + codexRepo));
1315
+ console.log(chalk7.dim(" 2. Configure AWS credentials for S3 access (if using file plugin)"));
1316
+ console.log(chalk7.dim(" 3. Edit .fractary/config.yaml to add external project dependencies"));
1317
+ console.log(chalk7.dim(" 4. Access current project files: codex://specs/SPEC-001.md"));
1318
+ console.log(chalk7.dim(" 5. Access external projects: codex://org/project/docs/README.md"));
1198
1319
  } catch (error) {
1199
1320
  console.error(chalk7.red("Error:"), error.message);
1200
1321
  process.exit(1);