@dollhousemcp/mcp-server 1.4.0 → 1.4.2

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 (42) hide show
  1. package/README.md +54 -9
  2. package/dist/config/updateConfig.d.ts +84 -0
  3. package/dist/config/updateConfig.d.ts.map +1 -0
  4. package/dist/config/updateConfig.js +148 -0
  5. package/dist/generated/version.d.ts +9 -0
  6. package/dist/generated/version.d.ts.map +1 -0
  7. package/dist/generated/version.js +9 -0
  8. package/dist/index.d.ts +6 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +34 -6
  11. package/dist/portfolio/DefaultElementProvider.d.ts +78 -0
  12. package/dist/portfolio/DefaultElementProvider.d.ts.map +1 -0
  13. package/dist/portfolio/DefaultElementProvider.js +398 -0
  14. package/dist/portfolio/PortfolioManager.d.ts +7 -0
  15. package/dist/portfolio/PortfolioManager.d.ts.map +1 -1
  16. package/dist/portfolio/PortfolioManager.js +44 -3
  17. package/dist/security/commandValidator.d.ts.map +1 -1
  18. package/dist/security/commandValidator.js +5 -2
  19. package/dist/security/securityMonitor.d.ts +2 -1
  20. package/dist/security/securityMonitor.d.ts.map +1 -1
  21. package/dist/security/securityMonitor.js +1 -1
  22. package/dist/server/tools/UpdateTools.d.ts.map +1 -1
  23. package/dist/server/tools/UpdateTools.js +22 -1
  24. package/dist/server/types.d.ts +1 -0
  25. package/dist/server/types.d.ts.map +1 -1
  26. package/dist/server/types.js +1 -1
  27. package/dist/update/BackupManager.d.ts +17 -0
  28. package/dist/update/BackupManager.d.ts.map +1 -1
  29. package/dist/update/BackupManager.js +112 -3
  30. package/dist/update/UpdateManager.d.ts +19 -0
  31. package/dist/update/UpdateManager.d.ts.map +1 -1
  32. package/dist/update/UpdateManager.js +485 -15
  33. package/dist/update/VersionManager.d.ts +1 -1
  34. package/dist/update/VersionManager.d.ts.map +1 -1
  35. package/dist/update/VersionManager.js +62 -15
  36. package/dist/utils/fileOperations.d.ts +83 -0
  37. package/dist/utils/fileOperations.d.ts.map +1 -0
  38. package/dist/utils/fileOperations.js +291 -0
  39. package/dist/utils/installation.d.ts +30 -0
  40. package/dist/utils/installation.d.ts.map +1 -0
  41. package/dist/utils/installation.js +160 -0
  42. package/package.json +3 -1
@@ -0,0 +1,78 @@
1
+ /**
2
+ * DefaultElementProvider - Populates portfolio with default elements from bundled data
3
+ *
4
+ * This class handles copying default personas, skills, templates, and other elements
5
+ * from the NPM package or Git repository to the user's portfolio on first run.
6
+ * It ensures users have example content to work with immediately after installation.
7
+ */
8
+ export declare const FILE_CONSTANTS: {
9
+ readonly ELEMENT_EXTENSION: ".md";
10
+ readonly YAML_EXTENSION: ".yaml";
11
+ readonly YML_EXTENSION: ".yml";
12
+ readonly JSON_EXTENSION: ".json";
13
+ readonly MAX_FILE_SIZE: number;
14
+ readonly CHECKSUM_ALGORITHM: "sha256";
15
+ readonly FILE_PERMISSIONS: 420;
16
+ readonly CHUNK_SIZE: number;
17
+ };
18
+ export interface DefaultElementProviderConfig {
19
+ /** Custom data directory paths to search (checked before default paths) */
20
+ customDataPaths?: string[];
21
+ /** Whether to use default search paths after custom paths */
22
+ useDefaultPaths?: boolean;
23
+ }
24
+ export declare class DefaultElementProvider {
25
+ private readonly __dirname;
26
+ private static cachedDataDir;
27
+ private static populateInProgress;
28
+ private readonly config;
29
+ constructor(config?: DefaultElementProviderConfig);
30
+ /**
31
+ * Search paths for bundled data directory
32
+ * Ordered by priority - custom paths first, then development/git, then NPM locations
33
+ */
34
+ private get dataSearchPaths();
35
+ /**
36
+ * Find the bundled data directory by checking each search path
37
+ * Uses Promise.allSettled for better performance and caches the result
38
+ */
39
+ private findDataDirectory;
40
+ /**
41
+ * Helper to check if a directory exists
42
+ */
43
+ private directoryExists;
44
+ /**
45
+ * Copy all files from source directory to destination directory
46
+ * Skips files that already exist to preserve user modifications
47
+ */
48
+ private copyElementFiles;
49
+ /**
50
+ * Copy a file with integrity verification
51
+ * Ensures the file was copied correctly by comparing sizes
52
+ */
53
+ /**
54
+ * Calculate checksum of a file for integrity verification
55
+ * @param filePath Path to the file
56
+ * @returns Hex-encoded checksum
57
+ */
58
+ private calculateChecksum;
59
+ /**
60
+ * Copy file with integrity verification and retry logic
61
+ * @param sourcePath Source file path
62
+ * @param destPath Destination file path
63
+ * @throws Error if copy fails after all retry attempts
64
+ */
65
+ private copyFileWithVerification;
66
+ /**
67
+ * Populate the portfolio with default elements from bundled data
68
+ * This is called during portfolio initialization for new installations
69
+ * Protected against concurrent calls to prevent race conditions
70
+ */
71
+ populateDefaults(portfolioBaseDir: string): Promise<void>;
72
+ /**
73
+ * Perform the actual population of default elements
74
+ * @param portfolioBaseDir Base directory of the portfolio
75
+ */
76
+ private performPopulation;
77
+ }
78
+ //# sourceMappingURL=DefaultElementProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DefaultElementProvider.d.ts","sourceRoot":"","sources":["../../src/portfolio/DefaultElementProvider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAYH,eAAO,MAAM,cAAc;;;;;;;;;CASjB,CAAC;AAOX,MAAM,WAAW,4BAA4B;IAC3C,2EAA2E;IAC3E,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,6DAA6D;IAC7D,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAuB;IACnD,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAyC;IAC1E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;gBAE1C,MAAM,CAAC,EAAE,4BAA4B;IASjD;;;OAGG;IACH,OAAO,KAAK,eAAe,GAmC1B;IAED;;;OAGG;YACW,iBAAiB;IAyC/B;;OAEG;YACW,eAAe;IAS7B;;;OAGG;YACW,gBAAgB;IAmG9B;;;OAGG;IACH;;;;OAIG;YACW,iBAAiB;IAuB/B;;;;;OAKG;YACW,wBAAwB;IA8EtC;;;;OAIG;IACU,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsBtE;;;OAGG;YACW,iBAAiB;CAwFhC"}
@@ -0,0 +1,398 @@
1
+ /**
2
+ * DefaultElementProvider - Populates portfolio with default elements from bundled data
3
+ *
4
+ * This class handles copying default personas, skills, templates, and other elements
5
+ * from the NPM package or Git repository to the user's portfolio on first run.
6
+ * It ensures users have example content to work with immediately after installation.
7
+ */
8
+ import * as fs from 'fs/promises';
9
+ import * as path from 'path';
10
+ import { fileURLToPath } from 'url';
11
+ import { createHash } from 'crypto';
12
+ import { logger } from '../utils/logger.js';
13
+ import { ElementType } from './types.js';
14
+ import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
15
+ import { SecurityMonitor } from '../security/securityMonitor.js';
16
+ // File operation constants
17
+ export const FILE_CONSTANTS = {
18
+ ELEMENT_EXTENSION: '.md',
19
+ YAML_EXTENSION: '.yaml',
20
+ YML_EXTENSION: '.yml',
21
+ JSON_EXTENSION: '.json',
22
+ MAX_FILE_SIZE: 10 * 1024 * 1024, // 10MB max file size for safety
23
+ CHECKSUM_ALGORITHM: 'sha256',
24
+ FILE_PERMISSIONS: 0o644,
25
+ CHUNK_SIZE: 64 * 1024 // 64KB chunks for reading large files
26
+ };
27
+ // Internal constants
28
+ const DATA_DIR_CACHE_KEY = 'dollhouse_data_dir';
29
+ const COPY_RETRY_ATTEMPTS = 3;
30
+ const COPY_RETRY_DELAY = 100; // ms
31
+ export class DefaultElementProvider {
32
+ __dirname;
33
+ static cachedDataDir = null;
34
+ static populateInProgress = new Map();
35
+ config;
36
+ constructor(config) {
37
+ const __filename = fileURLToPath(import.meta.url);
38
+ this.__dirname = path.dirname(__filename);
39
+ this.config = {
40
+ useDefaultPaths: true,
41
+ ...config
42
+ };
43
+ }
44
+ /**
45
+ * Search paths for bundled data directory
46
+ * Ordered by priority - custom paths first, then development/git, then NPM locations
47
+ */
48
+ get dataSearchPaths() {
49
+ const paths = [];
50
+ // Add custom paths first (highest priority)
51
+ if (this.config.customDataPaths) {
52
+ paths.push(...this.config.customDataPaths);
53
+ }
54
+ // Add default paths if enabled
55
+ if (this.config.useDefaultPaths !== false) {
56
+ paths.push(
57
+ // Development/Git installation (relative to this file)
58
+ path.join(this.__dirname, '../../data'), path.join(this.__dirname, '../../../data'),
59
+ // NPM installations - macOS Homebrew
60
+ '/opt/homebrew/lib/node_modules/@dollhousemcp/mcp-server/data',
61
+ // NPM installations - standard Unix/Linux
62
+ '/usr/local/lib/node_modules/@dollhousemcp/mcp-server/data', '/usr/lib/node_modules/@dollhousemcp/mcp-server/data',
63
+ // NPM installations - Windows
64
+ 'C:\\Program Files\\nodejs\\node_modules\\@dollhousemcp\\mcp-server\\data', 'C:\\Program Files (x86)\\nodejs\\node_modules\\@dollhousemcp\\mcp-server\\data',
65
+ // NPM installations - Windows with nvm
66
+ path.join(process.env.APPDATA || '', 'npm', 'node_modules', '@dollhousemcp', 'mcp-server', 'data'),
67
+ // Current working directory (last resort)
68
+ path.join(process.cwd(), 'data'));
69
+ }
70
+ return paths;
71
+ }
72
+ /**
73
+ * Find the bundled data directory by checking each search path
74
+ * Uses Promise.allSettled for better performance and caches the result
75
+ */
76
+ async findDataDirectory() {
77
+ // Return cached value if available
78
+ if (DefaultElementProvider.cachedDataDir !== null) {
79
+ return DefaultElementProvider.cachedDataDir;
80
+ }
81
+ // Check all paths in parallel for better performance
82
+ const checkPromises = this.dataSearchPaths.map(async (searchPath) => {
83
+ try {
84
+ const stats = await fs.stat(searchPath);
85
+ if (stats.isDirectory()) {
86
+ // Verify it contains expected subdirectories
87
+ const hasPersonas = await this.directoryExists(path.join(searchPath, 'personas'));
88
+ const hasSkills = await this.directoryExists(path.join(searchPath, 'skills'));
89
+ if (hasPersonas || hasSkills) {
90
+ return searchPath;
91
+ }
92
+ }
93
+ }
94
+ catch (error) {
95
+ // Directory doesn't exist or can't be accessed
96
+ return null;
97
+ }
98
+ return null;
99
+ });
100
+ const results = await Promise.allSettled(checkPromises);
101
+ // Find the first successful result
102
+ for (const result of results) {
103
+ if (result.status === 'fulfilled' && result.value !== null) {
104
+ logger.info(`[DefaultElementProvider] Found data directory at: ${result.value}`);
105
+ // Cache the result
106
+ DefaultElementProvider.cachedDataDir = result.value;
107
+ return result.value;
108
+ }
109
+ }
110
+ logger.warn('[DefaultElementProvider] No bundled data directory found in any search path');
111
+ return null;
112
+ }
113
+ /**
114
+ * Helper to check if a directory exists
115
+ */
116
+ async directoryExists(dirPath) {
117
+ try {
118
+ const stats = await fs.stat(dirPath);
119
+ return stats.isDirectory();
120
+ }
121
+ catch {
122
+ return false;
123
+ }
124
+ }
125
+ /**
126
+ * Copy all files from source directory to destination directory
127
+ * Skips files that already exist to preserve user modifications
128
+ */
129
+ async copyElementFiles(sourceDir, destDir, elementType) {
130
+ let copiedCount = 0;
131
+ try {
132
+ // Ensure destination directory exists
133
+ await fs.mkdir(destDir, { recursive: true });
134
+ // Read source directory
135
+ const files = await fs.readdir(sourceDir);
136
+ for (const file of files) {
137
+ // Only copy markdown files
138
+ if (!file.endsWith(FILE_CONSTANTS.ELEMENT_EXTENSION)) {
139
+ continue;
140
+ }
141
+ // Normalize filename for security
142
+ const normalizedFile = UnicodeValidator.normalize(file);
143
+ if (!normalizedFile.isValid) {
144
+ logger.warn(`[DefaultElementProvider] Skipping file with invalid Unicode: ${file}`);
145
+ continue;
146
+ }
147
+ const sourcePath = path.join(sourceDir, normalizedFile.normalizedContent);
148
+ const destPath = path.join(destDir, normalizedFile.normalizedContent);
149
+ try {
150
+ // Check if destination file already exists
151
+ await fs.access(destPath);
152
+ logger.debug(`[DefaultElementProvider] Skipping existing file: ${normalizedFile.normalizedContent}`);
153
+ continue;
154
+ }
155
+ catch {
156
+ // File doesn't exist, proceed with copy
157
+ }
158
+ try {
159
+ // Validate source file before copying
160
+ const sourceStats = await fs.stat(sourcePath);
161
+ // Check file size limit
162
+ if (sourceStats.size > FILE_CONSTANTS.MAX_FILE_SIZE) {
163
+ logger.warn(`[DefaultElementProvider] Skipping oversized file ${normalizedFile.normalizedContent}: ` +
164
+ `${sourceStats.size} bytes (max: ${FILE_CONSTANTS.MAX_FILE_SIZE} bytes)`, {
165
+ file: normalizedFile.normalizedContent,
166
+ size: sourceStats.size,
167
+ maxSize: FILE_CONSTANTS.MAX_FILE_SIZE,
168
+ elementType
169
+ });
170
+ continue;
171
+ }
172
+ // Copy the file with verification
173
+ await this.copyFileWithVerification(sourcePath, destPath);
174
+ copiedCount++;
175
+ logger.debug(`[DefaultElementProvider] Copied ${elementType}: ${normalizedFile.normalizedContent}`);
176
+ // Log security event for each file copied
177
+ SecurityMonitor.logSecurityEvent({
178
+ type: 'FILE_COPIED',
179
+ severity: 'LOW',
180
+ source: 'DefaultElementProvider.copyElementFiles',
181
+ details: `Copied default ${elementType} file: ${normalizedFile.normalizedContent}`,
182
+ metadata: {
183
+ sourcePath,
184
+ destPath,
185
+ elementType,
186
+ fileSize: (await fs.stat(destPath)).size
187
+ }
188
+ });
189
+ }
190
+ catch (error) {
191
+ const err = error;
192
+ logger.error(`[DefaultElementProvider] Failed to copy ${normalizedFile.normalizedContent}`, {
193
+ error: err.message,
194
+ stack: err.stack,
195
+ sourcePath,
196
+ destPath,
197
+ elementType
198
+ });
199
+ // Continue with other files instead of failing completely
200
+ }
201
+ }
202
+ if (copiedCount > 0) {
203
+ logger.info(`[DefaultElementProvider] Copied ${copiedCount} ${elementType} file(s)`);
204
+ }
205
+ }
206
+ catch (error) {
207
+ logger.error(`[DefaultElementProvider] Error copying ${elementType} files:`, error);
208
+ }
209
+ return copiedCount;
210
+ }
211
+ /**
212
+ * Copy a file with integrity verification
213
+ * Ensures the file was copied correctly by comparing sizes
214
+ */
215
+ /**
216
+ * Calculate checksum of a file for integrity verification
217
+ * @param filePath Path to the file
218
+ * @returns Hex-encoded checksum
219
+ */
220
+ async calculateChecksum(filePath) {
221
+ const hash = createHash(FILE_CONSTANTS.CHECKSUM_ALGORITHM);
222
+ const stream = await fs.open(filePath, 'r');
223
+ try {
224
+ const buffer = Buffer.alloc(FILE_CONSTANTS.CHUNK_SIZE);
225
+ let bytesRead;
226
+ do {
227
+ const result = await stream.read(buffer, 0, FILE_CONSTANTS.CHUNK_SIZE);
228
+ bytesRead = result.bytesRead;
229
+ if (bytesRead > 0) {
230
+ hash.update(buffer.subarray(0, bytesRead));
231
+ }
232
+ } while (bytesRead > 0);
233
+ return hash.digest('hex');
234
+ }
235
+ finally {
236
+ await stream.close();
237
+ }
238
+ }
239
+ /**
240
+ * Copy file with integrity verification and retry logic
241
+ * @param sourcePath Source file path
242
+ * @param destPath Destination file path
243
+ * @throws Error if copy fails after all retry attempts
244
+ */
245
+ async copyFileWithVerification(sourcePath, destPath) {
246
+ let lastError = null;
247
+ for (let attempt = 1; attempt <= COPY_RETRY_ATTEMPTS; attempt++) {
248
+ try {
249
+ // Copy the file
250
+ await fs.copyFile(sourcePath, destPath);
251
+ // Verify size matches
252
+ const [sourceStats, destStats] = await Promise.all([
253
+ fs.stat(sourcePath),
254
+ fs.stat(destPath)
255
+ ]);
256
+ if (sourceStats.size !== destStats.size) {
257
+ throw new Error(`Size mismatch after copy - source: ${sourceStats.size} bytes, ` +
258
+ `destination: ${destStats.size} bytes`);
259
+ }
260
+ // Verify checksum matches for complete integrity
261
+ const [sourceChecksum, destChecksum] = await Promise.all([
262
+ this.calculateChecksum(sourcePath),
263
+ this.calculateChecksum(destPath)
264
+ ]);
265
+ if (sourceChecksum !== destChecksum) {
266
+ throw new Error(`Checksum mismatch after copy - source: ${sourceChecksum}, ` +
267
+ `destination: ${destChecksum}`);
268
+ }
269
+ // Set proper permissions
270
+ try {
271
+ await fs.chmod(destPath, FILE_CONSTANTS.FILE_PERMISSIONS);
272
+ }
273
+ catch (error) {
274
+ logger.debug(`[DefaultElementProvider] Could not set permissions on ${destPath}: ${error}`, { sourcePath, destPath, attempt });
275
+ }
276
+ // Success - file copied and verified
277
+ logger.debug(`[DefaultElementProvider] Successfully copied and verified: ${path.basename(sourcePath)}`, { size: sourceStats.size, checksum: sourceChecksum.substring(0, 8) });
278
+ return;
279
+ }
280
+ catch (error) {
281
+ lastError = error;
282
+ // Clean up failed copy
283
+ try {
284
+ await fs.unlink(destPath);
285
+ }
286
+ catch {
287
+ // Ignore cleanup errors
288
+ }
289
+ if (attempt < COPY_RETRY_ATTEMPTS) {
290
+ logger.debug(`[DefaultElementProvider] Copy attempt ${attempt} failed, retrying...`, { error: lastError.message, sourcePath, destPath });
291
+ await new Promise(resolve => setTimeout(resolve, COPY_RETRY_DELAY * attempt));
292
+ }
293
+ }
294
+ }
295
+ // All attempts failed
296
+ throw new Error(`Failed to copy ${path.basename(sourcePath)} after ${COPY_RETRY_ATTEMPTS} attempts: ` +
297
+ `${lastError?.message || 'Unknown error'}`);
298
+ }
299
+ /**
300
+ * Populate the portfolio with default elements from bundled data
301
+ * This is called during portfolio initialization for new installations
302
+ * Protected against concurrent calls to prevent race conditions
303
+ */
304
+ async populateDefaults(portfolioBaseDir) {
305
+ // Check if population is already in progress for this portfolio
306
+ const existingPopulation = DefaultElementProvider.populateInProgress.get(portfolioBaseDir);
307
+ if (existingPopulation) {
308
+ logger.debug('[DefaultElementProvider] Population already in progress for portfolio, waiting...', { portfolioBaseDir });
309
+ return existingPopulation;
310
+ }
311
+ // Create new population promise
312
+ const populationPromise = this.performPopulation(portfolioBaseDir)
313
+ .finally(() => {
314
+ // Clean up when done
315
+ DefaultElementProvider.populateInProgress.delete(portfolioBaseDir);
316
+ });
317
+ DefaultElementProvider.populateInProgress.set(portfolioBaseDir, populationPromise);
318
+ return populationPromise;
319
+ }
320
+ /**
321
+ * Perform the actual population of default elements
322
+ * @param portfolioBaseDir Base directory of the portfolio
323
+ */
324
+ async performPopulation(portfolioBaseDir) {
325
+ logger.info('[DefaultElementProvider] Starting default element population', { portfolioBaseDir });
326
+ // Log security event for portfolio initialization
327
+ SecurityMonitor.logSecurityEvent({
328
+ type: 'PORTFOLIO_INITIALIZATION',
329
+ severity: 'LOW',
330
+ source: 'DefaultElementProvider.performPopulation',
331
+ details: `Starting default element population for portfolio: ${portfolioBaseDir}`
332
+ });
333
+ // Find the bundled data directory
334
+ const dataDir = await this.findDataDirectory();
335
+ if (!dataDir) {
336
+ logger.warn('[DefaultElementProvider] No bundled data directory found - portfolio will start empty', {
337
+ searchPaths: this.dataSearchPaths.slice(0, 3), // Log first few paths for debugging
338
+ cwd: process.cwd(),
339
+ dirname: this.__dirname
340
+ });
341
+ return;
342
+ }
343
+ // Track total files copied
344
+ let totalCopied = 0;
345
+ const copiedCounts = {};
346
+ // Map of data subdirectory names (plural) to portfolio directory names (singular)
347
+ const elementMappings = {
348
+ 'personas': ElementType.PERSONA,
349
+ 'skills': ElementType.SKILL,
350
+ 'templates': ElementType.TEMPLATE,
351
+ 'agents': ElementType.AGENT,
352
+ 'memories': ElementType.MEMORY,
353
+ 'ensembles': ElementType.ENSEMBLE
354
+ };
355
+ // Copy each element type
356
+ for (const [dataSubdir, elementType] of Object.entries(elementMappings)) {
357
+ const sourceDir = path.join(dataDir, dataSubdir);
358
+ const destDir = path.join(portfolioBaseDir, elementType);
359
+ try {
360
+ // Check if source directory exists
361
+ await fs.access(sourceDir);
362
+ const copiedCount = await this.copyElementFiles(sourceDir, destDir, dataSubdir);
363
+ copiedCounts[dataSubdir] = copiedCount;
364
+ totalCopied += copiedCount;
365
+ }
366
+ catch (error) {
367
+ // Source directory doesn't exist, skip
368
+ logger.debug(`[DefaultElementProvider] No ${dataSubdir} directory in bundled data`);
369
+ }
370
+ }
371
+ if (totalCopied > 0) {
372
+ logger.info(`[DefaultElementProvider] Successfully populated portfolio with ${totalCopied} default element(s)`, {
373
+ portfolioBaseDir,
374
+ dataDir,
375
+ breakdown: Object.entries(elementMappings).reduce((acc, [dataDir, elementType]) => {
376
+ acc[elementType] = copiedCounts[dataDir] || 0;
377
+ return acc;
378
+ }, {})
379
+ });
380
+ // Log security event for successful population
381
+ SecurityMonitor.logSecurityEvent({
382
+ type: 'PORTFOLIO_POPULATED',
383
+ severity: 'LOW',
384
+ source: 'DefaultElementProvider.performPopulation',
385
+ details: `Successfully populated portfolio with ${totalCopied} default elements`,
386
+ metadata: {
387
+ portfolioBaseDir,
388
+ dataDir,
389
+ copiedCounts
390
+ }
391
+ });
392
+ }
393
+ else {
394
+ logger.info('[DefaultElementProvider] No new elements to copy - portfolio may already have content');
395
+ }
396
+ }
397
+ }
398
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRGVmYXVsdEVsZW1lbnRQcm92aWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wb3J0Zm9saW8vRGVmYXVsdEVsZW1lbnRQcm92aWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEtBQUssRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNsQyxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBQ3BDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFDcEMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQzVDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDekMsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFDOUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRWpFLDJCQUEyQjtBQUMzQixNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUc7SUFDNUIsaUJBQWlCLEVBQUUsS0FBSztJQUN4QixjQUFjLEVBQUUsT0FBTztJQUN2QixhQUFhLEVBQUUsTUFBTTtJQUNyQixjQUFjLEVBQUUsT0FBTztJQUN2QixhQUFhLEVBQUUsRUFBRSxHQUFHLElBQUksR0FBRyxJQUFJLEVBQUUsZ0NBQWdDO0lBQ2pFLGtCQUFrQixFQUFFLFFBQVE7SUFDNUIsZ0JBQWdCLEVBQUUsS0FBSztJQUN2QixVQUFVLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyxzQ0FBc0M7Q0FDcEQsQ0FBQztBQUVYLHFCQUFxQjtBQUNyQixNQUFNLGtCQUFrQixHQUFHLG9CQUFvQixDQUFDO0FBQ2hELE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxDQUFDO0FBQzlCLE1BQU0sZ0JBQWdCLEdBQUcsR0FBRyxDQUFDLENBQUMsS0FBSztBQVNuQyxN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QkFDaEYsR0FBRyxDQUFDLFdBQVcsQ0FBQyxHQUFHLFlBQVksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7b0JBQzlDLE9BQU8sR0FBRyxDQUFDO2dCQUNiLENBQUMsRUFBRSxFQUE0QixDQUFDO2FBQ2pDLENBQ0YsQ0FBQztZQUVGLCtDQUErQztZQUMvQyxlQUFlLENBQUMsZ0JBQWdCLENBQUM7Z0JBQy9CLElBQUksRUFBRSxxQkFBcUI7Z0JBQzNCLFFBQVEsRUFBRSxLQUFLO2dCQUNmLE1BQU0sRUFBRSwwQ0FBMEM7Z0JBQ2xELE9BQU8sRUFBRSx5Q0FBeUMsV0FBVyxtQkFBbUI7Z0JBQ2hGLFFBQVEsRUFBRTtvQkFDUixnQkFBZ0I7b0JBQ2hCLE9BQU87b0JBQ1AsWUFBWTtpQkFDYjthQUNGLENBQUMsQ0FBQztRQUNMLENBQUM7YUFBTSxDQUFDO1lBQ04sTUFBTSxDQUFDLElBQUksQ0FBQyx1RkFBdUYsQ0FBQyxDQUFDO1FBQ3ZHLENBQUM7SUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBEZWZhdWx0RWxlbWVudFByb3ZpZGVyIC0gUG9wdWxhdGVzIHBvcnRmb2xpbyB3aXRoIGRlZmF1bHQgZWxlbWVudHMgZnJvbSBidW5kbGVkIGRhdGFcbiAqIFxuICogVGhpcyBjbGFzcyBoYW5kbGVzIGNvcHlpbmcgZGVmYXVsdCBwZXJzb25hcywgc2tpbGxzLCB0ZW1wbGF0ZXMsIGFuZCBvdGhlciBlbGVtZW50c1xuICogZnJvbSB0aGUgTlBNIHBhY2thZ2Ugb3IgR2l0IHJlcG9zaXRvcnkgdG8gdGhlIHVzZXIncyBwb3J0Zm9saW8gb24gZmlyc3QgcnVuLlxuICogSXQgZW5zdXJlcyB1c2VycyBoYXZlIGV4YW1wbGUgY29udGVudCB0byB3b3JrIHdpdGggaW1tZWRpYXRlbHkgYWZ0ZXIgaW5zdGFsbGF0aW9uLlxuICovXG5cbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzL3Byb21pc2VzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcbmltcG9ydCB7IGNyZWF0ZUhhc2ggfSBmcm9tICdjcnlwdG8nO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IEVsZW1lbnRUeXBlIH0gZnJvbSAnLi90eXBlcy5qcyc7XG5pbXBvcnQgeyBVbmljb2RlVmFsaWRhdG9yIH0gZnJvbSAnLi4vc2VjdXJpdHkvdmFsaWRhdG9ycy91bmljb2RlVmFsaWRhdG9yLmpzJztcbmltcG9ydCB7IFNlY3VyaXR5TW9uaXRvciB9IGZyb20gJy4uL3NlY3VyaXR5L3NlY3VyaXR5TW9uaXRvci5qcyc7XG5cbi8vIEZpbGUgb3BlcmF0aW9uIGNvbnN0YW50c1xuZXhwb3J0IGNvbnN0IEZJTEVfQ09OU1RBTlRTID0ge1xuICBFTEVNRU5UX0VYVEVOU0lPTjogJy5tZCcsXG4gIFlBTUxfRVhURU5TSU9OOiAnLnlhbWwnLFxuICBZTUxfRVhURU5TSU9OOiAnLnltbCcsXG4gIEpTT05fRVhURU5TSU9OOiAnLmpzb24nLFxuICBNQVhfRklMRV9TSVpFOiAxMCAqIDEwMjQgKiAxMDI0LCAvLyAxME1CIG1heCBmaWxlIHNpemUgZm9yIHNhZmV0eVxuICBDSEVDS1NVTV9BTEdPUklUSE06ICdzaGEyNTYnLFxuICBGSUxFX1BFUk1JU1NJT05TOiAwbzY0NCxcbiAgQ0hVTktfU0laRTogNjQgKiAxMDI0IC8vIDY0S0IgY2h1bmtzIGZvciByZWFkaW5nIGxhcmdlIGZpbGVzXG59IGFzIGNvbnN0O1xuXG4vLyBJbnRlcm5hbCBjb25zdGFudHNcbmNvbnN0IERBVEFfRElSX0NBQ0hFX0tFWSA9ICdkb2xsaG91c2VfZGF0YV9kaXInO1xuY29uc3QgQ09QWV9SRVRSWV9BVFRFTVBUUyA9IDM7XG5jb25zdCBDT1BZX1JFVFJZX0RFTEFZID0gMTAwOyAvLyBtc1xuXG5leHBvcnQgaW50ZXJmYWNlIERlZmF1bHRFbGVtZW50UHJvdmlkZXJDb25maWcge1xuICAvKiogQ3VzdG9tIGRhdGEgZGlyZWN0b3J5IHBhdGhzIHRvIHNlYXJjaCAoY2hlY2tlZCBiZWZvcmUgZGVmYXVsdCBwYXRocykgKi9cbiAgY3VzdG9tRGF0YVBhdGhzPzogc3RyaW5nW107XG4gIC8qKiBXaGV0aGVyIHRvIHVzZSBkZWZhdWx0IHNlYXJjaCBwYXRocyBhZnRlciBjdXN0b20gcGF0aHMgKi9cbiAgdXNlRGVmYXVsdFBhdGhzPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGNsYXNzIERlZmF1bHRFbGVtZW50UHJvdmlkZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IF9fZGlybmFtZTogc3RyaW5nO1xuICBwcml2YXRlIHN0YXRpYyBjYWNoZWREYXRhRGlyOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBzdGF0aWMgcG9wdWxhdGVJblByb2dyZXNzOiBNYXA8c3RyaW5nLCBQcm9taXNlPHZvaWQ+PiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSByZWFkb25seSBjb25maWc6IERlZmF1bHRFbGVtZW50UHJvdmlkZXJDb25maWc7XG4gIFxuICBjb25zdHJ1Y3Rvcihjb25maWc/OiBEZWZhdWx0RWxlbWVudFByb3ZpZGVyQ29uZmlnKSB7XG4gICAgY29uc3QgX19maWxlbmFtZSA9IGZpbGVVUkxUb1BhdGgoaW1wb3J0Lm1ldGEudXJsKTtcbiAgICB0aGlzLl9fZGlybmFtZSA9IHBhdGguZGlybmFtZShfX2ZpbGVuYW1lKTtcbiAgICB0aGlzLmNvbmZpZyA9IHtcbiAgICAgIHVzZURlZmF1bHRQYXRoczogdHJ1ZSxcbiAgICAgIC4uLmNvbmZpZ1xuICAgIH07XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBTZWFyY2ggcGF0aHMgZm9yIGJ1bmRsZWQgZGF0YSBkaXJlY3RvcnlcbiAgICogT3JkZXJlZCBieSBwcmlvcml0eSAtIGN1c3RvbSBwYXRocyBmaXJzdCwgdGhlbiBkZXZlbG9wbWVudC9naXQsIHRoZW4gTlBNIGxvY2F0aW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBnZXQgZGF0YVNlYXJjaFBhdGhzKCk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBwYXRoczogc3RyaW5nW10gPSBbXTtcbiAgICBcbiAgICAvLyBBZGQgY3VzdG9tIHBhdGhzIGZpcnN0IChoaWdoZXN0IHByaW9yaXR5KVxuICAgIGlmICh0aGlzLmNvbmZpZy5jdXN0b21EYXRhUGF0aHMpIHtcbiAgICAgIHBhdGhzLnB1c2goLi4udGhpcy5jb25maWcuY3VzdG9tRGF0YVBhdGhzKTtcbiAgICB9XG4gICAgXG4gICAgLy8gQWRkIGRlZmF1bHQgcGF0aHMgaWYgZW5hYmxlZFxuICAgIGlmICh0aGlzLmNvbmZpZy51c2VEZWZhdWx0UGF0aHMgIT09IGZhbHNlKSB7XG4gICAgICBwYXRocy5wdXNoKFxuICAgICAgICAvLyBEZXZlbG9wbWVudC9HaXQgaW5zdGFsbGF0aW9uIChyZWxhdGl2ZSB0byB0aGlzIGZpbGUpXG4gICAgICAgIHBhdGguam9pbih0aGlzLl9fZGlybmFtZSwgJy4uLy4uL2RhdGEnKSxcbiAgICAgICAgcGF0aC5qb2luKHRoaXMuX19kaXJuYW1lLCAnLi4vLi4vLi4vZGF0YScpLFxuICAgICAgICBcbiAgICAgICAgLy8gTlBNIGluc3RhbGxhdGlvbnMgLSBtYWNPUyBIb21lYnJld1xuICAgICAgICAnL29wdC9ob21lYnJldy9saWIvbm9kZV9tb2R1bGVzL0Bkb2xsaG91c2VtY3AvbWNwLXNlcnZlci9kYXRhJyxcbiAgICAgICAgXG4gICAgICAgIC8vIE5QTSBpbnN0YWxsYXRpb25zIC0gc3RhbmRhcmQgVW5peC9MaW51eFxuICAgICAgICAnL3Vzci9sb2NhbC9saWIvbm9kZV9tb2R1bGVzL0Bkb2xsaG91c2VtY3AvbWNwLXNlcnZlci9kYXRhJyxcbiAgICAgICAgJy91c3IvbGliL25vZGVfbW9kdWxlcy9AZG9sbGhvdXNlbWNwL21jcC1zZXJ2ZXIvZGF0YScsXG4gICAgICAgIFxuICAgICAgICAvLyBOUE0gaW5zdGFsbGF0aW9ucyAtIFdpbmRvd3NcbiAgICAgICAgJ0M6XFxcXFByb2dyYW0gRmlsZXNcXFxcbm9kZWpzXFxcXG5vZGVfbW9kdWxlc1xcXFxAZG9sbGhvdXNlbWNwXFxcXG1jcC1zZXJ2ZXJcXFxcZGF0YScsXG4gICAgICAgICdDOlxcXFxQcm9ncmFtIEZpbGVzICh4ODYpXFxcXG5vZGVqc1xcXFxub2RlX21vZHVsZXNcXFxcQGRvbGxob3VzZW1jcFxcXFxtY3Atc2VydmVyXFxcXGRhdGEnLFxuICAgICAgICBcbiAgICAgICAgLy8gTlBNIGluc3RhbGxhdGlvbnMgLSBXaW5kb3dzIHdpdGggbnZtXG4gICAgICAgIHBhdGguam9pbihwcm9jZXNzLmVudi5BUFBEQVRBIHx8ICcnLCAnbnBtJywgJ25vZGVfbW9kdWxlcycsICdAZG9sbGhvdXNlbWNwJywgJ21jcC1zZXJ2ZXInLCAnZGF0YScpLFxuICAgICAgICBcbiAgICAgICAgLy8gQ3VycmVudCB3b3JraW5nIGRpcmVjdG9yeSAobGFzdCByZXNvcnQpXG4gICAgICAgIHBhdGguam9pbihwcm9jZXNzLmN3ZCgpLCAnZGF0YScpXG4gICAgICApO1xuICAgIH1cbiAgICBcbiAgICByZXR1cm4gcGF0aHM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBGaW5kIHRoZSBidW5kbGVkIGRhdGEgZGlyZWN0b3J5IGJ5IGNoZWNraW5nIGVhY2ggc2VhcmNoIHBhdGhcbiAgICogVXNlcyBQcm9taXNlLmFsbFNldHRsZWQgZm9yIGJldHRlciBwZXJmb3JtYW5jZSBhbmQgY2FjaGVzIHRoZSByZXN1bHRcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZmluZERhdGFEaXJlY3RvcnkoKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPiB7XG4gICAgLy8gUmV0dXJuIGNhY2hlZCB2YWx1ZSBpZiBhdmFpbGFibGVcbiAgICBpZiAoRGVmYXVsdEVsZW1lbnRQcm92aWRlci5jYWNoZWREYXRhRGlyICE9PSBudWxsKSB7XG4gICAgICByZXR1cm4gRGVmYXVsdEVsZW1lbnRQcm92aWRlci5jYWNoZWREYXRhRGlyO1xuICAgIH1cbiAgICBcbiAgICAvLyBDaGVjayBhbGwgcGF0aHMgaW4gcGFyYWxsZWwgZm9yIGJldHRlciBwZXJmb3JtYW5jZVxuICAgIGNvbnN0IGNoZWNrUHJvbWlzZXMgPSB0aGlzLmRhdGFTZWFyY2hQYXRocy5tYXAoYXN5bmMgKHNlYXJjaFBhdGgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHN0YXRzID0gYXdhaXQgZnMuc3RhdChzZWFyY2hQYXRoKTtcbiAgICAgICAgaWYgKHN0YXRzLmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgICAgICAvLyBWZXJpZnkgaXQgY29udGFpbnMgZXhwZWN0ZWQgc3ViZGlyZWN0b3JpZXNcbiAgICAgICAgICBjb25zdCBoYXNQZXJzb25hcyA9IGF3YWl0IHRoaXMuZGlyZWN0b3J5RXhpc3RzKHBhdGguam9pbihzZWFyY2hQYXRoLCAncGVyc29uYXMnKSk7XG4gICAgICAgICAgY29uc3QgaGFzU2tpbGxzID0gYXdhaXQgdGhpcy5kaXJlY3RvcnlFeGlzdHMocGF0aC5qb2luKHNlYXJjaFBhdGgsICdza2lsbHMnKSk7XG4gICAgICAgICAgaWYgKGhhc1BlcnNvbmFzIHx8IGhhc1NraWxscykge1xuICAgICAgICAgICAgcmV0dXJuIHNlYXJjaFBhdGg7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAvLyBEaXJlY3RvcnkgZG9lc24ndCBleGlzdCBvciBjYW4ndCBiZSBhY2Nlc3NlZFxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIHJldHVybiBudWxsO1xuICAgIH0pO1xuICAgIFxuICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoY2hlY2tQcm9taXNlcyk7XG4gICAgXG4gICAgLy8gRmluZCB0aGUgZmlyc3Qgc3VjY2Vzc2Z1bCByZXN1bHRcbiAgICBmb3IgKGNvbnN0IHJlc3VsdCBvZiByZXN1bHRzKSB7XG4gICAgICBpZiAocmVzdWx0LnN0YXR1cyA9PT0gJ2Z1bGZpbGxlZCcgJiYgcmVzdWx0LnZhbHVlICE9PSBudWxsKSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gRm91bmQgZGF0YSBkaXJlY3RvcnkgYXQ6ICR7cmVzdWx0LnZhbHVlfWApO1xuICAgICAgICAvLyBDYWNoZSB0aGUgcmVzdWx0XG4gICAgICAgIERlZmF1bHRFbGVtZW50UHJvdmlkZXIuY2FjaGVkRGF0YURpciA9IHJlc3VsdC52YWx1ZTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdC52YWx1ZTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgbG9nZ2VyLndhcm4oJ1tEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBObyBidW5kbGVkIGRhdGEgZGlyZWN0b3J5IGZvdW5kIGluIGFueSBzZWFyY2ggcGF0aCcpO1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIFxuICAvKipcbiAgICogSGVscGVyIHRvIGNoZWNrIGlmIGEgZGlyZWN0b3J5IGV4aXN0c1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBkaXJlY3RvcnlFeGlzdHMoZGlyUGF0aDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHN0YXRzID0gYXdhaXQgZnMuc3RhdChkaXJQYXRoKTtcbiAgICAgIHJldHVybiBzdGF0cy5pc0RpcmVjdG9yeSgpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIENvcHkgYWxsIGZpbGVzIGZyb20gc291cmNlIGRpcmVjdG9yeSB0byBkZXN0aW5hdGlvbiBkaXJlY3RvcnlcbiAgICogU2tpcHMgZmlsZXMgdGhhdCBhbHJlYWR5IGV4aXN0IHRvIHByZXNlcnZlIHVzZXIgbW9kaWZpY2F0aW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjb3B5RWxlbWVudEZpbGVzKHNvdXJjZURpcjogc3RyaW5nLCBkZXN0RGlyOiBzdHJpbmcsIGVsZW1lbnRUeXBlOiBzdHJpbmcpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGxldCBjb3BpZWRDb3VudCA9IDA7XG4gICAgXG4gICAgdHJ5IHtcbiAgICAgIC8vIEVuc3VyZSBkZXN0aW5hdGlvbiBkaXJlY3RvcnkgZXhpc3RzXG4gICAgICBhd2FpdCBmcy5ta2RpcihkZXN0RGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgIFxuICAgICAgLy8gUmVhZCBzb3VyY2UgZGlyZWN0b3J5XG4gICAgICBjb25zdCBmaWxlcyA9IGF3YWl0IGZzLnJlYWRkaXIoc291cmNlRGlyKTtcbiAgICAgIFxuICAgICAgZm9yIChjb25zdCBmaWxlIG9mIGZpbGVzKSB7XG4gICAgICAgIC8vIE9ubHkgY29weSBtYXJrZG93biBmaWxlc1xuICAgICAgICBpZiAoIWZpbGUuZW5kc1dpdGgoRklMRV9DT05TVEFOVFMuRUxFTUVOVF9FWFRFTlNJT04pKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIE5vcm1hbGl6ZSBmaWxlbmFtZSBmb3Igc2VjdXJpdHlcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZEZpbGUgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShmaWxlKTtcbiAgICAgICAgaWYgKCFub3JtYWxpemVkRmlsZS5pc1ZhbGlkKSB7XG4gICAgICAgICAgbG9nZ2VyLndhcm4oYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBTa2lwcGluZyBmaWxlIHdpdGggaW52YWxpZCBVbmljb2RlOiAke2ZpbGV9YCk7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIGNvbnN0IHNvdXJjZVBhdGggPSBwYXRoLmpvaW4oc291cmNlRGlyLCBub3JtYWxpemVkRmlsZS5ub3JtYWxpemVkQ29udGVudCk7XG4gICAgICAgIGNvbnN0IGRlc3RQYXRoID0gcGF0aC5qb2luKGRlc3REaXIsIG5vcm1hbGl6ZWRGaWxlLm5vcm1hbGl6ZWRDb250ZW50KTtcbiAgICAgICAgXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gQ2hlY2sgaWYgZGVzdGluYXRpb24gZmlsZSBhbHJlYWR5IGV4aXN0c1xuICAgICAgICAgIGF3YWl0IGZzLmFjY2VzcyhkZXN0UGF0aCk7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gU2tpcHBpbmcgZXhpc3RpbmcgZmlsZTogJHtub3JtYWxpemVkRmlsZS5ub3JtYWxpemVkQ29udGVudH1gKTtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgLy8gRmlsZSBkb2Vzbid0IGV4aXN0LCBwcm9jZWVkIHdpdGggY29weVxuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICB0cnkge1xuICAgICAgICAgIC8vIFZhbGlkYXRlIHNvdXJjZSBmaWxlIGJlZm9yZSBjb3B5aW5nXG4gICAgICAgICAgY29uc3Qgc291cmNlU3RhdHMgPSBhd2FpdCBmcy5zdGF0KHNvdXJjZVBhdGgpO1xuICAgICAgICAgIFxuICAgICAgICAgIC8vIENoZWNrIGZpbGUgc2l6ZSBsaW1pdFxuICAgICAgICAgIGlmIChzb3VyY2VTdGF0cy5zaXplID4gRklMRV9DT05TVEFOVFMuTUFYX0ZJTEVfU0laRSkge1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oXG4gICAgICAgICAgICAgIGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gU2tpcHBpbmcgb3ZlcnNpemVkIGZpbGUgJHtub3JtYWxpemVkRmlsZS5ub3JtYWxpemVkQ29udGVudH06IGAgK1xuICAgICAgICAgICAgICBgJHtzb3VyY2VTdGF0cy5zaXplfSBieXRlcyAobWF4OiAke0ZJTEVfQ09OU1RBTlRTLk1BWF9GSUxFX1NJWkV9IGJ5dGVzKWAsXG4gICAgICAgICAgICAgIHsgXG4gICAgICAgICAgICAgICAgZmlsZTogbm9ybWFsaXplZEZpbGUubm9ybWFsaXplZENvbnRlbnQsIFxuICAgICAgICAgICAgICAgIHNpemU6IHNvdXJjZVN0YXRzLnNpemUsXG4gICAgICAgICAgICAgICAgbWF4U2l6ZTogRklMRV9DT05TVEFOVFMuTUFYX0ZJTEVfU0laRSxcbiAgICAgICAgICAgICAgICBlbGVtZW50VHlwZSBcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgICBcbiAgICAgICAgICAvLyBDb3B5IHRoZSBmaWxlIHdpdGggdmVyaWZpY2F0aW9uXG4gICAgICAgICAgYXdhaXQgdGhpcy5jb3B5RmlsZVdpdGhWZXJpZmljYXRpb24oc291cmNlUGF0aCwgZGVzdFBhdGgpO1xuICAgICAgICAgIGNvcGllZENvdW50Kys7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gQ29waWVkICR7ZWxlbWVudFR5cGV9OiAke25vcm1hbGl6ZWRGaWxlLm5vcm1hbGl6ZWRDb250ZW50fWApO1xuICAgICAgICAgIFxuICAgICAgICAgIC8vIExvZyBzZWN1cml0eSBldmVudCBmb3IgZWFjaCBmaWxlIGNvcGllZFxuICAgICAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgICAgIHR5cGU6ICdGSUxFX0NPUElFRCcsXG4gICAgICAgICAgICBzZXZlcml0eTogJ0xPVycsXG4gICAgICAgICAgICBzb3VyY2U6ICdEZWZhdWx0RWxlbWVudFByb3ZpZGVyLmNvcHlFbGVtZW50RmlsZXMnLFxuICAgICAgICAgICAgZGV0YWlsczogYENvcGllZCBkZWZhdWx0ICR7ZWxlbWVudFR5cGV9IGZpbGU6ICR7bm9ybWFsaXplZEZpbGUubm9ybWFsaXplZENvbnRlbnR9YCxcbiAgICAgICAgICAgIG1ldGFkYXRhOiB7XG4gICAgICAgICAgICAgIHNvdXJjZVBhdGgsXG4gICAgICAgICAgICAgIGRlc3RQYXRoLFxuICAgICAgICAgICAgICBlbGVtZW50VHlwZSxcbiAgICAgICAgICAgICAgZmlsZVNpemU6IChhd2FpdCBmcy5zdGF0KGRlc3RQYXRoKSkuc2l6ZVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGNvbnN0IGVyciA9IGVycm9yIGFzIEVycm9yO1xuICAgICAgICAgIGxvZ2dlci5lcnJvcihcbiAgICAgICAgICAgIGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gRmFpbGVkIHRvIGNvcHkgJHtub3JtYWxpemVkRmlsZS5ub3JtYWxpemVkQ29udGVudH1gLFxuICAgICAgICAgICAgeyBcbiAgICAgICAgICAgICAgZXJyb3I6IGVyci5tZXNzYWdlLFxuICAgICAgICAgICAgICBzdGFjazogZXJyLnN0YWNrLFxuICAgICAgICAgICAgICBzb3VyY2VQYXRoLFxuICAgICAgICAgICAgICBkZXN0UGF0aCxcbiAgICAgICAgICAgICAgZWxlbWVudFR5cGVcbiAgICAgICAgICAgIH1cbiAgICAgICAgICApO1xuICAgICAgICAgIC8vIENvbnRpbnVlIHdpdGggb3RoZXIgZmlsZXMgaW5zdGVhZCBvZiBmYWlsaW5nIGNvbXBsZXRlbHlcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICBpZiAoY29waWVkQ291bnQgPiAwKSB7XG4gICAgICAgIGxvZ2dlci5pbmZvKGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gQ29waWVkICR7Y29waWVkQ291bnR9ICR7ZWxlbWVudFR5cGV9IGZpbGUocylgKTtcbiAgICAgIH1cbiAgICAgIFxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZXJyb3IoYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBFcnJvciBjb3B5aW5nICR7ZWxlbWVudFR5cGV9IGZpbGVzOmAsIGVycm9yKTtcbiAgICB9XG4gICAgXG4gICAgcmV0dXJuIGNvcGllZENvdW50O1xuICB9XG4gIFxuICAvKipcbiAgICogQ29weSBhIGZpbGUgd2l0aCBpbnRlZ3JpdHkgdmVyaWZpY2F0aW9uXG4gICAqIEVuc3VyZXMgdGhlIGZpbGUgd2FzIGNvcGllZCBjb3JyZWN0bHkgYnkgY29tcGFyaW5nIHNpemVzXG4gICAqL1xuICAvKipcbiAgICogQ2FsY3VsYXRlIGNoZWNrc3VtIG9mIGEgZmlsZSBmb3IgaW50ZWdyaXR5IHZlcmlmaWNhdGlvblxuICAgKiBAcGFyYW0gZmlsZVBhdGggUGF0aCB0byB0aGUgZmlsZVxuICAgKiBAcmV0dXJucyBIZXgtZW5jb2RlZCBjaGVja3N1bVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBjYWxjdWxhdGVDaGVja3N1bShmaWxlUGF0aDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCBoYXNoID0gY3JlYXRlSGFzaChGSUxFX0NPTlNUQU5UUy5DSEVDS1NVTV9BTEdPUklUSE0pO1xuICAgIGNvbnN0IHN0cmVhbSA9IGF3YWl0IGZzLm9wZW4oZmlsZVBhdGgsICdyJyk7XG4gICAgXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGJ1ZmZlciA9IEJ1ZmZlci5hbGxvYyhGSUxFX0NPTlNUQU5UUy5DSFVOS19TSVpFKTtcbiAgICAgIGxldCBieXRlc1JlYWQ6IG51bWJlcjtcbiAgICAgIFxuICAgICAgZG8ge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBzdHJlYW0ucmVhZChidWZmZXIsIDAsIEZJTEVfQ09OU1RBTlRTLkNIVU5LX1NJWkUpO1xuICAgICAgICBieXRlc1JlYWQgPSByZXN1bHQuYnl0ZXNSZWFkO1xuICAgICAgICBcbiAgICAgICAgaWYgKGJ5dGVzUmVhZCA+IDApIHtcbiAgICAgICAgICBoYXNoLnVwZGF0ZShidWZmZXIuc3ViYXJyYXkoMCwgYnl0ZXNSZWFkKSk7XG4gICAgICAgIH1cbiAgICAgIH0gd2hpbGUgKGJ5dGVzUmVhZCA+IDApO1xuICAgICAgXG4gICAgICByZXR1cm4gaGFzaC5kaWdlc3QoJ2hleCcpO1xuICAgIH0gZmluYWxseSB7XG4gICAgICBhd2FpdCBzdHJlYW0uY2xvc2UoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ29weSBmaWxlIHdpdGggaW50ZWdyaXR5IHZlcmlmaWNhdGlvbiBhbmQgcmV0cnkgbG9naWNcbiAgICogQHBhcmFtIHNvdXJjZVBhdGggU291cmNlIGZpbGUgcGF0aFxuICAgKiBAcGFyYW0gZGVzdFBhdGggRGVzdGluYXRpb24gZmlsZSBwYXRoXG4gICAqIEB0aHJvd3MgRXJyb3IgaWYgY29weSBmYWlscyBhZnRlciBhbGwgcmV0cnkgYXR0ZW1wdHNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgY29weUZpbGVXaXRoVmVyaWZpY2F0aW9uKHNvdXJjZVBhdGg6IHN0cmluZywgZGVzdFBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxldCBsYXN0RXJyb3I6IEVycm9yIHwgbnVsbCA9IG51bGw7XG4gICAgXG4gICAgZm9yIChsZXQgYXR0ZW1wdCA9IDE7IGF0dGVtcHQgPD0gQ09QWV9SRVRSWV9BVFRFTVBUUzsgYXR0ZW1wdCsrKSB7XG4gICAgICB0cnkge1xuICAgICAgICAvLyBDb3B5IHRoZSBmaWxlXG4gICAgICAgIGF3YWl0IGZzLmNvcHlGaWxlKHNvdXJjZVBhdGgsIGRlc3RQYXRoKTtcbiAgICAgICAgXG4gICAgICAgIC8vIFZlcmlmeSBzaXplIG1hdGNoZXNcbiAgICAgICAgY29uc3QgW3NvdXJjZVN0YXRzLCBkZXN0U3RhdHNdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgIGZzLnN0YXQoc291cmNlUGF0aCksXG4gICAgICAgICAgZnMuc3RhdChkZXN0UGF0aClcbiAgICAgICAgXSk7XG4gICAgICAgIFxuICAgICAgICBpZiAoc291cmNlU3RhdHMuc2l6ZSAhPT0gZGVzdFN0YXRzLnNpemUpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgU2l6ZSBtaXNtYXRjaCBhZnRlciBjb3B5IC0gc291cmNlOiAke3NvdXJjZVN0YXRzLnNpemV9IGJ5dGVzLCBgICtcbiAgICAgICAgICAgIGBkZXN0aW5hdGlvbjogJHtkZXN0U3RhdHMuc2l6ZX0gYnl0ZXNgXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgLy8gVmVyaWZ5IGNoZWNrc3VtIG1hdGNoZXMgZm9yIGNvbXBsZXRlIGludGVncml0eVxuICAgICAgICBjb25zdCBbc291cmNlQ2hlY2tzdW0sIGRlc3RDaGVja3N1bV0gPSBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgICAgdGhpcy5jYWxjdWxhdGVDaGVja3N1bShzb3VyY2VQYXRoKSxcbiAgICAgICAgICB0aGlzLmNhbGN1bGF0ZUNoZWNrc3VtKGRlc3RQYXRoKVxuICAgICAgICBdKTtcbiAgICAgICAgXG4gICAgICAgIGlmIChzb3VyY2VDaGVja3N1bSAhPT0gZGVzdENoZWNrc3VtKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYENoZWNrc3VtIG1pc21hdGNoIGFmdGVyIGNvcHkgLSBzb3VyY2U6ICR7c291cmNlQ2hlY2tzdW19LCBgICtcbiAgICAgICAgICAgIGBkZXN0aW5hdGlvbjogJHtkZXN0Q2hlY2tzdW19YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIFNldCBwcm9wZXIgcGVybWlzc2lvbnNcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBhd2FpdCBmcy5jaG1vZChkZXN0UGF0aCwgRklMRV9DT05TVEFOVFMuRklMRV9QRVJNSVNTSU9OUyk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgbG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBDb3VsZCBub3Qgc2V0IHBlcm1pc3Npb25zIG9uICR7ZGVzdFBhdGh9OiAke2Vycm9yfWAsXG4gICAgICAgICAgICB7IHNvdXJjZVBhdGgsIGRlc3RQYXRoLCBhdHRlbXB0IH1cbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICAvLyBTdWNjZXNzIC0gZmlsZSBjb3BpZWQgYW5kIHZlcmlmaWVkXG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgICBgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIFN1Y2Nlc3NmdWxseSBjb3BpZWQgYW5kIHZlcmlmaWVkOiAke3BhdGguYmFzZW5hbWUoc291cmNlUGF0aCl9YCxcbiAgICAgICAgICB7IHNpemU6IHNvdXJjZVN0YXRzLnNpemUsIGNoZWNrc3VtOiBzb3VyY2VDaGVja3N1bS5zdWJzdHJpbmcoMCwgOCkgfVxuICAgICAgICApO1xuICAgICAgICByZXR1cm47XG4gICAgICAgIFxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbGFzdEVycm9yID0gZXJyb3IgYXMgRXJyb3I7XG4gICAgICAgIFxuICAgICAgICAvLyBDbGVhbiB1cCBmYWlsZWQgY29weVxuICAgICAgICB0cnkge1xuICAgICAgICAgIGF3YWl0IGZzLnVubGluayhkZXN0UGF0aCk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIElnbm9yZSBjbGVhbnVwIGVycm9yc1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICBpZiAoYXR0ZW1wdCA8IENPUFlfUkVUUllfQVRURU1QVFMpIHtcbiAgICAgICAgICBsb2dnZXIuZGVidWcoXG4gICAgICAgICAgICBgW0RlZmF1bHRFbGVtZW50UHJvdmlkZXJdIENvcHkgYXR0ZW1wdCAke2F0dGVtcHR9IGZhaWxlZCwgcmV0cnlpbmcuLi5gLFxuICAgICAgICAgICAgeyBlcnJvcjogbGFzdEVycm9yLm1lc3NhZ2UsIHNvdXJjZVBhdGgsIGRlc3RQYXRoIH1cbiAgICAgICAgICApO1xuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKHJlc29sdmUgPT4gc2V0VGltZW91dChyZXNvbHZlLCBDT1BZX1JFVFJZX0RFTEFZICogYXR0ZW1wdCkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIC8vIEFsbCBhdHRlbXB0cyBmYWlsZWRcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgRmFpbGVkIHRvIGNvcHkgJHtwYXRoLmJhc2VuYW1lKHNvdXJjZVBhdGgpfSBhZnRlciAke0NPUFlfUkVUUllfQVRURU1QVFN9IGF0dGVtcHRzOiBgICtcbiAgICAgIGAke2xhc3RFcnJvcj8ubWVzc2FnZSB8fCAnVW5rbm93biBlcnJvcid9YFxuICAgICk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBQb3B1bGF0ZSB0aGUgcG9ydGZvbGlvIHdpdGggZGVmYXVsdCBlbGVtZW50cyBmcm9tIGJ1bmRsZWQgZGF0YVxuICAgKiBUaGlzIGlzIGNhbGxlZCBkdXJpbmcgcG9ydGZvbGlvIGluaXRpYWxpemF0aW9uIGZvciBuZXcgaW5zdGFsbGF0aW9uc1xuICAgKiBQcm90ZWN0ZWQgYWdhaW5zdCBjb25jdXJyZW50IGNhbGxzIHRvIHByZXZlbnQgcmFjZSBjb25kaXRpb25zXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgcG9wdWxhdGVEZWZhdWx0cyhwb3J0Zm9saW9CYXNlRGlyOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAvLyBDaGVjayBpZiBwb3B1bGF0aW9uIGlzIGFscmVhZHkgaW4gcHJvZ3Jlc3MgZm9yIHRoaXMgcG9ydGZvbGlvXG4gICAgY29uc3QgZXhpc3RpbmdQb3B1bGF0aW9uID0gRGVmYXVsdEVsZW1lbnRQcm92aWRlci5wb3B1bGF0ZUluUHJvZ3Jlc3MuZ2V0KHBvcnRmb2xpb0Jhc2VEaXIpO1xuICAgIGlmIChleGlzdGluZ1BvcHVsYXRpb24pIHtcbiAgICAgIGxvZ2dlci5kZWJ1ZyhcbiAgICAgICAgJ1tEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBQb3B1bGF0aW9uIGFscmVhZHkgaW4gcHJvZ3Jlc3MgZm9yIHBvcnRmb2xpbywgd2FpdGluZy4uLicsXG4gICAgICAgIHsgcG9ydGZvbGlvQmFzZURpciB9XG4gICAgICApO1xuICAgICAgcmV0dXJuIGV4aXN0aW5nUG9wdWxhdGlvbjtcbiAgICB9XG4gICAgXG4gICAgLy8gQ3JlYXRlIG5ldyBwb3B1bGF0aW9uIHByb21pc2VcbiAgICBjb25zdCBwb3B1bGF0aW9uUHJvbWlzZSA9IHRoaXMucGVyZm9ybVBvcHVsYXRpb24ocG9ydGZvbGlvQmFzZURpcilcbiAgICAgIC5maW5hbGx5KCgpID0+IHtcbiAgICAgICAgLy8gQ2xlYW4gdXAgd2hlbiBkb25lXG4gICAgICAgIERlZmF1bHRFbGVtZW50UHJvdmlkZXIucG9wdWxhdGVJblByb2dyZXNzLmRlbGV0ZShwb3J0Zm9saW9CYXNlRGlyKTtcbiAgICAgIH0pO1xuICAgIFxuICAgIERlZmF1bHRFbGVtZW50UHJvdmlkZXIucG9wdWxhdGVJblByb2dyZXNzLnNldChwb3J0Zm9saW9CYXNlRGlyLCBwb3B1bGF0aW9uUHJvbWlzZSk7XG4gICAgcmV0dXJuIHBvcHVsYXRpb25Qcm9taXNlO1xuICB9XG4gIFxuICAvKipcbiAgICogUGVyZm9ybSB0aGUgYWN0dWFsIHBvcHVsYXRpb24gb2YgZGVmYXVsdCBlbGVtZW50c1xuICAgKiBAcGFyYW0gcG9ydGZvbGlvQmFzZURpciBCYXNlIGRpcmVjdG9yeSBvZiB0aGUgcG9ydGZvbGlvXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHBlcmZvcm1Qb3B1bGF0aW9uKHBvcnRmb2xpb0Jhc2VEaXI6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxvZ2dlci5pbmZvKFxuICAgICAgJ1tEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBTdGFydGluZyBkZWZhdWx0IGVsZW1lbnQgcG9wdWxhdGlvbicsXG4gICAgICB7IHBvcnRmb2xpb0Jhc2VEaXIgfVxuICAgICk7XG4gICAgXG4gICAgLy8gTG9nIHNlY3VyaXR5IGV2ZW50IGZvciBwb3J0Zm9saW8gaW5pdGlhbGl6YXRpb25cbiAgICBTZWN1cml0eU1vbml0b3IubG9nU2VjdXJpdHlFdmVudCh7XG4gICAgICB0eXBlOiAnUE9SVEZPTElPX0lOSVRJQUxJWkFUSU9OJyxcbiAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgIHNvdXJjZTogJ0RlZmF1bHRFbGVtZW50UHJvdmlkZXIucGVyZm9ybVBvcHVsYXRpb24nLFxuICAgICAgZGV0YWlsczogYFN0YXJ0aW5nIGRlZmF1bHQgZWxlbWVudCBwb3B1bGF0aW9uIGZvciBwb3J0Zm9saW86ICR7cG9ydGZvbGlvQmFzZURpcn1gXG4gICAgfSk7XG4gICAgXG4gICAgLy8gRmluZCB0aGUgYnVuZGxlZCBkYXRhIGRpcmVjdG9yeVxuICAgIGNvbnN0IGRhdGFEaXIgPSBhd2FpdCB0aGlzLmZpbmREYXRhRGlyZWN0b3J5KCk7XG4gICAgaWYgKCFkYXRhRGlyKSB7XG4gICAgICBsb2dnZXIud2FybihcbiAgICAgICAgJ1tEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBObyBidW5kbGVkIGRhdGEgZGlyZWN0b3J5IGZvdW5kIC0gcG9ydGZvbGlvIHdpbGwgc3RhcnQgZW1wdHknLFxuICAgICAgICB7IFxuICAgICAgICAgIHNlYXJjaFBhdGhzOiB0aGlzLmRhdGFTZWFyY2hQYXRocy5zbGljZSgwLCAzKSwgLy8gTG9nIGZpcnN0IGZldyBwYXRocyBmb3IgZGVidWdnaW5nXG4gICAgICAgICAgY3dkOiBwcm9jZXNzLmN3ZCgpLFxuICAgICAgICAgIGRpcm5hbWU6IHRoaXMuX19kaXJuYW1lXG4gICAgICAgIH1cbiAgICAgICk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIFxuICAgIC8vIFRyYWNrIHRvdGFsIGZpbGVzIGNvcGllZFxuICAgIGxldCB0b3RhbENvcGllZCA9IDA7XG4gICAgY29uc3QgY29waWVkQ291bnRzOiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+ID0ge307XG4gICAgXG4gICAgLy8gTWFwIG9mIGRhdGEgc3ViZGlyZWN0b3J5IG5hbWVzIChwbHVyYWwpIHRvIHBvcnRmb2xpbyBkaXJlY3RvcnkgbmFtZXMgKHNpbmd1bGFyKVxuICAgIGNvbnN0IGVsZW1lbnRNYXBwaW5nczogUmVjb3JkPHN0cmluZywgRWxlbWVudFR5cGU+ID0ge1xuICAgICAgJ3BlcnNvbmFzJzogRWxlbWVudFR5cGUuUEVSU09OQSxcbiAgICAgICdza2lsbHMnOiBFbGVtZW50VHlwZS5TS0lMTCxcbiAgICAgICd0ZW1wbGF0ZXMnOiBFbGVtZW50VHlwZS5URU1QTEFURSxcbiAgICAgICdhZ2VudHMnOiBFbGVtZW50VHlwZS5BR0VOVCxcbiAgICAgICdtZW1vcmllcyc6IEVsZW1lbnRUeXBlLk1FTU9SWSxcbiAgICAgICdlbnNlbWJsZXMnOiBFbGVtZW50VHlwZS5FTlNFTUJMRVxuICAgIH07XG4gICAgXG4gICAgLy8gQ29weSBlYWNoIGVsZW1lbnQgdHlwZVxuICAgIGZvciAoY29uc3QgW2RhdGFTdWJkaXIsIGVsZW1lbnRUeXBlXSBvZiBPYmplY3QuZW50cmllcyhlbGVtZW50TWFwcGluZ3MpKSB7XG4gICAgICBjb25zdCBzb3VyY2VEaXIgPSBwYXRoLmpvaW4oZGF0YURpciwgZGF0YVN1YmRpcik7XG4gICAgICBjb25zdCBkZXN0RGlyID0gcGF0aC5qb2luKHBvcnRmb2xpb0Jhc2VEaXIsIGVsZW1lbnRUeXBlKTtcbiAgICAgIFxuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gQ2hlY2sgaWYgc291cmNlIGRpcmVjdG9yeSBleGlzdHNcbiAgICAgICAgYXdhaXQgZnMuYWNjZXNzKHNvdXJjZURpcik7XG4gICAgICAgIGNvbnN0IGNvcGllZENvdW50ID0gYXdhaXQgdGhpcy5jb3B5RWxlbWVudEZpbGVzKHNvdXJjZURpciwgZGVzdERpciwgZGF0YVN1YmRpcik7XG4gICAgICAgIGNvcGllZENvdW50c1tkYXRhU3ViZGlyXSA9IGNvcGllZENvdW50O1xuICAgICAgICB0b3RhbENvcGllZCArPSBjb3BpZWRDb3VudDtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIC8vIFNvdXJjZSBkaXJlY3RvcnkgZG9lc24ndCBleGlzdCwgc2tpcFxuICAgICAgICBsb2dnZXIuZGVidWcoYFtEZWZhdWx0RWxlbWVudFByb3ZpZGVyXSBObyAke2RhdGFTdWJkaXJ9IGRpcmVjdG9yeSBpbiBidW5kbGVkIGRhdGFgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgaWYgKHRvdGFsQ29waWVkID4gMCkge1xuICAgICAgbG9nZ2VyLmluZm8oXG4gICAgICAgIGBbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gU3VjY2Vzc2Z1bGx5IHBvcHVsYXRlZCBwb3J0Zm9saW8gd2l0aCAke3RvdGFsQ29waWVkfSBkZWZhdWx0IGVsZW1lbnQocylgLFxuICAgICAgICB7XG4gICAgICAgICAgcG9ydGZvbGlvQmFzZURpcixcbiAgICAgICAgICBkYXRhRGlyLFxuICAgICAgICAgIGJyZWFrZG93bjogT2JqZWN0LmVudHJpZXMoZWxlbWVudE1hcHBpbmdzKS5yZWR1Y2UoKGFjYywgW2RhdGFEaXIsIGVsZW1lbnRUeXBlXSkgPT4ge1xuICAgICAgICAgICAgYWNjW2VsZW1lbnRUeXBlXSA9IGNvcGllZENvdW50c1tkYXRhRGlyXSB8fCAwO1xuICAgICAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgICAgICB9LCB7fSBhcyBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+KVxuICAgICAgICB9XG4gICAgICApO1xuICAgICAgXG4gICAgICAvLyBMb2cgc2VjdXJpdHkgZXZlbnQgZm9yIHN1Y2Nlc3NmdWwgcG9wdWxhdGlvblxuICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICB0eXBlOiAnUE9SVEZPTElPX1BPUFVMQVRFRCcsXG4gICAgICAgIHNldmVyaXR5OiAnTE9XJyxcbiAgICAgICAgc291cmNlOiAnRGVmYXVsdEVsZW1lbnRQcm92aWRlci5wZXJmb3JtUG9wdWxhdGlvbicsXG4gICAgICAgIGRldGFpbHM6IGBTdWNjZXNzZnVsbHkgcG9wdWxhdGVkIHBvcnRmb2xpbyB3aXRoICR7dG90YWxDb3BpZWR9IGRlZmF1bHQgZWxlbWVudHNgLFxuICAgICAgICBtZXRhZGF0YToge1xuICAgICAgICAgIHBvcnRmb2xpb0Jhc2VEaXIsXG4gICAgICAgICAgZGF0YURpcixcbiAgICAgICAgICBjb3BpZWRDb3VudHNcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZ2dlci5pbmZvKCdbRGVmYXVsdEVsZW1lbnRQcm92aWRlcl0gTm8gbmV3IGVsZW1lbnRzIHRvIGNvcHkgLSBwb3J0Zm9saW8gbWF5IGFscmVhZHkgaGF2ZSBjb250ZW50Jyk7XG4gICAgfVxuICB9XG59Il19
@@ -7,6 +7,8 @@ export type { PortfolioConfig };
7
7
  export declare class PortfolioManager {
8
8
  private static instance;
9
9
  private static instanceLock;
10
+ private static initializationLock;
11
+ private static initializationPromise;
10
12
  private baseDir;
11
13
  private constructor();
12
14
  static getInstance(config?: PortfolioConfig): PortfolioManager;
@@ -20,8 +22,13 @@ export declare class PortfolioManager {
20
22
  getElementDir(type: ElementType): string;
21
23
  /**
22
24
  * Initialize the portfolio directory structure
25
+ * Uses locking to prevent race conditions during concurrent initialization
23
26
  */
24
27
  initialize(): Promise<void>;
28
+ /**
29
+ * Perform the actual initialization - should only be called once
30
+ */
31
+ private performInitialization;
25
32
  /**
26
33
  * Check if portfolio directory exists
27
34
  */
@@ -1 +1 @@
1
- {"version":3,"file":"PortfolioManager.d.ts","sourceRoot":"","sources":["../../src/portfolio/PortfolioManager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAG1D,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAmB;IAC1C,OAAO,CAAC,MAAM,CAAC,YAAY,CAAS;IACpC,OAAO,CAAC,OAAO,CAAS;IAExB,OAAO;WA4BO,WAAW,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,gBAAgB;IAiBrE;;OAEG;IACI,UAAU,IAAI,MAAM;IAI3B;;OAEG;IACI,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM;IAI/C;;OAEG;IACU,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBxC;;OAEG;IACU,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IASvC;;OAEG;IACU,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IA4C/D;;OAEG;IACI,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IA0ClE;;OAEG;IACU,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASjF;;OAEG;IACI,oBAAoB,IAAI,MAAM;IAIrC;;OAEG;IACU,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC;IAUlD;;OAEG;IACU,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;CAUnE"}
1
+ {"version":3,"file":"PortfolioManager.d.ts","sourceRoot":"","sources":["../../src/portfolio/PortfolioManager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAO1D,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,YAAY,EAAE,eAAe,EAAE,CAAC;AAEhC,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAmB;IAC1C,OAAO,CAAC,MAAM,CAAC,YAAY,CAAS;IACpC,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAAS;IAC1C,OAAO,CAAC,MAAM,CAAC,qBAAqB,CAA8B;IAClE,OAAO,CAAC,OAAO,CAAS;IAExB,OAAO;WA4BO,WAAW,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,gBAAgB;IAiBrE;;OAEG;IACI,UAAU,IAAI,MAAM;IAI3B;;OAEG;IACI,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM;IAI/C;;;OAGG;IACU,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBxC;;OAEG;YACW,qBAAqB;IAgCnC;;OAEG;IACU,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IASvC;;OAEG;IACU,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IA4C/D;;OAEG;IACI,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IA0ClE;;OAEG;IACU,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASjF;;OAEG;IACI,oBAAoB,IAAI,MAAM;IAIrC;;OAEG;IACU,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC;IAUlD;;OAEG;IACU,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;CAUnE"}