github yuzeguitarist/Deck v1.2.0
v1.2.0 | Stabilized

latest releases: v1.4.5, v1.4.4, v1.4.3...
5 months ago

Deck

Deck

A modern, native, privacy-first clipboard OS for macOS


Release Notes v1.2.0

新增 / Added

  • 自动更新国内加速与兜底下载
    自动更新部署了 CF 反代,国内无法访问 GitHub 时也可稳定更新,并保留 GitHub 下载作为兜底。
    Auto-update now uses a CF proxy for reliable access in mainland China, with GitHub downloads kept as a fallback.

  • 诊断上传与内存采样
    新增诊断上传与内存采样器:每日 15:00 本地时间上传 24 小时诊断报告,失败会去掉日志再试;每分钟采样内存,最多 1440 点,数据写入 memory_samples.json
    Added diagnostics upload and memory sampling: uploads a 24-hour report daily at 15:00 local time with a log-less fallback, and records minute-level memory samples up to 1440 points in memory_samples.json.
    DiagnosticsUploadService.swift, DiagnosticsMemorySampler.swift

  • 隐私设置中的分析数据入口
    隐私设置新增“分析数据”卡片与开关,开启后提供“手动上传”按钮。
    Privacy settings add an “Analytics Data” card with a toggle and a manual upload action when enabled.
    PrivacySettingsView.swift

  • 新增繁体中文支持
    增加对繁体中文(zh-Hant)的本地化翻译支持。
    Added Traditional Chinese (zh-Hant) localization support.
    Localizable.xcstrings

Deck × Orbit

  • 每次安装唯一 Token 与安全兜底
    Orbit bridge token 改为每次安装随机生成并存储,#if DEBUG 仍兼容 legacy token;Release 不再接受硬编码 token。
    Orbit bridge tokens are now per-install random values with a DEBUG legacy fallback; Release no longer accepts a hardcoded token.
    OrbitBridgeAuth.swift

  • 启动即准备 Token 与 401 重试
    启动时强制创建 token,并在 401 时从磁盘重载并重试一次。
    Tokens are eagerly created at launch, and 401 responses trigger a disk reload and one retry.
    AppDelegate.swift, OrbitBridgeAuth.swift, OrbitBridgeClient.swift

优化 / Improvements

  • 预览渲染与缩略图网格增强
    预览始终显示电话行 + 全文并保留智能摘要;file URL 多图新增缩略图网格,历史卡片缩略图修复,预览对鼠标点击也会刷新。
    Preview now always shows the phone line + full text while keeping smart details; added multi-image thumbnail grids for file URLs, fixed history card thumbnails, and made previews refresh on mouse clicks.
    PreviewWindowController.swift, PreviewOverlayView.swift, HistoryListView.swift

  • 多图卡片的布局与省略指示优化
    多图卡片仅显示首图,右侧独立省略指示条(固定高度与最小宽度),不再遮盖图片、也不会顶起标题。
    Multi-image cards now show only the first image with a separate right-side ellipsis indicator of fixed height/min width, without overlaying the image or pushing titles.
    ClipItemCardView.swift

  • 安装/更新界面图标渲染稳定
    安装/更新 UI 强制使用原色应用图标,避免暗色模式出现模板色偏。
    Install/update UI now forces original-color app icons to avoid dark-mode template tinting.
    SettingsView.swift

  • 统计视图轻量化与内存回收
    统计改为仅用元数据查询,退出视图时触发 SQLite shrink;Top Apps 使用 appPath 作为稳定 id。
    Statistics now use metadata-only queries with a shrink-memory hook on exit, and Top Apps use appPath as a stable id.
    StatisticsView.swift, DeckSQLManager.swift

  • 数据库启动与向量索引性能优化
    PRAGMA quick_check(1) 以 24h 窗口限频,仅在备份恢复时强制;向量回填仅在 embeddings 存在且 vec 表为空时触发,并按最近数据分批带短暂休眠;updateVecIndex 避免重序列化并使用 INSERT OR REPLACE
    PRAGMA quick_check(1) is throttled to a 24h window and forced only on restore; vec backfill runs only when embeddings exist and vec tables are empty, favoring recent rows with short sleeps; updateVecIndex avoids heavy serialization and uses INSERT OR REPLACE.
    DeckSQLManager.swift

  • 隐写解码与导出任务离线化
    隐写解码改为后台任务执行并支持取消;导出认证在主线程,抓取/编码/写入在后台完成。
    Stego decoding now runs off-main with cancellation support; export auth stays on main while fetch/encode/write run in a detached worker.
    ClipboardService.swift, SteganographyService.swift, DataExportService.swift

  • 自动删除调度器替换逐条 sleep
    AutoDeleteScheduler actor 统一调度自动删除,减少队列阻塞。
    Auto-delete is now coordinated by an AutoDeleteScheduler actor instead of per-item sleeps.
    SmartRuleService.swift

  • 语义检索矩阵化与缓存
    引入矩阵化评分与向量范数缓存,保持阈值/排序语义不变,并用 vDSP_mmul 替代弃用的 cblas_sgemv
    Added matrixized scoring with norm caching while preserving threshold/sort semantics, and replaced deprecated cblas_sgemv with vDSP_mmul.
    SemanticSearchService.swift

变更 / Changes

  • 更新缓存清理与更新完成提示
    启动时清理 ~/Library/Caches/Deck/Updates/ 下所有版本前缀目录(含 unknown-),并记录 pendingUpdateVersion;满足条件时 8 秒后打开设置并提示“更新完成”,设置窗口新增 showWindow() 防止 toggle 误关。
    On launch, clears all version-prefixed update caches (including unknown-) and records pendingUpdateVersion; when applicable, opens Settings after 8 seconds to show “Update complete,” with a new showWindow() to avoid toggle mis-close.
    UpdateService.swift, AppDelegate.swift, SettingsWindowController.swift

  • 更新服务的签名强制与安全约束
    Release 更新路径强制代码签名校验。
    Release updates now enforce code signature validation.
    UpdateService.swift

  • 脚本执行队列策略调整
    脚本执行队列做过串行化以降低资源争用,现改为并发以避免单个脚本阻塞其他任务。
    Script execution was serialized to reduce contention, and is now concurrent to avoid head-of-line blocking.
    ScriptPluginService.swift

  • 规则/模板持久化稳定码
    TransformType 持久化改用稳定 code,并兼容旧中文 rawValue。
    TransformType persistence now uses a stable code with backward compatibility for legacy Chinese raw values.
    TextTransformer.swift

  • 加密迁移与行级状态跟踪
    数据库新增 is_encrypted 列并实现按字段幂等加解密与行级决策,检测阶段使用静默解密避免日志刷屏。
    DB now tracks is_encrypted with idempotent per-field encrypt/decrypt and row-level decisions; detection uses silent decrypt to avoid log spam.
    DeckSQLManager.swift, SecurityService.swift

  • 导出路径与临时文件策略
    导出改为直接写入用户选择路径,并在启动时清理遗留临时导出文件。
    Exports now write directly to the user-chosen path and clean leftover temp exports on launch.
    DataExportService.swift

  • DirectConnect 明文接收限制
    没有确认回调时拒绝明文接收。
    Plaintext receives are rejected when no confirmation callback is wired.
    DirectConnectService.swift

修复 / Fixes

  • 事件回调内存泄漏与 RunLoop 解绑问题
    所有 CGEventTap 回调返回 passUnretained(event),并统一使用 CFRunLoopGetMain() 绑定/解绑,避免泄漏与 runloop 不一致导致的资源悬挂。
    All CGEventTap callbacks now return passUnretained(event) and use CFRunLoopGetMain() for consistent attach/detach, preventing leaks and runloop mismatches.
    PasteQueueService.swift, CursorAssistantService.swift

  • 热键卸载遍历崩溃
    unregisterAllHotKeys() 改为遍历 Array(hotKeys.keys),避免遍历中修改集合崩溃。
    unregisterAllHotKeys() now iterates Array(hotKeys.keys) to avoid mutation-during-enumeration crashes.
    HotKeyManager.swift

  • 热键修饰键事件泄漏
    修饰键 event tap 回调改为返回 passUnretained(event)
    Modifier event tap callbacks now return passUnretained(event) to prevent leaks.
    HotKeyManager.swift

  • 剪贴板轮询定时器竞态
    轮询定时器的 schedule/cancel 全部在其所属队列执行,避免竞态和异常。
    Poll timer scheduling/canceling now runs on its own queue to avoid races and odd behavior.
    ClipboardService.swift

  • 云同步回环与漏同步
    远端变更落库时支持 shouldSyncToCloud=false,避免上传回环;moreComing 拉取改为循环直到完成,并正确推进 token。
    Remote changes now apply with shouldSyncToCloud=false to prevent echo uploads; moreComing fetches loop until complete with proper token advancement.
    CloudSyncService.swift, DeckDataStore.swift

  • 云端加密记录解密逻辑
    只要 record 标记为加密就强制解密,不再受本地开关影响。
    Encrypted records are always decrypted regardless of local encryption toggle.
    CloudSyncService.swift

  • 云同步远端更新落地方式
    远端更新改为直接更新数据库,不再 delete+insert,避免重复与写放大。
    Remote updates now write directly to the DB instead of delete+insert, preventing duplication and write amplification.
    CloudSyncService.swift, DeckSQLManager.swift

  • CloudSync 竞争态修复
    pendingUploadCount 统一在主线程更新,避免后台修改可观察状态导致竞态。
    pendingUploadCount now updates on the main thread to avoid races from background mutations.
    CloudSyncService.swift

  • 云同步编译错误清理
    移除 ManagedCriticalState 并补齐显式 tuple 类型,修复编译错误。
    Removed ManagedCriticalState and added explicit tuple types to fix compile errors.
    CloudSyncService.swift

  • 唯一索引与重复去重
    unique_id 建立 UNIQUE 索引并在需要时去重重试,失败则降级为普通索引并报警。
    unique_id now uses a UNIQUE index with dedupe-and-retry and a safe fallback to a normal index.
    DeckSQLManager.swift

  • 重复记录的稳定读取
    fetchRow(uniqueId:) 增加排序,确保重复时命中最新记录。
    fetchRow(uniqueId:) now orders results to pick the most recent row deterministically.
    DeckSQLManager.swift

  • Blob 更新一致性与磁盘清理
    更新时写入 blob_path,必要时转存大数据到 blob;旧 blob 路径在更新成功后清理。
    Updates now persist blob_path, offload large data to blob storage when needed, and remove old blob files after successful updates.
    DeckSQLManager.swift, BlobStorage.swift

  • Blob 路径与 symlink 安全
    BlobStorage 路径不再触碰 @MainActor;symlink 解析加强以避免路径穿越。
    BlobStorage no longer depends on @MainActor, and symlink resolution is hardened to prevent path traversal.
    BlobStorage.swift

  • 文件 URL 缩略图解码错误
    避免将文件路径字符串当作图像数据解码,直接从 file URL 生成缩略图。
    Avoids decoding file path strings as image data by generating thumbnails directly from file URLs.
    ClipItemCardView.swift

  • JS 执行超时与兼容性
    JSCore 执行加入超时限制;不可用符号改用 dlsym 动态查找,仅在支持时生效。
    JSCore execution now has a time limit; unavailable symbols are resolved via dlsym and applied only when present.
    ScriptPluginService.swift

  • 导出 OOM 修复
    大文件导出改为流式解析 items,避免一次性 decode 造成内存爆。
    Large exports now stream-parse items to avoid OOM from full JSON decoding.
    DataExportService.swift

  • Swift 6 并发与隔离修复
    日志方法标记 nonisolated(unsafe) 以支持后台调用;移除不必要的全局 logger nonisolated;隐写解码使用非隔离静态管线与预取 key;SteganographyKeyStore 访问改为 nonisolated。
    Logging now uses nonisolated(unsafe) for background calls while removing unnecessary global logger isolation; stego decoding routes through nonisolated static helpers with pre-fetched keys; SteganographyKeyStore access is nonisolated.
    AppLogger.swift, SteganographyService.swift, SteganographyKeyStore.swift, ClipboardService.swift

  • Swift 6 语义与线程安全修复
    主线程捕获隐写服务后再 detach,自动删除日志改到主线程,修复 Swift 6 隔离错误。
    Stego services are captured on main before detaching and auto-delete logging is moved to main to satisfy Swift 6 isolation.
    ClipboardService.swift, SmartRuleService.swift

  • 统计 SQL 迭代与 shrinkMemory 异步化
    原生 SQL 遍历改为 Statement 行索引,shrinkMemory() 改为 async 并补齐调用点。
    Raw SQL loops now use Statement row indexing, and shrinkMemory() is async with updated call sites.
    DeckSQLManager.swift, StatisticsView.swift, DeckDataStore.swift

  • 本地化警告清理
    16 个未引用 key 的 extractionState 改为 manual,保留翻译同时消除警告。
    Set 16 unused localization keys to manual to keep translations and remove warnings.
    Localizable.xcstrings

说明 / Notes

  • 诊断上传内容范围
    上传日志不包含剪贴板数据,仅包含 App 版本、系统信息、用户 ID、24h 内存曲线与崩溃日志。
    Diagnostic uploads exclude clipboard content and include only app version, system info, user ID, 24-hour memory curve, and crash logs.

Don't miss a new Deck release

NewReleases is sending notifications on new releases.