/feedback opens the Kigi GitHub issues page

Feedback about an unofficial community build belongs on its own issue
tracker, not Moonshot's feedback endpoint — and this mirrors the
official kimi-cli, whose /feedback opens its repo's issues page
(ISSUE_URL in ui/shell/slash.py). /feedback now returns
Action::OpenUrl(https://github.com/ZacharyZhang-NY/Kigi-CLI/issues),
the same battle-tested browser path /docs web uses.

The now-dead TUI text-feedback pipeline is excised: PromptInputMode::
Feedback (~ prefix composer mode), Action::{EnterFeedbackMode,
SendFeedback}, Effect::SendFeedback (the kigi/feedback ACP POST),
TaskResult::{FeedbackComplete,FeedbackFailed}, and their dispatchers.
The shell-side kigi/feedback ACP extension stays: it is protocol
surface for editor embeddings, OAuth-gated, and shared with kigi/btw.

Gates: workspace check/clippy --all-targets 0/0, fmt, kigi-tui lib
6621 passed / 0 failed.
This commit is contained in:
2026-07-18 11:51:13 -04:00
parent 0692198719
commit 0dc98a34a6
11 changed files with 74 additions and 221 deletions
@@ -1,4 +1,4 @@
//! Feedback, remember-note, btw, and recap dispatchers.
//! Remember-note, btw, and recap dispatchers.
use super::ctx::with_active_agent;
use crate::app::actions::Effect;
@@ -18,16 +18,6 @@ fn next_rewrite_nonce() -> u64 {
REWRITE_NONCE.fetch_add(1, Ordering::Relaxed)
}
/// Enter feedback mode: visual change to prompt bar (teal accent, pencil prefix).
/// No side effects — the user types feedback text and presses Enter to send.
pub(super) fn dispatch_enter_feedback_mode(app: &mut AppView) -> Vec<Effect> {
with_active_agent(app, |agent| {
agent.prompt_input_mode = PromptInputMode::Feedback;
agent.prompt.set_text("");
});
vec![]
}
/// Enter remember mode: visual change to prompt bar (remember accent, `#` prefix).
/// No side effects — the user types a memory note and presses Enter to send.
pub(super) fn dispatch_enter_remember_mode(app: &mut AppView) -> Vec<Effect> {
@@ -38,47 +28,6 @@ pub(super) fn dispatch_enter_remember_mode(app: &mut AppView) -> Vec<Effect> {
vec![]
}
/// Send feedback text to the server. Shows a thank-you message immediately
/// and fires the HTTP POST as a background effect.
pub(super) fn dispatch_send_feedback(app: &mut AppView, text: String) -> Vec<Effect> {
let ActiveView::Agent(id) = app.active_view else {
return vec![];
};
let Some(agent) = app.agents.get_mut(&id) else {
return vec![];
};
agent.prompt_input_mode = PromptInputMode::Normal;
agent.prompt.set_text("");
// Submitting feedback retires any edit-contextual ephemeral tip.
agent.ephemeral_tip.clear_on_submit();
let trimmed = text.trim().to_string();
if trimmed.is_empty() {
agent.scrollback.push_block(RenderBlock::system(
"Please provide feedback text.".to_string(),
));
return vec![];
}
let Some(session_id) = agent.session.session_id.clone() else {
agent
.scrollback
.push_block(RenderBlock::system("No active session.".to_string()));
return vec![];
};
agent.scrollback.push_block(RenderBlock::system(
"Thanks for the feedback! The Kigi team is on it.".to_string(),
));
vec![Effect::SendFeedback {
agent_id: id,
session_id,
feedback_text: trimmed,
}]
}
/// Send a raw remember note for LLM-powered rewriting via `kigi/memory/rewrite`.
/// Clears remember mode and prompts the LLM to reformat the note with session
/// context. Falls back to direct `SaveMemoryNote` when no session is available.
@@ -33,8 +33,7 @@ use super::modes::{
set_permission_mode, set_plan_mode, set_yolo_mode,
};
use super::notes::{
dispatch_enter_feedback_mode, dispatch_enter_remember_mode,
dispatch_save_remember_note_from_modal, dispatch_send_btw, dispatch_send_feedback,
dispatch_enter_remember_mode, dispatch_save_remember_note_from_modal, dispatch_send_btw,
dispatch_send_recap, dispatch_send_remember_note,
};
use super::permissions::{
@@ -784,8 +783,6 @@ pub(crate) fn dispatch(action: Action, app: &mut AppView) -> Vec<Effect> {
Action::ShowPlan => dispatch_show_plan(app),
Action::EnterPlanMode { description } => dispatch_enter_plan_mode(app, description),
Action::SetPlanMode(kind) => set_plan_mode(app, kind),
Action::EnterFeedbackMode => dispatch_enter_feedback_mode(app),
Action::SendFeedback(text) => dispatch_send_feedback(app, text),
Action::EnterRememberMode => dispatch_enter_remember_mode(app),
Action::SendRememberNote(text) => dispatch_send_remember_note(app, text),
Action::SaveRememberNoteFromModal => dispatch_save_remember_note_from_modal(app),
@@ -663,17 +663,6 @@ pub(super) fn dispatch_task_result(result: TaskResult, app: &mut AppView) -> Vec
}
vec![]
}
TaskResult::FeedbackComplete { .. } => vec![],
TaskResult::FeedbackFailed { agent_id, error } => {
if let Some(agent) = app.agents.get_mut(&agent_id) {
agent
.scrollback
.push_block(crate::scrollback::block::RenderBlock::system(format!(
"Couldn't send feedback: {error}"
)));
}
vec![]
}
TaskResult::MemoryNoteSaved { agent_id, result } => {
handle_memory_note_saved(app, agent_id, result)
}
@@ -32,23 +32,6 @@ fn seed_foreign_resume_hint(
}),
);
}
/// Sending feedback is a submit: it retires the active ephemeral tip.
#[test]
fn send_feedback_clears_active_ephemeral_tip() {
let mut app = test_app_with_agent();
let id = AgentId(0);
let agent = app.agents.get_mut(&id).unwrap();
let _ = agent.ephemeral_tip.show(
crate::tips::EphemeralTip::new("t", ratatui::text::Line::from("hint")),
&mut std::collections::HashMap::new(),
);
assert!(agent.ephemeral_tip.is_active());
let _ = dispatch(Action::SendFeedback("it broke".into()), &mut app);
assert!(
!app.agents.get(&id).unwrap().ephemeral_tip.is_active(),
"feedback submit must clear the tip"
);
}
/// Sending a remember note is a submit: it retires the active ephemeral tip.
#[test]
fn send_remember_note_clears_active_ephemeral_tip() {