mirror of
https://github.com/hanzoai/dev.git
synced 2026-10-25 03:32:32 +00:00
feat(tui): preserve event order relative to final assistant message; stabilize interrupt processing order\n\n- Track per-event sequence in and \n- Move exec/tool cells ahead of final assistant cell to keep narrative flow\n- Render tool results with markdown extracted from JSON\n- Improve history insertion: use Reverse Index + Clear instead of raw escape strings\n\nchore(deps): remove ratatui git override; downgrade (tests only); refresh lockfile with minor bumps (image, clap, deadpool, deranged)
This commit is contained in:
Generated
+164
-155
@@ -193,7 +193,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf"
|
||||
dependencies = [
|
||||
"clipboard-win",
|
||||
"image 0.25.6",
|
||||
"image 0.25.7",
|
||||
"log",
|
||||
"objc2",
|
||||
"objc2-app-kit",
|
||||
@@ -423,9 +423,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.2"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
|
||||
checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
@@ -461,7 +461,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"regex-automata 0.4.9",
|
||||
"regex-automata",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -650,9 +650,9 @@ checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.45"
|
||||
version = "4.5.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318"
|
||||
checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -660,9 +660,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.44"
|
||||
version = "4.5.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8"
|
||||
checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -761,7 +761,7 @@ dependencies = [
|
||||
"chromiumoxide_types",
|
||||
"chrono",
|
||||
"futures",
|
||||
"image 0.25.6",
|
||||
"image 0.25.7",
|
||||
"once_cell",
|
||||
"rand 0.8.5",
|
||||
"regex",
|
||||
@@ -849,7 +849,7 @@ dependencies = [
|
||||
"fs2",
|
||||
"futures",
|
||||
"htmd",
|
||||
"image 0.25.6",
|
||||
"image 0.25.7",
|
||||
"img_hash",
|
||||
"landlock",
|
||||
"lazy_static",
|
||||
@@ -1097,7 +1097,7 @@ dependencies = [
|
||||
"color-eyre",
|
||||
"crossterm",
|
||||
"diffy",
|
||||
"image 0.25.6",
|
||||
"image 0.25.7",
|
||||
"insta",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
@@ -1398,11 +1398,10 @@ checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
|
||||
|
||||
[[package]]
|
||||
name = "deadpool"
|
||||
version = "0.10.0"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb84100978c1c7b37f09ed3ce3e5f843af02c2a2c431bae5b19230dad2c1b490"
|
||||
checksum = "5ed5957ff93768adf7a65ab167a17835c3d2c3c50d084fe305174c112f468e2f"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"deadpool-runtime",
|
||||
"num_cpus",
|
||||
"tokio",
|
||||
@@ -1427,9 +1426,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.4.0"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||
checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
"serde",
|
||||
@@ -1507,7 +1506,7 @@ version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b545b8c50194bdd008283985ab0b31dba153cfd5b3066a92770634fbc0d7d291"
|
||||
dependencies = [
|
||||
"nu-ansi-term 0.50.1",
|
||||
"nu-ansi-term",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1833,6 +1832,26 @@ version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "fax"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab"
|
||||
dependencies = [
|
||||
"fax_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fax_derive"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.106",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fd-lock"
|
||||
version = "4.0.4"
|
||||
@@ -2046,21 +2065,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gethostname"
|
||||
version = "0.4.3"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
|
||||
checksum = "fc257fdb4038301ce4b9cd1b3b51704509692bb3ff716a410cbd07925d9dae55"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-targets 0.48.5",
|
||||
"rustix 1.0.8",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.23"
|
||||
version = "0.2.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1"
|
||||
checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df"
|
||||
dependencies = [
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2086,7 +2105,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi 0.14.2+wasi-0.2.4",
|
||||
"wasi 0.14.3+wasi-0.2.4",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@@ -2121,8 +2140,8 @@ dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
"log",
|
||||
"regex-automata 0.4.9",
|
||||
"regex-syntax 0.8.5",
|
||||
"regex-automata",
|
||||
"regex-syntax 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2350,7 +2369,7 @@ dependencies = [
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2 0.6.0",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -2509,7 +2528,7 @@ dependencies = [
|
||||
"globset",
|
||||
"log",
|
||||
"memchr",
|
||||
"regex-automata 0.4.9",
|
||||
"regex-automata",
|
||||
"same-file",
|
||||
"walkdir",
|
||||
"winapi-util",
|
||||
@@ -2531,9 +2550,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.6"
|
||||
version = "0.25.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a"
|
||||
checksum = "1c6a3ce16143778e24df6f95365f12ed105425b22abefd289dd88a64bab59605"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
@@ -2541,6 +2560,7 @@ dependencies = [
|
||||
"exr",
|
||||
"gif",
|
||||
"image-webp",
|
||||
"moxcms",
|
||||
"num-traits",
|
||||
"png",
|
||||
"qoi",
|
||||
@@ -2554,9 +2574,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "image-webp"
|
||||
version = "0.2.3"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6970fe7a5300b4b42e62c52efa0187540a5bef546c60edaf554ef595d2e6f0b"
|
||||
checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3"
|
||||
dependencies = [
|
||||
"byteorder-lite",
|
||||
"quick-error",
|
||||
@@ -2799,20 +2819,14 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.33"
|
||||
version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
|
||||
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jpeg-decoder"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.77"
|
||||
@@ -3052,11 +3066,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "matchers"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
|
||||
dependencies = [
|
||||
"regex-automata 0.1.10",
|
||||
"regex-automata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3157,6 +3171,16 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moxcms"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddd32fa8935aeadb8a8a6b6b351e40225570a37c43de67690383d87ef170cd08"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"pxfm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multimap"
|
||||
version = "0.10.1"
|
||||
@@ -3221,16 +3245,6 @@ version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||
dependencies = [
|
||||
"overload",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.50.1"
|
||||
@@ -3491,12 +3505,6 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "4.2.2"
|
||||
@@ -3649,11 +3657,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.16"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
|
||||
checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.9.3",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
@@ -3698,9 +3706,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "potential_utf"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
|
||||
checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a"
|
||||
dependencies = [
|
||||
"zerovec",
|
||||
]
|
||||
@@ -3822,6 +3830,15 @@ version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
|
||||
|
||||
[[package]]
|
||||
name = "pxfm"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e790881194f6f6e86945f0a42a6981977323669aeb6c40e9c7ec253133b96f8"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qoi"
|
||||
version = "0.4.1"
|
||||
@@ -3839,18 +3856,18 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.38.2"
|
||||
version = "0.38.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d200a41a7797e6461bd04e4e95c3347053a731c32c87f066f2f0dda22dbdbba8"
|
||||
checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quinn"
|
||||
version = "0.11.8"
|
||||
version = "0.11.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8"
|
||||
checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"cfg_aliases 0.2.1",
|
||||
@@ -3859,7 +3876,7 @@ dependencies = [
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"socket2 0.5.10",
|
||||
"socket2",
|
||||
"thiserror 2.0.16",
|
||||
"tokio",
|
||||
"tracing",
|
||||
@@ -3868,9 +3885,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quinn-proto"
|
||||
version = "0.11.12"
|
||||
version = "0.11.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e"
|
||||
checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.3.3",
|
||||
@@ -3889,16 +3906,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quinn-udp"
|
||||
version = "0.5.13"
|
||||
version = "0.5.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970"
|
||||
checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
|
||||
dependencies = [
|
||||
"cfg_aliases 0.2.1",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2 0.5.10",
|
||||
"socket2",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3988,7 +4005,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ratatui"
|
||||
version = "0.29.0"
|
||||
source = "git+https://github.com/nornagon/ratatui?branch=nornagon-v0.29.0-patch#9b2ad1298408c45918ee9f8241a6f95498cdbed2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b"
|
||||
dependencies = [
|
||||
"bitflags 2.9.3",
|
||||
"cassowary",
|
||||
@@ -4002,7 +4020,7 @@ dependencies = [
|
||||
"strum 0.26.3",
|
||||
"unicode-segmentation",
|
||||
"unicode-truncate",
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4013,7 +4031,7 @@ checksum = "e8fe71c551c67f34e4fa49797227f614cd064b82855d7b72d424e40d08ec0542"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"icy_sixel",
|
||||
"image 0.25.6",
|
||||
"image 0.25.7",
|
||||
"rand 0.8.5",
|
||||
"ratatui",
|
||||
"rustix 0.38.44",
|
||||
@@ -4144,41 +4162,32 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
version = "1.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata 0.4.9",
|
||||
"regex-syntax 0.8.5",
|
||||
"regex-automata",
|
||||
"regex-syntax 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.10"
|
||||
version = "0.4.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
dependencies = [
|
||||
"regex-syntax 0.6.29",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax 0.8.5",
|
||||
"regex-syntax 0.8.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-lite"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
|
||||
checksum = "943f41321c63ef1c92fd763bfe054d2668f7f225a5c29f0105903dc2fc04ba30"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
@@ -4188,9 +4197,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001"
|
||||
|
||||
[[package]]
|
||||
name = "relative-path"
|
||||
@@ -4819,16 +4828,6 @@ version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.0"
|
||||
@@ -5100,7 +5099,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"onig",
|
||||
"plist",
|
||||
"regex-syntax 0.8.5",
|
||||
"regex-syntax 0.8.6",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
@@ -5205,7 +5204,7 @@ checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
|
||||
dependencies = [
|
||||
"smawk",
|
||||
"unicode-linebreak",
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5259,23 +5258,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.9.1"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e"
|
||||
checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f"
|
||||
dependencies = [
|
||||
"fax",
|
||||
"flate2",
|
||||
"jpeg-decoder",
|
||||
"half",
|
||||
"quick-error",
|
||||
"weezl",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.41"
|
||||
version = "0.3.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||
checksum = "8ca967379f9d8eb8058d86ed467d81d03e81acd45757e4ca341c24affbe8e8e3"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"libc",
|
||||
"num-conv",
|
||||
"num_threads",
|
||||
@@ -5287,15 +5288,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||
checksum = "a9108bb380861b07264b950ded55a44a14a4adc68b9f5efd85aafc3aa4d40a68"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.22"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
|
||||
checksum = "7182799245a7264ce590b349d90338f1c1affad93d2639aed5f8f69c090b334c"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
@@ -5362,7 +5363,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"slab",
|
||||
"socket2 0.6.0",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
@@ -5624,14 +5625,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.19"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
|
||||
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
|
||||
dependencies = [
|
||||
"matchers",
|
||||
"nu-ansi-term 0.46.0",
|
||||
"nu-ansi-term",
|
||||
"once_cell",
|
||||
"regex",
|
||||
"regex-automata",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
@@ -5664,7 +5665,7 @@ checksum = "6d7b8994f367f16e6fa14b5aebbcb350de5d7cbea82dc5b00ae997dd71680dd2"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"regex",
|
||||
"regex-syntax 0.8.5",
|
||||
"regex-syntax 0.8.6",
|
||||
"serde_json",
|
||||
"streaming-iterator",
|
||||
"tree-sitter-language",
|
||||
@@ -5723,7 +5724,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "911e93158bf80bbc94bad533b2b16e3d711e1132d69a6a6980c3920a63422c19"
|
||||
dependencies = [
|
||||
"ratatui",
|
||||
"unicode-width 0.2.1",
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5809,9 +5810,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.1"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
|
||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
@@ -5827,9 +5828,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.5.6"
|
||||
version = "2.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "137a3c834eaf7139b73688502f3f1141a0337c5d8e4d9b536f9b8c796e26a7c4"
|
||||
checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
@@ -5910,23 +5911,35 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "vt100"
|
||||
version = "0.16.2"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "054ff75fb8fa83e609e685106df4faeffdf3a735d3c74ebce97ec557d5d36fd9"
|
||||
checksum = "84cd863bf0db7e392ba3bd04994be3473491b31e66340672af5d11943c6274de"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"unicode-width 0.2.1",
|
||||
"log",
|
||||
"unicode-width 0.1.14",
|
||||
"vte",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vte"
|
||||
version = "0.15.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5924018406ce0063cd67f8e008104968b74b563ee1b85dde3ed1f7cb87d3dbd"
|
||||
checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"memchr",
|
||||
"utf8parse",
|
||||
"vte_generate_state_changes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vte_generate_state_changes"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5965,11 +5978,11 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
version = "0.14.3+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||
checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6632,12 +6645,11 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||
|
||||
[[package]]
|
||||
name = "wiremock"
|
||||
version = "0.6.4"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2b8b99d4cdbf36b239a9532e31fe4fb8acc38d1897c1761e161550a7dc78e6a"
|
||||
checksum = "08db1edfb05d9b3c1542e521aea074442088292f00b5f28e435c714a98f85031"
|
||||
dependencies = [
|
||||
"assert-json-diff",
|
||||
"async-trait",
|
||||
"base64 0.22.1",
|
||||
"deadpool",
|
||||
"futures",
|
||||
@@ -6655,13 +6667,10 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.39.0"
|
||||
name = "wit-bindgen"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags 2.9.3",
|
||||
]
|
||||
checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814"
|
||||
|
||||
[[package]]
|
||||
name = "writeable"
|
||||
@@ -6671,20 +6680,20 @@ checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
|
||||
|
||||
[[package]]
|
||||
name = "x11rb"
|
||||
version = "0.13.1"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12"
|
||||
checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414"
|
||||
dependencies = [
|
||||
"gethostname",
|
||||
"rustix 0.38.44",
|
||||
"rustix 1.0.8",
|
||||
"x11rb-protocol",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11rb-protocol"
|
||||
version = "0.13.1"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d"
|
||||
checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd"
|
||||
|
||||
[[package]]
|
||||
name = "xml5ever"
|
||||
|
||||
+1
-2
@@ -65,5 +65,4 @@ lto = "fat" # Maximum link-time optimization
|
||||
strip = "debuginfo" # Fully strip debug info in production artifacts
|
||||
|
||||
[patch.crates-io]
|
||||
# ratatui = { path = "../../ratatui" }
|
||||
ratatui = { git = "https://github.com/nornagon/ratatui", branch = "nornagon-v0.29.0-patch" }
|
||||
# No overrides; use crates.io ratatui release
|
||||
|
||||
@@ -26,7 +26,7 @@ tokio = { version = "1", features = [
|
||||
] }
|
||||
toml = "0.9.5"
|
||||
tracing = { version = "0.1.41", features = ["log"] }
|
||||
wiremock = "0.6"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
wiremock = "0.6"
|
||||
|
||||
@@ -94,4 +94,7 @@ chrono = { version = "0.4", features = ["serde"] }
|
||||
insta = "1.43.1"
|
||||
pretty_assertions = "1"
|
||||
rand = "0.9"
|
||||
vt100 = "0.16.2"
|
||||
# Downgrade vt100 to avoid a hard requirement on unicode-width 0.2.1,
|
||||
# which conflicts with ratatui 0.29.x pinning 0.2.0. This crate is
|
||||
# only used in tests.
|
||||
vt100 = "0.15.0"
|
||||
|
||||
@@ -254,6 +254,11 @@ pub(crate) struct ChatWidget<'a> {
|
||||
// Track active task ids so we don't drop the working status while any
|
||||
// agent/sub‑agent is still running (long‑running sessions can interleave).
|
||||
active_task_ids: HashSet<String>,
|
||||
|
||||
// Event sequencing to preserve original order across streaming/tool events
|
||||
next_seq: u64,
|
||||
// Sequence marker for the final assistant message in the current turn
|
||||
seq_answer_final: Option<u64>,
|
||||
}
|
||||
|
||||
struct PendingJumpBack {
|
||||
@@ -875,11 +880,43 @@ impl ChatWidget<'_> {
|
||||
F1: FnOnce(&mut interrupts::InterruptManager),
|
||||
F2: FnOnce(&mut Self),
|
||||
{
|
||||
if self.is_write_cycle_active() {
|
||||
defer_fn(&mut self.interrupts);
|
||||
} else {
|
||||
handle_fn(self);
|
||||
}
|
||||
if self.is_write_cycle_active() { defer_fn(&mut self.interrupts); } else { handle_fn(self); }
|
||||
}
|
||||
|
||||
fn next_sequence(&mut self) -> u64 {
|
||||
let s = self.next_seq; self.next_seq = self.next_seq.saturating_add(1); s
|
||||
}
|
||||
|
||||
fn index_of_final_assistant(&self) -> Option<usize> {
|
||||
self.history_cells.iter().rposition(|c| c.as_any().downcast_ref::<history_cell::AssistantMarkdownCell>().is_some())
|
||||
}
|
||||
|
||||
fn maybe_move_last_before_final_assistant_exec(&mut self, call_id: &str) {
|
||||
let assistant_idx = match self.index_of_final_assistant() { Some(i) => i, None => return };
|
||||
if self.history_cells.is_empty() { return; }
|
||||
let last_idx = self.history_cells.len() - 1; if last_idx <= assistant_idx { return; }
|
||||
let cell = self.history_cells.remove(last_idx); self.history_cells.insert(assistant_idx, cell);
|
||||
if let Some(rc) = self.running_commands.get_mut(call_id) { rc.history_index = Some(assistant_idx); }
|
||||
self.invalidate_height_cache(); self.request_redraw();
|
||||
}
|
||||
|
||||
fn maybe_move_last_before_final_assistant_tool(&mut self, call_id: &str) {
|
||||
let assistant_idx = match self.index_of_final_assistant() { Some(i) => i, None => return };
|
||||
if self.history_cells.is_empty() { return; }
|
||||
let last_idx = self.history_cells.len() - 1; if last_idx <= assistant_idx { return; }
|
||||
let cell = self.history_cells.remove(last_idx); self.history_cells.insert(assistant_idx, cell);
|
||||
if let Some(idx) = self.running_custom_tools.get_mut(call_id) { *idx = assistant_idx; }
|
||||
self.invalidate_height_cache(); self.request_redraw();
|
||||
}
|
||||
|
||||
fn maybe_move_last_before_final_assistant(&mut self, seq: u64) {
|
||||
let ans_seq = match self.seq_answer_final { Some(s) => s, None => return };
|
||||
if seq >= ans_seq { return; }
|
||||
let assistant_idx = match self.index_of_final_assistant() { Some(i) => i, None => return };
|
||||
if self.history_cells.is_empty() { return; }
|
||||
let last_idx = self.history_cells.len() - 1; if last_idx <= assistant_idx { return; }
|
||||
let cell = self.history_cells.remove(last_idx); self.history_cells.insert(assistant_idx, cell);
|
||||
self.invalidate_height_cache(); self.request_redraw();
|
||||
}
|
||||
|
||||
|
||||
@@ -1752,6 +1789,8 @@ impl ChatWidget<'_> {
|
||||
pending_jump_back: None,
|
||||
active_task_ids: HashSet::new(),
|
||||
browser_is_external: false,
|
||||
next_seq: 1,
|
||||
seq_answer_final: None,
|
||||
};
|
||||
|
||||
// Note: Initial redraw needs to be triggered after widget is added to app_state
|
||||
@@ -1870,6 +1909,8 @@ impl ChatWidget<'_> {
|
||||
pending_jump_back: None,
|
||||
active_task_ids: HashSet::new(),
|
||||
browser_is_external: false,
|
||||
next_seq: 1,
|
||||
seq_answer_final: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2836,6 +2877,8 @@ impl ChatWidget<'_> {
|
||||
self.mark_needs_redraw();
|
||||
}
|
||||
EventMsg::AgentMessage(AgentMessageEvent { message }) => {
|
||||
// Record sequence for the final assistant message
|
||||
self.seq_answer_final = Some(self.next_sequence());
|
||||
tracing::debug!(
|
||||
"AgentMessage final id={} bytes={} preview={:?}",
|
||||
id,
|
||||
@@ -3153,7 +3196,8 @@ impl ChatWidget<'_> {
|
||||
// If a stream is active, defer until the stream finalizes so
|
||||
// the plan block doesn't split a heading and its content.
|
||||
if self.is_write_cycle_active() {
|
||||
self.interrupts.push_plan_update(update);
|
||||
let seq = self.next_sequence();
|
||||
self.interrupts.push_plan_update(seq, update);
|
||||
} else {
|
||||
self.add_to_history(history_cell::new_plan_update(update));
|
||||
}
|
||||
@@ -3161,8 +3205,9 @@ impl ChatWidget<'_> {
|
||||
EventMsg::ExecApprovalRequest(ev) => {
|
||||
let id2 = id.clone();
|
||||
let ev2 = ev.clone();
|
||||
let seq = self.next_sequence();
|
||||
self.defer_or_handle(
|
||||
|interrupts| interrupts.push_exec_approval(id, ev),
|
||||
move |interrupts| interrupts.push_exec_approval(seq, id, ev),
|
||||
|this| {
|
||||
this.finalize_active_stream();
|
||||
this.flush_interrupt_queue();
|
||||
@@ -3174,8 +3219,9 @@ impl ChatWidget<'_> {
|
||||
EventMsg::ApplyPatchApprovalRequest(ev) => {
|
||||
let id2 = id.clone();
|
||||
let ev2 = ev.clone();
|
||||
let seq = self.next_sequence();
|
||||
self.defer_or_handle(
|
||||
|interrupts| interrupts.push_apply_patch_approval(id, ev),
|
||||
move |interrupts| interrupts.push_apply_patch_approval(seq, id, ev),
|
||||
|this| {
|
||||
this.finalize_active_stream();
|
||||
this.flush_interrupt_queue();
|
||||
@@ -3186,8 +3232,9 @@ impl ChatWidget<'_> {
|
||||
}
|
||||
EventMsg::ExecCommandBegin(ev) => {
|
||||
let ev2 = ev.clone();
|
||||
let seq = self.next_sequence();
|
||||
self.defer_or_handle(
|
||||
|interrupts| interrupts.push_exec_begin(ev),
|
||||
move |interrupts| interrupts.push_exec_begin(seq, ev),
|
||||
|this| {
|
||||
// Finalize any active streaming sections, then establish
|
||||
// the running Exec cell before flushing queued interrupts.
|
||||
@@ -3241,22 +3288,25 @@ impl ChatWidget<'_> {
|
||||
}
|
||||
EventMsg::PatchApplyEnd(ev) => {
|
||||
let ev2 = ev.clone();
|
||||
let seq = self.next_sequence();
|
||||
self.defer_or_handle(
|
||||
|interrupts| interrupts.push_patch_end(ev),
|
||||
move |interrupts| interrupts.push_patch_end(seq, ev),
|
||||
|this| this.handle_patch_apply_end_now(ev2),
|
||||
);
|
||||
}
|
||||
EventMsg::ExecCommandEnd(ev) => {
|
||||
let ev2 = ev.clone();
|
||||
let seq = self.next_sequence();
|
||||
self.defer_or_handle(
|
||||
|interrupts| interrupts.push_exec_end(ev),
|
||||
move |interrupts| interrupts.push_exec_end(seq, ev),
|
||||
|this| this.handle_exec_end_now(ev2),
|
||||
);
|
||||
}
|
||||
EventMsg::McpToolCallBegin(ev) => {
|
||||
let ev2 = ev.clone();
|
||||
let seq = self.next_sequence();
|
||||
self.defer_or_handle(
|
||||
|interrupts| interrupts.push_mcp_begin(ev),
|
||||
move |interrupts| interrupts.push_mcp_begin(seq, ev),
|
||||
|this| {
|
||||
this.finalize_active_stream();
|
||||
this.flush_interrupt_queue();
|
||||
@@ -3266,8 +3316,9 @@ impl ChatWidget<'_> {
|
||||
}
|
||||
EventMsg::McpToolCallEnd(ev) => {
|
||||
let ev2 = ev.clone();
|
||||
let seq = self.next_sequence();
|
||||
self.defer_or_handle(
|
||||
|interrupts| interrupts.push_mcp_end(ev),
|
||||
move |interrupts| interrupts.push_mcp_end(seq, ev),
|
||||
|this| this.handle_mcp_end_now(ev2),
|
||||
);
|
||||
}
|
||||
@@ -3319,6 +3370,32 @@ impl ChatWidget<'_> {
|
||||
Ok(content) => (true, content),
|
||||
Err(error) => (false, error),
|
||||
};
|
||||
// Special-case web_fetch to render returned markdown nicely.
|
||||
if tool_name == "web_fetch" {
|
||||
let completed = history_cell::new_completed_web_fetch_tool_call(
|
||||
&self.config,
|
||||
params_string,
|
||||
duration,
|
||||
success,
|
||||
content,
|
||||
);
|
||||
if let Some(idx) = self.running_custom_tools.remove(&call_id) {
|
||||
if idx < self.history_cells.len() {
|
||||
self.history_cells[idx] = Box::new(completed);
|
||||
self.invalidate_height_cache();
|
||||
self.request_redraw();
|
||||
} else {
|
||||
self.add_to_history(completed);
|
||||
}
|
||||
} else {
|
||||
self.add_to_history(completed);
|
||||
}
|
||||
|
||||
// After tool completes, likely transitioning to response
|
||||
self.bottom_pane.update_status_text("responding".to_string());
|
||||
self.maybe_hide_spinner();
|
||||
return;
|
||||
}
|
||||
let completed = history_cell::new_completed_custom_tool_call(
|
||||
tool_name,
|
||||
params_string,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::VecDeque;
|
||||
// (none)
|
||||
|
||||
use codex_core::protocol::ApplyPatchApprovalRequestEvent;
|
||||
use codex_core::protocol::ExecApprovalRequestEvent;
|
||||
@@ -13,80 +13,110 @@ use super::ChatWidget;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum QueuedInterrupt {
|
||||
ExecApproval(String, ExecApprovalRequestEvent),
|
||||
ApplyPatchApproval(String, ApplyPatchApprovalRequestEvent),
|
||||
ExecBegin(ExecCommandBeginEvent),
|
||||
ExecEnd(ExecCommandEndEvent),
|
||||
McpBegin(McpToolCallBeginEvent),
|
||||
McpEnd(McpToolCallEndEvent),
|
||||
PatchEnd(PatchApplyEndEvent),
|
||||
PlanUpdate(UpdatePlanArgs),
|
||||
ExecApproval { seq: u64, id: String, ev: ExecApprovalRequestEvent },
|
||||
ApplyPatchApproval { seq: u64, id: String, ev: ApplyPatchApprovalRequestEvent },
|
||||
ExecBegin { seq: u64, ev: ExecCommandBeginEvent },
|
||||
ExecEnd { seq: u64, ev: ExecCommandEndEvent },
|
||||
McpBegin { seq: u64, ev: McpToolCallBeginEvent },
|
||||
McpEnd { seq: u64, ev: McpToolCallEndEvent },
|
||||
PatchEnd { seq: u64, ev: PatchApplyEndEvent },
|
||||
PlanUpdate { seq: u64, ev: UpdatePlanArgs },
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct InterruptManager {
|
||||
queue: VecDeque<QueuedInterrupt>,
|
||||
queue: Vec<QueuedInterrupt>,
|
||||
}
|
||||
|
||||
impl InterruptManager {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
queue: VecDeque::new(),
|
||||
queue: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn push_exec_approval(&mut self, id: String, ev: ExecApprovalRequestEvent) {
|
||||
self.queue.push_back(QueuedInterrupt::ExecApproval(id, ev));
|
||||
pub(crate) fn push_exec_approval(&mut self, seq: u64, id: String, ev: ExecApprovalRequestEvent) {
|
||||
self.queue.push(QueuedInterrupt::ExecApproval { seq, id, ev });
|
||||
}
|
||||
|
||||
pub(crate) fn push_apply_patch_approval(
|
||||
&mut self,
|
||||
seq: u64,
|
||||
id: String,
|
||||
ev: ApplyPatchApprovalRequestEvent,
|
||||
) {
|
||||
self.queue
|
||||
.push_back(QueuedInterrupt::ApplyPatchApproval(id, ev));
|
||||
self.queue.push(QueuedInterrupt::ApplyPatchApproval { seq, id, ev });
|
||||
}
|
||||
|
||||
pub(crate) fn push_exec_begin(&mut self, ev: ExecCommandBeginEvent) {
|
||||
self.queue.push_back(QueuedInterrupt::ExecBegin(ev));
|
||||
pub(crate) fn push_exec_begin(&mut self, seq: u64, ev: ExecCommandBeginEvent) {
|
||||
self.queue.push(QueuedInterrupt::ExecBegin { seq, ev });
|
||||
}
|
||||
|
||||
pub(crate) fn push_exec_end(&mut self, ev: ExecCommandEndEvent) {
|
||||
self.queue.push_back(QueuedInterrupt::ExecEnd(ev));
|
||||
pub(crate) fn push_exec_end(&mut self, seq: u64, ev: ExecCommandEndEvent) {
|
||||
self.queue.push(QueuedInterrupt::ExecEnd { seq, ev });
|
||||
}
|
||||
|
||||
pub(crate) fn push_mcp_begin(&mut self, ev: McpToolCallBeginEvent) {
|
||||
self.queue.push_back(QueuedInterrupt::McpBegin(ev));
|
||||
pub(crate) fn push_mcp_begin(&mut self, seq: u64, ev: McpToolCallBeginEvent) {
|
||||
self.queue.push(QueuedInterrupt::McpBegin { seq, ev });
|
||||
}
|
||||
|
||||
pub(crate) fn push_mcp_end(&mut self, ev: McpToolCallEndEvent) {
|
||||
self.queue.push_back(QueuedInterrupt::McpEnd(ev));
|
||||
pub(crate) fn push_mcp_end(&mut self, seq: u64, ev: McpToolCallEndEvent) {
|
||||
self.queue.push(QueuedInterrupt::McpEnd { seq, ev });
|
||||
}
|
||||
|
||||
pub(crate) fn push_patch_end(&mut self, ev: PatchApplyEndEvent) {
|
||||
self.queue.push_back(QueuedInterrupt::PatchEnd(ev));
|
||||
pub(crate) fn push_patch_end(&mut self, seq: u64, ev: PatchApplyEndEvent) {
|
||||
self.queue.push(QueuedInterrupt::PatchEnd { seq, ev });
|
||||
}
|
||||
|
||||
pub(crate) fn push_plan_update(&mut self, ev: UpdatePlanArgs) {
|
||||
self.queue.push_back(QueuedInterrupt::PlanUpdate(ev));
|
||||
pub(crate) fn push_plan_update(&mut self, seq: u64, ev: UpdatePlanArgs) {
|
||||
self.queue.push(QueuedInterrupt::PlanUpdate { seq, ev });
|
||||
}
|
||||
|
||||
pub(crate) fn flush_all(&mut self, chat: &mut ChatWidget<'_>) {
|
||||
while let Some(q) = self.queue.pop_front() {
|
||||
// Ensure stable order
|
||||
self.queue.sort_by(|a, b| seq_of(a).cmp(&seq_of(b)));
|
||||
for q in self.queue.drain(..) {
|
||||
match q {
|
||||
QueuedInterrupt::ExecApproval(id, ev) => chat.handle_exec_approval_now(id, ev),
|
||||
QueuedInterrupt::ApplyPatchApproval(id, ev) => {
|
||||
chat.handle_apply_patch_approval_now(id, ev)
|
||||
QueuedInterrupt::ExecApproval { id, ev, .. } => chat.handle_exec_approval_now(id, ev),
|
||||
QueuedInterrupt::ApplyPatchApproval { seq, id, ev } => {
|
||||
chat.handle_apply_patch_approval_now(id, ev);
|
||||
chat.maybe_move_last_before_final_assistant(seq);
|
||||
}
|
||||
QueuedInterrupt::ExecBegin { ev, .. } => {
|
||||
let call_id = ev.call_id.clone();
|
||||
chat.handle_exec_begin_now(ev);
|
||||
chat.maybe_move_last_before_final_assistant_exec(&call_id);
|
||||
}
|
||||
QueuedInterrupt::ExecEnd { ev, .. } => chat.handle_exec_end_now(ev),
|
||||
QueuedInterrupt::McpBegin { ev, .. } => {
|
||||
let call_id = ev.call_id.clone();
|
||||
chat.handle_mcp_begin_now(ev);
|
||||
chat.maybe_move_last_before_final_assistant_tool(&call_id);
|
||||
}
|
||||
QueuedInterrupt::McpEnd { ev, .. } => chat.handle_mcp_end_now(ev),
|
||||
QueuedInterrupt::PatchEnd { seq, ev, .. } => {
|
||||
chat.handle_patch_apply_end_now(ev);
|
||||
chat.maybe_move_last_before_final_assistant(seq);
|
||||
}
|
||||
QueuedInterrupt::PlanUpdate { seq, ev, .. } => {
|
||||
chat.add_to_history(crate::history_cell::new_plan_update(ev));
|
||||
chat.maybe_move_last_before_final_assistant(seq);
|
||||
}
|
||||
QueuedInterrupt::ExecBegin(ev) => chat.handle_exec_begin_now(ev),
|
||||
QueuedInterrupt::ExecEnd(ev) => chat.handle_exec_end_now(ev),
|
||||
QueuedInterrupt::McpBegin(ev) => chat.handle_mcp_begin_now(ev),
|
||||
QueuedInterrupt::McpEnd(ev) => chat.handle_mcp_end_now(ev),
|
||||
QueuedInterrupt::PatchEnd(ev) => chat.handle_patch_apply_end_now(ev),
|
||||
QueuedInterrupt::PlanUpdate(ev) => chat.add_to_history(crate::history_cell::new_plan_update(ev)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn seq_of(q: &QueuedInterrupt) -> u64 {
|
||||
match q {
|
||||
QueuedInterrupt::ExecApproval { seq, .. }
|
||||
| QueuedInterrupt::ApplyPatchApproval { seq, .. }
|
||||
| QueuedInterrupt::ExecBegin { seq, .. }
|
||||
| QueuedInterrupt::ExecEnd { seq, .. }
|
||||
| QueuedInterrupt::McpBegin { seq, .. }
|
||||
| QueuedInterrupt::McpEnd { seq, .. }
|
||||
| QueuedInterrupt::PatchEnd { seq, .. }
|
||||
| QueuedInterrupt::PlanUpdate { seq, .. } => *seq,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4908,6 +4908,72 @@ pub(crate) fn new_completed_custom_tool_call(
|
||||
}
|
||||
}
|
||||
|
||||
/// Completed web_fetch tool call with markdown rendering of the `markdown` field.
|
||||
pub(crate) fn new_completed_web_fetch_tool_call(
|
||||
cfg: &Config,
|
||||
args: Option<String>,
|
||||
duration: Duration,
|
||||
success: bool,
|
||||
result: String,
|
||||
) -> ToolCallCell {
|
||||
let duration = format_duration(duration);
|
||||
let status_str = if success { "Complete" } else { "Error" };
|
||||
let title_line = if success {
|
||||
Line::from(vec![
|
||||
Span::styled(status_str, Style::default().fg(crate::colors::success())),
|
||||
format!(", duration: {duration}").dim(),
|
||||
])
|
||||
} else {
|
||||
Line::from(vec![
|
||||
Span::styled(status_str, Style::default().fg(crate::colors::error())),
|
||||
format!(", duration: {duration}").dim(),
|
||||
])
|
||||
};
|
||||
|
||||
let invocation_str = if let Some(args) = args {
|
||||
format!("{}({})", "web_fetch", args)
|
||||
} else {
|
||||
format!("{}()", "web_fetch")
|
||||
};
|
||||
|
||||
let mut lines: Vec<Line<'static>> = Vec::new();
|
||||
lines.push(title_line);
|
||||
lines.push(Line::styled(
|
||||
invocation_str,
|
||||
Style::default()
|
||||
.fg(crate::colors::text_dim())
|
||||
.add_modifier(Modifier::ITALIC),
|
||||
));
|
||||
|
||||
// Try to parse JSON and extract the markdown field
|
||||
let mut appended_markdown = false;
|
||||
if !result.is_empty() {
|
||||
if let Ok(value) = serde_json::from_str::<serde_json::Value>(&result) {
|
||||
if let Some(md) = value.get("markdown").and_then(|v| v.as_str()) {
|
||||
lines.push(Line::from(""));
|
||||
crate::markdown::append_markdown(md, &mut lines, cfg);
|
||||
appended_markdown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: compact preview if JSON parse failed or no markdown present
|
||||
if !appended_markdown && !result.is_empty() {
|
||||
lines.push(Line::from(""));
|
||||
let preview = build_preview_lines(&result, true)
|
||||
.into_iter()
|
||||
.map(|l| l.style(Style::default().fg(crate::colors::text_dim())))
|
||||
.collect::<Vec<_>>();
|
||||
lines.extend(preview);
|
||||
}
|
||||
|
||||
lines.push(Line::from(""));
|
||||
ToolCallCell {
|
||||
lines,
|
||||
state: if success { ToolState::Success } else { ToolState::Failed },
|
||||
}
|
||||
}
|
||||
|
||||
// Map `browser_*` tool names to friendly titles
|
||||
fn browser_tool_title(tool_name: &str) -> &'static str {
|
||||
match tool_name {
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::io::Write;
|
||||
|
||||
use crate::tui;
|
||||
use crossterm::Command;
|
||||
use crossterm::cursor::MoveTo;
|
||||
use crossterm::cursor::{MoveTo, MoveToNextLine};
|
||||
use crossterm::queue;
|
||||
use crossterm::style::Color as CColor;
|
||||
use crossterm::style::Colors;
|
||||
@@ -13,6 +13,7 @@ use crossterm::style::SetAttribute;
|
||||
use crossterm::style::SetBackgroundColor;
|
||||
use crossterm::style::SetColors;
|
||||
use crossterm::style::SetForegroundColor;
|
||||
use crossterm::terminal::{Clear, ClearType};
|
||||
use ratatui::layout::Size;
|
||||
use ratatui::style::Color;
|
||||
use ratatui::style::Modifier;
|
||||
@@ -63,14 +64,15 @@ pub fn insert_history_lines_to_writer<B, W>(
|
||||
queue!(writer, SetScrollRegion(top_1based..screen_size.height)).ok();
|
||||
queue!(writer, MoveTo(0, area.top())).ok();
|
||||
for _ in 0..scroll_amount {
|
||||
// Reverse Index (RI): ESC M
|
||||
queue!(writer, Print("\x1bM")).ok();
|
||||
// Reverse Index (RI)
|
||||
queue!(writer, ReverseIndex).ok();
|
||||
}
|
||||
queue!(writer, ResetScrollRegion).ok();
|
||||
|
||||
let cursor_top = area.top().saturating_sub(1);
|
||||
// Adjust our local notion of area to account for the pre-scroll,
|
||||
// but avoid touching ratatui::Terminal internals (set_viewport_area is private).
|
||||
area.y += scroll_amount;
|
||||
terminal.set_viewport_area(area);
|
||||
cursor_top
|
||||
} else {
|
||||
area.top().saturating_sub(1)
|
||||
@@ -108,10 +110,10 @@ pub fn insert_history_lines_to_writer<B, W>(
|
||||
queue!(writer, MoveTo(0, cursor_top)).ok();
|
||||
|
||||
for line in wrapped {
|
||||
queue!(writer, Print("\r\n")).ok();
|
||||
queue!(writer, Print("\x1b[K")).ok(); // Clear to end of line with current bg
|
||||
queue!(writer, MoveToNextLine(1)).ok();
|
||||
queue!(writer, Clear(ClearType::UntilNewLine)).ok(); // Clear to end of line with current bg
|
||||
write_spans(writer, line.iter()).ok();
|
||||
queue!(writer, Print("\x1b[K")).ok(); // Clear remainder of line after content
|
||||
queue!(writer, Clear(ClearType::UntilNewLine)).ok(); // Clear remainder of line after content
|
||||
}
|
||||
|
||||
queue!(writer, ResetScrollRegion).ok();
|
||||
@@ -124,6 +126,27 @@ pub fn insert_history_lines_to_writer<B, W>(
|
||||
writer.flush().ok();
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ReverseIndex;
|
||||
|
||||
impl Command for ReverseIndex {
|
||||
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||
// RI (Reverse Index): ESC M
|
||||
write!(f, "\x1bM")
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_winapi(&self) -> io::Result<()> {
|
||||
// Use ANSI path through ConPTY; WinAPI equivalent isn't exposed.
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn is_ansi_code_supported(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct SetScrollRegion(pub std::ops::Range<u16>);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user