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
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,18 @@ before the client runs them.
Cursor, Continue and Antigravity CLI come with instructions. Switching
upstreams then happens in the gateway alone.
- **Protection against relays.** A relay sees every request in full and can
rewrite every answer. Outbound redaction swaps API keys, private keys, JWTs,
rewrite every answer. Secrets & privacy swaps API keys, private keys, JWTs,
connection-string passwords, Chinese resident ID numbers and bank card numbers
for placeholders before a request leaves, so the relay never holds the real
values. When an answer carries a tool call
that downloads and runs code, sends out environment variables or credential
files, reads private keys or installs a startup item or scheduled job,
tool-call inspection cuts the answer off before the client can run it.
Dangerous commands cuts the answer off before the client can run it.
The content filter deletes instructions hidden in invisible characters before
a request leaves and can refuse prompt injection. Each protection starts in
Observe, which only records, and is switched over one at a time.
a request leaves, can refuse prompt injection, and can delete or replace
chosen words in requests and in the model's answers. Each protection starts in
Monitor, which records and notifies, and is switched on one at a time; every
rule has its own action.
- **Upstreams, cross-checked.** Each upstream is compared with the others
serving the same model: answers naming a different model, reported input well
above or below theirs and low prompt-cache reads are marked on its row in the
Expand Down
2 changes: 1 addition & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Claude Code、Codex 等 AI 客户端的本地网关,支持 macOS、Windows 与
## 要点

- **一次接入,随时切换。** Claude Code、Claude Desktop、Codex、opencode、Pi、oh-my-pi、Grok Build、Qwen Code、Hermes Agent、Zed、Aider 与 DeepSeek Harness 可一键指向网关,写入前预览改动、备份原文件,随时可以还原;Cursor、Continue 与 Antigravity CLI 提供配置说明。此后切换上游只在网关中完成。
- **防范中转站。** 中转站能看到请求的全部内容,也能改写每一次回答。出站脱敏在请求发出前把 API 密钥、私钥、JWT、连接串口令、身份证号与银行卡号换成占位符,中转站拿不到原值。回答中若出现下载即执行、外发环境变量或凭据文件、读取私钥、写入开机启动项或定时任务之类的工具调用,工具调用审查会在客户端执行之前切断回答。内容过滤在请求发出前删除藏在不可见字符里的指令,也可以直接拒绝提示注入。各项防护出厂只记录,逐项切换后生效。
- **防范中转站。** 中转站能看到请求的全部内容,也能改写每一次回答。「密钥与隐私」在请求发出前把 API 密钥、私钥、JWT、连接串口令、身份证号与银行卡号换成占位符,中转站拿不到原值。回答中若出现下载即执行、外发环境变量或凭据文件、读取私钥、写入开机启动项或定时任务之类的工具调用,「危险命令」会在客户端执行之前切断回答。「内容过滤」在请求发出前删除藏在不可见字符里的指令,可以直接拒绝提示注入,也可以删除或替换请求和模型回答中的指定词语。各项防护出厂处于「监控」状态,只记录并发出通知,逐项开启后生效;每条规则可单独设定动作。
- **上游互相对照。** 每个上游都与服务同一模型的其他上游对照:回答中的模型名与发出的不同、报告的输入明显偏多或偏少、提示缓存读取偏低,都会在上游列表的那一行标出,悬停可见证据与样本数。
- **扫描 MCP、技能与钩子。** 十三款客户端的 MCP 服务器并列显示并标出第三方服务器;客户端配置、技能、钩子与项目指令中的隐藏字符、提示注入、危险命令与过宽权限会被找出。
- **每个请求都可追溯。** 命中的规则、尝试过的每个上游、API 格式转换与费用的计算依据都在请求详情中;已结束的请求可以重放到另一个上游,并排对比。全部请求记录都可以搜索,包括请求与回答的内容。
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "thinkwatch-lite",
"private": true,
"description": "Desktop app for a local AI API gateway on macOS, Windows and Linux",
"version": "2026.10.18",
"version": "2026.10.19",
"type": "module",
"packageManager": "pnpm@11.13.0",
"scripts": {
Expand Down
24 changes: 24 additions & 0 deletions release-notes/2026.10.19.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
**Upgrade notes:**
- The bundled core is now 0.73.0, with control-plane protocol 48. A remote server must run core 0.73.0; servers on 0.72.x do not connect until they are upgraded.
- Nothing is cleared; the request history, stored payloads and settings carry over, and every existing rule keeps its behaviour.

**Security page:**
- The three protections are now named for what they guard against: **Secrets & privacy** (formerly Outbound redaction), **Dangerous commands** (formerly Tool-call inspection) and **Content filter**. Each has three states, **On**, **Monitor** and **Off**, shown as a dot on its tab.
- **Monitor** records every match in the log and raises a system notification, and changes nothing. **Record only** on a single rule does the same under On. The same rule notifies at most once every 5 minutes, matches arriving together are merged into one notification, and a notification never contains the matched text.
- Every rule has its own switch and action, set directly in the list: Secrets & privacy rules replace with a placeholder or record only; Dangerous commands rules cut off or record only; Content filter rules refuse, delete, replace or record only. While a protection is in Monitor, rules show their action with "Monitoring" next to it.
- Built-in rules are grouped by category, with a checkbox on each group to switch all of its rules at once, and a search box filters rules by name and pattern.
- **Match case** in the Secrets & privacy rule dialog is now a switch.

**Content filter for answers:**
- A content rule now says what it checks: **Request**, **Answer** or **Request and answer**. A rule on answers checks the text the model writes, including Codex's freeform tool input; tool calls stay with Dangerous commands, and thinking is not checked.
- **Replace** writes the rule's replacement text (default `***`) in place of the match, on requests and answers. It is not undone in the answer. **Delete** removes the match without a trace.
- Answers keep streaming: only the few characters that could still become a match are held back. A rule on answers cannot refuse and cannot match code points; those options are disabled in the dialog with the reason given.
- The test box tries a sample as a request or as an answer.
- While a rule on answers can delete or replace, token probabilities (logprobs) are left out of streamed answers.

**Log and traffic:**
- Matches in answers show where they were found, and the outcome says how many places were deleted or replaced. Requests whose text was replaced carry a **Replaced** mark in the traffic list.
- Secrets that a Record only rule let through are counted as such instead of being shown as redacted.

**Fixed:**
- Rule dialogs fit small windows and scroll inside instead of pushing the buttons out of view.
1 change: 1 addition & 0 deletions scripts/shots/mock/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ export const CORE: { [N in WebviewEndpoint]: Handler<N> } = {
SetSecurityMode: refuse,
ToggleBuiltinRule: refuse,
SetBuiltinRuleAction: refuse,
SetRulesEnabled: refuse,
CreateCustomRule: refuse,
UpdateCustomRule: refuse,
DeleteCustomRule: refuse,
Expand Down
1 change: 1 addition & 0 deletions scripts/shots/mock/traffic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@ export function summary(from: number, to = Infinity): Summary {
content: count("content"),
content_blocked: count("content", ["blocked"]),
content_stripped: count("content", ["stripped"]),
content_replaced: count("content", ["replaced"]),
},
pricing_date: AS_OF,
};
Expand Down
32 changes: 17 additions & 15 deletions src-tauri/Cargo.lock

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

14 changes: 7 additions & 7 deletions src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "thinkwatch-lite"
version = "2026.10.18"
version = "2026.10.19"
edition = "2024"
# **这个数决定依赖能升到哪一版。**edition 2024 的解析器只挑声明的 Rust
# 版本编得动的依赖:写 1.85 的时候,`cargo update` 一直停在旧的 time 和
Expand All @@ -26,12 +26,12 @@ license = "MIT"
# twcore 二进制必须和这里编译进去的协议镜像来自同一个 core 版本 —— 打包脚本正是
# 从 tw-api 锁到的 tag 去取二进制的(见 scripts/fetch-core.sh)。
[workspace.dependencies]
tw-api = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.72.0" }
tw-types = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.72.0" }
tw-yaml = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.72.0" }
tw-guard = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.72.0" }
tw-watch = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.72.0" }
tw-link = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.72.0" }
tw-api = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.73.0" }
tw-types = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.73.0" }
tw-yaml = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.73.0" }
tw-guard = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.73.0" }
tw-watch = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.73.0" }
tw-link = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.73.0" }

[lib]
name = "thinkwatch_lite_lib"
Expand Down
1 change: 1 addition & 0 deletions src-tauri/src/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ webview_endpoints![
SetSecurityMode,
ToggleBuiltinRule,
SetBuiltinRuleAction,
SetRulesEnabled,
CreateCustomRule,
UpdateCustomRule,
DeleteCustomRule,
Expand Down
5 changes: 5 additions & 0 deletions src-tauri/src/core_text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ pub fn text(m: &Msg) -> String {
tr!(zh(m).unwrap_or_else(|| m.text.clone()), m.text.clone())
}

/// 词表里的一项(`guard`、`secret_rule`、`content_rule`…),中文。表或项不在是 `None`
pub fn table_zh(table: &str, key: &str) -> Option<String> {
self::table().tables.get(table)?.get(key).cloned()
}

/// 同 [`text`],去掉句末的句号:后面还要接自己的一句时用
pub fn clause(m: &Msg) -> String {
let s = text(m);
Expand Down
Loading
Loading