limai
# 理脈 limai
理華與理月的**共享神經系統**——從角色中按第一性原理提取的獨立器官。
## 第一性原理推導
| 角色裡的樣子 | 本質 | 模組 | MCP 工具 |
|---|---|---|---|
| 心跳輪詢+錯誤退避(on_idle.mjs) | **節律** | heartbeat.mjs | heartbeat_now・vitals_latest・vitals_history |
| 截圖/視窗/剪貼簿(screenshot.mjs) | **視覺** | vision.mjs | screen_capture(回圖片)・list_windows・read_clipboard |
| todo-tasks.json+權重融合心跳 | **意圖** | todo.mjs | todo_add・todo_list・todo_update |
| 長期記憶(名×關鍵字×內容) | **記憶** | memory.mjs | memory_add・memory_search・memory_list・memory_forget |
| o-pi 六文件工具 | **檔案行動** | filesys.mjs | fs_ls/read/write/edit/find/grep |
| o-pi websearch/webfetch | **網路行動** | web.mjs | web_search・web_fetch |
捨棄的:角色的 LLM 任務提示詞(人格不搬)、記憶的 JS eval 觸發器(安全)。
保留的精髓:加權隨機排程思想→心跳退避;STALE_READ 守衛;SSRF 防護;有界讀取。
## 架構:檔案/網頁工具直接內嵌 o-pi 原始碼
`fs_*` 與 `web_*` 八個工具直接呼叫 vendored 上游原始碼(不再使用自製重寫版):
- 位置:`third_party/o-pi/`(commit 見其 PROVENANCE.txt;含 AGPL-3.0 LICENSE)
- 載入:jiti 執行期 TypeScript 轉譯,相對匯入在上游樹內自解析
- 行為:回傳 o-pi 原生模型可見信封(<read>/<write>/<edit>/<grep>/<websearch_results>/<webfetch>),守衛、上限、錯誤碼完全等價
- 本地補丁僅一處:ports/read-pdf.ts 資源目錄改由宿主注入(記錄於 PROVENANCE.txt)
- 搜尋可靠性:DDG 免費備援可能被 bot challenge(PROVIDER_BLOCKED);穩定使用請設 BRAVE_SEARCH_API_KEY / EXA_API_KEY / TAVILY_API_KEY,o-pi 路由器自動採用
## 啟動
```bash
npm install
npm run start # ① stdio → Claude Desktop / Cursor 等本地客戶端
npm run serve:http # ② HTTP MCP → GPT 客戶端 / 區網 / 遠端
npm run tick # ③ 手動跑一次心跳(驗證感知層)
```
## CLI 為 AI agent 而設計
```bash
limai shot # → {"file":...,"width":1920,"height":1080,"bytes":...}
limai win # → {"foreground":...,"windows":[{process,title},…]}
limai clip [--json] # 剪貼簿原文走 stdout(利於管線)
limai tick # 心跳一次,生命徵象 JSON
limai web search <q> # → [{title,url,snippet},…]
limai web fetch <url> # 正文走 stdout、中繼 stderr;--json 得全包裝
limai fs ls|read|write|edit|find|grep …
limai mem … / limai todo … # 同前
```
**Agent 契約**:
- 輸出預設 JSON、錯誤碼前綴進 stderr 訊息(`STALE_READ: …`)、退出碼非零表失敗
- `fs edit` 嚴格契約與 MCP 相同:須先 `fs read`;觀測狀態持久化於 `fs-state.json`,
「read 行程 → edit 行程」跨呼叫依然成立,外部變更必被攔截(--force 可越過)
- 成功的 `fs write` 亦建立觀測,可接 edit(同 o-pi「緊接成功 write」規則)
架構上 MCP 只是核心模組之上的其中一種介面:同一套 vision/web/filesys/memory/todo/heartbeat
同時供 CLI 子命令與 MCP 工具呼叫,兩種介面共用同一份資料與同一套安全契約。`
首次執行自動建立 `~/.limai/`(config.json・memory.json・todo.json・vitals.*・screenshots/)並印出 token。
## 客戶端接入
### 本地(stdio)
```jsonc
// claude_desktop_config.json
{ "mcpServers": { "limai": { "command": "node", "args": ["F:\\fount開發項目\\理脈\\src\\cli.mjs", "serve", "--stdio"] } } }
```
### 區網/同機 GPT 客戶端(Cherry Studio、LobeChat、OpenWebUI…)
```bash
node src/cli.mjs serve --http # 預設 127.0.0.1:8931
# 對區網開放:--host 0.0.0.0 --token <強密碼>
```
```jsonc
{ "type": "http", "url": "http://192.168.x.x:8931/mcp",
"headers": { "Authorization": "Bearer <token>" } }
```
### 雙傳輸端點(內建)
| 端點 | 用途 |
|---|---|
| `/mcp` | Streamable HTTP(主要;Claude/Cursor/ChatGPT 新版) |
| `/sse` + `/messages` | 舊式 SSE 備援(相容性最大化) |
| `/health` | 健康檢查 |
自我診斷(模擬 ChatGPT 完整握手,5 項體檢):`limai doctor https://mcp.plocomcomui.cc --token <token>`
### 雲端 ChatGPT(Connectors/開發者模式)
ChatGPT 摸不到你的 localhost,需要公網 HTTPS——一行隧道:
```bash
cloudflared tunnel --url http://127.0.0.1:8931
# → https://xxxx.trycloudflare.com
```
連接器 URL 填 `https://xxxx.trycloudflare.com/mcp?token=<token>`(GPT 類客戶端多不能自訂 header,故支援 query 傳 token)。
長期方案:Tailscale Funnel(免開埠)或 Caddy 反代自有網域。
## 安全邊界
- 檔案:鎖在 `config.json` 的 `allowedRoots`;`.git` 永久阻擋;`fs_edit` 必須先 `fs_read`(STALE_READ 版本守衛);old 文本必須唯一
- 網路:拒 localhost/私網/link-local(SSRF)、重定向逐跳複檢、2MB 上限、30 秒逾時
- 認證:HTTP 全程 Bearer/query-token;預設只綁 127.0.0.1
- 隱私:心跳只記視窗標題+剪貼簿雜湊(變化時存前 60 字元預覽);像素截圖僅限明確呼叫 screen_capture
## 心跳語義(沿襲理華)
15 分鐘一跳(可調 `heartbeat.intervalMin`)。每跳收集:前景視窗・視窗清單(top8)・閒置秒數・剪貼簿變化・開放待辦數。失敗時間隔 ×2(上限 8×),成功復位。日誌滾動於 `vitals.ndjson`。
## 上游同步(o-pi)
- **2026-08-23 檢查**:上游當日大量提交為內部重構(file-tools/web-tools/filesystem/lsp 簡化),六工具+兩網頁工具的行為契約不變;`duckduckgo-html-provider` 仍為零-key 備援路徑——理脈提取依然忠實。
- 新能力 `read` 支援 PDF 頁面圖像(d762209):**理脈已對齊實作**——`fs_read` 加 `pages` 參數(N / N-M / N-),回傳頁面 PNG 的 MCP 圖像內容塊;CLI 用 `fs read <pdf> --pages "1-5"`。主路線 **PDF.js(pdfjs-dist legacy)+@napi-rs/canvas** 跨平臺渲染;Windows 上依賴無法載入時自動降級內建 WinRT `Windows.Data.Pdf`。預設單次上限 20 頁,含總頁數與續讀位置。
- skill URI/bash 工具/approval gate 屬 Pi 宿主專屬,不在提取範圍。
- **同日二檢(d795f92 new approval UI)**:僅動 `src/approval/*` 與 TUI,file-tools/web-tools 零變更。據此完成 grep 契約對齊:非法正則降級為精確字面量——有命中→回 `literal_fallback` 警告;零命中→`INVALID_REGEX` 不偽裝空結果。已測試通過。
## 授權與來源(License & Attribution)
本專案以 **GNU Affero General Public License v3.0 或更新版本**(AGPL-3.0-or-later)發佈,完整條款見 [LICENSE](./LICENSE)。
**代碼來源聲明**:
- **檔案工具與網頁工具**:直接內嵌上游完整原始碼於 `third_party/o-pi/`([Orion-zhen/o-pi](https://github.com/Orion-zhen/o-pi),AGPL-3.0),MCP 工具經橋接層直接呼叫,行為完全等價;上游授權文本隨附於該目錄。
- **長期記憶**:`src/core/memory.mjs` 移植自理華 `prompt/memory/long-term-memory.mjs`——完整 JSON 結構(trigger/prompt/name/createdAt/createdContext…)、`long-term-memory.json` 檔名與全部儲存函式語義;觸發器經 [@steve02081504/async-eval](https://www.npmjs.com/package/@steve02081504/async-eval) 執行。
- **match_keys**:`src/core/match.mjs` 移植自理華 `scripts/match.mjs`——中文免邊界/英文\b、繁簡雙變體比對(opencc-js)、getScopedChatLog 完整角色過濾;翻譯管線分支未移植(標註於檔頭)。
- **captureScreen**:`src/core/vision.mjs` 逐行移植自理華 `scripts/tools.mjs` 行428-438(node-screenshots);理脈加子行程隔離(Rust panic 不波及常駐)與 PowerShell 備援。listWindows/readClipboard/idleSeconds 為理脈原創。
- **心跳/todo**:提取自理華 on_idle 與 todo-tasks 的架構思想(閒置輪詢退避、加權任務),未複製程式碼。
- MCP 協議實作基於官方 [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk)。
- PDF 渲染依賴 [pdf.js](https://github.com/mozilla/pdf.js)(Apache-2.0)與 [@napi-rs/canvas](https://github.com/Brooooooklyn/canvas)(MIT)。
TDQS
Scored across 21 tools
Each tool targets a distinct resource and action—monitoring (screen, windows, clipboard, heartbeat), memory (add/search/list/forget), todo (add/list/update), web (search/fetch), and filesystem (ls/read/write/edit/find/grep). There is no meaningful overlap; even fs_write vs fs_edit are clearly separated by create/overwrite vs precise replacement.
All tool names follow a consistent 'domain_action' pattern with snake_case (e.g., memory_add, web_fetch, fs_grep). The verb is consistently after the domain, and every name is lowercase, making the API predictable and easy to navigate.
With 21 tools, the server is slightly above the ideal range but each tool serves a clear purpose across multiple domains (system monitoring, memory, todos, web, filesystem). The count is justified given the broad scope, though a few tools could potentially be consolidated without losing clarity.
The server covers most core operations for its domains—memory and todo have full CRUD-ish coverage, web has search and fetch, and filesystem has read/write/edit/find/grep. However, the absence of a file deletion tool (e.g., fs_delete) leaves the filesystem incomplete, and there is no explicit tool for renaming or moving files. This gap could cause agent failures when cleanup is required.