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.
Files changed (2) hide show
  1. package/index.js +65 -33
  2. 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
- // Try to get the gateway port from config
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 binary exists at all
161
- exec('command -v openclaw 2>/dev/null', { timeout: 2000 }, (err2, binPath) => {
162
- if (err2 || !binPath?.trim()) {
163
- // Method 3: Check if openclaw-gateway process is running
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
- // Binary exists but gateway might not be running — try health check
174
- exec('openclaw gateway health --url ws://127.0.0.1:18789 2>&1', { timeout: 5000 }, (err4, healthOut) => {
175
- const hOutput = (healthOut || '').toLowerCase();
176
- if (!err4 && (hOutput.includes('ok') || hOutput.includes('healthy') || hOutput.includes('reachable'))) {
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
- // Binary installed but gateway not running
180
- return resolve({ available: false, models: [], port: null });
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 running on port ${oc.port})`);
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, openclawToken, openclawPort, openclawHost }) {
956
- const port = openclawPort || 18789;
957
- const host = openclawHost || '127.0.0.1';
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "indieclaw-agent",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Manage your server from your phone. Agent for the IndieClaw mobile app.",
5
5
  "main": "index.js",
6
6
  "bin": {