Synced from monorepo

Synced from monorepo

Changes:
- Report invalid MCP server config instead of failing startup
- Keep completed terminal output when the gateway connection is lost
- Show a duration-only detail view for single-task task output
- Don't let a stale registry turn counter hide local sessions
- Raise the file-descriptor soft limit on Linux and log effective limits at startup
- Stop aborting when HTTP client construction fails
- Make session thread and runtime spawn failures recoverable
- Fix main-prompt paste parity in the question freeform input
- Fire SessionEnd hooks on /exit and headless quit
- Embed the deployment-config signing public key
- Repaint paste-chip background on inline panel inputs
- Security: prevent acceptEdits from auto-approving agent writes into the always-trusted global hook root
- Fix stacked "Worked for" markers so parks render as status and turns close with exactly one marker
- Parse hooks from config files
- Add a remote kill-switch for managed-config signature verification
- Security: fix workspace file-reference resolution bypassing workspace filesystem confinement

Source-Revision: d02693a856a54f1030695b36b91d276e96b30b23
This commit is contained in:
grokkybara[bot] 2026-07-25 18:44:42 +00:00
commit 47348d13ec
138 changed files with 7283 additions and 5796 deletions

View file

@ -801,16 +801,14 @@ impl ToolOutput {
format!("=== Task {} ===", r.task_id),
format!("Command: {}", r.command),
format!("Status: {}", r.status),
format!("Started: {}", r.started),
format!("Duration: {:.2}s", r.duration_secs),
];
if let Some(ref ended) = r.ended {
lines.push(format!("Ended: {}", ended));
}
lines.push(format!("Duration: {:.2}s", r.duration_secs));
if let Some(code) = r.exit_code {
lines.push(format!("Exit Code: {}", code));
}
lines.push(format!("Output File: {}", r.output_file));
if !r.output_file.is_empty() {
lines.push(format!("Output File: {}", r.output_file));
}
lines.push(String::new());
lines.push("=== Output ===".to_string());
if r.output.is_empty() {
@ -1641,6 +1639,55 @@ mod tests {
assert_eq!(json["Result"]["task_id"], "task-1");
assert_eq!(json["Result"]["status"], "running");
}
/// The single-task detail view is duration-only: absolute `started` /
/// `ended` instants stay on the wire struct but must not reach the prompt.
#[test]
fn task_output_prompt_is_duration_only() {
let out = ToolOutput::TaskOutput(TaskOutputOutput::Result(TaskOutputResult {
task_id: "task-1".into(),
command: "sleep 10".into(),
status: "completed".into(),
exit_code: Some(0),
started: "2026-03-09T00:00:00Z".into(),
ended: Some("2026-03-09T00:00:05Z".into()),
duration_secs: 5.0,
output: "hello".into(),
output_file: "/tmp/task-1.log".into(),
truncated: false,
truncation_hint: String::new(),
raw_output_bytes: 5,
}));
let prompt = out.to_prompt_format();
assert!(prompt.contains("Duration: 5.00s"), "{prompt}");
assert!(prompt.contains("Output File: /tmp/task-1.log"), "{prompt}");
assert!(
!prompt.contains("Started") && !prompt.contains("Ended"),
"absolute instants must not be model-visible: {prompt}"
);
assert!(
!prompt.contains("2026-03-09"),
"no wall-clock date may survive into the prompt: {prompt}"
);
}
#[test]
fn task_output_prompt_omits_empty_output_file() {
let out = ToolOutput::TaskOutput(TaskOutputOutput::Result(TaskOutputResult {
task_id: "task-2".into(),
command: "true".into(),
status: "completed".into(),
exit_code: Some(0),
started: String::new(),
ended: None,
duration_secs: 0.1,
output: "done".into(),
output_file: String::new(),
truncated: false,
truncation_hint: String::new(),
raw_output_bytes: 4,
}));
let prompt = out.to_prompt_format();
assert!(!prompt.contains("Output File"), "{prompt}");
}
fn make_result(status: &str, raw_output_bytes: usize) -> TaskOutputResult {
TaskOutputResult {
task_id: "t".into(),