feat(bot,bridge): P1 !auto 토글 자동승인 + P2 BridgeTransport 추상화 #task-304 #task-305
P1: !auto 토글 (bot.py + extension.ts)
- auto_approve_projects set으로 프로젝트별 상태 관리
- !auto → on/off 토글, pending 자동 승인 + 🤖 자동 승인됨 embed
- Extension step_probe에서 autoApproveEnabled 시 직접 tryApprovalStrategies
P2: BridgeTransport 추상화 (bridge.py)
- BridgeTransport ABC + LocalTransport (기존 동작 100% 호환)
- RemoteTransport 스켈레톤 (multi-PC 대비)
- config.py BOT_MODE/REMOTE_BRIDGE_URL, main.py transport 주입
docs: usage-guide.md + tech-stack.md Python 경로 기록
This commit is contained in:
62
bot.py
62
bot.py
@@ -179,6 +179,7 @@ class GravityBot(commands.Bot):
|
||||
self.bridge = BridgeProtocol()
|
||||
self.session_category: discord.CategoryChannel | None = None
|
||||
self.guild: discord.Guild | None = None
|
||||
self.auto_approve_projects: set[str] = set() # projects with auto-approve enabled
|
||||
|
||||
@staticmethod
|
||||
def _make_channel_name(project_name: str) -> str:
|
||||
@@ -211,12 +212,18 @@ class GravityBot(commands.Bot):
|
||||
)
|
||||
|
||||
@self.tree.command(name="auto", description="자동 승인 토글")
|
||||
async def slash_auto(interaction: discord.Interaction, mode: str):
|
||||
async def slash_auto(interaction: discord.Interaction):
|
||||
project = self.channel_to_project.get(interaction.channel_id)
|
||||
if not project:
|
||||
await interaction.response.send_message("⚠️ 프로젝트 채널이 아닙니다.", ephemeral=True)
|
||||
return
|
||||
enabled = mode.lower() in ("on", "true", "1")
|
||||
# Toggle
|
||||
if project in self.auto_approve_projects:
|
||||
self.auto_approve_projects.discard(project)
|
||||
enabled = False
|
||||
else:
|
||||
self.auto_approve_projects.add(project)
|
||||
enabled = True
|
||||
self.bridge.write_command(project, f"!auto {'on' if enabled else 'off'}", project_name=project)
|
||||
emoji = "🟢" if enabled else "🔴"
|
||||
await interaction.response.send_message(
|
||||
@@ -521,6 +528,35 @@ class GravityBot(commands.Bot):
|
||||
if req.discord_message_id != 0:
|
||||
continue
|
||||
|
||||
# Learn project mapping from pending approval
|
||||
project = req.project_name or Config.PROJECT_NAME
|
||||
if req.conversation_id and req.conversation_id != '__global__':
|
||||
self.conv_to_project[req.conversation_id] = project
|
||||
|
||||
# ── Auto-approve: if project has auto enabled, approve immediately ──
|
||||
if project in self.auto_approve_projects:
|
||||
self._sent_approval_ids.add(req.request_id)
|
||||
# Write auto-approve response for Extension
|
||||
self.bridge.write_response(UserResponse(
|
||||
request_id=req.request_id,
|
||||
approved=True,
|
||||
button_index=0, # first button (Allow Once / Run)
|
||||
step_type=getattr(req, 'step_type', ''),
|
||||
project_name=project,
|
||||
))
|
||||
# Show compact auto-approved embed in Discord
|
||||
channel = await self._get_channel(project)
|
||||
if channel:
|
||||
embed = discord.Embed(
|
||||
title="🤖 자동 승인됨",
|
||||
description=f"```\n{req.command[:500]}\n```",
|
||||
color=discord.Color.green(),
|
||||
)
|
||||
embed.set_footer(text=f"auto-approve | {req.request_id[:12]}")
|
||||
await channel.send(embed=embed)
|
||||
logger.info(f"Auto-approved: {req.request_id[:12]} project={project}")
|
||||
continue
|
||||
|
||||
# Defer short-command pendings (e.g. "Run") by 4 cycles (~12s)
|
||||
# to give step_probe time to merge detailed command info
|
||||
# (step_probe MERGE happens ~10s after pending creation)
|
||||
@@ -540,11 +576,6 @@ class GravityBot(commands.Bot):
|
||||
# Clean up defer tracking
|
||||
self._deferred_ids.pop(req.request_id, None)
|
||||
|
||||
# Learn project mapping from pending approval
|
||||
project = req.project_name or Config.PROJECT_NAME
|
||||
if req.conversation_id and req.conversation_id != '__global__':
|
||||
self.conv_to_project[req.conversation_id] = project
|
||||
|
||||
channel = await self._get_channel(project)
|
||||
if channel:
|
||||
self._sent_approval_ids.add(req.request_id)
|
||||
@@ -732,17 +763,22 @@ class GravityBot(commands.Bot):
|
||||
await message.channel.send(embed=embed)
|
||||
return
|
||||
|
||||
# Special command: !auto on/off
|
||||
if text in ("!auto on", "!auto off"):
|
||||
self.bridge.write_command(project, text, project_name=project)
|
||||
enabled = text == "!auto on"
|
||||
# Special command: !auto — toggle auto-approve
|
||||
if text == "!auto":
|
||||
# Toggle per-project auto-approve
|
||||
if project in self.auto_approve_projects:
|
||||
self.auto_approve_projects.discard(project)
|
||||
enabled = False
|
||||
else:
|
||||
self.auto_approve_projects.add(project)
|
||||
enabled = True
|
||||
self.bridge.write_command(project, f"!auto {'on' if enabled else 'off'}", project_name=project)
|
||||
emoji = "🟢" if enabled else "🔴"
|
||||
mode = "자동 승인" if enabled else "수동 승인"
|
||||
embed = discord.Embed(
|
||||
title=f"{emoji} {mode} 모드",
|
||||
description=f"프로젝트: **{project}**\n"
|
||||
f"`chat.tools.autoApprove = {enabled}`\n"
|
||||
f"`chat.agent.autoApprove = {enabled}`",
|
||||
f"모든 승인 요청이 {'자동으로 승인됩니다' if enabled else '수동 확인이 필요합니다'}",
|
||||
color=discord.Color.green() if enabled else discord.Color.red(),
|
||||
)
|
||||
await message.channel.send(embed=embed)
|
||||
|
||||
Reference in New Issue
Block a user