@dollhousemcp/mcp-server 1.5.2 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +494 -111
  3. package/data/agents/code-reviewer.md +8 -1
  4. package/data/agents/research-assistant.md +8 -1
  5. package/data/agents/task-manager.md +8 -1
  6. package/data/ensembles/business-advisor.md +8 -1
  7. package/data/ensembles/creative-studio.md +8 -1
  8. package/data/ensembles/development-team.md +8 -1
  9. package/data/ensembles/security-analysis-team.md +8 -1
  10. package/data/memories/conversation-history.md +8 -1
  11. package/data/memories/learning-progress.md +8 -1
  12. package/data/memories/project-context.md +8 -1
  13. package/data/personas/business-consultant.md +8 -1
  14. package/data/personas/creative-writer.md +8 -1
  15. package/data/personas/debug-detective.md +8 -1
  16. package/data/personas/eli5-explainer.md +8 -1
  17. package/data/personas/security-analyst.md +8 -1
  18. package/data/personas/technical-analyst.md +8 -1
  19. package/data/skills/code-review.md +8 -1
  20. package/data/skills/creative-writing.md +8 -1
  21. package/data/skills/data-analysis.md +8 -1
  22. package/data/skills/penetration-testing.md +8 -1
  23. package/data/skills/research.md +8 -1
  24. package/data/skills/threat-modeling.md +8 -1
  25. package/data/skills/translation.md +8 -1
  26. package/data/templates/code-documentation.md +8 -1
  27. package/data/templates/email-professional.md +8 -1
  28. package/data/templates/meeting-notes.md +8 -1
  29. package/data/templates/penetration-test-report.md +8 -1
  30. package/data/templates/project-brief.md +8 -1
  31. package/data/templates/report-executive.md +8 -1
  32. package/data/templates/security-vulnerability-report.md +8 -1
  33. package/data/templates/threat-assessment-report.md +8 -1
  34. package/dist/auth/GitHubAuthManager.d.ts +6 -1
  35. package/dist/auth/GitHubAuthManager.d.ts.map +1 -1
  36. package/dist/auth/GitHubAuthManager.js +45 -18
  37. package/dist/benchmarks/IndexPerformanceBenchmark.d.ts +98 -0
  38. package/dist/benchmarks/IndexPerformanceBenchmark.d.ts.map +1 -0
  39. package/dist/benchmarks/IndexPerformanceBenchmark.js +531 -0
  40. package/dist/cache/CollectionCache.d.ts.map +1 -1
  41. package/dist/cache/CollectionCache.js +13 -3
  42. package/dist/cache/CollectionIndexCache.d.ts +77 -0
  43. package/dist/cache/CollectionIndexCache.d.ts.map +1 -0
  44. package/dist/cache/CollectionIndexCache.js +349 -0
  45. package/dist/cache/LRUCache.d.ts +93 -0
  46. package/dist/cache/LRUCache.d.ts.map +1 -0
  47. package/dist/cache/LRUCache.js +299 -0
  48. package/dist/cache/index.d.ts +1 -0
  49. package/dist/cache/index.d.ts.map +1 -1
  50. package/dist/cache/index.js +2 -1
  51. package/dist/collection/CollectionBrowser.d.ts +21 -1
  52. package/dist/collection/CollectionBrowser.d.ts.map +1 -1
  53. package/dist/collection/CollectionBrowser.js +130 -10
  54. package/dist/collection/CollectionIndexManager.d.ts +151 -0
  55. package/dist/collection/CollectionIndexManager.d.ts.map +1 -0
  56. package/dist/collection/CollectionIndexManager.js +499 -0
  57. package/dist/collection/CollectionSearch.d.ts +55 -0
  58. package/dist/collection/CollectionSearch.d.ts.map +1 -1
  59. package/dist/collection/CollectionSearch.js +338 -13
  60. package/dist/collection/CollectionSeeder.d.ts.map +1 -1
  61. package/dist/collection/CollectionSeeder.js +38 -1
  62. package/dist/collection/ElementInstaller.d.ts +31 -0
  63. package/dist/collection/ElementInstaller.d.ts.map +1 -1
  64. package/dist/collection/ElementInstaller.js +77 -15
  65. package/dist/collection/PersonaSubmitter.d.ts +1 -1
  66. package/dist/collection/PersonaSubmitter.d.ts.map +1 -1
  67. package/dist/collection/PersonaSubmitter.js +2 -2
  68. package/dist/collection/index.d.ts +1 -0
  69. package/dist/collection/index.d.ts.map +1 -1
  70. package/dist/collection/index.js +2 -1
  71. package/dist/config/ConfigManager.d.ts +78 -0
  72. package/dist/config/ConfigManager.d.ts.map +1 -0
  73. package/dist/config/ConfigManager.js +216 -0
  74. package/dist/config/element-types.d.ts +135 -0
  75. package/dist/config/element-types.d.ts.map +1 -0
  76. package/dist/config/element-types.js +108 -0
  77. package/dist/config/index.d.ts +2 -0
  78. package/dist/config/index.d.ts.map +1 -1
  79. package/dist/config/index.js +3 -1
  80. package/dist/config/portfolio-constants.d.ts +83 -0
  81. package/dist/config/portfolio-constants.d.ts.map +1 -0
  82. package/dist/config/portfolio-constants.js +99 -0
  83. package/dist/elements/BaseElement.d.ts +14 -2
  84. package/dist/elements/BaseElement.d.ts.map +1 -1
  85. package/dist/elements/BaseElement.js +88 -6
  86. package/dist/elements/agents/Agent.d.ts +10 -1
  87. package/dist/elements/agents/Agent.d.ts.map +1 -1
  88. package/dist/elements/agents/Agent.js +66 -19
  89. package/dist/elements/agents/AgentManager.d.ts +2 -0
  90. package/dist/elements/agents/AgentManager.d.ts.map +1 -1
  91. package/dist/elements/agents/AgentManager.js +12 -10
  92. package/dist/elements/skills/Skill.d.ts +10 -1
  93. package/dist/elements/skills/Skill.d.ts.map +1 -1
  94. package/dist/elements/skills/Skill.js +40 -3
  95. package/dist/elements/skills/SkillManager.d.ts +1 -0
  96. package/dist/elements/skills/SkillManager.d.ts.map +1 -1
  97. package/dist/elements/skills/SkillManager.js +10 -4
  98. package/dist/elements/templates/Template.d.ts +10 -1
  99. package/dist/elements/templates/Template.d.ts.map +1 -1
  100. package/dist/elements/templates/Template.js +35 -18
  101. package/dist/elements/templates/TemplateManager.d.ts +1 -1
  102. package/dist/elements/templates/TemplateManager.d.ts.map +1 -1
  103. package/dist/elements/templates/TemplateManager.js +6 -5
  104. package/dist/generated/version.d.ts +2 -2
  105. package/dist/generated/version.js +3 -3
  106. package/dist/index.barrel.d.ts +1 -2
  107. package/dist/index.barrel.d.ts.map +1 -1
  108. package/dist/index.barrel.js +2 -4
  109. package/dist/index.d.ts +143 -25
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js +1883 -310
  112. package/dist/persona/PersonaElement.d.ts +10 -0
  113. package/dist/persona/PersonaElement.d.ts.map +1 -1
  114. package/dist/persona/PersonaElement.js +55 -32
  115. package/dist/persona/PersonaElementManager.d.ts.map +1 -1
  116. package/dist/persona/PersonaElementManager.js +13 -11
  117. package/dist/persona/PersonaLoader.d.ts.map +1 -1
  118. package/dist/persona/PersonaLoader.js +8 -2
  119. package/dist/persona/export-import/PersonaImporter.d.ts.map +1 -1
  120. package/dist/persona/export-import/PersonaImporter.js +24 -5
  121. package/dist/persona/export-import/PersonaSharer.d.ts +21 -0
  122. package/dist/persona/export-import/PersonaSharer.d.ts.map +1 -1
  123. package/dist/persona/export-import/PersonaSharer.js +198 -22
  124. package/dist/portfolio/DefaultElementProvider.d.ts +90 -0
  125. package/dist/portfolio/DefaultElementProvider.d.ts.map +1 -1
  126. package/dist/portfolio/DefaultElementProvider.js +499 -7
  127. package/dist/portfolio/GitHubPortfolioIndexer.d.ts +129 -0
  128. package/dist/portfolio/GitHubPortfolioIndexer.d.ts.map +1 -0
  129. package/dist/portfolio/GitHubPortfolioIndexer.js +475 -0
  130. package/dist/portfolio/MigrationManager.d.ts.map +1 -1
  131. package/dist/portfolio/MigrationManager.js +136 -3
  132. package/dist/portfolio/PortfolioIndexManager.d.ts +130 -0
  133. package/dist/portfolio/PortfolioIndexManager.d.ts.map +1 -0
  134. package/dist/portfolio/PortfolioIndexManager.js +478 -0
  135. package/dist/portfolio/PortfolioManager.d.ts +5 -0
  136. package/dist/portfolio/PortfolioManager.d.ts.map +1 -1
  137. package/dist/portfolio/PortfolioManager.js +61 -20
  138. package/dist/portfolio/PortfolioRepoManager.d.ts +75 -0
  139. package/dist/portfolio/PortfolioRepoManager.d.ts.map +1 -0
  140. package/dist/portfolio/PortfolioRepoManager.js +337 -0
  141. package/dist/portfolio/UnifiedIndexManager.d.ts +388 -0
  142. package/dist/portfolio/UnifiedIndexManager.d.ts.map +1 -0
  143. package/dist/portfolio/UnifiedIndexManager.js +1434 -0
  144. package/dist/portfolio/index.d.ts +15 -0
  145. package/dist/portfolio/index.d.ts.map +1 -0
  146. package/dist/portfolio/index.js +15 -0
  147. package/dist/portfolio/types.d.ts +7 -0
  148. package/dist/portfolio/types.d.ts.map +1 -1
  149. package/dist/portfolio/types.js +6 -1
  150. package/dist/security/InputValidator.d.ts.map +1 -1
  151. package/dist/security/InputValidator.js +50 -48
  152. package/dist/security/audit/SecurityAuditor.d.ts.map +1 -1
  153. package/dist/security/audit/SecurityAuditor.js +17 -9
  154. package/dist/security/audit/config/suppressions.d.ts.map +1 -1
  155. package/dist/security/audit/config/suppressions.js +19 -3
  156. package/dist/security/contentValidator.d.ts +2 -0
  157. package/dist/security/contentValidator.d.ts.map +1 -1
  158. package/dist/security/contentValidator.js +115 -4
  159. package/dist/security/secureYamlParser.d.ts +1 -0
  160. package/dist/security/secureYamlParser.d.ts.map +1 -1
  161. package/dist/security/secureYamlParser.js +29 -7
  162. package/dist/security/securityMonitor.d.ts +1 -1
  163. package/dist/security/securityMonitor.d.ts.map +1 -1
  164. package/dist/security/securityMonitor.js +1 -1
  165. package/dist/security/tokenManager.d.ts +1 -1
  166. package/dist/security/tokenManager.d.ts.map +1 -1
  167. package/dist/security/tokenManager.js +30 -10
  168. package/dist/server/ServerSetup.d.ts +22 -2
  169. package/dist/server/ServerSetup.d.ts.map +1 -1
  170. package/dist/server/ServerSetup.js +77 -12
  171. package/dist/server/tools/AuthTools.d.ts.map +1 -1
  172. package/dist/server/tools/AuthTools.js +33 -1
  173. package/dist/server/tools/BuildInfoTools.d.ts +25 -0
  174. package/dist/server/tools/BuildInfoTools.d.ts.map +1 -0
  175. package/dist/server/tools/BuildInfoTools.js +36 -0
  176. package/dist/server/tools/CollectionTools.d.ts.map +1 -1
  177. package/dist/server/tools/CollectionTools.js +55 -46
  178. package/dist/server/tools/ConfigTools.d.ts.map +1 -1
  179. package/dist/server/tools/ConfigTools.js +29 -1
  180. package/dist/server/tools/PersonaTools.d.ts +4 -2
  181. package/dist/server/tools/PersonaTools.d.ts.map +1 -1
  182. package/dist/server/tools/PersonaTools.js +5 -152
  183. package/dist/server/tools/PortfolioTools.d.ts +12 -0
  184. package/dist/server/tools/PortfolioTools.d.ts.map +1 -0
  185. package/dist/server/tools/PortfolioTools.js +221 -0
  186. package/dist/server/tools/index.d.ts +3 -1
  187. package/dist/server/tools/index.d.ts.map +1 -1
  188. package/dist/server/tools/index.js +4 -2
  189. package/dist/server/types.d.ts +40 -5
  190. package/dist/server/types.d.ts.map +1 -1
  191. package/dist/server/types.js +1 -1
  192. package/dist/services/BuildInfoService.d.ts +84 -0
  193. package/dist/services/BuildInfoService.d.ts.map +1 -0
  194. package/dist/services/BuildInfoService.js +271 -0
  195. package/dist/tools/portfolio/PortfolioElementAdapter.d.ts +54 -0
  196. package/dist/tools/portfolio/PortfolioElementAdapter.d.ts.map +1 -0
  197. package/dist/tools/portfolio/PortfolioElementAdapter.js +229 -0
  198. package/dist/tools/portfolio/submitToPortfolioTool.d.ts +164 -0
  199. package/dist/tools/portfolio/submitToPortfolioTool.d.ts.map +1 -0
  200. package/dist/tools/portfolio/submitToPortfolioTool.js +1523 -0
  201. package/dist/tools/portfolio/types.d.ts +41 -0
  202. package/dist/tools/portfolio/types.d.ts.map +1 -0
  203. package/dist/tools/portfolio/types.js +15 -0
  204. package/dist/types/collection.d.ts +51 -0
  205. package/dist/types/collection.d.ts.map +1 -1
  206. package/dist/types/collection.js +1 -1
  207. package/dist/utils/EarlyTerminationSearch.d.ts +41 -0
  208. package/dist/utils/EarlyTerminationSearch.d.ts.map +1 -0
  209. package/dist/utils/EarlyTerminationSearch.js +164 -0
  210. package/dist/utils/ErrorHandler.d.ts +86 -0
  211. package/dist/utils/ErrorHandler.d.ts.map +1 -0
  212. package/dist/utils/ErrorHandler.js +201 -0
  213. package/dist/utils/FileDiscoveryUtil.d.ts +53 -0
  214. package/dist/utils/FileDiscoveryUtil.d.ts.map +1 -0
  215. package/dist/utils/FileDiscoveryUtil.js +169 -0
  216. package/dist/utils/GitHubRateLimiter.d.ts +88 -0
  217. package/dist/utils/GitHubRateLimiter.d.ts.map +1 -0
  218. package/dist/utils/GitHubRateLimiter.js +315 -0
  219. package/dist/utils/PerformanceMonitor.d.ts +134 -0
  220. package/dist/utils/PerformanceMonitor.d.ts.map +1 -0
  221. package/dist/utils/PerformanceMonitor.js +347 -0
  222. package/dist/utils/RateLimiter.d.ts.map +1 -0
  223. package/dist/utils/RateLimiter.js +172 -0
  224. package/dist/utils/SecureDownloader.d.ts +241 -0
  225. package/dist/utils/SecureDownloader.d.ts.map +1 -0
  226. package/dist/utils/SecureDownloader.js +759 -0
  227. package/dist/utils/ToolCache.d.ts +82 -0
  228. package/dist/utils/ToolCache.d.ts.map +1 -0
  229. package/dist/utils/ToolCache.js +196 -0
  230. package/dist/utils/errorCodes.d.ts +136 -0
  231. package/dist/utils/errorCodes.d.ts.map +1 -0
  232. package/dist/utils/errorCodes.js +87 -0
  233. package/dist/utils/index.d.ts +3 -0
  234. package/dist/utils/index.d.ts.map +1 -1
  235. package/dist/utils/index.js +4 -1
  236. package/dist/utils/installation.d.ts +1 -1
  237. package/dist/utils/installation.d.ts.map +1 -1
  238. package/dist/utils/installation.js +9 -8
  239. package/dist/utils/searchUtils.d.ts +31 -0
  240. package/dist/utils/searchUtils.d.ts.map +1 -1
  241. package/dist/utils/searchUtils.js +62 -1
  242. package/package.json +17 -7
  243. package/dist/config/updateConfig.d.ts +0 -84
  244. package/dist/config/updateConfig.d.ts.map +0 -1
  245. package/dist/config/updateConfig.js +0 -148
  246. package/dist/server/tools/UpdateTools.d.ts +0 -10
  247. package/dist/server/tools/UpdateTools.d.ts.map +0 -1
  248. package/dist/server/tools/UpdateTools.js +0 -85
  249. package/dist/update/BackupManager.d.ts +0 -63
  250. package/dist/update/BackupManager.d.ts.map +0 -1
  251. package/dist/update/BackupManager.js +0 -370
  252. package/dist/update/DependencyChecker.d.ts +0 -41
  253. package/dist/update/DependencyChecker.d.ts.map +0 -1
  254. package/dist/update/DependencyChecker.js +0 -132
  255. package/dist/update/RateLimiter.d.ts.map +0 -1
  256. package/dist/update/RateLimiter.js +0 -172
  257. package/dist/update/SignatureVerifier.d.ts +0 -71
  258. package/dist/update/SignatureVerifier.d.ts.map +0 -1
  259. package/dist/update/SignatureVerifier.js +0 -214
  260. package/dist/update/UpdateChecker.d.ts +0 -132
  261. package/dist/update/UpdateChecker.d.ts.map +0 -1
  262. package/dist/update/UpdateChecker.js +0 -506
  263. package/dist/update/UpdateManager.d.ts +0 -60
  264. package/dist/update/UpdateManager.d.ts.map +0 -1
  265. package/dist/update/UpdateManager.js +0 -730
  266. package/dist/update/VersionManager.d.ts +0 -31
  267. package/dist/update/VersionManager.d.ts.map +0 -1
  268. package/dist/update/VersionManager.js +0 -181
  269. package/dist/update/index.d.ts +0 -9
  270. package/dist/update/index.d.ts.map +0 -1
  271. package/dist/update/index.js +0 -9
  272. /package/dist/{update → utils}/RateLimiter.d.ts +0 -0
@@ -0,0 +1,271 @@
1
+ /**
2
+ * BuildInfoService - Provides build and runtime information
3
+ * Separated from main index.ts to avoid making that file larger
4
+ *
5
+ * SECURITY FIX (PR #614):
6
+ * 1. DMCP-SEC-004: FALSE POSITIVE SUPPRESSION - No user input Unicode normalization needed
7
+ * This service only processes system information (git, package.json, environment variables)
8
+ * The MCP tool 'get_build_info' takes NO parameters (empty inputSchema)
9
+ * No user-provided data flows through this service that requires Unicode normalization
10
+ */
11
+ import * as fs from 'fs/promises';
12
+ import * as path from 'path';
13
+ import { fileURLToPath } from 'url';
14
+ import { execSync } from 'child_process';
15
+ import { logger } from '../utils/logger.js';
16
+ export class BuildInfoService {
17
+ static instance;
18
+ startTime;
19
+ packageInfo;
20
+ constructor() {
21
+ this.startTime = new Date();
22
+ }
23
+ static getInstance() {
24
+ if (!BuildInfoService.instance) {
25
+ BuildInfoService.instance = new BuildInfoService();
26
+ }
27
+ return BuildInfoService.instance;
28
+ }
29
+ /**
30
+ * Get comprehensive build information
31
+ * SECURITY NOTE: This method processes only system-generated data
32
+ * No user input is involved - all data comes from filesystem, git, and Node.js process
33
+ */
34
+ async getBuildInfo() {
35
+ const [packageInfo, gitInfo, dockerInfo] = await Promise.all([
36
+ this.getPackageInfo(),
37
+ this.getGitInfo(),
38
+ this.getDockerInfo()
39
+ ]);
40
+ const buildTimestamp = await this.getBuildTimestamp();
41
+ return {
42
+ package: packageInfo,
43
+ build: {
44
+ timestamp: buildTimestamp,
45
+ type: gitInfo.commit ? 'git' : buildTimestamp ? 'npm' : 'unknown',
46
+ gitCommit: gitInfo.commit,
47
+ gitBranch: gitInfo.branch
48
+ },
49
+ runtime: {
50
+ nodeVersion: process.version,
51
+ platform: process.platform,
52
+ arch: process.arch,
53
+ uptime: process.uptime(),
54
+ memoryUsage: process.memoryUsage()
55
+ },
56
+ environment: {
57
+ nodeEnv: process.env.NODE_ENV,
58
+ isProduction: process.env.NODE_ENV === 'production',
59
+ isDevelopment: process.env.NODE_ENV === 'development',
60
+ isDebug: process.env.DEBUG === 'true' || process.env.DEBUG === '1',
61
+ isDocker: dockerInfo.isDocker,
62
+ dockerInfo: dockerInfo.info
63
+ },
64
+ server: {
65
+ startTime: this.startTime,
66
+ uptime: Date.now() - this.startTime.getTime(),
67
+ mcpConnection: true // We're connected if this method is being called via MCP
68
+ }
69
+ };
70
+ }
71
+ /**
72
+ * Format build info as user-friendly markdown
73
+ * SECURITY NOTE: Only formats system-generated data - no user input processing
74
+ * All input data comes from getBuildInfo() which only reads system information
75
+ */
76
+ formatBuildInfo(info) {
77
+ const lines = [];
78
+ lines.push('# 🔧 Build Information\n');
79
+ // Package info
80
+ lines.push('## 📦 Package');
81
+ lines.push(`- **Name**: ${info.package.name}`);
82
+ lines.push(`- **Version**: ${info.package.version}`);
83
+ lines.push('');
84
+ // Build info
85
+ lines.push('## 🏗️ Build');
86
+ lines.push(`- **Type**: ${info.build.type}`);
87
+ if (info.build.timestamp) {
88
+ lines.push(`- **Timestamp**: ${info.build.timestamp}`);
89
+ }
90
+ if (info.build.gitCommit) {
91
+ lines.push(`- **Git Commit**: \`${info.build.gitCommit}\``);
92
+ }
93
+ if (info.build.gitBranch) {
94
+ lines.push(`- **Git Branch**: ${info.build.gitBranch}`);
95
+ }
96
+ lines.push('');
97
+ // Runtime info
98
+ lines.push('## 💻 Runtime');
99
+ lines.push(`- **Node.js**: ${info.runtime.nodeVersion}`);
100
+ lines.push(`- **Platform**: ${info.runtime.platform}`);
101
+ lines.push(`- **Architecture**: ${info.runtime.arch}`);
102
+ lines.push(`- **Process Uptime**: ${this.formatUptime(info.runtime.uptime)}`);
103
+ lines.push(`- **Memory Usage**: ${this.formatMemory(info.runtime.memoryUsage.heapUsed)} / ${this.formatMemory(info.runtime.memoryUsage.heapTotal)}`);
104
+ lines.push('');
105
+ // Environment info
106
+ lines.push('## ⚙️ Environment');
107
+ lines.push(`- **NODE_ENV**: ${info.environment.nodeEnv || 'not set'}`);
108
+ lines.push(`- **Mode**: ${info.environment.isProduction ? 'Production' : info.environment.isDevelopment ? 'Development' : 'Unknown'}`);
109
+ lines.push(`- **Debug**: ${info.environment.isDebug ? 'Enabled' : 'Disabled'}`);
110
+ lines.push(`- **Docker**: ${info.environment.isDocker ? 'Yes' : 'No'}`);
111
+ if (info.environment.dockerInfo) {
112
+ lines.push(`- **Container**: ${info.environment.dockerInfo}`);
113
+ }
114
+ lines.push('');
115
+ // Server info
116
+ lines.push('## 🚀 Server');
117
+ lines.push(`- **Started**: ${info.server.startTime.toISOString()}`);
118
+ lines.push(`- **Uptime**: ${this.formatUptime(info.server.uptime / 1000)}`);
119
+ lines.push(`- **MCP Connection**: ${info.server.mcpConnection ? '✅ Connected' : '❌ Disconnected'}`);
120
+ return lines.join('\n');
121
+ }
122
+ /**
123
+ * SECURITY NOTE: No Unicode normalization needed - reads application's own package.json
124
+ * Data source: Controlled file system path, no user input
125
+ */
126
+ async getPackageInfo() {
127
+ if (this.packageInfo) {
128
+ return this.packageInfo;
129
+ }
130
+ try {
131
+ const __filename = fileURLToPath(import.meta.url);
132
+ const __dirname = path.dirname(__filename);
133
+ // Try multiple paths to find package.json
134
+ // This handles both normal execution and compiled test scenarios
135
+ const possiblePaths = [
136
+ path.join(__dirname, '..', '..', 'package.json'), // Normal: dist/services -> root
137
+ path.join(__dirname, '..', '..', '..', 'package.json'), // Test: dist/test/services -> root
138
+ path.join(__dirname, '..', '..', '..', '..', 'package.json'), // Deep test: dist/test/deep/services -> root
139
+ path.join(process.cwd(), 'package.json') // Fallback to current working directory
140
+ ];
141
+ let pkg = null;
142
+ for (const packagePath of possiblePaths) {
143
+ try {
144
+ // SECURITY NOTE: Reading our own package.json file - not user input
145
+ // This file is controlled by the application, no Unicode normalization needed
146
+ const content = await fs.readFile(packagePath, 'utf-8');
147
+ pkg = JSON.parse(content);
148
+ break;
149
+ }
150
+ catch {
151
+ // Try next path
152
+ continue;
153
+ }
154
+ }
155
+ if (!pkg) {
156
+ throw new Error('Could not find package.json in any expected location');
157
+ }
158
+ this.packageInfo = {
159
+ name: pkg.name || 'unknown',
160
+ version: pkg.version || 'unknown'
161
+ };
162
+ return this.packageInfo;
163
+ }
164
+ catch (error) {
165
+ logger.debug('Failed to read package.json:', error);
166
+ return { name: 'unknown', version: 'unknown' };
167
+ }
168
+ }
169
+ /**
170
+ * SECURITY NOTE: No Unicode normalization needed - reads build-generated version file
171
+ * Data source: Build system output file, no user input
172
+ */
173
+ async getBuildTimestamp() {
174
+ try {
175
+ const __filename = fileURLToPath(import.meta.url);
176
+ const __dirname = path.dirname(__filename);
177
+ // Try multiple paths to find version.json
178
+ // This handles both normal execution and compiled test scenarios
179
+ const possiblePaths = [
180
+ path.join(__dirname, '..', '..', 'dist', 'version.json'), // Normal location
181
+ path.join(__dirname, '..', '..', '..', 'dist', 'version.json'), // Test scenario
182
+ path.join(process.cwd(), 'dist', 'version.json') // Fallback to cwd
183
+ ];
184
+ for (const versionPath of possiblePaths) {
185
+ try {
186
+ const content = await fs.readFile(versionPath, 'utf-8');
187
+ const version = JSON.parse(content);
188
+ return version.buildTime || version.timestamp;
189
+ }
190
+ catch {
191
+ // Try next path
192
+ continue;
193
+ }
194
+ }
195
+ // Version file might not exist, that's okay
196
+ return undefined;
197
+ }
198
+ catch {
199
+ // Version file might not exist, that's okay
200
+ return undefined;
201
+ }
202
+ }
203
+ /**
204
+ * SECURITY NOTE: No Unicode normalization needed - executes system git commands
205
+ * Data source: Git CLI output (system-controlled), no user input
206
+ */
207
+ async getGitInfo() {
208
+ try {
209
+ // SECURITY NOTE: Git commands return system-controlled data - not user input
210
+ // Git commit hashes and branch names are controlled by git, no Unicode normalization needed
211
+ const commit = execSync('git rev-parse --short HEAD', { encoding: 'utf-8' }).trim();
212
+ const branch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim();
213
+ return { commit, branch };
214
+ }
215
+ catch {
216
+ // Not in a git repository or git not available
217
+ return {};
218
+ }
219
+ }
220
+ /**
221
+ * SECURITY NOTE: No Unicode normalization needed - reads container runtime files
222
+ * Data source: System cgroup files (container-controlled), no user input
223
+ */
224
+ async getDockerInfo() {
225
+ try {
226
+ // SECURITY NOTE: Reading system cgroup file - controlled by container runtime, not user input
227
+ // Container runtime generates this file content, no Unicode normalization needed
228
+ const cgroupContent = await fs.readFile('/proc/1/cgroup', 'utf-8');
229
+ const isDocker = cgroupContent.includes('docker') || cgroupContent.includes('containerd');
230
+ if (isDocker) {
231
+ // Try to get container ID
232
+ const containerId = cgroupContent
233
+ .split('\n')
234
+ .find(line => line.includes('docker'))
235
+ ?.split('/')
236
+ .pop()
237
+ ?.substring(0, 12);
238
+ return {
239
+ isDocker: true,
240
+ info: containerId ? `Container ID: ${containerId}` : 'Running in Docker'
241
+ };
242
+ }
243
+ return { isDocker: false };
244
+ }
245
+ catch {
246
+ // Not in Docker or /proc not available
247
+ return { isDocker: false };
248
+ }
249
+ }
250
+ formatUptime(seconds) {
251
+ const days = Math.floor(seconds / 86400);
252
+ const hours = Math.floor((seconds % 86400) / 3600);
253
+ const minutes = Math.floor((seconds % 3600) / 60);
254
+ const secs = Math.floor(seconds % 60);
255
+ const parts = [];
256
+ if (days > 0)
257
+ parts.push(`${days}d`);
258
+ if (hours > 0)
259
+ parts.push(`${hours}h`);
260
+ if (minutes > 0)
261
+ parts.push(`${minutes}m`);
262
+ if (secs > 0 || parts.length === 0)
263
+ parts.push(`${secs}s`);
264
+ return parts.join(' ');
265
+ }
266
+ formatMemory(bytes) {
267
+ const mb = bytes / 1024 / 1024;
268
+ return `${mb.toFixed(1)} MB`;
269
+ }
270
+ }
271
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQnVpbGRJbmZvU2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aWNlcy9CdWlsZEluZm9TZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7R0FTRztBQUVILE9BQU8sS0FBSyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2xDLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQzdCLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxLQUFLLENBQUM7QUFDcEMsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFtQzVDLE1BQU0sT0FBTyxnQkFBZ0I7SUFDbkIsTUFBTSxDQUFDLFFBQVEsQ0FBbUI7SUFDekIsU0FBUyxDQUFPO0lBQ3pCLFdBQVcsQ0FBcUM7SUFFeEQ7UUFDRSxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7SUFDOUIsQ0FBQztJQUVNLE1BQU0sQ0FBQyxXQUFXO1FBQ3ZCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUMvQixnQkFBZ0IsQ0FBQyxRQUFRLEdBQUcsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3JELENBQUM7UUFDRCxPQUFPLGdCQUFnQixDQUFDLFFBQVEsQ0FBQztJQUNuQyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLEtBQUssQ0FBQyxZQUFZO1FBQ3ZCLE1BQU0sQ0FBQyxXQUFXLEVBQUUsT0FBTyxFQUFFLFVBQVUsQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztZQUMzRCxJQUFJLENBQUMsY0FBYyxFQUFFO1lBQ3JCLElBQUksQ0FBQyxVQUFVLEVBQUU7WUFDakIsSUFBSSxDQUFDLGFBQWEsRUFBRTtTQUNyQixDQUFDLENBQUM7UUFFSCxNQUFNLGNBQWMsR0FBRyxNQUFNLElBQUksQ0FBQyxp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SyxDQUFDLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ2xELE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBRXRDLE1BQU0sS0FBSyxHQUFhLEVBQUUsQ0FBQztRQUMzQixJQUFJLElBQUksR0FBRyxDQUFDO1lBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLENBQUM7UUFDckMsSUFBSSxLQUFLLEdBQUcsQ0FBQztZQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLEdBQUcsQ0FBQyxDQUFDO1FBQ3ZDLElBQUksT0FBTyxHQUFHLENBQUM7WUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxHQUFHLENBQUMsQ0FBQztRQUMzQyxJQUFJLElBQUksR0FBRyxDQUFDLElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDO1lBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLENBQUM7UUFFM0QsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3pCLENBQUM7SUFFTyxZQUFZLENBQUMsS0FBYTtRQUNoQyxNQUFNLEVBQUUsR0FBRyxLQUFLLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQztRQUMvQixPQUFPLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQy9CLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQnVpbGRJbmZvU2VydmljZSAtIFByb3ZpZGVzIGJ1aWxkIGFuZCBydW50aW1lIGluZm9ybWF0aW9uXG4gKiBTZXBhcmF0ZWQgZnJvbSBtYWluIGluZGV4LnRzIHRvIGF2b2lkIG1ha2luZyB0aGF0IGZpbGUgbGFyZ2VyXG4gKiBcbiAqIFNFQ1VSSVRZIEZJWCAoUFIgIzYxNCk6XG4gKiAxLiBETUNQLVNFQy0wMDQ6IEZBTFNFIFBPU0lUSVZFIFNVUFBSRVNTSU9OIC0gTm8gdXNlciBpbnB1dCBVbmljb2RlIG5vcm1hbGl6YXRpb24gbmVlZGVkXG4gKiAgICBUaGlzIHNlcnZpY2Ugb25seSBwcm9jZXNzZXMgc3lzdGVtIGluZm9ybWF0aW9uIChnaXQsIHBhY2thZ2UuanNvbiwgZW52aXJvbm1lbnQgdmFyaWFibGVzKVxuICogICAgVGhlIE1DUCB0b29sICdnZXRfYnVpbGRfaW5mbycgdGFrZXMgTk8gcGFyYW1ldGVycyAoZW1wdHkgaW5wdXRTY2hlbWEpXG4gKiAgICBObyB1c2VyLXByb3ZpZGVkIGRhdGEgZmxvd3MgdGhyb3VnaCB0aGlzIHNlcnZpY2UgdGhhdCByZXF1aXJlcyBVbmljb2RlIG5vcm1hbGl6YXRpb25cbiAqL1xuXG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcy9wcm9taXNlcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XG5pbXBvcnQgeyBleGVjU3luYyB9IGZyb20gJ2NoaWxkX3Byb2Nlc3MnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vdXRpbHMvbG9nZ2VyLmpzJztcblxuZXhwb3J0IGludGVyZmFjZSBCdWlsZEluZm8ge1xuICBwYWNrYWdlOiB7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIHZlcnNpb246IHN0cmluZztcbiAgfTtcbiAgYnVpbGQ6IHtcbiAgICB0aW1lc3RhbXA/OiBzdHJpbmc7XG4gICAgdHlwZTogJ2dpdCcgfCAnbnBtJyB8ICd1bmtub3duJztcbiAgICBnaXRDb21taXQ/OiBzdHJpbmc7XG4gICAgZ2l0QnJhbmNoPzogc3RyaW5nO1xuICB9O1xuICBydW50aW1lOiB7XG4gICAgbm9kZVZlcnNpb246IHN0cmluZztcbiAgICBwbGF0Zm9ybTogc3RyaW5nO1xuICAgIGFyY2g6IHN0cmluZztcbiAgICB1cHRpbWU6IG51bWJlcjtcbiAgICBtZW1vcnlVc2FnZTogTm9kZUpTLk1lbW9yeVVzYWdlO1xuICB9O1xuICBlbnZpcm9ubWVudDoge1xuICAgIG5vZGVFbnY/OiBzdHJpbmc7XG4gICAgaXNQcm9kdWN0aW9uOiBib29sZWFuO1xuICAgIGlzRGV2ZWxvcG1lbnQ6IGJvb2xlYW47XG4gICAgaXNEZWJ1ZzogYm9vbGVhbjtcbiAgICBpc0RvY2tlcjogYm9vbGVhbjtcbiAgICBkb2NrZXJJbmZvPzogc3RyaW5nO1xuICB9O1xuICBzZXJ2ZXI6IHtcbiAgICBzdGFydFRpbWU6IERhdGU7XG4gICAgdXB0aW1lOiBudW1iZXI7XG4gICAgbWNwQ29ubmVjdGlvbjogYm9vbGVhbjtcbiAgfTtcbn1cblxuZXhwb3J0IGNsYXNzIEJ1aWxkSW5mb1NlcnZpY2Uge1xuICBwcml2YXRlIHN0YXRpYyBpbnN0YW5jZTogQnVpbGRJbmZvU2VydmljZTtcbiAgcHJpdmF0ZSByZWFkb25seSBzdGFydFRpbWU6IERhdGU7XG4gIHByaXZhdGUgcGFja2FnZUluZm8/OiB7IG5hbWU6IHN0cmluZzsgdmVyc2lvbjogc3RyaW5nIH07XG5cbiAgcHJpdmF0ZSBjb25zdHJ1Y3RvcigpIHtcbiAgICB0aGlzLnN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XG4gIH1cblxuICBwdWJsaWMgc3RhdGljIGdldEluc3RhbmNlKCk6IEJ1aWxkSW5mb1NlcnZpY2Uge1xuICAgIGlmICghQnVpbGRJbmZvU2VydmljZS5pbnN0YW5jZSkge1xuICAgICAgQnVpbGRJbmZvU2VydmljZS5pbnN0YW5jZSA9IG5ldyBCdWlsZEluZm9TZXJ2aWNlKCk7XG4gICAgfVxuICAgIHJldHVybiBCdWlsZEluZm9TZXJ2aWNlLmluc3RhbmNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBjb21wcmVoZW5zaXZlIGJ1aWxkIGluZm9ybWF0aW9uXG4gICAqIFNFQ1VSSVRZIE5PVEU6IFRoaXMgbWV0aG9kIHByb2Nlc3NlcyBvbmx5IHN5c3RlbS1nZW5lcmF0ZWQgZGF0YVxuICAgKiBObyB1c2VyIGlucHV0IGlzIGludm9sdmVkIC0gYWxsIGRhdGEgY29tZXMgZnJvbSBmaWxlc3lzdGVtLCBnaXQsIGFuZCBOb2RlLmpzIHByb2Nlc3NcbiAgICovXG4gIHB1YmxpYyBhc3luYyBnZXRCdWlsZEluZm8oKTogUHJvbWlzZTxCdWlsZEluZm8+IHtcbiAgICBjb25zdCBbcGFja2FnZUluZm8sIGdpdEluZm8sIGRvY2tlckluZm9dID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgdGhpcy5nZXRQYWNrYWdlSW5mbygpLFxuICAgICAgdGhpcy5nZXRHaXRJbmZvKCksXG4gICAgICB0aGlzLmdldERvY2tlckluZm8oKVxuICAgIF0pO1xuXG4gICAgY29uc3QgYnVpbGRUaW1lc3RhbXAgPSBhd2FpdCB0aGlzLmdldEJ1aWxkVGltZXN0YW1wKCk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgcGFja2FnZTogcGFja2FnZUluZm8sXG4gICAgICBidWlsZDoge1xuICAgICAgICB0aW1lc3RhbXA6IGJ1aWxkVGltZXN0YW1wLFxuICAgICAgICB0eXBlOiBnaXRJbmZvLmNvbW1pdCA/ICdnaXQnIDogYnVpbGRUaW1lc3RhbXAgPyAnbnBtJyA6ICd1bmtub3duJyxcbiAgICAgICAgZ2l0Q29tbWl0OiBnaXRJbmZvLmNvbW1pdCxcbiAgICAgICAgZ2l0QnJhbmNoOiBnaXRJbmZvLmJyYW5jaFxuICAgICAgfSxcbiAgICAgIHJ1bnRpbWU6IHtcbiAgICAgICAgbm9kZVZlcnNpb246IHByb2Nlc3MudmVyc2lvbixcbiAgICAgICAgcGxhdGZvcm06IHByb2Nlc3MucGxhdGZvcm0sXG4gICAgICAgIGFyY2g6IHByb2Nlc3MuYXJjaCxcbiAgICAgICAgdXB0aW1lOiBwcm9jZXNzLnVwdGltZSgpLFxuICAgICAgICBtZW1vcnlVc2FnZTogcHJvY2Vzcy5tZW1vcnlVc2FnZSgpXG4gICAgICB9LFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgbm9kZUVudjogcHJvY2Vzcy5lbnYuTk9ERV9FTlYsXG4gICAgICAgIGlzUHJvZHVjdGlvbjogcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICdwcm9kdWN0aW9uJyxcbiAgICAgICAgaXNEZXZlbG9wbWVudDogcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICdkZXZlbG9wbWVudCcsXG4gICAgICAgIGlzRGVidWc6IHByb2Nlc3MuZW52LkRFQlVHID09PSAndHJ1ZScgfHwgcHJvY2Vzcy5lbnYuREVCVUcgPT09ICcxJyxcbiAgICAgICAgaXNEb2NrZXI6IGRvY2tlckluZm8uaXNEb2NrZXIsXG4gICAgICAgIGRvY2tlckluZm86IGRvY2tlckluZm8uaW5mb1xuICAgICAgfSxcbiAgICAgIHNlcnZlcjoge1xuICAgICAgICBzdGFydFRpbWU6IHRoaXMuc3RhcnRUaW1lLFxuICAgICAgICB1cHRpbWU6IERhdGUubm93KCkgLSB0aGlzLnN0YXJ0VGltZS5nZXRUaW1lKCksXG4gICAgICAgIG1jcENvbm5lY3Rpb246IHRydWUgLy8gV2UncmUgY29ubmVjdGVkIGlmIHRoaXMgbWV0aG9kIGlzIGJlaW5nIGNhbGxlZCB2aWEgTUNQXG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3JtYXQgYnVpbGQgaW5mbyBhcyB1c2VyLWZyaWVuZGx5IG1hcmtkb3duXG4gICAqIFNFQ1VSSVRZIE5PVEU6IE9ubHkgZm9ybWF0cyBzeXN0ZW0tZ2VuZXJhdGVkIGRhdGEgLSBubyB1c2VyIGlucHV0IHByb2Nlc3NpbmdcbiAgICogQWxsIGlucHV0IGRhdGEgY29tZXMgZnJvbSBnZXRCdWlsZEluZm8oKSB3aGljaCBvbmx5IHJlYWRzIHN5c3RlbSBpbmZvcm1hdGlvblxuICAgKi9cbiAgcHVibGljIGZvcm1hdEJ1aWxkSW5mbyhpbmZvOiBCdWlsZEluZm8pOiBzdHJpbmcge1xuICAgIGNvbnN0IGxpbmVzOiBzdHJpbmdbXSA9IFtdO1xuICAgIFxuICAgIGxpbmVzLnB1c2goJyMg8J+UpyBCdWlsZCBJbmZvcm1hdGlvblxcbicpO1xuICAgIFxuICAgIC8vIFBhY2thZ2UgaW5mb1xuICAgIGxpbmVzLnB1c2goJyMjIPCfk6YgUGFja2FnZScpO1xuICAgIGxpbmVzLnB1c2goYC0gKipOYW1lKio6ICR7aW5mby5wYWNrYWdlLm5hbWV9YCk7XG4gICAgbGluZXMucHVzaChgLSAqKlZlcnNpb24qKjogJHtpbmZvLnBhY2thZ2UudmVyc2lvbn1gKTtcbiAgICBsaW5lcy5wdXNoKCcnKTtcbiAgICBcbiAgICAvLyBCdWlsZCBpbmZvXG4gICAgbGluZXMucHVzaCgnIyMg8J+Pl++4jyBCdWlsZCcpO1xuICAgIGxpbmVzLnB1c2goYC0gKipUeXBlKio6ICR7aW5mby5idWlsZC50eXBlfWApO1xuICAgIGlmIChpbmZvLmJ1aWxkLnRpbWVzdGFtcCkge1xuICAgICAgbGluZXMucHVzaChgLSAqKlRpbWVzdGFtcCoqOiAke2luZm8uYnVpbGQudGltZXN0YW1wfWApO1xuICAgIH1cbiAgICBpZiAoaW5mby5idWlsZC5naXRDb21taXQpIHtcbiAgICAgIGxpbmVzLnB1c2goYC0gKipHaXQgQ29tbWl0Kio6IFxcYCR7aW5mby5idWlsZC5naXRDb21taXR9XFxgYCk7XG4gICAgfVxuICAgIGlmIChpbmZvLmJ1aWxkLmdpdEJyYW5jaCkge1xuICAgICAgbGluZXMucHVzaChgLSAqKkdpdCBCcmFuY2gqKjogJHtpbmZvLmJ1aWxkLmdpdEJyYW5jaH1gKTtcbiAgICB9XG4gICAgbGluZXMucHVzaCgnJyk7XG4gICAgXG4gICAgLy8gUnVudGltZSBpbmZvXG4gICAgbGluZXMucHVzaCgnIyMg8J+SuyBSdW50aW1lJyk7XG4gICAgbGluZXMucHVzaChgLSAqKk5vZGUuanMqKjogJHtpbmZvLnJ1bnRpbWUubm9kZVZlcnNpb259YCk7XG4gICAgbGluZXMucHVzaChgLSAqKlBsYXRmb3JtKio6ICR7aW5mby5ydW50aW1lLnBsYXRmb3JtfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipBcmNoaXRlY3R1cmUqKjogJHtpbmZvLnJ1bnRpbWUuYXJjaH1gKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqUHJvY2VzcyBVcHRpbWUqKjogJHt0aGlzLmZvcm1hdFVwdGltZShpbmZvLnJ1bnRpbWUudXB0aW1lKX1gKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqTWVtb3J5IFVzYWdlKio6ICR7dGhpcy5mb3JtYXRNZW1vcnkoaW5mby5ydW50aW1lLm1lbW9yeVVzYWdlLmhlYXBVc2VkKX0gLyAke3RoaXMuZm9ybWF0TWVtb3J5KGluZm8ucnVudGltZS5tZW1vcnlVc2FnZS5oZWFwVG90YWwpfWApO1xuICAgIGxpbmVzLnB1c2goJycpO1xuICAgIFxuICAgIC8vIEVudmlyb25tZW50IGluZm9cbiAgICBsaW5lcy5wdXNoKCcjIyDimpnvuI8gRW52aXJvbm1lbnQnKTtcbiAgICBsaW5lcy5wdXNoKGAtICoqTk9ERV9FTlYqKjogJHtpbmZvLmVudmlyb25tZW50Lm5vZGVFbnYgfHwgJ25vdCBzZXQnfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipNb2RlKio6ICR7aW5mby5lbnZpcm9ubWVudC5pc1Byb2R1Y3Rpb24gPyAnUHJvZHVjdGlvbicgOiBpbmZvLmVudmlyb25tZW50LmlzRGV2ZWxvcG1lbnQgPyAnRGV2ZWxvcG1lbnQnIDogJ1Vua25vd24nfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipEZWJ1ZyoqOiAke2luZm8uZW52aXJvbm1lbnQuaXNEZWJ1ZyA/ICdFbmFibGVkJyA6ICdEaXNhYmxlZCd9YCk7XG4gICAgbGluZXMucHVzaChgLSAqKkRvY2tlcioqOiAke2luZm8uZW52aXJvbm1lbnQuaXNEb2NrZXIgPyAnWWVzJyA6ICdObyd9YCk7XG4gICAgaWYgKGluZm8uZW52aXJvbm1lbnQuZG9ja2VySW5mbykge1xuICAgICAgbGluZXMucHVzaChgLSAqKkNvbnRhaW5lcioqOiAke2luZm8uZW52aXJvbm1lbnQuZG9ja2VySW5mb31gKTtcbiAgICB9XG4gICAgbGluZXMucHVzaCgnJyk7XG4gICAgXG4gICAgLy8gU2VydmVyIGluZm9cbiAgICBsaW5lcy5wdXNoKCcjIyDwn5qAIFNlcnZlcicpO1xuICAgIGxpbmVzLnB1c2goYC0gKipTdGFydGVkKio6ICR7aW5mby5zZXJ2ZXIuc3RhcnRUaW1lLnRvSVNPU3RyaW5nKCl9YCk7XG4gICAgbGluZXMucHVzaChgLSAqKlVwdGltZSoqOiAke3RoaXMuZm9ybWF0VXB0aW1lKGluZm8uc2VydmVyLnVwdGltZSAvIDEwMDApfWApO1xuICAgIGxpbmVzLnB1c2goYC0gKipNQ1AgQ29ubmVjdGlvbioqOiAke2luZm8uc2VydmVyLm1jcENvbm5lY3Rpb24gPyAn4pyFIENvbm5lY3RlZCcgOiAn4p2MIERpc2Nvbm5lY3RlZCd9YCk7XG4gICAgXG4gICAgcmV0dXJuIGxpbmVzLmpvaW4oJ1xcbicpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNFQ1VSSVRZIE5PVEU6IE5vIFVuaWNvZGUgbm9ybWFsaXphdGlvbiBuZWVkZWQgLSByZWFkcyBhcHBsaWNhdGlvbidzIG93biBwYWNrYWdlLmpzb25cbiAgICogRGF0YSBzb3VyY2U6IENvbnRyb2xsZWQgZmlsZSBzeXN0ZW0gcGF0aCwgbm8gdXNlciBpbnB1dFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRQYWNrYWdlSW5mbygpOiBQcm9taXNlPHsgbmFtZTogc3RyaW5nOyB2ZXJzaW9uOiBzdHJpbmcgfT4ge1xuICAgIGlmICh0aGlzLnBhY2thZ2VJbmZvKSB7XG4gICAgICByZXR1cm4gdGhpcy5wYWNrYWdlSW5mbztcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgX19maWxlbmFtZSA9IGZpbGVVUkxUb1BhdGgoaW1wb3J0Lm1ldGEudXJsKTtcbiAgICAgIGNvbnN0IF9fZGlybmFtZSA9IHBhdGguZGlybmFtZShfX2ZpbGVuYW1lKTtcbiAgICAgIFxuICAgICAgLy8gVHJ5IG11bHRpcGxlIHBhdGhzIHRvIGZpbmQgcGFja2FnZS5qc29uXG4gICAgICAvLyBUaGlzIGhhbmRsZXMgYm90aCBub3JtYWwgZXhlY3V0aW9uIGFuZCBjb21waWxlZCB0ZXN0IHNjZW5hcmlvc1xuICAgICAgY29uc3QgcG9zc2libGVQYXRocyA9IFtcbiAgICAgICAgcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uJywgJy4uJywgJ3BhY2thZ2UuanNvbicpLCAvLyBOb3JtYWw6IGRpc3Qvc2VydmljZXMgLT4gcm9vdFxuICAgICAgICBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nLCAnLi4nLCAnLi4nLCAncGFja2FnZS5qc29uJyksIC8vIFRlc3Q6IGRpc3QvdGVzdC9zZXJ2aWNlcyAtPiByb290XG4gICAgICAgIHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICcuLicsICcuLicsICcuLicsICdwYWNrYWdlLmpzb24nKSwgLy8gRGVlcCB0ZXN0OiBkaXN0L3Rlc3QvZGVlcC9zZXJ2aWNlcyAtPiByb290XG4gICAgICAgIHBhdGguam9pbihwcm9jZXNzLmN3ZCgpLCAncGFja2FnZS5qc29uJykgLy8gRmFsbGJhY2sgdG8gY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeVxuICAgICAgXTtcbiAgICAgIFxuICAgICAgbGV0IHBrZzogYW55ID0gbnVsbDtcbiAgICAgIFxuICAgICAgZm9yIChjb25zdCBwYWNrYWdlUGF0aCBvZiBwb3NzaWJsZVBhdGhzKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gU0VDVVJJVFkgTk9URTogUmVhZGluZyBvdXIgb3duIHBhY2thZ2UuanNvbiBmaWxlIC0gbm90IHVzZXIgaW5wdXRcbiAgICAgICAgICAvLyBUaGlzIGZpbGUgaXMgY29udHJvbGxlZCBieSB0aGUgYXBwbGljYXRpb24sIG5vIFVuaWNvZGUgbm9ybWFsaXphdGlvbiBuZWVkZWRcbiAgICAgICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUocGFja2FnZVBhdGgsICd1dGYtOCcpO1xuICAgICAgICAgIHBrZyA9IEpTT04ucGFyc2UoY29udGVudCk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIFRyeSBuZXh0IHBhdGhcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICBpZiAoIXBrZykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBmaW5kIHBhY2thZ2UuanNvbiBpbiBhbnkgZXhwZWN0ZWQgbG9jYXRpb24nKTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgdGhpcy5wYWNrYWdlSW5mbyA9IHtcbiAgICAgICAgbmFtZTogcGtnLm5hbWUgfHwgJ3Vua25vd24nLFxuICAgICAgICB2ZXJzaW9uOiBwa2cudmVyc2lvbiB8fCAndW5rbm93bidcbiAgICAgIH07XG4gICAgICBcbiAgICAgIHJldHVybiB0aGlzLnBhY2thZ2VJbmZvO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dnZXIuZGVidWcoJ0ZhaWxlZCB0byByZWFkIHBhY2thZ2UuanNvbjonLCBlcnJvcik7XG4gICAgICByZXR1cm4geyBuYW1lOiAndW5rbm93bicsIHZlcnNpb246ICd1bmtub3duJyB9O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTRUNVUklUWSBOT1RFOiBObyBVbmljb2RlIG5vcm1hbGl6YXRpb24gbmVlZGVkIC0gcmVhZHMgYnVpbGQtZ2VuZXJhdGVkIHZlcnNpb24gZmlsZVxuICAgKiBEYXRhIHNvdXJjZTogQnVpbGQgc3lzdGVtIG91dHB1dCBmaWxlLCBubyB1c2VyIGlucHV0XG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGdldEJ1aWxkVGltZXN0YW1wKCk6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IF9fZmlsZW5hbWUgPSBmaWxlVVJMVG9QYXRoKGltcG9ydC5tZXRhLnVybCk7XG4gICAgICBjb25zdCBfX2Rpcm5hbWUgPSBwYXRoLmRpcm5hbWUoX19maWxlbmFtZSk7XG4gICAgICBcbiAgICAgIC8vIFRyeSBtdWx0aXBsZSBwYXRocyB0byBmaW5kIHZlcnNpb24uanNvblxuICAgICAgLy8gVGhpcyBoYW5kbGVzIGJvdGggbm9ybWFsIGV4ZWN1dGlvbiBhbmQgY29tcGlsZWQgdGVzdCBzY2VuYXJpb3NcbiAgICAgIGNvbnN0IHBvc3NpYmxlUGF0aHMgPSBbXG4gICAgICAgIHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICcuLicsICdkaXN0JywgJ3ZlcnNpb24uanNvbicpLCAvLyBOb3JtYWwgbG9jYXRpb25cbiAgICAgICAgcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uJywgJy4uJywgJy4uJywgJ2Rpc3QnLCAndmVyc2lvbi5qc29uJyksIC8vIFRlc3Qgc2NlbmFyaW9cbiAgICAgICAgcGF0aC5qb2luKHByb2Nlc3MuY3dkKCksICdkaXN0JywgJ3ZlcnNpb24uanNvbicpIC8vIEZhbGxiYWNrIHRvIGN3ZFxuICAgICAgXTtcbiAgICAgIFxuICAgICAgZm9yIChjb25zdCB2ZXJzaW9uUGF0aCBvZiBwb3NzaWJsZVBhdGhzKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgY29udGVudCA9IGF3YWl0IGZzLnJlYWRGaWxlKHZlcnNpb25QYXRoLCAndXRmLTgnKTtcbiAgICAgICAgICBjb25zdCB2ZXJzaW9uID0gSlNPTi5wYXJzZShjb250ZW50KTtcbiAgICAgICAgICByZXR1cm4gdmVyc2lvbi5idWlsZFRpbWUgfHwgdmVyc2lvbi50aW1lc3RhbXA7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIFRyeSBuZXh0IHBhdGhcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgXG4gICAgICAvLyBWZXJzaW9uIGZpbGUgbWlnaHQgbm90IGV4aXN0LCB0aGF0J3Mgb2theVxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIFZlcnNpb24gZmlsZSBtaWdodCBub3QgZXhpc3QsIHRoYXQncyBva2F5XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTRUNVUklUWSBOT1RFOiBObyBVbmljb2RlIG5vcm1hbGl6YXRpb24gbmVlZGVkIC0gZXhlY3V0ZXMgc3lzdGVtIGdpdCBjb21tYW5kc1xuICAgKiBEYXRhIHNvdXJjZTogR2l0IENMSSBvdXRwdXQgKHN5c3RlbS1jb250cm9sbGVkKSwgbm8gdXNlciBpbnB1dFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBnZXRHaXRJbmZvKCk6IFByb21pc2U8eyBjb21taXQ/OiBzdHJpbmc7IGJyYW5jaD86IHN0cmluZyB9PiB7XG4gICAgdHJ5IHtcbiAgICAgIC8vIFNFQ1VSSVRZIE5PVEU6IEdpdCBjb21tYW5kcyByZXR1cm4gc3lzdGVtLWNvbnRyb2xsZWQgZGF0YSAtIG5vdCB1c2VyIGlucHV0XG4gICAgICAvLyBHaXQgY29tbWl0IGhhc2hlcyBhbmQgYnJhbmNoIG5hbWVzIGFyZSBjb250cm9sbGVkIGJ5IGdpdCwgbm8gVW5pY29kZSBub3JtYWxpemF0aW9uIG5lZWRlZFxuICAgICAgY29uc3QgY29tbWl0ID0gZXhlY1N5bmMoJ2dpdCByZXYtcGFyc2UgLS1zaG9ydCBIRUFEJywgeyBlbmNvZGluZzogJ3V0Zi04JyB9KS50cmltKCk7XG4gICAgICBjb25zdCBicmFuY2ggPSBleGVjU3luYygnZ2l0IHJldi1wYXJzZSAtLWFiYnJldi1yZWYgSEVBRCcsIHsgZW5jb2Rpbmc6ICd1dGYtOCcgfSkudHJpbSgpO1xuICAgICAgXG4gICAgICByZXR1cm4geyBjb21taXQsIGJyYW5jaCB9O1xuICAgIH0gY2F0Y2gge1xuICAgICAgLy8gTm90IGluIGEgZ2l0IHJlcG9zaXRvcnkgb3IgZ2l0IG5vdCBhdmFpbGFibGVcbiAgICAgIHJldHVybiB7fTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU0VDVVJJVFkgTk9URTogTm8gVW5pY29kZSBub3JtYWxpemF0aW9uIG5lZWRlZCAtIHJlYWRzIGNvbnRhaW5lciBydW50aW1lIGZpbGVzXG4gICAqIERhdGEgc291cmNlOiBTeXN0ZW0gY2dyb3VwIGZpbGVzIChjb250YWluZXItY29udHJvbGxlZCksIG5vIHVzZXIgaW5wdXRcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2V0RG9ja2VySW5mbygpOiBQcm9taXNlPHsgaXNEb2NrZXI6IGJvb2xlYW47IGluZm8/OiBzdHJpbmcgfT4ge1xuICAgIHRyeSB7XG4gICAgICAvLyBTRUNVUklUWSBOT1RFOiBSZWFkaW5nIHN5c3RlbSBjZ3JvdXAgZmlsZSAtIGNvbnRyb2xsZWQgYnkgY29udGFpbmVyIHJ1bnRpbWUsIG5vdCB1c2VyIGlucHV0XG4gICAgICAvLyBDb250YWluZXIgcnVudGltZSBnZW5lcmF0ZXMgdGhpcyBmaWxlIGNvbnRlbnQsIG5vIFVuaWNvZGUgbm9ybWFsaXphdGlvbiBuZWVkZWRcbiAgICAgIGNvbnN0IGNncm91cENvbnRlbnQgPSBhd2FpdCBmcy5yZWFkRmlsZSgnL3Byb2MvMS9jZ3JvdXAnLCAndXRmLTgnKTtcbiAgICAgIGNvbnN0IGlzRG9ja2VyID0gY2dyb3VwQ29udGVudC5pbmNsdWRlcygnZG9ja2VyJykgfHwgY2dyb3VwQ29udGVudC5pbmNsdWRlcygnY29udGFpbmVyZCcpO1xuICAgICAgXG4gICAgICBpZiAoaXNEb2NrZXIpIHtcbiAgICAgICAgLy8gVHJ5IHRvIGdldCBjb250YWluZXIgSURcbiAgICAgICAgY29uc3QgY29udGFpbmVySWQgPSBjZ3JvdXBDb250ZW50XG4gICAgICAgICAgLnNwbGl0KCdcXG4nKVxuICAgICAgICAgIC5maW5kKGxpbmUgPT4gbGluZS5pbmNsdWRlcygnZG9ja2VyJykpXG4gICAgICAgICAgPy5zcGxpdCgnLycpXG4gICAgICAgICAgLnBvcCgpXG4gICAgICAgICAgPy5zdWJzdHJpbmcoMCwgMTIpO1xuICAgICAgICBcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBpc0RvY2tlcjogdHJ1ZSxcbiAgICAgICAgICBpbmZvOiBjb250YWluZXJJZCA/IGBDb250YWluZXIgSUQ6ICR7Y29udGFpbmVySWR9YCA6ICdSdW5uaW5nIGluIERvY2tlcidcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICAgIFxuICAgICAgcmV0dXJuIHsgaXNEb2NrZXI6IGZhbHNlIH07XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBOb3QgaW4gRG9ja2VyIG9yIC9wcm9jIG5vdCBhdmFpbGFibGVcbiAgICAgIHJldHVybiB7IGlzRG9ja2VyOiBmYWxzZSB9O1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZm9ybWF0VXB0aW1lKHNlY29uZHM6IG51bWJlcik6IHN0cmluZyB7XG4gICAgY29uc3QgZGF5cyA9IE1hdGguZmxvb3Ioc2Vjb25kcyAvIDg2NDAwKTtcbiAgICBjb25zdCBob3VycyA9IE1hdGguZmxvb3IoKHNlY29uZHMgJSA4NjQwMCkgLyAzNjAwKTtcbiAgICBjb25zdCBtaW51dGVzID0gTWF0aC5mbG9vcigoc2Vjb25kcyAlIDM2MDApIC8gNjApO1xuICAgIGNvbnN0IHNlY3MgPSBNYXRoLmZsb29yKHNlY29uZHMgJSA2MCk7XG4gICAgXG4gICAgY29uc3QgcGFydHM6IHN0cmluZ1tdID0gW107XG4gICAgaWYgKGRheXMgPiAwKSBwYXJ0cy5wdXNoKGAke2RheXN9ZGApO1xuICAgIGlmIChob3VycyA+IDApIHBhcnRzLnB1c2goYCR7aG91cnN9aGApO1xuICAgIGlmIChtaW51dGVzID4gMCkgcGFydHMucHVzaChgJHttaW51dGVzfW1gKTtcbiAgICBpZiAoc2VjcyA+IDAgfHwgcGFydHMubGVuZ3RoID09PSAwKSBwYXJ0cy5wdXNoKGAke3NlY3N9c2ApO1xuICAgIFxuICAgIHJldHVybiBwYXJ0cy5qb2luKCcgJyk7XG4gIH1cblxuICBwcml2YXRlIGZvcm1hdE1lbW9yeShieXRlczogbnVtYmVyKTogc3RyaW5nIHtcbiAgICBjb25zdCBtYiA9IGJ5dGVzIC8gMTAyNCAvIDEwMjQ7XG4gICAgcmV0dXJuIGAke21iLnRvRml4ZWQoMSl9IE1CYDtcbiAgfVxufSJdfQ==
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Adapter to convert simple portfolio elements to full IElement interface
3
+ * This resolves type safety issues without complex type casting
4
+ *
5
+ * FIXES IMPLEMENTED (PR #503):
6
+ * 1. TYPE SAFETY (Issue #497): Eliminates complex type casting with adapter pattern
7
+ * 2. SECURITY FIX DMCP-SEC-004 (MEDIUM): Added Unicode normalization for all user input
8
+ * 3. SECURITY FIX DMCP-SEC-006 (LOW): Added audit logging for element creation
9
+ * 4. PERFORMANCE: Helper methods for efficient string normalization
10
+ */
11
+ import { IElement, IElementMetadata, ElementValidationResult, ElementStatus } from '../../types/elements/IElement.js';
12
+ import { ElementType } from '../../portfolio/types.js';
13
+ import { PortfolioElement } from './submitToPortfolioTool.js';
14
+ /**
15
+ * Adapter class that wraps a simple PortfolioElement and implements IElement
16
+ * This allows us to pass portfolio elements to methods expecting IElement
17
+ * without complex type casting
18
+ */
19
+ export declare class PortfolioElementAdapter implements IElement {
20
+ readonly id: string;
21
+ readonly type: ElementType;
22
+ readonly version: string;
23
+ readonly metadata: IElementMetadata;
24
+ private readonly portfolioElement;
25
+ constructor(element: PortfolioElement);
26
+ /**
27
+ * Helper to normalize string values safely
28
+ */
29
+ private normalizeString;
30
+ /**
31
+ * Validate the element
32
+ */
33
+ validate(): ElementValidationResult;
34
+ /**
35
+ * Serialize the element to markdown with YAML frontmatter
36
+ * FIX: Changed from JSON to markdown format for GitHub portfolio compatibility
37
+ * SECURITY FIX #544: Parse and validate existing frontmatter instead of returning as-is
38
+ * SECURITY FIX #543: Use gray-matter for robust frontmatter detection
39
+ */
40
+ serialize(): string;
41
+ /**
42
+ * Deserialize from string (not implemented for adapter)
43
+ */
44
+ deserialize(data: string): void;
45
+ /**
46
+ * Get element status
47
+ */
48
+ getStatus(): ElementStatus;
49
+ /**
50
+ * Get the original portfolio element content
51
+ */
52
+ getContent(): string;
53
+ }
54
+ //# sourceMappingURL=PortfolioElementAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PortfolioElementAdapter.d.ts","sourceRoot":"","sources":["../../../src/tools/portfolio/PortfolioElementAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,QAAQ,EACR,gBAAgB,EAChB,uBAAuB,EACvB,aAAa,EAGd,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAQ9D;;;;GAIG;AACH,qBAAa,uBAAwB,YAAW,QAAQ;IACtD,SAAgB,EAAE,EAAE,MAAM,CAAC;IAC3B,SAAgB,IAAI,EAAE,WAAW,CAAC;IAClC,SAAgB,OAAO,EAAE,MAAM,CAAC;IAChC,SAAgB,QAAQ,EAAE,gBAAgB,CAAC;IAC3C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;gBAExC,OAAO,EAAE,gBAAgB;IAsDrC;;OAEG;IACH,OAAO,CAAC,eAAe;IAMvB;;OAEG;IACH,QAAQ,IAAI,uBAAuB;IAyBnC;;;;;OAKG;IACH,SAAS,IAAI,MAAM;IA2GnB;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI/B;;OAEG;IACH,SAAS,IAAI,aAAa;IAI1B;;OAEG;IACH,UAAU,IAAI,MAAM;CAGrB"}
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Adapter to convert simple portfolio elements to full IElement interface
3
+ * This resolves type safety issues without complex type casting
4
+ *
5
+ * FIXES IMPLEMENTED (PR #503):
6
+ * 1. TYPE SAFETY (Issue #497): Eliminates complex type casting with adapter pattern
7
+ * 2. SECURITY FIX DMCP-SEC-004 (MEDIUM): Added Unicode normalization for all user input
8
+ * 3. SECURITY FIX DMCP-SEC-006 (LOW): Added audit logging for element creation
9
+ * 4. PERFORMANCE: Helper methods for efficient string normalization
10
+ */
11
+ import { ElementStatus } from '../../types/elements/IElement.js';
12
+ import { UnicodeValidator } from '../../security/validators/unicodeValidator.js';
13
+ import { SecurityMonitor } from '../../security/securityMonitor.js';
14
+ import { logger } from '../../utils/logger.js';
15
+ import * as yaml from 'js-yaml';
16
+ import matter from 'gray-matter';
17
+ import { ContentValidator } from '../../security/contentValidator.js';
18
+ /**
19
+ * Adapter class that wraps a simple PortfolioElement and implements IElement
20
+ * This allows us to pass portfolio elements to methods expecting IElement
21
+ * without complex type casting
22
+ */
23
+ export class PortfolioElementAdapter {
24
+ id;
25
+ type;
26
+ version;
27
+ metadata;
28
+ portfolioElement;
29
+ constructor(element) {
30
+ // SECURITY FIX #2 (DMCP-SEC-004): Normalize and validate all user input
31
+ // Previously: User input was used directly without validation
32
+ // Now: All string inputs go through UnicodeValidator to prevent homograph attacks
33
+ const normalizedName = UnicodeValidator.normalize(element.metadata.name);
34
+ if (!normalizedName.isValid) {
35
+ // Log security event for invalid Unicode
36
+ SecurityMonitor.logSecurityEvent({
37
+ type: 'UNICODE_VALIDATION_ERROR',
38
+ severity: 'MEDIUM',
39
+ source: 'PortfolioElementAdapter.constructor',
40
+ details: `Invalid Unicode in element name: ${normalizedName.detectedIssues?.[0] || 'unknown'}`
41
+ });
42
+ logger.warn('Invalid Unicode detected in element name', {
43
+ issues: normalizedName.detectedIssues
44
+ });
45
+ }
46
+ this.portfolioElement = element;
47
+ this.type = element.type;
48
+ this.version = element.metadata.version || '1.0.0';
49
+ // Generate ID from type and normalized name
50
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
51
+ const safeName = normalizedName.normalizedContent || element.metadata.name;
52
+ const nameSlug = safeName.toLowerCase().replace(/\s+/g, '-');
53
+ this.id = `${element.type}_${nameSlug}_${timestamp}`;
54
+ // Convert metadata to IElementMetadata format with normalized values
55
+ this.metadata = {
56
+ name: safeName,
57
+ description: this.normalizeString(element.metadata.description || ''),
58
+ author: this.normalizeString(element.metadata.author || ''),
59
+ version: element.metadata.version,
60
+ created: element.metadata.created,
61
+ modified: element.metadata.updated,
62
+ tags: []
63
+ };
64
+ // SECURITY FIX #3 (DMCP-SEC-006): Log element creation for audit trail
65
+ // Previously: No audit logging for portfolio operations
66
+ // Now: Complete audit trail using SecurityMonitor.logSecurityEvent()
67
+ SecurityMonitor.logSecurityEvent({
68
+ type: 'ELEMENT_CREATED',
69
+ severity: 'LOW',
70
+ source: 'PortfolioElementAdapter.constructor',
71
+ details: `Created portfolio element adapter: ${this.id}`,
72
+ metadata: {
73
+ elementType: this.type,
74
+ elementId: this.id
75
+ }
76
+ });
77
+ }
78
+ /**
79
+ * Helper to normalize string values safely
80
+ */
81
+ normalizeString(value) {
82
+ if (!value)
83
+ return value;
84
+ const normalized = UnicodeValidator.normalize(value);
85
+ return normalized.normalizedContent || value;
86
+ }
87
+ /**
88
+ * Validate the element
89
+ */
90
+ validate() {
91
+ const errors = [];
92
+ const warnings = [];
93
+ if (!this.metadata.name) {
94
+ errors.push({
95
+ field: 'name',
96
+ message: 'Element name is required'
97
+ });
98
+ }
99
+ if (!this.portfolioElement.content) {
100
+ errors.push({
101
+ field: 'content',
102
+ message: 'Element content is required'
103
+ });
104
+ }
105
+ return {
106
+ valid: errors.length === 0,
107
+ errors: errors.length > 0 ? errors : undefined,
108
+ warnings: warnings.length > 0 ? warnings : undefined
109
+ };
110
+ }
111
+ /**
112
+ * Serialize the element to markdown with YAML frontmatter
113
+ * FIX: Changed from JSON to markdown format for GitHub portfolio compatibility
114
+ * SECURITY FIX #544: Parse and validate existing frontmatter instead of returning as-is
115
+ * SECURITY FIX #543: Use gray-matter for robust frontmatter detection
116
+ */
117
+ serialize() {
118
+ // SECURITY FIX #543: Use gray-matter for robust frontmatter detection
119
+ // This handles different line endings, whitespace variations, and malformed YAML
120
+ let contentToProcess = this.portfolioElement.content;
121
+ let existingMetadata = {};
122
+ let bodyContent = contentToProcess;
123
+ // Try to parse existing frontmatter if present
124
+ try {
125
+ // gray-matter handles all edge cases:
126
+ // - Different line endings (\n, \r\n)
127
+ // - Whitespace variations
128
+ // - Malformed YAML (returns empty data object)
129
+ // - Missing closing delimiter
130
+ const parsed = matter(contentToProcess);
131
+ if (parsed.data && Object.keys(parsed.data).length > 0) {
132
+ // SECURITY FIX #544: Validate existing frontmatter instead of bypassing
133
+ logger.debug('Found existing frontmatter, validating before merge');
134
+ // Validate the parsed frontmatter
135
+ const validationResult = ContentValidator.validateAndSanitize(yaml.dump(parsed.data));
136
+ if (!validationResult.isValid && validationResult.severity === 'critical') {
137
+ // Log security event for malicious frontmatter
138
+ SecurityMonitor.logSecurityEvent({
139
+ type: 'CONTENT_INJECTION_ATTEMPT',
140
+ severity: 'HIGH',
141
+ source: 'PortfolioElementAdapter.serialize',
142
+ details: `Critical security issues in frontmatter: ${validationResult.detectedPatterns?.join(', ')}`,
143
+ metadata: {
144
+ elementId: this.id,
145
+ elementType: this.type
146
+ }
147
+ });
148
+ // Don't use the malicious frontmatter, create new
149
+ existingMetadata = {};
150
+ bodyContent = contentToProcess; // Use original content
151
+ }
152
+ else {
153
+ // Frontmatter is safe, merge with our metadata
154
+ existingMetadata = parsed.data;
155
+ bodyContent = parsed.content;
156
+ }
157
+ }
158
+ }
159
+ catch (error) {
160
+ // If gray-matter fails to parse, treat as content without frontmatter
161
+ logger.warn('Failed to parse potential frontmatter, treating as plain content', {
162
+ error: error instanceof Error ? error.message : String(error)
163
+ });
164
+ // Continue with empty metadata and full content
165
+ }
166
+ // Merge metadata, with our metadata taking precedence for security
167
+ // This ensures critical fields like ID and type are always from our validated source
168
+ const mergedMetadata = {
169
+ ...existingMetadata, // Existing metadata first
170
+ ...this.metadata, // Our validated metadata overwrites
171
+ id: this.id, // Always use our ID
172
+ type: this.type, // Always use our type
173
+ version: this.version // Always use our version
174
+ };
175
+ // Validate the final merged metadata
176
+ const metadataYaml = yaml.dump(mergedMetadata, {
177
+ noRefs: true,
178
+ sortKeys: false,
179
+ lineWidth: -1
180
+ });
181
+ // Final security check on the complete metadata
182
+ const finalValidation = ContentValidator.validateAndSanitize(metadataYaml);
183
+ if (!finalValidation.isValid && finalValidation.severity === 'critical') {
184
+ // This shouldn't happen with our sanitized data, but log if it does
185
+ SecurityMonitor.logSecurityEvent({
186
+ type: 'UNICODE_VALIDATION_ERROR',
187
+ severity: 'MEDIUM',
188
+ source: 'PortfolioElementAdapter.serialize',
189
+ details: 'Final metadata validation failed after merge',
190
+ metadata: { elementId: this.id }
191
+ });
192
+ // Fall back to minimal safe metadata
193
+ const safeMetadata = {
194
+ id: this.id,
195
+ type: this.type,
196
+ version: this.version,
197
+ name: this.normalizeString(this.metadata.name || 'Untitled'),
198
+ description: this.normalizeString(this.metadata.description || '')
199
+ };
200
+ const safeFrontmatter = yaml.dump(safeMetadata, {
201
+ noRefs: true,
202
+ sortKeys: false,
203
+ lineWidth: -1
204
+ });
205
+ return `---\n${safeFrontmatter}---\n\n${bodyContent}`;
206
+ }
207
+ // Return validated and sanitized markdown with frontmatter
208
+ return `---\n${metadataYaml}---\n\n${bodyContent}`;
209
+ }
210
+ /**
211
+ * Deserialize from string (not implemented for adapter)
212
+ */
213
+ deserialize(data) {
214
+ throw new Error('Deserialization not supported for PortfolioElementAdapter');
215
+ }
216
+ /**
217
+ * Get element status
218
+ */
219
+ getStatus() {
220
+ return ElementStatus.INACTIVE;
221
+ }
222
+ /**
223
+ * Get the original portfolio element content
224
+ */
225
+ getContent() {
226
+ return this.portfolioElement.content;
227
+ }
228
+ }
229
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUG9ydGZvbGlvRWxlbWVudEFkYXB0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdG9vbHMvcG9ydGZvbGlvL1BvcnRmb2xpb0VsZW1lbnRBZGFwdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7R0FTRztBQUVILE9BQU8sRUFJTCxhQUFhLEVBR2QsTUFBTSxrQ0FBa0MsQ0FBQztBQUcxQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQztBQUNqRixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUNBQW1DLENBQUM7QUFDcEUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQy9DLE9BQU8sS0FBSyxJQUFJLE1BQU0sU0FBUyxDQUFDO0FBQ2hDLE9BQU8sTUFBTSxNQUFNLGFBQWEsQ0FBQztBQUNqQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUV0RTs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLHVCQUF1QjtJQUNsQixFQUFFLENBQVM7SUFDWCxJQUFJLENBQWM7SUFDbEIsT0FBTyxDQUFTO0lBQ2hCLFFBQVEsQ0FBbUI7SUFDMUIsZ0JBQWdCLENBQW1CO0lBRXBELFlBQVksT0FBeUI7UUFDbkMsd0VBQXdFO1FBQ3hFLDhEQUE4RDtRQUM5RCxrRkFBa0Y7UUFDbEYsTUFBTSxjQUFjLEdBQUcsZ0JBQWdCLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDekUsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUM1Qix5Q0FBeUM7WUFDekMsZUFBZSxDQUFDLGdCQUFnQixDQUFDO2dCQUMvQixJQUFJLEVBQUUsMEJBQTBCO2dCQUNoQyxRQUFRLEVBQUUsUUFBUTtnQkFDbEIsTUFBTSxFQUFFLHFDQUFxQztnQkFDN0MsT0FBTyxFQUFFLG9DQUFvQyxjQUFjLENBQUMs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QUM7WUFFRixNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRTtnQkFDOUMsTUFBTSxFQUFFLElBQUk7Z0JBQ1osUUFBUSxFQUFFLEtBQUs7Z0JBQ2YsU0FBUyxFQUFFLENBQUMsQ0FBQzthQUNkLENBQUMsQ0FBQztZQUVILE9BQU8sUUFBUSxlQUFlLFVBQVUsV0FBVyxFQUFFLENBQUM7UUFDeEQsQ0FBQztRQUVELDJEQUEyRDtRQUMzRCxPQUFPLFFBQVEsWUFBWSxVQUFVLFdBQVcsRUFBRSxDQUFDO0lBQ3JELENBQUM7SUFFRDs7T0FFRztJQUNILFdBQVcsQ0FBQyxJQUFZO1FBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMsMkRBQTJELENBQUMsQ0FBQztJQUMvRSxDQUFDO0lBRUQ7O09BRUc7SUFDSCxTQUFTO1FBQ1AsT0FBTyxhQUFhLENBQUMsUUFBUSxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7T0FFRztJQUNILFVBQVU7UUFDUixPQUFPLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPLENBQUM7SUFDdkMsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBZGFwdGVyIHRvIGNvbnZlcnQgc2ltcGxlIHBvcnRmb2xpbyBlbGVtZW50cyB0byBmdWxsIElFbGVtZW50IGludGVyZmFjZVxuICogVGhpcyByZXNvbHZlcyB0eXBlIHNhZmV0eSBpc3N1ZXMgd2l0aG91dCBjb21wbGV4IHR5cGUgY2FzdGluZ1xuICogXG4gKiBGSVhFUyBJTVBMRU1FTlRFRCAoUFIgIzUwMyk6XG4gKiAxLiBUWVBFIFNBRkVUWSAoSXNzdWUgIzQ5Nyk6IEVsaW1pbmF0ZXMgY29tcGxleCB0eXBlIGNhc3Rpbmcgd2l0aCBhZGFwdGVyIHBhdHRlcm5cbiAqIDIuIFNFQ1VSSVRZIEZJWCBETUNQLVNFQy0wMDQgKE1FRElVTSk6IEFkZGVkIFVuaWNvZGUgbm9ybWFsaXphdGlvbiBmb3IgYWxsIHVzZXIgaW5wdXRcbiAqIDMuIFNFQ1VSSVRZIEZJWCBETUNQLVNFQy0wMDYgKExPVyk6IEFkZGVkIGF1ZGl0IGxvZ2dpbmcgZm9yIGVsZW1lbnQgY3JlYXRpb25cbiAqIDQuIFBFUkZPUk1BTkNFOiBIZWxwZXIgbWV0aG9kcyBmb3IgZWZmaWNpZW50IHN0cmluZyBub3JtYWxpemF0aW9uXG4gKi9cblxuaW1wb3J0IHsgXG4gIElFbGVtZW50LCBcbiAgSUVsZW1lbnRNZXRhZGF0YSwgXG4gIEVsZW1lbnRWYWxpZGF0aW9uUmVzdWx0LCBcbiAgRWxlbWVudFN0YXR1cyxcbiAgVmFsaWRhdGlvbkVycm9yLFxuICBWYWxpZGF0aW9uV2FybmluZ1xufSBmcm9tICcuLi8uLi90eXBlcy9lbGVtZW50cy9JRWxlbWVudC5qcyc7XG5pbXBvcnQgeyBFbGVtZW50VHlwZSB9IGZyb20gJy4uLy4uL3BvcnRmb2xpby90eXBlcy5qcyc7XG5pbXBvcnQgeyBQb3J0Zm9saW9FbGVtZW50IH0gZnJvbSAnLi9zdWJtaXRUb1BvcnRmb2xpb1Rvb2wuanMnO1xuaW1wb3J0IHsgVW5pY29kZVZhbGlkYXRvciB9IGZyb20gJy4uLy4uL3NlY3VyaXR5L3ZhbGlkYXRvcnMvdW5pY29kZVZhbGlkYXRvci5qcyc7XG5pbXBvcnQgeyBTZWN1cml0eU1vbml0b3IgfSBmcm9tICcuLi8uLi9zZWN1cml0eS9zZWN1cml0eU1vbml0b3IuanMnO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi4vLi4vdXRpbHMvbG9nZ2VyLmpzJztcbmltcG9ydCAqIGFzIHlhbWwgZnJvbSAnanMteWFtbCc7XG5pbXBvcnQgbWF0dGVyIGZyb20gJ2dyYXktbWF0dGVyJztcbmltcG9ydCB7IENvbnRlbnRWYWxpZGF0b3IgfSBmcm9tICcuLi8uLi9zZWN1cml0eS9jb250ZW50VmFsaWRhdG9yLmpzJztcblxuLyoqXG4gKiBBZGFwdGVyIGNsYXNzIHRoYXQgd3JhcHMgYSBzaW1wbGUgUG9ydGZvbGlvRWxlbWVudCBhbmQgaW1wbGVtZW50cyBJRWxlbWVudFxuICogVGhpcyBhbGxvd3MgdXMgdG8gcGFzcyBwb3J0Zm9saW8gZWxlbWVudHMgdG8gbWV0aG9kcyBleHBlY3RpbmcgSUVsZW1lbnRcbiAqIHdpdGhvdXQgY29tcGxleCB0eXBlIGNhc3RpbmdcbiAqL1xuZXhwb3J0IGNsYXNzIFBvcnRmb2xpb0VsZW1lbnRBZGFwdGVyIGltcGxlbWVudHMgSUVsZW1lbnQge1xuICBwdWJsaWMgcmVhZG9ubHkgaWQ6IHN0cmluZztcbiAgcHVibGljIHJlYWRvbmx5IHR5cGU6IEVsZW1lbnRUeXBlO1xuICBwdWJsaWMgcmVhZG9ubHkgdmVyc2lvbjogc3RyaW5nO1xuICBwdWJsaWMgcmVhZG9ubHkgbWV0YWRhdGE6IElFbGVtZW50TWV0YWRhdGE7XG4gIHByaXZhdGUgcmVhZG9ubHkgcG9ydGZvbGlvRWxlbWVudDogUG9ydGZvbGlvRWxlbWVudDtcblxuICBjb25zdHJ1Y3RvcihlbGVtZW50OiBQb3J0Zm9saW9FbGVtZW50KSB7XG4gICAgLy8gU0VDVVJJVFkgRklYICMyIChETUNQLVNFQy0wMDQpOiBOb3JtYWxpemUgYW5kIHZhbGlkYXRlIGFsbCB1c2VyIGlucHV0XG4gICAgLy8gUHJldmlvdXNseTogVXNlciBpbnB1dCB3YXMgdXNlZCBkaXJlY3RseSB3aXRob3V0IHZhbGlkYXRpb25cbiAgICAvLyBOb3c6IEFsbCBzdHJpbmcgaW5wdXRzIGdvIHRocm91Z2ggVW5pY29kZVZhbGlkYXRvciB0byBwcmV2ZW50IGhvbW9ncmFwaCBhdHRhY2tzXG4gICAgY29uc3Qgbm9ybWFsaXplZE5hbWUgPSBVbmljb2RlVmFsaWRhdG9yLm5vcm1hbGl6ZShlbGVtZW50Lm1ldGFkYXRhLm5hbWUpO1xuICAgIGlmICghbm9ybWFsaXplZE5hbWUuaXNWYWxpZCkge1xuICAgICAgLy8gTG9nIHNlY3VyaXR5IGV2ZW50IGZvciBpbnZhbGlkIFVuaWNvZGVcbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogJ1VOSUNPREVfVkFMSURBVElPTl9FUlJPUicsXG4gICAgICAgIHNldmVyaXR5OiAnTUVESVVNJyxcbiAgICAgICAgc291cmNlOiAnUG9ydGZvbGlvRWxlbWVudEFkYXB0ZXIuY29uc3RydWN0b3InLFxuICAgICAgICBkZXRhaWxzOiBgSW52YWxpZCBVbmljb2RlIGluIGVsZW1lbnQgbmFtZTogJHtub3JtYWxpemVkTmFtZS5kZXRlY3RlZElzc3Vlcz8uWzBdIHx8ICd1bmtub3duJ31gXG4gICAgICB9KTtcbiAgICAgIGxvZ2dlci53YXJuKCdJbnZhbGlkIFVuaWNvZGUgZGV0ZWN0ZWQgaW4gZWxlbWVudCBuYW1lJywge1xuICAgICAgICBpc3N1ZXM6IG5vcm1hbGl6ZWROYW1lLmRldGVjdGVkSXNzdWVzXG4gICAgICB9KTtcbiAgICB9XG4gICAgXG4gICAgdGhpcy5wb3J0Zm9saW9FbGVtZW50ID0gZWxlbWVudDtcbiAgICB0aGlzLnR5cGUgPSBlbGVtZW50LnR5cGU7XG4gICAgdGhpcy52ZXJzaW9uID0gZWxlbWVudC5tZXRhZGF0YS52ZXJzaW9uIHx8ICcxLjAuMCc7XG4gICAgXG4gICAgLy8gR2VuZXJhdGUgSUQgZnJvbSB0eXBlIGFuZCBub3JtYWxpemVkIG5hbWVcbiAgICBjb25zdCB0aW1lc3RhbXAgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkucmVwbGFjZSgvWzouXS9nLCAnLScpO1xuICAgIGNvbnN0IHNhZmVOYW1lID0gbm9ybWFsaXplZE5hbWUubm9ybWFsaXplZENvbnRlbnQgfHwgZWxlbWVudC5tZXRhZGF0YS5uYW1lO1xuICAgIGNvbnN0IG5hbWVTbHVnID0gc2FmZU5hbWUudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9cXHMrL2csICctJyk7XG4gICAgdGhpcy5pZCA9IGAke2VsZW1lbnQudHlwZX1fJHtuYW1lU2x1Z31fJHt0aW1lc3RhbXB9YDtcbiAgICBcbiAgICAvLyBDb252ZXJ0IG1ldGFkYXRhIHRvIElFbGVtZW50TWV0YWRhdGEgZm9ybWF0IHdpdGggbm9ybWFsaXplZCB2YWx1ZXNcbiAgICB0aGlzLm1ldGFkYXRhID0ge1xuICAgICAgbmFtZTogc2FmZU5hbWUsXG4gICAgICBkZXNjcmlwdGlvbjogdGhpcy5ub3JtYWxpemVTdHJpbmcoZWxlbWVudC5tZXRhZGF0YS5kZXNjcmlwdGlvbiB8fCAnJyksXG4gICAgICBhdXRob3I6IHRoaXMubm9ybWFsaXplU3RyaW5nKGVsZW1lbnQubWV0YWRhdGEuYXV0aG9yIHx8ICcnKSxcbiAgICAgIHZlcnNpb246IGVsZW1lbnQubWV0YWRhdGEudmVyc2lvbixcbiAgICAgIGNyZWF0ZWQ6IGVsZW1lbnQubWV0YWRhdGEuY3JlYXRlZCxcbiAgICAgIG1vZGlmaWVkOiBlbGVtZW50Lm1ldGFkYXRhLnVwZGF0ZWQsXG4gICAgICB0YWdzOiBbXVxuICAgIH07XG4gICAgXG4gICAgLy8gU0VDVVJJVFkgRklYICMzIChETUNQLVNFQy0wMDYpOiBMb2cgZWxlbWVudCBjcmVhdGlvbiBmb3IgYXVkaXQgdHJhaWxcbiAgICAvLyBQcmV2aW91c2x5OiBObyBhdWRpdCBsb2dnaW5nIGZvciBwb3J0Zm9saW8gb3BlcmF0aW9uc1xuICAgIC8vIE5vdzogQ29tcGxldGUgYXVkaXQgdHJhaWwgdXNpbmcgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoKVxuICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgIHR5cGU6ICdFTEVNRU5UX0NSRUFURUQnLFxuICAgICAgc2V2ZXJpdHk6ICdMT1cnLFxuICAgICAgc291cmNlOiAnUG9ydGZvbGlvRWxlbWVudEFkYXB0ZXIuY29uc3RydWN0b3InLFxuICAgICAgZGV0YWlsczogYENyZWF0ZWQgcG9ydGZvbGlvIGVsZW1lbnQgYWRhcHRlcjogJHt0aGlzLmlkfWAsXG4gICAgICBtZXRhZGF0YToge1xuICAgICAgICBlbGVtZW50VHlwZTogdGhpcy50eXBlLFxuICAgICAgICBlbGVtZW50SWQ6IHRoaXMuaWRcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIEhlbHBlciB0byBub3JtYWxpemUgc3RyaW5nIHZhbHVlcyBzYWZlbHlcbiAgICovXG4gIHByaXZhdGUgbm9ybWFsaXplU3RyaW5nKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmICghdmFsdWUpIHJldHVybiB2YWx1ZTtcbiAgICBjb25zdCBub3JtYWxpemVkID0gVW5pY29kZVZhbGlkYXRvci5ub3JtYWxpemUodmFsdWUpO1xuICAgIHJldHVybiBub3JtYWxpemVkLm5vcm1hbGl6ZWRDb250ZW50IHx8IHZhbHVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIHRoZSBlbGVtZW50XG4gICAqL1xuICB2YWxpZGF0ZSgpOiBFbGVtZW50VmFsaWRhdGlvblJlc3VsdCB7XG4gICAgY29uc3QgZXJyb3JzOiBWYWxpZGF0aW9uRXJyb3JbXSA9IFtdO1xuICAgIGNvbnN0IHdhcm5pbmdzOiBWYWxpZGF0aW9uV2FybmluZ1tdID0gW107XG5cbiAgICBpZiAoIXRoaXMubWV0YWRhdGEubmFtZSkge1xuICAgICAgZXJyb3JzLnB1c2goe1xuICAgICAgICBmaWVsZDogJ25hbWUnLFxuICAgICAgICBtZXNzYWdlOiAnRWxlbWVudCBuYW1lIGlzIHJlcXVpcmVkJ1xuICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIGlmICghdGhpcy5wb3J0Zm9saW9FbGVtZW50LmNvbnRlbnQpIHtcbiAgICAgIGVycm9ycy5wdXNoKHtcbiAgICAgICAgZmllbGQ6ICdjb250ZW50JyxcbiAgICAgICAgbWVzc2FnZTogJ0VsZW1lbnQgY29udGVudCBpcyByZXF1aXJlZCdcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICB2YWxpZDogZXJyb3JzLmxlbmd0aCA9PT0gMCxcbiAgICAgIGVycm9yczogZXJyb3JzLmxlbmd0aCA+IDAgPyBlcnJvcnMgOiB1bmRlZmluZWQsXG4gICAgICB3YXJuaW5nczogd2FybmluZ3MubGVuZ3RoID4gMCA/IHdhcm5pbmdzIDogdW5kZWZpbmVkXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXJpYWxpemUgdGhlIGVsZW1lbnQgdG8gbWFya2Rvd24gd2l0aCBZQU1MIGZyb250bWF0dGVyXG4gICAqIEZJWDogQ2hhbmdlZCBmcm9tIEpTT04gdG8gbWFya2Rvd24gZm9ybWF0IGZvciBHaXRIdWIgcG9ydGZvbGlvIGNvbXBhdGliaWxpdHlcbiAgICogU0VDVVJJVFkgRklYICM1NDQ6IFBhcnNlIGFuZCB2YWxpZGF0ZSBleGlzdGluZyBmcm9udG1hdHRlciBpbnN0ZWFkIG9mIHJldHVybmluZyBhcy1pc1xuICAgKiBTRUNVUklUWSBGSVggIzU0MzogVXNlIGdyYXktbWF0dGVyIGZvciByb2J1c3QgZnJvbnRtYXR0ZXIgZGV0ZWN0aW9uXG4gICAqL1xuICBzZXJpYWxpemUoKTogc3RyaW5nIHtcbiAgICAvLyBTRUNVUklUWSBGSVggIzU0MzogVXNlIGdyYXktbWF0dGVyIGZvciByb2J1c3QgZnJvbnRtYXR0ZXIgZGV0ZWN0aW9uXG4gICAgLy8gVGhpcyBoYW5kbGVzIGRpZmZlcmVudCBsaW5lIGVuZGluZ3MsIHdoaXRlc3BhY2UgdmFyaWF0aW9ucywgYW5kIG1hbGZvcm1lZCBZQU1MXG4gICAgbGV0IGNvbnRlbnRUb1Byb2Nlc3MgPSB0aGlzLnBvcnRmb2xpb0VsZW1lbnQuY29udGVudDtcbiAgICBsZXQgZXhpc3RpbmdNZXRhZGF0YTogUmVjb3JkPHN0cmluZywgYW55PiA9IHt9O1xuICAgIGxldCBib2R5Q29udGVudCA9IGNvbnRlbnRUb1Byb2Nlc3M7XG4gICAgXG4gICAgLy8gVHJ5IHRvIHBhcnNlIGV4aXN0aW5nIGZyb250bWF0dGVyIGlmIHByZXNlbnRcbiAgICB0cnkge1xuICAgICAgLy8gZ3JheS1tYXR0ZXIgaGFuZGxlcyBhbGwgZWRnZSBjYXNlczpcbiAgICAgIC8vIC0gRGlmZmVyZW50IGxpbmUgZW5kaW5ncyAoXFxuLCBcXHJcXG4pXG4gICAgICAvLyAtIFdoaXRlc3BhY2UgdmFyaWF0aW9uc1xuICAgICAgLy8gLSBNYWxmb3JtZWQgWUFNTCAocmV0dXJucyBlbXB0eSBkYXRhIG9iamVjdClcbiAgICAgIC8vIC0gTWlzc2luZyBjbG9zaW5nIGRlbGltaXRlclxuICAgICAgY29uc3QgcGFyc2VkID0gbWF0dGVyKGNvbnRlbnRUb1Byb2Nlc3MpO1xuICAgICAgXG4gICAgICBpZiAocGFyc2VkLmRhdGEgJiYgT2JqZWN0LmtleXMocGFyc2VkLmRhdGEpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgLy8gU0VDVVJJVFkgRklYICM1NDQ6IFZhbGlkYXRlIGV4aXN0aW5nIGZyb250bWF0dGVyIGluc3RlYWQgb2YgYnlwYXNzaW5nXG4gICAgICAgIGxvZ2dlci5kZWJ1ZygnRm91bmQgZXhpc3RpbmcgZnJvbnRtYXR0ZXIsIHZhbGlkYXRpbmcgYmVmb3JlIG1lcmdlJyk7XG4gICAgICAgIFxuICAgICAgICAvLyBWYWxpZGF0ZSB0aGUgcGFyc2VkIGZyb250bWF0dGVyXG4gICAgICAgIGNvbnN0IHZhbGlkYXRpb25SZXN1bHQgPSBDb250ZW50VmFsaWRhdG9yLnZhbGlkYXRlQW5kU2FuaXRpemUoXG4gICAgICAgICAgeWFtbC5kdW1wKHBhcnNlZC5kYXRhKVxuICAgICAgICApO1xuICAgICAgICBcbiAgICAgICAgaWYgKCF2YWxpZGF0aW9uUmVzdWx0LmlzVmFsaWQgJiYgdmFsaWRhdGlvblJlc3VsdC5zZXZlcml0eSA9PT0gJ2NyaXRpY2FsJykge1xuICAgICAgICAgIC8vIExvZyBzZWN1cml0eSBldmVudCBmb3IgbWFsaWNpb3VzIGZyb250bWF0dGVyXG4gICAgICAgICAgU2VjdXJpdHlNb25pdG9yLmxvZ1NlY3VyaXR5RXZlbnQoe1xuICAgICAgICAgICAgdHlwZTogJ0NPTlRFTlRfSU5KRUNUSU9OX0FUVEVNUFQnLFxuICAgICAgICAgICAgc2V2ZXJpdHk6ICdISUdIJyxcbiAgICAgICAgICAgIHNvdXJjZTogJ1BvcnRmb2xpb0VsZW1lbnRBZGFwdGVyLnNlcmlhbGl6ZScsXG4gICAgICAgICAgICBkZXRhaWxzOiBgQ3JpdGljYWwgc2VjdXJpdHkgaXNzdWVzIGluIGZyb250bWF0dGVyOiAke3ZhbGlkYXRpb25SZXN1bHQuZGV0ZWN0ZWRQYXR0ZXJucz8uam9pbignLCAnKX1gLFxuICAgICAgICAgICAgbWV0YWRhdGE6IHtcbiAgICAgICAgICAgICAgZWxlbWVudElkOiB0aGlzLmlkLFxuICAgICAgICAgICAgICBlbGVtZW50VHlwZTogdGhpcy50eXBlXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgXG4gICAgICAgICAgLy8gRG9uJ3QgdXNlIHRoZSBtYWxpY2lvdXMgZnJvbnRtYXR0ZXIsIGNyZWF0ZSBuZXdcbiAgICAgICAgICBleGlzdGluZ01ldGFkYXRhID0ge307XG4gICAgICAgICAgYm9keUNvbnRlbnQgPSBjb250ZW50VG9Qcm9jZXNzOyAvLyBVc2Ugb3JpZ2luYWwgY29udGVudFxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIEZyb250bWF0dGVyIGlzIHNhZmUsIG1lcmdlIHdpdGggb3VyIG1ldGFkYXRhXG4gICAgICAgICAgZXhpc3RpbmdNZXRhZGF0YSA9IHBhcnNlZC5kYXRhO1xuICAgICAgICAgIGJvZHlDb250ZW50ID0gcGFyc2VkLmNvbnRlbnQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgLy8gSWYgZ3JheS1tYXR0ZXIgZmFpbHMgdG8gcGFyc2UsIHRyZWF0IGFzIGNvbnRlbnQgd2l0aG91dCBmcm9udG1hdHRlclxuICAgICAgbG9nZ2VyLndhcm4oJ0ZhaWxlZCB0byBwYXJzZSBwb3RlbnRpYWwgZnJvbnRtYXR0ZXIsIHRyZWF0aW5nIGFzIHBsYWluIGNvbnRlbnQnLCB7XG4gICAgICAgIGVycm9yOiBlcnJvciBpbnN0YW5jZW9mIEVycm9yID8gZXJyb3IubWVzc2FnZSA6IFN0cmluZyhlcnJvcilcbiAgICAgIH0pO1xuICAgICAgLy8gQ29udGludWUgd2l0aCBlbXB0eSBtZXRhZGF0YSBhbmQgZnVsbCBjb250ZW50XG4gICAgfVxuICAgIFxuICAgIC8vIE1lcmdlIG1ldGFkYXRhLCB3aXRoIG91ciBtZXRhZGF0YSB0YWtpbmcgcHJlY2VkZW5jZSBmb3Igc2VjdXJpdHlcbiAgICAvLyBUaGlzIGVuc3VyZXMgY3JpdGljYWwgZmllbGRzIGxpa2UgSUQgYW5kIHR5cGUgYXJlIGFsd2F5cyBmcm9tIG91ciB2YWxpZGF0ZWQgc291cmNlXG4gICAgY29uc3QgbWVyZ2VkTWV0YWRhdGEgPSB7XG4gICAgICAuLi5leGlzdGluZ01ldGFkYXRhLCAvLyBFeGlzdGluZyBtZXRhZGF0YSBmaXJzdFxuICAgICAgLi4udGhpcy5tZXRhZGF0YSwgICAgLy8gT3VyIHZhbGlkYXRlZCBtZXRhZGF0YSBvdmVyd3JpdGVzXG4gICAgICBpZDogdGhpcy5pZCwgICAgICAgICAvLyBBbHdheXMgdXNlIG91ciBJRFxuICAgICAgdHlwZTogdGhpcy50eXBlLCAgICAgLy8gQWx3YXlzIHVzZSBvdXIgdHlwZVxuICAgICAgdmVyc2lvbjogdGhpcy52ZXJzaW9uIC8vIEFsd2F5cyB1c2Ugb3VyIHZlcnNpb25cbiAgICB9O1xuICAgIFxuICAgIC8vIFZhbGlkYXRlIHRoZSBmaW5hbCBtZXJnZWQgbWV0YWRhdGFcbiAgICBjb25zdCBtZXRhZGF0YVlhbWwgPSB5YW1sLmR1bXAobWVyZ2VkTWV0YWRhdGEsIHtcbiAgICAgIG5vUmVmczogdHJ1ZSxcbiAgICAgIHNvcnRLZXlzOiBmYWxzZSxcbiAgICAgIGxpbmVXaWR0aDogLTFcbiAgICB9KTtcbiAgICBcbiAgICAvLyBGaW5hbCBzZWN1cml0eSBjaGVjayBvbiB0aGUgY29tcGxldGUgbWV0YWRhdGFcbiAgICBjb25zdCBmaW5hbFZhbGlkYXRpb24gPSBDb250ZW50VmFsaWRhdG9yLnZhbGlkYXRlQW5kU2FuaXRpemUobWV0YWRhdGFZYW1sKTtcbiAgICBcbiAgICBpZiAoIWZpbmFsVmFsaWRhdGlvbi5pc1ZhbGlkICYmIGZpbmFsVmFsaWRhdGlvbi5zZXZlcml0eSA9PT0gJ2NyaXRpY2FsJykge1xuICAgICAgLy8gVGhpcyBzaG91bGRuJ3QgaGFwcGVuIHdpdGggb3VyIHNhbml0aXplZCBkYXRhLCBidXQgbG9nIGlmIGl0IGRvZXNcbiAgICAgIFNlY3VyaXR5TW9uaXRvci5sb2dTZWN1cml0eUV2ZW50KHtcbiAgICAgICAgdHlwZTogJ1VOSUNPREVfVkFMSURBVElPTl9FUlJPUicsXG4gICAgICAgIHNldmVyaXR5OiAnTUVESVVNJyxcbiAgICAgICAgc291cmNlOiAnUG9ydGZvbGlvRWxlbWVudEFkYXB0ZXIuc2VyaWFsaXplJyxcbiAgICAgICAgZGV0YWlsczogJ0ZpbmFsIG1ldGFkYXRhIHZhbGlkYXRpb24gZmFpbGVkIGFmdGVyIG1lcmdlJyxcbiAgICAgICAgbWV0YWRhdGE6IHsgZWxlbWVudElkOiB0aGlzLmlkIH1cbiAgICAgIH0pO1xuICAgICAgXG4gICAgICAvLyBGYWxsIGJhY2sgdG8gbWluaW1hbCBzYWZlIG1ldGFkYXRhXG4gICAgICBjb25zdCBzYWZlTWV0YWRhdGEgPSB7XG4gICAgICAgIGlkOiB0aGlzLmlkLFxuICAgICAgICB0eXBlOiB0aGlzLnR5cGUsXG4gICAgICAgIHZlcnNpb246IHRoaXMudmVyc2lvbixcbiAgICAgICAgbmFtZTogdGhpcy5ub3JtYWxpemVTdHJpbmcodGhpcy5tZXRhZGF0YS5uYW1lIHx8ICdVbnRpdGxlZCcpLFxuICAgICAgICBkZXNjcmlwdGlvbjogdGhpcy5ub3JtYWxpemVTdHJpbmcodGhpcy5tZXRhZGF0YS5kZXNjcmlwdGlvbiB8fCAnJylcbiAgICAgIH07XG4gICAgICBcbiAgICAgIGNvbnN0IHNhZmVGcm9udG1hdHRlciA9IHlhbWwuZHVtcChzYWZlTWV0YWRhdGEsIHtcbiAgICAgICAgbm9SZWZzOiB0cnVlLFxuICAgICAgICBzb3J0S2V5czogZmFsc2UsXG4gICAgICAgIGxpbmVXaWR0aDogLTFcbiAgICAgIH0pO1xuICAgICAgXG4gICAgICByZXR1cm4gYC0tLVxcbiR7c2FmZUZyb250bWF0dGVyfS0tLVxcblxcbiR7Ym9keUNvbnRlbnR9YDtcbiAgICB9XG4gICAgXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBhbmQgc2FuaXRpemVkIG1hcmtkb3duIHdpdGggZnJvbnRtYXR0ZXJcbiAgICByZXR1cm4gYC0tLVxcbiR7bWV0YWRhdGFZYW1sfS0tLVxcblxcbiR7Ym9keUNvbnRlbnR9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZXNlcmlhbGl6ZSBmcm9tIHN0cmluZyAobm90IGltcGxlbWVudGVkIGZvciBhZGFwdGVyKVxuICAgKi9cbiAgZGVzZXJpYWxpemUoZGF0YTogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdEZXNlcmlhbGl6YXRpb24gbm90IHN1cHBvcnRlZCBmb3IgUG9ydGZvbGlvRWxlbWVudEFkYXB0ZXInKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgZWxlbWVudCBzdGF0dXNcbiAgICovXG4gIGdldFN0YXR1cygpOiBFbGVtZW50U3RhdHVzIHtcbiAgICByZXR1cm4gRWxlbWVudFN0YXR1cy5JTkFDVElWRTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIG9yaWdpbmFsIHBvcnRmb2xpbyBlbGVtZW50IGNvbnRlbnRcbiAgICovXG4gIGdldENvbnRlbnQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5wb3J0Zm9saW9FbGVtZW50LmNvbnRlbnQ7XG4gIH1cbn0iXX0=