@aipanel/core 1.2.8 → 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.
Files changed (73) hide show
  1. package/es/{logger.d.ts → client/logger.d.ts} +1 -1
  2. package/es/{logger.mjs → client/logger.mjs} +4 -10
  3. package/es/client/storage.d.ts +15 -0
  4. package/es/client/storage.mjs +33 -0
  5. package/es/client/theme.d.ts +15 -0
  6. package/es/client/theme.mjs +11 -0
  7. package/es/client.d.ts +3 -0
  8. package/es/client.mjs +3 -0
  9. package/es/{constants.d.ts → common/constants.d.ts} +34 -6
  10. package/es/{constants.mjs → common/constants.mjs} +31 -8
  11. package/{lib → es/common}/options.d.ts +40 -0
  12. package/{lib → es/common}/types.d.ts +36 -11
  13. package/es/{utils.d.ts → common/utils.d.ts} +26 -3
  14. package/es/{utils.mjs → common/utils.mjs} +42 -1
  15. package/es/index.d.ts +6 -7
  16. package/es/index.mjs +6 -7
  17. package/es/node/diagnostics.d.ts +5 -0
  18. package/es/node/diagnostics.mjs +26 -4
  19. package/es/{file-log-watcher.mjs → node/file-log-watcher.mjs} +1 -1
  20. package/{lib → es/node}/node-logger.d.ts +1 -1
  21. package/es/{node-logger.mjs → node/node-logger.mjs} +4 -17
  22. package/es/node/node-utils.d.ts +69 -0
  23. package/es/node/node-utils.mjs +291 -0
  24. package/es/node.d.ts +6 -6
  25. package/es/node.mjs +6 -6
  26. package/lib/{logger.cjs → client/logger.cjs} +3 -10
  27. package/lib/{logger.d.ts → client/logger.d.ts} +1 -1
  28. package/lib/client/storage.cjs +58 -0
  29. package/lib/client/storage.d.ts +15 -0
  30. package/lib/client/theme.cjs +35 -0
  31. package/lib/client/theme.d.ts +15 -0
  32. package/lib/client.cjs +25 -0
  33. package/lib/client.d.ts +3 -0
  34. package/lib/{constants.cjs → common/constants.cjs} +38 -12
  35. package/lib/{constants.d.ts → common/constants.d.ts} +34 -6
  36. package/{es → lib/common}/options.d.ts +40 -0
  37. package/{es → lib/common}/types.d.ts +36 -11
  38. package/lib/{utils.cjs → common/utils.cjs} +47 -2
  39. package/lib/{utils.d.ts → common/utils.d.ts} +26 -3
  40. package/lib/index.cjs +12 -14
  41. package/lib/index.d.ts +6 -7
  42. package/lib/node/diagnostics.cjs +27 -4
  43. package/lib/node/diagnostics.d.ts +5 -0
  44. package/lib/{file-log-watcher.cjs → node/file-log-watcher.cjs} +1 -1
  45. package/lib/{node-logger.cjs → node/node-logger.cjs} +4 -19
  46. package/{es → lib/node}/node-logger.d.ts +1 -1
  47. package/lib/node/node-utils.cjs +329 -0
  48. package/lib/node/node-utils.d.ts +69 -0
  49. package/lib/node.cjs +12 -12
  50. package/lib/node.d.ts +6 -6
  51. package/package.json +6 -1
  52. package/es/node-utils.d.ts +0 -28
  53. package/es/node-utils.mjs +0 -56
  54. package/lib/node-utils.cjs +0 -93
  55. package/lib/node-utils.d.ts +0 -28
  56. /package/es/{logger-core.d.ts → common/logger-core.d.ts} +0 -0
  57. /package/es/{logger-core.mjs → common/logger-core.mjs} +0 -0
  58. /package/es/{options.mjs → common/options.mjs} +0 -0
  59. /package/es/{provider.d.ts → common/provider.d.ts} +0 -0
  60. /package/es/{provider.mjs → common/provider.mjs} +0 -0
  61. /package/es/{types.mjs → common/types.mjs} +0 -0
  62. /package/es/{file-log-watcher.d.ts → node/file-log-watcher.d.ts} +0 -0
  63. /package/es/{process-logger.d.ts → node/process-logger.d.ts} +0 -0
  64. /package/es/{process-logger.mjs → node/process-logger.mjs} +0 -0
  65. /package/lib/{logger-core.cjs → common/logger-core.cjs} +0 -0
  66. /package/lib/{logger-core.d.ts → common/logger-core.d.ts} +0 -0
  67. /package/lib/{options.cjs → common/options.cjs} +0 -0
  68. /package/lib/{provider.cjs → common/provider.cjs} +0 -0
  69. /package/lib/{provider.d.ts → common/provider.d.ts} +0 -0
  70. /package/lib/{types.cjs → common/types.cjs} +0 -0
  71. /package/lib/{file-log-watcher.d.ts → node/file-log-watcher.d.ts} +0 -0
  72. /package/lib/{process-logger.cjs → node/process-logger.cjs} +0 -0
  73. /package/lib/{process-logger.d.ts → node/process-logger.d.ts} +0 -0
@@ -1,4 +1,4 @@
1
- import { type LogContext } from "./logger-core";
1
+ import { type LogContext } from "../common/logger-core";
2
2
  export declare const logger: {
3
3
  debug(message: string, context?: LogContext, ...args: unknown[]): void;
4
4
  info(message: string, context?: LogContext, ...args: unknown[]): void;
@@ -1,18 +1,12 @@
1
- import { LOG_PREFIX } from "./constants.mjs";
1
+ import { LOG_PREFIX } from "../common/constants.mjs";
2
2
  import {
3
+ LEVEL_NAMES,
3
4
  LogLevel,
4
5
  getConfig,
5
6
  getTimestamp,
6
7
  formatContext,
7
8
  formatValue
8
- } from "./logger-core.mjs";
9
- const LEVEL_NAMES = {
10
- [LogLevel.DEBUG]: "DEBUG",
11
- [LogLevel.INFO]: "INFO ",
12
- [LogLevel.WARN]: "WARN ",
13
- [LogLevel.ERROR]: "ERROR",
14
- [LogLevel.NONE]: "NONE "
15
- };
9
+ } from "../common/logger-core.mjs";
16
10
  const C = {
17
11
  dim: "color: #888",
18
12
  bright: "font-weight: bold",
@@ -39,7 +33,7 @@ function log(level, message, context, ...args) {
39
33
  segments.push("%c%s");
40
34
  styles.push(C.dim, getTimestamp());
41
35
  }
42
- segments.push(`%c${LEVEL_NAMES[level]}`);
36
+ segments.push(`%c${LEVEL_NAMES[level].padEnd(5)}`);
43
37
  styles.push(LEVEL_COLORS[level]);
44
38
  segments.push(`%c${LOG_PREFIX}`);
45
39
  styles.push(C.bright);
@@ -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,33 @@
1
+ function storageArea(area) {
2
+ try {
3
+ if (typeof window === "undefined") return void 0;
4
+ return area === "local" ? window.localStorage : window.sessionStorage;
5
+ } catch {
6
+ return void 0;
7
+ }
8
+ }
9
+ function storageGet(area, key) {
10
+ try {
11
+ const raw = storageArea(area)?.getItem(key);
12
+ return raw == null ? null : JSON.parse(raw);
13
+ } catch {
14
+ return null;
15
+ }
16
+ }
17
+ function storageSet(area, key, value) {
18
+ try {
19
+ storageArea(area)?.setItem(key, JSON.stringify(value));
20
+ } catch {
21
+ }
22
+ }
23
+ function storageRemove(area, key) {
24
+ try {
25
+ storageArea(area)?.removeItem(key);
26
+ } catch {
27
+ }
28
+ }
29
+ export {
30
+ storageGet,
31
+ storageRemove,
32
+ storageSet
33
+ };
@@ -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";
@@ -0,0 +1,11 @@
1
+ function getSystemTheme() {
2
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return "light";
3
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
4
+ }
5
+ function resolveWidgetTheme(theme, system = getSystemTheme()) {
6
+ return theme === "auto" ? system : theme;
7
+ }
8
+ export {
9
+ getSystemTheme,
10
+ resolveWidgetTheme
11
+ };
package/es/client.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./client/logger";
2
+ export * from "./client/storage";
3
+ export * from "./client/theme";
package/es/client.mjs ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./client/logger.mjs";
2
+ export * from "./client/storage.mjs";
3
+ export * from "./client/theme.mjs";
@@ -56,6 +56,8 @@ 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
+ /** 页面会话标识键(sessionStorage,跨导航标识同一 Tab 的页面上下文) */
60
+ export declare const SESSION_ID_KEY = "_aipanel_pk";
59
61
  /** ==================== 缓存目录 ==================== */
60
62
  /**
61
63
  * AIPanel 项目级资源/缓存目录(相对于项目根目录,各 Provider 统一使用)。
@@ -83,6 +85,8 @@ export declare const EXT_MSG: {
83
85
  readonly SELECTION_START: "SELECTION_START";
84
86
  readonly SELECTION_STOP: "SELECTION_STOP";
85
87
  readonly CS_QUERY_WINDOW: "__CS_QUERY_WINDOW__";
88
+ /** Side Panel → Background:立即轮询一次并回传当前服务信息 */
89
+ readonly FORCE_POLL: "FORCE_POLL";
86
90
  readonly PAGE_CONTEXT: "PAGE_CONTEXT";
87
91
  readonly THEME_CHANGE: "THEME_CHANGE";
88
92
  readonly SERVICE_APPEARED: "SERVICE_APPEARED";
@@ -118,6 +122,8 @@ export declare const BRIDGE_SCRIPT_PATH = "/__aipanel_bridge__.js";
118
122
  export declare const LOGS_API_PATH = "/__aipanel_process_logs__";
119
123
  /** Widget 样式路径 */
120
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__";
121
127
  /** ==================== 文本处理 ==================== */
122
128
  /** 元素文本最大显示长度 */
123
129
  export declare const MAX_TEXT_LENGTH = 100;
@@ -134,12 +140,6 @@ export declare const PAGE_CONTEXT_MAX_TEXT_LENGTH = 10000;
134
140
  */
135
141
  export declare const SEVERITY_ERROR = 1;
136
142
  export declare const SEVERITY_WARN = 2;
137
- /** ==================== VS Code 扩展桥接 ==================== */
138
- /** VS Code 扩展 HTTP 服务端口(vscode-extension ↔ provider 通信协议) */
139
- export declare const VSCODE_EXTENSION_PORT = 51939;
140
- /** VS Code 扩展相关环境变量名 */
141
- export declare const ENV_VSCODE_MODE = "AIPANEL_VSCODE_MODE";
142
- export declare const ENV_VSCODE_PORT = "AIPANEL_VSCODE_PORT";
143
143
  /** ==================== Vue DevTools API ==================== */
144
144
  /** Vue DevTools API action 名称 */
145
145
  export declare const VUE_DEVTOOLS_ACTIONS: {
@@ -151,3 +151,31 @@ export declare const VUE_DEVTOOLS_ACTIONS: {
151
151
  readonly GET_ROUTER_INFO: "getRouterInfo";
152
152
  };
153
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];
@@ -22,6 +22,7 @@ const AUTO_OPEN_DELAY = 1e3;
22
22
  const NOTIFICATION_DURATION = 3e3;
23
23
  const INIT_MARKER = "__AIPANEL_INITIALIZED__";
24
24
  const SELECTED_ELEMENTS_KEY = "__aipanel_selected_elements__";
25
+ const SESSION_ID_KEY = "_aipanel_pk";
25
26
  const AIPANEL_CACHE_DIR = "node_modules/.cache/aipanel";
26
27
  const CHROME_DEVTOOLS_PORT = 9222;
27
28
  const CHROME_DEVTOOLS_CHECK_TIMEOUT = 2e3;
@@ -38,7 +39,9 @@ const EXT_MSG = {
38
39
  REQUEST_PAGE_CONTEXT: "REQUEST_PAGE_CONTEXT",
39
40
  SELECTION_START: "SELECTION_START",
40
41
  SELECTION_STOP: "SELECTION_STOP",
41
- CS_QUERY_WINDOW: "__CS_QUERY_WINDOW__"
42
+ CS_QUERY_WINDOW: "__CS_QUERY_WINDOW__",
43
+ /** Side Panel → Background:立即轮询一次并回传当前服务信息 */
44
+ FORCE_POLL: "FORCE_POLL"
42
45
  };
43
46
  const WIDGET_MSG = {
44
47
  READY: "AIPANEL_READY",
@@ -63,15 +66,13 @@ const WARMUP_API_PATH = "/__aipanel_warmup__";
63
66
  const BRIDGE_SCRIPT_PATH = "/__aipanel_bridge__.js";
64
67
  const LOGS_API_PATH = "/__aipanel_process_logs__";
65
68
  const WIDGET_STYLE_PATH = "/__aipanel_widget__.css";
69
+ const VUE_DEVTOOLS_API_PATH = "/__aipanel_vue_devtools__";
66
70
  const MAX_TEXT_LENGTH = 100;
67
71
  const CONTEXT_MARKER = "[\u5143\u7D20\u4E0A\u4E0B\u6587]";
68
72
  const PAGE_CONTEXT_MARKER = "__AIPANEL_CONTEXT__";
69
73
  const PAGE_CONTEXT_MAX_TEXT_LENGTH = 1e4;
70
74
  const SEVERITY_ERROR = 1;
71
75
  const SEVERITY_WARN = 2;
72
- const VSCODE_EXTENSION_PORT = 51939;
73
- const ENV_VSCODE_MODE = "AIPANEL_VSCODE_MODE";
74
- const ENV_VSCODE_PORT = "AIPANEL_VSCODE_PORT";
75
76
  const VUE_DEVTOOLS_ACTIONS = {
76
77
  GET_COMPONENT_TREE: "getComponentTree",
77
78
  GET_COMPONENT_STATE: "getComponentState",
@@ -80,6 +81,25 @@ const VUE_DEVTOOLS_ACTIONS = {
80
81
  TOGGLE_APP: "toggleApp",
81
82
  GET_ROUTER_INFO: "getRouterInfo"
82
83
  };
84
+ const MUTATING_TOOLS = /* @__PURE__ */ new Set(["write", "edit", "apply_patch"]);
85
+ const WIDGET_THEME_MODES = ["auto", "light", "dark"];
86
+ const OPENCODE_ENV = {
87
+ CONFIG_DIR: "OPENCODE_CONFIG_DIR",
88
+ CONTEXT_API_URL: "OPENCODE_CONTEXT_API_URL",
89
+ VITE_LOGS_API_URL: "OPENCODE_VITE_LOGS_API_URL",
90
+ LOG_FILES_JSON: "OPENCODE_LOG_FILES_JSON",
91
+ VERBOSE: "OPENCODE_VERBOSE",
92
+ ENABLE_LINT: "OPENCODE_ENABLE_LINT",
93
+ VUE_DEVTOOLS_API_URL: "OPENCODE_VUE_DEVTOOLS_API_URL",
94
+ WORKSPACE: "OPENCODE_WORKSPACE"
95
+ };
96
+ const SSE_EVENT_TYPES = {
97
+ CONNECTED: "CONNECTED",
98
+ STATUS_SYNC: "STATUS_SYNC",
99
+ TASK_UPDATE: "TASK_UPDATE",
100
+ SESSION_EVENT: "SESSION_EVENT",
101
+ CLEAR_ELEMENTS: "CLEAR_ELEMENTS"
102
+ };
83
103
  export {
84
104
  AIPANEL_CACHE_DIR,
85
105
  AUTO_OPEN_DELAY,
@@ -94,8 +114,6 @@ export {
94
114
  DEFAULT_PROXY_PORT,
95
115
  DEFAULT_RETRIES,
96
116
  DEFAULT_WEB_PORT,
97
- ENV_VSCODE_MODE,
98
- ENV_VSCODE_PORT,
99
117
  EXT_BROADCAST,
100
118
  EXT_MSG,
101
119
  HOST_EVENTS_API_PATH,
@@ -106,7 +124,9 @@ export {
106
124
  MAX_PORT_TRIES,
107
125
  MAX_TEXT_LENGTH,
108
126
  MCP_API_PATH,
127
+ MUTATING_TOOLS,
109
128
  NOTIFICATION_DURATION,
129
+ OPENCODE_ENV,
110
130
  PAGE_CONTEXT_MARKER,
111
131
  PAGE_CONTEXT_MAX_TEXT_LENGTH,
112
132
  RETRY_DELAY,
@@ -115,14 +135,17 @@ export {
115
135
  SERVER_START_TIMEOUT,
116
136
  SERVER_SYNC_INTERVAL,
117
137
  SESSIONS_API_PATH,
138
+ SESSION_ID_KEY,
118
139
  SEVERITY_ERROR,
119
140
  SEVERITY_WARN,
120
141
  SSE_EVENTS_PATH,
142
+ SSE_EVENT_TYPES,
121
143
  START_API_PATH,
122
- VSCODE_EXTENSION_PORT,
123
144
  VUE_DEVTOOLS_ACTIONS,
145
+ VUE_DEVTOOLS_API_PATH,
124
146
  WARMUP_API_PATH,
125
147
  WIDGET_MSG,
126
148
  WIDGET_SCRIPT_PATH,
127
- WIDGET_STYLE_PATH
149
+ WIDGET_STYLE_PATH,
150
+ WIDGET_THEME_MODES
128
151
  };
@@ -3,6 +3,44 @@
3
3
  * Provider 专属配置通过泛型 P 注入,核心层不感知具体 schema。
4
4
  */
5
5
  import type { DisplayMode, LogFileConfig, SplitModeOptions } from "./types";
6
+ /**
7
+ * chrome-devtools-mcp 进程的用户透传配置。
8
+ * 只允许“追加”,不允许覆盖核心受保护参数(由 McpProxy 统一过滤)。
9
+ */
10
+ export interface ChromeMcpOptions {
11
+ /**
12
+ * 追加的 CLI 参数(先于核心参数注入)。
13
+ * 与核心受保护项(auto-connect / usage-statistics / performance-crux /
14
+ * page-id-routing 及其反义)冲突的参数会被剔除并告警。
15
+ */
16
+ args?: string[];
17
+ /** 透传给 chrome-devtools-mcp 进程的额外环境变量(合并到 process.env 之上) */
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
+ };
43
+ }
6
44
  /**
7
45
  * 插件配置选项
8
46
  * @typeParam P - 当前 Provider 的专属配置段(schema 由具体 Provider 声明)
@@ -34,6 +72,8 @@ export interface PluginOptions<P extends Record<string, unknown> = Record<string
34
72
  warmupChromeMcp?: boolean;
35
73
  /** Chrome DevTools Protocol 端口,默认 9222 */
36
74
  chromeDevtoolsPort?: number;
75
+ /** chrome-devtools-mcp 进程透传配置(只可追加,不可覆盖核心受保护参数) */
76
+ chromeMcp?: ChromeMcpOptions;
37
77
  /** 展示模式,默认 'bubble' */
38
78
  displayMode?: DisplayMode;
39
79
  /** 分屏模式配置 */
@@ -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
  */
@@ -84,6 +85,8 @@ export interface SelectedElement {
84
85
  innerText: string;
85
86
  /** 元素描述(标签名+选择器) */
86
87
  description?: string;
88
+ /** 用户选中节点时的页面 URL(AIPanel 附加;host 端上下文注入用) */
89
+ previewPageUrl?: string;
87
90
  }
88
91
  /**
89
92
  * 页面上下文数据
@@ -121,9 +124,9 @@ export type AIPanelWidgetTheme = "light" | "dark" | "auto";
121
124
  */
122
125
  export type ServiceStatus = "idle" | "starting" | "ready" | "partial" | "failed";
123
126
  /**
124
- * Session 状态类型
127
+ * Session 状态类型(别名:以 ./provider 的 SessionStatus 为单一来源)
125
128
  */
126
- export type AIPanelSessionStatusType = "idle" | "running" | "streaming" | "completed";
129
+ export type AIPanelSessionStatusType = SessionStatus;
127
130
  /**
128
131
  * Session 思考状态
129
132
  */
@@ -144,16 +147,22 @@ export interface AIPanelWidgetSession {
144
147
  url?: string;
145
148
  }
146
149
  /**
147
- * 挂件选中的元素
150
+ * 挂件选中的元素(别名:与 host 端 SelectedElement 同构,单一来源为本文件上方的 SelectedElement)
148
151
  */
149
- export interface AIPanelSelectedElement {
150
- /** 节点唯一 id(与 SelectedElement.id 同源,`@节点[n<id>]` 标记与上下文注入共用) */
151
- id?: string;
152
- filePath: string | null;
153
- line: number | null;
154
- column: number | null;
155
- innerText: string;
156
- description?: string;
152
+ export type AIPanelSelectedElement = SelectedElement;
153
+ /**
154
+ * 单条代码诊断(1-based 行列坐标)——AIPanel 诊断工具(run_diagnostics 等)的
155
+ * canonical 持久化/展示共用协议:宿主插件写 tool/result.meta,client 插件据此渲染卡片。
156
+ */
157
+ export interface AIPanelDiagnosticEntry {
158
+ /** 所属文件(绝对路径) */
159
+ file: string;
160
+ /** 1-based 行号 */
161
+ line: number;
162
+ /** 1-based 列号 */
163
+ column: number;
164
+ severity: "error" | "warning";
165
+ message: string;
157
166
  }
158
167
  /**
159
168
  * 删除选中节点的载荷
@@ -185,6 +194,22 @@ export interface AIPanelSelectedElementItem {
185
194
  panelFileText: string;
186
195
  element: AIPanelSelectedElement;
187
196
  }
197
+ /**
198
+ * 服务实例信息(Chrome 扩展 Background ↔ Side Panel 共享的服务载荷;
199
+ * 由 widget 的 SERVICE_INFO 上报与 vite start 端点探测归一化而来)。
200
+ */
201
+ export interface AIPanelServiceInfo {
202
+ /** 代理端口 */
203
+ proxyPort: number;
204
+ /** Vite 开发服务端口(字符串;可能来自 widget 上报或探测 origin) */
205
+ vitePort: string;
206
+ /** 项目根目录 */
207
+ projectRoot: string;
208
+ /** 服务实例唯一 id(多实例隔离) */
209
+ serviceInstanceId: string;
210
+ /** 是否开启 verbose(可选) */
211
+ verbose?: boolean;
212
+ }
188
213
  /**
189
214
  * 挂件组件 Props
190
215
  */
@@ -1,6 +1,3 @@
1
- /**
2
- * @fileoverview 通用工具函数
3
- */
4
1
  /**
5
2
  * 取(或生成)元素的节点唯一 id:优先复用已赋值的 id,否则生成随机 id 并写回元素。
6
3
  * 同一引用在会话标记(`@节点[n<id>]`)与上下文注入里使用同一个 id;
@@ -42,3 +39,29 @@ export declare function base64Decode(base64: string): string;
42
39
  * 支持多种常见响应格式
43
40
  */
44
41
  export declare function extractTextFromResponse(data: unknown): string | null;
42
+ /**
43
+ * 生成节点提及标记 `@节点[n<id>]`(与 ensureNodeId 分配的 n<hex> id 体系一致)
44
+ */
45
+ export declare function toNodeMention(id: string): string;
46
+ /**
47
+ * 从文本中提取全部节点提及 id(去重、保序)
48
+ */
49
+ export declare function parseNodeMentions(text: string): string[];
50
+ /**
51
+ * 构造 iframe postMessage 信封:{ type, ...data }(AIPanel 挂件与 dsh-client 共用同一形状)
52
+ */
53
+ export declare function widgetEnvelope(type: string, data?: Record<string, unknown>): Record<string, unknown>;
54
+ /** 重试配置 */
55
+ export interface RetryOptions {
56
+ /** 总尝试次数(默认 core DEFAULT_RETRIES) */
57
+ attempts?: number;
58
+ /** 失败后连续尝试间隔毫秒(默认 core RETRY_DELAY) */
59
+ delayMs?: number;
60
+ /** 每次失败、重试前回调(attempt 为 1-based) */
61
+ onRetry?: (attempt: number, error: unknown) => void;
62
+ }
63
+ /**
64
+ * 带线性重试的执行包裹:执行 fn 直到成功或尝试完毕;最后一次失败原样抛出。
65
+ * 环境无关(仅使用 setTimeout),放于 common 供浏览器与 node 共用。
66
+ */
67
+ export declare function withRetries<T>(fn: (attempt: number) => Promise<T>, options?: RetryOptions): Promise<T>;
@@ -1,3 +1,4 @@
1
+ import { DEFAULT_RETRIES, RETRY_DELAY } from "./constants.mjs";
1
2
  function ensureNodeId(element) {
2
3
  if (element.id) return element.id;
3
4
  const random = typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID().replace(/-/g, "").slice(0, 8) : Math.random().toString(36).slice(2, 10);
@@ -50,11 +51,51 @@ function extractTextFromResponse(data) {
50
51
  }
51
52
  return null;
52
53
  }
54
+ const NODE_MENTION_RE = /@节点\[(n[0-9a-z]+)\]/g;
55
+ function toNodeMention(id) {
56
+ return `@\u8282\u70B9[${id}]`;
57
+ }
58
+ function parseNodeMentions(text) {
59
+ const out = [];
60
+ const seen = /* @__PURE__ */ new Set();
61
+ for (const m of text.matchAll(NODE_MENTION_RE)) {
62
+ const id = m[1];
63
+ if (!seen.has(id)) {
64
+ seen.add(id);
65
+ out.push(id);
66
+ }
67
+ }
68
+ return out;
69
+ }
70
+ function widgetEnvelope(type, data) {
71
+ return { type, ...data };
72
+ }
73
+ async function withRetries(fn, options = {}) {
74
+ const attempts = options.attempts ?? DEFAULT_RETRIES;
75
+ const delayMs = options.delayMs ?? RETRY_DELAY;
76
+ let lastError;
77
+ for (let i = 0; i < attempts; i++) {
78
+ try {
79
+ return await fn(i);
80
+ } catch (e) {
81
+ lastError = e;
82
+ if (i < attempts - 1) {
83
+ options.onRetry?.(i + 1, e);
84
+ if (delayMs > 0) await sleep(delayMs);
85
+ }
86
+ }
87
+ }
88
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
89
+ }
53
90
  export {
54
91
  base64Decode,
55
92
  base64Encode,
56
93
  ensureNodeId,
57
94
  extractTextFromResponse,
95
+ parseNodeMentions,
58
96
  sleep,
59
- truncate
97
+ toNodeMention,
98
+ truncate,
99
+ widgetEnvelope,
100
+ withRetries
60
101
  };
package/es/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- export * from "./constants";
2
- export * from "./logger-core";
3
- export * from "./logger";
4
- export * from "./options";
5
- export * from "./provider";
6
- export * from "./types";
7
- export * from "./utils";
1
+ export * from "./common/constants";
2
+ export * from "./common/logger-core";
3
+ export * from "./common/options";
4
+ export * from "./common/provider";
5
+ export * from "./common/types";
6
+ export * from "./common/utils";
package/es/index.mjs CHANGED
@@ -1,7 +1,6 @@
1
- export * from "./constants.mjs";
2
- export * from "./logger-core.mjs";
3
- export * from "./logger.mjs";
4
- export * from "./options.mjs";
5
- export * from "./provider.mjs";
6
- export * from "./types.mjs";
7
- export * from "./utils.mjs";
1
+ export * from "./common/constants.mjs";
2
+ export * from "./common/logger-core.mjs";
3
+ export * from "./common/options.mjs";
4
+ export * from "./common/provider.mjs";
5
+ export * from "./common/types.mjs";
6
+ export * from "./common/utils.mjs";
@@ -1,5 +1,10 @@
1
1
  /** 是否为可诊断的源码文件(供宿主钩子过滤 edit/write 目标) */
2
2
  export declare function isJsFile(filePath: string): boolean;
3
+ /**
4
+ * run_diagnostics 工具描述(单一来源,供 opencode / dsh 两侧插件引用):
5
+ * 只声明能力与支持的文件类型,不涉及内部使用的检查工具。
6
+ */
7
+ export declare const DIAGNOSTICS_TOOL_DESCRIPTION: string;
3
8
  /** LSP 风格诊断项(供宿主写入 metadata.diagnostics 等结构化输出) */
4
9
  export interface DiagnosticItem {
5
10
  /** 所属文件路径(相对/绝对,按来源解析);跨文件诊断(全量模式)时必有 */
@@ -2,8 +2,8 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { exec } from "node:child_process";
4
4
  import { createRequire } from "node:module";
5
- import { SEVERITY_ERROR, SEVERITY_WARN } from "../constants.mjs";
6
- import { createLogger } from "../node-logger.mjs";
5
+ import { SEVERITY_ERROR, SEVERITY_WARN } from "../common/constants.mjs";
6
+ import { createLogger } from "./node-logger.mjs";
7
7
  const log = createLogger("Diagnostics");
8
8
  const JS_EXTENSIONS = /* @__PURE__ */ new Set([
9
9
  ".js",
@@ -19,6 +19,19 @@ const JS_EXTENSIONS = /* @__PURE__ */ new Set([
19
19
  function isJsFile(filePath) {
20
20
  return JS_EXTENSIONS.has(path.extname(filePath));
21
21
  }
22
+ const DIAGNOSTICS_TOOL_DESCRIPTION = [
23
+ "\u8FD0\u884C ESLint \u4E0E TypeScript \u7C7B\u578B\u8BCA\u65AD\uFF0C\u8FD4\u56DE\u8BCA\u65AD\u7ED3\u679C\u3002",
24
+ "",
25
+ "**\u652F\u6301\u7684\u6587\u4EF6\u7C7B\u578B**\uFF1A",
26
+ `- ESLint\uFF1AJavaScript / TypeScript / Vue \u6E90\u7801\uFF08${[...JS_EXTENSIONS].map((e) => `*${e}`).join(" ")}\uFF09`,
27
+ "- TypeScript \u7C7B\u578B\u68C0\u67E5\uFF1A*.ts *.tsx *.vue",
28
+ "",
29
+ "**\u4F55\u65F6\u4F7F\u7528\u6B64\u5DE5\u5177**\uFF1A",
30
+ "- \u521A\u5B8C\u6210\u4EE3\u7801\u4FEE\u6539\uFF0C\u60F3\u9A8C\u8BC1\u662F\u5426\u6709 ESLint \u9519\u8BEF\u6216\u7C7B\u578B\u9519\u8BEF",
31
+ "- \u5728\u63D0\u4EA4\u4EE3\u7801\u524D\u8FDB\u884C\u8D28\u91CF\u68C0\u67E5",
32
+ "- \u6392\u67E5\u7F16\u8F91\u5668\u672A\u663E\u793A\u4F46\u5B9E\u9645\u5B58\u5728\u7684\u7C7B\u578B\u95EE\u9898",
33
+ "- \u4E0D\u4F20\u53C2\u6570\u53EF\u5168\u91CF\u8BCA\u65AD\u6574\u4E2A\u9879\u76EE"
34
+ ].join("\n");
22
35
  let ESLintClass;
23
36
  function loadESLint(workspace) {
24
37
  if (ESLintClass) return;
@@ -34,7 +47,12 @@ function loadESLint(workspace) {
34
47
  }
35
48
  async function lintFiles(pattern, cwd, warnLimit = 5) {
36
49
  loadESLint(cwd);
37
- if (!ESLintClass) return {};
50
+ if (!ESLintClass) {
51
+ return {
52
+ text: `[ESLint] \u672A\u8FD0\u884C\uFF1A\u65E0\u6CD5\u5728 workspace "${cwd}" \u89E3\u6790\u5230 eslint\uFF08\u4EC5\u663E\u793A TypeScript \u8BCA\u65AD\uFF09`,
53
+ diagnostics: []
54
+ };
55
+ }
38
56
  try {
39
57
  const eslint = new ESLintClass({ cwd });
40
58
  const results = await eslint.lintFiles(pattern);
@@ -82,7 +100,10 @@ async function lintFiles(pattern, cwd, warnLimit = 5) {
82
100
  return { text: lines.length > 0 ? lines.join("\n") : void 0, diagnostics };
83
101
  } catch (err) {
84
102
  log.warn("ESLint failed", { pattern, error: err.message });
85
- return {};
103
+ return {
104
+ text: `[ESLint] \u8FD0\u884C\u5931\u8D25\uFF1A${err.message}\uFF08\u4EC5\u663E\u793A TypeScript \u8BCA\u65AD\uFF09`,
105
+ diagnostics: []
106
+ };
86
107
  }
87
108
  }
88
109
  let _vueTscBin;
@@ -255,6 +276,7 @@ function formatDiagnosticsSections(title, eslintOutput, tscOutput) {
255
276
  ` + parts.join("\n\n");
256
277
  }
257
278
  export {
279
+ DIAGNOSTICS_TOOL_DESCRIPTION,
258
280
  findAllTsconfigDirs,
259
281
  findTsconfigDir,
260
282
  formatDiagnosticsSections,
@@ -1,6 +1,6 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import { createLogger } from "./logger.mjs";
3
+ import { createLogger } from "../client/logger.mjs";
4
4
  const log = createLogger("FileLogReader");
5
5
  function detectLogLevel(line) {
6
6
  const lowerLine = line.toLowerCase();
@@ -1,4 +1,4 @@
1
- import { type LogContext } from "./logger-core";
1
+ import { type LogContext } from "../common/logger-core";
2
2
  export declare const nodeLogger: {
3
3
  debug(message: string, context?: LogContext, ...args: unknown[]): void;
4
4
  info(message: string, context?: LogContext, ...args: unknown[]): void;