mirror of
https://github.com/openai/codex.git
synced 2026-04-24 14:45:27 +00:00
numeric prefix
This commit is contained in:
238
codex-rs/Cargo.lock
generated
238
codex-rs/Cargo.lock
generated
@@ -235,6 +235,17 @@ version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.19",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
@@ -387,6 +398,23 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "3.2.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"bitflags 1.3.2",
|
||||
"clap_derive 3.2.25",
|
||||
"clap_lex 0.2.4",
|
||||
"indexmap 1.9.3",
|
||||
"once_cell",
|
||||
"strsim 0.10.0",
|
||||
"termcolor",
|
||||
"textwrap 0.16.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.37"
|
||||
@@ -394,7 +422,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
"clap_derive 4.5.32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -405,23 +433,45 @@ checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"clap_lex 0.7.4",
|
||||
"strsim 0.11.1",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "3.2.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.4"
|
||||
@@ -472,7 +522,7 @@ name = "codex-cli"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"clap 4.5.37",
|
||||
"codex-core",
|
||||
"codex-exec",
|
||||
"codex-interactive",
|
||||
@@ -493,7 +543,7 @@ dependencies = [
|
||||
"async-channel",
|
||||
"base64 0.21.7",
|
||||
"bytes",
|
||||
"clap",
|
||||
"clap 4.5.37",
|
||||
"codex-apply-patch",
|
||||
"dirs 6.0.0",
|
||||
"env-flags",
|
||||
@@ -506,7 +556,7 @@ dependencies = [
|
||||
"openssl-sys",
|
||||
"patch",
|
||||
"predicates",
|
||||
"rand",
|
||||
"rand 0.9.1",
|
||||
"reqwest",
|
||||
"seccompiler",
|
||||
"serde",
|
||||
@@ -527,7 +577,7 @@ name = "codex-exec"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"clap 4.5.37",
|
||||
"codex-core",
|
||||
"tokio",
|
||||
"tracing",
|
||||
@@ -540,7 +590,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"allocative",
|
||||
"anyhow",
|
||||
"clap",
|
||||
"clap 4.5.37",
|
||||
"derive_more",
|
||||
"env_logger",
|
||||
"log",
|
||||
@@ -559,7 +609,7 @@ name = "codex-interactive"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"clap 4.5.37",
|
||||
"codex-core",
|
||||
"tokio",
|
||||
]
|
||||
@@ -569,10 +619,10 @@ name = "codex-repl"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"clap 4.5.37",
|
||||
"codex-core",
|
||||
"owo-colors 4.2.0",
|
||||
"rand",
|
||||
"rand 0.9.1",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
@@ -584,16 +634,18 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"clap",
|
||||
"clap 4.5.37",
|
||||
"codex-core",
|
||||
"codex-exec",
|
||||
"comfy-table",
|
||||
"dirs 5.0.1",
|
||||
"libc",
|
||||
"names",
|
||||
"nix 0.27.1",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"sysinfo",
|
||||
"tabwriter",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
@@ -605,7 +657,7 @@ name = "codex-tui"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"clap 4.5.37",
|
||||
"codex-ansi-escape",
|
||||
"codex-core",
|
||||
"color-eyre",
|
||||
@@ -653,17 +705,6 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "comfy-table"
|
||||
version = "7.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a65ebfec4fb190b6f90e944a817d60499ee0744e582530e2c9900a22e591d9a"
|
||||
dependencies = [
|
||||
"crossterm",
|
||||
"unicode-segmentation",
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "compact_str"
|
||||
version = "0.8.1"
|
||||
@@ -1418,12 +1459,27 @@ dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
@@ -2102,6 +2158,16 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "names"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7bddcd3bf5144b6392de80e04c347cd7fab2508f6df16a85fc496ecd5cec39bc"
|
||||
dependencies = [
|
||||
"clap 3.2.25",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.14"
|
||||
@@ -2322,6 +2388,12 @@ version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "os_str_bytes"
|
||||
version = "6.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
@@ -2523,6 +2595,30 @@ dependencies = [
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.95"
|
||||
@@ -2557,14 +2653,35 @@ dependencies = [
|
||||
"nibble_vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
dependencies = [
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2574,7 +2691,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3071,6 +3197,19 @@ dependencies = [
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.34+deprecated"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
|
||||
dependencies = [
|
||||
"indexmap 2.9.0",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
"unsafe-libyaml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
@@ -3201,7 +3340,7 @@ dependencies = [
|
||||
"starlark_syntax",
|
||||
"static_assertions",
|
||||
"strsim 0.10.0",
|
||||
"textwrap",
|
||||
"textwrap 0.11.0",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
@@ -3306,7 +3445,7 @@ version = "0.26.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
@@ -3397,6 +3536,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tabwriter"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fce91f2f0ec87dff7e6bcbbeb267439aa1188703003c6055193c821487400432"
|
||||
dependencies = [
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.19.1"
|
||||
@@ -3421,6 +3569,15 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.4.2"
|
||||
@@ -3446,6 +3603,12 @@ dependencies = [
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
@@ -3856,6 +4019,12 @@ version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-libyaml"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
@@ -4062,6 +4231,15 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
||||
@@ -31,8 +31,10 @@ chrono = { version = "0.4", features = ["serde"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
dirs = "5"
|
||||
comfy-table = "7"
|
||||
sysinfo = "0.29"
|
||||
tabwriter = "1.3"
|
||||
serde_yaml = "0.9"
|
||||
names = "0.14"
|
||||
|
||||
# Re-use the codex-exec library for its CLI definition
|
||||
codex_exec = { package = "codex-exec", path = "../exec" }
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
//! Command-line interface definition and dispatch.
|
||||
//! CLI command definitions and implementation.
|
||||
|
||||
use crate::{spawn, store};
|
||||
use anyhow::Result;
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use clap::{Args, Parser, Subcommand, ValueEnum};
|
||||
use serde::Serialize;
|
||||
|
||||
/// Top-level CLI entry (re-exported by the crate).
|
||||
#[derive(Parser)]
|
||||
#[command(name = "codex-session", about = "Manage detached codex-exec sessions")]
|
||||
#[command(name = "codex-session", about = "Manage codex-exec background sessions")]
|
||||
pub struct Cli {
|
||||
#[command(subcommand)]
|
||||
cmd: Commands,
|
||||
@@ -24,21 +24,28 @@ impl Cli {
|
||||
}
|
||||
}
|
||||
|
||||
fn human_bytes(b: u64) -> String {
|
||||
const KB: f64 = 1024.0;
|
||||
const MB: f64 = KB * 1024.0;
|
||||
const GB: f64 = MB * 1024.0;
|
||||
let f = b as f64;
|
||||
if f >= GB {
|
||||
format!("{:.1}G", f / GB)
|
||||
} else if f >= MB {
|
||||
format!("{:.1}M", f / MB)
|
||||
} else if f >= KB {
|
||||
format!("{:.1}K", f / KB)
|
||||
} else {
|
||||
format!("{}B", b)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
/// Spawn a new, detached agent.
|
||||
Create(CreateCmd),
|
||||
|
||||
/// Kill a running session and delete on-disk artefacts.
|
||||
Delete(DeleteCmd),
|
||||
|
||||
/// Show (and optionally follow) stdout / stderr logs of a session.
|
||||
Logs(LogsCmd),
|
||||
|
||||
/// Execute a one-shot command inside an existing session.
|
||||
Exec(ExecCmd),
|
||||
|
||||
/// List all known session IDs.
|
||||
List(ListCmd),
|
||||
}
|
||||
|
||||
@@ -47,61 +54,87 @@ enum Commands {
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct CreateCmd {
|
||||
/// Session identifier. Generates a random UUIDv4 when omitted.
|
||||
/// Explicit session name. If omitted, a memorable random one is generated.
|
||||
#[arg(long)]
|
||||
id: Option<String>,
|
||||
|
||||
/// All flags following `create` are forwarded to `codex-exec`.
|
||||
/// Flags passed through to codex-exec.
|
||||
#[clap(flatten)]
|
||||
exec_cli: codex_exec::Cli,
|
||||
}
|
||||
|
||||
impl CreateCmd {
|
||||
pub async fn run(self) -> Result<()> {
|
||||
let id = self
|
||||
.id
|
||||
.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
|
||||
let id = match self.id {
|
||||
Some(id) => id,
|
||||
None => generate_session_id()?,
|
||||
};
|
||||
|
||||
let paths = store::paths_for(&id)?;
|
||||
store::prepare_dirs(&paths)?;
|
||||
|
||||
let exec_args = build_exec_args(&self.exec_cli);
|
||||
|
||||
// Spawn the background agent and immediately detach.
|
||||
// Preview first 40 printable chars of prompt for status listing
|
||||
let prompt_preview = self
|
||||
.exec_cli
|
||||
.prompt
|
||||
.as_ref()
|
||||
.map(|p| {
|
||||
let slice: String = p.chars().take(40).collect();
|
||||
if p.len() > 40 {
|
||||
format!("{}…", slice)
|
||||
} else {
|
||||
slice
|
||||
}
|
||||
});
|
||||
|
||||
// Spawn process
|
||||
let child = spawn::spawn_agent(&paths, &exec_args)?;
|
||||
|
||||
// Record metadata (with PID) *after* successful spawn.
|
||||
let meta = store::SessionMeta {
|
||||
id: id.clone(),
|
||||
pid: child.id().unwrap_or_default(),
|
||||
created_at: chrono::Utc::now(),
|
||||
prompt_preview,
|
||||
};
|
||||
store::write_meta(&paths, &meta)?;
|
||||
|
||||
println!("{id}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Re-serialize a `codex_exec::Cli` struct back into the exact CLI args.
|
||||
fn generate_session_id() -> Result<String> {
|
||||
let mut generator = names::Generator::with_naming(names::Name::Numbered);
|
||||
loop {
|
||||
let candidate = generator.next().unwrap();
|
||||
let paths = store::paths_for(&candidate)?;
|
||||
if !paths.dir.exists() {
|
||||
return Ok(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_exec_args(cli: &codex_exec::Cli) -> Vec<String> {
|
||||
let mut args = Vec::new();
|
||||
|
||||
for path in &cli.images {
|
||||
args.push("--image".to_string());
|
||||
args.push(path.to_string_lossy().into_owned());
|
||||
for img in &cli.images {
|
||||
args.push("--image".into());
|
||||
args.push(img.to_string_lossy().into_owned());
|
||||
}
|
||||
|
||||
if let Some(model) = &cli.model {
|
||||
args.push("--model".to_string());
|
||||
args.push("--model".into());
|
||||
args.push(model.clone());
|
||||
}
|
||||
|
||||
if cli.skip_git_repo_check {
|
||||
args.push("--skip-git-repo-check".to_string());
|
||||
args.push("--skip-git-repo-check".into());
|
||||
}
|
||||
|
||||
if cli.disable_response_storage {
|
||||
args.push("--disable-response-storage".to_string());
|
||||
args.push("--disable-response-storage".into());
|
||||
}
|
||||
|
||||
if let Some(prompt) = &cli.prompt {
|
||||
@@ -116,14 +149,14 @@ fn build_exec_args(cli: &codex_exec::Cli) -> Vec<String> {
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct DeleteCmd {
|
||||
/// Session ID to terminate and remove.
|
||||
id: String,
|
||||
}
|
||||
|
||||
impl DeleteCmd {
|
||||
pub async fn run(self) -> Result<()> {
|
||||
store::kill_session(&self.id).await?;
|
||||
store::purge(&self.id)?;
|
||||
let id = store::resolve_selector(&self.id)?;
|
||||
store::kill_session(&id).await?;
|
||||
store::purge(&id)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -133,101 +166,141 @@ impl DeleteCmd {
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct LogsCmd {
|
||||
/// Session ID whose logs should be printed.
|
||||
id: String,
|
||||
|
||||
/// Follow the file and stream appended lines (like `tail -f`).
|
||||
#[arg(short, long)]
|
||||
follow: bool,
|
||||
|
||||
/// Show stderr instead of stdout.
|
||||
#[arg(long)]
|
||||
stderr: bool,
|
||||
}
|
||||
|
||||
impl LogsCmd {
|
||||
pub async fn run(self) -> Result<()> {
|
||||
use tokio::io::AsyncBufReadExt;
|
||||
|
||||
let paths = store::paths_for(&self.id)?;
|
||||
let target = if self.stderr {
|
||||
&paths.stderr
|
||||
} else {
|
||||
&paths.stdout
|
||||
};
|
||||
let id = store::resolve_selector(&self.id)?;
|
||||
let paths = store::paths_for(&id)?;
|
||||
let target = if self.stderr { &paths.stderr } else { &paths.stdout };
|
||||
|
||||
let file = tokio::fs::File::open(target).await?;
|
||||
|
||||
if self.follow {
|
||||
let reader = tokio::io::BufReader::new(file);
|
||||
let mut lines = reader.lines();
|
||||
use tokio::io::AsyncBufReadExt;
|
||||
let mut lines = tokio::io::BufReader::new(file).lines();
|
||||
while let Some(line) = lines.next_line().await? {
|
||||
println!("{line}");
|
||||
}
|
||||
} else {
|
||||
// Simply dump the file contents to stdout.
|
||||
let mut stdout = tokio::io::stdout();
|
||||
tokio::io::copy(&mut tokio::io::BufReader::new(file), &mut stdout).await?;
|
||||
tokio::io::copy(&mut tokio::io::BufReader::new(file), &mut tokio::io::stdout()).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// exec (not implemented yet)
|
||||
// exec (TODO)
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct ExecCmd {
|
||||
id: String,
|
||||
|
||||
/// Remaining arguments form the command to execute.
|
||||
#[arg(trailing_var_arg = true)]
|
||||
cmd: Vec<String>,
|
||||
}
|
||||
|
||||
impl ExecCmd {
|
||||
pub async fn run(self) -> Result<()> {
|
||||
anyhow::bail!("exec inside an existing session is not yet implemented");
|
||||
let _id = store::resolve_selector(&self.id)?;
|
||||
anyhow::bail!("exec inside session not implemented yet");
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// list
|
||||
|
||||
#[derive(Copy, Clone, ValueEnum, Debug)]
|
||||
enum OutputFormat { Table, Json, Yaml }
|
||||
|
||||
#[derive(Args)]
|
||||
pub struct ListCmd;
|
||||
pub struct ListCmd {
|
||||
#[arg(short = 'o', long = "output", value_enum, default_value_t = OutputFormat::Table)]
|
||||
output: OutputFormat,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct StatusRow {
|
||||
idx: usize,
|
||||
id: String,
|
||||
pid: u32,
|
||||
status: String,
|
||||
created: String,
|
||||
prompt: String,
|
||||
out: String,
|
||||
err: String,
|
||||
}
|
||||
|
||||
impl ListCmd {
|
||||
pub async fn run(self) -> Result<()> {
|
||||
use comfy_table::{Cell, Table};
|
||||
use sysinfo::{SystemExt, Pid, PidExt};
|
||||
use sysinfo::{SystemExt, PidExt};
|
||||
|
||||
let sessions = store::list_sessions()?;
|
||||
let mut sys = sysinfo::System::new_all();
|
||||
let metas = store::list_sessions_sorted()?;
|
||||
|
||||
let mut sys = sysinfo::System::new();
|
||||
sys.refresh_processes();
|
||||
|
||||
let mut table = Table::new();
|
||||
table.set_header(["ID", "PID", "STATUS", "CREATED"]);
|
||||
let rows: Vec<StatusRow> = metas
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(idx, m)| {
|
||||
let status = if m.pid == 0 {
|
||||
"unknown"
|
||||
} else if sys.process(sysinfo::Pid::from_u32(m.pid)).is_some() {
|
||||
"running"
|
||||
} else {
|
||||
"exited"
|
||||
};
|
||||
|
||||
for meta in sessions {
|
||||
let status: &str = if meta.pid == 0 {
|
||||
"unknown"
|
||||
} else if sys.process(Pid::from_u32(meta.pid)).is_some() {
|
||||
"running"
|
||||
} else {
|
||||
"exited"
|
||||
};
|
||||
// file sizes
|
||||
let paths = store::paths_for(&m.id).ok();
|
||||
let (out, err) = if let Some(p) = &paths {
|
||||
let osz = std::fs::metadata(&p.stdout).map(|m| m.len()).unwrap_or(0);
|
||||
let esz = std::fs::metadata(&p.stderr).map(|m| m.len()).unwrap_or(0);
|
||||
(human_bytes(osz), human_bytes(esz))
|
||||
} else {
|
||||
("-".into(), "-".into())
|
||||
};
|
||||
|
||||
table.add_row([
|
||||
Cell::new(&meta.id),
|
||||
Cell::new(meta.pid),
|
||||
Cell::new(status),
|
||||
Cell::new(meta.created_at.to_rfc3339()),
|
||||
]);
|
||||
StatusRow {
|
||||
idx,
|
||||
id: m.id,
|
||||
pid: m.pid,
|
||||
status: status.into(),
|
||||
created: m.created_at.to_rfc3339(),
|
||||
prompt: m.prompt_preview.unwrap_or_default(),
|
||||
out,
|
||||
err,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
match self.output {
|
||||
OutputFormat::Table => print_table(&rows)?,
|
||||
OutputFormat::Json => println!("{}", serde_json::to_string_pretty(&rows)?),
|
||||
OutputFormat::Yaml => println!("{}", serde_yaml::to_string(&rows)?),
|
||||
}
|
||||
|
||||
println!("{table}");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn print_table(rows: &[StatusRow]) -> Result<()> {
|
||||
use std::io::Write;
|
||||
use tabwriter::TabWriter;
|
||||
|
||||
let mut tw = TabWriter::new(Vec::new()).padding(2);
|
||||
writeln!(tw, "#\tID\tPID\tSTATUS\tOUT\tERR\tCREATED\tPROMPT")?;
|
||||
for r in rows {
|
||||
writeln!(tw, "{}\t{}\t{}\t{}\t{}\t{}\t{}\t{}", r.idx, r.id, r.pid, r.status, r.out, r.err, r.created, r.prompt)?;
|
||||
}
|
||||
let out = String::from_utf8(tw.into_inner()?)?;
|
||||
print!("{out}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ pub struct SessionMeta {
|
||||
pub id: String,
|
||||
pub pid: u32,
|
||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub prompt_preview: Option<String>,
|
||||
}
|
||||
|
||||
/// Create the on-disk directory structure and write metadata + empty log files.
|
||||
@@ -74,6 +76,42 @@ pub fn list_sessions() -> Result<Vec<SessionMeta>> {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// List sessions sorted by newest first (created_at desc).
|
||||
pub fn list_sessions_sorted() -> Result<Vec<SessionMeta>> {
|
||||
let mut v = list_sessions()?;
|
||||
v.sort_by(|a, b| b.created_at.cmp(&a.created_at));
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
/// Resolve a user-supplied selector to a concrete session id.
|
||||
///
|
||||
/// Rules:
|
||||
/// 1. Pure integer ⇒ index into newest-first list (0 = most recent)
|
||||
/// 2. Otherwise try exact id match, then unique prefix match.
|
||||
pub fn resolve_selector(sel: &str) -> Result<String> {
|
||||
let list = list_sessions_sorted()?;
|
||||
|
||||
// numeric index
|
||||
if let Ok(idx) = sel.parse::<usize>() {
|
||||
return list.get(idx)
|
||||
.map(|m| m.id.clone())
|
||||
.context(format!("no session at index {idx}"));
|
||||
}
|
||||
|
||||
// exact match
|
||||
if let Some(m) = list.iter().find(|m| m.id == sel) {
|
||||
return Ok(m.id.clone());
|
||||
}
|
||||
|
||||
// unique prefix match
|
||||
let mut matches: Vec<&SessionMeta> = list.iter().filter(|m| m.id.starts_with(sel)).collect();
|
||||
match matches.len() {
|
||||
1 => Ok(matches.remove(0).id.clone()),
|
||||
0 => anyhow::bail!("no session matching '{sel}'"),
|
||||
_ => anyhow::bail!("selector '{sel}' is ambiguous ({} matches)", matches.len()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a polite termination request to the session’s process.
|
||||
///
|
||||
/// NOTE: Full PID accounting is a future improvement; for now the function
|
||||
|
||||
Reference in New Issue
Block a user