feat: add default permission mode + rename accept→edit

- Add "default" permission mode: no flags passed to CC, uses its own
  built-in default (asks about everything). Now the system default.
- Rename "accept" alias to "edit" (acceptEdits) for clarity
- Remove "skip" alias (duplicate of "bypass")
- Update all help text, error messages, tests, and LLM prompts

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yuyao Huang (Sam) 2026-03-30 01:54:32 +08:00
parent 9c04d47c8e
commit b707fa84f9
5 changed files with 37 additions and 33 deletions

View File

@ -18,12 +18,13 @@ def strip_ansi(text: str) -> str:
PERMISSION_MODE_FLAGS: dict[str, list[str]] = { PERMISSION_MODE_FLAGS: dict[str, list[str]] = {
"bypassPermissions": ["--dangerously-skip-permissions"], "default": [], # CC's own default: asks about everything
"acceptEdits": ["--permission-mode", "acceptEdits"], "acceptEdits": ["--permission-mode", "acceptEdits"],
"plan": ["--permission-mode", "plan"], "plan": ["--permission-mode", "plan"],
"bypassPermissions": ["--dangerously-skip-permissions"],
} }
VALID_PERMISSION_MODES = list(PERMISSION_MODE_FLAGS) VALID_PERMISSION_MODES = list(PERMISSION_MODE_FLAGS)
DEFAULT_PERMISSION_MODE = "bypassPermissions" DEFAULT_PERMISSION_MODE = "default"
async def run_claude( async def run_claude(

View File

@ -20,14 +20,15 @@ logger = logging.getLogger(__name__)
# Permission mode aliases (user-facing shorthand → internal CC mode) # Permission mode aliases (user-facing shorthand → internal CC mode)
_PERM_ALIASES: dict[str, str] = { _PERM_ALIASES: dict[str, str] = {
"bypass": "bypassPermissions", "bypass": "bypassPermissions",
"skip": "bypassPermissions", "default": "default",
"accept": "acceptEdits", "edit": "acceptEdits",
"plan": "plan", "plan": "plan",
} }
_PERM_LABELS: dict[str, str] = { _PERM_LABELS: dict[str, str] = {
"default": "default",
"bypassPermissions": "bypass", "bypassPermissions": "bypass",
"acceptEdits": "accept", "acceptEdits": "edit",
"plan": "plan", "plan": "plan",
} }
@ -113,14 +114,14 @@ async def handle_command(user_id: str, text: str) -> Optional[str]:
async def _cmd_new(user_id: str, args: str) -> str: async def _cmd_new(user_id: str, args: str) -> str:
"""Create a new session.""" """Create a new session."""
if not args: if not args:
return "Usage: /new <project_dir> [initial_message] [--timeout N] [--perm MODE]\nModes: bypass (default), accept, plan" return "Usage: /new <project_dir> [initial_message] [--timeout N] [--perm MODE]\nModes: default, edit, plan, bypass"
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("working_dir", nargs="?", help="Project directory") parser.add_argument("working_dir", nargs="?", help="Project directory")
parser.add_argument("rest", nargs="*", help="Initial message") parser.add_argument("rest", nargs="*", help="Initial message")
parser.add_argument("--timeout", type=int, default=None, help="CC timeout in seconds") parser.add_argument("--timeout", type=int, default=None, help="CC timeout in seconds")
parser.add_argument("--idle", type=int, default=None, help="Idle timeout in seconds") parser.add_argument("--idle", type=int, default=None, help="Idle timeout in seconds")
parser.add_argument("--perm", default=None, help="Permission mode: bypass, accept, plan") parser.add_argument("--perm", default=None, help="Permission mode: default, edit, plan, bypass")
try: try:
parsed = parser.parse_args(args.split()) parsed = parser.parse_args(args.split())
@ -132,7 +133,7 @@ async def _cmd_new(user_id: str, args: str) -> str:
permission_mode = _resolve_perm(parsed.perm) if parsed.perm else DEFAULT_PERMISSION_MODE permission_mode = _resolve_perm(parsed.perm) if parsed.perm else DEFAULT_PERMISSION_MODE
if permission_mode is None: if permission_mode is None:
return f"Invalid --perm. Valid modes: bypass, accept, plan" return f"Invalid --perm. Valid modes: default, edit, plan, bypass"
working_dir = parsed.working_dir working_dir = parsed.working_dir
initial_msg = " ".join(parsed.rest) if parsed.rest else None initial_msg = " ".join(parsed.rest) if parsed.rest else None
@ -288,10 +289,11 @@ async def _cmd_perm(user_id: str, args: str) -> str:
if not parts: if not parts:
return ( return (
"Usage: /perm <mode> [conv_id]\n" "Usage: /perm <mode> [conv_id]\n"
"Modes: bypass (default), accept, plan\n" "Modes: default, edit, plan, bypass\n"
" bypass — skip all permission checks\n" " default — default mode\n"
" accept — auto-accept file edits, confirm shell commands\n" " edit — auto-accept file edits, confirm shell commands\n"
" plan — plan only, no writes" " plan — plan only, no writes\n"
" bypass — skip all permission checks"
) )
alias = parts[0] alias = parts[0]
@ -299,7 +301,7 @@ async def _cmd_perm(user_id: str, args: str) -> str:
permission_mode = _resolve_perm(alias) permission_mode = _resolve_perm(alias)
if permission_mode is None: if permission_mode is None:
return f"Unknown mode '{alias}'. Valid: bypass, accept, plan" return f"Unknown mode '{alias}'. Valid: default, edit, plan, bypass"
if not conv_id: if not conv_id:
return "No active session. Use `//perm <mode> <conv_id>` or activate a session first." return "No active session. Use `//perm <mode> <conv_id>` or activate a session first."
@ -442,7 +444,7 @@ def _cmd_help() -> str:
{P}status - Show sessions and current mode {P}status - Show sessions and current mode
{P}close [n] - Close session (active or by number) {P}close [n] - Close session (active or by number)
{P}switch <n> - Switch to session by number {P}switch <n> - Switch to session by number
{P}perm <mode> [conv_id] - Set permission mode (bypass/accept/plan) {P}perm <mode> [conv_id] - Set permission mode (default/edit/plan/bypass)
{P}direct - Direct mode: messages Claude Code (no LLM overhead) {P}direct - Direct mode: messages Claude Code (no LLM overhead)
{P}smart - Smart mode: messages LLM routing (default) {P}smart - Smart mode: messages LLM routing (default)
{P}shell <cmd> - Run shell command (bypasses LLM) {P}shell <cmd> - Run shell command (bypasses LLM)
@ -454,9 +456,10 @@ def _cmd_help() -> str:
{P}help - Show this help {P}help - Show this help
**Permission modes** (used by {P}perm and {P}new --perm): **Permission modes** (used by {P}perm and {P}new --perm):
bypass 跳过所有权限确认CC 自动执行一切操作默认 default 默认模式遇到文件编辑操作时手动确认
适合受信任的沙盒环境自动化任务 edit 自动接受文件编辑 shell 命令仍需手动确认
accept 自动接受文件编辑 shell 命令仍需手动确认
适合日常开发需要对命令执行保持控制 适合日常开发需要对命令执行保持控制
plan 只规划不执行任何写操作 plan 只规划不执行任何写操作
适合先预览 CC 的操作计划再决定是否执行""" 适合先预览 CC 的操作计划再决定是否执行
bypass 跳过所有权限确认CC 自动执行一切操作
适合受信任的沙盒环境自动化任务"""

View File

@ -53,10 +53,10 @@ Bot command prefix: {prefix}
- Any other command the user would type manually - Any other command the user would type manually
Available bot commands (pass verbatim to run_command): Available bot commands (pass verbatim to run_command):
{prefix}new <dir> [msg] [--perm bypass|accept|plan] create session {prefix}new <dir> [msg] [--perm default|edit|plan|bypass] create session
{prefix}close [n|conv_id] close session {prefix}close [n|conv_id] close session
{prefix}switch <n> switch active session {prefix}switch <n> switch active session
{prefix}perm <mode> [conv_id] permission mode: bypass (default), accept, plan {prefix}perm <mode> [conv_id] permission mode: default, edit, plan, bypass
{prefix}direct direct mode (bypass LLM for CC messages) {prefix}direct direct mode (bypass LLM for CC messages)
{prefix}smart smart mode (LLM routing, default) {prefix}smart smart mode (LLM routing, default)
{prefix}status list sessions {prefix}status list sessions

View File

@ -720,7 +720,7 @@ class RunCommandInput(BaseModel):
command: str = Field( command: str = Field(
..., ...,
description=( description=(
"A bot slash command to execute (e.g. '/perm accept', '/close 1', '/switch 2'). " "A bot slash command to execute (e.g. '//perm edit', '//close 1', '//switch 2'). "
"This runs bot control commands — NOT shell commands on the host machine. " "This runs bot control commands — NOT shell commands on the host machine. "
"Use run_shell for host shell commands (git, ls, etc.)." "Use run_shell for host shell commands (git, ls, etc.)."
), ),
@ -732,7 +732,7 @@ class RunCommandTool(BaseTool):
description: str = ( description: str = (
"Execute a PhoneWork bot slash command on behalf of the user. " "Execute a PhoneWork bot slash command on behalf of the user. "
"Use this to control sessions, switch modes, change permissions, etc. " "Use this to control sessions, switch modes, change permissions, etc. "
"Examples: '/perm accept', '/close 1', '/switch 2', '/direct', '/smart', '/status'. " "Examples: '/perm edit', '/close 1', '/switch 2', '/direct', '/smart', '/status'. "
"Do NOT use this for shell commands — use run_shell for those." "Do NOT use this for shell commands — use run_shell for those."
) )
args_schema: Type[BaseModel] = RunCommandInput args_schema: Type[BaseModel] = RunCommandInput

View File

@ -7,14 +7,14 @@ Feature: /perm command — change session permission mode
When user sends "/perm" When user sends "/perm"
Then reply contains "Usage" Then reply contains "Usage"
And reply contains "bypass" And reply contains "bypass"
And reply contains "accept" And reply contains "edit"
And reply contains "plan" And reply contains "plan"
Scenario: Set active session to accept mode Scenario: Set active session to edit mode
Given user has session "sess01" in "/tmp/proj1" Given user has session "sess01" in "/tmp/proj1"
And active session is "sess01" And active session is "sess01"
When user sends "/perm accept" When user sends "/perm edit"
Then reply contains "accept" Then reply contains "edit"
And reply contains "sess01" And reply contains "sess01"
And session "sess01" has permission mode "acceptEdits" And session "sess01" has permission mode "acceptEdits"
@ -40,7 +40,7 @@ Feature: /perm command — change session permission mode
Scenario: No active session returns error Scenario: No active session returns error
Given no active session for user "user_abc123" Given no active session for user "user_abc123"
When user sends "/perm accept" When user sends "/perm edit"
Then reply contains "No active session" Then reply contains "No active session"
Scenario: Set permission on specific conv_id Scenario: Set permission on specific conv_id
@ -53,12 +53,12 @@ Feature: /perm command — change session permission mode
Scenario: Cannot change permission of another user's session Scenario: Cannot change permission of another user's session
Given session "sess01" in "/tmp/proj1" belongs to user "other_user" Given session "sess01" in "/tmp/proj1" belongs to user "other_user"
When user sends "/perm accept sess01" When user sends "/perm edit sess01"
Then reply contains "another user" Then reply contains "another user"
Scenario: New session with --perm accept Scenario: New session with --perm edit
When user sends "/new myproject --perm accept" When user sends "/new myproject --perm edit"
Then reply contains "accept" Then reply contains "edit"
And session manager has 1 session for user "user_abc123" And session manager has 1 session for user "user_abc123"
Scenario: New session with --perm plan Scenario: New session with --perm plan