Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions desktop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ See [中文说明](README.zh.md), [security boundary](SECURITY.md), and [validat

## Observation

The sidebar provides Overview, Connections, Memories, and Observation, with Settings & diagnostics at the bottom. Overview is the initial page. Observation contains Runtime state, Current-Scope inventory & usage, and This session tabs. Inventory & usage hosts the qualified Statistics view; This session reads native session observations. Runtime state remains explicitly unavailable until integrated. Opening the page or switching tabs does not run connection checks or local diagnostics. English/Chinese and existing theme settings apply to Observation.
The sidebar provides Overview, Connections, Memories, and Observation, with Settings & diagnostics at the bottom. Overview is the initial page. Observation contains Runtime state, Current-Scope inventory & usage, and This session tabs. Inventory & usage hosts the qualified Statistics view; This session reads native session observations. Opening the page or switching tabs does not run connection checks or local diagnostics. English/Chinese and existing theme settings apply to Observation.

**Observation → Runtime state** shows the selected Server's liveness and available capabilities, with separate UTC
snapshots and process-level Memory extraction history. Refresh does not probe models. **Probe readiness** is a separate,
explicit action for a qualified connection with current observation access; it may contact configured dependencies.
Local Ops inspection and registered CLI diagnostics describe this computer and work independently of the remote Server.
Installation, recovery and service changes belong in **Local Server settings**. Local states are shown only when the
native service manager or helper reports them; an unreachable HTTP endpoint does not establish that a service is stopped
or starting.

The native host collects a bounded, in-memory window of HTTP requests and Memory/Scope user operations independently of page navigation. Trusted typed IPC provides an allowlisted summary, reset and safe JSON preview. The window retains at most 512 terminal records; it preserves cancellation and unknown-write outcomes and contains no content or target identities. See the [session observation contract](../docs/en/development/desktop-session-observations.md) for measurement units, coverage, reset and failure isolation. This session shows separate request/action counts, outcomes and millisecond latency, UTC snapshot/retention coverage, manual refresh and confirmed reset. **Preview safe diagnostic summary** opens the exact native text; copying is a separate explicit action with feedback and selectable text for manual recovery. Leaving the view or changing context closes its preview and discards late UI responses.

Expand All @@ -17,7 +25,7 @@ with independent retention/loss coverage, and contribute no HTTP or Memory/Scope

## Shared feedback and current context

Every page uses the same loading, empty, unavailable and error presentation. Loading local state is distinct from being disconnected; a local-state failure offers **Reload local state**, without probing Server readiness. Empty search results mean no matches for that query, not an empty Scope inventory. Unimplemented Observation views remain unavailable.
Every page uses the same loading, empty, unavailable and error presentation. Loading local state is distinct from being disconnected; a local-state failure offers **Reload local state**, without probing Server readiness. Empty search results mean no matches for that query, not an empty Scope inventory.

Errors explain the affected operation and recovery. Read failures offer an explicit retry; exact reads retain the original Artifact revision. An expired Scope cursor restarts from the first page. Credential, permission and compatibility failures explain the required configuration or authorization change. Save failures keep the draft; unknown writes retain their original target and require the existing confirmation before another submission. Writes are never replayed automatically. Local diagnostic failures offer a retry of the same selected local check and do not indicate remote unavailability.

Expand Down
7 changes: 6 additions & 1 deletion desktop/README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@

## 观察

侧栏提供总览、连接、记忆、观察入口,“设置与诊断”位于侧栏底部。默认进入总览。“观察”包含运行状态、当前 Scope 库存与用量、本次会话三个标签页。库存与用量已接入统计视图;本次会话读取原生会话观察。运行状态接入前明确显示尚未可用。进入页面或切换标签不会执行连接检查或本机诊断。观察页面沿用现有中英文和主题设置。
**观察 → 运行状态**分别显示当前 Server 的存活、能力和进程级记忆提取历史,并标明各自的 UTC 快照时间。
普通刷新不探测模型。连接具备兼容资格和当前观察权限时,可以单独点击**探测就绪状态**,该操作可能访问已配置的依赖。
本机 Ops 检查和已登记的 CLI 诊断只描述此电脑,与远程 Server 无关。安装、恢复及服务变更请前往**本机 Server 设置**。
本机状态以服务管理器或可信助手明确报告的事实为准;仅凭 HTTP 无法访问不能判断服务已停止或正在启动。

侧栏提供总览、连接、记忆、观察入口,“设置与诊断”位于侧栏底部。默认进入总览。“观察”包含运行状态、当前 Scope 库存与用量、本次会话三个标签页。库存与用量已接入统计视图;本次会话读取原生会话观察。进入页面或切换标签不会执行连接检查或本机诊断。观察页面沿用现有中英文和主题设置。

原生宿主独立于页面导航,采集有界的内存窗口,分别记录 HTTP 请求和 Memory/Scope 用户操作。可信的类型化 IPC 提供白名单摘要、重置和安全 JSON 预览。窗口最多保留 512 条终态记录,保留取消及未知写入的区别,不包含内容或目标身份。测量单位、覆盖范围、重置和故障隔离见[会话观察契约](../docs/zh/development/desktop-session-observations.md)。本次会话分别显示请求与操作的数量、结果和毫秒延迟,以及 UTC 快照时间和保留范围;支持手动刷新和确认后重置。“预览安全诊断摘要”展示原生生成的准确文本,复制是独立的显式操作,提供成功或失败反馈及可选择的手动复制文本。离开视图或切换上下文会关闭预览并丢弃晚到的界面响应。

Expand Down
4 changes: 4 additions & 0 deletions desktop/src-tauri/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ fn main() {
"search_memory",
"atomic_memory_entry",
"cancel_memory_reads",
"observe_runtime_liveness",
"observe_runtime_capabilities",
"probe_runtime_readiness",
"cancel_runtime_reads",
"get_stats",
"cancel_stats_reads",
"desktop_state",
Expand Down
4 changes: 4 additions & 0 deletions desktop/src-tauri/capabilities/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
"allow-search-memory",
"allow-atomic-memory-entry",
"allow-cancel-memory-reads",
"allow-observe-runtime-liveness",
"allow-observe-runtime-capabilities",
"allow-probe-runtime-readiness",
"allow-cancel-runtime-reads",
"allow-get-stats",
"allow-cancel-stats-reads",
"allow-desktop-state",
Expand Down
4 changes: 3 additions & 1 deletion desktop/src-tauri/examples/export_ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use powercontext_desktop::{
profiles::{Authentication, CredentialState, ProfileInput, ProfileView},
session::{
ActiveView, CheckReport, CompatibilityProfile, DesktopState, Fact, MemoryContext,
WriteOutcome, WriteRecord, WriteStatus,
RuntimeCapabilities, RuntimeFact, WriteOutcome, WriteRecord, WriteStatus,
},
},
credentials::{CredentialWriteReceipt, CredentialWriteRequest, StorageChoice},
Expand Down Expand Up @@ -118,6 +118,8 @@ fn main() {
ProfileInput::decl(&config),
CredentialState::decl(&config),
Fact::<String>::decl(&config),
RuntimeFact::<String>::decl(&config),
RuntimeCapabilities::decl(&config),
DiscoveryStatus::decl(&config),
CompatibilityReason::decl(&config),
CompatibilityStatus::decl(&config),
Expand Down
12 changes: 12 additions & 0 deletions desktop/src-tauri/examples/server_probe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,18 @@ async fn main() {
.any(|report| report.connection_id == profile)
);
let generation = manager.check(&profile, true).await.unwrap().generation;
// Check the real Runtime endpoints before selecting a Scope. No generation model is configured.
let live = manager.observe_runtime_liveness(generation).await.unwrap();
assert_eq!(live.fact.value.unwrap().status, "ok");
let capabilities = manager
.observe_runtime_capabilities(generation)
.await
.unwrap();
let runtime_capabilities = capabilities.fact.value.unwrap();
assert!(!runtime_capabilities.memory_extraction);
assert!(runtime_capabilities.extraction.is_some());
let readiness = manager.probe_runtime_readiness(generation).await.unwrap();
assert!(readiness.fact.value.is_some());
let generation = manager
.select_scope(generation, &fixture.scope_id)
.await
Expand Down
49 changes: 49 additions & 0 deletions desktop/src-tauri/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,55 @@ pub async fn local_diagnostics<R: tauri::Runtime>(
}
}

#[tauri::command]
pub async fn observe_runtime_liveness<R: tauri::Runtime>(
window: tauri::WebviewWindow<R>,
state: tauri::State<'_, HostState>,
generation: u32,
) -> Result<
crate::connections::session::RuntimeFact<crate::transport::wire::HealthResponse>,
ApiFailure,
> {
manager(&window, &state)?
.observe_runtime_liveness(generation)
.await
}
#[tauri::command]
pub async fn observe_runtime_capabilities<R: tauri::Runtime>(
window: tauri::WebviewWindow<R>,
state: tauri::State<'_, HostState>,
generation: u32,
) -> Result<
crate::connections::session::RuntimeFact<crate::connections::session::RuntimeCapabilities>,
ApiFailure,
> {
manager(&window, &state)?
.observe_runtime_capabilities(generation)
.await
}
#[tauri::command]
pub async fn probe_runtime_readiness<R: tauri::Runtime>(
window: tauri::WebviewWindow<R>,
state: tauri::State<'_, HostState>,
generation: u32,
) -> Result<
crate::connections::session::RuntimeFact<crate::transport::wire::ReadinessStatus>,
ApiFailure,
> {
manager(&window, &state)?
.probe_runtime_readiness(generation)
.await
}
#[tauri::command]
pub fn cancel_runtime_reads<R: tauri::Runtime>(
window: tauri::WebviewWindow<R>,
state: tauri::State<'_, HostState>,
generation: u32,
) -> Result<(), ApiFailure> {
manager(&window, &state)?
.cancel_runtime_reads(generation)
.map_err(Into::into)
}
#[tauri::command]
pub async fn get_stats<R: tauri::Runtime>(
window: tauri::WebviewWindow<R>,
Expand Down
9 changes: 9 additions & 0 deletions desktop/src-tauri/src/connections/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ use std::{
use tokio::sync::watch;
use ts_rs::TS;

mod runtime;
pub use runtime::{RuntimeCapabilities, RuntimeFact};

#[derive(Clone, Serialize, TS)]
pub struct Fact<T> {
pub value: Option<T>,
Expand Down Expand Up @@ -172,6 +175,9 @@ pub struct ConnectionManager {
writes: tokio::sync::Semaphore,
memory_reads: watch::Sender<u32>,
stats_reads: watch::Sender<u32>,
runtime_reads: watch::Sender<u32>,
runtime_slot: tokio::sync::Semaphore,
runtime_liveness_slot: tokio::sync::Semaphore,
}
impl ConnectionManager {
pub fn new(profiles: ProfileRepository) -> Self {
Expand Down Expand Up @@ -216,6 +222,9 @@ impl ConnectionManager {
writes: tokio::sync::Semaphore::new(1),
memory_reads: watch::channel(0).0,
stats_reads: watch::channel(0).0,
runtime_reads: watch::channel(0).0,
runtime_slot: tokio::sync::Semaphore::new(1),
runtime_liveness_slot: tokio::sync::Semaphore::new(1),
}
}
fn lock(&self) -> Result<std::sync::MutexGuard<'_, Inner>, SafeError> {
Expand Down
Loading
Loading