fix(review): custom provider login comments, doc placement, subagent scheme test
The subagent auth-scheme lookup is now a function with a test. The failed-login span carries the same method id as the successful one. README order matches the code: the provider is saved, then the key is checked.
This commit is contained in:
1 parent
c4ef8a3779
commit
c9855c4bb6
14 files changed
+77
-52
No files matched your search
@@ -570,9 +570,9 @@ pub enum Action {
|
||||
/// under the platform-id scope, then authenticate with the platform's
|
||||
/// method id. The key must never be logged.
|
||||
SubmitPlatformApiKey(String),
|
||||
/// A custom provider row was picked: start the URL, name, key steps.
|
||||
/// Custom provider row picked: open the URL step.
|
||||
BeginCustomProviderEntry(kigi_shell::models::custom::CustomApi),
|
||||
/// Enter in a custom provider step, with the trimmed input.
|
||||
/// Enter in a custom provider step.
|
||||
SubmitCustomProviderInput(String),
|
||||
/// Copy the auth URL to the clipboard during authentication.
|
||||
CopyAuthUrl,
|
||||
@@ -1618,8 +1618,7 @@ pub enum Effect {
|
||||
target: crate::app::app_view::PlatformLogin,
|
||||
key: String,
|
||||
},
|
||||
/// Save a custom provider (config.toml and auth.json), then send
|
||||
/// AuthenticateRequest with `custom:<name>`. SECURITY: never log the key.
|
||||
/// Saves the provider, then authenticates; never log the key.
|
||||
PersistCustomProviderAndAuthenticate {
|
||||
request_seq: u64,
|
||||
provider: kigi_shell::models::custom::CustomProvider,
|
||||
|
||||
@@ -262,7 +262,7 @@ pub enum AuthMode {
|
||||
/// Open-platform API-key entry: paste box for a Moonshot key selected
|
||||
/// from the welcome login picker. Esc returns to the picker (no quit).
|
||||
ApiKeyEntry(PlatformLogin),
|
||||
/// Custom provider login: one field per step; Esc returns to the picker.
|
||||
/// Custom provider login, one field per step.
|
||||
CustomProviderEntry(crate::app::custom_entry::CustomEntryStep),
|
||||
}
|
||||
/// API-key platform login target, selected from the welcome picker. Wraps a
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! The base URL, name, and key steps of the custom provider login.
|
||||
//! Custom provider login steps: base URL, name, key.
|
||||
|
||||
use kigi_shell::models::custom::{
|
||||
CustomApi, CustomProvider, default_name, normalize_base_url, validate_name,
|
||||
@@ -26,7 +26,7 @@ impl CustomEntryStep {
|
||||
}
|
||||
}
|
||||
|
||||
/// Only the key is a secret; URL and name show as typed.
|
||||
/// Only the key is masked.
|
||||
pub fn masks_input(self) -> bool {
|
||||
self.field == CustomEntryField::Key
|
||||
}
|
||||
@@ -43,9 +43,9 @@ impl CustomEntryStep {
|
||||
/// What one Enter press did.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum CustomEntryOutcome {
|
||||
/// The input stays; `CustomEntryDraft::error` says why, if it does.
|
||||
/// The input stays; the draft error says why.
|
||||
Stay,
|
||||
/// Move to the next field with this text in the box.
|
||||
/// Next field, with this text in the box.
|
||||
Next {
|
||||
field: CustomEntryField,
|
||||
prefill: String,
|
||||
|
||||
@@ -326,7 +326,7 @@ pub(super) fn dispatch_begin_platform_key_entry(
|
||||
vec![]
|
||||
}
|
||||
|
||||
/// A custom provider row was selected: open the first step (base URL).
|
||||
/// Custom provider row selected: open the URL step.
|
||||
pub(super) fn dispatch_begin_custom_provider_entry(
|
||||
app: &mut AppView,
|
||||
api: kigi_shell::models::custom::CustomApi,
|
||||
@@ -344,7 +344,7 @@ pub(super) fn dispatch_begin_custom_provider_entry(
|
||||
vec![]
|
||||
}
|
||||
|
||||
/// Enter in a custom provider step: advance, stay with a reason, or save.
|
||||
/// Enter in a custom provider step.
|
||||
pub(super) fn dispatch_submit_custom_provider_input(
|
||||
app: &mut AppView,
|
||||
input: String,
|
||||
|
||||
@@ -582,8 +582,7 @@ fn custom_field(app: &AppView) -> crate::app::custom_entry::CustomEntryField {
|
||||
}
|
||||
}
|
||||
|
||||
/// The custom provider flow: URL, then name (prefilled from the host), then
|
||||
/// key; the last Enter emits ONE persist+authenticate effect for the provider.
|
||||
/// URL, name, key; the last Enter emits one persist effect.
|
||||
#[test]
|
||||
fn custom_provider_steps_end_in_one_persist_effect() {
|
||||
use crate::app::custom_entry::CustomEntryField;
|
||||
@@ -649,7 +648,7 @@ fn custom_provider_steps_end_in_one_persist_effect() {
|
||||
assert!(app.auth_code_input.is_empty());
|
||||
}
|
||||
|
||||
/// A refused field keeps the user on it and does not emit an effect.
|
||||
/// A refused field keeps the user on it.
|
||||
#[test]
|
||||
fn custom_provider_refusals_stay_on_the_field() {
|
||||
use crate::app::custom_entry::CustomEntryField;
|
||||
@@ -687,7 +686,7 @@ fn custom_provider_refusals_stay_on_the_field() {
|
||||
assert!(app.custom_entry.error.is_some());
|
||||
}
|
||||
|
||||
/// Esc at any step returns to the picker and drops the draft.
|
||||
/// Esc returns to the picker and drops the draft.
|
||||
#[test]
|
||||
fn cancel_custom_provider_entry_returns_to_picker() {
|
||||
use kigi_shell::models::custom::CustomApi;
|
||||
|
||||
@@ -1294,7 +1294,7 @@ fn render_welcome_authenticating(
|
||||
}
|
||||
|
||||
AuthMode::ApiKeyEntry(target) => {
|
||||
// Platform API-key paste box: the key comes from the platform console.
|
||||
// Platform API-key paste box.
|
||||
let instruction = format!(
|
||||
"Paste your {} API key (from {})",
|
||||
target.vendor(),
|
||||
@@ -1938,8 +1938,7 @@ pub(crate) fn render_session_picker(
|
||||
)
|
||||
}
|
||||
|
||||
/// Render the auth token input box (loopback mode).
|
||||
/// One text field under the logo: instruction, optional error, input box, hints.
|
||||
/// One text field under the logo.
|
||||
struct EntryBox<'a> {
|
||||
instruction: &'a str,
|
||||
error: Option<&'a str>,
|
||||
@@ -2035,6 +2034,7 @@ fn render_entry_box(
|
||||
Paragraph::new(hints).render(hint_area, buf);
|
||||
}
|
||||
|
||||
/// Render the auth token input box (loopback mode).
|
||||
fn render_auth_input_box(
|
||||
area: Rect,
|
||||
buf: &mut Buffer,
|
||||
@@ -2393,8 +2393,6 @@ mod tests {
|
||||
assert!(!text.contains("Moonshot"), "{text}");
|
||||
}
|
||||
|
||||
/// The Moonshot API-key entry arm renders the platform copy, the paste
|
||||
/// box, and the esc-back hint — and no OAuth-URL affordances.
|
||||
fn render_custom_entry(
|
||||
step: crate::app::custom_entry::CustomEntryStep,
|
||||
draft: &crate::app::custom_entry::CustomEntryDraft,
|
||||
@@ -2417,7 +2415,7 @@ mod tests {
|
||||
buffer_text(&buf)
|
||||
}
|
||||
|
||||
/// The URL and name steps show typed text; only the key step masks it.
|
||||
/// Only the key step masks its input.
|
||||
#[test]
|
||||
fn custom_entry_arm_masks_only_the_key() {
|
||||
use crate::app::custom_entry::{CustomEntryDraft, CustomEntryField, CustomEntryStep};
|
||||
@@ -2447,7 +2445,7 @@ mod tests {
|
||||
assert!(empty.contains("provider name"), "{empty}");
|
||||
}
|
||||
|
||||
/// A refusal shows under the instruction so the user sees what to fix.
|
||||
/// A refusal shows under the instruction.
|
||||
#[test]
|
||||
fn custom_entry_arm_shows_the_refusal() {
|
||||
use crate::app::custom_entry::{CustomEntryDraft, CustomEntryStep};
|
||||
@@ -2460,6 +2458,8 @@ mod tests {
|
||||
assert!(text.contains("must start with http"), "{text}");
|
||||
}
|
||||
|
||||
/// The Moonshot API-key entry arm renders the platform copy, the paste
|
||||
/// box, and the esc-back hint — and no OAuth-URL affordances.
|
||||
#[test]
|
||||
fn api_key_entry_arm_shows_platform_copy_and_paste_box() {
|
||||
let area = Rect::new(0, 0, 80, 40);
|
||||
|
||||
Reference in new issue
Block a user