@aipanel/core 1.2.9 → 1.2.11

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.
@@ -1,6 +1,15 @@
1
+ import { spawn } from "node:child_process";
1
2
  import { createRequire } from "node:module";
3
+ import fs from "node:fs";
4
+ import http from "node:http";
2
5
  import path from "node:path";
3
- import { CHROME_DEVTOOLS_PORT, CHROME_DEVTOOLS_CHECK_TIMEOUT } from "../common/constants.mjs";
6
+ import {
7
+ CHROME_DEVTOOLS_PORT,
8
+ CHROME_DEVTOOLS_CHECK_TIMEOUT,
9
+ SERVER_CHECK_INTERVAL
10
+ } from "../common/constants.mjs";
11
+ import { PerformanceTimer, createLogger } from "./node-logger.mjs";
12
+ const log = createLogger("NodeUtils");
4
13
  function createPackageRequire(baseDir = process.cwd()) {
5
14
  return createRequire(path.join(baseDir, "package.json"));
6
15
  }
@@ -47,10 +56,236 @@ async function findAvailablePort(startPort, hostname, maxTries = 100) {
47
56
  }
48
57
  throw new Error(`No available port in range ${startPort}-${startPort + maxTries}`);
49
58
  }
59
+ function waitForServer(url, timeout = 1e4, proc) {
60
+ const timer = new PerformanceTimer("waitForServer", { url, timeout });
61
+ return new Promise((resolve, reject) => {
62
+ const startTime = Date.now();
63
+ let attempts = 0;
64
+ const check = () => {
65
+ attempts++;
66
+ log.debug(`Checking server availability (attempt ${attempts})`, { url });
67
+ if (proc?.exitCode !== null && proc?.exitCode !== void 0) {
68
+ timer.end(`\u2716 Process exited with code ${proc.exitCode}`);
69
+ reject(new Error(`Process exited with code ${proc.exitCode}`));
70
+ return;
71
+ }
72
+ const req = http.get(url, (res) => {
73
+ if (res.statusCode && res.statusCode < 500) {
74
+ timer.end(`\u2713 Server ready after ${attempts} attempts`);
75
+ resolve();
76
+ } else {
77
+ log.debug(`Server returned status ${res.statusCode}, retrying...`);
78
+ retryOrReject();
79
+ }
80
+ });
81
+ req.on("error", (err) => {
82
+ log.debug(`Server check failed: ${err.message}`);
83
+ retryOrReject();
84
+ });
85
+ };
86
+ const retryOrReject = () => {
87
+ const elapsed = Date.now() - startTime;
88
+ if (elapsed < timeout) {
89
+ setTimeout(check, SERVER_CHECK_INTERVAL);
90
+ } else {
91
+ timer.end("\u2716 Timeout");
92
+ reject(new Error(`Server not ready after ${timeout}ms (${attempts} attempts)`));
93
+ }
94
+ };
95
+ check();
96
+ });
97
+ }
98
+ function findGitRoot(startDir, maxDepth = 10) {
99
+ const timer = new PerformanceTimer("findGitRoot", { startDir, maxDepth });
100
+ let currentDir = startDir;
101
+ let depth = 0;
102
+ while (depth < maxDepth) {
103
+ const gitDir = path.join(currentDir, ".git");
104
+ try {
105
+ if (fs.existsSync(gitDir)) {
106
+ timer.end(`\u2713 Found git root at depth ${depth}: ${currentDir}`);
107
+ return currentDir;
108
+ }
109
+ } catch (err) {
110
+ log.debug(`Error checking .git directory at ${currentDir}`, {
111
+ error: err.message
112
+ });
113
+ }
114
+ const parentDir = path.dirname(currentDir);
115
+ if (parentDir === currentDir) {
116
+ log.debug("Reached filesystem root");
117
+ break;
118
+ }
119
+ currentDir = parentDir;
120
+ depth++;
121
+ }
122
+ timer.end(`\u2716 No git root found after ${depth} levels, using start directory`);
123
+ return startDir;
124
+ }
125
+ async function checkCliInstalled(bin) {
126
+ const timer = new PerformanceTimer(`checkCliInstalled:${bin}`);
127
+ return new Promise((resolve) => {
128
+ const proc = spawn(bin, ["--version"], { stdio: "ignore", shell: true });
129
+ proc.on("close", (code) => {
130
+ const installed = code === 0;
131
+ timer.end(installed ? `\u2713 ${bin} is installed` : `\u2716 ${bin} not found`);
132
+ resolve(installed);
133
+ });
134
+ proc.on("error", (err) => {
135
+ log.debug(`Failed to check ${bin} installation`, { error: err.message });
136
+ timer.end("\u2716 Check failed");
137
+ resolve(false);
138
+ });
139
+ });
140
+ }
141
+ function getCliVersion(bin) {
142
+ return new Promise((resolve) => {
143
+ const proc = spawn(bin, ["--version"], { stdio: "pipe", shell: true });
144
+ let output = "";
145
+ proc.stdout?.on("data", (data) => {
146
+ output += data.toString();
147
+ });
148
+ proc.on("close", (code) => {
149
+ resolve(code === 0 && output.trim() ? output.trim() : null);
150
+ });
151
+ proc.on("error", () => resolve(null));
152
+ });
153
+ }
154
+ function killOrphanCliProcesses(bin, options) {
155
+ const label = options.label ?? bin;
156
+ const timeoutMs = options.timeout ?? 5e3;
157
+ const timer = new PerformanceTimer(`killOrphanCliProcesses:${label}`);
158
+ log.debug(`Looking for orphan ${label} processes (PPID=1)`);
159
+ return new Promise((resolve) => {
160
+ let settled = false;
161
+ const done = (count) => {
162
+ if (!settled) {
163
+ settled = true;
164
+ resolve(count);
165
+ }
166
+ };
167
+ const timeout = setTimeout(() => {
168
+ log.warn(`Kill orphan ${label} processes timed out, skipping`);
169
+ timer.end("\u26A0 Timeout, skipped");
170
+ done(0);
171
+ }, timeoutMs);
172
+ const wrappedResolve = (count) => {
173
+ clearTimeout(timeout);
174
+ done(count);
175
+ };
176
+ if (process.platform === "win32") {
177
+ killOrphansOnWindows(wrappedResolve, options, label, timer);
178
+ } else {
179
+ killOrphansOnUnix(wrappedResolve, options, label, timer);
180
+ }
181
+ });
182
+ }
183
+ function killOrphansOnWindows(resolve, options, label, timer) {
184
+ log.debug(`Using Windows method to find orphan ${label} processes`);
185
+ const proc = spawn(
186
+ "wmic",
187
+ ["process", "where", `name="${options.winName}"`, "get", "processid,parentprocessid,commandline"],
188
+ { stdio: "pipe" }
189
+ );
190
+ let output = "";
191
+ proc.stdout?.on("data", (data) => {
192
+ output += data.toString();
193
+ });
194
+ proc.on("close", () => {
195
+ const pidsToKill = [];
196
+ output.split("\n").forEach((rawLine) => {
197
+ const line = rawLine.trim();
198
+ if (!line.includes(options.match)) return;
199
+ const parts = line.split(/\s+/);
200
+ if (parts.length >= 3) {
201
+ const ppid = parts[0];
202
+ const pid = parts[1];
203
+ if (ppid === "1" && pid && !Number.isNaN(Number(pid))) pidsToKill.push(pid);
204
+ }
205
+ });
206
+ finishOrphanKillWindows(pidsToKill, resolve, label, timer);
207
+ });
208
+ proc.on("error", (err) => {
209
+ log.debug(`Failed to find orphan ${label} processes`, { error: err.message });
210
+ timer.end("\u2716 Failed to find orphan processes");
211
+ resolve(0);
212
+ });
213
+ }
214
+ function finishOrphanKillWindows(pidsToKill, resolve, label, timer) {
215
+ if (pidsToKill.length === 0) {
216
+ log.debug("No orphan processes found");
217
+ timer.end("No orphan processes found");
218
+ resolve(0);
219
+ return;
220
+ }
221
+ log.debug(`Found ${pidsToKill.length} orphan processes`, { pids: pidsToKill });
222
+ let killedCount = 0;
223
+ let completedCount = 0;
224
+ pidsToKill.forEach((pid) => {
225
+ const killProc = spawn("taskkill", ["/F", "/PID", pid], { stdio: "ignore" });
226
+ killProc.on("close", (code) => {
227
+ completedCount++;
228
+ if (code === 0) killedCount++;
229
+ if (completedCount === pidsToKill.length) {
230
+ timer.end(`\u2713 Killed ${killedCount} orphan ${label} processes`);
231
+ resolve(killedCount);
232
+ }
233
+ });
234
+ });
235
+ }
236
+ function killOrphansOnUnix(resolve, options, label, timer) {
237
+ log.debug(`Using Unix method to find orphan ${label} processes`);
238
+ const proc = spawn("ps", ["-e", "-o", "pid,ppid,args"], { stdio: "pipe" });
239
+ let output = "";
240
+ proc.stdout?.on("data", (data) => {
241
+ output += data.toString();
242
+ });
243
+ proc.on("close", () => {
244
+ const pidsToKill = [];
245
+ output.split("\n").forEach((line) => {
246
+ if (!line.includes(options.match)) return;
247
+ const parts = line.trim().split(/\s+/);
248
+ if (parts.length >= 3) {
249
+ const pid = parts[0];
250
+ const ppid = parts[1];
251
+ if (ppid === "1" && pid && !Number.isNaN(Number(pid))) pidsToKill.push(pid);
252
+ }
253
+ });
254
+ if (pidsToKill.length === 0) {
255
+ log.debug("No orphan processes found");
256
+ timer.end("No orphan processes found");
257
+ resolve(0);
258
+ return;
259
+ }
260
+ log.debug(`Found ${pidsToKill.length} orphan processes`, { pids: pidsToKill });
261
+ const killProc = spawn("kill", ["-9", ...pidsToKill], { stdio: "ignore" });
262
+ killProc.on("close", (code) => {
263
+ const killedCount = code === 0 ? pidsToKill.length : 0;
264
+ timer.end(
265
+ killedCount > 0 ? `\u2713 Killed ${killedCount} orphan ${label} processes` : "\u2716 Failed to kill processes"
266
+ );
267
+ resolve(killedCount);
268
+ });
269
+ killProc.on("error", () => {
270
+ timer.end("\u2716 Failed to kill processes");
271
+ resolve(0);
272
+ });
273
+ });
274
+ proc.on("error", (err) => {
275
+ log.debug(`Failed to find orphan ${label} processes`, { error: err.message });
276
+ timer.end("\u2716 Failed to find orphan processes");
277
+ resolve(0);
278
+ });
279
+ }
50
280
  export {
51
281
  checkChromeDevToolsAvailable,
282
+ checkCliInstalled,
52
283
  createPackageRequire,
53
284
  findAvailablePort,
285
+ findGitRoot,
286
+ getCliVersion,
54
287
  isPortAvailable,
55
- resolvePackageDir
288
+ killOrphanCliProcesses,
289
+ resolvePackageDir,
290
+ waitForServer
56
291
  };
@@ -23,13 +23,6 @@ __export(logger_exports, {
23
23
  module.exports = __toCommonJS(logger_exports);
24
24
  var import_constants = require("../common/constants.cjs");
25
25
  var import_logger_core = require("../common/logger-core.cjs");
26
- const LEVEL_NAMES = {
27
- [import_logger_core.LogLevel.DEBUG]: "DEBUG",
28
- [import_logger_core.LogLevel.INFO]: "INFO ",
29
- [import_logger_core.LogLevel.WARN]: "WARN ",
30
- [import_logger_core.LogLevel.ERROR]: "ERROR",
31
- [import_logger_core.LogLevel.NONE]: "NONE "
32
- };
33
26
  const C = {
34
27
  dim: "color: #888",
35
28
  bright: "font-weight: bold",
@@ -56,7 +49,7 @@ function log(level, message, context, ...args) {
56
49
  segments.push("%c%s");
57
50
  styles.push(C.dim, (0, import_logger_core.getTimestamp)());
58
51
  }
59
- segments.push(`%c${LEVEL_NAMES[level]}`);
52
+ segments.push(`%c${import_logger_core.LEVEL_NAMES[level].padEnd(5)}`);
60
53
  styles.push(LEVEL_COLORS[level]);
61
54
  segments.push(`%c${import_constants.LOG_PREFIX}`);
62
55
  styles.push(C.bright);
@@ -0,0 +1,58 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var storage_exports = {};
19
+ __export(storage_exports, {
20
+ storageGet: () => storageGet,
21
+ storageRemove: () => storageRemove,
22
+ storageSet: () => storageSet
23
+ });
24
+ module.exports = __toCommonJS(storage_exports);
25
+ function storageArea(area) {
26
+ try {
27
+ if (typeof window === "undefined") return void 0;
28
+ return area === "local" ? window.localStorage : window.sessionStorage;
29
+ } catch {
30
+ return void 0;
31
+ }
32
+ }
33
+ function storageGet(area, key) {
34
+ try {
35
+ const raw = storageArea(area)?.getItem(key);
36
+ return raw == null ? null : JSON.parse(raw);
37
+ } catch {
38
+ return null;
39
+ }
40
+ }
41
+ function storageSet(area, key, value) {
42
+ try {
43
+ storageArea(area)?.setItem(key, JSON.stringify(value));
44
+ } catch {
45
+ }
46
+ }
47
+ function storageRemove(area, key) {
48
+ try {
49
+ storageArea(area)?.removeItem(key);
50
+ } catch {
51
+ }
52
+ }
53
+ // Annotate the CommonJS export names for ESM import in node:
54
+ 0 && (module.exports = {
55
+ storageGet,
56
+ storageRemove,
57
+ storageSet
58
+ });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 浏览器存储辅助(window.localStorage/sessionStorage,仅 client 端;通过 @aipanel/core/client 导出)
3
+ */
4
+ /**
5
+ * 安全读取浏览器存储(JSON 解码;不可用/异常返回 null)
6
+ */
7
+ export declare function storageGet<T>(area: "local" | "session", key: string): T | null;
8
+ /**
9
+ * 安全写入浏览器存储(JSON 序列化;异常忽略)
10
+ */
11
+ export declare function storageSet(area: "local" | "session", key: string, value: unknown): void;
12
+ /**
13
+ * 安全删除浏览器存储项
14
+ */
15
+ export declare function storageRemove(area: "local" | "session", key: string): void;
@@ -0,0 +1,35 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var theme_exports = {};
19
+ __export(theme_exports, {
20
+ getSystemTheme: () => getSystemTheme,
21
+ resolveWidgetTheme: () => resolveWidgetTheme
22
+ });
23
+ module.exports = __toCommonJS(theme_exports);
24
+ function getSystemTheme() {
25
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return "light";
26
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
27
+ }
28
+ function resolveWidgetTheme(theme, system = getSystemTheme()) {
29
+ return theme === "auto" ? system : theme;
30
+ }
31
+ // Annotate the CommonJS export names for ESM import in node:
32
+ 0 && (module.exports = {
33
+ getSystemTheme,
34
+ resolveWidgetTheme
35
+ });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 浏览器主题辅助(依赖 window.matchMedia,仅 client 端使用;通过 @aipanel/core/client 导出)
3
+ */
4
+ import type { AIPanelWidgetTheme } from "../common/types";
5
+ /**
6
+ * 当前系统主题(仅浏览器有效;SSR/无 window 环境返回 light)
7
+ */
8
+ export declare function getSystemTheme(): "light" | "dark";
9
+ /**
10
+ * 挂件主题偏好解析:auto 按系统主题折算为 light/dark
11
+ * @param theme - 挂件主题偏好(AIPanelWidgetTheme)
12
+ * @param system - 系统主题(默认当前系统)
13
+ * @returns 实际应用主题
14
+ */
15
+ export declare function resolveWidgetTheme(theme: AIPanelWidgetTheme, system?: "light" | "dark"): "light" | "dark";
package/lib/client.cjs CHANGED
@@ -15,7 +15,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
15
15
  var client_exports = {};
16
16
  module.exports = __toCommonJS(client_exports);
17
17
  __reExport(client_exports, require("./client/logger.cjs"), module.exports);
18
+ __reExport(client_exports, require("./client/storage.cjs"), module.exports);
19
+ __reExport(client_exports, require("./client/theme.cjs"), module.exports);
18
20
  // Annotate the CommonJS export names for ESM import in node:
19
21
  0 && (module.exports = {
20
- ...require("./client/logger.cjs")
22
+ ...require("./client/logger.cjs"),
23
+ ...require("./client/storage.cjs"),
24
+ ...require("./client/theme.cjs")
21
25
  });
package/lib/client.d.ts CHANGED
@@ -1 +1,3 @@
1
1
  export * from "./client/logger";
2
+ export * from "./client/storage";
3
+ export * from "./client/theme";
@@ -30,8 +30,6 @@ __export(constants_exports, {
30
30
  DEFAULT_PROXY_PORT: () => DEFAULT_PROXY_PORT,
31
31
  DEFAULT_RETRIES: () => DEFAULT_RETRIES,
32
32
  DEFAULT_WEB_PORT: () => DEFAULT_WEB_PORT,
33
- ENV_VSCODE_MODE: () => ENV_VSCODE_MODE,
34
- ENV_VSCODE_PORT: () => ENV_VSCODE_PORT,
35
33
  EXT_BROADCAST: () => EXT_BROADCAST,
36
34
  EXT_MSG: () => EXT_MSG,
37
35
  HOST_EVENTS_API_PATH: () => HOST_EVENTS_API_PATH,
@@ -42,7 +40,9 @@ __export(constants_exports, {
42
40
  MAX_PORT_TRIES: () => MAX_PORT_TRIES,
43
41
  MAX_TEXT_LENGTH: () => MAX_TEXT_LENGTH,
44
42
  MCP_API_PATH: () => MCP_API_PATH,
43
+ MUTATING_TOOLS: () => MUTATING_TOOLS,
45
44
  NOTIFICATION_DURATION: () => NOTIFICATION_DURATION,
45
+ OPENCODE_ENV: () => OPENCODE_ENV,
46
46
  PAGE_CONTEXT_MARKER: () => PAGE_CONTEXT_MARKER,
47
47
  PAGE_CONTEXT_MAX_TEXT_LENGTH: () => PAGE_CONTEXT_MAX_TEXT_LENGTH,
48
48
  RETRY_DELAY: () => RETRY_DELAY,
@@ -55,15 +55,15 @@ __export(constants_exports, {
55
55
  SEVERITY_ERROR: () => SEVERITY_ERROR,
56
56
  SEVERITY_WARN: () => SEVERITY_WARN,
57
57
  SSE_EVENTS_PATH: () => SSE_EVENTS_PATH,
58
+ SSE_EVENT_TYPES: () => SSE_EVENT_TYPES,
58
59
  START_API_PATH: () => START_API_PATH,
59
- VSCODE_EXTENSION_PORT: () => VSCODE_EXTENSION_PORT,
60
- VSCODE_ROUTE_FORMAT: () => VSCODE_ROUTE_FORMAT,
61
- VSCODE_ROUTE_HEALTH: () => VSCODE_ROUTE_HEALTH,
62
60
  VUE_DEVTOOLS_ACTIONS: () => VUE_DEVTOOLS_ACTIONS,
61
+ VUE_DEVTOOLS_API_PATH: () => VUE_DEVTOOLS_API_PATH,
63
62
  WARMUP_API_PATH: () => WARMUP_API_PATH,
64
63
  WIDGET_MSG: () => WIDGET_MSG,
65
64
  WIDGET_SCRIPT_PATH: () => WIDGET_SCRIPT_PATH,
66
- WIDGET_STYLE_PATH: () => WIDGET_STYLE_PATH
65
+ WIDGET_STYLE_PATH: () => WIDGET_STYLE_PATH,
66
+ WIDGET_THEME_MODES: () => WIDGET_THEME_MODES
67
67
  });
68
68
  module.exports = __toCommonJS(constants_exports);
69
69
  const DEFAULT_HOSTNAME = "127.0.0.1";
@@ -134,17 +134,13 @@ const WARMUP_API_PATH = "/__aipanel_warmup__";
134
134
  const BRIDGE_SCRIPT_PATH = "/__aipanel_bridge__.js";
135
135
  const LOGS_API_PATH = "/__aipanel_process_logs__";
136
136
  const WIDGET_STYLE_PATH = "/__aipanel_widget__.css";
137
+ const VUE_DEVTOOLS_API_PATH = "/__aipanel_vue_devtools__";
137
138
  const MAX_TEXT_LENGTH = 100;
138
139
  const CONTEXT_MARKER = "[\u5143\u7D20\u4E0A\u4E0B\u6587]";
139
140
  const PAGE_CONTEXT_MARKER = "__AIPANEL_CONTEXT__";
140
141
  const PAGE_CONTEXT_MAX_TEXT_LENGTH = 1e4;
141
142
  const SEVERITY_ERROR = 1;
142
143
  const SEVERITY_WARN = 2;
143
- const VSCODE_EXTENSION_PORT = 51939;
144
- const VSCODE_ROUTE_HEALTH = "/health";
145
- const VSCODE_ROUTE_FORMAT = "/format";
146
- const ENV_VSCODE_MODE = "AIPANEL_VSCODE_MODE";
147
- const ENV_VSCODE_PORT = "AIPANEL_VSCODE_PORT";
148
144
  const VUE_DEVTOOLS_ACTIONS = {
149
145
  GET_COMPONENT_TREE: "getComponentTree",
150
146
  GET_COMPONENT_STATE: "getComponentState",
@@ -153,6 +149,25 @@ const VUE_DEVTOOLS_ACTIONS = {
153
149
  TOGGLE_APP: "toggleApp",
154
150
  GET_ROUTER_INFO: "getRouterInfo"
155
151
  };
152
+ const MUTATING_TOOLS = /* @__PURE__ */ new Set(["write", "edit", "apply_patch"]);
153
+ const WIDGET_THEME_MODES = ["auto", "light", "dark"];
154
+ const OPENCODE_ENV = {
155
+ CONFIG_DIR: "OPENCODE_CONFIG_DIR",
156
+ CONTEXT_API_URL: "OPENCODE_CONTEXT_API_URL",
157
+ VITE_LOGS_API_URL: "OPENCODE_VITE_LOGS_API_URL",
158
+ LOG_FILES_JSON: "OPENCODE_LOG_FILES_JSON",
159
+ VERBOSE: "OPENCODE_VERBOSE",
160
+ ENABLE_LINT: "OPENCODE_ENABLE_LINT",
161
+ VUE_DEVTOOLS_API_URL: "OPENCODE_VUE_DEVTOOLS_API_URL",
162
+ WORKSPACE: "OPENCODE_WORKSPACE"
163
+ };
164
+ const SSE_EVENT_TYPES = {
165
+ CONNECTED: "CONNECTED",
166
+ STATUS_SYNC: "STATUS_SYNC",
167
+ TASK_UPDATE: "TASK_UPDATE",
168
+ SESSION_EVENT: "SESSION_EVENT",
169
+ CLEAR_ELEMENTS: "CLEAR_ELEMENTS"
170
+ };
156
171
  // Annotate the CommonJS export names for ESM import in node:
157
172
  0 && (module.exports = {
158
173
  AIPANEL_CACHE_DIR,
@@ -168,8 +183,6 @@ const VUE_DEVTOOLS_ACTIONS = {
168
183
  DEFAULT_PROXY_PORT,
169
184
  DEFAULT_RETRIES,
170
185
  DEFAULT_WEB_PORT,
171
- ENV_VSCODE_MODE,
172
- ENV_VSCODE_PORT,
173
186
  EXT_BROADCAST,
174
187
  EXT_MSG,
175
188
  HOST_EVENTS_API_PATH,
@@ -180,7 +193,9 @@ const VUE_DEVTOOLS_ACTIONS = {
180
193
  MAX_PORT_TRIES,
181
194
  MAX_TEXT_LENGTH,
182
195
  MCP_API_PATH,
196
+ MUTATING_TOOLS,
183
197
  NOTIFICATION_DURATION,
198
+ OPENCODE_ENV,
184
199
  PAGE_CONTEXT_MARKER,
185
200
  PAGE_CONTEXT_MAX_TEXT_LENGTH,
186
201
  RETRY_DELAY,
@@ -193,13 +208,13 @@ const VUE_DEVTOOLS_ACTIONS = {
193
208
  SEVERITY_ERROR,
194
209
  SEVERITY_WARN,
195
210
  SSE_EVENTS_PATH,
211
+ SSE_EVENT_TYPES,
196
212
  START_API_PATH,
197
- VSCODE_EXTENSION_PORT,
198
- VSCODE_ROUTE_FORMAT,
199
- VSCODE_ROUTE_HEALTH,
200
213
  VUE_DEVTOOLS_ACTIONS,
214
+ VUE_DEVTOOLS_API_PATH,
201
215
  WARMUP_API_PATH,
202
216
  WIDGET_MSG,
203
217
  WIDGET_SCRIPT_PATH,
204
- WIDGET_STYLE_PATH
218
+ WIDGET_STYLE_PATH,
219
+ WIDGET_THEME_MODES
205
220
  });
@@ -122,6 +122,8 @@ export declare const BRIDGE_SCRIPT_PATH = "/__aipanel_bridge__.js";
122
122
  export declare const LOGS_API_PATH = "/__aipanel_process_logs__";
123
123
  /** Widget 样式路径 */
124
124
  export declare const WIDGET_STYLE_PATH = "/__aipanel_widget__.css";
125
+ /** Vue DevTools API 路径 */
126
+ export declare const VUE_DEVTOOLS_API_PATH = "/__aipanel_vue_devtools__";
125
127
  /** ==================== 文本处理 ==================== */
126
128
  /** 元素文本最大显示长度 */
127
129
  export declare const MAX_TEXT_LENGTH = 100;
@@ -138,16 +140,6 @@ export declare const PAGE_CONTEXT_MAX_TEXT_LENGTH = 10000;
138
140
  */
139
141
  export declare const SEVERITY_ERROR = 1;
140
142
  export declare const SEVERITY_WARN = 2;
141
- /** ==================== VS Code 扩展桥接 ==================== */
142
- /** VS Code 扩展 HTTP 服务端口(vscode-extension ↔ provider 通信协议) */
143
- export declare const VSCODE_EXTENSION_PORT = 51939;
144
- /** VS Code 扩展 HTTP 路由:健康检查 */
145
- export declare const VSCODE_ROUTE_HEALTH = "/health";
146
- /** VS Code 扩展 HTTP 路由:文件格式化 */
147
- export declare const VSCODE_ROUTE_FORMAT = "/format";
148
- /** VS Code 扩展相关环境变量名 */
149
- export declare const ENV_VSCODE_MODE = "AIPANEL_VSCODE_MODE";
150
- export declare const ENV_VSCODE_PORT = "AIPANEL_VSCODE_PORT";
151
143
  /** ==================== Vue DevTools API ==================== */
152
144
  /** Vue DevTools API action 名称 */
153
145
  export declare const VUE_DEVTOOLS_ACTIONS: {
@@ -159,3 +151,31 @@ export declare const VUE_DEVTOOLS_ACTIONS: {
159
151
  readonly GET_ROUTER_INFO: "getRouterInfo";
160
152
  };
161
153
  export type VueDevtoolsAction = (typeof VUE_DEVTOOLS_ACTIONS)[keyof typeof VUE_DEVTOOLS_ACTIONS];
154
+ /** ==================== 写类工具名单 ==================== */
155
+ /** 会修改文件的工具名(host 插件与编辑后自动诊断共用的单一来源) */
156
+ export declare const MUTATING_TOOLS: ReadonlySet<string>;
157
+ /** ==================== 挂件主题 ==================== */
158
+ /** 挂件主题可选值(对应 AIPanelWidgetTheme) */
159
+ export declare const WIDGET_THEME_MODES: readonly ["auto", "light", "dark"];
160
+ /** ==================== OpenCode 环境变量名 ==================== */
161
+ /** OpenCode 相关环境变量名(opencode provider 写、es/plugins 与 dsh-plugin 读,统一引用防止字面量漂移) */
162
+ export declare const OPENCODE_ENV: {
163
+ readonly CONFIG_DIR: "OPENCODE_CONFIG_DIR";
164
+ readonly CONTEXT_API_URL: "OPENCODE_CONTEXT_API_URL";
165
+ readonly VITE_LOGS_API_URL: "OPENCODE_VITE_LOGS_API_URL";
166
+ readonly LOG_FILES_JSON: "OPENCODE_LOG_FILES_JSON";
167
+ readonly VERBOSE: "OPENCODE_VERBOSE";
168
+ readonly ENABLE_LINT: "OPENCODE_ENABLE_LINT";
169
+ readonly VUE_DEVTOOLS_API_URL: "OPENCODE_VUE_DEVTOOLS_API_URL";
170
+ readonly WORKSPACE: "OPENCODE_WORKSPACE";
171
+ };
172
+ /** ==================== SSE 事件流消息类型 ==================== */
173
+ /** 服务端 → 客户端 SSE 信封 type 字段(vite endpoints 写、client useServerSSE 读) */
174
+ export declare const SSE_EVENT_TYPES: {
175
+ readonly CONNECTED: "CONNECTED";
176
+ readonly STATUS_SYNC: "STATUS_SYNC";
177
+ readonly TASK_UPDATE: "TASK_UPDATE";
178
+ readonly SESSION_EVENT: "SESSION_EVENT";
179
+ readonly CLEAR_ELEMENTS: "CLEAR_ELEMENTS";
180
+ };
181
+ export type SSEEventType = (typeof SSE_EVENT_TYPES)[keyof typeof SSE_EVENT_TYPES];
@@ -16,6 +16,30 @@ export interface ChromeMcpOptions {
16
16
  args?: string[];
17
17
  /** 透传给 chrome-devtools-mcp 进程的额外环境变量(合并到 process.env 之上) */
18
18
  env?: Record<string, string>;
19
+ /** 项目边界策略(默认缺失 = 现状行为) */
20
+ project?: ChromeProjectOptions;
21
+ }
22
+ /**
23
+ * 项目边界策略(chrome-devtools-mcp 工具层的“本项目内操作”可配选项,默认均为现状)。
24
+ * 所有项只会收窄/放宽我们的边界判定,不改变白名单的权威性。
25
+ */
26
+ export interface ChromeProjectOptions {
27
+ /**
28
+ * 白名单条目:除自动项目页外,可开启/可见/可操作的额外页面。每条三种写法:
29
+ * - 精确 origin:"https://example.com"(前缀匹配该 origin 下任意路径)
30
+ * - glob 通配符:"https://*.example.com/**"(picomatch,* 不跨 /,放开路径需 /**)
31
+ * - 正则字面量:"/^https:\\/\\/app\\.example\\.com\\//"(以 / 起止、可带 flags,对完整 URL 匹配)
32
+ */
33
+ allowOrigins?: string[];
34
+ /** 是否允许扩展页(chrome-extension://)纳入可操作页面;启用时自动注入 --experimental-include-all-pages */
35
+ includeExtensionPages?: boolean;
36
+ /** 工具面选择:在默认白名单上按名字调整 */
37
+ tools?: {
38
+ /** 从默认白名单隐藏(如 ["upload_file"]) */
39
+ deny?: string[];
40
+ /** 仅可开启官方二级目录中的工具(如 click_at);非目录名将被忽略并告警 */
41
+ extra?: string[];
42
+ };
19
43
  }
20
44
  /**
21
45
  * 插件配置选项
@@ -26,6 +26,8 @@ export interface ChatSession {
26
26
  }
27
27
  /** 会话运行状态 */
28
28
  export type SessionStatus = "idle" | "running" | "streaming" | "completed";
29
+ /** 会话等待用户交互的类型(对齐 dsh host approval/request 与 user-questions/request) */
30
+ export type SessionPendingKind = "approval" | "plan-review" | "question";
29
31
  /** Provider 事件(Provider 私有事件 → 归一化,客户端只消费这些事件) */
30
32
  export type ProviderEvent = {
31
33
  type: "connected";
@@ -46,6 +48,19 @@ export type ProviderEvent = {
46
48
  type: "thinking";
47
49
  sessionId: string;
48
50
  thinking: boolean;
51
+ }
52
+ /** 会话等待用户交互(审批/提问/计划评审)开始或结束 */
53
+ | {
54
+ type: "session.pending";
55
+ sessionId: string;
56
+ pending: boolean;
57
+ kind?: SessionPendingKind;
58
+ }
59
+ /** 父会话的进行中子代理数(>0 表示有子代理在跑;自身 idle 时 UI 仍显示进行中) */
60
+ | {
61
+ type: "session.subagents";
62
+ sessionId: string;
63
+ running: number;
49
64
  };
50
65
  /** Provider 环境检查结果 */
51
66
  export interface ProviderEnvironmentInfo {