robot-resources 1.9.7 → 1.10.3
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/README.md +0 -1
- package/lib/detect.js +0 -53
- package/lib/health-report.js +3 -3
- package/lib/tool-config.js +14 -13
- package/lib/wizard.js +90 -303
- package/package.json +2 -5
- package/lib/python-bridge.js +0 -38
- package/lib/service.js +0 -740
package/README.md
CHANGED
package/lib/detect.js
CHANGED
|
@@ -1,46 +1,8 @@
|
|
|
1
|
-
import { execSync, execFileSync } from 'node:child_process';
|
|
2
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
2
|
import { homedir } from 'node:os';
|
|
4
3
|
import { join } from 'node:path';
|
|
5
4
|
import { stripJson5 } from './json5.js';
|
|
6
5
|
|
|
7
|
-
// Re-export findPython from the shared cli-core implementation.
|
|
8
|
-
export { findPython } from '@robot-resources/cli-core/python-bridge.mjs';
|
|
9
|
-
|
|
10
|
-
import { getVenvPython, MANAGED_VENV_DIR } from '@robot-resources/cli-core/python-bridge.mjs';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Check if the router venv exists and has the package installed.
|
|
14
|
-
* Returns { venvDir, venvPython } or null.
|
|
15
|
-
*/
|
|
16
|
-
export function checkRouterVenv() {
|
|
17
|
-
const venvPython = getVenvPython();
|
|
18
|
-
|
|
19
|
-
if (!existsSync(venvPython)) return null;
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
execSync(`"${venvPython}" -c "import robot_resources" 2>&1`, { encoding: 'utf-8' });
|
|
23
|
-
return { venvDir: MANAGED_VENV_DIR, venvPython };
|
|
24
|
-
} catch {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Check if port 3838 is available.
|
|
31
|
-
*/
|
|
32
|
-
export function isPortAvailable(port = 3838) {
|
|
33
|
-
if (typeof port !== 'number' || !Number.isInteger(port) || port < 1 || port > 65535) {
|
|
34
|
-
throw new Error('Invalid port number');
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
execFileSync('lsof', ['-i', `:${port}`, '-t'], { encoding: 'utf-8', stdio: 'pipe' });
|
|
38
|
-
return false; // port is in use
|
|
39
|
-
} catch {
|
|
40
|
-
return true; // port is available (lsof returned non-zero = no process)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
6
|
/**
|
|
45
7
|
* Check if OpenClaw is installed.
|
|
46
8
|
*/
|
|
@@ -154,18 +116,3 @@ export function isClaudeCodeInstalled() {
|
|
|
154
116
|
export function isCursorInstalled() {
|
|
155
117
|
return existsSync(join(homedir(), '.cursor'));
|
|
156
118
|
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Check if the router service is already registered.
|
|
160
|
-
*/
|
|
161
|
-
export function isServiceRegistered() {
|
|
162
|
-
if (process.platform === 'darwin') {
|
|
163
|
-
const plistPath = join(homedir(), 'Library', 'LaunchAgents', 'ai.robotresources.router.plist');
|
|
164
|
-
return existsSync(plistPath);
|
|
165
|
-
}
|
|
166
|
-
if (process.platform === 'linux') {
|
|
167
|
-
const unitPath = join(homedir(), '.config', 'systemd', 'user', 'robot-resources-router.service');
|
|
168
|
-
return existsSync(unitPath);
|
|
169
|
-
}
|
|
170
|
-
return false;
|
|
171
|
-
}
|
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,10 +113,10 @@ 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 hasPlugin = !!ocConfig?.plugins?.entries?.['
|
|
116
|
+
const hasPlugin = !!ocConfig?.plugins?.entries?.['robot-resources-router']?.enabled;
|
|
117
117
|
return {
|
|
118
118
|
healthy: hasPlugin,
|
|
119
|
-
detail: hasPlugin ? 'plugin registered' : '
|
|
119
|
+
detail: hasPlugin ? 'plugin registered' : 'robot-resources-router not registered',
|
|
120
120
|
};
|
|
121
121
|
} catch {
|
|
122
122
|
return { healthy: false, detail: 'openclaw.json not found' };
|
package/lib/tool-config.js
CHANGED
|
@@ -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,22 +94,23 @@ 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
|
-
* The plugin ships as a CLI dependency (@robot-resources/
|
|
99
|
+
* The plugin ships as a CLI dependency (@robot-resources/router — the
|
|
100
|
+
* router IS the OC plugin in the in-process architecture).
|
|
100
101
|
* Instead of spawning `openclaw plugins install` (30s npm overhead),
|
|
101
102
|
* we copy files directly. Same destination, same result.
|
|
102
103
|
*
|
|
103
|
-
*
|
|
104
|
+
* The plugin is a thin shim (index.js) that imports the rest
|
|
104
105
|
* of its code from ./lib/*.js — copy the lib/ directory too, or the shim
|
|
105
106
|
* fails to load with MODULE_NOT_FOUND.
|
|
106
107
|
*/
|
|
107
108
|
function installPluginFiles() {
|
|
108
109
|
const require = createRequire(import.meta.url);
|
|
109
|
-
const pluginPkgPath = require.resolve('@robot-resources/
|
|
110
|
+
const pluginPkgPath = require.resolve('@robot-resources/router/package.json');
|
|
110
111
|
const pluginDir = dirname(pluginPkgPath);
|
|
111
112
|
|
|
112
|
-
const targetDir = join(homedir(), '.openclaw', 'extensions', '
|
|
113
|
+
const targetDir = join(homedir(), '.openclaw', 'extensions', 'robot-resources-router');
|
|
113
114
|
mkdirSync(targetDir, { recursive: true });
|
|
114
115
|
|
|
115
116
|
for (const file of ['index.js', 'openclaw.plugin.json', 'package.json']) {
|
|
@@ -128,7 +129,7 @@ function installPluginFiles() {
|
|
|
128
129
|
|
|
129
130
|
/**
|
|
130
131
|
* Register the plugin in openclaw.json so OC loads it on gateway start.
|
|
131
|
-
* Adds plugins.entries.
|
|
132
|
+
* Adds plugins.entries.robot-resources-router = { enabled: true }.
|
|
132
133
|
*/
|
|
133
134
|
function registerPluginEntry() {
|
|
134
135
|
const configPath = join(homedir(), '.openclaw', 'openclaw.json');
|
|
@@ -140,9 +141,9 @@ function registerPluginEntry() {
|
|
|
140
141
|
if (!config.plugins.entries) config.plugins.entries = {};
|
|
141
142
|
|
|
142
143
|
// Already registered
|
|
143
|
-
if (config.plugins.entries['
|
|
144
|
+
if (config.plugins.entries['robot-resources-router']) return;
|
|
144
145
|
|
|
145
|
-
config.plugins.entries['
|
|
146
|
+
config.plugins.entries['robot-resources-router'] = { enabled: true };
|
|
146
147
|
|
|
147
148
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
148
149
|
} catch {
|
|
@@ -153,7 +154,7 @@ function registerPluginEntry() {
|
|
|
153
154
|
/**
|
|
154
155
|
* Configure OpenClaw to route through Robot Resources Router.
|
|
155
156
|
*
|
|
156
|
-
* Copies the bundled @robot-resources/
|
|
157
|
+
* Copies the bundled @robot-resources/router files into
|
|
157
158
|
* ~/.openclaw/extensions/. The plugin uses before_model_resolve to
|
|
158
159
|
* override the provider — survives gateway restarts because it
|
|
159
160
|
* lives in ~/.openclaw/extensions/, not in openclaw.json.
|
|
@@ -196,7 +197,7 @@ function configureOpenClaw() {
|
|
|
196
197
|
// Plugin file copy failed — fall back to instructions
|
|
197
198
|
const instructions = [
|
|
198
199
|
'Could not auto-install plugin. Install manually:',
|
|
199
|
-
' openclaw plugins install @robot-resources/
|
|
200
|
+
' openclaw plugins install @robot-resources/router',
|
|
200
201
|
];
|
|
201
202
|
|
|
202
203
|
if (authMode === 'subscription') {
|