openclaw-openagent 1.0.9 → 1.0.12

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 (64) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/src/app/remote-agent-tool.js +110 -14
  3. package/dist/src/app/types.d.ts +2 -2
  4. package/dist/src/plugin-ui/adapters/adapters/oc-2026-04.js +103 -0
  5. package/dist/src/plugin-ui/adapters/adapters/oc-2026-05.js +125 -0
  6. package/dist/src/plugin-ui/adapters/adapters/oc-2026-06.js +125 -0
  7. package/dist/src/plugin-ui/adapters/adapters/oc-unknown.js +48 -0
  8. package/dist/src/plugin-ui/adapters/oc-2026-04.js +103 -0
  9. package/dist/src/plugin-ui/adapters/oc-2026-05.js +125 -0
  10. package/dist/src/plugin-ui/adapters/oc-2026-06.js +125 -0
  11. package/dist/src/plugin-ui/adapters/oc-unknown.js +48 -0
  12. package/dist/src/plugin-ui/assets/bg.png +0 -0
  13. package/dist/src/plugin-ui/assets/icon.png +0 -0
  14. package/dist/src/plugin-ui/assets/openagent-override.js +2480 -1004
  15. package/dist/src/plugin-ui/index.d.ts +1 -1
  16. package/dist/src/plugin-ui/index.js +2 -2
  17. package/dist/src/plugin-ui/ui-extension-loader/index.d.ts +2 -1
  18. package/dist/src/plugin-ui/ui-extension-loader/index.js +5 -5
  19. package/dist/src/plugin-ui/ui-extension-loader/registry-regex.js +128 -13
  20. package/dist/src/plugin-ui/ui-extension-loader/types.d.ts +4 -1
  21. package/dist/src/state/store.d.ts +21 -0
  22. package/dist/src/state/store.js +54 -0
  23. package/dist/src/transport/oasn/oasn-invocation.d.ts +3 -0
  24. package/dist/src/transport/oasn/oasn-invocation.js +28 -12
  25. package/dist/src/transport/oasn/oasn-types.d.ts +8 -4
  26. package/index.ts +1 -1
  27. package/openclaw.plugin.json +1 -1
  28. package/package.json +5 -4
  29. package/src/app/remote-agent-tool.ts +131 -16
  30. package/src/app/types.ts +2 -2
  31. package/src/plugin-ui/adapters/oc-2026-04.js +103 -0
  32. package/src/plugin-ui/adapters/oc-2026-05.js +125 -0
  33. package/src/plugin-ui/adapters/oc-2026-06.js +125 -0
  34. package/src/plugin-ui/adapters/oc-unknown.js +48 -0
  35. package/src/plugin-ui/assets/bg.png +0 -0
  36. package/src/plugin-ui/assets/icon.png +0 -0
  37. package/src/plugin-ui/assets/openagent-override.js +2480 -1004
  38. package/src/plugin-ui/build.cjs +309 -23
  39. package/src/plugin-ui/index.ts +2 -2
  40. package/src/plugin-ui/modules/agent-book/panel/agent-book.js +187 -14
  41. package/src/plugin-ui/modules/agent-book/panel/agent-card.js +26 -10
  42. package/src/plugin-ui/modules/agent-book/panel/agent-data.js +1 -1
  43. package/src/plugin-ui/modules/agent-book/panel/inject-ui.js +149 -1
  44. package/src/plugin-ui/modules/agent-book/panel/styles.js +352 -210
  45. package/src/plugin-ui/modules/agent-book/remote-agent-tool/components-core.js +4 -2
  46. package/src/plugin-ui/modules/agent-book/remote-agent-tool/thought-chain-card.js +4 -1
  47. package/src/plugin-ui/modules/agent-book/scanner.js +17 -5
  48. package/src/plugin-ui/modules/agent-book/travelcard/travel-styles.js +5 -0
  49. package/src/plugin-ui/modules/loader/bootstrap.js +1 -1
  50. package/src/plugin-ui/modules/loader/shared-state.js +278 -0
  51. package/src/plugin-ui/modules/remote-agent/execution-card.js +385 -124
  52. package/src/plugin-ui/modules/remote-agent/native-style-adapter.js +5 -23
  53. package/src/plugin-ui/modules/remote-agent/output-card.js +97 -31
  54. package/src/plugin-ui/modules/remote-agent/render-hooks.js +149 -58
  55. package/src/plugin-ui/modules/remote-agent/styles.js +690 -523
  56. package/src/plugin-ui/modules/remote-agent/tool-card-model.js +77 -3
  57. package/src/plugin-ui/postinstall-deploy.cjs +52 -0
  58. package/src/plugin-ui/ui-extension-loader/index.ts +6 -6
  59. package/src/plugin-ui/ui-extension-loader/registry-regex.ts +131 -14
  60. package/src/plugin-ui/ui-extension-loader/types.ts +5 -1
  61. package/src/state/store.ts +80 -0
  62. package/src/transport/oasn/oasn-invocation.ts +47 -12
  63. package/src/transport/oasn/oasn-types.ts +6 -2
  64. package/src/types/openclaw-plugin-sdk-media-store.d.ts +9 -0
@@ -13,6 +13,34 @@
13
13
 
14
14
  const fs = require('fs');
15
15
  const path = require('path');
16
+ const crypto = require('crypto');
17
+ const childProcess = require('child_process');
18
+
19
+ // ── 读取 OpenClaw 版本(用于注入到产物中)──
20
+ function resolveBuildHostVersion() {
21
+ // 优先使用环境变量
22
+ if (process.env.OPENCLAW_HOST_VERSION) return normalizeHostVersion(process.env.OPENCLAW_HOST_VERSION);
23
+
24
+ var packageCandidates = [
25
+ path.join(__dirname, '..', '..', 'node_modules', 'openclaw', 'package.json'),
26
+ path.join(__dirname, '..', '..', 'package.json'),
27
+ ];
28
+ for (var i = 0; i < packageCandidates.length; i++) {
29
+ try {
30
+ if (!fs.existsSync(packageCandidates[i])) continue;
31
+ var candidatePkg = JSON.parse(fs.readFileSync(packageCandidates[i], 'utf-8'));
32
+ if (candidatePkg && candidatePkg.name === 'openclaw') {
33
+ var exactVersion = normalizeHostVersion(candidatePkg.version);
34
+ if (exactVersion) return exactVersion;
35
+ }
36
+ var depVersion = candidatePkg && candidatePkg.devDependencies && candidatePkg.devDependencies.openclaw;
37
+ depVersion = normalizeHostVersion(String(depVersion || '').replace(/^[\^~>=<]+/, '').trim());
38
+ if (depVersion) return depVersion;
39
+ } catch (e) {}
40
+ }
41
+
42
+ return '';
43
+ }
16
44
 
17
45
  // ═══════════════════════════════════════════════════════════════
18
46
  // MANIFEST — 显式构建顺序,不要用 readdir+sort
@@ -58,7 +86,201 @@ const MANIFEST = [
58
86
  // ═══════════════════════════════════════════════════════════════
59
87
 
60
88
  const modulesDir = path.join(__dirname, 'modules');
61
- const outFile = path.join(__dirname, 'assets', 'openagent-override.js');
89
+ const adaptersDir = path.join(__dirname, 'adapters');
90
+ const assetsDir = path.join(__dirname, 'assets');
91
+ const outFile = path.join(assetsDir, 'openagent-override.js');
92
+ const iconFile = path.join(assetsDir, 'icon.png');
93
+ const bgFile = path.join(assetsDir, 'bg.png');
94
+ const HOST_VERSION_TOKEN = "hostVersion: '__OPENCLAW_HOST_VERSION__'";
95
+ const BUILD_ID_TOKEN = "buildId: '__OPENAGENT_BUILD_ID__'";
96
+ const BUILD_ID_ASSIGNMENT_RE = /buildId:\s*(?:"[^"]*"|'[^']*')/;
97
+ const HOST_ADAPTER_START = '/*__OPENAGENT_HOST_ADAPTER_START__*/';
98
+ const HOST_ADAPTER_END = '/*__OPENAGENT_HOST_ADAPTER_END__*/';
99
+ const HOST_ADAPTER_BLOCK_RE = /\/\*__OPENAGENT_HOST_ADAPTER_START__\*\/[\s\S]*?\/\*__OPENAGENT_HOST_ADAPTER_END__\*\//;
100
+
101
+ function normalizeHostVersion(version) {
102
+ var match = String(version || '').match(/20\d{2}\.\d{1,2}\.\d{1,2}(?:-[A-Za-z0-9._-]+)?/);
103
+ return match ? match[0] : '';
104
+ }
105
+
106
+ function injectHostVersion(content, hostVersion) {
107
+ hostVersion = normalizeHostVersion(hostVersion);
108
+ if (!hostVersion) return content;
109
+ return content.replace(HOST_VERSION_TOKEN, 'hostVersion: ' + JSON.stringify(hostVersion));
110
+ }
111
+
112
+ function resolveHostAdapterId(hostVersion) {
113
+ var parsed = normalizeHostVersion(hostVersion).split('.');
114
+ var year = parseInt(parsed[0], 10);
115
+ var month = parseInt(parsed[1], 10);
116
+ if (year === 2026 && month === 4) return 'oc-2026-04';
117
+ if (year === 2026 && month === 5) return 'oc-2026-05';
118
+ if (year === 2026 && month === 6) return 'oc-2026-06';
119
+ return 'oc-unknown';
120
+ }
121
+
122
+ function getHostAdapterBlock(hostVersion) {
123
+ var adapterId = resolveHostAdapterId(hostVersion);
124
+ var adapterPath = path.join(adaptersDir, adapterId + '.js');
125
+ if (!fs.existsSync(adapterPath)) {
126
+ adapterId = 'oc-unknown';
127
+ adapterPath = path.join(adaptersDir, adapterId + '.js');
128
+ }
129
+ var adapterContent = fs.readFileSync(adapterPath, 'utf-8').trimEnd();
130
+ return [
131
+ HOST_ADAPTER_START,
132
+ '// HOST ADAPTER: ' + adapterId,
133
+ adapterContent,
134
+ HOST_ADAPTER_END,
135
+ ].join('\n');
136
+ }
137
+
138
+ function injectHostAdapter(content, hostVersion) {
139
+ var block = getHostAdapterBlock(hostVersion);
140
+ if (HOST_ADAPTER_BLOCK_RE.test(content)) {
141
+ return content.replace(HOST_ADAPTER_BLOCK_RE, block);
142
+ }
143
+ return content;
144
+ }
145
+
146
+ function renderOverrideContent(content, hostVersion) {
147
+ return injectBuildId(injectHostAdapter(injectHostVersion(content, hostVersion), hostVersion));
148
+ }
149
+
150
+ function hashContent(content) {
151
+ return crypto.createHash('sha256').update(content).digest('hex').slice(0, 12);
152
+ }
153
+
154
+ function injectBuildId(content) {
155
+ var normalized = content.replace(BUILD_ID_ASSIGNMENT_RE, BUILD_ID_TOKEN);
156
+ var buildId = hashContent(normalized);
157
+ return normalized.replace(BUILD_ID_TOKEN, 'buildId: ' + JSON.stringify(buildId));
158
+ }
159
+
160
+ function resolveControlUiHostVersion(controlUiDir) {
161
+ if (process.env.OPENCLAW_HOST_VERSION) return normalizeHostVersion(process.env.OPENCLAW_HOST_VERSION);
162
+
163
+ var candidates = [
164
+ path.join(controlUiDir, '..', '..', 'package.json'),
165
+ path.join(controlUiDir, '..', 'package.json'),
166
+ ];
167
+ for (var i = 0; i < candidates.length; i++) {
168
+ try {
169
+ if (!fs.existsSync(candidates[i])) continue;
170
+ var pkg = JSON.parse(fs.readFileSync(candidates[i], 'utf-8'));
171
+ if (pkg && pkg.name === 'openclaw') return normalizeHostVersion(pkg.version);
172
+ } catch (e) {}
173
+ }
174
+ return '';
175
+ }
176
+
177
+ function pushUniquePath(list, candidate) {
178
+ if (!list || !candidate) return;
179
+ var resolved = path.resolve(candidate);
180
+ for (var i = 0; i < list.length; i++) {
181
+ if (path.resolve(list[i]) === resolved) return;
182
+ }
183
+ list.push(resolved);
184
+ }
185
+
186
+ function collectCommandOutputLines(command, args) {
187
+ try {
188
+ var result = childProcess.spawnSync(command, args, {
189
+ encoding: 'utf-8',
190
+ stdio: ['ignore', 'pipe', 'ignore'],
191
+ });
192
+ return String(result.stdout || '')
193
+ .split(/\r?\n/)
194
+ .map(function(line) { return line.trim(); })
195
+ .filter(Boolean);
196
+ } catch (e) {
197
+ return [];
198
+ }
199
+ }
200
+
201
+ function collectGlobalNodeModuleRoots() {
202
+ var roots = [];
203
+
204
+ try {
205
+ pushUniquePath(roots, path.join(path.dirname(process.execPath), '..', 'lib', 'node_modules'));
206
+ } catch (e) {}
207
+
208
+ var npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
209
+ var npmRoots = collectCommandOutputLines(npmCommand, ['root', '-g']);
210
+ for (var n = 0; n < npmRoots.length; n++) {
211
+ pushUniquePath(roots, npmRoots[n]);
212
+ }
213
+
214
+ var openclawLocator = process.platform === 'win32' ? 'where' : 'which';
215
+ var openclawBins = collectCommandOutputLines(openclawLocator, ['openclaw']);
216
+ for (var b = 0; b < openclawBins.length; b++) {
217
+ var binPath = openclawBins[b];
218
+ try {
219
+ pushUniquePath(roots, path.join(path.dirname(binPath), '..', 'lib', 'node_modules'));
220
+ } catch (e) {}
221
+ try {
222
+ var realBin = fs.realpathSync(binPath);
223
+ var needle = path.join('node_modules', 'openclaw');
224
+ var idx = realBin.lastIndexOf(needle);
225
+ if (idx >= 0) {
226
+ pushUniquePath(roots, realBin.substring(0, idx + 'node_modules'.length));
227
+ }
228
+ } catch (e) {}
229
+ }
230
+
231
+ return roots;
232
+ }
233
+
234
+ function addGlobalOpenclawTargets(deployTargets, assetTargets) {
235
+ var roots = collectGlobalNodeModuleRoots();
236
+ for (var i = 0; i < roots.length; i++) {
237
+ var root = roots[i];
238
+ pushUniquePath(deployTargets, path.join(root, 'openclaw', 'dist', 'control-ui', 'openagent-override.js'));
239
+ pushUniquePath(deployTargets, path.join(root, 'openclaw-openagent', 'src', 'plugin-ui', 'assets', 'openagent-override.js'));
240
+ pushUniquePath(deployTargets, path.join(root, 'openclaw-openagent', 'dist', 'src', 'plugin-ui', 'assets', 'openagent-override.js'));
241
+
242
+ pushUniquePath(assetTargets, path.join(root, 'openclaw', 'dist', 'control-ui'));
243
+ pushUniquePath(assetTargets, path.join(root, 'openclaw-openagent', 'src', 'plugin-ui', 'assets'));
244
+ pushUniquePath(assetTargets, path.join(root, 'openclaw-openagent', 'dist', 'src', 'plugin-ui', 'assets'));
245
+ }
246
+ }
247
+
248
+ function updateControlUiIndex(controlUiDir, contentHash, hostVersion) {
249
+ var indexPath = path.join(controlUiDir, 'index.html');
250
+ if (!fs.existsSync(indexPath)) return false;
251
+
252
+ var html = fs.readFileSync(indexPath, 'utf-8');
253
+ var htmlMarker = '<!--openagent:html-script-tag-->';
254
+ var hostVersionAttr = hostVersion ? ' data-openagent-host-version="' + hostVersion + '"' : '';
255
+ var scriptTag = htmlMarker + '<script src="./openagent-override.js?v=' + contentHash + '"' + hostVersionAttr + '></script>';
256
+ var markedScriptPattern = /(?:\/\*openagent:html-script-tag\*\/|<!--openagent:html-script-tag-->)<script[^>]*openagent-override[^>]*><\/script>\n?\s*/g;
257
+ var oldScriptPattern = /<script[^>]*openagent-override[^>]*><\/script>\n?\s*/g;
258
+ var nextHtml;
259
+
260
+ if (/(?:\/\*openagent:html-script-tag\*\/|<!--openagent:html-script-tag-->)/.test(html)) {
261
+ nextHtml = html.replace(markedScriptPattern, scriptTag + '\n ');
262
+ if (nextHtml === html && !nextHtml.includes('openagent-override.js')) {
263
+ nextHtml = nextHtml.replace(/(?:\/\*openagent:html-script-tag\*\/|<!--openagent:html-script-tag-->)/, scriptTag + '\n ');
264
+ } else if (nextHtml === html && nextHtml.includes('openagent-override.js')) {
265
+ nextHtml = nextHtml.replace(oldScriptPattern, '').replace(/(?:\/\*openagent:html-script-tag\*\/|<!--openagent:html-script-tag-->)/, scriptTag + '\n ');
266
+ }
267
+ } else {
268
+ nextHtml = html.replace(oldScriptPattern, '');
269
+ var viteAnchor = '<script type="module" crossorigin src="./assets/index-';
270
+ var anchorIdx = nextHtml.indexOf(viteAnchor);
271
+ if (anchorIdx >= 0) {
272
+ nextHtml = nextHtml.substring(0, anchorIdx) + scriptTag + '\n ' + nextHtml.substring(anchorIdx);
273
+ } else {
274
+ nextHtml = nextHtml.replace('</head>', scriptTag + '\n</head>');
275
+ }
276
+ }
277
+
278
+ if (nextHtml && nextHtml !== html) {
279
+ fs.writeFileSync(indexPath, nextHtml, 'utf-8');
280
+ return true;
281
+ }
282
+ return false;
283
+ }
62
284
 
63
285
  const HEADER = `/**
64
286
  * OpenAgent UI Override — Auto-generated, do not edit directly!
@@ -99,6 +321,12 @@ function build() {
99
321
  body += `// MODULE: ${file}\n`;
100
322
  body += `// ════════════════════════════════════════════════════════════════\n\n`;
101
323
  body += content.trimEnd() + '\n';
324
+ if (file === 'loader/shared-state.js') {
325
+ body += `\n// ════════════════════════════════════════════════════════════════\n`;
326
+ body += `// MODULE: host-adapter/selected\n`;
327
+ body += `// ════════════════════════════════════════════════════════════════\n\n`;
328
+ body += getHostAdapterBlock('') + '\n';
329
+ }
102
330
  }
103
331
 
104
332
  if (errors > 0) {
@@ -107,12 +335,15 @@ function build() {
107
335
  return;
108
336
  }
109
337
 
110
- const output = HEADER + body + FOOTER;
338
+ // ── 不做构建时版本注入,由运行时 DOM/CSS 特征检测 ──
339
+ // (build.cjs 无法知道实际运行的 OpenClaw 版本)
340
+ var output = HEADER + body + FOOTER;
341
+ var assetOutput = renderOverrideContent(output, '');
111
342
 
112
343
  fs.mkdirSync(path.dirname(outFile), { recursive: true });
113
- fs.writeFileSync(outFile, output, 'utf-8');
344
+ fs.writeFileSync(outFile, assetOutput, 'utf-8');
114
345
 
115
- const lineCount = output.split('\n').length;
346
+ const lineCount = assetOutput.split('\n').length;
116
347
  console.log(`✅ Built: ${path.relative(process.cwd(), outFile)} (${lineCount} lines)`);
117
348
 
118
349
  // ── Auto-deploy to runtime targets ──────────────────────────────────────
@@ -123,25 +354,38 @@ function build() {
123
354
 
124
355
  const DEPLOY_TARGETS = [
125
356
  // 插件安装目录(Gateway 启动时从这里读取并复制到 control-ui)
126
- // 注意:安装目录仍使用旧路径 src/inject/,下次 npm publish 后才会变
127
357
  path.join(homedir, '.openclaw-docker/extensions/openclaw-openagent/src/inject/assets/openagent-override.js'),
128
358
  path.join(homedir, '.openclaw-docker/extensions/openclaw-openagent/src/plugin-ui/assets/openagent-override.js'),
129
359
  path.join(homedir, '.openclaw/extensions/openclaw-openagent/src/inject/assets/openagent-override.js'),
130
360
  path.join(homedir, '.openclaw/extensions/openclaw-openagent/src/plugin-ui/assets/openagent-override.js'),
361
+ // 本地开发 dist/ 目录
362
+ path.join(__dirname, '..', '..', 'dist', 'src', 'plugin-ui', 'assets', 'openagent-override.js'),
363
+ // 本地 node_modules 中的 openclaw control-ui(Gateway 实际运行路径)
364
+ path.join(__dirname, '..', '..', 'node_modules', 'openclaw', 'dist', 'control-ui', 'openagent-override.js'),
365
+ // npm 全局安装 + 项目缓存(Gateway 可能从这些路径加载)
366
+ path.join(homedir, '.openclaw/npm/projects/openclaw-openagent/node_modules/openclaw-openagent/src/plugin-ui/assets/openagent-override.js'),
367
+ path.join(homedir, '.openclaw/npm/projects/openclaw-openagent/node_modules/openclaw-openagent/dist/src/plugin-ui/assets/openagent-override.js'),
368
+ path.join(homedir, '.nvm/versions/node/v22.21.1/lib/node_modules/openclaw-openagent/src/plugin-ui/assets/openagent-override.js'),
369
+ path.join(homedir, '.nvm/versions/node/v22.21.1/lib/node_modules/openclaw-openagent/dist/src/plugin-ui/assets/openagent-override.js'),
131
370
  ];
132
-
133
- // 动态发现 control-ui 目录(通过 node 可执行文件路径推断)
134
- try {
135
- const nodeDir = path.dirname(process.execPath);
136
- const controlUiCandidate = path.join(nodeDir, '..', 'lib', 'node_modules', 'openclaw', 'dist', 'control-ui', 'openagent-override.js');
137
- DEPLOY_TARGETS.push(path.resolve(controlUiCandidate));
138
- } catch {}
371
+ addGlobalOpenclawTargets(DEPLOY_TARGETS, null);
139
372
 
140
373
  let deployed = 0;
141
374
  for (const target of DEPLOY_TARGETS) {
142
375
  try {
143
376
  if (fs.existsSync(path.dirname(target))) {
144
- fs.copyFileSync(outFile, target);
377
+ const targetDir = path.dirname(target);
378
+ const hostVersion = path.basename(targetDir) === 'control-ui'
379
+ ? resolveControlUiHostVersion(targetDir)
380
+ : '';
381
+ const targetOutput = renderOverrideContent(output, hostVersion);
382
+ fs.writeFileSync(target, targetOutput, 'utf-8');
383
+ if (hostVersion) {
384
+ const contentHash = hashContent(targetOutput);
385
+ if (updateControlUiIndex(targetDir, contentHash, hostVersion)) {
386
+ console.log(` ↻ updated index.html cache-bust (${hostVersion}, ${resolveHostAdapterId(hostVersion)}, ${contentHash})`);
387
+ }
388
+ }
145
389
  console.log(` → ${path.relative(homedir, target)}`);
146
390
  deployed++;
147
391
  }
@@ -149,10 +393,48 @@ function build() {
149
393
  }
150
394
 
151
395
  if (deployed > 0) {
152
- console.log(`✅ Auto-deployed to ${deployed} target(s)`);
396
+ console.log(`✅ Auto-deployed override to ${deployed} target(s)`);
153
397
  } else {
154
398
  console.log('ℹ️ No deploy targets found (standalone build)');
155
399
  }
400
+
401
+ // ── Shared asset deploy targets (control-ui + extension dirs) ──
402
+ const ASSET_DEPLOY_TARGETS = [
403
+ path.join(homedir, '.openclaw-docker/extensions/openclaw-openagent/src/inject/assets'),
404
+ path.join(homedir, '.openclaw-docker/extensions/openclaw-openagent/src/plugin-ui/assets'),
405
+ path.join(homedir, '.openclaw/extensions/openclaw-openagent/src/inject/assets'),
406
+ path.join(homedir, '.openclaw/extensions/openclaw-openagent/src/plugin-ui/assets'),
407
+ path.join(__dirname, '..', '..', 'dist', 'src', 'plugin-ui', 'assets'),
408
+ path.join(__dirname, '..', '..', 'node_modules', 'openclaw', 'dist', 'control-ui'),
409
+ path.join(homedir, '.openclaw/npm/projects/openclaw-openagent/node_modules/openclaw-openagent/src/plugin-ui/assets'),
410
+ path.join(homedir, '.openclaw/npm/projects/openclaw-openagent/node_modules/openclaw-openagent/dist/src/plugin-ui/assets'),
411
+ path.join(homedir, '.nvm/versions/node/v22.21.1/lib/node_modules/openclaw-openagent/src/plugin-ui/assets'),
412
+ path.join(homedir, '.nvm/versions/node/v22.21.1/lib/node_modules/openclaw-openagent/dist/src/plugin-ui/assets'),
413
+ ];
414
+ addGlobalOpenclawTargets(null, ASSET_DEPLOY_TARGETS);
415
+
416
+ // ── Deploy image assets (icon.png, bg.png) ──
417
+ const IMAGE_ASSETS = [
418
+ { file: iconFile, name: 'icon.png' },
419
+ { file: bgFile, name: 'bg.png' },
420
+ ];
421
+
422
+ for (const asset of IMAGE_ASSETS) {
423
+ if (!fs.existsSync(asset.file)) continue;
424
+ let deployed = 0;
425
+ for (const dir of ASSET_DEPLOY_TARGETS) {
426
+ try {
427
+ const dest = path.join(dir, asset.name);
428
+ if (fs.existsSync(dir)) {
429
+ fs.copyFileSync(asset.file, dest);
430
+ deployed++;
431
+ }
432
+ } catch {}
433
+ }
434
+ if (deployed > 0) {
435
+ console.log(`✅ Auto-deployed ${asset.name} to ${deployed} target(s)`);
436
+ }
437
+ }
156
438
  }
157
439
 
158
440
  // ── Execution ──
@@ -162,16 +444,20 @@ const isWatchMode = process.argv.includes('--watch');
162
444
  build();
163
445
 
164
446
  if (isWatchMode) {
165
- console.log(`\n👀 Watching for changes in ${path.relative(process.cwd(), modulesDir)}...`);
447
+ console.log(`\n👀 Watching for changes in ${path.relative(process.cwd(), modulesDir)} and ${path.relative(process.cwd(), adaptersDir)}...`);
166
448
 
167
449
  let debounceTimer;
168
- fs.watch(modulesDir, { recursive: true }, (eventType, filename) => {
169
- // Ignore dot files and non-js files
170
- if (!filename || filename.startsWith('.') || !filename.endsWith('.js')) return;
450
+ function watchSourceDir(sourceDir) {
451
+ fs.watch(sourceDir, { recursive: true }, (eventType, filename) => {
452
+ // Ignore dot files and non-js files
453
+ if (!filename || filename.startsWith('.') || !filename.endsWith('.js')) return;
171
454
 
172
- clearTimeout(debounceTimer);
173
- debounceTimer = setTimeout(() => {
174
- build();
175
- }, 100);
176
- });
455
+ clearTimeout(debounceTimer);
456
+ debounceTimer = setTimeout(() => {
457
+ build();
458
+ }, 100);
459
+ });
460
+ }
461
+ watchSourceDir(modulesDir);
462
+ watchSourceDir(adaptersDir);
177
463
  }
@@ -13,6 +13,6 @@ import { loadUIExtensions } from './ui-extension-loader/index.js';
13
13
  * 由 index.ts register() 调用。内部通过 Manifest Reconciler
14
14
  * 自动完成扩展点的 apply / revert / skip。
15
15
  */
16
- export async function injectControlUiOverride(): Promise<void> {
17
- await loadUIExtensions();
16
+ export async function injectControlUiOverride(hostVersion?: string): Promise<void> {
17
+ await loadUIExtensions({ hostVersion });
18
18
  }