Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ cmd/mysql-cli/main -> cli(cobra 装配 + 退出码映射 + config 子命令

配置文件:`~/.config/mysql-cli/config.toml`(`--config` 可覆盖)。数据源用 `[datasource.<name>]`,顶层 `default` 指定默认;SSH 隧道用 `[datasource.<name>.ssh]` 子表。完整示例见 `README.md`。

子命令与 flag 语义见 `README.md`(`query/txn/schema/sample/tables/databases/read/explore/analyze`,及 `--write/--ddl/--yes/--limit/--timeout/-f`)。默认只读;DML 需 `--write`,DDL 需 `--write --ddl`,`DROP/TRUNCATE` 及无 `WHERE` 的 `UPDATE/DELETE` 需 `--yes`。
子命令与 flag 语义见 `README.md`(`query/txn/schema/sample/tables/databases/read/explore/analyze`,及 `--write/--ddl/--yes/--limit/--timeout/-f`)。默认只读;DML 需 `--write`,DDL 需 `--write --ddl`,`DROP/TRUNCATE` 及无 `WHERE` 的 `UPDATE/DELETE` 需 `--yes`。运行任何写操作(含 `--write`/`--ddl`/`--yes`)前应提示用户确认;`--yes` 是标记破坏性操作而非豁免。各 agent 的强制确认配置见 `docs/agent-integration.md`。

## Skill 体系(对接 AI agent)

Expand All @@ -81,3 +81,11 @@ mysql-cli 的 skill 不再自研安装,而是接入 [vercel-labs/skills](https:/
- **格式校验**:`scripts/skill-format-check.sh` 校验 SKILL.md frontmatter(name/version/description/metadata + semver),CI `.github/workflows/skill-format-check.yml` PR 时强制。改 skill 后本地跑一遍。
- **版本真相源**:skill 版本 = 仓库 `skills/*/SKILL.md` frontmatter 的 `version` 字段(不再二进制内嵌)。
- **无 Node fallback**:手动复制仓库 `skills/` 目录到 agent skill 目录。

## 写操作人类确认(agent init)

`--write`/`--ddl`/`--yes` 是 AI 自传的 flag,CLI 内部无人类确认环节。`mysql-cli agent init` 为各 agent 安装配置,在写操作执行前弹窗找人类确认(命中 `--write`/`--ddl`/`--yes` 即拦,只读放行)。

- **命令**:`mysql-cli agent init`(交互式选 agent + 层级);非交互 `mysql-cli agent init --agents claude,opencode,copilot --project`。
- **支持**:claude / cursor / opencode / copilot / codebuddy。不含 Codex(hook 未坐实)、TRAE(规则文件格式未坐实)。
- **实现**:配置模板内嵌于二进制 `internal/agentsetup/templates/`;合并类配置(settings.json/opencode.json/.vscode/settings.json)深合并进现有文件并备份 `.bak`,幂等。详见 `docs/agent-integration.md`。
20 changes: 20 additions & 0 deletions README-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@

#### 安装

**一键脚本**(二进制 + skills + 各 agent 写操作确认配置):

```bash
curl -fsSL https://raw.githubusercontent.com/AllenMuu/mysql-cli/main/install.sh -o install.sh
bash install.sh # macOS/Linux;直接运行而非 curl|bash,以保留交互提示
# Windows: .\install.ps1 (仓库根目录)
```

**方式一 - `npx`(推荐,无需 Go 工具链):**

```bash
Expand Down Expand Up @@ -248,6 +256,18 @@ ssl_mode = "REQUIRED"
标识符按严格白名单校验(`^[a-zA-Z0-9_$]+$`);多语句输入被拒绝(请用 `txn`)。
只读 / 多语句检查在**打开连接之前**执行,因此 agent 无需触碰数据库即可拿到正确退出码。

### 写操作的人类确认

`--write`/`--yes` 是 AI 自己传的 flag,CLI 自身无法把人类拉进确认环节。`mysql-cli agent init` 为各 agent 安装配置,在写操作执行前弹窗找人类确认:

```bash
mysql-cli agent init # 交互式:选 agent + 层级
mysql-cli agent init --agents claude,opencode,copilot --project
mysql-cli agent init --agents codebuddy --global
```

支持 Claude Code、Cursor、opencode、GitHub Copilot、CodeBuddy。能力对照与各 agent 写入路径见 [`docs/agent-integration.md`](./docs/agent-integration.md)。

## SSH 隧道

数据源可以通过 SSH 堡垒机建立隧道,而非直连:
Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ binary with **JSON by default** and **stable exit codes**, so any agent

#### Install

**One-shot installer** (binary + skills + per-agent write-confirmation configs):

```bash
curl -fsSL https://raw.githubusercontent.com/AllenMuu/mysql-cli/main/install.sh -o install.sh
bash install.sh # macOS/Linux; run directly so prompts work (not curl|bash)
# Windows: .\install.ps1 (in repo root)
```

**Option 1 - `npx` (recommended, no Go toolchain needed):**

```bash
Expand Down Expand Up @@ -260,6 +268,22 @@ multi-statement input is rejected (use `txn`). The read-only / multi-statement
checks run **before** a connection is opened, so agents get the right exit code
without touching the database.

### Human confirmation for writes

`--write`/`--yes` are flags the AI passes itself, so the CLI alone can't pull a
human into the loop. `mysql-cli agent init` installs per-agent configs that
prompt a human before any write runs:

```bash
mysql-cli agent init # interactive: pick agents + scope
mysql-cli agent init --agents claude,opencode,copilot --project
mysql-cli agent init --agents codebuddy --global
```

Supports Claude Code, Cursor, opencode, GitHub Copilot, CodeBuddy. See
[`docs/agent-integration.md`](./docs/agent-integration.md) for the capability
matrix and per-agent install paths.

## SSH tunnel

A datasource can tunnel through an SSH bastion instead of connecting directly:
Expand Down
65 changes: 65 additions & 0 deletions docs/agent-integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# 多 Agent 写操作确认

mysql-cli 默认只读;写操作由 `--write`/`--ddl`/`--yes` 解锁。但这些 flag 是 AI 在命令行里自己传的--`--yes` 原义是“AI 已确认”,不是“找人类确认”。`mysql-cli agent init` 把写操作的确认权从 AI 手里拿回给人类:为各 agent 安装配置,命中写 flag 即弹窗,由用户批准才执行。

## 安装

```bash
mysql-cli agent init
```

交互式选择你用的 agent + 层级(项目/全局)。非交互环境用 flag:

```bash
mysql-cli agent init --agents claude,opencode,copilot --project
mysql-cli agent init --agents codebuddy --global
mysql-cli agent init --agents cursor --project --dry-run # 预览不写
```

支持的 agent(逗号分隔):`claude` `cursor` `opencode` `copilot` `codebuddy`。

## 能力对照

| Agent | name | 能力 | 机制 |
|---|---|---|---|
| Claude Code | `claude` | 精确强制 | PreToolUse hook -> `ask` |
| opencode | `opencode` | 精确强制 | `permission.bash` glob + `ask` |
| GitHub Copilot | `copilot` | 精确强制 | `autoApprove` 正则 `false` |
| CodeBuddy | `codebuddy` | 精确强制 | PreToolUse hook(兼容 Claude Code) |
| Cursor | `cursor` | 仅引导 | `.cursor/rules` 注入上下文 |

> “精确”= 只对含 `--write`/`--ddl`/`--yes` 的命令弹窗,只读放行;“仅引导”= 依赖模型遵守规则,非引擎级闸门。
> 不含 Codex(hook 未坐实,`.rules` 无法按 flag 精确拦)、TRAE(规则文件格式未坐实)。

## 写入位置

| Agent | 项目级(`--project`) | 全局(`--global`) |
|---|---|---|
| claude | `.claude/settings.json` + `.claude/hooks/mysql-write-guard.py` | `~/.claude/...` |
| cursor | `.cursor/rules/mysql-cli-write-guard.mdc` | 不支持(IDE 设置) |
| opencode | `opencode.json` | `~/.config/opencode/opencode.json` |
| copilot | `.vscode/settings.json` + `.github/copilot-instructions.md` | VS Code 用户 `settings.json` |
| codebuddy | `.codebuddy/settings.json` + `.codebuddy/hooks/mysql-write-guard.py` | `~/.codebuddy/...` |

合并类配置(`settings.json` / `opencode.json` / `.vscode/settings.json`)会深合并进现有文件并备份 `.bak`,不破坏既有内容;重复安装会按 command/键去重,幂等。单文件类(`.mdc` / instructions / `.md`)默认跳过已存在文件,`--force` 覆盖。

## 验证

每个 agent 配置后,新会话里让 AI 跑两条对照:

- 只读(应**放行**):`mysql-cli query "SELECT 1"`
- 写操作(应**弹窗**):`mysql-cli query "UPDATE t SET a=1 WHERE id=1" --write`

hook 脚本可单独测:
```bash
echo '{"tool_name":"Bash","tool_input":{"command":"mysql-cli query \"DROP TABLE x\" --write --yes"}}' \
| python3 .codebuddy/hooks/mysql-write-guard.py
# 期望: {"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"ask",...}}
```

## 原理

- `--yes` 是 AI 传的 flag,CLI 内部无人类确认环节;`agent init` 装的配置在 agent 执行命令前拦截,把含 `--write`/`--ddl`/`--yes` 的执行交给人类弹窗批准。
- hook 脚本用 shlex 精确匹配 flag token,SQL 字面量里的 `--write` 文本不会误伤;回退正则只认独立 token,兼容 `bash -c` 包裹。
- CodeBuddy / Claude Code 依赖其兼容 Claude Code PreToolUse hook(CodeBuddy 已交叉验证;若某版本不认 `ask` JSON,回退 `exit 2` 阻断)。
- 配置模板内嵌于 mysql-cli 二进制(`internal/agentsetup/templates/`),随版本发布;升级 mysql-cli 后重跑 `agent init` 即可刷新。
78 changes: 78 additions & 0 deletions install.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# mysql-cli one-shot installer (Windows / PowerShell):
# 1) download the mysql-cli binary from the latest GitHub release
# 2) install agent skills via `npx skills add`
# 3) install per-agent write-confirmation configs via `mysql-cli agent init`
#
# Run in PowerShell (allow execution for this session):
# Set-ExecutionPolicy -Scope Process Bypass -Force
# .\install.ps1
$ErrorActionPreference = "Stop"

$Repo = "AllenMuu/mysql-cli"
$InstallDir = if ($env:MYSQL_CLI_INSTALL_DIR) { $env:MYSQL_CLI_INSTALL_DIR } else { Join-Path $env:USERPROFILE ".local\bin" }

function Info($m) { Write-Host "==> $m" -ForegroundColor Blue }
function Ok($m) { Write-Host "OK $m" -ForegroundColor Green }
function Warn($m) { Write-Host "!! $m" -ForegroundColor Yellow }
function Err($m) { Write-Host "XX $m" -ForegroundColor Red }

# ---- 1. binary from the latest GitHub release ----
Info "Installing mysql-cli binary from latest release..."
$Arch = switch ($env:PROCESSOR_ARCHITECTURE) {
"ARM64" { "arm64" }
default { "amd64" }
}
$Archive = "mysql-cli_windows_$Arch.zip"
$Url = "https://github.com/$Repo/releases/latest/download/$Archive"
$Tmp = Join-Path ([IO.Path]::GetTempPath()) ("mysql-cli-" + [guid]::NewGuid().ToString())
New-Item -ItemType Directory -Force -Path $Tmp | Out-Null
try {
try {
Invoke-WebRequest -Uri $Url -OutFile (Join-Path $Tmp $Archive) -UseBasicParsing
} catch {
Err "download failed: $Url"
Err "alternative: go install github.com/AllenMuu/mysql-cli/cmd/mysql-cli@latest"
exit 1
}
Expand-Archive -Path (Join-Path $Tmp $Archive) -DestinationPath $Tmp -Force
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
Move-Item -Force (Join-Path $Tmp "mysql-cli.exe") (Join-Path $InstallDir "mysql-cli.exe")
Ok "binary -> $(Join-Path $InstallDir 'mysql-cli.exe')"
} finally {
Remove-Item -Recurse -Force $Tmp -ErrorAction SilentlyContinue
}
$Bin = Join-Path $InstallDir "mysql-cli.exe"

if ($env:PATH -notlike "*$InstallDir*") {
Warn "$InstallDir not in PATH; add it or invoke via full path."
}

# ---- 2. agent skills ----
Info "Installing skills (npx skills add)..."
if (Get-Command npx -ErrorAction SilentlyContinue) {
if (-not [Console]::IsInputRedirected) {
npx --yes skills add AllenMuu/mysql-cli
} else {
Warn "non-interactive shell; run later: npx skills add AllenMuu/mysql-cli"
}
} else {
Warn "npx not found; install Node, then: npx skills add AllenMuu/mysql-cli"
}

# ---- 3. per-agent write-confirmation configs ----
Info "Installing write-confirmation configs (agent init)..."
& $Bin agent init --help 2>$null | Out-Null
if ($LASTEXITCODE -eq 0) {
if (-not [Console]::IsInputRedirected) {
& $Bin agent init
} else {
Warn "non-interactive shell; run later: $Bin agent init"
}
} else {
Warn "this release has no 'agent init' (needs v2.1+); re-run after upgrading."
Warn "manual configs: https://github.com/$Repo/blob/main/docs/agent-integration.md"
}

Write-Host ""
Ok "Done. Next: $Bin config init --global # then edit ~/.config/mysql-cli/config.toml"
Ok "Verify: $Bin query 'SELECT 1'"
81 changes: 81 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env bash
# mysql-cli one-shot installer (macOS / Linux):
# 1) download the mysql-cli binary from the latest GitHub release
# 2) install agent skills via `npx skills add`
# 3) install per-agent write-confirmation configs via `mysql-cli agent init`
#
# Run it directly, not via `curl | bash`, so the interactive skills and
# agent-init prompts keep their TTY:
# curl -fsSL https://raw.githubusercontent.com/AllenMuu/mysql-cli/main/install.sh -o install.sh
# bash install.sh
set -euo pipefail

REPO="AllenMuu/mysql-cli"
INSTALL_DIR="${MYSQL_CLI_INSTALL_DIR:-$HOME/.local/bin}"

c_info() { printf '\033[1;34m==>\033[0m %s\n' "$1"; }
c_ok() { printf '\033[1;32mOK\033[0m %s\n' "$1"; }
c_warn() { printf '\033[1;33m!!\033[0m %s\n' "$1"; }
c_err() { printf '\033[1;31mXX\033[0m %s\n' "$1" >&2; }

# ---- 1. binary from the latest GitHub release ----
c_info "Installing mysql-cli binary from latest release..."
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
case "$ARCH" in
x86_64|amd64) ARCH=amd64 ;;
arm64|aarch64) ARCH=arm64 ;;
*) c_err "unsupported architecture: $ARCH"; exit 1 ;;
esac
case "$OS" in
darwin|linux) EXT=tar.gz ;;
*) c_err "unsupported OS: $OS (on Windows use install.ps1)"; exit 1 ;;
esac
ARCHIVE="mysql-cli_${OS}_${ARCH}.${EXT}"
URL="https://github.com/${REPO}/releases/latest/download/${ARCHIVE}"
TMP=$(mktemp -d); trap 'rm -rf "$TMP"' EXIT
if ! curl -fsSL "$URL" -o "$TMP/$ARCHIVE"; then
c_err "download failed: $URL"
c_err "alternative: go install github.com/AllenMuu/mysql-cli/cmd/mysql-cli@latest"
exit 1
fi
tar -xzf "$TMP/$ARCHIVE" -C "$TMP"
mkdir -p "$INSTALL_DIR"
mv -f "$TMP/mysql-cli" "$INSTALL_DIR/mysql-cli"
chmod +x "$INSTALL_DIR/mysql-cli"
c_ok "binary -> $INSTALL_DIR/mysql-cli"

case ":$PATH:" in
*":$INSTALL_DIR:"*) ;;
*) c_warn "$INSTALL_DIR not in PATH. Add: export PATH=\"$INSTALL_DIR:\$PATH\"" ;;
esac
BIN="$INSTALL_DIR/mysql-cli"

# ---- 2. agent skills ----
c_info "Installing skills (npx skills add)..."
if command -v npx >/dev/null 2>&1; then
if [ -t 0 ]; then
npx --yes skills add AllenMuu/mysql-cli || c_warn "skills install incomplete (non-fatal)"
else
c_warn "non-interactive shell; run later: npx skills add AllenMuu/mysql-cli"
fi
else
c_warn "npx not found; install Node, then: npx skills add AllenMuu/mysql-cli"
fi

# ---- 3. per-agent write-confirmation configs ----
c_info "Installing write-confirmation configs (agent init)..."
if "$BIN" agent init --help >/dev/null 2>&1; then
if [ -t 0 ]; then
"$BIN" agent init || c_warn "agent init incomplete (non-fatal)"
else
c_warn "non-interactive shell; run later: $BIN agent init"
fi
else
c_warn "this release has no 'agent init' (needs v2.1+); re-run this script after upgrading."
c_warn "manual configs: https://github.com/${REPO}/blob/main/docs/agent-integration.md"
fi

echo
c_ok "Done. Next: $BIN config init --global # then edit ~/.config/mysql-cli/config.toml"
c_ok "Verify: $BIN query 'SELECT 1'"
Loading
Loading