Skip to main content

aft/
response_finalize.rs

1use crate::context::AppContext;
2use crate::protocol::Response;
3
4pub fn attach_bg_completions(
5    response: &mut Response,
6    ctx: &AppContext,
7    session_id: &str,
8    command: &str,
9) {
10    if matches!(
11        command,
12        "configure"
13            | "bash_status"
14            | "bash_write"
15            | "bash_promote"
16            | "bash_regex_match"
17            | "bash_drain_completions"
18            | "bash_notify"
19            | "bash_unnotify"
20            | "bash_ack_completions"
21    ) {
22        return;
23    }
24    if !ctx
25        .bash_background()
26        .has_completions_for_session(Some(session_id))
27    {
28        return;
29    }
30    let completions = ctx
31        .bash_background()
32        .drain_completions_for_session(Some(session_id));
33    if completions.is_empty() {
34        return;
35    }
36    let value = serde_json::json!(completions);
37    match response.data.as_object_mut() {
38        Some(data) => {
39            data.insert("bg_completions".to_string(), value);
40        }
41        None => {
42            response.data = serde_json::json!({ "bg_completions": value });
43        }
44    }
45}
46
47/// Attach the agent status-bar counts to the response envelope so the plugin
48/// after-hook can surface the IDE-style status bar (emit-on-change). Skips
49/// internal/transport commands that don't represent agent tool calls (their
50/// responses never reach the agent, and bash-lifecycle commands fire rapidly).
51/// `errors`/`warnings` are read live from the LSP store here; Tier-2/todos are
52/// last-known. Omitted entirely until the Tier-2 cache is populated once.
53pub fn attach_status_bar(response: &mut Response, ctx: &AppContext, command: &str) {
54    if matches!(
55        command,
56        "configure"
57            | "ping"
58            | "version"
59            | "status"
60            | "bash_status"
61            | "bash_write"
62            | "bash_promote"
63            | "bash_regex_match"
64            | "bash_drain_completions"
65            | "bash_notify"
66            | "bash_unnotify"
67            | "bash_ack_completions"
68    ) {
69        return;
70    }
71    let Some(counts) = ctx.status_bar_counts() else {
72        return;
73    };
74    if !ctx.should_emit_status_bar(&counts) {
75        return;
76    }
77    let value = serde_json::json!({
78        "errors": counts.errors,
79        "warnings": counts.warnings,
80        "dead_code": counts.dead_code,
81        "unused_exports": counts.unused_exports,
82        "duplicates": counts.duplicates,
83        "todos": counts.todos,
84        "tier2_stale": counts.tier2_stale,
85    });
86    match response.data.as_object_mut() {
87        Some(data) => {
88            data.insert("status_bar".to_string(), value);
89        }
90        None => {
91            response.data = serde_json::json!({ "status_bar": value });
92        }
93    }
94}