Files
Kigi-CLI/crates/codegen/kigi-tui/src/slash/commands/feedback.rs
T
ZacharyZhang-NYandClaude Opus 5 9fb82291b2 chore(migration): repoint every published link off GitHub
The canonical repo is git.zacharyzhang.com now, so every URL a user can
actually reach had to move with it.

Self-updater: `PRODUCTION_ENDPOINTS.update_base_url` targets Gitea's
`/api/v1/repos/.../releases`, which serves the same wire format GitHub's
releases API did — `Release`/asset deserialisation is unchanged. The alpha
channel requests `?per_page=30&limit=30` because GitHub reads the page size
from `per_page` and Gitea from `limit`, and each ignores the other's, so one
URL stays correct on either.

Installers: same API base, and the documented one-liners become
`https://kigicli.dev/install.{sh,ps1}`. That domain's Worker proxies both
files from Gitea raw `main`, so the published install command survives any
future forge move without being reprinted everywhere. install.ps1 also drops
the GitHub-specific `Accept: application/vnd.github+json`.

Everything else user-facing: `/feedback` and the shell's feedback fallback
point at the Gitea issue tracker, `/docs` at the Gitea-rendered README, and
web_fetch's User-Agent at kigicli.dev. SECURITY.md now routes reports to the
issue tracker with a warning to withhold exploitable detail, because Gitea
has no equivalent of GitHub's private vulnerability reporting. Comments
naming `.github/workflows/release.yml` name `.gitea/` now.

Tests assert against these constants rather than literal URLs, so they
follow automatically; the one URL-shape assertion (production endpoints are
https) still holds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 21:13:19 -04:00

93 lines
2.7 KiB
Rust

//! `/feedback` -- open the Kigi issues page.
use crate::app::actions::Action;
use crate::slash::command::{CommandExecCtx, CommandResult, SlashCommand};
/// Where feedback goes: the project's own issue tracker. Kigi is a community
/// build, so its feedback belongs on its own repo — mirroring the official
/// kimi-cli, whose `/feedback` opens its repo's issues page.
pub const FEEDBACK_ISSUES_URL: &str =
"https://git.zacharyzhang.com/ZacharyZhang-NY/Kigi-CLI/issues";
/// Open the Kigi issue tracker in the browser.
pub struct FeedbackCommand;
impl SlashCommand for FeedbackCommand {
fn name(&self) -> &str {
"feedback"
}
fn description(&self) -> &str {
"Report feedback on the Kigi issues page"
}
fn usage(&self) -> &str {
"/feedback"
}
fn run(&self, _ctx: &mut CommandExecCtx, _args: &str) -> CommandResult {
CommandResult::Action(Action::OpenUrl(FEEDBACK_ISSUES_URL.into()))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::acp::model_state::ModelState;
static DEFAULT_BUNDLE_STATE: crate::app::bundle::BundleState =
crate::app::bundle::BundleState {
has_cache: false,
version: String::new(),
personas: Vec::new(),
roles: Vec::new(),
agents: Vec::new(),
skills: Vec::new(),
persona_details: Vec::new(),
role_details: Vec::new(),
};
fn make_ctx<'a>(models: &'a ModelState) -> CommandExecCtx<'a> {
CommandExecCtx {
models,
session_id: None,
bundle_state: &DEFAULT_BUNDLE_STATE,
screen_mode: crate::app::ScreenMode::Inline,
pager_state: crate::settings::PagerLocalSnapshot {
multiline_mode: false,
yolo_mode: false,
..crate::settings::PagerLocalSnapshot::default()
},
}
}
#[test]
fn feedback_opens_github_issues() {
let models = ModelState::default();
let mut ctx = make_ctx(&models);
match FeedbackCommand.run(&mut ctx, "") {
CommandResult::Action(Action::OpenUrl(url)) => {
assert_eq!(url, FEEDBACK_ISSUES_URL);
}
other => panic!("expected OpenUrl, got {other:?}"),
}
}
#[test]
fn feedback_ignores_stray_args() {
let models = ModelState::default();
let mut ctx = make_ctx(&models);
assert!(matches!(
FeedbackCommand.run(&mut ctx, "some typed text"),
CommandResult::Action(Action::OpenUrl(_))
));
}
#[test]
fn feedback_metadata() {
let cmd = FeedbackCommand;
assert_eq!(cmd.name(), "feedback");
assert!(!cmd.takes_args());
}
}