@fractary/codex 0.8.0 → 0.9.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.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import micromatch3 from 'micromatch';
2
- import path3 from 'path';
2
+ import * as path3 from 'path';
3
+ import path3__default from 'path';
3
4
  import { execFile, execSync } from 'child_process';
4
5
  import { z } from 'zod';
5
6
  import yaml from 'js-yaml';
6
- import fs2 from 'fs/promises';
7
+ import * as fs3 from 'fs/promises';
8
+ import fs3__default from 'fs/promises';
7
9
  import { promisify } from 'util';
8
10
 
9
11
  var __defProp = Object.defineProperty;
@@ -161,7 +163,7 @@ function validatePath(filePath) {
161
163
  return false;
162
164
  }
163
165
  }
164
- const normalized = path3.normalize(filePath);
166
+ const normalized = path3__default.normalize(filePath);
165
167
  if (normalized.startsWith("..") || normalized.includes("/../") || normalized.includes("\\..\\")) {
166
168
  return false;
167
169
  }
@@ -179,7 +181,7 @@ function sanitizePath(filePath) {
179
181
  }
180
182
  sanitized = sanitized.replace(/^\/+/, "");
181
183
  sanitized = sanitized.replace(/^~\//, "");
182
- sanitized = path3.normalize(sanitized);
184
+ sanitized = path3__default.normalize(sanitized);
183
185
  sanitized = sanitized.replace(/\.\.\//g, "").replace(/\.\./g, "");
184
186
  sanitized = sanitized.replace(/^\.\//, "");
185
187
  sanitized = sanitized.replace(/\0/g, "");
@@ -280,10 +282,10 @@ function parseReference(uri, options = {}) {
280
282
  path: filePath
281
283
  };
282
284
  }
283
- function buildUri(org, project, path6) {
285
+ function buildUri(org, project, path7) {
284
286
  const base = `${CODEX_URI_PREFIX}${org}/${project}`;
285
- if (path6) {
286
- const cleanPath = path6.startsWith("/") ? path6.slice(1) : path6;
287
+ if (path7) {
288
+ const cleanPath = path7.startsWith("/") ? path7.slice(1) : path7;
287
289
  return `${base}/${cleanPath}`;
288
290
  }
289
291
  return base;
@@ -354,7 +356,7 @@ function getCurrentContext(options = {}) {
354
356
  return detectCurrentProject(options.cwd);
355
357
  }
356
358
  function calculateCachePath(org, project, filePath, cacheDir) {
357
- return path3.join(cacheDir, org, project, filePath);
359
+ return path3__default.join(cacheDir, org, project, filePath);
358
360
  }
359
361
  function resolveReference(uri, options = {}) {
360
362
  const parsed = parseReference(uri);
@@ -363,7 +365,7 @@ function resolveReference(uri, options = {}) {
363
365
  }
364
366
  const cacheDir = options.cacheDir || DEFAULT_CACHE_DIR;
365
367
  const currentContext = getCurrentContext(options);
366
- const cachePath = parsed.path ? calculateCachePath(parsed.org, parsed.project, parsed.path, cacheDir) : path3.join(cacheDir, parsed.org, parsed.project);
368
+ const cachePath = parsed.path ? calculateCachePath(parsed.org, parsed.project, parsed.path, cacheDir) : path3__default.join(cacheDir, parsed.org, parsed.project);
367
369
  const isCurrentProject = currentContext.org === parsed.org && currentContext.project === parsed.project;
368
370
  const resolved = {
369
371
  ...parsed,
@@ -372,9 +374,45 @@ function resolveReference(uri, options = {}) {
372
374
  };
373
375
  if (isCurrentProject && parsed.path) {
374
376
  resolved.localPath = parsed.path;
377
+ if (options.config) {
378
+ const fileSource = detectFilePluginSource(parsed.path, options.config);
379
+ if (fileSource) {
380
+ resolved.sourceType = "file-plugin";
381
+ resolved.filePluginSource = fileSource.name;
382
+ resolved.localPath = fileSource.fullPath;
383
+ }
384
+ }
375
385
  }
376
386
  return resolved;
377
387
  }
388
+ function detectFilePluginSource(filePath, config) {
389
+ if (!config?.file?.sources) {
390
+ return null;
391
+ }
392
+ for (const [sourceName, source] of Object.entries(config.file.sources)) {
393
+ const basePath = source.local?.base_path;
394
+ if (!basePath) {
395
+ continue;
396
+ }
397
+ const normalizedPath = filePath.replace(/^\.\//, "").replace(/^\//, "");
398
+ const normalizedBasePath = basePath.replace(/^\.\//, "").replace(/^\//, "").replace(/\/$/, "");
399
+ if (normalizedPath.startsWith(normalizedBasePath)) {
400
+ return {
401
+ name: sourceName,
402
+ fullPath: path3__default.join(basePath, normalizedPath.substring(normalizedBasePath.length).replace(/^\//, ""))
403
+ };
404
+ }
405
+ const sourceNameInPath = normalizedBasePath.split("/").pop();
406
+ if (sourceNameInPath && normalizedPath.startsWith(sourceNameInPath + "/")) {
407
+ const pathWithoutSource = normalizedPath.substring(sourceNameInPath.length + 1);
408
+ return {
409
+ name: sourceName,
410
+ fullPath: path3__default.join(basePath, pathWithoutSource)
411
+ };
412
+ }
413
+ }
414
+ return null;
415
+ }
378
416
  function resolveReferences(uris, options = {}) {
379
417
  return uris.map((uri) => resolveReference(uri, options)).filter((r) => r !== null);
380
418
  }
@@ -388,9 +426,9 @@ function getRelativeCachePath(uri) {
388
426
  return null;
389
427
  }
390
428
  if (parsed.path) {
391
- return path3.join(parsed.org, parsed.project, parsed.path);
429
+ return path3__default.join(parsed.org, parsed.project, parsed.path);
392
430
  }
393
- return path3.join(parsed.org, parsed.project);
431
+ return path3__default.join(parsed.org, parsed.project);
394
432
  }
395
433
 
396
434
  // src/types/built-in.ts
@@ -845,8 +883,40 @@ var ArchiveProjectConfigSchema = z.object({
845
883
  var ArchiveConfigSchema = z.object({
846
884
  projects: z.record(ArchiveProjectConfigSchema)
847
885
  });
886
+ var GitHubAuthConfigSchema = z.object({
887
+ /** Default token environment variable name (default: GITHUB_TOKEN) */
888
+ default_token_env: z.string().optional(),
889
+ /** Fallback to public access if authentication fails */
890
+ fallback_to_public: z.boolean().optional()
891
+ });
892
+ var AuthConfigSchema = z.object({
893
+ /** GitHub authentication configuration */
894
+ github: GitHubAuthConfigSchema.optional()
895
+ });
896
+ var SourceConfigSchema = z.object({
897
+ /** Source type */
898
+ type: z.enum(["github", "s3", "http", "local"]),
899
+ /** Environment variable containing the authentication token */
900
+ token_env: z.string().optional(),
901
+ /** Direct token value (not recommended, use token_env instead) */
902
+ token: z.string().optional(),
903
+ /** Branch to fetch from (for GitHub sources) */
904
+ branch: z.string().optional(),
905
+ /** Base URL (for HTTP sources) */
906
+ base_url: z.string().optional(),
907
+ /** Bucket name (for S3 sources) */
908
+ bucket: z.string().optional(),
909
+ /** Prefix/path within bucket (for S3 sources) */
910
+ prefix: z.string().optional()
911
+ });
912
+ var DependencyConfigSchema = z.object({
913
+ /** Sources within this dependency */
914
+ sources: z.record(SourceConfigSchema)
915
+ });
848
916
  var CodexConfigSchema = z.object({
849
917
  organizationSlug: z.string(),
918
+ /** Project name (optional) */
919
+ project: z.string().optional(),
850
920
  directories: z.object({
851
921
  source: z.string().optional(),
852
922
  target: z.string().optional(),
@@ -856,8 +926,47 @@ var CodexConfigSchema = z.object({
856
926
  // Directional sync configuration
857
927
  sync: DirectionalSyncSchema.optional(),
858
928
  // Archive configuration
859
- archive: ArchiveConfigSchema.optional()
929
+ archive: ArchiveConfigSchema.optional(),
930
+ // Authentication configuration
931
+ auth: AuthConfigSchema.optional(),
932
+ // Dependencies configuration (external projects)
933
+ dependencies: z.record(DependencyConfigSchema).optional()
860
934
  }).strict();
935
+ var FileSourceSchema = z.object({
936
+ type: z.enum(["s3", "r2", "gcs", "local"]),
937
+ bucket: z.string().optional(),
938
+ prefix: z.string().optional(),
939
+ region: z.string().optional(),
940
+ local: z.object({
941
+ base_path: z.string()
942
+ }),
943
+ push: z.object({
944
+ compress: z.boolean().optional(),
945
+ keep_local: z.boolean().optional()
946
+ }).optional(),
947
+ auth: z.object({
948
+ profile: z.string().optional()
949
+ }).optional()
950
+ }).refine(
951
+ (data) => {
952
+ if (data.type !== "local" && !data.bucket) {
953
+ return false;
954
+ }
955
+ return true;
956
+ },
957
+ {
958
+ message: "Bucket is required for s3, r2, and gcs storage types",
959
+ path: ["bucket"]
960
+ }
961
+ );
962
+ var FileConfigSchema = z.object({
963
+ schema_version: z.string(),
964
+ sources: z.record(FileSourceSchema)
965
+ });
966
+ z.object({
967
+ file: FileConfigSchema.optional(),
968
+ codex: CodexConfigSchema.optional()
969
+ });
861
970
  function parseMetadata(content, options = {}) {
862
971
  const { strict = true, normalize = true } = options;
863
972
  const normalizedContent = normalize ? content.replace(/\r\n/g, "\n") : content;
@@ -1187,18 +1296,18 @@ function parseCustomDestination(value) {
1187
1296
  );
1188
1297
  }
1189
1298
  const repo = value.substring(0, colonIndex).trim();
1190
- const path6 = value.substring(colonIndex + 1).trim();
1299
+ const path7 = value.substring(colonIndex + 1).trim();
1191
1300
  if (!repo) {
1192
1301
  throw new ValidationError(
1193
1302
  `Invalid custom destination: repository name cannot be empty in "${value}"`
1194
1303
  );
1195
1304
  }
1196
- if (!path6) {
1305
+ if (!path7) {
1197
1306
  throw new ValidationError(
1198
1307
  `Invalid custom destination: path cannot be empty in "${value}"`
1199
1308
  );
1200
1309
  }
1201
- return { repo, path: path6 };
1310
+ return { repo, path: path7 };
1202
1311
  }
1203
1312
  function getCustomSyncDestinations(metadata) {
1204
1313
  const customDestinations = metadata.codex_sync_custom;
@@ -1234,8 +1343,8 @@ function mergeFetchOptions(options) {
1234
1343
  ...options
1235
1344
  };
1236
1345
  }
1237
- function detectContentType(path6) {
1238
- const ext = path6.split(".").pop()?.toLowerCase();
1346
+ function detectContentType(path7) {
1347
+ const ext = path7.split(".").pop()?.toLowerCase();
1239
1348
  const mimeTypes = {
1240
1349
  md: "text/markdown",
1241
1350
  markdown: "text/markdown",
@@ -1295,19 +1404,19 @@ var LocalStorage = class {
1295
1404
  if (!reference.localPath) {
1296
1405
  throw new Error(`No local path for reference: ${reference.uri}`);
1297
1406
  }
1298
- const fullPath = path3.isAbsolute(reference.localPath) ? reference.localPath : path3.join(this.baseDir, reference.localPath);
1407
+ const fullPath = path3__default.isAbsolute(reference.localPath) ? reference.localPath : path3__default.join(this.baseDir, reference.localPath);
1299
1408
  try {
1300
- await fs2.access(fullPath);
1409
+ await fs3__default.access(fullPath);
1301
1410
  } catch {
1302
1411
  throw new Error(`File not found: ${fullPath}`);
1303
1412
  }
1304
- const stats = await fs2.stat(fullPath);
1413
+ const stats = await fs3__default.stat(fullPath);
1305
1414
  if (stats.size > opts.maxSize) {
1306
1415
  throw new Error(
1307
1416
  `File too large: ${stats.size} bytes (max: ${opts.maxSize} bytes)`
1308
1417
  );
1309
1418
  }
1310
- const content = await fs2.readFile(fullPath);
1419
+ const content = await fs3__default.readFile(fullPath);
1311
1420
  return {
1312
1421
  content,
1313
1422
  contentType: detectContentType(reference.localPath),
@@ -1326,9 +1435,9 @@ var LocalStorage = class {
1326
1435
  if (!reference.localPath) {
1327
1436
  return false;
1328
1437
  }
1329
- const fullPath = path3.isAbsolute(reference.localPath) ? reference.localPath : path3.join(this.baseDir, reference.localPath);
1438
+ const fullPath = path3__default.isAbsolute(reference.localPath) ? reference.localPath : path3__default.join(this.baseDir, reference.localPath);
1330
1439
  try {
1331
- await fs2.access(fullPath);
1440
+ await fs3__default.access(fullPath);
1332
1441
  return true;
1333
1442
  } catch {
1334
1443
  return false;
@@ -1338,24 +1447,24 @@ var LocalStorage = class {
1338
1447
  * Read file content as string
1339
1448
  */
1340
1449
  async readText(filePath) {
1341
- const fullPath = path3.isAbsolute(filePath) ? filePath : path3.join(this.baseDir, filePath);
1342
- return fs2.readFile(fullPath, "utf-8");
1450
+ const fullPath = path3__default.isAbsolute(filePath) ? filePath : path3__default.join(this.baseDir, filePath);
1451
+ return fs3__default.readFile(fullPath, "utf-8");
1343
1452
  }
1344
1453
  /**
1345
1454
  * Write content to file
1346
1455
  */
1347
1456
  async write(filePath, content) {
1348
- const fullPath = path3.isAbsolute(filePath) ? filePath : path3.join(this.baseDir, filePath);
1349
- await fs2.mkdir(path3.dirname(fullPath), { recursive: true });
1350
- await fs2.writeFile(fullPath, content);
1457
+ const fullPath = path3__default.isAbsolute(filePath) ? filePath : path3__default.join(this.baseDir, filePath);
1458
+ await fs3__default.mkdir(path3__default.dirname(fullPath), { recursive: true });
1459
+ await fs3__default.writeFile(fullPath, content);
1351
1460
  }
1352
1461
  /**
1353
1462
  * Delete a file
1354
1463
  */
1355
1464
  async delete(filePath) {
1356
- const fullPath = path3.isAbsolute(filePath) ? filePath : path3.join(this.baseDir, filePath);
1465
+ const fullPath = path3__default.isAbsolute(filePath) ? filePath : path3__default.join(this.baseDir, filePath);
1357
1466
  try {
1358
- await fs2.unlink(fullPath);
1467
+ await fs3__default.unlink(fullPath);
1359
1468
  return true;
1360
1469
  } catch {
1361
1470
  return false;
@@ -1365,10 +1474,10 @@ var LocalStorage = class {
1365
1474
  * List files in a directory
1366
1475
  */
1367
1476
  async list(dirPath) {
1368
- const fullPath = path3.isAbsolute(dirPath) ? dirPath : path3.join(this.baseDir, dirPath);
1477
+ const fullPath = path3__default.isAbsolute(dirPath) ? dirPath : path3__default.join(this.baseDir, dirPath);
1369
1478
  try {
1370
- const entries = await fs2.readdir(fullPath, { withFileTypes: true });
1371
- return entries.filter((e) => e.isFile()).map((e) => path3.join(dirPath, e.name));
1479
+ const entries = await fs3__default.readdir(fullPath, { withFileTypes: true });
1480
+ return entries.filter((e) => e.isFile()).map((e) => path3__default.join(dirPath, e.name));
1372
1481
  } catch {
1373
1482
  return [];
1374
1483
  }
@@ -1713,6 +1822,300 @@ var HttpStorage = class {
1713
1822
  function createHttpStorage(options) {
1714
1823
  return new HttpStorage(options);
1715
1824
  }
1825
+
1826
+ // src/file-integration/source-resolver.ts
1827
+ var FileSourceResolver = class {
1828
+ constructor(config) {
1829
+ this.config = config;
1830
+ this.initializeSources();
1831
+ }
1832
+ sources = /* @__PURE__ */ new Map();
1833
+ /**
1834
+ * Initialize sources from config
1835
+ */
1836
+ initializeSources() {
1837
+ if (!this.config.file?.sources) {
1838
+ return;
1839
+ }
1840
+ for (const [name, sourceConfig] of Object.entries(this.config.file.sources)) {
1841
+ const resolved = {
1842
+ name,
1843
+ type: "file-plugin",
1844
+ localPath: sourceConfig.local.base_path,
1845
+ isCurrentProject: true,
1846
+ config: sourceConfig
1847
+ };
1848
+ if (sourceConfig.bucket && sourceConfig.type !== "local") {
1849
+ resolved.bucket = sourceConfig.bucket;
1850
+ resolved.prefix = sourceConfig.prefix;
1851
+ resolved.remotePath = this.buildRemotePath(sourceConfig);
1852
+ }
1853
+ this.sources.set(name, resolved);
1854
+ }
1855
+ }
1856
+ /**
1857
+ * Build remote path from source config
1858
+ */
1859
+ buildRemotePath(source) {
1860
+ const protocol = source.type === "s3" ? "s3://" : source.type === "r2" ? "r2://" : "gcs://";
1861
+ const bucket = source.bucket;
1862
+ const prefix = source.prefix ? `/${source.prefix}` : "";
1863
+ return `${protocol}${bucket}${prefix}`;
1864
+ }
1865
+ /**
1866
+ * Get all available file plugin sources
1867
+ *
1868
+ * @returns Array of resolved file sources
1869
+ */
1870
+ getAvailableSources() {
1871
+ return Array.from(this.sources.values());
1872
+ }
1873
+ /**
1874
+ * Resolve a source by name
1875
+ *
1876
+ * @param name - Source name (e.g., "specs", "logs")
1877
+ * @returns Resolved source or null if not found
1878
+ */
1879
+ resolveSource(name) {
1880
+ return this.sources.get(name) || null;
1881
+ }
1882
+ /**
1883
+ * Check if a path belongs to any file plugin source
1884
+ *
1885
+ * @param path - File path to check
1886
+ * @returns True if path matches any source's base_path
1887
+ */
1888
+ isFilePluginPath(path7) {
1889
+ return this.getSourceForPath(path7) !== null;
1890
+ }
1891
+ /**
1892
+ * Get the source for a given path
1893
+ *
1894
+ * Matches path against all source base_paths and returns the matching source.
1895
+ * Uses longest-match strategy if multiple sources match.
1896
+ *
1897
+ * @param path - File path to match
1898
+ * @returns Matching source or null
1899
+ */
1900
+ getSourceForPath(path7) {
1901
+ let bestMatch = null;
1902
+ let bestMatchLength = 0;
1903
+ for (const source of this.sources.values()) {
1904
+ const normalizedPath = this.normalizePath(path7);
1905
+ const normalizedBasePath = this.normalizePath(source.localPath);
1906
+ if (normalizedPath.startsWith(normalizedBasePath)) {
1907
+ const matchLength = normalizedBasePath.length;
1908
+ if (matchLength > bestMatchLength) {
1909
+ bestMatch = source;
1910
+ bestMatchLength = matchLength;
1911
+ }
1912
+ }
1913
+ }
1914
+ return bestMatch;
1915
+ }
1916
+ /**
1917
+ * Normalize path for comparison
1918
+ * - Remove leading "./" or "/"
1919
+ * - Remove trailing "/"
1920
+ * - Convert to lowercase for case-insensitive comparison
1921
+ */
1922
+ normalizePath(path7) {
1923
+ return path7.replace(/^\.\//, "").replace(/^\//, "").replace(/\/$/, "").toLowerCase();
1924
+ }
1925
+ /**
1926
+ * Get source names
1927
+ *
1928
+ * @returns Array of source names
1929
+ */
1930
+ getSourceNames() {
1931
+ return Array.from(this.sources.keys());
1932
+ }
1933
+ /**
1934
+ * Check if sources are configured
1935
+ *
1936
+ * @returns True if any file plugin sources are configured
1937
+ */
1938
+ hasSources() {
1939
+ return this.sources.size > 0;
1940
+ }
1941
+ };
1942
+
1943
+ // src/storage/errors.ts
1944
+ var FilePluginFileNotFoundError = class _FilePluginFileNotFoundError extends Error {
1945
+ constructor(filePath, sourceName, options) {
1946
+ const includeCloudSuggestions = options?.includeCloudSuggestions !== false;
1947
+ const storageType = options?.storageType;
1948
+ let message = `File not found: ${filePath}
1949
+
1950
+ `;
1951
+ if (includeCloudSuggestions) {
1952
+ if (storageType) {
1953
+ message += `This file may be in cloud storage (${storageType}).
1954
+
1955
+ `;
1956
+ } else {
1957
+ message += `This file may not have been synced from remote storage yet.
1958
+ `;
1959
+ }
1960
+ message += `To fetch from cloud storage, run:
1961
+ `;
1962
+ message += ` file pull ${sourceName}
1963
+
1964
+ `;
1965
+ message += `Or sync all sources:
1966
+ `;
1967
+ message += ` file sync`;
1968
+ } else {
1969
+ message += `Please ensure the file exists locally or pull it from cloud storage.`;
1970
+ }
1971
+ super(message);
1972
+ this.filePath = filePath;
1973
+ this.sourceName = sourceName;
1974
+ this.name = "FilePluginFileNotFoundError";
1975
+ if (Error.captureStackTrace) {
1976
+ Error.captureStackTrace(this, _FilePluginFileNotFoundError);
1977
+ }
1978
+ }
1979
+ };
1980
+
1981
+ // src/storage/file-plugin.ts
1982
+ var FilePluginStorage = class {
1983
+ constructor(options) {
1984
+ this.options = options;
1985
+ this.sourceResolver = new FileSourceResolver(options.config);
1986
+ this.baseDir = options.baseDir || process.cwd();
1987
+ }
1988
+ name = "file-plugin";
1989
+ type = "local";
1990
+ // Reuse local type for compatibility
1991
+ sourceResolver;
1992
+ baseDir;
1993
+ /**
1994
+ * Check if this provider can handle the reference
1995
+ *
1996
+ * Only handles:
1997
+ * - Current project references
1998
+ * - With sourceType === 'file-plugin'
1999
+ *
2000
+ * @param reference - Resolved reference
2001
+ * @returns True if this provider can handle the reference
2002
+ */
2003
+ canHandle(reference) {
2004
+ return reference.isCurrentProject && reference.sourceType === "file-plugin";
2005
+ }
2006
+ /**
2007
+ * Fetch content for a reference
2008
+ *
2009
+ * Reads from local filesystem based on the resolved local path.
2010
+ * If file not found and S3 fallback is enabled, throws helpful error.
2011
+ *
2012
+ * @param reference - Resolved reference
2013
+ * @param options - Fetch options (unused for local reads)
2014
+ * @returns Fetch result with content
2015
+ */
2016
+ async fetch(reference, _options) {
2017
+ if (!reference.localPath) {
2018
+ throw new Error(`File plugin reference missing localPath: ${reference.uri}`);
2019
+ }
2020
+ if (!reference.filePluginSource) {
2021
+ throw new Error(`File plugin reference missing source name: ${reference.uri}`);
2022
+ }
2023
+ const absolutePath = path3.isAbsolute(reference.localPath) ? path3.resolve(reference.localPath) : path3.resolve(this.baseDir, reference.localPath);
2024
+ const source = this.sourceResolver.resolveSource(reference.filePluginSource);
2025
+ if (source) {
2026
+ const allowedDir = path3.resolve(this.baseDir, source.localPath);
2027
+ if (!absolutePath.startsWith(allowedDir + path3.sep) && absolutePath !== allowedDir) {
2028
+ throw new Error(
2029
+ `Path traversal detected: ${reference.localPath} resolves outside allowed directory ${source.localPath}`
2030
+ );
2031
+ }
2032
+ }
2033
+ try {
2034
+ const content = await fs3.readFile(absolutePath);
2035
+ const contentType = this.detectContentType(absolutePath);
2036
+ return {
2037
+ content,
2038
+ contentType,
2039
+ size: content.length,
2040
+ source: "file-plugin",
2041
+ metadata: {
2042
+ filePluginSource: reference.filePluginSource,
2043
+ localPath: absolutePath
2044
+ }
2045
+ };
2046
+ } catch (error) {
2047
+ if (error.code === "ENOENT") {
2048
+ const source2 = this.sourceResolver.resolveSource(reference.filePluginSource);
2049
+ throw this.createFileNotFoundError(reference, source2);
2050
+ }
2051
+ throw error;
2052
+ }
2053
+ }
2054
+ /**
2055
+ * Check if a reference exists
2056
+ *
2057
+ * @param reference - Resolved reference
2058
+ * @param options - Fetch options (unused)
2059
+ * @returns True if file exists
2060
+ */
2061
+ async exists(reference, _options) {
2062
+ if (!reference.localPath) {
2063
+ return false;
2064
+ }
2065
+ const absolutePath = path3.isAbsolute(reference.localPath) ? path3.resolve(reference.localPath) : path3.resolve(this.baseDir, reference.localPath);
2066
+ if (reference.filePluginSource) {
2067
+ const source = this.sourceResolver.resolveSource(reference.filePluginSource);
2068
+ if (source) {
2069
+ const allowedDir = path3.resolve(this.baseDir, source.localPath);
2070
+ if (!absolutePath.startsWith(allowedDir + path3.sep) && absolutePath !== allowedDir) {
2071
+ return false;
2072
+ }
2073
+ }
2074
+ }
2075
+ try {
2076
+ await fs3.access(absolutePath);
2077
+ return true;
2078
+ } catch {
2079
+ return false;
2080
+ }
2081
+ }
2082
+ /**
2083
+ * Detect content type from file extension
2084
+ */
2085
+ detectContentType(filePath) {
2086
+ const ext = path3.extname(filePath).toLowerCase();
2087
+ const mimeTypes = {
2088
+ ".md": "text/markdown",
2089
+ ".txt": "text/plain",
2090
+ ".json": "application/json",
2091
+ ".yaml": "text/yaml",
2092
+ ".yml": "text/yaml",
2093
+ ".html": "text/html",
2094
+ ".xml": "application/xml",
2095
+ ".log": "text/plain",
2096
+ ".js": "application/javascript",
2097
+ ".ts": "application/typescript",
2098
+ ".py": "text/x-python",
2099
+ ".sh": "application/x-sh"
2100
+ };
2101
+ return mimeTypes[ext] || "application/octet-stream";
2102
+ }
2103
+ /**
2104
+ * Create a helpful error message when file is not found
2105
+ */
2106
+ createFileNotFoundError(reference, source) {
2107
+ const includeCloudSuggestions = this.options.enableS3Fallback !== false;
2108
+ const storageType = source?.config.type;
2109
+ return new FilePluginFileNotFoundError(
2110
+ reference.localPath || reference.path || "",
2111
+ reference.filePluginSource || "",
2112
+ {
2113
+ includeCloudSuggestions,
2114
+ storageType
2115
+ }
2116
+ );
2117
+ }
2118
+ };
1716
2119
  var execFileAsync = promisify(execFile);
1717
2120
  async function execFileNoThrow(command, args = [], options) {
1718
2121
  try {
@@ -1862,10 +2265,10 @@ var S3ArchiveStorage = class {
1862
2265
  *
1863
2266
  * Used to organize archives by type
1864
2267
  */
1865
- detectType(path6) {
1866
- if (path6.startsWith("specs/")) return "specs";
1867
- if (path6.startsWith("docs/")) return "docs";
1868
- if (path6.includes("/logs/")) return "logs";
2268
+ detectType(path7) {
2269
+ if (path7.startsWith("specs/")) return "specs";
2270
+ if (path7.startsWith("docs/")) return "docs";
2271
+ if (path7.includes("/logs/")) return "logs";
1869
2272
  return "misc";
1870
2273
  }
1871
2274
  /**
@@ -1876,9 +2279,9 @@ var S3ArchiveStorage = class {
1876
2279
  * - *.md (all markdown files)
1877
2280
  * - docs/*.md (markdown files in docs/)
1878
2281
  */
1879
- matchesPatterns(path6, patterns) {
2282
+ matchesPatterns(path7, patterns) {
1880
2283
  for (const pattern of patterns) {
1881
- if (this.matchesPattern(path6, pattern)) {
2284
+ if (this.matchesPattern(path7, pattern)) {
1882
2285
  return true;
1883
2286
  }
1884
2287
  }
@@ -1887,14 +2290,14 @@ var S3ArchiveStorage = class {
1887
2290
  /**
1888
2291
  * Check if path matches a single pattern
1889
2292
  */
1890
- matchesPattern(path6, pattern) {
2293
+ matchesPattern(path7, pattern) {
1891
2294
  const DOUBLE_STAR = "\0DOUBLE_STAR\0";
1892
2295
  let regexPattern = pattern.replace(/\*\*/g, DOUBLE_STAR);
1893
2296
  regexPattern = regexPattern.replace(/[.[\](){}+^$|\\]/g, "\\$&");
1894
2297
  regexPattern = regexPattern.replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]");
1895
2298
  regexPattern = regexPattern.replace(new RegExp(DOUBLE_STAR, "g"), ".*");
1896
2299
  const regex = new RegExp(`^${regexPattern}$`);
1897
- return regex.test(path6);
2300
+ return regex.test(path7);
1898
2301
  }
1899
2302
  };
1900
2303
 
@@ -1902,14 +2305,61 @@ var S3ArchiveStorage = class {
1902
2305
  var StorageManager = class {
1903
2306
  providers = /* @__PURE__ */ new Map();
1904
2307
  priority;
2308
+ codexConfig;
1905
2309
  constructor(config = {}) {
2310
+ this.codexConfig = config.codexConfig;
1906
2311
  this.providers.set("local", new LocalStorage(config.local));
1907
2312
  this.providers.set("github", new GitHubStorage(config.github));
1908
2313
  this.providers.set("http", new HttpStorage(config.http));
1909
2314
  if (config.s3Archive) {
1910
2315
  this.providers.set("s3-archive", new S3ArchiveStorage(config.s3Archive));
1911
2316
  }
1912
- this.priority = config.priority || (config.s3Archive ? ["local", "s3-archive", "github", "http"] : ["local", "github", "http"]);
2317
+ if (config.filePlugin) {
2318
+ this.providers.set("file-plugin", new FilePluginStorage(config.filePlugin));
2319
+ }
2320
+ 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"]);
2321
+ }
2322
+ /**
2323
+ * Resolve authentication token for a reference
2324
+ *
2325
+ * Looks up dependency-specific authentication or falls back to default
2326
+ */
2327
+ resolveToken(reference) {
2328
+ if (!this.codexConfig) {
2329
+ return void 0;
2330
+ }
2331
+ const dependencyKey = `${reference.org}/${reference.project}`;
2332
+ if (this.codexConfig.dependencies?.[dependencyKey]) {
2333
+ const dependency = this.codexConfig.dependencies[dependencyKey];
2334
+ for (const [, sourceConfig] of Object.entries(dependency.sources)) {
2335
+ if (sourceConfig.type === "github") {
2336
+ if (sourceConfig.token_env) {
2337
+ const token = process.env[sourceConfig.token_env];
2338
+ if (token) {
2339
+ return token;
2340
+ }
2341
+ }
2342
+ if (sourceConfig.token) {
2343
+ return sourceConfig.token;
2344
+ }
2345
+ }
2346
+ }
2347
+ }
2348
+ const defaultTokenEnv = this.codexConfig.auth?.github?.default_token_env || "GITHUB_TOKEN";
2349
+ return process.env[defaultTokenEnv];
2350
+ }
2351
+ /**
2352
+ * Resolve fetch options with authentication
2353
+ *
2354
+ * Merges reference-specific authentication with provided options
2355
+ */
2356
+ resolveFetchOptions(reference, options) {
2357
+ const token = this.resolveToken(reference);
2358
+ return {
2359
+ ...options,
2360
+ token: options?.token || token
2361
+ // Explicit option overrides resolved token
2362
+ };
1913
2363
  }
1914
2364
  /**
1915
2365
  * Register a custom storage provider
@@ -1951,8 +2401,10 @@ var StorageManager = class {
1951
2401
  * Fetch content for a reference
1952
2402
  *
1953
2403
  * Tries providers in priority order until one succeeds.
2404
+ * Automatically resolves authentication based on dependency configuration.
1954
2405
  */
1955
2406
  async fetch(reference, options) {
2407
+ const resolvedOptions = this.resolveFetchOptions(reference, options);
1956
2408
  const errors = [];
1957
2409
  for (const type of this.priority) {
1958
2410
  const provider = this.providers.get(type);
@@ -1960,7 +2412,7 @@ var StorageManager = class {
1960
2412
  continue;
1961
2413
  }
1962
2414
  try {
1963
- return await provider.fetch(reference, options);
2415
+ return await provider.fetch(reference, resolvedOptions);
1964
2416
  } catch (error) {
1965
2417
  errors.push(error instanceof Error ? error : new Error(String(error)));
1966
2418
  }
@@ -1981,15 +2433,17 @@ var StorageManager = class {
1981
2433
  * Check if content exists for a reference
1982
2434
  *
1983
2435
  * Returns true if any provider reports the content exists.
2436
+ * Automatically resolves authentication based on dependency configuration.
1984
2437
  */
1985
2438
  async exists(reference, options) {
2439
+ const resolvedOptions = this.resolveFetchOptions(reference, options);
1986
2440
  for (const type of this.priority) {
1987
2441
  const provider = this.providers.get(type);
1988
2442
  if (!provider || !provider.canHandle(reference)) {
1989
2443
  continue;
1990
2444
  }
1991
2445
  try {
1992
- if (await provider.exists(reference, options)) {
2446
+ if (await provider.exists(reference, resolvedOptions)) {
1993
2447
  return true;
1994
2448
  }
1995
2449
  } catch {
@@ -2009,6 +2463,8 @@ var StorageManager = class {
2009
2463
  }
2010
2464
  /**
2011
2465
  * Fetch multiple references in parallel
2466
+ *
2467
+ * Automatically resolves authentication for each reference based on dependency configuration.
2012
2468
  */
2013
2469
  async fetchMany(references, options) {
2014
2470
  const results = /* @__PURE__ */ new Map();
@@ -2149,7 +2605,7 @@ var CachePersistence = class {
2149
2605
  }
2150
2606
  const [, org, project, filePath] = match;
2151
2607
  const relativePath = filePath || "index";
2152
- return path3.join(this.cacheDir, org, project, relativePath + this.extension);
2608
+ return path3__default.join(this.cacheDir, org, project, relativePath + this.extension);
2153
2609
  }
2154
2610
  /**
2155
2611
  * Get the metadata file path for a URI
@@ -2165,8 +2621,8 @@ var CachePersistence = class {
2165
2621
  const metadataPath = this.getMetadataPath(uri);
2166
2622
  try {
2167
2623
  const [metadataJson, content] = await Promise.all([
2168
- fs2.readFile(metadataPath, "utf-8"),
2169
- fs2.readFile(cachePath)
2624
+ fs3__default.readFile(metadataPath, "utf-8"),
2625
+ fs3__default.readFile(cachePath)
2170
2626
  ]);
2171
2627
  const metadata = JSON.parse(metadataJson);
2172
2628
  return {
@@ -2186,32 +2642,32 @@ var CachePersistence = class {
2186
2642
  async write(entry) {
2187
2643
  const cachePath = this.getCachePath(entry.metadata.uri);
2188
2644
  const metadataPath = this.getMetadataPath(entry.metadata.uri);
2189
- await fs2.mkdir(path3.dirname(cachePath), { recursive: true });
2645
+ await fs3__default.mkdir(path3__default.dirname(cachePath), { recursive: true });
2190
2646
  if (this.atomicWrites) {
2191
2647
  const tempCachePath = cachePath + ".tmp";
2192
2648
  const tempMetadataPath = metadataPath + ".tmp";
2193
2649
  try {
2194
2650
  await Promise.all([
2195
- fs2.writeFile(tempCachePath, entry.content),
2196
- fs2.writeFile(tempMetadataPath, JSON.stringify(entry.metadata, null, 2))
2651
+ fs3__default.writeFile(tempCachePath, entry.content),
2652
+ fs3__default.writeFile(tempMetadataPath, JSON.stringify(entry.metadata, null, 2))
2197
2653
  ]);
2198
2654
  await Promise.all([
2199
- fs2.rename(tempCachePath, cachePath),
2200
- fs2.rename(tempMetadataPath, metadataPath)
2655
+ fs3__default.rename(tempCachePath, cachePath),
2656
+ fs3__default.rename(tempMetadataPath, metadataPath)
2201
2657
  ]);
2202
2658
  } catch (error) {
2203
2659
  await Promise.all([
2204
- fs2.unlink(tempCachePath).catch(() => {
2660
+ fs3__default.unlink(tempCachePath).catch(() => {
2205
2661
  }),
2206
- fs2.unlink(tempMetadataPath).catch(() => {
2662
+ fs3__default.unlink(tempMetadataPath).catch(() => {
2207
2663
  })
2208
2664
  ]);
2209
2665
  throw error;
2210
2666
  }
2211
2667
  } else {
2212
2668
  await Promise.all([
2213
- fs2.writeFile(cachePath, entry.content),
2214
- fs2.writeFile(metadataPath, JSON.stringify(entry.metadata, null, 2))
2669
+ fs3__default.writeFile(cachePath, entry.content),
2670
+ fs3__default.writeFile(metadataPath, JSON.stringify(entry.metadata, null, 2))
2215
2671
  ]);
2216
2672
  }
2217
2673
  }
@@ -2222,7 +2678,7 @@ var CachePersistence = class {
2222
2678
  const cachePath = this.getCachePath(uri);
2223
2679
  const metadataPath = this.getMetadataPath(uri);
2224
2680
  try {
2225
- await Promise.all([fs2.unlink(cachePath), fs2.unlink(metadataPath)]);
2681
+ await Promise.all([fs3__default.unlink(cachePath), fs3__default.unlink(metadataPath)]);
2226
2682
  return true;
2227
2683
  } catch (error) {
2228
2684
  if (error.code === "ENOENT") {
@@ -2237,7 +2693,7 @@ var CachePersistence = class {
2237
2693
  async exists(uri) {
2238
2694
  const cachePath = this.getCachePath(uri);
2239
2695
  try {
2240
- await fs2.access(cachePath);
2696
+ await fs3__default.access(cachePath);
2241
2697
  return true;
2242
2698
  } catch {
2243
2699
  return false;
@@ -2249,20 +2705,20 @@ var CachePersistence = class {
2249
2705
  async list() {
2250
2706
  const uris = [];
2251
2707
  try {
2252
- const orgs = await fs2.readdir(this.cacheDir);
2708
+ const orgs = await fs3__default.readdir(this.cacheDir);
2253
2709
  for (const org of orgs) {
2254
- const orgPath = path3.join(this.cacheDir, org);
2255
- const orgStat = await fs2.stat(orgPath);
2710
+ const orgPath = path3__default.join(this.cacheDir, org);
2711
+ const orgStat = await fs3__default.stat(orgPath);
2256
2712
  if (!orgStat.isDirectory()) continue;
2257
- const projects = await fs2.readdir(orgPath);
2713
+ const projects = await fs3__default.readdir(orgPath);
2258
2714
  for (const project of projects) {
2259
- const projectPath = path3.join(orgPath, project);
2260
- const projectStat = await fs2.stat(projectPath);
2715
+ const projectPath = path3__default.join(orgPath, project);
2716
+ const projectStat = await fs3__default.stat(projectPath);
2261
2717
  if (!projectStat.isDirectory()) continue;
2262
2718
  const files = await this.listFilesRecursive(projectPath);
2263
2719
  for (const file of files) {
2264
2720
  if (file.endsWith(this.extension)) {
2265
- const relativePath = path3.relative(projectPath, file);
2721
+ const relativePath = path3__default.relative(projectPath, file);
2266
2722
  const filePath = relativePath.slice(0, -this.extension.length);
2267
2723
  uris.push(`codex://${org}/${project}/${filePath}`);
2268
2724
  }
@@ -2282,9 +2738,9 @@ var CachePersistence = class {
2282
2738
  */
2283
2739
  async listFilesRecursive(dir) {
2284
2740
  const files = [];
2285
- const entries = await fs2.readdir(dir, { withFileTypes: true });
2741
+ const entries = await fs3__default.readdir(dir, { withFileTypes: true });
2286
2742
  for (const entry of entries) {
2287
- const fullPath = path3.join(dir, entry.name);
2743
+ const fullPath = path3__default.join(dir, entry.name);
2288
2744
  if (entry.isDirectory()) {
2289
2745
  files.push(...await this.listFilesRecursive(fullPath));
2290
2746
  } else if (entry.isFile()) {
@@ -2299,12 +2755,12 @@ var CachePersistence = class {
2299
2755
  async clear() {
2300
2756
  let count = 0;
2301
2757
  try {
2302
- const orgs = await fs2.readdir(this.cacheDir);
2758
+ const orgs = await fs3__default.readdir(this.cacheDir);
2303
2759
  for (const org of orgs) {
2304
- const orgPath = path3.join(this.cacheDir, org);
2305
- const stat = await fs2.stat(orgPath);
2760
+ const orgPath = path3__default.join(this.cacheDir, org);
2761
+ const stat = await fs3__default.stat(orgPath);
2306
2762
  if (stat.isDirectory()) {
2307
- await fs2.rm(orgPath, { recursive: true });
2763
+ await fs3__default.rm(orgPath, { recursive: true });
2308
2764
  count++;
2309
2765
  }
2310
2766
  }
@@ -2365,7 +2821,7 @@ var CachePersistence = class {
2365
2821
  * Ensure cache directory exists
2366
2822
  */
2367
2823
  async ensureDir() {
2368
- await fs2.mkdir(this.cacheDir, { recursive: true });
2824
+ await fs3__default.mkdir(this.cacheDir, { recursive: true });
2369
2825
  }
2370
2826
  /**
2371
2827
  * Get cache directory path
@@ -2413,8 +2869,17 @@ var CacheManager = class {
2413
2869
  * Get content for a reference
2414
2870
  *
2415
2871
  * Implements cache-first strategy with stale-while-revalidate.
2872
+ *
2873
+ * EXCEPTION: File plugin sources (current project files) bypass cache entirely.
2874
+ * They are always read fresh from disk for optimal development experience.
2416
2875
  */
2417
2876
  async get(reference, options) {
2877
+ if (reference.isCurrentProject && reference.sourceType === "file-plugin") {
2878
+ if (!this.storage) {
2879
+ throw new Error("Storage manager not set");
2880
+ }
2881
+ return await this.storage.fetch(reference, options);
2882
+ }
2418
2883
  const ttl = options?.ttl ?? this.config.defaultTtl;
2419
2884
  let entry = this.memoryCache.get(reference.uri);
2420
2885
  if (!entry && this.persistence) {
@@ -2620,13 +3085,18 @@ var CacheManager = class {
2620
3085
  }
2621
3086
  /**
2622
3087
  * Fetch content and store in cache
3088
+ *
3089
+ * EXCEPTION: File plugin sources are not cached (should not reach here,
3090
+ * but added as safety check).
2623
3091
  */
2624
3092
  async fetchAndCache(reference, ttl, options) {
2625
3093
  if (!this.storage) {
2626
3094
  throw new Error("Storage manager not set");
2627
3095
  }
2628
3096
  const result = await this.storage.fetch(reference, options);
2629
- await this.set(reference.uri, result, ttl);
3097
+ if (!(reference.isCurrentProject && reference.sourceType === "file-plugin")) {
3098
+ await this.set(reference.uri, result, ttl);
3099
+ }
2630
3100
  return result;
2631
3101
  }
2632
3102
  /**
@@ -2745,11 +3215,11 @@ var DEFAULT_SYNC_CONFIG = {
2745
3215
  deleteOrphans: false,
2746
3216
  conflictStrategy: "newest"
2747
3217
  };
2748
- function evaluatePath(path6, rules, direction, defaultExcludes = []) {
3218
+ function evaluatePath(path7, rules, direction, defaultExcludes = []) {
2749
3219
  for (const pattern of defaultExcludes) {
2750
- if (micromatch3.isMatch(path6, pattern)) {
3220
+ if (micromatch3.isMatch(path7, pattern)) {
2751
3221
  return {
2752
- path: path6,
3222
+ path: path7,
2753
3223
  shouldSync: false,
2754
3224
  reason: `Excluded by default pattern: ${pattern}`
2755
3225
  };
@@ -2760,9 +3230,9 @@ function evaluatePath(path6, rules, direction, defaultExcludes = []) {
2760
3230
  if (rule.direction && rule.direction !== direction) {
2761
3231
  continue;
2762
3232
  }
2763
- if (micromatch3.isMatch(path6, rule.pattern)) {
3233
+ if (micromatch3.isMatch(path7, rule.pattern)) {
2764
3234
  return {
2765
- path: path6,
3235
+ path: path7,
2766
3236
  shouldSync: rule.include,
2767
3237
  matchedRule: rule,
2768
3238
  reason: rule.include ? `Included by rule: ${rule.pattern}` : `Excluded by rule: ${rule.pattern}`
@@ -2770,21 +3240,21 @@ function evaluatePath(path6, rules, direction, defaultExcludes = []) {
2770
3240
  }
2771
3241
  }
2772
3242
  return {
2773
- path: path6,
3243
+ path: path7,
2774
3244
  shouldSync: true,
2775
3245
  reason: "No matching rule, included by default"
2776
3246
  };
2777
3247
  }
2778
3248
  function evaluatePaths(paths, rules, direction, defaultExcludes = []) {
2779
3249
  const results = /* @__PURE__ */ new Map();
2780
- for (const path6 of paths) {
2781
- results.set(path6, evaluatePath(path6, rules, direction, defaultExcludes));
3250
+ for (const path7 of paths) {
3251
+ results.set(path7, evaluatePath(path7, rules, direction, defaultExcludes));
2782
3252
  }
2783
3253
  return results;
2784
3254
  }
2785
3255
  function filterSyncablePaths(paths, rules, direction, defaultExcludes = []) {
2786
3256
  return paths.filter(
2787
- (path6) => evaluatePath(path6, rules, direction, defaultExcludes).shouldSync
3257
+ (path7) => evaluatePath(path7, rules, direction, defaultExcludes).shouldSync
2788
3258
  );
2789
3259
  }
2790
3260
  function createRulesFromPatterns(include = [], exclude = []) {
@@ -3050,8 +3520,8 @@ async function scanCodexWithRouting(options) {
3050
3520
  for (const filePath of allFiles) {
3051
3521
  totalScanned++;
3052
3522
  try {
3053
- const fullPath = path3.join(codexDir, filePath);
3054
- const stats = await fs2.stat(fullPath);
3523
+ const fullPath = path3__default.join(codexDir, filePath);
3524
+ const stats = await fs3__default.stat(fullPath);
3055
3525
  if (stats.size > maxFileSize) {
3056
3526
  totalSkipped++;
3057
3527
  errors.push({
@@ -3147,10 +3617,10 @@ async function listAllFilesRecursive(dirPath) {
3147
3617
  const files = [];
3148
3618
  async function scanDirectory(currentPath, relativePath = "") {
3149
3619
  try {
3150
- const entries = await fs2.readdir(currentPath, { withFileTypes: true });
3620
+ const entries = await fs3__default.readdir(currentPath, { withFileTypes: true });
3151
3621
  for (const entry of entries) {
3152
- const entryPath = path3.join(currentPath, entry.name);
3153
- const entryRelativePath = relativePath ? path3.join(relativePath, entry.name) : entry.name;
3622
+ const entryPath = path3__default.join(currentPath, entry.name);
3623
+ const entryRelativePath = relativePath ? path3__default.join(relativePath, entry.name) : entry.name;
3154
3624
  if (entry.isDirectory()) {
3155
3625
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build") {
3156
3626
  continue;
@@ -3389,17 +3859,17 @@ var SyncManager = class {
3389
3859
  if (file.operation === "create" || file.operation === "update") {
3390
3860
  const sourcePath = `${plan.source}/${file.path}`;
3391
3861
  const targetPath = `${plan.target}/${file.path}`;
3392
- const fs4 = await import('fs/promises');
3393
- const path6 = await import('path');
3394
- const targetDir = path6.dirname(targetPath);
3395
- await fs4.mkdir(targetDir, { recursive: true });
3396
- await fs4.copyFile(sourcePath, targetPath);
3862
+ const fs5 = await import('fs/promises');
3863
+ const path7 = await import('path');
3864
+ const targetDir = path7.dirname(targetPath);
3865
+ await fs5.mkdir(targetDir, { recursive: true });
3866
+ await fs5.copyFile(sourcePath, targetPath);
3397
3867
  synced++;
3398
3868
  } else if (file.operation === "delete") {
3399
3869
  const targetPath = `${plan.target}/${file.path}`;
3400
- const fs4 = await import('fs/promises');
3870
+ const fs5 = await import('fs/promises');
3401
3871
  try {
3402
- await fs4.unlink(targetPath);
3872
+ await fs5.unlink(targetPath);
3403
3873
  synced++;
3404
3874
  } catch (error) {
3405
3875
  if (error.code !== "ENOENT") {
@@ -3454,15 +3924,15 @@ var SyncManager = class {
3454
3924
  /**
3455
3925
  * Get sync status for a file
3456
3926
  */
3457
- async getFileStatus(path6) {
3927
+ async getFileStatus(path7) {
3458
3928
  const manifest = await this.loadManifest();
3459
- return manifest?.entries[path6] ?? null;
3929
+ return manifest?.entries[path7] ?? null;
3460
3930
  }
3461
3931
  /**
3462
3932
  * Check if a file is synced
3463
3933
  */
3464
- async isFileSynced(path6) {
3465
- const status = await this.getFileStatus(path6);
3934
+ async isFileSynced(path7) {
3935
+ const status = await this.getFileStatus(path7);
3466
3936
  return status !== null;
3467
3937
  }
3468
3938
  /**
@@ -3546,19 +4016,19 @@ function ruleMatchesContext(rule, context) {
3546
4016
  }
3547
4017
  return true;
3548
4018
  }
3549
- function ruleMatchesPath(rule, path6) {
3550
- return micromatch3.isMatch(path6, rule.pattern);
4019
+ function ruleMatchesPath(rule, path7) {
4020
+ return micromatch3.isMatch(path7, rule.pattern);
3551
4021
  }
3552
4022
  function ruleMatchesAction(rule, action) {
3553
4023
  return rule.actions.includes(action);
3554
4024
  }
3555
- function evaluatePermission(path6, action, context, config) {
4025
+ function evaluatePermission(path7, action, context, config) {
3556
4026
  const sortedRules = [...config.rules].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
3557
4027
  for (const rule of sortedRules) {
3558
4028
  if (!ruleMatchesContext(rule, context)) {
3559
4029
  continue;
3560
4030
  }
3561
- if (!ruleMatchesPath(rule, path6)) {
4031
+ if (!ruleMatchesPath(rule, path7)) {
3562
4032
  continue;
3563
4033
  }
3564
4034
  if (!ruleMatchesAction(rule, action)) {
@@ -3577,24 +4047,24 @@ function evaluatePermission(path6, action, context, config) {
3577
4047
  reason: config.defaultAllow ? "Allowed by default" : "Denied by default"
3578
4048
  };
3579
4049
  }
3580
- function isAllowed(path6, action, context, config) {
3581
- const result = evaluatePermission(path6, action, context, config);
4050
+ function isAllowed(path7, action, context, config) {
4051
+ const result = evaluatePermission(path7, action, context, config);
3582
4052
  return result.allowed;
3583
4053
  }
3584
- function hasPermission(path6, action, requiredLevel, context, config) {
3585
- const result = evaluatePermission(path6, action, context, config);
4054
+ function hasPermission(path7, action, requiredLevel, context, config) {
4055
+ const result = evaluatePermission(path7, action, context, config);
3586
4056
  return levelGrants(result.level, requiredLevel);
3587
4057
  }
3588
4058
  function evaluatePermissions(paths, action, context, config) {
3589
4059
  const results = /* @__PURE__ */ new Map();
3590
- for (const path6 of paths) {
3591
- results.set(path6, evaluatePermission(path6, action, context, config));
4060
+ for (const path7 of paths) {
4061
+ results.set(path7, evaluatePermission(path7, action, context, config));
3592
4062
  }
3593
4063
  return results;
3594
4064
  }
3595
4065
  function filterByPermission(paths, action, context, config, requiredLevel = "read") {
3596
- return paths.filter((path6) => {
3597
- const result = evaluatePermission(path6, action, context, config);
4066
+ return paths.filter((path7) => {
4067
+ const result = evaluatePermission(path7, action, context, config);
3598
4068
  return levelGrants(result.level, requiredLevel);
3599
4069
  });
3600
4070
  }
@@ -3685,21 +4155,21 @@ var PermissionManager = class {
3685
4155
  /**
3686
4156
  * Check if an action is allowed for a path
3687
4157
  */
3688
- isAllowed(path6, action, context) {
3689
- const result = this.evaluate(path6, action, context);
4158
+ isAllowed(path7, action, context) {
4159
+ const result = this.evaluate(path7, action, context);
3690
4160
  return result.allowed;
3691
4161
  }
3692
4162
  /**
3693
4163
  * Check if a permission level is granted
3694
4164
  */
3695
- hasPermission(path6, action, requiredLevel, context) {
3696
- const result = this.evaluate(path6, action, context);
4165
+ hasPermission(path7, action, requiredLevel, context) {
4166
+ const result = this.evaluate(path7, action, context);
3697
4167
  return levelGrants(result.level, requiredLevel);
3698
4168
  }
3699
4169
  /**
3700
4170
  * Evaluate permission for a path and action
3701
4171
  */
3702
- evaluate(path6, action, context) {
4172
+ evaluate(path7, action, context) {
3703
4173
  const mergedContext = { ...this.defaultContext, ...context };
3704
4174
  if (!this.config.enforced) {
3705
4175
  return {
@@ -3708,7 +4178,7 @@ var PermissionManager = class {
3708
4178
  reason: "Permissions not enforced"
3709
4179
  };
3710
4180
  }
3711
- return evaluatePermission(path6, action, mergedContext, this.config);
4181
+ return evaluatePermission(path7, action, mergedContext, this.config);
3712
4182
  }
3713
4183
  /**
3714
4184
  * Filter paths by permission
@@ -3811,12 +4281,12 @@ var PermissionManager = class {
3811
4281
  /**
3812
4282
  * Assert permission (throws if denied)
3813
4283
  */
3814
- assertPermission(path6, action, requiredLevel = "read", context) {
3815
- const result = this.evaluate(path6, action, context);
4284
+ assertPermission(path7, action, requiredLevel = "read", context) {
4285
+ const result = this.evaluate(path7, action, context);
3816
4286
  if (!levelGrants(result.level, requiredLevel)) {
3817
4287
  throw new PermissionDeniedError(
3818
- `Permission denied for ${action} on ${path6}: ${result.reason}`,
3819
- path6,
4288
+ `Permission denied for ${action} on ${path7}: ${result.reason}`,
4289
+ path7,
3820
4290
  action,
3821
4291
  result
3822
4292
  );
@@ -3824,9 +4294,9 @@ var PermissionManager = class {
3824
4294
  }
3825
4295
  };
3826
4296
  var PermissionDeniedError = class extends Error {
3827
- constructor(message, path6, action, result) {
4297
+ constructor(message, path7, action, result) {
3828
4298
  super(message);
3829
- this.path = path6;
4299
+ this.path = path7;
3830
4300
  this.action = action;
3831
4301
  this.result = result;
3832
4302
  this.name = "PermissionDeniedError";
@@ -4323,8 +4793,8 @@ function convertToUri(reference, options = {}) {
4323
4793
  const parts = parseReference2(trimmed);
4324
4794
  const org = parts.org || options.defaultOrg || "_";
4325
4795
  const project = parts.project || options.defaultProject || "_";
4326
- const path6 = parts.path;
4327
- return `codex://${org}/${project}/${path6}`;
4796
+ const path7 = parts.path;
4797
+ return `codex://${org}/${project}/${path7}`;
4328
4798
  }
4329
4799
  function parseReference2(reference) {
4330
4800
  const trimmed = reference.trim();
@@ -4404,6 +4874,6 @@ function generateReferenceMigrationSummary(results) {
4404
4874
  return lines.join("\n");
4405
4875
  }
4406
4876
 
4407
- export { AutoSyncPatternSchema, BUILT_IN_TYPES, CODEX_URI_PREFIX, CacheManager, CachePersistence, CodexConfigSchema, CodexError, CommonRules, ConfigurationError, CustomTypeSchema, DEFAULT_CACHE_DIR, DEFAULT_FETCH_OPTIONS, DEFAULT_MIGRATION_OPTIONS, DEFAULT_PERMISSION_CONFIG, DEFAULT_SYNC_CONFIG, DEFAULT_TYPE, GitHubStorage, HttpStorage, LEGACY_PATTERNS, LEGACY_REF_PREFIX, LocalStorage, MetadataSchema, PERMISSION_LEVEL_ORDER, PermissionDeniedError, PermissionManager, StorageManager, SyncManager, SyncRulesSchema, TTL, TypeRegistry, TypesConfigSchema, ValidationError, buildUri, calculateCachePath, calculateContentHash, convertLegacyReference, convertLegacyReferences, convertToUri, createCacheEntry, createCacheManager, createCachePersistence, createDefaultRegistry, createEmptyModernConfig, createEmptySyncPlan, createGitHubStorage, createHttpStorage, createLocalStorage, createPermissionManager, createRule, createRulesFromPatterns, createStorageManager, createSyncManager, createSyncPlan, deserializeCacheEntry, detectContentType, detectCurrentProject, detectVersion, estimateSyncTime, evaluatePath, evaluatePaths, evaluatePatterns, evaluatePermission, evaluatePermissions, extendType, extractOrgFromRepoName, extractRawFrontmatter, filterByPatterns, filterByPermission, filterPlanOperations, filterSyncablePaths, findLegacyReferences, formatPlanSummary, generateMigrationReport, generateReferenceMigrationSummary, getBuiltInType, getBuiltInTypeNames, getCacheEntryAge, getCacheEntryStatus, getCurrentContext, getCustomSyncDestinations, getDefaultCacheManager, getDefaultConfig, getDefaultDirectories, getDefaultPermissionManager, getDefaultRules, getDefaultStorageManager, getDirectory, getExtension, getFilename, getMigrationRequirements, getPlanStats, getRelativeCachePath, getRemainingTtl, getTargetRepos, hasContentChanged, hasFrontmatter, hasLegacyReferences, hasPermission as hasPermissionLevel, isBuiltInType, isCacheEntryFresh, isCacheEntryValid, isCurrentProjectUri, isLegacyConfig, isLegacyReference, isModernConfig, isAllowed as isPermissionAllowed, isValidUri, levelGrants, loadConfig, loadCustomTypes, matchAnyPattern, matchPattern, maxLevel, mergeFetchOptions, mergeRules, mergeTypes, migrateConfig, migrateFileReferences, minLevel, needsMigration, parseCustomDestination, parseMetadata, parseReference, parseTtl, resolveOrganization, resolveReference, resolveReferences, ruleMatchesAction, ruleMatchesContext, ruleMatchesPath, sanitizePath, serializeCacheEntry, setDefaultCacheManager, setDefaultPermissionManager, setDefaultStorageManager, shouldSyncToRepo, summarizeEvaluations, touchCacheEntry, validateCustomTypes, validateMetadata, validateMigratedConfig, validateOrg, validatePath, validateRules2 as validatePermissionRules, validateProject, validateRules, validateUri };
4877
+ export { AutoSyncPatternSchema, BUILT_IN_TYPES, CODEX_URI_PREFIX, CacheManager, CachePersistence, CodexConfigSchema, CodexError, CommonRules, ConfigurationError, CustomTypeSchema, DEFAULT_CACHE_DIR, DEFAULT_FETCH_OPTIONS, DEFAULT_MIGRATION_OPTIONS, DEFAULT_PERMISSION_CONFIG, DEFAULT_SYNC_CONFIG, DEFAULT_TYPE, FilePluginFileNotFoundError, FilePluginStorage, GitHubStorage, HttpStorage, LEGACY_PATTERNS, LEGACY_REF_PREFIX, LocalStorage, MetadataSchema, PERMISSION_LEVEL_ORDER, PermissionDeniedError, PermissionManager, StorageManager, SyncManager, SyncRulesSchema, TTL, TypeRegistry, TypesConfigSchema, ValidationError, buildUri, calculateCachePath, calculateContentHash, convertLegacyReference, convertLegacyReferences, convertToUri, createCacheEntry, createCacheManager, createCachePersistence, createDefaultRegistry, createEmptyModernConfig, createEmptySyncPlan, createGitHubStorage, createHttpStorage, createLocalStorage, createPermissionManager, createRule, createRulesFromPatterns, createStorageManager, createSyncManager, createSyncPlan, deserializeCacheEntry, detectContentType, detectCurrentProject, detectVersion, estimateSyncTime, evaluatePath, evaluatePaths, evaluatePatterns, evaluatePermission, evaluatePermissions, extendType, extractOrgFromRepoName, extractRawFrontmatter, filterByPatterns, filterByPermission, filterPlanOperations, filterSyncablePaths, findLegacyReferences, formatPlanSummary, generateMigrationReport, generateReferenceMigrationSummary, getBuiltInType, getBuiltInTypeNames, getCacheEntryAge, getCacheEntryStatus, getCurrentContext, getCustomSyncDestinations, getDefaultCacheManager, getDefaultConfig, getDefaultDirectories, getDefaultPermissionManager, getDefaultRules, getDefaultStorageManager, getDirectory, getExtension, getFilename, getMigrationRequirements, getPlanStats, getRelativeCachePath, getRemainingTtl, getTargetRepos, hasContentChanged, hasFrontmatter, hasLegacyReferences, hasPermission as hasPermissionLevel, isBuiltInType, isCacheEntryFresh, isCacheEntryValid, isCurrentProjectUri, isLegacyConfig, isLegacyReference, isModernConfig, isAllowed as isPermissionAllowed, isValidUri, levelGrants, loadConfig, loadCustomTypes, matchAnyPattern, matchPattern, maxLevel, mergeFetchOptions, mergeRules, mergeTypes, migrateConfig, migrateFileReferences, minLevel, needsMigration, parseCustomDestination, parseMetadata, parseReference, parseTtl, resolveOrganization, resolveReference, resolveReferences, ruleMatchesAction, ruleMatchesContext, ruleMatchesPath, sanitizePath, serializeCacheEntry, setDefaultCacheManager, setDefaultPermissionManager, setDefaultStorageManager, shouldSyncToRepo, summarizeEvaluations, touchCacheEntry, validateCustomTypes, validateMetadata, validateMigratedConfig, validateOrg, validatePath, validateRules2 as validatePermissionRules, validateProject, validateRules, validateUri };
4408
4878
  //# sourceMappingURL=index.js.map
4409
4879
  //# sourceMappingURL=index.js.map