generated from nhcarrigan/template
feat: parse plugin_errors from stream-json init event (#270)
Adds plugin_errors field to the System init message type and emits a claude:output error event for each failed plugin, giving users visibility into plugin load failures within Hikari Desktop. Requires Claude Code v2.1.111+.
This commit is contained in:
@@ -98,6 +98,10 @@ pub enum ClaudeMessage {
|
||||
/// Output style hint from Claude Code (v2.1.81+). Informational only.
|
||||
#[serde(default)]
|
||||
output_style: Option<String>,
|
||||
/// Plugin errors from Claude Code (v2.1.111+). Populated when plugins are demoted
|
||||
/// due to unsatisfied dependencies.
|
||||
#[serde(default)]
|
||||
plugin_errors: Option<serde_json::Value>,
|
||||
},
|
||||
#[serde(rename = "assistant")]
|
||||
Assistant {
|
||||
@@ -977,6 +981,44 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_system_init_with_plugin_errors() {
|
||||
let json = r#"{"type":"system","subtype":"init","session_id":"sess-1","plugin_errors":["Plugin 'foo' requires 'bar' which is not installed","Plugin 'baz' failed to load"]}"#;
|
||||
let msg: ClaudeMessage = serde_json::from_str(json).unwrap();
|
||||
if let ClaudeMessage::System { plugin_errors, .. } = msg {
|
||||
let errors = plugin_errors.expect("plugin_errors should be present");
|
||||
let arr = errors.as_array().expect("plugin_errors should be an array");
|
||||
assert_eq!(arr.len(), 2);
|
||||
assert_eq!(arr[0].as_str(), Some("Plugin 'foo' requires 'bar' which is not installed"));
|
||||
} else {
|
||||
panic!("Expected System variant");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_system_init_without_plugin_errors() {
|
||||
let json = r#"{"type":"system","subtype":"init","session_id":"sess-1"}"#;
|
||||
let msg: ClaudeMessage = serde_json::from_str(json).unwrap();
|
||||
if let ClaudeMessage::System { plugin_errors, .. } = msg {
|
||||
assert!(plugin_errors.is_none());
|
||||
} else {
|
||||
panic!("Expected System variant");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_system_init_with_empty_plugin_errors() {
|
||||
let json = r#"{"type":"system","subtype":"init","session_id":"sess-1","plugin_errors":[]}"#;
|
||||
let msg: ClaudeMessage = serde_json::from_str(json).unwrap();
|
||||
if let ClaudeMessage::System { plugin_errors, .. } = msg {
|
||||
let errors = plugin_errors.expect("plugin_errors should be present");
|
||||
let arr = errors.as_array().expect("plugin_errors should be an array");
|
||||
assert!(arr.is_empty());
|
||||
} else {
|
||||
panic!("Expected System variant");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_result_message_with_fast_mode_state() {
|
||||
let json = r#"{"type":"result","subtype":"success","fast_mode_state":"enabled"}"#;
|
||||
|
||||
@@ -1850,6 +1850,7 @@ fn process_json_line(
|
||||
subtype,
|
||||
session_id,
|
||||
cwd,
|
||||
plugin_errors,
|
||||
..
|
||||
} => {
|
||||
if subtype == "init" {
|
||||
@@ -1874,6 +1875,31 @@ fn process_json_line(
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Warn about any plugins that failed to load (v2.1.111+)
|
||||
if let Some(errors) = plugin_errors {
|
||||
if let Some(arr) = errors.as_array() {
|
||||
for error in arr {
|
||||
let msg = if let Some(s) = error.as_str() {
|
||||
s.to_string()
|
||||
} else {
|
||||
error.to_string()
|
||||
};
|
||||
let _ = app.emit(
|
||||
"claude:output",
|
||||
OutputEvent {
|
||||
line_type: "error".to_string(),
|
||||
content: format!("Plugin error: {}", msg),
|
||||
tool_name: None,
|
||||
conversation_id: conversation_id.clone(),
|
||||
cost: None,
|
||||
parent_tool_use_id: None,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit_state_change(app, CharacterState::Idle, None, conversation_id.clone());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user