chore(workspace): project-wide cleanup, dependency trimming, docs sync

deps: focus-core no longer depends on tokio at all (the core is fully
synchronous); workspace-level tokio drops the fat feature list, members
declare only what they use (transport: net/io-util/time, providers: rt/time)

code: remove dead AgentHandle (never constructed) and the dead
App::clamp_scroll; wire focus-harness' describe_plan into the TUI compaction
note (it was unused public API); clean a no-op replace_messages + confusing
comment in the compaction integration test

docs: AGENTS.md §2.2 tokio table reflects the new feature sets; README test
count 177→181, new env-var section (FOCUS_DATA_DIR / FOCUS_SHELL /
FOCUS_DEBUG_FILE), wheel + two-level expansion keybindings; add LICENSE (MIT,
matching Cargo.toml); TUI /help notes the two-level expansion and merged
tool blocks; delete the .VSCodeCounter artifact dir

verification: fmt, clippy -D warnings, 181 tests, workspace build all green
This commit is contained in:
DaiChaoXiong 2026-08-09 23:14:21 +08:00
parent ea22f3d9ea
commit bf92590fcd
14 changed files with 58 additions and 44 deletions

View File

@ -96,12 +96,14 @@ let b = self.buf.pop_front();
| crate | 推荐 tokio features |
|---|---|
| `focus-core` | `rt`, `sync`, `macros` |
| `focus-transport` | `rt`, `net`, `io-util`, `sync` |
| `focus-providers` | `rt`, `sync`, `macros` |
| `focus-core` | (无 tokio —— 核心层为纯同步逻辑) |
| `focus-transport` | `net`, `io-util`, `time`TCP/TLS、超时 |
| `focus-providers` | `rt`, `time`(后台 current-thread 运行时) |
| `focus-tools` | (无 tokio —— 工具为同步 `std` I/O |
| `focus-harness` | (无 tokio —— 会话/压缩为纯逻辑 + 同步 `std` I/O |
> workspace 级 `tokio` 声明不带 features由各成员按上表自行声明。
### 2.3 Rust 版本
- 使用**最新 stable** Rust。
@ -189,8 +191,9 @@ focus-tui ← focus-core, focus-providers, focus-tools, focus-harness, f
`~/.focus/config.json`TUI 内 `/config` 编辑provider 构造时传入)、动态系统
提示注入(方案 E 的 Usage/上下文占用、自动上下文压缩的执行harness 产出方案 →
调 provider 摘要 → `Agent::replace_messages` 写回)、会话持久化(`~/.focus/sessions/`)。
- **交互**多行输入、流式显示、Esc 中止、折叠的思考/工具块(显示耗时与内容摘要,
点击或 Tab 展开)、命令(`/new` `/sessions` `/config` `/compact`)。
- **交互**多行输入、Markdown 渲染、流式显示、Esc 中止、折叠的思考/工具块
(显示耗时与内容摘要,点击或 Tab 两级展开——先预览后全量)、工具请求与结果合并
为一块、命令(`/new` `/sessions` `/config` `/compact`)。
- **禁止**:把业务逻辑放这里。这里只做**组装与呈现**。
## 4. 代码规范

14
Cargo.lock generated
View File

@ -429,7 +429,6 @@ name = "focus-core"
version = "0.1.0"
dependencies = [
"focus-json",
"tokio",
]
[[package]]
@ -1702,23 +1701,10 @@ dependencies = [
"libc",
"mio",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.61.2",
]
[[package]]
name = "tokio-macros"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "tokio-rustls"
version = "0.26.4"

View File

@ -26,7 +26,9 @@ license = "MIT"
[workspace.dependencies]
# --- allowed runtime dependencies (see AGENTS.md §2.1) ---------------------
tokio = { version = "1", features = ["rt", "sync", "macros", "net", "io-util", "fs", "process", "rt-multi-thread", "signal", "time"] }
# tokio features 由各成员 crate 按需声明(见 AGENTS.md §2.2)。
# Each member declares the tokio features it actually needs (see AGENTS.md §2.2).
tokio = { version = "1" }
rustls = { version = "0.23", default-features = false, features = ["ring", "std"] }
tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "logging", "tls12"] }
rustls-native-certs = "0.7"

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 focus contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -62,7 +62,7 @@ focus-tui ← focus-core, focus-providers, focus-tools, focus-harness,
# 构建整个 workspace
cargo build --workspace
# 运行全部测试177 个用例,全绿)
# 运行全部测试181 个用例,全绿)
cargo test --workspace
# 代码质量检查
@ -116,6 +116,14 @@ cargo run -p focus-tui
| 配置 | `<data>/config.json` |
| 会话 | `<data>/sessions/<session-id>.jsonl`JSONL 追加写,树结构) |
### 环境变量
| 变量 | 说明 |
|---|---|
| `FOCUS_DATA_DIR` | 覆盖数据根目录(默认 `~/.focus` |
| `FOCUS_SHELL` | 覆盖 `shell` 工具使用的 shell 程序Windows 默认 PowerShell、可回退 cmdLinux 默认 bash |
| `FOCUS_DEBUG_FILE` | 设置后providers 把每个原始网络 chunk 追加到该文件(排查协议不兼容,如推理字段名差异) |
## ⌨️ TUI 使用
### 命令
@ -137,7 +145,8 @@ cargo run -p focus-tui
| `Esc` | 运行中中止任务;空闲时退出 |
| `Ctrl+C` | 退出 |
| `Ctrl+D` | 继续(追问一轮) |
| `Tab` | 展开 / 折叠最近的思考或工具块 |
| `Tab` | 展开 / 折叠最近的思考或工具块(两级:先预览,再全量) |
| 鼠标滚轮 | 逐行滚动Linux / Windows 均支持;上滚暂停自动跟随) |
| `Ctrl+U` / `PageUp` / `PageDown` | 滚动消息区(输入为空时 `↑` `↓` 也可滚动) |
## 🧪 测试
@ -145,7 +154,7 @@ cargo run -p focus-tui
- 所有测试位于各 crate 的 `crates/<name>/tests/`,禁止在 `src/` 内联测试
- 核心层(`focus-core`)测试**零网络依赖**,用 mock provider 驱动
- provider 测试用**录制 / 回放**的 mock transport不打真实 API真实 API 测试用 `#[ignore]` 标记)
- 当前共 **177 个测试用例**`cargo test --workspace` 全绿
- 当前共 **181 个测试用例**`cargo test --workspace` 全绿
## 📚 文档

View File

@ -7,5 +7,6 @@ license.workspace = true
description = "Core agent layer: domain types, agent loop, tool and provider traits"
[dependencies]
# 核心层是纯同步逻辑(同步拉取式流模型),不依赖任何运行时。
# The core layer is purely synchronous (pull-based streaming); no runtime.
focus-json.workspace = true
tokio = { workspace = true, features = ["rt", "sync", "macros"] }

View File

@ -434,10 +434,6 @@ impl std::fmt::Debug for Agent {
}
}
/// 一次运行返回的句柄(目前仅作信息用途)。
/// A handle returned from a run (currently just informational).
pub struct AgentHandle;
/// 一批已执行工具调用的结果。
/// The results of one executed batch of tool calls.
struct ExecutedBatch {

View File

@ -33,7 +33,7 @@ pub mod provider;
/// The `Tool` trait, effects bitflag, and tool registry.
pub mod tool;
pub use agent::{Agent, AgentConfig, AgentHandle};
pub use agent::{Agent, AgentConfig};
pub use error::{CoreError, CoreResult};
pub use event::{AgentEvent, EventSink};
pub use model::*;

View File

@ -10,7 +10,7 @@ description = "LLM provider implementations (Anthropic, OpenAI) for the focus ag
focus-core.workspace = true
focus-transport.workspace = true
focus-json.workspace = true
tokio = { workspace = true, features = ["rt", "sync", "macros"] }
tokio = { workspace = true, features = ["rt", "time"] }
[dev-dependencies]
focus-harness.workspace = true

View File

@ -165,10 +165,9 @@ fn full_conversation_compaction_and_continue() {
// Re-inject a provider (the mock is single-use).
let provider =
AnthropicProvider::with_transport(ProviderConfig::new("sk-test"), Arc::new(mock3));
agent.replace_messages(agent.messages().to_vec());
// 通过内部字段替换 provider直接重建 agent 以保留消息。
// Rebuild the agent keeping the transcript, since the provider is not
// swappable on an existing agent.
// provider 不可在既有 agent 上替换,重建 agent 并保留 transcript。
// The provider is not swappable on an existing agent; rebuild it keeping
// the transcript.
let mut agent2 = Agent::new(
AgentConfig {
model: "claude-sonnet-4".into(),

View File

@ -8,7 +8,7 @@ description = "Transport layer: HTTPS client (tokio + rustls), HTTP/1.1, SSE par
[dependencies]
focus-json.workspace = true
tokio = { workspace = true, features = ["rt", "net", "io-util", "sync"] }
tokio = { workspace = true, features = ["net", "io-util", "time"] }
rustls.workspace = true
tokio-rustls.workspace = true
rustls-native-certs.workspace = true

View File

@ -918,14 +918,6 @@ impl App {
}
}
/// 把输入框的滚动对齐到底部(跟随模式)。
/// Align the scroll to the bottom when following.
pub fn clamp_scroll(&mut self) {
if self.follow {
self.scroll = self.max_scroll();
}
}
/// 最大滚动偏移(由最近渲染的总行数决定;几何只含可展开块,不能用作依据)。
/// Max scroll offset (based on the last render's total line count; the
/// geometry only covers expandable blocks and is unusable for this).

View File

@ -113,6 +113,10 @@ fn run_job(job: RunJob, tx: Sender<JobEvent>) {
if let Some(plan) =
plan_compaction(&transcript, window, COMPACT_THRESHOLD, DEFAULT_KEEP_RATIO)
{
let _ = tx.send(JobEvent::Note(format!(
"compacting… ({})",
focus_harness::compaction::describe_plan(&plan)
)));
match summarize(provider.as_ref(), &job.config, &plan) {
Ok(summary) => {
transcript = apply_summary(&summary, &plan);

View File

@ -518,7 +518,8 @@ focus — 终端编码 agent
/help
/
Tab ";
Tab
";
fn draw_help_modal(frame: &mut Frame, area: Rect) {
let rect = centered_rect(70, 70, area);