fix: 品牌保护+知识库全量覆盖 - 6层防御解决传销问题 + 30+产品关键词补全
This commit is contained in:
18
mcp-server-ssh/check_current.cjs
Normal file
18
mcp-server-ssh/check_current.cjs
Normal file
@@ -0,0 +1,18 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== LAST 200 LINES server-out.log ==='",
|
||||
"tail -200 /var/log/bigwo/server-out.log",
|
||||
"echo ''",
|
||||
"echo '=== LAST 50 LINES server-error.log ==='",
|
||||
"tail -50 /var/log/bigwo/server-error.log 2>/dev/null || echo 'no error log'",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
23
mcp-server-ssh/check_double_msg.cjs
Normal file
23
mcp-server-ssh/check_double_msg.cjs
Normal file
@@ -0,0 +1,23 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== LATEST SESSION FULL EVENTS ==='",
|
||||
"LAST_SID=$(grep 'processReply start' /var/log/bigwo/server-out.log | tail -1 | grep -oP 'session=\\K[^ ]+')",
|
||||
"echo \"Session: $LAST_SID\"",
|
||||
"grep \"$LAST_SID\" /var/log/bigwo/server-out.log | grep -v 'partial' | head -60",
|
||||
"echo ''",
|
||||
"echo '=== 公司产品 SESSION EVENTS ==='",
|
||||
"grep '我们公司的产品\\|公司的产品' /var/log/bigwo/server-out.log | tail -5",
|
||||
"echo ''",
|
||||
"echo '=== EVENT 550/559/351 FOR LATEST SESSION ==='",
|
||||
"grep \"$LAST_SID\" /var/log/bigwo/server-out.log | grep -E 'upstream assistant|flush|persistAssistant|subtitle.*assistant' | tail -20",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
11
mcp-server-ssh/check_dual_reply.cjs
Normal file
11
mcp-server-ssh/check_dual_reply.cjs
Normal file
@@ -0,0 +1,11 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
c.exec('grep -E "processReply|upstream assistant|persistAssistant|SayHello|polishForSpeech|local_tts|delivery|blockUpstream|suppress" /var/log/bigwo/server-out.log | tail -50', (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
17
mcp-server-ssh/check_dual_reply2.cjs
Normal file
17
mcp-server-ssh/check_dual_reply2.cjs
Normal file
@@ -0,0 +1,17 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== LATEST SESSION FULL LOG ==='",
|
||||
"LAST_SID=$(grep 'upstream ready' /var/log/bigwo/server-out.log | tail -1 | grep -oP 'session=\\K[^ ]+')",
|
||||
"echo \"Session: $LAST_SID\"",
|
||||
"grep \"$LAST_SID\" /var/log/bigwo/server-out.log | head -80",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
16
mcp-server-ssh/check_dual_reply3.cjs
Normal file
16
mcp-server-ssh/check_dual_reply3.cjs
Normal file
@@ -0,0 +1,16 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"LAST_SID=$(grep 'upstream ready' /var/log/bigwo/server-out.log | tail -1 | grep -oP 'session=\\K[^ ]+')",
|
||||
"echo \"Session: $LAST_SID\"",
|
||||
"grep \"$LAST_SID\" /var/log/bigwo/server-out.log | grep -E 'processReply|upstream assistant|persistAssist|suppress|blockUpstream|delivery|local_tts|unblock|tts_event|event.*550|event.*351|event.*559|barge|chunk' | tail -40",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
16
mcp-server-ssh/check_dual_reply4.cjs
Normal file
16
mcp-server-ssh/check_dual_reply4.cjs
Normal file
@@ -0,0 +1,16 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"LAST_SID=$(grep 'upstream ready' /var/log/bigwo/server-out.log | tail -1 | grep -oP 'session=\\K[^ ]+')",
|
||||
"echo \"Session: $LAST_SID\"",
|
||||
"grep \"$LAST_SID\" /var/log/bigwo/server-out.log | grep -v 'upstream partial' | tail -40",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
24
mcp-server-ssh/check_env.cjs
Normal file
24
mcp-server-ssh/check_env.cjs
Normal file
@@ -0,0 +1,24 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== S2S ENV ==='",
|
||||
"grep -E '^VOLC_S2S|^VOLC_DIALOG' /www/wwwroot/demo.tensorgrove.com.cn/server/.env | sed 's/=.*/=***MASKED***/'",
|
||||
"echo ''",
|
||||
"echo '=== ALL VOLC ENV KEYS ==='",
|
||||
"grep '^VOLC_' /www/wwwroot/demo.tensorgrove.com.cn/server/.env | sed 's/=.*/=.../'",
|
||||
"echo ''",
|
||||
"echo '=== SESSIONS AFTER DEPLOY (17:06) ==='",
|
||||
"awk '/17:0[6-9]|17:[1-5]/' /var/log/bigwo/server-out.log | grep -E 'upstream ready|upstream error|upstream closed|quota' | tail -10",
|
||||
"echo ''",
|
||||
"echo '=== HEALTH ==='",
|
||||
"curl -s http://127.0.0.1:3012/api/health 2>&1",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
11
mcp-server-ssh/check_greeting.cjs
Normal file
11
mcp-server-ssh/check_greeting.cjs
Normal file
@@ -0,0 +1,11 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
c.exec('tail -200 /var/log/bigwo/server-out.log | grep -iE "sendGreeting|replayGreeting|sendSpeechText|upstream ready|tts_event|upstream closed|greeting|ready"', (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
11
mcp-server-ssh/check_greeting2.cjs
Normal file
11
mcp-server-ssh/check_greeting2.cjs
Normal file
@@ -0,0 +1,11 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
c.exec('grep -E "sendGreeting|replayGreeting|upstream ready|greeting|readySent" /var/log/bigwo/server-out.log | tail -30', (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
11
mcp-server-ssh/check_greeting3.cjs
Normal file
11
mcp-server-ssh/check_greeting3.cjs
Normal file
@@ -0,0 +1,11 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
c.exec('grep "mmsuckxe" /var/log/bigwo/server-out.log | head -60', (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
21
mcp-server-ssh/check_greeting4.cjs
Normal file
21
mcp-server-ssh/check_greeting4.cjs
Normal file
@@ -0,0 +1,21 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
// Get the last session's full greeting timeline + audio forwarding evidence
|
||||
const cmd = [
|
||||
"echo '=== GREETING LOGS ==='",
|
||||
"grep -E 'sendGreeting|replayGreeting|sendSpeechText|tts_event|tts_reset|audio block|upstream ready' /var/log/bigwo/server-out.log | tail -30",
|
||||
"echo ''",
|
||||
"echo '=== LAST SESSION FULL LOG (first 40 lines) ==='",
|
||||
"LAST_SID=$(grep 'upstream ready' /var/log/bigwo/server-out.log | tail -1 | grep -oP 'session=\\K[^ ]+')",
|
||||
"echo \"Session: $LAST_SID\"",
|
||||
"grep \"$LAST_SID\" /var/log/bigwo/server-out.log | head -40",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
21
mcp-server-ssh/check_health.cjs
Normal file
21
mcp-server-ssh/check_health.cjs
Normal file
@@ -0,0 +1,21 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== HEALTH CHECK ==='",
|
||||
"curl -s http://127.0.0.1:3012/api/health 2>&1",
|
||||
"echo ''",
|
||||
"echo '=== PM2 STATUS ==='",
|
||||
"pm2 list 2>/dev/null",
|
||||
"echo ''",
|
||||
"echo '=== LAST 5 LINES ==='",
|
||||
"tail -5 /var/log/bigwo/server-out.log",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
24
mcp-server-ssh/check_kb_env.cjs
Normal file
24
mcp-server-ssh/check_kb_env.cjs
Normal file
@@ -0,0 +1,24 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== ENV KB CONFIG ==='",
|
||||
"grep -E 'VOLC_ARK_ENDPOINT_ID|VOLC_ARK_KNOWLEDGE|VOLC_ARK_API_KEY|VOLC_ACCESS_KEY' /www/wwwroot/demo.tensorgrove.com.cn/server/.env | sed 's/=.\\{8\\}/=***REDACTED/g'",
|
||||
"echo ''",
|
||||
"echo '=== RECENT KB LOGS (last 500 lines) ==='",
|
||||
"tail -500 /var/log/bigwo/server-out.log | grep -E 'ToolExecutor|searchKnowledge|Ark KB|knowledge|processReply start|processReply handoff|external_rag|tts_reset|blockUpstream|unblock|barge-in|upstream assistant|upstream final|upstream partial'",
|
||||
"echo ''",
|
||||
"echo '=== RECENT ERROR LOGS ==='",
|
||||
"tail -100 /var/log/bigwo/server-error.log 2>/dev/null | grep -E 'ToolExecutor|Ark|knowledge|timeout|quota' | tail -20",
|
||||
"echo ''",
|
||||
"echo '=== PM2 STATUS ==='",
|
||||
"pm2 list 2>/dev/null || echo 'pm2 not found'",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
21
mcp-server-ssh/check_kb_issue.cjs
Normal file
21
mcp-server-ssh/check_kb_issue.cjs
Normal file
@@ -0,0 +1,21 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== RECENT KB RELATED LOGS ==='",
|
||||
"grep -E 'searchKnowledge|Ark KB|rewritten|classifyKnowledge|tryKnowledge|shouldForce|Chat.*User|Chat.*Assistant|基础三合一|三合一|胡辣汤' /var/log/bigwo/server-out.log | tail -80",
|
||||
"echo ''",
|
||||
"echo '=== RECENT CHAT LOGS ==='",
|
||||
"grep -E '\\[Chat\\]' /var/log/bigwo/server-out.log | tail -30",
|
||||
"echo ''",
|
||||
"echo '=== RECENT ERRORS ==='",
|
||||
"grep -iE 'error|failed|timeout' /var/log/bigwo/server-out.log | tail -20",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
27
mcp-server-ssh/check_kb_issue2.cjs
Normal file
27
mcp-server-ssh/check_kb_issue2.cjs
Normal file
@@ -0,0 +1,27 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== LAST 50 CHAT LOGS ==='",
|
||||
"grep '\\[Chat\\]' /var/log/bigwo/server-out.log | tail -50",
|
||||
"echo ''",
|
||||
"echo '=== LAST 30 TOOLEXECUTOR LOGS ==='",
|
||||
"grep '\\[ToolExecutor\\]' /var/log/bigwo/server-out.log | tail -30",
|
||||
"echo ''",
|
||||
"echo '=== LAST 20 COZE LOGS ==='",
|
||||
"grep '\\[CozeChat\\]' /var/log/bigwo/server-out.log | tail -20",
|
||||
"echo ''",
|
||||
"echo '=== LAST 20 ARK LOGS ==='",
|
||||
"grep '\\[ArkChat\\]' /var/log/bigwo/server-out.log | tail -20",
|
||||
"echo ''",
|
||||
"echo '=== .env KB CONFIG ==='",
|
||||
"grep -E 'VOLC_ARK_KNOWLEDGE|VOLC_ARK_ENDPOINT|VOLC_ARK_API_KEY|COZE_' /www/wwwroot/demo.tensorgrove.com.cn/server/.env | sed 's/=.\\{12\\}/=***REDACTED/g'",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
24
mcp-server-ssh/check_kb_issue3.cjs
Normal file
24
mcp-server-ssh/check_kb_issue3.cjs
Normal file
@@ -0,0 +1,24 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== LAST 100 LINES WITH CHAT/KB ==='",
|
||||
"grep -E '\\[Chat\\]|\\[ToolExecutor\\]|\\[CozeChat\\]|\\[ArkChat\\]|\\[POST\\]|\\[GET\\]' /var/log/bigwo/server-out.log | tail -100",
|
||||
"echo ''",
|
||||
"echo '=== SEARCH FOR 胡辣汤 ==='",
|
||||
"grep -i '胡辣汤' /var/log/bigwo/server-out.log | tail -10",
|
||||
"echo ''",
|
||||
"echo '=== SEARCH FOR 基础三合一 ==='",
|
||||
"grep -i '基础三合一\\|基础套装' /var/log/bigwo/server-out.log | tail -20",
|
||||
"echo ''",
|
||||
"echo '=== MOST RECENT 50 LINES ==='",
|
||||
"tail -50 /var/log/bigwo/server-out.log",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
16
mcp-server-ssh/check_latency.cjs
Normal file
16
mcp-server-ssh/check_latency.cjs
Normal file
@@ -0,0 +1,16 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"LAST_SID=$(grep 'upstream ready' /var/log/bigwo/server-out.log | tail -1 | grep -oP 'session=\\K[^ ]+')",
|
||||
"echo \"Session: $LAST_SID\"",
|
||||
"grep \"$LAST_SID\" /var/log/bigwo/server-out.log | grep -v 'upstream partial' | grep -v 'upstream assistant chunk'",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
16
mcp-server-ssh/check_latency2.cjs
Normal file
16
mcp-server-ssh/check_latency2.cjs
Normal file
@@ -0,0 +1,16 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"LAST_SID=$(grep 'upstream ready' /var/log/bigwo/server-out.log | tail -1 | grep -oP 'session=\\K[^ ]+')",
|
||||
"echo \"Session: $LAST_SID\"",
|
||||
"grep \"$LAST_SID\" /var/log/bigwo/server-out.log | grep -v 'upstream partial' | grep -v 'upstream assistant chunk'",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
12
mcp-server-ssh/check_logs.cjs
Normal file
12
mcp-server-ssh/check_logs.cjs
Normal file
@@ -0,0 +1,12 @@
|
||||
const { Client } = require("ssh2");
|
||||
const c = new Client();
|
||||
c.on("ready", () => {
|
||||
// 搜索包含"产品"的日志行,以及 processReply/handoff 相关行
|
||||
c.exec('tail -50 /var/log/bigwo/server-out.log | grep -E "greeting|upstream|tts_event|assistant|rag|ready|error"', (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = "";
|
||||
s.on("data", (d) => (o += d));
|
||||
s.stderr.on("data", (d) => (o += d));
|
||||
s.on("close", () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: "119.45.10.34", port: 22, username: "root", password: "#xyzh%CS#2512@28" });
|
||||
30
mcp-server-ssh/check_quota.cjs
Normal file
30
mcp-server-ssh/check_quota.cjs
Normal file
@@ -0,0 +1,30 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== ALL QUOTA ERRORS ==='",
|
||||
"grep -i 'quota exceeded' /var/log/bigwo/server-out.log | tail -20",
|
||||
"echo ''",
|
||||
"echo '=== QUOTA ERROR DETAILS (full payload) ==='",
|
||||
"grep -i 'quota exceeded' /var/log/bigwo/server-out.log | tail -5 | grep -oP 'payload=\\K.*'",
|
||||
"echo ''",
|
||||
"echo '=== S2S ENV CONFIG ==='",
|
||||
"grep -E 'VOLC_S2S|VOLC_DIALOG|VOLC_RTC|VOLC_ACCESS' /www/wwwroot/demo.tensorgrove.com.cn/server/.env",
|
||||
"echo ''",
|
||||
"echo '=== RECENT UPSTREAM CONNECTIONS ==='",
|
||||
"grep -E 'upstream ready|upstream closed|upstream error|createUpstream' /var/log/bigwo/server-out.log | tail -20",
|
||||
"echo ''",
|
||||
"echo '=== LAST ERROR LOG TIMESTAMPS ==='",
|
||||
"grep -i 'quota exceeded' /var/log/bigwo/server-error.log | tail -5",
|
||||
"echo ''",
|
||||
"echo '=== TRY FRESH CONNECTION TEST ==='",
|
||||
"curl -s http://127.0.0.1:3012/api/health 2>&1",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
30
mcp-server-ssh/check_quota2.cjs
Normal file
30
mcp-server-ssh/check_quota2.cjs
Normal file
@@ -0,0 +1,30 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== S2S ENV CONFIG (full) ==='",
|
||||
"grep -E 'VOLC_S2S|VOLC_DIALOG|VOLC_RTC|VOLC_ACCESS' /www/wwwroot/demo.tensorgrove.com.cn/server/.env",
|
||||
"echo ''",
|
||||
"echo '=== ALL QUOTA ERRORS in server-error.log ==='",
|
||||
"grep -i 'quota' /var/log/bigwo/server-error.log 2>/dev/null | tail -10",
|
||||
"echo ''",
|
||||
"echo '=== ALL QUOTA ERRORS in server-out.log ==='",
|
||||
"grep -i 'quota' /var/log/bigwo/server-out.log 2>/dev/null | tail -10",
|
||||
"echo ''",
|
||||
"echo '=== LAST 20 UPSTREAM EVENTS ==='",
|
||||
"grep -E 'upstream ready|upstream closed|upstream error' /var/log/bigwo/server-out.log 2>/dev/null | tail -20",
|
||||
"echo ''",
|
||||
"echo '=== MOST RECENT ERROR LOG ==='",
|
||||
"tail -20 /var/log/bigwo/server-error.log 2>/dev/null",
|
||||
"echo ''",
|
||||
"echo '=== MOST RECENT OUT LOG ==='",
|
||||
"tail -20 /var/log/bigwo/server-out.log 2>/dev/null",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
21
mcp-server-ssh/check_speaker.cjs
Normal file
21
mcp-server-ssh/check_speaker.cjs
Normal file
@@ -0,0 +1,21 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== .env speaker/s2s config ==='",
|
||||
"grep -i 'speaker\\|s2s\\|tts\\|voice\\|model' /www/wwwroot/demo.tensorgrove.com.cn/server/.env 2>/dev/null || echo 'no match'",
|
||||
"echo ''",
|
||||
"echo '=== Latest session start payload ==='",
|
||||
"grep -i 'buildStartSession\\|speaker\\|system_role\\|speaking_style\\|model.*version\\|session.*start' /var/log/bigwo/server-out.log | tail -10",
|
||||
"echo ''",
|
||||
"echo '=== Current nativeVoiceGateway speaker line ==='",
|
||||
"grep -n 'speaker' /www/wwwroot/demo.tensorgrove.com.cn/server/services/nativeVoiceGateway.js | head -5",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', d => o += d);
|
||||
s.stderr.on('data', d => o += d);
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
20
mcp-server-ssh/check_voice.cjs
Normal file
20
mcp-server-ssh/check_voice.cjs
Normal file
@@ -0,0 +1,20 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== SPEAKER ENV ==='",
|
||||
"grep -oP 'VOLC_S2S_SPEAKER_ID=\\K.*' /www/wwwroot/demo.tensorgrove.com.cn/server/.env",
|
||||
"echo ''",
|
||||
"echo '=== LATEST SESSION CONFIG ==='",
|
||||
"LAST_SID=$(grep 'upstream ready' /var/log/bigwo/server-out.log | tail -1 | grep -oP 'session=\\K[^ ]+')",
|
||||
"echo \"Session: $LAST_SID\"",
|
||||
"grep -E 'speaker|SayHello|tts_event|ttsType|voice|config' /var/log/bigwo/server-out.log | tail -20",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
21
mcp-server-ssh/check_voice2.cjs
Normal file
21
mcp-server-ssh/check_voice2.cjs
Normal file
@@ -0,0 +1,21 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== .env SPEAKER lines ==='",
|
||||
"grep -i 'speaker' /www/wwwroot/demo.tensorgrove.com.cn/server/.env || echo 'NO SPEAKER in .env'",
|
||||
"echo ''",
|
||||
"echo '=== .env S2S lines ==='",
|
||||
"grep -i 's2s' /www/wwwroot/demo.tensorgrove.com.cn/server/.env || echo 'NO S2S in .env'",
|
||||
"echo ''",
|
||||
"echo '=== Session startup log (speaker) ==='",
|
||||
"grep -i 'speaker\\|tts.*config\\|session.*start\\|StartSession' /var/log/bigwo/server-out.log | tail -10",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
29
mcp-server-ssh/check_voice_issue.cjs
Normal file
29
mcp-server-ssh/check_voice_issue.cjs
Normal file
@@ -0,0 +1,29 @@
|
||||
const { Client } = require('ssh2');
|
||||
const c = new Client();
|
||||
c.on('ready', () => {
|
||||
const cmd = [
|
||||
"echo '=== LAST SESSION VOICE LOGS ==='",
|
||||
"LAST_SID=$(grep 'upstream ready' /var/log/bigwo/server-out.log | tail -1 | grep -oP 'session=\\K[^ ]+')",
|
||||
"echo \"Last session: $LAST_SID\"",
|
||||
"grep \"$LAST_SID\" /var/log/bigwo/server-out.log | grep -v 'partial' | tail -40",
|
||||
"echo ''",
|
||||
"echo '=== START SESSION PAYLOAD EVIDENCE ==='",
|
||||
"grep -E 'buildStartSession|StartSession|model.*version|modelVersion|system_role' /var/log/bigwo/server-out.log | tail -10",
|
||||
"echo ''",
|
||||
"echo '=== UPSTREAM ASSISTANT TEXT ==='",
|
||||
"grep 'upstream assistant' /var/log/bigwo/server-out.log | tail -10",
|
||||
"echo ''",
|
||||
"echo '=== 旅游/江西 RELATED ==='",
|
||||
"grep -i '旅游\\|江西\\|景点' /var/log/bigwo/server-out.log | tail -10",
|
||||
"echo ''",
|
||||
"echo '=== processReply LOGS ==='",
|
||||
"grep 'processReply' /var/log/bigwo/server-out.log | tail -15",
|
||||
].join(' && ');
|
||||
c.exec(cmd, (err, s) => {
|
||||
if (err) { console.error(err); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log(o); c.end(); });
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
93
mcp-server-ssh/deploy_asr_alias_fix.cjs
Normal file
93
mcp-server-ssh/deploy_asr_alias_fix.cjs
Normal file
@@ -0,0 +1,93 @@
|
||||
const { Client } = require('ssh2');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const SSH_CONFIG = {
|
||||
host: '119.45.10.34',
|
||||
port: 22,
|
||||
username: 'root',
|
||||
password: '#xyzh%CS#2512@28',
|
||||
readyTimeout: 10000,
|
||||
};
|
||||
|
||||
const PROJECT = '/www/wwwroot/demo.tensorgrove.com.cn';
|
||||
const LOCAL_BASE = path.join(__dirname, '..', 'test2');
|
||||
const filesToDeploy = [
|
||||
{
|
||||
local: 'server/services/realtimeDialogRouting.js',
|
||||
remote: `${PROJECT}/server/services/realtimeDialogRouting.js`,
|
||||
},
|
||||
{
|
||||
local: 'server/services/nativeVoiceGateway.js',
|
||||
remote: `${PROJECT}/server/services/nativeVoiceGateway.js`,
|
||||
},
|
||||
];
|
||||
|
||||
function sshExec(command, timeout = 30000) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const conn = new Client();
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
const timer = setTimeout(() => {
|
||||
conn.end();
|
||||
resolve({ stdout, stderr: stderr + '\n[TIMEOUT]', code: -1 });
|
||||
}, timeout);
|
||||
conn.on('ready', () => {
|
||||
conn.exec(command, (err, stream) => {
|
||||
if (err) { clearTimeout(timer); conn.end(); return reject(err); }
|
||||
stream.on('close', (code) => { clearTimeout(timer); conn.end(); resolve({ stdout, stderr, code }); });
|
||||
stream.on('data', (d) => { stdout += d.toString(); });
|
||||
stream.stderr.on('data', (d) => { stderr += d.toString(); });
|
||||
});
|
||||
}).on('error', (err) => { clearTimeout(timer); reject(err); }).connect(SSH_CONFIG);
|
||||
});
|
||||
}
|
||||
|
||||
function sshUpload(localPath, remotePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.sftp((err, sftp) => {
|
||||
if (err) { conn.end(); return reject(err); }
|
||||
const content = fs.readFileSync(localPath);
|
||||
const ws = sftp.createWriteStream(remotePath);
|
||||
ws.on('close', () => { conn.end(); resolve(); });
|
||||
ws.on('error', (e) => { conn.end(); reject(e); });
|
||||
ws.write(content);
|
||||
ws.end();
|
||||
});
|
||||
}).on('error', (err) => reject(err)).connect(SSH_CONFIG);
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('=== 部署一成系统 ASR 别名修复 ===');
|
||||
const backupDir = `${PROJECT}/server/_backup_${Date.now()}`;
|
||||
await sshExec(`mkdir -p ${backupDir} && cp ${PROJECT}/server/services/realtimeDialogRouting.js ${PROJECT}/server/services/nativeVoiceGateway.js ${backupDir}/`);
|
||||
console.log('备份目录:', backupDir);
|
||||
|
||||
for (const item of filesToDeploy) {
|
||||
const localPath = path.join(LOCAL_BASE, item.local.replace(/\//g, path.sep));
|
||||
await sshUpload(localPath, item.remote);
|
||||
console.log('上传完成:', item.remote);
|
||||
}
|
||||
|
||||
const restart = await sshExec('pm2 restart bigwo-server 2>&1');
|
||||
console.log(restart.stdout);
|
||||
|
||||
await new Promise((r) => setTimeout(r, 3000));
|
||||
|
||||
const health = await sshExec('curl -s http://127.0.0.1:3012/api/health 2>&1');
|
||||
console.log('Health:', health.stdout);
|
||||
|
||||
const pm2 = await sshExec('pm2 list 2>&1');
|
||||
console.log(pm2.stdout);
|
||||
|
||||
const verify = await sshExec(`wc -l ${PROJECT}/server/services/realtimeDialogRouting.js ${PROJECT}/server/services/nativeVoiceGateway.js 2>&1`);
|
||||
console.log(verify.stdout);
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error('Fatal:', e.message);
|
||||
process.exit(1);
|
||||
});
|
||||
82
mcp-server-ssh/deploy_chat_switch_fix.cjs
Normal file
82
mcp-server-ssh/deploy_chat_switch_fix.cjs
Normal file
@@ -0,0 +1,82 @@
|
||||
const { Client } = require('ssh2');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const SSH_CONFIG = {
|
||||
host: '119.45.10.34',
|
||||
port: 22,
|
||||
username: 'root',
|
||||
password: '#xyzh%CS#2512@28',
|
||||
readyTimeout: 10000,
|
||||
};
|
||||
|
||||
const PROJECT = '/www/wwwroot/demo.tensorgrove.com.cn';
|
||||
const LOCAL_FILE = path.join(__dirname, '..', 'test2', 'server', 'services', 'realtimeDialogRouting.js');
|
||||
const REMOTE_FILE = `${PROJECT}/server/services/realtimeDialogRouting.js`;
|
||||
|
||||
function sshExec(command, timeout = 30000) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const conn = new Client();
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
const timer = setTimeout(() => {
|
||||
conn.end();
|
||||
resolve({ stdout, stderr: stderr + '\n[TIMEOUT]', code: -1 });
|
||||
}, timeout);
|
||||
conn.on('ready', () => {
|
||||
conn.exec(command, (err, stream) => {
|
||||
if (err) { clearTimeout(timer); conn.end(); return reject(err); }
|
||||
stream.on('close', (code) => { clearTimeout(timer); conn.end(); resolve({ stdout, stderr, code }); });
|
||||
stream.on('data', (d) => { stdout += d.toString(); });
|
||||
stream.stderr.on('data', (d) => { stderr += d.toString(); });
|
||||
});
|
||||
}).on('error', (err) => { clearTimeout(timer); reject(err); }).connect(SSH_CONFIG);
|
||||
});
|
||||
}
|
||||
|
||||
function sshUpload(localPath, remotePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.sftp((err, sftp) => {
|
||||
if (err) { conn.end(); return reject(err); }
|
||||
const content = fs.readFileSync(localPath);
|
||||
const ws = sftp.createWriteStream(remotePath);
|
||||
ws.on('close', () => { conn.end(); resolve(); });
|
||||
ws.on('error', (e) => { conn.end(); reject(e); });
|
||||
ws.write(content);
|
||||
ws.end();
|
||||
});
|
||||
}).on('error', (err) => reject(err)).connect(SSH_CONFIG);
|
||||
});
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('=== 部署闲聊切换修复 ===');
|
||||
const backupDir = `${PROJECT}/server/_backup_${Date.now()}`;
|
||||
const backup = await sshExec(`mkdir -p ${backupDir} && cp ${REMOTE_FILE} ${backupDir}/`);
|
||||
console.log('备份目录:', backupDir);
|
||||
if (backup.stderr) console.log(backup.stderr);
|
||||
|
||||
await sshUpload(LOCAL_FILE, REMOTE_FILE);
|
||||
console.log('上传完成:', REMOTE_FILE);
|
||||
|
||||
const restart = await sshExec('pm2 restart bigwo-server 2>&1');
|
||||
console.log(restart.stdout);
|
||||
|
||||
await new Promise((r) => setTimeout(r, 3000));
|
||||
|
||||
const health = await sshExec('curl -s http://127.0.0.1:3012/api/health 2>&1');
|
||||
console.log('Health:', health.stdout);
|
||||
|
||||
const pm2 = await sshExec('pm2 list 2>&1');
|
||||
console.log(pm2.stdout);
|
||||
|
||||
const verify = await sshExec(`wc -l ${REMOTE_FILE} 2>&1`);
|
||||
console.log(verify.stdout);
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error('Fatal:', e.message);
|
||||
process.exit(1);
|
||||
});
|
||||
51
mcp-server-ssh/deploy_fix.cjs
Normal file
51
mcp-server-ssh/deploy_fix.cjs
Normal file
@@ -0,0 +1,51 @@
|
||||
const { Client } = require('ssh2');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const c = new Client();
|
||||
const localFile = path.join(__dirname, '..', 'test2', 'server', 'services', 'toolExecutor.js');
|
||||
const remotePath = '/www/wwwroot/demo.tensorgrove.com.cn/server/services/toolExecutor.js';
|
||||
|
||||
const content = fs.readFileSync(localFile, 'utf8');
|
||||
|
||||
c.on('ready', () => {
|
||||
console.log('SSH connected, deploying toolExecutor.js...');
|
||||
|
||||
// Use SFTP to write the file
|
||||
c.sftp((err, sftp) => {
|
||||
if (err) {
|
||||
console.error('SFTP error:', err.message);
|
||||
c.end();
|
||||
return;
|
||||
}
|
||||
|
||||
const writeStream = sftp.createWriteStream(remotePath);
|
||||
writeStream.on('close', () => {
|
||||
console.log('File uploaded successfully.');
|
||||
|
||||
// Restart PM2
|
||||
c.exec('pm2 restart bigwo-server && sleep 2 && pm2 logs bigwo-server --nostream --lines 10', (err, s) => {
|
||||
if (err) {
|
||||
console.error('Restart error:', err.message);
|
||||
c.end();
|
||||
return;
|
||||
}
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => {
|
||||
console.log('PM2 restart output:\n' + o);
|
||||
c.end();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
writeStream.on('error', (err) => {
|
||||
console.error('Write error:', err.message);
|
||||
c.end();
|
||||
});
|
||||
|
||||
writeStream.write(content);
|
||||
writeStream.end();
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
55
mcp-server-ssh/deploy_fixes.cjs
Normal file
55
mcp-server-ssh/deploy_fixes.cjs
Normal file
@@ -0,0 +1,55 @@
|
||||
const { Client } = require('ssh2');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const c = new Client();
|
||||
const REMOTE_BASE = '/www/wwwroot/demo.tensorgrove.com.cn/server/services';
|
||||
|
||||
// Read local files
|
||||
const gatewayPath = path.join(__dirname, '..', 'test2', 'server', 'services', 'nativeVoiceGateway.js');
|
||||
const toolExecPath = path.join(__dirname, '..', 'test2', 'server', 'services', 'toolExecutor.js');
|
||||
|
||||
const gatewayContent = fs.readFileSync(gatewayPath, 'utf8');
|
||||
const toolExecContent = fs.readFileSync(toolExecPath, 'utf8');
|
||||
|
||||
console.log(`Gateway file size: ${gatewayContent.length} bytes`);
|
||||
console.log(`ToolExecutor file size: ${toolExecContent.length} bytes`);
|
||||
|
||||
c.on('ready', () => {
|
||||
console.log('SSH connected, starting SFTP...');
|
||||
c.sftp((err, sftp) => {
|
||||
if (err) { console.error('SFTP error:', err); c.end(); return; }
|
||||
|
||||
let done = 0;
|
||||
const total = 2;
|
||||
function checkDone() {
|
||||
done++;
|
||||
if (done >= total) {
|
||||
console.log('All files uploaded. Restarting PM2...');
|
||||
c.exec('cd /www/wwwroot/demo.tensorgrove.com.cn && pm2 restart bigwo-server && sleep 2 && pm2 logs bigwo-server --lines 20 --nostream', (err2, s) => {
|
||||
if (err2) { console.error('Restart error:', err2); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => {
|
||||
console.log('=== PM2 Restart Output ===');
|
||||
console.log(o);
|
||||
c.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Upload nativeVoiceGateway.js
|
||||
const ws1 = sftp.createWriteStream(`${REMOTE_BASE}/nativeVoiceGateway.js`);
|
||||
ws1.on('close', () => { console.log('✓ nativeVoiceGateway.js uploaded'); checkDone(); });
|
||||
ws1.on('error', (e) => { console.error('Upload gateway error:', e); });
|
||||
ws1.end(gatewayContent);
|
||||
|
||||
// Upload toolExecutor.js
|
||||
const ws2 = sftp.createWriteStream(`${REMOTE_BASE}/toolExecutor.js`);
|
||||
ws2.on('close', () => { console.log('✓ toolExecutor.js uploaded'); checkDone(); });
|
||||
ws2.on('error', (e) => { console.error('Upload toolExec error:', e); });
|
||||
ws2.end(toolExecContent);
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
30
mcp-server-ssh/deploy_voice_fix.cjs
Normal file
30
mcp-server-ssh/deploy_voice_fix.cjs
Normal file
@@ -0,0 +1,30 @@
|
||||
const { Client } = require('ssh2');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const c = new Client();
|
||||
const localFile = path.join(__dirname, '..', 'test2', 'server', 'services', 'nativeVoiceGateway.js');
|
||||
const remotePath = '/www/wwwroot/demo.tensorgrove.com.cn/server/services/nativeVoiceGateway.js';
|
||||
|
||||
const content = fs.readFileSync(localFile, 'utf8');
|
||||
|
||||
c.on('ready', () => {
|
||||
console.log('SSH connected, deploying nativeVoiceGateway.js...');
|
||||
c.sftp((err, sftp) => {
|
||||
if (err) { console.error('SFTP error:', err.message); c.end(); return; }
|
||||
const ws = sftp.createWriteStream(remotePath);
|
||||
ws.on('close', () => {
|
||||
console.log('File uploaded successfully.');
|
||||
c.exec('pm2 restart bigwo-server && sleep 2 && pm2 logs bigwo-server --nostream --lines 5', (err, s) => {
|
||||
if (err) { console.error('Restart error:', err.message); c.end(); return; }
|
||||
let o = '';
|
||||
s.on('data', (d) => (o += d));
|
||||
s.stderr.on('data', (d) => (o += d));
|
||||
s.on('close', () => { console.log('PM2 restart:\n' + o); c.end(); });
|
||||
});
|
||||
});
|
||||
ws.on('error', (err) => { console.error('Write error:', err.message); c.end(); });
|
||||
ws.write(content);
|
||||
ws.end();
|
||||
});
|
||||
}).connect({ host: '119.45.10.34', port: 22, username: 'root', password: '#xyzh%CS#2512@28' });
|
||||
141
mcp-server-ssh/deploy_voice_kb_fix.cjs
Normal file
141
mcp-server-ssh/deploy_voice_kb_fix.cjs
Normal file
@@ -0,0 +1,141 @@
|
||||
const { Client } = require('ssh2');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const SSH_CONFIG = {
|
||||
host: '119.45.10.34',
|
||||
port: 22,
|
||||
username: 'root',
|
||||
password: '#xyzh%CS#2512@28',
|
||||
readyTimeout: 10000,
|
||||
};
|
||||
|
||||
const PROJECT = '/www/wwwroot/demo.tensorgrove.com.cn';
|
||||
const LOCAL_BASE = path.join(__dirname, '..', 'test2');
|
||||
|
||||
function sshExec(command, timeout = 30000) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const conn = new Client();
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
const timer = setTimeout(() => {
|
||||
conn.end();
|
||||
resolve({ stdout, stderr: stderr + '\n[TIMEOUT]', code: -1 });
|
||||
}, timeout);
|
||||
conn.on('ready', () => {
|
||||
conn.exec(command, (err, stream) => {
|
||||
if (err) { clearTimeout(timer); conn.end(); return reject(err); }
|
||||
stream.on('close', (code) => { clearTimeout(timer); conn.end(); resolve({ stdout, stderr, code }); });
|
||||
stream.on('data', (d) => { stdout += d.toString(); });
|
||||
stream.stderr.on('data', (d) => { stderr += d.toString(); });
|
||||
});
|
||||
}).on('error', (err) => { clearTimeout(timer); reject(err); }).connect(SSH_CONFIG);
|
||||
});
|
||||
}
|
||||
|
||||
function sshUpload(localPath, remotePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const conn = new Client();
|
||||
conn.on('ready', () => {
|
||||
conn.sftp((err, sftp) => {
|
||||
if (err) { conn.end(); return reject(err); }
|
||||
const content = fs.readFileSync(localPath);
|
||||
const ws = sftp.createWriteStream(remotePath);
|
||||
ws.on('close', () => { conn.end(); resolve(); });
|
||||
ws.on('error', (e) => { conn.end(); reject(e); });
|
||||
ws.write(content);
|
||||
ws.end();
|
||||
});
|
||||
}).on('error', (err) => reject(err)).connect(SSH_CONFIG);
|
||||
});
|
||||
}
|
||||
|
||||
const filesToDeploy = [
|
||||
// 服务端文件
|
||||
{ local: 'server/services/toolExecutor.js', remote: `${PROJECT}/server/services/toolExecutor.js`, desc: '知识库回答精准度修复' },
|
||||
{ local: 'server/services/nativeVoiceGateway.js', remote: `${PROJECT}/server/services/nativeVoiceGateway.js`, desc: '语音连接提前ready+超时兜底' },
|
||||
// 客户端构建产物
|
||||
{ local: 'client/dist/index.html', remote: `${PROJECT}/client/dist/index.html`, desc: '客户端入口' },
|
||||
{ local: 'client/dist/assets/index-DFs3zFyd.css', remote: `${PROJECT}/client/dist/assets/index-DFs3zFyd.css`, desc: '客户端样式' },
|
||||
{ local: 'client/dist/assets/index-DiJ8zsnj.js', remote: `${PROJECT}/client/dist/assets/index-DiJ8zsnj.js`, desc: '客户端JS(含getUserMedia并行化+超时)' },
|
||||
];
|
||||
|
||||
async function main() {
|
||||
console.log('=== 语音通话延迟修复 + 知识库精准度修复 部署 ===\n');
|
||||
|
||||
// 1. 备份
|
||||
console.log('--- 1. 备份服务器文件 ---');
|
||||
const backupDir = `${PROJECT}/server/_backup_${Date.now()}`;
|
||||
const backupCmd = [
|
||||
`mkdir -p ${backupDir}`,
|
||||
`cp ${PROJECT}/server/services/toolExecutor.js ${backupDir}/`,
|
||||
`cp ${PROJECT}/server/services/nativeVoiceGateway.js ${backupDir}/`,
|
||||
`mkdir -p ${backupDir}/client_dist_assets`,
|
||||
`cp -r ${PROJECT}/client/dist/assets/* ${backupDir}/client_dist_assets/ 2>/dev/null || true`,
|
||||
`cp ${PROJECT}/client/dist/index.html ${backupDir}/client_dist_index.html 2>/dev/null || true`,
|
||||
].join(' && ');
|
||||
const backupResult = await sshExec(backupCmd);
|
||||
console.log(`备份目录: ${backupDir}`);
|
||||
if (backupResult.stderr && !backupResult.stderr.includes('true')) console.log(backupResult.stderr);
|
||||
|
||||
// 2. 确保远程目录存在
|
||||
console.log('\n--- 2. 确保目录存在 ---');
|
||||
await sshExec(`mkdir -p ${PROJECT}/client/dist/assets`);
|
||||
console.log('OK');
|
||||
|
||||
// 3. 清理旧的客户端资源文件
|
||||
console.log('\n--- 3. 清理旧客户端资源 ---');
|
||||
const cleanResult = await sshExec(`rm -f ${PROJECT}/client/dist/assets/index-*.js ${PROJECT}/client/dist/assets/index-*.css 2>&1`);
|
||||
console.log(cleanResult.stdout || 'OK');
|
||||
|
||||
// 4. 上传文件
|
||||
console.log('\n--- 4. 上传文件 ---');
|
||||
for (const { local, remote, desc } of filesToDeploy) {
|
||||
const localPath = path.join(LOCAL_BASE, local.replace(/\//g, path.sep));
|
||||
try {
|
||||
if (!fs.existsSync(localPath)) {
|
||||
console.log(`⚠️ 跳过 ${local} (本地文件不存在)`);
|
||||
continue;
|
||||
}
|
||||
await sshUpload(localPath, remote);
|
||||
const size = fs.statSync(localPath).size;
|
||||
console.log(`✅ ${local} → ${remote} (${size}B) [${desc}]`);
|
||||
} catch (e) {
|
||||
console.error(`❌ ${local}: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 重启 PM2
|
||||
console.log('\n--- 5. 重启 PM2 ---');
|
||||
const restart = await sshExec('pm2 restart bigwo-server 2>&1');
|
||||
console.log(restart.stdout);
|
||||
|
||||
// 6. 等待检查
|
||||
console.log('--- 6. 等待3秒后检查 ---');
|
||||
await new Promise(r => setTimeout(r, 3000));
|
||||
|
||||
const health = await sshExec('curl -s http://127.0.0.1:3012/api/health 2>&1');
|
||||
console.log('Health:', health.stdout);
|
||||
|
||||
const pm2 = await sshExec('pm2 list 2>&1');
|
||||
console.log(pm2.stdout);
|
||||
|
||||
// 7. 检查启动日志
|
||||
console.log('--- 7. 启动日志 ---');
|
||||
const logs = await sshExec('pm2 logs bigwo-server --nostream --lines 15 2>&1');
|
||||
console.log(logs.stdout);
|
||||
if (logs.stderr) console.log(logs.stderr);
|
||||
|
||||
// 8. 验证文件
|
||||
console.log('--- 8. 验证文件行数 ---');
|
||||
const wc = await sshExec(`wc -l ${PROJECT}/server/services/toolExecutor.js ${PROJECT}/server/services/nativeVoiceGateway.js 2>&1`);
|
||||
console.log(wc.stdout);
|
||||
|
||||
const lsAssets = await sshExec(`ls -la ${PROJECT}/client/dist/assets/ 2>&1`);
|
||||
console.log('客户端资源文件:');
|
||||
console.log(lsAssets.stdout);
|
||||
|
||||
console.log('\n=== 部署完成 ===');
|
||||
}
|
||||
|
||||
main().catch(e => { console.error('Fatal:', e.message); process.exit(1); });
|
||||
87
mcp-server-ssh/e2e_test.cjs
Normal file
87
mcp-server-ssh/e2e_test.cjs
Normal file
@@ -0,0 +1,87 @@
|
||||
const https = require('https');
|
||||
|
||||
const BASE = 'https://demo.tensorgrove.com.cn';
|
||||
|
||||
function post(path, body) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const url = new URL(path, BASE);
|
||||
const data = JSON.stringify(body);
|
||||
const req = https.request(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
|
||||
timeout: 60000,
|
||||
}, (res) => {
|
||||
let chunks = '';
|
||||
res.on('data', (d) => chunks += d);
|
||||
res.on('end', () => {
|
||||
try { resolve(JSON.parse(chunks)); } catch { resolve(chunks); }
|
||||
});
|
||||
});
|
||||
req.on('error', reject);
|
||||
req.on('timeout', () => { req.destroy(); reject(new Error('timeout')); });
|
||||
req.write(data);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
const TESTS = [
|
||||
{ q: '我们公司的产品有哪些', expect: 'kb', desc: '泛产品查询' },
|
||||
{ q: '基础三合一是什么', expect: 'kb', desc: '基础三合一' },
|
||||
{ q: '火炉原理是什么', expect: 'kb', desc: '火炉原理' },
|
||||
{ q: '一程系统的基础三合一是什么', expect: 'kb', desc: '一程系统基础三合一' },
|
||||
{ q: '我们公司卖手机和平板吗', expect: 'chat', desc: '手机平板(应走Coze)' },
|
||||
];
|
||||
|
||||
async function runTests() {
|
||||
// Create a session first
|
||||
let sessionId;
|
||||
try {
|
||||
const startRes = await post('/api/chat/start', { userId: 'e2e_test_' + Date.now() });
|
||||
sessionId = startRes.sessionId;
|
||||
console.log('Session:', sessionId);
|
||||
} catch (e) {
|
||||
console.error('Failed to create session:', e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
const results = [];
|
||||
for (const test of TESTS) {
|
||||
try {
|
||||
const sid = 'e2e_' + Date.now() + '_' + Math.random().toString(36).slice(2, 6);
|
||||
await post('/api/chat/start', { sessionId: sid });
|
||||
const res = await post('/api/chat/send', { sessionId: sid, message: test.q });
|
||||
const reply = (res.data && res.data.content) || res.reply || '';
|
||||
const replyShort = reply.slice(0, 100);
|
||||
|
||||
// Check for hallucination indicators
|
||||
const hasHallucination = /(手机|平板|笔记本|智能手表|护肤品|彩妆|香水|化妆品|电视|冰箱|洗衣机)/i.test(reply);
|
||||
const hasPMContent = /(PM|FitLine|细胞营养|Activize|Basics|Restorate|NTC|火炉|阿育吠陀|一成系统|基础套装|大白|小红|小白|儿童倍适|营养)/i.test(reply);
|
||||
|
||||
let status = '✅';
|
||||
if (test.expect === 'kb' && hasHallucination) status = '❌幻觉';
|
||||
else if (test.expect === 'kb' && !hasPMContent) status = '⚠️无PM内容';
|
||||
|
||||
results.push({ desc: test.desc, q: test.q, status, reply: replyShort });
|
||||
console.log(`${status} [${test.desc}] ${test.q} → ${replyShort}`);
|
||||
} catch (e) {
|
||||
results.push({ desc: test.desc, q: test.q, status: '❌ERROR', reply: e.message });
|
||||
console.log(`❌ [${test.desc}] ${test.q} → ERROR: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n=== 测试总结 ===');
|
||||
const pass = results.filter(r => r.status === '✅').length;
|
||||
const warn = results.filter(r => r.status.startsWith('⚠️')).length;
|
||||
const fail = results.filter(r => r.status.startsWith('❌')).length;
|
||||
console.log(`通过: ${pass}, 警告: ${warn}, 失败: ${fail}, 总计: ${results.length}`);
|
||||
|
||||
if (warn + fail > 0) {
|
||||
console.log('\n=== 问题详情 ===');
|
||||
results.filter(r => r.status !== '✅').forEach(r => {
|
||||
console.log(`${r.status} [${r.desc}] ${r.q}`);
|
||||
console.log(` 回答: ${r.reply}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
runTests().catch(e => console.error('Fatal:', e));
|
||||
156
mcp-server-ssh/verify_scenarios.cjs
Normal file
156
mcp-server-ssh/verify_scenarios.cjs
Normal file
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* 本地模拟多场景验证:toolExecutor.js 修复后的路由和分类逻辑
|
||||
*/
|
||||
const path = require('path');
|
||||
|
||||
// 模拟环境变量(模拟服务器配置)
|
||||
process.env.VOLC_ARK_ENDPOINT_ID = 'ep-xxx';
|
||||
process.env.VOLC_ARK_API_KEY = 'fake-key';
|
||||
process.env.VOLC_ARK_KNOWLEDGE_BASE_IDS = 'kb-f94cc30193b3b707,kb-a69b0928e1714de7,kb-a6c238e38ca81478,kb-149300b22195d2bf,kb-c7e7cd2bf0580fa0,kb-177fb1d978d88e0e';
|
||||
process.env.VOLC_ARK_KNOWLEDGE_BASE_ROUTING = JSON.stringify([
|
||||
{"name":"product","dataset_ids":["kb-f94cc30193b3b707"],"keywords":["pm产品","fitline","pm-fitline","产品","细胞营养素","activize","oxyplus","basics","restorate","儿童倍适","ntc","营养保送","小红产品","大白产品","小白产品","火炉原理","阿育吠陀","成分","功效","吃法","用法","服用","好转反应","活动","促销","分数"]},
|
||||
{"name":"company","dataset_ids":["kb-a69b0928e1714de7"],"keywords":["pm公司","德国pm公司","公司","地址","电话","联系方式","实力","背景","成立","总部","分公司"]},
|
||||
{"name":"training","dataset_ids":["kb-a6c238e38ca81478"],"keywords":["培训","新人","起步三关","精品会议","会议组织","成长上总裁","团队培训","新人入门"]},
|
||||
{"name":"investment","dataset_ids":["kb-149300b22195d2bf"],"keywords":["招商","代理","代理商","合作","加盟","招募","事业机会","创业","招商稿"]},
|
||||
{"name":"system","dataset_ids":["kb-c7e7cd2bf0580fa0"],"keywords":["一成系统","ai众享","数字化工作室","盛咖学愿","系统","邀约话术","文化解析","ai赋能","团队发展"]},
|
||||
{"name":"general","dataset_ids":["kb-177fb1d978d88e0e"],"keywords":["一成ai","ai落地","转观念","对比","综合知识库"]}
|
||||
]);
|
||||
|
||||
// 加载修复后的 toolExecutor
|
||||
const ToolExecutor = require(path.join(__dirname, '..', 'test2', 'server', 'services', 'toolExecutor'));
|
||||
|
||||
console.log('====== 多场景逻辑验证 ======\n');
|
||||
|
||||
// 场景定义
|
||||
const scenarios = [
|
||||
{
|
||||
name: '场景1: 德国PM基础三合一(截图问题)',
|
||||
query: '给我介绍一下德国PM的基础三合一吧?',
|
||||
context: [],
|
||||
expectRoute: 'product',
|
||||
expectDeterministic: '德国PM细胞营养素 基础套装 大白 小红 小白',
|
||||
},
|
||||
{
|
||||
name: '场景2: 我们公司的产品(上下文有基础套装)',
|
||||
query: '介绍一下我们公司的产品。',
|
||||
context: [
|
||||
{ role: 'user', content: '基础三合一是什么?' },
|
||||
{ role: 'assistant', content: '德国PM细胞营养素基础套装包括大白、小红、小白三款产品。' },
|
||||
],
|
||||
expectRoute: 'product',
|
||||
expectDeterministic: '德国PM FitLine 细胞营养素产品 大白Basics 小红Activize 小白Restorate 儿童倍适',
|
||||
},
|
||||
{
|
||||
name: '场景3: 德国PM公司介绍(纯公司查询)',
|
||||
query: '介绍一下德国PM公司',
|
||||
context: [],
|
||||
expectRoute: 'company',
|
||||
},
|
||||
{
|
||||
name: '场景4: 德国PM产品(产品+德国PM混合)',
|
||||
query: '德国PM的产品有哪些',
|
||||
context: [],
|
||||
expectRoute: 'product',
|
||||
},
|
||||
{
|
||||
name: '场景5: 一成系统(系统优先路由)',
|
||||
query: '一成系统是什么',
|
||||
context: [],
|
||||
expectRoute: 'system',
|
||||
},
|
||||
{
|
||||
name: '场景6: 河南胡辣汤(闲聊,不走知识库)',
|
||||
query: '河南胡辣汤',
|
||||
context: [],
|
||||
expectRoute: 'default_or_none',
|
||||
},
|
||||
{
|
||||
name: '场景7: 追问"这个怎么用"(上下文有小红产品)',
|
||||
query: '这个怎么用',
|
||||
context: [
|
||||
{ role: 'user', content: '小红产品是什么?' },
|
||||
{ role: 'assistant', content: 'Activize Oxyplus 是...' },
|
||||
],
|
||||
expectDeterministic: 'Fitline小红产品提升能量原理',
|
||||
},
|
||||
{
|
||||
name: '场景8: classifyKnowledgeAnswer - 未命中模式1',
|
||||
query: 'test',
|
||||
classifyContent: '关于PM细胞营养素基础套装,目前我这边没有找到这三个产品的具体成分和功效说明。建议你直接查看产品包装上的详细信息,或联系官方客服获取准确的使用指导。',
|
||||
expectHit: false,
|
||||
},
|
||||
{
|
||||
name: '场景9: classifyKnowledgeAnswer - 未命中模式2',
|
||||
query: 'test',
|
||||
classifyContent: '我没有找到德国PM细胞营养素基础三合一的相关介绍。你是想了解它的成分、功效,还是使用方法呢?',
|
||||
expectHit: false,
|
||||
},
|
||||
{
|
||||
name: '场景10: classifyKnowledgeAnswer - 正常命中',
|
||||
query: 'test',
|
||||
classifyContent: 'PM细胞营养素基础套装包含大白Basics、小红Activize和小白Restorate三款产品,通过NTC营养保送系统发挥协同作用。',
|
||||
expectHit: true,
|
||||
},
|
||||
{
|
||||
name: '场景11: 招商合作',
|
||||
query: '怎么加盟代理',
|
||||
context: [],
|
||||
expectRoute: 'investment',
|
||||
},
|
||||
{
|
||||
name: '场景12: 新人培训',
|
||||
query: '新人起步三关是什么',
|
||||
context: [],
|
||||
expectRoute: 'training',
|
||||
},
|
||||
];
|
||||
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const s of scenarios) {
|
||||
console.log(`--- ${s.name} ---`);
|
||||
|
||||
// 测试 classifyKnowledgeAnswer
|
||||
if (s.classifyContent !== undefined) {
|
||||
const result = ToolExecutor.classifyKnowledgeAnswer(s.query, s.classifyContent);
|
||||
const ok = result.hit === s.expectHit;
|
||||
console.log(` classify hit=${result.hit} reason=${result.reason} ${ok ? '✅' : '❌ EXPECTED hit=' + s.expectHit}`);
|
||||
if (ok) passed++; else failed++;
|
||||
console.log('');
|
||||
continue;
|
||||
}
|
||||
|
||||
// 测试路由
|
||||
const context = s.context || [];
|
||||
const normalizedQuery = ToolExecutor.normalizeKnowledgeQueryAlias(s.query);
|
||||
const anchored = ToolExecutor.applyKnowledgeQueryAnchor(normalizedQuery);
|
||||
const deterministicQuery = ToolExecutor.buildDeterministicKnowledgeQuery(anchored, context);
|
||||
const effectiveQuery = deterministicQuery || anchored;
|
||||
const kbTarget = ToolExecutor.selectKnowledgeBaseTargets(effectiveQuery, context);
|
||||
|
||||
console.log(` normalized: "${normalizedQuery}"`);
|
||||
console.log(` deterministic: "${deterministicQuery}"`);
|
||||
console.log(` effective: "${effectiveQuery}"`);
|
||||
console.log(` routes: [${kbTarget.matchedRoutes.join(', ')}]`);
|
||||
console.log(` datasets: [${kbTarget.datasetIds.join(', ')}]`);
|
||||
|
||||
if (s.expectDeterministic) {
|
||||
const ok = deterministicQuery === s.expectDeterministic;
|
||||
console.log(` deterministic check: ${ok ? '✅' : '❌ EXPECTED "' + s.expectDeterministic + '"'}`);
|
||||
if (ok) passed++; else failed++;
|
||||
}
|
||||
|
||||
if (s.expectRoute) {
|
||||
const ok = s.expectRoute === 'default_or_none'
|
||||
? kbTarget.matchedRoutes.includes('default') || kbTarget.matchedRoutes.length === 0
|
||||
: kbTarget.matchedRoutes.includes(s.expectRoute);
|
||||
console.log(` route check: ${ok ? '✅' : '❌ EXPECTED route=' + s.expectRoute}`);
|
||||
if (ok) passed++; else failed++;
|
||||
}
|
||||
|
||||
console.log('');
|
||||
}
|
||||
|
||||
console.log(`\n====== 结果:${passed} 通过, ${failed} 失败 ======`);
|
||||
if (failed > 0) process.exit(1);
|
||||
Reference in New Issue
Block a user