@fractary/codex 0.12.0 → 0.12.4

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/index.cjs CHANGED
@@ -4,7 +4,7 @@ var micromatch3 = require('micromatch');
4
4
  var path3 = require('path');
5
5
  var child_process = require('child_process');
6
6
  var zod = require('zod');
7
- var yaml = require('js-yaml');
7
+ var yaml2 = require('js-yaml');
8
8
  var fs3 = require('fs/promises');
9
9
  var util = require('util');
10
10
 
@@ -30,7 +30,7 @@ function _interopNamespace(e) {
30
30
 
31
31
  var micromatch3__default = /*#__PURE__*/_interopDefault(micromatch3);
32
32
  var path3__namespace = /*#__PURE__*/_interopNamespace(path3);
33
- var yaml__default = /*#__PURE__*/_interopDefault(yaml);
33
+ var yaml2__namespace = /*#__PURE__*/_interopNamespace(yaml2);
34
34
  var fs3__namespace = /*#__PURE__*/_interopNamespace(fs3);
35
35
 
36
36
  var __defProp = Object.defineProperty;
@@ -923,12 +923,24 @@ var DirectionalSyncConfigSchema = zod.z.object({
923
923
  /** Patterns to exclude (optional) */
924
924
  exclude: zod.z.array(zod.z.string()).optional()
925
925
  });
926
+ var FromCodexSyncConfigSchema = DirectionalSyncConfigSchema.refine(
927
+ (config) => {
928
+ const includeValid = config.include.every(
929
+ (pattern) => pattern.startsWith("codex://")
930
+ );
931
+ const excludeValid = !config.exclude || config.exclude.every((pattern) => pattern.startsWith("codex://"));
932
+ return includeValid && excludeValid;
933
+ },
934
+ {
935
+ message: 'from_codex patterns must use codex:// URI format (e.g., "codex://{org}/{codex_repo}/docs/**"). Plain paths like "docs/**" are not valid for from_codex.'
936
+ }
937
+ );
926
938
  var DirectionalSyncSchema = zod.z.object({
927
939
  // New format (v0.7.0+) - Recommended
928
- // Patterns for files to push from this project to codex
940
+ // Patterns for files to push from this project to codex (plain paths)
929
941
  to_codex: DirectionalSyncConfigSchema.optional(),
930
- // Patterns for files to pull from codex to this project
931
- from_codex: DirectionalSyncConfigSchema.optional(),
942
+ // Patterns for files to pull from codex to this project (codex:// URIs required)
943
+ from_codex: FromCodexSyncConfigSchema.optional(),
932
944
  // Global exclude patterns (applied to both directions)
933
945
  exclude: zod.z.array(zod.z.string()).optional(),
934
946
  // Legacy format (deprecated, backward compatible)
@@ -1046,7 +1058,7 @@ function parseMetadata(content, options = {}) {
1046
1058
  const rawFrontmatter = frontmatterMatch[1];
1047
1059
  const documentContent = frontmatterMatch[2];
1048
1060
  try {
1049
- const parsed = yaml__default.default.load(rawFrontmatter);
1061
+ const parsed = yaml2__namespace.default.load(rawFrontmatter);
1050
1062
  const normalized = normalizeLegacyMetadata(parsed);
1051
1063
  const metadata = strict ? MetadataSchema.parse(normalized) : MetadataSchema.safeParse(normalized).data || {};
1052
1064
  return {
@@ -3954,17 +3966,17 @@ var SyncManager = class {
3954
3966
  if (file.operation === "create" || file.operation === "update") {
3955
3967
  const sourcePath = `${plan.source}/${file.path}`;
3956
3968
  const targetPath = `${plan.target}/${file.path}`;
3957
- const fs5 = await import('fs/promises');
3969
+ const fs6 = await import('fs/promises');
3958
3970
  const path7 = await import('path');
3959
3971
  const targetDir = path7.dirname(targetPath);
3960
- await fs5.mkdir(targetDir, { recursive: true });
3961
- await fs5.copyFile(sourcePath, targetPath);
3972
+ await fs6.mkdir(targetDir, { recursive: true });
3973
+ await fs6.copyFile(sourcePath, targetPath);
3962
3974
  synced++;
3963
3975
  } else if (file.operation === "delete") {
3964
3976
  const targetPath = `${plan.target}/${file.path}`;
3965
- const fs5 = await import('fs/promises');
3977
+ const fs6 = await import('fs/promises');
3966
3978
  try {
3967
- await fs5.unlink(targetPath);
3979
+ await fs6.unlink(targetPath);
3968
3980
  synced++;
3969
3981
  } catch (error) {
3970
3982
  if (error.code !== "ENOENT") {
@@ -4969,6 +4981,176 @@ function generateReferenceMigrationSummary(results) {
4969
4981
  return lines.join("\n");
4970
4982
  }
4971
4983
 
4984
+ // src/core/env/index.ts
4985
+ function expandEnvVars(value, options = {}) {
4986
+ const env = options.env ?? process.env;
4987
+ return value.replace(/\$\{([^}]+)\}/g, (match, varName) => {
4988
+ const envValue = env[varName];
4989
+ if (envValue === void 0) {
4990
+ if (options.warnOnMissing) {
4991
+ console.warn(`Warning: Environment variable ${varName} is not set`);
4992
+ }
4993
+ if (options.onMissing) {
4994
+ options.onMissing(varName);
4995
+ }
4996
+ return match;
4997
+ }
4998
+ return envValue;
4999
+ });
5000
+ }
5001
+ function expandEnvVarsInConfig(config, options = {}) {
5002
+ if (typeof config === "string") {
5003
+ return expandEnvVars(config, options);
5004
+ }
5005
+ if (Array.isArray(config)) {
5006
+ return config.map((item) => expandEnvVarsInConfig(item, options));
5007
+ }
5008
+ if (config !== null && typeof config === "object") {
5009
+ const result = {};
5010
+ for (const [key, value] of Object.entries(config)) {
5011
+ result[key] = expandEnvVarsInConfig(value, options);
5012
+ }
5013
+ return result;
5014
+ }
5015
+ return config;
5016
+ }
5017
+ function hasEnvVars(value) {
5018
+ return /\$\{[^}]+\}/.test(value);
5019
+ }
5020
+ function extractEnvVarNames(value) {
5021
+ const matches = value.matchAll(/\$\{([^}]+)\}/g);
5022
+ const names = [];
5023
+ for (const match of matches) {
5024
+ if (match[1]) {
5025
+ names.push(match[1]);
5026
+ }
5027
+ }
5028
+ return names;
5029
+ }
5030
+ async function readCodexConfig(configPath, options = {}) {
5031
+ const content = await fs3__namespace.readFile(configPath, "utf-8");
5032
+ const rawConfig = yaml2__namespace.load(content);
5033
+ let config;
5034
+ if (rawConfig?.codex && typeof rawConfig.codex === "object") {
5035
+ config = rawConfig.codex;
5036
+ } else {
5037
+ config = rawConfig;
5038
+ }
5039
+ if (!config.organization) {
5040
+ throw new Error("Invalid config: organization is required");
5041
+ }
5042
+ if (options.expandEnv !== false) {
5043
+ const envOptions = {
5044
+ env: options.env,
5045
+ warnOnMissing: options.warnOnMissingEnv
5046
+ };
5047
+ config = expandEnvVarsInConfig(config, envOptions);
5048
+ }
5049
+ return config;
5050
+ }
5051
+ async function readUnifiedConfig(configPath, options = {}) {
5052
+ const content = await fs3__namespace.readFile(configPath, "utf-8");
5053
+ let config = yaml2__namespace.load(content);
5054
+ if (options.expandEnv !== false) {
5055
+ const envOptions = {
5056
+ env: options.env,
5057
+ warnOnMissing: options.warnOnMissingEnv
5058
+ };
5059
+ config = expandEnvVarsInConfig(config, envOptions);
5060
+ }
5061
+ return config;
5062
+ }
5063
+ function isUnifiedConfig(config) {
5064
+ if (config === null || typeof config !== "object") {
5065
+ return false;
5066
+ }
5067
+ const maybeUnified = config;
5068
+ return "codex" in maybeUnified && maybeUnified.codex !== null && typeof maybeUnified.codex === "object";
5069
+ }
5070
+
5071
+ // src/core/utils/index.ts
5072
+ var DURATION_MULTIPLIERS = {
5073
+ s: 1,
5074
+ // seconds
5075
+ m: 60,
5076
+ // minutes
5077
+ h: 3600,
5078
+ // hours
5079
+ d: 86400,
5080
+ // days
5081
+ w: 604800,
5082
+ // weeks (7 days)
5083
+ M: 2592e3,
5084
+ // months (30 days)
5085
+ y: 31536e3
5086
+ // years (365 days)
5087
+ };
5088
+ var SIZE_MULTIPLIERS = {
5089
+ B: 1,
5090
+ KB: 1024,
5091
+ MB: 1024 * 1024,
5092
+ GB: 1024 * 1024 * 1024,
5093
+ TB: 1024 * 1024 * 1024 * 1024
5094
+ };
5095
+ function parseDuration(duration) {
5096
+ if (typeof duration === "number") {
5097
+ return duration;
5098
+ }
5099
+ const match = duration.match(/^(\d+(?:\.\d+)?)\s*([smhdwMy])$/);
5100
+ if (!match || !match[1] || !match[2]) {
5101
+ throw new Error(`Invalid duration format: ${duration}. Use format like "1h", "7d", "1M"`);
5102
+ }
5103
+ const valueStr = match[1];
5104
+ const unit = match[2];
5105
+ const value = parseFloat(valueStr);
5106
+ const multiplier = DURATION_MULTIPLIERS[unit];
5107
+ if (multiplier === void 0) {
5108
+ throw new Error(`Unknown duration unit: ${unit}`);
5109
+ }
5110
+ return Math.round(value * multiplier);
5111
+ }
5112
+ function parseSize(size) {
5113
+ if (typeof size === "number") {
5114
+ return size;
5115
+ }
5116
+ const match = size.match(/^(\d+(?:\.\d+)?)\s*(B|KB|MB|GB|TB)$/i);
5117
+ if (!match || !match[1] || !match[2]) {
5118
+ throw new Error(`Invalid size format: ${size}. Use format like "100MB", "1GB"`);
5119
+ }
5120
+ const valueStr = match[1];
5121
+ const unit = match[2];
5122
+ const value = parseFloat(valueStr);
5123
+ const multiplier = SIZE_MULTIPLIERS[unit.toUpperCase()];
5124
+ if (multiplier === void 0) {
5125
+ throw new Error(`Unknown size unit: ${unit}`);
5126
+ }
5127
+ return Math.round(value * multiplier);
5128
+ }
5129
+ function formatBytes2(bytes) {
5130
+ if (bytes < 1024) return `${bytes} B`;
5131
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
5132
+ if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
5133
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
5134
+ }
5135
+ function formatDuration(ms) {
5136
+ if (ms < 1e3) return `${ms}ms`;
5137
+ if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
5138
+ if (ms < 36e5) return `${(ms / 6e4).toFixed(1)}m`;
5139
+ return `${(ms / 36e5).toFixed(1)}h`;
5140
+ }
5141
+ function formatSeconds(seconds) {
5142
+ if (seconds < 60) return `${seconds}s`;
5143
+ if (seconds < 3600) return `${(seconds / 60).toFixed(1)}m`;
5144
+ if (seconds < 86400) return `${(seconds / 3600).toFixed(1)}h`;
5145
+ return `${(seconds / 86400).toFixed(1)}d`;
5146
+ }
5147
+ function isValidDuration(value) {
5148
+ return /^\d+(?:\.\d+)?\s*[smhdwMy]$/.test(value);
5149
+ }
5150
+ function isValidSize(value) {
5151
+ return /^\d+(?:\.\d+)?\s*(B|KB|MB|GB|TB)$/i.test(value);
5152
+ }
5153
+
4972
5154
  exports.AutoSyncPatternSchema = AutoSyncPatternSchema;
4973
5155
  exports.BUILT_IN_TYPES = BUILT_IN_TYPES;
4974
5156
  exports.CODEX_URI_PREFIX = CODEX_URI_PREFIX;
@@ -5034,7 +5216,10 @@ exports.evaluatePaths = evaluatePaths;
5034
5216
  exports.evaluatePatterns = evaluatePatterns;
5035
5217
  exports.evaluatePermission = evaluatePermission;
5036
5218
  exports.evaluatePermissions = evaluatePermissions;
5219
+ exports.expandEnvVars = expandEnvVars;
5220
+ exports.expandEnvVarsInConfig = expandEnvVarsInConfig;
5037
5221
  exports.extendType = extendType;
5222
+ exports.extractEnvVarNames = extractEnvVarNames;
5038
5223
  exports.extractOrgFromRepoName = extractOrgFromRepoName;
5039
5224
  exports.extractRawFrontmatter = extractRawFrontmatter;
5040
5225
  exports.filterByPatterns = filterByPatterns;
@@ -5042,7 +5227,10 @@ exports.filterByPermission = filterByPermission;
5042
5227
  exports.filterPlanOperations = filterPlanOperations;
5043
5228
  exports.filterSyncablePaths = filterSyncablePaths;
5044
5229
  exports.findLegacyReferences = findLegacyReferences;
5230
+ exports.formatBytes = formatBytes2;
5231
+ exports.formatDuration = formatDuration;
5045
5232
  exports.formatPlanSummary = formatPlanSummary;
5233
+ exports.formatSeconds = formatSeconds;
5046
5234
  exports.generateMigrationReport = generateMigrationReport;
5047
5235
  exports.generateReferenceMigrationSummary = generateReferenceMigrationSummary;
5048
5236
  exports.getBuiltInType = getBuiltInType;
@@ -5066,6 +5254,7 @@ exports.getRelativeCachePath = getRelativeCachePath;
5066
5254
  exports.getRemainingTtl = getRemainingTtl;
5067
5255
  exports.getTargetRepos = getTargetRepos;
5068
5256
  exports.hasContentChanged = hasContentChanged;
5257
+ exports.hasEnvVars = hasEnvVars;
5069
5258
  exports.hasFrontmatter = hasFrontmatter;
5070
5259
  exports.hasLegacyReferences = hasLegacyReferences;
5071
5260
  exports.hasPermissionLevel = hasPermission;
@@ -5077,6 +5266,9 @@ exports.isLegacyConfig = isLegacyConfig;
5077
5266
  exports.isLegacyReference = isLegacyReference;
5078
5267
  exports.isModernConfig = isModernConfig;
5079
5268
  exports.isPermissionAllowed = isAllowed;
5269
+ exports.isUnifiedConfig = isUnifiedConfig;
5270
+ exports.isValidDuration = isValidDuration;
5271
+ exports.isValidSize = isValidSize;
5080
5272
  exports.isValidUri = isValidUri;
5081
5273
  exports.levelGrants = levelGrants;
5082
5274
  exports.loadConfig = loadConfig;
@@ -5092,9 +5284,13 @@ exports.migrateFileReferences = migrateFileReferences;
5092
5284
  exports.minLevel = minLevel;
5093
5285
  exports.needsMigration = needsMigration;
5094
5286
  exports.parseCustomDestination = parseCustomDestination;
5287
+ exports.parseDuration = parseDuration;
5095
5288
  exports.parseMetadata = parseMetadata;
5096
5289
  exports.parseReference = parseReference;
5290
+ exports.parseSize = parseSize;
5097
5291
  exports.parseTtl = parseTtl;
5292
+ exports.readCodexConfig = readCodexConfig;
5293
+ exports.readUnifiedConfig = readUnifiedConfig;
5098
5294
  exports.resolveOrganization = resolveOrganization;
5099
5295
  exports.resolveReference = resolveReference;
5100
5296
  exports.resolveReferences = resolveReferences;