@fractary/codex-cli 0.10.11 → 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.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  var fs$1 = require('fs/promises');
5
5
  var path4 = require('path');
6
- var yaml = require('js-yaml');
6
+ var yaml2 = require('js-yaml');
7
7
  var codex = require('@fractary/codex');
8
8
  var os = require('os');
9
9
  var child_process = require('child_process');
@@ -35,7 +35,7 @@ function _interopNamespace(e) {
35
35
 
36
36
  var fs__namespace = /*#__PURE__*/_interopNamespace(fs$1);
37
37
  var path4__namespace = /*#__PURE__*/_interopNamespace(path4);
38
- var yaml__namespace = /*#__PURE__*/_interopNamespace(yaml);
38
+ var yaml2__namespace = /*#__PURE__*/_interopNamespace(yaml2);
39
39
  var os__namespace = /*#__PURE__*/_interopNamespace(os);
40
40
  var chalk7__default = /*#__PURE__*/_interopDefault(chalk7);
41
41
  var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
@@ -71,7 +71,7 @@ __export(migrate_config_exports, {
71
71
  getDefaultYamlConfig: () => getDefaultYamlConfig,
72
72
  isLegacyConfig: () => isLegacyConfig,
73
73
  migrateConfig: () => migrateConfig,
74
- readYamlConfig: () => readYamlConfig,
74
+ readYamlConfig: () => codex.readCodexConfig,
75
75
  writeYamlConfig: () => writeYamlConfig
76
76
  });
77
77
  async function isLegacyConfig(configPath) {
@@ -196,7 +196,7 @@ async function migrateConfig(legacyConfigPath, options) {
196
196
  async function writeYamlConfig(config, outputPath) {
197
197
  const dir = path4__namespace.dirname(outputPath);
198
198
  await fs__namespace.mkdir(dir, { recursive: true });
199
- const yamlContent = yaml__namespace.dump(config, {
199
+ const yamlContent = yaml2__namespace.dump(config, {
200
200
  indent: 2,
201
201
  lineWidth: 80,
202
202
  noRefs: true,
@@ -261,20 +261,6 @@ function getDefaultYamlConfig(organization) {
261
261
  }
262
262
  };
263
263
  }
264
- async function readYamlConfig(configPath) {
265
- const content = await fs__namespace.readFile(configPath, "utf-8");
266
- const rawConfig = yaml__namespace.load(content);
267
- let config;
268
- if (rawConfig.codex && typeof rawConfig.codex === "object") {
269
- config = rawConfig.codex;
270
- } else {
271
- config = rawConfig;
272
- }
273
- if (!config.organization) {
274
- throw new Error("Invalid config: organization is required");
275
- }
276
- return config;
277
- }
278
264
  var init_migrate_config = __esm({
279
265
  "src/config/migrate-config.ts"() {
280
266
  init_cjs_shims();
@@ -284,91 +270,11 @@ var init_migrate_config = __esm({
284
270
  // src/config/config-types.ts
285
271
  var config_types_exports = {};
286
272
  __export(config_types_exports, {
287
- parseDuration: () => parseDuration,
288
- parseSize: () => parseSize,
289
- resolveEnvVars: () => resolveEnvVars,
290
- resolveEnvVarsInConfig: () => resolveEnvVarsInConfig
273
+ parseDuration: () => codex.parseDuration,
274
+ parseSize: () => codex.parseSize,
275
+ resolveEnvVars: () => codex.expandEnvVars,
276
+ resolveEnvVarsInConfig: () => codex.expandEnvVarsInConfig
291
277
  });
292
- function parseDuration(duration) {
293
- if (typeof duration === "number") {
294
- return duration;
295
- }
296
- const match = duration.match(/^(\d+)([smhdwMy])$/);
297
- if (!match) {
298
- throw new Error(`Invalid duration format: ${duration}`);
299
- }
300
- const [, valueStr, unit] = match;
301
- const value = parseInt(valueStr, 10);
302
- switch (unit) {
303
- case "s":
304
- return value;
305
- case "m":
306
- return value * 60;
307
- case "h":
308
- return value * 3600;
309
- case "d":
310
- return value * 86400;
311
- case "w":
312
- return value * 604800;
313
- case "M":
314
- return value * 2592e3;
315
- // 30 days
316
- case "y":
317
- return value * 31536e3;
318
- // 365 days
319
- default:
320
- throw new Error(`Unknown duration unit: ${unit}`);
321
- }
322
- }
323
- function parseSize(size) {
324
- if (typeof size === "number") {
325
- return size;
326
- }
327
- const match = size.match(/^(\d+(?:\.\d+)?)\s*(B|KB|MB|GB)$/i);
328
- if (!match) {
329
- throw new Error(`Invalid size format: ${size}`);
330
- }
331
- const [, valueStr, unit] = match;
332
- const value = parseFloat(valueStr);
333
- switch (unit.toUpperCase()) {
334
- case "B":
335
- return value;
336
- case "KB":
337
- return value * 1024;
338
- case "MB":
339
- return value * 1024 * 1024;
340
- case "GB":
341
- return value * 1024 * 1024 * 1024;
342
- default:
343
- throw new Error(`Unknown size unit: ${unit}`);
344
- }
345
- }
346
- function resolveEnvVars(value) {
347
- return value.replace(/\$\{([^}]+)\}/g, (_, varName) => {
348
- const envValue = process.env[varName];
349
- if (envValue === void 0) {
350
- console.warn(`Warning: Environment variable ${varName} is not set`);
351
- return `\${${varName}}`;
352
- }
353
- return envValue;
354
- });
355
- }
356
- function resolveEnvVarsInConfig(config) {
357
- if (typeof config === "string") {
358
- return resolveEnvVars(config);
359
- }
360
- if (Array.isArray(config)) {
361
- return config.map((item) => resolveEnvVarsInConfig(item));
362
- }
363
- if (config !== null && typeof config === "object") {
364
- const result = {};
365
- for (const [key, value] of Object.entries(config)) {
366
- result[key] = resolveEnvVarsInConfig(value);
367
- }
368
- return result;
369
- }
370
- return config;
371
- }
372
278
  var init_config_types = __esm({
373
279
  "src/config/config-types.ts"() {
374
280
  init_cjs_shims();
@@ -421,14 +327,14 @@ var init_codex_client = __esm({
421
327
  CodexError: CodexError2,
422
328
  ConfigurationError: ConfigurationError2
423
329
  } = await import('@fractary/codex');
424
- const { readYamlConfig: readYamlConfig2 } = await Promise.resolve().then(() => (init_migrate_config(), migrate_config_exports));
425
- const { resolveEnvVarsInConfig: resolveEnvVarsInConfig2 } = await Promise.resolve().then(() => (init_config_types(), config_types_exports));
330
+ const { readYamlConfig } = await Promise.resolve().then(() => (init_migrate_config(), migrate_config_exports));
331
+ const { resolveEnvVarsInConfig } = await Promise.resolve().then(() => (init_config_types(), config_types_exports));
426
332
  try {
427
333
  const configPath = path4__namespace.join(process.cwd(), ".fractary", "config.yaml");
428
334
  let config;
429
335
  try {
430
- config = await readYamlConfig2(configPath);
431
- config = resolveEnvVarsInConfig2(config);
336
+ config = await readYamlConfig(configPath);
337
+ config = resolveEnvVarsInConfig(config);
432
338
  } catch (error) {
433
339
  throw new ConfigurationError2(
434
340
  `Failed to load configuration from ${configPath}. Run "fractary codex init" to create a configuration.`
@@ -917,7 +823,7 @@ function getDefaultUnifiedConfig(organization, project, codexRepo) {
917
823
  const sanitizedProject = sanitizeForS3BucketName(project);
918
824
  return {
919
825
  file: {
920
- schema_version: "2.0",
826
+ schema_version: codex.CONFIG_SCHEMA_VERSION,
921
827
  sources: {
922
828
  specs: {
923
829
  type: "s3",
@@ -954,18 +860,23 @@ function getDefaultUnifiedConfig(organization, project, codexRepo) {
954
860
  }
955
861
  },
956
862
  codex: {
957
- schema_version: "2.0",
863
+ schema_version: codex.CONFIG_SCHEMA_VERSION,
958
864
  organization,
959
865
  project,
960
866
  codex_repo: codexRepo,
961
- dependencies: {}
867
+ remotes: {
868
+ // The codex repository - uses same token as git operations
869
+ [`${organization}/${codexRepo}`]: {
870
+ token: "${GITHUB_TOKEN}"
871
+ }
872
+ }
962
873
  }
963
874
  };
964
875
  }
965
876
  async function readUnifiedConfig(configPath) {
966
877
  try {
967
878
  const content = await fs__namespace.readFile(configPath, "utf-8");
968
- const config = yaml__namespace.load(content);
879
+ const config = yaml2__namespace.load(content);
969
880
  return config;
970
881
  } catch (error) {
971
882
  if (error.code === "ENOENT") {
@@ -977,7 +888,7 @@ async function readUnifiedConfig(configPath) {
977
888
  async function writeUnifiedConfig(config, outputPath) {
978
889
  const dir = path4__namespace.dirname(outputPath);
979
890
  await fs__namespace.mkdir(dir, { recursive: true });
980
- const yamlContent = yaml__namespace.dump(config, {
891
+ const yamlContent = yaml2__namespace.dump(config, {
981
892
  indent: 2,
982
893
  lineWidth: 120,
983
894
  noRefs: true,
@@ -989,7 +900,7 @@ function mergeUnifiedConfigs(existing, updates) {
989
900
  const merged = {};
990
901
  if (updates.file || existing.file) {
991
902
  merged.file = {
992
- schema_version: updates.file?.schema_version || existing.file?.schema_version || "2.0",
903
+ schema_version: updates.file?.schema_version || existing.file?.schema_version || codex.CONFIG_SCHEMA_VERSION,
993
904
  sources: {
994
905
  ...existing.file?.sources || {},
995
906
  ...updates.file?.sources || {}
@@ -998,13 +909,13 @@ function mergeUnifiedConfigs(existing, updates) {
998
909
  }
999
910
  if (updates.codex || existing.codex) {
1000
911
  merged.codex = {
1001
- schema_version: updates.codex?.schema_version || existing.codex?.schema_version || "2.0",
912
+ schema_version: updates.codex?.schema_version || existing.codex?.schema_version || codex.CONFIG_SCHEMA_VERSION,
1002
913
  organization: updates.codex?.organization || existing.codex?.organization || "default",
1003
914
  project: updates.codex?.project || existing.codex?.project || "default",
1004
915
  codex_repo: updates.codex?.codex_repo || existing.codex?.codex_repo || "",
1005
- dependencies: {
1006
- ...existing.codex?.dependencies || {},
1007
- ...updates.codex?.dependencies || {}
916
+ remotes: {
917
+ ...existing.codex?.remotes || {},
918
+ ...updates.codex?.remotes || {}
1008
919
  }
1009
920
  };
1010
921
  }
@@ -1218,9 +1129,64 @@ async function fileExists(filePath) {
1218
1129
  return false;
1219
1130
  }
1220
1131
  }
1132
+ async function installMcpServer(projectRoot, configPath = ".fractary/config.yaml", options = {}) {
1133
+ const mcpJsonPath = path4__namespace.join(projectRoot, ".mcp.json");
1134
+ const { backup = true } = options;
1135
+ let existingConfig = { mcpServers: {} };
1136
+ let backupPath;
1137
+ let migrated = false;
1138
+ if (await fileExists(mcpJsonPath)) {
1139
+ try {
1140
+ const content = await fs__namespace.readFile(mcpJsonPath, "utf-8");
1141
+ existingConfig = JSON.parse(content);
1142
+ if (backup) {
1143
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "").slice(0, 18);
1144
+ const suffix = Math.random().toString(36).substring(2, 6);
1145
+ backupPath = `${mcpJsonPath}.backup.${timestamp}-${suffix}`;
1146
+ await fs__namespace.writeFile(backupPath, content);
1147
+ }
1148
+ } catch {
1149
+ console.log(chalk7__default.default.yellow("\u26A0 Warning: .mcp.json contains invalid JSON, starting fresh"));
1150
+ existingConfig = { mcpServers: {} };
1151
+ }
1152
+ }
1153
+ if (!existingConfig.mcpServers) {
1154
+ existingConfig.mcpServers = {};
1155
+ }
1156
+ const existing = existingConfig.mcpServers["fractary-codex"];
1157
+ if (existing) {
1158
+ const existingCommand = existing.command;
1159
+ const existingArgs = existing.args || [];
1160
+ if (existingCommand === "npx" && existingArgs.includes("@fractary/codex-mcp")) {
1161
+ return {
1162
+ installed: false,
1163
+ migrated: false,
1164
+ alreadyInstalled: true,
1165
+ backupPath
1166
+ };
1167
+ }
1168
+ if (existingCommand === "node" || existingArgs.includes("@fractary/codex")) {
1169
+ migrated = true;
1170
+ }
1171
+ }
1172
+ existingConfig.mcpServers["fractary-codex"] = {
1173
+ command: "npx",
1174
+ args: ["-y", "@fractary/codex-mcp", "--config", configPath]
1175
+ };
1176
+ await fs__namespace.writeFile(
1177
+ mcpJsonPath,
1178
+ JSON.stringify(existingConfig, null, 2) + "\n"
1179
+ );
1180
+ return {
1181
+ installed: true,
1182
+ migrated,
1183
+ alreadyInstalled: false,
1184
+ backupPath
1185
+ };
1186
+ }
1221
1187
  function initCommand() {
1222
1188
  const cmd = new commander.Command("init");
1223
- 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) => {
1189
+ 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) => {
1224
1190
  try {
1225
1191
  console.log(chalk7__default.default.blue("Initializing unified Fractary configuration...\n"));
1226
1192
  let org = options.org;
@@ -1332,6 +1298,20 @@ function initCommand() {
1332
1298
  } else if (result.merged) {
1333
1299
  console.log(chalk7__default.default.green("\u2713"), chalk7__default.default.dim(".fractary/config.yaml (merged with existing)"));
1334
1300
  }
1301
+ if (options.mcp !== false) {
1302
+ console.log("\nConfiguring MCP server...");
1303
+ const mcpResult = await installMcpServer(process.cwd(), ".fractary/config.yaml");
1304
+ if (mcpResult.alreadyInstalled) {
1305
+ console.log(chalk7__default.default.green("\u2713"), chalk7__default.default.dim(".mcp.json (already configured)"));
1306
+ } else if (mcpResult.migrated) {
1307
+ console.log(chalk7__default.default.green("\u2713"), chalk7__default.default.dim(".mcp.json (migrated from old format)"));
1308
+ if (mcpResult.backupPath) {
1309
+ console.log(chalk7__default.default.dim(` Backup: ${path4__namespace.basename(mcpResult.backupPath)}`));
1310
+ }
1311
+ } else if (mcpResult.installed) {
1312
+ console.log(chalk7__default.default.green("\u2713"), chalk7__default.default.dim(".mcp.json (created)"));
1313
+ }
1314
+ }
1335
1315
  console.log(chalk7__default.default.green("\n\u2713 Unified configuration initialized successfully!\n"));
1336
1316
  console.log(chalk7__default.default.bold("Configuration:"));
1337
1317
  console.log(chalk7__default.default.dim(` Organization: ${org}`));
@@ -1343,18 +1323,19 @@ function initCommand() {
1343
1323
  console.log(chalk7__default.default.dim(" - logs: .fractary/logs/ \u2192 S3"));
1344
1324
  console.log(chalk7__default.default.bold("\nCodex plugin:"));
1345
1325
  console.log(chalk7__default.default.dim(" - Cache: .fractary/codex/cache/"));
1346
- console.log(chalk7__default.default.dim(" - Dependencies: (none configured)"));
1326
+ console.log(chalk7__default.default.dim(" - MCP Server: @fractary/codex-mcp (via npx)"));
1327
+ console.log(chalk7__default.default.dim(" - Remotes: codex repo configured"));
1347
1328
  console.log(chalk7__default.default.bold("\nGit Authentication:"));
1348
1329
  console.log(chalk7__default.default.dim(" Codex sync uses your existing git credentials."));
1349
1330
  console.log(chalk7__default.default.dim(" Ensure you have access to the codex repository:"));
1350
1331
  console.log(chalk7__default.default.dim(` gh repo view ${org}/${codexRepo}`));
1351
1332
  console.log(chalk7__default.default.dim(" Or set GITHUB_TOKEN environment variable."));
1352
1333
  console.log(chalk7__default.default.bold("\nNext steps:"));
1353
- console.log(chalk7__default.default.dim(" 1. Verify codex repository access: gh repo view " + org + "/" + codexRepo));
1354
- console.log(chalk7__default.default.dim(" 2. Configure AWS credentials for S3 access (if using file plugin)"));
1355
- console.log(chalk7__default.default.dim(" 3. Edit .fractary/config.yaml to add external project dependencies"));
1356
- console.log(chalk7__default.default.dim(" 4. Access current project files: codex://specs/SPEC-001.md"));
1357
- console.log(chalk7__default.default.dim(" 5. Access external projects: codex://org/project/docs/README.md"));
1334
+ console.log(chalk7__default.default.dim(" 1. Restart Claude Code to load the MCP server"));
1335
+ console.log(chalk7__default.default.dim(" 2. Verify codex repository access: gh repo view " + org + "/" + codexRepo));
1336
+ console.log(chalk7__default.default.dim(" 3. Configure AWS credentials for S3 access (if using file plugin)"));
1337
+ console.log(chalk7__default.default.dim(" 4. Edit .fractary/config.yaml to add external project remotes"));
1338
+ console.log(chalk7__default.default.dim(" 5. Reference docs via codex:// URIs (auto-fetched by MCP)"));
1358
1339
  } catch (error) {
1359
1340
  console.error(chalk7__default.default.red("Error:"), error.message);
1360
1341
  process.exit(1);
@@ -1572,7 +1553,7 @@ async function checkConfiguration() {
1572
1553
  details: 'Run "fractary codex init" to create configuration'
1573
1554
  };
1574
1555
  }
1575
- const config = await readYamlConfig(configPath);
1556
+ const config = await codex.readCodexConfig(configPath);
1576
1557
  if (!config.organization) {
1577
1558
  return {
1578
1559
  name: "Configuration",
@@ -1663,7 +1644,7 @@ async function checkCache() {
1663
1644
  async function checkStorage() {
1664
1645
  const configPath = path4__namespace.join(process.cwd(), ".fractary", "config.yaml");
1665
1646
  try {
1666
- const config = await readYamlConfig(configPath);
1647
+ const config = await codex.readCodexConfig(configPath);
1667
1648
  const providers = config.storage || [];
1668
1649
  if (providers.length === 0) {
1669
1650
  return {
@@ -1822,7 +1803,7 @@ function syncCommand() {
1822
1803
  const configPath = path4__namespace.join(process.cwd(), ".fractary", "config.yaml");
1823
1804
  let config;
1824
1805
  try {
1825
- config = await readYamlConfig(configPath);
1806
+ config = await codex.readCodexConfig(configPath);
1826
1807
  } catch (error) {
1827
1808
  console.error(chalk7__default.default.red("Error:"), "Codex not initialized.");
1828
1809
  console.log(chalk7__default.default.dim('Run "fractary codex init" first.'));
@@ -2390,7 +2371,7 @@ function typesAddCommand() {
2390
2371
  process.exit(1);
2391
2372
  }
2392
2373
  const configPath = path4__namespace.join(process.cwd(), ".fractary", "config.yaml");
2393
- const config = await readYamlConfig(configPath);
2374
+ const config = await codex.readCodexConfig(configPath);
2394
2375
  if (!config.types) {
2395
2376
  config.types = { custom: {} };
2396
2377
  }
@@ -2459,7 +2440,7 @@ function typesRemoveCommand() {
2459
2440
  }
2460
2441
  const typeInfo = registry.get(name);
2461
2442
  const configPath = path4__namespace.join(process.cwd(), ".fractary", "config.yaml");
2462
- const config = await readYamlConfig(configPath);
2443
+ const config = await codex.readCodexConfig(configPath);
2463
2444
  if (!config.types?.custom?.[name]) {
2464
2445
  console.error(chalk7__default.default.red("Error:"), `Custom type "${name}" not found in configuration.`);
2465
2446
  process.exit(1);