diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 71709534..1de10de5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -597,7 +597,7 @@ jobs: shell: pwsh run: | $ErrorActionPreference = "Stop" - $stage = Join-Path $env:GITHUB_WORKSPACE "target\desktop-ci-bundle" + $stage = Join-Path $env:RUNNER_TEMP "webcodex-desktop-ci-bundle" & .\scripts\prepare_desktop_bundle.ps1 ` -BinDir "target\dogfood" ` -Version "${{ steps.runtime.outputs.version }}" ` diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index ceafc93f..3e7ac68c 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -658,7 +658,7 @@ jobs: run: | $ErrorActionPreference = "Stop" $binDir = Join-Path "target" (Join-Path $env:RUST_TARGET "release") - $stage = Join-Path $env:GITHUB_WORKSPACE "target\desktop-release-bundle" + $stage = Join-Path $env:RUNNER_TEMP "webcodex-desktop-release-bundle" & .\scripts\prepare_desktop_bundle.ps1 ` -BinDir $binDir ` -Version $env:VERSION ` diff --git a/AGENTS.md b/AGENTS.md index 96f48ff7..15ba668d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,96 +1,69 @@ # AGENTS.md — WebCodex Repository Guide -These are the always-on rules for ordinary repository work. Read only the linked sections needed for the current task. A deeper `AGENTS.md` governs its directory. +These rules apply to ordinary repository work. Read linked domain guidance only when relevant; a deeper `AGENTS.md` governs its directory. -## Active development - -WebCodex is actively developed and is not feature-frozen. Ordinary work may add explicitly requested capabilities as well as correctness, reliability, and test improvements. Keep changes focused and do not weaken safety, credential, process-tree, transport, durability, or boundedness contracts. +WebCodex is actively developed. Requested features, fixes, and reliability improvements are welcome; preserve credential, process-tree, transport, durability, and boundedness contracts. ## 1. Verify and preserve -- Work only in the repository, worktree, and external target authorized by the user. -- At task start, verify the root, branch, HEAD, status, relevant changes, and recent history. Recheck only after a Git operation, an observed concurrent change, or before committing. -- Treat prompt hashes, paths, branches, and runtime state as expectations to verify, never as reasons to overwrite the actual repository. -- Preserve unrelated work. Do not reset, rebase, restore, clean, or rewrite history unless the user explicitly requests that operation. -- Inspect only the implementation, tests, documentation, and diff relevant to the task; do not bulk-read unrelated material. - -## 2. Build the simplest useful product - -- Optimize for a workflow that is simple, obvious, and easy to operate. -- Prefer the smallest direct solution. Add abstractions, configuration, modes, compatibility layers, or extension points only for a concrete current need or a demonstrated reliability problem. -- Do not build a general framework for one use case. Wait for a second concrete use case before extracting shared machinery. -- Do not design for hypothetical consumers, tenants, deployment scales, or trust boundaries that the product does not have. -- Protect real boundaries—credentials, public entry points, destructive actions, wrong-target execution, repository history, and published artifacts—without adding policy machinery for imaginary ones. -- A feature that introduces a new externally reachable authority, credential audience, or replaceable runtime target creates a concrete present boundary. Model it explicitly when reusing an existing scope, identity, or lease would broaden existing credentials or allow stale requests to retarget; fewer concepts is not a reason to collapse distinct authority. -- When two designs satisfy the current need, choose the one with fewer concepts, states, configuration paths, and maintenance costs. -- For model-facing execution, prefer structured process/argv and durable Job/observation primitives over shell-text orchestration. Keep shell as an escape hatch; structured lifecycle state is the source of truth for retry safety. -- Keep model-facing ToolSpec/OpenAPI operation descriptions accurate, self-contained, and reasonably concise. Do not compress descriptions merely to hit an arbitrary soft target; use up to `MODEL_TOOL_DESCRIPTION_MAX_CHARS` when needed to preserve selection, authority, effect, retry, continuation, uncertainty, safety, recovery, and other important model guidance. Shorter is better only when semantics remain equally precise. -- Treat demonstrated host features such as MCP App orchestration as optional adapters. Core execution and Job semantics must remain protocol-, UI-, transport-, and OS-neutral. -- Never assume a model-facing HTTP/MCP request has stable model-window or Workflow Session identity. Treat requests as stateless unless that exact adapter/protocol contract explicitly supplies a stable `ClientWindow`. Stateless MCP 2026 must not derive hidden continuity from `Mcp-Session-Id`, connection state, credentials, project identity, or prior requests. Transport/audit/session correlation ids are not Workflow Session, model-context-retention, or authority proofs by themselves; use explicit durable identifiers from their owning domain. Connector Tasks, Workflow Sessions, durable Agents/Conversations, and future Agent Tasks are distinct identities and must not be inferred from one another. +- Work only in the repository, worktree, and external targets authorized by the user. +- At task start, verify root, branch, HEAD, status, relevant changes, and recent history. Recheck after Git operations, observed concurrent changes, or before committing. +- Treat prompt paths, hashes, branches, and runtime state as expectations to verify, not permission to overwrite actual state. +- Preserve unrelated and concurrent work. Use guarded edits; do not reset, rebase, restore, clean, or rewrite history without an explicit request for that operation. +- Read only implementation, tests, documentation, and diffs relevant to the task. + +## 2. Design for the current need + +- Make workflows simple and obvious. Choose the smallest coherent solution with the fewest concepts, states, and maintenance costs. Add abstractions, configuration, or compatibility only for a concrete need; do not build for hypothetical consumers or scale. +- Protect real boundaries: credentials, public entry points, destructive actions, execution targets, history, and published artifacts. Model new authority, credential audiences, and replaceable targets explicitly when sharing scopes, identities, or leases would broaden access or allow stale requests to retarget. +- Prefer structured process/argv and durable Job/observation primitives for model-facing execution. Shell remains an escape hatch; structured lifecycle state owns retry safety. +- Keep ToolSpec/OpenAPI descriptions self-contained and accurate about selection, authority, effects, retries, continuation, uncertainty, and recovery. Use up to `MODEL_TOOL_DESCRIPTION_MAX_CHARS` when needed; arbitrary brevity must not remove semantics. +- Keep core execution and Job semantics protocol-, UI-, transport-, and OS-neutral. Host-specific features such as MCP App orchestration belong in optional adapters. +- HTTP/MCP requests are stateless unless their exact adapter contract supplies a stable `ClientWindow`. Never infer Workflow Session, model-context retention, or authority from transport/audit IDs, credentials, projects, or prior requests. Keep Connector Tasks, Workflow Sessions, durable Agents/Conversations, and Agent Tasks distinct; follow the Session and Agent contracts linked below. Product direction: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md). -## 3. Follow intent and make focused changes - -- The requested outcome, scope, prohibited actions, and acceptance conditions are hard constraints. Suggested files, symbols, commands, and step order are guidance unless explicitly mandatory. -- If guidance conflicts with current code or repository conventions, make the smallest adjustment that still satisfies the task. -- Do not knowingly create a bug, inconsistent state, resource leak, compatibility hazard, or false validation result. -- Prefer the smallest coherent change. Follow existing architecture and naming; avoid speculative compatibility, duplicate representations, unrelated cleanup, and broad refactors without a named current need. -- For explicit cross-layer feature work, map the complete authoritative vertical slice before editing and close the existing architecture end to end before local hardening. -- Minimize new concepts rather than the number of touched files. A coherent vertical slice may update several existing layers when each is part of the same current capability. -- Use compiler, type, schema, and exhaustiveness failures to find missing enum, registry, adapter, and projection closure before broadening validation. -- After focused tests pass, perform a separate completeness audit and then a trust/bounds/privacy/replay audit before considering the implementation finished. -- Implementation ownership and independent adversarial review are separate passes. In an implementation-owner pass, prioritize a complete authoritative vertical slice and strong first delivery within the current contract; resolve known correctness issues, including concrete authority/identity boundaries created by the feature, but do not fragment the implementation around speculative reviewer concerns. A later review pass independently challenges the resulting design and implementation. -- Keep only the interfaces actually affected by the change consistent. Do not touch or revalidate unrelated projections merely because they exist. -- Add focused tests for changed behavior when practical. Update documentation when public behavior or operations change. -- When a subsystem already has a dedicated `tests/` module tree, put ordinary new tests there instead of growing production facade files. Keep inline `#[cfg(test)]` blocks small and tightly coupled to private implementation helpers; process, network, and integration fixtures belong in dedicated test modules. -- Do not grow one test file into a multi-domain catch-all. When an already-large test module needs coverage for a distinct lifecycle or contract domain, create or reuse a domain-specific test module and split by canonical ownership, not arbitrary line-count chunks. -- In async tests, required readiness must use a `wait_*` path with one absolute deadline that partial progress never resets. `probe_*` helpers are only for observations where immediate absence is valid or for one iteration inside an already-owned outer deadline; never use a probe when absence means test failure. -- Ask only when required information cannot be discovered, instructions materially conflict, or proceeding could destroy work. Otherwise continue and report any material deviation. - -## 4. Validate only changed behavior - -Validation is evidence, not ceremony. - -- Start with the smallest check that can detect a regression. Stop when sufficient relevant evidence has passed. -- Reuse a successful result from the exact same HEAD when relevant files have not changed. -- Do not rerun the same command unless relevant code changed, a rebase or conflict invalidated it, the earlier run was incomplete or flaky, or the user requested a repeat. -- Documentation-only changes do not require Cargo compilation or tests. -- Rust changes normally require affected formatting, the smallest relevant package check when compilation may be affected, and focused tests. -- For ordinary development builds that need optimized binaries, use the `dogfood` Cargo profile by default (for example, `cargo build --profile dogfood --bin webcodex-server`). Reserve the `release` profile for formal release/publication artifacts. -- Full library or workspace tests, `--all-targets`, ignored tests, real-process harnesses, and E2E scripts are not defaults. Run them only for an explicit user request, release or deployment, a genuinely cross-cutting boundary, broad conflict resolution, or when focused validation cannot cover the change. State the reason first. -- Distinguish current failures from pre-existing failures, expected negative cases, and failures resolved by a successful retry. -- Before finishing, review the diff and confirm whitespace, worktree, conflict, and active-job state. +## 3. Implement and review + +- User outcomes, scope, prohibitions, and acceptance conditions are hard constraints. Suggested files and steps are guidance unless explicitly mandatory; adapt them to verified code and conventions. +- Follow existing architecture and naming. Avoid unrelated cleanup, duplicate representations, speculative compatibility, and broad refactors without a current need. +- For cross-layer features, map the authoritative path before editing and complete it end to end. Update affected enums, registries, schemas, adapters, and projections; do not touch unrelated interfaces merely because they exist. +- Use compiler, type, schema, and exhaustiveness failures to locate missing integration before broadening validation. +- Add focused tests where practical and update documentation when public behavior or operations change. +- Review the completed diff separately from implementation. Check completeness, then relevant authority, bounds, privacy, and replay risks. Match review depth to the change; resolve demonstrated issues without designing around hypothetical reviewer concerns. +- Ask only when required information cannot be discovered, instructions materially conflict, or proceeding could destroy work. Otherwise continue and report material deviations. + +## 4. Validate changed behavior + +- Start with the smallest check that can detect a regression; stop when sufficient relevant evidence passes. Reuse results when the validated source and relevant dependencies are unchanged. Repeat only after relevant changes, invalidating conflicts, incomplete/flaky runs, or a user request. +- Documentation-only changes need no Cargo compilation or tests. Rust changes normally need affected formatting, the smallest relevant package check when compilation may be affected, and focused tests. +- Use the `dogfood` Cargo profile for optimized development builds; reserve `release` for formal release/publication artifacts. +- Full library/workspace tests, `--all-targets`, ignored tests, real-process harnesses, and E2E are not defaults. Use them for explicit requests, release/deployment, cross-cutting boundaries, broad conflict resolution, or gaps in focused coverage. State the reason first. +- Put tests in existing dedicated module trees, grouped by domain. Keep inline `#[cfg(test)]` blocks small and tied to private helpers; process/network/integration fixtures belong in dedicated test modules. +- Async readiness must use a `wait_*` path with one absolute deadline that progress never resets. Use `probe_*` only when immediate absence is valid or inside an already-owned deadline. +- Distinguish current failures, pre-existing failures, expected negative cases, and failures resolved by retry. Never weaken authentication, authorization, validation, schemas, sandboxing, or tests to get a passing result. Testing guidance: [`docs/TESTING.md`](docs/TESTING.md). -## 5. Protect work and keep delivery explicit +## 5. Deliver only what is authorized - Never print, commit, or expose credentials, authorization headers, private keys, tokens, secret files, or sensitive command output. -- Do not silently overwrite concurrent changes. Prefer guarded or conflict-detecting edits. -- Do not weaken meaningful authentication, authorization, validation, schemas, sandboxing, or tests merely to obtain a green result. -- Do not force-push, move published tags, overwrite releases, destructively reset other work, or rewrite published history without an explicit request naming the operation and target. -- A failed **pre-publication** version tag is not yet a published release identity only when no GitHub Release exists, the npm version is absent, and no successful authoritative release-build exists. Such a tag may be reclaimed only in an explicitly requested release-recovery task through the repository release operator's guarded reclaim path; active/successful build or any publication makes the tag immutable. -- Push, publish, tag, release, deploy, restart services, or alter external systems only when the task explicitly includes it and identifies the destination. -- An explicit development/dogfood deployment of a reviewed commit to named targets is not a release rollout. It may install and restart that exact development build without a version bump, Git tag, GitHub Release, npm publication, or release-artifact preparation. -- For a development/dogfood deployment, change only the named targets, record the requested source commit and the existing build identity (`git_commit`, `git_dirty`, `built_at`), never hide dirty build state, preserve a rollback path, and run focused post-deployment smoke. -- Release or publication rollouts still follow the immutable version/tag/artifact contract in the release guidance below. -- Review status and diff before committing. Do not mix unrelated work or amend an unrelated commit. +- Before committing, review status and diff. Keep unrelated work separate; do not amend an unrelated commit. +- Push, publish, tag, release, deploy, restart services, or alter external systems only when explicitly requested with a named destination. +- Never force-push, move published tags, overwrite releases, or rewrite published history without an explicit request naming the operation and target. Release operations must also obey the immutable artifact contract below; failed pre-publication tag recovery is permitted only through its explicitly authorized guarded reclaim path. +- Named development/dogfood deployments are separate from releases. Deploy the reviewed source commit, record its build identity without hiding dirty state, preserve rollback, and run focused smoke. They do not authorize version bumps, tagging, or publication. +- Before finishing, check the final diff, whitespace, worktree, conflicts, and active jobs. Report the outcome, changed files/targets, validation, Git/job state, material deviations, and remaining risks. State whether push, publication, deployment, or service operations occurred. -Release guidance: [`docs/agent/release-process.md`](docs/agent/release-process.md) and [`docs/RELEASE_CHECKLIST.md`](docs/RELEASE_CHECKLIST.md). +For release, recovery, or deployment work, follow [`docs/agent/release-process.md`](docs/agent/release-process.md) and, for release/publication gates, [`docs/RELEASE_CHECKLIST.md`](docs/RELEASE_CHECKLIST.md). -## 6. Load domain rules only when relevant +## 6. Load relevant domain rules - Public runtime and API surfaces: [`docs/agent/openapi-guidelines.md`](docs/agent/openapi-guidelines.md). -- Workflow Sessions: [`docs/agent/session-model.md`](docs/agent/session-model.md). +- Workflow Sessions and request identity: [`docs/agent/session-model.md`](docs/agent/session-model.md). - Manual multi-window collaboration: [`docs/agent/manual-window-collaboration.md`](docs/agent/manual-window-collaboration.md). - Durable Agent identity, Conversation/Wake, and asynchronous Agent work: [`docs/architecture/durable-agent-runtime.md`](docs/architecture/durable-agent-runtime.md). - Current durable Agent/Conversation/Wake implementation contract: [`docs/architecture/durable-agent-conversation.md`](docs/architecture/durable-agent-conversation.md). - Authority boundaries: [`docs/agent/permission-model.md`](docs/agent/permission-model.md). - Architecture decisions: [`docs/agent/architecture-decisions.md`](docs/agent/architecture-decisions.md). -Use these documents as sources of truth instead of copying subsystem invariants into every task prompt. - -## 7. Report the completed state - -Report the outcome, changed files or external resources, validation performed, final Git and job state, material deviations, and remaining risks. State whether push, release, deployment, or service operations were performed. Tool output is evidence, not a substitute for engineering judgment. +Use these as domain sources of truth rather than duplicating their detailed contracts here. diff --git a/README.md b/README.md index 773af8ae..45a8b421 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ npx --yes @yyjeqhc/webcodex share - **Use the real toolchain** — run commands, tests, formatters, compilers, and project-specific tooling on the machine that owns the repository. - **Work with Git** — inspect status and diffs while keeping repository operations visible and reviewable. - **Handle long-running work** — keep jobs observable instead of requiring one model turn to stay open indefinitely. -- **Support human review** — use the Runtime Console and task workflow to guide, cancel, accept, or reject work where those actions are available. +- **Support human review** — use the [Runtime Console](docs/runtime-console.md) and task workflow to guide, cancel, accept, or reject work where those actions are available. ## Why WebCodex? diff --git a/apps/desktop/src-tauri/src/process/tests/macos.rs b/apps/desktop/src-tauri/src/process/tests/macos.rs index d9540452..1d13e8c5 100644 --- a/apps/desktop/src-tauri/src/process/tests/macos.rs +++ b/apps/desktop/src-tauri/src/process/tests/macos.rs @@ -1,8 +1,9 @@ use crate::activity::ActivityLog; use crate::process::{ProcessKind, ProcessSupervisor}; use std::path::{Path, PathBuf}; +use std::process::Command; use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use tokio::process::{Child, Command}; +use tokio::process::{Child, Command as TokioCommand}; const TEST_TIMEOUT: Duration = Duration::from_secs(5); const POLL_INTERVAL: Duration = Duration::from_millis(20); @@ -76,7 +77,7 @@ async fn desktop_owned_group_kills_descendant_without_touching_unrelated_process .arg("webcodex-owned-tree") .arg(&marker); - let mut control = Command::new("/bin/sleep") + let mut control = TokioCommand::new("/bin/sleep") .arg("60") .spawn() .expect("spawn unrelated control process"); diff --git a/apps/desktop/src-tauri/src/webcodex/cli.rs b/apps/desktop/src-tauri/src/webcodex/cli.rs index 2865cb88..57fb1809 100644 --- a/apps/desktop/src-tauri/src/webcodex/cli.rs +++ b/apps/desktop/src-tauri/src/webcodex/cli.rs @@ -1119,19 +1119,15 @@ mod tests { .unwrap_or_default() .as_nanos() )); - let script = concat!( - "$child = Start-Process powershell.exe ", - "-ArgumentList '-NoProfile','-NonInteractive','-Command','Start-Sleep -Seconds 30' ", - "-PassThru; ", - "Set-Content -Path $args[0] -Value \"$PID $($child.Id)\" -NoNewline; ", - "Start-Sleep -Seconds 30" + let escaped_marker = marker.to_string_lossy().replace('\'', "''"); + let script = format!( + "$child = Start-Process powershell.exe -ArgumentList '-NoProfile','-NonInteractive','-Command','Start-Sleep -Seconds 30' -PassThru; Set-Content -LiteralPath '{escaped_marker}' -Value \"$PID $($child.Id)\" -NoNewline; Start-Sleep -Seconds 30" ); let args = vec![ "-NoProfile".to_string(), "-NonInteractive".to_string(), "-Command".to_string(), - script.to_string(), - marker.to_string_lossy().to_string(), + script, ]; let payload = vec![b'x'; CLI_INPUT_BYTES]; let started = Instant::now(); @@ -1143,11 +1139,11 @@ mod tests { Some(&payload), false, &cancellation, - Duration::from_secs(5), + Duration::from_secs(8), ) .await }); - let marker_deadline = Instant::now() + Duration::from_secs(4); + let marker_deadline = Instant::now() + Duration::from_secs(6); while !marker.is_file() { assert!( Instant::now() < marker_deadline, @@ -1155,13 +1151,13 @@ mod tests { ); tokio::time::sleep(Duration::from_millis(20)).await; } - let error = tokio::time::timeout(Duration::from_secs(5), command) + let error = tokio::time::timeout(Duration::from_secs(12), command) .await .expect("blocked-stdin command must finish within its bounded cleanup") .expect("blocked-stdin fixture task") .unwrap_err(); assert_eq!(error.code, "webcodex_command_timeout"); - assert!(started.elapsed() < Duration::from_secs(9)); + assert!(started.elapsed() < Duration::from_secs(12)); let pids = std::fs::read_to_string(&marker) .expect("fixture must publish owned pids") .split_whitespace() diff --git a/crates/webcodex-core/src/runtime_contract.rs b/crates/webcodex-core/src/runtime_contract.rs index aedf2ab3..4c7be84a 100644 --- a/crates/webcodex-core/src/runtime_contract.rs +++ b/crates/webcodex-core/src/runtime_contract.rs @@ -48,7 +48,7 @@ pub const RECOVERY_TOOL_VALUES: [&str; 7] = [ ]; pub const BUILTIN_CODING_WORKFLOW_CONTRACT: &str = "webcodex.coding_workflow"; -pub const BUILTIN_CODING_WORKFLOW_VERSION: u64 = 6; +pub const BUILTIN_CODING_WORKFLOW_VERSION: u64 = 7; pub const BUILTIN_CODING_WORKFLOW_MAX_GUIDANCE_ITEMS: usize = 8; /// Validate a Runner project path without applying host-local filesystem semantics. diff --git a/crates/webcodex-tool-contracts/src/registry/output_schemas/coding_tasks.rs b/crates/webcodex-tool-contracts/src/registry/output_schemas/coding_tasks.rs index 58ae06d3..09baf122 100644 --- a/crates/webcodex-tool-contracts/src/registry/output_schemas/coding_tasks.rs +++ b/crates/webcodex-tool-contracts/src/registry/output_schemas/coding_tasks.rs @@ -402,12 +402,19 @@ fn startup_workspace_schema() -> Value { fn startup_workflow_schema() -> Value { json!({ "type": "object", - "description": "WebCodex-owned model guidance for named coding/review pass roles. Separate from project instructions and Session authority.", + "description": "WebCodex-owned workflow defaults and optional named coding/review roles. Separate from project instructions and Session authority.", "properties": { "contract": {"type": "string", "const": BUILTIN_CODING_WORKFLOW_CONTRACT}, "version": {"type": "integer", "const": BUILTIN_CODING_WORKFLOW_VERSION}, "authority": {"type": "string", "const": "model_guidance_only"}, "role_selection": {"type": "string", "maxLength": 240}, + "guidance": { + "type": "array", + "description": "Default behavior for every coding/review task, including tasks without a named role. Guidance never grants authority.", + "minItems": 1, + "maxItems": BUILTIN_CODING_WORKFLOW_MAX_GUIDANCE_ITEMS, + "items": {"type": "string", "maxLength": 320} + }, "model_protocol": { "type": "object", "description": "Shared model-invocation guidance. It is not Session state, authority, or execution policy.", @@ -443,7 +450,7 @@ fn startup_workflow_schema() -> Value { "additionalProperties": false } }, - "required": ["contract", "version", "authority", "role_selection", "model_protocol", "roles"], + "required": ["contract", "version", "authority", "role_selection", "guidance", "model_protocol", "roles"], "additionalProperties": false }) } diff --git a/crates/webcodex-tool-contracts/src/test_support.rs b/crates/webcodex-tool-contracts/src/test_support.rs index 75ba6b0b..ae416bac 100644 --- a/crates/webcodex-tool-contracts/src/test_support.rs +++ b/crates/webcodex-tool-contracts/src/test_support.rs @@ -108,6 +108,11 @@ fn validate_schema_instance_at(instance: &Value, schema: &Value, path: &str) -> } } if let Some(array) = instance.as_array() { + if let Some(min_items) = schema.get("minItems").and_then(Value::as_u64) { + if array.len() < min_items as usize { + return Err(format!("{path}: below minItems")); + } + } if let Some(max_items) = schema.get("maxItems").and_then(Value::as_u64) { if array.len() > max_items as usize { return Err(format!("{path}: maxItems exceeded")); diff --git a/docs/CODING_WORKFLOW.md b/docs/CODING_WORKFLOW.md index 968ec288..f21b1c98 100644 --- a/docs/CODING_WORKFLOW.md +++ b/docs/CODING_WORKFLOW.md @@ -25,7 +25,14 @@ Use `work_on_project` for both a new coding task and an explicit continuation. W For ordinary use you do not need to reason about WebCodex's internal continuity or audit fields. Those are implementation/maintainer contracts. -Behavioral roles are expressed in the task instruction, not through a separate authority mechanism. For example: +The built-in workflow includes default guidance for every task, even when no +role is named: inspect the target and applicable rules, preserve existing work, +complete authorized implementation, validate proportionally, observe existing +Jobs instead of duplicating effects, and report evidence honestly. Use only +tools and protocol fields supported by the current exposed schemas. + +Behavioral roles add emphasis to those defaults. They are expressed in the task +instruction, not through a separate authority mechanism. For example: ```text Use the implementation_owner guidance. Implement , run focused validation, @@ -36,15 +43,26 @@ For an independent review: ```text Use the independent_review guidance. Review independently, -correct only concrete findings, and run focused regression validation. +report concrete findings with file/line evidence and impact, and do not edit. ``` -Role guidance changes model behavior only. Authentication, project authority, tool policy, and safety checks remain authoritative. +To request corrections as well, explicitly add “fix concrete findings and run +focused regression validation.” Naming a review role alone does not authorize edits. + +Guidance is delivered in tool results; it is not the client's system prompt and +does not grant execution authority. Host instructions, the user's task, +applicable project rules, authentication, and runtime safety policy still apply. +Delivery is not proof that a model read, retained, or followed the guidance. +Keep guidance enabled unless the current model context already retains it. ## Inspect before editing Prefer structured project search/read tools over shell commands when they express the task. Read only the files and ranges needed to understand the change, and preserve unrelated work already present in the workspace. +The bootstrap reads a fixed set of instruction entry points; it does not scan +every subdirectory for rules. Before changing a path, inspect applicable nested +instructions and recover any relevant missing or truncated rule content. + For branch/PR review, start with the bounded review/change-summary tools exposed by the current Server, then narrow to targeted reads or diff hunks when needed. ## Editing @@ -81,6 +99,20 @@ Multi-window coordination is an advanced maintainer workflow, not part of the or The exact concurrency, retry, provenance, and cross-Session authorization rules are documented in [Manual Multi-Window Collaboration](agent/manual-window-collaboration.md). Their protocol fields are intentionally omitted here. +## Assessing effectiveness + +Runtime tests check that guidance is delivered consistently, remains bounded, +matches its schema, and never becomes authority. The scripted +`scripts/eval_coding_loop.sh` checks tool-loop mechanics; it does not run a model +or measure instruction following. + +To measure behavioral benefit, compare the same model, tools, settings, and task +fixtures with and without guidance over repeated runs. Include a small fix, a +review-only task, existing unrelated changes, nested instructions, and an +uncertain long-running effect. Compare correctness and scope preservation first, +then unnecessary clarification, duplicate execution, validation quality, tool +calls, and token cost. Do not infer a success-rate improvement from schema tests. + ## Internal protocol details When developing WebCodex itself, use the maintainer contracts rather than expanding this user guide: diff --git a/docs/CODING_WORKFLOW.zh-CN.md b/docs/CODING_WORKFLOW.zh-CN.md index f991b3a0..79a1ce7f 100644 --- a/docs/CODING_WORKFLOW.zh-CN.md +++ b/docs/CODING_WORKFLOW.zh-CN.md @@ -25,7 +25,9 @@ work_on_project 普通使用不需要理解 WebCodex 内部的 continuity/audit field;这些属于 implementation/maintainer contract。 -Behavioral role 写在 task instruction 里即可,例如实现任务: +内置工作流为所有任务提供默认 guidance,不要求先指定角色:核对目标和适用规则、保留已有工作、完成已授权的实现、按改动范围验证、观察已有 Job 而不重复执行,以及如实报告证据。只使用当前暴露的 schema 支持的工具与协议字段。 + +Behavioral role 在默认原则上增加侧重点,写在 task instruction 里即可,例如实现任务: ```text 使用 implementation_owner guidance。实现 <任务>,运行聚焦 validation, @@ -36,15 +38,19 @@ Behavioral role 写在 task instruction 里即可,例如实现任务: ```text 使用 independent_review guidance。独立评审 <改动或 commit>, -只修复具体问题,并运行聚焦 regression validation。 +报告有文件/行号证据和影响说明的具体发现,不修改文件。 ``` -Role guidance 只改变模型行为,不改变 authentication、project authority、tool policy 或 hard safety。 +如果也希望修复,明确补充“修复具体发现,并运行聚焦回归验证”。单独指定评审角色不代表授权修改。 + +Guidance 通过工具结果交给客户端,不是客户端的 system prompt,也不会授予执行权限。Host 指令、用户任务、适用项目规则、认证和运行时安全策略仍然有效。返回 guidance 不等于模型已经读取、记住或遵守;只有当前模型上下文仍保留内容时才应关闭其返回。 ## 编辑前先检查 能够表达任务时,优先使用 structured project search/read,而不是 shell。只读取理解当前改动所需的文件和范围,并保留 workspace 中已经存在的无关工作。 +Bootstrap 只读取固定的几个指令入口,不会扫描所有子目录规则。修改某个路径前,需要检查适用的子目录指令,并补读相关缺失或被截断的规则内容。 + 做 branch/PR review 时,先使用当前 Server 提供的有界 review/change-summary 工具,再按需要缩小到具体文件或 diff hunks。 ## 编辑 @@ -81,6 +87,12 @@ Guard failure 是 **zero-write conflict**,不是削弱 guard 的理由。重 精确的 concurrency、retry、provenance 与 cross-Session authorization 规则见 [Manual Multi-Window Collaboration](agent/manual-window-collaboration.md)。对应 protocol field 有意不放在普通工作流里。 +## 如何判断是否有效 + +运行时测试可以证明 guidance 的返回一致、有界、符合 schema,且不会变成执行权限。`scripts/eval_coding_loop.sh` 检查的是脚本化工具循环,没有运行模型,不能衡量模型是否遵守提示词。 + +要衡量行为收益,应固定模型、工具、参数与任务样本,对比有无 guidance 的多次运行。样本至少包括小型修复、只读评审、已有无关改动、子目录规则,以及结果不确定的长时间操作。先比较正确性与任务范围保持,再比较不必要的询问、重复执行、验证质量、工具调用和 token 成本。不能从 schema 测试通过推断模型成功率提升。 + ## 内部协议细节 开发 WebCodex 本身时,直接阅读 maintainer contract,而不是继续扩充这份普通用户指南: diff --git a/docs/agent/openapi-guidelines.md b/docs/agent/openapi-guidelines.md index 423a97b2..2d41ccee 100644 --- a/docs/agent/openapi-guidelines.md +++ b/docs/agent/openapi-guidelines.md @@ -1,9 +1,8 @@ # OpenAPI / GPT Action Guidelines Product and integration detail for GPT Actions and OpenAPI exposure. -**Hard invariants agents must obey are in [`AGENTS.md`](../../AGENTS.md)** -(architecture section). This document holds the longer product rules so -`AGENTS.md` stays an execution contract. +Repository-wide rules are in [`AGENTS.md`](../../AGENTS.md). This document +owns the API-specific invariants and product guidance linked from that guide. Related: [`GPT_ACTIONS.md`](../GPT_ACTIONS.md), [`MCP.md`](../MCP.md). diff --git a/docs/agent/session-model.md b/docs/agent/session-model.md index 36753a24..664f782c 100644 --- a/docs/agent/session-model.md +++ b/docs/agent/session-model.md @@ -562,10 +562,6 @@ For deliberate coordinator/worker delegation across separate windows, keep the Sessions independent and use the existing handoff plus message-board primitives; see [Manual Multi-Window Collaboration](manual-window-collaboration.md). -### Invariants (must) - -These are also summarized in `AGENTS.md` §7, **Sessions**: - --- ## 2. Action Audit Session diff --git a/docs/runtime-console.md b/docs/runtime-console.md new file mode 100644 index 00000000..deabb6ce --- /dev/null +++ b/docs/runtime-console.md @@ -0,0 +1,24 @@ +# Runtime Console navigation + +Open `/runtime` and connect with an existing runtime credential. + +- **Projects & Sessions** is the collaboration workspace. Select a Project and + Workflow Session in the sidebar. Recent Sessions starts expanded and can be + collapsed when more room is needed. +- **Context** opens the selected Session's context. **Overview** shows work, + attention, validation, and model-reported progress directly. **Activity** shows + retained events and the existing follow-latest control. **Details** shows + identity, lifecycle, mode, timestamps, and workspace information. +- **Runtime & Agents** provides three separate destinations: **Overview**, + **Runner fleet**, and **Durable Agents**. Selecting a destination shows its + full content and updates the navigation highlight. Switching destinations + keeps existing forms mounted so unsent input is retained. + +The context panel still adapts between a docked rail, popover, and mobile sheet. +Closing it leaves a labeled Context entry in the header. Context navigation uses +ordinary keyboard-focusable buttons, with the current choice announced as pressed. +Mobile operation navigation closes after selection and focuses the destination. + +These are presentation changes. Workflow Session and durable Agent identities, +credential scopes, refresh behavior, and mutation handling keep their existing +contracts. Model-reported progress remains informational. diff --git a/frontend/dist/runtime.css b/frontend/dist/runtime.css index 8664a02b..0cdbcec9 100644 --- a/frontend/dist/runtime.css +++ b/frontend/dist/runtime.css @@ -1 +1 @@ -:root{font-family:-apple-system,BlinkMacSystemFont,"SF Pro Text","SF Pro Display","PingFang SC","Microsoft YaHei",Inter,ui-sans-serif,system-ui,"Segoe UI",sans-serif;color-scheme:dark;--page:#090a0d;--page-end:#090a0d;--page-surface:#0c0e12;--sidebar:#111318;--sidebar-drawer:#111318;--topbar:rgba(12,14,18,.84);--sidebar-hover:rgba(255,255,255,.048);--sidebar-selected:rgba(117,126,232,.13);--composer:rgba(20,22,28,.9);--surface:rgba(22,24,30,.97);--surface-solid:#16181e;--surface-soft:rgba(255,255,255,.05);--surface-raised:#181a20;--surface-inset:rgba(255,255,255,.035);--input:rgba(255,255,255,.052);--text:#f2f3f5;--muted:#91969f;--muted-strong:#c7cad0;--placeholder:#737984;--border:rgba(255,255,255,.105);--border-soft:rgba(255,255,255,.065);--glass-highlight:transparent;--glass-sheen:transparent;--glass-glow:transparent;--glass-edge:var(--border);--message-incoming-bg:rgba(255,255,255,.055);--message-incoming-border:rgba(255,255,255,.075);--message-outgoing-bg:#285487;--message-outgoing-border:rgba(132,178,235,.2);--message-outgoing-text:#f8faff;--message-bubble-radius:22px;--accent:#9ba4ff;--accent-soft:rgba(112,122,225,.16);--accent-border:rgba(143,152,244,.46);--accent-solid:#6571d6;--accent-hover:#7681e4;--pass:#4bd38a;--warn:#f0ae5c;--fail:#ff7e82;--danger-bg:rgba(255,104,110,.1);--danger-border:rgba(255,118,123,.34);--overlay:rgba(5,7,11,.58);--scrollbar:rgba(184,193,207,.28);--avatar:rgba(255,255,255,.15);--send-bg:#f6f8fc;--send-text:#151922;--ambient-one:transparent;--ambient-two:transparent;--ambient-three:transparent;--layout-major:61.8%;--layout-minor:38.2%;--layout-tertiary:23.6%;--sidebar-width:clamp(300px,21vw,356px);--context-rail-width:clamp(320px,18vw,360px);--header-height:68px;--content-width:1120px;--content-gutter:clamp(20px,3vw,56px);--ease-out:cubic-bezier(.23,1,.32,1);--ease-drawer:cubic-bezier(.32,.72,0,1);--glass-blur:blur(14px) saturate(120%);--shadow-window:none;--shadow-raised:0 20px 60px rgba(0,0,0,.42)}:root[data-resolved-theme="light"]{color-scheme:light;--page:#f4f4f1;--page-end:#f4f4f1;--page-surface:#fafaf8;--sidebar:#efefec;--sidebar-drawer:#f4f4f1;--topbar:rgba(250,250,248,.86);--sidebar-hover:rgba(30,31,35,.045);--sidebar-selected:rgba(83,96,189,.095);--composer:rgba(255,255,253,.92);--surface:rgba(255,255,253,.97);--surface-solid:#fffffd;--surface-soft:rgba(27,29,35,.045);--surface-raised:#fffffd;--surface-inset:rgba(27,29,35,.035);--input:rgba(27,29,35,.045);--text:#202126;--muted:#737780;--muted-strong:#4e525b;--placeholder:#90949c;--border:rgba(30,31,35,.115);--border-soft:rgba(30,31,35,.07);--glass-highlight:transparent;--glass-sheen:transparent;--glass-glow:transparent;--glass-edge:var(--border);--message-incoming-bg:rgba(25,32,45,.055);--message-incoming-border:rgba(25,32,45,.065);--message-outgoing-bg:#2866a8;--message-outgoing-border:rgba(24,73,135,.2);--message-outgoing-text:#ffffff;--accent:#4f5eba;--accent-soft:rgba(83,96,189,.105);--accent-border:rgba(83,96,189,.34);--accent-solid:#5967c4;--accent-hover:#4d5bb6;--pass:#188659;--warn:#af680e;--fail:#d84d53;--danger-bg:rgba(216,77,83,.08);--danger-border:rgba(216,77,83,.26);--overlay:rgba(37,45,59,.24);--scrollbar:rgba(74,86,105,.25);--avatar:rgba(45,60,83,.12);--send-bg:#2875e5;--send-text:#fff;--ambient-one:transparent;--ambient-two:transparent;--ambient-three:transparent;--glass-blur:blur(14px) saturate(115%);--shadow-window:none;--shadow-raised:0 22px 60px rgba(45,52,68,.18)}*{box-sizing:border-box}[hidden]{display:none !important}html,body{width:100%;height:100%;background:var(--page)}html{-webkit-text-size-adjust:100%;text-size-adjust:100%}body{margin:0;overflow:hidden;overscroll-behavior:none;background:var(--page);color:var(--text);font-feature-settings:"kern" 1,"liga" 1;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}button,input,select,textarea{font:inherit}button,summary,[role="option"]{-webkit-tap-highlight-color:transparent}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,summary:focus-visible,[role="option"]:focus-visible{outline:2px solid var(--accent);outline-offset:2px}::selection{background:var(--accent-border);color:var(--text)}svg{display:block;fill:none;stroke:currentColor;stroke-width:1.65;stroke-linecap:round;stroke-linejoin:round}h1,h2,h3,h4,p{margin-top:0}h1{margin-bottom:3px;font-size:1.35rem}h2{margin-bottom:0;font-size:.95rem}h3{margin-bottom:8px;font-size:.86rem}h4{margin-bottom:5px;color:var(--muted);font-size:.7rem;letter-spacing:.065em;text-transform:uppercase}.muted{color:var(--muted)}.small{font-size:.78rem;line-height:1.45}.error{color:var(--fail)}.eyebrow{margin-bottom:3px;color:var(--muted);font-size:.69rem;font-weight:700;letter-spacing:.075em;text-transform:uppercase}.visually-hidden{position:absolute !important;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}#runtime-page{width:100%;height:100%}.runtime-shell{position:relative;width:100%;height:100dvh;display:grid;grid-template-columns:var(--sidebar-width) minmax(0,1fr);gap:0;padding:0;background:transparent}.auth-topbar{position:relative;z-index:40;width:min(760px,calc(100% - 40px));margin:0 auto;padding-top:max(40px,8vh);display:flex;justify-content:space-between;gap:20px;align-items:center}.runtime-connected .auth-topbar{display:none}.auth-preferences{display:flex;flex:0 0 auto;gap:7px;align-items:center}.brand-lockup{display:flex;align-items:center;gap:13px}.brand-lockup p{margin-bottom:0}.brand-mark{display:grid;width:40px;height:40px;place-items:center;border:1px solid var(--border);border-radius:11px;background:var(--surface-raised);color:var(--text);font-weight:800;box-shadow:none}.gate{width:min(660px,calc(100% - 40px));margin:32px auto 0;padding:30px;border:1px solid var(--border);border-radius:18px;background:var(--surface);box-shadow:var(--shadow-raised)}.gate h2{margin-bottom:9px;font-size:1.15rem}.gate>form>.muted{margin-bottom:20px;line-height:1.55}.gate-icon{display:grid;width:42px;height:42px;margin-bottom:18px;place-items:center;border:1px solid var(--border);border-radius:12px;background:var(--surface-soft);color:var(--muted-strong)}.gate-icon svg{width:21px;height:21px}.field-row{display:flex;gap:9px;align-items:center}.field-row input{flex:1;min-width:0;height:46px;border:1px solid var(--border);border-radius:10px;padding:0 14px;background:var(--input);color:var(--text);box-shadow:none}.remember-credential{display:flex;gap:7px;align-items:center;margin-top:11px;color:var(--muted);font-size:.72rem}.remember-credential input{accent-color:var(--accent-solid)}#runtime-token-error{min-height:1.2em;margin:9px 0 0;font-size:.8rem}.btn,.icon-btn,.send-btn{border:1px solid var(--border);background:var(--surface-soft);color:var(--text);cursor:pointer;box-shadow:none}.btn,.icon-btn,.send-btn,.mobile-nav-control,.text-button{transition:color 150ms ease,background-color 150ms ease,border-color 150ms ease,opacity 150ms ease,transform 150ms var(--ease-out)}.btn{min-height:36px;border-radius:9px;padding:6px 12px}.btn.primary{border-color:var(--accent-solid);background:var(--accent-solid);color:#fff;box-shadow:none}.btn.subtle{color:var(--muted-strong)}.btn:disabled,.icon-btn:disabled,.send-btn:disabled{cursor:not-allowed;opacity:.5}.icon-btn{display:grid;width:36px;height:36px;place-items:center;border-radius:9px}.icon-btn svg{width:17px;height:17px}.icon-btn.is-busy svg{animation:runtime-spin .8s linear infinite}.send-btn{display:grid;width:36px;height:36px;flex:0 0 auto;place-items:center;border:1px solid transparent;border-radius:999px;background:var(--surface-soft);color:var(--muted);box-shadow:none}.send-btn.is-ready{background:var(--send-bg);color:var(--send-text);animation:send-ready 180ms var(--ease-out)}.send-btn svg{width:17px;height:17px}.text-button{appearance:none;border:0;padding:2px 4px;background:transparent;color:var(--accent);cursor:pointer;font:inherit}.lock-button{display:inline-flex;gap:6px;align-items:center}.lock-button svg{display:none;width:17px;height:17px}@keyframes runtime-spin{to{transform:rotate(360deg)}}@keyframes send-ready{from{transform:scale(.88)}}@media (hover:hover){.btn:hover,.icon-btn:hover,.mobile-nav-control:hover{background:var(--sidebar-hover)}.btn.primary:hover{background:var(--accent-hover)}.send-btn.is-ready:hover{filter:brightness(1.06);transform:scale(1.04)}.text-button:hover{color:var(--accent-hover)}}.btn:active,.icon-btn:active,.send-btn:active,.mobile-nav-control:active,.text-button:active{transform:scale(.97)}.send-btn.is-ready:active{transform:scale(.94)}.topbar-controls,.chips,.summary-facts,.section-head,.timeline-controls{display:flex;gap:7px;align-items:center}.chips,.summary-facts{flex-wrap:wrap}.chip,.count-badge{display:inline-flex;align-items:center;border:1px solid var(--border);border-radius:999px;color:var(--muted-strong);font-size:.67rem;line-height:1}.chip{padding:4px 8px}.count-badge{min-width:22px;justify-content:center;padding:4px 6px;background:var(--surface-soft)}.tone-runtime{border-color:rgba(132,174,248,.55);color:var(--accent)}.tone-pass{border-color:rgba(71,199,125,.55);color:var(--pass)}.tone-warn{border-color:rgba(239,169,85,.55);color:var(--warn)}.tone-fail{border-color:rgba(242,115,115,.55);color:var(--fail)}.theme-menu{position:relative;z-index:70;flex:0 0 auto}.theme-menu>summary{list-style:none}.theme-menu>summary::-webkit-details-marker{display:none}.theme-trigger{color:var(--muted-strong)}.theme-menu[open] .theme-trigger{border-color:var(--accent-border);background:var(--accent-soft);color:var(--accent)}.theme-icon{display:none}:root[data-theme="system"] .theme-icon-system,:root[data-theme="light"] .theme-icon-light,:root[data-theme="dark"] .theme-icon-dark{display:block}.theme-popover{position:absolute;z-index:90;top:calc(100% + 9px);right:0;width:184px;padding:8px;border:1px solid var(--border);border-radius:13px;background:var(--surface);box-shadow:var(--shadow-raised);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);transform-origin:top right;animation:theme-menu-enter 160ms var(--ease-out);pointer-events:auto}.theme-popover-label{display:block;padding:5px 9px 7px;color:var(--muted);font-size:.62rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.theme-option{appearance:none;width:100%;min-height:38px;display:grid;grid-template-columns:18px minmax(0,1fr) 8px;gap:9px;align-items:center;border:0;border-radius:10px;padding:0 9px;background:transparent;color:var(--muted-strong);text-align:left;cursor:pointer}.theme-option svg{width:17px;height:17px}.theme-option span{font-size:.76rem;font-weight:590}.theme-option i{width:7px;height:7px;border-radius:50%;background:transparent;box-shadow:0 0 0 3px transparent}.language-toggle{flex:0 0 auto;color:var(--muted-strong)}.language-toggle span{display:block;min-width:1.35em;font-size:.68rem;font-weight:760;letter-spacing:.015em;line-height:1}:root[data-language="zh-CN"] .language-toggle span{font-size:.64rem;letter-spacing:.035em}.theme-option[aria-pressed="true"]{background:var(--accent-soft);color:var(--text)}.theme-option[aria-pressed="true"] i{background:var(--accent-solid);box-shadow:0 0 0 3px var(--accent-soft)}@media (hover:hover){.theme-option:hover{background:var(--sidebar-hover);color:var(--text)}}@keyframes theme-menu-enter{from{opacity:0;transform:translateY(-5px) scale(.97)}}.workspace-sidebar{min-width:0;min-height:0;display:grid;grid-template-rows:var(--header-height) auto minmax(0,1fr) 60px;overflow:hidden;border:0;border-right:1px solid var(--border-soft);border-radius:0;background:var(--sidebar);box-shadow:none}.sidebar-brand{display:flex;justify-content:space-between;align-items:center;padding:0 16px}.sidebar-brand-lockup,.sidebar-brand-tools,.sidebar-runtime-status{display:flex;align-items:center}.sidebar-brand-lockup{min-width:0;gap:10px}.sidebar-brand-lockup strong{overflow:hidden;font-size:.96rem;font-weight:650;letter-spacing:-.025em;text-overflow:ellipsis;white-space:nowrap}.sidebar-logo{display:grid;width:30px;height:30px;flex:0 0 auto;place-items:center;border:1px solid color-mix(in srgb,var(--text) 10%,transparent);border-radius:9px;background:var(--text);color:var(--page);font-size:.7rem;font-weight:760;box-shadow:0 1px 1px rgba(0,0,0,.12)}.sidebar-brand-tools{gap:8px}.sidebar-runtime-status{gap:5px;color:var(--muted);font-size:.7rem}.sidebar-runtime-status i{width:6px;height:6px;border-radius:50%;background:var(--pass);box-shadow:0 0 0 3px color-mix(in srgb,var(--pass) 13%,transparent)}.sidebar-runtime-status[data-connection="connecting"] i,.sidebar-connection[data-connection="connecting"] i,.operations-live[data-connection="connecting"] i{background:var(--warn)}.sidebar-runtime-status[data-connection="stale"] i,.sidebar-connection[data-connection="stale"] i,.operations-live[data-connection="stale"] i{background:var(--warn);box-shadow:0 0 0 3px color-mix(in srgb,var(--warn) 13%,transparent)}.sidebar-runtime-status[data-connection="disconnected"] i,.sidebar-connection[data-connection="disconnected"] i,.operations-live[data-connection="disconnected"] i{background:var(--fail);box-shadow:0 0 0 3px color-mix(in srgb,var(--fail) 13%,transparent)}.mobile-nav-control{display:none;width:40px;height:40px;flex:0 0 auto;place-items:center;border:1px solid transparent;border-radius:12px;background:transparent;color:var(--muted-strong);cursor:pointer}.mobile-nav-control svg{width:19px;height:19px}.mobile-nav-backdrop{position:fixed;z-index:39;inset:0;visibility:hidden;border:0;padding:0;background:var(--overlay);opacity:0;pointer-events:none;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);transition:opacity 220ms var(--ease-out),visibility 220ms}.sidebar-view-switch{display:grid;gap:3px;padding:0 10px 10px;border-bottom:1px solid var(--border-soft)}.sidebar-view-item{appearance:none;min-width:0;min-height:42px;display:grid;grid-template-columns:20px minmax(0,1fr) auto;gap:9px;align-items:center;border:0;border-radius:10px;padding:0 10px;background:transparent;color:var(--muted-strong);text-align:left;cursor:pointer;transition:background-color 140ms ease,color 140ms ease,transform 120ms var(--ease-out)}.sidebar-view-item>svg{width:18px;height:18px;color:var(--muted)}.sidebar-view-item>span:nth-child(2){overflow:hidden;font-size:.82rem;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.sidebar-view-item.selected{background:var(--sidebar-selected);color:var(--text)}.sidebar-view-item.selected>svg{color:var(--accent)}.sidebar-view-item:active{transform:scale(.985)}.sidebar-view-meta,.sidebar-connection{display:flex;gap:5px;align-items:center;color:var(--muted);font-size:.68rem;font-weight:450;white-space:nowrap}.sidebar-connection i,.live-pill i,.operations-live i{width:6px;height:6px;border-radius:50%;background:var(--pass)}.sidebar-scroll{min-height:0;overflow-y:auto;padding:14px 10px 16px;scrollbar-width:thin;scrollbar-color:var(--scrollbar) transparent}.sidebar-view-panel{min-width:0}.operations-navigation-copy{margin:9px 11px 15px}.operations-nav-item{appearance:none;width:100%;min-height:54px;display:grid;grid-template-columns:30px minmax(0,1fr);gap:9px;align-items:center;border:0;border-radius:10px;padding:7px 9px;background:transparent;color:var(--muted-strong);text-align:left;cursor:pointer}.operations-nav-item>svg{width:17px;height:17px;justify-self:center;color:var(--muted)}.operations-nav-item>span{min-width:0;display:grid;gap:2px}.operations-nav-item strong{font-size:.8rem;font-weight:600}.operations-nav-item small{overflow:hidden;color:var(--muted);font-size:.7rem;text-overflow:ellipsis;white-space:nowrap}.operations-nav-item:hover{background:var(--sidebar-hover)}.operations-nav-item.selected{background:var(--sidebar-selected);color:var(--text)}.operations-nav-item.selected>svg{color:var(--accent)}.sidebar-section{min-height:0;padding:0 0 14px}.sidebar-section-head{display:flex;justify-content:space-between;gap:10px;align-items:baseline;padding:0 11px}.sidebar-section-head h2{color:var(--muted);font-size:.74rem;font-weight:600;letter-spacing:.01em;text-transform:none}.sidebar-section-head #runtime-project-status{max-width:58%;overflow:hidden;color:var(--placeholder);font-size:.67rem;text-align:right;text-overflow:ellipsis;white-space:nowrap}.sidebar-filter-row{display:flex;gap:8px;align-items:center;margin:10px 2px 8px}.runner-filter{position:relative;min-width:0;flex:1;display:flex;align-items:center}.runner-filter>svg{position:absolute;z-index:1;left:9px;width:14px;height:14px;color:var(--muted);pointer-events:none}.runner-filter select{appearance:none;width:100%;height:36px;min-width:0;border:1px solid var(--border-soft);border-radius:9px;padding:0 28px 0 30px;background:var(--surface-soft);color:var(--muted-strong);font-size:.74rem;cursor:pointer}.runner-filter::after{content:"⌄";position:absolute;right:9px;color:var(--placeholder);font-size:.65rem;pointer-events:none}.sidebar-status{display:none}.selected-project{display:none}.sidebar-search{position:relative;margin:0 2px 14px}.sidebar-search svg{position:absolute;top:9px;left:9px;width:14px;height:14px;color:var(--placeholder);pointer-events:none}.sidebar-search input{width:100%;height:36px;min-width:0;border:1px solid var(--border-soft);border-radius:9px;padding:0 9px 0 31px;background:var(--surface-soft);color:var(--text);font-size:.75rem;transition:background-color 140ms ease,border-color 140ms ease}.sidebar-search input:hover,.sidebar-search input:focus{border-color:var(--border);background:var(--sidebar-selected);box-shadow:none}.sidebar-search input::placeholder{color:var(--placeholder)}.project-list,.session-list,.recent-session-list,.fleet-list,.communication-list{display:grid;align-content:start;grid-auto-rows:max-content;gap:2px;min-height:0;overflow:auto;scrollbar-width:thin;scrollbar-color:var(--scrollbar) transparent}.project-list{gap:8px;overflow:visible}.device-group{min-width:0;display:grid;gap:4px;padding:0;border:0}.device-group>summary::-webkit-details-marker{display:none}.device-group:last-child{padding-bottom:0;border-bottom:0}.device-group-head{display:grid;grid-template-columns:28px minmax(0,1fr) 8px 12px;gap:8px;align-items:center;min-height:40px;padding:2px 8px;border:0;border-radius:9px;background:transparent;box-shadow:none;cursor:pointer;list-style:none}.device-group-head::after{content:"›";color:var(--placeholder);font-size:1rem;transform:rotate(0deg);transition:transform 140ms var(--ease-out)}.device-group[open]>.device-group-head::after{transform:rotate(90deg)}.device-group-head:hover{background:var(--sidebar-hover)}.device-group-icon{display:grid;width:28px;height:28px;place-items:center;border:1px solid var(--border-soft);border-radius:8px;background:var(--surface-soft);color:var(--muted-strong)}.device-group-icon svg{width:14px;height:14px}.device-group-identity{display:grid;gap:1px;align-items:center}.device-group-identity strong{min-width:0;overflow:hidden;color:var(--muted-strong);font-size:.78rem;font-weight:620;letter-spacing:0;text-overflow:ellipsis;white-space:nowrap}.device-group-identity .small{overflow:hidden;color:var(--placeholder);font-size:.68rem;text-overflow:ellipsis;white-space:nowrap}.device-group-dot{width:6px;height:6px;border-radius:50%;background:var(--pass)}.device-group.offline .device-group-dot{background:var(--fail)}.device-project-list{display:grid;gap:2px;margin:0;padding:0;border-left:0}.device-project-empty{margin:4px 10px 8px}.project-row{appearance:none;position:relative;width:100%;min-width:0;display:grid;grid-template-columns:28px minmax(0,1fr);gap:0 9px;align-items:start;padding:8px;border:0;border-radius:9px;background:transparent;color:inherit;text-align:left;cursor:pointer;transition:background-color 140ms ease,color 140ms ease,transform 120ms var(--ease-out)}.project-row::before{content:none}.project-row::after{content:none}.project-row:hover{background:var(--sidebar-hover)}.project-row.selected{background:var(--sidebar-selected);box-shadow:inset 2px 0 0 var(--accent-solid)}.project-row-icon{display:grid;width:28px;height:28px;place-items:center;border-radius:8px;background:var(--surface-soft);color:var(--muted-strong)}.project-row-icon svg{width:15px;height:15px}.project-row.selected .project-row-icon{background:var(--accent-soft);color:var(--accent)}.project-row-main{min-width:0;display:grid;gap:3px;padding-top:1px}.project-row-heading{min-width:0;display:grid;grid-template-columns:minmax(0,1fr) auto;gap:7px;align-items:center}.project-row-title{overflow:hidden;font-size:.8rem;font-weight:620;letter-spacing:-.005em;text-overflow:ellipsis;white-space:nowrap}.project-row.selected .project-row-title{color:var(--text)}.project-row-id,.project-row-runner{display:none}.project-row-signals{min-width:0;display:flex;gap:4px;align-items:center}.project-row-signals:empty{display:none}.project-row-state{display:inline-flex;gap:4px;align-items:center;border-radius:999px;padding:3px 6px;background:var(--surface-soft);color:var(--muted-strong);font-size:.66rem;font-weight:650;line-height:1;white-space:nowrap}.project-row-state::before{content:"";width:5px;height:5px;flex:0 0 auto;border-radius:50%;background:currentColor;box-shadow:0 0 0 2px color-mix(in srgb,currentColor 12%,transparent)}.project-row-state.tone-runtime{background:var(--accent-soft);color:var(--accent)}.project-row-state.tone-warn{background:color-mix(in srgb,var(--warn) 10%,transparent);color:var(--warn)}.project-row-state.tone-fail{background:var(--danger-bg);color:var(--fail)}.project-row-meta{overflow:hidden;color:var(--muted);font-size:.7rem;line-height:1.4;text-overflow:ellipsis;white-space:nowrap}.workspace-path,.workspace-identity{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;overflow-wrap:anywhere}.sessions-panel{margin:4px 4px 10px 36px;padding:5px 0 2px 8px;border:0;border-left:1px solid var(--border-soft)}.sessions-panel .sidebar-section-head{margin:2px 0 5px;padding:0 8px}.sessions-panel .sidebar-section-head h2{font-size:.72rem}.session-list{overflow:visible;list-style:none;margin:0;padding:0}.session-list>li{margin:0;padding:0}.session-card{position:relative;min-width:0;display:grid;grid-template-columns:22px minmax(0,1fr);gap:8px;align-items:start;padding:8px;border:0;border-radius:8px;background:transparent;color:inherit;text-align:left;cursor:pointer;transition:background-color 140ms ease,color 140ms ease,transform 120ms var(--ease-out)}.session-card::before{content:none}.session-card::after{content:none}.session-card:hover{background:var(--sidebar-hover)}.session-card.selected{background:var(--sidebar-selected);box-shadow:none}.session-card-icon{display:grid;width:22px;height:22px;place-items:center;color:var(--placeholder)}.session-card-icon svg{width:14px;height:14px}.session-card.selected .session-card-icon{color:var(--accent)}.session-card-main{min-width:0}.session-title{display:-webkit-box;margin:0;overflow:hidden;font-size:.82rem;font-weight:500;line-height:1.35;overflow-wrap:anywhere;-webkit-box-orient:vertical;-webkit-line-clamp:4}.session-card .session-title{font-size:.78rem;line-height:1.42;-webkit-line-clamp:2}.session-card.selected .session-title{color:var(--text);font-weight:590}.session-card .chips{display:flex;gap:0;margin-top:4px}.session-card .chips .chip{border:0;padding:0;background:transparent;color:var(--muted);font-size:.68rem}.session-card .chips .chip + .chip::before{content:"·";margin:0 5px;color:var(--placeholder)}.summary-facts{margin-top:5px}.activity-preview{display:flex;gap:5px;margin-top:5px;overflow-wrap:anywhere}.activity-preview-label{flex:0 0 auto;font-weight:700}.empty-copy{margin:8px 40px}.recent-panel{margin:14px 4px 6px;padding:10px 4px 0;border-top:1px solid var(--border-soft)}.recent-panel-summary{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:6px 8px;border-radius:8px;color:var(--muted-strong);font-size:.74rem;font-weight:600;cursor:pointer;list-style:none;user-select:none;transition:background-color 140ms ease,color 140ms ease}.recent-panel-summary::-webkit-details-marker{display:none}.recent-panel-summary:hover{background:var(--sidebar-hover);color:var(--text)}.recent-panel-title{font-size:.74rem;font-weight:600;color:var(--muted-strong)}.recent-panel-meta{margin-left:auto;color:var(--placeholder);font-size:.68rem;font-weight:400}.recent-panel-summary::after{content:"›";display:inline-block;color:var(--placeholder);font-size:.95rem;line-height:1;transform:rotate(0deg);transition:transform 140ms var(--ease-out)}.recent-panel[open]>.recent-panel-summary::after{transform:rotate(90deg)}.recent-session-list{max-height:250px}.recent-session-row{appearance:none;width:100%;min-width:0;display:grid;gap:4px;padding:8px 10px;border:1px solid transparent;border-radius:11px;background:transparent;color:inherit;text-align:left;cursor:pointer}.recent-session-row:hover,.recent-session-row.selected{background:var(--sidebar-selected)}@media (hover:hover){.sidebar-view-item:hover,.project-row:hover,.session-card:hover,.recent-session-row:hover{background:var(--sidebar-hover)}}.project-row:active,.session-card:active,.recent-session-row:active{transform:scale(.985)}.recent-session-location{overflow-wrap:anywhere}.recent-session-signals{display:flex;flex-wrap:wrap;gap:5px}.sidebar-footer{display:flex;gap:10px;align-items:center;padding:0 18px;border-top:1px solid var(--border-soft);background:transparent;box-shadow:none}.local-avatar{display:grid;width:30px;height:30px;place-items:center;border:1px solid var(--border);border-radius:9px;background:var(--avatar);font-size:.72rem;font-weight:700;box-shadow:none}.sidebar-footer>span:last-child{display:grid;gap:1px;font-size:.72rem}.sidebar-footer small{color:var(--placeholder);font-size:.61rem}.workspace-main{position:relative;min-width:0;min-height:0;display:grid;grid-template-rows:var(--header-height) minmax(0,1fr);overflow:hidden;border:0;border-radius:0;background:var(--page-surface);box-shadow:none}.workspace-topbar{position:relative;z-index:40;min-width:0;display:flex;justify-content:space-between;gap:12px;align-items:center;overflow:visible;padding:0 18px 0 22px;border-bottom:1px solid var(--border-soft);background:var(--topbar);box-shadow:0 1px 0 color-mix(in srgb,var(--text) 2%,transparent);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur)}.workspace-heading{min-width:0;flex:1 1 auto;display:flex;gap:10px;align-items:center}.workspace-heading>svg{width:17px;height:17px;flex:0 0 auto;color:var(--muted-strong)}.workspace-heading-copy{min-width:0;display:grid;gap:2px}.workspace-breadcrumb{min-width:0;display:flex;gap:5px;align-items:center;overflow:hidden;color:var(--placeholder);font-size:.68rem;line-height:1}.workspace-breadcrumb span{min-width:0;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.workspace-breadcrumb i{color:var(--border);font-style:normal}.workspace-heading strong{max-width:min(760px,54vw);overflow:hidden;font-size:.94rem;font-weight:620;letter-spacing:-.012em;text-overflow:ellipsis;white-space:nowrap}.topbar-controls{min-width:0;display:flex;justify-content:flex-end;gap:7px;align-items:center;padding-right:42px}.topbar-more{position:relative;z-index:72}.topbar-more>summary{display:none;list-style:none}.topbar-more>summary::-webkit-details-marker{display:none}.topbar-more-popover{display:flex;gap:7px;align-items:center}.topbar-action-label{display:none}.session-state-chips{display:none}.runtime-has-session .session-state-chips{display:flex}.session-state-chips .chip:not(:last-child){display:none}.session-state-chips .chip{min-height:24px;border-color:var(--border-soft);background:var(--surface-soft);color:var(--muted)}.session-state-chips .chip:last-child{color:var(--muted-strong)}.banner{position:absolute;z-index:4;top:calc(var(--header-height) + 8px);right:18px;left:18px;margin:0;border:1px solid var(--danger-border);border-radius:12px;padding:9px 11px;background:var(--danger-bg);box-shadow:inset 0 1px 0 var(--glass-highlight);backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);font-size:.78rem}.conversation-stage{grid-row:2;min-height:0;position:relative;overflow:hidden}.conversation-empty{width:min(520px,calc(100% - 44px));height:100%;margin:0 auto;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding-top:clamp(88px,23.6dvh,220px);text-align:center}.conversation-empty h2{margin:17px 0 8px;font-size:1rem}.conversation-empty p{max-width:390px;margin-bottom:0;color:var(--muted);font-size:.82rem;line-height:1.55;text-wrap:balance}.empty-orbit{display:grid;width:56px;height:56px;place-items:center;border:1px solid var(--border);border-radius:16px;background:var(--surface-raised);color:var(--muted-strong);box-shadow:0 10px 28px rgba(0,0,0,.08)}.empty-orbit svg{width:24px;height:24px}.conversation-empty h2{margin-top:22px;font-size:clamp(1.35rem,3vw,1.8rem);font-weight:560;letter-spacing:-.03em}.conversation-empty p{max-width:470px;margin-top:4px;font-size:.84rem}.session-conversation{position:absolute;inset:0;min-height:0;display:grid;grid-template-rows:minmax(0,1fr) auto}.session-chat{position:relative;min-height:0;display:grid;grid-template-rows:auto auto minmax(0,1fr) auto}.chat-section-head,.unavailable-note,.collaboration-board,.chat-empty,.collaboration-composer{width:min(var(--content-width),calc(100% - var(--content-gutter) - var(--content-gutter)))}.chat-section-head{min-height:24px;margin:0 auto;display:flex;justify-content:flex-end;align-items:end;padding-top:8px}.chat-section-head>span{color:var(--placeholder);font-size:.68rem}#runtime-collaboration-status{display:none}.unavailable-note{margin:5px auto;padding:9px 11px;border:1px solid var(--border-soft);border-radius:12px;background:var(--surface-soft);box-shadow:inset 0 1px 0 var(--glass-highlight)}.chat-scroll{min-height:0;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--scrollbar) transparent}.collaboration-board{min-height:100%;margin:0 auto;display:flex;flex-direction:column;justify-content:flex-end;gap:0;padding:clamp(28px,3.8vh,44px) 0 clamp(44px,6vh,68px)}.chat-empty{min-height:100%;margin:0 auto;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding:clamp(72px,23.6dvh,190px) 0 48px;text-align:center}.chat-empty>span{margin-bottom:10px;color:var(--accent);font-size:1.2rem}.chat-empty strong{font-size:1rem;letter-spacing:-.01em}.chat-empty p{max-width:520px;margin:6px 0 0;line-height:1.55;text-wrap:balance}.chat-retention{display:none}.message-card{position:relative;min-width:0;max-width:100%;align-self:flex-start;display:grid;grid-template-columns:minmax(0,1fr);align-items:start;border:0;border-radius:0;padding:0;background:transparent}.message-card + .message-card{margin-top:28px}.message-card.message-incoming + .message-card.message-incoming{margin-top:17px}.message-card.message-neutral + .message-card.message-neutral{margin-top:17px}.message-card.message-outgoing + .message-card.message-outgoing{margin-top:13px}.message-card + .message-card.message-thread{margin-top:16px}.message-card.message-entering{animation:message-enter 240ms var(--ease-out)}@keyframes message-enter{from{opacity:0;transform:translateY(7px) scale(.992)}}.message-card.message-incoming{width:fit-content;max-width:min(82%,880px);align-self:flex-start}.message-card.message-neutral{width:fit-content;max-width:min(82%,880px);align-self:flex-start}.message-card.message-outgoing{width:fit-content;max-width:min(68%,680px);align-self:flex-end}.message-content{min-width:0;display:flex;flex-direction:column;align-items:flex-start}.message-card.message-outgoing .message-content{align-items:flex-end}.message-author{min-height:18px;display:flex;align-items:center;margin:0 2px 4px;color:var(--muted);font-size:.72rem}.message-author-name{font-weight:600}.message-card.message-outgoing .message-author{justify-content:flex-end}.message-card.message-group-continuation .message-author{display:none}.message-reply-context{max-width:100%;display:flex;gap:6px;align-items:center;margin:0 4px 7px;color:var(--placeholder);font-size:.7rem;line-height:1.4}.message-reply-context svg{width:12px;height:12px;flex:0 0 auto}.message-reply-context span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.message-card.message-outgoing .message-reply-context{justify-content:flex-end}.message-bubble{min-width:0;max-width:100%}.message-card.message-incoming .message-bubble{width:fit-content;border:0;border-radius:var(--message-bubble-radius);padding:clamp(11px,1.1vw,13px) clamp(16px,1.5vw,19px);background:var(--message-incoming-bg);color:var(--text);box-shadow:0 1px 1px rgba(0,0,0,.025)}.message-card.message-neutral .message-bubble{width:fit-content;border:0;border-radius:var(--message-bubble-radius);padding:clamp(11px,1.1vw,13px) clamp(16px,1.5vw,19px);background:var(--message-incoming-bg);color:var(--text);box-shadow:0 1px 1px rgba(0,0,0,.025)}.message-card.message-outgoing .message-bubble{align-self:flex-end;border:0;border-radius:var(--message-bubble-radius);padding:clamp(10px,1.1vw,12px) clamp(15px,1.5vw,18px);background:var(--message-outgoing-bg);color:var(--message-outgoing-text);box-shadow:0 1px 1px rgba(0,0,0,.055)}.message-footer{min-width:0;display:flex;flex-wrap:wrap;gap:5px 9px;align-items:center;margin-top:7px;color:var(--muted)}.message-card.message-outgoing .message-footer{width:100%;align-self:flex-end;justify-content:flex-end;padding:0 2px}.message-card.message-incoming .message-footer{justify-content:flex-start;padding:0 2px}.message-card.message-neutral .message-footer{justify-content:flex-start;padding:0 2px}.message-head{min-width:0;display:flex;flex:0 1 auto;justify-content:flex-start;gap:7px;align-items:center;color:var(--muted)}.message-card.message-outgoing .message-head{justify-content:flex-end}.message-kind{display:inline-flex;min-height:20px;align-items:center;border:1px solid var(--border-soft);border-radius:999px;padding:0 7px;background:var(--surface-soft);color:var(--muted);font-size:.68rem;font-weight:560}.message-head>.small{font-size:.7rem}.message-meta{display:none}.message-resolution{color:var(--muted);font-size:.7rem}.message-ack,.message-resolution{flex-basis:100%}.message-card.message-outgoing .message-ack,.message-card.message-outgoing .message-resolution{text-align:right}.message-card.message-outgoing .muted,.message-card.message-outgoing .message-resolution{color:var(--muted)}.message-body{position:relative;max-height:none;margin:0;overflow:visible;overflow-wrap:anywhere;font-size:.92rem;line-height:1.62}.message-body.is-collapsed{max-height:31rem;overflow:hidden;mask-image:linear-gradient(to bottom,#000 0,#000 calc(100% - 64px),transparent 100%)}.message-body.is-expanded{max-height:none;mask-image:none}.message-paragraph{margin:0;white-space:pre-wrap}.message-paragraph + .message-paragraph,.message-body>:not(:first-child){margin-top:.8em}.message-body ul,.message-body ol{margin-bottom:0;padding-left:1.4em}.message-body li + li{margin-top:.28em}.message-body blockquote{margin-right:0;margin-bottom:0;margin-left:0;padding-left:12px;border-left:2px solid color-mix(in srgb,currentColor 24%,transparent);color:var(--muted-strong)}.message-body blockquote .message-paragraph{margin:0}.message-heading{margin-bottom:0;color:inherit;font-size:1em;font-weight:680;letter-spacing:-.01em;text-transform:none}.message-body a{color:inherit;text-decoration-color:color-mix(in srgb,currentColor 46%,transparent);text-underline-offset:2px}.message-code{overflow:hidden;border:1px solid color-mix(in srgb,currentColor 11%,transparent);border-radius:13px;background:color-mix(in srgb,var(--page) 84%,transparent);color:var(--text)}.message-code>header{min-height:34px;display:flex;justify-content:space-between;gap:12px;align-items:center;padding:0 10px 0 12px;border-bottom:1px solid var(--border-soft);color:var(--muted);font:500 .7rem/1 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.message-code-copy{appearance:none;display:inline-flex;gap:6px;align-items:center;border:0;border-radius:7px;padding:5px 7px;background:transparent;color:var(--muted-strong);cursor:pointer;font:inherit}.message-code-copy:hover{background:var(--surface-soft);color:var(--text)}.message-code-copy svg{width:13px;height:13px}.message-code pre{max-width:100%;margin:0;overflow:auto;padding:13px 14px;scrollbar-width:thin}.message-code code{white-space:pre;font:500 .78rem/1.58 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.message-expand{appearance:none;margin-top:8px;border:0;border-radius:8px;padding:5px 8px;background:color-mix(in srgb,currentColor 8%,transparent);color:inherit;cursor:pointer;font-size:.72rem;font-weight:600}.message-ack{color:var(--warn);font-size:.7rem}.message-ack.observed{color:var(--muted)}.message-actions{display:flex;justify-content:flex-start;gap:2px;margin-left:auto;opacity:.58;transition:opacity 140ms ease}.message-card.message-outgoing .message-actions{justify-content:flex-end}.message-action{appearance:none;display:grid;width:26px;height:26px;place-items:center;border:0;border-radius:7px;background:transparent;color:var(--muted);cursor:pointer;transition:color 120ms ease,background-color 120ms ease,transform 120ms var(--ease-out)}.message-action svg{width:13px;height:13px}.message-action:hover{background:var(--surface-soft);color:var(--text)}.message-action.danger:hover{color:var(--fail)}.message-action:active{transform:scale(.94)}.message-card:hover .message-actions,.message-card:focus-within .message-actions{opacity:1}.message-thread{margin-left:0}.message-date-separator{width:100%;display:flex;align-items:center;gap:12px;margin:30px 0 22px;color:var(--placeholder);font-size:.7rem}.message-date-separator::before,.message-date-separator::after{content:"";height:1px;flex:1;background:var(--border-soft)}.new-messages-button{position:absolute;z-index:8;right:50%;bottom:12px;display:inline-flex;gap:7px;align-items:center;border:1px solid var(--border);border-radius:999px;padding:8px 12px;background:var(--surface);color:var(--muted-strong);box-shadow:var(--shadow-raised);cursor:pointer;transform:translateX(50%);animation:new-messages-enter 180ms var(--ease-out)}.new-messages-button svg{width:14px;height:14px}@keyframes new-messages-enter{from{opacity:0;transform:translate(50%,7px) scale(.96)}}.collaboration-composer{position:relative;isolation:isolate;margin:10px auto max(16px,env(safe-area-inset-bottom));padding:8px 9px 8px;border:1px solid var(--border);border-radius:24px;background:var(--composer);box-shadow:0 12px 34px rgba(5,7,12,.13),inset 0 1px 0 color-mix(in srgb,white 5%,transparent);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);transition:border-color 220ms ease,background-color 220ms ease,box-shadow 260ms var(--ease-out),transform 260ms var(--ease-out);animation:composer-enter 280ms var(--ease-out)}.collaboration-composer:focus-within{border-color:color-mix(in srgb,var(--accent) 34%,var(--border));box-shadow:0 18px 42px rgba(5,7,12,.17),0 0 0 3px color-mix(in srgb,var(--accent-soft) 72%,transparent);transform:translateY(-1px)}.collaboration-composer textarea{width:100%;height:44px;min-height:44px;max-height:180px;resize:none;overflow-y:hidden;border:0;outline:0;padding:10px 9px 7px;background:transparent;color:var(--text);font-size:.88rem;line-height:1.5}.collaboration-composer textarea::placeholder{color:var(--placeholder)}.collaboration-composer.is-unavailable{opacity:.7}.collaboration-composer.is-unavailable textarea{cursor:not-allowed}.composer-toolbar{min-height:38px;display:flex;justify-content:space-between;gap:10px;align-items:center}.composer-fields{min-width:0;display:flex;gap:8px;align-items:center}.composer-options{position:relative;z-index:12}.composer-options>summary{list-style:none}.composer-options>summary::-webkit-details-marker{display:none}.composer-tools-trigger{min-width:38px;height:36px;display:inline-flex;gap:7px;align-items:center;border-radius:999px;padding:0 11px 0 9px;color:var(--muted-strong);cursor:pointer;transition:color 160ms ease,background-color 160ms ease,transform 140ms var(--ease-out)}.composer-tools-trigger svg{width:18px;height:18px;transition:transform 190ms var(--ease-out)}.composer-tools-trigger span{max-width:210px;overflow:hidden;font-size:.67rem;font-weight:570;text-overflow:ellipsis;white-space:nowrap}.composer-options[open] .composer-tools-trigger,.composer-options.has-selection .composer-tools-trigger{background:var(--surface-soft);color:var(--text)}.composer-options.has-selection .composer-tools-trigger{color:var(--accent)}.composer-options[open] .composer-tools-trigger svg{transform:rotate(45deg)}.composer-options-popover{position:absolute;z-index:30;bottom:calc(100% + 12px);left:0;width:min(350px,calc(100vw - 40px));padding:12px;border:1px solid var(--border);border-radius:16px;background:var(--surface);box-shadow:var(--shadow-raised);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);transform-origin:bottom left;animation:composer-options-enter 180ms var(--ease-out)}.composer-options-head{display:grid;gap:2px;margin-bottom:10px;padding:0 2px}.composer-options-head strong{font-size:.76rem}.composer-options-head .small{font-size:.61rem}.composer-option-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.composer-control{min-width:0;display:grid;gap:5px;border:0;border-radius:10px;padding:8px 9px;background:var(--surface-soft);color:var(--placeholder);font-size:.61rem}.composer-control select{width:100%;height:28px;min-width:0;border:0;outline:0;padding:0;background:transparent;color:var(--text);font-size:.72rem;cursor:pointer}.composer-control:focus-within{box-shadow:0 0 0 2px var(--accent-soft)}.composer-check{grid-column:1 / -1;min-height:38px;display:flex;gap:8px;align-items:center;border-radius:10px;padding:0 10px;background:var(--surface-soft);color:var(--muted-strong);font-size:.68rem}.composer-fields input[type="checkbox"]{accent-color:var(--accent-solid)}.composer-actions{min-width:0;display:flex;justify-content:flex-end;align-items:center;gap:8px}.composer-actions>span{max-width:360px;overflow:hidden;text-align:right;line-height:1.3}.reply-target,.edit-target{display:flex;justify-content:space-between;gap:8px;align-items:center;margin:3px 3px 4px;padding:7px 9px;border:0;border-left:2px solid var(--accent);border-radius:0 9px 9px 0;background:var(--surface-soft);animation:composer-context-enter 180ms var(--ease-out)}.edit-target{border-left:3px solid var(--warn)}@keyframes composer-enter{from{opacity:0;transform:translateY(10px) scale(.992)}}@keyframes composer-options-enter{from{opacity:0;transform:translateY(6px) scale(.97)}}@keyframes composer-context-enter{from{opacity:0;transform:translateY(4px)}}.operations-stage{grid-row:2;min-width:0;min-height:0;overflow:hidden;background:var(--page-surface)}.operations-scroll{width:100%;height:100%;overflow-y:auto;padding:clamp(24px,3vw,44px) var(--content-gutter) 64px;scrollbar-width:thin;scrollbar-color:var(--scrollbar) transparent}.operations-heading{width:min(1440px,100%);margin:0 auto 22px;display:flex;justify-content:space-between;gap:24px;align-items:flex-start}.operations-heading h2{margin:1px 0 7px;font-size:clamp(1.35rem,2vw,1.75rem);font-weight:620;letter-spacing:-.035em}.operations-heading p:last-child{max-width:680px;margin-bottom:0;line-height:1.55}.operations-live{display:inline-flex;gap:7px;align-items:center;border:1px solid var(--border-soft);border-radius:999px;padding:7px 10px;background:var(--surface-soft);color:var(--muted-strong);font-size:.74rem;white-space:nowrap}.operations-layout{width:min(1440px,100%);margin:0 auto;display:grid;grid-template-columns:minmax(0,.82fr) minmax(0,1.18fr);gap:14px;align-items:start}.operations-card{min-width:0;scroll-margin-top:20px;border:1px solid var(--border-soft);border-radius:16px;padding:18px;background:color-mix(in srgb,var(--surface) 72%,transparent);box-shadow:0 1px 0 color-mix(in srgb,var(--text) 3%,transparent)}.operations-card:focus{outline:none}.operations-card:focus-visible{outline:2px solid var(--accent);outline-offset:3px}.operations-card-head{display:flex;justify-content:space-between;gap:16px;align-items:flex-start;margin-bottom:13px}.operations-card-head h3{margin:2px 0 0;font-size:.98rem;font-weight:630;letter-spacing:-.015em}.operations-card-head>.small{max-width:48%;text-align:right}.operations-agents{grid-column:1 / -1}.operations-metrics{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-top:0}.operations-metrics .metric{min-height:78px;grid-template-columns:1fr;gap:4px;align-content:center;border:0;border-radius:12px;padding:12px 13px;background:var(--surface-inset)}.operations-metrics .metric>.small{grid-column:1}.operations-metrics .metric strong{font-size:.88rem}.operations-runners .fleet-list{max-height:420px;margin-top:0}.operations-agents .communication-grid{grid-template-columns:minmax(300px,.85fr) minmax(360px,1.15fr);gap:12px}.operations-agents .communication-agents,.operations-agents .communication-conversations{align-content:start}.operations-agents .communication-section{border-radius:12px;padding:13px}.operations-agents .communication-list{max-height:320px}.operations-agents .conversation-list{max-height:280px}.operations-agents .conversation-transcript{max-height:520px}.runtime-shell[data-workspace-view="operations"] .runtime-inspector{display:none}.runtime-shell[data-workspace-view="operations"].context-docked{grid-template-columns:var(--sidebar-width) minmax(0,1fr)}.runtime-shell[data-workspace-view="operations"] .session-state-chips{display:none}.runtime-inspector{position:absolute;z-index:20;top:0;right:0}.runtime-inspector{display:none}.runtime-has-session .runtime-inspector{display:block}.runtime-operations-view .runtime-inspector{display:none}.runtime-shell[data-workspace-view="operations"] .topbar-controls,body:not(.runtime-has-session) .topbar-controls{padding-right:0}.context-trigger{position:absolute;z-index:23;top:16px;right:18px;display:grid;width:36px;height:36px;place-items:center;border:1px solid transparent;border-radius:9px;color:var(--muted);cursor:pointer;list-style:none;transition:color 140ms ease,background-color 140ms ease,border-color 140ms ease,transform 120ms var(--ease-out)}.context-trigger::-webkit-details-marker{display:none}.context-trigger:hover,.runtime-inspector[open] .context-trigger{border-color:var(--border);background:var(--sidebar-hover);color:var(--text);box-shadow:inset 0 1px 0 var(--glass-highlight)}.context-trigger svg{width:17px;height:17px}.inspector-backdrop{position:fixed;z-index:20;inset:0;border:0;background:color-mix(in srgb,var(--overlay) 78%,transparent);cursor:default}.inspector-popover{position:fixed;z-index:21;top:calc(var(--header-height) + 10px);right:10px;width:clamp(380px,var(--layout-minor),460px);max-width:calc(100vw - 20px);height:min(780px,calc(100dvh - var(--header-height) - 20px));display:grid;grid-template-rows:58px minmax(0,1fr);overflow:hidden;border:1px solid var(--border);border-radius:14px;background:var(--surface);box-shadow:var(--shadow-raised);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);transform-origin:top right;animation:inspector-enter 170ms var(--ease-out)}.inspector-backdrop{animation:inspector-backdrop-enter 160ms ease-out}@keyframes inspector-enter{from{opacity:0;transform:translateY(-4px) scale(.985)}}@keyframes inspector-backdrop-enter{from{opacity:0}}.inspector-header{display:flex;justify-content:space-between;gap:12px;align-items:center;padding:0 17px;border-bottom:1px solid var(--border-soft);background:transparent;box-shadow:none}.inspector-header>div:first-child{display:grid}.inspector-header strong{font-size:.86rem}.inspector-header-actions{display:flex;align-items:center;gap:8px}.inspector-close{display:grid;width:32px;height:32px;place-items:center;border:1px solid transparent;border-radius:8px;background:transparent;color:var(--muted-strong);cursor:pointer;transition:color 140ms ease,background-color 140ms ease,border-color 140ms ease}.inspector-close:hover{border-color:var(--border-soft);background:var(--sidebar-hover);color:var(--text)}.inspector-close svg{width:16px;height:16px}.live-pill{display:inline-flex;gap:6px;align-items:center;padding:5px 7px;border:1px solid var(--border);border-radius:999px;color:var(--muted-strong);font-size:.65rem}.inspector-scroll{min-height:0;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--scrollbar) transparent}.inspector-card{display:block;margin:0;padding:14px 16px;border:0;border-bottom:1px solid var(--border-soft);background:transparent}.inspector-card>summary{display:flex;justify-content:space-between;gap:9px;align-items:baseline;color:var(--muted-strong);font-size:.77rem;font-weight:680;cursor:pointer;list-style:none}.inspector-card>summary::-webkit-details-marker{display:none}.inspector-card>summary::before{content:"›";color:var(--muted)}.inspector-card[open]>summary::before{transform:rotate(90deg)}.inspector-card>summary>:nth-child(2){max-width:48%;overflow:hidden;text-align:right;text-overflow:ellipsis;white-space:nowrap}.inspector-card-head{display:flex;justify-content:space-between;gap:10px;align-items:baseline;margin-bottom:9px}.session-evidence{margin-top:11px;border-top:1px solid var(--border-soft)}.session-evidence>summary{min-height:38px;display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:8px;align-items:center;color:var(--muted-strong);font-size:.7rem;font-weight:620;cursor:pointer;list-style:none}.session-evidence>summary::-webkit-details-marker{display:none}.session-evidence>summary::before{content:"›";color:var(--muted);transition:transform 140ms var(--ease-out)}.session-evidence[open]>summary::before{transform:rotate(90deg)}.session-evidence>summary>:last-child{overflow:hidden;color:var(--placeholder);font-weight:450;text-align:right;text-overflow:ellipsis;white-space:nowrap}.session-evidence-body{padding-top:1px}.session-identity{display:grid;grid-template-columns:1fr;gap:7px;margin:8px 0;padding:10px;border:1px solid var(--border-soft);border-radius:10px;background:var(--surface-inset);box-shadow:none}.session-identity-fact{min-width:0;display:grid;gap:2px}.session-identity-value{overflow-wrap:anywhere}.session-identity code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.69rem;user-select:all}.workspace-identity{margin:8px 0;font-size:.68rem}.overview{display:grid;grid-template-columns:1fr;gap:6px;margin:11px 0}.context-primary-overview{margin-bottom:0}.context-secondary-overview{margin-top:8px}.overview-card{min-width:0;padding:9px 10px;border:1px solid var(--border-soft);border-left:3px solid var(--border);border-radius:9px;background:var(--surface-inset);box-shadow:none}.overview-card p{margin-bottom:0;overflow-wrap:anywhere;font-size:.75rem;line-height:1.4}.runtime-fact{border-left-color:var(--accent)}.reported-card{border-left-color:var(--muted);opacity:.84}.tone-card-pass{border-left-color:var(--pass)}.tone-card-warn{border-left-color:var(--warn)}.tone-card-fail{border-left-color:var(--fail)}.tone-card-muted{border-left-color:var(--muted)}.activity-section{margin-top:13px;padding-top:12px;border-top:1px solid var(--border-soft)}.timeline-controls{justify-content:space-between;margin-bottom:7px;font-size:.78rem}.timeline{display:grid;gap:6px;max-height:300px;overflow:auto;list-style:none;margin:0;padding:0}.timeline-event{padding:8px 9px;border:1px solid var(--border-soft);border-left:3px solid var(--border);border-radius:10px;background:var(--surface-inset)}.timeline-event.failed{border-left-color:var(--fail)}.timeline-event.reported-progress{border-left-color:var(--muted);opacity:.82}.timeline-head{display:flex;justify-content:space-between;gap:8px;align-items:baseline}.timeline-kind{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.7rem}.timeline-body{margin-top:4px;overflow-wrap:anywhere}.metric-grid{display:grid;grid-template-columns:1fr;gap:5px;margin-top:11px}.metric{min-width:0;display:grid;grid-template-columns:minmax(72px,.7fr) minmax(0,1.3fr);gap:3px 7px;align-items:baseline;padding:8px 9px;border:1px solid var(--border-soft);border-radius:10px;background:var(--surface-inset)}.metric strong,.metric span{overflow-wrap:anywhere}.metric strong{font-size:.74rem}.metric>.small{grid-column:2}.metric-label{color:var(--muted);font-size:.63rem;letter-spacing:.05em;text-transform:uppercase}.fleet-list{max-height:330px;margin-top:10px}.fleet-row{appearance:none;width:100%;min-width:0;display:grid;gap:6px;padding:10px;border:1px solid var(--border-soft);border-radius:11px;background:var(--surface-inset);color:inherit;text-align:left;cursor:pointer}.fleet-row.selected{border-color:var(--accent-border);background:var(--accent-soft)}.fleet-row-main,.fleet-row-signals,.fleet-row-facts{min-width:0}.fleet-row-title{overflow-wrap:anywhere;font-size:.76rem;font-weight:700}.fleet-row-meta,.fleet-row-facts{overflow-wrap:anywhere}.fleet-row-signals{display:flex;flex-wrap:wrap;gap:5px}.retention-note{margin:9px 0 0}.communication-grid{display:grid;grid-template-columns:1fr;gap:9px;margin-top:10px}.communication-agents,.communication-conversations{min-width:0;display:grid;gap:9px}.communication-section{min-width:0;padding:10px;border:1px solid var(--border-soft);border-radius:10px;background:var(--surface-inset);box-shadow:none}.communication-section h3{margin-bottom:8px;font-size:.76rem}.stack-form{display:grid;gap:7px;margin-bottom:9px}.stack-form>label,.compact-field-grid>label{display:grid;gap:3px;color:var(--muted);font-size:.68rem}.stack-form input,.stack-form textarea{width:100%;min-width:0;padding:8px 9px;border:1px solid var(--border);border-radius:10px;resize:vertical;background:var(--input);color:var(--text)}.stack-form>label.inline-choice{display:flex;grid-template-columns:none;flex-direction:row;align-items:center;gap:7px}.stack-form>label.inline-choice input{width:auto}.compact-field-grid{display:grid;grid-template-columns:1fr;gap:7px}.form-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:7px}.form-actions .muted{margin-right:auto}.communication-list{max-height:260px}.communication-row{appearance:none;width:100%;min-width:0;padding:9px;border:1px solid var(--border-soft);border-radius:10px;background:var(--surface);color:var(--text);text-align:left;cursor:pointer}.communication-row.selected{border-color:var(--accent);box-shadow:inset 2px 0 0 var(--accent)}.communication-row-head,.conversation-message-head{display:flex;justify-content:space-between;gap:7px;align-items:baseline}.communication-row-title,.conversation-message-author{overflow-wrap:anywhere;font-size:.74rem;font-weight:680}.communication-row-meta,.communication-id,.conversation-message-meta,.conversation-message-deliveries{display:block;color:var(--muted);font-size:.66rem;overflow-wrap:anywhere}.communication-id{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;user-select:all}.communication-description{margin:8px 0;white-space:pre-wrap;overflow-wrap:anywhere}.card-edit-form{border-top:1px solid var(--border);padding-top:9px;margin-top:9px}.communication-participants{margin:8px 0}.conversation-list{max-height:220px}.conversation-transcript{min-height:120px;max-height:430px;display:grid;gap:7px;overflow:auto;margin:9px 0}.conversation-message{min-width:0;padding:9px;border:1px solid var(--border-soft);border-left:3px solid var(--accent);border-radius:10px;background:var(--surface)}.conversation-message.agent-authored{border-left-color:var(--pass)}.conversation-message-body,.inbox-message-preview{margin-top:5px;white-space:pre-wrap;overflow-wrap:anywhere}.inbox-message-preview{max-height:6rem;overflow:auto}.inbox-delivery{cursor:default}.conversation-composer{margin:9px 0 0;padding-top:9px;border-top:1px solid var(--border-soft)}.section-head{justify-content:space-between}@media (min-width:1600px){.runtime-shell.context-docked{--content-width:1160px;grid-template-columns:var(--sidebar-width) minmax(0,1fr) var(--context-rail-width)}.runtime-shell.context-docked .runtime-inspector{position:relative;z-index:10;top:auto;right:auto;grid-column:3;grid-row:1;min-width:0;height:100dvh;overflow:hidden;border-left:1px solid var(--border-soft);background:var(--sidebar)}.runtime-shell.context-docked .context-trigger,.runtime-shell.context-docked .inspector-backdrop{display:none !important}.runtime-shell.context-docked .topbar-controls{padding-right:0}.runtime-shell.context-docked .inspector-popover{position:relative;top:auto;right:auto;width:100%;max-width:none;height:100dvh;border:0;border-radius:0;background:transparent;box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none;animation:none}.runtime-shell.context-docked .inspector-header{min-height:var(--header-height);padding:0 18px}}@media (max-width:1180px){.workspace-heading strong{max-width:min(620px,44vw)}.runtime-has-session .session-state-chips{display:flex}.operations-layout{grid-template-columns:1fr}.operations-agents{grid-column:1}}@media (hover:hover) and (pointer:fine){.message-actions{opacity:0}}@media (max-width:900px){:root{--header-height:calc(58px + env(safe-area-inset-top));--content-gutter:clamp(16px,3vw,24px)}.runtime-shell{grid-template-columns:minmax(0,1fr);gap:0;padding:0}.workspace-sidebar{position:fixed;z-index:60;inset:0 auto 0 0;width:min(88vw,360px);height:100dvh;visibility:hidden;border-width:0 1px 0 0;border-radius:0;background:var(--sidebar-drawer);box-shadow:20px 0 54px rgba(6,11,20,.28);transform:translateX(-102%);transition:transform 240ms var(--ease-drawer),visibility 240ms}.mobile-nav-backdrop{z-index:59}.runtime-shell.mobile-nav-open .workspace-sidebar{visibility:visible;transform:translateX(0)}.runtime-shell.mobile-nav-open .mobile-nav-backdrop{visibility:visible;opacity:1;pointer-events:auto}.mobile-nav-control{display:grid}.mobile-nav-toggle{margin-left:-5px}.sidebar-brand{padding-top:env(safe-area-inset-top)}.workspace-main{width:100%;height:100dvh;border:0;border-radius:0;box-shadow:none}.workspace-topbar{padding:env(safe-area-inset-top) max(12px,env(safe-area-inset-right)) 0 max(12px,env(safe-area-inset-left))}.workspace-heading strong{max-width:min(600px,58vw)}.topbar-controls{flex:0 0 auto;padding-right:46px}#runtime-refresh-status{display:none}.sidebar-scroll{padding-bottom:max(18px,env(safe-area-inset-bottom));overscroll-behavior:contain}.sidebar-footer{padding-bottom:env(safe-area-inset-bottom)}.runtime-inspector{z-index:50}.context-trigger{z-index:53;top:calc(9px + env(safe-area-inset-top));right:max(9px,env(safe-area-inset-right));width:40px;height:40px;border-radius:12px}.inspector-backdrop{z-index:49;background:var(--overlay)}.inspector-close{width:36px;height:36px}.inspector-close svg{width:18px;height:18px}.inspector-popover{z-index:51;top:var(--header-height);right:0;width:100vw;height:calc(100dvh - var(--header-height));border-right:0;border-bottom:0;border-left:0;border-radius:16px 16px 0 0;transform-origin:bottom center;animation-name:inspector-sheet-enter}.inspector-scroll{padding-bottom:env(safe-area-inset-bottom)}.operations-scroll{padding:24px max(18px,env(safe-area-inset-right)) max(48px,env(safe-area-inset-bottom)) max(18px,env(safe-area-inset-left))}.operations-agents .communication-grid{grid-template-columns:1fr}@keyframes inspector-sheet-enter{from{opacity:0;transform:translateY(14px)}}}@media (max-width:600px){:root{--header-height:calc(56px + env(safe-area-inset-top))}.auth-topbar{width:calc(100% - 28px);padding-top:max(24px,5vh)}.auth-topbar{gap:10px}.brand-lockup{align-items:flex-start}.brand-lockup h1{font-size:1.08rem}.brand-lockup p{font-size:.75rem;line-height:1.4}.gate{width:calc(100% - 28px);margin-top:20px;padding:21px;border-radius:20px}.gate h2{font-size:1.05rem}.gate>form>.muted{margin-bottom:16px;font-size:.79rem}.field-row{align-items:stretch;flex-direction:column}.field-row input,.field-row .btn{width:100%;min-height:44px}.workspace-sidebar{width:min(94vw,360px);grid-template-rows:var(--header-height) auto minmax(0,1fr) 58px}.sidebar-brand{padding:0 14px 0 16px}.sidebar-primary-row{padding:0 16px}.sidebar-scroll{padding-top:18px}.workspace-topbar{gap:6px;padding:env(safe-area-inset-top) max(8px,env(safe-area-inset-right)) 0 max(8px,env(safe-area-inset-left))}.workspace-heading{gap:7px}.workspace-heading>svg{display:none}.workspace-breadcrumb{display:none}.workspace-heading strong{max-width:none;font-size:.82rem}.topbar-controls{gap:3px;padding-right:43px}.session-state-chips{display:none !important}.topbar-more>summary{display:grid;width:40px;height:40px;place-items:center}.topbar-more:not([open])>.topbar-more-popover{display:none}.topbar-more-popover{position:absolute;z-index:95;top:calc(100% + 8px);right:0;width:210px;display:grid;gap:3px;padding:8px;border:1px solid var(--border);border-radius:14px;background:var(--surface);box-shadow:var(--shadow-raised);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);animation:theme-menu-enter 160ms var(--ease-out)}.topbar-more-popover>.icon-btn,.topbar-more-popover>.lock-button,.topbar-more-popover>.theme-menu>.theme-trigger{width:100%;height:40px;min-height:40px;display:grid;grid-template-columns:22px minmax(0,1fr);gap:9px;place-items:center start;border:0;padding:0 10px;background:transparent}.topbar-more-popover>.language-toggle{grid-template-columns:22px minmax(0,1fr)}.topbar-more-popover>.language-toggle>span:first-child{min-width:0;justify-self:center}.topbar-more-popover .topbar-action-label,.topbar-more-popover .lock-button span{display:block;color:var(--muted-strong);font-size:.78rem;font-weight:550}.topbar-more-popover .lock-button svg{display:block;width:17px;height:17px}.topbar-more-popover>.theme-menu{width:100%}.topbar-more-popover>.theme-menu .theme-popover{position:static;width:100%;margin-top:3px;border-color:var(--border-soft);box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none}.banner{top:calc(var(--header-height) + 7px);right:12px;left:12px;font-size:.72rem}.chat-section-head{min-height:28px;padding-top:6px}.chat-section-head,.collaboration-board,.chat-empty,.unavailable-note,.collaboration-composer{width:calc(100% - 24px)}.unavailable-note{margin-top:8px;padding:7px 9px;font-size:.68rem;line-height:1.4}.collaboration-board{gap:0;padding:26px 0 30px}.chat-empty{padding:0 14px 8vh}.chat-empty strong{font-size:.95rem}.chat-empty p{max-width:330px;font-size:.72rem}.message-card + .message-card{margin-top:21px}.message-card.message-incoming + .message-card.message-incoming{margin-top:13px}.message-card.message-neutral + .message-card.message-neutral{margin-top:13px}.message-card.message-outgoing + .message-card.message-outgoing{margin-top:10px}.message-card + .message-card.message-thread{margin-top:9px}.message-card.message-incoming,.message-card.message-neutral,.message-card.message-outgoing{max-width:90%}.message-card.message-incoming .message-bubble,.message-card.message-neutral .message-bubble,.message-card.message-outgoing .message-bubble{padding:10px 14px}.message-footer{gap:3px 8px;margin-top:6px}.message-body{font-size:.9rem}.collaboration-composer{margin:7px auto max(10px,env(safe-area-inset-bottom));padding:7px 8px;border-radius:22px}.collaboration-composer textarea{min-height:44px;padding:10px 8px 7px;font-size:.85rem}.composer-toolbar{gap:6px;align-items:center}.composer-fields{gap:3px}.composer-tools-trigger{padding-right:9px}.composer-options-popover{width:min(340px,calc(100vw - 32px))}.composer-control{padding:8px}.composer-check{font-size:.64rem}.composer-actions{gap:5px}.composer-actions>span{max-width:140px;font-size:.7rem;text-align:right}.send-btn{width:38px;height:38px}.conversation-empty{width:calc(100% - 32px)}.conversation-empty{padding-top:clamp(72px,18vh,150px)}.conversation-empty p{margin-bottom:0;font-size:.76rem}.empty-orbit{width:44px;height:44px}.inspector-header{height:58px;padding:0 16px}.inspector-card{padding:15px 16px}.communication-section{padding:10px}.compact-field-grid{grid-template-columns:1fr}.operations-heading{align-items:flex-start;flex-direction:column;margin-bottom:17px}.operations-live{align-self:flex-start}.operations-card{padding:15px;border-radius:14px}.operations-card-head{gap:10px}.operations-metrics{grid-template-columns:1fr}}@media (max-width:380px){.workspace-sidebar{width:100vw;border-radius:0}.sidebar-runtime-status span{display:none}.workspace-heading strong{font-size:.78rem}.topbar-controls{padding-right:41px}.topbar-controls .language-toggle{width:36px;min-width:36px}.collaboration-composer{width:calc(100% - 16px)}.unavailable-note,.chat-section-head,.collaboration-board,.chat-empty{width:calc(100% - 20px)}.composer-actions>span{max-width:72px}.message-card.message-incoming,.message-card.message-neutral,.message-card.message-outgoing{max-width:94%}.message-thread{margin-left:16px}}@media (max-height:620px){.auth-topbar{padding-top:18px}.gate{margin-top:14px;padding-top:18px;padding-bottom:18px}.gate-icon{width:36px;height:36px;margin-bottom:12px}.chat-section-head{min-height:22px;padding-top:2px}.collaboration-composer textarea{min-height:40px}.chat-empty{padding-bottom:3vh}}@media (pointer:coarse){.project-row,.session-card,.recent-session-row{min-height:44px}.context-trigger,.icon-btn,.send-btn,.mobile-nav-control,.inspector-close{min-width:44px;min-height:44px}.runner-filter select,.sidebar-search input,.sidebar-view-item,.operations-nav-item{min-height:44px}.message-action{width:44px;height:44px}.recent-panel-summary{min-height:44px;align-items:center}.message-actions{opacity:1}}@media (prefers-reduced-transparency:reduce){.workspace-topbar,.collaboration-composer,.composer-options-popover,.inspector-popover,.theme-popover{background:var(--surface-solid);backdrop-filter:none;-webkit-backdrop-filter:none}}@media (prefers-contrast:more){:root{--border:color-mix(in srgb,var(--text) 34%,transparent);--border-soft:color-mix(in srgb,var(--text) 20%,transparent)}.workspace-topbar,.collaboration-composer,.composer-options-popover,.inspector-popover,.theme-popover{background:var(--surface-solid)}}@supports not ((backdrop-filter:blur(2px)) or (-webkit-backdrop-filter:blur(2px))){.workspace-sidebar,.workspace-main,.gate,.composer-options-popover,.inspector-popover,.theme-popover{background:var(--surface-solid)}.collaboration-composer{background:var(--surface-solid)}}@media (forced-colors:active){body{background:Canvas}.workspace-sidebar,.workspace-main,.gate,.composer-options-popover,.inspector-popover,.theme-popover,.collaboration-composer{background:Canvas;box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none}.project-row.selected,.session-card.selected,.theme-option[aria-pressed="true"]{outline:2px solid Highlight;outline-offset:-2px}}@media (prefers-reduced-motion:reduce){*,*::before,*::after{scroll-behavior:auto !important;animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important}} +:root{font-family:-apple-system,BlinkMacSystemFont,"SF Pro Text","SF Pro Display","PingFang SC","Microsoft YaHei",Inter,ui-sans-serif,system-ui,"Segoe UI",sans-serif;color-scheme:dark;--page:#090a0d;--page-end:#090a0d;--page-surface:#0c0e12;--sidebar:#111318;--sidebar-drawer:#111318;--topbar:rgba(12,14,18,.84);--sidebar-hover:rgba(255,255,255,.048);--sidebar-selected:rgba(117,126,232,.13);--composer:rgba(20,22,28,.9);--surface:rgba(22,24,30,.97);--surface-solid:#16181e;--surface-soft:rgba(255,255,255,.05);--surface-raised:#181a20;--surface-inset:rgba(255,255,255,.035);--input:rgba(255,255,255,.052);--text:#f2f3f5;--muted:#91969f;--muted-strong:#c7cad0;--placeholder:#737984;--border:rgba(255,255,255,.105);--border-soft:rgba(255,255,255,.065);--glass-highlight:transparent;--glass-sheen:transparent;--glass-glow:transparent;--glass-edge:var(--border);--message-incoming-bg:rgba(255,255,255,.055);--message-incoming-border:rgba(255,255,255,.075);--message-outgoing-bg:#285487;--message-outgoing-border:rgba(132,178,235,.2);--message-outgoing-text:#f8faff;--message-bubble-radius:22px;--accent:#9ba4ff;--accent-soft:rgba(112,122,225,.16);--accent-border:rgba(143,152,244,.46);--accent-solid:#6571d6;--accent-hover:#7681e4;--pass:#4bd38a;--warn:#f0ae5c;--fail:#ff7e82;--danger-bg:rgba(255,104,110,.1);--danger-border:rgba(255,118,123,.34);--overlay:rgba(5,7,11,.58);--scrollbar:rgba(184,193,207,.28);--avatar:rgba(255,255,255,.15);--send-bg:#f6f8fc;--send-text:#151922;--ambient-one:transparent;--ambient-two:transparent;--ambient-three:transparent;--layout-major:61.8%;--layout-minor:38.2%;--layout-tertiary:23.6%;--sidebar-width:clamp(300px,21vw,356px);--context-rail-width:clamp(320px,18vw,360px);--header-height:68px;--content-width:1120px;--content-gutter:clamp(20px,3vw,56px);--ease-out:cubic-bezier(.23,1,.32,1);--ease-drawer:cubic-bezier(.32,.72,0,1);--glass-blur:blur(14px) saturate(120%);--shadow-window:none;--shadow-raised:0 20px 60px rgba(0,0,0,.42)}:root[data-resolved-theme="light"]{color-scheme:light;--page:#f4f4f1;--page-end:#f4f4f1;--page-surface:#fafaf8;--sidebar:#efefec;--sidebar-drawer:#f4f4f1;--topbar:rgba(250,250,248,.86);--sidebar-hover:rgba(30,31,35,.045);--sidebar-selected:rgba(83,96,189,.095);--composer:rgba(255,255,253,.92);--surface:rgba(255,255,253,.97);--surface-solid:#fffffd;--surface-soft:rgba(27,29,35,.045);--surface-raised:#fffffd;--surface-inset:rgba(27,29,35,.035);--input:rgba(27,29,35,.045);--text:#202126;--muted:#737780;--muted-strong:#4e525b;--placeholder:#90949c;--border:rgba(30,31,35,.115);--border-soft:rgba(30,31,35,.07);--glass-highlight:transparent;--glass-sheen:transparent;--glass-glow:transparent;--glass-edge:var(--border);--message-incoming-bg:rgba(25,32,45,.055);--message-incoming-border:rgba(25,32,45,.065);--message-outgoing-bg:#2866a8;--message-outgoing-border:rgba(24,73,135,.2);--message-outgoing-text:#ffffff;--accent:#4f5eba;--accent-soft:rgba(83,96,189,.105);--accent-border:rgba(83,96,189,.34);--accent-solid:#5967c4;--accent-hover:#4d5bb6;--pass:#188659;--warn:#af680e;--fail:#d84d53;--danger-bg:rgba(216,77,83,.08);--danger-border:rgba(216,77,83,.26);--overlay:rgba(37,45,59,.24);--scrollbar:rgba(74,86,105,.25);--avatar:rgba(45,60,83,.12);--send-bg:#2875e5;--send-text:#fff;--ambient-one:transparent;--ambient-two:transparent;--ambient-three:transparent;--glass-blur:blur(14px) saturate(115%);--shadow-window:none;--shadow-raised:0 22px 60px rgba(45,52,68,.18)}*{box-sizing:border-box}[hidden]{display:none !important}html,body{width:100%;height:100%;background:var(--page)}html{-webkit-text-size-adjust:100%;text-size-adjust:100%}body{margin:0;overflow:hidden;overscroll-behavior:none;background:var(--page);color:var(--text);font-feature-settings:"kern" 1,"liga" 1;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}button,input,select,textarea{font:inherit}button,summary,[role="option"]{-webkit-tap-highlight-color:transparent}button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,summary:focus-visible,[role="option"]:focus-visible{outline:2px solid var(--accent);outline-offset:2px}::selection{background:var(--accent-border);color:var(--text)}svg{display:block;fill:none;stroke:currentColor;stroke-width:1.65;stroke-linecap:round;stroke-linejoin:round}h1,h2,h3,h4,p{margin-top:0}h1{margin-bottom:3px;font-size:1.35rem}h2{margin-bottom:0;font-size:.95rem}h3{margin-bottom:8px;font-size:.86rem}h4{margin-bottom:5px;color:var(--muted);font-size:.7rem;letter-spacing:.065em;text-transform:uppercase}.muted{color:var(--muted)}.small{font-size:.78rem;line-height:1.45}.error{color:var(--fail)}.eyebrow{margin-bottom:3px;color:var(--muted);font-size:.69rem;font-weight:700;letter-spacing:.075em;text-transform:uppercase}.visually-hidden{position:absolute !important;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}#runtime-page{width:100%;height:100%}.runtime-shell{position:relative;width:100%;height:100dvh;display:grid;grid-template-columns:var(--sidebar-width) minmax(0,1fr);gap:0;padding:0;background:transparent}.auth-topbar{position:relative;z-index:40;width:min(760px,calc(100% - 40px));margin:0 auto;padding-top:max(40px,8vh);display:flex;justify-content:space-between;gap:20px;align-items:center}.runtime-connected .auth-topbar{display:none}.auth-preferences{display:flex;flex:0 0 auto;gap:7px;align-items:center}.brand-lockup{display:flex;align-items:center;gap:13px}.brand-lockup p{margin-bottom:0}.brand-mark{display:grid;width:40px;height:40px;place-items:center;border:1px solid var(--border);border-radius:11px;background:var(--surface-raised);color:var(--text);font-weight:800;box-shadow:none}.gate{width:min(660px,calc(100% - 40px));margin:32px auto 0;padding:30px;border:1px solid var(--border);border-radius:18px;background:var(--surface);box-shadow:var(--shadow-raised)}.gate h2{margin-bottom:9px;font-size:1.15rem}.gate>form>.muted{margin-bottom:20px;line-height:1.55}.gate-icon{display:grid;width:42px;height:42px;margin-bottom:18px;place-items:center;border:1px solid var(--border);border-radius:12px;background:var(--surface-soft);color:var(--muted-strong)}.gate-icon svg{width:21px;height:21px}.field-row{display:flex;gap:9px;align-items:center}.field-row input{flex:1;min-width:0;height:46px;border:1px solid var(--border);border-radius:10px;padding:0 14px;background:var(--input);color:var(--text);box-shadow:none}.remember-credential{display:flex;gap:7px;align-items:center;margin-top:11px;color:var(--muted);font-size:.72rem}.remember-credential input{accent-color:var(--accent-solid)}#runtime-token-error{min-height:1.2em;margin:9px 0 0;font-size:.8rem}.btn,.icon-btn,.send-btn{border:1px solid var(--border);background:var(--surface-soft);color:var(--text);cursor:pointer;box-shadow:none}.btn,.icon-btn,.send-btn,.mobile-nav-control,.text-button{transition:color 150ms ease,background-color 150ms ease,border-color 150ms ease,opacity 150ms ease,transform 150ms var(--ease-out)}.btn{min-height:36px;border-radius:9px;padding:6px 12px}.btn.primary{border-color:var(--accent-solid);background:var(--accent-solid);color:#fff;box-shadow:none}.btn.subtle{color:var(--muted-strong)}.btn:disabled,.icon-btn:disabled,.send-btn:disabled{cursor:not-allowed;opacity:.5}.icon-btn{display:grid;width:36px;height:36px;place-items:center;border-radius:9px}.icon-btn svg{width:17px;height:17px}.icon-btn.is-busy svg{animation:runtime-spin .8s linear infinite}.send-btn{display:grid;width:36px;height:36px;flex:0 0 auto;place-items:center;border:1px solid transparent;border-radius:999px;background:var(--surface-soft);color:var(--muted);box-shadow:none}.send-btn.is-ready{background:var(--send-bg);color:var(--send-text);animation:send-ready 180ms var(--ease-out)}.send-btn svg{width:17px;height:17px}.text-button{appearance:none;border:0;padding:2px 4px;background:transparent;color:var(--accent);cursor:pointer;font:inherit}.lock-button{display:inline-flex;gap:6px;align-items:center}.lock-button svg{display:none;width:17px;height:17px}@keyframes runtime-spin{to{transform:rotate(360deg)}}@keyframes send-ready{from{transform:scale(.88)}}@media (hover:hover){.btn:hover,.icon-btn:hover,.mobile-nav-control:hover{background:var(--sidebar-hover)}.btn.primary:hover{background:var(--accent-hover)}.send-btn.is-ready:hover{filter:brightness(1.06);transform:scale(1.04)}.text-button:hover{color:var(--accent-hover)}}.btn:active,.icon-btn:active,.send-btn:active,.mobile-nav-control:active,.text-button:active{transform:scale(.97)}.send-btn.is-ready:active{transform:scale(.94)}.topbar-controls,.chips,.summary-facts,.section-head,.timeline-controls{display:flex;gap:7px;align-items:center}.chips,.summary-facts{flex-wrap:wrap}.chip,.count-badge{display:inline-flex;align-items:center;border:1px solid var(--border);border-radius:999px;color:var(--muted-strong);font-size:.67rem;line-height:1}.chip{padding:4px 8px}.count-badge{min-width:22px;justify-content:center;padding:4px 6px;background:var(--surface-soft)}.tone-runtime{border-color:rgba(132,174,248,.55);color:var(--accent)}.tone-pass{border-color:rgba(71,199,125,.55);color:var(--pass)}.tone-warn{border-color:rgba(239,169,85,.55);color:var(--warn)}.tone-fail{border-color:rgba(242,115,115,.55);color:var(--fail)}.theme-menu{position:relative;z-index:70;flex:0 0 auto}.theme-menu>summary{list-style:none}.theme-menu>summary::-webkit-details-marker{display:none}.theme-trigger{color:var(--muted-strong)}.theme-menu[open] .theme-trigger{border-color:var(--accent-border);background:var(--accent-soft);color:var(--accent)}.theme-icon{display:none}:root[data-theme="system"] .theme-icon-system,:root[data-theme="light"] .theme-icon-light,:root[data-theme="dark"] .theme-icon-dark{display:block}.theme-popover{position:absolute;z-index:90;top:calc(100% + 9px);right:0;width:184px;padding:8px;border:1px solid var(--border);border-radius:13px;background:var(--surface);box-shadow:var(--shadow-raised);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);transform-origin:top right;animation:theme-menu-enter 160ms var(--ease-out);pointer-events:auto}.theme-popover-label{display:block;padding:5px 9px 7px;color:var(--muted);font-size:.62rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.theme-option{appearance:none;width:100%;min-height:38px;display:grid;grid-template-columns:18px minmax(0,1fr) 8px;gap:9px;align-items:center;border:0;border-radius:10px;padding:0 9px;background:transparent;color:var(--muted-strong);text-align:left;cursor:pointer}.theme-option svg{width:17px;height:17px}.theme-option span{font-size:.76rem;font-weight:590}.theme-option i{width:7px;height:7px;border-radius:50%;background:transparent;box-shadow:0 0 0 3px transparent}.language-toggle{flex:0 0 auto;color:var(--muted-strong)}.language-toggle span{display:block;min-width:1.35em;font-size:.68rem;font-weight:760;letter-spacing:.015em;line-height:1}:root[data-language="zh-CN"] .language-toggle span{font-size:.64rem;letter-spacing:.035em}.theme-option[aria-pressed="true"]{background:var(--accent-soft);color:var(--text)}.theme-option[aria-pressed="true"] i{background:var(--accent-solid);box-shadow:0 0 0 3px var(--accent-soft)}@media (hover:hover){.theme-option:hover{background:var(--sidebar-hover);color:var(--text)}}@keyframes theme-menu-enter{from{opacity:0;transform:translateY(-5px) scale(.97)}}.workspace-sidebar{min-width:0;min-height:0;display:grid;grid-template-rows:var(--header-height) auto minmax(0,1fr) 60px;overflow:hidden;border:0;border-right:1px solid var(--border-soft);border-radius:0;background:var(--sidebar);box-shadow:none}.sidebar-brand{display:flex;justify-content:space-between;align-items:center;padding:0 16px}.sidebar-brand-lockup,.sidebar-brand-tools,.sidebar-runtime-status{display:flex;align-items:center}.sidebar-brand-lockup{min-width:0;gap:10px}.sidebar-brand-lockup strong{overflow:hidden;font-size:.96rem;font-weight:650;letter-spacing:-.025em;text-overflow:ellipsis;white-space:nowrap}.sidebar-logo{display:grid;width:30px;height:30px;flex:0 0 auto;place-items:center;border:1px solid color-mix(in srgb,var(--text) 10%,transparent);border-radius:9px;background:var(--text);color:var(--page);font-size:.7rem;font-weight:760;box-shadow:0 1px 1px rgba(0,0,0,.12)}.sidebar-brand-tools{gap:8px}.sidebar-runtime-status{gap:5px;color:var(--muted);font-size:.7rem}.sidebar-runtime-status i{width:6px;height:6px;border-radius:50%;background:var(--pass);box-shadow:0 0 0 3px color-mix(in srgb,var(--pass) 13%,transparent)}.sidebar-runtime-status[data-connection="connecting"] i,.sidebar-connection[data-connection="connecting"] i,.operations-live[data-connection="connecting"] i{background:var(--warn)}.sidebar-runtime-status[data-connection="stale"] i,.sidebar-connection[data-connection="stale"] i,.operations-live[data-connection="stale"] i{background:var(--warn);box-shadow:0 0 0 3px color-mix(in srgb,var(--warn) 13%,transparent)}.sidebar-runtime-status[data-connection="disconnected"] i,.sidebar-connection[data-connection="disconnected"] i,.operations-live[data-connection="disconnected"] i{background:var(--fail);box-shadow:0 0 0 3px color-mix(in srgb,var(--fail) 13%,transparent)}.mobile-nav-control{display:none;width:40px;height:40px;flex:0 0 auto;place-items:center;border:1px solid transparent;border-radius:12px;background:transparent;color:var(--muted-strong);cursor:pointer}.mobile-nav-control svg{width:19px;height:19px}.mobile-nav-backdrop{position:fixed;z-index:39;inset:0;visibility:hidden;border:0;padding:0;background:var(--overlay);opacity:0;pointer-events:none;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);transition:opacity 220ms var(--ease-out),visibility 220ms}.sidebar-view-switch{display:grid;gap:3px;padding:0 10px 10px;border-bottom:1px solid var(--border-soft)}.sidebar-view-item{appearance:none;min-width:0;min-height:42px;display:grid;grid-template-columns:20px minmax(0,1fr) auto;gap:9px;align-items:center;border:0;border-radius:10px;padding:0 10px;background:transparent;color:var(--muted-strong);text-align:left;cursor:pointer;transition:background-color 140ms ease,color 140ms ease,transform 120ms var(--ease-out)}.sidebar-view-item>svg{width:18px;height:18px;color:var(--muted)}.sidebar-view-item>span:nth-child(2){overflow:hidden;font-size:.82rem;font-weight:600;text-overflow:ellipsis;white-space:nowrap}.sidebar-view-item.selected{background:var(--sidebar-selected);color:var(--text)}.sidebar-view-item.selected>svg{color:var(--accent)}.sidebar-view-item:active{transform:scale(.985)}.sidebar-view-meta,.sidebar-connection{display:flex;gap:5px;align-items:center;color:var(--muted);font-size:.68rem;font-weight:450;white-space:nowrap}.sidebar-connection i,.live-pill i,.operations-live i{width:6px;height:6px;border-radius:50%;background:var(--pass)}.sidebar-scroll{min-height:0;overflow-y:auto;padding:14px 10px 16px;scrollbar-width:thin;scrollbar-color:var(--scrollbar) transparent}.sidebar-view-panel{min-width:0}.operations-navigation-copy{margin:9px 11px 15px}.operations-nav-item{appearance:none;width:100%;min-height:54px;display:grid;grid-template-columns:30px minmax(0,1fr);gap:9px;align-items:center;border:0;border-radius:10px;padding:7px 9px;background:transparent;color:var(--muted-strong);text-align:left;cursor:pointer}.operations-nav-item>svg{width:17px;height:17px;justify-self:center;color:var(--muted)}.operations-nav-item>span{min-width:0;display:grid;gap:2px}.operations-nav-item strong{font-size:.8rem;font-weight:600}.operations-nav-item small{overflow:hidden;color:var(--muted);font-size:.7rem;text-overflow:ellipsis;white-space:nowrap}.operations-nav-item:hover{background:var(--sidebar-hover)}.operations-nav-item.selected{background:var(--sidebar-selected);color:var(--text)}.operations-nav-item.selected>svg{color:var(--accent)}.sidebar-section{min-height:0;padding:0 0 14px}.sidebar-section-head{display:flex;justify-content:space-between;gap:10px;align-items:baseline;padding:0 11px}.sidebar-section-head h2{color:var(--muted);font-size:.74rem;font-weight:600;letter-spacing:.01em;text-transform:none}.sidebar-section-head #runtime-project-status{max-width:58%;overflow:hidden;color:var(--placeholder);font-size:.67rem;text-align:right;text-overflow:ellipsis;white-space:nowrap}.sidebar-filter-row{display:flex;gap:8px;align-items:center;margin:10px 2px 8px}.runner-filter{position:relative;min-width:0;flex:1;display:flex;align-items:center}.runner-filter>svg{position:absolute;z-index:1;left:9px;width:14px;height:14px;color:var(--muted);pointer-events:none}.runner-filter select{appearance:none;width:100%;height:36px;min-width:0;border:1px solid var(--border-soft);border-radius:9px;padding:0 28px 0 30px;background:var(--surface-soft);color:var(--muted-strong);font-size:.74rem;cursor:pointer}.runner-filter::after{content:"⌄";position:absolute;right:9px;color:var(--placeholder);font-size:.65rem;pointer-events:none}.sidebar-status{display:none}.selected-project{display:none}.sidebar-search{position:relative;margin:0 2px 14px}.sidebar-search svg{position:absolute;top:9px;left:9px;width:14px;height:14px;color:var(--placeholder);pointer-events:none}.sidebar-search input{width:100%;height:36px;min-width:0;border:1px solid var(--border-soft);border-radius:9px;padding:0 9px 0 31px;background:var(--surface-soft);color:var(--text);font-size:.75rem;transition:background-color 140ms ease,border-color 140ms ease}.sidebar-search input:hover,.sidebar-search input:focus{border-color:var(--border);background:var(--sidebar-selected);box-shadow:none}.sidebar-search input::placeholder{color:var(--placeholder)}.project-list,.session-list,.recent-session-list,.fleet-list,.communication-list{display:grid;align-content:start;grid-auto-rows:max-content;gap:2px;min-height:0;overflow:auto;scrollbar-width:thin;scrollbar-color:var(--scrollbar) transparent}.project-list{gap:8px;overflow:visible}.device-group{min-width:0;display:grid;gap:4px;padding:0;border:0}.device-group>summary::-webkit-details-marker{display:none}.device-group:last-child{padding-bottom:0;border-bottom:0}.device-group-head{display:grid;grid-template-columns:28px minmax(0,1fr) 8px 12px;gap:8px;align-items:center;min-height:40px;padding:2px 8px;border:0;border-radius:9px;background:transparent;box-shadow:none;cursor:pointer;list-style:none}.device-group-head::after{content:"›";color:var(--placeholder);font-size:1rem;transform:rotate(0deg);transition:transform 140ms var(--ease-out)}.device-group[open]>.device-group-head::after{transform:rotate(90deg)}.device-group-head:hover{background:var(--sidebar-hover)}.device-group-icon{display:grid;width:28px;height:28px;place-items:center;border:1px solid var(--border-soft);border-radius:8px;background:var(--surface-soft);color:var(--muted-strong)}.device-group-icon svg{width:14px;height:14px}.device-group-identity{display:grid;gap:1px;align-items:center}.device-group-identity strong{min-width:0;overflow:hidden;color:var(--muted-strong);font-size:.78rem;font-weight:620;letter-spacing:0;text-overflow:ellipsis;white-space:nowrap}.device-group-identity .small{overflow:hidden;color:var(--placeholder);font-size:.68rem;text-overflow:ellipsis;white-space:nowrap}.device-group-dot{width:6px;height:6px;border-radius:50%;background:var(--pass)}.device-group.offline .device-group-dot{background:var(--fail)}.device-project-list{display:grid;gap:2px;margin:0;padding:0;border-left:0}.device-project-empty{margin:4px 10px 8px}.project-row{appearance:none;position:relative;width:100%;min-width:0;display:grid;grid-template-columns:28px minmax(0,1fr);gap:0 9px;align-items:start;padding:8px;border:0;border-radius:9px;background:transparent;color:inherit;text-align:left;cursor:pointer;transition:background-color 140ms ease,color 140ms ease,transform 120ms var(--ease-out)}.project-row::before{content:none}.project-row::after{content:none}.project-row:hover{background:var(--sidebar-hover)}.project-row.selected{background:var(--sidebar-selected);box-shadow:inset 2px 0 0 var(--accent-solid)}.project-row-icon{display:grid;width:28px;height:28px;place-items:center;border-radius:8px;background:var(--surface-soft);color:var(--muted-strong)}.project-row-icon svg{width:15px;height:15px}.project-row.selected .project-row-icon{background:var(--accent-soft);color:var(--accent)}.project-row-main{min-width:0;display:grid;gap:3px;padding-top:1px}.project-row-heading{min-width:0;display:grid;grid-template-columns:minmax(0,1fr) auto;gap:7px;align-items:center}.project-row-title{overflow:hidden;font-size:.8rem;font-weight:620;letter-spacing:-.005em;text-overflow:ellipsis;white-space:nowrap}.project-row.selected .project-row-title{color:var(--text)}.project-row-id,.project-row-runner{display:none}.project-row-signals{min-width:0;display:flex;gap:4px;align-items:center}.project-row-signals:empty{display:none}.project-row-state{display:inline-flex;gap:4px;align-items:center;border-radius:999px;padding:3px 6px;background:var(--surface-soft);color:var(--muted-strong);font-size:.66rem;font-weight:650;line-height:1;white-space:nowrap}.project-row-state::before{content:"";width:5px;height:5px;flex:0 0 auto;border-radius:50%;background:currentColor;box-shadow:0 0 0 2px color-mix(in srgb,currentColor 12%,transparent)}.project-row-state.tone-runtime{background:var(--accent-soft);color:var(--accent)}.project-row-state.tone-warn{background:color-mix(in srgb,var(--warn) 10%,transparent);color:var(--warn)}.project-row-state.tone-fail{background:var(--danger-bg);color:var(--fail)}.project-row-meta{overflow:hidden;color:var(--muted);font-size:.7rem;line-height:1.4;text-overflow:ellipsis;white-space:nowrap}.workspace-path,.workspace-identity{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;overflow-wrap:anywhere}.sessions-panel{margin:4px 4px 10px 36px;padding:5px 0 2px 8px;border:0;border-left:1px solid var(--border-soft)}.sessions-panel .sidebar-section-head{margin:2px 0 5px;padding:0 8px}.sessions-panel .sidebar-section-head h2{font-size:.72rem}.session-list{overflow:visible;list-style:none;margin:0;padding:0}.session-list>li{margin:0;padding:0}.session-card{position:relative;min-width:0;display:grid;grid-template-columns:22px minmax(0,1fr);gap:8px;align-items:start;padding:8px;border:0;border-radius:8px;background:transparent;color:inherit;text-align:left;cursor:pointer;transition:background-color 140ms ease,color 140ms ease,transform 120ms var(--ease-out)}.session-card::before{content:none}.session-card::after{content:none}.session-card:hover{background:var(--sidebar-hover)}.session-card.selected{background:var(--sidebar-selected);box-shadow:none}.session-card-icon{display:grid;width:22px;height:22px;place-items:center;color:var(--placeholder)}.session-card-icon svg{width:14px;height:14px}.session-card.selected .session-card-icon{color:var(--accent)}.session-card-main{min-width:0}.session-title{display:-webkit-box;margin:0;overflow:hidden;font-size:.82rem;font-weight:500;line-height:1.35;overflow-wrap:anywhere;-webkit-box-orient:vertical;-webkit-line-clamp:4}.session-card .session-title{font-size:.78rem;line-height:1.42;-webkit-line-clamp:2}.session-card.selected .session-title{color:var(--text);font-weight:590}.session-card .chips{display:flex;gap:0;margin-top:4px}.session-card .chips .chip{border:0;padding:0;background:transparent;color:var(--muted);font-size:.68rem}.session-card .chips .chip + .chip::before{content:"·";margin:0 5px;color:var(--placeholder)}.summary-facts{margin-top:5px}.activity-preview{display:flex;gap:5px;margin-top:5px;overflow-wrap:anywhere}.activity-preview-label{flex:0 0 auto;font-weight:700}.empty-copy{margin:8px 40px}.recent-panel{margin:14px 4px 6px;padding:10px 4px 0;border-top:1px solid var(--border-soft)}.recent-panel-summary{display:flex;justify-content:space-between;align-items:center;gap:8px;padding:6px 8px;border-radius:8px;color:var(--muted-strong);font-size:.74rem;font-weight:600;cursor:pointer;list-style:none;user-select:none;transition:background-color 140ms ease,color 140ms ease}.recent-panel-summary::-webkit-details-marker{display:none}.recent-panel-summary:hover{background:var(--sidebar-hover);color:var(--text)}.recent-panel-title{font-size:.74rem;font-weight:600;color:var(--muted-strong)}.recent-panel-meta{margin-left:auto;color:var(--placeholder);font-size:.68rem;font-weight:400}.recent-panel-summary::after{content:"›";display:inline-block;color:var(--placeholder);font-size:.95rem;line-height:1;transform:rotate(0deg);transition:transform 140ms var(--ease-out)}.recent-panel[open]>.recent-panel-summary::after{transform:rotate(90deg)}.recent-session-list{max-height:250px}.recent-session-row{appearance:none;width:100%;min-width:0;display:grid;gap:4px;padding:8px 10px;border:1px solid transparent;border-radius:11px;background:transparent;color:inherit;text-align:left;cursor:pointer}.recent-session-row:hover,.recent-session-row.selected{background:var(--sidebar-selected)}@media (hover:hover){.sidebar-view-item:hover,.project-row:hover,.session-card:hover,.recent-session-row:hover{background:var(--sidebar-hover)}}.project-row:active,.session-card:active,.recent-session-row:active{transform:scale(.985)}.recent-session-location{overflow-wrap:anywhere}.recent-session-signals{display:flex;flex-wrap:wrap;gap:5px}.sidebar-footer{display:flex;gap:10px;align-items:center;padding:0 18px;border-top:1px solid var(--border-soft);background:transparent;box-shadow:none}.local-avatar{display:grid;width:30px;height:30px;place-items:center;border:1px solid var(--border);border-radius:9px;background:var(--avatar);font-size:.72rem;font-weight:700;box-shadow:none}.sidebar-footer>span:last-child{display:grid;gap:1px;font-size:.72rem}.sidebar-footer small{color:var(--placeholder);font-size:.61rem}.workspace-main{position:relative;min-width:0;min-height:0;display:grid;grid-template-rows:var(--header-height) minmax(0,1fr);overflow:hidden;border:0;border-radius:0;background:var(--page-surface);box-shadow:none}.workspace-topbar{position:relative;z-index:40;min-width:0;display:flex;justify-content:space-between;gap:12px;align-items:center;overflow:visible;padding:0 18px 0 22px;border-bottom:1px solid var(--border-soft);background:var(--topbar);box-shadow:0 1px 0 color-mix(in srgb,var(--text) 2%,transparent);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur)}.workspace-heading{min-width:0;flex:1 1 auto;display:flex;gap:10px;align-items:center}.workspace-heading>svg{width:17px;height:17px;flex:0 0 auto;color:var(--muted-strong)}.workspace-heading-copy{min-width:0;display:grid;gap:2px}.workspace-breadcrumb{min-width:0;display:flex;gap:5px;align-items:center;overflow:hidden;color:var(--placeholder);font-size:.68rem;line-height:1}.workspace-breadcrumb span{min-width:0;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.workspace-breadcrumb i{color:var(--border);font-style:normal}.workspace-heading strong{max-width:min(760px,54vw);overflow:hidden;font-size:.94rem;font-weight:620;letter-spacing:-.012em;text-overflow:ellipsis;white-space:nowrap}.topbar-controls{min-width:0;display:flex;justify-content:flex-end;gap:7px;align-items:center;padding-right:42px}.topbar-more{position:relative;z-index:72}.topbar-more>summary{display:none;list-style:none}.topbar-more>summary::-webkit-details-marker{display:none}.topbar-more-popover{display:flex;gap:7px;align-items:center}.topbar-action-label{display:none}.session-state-chips{display:none}.runtime-has-session .session-state-chips{display:flex}.session-state-chips .chip:not(:last-child){display:none}.session-state-chips .chip{min-height:24px;border-color:var(--border-soft);background:var(--surface-soft);color:var(--muted)}.session-state-chips .chip:last-child{color:var(--muted-strong)}.banner{position:absolute;z-index:4;top:calc(var(--header-height) + 8px);right:18px;left:18px;margin:0;border:1px solid var(--danger-border);border-radius:12px;padding:9px 11px;background:var(--danger-bg);box-shadow:inset 0 1px 0 var(--glass-highlight);backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);font-size:.78rem}.conversation-stage{grid-row:2;min-height:0;position:relative;overflow:hidden}.conversation-empty{width:min(520px,calc(100% - 44px));height:100%;margin:0 auto;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding-top:clamp(88px,23.6dvh,220px);text-align:center}.conversation-empty h2{margin:17px 0 8px;font-size:1rem}.conversation-empty p{max-width:390px;margin-bottom:0;color:var(--muted);font-size:.82rem;line-height:1.55;text-wrap:balance}.empty-orbit{display:grid;width:56px;height:56px;place-items:center;border:1px solid var(--border);border-radius:16px;background:var(--surface-raised);color:var(--muted-strong);box-shadow:0 10px 28px rgba(0,0,0,.08)}.empty-orbit svg{width:24px;height:24px}.conversation-empty h2{margin-top:22px;font-size:clamp(1.35rem,3vw,1.8rem);font-weight:560;letter-spacing:-.03em}.conversation-empty p{max-width:470px;margin-top:4px;font-size:.84rem}.session-conversation{position:absolute;inset:0;min-height:0;display:grid;grid-template-rows:minmax(0,1fr) auto}.session-chat{position:relative;min-height:0;display:grid;grid-template-rows:auto auto minmax(0,1fr) auto}.chat-section-head,.unavailable-note,.collaboration-board,.chat-empty,.collaboration-composer{width:min(var(--content-width),calc(100% - var(--content-gutter) - var(--content-gutter)))}.chat-section-head{min-height:24px;margin:0 auto;display:flex;justify-content:flex-end;align-items:end;padding-top:8px}.chat-section-head>span{color:var(--placeholder);font-size:.68rem}#runtime-collaboration-status{display:none}.unavailable-note{margin:5px auto;padding:9px 11px;border:1px solid var(--border-soft);border-radius:12px;background:var(--surface-soft);box-shadow:inset 0 1px 0 var(--glass-highlight)}.chat-scroll{min-height:0;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--scrollbar) transparent}.collaboration-board{min-height:100%;margin:0 auto;display:flex;flex-direction:column;justify-content:flex-end;gap:0;padding:clamp(28px,3.8vh,44px) 0 clamp(44px,6vh,68px)}.chat-empty{min-height:100%;margin:0 auto;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding:clamp(72px,23.6dvh,190px) 0 48px;text-align:center}.chat-empty>span{margin-bottom:10px;color:var(--accent);font-size:1.2rem}.chat-empty strong{font-size:1rem;letter-spacing:-.01em}.chat-empty p{max-width:520px;margin:6px 0 0;line-height:1.55;text-wrap:balance}.chat-retention{display:none}.message-card{position:relative;min-width:0;max-width:100%;align-self:flex-start;display:grid;grid-template-columns:minmax(0,1fr);align-items:start;border:0;border-radius:0;padding:0;background:transparent}.message-card + .message-card{margin-top:28px}.message-card.message-incoming + .message-card.message-incoming{margin-top:17px}.message-card.message-neutral + .message-card.message-neutral{margin-top:17px}.message-card.message-outgoing + .message-card.message-outgoing{margin-top:13px}.message-card + .message-card.message-thread{margin-top:16px}.message-card.message-entering{animation:message-enter 240ms var(--ease-out)}@keyframes message-enter{from{opacity:0;transform:translateY(7px) scale(.992)}}.message-card.message-incoming{width:fit-content;max-width:min(82%,880px);align-self:flex-start}.message-card.message-neutral{width:fit-content;max-width:min(82%,880px);align-self:flex-start}.message-card.message-outgoing{width:fit-content;max-width:min(68%,680px);align-self:flex-end}.message-content{min-width:0;display:flex;flex-direction:column;align-items:flex-start}.message-card.message-outgoing .message-content{align-items:flex-end}.message-author{min-height:18px;display:flex;align-items:center;margin:0 2px 4px;color:var(--muted);font-size:.72rem}.message-author-name{font-weight:600}.message-card.message-outgoing .message-author{justify-content:flex-end}.message-card.message-group-continuation .message-author{display:none}.message-reply-context{max-width:100%;display:flex;gap:6px;align-items:center;margin:0 4px 7px;color:var(--placeholder);font-size:.7rem;line-height:1.4}.message-reply-context svg{width:12px;height:12px;flex:0 0 auto}.message-reply-context span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.message-card.message-outgoing .message-reply-context{justify-content:flex-end}.message-bubble{min-width:0;max-width:100%}.message-card.message-incoming .message-bubble{width:fit-content;border:0;border-radius:var(--message-bubble-radius);padding:clamp(11px,1.1vw,13px) clamp(16px,1.5vw,19px);background:var(--message-incoming-bg);color:var(--text);box-shadow:0 1px 1px rgba(0,0,0,.025)}.message-card.message-neutral .message-bubble{width:fit-content;border:0;border-radius:var(--message-bubble-radius);padding:clamp(11px,1.1vw,13px) clamp(16px,1.5vw,19px);background:var(--message-incoming-bg);color:var(--text);box-shadow:0 1px 1px rgba(0,0,0,.025)}.message-card.message-outgoing .message-bubble{align-self:flex-end;border:0;border-radius:var(--message-bubble-radius);padding:clamp(10px,1.1vw,12px) clamp(15px,1.5vw,18px);background:var(--message-outgoing-bg);color:var(--message-outgoing-text);box-shadow:0 1px 1px rgba(0,0,0,.055)}.message-footer{min-width:0;display:flex;flex-wrap:wrap;gap:5px 9px;align-items:center;margin-top:7px;color:var(--muted)}.message-card.message-outgoing .message-footer{width:100%;align-self:flex-end;justify-content:flex-end;padding:0 2px}.message-card.message-incoming .message-footer{justify-content:flex-start;padding:0 2px}.message-card.message-neutral .message-footer{justify-content:flex-start;padding:0 2px}.message-head{min-width:0;display:flex;flex:0 1 auto;justify-content:flex-start;gap:7px;align-items:center;color:var(--muted)}.message-card.message-outgoing .message-head{justify-content:flex-end}.message-kind{display:inline-flex;min-height:20px;align-items:center;border:1px solid var(--border-soft);border-radius:999px;padding:0 7px;background:var(--surface-soft);color:var(--muted);font-size:.68rem;font-weight:560}.message-head>.small{font-size:.7rem}.message-meta{display:none}.message-resolution{color:var(--muted);font-size:.7rem}.message-ack,.message-resolution{flex-basis:100%}.message-card.message-outgoing .message-ack,.message-card.message-outgoing .message-resolution{text-align:right}.message-card.message-outgoing .muted,.message-card.message-outgoing .message-resolution{color:var(--muted)}.message-body{position:relative;max-height:none;margin:0;overflow:visible;overflow-wrap:anywhere;font-size:.92rem;line-height:1.62}.message-body.is-collapsed{max-height:31rem;overflow:hidden;mask-image:linear-gradient(to bottom,#000 0,#000 calc(100% - 64px),transparent 100%)}.message-body.is-expanded{max-height:none;mask-image:none}.message-paragraph{margin:0;white-space:pre-wrap}.message-paragraph + .message-paragraph,.message-body>:not(:first-child){margin-top:.8em}.message-body ul,.message-body ol{margin-bottom:0;padding-left:1.4em}.message-body li + li{margin-top:.28em}.message-body blockquote{margin-right:0;margin-bottom:0;margin-left:0;padding-left:12px;border-left:2px solid color-mix(in srgb,currentColor 24%,transparent);color:var(--muted-strong)}.message-body blockquote .message-paragraph{margin:0}.message-heading{margin-bottom:0;color:inherit;font-size:1em;font-weight:680;letter-spacing:-.01em;text-transform:none}.message-body a{color:inherit;text-decoration-color:color-mix(in srgb,currentColor 46%,transparent);text-underline-offset:2px}.message-code{overflow:hidden;border:1px solid color-mix(in srgb,currentColor 11%,transparent);border-radius:13px;background:color-mix(in srgb,var(--page) 84%,transparent);color:var(--text)}.message-code>header{min-height:34px;display:flex;justify-content:space-between;gap:12px;align-items:center;padding:0 10px 0 12px;border-bottom:1px solid var(--border-soft);color:var(--muted);font:500 .7rem/1 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.message-code-copy{appearance:none;display:inline-flex;gap:6px;align-items:center;border:0;border-radius:7px;padding:5px 7px;background:transparent;color:var(--muted-strong);cursor:pointer;font:inherit}.message-code-copy:hover{background:var(--surface-soft);color:var(--text)}.message-code-copy svg{width:13px;height:13px}.message-code pre{max-width:100%;margin:0;overflow:auto;padding:13px 14px;scrollbar-width:thin}.message-code code{white-space:pre;font:500 .78rem/1.58 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.message-expand{appearance:none;margin-top:8px;border:0;border-radius:8px;padding:5px 8px;background:color-mix(in srgb,currentColor 8%,transparent);color:inherit;cursor:pointer;font-size:.72rem;font-weight:600}.message-ack{color:var(--warn);font-size:.7rem}.message-ack.observed{color:var(--muted)}.message-actions{display:flex;justify-content:flex-start;gap:2px;margin-left:auto;opacity:.58;transition:opacity 140ms ease}.message-card.message-outgoing .message-actions{justify-content:flex-end}.message-action{appearance:none;display:grid;width:26px;height:26px;place-items:center;border:0;border-radius:7px;background:transparent;color:var(--muted);cursor:pointer;transition:color 120ms ease,background-color 120ms ease,transform 120ms var(--ease-out)}.message-action svg{width:13px;height:13px}.message-action:hover{background:var(--surface-soft);color:var(--text)}.message-action.danger:hover{color:var(--fail)}.message-action:active{transform:scale(.94)}.message-card:hover .message-actions,.message-card:focus-within .message-actions{opacity:1}.message-thread{margin-left:0}.message-date-separator{width:100%;display:flex;align-items:center;gap:12px;margin:30px 0 22px;color:var(--placeholder);font-size:.7rem}.message-date-separator::before,.message-date-separator::after{content:"";height:1px;flex:1;background:var(--border-soft)}.new-messages-button{position:absolute;z-index:8;right:50%;bottom:12px;display:inline-flex;gap:7px;align-items:center;border:1px solid var(--border);border-radius:999px;padding:8px 12px;background:var(--surface);color:var(--muted-strong);box-shadow:var(--shadow-raised);cursor:pointer;transform:translateX(50%);animation:new-messages-enter 180ms var(--ease-out)}.new-messages-button svg{width:14px;height:14px}@keyframes new-messages-enter{from{opacity:0;transform:translate(50%,7px) scale(.96)}}.collaboration-composer{position:relative;isolation:isolate;margin:10px auto max(16px,env(safe-area-inset-bottom));padding:8px 9px 8px;border:1px solid var(--border);border-radius:24px;background:var(--composer);box-shadow:0 12px 34px rgba(5,7,12,.13),inset 0 1px 0 color-mix(in srgb,white 5%,transparent);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);transition:border-color 220ms ease,background-color 220ms ease,box-shadow 260ms var(--ease-out),transform 260ms var(--ease-out);animation:composer-enter 280ms var(--ease-out)}.collaboration-composer:focus-within{border-color:color-mix(in srgb,var(--accent) 34%,var(--border));box-shadow:0 18px 42px rgba(5,7,12,.17),0 0 0 3px color-mix(in srgb,var(--accent-soft) 72%,transparent);transform:translateY(-1px)}.collaboration-composer textarea{width:100%;height:44px;min-height:44px;max-height:180px;resize:none;overflow-y:hidden;border:0;outline:0;padding:10px 9px 7px;background:transparent;color:var(--text);font-size:.88rem;line-height:1.5}.collaboration-composer textarea::placeholder{color:var(--placeholder)}.collaboration-composer.is-unavailable{opacity:.7}.collaboration-composer.is-unavailable textarea{cursor:not-allowed}.composer-toolbar{min-height:38px;display:flex;justify-content:space-between;gap:10px;align-items:center}.composer-fields{min-width:0;display:flex;gap:8px;align-items:center}.composer-options{position:relative;z-index:12}.composer-options>summary{list-style:none}.composer-options>summary::-webkit-details-marker{display:none}.composer-tools-trigger{min-width:38px;height:36px;display:inline-flex;gap:7px;align-items:center;border-radius:999px;padding:0 11px 0 9px;color:var(--muted-strong);cursor:pointer;transition:color 160ms ease,background-color 160ms ease,transform 140ms var(--ease-out)}.composer-tools-trigger svg{width:18px;height:18px;transition:transform 190ms var(--ease-out)}.composer-tools-trigger span{max-width:210px;overflow:hidden;font-size:.67rem;font-weight:570;text-overflow:ellipsis;white-space:nowrap}.composer-options[open] .composer-tools-trigger,.composer-options.has-selection .composer-tools-trigger{background:var(--surface-soft);color:var(--text)}.composer-options.has-selection .composer-tools-trigger{color:var(--accent)}.composer-options[open] .composer-tools-trigger svg{transform:rotate(45deg)}.composer-options-popover{position:absolute;z-index:30;bottom:calc(100% + 12px);left:0;width:min(350px,calc(100vw - 40px));padding:12px;border:1px solid var(--border);border-radius:16px;background:var(--surface);box-shadow:var(--shadow-raised);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);transform-origin:bottom left;animation:composer-options-enter 180ms var(--ease-out)}.composer-options-head{display:grid;gap:2px;margin-bottom:10px;padding:0 2px}.composer-options-head strong{font-size:.76rem}.composer-options-head .small{font-size:.61rem}.composer-option-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.composer-control{min-width:0;display:grid;gap:5px;border:0;border-radius:10px;padding:8px 9px;background:var(--surface-soft);color:var(--placeholder);font-size:.61rem}.composer-control select{width:100%;height:28px;min-width:0;border:0;outline:0;padding:0;background:transparent;color:var(--text);font-size:.72rem;cursor:pointer}.composer-control:focus-within{box-shadow:0 0 0 2px var(--accent-soft)}.composer-check{grid-column:1 / -1;min-height:38px;display:flex;gap:8px;align-items:center;border-radius:10px;padding:0 10px;background:var(--surface-soft);color:var(--muted-strong);font-size:.68rem}.composer-fields input[type="checkbox"]{accent-color:var(--accent-solid)}.composer-actions{min-width:0;display:flex;justify-content:flex-end;align-items:center;gap:8px}.composer-actions>span{max-width:360px;overflow:hidden;text-align:right;line-height:1.3}.reply-target,.edit-target{display:flex;justify-content:space-between;gap:8px;align-items:center;margin:3px 3px 4px;padding:7px 9px;border:0;border-left:2px solid var(--accent);border-radius:0 9px 9px 0;background:var(--surface-soft);animation:composer-context-enter 180ms var(--ease-out)}.edit-target{border-left:3px solid var(--warn)}@keyframes composer-enter{from{opacity:0;transform:translateY(10px) scale(.992)}}@keyframes composer-options-enter{from{opacity:0;transform:translateY(6px) scale(.97)}}@keyframes composer-context-enter{from{opacity:0;transform:translateY(4px)}}.operations-stage{grid-row:2;min-width:0;min-height:0;overflow:hidden;background:var(--page-surface)}.operations-scroll{width:100%;height:100%;overflow-y:auto;padding:clamp(24px,3vw,44px) var(--content-gutter) 64px;scrollbar-width:thin;scrollbar-color:var(--scrollbar) transparent}.operations-heading{width:min(1440px,100%);margin:0 auto 22px;display:flex;justify-content:space-between;gap:24px;align-items:flex-start}.operations-heading h2{margin:1px 0 7px;font-size:clamp(1.35rem,2vw,1.75rem);font-weight:620;letter-spacing:-.035em}.operations-heading p:last-child{max-width:680px;margin-bottom:0;line-height:1.55}.operations-live{display:inline-flex;gap:7px;align-items:center;border:1px solid var(--border-soft);border-radius:999px;padding:7px 10px;background:var(--surface-soft);color:var(--muted-strong);font-size:.74rem;white-space:nowrap}.operations-layout{width:min(1440px,100%);margin:0 auto;display:grid;grid-template-columns:minmax(0,1fr);gap:14px;align-items:start}.operations-card{min-width:0;scroll-margin-top:20px;border:1px solid var(--border-soft);border-radius:16px;padding:18px;background:color-mix(in srgb,var(--surface) 72%,transparent);box-shadow:0 1px 0 color-mix(in srgb,var(--text) 3%,transparent)}.operations-card:focus{outline:none}.operations-card:focus-visible{outline:2px solid var(--accent);outline-offset:3px}.operations-card-head{display:flex;justify-content:space-between;gap:16px;align-items:flex-start;margin-bottom:13px}.operations-card-head h3{margin:2px 0 0;font-size:.98rem;font-weight:630;letter-spacing:-.015em}.operations-card-head>.small{max-width:48%;text-align:right}.operations-agents{grid-column:1 / -1}.operations-metrics{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-top:0}.operations-metrics .metric{min-height:78px;grid-template-columns:1fr;gap:4px;align-content:center;border:0;border-radius:12px;padding:12px 13px;background:var(--surface-inset)}.operations-metrics .metric>.small{grid-column:1}.operations-metrics .metric strong{font-size:.88rem}.operations-runners .fleet-list{max-height:none;margin-top:0}.operations-agents .communication-grid{grid-template-columns:minmax(300px,.85fr) minmax(360px,1.15fr);gap:12px}.operations-agents .communication-agents,.operations-agents .communication-conversations{align-content:start}.operations-agents .communication-section{border-radius:12px;padding:13px}.operations-agents .communication-list{max-height:320px}.operations-agents .conversation-list{max-height:280px}.operations-agents .conversation-transcript{max-height:520px}.runtime-shell[data-workspace-view="operations"] .runtime-inspector{display:none}.runtime-shell[data-workspace-view="operations"].context-docked{grid-template-columns:var(--sidebar-width) minmax(0,1fr)}.runtime-shell[data-workspace-view="operations"] .session-state-chips{display:none}.runtime-inspector{position:absolute;z-index:50;top:0;right:0}.runtime-inspector{display:none}.runtime-has-session .runtime-inspector{display:block}.runtime-operations-view .runtime-inspector{display:none}.runtime-shell[data-workspace-view="operations"] .topbar-controls,body:not(.runtime-has-session) .topbar-controls{padding-right:0}.context-trigger{position:absolute;z-index:23;top:16px;right:18px;display:grid;width:36px;height:36px;place-items:center;border:1px solid transparent;border-radius:9px;color:var(--muted);cursor:pointer;list-style:none;transition:color 140ms ease,background-color 140ms ease,border-color 140ms ease,transform 120ms var(--ease-out)}.context-trigger::-webkit-details-marker{display:none}.context-trigger:hover,.runtime-inspector[open] .context-trigger{border-color:var(--border);background:var(--sidebar-hover);color:var(--text);box-shadow:inset 0 1px 0 var(--glass-highlight)}.context-trigger svg{width:17px;height:17px}.inspector-backdrop{position:fixed;z-index:20;inset:0;border:0;background:color-mix(in srgb,var(--overlay) 78%,transparent);cursor:default}.inspector-popover{position:fixed;z-index:21;top:calc(var(--header-height) + 10px);right:10px;width:clamp(380px,var(--layout-minor),460px);max-width:calc(100vw - 20px);height:min(780px,calc(100dvh - var(--header-height) - 20px));display:grid;grid-template-rows:58px minmax(0,1fr);overflow:hidden;border:1px solid var(--border);border-radius:14px;background:var(--surface);box-shadow:var(--shadow-raised);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);transform-origin:top right;animation:inspector-enter 170ms var(--ease-out)}.inspector-backdrop{animation:inspector-backdrop-enter 160ms ease-out}@keyframes inspector-enter{from{opacity:0;transform:translateY(-4px) scale(.985)}}@keyframes inspector-backdrop-enter{from{opacity:0}}.inspector-header{display:flex;justify-content:space-between;gap:12px;align-items:center;padding:0 17px;border-bottom:1px solid var(--border-soft);background:transparent;box-shadow:none}.inspector-header>div:first-child{display:grid}.inspector-header strong{font-size:.86rem}.inspector-header-actions{display:flex;align-items:center;gap:8px}.inspector-close{display:grid;width:32px;height:32px;place-items:center;border:1px solid transparent;border-radius:8px;background:transparent;color:var(--muted-strong);cursor:pointer;transition:color 140ms ease,background-color 140ms ease,border-color 140ms ease}.inspector-close:hover{border-color:var(--border-soft);background:var(--sidebar-hover);color:var(--text)}.inspector-close svg{width:16px;height:16px}.live-pill{display:inline-flex;gap:6px;align-items:center;padding:5px 7px;border:1px solid var(--border);border-radius:999px;color:var(--muted-strong);font-size:.65rem}.inspector-scroll{min-height:0;overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--scrollbar) transparent}.inspector-card{display:block;margin:0;padding:14px 16px;border:0;border-bottom:1px solid var(--border-soft);background:transparent}.inspector-card>summary{display:flex;justify-content:space-between;gap:9px;align-items:baseline;color:var(--muted-strong);font-size:.77rem;font-weight:680;cursor:pointer;list-style:none}.inspector-card>summary::-webkit-details-marker{display:none}.inspector-card>summary::before{content:"›";color:var(--muted)}.inspector-card[open]>summary::before{transform:rotate(90deg)}.inspector-card>summary>:nth-child(2){max-width:48%;overflow:hidden;text-align:right;text-overflow:ellipsis;white-space:nowrap}.inspector-card-head{display:flex;justify-content:space-between;gap:10px;align-items:baseline;margin-bottom:9px}.context-navigation{position:sticky;top:-15px;z-index:1;display:flex;gap:4px;margin:-1px 0 16px;padding:5px;border:1px solid var(--border-soft);border-radius:12px;background:var(--surface-solid)}.context-navigation button{flex:1;min-width:0;min-height:40px;border:0;border-radius:8px;background:transparent;color:var(--muted-strong);font:inherit;font-size:.78rem;cursor:pointer}.context-navigation button:hover{background:var(--sidebar-hover);color:var(--text)}.context-navigation button[aria-pressed="true"]{background:var(--accent-soft);color:var(--accent);font-weight:650}.context-navigation button:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.session-identity{display:grid;grid-template-columns:1fr;gap:7px;margin:8px 0;padding:10px;border:1px solid var(--border-soft);border-radius:10px;background:var(--surface-inset);box-shadow:none}.session-identity-fact{min-width:0;display:grid;gap:2px}.session-identity-value{overflow-wrap:anywhere}.session-identity code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.69rem;user-select:all}.workspace-identity{margin:8px 0;font-size:.68rem}.overview{display:grid;grid-template-columns:1fr;gap:6px;margin:11px 0}.context-primary-overview{margin-bottom:0}.context-secondary-overview{margin-top:8px}.overview-card{min-width:0;padding:9px 10px;border:1px solid var(--border-soft);border-left:3px solid var(--border);border-radius:9px;background:var(--surface-inset);box-shadow:none}.overview-card p{margin-bottom:0;overflow-wrap:anywhere;font-size:.75rem;line-height:1.4}.runtime-fact{border-left-color:var(--accent)}.reported-card{border-left-color:var(--muted);opacity:.84}.tone-card-pass{border-left-color:var(--pass)}.tone-card-warn{border-left-color:var(--warn)}.tone-card-fail{border-left-color:var(--fail)}.tone-card-muted{border-left-color:var(--muted)}.activity-section{margin-top:13px;padding-top:12px;border-top:1px solid var(--border-soft)}.timeline-controls{justify-content:space-between;margin-bottom:7px;font-size:.78rem}.timeline{display:grid;gap:6px;max-height:300px;overflow:auto;list-style:none;margin:0;padding:0}.timeline-event{padding:8px 9px;border:1px solid var(--border-soft);border-left:3px solid var(--border);border-radius:10px;background:var(--surface-inset)}.timeline-event.failed{border-left-color:var(--fail)}.timeline-event.reported-progress{border-left-color:var(--muted);opacity:.82}.timeline-head{display:flex;justify-content:space-between;gap:8px;align-items:baseline}.timeline-kind{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.7rem}.timeline-body{margin-top:4px;overflow-wrap:anywhere}.metric-grid{display:grid;grid-template-columns:1fr;gap:5px;margin-top:11px}.metric{min-width:0;display:grid;grid-template-columns:minmax(72px,.7fr) minmax(0,1.3fr);gap:3px 7px;align-items:baseline;padding:8px 9px;border:1px solid var(--border-soft);border-radius:10px;background:var(--surface-inset)}.metric strong,.metric span{overflow-wrap:anywhere}.metric strong{font-size:.74rem}.metric>.small{grid-column:2}.metric-label{color:var(--muted);font-size:.63rem;letter-spacing:.05em;text-transform:uppercase}.fleet-list{max-height:330px;margin-top:10px}.fleet-row{appearance:none;width:100%;min-width:0;display:grid;gap:6px;padding:10px;border:1px solid var(--border-soft);border-radius:11px;background:var(--surface-inset);color:inherit;text-align:left;cursor:pointer}.fleet-row.selected{border-color:var(--accent-border);background:var(--accent-soft)}.fleet-row-main,.fleet-row-signals,.fleet-row-facts{min-width:0}.fleet-row-title{overflow-wrap:anywhere;font-size:.76rem;font-weight:700}.fleet-row-meta,.fleet-row-facts{overflow-wrap:anywhere}.fleet-row-signals{display:flex;flex-wrap:wrap;gap:5px}.retention-note{margin:9px 0 0}.communication-grid{display:grid;grid-template-columns:1fr;gap:9px;margin-top:10px}.communication-agents,.communication-conversations{min-width:0;display:grid;gap:9px}.communication-section{min-width:0;padding:10px;border:1px solid var(--border-soft);border-radius:10px;background:var(--surface-inset);box-shadow:none}.communication-section h3{margin-bottom:8px;font-size:.76rem}.stack-form{display:grid;gap:7px;margin-bottom:9px}.stack-form>label,.compact-field-grid>label{display:grid;gap:3px;color:var(--muted);font-size:.68rem}.stack-form input,.stack-form textarea{width:100%;min-width:0;padding:8px 9px;border:1px solid var(--border);border-radius:10px;resize:vertical;background:var(--input);color:var(--text)}.stack-form>label.inline-choice{display:flex;grid-template-columns:none;flex-direction:row;align-items:center;gap:7px}.stack-form>label.inline-choice input{width:auto}.compact-field-grid{display:grid;grid-template-columns:1fr;gap:7px}.form-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:7px}.form-actions .muted{margin-right:auto}.communication-list{max-height:260px}.communication-row{appearance:none;width:100%;min-width:0;padding:9px;border:1px solid var(--border-soft);border-radius:10px;background:var(--surface);color:var(--text);text-align:left;cursor:pointer}.communication-row.selected{border-color:var(--accent);box-shadow:inset 2px 0 0 var(--accent)}.communication-row-head,.conversation-message-head{display:flex;justify-content:space-between;gap:7px;align-items:baseline}.communication-row-title,.conversation-message-author{overflow-wrap:anywhere;font-size:.74rem;font-weight:680}.communication-row-meta,.communication-id,.conversation-message-meta,.conversation-message-deliveries{display:block;color:var(--muted);font-size:.66rem;overflow-wrap:anywhere}.communication-id{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;user-select:all}.communication-description{margin:8px 0;white-space:pre-wrap;overflow-wrap:anywhere}.card-edit-form{border-top:1px solid var(--border);padding-top:9px;margin-top:9px}.communication-participants{margin:8px 0}.conversation-list{max-height:220px}.conversation-transcript{min-height:120px;max-height:430px;display:grid;gap:7px;overflow:auto;margin:9px 0}.conversation-message{min-width:0;padding:9px;border:1px solid var(--border-soft);border-left:3px solid var(--accent);border-radius:10px;background:var(--surface)}.conversation-message.agent-authored{border-left-color:var(--pass)}.conversation-message-body,.inbox-message-preview{margin-top:5px;white-space:pre-wrap;overflow-wrap:anywhere}.inbox-message-preview{max-height:6rem;overflow:auto}.inbox-delivery{cursor:default}.conversation-composer{margin:9px 0 0;padding-top:9px;border-top:1px solid var(--border-soft)}.section-head{justify-content:space-between}@media (min-width:1600px){.runtime-shell.context-docked{--content-width:1160px;grid-template-columns:var(--sidebar-width) minmax(0,1fr) var(--context-rail-width)}.runtime-shell.context-docked .runtime-inspector{position:relative;z-index:10;top:auto;right:auto;grid-column:3;grid-row:1;min-width:0;height:100dvh;overflow:hidden;border-left:1px solid var(--border-soft);background:var(--sidebar)}.runtime-shell.context-docked .context-trigger,.runtime-shell.context-docked .inspector-backdrop{display:none !important}.runtime-shell.context-docked .topbar-controls{padding-right:0}.runtime-shell.context-docked .inspector-popover{position:relative;top:auto;right:auto;width:100%;max-width:none;height:100dvh;border:0;border-radius:0;background:transparent;box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none;animation:none}.runtime-shell.context-docked .inspector-header{min-height:var(--header-height);padding:0 18px}}@media (max-width:1180px){.workspace-heading strong{max-width:min(620px,44vw)}.runtime-has-session .session-state-chips{display:flex}.operations-layout{grid-template-columns:1fr}.operations-agents{grid-column:1}}@media (hover:hover) and (pointer:fine){.message-actions{opacity:0}}@media (max-width:900px){:root{--header-height:calc(58px + env(safe-area-inset-top));--content-gutter:clamp(16px,3vw,24px)}.runtime-shell{grid-template-columns:minmax(0,1fr);gap:0;padding:0}.workspace-sidebar{position:fixed;z-index:60;inset:0 auto 0 0;width:min(88vw,360px);height:100dvh;visibility:hidden;border-width:0 1px 0 0;border-radius:0;background:var(--sidebar-drawer);box-shadow:20px 0 54px rgba(6,11,20,.28);transform:translateX(-102%);transition:transform 240ms var(--ease-drawer),visibility 240ms}.mobile-nav-backdrop{z-index:59}.runtime-shell.mobile-nav-open .workspace-sidebar{visibility:visible;transform:translateX(0)}.runtime-shell.mobile-nav-open .mobile-nav-backdrop{visibility:visible;opacity:1;pointer-events:auto}.mobile-nav-control{display:grid}.mobile-nav-toggle{margin-left:-5px}.sidebar-brand{padding-top:env(safe-area-inset-top)}.workspace-main{width:100%;height:100dvh;border:0;border-radius:0;box-shadow:none}.workspace-topbar{padding:env(safe-area-inset-top) max(12px,env(safe-area-inset-right)) 0 max(12px,env(safe-area-inset-left))}.workspace-heading strong{max-width:min(600px,58vw)}.topbar-controls{flex:0 0 auto;padding-right:46px}#runtime-refresh-status{display:none}.sidebar-scroll{padding-bottom:max(18px,env(safe-area-inset-bottom));overscroll-behavior:contain}.sidebar-footer{padding-bottom:env(safe-area-inset-bottom)}.runtime-inspector{z-index:50}.context-trigger{z-index:53;top:calc(9px + env(safe-area-inset-top));right:max(9px,env(safe-area-inset-right));width:40px;height:40px;border-radius:12px}.inspector-backdrop{z-index:49;background:var(--overlay)}.inspector-close{width:36px;height:36px}.inspector-close svg{width:18px;height:18px}.inspector-popover{z-index:51;top:var(--header-height);right:0;width:100vw;height:calc(100dvh - var(--header-height));border-right:0;border-bottom:0;border-left:0;border-radius:16px 16px 0 0;transform-origin:bottom center;animation-name:inspector-sheet-enter}.inspector-scroll{padding-bottom:env(safe-area-inset-bottom)}.operations-scroll{padding:24px max(18px,env(safe-area-inset-right)) max(48px,env(safe-area-inset-bottom)) max(18px,env(safe-area-inset-left))}.operations-agents .communication-grid{grid-template-columns:1fr}@keyframes inspector-sheet-enter{from{opacity:0;transform:translateY(14px)}}}@media (max-width:600px){:root{--header-height:calc(56px + env(safe-area-inset-top))}.auth-topbar{width:calc(100% - 28px);padding-top:max(24px,5vh)}.auth-topbar{gap:10px}.brand-lockup{align-items:flex-start}.brand-lockup h1{font-size:1.08rem}.brand-lockup p{font-size:.75rem;line-height:1.4}.gate{width:calc(100% - 28px);margin-top:20px;padding:21px;border-radius:20px}.gate h2{font-size:1.05rem}.gate>form>.muted{margin-bottom:16px;font-size:.79rem}.field-row{align-items:stretch;flex-direction:column}.field-row input,.field-row .btn{width:100%;min-height:44px}.workspace-sidebar{width:min(94vw,360px);grid-template-rows:var(--header-height) auto minmax(0,1fr) 58px}.sidebar-brand{padding:0 14px 0 16px}.sidebar-primary-row{padding:0 16px}.sidebar-scroll{padding-top:18px}.workspace-topbar{gap:6px;padding:env(safe-area-inset-top) max(8px,env(safe-area-inset-right)) 0 max(8px,env(safe-area-inset-left))}.workspace-heading{gap:7px}.workspace-heading>svg{display:none}.workspace-breadcrumb{display:none}.workspace-heading strong{max-width:none;font-size:.82rem}.topbar-controls{gap:3px;padding-right:43px}.session-state-chips{display:none !important}.topbar-more>summary{display:grid;width:40px;height:40px;place-items:center}.topbar-more:not([open])>.topbar-more-popover{display:none}.topbar-more-popover{position:absolute;z-index:95;top:calc(100% + 8px);right:0;width:210px;display:grid;gap:3px;padding:8px;border:1px solid var(--border);border-radius:14px;background:var(--surface);box-shadow:var(--shadow-raised);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);animation:theme-menu-enter 160ms var(--ease-out)}.topbar-more-popover>.icon-btn,.topbar-more-popover>.lock-button,.topbar-more-popover>.theme-menu>.theme-trigger{width:100%;height:40px;min-height:40px;display:grid;grid-template-columns:22px minmax(0,1fr);gap:9px;place-items:center start;border:0;padding:0 10px;background:transparent}.topbar-more-popover>.language-toggle{grid-template-columns:22px minmax(0,1fr)}.topbar-more-popover>.language-toggle>span:first-child{min-width:0;justify-self:center}.topbar-more-popover .topbar-action-label,.topbar-more-popover .lock-button span{display:block;color:var(--muted-strong);font-size:.78rem;font-weight:550}.topbar-more-popover .lock-button svg{display:block;width:17px;height:17px}.topbar-more-popover>.theme-menu{width:100%}.topbar-more-popover>.theme-menu .theme-popover{position:static;width:100%;margin-top:3px;border-color:var(--border-soft);box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none}.banner{top:calc(var(--header-height) + 7px);right:12px;left:12px;font-size:.72rem}.chat-section-head{min-height:28px;padding-top:6px}.chat-section-head,.collaboration-board,.chat-empty,.unavailable-note,.collaboration-composer{width:calc(100% - 24px)}.unavailable-note{margin-top:8px;padding:7px 9px;font-size:.68rem;line-height:1.4}.collaboration-board{gap:0;padding:26px 0 30px}.chat-empty{padding:0 14px 8vh}.chat-empty strong{font-size:.95rem}.chat-empty p{max-width:330px;font-size:.72rem}.message-card + .message-card{margin-top:21px}.message-card.message-incoming + .message-card.message-incoming{margin-top:13px}.message-card.message-neutral + .message-card.message-neutral{margin-top:13px}.message-card.message-outgoing + .message-card.message-outgoing{margin-top:10px}.message-card + .message-card.message-thread{margin-top:9px}.message-card.message-incoming,.message-card.message-neutral,.message-card.message-outgoing{max-width:90%}.message-card.message-incoming .message-bubble,.message-card.message-neutral .message-bubble,.message-card.message-outgoing .message-bubble{padding:10px 14px}.message-footer{gap:3px 8px;margin-top:6px}.message-body{font-size:.9rem}.collaboration-composer{margin:7px auto max(10px,env(safe-area-inset-bottom));padding:7px 8px;border-radius:22px}.collaboration-composer textarea{min-height:44px;padding:10px 8px 7px;font-size:.85rem}.composer-toolbar{gap:6px;align-items:center}.composer-fields{gap:3px}.composer-tools-trigger{padding-right:9px}.composer-options-popover{width:min(340px,calc(100vw - 32px))}.composer-control{padding:8px}.composer-check{font-size:.64rem}.composer-actions{gap:5px}.composer-actions>span{max-width:140px;font-size:.7rem;text-align:right}.send-btn{width:38px;height:38px}.conversation-empty{width:calc(100% - 32px)}.conversation-empty{padding-top:clamp(72px,18vh,150px)}.conversation-empty p{margin-bottom:0;font-size:.76rem}.empty-orbit{width:44px;height:44px}.inspector-header{height:58px;padding:0 16px}.inspector-card{padding:15px 16px}.communication-section{padding:10px}.compact-field-grid{grid-template-columns:1fr}.operations-heading{align-items:flex-start;flex-direction:column;margin-bottom:17px}.operations-live{align-self:flex-start}.operations-card{padding:15px;border-radius:14px}.operations-card-head{gap:10px}.operations-metrics{grid-template-columns:1fr}}@media (max-width:380px){.workspace-sidebar{width:100vw;border-radius:0}.sidebar-runtime-status span{display:none}.workspace-heading strong{font-size:.78rem}.topbar-controls{padding-right:41px}.topbar-controls .language-toggle{width:36px;min-width:36px}.collaboration-composer{width:calc(100% - 16px)}.unavailable-note,.chat-section-head,.collaboration-board,.chat-empty{width:calc(100% - 20px)}.composer-actions>span{max-width:72px}.message-card.message-incoming,.message-card.message-neutral,.message-card.message-outgoing{max-width:94%}.message-thread{margin-left:16px}}.context-trigger{display:flex;justify-content:center;gap:6px;width:88px;font-size:.74rem}.topbar-controls{padding-right:96px}@media (max-width:760px){.context-trigger{width:76px;gap:4px;font-size:.7rem}.topbar-controls{padding-right:82px}}@media (max-height:620px){.auth-topbar{padding-top:18px}.gate{margin-top:14px;padding-top:18px;padding-bottom:18px}.gate-icon{width:36px;height:36px;margin-bottom:12px}.chat-section-head{min-height:22px;padding-top:2px}.collaboration-composer textarea{min-height:40px}.chat-empty{padding-bottom:3vh}}@media (pointer:coarse){.project-row,.session-card,.recent-session-row{min-height:44px}.context-trigger,.icon-btn,.send-btn,.mobile-nav-control,.inspector-close{min-width:44px;min-height:44px}.runner-filter select,.sidebar-search input,.sidebar-view-item,.operations-nav-item{min-height:44px}.message-action{width:44px;height:44px}.recent-panel-summary{min-height:44px;align-items:center}.message-actions{opacity:1}}@media (prefers-reduced-transparency:reduce){.workspace-topbar,.collaboration-composer,.composer-options-popover,.inspector-popover,.theme-popover{background:var(--surface-solid);backdrop-filter:none;-webkit-backdrop-filter:none}}@media (prefers-contrast:more){:root{--border:color-mix(in srgb,var(--text) 34%,transparent);--border-soft:color-mix(in srgb,var(--text) 20%,transparent)}.workspace-topbar,.collaboration-composer,.composer-options-popover,.inspector-popover,.theme-popover{background:var(--surface-solid)}}@supports not ((backdrop-filter:blur(2px)) or (-webkit-backdrop-filter:blur(2px))){.workspace-sidebar,.workspace-main,.gate,.composer-options-popover,.inspector-popover,.theme-popover{background:var(--surface-solid)}.collaboration-composer{background:var(--surface-solid)}}@media (forced-colors:active){body{background:Canvas}.workspace-sidebar,.workspace-main,.gate,.composer-options-popover,.inspector-popover,.theme-popover,.collaboration-composer{background:Canvas;box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none}.project-row.selected,.session-card.selected,.theme-option[aria-pressed="true"]{outline:2px solid Highlight;outline-offset:-2px}}@media (prefers-reduced-motion:reduce){*,*::before,*::after{scroll-behavior:auto !important;animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.01ms !important}} diff --git a/frontend/dist/runtime.html b/frontend/dist/runtime.html index 3f89e49c..c6bd3216 100644 --- a/frontend/dist/runtime.html +++ b/frontend/dist/runtime.html @@ -136,7 +136,7 @@

Sessions

-
+
Recent Sessions @@ -154,15 +154,15 @@

Runtime workspace

Local

Inspect infrastructure and manage durable Agents without mixing administration into the current Session.

- - - @@ -349,7 +349,7 @@

Runtime & Agents

-
+ -
+ diff --git a/frontend/dist/runtime.js b/frontend/dist/runtime.js index 60552046..528e46de 100644 --- a/frontend/dist/runtime.js +++ b/frontend/dist/runtime.js @@ -836,6 +836,8 @@ const RUNTIME_ZH_TEXT = { "Runtime workspace": "运行时工作区", "Inspect infrastructure and manage durable Agents without mixing administration into the current Session.": "检查基础设施并管理持久 Agent,同时避免将管理操作混入当前会话。", "Overview": "概览", + "Details": "详情", + "Session context views": "会话上下文视图", "Server health and fleet capacity": "服务器健康状态与设备群容量", "Runner fleet": "运行器设备群", "Devices, builds and current load": "设备、构建与当前负载", @@ -1424,14 +1426,22 @@ function applyWorkspaceView(view, persist = true) { } function revealOperationsSection(targetId) { applyWorkspaceView("operations"); - document.querySelectorAll("[data-operations-target]").forEach((button) => { - button.classList.toggle("selected", button.dataset.operationsTarget === targetId); - }); - const target = el(targetId); - window.requestAnimationFrame(() => { - target?.scrollIntoView({ behavior: window.matchMedia("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth", block: "start" }); - target?.focus({ preventScroll: true }); + const buttons = document.querySelectorAll("[data-operations-target]"); + if (!Array.from(buttons).some((button) => button.dataset.operationsTarget === targetId)) + return; + buttons.forEach((button) => { + const selected = button.dataset.operationsTarget === targetId; + button.classList.toggle("selected", selected); + if (selected) + button.setAttribute("aria-current", "page"); + else + button.removeAttribute("aria-current"); + show(String(button.dataset.operationsTarget), selected); }); + const scroll = document.querySelector(".operations-scroll"); + if (scroll) + scroll.scrollTop = 0; + el(targetId)?.focus({ preventScroll: true }); } function setRuntimeConnectionState(connection) { const label = connection === "connected" @@ -1543,7 +1553,10 @@ function setMobileNavigationOpen(open, restoreFocus = false) { closeAppearanceMenus(false); closeTopbarMore(false); closeRuntimeInspector(false); - window.setTimeout(() => close?.focus(), 260); + window.setTimeout(() => { + if (mobileNavigationViewport() && shell?.classList.contains("mobile-nav-open")) + close?.focus(); + }, 260); } else if (restoreFocus && mobile) { window.setTimeout(() => toggle?.focus(), 0); @@ -5032,6 +5045,15 @@ document.querySelector(".context-trigger")?.addEventListener("click", (event) => document.querySelectorAll("[data-runtime-view]").forEach((button) => { button.addEventListener("click", () => applyWorkspaceView(workspaceViewPreference(button.dataset.runtimeView))); }); +document.querySelectorAll("[data-context-target]").forEach((button) => { + button.addEventListener("click", () => { + document.querySelectorAll("[data-context-target]").forEach((item) => { + const selected = item === button; + item.setAttribute("aria-pressed", String(selected)); + show(String(item.dataset.contextTarget), selected); + }); + }); +}); document.querySelectorAll("[data-operations-target]").forEach((button) => { button.addEventListener("click", () => revealOperationsSection(String(button.dataset.operationsTarget || "runtime-operations-overview"))); }); diff --git a/frontend/src/runtime.css b/frontend/src/runtime.css index 8e834814..dd0ceecd 100644 --- a/frontend/src/runtime.css +++ b/frontend/src/runtime.css @@ -558,7 +558,7 @@ h4 { margin-bottom: 5px; color: var(--muted); font-size: .7rem; letter-spacing: .operations-heading h2 { margin: 1px 0 7px; font-size: clamp(1.35rem, 2vw, 1.75rem); font-weight: 620; letter-spacing: -.035em; } .operations-heading p:last-child { max-width: 680px; margin-bottom: 0; line-height: 1.55; } .operations-live { display: inline-flex; gap: 7px; align-items: center; border: 1px solid var(--border-soft); border-radius: 999px; padding: 7px 10px; background: var(--surface-soft); color: var(--muted-strong); font-size: .74rem; white-space: nowrap; } -.operations-layout { width: min(1440px, 100%); margin: 0 auto; display: grid; grid-template-columns: minmax(0, .82fr) minmax(0, 1.18fr); gap: 14px; align-items: start; } +.operations-layout { width: min(1440px, 100%); margin: 0 auto; display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; align-items: start; } .operations-card { min-width: 0; scroll-margin-top: 20px; border: 1px solid var(--border-soft); border-radius: 16px; padding: 18px; background: color-mix(in srgb, var(--surface) 72%, transparent); box-shadow: 0 1px 0 color-mix(in srgb, var(--text) 3%, transparent); } .operations-card:focus { outline: none; } .operations-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; } @@ -570,7 +570,7 @@ h4 { margin-bottom: 5px; color: var(--muted); font-size: .7rem; letter-spacing: .operations-metrics .metric { min-height: 78px; grid-template-columns: 1fr; gap: 4px; align-content: center; border: 0; border-radius: 12px; padding: 12px 13px; background: var(--surface-inset); } .operations-metrics .metric > .small { grid-column: 1; } .operations-metrics .metric strong { font-size: .88rem; } -.operations-runners .fleet-list { max-height: 420px; margin-top: 0; } +.operations-runners .fleet-list { max-height: none; margin-top: 0; } .operations-agents .communication-grid { grid-template-columns: minmax(300px, .85fr) minmax(360px, 1.15fr); gap: 12px; } .operations-agents .communication-agents, .operations-agents .communication-conversations { align-content: start; } @@ -583,7 +583,7 @@ h4 { margin-bottom: 5px; color: var(--muted); font-size: .7rem; letter-spacing: .runtime-shell[data-workspace-view="operations"] .session-state-chips { display: none; } /* Runtime context is a popover by default and becomes a useful Session rail on wide workspaces. */ -.runtime-inspector { position: absolute; z-index: 20; top: 0; right: 0; } +.runtime-inspector { position: absolute; z-index: 50; top: 0; right: 0; } .runtime-inspector { display: none; } .runtime-has-session .runtime-inspector { display: block; } .runtime-operations-view .runtime-inspector { display: none; } @@ -614,13 +614,12 @@ body:not(.runtime-has-session) .topbar-controls { padding-right: 0; } .inspector-card[open] > summary::before { transform: rotate(90deg); } .inspector-card > summary > :nth-child(2) { max-width: 48%; overflow: hidden; text-align: right; text-overflow: ellipsis; white-space: nowrap; } .inspector-card-head { display: flex; justify-content: space-between; gap: 10px; align-items: baseline; margin-bottom: 9px; } -.session-evidence { margin-top: 11px; border-top: 1px solid var(--border-soft); } -.session-evidence > summary { min-height: 38px; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 8px; align-items: center; color: var(--muted-strong); font-size: .7rem; font-weight: 620; cursor: pointer; list-style: none; } -.session-evidence > summary::-webkit-details-marker { display: none; } -.session-evidence > summary::before { content: "›"; color: var(--muted); transition: transform 140ms var(--ease-out); } -.session-evidence[open] > summary::before { transform: rotate(90deg); } -.session-evidence > summary > :last-child { overflow: hidden; color: var(--placeholder); font-weight: 450; text-align: right; text-overflow: ellipsis; white-space: nowrap; } -.session-evidence-body { padding-top: 1px; } +.context-navigation { position: sticky; top: -15px; z-index: 1; display: flex; gap: 4px; margin: -1px 0 16px; padding: 5px; border: 1px solid var(--border-soft); border-radius: 12px; background: var(--surface-solid); } +.context-navigation button { flex: 1; min-width: 0; min-height: 40px; border: 0; border-radius: 8px; background: transparent; color: var(--muted-strong); font: inherit; font-size: .78rem; cursor: pointer; } +.context-navigation button:hover { background: var(--sidebar-hover); color: var(--text); } +.context-navigation button[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent); font-weight: 650; } +.context-navigation button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; } + .session-identity { display: grid; grid-template-columns: 1fr; gap: 7px; margin: 8px 0; padding: 10px; border: 1px solid var(--border-soft); border-radius: 10px; background: var(--surface-inset); box-shadow: none; } .session-identity-fact { min-width: 0; display: grid; gap: 2px; } .session-identity-value { overflow-wrap: anywhere; } @@ -896,6 +895,14 @@ body:not(.runtime-has-session) .topbar-controls { padding-right: 0; } .message-thread { margin-left: 16px; } } +/* Keep the Session context entry discoverable when its panel is closed. */ +.context-trigger { display: flex; justify-content: center; gap: 6px; width: 88px; font-size: .74rem; } +.topbar-controls { padding-right: 96px; } +@media (max-width: 760px) { + .context-trigger { width: 76px; gap: 4px; font-size: .7rem; } + .topbar-controls { padding-right: 82px; } +} + @media (max-height: 620px) { .auth-topbar { padding-top: 18px; } .gate { margin-top: 14px; padding-top: 18px; padding-bottom: 18px; } diff --git a/frontend/src/runtime.html b/frontend/src/runtime.html index 3f89e49c..c6bd3216 100644 --- a/frontend/src/runtime.html +++ b/frontend/src/runtime.html @@ -136,7 +136,7 @@

Sessions

-
+
Recent Sessions @@ -154,15 +154,15 @@

Runtime workspace

Local

Inspect infrastructure and manage durable Agents without mixing administration into the current Session.

- - - @@ -349,7 +349,7 @@

Runtime & Agents

-
+ -
+ diff --git a/frontend/src/runtime.ts b/frontend/src/runtime.ts index 2df59b77..462af980 100644 --- a/frontend/src/runtime.ts +++ b/frontend/src/runtime.ts @@ -102,6 +102,8 @@ const RUNTIME_ZH_TEXT: Record = { "Runtime workspace": "运行时工作区", "Inspect infrastructure and manage durable Agents without mixing administration into the current Session.": "检查基础设施并管理持久 Agent,同时避免将管理操作混入当前会话。", "Overview": "概览", + "Details": "详情", + "Session context views": "会话上下文视图", "Server health and fleet capacity": "服务器健康状态与设备群容量", "Runner fleet": "运行器设备群", "Devices, builds and current load": "设备、构建与当前负载", @@ -695,14 +697,18 @@ function applyWorkspaceView(view: RuntimeWorkspaceView, persist = true): void { function revealOperationsSection(targetId: string): void { applyWorkspaceView("operations"); - document.querySelectorAll("[data-operations-target]").forEach((button) => { - button.classList.toggle("selected", button.dataset.operationsTarget === targetId); - }); - const target = el(targetId); - window.requestAnimationFrame(() => { - target?.scrollIntoView({ behavior: window.matchMedia("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth", block: "start" }); - target?.focus({ preventScroll: true }); + const buttons = document.querySelectorAll("[data-operations-target]"); + if (!Array.from(buttons).some((button) => button.dataset.operationsTarget === targetId)) return; + buttons.forEach((button) => { + const selected = button.dataset.operationsTarget === targetId; + button.classList.toggle("selected", selected); + if (selected) button.setAttribute("aria-current", "page"); + else button.removeAttribute("aria-current"); + show(String(button.dataset.operationsTarget), selected); }); + const scroll = document.querySelector(".operations-scroll"); + if (scroll) scroll.scrollTop = 0; + el(targetId)?.focus({ preventScroll: true }); } type RuntimeConnectionState = "connected" | "connecting" | "stale" | "disconnected"; @@ -816,7 +822,9 @@ function setMobileNavigationOpen(open: boolean, restoreFocus = false): void { closeAppearanceMenus(false); closeTopbarMore(false); closeRuntimeInspector(false); - window.setTimeout(() => close?.focus(), 260); + window.setTimeout(() => { + if (mobileNavigationViewport() && shell?.classList.contains("mobile-nav-open")) close?.focus(); + }, 260); } else if (restoreFocus && mobile) { window.setTimeout(() => toggle?.focus(), 0); } @@ -3941,6 +3949,15 @@ document.querySelector(".context-trigger")?.addEventListener("click", (event) => document.querySelectorAll("[data-runtime-view]").forEach((button) => { button.addEventListener("click", () => applyWorkspaceView(workspaceViewPreference(button.dataset.runtimeView))); }); +document.querySelectorAll("[data-context-target]").forEach((button) => { + button.addEventListener("click", () => { + document.querySelectorAll("[data-context-target]").forEach((item) => { + const selected = item === button; + item.setAttribute("aria-pressed", String(selected)); + show(String(item.dataset.contextTarget), selected); + }); + }); +}); document.querySelectorAll("[data-operations-target]").forEach((button) => { button.addEventListener("click", () => revealOperationsSection(String(button.dataset.operationsTarget || "runtime-operations-overview"))); }); diff --git a/frontend/test/build.test.mjs b/frontend/test/build.test.mjs index 79f94728..69e13032 100644 --- a/frontend/test/build.test.mjs +++ b/frontend/test/build.test.mjs @@ -224,7 +224,7 @@ async function assertRequiredAssets(outputDirectory) { assert.match(runtimeStyles, /send-btn\.is-ready/); assert.match(runtimeStyles, /session-state-chips \.chip:not\(:last-child\)\{display:none/); assert.match(runtimeStyles, /message-card\.message-group-continuation \.message-author\{display:none/); - assert.match(runtimeStyles, /session-evidence/); + assert.match(runtimeStyles, /context-navigation/); await exec(process.execPath, ["--check", resolve(outputDirectory, "app.js")]); const admin = await readFile(resolve(outputDirectory, "admin.js"), "utf8"); await exec(process.execPath, ["--check", resolve(outputDirectory, "admin.js")]); diff --git a/frontend/test/runtime_console_state.test.mjs b/frontend/test/runtime_console_state.test.mjs index a17470be..041d10ab 100644 --- a/frontend/test/runtime_console_state.test.mjs +++ b/frontend/test/runtime_console_state.test.mjs @@ -550,8 +550,8 @@ test("runtime collaboration rendering uses textContent and explicitly reloads on assert.match(html, /runtime-session-context-lifecycle/); assert.match(html, /runtime-session-context-mode/); assert.match(css, /\.session-identity/); - assert.match(html, /class="session-evidence"/); - assert.match(html, /Details & activity/); + assert.match(html, /class="context-navigation"/); + assert.match(html, /data-context-target="runtime-context-activity"/); assert.match(html, /workspace path/); assert.match(html, /class="recent-panel-title">Recent Sessions<\/span>/); assert.match(html, /id="runtime-inspector-close"[^>]*aria-label="Close session context"/); @@ -1161,7 +1161,7 @@ test("navigation and inspector source contracts maintain disclosure hierarchy an ]); // P3: Recent Sessions component semantics - clean class, no legacy sidebar-details overrides - assert.match(html, /
/); + assert.match(html, /
/); assert.match(html, /Recent Sessions<\/span>/); assert.doesNotMatch(html, /class="[^"]*sidebar-details/); assert.doesNotMatch(css, /\.sidebar-details/); diff --git a/frontend/test/runtime_navigation.test.mjs b/frontend/test/runtime_navigation.test.mjs new file mode 100644 index 00000000..3abb38bf --- /dev/null +++ b/frontend/test/runtime_navigation.test.mjs @@ -0,0 +1,87 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { readFile } from "node:fs/promises"; +import vm from "node:vm"; + +test("operation navigation shows one destination and moves focus without replacing its form", async () => { + const source = await readFile(new URL("../dist/runtime.js", import.meta.url), "utf8"); + const start = source.indexOf("function revealOperationsSection("); + const end = source.indexOf("\n}", start) + 2; + const names = ["overview", "runners", "agents"].map((name) => "runtime-operations-" + name); + let focused; + const panels = new Map(names.map((id) => [id, { + hidden: id !== names[0], + draft: "unsent message", + focus() { focused = id; }, + }])); + const buttons = names.map((id) => ({ + dataset: { operationsTarget: id }, + attrs: {}, + classList: { toggle() {} }, + setAttribute(key, value) { this.attrs[key] = value; }, + removeAttribute(key) { delete this.attrs[key]; }, + })); + const scroll = { scrollTop: 800 }; + const context = vm.createContext({ + document: { querySelectorAll: () => buttons, querySelector: () => scroll }, + applyWorkspaceView() {}, + show(id, visible) { panels.get(id).hidden = !visible; }, + el: (id) => panels.get(id), + }); + vm.runInContext(source.slice(start, end), context); + for (const id of [names[2], names[1], names[0], names[2]]) { + context.revealOperationsSection(id); + assert.deepEqual([...panels].filter(([, panel]) => !panel.hidden).map(([key]) => key), [id]); + assert.deepEqual(buttons.filter((button) => button.attrs["aria-current"] === "page").map((button) => button.dataset.operationsTarget), [id]); + assert.equal(focused, id); + assert.equal(scroll.scrollTop, 0); + assert.equal(panels.get(id).draft, "unsent message"); + } + context.revealOperationsSection("invalid"); + assert.equal(focused, names[2]); + assert.equal(panels.get(names[2]).hidden, false); +}); + +test("context overview exposes validation while activity and identity have direct entries", async () => { + const html = await readFile(new URL("../src/runtime.html", import.meta.url), "utf8"); + const overview = html.slice(html.indexOf('
{ + const source = await readFile(new URL("../dist/runtime.js", import.meta.url), "utf8"); + const start = source.indexOf("function setMobileNavigationOpen("); + const end = source.indexOf("\n}", start) + 2; + const classes = new Set(); + const callbacks = []; + let focused = false; + const shell = { classList: { + toggle(name, enabled) { if (enabled) classes.add(name); else classes.delete(name); }, + contains(name) { return classes.has(name); }, + } }; + const context = vm.createContext({ + el(id) { + if (id === "runtime-console") return shell; + if (id === "runtime-mobile-nav-close") return { focus() { focused = true; } }; + return { setAttribute() {}, removeAttribute() {} }; + }, + mobileNavigationViewport: () => true, + closeAppearanceMenus() {}, + closeTopbarMore() {}, + closeRuntimeInspector() {}, + window: { setTimeout(callback) { callbacks.push(callback); } }, + }); + vm.runInContext(source.slice(start, end), context); + context.setMobileNavigationOpen(true); + context.setMobileNavigationOpen(false); + callbacks.shift()(); + assert.equal(focused, false); + context.setMobileNavigationOpen(true); + callbacks.shift()(); + assert.equal(focused, true); +}); diff --git a/src/tool_runtime/startup_brief.rs b/src/tool_runtime/startup_brief.rs index d8dddebc..ead55d96 100644 --- a/src/tool_runtime/startup_brief.rs +++ b/src/tool_runtime/startup_brief.rs @@ -55,38 +55,41 @@ pub(crate) fn builtin_coding_workflow_projection() -> Value { "contract": BUILTIN_CODING_WORKFLOW_CONTRACT, "version": BUILTIN_CODING_WORKFLOW_VERSION, "authority": "model_guidance_only", - "role_selection": "Apply a named role only when the task says so; role guidance creates no Session mode or authority.", + "role_selection": "Default guidance always applies; named roles only when requested. Neither grants authority.", + "guidance": [ + "Defaults only: follow host safety, user scope, and project rules; guidance grants no authority.", + "Complete authorized work through validation and review; ask only for missing requirements or authority.", + "Verify Project, branch, HEAD, and existing changes; read nested rules for changed paths and recover truncated instructions.", + "Preserve unrelated work; make the smallest coherent change. Push/publish/deploy/restart need an explicit action and target.", + "Use structured tools and edit guards; apply model_protocol only where the exposed schema supports it.", + "Use the smallest meaningful validation; reuse unchanged-source/input evidence. Zero tests are not test coverage.", + "Observe existing Jobs; inspect state before retrying an unknown outcome. Timeout does not prove no effect.", + "Review the diff; report evidence, limits, and Jobs. finish_coding_task is advisory evidence, not proof." + ], "model_protocol": { - "session_context_ack": "Copy returned session_context_revision exactly to ack_session_context_revision; never derive it. No revision: keep the last ACK; if unknown, omit. Missing/invalid recovers a compact current handoff; stale may recover a bounded delta. Recovery is nonblocking.", - "session_recording": "After work_on_project creates or resumes a Workflow Session, pass it as recording_session_id. This is recorder provenance only; business session_id may target another Session, and recording_session_id grants no authority.", - "session_message_ack": "When session_attention has open requires_ack guidance still in context, echo its id in ack_session_message_ids. This request-scoped model-context proof neither resolves messages nor grants authority or gates execution.", - "session_message_resolution": "Resolve a handled non-todo by attaching session_message_resolution to the next ordinary call with recording_session_id; ACK-required guidance also needs ack_session_message_ids. It cannot predict the main call. Todos use complete_session_message.", - "context_sidecar": "context_request adds bounded context after the main tool and never authorizes its effect. Recover lost project.instructions on an observation call before dependent mutation.", - "runner_targeting": "When the user supplies an exact Runner client_id, query that Runner with runtime_status(client_id=...) or list_projects(client_id=...) before treating it as absent from a broad fleet snapshot.", - "persistent_shell": "For repeated commands in one Workflow Session, especially on a named SSH resource, prefer open_session_shell plus session_shell_exec. Keep run_process for isolated one-shot native commands.", - "normal_closeout": "Normal success: finish_coding_task(summary_only=true); full closeout only for unresolved validation/evidence or handoff/debug detail." + "session_context_ack": "Echo session_context_revision exactly in ack_session_context_revision; never derive it. No revision: keep prior ACK; if unknown, omit. Missing/invalid recovers compact handoff; stale may recover delta. Nonblocking.", + "session_recording": "When work_on_project creates or resumes, pass recording_session_id for recorder provenance only. business session_id may target another Session; it grants no authority.", + "session_message_ack": "For retained session_attention requires_ack guidance, echo ack_session_message_ids. This request-scoped model-context proof neither resolves messages, grants authority, nor gates execution.", + "session_message_resolution": "For a handled non-todo, send session_message_resolution on the next ordinary call with recording_session_id; ACK guidance also needs ack_session_message_ids. It cannot predict the main call. Todos use complete_session_message.", + "context_sidecar": "context_request adds bounded context after the main tool and never authorizes effects. Recover lost project.instructions with an observation call before dependent mutation.", + "runner_targeting": "For exact Runner client_id, use runtime_status(client_id=...) or list_projects(client_id=...) before treating it as absent.", + "persistent_shell": "For repeated commands in one Workflow Session, especially a named SSH resource, prefer open_session_shell + session_shell_exec; use run_process for isolated commands.", + "normal_closeout": "Normal success: finish_coding_task(summary_only=true); full closeout only for unresolved evidence or handoff/debug." }, "roles": { "implementation_owner": { - "purpose": "Implement one coherent change through the authoritative architecture.", + "purpose": "Implement one coherent change end to end.", "guidance": [ - "Map the authoritative vertical slice before editing.", - "Close it end to end before local hardening.", - "Minimize new concepts, not touched-file count.", - "Use compiler/schema/exhaustiveness failures to find missing adapters and projections.", - "When intentionally rerunning the same logical validation, reuse the same assertion_name; do not rerun solely to clear stale historical validation evidence.", - "After validation, review completeness, trust, bounds, privacy, and replay.", - "Fix discovered correctness issues; do not fragment the change around speculative concerns." + "Map cross-layer changes end to end; use compiler/schema/exhaustiveness failures to find missing integration.", + "Minimize concepts; fix concrete issues without speculative redesign.", + "When intentionally rerunning the same logical validation, reuse the same assertion_name; do not rerun solely to clear stale historical validation evidence." ] }, "independent_review": { - "purpose": "Independently challenge the change and correct concrete findings.", + "purpose": "Review independently within task scope.", "guidance": [ - "Inspect independently; do not assume the implementation pass was correct.", - "Challenge contracts and invariants before trusting passing tests.", - "Focus on authority, bounds, malformed data, privacy, replay/races, timeout/correlation, and fail-closed behavior.", - "Correct concrete findings and add focused regression evidence.", - "Do not broaden into unrelated redesign." + "Challenge authority, bounds, malformed data, privacy, replay/races, timeouts, and fail-closed behavior.", + "For review-only tasks, report concrete findings with file/line evidence and impact; do not edit. Fix only when the task authorizes corrections, with focused regression validation." ] } } diff --git a/src/tool_runtime/tests/builtin_coding_workflow.rs b/src/tool_runtime/tests/builtin_coding_workflow.rs new file mode 100644 index 00000000..c7db77fb --- /dev/null +++ b/src/tool_runtime/tests/builtin_coding_workflow.rs @@ -0,0 +1,76 @@ +use crate::tool_runtime::registry; +use crate::tool_runtime::startup_brief::{ + builtin_coding_workflow_projection, validate_schema_instance_for_test, + BUILTIN_CODING_WORKFLOW_MAX_GUIDANCE_ITEMS, +}; +use serde_json::{json, Value}; + +fn workflow_schema() -> Value { + registry::output_schema_for_tool("work_on_project")["properties"]["output"]["properties"] + ["workflow"] + .clone() +} + +#[test] +fn builtin_coding_workflow_defaults_are_required_and_bounded() { + let workflow = builtin_coding_workflow_projection(); + let schema = workflow_schema(); + validate_schema_instance_for_test(&workflow, &schema).unwrap(); + + let mut missing = workflow.clone(); + missing.as_object_mut().unwrap().remove("guidance"); + assert!(validate_schema_instance_for_test(&missing, &schema).is_err()); + + for guidance in [ + json!([]), + json!(vec!["rule"; BUILTIN_CODING_WORKFLOW_MAX_GUIDANCE_ITEMS + 1]), + json!(["x".repeat(321)]), + ] { + let mut invalid = workflow.clone(); + invalid["guidance"] = guidance; + assert!(validate_schema_instance_for_test(&invalid, &schema).is_err()); + } +} + +#[test] +fn builtin_coding_workflow_defaults_cover_unnamed_tasks_without_granting_authority() { + let workflow = builtin_coding_workflow_projection(); + assert_eq!(workflow["authority"], "model_guidance_only"); + assert!(workflow["role_selection"] + .as_str() + .unwrap() + .contains("Default guidance always applies")); + let defaults = workflow["guidance"] + .as_array() + .unwrap() + .iter() + .map(|item| item.as_str().unwrap()) + .collect::>() + .join("\n"); + for boundary in [ + "guidance grants no authority", + "explicit action and target", + "nested rules for changed paths", + "recover truncated instructions", + "only where the exposed schema supports it", + "unknown outcome", + "Zero tests are not test coverage", + "advisory evidence, not proof", + ] { + assert!(defaults.contains(boundary), "missing guidance: {boundary}"); + } +} + +#[test] +fn builtin_coding_workflow_review_does_not_implicitly_authorize_edits() { + let workflow = builtin_coding_workflow_projection(); + let review = workflow["roles"]["independent_review"]["guidance"] + .as_array() + .unwrap(); + assert!(review.iter().any(|item| { + let text = item.as_str().unwrap(); + text.contains("review-only") + && text.contains("do not edit") + && text.contains("only when the task authorizes corrections") + })); +} diff --git a/src/tool_runtime/tests/context_projection.rs b/src/tool_runtime/tests/context_projection.rs index de2decb3..0209aa2e 100644 --- a/src/tool_runtime/tests/context_projection.rs +++ b/src/tool_runtime/tests/context_projection.rs @@ -113,6 +113,11 @@ async fn context_projection_is_explicit_deduped_open_ended_and_nonfatal() { .unwrap(); assert_eq!(materials.len(), 3, "duplicates must be projected once"); assert_eq!(materials[0]["key"], "webcodex.workflow"); + assert_eq!( + materials[0]["projection"], + crate::tool_runtime::startup_brief::builtin_coding_workflow_projection(), + "context recovery must return the same guidance as coding startup" + ); assert_eq!(materials[0]["status"], "available"); assert_eq!( materials[0]["projection"]["contract"], diff --git a/src/tool_runtime/tests/mod.rs b/src/tool_runtime/tests/mod.rs index cde0ad24..9dd93d57 100644 --- a/src/tool_runtime/tests/mod.rs +++ b/src/tool_runtime/tests/mod.rs @@ -5,6 +5,7 @@ mod support; mod agent_tasks; mod apply_text_edits; mod assignment_fence; +mod builtin_coding_workflow; mod checkpoint; mod coding_task; mod coding_task_semantic_navigation; diff --git a/src/tool_runtime/tests/startup_brief.rs b/src/tool_runtime/tests/startup_brief.rs index 37ca3aa1..8db0afe8 100644 --- a/src/tool_runtime/tests/startup_brief.rs +++ b/src/tool_runtime/tests/startup_brief.rs @@ -108,7 +108,7 @@ fn instruction_source<'a>(output: &'a Value, path: &str) -> &'a Value { fn assert_builtin_workflow(output: &Value) { let workflow = &output["workflow"]; assert_eq!(workflow["contract"], "webcodex.coding_workflow"); - assert_eq!(workflow["version"], 6); + assert_eq!(workflow["version"], 7); assert_eq!(workflow["authority"], "model_guidance_only"); assert!(workflow["role_selection"] .as_str() @@ -117,14 +117,14 @@ fn assert_builtin_workflow(output: &Value) { .as_str() .expect("Session context ACK guidance"); assert!(ack_guidance.contains("ack_session_context_revision")); - assert!(ack_guidance.contains("returned session_context_revision exactly")); + assert!(ack_guidance.contains("session_context_revision exactly")); assert!(ack_guidance.contains("never derive it")); - assert!(ack_guidance.contains("No revision: keep the last ACK")); + assert!(ack_guidance.contains("No revision")); assert!(ack_guidance.contains("if unknown, omit")); assert!(ack_guidance.contains("Missing/invalid")); - assert!(ack_guidance.contains("compact current handoff")); + assert!(ack_guidance.contains("compact handoff")); assert!(ack_guidance.contains("stale may recover")); - assert!(ack_guidance.contains("nonblocking")); + assert!(ack_guidance.contains("Nonblocking")); let recording_guidance = workflow["model_protocol"]["session_recording"] .as_str() .expect("Session recording guidance"); @@ -132,7 +132,7 @@ fn assert_builtin_workflow(output: &Value) { assert!(recording_guidance.contains("recording_session_id")); assert!(recording_guidance.contains("recorder provenance only")); assert!(recording_guidance.contains("business session_id may target another Session")); - assert!(recording_guidance.contains("recording_session_id grants no authority")); + assert!(recording_guidance.contains("grants no authority")); let message_ack_guidance = workflow["model_protocol"]["session_message_ack"] .as_str() .expect("Session message ACK guidance");