fix(docker+brain): make container Chrome search work, harden, improve toggle
Addresses review findings on the dockerized stack: - Container Chrome search was dead: add --remote-debugging-port + a non-default --user-data-dir (Chrome 136+ refuses CDP on the default profile), add the playwright dep (browse-search.mjs connectOverCDP) with browser download skipped, and connect to 127.0.0.1 not "localhost" (container localhost -> ::1 while Chrome binds IPv4). Verified: browse-search returns real results. - Broadcast toggle reliability: always offer setBroadcast in screen-share mode (the embedding/keyword router dropped it for non-English utterances) and make its description force a tool call. "방송 꺼줘"->stop now 5/5; no false triggers. - Stop the broadcast on voice leave (no orphaned stream). - Security: bind VNC/noVNC to loopback by default (VNC_BIND override) and the bridge to the container loopback (BRIDGE_HOST=127.0.0.1), not published. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
"dotenv": "^16.4.5",
|
||||
"libsodium-wrappers": "^0.7.15",
|
||||
"opusscript": "^0.1.1",
|
||||
"playwright": "^1.60.0",
|
||||
"prism-media": "^1.3.5",
|
||||
"qrcode": "^1.5.4",
|
||||
},
|
||||
@@ -318,6 +319,8 @@
|
||||
|
||||
"fs-extra": ["fs-extra@11.3.5", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
|
||||
|
||||
"generate-function": ["generate-function@2.3.1", "", { "dependencies": { "is-property": "^1.0.2" } }, "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ=="],
|
||||
|
||||
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
|
||||
@@ -408,6 +411,10 @@
|
||||
|
||||
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
|
||||
|
||||
"playwright": ["playwright@1.60.0", "", { "dependencies": { "playwright-core": "1.60.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA=="],
|
||||
|
||||
"playwright-core": ["playwright-core@1.60.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA=="],
|
||||
|
||||
"pngjs": ["pngjs@5.0.0", "", {}, "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="],
|
||||
|
||||
"prebuild-install": ["prebuild-install@7.1.3", "", { "dependencies": { "detect-libc": "^2.0.0", "expand-template": "^2.0.3", "github-from-package": "0.0.0", "minimist": "^1.2.3", "mkdirp-classic": "^0.5.3", "napi-build-utils": "^2.0.0", "node-abi": "^3.3.0", "pump": "^3.0.0", "rc": "^1.2.7", "simple-get": "^4.0.0", "tar-fs": "^2.0.0", "tunnel-agent": "^0.6.0" }, "bin": { "prebuild-install": "bin.js" } }, "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug=="],
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"dotenv": "^16.4.5",
|
||||
"libsodium-wrappers": "^0.7.15",
|
||||
"opusscript": "^0.1.1",
|
||||
"playwright": "^1.60.0",
|
||||
"prism-media": "^1.3.5",
|
||||
"qrcode": "^1.5.4"
|
||||
},
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
import { chromium } from 'playwright';
|
||||
|
||||
const CDP = process.env.CDP_PORT || '9222';
|
||||
// Use 127.0.0.1, not "localhost": in containers localhost can resolve to IPv6
|
||||
// (::1) first while Chrome's CDP listens on IPv4, giving ECONNREFUSED ::1.
|
||||
const CDP_HOST = process.env.CDP_HOST || '127.0.0.1';
|
||||
const query = process.argv[2] || '';
|
||||
const mode = (process.argv[3] || 'search').toLowerCase();
|
||||
const out = (o) => { process.stdout.write(JSON.stringify(o)); };
|
||||
@@ -17,7 +20,7 @@ if (!query) { out({ ok: false, error: 'no query' }); process.exit(1); }
|
||||
|
||||
let b;
|
||||
try {
|
||||
b = await chromium.connectOverCDP(`http://localhost:${CDP}`);
|
||||
b = await chromium.connectOverCDP(`http://${CDP_HOST}:${CDP}`);
|
||||
const ctx = b.contexts()[0];
|
||||
const page = ctx.pages()[0] || (await ctx.newPage());
|
||||
page.setDefaultTimeout(20000);
|
||||
|
||||
@@ -110,6 +110,16 @@ async function handleJoin(i: ChatInputCommandInteraction) {
|
||||
|
||||
async function handleLeave(i: ChatInputCommandInteraction) {
|
||||
const left = leaveGuild(i.guildId!);
|
||||
// Leaving voice also ends the broadcast — don't leave a stream live with no
|
||||
// session driving it.
|
||||
const streamer = streamers.get(i.guildId!);
|
||||
if (streamer?.isActive()) {
|
||||
try {
|
||||
await streamer.stop();
|
||||
} catch (e) {
|
||||
console.error("[leave] stopping broadcast failed:", e);
|
||||
}
|
||||
}
|
||||
await i.reply({ content: left ? "음성 채널에서 나갔습니다." : "접속 중인 세션이 없습니다.", ...eph });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user