agent-bridge-abweb 1.0.6 → 1.0.7

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.
@@ -5,7 +5,7 @@ const node_fs_1 = require("node:fs");
5
5
  const node_path_1 = require("node:path");
6
6
  const MANIFEST = {
7
7
  id: "abweb",
8
- version: "1.0.6",
8
+ version: "1.0.7",
9
9
  displayName: "Agent Bridge Web",
10
10
  entry: "dist/index.js",
11
11
  apiVersion: "1",
@@ -16,6 +16,9 @@
16
16
  const versionsNode = node("#versions");
17
17
  const policyNode = node("#update-policy");
18
18
  const policyStatusNode = node("#update-policy-status");
19
+ const trustProvidersNode = node("#trust-providers");
20
+ const trustPluginsNode = node("#trust-plugins");
21
+ const trustStatusNode = node("#plugin-trust-status");
19
22
  const loginExpiry = Number(localStorage.getItem("mab-login-expires-at") ?? 0);
20
23
  if (loginExpiry <= Date.now()) {
21
24
  localStorage.removeItem("mab-login-token");
@@ -25,11 +28,32 @@
25
28
  let plugins = [];
26
29
  let selectedChannelId = "";
27
30
  let pluginVersions = {};
31
+ let pluginTrustConfig = { providers: {}, plugins: {} };
32
+ let pluginTrustDirty = false;
28
33
  let logPage = 1;
29
34
  let logHasNext = false;
30
35
  let loading = false;
31
36
  const installingPackages = new Set();
32
37
  function error(message) { errorNode.textContent = message; errorNode.hidden = !message; }
38
+ function showResult(title, message, failed) {
39
+ node("#operation-result-title").textContent = title;
40
+ const detail = node("#operation-result-message");
41
+ detail.textContent = message;
42
+ detail.className = failed ? "error" : "";
43
+ const dialog = node("#operation-result");
44
+ if (!dialog.open)
45
+ dialog.showModal();
46
+ }
47
+ node("#operation-result-close").onclick = () => node("#operation-result").close();
48
+ window.addEventListener("message", (event) => {
49
+ const frame = channelPanel.querySelector("iframe.channel-frame");
50
+ if (event.origin !== window.location.origin || !frame || event.source !== frame.contentWindow)
51
+ return;
52
+ const result = event.data;
53
+ if (!result || result.type !== "mab:operation-result" || typeof result.title !== "string" || typeof result.message !== "string" || typeof result.failed !== "boolean")
54
+ return;
55
+ showResult(result.title, result.message, result.failed);
56
+ });
33
57
  async function loadCatalog() {
34
58
  const result = await request(`/api/plugins/catalog?q=${encodeURIComponent(packageSearchNode.value.trim())}`);
35
59
  const items = result.plugins ?? [];
@@ -108,7 +132,7 @@
108
132
  item.type = "button";
109
133
  item.textContent = label;
110
134
  item.title = title;
111
- item.onclick = () => { void run().catch((cause) => error(String(cause))); };
135
+ item.onclick = () => { item.disabled = true; void run().catch((cause) => { const message = cause instanceof Error ? cause.message : String(cause); error(message); showResult(`${title}失败`, message, true); }).finally(() => { item.disabled = false; void load(false); }); };
112
136
  return item;
113
137
  }
114
138
  async function load(refreshCatalog = true) {
@@ -117,8 +141,8 @@
117
141
  loading = true;
118
142
  try {
119
143
  error("");
120
- const [health, plugins, messages, versions, policy, sessions] = await Promise.all([
121
- request("/api/health"), request("/api/plugins"), request("/api/messages"), request("/api/versions"), request("/api/update-policy"), request("/api/sessions"),
144
+ const [health, plugins, messages, versions, policy, sessions, trust] = await Promise.all([
145
+ request("/api/health"), request("/api/plugins"), request("/api/messages"), request("/api/versions"), request("/api/update-policy"), request("/api/sessions"), request("/api/plugin-trust"),
122
146
  ]);
123
147
  policyNode.value = policy.mode;
124
148
  policyStatusNode.textContent = `当前:${policyNode.options[policyNode.selectedIndex]?.text ?? policy.mode}`;
@@ -127,6 +151,7 @@
127
151
  node("#health").textContent = `服务运行中 · ${health.plugins} 个插件`;
128
152
  node("#access-panel").hidden = true;
129
153
  const installed = plugins.plugins ?? [];
154
+ renderPluginTrust(trust);
130
155
  renderPlugins(installed);
131
156
  renderChannels(installed);
132
157
  renderMessages(messages.messages ?? []);
@@ -199,6 +224,71 @@
199
224
  if (!entries.length)
200
225
  versionsNode.textContent = "尚未检查版本";
201
226
  }
227
+ function renderPluginTrust(data) {
228
+ if (pluginTrustDirty)
229
+ return;
230
+ pluginTrustConfig = structuredClone(data.config ?? { providers: {}, plugins: {} });
231
+ trustProvidersNode.replaceChildren();
232
+ for (const provider of data.providers ?? []) {
233
+ const row = document.createElement("tr");
234
+ const name = document.createElement("td");
235
+ name.textContent = provider.name;
236
+ const current = document.createElement("td");
237
+ current.textContent = provider.trusted ? "可信" : "不可信";
238
+ const action = document.createElement("td");
239
+ const select = document.createElement("select");
240
+ select.setAttribute("aria-label", `${provider.name} 提供者信任策略`);
241
+ for (const [value, label] of [["inherit", "使用默认"], ["allow", "信任并自动升级"], ["deny", "取消信任"]]) {
242
+ const option = document.createElement("option");
243
+ option.value = value;
244
+ option.textContent = label;
245
+ select.append(option);
246
+ }
247
+ select.value = provider.decision;
248
+ select.onchange = () => { pluginTrustDirty = true; if (select.value === "inherit")
249
+ delete pluginTrustConfig.providers[provider.name];
250
+ else
251
+ pluginTrustConfig.providers[provider.name] = select.value; };
252
+ action.append(select);
253
+ row.append(name, current, action);
254
+ trustProvidersNode.append(row);
255
+ }
256
+ trustPluginsNode.replaceChildren();
257
+ for (const entry of data.entries ?? []) {
258
+ const row = document.createElement("tr");
259
+ for (const value of [entry.id, entry.packageName ?? "非 npm 插件", entry.publisher ?? "未知提供者", entry.autoUpdate ? "允许" : "禁止"]) {
260
+ const cell = document.createElement("td");
261
+ cell.textContent = value;
262
+ row.append(cell);
263
+ }
264
+ const action = document.createElement("td");
265
+ const select = document.createElement("select");
266
+ select.setAttribute("aria-label", `${entry.id} 插件自动升级策略`);
267
+ for (const [value, label] of [["inherit", "继承提供者"], ["allow", "允许自动升级"], ["deny", "禁止自动升级"]]) {
268
+ const option = document.createElement("option");
269
+ option.value = value;
270
+ option.textContent = label;
271
+ select.append(option);
272
+ }
273
+ select.value = entry.pluginOverride ?? "inherit";
274
+ select.onchange = () => { pluginTrustDirty = true; if (select.value === "inherit")
275
+ delete pluginTrustConfig.plugins[entry.id];
276
+ else
277
+ pluginTrustConfig.plugins[entry.id] = select.value; };
278
+ action.append(select);
279
+ row.append(action);
280
+ trustPluginsNode.append(row);
281
+ }
282
+ trustStatusNode.textContent = "";
283
+ if (!(data.entries ?? []).length) {
284
+ const row = document.createElement("tr");
285
+ const cell = document.createElement("td");
286
+ cell.colSpan = 5;
287
+ cell.textContent = "暂无可管理的 npm 插件";
288
+ row.append(cell);
289
+ trustPluginsNode.append(row);
290
+ }
291
+ }
202
292
  function renderPlugins(items) {
203
293
  plugins = items;
204
294
  pluginsNode.replaceChildren();
@@ -328,6 +418,7 @@
328
418
  node("#refresh").onclick = () => void load();
329
419
  node("#check-versions").onclick = () => void request("/api/versions/check", "POST", {}).then(() => load()).catch((cause) => error(String(cause)));
330
420
  node("#save-update-policy").onclick = () => void request("/api/update-policy", "PATCH", { mode: policyNode.value }).then(() => load()).catch((cause) => error(String(cause)));
421
+ node("#save-plugin-trust").onclick = () => { const button = node("#save-plugin-trust"); button.disabled = true; trustStatusNode.textContent = "正在保存…"; void request("/api/plugin-trust", "PATCH", pluginTrustConfig).then(() => { pluginTrustDirty = false; trustStatusNode.textContent = "信任设置已保存"; return load(false); }).catch((cause) => { trustStatusNode.textContent = String(cause); }).finally(() => { button.disabled = false; }); };
331
422
  node("#update-core").onclick = () => { if (confirm("确认升级后台并自动重启?"))
332
423
  void request("/api/update", "POST", {}).then(() => { error("后台正在升级,页面将在几秒后恢复"); }).catch((cause) => error(String(cause))); };
333
424
  node("#pair-button").onclick = () => {
@@ -1,5 +1,5 @@
1
1
  (() => {
2
- type Plugin = { id: string; displayName: string; version: string; status: string; type?: string; capabilities?: string[]; error?: string; path: string; packageName?: string; dependencyStatus?: string[]; manifest?: { dependencies?: Record<string, string>; managementPage?: string; clientDownloadUrl?: string } };
2
+ type Plugin = { id: string; displayName: string; version: string; status: string; type?: string; capabilities?: string[]; error?: string; path: string; packageName?: string; publisher?: string; trusted?: boolean; autoUpdate?: boolean; dependencyStatus?: string[]; manifest?: { dependencies?: Record<string, string>; managementPage?: string; clientDownloadUrl?: string } };
3
3
  const node = <T extends HTMLElement>(selector: string): T => document.querySelector<T>(selector)!;
4
4
  const pluginsNode = node<HTMLTableSectionElement>("#plugins");
5
5
  const messagesNode = node<HTMLTableSectionElement>("#messages");
@@ -17,18 +17,38 @@
17
17
  const versionsNode = node<HTMLDivElement>("#versions");
18
18
  const policyNode = node<HTMLSelectElement>("#update-policy");
19
19
  const policyStatusNode = node<HTMLSpanElement>("#update-policy-status");
20
+ const trustProvidersNode = node<HTMLTableSectionElement>("#trust-providers");
21
+ const trustPluginsNode = node<HTMLTableSectionElement>("#trust-plugins");
22
+ const trustStatusNode = node<HTMLSpanElement>("#plugin-trust-status");
20
23
  const loginExpiry = Number(localStorage.getItem("mab-login-expires-at") ?? 0);
21
24
  if (loginExpiry <= Date.now()) { localStorage.removeItem("mab-login-token"); localStorage.removeItem("mab-login-expires-at"); }
22
25
  let authToken = localStorage.getItem("mab-login-token") ?? "";
23
26
  let plugins: Plugin[] = [];
24
27
  let selectedChannelId = "";
25
28
  let pluginVersions: Record<string, any> = {};
29
+ let pluginTrustConfig: { providers: Record<string, "allow" | "deny">; plugins: Record<string, "allow" | "deny"> } = { providers: {}, plugins: {} };
30
+ let pluginTrustDirty = false;
26
31
  let logPage = 1;
27
32
  let logHasNext = false;
28
33
  let loading = false;
29
34
  const installingPackages = new Set<string>();
30
35
 
31
36
  function error(message: string): void { errorNode.textContent = message; errorNode.hidden = !message; }
37
+ function showResult(title: string, message: string, failed: boolean): void {
38
+ node<HTMLElement>("#operation-result-title").textContent = title;
39
+ const detail = node<HTMLElement>("#operation-result-message");
40
+ detail.textContent = message; detail.className = failed ? "error" : "";
41
+ const dialog = node<HTMLDialogElement>("#operation-result");
42
+ if (!dialog.open) dialog.showModal();
43
+ }
44
+ node<HTMLButtonElement>("#operation-result-close").onclick = () => node<HTMLDialogElement>("#operation-result").close();
45
+ window.addEventListener("message", (event: MessageEvent) => {
46
+ const frame = channelPanel.querySelector<HTMLIFrameElement>("iframe.channel-frame");
47
+ if (event.origin !== window.location.origin || !frame || event.source !== frame.contentWindow) return;
48
+ const result = event.data;
49
+ if (!result || result.type !== "mab:operation-result" || typeof result.title !== "string" || typeof result.message !== "string" || typeof result.failed !== "boolean") return;
50
+ showResult(result.title, result.message, result.failed);
51
+ });
32
52
  async function loadCatalog(): Promise<void> {
33
53
  const result = await request(`/api/plugins/catalog?q=${encodeURIComponent(packageSearchNode.value.trim())}`);
34
54
  const items: Array<{ name: string; version: string; description: string; type: string }> = result.plugins ?? [];
@@ -75,15 +95,15 @@
75
95
  }
76
96
  function button(label: string, title: string, run: () => Promise<void>): HTMLButtonElement {
77
97
  const item = document.createElement("button"); item.type = "button"; item.textContent = label; item.title = title;
78
- item.onclick = () => { void run().catch((cause) => error(String(cause))); }; return item;
98
+ item.onclick = () => { item.disabled = true; void run().catch((cause) => { const message = cause instanceof Error ? cause.message : String(cause); error(message); showResult(`${title}失败`, message, true); }).finally(() => { item.disabled = false; void load(false); }); }; return item;
79
99
  }
80
100
  async function load(refreshCatalog = true): Promise<void> {
81
101
  if (loading) return;
82
102
  loading = true;
83
103
  try {
84
104
  error("");
85
- const [health, plugins, messages, versions, policy, sessions] = await Promise.all([
86
- request("/api/health"), request("/api/plugins"), request("/api/messages"), request("/api/versions"), request("/api/update-policy"), request("/api/sessions"),
105
+ const [health, plugins, messages, versions, policy, sessions, trust] = await Promise.all([
106
+ request("/api/health"), request("/api/plugins"), request("/api/messages"), request("/api/versions"), request("/api/update-policy"), request("/api/sessions"), request("/api/plugin-trust"),
87
107
  ]);
88
108
  policyNode.value = policy.mode; policyStatusNode.textContent = `当前:${policyNode.options[policyNode.selectedIndex]?.text ?? policy.mode}`;
89
109
  renderVersions(versions);
@@ -91,6 +111,7 @@
91
111
  node<HTMLElement>("#health").textContent = `服务运行中 · ${health.plugins} 个插件`;
92
112
  node<HTMLElement>("#access-panel").hidden = true;
93
113
  const installed: Plugin[] = plugins.plugins ?? [];
114
+ renderPluginTrust(trust);
94
115
  renderPlugins(installed);
95
116
  renderChannels(installed);
96
117
  renderMessages(messages.messages ?? []);
@@ -133,6 +154,35 @@
133
154
  }));
134
155
  if (!entries.length) versionsNode.textContent = "尚未检查版本";
135
156
  }
157
+ function renderPluginTrust(data: any): void {
158
+ if (pluginTrustDirty) return;
159
+ pluginTrustConfig = structuredClone(data.config ?? { providers: {}, plugins: {} });
160
+ trustProvidersNode.replaceChildren();
161
+ for (const provider of data.providers ?? []) {
162
+ const row = document.createElement("tr");
163
+ const name = document.createElement("td"); name.textContent = provider.name;
164
+ const current = document.createElement("td"); current.textContent = provider.trusted ? "可信" : "不可信";
165
+ const action = document.createElement("td");
166
+ const select = document.createElement("select"); select.setAttribute("aria-label", `${provider.name} 提供者信任策略`);
167
+ for (const [value, label] of [["inherit", "使用默认"], ["allow", "信任并自动升级"], ["deny", "取消信任"]]) { const option = document.createElement("option"); option.value = value; option.textContent = label; select.append(option); }
168
+ select.value = provider.decision;
169
+ select.onchange = () => { pluginTrustDirty = true; if (select.value === "inherit") delete pluginTrustConfig.providers[provider.name]; else pluginTrustConfig.providers[provider.name] = select.value as "allow" | "deny"; };
170
+ action.append(select); row.append(name, current, action); trustProvidersNode.append(row);
171
+ }
172
+ trustPluginsNode.replaceChildren();
173
+ for (const entry of data.entries ?? []) {
174
+ const row = document.createElement("tr");
175
+ for (const value of [entry.id, entry.packageName ?? "非 npm 插件", entry.publisher ?? "未知提供者", entry.autoUpdate ? "允许" : "禁止"]) { const cell = document.createElement("td"); cell.textContent = value; row.append(cell); }
176
+ const action = document.createElement("td");
177
+ const select = document.createElement("select"); select.setAttribute("aria-label", `${entry.id} 插件自动升级策略`);
178
+ for (const [value, label] of [["inherit", "继承提供者"], ["allow", "允许自动升级"], ["deny", "禁止自动升级"]]) { const option = document.createElement("option"); option.value = value; option.textContent = label; select.append(option); }
179
+ select.value = entry.pluginOverride ?? "inherit";
180
+ select.onchange = () => { pluginTrustDirty = true; if (select.value === "inherit") delete pluginTrustConfig.plugins[entry.id]; else pluginTrustConfig.plugins[entry.id] = select.value as "allow" | "deny"; };
181
+ action.append(select); row.append(action); trustPluginsNode.append(row);
182
+ }
183
+ trustStatusNode.textContent = "";
184
+ if (!(data.entries ?? []).length) { const row = document.createElement("tr"); const cell = document.createElement("td"); cell.colSpan = 5; cell.textContent = "暂无可管理的 npm 插件"; row.append(cell); trustPluginsNode.append(row); }
185
+ }
136
186
  function renderPlugins(items: Plugin[]): void {
137
187
  plugins = items;
138
188
  pluginsNode.replaceChildren();
@@ -200,6 +250,7 @@
200
250
  node<HTMLButtonElement>("#refresh").onclick = () => void load();
201
251
  node<HTMLButtonElement>("#check-versions").onclick = () => void request("/api/versions/check", "POST", {}).then(() => load()).catch((cause) => error(String(cause)));
202
252
  node<HTMLButtonElement>("#save-update-policy").onclick = () => void request("/api/update-policy", "PATCH", { mode: policyNode.value }).then(() => load()).catch((cause) => error(String(cause)));
253
+ node<HTMLButtonElement>("#save-plugin-trust").onclick = () => { const button = node<HTMLButtonElement>("#save-plugin-trust"); button.disabled = true; trustStatusNode.textContent = "正在保存…"; void request("/api/plugin-trust", "PATCH", pluginTrustConfig).then(() => { pluginTrustDirty = false; trustStatusNode.textContent = "信任设置已保存"; return load(false); }).catch((cause) => { trustStatusNode.textContent = String(cause); }).finally(() => { button.disabled = false; }); };
203
254
  node<HTMLButtonElement>("#update-core").onclick = () => { if (confirm("确认升级后台并自动重启?")) void request("/api/update", "POST", {}).then(() => { error("后台正在升级,页面将在几秒后恢复"); }).catch((cause) => error(String(cause))); };
204
255
  node<HTMLButtonElement>("#pair-button").onclick = () => {
205
256
  const code = pairCodeNode.value.trim();
@@ -13,6 +13,7 @@
13
13
  <nav class="tabs" role="tablist" aria-label="管理视图"><button id="settings-tab" type="button" role="tab" aria-selected="true" aria-controls="settings-panel">插件设置</button><button id="messages-tab" type="button" role="tab" aria-selected="false" aria-controls="messages-panel">通信记录</button><button id="logs-tab" type="button" role="tab" aria-selected="false" aria-controls="logs-panel">运行日志</button></nav>
14
14
  <div id="settings-panel" role="tabpanel" aria-labelledby="settings-tab">
15
15
  <section><div class="section-heading"><h2>版本管理</h2><div><button id="check-versions" type="button">检查更新</button><button id="update-core" type="button">升级后台</button></div></div><label for="update-policy">插件更新策略</label><select id="update-policy"><option value="auto-install">自动下载并安装</option><option value="download-only">自动下载,手动安装</option><option value="manual">手动下载和安装</option></select><button id="save-update-policy" type="button">保存策略</button><span id="update-policy-status" class="muted"></span><div id="versions" class="muted"></div></section>
16
+ <section id="plugin-trust"><div class="section-heading"><h2>自动升级信任</h2><button id="save-plugin-trust" type="button">保存信任设置</button></div><p class="muted">默认信任 m2lihui;未知提供者默认禁止自动升级。插件设置优先于提供者设置。</p><h3>提供者</h3><div class="table-scroll"><table class="trust-table"><thead><tr><th scope="col">npm 提供者</th><th scope="col">当前信任</th><th scope="col">策略</th></tr></thead><tbody id="trust-providers"></tbody></table></div><h3>插件</h3><div class="table-scroll"><table class="trust-table"><thead><tr><th scope="col">插件</th><th scope="col">npm 包</th><th scope="col">提供者</th><th scope="col">自动升级</th><th scope="col">单插件设置</th></tr></thead><tbody id="trust-plugins"></tbody></table></div><span id="plugin-trust-status" class="muted" role="status"></span></section>
16
17
  <section><details id="installed-plugins" open><summary><h2>已安装插件</h2></summary><div class="table-scroll"><table class="plugin-table"><thead><tr><th scope="col">名称</th><th scope="col">类型</th><th scope="col">版本</th><th scope="col">状态</th><th scope="col">操作</th></tr></thead><tbody id="plugins"></tbody></table></div><div class="plugin-catalog"><div class="section-heading"><h3>npm 插件目录</h3><button id="search-packages" type="button">刷新目录</button></div><input id="package-search" placeholder="搜索插件名称或功能" aria-label="搜索 npm 插件"><div id="catalog" class="catalog" aria-live="polite"></div></div><form id="install-local-form"><input id="plugin-path" required placeholder="Windows 上的插件目录路径" aria-label="本地插件目录"><button type="submit">安装本地插件</button></form></details></section>
17
18
  <section><div class="section-heading"><h2>Channel 设置</h2></div><nav id="channel-tabs" class="tabs channel-tabs" role="tablist" aria-label="Channel 设置"></nav><div id="channel-panel" role="tabpanel" aria-live="polite"></div></section>
18
19
  </div>
@@ -20,6 +21,9 @@
20
21
  <div id="logs-panel" role="tabpanel" aria-labelledby="logs-tab" hidden><section><div class="section-heading"><h2>运行日志</h2><button id="logs-refresh" type="button">刷新日志</button></div><div class="table-scroll"><table><thead><tr><th>时间</th><th>级别</th><th>来源</th><th>消息</th><th>详细字段</th></tr></thead><tbody id="logs"></tbody></table></div><p id="logs-empty" class="muted" hidden>暂无运行日志</p><div class="section-heading"><button id="logs-prev" type="button">上一页</button><span id="logs-page" class="muted">第 1 页</span><button id="logs-next" type="button">下一页</button></div></section></div>
21
22
  <p id="error" class="error" role="alert" hidden></p>
22
23
  </main>
24
+ <dialog id="operation-result" aria-labelledby="operation-result-title" aria-describedby="operation-result-message">
25
+ <h2 id="operation-result-title">操作结果</h2><p id="operation-result-message"></p><button id="operation-result-close" type="button" autofocus>确定</button>
26
+ </dialog>
23
27
  <script src="/abweb/app.js"></script>
24
28
  </body>
25
29
  </html>
@@ -29,6 +29,9 @@ form { margin-top: 14px; flex-wrap: wrap; }
29
29
  .plugin-table .controls { white-space: nowrap; }
30
30
  .plugin-table .controls button { margin: 0 5px 5px 0; }
31
31
  .plugin-id { display: block; margin-top: 4px; }
32
+ .trust-table { min-width: 620px; }
33
+ .trust-table th:nth-child(1) { width: 190px; }
34
+ #plugin-trust h3 { font-size: 14px; margin: 16px 0 5px; }
32
35
  .plugin-catalog { border-top: 1px solid #e0e5e2; margin-top: 18px; padding-top: 14px; }
33
36
  .plugin-catalog h3 { font-size: 14px; margin: 0; }
34
37
  .plugin-catalog input { width: min(100%, 420px); margin: 10px 0; }
@@ -53,3 +56,7 @@ th { color: #566761; font-weight: 600; background: #edf1ef; }
53
56
  th:nth-child(1) { width: 145px; } th:nth-child(2) { width: 100px; } th:nth-child(3), th:nth-child(4) { width: 145px; } th:nth-child(5) { width: 62px; } th:nth-child(7) { width: 140px; }
54
57
  .message-error td:last-child { color: #a83427; }
55
58
  @media (max-width: 620px) { .shell { padding: 16px; } .section-heading { align-items: flex-start; flex-direction: column; } form, form input { width: 100%; } }
59
+
60
+ #operation-result { width: min(520px, calc(100% - 32px)); border: 1px solid #bfc9c5; border-radius: 8px; padding: 24px; }
61
+ #operation-result::backdrop { background: rgb(0 0 0 / 35%); }
62
+ #operation-result-message { white-space: pre-wrap; overflow-wrap: anywhere; margin: 16px 0; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-bridge-abweb",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "agent-bridge 的网页管理插件。",
5
5
  "keywords": [
6
6
  "mu-agent-bridge-plugin",
package/plugin.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "id": "abweb",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "type": "management",
5
5
  "displayName": "Agent Bridge Web",
6
6
  "entry": "dist/src-ts/plugins/abweb/index.js",