@fractary/codex 0.12.2 → 0.12.5

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/README.md CHANGED
@@ -14,93 +14,38 @@ npm install @fractary/codex
14
14
  ## Features
15
15
 
16
16
  - **Universal References**: `codex://` URI scheme for cross-project knowledge references
17
- - **Multi-Provider Storage**: Local filesystem, GitHub, and HTTP storage backends
18
- - **Intelligent Caching**: Multi-tier caching (L1 memory, L2 disk, L3 network) with LRU eviction
17
+ - **Multi-Provider Storage**: Local filesystem, GitHub, HTTP, and S3 storage backends
18
+ - **Intelligent Caching**: Multi-tier caching with LRU eviction
19
19
  - **File Synchronization**: Bidirectional sync with conflict detection
20
- - **MCP Integration**: Model Context Protocol server for AI agent integration
21
- - **Permission System**: Fine-grained access control (none/read/write/admin)
22
- - **Migration Tools**: Upgrade from v2.x to v3.0 configuration format
23
- - **Type-Safe**: Full TypeScript support with strict typing
20
+ - **MCP Integration**: Model Context Protocol server for AI agents
21
+ - **Permission System**: Fine-grained access control
22
+ - **Type-Safe**: Full TypeScript support
24
23
 
25
24
  ## Quick Start
26
25
 
27
26
  ```typescript
28
- import {
29
- parseReference,
30
- resolveReference,
31
- CacheManager,
32
- StorageManager,
33
- createMcpServer
34
- } from '@fractary/codex'
27
+ import { parseReference, CacheManager, StorageManager } from '@fractary/codex'
35
28
 
36
29
  // Parse a codex URI
37
30
  const ref = parseReference('codex://myorg/docs/api-guide.md')
38
- console.log(ref.org) // 'myorg'
39
- console.log(ref.path) // 'docs/api-guide.md'
40
31
 
41
- // Create storage and cache managers
32
+ // Create managers
42
33
  const storage = StorageManager.create()
43
34
  const cache = CacheManager.create({ cacheDir: '.fractary/codex/cache' })
35
+ cache.setStorageManager(storage)
44
36
 
45
37
  // Fetch content with caching
46
38
  const content = await cache.get('codex://myorg/docs/api-guide.md')
47
39
  ```
48
40
 
49
- ## Core Modules
50
-
51
- ### References
52
-
53
- ```typescript
54
- import { parseReference, buildUri, validateUri } from '@fractary/codex'
55
-
56
- const ref = parseReference('codex://fractary/codex/docs/api.md')
57
- const uri = buildUri('fractary', 'codex', 'docs/api.md')
58
- const isValid = validateUri('codex://org/project/path.md')
59
- ```
60
-
61
- ### Storage
62
-
63
- ```typescript
64
- import { StorageManager } from '@fractary/codex'
65
-
66
- const storage = StorageManager.create({
67
- providers: [
68
- { type: 'local', basePath: './knowledge' },
69
- { type: 'github', token: process.env.GITHUB_TOKEN },
70
- { type: 'http', baseUrl: 'https://codex.example.com' }
71
- ]
72
- })
73
-
74
- const result = await storage.fetch('codex://org/project/file.md')
75
- ```
76
-
77
- ### Cache
78
-
79
- ```typescript
80
- import { createCacheManager } from '@fractary/codex'
81
-
82
- const cache = createCacheManager({
83
- cacheDir: '.fractary/codex/cache',
84
- maxMemorySize: 50 * 1024 * 1024,
85
- defaultTtl: 3600
86
- })
87
-
88
- const entry = await cache.get('codex://org/project/file.md')
89
- ```
90
-
91
- ### MCP Server
92
-
93
- ```typescript
94
- import { createMcpServer } from '@fractary/codex'
41
+ ## Documentation
95
42
 
96
- const server = createMcpServer({
97
- name: 'codex',
98
- version: '1.0.0',
99
- cacheDir: '.fractary/codex/cache'
100
- })
43
+ **Full documentation**: [docs/sdk/js/](../../docs/sdk/js/)
101
44
 
102
- await server.start()
103
- ```
45
+ - [API Reference](../../docs/sdk/js/#api-reference)
46
+ - [Authentication](../../docs/sdk/js/#authentication)
47
+ - [Troubleshooting](../../docs/sdk/js/#troubleshooting)
48
+ - [Configuration Guide](../../docs/configuration.md)
104
49
 
105
50
  ## Development
106
51
 
@@ -114,125 +59,35 @@ npm run build
114
59
  # Run tests
115
60
  npm test
116
61
 
117
- # Run tests in watch mode
118
- npm run test:watch
119
-
120
62
  # Type check
121
63
  npm run typecheck
122
64
 
123
65
  # Lint
124
66
  npm run lint
125
-
126
- # Format code
127
- npm run format
128
67
  ```
129
68
 
130
- ## Publishing to npm
131
-
132
- ### Prerequisites
133
-
134
- 1. **npm Account**: Create an account on [npmjs.com](https://www.npmjs.com)
135
- 2. **npm Login**: Run `npm login` to authenticate
136
- 3. **Organization Access**: Ensure you have publish access to `@fractary` scope
137
-
138
- ### Manual Publishing
69
+ ## Publishing
139
70
 
140
71
  ```bash
141
72
  # Build and test
142
- npm run build
143
- npm test
144
-
145
- # Check what will be published
146
- npm pack --dry-run
147
-
148
- # Publish to npm (the prepublishOnly script runs build & test automatically)
149
- npm publish
150
-
151
- # For first publish or after scope changes
152
- npm publish --access public
153
- ```
154
-
155
- ### Automated Publishing (CI/CD)
156
-
157
- For automated publishing via GitHub Actions:
158
-
159
- 1. **npm Token**: Generate an Automation token on npmjs.com
160
- 2. **GitHub Secret**: Add `NPM_TOKEN` to repository secrets
161
- 3. **Workflow**: Create `.github/workflows/npm-publish.yml`:
162
-
163
- ```yaml
164
- name: Publish to npm
165
- on:
166
- release:
167
- types: [published]
168
-
169
- jobs:
170
- publish:
171
- runs-on: ubuntu-latest
172
- steps:
173
- - uses: actions/checkout@v4
174
- - uses: actions/setup-node@v4
175
- with:
176
- node-version: '20'
177
- registry-url: 'https://registry.npmjs.org'
178
- - run: npm ci
179
- - run: npm run build
180
- - run: npm test
181
- - run: npm publish --access public
182
- env:
183
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
184
- ```
185
-
186
- ### Version Management
73
+ npm run build && npm test
187
74
 
188
- ```bash
189
- # Bump patch version (0.1.2 -> 0.1.3)
190
- npm version patch
191
-
192
- # Bump minor version (0.1.2 -> 0.2.0)
193
- npm version minor
194
-
195
- # Bump major version (0.1.2 -> 1.0.0)
196
- npm version major
197
-
198
- # This automatically:
199
- # - Updates package.json version
200
- # - Creates a git commit
201
- # - Creates a git tag
202
- ```
203
-
204
- To publish a new version:
205
-
206
- ```bash
207
- # 1. Ensure all changes are committed
208
- # 2. Bump version
75
+ # Bump version
209
76
  npm version patch # or minor/major
210
77
 
211
- # 3. Push with tags
78
+ # Push with tags
212
79
  git push && git push --tags
213
80
 
214
- # 4. Publish to npm
81
+ # Publish
215
82
  npm publish
216
83
  ```
217
84
 
218
- Follow [Semantic Versioning](https://semver.org/):
219
- - **MAJOR**: Breaking API changes
220
- - **MINOR**: New features, backward compatible
221
- - **PATCH**: Bug fixes, backward compatible
222
-
223
85
  ## License
224
86
 
225
87
  MIT - see [LICENSE](LICENSE)
226
88
 
227
- ## Documentation
228
-
229
- - [CLI Integration Guide](../../docs/guides/cli-integration.md) - How to integrate into CLI applications
230
- - [API Reference](../../docs/guides/api-reference.md) - Complete API documentation
231
- - [Configuration Guide](../../docs/guides/configuration.md) - Configuration reference
232
- - [Troubleshooting](../../docs/guides/troubleshooting.md) - Common issues and solutions
233
- - [Examples](../../docs/examples/) - Real-world usage patterns
234
-
235
89
  ## See Also
236
90
 
237
- - [Python SDK](../python/) - `fractary-codex` on PyPI
238
- - [Technical Specifications](../../docs/specs/) - Detailed specs
91
+ - [Python SDK](../py/) - `fractary-codex` on PyPI
92
+ - [CLI](../../cli/) - Command-line interface
93
+ - [MCP Server](../../mcp/server/) - AI agent integration
package/dist/index.cjs CHANGED
@@ -923,12 +923,24 @@ var DirectionalSyncConfigSchema = zod.z.object({
923
923
  /** Patterns to exclude (optional) */
924
924
  exclude: zod.z.array(zod.z.string()).optional()
925
925
  });
926
+ var FromCodexSyncConfigSchema = DirectionalSyncConfigSchema.refine(
927
+ (config) => {
928
+ const includeValid = config.include.every(
929
+ (pattern) => pattern.startsWith("codex://")
930
+ );
931
+ const excludeValid = !config.exclude || config.exclude.every((pattern) => pattern.startsWith("codex://"));
932
+ return includeValid && excludeValid;
933
+ },
934
+ {
935
+ message: 'from_codex patterns must use codex:// URI format (e.g., "codex://{org}/{codex_repo}/docs/**"). Plain paths like "docs/**" are not valid for from_codex.'
936
+ }
937
+ );
926
938
  var DirectionalSyncSchema = zod.z.object({
927
939
  // New format (v0.7.0+) - Recommended
928
- // Patterns for files to push from this project to codex
940
+ // Patterns for files to push from this project to codex (plain paths)
929
941
  to_codex: DirectionalSyncConfigSchema.optional(),
930
- // Patterns for files to pull from codex to this project
931
- from_codex: DirectionalSyncConfigSchema.optional(),
942
+ // Patterns for files to pull from codex to this project (codex:// URIs required)
943
+ from_codex: FromCodexSyncConfigSchema.optional(),
932
944
  // Global exclude patterns (applied to both directions)
933
945
  exclude: zod.z.array(zod.z.string()).optional(),
934
946
  // Legacy format (deprecated, backward compatible)
@@ -956,25 +968,9 @@ var AuthConfigSchema = zod.z.object({
956
968
  /** GitHub authentication configuration */
957
969
  github: GitHubAuthConfigSchema.optional()
958
970
  });
959
- var SourceConfigSchema = zod.z.object({
960
- /** Source type */
961
- type: zod.z.enum(["github", "s3", "http", "local"]),
962
- /** Environment variable containing the authentication token */
963
- token_env: zod.z.string().optional(),
964
- /** Direct token value (not recommended, use token_env instead) */
965
- token: zod.z.string().optional(),
966
- /** Branch to fetch from (for GitHub sources) */
967
- branch: zod.z.string().optional(),
968
- /** Base URL (for HTTP sources) */
969
- base_url: zod.z.string().optional(),
970
- /** Bucket name (for S3 sources) */
971
- bucket: zod.z.string().optional(),
972
- /** Prefix/path within bucket (for S3 sources) */
973
- prefix: zod.z.string().optional()
974
- });
975
- var DependencyConfigSchema = zod.z.object({
976
- /** Sources within this dependency */
977
- sources: zod.z.record(SourceConfigSchema)
971
+ var RemoteConfigSchema = zod.z.object({
972
+ /** Authentication token - can be direct value or ${ENV_VAR} reference */
973
+ token: zod.z.string().optional()
978
974
  });
979
975
  var CodexConfigSchema = zod.z.object({
980
976
  organizationSlug: zod.z.string(),
@@ -992,8 +988,9 @@ var CodexConfigSchema = zod.z.object({
992
988
  archive: ArchiveConfigSchema.optional(),
993
989
  // Authentication configuration
994
990
  auth: AuthConfigSchema.optional(),
995
- // Dependencies configuration (external projects)
996
- dependencies: zod.z.record(DependencyConfigSchema).optional()
991
+ // Remote repositories configuration (external projects)
992
+ // Keys are org/project identifiers, values configure authentication
993
+ remotes: zod.z.record(RemoteConfigSchema).optional()
997
994
  }).strict();
998
995
  var FileSourceSchema = zod.z.object({
999
996
  type: zod.z.enum(["s3", "r2", "gcs", "local"]),
@@ -1238,6 +1235,99 @@ function mergeConfigs(base, override) {
1238
1235
  };
1239
1236
  }
1240
1237
 
1238
+ // src/core/config/sync-presets.ts
1239
+ var CONFIG_SCHEMA_VERSION = "2.0";
1240
+ var SYNC_PATTERN_PRESETS = {
1241
+ standard: {
1242
+ name: "standard",
1243
+ description: "Standard configuration with docs, README, and CLAUDE.md",
1244
+ config: {
1245
+ to_codex: {
1246
+ include: ["docs/**", "README.md", "CLAUDE.md"],
1247
+ exclude: ["*.tmp"]
1248
+ },
1249
+ from_codex: {
1250
+ include: ["codex://{org}/{codex_repo}/docs/**"]
1251
+ }
1252
+ }
1253
+ },
1254
+ minimal: {
1255
+ name: "minimal",
1256
+ description: "Minimal configuration with just docs and README",
1257
+ config: {
1258
+ to_codex: {
1259
+ include: ["docs/**", "README.md"]
1260
+ },
1261
+ from_codex: {
1262
+ include: ["codex://{org}/{codex_repo}/docs/**"]
1263
+ }
1264
+ }
1265
+ }
1266
+ };
1267
+ var DEFAULT_GLOBAL_EXCLUDES = [
1268
+ "**/.git/**",
1269
+ "**/node_modules/**",
1270
+ "**/.env",
1271
+ "**/.env.*",
1272
+ "**/*.log",
1273
+ "**/dist/**",
1274
+ "**/build/**",
1275
+ "**/.DS_Store",
1276
+ "**/credentials.json",
1277
+ "**/*secret*",
1278
+ "**/*password*"
1279
+ ];
1280
+ function getSyncPreset(name) {
1281
+ return SYNC_PATTERN_PRESETS[name];
1282
+ }
1283
+ function getSyncPresetNames() {
1284
+ return Object.keys(SYNC_PATTERN_PRESETS);
1285
+ }
1286
+ function substitutePatternPlaceholders(patterns, org, codexRepo) {
1287
+ if (!org || typeof org !== "string" || org.trim() === "") {
1288
+ throw new ValidationError("org must be a non-empty string");
1289
+ }
1290
+ if (!codexRepo || typeof codexRepo !== "string" || codexRepo.trim() === "") {
1291
+ throw new ValidationError("codexRepo must be a non-empty string");
1292
+ }
1293
+ return patterns.map(
1294
+ (pattern) => pattern.replace(/\{org\}/g, org).replace(/\{codex_repo\}/g, codexRepo)
1295
+ );
1296
+ }
1297
+ function generateSyncConfigFromPreset(presetName, org, codexRepo, options) {
1298
+ const preset = getSyncPreset(presetName);
1299
+ if (!preset) {
1300
+ return void 0;
1301
+ }
1302
+ let toCodexExclude;
1303
+ if (options?.includeGlobalExcludes) {
1304
+ toCodexExclude = [
1305
+ ...preset.config.to_codex.exclude || [],
1306
+ ...DEFAULT_GLOBAL_EXCLUDES
1307
+ ];
1308
+ } else if (preset.config.to_codex.exclude) {
1309
+ toCodexExclude = [...preset.config.to_codex.exclude];
1310
+ }
1311
+ return {
1312
+ to_codex: {
1313
+ include: [...preset.config.to_codex.include],
1314
+ exclude: toCodexExclude
1315
+ },
1316
+ from_codex: {
1317
+ include: substitutePatternPlaceholders(
1318
+ preset.config.from_codex.include,
1319
+ org,
1320
+ codexRepo
1321
+ ),
1322
+ exclude: preset.config.from_codex.exclude ? substitutePatternPlaceholders(
1323
+ preset.config.from_codex.exclude,
1324
+ org,
1325
+ codexRepo
1326
+ ) : void 0
1327
+ }
1328
+ };
1329
+ }
1330
+
1241
1331
  // src/core/routing/evaluator.ts
1242
1332
  init_matcher();
1243
1333
  function shouldSyncToRepo(options) {
@@ -2382,30 +2472,31 @@ var StorageManager = class {
2382
2472
  }
2383
2473
  this.priority = config.priority || (config.filePlugin && config.s3Archive ? ["file-plugin", "local", "s3-archive", "github", "http"] : config.filePlugin ? ["file-plugin", "local", "github", "http"] : config.s3Archive ? ["local", "s3-archive", "github", "http"] : ["local", "github", "http"]);
2384
2474
  }
2475
+ /**
2476
+ * Resolve a token value, expanding ${VAR} references to environment variables
2477
+ */
2478
+ resolveTokenValue(token) {
2479
+ const envVarMatch = token.match(/^\$\{([^}]+)\}$/);
2480
+ if (envVarMatch && envVarMatch[1]) {
2481
+ const envVarName = envVarMatch[1];
2482
+ return process.env[envVarName];
2483
+ }
2484
+ return token;
2485
+ }
2385
2486
  /**
2386
2487
  * Resolve authentication token for a reference
2387
2488
  *
2388
- * Looks up dependency-specific authentication or falls back to default
2489
+ * Looks up remote-specific authentication or falls back to default
2389
2490
  */
2390
2491
  resolveToken(reference) {
2391
2492
  if (!this.codexConfig) {
2392
2493
  return void 0;
2393
2494
  }
2394
- const dependencyKey = `${reference.org}/${reference.project}`;
2395
- if (this.codexConfig.dependencies?.[dependencyKey]) {
2396
- const dependency = this.codexConfig.dependencies[dependencyKey];
2397
- for (const [, sourceConfig] of Object.entries(dependency.sources)) {
2398
- if (sourceConfig.type === "github") {
2399
- if (sourceConfig.token_env) {
2400
- const token = process.env[sourceConfig.token_env];
2401
- if (token) {
2402
- return token;
2403
- }
2404
- }
2405
- if (sourceConfig.token) {
2406
- return sourceConfig.token;
2407
- }
2408
- }
2495
+ const remoteKey = `${reference.org}/${reference.project}`;
2496
+ if (this.codexConfig.remotes?.[remoteKey]?.token) {
2497
+ const token = this.resolveTokenValue(this.codexConfig.remotes[remoteKey].token);
2498
+ if (token) {
2499
+ return token;
2409
2500
  }
2410
2501
  }
2411
2502
  const defaultTokenEnv = this.codexConfig.auth?.github?.default_token_env || "GITHUB_TOKEN";
@@ -2464,7 +2555,7 @@ var StorageManager = class {
2464
2555
  * Fetch content for a reference
2465
2556
  *
2466
2557
  * Tries providers in priority order until one succeeds.
2467
- * Automatically resolves authentication based on dependency configuration.
2558
+ * Automatically resolves authentication based on remote configuration.
2468
2559
  */
2469
2560
  async fetch(reference, options) {
2470
2561
  const resolvedOptions = this.resolveFetchOptions(reference, options);
@@ -2496,7 +2587,7 @@ var StorageManager = class {
2496
2587
  * Check if content exists for a reference
2497
2588
  *
2498
2589
  * Returns true if any provider reports the content exists.
2499
- * Automatically resolves authentication based on dependency configuration.
2590
+ * Automatically resolves authentication based on remote configuration.
2500
2591
  */
2501
2592
  async exists(reference, options) {
2502
2593
  const resolvedOptions = this.resolveFetchOptions(reference, options);
@@ -5142,6 +5233,7 @@ function isValidSize(value) {
5142
5233
  exports.AutoSyncPatternSchema = AutoSyncPatternSchema;
5143
5234
  exports.BUILT_IN_TYPES = BUILT_IN_TYPES;
5144
5235
  exports.CODEX_URI_PREFIX = CODEX_URI_PREFIX;
5236
+ exports.CONFIG_SCHEMA_VERSION = CONFIG_SCHEMA_VERSION;
5145
5237
  exports.CacheManager = CacheManager;
5146
5238
  exports.CachePersistence = CachePersistence;
5147
5239
  exports.CodexConfigSchema = CodexConfigSchema;
@@ -5151,6 +5243,7 @@ exports.ConfigurationError = ConfigurationError;
5151
5243
  exports.CustomTypeSchema = CustomTypeSchema;
5152
5244
  exports.DEFAULT_CACHE_DIR = DEFAULT_CACHE_DIR;
5153
5245
  exports.DEFAULT_FETCH_OPTIONS = DEFAULT_FETCH_OPTIONS;
5246
+ exports.DEFAULT_GLOBAL_EXCLUDES = DEFAULT_GLOBAL_EXCLUDES;
5154
5247
  exports.DEFAULT_MIGRATION_OPTIONS = DEFAULT_MIGRATION_OPTIONS;
5155
5248
  exports.DEFAULT_PERMISSION_CONFIG = DEFAULT_PERMISSION_CONFIG;
5156
5249
  exports.DEFAULT_SYNC_CONFIG = DEFAULT_SYNC_CONFIG;
@@ -5166,6 +5259,7 @@ exports.MetadataSchema = MetadataSchema;
5166
5259
  exports.PERMISSION_LEVEL_ORDER = PERMISSION_LEVEL_ORDER;
5167
5260
  exports.PermissionDeniedError = PermissionDeniedError;
5168
5261
  exports.PermissionManager = PermissionManager;
5262
+ exports.SYNC_PATTERN_PRESETS = SYNC_PATTERN_PRESETS;
5169
5263
  exports.StorageManager = StorageManager;
5170
5264
  exports.SyncManager = SyncManager;
5171
5265
  exports.SyncRulesSchema = SyncRulesSchema;
@@ -5221,6 +5315,7 @@ exports.formatPlanSummary = formatPlanSummary;
5221
5315
  exports.formatSeconds = formatSeconds;
5222
5316
  exports.generateMigrationReport = generateMigrationReport;
5223
5317
  exports.generateReferenceMigrationSummary = generateReferenceMigrationSummary;
5318
+ exports.generateSyncConfigFromPreset = generateSyncConfigFromPreset;
5224
5319
  exports.getBuiltInType = getBuiltInType;
5225
5320
  exports.getBuiltInTypeNames = getBuiltInTypeNames;
5226
5321
  exports.getCacheEntryAge = getCacheEntryAge;
@@ -5240,6 +5335,8 @@ exports.getMigrationRequirements = getMigrationRequirements;
5240
5335
  exports.getPlanStats = getPlanStats;
5241
5336
  exports.getRelativeCachePath = getRelativeCachePath;
5242
5337
  exports.getRemainingTtl = getRemainingTtl;
5338
+ exports.getSyncPreset = getSyncPreset;
5339
+ exports.getSyncPresetNames = getSyncPresetNames;
5243
5340
  exports.getTargetRepos = getTargetRepos;
5244
5341
  exports.hasContentChanged = hasContentChanged;
5245
5342
  exports.hasEnvVars = hasEnvVars;
@@ -5291,6 +5388,7 @@ exports.setDefaultCacheManager = setDefaultCacheManager;
5291
5388
  exports.setDefaultPermissionManager = setDefaultPermissionManager;
5292
5389
  exports.setDefaultStorageManager = setDefaultStorageManager;
5293
5390
  exports.shouldSyncToRepo = shouldSyncToRepo;
5391
+ exports.substitutePatternPlaceholders = substitutePatternPlaceholders;
5294
5392
  exports.summarizeEvaluations = summarizeEvaluations;
5295
5393
  exports.touchCacheEntry = touchCacheEntry;
5296
5394
  exports.validateCustomTypes = validateCustomTypes;