@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/dist/index.js ADDED
@@ -0,0 +1,388 @@
1
+ import { z } from 'zod';
2
+ import yaml from 'js-yaml';
3
+ import { isMatch } from 'micromatch';
4
+
5
+ // src/errors/CodexError.ts
6
+ var CodexError = class _CodexError extends Error {
7
+ constructor(message, options) {
8
+ super(message, options);
9
+ this.name = "CodexError";
10
+ Object.setPrototypeOf(this, _CodexError.prototype);
11
+ }
12
+ };
13
+
14
+ // src/errors/ConfigurationError.ts
15
+ var ConfigurationError = class _ConfigurationError extends CodexError {
16
+ constructor(message, options) {
17
+ super(message, options);
18
+ this.name = "ConfigurationError";
19
+ Object.setPrototypeOf(this, _ConfigurationError.prototype);
20
+ }
21
+ };
22
+
23
+ // src/errors/ValidationError.ts
24
+ var ValidationError = class _ValidationError extends CodexError {
25
+ constructor(message, options) {
26
+ super(message, options);
27
+ this.name = "ValidationError";
28
+ Object.setPrototypeOf(this, _ValidationError.prototype);
29
+ }
30
+ };
31
+ var MetadataSchema = z.object({
32
+ // Organizational
33
+ org: z.string().optional(),
34
+ system: z.string().optional(),
35
+ // Sync rules
36
+ codex_sync_include: z.array(z.string()).optional(),
37
+ codex_sync_exclude: z.array(z.string()).optional(),
38
+ // Metadata
39
+ title: z.string().optional(),
40
+ description: z.string().optional(),
41
+ visibility: z.enum(["public", "internal", "private"]).optional(),
42
+ audience: z.array(z.string()).optional(),
43
+ tags: z.array(z.string()).optional(),
44
+ // Timestamps
45
+ created: z.string().optional(),
46
+ // ISO 8601 date string
47
+ updated: z.string().optional()
48
+ }).passthrough();
49
+ var AutoSyncPatternSchema = z.object({
50
+ pattern: z.string(),
51
+ include: z.array(z.string()),
52
+ exclude: z.array(z.string()).optional()
53
+ });
54
+ var SyncRulesSchema = z.object({
55
+ autoSyncPatterns: z.array(AutoSyncPatternSchema).optional(),
56
+ preventSelfSync: z.boolean().optional(),
57
+ preventCodexSync: z.boolean().optional(),
58
+ allowProjectOverrides: z.boolean().optional(),
59
+ defaultInclude: z.array(z.string()).optional(),
60
+ defaultExclude: z.array(z.string()).optional()
61
+ });
62
+ var CodexConfigSchema = z.object({
63
+ organizationSlug: z.string(),
64
+ directories: z.object({
65
+ source: z.string().optional(),
66
+ target: z.string().optional(),
67
+ systems: z.string().optional()
68
+ }).optional(),
69
+ rules: SyncRulesSchema.optional()
70
+ }).strict();
71
+ function parseMetadata(content, options = {}) {
72
+ const { strict = true, normalize = true } = options;
73
+ const normalizedContent = normalize ? content.replace(/\r\n/g, "\n") : content;
74
+ const frontmatterMatch = normalizedContent.match(
75
+ /^---\n([\s\S]*?)\n---\n([\s\S]*)$/
76
+ );
77
+ if (!frontmatterMatch) {
78
+ return {
79
+ metadata: {},
80
+ content: normalizedContent,
81
+ raw: ""
82
+ };
83
+ }
84
+ const rawFrontmatter = frontmatterMatch[1];
85
+ const documentContent = frontmatterMatch[2];
86
+ try {
87
+ const parsed = yaml.load(rawFrontmatter);
88
+ const normalized = normalizeLegacyMetadata(parsed);
89
+ const metadata = strict ? MetadataSchema.parse(normalized) : MetadataSchema.safeParse(normalized).data || {};
90
+ return {
91
+ metadata,
92
+ content: documentContent,
93
+ raw: rawFrontmatter
94
+ };
95
+ } catch (error) {
96
+ if (strict) {
97
+ throw new ValidationError(
98
+ `Invalid frontmatter: ${error instanceof Error ? error.message : String(error)}`,
99
+ { cause: error }
100
+ );
101
+ }
102
+ return {
103
+ metadata: {},
104
+ content: documentContent,
105
+ raw: rawFrontmatter
106
+ };
107
+ }
108
+ }
109
+ function normalizeLegacyMetadata(parsed) {
110
+ const normalized = { ...parsed };
111
+ if (parsed.codex?.includes && !parsed.codex_sync_include) {
112
+ normalized.codex_sync_include = parsed.codex.includes;
113
+ }
114
+ if (parsed.codex?.excludes && !parsed.codex_sync_exclude) {
115
+ normalized.codex_sync_exclude = parsed.codex.excludes;
116
+ }
117
+ return normalized;
118
+ }
119
+ function hasFrontmatter(content) {
120
+ const normalized = content.replace(/\r\n/g, "\n");
121
+ return /^---\n[\s\S]*?\n---\n/.test(normalized);
122
+ }
123
+ function validateMetadata(metadata) {
124
+ const result = MetadataSchema.safeParse(metadata);
125
+ if (result.success) {
126
+ return { valid: true };
127
+ }
128
+ return {
129
+ valid: false,
130
+ errors: result.error.issues.map((issue) => issue.message)
131
+ };
132
+ }
133
+ function extractRawFrontmatter(content) {
134
+ const normalized = content.replace(/\r\n/g, "\n");
135
+ const match = normalized.match(/^---\n([\s\S]*?)\n---\n/);
136
+ return match && match[1] ? match[1] : null;
137
+ }
138
+ function matchPattern(pattern, value) {
139
+ if (pattern === value) return true;
140
+ return isMatch(value, pattern);
141
+ }
142
+ function matchAnyPattern(patterns, value) {
143
+ if (patterns.length === 1 && patterns[0] === "*") {
144
+ return true;
145
+ }
146
+ if (patterns.length === 0) {
147
+ return false;
148
+ }
149
+ return patterns.some((pattern) => matchPattern(pattern, value));
150
+ }
151
+ function filterByPatterns(patterns, values) {
152
+ return values.filter((value) => matchAnyPattern(patterns, value));
153
+ }
154
+ function evaluatePatterns(options) {
155
+ const { value, include = [], exclude = [] } = options;
156
+ if (exclude.length > 0 && matchAnyPattern(exclude, value)) {
157
+ return false;
158
+ }
159
+ if (include.length === 0) {
160
+ return true;
161
+ }
162
+ return matchAnyPattern(include, value);
163
+ }
164
+
165
+ // src/core/config/organization.ts
166
+ function resolveOrganization(options = {}) {
167
+ const { orgSlug, repoName, autoDetect = true } = options;
168
+ if (orgSlug) {
169
+ return orgSlug;
170
+ }
171
+ if (autoDetect && repoName) {
172
+ const detected = extractOrgFromRepoName(repoName);
173
+ if (detected) {
174
+ return detected;
175
+ }
176
+ }
177
+ const envOrg = process.env["ORGANIZATION_SLUG"] || process.env["CODEX_ORG_SLUG"];
178
+ if (envOrg) {
179
+ return envOrg;
180
+ }
181
+ throw new ConfigurationError(
182
+ "Organization slug could not be determined. Set ORGANIZATION_SLUG environment variable or pass orgSlug option."
183
+ );
184
+ }
185
+ function extractOrgFromRepoName(repoName) {
186
+ const match = repoName.match(/^codex\.([^.]+)\.[^.]+$/);
187
+ if (match && match[1]) {
188
+ return match[1];
189
+ }
190
+ return null;
191
+ }
192
+
193
+ // src/core/config/defaults.ts
194
+ function getDefaultDirectories(orgSlug) {
195
+ return {
196
+ source: `.${orgSlug}`,
197
+ target: `.${orgSlug}`,
198
+ systems: `.${orgSlug}/systems`
199
+ };
200
+ }
201
+ function getDefaultRules() {
202
+ return {
203
+ autoSyncPatterns: [],
204
+ preventSelfSync: true,
205
+ preventCodexSync: true,
206
+ allowProjectOverrides: true,
207
+ defaultInclude: [],
208
+ defaultExclude: []
209
+ };
210
+ }
211
+ function getDefaultConfig(orgSlug) {
212
+ return {
213
+ organizationSlug: orgSlug,
214
+ directories: getDefaultDirectories(orgSlug),
215
+ rules: getDefaultRules()
216
+ };
217
+ }
218
+
219
+ // src/core/config/loader.ts
220
+ function loadConfig(options = {}) {
221
+ const orgSlug = resolveOrganization({
222
+ orgSlug: options.organizationSlug,
223
+ repoName: options.repoName
224
+ });
225
+ let config = {
226
+ organizationSlug: orgSlug,
227
+ directories: getDefaultDirectories(orgSlug),
228
+ rules: getDefaultRules()
229
+ };
230
+ const envConfig = loadConfigFromEnv(options.env || process.env);
231
+ config = mergeConfigs(config, envConfig);
232
+ return CodexConfigSchema.parse(config);
233
+ }
234
+ function loadConfigFromEnv(env) {
235
+ const config = {};
236
+ if (env["ORGANIZATION_SLUG"] || env["CODEX_ORG_SLUG"]) {
237
+ config.organizationSlug = env["ORGANIZATION_SLUG"] || env["CODEX_ORG_SLUG"];
238
+ }
239
+ if (env["CODEX_SOURCE_DIR"] || env["CODEX_TARGET_DIR"]) {
240
+ config.directories = {
241
+ source: env["CODEX_SOURCE_DIR"],
242
+ target: env["CODEX_TARGET_DIR"]
243
+ };
244
+ }
245
+ const rules = {};
246
+ if (env["CODEX_PREVENT_SELF_SYNC"] !== void 0) {
247
+ rules.preventSelfSync = env["CODEX_PREVENT_SELF_SYNC"] === "true";
248
+ }
249
+ if (env["CODEX_PREVENT_CODEX_SYNC"] !== void 0) {
250
+ rules.preventCodexSync = env["CODEX_PREVENT_CODEX_SYNC"] === "true";
251
+ }
252
+ if (env["CODEX_ALLOW_PROJECT_OVERRIDES"] !== void 0) {
253
+ rules.allowProjectOverrides = env["CODEX_ALLOW_PROJECT_OVERRIDES"] === "true";
254
+ }
255
+ if (Object.keys(rules).length > 0) {
256
+ config.rules = rules;
257
+ }
258
+ return config;
259
+ }
260
+ function mergeConfigs(base, override) {
261
+ return {
262
+ organizationSlug: override.organizationSlug ?? base.organizationSlug,
263
+ directories: {
264
+ ...base.directories,
265
+ ...override.directories
266
+ },
267
+ rules: {
268
+ ...base.rules,
269
+ ...override.rules,
270
+ // Arrays are replaced, not merged
271
+ autoSyncPatterns: override.rules?.autoSyncPatterns ?? base.rules?.autoSyncPatterns,
272
+ defaultInclude: override.rules?.defaultInclude ?? base.rules?.defaultInclude,
273
+ defaultExclude: override.rules?.defaultExclude ?? base.rules?.defaultExclude
274
+ }
275
+ };
276
+ }
277
+
278
+ // src/core/routing/evaluator.ts
279
+ function shouldSyncToRepo(options) {
280
+ const {
281
+ filePath,
282
+ fileMetadata,
283
+ targetRepo,
284
+ sourceRepo,
285
+ rules = getDefaultRules()
286
+ } = options;
287
+ const specialRuleResult = evaluateSpecialRules({
288
+ filePath,
289
+ targetRepo,
290
+ sourceRepo,
291
+ rules
292
+ });
293
+ if (specialRuleResult !== null) {
294
+ return specialRuleResult;
295
+ }
296
+ return evaluateFrontmatterRules({
297
+ metadata: fileMetadata,
298
+ targetRepo,
299
+ allowOverrides: rules.allowProjectOverrides ?? true
300
+ });
301
+ }
302
+ function evaluateSpecialRules(options) {
303
+ const { filePath, targetRepo, sourceRepo, rules } = options;
304
+ if (rules.autoSyncPatterns?.length) {
305
+ const autoSyncResult = evaluateAutoSyncPatterns(
306
+ filePath,
307
+ targetRepo,
308
+ rules.autoSyncPatterns
309
+ );
310
+ if (autoSyncResult !== null) {
311
+ return autoSyncResult;
312
+ }
313
+ }
314
+ if (rules.preventSelfSync) {
315
+ const selfSyncResult = preventSelfSync(filePath, targetRepo);
316
+ if (selfSyncResult !== null) {
317
+ return selfSyncResult;
318
+ }
319
+ }
320
+ if (rules.preventCodexSync) {
321
+ const codexSyncResult = preventCodexSync(targetRepo, sourceRepo);
322
+ if (codexSyncResult !== null) {
323
+ return codexSyncResult;
324
+ }
325
+ }
326
+ return null;
327
+ }
328
+ function evaluateAutoSyncPatterns(filePath, targetRepo, patterns) {
329
+ for (const autoPattern of patterns) {
330
+ if (matchPattern(autoPattern.pattern, filePath)) {
331
+ return evaluatePatterns({
332
+ value: targetRepo,
333
+ include: autoPattern.include,
334
+ ...autoPattern.exclude && { exclude: autoPattern.exclude }
335
+ });
336
+ }
337
+ }
338
+ return null;
339
+ }
340
+ function preventSelfSync(filePath, targetRepo, _sourceRepo) {
341
+ const systemMatch = filePath.match(/systems\/([^/]+)\//);
342
+ if (systemMatch && systemMatch[1]) {
343
+ const systemName = systemMatch[1];
344
+ if (systemName === targetRepo) {
345
+ return false;
346
+ }
347
+ }
348
+ return null;
349
+ }
350
+ function preventCodexSync(targetRepo, sourceRepo) {
351
+ const isCodexRepo = targetRepo === sourceRepo || targetRepo.startsWith("codex.");
352
+ if (isCodexRepo) {
353
+ return false;
354
+ }
355
+ return null;
356
+ }
357
+ function evaluateFrontmatterRules(options) {
358
+ const { metadata, targetRepo, allowOverrides } = options;
359
+ if (!allowOverrides) {
360
+ return false;
361
+ }
362
+ const include = metadata.codex_sync_include || [];
363
+ const exclude = metadata.codex_sync_exclude || [];
364
+ if (include.length === 0) {
365
+ return false;
366
+ }
367
+ return evaluatePatterns({
368
+ value: targetRepo,
369
+ include,
370
+ exclude
371
+ });
372
+ }
373
+ function getTargetRepos(options) {
374
+ const { filePath, fileMetadata, sourceRepo, allRepos, rules } = options;
375
+ return allRepos.filter(
376
+ (targetRepo) => shouldSyncToRepo({
377
+ filePath,
378
+ fileMetadata,
379
+ targetRepo,
380
+ sourceRepo,
381
+ ...rules && { rules }
382
+ })
383
+ );
384
+ }
385
+
386
+ export { AutoSyncPatternSchema, CodexConfigSchema, CodexError, ConfigurationError, MetadataSchema, SyncRulesSchema, ValidationError, evaluatePatterns, extractOrgFromRepoName, extractRawFrontmatter, filterByPatterns, getDefaultConfig, getDefaultDirectories, getDefaultRules, getTargetRepos, hasFrontmatter, loadConfig, matchAnyPattern, matchPattern, parseMetadata, resolveOrganization, shouldSyncToRepo, validateMetadata };
387
+ //# sourceMappingURL=index.js.map
388
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors/CodexError.ts","../src/errors/ConfigurationError.ts","../src/errors/ValidationError.ts","../src/schemas/metadata.ts","../src/schemas/config.ts","../src/core/metadata/parser.ts","../src/core/patterns/matcher.ts","../src/core/config/organization.ts","../src/core/config/defaults.ts","../src/core/config/loader.ts","../src/core/routing/evaluator.ts"],"names":["z"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Base error class for all Codex SDK errors\n */\nexport class CodexError extends Error {\n constructor(\n message: string,\n options?: ErrorOptions\n ) {\n super(message, options)\n this.name = 'CodexError'\n Object.setPrototypeOf(this, CodexError.prototype)\n }\n}\n","import { CodexError } from './CodexError.js'\n\n/**\n * Error thrown when configuration is missing or invalid\n */\nexport class ConfigurationError extends CodexError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options)\n this.name = 'ConfigurationError'\n Object.setPrototypeOf(this, ConfigurationError.prototype)\n }\n}\n","import { CodexError } from './CodexError.js'\n\n/**\n * Error thrown when data validation fails\n */\nexport class ValidationError extends CodexError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options)\n this.name = 'ValidationError'\n Object.setPrototypeOf(this, ValidationError.prototype)\n }\n}\n","import { z } from 'zod'\n\n/**\n * Schema for document frontmatter metadata\n *\n * Based on SPEC-00002: Metadata Parsing\n */\nexport const MetadataSchema = z\n .object({\n // Organizational\n org: z.string().optional(),\n system: z.string().optional(),\n\n // Sync rules\n codex_sync_include: z.array(z.string()).optional(),\n codex_sync_exclude: z.array(z.string()).optional(),\n\n // Metadata\n title: z.string().optional(),\n description: z.string().optional(),\n visibility: z.enum(['public', 'internal', 'private']).optional(),\n audience: z.array(z.string()).optional(),\n tags: z.array(z.string()).optional(),\n\n // Timestamps\n created: z.string().optional(), // ISO 8601 date string\n updated: z.string().optional(),\n })\n .passthrough() // Allow additional fields for extensibility\n\nexport type Metadata = z.infer<typeof MetadataSchema>\n","import { z } from 'zod'\n\n/**\n * Schema for auto-sync patterns\n *\n * Based on SPEC-00004: Routing & Distribution\n */\nexport const AutoSyncPatternSchema = z.object({\n pattern: z.string(),\n include: z.array(z.string()),\n exclude: z.array(z.string()).optional(),\n})\n\nexport type AutoSyncPattern = z.infer<typeof AutoSyncPatternSchema>\n\n/**\n * Schema for sync rules configuration\n *\n * Based on SPEC-00004: Routing & Distribution\n */\nexport const SyncRulesSchema = z.object({\n autoSyncPatterns: z.array(AutoSyncPatternSchema).optional(),\n preventSelfSync: z.boolean().optional(),\n preventCodexSync: z.boolean().optional(),\n allowProjectOverrides: z.boolean().optional(),\n defaultInclude: z.array(z.string()).optional(),\n defaultExclude: z.array(z.string()).optional(),\n})\n\nexport type SyncRules = z.infer<typeof SyncRulesSchema>\n\n/**\n * Schema for Codex configuration\n *\n * Based on SPEC-00005: Configuration System\n */\nexport const CodexConfigSchema = z\n .object({\n organizationSlug: z.string(),\n\n directories: z\n .object({\n source: z.string().optional(),\n target: z.string().optional(),\n systems: z.string().optional(),\n })\n .optional(),\n\n rules: SyncRulesSchema.optional(),\n })\n .strict()\n\nexport type CodexConfig = z.infer<typeof CodexConfigSchema>\n","import yaml from 'js-yaml'\nimport { MetadataSchema, type Metadata } from '../../schemas/metadata.js'\nimport { ValidationError } from '../../errors/index.js'\n\nexport interface ParseMetadataOptions {\n strict?: boolean // Throw on validation errors (default: true)\n normalize?: boolean // Normalize line endings (default: true)\n}\n\nexport interface ParseResult {\n metadata: Metadata\n content: string // Document content without frontmatter\n raw: string // Raw frontmatter block\n}\n\n/**\n * Extracts and parses YAML frontmatter from markdown content\n *\n * Based on SPEC-00002: Metadata Parsing\n *\n * @param content - Markdown file content\n * @param options - Parsing options\n * @returns Parsed metadata and content\n * @throws ValidationError if frontmatter is malformed (in strict mode)\n */\nexport function parseMetadata(\n content: string,\n options: ParseMetadataOptions = {}\n): ParseResult {\n const { strict = true, normalize = true } = options\n\n // Normalize line endings (CRLF → LF)\n const normalizedContent = normalize\n ? content.replace(/\\r\\n/g, '\\n')\n : content\n\n // Extract frontmatter block\n const frontmatterMatch = normalizedContent.match(\n /^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/\n )\n\n if (!frontmatterMatch) {\n // No frontmatter found\n return {\n metadata: {},\n content: normalizedContent,\n raw: '',\n }\n }\n\n const rawFrontmatter = frontmatterMatch[1]!\n const documentContent = frontmatterMatch[2]!\n\n try {\n // Parse YAML\n const parsed = yaml.load(rawFrontmatter) as Record<string, unknown>\n\n // Normalize legacy formats\n const normalized = normalizeLegacyMetadata(parsed)\n\n // Validate against schema\n const metadata = strict\n ? MetadataSchema.parse(normalized)\n : MetadataSchema.safeParse(normalized).data || {}\n\n return {\n metadata,\n content: documentContent,\n raw: rawFrontmatter,\n }\n } catch (error) {\n if (strict) {\n throw new ValidationError(\n `Invalid frontmatter: ${error instanceof Error ? error.message : String(error)}`,\n { cause: error }\n )\n }\n\n // Non-strict mode: return empty metadata\n return {\n metadata: {},\n content: documentContent,\n raw: rawFrontmatter,\n }\n }\n}\n\n/**\n * Normalize legacy frontmatter formats to standard format\n *\n * Handles:\n * - Nested codex.includes → codex_sync_include\n * - Nested codex.excludes → codex_sync_exclude\n */\nfunction normalizeLegacyMetadata(parsed: any): any {\n const normalized: any = { ...parsed }\n\n // Handle nested codex.includes → codex_sync_include\n if (parsed.codex?.includes && !parsed.codex_sync_include) {\n normalized.codex_sync_include = parsed.codex.includes\n }\n\n // Handle nested codex.excludes → codex_sync_exclude\n if (parsed.codex?.excludes && !parsed.codex_sync_exclude) {\n normalized.codex_sync_exclude = parsed.codex.excludes\n }\n\n return normalized\n}\n\n/**\n * Check if content has frontmatter\n */\nexport function hasFrontmatter(content: string): boolean {\n const normalized = content.replace(/\\r\\n/g, '\\n')\n return /^---\\n[\\s\\S]*?\\n---\\n/.test(normalized)\n}\n\n/**\n * Validate metadata without parsing content\n */\nexport function validateMetadata(\n metadata: unknown\n): { valid: boolean; errors?: string[] } {\n const result = MetadataSchema.safeParse(metadata)\n\n if (result.success) {\n return { valid: true }\n }\n\n return {\n valid: false,\n errors: result.error.issues.map(issue => issue.message),\n }\n}\n\n/**\n * Extract only frontmatter (no validation)\n */\nexport function extractRawFrontmatter(content: string): string | null {\n const normalized = content.replace(/\\r\\n/g, '\\n')\n const match = normalized.match(/^---\\n([\\s\\S]*?)\\n---\\n/)\n return match && match[1] ? match[1] : null\n}\n","import { isMatch } from 'micromatch'\n\n/**\n * Match a pattern against a value using glob syntax\n *\n * Based on SPEC-00003: Pattern Matching\n *\n * @param pattern - Glob pattern (e.g., \"api-*\", \"core-*\")\n * @param value - Value to test (e.g., \"api-gateway\")\n * @returns true if pattern matches value\n */\nexport function matchPattern(pattern: string, value: string): boolean {\n // Special case: exact match\n if (pattern === value) return true\n\n // Use micromatch for glob pattern matching\n return isMatch(value, pattern)\n}\n\n/**\n * Check if value matches any pattern in array\n *\n * @param patterns - Array of glob patterns\n * @param value - Value to test\n * @returns true if value matches any pattern\n */\nexport function matchAnyPattern(\n patterns: string[],\n value: string\n): boolean {\n // Special case: [*] matches everything\n if (patterns.length === 1 && patterns[0] === '*') {\n return true\n }\n\n // Empty array matches nothing\n if (patterns.length === 0) {\n return false\n }\n\n // Check each pattern\n return patterns.some(pattern => matchPattern(pattern, value))\n}\n\n/**\n * Filter values that match any pattern\n *\n * @param patterns - Array of glob patterns\n * @param values - Array of values to filter\n * @returns Values that match any pattern\n */\nexport function filterByPatterns(\n patterns: string[],\n values: string[]\n): string[] {\n return values.filter(value => matchAnyPattern(patterns, value))\n}\n\n/**\n * Evaluate include/exclude rules\n *\n * @param options - Evaluation options\n * @returns true if value should be included\n */\nexport function evaluatePatterns(options: {\n value: string\n include?: string[]\n exclude?: string[]\n}): boolean {\n const { value, include = [], exclude = [] } = options\n\n // Check exclusions first (exclusions take priority)\n if (exclude.length > 0 && matchAnyPattern(exclude, value)) {\n return false\n }\n\n // Check inclusions\n if (include.length === 0) {\n // No include patterns = include by default\n return true\n }\n\n return matchAnyPattern(include, value)\n}\n","import { ConfigurationError } from '../../errors/index.js'\n\nexport interface ResolveOrgOptions {\n orgSlug?: string // Explicit org slug\n repoName?: string // Repo name for auto-detection\n autoDetect?: boolean // Enable auto-detection (default: true)\n}\n\n/**\n * Resolve organization slug from multiple sources\n *\n * Based on SPEC-00005: Configuration System\n *\n * Priority:\n * 1. Explicit orgSlug parameter\n * 2. Auto-detect from repoName (if enabled)\n * 3. Environment variable (ORGANIZATION_SLUG or CODEX_ORG_SLUG)\n * 4. Throw ConfigurationError if none found\n *\n * @param options - Resolution options\n * @returns Organization slug\n * @throws ConfigurationError if slug cannot be determined\n */\nexport function resolveOrganization(\n options: ResolveOrgOptions = {}\n): string {\n const { orgSlug, repoName, autoDetect = true } = options\n\n // 1. Explicit parameter\n if (orgSlug) {\n return orgSlug\n }\n\n // 2. Auto-detect from repo name\n if (autoDetect && repoName) {\n const detected = extractOrgFromRepoName(repoName)\n if (detected) {\n return detected\n }\n }\n\n // 3. Environment variables\n const envOrg =\n process.env['ORGANIZATION_SLUG'] || process.env['CODEX_ORG_SLUG']\n\n if (envOrg) {\n return envOrg\n }\n\n // 4. Fail - required parameter missing\n throw new ConfigurationError(\n 'Organization slug could not be determined. ' +\n 'Set ORGANIZATION_SLUG environment variable or pass orgSlug option.'\n )\n}\n\n/**\n * Extract org slug from repo name pattern\n *\n * Patterns:\n * - codex.fractary.com → \"fractary\"\n * - codex.acme.ai → \"acme\"\n * - codex.my-org.io → \"my-org\"\n *\n * @param repoName - Repository name\n * @returns Organization slug or null if pattern doesn't match\n */\nexport function extractOrgFromRepoName(repoName: string): string | null {\n // Pattern: codex.{org}.{tld}\n const match = repoName.match(/^codex\\.([^.]+)\\.[^.]+$/)\n\n if (match && match[1]) {\n return match[1]\n }\n\n return null\n}\n","import type { CodexConfig, SyncRules } from '../../schemas/config.js'\n\n/**\n * Get default directory structure\n *\n * Based on SPEC-00005: Configuration System\n */\nexport function getDefaultDirectories(orgSlug: string) {\n return {\n source: `.${orgSlug}`,\n target: `.${orgSlug}`,\n systems: `.${orgSlug}/systems`,\n }\n}\n\n/**\n * Get default sync rules\n *\n * Based on SPEC-00004: Routing & Distribution\n */\nexport function getDefaultRules(): SyncRules {\n return {\n autoSyncPatterns: [],\n preventSelfSync: true,\n preventCodexSync: true,\n allowProjectOverrides: true,\n defaultInclude: [],\n defaultExclude: [],\n }\n}\n\n/**\n * Get default configuration\n *\n * @param orgSlug - Organization slug\n * @returns Default CodexConfig\n */\nexport function getDefaultConfig(orgSlug: string): CodexConfig {\n return {\n organizationSlug: orgSlug,\n directories: getDefaultDirectories(orgSlug),\n rules: getDefaultRules(),\n }\n}\n","import {\n CodexConfigSchema,\n type CodexConfig,\n type SyncRules,\n} from '../../schemas/config.js'\nimport { resolveOrganization } from './organization.js'\nimport { getDefaultDirectories, getDefaultRules } from './defaults.js'\n\nexport interface LoadConfigOptions {\n organizationSlug?: string\n repoName?: string\n env?: Record<string, string | undefined> // Environment variables (default: process.env)\n}\n\n/**\n * Load and resolve configuration from all sources\n *\n * Based on SPEC-00005: Configuration System\n *\n * @param options - Loading options\n * @returns Fully resolved configuration\n */\nexport function loadConfig(options: LoadConfigOptions = {}): CodexConfig {\n // 1. Resolve organization slug\n const orgSlug = resolveOrganization({\n orgSlug: options.organizationSlug,\n repoName: options.repoName,\n })\n\n // 2. Build base config with defaults\n let config: Partial<CodexConfig> = {\n organizationSlug: orgSlug,\n directories: getDefaultDirectories(orgSlug),\n rules: getDefaultRules(),\n }\n\n // 3. Apply environment variable overrides\n const envConfig = loadConfigFromEnv(options.env || process.env)\n config = mergeConfigs(config, envConfig)\n\n // 4. Validate final configuration\n return CodexConfigSchema.parse(config)\n}\n\n/**\n * Load configuration from environment variables\n */\nfunction loadConfigFromEnv(\n env: Record<string, string | undefined>\n): Partial<CodexConfig> {\n const config: Partial<CodexConfig> = {}\n\n // Organization\n if (env['ORGANIZATION_SLUG'] || env['CODEX_ORG_SLUG']) {\n config.organizationSlug = env['ORGANIZATION_SLUG'] || env['CODEX_ORG_SLUG']\n }\n\n // Directories\n if (env['CODEX_SOURCE_DIR'] || env['CODEX_TARGET_DIR']) {\n config.directories = {\n source: env['CODEX_SOURCE_DIR'],\n target: env['CODEX_TARGET_DIR'],\n }\n }\n\n // Rules\n const rules: Partial<SyncRules> = {}\n\n if (env['CODEX_PREVENT_SELF_SYNC'] !== undefined) {\n rules.preventSelfSync = env['CODEX_PREVENT_SELF_SYNC'] === 'true'\n }\n\n if (env['CODEX_PREVENT_CODEX_SYNC'] !== undefined) {\n rules.preventCodexSync = env['CODEX_PREVENT_CODEX_SYNC'] === 'true'\n }\n\n if (env['CODEX_ALLOW_PROJECT_OVERRIDES'] !== undefined) {\n rules.allowProjectOverrides =\n env['CODEX_ALLOW_PROJECT_OVERRIDES'] === 'true'\n }\n\n if (Object.keys(rules).length > 0) {\n config.rules = rules\n }\n\n return config\n}\n\n/**\n * Deep merge two configuration objects\n * Later config overrides earlier config\n */\nfunction mergeConfigs(\n base: Partial<CodexConfig>,\n override: Partial<CodexConfig>\n): Partial<CodexConfig> {\n return {\n organizationSlug: override.organizationSlug ?? base.organizationSlug,\n\n directories: {\n ...base.directories,\n ...override.directories,\n },\n\n rules: {\n ...base.rules,\n ...override.rules,\n\n // Arrays are replaced, not merged\n autoSyncPatterns:\n override.rules?.autoSyncPatterns ?? base.rules?.autoSyncPatterns,\n defaultInclude:\n override.rules?.defaultInclude ?? base.rules?.defaultInclude,\n defaultExclude:\n override.rules?.defaultExclude ?? base.rules?.defaultExclude,\n },\n }\n}\n","import type { Metadata } from '../../schemas/metadata.js'\nimport type { SyncRules, AutoSyncPattern } from '../../schemas/config.js'\nimport { matchPattern, evaluatePatterns } from '../patterns/matcher.js'\nimport { getDefaultRules } from '../config/defaults.js'\n\nexport interface ShouldSyncOptions {\n filePath: string // Path to file being evaluated\n fileMetadata: Metadata // Parsed frontmatter from file\n targetRepo: string // Repository to sync to\n sourceRepo: string // Repository file is from\n rules?: SyncRules // Optional routing rules (defaults applied)\n}\n\n/**\n * Determine if a file should be synced to a target repository\n *\n * Based on SPEC-00004: Routing & Distribution\n *\n * @param options - Evaluation options\n * @returns true if file should sync to targetRepo\n */\nexport function shouldSyncToRepo(options: ShouldSyncOptions): boolean {\n const {\n filePath,\n fileMetadata,\n targetRepo,\n sourceRepo,\n rules = getDefaultRules(),\n } = options\n\n // 1. Check special rules first\n const specialRuleResult = evaluateSpecialRules({\n filePath,\n targetRepo,\n sourceRepo,\n rules,\n })\n\n if (specialRuleResult !== null) {\n return specialRuleResult\n }\n\n // 2. Evaluate frontmatter rules\n return evaluateFrontmatterRules({\n metadata: fileMetadata,\n targetRepo,\n allowOverrides: rules.allowProjectOverrides ?? true,\n })\n}\n\n/**\n * Evaluate special routing rules\n *\n * Returns true/false if a special rule matches, null otherwise\n */\nfunction evaluateSpecialRules(options: {\n filePath: string\n targetRepo: string\n sourceRepo: string\n rules: SyncRules\n}): boolean | null {\n const { filePath, targetRepo, sourceRepo, rules } = options\n\n // Rule 1: Auto-sync patterns (highest priority)\n if (rules.autoSyncPatterns?.length) {\n const autoSyncResult = evaluateAutoSyncPatterns(\n filePath,\n targetRepo,\n rules.autoSyncPatterns\n )\n\n if (autoSyncResult !== null) {\n return autoSyncResult\n }\n }\n\n // Rule 2: Prevent self-sync\n if (rules.preventSelfSync) {\n const selfSyncResult = preventSelfSync(filePath, targetRepo, sourceRepo)\n\n if (selfSyncResult !== null) {\n return selfSyncResult\n }\n }\n\n // Rule 3: Prevent codex sync\n if (rules.preventCodexSync) {\n const codexSyncResult = preventCodexSync(targetRepo, sourceRepo)\n\n if (codexSyncResult !== null) {\n return codexSyncResult\n }\n }\n\n // No special rule applies\n return null\n}\n\n/**\n * Evaluate auto-sync patterns\n */\nfunction evaluateAutoSyncPatterns(\n filePath: string,\n targetRepo: string,\n patterns: AutoSyncPattern[]\n): boolean | null {\n for (const autoPattern of patterns) {\n // Check if file matches auto-sync pattern\n if (matchPattern(autoPattern.pattern, filePath)) {\n // File matches - evaluate repo include/exclude\n return evaluatePatterns({\n value: targetRepo,\n include: autoPattern.include,\n ...(autoPattern.exclude && { exclude: autoPattern.exclude }),\n })\n }\n }\n\n // No auto-sync pattern matched\n return null\n}\n\n/**\n * Prevent system files from syncing to their own repository\n */\nfunction preventSelfSync(\n filePath: string,\n targetRepo: string,\n _sourceRepo: string\n): boolean | null {\n // Extract system name from file path\n // Example: \".fractary/systems/api-gateway/docs/README.md\" → \"api-gateway\"\n const systemMatch = filePath.match(/systems\\/([^/]+)\\//)\n\n if (systemMatch && systemMatch[1]) {\n const systemName = systemMatch[1]\n\n if (systemName === targetRepo) {\n // Prevent: Don't sync system files to their own repo\n return false\n }\n }\n\n // Not a system file, or different system\n return null\n}\n\n/**\n * Prevent files from syncing back to the codex repository\n */\nfunction preventCodexSync(\n targetRepo: string,\n sourceRepo: string\n): boolean | null {\n // Detect if target is the codex repo\n const isCodexRepo =\n targetRepo === sourceRepo || targetRepo.startsWith('codex.')\n\n if (isCodexRepo) {\n return false\n }\n\n return null\n}\n\n/**\n * Evaluate frontmatter sync rules\n */\nfunction evaluateFrontmatterRules(options: {\n metadata: Metadata\n targetRepo: string\n allowOverrides: boolean\n}): boolean {\n const { metadata, targetRepo, allowOverrides } = options\n\n // If project overrides disabled, return false (no sync by default)\n if (!allowOverrides) {\n return false\n }\n\n const include = metadata.codex_sync_include || []\n const exclude = metadata.codex_sync_exclude || []\n\n // If no include rules, don't sync (must be explicit)\n if (include.length === 0) {\n return false\n }\n\n // Evaluate include/exclude patterns\n return evaluatePatterns({\n value: targetRepo,\n include,\n exclude,\n })\n}\n\n/**\n * Determine all repos that should receive a file\n *\n * @param options - Evaluation options\n * @returns Array of repository names that should receive this file\n */\nexport function getTargetRepos(options: {\n filePath: string\n fileMetadata: Metadata\n sourceRepo: string\n allRepos: string[]\n rules?: SyncRules\n}): string[] {\n const { filePath, fileMetadata, sourceRepo, allRepos, rules } = options\n\n return allRepos.filter(targetRepo =>\n shouldSyncToRepo({\n filePath,\n fileMetadata,\n targetRepo,\n sourceRepo,\n ...(rules && { rules }),\n })\n )\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@fractary/codex",
3
+ "version": "0.1.0",
4
+ "description": "Core SDK for Fractary Codex - centralized knowledge management and distribution platform",
5
+ "keywords": [
6
+ "codex",
7
+ "documentation",
8
+ "knowledge-management",
9
+ "sync",
10
+ "fractary"
11
+ ],
12
+ "homepage": "https://github.com/fractary/codex#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/fractary/codex/issues"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/fractary/codex.git"
19
+ },
20
+ "license": "MIT",
21
+ "author": "Fractary Engineering",
22
+ "type": "module",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.js",
27
+ "require": "./dist/index.cjs"
28
+ }
29
+ },
30
+ "main": "./dist/index.cjs",
31
+ "module": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "files": [
34
+ "dist",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "scripts": {
39
+ "build": "tsup",
40
+ "dev": "tsup --watch",
41
+ "test": "vitest run",
42
+ "test:watch": "vitest",
43
+ "test:coverage": "vitest run --coverage",
44
+ "typecheck": "tsc --noEmit",
45
+ "lint": "eslint src",
46
+ "format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
47
+ "prepublishOnly": "npm run build && npm run test"
48
+ },
49
+ "dependencies": {
50
+ "js-yaml": "^4.1.0",
51
+ "micromatch": "^4.0.8",
52
+ "zod": "^3.23.8"
53
+ },
54
+ "devDependencies": {
55
+ "@types/js-yaml": "^4.0.9",
56
+ "@types/micromatch": "^4.0.9",
57
+ "@types/node": "^20.17.9",
58
+ "@typescript-eslint/eslint-plugin": "^8.17.0",
59
+ "@typescript-eslint/parser": "^8.17.0",
60
+ "@vitest/coverage-v8": "^2.1.8",
61
+ "eslint": "^9.17.0",
62
+ "prettier": "^3.4.2",
63
+ "tsup": "^8.3.5",
64
+ "typescript": "^5.7.2",
65
+ "vitest": "^2.1.8"
66
+ },
67
+ "engines": {
68
+ "node": ">=18.0.0"
69
+ },
70
+ "publishConfig": {
71
+ "access": "public"
72
+ }
73
+ }