@dollhousemcp/mcp-server 1.7.3 → 1.7.4

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 (51) hide show
  1. package/dist/config/ConfigWizard.d.ts +78 -0
  2. package/dist/config/ConfigWizard.d.ts.map +1 -0
  3. package/dist/config/ConfigWizard.js +370 -0
  4. package/dist/config/ConfigWizardCheck.d.ts +47 -0
  5. package/dist/config/ConfigWizardCheck.d.ts.map +1 -0
  6. package/dist/config/ConfigWizardCheck.js +208 -0
  7. package/dist/config/ConfigWizardDisplay.d.ts +64 -0
  8. package/dist/config/ConfigWizardDisplay.d.ts.map +1 -0
  9. package/dist/config/ConfigWizardDisplay.js +150 -0
  10. package/dist/config/WizardFirstResponse.d.ts +25 -0
  11. package/dist/config/WizardFirstResponse.d.ts.map +1 -0
  12. package/dist/config/WizardFirstResponse.js +118 -0
  13. package/dist/config/portfolioConfig.d.ts +40 -0
  14. package/dist/config/portfolioConfig.d.ts.map +1 -0
  15. package/dist/config/portfolioConfig.js +58 -0
  16. package/dist/config/wizardTemplates.d.ts +84 -0
  17. package/dist/config/wizardTemplates.d.ts.map +1 -0
  18. package/dist/config/wizardTemplates.js +195 -0
  19. package/dist/elements/BaseElement.d.ts +15 -0
  20. package/dist/elements/BaseElement.d.ts.map +1 -1
  21. package/dist/elements/BaseElement.js +38 -5
  22. package/dist/generated/version.d.ts +2 -2
  23. package/dist/generated/version.js +3 -3
  24. package/dist/handlers/PortfolioPullHandler.d.ts +69 -0
  25. package/dist/handlers/PortfolioPullHandler.d.ts.map +1 -0
  26. package/dist/handlers/PortfolioPullHandler.js +340 -0
  27. package/dist/scripts/scripts/run-config-wizard.js +57 -0
  28. package/dist/scripts/src/config/ConfigManager.js +799 -0
  29. package/dist/scripts/src/config/ConfigWizard.js +368 -0
  30. package/dist/scripts/src/errors/SecurityError.js +47 -0
  31. package/dist/scripts/src/security/constants.js +28 -0
  32. package/dist/scripts/src/security/contentValidator.js +415 -0
  33. package/dist/scripts/src/security/errors.js +32 -0
  34. package/dist/scripts/src/security/regexValidator.js +217 -0
  35. package/dist/scripts/src/security/secureYamlParser.js +272 -0
  36. package/dist/scripts/src/security/securityMonitor.js +111 -0
  37. package/dist/scripts/src/security/validators/unicodeValidator.js +315 -0
  38. package/dist/scripts/src/utils/logger.js +288 -0
  39. package/dist/sync/PortfolioDownloader.d.ts +27 -0
  40. package/dist/sync/PortfolioDownloader.d.ts.map +1 -0
  41. package/dist/sync/PortfolioDownloader.js +120 -0
  42. package/dist/sync/PortfolioSyncComparer.d.ts +50 -0
  43. package/dist/sync/PortfolioSyncComparer.d.ts.map +1 -0
  44. package/dist/sync/PortfolioSyncComparer.js +158 -0
  45. package/dist/tools/getWelcomeMessage.d.ts +41 -0
  46. package/dist/tools/getWelcomeMessage.d.ts.map +1 -0
  47. package/dist/tools/getWelcomeMessage.js +109 -0
  48. package/dist/utils/TemplateRenderer.d.ts +63 -0
  49. package/dist/utils/TemplateRenderer.d.ts.map +1 -0
  50. package/dist/utils/TemplateRenderer.js +154 -0
  51. package/package.json +1 -1
@@ -0,0 +1,120 @@
1
+ /**
2
+ * PortfolioDownloader - Downloads elements from GitHub repositories
3
+ *
4
+ * Handles fetching file contents from GitHub, decoding base64 content,
5
+ * and returning structured element data ready for local storage.
6
+ */
7
+ import { logger } from '../utils/logger.js';
8
+ import { UnicodeValidator } from '../security/validators/unicodeValidator.js';
9
+ export class PortfolioDownloader {
10
+ /**
11
+ * Download an element from GitHub
12
+ */
13
+ async downloadFromGitHub(repoManager, elementPath, username, repository) {
14
+ try {
15
+ logger.info('Downloading element from GitHub', {
16
+ path: elementPath,
17
+ username,
18
+ repository
19
+ });
20
+ // Fetch the file content from GitHub
21
+ const response = await repoManager.githubRequest(`/repos/${username}/${repository}/contents/${elementPath}`);
22
+ if (!response || !response.content) {
23
+ throw new Error(`No content found at path: ${elementPath}`);
24
+ }
25
+ // Decode base64 content
26
+ const decodedContent = Buffer.from(response.content, 'base64').toString('utf-8');
27
+ // Normalize Unicode for security
28
+ const normalized = UnicodeValidator.normalize(decodedContent);
29
+ // Log download for audit trail
30
+ logger.info('Element downloaded successfully', {
31
+ path: elementPath,
32
+ repository: `${username}/${repository}`,
33
+ sha: response.sha
34
+ });
35
+ // Parse metadata from frontmatter if present
36
+ const metadata = this.extractMetadata(normalized.normalizedContent);
37
+ return {
38
+ content: normalized.normalizedContent,
39
+ metadata,
40
+ sha: response.sha
41
+ };
42
+ }
43
+ catch (error) {
44
+ logger.error('Failed to download element from GitHub', {
45
+ error,
46
+ path: elementPath
47
+ });
48
+ // Re-throw with more context
49
+ if (error instanceof Error) {
50
+ if (error.message.includes('404')) {
51
+ throw new Error(`Element not found at path: ${elementPath}`);
52
+ }
53
+ if (error.message.includes('401') || error.message.includes('403')) {
54
+ throw new Error(`Authentication failed. Please check your GitHub token.`);
55
+ }
56
+ throw error;
57
+ }
58
+ throw new Error(`Failed to download ${elementPath}: ${String(error)}`);
59
+ }
60
+ }
61
+ /**
62
+ * Extract metadata from frontmatter
63
+ */
64
+ extractMetadata(content) {
65
+ const metadata = {};
66
+ // Check for YAML frontmatter
67
+ const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
68
+ if (frontmatterMatch) {
69
+ try {
70
+ // Parse the frontmatter as simple key-value pairs
71
+ // (avoiding using yaml.load for security)
72
+ const frontmatterContent = frontmatterMatch[1];
73
+ const lines = frontmatterContent.split('\n');
74
+ for (const line of lines) {
75
+ const colonIndex = line.indexOf(':');
76
+ if (colonIndex > 0) {
77
+ const key = line.substring(0, colonIndex).trim();
78
+ const value = line.substring(colonIndex + 1).trim();
79
+ // Remove quotes if present
80
+ const cleanValue = value.replace(/^["']|["']$/g, '');
81
+ // Try to parse as JSON for arrays/objects, otherwise use as string
82
+ try {
83
+ metadata[key] = JSON.parse(cleanValue);
84
+ }
85
+ catch {
86
+ metadata[key] = cleanValue;
87
+ }
88
+ }
89
+ }
90
+ }
91
+ catch (error) {
92
+ logger.warn('Failed to parse frontmatter metadata', { error });
93
+ }
94
+ }
95
+ return metadata;
96
+ }
97
+ /**
98
+ * Download multiple elements in batch
99
+ */
100
+ async downloadBatch(repoManager, elementPaths, username, repository, onProgress) {
101
+ const results = new Map();
102
+ let downloaded = 0;
103
+ for (const path of elementPaths) {
104
+ try {
105
+ const elementData = await this.downloadFromGitHub(repoManager, path, username, repository);
106
+ results.set(path, elementData);
107
+ downloaded++;
108
+ if (onProgress) {
109
+ onProgress(downloaded, elementPaths.length);
110
+ }
111
+ }
112
+ catch (error) {
113
+ logger.error(`Failed to download ${path}`, { error });
114
+ // Continue with other downloads even if one fails
115
+ }
116
+ }
117
+ return results;
118
+ }
119
+ }
120
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUG9ydGZvbGlvRG93bmxvYWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zeW5jL1BvcnRmb2xpb0Rvd25sb2FkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0dBS0c7QUFHSCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDNUMsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNENBQTRDLENBQUM7QUFROUUsTUFBTSxPQUFPLG1CQUFtQjtJQUM5Qjs7T0FFRztJQUNILEtBQUssQ0FBQyxrQkFBa0IsQ0FDdEIsV0FBaUMsRUFDakMsV0FBbUIsRUFDbkIsUUFBZ0IsRUFDaEIsVUFBa0I7UUFFbEIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxDQUFDLElBQUksQ0FBQyxpQ0FBaUMsRUFBRTtnQkFDN0MsSUFBSSxFQUFFLFdBQVc7Z0JBQ2pCLFFBQVE7Z0JBQ1IsVUFBVTthQUNYLENBQUMsQ0FBQztZQUVILHFDQUFxQztZQUNyQyxNQUFNLFFBQVEsR0FBRyxNQUFNLFdBQVcsQ0FBQyxhQUFhLENBQzlDLFVBQVUsUUFBUSxJQUFJLFVBQVUsYUFBYSxXQUFXLEVBQUUsQ0FDM0QsQ0FBQztZQUVGLElBQUksQ0FBQyxRQUFRLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ25DLE1BQU0sSUFBSSxLQUFLLENBQUMsNkJBQTZCLFdBQVcsRUFBRSxDQUFDLENBQUM7WUFDOUQsQ0FBQztZQUVELHdCQUF3QjtZQUN4QixNQUFNLGNBQWMsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBRWpGLGlDQUFpQztZQUNqQyxNQUFNLFVBQVUsR0FBRyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUMsY0FBYyxDQUFDLENBQUM7WUFFOUQsK0JBQStCO1lBQy9CLE1BQU0sQ0FBQyxJQUFJLENB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O1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixNQUFNLENBQUMsSUFBSSxDQUFDLHNDQUFzQyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUNqRSxDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxhQUFhLENBQ2pCLFdBQWlDLEVBQ2pDLFlBQXNCLEVBQ3RCLFFBQWdCLEVBQ2hCLFVBQWtCLEVBQ2xCLFVBQXdEO1FBRXhELE1BQU0sT0FBTyxHQUFHLElBQUksR0FBRyxFQUF1QixDQUFDO1FBQy9DLElBQUksVUFBVSxHQUFHLENBQUMsQ0FBQztRQUVuQixLQUFLLE1BQU0sSUFBSSxJQUFJLFlBQVksRUFBRSxDQUFDO1lBQ2hDLElBQUksQ0FBQztnQkFDSCxNQUFNLFdBQVcsR0FBRyxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FDL0MsV0FBVyxFQUNYLElBQUksRUFDSixRQUFRLEVBQ1IsVUFBVSxDQUNYLENBQUM7Z0JBRUYsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsV0FBVyxDQUFDLENBQUM7Z0JBQy9CLFVBQVUsRUFBRSxDQUFDO2dCQUViLElBQUksVUFBVSxFQUFFLENBQUM7b0JBQ2YsVUFBVSxDQUFDLFVBQVUsRUFBRSxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7Z0JBQzlDLENBQUM7WUFDSCxDQUFDO1lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztnQkFDZixNQUFNLENBQUMsS0FBSyxDQUFDLHNCQUFzQixJQUFJLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7Z0JBQ3RELGtEQUFrRDtZQUNwRCxDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUG9ydGZvbGlvRG93bmxvYWRlciAtIERvd25sb2FkcyBlbGVtZW50cyBmcm9tIEdpdEh1YiByZXBvc2l0b3JpZXNcbiAqIFxuICogSGFuZGxlcyBmZXRjaGluZyBmaWxlIGNvbnRlbnRzIGZyb20gR2l0SHViLCBkZWNvZGluZyBiYXNlNjQgY29udGVudCxcbiAqIGFuZCByZXR1cm5pbmcgc3RydWN0dXJlZCBlbGVtZW50IGRhdGEgcmVhZHkgZm9yIGxvY2FsIHN0b3JhZ2UuXG4gKi9cblxuaW1wb3J0IHsgUG9ydGZvbGlvUmVwb01hbmFnZXIgfSBmcm9tICcuLi9wb3J0Zm9saW8vUG9ydGZvbGlvUmVwb01hbmFnZXIuanMnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCB7IFVuaWNvZGVWYWxpZGF0b3IgfSBmcm9tICcuLi9zZWN1cml0eS92YWxpZGF0b3JzL3VuaWNvZGVWYWxpZGF0b3IuanMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIEVsZW1lbnREYXRhIHtcbiAgY29udGVudDogc3RyaW5nO1xuICBtZXRhZGF0YTogUmVjb3JkPHN0cmluZywgYW55PjtcbiAgc2hhOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjbGFzcyBQb3J0Zm9saW9Eb3dubG9hZGVyIHtcbiAgLyoqXG4gICAqIERvd25sb2FkIGFuIGVsZW1lbnQgZnJvbSBHaXRIdWJcbiAgICovXG4gIGFzeW5jIGRvd25sb2FkRnJvbUdpdEh1YihcbiAgICByZXBvTWFuYWdlcjogUG9ydGZvbGlvUmVwb01hbmFnZXIsXG4gICAgZWxlbWVudFBhdGg6IHN0cmluZyxcbiAgICB1c2VybmFtZTogc3RyaW5nLFxuICAgIHJlcG9zaXRvcnk6IHN0cmluZ1xuICApOiBQcm9taXNlPEVsZW1lbnREYXRhPiB7XG4gICAgdHJ5IHtcbiAgICAgIGxvZ2dlci5pbmZvKCdEb3dubG9hZGluZyBlbGVtZW50IGZyb20gR2l0SHViJywgeyBcbiAgICAgICAgcGF0aDogZWxlbWVudFBhdGgsIFxuICAgICAgICB1c2VybmFtZSwgXG4gICAgICAgIHJlcG9zaXRvcnkgXG4gICAgICB9KTtcblxuICAgICAgLy8gRmV0Y2ggdGhlIGZpbGUgY29udGVudCBmcm9tIEdpdEh1YlxuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCByZXBvTWFuYWdlci5naXRodWJSZXF1ZXN0KFxuICAgICAgICBgL3JlcG9zLyR7dXNlcm5hbWV9LyR7cmVwb3NpdG9yeX0vY29udGVudHMvJHtlbGVtZW50UGF0aH1gXG4gICAgICApO1xuXG4gICAgICBpZiAoIXJlc3BvbnNlIHx8ICFyZXNwb25zZS5jb250ZW50KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgTm8gY29udGVudCBmb3VuZCBhdCBwYXRoOiAke2VsZW1lbnRQYXRofWApO1xuICAgICAgfVxuXG4gICAgICAvLyBEZWNvZGUgYmFzZTY0IGNvbnRlbnRcbiAgICAgIGNvbnN0IGRlY29kZWRDb250ZW50ID0gQnVmZmVyLmZyb20ocmVzcG9uc2UuY29udGVudCwgJ2Jhc2U2NCcpLnRvU3RyaW5nKCd1dGYtOCcpO1xuICAgICAgXG4gICAgICAvLyBOb3JtYWxpemUgVW5pY29kZSBmb3Igc2VjdXJpdHlcbiAgICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShkZWNvZGVkQ29udGVudCk7XG4gICAgICBcbiAgICAgIC8vIExvZyBkb3dubG9hZCBmb3IgYXVkaXQgdHJhaWxcbiAgICAgIGxvZ2dlci5pbmZvKCdFbGVtZW50IGRvd25sb2FkZWQgc3VjY2Vzc2Z1bGx5Jywge1xuICAgICAgICBwYXRoOiBlbGVtZW50UGF0aCxcbiAgICAgICAgcmVwb3NpdG9yeTogYCR7dXNlcm5hbWV9LyR7cmVwb3NpdG9yeX1gLFxuICAgICAgICBzaGE6IHJlc3BvbnNlLnNoYVxuICAgICAgfSk7XG5cbiAgICAgIC8vIFBhcnNlIG1ldGFkYXRhIGZyb20gZnJvbnRtYXR0ZXIgaWYgcHJlc2VudFxuICAgICAgY29uc3QgbWV0YWRhdGEgPSB0aGlzLmV4dHJhY3RNZXRhZGF0YShub3JtYWxpemVkLm5vcm1hbGl6ZWRDb250ZW50KTtcblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgY29udGVudDogbm9ybWFsaXplZC5ub3JtYWxpemVkQ29udGVudCxcbiAgICAgICAgbWV0YWRhdGEsXG4gICAgICAgIHNoYTogcmVzcG9uc2Uuc2hhXG4gICAgICB9O1xuICAgICAgXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ2dlci5lcnJvcignRmFpbGVkIHRvIGRvd25sb2FkIGVsZW1lbnQgZnJvbSBHaXRIdWInLCB7IFxuICAgICAgICBlcnJvciwgXG4gICAgICAgIHBhdGg6IGVsZW1lbnRQYXRoIFxuICAgICAgfSk7XG4gICAgICBcbiAgICAgIC8vIFJlLXRocm93IHdpdGggbW9yZSBjb250ZXh0XG4gICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICBpZiAoZXJyb3IubWVzc2FnZS5pbmNsdWRlcygnNDA0JykpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEVsZW1lbnQgbm90IGZvdW5kIGF0IHBhdGg6ICR7ZWxlbWVudFBhdGh9YCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGVycm9yLm1lc3NhZ2UuaW5jbHVkZXMoJzQwMScpIHx8IGVycm9yLm1lc3NhZ2UuaW5jbHVkZXMoJzQwMycpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBBdXRoZW50aWNhdGlvbiBmYWlsZWQuIFBsZWFzZSBjaGVjayB5b3VyIEdpdEh1YiB0b2tlbi5gKTtcbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gZG93bmxvYWQgJHtlbGVtZW50UGF0aH06ICR7U3RyaW5nKGVycm9yKX1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRXh0cmFjdCBtZXRhZGF0YSBmcm9tIGZyb250bWF0dGVyXG4gICAqL1xuICBwcml2YXRlIGV4dHJhY3RNZXRhZGF0YShjb250ZW50OiBzdHJpbmcpOiBSZWNvcmQ8c3RyaW5nLCBhbnk+IHtcbiAgICBjb25zdCBtZXRhZGF0YTogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICAgIFxuICAgIC8vIENoZWNrIGZvciBZQU1MIGZyb250bWF0dGVyXG4gICAgY29uc3QgZnJvbnRtYXR0ZXJNYXRjaCA9IGNvbnRlbnQubWF0Y2goL14tLS1cXG4oW1xcc1xcU10qPylcXG4tLS0vKTtcbiAgICBcbiAgICBpZiAoZnJvbnRtYXR0ZXJNYXRjaCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gUGFyc2UgdGhlIGZyb250bWF0dGVyIGFzIHNpbXBsZSBrZXktdmFsdWUgcGFpcnNcbiAgICAgICAgLy8gKGF2b2lkaW5nIHVzaW5nIHlhbWwubG9hZCBmb3Igc2VjdXJpdHkpXG4gICAgICAgIGNvbnN0IGZyb250bWF0dGVyQ29udGVudCA9IGZyb250bWF0dGVyTWF0Y2hbMV07XG4gICAgICAgIGNvbnN0IGxpbmVzID0gZnJvbnRtYXR0ZXJDb250ZW50LnNwbGl0KCdcXG4nKTtcbiAgICAgICAgXG4gICAgICAgIGZvciAoY29uc3QgbGluZSBvZiBsaW5lcykge1xuICAgICAgICAgIGNvbnN0IGNvbG9uSW5kZXggPSBsaW5lLmluZGV4T2YoJzonKTtcbiAgICAgICAgICBpZiAoY29sb25JbmRleCA+IDApIHtcbiAgICAgICAgICAgIGNvbnN0IGtleSA9IGxpbmUuc3Vic3RyaW5nKDAsIGNvbG9uSW5kZXgpLnRyaW0oKTtcbiAgICAgICAgICAgIGNvbnN0IHZhbHVlID0gbGluZS5zdWJzdHJpbmcoY29sb25JbmRleCArIDEpLnRyaW0oKTtcbiAgICAgICAgICAgIFxuICAgICAgICAgICAgLy8gUmVtb3ZlIHF1b3RlcyBpZiBwcmVzZW50XG4gICAgICAgICAgICBjb25zdCBjbGVhblZhbHVlID0gdmFsdWUucmVwbGFjZSgvXltcIiddfFtcIiddJC9nLCAnJyk7XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIC8vIFRyeSB0byBwYXJzZSBhcyBKU09OIGZvciBhcnJheXMvb2JqZWN0cywgb3RoZXJ3aXNlIHVzZSBhcyBzdHJpbmdcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgIG1ldGFkYXRhW2tleV0gPSBKU09OLnBhcnNlKGNsZWFuVmFsdWUpO1xuICAgICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAgIG1ldGFkYXRhW2tleV0gPSBjbGVhblZhbHVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nZ2VyLndhcm4oJ0ZhaWxlZCB0byBwYXJzZSBmcm9udG1hdHRlciBtZXRhZGF0YScsIHsgZXJyb3IgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIHJldHVybiBtZXRhZGF0YTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEb3dubG9hZCBtdWx0aXBsZSBlbGVtZW50cyBpbiBiYXRjaFxuICAgKi9cbiAgYXN5bmMgZG93bmxvYWRCYXRjaChcbiAgICByZXBvTWFuYWdlcjogUG9ydGZvbGlvUmVwb01hbmFnZXIsXG4gICAgZWxlbWVudFBhdGhzOiBzdHJpbmdbXSxcbiAgICB1c2VybmFtZTogc3RyaW5nLFxuICAgIHJlcG9zaXRvcnk6IHN0cmluZyxcbiAgICBvblByb2dyZXNzPzogKGRvd25sb2FkZWQ6IG51bWJlciwgdG90YWw6IG51bWJlcikgPT4gdm9pZFxuICApOiBQcm9taXNlPE1hcDxzdHJpbmcsIEVsZW1lbnREYXRhPj4ge1xuICAgIGNvbnN0IHJlc3VsdHMgPSBuZXcgTWFwPHN0cmluZywgRWxlbWVudERhdGE+KCk7XG4gICAgbGV0IGRvd25sb2FkZWQgPSAwO1xuICAgIFxuICAgIGZvciAoY29uc3QgcGF0aCBvZiBlbGVtZW50UGF0aHMpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGVsZW1lbnREYXRhID0gYXdhaXQgdGhpcy5kb3dubG9hZEZyb21HaXRIdWIoXG4gICAgICAgICAgcmVwb01hbmFnZXIsXG4gICAgICAgICAgcGF0aCxcbiAgICAgICAgICB1c2VybmFtZSxcbiAgICAgICAgICByZXBvc2l0b3J5XG4gICAgICAgICk7XG4gICAgICAgIFxuICAgICAgICByZXN1bHRzLnNldChwYXRoLCBlbGVtZW50RGF0YSk7XG4gICAgICAgIGRvd25sb2FkZWQrKztcbiAgICAgICAgXG4gICAgICAgIGlmIChvblByb2dyZXNzKSB7XG4gICAgICAgICAgb25Qcm9ncmVzcyhkb3dubG9hZGVkLCBlbGVtZW50UGF0aHMubGVuZ3RoKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nZ2VyLmVycm9yKGBGYWlsZWQgdG8gZG93bmxvYWQgJHtwYXRofWAsIHsgZXJyb3IgfSk7XG4gICAgICAgIC8vIENvbnRpbnVlIHdpdGggb3RoZXIgZG93bmxvYWRzIGV2ZW4gaWYgb25lIGZhaWxzXG4gICAgICB9XG4gICAgfVxuICAgIFxuICAgIHJldHVybiByZXN1bHRzO1xuICB9XG59Il19
@@ -0,0 +1,50 @@
1
+ /**
2
+ * PortfolioSyncComparer - Compares local and GitHub portfolio elements
3
+ *
4
+ * Determines what actions need to be taken based on the sync mode:
5
+ * - additive: Only add missing elements
6
+ * - mirror: Make local exactly match GitHub
7
+ * - backup: Treat GitHub as authoritative source
8
+ */
9
+ import { ElementType } from '../portfolio/types.js';
10
+ import { GitHubIndexEntry } from '../portfolio/GitHubPortfolioIndexer.js';
11
+ export type SyncMode = 'additive' | 'mirror' | 'backup';
12
+ export interface SyncAction {
13
+ type: ElementType;
14
+ name: string;
15
+ path: string;
16
+ action: 'add' | 'update' | 'delete' | 'skip';
17
+ reason?: string;
18
+ localSha?: string;
19
+ remoteSha?: string;
20
+ }
21
+ export interface SyncActions {
22
+ toAdd: SyncAction[];
23
+ toUpdate: SyncAction[];
24
+ toDelete: SyncAction[];
25
+ toSkip: SyncAction[];
26
+ }
27
+ export declare class PortfolioSyncComparer {
28
+ /**
29
+ * Compare GitHub and local elements to determine sync actions
30
+ */
31
+ compareElements(githubElements: Map<ElementType, GitHubIndexEntry[]>, localElements: Map<ElementType, any[]>, mode: SyncMode): SyncActions;
32
+ /**
33
+ * Compare elements of a specific type
34
+ */
35
+ private compareTypeElements;
36
+ /**
37
+ * Determine if an element should be updated
38
+ */
39
+ private shouldUpdate;
40
+ /**
41
+ * Normalize element name for comparison
42
+ * Handles different naming formats and extensions
43
+ */
44
+ private normalizeElementName;
45
+ /**
46
+ * Count total elements in a map
47
+ */
48
+ private countElements;
49
+ }
50
+ //# sourceMappingURL=PortfolioSyncComparer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PortfolioSyncComparer.d.ts","sourceRoot":"","sources":["../../src/sync/PortfolioSyncComparer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAG1E,MAAM,MAAM,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAExD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC7C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,qBAAa,qBAAqB;IAChC;;OAEG;IACH,eAAe,CACb,cAAc,EAAE,GAAG,CAAC,WAAW,EAAE,gBAAgB,EAAE,CAAC,EACpD,aAAa,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,EACtC,IAAI,EAAE,QAAQ,GACb,WAAW;IA2Cd;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAuE3B;;OAEG;IACH,OAAO,CAAC,YAAY;IAgCpB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAe5B;;OAEG;IACH,OAAO,CAAC,aAAa;CAOtB"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * PortfolioSyncComparer - Compares local and GitHub portfolio elements
3
+ *
4
+ * Determines what actions need to be taken based on the sync mode:
5
+ * - additive: Only add missing elements
6
+ * - mirror: Make local exactly match GitHub
7
+ * - backup: Treat GitHub as authoritative source
8
+ */
9
+ import { logger } from '../utils/logger.js';
10
+ export class PortfolioSyncComparer {
11
+ /**
12
+ * Compare GitHub and local elements to determine sync actions
13
+ */
14
+ compareElements(githubElements, localElements, mode) {
15
+ const actions = {
16
+ toAdd: [],
17
+ toUpdate: [],
18
+ toDelete: [],
19
+ toSkip: []
20
+ };
21
+ logger.info('Comparing elements', {
22
+ githubCount: this.countElements(githubElements),
23
+ localCount: this.countElements(localElements),
24
+ mode
25
+ });
26
+ // Process each element type
27
+ const allTypes = new Set([
28
+ ...githubElements.keys(),
29
+ ...localElements.keys()
30
+ ]);
31
+ for (const type of allTypes) {
32
+ const githubTypeElements = githubElements.get(type) || [];
33
+ const localTypeElements = localElements.get(type) || [];
34
+ this.compareTypeElements(type, githubTypeElements, localTypeElements, mode, actions);
35
+ }
36
+ logger.info('Comparison complete', {
37
+ toAdd: actions.toAdd.length,
38
+ toUpdate: actions.toUpdate.length,
39
+ toDelete: actions.toDelete.length,
40
+ toSkip: actions.toSkip.length
41
+ });
42
+ return actions;
43
+ }
44
+ /**
45
+ * Compare elements of a specific type
46
+ */
47
+ compareTypeElements(type, githubElements, localElements, mode, actions) {
48
+ // Create maps for efficient lookup
49
+ const githubMap = new Map(githubElements.map(e => [this.normalizeElementName(e.name), e]));
50
+ const localMap = new Map(localElements.map(e => [this.normalizeElementName(e.name || e.metadata?.name), e]));
51
+ // Process GitHub elements (additions and updates)
52
+ for (const [name, githubElement] of githubMap) {
53
+ const localElement = localMap.get(name);
54
+ if (!localElement) {
55
+ // Element exists on GitHub but not locally
56
+ actions.toAdd.push({
57
+ type,
58
+ name: githubElement.name,
59
+ path: githubElement.path,
60
+ action: 'add',
61
+ remoteSha: githubElement.sha
62
+ });
63
+ }
64
+ else if (mode === 'backup' || this.shouldUpdate(githubElement, localElement, mode)) {
65
+ // Element needs updating
66
+ actions.toUpdate.push({
67
+ type,
68
+ name: githubElement.name,
69
+ path: githubElement.path,
70
+ action: 'update',
71
+ reason: mode === 'backup' ? 'backup mode' : 'newer on GitHub',
72
+ localSha: localElement.sha,
73
+ remoteSha: githubElement.sha
74
+ });
75
+ }
76
+ else {
77
+ // Element is up to date or should be skipped
78
+ actions.toSkip.push({
79
+ type,
80
+ name: githubElement.name,
81
+ path: githubElement.path,
82
+ action: 'skip',
83
+ reason: 'up to date',
84
+ localSha: localElement.sha,
85
+ remoteSha: githubElement.sha
86
+ });
87
+ }
88
+ }
89
+ // Process local elements (deletions - only in mirror mode)
90
+ if (mode === 'mirror') {
91
+ for (const [name, localElement] of localMap) {
92
+ if (!githubMap.has(name)) {
93
+ // Element exists locally but not on GitHub
94
+ actions.toDelete.push({
95
+ type,
96
+ name: localElement.name || localElement.metadata?.name || name,
97
+ path: `${type}/${name}.md`,
98
+ action: 'delete',
99
+ reason: 'not on GitHub',
100
+ localSha: localElement.sha
101
+ });
102
+ }
103
+ }
104
+ }
105
+ }
106
+ /**
107
+ * Determine if an element should be updated
108
+ */
109
+ shouldUpdate(githubElement, localElement, mode) {
110
+ // In backup mode, always update from GitHub
111
+ if (mode === 'backup') {
112
+ return true;
113
+ }
114
+ // In additive mode, never update existing elements
115
+ if (mode === 'additive') {
116
+ return false;
117
+ }
118
+ // In mirror mode, update if SHAs differ
119
+ // If we don't have SHAs, compare modified dates
120
+ if (githubElement.sha && localElement.sha) {
121
+ return githubElement.sha !== localElement.sha;
122
+ }
123
+ // Compare modified dates if available
124
+ if (githubElement.lastModified && localElement.lastModified) {
125
+ const githubDate = new Date(githubElement.lastModified).getTime();
126
+ const localDate = new Date(localElement.lastModified).getTime();
127
+ return githubDate > localDate;
128
+ }
129
+ // If we can't determine, skip updating in mirror mode
130
+ return false;
131
+ }
132
+ /**
133
+ * Normalize element name for comparison
134
+ * Handles different naming formats and extensions
135
+ */
136
+ normalizeElementName(name) {
137
+ if (!name)
138
+ return '';
139
+ // Remove .md extension if present
140
+ let normalized = name.replace(/\.md$/i, '');
141
+ // Convert to lowercase for comparison
142
+ normalized = normalized.toLowerCase();
143
+ // Replace spaces with hyphens (some systems use different formats)
144
+ normalized = normalized.replace(/\s+/g, '-');
145
+ return normalized;
146
+ }
147
+ /**
148
+ * Count total elements in a map
149
+ */
150
+ countElements(elements) {
151
+ let count = 0;
152
+ for (const typeElements of elements.values()) {
153
+ count += typeElements.length;
154
+ }
155
+ return count;
156
+ }
157
+ }
158
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUG9ydGZvbGlvU3luY0NvbXBhcmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N5bmMvUG9ydGZvbGlvU3luY0NvbXBhcmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7O0dBT0c7QUFJSCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFxQjVDLE1BQU0sT0FBTyxxQkFBcUI7SUFDaEM7O09BRUc7SUFDSCxlQUFlLENBQ2IsY0FBb0QsRUFDcEQsYUFBc0MsRUFDdEMsSUFBYztRQUVkLE1BQU0sT0FBTyxHQUFnQjtZQUMzQixLQUFLLEVBQUUsRUFBRTtZQUNULFFBQVEsRUFBRSxFQUFFO1lBQ1osUUFBUSxFQUFFLEVBQUU7WUFDWixNQUFNLEVBQUUsRUFBRTtTQUNYLENBQUM7UUFFRixNQUFNLENBQUMsSUFBSSxDQUFDLG9CQUFvQixFQUFFO1lBQ2hDLFdBQVcsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBQztZQUMvQyxVQUFVLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxhQUFhLENBQUM7WUFDN0MsSUFBSTtTQUNMLENBQUMsQ0FBQztRQUVILDRCQUE0QjtRQUM1QixNQUFNLFFBQVEsR0FBRyxJQUFJLEdBQUcsQ0FBQztZQUN2QixHQUFHLGNBQWMsQ0FBQyxJQUFJLEVBQUU7WUFDeEIsR0FBRyxhQUFhLENBQUMsSUFBSSxFQUFFO1NBQ3hCLENBQUMsQ0FBQztRQUVILEtBQUssTUFBTSxJQUFJLElBQUksUUFBUSxFQUFFLENBQUM7WUFDNUIsTUFBTSxrQkFBa0IsR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUMxRCxNQUFNLGlCQUFpQixHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBRXhELElBQUksQ0FBQyxtQkFBbUIsQ0FDdEIsSUFBSSxFQUNKLGtCQUFrQixFQUNsQixp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SUFBSSxJQUFJLENBQUMsYUFBYSxDQUFDLFlBQVksQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2xFLE1BQU0sU0FBUyxHQUFHLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNoRSxPQUFPLFVBQVUsR0FBRyxTQUFTLENBQUM7UUFDaEMsQ0FBQztRQUVELHNEQUFzRDtRQUN0RCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRDs7O09BR0c7SUFDSyxvQkFBb0IsQ0FBQyxJQUFZO1FBQ3ZDLElBQUksQ0FBQyxJQUFJO1lBQUUsT0FBTyxFQUFFLENBQUM7UUFFckIsa0NBQWtDO1FBQ2xDLElBQUksVUFBVSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRTVDLHNDQUFzQztRQUN0QyxVQUFVLEdBQUcsVUFBVSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBRXRDLG1FQUFtRTtRQUNuRSxVQUFVLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFFN0MsT0FBTyxVQUFVLENBQUM7SUFDcEIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssYUFBYSxDQUFDLFFBQWlDO1FBQ3JELElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztRQUNkLEtBQUssTUFBTSxZQUFZLElBQUksUUFBUSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7WUFDN0MsS0FBSyxJQUFJLFlBQVksQ0FBQyxNQUFNLENBQUM7UUFDL0IsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBQb3J0Zm9saW9TeW5jQ29tcGFyZXIgLSBDb21wYXJlcyBsb2NhbCBhbmQgR2l0SHViIHBvcnRmb2xpbyBlbGVtZW50c1xuICogXG4gKiBEZXRlcm1pbmVzIHdoYXQgYWN0aW9ucyBuZWVkIHRvIGJlIHRha2VuIGJhc2VkIG9uIHRoZSBzeW5jIG1vZGU6XG4gKiAtIGFkZGl0aXZlOiBPbmx5IGFkZCBtaXNzaW5nIGVsZW1lbnRzXG4gKiAtIG1pcnJvcjogTWFrZSBsb2NhbCBleGFjdGx5IG1hdGNoIEdpdEh1YlxuICogLSBiYWNrdXA6IFRyZWF0IEdpdEh1YiBhcyBhdXRob3JpdGF0aXZlIHNvdXJjZVxuICovXG5cbmltcG9ydCB7IEVsZW1lbnRUeXBlIH0gZnJvbSAnLi4vcG9ydGZvbGlvL3R5cGVzLmpzJztcbmltcG9ydCB7IEdpdEh1YkluZGV4RW50cnkgfSBmcm9tICcuLi9wb3J0Zm9saW8vR2l0SHViUG9ydGZvbGlvSW5kZXhlci5qcyc7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXIuanMnO1xuXG5leHBvcnQgdHlwZSBTeW5jTW9kZSA9ICdhZGRpdGl2ZScgfCAnbWlycm9yJyB8ICdiYWNrdXAnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFN5bmNBY3Rpb24ge1xuICB0eXBlOiBFbGVtZW50VHlwZTtcbiAgbmFtZTogc3RyaW5nO1xuICBwYXRoOiBzdHJpbmc7XG4gIGFjdGlvbjogJ2FkZCcgfCAndXBkYXRlJyB8ICdkZWxldGUnIHwgJ3NraXAnO1xuICByZWFzb24/OiBzdHJpbmc7XG4gIGxvY2FsU2hhPzogc3RyaW5nO1xuICByZW1vdGVTaGE/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3luY0FjdGlvbnMge1xuICB0b0FkZDogU3luY0FjdGlvbltdO1xuICB0b1VwZGF0ZTogU3luY0FjdGlvbltdO1xuICB0b0RlbGV0ZTogU3luY0FjdGlvbltdO1xuICB0b1NraXA6IFN5bmNBY3Rpb25bXTtcbn1cblxuZXhwb3J0IGNsYXNzIFBvcnRmb2xpb1N5bmNDb21wYXJlciB7XG4gIC8qKlxuICAgKiBDb21wYXJlIEdpdEh1YiBhbmQgbG9jYWwgZWxlbWVudHMgdG8gZGV0ZXJtaW5lIHN5bmMgYWN0aW9uc1xuICAgKi9cbiAgY29tcGFyZUVsZW1lbnRzKFxuICAgIGdpdGh1YkVsZW1lbnRzOiBNYXA8RWxlbWVudFR5cGUsIEdpdEh1YkluZGV4RW50cnlbXT4sXG4gICAgbG9jYWxFbGVtZW50czogTWFwPEVsZW1lbnRUeXBlLCBhbnlbXT4sXG4gICAgbW9kZTogU3luY01vZGVcbiAgKTogU3luY0FjdGlvbnMge1xuICAgIGNvbnN0IGFjdGlvbnM6IFN5bmNBY3Rpb25zID0ge1xuICAgICAgdG9BZGQ6IFtdLFxuICAgICAgdG9VcGRhdGU6IFtdLFxuICAgICAgdG9EZWxldGU6IFtdLFxuICAgICAgdG9Ta2lwOiBbXVxuICAgIH07XG5cbiAgICBsb2dnZXIuaW5mbygnQ29tcGFyaW5nIGVsZW1lbnRzJywgeyBcbiAgICAgIGdpdGh1YkNvdW50OiB0aGlzLmNvdW50RWxlbWVudHMoZ2l0aHViRWxlbWVudHMpLFxuICAgICAgbG9jYWxDb3VudDogdGhpcy5jb3VudEVsZW1lbnRzKGxvY2FsRWxlbWVudHMpLFxuICAgICAgbW9kZSBcbiAgICB9KTtcblxuICAgIC8vIFByb2Nlc3MgZWFjaCBlbGVtZW50IHR5cGVcbiAgICBjb25zdCBhbGxUeXBlcyA9IG5ldyBTZXQoW1xuICAgICAgLi4uZ2l0aHViRWxlbWVudHMua2V5cygpLFxuICAgICAgLi4ubG9jYWxFbGVtZW50cy5rZXlzKClcbiAgICBdKTtcblxuICAgIGZvciAoY29uc3QgdHlwZSBvZiBhbGxUeXBlcykge1xuICAgICAgY29uc3QgZ2l0aHViVHlwZUVsZW1lbnRzID0gZ2l0aHViRWxlbWVudHMuZ2V0KHR5cGUpIHx8IFtdO1xuICAgICAgY29uc3QgbG9jYWxUeXBlRWxlbWVudHMgPSBsb2NhbEVsZW1lbnRzLmdldCh0eXBlKSB8fCBbXTtcbiAgICAgIFxuICAgICAgdGhpcy5jb21wYXJlVHlwZUVsZW1lbnRzKFxuICAgICAgICB0eXBlLFxuICAgICAgICBnaXRodWJUeXBlRWxlbWVudHMsXG4gICAgICAgIGxvY2FsVHlwZUVsZW1lbnRzLFxuICAgICAgICBtb2RlLFxuICAgICAgICBhY3Rpb25zXG4gICAgICApO1xuICAgIH1cblxuICAgIGxvZ2dlci5pbmZvKCdDb21wYXJpc29uIGNvbXBsZXRlJywge1xuICAgICAgdG9BZGQ6IGFjdGlvbnMudG9BZGQubGVuZ3RoLFxuICAgICAgdG9VcGRhdGU6IGFjdGlvbnMudG9VcGRhdGUubGVuZ3RoLFxuICAgICAgdG9EZWxldGU6IGFjdGlvbnMudG9EZWxldGUubGVuZ3RoLFxuICAgICAgdG9Ta2lwOiBhY3Rpb25zLnRvU2tpcC5sZW5ndGhcbiAgICB9KTtcblxuICAgIHJldHVybiBhY3Rpb25zO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbXBhcmUgZWxlbWVudHMgb2YgYSBzcGVjaWZpYyB0eXBlXG4gICAqL1xuICBwcml2YXRlIGNvbXBhcmVUeXBlRWxlbWVudHMoXG4gICAgdHlwZTogRWxlbWVudFR5cGUsXG4gICAgZ2l0aHViRWxlbWVudHM6IEdpdEh1YkluZGV4RW50cnlbXSxcbiAgICBsb2NhbEVsZW1lbnRzOiBhbnlbXSxcbiAgICBtb2RlOiBTeW5jTW9kZSxcbiAgICBhY3Rpb25zOiBTeW5jQWN0aW9uc1xuICApOiB2b2lkIHtcbiAgICAvLyBDcmVhdGUgbWFwcyBmb3IgZWZmaWNpZW50IGxvb2t1cFxuICAgIGNvbnN0IGdpdGh1Yk1hcCA9IG5ldyBNYXAoXG4gICAgICBnaXRodWJFbGVtZW50cy5tYXAoZSA9PiBbdGhpcy5ub3JtYWxpemVFbGVtZW50TmFtZShlLm5hbWUpLCBlXSlcbiAgICApO1xuICAgIGNvbnN0IGxvY2FsTWFwID0gbmV3IE1hcChcbiAgICAgIGxvY2FsRWxlbWVudHMubWFwKGUgPT4gW3RoaXMubm9ybWFsaXplRWxlbWVudE5hbWUoZS5uYW1lIHx8IGUubWV0YWRhdGE/Lm5hbWUpLCBlXSlcbiAgICApO1xuXG4gICAgLy8gUHJvY2VzcyBHaXRIdWIgZWxlbWVudHMgKGFkZGl0aW9ucyBhbmQgdXBkYXRlcylcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBnaXRodWJFbGVtZW50XSBvZiBnaXRodWJNYXApIHtcbiAgICAgIGNvbnN0IGxvY2FsRWxlbWVudCA9IGxvY2FsTWFwLmdldChuYW1lKTtcbiAgICAgIFxuICAgICAgaWYgKCFsb2NhbEVsZW1lbnQpIHtcbiAgICAgICAgLy8gRWxlbWVudCBleGlzdHMgb24gR2l0SHViIGJ1dCBub3QgbG9jYWxseVxuICAgICAgICBhY3Rpb25zLnRvQWRkLnB1c2goe1xuICAgICAgICAgIHR5cGUsXG4gICAgICAgICAgbmFtZTogZ2l0aHViRWxlbWVudC5uYW1lLFxuICAgICAgICAgIHBhdGg6IGdpdGh1YkVsZW1lbnQucGF0aCxcbiAgICAgICAgICBhY3Rpb246ICdhZGQnLFxuICAgICAgICAgIHJlbW90ZVNoYTogZ2l0aHViRWxlbWVudC5zaGFcbiAgICAgICAgfSk7XG4gICAgICB9IGVsc2UgaWYgKG1vZGUgPT09ICdiYWNrdXAnIHx8IHRoaXMuc2hvdWxkVXBkYXRlKGdpdGh1YkVsZW1lbnQsIGxvY2FsRWxlbWVudCwgbW9kZSkpIHtcbiAgICAgICAgLy8gRWxlbWVudCBuZWVkcyB1cGRhdGluZ1xuICAgICAgICBhY3Rpb25zLnRvVXBkYXRlLnB1c2goe1xuICAgICAgICAgIHR5cGUsXG4gICAgICAgICAgbmFtZTogZ2l0aHViRWxlbWVudC5uYW1lLFxuICAgICAgICAgIHBhdGg6IGdpdGh1YkVsZW1lbnQucGF0aCxcbiAgICAgICAgICBhY3Rpb246ICd1cGRhdGUnLFxuICAgICAgICAgIHJlYXNvbjogbW9kZSA9PT0gJ2JhY2t1cCcgPyAnYmFja3VwIG1vZGUnIDogJ25ld2VyIG9uIEdpdEh1YicsXG4gICAgICAgICAgbG9jYWxTaGE6IGxvY2FsRWxlbWVudC5zaGEsXG4gICAgICAgICAgcmVtb3RlU2hhOiBnaXRodWJFbGVtZW50LnNoYVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIEVsZW1lbnQgaXMgdXAgdG8gZGF0ZSBvciBzaG91bGQgYmUgc2tpcHBlZFxuICAgICAgICBhY3Rpb25zLnRvU2tpcC5wdXNoKHtcbiAgICAgICAgICB0eXBlLFxuICAgICAgICAgIG5hbWU6IGdpdGh1YkVsZW1lbnQubmFtZSxcbiAgICAgICAgICBwYXRoOiBnaXRodWJFbGVtZW50LnBhdGgsXG4gICAgICAgICAgYWN0aW9uOiAnc2tpcCcsXG4gICAgICAgICAgcmVhc29uOiAndXAgdG8gZGF0ZScsXG4gICAgICAgICAgbG9jYWxTaGE6IGxvY2FsRWxlbWVudC5zaGEsXG4gICAgICAgICAgcmVtb3RlU2hhOiBnaXRodWJFbGVtZW50LnNoYVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBQcm9jZXNzIGxvY2FsIGVsZW1lbnRzIChkZWxldGlvbnMgLSBvbmx5IGluIG1pcnJvciBtb2RlKVxuICAgIGlmIChtb2RlID09PSAnbWlycm9yJykge1xuICAgICAgZm9yIChjb25zdCBbbmFtZSwgbG9jYWxFbGVtZW50XSBvZiBsb2NhbE1hcCkge1xuICAgICAgICBpZiAoIWdpdGh1Yk1hcC5oYXMobmFtZSkpIHtcbiAgICAgICAgICAvLyBFbGVtZW50IGV4aXN0cyBsb2NhbGx5IGJ1dCBub3Qgb24gR2l0SHViXG4gICAgICAgICAgYWN0aW9ucy50b0RlbGV0ZS5wdXNoKHtcbiAgICAgICAgICAgIHR5cGUsXG4gICAgICAgICAgICBuYW1lOiBsb2NhbEVsZW1lbnQubmFtZSB8fCBsb2NhbEVsZW1lbnQubWV0YWRhdGE/Lm5hbWUgfHwgbmFtZSxcbiAgICAgICAgICAgIHBhdGg6IGAke3R5cGV9LyR7bmFtZX0ubWRgLFxuICAgICAgICAgICAgYWN0aW9uOiAnZGVsZXRlJyxcbiAgICAgICAgICAgIHJlYXNvbjogJ25vdCBvbiBHaXRIdWInLFxuICAgICAgICAgICAgbG9jYWxTaGE6IGxvY2FsRWxlbWVudC5zaGFcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEZXRlcm1pbmUgaWYgYW4gZWxlbWVudCBzaG91bGQgYmUgdXBkYXRlZFxuICAgKi9cbiAgcHJpdmF0ZSBzaG91bGRVcGRhdGUoXG4gICAgZ2l0aHViRWxlbWVudDogR2l0SHViSW5kZXhFbnRyeSxcbiAgICBsb2NhbEVsZW1lbnQ6IGFueSxcbiAgICBtb2RlOiBTeW5jTW9kZVxuICApOiBib29sZWFuIHtcbiAgICAvLyBJbiBiYWNrdXAgbW9kZSwgYWx3YXlzIHVwZGF0ZSBmcm9tIEdpdEh1YlxuICAgIGlmIChtb2RlID09PSAnYmFja3VwJykge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgLy8gSW4gYWRkaXRpdmUgbW9kZSwgbmV2ZXIgdXBkYXRlIGV4aXN0aW5nIGVsZW1lbnRzXG4gICAgaWYgKG1vZGUgPT09ICdhZGRpdGl2ZScpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBJbiBtaXJyb3IgbW9kZSwgdXBkYXRlIGlmIFNIQXMgZGlmZmVyXG4gICAgLy8gSWYgd2UgZG9uJ3QgaGF2ZSBTSEFzLCBjb21wYXJlIG1vZGlmaWVkIGRhdGVzXG4gICAgaWYgKGdpdGh1YkVsZW1lbnQuc2hhICYmIGxvY2FsRWxlbWVudC5zaGEpIHtcbiAgICAgIHJldHVybiBnaXRodWJFbGVtZW50LnNoYSAhPT0gbG9jYWxFbGVtZW50LnNoYTtcbiAgICB9XG5cbiAgICAvLyBDb21wYXJlIG1vZGlmaWVkIGRhdGVzIGlmIGF2YWlsYWJsZVxuICAgIGlmIChnaXRodWJFbGVtZW50Lmxhc3RNb2RpZmllZCAmJiBsb2NhbEVsZW1lbnQubGFzdE1vZGlmaWVkKSB7XG4gICAgICBjb25zdCBnaXRodWJEYXRlID0gbmV3IERhdGUoZ2l0aHViRWxlbWVudC5sYXN0TW9kaWZpZWQpLmdldFRpbWUoKTtcbiAgICAgIGNvbnN0IGxvY2FsRGF0ZSA9IG5ldyBEYXRlKGxvY2FsRWxlbWVudC5sYXN0TW9kaWZpZWQpLmdldFRpbWUoKTtcbiAgICAgIHJldHVybiBnaXRodWJEYXRlID4gbG9jYWxEYXRlO1xuICAgIH1cblxuICAgIC8vIElmIHdlIGNhbid0IGRldGVybWluZSwgc2tpcCB1cGRhdGluZyBpbiBtaXJyb3IgbW9kZVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBOb3JtYWxpemUgZWxlbWVudCBuYW1lIGZvciBjb21wYXJpc29uXG4gICAqIEhhbmRsZXMgZGlmZmVyZW50IG5hbWluZyBmb3JtYXRzIGFuZCBleHRlbnNpb25zXG4gICAqL1xuICBwcml2YXRlIG5vcm1hbGl6ZUVsZW1lbnROYW1lKG5hbWU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgaWYgKCFuYW1lKSByZXR1cm4gJyc7XG4gICAgXG4gICAgLy8gUmVtb3ZlIC5tZCBleHRlbnNpb24gaWYgcHJlc2VudFxuICAgIGxldCBub3JtYWxpemVkID0gbmFtZS5yZXBsYWNlKC9cXC5tZCQvaSwgJycpO1xuICAgIFxuICAgIC8vIENvbnZlcnQgdG8gbG93ZXJjYXNlIGZvciBjb21wYXJpc29uXG4gICAgbm9ybWFsaXplZCA9IG5vcm1hbGl6ZWQudG9Mb3dlckNhc2UoKTtcbiAgICBcbiAgICAvLyBSZXBsYWNlIHNwYWNlcyB3aXRoIGh5cGhlbnMgKHNvbWUgc3lzdGVtcyB1c2UgZGlmZmVyZW50IGZvcm1hdHMpXG4gICAgbm9ybWFsaXplZCA9IG5vcm1hbGl6ZWQucmVwbGFjZSgvXFxzKy9nLCAnLScpO1xuICAgIFxuICAgIHJldHVybiBub3JtYWxpemVkO1xuICB9XG5cbiAgLyoqXG4gICAqIENvdW50IHRvdGFsIGVsZW1lbnRzIGluIGEgbWFwXG4gICAqL1xuICBwcml2YXRlIGNvdW50RWxlbWVudHMoZWxlbWVudHM6IE1hcDxFbGVtZW50VHlwZSwgYW55W10+KTogbnVtYmVyIHtcbiAgICBsZXQgY291bnQgPSAwO1xuICAgIGZvciAoY29uc3QgdHlwZUVsZW1lbnRzIG9mIGVsZW1lbnRzLnZhbHVlcygpKSB7XG4gICAgICBjb3VudCArPSB0eXBlRWxlbWVudHMubGVuZ3RoO1xuICAgIH1cbiAgICByZXR1cm4gY291bnQ7XG4gIH1cbn0iXX0=
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Get Welcome Message Tool
3
+ *
4
+ * A dedicated MCP tool that returns the welcome message
5
+ * This gives us more control over how the message is presented
6
+ */
7
+ export interface GetWelcomeMessageOptions {
8
+ format?: 'text' | 'markdown' | 'raw';
9
+ skipCheck?: boolean;
10
+ }
11
+ export declare class GetWelcomeMessageTool {
12
+ private configManager;
13
+ constructor();
14
+ /**
15
+ * Get the welcome message directly as a tool response
16
+ * This bypasses the response wrapping and gives us full control
17
+ */
18
+ execute(options?: GetWelcomeMessageOptions): Promise<any>;
19
+ /**
20
+ * Tool definition for MCP
21
+ */
22
+ static get definition(): {
23
+ name: string;
24
+ description: string;
25
+ inputSchema: {
26
+ type: string;
27
+ properties: {
28
+ format: {
29
+ type: string;
30
+ enum: string[];
31
+ description: string;
32
+ };
33
+ skipCheck: {
34
+ type: string;
35
+ description: string;
36
+ };
37
+ };
38
+ };
39
+ };
40
+ }
41
+ //# sourceMappingURL=getWelcomeMessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getWelcomeMessage.d.ts","sourceRoot":"","sources":["../../src/tools/getWelcomeMessage.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,KAAK,CAAC;IACrC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,qBAAa,qBAAqB;IAChC,OAAO,CAAC,aAAa,CAAgB;;IAMrC;;;OAGG;IACG,OAAO,CAAC,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,GAAG,CAAC;IAsEnE;;OAEG;IACH,MAAM,KAAK,UAAU;;;;;;;;;;;;;;;;;MAmBpB;CACF"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Get Welcome Message Tool
3
+ *
4
+ * A dedicated MCP tool that returns the welcome message
5
+ * This gives us more control over how the message is presented
6
+ */
7
+ import { ConfigManager } from '../config/ConfigManager.js';
8
+ export class GetWelcomeMessageTool {
9
+ configManager;
10
+ constructor() {
11
+ this.configManager = ConfigManager.getInstance();
12
+ }
13
+ /**
14
+ * Get the welcome message directly as a tool response
15
+ * This bypasses the response wrapping and gives us full control
16
+ */
17
+ async execute(options = {}) {
18
+ await this.configManager.initialize();
19
+ const config = this.configManager.getConfig();
20
+ // Check if we should show the welcome message
21
+ if (!options.skipCheck) {
22
+ if (config.wizard?.completed || config.wizard?.dismissed) {
23
+ return {
24
+ content: [{
25
+ type: "text",
26
+ text: "Welcome back to DollhouseMCP! The wizard has already been completed. Use 'Open configuration wizard' if you want to reconfigure."
27
+ }]
28
+ };
29
+ }
30
+ }
31
+ const welcomeMessage = `🎨 **Welcome to DollhouseMCP!**
32
+
33
+ Hi there! I see this is your first time here. DollhouseMCP helps you create powerful customization elements for your AI assistant - and it's easier than you might think!
34
+
35
+ **What can you do with DollhouseMCP?**
36
+
37
+ 🎭 **Personas** - Change your AI's personality (make it funny, professional, creative, or anything you imagine)
38
+ 💡 **Skills** - Give your AI new abilities like taking meeting notes, reviewing code, or organizing your thoughts
39
+ 📝 **Templates** - Create reusable formats for emails, documentation, resumes, and more
40
+ 🤖 **Agents** - Build smart assistants that handle specific tasks automatically
41
+ ✨ **And more!** - Just describe what you want, and DollhouseMCP will help you create it
42
+
43
+ The best part? Everything you create is saved and persistent. Your custom tools and assistants will be there whenever you need them. You can modify them anytime just by asking!
44
+
45
+ **Need ideas?** Just ask "What would be the best way to..." and I'll help you figure out the perfect solution.
46
+
47
+ **Ready to get started?** I'll help you:
48
+ - Choose a username (this tags your creations so you can find them later - or stay anonymous, that's totally fine!)
49
+ - Set up your workspace for saving all your customizations
50
+ - Browse examples to spark your creativity
51
+ - Create your first customization element
52
+
53
+ Just say:
54
+ - "Yes" or "Let's get started" → I'll guide you through setup
55
+ - "Skip for now" → You can set up later when you're ready
56
+ - "I'll stay anonymous" → Perfect! You can use everything without signing in
57
+
58
+ **What's a username for?** It simply tags your creations (like "created by: you") so you can find them easily. Staying anonymous means your creations are tagged with a fun random ID instead (like "created by: clever-fox"). Either way, all your work is saved locally on your computer!
59
+
60
+ Don't worry - this only takes a minute, and you can change any settings later! 🌟`;
61
+ // Return the message in the requested format
62
+ if (options.format === 'raw') {
63
+ // Just the text, no formatting
64
+ return welcomeMessage;
65
+ }
66
+ else if (options.format === 'markdown') {
67
+ // Return as markdown code block
68
+ return {
69
+ content: [{
70
+ type: "text",
71
+ text: "```markdown\n" + welcomeMessage + "\n```"
72
+ }]
73
+ };
74
+ }
75
+ else {
76
+ // Default: Return as clean text with instruction
77
+ return {
78
+ content: [{
79
+ type: "text",
80
+ text: welcomeMessage
81
+ }]
82
+ };
83
+ }
84
+ }
85
+ /**
86
+ * Tool definition for MCP
87
+ */
88
+ static get definition() {
89
+ return {
90
+ name: "dollhouse_welcome",
91
+ description: "Get the DollhouseMCP welcome message for first-time users",
92
+ inputSchema: {
93
+ type: "object",
94
+ properties: {
95
+ format: {
96
+ type: "string",
97
+ enum: ["text", "markdown", "raw"],
98
+ description: "Format for the welcome message (default: text)"
99
+ },
100
+ skipCheck: {
101
+ type: "boolean",
102
+ description: "Skip checking if wizard was already completed (default: false)"
103
+ }
104
+ }
105
+ }
106
+ };
107
+ }
108
+ }
109
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0V2VsY29tZU1lc3NhZ2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdG9vbHMvZ2V0V2VsY29tZU1lc3NhZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0dBS0c7QUFFSCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFPM0QsTUFBTSxPQUFPLHFCQUFxQjtJQUN4QixhQUFhLENBQWdCO0lBRXJDO1FBQ0UsSUFBSSxDQUFDLGFBQWEsR0FBRyxhQUFhLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDbkQsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxPQUFPLENBQUMsVUFBb0MsRUFBRTtRQUNsRCxNQUFNLElBQUksQ0FBQyxhQUFhLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDdEMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUU5Qyw4Q0FBOEM7UUFDOUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUN2QixJQUFJLE1BQU0sQ0FBQyxNQUFNLEVBQUUsU0FBUyxJQUFJLE1BQU0sQ0FBQyxNQUFNLEVBQUUsU0FBUyxFQUFFLENBQUM7Z0JBQ3pELE9BQU87b0JBQ0wsT0FBTyxFQUFFLENBQUM7NEJBQ1IsSUFBSSxFQUFFLE1BQU07NEJBQ1osSUFBSSxFQUFFLGtJQUFrSTt5QkFDekksQ0FBQztpQkFDSCxDQUFDO1lBQ0osQ0FBQztRQUNILENBQUM7UUFFRCxNQUFNLGNBQWMsR0FBRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7a0ZBNkJ1RCxDQUFDO1FBRS9FLDZDQUE2QztRQUM3QyxJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssS0FBSyxFQUFFLENBQUM7WUFDN0IsK0JBQStCO1lBQy9CLE9BQU8sY0FBYyxDQUFDO1FBQ3hCLENBQUM7YUFBTSxJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDekMsZ0NBQWdDO1lBQ2hDLE9BQU87Z0JBQ0wsT0FBTyxFQUFFLENBQUM7d0JBQ1IsSUFBSSxFQUFFLE1BQU07d0JBQ1osSUFBSSxFQUFFLGVBQWUsR0FBRyxjQUFjLEdBQUcsT0FBTztxQkFDakQsQ0FBQzthQUNILENBQUM7UUFDSixDQUFDO2FBQU0sQ0FBQztZQUNOLGlEQUFpRDtZQUNqRCxPQUFPO2dCQUNMLE9BQU8sRUFBRSxDQUFDO3dCQUNSLElBQUksRUFBRSxNQUFNO3dCQUNaLElBQUksRUFBRSxjQUFjO3FCQUNyQixDQUFDO2FBQ0gsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLEtBQUssVUFBVTtRQUNuQixPQUFPO1lBQ0wsSUFBSSxFQUFFLG1CQUFtQjtZQUN6QixXQUFXLEVBQUUsMkRBQTJEO1lBQ3hFLFdBQVcsRUFBRTtnQkFDWCxJQUFJLEVBQUUsUUFBUTtnQkFDZCxVQUFVLEVBQUU7b0JBQ1YsTUFBTSxFQUFFO3dCQUNOLElBQUksRUFBRSxRQUFRO3dCQUNkLElBQUksRUFBRSxDQUFDLE1BQU0sRUFBRSxVQUFVLEVBQUUsS0FBSyxDQUFDO3dCQUNqQyxXQUFXLEVBQUUsZ0RBQWdEO3FCQUM5RDtvQkFDRCxTQUFTLEVBQUU7d0JBQ1QsSUFBSSxFQUFFLFNBQVM7d0JBQ2YsV0FBVyxFQUFFLGdFQUFnRTtxQkFDOUU7aUJBQ0Y7YUFDRjtTQUNGLENBQUM7SUFDSixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdldCBXZWxjb21lIE1lc3NhZ2UgVG9vbFxuICogXG4gKiBBIGRlZGljYXRlZCBNQ1AgdG9vbCB0aGF0IHJldHVybnMgdGhlIHdlbGNvbWUgbWVzc2FnZVxuICogVGhpcyBnaXZlcyB1cyBtb3JlIGNvbnRyb2wgb3ZlciBob3cgdGhlIG1lc3NhZ2UgaXMgcHJlc2VudGVkXG4gKi9cblxuaW1wb3J0IHsgQ29uZmlnTWFuYWdlciB9IGZyb20gJy4uL2NvbmZpZy9Db25maWdNYW5hZ2VyLmpzJztcblxuZXhwb3J0IGludGVyZmFjZSBHZXRXZWxjb21lTWVzc2FnZU9wdGlvbnMge1xuICBmb3JtYXQ/OiAndGV4dCcgfCAnbWFya2Rvd24nIHwgJ3Jhdyc7XG4gIHNraXBDaGVjaz86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBjbGFzcyBHZXRXZWxjb21lTWVzc2FnZVRvb2wge1xuICBwcml2YXRlIGNvbmZpZ01hbmFnZXI6IENvbmZpZ01hbmFnZXI7XG4gIFxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLmNvbmZpZ01hbmFnZXIgPSBDb25maWdNYW5hZ2VyLmdldEluc3RhbmNlKCk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBHZXQgdGhlIHdlbGNvbWUgbWVzc2FnZSBkaXJlY3RseSBhcyBhIHRvb2wgcmVzcG9uc2VcbiAgICogVGhpcyBieXBhc3NlcyB0aGUgcmVzcG9uc2Ugd3JhcHBpbmcgYW5kIGdpdmVzIHVzIGZ1bGwgY29udHJvbFxuICAgKi9cbiAgYXN5bmMgZXhlY3V0ZShvcHRpb25zOiBHZXRXZWxjb21lTWVzc2FnZU9wdGlvbnMgPSB7fSk6IFByb21pc2U8YW55PiB7XG4gICAgYXdhaXQgdGhpcy5jb25maWdNYW5hZ2VyLmluaXRpYWxpemUoKTtcbiAgICBjb25zdCBjb25maWcgPSB0aGlzLmNvbmZpZ01hbmFnZXIuZ2V0Q29uZmlnKCk7XG4gICAgXG4gICAgLy8gQ2hlY2sgaWYgd2Ugc2hvdWxkIHNob3cgdGhlIHdlbGNvbWUgbWVzc2FnZVxuICAgIGlmICghb3B0aW9ucy5za2lwQ2hlY2spIHtcbiAgICAgIGlmIChjb25maWcud2l6YXJkPy5jb21wbGV0ZWQgfHwgY29uZmlnLndpemFyZD8uZGlzbWlzc2VkKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgY29udGVudDogW3tcbiAgICAgICAgICAgIHR5cGU6IFwidGV4dFwiLFxuICAgICAgICAgICAgdGV4dDogXCJXZWxjb21lIGJhY2sgdG8gRG9sbGhvdXNlTUNQISBUaGUgd2l6YXJkIGhhcyBhbHJlYWR5IGJlZW4gY29tcGxldGVkLiBVc2UgJ09wZW4gY29uZmlndXJhdGlvbiB3aXphcmQnIGlmIHlvdSB3YW50IHRvIHJlY29uZmlndXJlLlwiXG4gICAgICAgICAgfV1cbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgY29uc3Qgd2VsY29tZU1lc3NhZ2UgPSBg8J+OqCAqKldlbGNvbWUgdG8gRG9sbGhvdXNlTUNQISoqXG5cbkhpIHRoZXJlISBJIHNlZSB0aGlzIGlzIHlvdXIgZmlyc3QgdGltZSBoZXJlLiBEb2xsaG91c2VNQ1AgaGVscHMgeW91IGNyZWF0ZSBwb3dlcmZ1bCBjdXN0b21pemF0aW9uIGVsZW1lbnRzIGZvciB5b3VyIEFJIGFzc2lzdGFudCAtIGFuZCBpdCdzIGVhc2llciB0aGFuIHlvdSBtaWdodCB0aGluayFcblxuKipXaGF0IGNhbiB5b3UgZG8gd2l0aCBEb2xsaG91c2VNQ1A/Kipcblxu8J+OrSAqKlBlcnNvbmFzKiogLSBDaGFuZ2UgeW91ciBBSSdzIHBlcnNvbmFsaXR5IChtYWtlIGl0IGZ1bm55LCBwcm9mZXNzaW9uYWwsIGNyZWF0aXZlLCBvciBhbnl0aGluZyB5b3UgaW1hZ2luZSlcbvCfkqEgKipTa2lsbHMqKiAtIEdpdmUgeW91ciBBSSBuZXcgYWJpbGl0aWVzIGxpa2UgdGFraW5nIG1lZXRpbmcgbm90ZXMsIHJldmlld2luZyBjb2RlLCBvciBvcmdhbml6aW5nIHlvdXIgdGhvdWdodHNcbvCfk50gKipUZW1wbGF0ZXMqKiAtIENyZWF0ZSByZXVzYWJsZSBmb3JtYXRzIGZvciBlbWFpbHMsIGRvY3VtZW50YXRpb24sIHJlc3VtZXMsIGFuZCBtb3JlXG7wn6SWICoqQWdlbnRzKiogLSBCdWlsZCBzbWFydCBhc3Npc3RhbnRzIHRoYXQgaGFuZGxlIHNwZWNpZmljIHRhc2tzIGF1dG9tYXRpY2FsbHlcbuKcqCAqKkFuZCBtb3JlISoqIC0gSnVzdCBkZXNjcmliZSB3aGF0IHlvdSB3YW50LCBhbmQgRG9sbGhvdXNlTUNQIHdpbGwgaGVscCB5b3UgY3JlYXRlIGl0XG5cblRoZSBiZXN0IHBhcnQ/IEV2ZXJ5dGhpbmcgeW91IGNyZWF0ZSBpcyBzYXZlZCBhbmQgcGVyc2lzdGVudC4gWW91ciBjdXN0b20gdG9vbHMgYW5kIGFzc2lzdGFudHMgd2lsbCBiZSB0aGVyZSB3aGVuZXZlciB5b3UgbmVlZCB0aGVtLiBZb3UgY2FuIG1vZGlmeSB0aGVtIGFueXRpbWUganVzdCBieSBhc2tpbmchXG5cbioqTmVlZCBpZGVhcz8qKiBKdXN0IGFzayBcIldoYXQgd291bGQgYmUgdGhlIGJlc3Qgd2F5IHRvLi4uXCIgYW5kIEknbGwgaGVscCB5b3UgZmlndXJlIG91dCB0aGUgcGVyZmVjdCBzb2x1dGlvbi5cblxuKipSZWFkeSB0byBnZXQgc3RhcnRlZD8qKiBJJ2xsIGhlbHAgeW91OlxuLSBDaG9vc2UgYSB1c2VybmFtZSAodGhpcyB0YWdzIHlvdXIgY3JlYXRpb25zIHNvIHlvdSBjYW4gZmluZCB0aGVtIGxhdGVyIC0gb3Igc3RheSBhbm9ueW1vdXMsIHRoYXQncyB0b3RhbGx5IGZpbmUhKVxuLSBTZXQgdXAgeW91ciB3b3Jrc3BhY2UgZm9yIHNhdmluZyBhbGwgeW91ciBjdXN0b21pemF0aW9uc1xuLSBCcm93c2UgZXhhbXBsZXMgdG8gc3BhcmsgeW91ciBjcmVhdGl2aXR5XG4tIENyZWF0ZSB5b3VyIGZpcnN0IGN1c3RvbWl6YXRpb24gZWxlbWVudFxuXG5KdXN0IHNheTpcbi0gXCJZZXNcIiBvciBcIkxldCdzIGdldCBzdGFydGVkXCIg4oaSIEknbGwgZ3VpZGUgeW91IHRocm91Z2ggc2V0dXBcbi0gXCJTa2lwIGZvciBub3dcIiDihpIgWW91IGNhbiBzZXQgdXAgbGF0ZXIgd2hlbiB5b3UncmUgcmVhZHlcbi0gXCJJJ2xsIHN0YXkgYW5vbnltb3VzXCIg4oaSIFBlcmZlY3QhIFlvdSBjYW4gdXNlIGV2ZXJ5dGhpbmcgd2l0aG91dCBzaWduaW5nIGluXG5cbioqV2hhdCdzIGEgdXNlcm5hbWUgZm9yPyoqIEl0IHNpbXBseSB0YWdzIHlvdXIgY3JlYXRpb25zIChsaWtlIFwiY3JlYXRlZCBieTogeW91XCIpIHNvIHlvdSBjYW4gZmluZCB0aGVtIGVhc2lseS4gU3RheWluZyBhbm9ueW1vdXMgbWVhbnMgeW91ciBjcmVhdGlvbnMgYXJlIHRhZ2dlZCB3aXRoIGEgZnVuIHJhbmRvbSBJRCBpbnN0ZWFkIChsaWtlIFwiY3JlYXRlZCBieTogY2xldmVyLWZveFwiKS4gRWl0aGVyIHdheSwgYWxsIHlvdXIgd29yayBpcyBzYXZlZCBsb2NhbGx5IG9uIHlvdXIgY29tcHV0ZXIhXG5cbkRvbid0IHdvcnJ5IC0gdGhpcyBvbmx5IHRha2VzIGEgbWludXRlLCBhbmQgeW91IGNhbiBjaGFuZ2UgYW55IHNldHRpbmdzIGxhdGVyISDwn4yfYDtcbiAgICBcbiAgICAvLyBSZXR1cm4gdGhlIG1lc3NhZ2UgaW4gdGhlIHJlcXVlc3RlZCBmb3JtYXRcbiAgICBpZiAob3B0aW9ucy5mb3JtYXQgPT09ICdyYXcnKSB7XG4gICAgICAvLyBKdXN0IHRoZSB0ZXh0LCBubyBmb3JtYXR0aW5nXG4gICAgICByZXR1cm4gd2VsY29tZU1lc3NhZ2U7XG4gICAgfSBlbHNlIGlmIChvcHRpb25zLmZvcm1hdCA9PT0gJ21hcmtkb3duJykge1xuICAgICAgLy8gUmV0dXJuIGFzIG1hcmtkb3duIGNvZGUgYmxvY2tcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGNvbnRlbnQ6IFt7XG4gICAgICAgICAgdHlwZTogXCJ0ZXh0XCIsXG4gICAgICAgICAgdGV4dDogXCJgYGBtYXJrZG93blxcblwiICsgd2VsY29tZU1lc3NhZ2UgKyBcIlxcbmBgYFwiXG4gICAgICAgIH1dXG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBEZWZhdWx0OiBSZXR1cm4gYXMgY2xlYW4gdGV4dCB3aXRoIGluc3RydWN0aW9uXG4gICAgICByZXR1cm4ge1xuICAgICAgICBjb250ZW50OiBbe1xuICAgICAgICAgIHR5cGU6IFwidGV4dFwiLFxuICAgICAgICAgIHRleHQ6IHdlbGNvbWVNZXNzYWdlXG4gICAgICAgIH1dXG4gICAgICB9O1xuICAgIH1cbiAgfVxuICBcbiAgLyoqXG4gICAqIFRvb2wgZGVmaW5pdGlvbiBmb3IgTUNQXG4gICAqL1xuICBzdGF0aWMgZ2V0IGRlZmluaXRpb24oKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5hbWU6IFwiZG9sbGhvdXNlX3dlbGNvbWVcIixcbiAgICAgIGRlc2NyaXB0aW9uOiBcIkdldCB0aGUgRG9sbGhvdXNlTUNQIHdlbGNvbWUgbWVzc2FnZSBmb3IgZmlyc3QtdGltZSB1c2Vyc1wiLFxuICAgICAgaW5wdXRTY2hlbWE6IHtcbiAgICAgICAgdHlwZTogXCJvYmplY3RcIixcbiAgICAgICAgcHJvcGVydGllczoge1xuICAgICAgICAgIGZvcm1hdDoge1xuICAgICAgICAgICAgdHlwZTogXCJzdHJpbmdcIixcbiAgICAgICAgICAgIGVudW06IFtcInRleHRcIiwgXCJtYXJrZG93blwiLCBcInJhd1wiXSxcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkZvcm1hdCBmb3IgdGhlIHdlbGNvbWUgbWVzc2FnZSAoZGVmYXVsdDogdGV4dClcIlxuICAgICAgICAgIH0sXG4gICAgICAgICAgc2tpcENoZWNrOiB7XG4gICAgICAgICAgICB0eXBlOiBcImJvb2xlYW5cIixcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlNraXAgY2hlY2tpbmcgaWYgd2l6YXJkIHdhcyBhbHJlYWR5IGNvbXBsZXRlZCAoZGVmYXVsdDogZmFsc2UpXCJcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuICB9XG59Il19
@@ -0,0 +1,63 @@
1
+ /**
2
+ * TemplateRenderer - Utility class for rendering templates with comprehensive validation
3
+ *
4
+ * IMPROVEMENTS IMPLEMENTED (per Debug Detective recommendations):
5
+ * 1. instanceof Template verification for type safety
6
+ * 2. Performance logging to track render times
7
+ * 3. Validation of render() return value
8
+ * 4. Clear separation of concerns from index.ts
9
+ *
10
+ * This addresses Issues #913 and #914 from the v1.7.3 hotfix
11
+ */
12
+ import { TemplateManager } from '../elements/templates/TemplateManager.js';
13
+ export interface RenderResult {
14
+ success: boolean;
15
+ content?: string;
16
+ error?: string;
17
+ performance?: {
18
+ lookupTime: number;
19
+ renderTime: number;
20
+ totalTime: number;
21
+ };
22
+ }
23
+ export declare class TemplateRenderer {
24
+ private templateManager;
25
+ constructor(templateManager: TemplateManager);
26
+ /**
27
+ * Render a template with comprehensive validation and performance tracking
28
+ *
29
+ * VALIDATION CHAIN:
30
+ * 1. Unicode normalization of template name
31
+ * 2. Template exists in manager
32
+ * 3. Template is proper Template instance
33
+ * 4. Template has render() method
34
+ * 5. render() returns a string
35
+ *
36
+ * SECURITY:
37
+ * - Unicode normalization prevents homograph attacks
38
+ * - Variables are normalized by Template.render() internally
39
+ *
40
+ * PERFORMANCE TRACKING:
41
+ * - Lookup time (finding template)
42
+ * - Render time (actual rendering)
43
+ * - Total time (complete operation)
44
+ */
45
+ render(name: string, variables?: Record<string, any>): Promise<RenderResult>;
46
+ /**
47
+ * Batch render multiple templates (useful for testing)
48
+ * SECURITY: Each template name is normalized individually
49
+ */
50
+ renderBatch(templates: Array<{
51
+ name: string;
52
+ variables: Record<string, any>;
53
+ }>): Promise<Map<string, RenderResult>>;
54
+ /**
55
+ * Validate that a template can be rendered without actually rendering it
56
+ * SECURITY: Template name is normalized to prevent Unicode attacks
57
+ */
58
+ validate(name: string): Promise<{
59
+ valid: boolean;
60
+ reason?: string;
61
+ }>;
62
+ }
63
+ //# sourceMappingURL=TemplateRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TemplateRenderer.d.ts","sourceRoot":"","sources":["../../src/utils/TemplateRenderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,0CAA0C,CAAC;AAI3E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE;QACZ,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,qBAAa,gBAAgB;IACf,OAAO,CAAC,eAAe;gBAAf,eAAe,EAAE,eAAe;IAEpD;;;;;;;;;;;;;;;;;;OAkBG;IACG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAkGtF;;;OAGG;IACG,WAAW,CACf,SAAS,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;KAAE,CAAC,GACjE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAWrC;;;OAGG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CA4B3E"}