34bb0b5096
Batch-write surface and pagination consistency:
* weknora doc delete <doc-id> [<doc-id>...] — positional multi-id, default
keep-going on failure. Single -y confirms entire batch.
* weknora session delete <session-id> [<session-id>...] — same shape.
* weknora chunk delete <chunk-id> [<chunk-id>...] --doc <doc-id> — multi-id
with shared --doc parent.
* Multi-id partial-failure rolls up as operation.failed (exit 1), not
server.error (exit 7) — failures are operation outcomes, not transient
transport issues, and the retry-with-backoff hint for server.* would
mislead callers.
* weknora api <path> --paginate — auto-walks offset pagination and merges
pages into a single {data, total} JSON response.
* Paginate truncation fix across 6 list/follower call sites.
* All doc / search / chunk / session / kb list commands migrated to
FormatOptions API.
Multi-id RunE only emits the {ok, failed} envelope when the operation
actually ran — pre-flight failures (e.g. confirmation_required) leave
stdout empty per the wire contract.
doc upload's missing-positional-or-flag check is wrapped as FlagError so
the exit code (2) matches the convention used by other commands that
require a positional argument directly.
74 lines
2.6 KiB
Go
74 lines
2.6 KiB
Go
package cmdutil
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/Tencent/WeKnora/cli/internal/iostreams"
|
|
"github.com/Tencent/WeKnora/cli/internal/prompt"
|
|
)
|
|
|
|
// ConfirmDestructiveBatch is the multi-id flavor of ConfirmDestructive: same
|
|
// behavior matrix (yes / non-TTY / TTY-prompt / user-no) but the prompt text
|
|
// reflects the count, not a single id. Used by `doc delete <id> [<id>...]`
|
|
// — one -y confirms all items in the batch.
|
|
//
|
|
// Pass n = total count of items about to be deleted.
|
|
func ConfirmDestructiveBatch(p prompt.Prompter, yes, jsonOut bool, what string, n int) error {
|
|
if yes {
|
|
return nil
|
|
}
|
|
if !iostreams.IO.IsStdoutTTY() || jsonOut {
|
|
return NewError(
|
|
CodeInputConfirmationRequired,
|
|
fmt.Sprintf("delete %d %s(s) requires explicit confirmation: re-run with -y/--yes", n, what),
|
|
)
|
|
}
|
|
ok, err := p.Confirm(fmt.Sprintf("Delete %d %s(s)? This cannot be undone.", n, what), false)
|
|
if err != nil {
|
|
return Wrapf(CodeInputMissingFlag, err, "confirm batch delete")
|
|
}
|
|
if !ok {
|
|
fmt.Fprintln(iostreams.IO.Err, "Aborted.")
|
|
return NewError(CodeUserAborted, "delete aborted")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ConfirmDestructive guards a destructive operation (delete, force-overwrite)
|
|
// behind explicit user approval. Behavior matrix:
|
|
//
|
|
// yes=true → proceed (explicit user opt-in via -y/--yes)
|
|
// non-TTY OR jsonOut → return CodeInputConfirmationRequired (exit 10);
|
|
// no UI to prompt, agent/CI must re-invoke with -y
|
|
// after the human explicitly approves
|
|
// TTY + interactive → prompt; user-yes proceeds, user-no returns
|
|
// CodeUserAborted ("Aborted." to stderr)
|
|
// prompter error → returns CodeInputMissingFlag (rare; stdin closed
|
|
// mid-prompt)
|
|
//
|
|
// The non-TTY branch is the destructive-write protocol: high-risk writes
|
|
// always require explicit confirmation in scripted contexts, never silent
|
|
// proceed. See cli/README.md "Exit codes".
|
|
//
|
|
// `yes` should be sourced from the persistent global -y/--yes flag.
|
|
func ConfirmDestructive(p prompt.Prompter, yes, jsonOut bool, what, id string) error {
|
|
if yes {
|
|
return nil
|
|
}
|
|
if !iostreams.IO.IsStdoutTTY() || jsonOut {
|
|
return NewError(
|
|
CodeInputConfirmationRequired,
|
|
fmt.Sprintf("delete %s %s requires explicit confirmation: re-run with -y/--yes", what, id),
|
|
)
|
|
}
|
|
ok, err := p.Confirm(fmt.Sprintf("Delete %s %s? This cannot be undone.", what, id), false)
|
|
if err != nil {
|
|
return Wrapf(CodeInputMissingFlag, err, "confirm delete")
|
|
}
|
|
if !ok {
|
|
fmt.Fprintln(iostreams.IO.Err, "Aborted.")
|
|
return NewError(CodeUserAborted, "delete aborted")
|
|
}
|
|
return nil
|
|
}
|