@fractary/codex 0.3.1 → 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;
@@ -776,6 +888,12 @@ function normalizeLegacyMetadata(parsed) {
776
888
  if (parsed.codex?.excludes && !parsed.codex_sync_exclude) {
777
889
  normalized.codex_sync_exclude = parsed.codex.excludes;
778
890
  }
891
+ if (parsed.codex_sync_includes && !normalized.codex_sync_include) {
892
+ normalized.codex_sync_include = parsed.codex_sync_includes;
893
+ }
894
+ if (parsed.codex_sync_excludes && !normalized.codex_sync_exclude) {
895
+ normalized.codex_sync_exclude = parsed.codex_sync_excludes;
896
+ }
779
897
  return normalized;
780
898
  }
781
899
  function hasFrontmatter(content) {
@@ -797,32 +915,9 @@ function extractRawFrontmatter(content) {
797
915
  const match = normalized.match(/^---\n([\s\S]*?)\n---\n/);
798
916
  return match && match[1] ? match[1] : null;
799
917
  }
800
- function matchPattern(pattern, value) {
801
- if (pattern === value) return true;
802
- return micromatch3.isMatch(value, pattern);
803
- }
804
- function matchAnyPattern(patterns, value) {
805
- if (patterns.length === 1 && patterns[0] === "*") {
806
- return true;
807
- }
808
- if (patterns.length === 0) {
809
- return false;
810
- }
811
- return patterns.some((pattern) => matchPattern(pattern, value));
812
- }
813
- function filterByPatterns(patterns, values) {
814
- return values.filter((value) => matchAnyPattern(patterns, value));
815
- }
816
- function evaluatePatterns(options) {
817
- const { value, include = [], exclude = [] } = options;
818
- if (exclude.length > 0 && matchAnyPattern(exclude, value)) {
819
- return false;
820
- }
821
- if (include.length === 0) {
822
- return true;
823
- }
824
- return matchAnyPattern(include, value);
825
- }
918
+
919
+ // src/core/patterns/index.ts
920
+ init_matcher();
826
921
 
827
922
  // src/core/config/organization.ts
828
923
  function resolveOrganization(options = {}) {
@@ -933,11 +1028,24 @@ function mergeConfigs(base, override) {
933
1028
  autoSyncPatterns: override.rules?.autoSyncPatterns ?? base.rules?.autoSyncPatterns,
934
1029
  defaultInclude: override.rules?.defaultInclude ?? base.rules?.defaultInclude,
935
1030
  defaultExclude: override.rules?.defaultExclude ?? base.rules?.defaultExclude
936
- }
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
+ } : {}
937
1044
  };
938
1045
  }
939
1046
 
940
1047
  // src/core/routing/evaluator.ts
1048
+ init_matcher();
941
1049
  function shouldSyncToRepo(options) {
942
1050
  const {
943
1051
  filePath,
@@ -2711,9 +2819,10 @@ async function scanCodexWithRouting(options) {
2711
2819
  org,
2712
2820
  rules,
2713
2821
  storage,
2714
- skipNoFrontmatter = true,
2715
- maxFileSize = 10 * 1024 * 1024
2822
+ skipNoFrontmatter = false,
2823
+ maxFileSize = 10 * 1024 * 1024,
2716
2824
  // 10MB default
2825
+ fromCodexPatterns
2717
2826
  } = options;
2718
2827
  const startTime = Date.now();
2719
2828
  const routedFiles = [];
@@ -2721,14 +2830,17 @@ async function scanCodexWithRouting(options) {
2721
2830
  const errors = [];
2722
2831
  let totalScanned = 0;
2723
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
+ }
2724
2840
  const allFiles = await listAllFilesRecursive(codexDir);
2725
2841
  for (const filePath of allFiles) {
2726
2842
  totalScanned++;
2727
2843
  try {
2728
- if (!filePath.endsWith(".md")) {
2729
- totalSkipped++;
2730
- continue;
2731
- }
2732
2844
  const fullPath = path3.join(codexDir, filePath);
2733
2845
  const stats = await fs2.stat(fullPath);
2734
2846
  if (stats.size > maxFileSize) {
@@ -2741,18 +2853,23 @@ async function scanCodexWithRouting(options) {
2741
2853
  }
2742
2854
  const content = await storage.readText(fullPath);
2743
2855
  const parseResult = parseMetadata(content, { strict: false });
2744
- if (skipNoFrontmatter && Object.keys(parseResult.metadata).length === 0) {
2856
+ if (!matchFromCodexPattern2 && skipNoFrontmatter && Object.keys(parseResult.metadata).length === 0) {
2745
2857
  totalSkipped++;
2746
2858
  continue;
2747
2859
  }
2748
2860
  const sourceProject = extractProjectFromPath(filePath, org);
2749
- const shouldSync = shouldSyncToRepo({
2750
- filePath,
2751
- fileMetadata: parseResult.metadata,
2752
- targetRepo: targetProject,
2753
- sourceRepo: sourceProject,
2754
- rules
2755
- });
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
+ }
2756
2873
  if (shouldSync) {
2757
2874
  const buffer = Buffer.from(content);
2758
2875
  const hash = calculateContentHash(buffer);
@@ -2903,7 +3020,16 @@ var SyncManager = class {
2903
3020
  * @param options - Sync options
2904
3021
  */
2905
3022
  async createPlan(_org, _project, sourceDir, targetFiles, options) {
2906
- 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
+ }
2907
3033
  const plan = createSyncPlan(
2908
3034
  sourceFiles,
2909
3035
  targetFiles,
@@ -2941,13 +3067,16 @@ var SyncManager = class {
2941
3067
  * ```
2942
3068
  */
2943
3069
  async createRoutingAwarePlan(org, project, codexDir, options) {
3070
+ const fromCodexPatterns = this.config.from_codex || this.config.default_from_codex;
2944
3071
  const routingScan = await scanCodexWithRouting({
2945
3072
  codexDir,
2946
3073
  targetProject: project,
2947
3074
  org,
2948
3075
  rules: void 0,
2949
3076
  // Use default routing rules (preventSelfSync, preventCodexSync, etc.)
2950
- storage: this.localStorage
3077
+ storage: this.localStorage,
3078
+ fromCodexPatterns
3079
+ // Use directional patterns if configured
2951
3080
  });
2952
3081
  const sourceFiles = routingScan.files.map((rf) => ({
2953
3082
  path: rf.path,
@@ -2956,7 +3085,15 @@ var SyncManager = class {
2956
3085
  hash: rf.hash
2957
3086
  }));
2958
3087
  const targetFiles = await this.listLocalFiles(process.cwd());
2959
- 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);
2960
3097
  plan.estimatedTime = estimateSyncTime(plan);
2961
3098
  return {
2962
3099
  ...plan,