By PsychQuant
v3.20.0 cross-document OMath splice MCP tools (#160) — splice_omath_from_source + splice_paragraph_omath_from_source wrap ooxml-swift v0.24.0's spliceOMath API for verbatim copy of <m:oMath> XML blocks between WordDocument paragraphs. Source via source_path (Direct mode read-only) or source_doc_id (Session mode); target requires session-mode doc_id. Position via atStart/atEnd/afterText/beforeText with optional anchor + instance. Carrier preservation (Run.rawXML stays inline, unrecognizedChildren stays direct-child); joint document-order index for omath_index across both source carriers. rpr_mode controls source Run rPr propagation (full default verbatim / omathOnly whitelist / discard empty); namespace_policy controls prefix vs URI handling (lenient default accepts mml: vs m: prefix mismatch with same URI per ECMA-376 / strict throws on any mismatch). Error taxonomy returned as structured strings: sourceHasNoOMath / omathIndexOutOfRange / targetParagraphOutOfRange / anchorNotFound / namespaceMismatch / contextAnchorNotFound (batch only). Unblocks kiki830621/collaboration_guo_analysis Phase 7 inline-math restoration pipeline. Tests: 8 new Issue160SpliceOMathFromSourceTests (Direct/Session source modes, atEnd/afterText positions, error taxonomy, batch mode, rPr discard). Full suite: 297 passing, 0 failures, 9 pre-existing skips. Bumps ooxml-swift dep 0.21.0 → 0.24.0. v3.19.0 caption detection (#136) + estimate_paragraph_for_page structural weights v2 (#142). #136: two-layer detection — Paragraph.style primary + expanded prefix set (English Tab./Fig./Listing + CJK 表3/圖1 no-separator + U+3000 ideographic space) with digit-after-prefix guard rejecting body sentences like "Table reservations are required...". 17 new tests. #142: walker upgrade getParagraphs → collectStructuralBlocks enum (.paragraph/.table/.imageOnlyParagraph/.displayEquationParagraph). Per-block weights (12pt thesis calibration): table = tableRows × avgCellChars (200/row fallback), image = +200/drawing, display eq = 120 chars. New structural_breakdown metadata (9 sub-fields). API method bumped char_count_heuristic → char_count_heuristic_v2. ~95× thesis figure-counting accuracy improvement. paragraph_index semantics + getParagraphs() preserved (30+ other callers unaffected). Tests: 6 new + #89 backward-compat passes (text-only fixtures unchanged, just method literal updated). 1 P3 follow-up filed (#159 display-eq fixture limitation). v3.18.1 transitive dependency bump — ooxml-swift v0.21.11 → v0.22.1. Closes PsychQuant/che-word-mcp#155 (parent / mirror) auto-resolves via Package.resolved bump alone (no MCP source change). Pre-fix: che-word-mcp__search_text MCP tool's Server.swift:10310 calls para.getText(), which was a legacy 7-line implementation that only joined runs.map { $0.text } + hyperlink.text — missed every walker enhancement landed in flattenedDisplayText() over the #85 / #92 / #99 / #100 / #101 / #102 / #103 cluster. Callers couldn't grep for inline math symbols (α / β / γ / θ / λ / t) — silent zero gaps in match positions. Post-fix: ooxml-swift#43 collapsed Paragraph.getText() to single-line return flattenedDisplayText(); two text-extraction paths now return identical strings. Server.swift:10310 still calls para.getText() but that method now traverses inline OMML correctly. Position arithmetic now matches before_text / after_text anchor-matching paths. Downstream impact: kiki830621/collaboration_guo_analysis#6 (thesis 30 inline math symbols) unblocked from automation — re-running search_text 進行t檢定 against 碩士論文.docx para 324 now returns a match. Released via /idd-all #43 --cwd cross-repo IDD orchestration (issue-driven-dev v2.40.0). Closing summary at https://github.com/PsychQuant/ooxml-swift/issues/43#issuecomment-4365430488. v3.18.0 insert_equation argument-contract hardening (closes #105 #106 #107). v3.17.8 closes PsychQuant/che-word-mcp#98 — insert_equation MCP handler refactored across 3 commits (91506f8/357cbe7/339ab77). Pre-fix three structural defects: (1) silent-clamp on out-of-range paragraph_index via non-throwing insertParagraph(_:at: Int) — tool reported success but inserted at wrong location; (2) lib's #84/#91 InsertLocation overload + InsertLocationError.inlineModeRequiresParagraphIndex / .invalidParagraphIndex(Int) structured errors never reached MCP callers (handler self-built OMML and bypassed lib); (3) inline mode (display_mode=false) always created a NEW Paragraph(runs: [eqRun]) instead of appending OMML run to the EXISTING paragraph at paragraph_index. v1 (91506f8) tried delegating to lib but Codex 6-AI verify caught P1 regression: lib's Document.insertEquation overload internally uses @available(*, deprecated, ...) MathEquation flat output (Field.swift:301) — emits truncated '(a)/(b' AND nested <w:p><w:p> invalid OOXML. v2 (357cbe7) unified handler — both latex AND components paths use MathComponent.toOMML() for structurally correct OMML; display mode routes through lib's throwing insertParagraph(_:at: InsertLocation); inline mode handler-side appends OMML run to existing paragraph. v3 (339ab77) restored eqPara.properties.alignment = .center for display mode. BREAKING for inline mode callers: pre-fix inserted NEW paragraph; post-fix appends OMML run to EXISTING paragraph at paragraph_index. Migration: use display_mode=true for 'new paragraph with equation' or call insert_paragraph + insert_equation separately. 7 NEW Issue98InsertEquationLibBypassTests pin contracts (5 RED→GREEN scenarios + 2 quality regression tests including unzip -p document.xml verifying <m:f> structure + centering survives + deprecated '(a)/(b)' pattern absent). 6-AI verify ensemble (5 Claude reviewers + Codex gpt-5.5 xhigh) caught both P1 regressions in v1; Codex sanity check on v2 caught the centering P2. 6 P2/P3 follow-up issues filed (#105-#110). Suite: 236 → 243 tests, 0 failures, 9 pre-existing skips. Backward compatible except inline-mode BREAKING (documented). v3.17.7 ooxml-swift dep bump 0.21.10 → 0.21.11 — closes 5-issue cluster PsychQuant/che-word-mcp #99 + #100 + #101 + #102 + #103. Bilateral mirror coverage for direct-child OMML at 4 wrapper positions (<w:p> direct child for Pandoc display math / <w:hyperlink> direct child / <mc:Fallback> direct child / nested wrapper combos), plus 2 NEW library-wide spec capabilities. Pre-fix Paragraph.flattenedDisplayText AND Document.replaceInParagraphSurfaces shared a symmetric blind spot: direct-child <m:oMath>/<m:oMathPara> (not wrapped in <w:r>) was silently dropped → anchor lookups against paragraphs containing display math silently 0-matched. Spectra change flatten-replace-omml-bilateral-coverage. 2 NEW spec capabilities promoted to openspec/specs/: ooxml-paragraph-text-mirror (mirror invariant + ReplaceResult informative refusal contract) + ooxml-library-design-principles (Correctness primacy + Human-like operations as foundational normative invariants for all ooxml-swift mutators). Read side: flattenedDisplayText walks direct-child OMML at all 4 wrapper positions with source-XML position ordering. Write side: NEW public API WordDocument.replaceTextWithBoundaryDetection returns ReplaceResult enum (.replaced(count:) / .refusedDueToOMMLBoundary(occurrences:) / .mixed(replacedCount:, refusedOccurrences:)) with Occurrence(matchSpan:, ommlSpans:) carrying flattened-text coordinates. Mirror invariant — asymmetric by design: reads include OMML visibleText (anchor lookup universe extends to math); writes treat OMML as opaque structural units (refuse cross-OMML mutation rather than silently delete equations). Decision 4 raw passthrough preserved: direct-child OMML stays in Paragraph.unrecognizedChildren / HyperlinkChild.rawXML(_) / AlternateContent.rawXML — no parser change, no writer change, round-trip fidelity unaffected. MCP impact: replace_text and other anchor-lookup tools now find paragraphs containing direct-child OMML at all 4 wrapper positions; existing replace_text MCP tool unchanged (backward-compatible). Tests: 236 passing che-word-mcp / 813→829 ooxml-swift (+16 in Issue99FlattenReplaceOMMLBilateralTests). Backward compatible — strict superset of pre-fix behavior. v3.17.6 ooxml-swift dep bump 0.21.9 → 0.21.10 — closes PsychQuant/che-word-mcp#104. Form-level FieldParser canonical 5-run fldChar fix (orthogonal to v3.17.5's #94 container-level fix). Pre-fix update_all_fields returned silent no-op ('no SEQ fields found') on docs containing valid SEQ paragraphs at body top level when fldChar block was emitted in canonical 5-run form (each <w:fldChar>/<w:instrText>/<w:t> in its own <w:r> sibling — what DocxReader produces post-roundtrip and what native Word always emits). Pre-fix worked only on in-memory wrap_caption_seq output before save. Two ooxml-swift commits land via this dep bump: 537de62 FieldParser two-phase parse (Phase-1 baked form + Phase-2 parseFiveRunSpan state machine probing both Run.rawXML and Run.rawElements per recognizedRunChildren = ['rPr','t','drawing','oMath','oMathPara'] allowlist) + 58fe4f9 P1 sub-fix surfaced by 6-AI verify (Logic + Devil's Advocate runtime test): canonical-branch Run.text rewrite was silently overridden by Run.toXML() rawXML short-circuit; new rewriteCanonicalCachedText helper splices new value into embedded <w:t> while preserving <w:rPr> + xml:space=preserve, AND keeps Run.text in sync. MCP impact: update_all_fields now finds and updates SEQ fields in canonical 5-run form (post-roundtrip / native Word emission); list_captions benefits transitively via shared FieldParser. Verified by 6-AI ensemble (5 Claude reviewers + Codex gpt-5.5 xhigh) — 4 PASS / 2 WARN / 0 BLOCK; production reproducer rescue-swift-v317.docx via DocxReader path confirmed working. 5 P3 follow-ups filed in ooxml-swift (#29 SEQ Table coverage / #30 multi-paragraph counter / #31 multi-SEQ same paragraph / #32 DoS hardening / #33 discriminator invariant). Tests: 236 passing che-word-mcp / 809→813 ooxml-swift (+4 sub-tests in Issue104FieldParserCanonicalFormTests). Backward compatible — strict superset of pre-fix behavior. v3.17.5 ooxml-swift dep bump 0.21.8 → 0.21.9 — triple #87 + #93 + #94 release. #87 (Comment.paragraphIndex flat-counter, observable behavior change): list_comments paragraph_index now consistently 0-indexed against get_paragraphs() flat list; pre-fix off-by-N for any docx with non-paragraph BodyChild siblings before commented paragraph; callers manually compensating with paragraph_index - 1 must remove compensation. #93 (wrap_caption_seq SEQ inherits source position, caption visual fix): pre-fix 「圖 4-1:xxx」 became 「圖 4-:xxx1」 because new SEQ run had position=nil while source-loaded preText/postText had position>0; one-line fix seqRun.position = preRun.position; insert_bookmark=true × source-loaded paragraph still has same gap (filed PsychQuant/ooxml-swift#24, default insert_bookmark=false unaffected). #94 (update_all_fields traverses .table and .contentControl containers): pre-fix body loop only processed top-level .paragraph BodyChild, silently skipped .table and .contentControl(_, children:) — SEQ fields inside table cells/block-level SDTs never updated, returning 'no SEQ fields found' for thesis docs (caption paragraphs commonly live inside the table they describe); same gap #68 closed for findBodyChildContainingText; new walkAndProcessBodyChildForFields recursive walker mirrors #68 pattern; heading-count semantics: only top-level direct .paragraph body children count toward chapter-reset. Known incompleteness (3 follow-ups filed): ooxml-swift#25 header/footer/footnote/endnote SEQ scans still flat .paragraphs view; ooxml-swift#26 FieldParser.parse(paragraph:) misses inline SDT/hyperlink/fieldSimple/alternateContent surfaces; ooxml-swift#27 verify-with-user-fixture for real thesis docx roundtrip; plus ooxml-swift#28 refactor candidate (extract BodyChildVisitor protocol). Verified by 6-AI ensemble (5 Claude reviewers + Codex gpt-5.5 xhigh). Tests: 236 passing che-word-mcp / 805→809 ooxml-swift. Backward compatible except #87 documented behavior change. v3.17.4 paired #91 + #92 release. v3.17.3 bump ooxml-swift dep 0.21.6 → 0.21.7 (pure transitive bump, no MCP source changes; exposes public anchor lookup API). Three WordDocument APIs upgraded private → public (PsychQuant/che-word-mcp#86): findBodyChildContainingText(_:nthInstance:) instance method + bodyChildContainsText(_:needle:) static + tableContainsText(_:needle:) static. External Swift SPM consumers (rescue scripts, dxedit CLI, third-party tooling) can now call canonical anchor-lookup logic directly instead of reimplementing with diverging semantics (some skipped .contentControl recursion, some skipped table cell traversal pre-#68, some used different nthInstance counting rules). Result is exactly what insert_paragraph / insert_image_from_path / insert_caption etc. tools see when resolving after_text / before_text anchors. 10 new public-API surface tests in Issue86PublicAnchorLookupTests pin the canonical behavior across releases. Backward compatible: pure additive private → public visibility change; no API removals, no behavioral changes for existing callers. v3.17.2 bump ooxml-swift dep 0.21.2 → 0.21.6 (pure transitive bump, no MCP source changes; 4 ooxml-swift releases worth of hardening + new APIs land transparently). v0.21.3 (XML hardening, PsychQuant/ooxml-swift#7): DTD reject + 64KB attr-value cap + SAX-based root-element attribute parsing + name whitelist on emit. New XMLHardeningError throws on malicious .docx input. v0.21.4 (roundtrip loud-fail, PsychQuant/ooxml-swift#6): AlternateContent.fallbackRunsModified dirty flag throws RoundtripError.unserializedFallbackEdit on stale fallbackRuns mutation. Run.commentIds @available deprecated; migrate to commentRangeMarkers. v0.21.5 (insertEquation flexibility, PsychQuant/che-word-mcp#84 #85): InsertLocation overload for Document.insertEquation + flattenedDisplayText OMML coverage extends anchor lookup beyond plain runs. v0.21.6 (mutation surface, PsychQuant/ooxml-swift#5): Hyperlink.text setter @available deprecated (lossy); migrate to .runs property. Position field cascade Int = 0 → Int? = nil across 13 typed-child models. xml:space=preserve autosense in Run.toXMLThrowing emit. Plus 3 unreleased docs commits on ooxml-swift main (PsychQuant/ooxml-swift#14 #15 #17 + corrective cd841e7) covering needsPPr emit-gate ↔ Issue4 lock-in test bidirectional reference, parseRun vs parseParagraph walker pattern divergence rationale, foreign-namespace pPr asymmetry documentation. Tests: 236 passing (no regressions). Backward compatible: deprecation warnings only; no API removals. v3.17.1 bump ooxml-swift dep to v0.21.2 — pulls in pPr regression-guard + test infrastructure hardening from upstream (ooxml-swift#4 walker whitelist + #if DEBUG assert / ooxml-swift#13 empty <w:pPr/> self-closing test gap / ooxml-swift#16 countPPrOpenTags regex hardening excluding <w:pPrChange>). No public MCP tool change. v3.17.0 wrap_caption_seq MCP tool (Refs #62): Phase 2 of cross-repo work — exposes ooxml-swift v0.21.0 lib API as MCP tool. Bulk-wraps plain-text caption number portions in SEQ field runs across body paragraphs whose flattened text matches a regex (EXACTLY ONE numeric capture group). Captured digit becomes SEQ field cachedResult so Word's first-open render preserves user-typed numbering before F9. Rescues docs pasted from external sources (LaTeX-converted Word, Google Docs, Pandoc) so insert_table_of_figures / insert_table_of_tables produce populated TOFs. Idempotent: paragraphs already wrapping a SEQ field for sequence_name reported in skipped, never double-wrapped (detection covers both FieldSimple AND rawXML fldChar emissions). Phase 1 ships scope:body only (recurses into table cells + nestedTables + block-level SDT children); scope:all returns Error: scope_not_implemented for now (cross-container path lands in v3.17.x). Bookmark wrap opt-in (insert_bookmark + bookmark_template with literal ${number}) so default 23-caption rescue does NOT pollute list_bookmarks. Returns JSON: {matched_paragraphs, fields_inserted, paragraphs_modified:[idx,...], skipped:[{paragraph_index, reason},...]}. All preconditions checked BEFORE document mutation (regex compile + capture-group count + format/scope enums + bookmark_template invariant + doc_id opened). Tests: 5 new sub-tests in Issue62WrapCaptionSeqTests covering Scenarios 1-5. Suite 231 → 236 (+5, 0 fail / 9 skip). No ooxml-swift dep bump (still v0.21.0 from v3.16.2). v3.16.2 ooxml-swift dep bump 0.20.5 → 0.21.0 (Refs #62 #68): pure dep bump, no MCP source changes. Picks up two ooxml-swift fixes that surface transparently via existing tool dispatch. #68 (ooxml-swift v0.20.6): InsertLocation.findBodyChildContainingText now traverses .table (rows × cells × paragraphs + nestedTables) and .contentControl(_, children:) (recursive). MCP impact — insert_paragraph / insert_image_from_path / insert_equation / insert_caption calls using before_text / after_text now succeed when anchor text lives inside a table cell or block-level SDT (common in thesis docs with figure/table captions inside table cells). Returned position is top-level body.children index of the containing structure. Use into_table_cell for inside-cell inserts. Empty-needle guard: passing before_text:'' / after_text:'' now returns textNotFound instead of silently inserting at index 1. #62 (ooxml-swift v0.21.0): WordDocument.wrapCaptionSequenceFields(...) is now linked into the binary. Not yet exposed as an MCP tool — the wrap_caption_seq MCP wrapper ships in v3.17.0 (Phase 2 of the cross-repo work). Existing MCP tools unaffected. Suite: 231 → 231 (0 fail / 9 skip). v3.16.1 anchorPresence whitelist drift prevention (Refs #80): pure refactor, no runtime behavior change. New static toolAnchorWhitelists dict (single source of truth, keyed by MCP tool name → accepted anchor list) + new detectPresentAnchors(_:tool:) overload. 4 conflict-detection call sites switched from literal anchor arrays to (tool:) lookup. 4 new invariant/parity tests. Suite 227 → 231 (+4). Old (args, anchors:) overload preserved. Out-of-scope follow-ups: schema descriptions + dispatcher if-else chains still hardcode anchor names (pre-existing surfaces, not introduced by this PR). v3.16.0 Bundle B anchor DX consistency (Refs #70 #71 #72): BREAKING (input validation only) — three coordinated MCP-layer changes across the 4 #61-target tools. #71 (behavior) silent priority on conflicting anchors → structured error: insert_paragraph(after_text + index) was previously silent-priority; now returns 'Error: insert_paragraph: received conflicting anchors: after_text + index. Specify exactly one.' New static helper detectPresentAnchors with per-anchor type-aware predicates (null and wrong-type values do NOT count). #72 (validation) explicit text_instance ≤ 0 rejected — 'Error: <tool>: text_instance must be ≥ 1, got <N>.' Omitted text_instance still defaults to 1. #70 (DX) all 32 'return Error:' lines in 4 #61-target tools rewritten as 'Error: <tool>: <body>' for AI-caller error attribution. throw WordError.* paths unchanged. Scope deliberately limited to 4 tools; remaining 41 return Error lines elsewhere deferred to error-prefix-sweep follow-up. SemVer rationale (minor not major): no schema break, no tool removal, restricting previously-undefined behavior. Tests: 201 → 227 (+26 sub-tests, 0 fail / 9 skip). No ooxml-swift dep bump (still v0.20.5). v3.15.3 Bundle A2 polish from v3.15.2 verify R3-R6 follow-ups (Refs #76 #77 #78 #79): #76 (docs) insert_caption description corrected from '三種 anchor' to enumerate all 5 (paragraph_index / after_image_id / after_table_index / after_text / before_text); insert_equation paragraph_index description clarified that the int is body.children-indexed (cross-references PsychQuant/ooxml-swift#10 for the lib-layer convention split). #77 (docs) insert_caption anchor set wording precision in CHANGELOG / manifest / marketplace.json / plugin.json — was 'its own anchor set including after_table_index' (implies disjoint), now 'shares after_image_id / after_text / before_text / paragraph_index, adds after_table_index + position, lacks into_table_cell' (explicit shared/adds/lacks). #78 (test) extends #69 append-index regression pin to bookmarkMarker / rawBlockElement / block-level contentControl body-children — the table case alone wouldn't catch a regression to getParagraphs().count - 1 that breaks for SDT / TOC bookmark / vendor extensions. #79 (test) adds round-trip depth: testInsertParagraphAppendIndexRoundTripsForInsertCalls demonstrates insert-family round-trip works (append + insert(N+1) + verify ordering); testInsertParagraphAppendIndexCannotRoundTripToUpdate pins the cross-family trade-off (update_paragraph(index=N) throws WordError.invalidIndex). Tests: 196 → 201 (+5 sub-tests, 0 fail / 9 skip). No production code change. No ooxml-swift dep bump (still v0.20.5). v3.15.2 closes Bundle A polish from #61 R2 verify (Refs #69 #73 #74 #75): #69 (bug) insert_paragraph append message reports body.children index instead of getParagraphs().count - 1 (mis-reported in docs with tables/SDTs by skipping table children); #74 (bug) insert_image_from_path debug log labels after_image_id correctly (was silently labeled 'index' since v3.15.1); #73 (test) regression pin for equation F5 partial-dict guard (existed since v3.15.1 but was untested); #75 (docs) clarifies '3 insert tools' wording — scope is the 3 #61-target tools (insert_paragraph / insert_equation / insert_image_from_path); insert_caption is a 4th insert tool with a partially-overlapping anchor set (shares after_image_id / after_text / before_text / paragraph_index, adds after_table_index + position, lacks into_table_cell), intentionally outside this unification scope. Tests: 194 → 196 (0 fail / 9 skip). No behavior change in normal call paths. No ooxml-swift dep bump (still v0.20.5). Word MCP Server - Swift 原生 OOXML 操作,233 個工具。v3.15.1 closes verify findings F1+F2+F3+F5 from v3.15.0 6-AI ensemble (5 Claude reviewers + Codex gpt-5.5 xhigh):F1 (P1) `after_image_id` anchor 加到 insert_paragraph + insert_equation (display only) + insert_image_from_path — lib InsertLocation.afterImageId 從 #44 起就 ready 但只有 insert_caption 暴露 MCP-layer;v3.15.0 inherited 這個 gap,本 release 補齊。F2 (P1) `into_table_cell` 加到 insert_equation (display only) — display equation 是新建 paragraph,cell 放置 well-defined;inline mode 拒絕。F3 (P2) equation 成功訊息加 anchor info('Inserted equation (display mode: true, after text X (instance N))' 等)— 關閉同 v3.14.4 LOOKUP 的 over-claim 模式(caller 之前無法區分 anchor 命中 vs append fallthrough)。F5 (P2) malformed `into_table_cell` partial dict(傳 `{table_index: 0}` 缺 row + col)silent fallthrough → 走 next anchor / append → 結果在錯位置且 caller 不知。改回 structured 'Error: into_table_cell requires all three fields',3 #61-target tools 同步修(cross-cutting consistency)。Anchor priority unified across all 3 #61-target insert tools (`insert_paragraph` / `insert_equation` / `insert_image_from_path`; `insert_caption` has its own anchor set):into_table_cell > after_image_id > after_text > before_text > index > append。Inline equation 拒絕擴大 — 現在拒絕所有 4 個 anchor params(before/after_text + after_image_id + into_table_cell),不只 v3.15.0 的 2 個。Tests: Issue61V315PointReleaseTests (9 sub-tests cross 3 tools)。Suite 185 → 194 (0 fail / 9 pre-existing skips)。**No ooxml-swift dep bump** — 仍 v0.20.5(lib 從 #44 起就 ready)。Follow-up issues 另開:F4 inline equation 更通用設計 (e.g. into_paragraph_with_text) / F6 text anchor 擴及 table-cell paragraphs 與 block-level SDT / F7 getParagraphs().count - 1 message 在 doc 含 tables/SDTs 時 mis-report (pre-existing) / F8 error message 加 tool-prefix / F9 multiple anchor params 同時傳入 silent priority winner / F10 text_instance≤0 normalize。Backward compatible — schema additions optional,既有 v3.15.0 callers 不變;只有 malformed into_table_cell 從 silent fallthrough 改成 structured error(會被 buggy caller 注意到)+ equation message 加 suffix(substring 'Inserted equation' 仍存在)。v3.15.0 closes #61 — insert_paragraph 與 insert_equation 現在接受跟 insert_image_from_path 一致的 anchor 參數(after_text / before_text / text_instance / into_table_cell — into_table_cell 僅 insert_paragraph)。Pre-fix MCP 層 silently drop 這些參數 — JSON schema 接受但 handler dispatch 忽略,呼叫 fall through 到 legacy paragraph_index path 或 append at end。Lib API Document.insertParagraph(_: at: InsertLocation) 從 #44 起就支援所有六種 anchor cases(paragraphIndex / afterImageId / afterTableIndex / intoTableCell / afterText / beforeText),本 release 補齊 MCP 側 wire-up gap,無需 ooxml-swift dep bump(v0.20.5 已足夠)。Anchor priority mirror insert_image_from_path:into_table_cell > after_text > before_text > index > append。Errors(textNotFound / tableIndexOutOfRange / tableCellOutOfRange)回 structured 訊息而非 silent fallthrough — AI caller 能 surface failure 而非拿到位置錯誤的 misleading 'success'。**Inline equation explicit rejection**:insert_equation 在 display_mode=false(inline)時 explicitly 拒絕 after_text / before_text,回 structured error — 語意模糊('append OMML run into existing para containing this text' vs 'insert new para before/after target para'),inline placement 仍用 paragraph_index。Display-mode equation 建新 paragraph,anchor 語意明確。Tests: Issue61InsertParagraphAnchorsSmokeTests(5 sub-tests:after_text resolution / before_text resolution / text_instance disambiguation / into_table_cell append / textNotFound error)+ Issue61InsertEquationAnchorsSmokeTests(4 sub-tests:after_text + before_text in display mode / inline mode rejection / textNotFound error)。Suite 176 → 185 (0 fail / 9 pre-existing skips)。**No ooxml-swift dep bump** — v0.20.5 已有所有需要的 lib API。Backward compatible — anchor params 全 optional;既有 index / paragraph_index callers 不變;無 schema removal、無既有行為改動。**Real-world impact**:thesis-rescue / template-population workflow 不再需要 fall back 到「append at end + 手動 cut/paste in Word UI」或 binary-search 猜 paragraph_index,AI caller 對 3 #61-target insert tools(insert_image_from_path / insert_paragraph / insert_equation)對稱地用 surrounding context 定位 anchor。v3.14.5 closes Refs #63 verify F1 P1:擴充 findBodyChildContainingText 涵蓋所有 editable surfaces,補上 v3.14.4 CHANGELOG over-claim 的 insert anchor lookup gap。Pre-fix v3.14.4 只修了 REPLACE path(replace_text → Document.replaceInParagraphSurfaces 走 contentControls / hyperlinks / fieldSimples / alternateContents)但 LOOKUP path(findBodyChildContainingText 用於 InsertLocation.afterText / .beforeText 解析)只看 para.runs,所以 insert_image_from_path / insert_paragraph / insert_caption before_text/after_text 對 SDT-wrapped anchor 仍丟 textNotFound。Verify ensemble(5 Claude reviewers + Codex)的 requirements F1 P1 finding 抓到 CHANGELOG over-claim — 用戶選擇 Option B 擴充修而非縮 scope。ooxml-swift v0.20.5 新增 TextReplacementEngine.flatTextOfContentXML(read-only XML walker mirror replaceInContentXML flattening rules,跳過 <w:delText> / <w:instrText> / nested <w:sdt> subtrees)+ Paragraph.flattenedDisplayText 擴充 method 涵蓋 runs + hyperlinks + fieldSimples + alternateContents + contentControls(recursive into nested SDT children)。findBodyChildContainingText 改用 flattenedDisplayText 取代原本的 para.runs.map { $0.text }.joined()。新增 Issue63InsertAnchorInlineSDTTests(lib,3 wrappers × afterText/beforeText/insertImage = 3 sub-tests / 5 assertions)+ Issue63InsertAnchorInlineSDTSmokeTests(MCP,2 sub-tests pin lib-layer fix)。Suite 693 → 696 ooxml-swift / 174 → 176 che-word-mcp(0 fail)。基於 ooxml-swift v0.20.5。Backward compatible — strict superset of pre-fix lookup behavior(找到更多 anchors,既有 plain runs anchor 仍照常運作)。**Insert anchor lookup gap 此 release 完整補齊**,所有 inline wrappers 在 REPLACE + LOOKUP 兩個 path 都對稱覆蓋。v3.14.4 修 replace_text 對 inline `<w:sdt>` content control 的 wrapper coverage gap(Refs #63):Document.replaceInParagraphSurfaces 之前覆蓋 paragraph.runs / hyperlinks / fieldSimples / alternateContents 但 **沒有** paragraph.contentControls — 包在 inline `<w:sdt>` 裡的文字 silently 0-match。外部 converter(pandoc / Quarto / LaTeX→docx)習慣把 cross-ref placeholder([tab:foo] / [fig:bar] / [Smith 2020])包成 inline SDT,所以症狀跟 bracketed text 高度相關,但其實 **brackets 是 coincidence** — bracket-free needle 在 inline SDT 裡也 fail。Issue title「literal `[ ]` brackets」是誤導,差別測試(fldChar / fldSimple / hyperlink / inlineSDT 四個 inline wrapper × 四種 needle)證實只有 inline SDT case 失敗,其他三個 wrapper 從 v0.19.0+ #56 Phase 5 起就 typed-runs 覆蓋好了。Surgical fix architecture:ooxml-swift v0.20.4 新增 TextReplacementEngine.replaceInContentXML(XML DOM walker,wrap ContentControl.content 在 synthetic root xmlns:w,遍歷所有 `<w:t>` descendants 在 document order,build flat string + offset map mirror flattenRuns invariant,run same literal/regex find logic,splice replacements 回 `<w:t>` element string content;re-serialize wrapper children 去掉 wrapper tag)+ Document.replaceInContentControl(recursive helper 涵蓋 cc.content + cc.children 處理 nested SDT)。Wired 進 Document.replaceInParagraphSurfaces 接在 alternateContents loop 之後。設計上跳過:`<w:delText>`(TC deletion text,不顯示)、`<w:instrText>`(field instruction code,不顯示)、nested `<w:sdt>` subtrees(typed cc.children 由外層 recursion 處理避免 double-replacement)。Round-trip discipline:只 mutate `<w:t>` element 的 string content;xml:space="preserve" 與其他 attribute 完整保留(attribute set 從不被 touch)。新增 Issue63InlineSDTReplaceTests(4 個 wrapper × 4 個 needle 的 differential test + nested SDT recursion + round-trip wrapper preservation = 3 sub-tests / 18 assertions)+ MCP-layer Issue63ReplaceTextInlineSDTSmokeTests(2 sub-tests pin lib-layer fix)。Suite 690 → 693 ooxml-swift / 172 → 174 che-word-mcp(0 fail)。基於 ooxml-swift v0.20.4。Backward compatible — surgical fix 只新增 code path,沒改任何既有行為(runs/hyperlinks/fieldSimples/alternateContents replacement path 不動,ContentControl model 維持 raw XML storage 不重構)。Out-of-scope(separate follow-up):ContentControl 從 content:String 升級為 typed Run 列表(SDD-warranted refactor);smartTags / bidiOverrides / customXmlBlocks / unrecognizedChildren 維持 raw-carrier passthrough。v3.14.3 sub-stack E of paragraph-level content-equality (closes #66):Paragraph 新增 w14ParaId / w14TextId 欄位,提取並 round-trip <w:p> opening tag 上的 w14:* 屬性(Word 用於 collaborative editing 和 comment threading 的 revision-tracking GUIDs)。Plain attribute passthrough,String? typing — Word 的 GUIDs 是 8-char hex tokens(NOT RFC 4122 UUIDs),所以 opaque-string round-trip 是正確選擇。Pre-fix v3.14.2 silently dropped 兩個 attributes — 佔了 NTPU 論文 fixture w14:* token loss 的 ~95%(2214 / 2359 lost tokens 是這兩個 attrs)。Post-E 量測:w14: 保留率 10.55% → 93.98%;document.xml 流失 10.95% → 8.02%。Combined with sub-stack D (#65), total impact since v3.14.1:<w:lang> 50% → 98.89% (D)、w14:* 5% → 93.98% (E)、document.xml 流失 16.66% → 8.02% (D+E, -8.64 pp)。Matrix-pin testDocumentContentEqualityInvariant 同步抬升 floor(w14: 0.04→0.90、sizeLossRatio 上限 0.12→0.10)— matrix-pin 現在 LOAD-BEARING across **5 preservation classes**(rFonts/noProof/lang/kern/w14:)spanning run-level + paragraph-level + paragraph-mark scope。Defensive design (R2 review fixes):openingPTag() routes attributes through escapeXMLAttribute;parseParagraph rejects schema-invalid empty-string GUIDs。基於 ooxml-swift v0.20.3。Backward compatible(兩個 fields 都 optional、default nil;openingPTag empty-attrs gate 防止 synthetic emit)。剩餘 8% 流失主要是其他 w14:* attribute classes(如 w14:* on <w:r>)— tracked as separate follow-up SDD。v3.14.2 sub-stack D of paragraph-level content-equality (closes #65):ParagraphProperties 新增 markRunProperties 欄位,提取並 round-trip <w:rPr> direct child of <w:pPr> — paragraph-mark formatting per ECMA-376 §17.3.1.27 CT_PPrBase(控制 pilcrow ¶ 字符外觀的字型/顏色/語言/字距)。Reuses parseRunProperties verbatim — schema 跟 run-level CT_RPr 一致,所以 sub-stack C 的 typed extraction(rFonts 4-axis / noProof / kern / lang 3-axis)和 rawChildren passthrough(w14:* 效果)全部免費繼承。NTPU 論文 fixture 量測影響:<w:lang> 保留率 50% → 98.89%;<w:rFonts> 88% → 98.77%;<w:noProof> 92% → 100%;<w:kern> 84% → 99.93%;document.xml 大小流失 16.66% → 10.95%。Matrix-pin testDocumentContentEqualityInvariant 同步抬升 floor(lang 0.45→0.95、rFonts/noProof/kern 0.95、sizeLossRatio 上限 0.175→0.12)。Sub-stack E (#66 w14:paraId/textId) 接著 ship 到 v3.14.3,把流失壓到 < 5%,達成「edit 一個字 → document.xml shrinks <1%」strong demo。基於 ooxml-swift v0.20.2。Backward compatible(markRunProperties optional、default nil、writer empty-gate 防止 synthetic empty <w:rPr/>)。v3.14.1 sub-stack C-CONT closes triple-confirmed P0 (R2 + R5 + Codex 6-AI verify):recognizedRprChildren Set 列了 ~16+ rPr child kinds 為 'recognized' 但 parseRunProperties 沒有 typed extraction → silent drop。受影響的常見元素:<w:spacing>(character spacing)、<w:caps>/<w:smallCaps>、<w:position>、<w:shd>(run shading)、<w:bdr>、<w:em>(CJK emphasis marks)、<w:effect>、<w:vanish>/<w:specVanish>/<w:webHidden>、<w:outline>/<w:shadow>/<w:emboss>/<w:imprint>、<w:bCs>/<w:iCs>/<w:dstrike>。Fix:trim Set 到 ONLY actually-typed-extracted-or-emitted kinds。Round-trip size loss: pre-fix v3.13.x 32% → v3.14.0 17.75% → v3.14.1 16.66%。Methodology lesson (6th):P2 from one reviewer can become P0 when another applies real-world impact lens. v3.14.0 closes #60(sub-stack C of #58/#59/#60)— RunProperties field-loss audit。Bump ooxml-swift v0.19.13→v0.20.0。新增 typed fields:4-axis rFonts (ascii/hAnsi/eastAsia/cs/hint — 之前被收斂成單一值)、noProof、kern、3-axis lang (val/eastAsia/bidi),加上 rawChildren passthrough 處理 unrecognized rPr children(如 w14:textOutline / w14:textFill / w14:glow)。**Pre-fix MCP 用戶看到 eastAsia/cs 字型(如 DFKai-SB 用於繁體中文)在 round-trip 時 silently 被替換成 ascii 值;v3.14.0 完整保留 4 個 axis**。Matrix-pin testDocumentContentEqualityInvariant 加上 preservation-class-3 ratio-floor assertions,現在 LOAD-BEARING — 任何未來 RunProperties regression 都會被 matrix-pin 抓到。Thesis fixture document.xml round-trip 大小:pre-fix 32% 損失 → post-sub-stack-C 17.75% 損失(改善 14.25 percentage points)。剩餘 17.75% 是 paragraph-mark rPr + w14:paraId/textId drops(separate out-of-scope follow-up SDD)。**'if not typed, preserve as raw' 原則架構性完成** — 從 sub-stack A (#58 BodyChild)、B (#59 WhitespaceOverlay) 一路發展到 C (#60 RunProperties)。Backward compatible — 保留 fontName field,mirror rFonts.ascii。v3.13.13 CRITICAL HOTFIX (sub-stack B-CONT-2-CONT) reverted v3.13.12 的 TIER-0 over-fix。v3.13.12 (DO NOT USE — 刪除 <w:del> 內容)。v3.13.11 sub-stack B-CONT。基於 ooxml-swift v0.20.0。
Own this plugin?
Verify ownership to unlock analytics, metadata editing, and a verified badge. GitHub access is read-only (username + org membership).
Sign in to claimAdmin access level
Server config contains admin-level keywords
Based on adoption, maintenance, documentation, and repository signals. Not a security audit or endorsement.
macOS 行事曆與提醒事項 MCP Server - EventKit 整合,29 個工具,--cli 直接呼叫模式、--setup TCC 預授權、--self-update 自我升級+SHA-256 驗證、個別事件時區、復原/重做、週期事件 occurrence 操作、cleanup_completed_reminders 一鍵清除、清除到期日、星期驗證、MCP 層級 #標籤、冪等寫入、重複事件、地點觸發、結構化位置、彈性日期解析、模糊匹配、篩選/排序/限制
Protect files from AI-assisted deletion with the Archive-First strategy. PreToolUse hooks block destructive commands on archived/ paths. Toggle protection with archived-lock/archived-unlock.
Zotero reference manager + academic search + knowledge graph MCP Server
Telegram MCP Server Plugin — Bot API + 個人帳號 TDLib 全功能存取,28+ 工具,Keychain 密鑰管理
歸檔 LINE macOS 聊天記錄到文字檔
npx claudepluginhub psychquant/macdoc --plugin che-word-mcpComprehensive skill pack with 66 specialized skills for full-stack developers: 12 language experts (Python, TypeScript, Go, Rust, C++, Swift, Kotlin, C#, PHP, Java, SQL, JavaScript), 10 backend frameworks, 6 frontend/mobile, plus infrastructure, DevOps, security, and testing. Features progressive disclosure architecture for 50% faster loading.
Develop, test, build, and deploy Godot 4.x games with Claude Code. Includes GdUnit4 testing, web/desktop exports, CI/CD pipelines, and deployment to Vercel/GitHub Pages/itch.io.
Lazy senior dev mode. Forces the simplest, shortest solution that actually works: YAGNI, stdlib first, no unrequested abstractions.
Tools to maintain and improve CLAUDE.md files - audit quality, capture session learnings, and keep project memory current.
Browser automation and end-to-end testing MCP server by Microsoft. Enables Claude to interact with web pages, take screenshots, fill forms, click elements, and perform automated browser testing workflows.
Memory compression system for Claude Code - persist context across sessions