@fractary/codex-cli 0.10.13 → 0.10.14

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
@@ -4,7 +4,7 @@ import { dirname, join } from 'path';
4
4
  import { fileURLToPath } from 'url';
5
5
  import * as fs from 'fs/promises';
6
6
  import * as yaml2 from 'js-yaml';
7
- import { readCodexConfig, expandEnvVarsInConfig, expandEnvVars, parseSize, parseDuration, ValidationError, PermissionDeniedError, ConfigurationError, CodexError } from '@fractary/codex';
7
+ import { readCodexConfig, CONFIG_SCHEMA_VERSION, expandEnvVarsInConfig, expandEnvVars, parseSize, parseDuration, ValidationError, PermissionDeniedError, ConfigurationError, CodexError } from '@fractary/codex';
8
8
  import * as os from 'os';
9
9
  import { spawn } from 'child_process';
10
10
  import { Command } from 'commander';
@@ -790,7 +790,7 @@ function getDefaultUnifiedConfig(organization, project, codexRepo) {
790
790
  const sanitizedProject = sanitizeForS3BucketName(project);
791
791
  return {
792
792
  file: {
793
- schema_version: "2.0",
793
+ schema_version: CONFIG_SCHEMA_VERSION,
794
794
  sources: {
795
795
  specs: {
796
796
  type: "s3",
@@ -827,11 +827,16 @@ function getDefaultUnifiedConfig(organization, project, codexRepo) {
827
827
  }
828
828
  },
829
829
  codex: {
830
- schema_version: "2.0",
830
+ schema_version: CONFIG_SCHEMA_VERSION,
831
831
  organization,
832
832
  project,
833
833
  codex_repo: codexRepo,
834
- dependencies: {}
834
+ remotes: {
835
+ // The codex repository - uses same token as git operations
836
+ [`${organization}/${codexRepo}`]: {
837
+ token: "${GITHUB_TOKEN}"
838
+ }
839
+ }
835
840
  }
836
841
  };
837
842
  }
@@ -862,7 +867,7 @@ function mergeUnifiedConfigs(existing, updates) {
862
867
  const merged = {};
863
868
  if (updates.file || existing.file) {
864
869
  merged.file = {
865
- schema_version: updates.file?.schema_version || existing.file?.schema_version || "2.0",
870
+ schema_version: updates.file?.schema_version || existing.file?.schema_version || CONFIG_SCHEMA_VERSION,
866
871
  sources: {
867
872
  ...existing.file?.sources || {},
868
873
  ...updates.file?.sources || {}
@@ -871,13 +876,13 @@ function mergeUnifiedConfigs(existing, updates) {
871
876
  }
872
877
  if (updates.codex || existing.codex) {
873
878
  merged.codex = {
874
- schema_version: updates.codex?.schema_version || existing.codex?.schema_version || "2.0",
879
+ schema_version: updates.codex?.schema_version || existing.codex?.schema_version || CONFIG_SCHEMA_VERSION,
875
880
  organization: updates.codex?.organization || existing.codex?.organization || "default",
876
881
  project: updates.codex?.project || existing.codex?.project || "default",
877
882
  codex_repo: updates.codex?.codex_repo || existing.codex?.codex_repo || "",
878
- dependencies: {
879
- ...existing.codex?.dependencies || {},
880
- ...updates.codex?.dependencies || {}
883
+ remotes: {
884
+ ...existing.codex?.remotes || {},
885
+ ...updates.codex?.remotes || {}
881
886
  }
882
887
  };
883
888
  }
@@ -1091,9 +1096,64 @@ async function fileExists(filePath) {
1091
1096
  return false;
1092
1097
  }
1093
1098
  }
1099
+ async function installMcpServer(projectRoot, configPath = ".fractary/config.yaml", options = {}) {
1100
+ const mcpJsonPath = path5.join(projectRoot, ".mcp.json");
1101
+ const { backup = true } = options;
1102
+ let existingConfig = { mcpServers: {} };
1103
+ let backupPath;
1104
+ let migrated = false;
1105
+ if (await fileExists(mcpJsonPath)) {
1106
+ try {
1107
+ const content = await fs.readFile(mcpJsonPath, "utf-8");
1108
+ existingConfig = JSON.parse(content);
1109
+ if (backup) {
1110
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").slice(0, 18);
1111
+ const suffix = Math.random().toString(36).substring(2, 6);
1112
+ backupPath = `${mcpJsonPath}.backup.${timestamp}-${suffix}`;
1113
+ await fs.writeFile(backupPath, content);
1114
+ }
1115
+ } catch {
1116
+ console.log(chalk7.yellow("\u26A0 Warning: .mcp.json contains invalid JSON, starting fresh"));
1117
+ existingConfig = { mcpServers: {} };
1118
+ }
1119
+ }
1120
+ if (!existingConfig.mcpServers) {
1121
+ existingConfig.mcpServers = {};
1122
+ }
1123
+ const existing = existingConfig.mcpServers["fractary-codex"];
1124
+ if (existing) {
1125
+ const existingCommand = existing.command;
1126
+ const existingArgs = existing.args || [];
1127
+ if (existingCommand === "npx" && existingArgs.includes("@fractary/codex-mcp")) {
1128
+ return {
1129
+ installed: false,
1130
+ migrated: false,
1131
+ alreadyInstalled: true,
1132
+ backupPath
1133
+ };
1134
+ }
1135
+ if (existingCommand === "node" || existingArgs.includes("@fractary/codex")) {
1136
+ migrated = true;
1137
+ }
1138
+ }
1139
+ existingConfig.mcpServers["fractary-codex"] = {
1140
+ command: "npx",
1141
+ args: ["-y", "@fractary/codex-mcp", "--config", configPath]
1142
+ };
1143
+ await fs.writeFile(
1144
+ mcpJsonPath,
1145
+ JSON.stringify(existingConfig, null, 2) + "\n"
1146
+ );
1147
+ return {
1148
+ installed: true,
1149
+ migrated,
1150
+ alreadyInstalled: false,
1151
+ backupPath
1152
+ };
1153
+ }
1094
1154
  function initCommand() {
1095
1155
  const cmd = new Command("init");
1096
- 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) => {
1156
+ 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").option("--no-mcp", "Skip MCP server installation").action(async (options) => {
1097
1157
  try {
1098
1158
  console.log(chalk7.blue("Initializing unified Fractary configuration...\n"));
1099
1159
  let org = options.org;
@@ -1205,6 +1265,20 @@ function initCommand() {
1205
1265
  } else if (result.merged) {
1206
1266
  console.log(chalk7.green("\u2713"), chalk7.dim(".fractary/config.yaml (merged with existing)"));
1207
1267
  }
1268
+ if (options.mcp !== false) {
1269
+ console.log("\nConfiguring MCP server...");
1270
+ const mcpResult = await installMcpServer(process.cwd(), ".fractary/config.yaml");
1271
+ if (mcpResult.alreadyInstalled) {
1272
+ console.log(chalk7.green("\u2713"), chalk7.dim(".mcp.json (already configured)"));
1273
+ } else if (mcpResult.migrated) {
1274
+ console.log(chalk7.green("\u2713"), chalk7.dim(".mcp.json (migrated from old format)"));
1275
+ if (mcpResult.backupPath) {
1276
+ console.log(chalk7.dim(` Backup: ${path5.basename(mcpResult.backupPath)}`));
1277
+ }
1278
+ } else if (mcpResult.installed) {
1279
+ console.log(chalk7.green("\u2713"), chalk7.dim(".mcp.json (created)"));
1280
+ }
1281
+ }
1208
1282
  console.log(chalk7.green("\n\u2713 Unified configuration initialized successfully!\n"));
1209
1283
  console.log(chalk7.bold("Configuration:"));
1210
1284
  console.log(chalk7.dim(` Organization: ${org}`));
@@ -1216,18 +1290,19 @@ function initCommand() {
1216
1290
  console.log(chalk7.dim(" - logs: .fractary/logs/ \u2192 S3"));
1217
1291
  console.log(chalk7.bold("\nCodex plugin:"));
1218
1292
  console.log(chalk7.dim(" - Cache: .fractary/codex/cache/"));
1219
- console.log(chalk7.dim(" - Dependencies: (none configured)"));
1293
+ console.log(chalk7.dim(" - MCP Server: @fractary/codex-mcp (via npx)"));
1294
+ console.log(chalk7.dim(" - Remotes: codex repo configured"));
1220
1295
  console.log(chalk7.bold("\nGit Authentication:"));
1221
1296
  console.log(chalk7.dim(" Codex sync uses your existing git credentials."));
1222
1297
  console.log(chalk7.dim(" Ensure you have access to the codex repository:"));
1223
1298
  console.log(chalk7.dim(` gh repo view ${org}/${codexRepo}`));
1224
1299
  console.log(chalk7.dim(" Or set GITHUB_TOKEN environment variable."));
1225
1300
  console.log(chalk7.bold("\nNext steps:"));
1226
- console.log(chalk7.dim(" 1. Verify codex repository access: gh repo view " + org + "/" + codexRepo));
1227
- console.log(chalk7.dim(" 2. Configure AWS credentials for S3 access (if using file plugin)"));
1228
- console.log(chalk7.dim(" 3. Edit .fractary/config.yaml to add external project dependencies"));
1229
- console.log(chalk7.dim(" 4. Access current project files: codex://specs/SPEC-001.md"));
1230
- console.log(chalk7.dim(" 5. Access external projects: codex://org/project/docs/README.md"));
1301
+ console.log(chalk7.dim(" 1. Restart Claude Code to load the MCP server"));
1302
+ console.log(chalk7.dim(" 2. Verify codex repository access: gh repo view " + org + "/" + codexRepo));
1303
+ console.log(chalk7.dim(" 3. Configure AWS credentials for S3 access (if using file plugin)"));
1304
+ console.log(chalk7.dim(" 4. Edit .fractary/config.yaml to add external project remotes"));
1305
+ console.log(chalk7.dim(" 5. Reference docs via codex:// URIs (auto-fetched by MCP)"));
1231
1306
  } catch (error) {
1232
1307
  console.error(chalk7.red("Error:"), error.message);
1233
1308
  process.exit(1);