Skip to content

Commit c28d694

Browse files
committed
docs: add CLI TUI compatibility contract
1 parent 6192669 commit c28d694

4 files changed

Lines changed: 118 additions & 0 deletions

File tree

src/commands/skill.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1917,6 +1917,13 @@ mod tests {
19171917
));
19181918
}
19191919

1920+
#[test]
1921+
fn detect_suggest_install_output_mode_json_stays_json_without_tty() {
1922+
let mode =
1923+
detect_suggest_install_output_mode(true, false, Some("1"), Some("0"), Some("dumb"));
1924+
assert!(matches!(mode, SuggestInstallOutputMode::Json));
1925+
}
1926+
19201927
// Tests for skill_id validation
19211928
#[test]
19221929
fn validate_skill_id_rejects_dotdot() {

src/output.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,30 @@ mod tests {
411411
);
412412
}
413413

414+
#[test]
415+
fn detect_output_mode_non_tty_human_output_is_plain_even_without_term() {
416+
assert_eq!(
417+
detect_output_mode(false, false, None, None, None),
418+
OutputMode::Human { use_color: false }
419+
);
420+
}
421+
422+
#[test]
423+
fn detect_output_mode_no_color_value_disables_color_regardless_of_value() {
424+
assert_eq!(
425+
detect_output_mode(false, true, Some("false"), None, Some("xterm")),
426+
OutputMode::Human { use_color: false }
427+
);
428+
}
429+
430+
#[test]
431+
fn detect_output_mode_clicolor_zero_disables_color_even_with_no_color_empty() {
432+
assert_eq!(
433+
detect_output_mode(false, true, Some(""), Some("0"), Some("xterm")),
434+
OutputMode::Human { use_color: false }
435+
);
436+
}
437+
414438
#[test]
415439
fn detect_output_mode_term_dumb_case_insensitive() {
416440
assert_eq!(
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use std::fs;
2+
3+
#[test]
4+
fn cli_tui_compatibility_contract_documents_required_topics() {
5+
let contract = fs::read_to_string("website/docs/src/content/docs/cli-tui-compatibility.md")
6+
.expect("CLI/TUI compatibility contract should be documented");
7+
8+
for required_topic in [
9+
"--json",
10+
"TTY",
11+
"NO_COLOR",
12+
"CLICOLOR=0",
13+
"TERM=dumb",
14+
"CI and piped output",
15+
"exit codes",
16+
"non-interactive fallbacks",
17+
"full-screen TUI",
18+
"opt-in",
19+
] {
20+
assert!(
21+
contract.contains(required_topic),
22+
"compatibility contract should mention {required_topic}"
23+
);
24+
}
25+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# CLI and TUI compatibility contract
2+
3+
AgentSync can improve its human interface without breaking existing CLI users when every output change follows this contract.
4+
5+
## Stable machine output
6+
7+
Commands that support `--json` must treat `--json` as the highest-priority output mode. When `--json` is set:
8+
9+
- stdout must contain machine-readable JSON only.
10+
- Human headings, colors, spinners, progress frames, and hints must not be mixed into stdout.
11+
- Existing JSON field names and meanings should remain stable unless a schema migration is explicitly documented.
12+
- Error exits should preserve the command's existing exit-code behavior and return structured JSON whenever the command already supports JSON errors.
13+
14+
## Human output mode
15+
16+
Human output is optimized for people and may use headings, labels, Unicode status symbols, hints, and summaries. Human output must remain readable when copied from logs or piped into another command.
17+
18+
Use the shared formatter and output-mode detection rules instead of ad hoc color or TTY checks.
19+
20+
## TTY and color rules
21+
22+
Color is enabled only when stdout is a TTY and no supported color-disabling override is active.
23+
24+
The current color-disabling overrides are:
25+
26+
- `NO_COLOR` with any non-empty value.
27+
- `CLICOLOR=0`.
28+
- `TERM=dumb`, matched case-insensitively.
29+
30+
When stdout is not a TTY, AgentSync should continue in plain human output unless the user requested `--json`.
31+
32+
## CI and piped output
33+
34+
CI and piped output should be line-oriented and deterministic. Commands must not require cursor control, alternate-screen mode, or carriage-return animation when stdout is not an interactive TTY.
35+
36+
Progress-heavy flows may keep a live renderer for safe TTY contexts, but they must provide a plain line renderer for non-TTY contexts.
37+
38+
## Exit codes
39+
40+
Output rendering must not change command success or failure semantics. A formatting-only change should preserve existing exit codes for success, validation failures, partial failures, and unsupported terminal states.
41+
42+
## Non-interactive fallbacks
43+
44+
AgentSync supports non-interactive fallbacks for interactive flows. Interactive flows must detect unsupported non-interactive contexts before prompting. In non-interactive contexts, a command should either:
45+
46+
- use an explicit non-interactive path, such as an `--all` or dry-run mode;
47+
- fall back to the existing safe renderer; or
48+
- exit with a clear diagnostic and remediation.
49+
50+
A command must not hang waiting for input that cannot arrive.
51+
52+
## Full-screen TUI compatibility
53+
54+
A full-screen TUI is allowed only when it is explicitly opt-in or when AgentSync can prove the terminal context is safe and interactive. Until a future release changes this contract deliberately, full-screen TUI behavior must not replace the existing default wizard behavior.
55+
56+
Any full-screen TUI must:
57+
58+
- initialize only after confirming the required TTY capabilities;
59+
- clean up terminal state on success, error, and cancellation;
60+
- provide cancellation semantics that preserve existing generated files unless the user confirms changes;
61+
- fall back to the existing wizard or exit with a clear message when initialization fails; and
62+
- keep `--json` and non-interactive command paths free from full-screen rendering.

0 commit comments

Comments
 (0)