@fractary/codex 0.4.0 → 0.5.1
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 +188 -42
- 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 +187 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,19 +1,122 @@
|
|
|
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
|
+
if (pattern.startsWith("projects/")) {
|
|
78
|
+
return matchPattern(pattern, codexFilePath);
|
|
79
|
+
}
|
|
80
|
+
const projectSeparatorIndex = pattern.indexOf("/");
|
|
81
|
+
if (projectSeparatorIndex === -1) {
|
|
82
|
+
const fullPattern = `${targetProject}/${pattern}`;
|
|
83
|
+
return matchPattern(fullPattern, codexFilePath);
|
|
84
|
+
}
|
|
85
|
+
const firstSegment = pattern.substring(0, projectSeparatorIndex);
|
|
86
|
+
if (firstSegment.includes(".")) {
|
|
87
|
+
return matchPattern(pattern, codexFilePath);
|
|
88
|
+
} else {
|
|
89
|
+
const fullPattern = `${targetProject}/${pattern}`;
|
|
90
|
+
return matchPattern(fullPattern, codexFilePath);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function extractProjectFromCodexPath(codexFilePath) {
|
|
95
|
+
const firstSlashIndex = codexFilePath.indexOf("/");
|
|
96
|
+
if (firstSlashIndex === -1) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return codexFilePath.substring(0, firstSlashIndex);
|
|
100
|
+
}
|
|
101
|
+
function getRelativePath(codexFilePath) {
|
|
102
|
+
const firstSlashIndex = codexFilePath.indexOf("/");
|
|
103
|
+
if (firstSlashIndex === -1) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
return codexFilePath.substring(firstSlashIndex + 1);
|
|
107
|
+
}
|
|
108
|
+
function expandPlaceholders(patterns, targetProject) {
|
|
109
|
+
if (!patterns) {
|
|
110
|
+
return patterns;
|
|
111
|
+
}
|
|
112
|
+
return patterns.map((pattern) => pattern.replace(/{project}/g, targetProject));
|
|
113
|
+
}
|
|
114
|
+
var init_directional_patterns = __esm({
|
|
115
|
+
"src/sync/directional-patterns.ts"() {
|
|
116
|
+
init_matcher();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
17
120
|
// src/errors/CodexError.ts
|
|
18
121
|
var CodexError = class _CodexError extends Error {
|
|
19
122
|
constructor(message, options) {
|
|
@@ -730,6 +833,16 @@ var SyncRulesSchema = zod.z.object({
|
|
|
730
833
|
defaultInclude: zod.z.array(zod.z.string()).optional(),
|
|
731
834
|
defaultExclude: zod.z.array(zod.z.string()).optional()
|
|
732
835
|
});
|
|
836
|
+
var DirectionalSyncSchema = zod.z.object({
|
|
837
|
+
// Patterns for files to push from this project to codex
|
|
838
|
+
to_codex: zod.z.array(zod.z.string()).optional(),
|
|
839
|
+
// Patterns for files to pull from codex to this project
|
|
840
|
+
// Format: "project-name/path/pattern" or "project-name/**"
|
|
841
|
+
from_codex: zod.z.array(zod.z.string()).optional(),
|
|
842
|
+
// Org-level defaults (only in codex repository config)
|
|
843
|
+
default_to_codex: zod.z.array(zod.z.string()).optional(),
|
|
844
|
+
default_from_codex: zod.z.array(zod.z.string()).optional()
|
|
845
|
+
});
|
|
733
846
|
var CodexConfigSchema = zod.z.object({
|
|
734
847
|
organizationSlug: zod.z.string(),
|
|
735
848
|
directories: zod.z.object({
|
|
@@ -737,7 +850,9 @@ var CodexConfigSchema = zod.z.object({
|
|
|
737
850
|
target: zod.z.string().optional(),
|
|
738
851
|
systems: zod.z.string().optional()
|
|
739
852
|
}).optional(),
|
|
740
|
-
rules: SyncRulesSchema.optional()
|
|
853
|
+
rules: SyncRulesSchema.optional(),
|
|
854
|
+
// Directional sync configuration
|
|
855
|
+
sync: DirectionalSyncSchema.optional()
|
|
741
856
|
}).strict();
|
|
742
857
|
function parseMetadata(content, options = {}) {
|
|
743
858
|
const { strict = true, normalize = true } = options;
|
|
@@ -812,32 +927,9 @@ function extractRawFrontmatter(content) {
|
|
|
812
927
|
const match = normalized.match(/^---\n([\s\S]*?)\n---\n/);
|
|
813
928
|
return match && match[1] ? match[1] : null;
|
|
814
929
|
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
}
|
|
819
|
-
function matchAnyPattern(patterns, value) {
|
|
820
|
-
if (patterns.length === 1 && patterns[0] === "*") {
|
|
821
|
-
return true;
|
|
822
|
-
}
|
|
823
|
-
if (patterns.length === 0) {
|
|
824
|
-
return false;
|
|
825
|
-
}
|
|
826
|
-
return patterns.some((pattern) => matchPattern(pattern, value));
|
|
827
|
-
}
|
|
828
|
-
function filterByPatterns(patterns, values) {
|
|
829
|
-
return values.filter((value) => matchAnyPattern(patterns, value));
|
|
830
|
-
}
|
|
831
|
-
function evaluatePatterns(options) {
|
|
832
|
-
const { value, include = [], exclude = [] } = options;
|
|
833
|
-
if (exclude.length > 0 && matchAnyPattern(exclude, value)) {
|
|
834
|
-
return false;
|
|
835
|
-
}
|
|
836
|
-
if (include.length === 0) {
|
|
837
|
-
return true;
|
|
838
|
-
}
|
|
839
|
-
return matchAnyPattern(include, value);
|
|
840
|
-
}
|
|
930
|
+
|
|
931
|
+
// src/core/patterns/index.ts
|
|
932
|
+
init_matcher();
|
|
841
933
|
|
|
842
934
|
// src/core/config/organization.ts
|
|
843
935
|
function resolveOrganization(options = {}) {
|
|
@@ -948,11 +1040,24 @@ function mergeConfigs(base, override) {
|
|
|
948
1040
|
autoSyncPatterns: override.rules?.autoSyncPatterns ?? base.rules?.autoSyncPatterns,
|
|
949
1041
|
defaultInclude: override.rules?.defaultInclude ?? base.rules?.defaultInclude,
|
|
950
1042
|
defaultExclude: override.rules?.defaultExclude ?? base.rules?.defaultExclude
|
|
951
|
-
}
|
|
1043
|
+
},
|
|
1044
|
+
// Only include sync if either base or override has sync config
|
|
1045
|
+
...base.sync || override.sync ? {
|
|
1046
|
+
sync: {
|
|
1047
|
+
...base.sync,
|
|
1048
|
+
...override.sync,
|
|
1049
|
+
// Arrays are replaced, not merged
|
|
1050
|
+
to_codex: override.sync?.to_codex ?? base.sync?.to_codex,
|
|
1051
|
+
from_codex: override.sync?.from_codex ?? base.sync?.from_codex,
|
|
1052
|
+
default_to_codex: override.sync?.default_to_codex ?? base.sync?.default_to_codex,
|
|
1053
|
+
default_from_codex: override.sync?.default_from_codex ?? base.sync?.default_from_codex
|
|
1054
|
+
}
|
|
1055
|
+
} : {}
|
|
952
1056
|
};
|
|
953
1057
|
}
|
|
954
1058
|
|
|
955
1059
|
// src/core/routing/evaluator.ts
|
|
1060
|
+
init_matcher();
|
|
956
1061
|
function shouldSyncToRepo(options) {
|
|
957
1062
|
const {
|
|
958
1063
|
filePath,
|
|
@@ -2727,8 +2832,9 @@ async function scanCodexWithRouting(options) {
|
|
|
2727
2832
|
rules,
|
|
2728
2833
|
storage,
|
|
2729
2834
|
skipNoFrontmatter = false,
|
|
2730
|
-
maxFileSize = 10 * 1024 * 1024
|
|
2835
|
+
maxFileSize = 10 * 1024 * 1024,
|
|
2731
2836
|
// 10MB default
|
|
2837
|
+
fromCodexPatterns
|
|
2732
2838
|
} = options;
|
|
2733
2839
|
const startTime = Date.now();
|
|
2734
2840
|
const routedFiles = [];
|
|
@@ -2736,6 +2842,13 @@ async function scanCodexWithRouting(options) {
|
|
|
2736
2842
|
const errors = [];
|
|
2737
2843
|
let totalScanned = 0;
|
|
2738
2844
|
let totalSkipped = 0;
|
|
2845
|
+
let expandedFromCodexPatterns = fromCodexPatterns;
|
|
2846
|
+
let matchFromCodexPattern2 = null;
|
|
2847
|
+
if (fromCodexPatterns && fromCodexPatterns.length > 0) {
|
|
2848
|
+
const module = await Promise.resolve().then(() => (init_directional_patterns(), directional_patterns_exports));
|
|
2849
|
+
matchFromCodexPattern2 = module.matchFromCodexPattern;
|
|
2850
|
+
expandedFromCodexPatterns = module.expandPlaceholders(fromCodexPatterns, targetProject);
|
|
2851
|
+
}
|
|
2739
2852
|
const allFiles = await listAllFilesRecursive(codexDir);
|
|
2740
2853
|
for (const filePath of allFiles) {
|
|
2741
2854
|
totalScanned++;
|
|
@@ -2752,18 +2865,23 @@ async function scanCodexWithRouting(options) {
|
|
|
2752
2865
|
}
|
|
2753
2866
|
const content = await storage.readText(fullPath);
|
|
2754
2867
|
const parseResult = parseMetadata(content, { strict: false });
|
|
2755
|
-
if (skipNoFrontmatter && Object.keys(parseResult.metadata).length === 0) {
|
|
2868
|
+
if (!matchFromCodexPattern2 && skipNoFrontmatter && Object.keys(parseResult.metadata).length === 0) {
|
|
2756
2869
|
totalSkipped++;
|
|
2757
2870
|
continue;
|
|
2758
2871
|
}
|
|
2759
2872
|
const sourceProject = extractProjectFromPath(filePath, org);
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2873
|
+
let shouldSync = false;
|
|
2874
|
+
if (matchFromCodexPattern2 && expandedFromCodexPatterns && expandedFromCodexPatterns.length > 0) {
|
|
2875
|
+
shouldSync = matchFromCodexPattern2(filePath, expandedFromCodexPatterns, targetProject);
|
|
2876
|
+
} else {
|
|
2877
|
+
shouldSync = shouldSyncToRepo({
|
|
2878
|
+
filePath,
|
|
2879
|
+
fileMetadata: parseResult.metadata,
|
|
2880
|
+
targetRepo: targetProject,
|
|
2881
|
+
sourceRepo: sourceProject,
|
|
2882
|
+
rules
|
|
2883
|
+
});
|
|
2884
|
+
}
|
|
2767
2885
|
if (shouldSync) {
|
|
2768
2886
|
const buffer = Buffer.from(content);
|
|
2769
2887
|
const hash = calculateContentHash(buffer);
|
|
@@ -2803,6 +2921,14 @@ async function scanCodexWithRouting(options) {
|
|
|
2803
2921
|
function extractProjectFromPath(filePath, org) {
|
|
2804
2922
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
2805
2923
|
const withoutOrg = normalizedPath.startsWith(`${org}/`) ? normalizedPath.slice(org.length + 1) : normalizedPath;
|
|
2924
|
+
if (withoutOrg.startsWith("projects/")) {
|
|
2925
|
+
const afterProjects = withoutOrg.slice("projects/".length);
|
|
2926
|
+
const firstSlash2 = afterProjects.indexOf("/");
|
|
2927
|
+
if (firstSlash2 === -1) {
|
|
2928
|
+
return afterProjects;
|
|
2929
|
+
}
|
|
2930
|
+
return afterProjects.slice(0, firstSlash2);
|
|
2931
|
+
}
|
|
2806
2932
|
const firstSlash = withoutOrg.indexOf("/");
|
|
2807
2933
|
if (firstSlash === -1) {
|
|
2808
2934
|
return withoutOrg;
|
|
@@ -2914,7 +3040,16 @@ var SyncManager = class {
|
|
|
2914
3040
|
* @param options - Sync options
|
|
2915
3041
|
*/
|
|
2916
3042
|
async createPlan(_org, _project, sourceDir, targetFiles, options) {
|
|
2917
|
-
|
|
3043
|
+
let sourceFiles = await this.listLocalFiles(sourceDir);
|
|
3044
|
+
if (options?.direction === "to-codex") {
|
|
3045
|
+
const toCodexPatterns = this.config.to_codex || this.config.default_to_codex;
|
|
3046
|
+
if (toCodexPatterns) {
|
|
3047
|
+
const { matchToCodexPattern: matchToCodexPattern2 } = await Promise.resolve().then(() => (init_directional_patterns(), directional_patterns_exports));
|
|
3048
|
+
sourceFiles = sourceFiles.filter(
|
|
3049
|
+
(file) => matchToCodexPattern2(file.path, toCodexPatterns)
|
|
3050
|
+
);
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
2918
3053
|
const plan = createSyncPlan(
|
|
2919
3054
|
sourceFiles,
|
|
2920
3055
|
targetFiles,
|
|
@@ -2952,13 +3087,16 @@ var SyncManager = class {
|
|
|
2952
3087
|
* ```
|
|
2953
3088
|
*/
|
|
2954
3089
|
async createRoutingAwarePlan(org, project, codexDir, options) {
|
|
3090
|
+
const fromCodexPatterns = this.config.from_codex || this.config.default_from_codex;
|
|
2955
3091
|
const routingScan = await scanCodexWithRouting({
|
|
2956
3092
|
codexDir,
|
|
2957
3093
|
targetProject: project,
|
|
2958
3094
|
org,
|
|
2959
3095
|
rules: void 0,
|
|
2960
3096
|
// Use default routing rules (preventSelfSync, preventCodexSync, etc.)
|
|
2961
|
-
storage: this.localStorage
|
|
3097
|
+
storage: this.localStorage,
|
|
3098
|
+
fromCodexPatterns
|
|
3099
|
+
// Use directional patterns if configured
|
|
2962
3100
|
});
|
|
2963
3101
|
const sourceFiles = routingScan.files.map((rf) => ({
|
|
2964
3102
|
path: rf.path,
|
|
@@ -2967,7 +3105,15 @@ var SyncManager = class {
|
|
|
2967
3105
|
hash: rf.hash
|
|
2968
3106
|
}));
|
|
2969
3107
|
const targetFiles = await this.listLocalFiles(process.cwd());
|
|
2970
|
-
const
|
|
3108
|
+
const planOptions = {
|
|
3109
|
+
direction: options?.direction,
|
|
3110
|
+
force: options?.force,
|
|
3111
|
+
dryRun: options?.dryRun
|
|
3112
|
+
// Explicitly exclude include/exclude to prevent double filtering
|
|
3113
|
+
// include: undefined,
|
|
3114
|
+
// exclude: undefined,
|
|
3115
|
+
};
|
|
3116
|
+
const plan = createSyncPlan(sourceFiles, targetFiles, planOptions, this.config);
|
|
2971
3117
|
plan.estimatedTime = estimateSyncTime(plan);
|
|
2972
3118
|
return {
|
|
2973
3119
|
...plan,
|