feat(cmdcore): suppress interactive prompt off-terminal, document agent protocol

Align the write-confirmation UX with lark-cli: ConfirmRisk (and the
shortcut confirmRisk) now print the yes/no prompt only when stdin is a
real terminal (ioctl-level check via go-isatty; a char-device stat would
misclassify `< /dev/null`). Non-interactive callers get a clean
structured confirmation_required error on stderr. Piped answers are
still honored for humans/scripts; --yes/--dry-run remain the sanctioned
non-interactive paths.

skills/mono: add the recognition + retry protocol for agents —
identify confirmation_required via error.reason, show action and params,
retry the original command with --yes only after explicit user consent,
never silently append --yes or treat it as a transient error.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed 2026-07-30 21:42:19 +08:00
1 parent afb9c27560
commit d6292d92d3
9 files changed
+103 -10

No files matched your search

+5 -2
View File
@@ -74,8 +74,11 @@ func TestCrossPlatformCoverageConfirmRiskPromptsForStaticWrite(t *testing.T) {
if ok, err := confirmRisk(rt, s); err != nil || !ok {
t.Fatalf("static write risk was not confirmed: ok=%v err=%v", ok, err)
}
if got := stderr.String(); !strings.Contains(got, "chat +messages-send(write)") {
t.Fatalf("confirmation prompt = %q", got)
// A pipe is not a terminal: the prompt must be suppressed (the structured
// error carries the semantics for non-interactive callers), while the
// piped answer is still honored.
if got := stderr.String(); got != "" {
t.Fatalf("non-terminal stdin must not print a prompt, got %q", got)
}
}