vite-plugin-aipanel 1.2.0-beta.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.
Files changed (98) hide show
  1. package/README.md +72 -0
  2. package/es/client/vue-devtools-bridge.d.ts +58 -0
  3. package/es/client/vue-devtools-bridge.mjs +150 -0
  4. package/es/core/injector.d.ts +2 -0
  5. package/es/core/injector.mjs +15 -0
  6. package/es/core/mcp-chrome.d.ts +56 -0
  7. package/es/core/mcp-chrome.mjs +133 -0
  8. package/es/core/mcp-proxy.d.ts +23 -0
  9. package/es/core/mcp-proxy.mjs +212 -0
  10. package/es/core/mcp-tools.d.ts +15 -0
  11. package/es/core/mcp-tools.mjs +671 -0
  12. package/es/core/provider-loader.d.ts +19 -0
  13. package/es/core/provider-loader.mjs +30 -0
  14. package/es/core/proxy-server.d.ts +12 -0
  15. package/es/core/proxy-server.mjs +148 -0
  16. package/es/core/service.d.ts +39 -0
  17. package/es/core/service.mjs +267 -0
  18. package/es/endpoints/context.d.ts +3 -0
  19. package/es/endpoints/context.mjs +106 -0
  20. package/es/endpoints/index.d.ts +9 -0
  21. package/es/endpoints/index.mjs +30 -0
  22. package/es/endpoints/logs.d.ts +9 -0
  23. package/es/endpoints/logs.mjs +86 -0
  24. package/es/endpoints/mcp.d.ts +6 -0
  25. package/es/endpoints/mcp.mjs +610 -0
  26. package/es/endpoints/sessions.d.ts +3 -0
  27. package/es/endpoints/sessions.mjs +62 -0
  28. package/es/endpoints/sse.d.ts +3 -0
  29. package/es/endpoints/sse.mjs +44 -0
  30. package/es/endpoints/start.d.ts +3 -0
  31. package/es/endpoints/start.mjs +21 -0
  32. package/es/endpoints/types.d.ts +34 -0
  33. package/es/endpoints/types.mjs +0 -0
  34. package/es/endpoints/vue-devtools.d.ts +9 -0
  35. package/es/endpoints/vue-devtools.mjs +107 -0
  36. package/es/endpoints/warmup.d.ts +3 -0
  37. package/es/endpoints/warmup.mjs +42 -0
  38. package/es/endpoints/widget.d.ts +3 -0
  39. package/es/endpoints/widget.mjs +36 -0
  40. package/es/env.d.ts +1 -0
  41. package/es/index.d.ts +22 -0
  42. package/es/index.mjs +342 -0
  43. package/es/utils/format-bridge.d.ts +9 -0
  44. package/es/utils/format-bridge.mjs +80 -0
  45. package/es/utils/paths.d.ts +3 -0
  46. package/es/utils/paths.mjs +45 -0
  47. package/es/utils/system.d.ts +3 -0
  48. package/es/utils/system.mjs +76 -0
  49. package/lib/client/vue-devtools-bridge.cjs +150 -0
  50. package/lib/client/vue-devtools-bridge.d.ts +58 -0
  51. package/lib/client.css +2 -0
  52. package/lib/client.js +6950 -0
  53. package/lib/core/injector.cjs +34 -0
  54. package/lib/core/injector.d.ts +2 -0
  55. package/lib/core/mcp-chrome.cjs +161 -0
  56. package/lib/core/mcp-chrome.d.ts +56 -0
  57. package/lib/core/mcp-proxy.cjs +244 -0
  58. package/lib/core/mcp-proxy.d.ts +23 -0
  59. package/lib/core/mcp-tools.cjs +694 -0
  60. package/lib/core/mcp-tools.d.ts +15 -0
  61. package/lib/core/provider-loader.cjs +53 -0
  62. package/lib/core/provider-loader.d.ts +19 -0
  63. package/lib/core/proxy-server.cjs +181 -0
  64. package/lib/core/proxy-server.d.ts +12 -0
  65. package/lib/core/service.cjs +289 -0
  66. package/lib/core/service.d.ts +39 -0
  67. package/lib/endpoints/context.cjs +129 -0
  68. package/lib/endpoints/context.d.ts +3 -0
  69. package/lib/endpoints/index.cjs +58 -0
  70. package/lib/endpoints/index.d.ts +9 -0
  71. package/lib/endpoints/logs.cjs +107 -0
  72. package/lib/endpoints/logs.d.ts +9 -0
  73. package/lib/endpoints/mcp.cjs +624 -0
  74. package/lib/endpoints/mcp.d.ts +6 -0
  75. package/lib/endpoints/sessions.cjs +85 -0
  76. package/lib/endpoints/sessions.d.ts +3 -0
  77. package/lib/endpoints/sse.cjs +67 -0
  78. package/lib/endpoints/sse.d.ts +3 -0
  79. package/lib/endpoints/start.cjs +44 -0
  80. package/lib/endpoints/start.d.ts +3 -0
  81. package/lib/endpoints/types.cjs +15 -0
  82. package/lib/endpoints/types.d.ts +34 -0
  83. package/lib/endpoints/vue-devtools.cjs +132 -0
  84. package/lib/endpoints/vue-devtools.d.ts +9 -0
  85. package/lib/endpoints/warmup.cjs +65 -0
  86. package/lib/endpoints/warmup.d.ts +3 -0
  87. package/lib/endpoints/widget.cjs +69 -0
  88. package/lib/endpoints/widget.d.ts +3 -0
  89. package/lib/env.d.ts +1 -0
  90. package/lib/index.cjs +361 -0
  91. package/lib/index.d.ts +22 -0
  92. package/lib/utils/format-bridge.cjs +102 -0
  93. package/lib/utils/format-bridge.d.ts +9 -0
  94. package/lib/utils/paths.cjs +80 -0
  95. package/lib/utils/paths.d.ts +3 -0
  96. package/lib/utils/system.cjs +110 -0
  97. package/lib/utils/system.d.ts +3 -0
  98. package/package.json +68 -0
package/lib/index.cjs ADDED
@@ -0,0 +1,361 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var lib_exports = {};
29
+ __export(lib_exports, {
30
+ default: () => aipanelPlugin
31
+ });
32
+ module.exports = __toCommonJS(lib_exports);
33
+ var import_crypto = __toESM(require("crypto"));
34
+ var import_fs = __toESM(require("fs"));
35
+ var import_vite = __toESM(require("unplugin-vue-inspector/vite"));
36
+ var import_core = require("@aipanel/core");
37
+ var import_node = require("@aipanel/core/node");
38
+ var import_endpoints = require("./endpoints/index.cjs");
39
+ var import_injector = require("./core/injector.cjs");
40
+ var import_provider_loader = require("./core/provider-loader.cjs");
41
+ var import_service = require("./core/service.cjs");
42
+ var import_mcp_proxy = require("./core/mcp-proxy.cjs");
43
+ var import_paths = require("./utils/paths.cjs");
44
+ var import_system = require("./utils/system.cjs");
45
+ const DEVTOOLS_BRIDGE_IMPORTEE = "virtual:aipanel-vue-devtools-bridge";
46
+ const DEVTOOLS_BRIDGE_QUERY = "aipanel_vue_devtools_bridge";
47
+ const BRIDGE_SOURCE_PATH = (0, import_paths.resolveVueDevtoolsBridgePath)();
48
+ const SILENT_CONTEXT_SCRIPT = `<script>
49
+ (function () {
50
+ var API = "/__aipanel_context__";
51
+ var last = "";
52
+ function report(force) {
53
+ if (document.visibilityState !== "visible") return;
54
+ var url = location.href;
55
+ var title = document.title;
56
+ var key = url + "|" + title;
57
+ if (!force && key === last) return;
58
+ last = key;
59
+ var sessionId = "";
60
+ try { sessionId = sessionStorage.getItem("_aipanel_pk") || ""; } catch (e) {}
61
+ fetch(API, {
62
+ method: "POST",
63
+ headers: { "Content-Type": "application/json" },
64
+ body: JSON.stringify({ url: url, title: title, sessionId: sessionId }),
65
+ }).catch(function () {});
66
+ }
67
+ var push = history.pushState.bind(history);
68
+ var replace = history.replaceState.bind(history);
69
+ history.pushState = function () { push.apply(this, arguments); setTimeout(function () { report(false); }, 0); };
70
+ history.replaceState = function () { replace.apply(this, arguments); setTimeout(function () { report(false); }, 0); };
71
+ window.addEventListener("popstate", function () { report(false); });
72
+ window.addEventListener("hashchange", function () { report(false); });
73
+ document.addEventListener("visibilitychange", function () {
74
+ // \u5207\u56DE\u672C\u6807\u7B7E\u65F6\u5F3A\u5236\u4E0A\u62A5\uFF1A\u672C\u9875 url/title \u672A\u53D8\uFF0C\u4F46\u670D\u52A1\u7AEF\u4E0A\u4E0B\u6587\u53EF\u80FD\u5DF2\u88AB\u5176\u4ED6\u6807\u7B7E\u8986\u76D6
75
+ if (document.visibilityState === "visible") report(true);
76
+ });
77
+ window.addEventListener("focus", function () {
78
+ // \u591A\u7A97\u53E3\uFF08\u5206\u5C4F/\u591A\u663E\u793A\u5668\uFF09\u4E0B\u6240\u6709\u6807\u7B7E\u9875\u90FD visible\uFF0Cvisibilitychange \u4E0D\u89E6\u53D1\uFF1B
79
+ // \u7A97\u53E3\u83B7\u5F97\u7126\u70B9\u662F"\u7528\u6237\u6B63\u5728\u770B\u8FD9\u4E2A\u9875\u9762"\u7684\u6700\u51C6\u786E\u4FE1\u53F7
80
+ report(true);
81
+ });
82
+ try {
83
+ new MutationObserver(function () { report(false); })
84
+ .observe(document.head, { childList: true, subtree: true });
85
+ } catch (e) {}
86
+ report(false);
87
+ })();
88
+ </script>`;
89
+ function aipanelPlugin(options = {}) {
90
+ const plugins = [];
91
+ plugins.push(
92
+ ...(0, import_vite.default)({
93
+ enabled: false,
94
+ toggleButtonVisibility: "never",
95
+ toggleComboKey: false
96
+ })
97
+ );
98
+ plugins.push(createAIPanelPlugin(options));
99
+ return plugins;
100
+ }
101
+ function createAIPanelPlugin(options = {}) {
102
+ const config = (0, import_core.resolvePluginConfig)(options);
103
+ (0, import_core.setVerbose)(config.verbose);
104
+ (0, import_node.initProcessLogCapture)({ maxSize: 500 });
105
+ const log = (0, import_node.createLogger)("Plugin");
106
+ let actualWebPort = config.webPort;
107
+ let actualProxyPort = config.proxyPort ?? import_core.DEFAULT_PROXY_PORT;
108
+ let projectRoot = "";
109
+ let vueDevtoolsApiUrl = "";
110
+ const pageContext = { url: "", title: "" };
111
+ const DEFAULT_TAB = "default";
112
+ const pageContexts = /* @__PURE__ */ new Map([[DEFAULT_TAB, pageContext]]);
113
+ let activeTabId = DEFAULT_TAB;
114
+ const serviceInstanceId = import_crypto.default.randomUUID();
115
+ const sseClients = /* @__PURE__ */ new Set();
116
+ const mcpProxy = new import_mcp_proxy.McpProxy({ idleTimeout: 5 * 60 * 1e3 });
117
+ let provider = null;
118
+ const service = new import_service.AIPanelService(
119
+ config,
120
+ sseClients,
121
+ (port) => {
122
+ actualWebPort = port;
123
+ },
124
+ (port) => {
125
+ actualProxyPort = port;
126
+ }
127
+ );
128
+ service.workspaceRoot = (0, import_system.findGitRoot)(process.cwd());
129
+ return {
130
+ name: "vite-plugin-aipanel",
131
+ apply(_viteConfig, env) {
132
+ if (!config.enabled) return false;
133
+ return env.command === "serve" && process.env.NODE_ENV !== "test";
134
+ },
135
+ async configureServer(server) {
136
+ const timer = log.timer("configureServer");
137
+ projectRoot = server.config.root;
138
+ let viteOrigin = "";
139
+ (0, import_endpoints.setupMiddlewares)(
140
+ server,
141
+ {
142
+ get webUrl() {
143
+ return actualWebPort ? `http://${config.hostname}:${actualWebPort}` : null;
144
+ },
145
+ get sseClients() {
146
+ return sseClients;
147
+ },
148
+ getPageContext() {
149
+ return pageContexts.get(activeTabId) || pageContexts.get(DEFAULT_TAB) || { url: "", title: "" };
150
+ },
151
+ setPageContext(tabId, ctx) {
152
+ pageContexts.set(tabId || DEFAULT_TAB, ctx);
153
+ },
154
+ setActiveTabId(tabId) {
155
+ activeTabId = tabId;
156
+ },
157
+ clearSelectedElements() {
158
+ const ctx = pageContexts.get(activeTabId);
159
+ if (ctx) {
160
+ ctx.selectedElements = [];
161
+ pageContexts.set(activeTabId, ctx);
162
+ }
163
+ const defaultCtx = pageContexts.get(DEFAULT_TAB);
164
+ if (defaultCtx) {
165
+ defaultCtx.selectedElements = [];
166
+ }
167
+ },
168
+ get isServiceStarted() {
169
+ return service.isStarted;
170
+ },
171
+ get currentTask() {
172
+ return service.currentTask;
173
+ },
174
+ get actualProxyPort() {
175
+ return actualProxyPort;
176
+ },
177
+ get actualWebPort() {
178
+ return actualWebPort;
179
+ },
180
+ get serviceInstanceId() {
181
+ return serviceInstanceId;
182
+ },
183
+ getSessions: () => {
184
+ if (!provider) return Promise.reject(new Error("Provider \u672A\u521D\u59CB\u5316"));
185
+ return provider.listSessions(service.workspaceRoot);
186
+ },
187
+ createSession: () => {
188
+ if (!provider) return Promise.reject(new Error("Provider \u672A\u521D\u59CB\u5316"));
189
+ return provider.createSession(service.workspaceRoot);
190
+ },
191
+ deleteSession: (id) => {
192
+ if (!provider) return Promise.reject(new Error("Provider \u672A\u521D\u59CB\u5316"));
193
+ return provider.deleteSession ? provider.deleteSession(id) : Promise.reject(new Error("\u5F53\u524D Provider \u4E0D\u652F\u6301\u5220\u9664\u4F1A\u8BDD"));
194
+ },
195
+ getCapabilities: () => provider?.capabilities ?? {},
196
+ resolveWidgetPath: import_paths.resolveWidgetPath,
197
+ resolveWidgetStylePath: import_paths.resolveWidgetStylePath,
198
+ retryWarmupChromeMcp: () => service.retryWarmupChromeMcp()
199
+ },
200
+ mcpProxy,
201
+ config.logFiles
202
+ );
203
+ if (!config.mcpOnly) {
204
+ try {
205
+ provider = await (0, import_provider_loader.loadProvider)(config.provider, {
206
+ hostname: config.hostname,
207
+ chromeDevtoolsPort: config.chromeDevtoolsPort,
208
+ getWebPort: () => actualWebPort,
209
+ getProxyPort: () => actualProxyPort,
210
+ options: config
211
+ });
212
+ } catch (e) {
213
+ log.error("\u52A0\u8F7D Web Provider \u5931\u8D25", {
214
+ provider: config.provider,
215
+ error: e instanceof Error ? e.message : String(e)
216
+ });
217
+ service.currentTask = {
218
+ task: "provider_not_installed",
219
+ data: { error: e instanceof Error ? e.message : String(e) }
220
+ };
221
+ timer.end("\u274C Provider \u52A0\u8F7D\u5931\u8D25");
222
+ return;
223
+ }
224
+ provider.applyConfig?.({ theme: config.theme });
225
+ service.setProvider(provider);
226
+ }
227
+ server.httpServer?.on("listening", async () => {
228
+ log.debug("Vite server listening event fired");
229
+ const address = server.httpServer?.address();
230
+ let vitePort;
231
+ let viteHost;
232
+ if (address && typeof address === "object") {
233
+ vitePort = address.port;
234
+ const addr = address.address;
235
+ if (addr === "::" || addr === "::1" || addr === "0.0.0.0" || !addr) {
236
+ viteHost = "localhost";
237
+ } else {
238
+ viteHost = addr;
239
+ }
240
+ } else {
241
+ const host = server.config.server.host;
242
+ vitePort = server.config.server.port || 5173;
243
+ viteHost = typeof host === "string" && host !== "0.0.0.0" && host !== "::" && host !== "::1" ? host : "localhost";
244
+ }
245
+ viteOrigin = `http://${viteHost}:${vitePort}`;
246
+ const contextApiUrl = `http://${viteHost}:${vitePort}${import_core.CONTEXT_API_PATH}`;
247
+ const logsApiUrl = `http://${viteHost}:${vitePort}${import_endpoints.LOGS_API_PATH}`;
248
+ vueDevtoolsApiUrl = `http://${viteHost}:${vitePort}${import_endpoints.VUE_DEVTOOLS_API_PATH}`;
249
+ const mcpApiUrl = `http://${viteHost}:${vitePort}${import_core.MCP_API_PATH}`;
250
+ log.debug("Vite server ready", {
251
+ vitePort,
252
+ viteHost,
253
+ viteOrigin,
254
+ contextApiUrl,
255
+ logsApiUrl,
256
+ vueDevtoolsApiUrl,
257
+ mcpApiUrl
258
+ });
259
+ log.info(`MCP endpoint: ${mcpApiUrl}`);
260
+ try {
261
+ await mcpProxy.start();
262
+ if (config.warmupChromeMcp) {
263
+ const warmup = await mcpProxy.verify();
264
+ if (!warmup.ok) {
265
+ log.debug("Chrome MCP warmup failed", { error: warmup.error });
266
+ }
267
+ }
268
+ if (config.mcpOnly) {
269
+ return;
270
+ }
271
+ await service.start(
272
+ vitePort,
273
+ [viteOrigin],
274
+ contextApiUrl,
275
+ logsApiUrl,
276
+ viteOrigin,
277
+ mcpProxy,
278
+ vueDevtoolsApiUrl
279
+ );
280
+ } catch (e) {
281
+ log.error("Failed to start services", { error: e });
282
+ }
283
+ });
284
+ server.httpServer?.on("close", () => {
285
+ log.debug("HTTP server closing");
286
+ service.stop();
287
+ mcpProxy.stop();
288
+ });
289
+ const cleanup = async () => {
290
+ log.debug("Process cleanup triggered");
291
+ mcpProxy.stop();
292
+ await service.stop();
293
+ process.exit(0);
294
+ };
295
+ process.on("SIGINT", cleanup);
296
+ process.on("SIGTERM", cleanup);
297
+ timer.end("\u2713 Server configured");
298
+ },
299
+ resolveId(id) {
300
+ if (id === DEVTOOLS_BRIDGE_IMPORTEE) {
301
+ return `${BRIDGE_SOURCE_PATH}?${DEVTOOLS_BRIDGE_QUERY}`;
302
+ }
303
+ return void 0;
304
+ },
305
+ load(id) {
306
+ const [filePath, query] = id.split("?", 2);
307
+ if (query === DEVTOOLS_BRIDGE_QUERY) {
308
+ return import_fs.default.readFileSync(filePath, "utf-8");
309
+ }
310
+ return void 0;
311
+ },
312
+ transformIndexHtml(html) {
313
+ const timer = log.timer("transformIndexHtml");
314
+ const tags = [
315
+ {
316
+ tag: "script",
317
+ injectTo: "head-prepend",
318
+ attrs: {
319
+ type: "module",
320
+ src: `/@id/${DEVTOOLS_BRIDGE_IMPORTEE}`
321
+ }
322
+ }
323
+ ];
324
+ const titleInject = `<script>
325
+ (function () {
326
+ var KEY = "_aipanel_pk";
327
+ if (!sessionStorage.getItem(KEY)) {
328
+ sessionStorage.setItem(KEY, "[" + Math.random().toString(36).slice(2, 10) + "]");
329
+ }
330
+ })();
331
+ </script>`;
332
+ if (config.mcpOnly) {
333
+ timer.end("\u2713 mcp-only (skip widget bubble, keep vue-devtools bridge + context report)");
334
+ return {
335
+ html: html.replace("</body>", `${titleInject}
336
+ ${SILENT_CONTEXT_SCRIPT}</body>`),
337
+ tags
338
+ };
339
+ }
340
+ const widget = (0, import_injector.injectWidget)({
341
+ theme: config.theme,
342
+ open: config.open,
343
+ hotkey: config.hotkey,
344
+ proxyPort: actualProxyPort,
345
+ proxyHost: config.hostname,
346
+ displayMode: config.displayMode === "extension" ? "extension-selector" : config.displayMode,
347
+ splitMode: config.splitMode,
348
+ serviceInstanceId,
349
+ webPort: actualWebPort,
350
+ projectRoot,
351
+ verbose: config.verbose
352
+ });
353
+ timer.end();
354
+ return {
355
+ html: html.replace("</body>", `${titleInject}
356
+ ${widget}</body>`),
357
+ tags
358
+ };
359
+ }
360
+ };
361
+ }
package/lib/index.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ import type { Plugin } from "vite";
2
+ import type { PluginOptions } from "@aipanel/core";
3
+ import { type ProviderId } from "./core/provider-loader";
4
+ import type { OpenCodeProviderOptions } from "@aipanel/provider-opencode";
5
+ import type { DeepSeekProviderOptions } from "@aipanel/provider-deepseek";
6
+ export type { PluginOptions } from "@aipanel/core";
7
+ export type { OpenCodeProviderOptions } from "@aipanel/provider-opencode";
8
+ export type { DeepSeekProviderOptions } from "@aipanel/provider-deepseek";
9
+ export type { ProviderId };
10
+ /**
11
+ * 编译期映射:provider id → providerOptions schema
12
+ * 与 provider-loader 的运行时包名映射对应;未知 provider 回退为宽松对象。
13
+ */
14
+ type ProviderOptionsSchema<ID extends ProviderId> = ID extends "default" | "opencode" ? OpenCodeProviderOptions : ID extends "deepseek" ? DeepSeekProviderOptions : Record<string, unknown>;
15
+ /**
16
+ * AIPanel Vite 插件
17
+ * provider 字段收窄为已登记的 ProviderId 联合类型(拼写错误在编译期报错);
18
+ * providerOptions 的类型根据 options.provider 自动推断(未配置时默认 "default" → opencode)。
19
+ */
20
+ export default function aipanelPlugin<const P extends ProviderId = "default">(options?: Omit<PluginOptions<ProviderOptionsSchema<P>>, "provider"> & {
21
+ provider?: P;
22
+ }): Plugin[];
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var import_fs = __toESM(require("fs"));
25
+ var import_http = __toESM(require("http"));
26
+ var import_path = __toESM(require("path"));
27
+ const filePath = process.argv[2];
28
+ if (!filePath) {
29
+ console.error("Usage: node format-bridge.cjs <filePath>");
30
+ process.exit(1);
31
+ }
32
+ const absPath = import_path.default.resolve(filePath);
33
+ const PORT = parseInt(process.env.AIPANEL_VSCODE_PORT || "", 10) || 51939;
34
+ function touchFile() {
35
+ const now = /* @__PURE__ */ new Date();
36
+ import_fs.default.utimesSync(absPath, now, now);
37
+ }
38
+ function probeHealth() {
39
+ return new Promise((resolve) => {
40
+ const req = import_http.default.get(`http://127.0.0.1:${PORT}/health`, (res) => {
41
+ res.resume();
42
+ resolve(res.statusCode === 200);
43
+ });
44
+ req.setTimeout(500, () => {
45
+ req.destroy();
46
+ resolve(false);
47
+ });
48
+ req.on("error", () => resolve(false));
49
+ });
50
+ }
51
+ function formatViaExtension() {
52
+ return new Promise((resolve, reject) => {
53
+ const body = JSON.stringify({ filePath: absPath });
54
+ const req = import_http.default.request(
55
+ {
56
+ hostname: "127.0.0.1",
57
+ port: PORT,
58
+ path: "/format",
59
+ method: "POST",
60
+ headers: { "Content-Type": "application/json" },
61
+ timeout: 5e3
62
+ },
63
+ (res) => {
64
+ const chunks = [];
65
+ res.on("data", (c) => chunks.push(c));
66
+ res.on("end", () => {
67
+ try {
68
+ const result = JSON.parse(Buffer.concat(chunks).toString());
69
+ if (result.error) {
70
+ reject(new Error(result.error));
71
+ } else {
72
+ resolve(result);
73
+ }
74
+ } catch (e) {
75
+ reject(e);
76
+ }
77
+ });
78
+ }
79
+ );
80
+ req.on("error", reject);
81
+ req.on("timeout", () => {
82
+ req.destroy();
83
+ reject(new Error("Timeout"));
84
+ });
85
+ req.write(body);
86
+ req.end();
87
+ });
88
+ }
89
+ async function main() {
90
+ const healthy = await probeHealth();
91
+ if (!healthy) {
92
+ touchFile();
93
+ process.exit(0);
94
+ }
95
+ try {
96
+ await formatViaExtension();
97
+ } catch {
98
+ }
99
+ touchFile();
100
+ process.exit(0);
101
+ }
102
+ main();
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * OpenCode VS Code 格式化桥接脚本
4
+ *
5
+ * VS Code 扩展可用时通过 HTTP API 格式化,不可用时直接返回(由 OpenCode 内置 prettier 兜底)。
6
+ *
7
+ * 用法: node format-bridge.cjs <filePath>
8
+ */
9
+ export {};
@@ -0,0 +1,80 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var paths_exports = {};
29
+ __export(paths_exports, {
30
+ resolveVueDevtoolsBridgePath: () => resolveVueDevtoolsBridgePath,
31
+ resolveWidgetPath: () => resolveWidgetPath,
32
+ resolveWidgetStylePath: () => resolveWidgetStylePath
33
+ });
34
+ module.exports = __toCommonJS(paths_exports);
35
+ var import_fs = __toESM(require("fs"));
36
+ var import_path = __toESM(require("path"));
37
+ var import_node = require("@aipanel/core/node");
38
+ const packageDir = (0, import_node.resolvePackageDir)("vite-plugin-aipanel");
39
+ function resolveWidgetPath() {
40
+ const candidatePaths = [
41
+ import_path.default.join(packageDir, "es", "client.js"),
42
+ import_path.default.join(packageDir, "lib", "client.js")
43
+ ];
44
+ for (const candidatePath of candidatePaths) {
45
+ if (import_fs.default.existsSync(candidatePath)) {
46
+ return candidatePath;
47
+ }
48
+ }
49
+ return candidatePaths[0];
50
+ }
51
+ function resolveWidgetStylePath() {
52
+ const candidatePaths = [
53
+ import_path.default.join(packageDir, "es", "client.css"),
54
+ import_path.default.join(packageDir, "lib", "client.css")
55
+ ];
56
+ for (const candidatePath of candidatePaths) {
57
+ if (import_fs.default.existsSync(candidatePath)) {
58
+ return candidatePath;
59
+ }
60
+ }
61
+ return candidatePaths[0];
62
+ }
63
+ function resolveVueDevtoolsBridgePath() {
64
+ const candidatePaths = [
65
+ import_path.default.join(packageDir, "es", "client", "vue-devtools-bridge.mjs"),
66
+ import_path.default.join(packageDir, "lib", "client", "vue-devtools-bridge.cjs")
67
+ ];
68
+ for (const candidatePath of candidatePaths) {
69
+ if (import_fs.default.existsSync(candidatePath)) {
70
+ return candidatePath;
71
+ }
72
+ }
73
+ return candidatePaths[0];
74
+ }
75
+ // Annotate the CommonJS export names for ESM import in node:
76
+ 0 && (module.exports = {
77
+ resolveVueDevtoolsBridgePath,
78
+ resolveWidgetPath,
79
+ resolveWidgetStylePath
80
+ });
@@ -0,0 +1,3 @@
1
+ export declare function resolveWidgetPath(): string;
2
+ export declare function resolveWidgetStylePath(): string;
3
+ export declare function resolveVueDevtoolsBridgePath(): string;
@@ -0,0 +1,110 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+ var system_exports = {};
29
+ __export(system_exports, {
30
+ findGitRoot: () => findGitRoot,
31
+ waitForServer: () => waitForServer
32
+ });
33
+ module.exports = __toCommonJS(system_exports);
34
+ var import_fs = __toESM(require("fs"));
35
+ var import_http = __toESM(require("http"));
36
+ var import_path = __toESM(require("path"));
37
+ var import_core = require("@aipanel/core");
38
+ var import_node = require("@aipanel/core/node");
39
+ const log = (0, import_node.createLogger)("Utils");
40
+ function waitForServer(url, timeout = 1e4, process) {
41
+ const timer = new import_node.PerformanceTimer("waitForServer", { url, timeout });
42
+ return new Promise((resolve, reject) => {
43
+ const startTime = Date.now();
44
+ let attempts = 0;
45
+ const check = () => {
46
+ attempts++;
47
+ log.debug(`Checking server availability (attempt ${attempts})`, { url });
48
+ if (process?.exitCode !== null && process?.exitCode !== void 0) {
49
+ timer.end(`\u274C Process exited with code ${process.exitCode}`);
50
+ reject(new Error(`Process exited with code ${process.exitCode}`));
51
+ return;
52
+ }
53
+ const req = import_http.default.get(url, (res) => {
54
+ if (res.statusCode && res.statusCode < 500) {
55
+ timer.end(`\u2713 Server ready after ${attempts} attempts`);
56
+ resolve();
57
+ } else {
58
+ log.debug(`Server returned status ${res.statusCode}, retrying...`);
59
+ retryOrReject();
60
+ }
61
+ });
62
+ req.on("error", (err) => {
63
+ log.debug(`Server check failed: ${err.message}`);
64
+ retryOrReject();
65
+ });
66
+ };
67
+ const retryOrReject = () => {
68
+ const elapsed = Date.now() - startTime;
69
+ if (elapsed < timeout) {
70
+ setTimeout(check, import_core.SERVER_CHECK_INTERVAL);
71
+ } else {
72
+ timer.end("\u274C Timeout");
73
+ reject(new Error(`Server not ready after ${timeout}ms (${attempts} attempts)`));
74
+ }
75
+ };
76
+ check();
77
+ });
78
+ }
79
+ function findGitRoot(startDir, maxDepth = 10) {
80
+ const timer = log.timer("findGitRoot", { startDir, maxDepth });
81
+ let currentDir = startDir;
82
+ let depth = 0;
83
+ while (depth < maxDepth) {
84
+ const gitDir = import_path.default.join(currentDir, ".git");
85
+ try {
86
+ if (import_fs.default.existsSync(gitDir)) {
87
+ timer.end(`\u2713 Found git root at depth ${depth}: ${currentDir}`);
88
+ return currentDir;
89
+ }
90
+ } catch (err) {
91
+ log.debug(`Error checking .git directory at ${currentDir}`, {
92
+ error: err.message
93
+ });
94
+ }
95
+ const parentDir = import_path.default.dirname(currentDir);
96
+ if (parentDir === currentDir) {
97
+ log.debug("Reached filesystem root");
98
+ break;
99
+ }
100
+ currentDir = parentDir;
101
+ depth++;
102
+ }
103
+ timer.end(`\u274C No git root found after ${depth} levels, using start directory`);
104
+ return startDir;
105
+ }
106
+ // Annotate the CommonJS export names for ESM import in node:
107
+ 0 && (module.exports = {
108
+ findGitRoot,
109
+ waitForServer
110
+ });