robot-resources 1.10.2 → 1.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/detect.js +9 -0
- package/lib/health-report.js +12 -6
- package/lib/tool-config.js +107 -15
- package/lib/wizard.js +10 -4
- package/package.json +3 -2
package/lib/detect.js
CHANGED
|
@@ -21,6 +21,15 @@ export function isOpenClawPluginInstalled() {
|
|
|
21
21
|
|| existsSync(join(extDir, 'robot-resources-router'));
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Check if the Robot Resources scraper OC plugin is already installed.
|
|
26
|
+
*/
|
|
27
|
+
export function isScraperOcPluginInstalled() {
|
|
28
|
+
const home = homedir();
|
|
29
|
+
const extDir = join(home, '.openclaw', 'extensions');
|
|
30
|
+
return existsSync(join(extDir, 'robot-resources-scraper-oc-plugin'));
|
|
31
|
+
}
|
|
32
|
+
|
|
24
33
|
/**
|
|
25
34
|
* Detect OpenClaw auth mode: 'subscription' (OAuth token) or 'apikey'.
|
|
26
35
|
*
|
package/lib/health-report.js
CHANGED
|
@@ -12,7 +12,7 @@ const PROBE_TIMEOUT_MS = 5_000;
|
|
|
12
12
|
* 1. Router — GET http://127.0.0.1:3838/health
|
|
13
13
|
* 2. Scraper — check openclaw.json for scraper MCP registration
|
|
14
14
|
* 3. Platform — GET {platformUrl}/v1/health with api_key
|
|
15
|
-
* 4. MCP — check openclaw.json for
|
|
15
|
+
* 4. MCP — check openclaw.json for robot-resources-router registration
|
|
16
16
|
*
|
|
17
17
|
* @returns {{ status: 'healthy'|'partial'|'failed', components: Object, summary: string }}
|
|
18
18
|
*/
|
|
@@ -113,11 +113,17 @@ function probeMcp() {
|
|
|
113
113
|
try {
|
|
114
114
|
const ocPath = join(homedir(), '.openclaw', 'openclaw.json');
|
|
115
115
|
const ocConfig = JSON.parse(readFileSync(ocPath, 'utf-8'));
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
116
|
+
const hasRouter = !!ocConfig?.plugins?.entries?.['robot-resources-router']?.enabled;
|
|
117
|
+
const hasScraper = !!ocConfig?.plugins?.entries?.['robot-resources-scraper-oc-plugin']?.enabled;
|
|
118
|
+
|
|
119
|
+
if (hasRouter && hasScraper) {
|
|
120
|
+
return { healthy: true, detail: 'plugins registered' };
|
|
121
|
+
}
|
|
122
|
+
if (!hasRouter && !hasScraper) {
|
|
123
|
+
return { healthy: false, detail: 'router + scraper plugins not registered' };
|
|
124
|
+
}
|
|
125
|
+
const missing = !hasRouter ? 'robot-resources-router' : 'robot-resources-scraper-oc-plugin';
|
|
126
|
+
return { healthy: false, detail: `${missing} not registered` };
|
|
121
127
|
} catch {
|
|
122
128
|
return { healthy: false, detail: 'openclaw.json not found' };
|
|
123
129
|
}
|
package/lib/tool-config.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from 'node:module';
|
|
|
3
3
|
import { readFileSync, writeFileSync, copyFileSync, cpSync, mkdirSync, existsSync, rmSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { join, dirname } from 'node:path';
|
|
6
|
-
import { isOpenClawInstalled, isOpenClawPluginInstalled, getOpenClawAuthMode, isClaudeCodeInstalled, isCursorInstalled } from './detect.js';
|
|
6
|
+
import { isOpenClawInstalled, isOpenClawPluginInstalled, isScraperOcPluginInstalled, getOpenClawAuthMode, isClaudeCodeInstalled, isCursorInstalled } from './detect.js';
|
|
7
7
|
import { stripJson5 } from './json5.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -28,7 +28,7 @@ function readOrCreateOpenClawConfig() {
|
|
|
28
28
|
/**
|
|
29
29
|
* Trust the Robot Resources plugin in OpenClaw config.
|
|
30
30
|
*
|
|
31
|
-
* Adds "
|
|
31
|
+
* Adds "robot-resources-router" to plugins.allow so OpenClaw loads it without
|
|
32
32
|
* provenance warnings. The plugin's before_model_resolve hook intercepts
|
|
33
33
|
* ALL LLM calls regardless of the default model — no need to change the
|
|
34
34
|
* default model (which causes LiveSessionModelSwitchError in OC).
|
|
@@ -44,11 +44,11 @@ function trustPlugin() {
|
|
|
44
44
|
if (!config.plugins) config.plugins = {};
|
|
45
45
|
if (!Array.isArray(config.plugins.allow)) config.plugins.allow = [];
|
|
46
46
|
|
|
47
|
-
if (config.plugins.allow.includes('
|
|
47
|
+
if (config.plugins.allow.includes('robot-resources-router')) {
|
|
48
48
|
return false;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
config.plugins.allow.push('
|
|
51
|
+
config.plugins.allow.push('robot-resources-router');
|
|
52
52
|
|
|
53
53
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
54
54
|
return true;
|
|
@@ -94,7 +94,7 @@ function registerScraperMcp() {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
/**
|
|
97
|
-
* Copy the bundled plugin files to ~/.openclaw/extensions/
|
|
97
|
+
* Copy the bundled plugin files to ~/.openclaw/extensions/robot-resources-router/.
|
|
98
98
|
*
|
|
99
99
|
* The plugin ships as a CLI dependency (@robot-resources/router — the
|
|
100
100
|
* router IS the OC plugin in the in-process architecture).
|
|
@@ -110,7 +110,7 @@ function installPluginFiles() {
|
|
|
110
110
|
const pluginPkgPath = require.resolve('@robot-resources/router/package.json');
|
|
111
111
|
const pluginDir = dirname(pluginPkgPath);
|
|
112
112
|
|
|
113
|
-
const targetDir = join(homedir(), '.openclaw', 'extensions', '
|
|
113
|
+
const targetDir = join(homedir(), '.openclaw', 'extensions', 'robot-resources-router');
|
|
114
114
|
mkdirSync(targetDir, { recursive: true });
|
|
115
115
|
|
|
116
116
|
for (const file of ['index.js', 'openclaw.plugin.json', 'package.json']) {
|
|
@@ -129,7 +129,7 @@ function installPluginFiles() {
|
|
|
129
129
|
|
|
130
130
|
/**
|
|
131
131
|
* Register the plugin in openclaw.json so OC loads it on gateway start.
|
|
132
|
-
* Adds plugins.entries.
|
|
132
|
+
* Adds plugins.entries.robot-resources-router = { enabled: true }.
|
|
133
133
|
*/
|
|
134
134
|
function registerPluginEntry() {
|
|
135
135
|
const configPath = join(homedir(), '.openclaw', 'openclaw.json');
|
|
@@ -141,9 +141,91 @@ function registerPluginEntry() {
|
|
|
141
141
|
if (!config.plugins.entries) config.plugins.entries = {};
|
|
142
142
|
|
|
143
143
|
// Already registered
|
|
144
|
-
if (config.plugins.entries['
|
|
144
|
+
if (config.plugins.entries['robot-resources-router']) return;
|
|
145
145
|
|
|
146
|
-
config.plugins.entries['
|
|
146
|
+
config.plugins.entries['robot-resources-router'] = { enabled: true };
|
|
147
|
+
|
|
148
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
149
|
+
} catch {
|
|
150
|
+
// Non-fatal — plugin may still auto-load from extensions dir
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Trust the scraper OC plugin in OpenClaw config.
|
|
156
|
+
*
|
|
157
|
+
* Adds "robot-resources-scraper-oc-plugin" to plugins.allow so OpenClaw
|
|
158
|
+
* loads it without provenance warnings. The plugin's before_tool_call
|
|
159
|
+
* hook redirects web_fetch to scraper_compress_url.
|
|
160
|
+
*
|
|
161
|
+
* Returns true if the config was updated, false otherwise.
|
|
162
|
+
*/
|
|
163
|
+
function trustScraperOcPlugin() {
|
|
164
|
+
const configPath = join(homedir(), '.openclaw', 'openclaw.json');
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
const config = readOrCreateOpenClawConfig();
|
|
168
|
+
|
|
169
|
+
if (!config.plugins) config.plugins = {};
|
|
170
|
+
if (!Array.isArray(config.plugins.allow)) config.plugins.allow = [];
|
|
171
|
+
|
|
172
|
+
if (config.plugins.allow.includes('robot-resources-scraper-oc-plugin')) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
config.plugins.allow.push('robot-resources-scraper-oc-plugin');
|
|
177
|
+
|
|
178
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
179
|
+
return true;
|
|
180
|
+
} catch {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Copy the bundled scraper OC plugin files to
|
|
187
|
+
* ~/.openclaw/extensions/robot-resources-scraper-oc-plugin/.
|
|
188
|
+
*
|
|
189
|
+
* Mirrors installPluginFiles() but for the scraper OC plugin package.
|
|
190
|
+
*/
|
|
191
|
+
function installScraperOcPluginFiles() {
|
|
192
|
+
const require = createRequire(import.meta.url);
|
|
193
|
+
const pluginPkgPath = require.resolve('@robot-resources/scraper-oc-plugin/package.json');
|
|
194
|
+
const pluginDir = dirname(pluginPkgPath);
|
|
195
|
+
|
|
196
|
+
const targetDir = join(homedir(), '.openclaw', 'extensions', 'robot-resources-scraper-oc-plugin');
|
|
197
|
+
mkdirSync(targetDir, { recursive: true });
|
|
198
|
+
|
|
199
|
+
for (const file of ['index.js', 'openclaw.plugin.json', 'package.json']) {
|
|
200
|
+
copyFileSync(join(pluginDir, file), join(targetDir, file));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Copy lib/ recursively. Clear destination first so files removed in
|
|
204
|
+
// a new version don't linger from a previous install.
|
|
205
|
+
const srcLib = join(pluginDir, 'lib');
|
|
206
|
+
const dstLib = join(targetDir, 'lib');
|
|
207
|
+
if (existsSync(srcLib)) {
|
|
208
|
+
rmSync(dstLib, { recursive: true, force: true });
|
|
209
|
+
cpSync(srcLib, dstLib, { recursive: true });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Register the scraper OC plugin in openclaw.json so OC loads it on
|
|
215
|
+
* gateway start. Adds plugins.entries['robot-resources-scraper-oc-plugin'] = { enabled: true }.
|
|
216
|
+
*/
|
|
217
|
+
function registerScraperOcPluginEntry() {
|
|
218
|
+
const configPath = join(homedir(), '.openclaw', 'openclaw.json');
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
const config = readOrCreateOpenClawConfig();
|
|
222
|
+
|
|
223
|
+
if (!config.plugins) config.plugins = {};
|
|
224
|
+
if (!config.plugins.entries) config.plugins.entries = {};
|
|
225
|
+
|
|
226
|
+
if (config.plugins.entries['robot-resources-scraper-oc-plugin']) return;
|
|
227
|
+
|
|
228
|
+
config.plugins.entries['robot-resources-scraper-oc-plugin'] = { enabled: true };
|
|
147
229
|
|
|
148
230
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
149
231
|
} catch {
|
|
@@ -167,7 +249,10 @@ function registerPluginEntry() {
|
|
|
167
249
|
function configureOpenClaw() {
|
|
168
250
|
const authMode = getOpenClawAuthMode();
|
|
169
251
|
|
|
170
|
-
|
|
252
|
+
const routerWasInstalled = isOpenClawPluginInstalled();
|
|
253
|
+
const scraperWasInstalled = isScraperOcPluginInstalled();
|
|
254
|
+
|
|
255
|
+
if (routerWasInstalled && scraperWasInstalled) {
|
|
171
256
|
return {
|
|
172
257
|
name: 'OpenClaw',
|
|
173
258
|
action: 'already_configured',
|
|
@@ -176,13 +261,20 @@ function configureOpenClaw() {
|
|
|
176
261
|
}
|
|
177
262
|
|
|
178
263
|
try {
|
|
179
|
-
|
|
264
|
+
let configActivated = false;
|
|
180
265
|
|
|
181
|
-
|
|
182
|
-
|
|
266
|
+
if (!routerWasInstalled) {
|
|
267
|
+
installPluginFiles();
|
|
268
|
+
registerPluginEntry();
|
|
269
|
+
configActivated = trustPlugin();
|
|
270
|
+
}
|
|
183
271
|
|
|
184
|
-
|
|
185
|
-
|
|
272
|
+
if (!scraperWasInstalled) {
|
|
273
|
+
installScraperOcPluginFiles();
|
|
274
|
+
registerScraperOcPluginEntry();
|
|
275
|
+
// OR-combine so configActivated reflects "any plugin entry was added to allow".
|
|
276
|
+
configActivated = trustScraperOcPlugin() || configActivated;
|
|
277
|
+
}
|
|
186
278
|
|
|
187
279
|
return {
|
|
188
280
|
name: 'OpenClaw',
|
package/lib/wizard.js
CHANGED
|
@@ -31,10 +31,13 @@ const CLI_VERSION = (() => {
|
|
|
31
31
|
* The wizard's job is reduced to:
|
|
32
32
|
*
|
|
33
33
|
* 1. Provision an anonymous api_key (telemetry/dashboard identity).
|
|
34
|
-
* 2. Install
|
|
35
|
-
* routing logic) into
|
|
34
|
+
* 2. Install both OC plugins:
|
|
35
|
+
* a. router plugin (in-process HTTP server + routing logic) into
|
|
36
|
+
* ~/.openclaw/extensions/robot-resources-router/
|
|
37
|
+
* b. scraper OC plugin (web_fetch → scraper_compress_url hook) into
|
|
38
|
+
* ~/.openclaw/extensions/robot-resources-scraper-oc-plugin/
|
|
36
39
|
* 3. Register the scraper MCP in openclaw.json.
|
|
37
|
-
* 4. Restart the OC gateway so the
|
|
40
|
+
* 4. Restart the OC gateway so the plugins load.
|
|
38
41
|
*
|
|
39
42
|
* No Python, no venv, no systemd, no port probe.
|
|
40
43
|
*/
|
|
@@ -323,7 +326,10 @@ export async function runWizard({ nonInteractive = false } = {}) {
|
|
|
323
326
|
blank();
|
|
324
327
|
warn('IMPORTANT: Notify your human about this installation.');
|
|
325
328
|
info('Robot Resources has made the following changes to this machine:');
|
|
326
|
-
if (results.pluginInstalled)
|
|
329
|
+
if (results.pluginInstalled) {
|
|
330
|
+
info(' • Router plugin installed in ~/.openclaw/extensions/robot-resources-router/');
|
|
331
|
+
info(' • Scraper plugin installed in ~/.openclaw/extensions/robot-resources-scraper-oc-plugin/');
|
|
332
|
+
}
|
|
327
333
|
if (results.pluginInstalled) info(' • Plugin runs in-process inside OpenClaw — no separate service');
|
|
328
334
|
if (results.scraper) info(' • Scraper MCP configured — scraper_compress_url(url) available');
|
|
329
335
|
blank();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "robot-resources",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.4",
|
|
4
4
|
"description": "Robot Resources — AI agent tools. One command to install everything.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@robot-resources/cli-core": "*",
|
|
21
21
|
"@robot-resources/router": "*",
|
|
22
|
-
"@robot-resources/scraper": "^0.3.1"
|
|
22
|
+
"@robot-resources/scraper": "^0.3.1",
|
|
23
|
+
"@robot-resources/scraper-oc-plugin": "*"
|
|
23
24
|
},
|
|
24
25
|
"devDependencies": {
|
|
25
26
|
"vitest": "^1.2.0"
|