Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
26cb182
docs(release): draft v1.91.2 notes
Broccolito Sep 23, 2026
7ff03c0
fix(copilot): use Copilot wording in prompts and slash references
Broccolito Sep 23, 2026
78c0a49
fix(copilot): hide Windows PowerShell children and rename helper prompts
Broccolito Sep 23, 2026
dc8ba60
fix(copilot): reserve every Copilot slash spelling
Broccolito Sep 23, 2026
d4a99ee
chore(release): bump version to 1.91.2
Broccolito Sep 23, 2026
fb9221e
fix(copilot): polish native helper prompts
Broccolito Sep 23, 2026
90548af
test(copilot): reject compact retired names in helper prompts
Broccolito Sep 23, 2026
53e8c34
test(copilot): reserve built-in slash reference over custom alias
Broccolito Sep 23, 2026
4e54073
test(windows): report console probe traceback on failure
Broccolito Sep 23, 2026
5670530
test: update copilot prompt snapshots
Broccolito Sep 24, 2026
065f09a
test(windows): measure PowerShell child from inside console probe
Broccolito Sep 24, 2026
78757e8
test(windows): record pre-fix result without requiring reproduction
Broccolito Sep 24, 2026
176a690
ci(windows): gate release packages on Copilot console probe
Broccolito Sep 24, 2026
43309b7
fix(copilot): preserve exact custom extension references
Broccolito Sep 24, 2026
5dd25b8
fix(copilot): validate runtime against tracked pin
Broccolito Sep 24, 2026
87a0d54
fix(copilot): remove legacy wording from runtime notices
Broccolito Sep 24, 2026
9ff72d0
test(windows): check packaged Copilot process console path
Broccolito Sep 24, 2026
4366ea1
test(windows): fail fast when packaged MCP exits
Broccolito Sep 24, 2026
cfbe180
fix(copilot): name helper in accessibility guidance
Broccolito Sep 24, 2026
a22616c
test: assert Windows PowerShell startup hide request
Broccolito Sep 24, 2026
9df6b5a
fix(windows): constrain PowerShell modules for Copilot helper
Broccolito Sep 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/computer-use-native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ jobs:
if: runner.os == 'Windows'
working-directory: target/computer-use/source.noindex/apps/OpenComputerUseWindows
run: go test -p 2 ./...
- name: Measure the helper's PowerShell console with a visible control
if: runner.os == 'Windows'
run: python scripts/test-computer-use-windows-console.py target/computer-use/source.noindex target/computer-use/win32-x64/ocu.exe --report target/computer-use/windows-console.json
- name: Test Linux native runtime regressions
if: runner.os == 'Linux'
working-directory: target/computer-use/source.noindex/apps/OpenComputerUseLinux
Expand Down Expand Up @@ -87,7 +90,9 @@ jobs:
if: runner.os == 'Windows' && always()
with:
name: computer-use-windows-fixture-evidence
path: target/computer-use/windows-fixture*
path: |
target/computer-use/windows-fixture*
target/computer-use/windows-console.json
if-no-files-found: warn
- uses: actions/upload-artifact@v4
if: always()
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/release-artifact-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.26.8'
cache: false
- name: Download Windows artifact from the release
shell: pwsh
env:
Expand Down Expand Up @@ -83,6 +87,8 @@ jobs:
if ($LASTEXITCODE -ne 0) { throw "Packaged native helper protocol check failed" }
python scripts/test-computer-use-windows-fixture.py $helper --report artifact/windows-fixture.json
if ($LASTEXITCODE -ne 0) { throw "Packaged native helper fixture check failed" }
python scripts/test-computer-use-packaged-windows-console.py --cli $cli --report artifact/windows-packaged-console.json
if ($LASTEXITCODE -ne 0) { throw "Packaged Rust-to-Go console check failed" }
$cliVersion = & $cli --version
if ($LASTEXITCODE -ne 0 -or $cliVersion -notmatch [regex]::Escape($env:VERSION)) {
throw "Packaged CLI did not report $env:VERSION"
Expand Down Expand Up @@ -113,6 +119,13 @@ jobs:
Stop-Process -Id $process.Id -Force
Write-Host "Windows packaged runtime smoke passed for v$env:VERSION"

- uses: actions/upload-artifact@v4
if: always()
with:
name: release-windows-copilot-console
path: artifact/windows-packaged-console.json
if-no-files-found: warn

# ⚠ Proven able to fail, and repeatable: dispatch this workflow at a
# version whose daemon HAS the defect and the step below must fail with
# "PORT STILL HELD". Measured on v1.91.0 (2026-09-22, run 35763477213):
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/windows-gui-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,15 @@ jobs:
- name: Build the Biorouter Copilot helper payload
run: python scripts/computer-use-runtime.py build win32-x64

- name: Measure the release helper's PowerShell console
run: python scripts/test-computer-use-windows-console.py target/computer-use/source.noindex target/computer-use/win32-x64/ocu.exe --report target/computer-use/windows-console.json
- uses: actions/upload-artifact@v4
if: always()
with:
name: windows-package-console-evidence-${{ inputs.version }}
path: target/computer-use/windows-console.json
if-no-files-found: warn

# ⚠ `src/bin` is not tracked in git, so a fresh checkout has none.
# `prepare-platform-binaries.js` VALIDATES this directory and never copies
# from `target/`. Omitting this stage is how 1.91.0 produced an installer
Expand Down
18 changes: 9 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ resolver = "2"

[workspace.package]
edition = "2021"
version = "1.91.1"
version = "1.91.2"
authors = ["Wanjun Gu <wanjun.gu@ucsf.edu>"]
license = "Apache-2.0"
repository = "https://github.com/BaranziniLab/biorouter"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<p>
<a href="https://opensource.org/licenses/Apache-2.0"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg" alt="Apache 2.0 License"></a>
<img src="https://img.shields.io/badge/version-1.91.1-tan.svg" alt="Version 1.91.1">
<img src="https://img.shields.io/badge/version-1.91.2-tan.svg" alt="Version 1.91.2">
</p>

<a href="https://biorouter.ucsf.edu/download">Download</a> ·
Expand Down
9 changes: 7 additions & 2 deletions biorouter-self-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ instructions: |
- Test extension interactions
- Verify isolation between extensions
- In a disposable chat, browse `/` and `/ext:` and confirm current capability labels including Biorouter Copilot. Select a session-only extension and verify its exact reference identity.
- Submit `/extend computer controller` and verify actionable `/ext:` guidance without model execution or a permission grant.
- Submit `/extend Biorouter Copilot` and verify guidance names `/ext:BiorouterCopilot` without model execution or a permission grant.
- Verify `/effort` and a harmless configured workflow in the desktop, TUI, and classic CLI. A missing workflow must report its problem instead of falling through to the model.
- In a new desktop chat, verify `/diverge` is not suggested; typing it must preserve the draft and explain that an existing conversation is required.

Expand Down Expand Up @@ -482,7 +482,12 @@ prompt: |
Private and public chats must retain separate snapshots, trees, elements, results and
grants. Verify a private-to-public handoff pauses before capture; do not transfer real
private observations into the test report or a public model.
6. Repeat through native direct calls, code execution and a coding-agent provider where
6. On Windows, verify a packaged Copilot fixture call such as list_apps or get_app_state
does not show a console window for the Go helper's powershell.exe child. Pair the
measurement with a visible-console control and preserve the child-to-helper PID
relationship. A Node or Electron spawn probe does not exercise this path. If the
observer or packaged Windows runtime is unavailable, mark this NOT OBSERVABLE.
7. Repeat through native direct calls, code execution and a coding-agent provider where
available. Test Biorouter Copilot with Developer and Web & Documents disabled in an isolated
profile. Missing GUI/provider evidence is NOT OBSERVABLE, never PASS. Record target host,
helper version, exact fixture, tool results and remaining gaps in
Expand Down
18 changes: 16 additions & 2 deletions crates/biorouter-cli/src/session/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,12 @@ pub(super) fn extension_reference_search_terms(name: &str) -> String {
/// keep the compact marker when the real extractor proves it round-trips, and
/// emit the canonical `<biorouter-ref …>` tag when it does not.
pub(super) fn extension_marker(name: &str) -> String {
if name == "computercontroller" {
return reference_marker(
RefKind::Extension,
biorouter::agents::extension_manager::COPILOT_REFERENCE_ALIAS,
);
}
reference_marker(RefKind::Extension, name)
}

Expand Down Expand Up @@ -789,15 +795,23 @@ mod tests {
);
}
#[test]
fn completions_use_current_labels_and_preserve_canonical_markers() {
fn completions_use_current_labels_and_resolvable_markers() {
let pairs = reference_pairs_from_names(
"/copilot",
Vec::<String>::new(),
vec!["computercontroller".to_string()],
);
assert_eq!(pairs.len(), 1);
assert_eq!(pairs[0].display, "/ext:Biorouter Copilot");
assert_eq!(pairs[0].replacement, "/ext:computercontroller ");
assert_eq!(pairs[0].replacement, "/ext:BiorouterCopilot ");
let reference = extracted_refs(RefKind::Extension, &pairs[0].replacement);
assert_eq!(reference, ["BiorouterCopilot"]);
assert_eq!(
biorouter::agents::extension_manager::resolve_bundled_extension(&reference[0])
.unwrap()
.key(),
"computercontroller"
);
assert!(SLASH_COMMANDS.contains(&"/effort"));
let aliases = reference_pairs_from_names(
"/ext:autovisualizer",
Expand Down
6 changes: 3 additions & 3 deletions crates/biorouter-cli/src/session/tui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2415,16 +2415,16 @@ mod tests {
for command in biorouter::agents::execute_commands::list_commands() {
assert!(backend_slash_command(&format!("/{} value", command.name)));
}
assert!(backend_slash_command("/extend computer controller"));
assert!(backend_slash_command("/extend Biorouter Copilot"));
assert!(backend_slash_command("/knowledge"));
assert!(!backend_slash_command("/not-a-command"));
}

#[test]
fn computer_use_popup_shows_current_label_with_stable_wire_identity() {
fn copilot_popup_shows_current_label_with_stable_wire_identity() {
let item = extension_completion_item("computercontroller", "Use this extension", true);
assert_eq!(item.label, "Biorouter Copilot");
assert_eq!(item.insert, "/ext:computercontroller ");
assert_eq!(item.insert, "/ext:BiorouterCopilot ");
assert!(item.filter.contains("biorouter copilot"));
let american = extension_completion_item("autovisualiser", "Use this extension", true);
assert!(american.filter.contains("autovisualizer"));
Expand Down
2 changes: 1 addition & 1 deletion crates/biorouter-mcp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,4 @@ ctor = "0.2"
utoipa = ["dep:utoipa"]

[target."cfg(windows)".dependencies]
windows-sys = { version = "0.61", features = ["Win32_Foundation", "Win32_Security", "Win32_System_Diagnostics_ToolHelp", "Win32_System_JobObjects", "Win32_System_Threading"] }
windows-sys = { version = "0.61", features = ["Win32_Foundation", "Win32_Security", "Win32_System_Diagnostics_ToolHelp", "Win32_System_JobObjects", "Win32_System_SystemInformation", "Win32_System_Threading", "Win32_UI_Shell"] }
65 changes: 60 additions & 5 deletions crates/biorouter-mcp/src/computer_use/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,31 @@ use anyhow::{bail, Context, Result};
use serde::Deserialize;
use sha2::{Digest, Sha256};
use std::path::{Component, Path, PathBuf};
use std::sync::LazyLock;

pub const UPSTREAM_VERSION: &str = "0.3.5";
pub const UPSTREAM_COMMIT: &str = "547b4ffb8ed731a8f16486e6d8a3b215484267d3";

#[derive(Deserialize)]
struct RuntimePin {
schema_version: u32,
upstream_version: String,
upstream_commit: String,
patch_revision: String,
}

static RUNTIME_PIN: LazyLock<RuntimePin> = LazyLock::new(|| {
serde_json::from_str(include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../vendor/computer-use/pin.json"
)))
.expect("bundled Biorouter Copilot pin must be valid")
});

pub fn patch_revision() -> &'static str {
&RUNTIME_PIN.patch_revision
}

#[derive(Debug, Deserialize)]
pub struct Manifest {
pub schema_version: u32,
Expand Down Expand Up @@ -69,10 +90,10 @@ fn inspect(root: &Path, development_override: bool, verify_hashes: bool) -> Resu
.context("computer_use_missing_runtime: manifest.json is unavailable")?;
let manifest: Manifest = serde_json::from_slice(&bytes)
.context("computer_use_incompatible_runtime: invalid manifest")?;
if manifest.schema_version != 1
|| manifest.upstream_version != UPSTREAM_VERSION
|| manifest.upstream_commit != UPSTREAM_COMMIT
|| manifest.patch_revision != "biorouter-1"
if manifest.schema_version != RUNTIME_PIN.schema_version
|| manifest.upstream_version != RUNTIME_PIN.upstream_version
|| manifest.upstream_commit != RUNTIME_PIN.upstream_commit
|| manifest.patch_revision != RUNTIME_PIN.patch_revision
|| manifest.target != target()
{
bail!("computer_use_incompatible_runtime: runtime pin, patch or platform does not match BioRouter");
Expand Down Expand Up @@ -178,6 +199,40 @@ fn install_origin(bin: &Path) -> Option<PathBuf> {
.then(|| dunce::simplified(path).to_path_buf())
}

#[cfg(test)]
mod pin_tests {
use super::*;

#[test]
fn current_bundled_pin_is_accepted_and_other_patch_revisions_are_refused() {
assert_eq!(RUNTIME_PIN.upstream_version, UPSTREAM_VERSION);
assert_eq!(RUNTIME_PIN.upstream_commit, UPSTREAM_COMMIT);

let dir = tempfile::tempdir().unwrap();
let executable = dir.path().join("ocu");
std::fs::write(&executable, b"fixture helper").unwrap();
let digest = format!("{:x}", Sha256::digest(std::fs::read(&executable).unwrap()));
let mut manifest = serde_json::json!({
"schema_version": RUNTIME_PIN.schema_version,
"upstream_version": RUNTIME_PIN.upstream_version,
"upstream_commit": RUNTIME_PIN.upstream_commit,
"patch_revision": patch_revision(),
"target": target(),
"executable": "ocu",
"files": [{ "path": "ocu", "sha256": digest }],
});
std::fs::write(dir.path().join("manifest.json"), manifest.to_string()).unwrap();
inspect(dir.path(), false, true).expect("the bundled pin must be accepted");

manifest["patch_revision"] = serde_json::json!("outdated-patch");
std::fs::write(dir.path().join("manifest.json"), manifest.to_string()).unwrap();
assert!(inspect(dir.path(), false, true)
.unwrap_err()
.to_string()
.contains("computer_use_incompatible_runtime"));
}
}

#[cfg(all(test, windows))]
mod windows_path_spelling_tests {
use super::*;
Expand All @@ -193,7 +248,7 @@ mod windows_path_spelling_tests {
"schema_version": 1,
"upstream_version": UPSTREAM_VERSION,
"upstream_commit": UPSTREAM_COMMIT,
"patch_revision": "biorouter-1",
"patch_revision": patch_revision(),
"target": target(),
"executable": "ocu.exe",
"files": [{ "path": "ocu.exe", "sha256": digest }],
Expand Down
Loading
Loading