@elliotding/ai-agent-mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/cached-client.d.ts +48 -0
- package/dist/api/cached-client.d.ts.map +1 -0
- package/dist/api/cached-client.js +126 -0
- package/dist/api/cached-client.js.map +1 -0
- package/dist/api/client.d.ts +213 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +326 -0
- package/dist/api/client.js.map +1 -0
- package/dist/auth/index.d.ts +8 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +26 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/middleware.d.ts +36 -0
- package/dist/auth/middleware.d.ts.map +1 -0
- package/dist/auth/middleware.js +194 -0
- package/dist/auth/middleware.js.map +1 -0
- package/dist/auth/permissions.d.ts +60 -0
- package/dist/auth/permissions.d.ts.map +1 -0
- package/dist/auth/permissions.js +256 -0
- package/dist/auth/permissions.js.map +1 -0
- package/dist/auth/token-validator.d.ts +52 -0
- package/dist/auth/token-validator.d.ts.map +1 -0
- package/dist/auth/token-validator.js +217 -0
- package/dist/auth/token-validator.js.map +1 -0
- package/dist/cache/cache-manager.d.ts +49 -0
- package/dist/cache/cache-manager.d.ts.map +1 -0
- package/dist/cache/cache-manager.js +191 -0
- package/dist/cache/cache-manager.js.map +1 -0
- package/dist/cache/index.d.ts +6 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +12 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/redis-client.d.ts +45 -0
- package/dist/cache/redis-client.d.ts.map +1 -0
- package/dist/cache/redis-client.js +210 -0
- package/dist/cache/redis-client.js.map +1 -0
- package/dist/config/constants.d.ts +28 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +31 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/config/index.d.ts +54 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +168 -0
- package/dist/config/index.js.map +1 -0
- package/dist/filesystem/manager.d.ts +45 -0
- package/dist/filesystem/manager.d.ts.map +1 -0
- package/dist/filesystem/manager.js +246 -0
- package/dist/filesystem/manager.js.map +1 -0
- package/dist/git/multi-source-manager.d.ts +62 -0
- package/dist/git/multi-source-manager.d.ts.map +1 -0
- package/dist/git/multi-source-manager.js +293 -0
- package/dist/git/multi-source-manager.js.map +1 -0
- package/dist/git/operations.d.ts +27 -0
- package/dist/git/operations.d.ts.map +1 -0
- package/dist/git/operations.js +83 -0
- package/dist/git/operations.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +109 -0
- package/dist/index.js.map +1 -0
- package/dist/monitoring/health.d.ts +35 -0
- package/dist/monitoring/health.d.ts.map +1 -0
- package/dist/monitoring/health.js +105 -0
- package/dist/monitoring/health.js.map +1 -0
- package/dist/resources/index.d.ts +6 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +10 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/loader.d.ts +87 -0
- package/dist/resources/loader.d.ts.map +1 -0
- package/dist/resources/loader.js +452 -0
- package/dist/resources/loader.js.map +1 -0
- package/dist/server/http.d.ts +57 -0
- package/dist/server/http.d.ts.map +1 -0
- package/dist/server/http.js +336 -0
- package/dist/server/http.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +157 -0
- package/dist/server.js.map +1 -0
- package/dist/session/manager.d.ts +91 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +251 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +27 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/manage-subscription.d.ts +43 -0
- package/dist/tools/manage-subscription.d.ts.map +1 -0
- package/dist/tools/manage-subscription.js +268 -0
- package/dist/tools/manage-subscription.js.map +1 -0
- package/dist/tools/registry.d.ts +40 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +85 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/search-resources.d.ts +31 -0
- package/dist/tools/search-resources.d.ts.map +1 -0
- package/dist/tools/search-resources.js +154 -0
- package/dist/tools/search-resources.js.map +1 -0
- package/dist/tools/sync-resources.d.ts +41 -0
- package/dist/tools/sync-resources.d.ts.map +1 -0
- package/dist/tools/sync-resources.js +606 -0
- package/dist/tools/sync-resources.js.map +1 -0
- package/dist/tools/uninstall-resource.d.ts +30 -0
- package/dist/tools/uninstall-resource.d.ts.map +1 -0
- package/dist/tools/uninstall-resource.js +259 -0
- package/dist/tools/uninstall-resource.js.map +1 -0
- package/dist/tools/upload-resource.d.ts +77 -0
- package/dist/tools/upload-resource.d.ts.map +1 -0
- package/dist/tools/upload-resource.js +252 -0
- package/dist/tools/upload-resource.js.map +1 -0
- package/dist/transport/sse.d.ts +29 -0
- package/dist/transport/sse.d.ts.map +1 -0
- package/dist/transport/sse.js +271 -0
- package/dist/transport/sse.js.map +1 -0
- package/dist/types/errors.d.ts +60 -0
- package/dist/types/errors.d.ts.map +1 -0
- package/dist/types/errors.js +112 -0
- package/dist/types/errors.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +23 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/mcp.d.ts +50 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +6 -0
- package/dist/types/mcp.js.map +1 -0
- package/dist/types/resources.d.ts +109 -0
- package/dist/types/resources.d.ts.map +1 -0
- package/dist/types/resources.js +7 -0
- package/dist/types/resources.js.map +1 -0
- package/dist/types/tools.d.ts +147 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/types/tools.js +6 -0
- package/dist/types/tools.js.map +1 -0
- package/dist/utils/cursor-paths.d.ts +49 -0
- package/dist/utils/cursor-paths.d.ts.map +1 -0
- package/dist/utils/cursor-paths.js +116 -0
- package/dist/utils/cursor-paths.js.map +1 -0
- package/dist/utils/log-cleaner.d.ts +18 -0
- package/dist/utils/log-cleaner.d.ts.map +1 -0
- package/dist/utils/log-cleaner.js +112 -0
- package/dist/utils/log-cleaner.js.map +1 -0
- package/dist/utils/logger.d.ts +59 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +292 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/validation.d.ts +58 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +214 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +58 -0
- package/src/api/cached-client.ts +144 -0
- package/src/api/client.ts +578 -0
- package/src/auth/index.ts +11 -0
- package/src/auth/middleware.ts +244 -0
- package/src/auth/permissions.ts +317 -0
- package/src/auth/token-validator.ts +294 -0
- package/src/cache/cache-manager.ts +243 -0
- package/src/cache/index.ts +6 -0
- package/src/cache/redis-client.ts +249 -0
- package/src/config/constants.ts +33 -0
- package/src/config/index.ts +228 -0
- package/src/filesystem/manager.ts +235 -0
- package/src/git/multi-source-manager.ts +333 -0
- package/src/git/operations.ts +93 -0
- package/src/index.ts +139 -0
- package/src/monitoring/health.ts +132 -0
- package/src/resources/index.ts +13 -0
- package/src/resources/loader.ts +530 -0
- package/src/server/http.ts +427 -0
- package/src/server.ts +191 -0
- package/src/session/manager.ts +296 -0
- package/src/tools/index.ts +11 -0
- package/src/tools/manage-subscription.ts +332 -0
- package/src/tools/registry.ts +97 -0
- package/src/tools/search-resources.ts +177 -0
- package/src/tools/sync-resources.ts +662 -0
- package/src/tools/uninstall-resource.ts +248 -0
- package/src/tools/upload-resource.ts +258 -0
- package/src/transport/sse.ts +308 -0
- package/src/types/errors.ts +146 -0
- package/src/types/index.ts +7 -0
- package/src/types/mcp.ts +61 -0
- package/src/types/resources.ts +141 -0
- package/src/types/tools.ts +175 -0
- package/src/utils/cursor-paths.ts +83 -0
- package/src/utils/log-cleaner.ts +92 -0
- package/src/utils/logger.ts +333 -0
- package/src/utils/validation.ts +262 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HealthChecker = void 0;
|
|
4
|
+
class HealthChecker {
|
|
5
|
+
cacheManager = null;
|
|
6
|
+
constructor(cacheManager) {
|
|
7
|
+
this.cacheManager = cacheManager || null;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Check HTTP Server health
|
|
11
|
+
*/
|
|
12
|
+
checkHttpServer() {
|
|
13
|
+
// HTTP server is up if this code is running
|
|
14
|
+
return 'up';
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Check Redis connection health
|
|
18
|
+
*/
|
|
19
|
+
async checkRedis() {
|
|
20
|
+
if (!this.cacheManager) {
|
|
21
|
+
return { status: 'not_configured' };
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
// Try to check Redis connection via cache manager
|
|
25
|
+
const redisCache = this.cacheManager.l2Cache;
|
|
26
|
+
if (!redisCache) {
|
|
27
|
+
return { status: 'not_configured' };
|
|
28
|
+
}
|
|
29
|
+
// Try a simple Redis operation (check client status)
|
|
30
|
+
const client = redisCache.client;
|
|
31
|
+
if (!client || !client.isReady) {
|
|
32
|
+
return { status: 'down', error: 'Redis client not ready' };
|
|
33
|
+
}
|
|
34
|
+
// Try a ping operation
|
|
35
|
+
await client.ping();
|
|
36
|
+
return { status: 'up' };
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return {
|
|
40
|
+
status: 'down',
|
|
41
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check Cache health
|
|
47
|
+
*/
|
|
48
|
+
checkCache() {
|
|
49
|
+
if (!this.cacheManager) {
|
|
50
|
+
return { status: 'down', error: 'Cache manager not initialized' };
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
// Check if cache manager is functional
|
|
54
|
+
const stats = this.cacheManager.getStats();
|
|
55
|
+
// Cache is healthy if stats are available
|
|
56
|
+
if (stats && typeof stats.hitRate === 'number') {
|
|
57
|
+
// Check if hit rate is reasonable (> 0 means cache is working)
|
|
58
|
+
if (stats.hitRate >= 0) {
|
|
59
|
+
return { status: 'healthy' };
|
|
60
|
+
}
|
|
61
|
+
return { status: 'degraded', error: 'Low cache hit rate' };
|
|
62
|
+
}
|
|
63
|
+
return { status: 'degraded', error: 'Cache stats unavailable' };
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
return {
|
|
67
|
+
status: 'down',
|
|
68
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Perform comprehensive health check
|
|
74
|
+
*/
|
|
75
|
+
async check() {
|
|
76
|
+
const httpStatus = this.checkHttpServer();
|
|
77
|
+
const redisResult = await this.checkRedis();
|
|
78
|
+
const cacheResult = this.checkCache();
|
|
79
|
+
const allHealthy = httpStatus === 'up' &&
|
|
80
|
+
(redisResult.status === 'up' || redisResult.status === 'not_configured') &&
|
|
81
|
+
cacheResult.status === 'healthy';
|
|
82
|
+
const health = {
|
|
83
|
+
status: allHealthy ? 'healthy' : 'unhealthy',
|
|
84
|
+
timestamp: new Date().toISOString(),
|
|
85
|
+
services: {
|
|
86
|
+
http: httpStatus,
|
|
87
|
+
redis: redisResult.status,
|
|
88
|
+
cache: cacheResult.status
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
// Add error details if any
|
|
92
|
+
if (redisResult.error || cacheResult.error) {
|
|
93
|
+
health.details = {};
|
|
94
|
+
if (redisResult.error) {
|
|
95
|
+
health.details.redisError = redisResult.error;
|
|
96
|
+
}
|
|
97
|
+
if (cacheResult.error) {
|
|
98
|
+
health.details.cacheError = cacheResult.error;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return health;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
exports.HealthChecker = HealthChecker;
|
|
105
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/monitoring/health.ts"],"names":[],"mappings":";;;AAgBA,MAAa,aAAa;IAChB,YAAY,GAAwB,IAAI,CAAC;IAEjD,YAAY,YAA2B;QACrC,IAAI,CAAC,YAAY,GAAG,YAAY,IAAI,IAAI,CAAC;IAC3C,CAAC;IAED;;OAEG;IACK,eAAe;QACrB,4CAA4C;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,UAAU;QACtB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;QACtC,CAAC;QAED,IAAI,CAAC;YACH,kDAAkD;YAClD,MAAM,UAAU,GAAI,IAAI,CAAC,YAAoB,CAAC,OAAO,CAAC;YAEtD,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,OAAO,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;YACtC,CAAC;YAED,qDAAqD;YACrD,MAAM,MAAM,GAAI,UAAkB,CAAC,MAAM,CAAC;YAE1C,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,wBAAwB,EAAE,CAAC;YAC7D,CAAC;YAED,uBAAuB;YACvB,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC1B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,MAAM,EAAE,MAAM;gBACd,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;aAChE,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACK,UAAU;QAChB,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC;QACpE,CAAC;QAED,IAAI,CAAC;YACH,uCAAuC;YACvC,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC;YAE3C,0CAA0C;YAC1C,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAC/C,+DAA+D;gBAC/D,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,EAAE,CAAC;oBACvB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;gBAC/B,CAAC;gBACD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC;YAC7D,CAAC;YAED,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC;QAClE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,MAAM,EAAE,MAAM;gBACd,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;aAChE,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAC1C,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAC5C,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;QAEtC,MAAM,UAAU,GACd,UAAU,KAAK,IAAI;YACnB,CAAC,WAAW,CAAC,MAAM,KAAK,IAAI,IAAI,WAAW,CAAC,MAAM,KAAK,gBAAgB,CAAC;YACxE,WAAW,CAAC,MAAM,KAAK,SAAS,CAAC;QAEnC,MAAM,MAAM,GAAiB;YAC3B,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW;YAC5C,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,QAAQ,EAAE;gBACR,IAAI,EAAE,UAAU;gBAChB,KAAK,EAAE,WAAW,CAAC,MAAM;gBACzB,KAAK,EAAE,WAAW,CAAC,MAAM;aAC1B;SACF,CAAC;QAEF,2BAA2B;QAC3B,IAAI,WAAW,CAAC,KAAK,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;YAC3C,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC;YACpB,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;gBACtB,MAAM,CAAC,OAAO,CAAC,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC;YAChD,CAAC;YACD,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;gBACtB,MAAM,CAAC,OAAO,CAAC,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC;YAChD,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAnHD,sCAmHC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resources Module Exports
|
|
3
|
+
*/
|
|
4
|
+
export { ResourceLoader, resourceLoader } from './loader';
|
|
5
|
+
export type { AIResourcesConfig, ResourceMetadata, ResourceType, ResourceSource, ResourceConflict, LoaderStats, } from '../types/resources';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1D,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,WAAW,GACZ,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Resources Module Exports
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resourceLoader = exports.ResourceLoader = void 0;
|
|
7
|
+
var loader_1 = require("./loader");
|
|
8
|
+
Object.defineProperty(exports, "ResourceLoader", { enumerable: true, get: function () { return loader_1.ResourceLoader; } });
|
|
9
|
+
Object.defineProperty(exports, "resourceLoader", { enumerable: true, get: function () { return loader_1.resourceLoader; } });
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAEH,mCAA0D;AAAjD,wGAAA,cAAc,OAAA;AAAE,wGAAA,cAAc,OAAA"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resource Loader Module
|
|
3
|
+
* Manages multi-source AI resource loading and indexing
|
|
4
|
+
*
|
|
5
|
+
* Implements AI Resources Multi-Source Architecture as defined in:
|
|
6
|
+
* @see Docs/AI-Resources-Multi-Source-Architecture.md
|
|
7
|
+
* @see AGENTS.md (AI Resources 开发约束)
|
|
8
|
+
*/
|
|
9
|
+
import type { ResourceMetadata, ResourceType, ResourceConflict, LoaderStats } from '../types/resources';
|
|
10
|
+
/**
|
|
11
|
+
* Resource Loader
|
|
12
|
+
*
|
|
13
|
+
* Key responsibilities:
|
|
14
|
+
* 1. Load and validate ai-resources-config.json
|
|
15
|
+
* 2. Scan resources from multiple sources
|
|
16
|
+
* 3. Build resource index with priority
|
|
17
|
+
* 4. Resolve resource name conflicts
|
|
18
|
+
* 5. Provide unified resource query interface
|
|
19
|
+
*/
|
|
20
|
+
export declare class ResourceLoader {
|
|
21
|
+
private config;
|
|
22
|
+
private resourceIndex;
|
|
23
|
+
private conflicts;
|
|
24
|
+
private stats;
|
|
25
|
+
private loaded;
|
|
26
|
+
private cacheEnabled;
|
|
27
|
+
private cacheTTL;
|
|
28
|
+
private lastLoadTime;
|
|
29
|
+
/**
|
|
30
|
+
* Load AI Resources configuration file
|
|
31
|
+
*/
|
|
32
|
+
loadConfig(configPath?: string): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Validate configuration structure and constraints
|
|
35
|
+
*/
|
|
36
|
+
private validateConfig;
|
|
37
|
+
/**
|
|
38
|
+
* Get default configuration (fallback)
|
|
39
|
+
*/
|
|
40
|
+
private getDefaultConfig;
|
|
41
|
+
/**
|
|
42
|
+
* Scan and index resources from all sources
|
|
43
|
+
*/
|
|
44
|
+
scanResources(): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Scan resources from a single source
|
|
47
|
+
*/
|
|
48
|
+
private scanSource;
|
|
49
|
+
/**
|
|
50
|
+
* Scan resources of a specific type from a directory
|
|
51
|
+
*/
|
|
52
|
+
private scanResourceType;
|
|
53
|
+
/**
|
|
54
|
+
* Index a single resource with conflict detection
|
|
55
|
+
*/
|
|
56
|
+
private indexResource;
|
|
57
|
+
/**
|
|
58
|
+
* Get all resources by type
|
|
59
|
+
*/
|
|
60
|
+
getResourcesByType(type: ResourceType): ResourceMetadata[];
|
|
61
|
+
/**
|
|
62
|
+
* Get resource by ID (type:name)
|
|
63
|
+
*/
|
|
64
|
+
getResourceById(id: string): ResourceMetadata | null;
|
|
65
|
+
/**
|
|
66
|
+
* Search resources by name
|
|
67
|
+
*/
|
|
68
|
+
searchResourcesByName(name: string, type?: ResourceType): ResourceMetadata[];
|
|
69
|
+
/**
|
|
70
|
+
* Get all detected conflicts
|
|
71
|
+
*/
|
|
72
|
+
getConflicts(): ResourceConflict[];
|
|
73
|
+
/**
|
|
74
|
+
* Get loader statistics
|
|
75
|
+
*/
|
|
76
|
+
getStats(): LoaderStats | null;
|
|
77
|
+
/**
|
|
78
|
+
* Refresh resource index (clear cache and rescan)
|
|
79
|
+
*/
|
|
80
|
+
refresh(): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* Ensure resources are loaded
|
|
83
|
+
*/
|
|
84
|
+
private ensureLoaded;
|
|
85
|
+
}
|
|
86
|
+
export declare const resourceLoader: ResourceLoader;
|
|
87
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/resources/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAEV,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACZ,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;GASG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,aAAa,CAA4C;IACjE,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,MAAM,CAAkB;IAGhC,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,YAAY,CAAa;IAEjC;;OAEG;IACG,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsDpD;;OAEG;IACH,OAAO,CAAC,cAAc;IAsEtB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA2BxB;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAyEpC;;OAEG;YACW,UAAU;IAqCxB;;OAEG;YACW,gBAAgB;IAyC9B;;OAEG;YACW,aAAa;IAsF3B;;OAEG;IACH,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,gBAAgB,EAAE;IAW1D;;OAEG;IACH,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAKpD;;OAEG;IACH,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,gBAAgB,EAAE;IAiB5E;;OAEG;IACH,YAAY,IAAI,gBAAgB,EAAE;IAKlC;;OAEG;IACH,QAAQ,IAAI,WAAW,GAAG,IAAI;IAI9B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAO9B;;OAEG;IACH,OAAO,CAAC,YAAY;CAKrB;AAGD,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
|
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Resource Loader Module
|
|
4
|
+
* Manages multi-source AI resource loading and indexing
|
|
5
|
+
*
|
|
6
|
+
* Implements AI Resources Multi-Source Architecture as defined in:
|
|
7
|
+
* @see Docs/AI-Resources-Multi-Source-Architecture.md
|
|
8
|
+
* @see AGENTS.md (AI Resources 开发约束)
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.resourceLoader = exports.ResourceLoader = void 0;
|
|
45
|
+
const fs = __importStar(require("fs/promises"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const logger_1 = require("../utils/logger");
|
|
48
|
+
/**
|
|
49
|
+
* Resource Loader
|
|
50
|
+
*
|
|
51
|
+
* Key responsibilities:
|
|
52
|
+
* 1. Load and validate ai-resources-config.json
|
|
53
|
+
* 2. Scan resources from multiple sources
|
|
54
|
+
* 3. Build resource index with priority
|
|
55
|
+
* 4. Resolve resource name conflicts
|
|
56
|
+
* 5. Provide unified resource query interface
|
|
57
|
+
*/
|
|
58
|
+
class ResourceLoader {
|
|
59
|
+
config = null;
|
|
60
|
+
resourceIndex = new Map();
|
|
61
|
+
conflicts = [];
|
|
62
|
+
stats = null;
|
|
63
|
+
loaded = false;
|
|
64
|
+
// Cache configuration
|
|
65
|
+
cacheEnabled = false;
|
|
66
|
+
cacheTTL = 300000; // 5 minutes default
|
|
67
|
+
lastLoadTime = 0;
|
|
68
|
+
/**
|
|
69
|
+
* Load AI Resources configuration file
|
|
70
|
+
*/
|
|
71
|
+
async loadConfig(configPath) {
|
|
72
|
+
const startTime = Date.now();
|
|
73
|
+
try {
|
|
74
|
+
// Default config path
|
|
75
|
+
const defaultPath = path.resolve(process.cwd(), 'AI-Resources/ai-resources-config.json');
|
|
76
|
+
const finalPath = configPath || defaultPath;
|
|
77
|
+
logger_1.logger.debug({ configPath: finalPath }, 'Loading AI Resources configuration...');
|
|
78
|
+
// Check if config file exists
|
|
79
|
+
try {
|
|
80
|
+
await fs.access(finalPath);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
logger_1.logger.warn({ configPath: finalPath }, 'AI Resources config file not found, using default configuration');
|
|
84
|
+
this.config = this.getDefaultConfig();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Read and parse config file
|
|
88
|
+
const configContent = await fs.readFile(finalPath, 'utf-8');
|
|
89
|
+
const parsedConfig = JSON.parse(configContent);
|
|
90
|
+
// Validate configuration
|
|
91
|
+
this.validateConfig(parsedConfig);
|
|
92
|
+
this.config = parsedConfig;
|
|
93
|
+
this.cacheEnabled = parsedConfig.cache?.enabled ?? true;
|
|
94
|
+
this.cacheTTL = (parsedConfig.cache?.ttl ?? 300) * 1000; // Convert to ms
|
|
95
|
+
const duration = Date.now() - startTime;
|
|
96
|
+
logger_1.logger.info({
|
|
97
|
+
configPath: finalPath,
|
|
98
|
+
defaultSource: parsedConfig.default_source.name,
|
|
99
|
+
extendedSourcesCount: parsedConfig.extended_sources.length,
|
|
100
|
+
duration,
|
|
101
|
+
}, 'AI Resources configuration loaded successfully');
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
logger_1.logger.error({
|
|
105
|
+
type: 'resource',
|
|
106
|
+
operation: 'load_config',
|
|
107
|
+
error: error instanceof Error ? error.message : String(error),
|
|
108
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
109
|
+
}, 'Failed to load AI Resources configuration');
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Validate configuration structure and constraints
|
|
115
|
+
*/
|
|
116
|
+
validateConfig(config) {
|
|
117
|
+
// Check version
|
|
118
|
+
if (config.version !== '1.0') {
|
|
119
|
+
throw new Error(`Unsupported config version: ${config.version}, expected 1.0`);
|
|
120
|
+
}
|
|
121
|
+
// Check default source
|
|
122
|
+
if (!config.default_source) {
|
|
123
|
+
throw new Error('Missing required field: default_source');
|
|
124
|
+
}
|
|
125
|
+
if (config.default_source.name !== 'csp') {
|
|
126
|
+
logger_1.logger.warn({ name: config.default_source.name }, 'Default source name is not "csp", this may cause compatibility issues');
|
|
127
|
+
}
|
|
128
|
+
if (config.default_source.priority !== 100) {
|
|
129
|
+
logger_1.logger.warn({ priority: config.default_source.priority }, 'Default source priority is not 100, this may affect conflict resolution');
|
|
130
|
+
}
|
|
131
|
+
if (!config.default_source.enabled) {
|
|
132
|
+
throw new Error('Default source must be enabled');
|
|
133
|
+
}
|
|
134
|
+
// Check resource types
|
|
135
|
+
const expectedTypes = ['commands', 'skills', 'mcp', 'rules'];
|
|
136
|
+
if (!config.resource_types ||
|
|
137
|
+
config.resource_types.length !== 4 ||
|
|
138
|
+
!expectedTypes.every((type) => config.resource_types.includes(type))) {
|
|
139
|
+
throw new Error(`Invalid resource_types, expected: ${expectedTypes.join(', ')}, got: ${config.resource_types?.join(', ') || 'none'}`);
|
|
140
|
+
}
|
|
141
|
+
// Check loading order
|
|
142
|
+
if (config.loading_order !== 'priority_desc') {
|
|
143
|
+
logger_1.logger.warn({ loading_order: config.loading_order }, 'Loading order is not "priority_desc", this may affect resource precedence');
|
|
144
|
+
}
|
|
145
|
+
// Check conflict resolution
|
|
146
|
+
if (config.conflict_resolution !== 'highest_priority_wins') {
|
|
147
|
+
logger_1.logger.warn({ conflict_resolution: config.conflict_resolution }, 'Conflict resolution is not "highest_priority_wins", this may affect behavior');
|
|
148
|
+
}
|
|
149
|
+
// Check extended sources priority
|
|
150
|
+
const defaultPriority = config.default_source.priority;
|
|
151
|
+
for (const source of config.extended_sources || []) {
|
|
152
|
+
if (source.priority >= defaultPriority) {
|
|
153
|
+
throw new Error(`Extended source "${source.name}" has priority ${source.priority} which is >= default source priority ${defaultPriority}. Default source must have highest priority.`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
logger_1.logger.debug('AI Resources configuration validation passed');
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get default configuration (fallback)
|
|
160
|
+
*/
|
|
161
|
+
getDefaultConfig() {
|
|
162
|
+
return {
|
|
163
|
+
version: '1.0',
|
|
164
|
+
description: 'Default AI Resources configuration',
|
|
165
|
+
default_source: {
|
|
166
|
+
name: 'csp',
|
|
167
|
+
path: 'csp/ai-resources',
|
|
168
|
+
enabled: true,
|
|
169
|
+
priority: 100,
|
|
170
|
+
resources: {
|
|
171
|
+
commands: 'commands',
|
|
172
|
+
skills: 'skills',
|
|
173
|
+
mcp: 'mcp',
|
|
174
|
+
rules: 'rules',
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
extended_sources: [],
|
|
178
|
+
resource_types: ['commands', 'skills', 'mcp', 'rules'],
|
|
179
|
+
loading_order: 'priority_desc',
|
|
180
|
+
conflict_resolution: 'highest_priority_wins',
|
|
181
|
+
cache: {
|
|
182
|
+
enabled: true,
|
|
183
|
+
ttl: 300,
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Scan and index resources from all sources
|
|
189
|
+
*/
|
|
190
|
+
async scanResources() {
|
|
191
|
+
if (!this.config) {
|
|
192
|
+
throw new Error('Configuration not loaded. Call loadConfig() first.');
|
|
193
|
+
}
|
|
194
|
+
// Check cache validity
|
|
195
|
+
if (this.cacheEnabled && this.loaded) {
|
|
196
|
+
const cacheAge = Date.now() - this.lastLoadTime;
|
|
197
|
+
if (cacheAge < this.cacheTTL) {
|
|
198
|
+
logger_1.logger.debug({ cacheAge }, 'Using cached resource index');
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
logger_1.logger.debug('Resource cache expired, reloading...');
|
|
202
|
+
}
|
|
203
|
+
const startTime = Date.now();
|
|
204
|
+
this.resourceIndex.clear();
|
|
205
|
+
this.conflicts = [];
|
|
206
|
+
const stats = {
|
|
207
|
+
sourcesLoaded: 0,
|
|
208
|
+
resourcesIndexed: 0,
|
|
209
|
+
byType: {
|
|
210
|
+
commands: 0,
|
|
211
|
+
skills: 0,
|
|
212
|
+
mcp: 0,
|
|
213
|
+
rules: 0,
|
|
214
|
+
},
|
|
215
|
+
conflictsDetected: 0,
|
|
216
|
+
loadDuration: 0,
|
|
217
|
+
};
|
|
218
|
+
try {
|
|
219
|
+
// Collect all sources sorted by priority (descending)
|
|
220
|
+
const sources = [this.config.default_source, ...this.config.extended_sources.filter((s) => s.enabled)];
|
|
221
|
+
sources.sort((a, b) => b.priority - a.priority); // High priority first
|
|
222
|
+
logger_1.logger.info({ sourceCount: sources.length }, 'Scanning resources from all sources...');
|
|
223
|
+
// Scan each source
|
|
224
|
+
for (const source of sources) {
|
|
225
|
+
await this.scanSource(source, stats);
|
|
226
|
+
stats.sourcesLoaded++;
|
|
227
|
+
}
|
|
228
|
+
stats.conflictsDetected = this.conflicts.length;
|
|
229
|
+
stats.loadDuration = Date.now() - startTime;
|
|
230
|
+
this.stats = stats;
|
|
231
|
+
this.loaded = true;
|
|
232
|
+
this.lastLoadTime = Date.now();
|
|
233
|
+
logger_1.logger.info({
|
|
234
|
+
sourcesLoaded: stats.sourcesLoaded,
|
|
235
|
+
resourcesIndexed: stats.resourcesIndexed,
|
|
236
|
+
conflictsDetected: stats.conflictsDetected,
|
|
237
|
+
duration: stats.loadDuration,
|
|
238
|
+
}, 'Resource scanning completed');
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
logger_1.logger.error({
|
|
242
|
+
type: 'resource',
|
|
243
|
+
operation: 'scan_resources',
|
|
244
|
+
error: error instanceof Error ? error.message : String(error),
|
|
245
|
+
}, 'Failed to scan resources');
|
|
246
|
+
throw error;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Scan resources from a single source
|
|
251
|
+
*/
|
|
252
|
+
async scanSource(source, stats) {
|
|
253
|
+
logger_1.logger.debug({ source: source.name, path: source.path }, 'Scanning source...');
|
|
254
|
+
const baseDir = path.resolve(process.cwd(), 'AI-Resources', source.path);
|
|
255
|
+
// Check if source directory exists
|
|
256
|
+
try {
|
|
257
|
+
await fs.access(baseDir);
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
logger_1.logger.warn({ source: source.name, path: baseDir }, 'Source directory not found, skipping');
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
// Scan each resource type
|
|
264
|
+
for (const type of this.config.resource_types) {
|
|
265
|
+
const subDir = source.resources[type];
|
|
266
|
+
if (!subDir) {
|
|
267
|
+
logger_1.logger.debug({ source: source.name, type }, 'Resource type not defined for this source, skipping');
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const resourceDir = path.join(baseDir, subDir);
|
|
271
|
+
try {
|
|
272
|
+
await fs.access(resourceDir);
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
logger_1.logger.debug({ source: source.name, type, path: resourceDir }, 'Resource directory not found, skipping');
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
await this.scanResourceType(source, type, resourceDir, stats);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Scan resources of a specific type from a directory
|
|
283
|
+
*/
|
|
284
|
+
async scanResourceType(source, type, dir, stats) {
|
|
285
|
+
try {
|
|
286
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
287
|
+
for (const entry of entries) {
|
|
288
|
+
const fullPath = path.join(dir, entry.name);
|
|
289
|
+
if (entry.isFile() && (entry.name.endsWith('.md') || entry.name.endsWith('.mdc'))) {
|
|
290
|
+
// Handle file resources (commands, rules)
|
|
291
|
+
const resourceName = path.basename(entry.name, path.extname(entry.name));
|
|
292
|
+
await this.indexResource(source, type, resourceName, fullPath, stats);
|
|
293
|
+
}
|
|
294
|
+
else if (entry.isDirectory()) {
|
|
295
|
+
// Handle directory resources (skills, mcp)
|
|
296
|
+
const skillFile = path.join(fullPath, 'SKILL.md');
|
|
297
|
+
try {
|
|
298
|
+
await fs.access(skillFile);
|
|
299
|
+
await this.indexResource(source, type, entry.name, skillFile, stats);
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
// Not a skill directory, skip
|
|
303
|
+
logger_1.logger.debug({ dir: fullPath }, 'Directory does not contain SKILL.md, skipping');
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
catch (error) {
|
|
309
|
+
logger_1.logger.warn({
|
|
310
|
+
source: source.name,
|
|
311
|
+
type,
|
|
312
|
+
dir,
|
|
313
|
+
error: error instanceof Error ? error.message : String(error),
|
|
314
|
+
}, 'Failed to scan resource directory');
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Index a single resource with conflict detection
|
|
319
|
+
*/
|
|
320
|
+
async indexResource(source, type, name, filePath, stats) {
|
|
321
|
+
const resourceKey = `${type}:${name}`;
|
|
322
|
+
const existing = this.resourceIndex.get(resourceKey);
|
|
323
|
+
if (existing) {
|
|
324
|
+
// Conflict detected
|
|
325
|
+
logger_1.logger.warn({
|
|
326
|
+
resourceName: name,
|
|
327
|
+
type,
|
|
328
|
+
existingSource: existing.source,
|
|
329
|
+
existingPriority: existing.priority,
|
|
330
|
+
newSource: source.name,
|
|
331
|
+
newPriority: source.priority,
|
|
332
|
+
}, 'Resource name conflict detected');
|
|
333
|
+
// Record conflict
|
|
334
|
+
const conflict = {
|
|
335
|
+
name,
|
|
336
|
+
type,
|
|
337
|
+
conflicts: [
|
|
338
|
+
{
|
|
339
|
+
source: existing.source,
|
|
340
|
+
priority: existing.priority,
|
|
341
|
+
path: existing.path,
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
source: source.name,
|
|
345
|
+
priority: source.priority,
|
|
346
|
+
path: filePath,
|
|
347
|
+
},
|
|
348
|
+
],
|
|
349
|
+
selected: source.priority > existing.priority
|
|
350
|
+
? { source: source.name, priority: source.priority, path: filePath }
|
|
351
|
+
: { source: existing.source, priority: existing.priority, path: existing.path },
|
|
352
|
+
};
|
|
353
|
+
this.conflicts.push(conflict);
|
|
354
|
+
// Keep higher priority resource (already sorted by priority)
|
|
355
|
+
if (source.priority <= existing.priority) {
|
|
356
|
+
logger_1.logger.debug({
|
|
357
|
+
resourceName: name,
|
|
358
|
+
selectedSource: existing.source,
|
|
359
|
+
}, 'Keeping existing resource (higher priority)');
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
logger_1.logger.debug({
|
|
363
|
+
resourceName: name,
|
|
364
|
+
selectedSource: source.name,
|
|
365
|
+
}, 'Replacing with new resource (higher priority)');
|
|
366
|
+
}
|
|
367
|
+
// Index resource
|
|
368
|
+
const metadata = {
|
|
369
|
+
id: resourceKey,
|
|
370
|
+
name,
|
|
371
|
+
type,
|
|
372
|
+
source: source.name,
|
|
373
|
+
priority: source.priority,
|
|
374
|
+
path: filePath,
|
|
375
|
+
};
|
|
376
|
+
this.resourceIndex.set(resourceKey, metadata);
|
|
377
|
+
stats.resourcesIndexed++;
|
|
378
|
+
stats.byType[type]++;
|
|
379
|
+
logger_1.logger.debug({ resourceKey, source: source.name }, 'Resource indexed');
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Get all resources by type
|
|
383
|
+
*/
|
|
384
|
+
getResourcesByType(type) {
|
|
385
|
+
this.ensureLoaded();
|
|
386
|
+
const results = [];
|
|
387
|
+
for (const [, metadata] of this.resourceIndex) {
|
|
388
|
+
if (metadata.type === type) {
|
|
389
|
+
results.push(metadata);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return results;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Get resource by ID (type:name)
|
|
396
|
+
*/
|
|
397
|
+
getResourceById(id) {
|
|
398
|
+
this.ensureLoaded();
|
|
399
|
+
return this.resourceIndex.get(id) || null;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Search resources by name
|
|
403
|
+
*/
|
|
404
|
+
searchResourcesByName(name, type) {
|
|
405
|
+
this.ensureLoaded();
|
|
406
|
+
const results = [];
|
|
407
|
+
const lowerName = name.toLowerCase();
|
|
408
|
+
for (const metadata of this.resourceIndex.values()) {
|
|
409
|
+
if (type && metadata.type !== type) {
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
if (metadata.name.toLowerCase().includes(lowerName)) {
|
|
413
|
+
results.push(metadata);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return results;
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Get all detected conflicts
|
|
420
|
+
*/
|
|
421
|
+
getConflicts() {
|
|
422
|
+
this.ensureLoaded();
|
|
423
|
+
return [...this.conflicts];
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Get loader statistics
|
|
427
|
+
*/
|
|
428
|
+
getStats() {
|
|
429
|
+
return this.stats;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Refresh resource index (clear cache and rescan)
|
|
433
|
+
*/
|
|
434
|
+
async refresh() {
|
|
435
|
+
logger_1.logger.info('Refreshing resource index...');
|
|
436
|
+
this.loaded = false;
|
|
437
|
+
this.lastLoadTime = 0;
|
|
438
|
+
await this.scanResources();
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Ensure resources are loaded
|
|
442
|
+
*/
|
|
443
|
+
ensureLoaded() {
|
|
444
|
+
if (!this.loaded) {
|
|
445
|
+
throw new Error('Resources not loaded. Call scanResources() first.');
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
exports.ResourceLoader = ResourceLoader;
|
|
450
|
+
// Singleton instance
|
|
451
|
+
exports.resourceLoader = new ResourceLoader();
|
|
452
|
+
//# sourceMappingURL=loader.js.map
|