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
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview OpenCode 页面上下文插件
|
|
3
|
+
* @description 用于将页面上下文信息注入到 AI 对话中
|
|
4
|
+
*/
|
|
5
|
+
/** 最大文本长度 */
|
|
6
|
+
const MAX_TEXT_LENGTH = 10000;
|
|
7
|
+
/** 上下文标记 */
|
|
8
|
+
const CONTEXT_MARKER = '__OPENCODE_CONTEXT__';
|
|
9
|
+
/**
|
|
10
|
+
* OpenCode 页面上下文插件
|
|
11
|
+
* @returns 插件钩子
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* // 在 opencode 配置中使用
|
|
15
|
+
* import { PageContextPlugin } from './plugins/page-context'
|
|
16
|
+
*
|
|
17
|
+
* export default {
|
|
18
|
+
* plugins: [PageContextPlugin]
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export const PageContextPlugin = async () => {
|
|
23
|
+
const contextApiUrl = process.env.OPENCODE_CONTEXT_API_URL;
|
|
24
|
+
if (!contextApiUrl) {
|
|
25
|
+
console.warn('OPENCODE_CONTEXT_API_URL is not set, page context plugin will not work');
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
const apiUrl = contextApiUrl;
|
|
29
|
+
/**
|
|
30
|
+
* 获取页面上下文
|
|
31
|
+
* @returns 页面上下文数据,获取失败时返回 null
|
|
32
|
+
*/
|
|
33
|
+
async function getPageContext() {
|
|
34
|
+
try {
|
|
35
|
+
const response = await fetch(apiUrl);
|
|
36
|
+
const data = await response.json();
|
|
37
|
+
return {
|
|
38
|
+
url: data.url || "",
|
|
39
|
+
title: data.title || "",
|
|
40
|
+
selectedElements: data.selectedElements
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 清除选中的元素
|
|
49
|
+
*/
|
|
50
|
+
async function clearSelectedElements() {
|
|
51
|
+
try {
|
|
52
|
+
await fetch(apiUrl, { method: 'DELETE' });
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// 忽略错误
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 格式化选中元素信息
|
|
60
|
+
* @param element - 选中的元素
|
|
61
|
+
* @returns 格式化后的元素信息字符串
|
|
62
|
+
*/
|
|
63
|
+
function formatSelectedElement(element) {
|
|
64
|
+
const parts = [];
|
|
65
|
+
if (element.filePath) {
|
|
66
|
+
let location = `文件: ${element.filePath}`;
|
|
67
|
+
if (element.line) {
|
|
68
|
+
location += `:${element.line}`;
|
|
69
|
+
if (element.column) {
|
|
70
|
+
location += `:${element.column}`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
parts.push(location);
|
|
74
|
+
}
|
|
75
|
+
if (element.innerText?.trim()) {
|
|
76
|
+
const text = element.innerText.trim().substring(0, MAX_TEXT_LENGTH);
|
|
77
|
+
const suffix = element.innerText.length > MAX_TEXT_LENGTH ? '...' : '';
|
|
78
|
+
parts.push(`节点文本: "${text}${suffix}"`);
|
|
79
|
+
}
|
|
80
|
+
return parts.join('\n') + '\n';
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 构建上下文前缀
|
|
84
|
+
* @param context - 页面上下文
|
|
85
|
+
* @returns 上下文前缀字符串
|
|
86
|
+
*/
|
|
87
|
+
function buildContextPrefix(context) {
|
|
88
|
+
let prefix = `我现在正在浏览这个页面:${context.url}\n\n`;
|
|
89
|
+
if (context.selectedElements?.length) {
|
|
90
|
+
prefix += `帮我找到以下节点,一定要精确到具体的节点:\n\n`;
|
|
91
|
+
context.selectedElements.forEach((element) => {
|
|
92
|
+
prefix += formatSelectedElement(element) + "\n";
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
prefix += `请根据以上信息,完成以下任务:\n`;
|
|
96
|
+
prefix += `\n`;
|
|
97
|
+
return prefix;
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
"experimental.chat.messages.transform": async (_input, output) => {
|
|
101
|
+
const context = await getPageContext();
|
|
102
|
+
if (!context?.url)
|
|
103
|
+
return;
|
|
104
|
+
const lastUserMsg = [...output.messages].reverse().find(m => m.info.role === "user");
|
|
105
|
+
if (!lastUserMsg)
|
|
106
|
+
return;
|
|
107
|
+
const textPart = lastUserMsg.parts.find(p => p.type === "text");
|
|
108
|
+
if (!textPart || !("text" in textPart))
|
|
109
|
+
return;
|
|
110
|
+
if (textPart.text.includes(CONTEXT_MARKER))
|
|
111
|
+
return;
|
|
112
|
+
const prefix = buildContextPrefix(context);
|
|
113
|
+
textPart.text = prefix + textPart.text;
|
|
114
|
+
if (context.selectedElements?.length) {
|
|
115
|
+
await clearSelectedElements();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
export default PageContextPlugin;
|
|
121
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFnZS1jb250ZXh0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BsdWdpbnMvcGFnZS1jb250ZXh0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQUlILGFBQWE7QUFDYixNQUFNLGVBQWUsR0FBRyxLQUFLLENBQUE7QUFFN0IsWUFBWTtBQUNaLE1BQU0sY0FBYyxHQUFHLHNCQUFzQixDQUFBO0FBNEI3Qzs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBVyxLQUFLLElBQW9CLEVBQUU7SUFDbEUsTUFBTSxhQUFhLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsQ0FBQTtJQUUxRCxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDbkIsT0FBTyxDQUFDLElBQUksQ0FBQyx3RUFBd0UsQ0FBQyxDQUFBO1FBQ3RGLE9BQU8sRUFBRSxDQUFBO0lBQ1gsQ0FBQztJQUVELE1BQU0sTUFBTSxHQUFHLGFBQXVCLENBQUE7SUFFdEM7OztPQUdHO0lBQ0gsS0FBSyxVQUFVLGNBQWM7UUFDM0IsSUFBSSxDQUFDO1lBQ0gsTUFBTSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUE7WUFDcEMsTUFBTSxJQUFJLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFxQixDQUFBO1lBQ3JELE9BQU87Z0JBQ0wsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHLElBQUksRUFBRTtnQkFDbkIsS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLElBQUksRUFBRTtnQkFDdkIsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLGdCQUFnQjthQUN4QyxDQUFBO1FBQ0gsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLE9BQU8sSUFBSSxDQUFBO1FBQ2IsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssVUFBVSxxQkFBcUI7UUFDbEMsSUFBSSxDQUFDO1lBQ0gsTUFBTSxLQUFL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SSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUM7Z0JBQUUsT0FBTTtZQUVsRCxNQUFNLE1BQU0sR0FBRyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQTtZQUMxQyxRQUFRLENBQUMsSUFBSSxHQUFHLE1BQU0sR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFBO1lBRXRDLElBQUksT0FBTyxDQUFDLGdCQUFnQixFQUFFLE1BQU0sRUFBRSxDQUFDO2dCQUNyQyxNQUFNLHFCQUFxQixFQUFFLENBQUE7WUFDL0IsQ0FBQztRQUNILENBQUM7S0FDRixDQUFBO0FBQ0gsQ0FBQyxDQUFBO0FBRUQsZUFBZSxpQkFBaUIsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGZpbGVvdmVydmlldyBPcGVuQ29kZSDpobXpnaLkuIrkuIvmlofmj5Lku7ZcbiAqIEBkZXNjcmlwdGlvbiDnlKjkuo7lsIbpobXpnaLkuIrkuIvmlofkv6Hmga/ms6jlhaXliLAgQUkg5a+56K+d5LitXG4gKi9cblxuaW1wb3J0IHR5cGUgeyBQbHVnaW4sIEhvb2tzIH0gZnJvbSBcIkBvcGVuY29kZS1haS9wbHVnaW5cIlxuXG4vKiog5pyA5aSn5paH5pys6ZW/5bqmICovXG5jb25zdCBNQVhfVEVYVF9MRU5HVEggPSAxMDAwMFxuXG4vKiog5LiK5LiL5paH5qCH6K6wICovXG5jb25zdCBDT05URVhUX01BUktFUiA9ICdfX09QRU5DT0RFX0NPTlRFWFRfXydcblxuLyoqXG4gKiDpgInkuK3nmoTlhYPntKDkv6Hmga9cbiAqL1xuaW50ZXJmYWNlIFNlbGVjdGVkRWxlbWVudCB7XG4gIC8qKiDmlofku7bot6/lvoQgKi9cbiAgZmlsZVBhdGg6IHN0cmluZyB8IG51bGxcbiAgLyoqIOihjOWPtyAqL1xuICBsaW5lOiBudW1iZXIgfCBudWxsXG4gIC8qKiDliJflj7cgKi9cbiAgY29sdW1uOiBudW1iZXIgfCBudWxsXG4gIC8qKiDlhYPntKDlhoXpg6jmlofmnKwgKi9cbiAgaW5uZXJUZXh0OiBzdHJpbmdcbn1cblxuLyoqXG4gKiDpobXpnaLkuIrkuIvmlofmlbDmja5cbiAqL1xuaW50ZXJmYWNlIFBhZ2VDb250ZXh0RGF0YSB7XG4gIC8qKiDlvZPliY3pobXpnaIgVVJMICovXG4gIHVybDogc3RyaW5nXG4gIC8qKiDlvZPliY3pobXpnaLmoIfpopggKi9cbiAgdGl0bGU6IHN0cmluZ1xuICAvKiog6YCJ5Lit55qE5YWD57Sg5YiX6KGoICovXG4gIHNlbGVjdGVkRWxlbWVudHM/OiBTZWxlY3RlZEVsZW1lbnRbXVxufVxuXG4vKipcbiAqIE9wZW5Db2RlIOmhtemdouS4iuS4i+aWh+aPkuS7tlxuICogQHJldHVybnMg5o+S5Lu26ZKp5a2QXG4gKiBAZXhhbXBsZVxuICogYGBgdHNcbiAqIC8vIOWcqCBvcGVuY29kZSDphY3nva7kuK3kvb/nlKhcbiAqIGltcG9ydCB7IFBhZ2VDb250ZXh0UGx1Z2luIH0gZnJvbSAnLi9wbHVnaW5zL3BhZ2UtY29udGV4dCdcbiAqXG4gKiBleHBvcnQgZGVmYXVsdCB7XG4gKiAgIHBsdWdpbnM6IFtQYWdlQ29udGV4dFBsdWdpbl1cbiAqIH1cbiAqIGBgYFxuICovXG5leHBvcnQgY29uc3QgUGFnZUNvbnRleHRQbHVnaW46IFBsdWdpbiA9IGFzeW5jICgpOiBQcm9taXNlPEhvb2tzPiA9PiB7XG4gIGNvbnN0IGNvbnRleHRBcGlVcmwgPSBwcm9jZXNzLmVudi5PUEVOQ09ERV9DT05URVhUX0FQSV9VUkxcblxuICBpZiAoIWNvbnRleHRBcGlVcmwpIHtcbiAgICBjb25zb2xlLndhcm4oJ09QRU5DT0RFX0NPTlRFWFRfQVBJX1VSTCBpcyBub3Qgc2V0LCBwYWdlIGNvbnRleHQgcGx1Z2luIHdpbGwgbm90IHdvcmsnKVxuICAgIHJldHVybiB7fVxuICB9XG5cbiAgY29uc3QgYXBpVXJsID0gY29udGV4dEFwaVVybCBhcyBzdHJpbmdcblxuICAvKipcbiAgICog6I635Y+W6aG16Z2i5LiK5LiL5paHXG4gICAqIEByZXR1cm5zIOmhtemdouS4iuS4i+aWh+aVsOaNru+8jOiOt+WPluWksei0peaXtui/lOWbniBudWxsXG4gICAqL1xuICBhc3luYyBmdW5jdGlvbiBnZXRQYWdlQ29udGV4dCgpOiBQcm9taXNlPFBhZ2VDb250ZXh0RGF0YSB8IG51bGw+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChhcGlVcmwpXG4gICAgICBjb25zdCBkYXRhID0gYXdhaXQgcmVzcG9uc2UuanNvbigpIGFzIFBhZ2VDb250ZXh0RGF0YVxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdXJsOiBkYXRhLnVybCB8fCBcIlwiLFxuICAgICAgICB0aXRsZTogZGF0YS50aXRsZSB8fCBcIlwiLFxuICAgICAgICBzZWxlY3RlZEVsZW1lbnRzOiBkYXRhLnNlbGVjdGVkRWxlbWVudHNcbiAgICAgIH1cbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBudWxsXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIOa4hemZpOmAieS4reeahOWFg+e0oFxuICAgKi9cbiAgYXN5bmMgZnVuY3Rpb24gY2xlYXJTZWxlY3RlZEVsZW1lbnRzKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBmZXRjaChhcGlVcmwsIHsgbWV0aG9kOiAnREVMRVRFJyB9KVxuICAgIH0gY2F0Y2gge1xuICAgICAgLy8g5b+955Wl6ZSZ6K+vXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIOagvOW8j+WMlumAieS4reWFg+e0oOS/oeaBr1xuICAgKiBAcGFyYW0gZWxlbWVudCAtIOmAieS4reeahOWFg+e0oFxuICAgKiBAcmV0dXJucyDmoLzlvI/ljJblkI7nmoTlhYPntKDkv6Hmga/lrZfnrKbkuLJcbiAgICovXG4gIGZ1bmN0aW9uIGZvcm1hdFNlbGVjdGVkRWxlbWVudChlbGVtZW50OiBTZWxlY3RlZEVsZW1lbnQpOiBzdHJpbmcge1xuICAgIGNvbnN0IHBhcnRzOiBzdHJpbmdbXSA9IFtdXG5cbiAgICBpZiAoZWxlbWVudC5maWxlUGF0aCkge1xuICAgICAgbGV0IGxvY2F0aW9uID0gYOaWh+S7tjogJHtlbGVtZW50LmZpbGVQYXRofWBcbiAgICAgIGlmIChlbGVtZW50LmxpbmUpIHtcbiAgICAgICAgbG9jYXRpb24gKz0gYDoke2VsZW1lbnQubGluZX1gXG4gICAgICAgIGlmIChlbGVtZW50LmNvbHVtbikge1xuICAgICAgICAgIGxvY2F0aW9uICs9IGA6JHtlbGVtZW50LmNvbHVtbn1gXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHBhcnRzLnB1c2gobG9jYXRpb24pXG4gICAgfVxuXG4gICAgaWYgKGVsZW1lbnQuaW5uZXJUZXh0Py50cmltKCkpIHtcbiAgICAgIGNvbnN0IHRleHQgPSBlbGVtZW50LmlubmVyVGV4dC50cmltKCkuc3Vic3RyaW5nKDAsIE1BWF9URVhUX0xFTkdUSClcbiAgICAgIGNvbnN0IHN1ZmZpeCA9IGVsZW1lbnQuaW5uZXJUZXh0Lmxlbmd0aCA+IE1BWF9URVhUX0xFTkdUSCA/ICcuLi4nIDogJydcbiAgICAgIHBhcnRzLnB1c2goYOiKgueCueaWh+acrDogXCIke3RleHR9JHtzdWZmaXh9XCJgKVxuICAgIH1cblxuICAgIHJldHVybiBwYXJ0cy5qb2luKCdcXG4nKSArICdcXG4nXG4gIH1cblxuICAvKipcbiAgICog5p6E5bu65LiK5LiL5paH5YmN57yAXG4gICAqIEBwYXJhbSBjb250ZXh0IC0g6aG16Z2i5LiK5LiL5paHXG4gICAqIEByZXR1cm5zIOS4iuS4i+aWh+WJjee8gOWtl+espuS4slxuICAgKi9cbiAgZnVuY3Rpb24gYnVpbGRDb250ZXh0UHJlZml4KGNvbnRleHQ6IFBhZ2VDb250ZXh0RGF0YSk6IHN0cmluZyB7XG4gICAgbGV0IHByZWZpeCA9IGDmiJHnjrDlnKjmraPlnKjmtY/op4jov5nkuKrpobXpnaLvvJoke2NvbnRleHQudXJsfVxcblxcbmBcblxuICAgIGlmIChjb250ZXh0LnNlbGVjdGVkRWxlbWVudHM/Lmxlbmd0aCkge1xuICAgICAgcHJlZml4ICs9IGDluK7miJHmib7liLDku6XkuIvoioLngrnvvIzkuIDlrpropoHnsr7noa7liLDlhbfkvZPnmoToioLngrnvvJpcXG5cXG5gXG4gICAgICBjb250ZXh0LnNlbGVjdGVkRWxlbWVudHMuZm9yRWFjaCgoZWxlbWVudCkgPT4ge1xuICAgICAgICBwcmVmaXggKz0gZm9ybWF0U2VsZWN0ZWRFbGVtZW50KGVsZW1lbnQpICsgXCJcXG5cIlxuICAgICAgfSlcbiAgICB9XG5cbiAgICBwcmVmaXggKz0gYOivt+agueaNruS7peS4iuS/oeaBr++8jOWujOaIkOS7peS4i+S7u+WKoe+8mlxcbmBcblxuICAgIHByZWZpeCArPSBgXFxuYFxuICAgIHJldHVybiBwcmVmaXhcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgXCJleHBlcmltZW50YWwuY2hhdC5tZXNzYWdlcy50cmFuc2Zvcm1cIjogYXN5bmMgKF9pbnB1dCwgb3V0cHV0KSA9PiB7XG4gICAgICBjb25zdCBjb250ZXh0ID0gYXdhaXQgZ2V0UGFnZUNvbnRleHQoKVxuICAgICAgXG4gICAgICBpZiAoIWNvbnRleHQ/LnVybCkgcmV0dXJuXG5cbiAgICAgIGNvbnN0IGxhc3RVc2VyTXNnID0gWy4uLm91dHB1dC5tZXNzYWdlc10ucmV2ZXJzZSgpLmZpbmQobSA9PiBtLmluZm8ucm9sZSA9PT0gXCJ1c2VyXCIpXG4gICAgICBpZiAoIWxhc3RVc2VyTXNnKSByZXR1cm5cblxuICAgICAgY29uc3QgdGV4dFBhcnQgPSBsYXN0VXNlck1zZy5wYXJ0cy5maW5kKHAgPT4gcC50eXBlID09PSBcInRleHRcIilcbiAgICAgIGlmICghdGV4dFBhcnQgfHwgIShcInRleHRcIiBpbiB0ZXh0UGFydCkpIHJldHVyblxuICAgICAgXG4gICAgICBpZiAodGV4dFBhcnQudGV4dC5pbmNsdWRlcyhDT05URVhUX01BUktFUikpIHJldHVyblxuXG4gICAgICBjb25zdCBwcmVmaXggPSBidWlsZENvbnRleHRQcmVmaXgoY29udGV4dClcbiAgICAgIHRleHRQYXJ0LnRleHQgPSBwcmVmaXggKyB0ZXh0UGFydC50ZXh0XG5cbiAgICAgIGlmIChjb250ZXh0LnNlbGVjdGVkRWxlbWVudHM/Lmxlbmd0aCkge1xuICAgICAgICBhd2FpdCBjbGVhclNlbGVjdGVkRWxlbWVudHMoKVxuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBQYWdlQ29udGV4dFBsdWdpblxuIl19
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode Vite 插件配置选项
|
|
3
|
+
*/
|
|
4
|
+
export interface OpenCodeOptions {
|
|
5
|
+
/** 是否启用插件,默认 true */
|
|
6
|
+
enabled?: boolean;
|
|
7
|
+
/** @deprecated 使用 webPort 代替 */
|
|
8
|
+
serverPort?: number;
|
|
9
|
+
/** Web 服务端口,默认 4097 */
|
|
10
|
+
webPort?: number;
|
|
11
|
+
/** 服务主机名,默认 '127.0.0.1' */
|
|
12
|
+
hostname?: string;
|
|
13
|
+
/** 挂件位置,默认 'bottom-right' */
|
|
14
|
+
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
15
|
+
/** 主题模式,默认 'auto' */
|
|
16
|
+
theme?: 'light' | 'dark' | 'auto';
|
|
17
|
+
/** 是否自动打开面板,默认 false */
|
|
18
|
+
open?: boolean;
|
|
19
|
+
/** 是否自动重载,默认 true */
|
|
20
|
+
autoReload?: boolean;
|
|
21
|
+
/** 是否输出详细日志,默认 false */
|
|
22
|
+
verbose?: boolean;
|
|
23
|
+
/** 是否懒加载服务,默认 false */
|
|
24
|
+
lazy?: boolean;
|
|
25
|
+
/** 快捷键配置,默认 'ctrl+k' */
|
|
26
|
+
hotkey?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* OpenCode Web 服务启动选项
|
|
30
|
+
*/
|
|
31
|
+
export interface WebOptions {
|
|
32
|
+
/** 服务端口 */
|
|
33
|
+
port: number;
|
|
34
|
+
/** 服务主机名 */
|
|
35
|
+
hostname: string;
|
|
36
|
+
/** 服务器 URL */
|
|
37
|
+
serverUrl: string;
|
|
38
|
+
/** 工作目录 */
|
|
39
|
+
cwd: string;
|
|
40
|
+
/** 配置目录路径 */
|
|
41
|
+
configDir?: string;
|
|
42
|
+
/** CORS 允许的源 */
|
|
43
|
+
corsOrigins?: string[];
|
|
44
|
+
/** 上下文 API URL */
|
|
45
|
+
contextApiUrl?: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 挂件注入配置选项
|
|
49
|
+
*/
|
|
50
|
+
export interface WidgetOptions {
|
|
51
|
+
/** Web 服务 URL */
|
|
52
|
+
webUrl: string;
|
|
53
|
+
/** 服务器 URL */
|
|
54
|
+
serverUrl: string;
|
|
55
|
+
/** 挂件位置 */
|
|
56
|
+
position: string;
|
|
57
|
+
/** 主题模式 */
|
|
58
|
+
theme: string;
|
|
59
|
+
/** 是否自动打开 */
|
|
60
|
+
open: boolean;
|
|
61
|
+
/** 是否自动重载 */
|
|
62
|
+
autoReload: boolean;
|
|
63
|
+
/** 工作目录 */
|
|
64
|
+
cwd: string;
|
|
65
|
+
/** 会话 URL */
|
|
66
|
+
sessionUrl?: string;
|
|
67
|
+
/** 是否懒加载 */
|
|
68
|
+
lazy?: boolean;
|
|
69
|
+
/** 快捷键配置 */
|
|
70
|
+
hotkey?: string;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* OpenCode 会话信息
|
|
74
|
+
*/
|
|
75
|
+
export interface SessionInfo {
|
|
76
|
+
/** 会话 ID */
|
|
77
|
+
id: string;
|
|
78
|
+
/** 会话标识符 */
|
|
79
|
+
slug: string;
|
|
80
|
+
/** 项目 ID */
|
|
81
|
+
projectID: string;
|
|
82
|
+
/** 项目目录 */
|
|
83
|
+
directory: string;
|
|
84
|
+
/** 会话标题 */
|
|
85
|
+
title: string;
|
|
86
|
+
/** 版本号 */
|
|
87
|
+
version: string;
|
|
88
|
+
/** 代码变更统计 */
|
|
89
|
+
summary: {
|
|
90
|
+
/** 新增行数 */
|
|
91
|
+
additions: number;
|
|
92
|
+
/** 删除行数 */
|
|
93
|
+
deletions: number;
|
|
94
|
+
/** 修改文件数 */
|
|
95
|
+
files: number;
|
|
96
|
+
};
|
|
97
|
+
/** 时间信息 */
|
|
98
|
+
time: {
|
|
99
|
+
/** 创建时间戳 */
|
|
100
|
+
created: number;
|
|
101
|
+
/** 更新时间戳 */
|
|
102
|
+
updated: number;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 选中的元素信息
|
|
107
|
+
*/
|
|
108
|
+
export interface SelectedElement {
|
|
109
|
+
/** 文件路径 */
|
|
110
|
+
filePath: string | null;
|
|
111
|
+
/** 行号 */
|
|
112
|
+
line: number | null;
|
|
113
|
+
/** 列号 */
|
|
114
|
+
column: number | null;
|
|
115
|
+
/** 元素内部文本 */
|
|
116
|
+
innerText: string;
|
|
117
|
+
/** 元素描述(标签名+选择器) */
|
|
118
|
+
description?: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* 页面上下文数据
|
|
122
|
+
*/
|
|
123
|
+
export interface PageContext {
|
|
124
|
+
/** 当前页面 URL */
|
|
125
|
+
url: string;
|
|
126
|
+
/** 当前页面标题 */
|
|
127
|
+
title: string;
|
|
128
|
+
/** 选中的元素列表 */
|
|
129
|
+
selectedElements?: SelectedElement[];
|
|
130
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogT3BlbkNvZGUgVml0ZSDmj5Lku7bphY3nva7pgInpoblcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBPcGVuQ29kZU9wdGlvbnMge1xuICAvKiog5piv5ZCm5ZCv55So5o+S5Lu277yM6buY6K6kIHRydWUgKi9cbiAgZW5hYmxlZD86IGJvb2xlYW5cbiAgLyoqIEBkZXByZWNhdGVkIOS9v+eUqCB3ZWJQb3J0IOS7o+abvyAqL1xuICBzZXJ2ZXJQb3J0PzogbnVtYmVyXG4gIC8qKiBXZWIg5pyN5Yqh56uv5Y+j77yM6buY6K6kIDQwOTcgKi9cbiAgd2ViUG9ydD86IG51bWJlclxuICAvKiog5pyN5Yqh5Li75py65ZCN77yM6buY6K6kICcxMjcuMC4wLjEnICovXG4gIGhvc3RuYW1lPzogc3RyaW5nXG4gIC8qKiDmjILku7bkvY3nva7vvIzpu5jorqQgJ2JvdHRvbS1yaWdodCcgKi9cbiAgcG9zaXRpb24/OiAnYm90dG9tLXJpZ2h0JyB8ICdib3R0b20tbGVmdCcgfCAndG9wLXJpZ2h0JyB8ICd0b3AtbGVmdCdcbiAgLyoqIOS4u+mimOaooeW8j++8jOm7mOiupCAnYXV0bycgKi9cbiAgdGhlbWU/OiAnbGlnaHQnIHwgJ2RhcmsnIHwgJ2F1dG8nXG4gIC8qKiDmmK/lkKboh6rliqjmiZPlvIDpnaLmnb/vvIzpu5jorqQgZmFsc2UgKi9cbiAgb3Blbj86IGJvb2xlYW5cbiAgLyoqIOaYr+WQpuiHquWKqOmHjei9ve+8jOm7mOiupCB0cnVlICovXG4gIGF1dG9SZWxvYWQ/OiBib29sZWFuXG4gIC8qKiDmmK/lkKbovpPlh7ror6bnu4bml6Xlv5fvvIzpu5jorqQgZmFsc2UgKi9cbiAgdmVyYm9zZT86IGJvb2xlYW5cbiAgLyoqIOaYr+WQpuaHkuWKoOi9veacjeWKoe+8jOm7mOiupCBmYWxzZSAqL1xuICBsYXp5PzogYm9vbGVhblxuICAvKiog5b+r5o236ZSu6YWN572u77yM6buY6K6kICdjdHJsK2snICovXG4gIGhvdGtleT86IHN0cmluZ1xufVxuXG4vKipcbiAqIE9wZW5Db2RlIFdlYiDmnI3liqHlkK/liqjpgInpoblcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBXZWJPcHRpb25zIHtcbiAgLyoqIOacjeWKoeerr+WPoyAqL1xuICBwb3J0OiBudW1iZXJcbiAgLyoqIOacjeWKoeS4u+acuuWQjSAqL1xuICBob3N0bmFtZTogc3RyaW5nXG4gIC8qKiDmnI3liqHlmaggVVJMICovXG4gIHNlcnZlclVybDogc3RyaW5nXG4gIC8qKiDlt6XkvZznm67lvZUgKi9cbiAgY3dkOiBzdHJpbmdcbiAgLyoqIOmFjee9ruebruW9lei3r+W+hCAqL1xuICBjb25maWdEaXI/OiBzdHJpbmdcbiAgLyoqIENPUlMg5YWB6K6455qE5rqQICovXG4gIGNvcnNPcmlnaW5zPzogc3RyaW5nW11cbiAgLyoqIOS4iuS4i+aWhyBBUEkgVVJMICovXG4gIGNvbnRleHRBcGlVcmw/OiBzdHJpbmdcbn1cblxuLyoqXG4gKiDmjILku7bms6jlhaXphY3nva7pgInpoblcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBXaWRnZXRPcHRpb25zIHtcbiAgLyoqIFdlYiDmnI3liqEgVVJMICovXG4gIHdlYlVybDogc3RyaW5nXG4gIC8qKiDmnI3liqHlmaggVVJMICovXG4gIHNlcnZlclVybDogc3RyaW5nXG4gIC8qKiDmjILku7bkvY3nva4gKi9cbiAgcG9zaXRpb246IHN0cmluZ1xuICAvKiog5Li76aKY5qih5byPICovXG4gIHRoZW1lOiBzdHJpbmdcbiAgLyoqIOaYr+WQpuiHquWKqOaJk+W8gCAqL1xuICBvcGVuOiBib29sZWFuXG4gIC8qKiDmmK/lkKboh6rliqjph43ovb0gKi9cbiAgYXV0b1JlbG9hZDogYm9vbGVhblxuICAvKiog5bel5L2c55uu5b2VICovXG4gIGN3ZDogc3RyaW5nXG4gIC8qKiDkvJror50gVVJMICovXG4gIHNlc3Npb25Vcmw/OiBzdHJpbmdcbiAgLyoqIOaYr+WQpuaHkuWKoOi9vSAqL1xuICBsYXp5PzogYm9vbGVhblxuICAvKiog5b+r5o236ZSu6YWN572uICovXG4gIGhvdGtleT86IHN0cmluZ1xufVxuXG4vKipcbiAqIE9wZW5Db2RlIOS8muivneS/oeaBr1xuICovXG5leHBvcnQgaW50ZXJmYWNlIFNlc3Npb25JbmZvIHtcbiAgLyoqIOS8muivnSBJRCAqL1xuICBpZDogc3RyaW5nXG4gIC8qKiDkvJror53moIfor4bnrKYgKi9cbiAgc2x1Zzogc3RyaW5nXG4gIC8qKiDpobnnm64gSUQgKi9cbiAgcHJvamVjdElEOiBzdHJpbmdcbiAgLyoqIOmhueebruebruW9lSAqL1xuICBkaXJlY3Rvcnk6IHN0cmluZ1xuICAvKiog5Lya6K+d5qCH6aKYICovXG4gIHRpdGxlOiBzdHJpbmdcbiAgLyoqIOeJiOacrOWPtyAqL1xuICB2ZXJzaW9uOiBzdHJpbmdcbiAgLyoqIOS7o+eggeWPmOabtOe7n+iuoSAqL1xuICBzdW1tYXJ5OiB7XG4gICAgLyoqIOaWsOWinuihjOaVsCAqL1xuICAgIGFkZGl0aW9uczogbnVtYmVyXG4gICAgLyoqIOWIoOmZpOihjOaVsCAqL1xuICAgIGRlbGV0aW9uczogbnVtYmVyXG4gICAgLyoqIOS/ruaUueaWh+S7tuaVsCAqL1xuICAgIGZpbGVzOiBudW1iZXJcbiAgfVxuICAvKiog5pe26Ze05L+h5oGvICovXG4gIHRpbWU6IHtcbiAgICAvKiog5Yib5bu65pe26Ze05oizICovXG4gICAgY3JlYXRlZDogbnVtYmVyXG4gICAgLyoqIOabtOaWsOaXtumXtOaIsyAqL1xuICAgIHVwZGF0ZWQ6IG51bWJlclxuICB9XG59XG5cbi8qKlxuICog6YCJ5Lit55qE5YWD57Sg5L+h5oGvXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2VsZWN0ZWRFbGVtZW50IHtcbiAgLyoqIOaWh+S7tui3r+W+hCAqL1xuICBmaWxlUGF0aDogc3RyaW5nIHwgbnVsbFxuICAvKiog6KGM5Y+3ICovXG4gIGxpbmU6IG51bWJlciB8IG51bGxcbiAgLyoqIOWIl+WPtyAqL1xuICBjb2x1bW46IG51bWJlciB8IG51bGxcbiAgLyoqIOWFg+e0oOWGhemDqOaWh+acrCAqL1xuICBpbm5lclRleHQ6IHN0cmluZ1xuICAvKiog5YWD57Sg5o+P6L+w77yI5qCH562+5ZCNK+mAieaLqeWZqO+8iSAqL1xuICBkZXNjcmlwdGlvbj86IHN0cmluZ1xufVxuXG4vKipcbiAqIOmhtemdouS4iuS4i+aWh+aVsOaNrlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFBhZ2VDb250ZXh0IHtcbiAgLyoqIOW9k+WJjemhtemdoiBVUkwgKi9cbiAgdXJsOiBzdHJpbmdcbiAgLyoqIOW9k+WJjemhtemdouagh+mimCAqL1xuICB0aXRsZTogc3RyaW5nXG4gIC8qKiDpgInkuK3nmoTlhYPntKDliJfooaggKi9cbiAgc2VsZWN0ZWRFbGVtZW50cz86IFNlbGVjdGVkRWxlbWVudFtdXG59XG4iXX0=
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 等待服务器就绪
|
|
3
|
+
* @param url - 服务器 URL
|
|
4
|
+
* @param timeout - 超时时间(毫秒),默认 10000
|
|
5
|
+
* @returns Promise,服务器就绪时 resolve
|
|
6
|
+
* @throws 超时后抛出错误
|
|
7
|
+
*/
|
|
8
|
+
export declare function waitForServer(url: string, timeout?: number): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* 检查 OpenCode 是否已安装
|
|
11
|
+
* @returns 是否已安装
|
|
12
|
+
*/
|
|
13
|
+
export declare function checkOpenCodeInstalled(): Promise<boolean>;
|
|
14
|
+
/**
|
|
15
|
+
* 检查端口是否可用
|
|
16
|
+
* @param port - 端口号
|
|
17
|
+
* @param hostname - 主机名,默认 '127.0.0.1'
|
|
18
|
+
* @returns 端口是否可用
|
|
19
|
+
*/
|
|
20
|
+
export declare function isPortAvailable(port: number, hostname?: string): Promise<boolean>;
|
|
21
|
+
/**
|
|
22
|
+
* 查找可用端口
|
|
23
|
+
* @param startPort - 起始端口
|
|
24
|
+
* @param hostname - 主机名,默认 '127.0.0.1'
|
|
25
|
+
* @param maxTries - 最大尝试次数,默认 10
|
|
26
|
+
* @returns 可用的端口号
|
|
27
|
+
* @throws 找不到可用端口时抛出错误
|
|
28
|
+
*/
|
|
29
|
+
export declare function findAvailablePort(startPort: number, hostname?: string, maxTries?: number): Promise<number>;
|
|
30
|
+
/**
|
|
31
|
+
* 终止占用指定端口的进程
|
|
32
|
+
* @param port - 端口号
|
|
33
|
+
* @param hostname - 主机名,默认 '127.0.0.1'
|
|
34
|
+
* @returns 是否成功终止进程
|
|
35
|
+
*/
|
|
36
|
+
export declare function killProcessOnPort(port: number, hostname?: string): Promise<boolean>;
|
|
37
|
+
/**
|
|
38
|
+
* 检查 OpenCode 进程是否在运行
|
|
39
|
+
* @param port - 服务端口
|
|
40
|
+
* @returns 进程是否在运行
|
|
41
|
+
*/
|
|
42
|
+
export declare function checkOpenCodeProcess(port: number): Promise<boolean>;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import http from 'http';
|
|
2
|
+
import { spawn } from 'child_process';
|
|
3
|
+
import net from 'net';
|
|
4
|
+
import { DEFAULT_HOSTNAME, SERVER_CHECK_INTERVAL, HEALTH_CHECK_TIMEOUT, MAX_PORT_TRIES, } from './constants';
|
|
5
|
+
/**
|
|
6
|
+
* 等待服务器就绪
|
|
7
|
+
* @param url - 服务器 URL
|
|
8
|
+
* @param timeout - 超时时间(毫秒),默认 10000
|
|
9
|
+
* @returns Promise,服务器就绪时 resolve
|
|
10
|
+
* @throws 超时后抛出错误
|
|
11
|
+
*/
|
|
12
|
+
export function waitForServer(url, timeout = 10000) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
const startTime = Date.now();
|
|
15
|
+
const check = () => {
|
|
16
|
+
const req = http.get(url, (res) => {
|
|
17
|
+
if (res.statusCode && res.statusCode < 500) {
|
|
18
|
+
resolve();
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
retryOrReject();
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
req.on('error', retryOrReject);
|
|
25
|
+
};
|
|
26
|
+
const retryOrReject = () => {
|
|
27
|
+
if (Date.now() - startTime < timeout) {
|
|
28
|
+
setTimeout(check, SERVER_CHECK_INTERVAL);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
reject(new Error(`Server not ready after ${timeout}ms`));
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
check();
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 检查 OpenCode 是否已安装
|
|
39
|
+
* @returns 是否已安装
|
|
40
|
+
*/
|
|
41
|
+
export async function checkOpenCodeInstalled() {
|
|
42
|
+
return new Promise((resolve) => {
|
|
43
|
+
const proc = spawn('opencode', ['--version'], { stdio: 'ignore' });
|
|
44
|
+
proc.on('close', (code) => resolve(code === 0));
|
|
45
|
+
proc.on('error', () => resolve(false));
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 检查端口是否可用
|
|
50
|
+
* @param port - 端口号
|
|
51
|
+
* @param hostname - 主机名,默认 '127.0.0.1'
|
|
52
|
+
* @returns 端口是否可用
|
|
53
|
+
*/
|
|
54
|
+
export async function isPortAvailable(port, hostname = DEFAULT_HOSTNAME) {
|
|
55
|
+
return new Promise((resolve) => {
|
|
56
|
+
const server = net.createServer();
|
|
57
|
+
server.once('error', () => resolve(false));
|
|
58
|
+
server.once('listening', () => {
|
|
59
|
+
server.close();
|
|
60
|
+
resolve(true);
|
|
61
|
+
});
|
|
62
|
+
server.listen(port, hostname);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 查找可用端口
|
|
67
|
+
* @param startPort - 起始端口
|
|
68
|
+
* @param hostname - 主机名,默认 '127.0.0.1'
|
|
69
|
+
* @param maxTries - 最大尝试次数,默认 10
|
|
70
|
+
* @returns 可用的端口号
|
|
71
|
+
* @throws 找不到可用端口时抛出错误
|
|
72
|
+
*/
|
|
73
|
+
export async function findAvailablePort(startPort, hostname = DEFAULT_HOSTNAME, maxTries = MAX_PORT_TRIES) {
|
|
74
|
+
for (let port = startPort; port < startPort + maxTries; port++) {
|
|
75
|
+
if (await isPortAvailable(port, hostname)) {
|
|
76
|
+
return port;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
throw new Error(`No available port found after ${maxTries} tries starting from ${startPort}`);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 终止占用指定端口的进程
|
|
83
|
+
* @param port - 端口号
|
|
84
|
+
* @param hostname - 主机名,默认 '127.0.0.1'
|
|
85
|
+
* @returns 是否成功终止进程
|
|
86
|
+
*/
|
|
87
|
+
export async function killProcessOnPort(port, hostname = DEFAULT_HOSTNAME) {
|
|
88
|
+
return new Promise((resolve) => {
|
|
89
|
+
if (process.platform === 'win32') {
|
|
90
|
+
killProcessOnWindows(port, resolve);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
killProcessOnUnix(port, resolve);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 在 Windows 上终止占用端口的进程
|
|
99
|
+
*/
|
|
100
|
+
function killProcessOnWindows(port, resolve) {
|
|
101
|
+
const proc = spawn('cmd', ['/c', `netstat -ano | findstr :${port}`], { stdio: 'pipe' });
|
|
102
|
+
let output = '';
|
|
103
|
+
proc.stdout?.on('data', (data) => {
|
|
104
|
+
output += data.toString();
|
|
105
|
+
});
|
|
106
|
+
proc.on('close', () => {
|
|
107
|
+
const match = output.match(/LISTENING\s+(\d+)/);
|
|
108
|
+
if (match) {
|
|
109
|
+
spawn('taskkill', ['/F', '/PID', match[1]], { stdio: 'ignore' })
|
|
110
|
+
.on('close', (code) => resolve(code === 0));
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
resolve(false);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* 在 Unix 系统上终止占用端口的进程
|
|
119
|
+
*/
|
|
120
|
+
function killProcessOnUnix(port, resolve) {
|
|
121
|
+
const proc = spawn('lsof', ['-ti', `tcp:${port}`, '-sTCP:LISTEN'], { stdio: 'pipe' });
|
|
122
|
+
let output = '';
|
|
123
|
+
proc.stdout?.on('data', (data) => {
|
|
124
|
+
output += data.toString();
|
|
125
|
+
});
|
|
126
|
+
proc.on('close', () => {
|
|
127
|
+
const pids = output.trim().split('\n').filter(Boolean);
|
|
128
|
+
if (pids.length > 0) {
|
|
129
|
+
const killProc = spawn('kill', ['-9', ...pids], { stdio: 'ignore' });
|
|
130
|
+
killProc.on('close', (code) => resolve(code === 0));
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
resolve(false);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* 检查 OpenCode 进程是否在运行
|
|
139
|
+
* @param port - 服务端口
|
|
140
|
+
* @returns 进程是否在运行
|
|
141
|
+
*/
|
|
142
|
+
export async function checkOpenCodeProcess(port) {
|
|
143
|
+
return new Promise((resolve) => {
|
|
144
|
+
const req = http.get({
|
|
145
|
+
hostname: DEFAULT_HOSTNAME,
|
|
146
|
+
port,
|
|
147
|
+
path: '/health',
|
|
148
|
+
timeout: HEALTH_CHECK_TIMEOUT,
|
|
149
|
+
}, (res) => {
|
|
150
|
+
resolve(res.statusCode === 200);
|
|
151
|
+
});
|
|
152
|
+
req.on('error', () => resolve(false));
|
|
153
|
+
req.end();
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBQ3ZCLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxlQUFlLENBQUE7QUFDckMsT0FBTyxHQUFHLE1BQU0sS0FBSyxDQUFBO0FBQ3JCLE9BQU8sRUFDTCxnQkFBZ0IsRUFDaEIscUJBQXFCLEVBQ3JCLG9CQUFvQixFQUNwQixjQUFjLEdBQ2YsTUFBTSxhQUFhLENBQUE7QUFFcEI7Ozs7OztHQU1HO0FBQ0gsTUFBTSxVQUFVLGFBQWEsQ0FBQyxHQUFXLEVBQUUsT0FBTyxHQUFHLEtBQUs7SUFDeEQsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtRQUNyQyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUE7UUFFNUIsTUFBTSxLQUFLLEdBQUcsR0FBUyxFQUFFO1lBQ3ZCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUU7Z0JBQ2hDLElBQUksR0FBRyxDQUFDLFVBQVUsSUFBSSxHQUFHLENBQUMsVUFBVSxHQUFHLEdBQUcsRUFBRSxDQUFDO29CQUMzQyxPQUFPLEVBQUUsQ0FBQTtnQkFDWCxDQUFDO3FCQUFNLENBQUM7b0JBQ04sYUFBYSxFQUFFLENBQUE7Z0JBQ2pCLENBQUM7WUFDSCxDQUFDLENBQUMsQ0FBQTtZQUVGLEdBQUcsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLGFBQWEsQ0FBQyxDQUFBO1FBQ2hDLENBQUMsQ0FBQTtRQUVELE1BQU0sYUFBYSxHQUFHLEdBQVMsRUFBRTtZQUMvQixJQUFJLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLEdBQUcsT0FBTyxFQUFFLENBQUM7Z0JBQ3JDLFVBQVUsQ0FBQyxLQUFLLEVBQUUs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Q0FBQTtRQUNGLEdBQUcsQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFBO1FBQ3JDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQTtJQUNYLENBQUMsQ0FBQyxDQUFBO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBodHRwIGZyb20gJ2h0dHAnXG5pbXBvcnQgeyBzcGF3biB9IGZyb20gJ2NoaWxkX3Byb2Nlc3MnXG5pbXBvcnQgbmV0IGZyb20gJ25ldCdcbmltcG9ydCB7XG4gIERFRkFVTFRfSE9TVE5BTUUsXG4gIFNFUlZFUl9DSEVDS19JTlRFUlZBTCxcbiAgSEVBTFRIX0NIRUNLX1RJTUVPVVQsXG4gIE1BWF9QT1JUX1RSSUVTLFxufSBmcm9tICcuL2NvbnN0YW50cydcblxuLyoqXG4gKiDnrYnlvoXmnI3liqHlmajlsLHnu6pcbiAqIEBwYXJhbSB1cmwgLSDmnI3liqHlmaggVVJMXG4gKiBAcGFyYW0gdGltZW91dCAtIOi2heaXtuaXtumXtO+8iOavq+enku+8ie+8jOm7mOiupCAxMDAwMFxuICogQHJldHVybnMgUHJvbWlzZe+8jOacjeWKoeWZqOWwsee7quaXtiByZXNvbHZlXG4gKiBAdGhyb3dzIOi2heaXtuWQjuaKm+WHuumUmeivr1xuICovXG5leHBvcnQgZnVuY3Rpb24gd2FpdEZvclNlcnZlcih1cmw6IHN0cmluZywgdGltZW91dCA9IDEwMDAwKTogUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKVxuXG4gICAgY29uc3QgY2hlY2sgPSAoKTogdm9pZCA9PiB7XG4gICAgICBjb25zdCByZXEgPSBodHRwLmdldCh1cmwsIChyZXMpID0+IHtcbiAgICAgICAgaWYgKHJlcy5zdGF0dXNDb2RlICYmIHJlcy5zdGF0dXNDb2RlIDwgNTAwKSB7XG4gICAgICAgICAgcmVzb2x2ZSgpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0cnlPclJlamVjdCgpXG4gICAgICAgIH1cbiAgICAgIH0pXG5cbiAgICAgIHJlcS5vbignZXJyb3InLCByZXRyeU9yUmVqZWN0KVxuICAgIH1cblxuICAgIGNvbnN0IHJldHJ5T3JSZWplY3QgPSAoKTogdm9pZCA9PiB7XG4gICAgICBpZiAoRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSA8IHRpbWVvdXQpIHtcbiAgICAgICAgc2V0VGltZW91dChjaGVjaywgU0VSVkVSX0NIRUNLX0lOVEVSVkFMKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihgU2VydmVyIG5vdCByZWFkeSBhZnRlciAke3RpbWVvdXR9bXNgKSlcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjaGVjaygpXG4gIH0pXG59XG5cbi8qKlxuICog5qOA5p+lIE9wZW5Db2RlIOaYr+WQpuW3suWuieijhVxuICogQHJldHVybnMg5piv5ZCm5bey5a6J6KOFXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjaGVja09wZW5Db2RlSW5zdGFsbGVkKCk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICBjb25zdCBwcm9jID0gc3Bhd24oJ29wZW5jb2RlJywgWyctLXZlcnNpb24nXSwgeyBzdGRpbzogJ2lnbm9yZScgfSlcbiAgICBwcm9jLm9uKCdjbG9zZScsIChjb2RlKSA9PiByZXNvbHZlKGNvZGUgPT09IDApKVxuICAgIHByb2Mub24oJ2Vycm9yJywgKCkgPT4gcmVzb2x2ZShmYWxzZSkpXG4gIH0pXG59XG5cbi8qKlxuICog5qOA5p+l56uv5Y+j5piv5ZCm5Y+v55SoXG4gKiBAcGFyYW0gcG9ydCAtIOerr+WPo+WPt1xuICogQHBhcmFtIGhvc3RuYW1lIC0g5Li75py65ZCN77yM6buY6K6kICcxMjcuMC4wLjEnXG4gKiBAcmV0dXJucyDnq6/lj6PmmK/lkKblj6/nlKhcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGlzUG9ydEF2YWlsYWJsZShwb3J0OiBudW1iZXIsIGhvc3RuYW1lID0gREVGQVVMVF9IT1NUTkFNRSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICBjb25zdCBzZXJ2ZXIgPSBuZXQuY3JlYXRlU2VydmVyKClcbiAgICBzZXJ2ZXIub25jZSgnZXJyb3InLCAoKSA9PiByZXNvbHZlKGZhbHNlKSlcbiAgICBzZXJ2ZXIub25jZSgnbGlzdGVuaW5nJywgKCkgPT4ge1xuICAgICAgc2VydmVyLmNsb3NlKClcbiAgICAgIHJlc29sdmUodHJ1ZSlcbiAgICB9KVxuICAgIHNlcnZlci5saXN0ZW4ocG9ydCwgaG9zdG5hbWUpXG4gIH0pXG59XG5cbi8qKlxuICog5p+l5om+5Y+v55So56uv5Y+jXG4gKiBAcGFyYW0gc3RhcnRQb3J0IC0g6LW35aeL56uv5Y+jXG4gKiBAcGFyYW0gaG9zdG5hbWUgLSDkuLvmnLrlkI3vvIzpu5jorqQgJzEyNy4wLjAuMSdcbiAqIEBwYXJhbSBtYXhUcmllcyAtIOacgOWkp+WwneivleasoeaVsO+8jOm7mOiupCAxMFxuICogQHJldHVybnMg5Y+v55So55qE56uv5Y+j5Y+3XG4gKiBAdGhyb3dzIOaJvuS4jeWIsOWPr+eUqOerr+WPo+aXtuaKm+WHuumUmeivr1xuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmluZEF2YWlsYWJsZVBvcnQoXG4gIHN0YXJ0UG9ydDogbnVtYmVyLFxuICBob3N0bmFtZSA9IERFRkFVTFRfSE9TVE5BTUUsXG4gIG1heFRyaWVzID0gTUFYX1BPUlRfVFJJRVNcbik6IFByb21pc2U8bnVtYmVyPiB7XG4gIGZvciAobGV0IHBvcnQgPSBzdGFydFBvcnQ7IHBvcnQgPCBzdGFydFBvcnQgKyBtYXhUcmllczsgcG9ydCsrKSB7XG4gICAgaWYgKGF3YWl0IGlzUG9ydEF2YWlsYWJsZShwb3J0LCBob3N0bmFtZSkpIHtcbiAgICAgIHJldHVybiBwb3J0XG4gICAgfVxuICB9XG4gIHRocm93IG5ldyBFcnJvcihgTm8gYXZhaWxhYmxlIHBvcnQgZm91bmQgYWZ0ZXIgJHttYXhUcmllc30gdHJpZXMgc3RhcnRpbmcgZnJvbSAke3N0YXJ0UG9ydH1gKVxufVxuXG4vKipcbiAqIOe7iOatouWNoOeUqOaMh+Wumuerr+WPo+eahOi/m+eoi1xuICogQHBhcmFtIHBvcnQgLSDnq6/lj6Plj7dcbiAqIEBwYXJhbSBob3N0bmFtZSAtIOS4u+acuuWQje+8jOm7mOiupCAnMTI3LjAuMC4xJ1xuICogQHJldHVybnMg5piv5ZCm5oiQ5Yqf57uI5q2i6L+b56iLXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUHJvY2Vzc09uUG9ydChwb3J0OiBudW1iZXIsIGhvc3RuYW1lID0gREVGQVVMVF9IT1NUTkFNRSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICBpZiAocHJvY2Vzcy5wbGF0Zm9ybSA9PT0gJ3dpbjMyJykge1xuICAgICAga2lsbFByb2Nlc3NPbldpbmRvd3MocG9ydCwgcmVzb2x2ZSlcbiAgICB9IGVsc2Uge1xuICAgICAga2lsbFByb2Nlc3NPblVuaXgocG9ydCwgcmVzb2x2ZSlcbiAgICB9XG4gIH0pXG59XG5cbi8qKlxuICog5ZyoIFdpbmRvd3Mg5LiK57uI5q2i5Y2g55So56uv5Y+j55qE6L+b56iLXG4gKi9cbmZ1bmN0aW9uIGtpbGxQcm9jZXNzT25XaW5kb3dzKHBvcnQ6IG51bWJlciwgcmVzb2x2ZTogKHZhbHVlOiBib29sZWFuKSA9PiB2b2lkKTogdm9pZCB7XG4gIGNvbnN0IHByb2MgPSBzcGF3bignY21kJywgWycvYycsIGBuZXRzdGF0IC1hbm8gfCBmaW5kc3RyIDoke3BvcnR9YF0sIHsgc3RkaW86ICdwaXBlJyB9KVxuICBsZXQgb3V0cHV0ID0gJydcblxuICBwcm9jLnN0ZG91dD8ub24oJ2RhdGEnLCAoZGF0YSkgPT4ge1xuICAgIG91dHB1dCArPSBkYXRhLnRvU3RyaW5nKClcbiAgfSlcblxuICBwcm9jLm9uKCdjbG9zZScsICgpID0+IHtcbiAgICBjb25zdCBtYXRjaCA9IG91dHB1dC5tYXRjaCgvTElTVEVOSU5HXFxzKyhcXGQrKS8pXG4gICAgaWYgKG1hdGNoKSB7XG4gICAgICBzcGF3bigndGFza2tpbGwnLCBbJy9GJywgJy9QSUQnLCBtYXRjaFsxXV0sIHsgc3RkaW86ICdpZ25vcmUnIH0pXG4gICAgICAgIC5vbignY2xvc2UnLCAoY29kZSkgPT4gcmVzb2x2ZShjb2RlID09PSAwKSlcbiAgICB9IGVsc2Uge1xuICAgICAgcmVzb2x2ZShmYWxzZSlcbiAgICB9XG4gIH0pXG59XG5cbi8qKlxuICog5ZyoIFVuaXgg57O757uf5LiK57uI5q2i5Y2g55So56uv5Y+j55qE6L+b56iLXG4gKi9cbmZ1bmN0aW9uIGtpbGxQcm9jZXNzT25Vbml4KHBvcnQ6IG51bWJlciwgcmVzb2x2ZTogKHZhbHVlOiBib29sZWFuKSA9PiB2b2lkKTogdm9pZCB7XG4gIGNvbnN0IHByb2MgPSBzcGF3bignbHNvZicsIFsnLXRpJywgYHRjcDoke3BvcnR9YCwgJy1zVENQOkxJU1RFTiddLCB7IHN0ZGlvOiAncGlwZScgfSlcbiAgbGV0IG91dHB1dCA9ICcnXG5cbiAgcHJvYy5zdGRvdXQ/Lm9uKCdkYXRhJywgKGRhdGEpID0+IHtcbiAgICBvdXRwdXQgKz0gZGF0YS50b1N0cmluZygpXG4gIH0pXG5cbiAgcHJvYy5vbignY2xvc2UnLCAoKSA9PiB7XG4gICAgY29uc3QgcGlkcyA9IG91dHB1dC50cmltKCkuc3BsaXQoJ1xcbicpLmZpbHRlcihCb29sZWFuKVxuICAgIGlmIChwaWRzLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IGtpbGxQcm9jID0gc3Bhd24oJ2tpbGwnLCBbJy05JywgLi4ucGlkc10sIHsgc3RkaW86ICdpZ25vcmUnIH0pXG4gICAgICBraWxsUHJvYy5vbignY2xvc2UnLCAoY29kZSkgPT4gcmVzb2x2ZShjb2RlID09PSAwKSlcbiAgICB9IGVsc2Uge1xuICAgICAgcmVzb2x2ZShmYWxzZSlcbiAgICB9XG4gIH0pXG59XG5cbi8qKlxuICog5qOA5p+lIE9wZW5Db2RlIOi/m+eoi+aYr+WQpuWcqOi/kOihjFxuICogQHBhcmFtIHBvcnQgLSDmnI3liqHnq6/lj6NcbiAqIEByZXR1cm5zIOi/m+eoi+aYr+WQpuWcqOi/kOihjFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2hlY2tPcGVuQ29kZVByb2Nlc3MocG9ydDogbnVtYmVyKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgIGNvbnN0IHJlcSA9IGh0dHAuZ2V0KHtcbiAgICAgIGhvc3RuYW1lOiBERUZBVUxUX0hPU1ROQU1FLFxuICAgICAgcG9ydCxcbiAgICAgIHBhdGg6ICcvaGVhbHRoJyxcbiAgICAgIHRpbWVvdXQ6IEhFQUxUSF9DSEVDS19USU1FT1VULFxuICAgIH0sIChyZXMpID0+IHtcbiAgICAgIHJlc29sdmUocmVzLnN0YXR1c0NvZGUgPT09IDIwMClcbiAgICB9KVxuICAgIHJlcS5vbignZXJyb3InLCAoKSA9PiByZXNvbHZlKGZhbHNlKSlcbiAgICByZXEuZW5kKClcbiAgfSlcbn1cbiJdfQ==
|
package/dist/web.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ChildProcess } from 'child_process';
|
|
2
|
+
import { WebOptions } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* 启动 OpenCode Web 服务
|
|
5
|
+
* @param options - Web 服务启动选项
|
|
6
|
+
* @returns 子进程实例
|
|
7
|
+
* @throws 服务启动超时时抛出错误
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const proc = await startOpenCodeWeb({
|
|
11
|
+
* port: 4097,
|
|
12
|
+
* hostname: '127.0.0.1',
|
|
13
|
+
* serverUrl: '',
|
|
14
|
+
* cwd: process.cwd()
|
|
15
|
+
* })
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function startOpenCodeWeb(options: WebOptions): Promise<ChildProcess>;
|
package/dist/web.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { waitForServer } from './utils';
|
|
3
|
+
import { SERVER_START_TIMEOUT, LOG_PREFIX, } from './constants';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
/**
|
|
7
|
+
* 启动 OpenCode Web 服务
|
|
8
|
+
* @param options - Web 服务启动选项
|
|
9
|
+
* @returns 子进程实例
|
|
10
|
+
* @throws 服务启动超时时抛出错误
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const proc = await startOpenCodeWeb({
|
|
14
|
+
* port: 4097,
|
|
15
|
+
* hostname: '127.0.0.1',
|
|
16
|
+
* serverUrl: '',
|
|
17
|
+
* cwd: process.cwd()
|
|
18
|
+
* })
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export async function startOpenCodeWeb(options) {
|
|
22
|
+
const { port, hostname, cwd, configDir, corsOrigins, contextApiUrl } = options;
|
|
23
|
+
const stateDir = createStateDirectory(cwd);
|
|
24
|
+
const pluginPath = path.join(stateDir, 'plugins', 'page-context.js');
|
|
25
|
+
const env = buildProcessEnv(stateDir, configDir, contextApiUrl, pluginPath);
|
|
26
|
+
const args = [
|
|
27
|
+
'serve',
|
|
28
|
+
'--port', String(port),
|
|
29
|
+
'--hostname', hostname,
|
|
30
|
+
];
|
|
31
|
+
if (corsOrigins && corsOrigins.length > 0) {
|
|
32
|
+
corsOrigins.forEach(origin => {
|
|
33
|
+
args.push('--cors', origin);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
const proc = spawn('opencode', args, {
|
|
37
|
+
cwd,
|
|
38
|
+
stdio: 'pipe',
|
|
39
|
+
env,
|
|
40
|
+
});
|
|
41
|
+
setupProcessHandlers(proc, port, hostname);
|
|
42
|
+
await waitForServer(`http://${hostname}:${port}`, SERVER_START_TIMEOUT);
|
|
43
|
+
console.log(`\n\x1b[36m\x1b[1m${LOG_PREFIX}\x1b[0m ✨ OpenCode server started successfully\n`);
|
|
44
|
+
return proc;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 创建状态目录
|
|
48
|
+
* @param cwd - 工作目录
|
|
49
|
+
* @returns 状态目录路径
|
|
50
|
+
*/
|
|
51
|
+
function createStateDirectory(cwd) {
|
|
52
|
+
const stateDir = path.join(cwd, 'node_modules', '.cache', 'opencode');
|
|
53
|
+
if (!fs.existsSync(stateDir)) {
|
|
54
|
+
fs.mkdirSync(stateDir, { recursive: true });
|
|
55
|
+
}
|
|
56
|
+
return stateDir;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* 构建进程环境变量
|
|
60
|
+
* @param stateDir - 状态目录路径
|
|
61
|
+
* @param configDir - 配置目录路径
|
|
62
|
+
* @param contextApiUrl - 上下文 API URL
|
|
63
|
+
* @param pluginPath - 插件路径
|
|
64
|
+
* @returns 环境变量对象
|
|
65
|
+
*/
|
|
66
|
+
function buildProcessEnv(stateDir, configDir, contextApiUrl, pluginPath) {
|
|
67
|
+
const env = {
|
|
68
|
+
...Object.fromEntries(Object.entries(process.env).filter(([, v]) => v !== undefined)),
|
|
69
|
+
XDG_STATE_HOME: stateDir,
|
|
70
|
+
};
|
|
71
|
+
if (configDir) {
|
|
72
|
+
env.OPENCODE_CONFIG_DIR = configDir;
|
|
73
|
+
}
|
|
74
|
+
if (contextApiUrl) {
|
|
75
|
+
env.OPENCODE_CONTEXT_API_URL = contextApiUrl;
|
|
76
|
+
}
|
|
77
|
+
if (pluginPath) {
|
|
78
|
+
env.OPENCODE_PLUGINS = pluginPath;
|
|
79
|
+
}
|
|
80
|
+
return env;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 设置进程事件处理器
|
|
84
|
+
* @param proc - 子进程实例
|
|
85
|
+
*/
|
|
86
|
+
function setupProcessHandlers(proc, port, hostname) {
|
|
87
|
+
proc.stdout?.on('data', () => {
|
|
88
|
+
});
|
|
89
|
+
proc.stderr?.on('data', () => {
|
|
90
|
+
});
|
|
91
|
+
proc.on('error', (err) => {
|
|
92
|
+
console.error(`\x1b[31m\x1b[1m${LOG_PREFIX}\x1b[0m ❌ Failed to start OpenCode server:`, err.message);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3dlYi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsS0FBSyxFQUFnQixNQUFNLGVBQWUsQ0FBQTtBQUNuRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sU0FBUyxDQUFBO0FBRXZDLE9BQU8sRUFDTCxvQkFBb0IsRUFDcEIsVUFBVSxHQUNYLE1BQU0sYUFBYSxDQUFBO0FBQ3BCLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQTtBQUN2QixPQUFPLEVBQUUsTUFBTSxJQUFJLENBQUE7QUFFbkI7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLGdCQUFnQixDQUFDLE9BQW1CO0lBQ3hELE1BQU0sRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsV0FBVyxFQUFFLGFBQWEsRUFBRSxHQUFHLE9BQU8sQ0FBQTtJQUU5RSxNQUFNLFFBQVEsR0FBRyxvQkFBb0IsQ0FBQyxHQUFHLENBQUMsQ0FBQTtJQUMxQyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxTQUFTLEVBQUUsaUJBQWlCLENBQUMsQ0FBQTtJQUNwRSxNQUFNLEdBQUcsR0FBRyxlQUFlLENBQUMsUUFBUSxFQUFFLFNBQVMsRUFBRSxhQUFhLEVBQUUsVUFBVSxDQUFDLENBQUE7SUFFM0UsTUFBTSxJQUFJLEdBQUc7UUFDWCxPQUFPO1FBQ1AsUUFBUSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUM7UUFDdEIsWUFBWSxFQUFFLFFBQVE7S0FDdkIsQ0FBQTtJQUVELElBQUksV0FBVyxJQUFJLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDMUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRTtZQUMzQixJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQTtRQUM3QixDQUFDLENBQUMsQ0FBQTtJQUNKLENBQUM7SUFFRCxNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsVUFBVSxFQUFFLElBQUksRUFBRTtRQUNuQyxHQUFHO1FBQ0gsS0FBSyxFQUFFLE1BQU07UUFDYixHQUFHO0tBQ0osQ0FBQyxDQUFBO0lBRUYsb0JBQW9CLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxRQUFRLENBQUMsQ0FBQTtJQUUxQyxNQUFNLGFBQWEsQ0FBQyxVQUFVLFFBQVEsSUFBSSxJQUFJLEVBQUUsRUFBRSxvQkFBb0IsQ0FBQyxDQUFBO0lBRXZFLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0JBQW9CLFVBQVUsa0RBQWtELENBQUMsQ0FBQTtJQUU3RixPQUFPLElBQUksQ0FBQTtBQUNiLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBUyxvQkFBb0IsQ0FBQyxHQUFXO0lBQ3ZDLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLGNBQWMsRUFBRSxRQUFRLEVBQUUsVUFBVSxDQUFDLENBQUE7SUFFckUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztRQUM3QixFQUFFLENBQUMsU0FBUyxDQUFDLFFBQVEsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFBO0lBQzdDLENBQUM7SUFFRCxPQUFPLFFBQVEsQ0FBQTtBQUNqQixDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILFNBQVMsZUFBZSxDQUFDLFFBQWdCLEVBQUUsU0FBa0IsRUFBRSxhQUFzQixFQUFFLFVBQW1CO0lBQ3hHLE1BQU0sR0FBRyxHQUEyQjtRQUNsQyxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQ25CLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLFNBQVMsQ0FBQyxDQUNyQztRQUMzQixjQUFjLEVBQUUsUUFBUTtLQUN6QixDQUFBO0lBRUQsSUFBSSxTQUFTLEVBQUUsQ0FBQztRQUNkLEdBQUcsQ0FBQyxtQkFBbUIsR0FBRyxTQUFTLENBQUE7SUFDckMsQ0FBQztJQUVELElBQUksYUFBYSxFQUFFLENBQUM7UUFDbEIsR0FBRyxDQUFDLHdCQUF3QixHQUFHLGFBQWEsQ0FBQTtJQUM5QyxDQUFDO0lBRUQsSUFBSSxVQUFVLEVBQUUsQ0FBQztRQUNmLEdBQUcsQ0FBQyxnQkFBZ0IsR0FBRyxVQUFVLENBQUE7SUFDbkMsQ0FBQztJQUVELE9BQU8sR0FBRyxDQUFBO0FBQ1osQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQVMsb0JBQW9CLENBQUMsSUFBa0IsRUFBRSxJQUFZLEVBQUUsUUFBZ0I7SUFDOUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRTtJQUM3QixDQUFDLENBQUMsQ0FBQTtJQUVGLElBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUU7SUFDN0IsQ0FBQyxDQUFDLENBQUE7SUFFRixJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFO1FBQ3ZCLE9BQU8sQ0FBQyxLQUFLLENBQUMsa0JBQWtCLFVBQVUsNENBQTRDLEVBQUUsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQ3RHLENBQUMsQ0FBQyxDQUFBO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHNwYXduLCBDaGlsZFByb2Nlc3MgfSBmcm9tICdjaGlsZF9wcm9jZXNzJ1xuaW1wb3J0IHsgd2FpdEZvclNlcnZlciB9IGZyb20gJy4vdXRpbHMnXG5pbXBvcnQgeyBXZWJPcHRpb25zIH0gZnJvbSAnLi90eXBlcydcbmltcG9ydCB7XG4gIFNFUlZFUl9TVEFSVF9USU1FT1VULFxuICBMT0dfUFJFRklYLFxufSBmcm9tICcuL2NvbnN0YW50cydcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnXG5pbXBvcnQgZnMgZnJvbSAnZnMnXG5cbi8qKlxuICog5ZCv5YqoIE9wZW5Db2RlIFdlYiDmnI3liqFcbiAqIEBwYXJhbSBvcHRpb25zIC0gV2ViIOacjeWKoeWQr+WKqOmAiemhuVxuICogQHJldHVybnMg5a2Q6L+b56iL5a6e5L6LXG4gKiBAdGhyb3dzIOacjeWKoeWQr+WKqOi2heaXtuaXtuaKm+WHuumUmeivr1xuICogQGV4YW1wbGVcbiAqIGBgYHRzXG4gKiBjb25zdCBwcm9jID0gYXdhaXQgc3RhcnRPcGVuQ29kZVdlYih7XG4gKiAgIHBvcnQ6IDQwOTcsXG4gKiAgIGhvc3RuYW1lOiAnMTI3LjAuMC4xJyxcbiAqICAgc2VydmVyVXJsOiAnJyxcbiAqICAgY3dkOiBwcm9jZXNzLmN3ZCgpXG4gKiB9KVxuICogYGBgXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydE9wZW5Db2RlV2ViKG9wdGlvbnM6IFdlYk9wdGlvbnMpOiBQcm9taXNlPENoaWxkUHJvY2Vzcz4ge1xuICBjb25zdCB7IHBvcnQsIGhvc3RuYW1lLCBjd2QsIGNvbmZpZ0RpciwgY29yc09yaWdpbnMsIGNvbnRleHRBcGlVcmwgfSA9IG9wdGlvbnNcblxuICBjb25zdCBzdGF0ZURpciA9IGNyZWF0ZVN0YXRlRGlyZWN0b3J5KGN3ZClcbiAgY29uc3QgcGx1Z2luUGF0aCA9IHBhdGguam9pbihzdGF0ZURpciwgJ3BsdWdpbnMnLCAncGFnZS1jb250ZXh0LmpzJylcbiAgY29uc3QgZW52ID0gYnVpbGRQcm9jZXNzRW52KHN0YXRlRGlyLCBjb25maWdEaXIsIGNvbnRleHRBcGlVcmwsIHBsdWdpblBhdGgpXG5cbiAgY29uc3QgYXJncyA9IFtcbiAgICAnc2VydmUnLFxuICAgICctLXBvcnQnLCBTdHJpbmcocG9ydCksXG4gICAgJy0taG9zdG5hbWUnLCBob3N0bmFtZSxcbiAgXVxuXG4gIGlmIChjb3JzT3JpZ2lucyAmJiBjb3JzT3JpZ2lucy5sZW5ndGggPiAwKSB7XG4gICAgY29yc09yaWdpbnMuZm9yRWFjaChvcmlnaW4gPT4ge1xuICAgICAgYXJncy5wdXNoKCctLWNvcnMnLCBvcmlnaW4pXG4gICAgfSlcbiAgfVxuXG4gIGNvbnN0IHByb2MgPSBzcGF3bignb3BlbmNvZGUnLCBhcmdzLCB7XG4gICAgY3dkLFxuICAgIHN0ZGlvOiAncGlwZScsXG4gICAgZW52LFxuICB9KVxuXG4gIHNldHVwUHJvY2Vzc0hhbmRsZXJzKHByb2MsIHBvcnQsIGhvc3RuYW1lKVxuXG4gIGF3YWl0IHdhaXRGb3JTZXJ2ZXIoYGh0dHA6Ly8ke2hvc3RuYW1lfToke3BvcnR9YCwgU0VSVkVSX1NUQVJUX1RJTUVPVVQpXG5cbiAgY29uc29sZS5sb2coYFxcblxceDFiWzM2bVxceDFiWzFtJHtMT0dfUFJFRklYfVxceDFiWzBtIOKcqCBPcGVuQ29kZSBzZXJ2ZXIgc3RhcnRlZCBzdWNjZXNzZnVsbHlcXG5gKVxuXG4gIHJldHVybiBwcm9jXG59XG5cbi8qKlxuICog5Yib5bu654q25oCB55uu5b2VXG4gKiBAcGFyYW0gY3dkIC0g5bel5L2c55uu5b2VXG4gKiBAcmV0dXJucyDnirbmgIHnm67lvZXot6/lvoRcbiAqL1xuZnVuY3Rpb24gY3JlYXRlU3RhdGVEaXJlY3RvcnkoY3dkOiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCBzdGF0ZURpciA9IHBhdGguam9pbihjd2QsICdub2RlX21vZHVsZXMnLCAnLmNhY2hlJywgJ29wZW5jb2RlJylcbiAgXG4gIGlmICghZnMuZXhpc3RzU3luYyhzdGF0ZURpcikpIHtcbiAgICBmcy5ta2RpclN5bmMoc3RhdGVEaXIsIHsgcmVjdXJzaXZlOiB0cnVlIH0pXG4gIH1cbiAgXG4gIHJldHVybiBzdGF0ZURpclxufVxuXG4vKipcbiAqIOaehOW7uui/m+eoi+eOr+Wig+WPmOmHj1xuICogQHBhcmFtIHN0YXRlRGlyIC0g54q25oCB55uu5b2V6Lev5b6EXG4gKiBAcGFyYW0gY29uZmlnRGlyIC0g6YWN572u55uu5b2V6Lev5b6EXG4gKiBAcGFyYW0gY29udGV4dEFwaVVybCAtIOS4iuS4i+aWhyBBUEkgVVJMXG4gKiBAcGFyYW0gcGx1Z2luUGF0aCAtIOaPkuS7tui3r+W+hFxuICogQHJldHVybnMg546v5aKD5Y+Y6YeP5a+56LGhXG4gKi9cbmZ1bmN0aW9uIGJ1aWxkUHJvY2Vzc0VudihzdGF0ZURpcjogc3RyaW5nLCBjb25maWdEaXI/OiBzdHJpbmcsIGNvbnRleHRBcGlVcmw/OiBzdHJpbmcsIHBsdWdpblBhdGg/OiBzdHJpbmcpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgY29uc3QgZW52OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgIC4uLk9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgIE9iamVjdC5lbnRyaWVzKHByb2Nlc3MuZW52KS5maWx0ZXIoKFssIHZdKSA9PiB2ICE9PSB1bmRlZmluZWQpXG4gICAgKSBhcyBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LFxuICAgIFhER19TVEFURV9IT01FOiBzdGF0ZURpcixcbiAgfVxuXG4gIGlmIChjb25maWdEaXIpIHtcbiAgICBlbnYuT1BFTkNPREVfQ09ORklHX0RJUiA9IGNvbmZpZ0RpclxuICB9XG5cbiAgaWYgKGNvbnRleHRBcGlVcmwpIHtcbiAgICBlbnYuT1BFTkNPREVfQ09OVEVYVF9BUElfVVJMID0gY29udGV4dEFwaVVybFxuICB9XG5cbiAgaWYgKHBsdWdpblBhdGgpIHtcbiAgICBlbnYuT1BFTkNPREVfUExVR0lOUyA9IHBsdWdpblBhdGhcbiAgfVxuXG4gIHJldHVybiBlbnZcbn1cblxuLyoqXG4gKiDorr7nva7ov5vnqIvkuovku7blpITnkIblmahcbiAqIEBwYXJhbSBwcm9jIC0g5a2Q6L+b56iL5a6e5L6LXG4gKi9cbmZ1bmN0aW9uIHNldHVwUHJvY2Vzc0hhbmRsZXJzKHByb2M6IENoaWxkUHJvY2VzcywgcG9ydDogbnVtYmVyLCBob3N0bmFtZTogc3RyaW5nKTogdm9pZCB7XG4gIHByb2Muc3Rkb3V0Py5vbignZGF0YScsICgpID0+IHtcbiAgfSlcblxuICBwcm9jLnN0ZGVycj8ub24oJ2RhdGEnLCAoKSA9PiB7XG4gIH0pXG5cbiAgcHJvYy5vbignZXJyb3InLCAoZXJyKSA9PiB7XG4gICAgY29uc29sZS5lcnJvcihgXFx4MWJbMzFtXFx4MWJbMW0ke0xPR19QUkVGSVh9XFx4MWJbMG0g4p2MIEZhaWxlZCB0byBzdGFydCBPcGVuQ29kZSBzZXJ2ZXI6YCwgZXJyLm1lc3NhZ2UpXG4gIH0pXG59XG4iXX0=
|