vite-plugin-opencode-assistant 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.
- package/README.md +282 -0
- package/dist/client.d.ts +0 -0
- package/dist/client.js +1549 -0
- package/dist/constants.d.ts +76 -0
- package/dist/constants.js +77 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +448 -0
- package/dist/injector.d.ts +20 -0
- package/dist/injector.js +24 -0
- package/dist/plugins/page-context.d.ts +20 -0
- package/dist/plugins/page-context.js +121 -0
- package/dist/types.d.ts +130 -0
- package/dist/types.js +2 -0
- package/dist/utils.d.ts +42 -0
- package/dist/utils.js +156 -0
- package/dist/web.d.ts +18 -0
- package/dist/web.js +95 -0
- package/package.json +54 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import http from 'http';
|
|
4
|
+
import { startOpenCodeWeb } from './web';
|
|
5
|
+
import { injectWidget } from './injector';
|
|
6
|
+
import { checkOpenCodeInstalled, findAvailablePort, killProcessOnPort, checkOpenCodeProcess } from './utils';
|
|
7
|
+
import { DEFAULT_CONFIG, DEFAULT_RETRIES, RETRY_DELAY, PROCESS_KILL_DELAY, LOG_PREFIX, WIDGET_SCRIPT_PATH, CONTEXT_API_PATH, START_API_PATH, SESSIONS_API_PATH, } from './constants';
|
|
8
|
+
/**
|
|
9
|
+
* OpenCode Vite 插件
|
|
10
|
+
* @param options - 插件配置选项
|
|
11
|
+
* @returns Vite 插件实例
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* // vite.config.ts
|
|
15
|
+
* import opencode from 'vite-plugin-opencode'
|
|
16
|
+
*
|
|
17
|
+
* export default {
|
|
18
|
+
* plugins: [
|
|
19
|
+
* opencode({
|
|
20
|
+
* webPort: 4097,
|
|
21
|
+
* position: 'bottom-right',
|
|
22
|
+
* theme: 'auto'
|
|
23
|
+
* })
|
|
24
|
+
* ]
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export default function opencodePlugin(options = {}) {
|
|
29
|
+
let webProcess = null;
|
|
30
|
+
let sessionUrl = null;
|
|
31
|
+
let actualWebPort = DEFAULT_CONFIG.webPort;
|
|
32
|
+
let isStarted = false;
|
|
33
|
+
let startPromise = null;
|
|
34
|
+
let pageContext = { url: '', title: '' };
|
|
35
|
+
const config = { ...DEFAULT_CONFIG, ...options };
|
|
36
|
+
/**
|
|
37
|
+
* 输出日志(仅在 verbose 模式下)
|
|
38
|
+
*/
|
|
39
|
+
function log(message, ...args) {
|
|
40
|
+
if (config.verbose) {
|
|
41
|
+
console.log(`${LOG_PREFIX} ${message}`, ...args);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 输出错误日志
|
|
46
|
+
*/
|
|
47
|
+
function logError(message, ...args) {
|
|
48
|
+
console.error(`${LOG_PREFIX} ${message}`, ...args);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Base64 编码字符串
|
|
52
|
+
*/
|
|
53
|
+
function base64Encode(str) {
|
|
54
|
+
return Buffer.from(str).toString('base64');
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 延迟执行
|
|
58
|
+
*/
|
|
59
|
+
function sleep(ms) {
|
|
60
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 创建 HTTP 请求 Promise
|
|
64
|
+
*/
|
|
65
|
+
function createHttpRequest(options, body) {
|
|
66
|
+
return new Promise((resolve, reject) => {
|
|
67
|
+
const req = http.request(options, (res) => {
|
|
68
|
+
let data = '';
|
|
69
|
+
res.on('data', chunk => data += chunk);
|
|
70
|
+
res.on('end', () => {
|
|
71
|
+
try {
|
|
72
|
+
resolve(JSON.parse(data));
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
reject(new Error(`JSON parse error: ${data.substring(0, 100)}`));
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
req.on('error', reject);
|
|
80
|
+
if (body)
|
|
81
|
+
req.write(body);
|
|
82
|
+
req.end();
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 获取会话列表
|
|
87
|
+
*/
|
|
88
|
+
async function getSessions(retries = DEFAULT_RETRIES) {
|
|
89
|
+
let lastError = null;
|
|
90
|
+
for (let i = 0; i < retries; i++) {
|
|
91
|
+
try {
|
|
92
|
+
return await createHttpRequest({
|
|
93
|
+
hostname: config.hostname,
|
|
94
|
+
port: actualWebPort,
|
|
95
|
+
path: '/session',
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
lastError = e instanceof Error ? e : new Error(String(e));
|
|
100
|
+
if (i < retries - 1)
|
|
101
|
+
await sleep(RETRY_DELAY);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
throw lastError;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 创建新会话
|
|
108
|
+
*/
|
|
109
|
+
async function createSession(retries = DEFAULT_RETRIES) {
|
|
110
|
+
let lastError = null;
|
|
111
|
+
for (let i = 0; i < retries; i++) {
|
|
112
|
+
try {
|
|
113
|
+
return await createHttpRequest({
|
|
114
|
+
hostname: config.hostname,
|
|
115
|
+
port: actualWebPort,
|
|
116
|
+
path: '/session',
|
|
117
|
+
method: 'POST',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
lastError = e instanceof Error ? e : new Error(String(e));
|
|
122
|
+
if (i < retries - 1)
|
|
123
|
+
await sleep(RETRY_DELAY);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
throw lastError;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 删除会话
|
|
130
|
+
*/
|
|
131
|
+
async function deleteSession(sessionId, retries = DEFAULT_RETRIES) {
|
|
132
|
+
let lastError = null;
|
|
133
|
+
for (let i = 0; i < retries; i++) {
|
|
134
|
+
try {
|
|
135
|
+
await createHttpRequest({
|
|
136
|
+
hostname: config.hostname,
|
|
137
|
+
port: actualWebPort,
|
|
138
|
+
path: `/session/${sessionId}`,
|
|
139
|
+
method: 'DELETE',
|
|
140
|
+
});
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
lastError = e instanceof Error ? e : new Error(String(e));
|
|
145
|
+
if (i < retries - 1)
|
|
146
|
+
await sleep(RETRY_DELAY);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
throw lastError;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* 获取或创建会话
|
|
153
|
+
*/
|
|
154
|
+
async function getOrCreateSession() {
|
|
155
|
+
const projectDir = process.cwd();
|
|
156
|
+
log('Getting sessions...');
|
|
157
|
+
const sessions = await getSessions();
|
|
158
|
+
log(`Found ${sessions.length} sessions`);
|
|
159
|
+
const matchingSession = sessions.find(s => s.directory === projectDir);
|
|
160
|
+
if (matchingSession) {
|
|
161
|
+
return `http://${config.hostname}:${actualWebPort}/${base64Encode(projectDir)}/session/${matchingSession.id}`;
|
|
162
|
+
}
|
|
163
|
+
log('Creating new session...');
|
|
164
|
+
const newSession = await createSession();
|
|
165
|
+
return `http://${config.hostname}:${actualWebPort}/${base64Encode(projectDir)}/session/${newSession.id}`;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* 设置 OpenCode 插件
|
|
169
|
+
*/
|
|
170
|
+
function setupOpenCodePlugin() {
|
|
171
|
+
const projectDir = process.cwd();
|
|
172
|
+
const cacheDir = path.join(projectDir, 'node_modules', '.cache', 'opencode');
|
|
173
|
+
const pluginsDir = path.join(cacheDir, 'plugins');
|
|
174
|
+
if (!fs.existsSync(pluginsDir)) {
|
|
175
|
+
fs.mkdirSync(pluginsDir, { recursive: true });
|
|
176
|
+
}
|
|
177
|
+
const pluginSourcePath = path.join(__dirname, 'plugins', 'page-context.js');
|
|
178
|
+
const pluginTargetPath = path.join(pluginsDir, 'page-context.js');
|
|
179
|
+
if (fs.existsSync(pluginSourcePath)) {
|
|
180
|
+
fs.copyFileSync(pluginSourcePath, pluginTargetPath);
|
|
181
|
+
log(`Plugin installed to ${pluginTargetPath}`);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
console.warn(`${LOG_PREFIX} Plugin source not found: ${pluginSourcePath}`);
|
|
185
|
+
}
|
|
186
|
+
return cacheDir;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* 启动服务
|
|
190
|
+
*/
|
|
191
|
+
async function startServices(corsOrigins, contextApiUrl) {
|
|
192
|
+
if (isStarted)
|
|
193
|
+
return;
|
|
194
|
+
if (startPromise)
|
|
195
|
+
return startPromise;
|
|
196
|
+
startPromise = (async () => {
|
|
197
|
+
log('Starting OpenCode services...');
|
|
198
|
+
if (!await checkOpenCodeInstalled()) {
|
|
199
|
+
logError(`OpenCode is not installed!
|
|
200
|
+
|
|
201
|
+
Please install OpenCode first:
|
|
202
|
+
|
|
203
|
+
# Using Homebrew (macOS)
|
|
204
|
+
brew install opencode-ai/tap/opencode
|
|
205
|
+
|
|
206
|
+
# Or using the install script
|
|
207
|
+
curl -fsSL https://opencode.ai/install | bash
|
|
208
|
+
`);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
actualWebPort = await findAvailablePort(config.webPort, config.hostname);
|
|
212
|
+
if (actualWebPort !== config.webPort) {
|
|
213
|
+
log(`Port ${config.webPort} is in use, using ${actualWebPort} instead`);
|
|
214
|
+
}
|
|
215
|
+
const existingProcess = await checkOpenCodeProcess(actualWebPort);
|
|
216
|
+
if (existingProcess) {
|
|
217
|
+
log(`Found existing OpenCode process on port ${actualWebPort}`);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
const killed = await killProcessOnPort(actualWebPort, config.hostname);
|
|
221
|
+
if (killed) {
|
|
222
|
+
log(`Killed stale process on port ${actualWebPort}`);
|
|
223
|
+
await sleep(PROCESS_KILL_DELAY);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
const configDir = setupOpenCodePlugin();
|
|
227
|
+
if (!existingProcess) {
|
|
228
|
+
webProcess = await startOpenCodeWeb({
|
|
229
|
+
port: actualWebPort,
|
|
230
|
+
hostname: config.hostname,
|
|
231
|
+
serverUrl: '',
|
|
232
|
+
cwd: process.cwd(),
|
|
233
|
+
configDir,
|
|
234
|
+
corsOrigins,
|
|
235
|
+
contextApiUrl,
|
|
236
|
+
});
|
|
237
|
+
log(`OpenCode Web started at http://${config.hostname}:${actualWebPort}`);
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
sessionUrl = await getOrCreateSession();
|
|
241
|
+
log(`Session URL: ${sessionUrl}`);
|
|
242
|
+
}
|
|
243
|
+
catch (e) {
|
|
244
|
+
console.warn(`${LOG_PREFIX} Failed to get/create session:`, e);
|
|
245
|
+
}
|
|
246
|
+
isStarted = true;
|
|
247
|
+
})();
|
|
248
|
+
return startPromise;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* 停止服务
|
|
252
|
+
*/
|
|
253
|
+
async function stopServices() {
|
|
254
|
+
log('Stopping OpenCode services...');
|
|
255
|
+
if (webProcess) {
|
|
256
|
+
webProcess.kill('SIGTERM');
|
|
257
|
+
await new Promise(resolve => {
|
|
258
|
+
webProcess?.on('exit', () => resolve());
|
|
259
|
+
setTimeout(() => {
|
|
260
|
+
webProcess?.kill('SIGKILL');
|
|
261
|
+
resolve();
|
|
262
|
+
}, 3000);
|
|
263
|
+
});
|
|
264
|
+
webProcess = null;
|
|
265
|
+
}
|
|
266
|
+
if (isStarted) {
|
|
267
|
+
await killProcessOnPort(actualWebPort, config.hostname);
|
|
268
|
+
}
|
|
269
|
+
isStarted = false;
|
|
270
|
+
startPromise = null;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* 处理上下文 API 请求
|
|
274
|
+
*/
|
|
275
|
+
function handleContextRequest(req, res) {
|
|
276
|
+
res.setHeader('Content-Type', 'application/json');
|
|
277
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
278
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
|
|
279
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
280
|
+
if (req.method === 'OPTIONS') {
|
|
281
|
+
res.writeHead(200);
|
|
282
|
+
res.end();
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (req.method === 'GET') {
|
|
286
|
+
res.writeHead(200);
|
|
287
|
+
res.end(JSON.stringify(pageContext));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (req.method === 'DELETE') {
|
|
291
|
+
pageContext.selectedElements = [];
|
|
292
|
+
log('Selected elements cleared');
|
|
293
|
+
res.writeHead(200);
|
|
294
|
+
res.end(JSON.stringify({ success: true }));
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (req.method === 'POST') {
|
|
298
|
+
let body = '';
|
|
299
|
+
req.on('data', chunk => body += chunk);
|
|
300
|
+
req.on('end', () => {
|
|
301
|
+
try {
|
|
302
|
+
const data = JSON.parse(body);
|
|
303
|
+
pageContext = {
|
|
304
|
+
url: data.url || '',
|
|
305
|
+
title: data.title || '',
|
|
306
|
+
selectedElements: data.selectedElements || [],
|
|
307
|
+
};
|
|
308
|
+
log(`Context updated: ${pageContext.url}`, data.selectedElements?.length ? `elements: ${data.selectedElements.length}` : '');
|
|
309
|
+
res.writeHead(200);
|
|
310
|
+
res.end(JSON.stringify({ success: true }));
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
res.writeHead(400);
|
|
314
|
+
res.end(JSON.stringify({ error: 'Invalid JSON' }));
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
res.writeHead(405);
|
|
320
|
+
res.end(JSON.stringify({ error: 'Method not allowed' }));
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
name: 'vite-plugin-opencode',
|
|
324
|
+
async configureServer(server) {
|
|
325
|
+
if (!config.enabled)
|
|
326
|
+
return;
|
|
327
|
+
const vitePort = server.config.server.port || 5173;
|
|
328
|
+
const viteHost = server.config.server.host || 'localhost';
|
|
329
|
+
const viteOrigin = `http://${viteHost}:${vitePort}`;
|
|
330
|
+
const contextApiUrl = `http://${viteHost}:${vitePort}${CONTEXT_API_PATH}`;
|
|
331
|
+
if (!config.lazy) {
|
|
332
|
+
await startServices([viteOrigin], contextApiUrl);
|
|
333
|
+
}
|
|
334
|
+
server.middlewares.use(WIDGET_SCRIPT_PATH, async (_req, res) => {
|
|
335
|
+
if (config.lazy && !isStarted) {
|
|
336
|
+
await startServices([viteOrigin], contextApiUrl);
|
|
337
|
+
}
|
|
338
|
+
const widgetPath = path.join(__dirname, 'client.js');
|
|
339
|
+
if (fs.existsSync(widgetPath)) {
|
|
340
|
+
res.setHeader('Content-Type', 'application/javascript');
|
|
341
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
342
|
+
fs.createReadStream(widgetPath).pipe(res);
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
res.writeHead(404);
|
|
346
|
+
res.end('Widget script not found');
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
server.middlewares.use(CONTEXT_API_PATH, async (req, res) => {
|
|
350
|
+
if (config.lazy && !isStarted) {
|
|
351
|
+
await startServices([viteOrigin], contextApiUrl);
|
|
352
|
+
}
|
|
353
|
+
handleContextRequest(req, res);
|
|
354
|
+
});
|
|
355
|
+
server.middlewares.use(START_API_PATH, async (_req, res) => {
|
|
356
|
+
res.setHeader('Content-Type', 'application/json');
|
|
357
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
358
|
+
if (config.lazy && !isStarted) {
|
|
359
|
+
try {
|
|
360
|
+
await startServices([viteOrigin], contextApiUrl);
|
|
361
|
+
res.writeHead(200);
|
|
362
|
+
res.end(JSON.stringify({ success: true, sessionUrl }));
|
|
363
|
+
}
|
|
364
|
+
catch (e) {
|
|
365
|
+
res.writeHead(500);
|
|
366
|
+
res.end(JSON.stringify({ error: String(e) }));
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
res.writeHead(200);
|
|
371
|
+
res.end(JSON.stringify({ success: true, sessionUrl }));
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
server.middlewares.use(SESSIONS_API_PATH, async (req, res) => {
|
|
375
|
+
res.setHeader('Content-Type', 'application/json');
|
|
376
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
377
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS');
|
|
378
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
379
|
+
if (req.method === 'OPTIONS') {
|
|
380
|
+
res.writeHead(200);
|
|
381
|
+
res.end();
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (config.lazy && !isStarted) {
|
|
385
|
+
await startServices([viteOrigin], contextApiUrl);
|
|
386
|
+
}
|
|
387
|
+
try {
|
|
388
|
+
if (req.method === 'GET') {
|
|
389
|
+
const sessions = await getSessions();
|
|
390
|
+
res.writeHead(200);
|
|
391
|
+
res.end(JSON.stringify(sessions));
|
|
392
|
+
}
|
|
393
|
+
else if (req.method === 'POST') {
|
|
394
|
+
const newSession = await createSession();
|
|
395
|
+
res.writeHead(200);
|
|
396
|
+
res.end(JSON.stringify(newSession));
|
|
397
|
+
}
|
|
398
|
+
else if (req.method === 'DELETE') {
|
|
399
|
+
const url = new URL(req.url || '', `http://${req.headers.host}`);
|
|
400
|
+
const sessionId = url.searchParams.get('id');
|
|
401
|
+
if (!sessionId) {
|
|
402
|
+
res.writeHead(400);
|
|
403
|
+
res.end(JSON.stringify({ error: 'Session ID is required' }));
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
await deleteSession(sessionId);
|
|
407
|
+
res.writeHead(200);
|
|
408
|
+
res.end(JSON.stringify({ success: true }));
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
res.writeHead(405);
|
|
412
|
+
res.end(JSON.stringify({ error: 'Method not allowed' }));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
catch (e) {
|
|
416
|
+
res.writeHead(500);
|
|
417
|
+
res.end(JSON.stringify({ error: String(e) }));
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
server.httpServer?.on('close', stopServices);
|
|
421
|
+
const cleanup = async () => {
|
|
422
|
+
await stopServices();
|
|
423
|
+
process.exit(0);
|
|
424
|
+
};
|
|
425
|
+
process.on('SIGINT', cleanup);
|
|
426
|
+
process.on('SIGTERM', cleanup);
|
|
427
|
+
process.on('exit', () => {
|
|
428
|
+
webProcess?.kill('SIGKILL');
|
|
429
|
+
});
|
|
430
|
+
},
|
|
431
|
+
transformIndexHtml(html) {
|
|
432
|
+
const widget = injectWidget({
|
|
433
|
+
webUrl: `http://${config.hostname}:${actualWebPort}`,
|
|
434
|
+
serverUrl: `http://${config.hostname}:${actualWebPort}`,
|
|
435
|
+
position: config.position,
|
|
436
|
+
theme: config.theme,
|
|
437
|
+
open: config.open,
|
|
438
|
+
autoReload: config.autoReload,
|
|
439
|
+
cwd: process.cwd(),
|
|
440
|
+
sessionUrl: sessionUrl || undefined,
|
|
441
|
+
lazy: config.lazy,
|
|
442
|
+
hotkey: config.hotkey,
|
|
443
|
+
});
|
|
444
|
+
return html.replace('</body>', `${widget}</body>`);
|
|
445
|
+
},
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBQ3ZCLE9BQU8sRUFBRSxNQUFNLElBQUksQ0FBQTtBQUNuQixPQUFPLElBQUksTUFBTSxNQUFNLENBQUE7QUFDdkIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sT0FBTyxDQUFBO0FBQ3hDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDekMsT0FBTyxFQUFFLHNCQUFzQixFQUFFLGlCQUFpQixFQUFFLGlCQUFpQixFQUFFLG9CQUFvQixFQUFFLE1BQU0sU0FBUyxDQUFBO0FBRTVHLE9BQU8sRUFDTCxjQUFjLEVBQ2QsZUFBZSxFQUNmLFdBQVcsRUFDWCxrQkFBa0IsRUFDbEIsVUFBVSxFQUNWLGtCQUFrQixFQUNsQixnQkFBZ0IsRUFDaEIsY0FBYyxFQUNkLGlCQUFpQixHQUNsQixNQUFNLGFBQWEsQ0FBQTtBQUVwQjs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUNILE1BQU0sQ0FBQyxPQUFPLFVBQVUsY0FBYyxDQUFDLFVBQTJCLEVBQUU7SUFDbEUsSUFBSSxVQUFVLEdBQXdCLElBQUksQ0FBQTtJQUMxQyxJQUFJLFVBQVUsR0FBa0IsSUFBSSxDQUFBO0lBQ3BDLElBQUksYUFBYSxHQUFXLGNBQWMsQ0FBQyxPQUFPLENBQUE7SUFDbEQsSUFBSSxTQUFTLEdBQUcsS0FBSyxDQUFBO0lBQ3JCLElBQUksWUFBWSxHQUF5QixJQUFJLENBQUE7SUFDN0MsSUFBSSxXQUFXLEdBQWdCLEVBQUUsR0FBRyxFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUE7SUFFckQsTUFBTSxNQUFNLEdBQUcsRUFBRSxHQUFHLGNBQWMsRUFBRSxHQUFHLE9BQU8sRUFBRSxDQUFBO0lBRWhEOztPQUVHO0lBQ0gsU0FBUyxHQUFHLENBQUMsT0FB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Q0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgUGx1Z2luLCBWaXRlRGV2U2VydmVyIH0gZnJvbSAndml0ZSdcbmltcG9ydCB7IHNwYXduLCBDaGlsZFByb2Nlc3MgfSBmcm9tICdjaGlsZF9wcm9jZXNzJ1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCdcbmltcG9ydCBmcyBmcm9tICdmcydcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnXG5pbXBvcnQgeyBzdGFydE9wZW5Db2RlV2ViIH0gZnJvbSAnLi93ZWInXG5pbXBvcnQgeyBpbmplY3RXaWRnZXQgfSBmcm9tICcuL2luamVjdG9yJ1xuaW1wb3J0IHsgY2hlY2tPcGVuQ29kZUluc3RhbGxlZCwgZmluZEF2YWlsYWJsZVBvcnQsIGtpbGxQcm9jZXNzT25Qb3J0LCBjaGVja09wZW5Db2RlUHJvY2VzcyB9IGZyb20gJy4vdXRpbHMnXG5pbXBvcnQgeyBPcGVuQ29kZU9wdGlvbnMsIFNlc3Npb25JbmZvLCBQYWdlQ29udGV4dCB9IGZyb20gJy4vdHlwZXMnXG5pbXBvcnQge1xuICBERUZBVUxUX0NPTkZJRyxcbiAgREVGQVVMVF9SRVRSSUVTLFxuICBSRVRSWV9ERUxBWSxcbiAgUFJPQ0VTU19LSUxMX0RFTEFZLFxuICBMT0dfUFJFRklYLFxuICBXSURHRVRfU0NSSVBUX1BBVEgsXG4gIENPTlRFWFRfQVBJX1BBVEgsXG4gIFNUQVJUX0FQSV9QQVRILFxuICBTRVNTSU9OU19BUElfUEFUSCxcbn0gZnJvbSAnLi9jb25zdGFudHMnXG5cbi8qKlxuICogT3BlbkNvZGUgVml0ZSDmj5Lku7ZcbiAqIEBwYXJhbSBvcHRpb25zIC0g5o+S5Lu26YWN572u6YCJ6aG5XG4gKiBAcmV0dXJucyBWaXRlIOaPkuS7tuWunuS+i1xuICogQGV4YW1wbGVcbiAqIGBgYHRzXG4gKiAvLyB2aXRlLmNvbmZpZy50c1xuICogaW1wb3J0IG9wZW5jb2RlIGZyb20gJ3ZpdGUtcGx1Z2luLW9wZW5jb2RlJ1xuICpcbiAqIGV4cG9ydCBkZWZhdWx0IHtcbiAqICAgcGx1Z2luczogW1xuICogICAgIG9wZW5jb2RlKHtcbiAqICAgICAgIHdlYlBvcnQ6IDQwOTcsXG4gKiAgICAgICBwb3NpdGlvbjogJ2JvdHRvbS1yaWdodCcsXG4gKiAgICAgICB0aGVtZTogJ2F1dG8nXG4gKiAgICAgfSlcbiAqICAgXVxuICogfVxuICogYGBgXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIG9wZW5jb2RlUGx1Z2luKG9wdGlvbnM6IE9wZW5Db2RlT3B0aW9ucyA9IHt9KTogUGx1Z2luIHtcbiAgbGV0IHdlYlByb2Nlc3M6IENoaWxkUHJvY2VzcyB8IG51bGwgPSBudWxsXG4gIGxldCBzZXNzaW9uVXJsOiBzdHJpbmcgfCBudWxsID0gbnVsbFxuICBsZXQgYWN0dWFsV2ViUG9ydDogbnVtYmVyID0gREVGQVVMVF9DT05GSUcud2ViUG9ydFxuICBsZXQgaXNTdGFydGVkID0gZmFsc2VcbiAgbGV0IHN0YXJ0UHJvbWlzZTogUHJvbWlzZTx2b2lkPiB8IG51bGwgPSBudWxsXG4gIGxldCBwYWdlQ29udGV4dDogUGFnZUNvbnRleHQgPSB7IHVybDogJycsIHRpdGxlOiAnJyB9XG5cbiAgY29uc3QgY29uZmlnID0geyAuLi5ERUZBVUxUX0NPTkZJRywgLi4ub3B0aW9ucyB9XG5cbiAgLyoqXG4gICAqIOi+k+WHuuaXpeW/l++8iOS7heWcqCB2ZXJib3NlIOaooeW8j+S4i++8iVxuICAgKi9cbiAgZnVuY3Rpb24gbG9nKG1lc3NhZ2U6IHN0cmluZywgLi4uYXJnczogdW5rbm93bltdKTogdm9pZCB7XG4gICAgaWYgKGNvbmZpZy52ZXJib3NlKSB7XG4gICAgICBjb25zb2xlLmxvZyhgJHtMT0dfUFJFRklYfSAke21lc3NhZ2V9YCwgLi4uYXJncylcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICog6L6T5Ye66ZSZ6K+v5pel5b+XXG4gICAqL1xuICBmdW5jdGlvbiBsb2dFcnJvcihtZXNzYWdlOiBzdHJpbmcsIC4uLmFyZ3M6IHVua25vd25bXSk6IHZvaWQge1xuICAgIGNvbnNvbGUuZXJyb3IoYCR7TE9HX1BSRUZJWH0gJHttZXNzYWdlfWAsIC4uLmFyZ3MpXG4gIH1cblxuICAvKipcbiAgICogQmFzZTY0IOe8lueggeWtl+espuS4slxuICAgKi9cbiAgZnVuY3Rpb24gYmFzZTY0RW5jb2RlKHN0cjogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gQnVmZmVyLmZyb20oc3RyKS50b1N0cmluZygnYmFzZTY0JylcbiAgfVxuXG4gIC8qKlxuICAgKiDlu7bov5/miafooYxcbiAgICovXG4gIGZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKSlcbiAgfVxuXG4gIC8qKlxuICAgKiDliJvlu7ogSFRUUCDor7fmsYIgUHJvbWlzZVxuICAgKi9cbiAgZnVuY3Rpb24gY3JlYXRlSHR0cFJlcXVlc3Q8VD4ob3B0aW9uczogaHR0cC5SZXF1ZXN0T3B0aW9ucywgYm9keT86IHN0cmluZyk6IFByb21pc2U8VD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCByZXEgPSBodHRwLnJlcXVlc3Qob3B0aW9ucywgKHJlcykgPT4ge1xuICAgICAgICBsZXQgZGF0YSA9ICcnXG4gICAgICAgIHJlcy5vbignZGF0YScsIGNodW5rID0+IGRhdGEgKz0gY2h1bmspXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXNvbHZlKEpTT04ucGFyc2UoZGF0YSkpXG4gICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICByZWplY3QobmV3IEVycm9yKGBKU09OIHBhcnNlIGVycm9yOiAke2RhdGEuc3Vic3RyaW5nKDAsIDEwMCl9YCkpXG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgfSlcbiAgICAgIHJlcS5vbignZXJyb3InLCByZWplY3QpXG4gICAgICBpZiAoYm9keSkgcmVxLndyaXRlKGJvZHkpXG4gICAgICByZXEuZW5kKClcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIOiOt+WPluS8muivneWIl+ihqFxuICAgKi9cbiAgYXN5bmMgZnVuY3Rpb24gZ2V0U2Vzc2lvbnMocmV0cmllcyA9IERFRkFVTFRfUkVUUklFUyk6IFByb21pc2U8U2Vzc2lvbkluZm9bXT4ge1xuICAgIGxldCBsYXN0RXJyb3I6IEVycm9yIHwgbnVsbCA9IG51bGxcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcmV0cmllczsgaSsrKSB7XG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gYXdhaXQgY3JlYXRlSHR0cFJlcXVlc3Q8U2Vzc2lvbkluZm9bXT4oe1xuICAgICAgICAgIGhvc3RuYW1lOiBjb25maWcuaG9zdG5hbWUsXG4gICAgICAgICAgcG9ydDogYWN0dWFsV2ViUG9ydCxcbiAgICAgICAgICBwYXRoOiAnL3Nlc3Npb24nLFxuICAgICAgICB9KVxuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBsYXN0RXJyb3IgPSBlIGluc3RhbmNlb2YgRXJyb3IgPyBlIDogbmV3IEVycm9yKFN0cmluZyhlKSlcbiAgICAgICAgaWYgKGkgPCByZXRyaWVzIC0gMSkgYXdhaXQgc2xlZXAoUkVUUllfREVMQVkpXG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhyb3cgbGFzdEVycm9yXG4gIH1cblxuICAvKipcbiAgICog5Yib5bu65paw5Lya6K+dXG4gICAqL1xuICBhc3luYyBmdW5jdGlvbiBjcmVhdGVTZXNzaW9uKHJldHJpZXMgPSBERUZBVUxUX1JFVFJJRVMpOiBQcm9taXNlPFNlc3Npb25JbmZvPiB7XG4gICAgbGV0IGxhc3RFcnJvcjogRXJyb3IgfCBudWxsID0gbnVsbFxuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByZXRyaWVzOyBpKyspIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCBjcmVhdGVIdHRwUmVxdWVzdDxTZXNzaW9uSW5mbz4oe1xuICAgICAgICAgIGhvc3RuYW1lOiBjb25maWcuaG9zdG5hbWUsXG4gICAgICAgICAgcG9ydDogYWN0dWFsV2ViUG9ydCxcbiAgICAgICAgICBwYXRoOiAnL3Nlc3Npb24nLFxuICAgICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICB9KVxuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBsYXN0RXJyb3IgPSBlIGluc3RhbmNlb2YgRXJyb3IgPyBlIDogbmV3IEVycm9yKFN0cmluZyhlKSlcbiAgICAgICAgaWYgKGkgPCByZXRyaWVzIC0gMSkgYXdhaXQgc2xlZXAoUkVUUllfREVMQVkpXG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhyb3cgbGFzdEVycm9yXG4gIH1cblxuICAvKipcbiAgICog5Yig6Zmk5Lya6K+dXG4gICAqL1xuICBhc3luYyBmdW5jdGlvbiBkZWxldGVTZXNzaW9uKHNlc3Npb25JZDogc3RyaW5nLCByZXRyaWVzID0gREVGQVVMVF9SRVRSSUVTKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgbGV0IGxhc3RFcnJvcjogRXJyb3IgfCBudWxsID0gbnVsbFxuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByZXRyaWVzOyBpKyspIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGNyZWF0ZUh0dHBSZXF1ZXN0PHZvaWQ+KHtcbiAgICAgICAgICBob3N0bmFtZTogY29uZmlnLmhvc3RuYW1lLFxuICAgICAgICAgIHBvcnQ6IGFjdHVhbFdlYlBvcnQsXG4gICAgICAgICAgcGF0aDogYC9zZXNzaW9uLyR7c2Vzc2lvbklkfWAsXG4gICAgICAgICAgbWV0aG9kOiAnREVMRVRFJyxcbiAgICAgICAgfSlcbiAgICAgICAgcmV0dXJuXG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGxhc3RFcnJvciA9IGUgaW5zdGFuY2VvZiBFcnJvciA/IGUgOiBuZXcgRXJyb3IoU3RyaW5nKGUpKVxuICAgICAgICBpZiAoaSA8IHJldHJpZXMgLSAxKSBhd2FpdCBzbGVlcChSRVRSWV9ERUxBWSlcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aHJvdyBsYXN0RXJyb3JcbiAgfVxuXG4gIC8qKlxuICAgKiDojrflj5bmiJbliJvlu7rkvJror51cbiAgICovXG4gIGFzeW5jIGZ1bmN0aW9uIGdldE9yQ3JlYXRlU2Vzc2lvbigpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IHByb2plY3REaXIgPSBwcm9jZXNzLmN3ZCgpXG4gICAgbG9nKCdHZXR0aW5nIHNlc3Npb25zLi4uJylcbiAgICBjb25zdCBzZXNzaW9ucyA9IGF3YWl0IGdldFNlc3Npb25zKClcbiAgICBsb2coYEZvdW5kICR7c2Vzc2lvbnMubGVuZ3RofSBzZXNzaW9uc2ApXG5cbiAgICBjb25zdCBtYXRjaGluZ1Nlc3Npb24gPSBzZXNzaW9ucy5maW5kKHMgPT4gcy5kaXJlY3RvcnkgPT09IHByb2plY3REaXIpXG5cbiAgICBpZiAobWF0Y2hpbmdTZXNzaW9uKSB7XG4gICAgICByZXR1cm4gYGh0dHA6Ly8ke2NvbmZpZy5ob3N0bmFtZX06JHthY3R1YWxXZWJQb3J0fS8ke2Jhc2U2NEVuY29kZShwcm9qZWN0RGlyKX0vc2Vzc2lvbi8ke21hdGNoaW5nU2Vzc2lvbi5pZH1gXG4gICAgfVxuXG4gICAgbG9nKCdDcmVhdGluZyBuZXcgc2Vzc2lvbi4uLicpXG4gICAgY29uc3QgbmV3U2Vzc2lvbiA9IGF3YWl0IGNyZWF0ZVNlc3Npb24oKVxuICAgIHJldHVybiBgaHR0cDovLyR7Y29uZmlnLmhvc3RuYW1lfToke2FjdHVhbFdlYlBvcnR9LyR7YmFzZTY0RW5jb2RlKHByb2plY3REaXIpfS9zZXNzaW9uLyR7bmV3U2Vzc2lvbi5pZH1gXG4gIH1cblxuICAvKipcbiAgICog6K6+572uIE9wZW5Db2RlIOaPkuS7tlxuICAgKi9cbiAgZnVuY3Rpb24gc2V0dXBPcGVuQ29kZVBsdWdpbigpOiBzdHJpbmcge1xuICAgIGNvbnN0IHByb2plY3REaXIgPSBwcm9jZXNzLmN3ZCgpXG4gICAgY29uc3QgY2FjaGVEaXIgPSBwYXRoLmpvaW4ocHJvamVjdERpciwgJ25vZGVfbW9kdWxlcycsICcuY2FjaGUnLCAnb3BlbmNvZGUnKVxuICAgIGNvbnN0IHBsdWdpbnNEaXIgPSBwYXRoLmpvaW4oY2FjaGVEaXIsICdwbHVnaW5zJylcblxuICAgIGlmICghZnMuZXhpc3RzU3luYyhwbHVnaW5zRGlyKSkge1xuICAgICAgZnMubWtkaXJTeW5jKHBsdWdpbnNEaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pXG4gICAgfVxuXG4gICAgY29uc3QgcGx1Z2luU291cmNlUGF0aCA9IHBhdGguam9pbihfX2Rpcm5hbWUsICdwbHVnaW5zJywgJ3BhZ2UtY29udGV4dC5qcycpXG4gICAgY29uc3QgcGx1Z2luVGFyZ2V0UGF0aCA9IHBhdGguam9pbihwbHVnaW5zRGlyLCAncGFnZS1jb250ZXh0LmpzJylcblxuICAgIGlmIChmcy5leGlzdHNTeW5jKHBsdWdpblNvdXJjZVBhdGgpKSB7XG4gICAgICBmcy5jb3B5RmlsZVN5bmMocGx1Z2luU291cmNlUGF0aCwgcGx1Z2luVGFyZ2V0UGF0aClcbiAgICAgIGxvZyhgUGx1Z2luIGluc3RhbGxlZCB0byAke3BsdWdpblRhcmdldFBhdGh9YClcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS53YXJuKGAke0xPR19QUkVGSVh9IFBsdWdpbiBzb3VyY2Ugbm90IGZvdW5kOiAke3BsdWdpblNvdXJjZVBhdGh9YClcbiAgICB9XG5cbiAgICByZXR1cm4gY2FjaGVEaXJcbiAgfVxuXG4gIC8qKlxuICAgKiDlkK/liqjmnI3liqFcbiAgICovXG4gIGFzeW5jIGZ1bmN0aW9uIHN0YXJ0U2VydmljZXMoY29yc09yaWdpbnM/OiBzdHJpbmdbXSwgY29udGV4dEFwaVVybD86IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmIChpc1N0YXJ0ZWQpIHJldHVyblxuICAgIGlmIChzdGFydFByb21pc2UpIHJldHVybiBzdGFydFByb21pc2VcblxuICAgIHN0YXJ0UHJvbWlzZSA9IChhc3luYyAoKSA9PiB7XG4gICAgICBsb2coJ1N0YXJ0aW5nIE9wZW5Db2RlIHNlcnZpY2VzLi4uJylcblxuICAgICAgaWYgKCFhd2FpdCBjaGVja09wZW5Db2RlSW5zdGFsbGVkKCkpIHtcbiAgICAgICAgbG9nRXJyb3IoYE9wZW5Db2RlIGlzIG5vdCBpbnN0YWxsZWQhXG5cblBsZWFzZSBpbnN0YWxsIE9wZW5Db2RlIGZpcnN0OlxuXG4gICMgVXNpbmcgSG9tZWJyZXcgKG1hY09TKVxuICBicmV3IGluc3RhbGwgb3BlbmNvZGUtYWkvdGFwL29wZW5jb2RlXG5cbiAgIyBPciB1c2luZyB0aGUgaW5zdGFsbCBzY3JpcHRcbiAgY3VybCAtZnNTTCBodHRwczovL29wZW5jb2RlLmFpL2luc3RhbGwgfCBiYXNoXG4gICAgICAgIGApXG4gICAgICAgIHJldHVyblxuICAgICAgfVxuXG4gICAgICBhY3R1YWxXZWJQb3J0ID0gYXdhaXQgZmluZEF2YWlsYWJsZVBvcnQoY29uZmlnLndlYlBvcnQsIGNvbmZpZy5ob3N0bmFtZSlcbiAgICAgIGlmIChhY3R1YWxXZWJQb3J0ICE9PSBjb25maWcud2ViUG9ydCkge1xuICAgICAgICBsb2coYFBvcnQgJHtjb25maWcud2ViUG9ydH0gaXMgaW4gdXNlLCB1c2luZyAke2FjdHVhbFdlYlBvcnR9IGluc3RlYWRgKVxuICAgICAgfVxuXG4gICAgICBjb25zdCBleGlzdGluZ1Byb2Nlc3MgPSBhd2FpdCBjaGVja09wZW5Db2RlUHJvY2VzcyhhY3R1YWxXZWJQb3J0KVxuICAgICAgaWYgKGV4aXN0aW5nUHJvY2Vzcykge1xuICAgICAgICBsb2coYEZvdW5kIGV4aXN0aW5nIE9wZW5Db2RlIHByb2Nlc3Mgb24gcG9ydCAke2FjdHVhbFdlYlBvcnR9YClcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGtpbGxlZCA9IGF3YWl0IGtpbGxQcm9jZXNzT25Qb3J0KGFjdHVhbFdlYlBvcnQsIGNvbmZpZy5ob3N0bmFtZSlcbiAgICAgICAgaWYgKGtpbGxlZCkge1xuICAgICAgICAgIGxvZyhgS2lsbGVkIHN0YWxlIHByb2Nlc3Mgb24gcG9ydCAke2FjdHVhbFdlYlBvcnR9YClcbiAgICAgICAgICBhd2FpdCBzbGVlcChQUk9DRVNTX0tJTExfREVMQVkpXG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgY29uZmlnRGlyID0gc2V0dXBPcGVuQ29kZVBsdWdpbigpXG5cbiAgICAgIGlmICghZXhpc3RpbmdQcm9jZXNzKSB7XG4gICAgICAgIHdlYlByb2Nlc3MgPSBhd2FpdCBzdGFydE9wZW5Db2RlV2ViKHtcbiAgICAgICAgICBwb3J0OiBhY3R1YWxXZWJQb3J0LFxuICAgICAgICAgIGhvc3RuYW1lOiBjb25maWcuaG9zdG5hbWUsXG4gICAgICAgICAgc2VydmVyVXJsOiAnJyxcbiAgICAgICAgICBjd2Q6IHByb2Nlc3MuY3dkKCksXG4gICAgICAgICAgY29uZmlnRGlyLFxuICAgICAgICAgIGNvcnNPcmlnaW5zLFxuICAgICAgICAgIGNvbnRleHRBcGlVcmwsXG4gICAgICAgIH0pXG4gICAgICAgIGxvZyhgT3BlbkNvZGUgV2ViIHN0YXJ0ZWQgYXQgaHR0cDovLyR7Y29uZmlnLmhvc3RuYW1lfToke2FjdHVhbFdlYlBvcnR9YClcbiAgICAgIH1cblxuICAgICAgdHJ5IHtcbiAgICAgICAgc2Vzc2lvblVybCA9IGF3YWl0IGdldE9yQ3JlYXRlU2Vzc2lvbigpXG4gICAgICAgIGxvZyhgU2Vzc2lvbiBVUkw6ICR7c2Vzc2lvblVybH1gKVxuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjb25zb2xlLndhcm4oYCR7TE9HX1BSRUZJWH0gRmFpbGVkIHRvIGdldC9jcmVhdGUgc2Vzc2lvbjpgLCBlKVxuICAgICAgfVxuXG4gICAgICBpc1N0YXJ0ZWQgPSB0cnVlXG4gICAgfSkoKVxuXG4gICAgcmV0dXJuIHN0YXJ0UHJvbWlzZVxuICB9XG5cbiAgLyoqXG4gICAqIOWBnOatouacjeWKoVxuICAgKi9cbiAgYXN5bmMgZnVuY3Rpb24gc3RvcFNlcnZpY2VzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGxvZygnU3RvcHBpbmcgT3BlbkNvZGUgc2VydmljZXMuLi4nKVxuICAgIFxuICAgIGlmICh3ZWJQcm9jZXNzKSB7XG4gICAgICB3ZWJQcm9jZXNzLmtpbGwoJ1NJR1RFUk0nKVxuICAgICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4ocmVzb2x2ZSA9PiB7XG4gICAgICAgIHdlYlByb2Nlc3M/Lm9uKCdleGl0JywgKCkgPT4gcmVzb2x2ZSgpKVxuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICB3ZWJQcm9jZXNzPy5raWxsKCdTSUdLSUxMJylcbiAgICAgICAgICByZXNvbHZlKClcbiAgICAgICAgfSwgMzAwMClcbiAgICAgIH0pXG4gICAgICB3ZWJQcm9jZXNzID0gbnVsbFxuICAgIH1cbiAgICBcbiAgICBpZiAoaXNTdGFydGVkKSB7XG4gICAgICBhd2FpdCBraWxsUHJvY2Vzc09uUG9ydChhY3R1YWxXZWJQb3J0LCBjb25maWcuaG9zdG5hbWUpXG4gICAgfVxuICAgIFxuICAgIGlzU3RhcnRlZCA9IGZhbHNlXG4gICAgc3RhcnRQcm9taXNlID0gbnVsbFxuICB9XG5cbiAgLyoqXG4gICAqIOWkhOeQhuS4iuS4i+aWhyBBUEkg6K+35rGCXG4gICAqL1xuICBmdW5jdGlvbiBoYW5kbGVDb250ZXh0UmVxdWVzdChyZXE6IGh0dHAuSW5jb21pbmdNZXNzYWdlLCByZXM6IGh0dHAuU2VydmVyUmVzcG9uc2UpOiB2b2lkIHtcbiAgICByZXMuc2V0SGVhZGVyKCdDb250ZW50LVR5cGUnLCAnYXBwbGljYXRpb24vanNvbicpXG4gICAgcmVzLnNldEhlYWRlcignQWNjZXNzLUNvbnRyb2wtQWxsb3ctT3JpZ2luJywgJyonKVxuICAgIHJlcy5zZXRIZWFkZXIoJ0FjY2Vzcy1Db250cm9sLUFsbG93LU1ldGhvZHMnLCAnR0VULCBQT1NULCBERUxFVEUsIE9QVElPTlMnKVxuICAgIHJlcy5zZXRIZWFkZXIoJ0FjY2Vzcy1Db250cm9sLUFsbG93LUhlYWRlcnMnLCAnQ29udGVudC1UeXBlJylcblxuICAgIGlmIChyZXEubWV0aG9kID09PSAnT1BUSU9OUycpIHtcbiAgICAgIHJlcy53cml0ZUhlYWQoMjAwKVxuICAgICAgcmVzLmVuZCgpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBpZiAocmVxLm1ldGhvZCA9PT0gJ0dFVCcpIHtcbiAgICAgIHJlcy53cml0ZUhlYWQoMjAwKVxuICAgICAgcmVzLmVuZChKU09OLnN0cmluZ2lmeShwYWdlQ29udGV4dCkpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBpZiAocmVxLm1ldGhvZCA9PT0gJ0RFTEVURScpIHtcbiAgICAgIHBhZ2VDb250ZXh0LnNlbGVjdGVkRWxlbWVudHMgPSBbXVxuICAgICAgbG9nKCdTZWxlY3RlZCBlbGVtZW50cyBjbGVhcmVkJylcbiAgICAgIHJlcy53cml0ZUhlYWQoMjAwKVxuICAgICAgcmVzLmVuZChKU09OLnN0cmluZ2lmeSh7IHN1Y2Nlc3M6IHRydWUgfSkpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBpZiAocmVxLm1ldGhvZCA9PT0gJ1BPU1QnKSB7XG4gICAgICBsZXQgYm9keSA9ICcnXG4gICAgICByZXEub24oJ2RhdGEnLCBjaHVuayA9PiBib2R5ICs9IGNodW5rKVxuICAgICAgcmVxLm9uKCdlbmQnLCAoKSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgZGF0YSA9IEpTT04ucGFyc2UoYm9keSlcbiAgICAgICAgICBwYWdlQ29udGV4dCA9IHtcbiAgICAgICAgICAgIHVybDogZGF0YS51cmwgfHwgJycsXG4gICAgICAgICAgICB0aXRsZTogZGF0YS50aXRsZSB8fCAnJyxcbiAgICAgICAgICAgIHNlbGVjdGVkRWxlbWVudHM6IGRhdGEuc2VsZWN0ZWRFbGVtZW50cyB8fCBbXSxcbiAgICAgICAgICB9XG4gICAgICAgICAgbG9nKGBDb250ZXh0IHVwZGF0ZWQ6ICR7cGFnZUNvbnRleHQudXJsfWAsIGRhdGEuc2VsZWN0ZWRFbGVtZW50cz8ubGVuZ3RoID8gYGVsZW1lbnRzOiAke2RhdGEuc2VsZWN0ZWRFbGVtZW50cy5sZW5ndGh9YCA6ICcnKVxuICAgICAgICAgIHJlcy53cml0ZUhlYWQoMjAwKVxuICAgICAgICAgIHJlcy5lbmQoSlNPTi5zdHJpbmdpZnkoeyBzdWNjZXNzOiB0cnVlIH0pKVxuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICByZXMud3JpdGVIZWFkKDQwMClcbiAgICAgICAgICByZXMuZW5kKEpTT04uc3RyaW5naWZ5KHsgZXJyb3I6ICdJbnZhbGlkIEpTT04nIH0pKVxuICAgICAgICB9XG4gICAgICB9KVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgcmVzLndyaXRlSGVhZCg0MDUpXG4gICAgcmVzLmVuZChKU09OLnN0cmluZ2lmeSh7IGVycm9yOiAnTWV0aG9kIG5vdCBhbGxvd2VkJyB9KSlcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgbmFtZTogJ3ZpdGUtcGx1Z2luLW9wZW5jb2RlJyxcblxuICAgIGFzeW5jIGNvbmZpZ3VyZVNlcnZlcihzZXJ2ZXI6IFZpdGVEZXZTZXJ2ZXIpIHtcbiAgICAgIGlmICghY29uZmlnLmVuYWJsZWQpIHJldHVyblxuXG4gICAgICBjb25zdCB2aXRlUG9ydCA9IHNlcnZlci5jb25maWcuc2VydmVyLnBvcnQgfHwgNTE3M1xuICAgICAgY29uc3Qgdml0ZUhvc3QgPSBzZXJ2ZXIuY29uZmlnLnNlcnZlci5ob3N0IHx8ICdsb2NhbGhvc3QnXG4gICAgICBjb25zdCB2aXRlT3JpZ2luID0gYGh0dHA6Ly8ke3ZpdGVIb3N0fToke3ZpdGVQb3J0fWBcbiAgICAgIGNvbnN0IGNvbnRleHRBcGlVcmwgPSBgaHR0cDovLyR7dml0ZUhvc3R9OiR7dml0ZVBvcnR9JHtDT05URVhUX0FQSV9QQVRIfWBcblxuICAgICAgaWYgKCFjb25maWcubGF6eSkge1xuICAgICAgICBhd2FpdCBzdGFydFNlcnZpY2VzKFt2aXRlT3JpZ2luXSwgY29udGV4dEFwaVVybClcbiAgICAgIH1cblxuICAgICAgc2VydmVyLm1pZGRsZXdhcmVzLnVzZShXSURHRVRfU0NSSVBUX1BBVEgsIGFzeW5jIChfcmVxLCByZXMpID0+IHtcbiAgICAgICAgaWYgKGNvbmZpZy5sYXp5ICYmICFpc1N0YXJ0ZWQpIHtcbiAgICAgICAgICBhd2FpdCBzdGFydFNlcnZpY2VzKFt2aXRlT3JpZ2luXSwgY29udGV4dEFwaVVybClcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHdpZGdldFBhdGggPSBwYXRoLmpvaW4oX19kaXJuYW1lLCAnY2xpZW50LmpzJylcbiAgICAgICAgaWYgKGZzLmV4aXN0c1N5bmMod2lkZ2V0UGF0aCkpIHtcbiAgICAgICAgICByZXMuc2V0SGVhZGVyKCdDb250ZW50LVR5cGUnLCAnYXBwbGljYXRpb24vamF2YXNjcmlwdCcpXG4gICAgICAgICAgcmVzLnNldEhlYWRlcignQWNjZXNzLUNvbnRyb2wtQWxsb3ctT3JpZ2luJywgJyonKVxuICAgICAgICAgIGZzLmNyZWF0ZVJlYWRTdHJlYW0od2lkZ2V0UGF0aCkucGlwZShyZXMpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmVzLndyaXRlSGVhZCg0MDQpXG4gICAgICAgICAgcmVzLmVuZCgnV2lkZ2V0IHNjcmlwdCBub3QgZm91bmQnKVxuICAgICAgICB9XG4gICAgICB9KVxuXG4gICAgICBzZXJ2ZXIubWlkZGxld2FyZXMudXNlKENPTlRFWFRfQVBJX1BBVEgsIGFzeW5jIChyZXEsIHJlcykgPT4ge1xuICAgICAgICBpZiAoY29uZmlnLmxhenkgJiYgIWlzU3RhcnRlZCkge1xuICAgICAgICAgIGF3YWl0IHN0YXJ0U2VydmljZXMoW3ZpdGVPcmlnaW5dLCBjb250ZXh0QXBpVXJsKVxuICAgICAgICB9XG4gICAgICAgIGhhbmRsZUNvbnRleHRSZXF1ZXN0KHJlcSBhcyBodHRwLkluY29taW5nTWVzc2FnZSwgcmVzKVxuICAgICAgfSlcblxuICAgICAgc2VydmVyLm1pZGRsZXdhcmVzLnVzZShTVEFSVF9BUElfUEFUSCwgYXN5bmMgKF9yZXEsIHJlcykgPT4ge1xuICAgICAgICByZXMuc2V0SGVhZGVyKCdDb250ZW50LVR5cGUnLCAnYXBwbGljYXRpb24vanNvbicpXG4gICAgICAgIHJlcy5zZXRIZWFkZXIoJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbicsICcqJylcblxuICAgICAgICBpZiAoY29uZmlnLmxhenkgJiYgIWlzU3RhcnRlZCkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBzdGFydFNlcnZpY2VzKFt2aXRlT3JpZ2luXSwgY29udGV4dEFwaVVybClcbiAgICAgICAgICAgIHJlcy53cml0ZUhlYWQoMjAwKVxuICAgICAgICAgICAgcmVzLmVuZChKU09OLnN0cmluZ2lmeSh7IHN1Y2Nlc3M6IHRydWUsIHNlc3Npb25VcmwgfSkpXG4gICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgcmVzLndyaXRlSGVhZCg1MDApXG4gICAgICAgICAgICByZXMuZW5kKEpTT04uc3RyaW5naWZ5KHsgZXJyb3I6IFN0cmluZyhlKSB9KSlcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmVzLndyaXRlSGVhZCgyMDApXG4gICAgICAgICAgcmVzLmVuZChKU09OLnN0cmluZ2lmeSh7IHN1Y2Nlc3M6IHRydWUsIHNlc3Npb25VcmwgfSkpXG4gICAgICAgIH1cbiAgICAgIH0pXG5cbiAgICAgIHNlcnZlci5taWRkbGV3YXJlcy51c2UoU0VTU0lPTlNfQVBJX1BBVEgsIGFzeW5jIChyZXEsIHJlcykgPT4ge1xuICAgICAgICByZXMuc2V0SGVhZGVyKCdDb250ZW50LVR5cGUnLCAnYXBwbGljYXRpb24vanNvbicpXG4gICAgICAgIHJlcy5zZXRIZWFkZXIoJ0FjY2Vzcy1Db250cm9sLUFsbG93LU9yaWdpbicsICcqJylcbiAgICAgICAgcmVzLnNldEhlYWRlcignQWNjZXNzLUNvbnRyb2wtQWxsb3ctTWV0aG9kcycsICdHRVQsIFBPU1QsIERFTEVURSwgT1BUSU9OUycpXG4gICAgICAgIHJlcy5zZXRIZWFkZXIoJ0FjY2Vzcy1Db250cm9sLUFsbG93LUhlYWRlcnMnLCAnQ29udGVudC1UeXBlJylcblxuICAgICAgICBpZiAocmVxLm1ldGhvZCA9PT0gJ09QVElPTlMnKSB7XG4gICAgICAgICAgcmVzLndyaXRlSGVhZCgyMDApXG4gICAgICAgICAgcmVzLmVuZCgpXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY29uZmlnLmxhenkgJiYgIWlzU3RhcnRlZCkge1xuICAgICAgICAgIGF3YWl0IHN0YXJ0U2VydmljZXMoW3ZpdGVPcmlnaW5dLCBjb250ZXh0QXBpVXJsKVxuICAgICAgICB9XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBpZiAocmVxLm1ldGhvZCA9PT0gJ0dFVCcpIHtcbiAgICAgICAgICAgIGNvbnN0IHNlc3Npb25zID0gYXdhaXQgZ2V0U2Vzc2lvbnMoKVxuICAgICAgICAgICAgcmVzLndyaXRlSGVhZCgyMDApXG4gICAgICAgICAgICByZXMuZW5kKEpTT04uc3RyaW5naWZ5KHNlc3Npb25zKSlcbiAgICAgICAgICB9IGVsc2UgaWYgKHJlcS5tZXRob2QgPT09ICdQT1NUJykge1xuICAgICAgICAgICAgY29uc3QgbmV3U2Vzc2lvbiA9IGF3YWl0IGNyZWF0ZVNlc3Npb24oKVxuICAgICAgICAgICAgcmVzLndyaXRlSGVhZCgyMDApXG4gICAgICAgICAgICByZXMuZW5kKEpTT04uc3RyaW5naWZ5KG5ld1Nlc3Npb24pKVxuICAgICAgICAgIH0gZWxzZSBpZiAocmVxLm1ldGhvZCA9PT0gJ0RFTEVURScpIHtcbiAgICAgICAgICAgIGNvbnN0IHVybCA9IG5ldyBVUkwocmVxLnVybCB8fCAnJywgYGh0dHA6Ly8ke3JlcS5oZWFkZXJzLmhvc3R9YClcbiAgICAgICAgICAgIGNvbnN0IHNlc3Npb25JZCA9IHVybC5zZWFyY2hQYXJhbXMuZ2V0KCdpZCcpXG4gICAgICAgICAgICBcbiAgICAgICAgICAgIGlmICghc2Vzc2lvbklkKSB7XG4gICAgICAgICAgICAgIHJlcy53cml0ZUhlYWQoNDAwKVxuICAgICAgICAgICAgICByZXMuZW5kKEpTT04uc3RyaW5naWZ5KHsgZXJyb3I6ICdTZXNzaW9uIElEIGlzIHJlcXVpcmVkJyB9KSlcbiAgICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBcbiAgICAgICAgICAgIGF3YWl0IGRlbGV0ZVNlc3Npb24oc2Vzc2lvbklkKVxuICAgICAgICAgICAgcmVzLndyaXRlSGVhZCgyMDApXG4gICAgICAgICAgICByZXMuZW5kKEpTT04uc3RyaW5naWZ5KHsgc3VjY2VzczogdHJ1ZSB9KSlcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVzLndyaXRlSGVhZCg0MDUpXG4gICAgICAgICAgICByZXMuZW5kKEpTT04uc3RyaW5naWZ5KHsgZXJyb3I6ICdNZXRob2Qgbm90IGFsbG93ZWQnIH0pKVxuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgIHJlcy53cml0ZUhlYWQoNTAwKVxuICAgICAgICAgIHJlcy5lbmQoSlNPTi5zdHJpbmdpZnkoeyBlcnJvcjogU3RyaW5nKGUpIH0pKVxuICAgICAgICB9XG4gICAgICB9KVxuXG4gICAgICBzZXJ2ZXIuaHR0cFNlcnZlcj8ub24oJ2Nsb3NlJywgc3RvcFNlcnZpY2VzKVxuICAgICAgXG4gICAgICBjb25zdCBjbGVhbnVwID0gYXN5bmMgKCkgPT4ge1xuICAgICAgICBhd2FpdCBzdG9wU2VydmljZXMoKVxuICAgICAgICBwcm9jZXNzLmV4aXQoMClcbiAgICAgIH1cbiAgICAgIFxuICAgICAgcHJvY2Vzcy5vbignU0lHSU5UJywgY2xlYW51cClcbiAgICAgIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCBjbGVhbnVwKVxuICAgICAgcHJvY2Vzcy5vbignZXhpdCcsICgpID0+IHtcbiAgICAgICAgd2ViUHJvY2Vzcz8ua2lsbCgnU0lHS0lMTCcpXG4gICAgICB9KVxuICAgIH0sXG5cbiAgICB0cmFuc2Zvcm1JbmRleEh0bWwoaHRtbCkge1xuICAgICAgY29uc3Qgd2lkZ2V0ID0gaW5qZWN0V2lkZ2V0KHtcbiAgICAgICAgd2ViVXJsOiBgaHR0cDovLyR7Y29uZmlnLmhvc3RuYW1lfToke2FjdHVhbFdlYlBvcnR9YCxcbiAgICAgICAgc2VydmVyVXJsOiBgaHR0cDovLyR7Y29uZmlnLmhvc3RuYW1lfToke2FjdHVhbFdlYlBvcnR9YCxcbiAgICAgICAgcG9zaXRpb246IGNvbmZpZy5wb3NpdGlvbixcbiAgICAgICAgdGhlbWU6IGNvbmZpZy50aGVtZSxcbiAgICAgICAgb3BlbjogY29uZmlnLm9wZW4sXG4gICAgICAgIGF1dG9SZWxvYWQ6IGNvbmZpZy5hdXRvUmVsb2FkLFxuICAgICAgICBjd2Q6IHByb2Nlc3MuY3dkKCksXG4gICAgICAgIHNlc3Npb25Vcmw6IHNlc3Npb25VcmwgfHwgdW5kZWZpbmVkLFxuICAgICAgICBsYXp5OiBjb25maWcubGF6eSxcbiAgICAgICAgaG90a2V5OiBjb25maWcuaG90a2V5LFxuICAgICAgfSlcbiAgICAgIHJldHVybiBodG1sLnJlcGxhY2UoJzwvYm9keT4nLCBgJHt3aWRnZXR9PC9ib2R5PmApXG4gICAgfSxcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { WidgetOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* 生成挂件注入脚本标签
|
|
4
|
+
* @param options - 挂件配置选项
|
|
5
|
+
* @returns HTML 脚本标签字符串
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* const widget = injectWidget({
|
|
9
|
+
* webUrl: 'http://127.0.0.1:4097',
|
|
10
|
+
* serverUrl: 'http://127.0.0.1:4097',
|
|
11
|
+
* position: 'bottom-right',
|
|
12
|
+
* theme: 'auto',
|
|
13
|
+
* open: false,
|
|
14
|
+
* autoReload: true,
|
|
15
|
+
* cwd: process.cwd()
|
|
16
|
+
* })
|
|
17
|
+
* // 返回: '<script src="/__opencode_widget__.js" data-opencode-config="..."></script>'
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function injectWidget(options: WidgetOptions): string;
|
package/dist/injector.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { WIDGET_SCRIPT_PATH, CONFIG_DATA_ATTR } from './constants';
|
|
2
|
+
/**
|
|
3
|
+
* 生成挂件注入脚本标签
|
|
4
|
+
* @param options - 挂件配置选项
|
|
5
|
+
* @returns HTML 脚本标签字符串
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* const widget = injectWidget({
|
|
9
|
+
* webUrl: 'http://127.0.0.1:4097',
|
|
10
|
+
* serverUrl: 'http://127.0.0.1:4097',
|
|
11
|
+
* position: 'bottom-right',
|
|
12
|
+
* theme: 'auto',
|
|
13
|
+
* open: false,
|
|
14
|
+
* autoReload: true,
|
|
15
|
+
* cwd: process.cwd()
|
|
16
|
+
* })
|
|
17
|
+
* // 返回: '<script src="/__opencode_widget__.js" data-opencode-config="..."></script>'
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function injectWidget(options) {
|
|
21
|
+
const configBase64 = Buffer.from(JSON.stringify(options)).toString('base64');
|
|
22
|
+
return `<script src="${WIDGET_SCRIPT_PATH}" ${CONFIG_DATA_ATTR}="${configBase64}"></script>`;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5qZWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5qZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLGtCQUFrQixFQUFFLGdCQUFnQixFQUFFLE1BQU0sYUFBYSxDQUFBO0FBRWxFOzs7Ozs7Ozs7Ozs7Ozs7OztHQWlCRztBQUNILE1BQU0sVUFBVSxZQUFZLENBQUMsT0FBc0I7SUFDakQsTUFBTSxZQUFZLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFBO0lBQzVFLE9BQU8sZ0JBQWdCLGtCQUFrQixLQUFLLGdCQUFnQixLQUFLLFlBQVksYUFBYSxDQUFBO0FBQzlGLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBXaWRnZXRPcHRpb25zIH0gZnJvbSAnLi90eXBlcydcbmltcG9ydCB7IFdJREdFVF9TQ1JJUFRfUEFUSCwgQ09ORklHX0RBVEFfQVRUUiB9IGZyb20gJy4vY29uc3RhbnRzJ1xuXG4vKipcbiAqIOeUn+aIkOaMguS7tuazqOWFpeiEmuacrOagh+etvlxuICogQHBhcmFtIG9wdGlvbnMgLSDmjILku7bphY3nva7pgInpoblcbiAqIEByZXR1cm5zIEhUTUwg6ISa5pys5qCH562+5a2X56ym5LiyXG4gKiBAZXhhbXBsZVxuICogYGBgdHNcbiAqIGNvbnN0IHdpZGdldCA9IGluamVjdFdpZGdldCh7XG4gKiAgIHdlYlVybDogJ2h0dHA6Ly8xMjcuMC4wLjE6NDA5NycsXG4gKiAgIHNlcnZlclVybDogJ2h0dHA6Ly8xMjcuMC4wLjE6NDA5NycsXG4gKiAgIHBvc2l0aW9uOiAnYm90dG9tLXJpZ2h0JyxcbiAqICAgdGhlbWU6ICdhdXRvJyxcbiAqICAgb3BlbjogZmFsc2UsXG4gKiAgIGF1dG9SZWxvYWQ6IHRydWUsXG4gKiAgIGN3ZDogcHJvY2Vzcy5jd2QoKVxuICogfSlcbiAqIC8vIOi/lOWbnjogJzxzY3JpcHQgc3JjPVwiL19fb3BlbmNvZGVfd2lkZ2V0X18uanNcIiBkYXRhLW9wZW5jb2RlLWNvbmZpZz1cIi4uLlwiPjwvc2NyaXB0PidcbiAqIGBgYFxuICovXG5leHBvcnQgZnVuY3Rpb24gaW5qZWN0V2lkZ2V0KG9wdGlvbnM6IFdpZGdldE9wdGlvbnMpOiBzdHJpbmcge1xuICBjb25zdCBjb25maWdCYXNlNjQgPSBCdWZmZXIuZnJvbShKU09OLnN0cmluZ2lmeShvcHRpb25zKSkudG9TdHJpbmcoJ2Jhc2U2NCcpXG4gIHJldHVybiBgPHNjcmlwdCBzcmM9XCIke1dJREdFVF9TQ1JJUFRfUEFUSH1cIiAke0NPTkZJR19EQVRBX0FUVFJ9PVwiJHtjb25maWdCYXNlNjR9XCI+PC9zY3JpcHQ+YFxufVxuIl19
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview OpenCode 页面上下文插件
|
|
3
|
+
* @description 用于将页面上下文信息注入到 AI 对话中
|
|
4
|
+
*/
|
|
5
|
+
import type { Plugin } from "@opencode-ai/plugin";
|
|
6
|
+
/**
|
|
7
|
+
* OpenCode 页面上下文插件
|
|
8
|
+
* @returns 插件钩子
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* // 在 opencode 配置中使用
|
|
12
|
+
* import { PageContextPlugin } from './plugins/page-context'
|
|
13
|
+
*
|
|
14
|
+
* export default {
|
|
15
|
+
* plugins: [PageContextPlugin]
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare const PageContextPlugin: Plugin;
|
|
20
|
+
export default PageContextPlugin;
|