indieclaw-agent 2.2.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 (3) hide show
  1. package/index.js +75 -54
  2. package/install.sh +14 -4
  3. package/package.json +1 -1
package/index.js CHANGED
@@ -143,64 +143,79 @@ try {
143
143
  // qrcode-terminal not installed, skip QR display
144
144
  }
145
145
 
146
- // --- OpenClaw Detection ---
147
- const OPENCLAW_PORTS = [18789, 8080, 11434, 1234, 8000];
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();
148
176
 
149
- function tryOpenClawPort(port) {
177
+ function detectOpenClaw() {
150
178
  return new Promise((resolve) => {
151
- const req = http.request(
152
- {
153
- hostname: '127.0.0.1',
154
- port,
155
- path: '/v1/models',
156
- method: 'GET',
157
- timeout: 2000,
158
- },
159
- (res) => {
160
- let body = '';
161
- res.on('data', (chunk) => (body += chunk));
162
- res.on('end', () => {
163
- try {
164
- const json = JSON.parse(body);
165
- const models = (json.data || []).map((m) => m.id);
166
- if (models.length > 0) {
167
- resolve({ available: true, models, port });
168
- } else {
169
- resolve({ available: false, models: [], port });
170
- }
171
- } catch {
172
- resolve({ available: false, models: [], port });
179
+ // Refresh config each detection
180
+ openClawConfig = readOpenClawConfig();
181
+
182
+ // Method 1: Use `openclaw gateway status` CLI (most reliable)
183
+ exec('openclaw gateway status 2>&1', { timeout: 5000 }, (err, stdout) => {
184
+ const output = (stdout || '').toLowerCase();
185
+ if (!err && (output.includes('running') || output.includes('active'))) {
186
+ return resolve({ available: true, models: ['openclaw'], port: openClawConfig.port });
187
+ }
188
+
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 });
193
+ }
194
+
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 });
173
199
  }
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
+ });
174
207
  });
175
- }
176
- );
177
- req.on('timeout', () => {
178
- req.destroy();
179
- resolve({ available: false, models: [], port });
180
- });
181
- req.on('error', () => {
182
- resolve({ available: false, models: [], port });
208
+ });
183
209
  });
184
- req.end();
185
210
  });
186
211
  }
187
212
 
188
- async function detectOpenClaw() {
189
- // Try all common ports in parallel
190
- const results = await Promise.all(OPENCLAW_PORTS.map(tryOpenClawPort));
191
- const found = results.find((r) => r.available);
192
- if (found) {
193
- return { available: true, models: found.models, port: found.port };
194
- }
195
- return { available: false, models: [], port: null };
196
- }
197
-
198
213
  // Run detection on startup
199
214
  detectOpenClaw().then((oc) => {
200
215
  if (oc.available) {
201
- console.log(` [OpenClaw] Detected on port ${oc.port}! Models: ${oc.models.join(', ')}`);
216
+ console.log(` [OpenClaw] Detected (gateway on port ${oc.port})`);
202
217
  } else {
203
- console.log(` [OpenClaw] Not detected on ports ${OPENCLAW_PORTS.join(', ')}`);
218
+ console.log(' [OpenClaw] Not detected');
204
219
  }
205
220
  });
206
221
 
@@ -963,9 +978,11 @@ function handleTerminalStop(ws, { id }) {
963
978
  }
964
979
 
965
980
  // --- Chat (OpenClaw Proxy) ---
966
- function handleChatSend(ws, { id, messages, openclawToken, openclawPort, openclawHost }) {
967
- const port = openclawPort || 18789;
968
- 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;
969
986
 
970
987
  const body = JSON.stringify({
971
988
  model: 'openclaw:main',
@@ -973,17 +990,21 @@ function handleChatSend(ws, { id, messages, openclawToken, openclawPort, opencla
973
990
  stream: true,
974
991
  });
975
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
+
976
1001
  const req = http.request(
977
1002
  {
978
1003
  hostname: host,
979
1004
  port,
980
1005
  path: '/v1/chat/completions',
981
1006
  method: 'POST',
982
- headers: {
983
- 'Content-Type': 'application/json',
984
- Authorization: `Bearer ${openclawToken}`,
985
- 'x-openclaw-agent-id': 'main',
986
- },
1007
+ headers,
987
1008
  },
988
1009
  (res) => {
989
1010
  if (res.statusCode !== 200) {
package/install.sh CHANGED
@@ -110,11 +110,21 @@ echo -e " ${GREEN}✓${NC} IP: ${MACHINE_IP}"
110
110
  # Step 5: Check OpenClaw
111
111
  echo -e "${YELLOW}[5/5]${NC} Checking OpenClaw..."
112
112
  OPENCLAW_STATUS="not detected"
113
- if curl -s --max-time 2 http://127.0.0.1:18789/v1/models > /dev/null 2>&1; then
114
- OPENCLAW_STATUS="detected on port 18789"
115
- echo -e " ${GREEN}✓${NC} OpenClaw detected on port 18789"
113
+ # Check via CLI (gateway status), then via process, then via binary existence
114
+ if command -v openclaw &> /dev/null; then
115
+ OC_STATUS=$(openclaw gateway status 2>&1 || true)
116
+ if echo "$OC_STATUS" | grep -qi "running\|active"; then
117
+ OPENCLAW_STATUS="running"
118
+ echo -e " ${GREEN}✓${NC} OpenClaw gateway is running"
119
+ elif pgrep -f "openclaw.gateway\|openclaw-gateway" > /dev/null 2>&1; then
120
+ OPENCLAW_STATUS="running"
121
+ echo -e " ${GREEN}✓${NC} OpenClaw gateway process detected"
122
+ else
123
+ OPENCLAW_STATUS="installed (gateway not running)"
124
+ echo -e " ${YELLOW}—${NC} OpenClaw installed but gateway not running. Start with: openclaw gateway run"
125
+ fi
116
126
  else
117
- echo -e " ${YELLOW}—${NC} OpenClaw not detected on port 18789 (optional, for AI features)"
127
+ echo -e " ${YELLOW}—${NC} OpenClaw not installed (optional, for AI features)"
118
128
  fi
119
129
 
120
130
  # Build deep link
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "indieclaw-agent",
3
- "version": "2.2.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": {