e2e-pilot 0.0.69 → 0.0.71
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/dist/cli.js +56 -1
- package/dist/cli.js.map +1 -1
- package/extension-dist/icons/icon-black-128.png +0 -0
- package/extension-dist/icons/icon-black-16.png +0 -0
- package/extension-dist/icons/icon-black-32.png +0 -0
- package/extension-dist/icons/icon-black-48.png +0 -0
- package/extension-dist/icons/icon-black.svg +4 -0
- package/extension-dist/icons/icon-gray-128.png +0 -0
- package/extension-dist/icons/icon-gray-16.png +0 -0
- package/extension-dist/icons/icon-gray-32.png +0 -0
- package/extension-dist/icons/icon-gray-48.png +0 -0
- package/extension-dist/icons/icon-gray.svg +4 -0
- package/extension-dist/icons/icon-green-128.png +0 -0
- package/extension-dist/icons/icon-green-16.png +0 -0
- package/extension-dist/icons/icon-green-32.png +0 -0
- package/extension-dist/icons/icon-green-48.png +0 -0
- package/extension-dist/icons/icon-green.svg +4 -0
- package/extension-dist/lib/background.mjs +1126 -0
- package/extension-dist/manifest.json +35 -0
- package/extension-dist/popup/popup.css +2 -0
- package/extension-dist/popup/popup.js +16829 -0
- package/extension-dist/popup.html +13 -0
- package/extension-dist/welcome.html +335 -0
- package/package.json +2 -2
- package/src/cli.ts +62 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>E2E Pilot</title>
|
|
7
|
+
<script type="module" crossorigin src="./popup/popup.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="./popup/popup.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Welcome to E2E Pilot MCP</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--color-bg: #ffffff;
|
|
10
|
+
--color-text: #262626;
|
|
11
|
+
--color-heading: #171717;
|
|
12
|
+
--color-border: #d4d4d4;
|
|
13
|
+
--color-code-bg: #f5f5f5;
|
|
14
|
+
--color-link: #0969da;
|
|
15
|
+
--color-link-hover: #0550ae;
|
|
16
|
+
--color-success: #16a34a;
|
|
17
|
+
--color-muted: #737373;
|
|
18
|
+
--max-width: 640px;
|
|
19
|
+
--spacing: 1.5rem;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@media (prefers-color-scheme: dark) {
|
|
23
|
+
:root {
|
|
24
|
+
--color-bg: #0a0a0a;
|
|
25
|
+
--color-text: #e5e5e5;
|
|
26
|
+
--color-heading: #fafafa;
|
|
27
|
+
--color-border: #404040;
|
|
28
|
+
--color-code-bg: #171717;
|
|
29
|
+
--color-link: #4493f8;
|
|
30
|
+
--color-link-hover: #539bf5;
|
|
31
|
+
--color-success: #22c55e;
|
|
32
|
+
--color-muted: #a3a3a3;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
* {
|
|
37
|
+
margin: 0;
|
|
38
|
+
padding: 0;
|
|
39
|
+
box-sizing: border-box;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
body {
|
|
43
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans",
|
|
44
|
+
Helvetica, Arial, sans-serif;
|
|
45
|
+
font-size: 16px;
|
|
46
|
+
line-height: 1.6;
|
|
47
|
+
color: var(--color-text);
|
|
48
|
+
background-color: var(--color-bg);
|
|
49
|
+
padding: 2rem 1rem;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
main {
|
|
53
|
+
max-width: var(--max-width);
|
|
54
|
+
margin: 0 auto;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
h2 {
|
|
58
|
+
font-size: 1.75rem;
|
|
59
|
+
font-weight: 600;
|
|
60
|
+
color: var(--color-heading);
|
|
61
|
+
margin-top: 2rem;
|
|
62
|
+
margin-bottom: 1rem;
|
|
63
|
+
padding-bottom: 0.5rem;
|
|
64
|
+
border-bottom: 1px solid var(--color-border);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
h3 {
|
|
68
|
+
font-size: 1.25rem;
|
|
69
|
+
font-weight: 600;
|
|
70
|
+
color: var(--color-heading);
|
|
71
|
+
margin-top: 1.5rem;
|
|
72
|
+
margin-bottom: 0.75rem;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
p {
|
|
76
|
+
margin-bottom: 1rem;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
a {
|
|
80
|
+
color: var(--color-link);
|
|
81
|
+
text-decoration: none;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
a:hover {
|
|
85
|
+
color: var(--color-link-hover);
|
|
86
|
+
text-decoration: underline;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
code {
|
|
90
|
+
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
|
|
91
|
+
"Liberation Mono", monospace;
|
|
92
|
+
font-size: 0.875em;
|
|
93
|
+
background-color: var(--color-code-bg);
|
|
94
|
+
padding: 0.2em 0.4em;
|
|
95
|
+
border-radius: 6px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
pre {
|
|
99
|
+
background-color: var(--color-code-bg);
|
|
100
|
+
padding: 1rem;
|
|
101
|
+
border-radius: 6px;
|
|
102
|
+
overflow-x: auto;
|
|
103
|
+
margin-bottom: 1rem;
|
|
104
|
+
border: 1px solid var(--color-border);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
pre code {
|
|
108
|
+
background-color: transparent;
|
|
109
|
+
padding: 0;
|
|
110
|
+
font-size: 0.875rem;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
ol,
|
|
114
|
+
ul {
|
|
115
|
+
margin-bottom: 1rem;
|
|
116
|
+
padding-left: 2rem;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
li {
|
|
120
|
+
margin-bottom: 0.5rem;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
strong {
|
|
124
|
+
font-weight: 600;
|
|
125
|
+
color: var(--color-heading);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
.step-number {
|
|
131
|
+
color: var(--color-link);
|
|
132
|
+
font-weight: 700;
|
|
133
|
+
font-size: 1.125rem;
|
|
134
|
+
margin-right: 0.75rem;
|
|
135
|
+
flex-shrink: 0;
|
|
136
|
+
line-height: 1.6;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.step {
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: flex-start;
|
|
142
|
+
margin-bottom: 1.5rem;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.step-content {
|
|
146
|
+
flex: 1;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.install-button {
|
|
150
|
+
display: inline-flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
gap: 0.5rem;
|
|
153
|
+
padding: 0.5rem 1rem;
|
|
154
|
+
background-color: #262626;
|
|
155
|
+
color: #fff;
|
|
156
|
+
border-radius: 0.5rem;
|
|
157
|
+
text-decoration: none;
|
|
158
|
+
transition: background-color 0.15s;
|
|
159
|
+
font-size: 0.875rem;
|
|
160
|
+
font-weight: 500;
|
|
161
|
+
margin-top: 0.5rem;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.install-button:hover {
|
|
165
|
+
background-color: #404040;
|
|
166
|
+
color: #fff;
|
|
167
|
+
text-decoration: none;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.install-button svg {
|
|
171
|
+
width: 1.25rem;
|
|
172
|
+
height: 1.25rem;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
footer {
|
|
176
|
+
margin-top: 3rem;
|
|
177
|
+
padding-top: 2rem;
|
|
178
|
+
border-top: 1px solid var(--color-border);
|
|
179
|
+
text-align: center;
|
|
180
|
+
color: var(--color-muted);
|
|
181
|
+
font-size: 0.875rem;
|
|
182
|
+
}
|
|
183
|
+
</style>
|
|
184
|
+
</head>
|
|
185
|
+
<body>
|
|
186
|
+
<main>
|
|
187
|
+
<section>
|
|
188
|
+
<h2>Getting Started with E2E Pilot MCP</h2>
|
|
189
|
+
|
|
190
|
+
<p>
|
|
191
|
+
Control your browser via extension instead of spawning a full new
|
|
192
|
+
Chrome window. Uses less context window by running Playwright CDP
|
|
193
|
+
protocol directly. Collaborate with your agent and help get it
|
|
194
|
+
unstuck when needed.
|
|
195
|
+
</p>
|
|
196
|
+
|
|
197
|
+
<h3>Quick Start</h3>
|
|
198
|
+
|
|
199
|
+
<div class="step">
|
|
200
|
+
<span class="step-number">1</span>
|
|
201
|
+
<div class="step-content">
|
|
202
|
+
<strong>Pin this extension on Chrome toolbar</strong>
|
|
203
|
+
<p>
|
|
204
|
+
Click the puzzle icon in your Chrome toolbar and pin the
|
|
205
|
+
E2E Pilot MCP extension for easy access.
|
|
206
|
+
</p>
|
|
207
|
+
</div>
|
|
208
|
+
</div>
|
|
209
|
+
|
|
210
|
+
<div class="step">
|
|
211
|
+
<span class="step-number">2</span>
|
|
212
|
+
<div class="step-content">
|
|
213
|
+
<strong>Click the extension icon</strong>
|
|
214
|
+
<p>
|
|
215
|
+
Click the E2E Pilot MCP extension icon in your browser toolbar
|
|
216
|
+
to attach the debugger to the current tab. The icon will turn
|
|
217
|
+
green when successfully connected.
|
|
218
|
+
</p>
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
|
|
222
|
+
<div class="step">
|
|
223
|
+
<span class="step-number">3</span>
|
|
224
|
+
<div class="step-content">
|
|
225
|
+
<strong>Add the MCP to your agent</strong>
|
|
226
|
+
<p>
|
|
227
|
+
Add the following configuration to your MCP client settings (e.g.,
|
|
228
|
+
Claude Desktop's <code>claude_desktop_config.json</code>):
|
|
229
|
+
</p>
|
|
230
|
+
<pre><code>{
|
|
231
|
+
"mcpServers": {
|
|
232
|
+
"e2e-pilot": {
|
|
233
|
+
"command": "npx",
|
|
234
|
+
"args": [
|
|
235
|
+
"-y",
|
|
236
|
+
"e2e-pilot@latest"
|
|
237
|
+
]
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}</code></pre>
|
|
241
|
+
<p>
|
|
242
|
+
Or install directly in Cursor:
|
|
243
|
+
</p>
|
|
244
|
+
<a
|
|
245
|
+
href="https://cursor.com/en/install-mcp?name=playwriter&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyJwbGF5d3JpdGVyQGxhdGVzdCJdfQ%3D%3D"
|
|
246
|
+
target="_blank"
|
|
247
|
+
rel="noopener noreferrer"
|
|
248
|
+
class="install-button"
|
|
249
|
+
>
|
|
250
|
+
<svg viewBox="0 0 466.73 533.32" xmlns="http://www.w3.org/2000/svg">
|
|
251
|
+
<path d="m233.37 266.66 231.16 133.46c-1.42 2.46-3.48 4.56-6.03 6.03l-216.06 124.74c-5.61 3.24-12.53 3.24-18.14 0l-216.06-124.74c-2.55-1.47-4.61-3.57-6.03-6.03z" fill="#72716d"/>
|
|
252
|
+
<path d="m233.37 0v266.66l-231.16 133.46c-1.42-2.46-2.21-5.3-2.21-8.24v-250.44c0-5.89 3.14-11.32 8.24-14.27l216.05-124.74c2.81-1.62 5.94-2.43 9.07-2.43z" fill="#55544f"/>
|
|
253
|
+
<path d="m464.52 133.2c-1.42-2.46-3.48-4.56-6.03-6.03l-216.06-124.74c-2.8-1.62-5.93-2.43-9.06-2.43v266.66l231.16 133.46c1.42-2.46 2.21-5.3 2.21-8.24v-250.44c0-2.95-.78-5.77-2.21-8.24z" fill="#43413c"/>
|
|
254
|
+
<path d="m448.35 142.54c1.31 2.26 1.49 5.16 0 7.74l-209.83 363.42c-1.41 2.46-5.16 1.45-5.16-1.38v-239.48c0-1.91-.51-3.75-1.44-5.36l216.42-124.95h.01z" fill="#d6d5d2"/>
|
|
255
|
+
<path d="m448.35 142.54-216.42 124.95c-.92-1.6-2.26-2.96-3.92-3.92l-207.39-119.74c-2.46-1.41-1.45-5.16 1.38-5.16h419.65c2.98 0 5.4 1.61 6.7 3.87z" fill="#fff"/>
|
|
256
|
+
</svg>
|
|
257
|
+
Install in Cursor
|
|
258
|
+
</a>
|
|
259
|
+
<p style="margin-top: 1rem;">
|
|
260
|
+
This will enable your AI assistant to control the browser through
|
|
261
|
+
the extension.
|
|
262
|
+
</p>
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
</section>
|
|
266
|
+
|
|
267
|
+
<section>
|
|
268
|
+
<h2>How It Works</h2>
|
|
269
|
+
|
|
270
|
+
<ul>
|
|
271
|
+
<li>
|
|
272
|
+
<strong>No new Chrome instances:</strong> Works with your current
|
|
273
|
+
browser session
|
|
274
|
+
</li>
|
|
275
|
+
<li>
|
|
276
|
+
<strong>No CDP mode required:</strong> No need to restart Chrome
|
|
277
|
+
with special flags
|
|
278
|
+
</li>
|
|
279
|
+
<li>
|
|
280
|
+
<strong>Full CDP access:</strong> Complete Chrome DevTools Protocol
|
|
281
|
+
capabilities
|
|
282
|
+
</li>
|
|
283
|
+
<li>
|
|
284
|
+
<strong>Visual feedback:</strong> Extension icon changes color to
|
|
285
|
+
indicate connection status
|
|
286
|
+
</li>
|
|
287
|
+
</ul>
|
|
288
|
+
</section>
|
|
289
|
+
|
|
290
|
+
<section>
|
|
291
|
+
<h2>Icon States</h2>
|
|
292
|
+
|
|
293
|
+
<ul>
|
|
294
|
+
<li><strong>Gray:</strong> Not connected to any tab</li>
|
|
295
|
+
<li><strong>Green:</strong> Successfully connected and ready</li>
|
|
296
|
+
<li><strong>Orange badge (...):</strong> Connecting to relay server</li>
|
|
297
|
+
<li><strong>Red badge (!):</strong> Error occurred</li>
|
|
298
|
+
</ul>
|
|
299
|
+
</section>
|
|
300
|
+
|
|
301
|
+
<section>
|
|
302
|
+
<h2>Privacy & Security</h2>
|
|
303
|
+
|
|
304
|
+
<p>
|
|
305
|
+
E2E Pilot MCP runs locally in your browser and does not send any
|
|
306
|
+
data to external servers. All browser control happens through the
|
|
307
|
+
standard Chrome DevTools Protocol on your machine.
|
|
308
|
+
</p>
|
|
309
|
+
</section>
|
|
310
|
+
|
|
311
|
+
<section>
|
|
312
|
+
<h2>Need Help?</h2>
|
|
313
|
+
|
|
314
|
+
<p>
|
|
315
|
+
For issues, feature requests, or contributions, visit the
|
|
316
|
+
<a
|
|
317
|
+
href="https://github.com/remorses/playwriter"
|
|
318
|
+
target="_blank"
|
|
319
|
+
rel="noopener noreferrer"
|
|
320
|
+
>
|
|
321
|
+
GitHub repository
|
|
322
|
+
</a>
|
|
323
|
+
.
|
|
324
|
+
</p>
|
|
325
|
+
</section>
|
|
326
|
+
|
|
327
|
+
<footer>
|
|
328
|
+
<p>
|
|
329
|
+
E2E Pilot MCP © Microsoft Corporation · Licensed under
|
|
330
|
+
Apache-2.0
|
|
331
|
+
</p>
|
|
332
|
+
</footer>
|
|
333
|
+
</main>
|
|
334
|
+
</body>
|
|
335
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "e2e-pilot",
|
|
3
3
|
"description": "",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.71",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"@types/ws": "^8.18.1",
|
|
38
38
|
"@vitest/ui": "^4.0.8",
|
|
39
39
|
"bippy": "^0.5.27",
|
|
40
|
+
"bun": "^1.3.6",
|
|
40
41
|
"image-size": "^2.0.2",
|
|
41
42
|
"e2e-pilot-extension": "workspace:*",
|
|
42
43
|
"vite-node": "^5.0.0",
|
|
@@ -49,7 +50,6 @@
|
|
|
49
50
|
"@hono/node-server": "^1.19.6",
|
|
50
51
|
"@hono/node-ws": "^1.2.0",
|
|
51
52
|
"@modelcontextprotocol/sdk": "^1.21.1",
|
|
52
|
-
"bun": "^1.3.6",
|
|
53
53
|
"cac": "^6.7.14",
|
|
54
54
|
"chalk": "^5.6.2",
|
|
55
55
|
"colord": "^2.9.3",
|
package/src/cli.ts
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
import { cac } from 'cac'
|
|
4
4
|
import fs from 'node:fs'
|
|
5
5
|
import path from 'node:path'
|
|
6
|
-
import { spawn } from 'node:child_process'
|
|
6
|
+
import { exec, spawn } from 'node:child_process'
|
|
7
|
+
import { promisify } from 'node:util'
|
|
8
|
+
import chalk from 'chalk'
|
|
7
9
|
import { fileURLToPath } from 'node:url'
|
|
8
10
|
import { chromium, Page } from 'playwright-core'
|
|
9
11
|
import { startE2EPilotCDPRelayServer } from './cdp-relay.js'
|
|
@@ -244,6 +246,65 @@ async function readStdin(): Promise<string> {
|
|
|
244
246
|
})
|
|
245
247
|
}
|
|
246
248
|
|
|
249
|
+
function copyDirRecursive(src: string, dest: string): void {
|
|
250
|
+
fs.mkdirSync(dest, { recursive: true })
|
|
251
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
252
|
+
const srcPath = path.join(src, entry.name)
|
|
253
|
+
const destPath = path.join(dest, entry.name)
|
|
254
|
+
entry.isDirectory()
|
|
255
|
+
? copyDirRecursive(srcPath, destPath)
|
|
256
|
+
: fs.copyFileSync(srcPath, destPath)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
cli
|
|
261
|
+
.command('chrome', 'Set up the Chrome extension for E2E Pilot')
|
|
262
|
+
.action(async () => {
|
|
263
|
+
const execAsync = promisify(exec)
|
|
264
|
+
const extensionSrc = path.join(__dirname, '..', 'extension-dist')
|
|
265
|
+
const targetDir = path.join(process.cwd(), '.e2e-pilot', 'extension')
|
|
266
|
+
|
|
267
|
+
// Verify source exists
|
|
268
|
+
if (!fs.existsSync(extensionSrc)) {
|
|
269
|
+
console.error(chalk.red('Error: Extension files not found.'))
|
|
270
|
+
process.exit(1)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Copy extension files
|
|
274
|
+
if (fs.existsSync(targetDir)) {
|
|
275
|
+
fs.rmSync(targetDir, { recursive: true })
|
|
276
|
+
}
|
|
277
|
+
copyDirRecursive(extensionSrc, targetDir)
|
|
278
|
+
|
|
279
|
+
// Show instructions first
|
|
280
|
+
console.log()
|
|
281
|
+
console.log(chalk.green.bold('Extension ready!'))
|
|
282
|
+
console.log()
|
|
283
|
+
console.log('Extension files copied to:')
|
|
284
|
+
console.log(chalk.cyan(` ${targetDir}`))
|
|
285
|
+
console.log()
|
|
286
|
+
console.log(chalk.bold('To load in Chrome:'))
|
|
287
|
+
console.log(' 1. Go to', chalk.cyan('chrome://extensions'))
|
|
288
|
+
console.log(' 2. Enable', chalk.yellow('Developer mode'), '(top-right toggle)')
|
|
289
|
+
console.log(' 3. Drag extension folder to chrome')
|
|
290
|
+
console.log()
|
|
291
|
+
|
|
292
|
+
// Wait for Enter key
|
|
293
|
+
process.stdout.write('Press Enter to open Chrome and extension folder...')
|
|
294
|
+
await new Promise<void>((resolve) => {
|
|
295
|
+
process.stdin.setRawMode?.(false)
|
|
296
|
+
process.stdin.resume()
|
|
297
|
+
process.stdin.once('data', () => resolve())
|
|
298
|
+
})
|
|
299
|
+
console.log()
|
|
300
|
+
|
|
301
|
+
// Open folder and Chrome extensions page (macOS)
|
|
302
|
+
try {
|
|
303
|
+
await execAsync(`open "${targetDir}"`)
|
|
304
|
+
await execAsync('open -a "Google Chrome" "chrome://extensions"')
|
|
305
|
+
} catch { /* continue if opening fails */ }
|
|
306
|
+
})
|
|
307
|
+
|
|
247
308
|
cli.help()
|
|
248
309
|
cli.version(VERSION)
|
|
249
310
|
|