@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.cjs +184 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +183 -46
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,19 +1,119 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var micromatch3 = require('micromatch');
|
|
3
4
|
var path3 = require('path');
|
|
4
5
|
var child_process = require('child_process');
|
|
5
|
-
var micromatch3 = require('micromatch');
|
|
6
6
|
var zod = require('zod');
|
|
7
7
|
var yaml = require('js-yaml');
|
|
8
8
|
var fs2 = require('fs/promises');
|
|
9
9
|
|
|
10
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
11
|
|
|
12
|
-
var path3__default = /*#__PURE__*/_interopDefault(path3);
|
|
13
12
|
var micromatch3__default = /*#__PURE__*/_interopDefault(micromatch3);
|
|
13
|
+
var path3__default = /*#__PURE__*/_interopDefault(path3);
|
|
14
14
|
var yaml__default = /*#__PURE__*/_interopDefault(yaml);
|
|
15
15
|
var fs2__default = /*#__PURE__*/_interopDefault(fs2);
|
|
16
16
|
|
|
17
|
+
var __defProp = Object.defineProperty;
|
|
18
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
19
|
+
var __esm = (fn, res) => function __init() {
|
|
20
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
21
|
+
};
|
|
22
|
+
var __export = (target, all) => {
|
|
23
|
+
for (var name in all)
|
|
24
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
25
|
+
};
|
|
26
|
+
function matchPattern(pattern, value) {
|
|
27
|
+
if (pattern === value) return true;
|
|
28
|
+
return micromatch3__default.default.isMatch(value, pattern);
|
|
29
|
+
}
|
|
30
|
+
function matchAnyPattern(patterns, value) {
|
|
31
|
+
if (patterns.length === 1 && patterns[0] === "*") {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
if (patterns.length === 0) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return patterns.some((pattern) => matchPattern(pattern, value));
|
|
38
|
+
}
|
|
39
|
+
function filterByPatterns(patterns, values) {
|
|
40
|
+
return values.filter((value) => matchAnyPattern(patterns, value));
|
|
41
|
+
}
|
|
42
|
+
function evaluatePatterns(options) {
|
|
43
|
+
const { value, include = [], exclude = [] } = options;
|
|
44
|
+
if (exclude.length > 0 && matchAnyPattern(exclude, value)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (include.length === 0) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return matchAnyPattern(include, value);
|
|
51
|
+
}
|
|
52
|
+
var init_matcher = __esm({
|
|
53
|
+
"src/core/patterns/matcher.ts"() {
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// src/sync/directional-patterns.ts
|
|
58
|
+
var directional_patterns_exports = {};
|
|
59
|
+
__export(directional_patterns_exports, {
|
|
60
|
+
expandPlaceholders: () => expandPlaceholders,
|
|
61
|
+
extractProjectFromCodexPath: () => extractProjectFromCodexPath,
|
|
62
|
+
getRelativePath: () => getRelativePath,
|
|
63
|
+
matchFromCodexPattern: () => matchFromCodexPattern,
|
|
64
|
+
matchToCodexPattern: () => matchToCodexPattern
|
|
65
|
+
});
|
|
66
|
+
function matchToCodexPattern(filePath, patterns) {
|
|
67
|
+
if (!patterns || patterns.length === 0) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
return patterns.some((pattern) => matchPattern(pattern, filePath));
|
|
71
|
+
}
|
|
72
|
+
function matchFromCodexPattern(codexFilePath, patterns, targetProject) {
|
|
73
|
+
if (!patterns || patterns.length === 0) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return patterns.some((pattern) => {
|
|
77
|
+
const projectSeparatorIndex = pattern.indexOf("/");
|
|
78
|
+
if (projectSeparatorIndex === -1) {
|
|
79
|
+
const fullPattern = `${targetProject}/${pattern}`;
|
|
80
|
+
return matchPattern(fullPattern, codexFilePath);
|
|
81
|
+
}
|
|
82
|
+
const firstSegment = pattern.substring(0, projectSeparatorIndex);
|
|
83
|
+
if (firstSegment.includes(".")) {
|
|
84
|
+
return matchPattern(pattern, codexFilePath);
|
|
85
|
+
} else {
|
|
86
|
+
const fullPattern = `${targetProject}/${pattern}`;
|
|
87
|
+
return matchPattern(fullPattern, codexFilePath);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function extractProjectFromCodexPath(codexFilePath) {
|
|
92
|
+
const firstSlashIndex = codexFilePath.indexOf("/");
|
|
93
|
+
if (firstSlashIndex === -1) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
return codexFilePath.substring(0, firstSlashIndex);
|
|
97
|
+
}
|
|
98
|
+
function getRelativePath(codexFilePath) {
|
|
99
|
+
const firstSlashIndex = codexFilePath.indexOf("/");
|
|
100
|
+
if (firstSlashIndex === -1) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
return codexFilePath.substring(firstSlashIndex + 1);
|
|
104
|
+
}
|
|
105
|
+
function expandPlaceholders(patterns, targetProject) {
|
|
106
|
+
if (!patterns) {
|
|
107
|
+
return patterns;
|
|
108
|
+
}
|
|
109
|
+
return patterns.map((pattern) => pattern.replace(/{project}/g, targetProject));
|
|
110
|
+
}
|
|
111
|
+
var init_directional_patterns = __esm({
|
|
112
|
+
"src/sync/directional-patterns.ts"() {
|
|
113
|
+
init_matcher();
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
17
117
|
// src/errors/CodexError.ts
|
|
18
118
|
var CodexError = class _CodexError extends Error {
|
|
19
119
|
constructor(message, options) {
|
|
@@ -730,6 +830,16 @@ var SyncRulesSchema = zod.z.object({
|
|
|
730
830
|
defaultInclude: zod.z.array(zod.z.string()).optional(),
|
|
731
831
|
defaultExclude: zod.z.array(zod.z.string()).optional()
|
|
732
832
|
});
|
|
833
|
+
var DirectionalSyncSchema = zod.z.object({
|
|
834
|
+
// Patterns for files to push from this project to codex
|
|
835
|
+
to_codex: zod.z.array(zod.z.string()).optional(),
|
|
836
|
+
// Patterns for files to pull from codex to this project
|
|
837
|
+
// Format: "project-name/path/pattern" or "project-name/**"
|
|
838
|
+
from_codex: zod.z.array(zod.z.string()).optional(),
|
|
839
|
+
// Org-level defaults (only in codex repository config)
|
|
840
|
+
default_to_codex: zod.z.array(zod.z.string()).optional(),
|
|
841
|
+
default_from_codex: zod.z.array(zod.z.string()).optional()
|
|
842
|
+
});
|
|
733
843
|
var CodexConfigSchema = zod.z.object({
|
|
734
844
|
organizationSlug: zod.z.string(),
|
|
735
845
|
directories: zod.z.object({
|
|
@@ -737,7 +847,9 @@ var CodexConfigSchema = zod.z.object({
|
|
|
737
847
|
target: zod.z.string().optional(),
|
|
738
848
|
systems: zod.z.string().optional()
|
|
739
849
|
}).optional(),
|
|
740
|
-
rules: SyncRulesSchema.optional()
|
|
850
|
+
rules: SyncRulesSchema.optional(),
|
|
851
|
+
// Directional sync configuration
|
|
852
|
+
sync: DirectionalSyncSchema.optional()
|
|
741
853
|
}).strict();
|
|
742
854
|
function parseMetadata(content, options = {}) {
|
|
743
855
|
const { strict = true, normalize = true } = options;
|
|
@@ -785,6 +897,12 @@ function normalizeLegacyMetadata(parsed) {
|
|
|
785
897
|
if (parsed.codex?.excludes && !parsed.codex_sync_exclude) {
|
|
786
898
|
normalized.codex_sync_exclude = parsed.codex.excludes;
|
|
787
899
|
}
|
|
900
|
+
if (parsed.codex_sync_includes && !normalized.codex_sync_include) {
|
|
901
|
+
normalized.codex_sync_include = parsed.codex_sync_includes;
|
|
902
|
+
}
|
|
903
|
+
if (parsed.codex_sync_excludes && !normalized.codex_sync_exclude) {
|
|
904
|
+
normalized.codex_sync_exclude = parsed.codex_sync_excludes;
|
|
905
|
+
}
|
|
788
906
|
return normalized;
|
|
789
907
|
}
|
|
790
908
|
function hasFrontmatter(content) {
|
|
@@ -806,32 +924,9 @@ function extractRawFrontmatter(content) {
|
|
|
806
924
|
const match = normalized.match(/^---\n([\s\S]*?)\n---\n/);
|
|
807
925
|
return match && match[1] ? match[1] : null;
|
|
808
926
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
}
|
|
813
|
-
function matchAnyPattern(patterns, value) {
|
|
814
|
-
if (patterns.length === 1 && patterns[0] === "*") {
|
|
815
|
-
return true;
|
|
816
|
-
}
|
|
817
|
-
if (patterns.length === 0) {
|
|
818
|
-
return false;
|
|
819
|
-
}
|
|
820
|
-
return patterns.some((pattern) => matchPattern(pattern, value));
|
|
821
|
-
}
|
|
822
|
-
function filterByPatterns(patterns, values) {
|
|
823
|
-
return values.filter((value) => matchAnyPattern(patterns, value));
|
|
824
|
-
}
|
|
825
|
-
function evaluatePatterns(options) {
|
|
826
|
-
const { value, include = [], exclude = [] } = options;
|
|
827
|
-
if (exclude.length > 0 && matchAnyPattern(exclude, value)) {
|
|
828
|
-
return false;
|
|
829
|
-
}
|
|
830
|
-
if (include.length === 0) {
|
|
831
|
-
return true;
|
|
832
|
-
}
|
|
833
|
-
return matchAnyPattern(include, value);
|
|
834
|
-
}
|
|
927
|
+
|
|
928
|
+
// src/core/patterns/index.ts
|
|
929
|
+
init_matcher();
|
|
835
930
|
|
|
836
931
|
// src/core/config/organization.ts
|
|
837
932
|
function resolveOrganization(options = {}) {
|
|
@@ -942,11 +1037,24 @@ function mergeConfigs(base, override) {
|
|
|
942
1037
|
autoSyncPatterns: override.rules?.autoSyncPatterns ?? base.rules?.autoSyncPatterns,
|
|
943
1038
|
defaultInclude: override.rules?.defaultInclude ?? base.rules?.defaultInclude,
|
|
944
1039
|
defaultExclude: override.rules?.defaultExclude ?? base.rules?.defaultExclude
|
|
945
|
-
}
|
|
1040
|
+
},
|
|
1041
|
+
// Only include sync if either base or override has sync config
|
|
1042
|
+
...base.sync || override.sync ? {
|
|
1043
|
+
sync: {
|
|
1044
|
+
...base.sync,
|
|
1045
|
+
...override.sync,
|
|
1046
|
+
// Arrays are replaced, not merged
|
|
1047
|
+
to_codex: override.sync?.to_codex ?? base.sync?.to_codex,
|
|
1048
|
+
from_codex: override.sync?.from_codex ?? base.sync?.from_codex,
|
|
1049
|
+
default_to_codex: override.sync?.default_to_codex ?? base.sync?.default_to_codex,
|
|
1050
|
+
default_from_codex: override.sync?.default_from_codex ?? base.sync?.default_from_codex
|
|
1051
|
+
}
|
|
1052
|
+
} : {}
|
|
946
1053
|
};
|
|
947
1054
|
}
|
|
948
1055
|
|
|
949
1056
|
// src/core/routing/evaluator.ts
|
|
1057
|
+
init_matcher();
|
|
950
1058
|
function shouldSyncToRepo(options) {
|
|
951
1059
|
const {
|
|
952
1060
|
filePath,
|
|
@@ -2720,9 +2828,10 @@ async function scanCodexWithRouting(options) {
|
|
|
2720
2828
|
org,
|
|
2721
2829
|
rules,
|
|
2722
2830
|
storage,
|
|
2723
|
-
skipNoFrontmatter =
|
|
2724
|
-
maxFileSize = 10 * 1024 * 1024
|
|
2831
|
+
skipNoFrontmatter = false,
|
|
2832
|
+
maxFileSize = 10 * 1024 * 1024,
|
|
2725
2833
|
// 10MB default
|
|
2834
|
+
fromCodexPatterns
|
|
2726
2835
|
} = options;
|
|
2727
2836
|
const startTime = Date.now();
|
|
2728
2837
|
const routedFiles = [];
|
|
@@ -2730,14 +2839,17 @@ async function scanCodexWithRouting(options) {
|
|
|
2730
2839
|
const errors = [];
|
|
2731
2840
|
let totalScanned = 0;
|
|
2732
2841
|
let totalSkipped = 0;
|
|
2842
|
+
let expandedFromCodexPatterns = fromCodexPatterns;
|
|
2843
|
+
let matchFromCodexPattern2 = null;
|
|
2844
|
+
if (fromCodexPatterns && fromCodexPatterns.length > 0) {
|
|
2845
|
+
const module = await Promise.resolve().then(() => (init_directional_patterns(), directional_patterns_exports));
|
|
2846
|
+
matchFromCodexPattern2 = module.matchFromCodexPattern;
|
|
2847
|
+
expandedFromCodexPatterns = module.expandPlaceholders(fromCodexPatterns, targetProject);
|
|
2848
|
+
}
|
|
2733
2849
|
const allFiles = await listAllFilesRecursive(codexDir);
|
|
2734
2850
|
for (const filePath of allFiles) {
|
|
2735
2851
|
totalScanned++;
|
|
2736
2852
|
try {
|
|
2737
|
-
if (!filePath.endsWith(".md")) {
|
|
2738
|
-
totalSkipped++;
|
|
2739
|
-
continue;
|
|
2740
|
-
}
|
|
2741
2853
|
const fullPath = path3__default.default.join(codexDir, filePath);
|
|
2742
2854
|
const stats = await fs2__default.default.stat(fullPath);
|
|
2743
2855
|
if (stats.size > maxFileSize) {
|
|
@@ -2750,18 +2862,23 @@ async function scanCodexWithRouting(options) {
|
|
|
2750
2862
|
}
|
|
2751
2863
|
const content = await storage.readText(fullPath);
|
|
2752
2864
|
const parseResult = parseMetadata(content, { strict: false });
|
|
2753
|
-
if (skipNoFrontmatter && Object.keys(parseResult.metadata).length === 0) {
|
|
2865
|
+
if (!matchFromCodexPattern2 && skipNoFrontmatter && Object.keys(parseResult.metadata).length === 0) {
|
|
2754
2866
|
totalSkipped++;
|
|
2755
2867
|
continue;
|
|
2756
2868
|
}
|
|
2757
2869
|
const sourceProject = extractProjectFromPath(filePath, org);
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2870
|
+
let shouldSync = false;
|
|
2871
|
+
if (matchFromCodexPattern2 && expandedFromCodexPatterns && expandedFromCodexPatterns.length > 0) {
|
|
2872
|
+
shouldSync = matchFromCodexPattern2(filePath, expandedFromCodexPatterns, targetProject);
|
|
2873
|
+
} else {
|
|
2874
|
+
shouldSync = shouldSyncToRepo({
|
|
2875
|
+
filePath,
|
|
2876
|
+
fileMetadata: parseResult.metadata,
|
|
2877
|
+
targetRepo: targetProject,
|
|
2878
|
+
sourceRepo: sourceProject,
|
|
2879
|
+
rules
|
|
2880
|
+
});
|
|
2881
|
+
}
|
|
2765
2882
|
if (shouldSync) {
|
|
2766
2883
|
const buffer = Buffer.from(content);
|
|
2767
2884
|
const hash = calculateContentHash(buffer);
|
|
@@ -2912,7 +3029,16 @@ var SyncManager = class {
|
|
|
2912
3029
|
* @param options - Sync options
|
|
2913
3030
|
*/
|
|
2914
3031
|
async createPlan(_org, _project, sourceDir, targetFiles, options) {
|
|
2915
|
-
|
|
3032
|
+
let sourceFiles = await this.listLocalFiles(sourceDir);
|
|
3033
|
+
if (options?.direction === "to-codex") {
|
|
3034
|
+
const toCodexPatterns = this.config.to_codex || this.config.default_to_codex;
|
|
3035
|
+
if (toCodexPatterns) {
|
|
3036
|
+
const { matchToCodexPattern: matchToCodexPattern2 } = await Promise.resolve().then(() => (init_directional_patterns(), directional_patterns_exports));
|
|
3037
|
+
sourceFiles = sourceFiles.filter(
|
|
3038
|
+
(file) => matchToCodexPattern2(file.path, toCodexPatterns)
|
|
3039
|
+
);
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
2916
3042
|
const plan = createSyncPlan(
|
|
2917
3043
|
sourceFiles,
|
|
2918
3044
|
targetFiles,
|
|
@@ -2950,13 +3076,16 @@ var SyncManager = class {
|
|
|
2950
3076
|
* ```
|
|
2951
3077
|
*/
|
|
2952
3078
|
async createRoutingAwarePlan(org, project, codexDir, options) {
|
|
3079
|
+
const fromCodexPatterns = this.config.from_codex || this.config.default_from_codex;
|
|
2953
3080
|
const routingScan = await scanCodexWithRouting({
|
|
2954
3081
|
codexDir,
|
|
2955
3082
|
targetProject: project,
|
|
2956
3083
|
org,
|
|
2957
3084
|
rules: void 0,
|
|
2958
3085
|
// Use default routing rules (preventSelfSync, preventCodexSync, etc.)
|
|
2959
|
-
storage: this.localStorage
|
|
3086
|
+
storage: this.localStorage,
|
|
3087
|
+
fromCodexPatterns
|
|
3088
|
+
// Use directional patterns if configured
|
|
2960
3089
|
});
|
|
2961
3090
|
const sourceFiles = routingScan.files.map((rf) => ({
|
|
2962
3091
|
path: rf.path,
|
|
@@ -2965,7 +3094,15 @@ var SyncManager = class {
|
|
|
2965
3094
|
hash: rf.hash
|
|
2966
3095
|
}));
|
|
2967
3096
|
const targetFiles = await this.listLocalFiles(process.cwd());
|
|
2968
|
-
const
|
|
3097
|
+
const planOptions = {
|
|
3098
|
+
direction: options?.direction,
|
|
3099
|
+
force: options?.force,
|
|
3100
|
+
dryRun: options?.dryRun
|
|
3101
|
+
// Explicitly exclude include/exclude to prevent double filtering
|
|
3102
|
+
// include: undefined,
|
|
3103
|
+
// exclude: undefined,
|
|
3104
|
+
};
|
|
3105
|
+
const plan = createSyncPlan(sourceFiles, targetFiles, planOptions, this.config);
|
|
2969
3106
|
plan.estimatedTime = estimateSyncTime(plan);
|
|
2970
3107
|
return {
|
|
2971
3108
|
...plan,
|