@fractary/codex 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Fractary Engineering
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,280 @@
1
+ # @fractary/codex
2
+
3
+ Core SDK for Fractary Codex - a centralized knowledge management and distribution platform for organizations.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@fractary/codex.svg)](https://www.npmjs.com/package/@fractary/codex)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Overview
9
+
10
+ The Codex SDK provides the foundational business logic for the Fractary Codex system, which enables organizations to maintain a single source of truth for documentation, AI tools, and organizational knowledge across all projects.
11
+
12
+ ### Key Features
13
+
14
+ - **Metadata Parsing**: Extract and validate YAML frontmatter from markdown files
15
+ - **Pattern Matching**: Glob-based pattern matching for intelligent file routing
16
+ - **Smart Routing**: Determine which files should sync to which repositories
17
+ - **Configuration Management**: Multi-source configuration with sensible defaults
18
+ - **Organization-Agnostic**: Works for any organization, not just Fractary
19
+ - **Type-Safe**: Full TypeScript support with strict typing
20
+ - **Well-Tested**: Comprehensive unit test coverage
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install @fractary/codex
26
+ ```
27
+
28
+ ## Quick Start
29
+
30
+ ```typescript
31
+ import {
32
+ parseMetadata,
33
+ shouldSyncToRepo,
34
+ loadConfig
35
+ } from '@fractary/codex'
36
+
37
+ // 1. Load configuration
38
+ const config = loadConfig({
39
+ organizationSlug: 'fractary'
40
+ })
41
+
42
+ // 2. Parse frontmatter from a markdown file
43
+ const fileContent = await readFile('docs/api-guide.md', 'utf-8')
44
+ const { metadata, content } = parseMetadata(fileContent)
45
+
46
+ // 3. Determine if file should sync to a target repository
47
+ const shouldSync = shouldSyncToRepo({
48
+ filePath: 'docs/api-guide.md',
49
+ fileMetadata: metadata,
50
+ targetRepo: 'api-gateway',
51
+ sourceRepo: 'codex.fractary.com',
52
+ rules: config.rules
53
+ })
54
+
55
+ console.log(`Sync to api-gateway: ${shouldSync}`)
56
+ ```
57
+
58
+ ## Core Concepts
59
+
60
+ ### Metadata Parsing
61
+
62
+ The SDK parses YAML frontmatter from markdown files to extract sync rules and metadata:
63
+
64
+ ```yaml
65
+ ---
66
+ org: fractary
67
+ system: api-gateway
68
+ codex_sync_include: ['api-*', 'core-*']
69
+ codex_sync_exclude: ['*-test', '*-dev']
70
+ visibility: internal
71
+ tags: [api, rest]
72
+ ---
73
+
74
+ # API Documentation
75
+ ```
76
+
77
+ ```typescript
78
+ import { parseMetadata } from '@fractary/codex'
79
+
80
+ const result = parseMetadata(markdown)
81
+ console.log(result.metadata.codex_sync_include) // ['api-*', 'core-*']
82
+ ```
83
+
84
+ ### Pattern Matching
85
+
86
+ Glob patterns determine which repositories receive which files:
87
+
88
+ ```typescript
89
+ import { matchPattern, matchAnyPattern } from '@fractary/codex'
90
+
91
+ // Single pattern
92
+ matchPattern('api-*', 'api-gateway') // true
93
+ matchPattern('api-*', 'web-app') // false
94
+
95
+ // Multiple patterns
96
+ matchAnyPattern(['api-*', 'core-*'], 'api-gateway') // true
97
+ matchAnyPattern(['api-*', 'core-*'], 'web-app') // false
98
+
99
+ // Special: match all
100
+ matchAnyPattern(['*'], 'anything') // true
101
+ ```
102
+
103
+ ### Sync Routing
104
+
105
+ Determine which repositories should receive a file based on frontmatter rules:
106
+
107
+ ```typescript
108
+ import { shouldSyncToRepo } from '@fractary/codex'
109
+
110
+ const shouldSync = shouldSyncToRepo({
111
+ filePath: 'docs/api-guide.md',
112
+ fileMetadata: {
113
+ codex_sync_include: ['api-*', 'core-*'],
114
+ codex_sync_exclude: ['*-test']
115
+ },
116
+ targetRepo: 'api-gateway',
117
+ sourceRepo: 'codex.fractary.com'
118
+ })
119
+
120
+ // Returns: true (matches 'api-*' and not excluded)
121
+ ```
122
+
123
+ ### Configuration
124
+
125
+ The SDK supports multi-source configuration:
126
+
127
+ ```typescript
128
+ import { loadConfig, resolveOrganization } from '@fractary/codex'
129
+
130
+ // Auto-detect organization from repo name
131
+ const org = resolveOrganization({
132
+ repoName: 'codex.fractary.com'
133
+ }) // Returns: 'fractary'
134
+
135
+ // Load configuration
136
+ const config = loadConfig({
137
+ organizationSlug: 'fractary'
138
+ })
139
+
140
+ console.log(config)
141
+ /*
142
+ {
143
+ organizationSlug: 'fractary',
144
+ directories: {
145
+ source: '.fractary',
146
+ target: '.fractary',
147
+ systems: '.fractary/systems'
148
+ },
149
+ rules: {
150
+ preventSelfSync: true,
151
+ preventCodexSync: true,
152
+ allowProjectOverrides: true,
153
+ autoSyncPatterns: []
154
+ }
155
+ }
156
+ */
157
+ ```
158
+
159
+ ## API Reference
160
+
161
+ ### Metadata Parsing
162
+
163
+ - `parseMetadata(content, options?)` - Parse YAML frontmatter from markdown
164
+ - `hasFrontmatter(content)` - Check if content has frontmatter
165
+ - `validateMetadata(metadata)` - Validate metadata against schema
166
+ - `extractRawFrontmatter(content)` - Extract raw frontmatter string
167
+
168
+ ### Pattern Matching
169
+
170
+ - `matchPattern(pattern, value)` - Match a single glob pattern
171
+ - `matchAnyPattern(patterns, value)` - Match against multiple patterns
172
+ - `filterByPatterns(patterns, values)` - Filter array by patterns
173
+ - `evaluatePatterns({ value, include, exclude })` - Evaluate include/exclude rules
174
+
175
+ ### Configuration
176
+
177
+ - `loadConfig(options)` - Load configuration from all sources
178
+ - `resolveOrganization(options)` - Resolve organization slug
179
+ - `extractOrgFromRepoName(repoName)` - Extract org from repo name pattern
180
+ - `getDefaultConfig(orgSlug)` - Get default configuration
181
+
182
+ ### Routing
183
+
184
+ - `shouldSyncToRepo(options)` - Determine if file should sync to repo
185
+ - `getTargetRepos(options)` - Get all repos that should receive a file
186
+
187
+ ## Configuration
188
+
189
+ ### Environment Variables
190
+
191
+ - `ORGANIZATION_SLUG` - Organization identifier
192
+ - `CODEX_ORG_SLUG` - Alternative organization identifier
193
+ - `CODEX_SOURCE_DIR` - Source directory (default: `.{org}`)
194
+ - `CODEX_TARGET_DIR` - Target directory (default: `.{org}`)
195
+ - `CODEX_PREVENT_SELF_SYNC` - Prevent self-sync (default: `true`)
196
+ - `CODEX_ALLOW_PROJECT_OVERRIDES` - Allow project overrides (default: `true`)
197
+
198
+ ### Auto-Sync Patterns
199
+
200
+ Configure patterns that automatically sync to repositories:
201
+
202
+ ```typescript
203
+ const config = loadConfig({
204
+ organizationSlug: 'fractary'
205
+ })
206
+
207
+ config.rules.autoSyncPatterns = [
208
+ {
209
+ pattern: '*/docs/schema/*.json',
210
+ include: ['*'], // All repos
211
+ exclude: []
212
+ },
213
+ {
214
+ pattern: '*/security/**/*.md',
215
+ include: ['*'],
216
+ exclude: ['*-public']
217
+ }
218
+ ]
219
+ ```
220
+
221
+ ## Development
222
+
223
+ ```bash
224
+ # Install dependencies
225
+ npm install
226
+
227
+ # Build
228
+ npm run build
229
+
230
+ # Test
231
+ npm test
232
+
233
+ # Test with coverage
234
+ npm run test:coverage
235
+
236
+ # Type check
237
+ npm run typecheck
238
+ ```
239
+
240
+ ## Project Structure
241
+
242
+ ```
243
+ src/
244
+ ├── core/
245
+ │ ├── metadata/ # Frontmatter parsing
246
+ │ ├── patterns/ # Pattern matching
247
+ │ ├── routing/ # Sync routing logic
248
+ │ └── config/ # Configuration system
249
+ ├── schemas/ # Zod schemas
250
+ ├── errors/ # Error classes
251
+ └── index.ts # Main exports
252
+
253
+ tests/
254
+ ├── unit/ # Unit tests
255
+ └── fixtures/ # Test fixtures
256
+ ```
257
+
258
+ ## Specifications
259
+
260
+ Detailed specifications are available in `/docs/specs/`:
261
+
262
+ - [SPEC-00001: Core SDK Overview](./docs/specs/SPEC-00001-core-sdk-overview.md)
263
+ - [SPEC-00002: Metadata Parsing](./docs/specs/SPEC-00002-metadata-parsing.md)
264
+ - [SPEC-00003: Pattern Matching](./docs/specs/SPEC-00003-pattern-matching.md)
265
+ - [SPEC-00004: Routing & Distribution](./docs/specs/SPEC-00004-routing-distribution.md)
266
+ - [SPEC-00005: Configuration System](./docs/specs/SPEC-00005-configuration-system.md)
267
+
268
+ ## Related Projects
269
+
270
+ - **fractary-cli** - Unified CLI for all Fractary tools (coming soon)
271
+ - **forge-bundle-codex-github-core** - GitHub Actions workflows for codex sync
272
+ - **forge-bundle-codex-claude-agents** - Claude Code agents for codex management
273
+
274
+ ## License
275
+
276
+ MIT © Fractary Engineering
277
+
278
+ ## Contributing
279
+
280
+ This is part of the Fractary ecosystem. For issues or contributions, please refer to the [main repository](https://github.com/fractary/codex).
package/dist/index.cjs ADDED
@@ -0,0 +1,416 @@
1
+ 'use strict';
2
+
3
+ var zod = require('zod');
4
+ var yaml = require('js-yaml');
5
+ var micromatch = require('micromatch');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var yaml__default = /*#__PURE__*/_interopDefault(yaml);
10
+
11
+ // src/errors/CodexError.ts
12
+ var CodexError = class _CodexError extends Error {
13
+ constructor(message, options) {
14
+ super(message, options);
15
+ this.name = "CodexError";
16
+ Object.setPrototypeOf(this, _CodexError.prototype);
17
+ }
18
+ };
19
+
20
+ // src/errors/ConfigurationError.ts
21
+ var ConfigurationError = class _ConfigurationError extends CodexError {
22
+ constructor(message, options) {
23
+ super(message, options);
24
+ this.name = "ConfigurationError";
25
+ Object.setPrototypeOf(this, _ConfigurationError.prototype);
26
+ }
27
+ };
28
+
29
+ // src/errors/ValidationError.ts
30
+ var ValidationError = class _ValidationError extends CodexError {
31
+ constructor(message, options) {
32
+ super(message, options);
33
+ this.name = "ValidationError";
34
+ Object.setPrototypeOf(this, _ValidationError.prototype);
35
+ }
36
+ };
37
+ var MetadataSchema = zod.z.object({
38
+ // Organizational
39
+ org: zod.z.string().optional(),
40
+ system: zod.z.string().optional(),
41
+ // Sync rules
42
+ codex_sync_include: zod.z.array(zod.z.string()).optional(),
43
+ codex_sync_exclude: zod.z.array(zod.z.string()).optional(),
44
+ // Metadata
45
+ title: zod.z.string().optional(),
46
+ description: zod.z.string().optional(),
47
+ visibility: zod.z.enum(["public", "internal", "private"]).optional(),
48
+ audience: zod.z.array(zod.z.string()).optional(),
49
+ tags: zod.z.array(zod.z.string()).optional(),
50
+ // Timestamps
51
+ created: zod.z.string().optional(),
52
+ // ISO 8601 date string
53
+ updated: zod.z.string().optional()
54
+ }).passthrough();
55
+ var AutoSyncPatternSchema = zod.z.object({
56
+ pattern: zod.z.string(),
57
+ include: zod.z.array(zod.z.string()),
58
+ exclude: zod.z.array(zod.z.string()).optional()
59
+ });
60
+ var SyncRulesSchema = zod.z.object({
61
+ autoSyncPatterns: zod.z.array(AutoSyncPatternSchema).optional(),
62
+ preventSelfSync: zod.z.boolean().optional(),
63
+ preventCodexSync: zod.z.boolean().optional(),
64
+ allowProjectOverrides: zod.z.boolean().optional(),
65
+ defaultInclude: zod.z.array(zod.z.string()).optional(),
66
+ defaultExclude: zod.z.array(zod.z.string()).optional()
67
+ });
68
+ var CodexConfigSchema = zod.z.object({
69
+ organizationSlug: zod.z.string(),
70
+ directories: zod.z.object({
71
+ source: zod.z.string().optional(),
72
+ target: zod.z.string().optional(),
73
+ systems: zod.z.string().optional()
74
+ }).optional(),
75
+ rules: SyncRulesSchema.optional()
76
+ }).strict();
77
+ function parseMetadata(content, options = {}) {
78
+ const { strict = true, normalize = true } = options;
79
+ const normalizedContent = normalize ? content.replace(/\r\n/g, "\n") : content;
80
+ const frontmatterMatch = normalizedContent.match(
81
+ /^---\n([\s\S]*?)\n---\n([\s\S]*)$/
82
+ );
83
+ if (!frontmatterMatch) {
84
+ return {
85
+ metadata: {},
86
+ content: normalizedContent,
87
+ raw: ""
88
+ };
89
+ }
90
+ const rawFrontmatter = frontmatterMatch[1];
91
+ const documentContent = frontmatterMatch[2];
92
+ try {
93
+ const parsed = yaml__default.default.load(rawFrontmatter);
94
+ const normalized = normalizeLegacyMetadata(parsed);
95
+ const metadata = strict ? MetadataSchema.parse(normalized) : MetadataSchema.safeParse(normalized).data || {};
96
+ return {
97
+ metadata,
98
+ content: documentContent,
99
+ raw: rawFrontmatter
100
+ };
101
+ } catch (error) {
102
+ if (strict) {
103
+ throw new ValidationError(
104
+ `Invalid frontmatter: ${error instanceof Error ? error.message : String(error)}`,
105
+ { cause: error }
106
+ );
107
+ }
108
+ return {
109
+ metadata: {},
110
+ content: documentContent,
111
+ raw: rawFrontmatter
112
+ };
113
+ }
114
+ }
115
+ function normalizeLegacyMetadata(parsed) {
116
+ const normalized = { ...parsed };
117
+ if (parsed.codex?.includes && !parsed.codex_sync_include) {
118
+ normalized.codex_sync_include = parsed.codex.includes;
119
+ }
120
+ if (parsed.codex?.excludes && !parsed.codex_sync_exclude) {
121
+ normalized.codex_sync_exclude = parsed.codex.excludes;
122
+ }
123
+ return normalized;
124
+ }
125
+ function hasFrontmatter(content) {
126
+ const normalized = content.replace(/\r\n/g, "\n");
127
+ return /^---\n[\s\S]*?\n---\n/.test(normalized);
128
+ }
129
+ function validateMetadata(metadata) {
130
+ const result = MetadataSchema.safeParse(metadata);
131
+ if (result.success) {
132
+ return { valid: true };
133
+ }
134
+ return {
135
+ valid: false,
136
+ errors: result.error.issues.map((issue) => issue.message)
137
+ };
138
+ }
139
+ function extractRawFrontmatter(content) {
140
+ const normalized = content.replace(/\r\n/g, "\n");
141
+ const match = normalized.match(/^---\n([\s\S]*?)\n---\n/);
142
+ return match && match[1] ? match[1] : null;
143
+ }
144
+ function matchPattern(pattern, value) {
145
+ if (pattern === value) return true;
146
+ return micromatch.isMatch(value, pattern);
147
+ }
148
+ function matchAnyPattern(patterns, value) {
149
+ if (patterns.length === 1 && patterns[0] === "*") {
150
+ return true;
151
+ }
152
+ if (patterns.length === 0) {
153
+ return false;
154
+ }
155
+ return patterns.some((pattern) => matchPattern(pattern, value));
156
+ }
157
+ function filterByPatterns(patterns, values) {
158
+ return values.filter((value) => matchAnyPattern(patterns, value));
159
+ }
160
+ function evaluatePatterns(options) {
161
+ const { value, include = [], exclude = [] } = options;
162
+ if (exclude.length > 0 && matchAnyPattern(exclude, value)) {
163
+ return false;
164
+ }
165
+ if (include.length === 0) {
166
+ return true;
167
+ }
168
+ return matchAnyPattern(include, value);
169
+ }
170
+
171
+ // src/core/config/organization.ts
172
+ function resolveOrganization(options = {}) {
173
+ const { orgSlug, repoName, autoDetect = true } = options;
174
+ if (orgSlug) {
175
+ return orgSlug;
176
+ }
177
+ if (autoDetect && repoName) {
178
+ const detected = extractOrgFromRepoName(repoName);
179
+ if (detected) {
180
+ return detected;
181
+ }
182
+ }
183
+ const envOrg = process.env["ORGANIZATION_SLUG"] || process.env["CODEX_ORG_SLUG"];
184
+ if (envOrg) {
185
+ return envOrg;
186
+ }
187
+ throw new ConfigurationError(
188
+ "Organization slug could not be determined. Set ORGANIZATION_SLUG environment variable or pass orgSlug option."
189
+ );
190
+ }
191
+ function extractOrgFromRepoName(repoName) {
192
+ const match = repoName.match(/^codex\.([^.]+)\.[^.]+$/);
193
+ if (match && match[1]) {
194
+ return match[1];
195
+ }
196
+ return null;
197
+ }
198
+
199
+ // src/core/config/defaults.ts
200
+ function getDefaultDirectories(orgSlug) {
201
+ return {
202
+ source: `.${orgSlug}`,
203
+ target: `.${orgSlug}`,
204
+ systems: `.${orgSlug}/systems`
205
+ };
206
+ }
207
+ function getDefaultRules() {
208
+ return {
209
+ autoSyncPatterns: [],
210
+ preventSelfSync: true,
211
+ preventCodexSync: true,
212
+ allowProjectOverrides: true,
213
+ defaultInclude: [],
214
+ defaultExclude: []
215
+ };
216
+ }
217
+ function getDefaultConfig(orgSlug) {
218
+ return {
219
+ organizationSlug: orgSlug,
220
+ directories: getDefaultDirectories(orgSlug),
221
+ rules: getDefaultRules()
222
+ };
223
+ }
224
+
225
+ // src/core/config/loader.ts
226
+ function loadConfig(options = {}) {
227
+ const orgSlug = resolveOrganization({
228
+ orgSlug: options.organizationSlug,
229
+ repoName: options.repoName
230
+ });
231
+ let config = {
232
+ organizationSlug: orgSlug,
233
+ directories: getDefaultDirectories(orgSlug),
234
+ rules: getDefaultRules()
235
+ };
236
+ const envConfig = loadConfigFromEnv(options.env || process.env);
237
+ config = mergeConfigs(config, envConfig);
238
+ return CodexConfigSchema.parse(config);
239
+ }
240
+ function loadConfigFromEnv(env) {
241
+ const config = {};
242
+ if (env["ORGANIZATION_SLUG"] || env["CODEX_ORG_SLUG"]) {
243
+ config.organizationSlug = env["ORGANIZATION_SLUG"] || env["CODEX_ORG_SLUG"];
244
+ }
245
+ if (env["CODEX_SOURCE_DIR"] || env["CODEX_TARGET_DIR"]) {
246
+ config.directories = {
247
+ source: env["CODEX_SOURCE_DIR"],
248
+ target: env["CODEX_TARGET_DIR"]
249
+ };
250
+ }
251
+ const rules = {};
252
+ if (env["CODEX_PREVENT_SELF_SYNC"] !== void 0) {
253
+ rules.preventSelfSync = env["CODEX_PREVENT_SELF_SYNC"] === "true";
254
+ }
255
+ if (env["CODEX_PREVENT_CODEX_SYNC"] !== void 0) {
256
+ rules.preventCodexSync = env["CODEX_PREVENT_CODEX_SYNC"] === "true";
257
+ }
258
+ if (env["CODEX_ALLOW_PROJECT_OVERRIDES"] !== void 0) {
259
+ rules.allowProjectOverrides = env["CODEX_ALLOW_PROJECT_OVERRIDES"] === "true";
260
+ }
261
+ if (Object.keys(rules).length > 0) {
262
+ config.rules = rules;
263
+ }
264
+ return config;
265
+ }
266
+ function mergeConfigs(base, override) {
267
+ return {
268
+ organizationSlug: override.organizationSlug ?? base.organizationSlug,
269
+ directories: {
270
+ ...base.directories,
271
+ ...override.directories
272
+ },
273
+ rules: {
274
+ ...base.rules,
275
+ ...override.rules,
276
+ // Arrays are replaced, not merged
277
+ autoSyncPatterns: override.rules?.autoSyncPatterns ?? base.rules?.autoSyncPatterns,
278
+ defaultInclude: override.rules?.defaultInclude ?? base.rules?.defaultInclude,
279
+ defaultExclude: override.rules?.defaultExclude ?? base.rules?.defaultExclude
280
+ }
281
+ };
282
+ }
283
+
284
+ // src/core/routing/evaluator.ts
285
+ function shouldSyncToRepo(options) {
286
+ const {
287
+ filePath,
288
+ fileMetadata,
289
+ targetRepo,
290
+ sourceRepo,
291
+ rules = getDefaultRules()
292
+ } = options;
293
+ const specialRuleResult = evaluateSpecialRules({
294
+ filePath,
295
+ targetRepo,
296
+ sourceRepo,
297
+ rules
298
+ });
299
+ if (specialRuleResult !== null) {
300
+ return specialRuleResult;
301
+ }
302
+ return evaluateFrontmatterRules({
303
+ metadata: fileMetadata,
304
+ targetRepo,
305
+ allowOverrides: rules.allowProjectOverrides ?? true
306
+ });
307
+ }
308
+ function evaluateSpecialRules(options) {
309
+ const { filePath, targetRepo, sourceRepo, rules } = options;
310
+ if (rules.autoSyncPatterns?.length) {
311
+ const autoSyncResult = evaluateAutoSyncPatterns(
312
+ filePath,
313
+ targetRepo,
314
+ rules.autoSyncPatterns
315
+ );
316
+ if (autoSyncResult !== null) {
317
+ return autoSyncResult;
318
+ }
319
+ }
320
+ if (rules.preventSelfSync) {
321
+ const selfSyncResult = preventSelfSync(filePath, targetRepo);
322
+ if (selfSyncResult !== null) {
323
+ return selfSyncResult;
324
+ }
325
+ }
326
+ if (rules.preventCodexSync) {
327
+ const codexSyncResult = preventCodexSync(targetRepo, sourceRepo);
328
+ if (codexSyncResult !== null) {
329
+ return codexSyncResult;
330
+ }
331
+ }
332
+ return null;
333
+ }
334
+ function evaluateAutoSyncPatterns(filePath, targetRepo, patterns) {
335
+ for (const autoPattern of patterns) {
336
+ if (matchPattern(autoPattern.pattern, filePath)) {
337
+ return evaluatePatterns({
338
+ value: targetRepo,
339
+ include: autoPattern.include,
340
+ ...autoPattern.exclude && { exclude: autoPattern.exclude }
341
+ });
342
+ }
343
+ }
344
+ return null;
345
+ }
346
+ function preventSelfSync(filePath, targetRepo, _sourceRepo) {
347
+ const systemMatch = filePath.match(/systems\/([^/]+)\//);
348
+ if (systemMatch && systemMatch[1]) {
349
+ const systemName = systemMatch[1];
350
+ if (systemName === targetRepo) {
351
+ return false;
352
+ }
353
+ }
354
+ return null;
355
+ }
356
+ function preventCodexSync(targetRepo, sourceRepo) {
357
+ const isCodexRepo = targetRepo === sourceRepo || targetRepo.startsWith("codex.");
358
+ if (isCodexRepo) {
359
+ return false;
360
+ }
361
+ return null;
362
+ }
363
+ function evaluateFrontmatterRules(options) {
364
+ const { metadata, targetRepo, allowOverrides } = options;
365
+ if (!allowOverrides) {
366
+ return false;
367
+ }
368
+ const include = metadata.codex_sync_include || [];
369
+ const exclude = metadata.codex_sync_exclude || [];
370
+ if (include.length === 0) {
371
+ return false;
372
+ }
373
+ return evaluatePatterns({
374
+ value: targetRepo,
375
+ include,
376
+ exclude
377
+ });
378
+ }
379
+ function getTargetRepos(options) {
380
+ const { filePath, fileMetadata, sourceRepo, allRepos, rules } = options;
381
+ return allRepos.filter(
382
+ (targetRepo) => shouldSyncToRepo({
383
+ filePath,
384
+ fileMetadata,
385
+ targetRepo,
386
+ sourceRepo,
387
+ ...rules && { rules }
388
+ })
389
+ );
390
+ }
391
+
392
+ exports.AutoSyncPatternSchema = AutoSyncPatternSchema;
393
+ exports.CodexConfigSchema = CodexConfigSchema;
394
+ exports.CodexError = CodexError;
395
+ exports.ConfigurationError = ConfigurationError;
396
+ exports.MetadataSchema = MetadataSchema;
397
+ exports.SyncRulesSchema = SyncRulesSchema;
398
+ exports.ValidationError = ValidationError;
399
+ exports.evaluatePatterns = evaluatePatterns;
400
+ exports.extractOrgFromRepoName = extractOrgFromRepoName;
401
+ exports.extractRawFrontmatter = extractRawFrontmatter;
402
+ exports.filterByPatterns = filterByPatterns;
403
+ exports.getDefaultConfig = getDefaultConfig;
404
+ exports.getDefaultDirectories = getDefaultDirectories;
405
+ exports.getDefaultRules = getDefaultRules;
406
+ exports.getTargetRepos = getTargetRepos;
407
+ exports.hasFrontmatter = hasFrontmatter;
408
+ exports.loadConfig = loadConfig;
409
+ exports.matchAnyPattern = matchAnyPattern;
410
+ exports.matchPattern = matchPattern;
411
+ exports.parseMetadata = parseMetadata;
412
+ exports.resolveOrganization = resolveOrganization;
413
+ exports.shouldSyncToRepo = shouldSyncToRepo;
414
+ exports.validateMetadata = validateMetadata;
415
+ //# sourceMappingURL=index.cjs.map
416
+ //# sourceMappingURL=index.cjs.map