vite-plugin-opencode-assistant 1.1.17 → 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.
@@ -62,31 +62,14 @@ function startOpenCodeWeb(options) {
62
62
  var _a, _b;
63
63
  const { port, hostname, cwd, configDir, corsOrigins, contextApiUrl, logsApiUrl, logFilesJson } = options;
64
64
  const stateDir = createStateDirectory(cwd);
65
- const pluginsDir = path.join(stateDir, "plugins");
66
- const pluginPaths = [
67
- path.join(pluginsDir, "page-context.js"),
68
- path.join(pluginsDir, "vite-logs.js")
69
- ];
70
- if (logFilesJson) {
71
- pluginPaths.push(path.join(pluginsDir, "service-logs.js"));
72
- }
73
- const pluginPathsStr = pluginPaths.join(",");
74
65
  log.debug("Building process environment", {
75
66
  stateDir,
76
67
  configDir,
77
68
  contextApiUrl,
78
69
  logsApiUrl,
79
- logFilesJson,
80
- pluginPathsStr
81
- });
82
- const env = buildProcessEnv(
83
- stateDir,
84
- configDir,
85
- contextApiUrl,
86
- logsApiUrl,
87
- pluginPathsStr,
88
70
  logFilesJson
89
- );
71
+ });
72
+ const env = buildProcessEnv(stateDir, configDir, contextApiUrl, logsApiUrl, logFilesJson);
90
73
  const args = ["serve", "--port", String(port), "--hostname", hostname];
91
74
  if (corsOrigins && corsOrigins.length > 0) {
92
75
  corsOrigins.forEach((origin) => {
@@ -153,11 +136,13 @@ function copyPluginFiles(sourceDir, targetDir) {
153
136
  }
154
137
  log.debug("All plugin files copied", { count: files.length, files });
155
138
  }
156
- function buildProcessEnv(stateDir, configDir, contextApiUrl, logsApiUrl, pluginPaths, logFilesJson) {
139
+ function buildProcessEnv(stateDir, configDir, contextApiUrl, logsApiUrl, logFilesJson) {
157
140
  const env = __spreadProps(__spreadValues({}, Object.fromEntries(
158
141
  Object.entries(process.env).filter(([, v]) => v !== void 0)
159
142
  )), {
160
- XDG_STATE_HOME: stateDir
143
+ XDG_STATE_HOME: stateDir,
144
+ // 指向缓存目录,OpenCode 会从 <stateDir>/plugins/ 自动发现插件
145
+ OPENCODE_CONFIG_DIR: stateDir
161
146
  });
162
147
  if (configDir) {
163
148
  env.OPENCODE_CONFIG_DIR = configDir;
@@ -171,10 +156,6 @@ function buildProcessEnv(stateDir, configDir, contextApiUrl, logsApiUrl, pluginP
171
156
  env.OPENCODE_VITE_LOGS_API_URL = logsApiUrl;
172
157
  log.debug("Set OPENCODE_VITE_LOGS_API_URL", { logsApiUrl });
173
158
  }
174
- if (pluginPaths) {
175
- env.OPENCODE_PLUGINS = pluginPaths;
176
- log.debug("Set OPENCODE_PLUGINS", { pluginPaths });
177
- }
178
159
  if (logFilesJson) {
179
160
  env.OPENCODE_LOG_FILES_JSON = logFilesJson;
180
161
  log.debug("Set OPENCODE_LOG_FILES_JSON", { logFilesJson });
@@ -35,13 +35,15 @@ function setupContextEndpoint(server, ctx) {
35
35
  return;
36
36
  }
37
37
  if (req.method === "GET") {
38
+ const pc = ctx.getPageContext();
39
+ log.debug(`[Context] GET \u2192 url=${pc.url} title=${pc.title} tabId=${pc.tabId}`);
38
40
  res.writeHead(200);
39
- res.end(JSON.stringify(ctx.pageContext));
41
+ res.end(JSON.stringify(pc));
40
42
  reqCtx.end(200);
41
43
  return;
42
44
  }
43
45
  if (req.method === "DELETE") {
44
- ctx.pageContext.selectedElements = [];
46
+ ctx.clearSelectedElements();
45
47
  log.debug("Selected elements cleared", { sseClients: ctx.sseClients.size });
46
48
  let sentCount = 0;
47
49
  ctx.sseClients.forEach((client) => {
@@ -70,22 +72,28 @@ function setupContextEndpoint(server, ctx) {
70
72
  var _a, _b, _c;
71
73
  try {
72
74
  const data = JSON.parse(body);
73
- ctx.pageContext = {
75
+ const tabId = data.tabId != null ? String(data.tabId) : "default";
76
+ const existing = ctx.getPageContext();
77
+ const newCtx = {
74
78
  url: data.url || "",
75
79
  title: data.title || "",
76
- // 保留已有的 tabId/tabIndex(避免页内 widget 覆盖 Side Panel 写入的值)
77
- tabId: (_a = data.tabId) != null ? _a : ctx.pageContext.tabId,
78
- tabIndex: (_b = data.tabIndex) != null ? _b : ctx.pageContext.tabIndex,
80
+ tabId: (_a = data.tabId) != null ? _a : existing.tabId,
81
+ tabIndex: (_b = data.tabIndex) != null ? _b : existing.tabIndex,
79
82
  selectedElements: data.selectedElements || []
80
83
  };
84
+ ctx.setPageContext(tabId, newCtx);
85
+ if (data.active) {
86
+ ctx.setActiveTabId(tabId);
87
+ }
81
88
  log.debug("Context updated", {
82
- url: ctx.pageContext.url,
83
- title: ctx.pageContext.title,
84
- selectedElementsCount: ((_c = ctx.pageContext.selectedElements) == null ? void 0 : _c.length) || 0
89
+ tabId,
90
+ url: newCtx.url,
91
+ title: newCtx.title,
92
+ selectedElementsCount: ((_c = newCtx.selectedElements) == null ? void 0 : _c.length) || 0
85
93
  });
86
- if (ctx.pageContext.selectedElements && ctx.pageContext.selectedElements.length > 0) {
94
+ if (newCtx.selectedElements && newCtx.selectedElements.length > 0) {
87
95
  log.debug("Selected elements details", {
88
- elements: ctx.pageContext.selectedElements.map((el) => {
96
+ elements: newCtx.selectedElements.map((el) => {
89
97
  var _a2;
90
98
  return {
91
99
  filePath: el.filePath,
@@ -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
- get pageContext(): PageContext;
7
- set pageContext(ctx: PageContext);
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/es/index.mjs CHANGED
@@ -69,7 +69,10 @@ function createOpenCodePlugin(options = {}) {
69
69
  let actualWebPort = config.webPort;
70
70
  let actualProxyPort = (_a = config.proxyPort) != null ? _a : DEFAULT_PROXY_PORT;
71
71
  let projectRoot = "";
72
- let pageContext = { url: "", title: "" };
72
+ const pageContext = { url: "", title: "" };
73
+ const DEFAULT_TAB = "default";
74
+ const pageContexts = /* @__PURE__ */ new Map([[DEFAULT_TAB, pageContext]]);
75
+ let activeTabId = DEFAULT_TAB;
73
76
  const serviceInstanceId = crypto.randomUUID();
74
77
  const sseClients = /* @__PURE__ */ new Set();
75
78
  const api = new OpenCodeAPI(
@@ -110,11 +113,25 @@ function createOpenCodePlugin(options = {}) {
110
113
  get sseClients() {
111
114
  return sseClients;
112
115
  },
113
- get pageContext() {
114
- return pageContext;
116
+ getPageContext() {
117
+ return pageContexts.get(activeTabId) || pageContexts.get(DEFAULT_TAB) || { url: "", title: "" };
115
118
  },
116
- set pageContext(ctx) {
117
- pageContext = ctx;
119
+ setPageContext(tabId, ctx) {
120
+ pageContexts.set(tabId || DEFAULT_TAB, ctx);
121
+ },
122
+ setActiveTabId(tabId) {
123
+ activeTabId = tabId;
124
+ },
125
+ clearSelectedElements() {
126
+ const ctx = pageContexts.get(activeTabId);
127
+ if (ctx) {
128
+ ctx.selectedElements = [];
129
+ pageContexts.set(activeTabId, ctx);
130
+ }
131
+ const defaultCtx = pageContexts.get(DEFAULT_TAB);
132
+ if (defaultCtx) {
133
+ defaultCtx.selectedElements = [];
134
+ }
118
135
  },
119
136
  get isServiceStarted() {
120
137
  return service.isStarted;
@@ -203,8 +220,11 @@ function createOpenCodePlugin(options = {}) {
203
220
  projectRoot,
204
221
  verbose: config.verbose
205
222
  });
223
+ const pageKey = Math.random().toString(36).slice(2, 5);
224
+ 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>`;
206
225
  timer.end();
207
- return html.replace("</body>", `${widget}</body>`);
226
+ return html.replace("</body>", `${titleInject}
227
+ ${widget}</body>`);
208
228
  }
209
229
  };
210
230
  }