mirror of
https://github.com/stablyai/orca.git
synced 2026-11-01 01:27:35 +00:00
* [comment audit] Align legacy failure-read counts with cached display * [comment audit] Condense shared provider lifecycle and browser recovery comments [skip ci] * [comment audit] Condense shared generation, path and preview comments [skip ci] * [comment audit] Condense host, file and Git contract rationale [skip ci] * [comment audit] Tighten Git lifecycle and provider contract comments [skip ci] * [comment audit] Clarify shared host authority and launch isolation [skip ci] * [comment audit] simplify local access mobile and native chat contracts [skip ci] * [comment audit] simplify native chat presentation and state contracts [skip ci] * [comment audit] simplify native runtime and provider contracts [skip ci] * [comment audit] simplify migration and orchestration contracts [skip ci] * [comment audit] simplify plugin trust and process capture rationale [skip ci] * [comment audit] simplify terminal delivery and remote compatibility rationale [skip ci] * [comment audit] clarify remote recovery and launch wire rationale [skip ci] * [comment audit] shorten shared RPC compatibility and runtime evidence comments [skip ci] * [comment audit] simplify secure storage shell startup and sidebar rationale [skip ci] * [comment audit] clarify sidebar, skill and SSH invariants [skip ci] * [comment audit] condense structured chat delivery and timing rationale [skip ci] * [comment audit] condense terminal replay and telemetry invariants [skip ci] * [comment audit] clarify launch permission and terminal delivery rationale [skip ci] * [comment audit] clarify workspace ownership and layout contracts [skip ci] * [comment audit] wait for fitted and painted SSH terminal links * [comment audit] clarify layout persistence and session ownership [skip ci] * [comment audit] clarify host routing and workspace lifecycle contracts [skip ci] * [comment audit] clarify startup persistence and app lifetime comments [skip ci] * [comment audit] clarify recovery and activity boundaries [skip ci] * [comment audit] condense activity and artifact invariants [skip ci] * [comment audit] condense automation authority contracts [skip ci] * [comment audit] simplify automation scheduling and history contracts [skip ci] * [comment audit] clarify browser chrome and annotation lifecycles [skip ci] * [comment audit] clarify browser routing and retained guest ownership [skip ci] * [comment audit] clarify browser recovery and document ownership comments [skip ci] * [comment audit] restore hosted runners required by native IME fixtures * [comment audit] shorten preview, palette and dashboard invariants [skip ci] * [comment audit] clarify terminal preview, dashboard and retention comments [skip ci] * [comment audit] clarify diff-note recovery and editor lifecycle comments [skip ci] * [comment audit] shorten rich-text and combined-diff ownership comments [skip ci] * [comment audit] shorten autosave, draft recovery and model ownership comments [skip ci] * [comment audit] shorten save-queue, notebook and Markdown constraints [skip ci] * [comment audit] shorten Monaco, PDF and rich Markdown safeguards [skip ci] * [comment audit] clarify rich Markdown source and selection safeguards [skip ci] * [comment audit] clarify editor loading and emulator stream lifetimes [skip ci] * [comment audit] trim emulator and feature tour narration [skip ci] * [comment audit] clarify floating workspace and GitHub cache ownership [skip ci] * [comment audit] trim provider controls and Linear filter explanations [skip ci] * [comment audit] clarify pairing and chat resume lifetimes [skip ci] * [comment audit] clarify chat delivery and transcript lifetimes [skip ci] * [comment audit] clarify session options and host-owned status [skip ci] * [comment audit] clarify draft durability and live-status precedence [skip ci] * [comment audit] Trim chat send and model ownership explanations [skip ci] * [comment audit] Shorten transcript ownership and send recovery comments [skip ci] * [comment audit] Simplify native chat composer and transcript hook comments [skip ci] * [comment audit] Shorten native chat scroll and structured session explanations [skip ci] * [comment audit] Trim workspace picker and onboarding commentary [skip ci] * [comment audit] Simplify pet rendering, review cache and quick open comments [skip ci] * [comment audit] Trim sidebar and session history explanations [skip ci] * [comment audit] Condense session resume and review checks comments [skip ci] * [comment audit] Shorten checks state and file explorer refresh comments [skip ci] * [comment audit] Trim plugin bridge and source-control action rationale [skip ci] * [comment audit] Trim source-control listing and review rationale [skip ci] * [comment audit] Shorten sidebar lifecycle and explorer safeguards [skip ci] * [comment audit] Condense Settings account and appearance rationale [skip ci] * [comment audit] Trim pairing and repository Settings explanations [skip ci] * [comment audit] Condense Settings search SSH and terminal safeguards [skip ci] * [comment audit] Shorten Settings voice and provider ownership comments [skip ci] * [comment audit] Condense Settings draft persistence and host-state rationale [skip ci] * [comment audit] Trim Settings hooks and sidebar setup rationale [skip ci] * [comment audit] Condense sidebar deletion and board-filter safeguards [skip ci] * [comment audit] Condense worktree cards, host ownership and Markdown contracts [skip ci] * [comment audit] Condense sidebar drag, folder and filtering contracts [skip ci] * [comment audit] Condense sidebar parity, sleep and host ownership contracts [skip ci] * [comment audit] Prune focus-read baseline after comment cleanup * [comment audit] Clarify sidebar visibility, board drops and agent evidence [skip ci] * [comment audit] Tighten sidebar listing, drag and reveal contracts [skip ci] * [comment audit] Clarify viewport geometry and skill update safeguards [skip ci] * [comment audit] Tighten skill inventory, usage and host status comments [skip ci] * [comment audit] Clarify usage ownership and resource kill safeguards [skip ci] * [comment audit] Tighten tab selection, rename and search contracts [skip ci] * [comment audit] Tighten tab-strip geometry and drag ownership comments [skip ci] * [comment audit] Tighten Tasks recovery, pagination and mutation comments [skip ci] * [comment audit] Tighten provider loading and terminal recovery comments [skip ci] * [comment audit] Tighten completion, cadence and PTY ownership comments [skip ci] * [comment audit] Clarify terminal restore and parked-pane boundaries [skip ci] * [comment audit] Tighten PTY startup and replay explanations [skip ci] * [comment audit] Clarify PTY identity and delivery ownership [skip ci] * [comment audit] Shorten remote reconnect and input replay rationale [skip ci] * [comment audit] Condense terminal parking clipboard and file link comments [skip ci] * [comment audit] Clarify IME ownership and trim trace history [skip ci] * [comment audit] Shorten pane recovery and parked watcher explanations [skip ci] * [comment audit] Condense snapshot replay and visibility recovery rationale [skip ci] * [comment audit] Shorten terminal parking and keyboard ownership rationale [skip ci] * [comment audit] Trim renderer lifecycle and menu rationale [skip ci] * [comment audit] Condense workspace cleanup ownership and settlement notes [skip ci] * [comment audit] Clarify renderer hook evidence and source ownership [skip ci] * [comment audit] Tighten IPC ownership and reconnect explanations [skip ci] * [comment audit] Trim renderer focus, paste and attention comments [skip ci] * [comment audit] Shorten scroll, locale and agent lifecycle comments [skip ci] * [comment audit] Trim agent launch, resume and ownership commentary [skip ci] * [comment audit] Shorten account, browser and editor comments [skip ci] * [comment audit] Clarify host-mirror waits, previews and input ownership [skip ci] * [comment audit] Condense launch recovery and editor tokenization comments [skip ci] * [comment audit] Condense workspace selection and terminal pane rationale [skip ci] * [comment audit] Condense terminal fitting and rendering recovery comments [skip ci] * [comment audit] Condense terminal input and host routing explanations [skip ci] * [comment audit] Condense ownership and sleeping-session recovery rationale [skip ci] * [comment audit] Condense structured launch and terminal link explanations [skip ci] * [comment audit] Condense terminal ownership and workspace file routing rationale [skip ci] * [comment audit] Condense session persistence and workspace activation rationale [skip ci] * [comment audit] Condense workspace routing and browser ownership rationale [skip ci] * [comment audit] Condense mirror recovery and layout authority rationale [skip ci] * [comment audit] Condense runtime transport and file safety rationale [skip ci] * [comment audit] Condense runtime graph and structured session rationale [skip ci] * [comment audit] Condense browser creation and remote tab recovery rationale [skip ci] * [comment audit] Condense snapshot authority and publisher recovery rationale [skip ci] * [comment audit] Condense frame, startup and provider cache rationale [skip ci] * [comment audit] Condense host twin and agent lifecycle rationale [skip ci] * [comment audit] Condense browser authority and editor cleanup rationale [skip ci] * [comment audit] Condense editor buffer identity and review cache rationale [skip ci] * [comment audit] Condense provider lifetime and repository ownership rationale [skip ci] * [comment audit] Condense reconnect, hydration and terminal retirement rationale [skip ci] * [comment audit] Condense recovery, reconciliation and persistence rationale [skip ci] * [comment audit] Condense cleanup ownership and listing admission rationale [skip ci] * [comment audit] Condense teardown ordering and terminal ownership rationale [skip ci] * [comment audit] Condense recovery ledger and web host-boundary rationale [skip ci] * [comment audit] Condense web reconnect and credential lifecycle rationale [skip ci] * [comment audit] Condense cloud rollout and assignment safety rationale [skip ci] * [comment audit] Condense relay session and database recovery rationale [skip ci] * [comment audit] Condense relay placement and protocol compatibility rationale [skip ci] * [comment audit] Condense build and packaging constraints [skip ci] * [comment audit] Condense CI gates and validation isolation rationale [skip ci] * [comment audit] Condense catalog identity and browser validation rationale [skip ci] * [comment audit] Condense mobile browser and frame-budget rationale [skip ci] * [comment audit] Shorten mobile route and browser test explanations [skip ci] * [comment audit] Condense editor and session seam test rationale [skip ci] * [comment audit] Trim session and terminal closure history [skip ci] * [comment audit] Shorten terminal browser and census explanations [skip ci] * [comment audit] Preserve root-only E2E diagnostic baseline * [comment audit] Condense mobile seam and HTML preview test rationale [skip ci] * [comment audit] Condense preview instrumentation and render harness rationale [skip ci] * [comment audit] Condense bundle contracts and native-build constraints [skip ci] * [comment audit] Shorten native packaging and CI routing rationale [skip ci] * [comment audit] Condense release tooling and benchmark constraints [skip ci] * [comment audit] Condense packaging and platform gate rationale [skip ci] * [comment audit] Shorten mobile route and history rationale [skip ci] * [comment audit] Condense mobile browser and component rationale [skip ci] * [comment audit] Shorten drawer and workspace-form rationale [skip ci] * [comment audit] Trim mobile review and editor-document explanations [skip ci] * [comment audit] Condense editor lifecycle and Markdown explanations [skip ci] * [comment audit] Trim mobile file, diagnostics and dictation commentary [skip ci] * [comment audit] Simplify mobile host-list and workspace-view explanations [skip ci] * [comment audit] Clarify mobile shell lifetime and bridge delivery constraints [skip ci] * [comment audit] Condense bridge stream, native request and audio rationale [skip ci] * [comment audit] Reduce bridge schema and page-client commentary [skip ci] * [comment audit] Tighten mobile page bridge contracts [skip ci] * [comment audit] Clarify mobile cache and session constraints [skip ci] * [comment audit] Condense mobile route and lifecycle rationale [skip ci] * [comment audit] Tighten mobile shell hook timing rationale [skip ci] * [comment audit] Clarify route handoff and notification compatibility [skip ci] * [comment audit] Clarify push registration and dictation cleanup constraints [skip ci] * [comment audit] Condense keyboard geometry and native media ownership rationale [skip ci] * [comment audit] Tighten mobile chat scroll and composer concurrency rationale [skip ci] * [comment audit] Condense mobile reply compatibility and upload ownership rationale [skip ci] * [comment audit] Condense optimistic echo and scroll ownership rationale [skip ci] * [comment audit] Tighten stream replay and queued session ownership rationale [skip ci] * [comment audit] Condense mobile composer and reply-schema constraints [skip ci] * [comment audit] Clarify mobile transcript recovery and session ownership [skip ci] * [comment audit] Clarify mobile queue and source-control compatibility [skip ci] * [comment audit] Condense storage and task launch constraints [skip ci] * [comment audit] Clarify task schemas and terminal document ownership [skip ci] * [comment audit] Tighten terminal input and viewport rationale [skip ci] * [comment audit] Shorten terminal and RPC recorder contracts [skip ci] * [comment audit] Condense recorder engine and connection contracts [skip ci] * [comment audit] Shorten host credential and relay recovery comments [skip ci] * [comment audit] Tighten pairing recovery and bundle transport rationale [skip ci] * [comment audit] Clarify RPC delivery and workspace catalog boundaries [skip ci] * [comment audit] Condense catalog and relay entry contracts [skip ci] * [comment audit] Shorten shutdown and SSH relay delivery contracts [skip ci] * [comment audit] Condense WSL relay and E2E regression rationale [skip ci] * [comment audit] Shorten cross-version harness and renderer fixture explanations [skip ci] * [comment audit] Condense paired-host and E2E lifecycle rationale [skip ci] * [comment audit] Shorten layout oracle and regression explanations [skip ci] * [comment audit] Condense paired recovery and ownership regression contracts [skip ci] * [comment audit] Shorten restart, sidebar and SSH lifecycle contracts [skip ci] * [comment audit] Condense terminal rendering and IME regression rationale [skip ci] * [comment audit] Shorten terminal recovery and benchmark contracts [skip ci] * [comment audit] Condense tooling and Windows lifecycle proof rationale [skip ci] * [comment audit] Condense workflow routing and release rationale [skip ci] * [comment audit] Condense mobile security and installer contracts [skip ci] * [comment audit] Shorten native rationale and stylesheet workarounds [skip ci] * [comment audit] Shorten Windows visibility probe rationale [skip ci] * [comment audit] Condense embedded release and signing rationale [skip ci] * [comment audit] Retain current main test behavior in final reconciliation [skip ci] * [comment audit] Complete final comment review across current source inventory * [comment audit] Handle consolidated audit reports before final CI * [comment audit] Preserve credential storage census detail [skip ci] * [comment audit] Scale broad changed E2E selections with verified timing shards * [comment audit] Align E2E assertions with browser close and settled session metadata * [comment audit] Match existing E2Es to current resource and windowing contracts * [comment audit] Observe the shared server outage notice in reconnect coverage * [comment audit] Make existing renderer probes measure settled tab and PTY work * [comment audit] Align palette E2E selector with task search * [comment audit] Refresh remaining palette search selectors * [comment audit] Keep selector correction within selected audit specs * [comment audit] Await emoji fixture settings inside renderer evaluation * [comment audit] Cancel fixture fit retries between terminal tests --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
172 lines
6.7 KiB
Rust
172 lines
6.7 KiB
Rust
//! Orca's native Windows agent hook, registered as `orca-agent-hook.exe <agent>`: answers
|
|
//! `{}`, then posts the hook payload to Orca's loopback listener and waits for the reply,
|
|
//! so status events arrive in the order the agent emitted them.
|
|
//!
|
|
//! Why native: the `.cmd` form costs a cmd.exe start (plus the user's AutoRun) and
|
|
//! a curl.exe start on every event, and only an executable runs the same way under
|
|
//! Git Bash, PowerShell, and a direct CreateProcess (#20913). The `claude` contract
|
|
//! mirrors the managed Windows script in src/main/claude/hook-script.ts.
|
|
|
|
use std::env;
|
|
use std::fs::File;
|
|
use std::io::{self, Read, Write};
|
|
use std::net::{Ipv4Addr, SocketAddr, TcpStream};
|
|
use std::time::{Duration, Instant};
|
|
|
|
// Same caps as the curl form's `--connect-timeout 0.5 --max-time 1.5`.
|
|
const CONNECT_TIMEOUT: Duration = Duration::from_millis(500);
|
|
const TOTAL_TIMEOUT: Duration = Duration::from_millis(1500);
|
|
const ENDPOINT_FILE_BYTE_LIMIT: u64 = 64 * 1024;
|
|
|
|
/// What one agent's hooks report under, and which of its env vars veto reporting.
|
|
struct Agent {
|
|
source: &'static str,
|
|
/// Set means the event is not this pane's to report: exit without owning stdin.
|
|
exit_vars: &'static [&'static str],
|
|
}
|
|
|
|
fn agent(name: &str) -> Option<Agent> {
|
|
match name {
|
|
"claude" => Some(Agent {
|
|
source: "claude",
|
|
// Background sessions inherit pane env (#9236); Grok/Devin replay Claude hooks.
|
|
// Exit before draining: callers may hold stdin open indefinitely (#24907).
|
|
exit_vars: &["CLAUDE_JOB_DIR", "GROK_HOOK_EVENT", "DEVIN_PROJECT_DIR"],
|
|
}),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let mut stdout = io::stdout();
|
|
// Why first: Claude-compatible permission hooks fail closed on empty stdout (#14818).
|
|
let _ = stdout.write_all(b"{}\r\n");
|
|
let _ = stdout.flush();
|
|
// Why no stdin for an unknown agent: a newer Orca may register one this copy predates.
|
|
if let Some(agent) = env::args_os().nth(1).and_then(|arg| agent(arg.to_str()?)) {
|
|
run(&agent);
|
|
}
|
|
// Why always 0: a hook failure must never block or fail the agent's tool call.
|
|
std::process::exit(0);
|
|
}
|
|
|
|
fn run(agent: &Agent) {
|
|
// Why: refresh the listener coordinates for terminals that survived an Orca restart.
|
|
let endpoint = read_endpoint_file();
|
|
let coordinate = |key: &str| endpoint_value(&endpoint, key).unwrap_or_else(|| var(key));
|
|
let port = coordinate("ORCA_AGENT_HOOK_PORT");
|
|
let token = coordinate("ORCA_AGENT_HOOK_TOKEN");
|
|
// Why (#11549): without Orca's env the hook ran outside an Orca pane, where the caller
|
|
// may abandon stdin; exit before reading it.
|
|
if port.is_empty() || token.is_empty() || var("ORCA_PANE_KEY").is_empty() {
|
|
return;
|
|
}
|
|
let is_set = |name: &&str| !var(name).is_empty();
|
|
if agent.exit_vars.iter().any(is_set) {
|
|
return;
|
|
}
|
|
let mut payload = Vec::new();
|
|
let _ = io::stdin().lock().read_to_end(&mut payload);
|
|
let form = [
|
|
("paneKey", var("ORCA_PANE_KEY")),
|
|
("tabId", var("ORCA_TAB_ID")),
|
|
("launchToken", var("ORCA_AGENT_LAUNCH_TOKEN")),
|
|
("worktreeId", var("ORCA_WORKTREE_ID")),
|
|
("env", coordinate("ORCA_AGENT_HOOK_ENV")),
|
|
("version", coordinate("ORCA_AGENT_HOOK_VERSION")),
|
|
];
|
|
post(agent.source, &port, &token, &form, &payload);
|
|
}
|
|
|
|
fn var(name: &str) -> String {
|
|
env::var_os(name)
|
|
.map(|value| value.to_string_lossy().into_owned())
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
/// The file src/shared/agent-hook-listener/endpoint-publication.ts writes, or "" if unreadable.
|
|
fn read_endpoint_file() -> String {
|
|
let mut text = String::new();
|
|
let read = File::open(var("ORCA_AGENT_HOOK_ENDPOINT")).and_then(|file| {
|
|
file.take(ENDPOINT_FILE_BYTE_LIMIT)
|
|
.read_to_string(&mut text)
|
|
});
|
|
if read.is_err() {
|
|
text.clear();
|
|
}
|
|
text
|
|
}
|
|
|
|
/// The last `set KEY=VALUE` for `key`, as `call` would leave it; `lines` strips the CRLF.
|
|
fn endpoint_value(text: &str, key: &str) -> Option<String> {
|
|
text.lines().rev().find_map(|line| {
|
|
let assignment = line
|
|
.get(..4)
|
|
.filter(|prefix| prefix.eq_ignore_ascii_case("set "))
|
|
.and(line.get(4..))?;
|
|
let (name, value) = assignment.split_once('=')?;
|
|
(name == key).then(|| value.to_string())
|
|
})
|
|
}
|
|
|
|
fn post(source: &str, port: &str, token: &str, form: &[(&str, String)], payload: &[u8]) {
|
|
let Ok(port) = port.parse::<u16>() else {
|
|
return;
|
|
};
|
|
// A header value cannot carry control characters; such a token never authenticates anyway.
|
|
if port == 0 || token.bytes().any(|byte| byte < 0x20 || byte == 0x7f) {
|
|
return;
|
|
}
|
|
let mut body = Vec::with_capacity(payload.len() * 3 / 2 + 512);
|
|
for (name, value) in form {
|
|
append_form_field(&mut body, name, value.as_bytes());
|
|
body.push(b'&');
|
|
}
|
|
append_form_field(&mut body, "payload", payload);
|
|
let mut request = format!(
|
|
"POST /hook/{source} HTTP/1.1\r\nHost: 127.0.0.1:{port}\r\n\
|
|
Content-Type: application/x-www-form-urlencoded\r\n\
|
|
X-Orca-Agent-Hook-Token: {token}\r\nContent-Length: {}\r\nConnection: close\r\n\r\n",
|
|
body.len()
|
|
)
|
|
.into_bytes();
|
|
request.extend_from_slice(&body);
|
|
|
|
let deadline = Instant::now() + TOTAL_TIMEOUT;
|
|
let address = SocketAddr::from((Ipv4Addr::LOCALHOST, port));
|
|
let Ok(mut stream) = TcpStream::connect_timeout(&address, CONNECT_TIMEOUT) else {
|
|
return;
|
|
};
|
|
// Why wait for the reply: the listener applies the event before answering, and an exit
|
|
// before that would let the agent's next event overtake this one.
|
|
if arm(&stream, deadline) && stream.write_all(&request).is_ok() && arm(&stream, deadline) {
|
|
let _ = io::copy(&mut stream, &mut io::sink());
|
|
}
|
|
}
|
|
|
|
/// Bounds the next socket calls by what is left of the deadline; false once it has passed.
|
|
fn arm(stream: &TcpStream, deadline: Instant) -> bool {
|
|
let remaining = deadline.saturating_duration_since(Instant::now());
|
|
!remaining.is_zero()
|
|
&& stream.set_read_timeout(Some(remaining)).is_ok()
|
|
&& stream.set_write_timeout(Some(remaining)).is_ok()
|
|
}
|
|
|
|
/// `name=value` with the value percent-encoded exactly as curl's `--data-urlencode` does.
|
|
fn append_form_field(body: &mut Vec<u8>, name: &str, value: &[u8]) {
|
|
const HEX: &[u8; 16] = b"0123456789ABCDEF";
|
|
body.extend_from_slice(name.as_bytes());
|
|
body.push(b'=');
|
|
for &byte in value {
|
|
if byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'.' | b'_' | b'~') {
|
|
body.push(byte);
|
|
} else {
|
|
body.extend_from_slice(&[
|
|
b'%',
|
|
HEX[usize::from(byte >> 4)],
|
|
HEX[usize::from(byte & 15)],
|
|
]);
|
|
}
|
|
}
|
|
}
|