@mrtrinhvn/ag-kit 1.1.7 → 1.1.9
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/bin/cli.js +46 -11
- package/package.json +1 -1
- package/template/.agent/scripts/port_utils.sh +67 -0
- package/template/.agent/scripts/receptionist_down.sh +37 -0
- package/template/.agent/scripts/receptionist_up.sh +53 -0
- package/template/.env.example +5 -1
- package/template/scripts/ag_hud.js +162 -0
- package/template/scripts/ag_portal_bridge.js +141 -0
- package/template/start.sh +2 -2
- package/template/stop_bot.sh +2 -2
package/bin/cli.js
CHANGED
|
@@ -1,12 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
2
|
const { program } = require('commander');
|
|
4
3
|
const fs = require('fs');
|
|
5
4
|
const path = require('path');
|
|
5
|
+
const net = require('net');
|
|
6
6
|
|
|
7
7
|
const TEMPLATE_DIR = path.join(__dirname, '..', 'template');
|
|
8
8
|
const TARGET_AGENT_DIR = path.join(process.cwd(), '.agent');
|
|
9
9
|
|
|
10
|
+
function isPortAvailable(port) {
|
|
11
|
+
return new Promise((resolve) => {
|
|
12
|
+
const server = net.createServer();
|
|
13
|
+
server.once('error', () => resolve(false));
|
|
14
|
+
server.once('listening', () => {
|
|
15
|
+
server.close();
|
|
16
|
+
resolve(true);
|
|
17
|
+
});
|
|
18
|
+
server.listen(port, '127.0.0.1');
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function findNextAvailablePort(startPort) {
|
|
23
|
+
let port = startPort;
|
|
24
|
+
while (!(await isPortAvailable(port))) {
|
|
25
|
+
port++;
|
|
26
|
+
}
|
|
27
|
+
return port;
|
|
28
|
+
}
|
|
29
|
+
|
|
10
30
|
// Helper copy đệ quy
|
|
11
31
|
function copyRecursiveSync(src, dest) {
|
|
12
32
|
const exists = fs.existsSync(src);
|
|
@@ -77,18 +97,33 @@ program.command('init')
|
|
|
77
97
|
fs.writeFileSync(path.join(TARGET_AGENT_DIR, '.version'), pkg.version);
|
|
78
98
|
console.log(`\x1b[32m✅ Đã cài ráp thành công thư mục .agent (phiên bản v${pkg.version}) vào Project!\x1b[0m`);
|
|
79
99
|
|
|
80
|
-
// Khởi
|
|
100
|
+
// Khởi động .env nếu chưa có
|
|
81
101
|
const envPath = path.join(process.cwd(), '.env');
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
fs.
|
|
89
|
-
console.log(
|
|
102
|
+
(async () => {
|
|
103
|
+
const idePort = await findNextAvailablePort(9555);
|
|
104
|
+
const bridgePort = await findNextAvailablePort(idePort + 1);
|
|
105
|
+
|
|
106
|
+
if (!fs.existsSync(envPath)) {
|
|
107
|
+
const envTemplate = `# --- Remote Orchestration (Golden Combo) ---\nIDE_PORT=${idePort}\nBRIDGE_PORT=${bridgePort}\n\nPROJECT_NAME=ag-project\n`;
|
|
108
|
+
fs.writeFileSync(envPath, envTemplate);
|
|
109
|
+
console.log(`\x1b[34mℹ️ Đã tạo .env với IDE_PORT=${idePort} và BRIDGE_PORT=${bridgePort}\x1b[0m`);
|
|
110
|
+
} else {
|
|
111
|
+
let envContent = fs.readFileSync(envPath, 'utf-8');
|
|
112
|
+
let changed = false;
|
|
113
|
+
if (!envContent.includes('IDE_PORT=')) {
|
|
114
|
+
envContent += `\nIDE_PORT=${idePort}\n`;
|
|
115
|
+
changed = true;
|
|
116
|
+
}
|
|
117
|
+
if (!envContent.includes('BRIDGE_PORT=')) {
|
|
118
|
+
envContent += `BRIDGE_PORT=${bridgePort}\n`;
|
|
119
|
+
changed = true;
|
|
120
|
+
}
|
|
121
|
+
if (changed) {
|
|
122
|
+
fs.writeFileSync(envPath, envContent);
|
|
123
|
+
console.log(`\x1b[34mℹ️ Đã bổ sung cổng tự động: IDE_PORT=${idePort}, BRIDGE_PORT=${bridgePort}\x1b[0m`);
|
|
124
|
+
}
|
|
90
125
|
}
|
|
91
|
-
}
|
|
126
|
+
})();
|
|
92
127
|
} else {
|
|
93
128
|
console.log('\x1b[33m⚠️ Thư mục .agent đã tồn tại.\x1b[0m');
|
|
94
129
|
const vPath = path.join(TARGET_AGENT_DIR, '.version');
|
package/package.json
CHANGED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# --- Port Management Utility (Golden V4) ---
|
|
4
|
+
# Finds free ports and updates .env to ensure consistent project-wide communication.
|
|
5
|
+
|
|
6
|
+
ENV_FILE=".env"
|
|
7
|
+
|
|
8
|
+
# Logic tìm cổng trống
|
|
9
|
+
function find_free_port() {
|
|
10
|
+
local port=$1
|
|
11
|
+
while netstat -atn | grep -q ":$port "; do
|
|
12
|
+
port=$((port + 1))
|
|
13
|
+
done
|
|
14
|
+
echo $port
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# Cập nhật hoặc thêm cổng vào .env
|
|
18
|
+
function update_env_port() {
|
|
19
|
+
local key=$1
|
|
20
|
+
local value=$2
|
|
21
|
+
|
|
22
|
+
if grep -q "^${key}=" "$ENV_FILE"; then
|
|
23
|
+
# OS-compatible sed (Linux/macOS)
|
|
24
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
25
|
+
sed -i '' "s/^${key}=.*/${key}=${value}/" "$ENV_FILE"
|
|
26
|
+
else
|
|
27
|
+
sed -i "s/^${key}=.*/${key}=${value}/" "$ENV_FILE"
|
|
28
|
+
fi
|
|
29
|
+
else
|
|
30
|
+
echo "${key}=${value}" >> "$ENV_FILE"
|
|
31
|
+
fi
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
# --- Main Logic ---
|
|
35
|
+
# 1. Đọc cổng hiện tại
|
|
36
|
+
if [ -f "$ENV_FILE" ]; then
|
|
37
|
+
source "$ENV_FILE"
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
ORIGINAL_IDE_PORT=${IDE_PORT:-9555}
|
|
41
|
+
ORIGINAL_BRIDGE_PORT=${BRIDGE_PORT:-9556}
|
|
42
|
+
|
|
43
|
+
# 2. Kiểm tra xung đột (IDE_PORT)
|
|
44
|
+
# Nếu cổng IDE bận, và không phải là do IDE của chính dự án này chiếm giữ (kiểm tra qua /json endpoint)
|
|
45
|
+
PORT_TAKEN=false
|
|
46
|
+
if netstat -atn | grep -q ":$ORIGINAL_IDE_PORT "; then
|
|
47
|
+
# Kiểm tra xem folder dự án hiện tại có nằm trong danh sách tab/window của IDE không
|
|
48
|
+
if ! curl -s "http://127.0.0.1:$ORIGINAL_IDE_PORT/json" | grep -q "$PROJECT_DIR" > /dev/null 2>&1; then
|
|
49
|
+
PORT_TAKEN=true
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
if [ "$PORT_TAKEN" = true ]; then
|
|
54
|
+
echo "⚠️ Xung đột PORT phaát hieện! Đang tìm cổng mới..."
|
|
55
|
+
NEW_IDE_PORT=$(find_free_port $ORIGINAL_IDE_PORT)
|
|
56
|
+
NEW_BRIDGE_PORT=$(find_free_port $((NEW_IDE_PORT + 1)))
|
|
57
|
+
|
|
58
|
+
update_env_port "IDE_PORT" "$NEW_IDE_PORT"
|
|
59
|
+
update_env_port "BRIDGE_PORT" "$NEW_BRIDGE_PORT"
|
|
60
|
+
|
|
61
|
+
echo "✅ Đã cập nhật .env: IDE_PORT=$NEW_IDE_PORT, BRIDGE_PORT=$NEW_BRIDGE_PORT"
|
|
62
|
+
export IDE_PORT=$NEW_IDE_PORT
|
|
63
|
+
export BRIDGE_PORT=$NEW_BRIDGE_PORT
|
|
64
|
+
else
|
|
65
|
+
export IDE_PORT=$ORIGINAL_IDE_PORT
|
|
66
|
+
export BRIDGE_PORT=$ORIGINAL_BRIDGE_PORT
|
|
67
|
+
fi
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# --- Antigravity Unified Shutdown (Agent-Defined V3) ---
|
|
4
|
+
# Dọn dẹp trạm gác theo Port Isolation.
|
|
5
|
+
|
|
6
|
+
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
7
|
+
cd "$PROJECT_DIR"
|
|
8
|
+
|
|
9
|
+
if [ -f .env ]; then
|
|
10
|
+
source .env
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
BRIDGE_PORT=${BRIDGE_PORT:-9556}
|
|
14
|
+
|
|
15
|
+
echo "════════════════════════════════════════════════════"
|
|
16
|
+
echo " 🚑 SHUTTING DOWN GATEWAY [$BRIDGE_PORT]..."
|
|
17
|
+
echo "════════════════════════════════════════════════════"
|
|
18
|
+
|
|
19
|
+
# 1. Tắt Portal Bridge (HUD)
|
|
20
|
+
BRIDGE_PID_FILE=".portal_bridge_${BRIDGE_PORT}.pid"
|
|
21
|
+
if [ -f "$BRIDGE_PID_FILE" ]; then
|
|
22
|
+
PID=$(cat "$BRIDGE_PID_FILE")
|
|
23
|
+
echo "[1/2] 🧪 Stopping Portal Bridge [$BRIDGE_PORT] (PID: $PID)..."
|
|
24
|
+
kill $PID 2>/dev/null && rm "$BRIDGE_PID_FILE"
|
|
25
|
+
echo " ✅ Bridge stopped."
|
|
26
|
+
else
|
|
27
|
+
echo "[1/2] 🧪 Portal Bridge on port $BRIDGE_PORT not running."
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# 2. Tắt Docker Backend (Bot)
|
|
31
|
+
echo "[2/2] 🤖 Stopping Receptionist (Docker)..."
|
|
32
|
+
docker compose -f docker-compose.dev.yml stop ck-backend-dev
|
|
33
|
+
echo " ✅ Bot stopped."
|
|
34
|
+
|
|
35
|
+
echo "════════════════════════════════════════════════════"
|
|
36
|
+
echo "✅ SYSTEM IDLE."
|
|
37
|
+
echo "════════════════════════════════════════════════════"
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# --- Antigravity Unified Receptionist (Agent-Defined V4) ---
|
|
4
|
+
# Trạm gác hợp nhất: Bot + Portal Bridge (HUD) + Monitor Dashboard.
|
|
5
|
+
# Hỗ trợ Đa dự án & Tự động xử lý Cổng (Smart Port Orchestration).
|
|
6
|
+
|
|
7
|
+
# 1. Load Cấu hình & Xử lý Cổng Thông minh
|
|
8
|
+
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
9
|
+
cd "$PROJECT_DIR"
|
|
10
|
+
|
|
11
|
+
if [ -f .agent/scripts/port_utils.sh ]; then
|
|
12
|
+
source .agent/scripts/port_utils.sh
|
|
13
|
+
else
|
|
14
|
+
source .env
|
|
15
|
+
export IDE_PORT=${IDE_PORT:-9555}
|
|
16
|
+
export BRIDGE_PORT=${BRIDGE_PORT:-9556}
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
echo "════════════════════════════════════════════════════"
|
|
20
|
+
echo " 🚑 AGENTIC GATEWAY - PORTAL [$BRIDGE_PORT]"
|
|
21
|
+
echo "════════════════════════════════════════════════════"
|
|
22
|
+
|
|
23
|
+
# 1. Kiểm tra Cổng IDE (CDP)
|
|
24
|
+
echo -n "[1/4] 🛰️ Checking IDE Portal (Port $IDE_PORT)... "
|
|
25
|
+
if curl -s http://127.0.0.1:$IDE_PORT/json/version > /dev/null; then
|
|
26
|
+
echo "✅ READY."
|
|
27
|
+
else
|
|
28
|
+
echo "❌ NOT FOUND."
|
|
29
|
+
echo " 👉 Please start Antigravity in Debug mode on port $IDE_PORT"
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# 2. Khởi động Portal Bridge (HUD Injector)
|
|
33
|
+
echo "[2/4] 🧪 Injected Golden HUD Bridge... "
|
|
34
|
+
BRIDGE_PID_FILE=".portal_bridge_${BRIDGE_PORT}.pid"
|
|
35
|
+
|
|
36
|
+
# Tắt bridge cũ nếu đang chạy trên port này
|
|
37
|
+
if [ -f "$BRIDGE_PID_FILE" ]; then
|
|
38
|
+
kill $(cat "$BRIDGE_PID_FILE") 2>/dev/null
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
nohup node scripts/ag_portal_bridge.js > ".portal_bridge_${BRIDGE_PORT}.log" 2>&1 &
|
|
42
|
+
echo $! > "$BRIDGE_PID_FILE"
|
|
43
|
+
echo " ✅ Bridge running (PID: $(cat "$BRIDGE_PID_FILE") on Port $BRIDGE_PORT)"
|
|
44
|
+
|
|
45
|
+
# 3. Khởi động Bot (Tùy chỉnh theo dự án)
|
|
46
|
+
echo "[3/4] 🤖 Waking up Agent Bot... "
|
|
47
|
+
# [TEMPLATE_NOTE]: Sếp hãy gõ lệnh khởi động Bot của mình vào đây.
|
|
48
|
+
# Ví dụ: docker compose up -d (nếu dùng docker) hoặc npx tsx src/index.ts (nếu dùng local)
|
|
49
|
+
echo " ⚠️ Vui lòng cấu hình lệnh khởi động Bot trong .agent/scripts/receptionist_up.sh"
|
|
50
|
+
|
|
51
|
+
# 4. Monitor
|
|
52
|
+
echo "[4/4] 📊 Ready."
|
|
53
|
+
echo "----------------------------------------------------"
|
package/template/.env.example
CHANGED
|
@@ -12,11 +12,15 @@ ALLOWED_USER_IDS="123456789,987654321"
|
|
|
12
12
|
# ID Chat/Group được phép hoạt động (Để tránh Bot bị kéo vào group lạ)
|
|
13
13
|
ALLOWED_CHAT_IDS="-100123456789"
|
|
14
14
|
|
|
15
|
-
# [Cấu Hình IDE]
|
|
15
|
+
# [Cấu Hình IDE & Remote]
|
|
16
16
|
# Cổng Debug của Antigravity (Mặc định là 9555)
|
|
17
17
|
# Phải khớp với tham số --remote-debugging-port khi mở Editor
|
|
18
18
|
IDE_PORT=9555
|
|
19
19
|
|
|
20
|
+
# Cổng của Portal Bridge (Mặc định là 9556)
|
|
21
|
+
# Phải khớp với script start.sh và bot callback
|
|
22
|
+
BRIDGE_PORT=9556
|
|
23
|
+
|
|
20
24
|
# Tên dự án để Bot tự động tìm kiếm target phù hợp trong CDP
|
|
21
25
|
PROJECT_NAME="ceogravity"
|
|
22
26
|
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity Golden HUD - Medical/Trading Theme
|
|
3
|
+
* Purpose: Inject a premium status dashboard into the IDE.
|
|
4
|
+
*/
|
|
5
|
+
export const AG_HUD_JS = `(async () => {
|
|
6
|
+
const HUD_ID = 'antigravity-golden-hud';
|
|
7
|
+
if (document.getElementById(HUD_ID)) return "ALREADY_EXISTS";
|
|
8
|
+
|
|
9
|
+
// 1. Create Styles
|
|
10
|
+
const style = document.createElement('style');
|
|
11
|
+
style.innerHTML = \`
|
|
12
|
+
#\${HUD_ID} {
|
|
13
|
+
position: fixed;
|
|
14
|
+
top: 15px;
|
|
15
|
+
right: 15px;
|
|
16
|
+
z-index: 999999;
|
|
17
|
+
background: rgba(10, 10, 10, 0.85);
|
|
18
|
+
backdrop-filter: blur(12px);
|
|
19
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
20
|
+
border-radius: 12px;
|
|
21
|
+
padding: 12px;
|
|
22
|
+
width: 280px;
|
|
23
|
+
color: #fff;
|
|
24
|
+
font-family: 'Inter', system-ui, sans-serif;
|
|
25
|
+
box-shadow: 0 8px 32px rgba(0,0,0,0.5);
|
|
26
|
+
transition: all 0.3s ease;
|
|
27
|
+
user-select: none;
|
|
28
|
+
}
|
|
29
|
+
#\${HUD_ID}:hover {
|
|
30
|
+
border-color: #4caf50;
|
|
31
|
+
box-shadow: 0 0 20px rgba(76, 175, 80, 0.2);
|
|
32
|
+
}
|
|
33
|
+
#\${HUD_ID} .header {
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: center;
|
|
36
|
+
justify-content: space-between;
|
|
37
|
+
margin-bottom: 10px;
|
|
38
|
+
font-weight: 700;
|
|
39
|
+
letter-spacing: 0.5px;
|
|
40
|
+
}
|
|
41
|
+
#\${HUD_ID} .status-dot {
|
|
42
|
+
width: 8px;
|
|
43
|
+
height: 8px;
|
|
44
|
+
border-radius: 50%;
|
|
45
|
+
background: #4caf50;
|
|
46
|
+
display: inline-block;
|
|
47
|
+
margin-right: 6px;
|
|
48
|
+
animation: pulse 2s infinite;
|
|
49
|
+
}
|
|
50
|
+
@keyframes pulse {
|
|
51
|
+
0% { transform: scale(1); opacity: 1; }
|
|
52
|
+
50% { transform: scale(1.5); opacity: 0.5; }
|
|
53
|
+
100% { transform: scale(1); opacity: 1; }
|
|
54
|
+
}
|
|
55
|
+
#\${HUD_ID} .metric {
|
|
56
|
+
display: flex;
|
|
57
|
+
justify-content: space-between;
|
|
58
|
+
font-size: 12px;
|
|
59
|
+
margin-bottom: 6px;
|
|
60
|
+
color: #ccc;
|
|
61
|
+
}
|
|
62
|
+
#\${HUD_ID} .metric b { color: #fff; }
|
|
63
|
+
#\${HUD_ID} .action-btn {
|
|
64
|
+
background: #1a1a1a;
|
|
65
|
+
border: 1px solid #333;
|
|
66
|
+
color: #4caf50;
|
|
67
|
+
font-size: 11px;
|
|
68
|
+
padding: 6px;
|
|
69
|
+
border-radius: 6px;
|
|
70
|
+
width: 100%;
|
|
71
|
+
margin-top: 8px;
|
|
72
|
+
cursor: pointer;
|
|
73
|
+
text-align: center;
|
|
74
|
+
font-weight: 600;
|
|
75
|
+
transition: all 0.2s;
|
|
76
|
+
}
|
|
77
|
+
#\${HUD_ID} .action-btn:hover {
|
|
78
|
+
background: #4caf50;
|
|
79
|
+
color: #000;
|
|
80
|
+
}
|
|
81
|
+
#\${HUD_ID} .surgery-alert {
|
|
82
|
+
background: rgba(244, 67, 54, 0.2);
|
|
83
|
+
border: 1px solid #f44336;
|
|
84
|
+
color: #f44336;
|
|
85
|
+
padding: 8px;
|
|
86
|
+
border-radius: 8px;
|
|
87
|
+
font-size: 11px;
|
|
88
|
+
margin-top: 10px;
|
|
89
|
+
display: none;
|
|
90
|
+
animation: shake 0.5s infinite;
|
|
91
|
+
}
|
|
92
|
+
@keyframes shake {
|
|
93
|
+
0% { transform: translateX(0); }
|
|
94
|
+
25% { transform: translateX(2px); }
|
|
95
|
+
50% { transform: translateX(0); }
|
|
96
|
+
75% { transform: translateX(-2px); }
|
|
97
|
+
100% { transform: translateX(0); }
|
|
98
|
+
}
|
|
99
|
+
\`;
|
|
100
|
+
document.head.appendChild(style);
|
|
101
|
+
|
|
102
|
+
// 2. Create UI
|
|
103
|
+
const hud = document.createElement('div');
|
|
104
|
+
hud.id = HUD_ID;
|
|
105
|
+
hud.innerHTML = \`
|
|
106
|
+
<div class="header">
|
|
107
|
+
<span>🧠 CORE AGENT B1</span>
|
|
108
|
+
<span id="ag-status"><span class="status-dot"></span>ONLINE</span>
|
|
109
|
+
</div>
|
|
110
|
+
<div class="metric">AI Evolution: <b id="ag-gen">GEN-439</b></div>
|
|
111
|
+
<div class="metric">Win Rate: <b id="ag-win">47.7%</b></div>
|
|
112
|
+
<div class="metric">Current Phase: <b id="ag-phase">5m VSA Trading</b></div>
|
|
113
|
+
|
|
114
|
+
<div class="surgery-alert" id="ag-alert">
|
|
115
|
+
🛑 <b>DOCTOR CALL REQUIRED!</b><br>AI Learning Stalled. Surgery needed.
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div id="ag-toast" style="display:none; background:rgba(33, 150, 243, 0.9); color:#fff; padding:8px; border-radius:8px; margin-top:10px; font-size:11px; border-left:4px solid #0d47a1; backdrop-filter: blur(8px); box-shadow: 0 4px 12px rgba(0,0,0,0.3);">
|
|
119
|
+
<b>💬 TELEGRAM:</b> <span id="ag-toast-msg"></span>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<div class="action-btn" id="ag-btn-surgery">🏥 START BRAIN SURGERY</div>
|
|
123
|
+
\`;
|
|
124
|
+
document.body.appendChild(hud);
|
|
125
|
+
|
|
126
|
+
// 3. Logic to update from Bridge
|
|
127
|
+
window.addEventListener('ag-portal-update', (e) => {
|
|
128
|
+
const data = e.detail;
|
|
129
|
+
if (data.gen) document.getElementById('ag-gen').innerText = data.gen;
|
|
130
|
+
if (data.win) document.getElementById('ag-win').innerText = data.win;
|
|
131
|
+
if (data.phase) document.getElementById('ag-phase').innerText = data.phase;
|
|
132
|
+
|
|
133
|
+
const alert = document.getElementById('ag-alert');
|
|
134
|
+
if (data.status === 'DOCTOR_REQUIRED' || data.status === 'STALLED') {
|
|
135
|
+
alert.style.display = 'block';
|
|
136
|
+
document.getElementById('ag-status').innerHTML = '<span class="status-dot" style="background:#f44336"></span>REPAIR';
|
|
137
|
+
} else {
|
|
138
|
+
alert.style.display = 'none';
|
|
139
|
+
document.getElementById('ag-status').innerHTML = '<span class="status-dot" style="background:#4caf50"></span>ONLINE';
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
window.addEventListener('ag-portal-alert', (e) => {
|
|
144
|
+
const data = e.detail;
|
|
145
|
+
const toast = document.getElementById('ag-toast');
|
|
146
|
+
const toastMsg = document.getElementById('ag-toast-msg');
|
|
147
|
+
|
|
148
|
+
toastMsg.innerText = data.message || "New message from Telegram.";
|
|
149
|
+
toast.style.display = 'block';
|
|
150
|
+
if (data.color) toast.style.background = data.color;
|
|
151
|
+
|
|
152
|
+
// Auto-hide after 10 seconds
|
|
153
|
+
setTimeout(() => { toast.style.display = 'none'; }, 10000);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
document.getElementById('ag-btn-surgery').onclick = () => {
|
|
157
|
+
console.log("AG_PORTAL_ACTION:START_SURGERY");
|
|
158
|
+
document.getElementById('ag-btn-surgery').innerText = "🚑 REQUESTING SURGEON...";
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
return "GOLDEN_HUD_INJECTED";
|
|
162
|
+
})()`;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import WebSocket from 'ws';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import fetch from 'node-fetch';
|
|
5
|
+
import http from 'http';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import dotenv from 'dotenv';
|
|
8
|
+
|
|
9
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
dotenv.config({ path: path.join(__dirname, '../.env') });
|
|
11
|
+
|
|
12
|
+
const HUD_JS_FILE = path.join(__dirname, 'ag_hud.js');
|
|
13
|
+
const STATE_FILE = path.join(__dirname, '../backend/data/ai_state.json');
|
|
14
|
+
const REQUEST_FILE = path.join(__dirname, '../backend/data/remote_requests.json');
|
|
15
|
+
const IDE_PORT = process.env.IDE_PORT || 9555;
|
|
16
|
+
const BRIDGE_PORT = process.env.BRIDGE_PORT || 9556;
|
|
17
|
+
|
|
18
|
+
let globalWs = null;
|
|
19
|
+
|
|
20
|
+
async function getWsUrl() {
|
|
21
|
+
try {
|
|
22
|
+
const resp = await fetch(`http://127.0.0.1:${IDE_PORT}/json/version`);
|
|
23
|
+
const data = await resp.json();
|
|
24
|
+
return data.webSocketDebuggerUrl;
|
|
25
|
+
} catch (err) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function injectHud(ws) {
|
|
31
|
+
const hudJsContent = fs.readFileSync(HUD_JS_FILE, 'utf8');
|
|
32
|
+
const script = hudJsContent.match(/export const AG_HUD_JS = `([\s\S]*)`;/)[1];
|
|
33
|
+
|
|
34
|
+
const message = {
|
|
35
|
+
id: 1,
|
|
36
|
+
method: "Runtime.evaluate",
|
|
37
|
+
params: {
|
|
38
|
+
expression: script,
|
|
39
|
+
awaitPromise: true,
|
|
40
|
+
userGesture: true
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
ws.send(JSON.stringify(message));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function updateHud(ws, state) {
|
|
47
|
+
const updateEvent = {
|
|
48
|
+
id: Date.now(),
|
|
49
|
+
method: "Runtime.evaluate",
|
|
50
|
+
params: {
|
|
51
|
+
expression: `window.dispatchEvent(new CustomEvent('ag-portal-update', { detail: ${JSON.stringify(state)} }));`
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
ws.send(JSON.stringify(updateEvent));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function pushInstantAlert(ws, alertData) {
|
|
58
|
+
const alertEvent = {
|
|
59
|
+
id: Date.now(),
|
|
60
|
+
method: "Runtime.evaluate",
|
|
61
|
+
params: {
|
|
62
|
+
expression: `window.dispatchEvent(new CustomEvent('ag-portal-alert', { detail: ${JSON.stringify(alertData)} }));`
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
ws.send(JSON.stringify(alertEvent));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function startHttpServer() {
|
|
69
|
+
const server = http.createServer((req, res) => {
|
|
70
|
+
if (req.method === 'POST' && (req.url === '/alert' || req.url === '/update')) {
|
|
71
|
+
let body = '';
|
|
72
|
+
req.on('data', chunk => { body += chunk; });
|
|
73
|
+
req.on('end', async () => {
|
|
74
|
+
try {
|
|
75
|
+
const data = JSON.parse(body);
|
|
76
|
+
if (globalWs && globalWs.readyState === WebSocket.OPEN) {
|
|
77
|
+
if (req.url === '/alert') {
|
|
78
|
+
await pushInstantAlert(globalWs, data);
|
|
79
|
+
} else {
|
|
80
|
+
await updateHud(globalWs, data);
|
|
81
|
+
}
|
|
82
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
83
|
+
res.end(JSON.stringify({ status: 'ok' }));
|
|
84
|
+
} else {
|
|
85
|
+
res.writeHead(503, { 'Content-Type': 'application/json' });
|
|
86
|
+
res.end(JSON.stringify({ error: 'Bridge not connected to IDE' }));
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
90
|
+
res.end(JSON.stringify({ error: 'Invalid JSON' }));
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
} else {
|
|
94
|
+
res.writeHead(404);
|
|
95
|
+
res.end();
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
server.listen(BRIDGE_PORT, '0.0.0.0', () => {
|
|
100
|
+
console.log(`📡 Instant Alert Server listening on port ${BRIDGE_PORT}`);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function startBridge() {
|
|
105
|
+
console.log(`🛰️ Connecting to Antigravity Portal on port ${IDE_PORT}...`);
|
|
106
|
+
|
|
107
|
+
const wsUrl = await getWsUrl();
|
|
108
|
+
if (!wsUrl) {
|
|
109
|
+
console.log("❌ IDE is not running or port 9555 is closed.");
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const ws = new WebSocket(wsUrl);
|
|
114
|
+
globalWs = ws;
|
|
115
|
+
|
|
116
|
+
ws.on('open', async () => {
|
|
117
|
+
console.log("✅ Bridge Established. Injecting Golden HUD...");
|
|
118
|
+
await injectHud(ws);
|
|
119
|
+
|
|
120
|
+
// Start HTTP server for instant pushes
|
|
121
|
+
startHttpServer();
|
|
122
|
+
|
|
123
|
+
// Background polling for legacy state compatibility
|
|
124
|
+
setInterval(async () => {
|
|
125
|
+
if (fs.existsSync(STATE_FILE)) {
|
|
126
|
+
const state = JSON.parse(fs.readFileSync(STATE_FILE, 'utf8'));
|
|
127
|
+
await updateHud(ws, state);
|
|
128
|
+
}
|
|
129
|
+
}, 5000);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
ws.on('message', (data) => {
|
|
133
|
+
const msg = JSON.parse(data);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
ws.on('error', (err) => {
|
|
137
|
+
console.error("❌ WS Error:", err);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
startBridge();
|
package/template/start.sh
CHANGED
|
@@ -17,6 +17,6 @@ if [ $? -ne 0 ]; then
|
|
|
17
17
|
echo "⚠️ Cảnh báo: Cổng CDP ${IDE_PORT:-9555} chưa mở. Đang chờ Antigravity khởi động..."
|
|
18
18
|
fi
|
|
19
19
|
|
|
20
|
-
# 4. Khởi động Bridge và Bot (
|
|
20
|
+
# 4. Khởi động Bridge và Bot (Agent-Defined)
|
|
21
21
|
echo "🚀 Khởi động Lễ tân trực chiến (Agentic Gateway)..."
|
|
22
|
-
|
|
22
|
+
bash .agent/scripts/receptionist_up.sh
|
package/template/stop_bot.sh
CHANGED