indieclaw-agent 2.3.0 → 2.4.0
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/index.js +65 -33
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -143,41 +143,67 @@ try {
|
|
|
143
143
|
// qrcode-terminal not installed, skip QR display
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
// --- OpenClaw Detection ---
|
|
146
|
+
// --- OpenClaw Detection & Config ---
|
|
147
|
+
const OPENCLAW_CONFIG_PATHS = [
|
|
148
|
+
path.join(os.homedir(), '.openclaw', 'openclaw.json'),
|
|
149
|
+
path.join(os.homedir(), '.openclaw', 'openclaw.json5'),
|
|
150
|
+
];
|
|
151
|
+
|
|
152
|
+
// Read OpenClaw gateway config (port + auth token) from local config file
|
|
153
|
+
function readOpenClawConfig() {
|
|
154
|
+
for (const configPath of OPENCLAW_CONFIG_PATHS) {
|
|
155
|
+
try {
|
|
156
|
+
if (!fs.existsSync(configPath)) continue;
|
|
157
|
+
let raw = fs.readFileSync(configPath, 'utf-8');
|
|
158
|
+
// Strip JSON5 comments (// and /* */) for safe JSON.parse
|
|
159
|
+
raw = raw.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
|
|
160
|
+
// Strip trailing commas before } or ]
|
|
161
|
+
raw = raw.replace(/,\s*([\]}])/g, '$1');
|
|
162
|
+
const config = JSON.parse(raw);
|
|
163
|
+
const gw = config.gateway || {};
|
|
164
|
+
return {
|
|
165
|
+
port: gw.port || 18789,
|
|
166
|
+
token: gw.auth?.token || gw.auth?.password || null,
|
|
167
|
+
host: gw.bind || '127.0.0.1',
|
|
168
|
+
};
|
|
169
|
+
} catch {}
|
|
170
|
+
}
|
|
171
|
+
return { port: 18789, token: null, host: '127.0.0.1' };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Cache the config on startup
|
|
175
|
+
let openClawConfig = readOpenClawConfig();
|
|
176
|
+
|
|
147
177
|
function detectOpenClaw() {
|
|
148
178
|
return new Promise((resolve) => {
|
|
179
|
+
// Refresh config each detection
|
|
180
|
+
openClawConfig = readOpenClawConfig();
|
|
181
|
+
|
|
149
182
|
// Method 1: Use `openclaw gateway status` CLI (most reliable)
|
|
150
183
|
exec('openclaw gateway status 2>&1', { timeout: 5000 }, (err, stdout) => {
|
|
151
184
|
const output = (stdout || '').toLowerCase();
|
|
152
|
-
// "running" in output means gateway is active
|
|
153
185
|
if (!err && (output.includes('running') || output.includes('active'))) {
|
|
154
|
-
|
|
155
|
-
const portMatch = (stdout || '').match(/:(\d+)/);
|
|
156
|
-
const port = portMatch ? parseInt(portMatch[1], 10) : 18789;
|
|
157
|
-
return resolve({ available: true, models: ['openclaw'], port });
|
|
186
|
+
return resolve({ available: true, models: ['openclaw'], port: openClawConfig.port });
|
|
158
187
|
}
|
|
159
188
|
|
|
160
|
-
// Method 2: Check if openclaw
|
|
161
|
-
exec('
|
|
162
|
-
if (
|
|
163
|
-
|
|
164
|
-
exec('pgrep -f "openclaw.gateway\\|openclaw-gateway" 2>/dev/null', { timeout: 2000 }, (err3, pid) => {
|
|
165
|
-
if (!err3 && pid?.trim()) {
|
|
166
|
-
return resolve({ available: true, models: ['openclaw'], port: 18789 });
|
|
167
|
-
}
|
|
168
|
-
return resolve({ available: false, models: [], port: null });
|
|
169
|
-
});
|
|
170
|
-
return;
|
|
189
|
+
// Method 2: Check if openclaw-gateway process is running
|
|
190
|
+
exec('pgrep -f "openclaw.gateway\\|openclaw-gateway" 2>/dev/null', { timeout: 2000 }, (err3, pid) => {
|
|
191
|
+
if (!err3 && pid?.trim()) {
|
|
192
|
+
return resolve({ available: true, models: ['openclaw'], port: openClawConfig.port });
|
|
171
193
|
}
|
|
172
194
|
|
|
173
|
-
//
|
|
174
|
-
exec('
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
return resolve({ available: true, models: ['openclaw'], port: 18789 });
|
|
195
|
+
// Method 3: Check if openclaw binary exists + health check
|
|
196
|
+
exec('command -v openclaw 2>/dev/null', { timeout: 2000 }, (err2, binPath) => {
|
|
197
|
+
if (err2 || !binPath?.trim()) {
|
|
198
|
+
return resolve({ available: false, models: [], port: null });
|
|
178
199
|
}
|
|
179
|
-
|
|
180
|
-
|
|
200
|
+
exec(`openclaw gateway health --url ws://127.0.0.1:${openClawConfig.port} 2>&1`, { timeout: 5000 }, (err4, healthOut) => {
|
|
201
|
+
const hOutput = (healthOut || '').toLowerCase();
|
|
202
|
+
if (!err4 && (hOutput.includes('ok') || hOutput.includes('healthy') || hOutput.includes('reachable'))) {
|
|
203
|
+
return resolve({ available: true, models: ['openclaw'], port: openClawConfig.port });
|
|
204
|
+
}
|
|
205
|
+
return resolve({ available: false, models: [], port: null });
|
|
206
|
+
});
|
|
181
207
|
});
|
|
182
208
|
});
|
|
183
209
|
});
|
|
@@ -187,7 +213,7 @@ function detectOpenClaw() {
|
|
|
187
213
|
// Run detection on startup
|
|
188
214
|
detectOpenClaw().then((oc) => {
|
|
189
215
|
if (oc.available) {
|
|
190
|
-
console.log(` [OpenClaw] Detected (gateway
|
|
216
|
+
console.log(` [OpenClaw] Detected (gateway on port ${oc.port})`);
|
|
191
217
|
} else {
|
|
192
218
|
console.log(' [OpenClaw] Not detected');
|
|
193
219
|
}
|
|
@@ -952,9 +978,11 @@ function handleTerminalStop(ws, { id }) {
|
|
|
952
978
|
}
|
|
953
979
|
|
|
954
980
|
// --- Chat (OpenClaw Proxy) ---
|
|
955
|
-
function handleChatSend(ws, { id, messages
|
|
956
|
-
|
|
957
|
-
const
|
|
981
|
+
function handleChatSend(ws, { id, messages }) {
|
|
982
|
+
// Use locally-detected OpenClaw config — no need for app to send credentials
|
|
983
|
+
const port = openClawConfig.port || 18789;
|
|
984
|
+
const host = openClawConfig.host || '127.0.0.1';
|
|
985
|
+
const token = openClawConfig.token;
|
|
958
986
|
|
|
959
987
|
const body = JSON.stringify({
|
|
960
988
|
model: 'openclaw:main',
|
|
@@ -962,17 +990,21 @@ function handleChatSend(ws, { id, messages, openclawToken, openclawPort, opencla
|
|
|
962
990
|
stream: true,
|
|
963
991
|
});
|
|
964
992
|
|
|
993
|
+
const headers = {
|
|
994
|
+
'Content-Type': 'application/json',
|
|
995
|
+
'x-openclaw-agent-id': 'main',
|
|
996
|
+
};
|
|
997
|
+
if (token) {
|
|
998
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
999
|
+
}
|
|
1000
|
+
|
|
965
1001
|
const req = http.request(
|
|
966
1002
|
{
|
|
967
1003
|
hostname: host,
|
|
968
1004
|
port,
|
|
969
1005
|
path: '/v1/chat/completions',
|
|
970
1006
|
method: 'POST',
|
|
971
|
-
headers
|
|
972
|
-
'Content-Type': 'application/json',
|
|
973
|
-
Authorization: `Bearer ${openclawToken}`,
|
|
974
|
-
'x-openclaw-agent-id': 'main',
|
|
975
|
-
},
|
|
1007
|
+
headers,
|
|
976
1008
|
},
|
|
977
1009
|
(res) => {
|
|
978
1010
|
if (res.statusCode !== 200) {
|