vite-plugin-opencode-assistant 1.1.18 → 1.1.19
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/es/core/opencode-web.mjs +6 -25
- package/es/endpoints/context.mjs +19 -11
- package/es/endpoints/types.d.ts +8 -2
- package/es/index.mjs +26 -6
- package/lib/client.js +1136 -1134
- package/lib/core/opencode-web.cjs +6 -25
- package/lib/endpoints/context.cjs +19 -11
- package/lib/endpoints/types.d.ts +8 -2
- package/lib/index.cjs +26 -6
- package/package.json +5 -5
|
@@ -93,31 +93,14 @@ function startOpenCodeWeb(options) {
|
|
|
93
93
|
var _a, _b;
|
|
94
94
|
const { port, hostname, cwd, configDir, corsOrigins, contextApiUrl, logsApiUrl, logFilesJson } = options;
|
|
95
95
|
const stateDir = createStateDirectory(cwd);
|
|
96
|
-
const pluginsDir = import_path.default.join(stateDir, "plugins");
|
|
97
|
-
const pluginPaths = [
|
|
98
|
-
import_path.default.join(pluginsDir, "page-context.js"),
|
|
99
|
-
import_path.default.join(pluginsDir, "vite-logs.js")
|
|
100
|
-
];
|
|
101
|
-
if (logFilesJson) {
|
|
102
|
-
pluginPaths.push(import_path.default.join(pluginsDir, "service-logs.js"));
|
|
103
|
-
}
|
|
104
|
-
const pluginPathsStr = pluginPaths.join(",");
|
|
105
96
|
log.debug("Building process environment", {
|
|
106
97
|
stateDir,
|
|
107
98
|
configDir,
|
|
108
99
|
contextApiUrl,
|
|
109
100
|
logsApiUrl,
|
|
110
|
-
logFilesJson,
|
|
111
|
-
pluginPathsStr
|
|
112
|
-
});
|
|
113
|
-
const env = buildProcessEnv(
|
|
114
|
-
stateDir,
|
|
115
|
-
configDir,
|
|
116
|
-
contextApiUrl,
|
|
117
|
-
logsApiUrl,
|
|
118
|
-
pluginPathsStr,
|
|
119
101
|
logFilesJson
|
|
120
|
-
);
|
|
102
|
+
});
|
|
103
|
+
const env = buildProcessEnv(stateDir, configDir, contextApiUrl, logsApiUrl, logFilesJson);
|
|
121
104
|
const args = ["serve", "--port", String(port), "--hostname", hostname];
|
|
122
105
|
if (corsOrigins && corsOrigins.length > 0) {
|
|
123
106
|
corsOrigins.forEach((origin) => {
|
|
@@ -184,11 +167,13 @@ function copyPluginFiles(sourceDir, targetDir) {
|
|
|
184
167
|
}
|
|
185
168
|
log.debug("All plugin files copied", { count: files.length, files });
|
|
186
169
|
}
|
|
187
|
-
function buildProcessEnv(stateDir, configDir, contextApiUrl, logsApiUrl,
|
|
170
|
+
function buildProcessEnv(stateDir, configDir, contextApiUrl, logsApiUrl, logFilesJson) {
|
|
188
171
|
const env = __spreadProps(__spreadValues({}, Object.fromEntries(
|
|
189
172
|
Object.entries(process.env).filter(([, v]) => v !== void 0)
|
|
190
173
|
)), {
|
|
191
|
-
XDG_STATE_HOME: stateDir
|
|
174
|
+
XDG_STATE_HOME: stateDir,
|
|
175
|
+
// 指向缓存目录,OpenCode 会从 <stateDir>/plugins/ 自动发现插件
|
|
176
|
+
OPENCODE_CONFIG_DIR: stateDir
|
|
192
177
|
});
|
|
193
178
|
if (configDir) {
|
|
194
179
|
env.OPENCODE_CONFIG_DIR = configDir;
|
|
@@ -202,10 +187,6 @@ function buildProcessEnv(stateDir, configDir, contextApiUrl, logsApiUrl, pluginP
|
|
|
202
187
|
env.OPENCODE_VITE_LOGS_API_URL = logsApiUrl;
|
|
203
188
|
log.debug("Set OPENCODE_VITE_LOGS_API_URL", { logsApiUrl });
|
|
204
189
|
}
|
|
205
|
-
if (pluginPaths) {
|
|
206
|
-
env.OPENCODE_PLUGINS = pluginPaths;
|
|
207
|
-
log.debug("Set OPENCODE_PLUGINS", { pluginPaths });
|
|
208
|
-
}
|
|
209
190
|
if (logFilesJson) {
|
|
210
191
|
env.OPENCODE_LOG_FILES_JSON = logFilesJson;
|
|
211
192
|
log.debug("Set OPENCODE_LOG_FILES_JSON", { logFilesJson });
|
|
@@ -57,13 +57,15 @@ function setupContextEndpoint(server, ctx) {
|
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
59
59
|
if (req.method === "GET") {
|
|
60
|
+
const pc = ctx.getPageContext();
|
|
61
|
+
log.debug(`[Context] GET \u2192 url=${pc.url} title=${pc.title} tabId=${pc.tabId}`);
|
|
60
62
|
res.writeHead(200);
|
|
61
|
-
res.end(JSON.stringify(
|
|
63
|
+
res.end(JSON.stringify(pc));
|
|
62
64
|
reqCtx.end(200);
|
|
63
65
|
return;
|
|
64
66
|
}
|
|
65
67
|
if (req.method === "DELETE") {
|
|
66
|
-
ctx.
|
|
68
|
+
ctx.clearSelectedElements();
|
|
67
69
|
log.debug("Selected elements cleared", { sseClients: ctx.sseClients.size });
|
|
68
70
|
let sentCount = 0;
|
|
69
71
|
ctx.sseClients.forEach((client) => {
|
|
@@ -92,22 +94,28 @@ function setupContextEndpoint(server, ctx) {
|
|
|
92
94
|
var _a, _b, _c;
|
|
93
95
|
try {
|
|
94
96
|
const data = JSON.parse(body);
|
|
95
|
-
|
|
97
|
+
const tabId = data.tabId != null ? String(data.tabId) : "default";
|
|
98
|
+
const existing = ctx.getPageContext();
|
|
99
|
+
const newCtx = {
|
|
96
100
|
url: data.url || "",
|
|
97
101
|
title: data.title || "",
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
tabIndex: (_b = data.tabIndex) != null ? _b : ctx.pageContext.tabIndex,
|
|
102
|
+
tabId: (_a = data.tabId) != null ? _a : existing.tabId,
|
|
103
|
+
tabIndex: (_b = data.tabIndex) != null ? _b : existing.tabIndex,
|
|
101
104
|
selectedElements: data.selectedElements || []
|
|
102
105
|
};
|
|
106
|
+
ctx.setPageContext(tabId, newCtx);
|
|
107
|
+
if (data.active) {
|
|
108
|
+
ctx.setActiveTabId(tabId);
|
|
109
|
+
}
|
|
103
110
|
log.debug("Context updated", {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
111
|
+
tabId,
|
|
112
|
+
url: newCtx.url,
|
|
113
|
+
title: newCtx.title,
|
|
114
|
+
selectedElementsCount: ((_c = newCtx.selectedElements) == null ? void 0 : _c.length) || 0
|
|
107
115
|
});
|
|
108
|
-
if (
|
|
116
|
+
if (newCtx.selectedElements && newCtx.selectedElements.length > 0) {
|
|
109
117
|
log.debug("Selected elements details", {
|
|
110
|
-
elements:
|
|
118
|
+
elements: newCtx.selectedElements.map((el) => {
|
|
111
119
|
var _a2;
|
|
112
120
|
return {
|
|
113
121
|
filePath: el.filePath,
|
package/lib/endpoints/types.d.ts
CHANGED
|
@@ -3,8 +3,14 @@ import type http from "http";
|
|
|
3
3
|
export interface EndpointContext {
|
|
4
4
|
get webUrl(): string | null;
|
|
5
5
|
get sseClients(): Set<http.ServerResponse>;
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
/** 获取当前活跃 Tab 的上下文(扩展模式)或默认上下文(非扩展模式) */
|
|
7
|
+
getPageContext(): PageContext;
|
|
8
|
+
/** 写入某个 Tab 的上下文 */
|
|
9
|
+
setPageContext(tabId: string, ctx: PageContext): void;
|
|
10
|
+
/** 设置当前活跃 Tab ID */
|
|
11
|
+
setActiveTabId(tabId: string): void;
|
|
12
|
+
/** 清除选中元素(活跃 Tab) */
|
|
13
|
+
clearSelectedElements(): void;
|
|
8
14
|
get isServiceStarted(): boolean;
|
|
9
15
|
get currentTask(): {
|
|
10
16
|
task: ServiceStartupTask;
|
package/lib/index.cjs
CHANGED
|
@@ -94,7 +94,10 @@ function createOpenCodePlugin(options = {}) {
|
|
|
94
94
|
let actualWebPort = config.webPort;
|
|
95
95
|
let actualProxyPort = (_a = config.proxyPort) != null ? _a : import_shared.DEFAULT_PROXY_PORT;
|
|
96
96
|
let projectRoot = "";
|
|
97
|
-
|
|
97
|
+
const pageContext = { url: "", title: "" };
|
|
98
|
+
const DEFAULT_TAB = "default";
|
|
99
|
+
const pageContexts = /* @__PURE__ */ new Map([[DEFAULT_TAB, pageContext]]);
|
|
100
|
+
let activeTabId = DEFAULT_TAB;
|
|
98
101
|
const serviceInstanceId = import_crypto.default.randomUUID();
|
|
99
102
|
const sseClients = /* @__PURE__ */ new Set();
|
|
100
103
|
const api = new import_api.OpenCodeAPI(
|
|
@@ -135,11 +138,25 @@ function createOpenCodePlugin(options = {}) {
|
|
|
135
138
|
get sseClients() {
|
|
136
139
|
return sseClients;
|
|
137
140
|
},
|
|
138
|
-
|
|
139
|
-
return
|
|
141
|
+
getPageContext() {
|
|
142
|
+
return pageContexts.get(activeTabId) || pageContexts.get(DEFAULT_TAB) || { url: "", title: "" };
|
|
140
143
|
},
|
|
141
|
-
|
|
142
|
-
|
|
144
|
+
setPageContext(tabId, ctx) {
|
|
145
|
+
pageContexts.set(tabId || DEFAULT_TAB, ctx);
|
|
146
|
+
},
|
|
147
|
+
setActiveTabId(tabId) {
|
|
148
|
+
activeTabId = tabId;
|
|
149
|
+
},
|
|
150
|
+
clearSelectedElements() {
|
|
151
|
+
const ctx = pageContexts.get(activeTabId);
|
|
152
|
+
if (ctx) {
|
|
153
|
+
ctx.selectedElements = [];
|
|
154
|
+
pageContexts.set(activeTabId, ctx);
|
|
155
|
+
}
|
|
156
|
+
const defaultCtx = pageContexts.get(DEFAULT_TAB);
|
|
157
|
+
if (defaultCtx) {
|
|
158
|
+
defaultCtx.selectedElements = [];
|
|
159
|
+
}
|
|
143
160
|
},
|
|
144
161
|
get isServiceStarted() {
|
|
145
162
|
return service.isStarted;
|
|
@@ -228,8 +245,11 @@ function createOpenCodePlugin(options = {}) {
|
|
|
228
245
|
projectRoot,
|
|
229
246
|
verbose: config.verbose
|
|
230
247
|
});
|
|
248
|
+
const pageKey = Math.random().toString(36).slice(2, 5);
|
|
249
|
+
const titleInject = `<script>(function(){var k="[${pageKey}]",d=document,p=!1,f=function(){if(p)return;var t=d.title;if(t.indexOf(k)===0)return;p=!0;d.title=k+t.replace(k,"");p=!1};f();new MutationObserver(f).observe(d.querySelector("title")||d.head,{childList:!0})})();</script>`;
|
|
231
250
|
timer.end();
|
|
232
|
-
return html.replace("</body>", `${
|
|
251
|
+
return html.replace("</body>", `${titleInject}
|
|
252
|
+
${widget}</body>`);
|
|
233
253
|
}
|
|
234
254
|
};
|
|
235
255
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-opencode-assistant",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.19",
|
|
4
4
|
"description": "Embed OpenCode Web UI in your Vite dev server for real-time code modification and preview",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.cjs",
|
|
@@ -37,15 +37,15 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"unplugin-vue-inspector": "^3.0.0",
|
|
39
39
|
"execa": "^9.6.1",
|
|
40
|
-
"@vite-plugin-opencode-assistant/
|
|
41
|
-
"@vite-plugin-opencode-assistant/
|
|
42
|
-
"@vite-plugin-opencode-assistant/
|
|
40
|
+
"@vite-plugin-opencode-assistant/shared": "1.1.19",
|
|
41
|
+
"@vite-plugin-opencode-assistant/opencode": "1.1.19",
|
|
42
|
+
"@vite-plugin-opencode-assistant/components": "1.1.19"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"vite": ">=5.0.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@vite-plugin-opencode-assistant/client": "1.1.
|
|
48
|
+
"@vite-plugin-opencode-assistant/client": "1.1.19"
|
|
49
49
|
},
|
|
50
50
|
"scripts": {
|
|
51
51
|
"build": "pagoda-cli build && vite build -c vite.client.config.ts",
|