brave-mcp 0.2.0 → 0.2.1
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/build/src/HeapSnapshotManager.js +61 -0
- package/build/src/McpContext.js +11 -0
- package/build/src/McpResponse.js +44 -0
- package/build/src/PageCollector.js +5 -0
- package/build/src/bin/brave-devtools-mcp-cli-options.js +5 -0
- package/build/src/bin/cliDefinitions.js +3 -3
- package/build/src/formatters/HeapSnapshotFormatter.js +35 -0
- package/build/src/formatters/NetworkFormatter.js +1 -1
- package/build/src/index.js +4 -0
- package/build/src/third_party/devtools-heap-snapshot-worker.js +7 -0
- package/build/src/third_party/index.js +1 -0
- package/build/src/tools/categories.js +2 -0
- package/build/src/tools/memory.js +18 -1
- package/build/src/tools/network.js +2 -2
- package/build/src/tools/pages.js +1 -1
- package/build/src/utils/check-for-updates.js +2 -1
- package/build/src/version.js +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import fsSync from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { DevTools } from './third_party/index.js';
|
|
9
|
+
export class HeapSnapshotManager {
|
|
10
|
+
#snapshots = new Map();
|
|
11
|
+
async getSnapshot(filePath) {
|
|
12
|
+
const absolutePath = path.resolve(filePath);
|
|
13
|
+
const cached = this.#snapshots.get(absolutePath);
|
|
14
|
+
if (cached) {
|
|
15
|
+
return cached.snapshot;
|
|
16
|
+
}
|
|
17
|
+
const { snapshot, worker } = await this.#loadSnapshot(absolutePath);
|
|
18
|
+
this.#snapshots.set(absolutePath, { snapshot, worker });
|
|
19
|
+
return snapshot;
|
|
20
|
+
}
|
|
21
|
+
async getAggregates(filePath) {
|
|
22
|
+
const snapshot = await this.getSnapshot(filePath);
|
|
23
|
+
const filter = new DevTools.HeapSnapshotModel.HeapSnapshotModel.NodeFilter();
|
|
24
|
+
return await snapshot.aggregatesWithFilter(filter);
|
|
25
|
+
}
|
|
26
|
+
async getStats(filePath) {
|
|
27
|
+
const snapshot = await this.getSnapshot(filePath);
|
|
28
|
+
return await snapshot.getStatistics();
|
|
29
|
+
}
|
|
30
|
+
async getStaticData(filePath) {
|
|
31
|
+
const snapshot = await this.getSnapshot(filePath);
|
|
32
|
+
return snapshot.staticData;
|
|
33
|
+
}
|
|
34
|
+
async #loadSnapshot(absolutePath) {
|
|
35
|
+
const workerProxy = new DevTools.HeapSnapshotModel.HeapSnapshotProxy.HeapSnapshotWorkerProxy(() => {
|
|
36
|
+
/* noop */
|
|
37
|
+
}, import.meta.resolve('./third_party/devtools-heap-snapshot-worker.js'));
|
|
38
|
+
const { promise: snapshotPromise, resolve: resolveSnapshot } = Promise.withResolvers();
|
|
39
|
+
const loaderProxy = workerProxy.createLoader(1, snapshotProxy => {
|
|
40
|
+
resolveSnapshot(snapshotProxy);
|
|
41
|
+
});
|
|
42
|
+
const fileStream = fsSync.createReadStream(absolutePath, {
|
|
43
|
+
encoding: 'utf-8',
|
|
44
|
+
highWaterMark: 1024 * 1024,
|
|
45
|
+
});
|
|
46
|
+
for await (const chunk of fileStream) {
|
|
47
|
+
await loaderProxy.write(chunk);
|
|
48
|
+
}
|
|
49
|
+
await loaderProxy.close();
|
|
50
|
+
const snapshot = await snapshotPromise;
|
|
51
|
+
return { snapshot, worker: workerProxy };
|
|
52
|
+
}
|
|
53
|
+
dispose(filePath) {
|
|
54
|
+
const absolutePath = path.resolve(filePath);
|
|
55
|
+
const cached = this.#snapshots.get(absolutePath);
|
|
56
|
+
if (cached) {
|
|
57
|
+
cached.worker.dispose();
|
|
58
|
+
this.#snapshots.delete(absolutePath);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
package/build/src/McpContext.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import fs from 'node:fs/promises';
|
|
7
7
|
import path from 'node:path';
|
|
8
8
|
import { UniverseManager } from './DevtoolsUtils.js';
|
|
9
|
+
import { HeapSnapshotManager } from './HeapSnapshotManager.js';
|
|
9
10
|
import { McpPage } from './McpPage.js';
|
|
10
11
|
import { NetworkCollector, ConsoleCollector, } from './PageCollector.js';
|
|
11
12
|
import { Locator } from './third_party/index.js';
|
|
@@ -42,6 +43,7 @@ export class McpContext {
|
|
|
42
43
|
#traceResults = [];
|
|
43
44
|
#locatorClass;
|
|
44
45
|
#options;
|
|
46
|
+
#heapSnapshotManager = new HeapSnapshotManager();
|
|
45
47
|
constructor(browser, logger, options, locatorClass) {
|
|
46
48
|
this.browser = browser;
|
|
47
49
|
this.logger = logger;
|
|
@@ -673,4 +675,13 @@ export class McpContext {
|
|
|
673
675
|
getExtension(id) {
|
|
674
676
|
return this.#extensionRegistry.getById(id);
|
|
675
677
|
}
|
|
678
|
+
async getHeapSnapshotAggregates(filePath) {
|
|
679
|
+
return await this.#heapSnapshotManager.getAggregates(filePath);
|
|
680
|
+
}
|
|
681
|
+
async getHeapSnapshotStats(filePath) {
|
|
682
|
+
return await this.#heapSnapshotManager.getStats(filePath);
|
|
683
|
+
}
|
|
684
|
+
async getHeapSnapshotStaticData(filePath) {
|
|
685
|
+
return await this.#heapSnapshotManager.getStaticData(filePath);
|
|
686
|
+
}
|
|
676
687
|
}
|
package/build/src/McpResponse.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import { ConsoleFormatter } from './formatters/ConsoleFormatter.js';
|
|
7
|
+
import { HeapSnapshotFormatter } from './formatters/HeapSnapshotFormatter.js';
|
|
7
8
|
import { IssueFormatter } from './formatters/IssueFormatter.js';
|
|
8
9
|
import { NetworkFormatter } from './formatters/NetworkFormatter.js';
|
|
9
10
|
import { SnapshotFormatter } from './formatters/SnapshotFormatter.js';
|
|
@@ -118,6 +119,7 @@ export class McpResponse {
|
|
|
118
119
|
#attachedLighthouseResult;
|
|
119
120
|
#textResponseLines = [];
|
|
120
121
|
#images = [];
|
|
122
|
+
#heapSnapshotOptions;
|
|
121
123
|
#networkRequestsOptions;
|
|
122
124
|
#consoleDataOptions;
|
|
123
125
|
#listExtensions;
|
|
@@ -254,6 +256,22 @@ export class McpResponse {
|
|
|
254
256
|
appendResponseLine(value) {
|
|
255
257
|
this.#textResponseLines.push(value);
|
|
256
258
|
}
|
|
259
|
+
setHeapSnapshotAggregates(aggregates, options) {
|
|
260
|
+
this.#heapSnapshotOptions = {
|
|
261
|
+
...this.#heapSnapshotOptions,
|
|
262
|
+
include: true,
|
|
263
|
+
aggregates,
|
|
264
|
+
pagination: options,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
setHeapSnapshotStats(stats, staticData) {
|
|
268
|
+
this.#heapSnapshotOptions = {
|
|
269
|
+
...this.#heapSnapshotOptions,
|
|
270
|
+
include: true,
|
|
271
|
+
stats,
|
|
272
|
+
staticData,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
257
275
|
attachImage(value) {
|
|
258
276
|
this.#images.push(value);
|
|
259
277
|
}
|
|
@@ -598,6 +616,32 @@ Call ${handleDialog.name} to handle it before continuing.`);
|
|
|
598
616
|
structuredContent.snapshot = data.snapshot.toJSON();
|
|
599
617
|
}
|
|
600
618
|
}
|
|
619
|
+
if (this.#heapSnapshotOptions?.include) {
|
|
620
|
+
response.push('## Heap Snapshot Data');
|
|
621
|
+
const stats = this.#heapSnapshotOptions.stats;
|
|
622
|
+
const staticData = this.#heapSnapshotOptions.staticData;
|
|
623
|
+
if (stats) {
|
|
624
|
+
response.push(`Statistics: ${JSON.stringify(stats, null, 2)}`);
|
|
625
|
+
structuredContent.heapSnapshot = structuredContent.heapSnapshot || {};
|
|
626
|
+
structuredContent.heapSnapshot.stats = stats;
|
|
627
|
+
}
|
|
628
|
+
if (staticData) {
|
|
629
|
+
response.push(`Static Data: ${JSON.stringify(staticData, null, 2)}`);
|
|
630
|
+
structuredContent.heapSnapshot = structuredContent.heapSnapshot || {};
|
|
631
|
+
structuredContent.heapSnapshot.staticData = staticData;
|
|
632
|
+
}
|
|
633
|
+
const aggregates = this.#heapSnapshotOptions.aggregates;
|
|
634
|
+
if (aggregates) {
|
|
635
|
+
const sortedEntries = HeapSnapshotFormatter.sort(aggregates);
|
|
636
|
+
const paginationData = this.#dataWithPagination(sortedEntries, this.#heapSnapshotOptions.pagination);
|
|
637
|
+
structuredContent.pagination = paginationData.pagination;
|
|
638
|
+
response.push(...paginationData.info);
|
|
639
|
+
const paginatedRecord = Object.fromEntries(paginationData.items);
|
|
640
|
+
const formatter = new HeapSnapshotFormatter(paginatedRecord);
|
|
641
|
+
response.push(formatter.toString());
|
|
642
|
+
structuredContent.heapSnapshotData = formatter.toJSON();
|
|
643
|
+
}
|
|
644
|
+
}
|
|
601
645
|
if (data.detailedNetworkRequest) {
|
|
602
646
|
response.push(data.detailedNetworkRequest.toStringDetailed());
|
|
603
647
|
structuredContent.networkRequest =
|
|
@@ -250,6 +250,11 @@ class PageEventSubscriber {
|
|
|
250
250
|
};
|
|
251
251
|
#onIssueAdded = (inspectorIssue) => {
|
|
252
252
|
try {
|
|
253
|
+
// DevTools currently defines this protocol issue code but has no
|
|
254
|
+
// IssuesManager handler for it, so calling into the mapper only warns.
|
|
255
|
+
if (String(inspectorIssue.code) === 'PerformanceIssue') {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
253
258
|
const issue = DevTools.createIssuesFromProtocolIssue(null,
|
|
254
259
|
// @ts-expect-error Protocol types diverge.
|
|
255
260
|
inspectorIssue)[0];
|
|
@@ -149,6 +149,11 @@ export const cliOptions = {
|
|
|
149
149
|
describe: 'Whether to enable coordinate-based tools such as click_at(x,y). Usually requires a computer-use model able to produce accurate coordinates by looking at screenshots.',
|
|
150
150
|
hidden: false,
|
|
151
151
|
},
|
|
152
|
+
experimentalMemory: {
|
|
153
|
+
type: 'boolean',
|
|
154
|
+
describe: 'Whether to enable experimental memory tools.',
|
|
155
|
+
hidden: true,
|
|
156
|
+
},
|
|
152
157
|
experimentalStructuredContent: {
|
|
153
158
|
type: 'boolean',
|
|
154
159
|
describe: 'Whether to output structured formatted content.',
|
|
@@ -175,13 +175,13 @@ export const commands = {
|
|
|
175
175
|
requestFilePath: {
|
|
176
176
|
name: 'requestFilePath',
|
|
177
177
|
type: 'string',
|
|
178
|
-
description: 'The absolute or relative path to save the request body to. If omitted, the body is returned inline.',
|
|
178
|
+
description: 'The absolute or relative path to a .network-request file to save the request body to. If omitted, the body is returned inline.',
|
|
179
179
|
required: false,
|
|
180
180
|
},
|
|
181
181
|
responseFilePath: {
|
|
182
182
|
name: 'responseFilePath',
|
|
183
183
|
type: 'string',
|
|
184
|
-
description: 'The absolute or relative path to save the response body to. If omitted, the body is returned inline.',
|
|
184
|
+
description: 'The absolute or relative path to a .network-response file to save the response body to. If omitted, the body is returned inline.',
|
|
185
185
|
required: false,
|
|
186
186
|
},
|
|
187
187
|
},
|
|
@@ -314,7 +314,7 @@ export const commands = {
|
|
|
314
314
|
},
|
|
315
315
|
},
|
|
316
316
|
list_pages: {
|
|
317
|
-
description: 'Get a list of pages
|
|
317
|
+
description: 'Get a list of pages open in the browser.',
|
|
318
318
|
category: 'Navigation automation',
|
|
319
319
|
args: {},
|
|
320
320
|
},
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
export class HeapSnapshotFormatter {
|
|
7
|
+
#aggregates;
|
|
8
|
+
constructor(aggregates) {
|
|
9
|
+
this.#aggregates = aggregates;
|
|
10
|
+
}
|
|
11
|
+
#getSortedAggregates() {
|
|
12
|
+
return Object.values(this.#aggregates).sort((a, b) => b.self - a.self);
|
|
13
|
+
}
|
|
14
|
+
toString() {
|
|
15
|
+
const sorted = this.#getSortedAggregates();
|
|
16
|
+
const lines = [];
|
|
17
|
+
lines.push('className,count,selfSize,maxRetainedSize');
|
|
18
|
+
for (const info of sorted) {
|
|
19
|
+
lines.push(`"${info.name}",${info.count},${info.self},${info.maxRet}`);
|
|
20
|
+
}
|
|
21
|
+
return lines.join('\n');
|
|
22
|
+
}
|
|
23
|
+
toJSON() {
|
|
24
|
+
const sorted = this.#getSortedAggregates();
|
|
25
|
+
return sorted.map(info => ({
|
|
26
|
+
className: info.name,
|
|
27
|
+
count: info.count,
|
|
28
|
+
selfSize: info.self,
|
|
29
|
+
retainedSize: info.maxRet,
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
static sort(aggregates) {
|
|
33
|
+
return Object.entries(aggregates).sort((a, b) => b[1].self - a[1].self);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -227,7 +227,7 @@ function converNetworkRequestDetailedToStringDetailed(data) {
|
|
|
227
227
|
response.push(`### Redirect chain`);
|
|
228
228
|
let indent = 0;
|
|
229
229
|
for (const request of redirectChain.reverse()) {
|
|
230
|
-
response.push(`${' '.repeat(indent)}${convertNetworkRequestConciseToString(request)}
|
|
230
|
+
response.push(`${' '.repeat(indent)}${convertNetworkRequestConciseToString(request)}`);
|
|
231
231
|
indent++;
|
|
232
232
|
}
|
|
233
233
|
}
|
package/build/src/index.js
CHANGED
|
@@ -111,6 +111,10 @@ export async function createMcpServer(serverArgs, options) {
|
|
|
111
111
|
!serverArgs.experimentalVision) {
|
|
112
112
|
return;
|
|
113
113
|
}
|
|
114
|
+
if (tool.annotations.conditions?.includes('experimentalMemory') &&
|
|
115
|
+
!serverArgs.experimentalMemory) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
114
118
|
if (tool.annotations.conditions?.includes('experimentalInteropTools') &&
|
|
115
119
|
!serverArgs.experimentalInteropTools) {
|
|
116
120
|
return;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
// eslint-disable-next-line no-restricted-imports
|
|
7
|
+
import '../../node_modules/chrome-devtools-frontend/front_end/entrypoints/heap_snapshot_worker/heap_snapshot_worker-entrypoint.js';
|
|
@@ -8,6 +8,7 @@ import 'core-js/modules/es.set.union.v2.js';
|
|
|
8
8
|
import 'core-js/proposals/iterator-helpers.js';
|
|
9
9
|
export { default as yargs } from 'yargs';
|
|
10
10
|
export { hideBin } from 'yargs/helpers';
|
|
11
|
+
export { default as semver } from 'semver';
|
|
11
12
|
export { default as debug } from 'debug';
|
|
12
13
|
export { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
13
14
|
export { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
@@ -13,6 +13,7 @@ export var ToolCategory;
|
|
|
13
13
|
ToolCategory["DEBUGGING"] = "debugging";
|
|
14
14
|
ToolCategory["EXTENSIONS"] = "extensions";
|
|
15
15
|
ToolCategory["IN_PAGE"] = "in-page";
|
|
16
|
+
ToolCategory["MEMORY"] = "memory";
|
|
16
17
|
})(ToolCategory || (ToolCategory = {}));
|
|
17
18
|
export const labels = {
|
|
18
19
|
[ToolCategory.INPUT]: 'Input automation',
|
|
@@ -23,4 +24,5 @@ export const labels = {
|
|
|
23
24
|
[ToolCategory.DEBUGGING]: 'Debugging',
|
|
24
25
|
[ToolCategory.EXTENSIONS]: 'Extensions',
|
|
25
26
|
[ToolCategory.IN_PAGE]: 'In-page tools',
|
|
27
|
+
[ToolCategory.MEMORY]: 'Memory',
|
|
26
28
|
};
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { zod } from '../third_party/index.js';
|
|
7
7
|
import { ensureExtension } from '../utils/files.js';
|
|
8
8
|
import { ToolCategory } from './categories.js';
|
|
9
|
-
import { definePageTool } from './ToolDefinition.js';
|
|
9
|
+
import { definePageTool, defineTool } from './ToolDefinition.js';
|
|
10
10
|
export const takeMemorySnapshot = definePageTool({
|
|
11
11
|
name: 'take_memory_snapshot',
|
|
12
12
|
description: `Capture a heap snapshot of the currently selected page. Use to analyze the memory distribution of JavaScript objects and debug memory leaks.`,
|
|
@@ -27,3 +27,20 @@ export const takeMemorySnapshot = definePageTool({
|
|
|
27
27
|
response.appendResponseLine(`Heap snapshot saved to ${request.params.filePath}`);
|
|
28
28
|
},
|
|
29
29
|
});
|
|
30
|
+
export const exploreMemorySnapshot = defineTool({
|
|
31
|
+
name: 'load_memory_snapshot',
|
|
32
|
+
description: 'Loads a memory heapsnapshot and returns snapshot summary stats. ',
|
|
33
|
+
annotations: {
|
|
34
|
+
category: ToolCategory.MEMORY,
|
|
35
|
+
readOnlyHint: true,
|
|
36
|
+
conditions: ['experimentalMemory'],
|
|
37
|
+
},
|
|
38
|
+
schema: {
|
|
39
|
+
filePath: zod.string().describe('A path to a .heapsnapshot file to read.'),
|
|
40
|
+
},
|
|
41
|
+
handler: async (request, response, context) => {
|
|
42
|
+
const stats = await context.getHeapSnapshotStats(request.params.filePath);
|
|
43
|
+
const staticData = await context.getHeapSnapshotStaticData(request.params.filePath);
|
|
44
|
+
response.setHeapSnapshotStats(stats, staticData);
|
|
45
|
+
},
|
|
46
|
+
});
|
|
@@ -87,11 +87,11 @@ export const getNetworkRequest = definePageTool({
|
|
|
87
87
|
requestFilePath: zod
|
|
88
88
|
.string()
|
|
89
89
|
.optional()
|
|
90
|
-
.describe('The absolute or relative path to save the request body to. If omitted, the body is returned inline.'),
|
|
90
|
+
.describe('The absolute or relative path to a .network-request file to save the request body to. If omitted, the body is returned inline.'),
|
|
91
91
|
responseFilePath: zod
|
|
92
92
|
.string()
|
|
93
93
|
.optional()
|
|
94
|
-
.describe('The absolute or relative path to save the response body to. If omitted, the body is returned inline.'),
|
|
94
|
+
.describe('The absolute or relative path to a .network-response file to save the response body to. If omitted, the body is returned inline.'),
|
|
95
95
|
},
|
|
96
96
|
handler: async (request, response, context) => {
|
|
97
97
|
if (request.params.reqid) {
|
package/build/src/tools/pages.js
CHANGED
|
@@ -10,7 +10,7 @@ import { CLOSE_PAGE_ERROR, definePageTool, defineTool, timeoutSchema, } from './
|
|
|
10
10
|
export const listPages = defineTool(args => {
|
|
11
11
|
return {
|
|
12
12
|
name: 'list_pages',
|
|
13
|
-
description: `Get a list of pages
|
|
13
|
+
description: `Get a list of pages${args?.categoryExtensions ? ' including extension service workers' : ''} open in the browser.`,
|
|
14
14
|
annotations: {
|
|
15
15
|
category: ToolCategory.NAVIGATION,
|
|
16
16
|
readOnlyHint: true,
|
|
@@ -8,6 +8,7 @@ import fs from 'node:fs/promises';
|
|
|
8
8
|
import os from 'node:os';
|
|
9
9
|
import path from 'node:path';
|
|
10
10
|
import process from 'node:process';
|
|
11
|
+
import { semver } from '../third_party/index.js';
|
|
11
12
|
import { VERSION } from '../version.js';
|
|
12
13
|
/**
|
|
13
14
|
* Notifies the user if an update is available.
|
|
@@ -34,7 +35,7 @@ export async function checkForUpdates(message) {
|
|
|
34
35
|
catch {
|
|
35
36
|
// Ignore errors reading cache.
|
|
36
37
|
}
|
|
37
|
-
if (cachedVersion && cachedVersion
|
|
38
|
+
if (cachedVersion && semver.lt(VERSION, cachedVersion)) {
|
|
38
39
|
console.warn(`\nUpdate available: ${VERSION} -> ${cachedVersion}\n${message}\n`);
|
|
39
40
|
}
|
|
40
41
|
const now = Date.now();
|
package/build/src/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "MCP server for Brave DevTools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"@types/debug": "^4.1.12",
|
|
59
59
|
"@types/filesystem": "^0.0.36",
|
|
60
60
|
"@types/node": "^25.0.0",
|
|
61
|
+
"@types/semver": "^7.7.1",
|
|
61
62
|
"@types/sinon": "^21.0.0",
|
|
62
63
|
"@types/yargs": "^17.0.33",
|
|
63
64
|
"@typescript-eslint/eslint-plugin": "^8.43.0",
|
|
@@ -75,6 +76,7 @@
|
|
|
75
76
|
"rollup": "4.60.1",
|
|
76
77
|
"rollup-plugin-cleanup": "^3.2.1",
|
|
77
78
|
"rollup-plugin-license": "^3.6.0",
|
|
79
|
+
"semver": "^7.7.4",
|
|
78
80
|
"sinon": "^21.0.0",
|
|
79
81
|
"tiktoken": "^1.0.22",
|
|
80
82
|
"typescript": "^6.0.2",
|