This project uses Spectra for Spec-Driven Development(SDD). Specs live in openspec/specs/, change proposals in openspec/changes/.
- A discussion needs structure before coding →
/spectra-discuss - User wants to plan, propose, or design a change →
/spectra-propose - Tasks are ready to implement →
/spectra-apply - There's an in-progress change to continue →
/spectra-ingest - User asks about specs or how something works →
/spectra-ask - Implementation is done →
/spectra-archive - Commit only files related to a specific change →
/spectra-commit
discuss? → propose → apply ⇄ ingest → archive
discussis optional — skip if requirements are clear- Requirements change mid-work? Plan mode →
ingest→ resumeapply
Changes can be parked(暫存)— temporarily moved out of openspec/changes/. Parked changes won't appear in spectra list but can be found with spectra list --parked. To restore: spectra unpark <name>. The /spectra-apply and /spectra-ingest skills handle parked changes automatically.
This file provides guidance to Claude Code when working with code in this repository.
macdoc 是一個原生 macOS 文件處理工具集,專注於文件格式解析、轉換和 OCR 功能。整個專案使用 Swift 開發,充分利用 Apple 平台的原生能力。
本 repo 同時是 Claude Code plugin marketplace(.claude-plugin/marketplace.json + plugins/,2026-07 起,#112):發布 che-word-mcp、che-pdf-mcp、che-pptx-mcp、macdoc 四個 plugins,使用者以 claude plugin marketplace add PsychQuant/macdoc 安裝。注意 plugins/(plugin shells,正常入版控)與 packages/(gitignored 本地套件)的差異;MCP shells 的 wrapper 從各 binary repo 的 GitHub Releases 自動下載 binary,安裝前強制驗證 sha256 + Developer ID 簽章鏈(requirement-based codesign,Team 6W377FS7BS)。發布新版時同步 bump plugins/<name>/.claude-plugin/plugin.json 與 .claude-plugin/marketplace.json 兩處版本;binary-backed plugin 的 binary_version 只在 binary repo 發新 release 後才改(shell-only 變更 bump version 即可,#116 解耦契約)。
macdoc/ # Monorepo 根目錄(同時也是 CLI 專案)
├── Package.swift # CLI 的 Swift Package 定義
├── Sources/
│ └── MacDocCLI/ # CLI 入口點
│ ├── MacDoc.swift # 主命令(Convert + PDF + Bib + Config + OCR + Docx + Word 子命令群)
│ ├── MacDoc+Convert.swift # Convert 統一轉換入口(16 路由,textutil-compatible)
│ ├── MacDoc+PDF.swift # PDF 子命令群(Phase 1 pipeline)
│ ├── MacDoc+PDF+Phase2.swift # PDF Phase 2 consolidation 子命令
│ ├── MacDoc+Bib.swift # Bib 子命令群(.bib → APA 7 HTML/Markdown/JSON)
│ ├── MacDoc+Config.swift# Config 子命令群(AI 設定管理)
│ └── CLIHelpers.swift # 共用 helpers(validatedInputURL, writeStringOutput 等)
├── Tests/
├── docs/ # 開發文檔和對話記錄
│ └── plans/ # 實作計畫
├── packages/ # 本地套件(.gitignore 忽略)
│ ├── common-converter-swift/ # Layer 2: 轉換器協議(DocumentConverter, StreamingOutput)
│ ├── word-to-md-swift/ # Layer 3: Word → Markdown
│ ├── html-to-md-swift/ # Layer 3: HTML → Markdown
│ ├── md-to-html-swift/ # Layer 3: Markdown → HTML
│ ├── word-to-html-swift/ # Layer 3: Word → HTML
│ ├── html-to-word-swift/ # Layer 3: HTML → Word
│ ├── md-to-word-swift/ # Layer 3: Markdown → Word
│ ├── pdf-to-md-swift/ # Layer 3: PDF → Markdown
│ ├── pdf-to-docx-swift/ # Layer 3: PDF → DOCX
│ ├── srt-to-html-swift/ # Layer 3: SRT → HTML
│ ├── marker-word-converter-swift/ # Layer 3: Word → Marker 模式
│ ├── bib-apa-to-html-swift/ # Layer 3: BibLaTeX → APA 7 HTML
│ ├── bib-apa-to-md-swift/ # Layer 3: BibLaTeX → APA 7 Markdown
│ ├── bib-apa-to-json-swift/ # Layer 3: BibLaTeX → APA 7 JSON
│ ├── bib-apa-swift/ # APA 7 styling engine
│ ├── ooxml-swift/ # Layer 1: OOXML (Word/Excel) 解析
│ ├── markdown-swift/ # Layer 1: Markdown 生成
│ ├── marker-swift/ # Layer 1: 圖片分類 + Marker 輸出
│ ├── surya-swift/ # Layer 1: OCR 文字辨識
│ └── pdf-to-latex-swift/ # PDF → LaTeX pipeline(簡化: GLM-OCR + Phase 2)
├── mcp/ # MCP 工具(各自獨立 git repo,.gitignore 忽略)
│ ├── che-word-mcp/ # Layer 4: Word 文件處理 MCP(245 工具)
│ └── che-pdf-mcp/ # Layer 4: PDF 文件處理 MCP(25 工具)
├── cli/ # CLI 實驗專案(預設 .gitignore;FastOCR 為 submodule)
│ └── FastOCR/ # GLM-OCR PDF→Markdown CLI + 實驗 harness(submodule)
└── reference/ # 參考專案(.gitignore 忽略)
Layer 4 (Consumers) Layer 3 (Converters) Layer 2 (Protocols) Layer 1 (Formats)
macdoc CLI ──────────┐
├──→ word-to-md-swift ──┬──→ common-converter-swift ooxml-swift
che-word-mcp ────────┘ ├──→ ooxml-swift markdown-swift
└──→ ooxml-swift (直接讀寫) └──→ markdown-swift marker-swift
surya-swift
macdoc CLI ──→ pdf-to-latex-swift (PDFToLaTeXCore) pdf-to-latex-swift
macdoc CLI ──→ bib-apa-to-html-swift ──→ bib-apa-swift ──→ biblatex-apa-swift
macdoc CLI ──→ bib-apa-to-md-swift ──→ bib-apa-swift ──→ biblatex-apa-swift
macdoc CLI ──→ word-builder-swift ──→ ooxml-swift (fluent Swift API for .docx, 1:1 mirror of docx.js)
che-pdf-mcp
└──→ Vision.framework / surya-swift
詳見 docs/modular-architecture.md。
# 建構主專案(debug,快速迭代)
swift build
# 建構 release(推薦,效能差 10-50x)
swift build -c release
# 安裝到 PATH(~/bin 需在 $PATH 中)
cp .build/release/macdoc ~/bin/macdoc
# 驗證
macdoc --version# 執行 CLI — 統一轉換入口(textutil-compatible,16 路由)
swift run macdoc convert --to md file.docx # Word → Markdown
swift run macdoc convert --to md file.docx --frontmatter # Word → Markdown(含 YAML frontmatter)
swift run macdoc convert --to html file.docx # Word → HTML
swift run macdoc convert --to marker file.docx # Word → Marker 目錄(.md + _meta.json + images/)
swift run macdoc convert --to html file.md [--full] # Markdown → HTML
swift run macdoc convert --to html file.md --html-extensions # Markdown → HTML(啟用擴充語法)
swift run macdoc convert --to docx file.md # Markdown → Word
swift run macdoc convert --to md file.html # HTML → Markdown
swift run macdoc convert --to docx file.html # HTML → Word
swift run macdoc convert --to pdf file.html # HTML → PDF(需要 playwright CLI)
swift run macdoc convert --to html file.srt [--full] [--css dark|light] # SRT → HTML(支援 speaker 偵測)
swift run macdoc convert --to md file.pdf # PDF → Markdown
swift run macdoc convert --to docx file.pdf # PDF → Word
swift run macdoc convert --to docx file.tex # TeX → Word
swift run macdoc convert --to html file.bib [--full] [--css minimal|web] # Bib → HTML
swift run macdoc convert --to md file.bib # Bib → Markdown
swift run macdoc convert --to json file.bib # Bib → JSON
# 執行 CLI — PDF pipeline(OCR + Phase 2 consolidation)
swift run macdoc pdf ocr --project /path/to/project # 整頁 GLM-OCR(預設 local MLX)
swift run macdoc pdf ocr --project /path/to/project --mode ollama # 透過 Ollama HTTP API
swift run macdoc pdf normalize --project /path/to/project
swift run macdoc pdf fix-envs --project /path/to/project [--fix]
swift run macdoc pdf compile-check --project /path/to/project
swift run macdoc pdf consolidate --project /path/to/project [--dry-run] [--agent codex|claude|gemini]
# (deprecated)舊的 block-level 轉寫命令,已被 pdf ocr 取代:
# swift run macdoc pdf transcribe --project /path/to/project --backend codex|claude|gemini
# swift run macdoc pdf transcribe-pages --project /path/to/project
# 執行 CLI — Bib(APA 7 格式轉換)
swift run macdoc bib list paper.bib [--show-type]
swift run macdoc bib to-html paper.bib -o refs.html [--full] [--css minimal|web]
swift run macdoc bib to-md paper.bib -o refs.md [--heading]
swift run macdoc bib to-html paper.bib --key cheng2025 --key yang2024
# AI 設定管理
swift run macdoc config ai detect
swift run macdoc config ai list
swift run macdoc config ai set agent claude
# OCR 設定管理(v1.1+:具名 host profile;供 pdf-to-latex 內部頁級 OCR 使用)
swift run macdoc config ocr list
swift run macdoc config ocr add-host kyle localhost:11435 # 例:SSH tunnel 到遠端 Ollama
swift run macdoc config ocr set-default kyle
# 注意:通用文字辨識入口 `macdoc ocr` 已移除(#145),改用 bestocr——
# 此處設定只影響 pdf-to-latex 管線內部的頁級 OCR
# 建構個別套件
cd packages/ooxml-swift && swift build
cd packages/markdown-swift && swift build
cd packages/marker-swift && swift build
cd packages/surya-swift && swift build
# 建構 MCP 工具(release 模式)
cd mcp/che-word-mcp && swift build -c release
cd mcp/che-pdf-mcp && swift build -c release# 測試主專案(在 repo 根目錄)
swift test
# 測試個別套件
cd packages/ooxml-swift && swift test
cd packages/marker-swift && swift test# 清除快取(更新本地套件後建議執行)
swift package clean && swift build- 用途:解析 Office Open XML 格式(.docx)
- 功能:段落、表格、清單解析、圖片提取、語義標註、樣式解析
- 依賴:ZIPFoundation
- 用途:生成 Markdown 文本
- 功能:Streaming 輸出、行內格式、特殊字元跳脫
- 依賴:無
- 用途:圖片分類和 Marker 格式輸出
- 依賴:markdown-swift
- 用途:OCR 文字辨識(Detection、Recognition、Table、ReadingOrder、LaTeX)
- 依賴:swift-async-algorithms
- 平台:macOS 14+, iOS 17+
- 用途:轉換器共用協議和模型
- 內容:
DocumentConverterprotocol,StreamingOutputprotocol,ConversionOptions,ConversionError - 依賴:無
- 用途:Word → Markdown 轉換
- 功能:streaming 轉換、標題/清單/表格偵測、行內格式、YAML frontmatter
- 依賴:common-converter-swift + ooxml-swift + markdown-swift
- API:
WordConverter.convert(input:)/WordConverter.convert(document:)/convertToString()
- 用途:PDF → LaTeX 轉換 pipeline
- Phase 1:PDF 掃描、頁面渲染、GLM-OCR 整頁轉錄、章節偵測、TeX 組裝(舊的 block-level AI 轉寫已 deprecated)
- Phase 2(consolidation):
AIConfig— AI CLI 工具設定(codex/claude/gemini 自動偵測,~/.config/macdoc/config.json)LaTeXNormalizer— document class 修正、符號正規化、跨頁去重LaTeXEnvChecker—\begin/\end配對檢查與修復TexCompileChecker— pdflatex log 解析(支援!和 file-line-error 格式)Consolidator— 機械步驟 + agent 迭代修復 orchestrator
- 依賴:swift-argument-parser
- 平台:macOS 14+
- 用途:CLI 工具,整合各套件功能
- Convert:統一轉換入口(
macdoc convert --to <format> <file>),textutil-compatible 語法,16 路由 - PDF:簡化 pipeline(init → render → ocr → chapters → assemble)+ Phase 2(normalize → fix-envs → compile-check → consolidate)。舊的 block-level transcribe 已 deprecated,改用整頁 GLM-OCR。
- Bib:BibLaTeX → APA 7 HTML/Markdown(to-html, to-md, list,支援 --key 過濾)
- Config:AI 後端設定管理
- 依賴:word-to-md-swift + marker-word-converter-swift + word-to-html-swift + html-to-word-swift + md-to-word-swift + pdf-to-md-swift + pdf-to-docx-swift + marker-swift + pdf-to-latex-swift + html-to-md-swift + md-to-html-swift + srt-to-html-swift + bib-apa-to-html-swift + bib-apa-to-json-swift + bib-apa-to-md-swift + ArgumentParser
- 用途:Word 文件處理 MCP,讓 Claude 能讀取和分析 Word 文件
- 功能:OOXML 讀寫(段落、表格、清單、圖片、樣式)+ Markdown 匯出 + 腳本管線(
export_script/get_script_coverage/execute_script——與macdoc word reverse同一條 ooxml-swift transcoder code path,byte-equal parity 由共享 library 結構保證,見 Spectra changeche-word-mcp-script-pipeline-parity) - 依賴:ooxml-swift + word-to-md-swift
- 架構:Server.swift(~16,000 行)+ satellite tool 檔(MarkdownExportTools / ReadbackTools / ScriptPipelineTools)
- Binary:
.build/release/CheWordMCP
- 用途:PDF 文件處理 MCP,讓 Claude 能讀取和分析 PDF 文件
- 功能:
- PDF 解析和文字提取
- Vision OCR(原生 macOS)
- 圖片提取
- 頁面資訊
- 依賴:Vision.framework, PDFKit
- 架構:模組化(分離 OCR、解析邏輯)
- Binary:
.build/release/ChePDFMCP
{
"mcpServers": {
"che-word-mcp": {
"command": "/path/to/macdoc/mcp/che-word-mcp/.build/release/CheWordMCP"
},
"che-pdf-mcp": {
"command": "/path/to/macdoc/mcp/che-pdf-mcp/.build/release/ChePDFMCP"
}
}
}所有轉換器採用 streaming 設計,避免將整份文件載入記憶體:
protocol StreamingOutput {
func write(_ text: String) throws
func writeLine(_ text: String) throws
}ooxml-swift 在解析階段產生語義標註,讓轉換器直接使用:
// 解析時標註
paragraph.semantic = .heading(level: 1)
paragraph.semantic = .bulletListItem(level: 0)
run.semantic = .formula(.omml)
// 轉換時直接使用
switch paragraph.semantic?.type {
case .heading(let level): // ...
case .paragraph: // ...
}新套件的 target / product / Sources/ 目錄名一律不加 Swift 後綴。 repo 叫
foo-to-bar-swift,module 就叫 FooToBar。
這是 Swift 生態系的慣例,不是本 repo 的偏好 —— Apple 自己的套件就是這個形狀:
| Repo | Module |
|---|---|
swift-markdown |
Markdown |
swift-argument-parser |
ArgumentParser |
swift-async-algorithms |
AsyncAlgorithms |
repo 名負責標示語言,module 名不必再說一次;在 Swift 檔案裡寫 import OOXMLSwift
是把「Swift」講兩遍。本 repo 的 29 個 target 已有 20 個是這個形狀(HTMLToMD、
PDFToDOCX、NoteToPDF、BibAPAToHTML…),所以這是把既有多數寫下來,不是新規定。
既有的 9 個帶後綴者不做大掃除。 改 module 名是對每個 consumer 的 breaking change
(所有 import 都要跟著改),成本與消費者數量成正比:
| 類別 | 例 | 消費者 | 何時改 |
|---|---|---|---|
| Converter,只有 macdoc 用 | WordToMDSwift → WordToMD(已完成,word-to-md-swift 1.0.0) |
少數 | 該套件本來就要發 breaking release 時順手 |
| 廣用函式庫 | OOXMLSwift |
25+ 套件跨 3 repo | 不改 —— 為了美觀發一輪全圖 major bump 不划算 |
判準是「這次改名有沒有搭上一班本來就要開的車」。沒有就別發車。
DocumentConverter- 文件轉換協議ImageClassifier- 圖片分類協議StreamingOutput- 輸出協議
任何第一方 Package.swift 都不得宣告 branch:。 這不是風格偏好,是踩過的坑:
branch: 記的是一個 revision,swift build 永不推進它;而且它是 unversioned requirement,會壓過整張圖的版本範圍。所以它不是「追最新」,是「凍結,並且讓別人的版本需求失效」。
2026-09-08 實測到的後果(macdoc#184):
- word-builder-swift 的一條
branch: "main"宣告,同時解出兩個不同的舊 revision —— macdoc 拿到 ooxml-swift v3.2.0、word-builder 自己的 resolve 停在 v3.0.0,而宣告旁的註解寫著「always picks up the latest」。 - 它還被烤進已發布的
v1.0.0tag,於是每個外部消費者都繼承一個不可重現的建置。 - 拿掉它之後才發現版本圖本來就無解:六個套件宣告
from: "0.5.x"/"0.7.0",SwiftPM 的from:封頂在下一個 major,等於< 1.0.0,與另外四個的2.0.0..<4.0.0互斥。pin 遮的不只是落後,是不可滿足性。 - 它同時遮住了 macdoc CLI 自己的編譯破口(
TranscodeError.rawSlotExecutionFailure,ooxml-swift v3.5.0 新增卻從未處理)。
反模式會靠引用繁殖:docx-workflow-swift 當初就是照抄 word-builder 的做法,理由寫「per the word-builder-swift v1.0.0 policy」。所以這條要寫成規則而不是留在 issue 裡。
現況(2026-09-08):from: "3.7.0"(ooxml-swift)與 from: "1.0.2"(word-builder-swift),第一方 manifest 零 branch:。packages/token-counter-swift 的 revision: 是第三方 fork 的刻意釘選,不在此規則內。
所有套件皆使用 url: 遠端依賴。
# 1. 在套件目錄提交、推送、打 tag
cd packages/ooxml-swift
git add . && git commit -m "feat: 描述"
git push origin main
git tag v0.3.0 && git push --tags
# 2. 回到主專案更新依賴
cd ../..
swift package update
swift build若需要本地開發迭代,可暫時將 Package.swift 中的 url: 改為 path: 指向本地路徑,完成後再改回。
主 repo 以兩種方式追蹤外部 repo:
- Submodule(
.gitmodules):mcp/下三個 MCP server。Clone 主 repo 時加--recurse-submodules會自動拉齊,或事後git submodule update --init --recursive - Gitignore 忽略(各自獨立管理):
packages/下的 Swift 套件、reference/。重建環境時在對應目錄git clone即可
| 目錄 | Git Remote | 說明 |
|---|---|---|
. (root) |
https://github.com/PsychQuant/macdoc.git | 主專案 CLI |
packages/common-converter-swift |
https://github.com/PsychQuant/doc-converter-swift.git | 轉換器協議(remote 名 doc-converter-swift) |
packages/word-to-md-swift |
https://github.com/PsychQuant/word-to-md-swift.git | Word → MD 轉換 |
packages/word-builder-swift |
https://github.com/PsychQuant/word-builder-swift.git | Lens-model authoring surface for .docx (v1.0.2+) — wraps OOXMLSwift.WordDocument |
packages/docx-workflow-swift |
(local only — not yet published) | Layer 3 manifest-driven docx-edit library on top of word-builder-swift v1.0.2 |
packages/ooxml-swift |
https://github.com/PsychQuant/ooxml-swift.git | OOXML 解析 |
packages/markdown-swift |
https://github.com/PsychQuant/markdown-swift.git | Markdown 生成 |
packages/marker-swift |
https://github.com/PsychQuant/marker-swift.git | 圖片分類 |
packages/surya-swift |
(local only) | OCR 文字辨識 |
packages/pptx-swift |
https://github.com/PsychQuant/pptx-swift.git | PresentationML (.pptx) 解析與生成(v0.1.0+) |
packages/pdf-to-latex-swift |
https://github.com/PsychQuant/pdf-to-latex-swift.git | PDF → LaTeX pipeline (consumed via remote url dep since #79) |
packages/ocr-swift |
https://github.com/PsychQuant/ocr-swift.git | OCR pipeline (MLX + Ollama backends, PDFKit extractor; consumed via remote url dep since #79) |
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) |
reference/* |
見 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 packagepackages/ocr-swift(PsychQuant/ocr-swift)取用 OCR;搬走的只是 benchmark 儀器。遷移全紀錄見 bestOCR repo 的docs/migration-2026-07-18.md。
Sources/MacDocCLI/MacDoc.swift- CLI 入口點(Convert + PDF + Bib + Config + OCR + Docx + Word 子命令群)Sources/MacDocCLI/MacDoc+Docx.swift-macdoc docx ...子命令(apply / plan / verify / diff —— manifest-driven .docx edit workflows,per openspec changemacdoc-docx-workflow-cli,library 在packages/docx-workflow-swift)Sources/MacDocCLI/MacDoc+Word+Render.swift-macdoc word render <script.mdocx.swift|.mdocx> --to-docx <out> [--verify-against <ref.docx>] [--force](腳本 → docx;word reverse的反向半邊,補實mdocx-grammar早已具名卻從未實作的命令)。與 che-word-mcp 的execute_script呼叫同一個 shared entry point(ooxml-swiftTranscode/ScriptPipelineExecute.swift的scriptPipelineExecute,v2.1.0 起),兩面因此由結構保證一致而非靠慣例。--verify-against是 opt-in:不給就不驗、也不印任何驗證結論——沉默永遠不等於通過;給了則不符時 exit 非零並列出不符的 part。ordering contract:參考檔在任何寫入之前先讀進記憶體,因此--to-docx與--verify-against指向同一路徑時比對的是寫入前的位元組,不會自我比對出假通過。Sources/MacDocCLI/MacDoc+Word.swift-macdoc word reverse <docx> --to-mdocx <out> [--from-oplog] [--force] [--coverage] [--paragraphs-only] [--slot name=paraId]…(docx →.mdocx.swift腳本反向轉換;transcoder 本體在 ooxml-swift 的ScriptExporter/ScriptImporter)。預設 full-fidelity(format-alignment-engine Phase C #130):全 parts 騎在腳本上(raw channel byte-equal floor)+ typed DSL 升級(ReverseExtractor的 trial-rebuild byte-equal gate 通過才升級,涵蓋 run rPr / paragraph pPr / sections / canonical tables 五層);執行腳本重建出 Stage B byte-equal 的 docx。真實 Word 文件的 document.xml 現在會升級(word-canonical-forms #131,ooxml-swift v1.4.0):新增 Word-canonical 詞彙(root namespace 雲、rsid 家族、xml:space、inline passthrough markers(bookmark/proofErr)、pPr/rPr 長尾、docGrid/section-type/pgSz、CRLF prolog)後,90_template_ja.docx(JPA 日文學術 template)的 document.xml 由 0% 升到 per-part 100%(aggregate 53.5%,餘量為尚無 typed 表示的 sibling parts)。--paragraphs-only退回舊的段落 text+styleId 反向(無 byte-equal 保證);有 oplog sidecar 時仍優先匯出現況 log。--coverage印出 dual-track 覆蓋率報告:每個 part 的 DSL/raw split + aggregate %(DSL 份額 = byte-equal 證明過的 typed 重建;raw = 逐字搬運;基線數字見 docs/format-alignment-baselines.md)。--slot name=paraId(可重複,Phase D + #131):指定段落的文字成為腳本的 Swift 函式參數;DSL-spellable 段落走 script-text 參數,raw-form 格式化段落(真實 template 常見)走 op-level 替換(// @slotdirective + 替換setRunsrun text),raw-channel 文件(整個 document.xml 落 raw,如含表格的官方表單)走 carried XML 內 paraId 定位的 run 級手術(// @slot-rawdirective;#171,ooxml-swift v3.5.0——結構感知定位、identity-shortcut default、fail-loud import+術後 well-formedness 驗證),三者都 strict mode 明確指定、不推斷;無 slot 時腳本逐字重建 byte-equal。能拼寫 ≠ 理解渲染效果(render-effect-semantics 第三層):typed 欄位對排版的實際效果由 docs/render-effect-registry.md 台帳記錄——每條 entry 須經 gated perturbation probe(RUN_WORD_INTEGRATION=1 swift test --filter RenderEffectProbeTests,真實 Word 渲染 + PDFKit 幾何量測)驗證方標verified(no probe, no claim);slot 換內容另有渲染驗收(RealTemplateUpgradeTests scenario (d):頁數/頁框/被替換頁行距結構不變、未動頁 pixel-equal)Sources/MacDocCLI/MacDoc+Convert.swift- Convert 統一轉換入口(16 路由,textutil-compatible)Sources/MacDocCLI/MacDoc+PDF.swift- PDF 子命令(簡化 pipeline: ocr + Phase 2 consolidation)Sources/MacDocCLI/MacDoc+OCR.swift- deprecation shim(#145):macdoc ocr已移除,印遷移訊息指向 bestocr 並以 exit 2 結束。通用文字辨識歸 PsychQuant/bestOCR 單點;pdf-to-latex 內部頁級 OCR(PageOCRRunner)不受影響,其委派屬第二期(bestOCR#55 介面定案後)Sources/MacDocCLI/MacDoc+Bib.swift- Bib 子命令(.bib → APA 7 HTML/Markdown,支援 --key 過濾)Sources/MacDocCLI/MacDoc+Config.swift- Config 子命令(AI 設定管理)
Sources/PDFToLaTeXCore/AIConfig.swift- AI CLI 工具設定Sources/PDFToLaTeXCore/LaTeXNormalizer.swift- 機械式 LaTeX 清理Sources/PDFToLaTeXCore/LaTeXEnvChecker.swift- 環境配對檢查Sources/PDFToLaTeXCore/TexCompileChecker.swift- 編譯錯誤解析Sources/PDFToLaTeXCore/Consolidator.swift- consolidation orchestrator
Sources/SRTToHTML/SRTConverter.swift- SRT → HTML 轉換器- Speaker 偵測:自動辨識兩種格式,產出
<span class="speaker">badge +data-speaker="N"屬性- 冒號格式:
Speaker 1: text(Otter.ai、Google Meet、部分 Plaud) - 方括號格式:
[Speaker 1] text(Whisper、Assembly AI、部分 Plaud)
- 冒號格式:
- CSS 主題:
--css dark(深色卡片)或--css light(淺色列表,適合列印) - 輸出模式:
--full輸出完整 HTML 文件,否則只輸出<main>fragment
Sources/CommonConverterSwift/Protocols/DocumentConverter.swift- 轉換器 protocolSources/CommonConverterSwift/Protocols/StreamingOutput.swift- 串流輸出 protocol
Sources/WordToMD/WordConverter.swift- Word → Markdown 轉換器(module 於 1.0.0 由WordToMDSwift更名)
Sources/OOXMLSwift/IO/DocxReader.swift- Word 文件讀取Sources/OOXMLSwift/Models/SemanticAnnotation.swift- 語義標註定義
Sources/CheWordMCP/Server.swift- MCP 伺服器主體(245 工具;script-pipeline handlers 在 ScriptPipelineTools.swift)Package.swift- 依賴 ooxml-swift + word-to-md-swift
Sources/ChePDFMCP/Server.swift- MCP 伺服器主體(25 工具)Sources/ChePDFMCP/VisionOCR.swift- Vision OCR 實作
測試時可使用任意 .docx 文件:
swift run macdoc convert --to md /path/to/test.docx
swift run macdoc convert --to marker /path/to/test.docx -o /tmp/test_output/Tests/MacDocCLITests/NotePDFConvertTests.swift 和 NoteHTMLConvertTests.swift 跑 .note → pdf/html 的端到端 smoke coverage(#81)。兩個 test 透過 CLITestHelper.noteFixture() 找 test-files/*.note 樣本,找不到就 XCTSkip — CI / clean-clone 不會 fail,只會跳過。
若要在本機實際跑 coverage,把任一 .note 檔放到 test-files/(該目錄被 .gitignore 忽略,檔案不會入版控)。committable 小 fixture 是 follow-up(見 #79 討論 serial)。
- macOS 14+ (macdoc, pdf-to-latex-swift)
- macOS 13+ (ooxml-swift, markdown-swift, marker-swift)
- macOS 14+ / iOS 17+ (surya-swift)
- Swift 5.9+