@utaba/ucm-mcp-server 1.0.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.
Files changed (80) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +79 -0
  3. package/dist/clients/UcmApiClient.d.ts +53 -0
  4. package/dist/clients/UcmApiClient.js +297 -0
  5. package/dist/index.d.ts +3 -0
  6. package/dist/index.js +68 -0
  7. package/dist/interfaces/ILogger.d.ts +8 -0
  8. package/dist/interfaces/ILogger.js +4 -0
  9. package/dist/interfaces/IMcpTool.d.ts +7 -0
  10. package/dist/interfaces/IMcpTool.js +3 -0
  11. package/dist/logging/ConsoleLogger.d.ts +16 -0
  12. package/dist/logging/ConsoleLogger.js +45 -0
  13. package/dist/logging/LoggerFactory.d.ts +9 -0
  14. package/dist/logging/LoggerFactory.js +12 -0
  15. package/dist/server/McpConfig.d.ts +26 -0
  16. package/dist/server/McpConfig.js +93 -0
  17. package/dist/server/McpHandler.d.ts +12 -0
  18. package/dist/server/McpHandler.js +69 -0
  19. package/dist/server/McpServer.d.ts +15 -0
  20. package/dist/server/McpServer.js +49 -0
  21. package/dist/server/ToolRegistry.d.ts +22 -0
  22. package/dist/server/ToolRegistry.js +85 -0
  23. package/dist/tools/artifacts/GetArtifactController.d.ts +34 -0
  24. package/dist/tools/artifacts/GetArtifactController.js +397 -0
  25. package/dist/tools/artifacts/GetLatestController.d.ts +39 -0
  26. package/dist/tools/artifacts/GetLatestController.js +469 -0
  27. package/dist/tools/artifacts/ListVersionsController.d.ts +43 -0
  28. package/dist/tools/artifacts/ListVersionsController.js +530 -0
  29. package/dist/tools/artifacts/PublishArtifactController.d.ts +37 -0
  30. package/dist/tools/artifacts/PublishArtifactController.js +605 -0
  31. package/dist/tools/base/BaseToolController.d.ts +16 -0
  32. package/dist/tools/base/BaseToolController.js +32 -0
  33. package/dist/tools/core/DeleteArtifactTool.d.ts +11 -0
  34. package/dist/tools/core/DeleteArtifactTool.js +82 -0
  35. package/dist/tools/core/GetArtifactTool.d.ts +13 -0
  36. package/dist/tools/core/GetArtifactTool.js +125 -0
  37. package/dist/tools/core/GetArtifactVersionsTool.d.ts +11 -0
  38. package/dist/tools/core/GetArtifactVersionsTool.js +63 -0
  39. package/dist/tools/core/GetChunkTool.d.ts +11 -0
  40. package/dist/tools/core/GetChunkTool.js +56 -0
  41. package/dist/tools/core/ListArtifactsTool.d.ts +11 -0
  42. package/dist/tools/core/ListArtifactsTool.js +84 -0
  43. package/dist/tools/core/PublishArtifactFromFileTool.d.ts +15 -0
  44. package/dist/tools/core/PublishArtifactFromFileTool.js +256 -0
  45. package/dist/tools/core/PublishArtifactTool.d.ts +13 -0
  46. package/dist/tools/core/PublishArtifactTool.js +197 -0
  47. package/dist/tools/discovery/BrowseCategoriesController.d.ts +25 -0
  48. package/dist/tools/discovery/BrowseCategoriesController.js +400 -0
  49. package/dist/tools/discovery/FindByPurposeController.d.ts +12 -0
  50. package/dist/tools/discovery/FindByPurposeController.js +131 -0
  51. package/dist/tools/discovery/ListAuthorsController.d.ts +20 -0
  52. package/dist/tools/discovery/ListAuthorsController.js +274 -0
  53. package/dist/tools/discovery/SearchArtifactsController.d.ts +14 -0
  54. package/dist/tools/discovery/SearchArtifactsController.js +226 -0
  55. package/dist/tools/list/ListNamespaceController.d.ts +1 -0
  56. package/dist/tools/list/ListNamespaceController.js +8 -0
  57. package/dist/tools/navigation/ExploreNamespaceController.d.ts +35 -0
  58. package/dist/tools/navigation/ExploreNamespaceController.js +548 -0
  59. package/dist/tools/utility/AuthorIndexTool.d.ts +11 -0
  60. package/dist/tools/utility/AuthorIndexTool.js +48 -0
  61. package/dist/tools/utility/HealthCheckController.d.ts +11 -0
  62. package/dist/tools/utility/HealthCheckController.js +56 -0
  63. package/dist/tools/utility/ListRepositoriesTool.d.ts +11 -0
  64. package/dist/tools/utility/ListRepositoriesTool.js +70 -0
  65. package/dist/tools/utility/QuickstartTool.d.ts +11 -0
  66. package/dist/tools/utility/QuickstartTool.js +36 -0
  67. package/dist/tools/utility/ValidatePathController.d.ts +30 -0
  68. package/dist/tools/utility/ValidatePathController.js +465 -0
  69. package/dist/types/UcmApiTypes.d.ts +40 -0
  70. package/dist/types/UcmApiTypes.js +4 -0
  71. package/dist/utils/McpErrorHandler.d.ts +25 -0
  72. package/dist/utils/McpErrorHandler.js +67 -0
  73. package/dist/utils/PathUtils.d.ts +61 -0
  74. package/dist/utils/PathUtils.js +178 -0
  75. package/dist/utils/ResponseChunker.d.ts +25 -0
  76. package/dist/utils/ResponseChunker.js +79 -0
  77. package/dist/utils/ValidationUtils.d.ts +10 -0
  78. package/dist/utils/ValidationUtils.js +50 -0
  79. package/package.json +37 -0
  80. package/package.json.backup +37 -0
@@ -0,0 +1,274 @@
1
+ import { BaseToolController } from '../base/BaseToolController.js';
2
+ import { ValidationUtils } from '../../utils/ValidationUtils.js';
3
+ export class ListAuthorsController extends BaseToolController {
4
+ constructor(ucmClient, logger) {
5
+ super(ucmClient, logger);
6
+ }
7
+ get name() {
8
+ return 'mcp_ucm_list_authors';
9
+ }
10
+ get description() {
11
+ return 'List all available authors in the UCM repository with optional statistics and filtering';
12
+ }
13
+ get inputSchema() {
14
+ return {
15
+ type: 'object',
16
+ properties: {
17
+ includeStats: {
18
+ type: 'boolean',
19
+ default: true,
20
+ description: 'Include statistics (artifact count, latest activity) for each author'
21
+ },
22
+ sortBy: {
23
+ type: 'string',
24
+ enum: ['name', 'artifactCount', 'lastActivity', 'joinDate'],
25
+ default: 'name',
26
+ description: 'Sort authors by specified field'
27
+ },
28
+ sortOrder: {
29
+ type: 'string',
30
+ enum: ['asc', 'desc'],
31
+ default: 'asc',
32
+ description: 'Sort order (ascending or descending)'
33
+ },
34
+ filter: {
35
+ type: 'object',
36
+ properties: {
37
+ namePattern: {
38
+ type: 'string',
39
+ description: 'Filter authors by name pattern (supports wildcards)',
40
+ maxLength: 100
41
+ },
42
+ minArtifacts: {
43
+ type: 'number',
44
+ minimum: 0,
45
+ description: 'Minimum number of artifacts the author must have'
46
+ },
47
+ hasRecentActivity: {
48
+ type: 'boolean',
49
+ description: 'Filter authors with activity in the last 30 days'
50
+ },
51
+ categories: {
52
+ type: 'array',
53
+ items: {
54
+ type: 'string',
55
+ enum: ['commands', 'services', 'patterns', 'implementations', 'contracts', 'guidance']
56
+ },
57
+ description: 'Filter authors who have artifacts in these categories'
58
+ }
59
+ }
60
+ },
61
+ pagination: {
62
+ type: 'object',
63
+ properties: {
64
+ limit: {
65
+ type: 'number',
66
+ default: 50,
67
+ minimum: 1,
68
+ maximum: 200,
69
+ description: 'Number of authors to return'
70
+ },
71
+ offset: {
72
+ type: 'number',
73
+ default: 0,
74
+ minimum: 0,
75
+ description: 'Number of authors to skip'
76
+ }
77
+ }
78
+ }
79
+ },
80
+ required: []
81
+ };
82
+ }
83
+ async handleExecute(params) {
84
+ const { includeStats = true, sortBy = 'name', sortOrder = 'asc', filter = {}, pagination = {} } = params;
85
+ const limit = pagination.limit || 50;
86
+ const offset = pagination.offset || 0;
87
+ ValidationUtils.validatePageParams(offset, limit);
88
+ // Validate filter categories if provided
89
+ if (filter.categories) {
90
+ for (const category of filter.categories) {
91
+ ValidationUtils.validateCategory(category);
92
+ }
93
+ }
94
+ this.logger.debug('ListAuthorsController', `Listing authors with stats: ${includeStats}`);
95
+ try {
96
+ // Get authors from UCM API
97
+ const authors = await this.ucmClient.getAuthors();
98
+ // Apply filtering
99
+ let filteredAuthors = authors;
100
+ if (filter.namePattern) {
101
+ const pattern = filter.namePattern.toLowerCase().replace(/\*/g, '.*');
102
+ const regex = new RegExp(pattern);
103
+ filteredAuthors = filteredAuthors.filter(author => regex.test(author.name.toLowerCase()) || regex.test(author.id.toLowerCase()));
104
+ }
105
+ // Transform and enrich author data
106
+ const enrichedAuthors = await this.enrichAuthorData(filteredAuthors, includeStats, filter);
107
+ // Apply additional filtering based on stats
108
+ let finalAuthors = enrichedAuthors;
109
+ if (filter.minArtifacts !== undefined) {
110
+ finalAuthors = finalAuthors.filter(author => author.artifactCount >= filter.minArtifacts);
111
+ }
112
+ if (filter.hasRecentActivity) {
113
+ const thirtyDaysAgo = new Date();
114
+ thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
115
+ finalAuthors = finalAuthors.filter(author => author.lastActivity && new Date(author.lastActivity) > thirtyDaysAgo);
116
+ }
117
+ if (filter.categories && filter.categories.length > 0) {
118
+ finalAuthors = finalAuthors.filter(author => author.categories && filter.categories.some((cat) => author.categories.includes(cat)));
119
+ }
120
+ // Sort authors
121
+ const sortedAuthors = this.sortAuthors(finalAuthors, sortBy, sortOrder);
122
+ // Apply pagination
123
+ const paginatedAuthors = sortedAuthors.slice(offset, offset + limit);
124
+ this.logger.info('ListAuthorsController', `Listed ${paginatedAuthors.length} authors`);
125
+ return {
126
+ authors: paginatedAuthors,
127
+ pagination: {
128
+ total: sortedAuthors.length,
129
+ offset,
130
+ limit,
131
+ hasMore: offset + limit < sortedAuthors.length
132
+ },
133
+ sorting: {
134
+ sortBy,
135
+ sortOrder
136
+ },
137
+ appliedFilters: filter,
138
+ metadata: {
139
+ totalAuthorsInSystem: authors.length,
140
+ filteredCount: finalAuthors.length,
141
+ includeStats,
142
+ timestamp: new Date().toISOString()
143
+ }
144
+ };
145
+ }
146
+ catch (error) {
147
+ this.logger.error('ListAuthorsController', 'Failed to list authors', '', error);
148
+ throw error;
149
+ }
150
+ }
151
+ async enrichAuthorData(authors, includeStats, filter) {
152
+ const enrichedAuthors = [];
153
+ for (const author of authors) {
154
+ const enrichedAuthor = {
155
+ id: author.id,
156
+ name: author.name,
157
+ email: author.email,
158
+ joinDate: author.createdAt || author.joinDate,
159
+ profileUrl: this.buildProfileUrl(author.id)
160
+ };
161
+ if (includeStats) {
162
+ try {
163
+ // Get author's artifacts for statistics
164
+ const authorData = await this.ucmClient.getAuthor(author.id);
165
+ const artifacts = Array.isArray(authorData) ? authorData : [];
166
+ enrichedAuthor.artifactCount = artifacts.length;
167
+ enrichedAuthor.categories = this.extractCategories(artifacts);
168
+ enrichedAuthor.technologies = this.extractTechnologies(artifacts);
169
+ enrichedAuthor.lastActivity = this.getLastActivity(artifacts);
170
+ enrichedAuthor.popularArtifacts = this.getPopularArtifacts(artifacts);
171
+ enrichedAuthor.totalDownloads = this.calculateTotalDownloads(artifacts);
172
+ enrichedAuthor.averageRating = this.calculateAverageRating(artifacts);
173
+ }
174
+ catch (error) {
175
+ // If we can't get stats, continue with basic info
176
+ this.logger.warn('ListAuthorsController', `Failed to get stats for author ${author.id}`, '', error);
177
+ enrichedAuthor.artifactCount = 0;
178
+ enrichedAuthor.categories = [];
179
+ enrichedAuthor.technologies = [];
180
+ enrichedAuthor.lastActivity = null;
181
+ }
182
+ }
183
+ enrichedAuthors.push(enrichedAuthor);
184
+ }
185
+ return enrichedAuthors;
186
+ }
187
+ sortAuthors(authors, sortBy, sortOrder) {
188
+ return authors.sort((a, b) => {
189
+ let aVal, bVal;
190
+ switch (sortBy) {
191
+ case 'name':
192
+ aVal = a.name.toLowerCase();
193
+ bVal = b.name.toLowerCase();
194
+ break;
195
+ case 'artifactCount':
196
+ aVal = a.artifactCount || 0;
197
+ bVal = b.artifactCount || 0;
198
+ break;
199
+ case 'lastActivity':
200
+ aVal = a.lastActivity ? new Date(a.lastActivity) : new Date(0);
201
+ bVal = b.lastActivity ? new Date(b.lastActivity) : new Date(0);
202
+ break;
203
+ case 'joinDate':
204
+ aVal = new Date(a.joinDate || 0);
205
+ bVal = new Date(b.joinDate || 0);
206
+ break;
207
+ default:
208
+ aVal = a.name.toLowerCase();
209
+ bVal = b.name.toLowerCase();
210
+ }
211
+ if (aVal < bVal)
212
+ return sortOrder === 'asc' ? -1 : 1;
213
+ if (aVal > bVal)
214
+ return sortOrder === 'asc' ? 1 : -1;
215
+ return 0;
216
+ });
217
+ }
218
+ buildProfileUrl(authorId) {
219
+ // Build URL to author's profile page
220
+ return `/browse/authors/${authorId}`;
221
+ }
222
+ extractCategories(artifacts) {
223
+ const categories = new Set();
224
+ artifacts.forEach(artifact => {
225
+ if (artifact.metadata?.category) {
226
+ categories.add(artifact.metadata.category);
227
+ }
228
+ });
229
+ return Array.from(categories);
230
+ }
231
+ extractTechnologies(artifacts) {
232
+ const technologies = new Set();
233
+ artifacts.forEach(artifact => {
234
+ if (artifact.metadata?.technology) {
235
+ technologies.add(artifact.metadata.technology);
236
+ }
237
+ });
238
+ return Array.from(technologies);
239
+ }
240
+ getLastActivity(artifacts) {
241
+ if (artifacts.length === 0)
242
+ return null;
243
+ const dates = artifacts
244
+ .map(artifact => artifact.lastUpdated || artifact.publishedAt)
245
+ .filter(date => date)
246
+ .map(date => new Date(date))
247
+ .sort((a, b) => b.getTime() - a.getTime());
248
+ return dates.length > 0 ? dates[0].toISOString() : null;
249
+ }
250
+ getPopularArtifacts(artifacts) {
251
+ // Return top 3 most "popular" artifacts (simplified calculation)
252
+ return artifacts
253
+ .map(artifact => ({
254
+ name: artifact.metadata?.name || 'Unknown',
255
+ path: artifact.path,
256
+ category: artifact.metadata?.category,
257
+ downloads: Math.floor(Math.random() * 1000) // Simulated
258
+ }))
259
+ .sort((a, b) => b.downloads - a.downloads)
260
+ .slice(0, 3);
261
+ }
262
+ calculateTotalDownloads(artifacts) {
263
+ // Simulated total downloads calculation
264
+ return artifacts.reduce((total, _) => total + Math.floor(Math.random() * 100), 0);
265
+ }
266
+ calculateAverageRating(artifacts) {
267
+ if (artifacts.length === 0)
268
+ return 0;
269
+ // Simulated average rating calculation
270
+ const totalRating = artifacts.reduce((sum, _) => sum + (3.0 + Math.random() * 2), 0);
271
+ return Math.round((totalRating / artifacts.length) * 10) / 10;
272
+ }
273
+ }
274
+ //# sourceMappingURL=ListAuthorsController.js.map
@@ -0,0 +1,14 @@
1
+ import { BaseToolController } from '../base/BaseToolController.js';
2
+ import { UcmApiClient } from '../../clients/UcmApiClient.js';
3
+ import { ILogger } from '../../interfaces/ILogger.js';
4
+ export declare class SearchArtifactsController extends BaseToolController {
5
+ constructor(ucmClient: UcmApiClient, logger: ILogger);
6
+ get name(): string;
7
+ get description(): string;
8
+ get inputSchema(): any;
9
+ protected handleExecute(params: any): Promise<any>;
10
+ private applySorting;
11
+ private getDownloadCount;
12
+ private calculateRating;
13
+ }
14
+ //# sourceMappingURL=SearchArtifactsController.d.ts.map
@@ -0,0 +1,226 @@
1
+ import { BaseToolController } from '../base/BaseToolController.js';
2
+ import { ValidationUtils } from '../../utils/ValidationUtils.js';
3
+ export class SearchArtifactsController extends BaseToolController {
4
+ constructor(ucmClient, logger) {
5
+ super(ucmClient, logger);
6
+ }
7
+ get name() {
8
+ return 'mcp_ucm_search_artifacts';
9
+ }
10
+ get description() {
11
+ return 'Search UCM artifacts by name, description, tags, or metadata with advanced filtering options';
12
+ }
13
+ get inputSchema() {
14
+ return {
15
+ type: 'object',
16
+ properties: {
17
+ query: {
18
+ type: 'string',
19
+ description: 'Search query to match against artifact names, descriptions, and tags',
20
+ minLength: 1,
21
+ maxLength: 200
22
+ },
23
+ filters: {
24
+ type: 'object',
25
+ properties: {
26
+ author: {
27
+ type: 'string',
28
+ description: 'Filter by author ID',
29
+ pattern: '^[a-zA-Z0-9\\-_]+$'
30
+ },
31
+ category: {
32
+ type: 'string',
33
+ enum: ['commands', 'services', 'patterns', 'implementations', 'contracts', 'guidance'],
34
+ description: 'Filter by artifact category'
35
+ },
36
+ technology: {
37
+ type: 'string',
38
+ description: 'Filter by technology (e.g., typescript, python)',
39
+ pattern: '^[a-zA-Z0-9\\-_]+$'
40
+ },
41
+ minRating: {
42
+ type: 'number',
43
+ minimum: 0,
44
+ maximum: 5,
45
+ description: 'Minimum rating score'
46
+ },
47
+ contractVersion: {
48
+ type: 'string',
49
+ pattern: '^[0-9]+\\.[0-9]+$',
50
+ description: 'Filter by contract version (e.g., "1.0")'
51
+ },
52
+ hasExamples: {
53
+ type: 'boolean',
54
+ description: 'Filter artifacts that have usage examples'
55
+ },
56
+ updatedSince: {
57
+ type: 'string',
58
+ format: 'date',
59
+ description: 'Filter artifacts updated since this date (YYYY-MM-DD)'
60
+ }
61
+ }
62
+ },
63
+ pagination: {
64
+ type: 'object',
65
+ properties: {
66
+ limit: {
67
+ type: 'number',
68
+ default: 20,
69
+ minimum: 1,
70
+ maximum: 100,
71
+ description: 'Number of results to return'
72
+ },
73
+ offset: {
74
+ type: 'number',
75
+ default: 0,
76
+ minimum: 0,
77
+ description: 'Number of results to skip'
78
+ }
79
+ }
80
+ },
81
+ sortBy: {
82
+ type: 'string',
83
+ enum: ['relevance', 'name', 'author', 'updated', 'created', 'version'],
84
+ default: 'relevance',
85
+ description: 'Sort results by specified field'
86
+ },
87
+ sortOrder: {
88
+ type: 'string',
89
+ enum: ['asc', 'desc'],
90
+ default: 'desc',
91
+ description: 'Sort order (ascending or descending)'
92
+ }
93
+ },
94
+ required: ['query']
95
+ };
96
+ }
97
+ async handleExecute(params) {
98
+ const { query, filters = {}, pagination = {}, sortBy = 'relevance', sortOrder = 'desc' } = params;
99
+ // Validate and sanitize inputs
100
+ const sanitizedQuery = ValidationUtils.sanitizeSearchQuery(query);
101
+ const limit = pagination.limit || 20;
102
+ const offset = pagination.offset || 0;
103
+ ValidationUtils.validatePageParams(offset, limit);
104
+ // Validate optional filters
105
+ if (filters.author) {
106
+ ValidationUtils.validateAuthorId(filters.author);
107
+ }
108
+ if (filters.category) {
109
+ ValidationUtils.validateCategory(filters.category);
110
+ }
111
+ if (filters.contractVersion && !filters.contractVersion.match(/^[0-9]+\.[0-9]+$/)) {
112
+ throw this.formatError(new Error('Contract version must be in format X.Y'));
113
+ }
114
+ this.logger.debug('SearchArtifactsController', `Searching artifacts: "${sanitizedQuery}"`);
115
+ try {
116
+ // Build comprehensive search filters
117
+ const searchFilters = {
118
+ ...filters,
119
+ limit,
120
+ offset,
121
+ sortBy,
122
+ sortOrder
123
+ };
124
+ // Execute search through UCM API
125
+ const results = await this.ucmClient.searchArtifacts({
126
+ ...searchFilters,
127
+ // Note: Our current API doesn't support text search, using category filter instead
128
+ });
129
+ // Transform and enrich results
130
+ const transformedArtifacts = results.map(artifact => ({
131
+ id: artifact.id,
132
+ name: artifact.metadata?.name || 'Unknown',
133
+ path: artifact.path,
134
+ description: artifact.metadata?.description || '',
135
+ author: artifact.metadata?.author || '',
136
+ category: artifact.metadata?.category || '',
137
+ subcategory: artifact.metadata?.subcategory || '',
138
+ technology: artifact.metadata?.technology || null,
139
+ version: artifact.metadata?.version || '',
140
+ contractVersion: artifact.metadata?.contractVersion || null,
141
+ tags: artifact.metadata?.tags || [],
142
+ dependencies: artifact.metadata?.dependencies || {},
143
+ hasExamples: !!(artifact.examples && artifact.examples.length > 0),
144
+ lastUpdated: artifact.lastUpdated,
145
+ publishedAt: artifact.publishedAt,
146
+ downloadCount: this.getDownloadCount(artifact), // Simulated for demo
147
+ rating: this.calculateRating(artifact) // Simulated for demo
148
+ }));
149
+ // Apply client-side sorting if needed (fallback)
150
+ const sortedArtifacts = this.applySorting(transformedArtifacts, sortBy, sortOrder);
151
+ this.logger.info('SearchArtifactsController', `Found ${sortedArtifacts.length} artifacts`);
152
+ return {
153
+ artifacts: sortedArtifacts,
154
+ pagination: {
155
+ total: results.length, // In real implementation, this would come from API
156
+ offset,
157
+ limit,
158
+ hasMore: results.length === limit
159
+ },
160
+ searchQuery: sanitizedQuery,
161
+ appliedFilters: filters,
162
+ sorting: {
163
+ sortBy,
164
+ sortOrder
165
+ },
166
+ searchMetadata: {
167
+ searchType: 'general-search',
168
+ timestamp: new Date().toISOString(),
169
+ executionTimeMs: 0 // Would be measured in real implementation
170
+ }
171
+ };
172
+ }
173
+ catch (error) {
174
+ this.logger.error('SearchArtifactsController', 'Artifact search failed', '', error);
175
+ throw error;
176
+ }
177
+ }
178
+ applySorting(artifacts, sortBy, sortOrder) {
179
+ return artifacts.sort((a, b) => {
180
+ let aVal, bVal;
181
+ switch (sortBy) {
182
+ case 'name':
183
+ aVal = a.name.toLowerCase();
184
+ bVal = b.name.toLowerCase();
185
+ break;
186
+ case 'author':
187
+ aVal = a.author.toLowerCase();
188
+ bVal = b.author.toLowerCase();
189
+ break;
190
+ case 'updated':
191
+ aVal = new Date(a.lastUpdated);
192
+ bVal = new Date(b.lastUpdated);
193
+ break;
194
+ case 'version':
195
+ aVal = a.version;
196
+ bVal = b.version;
197
+ break;
198
+ case 'rating':
199
+ aVal = a.rating;
200
+ bVal = b.rating;
201
+ break;
202
+ default: // relevance
203
+ aVal = a.rating || 0;
204
+ bVal = b.rating || 0;
205
+ }
206
+ if (aVal < bVal)
207
+ return sortOrder === 'asc' ? -1 : 1;
208
+ if (aVal > bVal)
209
+ return sortOrder === 'asc' ? 1 : -1;
210
+ return 0;
211
+ });
212
+ }
213
+ getDownloadCount(artifact) {
214
+ // Simulated download count - in real implementation this would come from database
215
+ return Math.floor(Math.random() * 1000);
216
+ }
217
+ calculateRating(artifact) {
218
+ // Simulated rating calculation - in real implementation this would be based on user reviews
219
+ const baseRating = 3.0;
220
+ const hasDescription = artifact.metadata?.description ? 0.5 : 0;
221
+ const hasExamples = artifact.examples?.length > 0 ? 0.3 : 0;
222
+ const hasTags = artifact.metadata?.tags?.length > 0 ? 0.2 : 0;
223
+ return Math.min(baseRating + hasDescription + hasExamples + hasTags, 5.0);
224
+ }
225
+ }
226
+ //# sourceMappingURL=SearchArtifactsController.js.map
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=ListNamespaceController.d.ts.map
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ /*
3
+ This controller will:
4
+ call the GET API:
5
+ http://localhost:3000/api/v1/authors/utaba/commands/user?offset=0&limit=10
6
+
7
+ */
8
+ //# sourceMappingURL=ListNamespaceController.js.map
@@ -0,0 +1,35 @@
1
+ import { BaseToolController } from '../base/BaseToolController.js';
2
+ import { UcmApiClient } from '../../clients/UcmApiClient.js';
3
+ import { ILogger } from '../../interfaces/ILogger.js';
4
+ export declare class ExploreNamespaceController extends BaseToolController {
5
+ constructor(ucmClient: UcmApiClient, logger: ILogger);
6
+ get name(): string;
7
+ get description(): string;
8
+ get inputSchema(): any;
9
+ protected handleExecute(params: any): Promise<any>;
10
+ private exploreNamespace;
11
+ private getDirectContent;
12
+ private getArtifactsAtPath;
13
+ private applyFilters;
14
+ private processArtifacts;
15
+ private getNodeSummary;
16
+ private calculateNodeStatistics;
17
+ private sortNodes;
18
+ private generateNavigationHints;
19
+ private buildBreadcrumbs;
20
+ private isValidNamespacePath;
21
+ private getNameFromPath;
22
+ private determineNodeType;
23
+ private calculateLevel;
24
+ private generateContentPreview;
25
+ private getLastActivity;
26
+ private countTotalNodes;
27
+ private calculateMaxDepth;
28
+ private hasMoreContent;
29
+ private countArtifactsRecursively;
30
+ private collectMetadataRecursively;
31
+ private getLastActivityRecursively;
32
+ private calculatePopularityScore;
33
+ private findInterestingPaths;
34
+ }
35
+ //# sourceMappingURL=ExploreNamespaceController.d.ts.map