mirror of
https://github.com/codewhale-hq/Codewhale.git
synced 2026-11-11 01:51:34 -10:00
fix(tui): green main CI — fmt, parking followup receipt, Windows path gate
Align turn-end parking assertions with the actionable followup Interrupted receipt (agent_id + action=followup), strip Windows \\?\ verbatim prefixes from snapshot size-gate diagnostics, and rustfmt the two lint offenders so macOS/Windows CI stay green with Ubuntu.
This commit is contained in:
1 parent
aade9361bb
commit
dfa0f2d223
4 files changed
+61
-23
No files matched your search
@@ -104,20 +104,30 @@ pub const GATE_TOO_LARGE_MARKER: &str = "workspace too large for snapshots";
|
||||
pub const GATE_TOO_MANY_ENTRIES_MARKER: &str = "workspace has too many files for snapshots";
|
||||
pub const GATE_UNSAFE_LOCATION_MARKER: &str = "workspace snapshots are disabled";
|
||||
|
||||
/// Display a workspace path in gate diagnostics without Windows verbatim
|
||||
/// (`\\?\`) prefixes. `Path::canonicalize` embeds that prefix; users and
|
||||
/// tests name the workspace without it, so leave it out of the message.
|
||||
fn display_workspace_for_gate(workspace: &Path) -> String {
|
||||
let raw = workspace.display().to_string();
|
||||
raw.strip_prefix(r"\\?\")
|
||||
.or_else(|| raw.strip_prefix("//?/"))
|
||||
.unwrap_or(&raw)
|
||||
.to_string()
|
||||
}
|
||||
|
||||
impl WorkspaceGate {
|
||||
/// One-line English diagnostic for logs, `/undo`, and the gate matcher.
|
||||
/// The user-facing consequence and recovery are localized by the notice
|
||||
/// surfaces; this string must not restate them.
|
||||
fn describe(self, cap_bytes: u64, workspace: &Path) -> String {
|
||||
let workspace = display_workspace_for_gate(workspace);
|
||||
match self {
|
||||
Self::TooLarge => format!(
|
||||
"{GATE_TOO_LARGE_MARKER}: over {} bytes of snapshot-eligible content in {}",
|
||||
"{GATE_TOO_LARGE_MARKER}: over {} bytes of snapshot-eligible content in {workspace}",
|
||||
cap_bytes,
|
||||
workspace.display()
|
||||
),
|
||||
Self::TooManyEntries => format!(
|
||||
"{GATE_TOO_MANY_ENTRIES_MARKER}: over {SIZE_WALK_MAX_ENTRIES} snapshot-eligible entries in {}",
|
||||
workspace.display()
|
||||
"{GATE_TOO_MANY_ENTRIES_MARKER}: over {SIZE_WALK_MAX_ENTRIES} snapshot-eligible entries in {workspace}"
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -277,7 +287,7 @@ impl SnapshotRepo {
|
||||
io::ErrorKind::InvalidInput,
|
||||
format!(
|
||||
"{GATE_UNSAFE_LOCATION_MARKER} for {reason}: {}",
|
||||
work_tree.display()
|
||||
display_workspace_for_gate(&work_tree)
|
||||
),
|
||||
));
|
||||
}
|
||||
@@ -1994,8 +2004,13 @@ mod tests {
|
||||
msg.contains(GATE_TOO_LARGE_MARKER),
|
||||
"error must call out the size cap; got: {msg}"
|
||||
);
|
||||
let named_owned = workspace.display().to_string();
|
||||
let named = named_owned
|
||||
.strip_prefix(r"\\?\")
|
||||
.or_else(|| named_owned.strip_prefix("//?/"))
|
||||
.unwrap_or(named_owned.as_str());
|
||||
assert!(
|
||||
msg.contains(&workspace.display().to_string()),
|
||||
msg.contains(named),
|
||||
"error must name the workspace it refused; got: {msg}"
|
||||
);
|
||||
// The remedy belongs to the localized notice. Repeating it here is
|
||||
|
||||
@@ -2923,8 +2923,7 @@ async fn read_file_denies_ambient_home_config_even_when_codewhale_home_is_reloca
|
||||
let _home = crate::test_support::EnvVarGuard::set("HOME", home.path());
|
||||
let _userprofile = crate::test_support::EnvVarGuard::set("USERPROFILE", home.path());
|
||||
// The override points somewhere else entirely — the ambient store must stay guarded.
|
||||
let _codewhale_home =
|
||||
crate::test_support::EnvVarGuard::set("CODEWHALE_HOME", relocated.path());
|
||||
let _codewhale_home = crate::test_support::EnvVarGuard::set("CODEWHALE_HOME", relocated.path());
|
||||
let _config_path = crate::test_support::EnvVarGuard::remove("CODEWHALE_CONFIG_PATH");
|
||||
let _legacy_config_path = crate::test_support::EnvVarGuard::remove("DEEPSEEK_CONFIG_PATH");
|
||||
|
||||
|
||||
@@ -13297,7 +13297,9 @@ async fn turn_end_parking_preserves_a_step_zero_resumable_checkpoint() {
|
||||
panic!("turn-end parking must interrupt resumably: {result:?}");
|
||||
};
|
||||
assert!(
|
||||
reason.contains(&format!("resume_from=\"{agent_id}\"")),
|
||||
reason.contains(&format!(
|
||||
"agent(action=\"followup\", agent_id=\"{agent_id}\""
|
||||
)),
|
||||
"{reason}"
|
||||
);
|
||||
assert_eq!(result.steps_taken, 0);
|
||||
@@ -13317,9 +13319,9 @@ async fn turn_end_parking_preserves_a_step_zero_resumable_checkpoint() {
|
||||
.as_ref()
|
||||
.expect("parked work must carry an actionable recovery instruction");
|
||||
assert!(
|
||||
recovery
|
||||
.question
|
||||
.contains(&format!("resume_from=\"{agent_id}\"")),
|
||||
recovery.question.contains(&format!(
|
||||
"agent(action=\"followup\", agent_id=\"{agent_id}\""
|
||||
)),
|
||||
"{}",
|
||||
recovery.question
|
||||
);
|
||||
@@ -13329,7 +13331,9 @@ async fn turn_end_parking_preserves_a_step_zero_resumable_checkpoint() {
|
||||
agent_id: ref delivered_agent_id,
|
||||
reason: ref delivered_reason,
|
||||
} if delivered_agent_id == agent_id
|
||||
&& delivered_reason.contains(&format!("resume_from=\"{agent_id}\""))
|
||||
&& delivered_reason.contains(&format!(
|
||||
"agent(action=\"followup\", agent_id=\"{agent_id}\""
|
||||
))
|
||||
));
|
||||
|
||||
let (explicit_status, _, _, explicit_needs_input, explicit_worker_status, _) =
|
||||
@@ -16260,7 +16264,9 @@ async fn queued_turn_owned_child_parks_without_a_false_start_transition() {
|
||||
message,
|
||||
MailboxMessage::Interrupted { agent_id, reason }
|
||||
if agent_id == "agent_queued_turn_end_park"
|
||||
&& reason.contains("resume_from=\"agent_queued_turn_end_park\"")
|
||||
&& reason.contains(
|
||||
"agent(action=\"followup\", agent_id=\"agent_queued_turn_end_park\""
|
||||
)
|
||||
)),
|
||||
"parking must publish an actionable interrupted receipt: {messages:?}"
|
||||
);
|
||||
|
||||
@@ -70,15 +70,33 @@ pub fn visible_slash_menu_entries(app: &App, limit: usize) -> Vec<SlashMenuEntry
|
||||
effort_entries.push(SlashMenuEntry {
|
||||
name: format!("/effort {}", label),
|
||||
description: match eff {
|
||||
crate::reasoning_preference::ReasoningEffort::Auto => "choose per turn".into(),
|
||||
crate::reasoning_preference::ReasoningEffort::Off => "no extra reasoning".into(),
|
||||
crate::reasoning_preference::ReasoningEffort::Minimal => "minimal reasoning".into(),
|
||||
crate::reasoning_preference::ReasoningEffort::Low => "lighter reasoning".into(),
|
||||
crate::reasoning_preference::ReasoningEffort::Medium => "balanced reasoning".into(),
|
||||
crate::reasoning_preference::ReasoningEffort::High => "deeper reasoning".into(),
|
||||
crate::reasoning_preference::ReasoningEffort::XHigh => "extra-high reasoning".into(),
|
||||
crate::reasoning_preference::ReasoningEffort::Ultra => "ultra reasoning".into(),
|
||||
crate::reasoning_preference::ReasoningEffort::Max => "maximum reasoning".into(),
|
||||
crate::reasoning_preference::ReasoningEffort::Auto => {
|
||||
"choose per turn".into()
|
||||
}
|
||||
crate::reasoning_preference::ReasoningEffort::Off => {
|
||||
"no extra reasoning".into()
|
||||
}
|
||||
crate::reasoning_preference::ReasoningEffort::Minimal => {
|
||||
"minimal reasoning".into()
|
||||
}
|
||||
crate::reasoning_preference::ReasoningEffort::Low => {
|
||||
"lighter reasoning".into()
|
||||
}
|
||||
crate::reasoning_preference::ReasoningEffort::Medium => {
|
||||
"balanced reasoning".into()
|
||||
}
|
||||
crate::reasoning_preference::ReasoningEffort::High => {
|
||||
"deeper reasoning".into()
|
||||
}
|
||||
crate::reasoning_preference::ReasoningEffort::XHigh => {
|
||||
"extra-high reasoning".into()
|
||||
}
|
||||
crate::reasoning_preference::ReasoningEffort::Ultra => {
|
||||
"ultra reasoning".into()
|
||||
}
|
||||
crate::reasoning_preference::ReasoningEffort::Max => {
|
||||
"maximum reasoning".into()
|
||||
}
|
||||
},
|
||||
is_skill: false,
|
||||
alias_hint: None,
|
||||
|
||||
Reference in new issue
Block a user