@fractary/codex 0.7.1 → 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.cjs +724 -116
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +570 -48
- package/dist/index.d.ts +570 -48
- package/dist/index.js +707 -117
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import micromatch3 from 'micromatch';
|
|
2
|
-
import path3 from 'path';
|
|
3
|
-
import
|
|
2
|
+
import * as path3 from 'path';
|
|
3
|
+
import path3__default from 'path';
|
|
4
|
+
import { execFile, execSync } from 'child_process';
|
|
4
5
|
import { z } from 'zod';
|
|
5
6
|
import yaml from 'js-yaml';
|
|
6
|
-
import
|
|
7
|
+
import * as fs3 from 'fs/promises';
|
|
8
|
+
import fs3__default from 'fs/promises';
|
|
9
|
+
import { promisify } from 'util';
|
|
7
10
|
|
|
8
11
|
var __defProp = Object.defineProperty;
|
|
9
12
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -160,7 +163,7 @@ function validatePath(filePath) {
|
|
|
160
163
|
return false;
|
|
161
164
|
}
|
|
162
165
|
}
|
|
163
|
-
const normalized =
|
|
166
|
+
const normalized = path3__default.normalize(filePath);
|
|
164
167
|
if (normalized.startsWith("..") || normalized.includes("/../") || normalized.includes("\\..\\")) {
|
|
165
168
|
return false;
|
|
166
169
|
}
|
|
@@ -178,7 +181,7 @@ function sanitizePath(filePath) {
|
|
|
178
181
|
}
|
|
179
182
|
sanitized = sanitized.replace(/^\/+/, "");
|
|
180
183
|
sanitized = sanitized.replace(/^~\//, "");
|
|
181
|
-
sanitized =
|
|
184
|
+
sanitized = path3__default.normalize(sanitized);
|
|
182
185
|
sanitized = sanitized.replace(/\.\.\//g, "").replace(/\.\./g, "");
|
|
183
186
|
sanitized = sanitized.replace(/^\.\//, "");
|
|
184
187
|
sanitized = sanitized.replace(/\0/g, "");
|
|
@@ -279,10 +282,10 @@ function parseReference(uri, options = {}) {
|
|
|
279
282
|
path: filePath
|
|
280
283
|
};
|
|
281
284
|
}
|
|
282
|
-
function buildUri(org, project,
|
|
285
|
+
function buildUri(org, project, path7) {
|
|
283
286
|
const base = `${CODEX_URI_PREFIX}${org}/${project}`;
|
|
284
|
-
if (
|
|
285
|
-
const cleanPath =
|
|
287
|
+
if (path7) {
|
|
288
|
+
const cleanPath = path7.startsWith("/") ? path7.slice(1) : path7;
|
|
286
289
|
return `${base}/${cleanPath}`;
|
|
287
290
|
}
|
|
288
291
|
return base;
|
|
@@ -353,7 +356,7 @@ function getCurrentContext(options = {}) {
|
|
|
353
356
|
return detectCurrentProject(options.cwd);
|
|
354
357
|
}
|
|
355
358
|
function calculateCachePath(org, project, filePath, cacheDir) {
|
|
356
|
-
return
|
|
359
|
+
return path3__default.join(cacheDir, org, project, filePath);
|
|
357
360
|
}
|
|
358
361
|
function resolveReference(uri, options = {}) {
|
|
359
362
|
const parsed = parseReference(uri);
|
|
@@ -362,7 +365,7 @@ function resolveReference(uri, options = {}) {
|
|
|
362
365
|
}
|
|
363
366
|
const cacheDir = options.cacheDir || DEFAULT_CACHE_DIR;
|
|
364
367
|
const currentContext = getCurrentContext(options);
|
|
365
|
-
const cachePath = parsed.path ? calculateCachePath(parsed.org, parsed.project, parsed.path, cacheDir) :
|
|
368
|
+
const cachePath = parsed.path ? calculateCachePath(parsed.org, parsed.project, parsed.path, cacheDir) : path3__default.join(cacheDir, parsed.org, parsed.project);
|
|
366
369
|
const isCurrentProject = currentContext.org === parsed.org && currentContext.project === parsed.project;
|
|
367
370
|
const resolved = {
|
|
368
371
|
...parsed,
|
|
@@ -371,9 +374,45 @@ function resolveReference(uri, options = {}) {
|
|
|
371
374
|
};
|
|
372
375
|
if (isCurrentProject && parsed.path) {
|
|
373
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
|
+
}
|
|
374
385
|
}
|
|
375
386
|
return resolved;
|
|
376
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
|
+
}
|
|
377
416
|
function resolveReferences(uris, options = {}) {
|
|
378
417
|
return uris.map((uri) => resolveReference(uri, options)).filter((r) => r !== null);
|
|
379
418
|
}
|
|
@@ -387,9 +426,9 @@ function getRelativeCachePath(uri) {
|
|
|
387
426
|
return null;
|
|
388
427
|
}
|
|
389
428
|
if (parsed.path) {
|
|
390
|
-
return
|
|
429
|
+
return path3__default.join(parsed.org, parsed.project, parsed.path);
|
|
391
430
|
}
|
|
392
|
-
return
|
|
431
|
+
return path3__default.join(parsed.org, parsed.project);
|
|
393
432
|
}
|
|
394
433
|
|
|
395
434
|
// src/types/built-in.ts
|
|
@@ -834,6 +873,16 @@ var DirectionalSyncSchema = z.object({
|
|
|
834
873
|
default_to_codex: z.array(z.string()).optional(),
|
|
835
874
|
default_from_codex: z.array(z.string()).optional()
|
|
836
875
|
});
|
|
876
|
+
var ArchiveProjectConfigSchema = z.object({
|
|
877
|
+
enabled: z.boolean(),
|
|
878
|
+
handler: z.enum(["s3", "r2", "gcs", "local"]),
|
|
879
|
+
bucket: z.string().optional(),
|
|
880
|
+
prefix: z.string().optional(),
|
|
881
|
+
patterns: z.array(z.string()).optional()
|
|
882
|
+
});
|
|
883
|
+
var ArchiveConfigSchema = z.object({
|
|
884
|
+
projects: z.record(ArchiveProjectConfigSchema)
|
|
885
|
+
});
|
|
837
886
|
var CodexConfigSchema = z.object({
|
|
838
887
|
organizationSlug: z.string(),
|
|
839
888
|
directories: z.object({
|
|
@@ -843,8 +892,45 @@ var CodexConfigSchema = z.object({
|
|
|
843
892
|
}).optional(),
|
|
844
893
|
rules: SyncRulesSchema.optional(),
|
|
845
894
|
// Directional sync configuration
|
|
846
|
-
sync: DirectionalSyncSchema.optional()
|
|
895
|
+
sync: DirectionalSyncSchema.optional(),
|
|
896
|
+
// Archive configuration
|
|
897
|
+
archive: ArchiveConfigSchema.optional()
|
|
847
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
|
+
});
|
|
848
934
|
function parseMetadata(content, options = {}) {
|
|
849
935
|
const { strict = true, normalize = true } = options;
|
|
850
936
|
const normalizedContent = normalize ? content.replace(/\r\n/g, "\n") : content;
|
|
@@ -968,11 +1054,17 @@ function getDefaultRules() {
|
|
|
968
1054
|
defaultExclude: []
|
|
969
1055
|
};
|
|
970
1056
|
}
|
|
1057
|
+
function getDefaultArchiveConfig() {
|
|
1058
|
+
return {
|
|
1059
|
+
projects: {}
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
971
1062
|
function getDefaultConfig(orgSlug) {
|
|
972
1063
|
return {
|
|
973
1064
|
organizationSlug: orgSlug,
|
|
974
1065
|
directories: getDefaultDirectories(orgSlug),
|
|
975
|
-
rules: getDefaultRules()
|
|
1066
|
+
rules: getDefaultRules(),
|
|
1067
|
+
archive: getDefaultArchiveConfig()
|
|
976
1068
|
};
|
|
977
1069
|
}
|
|
978
1070
|
|
|
@@ -1168,18 +1260,18 @@ function parseCustomDestination(value) {
|
|
|
1168
1260
|
);
|
|
1169
1261
|
}
|
|
1170
1262
|
const repo = value.substring(0, colonIndex).trim();
|
|
1171
|
-
const
|
|
1263
|
+
const path7 = value.substring(colonIndex + 1).trim();
|
|
1172
1264
|
if (!repo) {
|
|
1173
1265
|
throw new ValidationError(
|
|
1174
1266
|
`Invalid custom destination: repository name cannot be empty in "${value}"`
|
|
1175
1267
|
);
|
|
1176
1268
|
}
|
|
1177
|
-
if (!
|
|
1269
|
+
if (!path7) {
|
|
1178
1270
|
throw new ValidationError(
|
|
1179
1271
|
`Invalid custom destination: path cannot be empty in "${value}"`
|
|
1180
1272
|
);
|
|
1181
1273
|
}
|
|
1182
|
-
return { repo, path:
|
|
1274
|
+
return { repo, path: path7 };
|
|
1183
1275
|
}
|
|
1184
1276
|
function getCustomSyncDestinations(metadata) {
|
|
1185
1277
|
const customDestinations = metadata.codex_sync_custom;
|
|
@@ -1215,8 +1307,8 @@ function mergeFetchOptions(options) {
|
|
|
1215
1307
|
...options
|
|
1216
1308
|
};
|
|
1217
1309
|
}
|
|
1218
|
-
function detectContentType(
|
|
1219
|
-
const ext =
|
|
1310
|
+
function detectContentType(path7) {
|
|
1311
|
+
const ext = path7.split(".").pop()?.toLowerCase();
|
|
1220
1312
|
const mimeTypes = {
|
|
1221
1313
|
md: "text/markdown",
|
|
1222
1314
|
markdown: "text/markdown",
|
|
@@ -1276,19 +1368,19 @@ var LocalStorage = class {
|
|
|
1276
1368
|
if (!reference.localPath) {
|
|
1277
1369
|
throw new Error(`No local path for reference: ${reference.uri}`);
|
|
1278
1370
|
}
|
|
1279
|
-
const fullPath =
|
|
1371
|
+
const fullPath = path3__default.isAbsolute(reference.localPath) ? reference.localPath : path3__default.join(this.baseDir, reference.localPath);
|
|
1280
1372
|
try {
|
|
1281
|
-
await
|
|
1373
|
+
await fs3__default.access(fullPath);
|
|
1282
1374
|
} catch {
|
|
1283
1375
|
throw new Error(`File not found: ${fullPath}`);
|
|
1284
1376
|
}
|
|
1285
|
-
const stats = await
|
|
1377
|
+
const stats = await fs3__default.stat(fullPath);
|
|
1286
1378
|
if (stats.size > opts.maxSize) {
|
|
1287
1379
|
throw new Error(
|
|
1288
1380
|
`File too large: ${stats.size} bytes (max: ${opts.maxSize} bytes)`
|
|
1289
1381
|
);
|
|
1290
1382
|
}
|
|
1291
|
-
const content = await
|
|
1383
|
+
const content = await fs3__default.readFile(fullPath);
|
|
1292
1384
|
return {
|
|
1293
1385
|
content,
|
|
1294
1386
|
contentType: detectContentType(reference.localPath),
|
|
@@ -1307,9 +1399,9 @@ var LocalStorage = class {
|
|
|
1307
1399
|
if (!reference.localPath) {
|
|
1308
1400
|
return false;
|
|
1309
1401
|
}
|
|
1310
|
-
const fullPath =
|
|
1402
|
+
const fullPath = path3__default.isAbsolute(reference.localPath) ? reference.localPath : path3__default.join(this.baseDir, reference.localPath);
|
|
1311
1403
|
try {
|
|
1312
|
-
await
|
|
1404
|
+
await fs3__default.access(fullPath);
|
|
1313
1405
|
return true;
|
|
1314
1406
|
} catch {
|
|
1315
1407
|
return false;
|
|
@@ -1319,24 +1411,24 @@ var LocalStorage = class {
|
|
|
1319
1411
|
* Read file content as string
|
|
1320
1412
|
*/
|
|
1321
1413
|
async readText(filePath) {
|
|
1322
|
-
const fullPath =
|
|
1323
|
-
return
|
|
1414
|
+
const fullPath = path3__default.isAbsolute(filePath) ? filePath : path3__default.join(this.baseDir, filePath);
|
|
1415
|
+
return fs3__default.readFile(fullPath, "utf-8");
|
|
1324
1416
|
}
|
|
1325
1417
|
/**
|
|
1326
1418
|
* Write content to file
|
|
1327
1419
|
*/
|
|
1328
1420
|
async write(filePath, content) {
|
|
1329
|
-
const fullPath =
|
|
1330
|
-
await
|
|
1331
|
-
await
|
|
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);
|
|
1332
1424
|
}
|
|
1333
1425
|
/**
|
|
1334
1426
|
* Delete a file
|
|
1335
1427
|
*/
|
|
1336
1428
|
async delete(filePath) {
|
|
1337
|
-
const fullPath =
|
|
1429
|
+
const fullPath = path3__default.isAbsolute(filePath) ? filePath : path3__default.join(this.baseDir, filePath);
|
|
1338
1430
|
try {
|
|
1339
|
-
await
|
|
1431
|
+
await fs3__default.unlink(fullPath);
|
|
1340
1432
|
return true;
|
|
1341
1433
|
} catch {
|
|
1342
1434
|
return false;
|
|
@@ -1346,10 +1438,10 @@ var LocalStorage = class {
|
|
|
1346
1438
|
* List files in a directory
|
|
1347
1439
|
*/
|
|
1348
1440
|
async list(dirPath) {
|
|
1349
|
-
const fullPath =
|
|
1441
|
+
const fullPath = path3__default.isAbsolute(dirPath) ? dirPath : path3__default.join(this.baseDir, dirPath);
|
|
1350
1442
|
try {
|
|
1351
|
-
const entries = await
|
|
1352
|
-
return entries.filter((e) => e.isFile()).map((e) =>
|
|
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));
|
|
1353
1445
|
} catch {
|
|
1354
1446
|
return [];
|
|
1355
1447
|
}
|
|
@@ -1695,6 +1787,484 @@ function createHttpStorage(options) {
|
|
|
1695
1787
|
return new HttpStorage(options);
|
|
1696
1788
|
}
|
|
1697
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
|
+
};
|
|
2083
|
+
var execFileAsync = promisify(execFile);
|
|
2084
|
+
async function execFileNoThrow(command, args = [], options) {
|
|
2085
|
+
try {
|
|
2086
|
+
const { stdout, stderr } = await execFileAsync(command, args, {
|
|
2087
|
+
...options,
|
|
2088
|
+
maxBuffer: options?.maxBuffer || 1024 * 1024 * 10
|
|
2089
|
+
// 10MB default
|
|
2090
|
+
});
|
|
2091
|
+
return {
|
|
2092
|
+
stdout: stdout || "",
|
|
2093
|
+
stderr: stderr || "",
|
|
2094
|
+
exitCode: 0
|
|
2095
|
+
};
|
|
2096
|
+
} catch (error) {
|
|
2097
|
+
const exitCode = typeof error.exitCode === "number" ? error.exitCode : 1;
|
|
2098
|
+
return {
|
|
2099
|
+
stdout: error.stdout || "",
|
|
2100
|
+
stderr: error.stderr || error.message || "",
|
|
2101
|
+
exitCode
|
|
2102
|
+
};
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
// src/storage/s3-archive.ts
|
|
2107
|
+
var S3ArchiveStorage = class {
|
|
2108
|
+
name = "s3-archive";
|
|
2109
|
+
type = "s3-archive";
|
|
2110
|
+
projects;
|
|
2111
|
+
fractaryCli;
|
|
2112
|
+
constructor(options = {}) {
|
|
2113
|
+
this.projects = options.projects || {};
|
|
2114
|
+
this.fractaryCli = options.fractaryCli || "fractary";
|
|
2115
|
+
}
|
|
2116
|
+
/**
|
|
2117
|
+
* Check if this provider can handle the reference
|
|
2118
|
+
*
|
|
2119
|
+
* S3 Archive provider handles references that:
|
|
2120
|
+
* 1. Are for the current project (same org/project)
|
|
2121
|
+
* 2. Have archive enabled in config
|
|
2122
|
+
* 3. Match configured patterns (if specified)
|
|
2123
|
+
*/
|
|
2124
|
+
canHandle(reference) {
|
|
2125
|
+
if (!reference.isCurrentProject) {
|
|
2126
|
+
return false;
|
|
2127
|
+
}
|
|
2128
|
+
const projectKey = `${reference.org}/${reference.project}`;
|
|
2129
|
+
const config = this.projects[projectKey];
|
|
2130
|
+
if (!config || !config.enabled) {
|
|
2131
|
+
return false;
|
|
2132
|
+
}
|
|
2133
|
+
if (config.patterns && config.patterns.length > 0) {
|
|
2134
|
+
return this.matchesPatterns(reference.path, config.patterns);
|
|
2135
|
+
}
|
|
2136
|
+
return true;
|
|
2137
|
+
}
|
|
2138
|
+
/**
|
|
2139
|
+
* Fetch content from S3 archive via fractary-file CLI
|
|
2140
|
+
*/
|
|
2141
|
+
async fetch(reference, options) {
|
|
2142
|
+
const opts = mergeFetchOptions(options);
|
|
2143
|
+
const projectKey = `${reference.org}/${reference.project}`;
|
|
2144
|
+
const config = this.projects[projectKey];
|
|
2145
|
+
if (!config) {
|
|
2146
|
+
throw new Error(`No archive config for project: ${projectKey}`);
|
|
2147
|
+
}
|
|
2148
|
+
const archivePath = this.calculateArchivePath(reference, config);
|
|
2149
|
+
try {
|
|
2150
|
+
const result = await execFileNoThrow(
|
|
2151
|
+
this.fractaryCli,
|
|
2152
|
+
[
|
|
2153
|
+
"file",
|
|
2154
|
+
"read",
|
|
2155
|
+
"--remote-path",
|
|
2156
|
+
archivePath,
|
|
2157
|
+
"--handler",
|
|
2158
|
+
config.handler,
|
|
2159
|
+
...config.bucket ? ["--bucket", config.bucket] : []
|
|
2160
|
+
],
|
|
2161
|
+
{
|
|
2162
|
+
timeout: opts.timeout
|
|
2163
|
+
}
|
|
2164
|
+
);
|
|
2165
|
+
if (result.exitCode !== 0) {
|
|
2166
|
+
throw new Error(`fractary-file read failed: ${result.stderr}`);
|
|
2167
|
+
}
|
|
2168
|
+
const content = Buffer.from(result.stdout);
|
|
2169
|
+
return {
|
|
2170
|
+
content,
|
|
2171
|
+
contentType: detectContentType(reference.path),
|
|
2172
|
+
size: content.length,
|
|
2173
|
+
source: "s3-archive",
|
|
2174
|
+
metadata: {
|
|
2175
|
+
archivePath,
|
|
2176
|
+
bucket: config.bucket,
|
|
2177
|
+
handler: config.handler
|
|
2178
|
+
}
|
|
2179
|
+
};
|
|
2180
|
+
} catch (error) {
|
|
2181
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2182
|
+
throw new Error(`Failed to fetch from archive: ${message}`);
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
/**
|
|
2186
|
+
* Check if archived file exists
|
|
2187
|
+
*
|
|
2188
|
+
* Note: This currently downloads the file to check existence.
|
|
2189
|
+
* TODO: Optimize by using fractary-file 'stat' or 'head' command when available
|
|
2190
|
+
* to avoid downloading full file for existence checks.
|
|
2191
|
+
*/
|
|
2192
|
+
async exists(reference, options) {
|
|
2193
|
+
const projectKey = `${reference.org}/${reference.project}`;
|
|
2194
|
+
const config = this.projects[projectKey];
|
|
2195
|
+
if (!config) {
|
|
2196
|
+
return false;
|
|
2197
|
+
}
|
|
2198
|
+
try {
|
|
2199
|
+
await this.fetch(reference, { ...options, timeout: 5e3 });
|
|
2200
|
+
return true;
|
|
2201
|
+
} catch {
|
|
2202
|
+
return false;
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
/**
|
|
2206
|
+
* Calculate archive path from reference
|
|
2207
|
+
*
|
|
2208
|
+
* Pattern: {prefix}/{type}/{org}/{project}/{original-path}
|
|
2209
|
+
*
|
|
2210
|
+
* Examples (with default prefix "archive/"):
|
|
2211
|
+
* specs/WORK-123.md → archive/specs/org/project/specs/WORK-123.md
|
|
2212
|
+
* docs/api.md → archive/docs/org/project/docs/api.md
|
|
2213
|
+
*
|
|
2214
|
+
* Examples (with custom prefix "archived-docs/"):
|
|
2215
|
+
* specs/WORK-123.md → archived-docs/specs/org/project/specs/WORK-123.md
|
|
2216
|
+
*/
|
|
2217
|
+
calculateArchivePath(reference, config) {
|
|
2218
|
+
const type = this.detectType(reference.path);
|
|
2219
|
+
const prefix = config.prefix || "archive/";
|
|
2220
|
+
const trimmedPrefix = prefix.trim();
|
|
2221
|
+
if (!trimmedPrefix) {
|
|
2222
|
+
throw new Error("Archive prefix cannot be empty or whitespace-only");
|
|
2223
|
+
}
|
|
2224
|
+
const normalizedPrefix = trimmedPrefix.endsWith("/") ? trimmedPrefix : `${trimmedPrefix}/`;
|
|
2225
|
+
return `${normalizedPrefix}${type}/${reference.org}/${reference.project}/${reference.path}`;
|
|
2226
|
+
}
|
|
2227
|
+
/**
|
|
2228
|
+
* Detect artifact type from path
|
|
2229
|
+
*
|
|
2230
|
+
* Used to organize archives by type
|
|
2231
|
+
*/
|
|
2232
|
+
detectType(path7) {
|
|
2233
|
+
if (path7.startsWith("specs/")) return "specs";
|
|
2234
|
+
if (path7.startsWith("docs/")) return "docs";
|
|
2235
|
+
if (path7.includes("/logs/")) return "logs";
|
|
2236
|
+
return "misc";
|
|
2237
|
+
}
|
|
2238
|
+
/**
|
|
2239
|
+
* Check if path matches any of the patterns
|
|
2240
|
+
*
|
|
2241
|
+
* Supports glob-style patterns:
|
|
2242
|
+
* - specs/** (all files in specs/)
|
|
2243
|
+
* - *.md (all markdown files)
|
|
2244
|
+
* - docs/*.md (markdown files in docs/)
|
|
2245
|
+
*/
|
|
2246
|
+
matchesPatterns(path7, patterns) {
|
|
2247
|
+
for (const pattern of patterns) {
|
|
2248
|
+
if (this.matchesPattern(path7, pattern)) {
|
|
2249
|
+
return true;
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
return false;
|
|
2253
|
+
}
|
|
2254
|
+
/**
|
|
2255
|
+
* Check if path matches a single pattern
|
|
2256
|
+
*/
|
|
2257
|
+
matchesPattern(path7, pattern) {
|
|
2258
|
+
const DOUBLE_STAR = "\0DOUBLE_STAR\0";
|
|
2259
|
+
let regexPattern = pattern.replace(/\*\*/g, DOUBLE_STAR);
|
|
2260
|
+
regexPattern = regexPattern.replace(/[.[\](){}+^$|\\]/g, "\\$&");
|
|
2261
|
+
regexPattern = regexPattern.replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]");
|
|
2262
|
+
regexPattern = regexPattern.replace(new RegExp(DOUBLE_STAR, "g"), ".*");
|
|
2263
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
2264
|
+
return regex.test(path7);
|
|
2265
|
+
}
|
|
2266
|
+
};
|
|
2267
|
+
|
|
1698
2268
|
// src/storage/manager.ts
|
|
1699
2269
|
var StorageManager = class {
|
|
1700
2270
|
providers = /* @__PURE__ */ new Map();
|
|
@@ -1703,7 +2273,13 @@ var StorageManager = class {
|
|
|
1703
2273
|
this.providers.set("local", new LocalStorage(config.local));
|
|
1704
2274
|
this.providers.set("github", new GitHubStorage(config.github));
|
|
1705
2275
|
this.providers.set("http", new HttpStorage(config.http));
|
|
1706
|
-
|
|
2276
|
+
if (config.s3Archive) {
|
|
2277
|
+
this.providers.set("s3-archive", new S3ArchiveStorage(config.s3Archive));
|
|
2278
|
+
}
|
|
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"]);
|
|
1707
2283
|
}
|
|
1708
2284
|
/**
|
|
1709
2285
|
* Register a custom storage provider
|
|
@@ -1943,7 +2519,7 @@ var CachePersistence = class {
|
|
|
1943
2519
|
}
|
|
1944
2520
|
const [, org, project, filePath] = match;
|
|
1945
2521
|
const relativePath = filePath || "index";
|
|
1946
|
-
return
|
|
2522
|
+
return path3__default.join(this.cacheDir, org, project, relativePath + this.extension);
|
|
1947
2523
|
}
|
|
1948
2524
|
/**
|
|
1949
2525
|
* Get the metadata file path for a URI
|
|
@@ -1959,8 +2535,8 @@ var CachePersistence = class {
|
|
|
1959
2535
|
const metadataPath = this.getMetadataPath(uri);
|
|
1960
2536
|
try {
|
|
1961
2537
|
const [metadataJson, content] = await Promise.all([
|
|
1962
|
-
|
|
1963
|
-
|
|
2538
|
+
fs3__default.readFile(metadataPath, "utf-8"),
|
|
2539
|
+
fs3__default.readFile(cachePath)
|
|
1964
2540
|
]);
|
|
1965
2541
|
const metadata = JSON.parse(metadataJson);
|
|
1966
2542
|
return {
|
|
@@ -1980,32 +2556,32 @@ var CachePersistence = class {
|
|
|
1980
2556
|
async write(entry) {
|
|
1981
2557
|
const cachePath = this.getCachePath(entry.metadata.uri);
|
|
1982
2558
|
const metadataPath = this.getMetadataPath(entry.metadata.uri);
|
|
1983
|
-
await
|
|
2559
|
+
await fs3__default.mkdir(path3__default.dirname(cachePath), { recursive: true });
|
|
1984
2560
|
if (this.atomicWrites) {
|
|
1985
2561
|
const tempCachePath = cachePath + ".tmp";
|
|
1986
2562
|
const tempMetadataPath = metadataPath + ".tmp";
|
|
1987
2563
|
try {
|
|
1988
2564
|
await Promise.all([
|
|
1989
|
-
|
|
1990
|
-
|
|
2565
|
+
fs3__default.writeFile(tempCachePath, entry.content),
|
|
2566
|
+
fs3__default.writeFile(tempMetadataPath, JSON.stringify(entry.metadata, null, 2))
|
|
1991
2567
|
]);
|
|
1992
2568
|
await Promise.all([
|
|
1993
|
-
|
|
1994
|
-
|
|
2569
|
+
fs3__default.rename(tempCachePath, cachePath),
|
|
2570
|
+
fs3__default.rename(tempMetadataPath, metadataPath)
|
|
1995
2571
|
]);
|
|
1996
2572
|
} catch (error) {
|
|
1997
2573
|
await Promise.all([
|
|
1998
|
-
|
|
2574
|
+
fs3__default.unlink(tempCachePath).catch(() => {
|
|
1999
2575
|
}),
|
|
2000
|
-
|
|
2576
|
+
fs3__default.unlink(tempMetadataPath).catch(() => {
|
|
2001
2577
|
})
|
|
2002
2578
|
]);
|
|
2003
2579
|
throw error;
|
|
2004
2580
|
}
|
|
2005
2581
|
} else {
|
|
2006
2582
|
await Promise.all([
|
|
2007
|
-
|
|
2008
|
-
|
|
2583
|
+
fs3__default.writeFile(cachePath, entry.content),
|
|
2584
|
+
fs3__default.writeFile(metadataPath, JSON.stringify(entry.metadata, null, 2))
|
|
2009
2585
|
]);
|
|
2010
2586
|
}
|
|
2011
2587
|
}
|
|
@@ -2016,7 +2592,7 @@ var CachePersistence = class {
|
|
|
2016
2592
|
const cachePath = this.getCachePath(uri);
|
|
2017
2593
|
const metadataPath = this.getMetadataPath(uri);
|
|
2018
2594
|
try {
|
|
2019
|
-
await Promise.all([
|
|
2595
|
+
await Promise.all([fs3__default.unlink(cachePath), fs3__default.unlink(metadataPath)]);
|
|
2020
2596
|
return true;
|
|
2021
2597
|
} catch (error) {
|
|
2022
2598
|
if (error.code === "ENOENT") {
|
|
@@ -2031,7 +2607,7 @@ var CachePersistence = class {
|
|
|
2031
2607
|
async exists(uri) {
|
|
2032
2608
|
const cachePath = this.getCachePath(uri);
|
|
2033
2609
|
try {
|
|
2034
|
-
await
|
|
2610
|
+
await fs3__default.access(cachePath);
|
|
2035
2611
|
return true;
|
|
2036
2612
|
} catch {
|
|
2037
2613
|
return false;
|
|
@@ -2043,20 +2619,20 @@ var CachePersistence = class {
|
|
|
2043
2619
|
async list() {
|
|
2044
2620
|
const uris = [];
|
|
2045
2621
|
try {
|
|
2046
|
-
const orgs = await
|
|
2622
|
+
const orgs = await fs3__default.readdir(this.cacheDir);
|
|
2047
2623
|
for (const org of orgs) {
|
|
2048
|
-
const orgPath =
|
|
2049
|
-
const orgStat = await
|
|
2624
|
+
const orgPath = path3__default.join(this.cacheDir, org);
|
|
2625
|
+
const orgStat = await fs3__default.stat(orgPath);
|
|
2050
2626
|
if (!orgStat.isDirectory()) continue;
|
|
2051
|
-
const projects = await
|
|
2627
|
+
const projects = await fs3__default.readdir(orgPath);
|
|
2052
2628
|
for (const project of projects) {
|
|
2053
|
-
const projectPath =
|
|
2054
|
-
const projectStat = await
|
|
2629
|
+
const projectPath = path3__default.join(orgPath, project);
|
|
2630
|
+
const projectStat = await fs3__default.stat(projectPath);
|
|
2055
2631
|
if (!projectStat.isDirectory()) continue;
|
|
2056
2632
|
const files = await this.listFilesRecursive(projectPath);
|
|
2057
2633
|
for (const file of files) {
|
|
2058
2634
|
if (file.endsWith(this.extension)) {
|
|
2059
|
-
const relativePath =
|
|
2635
|
+
const relativePath = path3__default.relative(projectPath, file);
|
|
2060
2636
|
const filePath = relativePath.slice(0, -this.extension.length);
|
|
2061
2637
|
uris.push(`codex://${org}/${project}/${filePath}`);
|
|
2062
2638
|
}
|
|
@@ -2076,9 +2652,9 @@ var CachePersistence = class {
|
|
|
2076
2652
|
*/
|
|
2077
2653
|
async listFilesRecursive(dir) {
|
|
2078
2654
|
const files = [];
|
|
2079
|
-
const entries = await
|
|
2655
|
+
const entries = await fs3__default.readdir(dir, { withFileTypes: true });
|
|
2080
2656
|
for (const entry of entries) {
|
|
2081
|
-
const fullPath =
|
|
2657
|
+
const fullPath = path3__default.join(dir, entry.name);
|
|
2082
2658
|
if (entry.isDirectory()) {
|
|
2083
2659
|
files.push(...await this.listFilesRecursive(fullPath));
|
|
2084
2660
|
} else if (entry.isFile()) {
|
|
@@ -2093,12 +2669,12 @@ var CachePersistence = class {
|
|
|
2093
2669
|
async clear() {
|
|
2094
2670
|
let count = 0;
|
|
2095
2671
|
try {
|
|
2096
|
-
const orgs = await
|
|
2672
|
+
const orgs = await fs3__default.readdir(this.cacheDir);
|
|
2097
2673
|
for (const org of orgs) {
|
|
2098
|
-
const orgPath =
|
|
2099
|
-
const stat = await
|
|
2674
|
+
const orgPath = path3__default.join(this.cacheDir, org);
|
|
2675
|
+
const stat = await fs3__default.stat(orgPath);
|
|
2100
2676
|
if (stat.isDirectory()) {
|
|
2101
|
-
await
|
|
2677
|
+
await fs3__default.rm(orgPath, { recursive: true });
|
|
2102
2678
|
count++;
|
|
2103
2679
|
}
|
|
2104
2680
|
}
|
|
@@ -2159,7 +2735,7 @@ var CachePersistence = class {
|
|
|
2159
2735
|
* Ensure cache directory exists
|
|
2160
2736
|
*/
|
|
2161
2737
|
async ensureDir() {
|
|
2162
|
-
await
|
|
2738
|
+
await fs3__default.mkdir(this.cacheDir, { recursive: true });
|
|
2163
2739
|
}
|
|
2164
2740
|
/**
|
|
2165
2741
|
* Get cache directory path
|
|
@@ -2207,8 +2783,17 @@ var CacheManager = class {
|
|
|
2207
2783
|
* Get content for a reference
|
|
2208
2784
|
*
|
|
2209
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.
|
|
2210
2789
|
*/
|
|
2211
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
|
+
}
|
|
2212
2797
|
const ttl = options?.ttl ?? this.config.defaultTtl;
|
|
2213
2798
|
let entry = this.memoryCache.get(reference.uri);
|
|
2214
2799
|
if (!entry && this.persistence) {
|
|
@@ -2414,13 +2999,18 @@ var CacheManager = class {
|
|
|
2414
2999
|
}
|
|
2415
3000
|
/**
|
|
2416
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).
|
|
2417
3005
|
*/
|
|
2418
3006
|
async fetchAndCache(reference, ttl, options) {
|
|
2419
3007
|
if (!this.storage) {
|
|
2420
3008
|
throw new Error("Storage manager not set");
|
|
2421
3009
|
}
|
|
2422
3010
|
const result = await this.storage.fetch(reference, options);
|
|
2423
|
-
|
|
3011
|
+
if (!(reference.isCurrentProject && reference.sourceType === "file-plugin")) {
|
|
3012
|
+
await this.set(reference.uri, result, ttl);
|
|
3013
|
+
}
|
|
2424
3014
|
return result;
|
|
2425
3015
|
}
|
|
2426
3016
|
/**
|
|
@@ -2539,11 +3129,11 @@ var DEFAULT_SYNC_CONFIG = {
|
|
|
2539
3129
|
deleteOrphans: false,
|
|
2540
3130
|
conflictStrategy: "newest"
|
|
2541
3131
|
};
|
|
2542
|
-
function evaluatePath(
|
|
3132
|
+
function evaluatePath(path7, rules, direction, defaultExcludes = []) {
|
|
2543
3133
|
for (const pattern of defaultExcludes) {
|
|
2544
|
-
if (micromatch3.isMatch(
|
|
3134
|
+
if (micromatch3.isMatch(path7, pattern)) {
|
|
2545
3135
|
return {
|
|
2546
|
-
path:
|
|
3136
|
+
path: path7,
|
|
2547
3137
|
shouldSync: false,
|
|
2548
3138
|
reason: `Excluded by default pattern: ${pattern}`
|
|
2549
3139
|
};
|
|
@@ -2554,9 +3144,9 @@ function evaluatePath(path6, rules, direction, defaultExcludes = []) {
|
|
|
2554
3144
|
if (rule.direction && rule.direction !== direction) {
|
|
2555
3145
|
continue;
|
|
2556
3146
|
}
|
|
2557
|
-
if (micromatch3.isMatch(
|
|
3147
|
+
if (micromatch3.isMatch(path7, rule.pattern)) {
|
|
2558
3148
|
return {
|
|
2559
|
-
path:
|
|
3149
|
+
path: path7,
|
|
2560
3150
|
shouldSync: rule.include,
|
|
2561
3151
|
matchedRule: rule,
|
|
2562
3152
|
reason: rule.include ? `Included by rule: ${rule.pattern}` : `Excluded by rule: ${rule.pattern}`
|
|
@@ -2564,21 +3154,21 @@ function evaluatePath(path6, rules, direction, defaultExcludes = []) {
|
|
|
2564
3154
|
}
|
|
2565
3155
|
}
|
|
2566
3156
|
return {
|
|
2567
|
-
path:
|
|
3157
|
+
path: path7,
|
|
2568
3158
|
shouldSync: true,
|
|
2569
3159
|
reason: "No matching rule, included by default"
|
|
2570
3160
|
};
|
|
2571
3161
|
}
|
|
2572
3162
|
function evaluatePaths(paths, rules, direction, defaultExcludes = []) {
|
|
2573
3163
|
const results = /* @__PURE__ */ new Map();
|
|
2574
|
-
for (const
|
|
2575
|
-
results.set(
|
|
3164
|
+
for (const path7 of paths) {
|
|
3165
|
+
results.set(path7, evaluatePath(path7, rules, direction, defaultExcludes));
|
|
2576
3166
|
}
|
|
2577
3167
|
return results;
|
|
2578
3168
|
}
|
|
2579
3169
|
function filterSyncablePaths(paths, rules, direction, defaultExcludes = []) {
|
|
2580
3170
|
return paths.filter(
|
|
2581
|
-
(
|
|
3171
|
+
(path7) => evaluatePath(path7, rules, direction, defaultExcludes).shouldSync
|
|
2582
3172
|
);
|
|
2583
3173
|
}
|
|
2584
3174
|
function createRulesFromPatterns(include = [], exclude = []) {
|
|
@@ -2844,8 +3434,8 @@ async function scanCodexWithRouting(options) {
|
|
|
2844
3434
|
for (const filePath of allFiles) {
|
|
2845
3435
|
totalScanned++;
|
|
2846
3436
|
try {
|
|
2847
|
-
const fullPath =
|
|
2848
|
-
const stats = await
|
|
3437
|
+
const fullPath = path3__default.join(codexDir, filePath);
|
|
3438
|
+
const stats = await fs3__default.stat(fullPath);
|
|
2849
3439
|
if (stats.size > maxFileSize) {
|
|
2850
3440
|
totalSkipped++;
|
|
2851
3441
|
errors.push({
|
|
@@ -2941,10 +3531,10 @@ async function listAllFilesRecursive(dirPath) {
|
|
|
2941
3531
|
const files = [];
|
|
2942
3532
|
async function scanDirectory(currentPath, relativePath = "") {
|
|
2943
3533
|
try {
|
|
2944
|
-
const entries = await
|
|
3534
|
+
const entries = await fs3__default.readdir(currentPath, { withFileTypes: true });
|
|
2945
3535
|
for (const entry of entries) {
|
|
2946
|
-
const entryPath =
|
|
2947
|
-
const entryRelativePath = relativePath ?
|
|
3536
|
+
const entryPath = path3__default.join(currentPath, entry.name);
|
|
3537
|
+
const entryRelativePath = relativePath ? path3__default.join(relativePath, entry.name) : entry.name;
|
|
2948
3538
|
if (entry.isDirectory()) {
|
|
2949
3539
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build") {
|
|
2950
3540
|
continue;
|
|
@@ -3183,17 +3773,17 @@ var SyncManager = class {
|
|
|
3183
3773
|
if (file.operation === "create" || file.operation === "update") {
|
|
3184
3774
|
const sourcePath = `${plan.source}/${file.path}`;
|
|
3185
3775
|
const targetPath = `${plan.target}/${file.path}`;
|
|
3186
|
-
const
|
|
3187
|
-
const
|
|
3188
|
-
const targetDir =
|
|
3189
|
-
await
|
|
3190
|
-
await
|
|
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);
|
|
3191
3781
|
synced++;
|
|
3192
3782
|
} else if (file.operation === "delete") {
|
|
3193
3783
|
const targetPath = `${plan.target}/${file.path}`;
|
|
3194
|
-
const
|
|
3784
|
+
const fs5 = await import('fs/promises');
|
|
3195
3785
|
try {
|
|
3196
|
-
await
|
|
3786
|
+
await fs5.unlink(targetPath);
|
|
3197
3787
|
synced++;
|
|
3198
3788
|
} catch (error) {
|
|
3199
3789
|
if (error.code !== "ENOENT") {
|
|
@@ -3248,15 +3838,15 @@ var SyncManager = class {
|
|
|
3248
3838
|
/**
|
|
3249
3839
|
* Get sync status for a file
|
|
3250
3840
|
*/
|
|
3251
|
-
async getFileStatus(
|
|
3841
|
+
async getFileStatus(path7) {
|
|
3252
3842
|
const manifest = await this.loadManifest();
|
|
3253
|
-
return manifest?.entries[
|
|
3843
|
+
return manifest?.entries[path7] ?? null;
|
|
3254
3844
|
}
|
|
3255
3845
|
/**
|
|
3256
3846
|
* Check if a file is synced
|
|
3257
3847
|
*/
|
|
3258
|
-
async isFileSynced(
|
|
3259
|
-
const status = await this.getFileStatus(
|
|
3848
|
+
async isFileSynced(path7) {
|
|
3849
|
+
const status = await this.getFileStatus(path7);
|
|
3260
3850
|
return status !== null;
|
|
3261
3851
|
}
|
|
3262
3852
|
/**
|
|
@@ -3340,19 +3930,19 @@ function ruleMatchesContext(rule, context) {
|
|
|
3340
3930
|
}
|
|
3341
3931
|
return true;
|
|
3342
3932
|
}
|
|
3343
|
-
function ruleMatchesPath(rule,
|
|
3344
|
-
return micromatch3.isMatch(
|
|
3933
|
+
function ruleMatchesPath(rule, path7) {
|
|
3934
|
+
return micromatch3.isMatch(path7, rule.pattern);
|
|
3345
3935
|
}
|
|
3346
3936
|
function ruleMatchesAction(rule, action) {
|
|
3347
3937
|
return rule.actions.includes(action);
|
|
3348
3938
|
}
|
|
3349
|
-
function evaluatePermission(
|
|
3939
|
+
function evaluatePermission(path7, action, context, config) {
|
|
3350
3940
|
const sortedRules = [...config.rules].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
3351
3941
|
for (const rule of sortedRules) {
|
|
3352
3942
|
if (!ruleMatchesContext(rule, context)) {
|
|
3353
3943
|
continue;
|
|
3354
3944
|
}
|
|
3355
|
-
if (!ruleMatchesPath(rule,
|
|
3945
|
+
if (!ruleMatchesPath(rule, path7)) {
|
|
3356
3946
|
continue;
|
|
3357
3947
|
}
|
|
3358
3948
|
if (!ruleMatchesAction(rule, action)) {
|
|
@@ -3371,24 +3961,24 @@ function evaluatePermission(path6, action, context, config) {
|
|
|
3371
3961
|
reason: config.defaultAllow ? "Allowed by default" : "Denied by default"
|
|
3372
3962
|
};
|
|
3373
3963
|
}
|
|
3374
|
-
function isAllowed(
|
|
3375
|
-
const result = evaluatePermission(
|
|
3964
|
+
function isAllowed(path7, action, context, config) {
|
|
3965
|
+
const result = evaluatePermission(path7, action, context, config);
|
|
3376
3966
|
return result.allowed;
|
|
3377
3967
|
}
|
|
3378
|
-
function hasPermission(
|
|
3379
|
-
const result = evaluatePermission(
|
|
3968
|
+
function hasPermission(path7, action, requiredLevel, context, config) {
|
|
3969
|
+
const result = evaluatePermission(path7, action, context, config);
|
|
3380
3970
|
return levelGrants(result.level, requiredLevel);
|
|
3381
3971
|
}
|
|
3382
3972
|
function evaluatePermissions(paths, action, context, config) {
|
|
3383
3973
|
const results = /* @__PURE__ */ new Map();
|
|
3384
|
-
for (const
|
|
3385
|
-
results.set(
|
|
3974
|
+
for (const path7 of paths) {
|
|
3975
|
+
results.set(path7, evaluatePermission(path7, action, context, config));
|
|
3386
3976
|
}
|
|
3387
3977
|
return results;
|
|
3388
3978
|
}
|
|
3389
3979
|
function filterByPermission(paths, action, context, config, requiredLevel = "read") {
|
|
3390
|
-
return paths.filter((
|
|
3391
|
-
const result = evaluatePermission(
|
|
3980
|
+
return paths.filter((path7) => {
|
|
3981
|
+
const result = evaluatePermission(path7, action, context, config);
|
|
3392
3982
|
return levelGrants(result.level, requiredLevel);
|
|
3393
3983
|
});
|
|
3394
3984
|
}
|
|
@@ -3479,21 +4069,21 @@ var PermissionManager = class {
|
|
|
3479
4069
|
/**
|
|
3480
4070
|
* Check if an action is allowed for a path
|
|
3481
4071
|
*/
|
|
3482
|
-
isAllowed(
|
|
3483
|
-
const result = this.evaluate(
|
|
4072
|
+
isAllowed(path7, action, context) {
|
|
4073
|
+
const result = this.evaluate(path7, action, context);
|
|
3484
4074
|
return result.allowed;
|
|
3485
4075
|
}
|
|
3486
4076
|
/**
|
|
3487
4077
|
* Check if a permission level is granted
|
|
3488
4078
|
*/
|
|
3489
|
-
hasPermission(
|
|
3490
|
-
const result = this.evaluate(
|
|
4079
|
+
hasPermission(path7, action, requiredLevel, context) {
|
|
4080
|
+
const result = this.evaluate(path7, action, context);
|
|
3491
4081
|
return levelGrants(result.level, requiredLevel);
|
|
3492
4082
|
}
|
|
3493
4083
|
/**
|
|
3494
4084
|
* Evaluate permission for a path and action
|
|
3495
4085
|
*/
|
|
3496
|
-
evaluate(
|
|
4086
|
+
evaluate(path7, action, context) {
|
|
3497
4087
|
const mergedContext = { ...this.defaultContext, ...context };
|
|
3498
4088
|
if (!this.config.enforced) {
|
|
3499
4089
|
return {
|
|
@@ -3502,7 +4092,7 @@ var PermissionManager = class {
|
|
|
3502
4092
|
reason: "Permissions not enforced"
|
|
3503
4093
|
};
|
|
3504
4094
|
}
|
|
3505
|
-
return evaluatePermission(
|
|
4095
|
+
return evaluatePermission(path7, action, mergedContext, this.config);
|
|
3506
4096
|
}
|
|
3507
4097
|
/**
|
|
3508
4098
|
* Filter paths by permission
|
|
@@ -3605,12 +4195,12 @@ var PermissionManager = class {
|
|
|
3605
4195
|
/**
|
|
3606
4196
|
* Assert permission (throws if denied)
|
|
3607
4197
|
*/
|
|
3608
|
-
assertPermission(
|
|
3609
|
-
const result = this.evaluate(
|
|
4198
|
+
assertPermission(path7, action, requiredLevel = "read", context) {
|
|
4199
|
+
const result = this.evaluate(path7, action, context);
|
|
3610
4200
|
if (!levelGrants(result.level, requiredLevel)) {
|
|
3611
4201
|
throw new PermissionDeniedError(
|
|
3612
|
-
`Permission denied for ${action} on ${
|
|
3613
|
-
|
|
4202
|
+
`Permission denied for ${action} on ${path7}: ${result.reason}`,
|
|
4203
|
+
path7,
|
|
3614
4204
|
action,
|
|
3615
4205
|
result
|
|
3616
4206
|
);
|
|
@@ -3618,9 +4208,9 @@ var PermissionManager = class {
|
|
|
3618
4208
|
}
|
|
3619
4209
|
};
|
|
3620
4210
|
var PermissionDeniedError = class extends Error {
|
|
3621
|
-
constructor(message,
|
|
4211
|
+
constructor(message, path7, action, result) {
|
|
3622
4212
|
super(message);
|
|
3623
|
-
this.path =
|
|
4213
|
+
this.path = path7;
|
|
3624
4214
|
this.action = action;
|
|
3625
4215
|
this.result = result;
|
|
3626
4216
|
this.name = "PermissionDeniedError";
|
|
@@ -4117,8 +4707,8 @@ function convertToUri(reference, options = {}) {
|
|
|
4117
4707
|
const parts = parseReference2(trimmed);
|
|
4118
4708
|
const org = parts.org || options.defaultOrg || "_";
|
|
4119
4709
|
const project = parts.project || options.defaultProject || "_";
|
|
4120
|
-
const
|
|
4121
|
-
return `codex://${org}/${project}/${
|
|
4710
|
+
const path7 = parts.path;
|
|
4711
|
+
return `codex://${org}/${project}/${path7}`;
|
|
4122
4712
|
}
|
|
4123
4713
|
function parseReference2(reference) {
|
|
4124
4714
|
const trimmed = reference.trim();
|
|
@@ -4198,6 +4788,6 @@ function generateReferenceMigrationSummary(results) {
|
|
|
4198
4788
|
return lines.join("\n");
|
|
4199
4789
|
}
|
|
4200
4790
|
|
|
4201
|
-
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 };
|
|
4202
4792
|
//# sourceMappingURL=index.js.map
|
|
4203
4793
|
//# sourceMappingURL=index.js.map
|