brms-host 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/build/bin/install.d.ts +13 -0
  2. package/build/bin/install.js +124 -0
  3. package/build/bin/install.js.map +1 -0
  4. package/build/bridge/native-messaging.d.ts +27 -0
  5. package/build/bridge/native-messaging.js +118 -0
  6. package/build/bridge/native-messaging.js.map +1 -0
  7. package/build/browser/connection.d.ts +12 -0
  8. package/build/browser/connection.js +57 -0
  9. package/build/browser/connection.js.map +1 -0
  10. package/build/browser/console.d.ts +16 -0
  11. package/build/browser/console.js +44 -0
  12. package/build/browser/console.js.map +1 -0
  13. package/build/browser/dom.d.ts +9 -0
  14. package/build/browser/dom.js +16 -0
  15. package/build/browser/dom.js.map +1 -0
  16. package/build/browser/network.d.ts +14 -0
  17. package/build/browser/network.js +47 -0
  18. package/build/browser/network.js.map +1 -0
  19. package/build/index.d.ts +8 -0
  20. package/build/index.js +111 -0
  21. package/build/index.js.map +1 -0
  22. package/build/server.d.ts +2 -0
  23. package/build/server.js +30 -0
  24. package/build/server.js.map +1 -0
  25. package/build/tools/connection.tools.d.ts +2 -0
  26. package/build/tools/connection.tools.js +28 -0
  27. package/build/tools/connection.tools.js.map +1 -0
  28. package/build/tools/console.tools.d.ts +2 -0
  29. package/build/tools/console.tools.js +25 -0
  30. package/build/tools/console.tools.js.map +1 -0
  31. package/build/tools/debug.tools.d.ts +2 -0
  32. package/build/tools/debug.tools.js +226 -0
  33. package/build/tools/debug.tools.js.map +1 -0
  34. package/build/tools/dom.tools.d.ts +2 -0
  35. package/build/tools/dom.tools.js +26 -0
  36. package/build/tools/dom.tools.js.map +1 -0
  37. package/build/tools/events.tools.d.ts +2 -0
  38. package/build/tools/events.tools.js +18 -0
  39. package/build/tools/events.tools.js.map +1 -0
  40. package/build/tools/layout.tools.d.ts +2 -0
  41. package/build/tools/layout.tools.js +20 -0
  42. package/build/tools/layout.tools.js.map +1 -0
  43. package/build/tools/network.tools.d.ts +2 -0
  44. package/build/tools/network.tools.js +29 -0
  45. package/build/tools/network.tools.js.map +1 -0
  46. package/build/tools/screenshot.tools.d.ts +2 -0
  47. package/build/tools/screenshot.tools.js +40 -0
  48. package/build/tools/screenshot.tools.js.map +1 -0
  49. package/build/tools/styles.tools.d.ts +2 -0
  50. package/build/tools/styles.tools.js +22 -0
  51. package/build/tools/styles.tools.js.map +1 -0
  52. package/build/types/index.d.ts +130 -0
  53. package/build/types/index.js +2 -0
  54. package/build/types/index.js.map +1 -0
  55. package/build/utils/errors.d.ts +16 -0
  56. package/build/utils/errors.js +29 -0
  57. package/build/utils/errors.js.map +1 -0
  58. package/build/utils/logger.d.ts +11 -0
  59. package/build/utils/logger.js +15 -0
  60. package/build/utils/logger.js.map +1 -0
  61. package/package.json +35 -0
@@ -0,0 +1,40 @@
1
+ import { z } from 'zod';
2
+ import { bridge } from '../bridge/native-messaging.js';
3
+ import { log } from '../utils/logger.js';
4
+ export function registerScreenshotTools(server) {
5
+ server.tool('capture_screenshot', 'Capture a screenshot of the active page or a specific element. Optionally highlight the target element with a red border before capture.', {
6
+ selector: z.string().optional().describe('CSS selector of element to screenshot (default: full page)'),
7
+ highlight: z.boolean().optional().describe('Inject a temporary red border on the selector before capture (default: false)'),
8
+ format: z.enum(['png', 'jpeg']).optional().describe('Image format (default: png)'),
9
+ quality: z.number().int().min(1).max(100).optional().describe('JPEG quality 1-100 (only for jpeg format)'),
10
+ }, async ({ selector, highlight, format, quality }) => {
11
+ try {
12
+ if (highlight && selector) {
13
+ await bridge.sendRequest('highlight_element', { selector });
14
+ }
15
+ const result = await bridge.sendRequest('screenshot', {
16
+ selector,
17
+ format: format ?? 'png',
18
+ quality: quality ?? 80,
19
+ });
20
+ if (highlight && selector) {
21
+ await bridge.sendRequest('remove_highlight', { selector }).catch(() => { });
22
+ }
23
+ const base64 = result.base64;
24
+ const mimeType = result.mimeType;
25
+ return {
26
+ content: [{
27
+ type: 'image',
28
+ data: base64,
29
+ mimeType,
30
+ }],
31
+ };
32
+ }
33
+ catch (err) {
34
+ const message = err instanceof Error ? err.message : String(err);
35
+ log.error(message);
36
+ return { content: [{ type: 'text', text: `Error: ${message}` }] };
37
+ }
38
+ });
39
+ }
40
+ //# sourceMappingURL=screenshot.tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screenshot.tools.js","sourceRoot":"","sources":["../../src/tools/screenshot.tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAEzC,MAAM,UAAU,uBAAuB,CAAC,MAAiB;IACvD,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,0IAA0I,EAC1I;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4DAA4D,CAAC;QACtG,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+EAA+E,CAAC;QAC3H,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QAClF,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;KAC3G,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QACjD,IAAI,CAAC;YACH,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;gBAC1B,MAAM,MAAM,CAAC,WAAW,CAAC,mBAAmB,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC9D,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE;gBACpD,QAAQ;gBACR,MAAM,EAAE,MAAM,IAAI,KAAK;gBACvB,OAAO,EAAE,OAAO,IAAI,EAAE;aACvB,CAAC,CAAC;YAEH,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;gBAC1B,MAAM,MAAM,CAAC,WAAW,CAAC,kBAAkB,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAC7E,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAgB,CAAC;YACvC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAkB,CAAC;YAE3C,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,OAAgB;wBACtB,IAAI,EAAE,MAAM;wBACZ,QAAQ;qBACT,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACnB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;QAC7E,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ export declare function registerStyleTools(server: McpServer): void;
@@ -0,0 +1,22 @@
1
+ import { z } from 'zod';
2
+ import { bridge } from '../bridge/native-messaging.js';
3
+ import { safeResult } from '../utils/errors.js';
4
+ export function registerStyleTools(server) {
5
+ server.tool('get_computed_styles', 'Get computed CSS styles for elements matching a selector. Optionally includes ancestor chain styles (for debugging clipping/stacking) and pseudo-element styles.', {
6
+ selector: z.string().describe('CSS selector to query'),
7
+ properties: z.array(z.string()).optional().describe('Specific CSS properties to return (default: key layout properties)'),
8
+ includeAncestors: z.boolean().optional().describe('Include overflow/position/zIndex/display of each ancestor up to body (default: false)'),
9
+ includePseudo: z.boolean().optional().describe('Include ::before and ::after pseudo-element styles (default: false)'),
10
+ }, async ({ selector, properties, includeAncestors, includePseudo }) => {
11
+ return safeResult(async () => {
12
+ const result = await bridge.sendRequest('get_styles', {
13
+ selector,
14
+ properties,
15
+ includeAncestors: includeAncestors ?? false,
16
+ includePseudo: includePseudo ?? false,
17
+ });
18
+ return JSON.stringify(result.results ?? result, null, 2);
19
+ });
20
+ });
21
+ }
22
+ //# sourceMappingURL=styles.tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.tools.js","sourceRoot":"","sources":["../../src/tools/styles.tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,kKAAkK,EAClK;QACE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QACtD,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oEAAoE,CAAC;QACzH,gBAAgB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,uFAAuF,CAAC;QAC1I,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qEAAqE,CAAC;KACtH,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,EAAE,EAAE;QAClE,OAAO,UAAU,CAAC,KAAK,IAAI,EAAE;YAC3B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE;gBACpD,QAAQ;gBACR,UAAU;gBACV,gBAAgB,EAAE,gBAAgB,IAAI,KAAK;gBAC3C,aAAa,EAAE,aAAa,IAAI,KAAK;aACtC,CAAC,CAAC;YAEH,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3D,CAAC,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,130 @@
1
+ export interface DOMNode {
2
+ tag: string;
3
+ id: string;
4
+ classes: string[];
5
+ text: string;
6
+ attributes: Record<string, string>;
7
+ children: DOMNode[];
8
+ }
9
+ export interface NetworkEntry {
10
+ url: string;
11
+ method: string;
12
+ status: number | null;
13
+ statusText: string;
14
+ headers: Record<string, string>;
15
+ requestHeaders: Record<string, string>;
16
+ requestBody: string | null;
17
+ responseBody: string | null;
18
+ resourceType: string;
19
+ timing: {
20
+ startTime: number;
21
+ duration: number;
22
+ };
23
+ timestamp: number;
24
+ }
25
+ export interface ConsoleEntry {
26
+ level: 'log' | 'warn' | 'error' | 'info' | 'debug';
27
+ text: string;
28
+ timestamp: number;
29
+ location: string | null;
30
+ }
31
+ export interface PageInfo {
32
+ index: number;
33
+ title: string;
34
+ url: string;
35
+ }
36
+ export interface NetworkFilter {
37
+ urlPattern?: string;
38
+ statusCode?: number;
39
+ resourceType?: string;
40
+ limit?: number;
41
+ }
42
+ export interface ComputedStyleResult {
43
+ selector: string;
44
+ styles: Record<string, string>;
45
+ }
46
+ export interface LayoutInfo {
47
+ selector: string;
48
+ boundingBox: {
49
+ x: number;
50
+ y: number;
51
+ width: number;
52
+ height: number;
53
+ } | null;
54
+ isVisible: boolean;
55
+ isInViewport: boolean;
56
+ }
57
+ export interface OverlapInfo {
58
+ coveredBy: {
59
+ tag: string;
60
+ id: string;
61
+ classes: string[];
62
+ zIndex: string;
63
+ } | null;
64
+ checkedPoints: Array<{
65
+ label: string;
66
+ x: number;
67
+ y: number;
68
+ hitTag: string;
69
+ hitId: string;
70
+ isSelf: boolean;
71
+ }>;
72
+ }
73
+ export interface EventListenerEntry {
74
+ type: string;
75
+ handler: string;
76
+ useCapture: boolean;
77
+ once: boolean;
78
+ passive: boolean;
79
+ }
80
+ export interface EventListenerInfo {
81
+ selector: string;
82
+ element: {
83
+ tag: string;
84
+ id: string;
85
+ };
86
+ listeners: EventListenerEntry[];
87
+ }
88
+ export interface DebugIssue {
89
+ issue: string;
90
+ reasons: string[];
91
+ confidence: number;
92
+ }
93
+ export interface DebugCheck {
94
+ name: string;
95
+ passed: boolean;
96
+ detail: string;
97
+ }
98
+ export type Severity = 'critical' | 'warning' | 'info';
99
+ export interface CorrelationResult {
100
+ domain: string;
101
+ severity: Severity;
102
+ details: string;
103
+ evidence: string[];
104
+ }
105
+ export interface NetworkDiagnosis {
106
+ totalRequests: number;
107
+ timingBuckets: {
108
+ fast: number;
109
+ normal: number;
110
+ slow: number;
111
+ verySlow: number;
112
+ };
113
+ p95ResponseTime: number;
114
+ failedRequests: Array<{
115
+ url: string;
116
+ status: number | null;
117
+ method: string;
118
+ errorBody: string | null;
119
+ }>;
120
+ corsIssues: Array<{
121
+ url: string;
122
+ method: string;
123
+ }>;
124
+ rateLimited: Array<{
125
+ url: string;
126
+ domain: string;
127
+ }>;
128
+ failuresByDomain: Record<string, number>;
129
+ summary: string;
130
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,16 @@
1
+ export declare class BRMSError extends Error {
2
+ readonly code: string;
3
+ constructor(message: string, code: string);
4
+ }
5
+ export declare function notConnected(): BRMSError;
6
+ export declare function noActivePage(): BRMSError;
7
+ /**
8
+ * Wraps a tool handler so MCP errors are returned as structured text
9
+ * instead of crashing the server.
10
+ */
11
+ export declare function safeResult(fn: () => Promise<string>): Promise<{
12
+ content: {
13
+ type: 'text';
14
+ text: string;
15
+ }[];
16
+ }>;
@@ -0,0 +1,29 @@
1
+ import { log } from './logger.js';
2
+ export class BRMSError extends Error {
3
+ code;
4
+ constructor(message, code) {
5
+ super(message);
6
+ this.code = code;
7
+ this.name = 'BRMSError';
8
+ }
9
+ }
10
+ export function notConnected() {
11
+ return new BRMSError('Extension not connected. Ensure the BRMS Chrome Extension is installed and active.', 'NOT_CONNECTED');
12
+ }
13
+ export function noActivePage() {
14
+ return new BRMSError('No active tab selected. Call select_page first.', 'NO_ACTIVE_PAGE');
15
+ }
16
+ /**
17
+ * Wraps a tool handler so MCP errors are returned as structured text
18
+ * instead of crashing the server.
19
+ */
20
+ export function safeResult(fn) {
21
+ return fn()
22
+ .then((text) => ({ content: [{ type: 'text', text }] }))
23
+ .catch((err) => {
24
+ const message = err instanceof Error ? err.message : String(err);
25
+ log.error(message);
26
+ return { content: [{ type: 'text', text: `Error: ${message}` }] };
27
+ });
28
+ }
29
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAElC,MAAM,OAAO,SAAU,SAAQ,KAAK;IAGhB;IAFlB,YACE,OAAe,EACC,IAAY;QAE5B,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,SAAI,GAAJ,IAAI,CAAQ;QAG5B,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC1B,CAAC;CACF;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,SAAS,CAClB,oFAAoF,EACpF,eAAe,CAChB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,SAAS,CAClB,iDAAiD,EACjD,gBAAgB,CACjB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,EAAyB;IAClD,OAAO,EAAE,EAAE;SACR,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;SAChE,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACnB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC;IAC7E,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * All logging goes to stderr so stdout remains clean for native messaging.
3
+ */
4
+ export declare function info(...args: unknown[]): void;
5
+ export declare function warn(...args: unknown[]): void;
6
+ export declare function error(...args: unknown[]): void;
7
+ export declare const log: {
8
+ info: typeof info;
9
+ warn: typeof warn;
10
+ error: typeof error;
11
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * All logging goes to stderr so stdout remains clean for native messaging.
3
+ */
4
+ const PREFIX = '[brms]';
5
+ export function info(...args) {
6
+ console.error(PREFIX, ...args);
7
+ }
8
+ export function warn(...args) {
9
+ console.error(PREFIX, 'WARN', ...args);
10
+ }
11
+ export function error(...args) {
12
+ console.error(PREFIX, 'ERROR', ...args);
13
+ }
14
+ export const log = { info, warn, error };
15
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,GAAG,QAAQ,CAAC;AAExB,MAAM,UAAU,IAAI,CAAC,GAAG,IAAe;IACrC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAG,IAAe;IACrC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,GAAG,IAAe;IACtC,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "brms-host",
3
+ "version": "1.0.0",
4
+ "description": "Native messaging host for BRMS Chrome Extension — bridges browser state to Cursor via MCP",
5
+ "type": "module",
6
+ "bin": {
7
+ "brms-host": "./build/bin/install.js"
8
+ },
9
+ "main": "./build/index.js",
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "start": "node build/index.js",
13
+ "dev": "tsc --watch"
14
+ },
15
+ "files": [
16
+ "build"
17
+ ],
18
+ "keywords": [
19
+ "mcp",
20
+ "browser",
21
+ "devtools",
22
+ "chrome-extension",
23
+ "native-messaging",
24
+ "ai"
25
+ ],
26
+ "license": "MIT",
27
+ "dependencies": {
28
+ "@modelcontextprotocol/sdk": "^1.28.0",
29
+ "zod": "^4.3.6"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^25.5.0",
33
+ "typescript": "^6.0.2"
34
+ }
35
+ }