harmonica-mcp 0.2.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.
- package/LICENSE +18 -0
- package/README.md +73 -0
- package/dist/client.d.ts +99 -0
- package/dist/client.js +70 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +127 -0
- package/dist/index.js.map +1 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Harmonica
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
6
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
12
|
+
portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
15
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
16
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
18
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Harmonica MCP Server
|
|
2
|
+
|
|
3
|
+
MCP server enabling AI agents to create and query [Harmonica](https://harmonica.chat) deliberation sessions.
|
|
4
|
+
|
|
5
|
+
[Harmonica](https://harmonica.chat) is a structured deliberation platform where groups coordinate through AI-facilitated async conversations. Create a session with a topic and goal, share a link with participants, and each person has a private 1:1 conversation with an AI facilitator. Responses are synthesized into actionable insights.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
### npx (no install)
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"mcpServers": {
|
|
14
|
+
"harmonica": {
|
|
15
|
+
"command": "npx",
|
|
16
|
+
"args": ["-y", "harmonica-mcp"],
|
|
17
|
+
"env": {
|
|
18
|
+
"HARMONICA_API_KEY": "hm_live_your_key_here"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### From source
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
git clone https://github.com/harmonicabot/harmonica-mcp.git
|
|
29
|
+
cd harmonica-mcp
|
|
30
|
+
npm install && npm run build
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"harmonica": {
|
|
37
|
+
"command": "node",
|
|
38
|
+
"args": ["/path/to/harmonica-mcp/dist/index.js"],
|
|
39
|
+
"env": {
|
|
40
|
+
"HARMONICA_API_KEY": "hm_live_your_key_here"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Get an API key
|
|
48
|
+
|
|
49
|
+
1. [Sign up for Harmonica](https://app.harmonica.chat) (free)
|
|
50
|
+
2. Go to [Profile](https://app.harmonica.chat/profile) > **API Keys** > **Generate API Key**
|
|
51
|
+
3. Copy your `hm_live_...` key — it's only shown once
|
|
52
|
+
|
|
53
|
+
## Tools
|
|
54
|
+
|
|
55
|
+
| Tool | Description |
|
|
56
|
+
|------|-------------|
|
|
57
|
+
| `create_session` | Create a new deliberation session and get a shareable join URL |
|
|
58
|
+
| `list_sessions` | List your deliberation sessions (filter by status, search) |
|
|
59
|
+
| `get_session` | Get full session details |
|
|
60
|
+
| `get_responses` | Get participant responses |
|
|
61
|
+
| `get_summary` | Get AI-generated summary |
|
|
62
|
+
| `search_sessions` | Search by topic or goal |
|
|
63
|
+
|
|
64
|
+
## Environment Variables
|
|
65
|
+
|
|
66
|
+
| Variable | Required | Default | Description |
|
|
67
|
+
|----------|----------|---------|-------------|
|
|
68
|
+
| `HARMONICA_API_KEY` | Yes | — | Your Harmonica API key |
|
|
69
|
+
| `HARMONICA_API_URL` | No | `https://app.harmonica.chat` | API base URL |
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for the Harmonica REST API v1.
|
|
3
|
+
* All methods throw on HTTP errors.
|
|
4
|
+
*/
|
|
5
|
+
export interface HarmonicaClientConfig {
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
apiKey: string;
|
|
8
|
+
}
|
|
9
|
+
export declare class HarmonicaClient {
|
|
10
|
+
private baseUrl;
|
|
11
|
+
private apiKey;
|
|
12
|
+
constructor(config: HarmonicaClientConfig);
|
|
13
|
+
private request;
|
|
14
|
+
getMe(): Promise<{
|
|
15
|
+
id: string;
|
|
16
|
+
email: string;
|
|
17
|
+
name: string | null;
|
|
18
|
+
subscription_status: string;
|
|
19
|
+
}>;
|
|
20
|
+
listSessions(params?: {
|
|
21
|
+
status?: 'active' | 'completed';
|
|
22
|
+
q?: string;
|
|
23
|
+
limit?: number;
|
|
24
|
+
offset?: number;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
data: Array<{
|
|
27
|
+
id: string;
|
|
28
|
+
topic: string;
|
|
29
|
+
goal: string;
|
|
30
|
+
status: string;
|
|
31
|
+
participant_count: number;
|
|
32
|
+
created_at: string;
|
|
33
|
+
updated_at: string;
|
|
34
|
+
}>;
|
|
35
|
+
pagination: {
|
|
36
|
+
total: number;
|
|
37
|
+
limit: number;
|
|
38
|
+
offset: number;
|
|
39
|
+
};
|
|
40
|
+
}>;
|
|
41
|
+
getSession(id: string): Promise<{
|
|
42
|
+
id: string;
|
|
43
|
+
topic: string;
|
|
44
|
+
goal: string;
|
|
45
|
+
critical: string | null;
|
|
46
|
+
context: string | null;
|
|
47
|
+
status: string;
|
|
48
|
+
summary: string | null;
|
|
49
|
+
participant_count: number;
|
|
50
|
+
created_at: string;
|
|
51
|
+
updated_at: string;
|
|
52
|
+
}>;
|
|
53
|
+
getSessionQuestions(sessionId: string): Promise<{
|
|
54
|
+
data: Array<{
|
|
55
|
+
id: string;
|
|
56
|
+
text: string;
|
|
57
|
+
position: number;
|
|
58
|
+
}>;
|
|
59
|
+
}>;
|
|
60
|
+
getSessionResponses(sessionId: string): Promise<{
|
|
61
|
+
data: Array<{
|
|
62
|
+
participant_name: string | null;
|
|
63
|
+
messages: Array<{
|
|
64
|
+
role: "user" | "assistant";
|
|
65
|
+
content: string;
|
|
66
|
+
created_at: string;
|
|
67
|
+
}>;
|
|
68
|
+
}>;
|
|
69
|
+
}>;
|
|
70
|
+
submitResponse(sessionId: string, content: string): Promise<{
|
|
71
|
+
id: string;
|
|
72
|
+
session_id: string;
|
|
73
|
+
content: string;
|
|
74
|
+
created_at: string;
|
|
75
|
+
}>;
|
|
76
|
+
createSession(params: {
|
|
77
|
+
topic: string;
|
|
78
|
+
goal: string;
|
|
79
|
+
context?: string;
|
|
80
|
+
critical?: string;
|
|
81
|
+
prompt?: string;
|
|
82
|
+
template_id?: string;
|
|
83
|
+
cross_pollination?: boolean;
|
|
84
|
+
}): Promise<{
|
|
85
|
+
id: string;
|
|
86
|
+
topic: string;
|
|
87
|
+
goal: string;
|
|
88
|
+
status: string;
|
|
89
|
+
participant_count: number;
|
|
90
|
+
created_at: string;
|
|
91
|
+
updated_at: string;
|
|
92
|
+
join_url: string;
|
|
93
|
+
}>;
|
|
94
|
+
getSessionSummary(sessionId: string): Promise<{
|
|
95
|
+
session_id: string;
|
|
96
|
+
summary: string | null;
|
|
97
|
+
generated_at: string | null;
|
|
98
|
+
}>;
|
|
99
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for the Harmonica REST API v1.
|
|
3
|
+
* All methods throw on HTTP errors.
|
|
4
|
+
*/
|
|
5
|
+
export class HarmonicaClient {
|
|
6
|
+
baseUrl;
|
|
7
|
+
apiKey;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.baseUrl = config.baseUrl.replace(/\/+$/, '');
|
|
10
|
+
this.apiKey = config.apiKey;
|
|
11
|
+
}
|
|
12
|
+
async request(path, options) {
|
|
13
|
+
const url = `${this.baseUrl}/api/v1${path}`;
|
|
14
|
+
const res = await fetch(url, {
|
|
15
|
+
...options,
|
|
16
|
+
headers: {
|
|
17
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
18
|
+
'Content-Type': 'application/json',
|
|
19
|
+
...options?.headers,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
const body = await res.json().catch(() => ({}));
|
|
24
|
+
const message = body?.error?.message || `HTTP ${res.status}`;
|
|
25
|
+
throw new Error(`Harmonica API error: ${message}`);
|
|
26
|
+
}
|
|
27
|
+
return res.json();
|
|
28
|
+
}
|
|
29
|
+
async getMe() {
|
|
30
|
+
return this.request('/me');
|
|
31
|
+
}
|
|
32
|
+
async listSessions(params) {
|
|
33
|
+
const query = new URLSearchParams();
|
|
34
|
+
if (params?.status)
|
|
35
|
+
query.set('status', params.status);
|
|
36
|
+
if (params?.q)
|
|
37
|
+
query.set('q', params.q);
|
|
38
|
+
if (params?.limit)
|
|
39
|
+
query.set('limit', String(params.limit));
|
|
40
|
+
if (params?.offset)
|
|
41
|
+
query.set('offset', String(params.offset));
|
|
42
|
+
const qs = query.toString();
|
|
43
|
+
return this.request(`/sessions${qs ? `?${qs}` : ''}`);
|
|
44
|
+
}
|
|
45
|
+
async getSession(id) {
|
|
46
|
+
return this.request(`/sessions/${id}`);
|
|
47
|
+
}
|
|
48
|
+
async getSessionQuestions(sessionId) {
|
|
49
|
+
return this.request(`/sessions/${sessionId}/questions`);
|
|
50
|
+
}
|
|
51
|
+
async getSessionResponses(sessionId) {
|
|
52
|
+
return this.request(`/sessions/${sessionId}/responses`);
|
|
53
|
+
}
|
|
54
|
+
async submitResponse(sessionId, content) {
|
|
55
|
+
return this.request(`/sessions/${sessionId}/responses`, {
|
|
56
|
+
method: 'POST',
|
|
57
|
+
body: JSON.stringify({ content }),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
async createSession(params) {
|
|
61
|
+
return this.request('/sessions', {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
body: JSON.stringify(params),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async getSessionSummary(sessionId) {
|
|
67
|
+
return this.request(`/sessions/${sessionId}/summary`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { HarmonicaClient } from './client.js';
|
|
6
|
+
const HARMONICA_API_URL = process.env.HARMONICA_API_URL || 'https://app.harmonica.chat';
|
|
7
|
+
const HARMONICA_API_KEY = process.env.HARMONICA_API_KEY;
|
|
8
|
+
if (!HARMONICA_API_KEY) {
|
|
9
|
+
console.error('Error: HARMONICA_API_KEY environment variable is required.');
|
|
10
|
+
console.error('Generate one at https://app.harmonica.chat (Profile → API Keys)');
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
const client = new HarmonicaClient({
|
|
14
|
+
baseUrl: HARMONICA_API_URL,
|
|
15
|
+
apiKey: HARMONICA_API_KEY,
|
|
16
|
+
});
|
|
17
|
+
const server = new McpServer({
|
|
18
|
+
name: 'harmonica',
|
|
19
|
+
version: '0.1.0',
|
|
20
|
+
});
|
|
21
|
+
// ─── Tools ───────────────────────────────────────────────────────────
|
|
22
|
+
server.tool('list_sessions', 'List Harmonica deliberation sessions you have access to', {
|
|
23
|
+
status: z.enum(['active', 'completed']).optional().describe('Filter by status'),
|
|
24
|
+
query: z.string().optional().describe('Search by topic or goal'),
|
|
25
|
+
limit: z.number().min(1).max(100).optional().describe('Results per page (default 20)'),
|
|
26
|
+
}, async ({ status, query, limit }) => {
|
|
27
|
+
const result = await client.listSessions({ status, q: query, limit });
|
|
28
|
+
const lines = result.data.map((s) => `[${s.status}] ${s.topic} (${s.participant_count} participants) — ${s.id}`);
|
|
29
|
+
const text = lines.length
|
|
30
|
+
? `${result.pagination.total} sessions found:\n\n${lines.join('\n')}`
|
|
31
|
+
: 'No sessions found.';
|
|
32
|
+
return { content: [{ type: 'text', text }] };
|
|
33
|
+
});
|
|
34
|
+
server.tool('get_session', 'Get details of a specific Harmonica session', {
|
|
35
|
+
session_id: z.string().describe('Session ID (UUID)'),
|
|
36
|
+
}, async ({ session_id }) => {
|
|
37
|
+
const s = await client.getSession(session_id);
|
|
38
|
+
const text = [
|
|
39
|
+
`**${s.topic}**`,
|
|
40
|
+
`Status: ${s.status} | Participants: ${s.participant_count}`,
|
|
41
|
+
`Goal: ${s.goal}`,
|
|
42
|
+
s.critical ? `Critical: ${s.critical}` : null,
|
|
43
|
+
s.context ? `Context: ${s.context}` : null,
|
|
44
|
+
s.summary ? `\nSummary:\n${s.summary}` : null,
|
|
45
|
+
`\nCreated: ${s.created_at}`,
|
|
46
|
+
]
|
|
47
|
+
.filter(Boolean)
|
|
48
|
+
.join('\n');
|
|
49
|
+
return { content: [{ type: 'text', text }] };
|
|
50
|
+
});
|
|
51
|
+
server.tool('get_responses', 'Get participant responses for a Harmonica session', {
|
|
52
|
+
session_id: z.string().describe('Session ID (UUID)'),
|
|
53
|
+
}, async ({ session_id }) => {
|
|
54
|
+
const result = await client.getSessionResponses(session_id);
|
|
55
|
+
if (!result.data.length) {
|
|
56
|
+
return { content: [{ type: 'text', text: 'No responses yet.' }] };
|
|
57
|
+
}
|
|
58
|
+
const sections = result.data.map((p) => {
|
|
59
|
+
const name = p.participant_name || 'Anonymous';
|
|
60
|
+
const msgs = p.messages
|
|
61
|
+
.filter((m) => m.role === 'user')
|
|
62
|
+
.map((m) => ` > ${m.content}`)
|
|
63
|
+
.join('\n');
|
|
64
|
+
return `**${name}:**\n${msgs || ' (no responses)'}`;
|
|
65
|
+
});
|
|
66
|
+
return { content: [{ type: 'text', text: sections.join('\n\n') }] };
|
|
67
|
+
});
|
|
68
|
+
server.tool('get_summary', 'Get the AI-generated summary for a Harmonica session', {
|
|
69
|
+
session_id: z.string().describe('Session ID (UUID)'),
|
|
70
|
+
}, async ({ session_id }) => {
|
|
71
|
+
const result = await client.getSessionSummary(session_id);
|
|
72
|
+
const text = result.summary || 'No summary available yet (session may still be active).';
|
|
73
|
+
return { content: [{ type: 'text', text }] };
|
|
74
|
+
});
|
|
75
|
+
server.tool('search_sessions', 'Search Harmonica sessions by topic or goal keywords', {
|
|
76
|
+
query: z.string().describe('Search keywords'),
|
|
77
|
+
status: z.enum(['active', 'completed']).optional().describe('Filter by status'),
|
|
78
|
+
}, async ({ query, status }) => {
|
|
79
|
+
const result = await client.listSessions({ q: query, status, limit: 20 });
|
|
80
|
+
if (!result.data.length) {
|
|
81
|
+
return { content: [{ type: 'text', text: `No sessions match "${query}".` }] };
|
|
82
|
+
}
|
|
83
|
+
const lines = result.data.map((s) => `- [${s.status}] **${s.topic}** — ${s.goal}\n ID: ${s.id}`);
|
|
84
|
+
return {
|
|
85
|
+
content: [{ type: 'text', text: `Found ${result.pagination.total} sessions:\n\n${lines.join('\n')}` }],
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
server.tool('create_session', 'Create a new Harmonica deliberation session and get a shareable join URL', {
|
|
89
|
+
topic: z.string().describe('Session topic'),
|
|
90
|
+
goal: z.string().describe('What this session aims to achieve'),
|
|
91
|
+
context: z.string().optional().describe('Background context for participants'),
|
|
92
|
+
critical: z.string().optional().describe('Critical question or constraint'),
|
|
93
|
+
prompt: z.string().optional().describe('Custom facilitation prompt'),
|
|
94
|
+
template_id: z.string().optional().describe('Template ID to use'),
|
|
95
|
+
cross_pollination: z.boolean().optional().describe('Enable idea sharing between participant threads'),
|
|
96
|
+
}, async ({ topic, goal, context, critical, prompt, template_id, cross_pollination }) => {
|
|
97
|
+
const session = await client.createSession({
|
|
98
|
+
topic,
|
|
99
|
+
goal,
|
|
100
|
+
context,
|
|
101
|
+
critical,
|
|
102
|
+
prompt,
|
|
103
|
+
template_id,
|
|
104
|
+
cross_pollination,
|
|
105
|
+
});
|
|
106
|
+
const text = [
|
|
107
|
+
`Session created!`,
|
|
108
|
+
``,
|
|
109
|
+
` Topic: ${session.topic}`,
|
|
110
|
+
` ID: ${session.id}`,
|
|
111
|
+
` Status: ${session.status}`,
|
|
112
|
+
` Join URL: ${session.join_url}`,
|
|
113
|
+
``,
|
|
114
|
+
`Share the join URL with participants to start the session.`,
|
|
115
|
+
].join('\n');
|
|
116
|
+
return { content: [{ type: 'text', text }] };
|
|
117
|
+
});
|
|
118
|
+
// ─── Start ───────────────────────────────────────────────────────────
|
|
119
|
+
async function main() {
|
|
120
|
+
const transport = new StdioServerTransport();
|
|
121
|
+
await server.connect(transport);
|
|
122
|
+
}
|
|
123
|
+
main().catch((error) => {
|
|
124
|
+
console.error('Fatal error:', error);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
});
|
|
127
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "harmonica-mcp",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "MCP server for Harmonica deliberation sessions",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"bin": {
|
|
9
|
+
"harmonica-mcp": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"prepublishOnly": "npm run build",
|
|
17
|
+
"start": "node dist/index.js",
|
|
18
|
+
"dev": "tsc --watch"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"mcp",
|
|
22
|
+
"harmonica",
|
|
23
|
+
"deliberation",
|
|
24
|
+
"facilitation",
|
|
25
|
+
"model-context-protocol"
|
|
26
|
+
],
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/harmonicabot/harmonica-mcp.git"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/harmonicabot/harmonica-mcp#readme",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
34
|
+
"zod": "^3.24.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^20.11.0",
|
|
38
|
+
"typescript": "^5.5.0"
|
|
39
|
+
}
|
|
40
|
+
}
|