fix(collector): 기능 누락 3건 수정 — Discord 명령어/채팅/등록 중계
Gap 1: Discord→Extension 명령어 깨짐 - bot.py: _write_command() 래퍼 — gateway.push_command()도 호출 - main.py: bot.gateway 연결 - 슬래시 명령어 + on_message 모두 _write_command 사용 Gap 2: Chat snapshot 미전달 - collector.py: _forward_chat_snapshots_loop 추가 Gap 3: Session registration 미전달 - collector.py: _forward_registrations_loop 추가
This commit is contained in:
24
bot.py
24
bot.py
@@ -180,6 +180,18 @@ class GravityBot(commands.Bot):
|
|||||||
self.session_category: discord.CategoryChannel | None = None
|
self.session_category: discord.CategoryChannel | None = None
|
||||||
self.guild: discord.Guild | None = None
|
self.guild: discord.Guild | None = None
|
||||||
self.auto_approve_projects: set[str] = set() # projects with auto-approve enabled
|
self.auto_approve_projects: set[str] = set() # projects with auto-approve enabled
|
||||||
|
self.gateway = None # Set by main.py in gateway mode
|
||||||
|
|
||||||
|
def _write_command(self, project: str, text: str, **kwargs):
|
||||||
|
"""Write command to bridge AND push to gateway (if gateway mode)."""
|
||||||
|
self.bridge.write_command(project, text, **kwargs)
|
||||||
|
if self.gateway:
|
||||||
|
import time
|
||||||
|
self.gateway.push_command(project, {
|
||||||
|
"id": str(int(time.time() * 1000)),
|
||||||
|
"text": text,
|
||||||
|
"project_name": kwargs.get('project_name', project),
|
||||||
|
})
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _make_channel_name(project_name: str) -> str:
|
def _make_channel_name(project_name: str) -> str:
|
||||||
@@ -202,7 +214,7 @@ class GravityBot(commands.Bot):
|
|||||||
if not project:
|
if not project:
|
||||||
await interaction.response.send_message("⚠️ 프로젝트 채널이 아닙니다.", ephemeral=True)
|
await interaction.response.send_message("⚠️ 프로젝트 채널이 아닙니다.", ephemeral=True)
|
||||||
return
|
return
|
||||||
self.bridge.write_command(project, "!stop", project_name=project)
|
self._write_command(project, "!stop", project_name=project)
|
||||||
await interaction.response.send_message(
|
await interaction.response.send_message(
|
||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
title="⏹️ AI 작업 중지",
|
title="⏹️ AI 작업 중지",
|
||||||
@@ -224,7 +236,7 @@ class GravityBot(commands.Bot):
|
|||||||
else:
|
else:
|
||||||
self.auto_approve_projects.add(project)
|
self.auto_approve_projects.add(project)
|
||||||
enabled = True
|
enabled = True
|
||||||
self.bridge.write_command(project, f"!auto {'on' if enabled else 'off'}", project_name=project)
|
self._write_command(project, f"!auto {'on' if enabled else 'off'}", project_name=project)
|
||||||
emoji = "🟢" if enabled else "🔴"
|
emoji = "🟢" if enabled else "🔴"
|
||||||
await interaction.response.send_message(
|
await interaction.response.send_message(
|
||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
@@ -240,7 +252,7 @@ class GravityBot(commands.Bot):
|
|||||||
if not project:
|
if not project:
|
||||||
await interaction.response.send_message("⚠️ 프로젝트 채널이 아닙니다.", ephemeral=True)
|
await interaction.response.send_message("⚠️ 프로젝트 채널이 아닙니다.", ephemeral=True)
|
||||||
return
|
return
|
||||||
self.bridge.write_command(project, message, project_name=project)
|
self._write_command(project, message, project_name=project)
|
||||||
await interaction.response.send_message(
|
await interaction.response.send_message(
|
||||||
embed=discord.Embed(
|
embed=discord.Embed(
|
||||||
description=f"📨 → **{project}** IDE에 전달됨\n`{message[:100]}`",
|
description=f"📨 → **{project}** IDE에 전달됨\n`{message[:100]}`",
|
||||||
@@ -754,7 +766,7 @@ class GravityBot(commands.Bot):
|
|||||||
|
|
||||||
# Special command: !stop — cancel AI work
|
# Special command: !stop — cancel AI work
|
||||||
if text == "!stop":
|
if text == "!stop":
|
||||||
self.bridge.write_command(project, "!stop", project_name=project)
|
self._write_command(project, "!stop", project_name=project)
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
title="⏹️ AI 작업 중지",
|
title="⏹️ AI 작업 중지",
|
||||||
description=f"프로젝트: **{project}**\n중지 요청을 Extension에 전달했습니다.",
|
description=f"프로젝트: **{project}**\n중지 요청을 Extension에 전달했습니다.",
|
||||||
@@ -772,7 +784,7 @@ class GravityBot(commands.Bot):
|
|||||||
else:
|
else:
|
||||||
self.auto_approve_projects.add(project)
|
self.auto_approve_projects.add(project)
|
||||||
enabled = True
|
enabled = True
|
||||||
self.bridge.write_command(project, f"!auto {'on' if enabled else 'off'}", project_name=project)
|
self._write_command(project, f"!auto {'on' if enabled else 'off'}", project_name=project)
|
||||||
emoji = "🟢" if enabled else "🔴"
|
emoji = "🟢" if enabled else "🔴"
|
||||||
mode = "자동 승인" if enabled else "수동 승인"
|
mode = "자동 승인" if enabled else "수동 승인"
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
@@ -786,7 +798,7 @@ class GravityBot(commands.Bot):
|
|||||||
|
|
||||||
# General text relay — routed by project
|
# General text relay — routed by project
|
||||||
if text:
|
if text:
|
||||||
self.bridge.write_command(project, text, project_name=project)
|
self._write_command(project, text, project_name=project)
|
||||||
await message.add_reaction("📨")
|
await message.add_reaction("📨")
|
||||||
embed = discord.Embed(
|
embed = discord.Embed(
|
||||||
description=f"📨 → **{project}** IDE에 전달됨\n`{text[:100]}`",
|
description=f"📨 → **{project}** IDE에 전달됨\n`{text[:100]}`",
|
||||||
|
|||||||
52
collector.py
52
collector.py
@@ -50,6 +50,8 @@ class CollectorBridge:
|
|||||||
self._forward_pending_loop(),
|
self._forward_pending_loop(),
|
||||||
self._poll_responses_loop(),
|
self._poll_responses_loop(),
|
||||||
self._poll_commands_loop(),
|
self._poll_commands_loop(),
|
||||||
|
self._forward_chat_snapshots_loop(),
|
||||||
|
self._forward_registrations_loop(),
|
||||||
]
|
]
|
||||||
if self.event_queue:
|
if self.event_queue:
|
||||||
tasks.append(self._forward_events_loop())
|
tasks.append(self._forward_events_loop())
|
||||||
@@ -132,6 +134,56 @@ class CollectorBridge:
|
|||||||
|
|
||||||
await asyncio.sleep(self._poll_interval)
|
await asyncio.sleep(self._poll_interval)
|
||||||
|
|
||||||
|
# ─── Forward chat snapshots → Gateway ───
|
||||||
|
|
||||||
|
async def _forward_chat_snapshots_loop(self):
|
||||||
|
"""Forward chat_snapshots/ from Extension to Gateway."""
|
||||||
|
while self._running:
|
||||||
|
try:
|
||||||
|
snap_dir = self.local.bridge_dir / "chat_snapshots"
|
||||||
|
if snap_dir.exists():
|
||||||
|
for f in snap_dir.glob("*.json"):
|
||||||
|
try:
|
||||||
|
data = json.loads(f.read_text(encoding="utf-8-sig"))
|
||||||
|
project = data.get("project_name", self.project_name)
|
||||||
|
content = data.get("content", "")
|
||||||
|
if content:
|
||||||
|
self.remote.send_chat(project, content)
|
||||||
|
logger.info(f"[COLLECTOR] → Gateway: chat snapshot len={len(content)}")
|
||||||
|
f.unlink() # Cleanup after forwarding
|
||||||
|
except (json.JSONDecodeError, OSError) as e:
|
||||||
|
logger.warning(f"[COLLECTOR] bad chat snapshot {f.name}: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"[COLLECTOR] forward_chat_snapshots error: {e}")
|
||||||
|
|
||||||
|
await asyncio.sleep(self._poll_interval)
|
||||||
|
|
||||||
|
# ─── Forward session registrations → Gateway ───
|
||||||
|
|
||||||
|
async def _forward_registrations_loop(self):
|
||||||
|
"""Forward register/ files from Extension to Gateway."""
|
||||||
|
forwarded_regs: set[str] = set()
|
||||||
|
while self._running:
|
||||||
|
try:
|
||||||
|
register_dir = self.local.bridge_dir / "register"
|
||||||
|
if register_dir.exists():
|
||||||
|
for f in register_dir.glob("*.json"):
|
||||||
|
if f.name in forwarded_regs:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
data = json.loads(f.read_text(encoding="utf-8-sig"))
|
||||||
|
conv_id = data.get("conversation_id", "")
|
||||||
|
project = data.get("project_name", "")
|
||||||
|
if conv_id and project:
|
||||||
|
self.remote.register_session(conv_id, project)
|
||||||
|
forwarded_regs.add(f.name)
|
||||||
|
logger.info(f"[COLLECTOR] → Gateway: register {conv_id[:8]} → {project}")
|
||||||
|
except (json.JSONDecodeError, OSError) as e:
|
||||||
|
logger.warning(f"[COLLECTOR] bad register {f.name}: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"[COLLECTOR] forward_registrations error: {e}")
|
||||||
|
|
||||||
|
await asyncio.sleep(self._poll_interval * 3) # Less frequent
|
||||||
# ─── Forward brain events → Gateway ───
|
# ─── Forward brain events → Gateway ───
|
||||||
|
|
||||||
async def _forward_events_loop(self):
|
async def _forward_events_loop(self):
|
||||||
|
|||||||
1
main.py
1
main.py
@@ -107,6 +107,7 @@ async def main():
|
|||||||
from gateway import GatewayAPI
|
from gateway import GatewayAPI
|
||||||
gateway_port = int(os.environ.get('GATEWAY_PORT', '8585'))
|
gateway_port = int(os.environ.get('GATEWAY_PORT', '8585'))
|
||||||
gateway = GatewayAPI(bot, port=gateway_port, api_key=Config.GATEWAY_API_KEY)
|
gateway = GatewayAPI(bot, port=gateway_port, api_key=Config.GATEWAY_API_KEY)
|
||||||
|
bot.gateway = gateway # Enable _write_command → gateway.push_command
|
||||||
await gateway.start()
|
await gateway.start()
|
||||||
logger.info(f"Gateway API running on port {gateway_port}")
|
logger.info(f"Gateway API running on port {gateway_port}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user