@fractary/codex 0.8.0 → 0.9.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 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
@@ -858,6 +896,41 @@ var CodexConfigSchema = z.object({
858
896
  // Archive configuration
859
897
  archive: ArchiveConfigSchema.optional()
860
898
  }).strict();
899
+ var FileSourceSchema = z.object({
900
+ type: z.enum(["s3", "r2", "gcs", "local"]),
901
+ bucket: z.string().optional(),
902
+ prefix: z.string().optional(),
903
+ region: z.string().optional(),
904
+ local: z.object({
905
+ base_path: z.string()
906
+ }),
907
+ push: z.object({
908
+ compress: z.boolean().optional(),
909
+ keep_local: z.boolean().optional()
910
+ }).optional(),
911
+ auth: z.object({
912
+ profile: z.string().optional()
913
+ }).optional()
914
+ }).refine(
915
+ (data) => {
916
+ if (data.type !== "local" && !data.bucket) {
917
+ return false;
918
+ }
919
+ return true;
920
+ },
921
+ {
922
+ message: "Bucket is required for s3, r2, and gcs storage types",
923
+ path: ["bucket"]
924
+ }
925
+ );
926
+ var FileConfigSchema = z.object({
927
+ schema_version: z.string(),
928
+ sources: z.record(FileSourceSchema)
929
+ });
930
+ z.object({
931
+ file: FileConfigSchema.optional(),
932
+ codex: CodexConfigSchema.optional()
933
+ });
861
934
  function parseMetadata(content, options = {}) {
862
935
  const { strict = true, normalize = true } = options;
863
936
  const normalizedContent = normalize ? content.replace(/\r\n/g, "\n") : content;
@@ -1187,18 +1260,18 @@ function parseCustomDestination(value) {
1187
1260
  );
1188
1261
  }
1189
1262
  const repo = value.substring(0, colonIndex).trim();
1190
- const path6 = value.substring(colonIndex + 1).trim();
1263
+ const path7 = value.substring(colonIndex + 1).trim();
1191
1264
  if (!repo) {
1192
1265
  throw new ValidationError(
1193
1266
  `Invalid custom destination: repository name cannot be empty in "${value}"`
1194
1267
  );
1195
1268
  }
1196
- if (!path6) {
1269
+ if (!path7) {
1197
1270
  throw new ValidationError(
1198
1271
  `Invalid custom destination: path cannot be empty in "${value}"`
1199
1272
  );
1200
1273
  }
1201
- return { repo, path: path6 };
1274
+ return { repo, path: path7 };
1202
1275
  }
1203
1276
  function getCustomSyncDestinations(metadata) {
1204
1277
  const customDestinations = metadata.codex_sync_custom;
@@ -1234,8 +1307,8 @@ function mergeFetchOptions(options) {
1234
1307
  ...options
1235
1308
  };
1236
1309
  }
1237
- function detectContentType(path6) {
1238
- const ext = path6.split(".").pop()?.toLowerCase();
1310
+ function detectContentType(path7) {
1311
+ const ext = path7.split(".").pop()?.toLowerCase();
1239
1312
  const mimeTypes = {
1240
1313
  md: "text/markdown",
1241
1314
  markdown: "text/markdown",
@@ -1295,19 +1368,19 @@ var LocalStorage = class {
1295
1368
  if (!reference.localPath) {
1296
1369
  throw new Error(`No local path for reference: ${reference.uri}`);
1297
1370
  }
1298
- const fullPath = path3.isAbsolute(reference.localPath) ? reference.localPath : path3.join(this.baseDir, reference.localPath);
1371
+ const fullPath = path3__default.isAbsolute(reference.localPath) ? reference.localPath : path3__default.join(this.baseDir, reference.localPath);
1299
1372
  try {
1300
- await fs2.access(fullPath);
1373
+ await fs3__default.access(fullPath);
1301
1374
  } catch {
1302
1375
  throw new Error(`File not found: ${fullPath}`);
1303
1376
  }
1304
- const stats = await fs2.stat(fullPath);
1377
+ const stats = await fs3__default.stat(fullPath);
1305
1378
  if (stats.size > opts.maxSize) {
1306
1379
  throw new Error(
1307
1380
  `File too large: ${stats.size} bytes (max: ${opts.maxSize} bytes)`
1308
1381
  );
1309
1382
  }
1310
- const content = await fs2.readFile(fullPath);
1383
+ const content = await fs3__default.readFile(fullPath);
1311
1384
  return {
1312
1385
  content,
1313
1386
  contentType: detectContentType(reference.localPath),
@@ -1326,9 +1399,9 @@ var LocalStorage = class {
1326
1399
  if (!reference.localPath) {
1327
1400
  return false;
1328
1401
  }
1329
- const fullPath = path3.isAbsolute(reference.localPath) ? reference.localPath : path3.join(this.baseDir, reference.localPath);
1402
+ const fullPath = path3__default.isAbsolute(reference.localPath) ? reference.localPath : path3__default.join(this.baseDir, reference.localPath);
1330
1403
  try {
1331
- await fs2.access(fullPath);
1404
+ await fs3__default.access(fullPath);
1332
1405
  return true;
1333
1406
  } catch {
1334
1407
  return false;
@@ -1338,24 +1411,24 @@ var LocalStorage = class {
1338
1411
  * Read file content as string
1339
1412
  */
1340
1413
  async readText(filePath) {
1341
- const fullPath = path3.isAbsolute(filePath) ? filePath : path3.join(this.baseDir, filePath);
1342
- return fs2.readFile(fullPath, "utf-8");
1414
+ const fullPath = path3__default.isAbsolute(filePath) ? filePath : path3__default.join(this.baseDir, filePath);
1415
+ return fs3__default.readFile(fullPath, "utf-8");
1343
1416
  }
1344
1417
  /**
1345
1418
  * Write content to file
1346
1419
  */
1347
1420
  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);
1421
+ const fullPath = path3__default.isAbsolute(filePath) ? filePath : path3__default.join(this.baseDir, filePath);
1422
+ await fs3__default.mkdir(path3__default.dirname(fullPath), { recursive: true });
1423
+ await fs3__default.writeFile(fullPath, content);
1351
1424
  }
1352
1425
  /**
1353
1426
  * Delete a file
1354
1427
  */
1355
1428
  async delete(filePath) {
1356
- const fullPath = path3.isAbsolute(filePath) ? filePath : path3.join(this.baseDir, filePath);
1429
+ const fullPath = path3__default.isAbsolute(filePath) ? filePath : path3__default.join(this.baseDir, filePath);
1357
1430
  try {
1358
- await fs2.unlink(fullPath);
1431
+ await fs3__default.unlink(fullPath);
1359
1432
  return true;
1360
1433
  } catch {
1361
1434
  return false;
@@ -1365,10 +1438,10 @@ var LocalStorage = class {
1365
1438
  * List files in a directory
1366
1439
  */
1367
1440
  async list(dirPath) {
1368
- const fullPath = path3.isAbsolute(dirPath) ? dirPath : path3.join(this.baseDir, dirPath);
1441
+ const fullPath = path3__default.isAbsolute(dirPath) ? dirPath : path3__default.join(this.baseDir, dirPath);
1369
1442
  try {
1370
- const entries = await fs2.readdir(fullPath, { withFileTypes: true });
1371
- return entries.filter((e) => e.isFile()).map((e) => path3.join(dirPath, e.name));
1443
+ const entries = await fs3__default.readdir(fullPath, { withFileTypes: true });
1444
+ return entries.filter((e) => e.isFile()).map((e) => path3__default.join(dirPath, e.name));
1372
1445
  } catch {
1373
1446
  return [];
1374
1447
  }
@@ -1713,6 +1786,300 @@ var HttpStorage = class {
1713
1786
  function createHttpStorage(options) {
1714
1787
  return new HttpStorage(options);
1715
1788
  }
1789
+
1790
+ // src/file-integration/source-resolver.ts
1791
+ var FileSourceResolver = class {
1792
+ constructor(config) {
1793
+ this.config = config;
1794
+ this.initializeSources();
1795
+ }
1796
+ sources = /* @__PURE__ */ new Map();
1797
+ /**
1798
+ * Initialize sources from config
1799
+ */
1800
+ initializeSources() {
1801
+ if (!this.config.file?.sources) {
1802
+ return;
1803
+ }
1804
+ for (const [name, sourceConfig] of Object.entries(this.config.file.sources)) {
1805
+ const resolved = {
1806
+ name,
1807
+ type: "file-plugin",
1808
+ localPath: sourceConfig.local.base_path,
1809
+ isCurrentProject: true,
1810
+ config: sourceConfig
1811
+ };
1812
+ if (sourceConfig.bucket && sourceConfig.type !== "local") {
1813
+ resolved.bucket = sourceConfig.bucket;
1814
+ resolved.prefix = sourceConfig.prefix;
1815
+ resolved.remotePath = this.buildRemotePath(sourceConfig);
1816
+ }
1817
+ this.sources.set(name, resolved);
1818
+ }
1819
+ }
1820
+ /**
1821
+ * Build remote path from source config
1822
+ */
1823
+ buildRemotePath(source) {
1824
+ const protocol = source.type === "s3" ? "s3://" : source.type === "r2" ? "r2://" : "gcs://";
1825
+ const bucket = source.bucket;
1826
+ const prefix = source.prefix ? `/${source.prefix}` : "";
1827
+ return `${protocol}${bucket}${prefix}`;
1828
+ }
1829
+ /**
1830
+ * Get all available file plugin sources
1831
+ *
1832
+ * @returns Array of resolved file sources
1833
+ */
1834
+ getAvailableSources() {
1835
+ return Array.from(this.sources.values());
1836
+ }
1837
+ /**
1838
+ * Resolve a source by name
1839
+ *
1840
+ * @param name - Source name (e.g., "specs", "logs")
1841
+ * @returns Resolved source or null if not found
1842
+ */
1843
+ resolveSource(name) {
1844
+ return this.sources.get(name) || null;
1845
+ }
1846
+ /**
1847
+ * Check if a path belongs to any file plugin source
1848
+ *
1849
+ * @param path - File path to check
1850
+ * @returns True if path matches any source's base_path
1851
+ */
1852
+ isFilePluginPath(path7) {
1853
+ return this.getSourceForPath(path7) !== null;
1854
+ }
1855
+ /**
1856
+ * Get the source for a given path
1857
+ *
1858
+ * Matches path against all source base_paths and returns the matching source.
1859
+ * Uses longest-match strategy if multiple sources match.
1860
+ *
1861
+ * @param path - File path to match
1862
+ * @returns Matching source or null
1863
+ */
1864
+ getSourceForPath(path7) {
1865
+ let bestMatch = null;
1866
+ let bestMatchLength = 0;
1867
+ for (const source of this.sources.values()) {
1868
+ const normalizedPath = this.normalizePath(path7);
1869
+ const normalizedBasePath = this.normalizePath(source.localPath);
1870
+ if (normalizedPath.startsWith(normalizedBasePath)) {
1871
+ const matchLength = normalizedBasePath.length;
1872
+ if (matchLength > bestMatchLength) {
1873
+ bestMatch = source;
1874
+ bestMatchLength = matchLength;
1875
+ }
1876
+ }
1877
+ }
1878
+ return bestMatch;
1879
+ }
1880
+ /**
1881
+ * Normalize path for comparison
1882
+ * - Remove leading "./" or "/"
1883
+ * - Remove trailing "/"
1884
+ * - Convert to lowercase for case-insensitive comparison
1885
+ */
1886
+ normalizePath(path7) {
1887
+ return path7.replace(/^\.\//, "").replace(/^\//, "").replace(/\/$/, "").toLowerCase();
1888
+ }
1889
+ /**
1890
+ * Get source names
1891
+ *
1892
+ * @returns Array of source names
1893
+ */
1894
+ getSourceNames() {
1895
+ return Array.from(this.sources.keys());
1896
+ }
1897
+ /**
1898
+ * Check if sources are configured
1899
+ *
1900
+ * @returns True if any file plugin sources are configured
1901
+ */
1902
+ hasSources() {
1903
+ return this.sources.size > 0;
1904
+ }
1905
+ };
1906
+
1907
+ // src/storage/errors.ts
1908
+ var FilePluginFileNotFoundError = class _FilePluginFileNotFoundError extends Error {
1909
+ constructor(filePath, sourceName, options) {
1910
+ const includeCloudSuggestions = options?.includeCloudSuggestions !== false;
1911
+ const storageType = options?.storageType;
1912
+ let message = `File not found: ${filePath}
1913
+
1914
+ `;
1915
+ if (includeCloudSuggestions) {
1916
+ if (storageType) {
1917
+ message += `This file may be in cloud storage (${storageType}).
1918
+
1919
+ `;
1920
+ } else {
1921
+ message += `This file may not have been synced from remote storage yet.
1922
+ `;
1923
+ }
1924
+ message += `To fetch from cloud storage, run:
1925
+ `;
1926
+ message += ` file pull ${sourceName}
1927
+
1928
+ `;
1929
+ message += `Or sync all sources:
1930
+ `;
1931
+ message += ` file sync`;
1932
+ } else {
1933
+ message += `Please ensure the file exists locally or pull it from cloud storage.`;
1934
+ }
1935
+ super(message);
1936
+ this.filePath = filePath;
1937
+ this.sourceName = sourceName;
1938
+ this.name = "FilePluginFileNotFoundError";
1939
+ if (Error.captureStackTrace) {
1940
+ Error.captureStackTrace(this, _FilePluginFileNotFoundError);
1941
+ }
1942
+ }
1943
+ };
1944
+
1945
+ // src/storage/file-plugin.ts
1946
+ var FilePluginStorage = class {
1947
+ constructor(options) {
1948
+ this.options = options;
1949
+ this.sourceResolver = new FileSourceResolver(options.config);
1950
+ this.baseDir = options.baseDir || process.cwd();
1951
+ }
1952
+ name = "file-plugin";
1953
+ type = "local";
1954
+ // Reuse local type for compatibility
1955
+ sourceResolver;
1956
+ baseDir;
1957
+ /**
1958
+ * Check if this provider can handle the reference
1959
+ *
1960
+ * Only handles:
1961
+ * - Current project references
1962
+ * - With sourceType === 'file-plugin'
1963
+ *
1964
+ * @param reference - Resolved reference
1965
+ * @returns True if this provider can handle the reference
1966
+ */
1967
+ canHandle(reference) {
1968
+ return reference.isCurrentProject && reference.sourceType === "file-plugin";
1969
+ }
1970
+ /**
1971
+ * Fetch content for a reference
1972
+ *
1973
+ * Reads from local filesystem based on the resolved local path.
1974
+ * If file not found and S3 fallback is enabled, throws helpful error.
1975
+ *
1976
+ * @param reference - Resolved reference
1977
+ * @param options - Fetch options (unused for local reads)
1978
+ * @returns Fetch result with content
1979
+ */
1980
+ async fetch(reference, _options) {
1981
+ if (!reference.localPath) {
1982
+ throw new Error(`File plugin reference missing localPath: ${reference.uri}`);
1983
+ }
1984
+ if (!reference.filePluginSource) {
1985
+ throw new Error(`File plugin reference missing source name: ${reference.uri}`);
1986
+ }
1987
+ const absolutePath = path3.isAbsolute(reference.localPath) ? path3.resolve(reference.localPath) : path3.resolve(this.baseDir, reference.localPath);
1988
+ const source = this.sourceResolver.resolveSource(reference.filePluginSource);
1989
+ if (source) {
1990
+ const allowedDir = path3.resolve(this.baseDir, source.localPath);
1991
+ if (!absolutePath.startsWith(allowedDir + path3.sep) && absolutePath !== allowedDir) {
1992
+ throw new Error(
1993
+ `Path traversal detected: ${reference.localPath} resolves outside allowed directory ${source.localPath}`
1994
+ );
1995
+ }
1996
+ }
1997
+ try {
1998
+ const content = await fs3.readFile(absolutePath);
1999
+ const contentType = this.detectContentType(absolutePath);
2000
+ return {
2001
+ content,
2002
+ contentType,
2003
+ size: content.length,
2004
+ source: "file-plugin",
2005
+ metadata: {
2006
+ filePluginSource: reference.filePluginSource,
2007
+ localPath: absolutePath
2008
+ }
2009
+ };
2010
+ } catch (error) {
2011
+ if (error.code === "ENOENT") {
2012
+ const source2 = this.sourceResolver.resolveSource(reference.filePluginSource);
2013
+ throw this.createFileNotFoundError(reference, source2);
2014
+ }
2015
+ throw error;
2016
+ }
2017
+ }
2018
+ /**
2019
+ * Check if a reference exists
2020
+ *
2021
+ * @param reference - Resolved reference
2022
+ * @param options - Fetch options (unused)
2023
+ * @returns True if file exists
2024
+ */
2025
+ async exists(reference, _options) {
2026
+ if (!reference.localPath) {
2027
+ return false;
2028
+ }
2029
+ const absolutePath = path3.isAbsolute(reference.localPath) ? path3.resolve(reference.localPath) : path3.resolve(this.baseDir, reference.localPath);
2030
+ if (reference.filePluginSource) {
2031
+ const source = this.sourceResolver.resolveSource(reference.filePluginSource);
2032
+ if (source) {
2033
+ const allowedDir = path3.resolve(this.baseDir, source.localPath);
2034
+ if (!absolutePath.startsWith(allowedDir + path3.sep) && absolutePath !== allowedDir) {
2035
+ return false;
2036
+ }
2037
+ }
2038
+ }
2039
+ try {
2040
+ await fs3.access(absolutePath);
2041
+ return true;
2042
+ } catch {
2043
+ return false;
2044
+ }
2045
+ }
2046
+ /**
2047
+ * Detect content type from file extension
2048
+ */
2049
+ detectContentType(filePath) {
2050
+ const ext = path3.extname(filePath).toLowerCase();
2051
+ const mimeTypes = {
2052
+ ".md": "text/markdown",
2053
+ ".txt": "text/plain",
2054
+ ".json": "application/json",
2055
+ ".yaml": "text/yaml",
2056
+ ".yml": "text/yaml",
2057
+ ".html": "text/html",
2058
+ ".xml": "application/xml",
2059
+ ".log": "text/plain",
2060
+ ".js": "application/javascript",
2061
+ ".ts": "application/typescript",
2062
+ ".py": "text/x-python",
2063
+ ".sh": "application/x-sh"
2064
+ };
2065
+ return mimeTypes[ext] || "application/octet-stream";
2066
+ }
2067
+ /**
2068
+ * Create a helpful error message when file is not found
2069
+ */
2070
+ createFileNotFoundError(reference, source) {
2071
+ const includeCloudSuggestions = this.options.enableS3Fallback !== false;
2072
+ const storageType = source?.config.type;
2073
+ return new FilePluginFileNotFoundError(
2074
+ reference.localPath || reference.path || "",
2075
+ reference.filePluginSource || "",
2076
+ {
2077
+ includeCloudSuggestions,
2078
+ storageType
2079
+ }
2080
+ );
2081
+ }
2082
+ };
1716
2083
  var execFileAsync = promisify(execFile);
1717
2084
  async function execFileNoThrow(command, args = [], options) {
1718
2085
  try {
@@ -1862,10 +2229,10 @@ var S3ArchiveStorage = class {
1862
2229
  *
1863
2230
  * Used to organize archives by type
1864
2231
  */
1865
- detectType(path6) {
1866
- if (path6.startsWith("specs/")) return "specs";
1867
- if (path6.startsWith("docs/")) return "docs";
1868
- if (path6.includes("/logs/")) return "logs";
2232
+ detectType(path7) {
2233
+ if (path7.startsWith("specs/")) return "specs";
2234
+ if (path7.startsWith("docs/")) return "docs";
2235
+ if (path7.includes("/logs/")) return "logs";
1869
2236
  return "misc";
1870
2237
  }
1871
2238
  /**
@@ -1876,9 +2243,9 @@ var S3ArchiveStorage = class {
1876
2243
  * - *.md (all markdown files)
1877
2244
  * - docs/*.md (markdown files in docs/)
1878
2245
  */
1879
- matchesPatterns(path6, patterns) {
2246
+ matchesPatterns(path7, patterns) {
1880
2247
  for (const pattern of patterns) {
1881
- if (this.matchesPattern(path6, pattern)) {
2248
+ if (this.matchesPattern(path7, pattern)) {
1882
2249
  return true;
1883
2250
  }
1884
2251
  }
@@ -1887,14 +2254,14 @@ var S3ArchiveStorage = class {
1887
2254
  /**
1888
2255
  * Check if path matches a single pattern
1889
2256
  */
1890
- matchesPattern(path6, pattern) {
2257
+ matchesPattern(path7, pattern) {
1891
2258
  const DOUBLE_STAR = "\0DOUBLE_STAR\0";
1892
2259
  let regexPattern = pattern.replace(/\*\*/g, DOUBLE_STAR);
1893
2260
  regexPattern = regexPattern.replace(/[.[\](){}+^$|\\]/g, "\\$&");
1894
2261
  regexPattern = regexPattern.replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]");
1895
2262
  regexPattern = regexPattern.replace(new RegExp(DOUBLE_STAR, "g"), ".*");
1896
2263
  const regex = new RegExp(`^${regexPattern}$`);
1897
- return regex.test(path6);
2264
+ return regex.test(path7);
1898
2265
  }
1899
2266
  };
1900
2267
 
@@ -1909,7 +2276,10 @@ var StorageManager = class {
1909
2276
  if (config.s3Archive) {
1910
2277
  this.providers.set("s3-archive", new S3ArchiveStorage(config.s3Archive));
1911
2278
  }
1912
- this.priority = config.priority || (config.s3Archive ? ["local", "s3-archive", "github", "http"] : ["local", "github", "http"]);
2279
+ if (config.filePlugin) {
2280
+ this.providers.set("file-plugin", new FilePluginStorage(config.filePlugin));
2281
+ }
2282
+ 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"]);
1913
2283
  }
1914
2284
  /**
1915
2285
  * Register a custom storage provider
@@ -2149,7 +2519,7 @@ var CachePersistence = class {
2149
2519
  }
2150
2520
  const [, org, project, filePath] = match;
2151
2521
  const relativePath = filePath || "index";
2152
- return path3.join(this.cacheDir, org, project, relativePath + this.extension);
2522
+ return path3__default.join(this.cacheDir, org, project, relativePath + this.extension);
2153
2523
  }
2154
2524
  /**
2155
2525
  * Get the metadata file path for a URI
@@ -2165,8 +2535,8 @@ var CachePersistence = class {
2165
2535
  const metadataPath = this.getMetadataPath(uri);
2166
2536
  try {
2167
2537
  const [metadataJson, content] = await Promise.all([
2168
- fs2.readFile(metadataPath, "utf-8"),
2169
- fs2.readFile(cachePath)
2538
+ fs3__default.readFile(metadataPath, "utf-8"),
2539
+ fs3__default.readFile(cachePath)
2170
2540
  ]);
2171
2541
  const metadata = JSON.parse(metadataJson);
2172
2542
  return {
@@ -2186,32 +2556,32 @@ var CachePersistence = class {
2186
2556
  async write(entry) {
2187
2557
  const cachePath = this.getCachePath(entry.metadata.uri);
2188
2558
  const metadataPath = this.getMetadataPath(entry.metadata.uri);
2189
- await fs2.mkdir(path3.dirname(cachePath), { recursive: true });
2559
+ await fs3__default.mkdir(path3__default.dirname(cachePath), { recursive: true });
2190
2560
  if (this.atomicWrites) {
2191
2561
  const tempCachePath = cachePath + ".tmp";
2192
2562
  const tempMetadataPath = metadataPath + ".tmp";
2193
2563
  try {
2194
2564
  await Promise.all([
2195
- fs2.writeFile(tempCachePath, entry.content),
2196
- fs2.writeFile(tempMetadataPath, JSON.stringify(entry.metadata, null, 2))
2565
+ fs3__default.writeFile(tempCachePath, entry.content),
2566
+ fs3__default.writeFile(tempMetadataPath, JSON.stringify(entry.metadata, null, 2))
2197
2567
  ]);
2198
2568
  await Promise.all([
2199
- fs2.rename(tempCachePath, cachePath),
2200
- fs2.rename(tempMetadataPath, metadataPath)
2569
+ fs3__default.rename(tempCachePath, cachePath),
2570
+ fs3__default.rename(tempMetadataPath, metadataPath)
2201
2571
  ]);
2202
2572
  } catch (error) {
2203
2573
  await Promise.all([
2204
- fs2.unlink(tempCachePath).catch(() => {
2574
+ fs3__default.unlink(tempCachePath).catch(() => {
2205
2575
  }),
2206
- fs2.unlink(tempMetadataPath).catch(() => {
2576
+ fs3__default.unlink(tempMetadataPath).catch(() => {
2207
2577
  })
2208
2578
  ]);
2209
2579
  throw error;
2210
2580
  }
2211
2581
  } else {
2212
2582
  await Promise.all([
2213
- fs2.writeFile(cachePath, entry.content),
2214
- fs2.writeFile(metadataPath, JSON.stringify(entry.metadata, null, 2))
2583
+ fs3__default.writeFile(cachePath, entry.content),
2584
+ fs3__default.writeFile(metadataPath, JSON.stringify(entry.metadata, null, 2))
2215
2585
  ]);
2216
2586
  }
2217
2587
  }
@@ -2222,7 +2592,7 @@ var CachePersistence = class {
2222
2592
  const cachePath = this.getCachePath(uri);
2223
2593
  const metadataPath = this.getMetadataPath(uri);
2224
2594
  try {
2225
- await Promise.all([fs2.unlink(cachePath), fs2.unlink(metadataPath)]);
2595
+ await Promise.all([fs3__default.unlink(cachePath), fs3__default.unlink(metadataPath)]);
2226
2596
  return true;
2227
2597
  } catch (error) {
2228
2598
  if (error.code === "ENOENT") {
@@ -2237,7 +2607,7 @@ var CachePersistence = class {
2237
2607
  async exists(uri) {
2238
2608
  const cachePath = this.getCachePath(uri);
2239
2609
  try {
2240
- await fs2.access(cachePath);
2610
+ await fs3__default.access(cachePath);
2241
2611
  return true;
2242
2612
  } catch {
2243
2613
  return false;
@@ -2249,20 +2619,20 @@ var CachePersistence = class {
2249
2619
  async list() {
2250
2620
  const uris = [];
2251
2621
  try {
2252
- const orgs = await fs2.readdir(this.cacheDir);
2622
+ const orgs = await fs3__default.readdir(this.cacheDir);
2253
2623
  for (const org of orgs) {
2254
- const orgPath = path3.join(this.cacheDir, org);
2255
- const orgStat = await fs2.stat(orgPath);
2624
+ const orgPath = path3__default.join(this.cacheDir, org);
2625
+ const orgStat = await fs3__default.stat(orgPath);
2256
2626
  if (!orgStat.isDirectory()) continue;
2257
- const projects = await fs2.readdir(orgPath);
2627
+ const projects = await fs3__default.readdir(orgPath);
2258
2628
  for (const project of projects) {
2259
- const projectPath = path3.join(orgPath, project);
2260
- const projectStat = await fs2.stat(projectPath);
2629
+ const projectPath = path3__default.join(orgPath, project);
2630
+ const projectStat = await fs3__default.stat(projectPath);
2261
2631
  if (!projectStat.isDirectory()) continue;
2262
2632
  const files = await this.listFilesRecursive(projectPath);
2263
2633
  for (const file of files) {
2264
2634
  if (file.endsWith(this.extension)) {
2265
- const relativePath = path3.relative(projectPath, file);
2635
+ const relativePath = path3__default.relative(projectPath, file);
2266
2636
  const filePath = relativePath.slice(0, -this.extension.length);
2267
2637
  uris.push(`codex://${org}/${project}/${filePath}`);
2268
2638
  }
@@ -2282,9 +2652,9 @@ var CachePersistence = class {
2282
2652
  */
2283
2653
  async listFilesRecursive(dir) {
2284
2654
  const files = [];
2285
- const entries = await fs2.readdir(dir, { withFileTypes: true });
2655
+ const entries = await fs3__default.readdir(dir, { withFileTypes: true });
2286
2656
  for (const entry of entries) {
2287
- const fullPath = path3.join(dir, entry.name);
2657
+ const fullPath = path3__default.join(dir, entry.name);
2288
2658
  if (entry.isDirectory()) {
2289
2659
  files.push(...await this.listFilesRecursive(fullPath));
2290
2660
  } else if (entry.isFile()) {
@@ -2299,12 +2669,12 @@ var CachePersistence = class {
2299
2669
  async clear() {
2300
2670
  let count = 0;
2301
2671
  try {
2302
- const orgs = await fs2.readdir(this.cacheDir);
2672
+ const orgs = await fs3__default.readdir(this.cacheDir);
2303
2673
  for (const org of orgs) {
2304
- const orgPath = path3.join(this.cacheDir, org);
2305
- const stat = await fs2.stat(orgPath);
2674
+ const orgPath = path3__default.join(this.cacheDir, org);
2675
+ const stat = await fs3__default.stat(orgPath);
2306
2676
  if (stat.isDirectory()) {
2307
- await fs2.rm(orgPath, { recursive: true });
2677
+ await fs3__default.rm(orgPath, { recursive: true });
2308
2678
  count++;
2309
2679
  }
2310
2680
  }
@@ -2365,7 +2735,7 @@ var CachePersistence = class {
2365
2735
  * Ensure cache directory exists
2366
2736
  */
2367
2737
  async ensureDir() {
2368
- await fs2.mkdir(this.cacheDir, { recursive: true });
2738
+ await fs3__default.mkdir(this.cacheDir, { recursive: true });
2369
2739
  }
2370
2740
  /**
2371
2741
  * Get cache directory path
@@ -2413,8 +2783,17 @@ var CacheManager = class {
2413
2783
  * Get content for a reference
2414
2784
  *
2415
2785
  * Implements cache-first strategy with stale-while-revalidate.
2786
+ *
2787
+ * EXCEPTION: File plugin sources (current project files) bypass cache entirely.
2788
+ * They are always read fresh from disk for optimal development experience.
2416
2789
  */
2417
2790
  async get(reference, options) {
2791
+ if (reference.isCurrentProject && reference.sourceType === "file-plugin") {
2792
+ if (!this.storage) {
2793
+ throw new Error("Storage manager not set");
2794
+ }
2795
+ return await this.storage.fetch(reference, options);
2796
+ }
2418
2797
  const ttl = options?.ttl ?? this.config.defaultTtl;
2419
2798
  let entry = this.memoryCache.get(reference.uri);
2420
2799
  if (!entry && this.persistence) {
@@ -2620,13 +2999,18 @@ var CacheManager = class {
2620
2999
  }
2621
3000
  /**
2622
3001
  * Fetch content and store in cache
3002
+ *
3003
+ * EXCEPTION: File plugin sources are not cached (should not reach here,
3004
+ * but added as safety check).
2623
3005
  */
2624
3006
  async fetchAndCache(reference, ttl, options) {
2625
3007
  if (!this.storage) {
2626
3008
  throw new Error("Storage manager not set");
2627
3009
  }
2628
3010
  const result = await this.storage.fetch(reference, options);
2629
- await this.set(reference.uri, result, ttl);
3011
+ if (!(reference.isCurrentProject && reference.sourceType === "file-plugin")) {
3012
+ await this.set(reference.uri, result, ttl);
3013
+ }
2630
3014
  return result;
2631
3015
  }
2632
3016
  /**
@@ -2745,11 +3129,11 @@ var DEFAULT_SYNC_CONFIG = {
2745
3129
  deleteOrphans: false,
2746
3130
  conflictStrategy: "newest"
2747
3131
  };
2748
- function evaluatePath(path6, rules, direction, defaultExcludes = []) {
3132
+ function evaluatePath(path7, rules, direction, defaultExcludes = []) {
2749
3133
  for (const pattern of defaultExcludes) {
2750
- if (micromatch3.isMatch(path6, pattern)) {
3134
+ if (micromatch3.isMatch(path7, pattern)) {
2751
3135
  return {
2752
- path: path6,
3136
+ path: path7,
2753
3137
  shouldSync: false,
2754
3138
  reason: `Excluded by default pattern: ${pattern}`
2755
3139
  };
@@ -2760,9 +3144,9 @@ function evaluatePath(path6, rules, direction, defaultExcludes = []) {
2760
3144
  if (rule.direction && rule.direction !== direction) {
2761
3145
  continue;
2762
3146
  }
2763
- if (micromatch3.isMatch(path6, rule.pattern)) {
3147
+ if (micromatch3.isMatch(path7, rule.pattern)) {
2764
3148
  return {
2765
- path: path6,
3149
+ path: path7,
2766
3150
  shouldSync: rule.include,
2767
3151
  matchedRule: rule,
2768
3152
  reason: rule.include ? `Included by rule: ${rule.pattern}` : `Excluded by rule: ${rule.pattern}`
@@ -2770,21 +3154,21 @@ function evaluatePath(path6, rules, direction, defaultExcludes = []) {
2770
3154
  }
2771
3155
  }
2772
3156
  return {
2773
- path: path6,
3157
+ path: path7,
2774
3158
  shouldSync: true,
2775
3159
  reason: "No matching rule, included by default"
2776
3160
  };
2777
3161
  }
2778
3162
  function evaluatePaths(paths, rules, direction, defaultExcludes = []) {
2779
3163
  const results = /* @__PURE__ */ new Map();
2780
- for (const path6 of paths) {
2781
- results.set(path6, evaluatePath(path6, rules, direction, defaultExcludes));
3164
+ for (const path7 of paths) {
3165
+ results.set(path7, evaluatePath(path7, rules, direction, defaultExcludes));
2782
3166
  }
2783
3167
  return results;
2784
3168
  }
2785
3169
  function filterSyncablePaths(paths, rules, direction, defaultExcludes = []) {
2786
3170
  return paths.filter(
2787
- (path6) => evaluatePath(path6, rules, direction, defaultExcludes).shouldSync
3171
+ (path7) => evaluatePath(path7, rules, direction, defaultExcludes).shouldSync
2788
3172
  );
2789
3173
  }
2790
3174
  function createRulesFromPatterns(include = [], exclude = []) {
@@ -3050,8 +3434,8 @@ async function scanCodexWithRouting(options) {
3050
3434
  for (const filePath of allFiles) {
3051
3435
  totalScanned++;
3052
3436
  try {
3053
- const fullPath = path3.join(codexDir, filePath);
3054
- const stats = await fs2.stat(fullPath);
3437
+ const fullPath = path3__default.join(codexDir, filePath);
3438
+ const stats = await fs3__default.stat(fullPath);
3055
3439
  if (stats.size > maxFileSize) {
3056
3440
  totalSkipped++;
3057
3441
  errors.push({
@@ -3147,10 +3531,10 @@ async function listAllFilesRecursive(dirPath) {
3147
3531
  const files = [];
3148
3532
  async function scanDirectory(currentPath, relativePath = "") {
3149
3533
  try {
3150
- const entries = await fs2.readdir(currentPath, { withFileTypes: true });
3534
+ const entries = await fs3__default.readdir(currentPath, { withFileTypes: true });
3151
3535
  for (const entry of entries) {
3152
- const entryPath = path3.join(currentPath, entry.name);
3153
- const entryRelativePath = relativePath ? path3.join(relativePath, entry.name) : entry.name;
3536
+ const entryPath = path3__default.join(currentPath, entry.name);
3537
+ const entryRelativePath = relativePath ? path3__default.join(relativePath, entry.name) : entry.name;
3154
3538
  if (entry.isDirectory()) {
3155
3539
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build") {
3156
3540
  continue;
@@ -3389,17 +3773,17 @@ var SyncManager = class {
3389
3773
  if (file.operation === "create" || file.operation === "update") {
3390
3774
  const sourcePath = `${plan.source}/${file.path}`;
3391
3775
  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);
3776
+ const fs5 = await import('fs/promises');
3777
+ const path7 = await import('path');
3778
+ const targetDir = path7.dirname(targetPath);
3779
+ await fs5.mkdir(targetDir, { recursive: true });
3780
+ await fs5.copyFile(sourcePath, targetPath);
3397
3781
  synced++;
3398
3782
  } else if (file.operation === "delete") {
3399
3783
  const targetPath = `${plan.target}/${file.path}`;
3400
- const fs4 = await import('fs/promises');
3784
+ const fs5 = await import('fs/promises');
3401
3785
  try {
3402
- await fs4.unlink(targetPath);
3786
+ await fs5.unlink(targetPath);
3403
3787
  synced++;
3404
3788
  } catch (error) {
3405
3789
  if (error.code !== "ENOENT") {
@@ -3454,15 +3838,15 @@ var SyncManager = class {
3454
3838
  /**
3455
3839
  * Get sync status for a file
3456
3840
  */
3457
- async getFileStatus(path6) {
3841
+ async getFileStatus(path7) {
3458
3842
  const manifest = await this.loadManifest();
3459
- return manifest?.entries[path6] ?? null;
3843
+ return manifest?.entries[path7] ?? null;
3460
3844
  }
3461
3845
  /**
3462
3846
  * Check if a file is synced
3463
3847
  */
3464
- async isFileSynced(path6) {
3465
- const status = await this.getFileStatus(path6);
3848
+ async isFileSynced(path7) {
3849
+ const status = await this.getFileStatus(path7);
3466
3850
  return status !== null;
3467
3851
  }
3468
3852
  /**
@@ -3546,19 +3930,19 @@ function ruleMatchesContext(rule, context) {
3546
3930
  }
3547
3931
  return true;
3548
3932
  }
3549
- function ruleMatchesPath(rule, path6) {
3550
- return micromatch3.isMatch(path6, rule.pattern);
3933
+ function ruleMatchesPath(rule, path7) {
3934
+ return micromatch3.isMatch(path7, rule.pattern);
3551
3935
  }
3552
3936
  function ruleMatchesAction(rule, action) {
3553
3937
  return rule.actions.includes(action);
3554
3938
  }
3555
- function evaluatePermission(path6, action, context, config) {
3939
+ function evaluatePermission(path7, action, context, config) {
3556
3940
  const sortedRules = [...config.rules].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
3557
3941
  for (const rule of sortedRules) {
3558
3942
  if (!ruleMatchesContext(rule, context)) {
3559
3943
  continue;
3560
3944
  }
3561
- if (!ruleMatchesPath(rule, path6)) {
3945
+ if (!ruleMatchesPath(rule, path7)) {
3562
3946
  continue;
3563
3947
  }
3564
3948
  if (!ruleMatchesAction(rule, action)) {
@@ -3577,24 +3961,24 @@ function evaluatePermission(path6, action, context, config) {
3577
3961
  reason: config.defaultAllow ? "Allowed by default" : "Denied by default"
3578
3962
  };
3579
3963
  }
3580
- function isAllowed(path6, action, context, config) {
3581
- const result = evaluatePermission(path6, action, context, config);
3964
+ function isAllowed(path7, action, context, config) {
3965
+ const result = evaluatePermission(path7, action, context, config);
3582
3966
  return result.allowed;
3583
3967
  }
3584
- function hasPermission(path6, action, requiredLevel, context, config) {
3585
- const result = evaluatePermission(path6, action, context, config);
3968
+ function hasPermission(path7, action, requiredLevel, context, config) {
3969
+ const result = evaluatePermission(path7, action, context, config);
3586
3970
  return levelGrants(result.level, requiredLevel);
3587
3971
  }
3588
3972
  function evaluatePermissions(paths, action, context, config) {
3589
3973
  const results = /* @__PURE__ */ new Map();
3590
- for (const path6 of paths) {
3591
- results.set(path6, evaluatePermission(path6, action, context, config));
3974
+ for (const path7 of paths) {
3975
+ results.set(path7, evaluatePermission(path7, action, context, config));
3592
3976
  }
3593
3977
  return results;
3594
3978
  }
3595
3979
  function filterByPermission(paths, action, context, config, requiredLevel = "read") {
3596
- return paths.filter((path6) => {
3597
- const result = evaluatePermission(path6, action, context, config);
3980
+ return paths.filter((path7) => {
3981
+ const result = evaluatePermission(path7, action, context, config);
3598
3982
  return levelGrants(result.level, requiredLevel);
3599
3983
  });
3600
3984
  }
@@ -3685,21 +4069,21 @@ var PermissionManager = class {
3685
4069
  /**
3686
4070
  * Check if an action is allowed for a path
3687
4071
  */
3688
- isAllowed(path6, action, context) {
3689
- const result = this.evaluate(path6, action, context);
4072
+ isAllowed(path7, action, context) {
4073
+ const result = this.evaluate(path7, action, context);
3690
4074
  return result.allowed;
3691
4075
  }
3692
4076
  /**
3693
4077
  * Check if a permission level is granted
3694
4078
  */
3695
- hasPermission(path6, action, requiredLevel, context) {
3696
- const result = this.evaluate(path6, action, context);
4079
+ hasPermission(path7, action, requiredLevel, context) {
4080
+ const result = this.evaluate(path7, action, context);
3697
4081
  return levelGrants(result.level, requiredLevel);
3698
4082
  }
3699
4083
  /**
3700
4084
  * Evaluate permission for a path and action
3701
4085
  */
3702
- evaluate(path6, action, context) {
4086
+ evaluate(path7, action, context) {
3703
4087
  const mergedContext = { ...this.defaultContext, ...context };
3704
4088
  if (!this.config.enforced) {
3705
4089
  return {
@@ -3708,7 +4092,7 @@ var PermissionManager = class {
3708
4092
  reason: "Permissions not enforced"
3709
4093
  };
3710
4094
  }
3711
- return evaluatePermission(path6, action, mergedContext, this.config);
4095
+ return evaluatePermission(path7, action, mergedContext, this.config);
3712
4096
  }
3713
4097
  /**
3714
4098
  * Filter paths by permission
@@ -3811,12 +4195,12 @@ var PermissionManager = class {
3811
4195
  /**
3812
4196
  * Assert permission (throws if denied)
3813
4197
  */
3814
- assertPermission(path6, action, requiredLevel = "read", context) {
3815
- const result = this.evaluate(path6, action, context);
4198
+ assertPermission(path7, action, requiredLevel = "read", context) {
4199
+ const result = this.evaluate(path7, action, context);
3816
4200
  if (!levelGrants(result.level, requiredLevel)) {
3817
4201
  throw new PermissionDeniedError(
3818
- `Permission denied for ${action} on ${path6}: ${result.reason}`,
3819
- path6,
4202
+ `Permission denied for ${action} on ${path7}: ${result.reason}`,
4203
+ path7,
3820
4204
  action,
3821
4205
  result
3822
4206
  );
@@ -3824,9 +4208,9 @@ var PermissionManager = class {
3824
4208
  }
3825
4209
  };
3826
4210
  var PermissionDeniedError = class extends Error {
3827
- constructor(message, path6, action, result) {
4211
+ constructor(message, path7, action, result) {
3828
4212
  super(message);
3829
- this.path = path6;
4213
+ this.path = path7;
3830
4214
  this.action = action;
3831
4215
  this.result = result;
3832
4216
  this.name = "PermissionDeniedError";
@@ -4323,8 +4707,8 @@ function convertToUri(reference, options = {}) {
4323
4707
  const parts = parseReference2(trimmed);
4324
4708
  const org = parts.org || options.defaultOrg || "_";
4325
4709
  const project = parts.project || options.defaultProject || "_";
4326
- const path6 = parts.path;
4327
- return `codex://${org}/${project}/${path6}`;
4710
+ const path7 = parts.path;
4711
+ return `codex://${org}/${project}/${path7}`;
4328
4712
  }
4329
4713
  function parseReference2(reference) {
4330
4714
  const trimmed = reference.trim();
@@ -4404,6 +4788,6 @@ function generateReferenceMigrationSummary(results) {
4404
4788
  return lines.join("\n");
4405
4789
  }
4406
4790
 
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 };
4791
+ 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
4792
  //# sourceMappingURL=index.js.map
4409
4793
  //# sourceMappingURL=index.js.map