indieclaw-agent 2.4.1 → 2.4.2
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 +102 -15
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -146,28 +146,85 @@ try {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
// --- OpenClaw Detection, Config & Gateway Client ---
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
];
|
|
149
|
+
|
|
150
|
+
// Search multiple possible config locations (systemd may resolve homedir differently)
|
|
151
|
+
function getConfigPaths() {
|
|
152
|
+
const paths = [];
|
|
153
|
+
const home = os.homedir();
|
|
154
|
+
paths.push(path.join(home, '.openclaw', 'openclaw.json'));
|
|
155
|
+
paths.push(path.join(home, '.openclaw', 'openclaw.json5'));
|
|
156
|
+
// Also check /root explicitly (systemd services may not resolve ~ to /root)
|
|
157
|
+
if (home !== '/root') {
|
|
158
|
+
paths.push('/root/.openclaw/openclaw.json');
|
|
159
|
+
paths.push('/root/.openclaw/openclaw.json5');
|
|
160
|
+
}
|
|
161
|
+
return paths;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const OPENCLAW_CONFIG_PATHS = getConfigPaths();
|
|
165
|
+
|
|
166
|
+
function stripJsonComments(raw) {
|
|
167
|
+
// Remove comments WITHOUT corrupting URLs inside strings
|
|
168
|
+
// Walk char-by-char, track if we're inside a string
|
|
169
|
+
let result = '';
|
|
170
|
+
let inString = false;
|
|
171
|
+
let escaped = false;
|
|
172
|
+
for (let i = 0; i < raw.length; i++) {
|
|
173
|
+
const ch = raw[i];
|
|
174
|
+
if (inString) {
|
|
175
|
+
result += ch;
|
|
176
|
+
if (escaped) { escaped = false; continue; }
|
|
177
|
+
if (ch === '\\') { escaped = true; continue; }
|
|
178
|
+
if (ch === '"') { inString = false; }
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
// Not in string
|
|
182
|
+
if (ch === '"') { inString = true; result += ch; continue; }
|
|
183
|
+
// Line comment
|
|
184
|
+
if (ch === '/' && raw[i + 1] === '/') {
|
|
185
|
+
// Skip to end of line
|
|
186
|
+
while (i < raw.length && raw[i] !== '\n') i++;
|
|
187
|
+
result += '\n';
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
// Block comment
|
|
191
|
+
if (ch === '/' && raw[i + 1] === '*') {
|
|
192
|
+
i += 2;
|
|
193
|
+
while (i < raw.length && !(raw[i] === '*' && raw[i + 1] === '/')) i++;
|
|
194
|
+
i++; // skip closing /
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
result += ch;
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
153
201
|
|
|
154
202
|
function readOpenClawConfig() {
|
|
155
203
|
for (const cfgPath of OPENCLAW_CONFIG_PATHS) {
|
|
156
204
|
try {
|
|
157
|
-
|
|
205
|
+
const exists = fs.existsSync(cfgPath);
|
|
206
|
+
console.log(` [OpenClaw] Config ${cfgPath}: ${exists ? 'EXISTS' : 'not found'}`);
|
|
207
|
+
if (!exists) continue;
|
|
158
208
|
let raw = fs.readFileSync(cfgPath, 'utf-8');
|
|
159
|
-
|
|
209
|
+
// Strip comments safely (preserves URLs in strings)
|
|
210
|
+
raw = stripJsonComments(raw);
|
|
211
|
+
// Remove trailing commas
|
|
160
212
|
raw = raw.replace(/,\s*([\]}])/g, '$1');
|
|
161
213
|
const config = JSON.parse(raw);
|
|
162
214
|
const gw = config.gateway || {};
|
|
163
|
-
|
|
215
|
+
const result = {
|
|
164
216
|
port: gw.port || 18789,
|
|
165
217
|
token: gw.auth?.token || gw.auth?.password || null,
|
|
166
218
|
host: gw.bind || '127.0.0.1',
|
|
167
219
|
};
|
|
168
|
-
|
|
220
|
+
console.log(` [OpenClaw] Config parsed: port=${result.port}, host=${result.host}, token=${result.token ? 'SET' : 'NONE'}`);
|
|
221
|
+
return result;
|
|
222
|
+
} catch (err) {
|
|
223
|
+
console.log(` [OpenClaw] Config parse error for ${cfgPath}: ${err.message}`);
|
|
224
|
+
}
|
|
169
225
|
}
|
|
170
226
|
// Fallback: check env var
|
|
227
|
+
console.log(' [OpenClaw] No config file found, using defaults (port 18789)');
|
|
171
228
|
return {
|
|
172
229
|
port: parseInt(process.env.OPENCLAW_GATEWAY_PORT || '18789', 10),
|
|
173
230
|
token: process.env.OPENCLAW_GATEWAY_TOKEN || null,
|
|
@@ -180,26 +237,43 @@ let openClawConfig = readOpenClawConfig();
|
|
|
180
237
|
// TCP port check — fast and reliable, no auth needed
|
|
181
238
|
function isPortListening(port, host = '127.0.0.1') {
|
|
182
239
|
return new Promise((resolve) => {
|
|
240
|
+
console.log(` [OpenClaw] TCP probe ${host}:${port}...`);
|
|
183
241
|
const sock = net.createConnection({ port, host }, () => {
|
|
242
|
+
console.log(` [OpenClaw] TCP probe ${host}:${port} → OPEN`);
|
|
184
243
|
sock.destroy();
|
|
185
244
|
resolve(true);
|
|
186
245
|
});
|
|
187
|
-
sock.on('error', () =>
|
|
188
|
-
|
|
246
|
+
sock.on('error', (err) => {
|
|
247
|
+
console.log(` [OpenClaw] TCP probe ${host}:${port} → ERROR: ${err.message}`);
|
|
248
|
+
resolve(false);
|
|
249
|
+
});
|
|
250
|
+
sock.setTimeout(2000, () => {
|
|
251
|
+
console.log(` [OpenClaw] TCP probe ${host}:${port} → TIMEOUT`);
|
|
252
|
+
sock.destroy();
|
|
253
|
+
resolve(false);
|
|
254
|
+
});
|
|
189
255
|
});
|
|
190
256
|
}
|
|
191
257
|
|
|
192
258
|
async function detectOpenClaw() {
|
|
259
|
+
console.log(' [OpenClaw] Running detection...');
|
|
193
260
|
openClawConfig = readOpenClawConfig();
|
|
194
|
-
|
|
261
|
+
|
|
262
|
+
// Always probe 127.0.0.1 — the gateway listens on loopback
|
|
263
|
+
const port = openClawConfig.port || 18789;
|
|
264
|
+
const listening = await isPortListening(port, '127.0.0.1');
|
|
195
265
|
if (listening) {
|
|
196
|
-
|
|
266
|
+
console.log(` [OpenClaw] Detection result: AVAILABLE (port ${port})`);
|
|
267
|
+
return { available: true, models: ['openclaw'], port };
|
|
197
268
|
}
|
|
269
|
+
|
|
198
270
|
// Fallback: check if config file exists (installed but not running)
|
|
199
271
|
const installed = OPENCLAW_CONFIG_PATHS.some((p) => fs.existsSync(p));
|
|
200
272
|
if (installed) {
|
|
201
|
-
|
|
273
|
+
console.log(` [OpenClaw] Detection result: INSTALLED but gateway not running`);
|
|
274
|
+
return { available: false, models: [], port, installed: true };
|
|
202
275
|
}
|
|
276
|
+
console.log(' [OpenClaw] Detection result: NOT FOUND');
|
|
203
277
|
return { available: false, models: [], port: null };
|
|
204
278
|
}
|
|
205
279
|
|
|
@@ -213,6 +287,7 @@ function connectOcGateway() {
|
|
|
213
287
|
return new Promise((resolve, reject) => {
|
|
214
288
|
openClawConfig = readOpenClawConfig();
|
|
215
289
|
const url = `ws://127.0.0.1:${openClawConfig.port}`;
|
|
290
|
+
console.log(` [OpenClaw] Connecting to gateway: ${url}`);
|
|
216
291
|
|
|
217
292
|
if (ocGateway) { try { ocGateway.close(); } catch {} }
|
|
218
293
|
ocGateway = null;
|
|
@@ -220,12 +295,14 @@ function connectOcGateway() {
|
|
|
220
295
|
|
|
221
296
|
const ws = new WebSocket(url);
|
|
222
297
|
let connectReqId = null;
|
|
223
|
-
const timeout = setTimeout(() => { ws.close(); reject(new Error('Gateway timeout')); }, 10000);
|
|
298
|
+
const timeout = setTimeout(() => { console.log(' [OpenClaw] Gateway connection TIMEOUT'); ws.close(); reject(new Error('Gateway timeout')); }, 10000);
|
|
224
299
|
|
|
225
300
|
ws.on('message', (data) => {
|
|
226
301
|
let msg;
|
|
227
302
|
try { msg = JSON.parse(data.toString()); } catch { return; }
|
|
228
303
|
|
|
304
|
+
console.log(` [OpenClaw] Gateway msg: type=${msg.type}, event=${msg.event || ''}, id=${msg.id || ''}, ok=${msg.ok}`);
|
|
305
|
+
|
|
229
306
|
// Step 1: Gateway sends connect.challenge
|
|
230
307
|
if (msg.type === 'event' && msg.event === 'connect.challenge') {
|
|
231
308
|
connectReqId = crypto.randomUUID();
|
|
@@ -292,8 +369,9 @@ function connectOcGateway() {
|
|
|
292
369
|
}
|
|
293
370
|
});
|
|
294
371
|
|
|
295
|
-
ws.on('error', (err) => { clearTimeout(timeout); ocReady = false; reject(err); });
|
|
372
|
+
ws.on('error', (err) => { console.log(` [OpenClaw] Gateway error: ${err.message}`); clearTimeout(timeout); ocReady = false; reject(err); });
|
|
296
373
|
ws.on('close', () => {
|
|
374
|
+
console.log(' [OpenClaw] Gateway connection closed');
|
|
297
375
|
ocReady = false;
|
|
298
376
|
ocGateway = null;
|
|
299
377
|
// Notify all pending chat streams that gateway disconnected
|
|
@@ -383,6 +461,7 @@ wss.on('connection', (ws) => {
|
|
|
383
461
|
if (msg.type === 'auth' && msg.token === AUTH_TOKEN) {
|
|
384
462
|
authenticated = true;
|
|
385
463
|
const openclaw = await detectOpenClaw();
|
|
464
|
+
console.log(` [Auth] Sending auth success, openclaw:`, JSON.stringify(openclaw));
|
|
386
465
|
return ws.send(JSON.stringify({ type: 'auth', success: true, openclaw }));
|
|
387
466
|
}
|
|
388
467
|
if (msg.type === 'ping') {
|
|
@@ -1105,14 +1184,18 @@ function handleTerminalStop(ws, { id }) {
|
|
|
1105
1184
|
// --- Chat (OpenClaw Gateway Proxy) ---
|
|
1106
1185
|
async function handleChatSend(ws, { id, messages }) {
|
|
1107
1186
|
try {
|
|
1187
|
+
console.log(` [Chat] handleChatSend id=${id}, messages=${messages.length}`);
|
|
1188
|
+
|
|
1108
1189
|
// Connect to OpenClaw gateway (auto-reconnects if needed)
|
|
1109
1190
|
await getOcGateway();
|
|
1191
|
+
console.log(' [Chat] Gateway connected');
|
|
1110
1192
|
|
|
1111
1193
|
// Extract the last user message from the conversation
|
|
1112
1194
|
const lastUserMsg = [...messages].reverse().find(m => m.role === 'user');
|
|
1113
1195
|
if (!lastUserMsg) {
|
|
1114
1196
|
return send(ws, { type: 'chat.done', id, error: 'No user message found' });
|
|
1115
1197
|
}
|
|
1198
|
+
console.log(` [Chat] Sending to OpenClaw: "${lastUserMsg.content.substring(0, 80)}..."`);
|
|
1116
1199
|
|
|
1117
1200
|
// Build a session key — unique per chat conversation
|
|
1118
1201
|
const sessionKey = `agent:indieclaw:mobile:${id}`;
|
|
@@ -1125,12 +1208,16 @@ async function handleChatSend(ws, { id, messages }) {
|
|
|
1125
1208
|
idempotencyKey,
|
|
1126
1209
|
});
|
|
1127
1210
|
|
|
1211
|
+
console.log(` [Chat] ocRequest result:`, JSON.stringify(result).substring(0, 200));
|
|
1212
|
+
|
|
1128
1213
|
// Register for streaming events using the runId from the response
|
|
1129
1214
|
const runId = result?.runId || result?.id || id;
|
|
1215
|
+
console.log(` [Chat] Registered callback for runId=${runId}`);
|
|
1130
1216
|
ocChatCallbacks.set(runId, { ws, chatId: id });
|
|
1131
1217
|
activeChats.set(id, { runId, _ws: ws });
|
|
1132
1218
|
|
|
1133
1219
|
} catch (err) {
|
|
1220
|
+
console.log(` [Chat] ERROR: ${err.message}`);
|
|
1134
1221
|
send(ws, { type: 'chat.done', id, error: `OpenClaw: ${err.message}` });
|
|
1135
1222
|
}
|
|
1136
1223
|
}
|