Guidance for Claude-family coding agents working on the vChewing (唯音) macOS repository. Treat AGENTS.md as canonical for architecture and workflow; align with .github/copilot-instructions.md for shared guardrails. Use only English or zh-Hant-TW in documentation/comments/reviews; zh-Hans is allowed only in filename stems ending with -CHS, and there the required style is zh-Hans-TW — characters simplified, Taiwan vocabulary kept.
- Language:Documentation、comments、reviews 僅能使用 English 或 zh-Hant-TW(檔名結尾
-CHS可用 zh-Hans,且該處一律為 zh-Hans-TW:僅做字元簡化、詞彙沿用台灣用語——「支援」不寫成「支持」、「記憶體」寫成「记忆体」而非「内存」、「硬碟」不寫成「硬盘」。把-CHS檔的用詞改成大陸用法是漂移、不是修好)。尤其注意中文資訊電子術語必須得是 zh-Hant-TW。 - Commits:遵循
ModuleName // SubModuleName: Change.的 Conventional Commit 風格。 - Scope:主要工作區位於
Packages/。Linux 環境僅構建vChewing_OSNeutral_LibVanguard與其依賴。macOS 構建使用Package.swift+Makefile+BundleAppsCommandPlugin。另有一條附加的、僅供本地驗收的 Swift 5.10 路徑(Swift 5.10 toolchain + Command Line Tools 之MacOSX13.3.sdk(/Library/Developer/CommandLineTools/SDKs/;Xcode 15 內那份只是 symlink,且現行 CLT 已改為移除它、須自行備妥)、目標x86_64-apple-macosx10.9,且須以一個「預設 SDK ≤ 14.x」的 Xcode(=任何 ≤ 15.4 者)為 active developer directory——--sdk不會傳到 build plugin 的編譯):逐套件只產出 static.a(make build510/make clean510),倉根Package@swift-5.10.swift則產出兩支執行檔(vChewing、vChewingInstallerLegacy,make debugLegacy/make releaseLegacy/make archiveLegacy/make cleanLegacy、scratch.build/.legacy-root)。debugLegacy出單一 x86_64(macOS 10.9)slice、可動但未最佳化;releaseLegacy另建arm64-apple-macosx11.0slice 並 lipo 成 universal。兩者收尾都會自行組 bundle($(MAKE) bundleLegacy LEGACY_CONFIG=<cfg>)——兩個 config 共用同一個Build/Products/Legacy/,若把組裝留給手跑的make bundleLegacy(其預設 config 為debug),就會把未最佳化的產物包進.app(實測發生過一次)。兩者也一律補-Xlinker -platform_version -Xlinker macos -Xlinker <min> -Xlinker <sdkVersion>(版本讀$(LEGACY_SDK)/SDKSettings.plist):SwiftPM 5.10 會把那一格填成 triple 的版本,不覆寫則執行檔自稱sdk 10.9而實以 13.3 的 SDK 鏈結——AppKit 正是讀該欄決定要不要把 app 鎖進 Aqua,vChewingInstallerLegacy沒有暗色模式即由此而來(IME 僅因其 plist 帶NSRequiresAquaSystemAppearance而倖免),其中只有 x86_64 支線 force-loadLegacyZone/ARCLite/libarclite_macosx.a(arm64 沒有 11.0 以下的 macOS、其 ARC 執行期自 11 起即在 libobjc 內,且該 archive 僅有 x86_64 一個 slice),故該 link flag 由makefile按 triple 下、不在 manifest 內。再由BundleAppsLegacyplugin 自各 Xcode 蒐集 back-deployment Swift 執行期動態庫進Frameworks/,並以「附加 fallback rpath」的方式讓 10.9–10.13 走該副本、現行系統仍走系統內建執行期,最後於Build/Products/Legacy/組出兩份.app(make bundleLegacy),兩份Info.plist亦補上 Xcode 慣例的DT*建置環境鍵(DTSDKName/DTSDKBuild/DTPlatformVersion/DTXcode/DTXcodeBuild/BuildMachineOSBuild等)——plugin 讀<sdk>/../../Info.plist之AdditionalInfo(Xcode 自己蓋章所依據的同份模板)並即時解析其$(…)變數,--sdk由make bundleLegacy傳入$(LEGACY_SDK);未傳則不注入。LSMinimumSystemVersion刻意不自該模板抄入,一律 pin 在legacyDeploymentTarget。。該 plugin 另會清掉建置機留下的絕對LC_RPATH(SwiftPM 會把供給執行期的那條 toolchain 路徑寫成絕對路徑,在 bundle 內永遠贏不了、也只存在於跑建置的機器上),只留/usr/lib/swift與 bundle 相對者;而自 2026-09-16 起整個 5.10 閉包已零 concurrency 引用(每 slice 20/20 archive 乾淨、兩支執行檔之swift_task_*未定符號為 0),故libswift_Concurrency.dylib不再是任何載入記錄。另:CGRect.seniorTheBeast一律是各消費檔檔尾的fileprivate常數(不放在SwiftExtension),legacy 倉逐檔同構——其LibVanguard/Session/兩檔與本倉逐位元組相同。另:legacy 之 app-bundle 安裝程式在 Finder 中的顯示名(CFBundleName,靠LSHasLocalizedDisplayName生效)與主線不同,來源是LegacyZone/InstallerLocalizations/<lproj>/InfoPlist.strings(IME 側另有對位的LegacyZone/IMELocalizations/<lproj>/InfoPlist.strings,把NSHumanReadableCopyright改寫為Aqua Special Build. …,供 About 面板顯示),由BundleAppsLegacy於複製 lproj 之後 merge 進去(merge 而非取代,以保CFEULAContent);該目錄刻意不放在Sources/Installer_macOS/之下——那裡是 Xcode 的同步根群組,新目錄會被掃進現代安裝程式的資源 phase。權威工具鏈為 Swift 6.4+(6.2/6.3 由封堵檔擋下)、runtime 目標仍為 macOS 12+。P217 之下,逐套件以Package@swift-5.10.swift(+ 6.0/6.1/6.2/6.3 封堵檔)與各自的makefile為入口;聚合體vChewing_OSNeutral_LibVanguard的這一套(六份 manifest + 其makefile)即該佈局的參考實作。部署地板為 macOS 10.9,不容犧牲——支援它是這條路徑存在的唯一意義:兩支 legacy bundle 之legacyDeploymentTarget、倉根Makefile之LEGACY_X86_TRIPLE、以及 20 份逐包makefile之LEGACY_TRIPLE一律10.9(arm64 slice 仍為11.0,那是 arm64 的下限);維持該地板之代價是vChewing_SettingsUI裡三處#available(macOS 10.10, *)守衛。AppKit API 之 availability 有疑者,一律照vChewing-OSX-Legacy(10.9-compliant 參照)的寫法。該倉已於 vChewing 4.8.0 封存——legacy 發行版之建置自此唯由本倉承擔,故它只作參照、勿再回寫。三則 10.9 專屬陷阱:① libdispatch 在 10.9 拒收 NULL block——setEventHandler(handler: nil)會被此路徑內建的 Swift 5.0 back-deployment shim 原樣轉成dispatch_source_set_event_handler(source, NULL),10.9 的 libdispatch 對此直接 BUG(SIGILL),一律改傳{}(2026-09-16 前vChewingInstallerLegacy一按「安裝」數秒即崩,現已修;現代系統容忍 NULL,故 6.4 側從未顯露);②LEGACY_SDK現直接綁 CLT 那份MacOSX13.3.sdk(Xcode 15 自帶的是 macOS 14 系、其同名目錄只是 symlink;且該 SDK 屬 legacy——現行 CLT 已改成「移除包」,換機時須自 macOS 13.3 的 CLT/Xcode 14.3 自行備妥);③ 辭典資產自此自動建置——bundleLegacy之前置lexiconLegacy會跑LegacyZone/LexiconBuildTrigger,其 config 變數為LEXICON_CONFIG(預設release;刻意不叫LEGACY_CONFIG,後者指 app 的 config 且會隨 sub-make 外洩,同名會把詞典建置拖回 debug)。另:Xcode 無法用另裝的 OpenSource toolchain 解讀 Swift Package(套件解析固定用它自己內建的 toolchain),故 Intel Mac(Xcode 上限 26.x、內建 Swift < 6.4)已不能以 Xcode 建置本倉,只能走 SwiftPM CLI + 6.4+ toolchain;Apple silicon 不受影響。細節見AGENTS.md§2。 - UI 規範:視窗預設以 AppKit 實作——使用
vChewing_OSFrameworkImpl的 AppKit Result Builder DSL、不得引入 Interface Builder 資產;例外為vChewing_SettingsUI的 macOS 14+ SwiftUI 設定介面(含 PhraseEditor 語彙編輯器與 About 窗格)與vChewing_InstallerAssembly4Darwin安裝程式的 SwiftUI。 - FSM 流程:維持
InputSession → InputHandler (→ Homa) → IMEState流程;新增 API 時先更新協定(SessionCoreProtocol提供共用的switchState()/resetInputHandler()預設實作;InputHandlerProtocol處理輸入事件分診)。Sessions 體系已遷移至 LibVanguard 且 OS-independent——所有 OS-dependent 動作(LXMgr、IMEApp、Notifier、AppDelegate、NS*、IMKHelper 等)一律經SessionHost閉包注入(見SessionHostWiring.swift),不要在 portable 會話程式碼內直接呼叫 Darwin 專屬 API。 - Lexicon:詞庫資源由遠端 Swift Package plugin
VanguardTextMapPlugin(來自vChewing-VanguardLexicon倉庫)提供,構建時以.txtMap/.revlookup格式動態注入至vChewing_MainAssembly4Darwin;編譯後的成品為暫時構建產物,不應簽入版控。 - ObjC(++)/C(++) 風格:Objective-C(++) 與 C(++) 原始碼請遵守 Google Style Guide 的格式規範。
- 使用者資料路徑:除非是 Swift Package 的測試目標所需,請勿在程式中寫死使用者資料路徑。
Packages/vChewing_MainAssembly4Darwin/.../SessionController/InputSession_DarwinSurface.swift:IMK 進入表面(InputSession的 Darwin 端:controller 綁定、NSEvent→KBEvent 轉換、IMKInputController surface、toggleInputModeTIS 邏輯);SessionHostWiring.swift注入SessionHost閉包。Packages/vChewing_MainAssembly4Darwin/.../LXManager/BundleAccessor.swift:自訂Bundle.currentSPM查詢器,用於定位 factory 詞庫資源。Packages/vChewing_SettingsUI/:偏好設定獨立套件——SwiftUISettingsUI(macOS 14+,含 PhraseEditor 語彙編輯器與 About 窗格)與 AppKitSettingsCocoa並存;主程式端以SettingsUIHostWiring.swift(SettingsUIHost閉包注入)接線。Packages/vChewing_OSNeutral_LibVanguard/Sources/LibVanguard/InputHandler/:FSM 實作、Tekkon/Homa 橋接。Packages/vChewing_OSNeutral_LibVanguard/Sources/LibVanguard/Session/:OS-independent 會話體系——SessionCoreProtocol(共用基底協定,提供switchState()/resetInputHandler()預設實作)、SessionProtocol+InputSession(會話類別)、IMEStatefactories/IMEStateParsed、SessionClientProxy(跨平台客戶端 proxy 抽象)、SessionHost(OS-dependent 動作注入點)。Darwin 專屬行為由 MainAssembly 的SessionHostWiring注入+Darwin surface 提供。Packages/vChewing_OSNeutral_LibVanguard/Sources/Tekkon/:注音/拼音解析、組筆處理。Packages/vChewing_OSNeutral_LibVanguard/Sources/Homa/:DAG-DP 組字器、候選輪替/鞏固 API、POM 觀測資料生成器。Packages/vChewing_OSNeutral_LibVanguard/Sources/LexiconAssembly/:語言模型匯流、使用者詞語、關聯詞、POM 記憶管理。Packages/vChewing_OSNeutral_LibVanguard/Deps/VanguardSwiftExtension/:通用SwiftExtension工具套件,以巢狀子套件形式置於聚合體目錄內(SwiftPM 接受巢狀套件);如此兩倉.package(path:)同字串、manifest 得以逐位元組相同。package 名與產品名為VanguardSwiftExtension、target/模組名為SwiftExtension(全倉一律import SwiftExtension)。
- 針對變更的 package 執行
swift test;對 Tekkon/Homa 相關改動請補齊邊界案例。 - 單元測試不對 Swift 5.10 開放:5.10 側 manifest 不宣告任何測試靶(含僅供測試的素材靶),逐套件 makefile 亦不提供測試目標;測試一律只在 6.4 側跑(
swift test),5.10 側僅以make build510(逐套件)與make debugLegacy(倉根兩支執行檔)驗可建置性。 - 偏好 (PrefMgr) 相關測試需在測試前後還原設定,避免滲漏。
- 若新增可視化或除錯輸出,透過偏好旗標控制,避免影響 Release 組建。
AGENTS.md:完整開發守則。algorithm.md:Tekkon、Homa、語言模型、詞庫製程的詳細說明(zh-Hant)。.github/copilot-instructions.md:Copilot/Claude 共用的即時守則。vChewing-DevLogs/Research/Phase217_SOP.md:P217(把 Swift 5.10 靜態路徑推及全倉)的施工規範;未載者依本檔(AGENTS.md/CLAUDE.md),兩者衝突時上報。
遵守以上規範能確保與維護者協作順暢。如遇到與守則衝突的新需求,請在 PR 說明內註記並提出調整建議。