feat: delete 命令支持批量删除,--name 改为可选

省略 --name 时按 namespace(+ 可选 --kind)批量删除所有匹配记录;
支持 --dry-run 预览;删除前自动快照历史并写入审计日志。
移除独立的 delete-ns 子命令,合并为统一的 delete 入口。
更新 AGENTS.md 文档,版本 bump 至 0.9.3。

Made-with: Cursor
This commit is contained in:
voson
2026-03-19 16:31:18 +08:00
parent 66b6417faa
commit d0796e9c9a
5 changed files with 259 additions and 42 deletions

View File

@@ -211,23 +211,39 @@ EXAMPLES:
output: Option<String>,
},
/// Delete a record permanently. Requires exact namespace + kind + name.
/// Delete one record precisely, or bulk-delete by namespace.
///
/// With --name: deletes exactly that record (--kind also required).
/// Without --name: bulk-deletes all records matching namespace + optional --kind.
/// Use --dry-run to preview bulk deletes before committing.
#[command(after_help = "EXAMPLES:
# Delete a service credential
# Delete a single record (exact match)
secrets delete -n refining --kind service --name legacy-mqtt
# Delete a server record
secrets delete -n ricnsmart --kind server --name i-old-server-id")]
# Preview what a bulk delete would remove (no writes)
secrets delete -n refining --dry-run
# Bulk-delete all records in a namespace
secrets delete -n ricnsmart
# Bulk-delete only server records in a namespace
secrets delete -n ricnsmart --kind server
# JSON output
secrets delete -n refining --kind service -o json")]
Delete {
/// Namespace, e.g. refining
#[arg(short, long)]
namespace: String,
/// Kind, e.g. server, service
/// Kind filter, e.g. server, service (required with --name; optional for bulk)
#[arg(long)]
kind: String,
/// Exact name of the record to delete
kind: Option<String>,
/// Exact name of the record to delete (omit for bulk delete)
#[arg(long)]
name: String,
name: Option<String>,
/// Preview what would be deleted without making any changes (bulk mode only)
#[arg(long)]
dry_run: bool,
/// Output format: text (default on TTY), json, json-compact
#[arg(short, long = "output")]
output: Option<String>,
@@ -640,17 +656,19 @@ async fn main() -> Result<()> {
namespace,
kind,
name,
dry_run,
output,
} => {
let _span =
tracing::info_span!("cmd", command = "delete", %namespace, %kind, %name).entered();
tracing::info_span!("cmd", command = "delete", %namespace, ?kind, ?name).entered();
let out = resolve_output_mode(output.as_deref())?;
commands::delete::run(
&pool,
commands::delete::DeleteArgs {
namespace: &namespace,
kind: &kind,
name: &name,
kind: kind.as_deref(),
name: name.as_deref(),
dry_run,
output: out,
},
)