@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.cjs CHANGED
@@ -907,7 +907,7 @@ init_cjs_shims();
907
907
  function sanitizeForS3BucketName(name) {
908
908
  return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "").replace(/-+/g, "-").substring(0, 63);
909
909
  }
910
- function getDefaultUnifiedConfig(organization, project) {
910
+ function getDefaultUnifiedConfig(organization, project, codexRepo) {
911
911
  const sanitizedProject = sanitizeForS3BucketName(project);
912
912
  return {
913
913
  file: {
@@ -951,6 +951,7 @@ function getDefaultUnifiedConfig(organization, project) {
951
951
  schema_version: "2.0",
952
952
  organization,
953
953
  project,
954
+ codex_repo: codexRepo,
954
955
  dependencies: {}
955
956
  }
956
957
  };
@@ -994,6 +995,7 @@ function mergeUnifiedConfigs(existing, updates) {
994
995
  schema_version: updates.codex?.schema_version || existing.codex?.schema_version || "2.0",
995
996
  organization: updates.codex?.organization || existing.codex?.organization || "default",
996
997
  project: updates.codex?.project || existing.codex?.project || "default",
998
+ codex_repo: updates.codex?.codex_repo || existing.codex?.codex_repo || "",
997
999
  dependencies: {
998
1000
  ...existing.codex?.dependencies || {},
999
1001
  ...updates.codex?.dependencies || {}
@@ -1002,10 +1004,10 @@ function mergeUnifiedConfigs(existing, updates) {
1002
1004
  }
1003
1005
  return merged;
1004
1006
  }
1005
- async function initializeUnifiedConfig(configPath, organization, project, options) {
1007
+ async function initializeUnifiedConfig(configPath, organization, project, codexRepo, options) {
1006
1008
  const existingConfig = await readUnifiedConfig(configPath);
1007
1009
  if (existingConfig && !options?.force) {
1008
- const defaultConfig = getDefaultUnifiedConfig(organization, project);
1010
+ const defaultConfig = getDefaultUnifiedConfig(organization, project, codexRepo);
1009
1011
  const merged = mergeUnifiedConfigs(existingConfig, defaultConfig);
1010
1012
  await writeUnifiedConfig(merged, configPath);
1011
1013
  return {
@@ -1014,7 +1016,7 @@ async function initializeUnifiedConfig(configPath, organization, project, option
1014
1016
  config: merged
1015
1017
  };
1016
1018
  }
1017
- const config = getDefaultUnifiedConfig(organization, project);
1019
+ const config = getDefaultUnifiedConfig(organization, project, codexRepo);
1018
1020
  await writeUnifiedConfig(config, configPath);
1019
1021
  return {
1020
1022
  created: true,
@@ -1123,6 +1125,20 @@ async function ensureCachePathIgnored(projectRoot, cachePath) {
1123
1125
  }
1124
1126
 
1125
1127
  // src/commands/config/init.ts
1128
+ function validateNameFormat(name, type) {
1129
+ if (!name || typeof name !== "string") {
1130
+ throw new Error(`${type} name is required`);
1131
+ }
1132
+ if (name.length > 100) {
1133
+ throw new Error(`${type} name too long (max 100 characters)`);
1134
+ }
1135
+ const safePattern = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
1136
+ if (!safePattern.test(name)) {
1137
+ throw new Error(
1138
+ `Invalid ${type} name format: "${name}". Must start with alphanumeric and contain only: a-z, A-Z, 0-9, ., -, _`
1139
+ );
1140
+ }
1141
+ }
1126
1142
  async function getOrgFromGitRemote() {
1127
1143
  try {
1128
1144
  const { execSync } = __require("child_process");
@@ -1134,6 +1150,60 @@ async function getOrgFromGitRemote() {
1134
1150
  return null;
1135
1151
  }
1136
1152
  }
1153
+ async function discoverCodexRepo(org) {
1154
+ try {
1155
+ validateNameFormat(org, "organization");
1156
+ } catch (error) {
1157
+ return { repo: null, error: "unknown", message: error.message };
1158
+ }
1159
+ try {
1160
+ const { execSync } = __require("child_process");
1161
+ try {
1162
+ execSync("gh --version", { encoding: "utf-8", stdio: "pipe" });
1163
+ } catch {
1164
+ return {
1165
+ repo: null,
1166
+ error: "gh_not_installed",
1167
+ message: "GitHub CLI (gh) is not installed. Install from https://cli.github.com/"
1168
+ };
1169
+ }
1170
+ try {
1171
+ execSync("gh auth status", { encoding: "utf-8", stdio: "pipe" });
1172
+ } catch {
1173
+ return {
1174
+ repo: null,
1175
+ error: "auth_failed",
1176
+ message: "GitHub CLI not authenticated. Run: gh auth login"
1177
+ };
1178
+ }
1179
+ const result = execSync(
1180
+ `gh repo list ${org} --json name --jq '.[].name | select(startswith("codex."))' 2>&1`,
1181
+ { encoding: "utf-8" }
1182
+ ).trim();
1183
+ if (result.includes("Could not resolve to an Organization") || result.includes("Not Found")) {
1184
+ return {
1185
+ repo: null,
1186
+ error: "org_not_found",
1187
+ message: `Organization '${org}' not found on GitHub`
1188
+ };
1189
+ }
1190
+ const repos = result.split("\n").filter(Boolean);
1191
+ if (repos.length === 0) {
1192
+ return {
1193
+ repo: null,
1194
+ error: "no_repos_found",
1195
+ message: `No codex.* repositories found in organization '${org}'`
1196
+ };
1197
+ }
1198
+ return { repo: repos[0] };
1199
+ } catch (error) {
1200
+ return {
1201
+ repo: null,
1202
+ error: "unknown",
1203
+ message: error.message || "Unknown error during discovery"
1204
+ };
1205
+ }
1206
+ }
1137
1207
  async function fileExists(filePath) {
1138
1208
  try {
1139
1209
  await fs__namespace.access(filePath);
@@ -1144,7 +1214,7 @@ async function fileExists(filePath) {
1144
1214
  }
1145
1215
  function initCommand() {
1146
1216
  const cmd = new commander.Command("init");
1147
- 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) => {
1217
+ 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) => {
1148
1218
  try {
1149
1219
  console.log(chalk7__default.default.blue("Initializing unified Fractary configuration...\n"));
1150
1220
  let org = options.org;
@@ -1168,10 +1238,53 @@ function initCommand() {
1168
1238
  console.log(chalk7__default.default.dim(`Organization: ${chalk7__default.default.cyan(org)}
1169
1239
  `));
1170
1240
  }
1241
+ try {
1242
+ validateNameFormat(org, "organization");
1243
+ } catch (error) {
1244
+ console.error(chalk7__default.default.red("Error:"), error.message);
1245
+ process.exit(1);
1246
+ }
1171
1247
  let project = options.project;
1172
1248
  if (!project) {
1173
1249
  project = path4__namespace.basename(process.cwd());
1174
1250
  console.log(chalk7__default.default.dim(`Project: ${chalk7__default.default.cyan(project)}
1251
+ `));
1252
+ }
1253
+ let codexRepo = options.codexRepo;
1254
+ if (codexRepo) {
1255
+ try {
1256
+ validateNameFormat(codexRepo, "repository");
1257
+ } catch (error) {
1258
+ console.error(chalk7__default.default.red("Error:"), error.message);
1259
+ process.exit(1);
1260
+ }
1261
+ console.log(chalk7__default.default.dim(`Codex repository: ${chalk7__default.default.cyan(codexRepo)}
1262
+ `));
1263
+ } else {
1264
+ const discoveryResult = await discoverCodexRepo(org);
1265
+ if (discoveryResult.repo) {
1266
+ codexRepo = discoveryResult.repo;
1267
+ console.log(chalk7__default.default.dim(`Codex repository: ${chalk7__default.default.cyan(codexRepo)} (auto-discovered)
1268
+ `));
1269
+ } else {
1270
+ if (discoveryResult.error === "gh_not_installed") {
1271
+ console.log(chalk7__default.default.dim(` Note: ${discoveryResult.message}
1272
+ `));
1273
+ } else if (discoveryResult.error === "auth_failed") {
1274
+ console.log(chalk7__default.default.dim(` Note: ${discoveryResult.message}
1275
+ `));
1276
+ } else if (discoveryResult.error === "org_not_found") {
1277
+ console.log(chalk7__default.default.dim(` Note: ${discoveryResult.message}
1278
+ `));
1279
+ }
1280
+ }
1281
+ }
1282
+ if (!codexRepo) {
1283
+ console.log(chalk7__default.default.yellow(`\u26A0 Could not discover codex repository in organization '${org}'`));
1284
+ console.log(chalk7__default.default.dim(" Use --codex-repo <name> to specify explicitly"));
1285
+ console.log(chalk7__default.default.dim(" Expected naming convention: codex.{org}.{tld} (e.g., codex.fractary.com)\n"));
1286
+ codexRepo = `codex.${org}.com`;
1287
+ console.log(chalk7__default.default.dim(` Using default: ${chalk7__default.default.cyan(codexRepo)}
1175
1288
  `));
1176
1289
  }
1177
1290
  const configPath = path4__namespace.join(process.cwd(), ".fractary", "config.yaml");
@@ -1205,6 +1318,7 @@ function initCommand() {
1205
1318
  configPath,
1206
1319
  org,
1207
1320
  project,
1321
+ codexRepo,
1208
1322
  { force: options.force }
1209
1323
  );
1210
1324
  if (result.created) {
@@ -1216,6 +1330,7 @@ function initCommand() {
1216
1330
  console.log(chalk7__default.default.bold("Configuration:"));
1217
1331
  console.log(chalk7__default.default.dim(` Organization: ${org}`));
1218
1332
  console.log(chalk7__default.default.dim(` Project: ${project}`));
1333
+ console.log(chalk7__default.default.dim(` Codex Repository: ${codexRepo}`));
1219
1334
  console.log(chalk7__default.default.dim(` Config: .fractary/config.yaml`));
1220
1335
  console.log(chalk7__default.default.bold("\nFile plugin sources:"));
1221
1336
  console.log(chalk7__default.default.dim(" - specs: .fractary/specs/ \u2192 S3"));
@@ -1223,11 +1338,17 @@ function initCommand() {
1223
1338
  console.log(chalk7__default.default.bold("\nCodex plugin:"));
1224
1339
  console.log(chalk7__default.default.dim(" - Cache: .fractary/codex/cache/"));
1225
1340
  console.log(chalk7__default.default.dim(" - Dependencies: (none configured)"));
1341
+ console.log(chalk7__default.default.bold("\nGit Authentication:"));
1342
+ console.log(chalk7__default.default.dim(" Codex sync uses your existing git credentials."));
1343
+ console.log(chalk7__default.default.dim(" Ensure you have access to the codex repository:"));
1344
+ console.log(chalk7__default.default.dim(` gh repo view ${org}/${codexRepo}`));
1345
+ console.log(chalk7__default.default.dim(" Or set GITHUB_TOKEN environment variable."));
1226
1346
  console.log(chalk7__default.default.bold("\nNext steps:"));
1227
- console.log(chalk7__default.default.dim(" 1. Configure AWS credentials for S3 access"));
1228
- console.log(chalk7__default.default.dim(" 2. Edit .fractary/config.yaml to add external project dependencies"));
1229
- console.log(chalk7__default.default.dim(" 3. Access current project files: codex://specs/SPEC-001.md"));
1230
- console.log(chalk7__default.default.dim(" 4. Access external projects: codex://org/project/docs/README.md"));
1347
+ console.log(chalk7__default.default.dim(" 1. Verify codex repository access: gh repo view " + org + "/" + codexRepo));
1348
+ console.log(chalk7__default.default.dim(" 2. Configure AWS credentials for S3 access (if using file plugin)"));
1349
+ console.log(chalk7__default.default.dim(" 3. Edit .fractary/config.yaml to add external project dependencies"));
1350
+ console.log(chalk7__default.default.dim(" 4. Access current project files: codex://specs/SPEC-001.md"));
1351
+ console.log(chalk7__default.default.dim(" 5. Access external projects: codex://org/project/docs/README.md"));
1231
1352
  } catch (error) {
1232
1353
  console.error(chalk7__default.default.red("Error:"), error.message);
1233
1354
  process.exit(1);