Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f1a6337
feat(ui): add Activity Bar for global navigation
donfaquir Jul 7, 2026
cdab582
chore: untrack plan/INDEX.md (already in .gitignore)
donfaquir Jul 7, 2026
2043687
refactor(ui): simplify right panel to 3 tabs
donfaquir Jul 7, 2026
1bc9c8c
fix(ui): keep Activity Bar visible when sidebar collapsed
donfaquir Jul 7, 2026
9a78dea
fix(ui): preserve sidebar width for thought management when collapsed
donfaquir Jul 7, 2026
4cd7de1
refactor(ui): render thought management as Activity Bar view mode
donfaquir Jul 7, 2026
ec3ea6c
fix(ui): hide folder/search buttons when sidebar collapsed
donfaquir Jul 7, 2026
5798985
refactor(ui): move open-folder action from toolbar to sidebar footer
donfaquir Jul 7, 2026
765ebea
fix(ui): instant tooltip for Activity Bar buttons via CSS
donfaquir Jul 7, 2026
4b0eefb
fix(ui): allow Activity Bar tooltip overflow
donfaquir Jul 7, 2026
61ced3a
feat(editor): add save-as-thought button to selection toolbar
donfaquir Jul 7, 2026
db683b9
feat(writing-coach): add manual trigger, perf optimizations, and stre…
donfaquir Jul 7, 2026
dd28972
feat(onboarding): add 4-step onboarding wizard
donfaquir Jul 8, 2026
8cf684e
style(file-tree): redesign new-file and new-folder icons for better d…
donfaquir Jul 8, 2026
8b2bf4f
refactor(link-rec): move panel from full-screen view to right sidebar…
donfaquir Jul 8, 2026
b624660
fix(editor): save/restore scroll position on tab switch
donfaquir Jul 8, 2026
98e906a
style(right-panel): remove duplicate linkRec tab button
donfaquir Jul 8, 2026
cc2a0ae
fix(sidebar): auto-expand file tree when clicking files icon
donfaquir Jul 8, 2026
9e1c907
refactor(link-rec): move entry from ActivityBar to right panel tab
donfaquir Jul 8, 2026
bcec414
fix(macos): center traffic lights in toolbar
donfaquir Jul 8, 2026
64a0d01
fix(toolbar): fix clipped toggle and hidden search when sidebar colla…
donfaquir Jul 8, 2026
4711874
feat(ai-panel): show model label and remove redundant vault search to…
donfaquir Jul 8, 2026
c167d91
style(thought-popover): improve visual hierarchy and layout
donfaquir Jul 8, 2026
e66c6a2
chore: bump version to 0.7.5
donfaquir Jul 8, 2026
0ee2e09
chore: update Cargo.lock for 0.7.5
donfaquir Jul 8, 2026
2d540db
docs: add CHANGELOG entry for 0.7.5
donfaquir Jul 8, 2026
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
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,34 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).

## [0.7.5] - 2026-07-08

### Added
- Activity Bar for global navigation (files, graph, thoughts) with instant CSS tooltips
- Save-as-thought button in editor selection toolbar
- 4-step onboarding wizard for new users
- Writing coach: manual trigger, performance optimizations, and streaming support
- Active model label displayed below the AI chat input box

### Changed
- Link recommendations moved from full-screen view to right sidebar tab (4th tab, disabled when no document is open)
- Thought management rendered as Activity Bar view mode instead of a separate panel
- Right panel simplified to 3 core tabs (outline, AI, review) plus link-rec
- Open-folder action moved from top toolbar to sidebar footer
- ThoughtSavePopover redesigned: section dividers, labels, search icon, options-bar grouping
- Depth selector removed from thought-save popover; default depth changed to "deep"
- New-file and new-folder icons redesigned for better visual distinction
- Redundant "workspace keyword search" toggle removed from AI panel (semantic search covers it)

### Fixed
- Editor scroll position now saves/restores correctly when switching document tabs
- macOS traffic light controls vertically centered in the toolbar
- Sidebar toggle icon no longer clipped when sidebar is collapsed on macOS
- Search icon stays visible when sidebar is collapsed
- File tree auto-expands when clicking the files icon in Activity Bar
- Activity Bar remains visible when sidebar is collapsed
- Thought-save popover dropdown now closes on blur

## [0.7.4] - 2026-07-06

### Added
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "knowforge",
"private": true,
"version": "0.7.4",
"version": "0.7.5",
"license": "Apache-2.0",
"repository": {
"type": "git",
Expand Down
76 changes: 0 additions & 76 deletions plan/INDEX.md

This file was deleted.

51 changes: 51 additions & 0 deletions resources/onboarding/sample_challenges.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"thoughts": [
{
"key": "feynman",
"body_zh": "费曼学习法的核心不是「简化」——是「发现你无法简化的地方」。当你无法用简单语言解释一个概念时,说明你的理解有漏洞。",
"body_en": "The core of the Feynman technique isn't 'simplifying' — it's 'discovering what you can't simplify.' When you can't explain a concept in plain language, it reveals gaps in your understanding.",
"summary_zh": "费曼学习法的核心洞察",
"summary_en": "Core insight of the Feynman technique"
},
{
"key": "spaced-repetition",
"body_zh": "间隔效应说明大脑在「快要忘记」的时刻复习效果最好。这解释了为什么考前突击虽然能通过考试,但两周后什么都不记得。",
"body_en": "The spacing effect shows that the brain learns best when reviewing at the moment of near-forgetting. This explains why cramming before an exam might pass the test, but leaves nothing two weeks later.",
"summary_zh": "间隔重复与遗忘曲线",
"summary_en": "Spaced repetition and the forgetting curve"
},
{
"key": "hicks-law",
"body_zh": "少即是多不是美学口号——它是认知负载理论的应用。每增加一个选项,用户做决定的时间指数增长(Hick's Law)。",
"body_en": "Less is more isn't an aesthetic slogan — it's applied cognitive load theory. Each additional option increases decision time exponentially (Hick's Law).",
"summary_zh": "Hick's Law 与认知负载",
"summary_en": "Hick's Law and cognitive load"
}
],
"challenges": [
{
"thoughtKey": "feynman",
"questionType": "apply",
"question_zh": "你最近学了一个新的编程概念,请试着用费曼学习法的思路来检验你是否真正理解了它。你会怎么做?",
"question_en": "You recently learned a new programming concept. How would you apply the Feynman technique to test whether you truly understand it?",
"sampleFeedback_zh": "很好的思考!你抓住了费曼学习法的关键——不是简单重复,而是通过「教别人」来暴露理解的盲区。坚持这个习惯,你会发现学习效率大幅提升。",
"sampleFeedback_en": "Great thinking! You've grasped the key insight — it's not about simplifying, but about exposing gaps in understanding through teaching. Keep this habit, and you'll see a significant boost in learning efficiency."
},
{
"thoughtKey": "spaced-repetition",
"questionType": "explain",
"question_zh": "为什么「快要忘记」的时刻复习效果最好?用你自己的话解释这背后的原理。",
"question_en": "Why is reviewing most effective at the moment of near-forgetting? Explain the underlying principle in your own words.",
"sampleFeedback_zh": "不错的解释!关键在于:大脑在「费力回忆」时形成的记忆痕迹更深。就像锻炼肌肉,适度的挑战才能促进成长。",
"sampleFeedback_en": "Nice explanation! The key point: the brain forms deeper memory traces when 'effortful retrieval' is required. Like exercising muscles, moderate challenge promotes growth."
},
{
"thoughtKey": "hicks-law",
"questionType": "apply",
"question_zh": "想象你正在设计一个设置页面,有 15 个选项。根据 Hick's Law,你会如何优化用户体验?",
"question_en": "Imagine you're designing a settings page with 15 options. Based on Hick's Law, how would you optimize the user experience?",
"sampleFeedback_zh": "很棒的思路!把选项分组、设置合理的默认值、隐藏高级选项——这些都是 Hick's Law 的实际应用。好的设计就是帮用户减少不必要的决策。",
"sampleFeedback_en": "Great approach! Grouping options, setting sensible defaults, hiding advanced options — these are all practical applications of Hick's Law. Good design helps users avoid unnecessary decisions."
}
]
}
2 changes: 1 addition & 1 deletion src-tauri/Cargo.lock

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

2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "knowforge"
version = "0.7.4"
version = "0.7.5"
description = "Knowforge desktop app"
authors = ["caichangqing"]
edition = "2024"
Expand Down
8 changes: 5 additions & 3 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ mod understanding_graph;
mod link_recommendation;
mod topic_network;
mod tools;
mod onboarding;
mod skills;

/// 供前端展示的文件树节点(目录带 children,Markdown 文件为叶子)
Expand Down Expand Up @@ -64,7 +65,7 @@ struct MarkdownFileSignature {
modified_ns: String,
}

struct WorkspaceState {
pub(crate) struct WorkspaceState {
/// 当前已授权工作区根目录,仅允许命令访问这里
root: Mutex<Option<PathBuf>>,
/// 本应用已成功写入的路径与时间,用于忽略紧随其后的 notify
Expand Down Expand Up @@ -214,7 +215,7 @@ pub(crate) fn sanitize_io_error(err: std::io::Error, permission_context: &'stati
}
}

fn lock_workspace_root(state: &tauri::State<'_, WorkspaceState>) -> Result<PathBuf, String> {
pub(crate) fn lock_workspace_root(state: &tauri::State<'_, WorkspaceState>) -> Result<PathBuf, String> {
let guard = match state.root.lock() {
Ok(g) => g,
Err(poisoned) => {
Expand Down Expand Up @@ -1800,7 +1801,8 @@ pub fn run() {
skills::commands::update_custom_skill,
skills::commands::delete_custom_skill,
skills::commands::reload_custom_skills,
skills::commands::list_available_tools
skills::commands::list_available_tools,
onboarding::seed_onboarding_content
])
.setup(|app| {
use tauri::Manager;
Expand Down
5 changes: 3 additions & 2 deletions src-tauri/src/llm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,15 +308,15 @@ struct LlmStreamErrorPayload {
message: String,
}

pub(super) fn emit_chunk(app: &AppHandle, session_id: &str, delta: &str) {
pub(crate) fn emit_chunk(app: &AppHandle, session_id: &str, delta: &str) {
let payload = LlmStreamChunkPayload {
session_id: session_id.to_string(),
delta: delta.to_string(),
};
let _ = app.emit("llm:stream-chunk", payload);
}

pub(super) fn emit_done(app: &AppHandle, session_id: &str) -> Result<(), tauri::Error> {
pub(crate) fn emit_done(app: &AppHandle, session_id: &str) -> Result<(), tauri::Error> {
app.emit(
"llm:stream-done",
LlmStreamDonePayload {
Expand Down Expand Up @@ -638,6 +638,7 @@ async fn build_context_pipeline(
query: query_clone,
exclude_rel_paths: exclude,
limits: None,
redact_private_override: None,
},
)
.ok()
Expand Down
92 changes: 92 additions & 0 deletions src-tauri/src/onboarding.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use chrono::Utc;
use serde::Serialize;
use std::fs;
use std::path::Path;

use crate::vault_thoughts_db;

const SEED_MARKER: &str = ".knowforge/onboarding_seeded";

struct SeedThought {
body: &'static str,
summary: &'static str,
}

const SEED_THOUGHTS: &[SeedThought] = &[
SeedThought {
body: "费曼学习法的核心不是「简化」——是「发现你无法简化的地方」。当你无法用简单语言解释一个概念时,说明你的理解有漏洞。\n\nThe core of the Feynman technique isn't 'simplifying' — it's 'discovering what you can't simplify.' When you can't explain a concept in plain language, it reveals gaps in your understanding.",
summary: "Feynman technique: expose understanding gaps",
},
SeedThought {
body: "间隔效应说明大脑在「快要忘记」的时刻复习效果最好。这解释了为什么考前突击虽然能通过考试,但两周后什么都不记得。\n\nThe spacing effect shows that the brain learns best when reviewing at the moment of near-forgetting. This explains why cramming might pass the test, but leaves nothing two weeks later.",
summary: "Spaced repetition and the forgetting curve",
},
SeedThought {
body: "少即是多不是美学口号——它是认知负载理论的应用。每增加一个选项,用户做决定的时间指数增长(Hick's Law)。\n\nLess is more isn't an aesthetic slogan — it's applied cognitive load theory. Each additional option increases decision time exponentially (Hick's Law).",
summary: "Hick's Law and cognitive load",
},
];

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct SeedResult {
pub seeded: bool,
pub thought_ids: Vec<String>,
}

#[tauri::command]
pub async fn seed_onboarding_content(
state: tauri::State<'_, crate::WorkspaceState>,
) -> Result<SeedResult, String> {
let root = crate::lock_workspace_root(&state)?;
tauri::async_runtime::spawn_blocking(move || seed_blocking(&root))
.await
.map_err(|e| e.to_string())?
}

fn seed_blocking(vault_root: &Path) -> Result<SeedResult, String> {
let marker = vault_root.join(SEED_MARKER);
if marker.exists() {
return Ok(SeedResult {
seeded: false,
thought_ids: Vec::new(),
});
}

let conn = vault_thoughts_db::open_thoughts_db(vault_root)?;
let now = Utc::now().to_rfc3339();
let mut ids = Vec::new();

for seed in SEED_THOUGHTS {
let thought_id = format!("thought-{}", uuid::Uuid::new_v4().simple());
let note_stable_id = thought_id.clone();
let note_rel_path = format!(".knowforge/standalone/{thought_id}");

vault_thoughts_db::upsert_thought_body(
&conn,
&thought_id,
&note_stable_id,
&note_rel_path,
seed.body,
Some(seed.summary),
"seedling",
true,
true,
&now,
&now,
0,
Some(&now),
)?;
ids.push(thought_id);
}

if let Some(parent) = marker.parent() {
fs::create_dir_all(parent).map_err(|e| format!("create marker dir: {e}"))?;
}
fs::write(&marker, "seeded").map_err(|e| format!("write marker: {e}"))?;

Ok(SeedResult {
seeded: true,
thought_ids: ids,
})
}
1 change: 1 addition & 0 deletions src-tauri/src/tools/built_in/vault_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ impl Tool for VaultSearchKeywordTool {
max_chars_per_snippet: Some(max_chars_per_snippet),
..Default::default()
}),
redact_private_override: None,
};

let result = tauri::async_runtime::spawn_blocking(move || {
Expand Down
4 changes: 2 additions & 2 deletions src-tauri/src/vault_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ impl Default for CognitiveConfig {
passive_highlight_enabled: default_passive_highlight_enabled(),
passive_highlight_confidence_min: default_passive_highlight_confidence_min(),
passive_highlight_inaccuracy_counts: PassiveHighlightInaccuracyCounts::default(),
independent_review_enabled: false,
independent_review_enabled: true,
challenge_review_daily_cap_independent: default_challenge_review_cap_independent(),
challenge_review_daily_cap_inline: default_challenge_review_cap_inline(),
challenge_review_inline_dates: ChallengeReviewInlineDates::default(),
Expand Down Expand Up @@ -1586,7 +1586,7 @@ mod tests {
assert!(cfg.passive_highlight_enabled);
assert!((cfg.passive_highlight_confidence_min - 0.55).abs() < f64::EPSILON);
assert_eq!(cfg.passive_highlight_inaccuracy_counts.integrate, 0);
assert!(!cfg.independent_review_enabled);
assert!(cfg.independent_review_enabled);
assert_eq!(cfg.challenge_review_daily_cap_independent, 3);
assert_eq!(cfg.challenge_review_daily_cap_inline, 2);
assert!(cfg.challenge_review_inline_dates.by_day.is_empty());
Expand Down
Loading