dsh-config-manager 0.1.19 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/lib/client.d.ts +319 -2
  2. package/lib/client.js +1271 -109
  3. package/lib/client.js.map +1 -1
  4. package/lib/core/run-registry.d.ts +2 -2
  5. package/lib/core/run-registry.js +5 -1
  6. package/lib/core/run-registry.js.map +1 -1
  7. package/lib/index.js +408 -2
  8. package/lib/index.js.map +1 -1
  9. package/lib/sync/ancestor.d.ts +17 -0
  10. package/lib/sync/ancestor.js +64 -0
  11. package/lib/sync/ancestor.js.map +1 -0
  12. package/lib/sync/autosync-config.d.ts +34 -0
  13. package/lib/sync/autosync-config.js +116 -0
  14. package/lib/sync/autosync-config.js.map +1 -0
  15. package/lib/sync/autosync-scheduler.d.ts +95 -0
  16. package/lib/sync/autosync-scheduler.js +379 -0
  17. package/lib/sync/autosync-scheduler.js.map +1 -0
  18. package/lib/sync/merge.d.ts +42 -0
  19. package/lib/sync/merge.js +325 -0
  20. package/lib/sync/merge.js.map +1 -0
  21. package/lib/sync/review-queue.d.ts +51 -0
  22. package/lib/sync/review-queue.js +119 -0
  23. package/lib/sync/review-queue.js.map +1 -0
  24. package/lib/sync/risk.d.ts +59 -0
  25. package/lib/sync/risk.js +76 -0
  26. package/lib/sync/risk.js.map +1 -0
  27. package/lib/sync/sync-config.d.ts +7 -2
  28. package/lib/sync/sync-config.js +24 -4
  29. package/lib/sync/sync-config.js.map +1 -1
  30. package/lib/sync/sync-engine.d.ts +88 -2
  31. package/lib/sync/sync-engine.js +333 -8
  32. package/lib/sync/sync-engine.js.map +1 -1
  33. package/lib/sync/sync-history.d.ts +39 -0
  34. package/lib/sync/sync-history.js +88 -0
  35. package/lib/sync/sync-history.js.map +1 -0
  36. package/lib/sync/sync-session.d.ts +39 -0
  37. package/lib/sync/sync-session.js +54 -0
  38. package/lib/sync/sync-session.js.map +1 -0
  39. package/lib/sync/sync-state.d.ts +7 -2
  40. package/lib/sync/sync-state.js +9 -5
  41. package/lib/sync/sync-state.js.map +1 -1
  42. package/lib/ui/i18n.d.ts +63 -0
  43. package/lib/ui/i18n.js +130 -1
  44. package/lib/ui/i18n.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/client/config-manager.module.css +18 -0
  47. package/src/client/sync/SyncConfirmView.tsx +301 -0
  48. package/src/client/sync/SyncHistoryView.test.ts +40 -0
  49. package/src/client/sync/SyncHistoryView.tsx +155 -0
  50. package/src/client/sync/SyncSettingsView.tsx +241 -12
  51. package/src/client/sync/history-model.test.ts +82 -0
  52. package/src/client/sync/history-model.ts +112 -0
  53. package/src/client/sync/sync-api.test.ts +155 -0
  54. package/src/client/sync/sync-api.ts +219 -0
  55. package/src/client/sync/sync-locales.ts +162 -1
  56. package/src/client/sync/sync-view-v2.test.ts +131 -0
  57. package/src/client/sync/sync-view.ts +151 -4
  58. package/src/core/run-registry.ts +7 -3
  59. package/src/index.ts +420 -3
  60. package/src/sync/ancestor.test.ts +152 -0
  61. package/src/sync/ancestor.ts +81 -0
  62. package/src/sync/autosync-config.test.ts +93 -0
  63. package/src/sync/autosync-config.ts +137 -0
  64. package/src/sync/autosync-scheduler.test.ts +191 -0
  65. package/src/sync/autosync-scheduler.ts +443 -0
  66. package/src/sync/merge.test.ts +204 -0
  67. package/src/sync/merge.ts +360 -0
  68. package/src/sync/review-queue.test.ts +120 -0
  69. package/src/sync/review-queue.ts +167 -0
  70. package/src/sync/risk.test.ts +131 -0
  71. package/src/sync/risk.ts +122 -0
  72. package/src/sync/sync-config.test.ts +106 -0
  73. package/src/sync/sync-config.ts +23 -4
  74. package/src/sync/sync-engine.test.ts +392 -3
  75. package/src/sync/sync-engine.ts +383 -10
  76. package/src/sync/sync-history.test.ts +85 -0
  77. package/src/sync/sync-history.ts +126 -0
  78. package/src/sync/sync-session.test.ts +137 -0
  79. package/src/sync/sync-session.ts +76 -0
  80. package/src/sync/sync-state.test.ts +48 -2
  81. package/src/sync/sync-state.ts +11 -5
  82. package/src/ui/i18n.ts +132 -3
package/lib/client.d.ts CHANGED
@@ -240,8 +240,8 @@ interface SnapshotMeta {
240
240
  }
241
241
  //#endregion
242
242
  //#region src/core/run-registry.d.ts
243
- /** run 类型:导出 / 导入。 */
244
- type RunKind = 'export' | 'import';
243
+ /** run 类型:导出 / 导入 / 自动同步 / 一键同步逐项应用。 */
244
+ type RunKind = 'export' | 'import' | 'autosync' | 'sync-apply';
245
245
  /** run 状态:进行中 / 完成 / 失败。 */
246
246
  type RunStatus = 'running' | 'done' | 'failed';
247
247
  /** 单个 run 的实时状态(/progress 返回体;纯 JSON 可序列化)。 */
@@ -421,6 +421,69 @@ declare const uiZh: {
421
421
  readonly 'sync.pullOk': "远端快照 {id} 差异预览:共 {count} 项变更";
422
422
  readonly 'sync.pullEmpty': "远端快照与本地一致(无变更)";
423
423
  readonly 'sync.previewHint': "以上为只读差异预览,不会执行导入。v1 暂不提供一键导入接线;如需应用远端配置,请使用「导入恢复」向导手动导入导出的备份。";
424
+ readonly 'sync.syncTitle': "一键同步";
425
+ readonly 'sync.syncButton': "一键同步";
426
+ readonly 'sync.syncing': "正在同步…";
427
+ readonly 'sync.syncHeadline': "远端快照 {id} 差异确认:共 {count} 项";
428
+ readonly 'sync.syncEmpty': "远端快照与本地一致(无变更)";
429
+ readonly 'sync.syncFailed': "同步失败";
430
+ readonly 'sync.confirmAdopt': "采用远端";
431
+ readonly 'sync.confirmSkip': "跳过";
432
+ readonly 'sync.confirmRequired': "需要人工决策";
433
+ readonly 'sync.needsReviewBadge': "需人工决策";
434
+ readonly 'sync.selectSnapshot': "选择历史快照";
435
+ readonly 'sync.latestSnapshot': "最新快照";
436
+ readonly 'sync.noSnapshots': "远端暂无快照";
437
+ readonly 'sync.confirmImport': "确认导入";
438
+ readonly 'sync.cancelConfirm': "取消";
439
+ readonly 'sync.conflictResolve': "冲突解决";
440
+ readonly 'sync.conflictUseLocal': "用本地";
441
+ readonly 'sync.conflictUseRemote': "用远端";
442
+ readonly 'sync.conflictSkip': "跳过";
443
+ readonly 'sync.conflictResolvedLocal': "已选:本地";
444
+ readonly 'sync.conflictResolvedRemote': "已选:远端";
445
+ readonly 'sync.conflictResolvedSkip': "已选:跳过";
446
+ readonly 'sync.importDone': "已导入 {n} 个分区";
447
+ readonly 'sync.importSkipped': "已跳过 {n} 项";
448
+ readonly 'sync.importFailed': "导入失败(已整体回滚)";
449
+ readonly 'sync.rollbackButton': "回滚到应用前";
450
+ readonly 'sync.rollingBack': "正在回滚…";
451
+ readonly 'sync.rollbackDone': "已回滚到应用前";
452
+ readonly 'sync.appliedSections': "已写入";
453
+ readonly 'sync.importWarnings': "导入告警";
454
+ readonly 'sync.autosyncTitle': "自动同步";
455
+ readonly 'sync.autosyncDesc': "开启后,DSH 将按固定间隔自动执行双向同步(拉取合并 + 上传);DSH 启动时还会触发一次「自动下载合并(不上传)」以保持本地为最新。仅在无冲突且无需人工干预时才自动写入。";
456
+ readonly 'sync.autosyncEnabled': "启用自动同步";
457
+ readonly 'sync.autosyncInterval': "同步间隔";
458
+ readonly 'sync.autosyncIntervalHint': "DSH 启动时自动下载合并不上传。";
459
+ readonly 'sync.autosyncNever': "从未运行";
460
+ readonly 'sync.autosyncLastRun': "上次运行:{time}";
461
+ readonly 'sync.autosyncNextIn': "下次约 {time} 后";
462
+ readonly 'sync.autosyncSuccess': "成功";
463
+ readonly 'sync.autosyncSkipped': "已跳过";
464
+ readonly 'sync.autosyncFailed': "失败";
465
+ readonly 'sync.autosyncPartial': "部分成功";
466
+ readonly 'sync.autosyncFailCount': "连续失败 {n} 次";
467
+ readonly 'sync.autosyncSyncing': "自动同步进行中…";
468
+ readonly 'sync.interval.5m': "5 分钟";
469
+ readonly 'sync.interval.15m': "15 分钟";
470
+ readonly 'sync.interval.30m': "30 分钟";
471
+ readonly 'sync.interval.60m': "60 分钟";
472
+ readonly 'sync.interval.6h': "6 小时";
473
+ readonly 'sync.interval.12h': "12 小时";
474
+ readonly 'sync.interval.24h': "24 小时";
475
+ readonly 'sync.hist.autosync': "自动同步";
476
+ readonly 'sync.hist.directionPull': "下载";
477
+ readonly 'sync.hist.directionPush': "上传";
478
+ readonly 'sync.hist.directionBoth': "双向";
479
+ readonly 'sync.hist.skipReasonConflict': "冲突项被跳过";
480
+ readonly 'sync.hist.skipReasonNoRemote': "远端无快照";
481
+ readonly 'sync.hist.skipReasonNotConfigured': "未配置仓库";
482
+ readonly 'sync.hist.skipReasonNetwork': "网络问题";
483
+ readonly 'sync.hist.conflictedSections': "跳过冲突分区:{sections}";
484
+ readonly 'sync.hist.appliedSections': "应用分区:{sections}";
485
+ readonly 'sync.hist.failedError': "错误:{error}";
486
+ readonly 'sync.hist.notifiedAt': "已通知";
424
487
  readonly 'sync.github.starting': "正在发起 GitHub 授权…";
425
488
  readonly 'sync.github.waitingNoCode': "请在浏览器中打开授权页面并完成授权…";
426
489
  readonly 'sync.github.waiting': "请在浏览器中打开授权页面,输入一次性代码 {code} 完成授权(自动等待确认)。";
@@ -575,6 +638,8 @@ interface SyncStatusResponse {
575
638
  type: string;
576
639
  ref: string;
577
640
  };
641
+ /** 自动同步当前状态(供 UI 顶部开关回填;§3.9) */
642
+ autosync?: AutosyncStatusResponse;
578
643
  }
579
644
  /** push 请求体(token 可选:非空则 Host 先写入 DSH credentials 再使用) */
580
645
  interface SyncPushPayload {
@@ -587,6 +652,156 @@ interface SyncPullPayload extends SyncPushPayload {
587
652
  strategy?: 'merge' | 'replace' | 'skipExisting';
588
653
  snapshotId?: string;
589
654
  }
655
+ /** GET /sync/snapshots-list 响应:远端历史快照列表(按 createdAt 倒序)。 */
656
+ interface SyncSnapshotsListResponse {
657
+ ok: boolean;
658
+ /** 按 createdAt 倒序(最新在前) */
659
+ snapshots: SyncSnapshotLite[];
660
+ /** 当前本地祖先指针(sync-state.lastSnapshotId),用于高亮当前基线 */
661
+ currentSnapshotId?: string;
662
+ }
663
+ /** 远端快照摘要(「选择历史快照」下拉项)。 */
664
+ interface SyncSnapshotLite {
665
+ id: string;
666
+ createdAt: string;
667
+ sectionCount: number;
668
+ platform: string;
669
+ dshVersion: string;
670
+ }
671
+ /** POST /sync/sync 请求体(一键同步第一步:拉取 → 差异确认会话)。 */
672
+ interface SyncStartPayload {
673
+ repoUrl: string;
674
+ gitBin?: string;
675
+ token?: string;
676
+ /** 缺省 = 最新快照;传入则对该历史快照拉取 */
677
+ snapshotId?: string;
678
+ }
679
+ /** POST /sync/sync 响应:差异确认会话(items 供 UI 逐项确认)。 */
680
+ interface SyncStartResponse {
681
+ ok: boolean;
682
+ /** 差异确认会话 id:后续 apply-items / cancel 引用 */
683
+ syncSessionId: string;
684
+ /** 被拉取的远端快照 id */
685
+ snapshotId: string;
686
+ items: SyncConfirmItem[];
687
+ /** 是否包含任何需人工决策项 */
688
+ needsReview: boolean;
689
+ compatibility: 'excellent' | 'good' | 'partial' | 'unsupported';
690
+ message?: string;
691
+ }
692
+ /** 单条可确认的差异项(由 ImportPlan.item 投影 + 冲突详情)。 */
693
+ interface SyncConfirmItem {
694
+ itemId: string;
695
+ adapter: SectionId;
696
+ kind: PlanItemKind;
697
+ description: string;
698
+ severity: 'info' | 'warning' | 'error';
699
+ /** 默认采纳方向;Conflict/MissingSecret 等人工项默认 false */
700
+ defaultAdopt: boolean;
701
+ /** 用户最终决策(缺省 = defaultAdopt) */
702
+ adopt: boolean;
703
+ /** 冲突项内联解决所需详情(仅 Conflict 项非空) */
704
+ conflict?: SyncConflictDetail;
705
+ /** 该项若采用将写入的目标摘要 */
706
+ target?: {
707
+ adapter: SectionId;
708
+ ref: string;
709
+ };
710
+ }
711
+ /** 冲突项内联解决详情(来源 MergeConflict + 可读 diff)。 */
712
+ interface SyncConflictDetail {
713
+ path: string;
714
+ kind: 'key' | 'file' | 'section';
715
+ local?: unknown;
716
+ remote?: unknown;
717
+ ancestor?: unknown;
718
+ diff?: string;
719
+ }
720
+ /** POST /sync/apply-items 请求体(一键同步第二步:按逐项决策执行导入)。 */
721
+ interface ApplyItemsPayload {
722
+ syncSessionId: string;
723
+ /** 每项的最终采纳决策(未列出项视为 adopt=false) */
724
+ adoptions: SyncItemAdoption[];
725
+ }
726
+ /** 单条采纳决策。 */
727
+ interface SyncItemAdoption {
728
+ itemId: string;
729
+ adopt: boolean;
730
+ /** 冲突项解决方案(仅当该项是 Conflict 且 adopt=true 时必须) */
731
+ resolution?: 'useRemote' | 'keepLocal' | 'skip';
732
+ }
733
+ /** POST /sync/apply-items 响应。 */
734
+ interface ApplyItemsResponse {
735
+ ok: boolean;
736
+ applied: string[];
737
+ skipped: string[];
738
+ needsRestart: boolean;
739
+ warnings: string[];
740
+ /** 应用前快照 id(UI 一键回滚用) */
741
+ restoreId: string;
742
+ /** 任一失败是否整体回滚 */
743
+ rolledBack: boolean;
744
+ failed: {
745
+ itemId: string;
746
+ message?: string;
747
+ }[];
748
+ result: unknown;
749
+ }
750
+ /** 统一间隔类型。 */
751
+ type AutosyncInterval = '5m' | '15m' | '30m' | '60m' | '6h' | '12h' | '24h';
752
+ /** 最近一次自动同步执行状态。 */
753
+ type AutosyncRunStatus = 'success' | 'skipped' | 'failed' | 'partial';
754
+ /** GET/POST /sync/autosync 响应:自动同步状态。 */
755
+ interface AutosyncStatusResponse {
756
+ enabled: boolean;
757
+ interval: AutosyncInterval;
758
+ lastRunAt?: string;
759
+ lastRunStatus?: AutosyncRunStatus;
760
+ lastRunMessage?: string;
761
+ consecutiveFailures: number;
762
+ /** 距上次自动同步已过 ms(host 计算,供 UI 倒计时/立即触发判断) */
763
+ elapsedMs: number;
764
+ lastRunHistoryId?: string;
765
+ }
766
+ /** POST /sync/autosync 请求体。 */
767
+ interface AutosyncUpdatePayload {
768
+ enabled: boolean;
769
+ interval?: AutosyncInterval;
770
+ startupMinIntervalMs?: number;
771
+ }
772
+ /** 自动同步执行记录(§3.7 AutosyncHistoryEntry)。 */
773
+ interface AutosyncHistoryEntry {
774
+ direction: 'pull' | 'push' | 'both';
775
+ status: 'success' | 'skipped' | 'failed' | 'partial';
776
+ /** 跳过原因(冲突项 / 缺失依赖 / Install / 错误 / 无远端 / 网络) */
777
+ skipReason?: string;
778
+ /** 被跳过的冲突分区 id(冲突跳过时列出) */
779
+ conflictedSections?: string[];
780
+ /** 本次自动合并实际写入的分区 */
781
+ appliedSections?: string[];
782
+ /** 本次 push 产生的快照 id */
783
+ pushedSnapshotId?: string;
784
+ /** 本次 pull 来源快照 id */
785
+ pulledSnapshotId?: string;
786
+ error?: string;
787
+ notifiedAt?: string;
788
+ /** 本次触发时的连续失败计数 */
789
+ failureCountAtRun: number;
790
+ createdAt: string;
791
+ }
792
+ /** 同步历史条目(Host 端返回;kind='autosync' 时 autosync 非空)。 */
793
+ interface SyncHistoryEntry {
794
+ id: string;
795
+ createdAt: string;
796
+ kind: 'push' | 'pull' | 'apply' | 'autosync' | 'rollback';
797
+ sectionCount?: number;
798
+ reviewCount?: number;
799
+ autosync?: AutosyncHistoryEntry;
800
+ }
801
+ /** GET /sync/history 响应:{ entries }。 */
802
+ interface SyncHistoryResponse {
803
+ entries: SyncHistoryEntry[];
804
+ }
590
805
  /** POST /sync/github/start 响应:UI 展示用(device_code 只存宿主,绝不回传) */
591
806
  interface GithubDeviceFlowStartResponse {
592
807
  /** 随机 flowId:后续 poll/cancel 凭它引用宿主侧登记的 device_code */
@@ -632,6 +847,29 @@ declare class SyncApi {
632
847
  githubCancel(flowId: string): Promise<{
633
848
  ok: boolean;
634
849
  }>;
850
+ /** 同步历史:列出本地祖先快照 + 自动同步执行记录(按 createdAt 倒序合并)。 */
851
+ history(): Promise<SyncHistoryResponse>;
852
+ /** 远端历史快照列表(供「选择历史快照」下拉)。 */
853
+ snapshotsList(payload: SyncPushPayload): Promise<SyncSnapshotsListResponse>;
854
+ /** 一键同步第一步:拉取 → 差异确认会话(items 逐项确认,暂不导入)。 */
855
+ sync(payload: SyncStartPayload): Promise<SyncStartResponse>;
856
+ /** 一键同步第二步:按用户对差异项的逐项决策执行导入。 */
857
+ applyItems(payload: ApplyItemsPayload): Promise<ApplyItemsResponse>;
858
+ /** 取消/清理差异确认会话(丢弃临时 ZIP,零副作用)。 */
859
+ cancel(syncSessionId: string): Promise<{
860
+ ok: boolean;
861
+ }>;
862
+ /** 自动同步状态(GET /sync/autosync)。 */
863
+ autosyncStatus(): Promise<AutosyncStatusResponse>;
864
+ /** 自动同步配置更新(POST /sync/autosync)。 */
865
+ autosyncUpdate(payload: AutosyncUpdatePayload): Promise<AutosyncStatusResponse>;
866
+ /** 一键回滚:按 restoreId 调用 backup→rollback */
867
+ rollback(payload: {
868
+ restoreId: string;
869
+ }): Promise<{
870
+ ok: boolean;
871
+ full: boolean;
872
+ }>;
635
873
  }
636
874
  //#endregion
637
875
  //#region src/client/client-types.d.ts
@@ -780,6 +1018,7 @@ declare const zh: {
780
1018
  readonly 'config.token': "认证 token";
781
1019
  readonly 'config.tokenHint': "将安全写入 DSH credentials(引用名 {ref}),不会写入同步文件或日志。留空表示沿用已保存的凭据。";
782
1020
  readonly 'config.tokenSaved': "凭据已配置";
1021
+ readonly 'config.tokenPlaceholder': "ghp_…(可选)";
783
1022
  readonly 'config.gitBin': "git 可执行文件(可选)";
784
1023
  readonly 'config.gitBinHint': "缺省使用 PATH 中的 git。";
785
1024
  readonly 'github.title': "GitHub 登录";
@@ -804,6 +1043,84 @@ declare const zh: {
804
1043
  readonly 'change.total': "共 {total} 项变更";
805
1044
  readonly 'sections.title': "同步分区";
806
1045
  readonly 'warnings.title': "分区告警";
1046
+ readonly 'syncflow.title': "一键同步";
1047
+ readonly 'syncflow.button': "一键同步";
1048
+ readonly 'syncflow.syncing': "正在同步…";
1049
+ readonly 'syncflow.syncFailed': "同步失败";
1050
+ readonly 'syncflow.snapshotOption': "({date} · {count} 分区)";
1051
+ readonly 'syncflow.selectSnapshot': "选择历史快照";
1052
+ readonly 'syncflow.latestSnapshot': "最新快照";
1053
+ readonly 'syncflow.noSnapshots': "远端暂无快照";
1054
+ readonly 'syncflow.confirmImport': "确认导入";
1055
+ readonly 'syncflow.cancel': "取消";
1056
+ readonly 'syncflow.adoptRemote': "采用远端";
1057
+ readonly 'syncflow.adoptHint': "勾选 = 导入该项;取消 = 跳过";
1058
+ readonly 'syncflow.needsReviewBadge': "需人工决策";
1059
+ readonly 'syncflow.empty': "远端快照与本地一致(无变更)";
1060
+ readonly 'syncflow.diffCount': "共 {count} 项差异";
1061
+ readonly 'syncflow.conflictTitle': "冲突解决";
1062
+ readonly 'syncflow.conflictUseLocal': "用本地";
1063
+ readonly 'syncflow.conflictUseRemote': "用远端";
1064
+ readonly 'syncflow.conflictSkip': "跳过";
1065
+ readonly 'syncflow.conflictLocalLabel': "本地";
1066
+ readonly 'syncflow.conflictRemoteLabel': "远端";
1067
+ readonly 'syncflow.conflictAncestorLabel': "共同祖先";
1068
+ readonly 'syncflow.conflictUnresolved': "冲突项 {itemId} 尚未选择解决方式(用本地 / 用远端 / 跳过)";
1069
+ readonly 'syncflow.diff': "差异";
1070
+ readonly 'syncflow.importDone': "已导入 {n} 个分区";
1071
+ readonly 'syncflow.importFailed': "导入失败(已整体回滚)";
1072
+ readonly 'syncflow.importedSections': "已写入";
1073
+ readonly 'syncflow.importWarnings': "导入告警";
1074
+ readonly 'syncflow.rollback': "回滚到应用前";
1075
+ readonly 'syncflow.rollingBack': "正在回滚…";
1076
+ readonly 'syncflow.rollbackDone': "已回滚到应用前";
1077
+ readonly 'syncflow.needsRestart': "部分改动需要重启 DSH 后生效";
1078
+ readonly 'autosync.title': "自动同步";
1079
+ readonly 'autosync.description': "开启后,DSH 将按固定间隔自动执行双向同步(拉取合并 + 上传);DSH 启动时还会触发一次「自动下载合并(不上传)」以保持本地为最新。仅在无冲突且无需人工干预时才自动写入。";
1080
+ readonly 'autosync.enable': "启用自动同步";
1081
+ readonly 'autosync.interval': "同步间隔";
1082
+ readonly 'autosync.intervalHint': "DSH 启动时自动下载合并不上传。";
1083
+ readonly 'autosync.interval5m': "5 分钟";
1084
+ readonly 'autosync.interval15m': "15 分钟";
1085
+ readonly 'autosync.interval30m': "30 分钟";
1086
+ readonly 'autosync.interval60m': "60 分钟";
1087
+ readonly 'autosync.interval6h': "6 小时";
1088
+ readonly 'autosync.interval12h': "12 小时";
1089
+ readonly 'autosync.interval24h': "24 小时";
1090
+ readonly 'autosync.status': "上次运行:{status}({time})";
1091
+ readonly 'autosync.statusNever': "从未运行";
1092
+ readonly 'autosync.nextRun': "下次约 {time} 后";
1093
+ readonly 'autosync.failCount': "连续失败 {n} 次";
1094
+ readonly 'autosync.running': "自动同步进行中…";
1095
+ readonly 'autosync.success': "成功";
1096
+ readonly 'autosync.skipped': "已跳过";
1097
+ readonly 'autosync.failed': "失败";
1098
+ readonly 'autosync.partial': "部分成功";
1099
+ readonly 'history.title': "同步历史";
1100
+ readonly 'history.empty': "尚无同步历史";
1101
+ readonly 'history.emptyHint': "完成首次 push / 一键同步 / 自动同步后,这里会显示记录。";
1102
+ readonly 'history.colTime': "时间";
1103
+ readonly 'history.colKind': "类型";
1104
+ readonly 'history.colDetail': "详情";
1105
+ readonly 'history.kindSnapshot': "快照";
1106
+ readonly 'history.kindAutosync': "自动同步";
1107
+ readonly 'history.sectionCount': "分区";
1108
+ readonly 'history.detail': "明细";
1109
+ readonly 'history.autosyncDirection': "方向:{direction}";
1110
+ readonly 'history.autosyncPull': "下载";
1111
+ readonly 'history.autosyncPush': "上传";
1112
+ readonly 'history.autosyncBoth': "双向";
1113
+ readonly 'history.autosyncSkipReason': "跳过原因:{reason}";
1114
+ readonly 'history.autosyncReasonConflict': "冲突";
1115
+ readonly 'history.autosyncReasonNoRemote': "无远端快照";
1116
+ readonly 'history.autosyncReasonNotConfigured': "未配置仓库";
1117
+ readonly 'history.autosyncReasonNetwork': "网络问题";
1118
+ readonly 'history.autosyncConflicted': "跳过冲突分区:{sections}";
1119
+ readonly 'history.autosyncApplied': "应用分区:{sections}";
1120
+ readonly 'history.autosyncError': "错误:{error}";
1121
+ readonly 'history.autosyncNotified': "已通知(连续失败 3 次)";
1122
+ readonly 'history.column.snapshot': "快照";
1123
+ readonly 'history.column.autosync': "自动同步";
807
1124
  readonly 'common.close': "关闭";
808
1125
  readonly 'common.retry': "重试";
809
1126
  readonly 'common.loading': "加载中…";