From c358d3a10fea89671d9e21577e1d7b71072cf51a Mon Sep 17 00:00:00 2001 From: 0thernet <894119+0thernet@users.noreply.github.com> Date: Fri, 9 Oct 2026 12:31:25 -0400 Subject: [PATCH 1/2] Document native build timeout guidance --- crates/xcb-runtime/src/broker.rs | 4 ++-- crates/xcb-runtime/tests/broker.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/crates/xcb-runtime/src/broker.rs b/crates/xcb-runtime/src/broker.rs index 4212189c..a505243e 100644 --- a/crates/xcb-runtime/src/broker.rs +++ b/crates/xcb-runtime/src/broker.rs @@ -696,7 +696,7 @@ pub fn descriptors() -> Vec { ("xcb_tools_image", "Reopen a stored screenshot or image named in this session's recent history. Returns the image itself without taking another screenshot or interacting with the page.", json!({"id":{"type":"string","minLength":1,"maxLength":160}}), vec!["id"]), ("workspace_exec", "Run a bounded offline Linux command in a staged workspace, then publish successful joined changes with revision checks. Host credentials, source Git configuration/hooks/history, host dependencies and build outputs are excluded. Supported repositories provide filtered read-only Git HEAD/index for status and diffs; Git writes are unavailable. Requires the configured isolated command runner. argv executes directly; use sh -c explicitly for shell syntax.", json!({"argv":{"type":"array","minItems":1,"maxItems":64,"items":{"type":"string","maxLength":32768}},"cwd":{"type":"string","minLength":1,"maxLength":4096,"description":"Folder to run in, relative to the workspace root; use \".\" for the root"},"timeoutMs":{"type":"integer","minimum":1,"maximum":600000},"network":{"type":"string","enum":["none"]}}), vec!["argv","cwd","timeoutMs","network"]), ("workspace_host_exec", "Run a bounded command in the real host worktree with ordinary network and host GitHub credentials. Only an explicitly host-admitted managed Codex task can use this lane. Host commands can change the worktree, Git history and remote services directly; nonzero or interrupted outcomes retain uncertain effects. argv executes directly; use sh -c explicitly for shell syntax.", json!({"argv":{"type":"array","minItems":1,"maxItems":64,"items":{"type":"string","maxLength":32768}},"cwd":{"type":"string","minLength":1,"maxLength":4096},"timeoutMs":{"type":"integer","minimum":1,"maximum":600000},"network":{"type":"string","enum":["host"]}}), vec!["argv","cwd","timeoutMs","network"]), - ("workspace_native_exec", "Run argv directly in the real worktree through XCB's OS-confined native executor, shared by Claude and Codex. Requires a host-owned workspace/provider grant and a persistent native task requirement. Network is DNS and HTTPS, not offline replay. File writes are immediate and bounded to the workspace and explicitly granted Git metadata; credentials are unavailable unless the host grant explicitly includes GitHub. Never retry a failed or interrupted command without effect reconciliation.", json!({"argv":{"type":"array","minItems":1,"maxItems":64,"items":{"type":"string","maxLength":32768}},"cwd":{"type":"string","minLength":1,"maxLength":4096},"timeoutMs":{"type":"integer","minimum":1,"maximum":600000},"network":{"type":"string","enum":["https"]}}), vec!["argv","cwd","timeoutMs","network"]), + ("workspace_native_exec", "Run argv directly in the real worktree through XCB's OS-confined native executor, shared by Claude and Codex. Requires a host-owned workspace/provider grant and a persistent native task requirement. Network is DNS and HTTPS, not offline replay. Builds and test suites may take several minutes; set timeoutMs to as much as 600000ms. File writes are immediate and bounded to the workspace and explicitly granted Git metadata; credentials are unavailable unless the host grant explicitly includes GitHub. Never retry a failed or interrupted command without effect reconciliation.", json!({"argv":{"type":"array","minItems":1,"maxItems":64,"items":{"type":"string","maxLength":32768}},"cwd":{"type":"string","minLength":1,"maxLength":4096},"timeoutMs":{"type":"integer","minimum":1,"maximum":600000,"description":"Builds and test suites may take several minutes; set timeoutMs up to 600000ms."},"network":{"type":"string","enum":["https"]}}), vec!["argv","cwd","timeoutMs","network"]), ("xcb_swarm_status", "List active XCB-managed tasks in this worker's workspace so agents on different providers can discover one another without exposing unrelated workspaces.", json!({}), vec![]), ("xcb_context_query", "Read the exact instructions and declared input context saved for the current managed program child. Hidden inputs and other child reports are unavailable unless passed into this call. op is inspect, read, slice, search or history. inspect pages entry metadata; read returns one entry; slice uses UTF-8 byte boundaries; search finds literal text. history takes a history object (contract \"xcb.program-history.v1\", view inspect/overview/expand/read/search) over the retained program call records: every call keeps its original task and state, and report bodies appear only for calls declared as inputs to this cell. Historical records do not change permissions or prove current facts. The host selects the task and snapshot; other tasks and provider state are unavailable.", json!({"op":{"type":"string","enum":["inspect","read","slice","search","history"]},"offset":{"type":"integer","minimum":0,"maximum":5},"limit":{"type":"integer","minimum":1,"maximum":32},"index":{"type":"integer","minimum":0,"maximum":4},"startByte":{"type":"integer","minimum":0,"maximum":1048576},"endByte":{"type":"integer","minimum":0,"maximum":1048576},"query":{"type":"string","minLength":1,"maxLength":4096},"maxResults":{"type":"integer","minimum":1,"maximum":32},"maxScanBytes":{"type":"integer","minimum":1,"maximum":32768},"history":{"type":"object","properties":{"contract":{"type":"string","enum":["xcb.program-history.v1"]},"view":{"type":"string","enum":["inspect","overview","expand","read","search"]},"recentLeaves":{"type":"integer","minimum":0,"maximum":1024},"derivatives":{"type":"object"},"node":{"type":"string","maxLength":160},"sourceIndex":{"type":"integer","minimum":0,"maximum":1023},"query":{"type":"string","minLength":1,"maxLength":4096},"maxResults":{"type":"integer","minimum":1,"maximum":16},"maxScanBytes":{"type":"integer","minimum":1,"maximum":262144},"limits":{"type":"object"}},"required":["contract","view"],"additionalProperties":false}}), vec!["op"]), ("xcb_message_list", "Read bounded durable XCB messages addressed to the current managed task. Use after to poll for newer cross-provider messages.", json!({"after":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1,"maximum":64}}), vec![]), @@ -756,7 +756,7 @@ const COMPACT_DESCRIPTIONS: &[(&str, &str)] = &[ ), ( "workspace_native_exec", - "Run argv in the real worktree, cwd relative (use .), timeoutMs1..600000, network https. Requires the host's exact workspace/provider grant and native task requirement. OS-confined; credentials only when explicitly granted. Writes are immediate. Failed/interrupted effects require reconciliation, not retry.", + "Run argv in real worktree; cwd relative (use .), timeoutMs 1..600000, network https. Builds/tests may take several minutes; timeoutMs up to 600000ms. Requires exact host workspace/provider grant and native task requirement. OS-confined; credentials only when granted. Writes immediate; reconcile failures, never retry.", ), ( "xcb_swarm_status", diff --git a/crates/xcb-runtime/tests/broker.rs b/crates/xcb-runtime/tests/broker.rs index f675856f..6dc54441 100644 --- a/crates/xcb-runtime/tests/broker.rs +++ b/crates/xcb-runtime/tests/broker.rs @@ -853,6 +853,33 @@ fn workspace_read_rejects_oversized_files_with_a_guided_tool_error() { assert!(error.to_string().contains("exceeds the 128 KiB read limit")); } +#[test] +fn native_command_descriptor_documents_long_builds_and_binds_timeout() { + use xcb_runtime::broker::{compact_descriptors, descriptors}; + let descriptor = descriptors() + .into_iter() + .find(|tool| tool["name"] == "workspace_native_exec") + .expect("native workspace tool descriptor"); + let description = descriptor["description"].as_str().unwrap(); + assert!(description.contains("several minutes")); + assert!(description.contains("600000ms")); + assert_eq!( + descriptor["inputSchema"]["properties"]["timeoutMs"]["maximum"], + 600000 + ); + assert_eq!( + descriptor["inputSchema"]["properties"]["timeoutMs"]["description"], + "Builds and test suites may take several minutes; set timeoutMs up to 600000ms." + ); + let compact = compact_descriptors() + .into_iter() + .find(|tool| tool["name"] == "workspace_native_exec") + .expect("compact native workspace tool descriptor"); + let compact_description = compact["description"].as_str().unwrap(); + assert!(compact_description.contains("several minutes")); + assert!(compact_description.contains("600000ms")); +} + /// Devin shows `tools/list` to its model as indented JSON and moves any tool /// output over 10,000 characters into a file that only a denied native tool /// could read. The listing it receives stays well inside that limit while From f612ae215b092673879e95d94dd43d46d9e4451e Mon Sep 17 00:00:00 2001 From: 0thernet <894119+0thernet@users.noreply.github.com> Date: Fri, 9 Oct 2026 13:21:56 -0400 Subject: [PATCH 2/2] Release xcb 0.20.6: document native build timeouts --- CHANGELOG.md | 7 +++++++ Cargo.lock | 8 ++++---- Cargo.toml | 2 +- crates/xcb-cli/Cargo.toml | 4 ++-- crates/xcb-core/Cargo.toml | 2 +- crates/xcb-runtime/Cargo.toml | 4 ++-- package.json | 2 +- src/cli.ts | 2 +- 8 files changed, 19 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14d09309..58218d36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,13 @@ workflow copies that section onto the GitHub Release page and refuses to publish when it is missing, empty, or still says Unreleased. Write it in the version bump pull request by renaming `## Unreleased` to the version. +## 0.20.6 - 2026-10-09 + +Native build and test commands now document the time needed for cold builds. + +- `workspace_native_exec` tells workers that builds and test suites may take several minutes and accepts a `timeoutMs` up to `600000ms`, including in its compact descriptor. +- Regression coverage pins the full and compact tool descriptions and the timeout schema. + ## 0.20.5 - 2026-10-08 A scheduled program no longer waits forever on a child task you cancelled. diff --git a/Cargo.lock b/Cargo.lock index 9dedbbe8..ffc519fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3207,7 +3207,7 @@ checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "xcb-cli" -version = "0.20.5" +version = "0.20.6" dependencies = [ "clap", "clap_complete", @@ -3225,7 +3225,7 @@ dependencies = [ [[package]] name = "xcb-core" -version = "0.20.5" +version = "0.20.6" dependencies = [ "proptest", "serde", @@ -3236,7 +3236,7 @@ dependencies = [ [[package]] name = "xcb-platform" -version = "0.20.5" +version = "0.20.6" dependencies = [ "tempfile", "windows-sys 0.61.2", @@ -3244,7 +3244,7 @@ dependencies = [ [[package]] name = "xcb-runtime" -version = "0.20.5" +version = "0.20.6" dependencies = [ "aes-gcm", "aicharts-core", diff --git a/Cargo.toml b/Cargo.toml index d888ed91..012c0380 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["crates/xcb-platform", "crates/xcb-core", "crates/xcb-runtime", "crat resolver = "3" [workspace.package] -version = "0.20.5" +version = "0.20.6" edition = "2024" rust-version = "1.97.1" license = "MIT" diff --git a/crates/xcb-cli/Cargo.toml b/crates/xcb-cli/Cargo.toml index 4f13f4b5..aadb5e39 100644 --- a/crates/xcb-cli/Cargo.toml +++ b/crates/xcb-cli/Cargo.toml @@ -21,8 +21,8 @@ serde = "=1.0.229" serde_json = "=1.0.151" tokio = { version = "=1.47.1", features = ["rt-multi-thread", "macros", "signal", "sync", "time"] } unicode-width = "=0.2.2" -xcb-core = { version = "0.20.5", path = "../xcb-core" } -xcb-runtime = { version = "0.20.5", path = "../xcb-runtime" } +xcb-core = { version = "0.20.6", path = "../xcb-core" } +xcb-runtime = { version = "0.20.6", path = "../xcb-runtime" } zeroize = "=1.9.0" [target.'cfg(unix)'.dependencies] diff --git a/crates/xcb-core/Cargo.toml b/crates/xcb-core/Cargo.toml index f324ab15..dfc70ac1 100644 --- a/crates/xcb-core/Cargo.toml +++ b/crates/xcb-core/Cargo.toml @@ -18,4 +18,4 @@ thiserror = "=2.0.21" proptest = "=1.11.0" [target.'cfg(windows)'.dependencies] -xcb-platform = { version = "0.20.5", path = "../xcb-platform" } +xcb-platform = { version = "0.20.6", path = "../xcb-platform" } diff --git a/crates/xcb-runtime/Cargo.toml b/crates/xcb-runtime/Cargo.toml index c3c367a3..b4aee7b1 100644 --- a/crates/xcb-runtime/Cargo.toml +++ b/crates/xcb-runtime/Cargo.toml @@ -36,7 +36,7 @@ tokio = { version = "=1.47.1", features = ["rt-multi-thread", "macros", "process tokio-rustls = { version = "=0.26.6", default-features = false, features = ["ring", "tls12"] } uuid = { version = "=1.27.0", features = ["v4", "v7", "serde"] } webpki-roots = "=1.0.9" -xcb-core = { version = "0.20.5", path = "../xcb-core" } +xcb-core = { version = "0.20.6", path = "../xcb-core" } zeroize = "=1.9.0" [target.'cfg(unix)'.dependencies] @@ -46,4 +46,4 @@ local-custody = { git = "https://github.com/hraness/local-custody", rev = "4fd65 rustix = { version = "=1.1.5", features = ["fs", "process", "pty", "termios"] } [target.'cfg(windows)'.dependencies] -xcb-platform = { version = "0.20.5", path = "../xcb-platform" } +xcb-platform = { version = "0.20.6", path = "../xcb-platform" } diff --git a/package.json b/package.json index 1f90fdb2..2a0a6cf7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hraness/xcb", - "version": "0.20.5", + "version": "0.20.6", "description": "TypeScript SDK and compatibility CLI for Excalibur (xcb), which routes coding tasks across the Claude and Codex subscriptions you already pay for.", "type": "module", "license": "MIT", diff --git a/src/cli.ts b/src/cli.ts index 28b6eb78..4886af0b 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -3,7 +3,7 @@ import { fileURLToPath } from "node:url"; import { runCliUpdate } from "@hraness/cli-update"; import { compatibilityUpdateOptions } from "./cli/update.ts"; -const VERSION = "0.20.5"; +const VERSION = "0.20.6"; function reportStartupError(error: unknown): number { process.stderr.write(`xcb-compat: ${error instanceof Error ? error.message : "unexpected failure"}\n`);