---
title: "能力查询与通用调用"
description: "Kasumi 桥接通路、能力查询、超时与取消。"
---


> 验证桥接通路、读取当前宿主能力，并在超时或取消时得到确定的请求结果。

## 模块边界

`capabilities` 覆盖最小通路和能力查询，不执行文件、窗口或系统能力。业务调用必须经过
`KSM` 根入口；直接访问 `window.chrome.webview`、`WebViewCompat` 或宿主内部对象会绕过
请求表、超时和能力缓存。

实现入口：

| 入口 | 责任 |
| --- | --- |
| `frontend/src/bridge/ksm.ts` | `KSM.initialize`、`ping`、`capabilities`、`invoke` 和生命周期 |
| `frontend/src/bridge/bus.ts` | 请求 ID、超时、取消和响应派发 |
| `frontend/src/generated/contract.ts` | 命令、事件、权限和参数校验器 |
| `protocol/commands.json` | `ping` 与 `capabilities.query` 的事实源 |

## 平台支持

| 方法 | 协议命令 | Windows | Android | 权限 |
| --- | --- | --- | --- | --- |
| `KSM.ping()` | `ping` | 支持 | 支持 | 无 |
| `KSM.capabilities()` / `KSM.get()` | `capabilities.query` | 支持 | 支持 | 无 |
| `KSM.invoke(cmd, args, timeoutMs?)` | 已注册命令 | 按平台矩阵 | 按平台矩阵 | 由命令决定 |

`capabilities.query` 返回：

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `platform` | `"windows" \| "android"` | 当前宿主平台 |
| `commands` | `string[]` | 当前平台实际注册的命令 |
| `permissions` | `string[]` | 当前已授予的权限 |

## 请求语义

`KSM.invoke` 的默认超时是 10 秒。`timeoutMs` 必须是有限正数；非法值会直接拒绝。请求发出后，
前端生成唯一 `req-<n>` ID，并保证同一请求只结算一次。

超时发生时，总线先从等待表移除请求，再尽力发送：

```json
{ "type": "cancel", "id": "req-1" }
```

随后 Promise 以 `name === "TIMEOUT"` 的 `Error` 拒绝。宿主完成得比取消更晚时，迟到响应会被
前端忽略。`KSM.dispose()` 会拒绝所有未完成请求；WebView 重载时也会清理旧请求。

`KSM.capabilities()` 会缓存查询结果。`webview.reloaded` 会清空缓存并重新查询；
`permission.request` 改变权限后不会自动刷新缓存，需要重新加载页面或重新初始化桥接。

## 示例

```ts
import { KSM, KSMWebMessageTransport } from '@kasumi/bridge';

KSM.initialize(new KSMWebMessageTransport());

const pong = await KSM.ping();
if (!pong.pong) {
  throw new Error('Kasumi ping returned an invalid result.');
}

const capabilities = await KSM.capabilities();
if (capabilities.commands.includes('window.setSize')) {
  await KSM.window.setSize({ width: 960, height: 720 });
}

try {
  await KSM.invoke('fs.stat', { path: 'app://data/config.json' }, 5000);
} catch (error) {
  if (error instanceof Error && error.name === 'TIMEOUT') {
    console.warn('stat timed out');
  }
}
```

## 错误行为

| 情况 | 结果 |
| --- | --- |
| 桥接尚未初始化 | 普通 `Error`，提示先调用 `KSM.initialize` |
| 参数不符合生成契约 | `name === "INVALID_ARGS"` |
| 命令未注册 | `name === "UNKNOWN_COMMAND"` |
| 请求超时 | `name === "TIMEOUT"` |
| 请求被取消 | `name === "CANCELLED"` |
| 当前平台不支持 | `name === "NOT_SUPPORTED"` |

前端参数校验不能替代宿主校验。绕过封装直接调用 `KSM.invoke` 时，宿主仍会检查参数、权限和
平台矩阵。

## 平台差异

两个平台的协议字段一致，但 `commands` 和 `permissions` 内容不同。Windows 不注册
`device.getInfo`；Android 不注册 Windows 专属窗口命令。业务代码应检查能力列表，不要复制
平台命令清单。

## 排查路径

1. 确认 `KSM.initialize` 已执行，且页面通过受信任来源加载。
2. 确认 `KSM.ping()` 能返回 `{ pong: true }`。
3. 确认 `capabilities.commands` 包含目标命令。
4. 确认目标权限已出现在 `capabilities.permissions` 中。
5. 超时后检查宿主是否收到 `cancel`，以及任务是否真的中止。
6. 页面重载后重新查询能力，不复用旧页面的缓存。
