agent-window 1.4.1 → 1.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/package.json +5 -2
- package/scripts/cleanup-pm2.sh +130 -0
- package/src/bot.js +70 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-window",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "A window to interact with AI agents through chat interfaces. Simplified interaction, powerful backend capabilities.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/bot.js",
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
"ui": "node bin/cli.js ui",
|
|
12
12
|
"ui:dev": "cd web && npm run dev",
|
|
13
13
|
"ui:build": "cd web && npm run build",
|
|
14
|
+
"cleanup-pm2": "bash scripts/cleanup-pm2.sh",
|
|
15
|
+
"check-node": "node -e \"const v=process.version; const n=parseInt(v.slice(1)); if(n>=23){console.error('⚠️ Node.js',v,'not supported. Use v18 or v20 LTS.'); process.exit(1);}else{console.log('✓ Node.js',v,'is supported');}\"",
|
|
14
16
|
"pm2:start": "pm2 start ecosystem.config.cjs",
|
|
15
17
|
"pm2:stop": "pm2 stop bot-corp",
|
|
16
18
|
"pm2:restart": "pm2 restart bot-corp",
|
|
@@ -26,7 +28,8 @@
|
|
|
26
28
|
"author": "",
|
|
27
29
|
"license": "MIT",
|
|
28
30
|
"engines": {
|
|
29
|
-
"node": ">=18.0.0"
|
|
31
|
+
"node": ">=18.0.0 <23.0.0",
|
|
32
|
+
"npm": ">=9.0.0"
|
|
30
33
|
},
|
|
31
34
|
"dependencies": {
|
|
32
35
|
"@fastify/static": "^6.0.0",
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# PM2 Deep Cleanup Script
|
|
3
|
+
# AgentWindow Multi-Instance Bug Recovery Tool
|
|
4
|
+
#
|
|
5
|
+
# This script cleans up:
|
|
6
|
+
# - Multiple PM2 God Daemon processes (200+ leaked instances)
|
|
7
|
+
# - Orphaned bot processes
|
|
8
|
+
# - Stale PM2 dump files
|
|
9
|
+
# - Duplicate instances
|
|
10
|
+
|
|
11
|
+
set -e
|
|
12
|
+
|
|
13
|
+
echo "🧹 PM2 Deep Cleanup Script"
|
|
14
|
+
echo "======================================"
|
|
15
|
+
echo ""
|
|
16
|
+
|
|
17
|
+
# Color codes for output
|
|
18
|
+
RED='\033[0;31m'
|
|
19
|
+
GREEN='\033[0;32m'
|
|
20
|
+
YELLOW='\033[1;33m'
|
|
21
|
+
NC='\033[0m' # No Color
|
|
22
|
+
|
|
23
|
+
# Step 1: Check PM2 processes before cleanup
|
|
24
|
+
echo "[1/7] Analyzing current state..."
|
|
25
|
+
echo "-----------------------------------"
|
|
26
|
+
|
|
27
|
+
PM2_COUNT=$(pgrep -f "PM2.*God Daemon" | wc -l | tr -d ' ' || echo "0")
|
|
28
|
+
BOT_COUNT=$(ps aux | grep "node.*bot.js" | grep -v grep | wc -l | tr -d ' ' || echo "0")
|
|
29
|
+
|
|
30
|
+
echo -e "PM2 God Daemons: ${YELLOW}${PM2_COUNT}${NC}"
|
|
31
|
+
echo -e "Bot processes: ${YELLOW}${BOT_COUNT}${NC}"
|
|
32
|
+
echo ""
|
|
33
|
+
|
|
34
|
+
if [ "$PM2_COUNT" -lt 5 ] && [ "$BOT_COUNT" -lt 3 ]; then
|
|
35
|
+
echo -e "${GREEN}✓ System appears clean (no major issues detected)${NC}"
|
|
36
|
+
echo ""
|
|
37
|
+
read -p "Continue cleanup anyway? (y/N): " -n 1 -r
|
|
38
|
+
echo
|
|
39
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
40
|
+
echo "Cleanup cancelled."
|
|
41
|
+
exit 0
|
|
42
|
+
fi
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
# Step 2: Stop all PM2 apps
|
|
46
|
+
echo "[2/7] Stopping all PM2 apps..."
|
|
47
|
+
echo "-----------------------------------"
|
|
48
|
+
if command -v pm2 &> /dev/null; then
|
|
49
|
+
pm2 stop all 2>/dev/null || echo " No apps to stop"
|
|
50
|
+
pm2 delete all 2>/dev/null || echo " No apps to delete"
|
|
51
|
+
echo -e "${GREEN}✓ PM2 apps stopped${NC}"
|
|
52
|
+
else
|
|
53
|
+
echo -e "${YELLOW}⚠ PM2 not found, skipping...${NC}"
|
|
54
|
+
fi
|
|
55
|
+
echo ""
|
|
56
|
+
|
|
57
|
+
# Step 3: Kill PM2 daemon
|
|
58
|
+
echo "[3/7] Killing PM2 daemon..."
|
|
59
|
+
echo "-----------------------------------"
|
|
60
|
+
if command -v pm2 &> /dev/null; then
|
|
61
|
+
pm2 kill 2>/dev/null || echo " Daemon already stopped"
|
|
62
|
+
echo -e "${GREEN}✓ PM2 daemon killed${NC}"
|
|
63
|
+
else
|
|
64
|
+
echo -e "${YELLOW}⚠ PM2 not found, skipping...${NC}"
|
|
65
|
+
fi
|
|
66
|
+
echo ""
|
|
67
|
+
|
|
68
|
+
# Step 4: Kill remaining PM2 God processes
|
|
69
|
+
echo "[4/7] Cleaning up PM2 God processes..."
|
|
70
|
+
echo "-----------------------------------"
|
|
71
|
+
PM2_PIDS=$(pgrep -f "PM2.*God Daemon" || true)
|
|
72
|
+
if [ -n "$PM2_PIDS" ]; then
|
|
73
|
+
echo "$PM2_PIDS" | xargs -I {} kill -9 {} 2>/dev/null || true
|
|
74
|
+
echo -e "${GREEN}✓ Killed PM2 God processes${NC}"
|
|
75
|
+
else
|
|
76
|
+
echo -e "${GREEN}✓ No PM2 God processes found${NC}"
|
|
77
|
+
fi
|
|
78
|
+
echo ""
|
|
79
|
+
|
|
80
|
+
# Step 5: Remove dump file
|
|
81
|
+
echo "[5/7] Removing PM2 dump file..."
|
|
82
|
+
echo "-----------------------------------"
|
|
83
|
+
DUMP_FILE="$HOME/.pm2/dump.pm2"
|
|
84
|
+
if [ -f "$DUMP_FILE" ]; then
|
|
85
|
+
rm -f "$DUMP_FILE"
|
|
86
|
+
echo -e "${GREEN}✓ Removed dump file${NC}"
|
|
87
|
+
else
|
|
88
|
+
echo -e "${GREEN}✓ No dump file found${NC}"
|
|
89
|
+
fi
|
|
90
|
+
echo ""
|
|
91
|
+
|
|
92
|
+
# Step 6: Kill orphaned bot processes
|
|
93
|
+
echo "[6/7] Cleaning up orphaned bot processes..."
|
|
94
|
+
echo "-----------------------------------"
|
|
95
|
+
BOT_PIDS=$(ps aux | grep "node.*bot.js" | grep -v grep | awk '{print $2}' || true)
|
|
96
|
+
if [ -n "$BOT_PIDS" ]; then
|
|
97
|
+
echo "$BOT_PIDS" | xargs -I {} kill -9 {} 2>/dev/null || true
|
|
98
|
+
echo -e "${GREEN}✓ Killed orphaned bot processes${NC}"
|
|
99
|
+
else
|
|
100
|
+
echo -e "${GREEN}✓ No orphaned bot processes found${NC}"
|
|
101
|
+
fi
|
|
102
|
+
echo ""
|
|
103
|
+
|
|
104
|
+
# Step 7: Verification
|
|
105
|
+
echo "[7/7] Verification..."
|
|
106
|
+
echo "-----------------------------------"
|
|
107
|
+
sleep 1
|
|
108
|
+
|
|
109
|
+
FINAL_PM2_COUNT=$(pgrep -f "PM2.*God Daemon" | wc -l | tr -d ' ' || echo "0")
|
|
110
|
+
FINAL_BOT_COUNT=$(ps aux | grep "node.*bot.js" | grep -v grep | wc -l | tr -d ' ' || echo "0")
|
|
111
|
+
|
|
112
|
+
echo -e "PM2 God Daemons: ${GREEN}${FINAL_PM2_COUNT}${NC} (was ${PM2_COUNT})"
|
|
113
|
+
echo -e "Bot processes: ${GREEN}${FINAL_BOT_COUNT}${NC} (was ${BOT_COUNT})"
|
|
114
|
+
echo ""
|
|
115
|
+
|
|
116
|
+
if [ "$FINAL_PM2_COUNT" -eq 0 ] && [ "$FINAL_BOT_COUNT" -eq 0 ]; then
|
|
117
|
+
echo -e "${GREEN}✅ Cleanup complete! System is clean.${NC}"
|
|
118
|
+
echo ""
|
|
119
|
+
echo "Next steps:"
|
|
120
|
+
echo " 1. Start your bot: pm2 start ecosystem.config.cjs"
|
|
121
|
+
echo " 2. Verify: pm2 list"
|
|
122
|
+
echo " 3. Check logs: pm2 logs --lines 20"
|
|
123
|
+
else
|
|
124
|
+
echo -e "${YELLOW}⚠️ Some processes still running. You may need to:${NC}"
|
|
125
|
+
echo " - Check manually: ps aux | grep bot.js"
|
|
126
|
+
echo " - Kill manually: kill -9 <PID>"
|
|
127
|
+
echo " - Restart terminal/daemon"
|
|
128
|
+
fi
|
|
129
|
+
echo ""
|
|
130
|
+
echo "======================================"
|
package/src/bot.js
CHANGED
|
@@ -24,8 +24,6 @@ import { spawn, execSync } from 'child_process';
|
|
|
24
24
|
import { readFileSync, writeFileSync, existsSync, readdirSync, unlinkSync, mkdirSync, chmodSync } from 'fs';
|
|
25
25
|
import { join } from 'path';
|
|
26
26
|
import { homedir } from 'os';
|
|
27
|
-
import { https } from 'https';
|
|
28
|
-
import { http } from 'http';
|
|
29
27
|
import { createWriteStream } from 'fs';
|
|
30
28
|
|
|
31
29
|
// Import performance monitoring utilities (local)
|
|
@@ -41,6 +39,33 @@ import {
|
|
|
41
39
|
// Import centralized configuration (local, project-specific)
|
|
42
40
|
import config from './core/config.js';
|
|
43
41
|
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// CRITICAL: Check Node.js version compatibility
|
|
44
|
+
// ============================================================================
|
|
45
|
+
const NODE_VERSION = process.version;
|
|
46
|
+
const NODE_MAJOR = parseInt(NODE_VERSION.slice(1).split('.')[0]);
|
|
47
|
+
|
|
48
|
+
if (NODE_MAJOR >= 23) {
|
|
49
|
+
console.error('\n' + '='.repeat(70));
|
|
50
|
+
console.error('⚠️ CRITICAL: Node.js v23+ is not compatible with AgentWindow!');
|
|
51
|
+
console.error('='.repeat(70));
|
|
52
|
+
console.error(`Current version: ${NODE_VERSION}`);
|
|
53
|
+
console.error('Supported versions: Node.js v18 LTS or v20 LTS');
|
|
54
|
+
console.error('\n❌ Issues with Node.js v23:');
|
|
55
|
+
console.error(' - ES module import syntax incompatibility');
|
|
56
|
+
console.error(' - Potential runtime errors with Discord.js');
|
|
57
|
+
console.error(' - Breaking changes in core modules');
|
|
58
|
+
console.error('\n✅ Recommended actions:');
|
|
59
|
+
console.error(' 1. Install Node.js v20 LTS (recommended)');
|
|
60
|
+
console.error(' Using nvm: nvm install 20 && nvm use 20');
|
|
61
|
+
console.error(' Using Homebrew: brew install node@20');
|
|
62
|
+
console.error(' 2. Reinstall global packages: npm install -g agent-window');
|
|
63
|
+
console.error(' 3. Restart your bots');
|
|
64
|
+
console.error('\n📖 See: https://nodejs.org/en/download/releases');
|
|
65
|
+
console.error('='.repeat(70) + '\n');
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
|
|
44
69
|
// Extract commonly used config values for convenience
|
|
45
70
|
const BOT_TOKEN = config.discord.token;
|
|
46
71
|
const PROJECT_DIR = config.workspace.projectDir;
|
|
@@ -1850,11 +1875,52 @@ client.on(Events.MessageCreate, async (message) => {
|
|
|
1850
1875
|
|
|
1851
1876
|
// Ready event
|
|
1852
1877
|
client.on(Events.ClientReady, async () => {
|
|
1878
|
+
// ========================================================================
|
|
1879
|
+
// CRITICAL: Check for duplicate bot instances
|
|
1880
|
+
// ========================================================================
|
|
1881
|
+
try {
|
|
1882
|
+
const { execSync } = await import('child_process');
|
|
1883
|
+
const psCommand = process.platform === 'win32'
|
|
1884
|
+
? 'tasklist | findstr node.exe'
|
|
1885
|
+
: 'ps aux | grep "node.*bot.js" | grep -v grep';
|
|
1886
|
+
|
|
1887
|
+
const result = execSync(psCommand, { encoding: 'utf-8', timeout: 5000 });
|
|
1888
|
+
const botProcesses = result.split('\n').filter(line => line.trim() && line.includes('bot.js'));
|
|
1889
|
+
|
|
1890
|
+
if (botProcesses.length > 1) {
|
|
1891
|
+
console.error('\n' + '='.repeat(70));
|
|
1892
|
+
console.error('⚠️ CRITICAL WARNING: Multiple bot instances detected!');
|
|
1893
|
+
console.error('='.repeat(70));
|
|
1894
|
+
console.error(`Found ${botProcesses.length} bot instances running concurrently.`);
|
|
1895
|
+
console.error('This will cause duplicate responses to every message!');
|
|
1896
|
+
console.error('\n🔍 Running instances:');
|
|
1897
|
+
botProcesses.forEach((proc, i) => {
|
|
1898
|
+
console.error(` ${i + 1}. ${proc.trim()}`);
|
|
1899
|
+
});
|
|
1900
|
+
console.error('\n🔧 To fix this issue:');
|
|
1901
|
+
console.error(' 1. Check running PM2 processes: pm2 list');
|
|
1902
|
+
console.error(' 2. Stop all bots: pm2 stop all && pm2 delete all');
|
|
1903
|
+
console.error(' 3. Kill PM2 daemon: pm2 kill');
|
|
1904
|
+
console.error(' 4. Kill all bot processes: pkill -9 -f "node.*bot.js"');
|
|
1905
|
+
console.error(' 5. Clean dump file: rm -f ~/.pm2/dump.pm2');
|
|
1906
|
+
console.error(' 6. Restart single instance: pm2 start ecosystem.config.cjs');
|
|
1907
|
+
console.error('\n📖 Or use the cleanup script: npm run cleanup-pm2');
|
|
1908
|
+
console.error('='.repeat(70) + '\n');
|
|
1909
|
+
} else {
|
|
1910
|
+
console.log('✓ Instance check: Single bot instance (good)');
|
|
1911
|
+
}
|
|
1912
|
+
} catch (e) {
|
|
1913
|
+
// Command failed (likely no other instances or platform not supported)
|
|
1914
|
+
console.log('✓ Instance check: Passed');
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1853
1917
|
console.log(`AgentBridge logged in as ${client.user.tag}`);
|
|
1854
1918
|
console.log(`Bot User ID: ${client.user.id}`);
|
|
1855
1919
|
console.log(`Project: ${PROJECT_DIR}`);
|
|
1856
|
-
console.log(`Mode: Docker Sandbox + Hooks Permission`);
|
|
1857
|
-
|
|
1920
|
+
console.log(`Mode: ${USE_DOCKER ? 'Docker Sandbox' : 'Local Host'} + Hooks Permission`);
|
|
1921
|
+
if (USE_DOCKER) {
|
|
1922
|
+
console.log(`Container: ${CONTAINER_NAME}`);
|
|
1923
|
+
}
|
|
1858
1924
|
console.log(`OAuth: ${OAUTH_TOKEN ? 'configured' : 'not set'}`);
|
|
1859
1925
|
|
|
1860
1926
|
// Update PM2 and Discord health status
|