@aipanel/core 1.2.9 → 1.2.10
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/client/logger.mjs +2 -8
- package/es/client/storage.d.ts +15 -0
- package/es/client/storage.mjs +33 -0
- package/es/client/theme.d.ts +15 -0
- package/es/client/theme.mjs +11 -0
- package/es/client.d.ts +2 -0
- package/es/client.mjs +2 -0
- package/es/common/constants.d.ts +30 -10
- package/es/common/constants.mjs +26 -11
- package/es/common/options.d.ts +24 -0
- package/es/common/types.d.ts +5 -14
- package/es/common/utils.d.ts +26 -3
- package/es/common/utils.mjs +42 -1
- package/es/node/diagnostics.d.ts +5 -0
- package/es/node/diagnostics.mjs +24 -2
- package/es/node/node-logger.mjs +2 -15
- package/es/node/node-utils.d.ts +41 -0
- package/es/node/node-utils.mjs +237 -2
- package/lib/client/logger.cjs +1 -8
- package/lib/client/storage.cjs +58 -0
- package/lib/client/storage.d.ts +15 -0
- package/lib/client/theme.cjs +35 -0
- package/lib/client/theme.d.ts +15 -0
- package/lib/client.cjs +5 -1
- package/lib/client.d.ts +2 -0
- package/lib/common/constants.cjs +32 -17
- package/lib/common/constants.d.ts +30 -10
- package/lib/common/options.d.ts +24 -0
- package/lib/common/types.d.ts +5 -14
- package/lib/common/utils.cjs +47 -2
- package/lib/common/utils.d.ts +26 -3
- package/lib/node/diagnostics.cjs +25 -2
- package/lib/node/diagnostics.d.ts +5 -0
- package/lib/node/node-logger.cjs +2 -17
- package/lib/node/node-utils.cjs +238 -2
- package/lib/node/node-utils.d.ts +41 -0
- package/package.json +1 -1
package/es/node/node-utils.mjs
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
288
|
+
killOrphanCliProcesses,
|
|
289
|
+
resolvePackageDir,
|
|
290
|
+
waitForServer
|
|
56
291
|
};
|
package/lib/client/logger.cjs
CHANGED
|
@@ -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
package/lib/common/constants.cjs
CHANGED
|
@@ -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];
|
package/lib/common/options.d.ts
CHANGED
|
@@ -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
|
* 插件配置选项
|
package/lib/common/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* 通用类型(Provider 无关)
|
|
3
3
|
* Provider 专属类型已下沉至 @aipanel/provider-opencode。
|
|
4
4
|
*/
|
|
5
|
+
import type { SessionStatus } from "./provider";
|
|
5
6
|
/**
|
|
6
7
|
* 展示模式类型
|
|
7
8
|
*/
|
|
@@ -123,9 +124,9 @@ export type AIPanelWidgetTheme = "light" | "dark" | "auto";
|
|
|
123
124
|
*/
|
|
124
125
|
export type ServiceStatus = "idle" | "starting" | "ready" | "partial" | "failed";
|
|
125
126
|
/**
|
|
126
|
-
* Session
|
|
127
|
+
* Session 状态类型(别名:以 ./provider 的 SessionStatus 为单一来源)
|
|
127
128
|
*/
|
|
128
|
-
export type AIPanelSessionStatusType =
|
|
129
|
+
export type AIPanelSessionStatusType = SessionStatus;
|
|
129
130
|
/**
|
|
130
131
|
* Session 思考状态
|
|
131
132
|
*/
|
|
@@ -146,19 +147,9 @@ export interface AIPanelWidgetSession {
|
|
|
146
147
|
url?: string;
|
|
147
148
|
}
|
|
148
149
|
/**
|
|
149
|
-
*
|
|
150
|
+
* 挂件选中的元素(别名:与 host 端 SelectedElement 同构,单一来源为本文件上方的 SelectedElement)
|
|
150
151
|
*/
|
|
151
|
-
export
|
|
152
|
-
/** 节点唯一 id(与 SelectedElement.id 同源,`@节点[n<id>]` 标记与上下文注入共用) */
|
|
153
|
-
id?: string;
|
|
154
|
-
filePath: string | null;
|
|
155
|
-
line: number | null;
|
|
156
|
-
column: number | null;
|
|
157
|
-
innerText: string;
|
|
158
|
-
description?: string;
|
|
159
|
-
/** 用户选中节点时的页面 URL(AIPanel 附加;host 端上下文注入用) */
|
|
160
|
-
previewPageUrl?: string;
|
|
161
|
-
}
|
|
152
|
+
export type AIPanelSelectedElement = SelectedElement;
|
|
162
153
|
/**
|
|
163
154
|
* 单条代码诊断(1-based 行列坐标)——AIPanel 诊断工具(run_diagnostics 等)的
|
|
164
155
|
* canonical 持久化/展示共用协议:宿主插件写 tool/result.meta,client 插件据此渲染卡片。
|