@fractary/codex 0.4.0 → 0.5.0

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.d.cts CHANGED
@@ -408,6 +408,22 @@ declare const CodexConfigSchema: z.ZodObject<{
408
408
  defaultInclude?: string[] | undefined;
409
409
  defaultExclude?: string[] | undefined;
410
410
  }>>;
411
+ sync: z.ZodOptional<z.ZodObject<{
412
+ to_codex: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
413
+ from_codex: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
414
+ default_to_codex: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
415
+ default_from_codex: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
416
+ }, "strip", z.ZodTypeAny, {
417
+ to_codex?: string[] | undefined;
418
+ from_codex?: string[] | undefined;
419
+ default_to_codex?: string[] | undefined;
420
+ default_from_codex?: string[] | undefined;
421
+ }, {
422
+ to_codex?: string[] | undefined;
423
+ from_codex?: string[] | undefined;
424
+ default_to_codex?: string[] | undefined;
425
+ default_from_codex?: string[] | undefined;
426
+ }>>;
411
427
  }, "strict", z.ZodTypeAny, {
412
428
  organizationSlug: string;
413
429
  directories?: {
@@ -427,6 +443,12 @@ declare const CodexConfigSchema: z.ZodObject<{
427
443
  defaultInclude?: string[] | undefined;
428
444
  defaultExclude?: string[] | undefined;
429
445
  } | undefined;
446
+ sync?: {
447
+ to_codex?: string[] | undefined;
448
+ from_codex?: string[] | undefined;
449
+ default_to_codex?: string[] | undefined;
450
+ default_from_codex?: string[] | undefined;
451
+ } | undefined;
430
452
  }, {
431
453
  organizationSlug: string;
432
454
  directories?: {
@@ -446,6 +468,12 @@ declare const CodexConfigSchema: z.ZodObject<{
446
468
  defaultInclude?: string[] | undefined;
447
469
  defaultExclude?: string[] | undefined;
448
470
  } | undefined;
471
+ sync?: {
472
+ to_codex?: string[] | undefined;
473
+ from_codex?: string[] | undefined;
474
+ default_to_codex?: string[] | undefined;
475
+ default_from_codex?: string[] | undefined;
476
+ } | undefined;
449
477
  }>;
450
478
  type CodexConfig = z.infer<typeof CodexConfigSchema>;
451
479
 
@@ -848,6 +876,11 @@ interface SyncConfig {
848
876
  defaultExcludes: string[];
849
877
  deleteOrphans: boolean;
850
878
  conflictStrategy: 'newest' | 'local' | 'remote' | 'manual';
879
+ to_codex?: string[];
880
+ from_codex?: string[];
881
+ default_to_codex?: string[];
882
+ default_from_codex?: string[];
883
+ exclude?: string[];
851
884
  }
852
885
  declare const DEFAULT_SYNC_CONFIG: SyncConfig;
853
886
 
package/dist/index.d.ts CHANGED
@@ -408,6 +408,22 @@ declare const CodexConfigSchema: z.ZodObject<{
408
408
  defaultInclude?: string[] | undefined;
409
409
  defaultExclude?: string[] | undefined;
410
410
  }>>;
411
+ sync: z.ZodOptional<z.ZodObject<{
412
+ to_codex: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
413
+ from_codex: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
414
+ default_to_codex: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
415
+ default_from_codex: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
416
+ }, "strip", z.ZodTypeAny, {
417
+ to_codex?: string[] | undefined;
418
+ from_codex?: string[] | undefined;
419
+ default_to_codex?: string[] | undefined;
420
+ default_from_codex?: string[] | undefined;
421
+ }, {
422
+ to_codex?: string[] | undefined;
423
+ from_codex?: string[] | undefined;
424
+ default_to_codex?: string[] | undefined;
425
+ default_from_codex?: string[] | undefined;
426
+ }>>;
411
427
  }, "strict", z.ZodTypeAny, {
412
428
  organizationSlug: string;
413
429
  directories?: {
@@ -427,6 +443,12 @@ declare const CodexConfigSchema: z.ZodObject<{
427
443
  defaultInclude?: string[] | undefined;
428
444
  defaultExclude?: string[] | undefined;
429
445
  } | undefined;
446
+ sync?: {
447
+ to_codex?: string[] | undefined;
448
+ from_codex?: string[] | undefined;
449
+ default_to_codex?: string[] | undefined;
450
+ default_from_codex?: string[] | undefined;
451
+ } | undefined;
430
452
  }, {
431
453
  organizationSlug: string;
432
454
  directories?: {
@@ -446,6 +468,12 @@ declare const CodexConfigSchema: z.ZodObject<{
446
468
  defaultInclude?: string[] | undefined;
447
469
  defaultExclude?: string[] | undefined;
448
470
  } | undefined;
471
+ sync?: {
472
+ to_codex?: string[] | undefined;
473
+ from_codex?: string[] | undefined;
474
+ default_to_codex?: string[] | undefined;
475
+ default_from_codex?: string[] | undefined;
476
+ } | undefined;
449
477
  }>;
450
478
  type CodexConfig = z.infer<typeof CodexConfigSchema>;
451
479
 
@@ -848,6 +876,11 @@ interface SyncConfig {
848
876
  defaultExcludes: string[];
849
877
  deleteOrphans: boolean;
850
878
  conflictStrategy: 'newest' | 'local' | 'remote' | 'manual';
879
+ to_codex?: string[];
880
+ from_codex?: string[];
881
+ default_to_codex?: string[];
882
+ default_from_codex?: string[];
883
+ exclude?: string[];
851
884
  }
852
885
  declare const DEFAULT_SYNC_CONFIG: SyncConfig;
853
886
 
package/dist/index.js CHANGED
@@ -1,10 +1,110 @@
1
+ import micromatch3 from 'micromatch';
1
2
  import path3 from 'path';
2
3
  import { execSync } from 'child_process';
3
- import micromatch3 from 'micromatch';
4
4
  import { z } from 'zod';
5
5
  import yaml from 'js-yaml';
6
6
  import fs2 from 'fs/promises';
7
7
 
8
+ var __defProp = Object.defineProperty;
9
+ var __getOwnPropNames = Object.getOwnPropertyNames;
10
+ var __esm = (fn, res) => function __init() {
11
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
12
+ };
13
+ var __export = (target, all) => {
14
+ for (var name in all)
15
+ __defProp(target, name, { get: all[name], enumerable: true });
16
+ };
17
+ function matchPattern(pattern, value) {
18
+ if (pattern === value) return true;
19
+ return micromatch3.isMatch(value, pattern);
20
+ }
21
+ function matchAnyPattern(patterns, value) {
22
+ if (patterns.length === 1 && patterns[0] === "*") {
23
+ return true;
24
+ }
25
+ if (patterns.length === 0) {
26
+ return false;
27
+ }
28
+ return patterns.some((pattern) => matchPattern(pattern, value));
29
+ }
30
+ function filterByPatterns(patterns, values) {
31
+ return values.filter((value) => matchAnyPattern(patterns, value));
32
+ }
33
+ function evaluatePatterns(options) {
34
+ const { value, include = [], exclude = [] } = options;
35
+ if (exclude.length > 0 && matchAnyPattern(exclude, value)) {
36
+ return false;
37
+ }
38
+ if (include.length === 0) {
39
+ return true;
40
+ }
41
+ return matchAnyPattern(include, value);
42
+ }
43
+ var init_matcher = __esm({
44
+ "src/core/patterns/matcher.ts"() {
45
+ }
46
+ });
47
+
48
+ // src/sync/directional-patterns.ts
49
+ var directional_patterns_exports = {};
50
+ __export(directional_patterns_exports, {
51
+ expandPlaceholders: () => expandPlaceholders,
52
+ extractProjectFromCodexPath: () => extractProjectFromCodexPath,
53
+ getRelativePath: () => getRelativePath,
54
+ matchFromCodexPattern: () => matchFromCodexPattern,
55
+ matchToCodexPattern: () => matchToCodexPattern
56
+ });
57
+ function matchToCodexPattern(filePath, patterns) {
58
+ if (!patterns || patterns.length === 0) {
59
+ return false;
60
+ }
61
+ return patterns.some((pattern) => matchPattern(pattern, filePath));
62
+ }
63
+ function matchFromCodexPattern(codexFilePath, patterns, targetProject) {
64
+ if (!patterns || patterns.length === 0) {
65
+ return false;
66
+ }
67
+ return patterns.some((pattern) => {
68
+ const projectSeparatorIndex = pattern.indexOf("/");
69
+ if (projectSeparatorIndex === -1) {
70
+ const fullPattern = `${targetProject}/${pattern}`;
71
+ return matchPattern(fullPattern, codexFilePath);
72
+ }
73
+ const firstSegment = pattern.substring(0, projectSeparatorIndex);
74
+ if (firstSegment.includes(".")) {
75
+ return matchPattern(pattern, codexFilePath);
76
+ } else {
77
+ const fullPattern = `${targetProject}/${pattern}`;
78
+ return matchPattern(fullPattern, codexFilePath);
79
+ }
80
+ });
81
+ }
82
+ function extractProjectFromCodexPath(codexFilePath) {
83
+ const firstSlashIndex = codexFilePath.indexOf("/");
84
+ if (firstSlashIndex === -1) {
85
+ return null;
86
+ }
87
+ return codexFilePath.substring(0, firstSlashIndex);
88
+ }
89
+ function getRelativePath(codexFilePath) {
90
+ const firstSlashIndex = codexFilePath.indexOf("/");
91
+ if (firstSlashIndex === -1) {
92
+ return null;
93
+ }
94
+ return codexFilePath.substring(firstSlashIndex + 1);
95
+ }
96
+ function expandPlaceholders(patterns, targetProject) {
97
+ if (!patterns) {
98
+ return patterns;
99
+ }
100
+ return patterns.map((pattern) => pattern.replace(/{project}/g, targetProject));
101
+ }
102
+ var init_directional_patterns = __esm({
103
+ "src/sync/directional-patterns.ts"() {
104
+ init_matcher();
105
+ }
106
+ });
107
+
8
108
  // src/errors/CodexError.ts
9
109
  var CodexError = class _CodexError extends Error {
10
110
  constructor(message, options) {
@@ -721,6 +821,16 @@ var SyncRulesSchema = z.object({
721
821
  defaultInclude: z.array(z.string()).optional(),
722
822
  defaultExclude: z.array(z.string()).optional()
723
823
  });
824
+ var DirectionalSyncSchema = z.object({
825
+ // Patterns for files to push from this project to codex
826
+ to_codex: z.array(z.string()).optional(),
827
+ // Patterns for files to pull from codex to this project
828
+ // Format: "project-name/path/pattern" or "project-name/**"
829
+ from_codex: z.array(z.string()).optional(),
830
+ // Org-level defaults (only in codex repository config)
831
+ default_to_codex: z.array(z.string()).optional(),
832
+ default_from_codex: z.array(z.string()).optional()
833
+ });
724
834
  var CodexConfigSchema = z.object({
725
835
  organizationSlug: z.string(),
726
836
  directories: z.object({
@@ -728,7 +838,9 @@ var CodexConfigSchema = z.object({
728
838
  target: z.string().optional(),
729
839
  systems: z.string().optional()
730
840
  }).optional(),
731
- rules: SyncRulesSchema.optional()
841
+ rules: SyncRulesSchema.optional(),
842
+ // Directional sync configuration
843
+ sync: DirectionalSyncSchema.optional()
732
844
  }).strict();
733
845
  function parseMetadata(content, options = {}) {
734
846
  const { strict = true, normalize = true } = options;
@@ -803,32 +915,9 @@ function extractRawFrontmatter(content) {
803
915
  const match = normalized.match(/^---\n([\s\S]*?)\n---\n/);
804
916
  return match && match[1] ? match[1] : null;
805
917
  }
806
- function matchPattern(pattern, value) {
807
- if (pattern === value) return true;
808
- return micromatch3.isMatch(value, pattern);
809
- }
810
- function matchAnyPattern(patterns, value) {
811
- if (patterns.length === 1 && patterns[0] === "*") {
812
- return true;
813
- }
814
- if (patterns.length === 0) {
815
- return false;
816
- }
817
- return patterns.some((pattern) => matchPattern(pattern, value));
818
- }
819
- function filterByPatterns(patterns, values) {
820
- return values.filter((value) => matchAnyPattern(patterns, value));
821
- }
822
- function evaluatePatterns(options) {
823
- const { value, include = [], exclude = [] } = options;
824
- if (exclude.length > 0 && matchAnyPattern(exclude, value)) {
825
- return false;
826
- }
827
- if (include.length === 0) {
828
- return true;
829
- }
830
- return matchAnyPattern(include, value);
831
- }
918
+
919
+ // src/core/patterns/index.ts
920
+ init_matcher();
832
921
 
833
922
  // src/core/config/organization.ts
834
923
  function resolveOrganization(options = {}) {
@@ -939,11 +1028,24 @@ function mergeConfigs(base, override) {
939
1028
  autoSyncPatterns: override.rules?.autoSyncPatterns ?? base.rules?.autoSyncPatterns,
940
1029
  defaultInclude: override.rules?.defaultInclude ?? base.rules?.defaultInclude,
941
1030
  defaultExclude: override.rules?.defaultExclude ?? base.rules?.defaultExclude
942
- }
1031
+ },
1032
+ // Only include sync if either base or override has sync config
1033
+ ...base.sync || override.sync ? {
1034
+ sync: {
1035
+ ...base.sync,
1036
+ ...override.sync,
1037
+ // Arrays are replaced, not merged
1038
+ to_codex: override.sync?.to_codex ?? base.sync?.to_codex,
1039
+ from_codex: override.sync?.from_codex ?? base.sync?.from_codex,
1040
+ default_to_codex: override.sync?.default_to_codex ?? base.sync?.default_to_codex,
1041
+ default_from_codex: override.sync?.default_from_codex ?? base.sync?.default_from_codex
1042
+ }
1043
+ } : {}
943
1044
  };
944
1045
  }
945
1046
 
946
1047
  // src/core/routing/evaluator.ts
1048
+ init_matcher();
947
1049
  function shouldSyncToRepo(options) {
948
1050
  const {
949
1051
  filePath,
@@ -2718,8 +2820,9 @@ async function scanCodexWithRouting(options) {
2718
2820
  rules,
2719
2821
  storage,
2720
2822
  skipNoFrontmatter = false,
2721
- maxFileSize = 10 * 1024 * 1024
2823
+ maxFileSize = 10 * 1024 * 1024,
2722
2824
  // 10MB default
2825
+ fromCodexPatterns
2723
2826
  } = options;
2724
2827
  const startTime = Date.now();
2725
2828
  const routedFiles = [];
@@ -2727,6 +2830,13 @@ async function scanCodexWithRouting(options) {
2727
2830
  const errors = [];
2728
2831
  let totalScanned = 0;
2729
2832
  let totalSkipped = 0;
2833
+ let expandedFromCodexPatterns = fromCodexPatterns;
2834
+ let matchFromCodexPattern2 = null;
2835
+ if (fromCodexPatterns && fromCodexPatterns.length > 0) {
2836
+ const module = await Promise.resolve().then(() => (init_directional_patterns(), directional_patterns_exports));
2837
+ matchFromCodexPattern2 = module.matchFromCodexPattern;
2838
+ expandedFromCodexPatterns = module.expandPlaceholders(fromCodexPatterns, targetProject);
2839
+ }
2730
2840
  const allFiles = await listAllFilesRecursive(codexDir);
2731
2841
  for (const filePath of allFiles) {
2732
2842
  totalScanned++;
@@ -2743,18 +2853,23 @@ async function scanCodexWithRouting(options) {
2743
2853
  }
2744
2854
  const content = await storage.readText(fullPath);
2745
2855
  const parseResult = parseMetadata(content, { strict: false });
2746
- if (skipNoFrontmatter && Object.keys(parseResult.metadata).length === 0) {
2856
+ if (!matchFromCodexPattern2 && skipNoFrontmatter && Object.keys(parseResult.metadata).length === 0) {
2747
2857
  totalSkipped++;
2748
2858
  continue;
2749
2859
  }
2750
2860
  const sourceProject = extractProjectFromPath(filePath, org);
2751
- const shouldSync = shouldSyncToRepo({
2752
- filePath,
2753
- fileMetadata: parseResult.metadata,
2754
- targetRepo: targetProject,
2755
- sourceRepo: sourceProject,
2756
- rules
2757
- });
2861
+ let shouldSync = false;
2862
+ if (matchFromCodexPattern2 && expandedFromCodexPatterns && expandedFromCodexPatterns.length > 0) {
2863
+ shouldSync = matchFromCodexPattern2(filePath, expandedFromCodexPatterns, targetProject);
2864
+ } else {
2865
+ shouldSync = shouldSyncToRepo({
2866
+ filePath,
2867
+ fileMetadata: parseResult.metadata,
2868
+ targetRepo: targetProject,
2869
+ sourceRepo: sourceProject,
2870
+ rules
2871
+ });
2872
+ }
2758
2873
  if (shouldSync) {
2759
2874
  const buffer = Buffer.from(content);
2760
2875
  const hash = calculateContentHash(buffer);
@@ -2905,7 +3020,16 @@ var SyncManager = class {
2905
3020
  * @param options - Sync options
2906
3021
  */
2907
3022
  async createPlan(_org, _project, sourceDir, targetFiles, options) {
2908
- const sourceFiles = await this.listLocalFiles(sourceDir);
3023
+ let sourceFiles = await this.listLocalFiles(sourceDir);
3024
+ if (options?.direction === "to-codex") {
3025
+ const toCodexPatterns = this.config.to_codex || this.config.default_to_codex;
3026
+ if (toCodexPatterns) {
3027
+ const { matchToCodexPattern: matchToCodexPattern2 } = await Promise.resolve().then(() => (init_directional_patterns(), directional_patterns_exports));
3028
+ sourceFiles = sourceFiles.filter(
3029
+ (file) => matchToCodexPattern2(file.path, toCodexPatterns)
3030
+ );
3031
+ }
3032
+ }
2909
3033
  const plan = createSyncPlan(
2910
3034
  sourceFiles,
2911
3035
  targetFiles,
@@ -2943,13 +3067,16 @@ var SyncManager = class {
2943
3067
  * ```
2944
3068
  */
2945
3069
  async createRoutingAwarePlan(org, project, codexDir, options) {
3070
+ const fromCodexPatterns = this.config.from_codex || this.config.default_from_codex;
2946
3071
  const routingScan = await scanCodexWithRouting({
2947
3072
  codexDir,
2948
3073
  targetProject: project,
2949
3074
  org,
2950
3075
  rules: void 0,
2951
3076
  // Use default routing rules (preventSelfSync, preventCodexSync, etc.)
2952
- storage: this.localStorage
3077
+ storage: this.localStorage,
3078
+ fromCodexPatterns
3079
+ // Use directional patterns if configured
2953
3080
  });
2954
3081
  const sourceFiles = routingScan.files.map((rf) => ({
2955
3082
  path: rf.path,
@@ -2958,7 +3085,15 @@ var SyncManager = class {
2958
3085
  hash: rf.hash
2959
3086
  }));
2960
3087
  const targetFiles = await this.listLocalFiles(process.cwd());
2961
- const plan = createSyncPlan(sourceFiles, targetFiles, options ?? {}, this.config);
3088
+ const planOptions = {
3089
+ direction: options?.direction,
3090
+ force: options?.force,
3091
+ dryRun: options?.dryRun
3092
+ // Explicitly exclude include/exclude to prevent double filtering
3093
+ // include: undefined,
3094
+ // exclude: undefined,
3095
+ };
3096
+ const plan = createSyncPlan(sourceFiles, targetFiles, planOptions, this.config);
2962
3097
  plan.estimatedTime = estimateSyncTime(plan);
2963
3098
  return {
2964
3099
  ...plan,