indieclaw-agent 1.0.0 → 1.1.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 (4) hide show
  1. package/README.md +1 -1
  2. package/index.js +110 -0
  3. package/install.sh +113 -0
  4. package/package.json +4 -4
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # IndieClaw Agent
2
2
 
3
- Manage your server from your phone. This is the server-side agent for the [IndieClaw](https://github.com/muhammetarslantas/indieclaw) mobile app.
3
+ Manage your server from your phone. This is the server-side agent for the [IndieClaw](https://github.com/Muhammed58/indieclaw) mobile app.
4
4
 
5
5
  ## Quick Start
6
6
 
package/index.js CHANGED
@@ -119,6 +119,12 @@ async function handleMessage(ws, msg) {
119
119
  return handleFsDelete(ws, msg);
120
120
  case 'system.stats':
121
121
  return handleSystemStats(ws, msg);
122
+ case 'system.top.cpu':
123
+ return handleTopCpu(ws, msg);
124
+ case 'system.top.memory':
125
+ return handleTopMemory(ws, msg);
126
+ case 'system.disk.details':
127
+ return handleDiskDetails(ws, msg);
122
128
  case 'docker.list':
123
129
  return handleDockerList(ws, msg);
124
130
  case 'docker.logs':
@@ -276,6 +282,110 @@ function getDiskUsage(platform) {
276
282
  }
277
283
  }
278
284
 
285
+ // --- Top Processes (CPU) ---
286
+ function handleTopCpu(ws, { id }) {
287
+ const platform = os.platform();
288
+ const cmd = platform === 'darwin'
289
+ ? 'ps aux -r | head -11'
290
+ : 'ps aux --sort=-%cpu | head -11';
291
+
292
+ exec(cmd, { timeout: 5000 }, (err, stdout) => {
293
+ if (err) return replyError(ws, id, err.message);
294
+ const processes = parsePsOutput(stdout);
295
+ reply(ws, id, { processes, timestamp: Date.now() });
296
+ });
297
+ }
298
+
299
+ // --- Top Processes (Memory) ---
300
+ function handleTopMemory(ws, { id }) {
301
+ const platform = os.platform();
302
+ const cmd = platform === 'darwin'
303
+ ? 'ps aux -m | head -11'
304
+ : 'ps aux --sort=-%mem | head -11';
305
+
306
+ exec(cmd, { timeout: 5000 }, (err, stdout) => {
307
+ if (err) return replyError(ws, id, err.message);
308
+ const processes = parsePsOutput(stdout);
309
+ reply(ws, id, { processes, timestamp: Date.now() });
310
+ });
311
+ }
312
+
313
+ function parsePsOutput(stdout) {
314
+ const lines = stdout.trim().split('\n').slice(1); // skip header
315
+ return lines.map((line) => {
316
+ const parts = line.trim().split(/\s+/);
317
+ // ps aux columns: USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
318
+ return {
319
+ pid: parseInt(parts[1], 10),
320
+ name: parts.slice(10).join(' '),
321
+ cpu: parseFloat(parts[2]) || 0,
322
+ memory: parseFloat(parts[3]) || 0,
323
+ };
324
+ });
325
+ }
326
+
327
+ // --- Disk Details ---
328
+ function handleDiskDetails(ws, { id }) {
329
+ const platform = os.platform();
330
+
331
+ const virtualFs = new Set([
332
+ 'devtmpfs', 'tmpfs', 'sysfs', 'proc', 'devpts', 'securityfs',
333
+ 'cgroup', 'cgroup2', 'pstore', 'debugfs', 'hugetlbfs', 'mqueue',
334
+ 'configfs', 'fusectl', 'tracefs', 'bpf', 'overlay', 'nsfs',
335
+ 'autofs', 'binfmt_misc', 'efivarfs',
336
+ ]);
337
+
338
+ const cmd = 'df -kT';
339
+
340
+ exec(cmd, { timeout: 5000 }, (err, stdout) => {
341
+ if (err) {
342
+ // Fallback: df -k without -T (macOS sometimes lacks -T)
343
+ return exec('df -k', { timeout: 5000 }, (err2, stdout2) => {
344
+ if (err2) return replyError(ws, id, err2.message);
345
+ const partitions = parseDfOutput(stdout2, false, virtualFs);
346
+ reply(ws, id, { partitions, timestamp: Date.now() });
347
+ });
348
+ }
349
+ const partitions = parseDfOutput(stdout, true, virtualFs);
350
+ reply(ws, id, { partitions, timestamp: Date.now() });
351
+ });
352
+ }
353
+
354
+ function parseDfOutput(stdout, hasType, virtualFs) {
355
+ const lines = stdout.trim().split('\n').slice(1);
356
+ return lines
357
+ .map((line) => {
358
+ const parts = line.trim().split(/\s+/);
359
+ if (hasType) {
360
+ // Filesystem Type 1K-blocks Used Available Use% Mounted
361
+ const fsType = parts[1];
362
+ if (virtualFs.has(fsType)) return null;
363
+ return {
364
+ filesystem: parts[0],
365
+ type: fsType,
366
+ total: parseInt(parts[2], 10) * 1024,
367
+ used: parseInt(parts[3], 10) * 1024,
368
+ available: parseInt(parts[4], 10) * 1024,
369
+ usagePercent: parseInt(parts[5], 10) || 0,
370
+ mount: parts.slice(6).join(' ') || '/',
371
+ };
372
+ }
373
+ // Filesystem 1K-blocks Used Available Use% Mounted
374
+ const fsName = parts[0];
375
+ if (fsName === 'devfs' || fsName === 'map' || fsName.startsWith('map ')) return null;
376
+ return {
377
+ filesystem: fsName,
378
+ type: 'unknown',
379
+ total: parseInt(parts[1], 10) * 1024,
380
+ used: parseInt(parts[2], 10) * 1024,
381
+ available: parseInt(parts[3], 10) * 1024,
382
+ usagePercent: parseInt(parts[4], 10) || 0,
383
+ mount: parts.slice(5).join(' ') || '/',
384
+ };
385
+ })
386
+ .filter(Boolean);
387
+ }
388
+
279
389
  // --- Docker ---
280
390
  function handleDockerList(ws, { id }) {
281
391
  exec(
package/install.sh ADDED
@@ -0,0 +1,113 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ # Colors
5
+ GREEN='\033[0;32m'
6
+ YELLOW='\033[1;33m'
7
+ CYAN='\033[0;36m'
8
+ RED='\033[0;31m'
9
+ NC='\033[0m'
10
+ BOLD='\033[1m'
11
+
12
+ echo ""
13
+ echo -e "${CYAN}╔═══════════════════════════════════════╗${NC}"
14
+ echo -e "${CYAN}║ ${BOLD}IndieClaw Agent Installer${NC}${CYAN} ║${NC}"
15
+ echo -e "${CYAN}╚═══════════════════════════════════════╝${NC}"
16
+ echo ""
17
+
18
+ # Check if running as root
19
+ if [ "$EUID" -eq 0 ]; then
20
+ SUDO=""
21
+ else
22
+ SUDO="sudo"
23
+ fi
24
+
25
+ # Step 1: Check/Install Node.js
26
+ echo -e "${YELLOW}[1/4]${NC} Checking Node.js..."
27
+ if command -v node &> /dev/null; then
28
+ NODE_VERSION=$(node -v)
29
+ echo -e " ${GREEN}✓${NC} Node.js ${NODE_VERSION} found"
30
+ else
31
+ echo -e " Installing Node.js..."
32
+ if command -v apt-get &> /dev/null; then
33
+ curl -fsSL https://deb.nodesource.com/setup_20.x | $SUDO bash -
34
+ $SUDO apt-get install -y nodejs
35
+ elif command -v yum &> /dev/null; then
36
+ curl -fsSL https://rpm.nodesource.com/setup_20.x | $SUDO bash -
37
+ $SUDO yum install -y nodejs
38
+ elif command -v dnf &> /dev/null; then
39
+ curl -fsSL https://rpm.nodesource.com/setup_20.x | $SUDO bash -
40
+ $SUDO dnf install -y nodejs
41
+ else
42
+ echo -e " ${RED}✗${NC} Could not detect package manager. Install Node.js 18+ manually."
43
+ exit 1
44
+ fi
45
+ echo -e " ${GREEN}✓${NC} Node.js $(node -v) installed"
46
+ fi
47
+
48
+ # Step 2: Install indieclaw-agent
49
+ echo -e "${YELLOW}[2/4]${NC} Installing indieclaw-agent..."
50
+ $SUDO npm install -g indieclaw-agent 2>/dev/null || npm install -g indieclaw-agent
51
+ echo -e " ${GREEN}✓${NC} indieclaw-agent installed"
52
+
53
+ # Step 3: Create systemd service
54
+ echo -e "${YELLOW}[3/4]${NC} Setting up background service..."
55
+ AGENT_PATH=$(which indieclaw-agent)
56
+ CURRENT_USER=$(whoami)
57
+
58
+ $SUDO tee /etc/systemd/system/indieclaw-agent.service > /dev/null <<EOF
59
+ [Unit]
60
+ Description=IndieClaw Agent
61
+ After=network.target
62
+
63
+ [Service]
64
+ Type=simple
65
+ User=${CURRENT_USER}
66
+ ExecStart=${AGENT_PATH}
67
+ Restart=always
68
+ RestartSec=10
69
+ Environment=INDIECLAW_PORT=3100
70
+
71
+ [Install]
72
+ WantedBy=multi-user.target
73
+ EOF
74
+
75
+ $SUDO systemctl daemon-reload
76
+ $SUDO systemctl enable indieclaw-agent
77
+ $SUDO systemctl start indieclaw-agent
78
+ echo -e " ${GREEN}✓${NC} Service created and started"
79
+
80
+ # Step 4: Wait for token to be generated
81
+ sleep 2
82
+
83
+ # Show token
84
+ echo ""
85
+ echo -e "${CYAN}═══════════════════════════════════════${NC}"
86
+ echo ""
87
+
88
+ if [ -f "$HOME/.indieclaw-token" ]; then
89
+ TOKEN=$(cat "$HOME/.indieclaw-token")
90
+ echo -e " ${GREEN}${BOLD}Setup complete!${NC}"
91
+ echo ""
92
+ echo -e " Your auth token:"
93
+ echo ""
94
+ echo -e " ${BOLD}${CYAN}${TOKEN}${NC}"
95
+ echo ""
96
+ echo -e " Copy this token into the IndieClaw app."
97
+ echo -e " Port: ${BOLD}3100${NC}"
98
+ else
99
+ echo -e " ${GREEN}${BOLD}Setup complete!${NC}"
100
+ echo ""
101
+ echo -e " Run this to see your token:"
102
+ echo -e " ${BOLD}cat ~/.indieclaw-token${NC}"
103
+ fi
104
+
105
+ echo ""
106
+ echo -e "${CYAN}═══════════════════════════════════════${NC}"
107
+ echo ""
108
+ echo -e " Useful commands:"
109
+ echo -e " Status: ${BOLD}sudo systemctl status indieclaw-agent${NC}"
110
+ echo -e " Logs: ${BOLD}sudo journalctl -u indieclaw-agent -f${NC}"
111
+ echo -e " Restart: ${BOLD}sudo systemctl restart indieclaw-agent${NC}"
112
+ echo -e " Remove: ${BOLD}sudo systemctl stop indieclaw-agent && sudo systemctl disable indieclaw-agent${NC}"
113
+ echo ""
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "indieclaw-agent",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Manage your server from your phone. Agent for the IndieClaw mobile app.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -24,11 +24,11 @@
24
24
  "license": "MIT",
25
25
  "repository": {
26
26
  "type": "git",
27
- "url": "https://github.com/muhammetarslantas/indieclaw-agent"
27
+ "url": "https://github.com/Muhammed58/indieclaw-agent"
28
28
  },
29
- "homepage": "https://github.com/muhammetarslantas/indieclaw-agent#readme",
29
+ "homepage": "https://github.com/Muhammed58/indieclaw-agent#readme",
30
30
  "bugs": {
31
- "url": "https://github.com/muhammetarslantas/indieclaw-agent/issues"
31
+ "url": "https://github.com/Muhammed58/indieclaw-agent/issues"
32
32
  },
33
33
  "engines": {
34
34
  "node": ">=18.0.0"