@skillsmith/core 0.11.2 → 0.11.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 (235) hide show
  1. package/CHANGELOG.md +36 -9
  2. package/README.md +6 -7
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/src/analysis/McpReferenceExtractor.d.ts +59 -5
  5. package/dist/src/analysis/McpReferenceExtractor.d.ts.map +1 -1
  6. package/dist/src/analysis/McpReferenceExtractor.hardening.test.d.ts +2 -0
  7. package/dist/src/analysis/McpReferenceExtractor.hardening.test.d.ts.map +1 -0
  8. package/dist/src/analysis/McpReferenceExtractor.hardening.test.js +278 -0
  9. package/dist/src/analysis/McpReferenceExtractor.hardening.test.js.map +1 -0
  10. package/dist/src/analysis/McpReferenceExtractor.js +276 -20
  11. package/dist/src/analysis/McpReferenceExtractor.js.map +1 -1
  12. package/dist/src/analysis/McpReferenceExtractor.test.js +4 -0
  13. package/dist/src/analysis/McpReferenceExtractor.test.js.map +1 -1
  14. package/dist/src/config/config-atomic-write.d.ts +58 -0
  15. package/dist/src/config/config-atomic-write.d.ts.map +1 -0
  16. package/dist/src/config/config-atomic-write.js +151 -0
  17. package/dist/src/config/config-atomic-write.js.map +1 -0
  18. package/dist/src/config/config-atomic-write.test.d.ts +9 -0
  19. package/dist/src/config/config-atomic-write.test.d.ts.map +1 -0
  20. package/dist/src/config/config-atomic-write.test.js +92 -0
  21. package/dist/src/config/config-atomic-write.test.js.map +1 -0
  22. package/dist/src/config/device-identity.d.ts +16 -0
  23. package/dist/src/config/device-identity.d.ts.map +1 -1
  24. package/dist/src/config/device-identity.js +82 -14
  25. package/dist/src/config/device-identity.js.map +1 -1
  26. package/dist/src/config/device-identity.test.js +158 -1
  27. package/dist/src/config/device-identity.test.js.map +1 -1
  28. package/dist/src/config/index.d.ts +14 -0
  29. package/dist/src/config/index.d.ts.map +1 -1
  30. package/dist/src/config/index.js +31 -15
  31. package/dist/src/config/index.js.map +1 -1
  32. package/dist/src/exports/services.d.ts +2 -1
  33. package/dist/src/exports/services.d.ts.map +1 -1
  34. package/dist/src/exports/services.js +1 -0
  35. package/dist/src/exports/services.js.map +1 -1
  36. package/dist/src/index.d.ts +4 -1
  37. package/dist/src/index.d.ts.map +1 -1
  38. package/dist/src/index.js +13 -1
  39. package/dist/src/index.js.map +1 -1
  40. package/dist/src/indexer/SwarmIndexer.d.ts +1 -1
  41. package/dist/src/indexer/SwarmIndexer.js +2 -2
  42. package/dist/src/indexer/SwarmIndexer.js.map +1 -1
  43. package/dist/src/install/paths.d.ts +1 -1
  44. package/dist/src/install/paths.d.ts.map +1 -1
  45. package/dist/src/install/paths.js +2 -0
  46. package/dist/src/install/paths.js.map +1 -1
  47. package/dist/src/install/paths.test.js +10 -1
  48. package/dist/src/install/paths.test.js.map +1 -1
  49. package/dist/src/logging/logger.test.js +57 -0
  50. package/dist/src/logging/logger.test.js.map +1 -1
  51. package/dist/src/logging/rotation.d.ts +27 -2
  52. package/dist/src/logging/rotation.d.ts.map +1 -1
  53. package/dist/src/logging/rotation.js +44 -3
  54. package/dist/src/logging/rotation.js.map +1 -1
  55. package/dist/src/logging/rotation.test.js +69 -0
  56. package/dist/src/logging/rotation.test.js.map +1 -1
  57. package/dist/src/logging/types.d.ts +8 -2
  58. package/dist/src/logging/types.d.ts.map +1 -1
  59. package/dist/src/scripts/__tests__/scan-imported-skills.test.js +5 -0
  60. package/dist/src/scripts/__tests__/scan-imported-skills.test.js.map +1 -1
  61. package/dist/src/security/audit-types.d.ts +1 -1
  62. package/dist/src/security/audit-types.d.ts.map +1 -1
  63. package/dist/src/security/audit-types.js.map +1 -1
  64. package/dist/src/security/index.d.ts +2 -1
  65. package/dist/src/security/index.d.ts.map +1 -1
  66. package/dist/src/security/index.js +3 -0
  67. package/dist/src/security/index.js.map +1 -1
  68. package/dist/src/security/scanner/SecurityScanner.d.ts +2 -2
  69. package/dist/src/security/scanner/SecurityScanner.d.ts.map +1 -1
  70. package/dist/src/security/scanner/SecurityScanner.evidence.d.ts +76 -0
  71. package/dist/src/security/scanner/SecurityScanner.evidence.d.ts.map +1 -0
  72. package/dist/src/security/scanner/SecurityScanner.evidence.js +176 -0
  73. package/dist/src/security/scanner/SecurityScanner.evidence.js.map +1 -0
  74. package/dist/src/security/scanner/SecurityScanner.exec.d.ts +15 -1
  75. package/dist/src/security/scanner/SecurityScanner.exec.d.ts.map +1 -1
  76. package/dist/src/security/scanner/SecurityScanner.exec.js +68 -76
  77. package/dist/src/security/scanner/SecurityScanner.exec.js.map +1 -1
  78. package/dist/src/security/scanner/SecurityScanner.formatters.d.ts +14 -1
  79. package/dist/src/security/scanner/SecurityScanner.formatters.d.ts.map +1 -1
  80. package/dist/src/security/scanner/SecurityScanner.formatters.js +33 -0
  81. package/dist/src/security/scanner/SecurityScanner.formatters.js.map +1 -1
  82. package/dist/src/security/scanner/SecurityScanner.formatters.test.d.ts +9 -0
  83. package/dist/src/security/scanner/SecurityScanner.formatters.test.d.ts.map +1 -0
  84. package/dist/src/security/scanner/SecurityScanner.formatters.test.js +65 -0
  85. package/dist/src/security/scanner/SecurityScanner.formatters.test.js.map +1 -0
  86. package/dist/src/security/scanner/SecurityScanner.helpers.d.ts +35 -10
  87. package/dist/src/security/scanner/SecurityScanner.helpers.d.ts.map +1 -1
  88. package/dist/src/security/scanner/SecurityScanner.helpers.js +121 -60
  89. package/dist/src/security/scanner/SecurityScanner.helpers.js.map +1 -1
  90. package/dist/src/security/scanner/SecurityScanner.js +41 -13
  91. package/dist/src/security/scanner/SecurityScanner.js.map +1 -1
  92. package/dist/src/security/scanner/SecurityScanner.pii.d.ts.map +1 -1
  93. package/dist/src/security/scanner/SecurityScanner.pii.js +23 -1
  94. package/dist/src/security/scanner/SecurityScanner.pii.js.map +1 -1
  95. package/dist/src/security/scanner/SecurityScanner.scanners.d.ts.map +1 -1
  96. package/dist/src/security/scanner/SecurityScanner.scanners.js +15 -3
  97. package/dist/src/security/scanner/SecurityScanner.scanners.js.map +1 -1
  98. package/dist/src/security/scanner/SecurityScanner.ssrf.d.ts +11 -1
  99. package/dist/src/security/scanner/SecurityScanner.ssrf.d.ts.map +1 -1
  100. package/dist/src/security/scanner/SecurityScanner.ssrf.js +18 -7
  101. package/dist/src/security/scanner/SecurityScanner.ssrf.js.map +1 -1
  102. package/dist/src/security/scanner/confusables.d.ts +28 -0
  103. package/dist/src/security/scanner/confusables.d.ts.map +1 -0
  104. package/dist/src/security/scanner/confusables.js +87 -0
  105. package/dist/src/security/scanner/confusables.js.map +1 -0
  106. package/dist/src/security/scanner/confusables.test.d.ts +10 -0
  107. package/dist/src/security/scanner/confusables.test.d.ts.map +1 -0
  108. package/dist/src/security/scanner/confusables.test.js +44 -0
  109. package/dist/src/security/scanner/confusables.test.js.map +1 -0
  110. package/dist/src/security/scanner/index.d.ts +9 -3
  111. package/dist/src/security/scanner/index.d.ts.map +1 -1
  112. package/dist/src/security/scanner/index.js +18 -2
  113. package/dist/src/security/scanner/index.js.map +1 -1
  114. package/dist/src/security/scanner/patterns.d.ts +41 -14
  115. package/dist/src/security/scanner/patterns.d.ts.map +1 -1
  116. package/dist/src/security/scanner/patterns.jailbreak.d.ts +41 -0
  117. package/dist/src/security/scanner/patterns.jailbreak.d.ts.map +1 -0
  118. package/dist/src/security/scanner/patterns.jailbreak.evidence.d.ts +35 -0
  119. package/dist/src/security/scanner/patterns.jailbreak.evidence.d.ts.map +1 -0
  120. package/dist/src/security/scanner/patterns.jailbreak.evidence.js +119 -0
  121. package/dist/src/security/scanner/patterns.jailbreak.evidence.js.map +1 -0
  122. package/dist/src/security/scanner/patterns.jailbreak.js +370 -0
  123. package/dist/src/security/scanner/patterns.jailbreak.js.map +1 -0
  124. package/dist/src/security/scanner/patterns.js +101 -82
  125. package/dist/src/security/scanner/patterns.js.map +1 -1
  126. package/dist/src/security/scanner/patterns.scope.d.ts +62 -0
  127. package/dist/src/security/scanner/patterns.scope.d.ts.map +1 -0
  128. package/dist/src/security/scanner/patterns.scope.js +207 -0
  129. package/dist/src/security/scanner/patterns.scope.js.map +1 -0
  130. package/dist/src/security/scanner/regex-utils.d.ts +20 -0
  131. package/dist/src/security/scanner/regex-utils.d.ts.map +1 -1
  132. package/dist/src/security/scanner/regex-utils.js +20 -0
  133. package/dist/src/security/scanner/regex-utils.js.map +1 -1
  134. package/dist/src/security/scanner/types.d.ts +49 -1
  135. package/dist/src/security/scanner/types.d.ts.map +1 -1
  136. package/dist/src/security/scanner/typosquat-reference-list.d.ts +54 -0
  137. package/dist/src/security/scanner/typosquat-reference-list.d.ts.map +1 -0
  138. package/dist/src/security/scanner/typosquat-reference-list.js +55 -0
  139. package/dist/src/security/scanner/typosquat-reference-list.js.map +1 -0
  140. package/dist/src/security/scanner/typosquat-reference-list.test.d.ts +5 -0
  141. package/dist/src/security/scanner/typosquat-reference-list.test.d.ts.map +1 -0
  142. package/dist/src/security/scanner/typosquat-reference-list.test.js +52 -0
  143. package/dist/src/security/scanner/typosquat-reference-list.test.js.map +1 -0
  144. package/dist/src/security/scanner/typosquat.d.ts +100 -0
  145. package/dist/src/security/scanner/typosquat.d.ts.map +1 -0
  146. package/dist/src/security/scanner/typosquat.js +256 -0
  147. package/dist/src/security/scanner/typosquat.js.map +1 -0
  148. package/dist/src/security/scanner/typosquat.test.d.ts +12 -0
  149. package/dist/src/security/scanner/typosquat.test.d.ts.map +1 -0
  150. package/dist/src/security/scanner/typosquat.test.js +140 -0
  151. package/dist/src/security/scanner/typosquat.test.js.map +1 -0
  152. package/dist/src/security/scanner/weights.d.ts.map +1 -1
  153. package/dist/src/security/scanner/weights.js +10 -0
  154. package/dist/src/security/scanner/weights.js.map +1 -1
  155. package/dist/src/services/skill-installation.helpers.d.ts +21 -0
  156. package/dist/src/services/skill-installation.helpers.d.ts.map +1 -1
  157. package/dist/src/services/skill-installation.helpers.js +46 -2
  158. package/dist/src/services/skill-installation.helpers.js.map +1 -1
  159. package/dist/src/services/skill-installation.helpers.test.d.ts +2 -0
  160. package/dist/src/services/skill-installation.helpers.test.d.ts.map +1 -0
  161. package/dist/src/services/skill-installation.helpers.test.js +80 -0
  162. package/dist/src/services/skill-installation.helpers.test.js.map +1 -0
  163. package/dist/src/services/skill-installation.io.d.ts.map +1 -1
  164. package/dist/src/services/skill-installation.io.js +12 -1
  165. package/dist/src/services/skill-installation.io.js.map +1 -1
  166. package/dist/src/sync/inventory-collector.d.ts +15 -4
  167. package/dist/src/sync/inventory-collector.d.ts.map +1 -1
  168. package/dist/src/sync/inventory-collector.js +75 -26
  169. package/dist/src/sync/inventory-collector.js.map +1 -1
  170. package/dist/src/sync/inventory-collector.test.d.ts +15 -1
  171. package/dist/src/sync/inventory-collector.test.d.ts.map +1 -1
  172. package/dist/src/sync/inventory-collector.test.js +75 -5
  173. package/dist/src/sync/inventory-collector.test.js.map +1 -1
  174. package/dist/src/telemetry/tracer-imports.d.ts +1 -1
  175. package/dist/src/telemetry/tracer-imports.js +1 -1
  176. package/dist/src/telemetry/tracer.js +1 -1
  177. package/dist/tests/SecurityScanner.ai-defence.test.js +32 -7
  178. package/dist/tests/SecurityScanner.ai-defence.test.js.map +1 -1
  179. package/dist/tests/SecurityScanner.exec.test.js +79 -0
  180. package/dist/tests/SecurityScanner.exec.test.js.map +1 -1
  181. package/dist/tests/SecurityScanner.scoring.test.js +60 -0
  182. package/dist/tests/SecurityScanner.scoring.test.js.map +1 -1
  183. package/dist/tests/SwarmIndexer.test.js +4 -5
  184. package/dist/tests/SwarmIndexer.test.js.map +1 -1
  185. package/dist/tests/security/ContinuousSecurity.performance.test.js +6 -0
  186. package/dist/tests/security/ContinuousSecurity.performance.test.js.map +1 -1
  187. package/dist/tests/security/ContinuousSecurity.test.js +15 -0
  188. package/dist/tests/security/ContinuousSecurity.test.js.map +1 -1
  189. package/dist/tests/security/ad-crlf-injection.test.d.ts +18 -0
  190. package/dist/tests/security/ad-crlf-injection.test.d.ts.map +1 -0
  191. package/dist/tests/security/ad-crlf-injection.test.js +150 -0
  192. package/dist/tests/security/ad-crlf-injection.test.js.map +1 -0
  193. package/dist/tests/security/ai-defence-multiline-promotion.test.d.ts +25 -0
  194. package/dist/tests/security/ai-defence-multiline-promotion.test.d.ts.map +1 -0
  195. package/dist/tests/security/ai-defence-multiline-promotion.test.js +138 -0
  196. package/dist/tests/security/ai-defence-multiline-promotion.test.js.map +1 -0
  197. package/dist/tests/security/nested-instruction-long-attribute.test.d.ts +15 -0
  198. package/dist/tests/security/nested-instruction-long-attribute.test.d.ts.map +1 -0
  199. package/dist/tests/security/nested-instruction-long-attribute.test.js +60 -0
  200. package/dist/tests/security/nested-instruction-long-attribute.test.js.map +1 -0
  201. package/dist/tests/security/pattern-scope.test.d.ts +17 -0
  202. package/dist/tests/security/pattern-scope.test.d.ts.map +1 -0
  203. package/dist/tests/security/pattern-scope.test.js +128 -0
  204. package/dist/tests/security/pattern-scope.test.js.map +1 -0
  205. package/dist/tests/security/pii-detection.test.js +39 -0
  206. package/dist/tests/security/pii-detection.test.js.map +1 -1
  207. package/dist/tests/security/scanner-evidence-tiers.test.d.ts +30 -0
  208. package/dist/tests/security/scanner-evidence-tiers.test.d.ts.map +1 -0
  209. package/dist/tests/security/scanner-evidence-tiers.test.js +258 -0
  210. package/dist/tests/security/scanner-evidence-tiers.test.js.map +1 -0
  211. package/dist/tests/security/scanner-privesc-severity.test.d.ts +23 -0
  212. package/dist/tests/security/scanner-privesc-severity.test.d.ts.map +1 -0
  213. package/dist/tests/security/scanner-privesc-severity.test.js +43 -0
  214. package/dist/tests/security/scanner-privesc-severity.test.js.map +1 -0
  215. package/dist/tests/security/scanner-regression-guard.exec-locality.test.d.ts +20 -0
  216. package/dist/tests/security/scanner-regression-guard.exec-locality.test.d.ts.map +1 -0
  217. package/dist/tests/security/scanner-regression-guard.exec-locality.test.js +71 -0
  218. package/dist/tests/security/scanner-regression-guard.exec-locality.test.js.map +1 -0
  219. package/dist/tests/security/scanner-regression-guard.test.d.ts +24 -0
  220. package/dist/tests/security/scanner-regression-guard.test.d.ts.map +1 -1
  221. package/dist/tests/security/scanner-regression-guard.test.js +60 -3
  222. package/dist/tests/security/scanner-regression-guard.test.js.map +1 -1
  223. package/dist/tests/security/scanner-ssrf-word-boundary.test.d.ts +19 -0
  224. package/dist/tests/security/scanner-ssrf-word-boundary.test.d.ts.map +1 -0
  225. package/dist/tests/security/scanner-ssrf-word-boundary.test.js +65 -0
  226. package/dist/tests/security/scanner-ssrf-word-boundary.test.js.map +1 -0
  227. package/dist/tests/security.test.js +11 -2
  228. package/dist/tests/security.test.js.map +1 -1
  229. package/dist/tests/services/aidefence-feedback.test.js +1 -0
  230. package/dist/tests/services/aidefence-feedback.test.js.map +1 -1
  231. package/dist/tests/skill-scanner/allowlist.test.js +16 -7
  232. package/dist/tests/skill-scanner/allowlist.test.js.map +1 -1
  233. package/dist/tests/unit/services/skill-installation.io.test.js +54 -1
  234. package/dist/tests/unit/services/skill-installation.io.test.js.map +1 -1
  235. package/package.json +13 -8
@@ -2,10 +2,29 @@
2
2
  * @fileoverview Extracts MCP tool references from SKILL.md content
3
3
  * @module @skillsmith/core/analysis/McpReferenceExtractor
4
4
  * @see SMI-3145: Build McpReferenceExtractor
5
+ * @see SMI-5676: Wave 1 Step 3b — harden extraction (26-file validation found a
6
+ * 71% false-negative rate against real SKILL.md files)
5
7
  *
6
- * Scans skill content for `mcp__<server>__<tool>` patterns,
7
- * tracking whether each reference appears inside a fenced code block.
8
+ * Scans skill content for three kinds of MCP dependency signal:
9
+ * 1. Inline `mcp__<server>__<tool>` references in prose/code (original
10
+ * SMI-3145 behavior), tracking fenced-code-block state for confidence.
11
+ * 2. Frontmatter `allowed-tools`/`tools` YAML fields, including the
12
+ * bare-server (`mcp__linear`) and wildcard (`mcp__linear__*`) forms.
13
+ * 3. Embedded `mcpServers` JSON registration blocks (e.g. a fenced code
14
+ * block showing how to add the skill's server to `.mcp.json`).
15
+ *
16
+ * All three feed the same `references`/`servers`/`highConfidenceServers`
17
+ * output — hardening changes what gets *extracted*, not how extracted
18
+ * results get scored (see `DependencyMerger.ts`, unchanged).
19
+ *
20
+ * A fourth signal, `registeredServers`, lets a caller cross-check every
21
+ * candidate server name against the consuming project's own `.mcp.json`.
22
+ * This is advisory tagging only (`serverResolutions`) — a name is NEVER
23
+ * excluded from `references`/`servers` just because it doesn't resolve,
24
+ * since a real (but not-yet-installed) dependency looks identical to a
25
+ * stale/renamed one from here. See `serverResolutions` doc below.
8
26
  */
27
+ import { LineCounter, isScalar, isSeq, parseDocument } from 'yaml';
9
28
  /** Maximum input size in bytes before truncation */
10
29
  const MAX_INPUT_BYTES = 100 * 1024;
11
30
  /**
@@ -16,17 +35,48 @@ const MAX_INPUT_BYTES = 100 * 1024;
16
35
  const MCP_PATTERN = /mcp__([a-z][a-z0-9-]*)__([a-z][a-z0-9_]*)/g;
17
36
  /** Matches the opening or closing of a fenced code block */
18
37
  const FENCE_PATTERN = /^(`{3,}|~{3,})/;
38
+ /** Matches a bare `---` frontmatter delimiter line */
39
+ const FRONTMATTER_DELIMITER = /^---\s*$/;
40
+ /** Frontmatter fields scanned for `mcp__*` tool references (SMI-5676) */
41
+ const TOOL_LIST_FIELDS = ['allowed-tools', 'tools'];
42
+ /**
43
+ * Matches a single `mcp__` token from a frontmatter tools list. Supports:
44
+ * - bare server: `mcp__linear` (capture 2 undefined)
45
+ * - wildcard: `mcp__linear__*` (capture 2 === '*')
46
+ * - full: `mcp__linear__save_issue` (capture 2 is the tool name)
47
+ */
48
+ const FRONTMATTER_MCP_TOKEN = /^mcp__([a-z][a-z0-9-]*)(?:__([a-z][a-z0-9_]*|\*))?$/;
49
+ /** Plausible JSON object key for an MCP server name in an `mcpServers` block */
50
+ const JSON_SERVER_NAME = /^[a-zA-Z][a-zA-Z0-9_-]*$/;
51
+ /**
52
+ * Cap on `"mcpServers"` marker occurrences processed per document. Real
53
+ * skills have at most 1-2 legitimate registration blocks; without a cap,
54
+ * adversarial content with many unclosed `"mcpServers": {` occurrences would
55
+ * each trigger an O(remaining-document-length) brace scan in
56
+ * {@link findMatchingBrace} — O(n^2) worst case even though the 100KB input
57
+ * cap already bounds n (SMI-5676 review finding).
58
+ */
59
+ const MAX_MCP_SERVERS_MARKERS = 20;
19
60
  /**
20
61
  * Extract all MCP tool references from skill content.
21
62
  *
22
63
  * Scans each line for `mcp__server__tool` patterns, tracking fenced
23
64
  * code block state to distinguish high-confidence (prose) references
24
- * from low-confidence (code example) references.
65
+ * from low-confidence (code example) references. Also parses frontmatter
66
+ * `allowed-tools`/`tools` fields and embedded `mcpServers` JSON blocks
67
+ * (SMI-5676).
25
68
  *
26
69
  * @param content - Raw SKILL.md content (markdown)
70
+ * @param registeredServers - Optional list of MCP server names actually
71
+ * registered in the consuming project's `.mcp.json`. When provided
72
+ * (even as `[]`), every candidate server name is tagged `registered` or
73
+ * `unregistered` in the result's `serverResolutions` map — never filtered
74
+ * out. Omit (or pass `undefined`) when the caller couldn't determine this
75
+ * (e.g. `.mcp.json` missing/unparseable); every name is then tagged
76
+ * `unknown` rather than assumed unregistered.
27
77
  * @returns Extraction result with references, servers, and confidence info
28
78
  */
29
- export function extractMcpReferences(content) {
79
+ export function extractMcpReferences(content, registeredServers) {
30
80
  let truncated;
31
81
  // Cap input at 100KB
32
82
  if (new TextEncoder().encode(content).byteLength > MAX_INPUT_BYTES) {
@@ -37,12 +87,21 @@ export function extractMcpReferences(content) {
37
87
  const references = [];
38
88
  const serverSet = new Set();
39
89
  const highConfidenceSet = new Set();
90
+ /** Per-line fenced-code-block state, reused by the mcpServers JSON pass below */
91
+ const lineInCodeBlock = [];
92
+ // SMI-5676 review fix: the frontmatter block (open delimiter, YAML body,
93
+ // close delimiter) is excluded from the base inline-regex scan below, so a
94
+ // full-form frontmatter entry like `- mcp__linear__save_issue` is only
95
+ // ever counted once (by extractFrontmatterMcpRefs), not twice.
96
+ const frontmatterBlock = extractFrontmatterBlock(lines);
97
+ const frontmatterEndLine = frontmatterBlock ? frontmatterBlock.endLine : 0;
40
98
  let inCodeBlock = false;
41
99
  let fenceChar = null;
42
100
  let fenceLength = 0;
43
101
  for (let i = 0; i < lines.length; i++) {
44
102
  const line = lines[i];
45
103
  const lineNumber = i + 1;
104
+ const inFrontmatter = lineNumber <= frontmatterEndLine;
46
105
  // Check for fence toggle
47
106
  const fenceMatch = FENCE_PATTERN.exec(line);
48
107
  if (fenceMatch) {
@@ -60,33 +119,230 @@ export function extractMcpReferences(content) {
60
119
  fenceLength = 0;
61
120
  }
62
121
  }
63
- // Find all MCP references on this line
64
- let match;
65
- // Reset lastIndex for each line since we reuse the global regex
66
- MCP_PATTERN.lastIndex = 0;
67
- while ((match = MCP_PATTERN.exec(line)) !== null) {
68
- const server = match[1];
69
- const tool = match[2];
70
- references.push({
71
- server,
72
- tool,
73
- line: lineNumber,
74
- inCodeBlock,
75
- });
76
- serverSet.add(server);
77
- if (!inCodeBlock) {
78
- highConfidenceSet.add(server);
122
+ // Find all MCP references on this line (skip the frontmatter block —
123
+ // handled separately below, so full-form entries aren't double-counted)
124
+ if (!inFrontmatter) {
125
+ let match;
126
+ // Reset lastIndex for each line since we reuse the global regex
127
+ MCP_PATTERN.lastIndex = 0;
128
+ while ((match = MCP_PATTERN.exec(line)) !== null) {
129
+ const server = match[1];
130
+ const tool = match[2];
131
+ references.push({
132
+ server,
133
+ tool,
134
+ line: lineNumber,
135
+ inCodeBlock,
136
+ });
137
+ serverSet.add(server);
138
+ if (!inCodeBlock) {
139
+ highConfidenceSet.add(server);
140
+ }
79
141
  }
80
142
  }
143
+ lineInCodeBlock.push(inCodeBlock);
144
+ }
145
+ // SMI-5676: frontmatter allowed-tools/tools YAML fields (bare-server +
146
+ // wildcard forms). Always high-confidence — an explicit declaration, not a
147
+ // prose/code example.
148
+ for (const ref of extractFrontmatterMcpRefs(frontmatterBlock)) {
149
+ references.push({ server: ref.server, tool: ref.tool, line: ref.line, inCodeBlock: false });
150
+ serverSet.add(ref.server);
151
+ highConfidenceSet.add(ref.server);
152
+ }
153
+ // SMI-5676: embedded mcpServers JSON registration blocks. Confidence
154
+ // follows the same fenced-code-block state as inline references, since
155
+ // these blocks are themselves almost always fenced JSON examples.
156
+ for (const ref of extractMcpServersJsonRefs(content)) {
157
+ const refInCodeBlock = lineInCodeBlock[ref.line - 1] ?? false;
158
+ references.push({ server: ref.server, tool: '*', line: ref.line, inCodeBlock: refInCodeBlock });
159
+ serverSet.add(ref.server);
160
+ if (!refInCodeBlock) {
161
+ highConfidenceSet.add(ref.server);
162
+ }
163
+ }
164
+ // Keep a stable, file-order-ish `references` array across the three
165
+ // detection passes above (each pass is internally in-order already;
166
+ // Array#sort is stable in Node, so same-line entries keep their order).
167
+ references.sort((a, b) => a.line - b.line);
168
+ // SMI-5676: cross-check every candidate against the consuming project's
169
+ // .mcp.json — tag, never exclude (see McpServerResolution doc).
170
+ const serverResolutions = {};
171
+ for (const server of serverSet) {
172
+ serverResolutions[server] =
173
+ registeredServers === undefined
174
+ ? 'unknown'
175
+ : registeredServers.includes(server)
176
+ ? 'registered'
177
+ : 'unregistered';
81
178
  }
82
179
  const result = {
83
180
  references,
84
181
  servers: [...serverSet].sort(),
85
182
  highConfidenceServers: [...highConfidenceSet].sort(),
183
+ serverResolutions,
86
184
  };
87
185
  if (truncated) {
88
186
  result.truncated = true;
89
187
  }
90
188
  return result;
91
189
  }
190
+ /**
191
+ * Locate the frontmatter block (between the first two `---` delimiter
192
+ * lines) and return its YAML lines, the absolute file line number of the
193
+ * first YAML content line, and the absolute line number of the closing
194
+ * delimiter (used by callers to exclude the whole block from other line
195
+ * scans). Returns null if there's no well-formed frontmatter (no delimiters
196
+ * at all, or an unterminated block) — fails open.
197
+ */
198
+ function extractFrontmatterBlock(lines) {
199
+ if (lines.length === 0 || !FRONTMATTER_DELIMITER.test(lines[0]))
200
+ return null;
201
+ for (let i = 1; i < lines.length; i++) {
202
+ if (FRONTMATTER_DELIMITER.test(lines[i])) {
203
+ return { yamlLines: lines.slice(1, i), startLine: 2, endLine: i + 1 };
204
+ }
205
+ }
206
+ return null;
207
+ }
208
+ /**
209
+ * Parse the frontmatter's `allowed-tools`/`tools` fields (structurally, via
210
+ * the `yaml` package — already a `@skillsmith/core` dependency, used the
211
+ * same way in `agent-config-merge.yaml.ts`) and pull out any `mcp__*`
212
+ * tokens, in whichever YAML shape the author used: block list (`- item`),
213
+ * flow list (`[item, item]`), or a single bare scalar. Fails open (returns
214
+ * `[]`) on missing frontmatter, missing fields, or a YAML parse error.
215
+ *
216
+ * @param block - The already-located frontmatter block (or null if the
217
+ * content has none), from {@link extractFrontmatterBlock} — computed once
218
+ * by the caller and shared with the base inline-regex scan's exclusion
219
+ * range, rather than re-derived here.
220
+ */
221
+ function extractFrontmatterMcpRefs(block) {
222
+ if (!block || block.yamlLines.length === 0)
223
+ return [];
224
+ const yamlSource = block.yamlLines.join('\n');
225
+ const lineCounter = new LineCounter();
226
+ let doc;
227
+ try {
228
+ doc = parseDocument(yamlSource, { lineCounter });
229
+ }
230
+ catch {
231
+ return [];
232
+ }
233
+ if (doc.errors.length > 0)
234
+ return [];
235
+ const refs = [];
236
+ for (const field of TOOL_LIST_FIELDS) {
237
+ let node;
238
+ try {
239
+ node = doc.get(field, true);
240
+ }
241
+ catch {
242
+ continue;
243
+ }
244
+ if (node === undefined || node === null)
245
+ continue;
246
+ const scalarNodes = isSeq(node) ? node.items : isScalar(node) ? [node] : [];
247
+ for (const item of scalarNodes) {
248
+ if (!isScalar(item) || typeof item.value !== 'string')
249
+ continue;
250
+ const tokenMatch = FRONTMATTER_MCP_TOKEN.exec(item.value.trim());
251
+ if (!tokenMatch)
252
+ continue;
253
+ const server = tokenMatch[1];
254
+ const tool = tokenMatch[2] && tokenMatch[2] !== '*' ? tokenMatch[2] : '*';
255
+ const range = item.range;
256
+ const relativeLine = range ? lineCounter.linePos(range[0]).line : 1;
257
+ refs.push({ server, tool, line: block.startLine + relativeLine - 1 });
258
+ }
259
+ }
260
+ return refs;
261
+ }
262
+ /**
263
+ * Find the index of the `}` that closes the `{` at `openIdx`, respecting
264
+ * JSON string literals (so braces inside string values don't miscount).
265
+ * Returns -1 if unterminated.
266
+ */
267
+ function findMatchingBrace(text, openIdx) {
268
+ let depth = 0;
269
+ let inString = false;
270
+ let escapeNext = false;
271
+ for (let i = openIdx; i < text.length; i++) {
272
+ const ch = text[i];
273
+ if (escapeNext) {
274
+ escapeNext = false;
275
+ continue;
276
+ }
277
+ if (inString) {
278
+ if (ch === '\\')
279
+ escapeNext = true;
280
+ else if (ch === '"')
281
+ inString = false;
282
+ continue;
283
+ }
284
+ if (ch === '"') {
285
+ inString = true;
286
+ continue;
287
+ }
288
+ if (ch === '{') {
289
+ depth++;
290
+ }
291
+ else if (ch === '}') {
292
+ depth--;
293
+ if (depth === 0)
294
+ return i;
295
+ }
296
+ }
297
+ return -1;
298
+ }
299
+ /**
300
+ * Detect `"mcpServers": { ... }` JSON registration blocks embedded anywhere
301
+ * in the content (typically inside a fenced code example showing how to add
302
+ * the skill's server to `.mcp.json`/`settings.json`). Each top-level key of
303
+ * the object is a candidate server name. Fails open (skips) on invalid JSON
304
+ * rather than throwing.
305
+ */
306
+ function extractMcpServersJsonRefs(content) {
307
+ const refs = [];
308
+ const marker = '"mcpServers"';
309
+ let fromIdx = 0;
310
+ let markersProcessed = 0;
311
+ while (markersProcessed < MAX_MCP_SERVERS_MARKERS) {
312
+ const markerIdx = content.indexOf(marker, fromIdx);
313
+ if (markerIdx === -1)
314
+ break;
315
+ fromIdx = markerIdx + marker.length;
316
+ markersProcessed++;
317
+ let i = markerIdx + marker.length;
318
+ while (i < content.length && /\s/.test(content[i]))
319
+ i++;
320
+ if (content[i] !== ':')
321
+ continue;
322
+ i++;
323
+ while (i < content.length && /\s/.test(content[i]))
324
+ i++;
325
+ if (content[i] !== '{')
326
+ continue;
327
+ const closeIdx = findMatchingBrace(content, i);
328
+ if (closeIdx === -1)
329
+ continue;
330
+ let parsed;
331
+ try {
332
+ parsed = JSON.parse(content.slice(i, closeIdx + 1));
333
+ }
334
+ catch {
335
+ continue;
336
+ }
337
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
338
+ const lineNumber = content.slice(0, markerIdx).split('\n').length;
339
+ for (const server of Object.keys(parsed)) {
340
+ if (JSON_SERVER_NAME.test(server)) {
341
+ refs.push({ server, line: lineNumber });
342
+ }
343
+ }
344
+ }
345
+ }
346
+ return refs;
347
+ }
92
348
  //# sourceMappingURL=McpReferenceExtractor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"McpReferenceExtractor.js","sourceRoot":"","sources":["../../../src/analysis/McpReferenceExtractor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"McpReferenceExtractor.js","sourceRoot":"","sources":["../../../src/analysis/McpReferenceExtractor.ts"],"names":[],"mappings":"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"}
@@ -259,4 +259,8 @@ describe('McpReferenceExtractor', () => {
259
259
  });
260
260
  });
261
261
  });
262
+ // SMI-5676 extraction-hardening tests (frontmatter parsing, mcpServers
263
+ // JSON-block detection, .mcp.json cross-check tagging) live in the sibling
264
+ // McpReferenceExtractor.hardening.test.ts, split out to stay under the
265
+ // 500-line file gate.
262
266
  //# sourceMappingURL=McpReferenceExtractor.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"McpReferenceExtractor.test.js","sourceRoot":"","sources":["../../../src/analysis/McpReferenceExtractor.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EAAE,oBAAoB,EAAqB,MAAM,4BAA4B,CAAA;AAEpF,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;QACpC,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,OAAO,GAAG,+CAA+C,CAAA;YAC/D,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;YACzC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAe;gBACjD,MAAM,EAAE,QAAQ;gBAChB,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,CAAC;gBACP,WAAW,EAAE,KAAK;aACnB,CAAC,CAAA;YACF,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC1C,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC1D,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,MAAM,OAAO,GAAG;gBACd,WAAW;gBACX,eAAe;gBACf,kDAAkD;gBAClD,KAAK;gBACL,WAAW;aACZ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAEZ,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;YACzC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC1C,gDAAgD;YAChD,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAClD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,OAAO,GAAG;gBACd,yCAAyC;gBACzC,+CAA+C;gBAC/C,yCAAyC;aAC1C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAEZ,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;YACzC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAA;QACzE,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,OAAO,GAAG,+CAA+C,CAAA;YAC/D,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;YACzC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;YACvD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QACvD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;YACvD,MAAM,OAAO,GAAG;gBACd,YAAY;gBACZ,EAAE;gBACF,iCAAiC;gBACjC,EAAE;gBACF,UAAU;gBACV,EAAE;gBACF,0BAA0B;aAC3B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAEZ,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YACrC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YAClC,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YAChD,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,aAAa,EAAE,CAAA;QAC1C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,MAAM,OAAO,GAAG;gBACd,0CAA0C;gBAC1C,KAAK;gBACL,4CAA4C;gBAC5C,KAAK;gBACL,wCAAwC;aACzC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAEZ,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;YACzC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACpD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,OAAO,GAAG;gBACd,KAAK;gBACL,+CAA+C;gBAC/C,KAAK;gBACL,mEAAmE;gBACnE,KAAK;gBACL,kCAAkC;aACnC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAEZ,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAC/C,0EAA0E;YAC1E,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAA;YACnC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA,CAAC,SAAS;YAE3C,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACvC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,MAAM,OAAO,GAAG,2BAA2B,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;YACtD,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,aAAa,EAAE,CAAA;YACxC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;QAC5C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;YAC7D,MAAM,OAAO,GAAG,mDAAmD,CAAA;YACnE,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACvC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YAC3D,MAAM,OAAO,GAAG,mEAAmE,CAAA;YACnF,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;YACzC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACpD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;YACxD,MAAM,OAAO,GAAG,kEAAkE,CAAA;YAClF,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;YACzC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;YACpD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;YACnD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACzC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QAC3C,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,wEAAwE,EAAE,GAAG,EAAE;YAChF,MAAM,OAAO,GAAG;gBACd,+CAA+C;gBAC/C,KAAK;gBACL,kDAAkD;gBAClD,KAAK;aACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAEZ,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAA;YACzD,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC1D,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;YAC9E,MAAM,OAAO,GAAG;gBACd,yCAAyC;gBACzC,KAAK;gBACL,uCAAuC;gBACvC,KAAK;aACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAEZ,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;YACzC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;YAC1C,6DAA6D;YAC7D,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;QAC1D,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,OAAO,GAAG;gBACd,MAAM;gBACN,iDAAiD;gBACjD,KAAK;gBACL,0DAA0D;gBAC1D,wBAAwB;gBACxB,MAAM;gBACN,kCAAkC;aACnC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAEZ,MAAM,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAE5C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtD,CAAC,CAAC,CAAA;QAEF,QAAQ,CAAC,0CAA0C,EAAE,GAAG,EAAE;YACxD,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;gBACjE,MAAM,cAAc,GAAG;oBACrB,4BAA4B;oBAC5B,EAAE;oBACF,aAAa;oBACb,EAAE;oBACF,uDAAuD;oBACvD,qDAAqD;oBACrD,iDAAiD;oBACjD,EAAE;oBACF,iBAAiB;oBACjB,EAAE;oBACF,mEAAmE;oBACnE,EAAE;oBACF,UAAU;oBACV,EAAE;oBACF,uBAAuB;oBACvB,EAAE;oBACF,eAAe;oBACf,8BAA8B;oBAC9B,gDAAgD;oBAChD,qBAAqB;oBACrB,uBAAuB;oBACvB,IAAI;oBACJ,KAAK;oBACL,EAAE;oBACF,qBAAqB;oBACrB,EAAE;oBACF,SAAS;oBACT,4CAA4C;oBAC5C,gDAAgD;oBAChD,KAAK;oBACL,EAAE;oBACF,UAAU;oBACV,EAAE;oBACF,oDAAoD;iBACrD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBAEZ,MAAM,MAAM,GAAG,oBAAoB,CAAC,cAAc,CAAC,CAAA;gBAEnD,oBAAoB;gBACpB,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAA;gBAE1D,iBAAiB;gBACjB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAA;gBAEvE,oEAAoE;gBACpE,8CAA8C;gBAC9C,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAA;gBAEtE,sDAAsD;gBACtD,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;gBACjE,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;gBAE/D,sDAAsD;gBACtD,kCAAkC;gBAClC,MAAM,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;gBAEjC,uCAAuC;gBACvC,4CAA4C;gBAC5C,MAAM,CAAC,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;gBAEhC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,aAAa,EAAE,CAAA;YAC1C,CAAC,CAAC,CAAA;YAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;gBACvD,MAAM,UAAU,GAAG;oBACjB,gBAAgB;oBAChB,EAAE;oBACF,aAAa;oBACb,EAAE;oBACF,iCAAiC;oBACjC,EAAE;oBACF,UAAU;oBACV,EAAE;oBACF,SAAS;oBACT,oBAAoB;oBACpB,KAAK;iBACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBAEZ,MAAM,MAAM,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAAA;gBAE/C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;gBACrC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;gBAClC,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YAClD,CAAC,CAAC,CAAA;YAEF,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;gBAChE,MAAM,aAAa,GAAG;oBACpB,eAAe;oBACf,EAAE;oBACF,iCAAiC;oBACjC,EAAE;oBACF,eAAe;oBACf,kDAAkD;oBAClD,qDAAqD;oBACrD,KAAK;iBACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBAEZ,MAAM,MAAM,GAAG,oBAAoB,CAAC,aAAa,CAAC,CAAA;gBAElD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;gBACzC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,CAAC,CAAC,CAAA;gBAC/C,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YAClD,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"McpReferenceExtractor.test.js","sourceRoot":"","sources":["../../../src/analysis/McpReferenceExtractor.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Atomic config-file write primitives.
3
+ * @module @skillsmith/core/config/config-atomic-write
4
+ *
5
+ * SMI-5531: `saveConfig` (./index.ts) previously did an unguarded
6
+ * read-then-write (`loadConfig()` then a bare `writeFileSync()`), which has
7
+ * two distinct failure modes under concurrent writers (two CLI/MCP-server
8
+ * processes touching `~/.skillsmith/config.json` around the same time —
9
+ * e.g. one setting `apiKey`, another calling `getOrCreateInstallId()`):
10
+ *
11
+ * 1. Lost update / dropped sibling key: process A and process B both read
12
+ * the same pre-write snapshot, each merges its OWN change on top, then
13
+ * writes; whichever writes last wins, and its snapshot does not include
14
+ * the other's change — that key is silently dropped.
15
+ * 2. Torn write: a bare `writeFileSync` is not atomic with respect to a
16
+ * concurrent reader on every platform/filesystem; a reader could in
17
+ * principle observe a partially-written file.
18
+ *
19
+ * This module fixes both:
20
+ * - {@link acquireConfigLock} serializes ALL writers (cross-process, via a
21
+ * create-exclusive `.lock` sentinel file) so a caller's full
22
+ * read-modify-write sequence is one atomic critical section.
23
+ * - {@link atomicWriteFile} writes to a temp file in the same directory,
24
+ * then `renameSync`s it into place — POSIX guarantees `rename(2)` is
25
+ * atomic, so a concurrent reader (which never needs the lock — only
26
+ * writers do) always observes either the fully-old or fully-new file,
27
+ * never a torn write.
28
+ */
29
+ /**
30
+ * Acquire an exclusive, cross-process lock guarding `configPath`.
31
+ *
32
+ * Uses atomic create-exclusive (the `wx` flag — fails with `EEXIST` if the
33
+ * lock file already exists) as the mutual-exclusion primitive: portable
34
+ * (identical behavior on macOS/Linux/Windows) and needs no extra
35
+ * dependency. Retries with a short backoff until `LOCK_ACQUIRE_TIMEOUT_MS`
36
+ * elapses. If the held lock is older than `STALE_LOCK_AGE_MS` it is assumed
37
+ * abandoned by a crashed process and force-cleared once, then retried.
38
+ *
39
+ * @param configPath - Path to the config file being guarded (NOT the lock
40
+ * file itself — the lock file is `${configPath}.lock`).
41
+ * @param timeoutMs - Override the acquire timeout (test seam; production
42
+ * callers should omit this and use the default).
43
+ * @returns A release function. Callers MUST call it exactly once, in a
44
+ * `finally` block, so the lock is released even if the guarded work throws.
45
+ */
46
+ export declare function acquireConfigLock(configPath: string, timeoutMs?: number): () => void;
47
+ /**
48
+ * Write `content` to `filePath` atomically: write to a temp file in the same
49
+ * directory, then `renameSync` into place. A concurrent reader (which never
50
+ * needs to hold the config lock — only writers do) always observes either
51
+ * the fully-old or fully-new file content, never a torn write.
52
+ *
53
+ * The caller is responsible for holding {@link acquireConfigLock} for the
54
+ * duration of the read-modify-write this write is part of; this function
55
+ * alone only makes the WRITE step atomic, not the whole sequence around it.
56
+ */
57
+ export declare function atomicWriteFile(filePath: string, content: string, mode: number): void;
58
+ //# sourceMappingURL=config-atomic-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-atomic-write.d.ts","sourceRoot":"","sources":["../../../src/config/config-atomic-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AA2CH;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAAgC,GAC1C,MAAM,IAAI,CAmDZ;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAarF"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Atomic config-file write primitives.
3
+ * @module @skillsmith/core/config/config-atomic-write
4
+ *
5
+ * SMI-5531: `saveConfig` (./index.ts) previously did an unguarded
6
+ * read-then-write (`loadConfig()` then a bare `writeFileSync()`), which has
7
+ * two distinct failure modes under concurrent writers (two CLI/MCP-server
8
+ * processes touching `~/.skillsmith/config.json` around the same time —
9
+ * e.g. one setting `apiKey`, another calling `getOrCreateInstallId()`):
10
+ *
11
+ * 1. Lost update / dropped sibling key: process A and process B both read
12
+ * the same pre-write snapshot, each merges its OWN change on top, then
13
+ * writes; whichever writes last wins, and its snapshot does not include
14
+ * the other's change — that key is silently dropped.
15
+ * 2. Torn write: a bare `writeFileSync` is not atomic with respect to a
16
+ * concurrent reader on every platform/filesystem; a reader could in
17
+ * principle observe a partially-written file.
18
+ *
19
+ * This module fixes both:
20
+ * - {@link acquireConfigLock} serializes ALL writers (cross-process, via a
21
+ * create-exclusive `.lock` sentinel file) so a caller's full
22
+ * read-modify-write sequence is one atomic critical section.
23
+ * - {@link atomicWriteFile} writes to a temp file in the same directory,
24
+ * then `renameSync`s it into place — POSIX guarantees `rename(2)` is
25
+ * atomic, so a concurrent reader (which never needs the lock — only
26
+ * writers do) always observes either the fully-old or fully-new file,
27
+ * never a torn write.
28
+ */
29
+ import { randomBytes } from 'node:crypto';
30
+ import { openSync, closeSync, unlinkSync, writeFileSync, renameSync, statSync, chmodSync, } from 'node:fs';
31
+ import { dirname, join } from 'node:path';
32
+ /**
33
+ * Max time to wait for a lock before giving up (ms). This guards a
34
+ * user-facing CLI/MCP-server startup path, so it must fail loudly with a
35
+ * clear error rather than hang indefinitely.
36
+ */
37
+ const LOCK_ACQUIRE_TIMEOUT_MS = 5_000;
38
+ /** Backoff between lock-acquisition retries (ms). */
39
+ const LOCK_RETRY_DELAY_MS = 20;
40
+ /**
41
+ * A lock file older than this is assumed to be left behind by a crashed
42
+ * process (stale) and is force-removed. A healthy holder releases the lock
43
+ * within milliseconds of a local JSON read+write, so this is a generous
44
+ * margin, not a tight race.
45
+ */
46
+ const STALE_LOCK_AGE_MS = 10_000;
47
+ /**
48
+ * Synchronously block the calling thread for `ms` milliseconds without
49
+ * spinning the CPU. `Atomics.wait` on a throwaway `SharedArrayBuffer` is the
50
+ * standard synchronous-sleep primitive in Node (unlike browsers, Node does
51
+ * not forbid calling it on the main thread).
52
+ */
53
+ function sleepSync(ms) {
54
+ const view = new Int32Array(new SharedArrayBuffer(4));
55
+ Atomics.wait(view, 0, 0, ms);
56
+ }
57
+ /**
58
+ * Acquire an exclusive, cross-process lock guarding `configPath`.
59
+ *
60
+ * Uses atomic create-exclusive (the `wx` flag — fails with `EEXIST` if the
61
+ * lock file already exists) as the mutual-exclusion primitive: portable
62
+ * (identical behavior on macOS/Linux/Windows) and needs no extra
63
+ * dependency. Retries with a short backoff until `LOCK_ACQUIRE_TIMEOUT_MS`
64
+ * elapses. If the held lock is older than `STALE_LOCK_AGE_MS` it is assumed
65
+ * abandoned by a crashed process and force-cleared once, then retried.
66
+ *
67
+ * @param configPath - Path to the config file being guarded (NOT the lock
68
+ * file itself — the lock file is `${configPath}.lock`).
69
+ * @param timeoutMs - Override the acquire timeout (test seam; production
70
+ * callers should omit this and use the default).
71
+ * @returns A release function. Callers MUST call it exactly once, in a
72
+ * `finally` block, so the lock is released even if the guarded work throws.
73
+ */
74
+ export function acquireConfigLock(configPath, timeoutMs = LOCK_ACQUIRE_TIMEOUT_MS) {
75
+ const lockPath = `${configPath}.lock`;
76
+ const deadline = Date.now() + timeoutMs;
77
+ let staleClearAttempted = false;
78
+ for (;;) {
79
+ try {
80
+ const fd = openSync(lockPath, 'wx', 0o600);
81
+ try {
82
+ writeFileSync(fd, String(process.pid));
83
+ }
84
+ finally {
85
+ closeSync(fd);
86
+ }
87
+ return () => {
88
+ try {
89
+ unlinkSync(lockPath);
90
+ }
91
+ catch {
92
+ // Already gone. Releasing an already-released lock is a no-op,
93
+ // not an error (defensive — should not happen in practice since
94
+ // each acquire pairs with exactly one release).
95
+ }
96
+ };
97
+ }
98
+ catch (err) {
99
+ if (err.code !== 'EEXIST')
100
+ throw err;
101
+ if (!staleClearAttempted) {
102
+ staleClearAttempted = true;
103
+ try {
104
+ const age = Date.now() - statSync(lockPath).mtimeMs;
105
+ if (age > STALE_LOCK_AGE_MS) {
106
+ unlinkSync(lockPath);
107
+ continue; // retry immediately — don't burn the backoff budget on this attempt
108
+ }
109
+ }
110
+ catch {
111
+ // Lock file vanished between the failed open and this stat (the
112
+ // holder released it concurrently, or another waiter already
113
+ // cleared it) — just retry the open below.
114
+ continue;
115
+ }
116
+ }
117
+ if (Date.now() >= deadline) {
118
+ throw new Error(`[skillsmith] Timed out waiting for config lock at ${lockPath} after ` +
119
+ `${timeoutMs}ms. If this persists, a crashed process may have left a ` +
120
+ `stale lock — verify no other skillsmith process is running, then remove ${lockPath} manually.`);
121
+ }
122
+ sleepSync(LOCK_RETRY_DELAY_MS);
123
+ }
124
+ }
125
+ }
126
+ /**
127
+ * Write `content` to `filePath` atomically: write to a temp file in the same
128
+ * directory, then `renameSync` into place. A concurrent reader (which never
129
+ * needs to hold the config lock — only writers do) always observes either
130
+ * the fully-old or fully-new file content, never a torn write.
131
+ *
132
+ * The caller is responsible for holding {@link acquireConfigLock} for the
133
+ * duration of the read-modify-write this write is part of; this function
134
+ * alone only makes the WRITE step atomic, not the whole sequence around it.
135
+ */
136
+ export function atomicWriteFile(filePath, content, mode) {
137
+ const dir = dirname(filePath);
138
+ const tmpPath = join(dir, `.${randomBytes(6).toString('hex')}.tmp`);
139
+ writeFileSync(tmpPath, content, { encoding: 'utf-8', mode });
140
+ renameSync(tmpPath, filePath);
141
+ // rename() preserves the temp file's mode bits on POSIX, but re-assert
142
+ // explicitly — belt-and-braces, mirroring saveConfig's prior behavior, and
143
+ // a no-op cost on the common path.
144
+ try {
145
+ chmodSync(filePath, mode);
146
+ }
147
+ catch {
148
+ // Ignore chmod errors on Windows.
149
+ }
150
+ }
151
+ //# sourceMappingURL=config-atomic-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-atomic-write.js","sourceRoot":"","sources":["../../../src/config/config-atomic-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EACL,QAAQ,EACR,SAAS,EACT,UAAU,EACV,aAAa,EACb,UAAU,EACV,QAAQ,EACR,SAAS,GACV,MAAM,SAAS,CAAA;AAChB,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEzC;;;;GAIG;AACH,MAAM,uBAAuB,GAAG,KAAK,CAAA;AAErC,qDAAqD;AACrD,MAAM,mBAAmB,GAAG,EAAE,CAAA;AAE9B;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,MAAM,CAAA;AAEhC;;;;;GAKG;AACH,SAAS,SAAS,CAAC,EAAU;IAC3B,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAA;IACrD,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAA;AAC9B,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAkB,EAClB,YAAoB,uBAAuB;IAE3C,MAAM,QAAQ,GAAG,GAAG,UAAU,OAAO,CAAA;IACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAA;IACvC,IAAI,mBAAmB,GAAG,KAAK,CAAA;IAE/B,SAAS,CAAC;QACR,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;YAC1C,IAAI,CAAC;gBACH,aAAa,CAAC,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;YACxC,CAAC;oBAAS,CAAC;gBACT,SAAS,CAAC,EAAE,CAAC,CAAA;YACf,CAAC;YACD,OAAO,GAAG,EAAE;gBACV,IAAI,CAAC;oBACH,UAAU,CAAC,QAAQ,CAAC,CAAA;gBACtB,CAAC;gBAAC,MAAM,CAAC;oBACP,+DAA+D;oBAC/D,gEAAgE;oBAChE,gDAAgD;gBAClD,CAAC;YACH,CAAC,CAAA;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,GAAG,CAAA;YAE/D,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBACzB,mBAAmB,GAAG,IAAI,CAAA;gBAC1B,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAA;oBACnD,IAAI,GAAG,GAAG,iBAAiB,EAAE,CAAC;wBAC5B,UAAU,CAAC,QAAQ,CAAC,CAAA;wBACpB,SAAQ,CAAC,oEAAoE;oBAC/E,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,gEAAgE;oBAChE,6DAA6D;oBAC7D,2CAA2C;oBAC3C,SAAQ;gBACV,CAAC;YACH,CAAC;YAED,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CACb,qDAAqD,QAAQ,SAAS;oBACpE,GAAG,SAAS,0DAA0D;oBACtE,2EAA2E,QAAQ,YAAY,CAClG,CAAA;YACH,CAAC;YACD,SAAS,CAAC,mBAAmB,CAAC,CAAA;QAChC,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,OAAe,EAAE,IAAY;IAC7E,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IACnE,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;IAC5D,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IAC7B,uEAAuE;IACvE,2EAA2E;IAC3E,mCAAmC;IACnC,IAAI,CAAC;QACH,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,kCAAkC;IACpC,CAAC;AACH,CAAC"}