mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-17 15:34:54 +00:00
Merge branch 'code-branch-20251003-051152' into main
This commit is contained in:
@@ -3,6 +3,13 @@
|
||||
> [!TIP]
|
||||
> We're constantly improving Code! This page documents the core changes. You can also check our [releases page](https://github.com/just-every/code/releases) for additional information.
|
||||
|
||||
## [0.2.182] - 2025-10-03
|
||||
|
||||
- Agents: add first-class cloud agent flows with submit --wait support and richer previews. (6556ac9, 51e60cb, cdc833d)
|
||||
- Protocol: introduce MCP shim and sync the tool stack for new runtime integrations. (d0a0f01)
|
||||
- Auto-drive: forward CLI context, export rendered history, and surface progress for coordinator runs. (0d2e51f, ec0bbc4, bccd39f)
|
||||
- TUI: open the undo timeline overlay on double Esc and persist auto-resolve workflows between sessions. (a658b1a, e1916f7, 4e35c09)
|
||||
|
||||
## [0.2.180] - 2025-10-01
|
||||
|
||||
- Auto-drive: add final observer validation before finishing runs so missed work is caught. (94061ee)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@just-every/code",
|
||||
"version": "0.2.181",
|
||||
"version": "0.2.182",
|
||||
"license": "Apache-2.0",
|
||||
"description": "Lightweight coding agent that runs in your terminal - fork of OpenAI Codex",
|
||||
"bin": {
|
||||
@@ -35,10 +35,10 @@
|
||||
"prettier": "^3.3.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@just-every/code-darwin-arm64": "0.2.181",
|
||||
"@just-every/code-darwin-x64": "0.2.181",
|
||||
"@just-every/code-linux-x64-musl": "0.2.181",
|
||||
"@just-every/code-linux-arm64-musl": "0.2.181",
|
||||
"@just-every/code-win32-x64": "0.2.181"
|
||||
"@just-every/code-darwin-arm64": "0.2.182",
|
||||
"@just-every/code-darwin-x64": "0.2.182",
|
||||
"@just-every/code-linux-x64-musl": "0.2.182",
|
||||
"@just-every/code-linux-arm64-musl": "0.2.182",
|
||||
"@just-every/code-win32-x64": "0.2.182"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,8 +89,8 @@ use self::auto_coordinator::{
|
||||
use self::limits_overlay::{LimitsOverlay, LimitsOverlayContent, LimitsTab};
|
||||
use self::rate_limit_refresh::start_rate_limit_refresh;
|
||||
use self::history_render::{
|
||||
CachedLayout, HistoryRenderState, RenderRequest, RenderRequestKind, RenderSettings,
|
||||
VisibleCell,
|
||||
explore_should_hold_title, CachedLayout, HistoryRenderState, RenderRequest, RenderRequestKind,
|
||||
RenderSettings, VisibleCell,
|
||||
};
|
||||
use codex_core::parse_command::ParsedCommand;
|
||||
use codex_core::protocol::AgentMessageDeltaEvent;
|
||||
@@ -2518,7 +2518,7 @@ impl ChatWidget<'_> {
|
||||
|
||||
fn refresh_reasoning_collapsed_visibility(&mut self) {
|
||||
let show = self.config.tui.show_reasoning;
|
||||
let mut changed = false;
|
||||
let mut needs_invalidate = false;
|
||||
if show {
|
||||
for cell in &self.history_cells {
|
||||
if let Some(reasoning_cell) = cell
|
||||
@@ -2526,70 +2526,78 @@ impl ChatWidget<'_> {
|
||||
.downcast_ref::<history_cell::CollapsibleReasoningCell>()
|
||||
{
|
||||
if reasoning_cell.set_hide_when_collapsed(false) {
|
||||
changed = true;
|
||||
needs_invalidate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if changed {
|
||||
self.invalidate_height_cache();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
use std::collections::HashSet;
|
||||
let mut hide_indices: HashSet<usize> = HashSet::new();
|
||||
let len = self.history_cells.len();
|
||||
let mut idx = 0usize;
|
||||
while idx < len {
|
||||
let is_explore = self.history_cells[idx]
|
||||
.as_any()
|
||||
.downcast_ref::<history_cell::ExploreAggregationCell>()
|
||||
.is_some();
|
||||
if !is_explore {
|
||||
idx += 1;
|
||||
continue;
|
||||
}
|
||||
let mut reasoning_indices: Vec<usize> = Vec::new();
|
||||
let mut j = idx + 1;
|
||||
while j < len {
|
||||
if self.history_cells[j]
|
||||
} else {
|
||||
use std::collections::HashSet;
|
||||
let mut hide_indices: HashSet<usize> = HashSet::new();
|
||||
let len = self.history_cells.len();
|
||||
let mut idx = 0usize;
|
||||
while idx < len {
|
||||
let is_explore = self.history_cells[idx]
|
||||
.as_any()
|
||||
.downcast_ref::<history_cell::CollapsibleReasoningCell>()
|
||||
.is_some()
|
||||
{
|
||||
reasoning_indices.push(j);
|
||||
j += 1;
|
||||
.downcast_ref::<history_cell::ExploreAggregationCell>()
|
||||
.is_some();
|
||||
if !is_explore {
|
||||
idx += 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
let mut reasoning_indices: Vec<usize> = Vec::new();
|
||||
let mut j = idx + 1;
|
||||
while j < len {
|
||||
if self.history_cells[j]
|
||||
.as_any()
|
||||
.downcast_ref::<history_cell::CollapsibleReasoningCell>()
|
||||
.is_some()
|
||||
{
|
||||
reasoning_indices.push(j);
|
||||
j += 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if reasoning_indices.len() > 1 {
|
||||
for &ri in &reasoning_indices[..reasoning_indices.len() - 1] {
|
||||
hide_indices.insert(ri);
|
||||
}
|
||||
}
|
||||
idx = j;
|
||||
}
|
||||
if reasoning_indices.len() > 1 {
|
||||
for &ri in &reasoning_indices[..reasoning_indices.len() - 1] {
|
||||
hide_indices.insert(ri);
|
||||
|
||||
for (i, cell) in self.history_cells.iter().enumerate() {
|
||||
if let Some(reasoning_cell) = cell
|
||||
.as_any()
|
||||
.downcast_ref::<history_cell::CollapsibleReasoningCell>()
|
||||
{
|
||||
if hide_indices.contains(&i) {
|
||||
if reasoning_cell.set_hide_when_collapsed(true) {
|
||||
needs_invalidate = true;
|
||||
}
|
||||
} else if reasoning_cell.set_hide_when_collapsed(false) {
|
||||
needs_invalidate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
idx = j;
|
||||
}
|
||||
|
||||
for (i, cell) in self.history_cells.iter().enumerate() {
|
||||
if let Some(reasoning_cell) = cell
|
||||
.as_any()
|
||||
.downcast_ref::<history_cell::CollapsibleReasoningCell>()
|
||||
for cell in &mut self.history_cells {
|
||||
if let Some(explore_cell) = cell
|
||||
.as_any_mut()
|
||||
.downcast_mut::<history_cell::ExploreAggregationCell>()
|
||||
{
|
||||
if hide_indices.contains(&i) {
|
||||
if reasoning_cell.set_hide_when_collapsed(true) {
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if reasoning_cell.set_hide_when_collapsed(false) {
|
||||
changed = true;
|
||||
}
|
||||
let should_force =
|
||||
explore_should_hold_title(&self.history_state, explore_cell.record().id);
|
||||
if explore_cell.set_force_exploring_header(should_force) {
|
||||
needs_invalidate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if changed {
|
||||
if needs_invalidate {
|
||||
self.invalidate_height_cache();
|
||||
self.request_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5883,9 +5891,12 @@ impl ChatWidget<'_> {
|
||||
HistoryRecord::Patch(state) => {
|
||||
Some(Box::new(history_cell::PatchSummaryCell::from_record(state.clone())))
|
||||
}
|
||||
HistoryRecord::Explore(state) => Some(Box::new(
|
||||
history_cell::ExploreAggregationCell::from_record(state.clone()),
|
||||
)),
|
||||
HistoryRecord::Explore(state) => {
|
||||
let mut cell = history_cell::ExploreAggregationCell::from_record(state.clone());
|
||||
let hold_title = explore_should_hold_title(&self.history_state, state.id);
|
||||
cell.set_force_exploring_header(hold_title);
|
||||
Some(Box::new(cell))
|
||||
}
|
||||
HistoryRecord::RateLimits(state) => Some(Box::new(
|
||||
history_cell::RateLimitsCell::from_record(state.clone()),
|
||||
)),
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::history::state::{HistoryId, HistoryRecord, HistoryState};
|
||||
use crate::history_cell::{
|
||||
assistant_markdown_lines,
|
||||
compute_assistant_layout,
|
||||
explore_lines_from_record,
|
||||
explore_lines_from_record_with_force,
|
||||
diff_lines_from_record,
|
||||
exec_display_lines_from_record,
|
||||
merged_exec_lines_from_record,
|
||||
@@ -446,7 +446,8 @@ impl<'a> RenderRequest<'a> {
|
||||
|
||||
if let RenderRequestKind::Explore { id } = self.kind {
|
||||
if let Some(HistoryRecord::Explore(record)) = history_state.record(id) {
|
||||
return explore_lines_from_record(record);
|
||||
let hold_title = explore_should_hold_title(history_state, id);
|
||||
return explore_lines_from_record_with_force(record, hold_title);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,6 +494,29 @@ pub(crate) enum RenderRequestKind {
|
||||
Assistant { id: HistoryId },
|
||||
}
|
||||
|
||||
pub(crate) fn explore_should_hold_title(history_state: &HistoryState, explore_id: HistoryId) -> bool {
|
||||
if explore_id == HistoryId::ZERO {
|
||||
return true;
|
||||
}
|
||||
|
||||
let Some(mut idx) = history_state.index_of(explore_id) else {
|
||||
return true;
|
||||
};
|
||||
|
||||
idx += 1;
|
||||
while let Some(record) = history_state.get(idx) {
|
||||
match record {
|
||||
HistoryRecord::Reasoning(_) => {
|
||||
idx += 1;
|
||||
continue;
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -1254,7 +1278,7 @@ mod tests {
|
||||
.expect("explore layout missing")
|
||||
.layout();
|
||||
let text = collect_lines(&layout);
|
||||
assert!(text.iter().any(|line| line.contains("Explored")));
|
||||
assert!(text.iter().any(|line| line.contains("Exploring")));
|
||||
assert!(text.iter().any(|line| line.contains("pattern")));
|
||||
}
|
||||
|
||||
@@ -1370,8 +1394,24 @@ mod tests {
|
||||
"collapsed reasoning cells should not push the next visible cell"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explore_should_hold_title_until_non_reasoning_block() {
|
||||
let mut state = HistoryState::new();
|
||||
let explore_id = insert_explore_record(&mut state);
|
||||
assert!(explore_should_hold_title(&state, explore_id));
|
||||
|
||||
let _reasoning_id = state.push(HistoryRecord::Reasoning(make_reasoning_state(
|
||||
"reasoning only",
|
||||
)));
|
||||
assert!(explore_should_hold_title(&state, explore_id));
|
||||
|
||||
let _plain_id = state.push(HistoryRecord::PlainMessage(make_plain_message(
|
||||
"ready to summarize",
|
||||
)));
|
||||
assert!(!explore_should_hold_title(&state, explore_id));
|
||||
}
|
||||
}
|
||||
/// Output from `HistoryRenderState::visible_cells()`. Contains the resolved
|
||||
/// layout (if any), plus the optional `HistoryCell` pointer so the caller can
|
||||
/// reuse existing caches.
|
||||
|
||||
+1
-1
@@ -2,5 +2,5 @@
|
||||
source: tui/src/chatwidget/tests.rs
|
||||
expression: blob2
|
||||
---
|
||||
• Explored
|
||||
• Exploring...
|
||||
└ List ls -la
|
||||
|
||||
+1
-1
@@ -2,6 +2,6 @@
|
||||
source: tui/src/chatwidget/tests.rs
|
||||
expression: blob4
|
||||
---
|
||||
• Explored
|
||||
• Exploring...
|
||||
└ List ls -la
|
||||
Read foo.txt
|
||||
|
||||
+1
-1
@@ -2,6 +2,6 @@
|
||||
source: tui/src/chatwidget/tests.rs
|
||||
expression: blob5
|
||||
---
|
||||
• Explored
|
||||
• Exploring...
|
||||
└ List ls -la
|
||||
Read foo.txt
|
||||
|
||||
+1
-1
@@ -2,6 +2,6 @@
|
||||
source: tui/src/chatwidget/tests.rs
|
||||
expression: blob6
|
||||
---
|
||||
• Explored
|
||||
• Exploring...
|
||||
└ List ls -la
|
||||
Read foo.txt, bar.txt
|
||||
|
||||
@@ -13,11 +13,15 @@ use std::path::{Component, Path};
|
||||
|
||||
pub(crate) struct ExploreAggregationCell {
|
||||
record: ExploreRecord,
|
||||
force_exploring_header: bool,
|
||||
}
|
||||
|
||||
impl ExploreAggregationCell {
|
||||
pub(crate) fn from_record(record: ExploreRecord) -> Self {
|
||||
Self { record }
|
||||
Self {
|
||||
record,
|
||||
force_exploring_header: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn record(&self) -> &ExploreRecord {
|
||||
@@ -28,6 +32,14 @@ impl ExploreAggregationCell {
|
||||
&mut self.record
|
||||
}
|
||||
|
||||
pub(crate) fn set_force_exploring_header(&mut self, force: bool) -> bool {
|
||||
if self.force_exploring_header == force {
|
||||
return false;
|
||||
}
|
||||
self.force_exploring_header = force;
|
||||
true
|
||||
}
|
||||
|
||||
fn current_exec_status(&self) -> ExecStatus {
|
||||
if self
|
||||
.record
|
||||
@@ -66,7 +78,7 @@ impl HistoryCell for ExploreAggregationCell {
|
||||
}
|
||||
|
||||
fn display_lines(&self) -> Vec<Line<'static>> {
|
||||
explore_lines_from_record(&self.record)
|
||||
explore_lines_from_record_with_force(&self.record, self.force_exploring_header)
|
||||
}
|
||||
|
||||
fn desired_height(&self, width: u16) -> u16 {
|
||||
@@ -255,7 +267,15 @@ pub(crate) fn explore_record_update_status(
|
||||
}
|
||||
|
||||
pub(crate) fn explore_lines_from_record(record: &ExploreRecord) -> Vec<Line<'static>> {
|
||||
let exploring = record.entries.is_empty()
|
||||
explore_lines_from_record_with_force(record, false)
|
||||
}
|
||||
|
||||
pub(crate) fn explore_lines_from_record_with_force(
|
||||
record: &ExploreRecord,
|
||||
force_exploring: bool,
|
||||
) -> Vec<Line<'static>> {
|
||||
let exploring = force_exploring
|
||||
|| record.entries.is_empty()
|
||||
|| record
|
||||
.entries
|
||||
.iter()
|
||||
@@ -375,6 +395,9 @@ mod tests {
|
||||
}
|
||||
let completed_lines = explore_lines_from_record(&completed);
|
||||
assert_eq!(line_text(&completed_lines[0]), "Explored");
|
||||
|
||||
let forced_lines = explore_lines_from_record_with_force(&completed, true);
|
||||
assert_eq!(line_text(&forced_lines[0]), "Exploring...");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -111,6 +111,7 @@ pub(crate) use diff::{
|
||||
};
|
||||
pub(crate) use explore::{
|
||||
explore_lines_from_record,
|
||||
explore_lines_from_record_with_force,
|
||||
explore_record_push_from_parsed,
|
||||
explore_record_update_status,
|
||||
ExploreAggregationCell,
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
## @just-every/code v0.2.180
|
||||
## @just-every/code v0.2.182
|
||||
|
||||
This release hardens auto-drive finishes and keeps decision prompts tidy.
|
||||
This release expands cloud agent automation and polishes coordinator workflows.
|
||||
|
||||
### Changes
|
||||
|
||||
- Auto-drive: add final observer validation before finishing runs so missed work is caught.
|
||||
- Auto-drive: stop appending ellipsis to decision summaries so prompts stay clean.
|
||||
- Agents: add first-class cloud agent flows with submit --wait support and richer previews.
|
||||
- Protocol: introduce MCP shim and sync the tool stack for new runtime integrations.
|
||||
- Auto-drive: forward CLI context, export rendered history, and surface progress for coordinator runs.
|
||||
- TUI: open the undo timeline overlay on double Esc and persist auto-resolve workflows between sessions.
|
||||
|
||||
### Install
|
||||
|
||||
@@ -14,4 +16,4 @@ npm install -g @just-every/code@latest
|
||||
code
|
||||
```
|
||||
|
||||
Compare: https://github.com/just-every/code/compare/v0.2.179...v0.2.180
|
||||
Compare: https://github.com/just-every/code/compare/v0.2.181...v0.2.182
|
||||
|
||||
Reference in New Issue
Block a user