openclaw-openagent 1.0.8 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/src/app/remote-agent-tool.js +108 -10
  2. package/dist/src/auth/config.js +65 -10
  3. package/dist/src/channel.js +2 -1
  4. package/dist/src/plugin-ui/assets/bg.png +0 -0
  5. package/dist/src/plugin-ui/assets/icon.png +0 -0
  6. package/dist/src/plugin-ui/assets/openagent-override.js +1753 -774
  7. package/dist/src/plugin-ui/ui-extension-loader/registry-regex.js +53 -5
  8. package/dist/src/proxy/auth-proxy.d.ts +1 -0
  9. package/dist/src/proxy/auth-proxy.js +28 -9
  10. package/dist/src/transport/oasn/oasn-http.d.ts +12 -0
  11. package/dist/src/transport/oasn/oasn-http.js +45 -14
  12. package/dist/src/util/url-resolver.d.ts +6 -0
  13. package/dist/src/util/url-resolver.js +24 -8
  14. package/openclaw.plugin.json +16 -1
  15. package/package.json +3 -3
  16. package/src/app/remote-agent-tool.ts +126 -11
  17. package/src/auth/config.ts +79 -10
  18. package/src/channel.ts +2 -1
  19. package/src/plugin-ui/assets/bg.png +0 -0
  20. package/src/plugin-ui/assets/icon.png +0 -0
  21. package/src/plugin-ui/assets/openagent-override.js +1753 -774
  22. package/src/plugin-ui/build.cjs +80 -4
  23. package/src/plugin-ui/modules/agent-book/panel/agent-book.js +92 -9
  24. package/src/plugin-ui/modules/agent-book/panel/agent-card.js +26 -10
  25. package/src/plugin-ui/modules/agent-book/panel/agent-data.js +1 -1
  26. package/src/plugin-ui/modules/agent-book/panel/inject-ui.js +64 -0
  27. package/src/plugin-ui/modules/agent-book/panel/styles.js +313 -178
  28. package/src/plugin-ui/modules/loader/bootstrap.js +1 -1
  29. package/src/plugin-ui/modules/loader/shared-state.js +54 -0
  30. package/src/plugin-ui/modules/remote-agent/execution-card.js +347 -124
  31. package/src/plugin-ui/modules/remote-agent/media-links.js +151 -0
  32. package/src/plugin-ui/modules/remote-agent/output-card.js +110 -33
  33. package/src/plugin-ui/modules/remote-agent/render-hooks.js +97 -18
  34. package/src/plugin-ui/modules/remote-agent/styles.js +488 -402
  35. package/src/plugin-ui/modules/remote-agent/tool-card-model.js +6 -0
  36. package/src/plugin-ui/ui-extension-loader/registry-regex.ts +50 -5
  37. package/src/proxy/auth-proxy.ts +30 -10
  38. package/src/transport/oasn/oasn-http.ts +60 -14
  39. package/src/util/url-resolver.ts +24 -8
@@ -14,6 +14,26 @@
14
14
  const fs = require('fs');
15
15
  const path = require('path');
16
16
 
17
+ // ── 读取 OpenClaw 版本(用于注入到产物中)──
18
+ function resolveHostVersion() {
19
+ // 优先使用环境变量
20
+ if (process.env.OPENCLAW_HOST_VERSION) return process.env.OPENCLAW_HOST_VERSION;
21
+
22
+ // 从 package.json devDependencies 读取
23
+ try {
24
+ var pkgPath = path.join(__dirname, '..', 'package.json');
25
+ if (fs.existsSync(pkgPath)) {
26
+ var pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
27
+ var ver = (pkg.devDependencies && pkg.devDependencies.openclaw) || '';
28
+ // 去掉 ^ 前缀: "^2026.4.22" → "2026.4.22"
29
+ ver = String(ver).replace(/^[\^~>=<]+/, '').trim();
30
+ if (ver) return ver;
31
+ }
32
+ } catch (e) {}
33
+
34
+ return '2026.4.22'; // 默认 fallback
35
+ }
36
+
17
37
  // ═══════════════════════════════════════════════════════════════
18
38
  // MANIFEST — 显式构建顺序,不要用 readdir+sort
19
39
  // 新增模块必须在此注册,否则不进产物
@@ -48,6 +68,7 @@ const MANIFEST = [
48
68
  'remote-agent/tool-card-model.js',
49
69
  'remote-agent/execution-card.js',
50
70
  'remote-agent/markdown-renderer.js',
71
+ 'remote-agent/media-links.js',
51
72
  'remote-agent/output-card.js',
52
73
  'remote-agent/render-hooks.js',
53
74
  // ── loader (bootstrap 必须最后) ──
@@ -57,7 +78,10 @@ const MANIFEST = [
57
78
  // ═══════════════════════════════════════════════════════════════
58
79
 
59
80
  const modulesDir = path.join(__dirname, 'modules');
60
- const outFile = path.join(__dirname, 'assets', 'openagent-override.js');
81
+ const assetsDir = path.join(__dirname, 'assets');
82
+ const outFile = path.join(assetsDir, 'openagent-override.js');
83
+ const iconFile = path.join(assetsDir, 'icon.png');
84
+ const bgFile = path.join(assetsDir, 'bg.png');
61
85
 
62
86
  const HEADER = `/**
63
87
  * OpenAgent UI Override — Auto-generated, do not edit directly!
@@ -106,7 +130,9 @@ function build() {
106
130
  return;
107
131
  }
108
132
 
109
- const output = HEADER + body + FOOTER;
133
+ // ── 不做构建时版本注入,由运行时 DOM/CSS 特征检测 ──
134
+ // (build.cjs 无法知道实际运行的 OpenClaw 版本)
135
+ var output = HEADER + body + FOOTER;
110
136
 
111
137
  fs.mkdirSync(path.dirname(outFile), { recursive: true });
112
138
  fs.writeFileSync(outFile, output, 'utf-8');
@@ -122,11 +148,19 @@ function build() {
122
148
 
123
149
  const DEPLOY_TARGETS = [
124
150
  // 插件安装目录(Gateway 启动时从这里读取并复制到 control-ui)
125
- // 注意:安装目录仍使用旧路径 src/inject/,下次 npm publish 后才会变
126
151
  path.join(homedir, '.openclaw-docker/extensions/openclaw-openagent/src/inject/assets/openagent-override.js'),
127
152
  path.join(homedir, '.openclaw-docker/extensions/openclaw-openagent/src/plugin-ui/assets/openagent-override.js'),
128
153
  path.join(homedir, '.openclaw/extensions/openclaw-openagent/src/inject/assets/openagent-override.js'),
129
154
  path.join(homedir, '.openclaw/extensions/openclaw-openagent/src/plugin-ui/assets/openagent-override.js'),
155
+ // 本地开发 dist/ 目录
156
+ path.join(__dirname, '..', '..', 'dist', 'src', 'plugin-ui', 'assets', 'openagent-override.js'),
157
+ // 本地 node_modules 中的 openclaw control-ui(Gateway 实际运行路径)
158
+ path.join(__dirname, '..', '..', 'node_modules', 'openclaw', 'dist', 'control-ui', 'openagent-override.js'),
159
+ // npm 全局安装 + 项目缓存(Gateway 可能从这些路径加载)
160
+ path.join(homedir, '.openclaw/npm/projects/openclaw-openagent/node_modules/openclaw-openagent/src/plugin-ui/assets/openagent-override.js'),
161
+ path.join(homedir, '.openclaw/npm/projects/openclaw-openagent/node_modules/openclaw-openagent/dist/src/plugin-ui/assets/openagent-override.js'),
162
+ path.join(homedir, '.nvm/versions/node/v22.21.1/lib/node_modules/openclaw-openagent/src/plugin-ui/assets/openagent-override.js'),
163
+ path.join(homedir, '.nvm/versions/node/v22.21.1/lib/node_modules/openclaw-openagent/dist/src/plugin-ui/assets/openagent-override.js'),
130
164
  ];
131
165
 
132
166
  // 动态发现 control-ui 目录(通过 node 可执行文件路径推断)
@@ -148,10 +182,52 @@ function build() {
148
182
  }
149
183
 
150
184
  if (deployed > 0) {
151
- console.log(`✅ Auto-deployed to ${deployed} target(s)`);
185
+ console.log(`✅ Auto-deployed override to ${deployed} target(s)`);
152
186
  } else {
153
187
  console.log('ℹ️ No deploy targets found (standalone build)');
154
188
  }
189
+
190
+ // ── Shared asset deploy targets (control-ui + extension dirs) ──
191
+ const ASSET_DEPLOY_TARGETS = [
192
+ path.join(homedir, '.openclaw-docker/extensions/openclaw-openagent/src/inject/assets'),
193
+ path.join(homedir, '.openclaw-docker/extensions/openclaw-openagent/src/plugin-ui/assets'),
194
+ path.join(homedir, '.openclaw/extensions/openclaw-openagent/src/inject/assets'),
195
+ path.join(homedir, '.openclaw/extensions/openclaw-openagent/src/plugin-ui/assets'),
196
+ path.join(__dirname, '..', '..', 'dist', 'src', 'plugin-ui', 'assets'),
197
+ path.join(__dirname, '..', '..', 'node_modules', 'openclaw', 'dist', 'control-ui'),
198
+ path.join(homedir, '.openclaw/npm/projects/openclaw-openagent/node_modules/openclaw-openagent/src/plugin-ui/assets'),
199
+ path.join(homedir, '.openclaw/npm/projects/openclaw-openagent/node_modules/openclaw-openagent/dist/src/plugin-ui/assets'),
200
+ path.join(homedir, '.nvm/versions/node/v22.21.1/lib/node_modules/openclaw-openagent/src/plugin-ui/assets'),
201
+ path.join(homedir, '.nvm/versions/node/v22.21.1/lib/node_modules/openclaw-openagent/dist/src/plugin-ui/assets'),
202
+ ];
203
+
204
+ try {
205
+ const nodeDir = path.dirname(process.execPath);
206
+ ASSET_DEPLOY_TARGETS.push(path.resolve(path.join(nodeDir, '..', 'lib', 'node_modules', 'openclaw', 'dist', 'control-ui')));
207
+ } catch {}
208
+
209
+ // ── Deploy image assets (icon.png, bg.png) ──
210
+ const IMAGE_ASSETS = [
211
+ { file: iconFile, name: 'icon.png' },
212
+ { file: bgFile, name: 'bg.png' },
213
+ ];
214
+
215
+ for (const asset of IMAGE_ASSETS) {
216
+ if (!fs.existsSync(asset.file)) continue;
217
+ let deployed = 0;
218
+ for (const dir of ASSET_DEPLOY_TARGETS) {
219
+ try {
220
+ const dest = path.join(dir, asset.name);
221
+ if (fs.existsSync(dir)) {
222
+ fs.copyFileSync(asset.file, dest);
223
+ deployed++;
224
+ }
225
+ } catch {}
226
+ }
227
+ if (deployed > 0) {
228
+ console.log(`✅ Auto-deployed ${asset.name} to ${deployed} target(s)`);
229
+ }
230
+ }
155
231
  }
156
232
 
157
233
  // ── Execution ──
@@ -45,9 +45,9 @@ panel.innerHTML = `
45
45
  <path d="M39 31H42C44.2091 31 46 29.2091 46 27V17C46 14.7909 44.2091 13 42 13H24C21.7909 13 20 14.7909 20 17V27C20 29.2091 21.7909 31 24 31H30.0652C30.236 31 30.3282 31.2004 30.217 31.3302L27.5 34.5" stroke="#12CCF6" stroke-width="3.3" stroke-linecap="round"/>
46
46
  <path d="M27 25.5L32.5 21" stroke="#12CCF6" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
47
47
  </svg>
48
- <span class="panel-title-text">Agent Book</span>
48
+ <span class="panel-title-text">OpenAgent</span>
49
49
  </span>
50
- <button class="openagent-panel-close">✕</button>
50
+ <button class="openagent-panel-close"><svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21" fill="none"><path d="M5.625 5.625L15.375 15.375" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/><path d="M15.375 5.625L5.625 15.375" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
51
51
  </div>
52
52
  <hr class="openagent-panel-divider" />
53
53
  <div class="openagent-agent-list">
@@ -60,6 +60,15 @@ panel.querySelector('.openagent-panel-close').addEventListener('click', () => {
60
60
  closePanel();
61
61
  });
62
62
 
63
+
64
+ // 提示栏关闭按钮
65
+ const hintClose = panel.querySelector('.openagent-hint-bar__close');
66
+ if (hintClose) {
67
+ hintClose.addEventListener('click', () => {
68
+ const hintBar = panel.querySelector('.openagent-hint-bar');
69
+ if (hintBar) hintBar.style.display = 'none';
70
+ });
71
+ }
63
72
  // 挂到 body(与 backdrop 同级,z-index 自然生效)
64
73
  document.body.appendChild(panel);
65
74
  return panel;
@@ -98,6 +107,12 @@ return textarea.value.replace(/@/g, ' ').replace(/\s+/g, ' ').trim();
98
107
  }
99
108
 
100
109
  function openPanel(textarea) {
110
+ // 清除上次的空状态弹窗
111
+ var oldToast = document.querySelector('.openagent-empty-toast');
112
+ if (oldToast) oldToast.remove();
113
+ var oldEmpty = document.querySelector('.openagent-empty-state');
114
+ if (oldEmpty) oldEmpty.remove();
115
+
101
116
  const p = ensurePanel();
102
117
  _positionPanel(); // 动态定位到 input 上方
103
118
  p.classList.add('visible');
@@ -281,14 +296,82 @@ function _appendSearchResults(container, agents, textarea, renderedAgents) {
281
296
  container.appendChild(list);
282
297
  }
283
298
 
299
+ /**
300
+ * 空状态组件(Figma 144:3444)— 未匹配到 Agent 时显示
301
+ */
302
+ /** 关闭已有空状态浮层 */
303
+ function _dismissEmptyToast() {
304
+ var existing = document.querySelector('.openagent-empty-toast');
305
+ if (existing) existing.remove();
306
+ }
307
+
308
+ /** 独立浮层空状态(不在面板内) */
309
+ function _showEmptyToast(query) {
310
+ _dismissEmptyToast();
311
+ var toast = _el('div', 'openagent-empty-toast');
312
+
313
+ var iconWrap = _el('div', 'openagent-empty-state__icon');
314
+ iconWrap.innerHTML = '<svg width="14" height="14" viewBox="0 0 14 14" fill="none">' +
315
+ '<path d="M7 1.5C10.0376 1.5 12.5 3.96243 12.5 7C12.5 8.69527 11.7389 10.2145 10.5237 11.2559L13.0303 13.7626C13.3232 14.0555 13.3232 14.5303 13.0303 14.8232C12.7374 15.1161 12.2626 15.1161 11.9697 14.8232L9.38402 12.2376C8.53401 12.7803 7.49507 13.1079 6.37793 13.1079L7 12.5C6.99363 12.5008 6.98726 12.5012 6.98089 12.5012C3.9368 12.5307 1.46927 10.0632 1.49878 7.01908C1.52829 3.97499 3.99398 1.50537 7.03789 1.5H7ZM7 3C4.79086 3 3 4.79086 3 7C3 9.20914 4.79086 11 7 11C9.20914 11 11 9.20914 11 7C11 4.79086 9.20914 3 7 3Z" fill="#8274ff" fill-opacity="0.6"/>' +
316
+ '</svg>';
317
+ toast.appendChild(iconWrap);
318
+
319
+ toast.appendChild(_text('span', 'openagent-empty-state__text',
320
+ query ? '暂未匹配到您想要的Agent 我们将持续上新~' : '暂无在线 Agent,请输入关键词搜索'));
321
+
322
+ var closeBtn = _el('button', 'openagent-empty-state__close');
323
+ closeBtn.innerHTML = '<svg width="12" height="12" viewBox="0 0 12 12" fill="none">' +
324
+ '<path d="M1 1L11 11M11 1L1 11" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>' +
325
+ '</svg>';
326
+ closeBtn.addEventListener('click', function() { toast.remove(); });
327
+ toast.appendChild(closeBtn);
328
+
329
+ // 定位到输入框上方
330
+ if (inputWrapperRef) {
331
+ var rect = inputWrapperRef.getBoundingClientRect();
332
+ toast.style.position = 'fixed';
333
+ toast.style.left = Math.max(16, rect.left) + 'px';
334
+ toast.style.width = Math.min(rect.width, window.innerWidth - 32) + 'px';
335
+ toast.style.bottom = (window.innerHeight - rect.top + 8) + 'px';
336
+ toast.style.zIndex = '100000';
337
+ }
338
+ document.body.appendChild(toast);
339
+ }
340
+
341
+ function _createEmptyState(query) {
342
+ var wrapper = _el('div', 'openagent-empty-state');
343
+ var row = _el('div', 'openagent-empty-state__row');
344
+
345
+ var iconWrap = _el('div', 'openagent-empty-state__icon');
346
+ iconWrap.innerHTML = '<svg width="14" height="14" viewBox="0 0 14 14" fill="none">' +
347
+ '<path d="M7 1.5C10.0376 1.5 12.5 3.96243 12.5 7C12.5 8.69527 11.7389 10.2145 10.5237 11.2559L13.0303 13.7626C13.3232 14.0555 13.3232 14.5303 13.0303 14.8232C12.7374 15.1161 12.2626 15.1161 11.9697 14.8232L9.38402 12.2376C8.53401 12.7803 7.49507 13.1079 6.37793 13.1079L7 12.5C6.99363 12.5008 6.98726 12.5012 6.98089 12.5012C3.9368 12.5307 1.46927 10.0632 1.49878 7.01908C1.52829 3.97499 3.99398 1.50537 7.03789 1.5H7ZM7 3C4.79086 3 3 4.79086 3 7C3 9.20914 4.79086 11 7 11C9.20914 11 11 9.20914 11 7C11 4.79086 9.20914 3 7 3Z" fill="#8274ff" fill-opacity="0.6"/>' +
348
+ '</svg>';
349
+ row.appendChild(iconWrap);
350
+
351
+ var text = _text('span', 'openagent-empty-state__text',
352
+ query ? '暂未匹配到您想要的Agent 我们将持续上新~' : '暂无在线 Agent,请输入关键词搜索');
353
+ row.appendChild(text);
354
+
355
+ var closeBtn = _el('button', 'openagent-empty-state__close');
356
+ closeBtn.innerHTML = '<svg width="12" height="12" viewBox="0 0 12 12" fill="none">' +
357
+ '<path d="M1 1L11 11M11 1L1 11" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"/>' +
358
+ '</svg>';
359
+ closeBtn.addEventListener('click', function() {
360
+ wrapper.style.display = 'none';
361
+ });
362
+ row.appendChild(closeBtn);
363
+
364
+ wrapper.appendChild(row);
365
+ return wrapper;
366
+ }
367
+
284
368
  function renderAgentList(container, agents, textarea, query) {
285
- if (!agents.length) {
286
- const message = CL.agentBookLastError || '暂无在线 Agent';
287
- container.innerHTML = '';
288
- container.appendChild(_text('div', 'openagent-loading', message));
289
- _currentAgents = [];
290
- _currentTextarea = textarea;
291
- return;
369
+ if (!agents.length) {
370
+ _currentAgents = [];
371
+ _currentTextarea = textarea;
372
+ closePanel();
373
+ _showEmptyToast(query);
374
+ return;
292
375
  }
293
376
 
294
377
  console.log('[openagent] renderAgentList:', agents.length, 'agents, textarea:', !!textarea);
@@ -44,17 +44,23 @@ function AgentCard(agent, opts = {}) {
44
44
  info.appendChild(_text('div', 'agent-card__name', agent.name || ''));
45
45
  info.appendChild(_text('div', 'agent-card__bio', agent.bio || '暂无简介'));
46
46
  const stats = _el('div', 'agent-card__stats');
47
- stats.appendChild(_text('span', 'agent-card__stat agent-card__stat--claws', `${formatNumber(agent.claws)}☆`));
47
+ // 星标 + 数字 紧密组合(Figma gap 1.5px)
48
+ const statGroup = _el('span', 'agent-card__stat-group');
49
+ var starIcon = _el('span', 'agent-card__stat-icon');
50
+ starIcon.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M5.94531 0.525391C6.08953 0.525551 6.20334 0.604267 6.25098 0.701172L7.59668 3.43262L7.71875 3.68066L7.99121 3.7207L11.0859 4.16992V4.1709H11.0869C11.1865 4.18536 11.2656 4.2375 11.3135 4.30371L11.3506 4.37402C11.3752 4.44422 11.3691 4.52183 11.3301 4.58984L11.2803 4.6543L9.01172 6.86914L8.81543 7.06152L8.86133 7.33301L9.3877 10.4043C9.40428 10.501 9.36472 10.6085 9.26172 10.6797C9.20158 10.7197 9.13 10.7412 9.05762 10.7412C9.00017 10.7412 8.94132 10.7275 8.8877 10.7002L6.18945 9.2793L5.94531 9.15039L5.7002 9.2793L3.00684 10.6982C2.95198 10.7266 2.89097 10.7412 2.83203 10.7412C2.77821 10.7412 2.72454 10.7298 2.67578 10.707L2.62891 10.6797C2.52556 10.6083 2.48649 10.5012 2.50293 10.4053V10.4043L3.0293 7.33301L3.0752 7.06152L2.87793 6.86914L0.611328 4.6543L0.610352 4.65332L0.560547 4.58984C0.521516 4.522 0.515166 4.44401 0.540039 4.37305L0.539062 4.37207C0.573747 4.27569 0.671018 4.18999 0.803711 4.1709L0.804688 4.16992L3.89844 3.7207L4.17188 3.68066L4.29395 3.43262L5.63867 0.702148C5.68788 0.603278 5.80274 0.525391 5.94531 0.525391Z" stroke="#666666" stroke-width="1.05"/></svg>';
51
+ statGroup.appendChild(starIcon);
52
+ statGroup.appendChild(_text('span', 'agent-card__stat agent-card__stat--claws', formatNumber(agent.claws)));
53
+ stats.appendChild(statGroup);
48
54
  if (agent.owner) {
49
- stats.appendChild(_text('span', 'agent-card__stat agent-card__stat--owner', ` · owner${agent.owner}`));
55
+ stats.appendChild(_text('span', 'agent-card__stat agent-card__stat--owner', ` · ${agent.owner}`));
50
56
  }
51
57
  info.appendChild(stats);
52
58
  contentGroup.appendChild(info);
53
59
 
54
60
  row1.appendChild(contentGroup);
55
61
 
56
- // @Try 按钮
57
- const defaultLabel = 'Try';
62
+ // @召唤 按钮
63
+ const defaultLabel = '@召唤';
58
64
  const btn = _text('button', 'agent-card__action', actionLabel || defaultLabel);
59
65
  if (onAction) {
60
66
  btn.addEventListener('click', (e) => {
@@ -90,14 +96,19 @@ function AgentCard(agent, opts = {}) {
90
96
  body.appendChild(_text('div', 'agent-card__bio', agent.bio || '暂无简介'));
91
97
 
92
98
  const stats = _el('div', 'agent-card__stats');
93
- stats.appendChild(_text('span', 'agent-card__stat agent-card__stat--claws', `${formatNumber(agent.claws)}☆`));
99
+ const statGroup = _el('span', 'agent-card__stat-group');
100
+ var starIcon = _el('span', 'agent-card__stat-icon');
101
+ starIcon.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M5.94531 0.525391C6.08953 0.525551 6.20334 0.604267 6.25098 0.701172L7.59668 3.43262L7.71875 3.68066L7.99121 3.7207L11.0859 4.16992V4.1709H11.0869C11.1865 4.18536 11.2656 4.2375 11.3135 4.30371L11.3506 4.37402C11.3752 4.44422 11.3691 4.52183 11.3301 4.58984L11.2803 4.6543L9.01172 6.86914L8.81543 7.06152L8.86133 7.33301L9.3877 10.4043C9.40428 10.501 9.36472 10.6085 9.26172 10.6797C9.20158 10.7197 9.13 10.7412 9.05762 10.7412C9.00017 10.7412 8.94132 10.7275 8.8877 10.7002L6.18945 9.2793L5.94531 9.15039L5.7002 9.2793L3.00684 10.6982C2.95198 10.7266 2.89097 10.7412 2.83203 10.7412C2.77821 10.7412 2.72454 10.7298 2.67578 10.707L2.62891 10.6797C2.52556 10.6083 2.48649 10.5012 2.50293 10.4053V10.4043L3.0293 7.33301L3.0752 7.06152L2.87793 6.86914L0.611328 4.6543L0.610352 4.65332L0.560547 4.58984C0.521516 4.522 0.515166 4.44401 0.540039 4.37305L0.539062 4.37207C0.573747 4.27569 0.671018 4.18999 0.803711 4.1709L0.804688 4.16992L3.89844 3.7207L4.17188 3.68066L4.29395 3.43262L5.63867 0.702148C5.68788 0.603278 5.80274 0.525391 5.94531 0.525391Z" stroke="#666666" stroke-width="1.05"/></svg>';
102
+ statGroup.appendChild(starIcon);
103
+ statGroup.appendChild(_text('span', 'agent-card__stat agent-card__stat--claws', formatNumber(agent.claws)));
104
+ stats.appendChild(statGroup);
94
105
  if (agent.owner) {
95
- stats.appendChild(_text('span', 'agent-card__stat agent-card__stat--owner', ` · owner${agent.owner}`));
106
+ stats.appendChild(_text('span', 'agent-card__stat agent-card__stat--owner', ` · ${agent.owner}`));
96
107
  }
97
108
  body.appendChild(stats);
98
109
  card.appendChild(body);
99
110
 
100
- const btn = _text('button', 'agent-card__action', actionLabel || 'Try');
111
+ const btn = _text('button', 'agent-card__action', actionLabel || '@召唤');
101
112
  if (onAction) {
102
113
  btn.addEventListener('click', (e) => {
103
114
  e.stopPropagation();
@@ -134,14 +145,19 @@ function AgentCard(agent, opts = {}) {
134
145
  body.appendChild(_text('div', 'agent-card__bio', agent.bio || '暂无简介'));
135
146
 
136
147
  const stats = _el('div', 'agent-card__stats');
137
- stats.appendChild(_text('span', 'agent-card__stat agent-card__stat--claws', `${formatNumber(agent.claws)}☆`));
148
+ const statGroup = _el('span', 'agent-card__stat-group');
149
+ var starIcon = _el('span', 'agent-card__stat-icon');
150
+ starIcon.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M5.94531 0.525391C6.08953 0.525551 6.20334 0.604267 6.25098 0.701172L7.59668 3.43262L7.71875 3.68066L7.99121 3.7207L11.0859 4.16992V4.1709H11.0869C11.1865 4.18536 11.2656 4.2375 11.3135 4.30371L11.3506 4.37402C11.3752 4.44422 11.3691 4.52183 11.3301 4.58984L11.2803 4.6543L9.01172 6.86914L8.81543 7.06152L8.86133 7.33301L9.3877 10.4043C9.40428 10.501 9.36472 10.6085 9.26172 10.6797C9.20158 10.7197 9.13 10.7412 9.05762 10.7412C9.00017 10.7412 8.94132 10.7275 8.8877 10.7002L6.18945 9.2793L5.94531 9.15039L5.7002 9.2793L3.00684 10.6982C2.95198 10.7266 2.89097 10.7412 2.83203 10.7412C2.77821 10.7412 2.72454 10.7298 2.67578 10.707L2.62891 10.6797C2.52556 10.6083 2.48649 10.5012 2.50293 10.4053V10.4043L3.0293 7.33301L3.0752 7.06152L2.87793 6.86914L0.611328 4.6543L0.610352 4.65332L0.560547 4.58984C0.521516 4.522 0.515166 4.44401 0.540039 4.37305L0.539062 4.37207C0.573747 4.27569 0.671018 4.18999 0.803711 4.1709L0.804688 4.16992L3.89844 3.7207L4.17188 3.68066L4.29395 3.43262L5.63867 0.702148C5.68788 0.603278 5.80274 0.525391 5.94531 0.525391Z" stroke="#666666" stroke-width="1.05"/></svg>';
151
+ statGroup.appendChild(starIcon);
152
+ statGroup.appendChild(_text('span', 'agent-card__stat agent-card__stat--claws', formatNumber(agent.claws)));
153
+ stats.appendChild(statGroup);
138
154
  if (agent.owner) {
139
- stats.appendChild(_text('span', 'agent-card__stat agent-card__stat--owner', ` · owner${agent.owner}`));
155
+ stats.appendChild(_text('span', 'agent-card__stat agent-card__stat--owner', ` · ${agent.owner}`));
140
156
  }
141
157
  body.appendChild(stats);
142
158
  card.appendChild(body);
143
159
 
144
- const btn = _text('button', 'agent-card__action', actionLabel || '@ Chat');
160
+ const btn = _text('button', 'agent-card__action', actionLabel || '@召唤');
145
161
  if (onAction) {
146
162
  btn.addEventListener('click', (e) => { e.stopPropagation(); onAction(agent); });
147
163
  card.addEventListener('click', (e) => { e.stopPropagation(); onAction(agent); });
@@ -619,7 +619,7 @@ function avatarUrl(agent) {
619
619
  if (agent.avatar.startsWith('http')) return agent.avatar;
620
620
  return CL.AUTH_API + '/' + agent.avatar;
621
621
  }
622
- return `https://ui-avatars.com/api/?name=${encodeURIComponent(agent.name)}&background=random&size=64`;
622
+ return './icon.png';
623
623
  }
624
624
 
625
625
  const ESC_MAP = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' };
@@ -136,6 +136,23 @@ function _installSendClickInterceptor() {
136
136
  }, true);
137
137
  }
138
138
 
139
+ function _installSendKeydownInterceptor() {
140
+ if (window.__openagentSendKeydownInterceptorInstalled) return;
141
+ window.__openagentSendKeydownInterceptorInstalled = true;
142
+ document.addEventListener('keydown', function(e) {
143
+ if (!CL.pendingMention || CL.remoteSendInFlight) return;
144
+ if (e.key !== 'Enter' || e.shiftKey || e.isComposing) return;
145
+
146
+ const textarea = _getTextarea();
147
+ if (!textarea || e.target !== textarea) return;
148
+
149
+ e.preventDefault();
150
+ e.stopPropagation();
151
+ if (typeof e.stopImmediatePropagation === 'function') e.stopImmediatePropagation();
152
+ _sendPendingMention(textarea);
153
+ }, true);
154
+ }
155
+
139
156
  /**
140
157
  * 多策略定位 textarea 所在输入区域的工具栏行。
141
158
  * v4.x: 工具栏在 textarea.parentElement.children 中
@@ -184,6 +201,7 @@ function tryInject() {
184
201
 
185
202
  if (!textarea) return false;
186
203
  _installSendClickInterceptor();
204
+ _installSendKeydownInterceptor();
187
205
  if (document.querySelector('.openagent-at-btn')) return true; // 已注入
188
206
 
189
207
  // ── 定位插入点:麦克风图标所在的 toolbar 行(多策略)──
@@ -202,6 +220,8 @@ function tryInject() {
202
220
  const pos = ta.selectionStart;
203
221
  // 如果光标前已经是 @,不重复插入
204
222
  if (pos > 0 && val[pos - 1] === '@') {
223
+ // 按钮主动触发 → 清除 dismissed 状态,确保弹窗能打开
224
+ if (typeof resetMention === 'function') resetMention();
205
225
  _handleStateChange(ta);
206
226
  return;
207
227
  }
@@ -260,9 +280,53 @@ function tryInject() {
260
280
 
261
281
  console.log('[openagent] ✅ Agent Book UI injected (v3 hook-driven)');
262
282
 
283
+ // ── 提示栏(Figma 141:3293):页面加载即显示 ──
284
+ _injectHintBar(inputContainer || textarea.parentElement);
285
+
263
286
  return true;
264
287
  }
265
288
 
289
+ /** 注入提示栏到输入区域上方 */
290
+ function _injectHintBar(anchorEl) {
291
+ if (!anchorEl || document.querySelector('.openagent-hint-bar')) return;
292
+
293
+ const hintBar = document.createElement('div');
294
+ hintBar.className = 'openagent-hint-bar';
295
+ hintBar.innerHTML = '' +
296
+ '<div class="openagent-hint-bar__content">' +
297
+ '<div class="openagent-hint-bar__icon">' +
298
+ '<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27" viewBox="0 0 27 27" fill="none">' +
299
+ '<rect width="27" height="27" rx="6" fill="url(#paint0_linear_141_3277)" fill-opacity="0.1"/>' +
300
+ '<path d="M13.5 6.75098C16.8137 6.75098 19.5 9.43727 19.5 12.751C19.5 14.3288 18.8894 15.7629 17.8936 16.834L20.7803 19.7207C21.0732 20.0136 21.0732 20.4884 20.7803 20.7812C20.4874 21.0741 20.0126 21.0741 19.7197 20.7812L16.7383 17.7998C15.8038 18.4004 14.6933 18.751 13.5 18.751C10.1863 18.751 7.5 16.0647 7.5 12.751C7.5 9.43727 10.1863 6.75098 13.5 6.75098ZM13.5 8.25098C11.0147 8.25098 9 10.2657 9 12.751C9 15.2363 11.0147 17.251 13.5 17.251C15.9853 17.251 18 15.2363 18 12.751C18 10.2657 15.9853 8.25098 13.5 8.25098Z" fill="url(#paint1_linear_141_3277)"/>' +
301
+ '<defs>' +
302
+ '<linearGradient id="paint0_linear_141_3277" x1="0" y1="13.5" x2="27" y2="13.5" gradientUnits="userSpaceOnUse">' +
303
+ '<stop stop-color="#8274FF"/>' +
304
+ '<stop offset="1" stop-color="#3890FF"/>' +
305
+ '</linearGradient>' +
306
+ '<linearGradient id="paint1_linear_141_3277" x1="7.5" y1="13.8759" x2="20.9999" y2="13.8759" gradientUnits="userSpaceOnUse">' +
307
+ '<stop stop-color="#8274FF"/>' +
308
+ '<stop offset="1" stop-color="#3890FF"/>' +
309
+ '</linearGradient>' +
310
+ '</defs>' +
311
+ '</svg>' +
312
+ '</div>' +
313
+ '<span class="openagent-hint-bar__text">输入你的需求,调配远端Agent为你解决</span>' +
314
+ '</div>' +
315
+ '<button class="openagent-hint-bar__close">' +
316
+ '<svg xmlns="http://www.w3.org/2000/svg" width="21" height="21" viewBox="0 0 21 21" fill="none">' +
317
+ '<path d="M5.625 5.625L15.375 15.375" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>' +
318
+ '<path d="M15.375 5.625L5.625 15.375" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>' +
319
+ '</svg>' +
320
+ '</button>';
321
+
322
+ hintBar.querySelector('.openagent-hint-bar__close').addEventListener('click', () => {
323
+ hintBar.style.display = 'none';
324
+ });
325
+
326
+ // 插入到 wrapper 外面、上方
327
+ anchorEl.parentElement.insertBefore(hintBar, anchorEl);
328
+ }
329
+
266
330
  // ════════════════════════════════════════════════════════════════
267
331
  // ── window.__clMention — OC 注入钩子的桥接对象 ──
268
332
  // ════════════════════════════════════════════════════════════════