@aipanel/core 1.3.8 → 1.3.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/common/constants.d.ts +17 -1
- package/es/common/constants.mjs +9 -1
- package/es/common/diagnostics.mjs +2 -1
- package/es/common/inspector/vue.mjs +3 -3
- package/es/common/types.d.ts +7 -1
- package/es/common/utils.d.ts +30 -0
- package/es/common/utils.mjs +19 -1
- package/es/node/node-logger.mjs +2 -1
- package/lib/common/constants.cjs +11 -1
- package/lib/common/constants.d.ts +17 -1
- package/lib/common/diagnostics.cjs +2 -1
- package/lib/common/inspector/vue.cjs +3 -3
- package/lib/common/types.d.ts +7 -1
- package/lib/common/utils.cjs +22 -0
- package/lib/common/utils.d.ts +30 -0
- package/lib/node/node-logger.cjs +2 -1
- package/package.json +1 -1
package/es/common/constants.d.ts
CHANGED
|
@@ -56,7 +56,7 @@ export declare const NOTIFICATION_DURATION = 3000;
|
|
|
56
56
|
export declare const INIT_MARKER = "__AIPANEL_INITIALIZED__";
|
|
57
57
|
/** 选中元素存储键 */
|
|
58
58
|
export declare const SELECTED_ELEMENTS_KEY = "__aipanel_selected_elements__";
|
|
59
|
-
/**
|
|
59
|
+
/** 页内会话标识键(sessionStorage,跨导航标识同一 Tab 的页面上下文) */
|
|
60
60
|
export declare const SESSION_ID_KEY = "_aipanel_pk";
|
|
61
61
|
/** ==================== 缓存目录 ==================== */
|
|
62
62
|
/**
|
|
@@ -64,6 +64,18 @@ export declare const SESSION_ID_KEY = "_aipanel_pk";
|
|
|
64
64
|
* 存放 opencode.json、dsh overlay 等运行时状态,不污染项目根目录。
|
|
65
65
|
*/
|
|
66
66
|
export declare const AIPANEL_CACHE_DIR = "node_modules/.cache/aipanel";
|
|
67
|
+
/** ==================== 源码路径 ==================== */
|
|
68
|
+
/**
|
|
69
|
+
* 依赖安装目录名(判定文件是否来自依赖包的唯一依据)。
|
|
70
|
+
* 宿主侧上下文归一化与两个 Provider 的注入文案共用,避免各写一份 magic string。
|
|
71
|
+
*/
|
|
72
|
+
export declare const DEPENDENCY_DIR_NAME = "node_modules";
|
|
73
|
+
/**
|
|
74
|
+
* 依赖内部文件的归属提示(注入给 agent 的上下文文案)。
|
|
75
|
+
* 两个 Provider 共用同一措辞:agent 拿到 node_modules 路径时最容易顺着它去改第三方实现,
|
|
76
|
+
* 归属必须显式声明,而不是让「源码文件路径」这行字暗示它是项目源码。
|
|
77
|
+
*/
|
|
78
|
+
export declare const DEPENDENCY_SOURCE_NOTE = "\u4F9D\u8D56\u5305\u5185\u6587\u4EF6\uFF08node_modules\uFF09\uFF1A\u901A\u5E38\u4E0D\u5E94\u76F4\u63A5\u4FEE\u6539\uFF0C\u9875\u9762\u884C\u4E3A\u8BF7\u6539\u9879\u76EE\u5185\u6E90\u7801";
|
|
67
79
|
/** ==================== Chrome DevTools ==================== */
|
|
68
80
|
/** Chrome DevTools Protocol 默认端口 */
|
|
69
81
|
export declare const CHROME_DEVTOOLS_PORT = 9222;
|
|
@@ -84,6 +96,8 @@ export declare const EXT_MSG: {
|
|
|
84
96
|
readonly REQUEST_PAGE_CONTEXT: "REQUEST_PAGE_CONTEXT";
|
|
85
97
|
readonly SELECTION_START: "SELECTION_START";
|
|
86
98
|
readonly SELECTION_STOP: "SELECTION_STOP";
|
|
99
|
+
/** Side Panel → 目标 Tab:请目标页定位某个已选节点(跳回其页面并呼吸高亮) */
|
|
100
|
+
readonly LOCATE_NODE: "LOCATE_NODE";
|
|
87
101
|
readonly CS_QUERY_WINDOW: "__CS_QUERY_WINDOW__";
|
|
88
102
|
/** Side Panel → Background:立即轮询一次并回传当前服务信息 */
|
|
89
103
|
readonly FORCE_POLL: "FORCE_POLL";
|
|
@@ -118,6 +132,8 @@ export declare const WIDGET_MSG: {
|
|
|
118
132
|
readonly FOCUS_SESSION: "AIPANEL_FOCUS_SESSION";
|
|
119
133
|
/** 无 deepLink 能力的 Provider:iframe 确认目标会话已激活且渲染稳定(携带 sessionId) */
|
|
120
134
|
readonly SESSION_READY: "AIPANEL_SESSION_READY";
|
|
135
|
+
/** iframe → 宿主:点节点 chip 时把该节点交回挂件,跳回它被选中时的页面并闪烁高亮;载荷 { element } */
|
|
136
|
+
readonly LOCATE_NODE: "AIPANEL_LOCATE_NODE";
|
|
121
137
|
};
|
|
122
138
|
/** ==================== API 路径补充 ==================== */
|
|
123
139
|
/** Provider 预热 API 路径 */
|
package/es/common/constants.mjs
CHANGED
|
@@ -24,6 +24,8 @@ const INIT_MARKER = "__AIPANEL_INITIALIZED__";
|
|
|
24
24
|
const SELECTED_ELEMENTS_KEY = "__aipanel_selected_elements__";
|
|
25
25
|
const SESSION_ID_KEY = "_aipanel_pk";
|
|
26
26
|
const AIPANEL_CACHE_DIR = "node_modules/.cache/aipanel";
|
|
27
|
+
const DEPENDENCY_DIR_NAME = "node_modules";
|
|
28
|
+
const DEPENDENCY_SOURCE_NOTE = `\u4F9D\u8D56\u5305\u5185\u6587\u4EF6\uFF08${DEPENDENCY_DIR_NAME}\uFF09\uFF1A\u901A\u5E38\u4E0D\u5E94\u76F4\u63A5\u4FEE\u6539\uFF0C\u9875\u9762\u884C\u4E3A\u8BF7\u6539\u9879\u76EE\u5185\u6E90\u7801`;
|
|
27
29
|
const CHROME_DEVTOOLS_PORT = 9222;
|
|
28
30
|
const CHROME_DEVTOOLS_CHECK_TIMEOUT = 2e3;
|
|
29
31
|
const EXT_BROADCAST = {
|
|
@@ -39,6 +41,8 @@ const EXT_MSG = {
|
|
|
39
41
|
REQUEST_PAGE_CONTEXT: "REQUEST_PAGE_CONTEXT",
|
|
40
42
|
SELECTION_START: "SELECTION_START",
|
|
41
43
|
SELECTION_STOP: "SELECTION_STOP",
|
|
44
|
+
/** Side Panel → 目标 Tab:请目标页定位某个已选节点(跳回其页面并呼吸高亮) */
|
|
45
|
+
LOCATE_NODE: "LOCATE_NODE",
|
|
42
46
|
CS_QUERY_WINDOW: "__CS_QUERY_WINDOW__",
|
|
43
47
|
/** Side Panel → Background:立即轮询一次并回传当前服务信息 */
|
|
44
48
|
FORCE_POLL: "FORCE_POLL"
|
|
@@ -66,7 +70,9 @@ const WIDGET_MSG = {
|
|
|
66
70
|
/** 无 deepLink 能力的 Provider:通知 iframe 聚焦指定会话 */
|
|
67
71
|
FOCUS_SESSION: "AIPANEL_FOCUS_SESSION",
|
|
68
72
|
/** 无 deepLink 能力的 Provider:iframe 确认目标会话已激活且渲染稳定(携带 sessionId) */
|
|
69
|
-
SESSION_READY: "AIPANEL_SESSION_READY"
|
|
73
|
+
SESSION_READY: "AIPANEL_SESSION_READY",
|
|
74
|
+
/** iframe → 宿主:点节点 chip 时把该节点交回挂件,跳回它被选中时的页面并闪烁高亮;载荷 { element } */
|
|
75
|
+
LOCATE_NODE: "AIPANEL_LOCATE_NODE"
|
|
70
76
|
};
|
|
71
77
|
const WARMUP_API_PATH = "/__aipanel_warmup__";
|
|
72
78
|
const BRIDGE_SCRIPT_PATH = "/__aipanel_bridge__.js";
|
|
@@ -160,6 +166,8 @@ export {
|
|
|
160
166
|
DEFAULT_PROXY_PORT,
|
|
161
167
|
DEFAULT_RETRIES,
|
|
162
168
|
DEFAULT_WEB_PORT,
|
|
169
|
+
DEPENDENCY_DIR_NAME,
|
|
170
|
+
DEPENDENCY_SOURCE_NOTE,
|
|
163
171
|
EXT_BROADCAST,
|
|
164
172
|
EXT_MSG,
|
|
165
173
|
HOST_EVENTS_API_PATH,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { fileNameOf } from "./utils.mjs";
|
|
1
2
|
const COMMAND_CHECK_TIMEOUT_MS = 6e4;
|
|
2
3
|
const SOURCE_EXTENSIONS = [
|
|
3
4
|
".js",
|
|
@@ -12,7 +13,7 @@ const SOURCE_EXTENSIONS = [
|
|
|
12
13
|
];
|
|
13
14
|
function matchesExtensions(filePath, extensions) {
|
|
14
15
|
if (!extensions?.length) return true;
|
|
15
|
-
const base = filePath
|
|
16
|
+
const base = fileNameOf(filePath);
|
|
16
17
|
const dot = base.lastIndexOf(".");
|
|
17
18
|
if (dot <= 0) return false;
|
|
18
19
|
return extensions.includes(base.slice(dot).toLowerCase());
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { INSPECTOR_ADAPTER_IDS } from "../constants.mjs";
|
|
2
|
+
import { isDependencyPath } from "../utils.mjs";
|
|
2
3
|
import {
|
|
3
4
|
parseSourceLocation
|
|
4
5
|
} from "./types.mjs";
|
|
@@ -63,9 +64,8 @@ function resolveFromVueInstance(element) {
|
|
|
63
64
|
function mergeSourceLocations(markerLocation, instanceLocation) {
|
|
64
65
|
if (!markerLocation?.file && !instanceLocation?.file) return null;
|
|
65
66
|
if (markerLocation?.file && instanceLocation?.file) {
|
|
66
|
-
|
|
67
|
-
if (!
|
|
68
|
-
if (!isNodeModules(instanceLocation.file)) return instanceLocation;
|
|
67
|
+
if (!isDependencyPath(markerLocation.file)) return markerLocation;
|
|
68
|
+
if (!isDependencyPath(instanceLocation.file)) return instanceLocation;
|
|
69
69
|
return markerLocation;
|
|
70
70
|
}
|
|
71
71
|
return markerLocation?.file ? markerLocation : instanceLocation;
|
package/es/common/types.d.ts
CHANGED
|
@@ -77,7 +77,11 @@ export interface LogFileConfig {
|
|
|
77
77
|
export interface SelectedElement {
|
|
78
78
|
/** 节点唯一 id(`@节点[n<id>]` 引用标记与上下文注入共用;由 ensureNodeId 分配) */
|
|
79
79
|
id?: string;
|
|
80
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* 文件路径(绝对路径)。
|
|
82
|
+
* 浏览器只上报相对路径(各 Inspector 基准不同),由 Vite 端点按宿主基准归一化后落库,
|
|
83
|
+
* 消费方(Provider 注入、UI 展示)拿到的恒为绝对路径。
|
|
84
|
+
*/
|
|
81
85
|
filePath: string | null;
|
|
82
86
|
/** 行号 */
|
|
83
87
|
line: number | null;
|
|
@@ -305,6 +309,8 @@ export type AIPanelWidgetEmits = {
|
|
|
305
309
|
(e: "select-session", session: AIPanelWidgetSession): void;
|
|
306
310
|
(e: "delete-session", session: AIPanelWidgetSession): void;
|
|
307
311
|
(e: "click-selected-node", element: AIPanelSelectedElement): void;
|
|
312
|
+
/** 宿主无法在本地定位(扩展模式下页面不在本上下文):把节点交给宿主转发到目标页 */
|
|
313
|
+
(e: "locate-node", element: AIPanelSelectedElement): void;
|
|
308
314
|
(e: "remove-selected-node", payload: AIPanelRemoveSelectedPayload): void;
|
|
309
315
|
(e: "clear-selected-nodes"): void;
|
|
310
316
|
(e: "empty-action"): void;
|
package/es/common/utils.d.ts
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 路径分隔符归一化(反斜杠 → 正斜杠)。
|
|
3
|
+
* 浏览器侧没有 node:path,路径处理统一按字符串做;宿主的绝对路径在 Windows 上会带 `\`。
|
|
4
|
+
* @param filePath - 原始路径
|
|
5
|
+
* @returns 分隔符统一为正斜杠的路径
|
|
6
|
+
*/
|
|
7
|
+
export declare function normalizePathSeparators(filePath: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* 取路径的文件名(最后一段),兼容 `/` 与 `\` 分隔。
|
|
10
|
+
* 挂件气泡/节点卡片(浏览器)与进程日志(node)共用,避免各处自写 split("/").pop()。
|
|
11
|
+
* @param filePath - 原始路径
|
|
12
|
+
* @returns 文件名;路径为空或以分隔符结尾时返回空串
|
|
13
|
+
*/
|
|
14
|
+
export declare function fileNameOf(filePath: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* 路径是否位于依赖安装目录内(含 pnpm 的 `.pnpm/<pkg>@<ver>/node_modules/<pkg>` 真身)。
|
|
17
|
+
* 按路径分段判定,避免误伤名字里含 node_modules 的项目目录。
|
|
18
|
+
* @param filePath - 原始路径
|
|
19
|
+
* @returns 为依赖内部文件时 true
|
|
20
|
+
*/
|
|
21
|
+
export declare function isDependencyPath(filePath: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* 拼「路径:行:列」形式的源码位置(形如 `/proj/src/App.vue:53:11`)。
|
|
24
|
+
* 节点上下文注入(两个 Provider)与编辑器跳转(launch-editor 的位置格式)共用同一形态。
|
|
25
|
+
* @param filePath - 文件路径
|
|
26
|
+
* @param line - 行号(缺省时只返回路径)
|
|
27
|
+
* @param column - 列号(缺省时只到行)
|
|
28
|
+
* @returns 源码位置字符串
|
|
29
|
+
*/
|
|
30
|
+
export declare function formatSourceLocation(filePath: string, line?: number | null, column?: number | null): string;
|
|
1
31
|
/**
|
|
2
32
|
* 取(或生成)元素的节点唯一 id:优先复用已赋值的 id,否则生成随机 id 并写回元素。
|
|
3
33
|
* 同一引用在会话标记(`@节点[n<id>]`)与上下文注入里使用同一个 id;
|
package/es/common/utils.mjs
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
import { DEFAULT_RETRIES, RETRY_DELAY } from "./constants.mjs";
|
|
1
|
+
import { DEFAULT_RETRIES, DEPENDENCY_DIR_NAME, RETRY_DELAY } from "./constants.mjs";
|
|
2
|
+
function normalizePathSeparators(filePath) {
|
|
3
|
+
return filePath.replace(/\\/g, "/");
|
|
4
|
+
}
|
|
5
|
+
function fileNameOf(filePath) {
|
|
6
|
+
const normalized = normalizePathSeparators(filePath);
|
|
7
|
+
return normalized.slice(normalized.lastIndexOf("/") + 1);
|
|
8
|
+
}
|
|
9
|
+
function isDependencyPath(filePath) {
|
|
10
|
+
return normalizePathSeparators(filePath).split("/").includes(DEPENDENCY_DIR_NAME);
|
|
11
|
+
}
|
|
12
|
+
function formatSourceLocation(filePath, line, column) {
|
|
13
|
+
if (!line) return filePath;
|
|
14
|
+
return column ? `${filePath}:${line}:${column}` : `${filePath}:${line}`;
|
|
15
|
+
}
|
|
2
16
|
function ensureNodeId(element) {
|
|
3
17
|
if (element.id) return element.id;
|
|
4
18
|
const random = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID().replace(/-/g, "").slice(0, 8) : Math.random().toString(36).slice(2, 10);
|
|
@@ -92,6 +106,10 @@ export {
|
|
|
92
106
|
base64Encode,
|
|
93
107
|
ensureNodeId,
|
|
94
108
|
extractTextFromResponse,
|
|
109
|
+
fileNameOf,
|
|
110
|
+
formatSourceLocation,
|
|
111
|
+
isDependencyPath,
|
|
112
|
+
normalizePathSeparators,
|
|
95
113
|
parseNodeMentions,
|
|
96
114
|
sleep,
|
|
97
115
|
toNodeMention,
|
package/es/node/node-logger.mjs
CHANGED
|
@@ -2,6 +2,7 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
import { LOG_PREFIX } from "../common/constants.mjs";
|
|
5
|
+
import { fileNameOf } from "../common/utils.mjs";
|
|
5
6
|
import {
|
|
6
7
|
LEVEL_NAMES,
|
|
7
8
|
LogLevel,
|
|
@@ -39,7 +40,7 @@ function getCallerInfo(depth = 3) {
|
|
|
39
40
|
const match = targetLine.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?/);
|
|
40
41
|
if (!match) return "";
|
|
41
42
|
const [, funcName, filePath, line] = match;
|
|
42
|
-
const fileName = filePath
|
|
43
|
+
const fileName = fileNameOf(filePath) || filePath;
|
|
43
44
|
const func = funcName || "<anonymous>";
|
|
44
45
|
return `${fileName}:${line} ${func}`;
|
|
45
46
|
}
|
package/lib/common/constants.cjs
CHANGED
|
@@ -30,6 +30,8 @@ __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
|
+
DEPENDENCY_DIR_NAME: () => DEPENDENCY_DIR_NAME,
|
|
34
|
+
DEPENDENCY_SOURCE_NOTE: () => DEPENDENCY_SOURCE_NOTE,
|
|
33
35
|
EXT_BROADCAST: () => EXT_BROADCAST,
|
|
34
36
|
EXT_MSG: () => EXT_MSG,
|
|
35
37
|
HOST_EVENTS_API_PATH: () => HOST_EVENTS_API_PATH,
|
|
@@ -97,6 +99,8 @@ const INIT_MARKER = "__AIPANEL_INITIALIZED__";
|
|
|
97
99
|
const SELECTED_ELEMENTS_KEY = "__aipanel_selected_elements__";
|
|
98
100
|
const SESSION_ID_KEY = "_aipanel_pk";
|
|
99
101
|
const AIPANEL_CACHE_DIR = "node_modules/.cache/aipanel";
|
|
102
|
+
const DEPENDENCY_DIR_NAME = "node_modules";
|
|
103
|
+
const DEPENDENCY_SOURCE_NOTE = `\u4F9D\u8D56\u5305\u5185\u6587\u4EF6\uFF08${DEPENDENCY_DIR_NAME}\uFF09\uFF1A\u901A\u5E38\u4E0D\u5E94\u76F4\u63A5\u4FEE\u6539\uFF0C\u9875\u9762\u884C\u4E3A\u8BF7\u6539\u9879\u76EE\u5185\u6E90\u7801`;
|
|
100
104
|
const CHROME_DEVTOOLS_PORT = 9222;
|
|
101
105
|
const CHROME_DEVTOOLS_CHECK_TIMEOUT = 2e3;
|
|
102
106
|
const EXT_BROADCAST = {
|
|
@@ -112,6 +116,8 @@ const EXT_MSG = {
|
|
|
112
116
|
REQUEST_PAGE_CONTEXT: "REQUEST_PAGE_CONTEXT",
|
|
113
117
|
SELECTION_START: "SELECTION_START",
|
|
114
118
|
SELECTION_STOP: "SELECTION_STOP",
|
|
119
|
+
/** Side Panel → 目标 Tab:请目标页定位某个已选节点(跳回其页面并呼吸高亮) */
|
|
120
|
+
LOCATE_NODE: "LOCATE_NODE",
|
|
115
121
|
CS_QUERY_WINDOW: "__CS_QUERY_WINDOW__",
|
|
116
122
|
/** Side Panel → Background:立即轮询一次并回传当前服务信息 */
|
|
117
123
|
FORCE_POLL: "FORCE_POLL"
|
|
@@ -139,7 +145,9 @@ const WIDGET_MSG = {
|
|
|
139
145
|
/** 无 deepLink 能力的 Provider:通知 iframe 聚焦指定会话 */
|
|
140
146
|
FOCUS_SESSION: "AIPANEL_FOCUS_SESSION",
|
|
141
147
|
/** 无 deepLink 能力的 Provider:iframe 确认目标会话已激活且渲染稳定(携带 sessionId) */
|
|
142
|
-
SESSION_READY: "AIPANEL_SESSION_READY"
|
|
148
|
+
SESSION_READY: "AIPANEL_SESSION_READY",
|
|
149
|
+
/** iframe → 宿主:点节点 chip 时把该节点交回挂件,跳回它被选中时的页面并闪烁高亮;载荷 { element } */
|
|
150
|
+
LOCATE_NODE: "AIPANEL_LOCATE_NODE"
|
|
143
151
|
};
|
|
144
152
|
const WARMUP_API_PATH = "/__aipanel_warmup__";
|
|
145
153
|
const BRIDGE_SCRIPT_PATH = "/__aipanel_bridge__.js";
|
|
@@ -234,6 +242,8 @@ const INSPECTOR_ADAPTER_IDS = {
|
|
|
234
242
|
DEFAULT_PROXY_PORT,
|
|
235
243
|
DEFAULT_RETRIES,
|
|
236
244
|
DEFAULT_WEB_PORT,
|
|
245
|
+
DEPENDENCY_DIR_NAME,
|
|
246
|
+
DEPENDENCY_SOURCE_NOTE,
|
|
237
247
|
EXT_BROADCAST,
|
|
238
248
|
EXT_MSG,
|
|
239
249
|
HOST_EVENTS_API_PATH,
|
|
@@ -56,7 +56,7 @@ export declare const NOTIFICATION_DURATION = 3000;
|
|
|
56
56
|
export declare const INIT_MARKER = "__AIPANEL_INITIALIZED__";
|
|
57
57
|
/** 选中元素存储键 */
|
|
58
58
|
export declare const SELECTED_ELEMENTS_KEY = "__aipanel_selected_elements__";
|
|
59
|
-
/**
|
|
59
|
+
/** 页内会话标识键(sessionStorage,跨导航标识同一 Tab 的页面上下文) */
|
|
60
60
|
export declare const SESSION_ID_KEY = "_aipanel_pk";
|
|
61
61
|
/** ==================== 缓存目录 ==================== */
|
|
62
62
|
/**
|
|
@@ -64,6 +64,18 @@ export declare const SESSION_ID_KEY = "_aipanel_pk";
|
|
|
64
64
|
* 存放 opencode.json、dsh overlay 等运行时状态,不污染项目根目录。
|
|
65
65
|
*/
|
|
66
66
|
export declare const AIPANEL_CACHE_DIR = "node_modules/.cache/aipanel";
|
|
67
|
+
/** ==================== 源码路径 ==================== */
|
|
68
|
+
/**
|
|
69
|
+
* 依赖安装目录名(判定文件是否来自依赖包的唯一依据)。
|
|
70
|
+
* 宿主侧上下文归一化与两个 Provider 的注入文案共用,避免各写一份 magic string。
|
|
71
|
+
*/
|
|
72
|
+
export declare const DEPENDENCY_DIR_NAME = "node_modules";
|
|
73
|
+
/**
|
|
74
|
+
* 依赖内部文件的归属提示(注入给 agent 的上下文文案)。
|
|
75
|
+
* 两个 Provider 共用同一措辞:agent 拿到 node_modules 路径时最容易顺着它去改第三方实现,
|
|
76
|
+
* 归属必须显式声明,而不是让「源码文件路径」这行字暗示它是项目源码。
|
|
77
|
+
*/
|
|
78
|
+
export declare const DEPENDENCY_SOURCE_NOTE = "\u4F9D\u8D56\u5305\u5185\u6587\u4EF6\uFF08node_modules\uFF09\uFF1A\u901A\u5E38\u4E0D\u5E94\u76F4\u63A5\u4FEE\u6539\uFF0C\u9875\u9762\u884C\u4E3A\u8BF7\u6539\u9879\u76EE\u5185\u6E90\u7801";
|
|
67
79
|
/** ==================== Chrome DevTools ==================== */
|
|
68
80
|
/** Chrome DevTools Protocol 默认端口 */
|
|
69
81
|
export declare const CHROME_DEVTOOLS_PORT = 9222;
|
|
@@ -84,6 +96,8 @@ export declare const EXT_MSG: {
|
|
|
84
96
|
readonly REQUEST_PAGE_CONTEXT: "REQUEST_PAGE_CONTEXT";
|
|
85
97
|
readonly SELECTION_START: "SELECTION_START";
|
|
86
98
|
readonly SELECTION_STOP: "SELECTION_STOP";
|
|
99
|
+
/** Side Panel → 目标 Tab:请目标页定位某个已选节点(跳回其页面并呼吸高亮) */
|
|
100
|
+
readonly LOCATE_NODE: "LOCATE_NODE";
|
|
87
101
|
readonly CS_QUERY_WINDOW: "__CS_QUERY_WINDOW__";
|
|
88
102
|
/** Side Panel → Background:立即轮询一次并回传当前服务信息 */
|
|
89
103
|
readonly FORCE_POLL: "FORCE_POLL";
|
|
@@ -118,6 +132,8 @@ export declare const WIDGET_MSG: {
|
|
|
118
132
|
readonly FOCUS_SESSION: "AIPANEL_FOCUS_SESSION";
|
|
119
133
|
/** 无 deepLink 能力的 Provider:iframe 确认目标会话已激活且渲染稳定(携带 sessionId) */
|
|
120
134
|
readonly SESSION_READY: "AIPANEL_SESSION_READY";
|
|
135
|
+
/** iframe → 宿主:点节点 chip 时把该节点交回挂件,跳回它被选中时的页面并闪烁高亮;载荷 { element } */
|
|
136
|
+
readonly LOCATE_NODE: "AIPANEL_LOCATE_NODE";
|
|
121
137
|
};
|
|
122
138
|
/** ==================== API 路径补充 ==================== */
|
|
123
139
|
/** Provider 预热 API 路径 */
|
|
@@ -33,6 +33,7 @@ __export(diagnostics_exports, {
|
|
|
33
33
|
resolveDiagnosticsPolicy: () => resolveDiagnosticsPolicy
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(diagnostics_exports);
|
|
36
|
+
var import_utils = require("./utils.cjs");
|
|
36
37
|
const COMMAND_CHECK_TIMEOUT_MS = 6e4;
|
|
37
38
|
const SOURCE_EXTENSIONS = [
|
|
38
39
|
".js",
|
|
@@ -47,7 +48,7 @@ const SOURCE_EXTENSIONS = [
|
|
|
47
48
|
];
|
|
48
49
|
function matchesExtensions(filePath, extensions) {
|
|
49
50
|
if (!extensions?.length) return true;
|
|
50
|
-
const base =
|
|
51
|
+
const base = (0, import_utils.fileNameOf)(filePath);
|
|
51
52
|
const dot = base.lastIndexOf(".");
|
|
52
53
|
if (dot <= 0) return false;
|
|
53
54
|
return extensions.includes(base.slice(dot).toLowerCase());
|
|
@@ -21,6 +21,7 @@ __export(vue_exports, {
|
|
|
21
21
|
});
|
|
22
22
|
module.exports = __toCommonJS(vue_exports);
|
|
23
23
|
var import_constants = require("../constants.cjs");
|
|
24
|
+
var import_utils = require("../utils.cjs");
|
|
24
25
|
var import_types = require("./types.cjs");
|
|
25
26
|
const SOURCE_LOCATION_ATTRIBUTE = "data-v-inspector";
|
|
26
27
|
const VNODE_SOURCE_KEY = "__v_inspector";
|
|
@@ -83,9 +84,8 @@ function resolveFromVueInstance(element) {
|
|
|
83
84
|
function mergeSourceLocations(markerLocation, instanceLocation) {
|
|
84
85
|
if (!markerLocation?.file && !instanceLocation?.file) return null;
|
|
85
86
|
if (markerLocation?.file && instanceLocation?.file) {
|
|
86
|
-
|
|
87
|
-
if (!
|
|
88
|
-
if (!isNodeModules(instanceLocation.file)) return instanceLocation;
|
|
87
|
+
if (!(0, import_utils.isDependencyPath)(markerLocation.file)) return markerLocation;
|
|
88
|
+
if (!(0, import_utils.isDependencyPath)(instanceLocation.file)) return instanceLocation;
|
|
89
89
|
return markerLocation;
|
|
90
90
|
}
|
|
91
91
|
return markerLocation?.file ? markerLocation : instanceLocation;
|
package/lib/common/types.d.ts
CHANGED
|
@@ -77,7 +77,11 @@ export interface LogFileConfig {
|
|
|
77
77
|
export interface SelectedElement {
|
|
78
78
|
/** 节点唯一 id(`@节点[n<id>]` 引用标记与上下文注入共用;由 ensureNodeId 分配) */
|
|
79
79
|
id?: string;
|
|
80
|
-
/**
|
|
80
|
+
/**
|
|
81
|
+
* 文件路径(绝对路径)。
|
|
82
|
+
* 浏览器只上报相对路径(各 Inspector 基准不同),由 Vite 端点按宿主基准归一化后落库,
|
|
83
|
+
* 消费方(Provider 注入、UI 展示)拿到的恒为绝对路径。
|
|
84
|
+
*/
|
|
81
85
|
filePath: string | null;
|
|
82
86
|
/** 行号 */
|
|
83
87
|
line: number | null;
|
|
@@ -305,6 +309,8 @@ export type AIPanelWidgetEmits = {
|
|
|
305
309
|
(e: "select-session", session: AIPanelWidgetSession): void;
|
|
306
310
|
(e: "delete-session", session: AIPanelWidgetSession): void;
|
|
307
311
|
(e: "click-selected-node", element: AIPanelSelectedElement): void;
|
|
312
|
+
/** 宿主无法在本地定位(扩展模式下页面不在本上下文):把节点交给宿主转发到目标页 */
|
|
313
|
+
(e: "locate-node", element: AIPanelSelectedElement): void;
|
|
308
314
|
(e: "remove-selected-node", payload: AIPanelRemoveSelectedPayload): void;
|
|
309
315
|
(e: "clear-selected-nodes"): void;
|
|
310
316
|
(e: "empty-action"): void;
|
package/lib/common/utils.cjs
CHANGED
|
@@ -21,6 +21,10 @@ __export(utils_exports, {
|
|
|
21
21
|
base64Encode: () => base64Encode,
|
|
22
22
|
ensureNodeId: () => ensureNodeId,
|
|
23
23
|
extractTextFromResponse: () => extractTextFromResponse,
|
|
24
|
+
fileNameOf: () => fileNameOf,
|
|
25
|
+
formatSourceLocation: () => formatSourceLocation,
|
|
26
|
+
isDependencyPath: () => isDependencyPath,
|
|
27
|
+
normalizePathSeparators: () => normalizePathSeparators,
|
|
24
28
|
parseNodeMentions: () => parseNodeMentions,
|
|
25
29
|
sleep: () => sleep,
|
|
26
30
|
toNodeMention: () => toNodeMention,
|
|
@@ -30,6 +34,20 @@ __export(utils_exports, {
|
|
|
30
34
|
});
|
|
31
35
|
module.exports = __toCommonJS(utils_exports);
|
|
32
36
|
var import_constants = require("./constants.cjs");
|
|
37
|
+
function normalizePathSeparators(filePath) {
|
|
38
|
+
return filePath.replace(/\\/g, "/");
|
|
39
|
+
}
|
|
40
|
+
function fileNameOf(filePath) {
|
|
41
|
+
const normalized = normalizePathSeparators(filePath);
|
|
42
|
+
return normalized.slice(normalized.lastIndexOf("/") + 1);
|
|
43
|
+
}
|
|
44
|
+
function isDependencyPath(filePath) {
|
|
45
|
+
return normalizePathSeparators(filePath).split("/").includes(import_constants.DEPENDENCY_DIR_NAME);
|
|
46
|
+
}
|
|
47
|
+
function formatSourceLocation(filePath, line, column) {
|
|
48
|
+
if (!line) return filePath;
|
|
49
|
+
return column ? `${filePath}:${line}:${column}` : `${filePath}:${line}`;
|
|
50
|
+
}
|
|
33
51
|
function ensureNodeId(element) {
|
|
34
52
|
if (element.id) return element.id;
|
|
35
53
|
const random = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID().replace(/-/g, "").slice(0, 8) : Math.random().toString(36).slice(2, 10);
|
|
@@ -124,6 +142,10 @@ async function withRetries(fn, options = {}) {
|
|
|
124
142
|
base64Encode,
|
|
125
143
|
ensureNodeId,
|
|
126
144
|
extractTextFromResponse,
|
|
145
|
+
fileNameOf,
|
|
146
|
+
formatSourceLocation,
|
|
147
|
+
isDependencyPath,
|
|
148
|
+
normalizePathSeparators,
|
|
127
149
|
parseNodeMentions,
|
|
128
150
|
sleep,
|
|
129
151
|
toNodeMention,
|
package/lib/common/utils.d.ts
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 路径分隔符归一化(反斜杠 → 正斜杠)。
|
|
3
|
+
* 浏览器侧没有 node:path,路径处理统一按字符串做;宿主的绝对路径在 Windows 上会带 `\`。
|
|
4
|
+
* @param filePath - 原始路径
|
|
5
|
+
* @returns 分隔符统一为正斜杠的路径
|
|
6
|
+
*/
|
|
7
|
+
export declare function normalizePathSeparators(filePath: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* 取路径的文件名(最后一段),兼容 `/` 与 `\` 分隔。
|
|
10
|
+
* 挂件气泡/节点卡片(浏览器)与进程日志(node)共用,避免各处自写 split("/").pop()。
|
|
11
|
+
* @param filePath - 原始路径
|
|
12
|
+
* @returns 文件名;路径为空或以分隔符结尾时返回空串
|
|
13
|
+
*/
|
|
14
|
+
export declare function fileNameOf(filePath: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* 路径是否位于依赖安装目录内(含 pnpm 的 `.pnpm/<pkg>@<ver>/node_modules/<pkg>` 真身)。
|
|
17
|
+
* 按路径分段判定,避免误伤名字里含 node_modules 的项目目录。
|
|
18
|
+
* @param filePath - 原始路径
|
|
19
|
+
* @returns 为依赖内部文件时 true
|
|
20
|
+
*/
|
|
21
|
+
export declare function isDependencyPath(filePath: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* 拼「路径:行:列」形式的源码位置(形如 `/proj/src/App.vue:53:11`)。
|
|
24
|
+
* 节点上下文注入(两个 Provider)与编辑器跳转(launch-editor 的位置格式)共用同一形态。
|
|
25
|
+
* @param filePath - 文件路径
|
|
26
|
+
* @param line - 行号(缺省时只返回路径)
|
|
27
|
+
* @param column - 列号(缺省时只到行)
|
|
28
|
+
* @returns 源码位置字符串
|
|
29
|
+
*/
|
|
30
|
+
export declare function formatSourceLocation(filePath: string, line?: number | null, column?: number | null): string;
|
|
1
31
|
/**
|
|
2
32
|
* 取(或生成)元素的节点唯一 id:优先复用已赋值的 id,否则生成随机 id 并写回元素。
|
|
3
33
|
* 同一引用在会话标记(`@节点[n<id>]`)与上下文注入里使用同一个 id;
|
package/lib/node/node-logger.cjs
CHANGED
|
@@ -29,6 +29,7 @@ __export(node_logger_exports, {
|
|
|
29
29
|
});
|
|
30
30
|
module.exports = __toCommonJS(node_logger_exports);
|
|
31
31
|
var import_constants = require("../common/constants.cjs");
|
|
32
|
+
var import_utils = require("../common/utils.cjs");
|
|
32
33
|
var import_logger_core = require("../common/logger-core.cjs");
|
|
33
34
|
const COLORS = {
|
|
34
35
|
reset: "\x1B[0m",
|
|
@@ -58,7 +59,7 @@ function getCallerInfo(depth = 3) {
|
|
|
58
59
|
const match = targetLine.match(/at\s+(?:(.+?)\s+\()?(.+?):(\d+):(\d+)\)?/);
|
|
59
60
|
if (!match) return "";
|
|
60
61
|
const [, funcName, filePath, line] = match;
|
|
61
|
-
const fileName =
|
|
62
|
+
const fileName = (0, import_utils.fileNameOf)(filePath) || filePath;
|
|
62
63
|
const func = funcName || "<anonymous>";
|
|
63
64
|
return `${fileName}:${line} ${func}`;
|
|
64
65
|
}
|