diff --git a/journals/20260225-0001-MCP-doc-count-auto-retrain-GUI.md b/journals/20260225-0001-MCP-doc-count-auto-retrain-GUI.md new file mode 100644 index 0000000..02657ff --- /dev/null +++ b/journals/20260225-0001-MCP-doc-count-auto-retrain-GUI.md @@ -0,0 +1,49 @@ +# 2026-02-25: MCP件数・自動再学習・GUI改善 + +## 1. 作業実施の理由と指示 + +- **背景**: Issue #5 として MCP から格納件数を取得したい要望があり、当初は items(チャンク)数だったがドキュメント数に統一するよう指摘された。また、MCP ACTIVITY が空になる不具合、トレイクリックでウィンドウが一瞬開いて閉じる事象、追加・更新・削除のたびに手動 RE-INDEX が必要な点、インデックス化の進行が分からない点、文書一覧で内容が想像しづらい点、サイドバー下部の不要なアコーディオン・著作権表示が指摘された。 +- **観点**: 件数は「ドキュメント数」で MCP・HTTP・UI を統一する。LSA 再学習は変更がたまったタイミングで自動実行し、状態は GUI に表示する。UI は必要な情報を表示し、冗長な要素を削除する。 +- **意図**: get_document_count の追加と doc_count の documents 統一、MCP 呼び出しの SSE ブロードキャスト、トレイのデバウンス、LSA 自動再学習(閾値・90秒デバウンス)、インデックス状態のヘッダー表示、文書一覧にチャンク0の先頭15文字表示、サイドバー下部の整理を行う。 + +## 2. 指摘事項とその対応 + +- **指摘**: 格納件数は「ドキュメント数」にすべき。items 数では「X docs」と一致しない。 + - **対応**: MCP ツールを `get_document_count` に改名し、`SELECT COUNT(*) FROM documents` で返す。HTTP `/doc_count` と UI も同様に documents 件数に統一した。 +- **指摘**: MCP ACTIVITY が常に空である。 + - **対応**: `mcp_messages_handler` 内で `tools/call` 受信時に `state.tx.send("mcp:call:")` を送信するようにした。 +- **指摘**: トレイクリックでウィンドウが一瞬開いてすぐ閉じる。 + - **対応**: 左クリックに 400ms デバウンスを導入し、二重発火を無視するようにした。 +- **指摘**: 文書追加・更新・削除のたびに手動で RE-INDEX するのは手間。毎回再学習はコストが高い。 + - **対応**: 変更件数が「登録ドキュメント数の 20%」と「5 件」の少ない方を超えたら、90 秒デバウンス後に自動で `train_lsa_and_sync_hnsw` を実行する `schedule_retrain_if_needed` を実装し、add_item_text・update_item・delete_item・delete_document の成功後に呼び出すようにした。 +- **指摘**: インデックス化の様子が GUI で分からない。 + - **対応**: `AppState` に `indexing_status` を追加し、`/indexing_status` API と SSE の `indexing:training` / `indexing:syncing` / `indexing:idle` でヘッダーに表示するようにした。 +- **指摘**: 文書一覧で内容が想像しづらい。サイドバー下部のアコーディオン・著作権表示は不要。 + - **対応**: list_documents に chunk0 の先頭15文字(chunk0_preview)を追加し、文書管理テーブルに表示。app-sidebar から sidebar-bottom(アコーディオン・著作権)を削除した。 + +## 3. 作業詳細 + +AIエージェントは、次の変更を実施した。 + +- **MCP・HTTP・仕様**: `get_item_count` を `get_document_count` に変更し、`SELECT COUNT(*) FROM documents` で件数を返す。`tools/list`・dispatch・`handle_get_document_count` を追加・改名。`handlers.rs` の `doc_count_handler` を documents に変更。`04_mcp_api_specification.md` に get_document_count を追記。 +- **MCP ACTIVITY**: `mcp/mod.rs` の `mcp_messages_handler` で、`tools/call` および該当ツール実行直後に `state.tx.send(format!("mcp:call:{}", actual_method))` を実行。 +- **トレイ**: `lib.rs` の `on_tray_icon_event` で左クリック時に AtomicU64 で前回クリック時刻を記録し、400ms 以内のクリックを無視。それ以外で表示/非表示をトグル。 +- **LSA 自動再学習**: `AppState` に `changes_since_train`(AtomicU64)と `retrain_scheduled`(AtomicBool)を追加。`system.rs` に `schedule_retrain_if_needed` を実装(閾値 `max(1, min(ceil(doc_count*0.2), 5))`、90秒デバウンス、spawn で train_lsa_and_sync_hnsw)。add_item_text・update_item・delete_item・delete_document の成功後に呼び出し。 +- **インデックス状態表示**: `AppState` に `indexing_status`(RwLock)を追加。`train_lsa_and_sync_hnsw` の開始・sync 前・完了・失敗・件数0 で `indexing_status` と SSE を更新。`GET /indexing_status` を追加。フロントのヘッダーにバッジを追加し、3秒ポーリングと SSE の `indexing:*` で更新。 +- **文書一覧**: `list_documents` の SQL に chunk0 の先頭15文字のサブクエリを追加し、返却に `chunk0_preview` を含める。main-panel の文書管理テーブルに「先頭(chunk0)」列を追加。`.docs-cell-preview` でスタイルを指定。 +- **サイドバー**: `app-sidebar.js` から `sidebar-bottom`(TelosDB アコーディオン・著作権表示)を削除。 + +```mermaid +flowchart LR + A[get_document_count / doc_count] --> B[documents 統一] + C[MCP tools/call] --> D[SSE mcp:call] + E[変更検知] --> F[schedule_retrain_if_needed] + F --> G[90s デバウンス] + G --> H[train_lsa_and_sync_hnsw] + H --> I[indexing_status / SSE] + I --> J[ヘッダー表示] +``` + +## 4. AI視点での結果 + +MCP と UI の「X docs」がドキュメント数で一致し、MCP ACTIVITY にツール呼び出しが表示されるようになった。トレイクリックでウィンドウの表示・非表示が安定して切り替わる。変更が閾値を超えたタイミングで 90 秒後に LSA が自動再学習され、ヘッダーで training / syncing / idle が確認できる。文書一覧でチャンク0の冒頭が把握でき、サイドバーはナビのみに整理された。 diff --git "a/journals/20260225-0001-MCP\344\273\266\346\225\260\343\203\273\350\207\252\345\213\225\345\206\215\345\255\246\347\277\222\343\203\273GUI\346\224\271\345\226\204.md" "b/journals/20260225-0001-MCP\344\273\266\346\225\260\343\203\273\350\207\252\345\213\225\345\206\215\345\255\246\347\277\222\343\203\273GUI\346\224\271\345\226\204.md" deleted file mode 100644 index 02657ff..0000000 --- "a/journals/20260225-0001-MCP\344\273\266\346\225\260\343\203\273\350\207\252\345\213\225\345\206\215\345\255\246\347\277\222\343\203\273GUI\346\224\271\345\226\204.md" +++ /dev/null @@ -1,49 +0,0 @@ -# 2026-02-25: MCP件数・自動再学習・GUI改善 - -## 1. 作業実施の理由と指示 - -- **背景**: Issue #5 として MCP から格納件数を取得したい要望があり、当初は items(チャンク)数だったがドキュメント数に統一するよう指摘された。また、MCP ACTIVITY が空になる不具合、トレイクリックでウィンドウが一瞬開いて閉じる事象、追加・更新・削除のたびに手動 RE-INDEX が必要な点、インデックス化の進行が分からない点、文書一覧で内容が想像しづらい点、サイドバー下部の不要なアコーディオン・著作権表示が指摘された。 -- **観点**: 件数は「ドキュメント数」で MCP・HTTP・UI を統一する。LSA 再学習は変更がたまったタイミングで自動実行し、状態は GUI に表示する。UI は必要な情報を表示し、冗長な要素を削除する。 -- **意図**: get_document_count の追加と doc_count の documents 統一、MCP 呼び出しの SSE ブロードキャスト、トレイのデバウンス、LSA 自動再学習(閾値・90秒デバウンス)、インデックス状態のヘッダー表示、文書一覧にチャンク0の先頭15文字表示、サイドバー下部の整理を行う。 - -## 2. 指摘事項とその対応 - -- **指摘**: 格納件数は「ドキュメント数」にすべき。items 数では「X docs」と一致しない。 - - **対応**: MCP ツールを `get_document_count` に改名し、`SELECT COUNT(*) FROM documents` で返す。HTTP `/doc_count` と UI も同様に documents 件数に統一した。 -- **指摘**: MCP ACTIVITY が常に空である。 - - **対応**: `mcp_messages_handler` 内で `tools/call` 受信時に `state.tx.send("mcp:call:")` を送信するようにした。 -- **指摘**: トレイクリックでウィンドウが一瞬開いてすぐ閉じる。 - - **対応**: 左クリックに 400ms デバウンスを導入し、二重発火を無視するようにした。 -- **指摘**: 文書追加・更新・削除のたびに手動で RE-INDEX するのは手間。毎回再学習はコストが高い。 - - **対応**: 変更件数が「登録ドキュメント数の 20%」と「5 件」の少ない方を超えたら、90 秒デバウンス後に自動で `train_lsa_and_sync_hnsw` を実行する `schedule_retrain_if_needed` を実装し、add_item_text・update_item・delete_item・delete_document の成功後に呼び出すようにした。 -- **指摘**: インデックス化の様子が GUI で分からない。 - - **対応**: `AppState` に `indexing_status` を追加し、`/indexing_status` API と SSE の `indexing:training` / `indexing:syncing` / `indexing:idle` でヘッダーに表示するようにした。 -- **指摘**: 文書一覧で内容が想像しづらい。サイドバー下部のアコーディオン・著作権表示は不要。 - - **対応**: list_documents に chunk0 の先頭15文字(chunk0_preview)を追加し、文書管理テーブルに表示。app-sidebar から sidebar-bottom(アコーディオン・著作権)を削除した。 - -## 3. 作業詳細 - -AIエージェントは、次の変更を実施した。 - -- **MCP・HTTP・仕様**: `get_item_count` を `get_document_count` に変更し、`SELECT COUNT(*) FROM documents` で件数を返す。`tools/list`・dispatch・`handle_get_document_count` を追加・改名。`handlers.rs` の `doc_count_handler` を documents に変更。`04_mcp_api_specification.md` に get_document_count を追記。 -- **MCP ACTIVITY**: `mcp/mod.rs` の `mcp_messages_handler` で、`tools/call` および該当ツール実行直後に `state.tx.send(format!("mcp:call:{}", actual_method))` を実行。 -- **トレイ**: `lib.rs` の `on_tray_icon_event` で左クリック時に AtomicU64 で前回クリック時刻を記録し、400ms 以内のクリックを無視。それ以外で表示/非表示をトグル。 -- **LSA 自動再学習**: `AppState` に `changes_since_train`(AtomicU64)と `retrain_scheduled`(AtomicBool)を追加。`system.rs` に `schedule_retrain_if_needed` を実装(閾値 `max(1, min(ceil(doc_count*0.2), 5))`、90秒デバウンス、spawn で train_lsa_and_sync_hnsw)。add_item_text・update_item・delete_item・delete_document の成功後に呼び出し。 -- **インデックス状態表示**: `AppState` に `indexing_status`(RwLock)を追加。`train_lsa_and_sync_hnsw` の開始・sync 前・完了・失敗・件数0 で `indexing_status` と SSE を更新。`GET /indexing_status` を追加。フロントのヘッダーにバッジを追加し、3秒ポーリングと SSE の `indexing:*` で更新。 -- **文書一覧**: `list_documents` の SQL に chunk0 の先頭15文字のサブクエリを追加し、返却に `chunk0_preview` を含める。main-panel の文書管理テーブルに「先頭(chunk0)」列を追加。`.docs-cell-preview` でスタイルを指定。 -- **サイドバー**: `app-sidebar.js` から `sidebar-bottom`(TelosDB アコーディオン・著作権表示)を削除。 - -```mermaid -flowchart LR - A[get_document_count / doc_count] --> B[documents 統一] - C[MCP tools/call] --> D[SSE mcp:call] - E[変更検知] --> F[schedule_retrain_if_needed] - F --> G[90s デバウンス] - G --> H[train_lsa_and_sync_hnsw] - H --> I[indexing_status / SSE] - I --> J[ヘッダー表示] -``` - -## 4. AI視点での結果 - -MCP と UI の「X docs」がドキュメント数で一致し、MCP ACTIVITY にツール呼び出しが表示されるようになった。トレイクリックでウィンドウの表示・非表示が安定して切り替わる。変更が閾値を超えたタイミングで 90 秒後に LSA が自動再学習され、ヘッダーで training / syncing / idle が確認できる。文書一覧でチャンク0の冒頭が把握でき、サイドバーはナビのみに整理された。 diff --git a/package-lock.json b/package-lock.json index 83ba51f..431f751 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@modelcontextprotocol/sdk": "^1.26.0", "@tauri-apps/api": "^2.10.1", "@tauri-apps/cli": "^2.10.0", + "@tauri-apps/plugin-autostart": "^2.5.1", "@toast-ui/editor": "^3.2.2", "axios": "^1.13.5", "better-sqlite3": "^12.6.2", @@ -1051,6 +1052,14 @@ "node": ">= 10" } }, + "node_modules/@tauri-apps/plugin-autostart": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-autostart/-/plugin-autostart-2.5.1.tgz", + "integrity": "sha512-zS/xx7yzveCcotkA+8TqkI2lysmG2wvQXv2HGAVExITmnFfHAdj1arGsbbfs3o6EktRHf6l34pJxc3YGG2mg7w==", + "dependencies": { + "@tauri-apps/api": "^2.8.0" + } + }, "node_modules/@toast-ui/editor": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/@toast-ui/editor/-/editor-3.2.2.tgz", diff --git a/package.json b/package.json index cfa75a6..34ae86a 100644 --- a/package.json +++ b/package.json @@ -10,21 +10,22 @@ }, "dependencies": { "@modelcontextprotocol/sdk": "^1.26.0", - "@toast-ui/editor": "^3.2.2", "@tauri-apps/api": "^2.10.1", "@tauri-apps/cli": "^2.10.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", + "@tauri-apps/plugin-autostart": "^2.5.1", + "@toast-ui/editor": "^3.2.2", "axios": "^1.13.5", "better-sqlite3": "^12.6.2", "eventsource": "^4.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", "sqlite-vec-windows-x64": "^0.1.7-alpha.2" }, "devDependencies": { + "@types/react": "^18.2.21", + "@types/react-dom": "^18.2.7", "prettier": "^3.8.1", "typescript": "^5.2.2", - "vite": "^6.0.0", - "@types/react": "^18.2.21", - "@types/react-dom": "^18.2.7" + "vite": "^6.0.0" } } diff --git a/src/backend/Cargo.lock b/src/backend/Cargo.lock index 5b00fe5..2cefeaf 100644 --- a/src/backend/Cargo.lock +++ b/src/backend/Cargo.lock @@ -174,7 +174,7 @@ "axum", "bincode 1.3.3", "chrono", - "dirs", + "dirs 6.0.0", "env_logger", "futures", "hnsw_rs", @@ -188,6 +188,7 @@ "sqlx", "tauri", "tauri-build", + "tauri-plugin-autostart", "tauri-plugin-log", "tauri-plugin-shell", "tempfile", @@ -321,6 +322,17 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] +name = "auto-launch" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f012b8cc0c850f34117ec8252a44418f2e34a2cf501de89e29b241ae5f79471" +dependencies = [ + "dirs 4.0.0", + "thiserror 1.0.69", + "winreg 0.10.1", +] + +[[package]] name = "autocfg" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1086,11 +1098,31 @@ [[package]] name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys 0.3.7", +] + +[[package]] +name = "dirs" version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ - "dirs-sys", + "dirs-sys 0.5.0", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users 0.4.6", + "winapi", ] [[package]] @@ -1101,7 +1133,7 @@ dependencies = [ "libc", "option-ext", - "redox_users", + "redox_users 0.5.2", "windows-sys 0.61.2", ] @@ -1217,7 +1249,7 @@ "rustc_version", "toml 0.9.12+spec-1.1.0", "vswhom", - "winreg", + "winreg 0.55.0", ] [[package]] @@ -4048,6 +4080,17 @@ [[package]] name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 1.0.69", +] + +[[package]] +name = "redox_users" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" @@ -5454,7 +5497,7 @@ "anyhow", "bytes", "cookie", - "dirs", + "dirs 6.0.0", "dunce", "embed_plist", "getrandom 0.3.4", @@ -5504,7 +5547,7 @@ dependencies = [ "anyhow", "cargo_toml", - "dirs", + "dirs 6.0.0", "glob", "heck 0.5.0", "json-patch", @@ -5577,6 +5620,20 @@ ] [[package]] +name = "tauri-plugin-autostart" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459383cebc193cdd03d1ba4acc40f2c408a7abce419d64bdcd2d745bc2886f70" +dependencies = [ + "auto-launch", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.18", +] + +[[package]] name = "tauri-plugin-log" version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6115,7 +6172,7 @@ checksum = "a5e85aa143ceb072062fc4d6356c1b520a51d636e7bc8e77ec94be3608e5e80c" dependencies = [ "crossbeam-channel", - "dirs", + "dirs 6.0.0", "libappindicator", "muda", "objc2", @@ -7190,6 +7247,15 @@ [[package]] name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "winreg" version = "0.55.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" @@ -7302,7 +7368,7 @@ "block2", "cookie", "crossbeam-channel", - "dirs", + "dirs 6.0.0", "dpi", "dunce", "gdkx11", diff --git a/src/backend/Cargo.toml b/src/backend/Cargo.toml index 0573322..88f4257 100644 --- a/src/backend/Cargo.toml +++ b/src/backend/Cargo.toml @@ -39,6 +39,7 @@ env_logger = "0.11" chrono = { version = "0.4", features = ["serde"] } tauri-plugin-shell = "2.0.0" +tauri-plugin-autostart = "2.0.0" reqwest = { version = "0.12", features = ["json"] } dirs = "6.0" # Japanese NLP & LSA diff --git a/src/backend/capabilities/default.json b/src/backend/capabilities/default.json index 137b8a3..1734009 100644 --- a/src/backend/capabilities/default.json +++ b/src/backend/capabilities/default.json @@ -18,6 +18,9 @@ "sidecar": true } ] - } + }, + "autostart:allow-enable", + "autostart:allow-disable", + "autostart:allow-is-enabled" ] } \ No newline at end of file diff --git a/src/backend/src/lib.rs b/src/backend/src/lib.rs index 038c1da..efa733a 100644 --- a/src/backend/src/lib.rs +++ b/src/backend/src/lib.rs @@ -56,6 +56,10 @@ let llama_child: Arc>> = Arc::new(Mutex::new(None)); tauri::Builder::default() .plugin(tauri_plugin_shell::init()) + .plugin(tauri_plugin_autostart::init( + tauri_plugin_autostart::MacosLauncher::LaunchAgent, + None, + )) .plugin({ let log_dir = if cfg!(debug_assertions) { std::env::current_dir().unwrap().join("logs") diff --git a/src/frontend/components/main-panel.js b/src/frontend/components/main-panel.js index 6c0788f..0a6feaf 100644 --- a/src/frontend/components/main-panel.js +++ b/src/frontend/components/main-panel.js @@ -75,6 +75,15 @@

設定

+ 起動 +
+ +
+
+
検索
@@ -101,7 +110,7 @@ // Expose showPanel as method const SETTINGS_KEY = 'telosdb_settings'; - const DEFAULTS = { min_score: 0.3, limit: 10 }; + const DEFAULTS = { min_score: 0.3, limit: 10, run_on_login: false }; const loadSettingsIntoForm = () => { try { @@ -109,13 +118,17 @@ const s = raw ? { ...DEFAULTS, ...JSON.parse(raw) } : DEFAULTS; const minScoreEl = this.querySelector('#setting-min-score'); const limitEl = this.querySelector('#setting-limit'); + const runOnLoginEl = this.querySelector('#setting-run-on-login'); if (minScoreEl) minScoreEl.value = String(Number(s.min_score)); if (limitEl) limitEl.value = String(Number(s.limit)); + if (runOnLoginEl) runOnLoginEl.checked = Boolean(s.run_on_login); } catch (e) { const minScoreEl = this.querySelector('#setting-min-score'); const limitEl = this.querySelector('#setting-limit'); + const runOnLoginEl = this.querySelector('#setting-run-on-login'); if (minScoreEl) minScoreEl.value = String(DEFAULTS.min_score); if (limitEl) limitEl.value = String(DEFAULTS.limit); + if (runOnLoginEl) runOnLoginEl.checked = DEFAULTS.run_on_login; } }; @@ -137,18 +150,45 @@ // default show search this.showPanel('search'); + // 起動時に保存済みの「ログイン時自動起動」をOSに反映 + (async () => { + try { + const raw = localStorage.getItem(SETTINGS_KEY); + const s = raw ? { ...DEFAULTS, ...JSON.parse(raw) } : DEFAULTS; + const autostart = await import('@tauri-apps/plugin-autostart').catch(() => null); + if (autostart) { + if (s.run_on_login) await autostart.enable(); + else await autostart.disable(); + } + } catch (_) {} + })(); + const saveBtn = this.querySelector('#settings-save-btn'); const feedbackEl = this.querySelector('#settings-feedback'); if (saveBtn && feedbackEl) { - saveBtn.addEventListener('click', () => { + saveBtn.addEventListener('click', async () => { const minScoreEl = this.querySelector('#setting-min-score'); const limitEl = this.querySelector('#setting-limit'); + const runOnLoginEl = this.querySelector('#setting-run-on-login'); const min_score = Math.max(0, Math.min(1, parseFloat(minScoreEl?.value) || DEFAULTS.min_score)); const limit = Math.max(1, Math.min(100, parseInt(limitEl?.value, 10) || DEFAULTS.limit)); + const run_on_login = runOnLoginEl ? runOnLoginEl.checked : DEFAULTS.run_on_login; try { - localStorage.setItem(SETTINGS_KEY, JSON.stringify({ min_score, limit })); + // Tauri autostart(OSログイン時自動起動)を反映 + try { + const autostart = await import('@tauri-apps/plugin-autostart'); + if (run_on_login) { + await autostart.enable(); + } else { + await autostart.disable(); + } + } catch (_) { + // ブラウザなど Tauri 外では無視 + } + localStorage.setItem(SETTINGS_KEY, JSON.stringify({ min_score, limit, run_on_login })); if (minScoreEl) minScoreEl.value = String(min_score); if (limitEl) limitEl.value = String(limit); + if (runOnLoginEl) runOnLoginEl.checked = run_on_login; feedbackEl.textContent = '保存しました'; feedbackEl.classList.remove('error'); setTimeout(() => { feedbackEl.textContent = ''; }, 2000); diff --git a/src/frontend/index.html b/src/frontend/index.html index c874f9e..fea7bb6 100644 --- a/src/frontend/index.html +++ b/src/frontend/index.html @@ -158,7 +158,7 @@ const settings = (() => { try { const raw = localStorage.getItem("telosdb_settings"); - const def = { min_score: 0.3, limit: 10 }; + const def = { min_score: 0.3, limit: 10, run_on_login: false }; return raw ? { ...def, ...JSON.parse(raw) } : def; } catch (e) { return { min_score: 0.3, limit: 10 }; diff --git a/src/frontend/styles.css b/src/frontend/styles.css index 10229a5..47a5fa8 100644 --- a/src/frontend/styles.css +++ b/src/frontend/styles.css @@ -261,6 +261,13 @@ min-width: 140px; font-size: 0.9rem; } +.setting-row .setting-checkbox-label { + min-width: 0; + display: inline-flex; + align-items: center; + gap: 8px; + cursor: pointer; +} .setting-row input[type="number"] { width: 80px; padding: 6px 10px;