From ae6aa3fbde09da6faa15a24255924e64d2c830e0 Mon Sep 17 00:00:00 2001 From: che cheng Date: Sun, 19 Jul 2026 05:37:10 +0800 Subject: [PATCH 1/3] =?UTF-8?q?chore:=20MeasureOCR=20=E9=81=B7=E5=87=BA?= =?UTF-8?q?=E8=87=B3=20bestOCR=20umbrella=EF=BC=88submodule=20=E8=A7=A3?= =?UTF-8?q?=E9=99=A4=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原 cli/FastOCR(→MeasureOCR)為研究儀器、非文件工具,遷至 ~/Developer/bestOCR/repos/measureOCR;GitHub repo 同步改名 PsychQuant/measureOCR(舊 URL 轉址)。macdoc PDF 工具的 OCR 能力 不變——照常經 published package ocr-swift 取用。 --- .gitmodules | 3 --- CLAUDE.md | 5 +++-- cli/FastOCR | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) delete mode 160000 cli/FastOCR diff --git a/.gitmodules b/.gitmodules index a5d451c8..4c4ea221 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,6 +7,3 @@ [submodule "mcp/che-pptx-mcp"] path = mcp/che-pptx-mcp url = git@github.com:PsychQuant/che-pptx-mcp.git -[submodule "cli/FastOCR"] - path = cli/FastOCR - url = https://github.com/PsychQuant/FastOCR.git diff --git a/CLAUDE.md b/CLAUDE.md index 46f758da..31f96442 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -347,7 +347,7 @@ swift build 主 repo 以兩種方式追蹤外部 repo: -- **Submodule**(`.gitmodules`):`mcp/` 下三個 MCP server + `cli/FastOCR`。Clone 主 repo 時加 `--recurse-submodules` 會自動拉齊,或事後 `git submodule update --init --recursive` +- **Submodule**(`.gitmodules`):`mcp/` 下三個 MCP server。Clone 主 repo 時加 `--recurse-submodules` 會自動拉齊,或事後 `git submodule update --init --recursive` - **Gitignore 忽略**(各自獨立管理):`packages/` 下的 Swift 套件、`reference/`。重建環境時在對應目錄 `git clone` 即可 | 目錄 | Git Remote | 說明 | @@ -367,9 +367,10 @@ swift build | `mcp/che-word-mcp` | https://github.com/PsychQuant/che-word-mcp.git | Word MCP(submodule) | | `mcp/che-pdf-mcp` | https://github.com/PsychQuant/che-pdf-mcp.git | PDF MCP(submodule) | | `mcp/che-pptx-mcp` | https://github.com/PsychQuant/che-pptx-mcp.git | PPTX MCP(submodule) | -| `cli/FastOCR` | https://github.com/PsychQuant/FastOCR.git | GLM-OCR PDF→Markdown CLI + 實驗 harness(submodule) | | `reference/*` | 見 [`reference/README.md`](reference/README.md) | 外部參考 repo(docx-js、pandoc、mlx-swift-lm、swift-argument-parser)— clone-on-demand,只有 README 進版控 | +> **MeasureOCR 已遷出(2026-07-18)**:原 `cli/FastOCR`(後改名 MeasureOCR)是研究儀器而非文件工具,已遷至 `~/Developer/bestOCR/repos/measureOCR`(GitHub repo 同步改名 `PsychQuant/measureOCR`,舊 URL 自動轉址)。OCR **能力**不受影響——macdoc 的 PDF 工具照常透過 published package `packages/ocr-swift`(`PsychQuant/ocr-swift`)取用 OCR;搬走的只是 benchmark 儀器。遷移全紀錄見 bestOCR repo 的 `docs/migration-2026-07-18.md`。 + ## Key Files ### macdoc diff --git a/cli/FastOCR b/cli/FastOCR deleted file mode 160000 index aa99d149..00000000 --- a/cli/FastOCR +++ /dev/null @@ -1 +0,0 @@ -Subproject commit aa99d149a597ba6ac2eab9e23a043ca7455f2f1e From 235d4e084ebdbc96ba857f25770c48ce03844c40 Mon Sep 17 00:00:00 2001 From: che cheng Date: Tue, 4 Aug 2026 00:25:51 +0800 Subject: [PATCH 2/3] docs: add genoffice to reference index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Genspark 的 AI-native office suite,shallow clone 至 reference/genoffice/。 不是競品(無 MCP / CLI / public API,AI 綁自家雲端),但 packages/ 下的 engine 是純 TS、無 Electron 依賴,是唯一同時涵蓋 docx + xlsx + pptx + pdf 的現代 開源對照組。 三個對照點: - xlsx 缺口(file-parse/src/xlsx.ts)——macdoc 唯一缺的 OOXML 主格式 - patch-narrowly round-trip(docx-engine/src/patch.ts)——與 ooxml-swift op log 同目標、不同解法的第三種參考(python-docx 直接 mutate、genoffice 保留原 bytes 窄幅重生、macdoc op log 重放) - pptx 功能廣度(smartart / custgeom / animation)——pptx-swift 擴充 checklist 含 Apache-2.0 / ee\/ 另授權的移植注意事項,以及 snapshot-sync 開發模式的 成熟度警語。 --- reference/README.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/reference/README.md b/reference/README.md index bd6cc51e..7bc0d5f9 100644 --- a/reference/README.md +++ b/reference/README.md @@ -11,6 +11,7 @@ git clone https://github.com/python-openxml/python-docx.git git clone https://github.com/ml-explore/mlx-swift-lm.git git clone https://github.com/jgm/pandoc.git git clone https://github.com/apple/swift-argument-parser.git +git clone --depth 1 https://github.com/genspark-ai/genoffice.git # 43M,只讀 source 不需要 history # textutil-manpage.txt 已在版控中 ``` @@ -22,6 +23,7 @@ git clone https://github.com/apple/swift-argument-parser.git | `python-docx/` | git repo | https://github.com/python-openxml/python-docx | Python + lxml 的 OOXML 函式庫。**典範:tree-backed wrapper**——每個 `Document` / `Paragraph` / `Run` 包一個 lxml `_Element`,typed accessor 讀寫該 element。`word-aligned-state-sync` 的 Phase 1 (typed views as tree projections) 直接對照它。詳見 `docs/docx-libraries-comparison.md` | | `mlx-swift-lm/` | git repo | https://github.com/ml-explore/mlx-swift-lm | Apple MLX Swift LLM runtime。`pdf-to-latex-swift` Phase 1 的 local GLM-OCR backend 用它載模型 | | `pandoc/` | git repo | https://github.com/jgm/pandoc | Haskell 文件轉換工具。macdoc 不依賴 pandoc,純粹參考它怎麼處理邊界情況(複雜 table、field、footnote 跨段落) | +| `genoffice/` | git repo (shallow) | https://github.com/genspark-ai/genoffice | Genspark 的 AI-native office suite(Electron GUI)。**不是競品**——它沒有 MCP / CLI / public API,AI 綁自家雲端帳號;但 `packages/` 下的 engine 是純 TS、無 Electron 依賴,是**唯一同時涵蓋 docx + xlsx + pptx + pdf 的現代開源對照組**。看三件事:xlsx 缺口、patch-narrowly round-trip、pptx 功能廣度。Apache-2.0(`ee/` 另授權) | | `swift-argument-parser/` | git repo | https://github.com/apple/swift-argument-parser | Apple 官方 CLI 解析器。`macdoc` CLI 已是使用者,這裡留一份方便查 source-level 行為(尤其是 subcommand dispatch、ExitCode) | | `textutil-manpage.txt` | 單檔 | [textutil(1) macOS man page](https://ss64.com/mac/textutil.html) | macOS 內建 `textutil` 的 manual。`macdoc convert` 的 CLI 語法對齊 textutil(見 `.claude/rules/cli-design/textutil-compat.md`),改 CLI 前對一下 | @@ -67,6 +69,43 @@ git clone https://github.com/apple/swift-argument-parser.git - `pandoc/src/Text/Pandoc/Readers/HTML.hs` — HTML 讀取邏輯 - `pandoc/src/Text/Pandoc/Writers/Markdown.hs` — Markdown 輸出邏輯 +### genoffice → xlsx 缺口 / patch-narrowly round-trip / pptx 功能廣度 + +先講清楚定位,免得誤判:genoffice 是**桌面 GUI 套裝軟體**(Electron,五個 app 共用 engine 層),macdoc 是 CLI + MCP 的管線工具,兩者不是同一個品類,也不互相取代。它沒有 MCP server、沒有 public API、沒有自動化 CLI,AI 走 Genspark 帳號的雲端(本機不存 API key)。 + +**真正有參考價值的是 `packages/` 那層**——官方描述為「All pure TypeScript, no Electron dependency」,可以完全脫離 GUI 單獨閱讀。這是目前少見的、同時涵蓋 docx + xlsx + pptx + pdf 四種格式的現代開源實作。 + +三個具體對照點: + +**1. xlsx——macdoc 唯一缺的 OOXML 主格式** + +macdoc 有 word / pptx / keynote / pdf,沒有 Excel。genoffice 的做法是 UI 用 Univer core(Apache-2.0),import/export 走 Rust sidecar(calamine + IronCalc)。 +- `genoffice/packages/file-parse/src/xlsx.ts` — 解析入口,先看它把 xlsx 拆成什麼中介結構 +- `genoffice/apps/sheets/` — 上層怎麼消費 + +注意這是「要不要做 xlsx」的判斷材料,不是「該做」的理由。先問自己的工作流有沒有 Excel 需求,不要為了對齊功能表而追賽道。 + +**2. patch-narrowly / byte-preserving round-trip——跟 `ooxml-swift` op log 同目標、不同解法** + +genoffice 的 docx 存檔只重新產生被改動的段落,未觸碰的 block 保留原始 bytes,其餘 zip entry 逐 byte 複製。目的跟 `word-aligned-state-sync` 的 op log 一樣(存檔不破壞 Word 版面),但走的是「差異化重生」而非「op 重放」。 +- `genoffice/packages/docx-engine/src/patch.ts` — 核心 patch 邏輯 +- `genoffice/packages/docx-engine/src/text-patch.ts` — 文字層級的窄幅修改 +- `genoffice/packages/docx-engine/src/parse.ts` / `scan.ts` — 解析與掃描(patch 的前置) +- `genoffice/packages/docx-engine/src/generate.ts` — 產生端 +- `genoffice/packages/pptx-engine/src/zip.ts` — zip entry 保留策略 + +對照重點:python-docx 是「直接 mutate tree、沒有 op log」,genoffice 是「保留原 bytes + 窄幅重生」,macdoc 是「op log 重放」。三種解法擺在一起看,才知道 op log 的成本換到了什麼。 + +**3. pptx 功能廣度——`pptx-swift` 的擴充 checklist** + +`genoffice/packages/pptx-engine/src/` 有 macdoc 目前沒有的項目,可當功能對照表:`smartart.ts` / `smartart-layout.ts`、`custgeom.ts`(自訂幾何)、`animation.ts`、`theme-apply.ts`、`format-brush.ts`、`slide-transfer.ts`、`table-style.ts`。 + +**授權注意**:Apache-2.0,但 `ee/` 目錄保留給未來的 enterprise 模組(另一套 GenOffice Enterprise License)。GenOffice / Genspark 名稱與 logo 是 Mainfunc, Inc. 商標。當**設計參考**讀沒問題;若要逐行移植實作到 Swift,先確認 Apache-2.0 的 NOTICE 保留義務與 macdoc 自身授權相容。 + +**成熟度警語**:clone 當下(2026-08-04)發布版是 v0.4.110,pre-1.0,354 stars / 3 watchers。`main` 的 commit history 極短且訊息形如 `Sync snapshot (2026-08-03) (#6)`——是**內部開發、定期推 snapshot 出來**的模式,不是長期公開開發史,所以看不到 PR 討論、design rationale、bug 修復的來龍去脈,只能讀最終碼。程式碼本身看起來紮實(有 CI、Vitest、ESLint、SECURITY.md),但**不要當作經過長期生產驗證的參考**——跟 pandoc、python-docx 那種十年老專案不是同一個信賴等級。 + +上游仍在活躍同步(上次 snapshot 距 clone 僅一天),所以這份 clone 會很快過時。要更新直接 `cd reference/genoffice && git pull`;因為是 `--depth 1` 淺 clone,必要時 `git fetch --unshallow` 才拿得到完整歷史(但如上所述,歷史本身資訊量不高)。 + ### swift-argument-parser → `macdoc` CLI `macdoc` 的 `Sources/MacDocCLI/` 全部基於 `ArgumentParser`。遇到奇怪行為(subcommand completion、async command、ValidationError 訊息控制)時查: From 9220c3c97ba944c17edc12310c4c7c3cfeb4be0d Mon Sep 17 00:00:00 2001 From: che cheng Date: Thu, 13 Aug 2026 01:24:58 +0800 Subject: [PATCH 3/3] Align Word sidecar naming contract (#127) --- openspec/specs/ooxml-word-sync/spec.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openspec/specs/ooxml-word-sync/spec.md b/openspec/specs/ooxml-word-sync/spec.md index a506547e..cf7629bf 100644 --- a/openspec/specs/ooxml-word-sync/spec.md +++ b/openspec/specs/ooxml-word-sync/spec.md @@ -1106,12 +1106,12 @@ code: --- ### Requirement: Sidecar persistence of snapshot and log -The orchestrator SHALL persist the operation log as `.oplog.jsonl` and the most-recently-imported snapshot tree as `.snapshot.json` in the same directory as the docx. The orchestrator SHALL NOT write metadata into the docx itself. +The orchestrator SHALL persist the operation log as `.oplog.jsonl` and the most-recently-imported snapshot tree as `.snapshot.json` in the same directory as the docx. For example, `report.docx` uses `report.docx.oplog.jsonl` and `report.docx.snapshot.json`. The orchestrator SHALL NOT write metadata into the docx itself. During migration, loaders SHALL fall back to the legacy stem paths (`report.oplog.jsonl` / `report.snapshot.json`) when the full-name path is absent; writers SHALL create only the full-name paths. #### Scenario: Sidecar files created on first sync - **WHEN** `SyncOrchestrator.bootstrapFromDocx(url:)` runs on a docx with no existing sidecar files -- **THEN** `.oplog.jsonl` is created (initially empty) and `.snapshot.json` is created with the initial tree snapshot +- **THEN** `.oplog.jsonl` is created (initially empty) and `.snapshot.json` is created with the initial tree snapshot #### Scenario: docx contains zero sync metadata @@ -1291,13 +1291,13 @@ The orchestrator SHALL provide `SyncOrchestrator.bootstrapFromDocx(url:)` that i #### Scenario: Fresh docx without sidecars -- **GIVEN** `report.docx` exists with no `report.oplog.jsonl` and no `report.snapshot.json` +- **GIVEN** `report.docx` exists with no `report.docx.oplog.jsonl` and no `report.docx.snapshot.json` - **WHEN** `bootstrapFromDocx(url:)` runs - **THEN** sidecars are created with the docx's current state as the snapshot and an empty log; subsequent Swift mutations append to the new log #### Scenario: Existing sidecars are reused -- **GIVEN** `report.docx`, `report.oplog.jsonl` (with prior history), and `report.snapshot.json` (from prior session) all exist +- **GIVEN** `report.docx`, `report.docx.oplog.jsonl` (with prior history), and `report.docx.snapshot.json` (from prior session) all exist - **WHEN** `bootstrapFromDocx(url:)` runs - **THEN** the orchestrator loads the existing log and snapshot; if the docx has changed since the snapshot's timestamp, an import diff is run to capture the intervening changes @@ -1992,4 +1992,4 @@ code: - docs/stale-triage-chain-batch2-2026-05-25.md - .remember/logs/autonomous/save-144550.log - .remember/logs/autonomous/save-143700.log ---> \ No newline at end of file +-->