dsh-config-manager 0.1.71 → 0.1.72
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.
- package/README.md +111 -96
- package/README.zh-CN.md +207 -86
- package/lib/adapters/agent-instructions.js +1 -1
- package/lib/adapters/file-collection.js +1 -1
- package/lib/adapters/index.d.ts +1 -1
- package/lib/adapters/index.js +1 -1
- package/lib/adapters/link-report.d.ts +1 -0
- package/lib/adapters/link-report.js +27 -3
- package/lib/adapters/messages.d.ts +18 -0
- package/lib/adapters/messages.js +50 -0
- package/lib/adapters/plugin-files.js +3 -2
- package/lib/adapters/plugins.js +4 -3
- package/lib/adapters/prompts.d.ts +1 -0
- package/lib/adapters/prompts.js +7 -1
- package/lib/adapters/self.d.ts +7 -1
- package/lib/adapters/self.js +1 -1
- package/lib/adapters/sessions.d.ts +1 -0
- package/lib/adapters/sessions.js +4 -2
- package/lib/adapters/ui.d.ts +2 -2
- package/lib/adapters/ui.js +25 -25
- package/lib/adapters/workspaces.d.ts +1 -0
- package/lib/adapters/workspaces.js +7 -3
- package/lib/cli/actions.d.ts +9 -1
- package/lib/cli/actions.js +5 -2
- package/lib/cli/help.js +23 -10
- package/lib/cli/index.d.ts +23 -0
- package/lib/cli/index.js +90 -32
- package/lib/cli/sessions-inspect.js +3 -1
- package/lib/cli/sessions-repair.js +25 -6
- package/lib/cli/web/page.d.ts +12 -0
- package/lib/cli/web/page.js +21 -12
- package/lib/cli/web/routes.js +2 -2
- package/lib/cli/web/server.js +4 -4
- package/lib/client.d.ts +1349 -490
- package/lib/client.js +43047 -36738
- package/lib/core/backup-plan.js +30 -17
- package/lib/core/backup-verify.js +24 -23
- package/lib/core/backup.d.ts +5 -0
- package/lib/core/backup.js +51 -25
- package/lib/core/boot-rescue.js +4 -3
- package/lib/core/boot-safety.js +2 -1
- package/lib/core/command-rollback.d.ts +178 -0
- package/lib/core/command-rollback.js +289 -0
- package/lib/core/consult-source.js +7 -6
- package/lib/core/disk-usage.d.ts +74 -10
- package/lib/core/disk-usage.js +67 -4
- package/lib/core/engine-locale.d.ts +87 -0
- package/lib/core/engine-locale.js +125 -0
- package/lib/core/exporter.js +3 -3
- package/lib/core/fork-reconcile.d.ts +128 -0
- package/lib/core/fork-reconcile.js +150 -0
- package/lib/core/journal.js +6 -5
- package/lib/core/local-plugin-host.js +3 -2
- package/lib/core/local-plugin-pack.js +11 -6
- package/lib/core/messages-core.d.ts +292 -0
- package/lib/core/messages-core.js +615 -0
- package/lib/core/messages.d.ts +60 -2
- package/lib/core/messages.js +116 -13
- package/lib/core/migration-consult.js +21 -20
- package/lib/core/migration-history.js +19 -5
- package/lib/core/model-tools.d.ts +0 -22
- package/lib/core/model-tools.js +50 -27
- package/lib/core/phase3-host.js +30 -5
- package/lib/core/plugin-cli.js +18 -19
- package/lib/core/reconcile.d.ts +2 -14
- package/lib/core/reconcile.js +87 -17
- package/lib/core/recovery-orchestrator.js +19 -18
- package/lib/core/reinstall.d.ts +4 -0
- package/lib/core/reinstall.js +26 -21
- package/lib/core/restore.js +20 -17
- package/lib/core/rollback-ignore-rules.d.ts +31 -0
- package/lib/core/rollback-ignore-rules.js +140 -0
- package/lib/core/rollback-point.d.ts +1208 -0
- package/lib/core/rollback-point.js +2993 -0
- package/lib/core/run-registry.js +6 -5
- package/lib/core/session-health.d.ts +15 -0
- package/lib/core/session-meta.d.ts +42 -2
- package/lib/core/session-meta.js +140 -1
- package/lib/core/session-title.d.ts +28 -0
- package/lib/core/session-title.js +185 -0
- package/lib/core/startup-barrier.d.ts +24 -0
- package/lib/core/startup-barrier.js +22 -0
- package/lib/core/transaction-coordinator.js +4 -3
- package/lib/core/types.d.ts +18 -1
- package/lib/core/validator.js +5 -4
- package/lib/core/verify-recovery.js +31 -30
- package/lib/foreign/bundle.js +3 -2
- package/lib/foreign/continue.js +2 -1
- package/lib/foreign/crush.js +2 -1
- package/lib/foreign/gemini.js +2 -1
- package/lib/foreign/goose.js +2 -1
- package/lib/foreign/kilocode.js +2 -1
- package/lib/foreign/kimi.js +2 -1
- package/lib/foreign/messages.d.ts +15 -0
- package/lib/foreign/messages.js +40 -0
- package/lib/foreign/mimocode.js +2 -1
- package/lib/foreign/openclaw.js +2 -1
- package/lib/foreign/opencode.js +2 -1
- package/lib/foreign/pi.js +2 -1
- package/lib/foreign/qoder.js +2 -1
- package/lib/foreign/qwen.js +2 -1
- package/lib/foreign/registry.js +7 -6
- package/lib/foreign/teleagent.js +2 -1
- package/lib/foreign/workbuddy.js +2 -1
- package/lib/foreign/zcode.js +2 -1
- package/lib/foreign/zed.js +2 -1
- package/lib/index.d.ts +223 -7
- package/lib/index.js +729 -54
- package/lib/market/git-file-writer.js +20 -19
- package/lib/market/github-repos.js +35 -19
- package/lib/market/index-parser.js +31 -30
- package/lib/market/messages-market.d.ts +138 -0
- package/lib/market/messages-market.js +305 -0
- package/lib/market/my-repo.d.ts +2 -2
- package/lib/market/my-repo.js +32 -29
- package/lib/market/prepare.js +18 -15
- package/lib/market/security.js +20 -19
- package/lib/market/types.js +2 -1
- package/lib/market/url.js +2 -1
- package/lib/migrations/index.js +6 -5
- package/lib/migrations/messages-migrations.d.ts +32 -0
- package/lib/migrations/messages-migrations.js +58 -0
- package/lib/profiles/dsh-profile-launcher.js +2 -1
- package/lib/profiles/dsh-profile-runtime.js +2 -1
- package/lib/profiles/messages.d.ts +7 -0
- package/lib/profiles/messages.js +27 -0
- package/lib/routes/backup.js +18 -2
- package/lib/routes/import.js +3 -3
- package/lib/routes/index.d.ts +1 -1
- package/lib/routes/kit.d.ts +3 -2
- package/lib/routes/kit.js +6 -1
- package/lib/routes/market.js +1 -1
- package/lib/routes/messages.d.ts +42 -0
- package/lib/routes/messages.js +100 -0
- package/lib/routes/profiles.js +12 -6
- package/lib/routes/recovery.js +378 -114
- package/lib/routes/snapshots.js +51 -4
- package/lib/routes/sync.js +68 -16
- package/lib/schema/config.d.ts +11 -1
- package/lib/schema/config.js +52 -20
- package/lib/schema/index.d.ts +8 -6
- package/lib/schema/index.js +8 -6
- package/lib/schema/manifest.js +19 -18
- package/lib/schema/messages.d.ts +47 -0
- package/lib/schema/messages.js +110 -0
- package/lib/schema/section-registry.d.ts +41 -14
- package/lib/schema/section-registry.js +35 -29
- package/lib/schema/versions.js +6 -5
- package/lib/security/encryption.js +16 -15
- package/lib/security/integrity.js +8 -7
- package/lib/security/messages.d.ts +30 -0
- package/lib/security/messages.js +77 -0
- package/lib/security/redaction.js +12 -0
- package/lib/security/secret-scanner.js +16 -13
- package/lib/security/vault.js +2 -1
- package/lib/security/zip-security.js +4 -3
- package/lib/sync/ancestor.js +2 -1
- package/lib/sync/autosync-config.d.ts +11 -0
- package/lib/sync/autosync-config.js +12 -0
- package/lib/sync/autosync-scheduler.d.ts +11 -1
- package/lib/sync/autosync-scheduler.js +115 -76
- package/lib/sync/backup-files.js +3 -2
- package/lib/sync/backup-scheduler.js +6 -5
- package/lib/sync/blob-store.js +2 -1
- package/lib/sync/git/git-transport.d.ts +55 -0
- package/lib/sync/git/git-transport.js +152 -2
- package/lib/sync/github-auth.js +10 -9
- package/lib/sync/layout.js +13 -12
- package/lib/sync/messages.d.ts +63 -0
- package/lib/sync/messages.js +149 -0
- package/lib/sync/review-queue.js +6 -5
- package/lib/sync/s3/messages.d.ts +7 -0
- package/lib/sync/s3/messages.js +16 -0
- package/lib/sync/s3/s3-providers.d.ts +4 -1
- package/lib/sync/s3/s3-providers.js +5 -5
- package/lib/sync/s3/s3-transport.js +1 -1
- package/lib/sync/s3/sigv4.js +2 -1
- package/lib/sync/snapshot-crypto.js +6 -5
- package/lib/sync/snapshot-json.js +3 -2
- package/lib/sync/sync-engine.d.ts +37 -15
- package/lib/sync/sync-engine.js +67 -37
- package/lib/sync/sync-history.js +7 -6
- package/lib/sync/sync-selection.d.ts +15 -4
- package/lib/sync/sync-selection.js +17 -5
- package/lib/sync/webdav/webdav-transport.d.ts +1 -0
- package/lib/sync/webdav/webdav-transport.js +4 -1
- package/lib/ui/artifact-view.js +4 -3
- package/lib/ui/commands.d.ts +1 -1
- package/lib/ui/commands.js +10 -0
- package/lib/ui/disk-usage-view.d.ts +33 -4
- package/lib/ui/disk-usage-view.js +29 -1
- package/lib/ui/errors.d.ts +1 -1
- package/lib/ui/errors.js +4 -3
- package/lib/ui/export-flow.js +24 -20
- package/lib/ui/foreign-view.d.ts +5 -1
- package/lib/ui/foreign-view.js +26 -2
- package/lib/ui/i18n.d.ts +65 -0
- package/lib/ui/i18n.js +114 -0
- package/lib/ui/import-wizard.d.ts +7 -0
- package/lib/ui/import-wizard.js +13 -10
- package/lib/ui/progress.d.ts +2 -2
- package/lib/ui/progress.js +1 -2
- package/lib/ui/report.d.ts +5 -5
- package/lib/ui/report.js +6 -6
- package/lib/ui/rollback-view.d.ts +756 -0
- package/lib/ui/rollback-view.js +724 -0
- package/lib/ui/selection-model.d.ts +41 -0
- package/lib/ui/selection-model.js +30 -0
- package/lib/ui/session-inventory-view.d.ts +97 -3
- package/lib/ui/session-inventory-view.js +76 -2
- package/lib/ui/session-issue-labels.d.ts +43 -0
- package/lib/ui/session-issue-labels.js +48 -0
- package/lib/ui/sync-settings-view.d.ts +33 -0
- package/lib/ui/sync-settings-view.js +40 -0
- package/lib/ui/types.d.ts +8 -3
- package/lib/ui/types.js +1 -1
- package/lib/utils/atomic-write.js +6 -5
- package/lib/utils/bundle-scan.d.ts +11 -1
- package/lib/utils/bundle-scan.js +12 -1
- package/lib/utils/env-lock.d.ts +10 -0
- package/lib/utils/env-lock.js +73 -46
- package/lib/utils/json.js +6 -5
- package/lib/utils/messages-utils.d.ts +96 -0
- package/lib/utils/messages-utils.js +216 -0
- package/lib/utils/proxy.js +18 -5
- package/lib/utils/recursive-walk.d.ts +22 -0
- package/lib/utils/recursive-walk.js +75 -1
- package/lib/utils/session-log-repair.js +10 -9
- package/lib/utils/zip.js +27 -26
- package/package.json +12 -2
- package/src/adapters/agent-instructions.ts +1 -1
- package/src/adapters/file-collection.test.ts +1 -0
- package/src/adapters/file-collection.ts +1 -1
- package/src/adapters/files.test.ts +27 -0
- package/src/adapters/index.ts +1 -1
- package/src/adapters/link-report.test.ts +22 -2
- package/src/adapters/link-report.ts +29 -4
- package/src/adapters/messages.ts +54 -0
- package/src/adapters/plugin-files.ts +3 -2
- package/src/adapters/plugins.ts +4 -3
- package/src/adapters/prompts.ts +7 -1
- package/src/adapters/self.test.ts +26 -0
- package/src/adapters/self.ts +8 -2
- package/src/adapters/sessions.ts +4 -2
- package/src/adapters/settings.test.ts +38 -1
- package/src/adapters/ui.test.ts +2 -2
- package/src/adapters/ui.ts +27 -26
- package/src/adapters/workspaces.ts +7 -3
- package/src/cli/actions.test.ts +28 -0
- package/src/cli/actions.ts +11 -2
- package/src/cli/help.ts +23 -10
- package/src/cli/index-guards.test.ts +193 -0
- package/src/cli/index.ts +106 -31
- package/src/cli/sessions-inspect.test.ts +15 -1
- package/src/cli/sessions-inspect.ts +3 -1
- package/src/cli/sessions-repair.test.ts +84 -0
- package/src/cli/sessions-repair.ts +33 -7
- package/src/cli/web/console-route-parity.test.ts +115 -0
- package/src/cli/web/page.ts +23 -12
- package/src/cli/web/routes.ts +2 -1
- package/src/cli/web/server.ts +4 -4
- package/src/cli/web/web.test.ts +2 -2
- package/src/client/ConfigManagerSection.tsx +30 -2
- package/src/client/about/AboutPanel.tsx +2 -2
- package/src/client/about/PluginUpdateDialog.tsx +1 -1
- package/src/client/about/ReleaseNotesDialog.tsx +2 -2
- package/src/client/about/about-view.test.ts +13 -3
- package/src/client/about/about-view.ts +10 -6
- package/src/client/about/release-notes-view.test.ts +14 -4
- package/src/client/about/release-notes-view.ts +4 -2
- package/src/client/api.ts +18 -6
- package/src/client/chat/ChatEntryView.tsx +391 -0
- package/src/client/chat/RollbackDiffTab.tsx +61 -0
- package/src/client/chat/RollbackFileIcon.tsx +96 -0
- package/src/client/chat/RollbackReviewDialog.tsx +591 -0
- package/src/client/chat/chat-entry-view.test.ts +1174 -0
- package/src/client/chat/chat-entry-view.ts +758 -0
- package/src/client/chat/chat-locales.ts +152 -0
- package/src/client/chat/chat-node-registration.ts +64 -0
- package/src/client/chat/chat-point-window.ts +173 -0
- package/src/client/chat/chat-slots.ts +107 -0
- package/src/client/chat/rollback-diff-tab.test.ts +105 -0
- package/src/client/chat/rollback-diff-tab.ts +164 -0
- package/src/client/chat/rollback-entry-view.test.ts +1469 -0
- package/src/client/chat/rollback-entry-view.ts +941 -0
- package/src/client/chat/sidebar-slots.ts +37 -0
- package/src/client/common/ConfirmDialog.tsx +7 -3
- package/src/client/common/ContentPicker.tsx +48 -10
- package/src/client/common/DiffTable.tsx +97 -0
- package/src/client/common/ErrorBanner.tsx +4 -4
- package/src/client/common/Icon.tsx +2 -0
- package/src/client/common/Modal.tsx +8 -1
- package/src/client/common/ProgressBar.tsx +8 -2
- package/src/client/common/ReportView.tsx +4 -4
- package/src/client/common/RunsCenter.tsx +1 -0
- package/src/client/common/client-route-parity.test.ts +78 -0
- package/src/client/common/info-hint-guard.test.ts +46 -13
- package/src/client/common/picker-lazy-units.test.ts +42 -0
- package/src/client/common/plan-text-redaction.test.ts +17 -6
- package/src/client/common/progress-view-edge.test.ts +8 -7
- package/src/client/common/progress-view.test.ts +9 -9
- package/src/client/common/progress-view.ts +2 -2
- package/src/client/common/routes.ts +28 -0
- package/src/client/common/ui.tsx +73 -10
- package/src/client/config-manager.module.css +996 -21
- package/src/client/css-scale-guard.test.ts +30 -0
- package/src/client/environment/EnvironmentPanel.tsx +11 -4
- package/src/client/environment/maintenance/DiskUsageCard.tsx +23 -2
- package/src/client/export/ExportView.tsx +13 -8
- package/src/client/history/HistoryPanel.tsx +4 -3
- package/src/client/history/history-api.ts +2 -2
- package/src/client/history/history-locales.ts +5 -1
- package/src/client/home/HomePanel.tsx +29 -8
- package/src/client/import/ForeignImportView.tsx +4 -5
- package/src/client/import/ImportWizardView.tsx +5 -3
- package/src/client/import/import-wizard-split.test.ts +3 -1
- package/src/client/import/import-wizard-steps.tsx +9 -9
- package/src/client/index.ts +186 -3
- package/src/client/library/LibraryActions.tsx +32 -7
- package/src/client/library/LibraryPanel.tsx +23 -3
- package/src/client/library/RestorePlanView.tsx +9 -66
- package/src/client/locales.ts +54 -5
- package/src/client/lucide-icons.d.ts +1 -0
- package/src/client/market/MarketPanel.tsx +13 -2
- package/src/client/market/MyConfigsView.tsx +5 -4
- package/src/client/market/MyConfigsWizard.tsx +10 -8
- package/src/client/market/market-api.test.ts +9 -8
- package/src/client/market/market-api.ts +2 -2
- package/src/client/market/market-locales.ts +3 -0
- package/src/client/market/market-view.test.ts +6 -6
- package/src/client/market/market-view.ts +3 -3
- package/src/client/market/my-configs-api.ts +2 -2
- package/src/client/market/my-configs-view.test.ts +23 -22
- package/src/client/market/my-configs-view.ts +8 -8
- package/src/client/recovery/IncompleteCopiesSection.tsx +2 -1
- package/src/client/recovery/RecoveryPanel.tsx +442 -283
- package/src/client/recovery/RollbackCard.tsx +665 -0
- package/src/client/recovery/RollbackDiffPane.tsx +58 -0
- package/src/client/recovery/RollbackFileChanges.tsx +163 -0
- package/src/client/recovery/incident-api.ts +2 -2
- package/src/client/recovery/recovery-api.ts +116 -6
- package/src/client/recovery/recovery-locales.test.ts +299 -0
- package/src/client/recovery/recovery-locales.ts +488 -149
- package/src/client/recovery/recovery-panel-layout.test.ts +132 -2
- package/src/client/recovery/rollback-file-changes.test.ts +73 -0
- package/src/client/recovery/session-dialog-mount.test.ts +54 -0
- package/src/client/run-store.ts +84 -21
- package/src/client/sync/AutosyncCard.tsx +25 -1
- package/src/client/sync/ChannelClearConfirmDialog.tsx +6 -3
- package/src/client/sync/ChannelConfigDialog.tsx +10 -10
- package/src/client/sync/DecryptPasswordCard.tsx +2 -2
- package/src/client/sync/SecurityOptionsCard.tsx +27 -17
- package/src/client/sync/SyncChannelEntryCard.tsx +14 -2
- package/src/client/sync/SyncConfirmView.tsx +46 -8
- package/src/client/sync/SyncLogList.tsx +1 -1
- package/src/client/sync/SyncPanel.tsx +31 -23
- package/src/client/sync/SyncRepositoryPicker.tsx +3 -5
- package/src/client/sync/SyncSectionPickerDialog.tsx +11 -2
- package/src/client/sync/SyncSettingsView.test.ts +20 -1
- package/src/client/sync/UnreadableSnapshotsBanner.tsx +1 -1
- package/src/client/sync/WorkDirCard.tsx +112 -0
- package/src/client/sync/history-model.test.ts +42 -9
- package/src/client/sync/history-model.ts +30 -15
- package/src/client/sync/sync-api.test.ts +57 -33
- package/src/client/sync/sync-api.ts +80 -6
- package/src/client/sync/sync-locales.ts +104 -3
- package/src/client/sync/sync-view-v2.test.ts +65 -13
- package/src/client/sync/sync-view.test.ts +107 -52
- package/src/client/sync/sync-view.ts +124 -41
- package/src/core/backup-plan.test.ts +28 -0
- package/src/core/backup-plan.ts +29 -17
- package/src/core/backup-verify.ts +24 -23
- package/src/core/backup.test.ts +76 -0
- package/src/core/backup.ts +55 -25
- package/src/core/boot-rescue.ts +4 -3
- package/src/core/boot-safety.ts +2 -1
- package/src/core/command-rollback.test.ts +536 -0
- package/src/core/command-rollback.ts +402 -0
- package/src/core/consult-source.ts +7 -6
- package/src/core/disk-usage.test.ts +257 -1
- package/src/core/disk-usage.ts +134 -14
- package/src/core/engine-locale.test.ts +593 -0
- package/src/core/engine-locale.ts +175 -0
- package/src/core/exporter.ts +3 -3
- package/src/core/fork-reconcile.test.ts +279 -0
- package/src/core/fork-reconcile.ts +234 -0
- package/src/core/journal.ts +6 -5
- package/src/core/local-plugin-host.ts +3 -2
- package/src/core/local-plugin-pack.ts +11 -6
- package/src/core/messages-core.ts +657 -0
- package/src/core/messages.ts +123 -17
- package/src/core/migration-consult.ts +21 -20
- package/src/core/migration-history.ts +19 -5
- package/src/core/model-tools.ts +28 -27
- package/src/core/phase3-host.ts +21 -5
- package/src/core/phase3-p2b-fingerprint.test.ts +22 -0
- package/src/core/plugin-cli.ts +18 -19
- package/src/core/reconcile.test.ts +117 -0
- package/src/core/reconcile.ts +85 -17
- package/src/core/recovery-orchestrator.ts +19 -18
- package/src/core/reinstall.ts +26 -21
- package/src/core/restore.ts +20 -17
- package/src/core/rollback-file-diff.test.ts +159 -0
- package/src/core/rollback-ignore-rules.ts +126 -0
- package/src/core/rollback-point.test.ts +2603 -0
- package/src/core/rollback-point.ts +3755 -0
- package/src/core/run-registry.ts +6 -5
- package/src/core/session-health.ts +15 -0
- package/src/core/session-meta.test.ts +117 -1
- package/src/core/session-meta.ts +149 -2
- package/src/core/session-title.test.ts +127 -0
- package/src/core/session-title.ts +189 -0
- package/src/core/startup-barrier.test.ts +69 -0
- package/src/core/startup-barrier.ts +27 -0
- package/src/core/transaction-coordinator.ts +4 -3
- package/src/core/types.ts +18 -1
- package/src/core/validator.ts +5 -4
- package/src/core/verify-recovery.ts +31 -30
- package/src/foreign/bundle.ts +3 -2
- package/src/foreign/continue.ts +2 -1
- package/src/foreign/crush.ts +2 -1
- package/src/foreign/file-budget.test.ts +2 -0
- package/src/foreign/gemini.ts +2 -1
- package/src/foreign/goose.ts +2 -1
- package/src/foreign/kilocode.ts +2 -1
- package/src/foreign/kimi.ts +2 -1
- package/src/foreign/messages.ts +44 -0
- package/src/foreign/mimocode.ts +2 -1
- package/src/foreign/openclaw.ts +2 -1
- package/src/foreign/opencode.ts +2 -1
- package/src/foreign/pi.ts +2 -1
- package/src/foreign/qoder.ts +2 -1
- package/src/foreign/qwen.ts +2 -1
- package/src/foreign/registry.ts +7 -6
- package/src/foreign/teleagent.ts +2 -1
- package/src/foreign/workbuddy.ts +2 -1
- package/src/foreign/zcode.ts +2 -1
- package/src/foreign/zed.ts +2 -1
- package/src/index.facade.test.ts +340 -1
- package/src/index.ts +813 -57
- package/src/market/git-file-writer.ts +20 -19
- package/src/market/github-repos.test.ts +23 -0
- package/src/market/github-repos.ts +37 -19
- package/src/market/index-parser.ts +31 -30
- package/src/market/messages-market.ts +325 -0
- package/src/market/my-repo.ts +32 -29
- package/src/market/prepare.ts +18 -15
- package/src/market/security.ts +20 -19
- package/src/market/types.ts +2 -1
- package/src/market/url.ts +2 -1
- package/src/migrations/index.ts +6 -5
- package/src/migrations/messages-migrations.ts +59 -0
- package/src/profiles/dsh-profile-launcher.ts +2 -1
- package/src/profiles/dsh-profile-runtime.ts +2 -1
- package/src/profiles/messages.ts +31 -0
- package/src/routes/backup.ts +18 -2
- package/src/routes/import.ts +3 -3
- package/src/routes/index.ts +1 -1
- package/src/routes/kit.ts +9 -3
- package/src/routes/market.ts +1 -1
- package/src/routes/messages.ts +104 -0
- package/src/routes/profiles.ts +12 -6
- package/src/routes/recovery.test.ts +405 -1
- package/src/routes/recovery.ts +377 -109
- package/src/routes/snapshots.ts +51 -4
- package/src/routes/sync.ts +67 -16
- package/src/schema/config.ts +53 -20
- package/src/schema/index.ts +7 -5
- package/src/schema/manifest.ts +19 -18
- package/src/schema/messages.ts +120 -0
- package/src/schema/registry.test.ts +19 -5
- package/src/schema/section-registry.ts +64 -39
- package/src/schema/versions.ts +6 -5
- package/src/security/encryption.ts +16 -15
- package/src/security/integrity.ts +8 -7
- package/src/security/messages.ts +87 -0
- package/src/security/redaction.test.ts +17 -1
- package/src/security/redaction.ts +13 -0
- package/src/security/secret-scanner.ts +19 -12
- package/src/security/security.test.ts +47 -0
- package/src/security/vault.ts +2 -1
- package/src/security/zip-security.ts +4 -3
- package/src/sync/ancestor.ts +2 -1
- package/src/sync/autosync-config.ts +21 -0
- package/src/sync/autosync-scheduler.test.ts +63 -7
- package/src/sync/autosync-scheduler.ts +118 -78
- package/src/sync/backup-files.ts +3 -2
- package/src/sync/backup-scheduler.ts +6 -5
- package/src/sync/blob-store.ts +2 -1
- package/src/sync/git/git-transport.test.ts +170 -8
- package/src/sync/git/git-transport.ts +176 -2
- package/src/sync/github-auth.ts +10 -9
- package/src/sync/layout.ts +13 -12
- package/src/sync/messages.ts +153 -0
- package/src/sync/review-queue.ts +6 -5
- package/src/sync/s3/messages.ts +16 -0
- package/src/sync/s3/s3-providers.ts +9 -6
- package/src/sync/s3/s3-transport.ts +1 -1
- package/src/sync/s3/sigv4.ts +3 -1
- package/src/sync/snapshot-crypto.ts +6 -5
- package/src/sync/snapshot-json.ts +3 -2
- package/src/sync/sync-engine-download-tombstone.test.ts +1 -1
- package/src/sync/sync-engine.test.ts +226 -8
- package/src/sync/sync-engine.ts +103 -41
- package/src/sync/sync-history.ts +7 -6
- package/src/sync/sync-selection.test.ts +12 -2
- package/src/sync/sync-selection.ts +18 -5
- package/src/sync/webdav/webdav-transport.ts +4 -1
- package/src/ui/artifact-view.ts +4 -3
- package/src/ui/commands.test.ts +1 -0
- package/src/ui/commands.ts +11 -1
- package/src/ui/disk-usage-view.test.ts +113 -6
- package/src/ui/disk-usage-view.ts +63 -7
- package/src/ui/errors.ts +4 -3
- package/src/ui/export-flow.ts +24 -20
- package/src/ui/foreign-view.test.ts +43 -0
- package/src/ui/foreign-view.ts +30 -3
- package/src/ui/i18n.ts +125 -0
- package/src/ui/import-wizard.ts +18 -10
- package/src/ui/progress.ts +2 -2
- package/src/ui/report.ts +7 -6
- package/src/ui/rollback-view.test.ts +819 -0
- package/src/ui/rollback-view.ts +1339 -0
- package/src/ui/selection-model.test.ts +33 -1
- package/src/ui/selection-model.ts +53 -0
- package/src/ui/session-inventory-view.test.ts +109 -0
- package/src/ui/session-inventory-view.ts +138 -3
- package/src/ui/session-issue-labels.test.ts +51 -0
- package/src/ui/session-issue-labels.ts +70 -0
- package/src/ui/sync-settings-view.test.ts +36 -0
- package/src/ui/sync-settings-view.ts +49 -0
- package/src/ui/types.ts +10 -4
- package/src/utils/atomic-write.ts +6 -5
- package/src/utils/bundle-scan.test.ts +2 -2
- package/src/utils/bundle-scan.ts +12 -1
- package/src/utils/env-lock.ts +83 -49
- package/src/utils/json.ts +7 -5
- package/src/utils/messages-utils.ts +232 -0
- package/src/utils/proxy.test.ts +25 -0
- package/src/utils/proxy.ts +19 -5
- package/src/utils/recursive-walk.test.ts +43 -0
- package/src/utils/recursive-walk.ts +75 -1
- package/src/utils/session-log-repair.ts +10 -9
- package/src/utils/zip.ts +27 -26
- package/lib/core/checkpoint.d.ts +0 -362
- package/lib/core/checkpoint.js +0 -1309
- package/src/core/checkpoint.test.ts +0 -665
- package/src/core/checkpoint.ts +0 -1614
|
@@ -7,14 +7,18 @@ import assert from 'node:assert/strict'
|
|
|
7
7
|
|
|
8
8
|
import type { PullChange, SyncPullReport, SyncPushReport } from '../../sync/sync-engine.ts'
|
|
9
9
|
import type { SectionId } from '../../schema/types.ts'
|
|
10
|
-
import type { GithubPollResponse, SyncSectionInfo, SyncStatusResponse } from './sync-api.ts'
|
|
10
|
+
import type { AutosyncStatusResponse, GithubPollResponse, SyncSectionInfo, SyncStatusResponse } from './sync-api.ts'
|
|
11
11
|
import {
|
|
12
12
|
autosyncIntervalMs, computeAutosyncCountdown, computeGithubLoginView, computeSyncButtons, computeSyncStatus,
|
|
13
13
|
DEFAULT_SYNC_SESSIONS_LIMIT, defaultChannelSyncState, formatDateTime, formatIntervalDuration, formatLastSync,
|
|
14
|
+
autosyncSkipDetail,
|
|
14
15
|
githubPollMessage, initialSyncSections, kindLabel, normalizeSessionsLimit, privateRepoHint,
|
|
15
16
|
pullReportView, pushReportView, presetById, presetIdForUrl, readStoredChannel, recommendedSyncSections,
|
|
16
17
|
severityLabel, summarizePullChanges, syncSectionGroups, syncSectionOptions, WEBDAV_PRESETS, writeStoredChannel,
|
|
17
18
|
} from './sync-view.ts'
|
|
19
|
+
import type { SyncTextFn } from './sync-view.ts'
|
|
20
|
+
import { en as syncEn, zh as syncZh } from './sync-locales.ts'
|
|
21
|
+
import { zhUiT } from '../../ui/i18n.ts'
|
|
18
22
|
|
|
19
23
|
/* ---------------------------------------------------------------- sessions 可选分区 */
|
|
20
24
|
|
|
@@ -50,7 +54,7 @@ test('sync-view: initialSyncSections —— 首次打开预勾选推荐分区;
|
|
|
50
54
|
/* ---------------------------------------------------------------- 私有仓库提示 */
|
|
51
55
|
|
|
52
56
|
test('sync-view: 私有仓库强制提示文案存在且强调私有', () => {
|
|
53
|
-
const hint = privateRepoHint()
|
|
57
|
+
const hint = privateRepoHint(zhUiT)
|
|
54
58
|
assert.match(hint, /私有/)
|
|
55
59
|
assert.match(hint, /public/)
|
|
56
60
|
assert.match(hint, /token/)
|
|
@@ -66,7 +70,7 @@ const SYNC_CATALOG: SyncSectionInfo[] = [
|
|
|
66
70
|
];
|
|
67
71
|
|
|
68
72
|
test('sync-view: syncSectionOptions 把 host 目录投影为勾选项(保 id 顺序 + 导出目录分组/描述补充)', () => {
|
|
69
|
-
const opts = syncSectionOptions(SYNC_CATALOG)
|
|
73
|
+
const opts = syncSectionOptions(SYNC_CATALOG, zhUiT)
|
|
70
74
|
assert.deepEqual(opts.map((o) => o.id), ['settings', 'providers', 'plugins', 'skills'])
|
|
71
75
|
assert.equal(opts[0]?.label, 'Settings')
|
|
72
76
|
assert.equal(opts[0]?.defaultIncluded, true)
|
|
@@ -82,14 +86,14 @@ test('sync-view: syncSectionOptions 把 host 目录投影为勾选项(保 id
|
|
|
82
86
|
test('sync-view: syncSectionOptions 未知分区 id → 兜底(description 空、group=general)', () => {
|
|
83
87
|
const opts = syncSectionOptions([
|
|
84
88
|
{ id: 'nope' as SectionId, displayName: 'Nope', portability: 'portable', defaultIncluded: true },
|
|
85
|
-
])
|
|
89
|
+
], zhUiT)
|
|
86
90
|
assert.equal(opts[0]?.label, 'Nope')
|
|
87
91
|
assert.equal(opts[0]?.description, '')
|
|
88
92
|
assert.equal(opts[0]?.group, 'general')
|
|
89
93
|
});
|
|
90
94
|
|
|
91
95
|
test('sync-view: syncSectionGroups 按导出分组投影(与「导出备份·自定义模式」同构,空组省略)', () => {
|
|
92
|
-
const groups = syncSectionGroups(syncSectionOptions(SYNC_CATALOG))
|
|
96
|
+
const groups = syncSectionGroups(syncSectionOptions(SYNC_CATALOG, zhUiT), zhUiT)
|
|
93
97
|
// settings(general) + providers(ai) + plugins(extensions) + skills(customization)
|
|
94
98
|
assert.deepEqual(groups.map((g) => g.group), ['general', 'ai', 'extensions', 'customization'])
|
|
95
99
|
assert.equal(groups[0]?.label, 'General')
|
|
@@ -114,13 +118,13 @@ test('sync-view: recommendedSyncSections 排除非 portable / 非默认包含分
|
|
|
114
118
|
|
|
115
119
|
test('sync-view: 空/缺省目录 → 推荐分区为空数组(UI 显示「至少选一个」场景)', () => {
|
|
116
120
|
assert.deepEqual(recommendedSyncSections([]), [])
|
|
117
|
-
assert.deepEqual(syncSectionOptions([]), [])
|
|
121
|
+
assert.deepEqual(syncSectionOptions([], zhUiT), [])
|
|
118
122
|
});
|
|
119
123
|
|
|
120
124
|
/* ---------------------------------------------------------------- 按钮状态 */
|
|
121
125
|
|
|
122
126
|
test('sync-view: 空闲 + 活动通道地址未就绪 → 两个按钮都禁用', () => {
|
|
123
|
-
const b = computeSyncButtons(null, false)
|
|
127
|
+
const b = computeSyncButtons(null, false, zhUiT)
|
|
124
128
|
assert.equal(b.canPush, false)
|
|
125
129
|
assert.equal(b.canPull, false)
|
|
126
130
|
assert.equal(b.pushLabel, '推送到远端')
|
|
@@ -128,13 +132,13 @@ test('sync-view: 空闲 + 活动通道地址未就绪 → 两个按钮都禁用'
|
|
|
128
132
|
})
|
|
129
133
|
|
|
130
134
|
test('sync-view: 空闲 + 活动通道地址就绪 → 两个按钮可用', () => {
|
|
131
|
-
const b = computeSyncButtons(null, true)
|
|
135
|
+
const b = computeSyncButtons(null, true, zhUiT)
|
|
132
136
|
assert.equal(b.canPush, true)
|
|
133
137
|
assert.equal(b.canPull, true)
|
|
134
138
|
})
|
|
135
139
|
|
|
136
140
|
test('sync-view: push 进行中 → 按钮禁用且文案切换为正在推送(防并发)', () => {
|
|
137
|
-
const b = computeSyncButtons('push', true)
|
|
141
|
+
const b = computeSyncButtons('push', true, zhUiT)
|
|
138
142
|
assert.equal(b.canPush, false)
|
|
139
143
|
assert.equal(b.canPull, false)
|
|
140
144
|
assert.equal(b.pushLabel, '正在推送…')
|
|
@@ -142,7 +146,7 @@ test('sync-view: push 进行中 → 按钮禁用且文案切换为正在推送
|
|
|
142
146
|
})
|
|
143
147
|
|
|
144
148
|
test('sync-view: pull 进行中 → 两个按钮都禁用,pull 文案切换', () => {
|
|
145
|
-
const b = computeSyncButtons('pull', true)
|
|
149
|
+
const b = computeSyncButtons('pull', true, zhUiT)
|
|
146
150
|
assert.equal(b.canPush, false)
|
|
147
151
|
assert.equal(b.canPull, false)
|
|
148
152
|
assert.equal(b.pullLabel, '正在拉取…')
|
|
@@ -191,19 +195,19 @@ test('sync-view: summarizePullChanges 空数组 → total 0 且不需决策', ()
|
|
|
191
195
|
})
|
|
192
196
|
|
|
193
197
|
test('sync-view: kindLabel / severityLabel 覆盖关键类型', () => {
|
|
194
|
-
assert.equal(kindLabel('Conflict'), '冲突')
|
|
195
|
-
assert.equal(kindLabel('Install'), '安装')
|
|
196
|
-
assert.equal(kindLabel('MissingSecret'), '缺密钥')
|
|
197
|
-
assert.equal(severityLabel('error'), '错误')
|
|
198
|
-
assert.equal(severityLabel('warning'), '警告')
|
|
199
|
-
assert.equal(severityLabel('info'), '信息')
|
|
198
|
+
assert.equal(kindLabel('Conflict', zhUiT), '冲突')
|
|
199
|
+
assert.equal(kindLabel('Install', zhUiT), '安装')
|
|
200
|
+
assert.equal(kindLabel('MissingSecret', zhUiT), '缺密钥')
|
|
201
|
+
assert.equal(severityLabel('error', zhUiT), '错误')
|
|
202
|
+
assert.equal(severityLabel('warning', zhUiT), '警告')
|
|
203
|
+
assert.equal(severityLabel('info', zhUiT), '信息')
|
|
200
204
|
})
|
|
201
205
|
|
|
202
206
|
/* ---------------------------------------------------------------- push 报告渲染 */
|
|
203
207
|
|
|
204
208
|
test('sync-view: push 成功报告 → ok 头部含快照 id + 分区透传', () => {
|
|
205
209
|
const report: SyncPushReport = { ok: true, snapshotId: 'sync-1', sections: ['settings', 'plugins'], warnings: [] }
|
|
206
|
-
const view = pushReportView(report)
|
|
210
|
+
const view = pushReportView(report, zhUiT)
|
|
207
211
|
assert.notEqual(view, null)
|
|
208
212
|
assert.equal(view?.kind, 'ok')
|
|
209
213
|
assert.match(view?.headline ?? '', /sync-1/)
|
|
@@ -212,21 +216,21 @@ test('sync-view: push 成功报告 → ok 头部含快照 id + 分区透传', ()
|
|
|
212
216
|
|
|
213
217
|
test('sync-view: push 失败报告 → error 显示引擎 message', () => {
|
|
214
218
|
const report: SyncPushReport = { ok: false, snapshotId: '', sections: [], warnings: [], message: '全部导出失败' }
|
|
215
|
-
const view = pushReportView(report)
|
|
219
|
+
const view = pushReportView(report, zhUiT)
|
|
216
220
|
assert.equal(view?.kind, 'error')
|
|
217
221
|
assert.equal(view?.headline, '全部导出失败')
|
|
218
222
|
})
|
|
219
223
|
|
|
220
224
|
test('sync-view: null 报告 → null(不渲染卡片)', () => {
|
|
221
|
-
assert.equal(pushReportView(null), null)
|
|
222
|
-
assert.equal(pullReportView(null), null)
|
|
225
|
+
assert.equal(pushReportView(null, zhUiT), null)
|
|
226
|
+
assert.equal(pullReportView(null, zhUiT), null)
|
|
223
227
|
})
|
|
224
228
|
|
|
225
229
|
/* ---------------------------------------------------------------- pull 报告渲染 */
|
|
226
230
|
|
|
227
231
|
test('sync-view: pull 无变更 → empty 渲染(无差异列表)', () => {
|
|
228
232
|
const report: SyncPullReport = { ok: true, snapshotId: 'sync-1', changes: [], needsReview: false }
|
|
229
|
-
const view = pullReportView(report)
|
|
233
|
+
const view = pullReportView(report, zhUiT)
|
|
230
234
|
assert.equal(view?.kind, 'empty')
|
|
231
235
|
assert.equal(view?.summary, null)
|
|
232
236
|
})
|
|
@@ -241,7 +245,7 @@ test('sync-view: pull 差异报告 → ok + 摘要计数 + needsReview + 只读
|
|
|
241
245
|
],
|
|
242
246
|
needsReview: true,
|
|
243
247
|
}
|
|
244
|
-
const view = pullReportView(report)
|
|
248
|
+
const view = pullReportView(report, zhUiT)
|
|
245
249
|
assert.equal(view?.kind, 'ok')
|
|
246
250
|
assert.match(view?.headline ?? '', /sync-9/)
|
|
247
251
|
assert.equal(view?.summary?.total, 2)
|
|
@@ -254,7 +258,7 @@ test('sync-view: pull 差异报告 → ok + 摘要计数 + needsReview + 只读
|
|
|
254
258
|
|
|
255
259
|
test('sync-view: pull 失败 → error 渲染', () => {
|
|
256
260
|
const report: SyncPullReport = { ok: false, snapshotId: '', changes: [], needsReview: false, message: '认证失败' }
|
|
257
|
-
const view = pullReportView(report)
|
|
261
|
+
const view = pullReportView(report, zhUiT)
|
|
258
262
|
assert.equal(view?.kind, 'error')
|
|
259
263
|
assert.equal(view?.headline, '认证失败')
|
|
260
264
|
})
|
|
@@ -262,18 +266,18 @@ test('sync-view: pull 失败 → error 渲染', () => {
|
|
|
262
266
|
/* ---------------------------------------------------------------- 状态行 */
|
|
263
267
|
|
|
264
268
|
test('sync-view: 加载中 → loading 状态', () => {
|
|
265
|
-
const s = computeSyncStatus(null, true, null)
|
|
269
|
+
const s = computeSyncStatus(null, true, null, zhUiT)
|
|
266
270
|
assert.equal(s.kind, 'loading')
|
|
267
271
|
})
|
|
268
272
|
|
|
269
273
|
test('sync-view: 加载失败 → error 状态带消息', () => {
|
|
270
|
-
const s = computeSyncStatus(null, false, '网络错误')
|
|
274
|
+
const s = computeSyncStatus(null, false, '网络错误', zhUiT)
|
|
271
275
|
assert.equal(s.kind, 'error')
|
|
272
276
|
assert.equal(s.text, '网络错误')
|
|
273
277
|
})
|
|
274
278
|
|
|
275
279
|
test('sync-view: 未配置仓库 → unconfigured 提示', () => {
|
|
276
|
-
const s = computeSyncStatus(null, false, null)
|
|
280
|
+
const s = computeSyncStatus(null, false, null, zhUiT)
|
|
277
281
|
assert.equal(s.kind, 'unconfigured')
|
|
278
282
|
assert.match(s.text, /尚未配置/)
|
|
279
283
|
})
|
|
@@ -283,7 +287,7 @@ test('sync-view: 已配置但缺凭据 → ready 文案提示未配置凭据', (
|
|
|
283
287
|
ok: true, configured: true, repoUrl: 'https://github.com/u/r.git',
|
|
284
288
|
credentialConfigured: false, credentialWritable: true, lastSyncAt: undefined, sectionCount: 0,
|
|
285
289
|
}
|
|
286
|
-
const s = computeSyncStatus(info, false, null)
|
|
290
|
+
const s = computeSyncStatus(info, false, null, zhUiT)
|
|
287
291
|
assert.equal(s.kind, 'ready')
|
|
288
292
|
assert.match(s.text, /未配置凭据/)
|
|
289
293
|
})
|
|
@@ -295,7 +299,7 @@ test('sync-view: 已配置 + 凭据就绪 + 上次同步 → ready 文案含日
|
|
|
295
299
|
lastSyncAt: '2026-08-16T10:30:00.000Z', sectionCount: 3,
|
|
296
300
|
transport: { type: 'git', ref: 'main' },
|
|
297
301
|
}
|
|
298
|
-
const s = computeSyncStatus(info, false, null)
|
|
302
|
+
const s = computeSyncStatus(info, false, null, zhUiT)
|
|
299
303
|
assert.equal(s.kind, 'ready')
|
|
300
304
|
assert.match(s.text, /凭据已配置/)
|
|
301
305
|
assert.match(s.text, /上次同步/)
|
|
@@ -310,7 +314,7 @@ test('sync-view: webdav 通道 → ready 文案回显通道类型(webdav + 服
|
|
|
310
314
|
lastSyncAt: '2026-08-16T10:30:00.000Z', sectionCount: 2,
|
|
311
315
|
transport: { type: 'webdav', ref: 'https://dav.example.com/dav/config' },
|
|
312
316
|
}
|
|
313
|
-
const s = computeSyncStatus(info, false, null)
|
|
317
|
+
const s = computeSyncStatus(info, false, null, zhUiT)
|
|
314
318
|
assert.equal(s.kind, 'ready')
|
|
315
319
|
assert.match(s.text, /凭据已配置/)
|
|
316
320
|
assert.match(s.text, /webdav/)
|
|
@@ -320,12 +324,12 @@ test('sync-view: webdav 通道 → ready 文案回显通道类型(webdav + 服
|
|
|
320
324
|
/* ---------------------------------------------------------------- 时间格式化 */
|
|
321
325
|
|
|
322
326
|
test('sync-view: formatLastSync 空值 → 从未同步', () => {
|
|
323
|
-
assert.equal(formatLastSync(undefined), '从未同步')
|
|
324
|
-
assert.equal(formatLastSync(''), '从未同步')
|
|
327
|
+
assert.equal(formatLastSync(undefined, zhUiT), '从未同步')
|
|
328
|
+
assert.equal(formatLastSync('', zhUiT), '从未同步')
|
|
325
329
|
})
|
|
326
330
|
|
|
327
331
|
test('sync-view: formatLastSync / formatDateTime 合法 ISO → 本地可读格式', () => {
|
|
328
|
-
const text = formatLastSync('2026-08-16T10:30:00.000Z')
|
|
332
|
+
const text = formatLastSync('2026-08-16T10:30:00.000Z', zhUiT)
|
|
329
333
|
assert.match(text, /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/)
|
|
330
334
|
assert.equal(formatDateTime('not-a-date'), 'not-a-date')
|
|
331
335
|
})
|
|
@@ -333,7 +337,7 @@ test('sync-view: formatLastSync / formatDateTime 合法 ISO → 本地可读格
|
|
|
333
337
|
/* ------------------------------------------------ GitHub 登录视图模型 */
|
|
334
338
|
|
|
335
339
|
test('sync-view: github 登录 idle → 可开始、不展示代码区块、无错误', () => {
|
|
336
|
-
const v = computeGithubLoginView('idle', '', '', null)
|
|
340
|
+
const v = computeGithubLoginView('idle', '', '', null, zhUiT)
|
|
337
341
|
assert.equal(v.phase, 'idle')
|
|
338
342
|
assert.equal(v.canStart, true)
|
|
339
343
|
assert.equal(v.canCancel, false)
|
|
@@ -342,14 +346,14 @@ test('sync-view: github 登录 idle → 可开始、不展示代码区块、无
|
|
|
342
346
|
})
|
|
343
347
|
|
|
344
348
|
test('sync-view: github 登录 starting → 不可重复发起、显示进行中文案', () => {
|
|
345
|
-
const v = computeGithubLoginView('starting', '', '', null)
|
|
349
|
+
const v = computeGithubLoginView('starting', '', '', null, zhUiT)
|
|
346
350
|
assert.equal(v.canStart, false)
|
|
347
351
|
assert.equal(v.canCancel, true)
|
|
348
352
|
assert.match(v.statusText, /发起/)
|
|
349
353
|
})
|
|
350
354
|
|
|
351
355
|
test('sync-view: github 登录 waiting → 展示设备码与授权链接、可取消', () => {
|
|
352
|
-
const v = computeGithubLoginView('waiting', 'ABCD-EFGH', 'https://github.com/login/device', null)
|
|
356
|
+
const v = computeGithubLoginView('waiting', 'ABCD-EFGH', 'https://github.com/login/device', null, zhUiT)
|
|
353
357
|
assert.equal(v.showCode, true)
|
|
354
358
|
assert.equal(v.canCancel, true)
|
|
355
359
|
assert.equal(v.userCode, 'ABCD-EFGH')
|
|
@@ -358,7 +362,7 @@ test('sync-view: github 登录 waiting → 展示设备码与授权链接、可
|
|
|
358
362
|
})
|
|
359
363
|
|
|
360
364
|
test('sync-view: github 登录 polling → 仍展示代码区块且可取消', () => {
|
|
361
|
-
const v = computeGithubLoginView('polling', 'ABCD-EFGH', 'https://github.com/login/device', null)
|
|
365
|
+
const v = computeGithubLoginView('polling', 'ABCD-EFGH', 'https://github.com/login/device', null, zhUiT)
|
|
362
366
|
assert.equal(v.showCode, true)
|
|
363
367
|
assert.equal(v.canCancel, true)
|
|
364
368
|
assert.equal(v.canStart, false)
|
|
@@ -366,14 +370,14 @@ test('sync-view: github 登录 polling → 仍展示代码区块且可取消', (
|
|
|
366
370
|
})
|
|
367
371
|
|
|
368
372
|
test('sync-view: github 登录 success → 成功文案、代码区块隐藏', () => {
|
|
369
|
-
const v = computeGithubLoginView('success', 'ABCD-EFGH', 'https://github.com/login/device', null)
|
|
373
|
+
const v = computeGithubLoginView('success', 'ABCD-EFGH', 'https://github.com/login/device', null, zhUiT)
|
|
370
374
|
assert.equal(v.showCode, false)
|
|
371
375
|
assert.equal(v.canStart, false)
|
|
372
376
|
assert.match(v.statusText, /已安全写入/)
|
|
373
377
|
})
|
|
374
378
|
|
|
375
379
|
test('sync-view: github 登录 error → 展示错误 + 重新登录入口', () => {
|
|
376
|
-
const v = computeGithubLoginView('error', '', '', '授权被拒绝')
|
|
380
|
+
const v = computeGithubLoginView('error', '', '', '授权被拒绝', zhUiT)
|
|
377
381
|
assert.equal(v.canStart, true)
|
|
378
382
|
assert.equal(v.canCancel, false)
|
|
379
383
|
assert.equal(v.error, '授权被拒绝')
|
|
@@ -383,15 +387,15 @@ test('sync-view: github 登录 error → 展示错误 + 重新登录入口', ()
|
|
|
383
387
|
|
|
384
388
|
test('sync-view: githubPollMessage 映射轮询终止态(denied/expired/error/success)', () => {
|
|
385
389
|
const denied: GithubPollResponse = { status: 'denied' }
|
|
386
|
-
assert.match(githubPollMessage(denied), /拒绝/)
|
|
390
|
+
assert.match(githubPollMessage(denied, zhUiT), /拒绝/)
|
|
387
391
|
const expired: GithubPollResponse = { status: 'expired' }
|
|
388
|
-
assert.match(githubPollMessage(expired), /过期/)
|
|
392
|
+
assert.match(githubPollMessage(expired, zhUiT), /过期/)
|
|
389
393
|
const error: GithubPollResponse = { status: 'error', errorCode: 'incorrect_device_code', message: '设备码不匹配' }
|
|
390
|
-
assert.match(githubPollMessage(error), /设备码不匹配/)
|
|
394
|
+
assert.match(githubPollMessage(error, zhUiT), /设备码不匹配/)
|
|
391
395
|
const success: GithubPollResponse = { status: 'success', credentialConfigured: true }
|
|
392
|
-
assert.match(githubPollMessage(success), /已安全写入/)
|
|
396
|
+
assert.match(githubPollMessage(success, zhUiT), /已安全写入/)
|
|
393
397
|
const pending: GithubPollResponse = { status: 'pending', pollDelayMs: 5000 }
|
|
394
|
-
assert.equal(githubPollMessage(pending), '', 'pending 不是终止态,不应产生消息')
|
|
398
|
+
assert.equal(githubPollMessage(pending, zhUiT), '', 'pending 不是终止态,不应产生消息')
|
|
395
399
|
})
|
|
396
400
|
|
|
397
401
|
/* ---------------------------------------------------------------- 自动同步倒计时 */
|
|
@@ -416,19 +420,19 @@ test('sync-view: computeAutosyncCountdown 已到期 → 0;未到 → interval
|
|
|
416
420
|
|
|
417
421
|
test('sync-view: formatIntervalDuration 输出真实剩余时长(不再把 <1 小时一律显示成 30 分钟)', () => {
|
|
418
422
|
// 回归:旧实现 `if (minutes < 60) return '30 分钟'` 导致 5m 间隔永远显示「约 30 分钟后」
|
|
419
|
-
assert.equal(formatIntervalDuration(4 * 60 * 1000), '4 分钟')
|
|
420
|
-
assert.equal(formatIntervalDuration(5 * 60 * 1000), '5 分钟')
|
|
421
|
-
assert.equal(formatIntervalDuration(30 * 60 * 1000), '30 分钟')
|
|
423
|
+
assert.equal(formatIntervalDuration(4 * 60 * 1000, zhUiT), '4 分钟')
|
|
424
|
+
assert.equal(formatIntervalDuration(5 * 60 * 1000, zhUiT), '5 分钟')
|
|
425
|
+
assert.equal(formatIntervalDuration(30 * 60 * 1000, zhUiT), '30 分钟')
|
|
422
426
|
// 整 60 分钟进位为 1 小时
|
|
423
|
-
assert.equal(formatIntervalDuration(60 * 60 * 1000), '1 小时')
|
|
427
|
+
assert.equal(formatIntervalDuration(60 * 60 * 1000, zhUiT), '1 小时')
|
|
424
428
|
// 向上取整:90 分钟 → 2 小时;6 小时整 → 6 小时
|
|
425
|
-
assert.equal(formatIntervalDuration(90 * 60 * 1000), '2 小时')
|
|
426
|
-
assert.equal(formatIntervalDuration(6 * 60 * 60 * 1000), '6 小时')
|
|
429
|
+
assert.equal(formatIntervalDuration(90 * 60 * 1000, zhUiT), '2 小时')
|
|
430
|
+
assert.equal(formatIntervalDuration(6 * 60 * 60 * 1000, zhUiT), '6 小时')
|
|
427
431
|
// 跨天:24 小时 → 1 天;48 小时 → 2 天
|
|
428
|
-
assert.equal(formatIntervalDuration(24 * 60 * 60 * 1000), '1 天')
|
|
429
|
-
assert.equal(formatIntervalDuration(48 * 60 * 60 * 1000), '2 天')
|
|
432
|
+
assert.equal(formatIntervalDuration(24 * 60 * 60 * 1000, zhUiT), '1 天')
|
|
433
|
+
assert.equal(formatIntervalDuration(48 * 60 * 60 * 1000, zhUiT), '2 天')
|
|
430
434
|
// 已到期/异常值兜底为 1 分钟,不出现 0 分钟
|
|
431
|
-
assert.equal(formatIntervalDuration(0), '1 分钟')
|
|
435
|
+
assert.equal(formatIntervalDuration(0, zhUiT), '1 分钟')
|
|
432
436
|
})
|
|
433
437
|
|
|
434
438
|
/* ---------------------------------------------------------------- WebDAV 预设 */
|
|
@@ -505,3 +509,54 @@ test('sync-view: defaultChannelSyncState 每通道独立缺省值', () => {
|
|
|
505
509
|
assert.equal(git.syncMode, 'advanced', '修改一个通道缺省不影响另一个')
|
|
506
510
|
assert.deepEqual(git.syncSections, [], '另一个通道的勾选不受影响')
|
|
507
511
|
})
|
|
512
|
+
|
|
513
|
+
/* ---------------------------------------------------------------- issue #79 */
|
|
514
|
+
|
|
515
|
+
/** 同步字典取词器(支持 {n} 插值;缺键回退键本身,与运行时同口径)。 */
|
|
516
|
+
function mkSyncText(dict: Record<string, string>): SyncTextFn {
|
|
517
|
+
return ((key: string, params?: Record<string, unknown>): string => {
|
|
518
|
+
const raw = dict[key] ?? key
|
|
519
|
+
return params === undefined
|
|
520
|
+
? raw
|
|
521
|
+
: raw.replace(/\{(\w+)\}/g, (m, k: string) => (k in params ? String(params[k]) : m))
|
|
522
|
+
}) as unknown as SyncTextFn
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const syncZhText = mkSyncText(syncZh)
|
|
526
|
+
const syncEnText = mkSyncText(syncEn)
|
|
527
|
+
|
|
528
|
+
function autosyncStatus(overrides: Partial<AutosyncStatusResponse> = {}): AutosyncStatusResponse {
|
|
529
|
+
return { enabled: true, interval: '30m', consecutiveFailures: 0, elapsedMs: 0, ...overrides }
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
test('issue #79:autosyncSkipDetail —— 冲突带「另有 N 个分区待确认」,其余码只给原因', () => {
|
|
533
|
+
assert.equal(
|
|
534
|
+
autosyncSkipDetail(autosyncStatus({ lastRunSkipReason: 'conflict', lastRunSkipCount: 3 }), syncZhText),
|
|
535
|
+
'冲突(远端另有 3 个分区待确认,可在同步页手动处理)',
|
|
536
|
+
)
|
|
537
|
+
assert.equal(autosyncSkipDetail(autosyncStatus({ lastRunSkipReason: 'conflict' }), syncZhText), '冲突', '无计数时只给原因,不编数字')
|
|
538
|
+
assert.equal(
|
|
539
|
+
autosyncSkipDetail(autosyncStatus({ lastRunSkipReason: 'upToDate' }), syncZhText),
|
|
540
|
+
syncZh['history.autosyncReasonUpToDate'],
|
|
541
|
+
)
|
|
542
|
+
assert.equal(
|
|
543
|
+
autosyncSkipDetail(autosyncStatus({ lastRunSkipReason: 'unconfigured' }), syncZhText),
|
|
544
|
+
syncZh['history.autosyncReasonNotConfigured'],
|
|
545
|
+
'宿主两处命名同义 → 同一文案',
|
|
546
|
+
)
|
|
547
|
+
})
|
|
548
|
+
|
|
549
|
+
test('issue #79:autosyncSkipDetail —— 未跳过时无明细;未知码给兜底而**不渲染裸码**', () => {
|
|
550
|
+
assert.equal(autosyncSkipDetail(autosyncStatus(), syncZhText), null)
|
|
551
|
+
assert.equal(autosyncSkipDetail(autosyncStatus({ lastRunSkipReason: '' }), syncZhText), null)
|
|
552
|
+
const unknown = autosyncSkipDetail(autosyncStatus({ lastRunSkipReason: 'brand-new-code' }), syncZhText)
|
|
553
|
+
assert.equal(unknown, syncZh['history.autosyncReasonUnknown'])
|
|
554
|
+
assert.ok(!String(unknown).includes('brand-new-code'), '绝不把裸码当文案渲染')
|
|
555
|
+
})
|
|
556
|
+
|
|
557
|
+
test('issue #79:autosyncSkipDetail —— en 界面下不得出现中文(文案只许来自字典)', () => {
|
|
558
|
+
const en = autosyncSkipDetail(autosyncStatus({ lastRunSkipReason: 'conflict', lastRunSkipCount: 2 }), syncEnText)
|
|
559
|
+
assert.doesNotMatch(String(en), /[\u4e00-\u9fff]/, 'en 界面不得出现中文:' + String(en))
|
|
560
|
+
assert.match(String(en), /2/)
|
|
561
|
+
})
|
|
562
|
+
|