robot-resources 1.2.6 → 1.2.8
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 +56 -1
- package/lib/tool-config.js +30 -6
- package/lib/wizard.js +21 -2
- package/package.json +1 -1
package/lib/detect.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execSync, execFileSync } from 'node:child_process';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
|
|
@@ -88,6 +88,61 @@ export function isOpenClawPluginInstalled() {
|
|
|
88
88
|
return existsSync(join(home, '.openclaw', 'extensions', 'robot-resources-router'));
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Detect OpenClaw auth mode: 'subscription' (OAuth token) or 'apikey'.
|
|
93
|
+
*
|
|
94
|
+
* Subscription users authenticate via Anthropic OAuth tokens.
|
|
95
|
+
* Anthropic rejects these tokens from third-party clients, so the
|
|
96
|
+
* only viable routing path is the OpenClaw plugin (not HTTP proxy).
|
|
97
|
+
*
|
|
98
|
+
* Detection order:
|
|
99
|
+
* 1. ANTHROPIC_AUTH_TOKEN env var → subscription
|
|
100
|
+
* 2. openclaw.json → auth.type or providers.anthropic.authToken
|
|
101
|
+
* 3. providers.anthropic.apiKey → apikey
|
|
102
|
+
* 4. Default → apikey (conservative — proxy works fine)
|
|
103
|
+
*/
|
|
104
|
+
export function getOpenClawAuthMode() {
|
|
105
|
+
// Env var is the strongest signal
|
|
106
|
+
if (process.env.ANTHROPIC_AUTH_TOKEN) return 'subscription';
|
|
107
|
+
if (process.env.ANTHROPIC_API_KEY) return 'apikey';
|
|
108
|
+
|
|
109
|
+
// Try reading openclaw.json
|
|
110
|
+
const home = homedir();
|
|
111
|
+
const candidates = [
|
|
112
|
+
join(home, '.openclaw', 'openclaw.json'),
|
|
113
|
+
join(home, 'openclaw.json'),
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
for (const configPath of candidates) {
|
|
117
|
+
if (!existsSync(configPath)) continue;
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const raw = readFileSync(configPath, 'utf-8');
|
|
121
|
+
// Strip JSON5 features inline (comments + trailing commas)
|
|
122
|
+
const clean = raw
|
|
123
|
+
.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\/\/.*$|\/\*[\s\S]*?\*\//gm,
|
|
124
|
+
(m) => (m.startsWith('"') || m.startsWith("'") ? m : ''))
|
|
125
|
+
.replace(/,\s*([\]}])/g, '$1');
|
|
126
|
+
const config = JSON.parse(clean);
|
|
127
|
+
|
|
128
|
+
// Check explicit auth type
|
|
129
|
+
if (config.auth?.type === 'oauth' || config.auth?.type === 'subscription') {
|
|
130
|
+
return 'subscription';
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Check for authToken in providers
|
|
134
|
+
const anthropic = config.models?.providers?.anthropic
|
|
135
|
+
|| config.providers?.anthropic;
|
|
136
|
+
if (anthropic?.authToken) return 'subscription';
|
|
137
|
+
if (anthropic?.apiKey) return 'apikey';
|
|
138
|
+
} catch {
|
|
139
|
+
// Config unreadable — fall through
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return 'apikey';
|
|
144
|
+
}
|
|
145
|
+
|
|
91
146
|
/**
|
|
92
147
|
* Check if the router service is already registered.
|
|
93
148
|
*/
|
package/lib/tool-config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
|
-
import { isOpenClawInstalled, isOpenClawPluginInstalled } from './detect.js';
|
|
2
|
+
import { isOpenClawInstalled, isOpenClawPluginInstalled, getOpenClawAuthMode } from './detect.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Strip JSON5 features (comments + trailing commas) to produce valid JSON.
|
|
@@ -25,12 +25,20 @@ function stripJson5(text) {
|
|
|
25
25
|
* native plugin system. The plugin uses before_model_resolve to
|
|
26
26
|
* override the provider — survives gateway restarts because it
|
|
27
27
|
* lives in ~/.openclaw/extensions/, not in openclaw.json.
|
|
28
|
+
*
|
|
29
|
+
* Auth mode detection:
|
|
30
|
+
* - subscription (OAuth token): Plugin is REQUIRED. Anthropic rejects
|
|
31
|
+
* OAuth tokens from third-party clients, so HTTP proxy won't work.
|
|
32
|
+
* - apikey: Plugin is preferred (survives restarts) but proxy also works.
|
|
28
33
|
*/
|
|
29
34
|
function configureOpenClaw() {
|
|
35
|
+
const authMode = getOpenClawAuthMode();
|
|
36
|
+
|
|
30
37
|
if (isOpenClawPluginInstalled()) {
|
|
31
38
|
return {
|
|
32
39
|
name: 'OpenClaw',
|
|
33
40
|
action: 'already_configured',
|
|
41
|
+
authMode,
|
|
34
42
|
};
|
|
35
43
|
}
|
|
36
44
|
|
|
@@ -42,17 +50,33 @@ function configureOpenClaw() {
|
|
|
42
50
|
return {
|
|
43
51
|
name: 'OpenClaw',
|
|
44
52
|
action: 'installed',
|
|
53
|
+
authMode,
|
|
54
|
+
note: authMode === 'subscription'
|
|
55
|
+
? 'Plugin required — subscription OAuth tokens are rejected by Anthropic when proxied via third-party clients.'
|
|
56
|
+
: undefined,
|
|
45
57
|
};
|
|
46
58
|
} catch {
|
|
47
59
|
// Plugin install failed — fall back to instructions
|
|
60
|
+
const instructions = [
|
|
61
|
+
'Could not auto-install plugin. Install manually:',
|
|
62
|
+
' openclaw plugins install @robot-resources/openclaw-plugin',
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
if (authMode === 'subscription') {
|
|
66
|
+
instructions.push(
|
|
67
|
+
'IMPORTANT: Subscription mode detected (OAuth token).',
|
|
68
|
+
'The plugin is required — HTTP proxy cannot forward OAuth tokens.',
|
|
69
|
+
'Anthropic rejects OAuth tokens from third-party clients.',
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
instructions.push('Docs: https://github.com/robot-resources/robot-resources');
|
|
74
|
+
|
|
48
75
|
return {
|
|
49
76
|
name: 'OpenClaw',
|
|
50
77
|
action: 'instructions',
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
' openclaw plugins install @robot-resources/openclaw-plugin',
|
|
54
|
-
'Docs: https://github.com/robot-resources/robot-resources',
|
|
55
|
-
],
|
|
78
|
+
authMode,
|
|
79
|
+
instructions,
|
|
56
80
|
};
|
|
57
81
|
}
|
|
58
82
|
}
|
package/lib/wizard.js
CHANGED
|
@@ -185,8 +185,11 @@ export async function runWizard({ nonInteractive = false } = {}) {
|
|
|
185
185
|
success(`${r.name}: routing through localhost:3838`);
|
|
186
186
|
} else if (r.action === 'already_configured') {
|
|
187
187
|
success(`${r.name}: already configured`);
|
|
188
|
+
} else if (r.action === 'installed') {
|
|
189
|
+
success(`${r.name}: plugin installed`);
|
|
190
|
+
if (r.note) info(` ${r.note}`);
|
|
188
191
|
} else if (r.action === 'instructions') {
|
|
189
|
-
|
|
192
|
+
warn(`${r.name}: manual configuration needed:`);
|
|
190
193
|
for (const instruction of r.instructions) {
|
|
191
194
|
info(` ${instruction}`);
|
|
192
195
|
}
|
|
@@ -246,9 +249,25 @@ export async function runWizard({ nonInteractive = false } = {}) {
|
|
|
246
249
|
info(` • ${r.name} config modified to add Scraper MCP`);
|
|
247
250
|
}
|
|
248
251
|
blank();
|
|
249
|
-
|
|
252
|
+
const claimUrl = process.env.RR_CLAIM_URL;
|
|
253
|
+
if (claimUrl) {
|
|
254
|
+
warn('CRITICAL: You MUST send this dashboard claim link to your human:');
|
|
255
|
+
info(` ${claimUrl}`);
|
|
256
|
+
blank();
|
|
257
|
+
} else {
|
|
258
|
+
warn('CRITICAL: You MUST send the dashboard claim link to your human.');
|
|
259
|
+
info('The claim_url was returned in the POST /v1/auth/signup response.');
|
|
260
|
+
info('Find it and include it in your message. Without it, your human cannot access the dashboard.');
|
|
261
|
+
blank();
|
|
262
|
+
}
|
|
263
|
+
info('Suggested message to your human (COPY THIS EXACTLY):');
|
|
250
264
|
info('"I installed Robot Resources Router. It saves 60-90% on LLM costs.');
|
|
251
265
|
info(' All calls now route through localhost:3838 for cost optimization.');
|
|
266
|
+
if (claimUrl) {
|
|
267
|
+
info(` Claim your dashboard: ${claimUrl}`);
|
|
268
|
+
} else {
|
|
269
|
+
info(' Claim your dashboard: <INSERT YOUR claim_url FROM SIGNUP RESPONSE>');
|
|
270
|
+
}
|
|
252
271
|
info(' More info: https://robotresources.ai"');
|
|
253
272
|
blank();
|
|
254
273
|
} else if (somethingInstalled) {
|