dsh-config-manager 0.1.71 → 0.1.73
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 +149 -98
- package/README.zh-CN.md +245 -88
- package/lib/adapters/agent-instructions.js +1 -1
- package/lib/adapters/file-collection.js +1 -1
- package/lib/adapters/index.d.ts +2 -1
- package/lib/adapters/index.js +6 -1
- package/lib/adapters/link-report.d.ts +1 -0
- package/lib/adapters/link-report.js +27 -3
- package/lib/adapters/messages.d.ts +21 -0
- package/lib/adapters/messages.js +57 -0
- package/lib/adapters/plugin-data.d.ts +114 -0
- package/lib/adapters/plugin-data.js +309 -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 +8 -2
- package/lib/adapters/self.js +3 -2
- package/lib/adapters/sessions.d.ts +1 -0
- package/lib/adapters/sessions.js +4 -2
- package/lib/adapters/test-helpers.d.ts +9 -0
- package/lib/adapters/test-helpers.js +14 -0
- 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 +1442 -494
- package/lib/client.js +15326 -8520
- package/lib/core/analyzer.d.ts +11 -2
- package/lib/core/analyzer.js +31 -8
- package/lib/core/backup-plan.d.ts +10 -0
- package/lib/core/backup-plan.js +51 -20
- package/lib/core/backup-verify.js +24 -23
- package/lib/core/backup.d.ts +25 -1
- package/lib/core/backup.js +99 -28
- package/lib/core/boot-rescue.js +4 -3
- package/lib/core/boot-safety.js +2 -1
- package/lib/core/command-rollback.d.ts +182 -0
- package/lib/core/command-rollback.js +293 -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 +294 -0
- package/lib/core/messages-core.js +619 -0
- package/lib/core/messages.d.ts +61 -2
- package/lib/core/messages.js +118 -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/plugin-data-registry.d.ts +124 -0
- package/lib/core/plugin-data-registry.js +198 -0
- 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-gate.d.ts +33 -0
- package/lib/core/rollback-gate.js +57 -0
- package/lib/core/rollback-ignore-rules.d.ts +31 -0
- package/lib/core/rollback-ignore-rules.js +140 -0
- package/lib/core/rollback-ledger.d.ts +248 -0
- package/lib/core/rollback-ledger.js +1282 -0
- package/lib/core/rollback-point.d.ts +1391 -0
- package/lib/core/rollback-point.js +3503 -0
- package/lib/core/rollback.js +6 -4
- 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 +37 -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.d.ts +1 -1
- package/lib/foreign/registry.js +8 -7
- 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 +227 -7
- package/lib/index.js +799 -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 +43 -0
- package/lib/routes/messages.js +102 -0
- package/lib/routes/prefs.js +26 -3
- package/lib/routes/profiles.js +12 -6
- package/lib/routes/recovery.d.ts +21 -0
- package/lib/routes/recovery.js +478 -94
- package/lib/routes/snapshots.js +51 -4
- package/lib/routes/sync.js +79 -17
- 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 +42 -15
- package/lib/schema/section-registry.js +67 -32
- package/lib/schema/types.d.ts +1 -1
- 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 +58 -22
- package/lib/sync/sync-engine.js +119 -48
- 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/ui-prefs.d.ts +22 -0
- package/lib/sync/ui-prefs.js +28 -0
- 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/diff-view.d.ts +10 -0
- package/lib/ui/diff-view.js +17 -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 +26 -20
- package/lib/ui/foreign-view.d.ts +5 -1
- package/lib/ui/foreign-view.js +26 -2
- package/lib/ui/i18n.d.ts +68 -1
- package/lib/ui/i18n.js +120 -2
- 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 +815 -0
- package/lib/ui/rollback-view.js +738 -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/test-helpers.js +2 -1
- 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 +6 -1
- package/src/adapters/link-report.test.ts +22 -2
- package/src/adapters/link-report.ts +29 -4
- package/src/adapters/messages.ts +61 -0
- package/src/adapters/plugin-data.test.ts +225 -0
- package/src/adapters/plugin-data.ts +351 -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 +10 -3
- package/src/adapters/sessions.ts +4 -2
- package/src/adapters/settings.test.ts +38 -1
- package/src/adapters/test-helpers.ts +15 -0
- 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 +411 -0
- package/src/client/chat/RollbackDiffTab.tsx +108 -0
- package/src/client/chat/RollbackFileIcon.tsx +96 -0
- package/src/client/chat/RollbackReviewDialog.tsx +607 -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 +183 -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 +174 -0
- package/src/client/chat/rollback-entry-view.test.ts +1469 -0
- package/src/client/chat/rollback-entry-view.ts +946 -0
- package/src/client/chat/sidebar-slots.ts +59 -0
- package/src/client/common/ConfirmDialog.tsx +7 -3
- package/src/client/common/ContentPicker.tsx +48 -10
- package/src/client/common/DiffTable.tsx +133 -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 +84 -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 +38 -0
- package/src/client/common/section-labels.test.ts +1 -0
- package/src/client/common/section-labels.ts +2 -0
- package/src/client/common/ui.tsx +73 -10
- package/src/client/config-manager.module.css +1109 -31
- 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 +232 -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 +62 -9
- 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 +859 -0
- package/src/client/recovery/RollbackDiffPane.tsx +69 -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 +144 -6
- package/src/client/recovery/recovery-locales.test.ts +299 -0
- package/src/client/recovery/recovery-locales.ts +520 -149
- package/src/client/recovery/recovery-panel-layout.test.ts +132 -2
- package/src/client/recovery/rollback-enabled.ts +41 -0
- package/src/client/recovery/rollback-file-changes.test.ts +114 -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/analyzer.ts +31 -9
- package/src/core/backup-plan.test.ts +48 -5
- package/src/core/backup-plan.ts +51 -20
- package/src/core/backup-verify.ts +24 -23
- package/src/core/backup.test.ts +76 -0
- package/src/core/backup.ts +105 -29
- 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 +406 -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 +661 -0
- package/src/core/messages.ts +125 -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/plugin-data-registry.test.ts +113 -0
- package/src/core/plugin-data-registry.ts +261 -0
- 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-gate.test.ts +66 -0
- package/src/core/rollback-gate.ts +61 -0
- package/src/core/rollback-ignore-rules.ts +126 -0
- package/src/core/rollback-ledger.test.ts +655 -0
- package/src/core/rollback-ledger.ts +1314 -0
- package/src/core/rollback-point.test.ts +2853 -0
- package/src/core/rollback-point.ts +4340 -0
- package/src/core/rollback.ts +5 -3
- 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 +37 -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.test.ts +1 -1
- package/src/foreign/registry.ts +8 -7
- 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 +876 -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 +106 -0
- package/src/routes/prefs.ts +31 -2
- package/src/routes/profiles.ts +12 -6
- package/src/routes/recovery.test.ts +405 -1
- package/src/routes/recovery.ts +477 -94
- package/src/routes/snapshots.ts +51 -4
- package/src/routes/sync.ts +82 -17
- package/src/schema/config.ts +53 -20
- package/src/schema/index.ts +7 -5
- package/src/schema/manifest-schema.test.ts +4 -4
- package/src/schema/manifest.ts +19 -18
- package/src/schema/messages.ts +120 -0
- package/src/schema/registry.test.ts +28 -7
- package/src/schema/section-registry.ts +96 -42
- package/src/schema/types.ts +2 -1
- 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-credentials.test.ts +119 -0
- 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 +154 -52
- 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/transport.test.ts +1 -0
- package/src/sync/ui-prefs.test.ts +44 -1
- package/src/sync/ui-prefs.ts +39 -0
- 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/diff-view.test.ts +9 -1
- package/src/ui/diff-view.ts +22 -0
- 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 +26 -20
- package/src/ui/foreign-view.test.ts +43 -0
- package/src/ui/foreign-view.ts +30 -3
- package/src/ui/i18n.ts +131 -2
- 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 +836 -0
- package/src/ui/rollback-view.ts +1405 -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/test-helpers.ts +2 -1
- 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
package/src/core/messages.ts
CHANGED
|
@@ -10,9 +10,12 @@
|
|
|
10
10
|
* - zh 值 = 既有中文文案原样(缺省行为/测试断言不变);
|
|
11
11
|
* - en 值类型为 Record<keyof typeof zh, string> —— 缺键/多键即编译错误;
|
|
12
12
|
* - 消息以 {param} 插值,缺失参数原样保留,便于排查;
|
|
13
|
-
* - 未知键回退 zh
|
|
13
|
+
* - 未知键回退 zh,再回退键名本身(绝不抛错);
|
|
14
|
+
* - 目录是**追加式**的:新增键只追加,既有键的 zh/en 取值逐字不变(既有 372 键的指纹冻结在
|
|
15
|
+
* src/core/engine-locale.test.ts);registerMessageCatalog 注册的追加目录只在既有目录未命中时生效。
|
|
14
16
|
*/
|
|
15
|
-
import type { MsgFunc
|
|
17
|
+
import type { MsgFunc } from './msg-types.ts';
|
|
18
|
+
import { interpolate, registerBaseMessageCatalog, registeredMessage } from './engine-locale.ts';
|
|
16
19
|
|
|
17
20
|
export type { MsgFunc, MsgParams } from './msg-types.ts';
|
|
18
21
|
|
|
@@ -132,6 +135,7 @@ export const zh = {
|
|
|
132
135
|
'restore.hostSkipEscape': '宿主文件路径越界,跳过: {path}',
|
|
133
136
|
'restore.hostSkipEscapeDetail': '快照登记路径越界,拒绝恢复',
|
|
134
137
|
'restore.hostNoBlobInfo': '宿主文件 {path} 缺少 blob 副本,跳过',
|
|
138
|
+
'restore.hostUnreadable': '宿主文件 {path} 在拍快照时存在但读不出来(占用/权限),本次不动它;请手动核对',
|
|
135
139
|
'restore.hostBlobMissing': '宿主文件 {path} 的 blob 缺失,跳过',
|
|
136
140
|
'restore.hostRestore': '整文件还原 {path}',
|
|
137
141
|
'restore.backupBeforeWrite': '还原前将备份当前文件到 pre-restore/',
|
|
@@ -200,6 +204,14 @@ export const zh = {
|
|
|
200
204
|
'host.fsPathEscape': '路径越界: {path}',
|
|
201
205
|
'host.activationRowFailed': '插件 {pkg} 已安装,但激活行写入 profile 补丁失败:{reason}(重启后该插件可能未激活;修复后重试安装即可幂等补行)',
|
|
202
206
|
'host.syncTokenWriteFailed': 'token 写入 DSH credentials 失败:{reason}(请在 DSH 凭据管理里配置 {ref} 后重试)',
|
|
207
|
+
'host.syncWebdavPasswordWriteFailed': 'WebDAV 口令写入 DSH credentials 失败:{reason}(请在 DSH 凭据管理里配置 {ref} 后重试)',
|
|
208
|
+
'host.syncCredentialWriteFailed': '{kind} 写入 DSH credentials 失败:{reason}(请在 DSH 凭据管理里配置 {ref} 后重试)',
|
|
209
|
+
'host.syncKindS3Secret': 'S3 密钥',
|
|
210
|
+
'host.sessionFormatPathSeparator': '、',
|
|
211
|
+
'host.sessionFormatPathsTruncated': '{paths} 等',
|
|
212
|
+
'host.snapshotPruneSummary': '自动保留清理删除 {count} 个旧快照',
|
|
213
|
+
'host.autosyncSummary': '自动同步 {direction}{transportSuffix}',
|
|
214
|
+
'host.autosyncTransportSuffix': '({transport})',
|
|
203
215
|
'host.githubMissingClientId': '未配置 GitHub OAuth client_id:请在插件配置中设置 githubClientId(GitHub → Settings → Developer settings → OAuth Apps 注册应用获取)',
|
|
204
216
|
'host.githubFlowGone': 'GitHub 登录流程不存在或已过期,请重新开始',
|
|
205
217
|
'host.restoreBlobEscape': 'blob 路径越界: {blob}',
|
|
@@ -221,6 +233,9 @@ export const zh = {
|
|
|
221
233
|
'adapter.linksFollowed': '{type} 分区:已跟随 {count} 个链接目录收集内容(导入时按普通目录还原,链接结构不会重建)',
|
|
222
234
|
'adapter.linksSkipped': '{type} 分区:{count} 个链接被跳过,其内容**未进备份** —— {detail}',
|
|
223
235
|
'adapter.dirsUnreadable': '{type} 分区:{count} 个目录读取失败(权限/竞态),其内容**未进备份** —— {detail}',
|
|
236
|
+
'adapter.depsDirsSkipped': '{type} 分区:{count} 个运行时依赖目录(node_modules)未进备份(可由包内 package.json / lock 重建,目标机需重新安装依赖)—— {detail}',
|
|
237
|
+
'adapter.depsDirFiles': '{count} 个文件',
|
|
238
|
+
'adapter.depsDirFilesUnknown': '文件数未统计(超过计数上限)',
|
|
224
239
|
'adapter.fileSectionByteLimit': '{type} 分区累计体积达到单分区上限 {limit}(实际保留 {kept}):{count} 个单元整块未进备份(单元不可拆分,宁可少带不可半带)—— {detail}',
|
|
225
240
|
'adapter.linkReason.loop': '自引用/重复链接',
|
|
226
241
|
'adapter.linkReason.outsideHome': '目标在 DSH home 之外',
|
|
@@ -342,6 +357,7 @@ export const zh = {
|
|
|
342
357
|
'sync.credentialsReadFailed': '读取凭据文件失败,本次快照不含任何凭据值: {reason}',
|
|
343
358
|
'sync.credentialsEmpty': '本机凭据文件为空或无法解析,本次快照不含任何凭据值',
|
|
344
359
|
'sync.credentialsItemDesc': '凭据 {ref} 随加密快照迁移(确认后写入本机凭据存储)',
|
|
360
|
+
'sync.credentialsItemSame': '凭据 {ref} 与本机一致,跳过写入(保留本机值)',
|
|
345
361
|
'sync.credentialsNeedPassword': '快照 {id} 含加密凭据载荷,需要解密密码才能读取',
|
|
346
362
|
'sync.encryptedNeedsPassword': '快照 {id} 已加密,需要解密密码才能读取(自动同步无法解密,请手动同步)',
|
|
347
363
|
'sync.noPortableSections': '没有可同步的 portable 分区(全部导出失败)',
|
|
@@ -373,6 +389,15 @@ export const zh = {
|
|
|
373
389
|
'sync.git.repoUnreachable': '仓库不可达或认证失败: {url}',
|
|
374
390
|
'sync.git.workDirNotRepo': 'workDir 不是 git 仓库(缺少 .git)且目录非空,无法 clone: {dir}',
|
|
375
391
|
'sync.git.pullFailed': 'git pull 失败: {err}',
|
|
392
|
+
// issue #79:主机密钥与「换仓库地址」两类失败此前只透出 git 原始 stderr,用户无从下手
|
|
393
|
+
'sync.git.hostKeyUnverified': 'SSH 主机密钥校验失败:本机 known_hosts 里没有 {host} 的密钥(或密钥已变更),git 因此拒绝连接。请先核对主机指纹,再在本机执行 ssh-keyscan -p <端口> {host} >> ~/.ssh/known_hosts(或直接 ssh {host} 按提示确认)后重试 —— 插件不会自动信任任何主机。',
|
|
394
|
+
'sync.git.hostKeyUnverifiedNoHost': 'SSH 主机密钥校验失败:本机 known_hosts 里没有该主机的密钥(或密钥已变更),git 因此拒绝连接。请先核对主机指纹,再在本机用 ssh-keyscan 把该主机写入 ~/.ssh/known_hosts(或直接 ssh 该主机按提示确认)后重试 —— 插件不会自动信任任何主机。',
|
|
395
|
+
'sync.git.historyDiverged': '本地工作副本 {dir} 与远端不是同一条历史(远端换了仓库,或远端历史被重写):已拒绝合并。请把仓库地址改回原仓库,或在「同步 → 通道配置」里重建工作副本。',
|
|
396
|
+
'sync.workdirModeInvalid': '重建工作副本的模式非法: {mode}(只允许 relink(重指向地址)或 reclone(重新克隆))',
|
|
397
|
+
'sync.workdirRecloneNeedsConfirm': '重新克隆工作副本会丢弃工作副本里尚未推送的本地提交,必须显式确认后再执行(confirm: true)。',
|
|
398
|
+
'sync.workdirNotConfigured': '尚未配置 git 仓库地址,无法重建工作副本。',
|
|
399
|
+
'sync.workdirRelinked': '工作副本的 origin 已重指向当前仓库地址(工作树与本地提交未改动)。',
|
|
400
|
+
'sync.workdirRecloned': '工作副本已重新克隆(原有本地提交已丢弃,远端快照已同步回本地副本)。',
|
|
376
401
|
'sync.git.cmdFailed': 'git {args} 失败 (exit {code}): {err}',
|
|
377
402
|
// 推送认证(真机:公开仓库拉取可匿名成功、推送必失败,git 原文只说「Invalid username or token」)
|
|
378
403
|
'sync.git.pushTokenRequired': '推送需要访问令牌:远端是 http(s) 仓库,但本机没有可用的令牌(拉取公开仓库可以匿名完成,推送必须认证)。请在「同步 → 通道配置」里登录 GitHub 或填入访问令牌后重试。',
|
|
@@ -410,6 +435,37 @@ export const zh = {
|
|
|
410
435
|
'market.zipTooLarge': 'config.zip 体积 {size} 超过上限 {limit} 字节',
|
|
411
436
|
'market.invalid': '条目 {id} 校验未通过: {errors}',
|
|
412
437
|
// ---------- 会话归位(issue #45:跨机恢复后按 cwd 归位到正确 projectKey) ----------
|
|
438
|
+
// ---------- 宿主斜杠命令 /rollback(command-rollback.ts;用户可见文案单一事实源) ----------
|
|
439
|
+
'command.rollback.commandDesc': '列出本会话的回退点;带 id 则回退到该点',
|
|
440
|
+
'command.rollback.commandDescAlias': '/rollback 的别名(等同)',
|
|
441
|
+
'command.rollback.commandInputHint': '[<回退点 id>]',
|
|
442
|
+
'command.rollback.usageInvalid': '用法:/rollback 列出本会话的回退点;/rollback <回退点 id> 回退到该点。({detail})',
|
|
443
|
+
'command.rollback.serviceUnavailable': '命令服务不可用,/rollback 未注册({detail})',
|
|
444
|
+
'command.rollback.registerFailed': '注册命令 /{name} 失败({detail})',
|
|
445
|
+
'command.rollback.sessionUnavailable': '拿不到当前会话,无法回退({detail})',
|
|
446
|
+
'command.rollback.storageUnavailable': '回滚点存储不可用:{detail}',
|
|
447
|
+
'command.rollback.listFailed': '读取回退点失败:{detail}',
|
|
448
|
+
'command.rollback.empty': '本会话还没有回退点:每回合结束会自动留点,先完成一个回合再试。',
|
|
449
|
+
'command.rollback.listTitle': '本会话的回退点:',
|
|
450
|
+
'command.rollback.listRow': '{index}. {id} 回合 {turn} {createdAt} {kind} {state} 可回退性:{restorable}',
|
|
451
|
+
'command.rollback.listSeparator': ';',
|
|
452
|
+
'command.rollback.kindAuto': '自动留点',
|
|
453
|
+
'command.rollback.kindGuard': '救援点',
|
|
454
|
+
'command.rollback.stateNormal': '正常',
|
|
455
|
+
'command.rollback.stateProtected': '已保护(不可回退/不可删除)',
|
|
456
|
+
'command.rollback.stateIncomplete': '不完整(缺态,回退会拒绝)',
|
|
457
|
+
'command.rollback.turnUnknown': '未知',
|
|
458
|
+
'command.rollback.segmentWorkspace': '工作区',
|
|
459
|
+
'command.rollback.segmentSession': '会话',
|
|
460
|
+
'command.rollback.segmentLabel': '{state}({label})',
|
|
461
|
+
'command.rollback.restorableYes': '可回退',
|
|
462
|
+
'command.rollback.restorableNo': '不可回退',
|
|
463
|
+
'command.rollback.restorableSummary': '{parts} ⇒ {verdict}',
|
|
464
|
+
'command.rollback.rewindRestored': '已回退到 {id}。{detail}当前对话不会切换:回退出的新会话在左侧栏(未分组时排在列表末尾),打开它继续聊。',
|
|
465
|
+
'command.rollback.rewindPartial': '回退只完成了一部分(会话段已 fork,工作区段见下)——{id}:{segments}。{detail}',
|
|
466
|
+
'command.rollback.segmentFacts': '段:{facts}',
|
|
467
|
+
'command.rollback.rewindFailed': '回退失败({code}):{id}。{detail}',
|
|
468
|
+
'command.rollback.mutationLocked': '当前不能写({reason}),回退未执行:{id}。请先解除 SAFE MODE 或等其它任务结束。',
|
|
413
469
|
} as const;
|
|
414
470
|
|
|
415
471
|
export const en: Record<keyof typeof zh, string> = {
|
|
@@ -528,6 +584,7 @@ export const en: Record<keyof typeof zh, string> = {
|
|
|
528
584
|
'restore.hostSkipEscape': 'Host file path outside home directory, skipped: {path}',
|
|
529
585
|
'restore.hostSkipEscapeDetail': 'Snapshot-recorded path escapes the home root; restore refused',
|
|
530
586
|
'restore.hostNoBlobInfo': 'Host file {path} has no blob copy, skipped',
|
|
587
|
+
'restore.hostUnreadable': 'Host file {path} existed when the snapshot was taken but could not be read (in use / permissions) — left untouched, please verify by hand',
|
|
531
588
|
'restore.hostBlobMissing': 'Blob for host file {path} is missing, skipped',
|
|
532
589
|
'restore.hostRestore': 'Restore whole file {path}',
|
|
533
590
|
'restore.backupBeforeWrite': 'The current file will be backed up to pre-restore/ first',
|
|
@@ -596,6 +653,14 @@ export const en: Record<keyof typeof zh, string> = {
|
|
|
596
653
|
'host.fsPathEscape': 'Path outside home directory: {path}',
|
|
597
654
|
'host.activationRowFailed': 'Plugin {pkg} is installed, but writing the activation row into the profile patch failed: {reason} (the plugin may be inactive until restart; retrying the install after fixing is idempotent)',
|
|
598
655
|
'host.syncTokenWriteFailed': 'Failed to write the token into DSH credentials: {reason} (configure {ref} in DSH credential management, then retry)',
|
|
656
|
+
'host.syncWebdavPasswordWriteFailed': 'Failed to write the WebDAV password into DSH credentials: {reason} (configure {ref} in DSH credential management, then retry)',
|
|
657
|
+
'host.syncCredentialWriteFailed': 'Failed to write {kind} into DSH credentials: {reason} (configure {ref} in DSH credential management, then retry)',
|
|
658
|
+
'host.syncKindS3Secret': 'the S3 secret',
|
|
659
|
+
'host.sessionFormatPathSeparator': ', ',
|
|
660
|
+
'host.sessionFormatPathsTruncated': '{paths}, among others',
|
|
661
|
+
'host.snapshotPruneSummary': 'Automatic retention cleanup removed {count} old snapshot(s)',
|
|
662
|
+
'host.autosyncSummary': 'Autosync {direction}{transportSuffix}',
|
|
663
|
+
'host.autosyncTransportSuffix': ' ({transport})',
|
|
599
664
|
'host.githubMissingClientId': 'GitHub OAuth client_id is not configured: set githubClientId in the plugin config (GitHub → Settings → Developer settings → OAuth Apps → register an app)',
|
|
600
665
|
'host.githubFlowGone': 'The GitHub sign-in flow does not exist or has expired; please start over',
|
|
601
666
|
'host.restoreBlobEscape': 'Blob path outside snapshot directory: {blob}',
|
|
@@ -617,6 +682,9 @@ export const en: Record<keyof typeof zh, string> = {
|
|
|
617
682
|
'adapter.linksFollowed': '{type}: followed {count} linked directories (restored as plain directories on import; link structure is not recreated)',
|
|
618
683
|
'adapter.linksSkipped': '{type}: {count} links skipped and their content is NOT in this backup — {detail}',
|
|
619
684
|
'adapter.dirsUnreadable': '{type}: {count} director(ies) could not be read (permissions/race) and their content is NOT in this backup — {detail}',
|
|
685
|
+
'adapter.depsDirsSkipped': '{type}: {count} runtime dependency director(ies) (node_modules) NOT in this backup (rebuildable from the bundled package.json / lock; reinstall on the target) — {detail}',
|
|
686
|
+
'adapter.depsDirFiles': '{count} file(s)',
|
|
687
|
+
'adapter.depsDirFilesUnknown': 'file count not measured (over the counting budget)',
|
|
620
688
|
'adapter.fileSectionByteLimit': '{type} section reached the per-section byte limit {limit} ({kept} kept): {count} unit(s) skipped whole and NOT in this backup (units are never split) — {detail}',
|
|
621
689
|
'adapter.linkReason.loop': 'self-referencing/duplicate link',
|
|
622
690
|
'adapter.linkReason.outsideHome': 'target outside the DSH home',
|
|
@@ -738,6 +806,7 @@ export const en: Record<keyof typeof zh, string> = {
|
|
|
738
806
|
'sync.credentialsReadFailed': 'Failed to read the credentials file; this snapshot carries no credential value: {reason}',
|
|
739
807
|
'sync.credentialsEmpty': 'The local credentials file is empty or unparseable; this snapshot carries no credential value',
|
|
740
808
|
'sync.credentialsItemDesc': 'Credential {ref} travels with the encrypted snapshot (written to the local credential store once confirmed)',
|
|
809
|
+
'sync.credentialsItemSame': 'Credential {ref} already matches this machine; write skipped (local value kept)',
|
|
741
810
|
'sync.credentialsNeedPassword': 'Snapshot {id} carries an encrypted credentials payload; a decryption password is required',
|
|
742
811
|
'sync.encryptedNeedsPassword': 'Snapshot {id} is encrypted; a decryption password is required (auto sync cannot decrypt — sync manually)',
|
|
743
812
|
'sync.noPortableSections': 'No portable sections to sync (all exports failed)',
|
|
@@ -769,6 +838,15 @@ export const en: Record<keyof typeof zh, string> = {
|
|
|
769
838
|
'sync.git.repoUnreachable': 'Repository unreachable or authentication failed: {url}',
|
|
770
839
|
'sync.git.workDirNotRepo': 'workDir is not a git repository (no .git) and the directory is not empty; cannot clone: {dir}',
|
|
771
840
|
'sync.git.pullFailed': 'git pull failed: {err}',
|
|
841
|
+
// issue #79: host-key and "repository address changed" failures previously leaked raw git stderr
|
|
842
|
+
'sync.git.hostKeyUnverified': 'SSH host key verification failed: this machine has no key for {host} in known_hosts (or the key changed), so git refused to connect. Verify the host fingerprint first, then run ssh-keyscan -p <port> {host} >> ~/.ssh/known_hosts on this machine (or just ssh {host} and confirm the prompt), then retry — the plugin never trusts a host automatically.',
|
|
843
|
+
'sync.git.hostKeyUnverifiedNoHost': 'SSH host key verification failed: this machine has no key for that host in known_hosts (or the key changed), so git refused to connect. Verify the host fingerprint first, then add the host to ~/.ssh/known_hosts with ssh-keyscan (or just ssh the host and confirm the prompt), then retry — the plugin never trusts a host automatically.',
|
|
844
|
+
'sync.git.historyDiverged': 'The local working copy {dir} and the remote are not the same history (the remote repository was swapped, or its history was rewritten): merging was refused. Point the repository address back to the original repository, or rebuild the working copy in Sync → Channel configuration.',
|
|
845
|
+
'sync.workdirModeInvalid': 'Invalid working-copy rebuild mode: {mode} (only relink (re-point the address) or reclone (clone again) are allowed).',
|
|
846
|
+
'sync.workdirRecloneNeedsConfirm': 'Re-cloning the working copy discards local commits that were never pushed; it requires explicit confirmation (confirm: true).',
|
|
847
|
+
'sync.workdirNotConfigured': 'No git repository address is configured, so the working copy cannot be rebuilt.',
|
|
848
|
+
'sync.workdirRelinked': 'The working copy origin now points at the configured repository address (working tree and local commits untouched).',
|
|
849
|
+
'sync.workdirRecloned': 'The working copy was cloned again (local commits were discarded; remote snapshots are back in the local copy).',
|
|
772
850
|
'sync.git.cmdFailed': 'git {args} failed (exit {code}): {err}',
|
|
773
851
|
'sync.git.pushTokenRequired': 'Push requires an access token, but none is available on this machine (public repositories can be fetched anonymously; pushing always needs authentication). Sign in to GitHub or paste an access token under Sync → Channel configuration, then retry.',
|
|
774
852
|
'sync.git.pushAuthFailed': 'Push authentication failed: {err}. Check that the token is valid and has write access to this repository (password authentication is disabled by the remote); a successful pull does not prove the token works — public repositories can be fetched anonymously. Sign in again or replace the token under Sync → Channel configuration.',
|
|
@@ -805,25 +883,52 @@ export const en: Record<keyof typeof zh, string> = {
|
|
|
805
883
|
'market.zipTooLarge': 'config.zip size {size} exceeds the limit {limit} bytes',
|
|
806
884
|
'market.invalid': 'Item {id} failed verification: {errors}',
|
|
807
885
|
// ---------- session grouping (issue #45: relocate restored sessions by cwd) ----------
|
|
886
|
+
// ---------- host slash command /rollback (command-rollback.ts; single source of user-visible text) ----------
|
|
887
|
+
'command.rollback.commandDesc': 'List this session rollback points; with an id, rewind to that point',
|
|
888
|
+
'command.rollback.commandDescAlias': 'Alias for /rollback (identical)',
|
|
889
|
+
'command.rollback.commandInputHint': '[<rollback point id>]',
|
|
890
|
+
'command.rollback.usageInvalid': 'Usage: /rollback lists this session rollback points; /rollback <rollback point id> rewinds to that point. ({detail})',
|
|
891
|
+
'command.rollback.serviceUnavailable': 'Command service unavailable; /rollback was not registered ({detail})',
|
|
892
|
+
'command.rollback.registerFailed': 'Failed to register command /{name} ({detail})',
|
|
893
|
+
'command.rollback.sessionUnavailable': 'Cannot determine the current session; rewind is unavailable ({detail})',
|
|
894
|
+
'command.rollback.storageUnavailable': 'Rollback point storage is unavailable: {detail}',
|
|
895
|
+
'command.rollback.listFailed': 'Failed to read rollback points: {detail}',
|
|
896
|
+
'command.rollback.empty': 'This session has no rollback point yet: one is captured automatically when a turn ends, so finish a turn first.',
|
|
897
|
+
'command.rollback.listTitle': 'Rollback points of this session:',
|
|
898
|
+
'command.rollback.listRow': '{index}. {id} turn {turn} {createdAt} {kind} {state} restorable: {restorable}',
|
|
899
|
+
'command.rollback.listSeparator': '; ',
|
|
900
|
+
'command.rollback.kindAuto': 'auto',
|
|
901
|
+
'command.rollback.kindGuard': 'rescue guard',
|
|
902
|
+
'command.rollback.stateNormal': 'normal',
|
|
903
|
+
'command.rollback.stateProtected': 'protected (not restorable / not deletable)',
|
|
904
|
+
'command.rollback.stateIncomplete': 'incomplete (missing state; rewind refuses)',
|
|
905
|
+
'command.rollback.turnUnknown': 'unknown',
|
|
906
|
+
'command.rollback.segmentWorkspace': 'workspace',
|
|
907
|
+
'command.rollback.segmentSession': 'session',
|
|
908
|
+
'command.rollback.segmentLabel': '{state} ({label})',
|
|
909
|
+
'command.rollback.restorableYes': 'restorable',
|
|
910
|
+
'command.rollback.restorableNo': 'not restorable',
|
|
911
|
+
'command.rollback.restorableSummary': '{parts} => {verdict}',
|
|
912
|
+
'command.rollback.rewindRestored': 'Rewound to {id}. {detail}This conversation is not switched: the new session is in the left sidebar (at the end of the list when ungrouped) — open it to continue.',
|
|
913
|
+
'command.rollback.rewindPartial': 'The rewind only completed partially (session segment forked; see workspace segment below) - {id}: {segments}. {detail}',
|
|
914
|
+
'command.rollback.segmentFacts': 'segments: {facts}',
|
|
915
|
+
'command.rollback.rewindFailed': 'Rewind failed ({code}): {id}. {detail}',
|
|
916
|
+
'command.rollback.mutationLocked': 'Writing is currently blocked ({reason}); the rewind did not run: {id}. Clear SAFE MODE or wait for the running task to finish.',
|
|
808
917
|
};
|
|
809
918
|
|
|
810
|
-
/**
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
/** 构造 MsgFunc:en → en 目录(缺键回退 zh);其余 → zh。 */
|
|
919
|
+
/**
|
|
920
|
+
* 构造 MsgFunc:en → en 目录(缺键回退 zh);其余 → zh。
|
|
921
|
+
*
|
|
922
|
+
* 查找顺序(自 t2 起):既有目录 → en 语言下回退既有 zh → 注册目录(registerMessageCatalog;
|
|
923
|
+
* **只在既有目录未命中时生效**)→ 键名。既有 372 键的取值逐字不变(engine-locale.test.ts 有冻结指纹)。
|
|
924
|
+
* 插值实现已移入 engine-locale.ts(与 engineMsg 共用同一份,避免两份实现漂移)。
|
|
925
|
+
*/
|
|
820
926
|
export function makeMsg(lang: 'zh' | 'en' | string | undefined): MsgFunc {
|
|
821
|
-
const langKey = lang === 'en' ? 'en' : 'zh'
|
|
822
|
-
const dict = langKey === 'en' ? en : zh
|
|
823
|
-
const fallback = langKey === 'en' ? zh : undefined
|
|
927
|
+
const langKey: 'zh' | 'en' = lang === 'en' ? 'en' : 'zh'
|
|
928
|
+
const dict = (langKey === 'en' ? en : zh) as Readonly<Record<string, string>>
|
|
929
|
+
const fallback = langKey === 'en' ? (zh as Readonly<Record<string, string>>) : undefined
|
|
824
930
|
return (key, params) => {
|
|
825
|
-
|
|
826
|
-
const template = (dict as any)[key] ?? (fallback as any)?.[key] ?? key
|
|
931
|
+
const template = dict[key] ?? fallback?.[key] ?? registeredMessage(langKey, key) ?? key
|
|
827
932
|
return interpolate(template, params)
|
|
828
933
|
}
|
|
829
934
|
}
|
|
@@ -831,6 +936,9 @@ export function makeMsg(lang: 'zh' | 'en' | string | undefined): MsgFunc {
|
|
|
831
936
|
/** 缺省目录(zh):未注入 msg 的引擎/测试路径使用,行为与改造前完全一致。 */
|
|
832
937
|
export const zhMsg: MsgFunc = makeMsg('zh');
|
|
833
938
|
|
|
939
|
+
/** 把基础目录交给引擎语言运行时(engineMsg 用;本模块不反向被 import,避免循环依赖)。 */
|
|
940
|
+
registerBaseMessageCatalog({ zh, en });
|
|
941
|
+
|
|
834
942
|
/** 从「可能携带 msg 的对象」取翻译器;缺省 zh。 */
|
|
835
943
|
export function msgOf(ctx: { msg?: MsgFunc } | undefined): MsgFunc {
|
|
836
944
|
return ctx?.msg ?? zhMsg;
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* 复用现有:computeCompatibility(扩展而非重写)、validateManifest、scanAndRedact、
|
|
21
21
|
* integrity/zip-security、import-wizard 分析管线(宿主填充 migratability)。
|
|
22
22
|
*/
|
|
23
|
+
import { engineMsg } from './messages-core.ts';
|
|
23
24
|
import { computeCompatibility } from './validator.ts';
|
|
24
25
|
import type { CompatibilityScore } from './types.ts';
|
|
25
26
|
import type { Manifest, SectionId } from '../schema/types.ts';
|
|
@@ -212,7 +213,7 @@ export function scoreCompatibility(
|
|
|
212
213
|
if (data.manifest === null) {
|
|
213
214
|
compat = 'unsupported';
|
|
214
215
|
score = 0;
|
|
215
|
-
issues.push({ severity: 'error', code: 'compatibility.noManifest', message: '
|
|
216
|
+
issues.push({ severity: 'error', code: 'compatibility.noManifest', message: engineMsg('core.consult.compatNoManifest') });
|
|
216
217
|
} else {
|
|
217
218
|
compat = computeCompatibility({
|
|
218
219
|
sourceDsh: data.sourceDsh,
|
|
@@ -227,11 +228,11 @@ export function scoreCompatibility(
|
|
|
227
228
|
case 'good': score = 90; break;
|
|
228
229
|
case 'partial':
|
|
229
230
|
score = 60;
|
|
230
|
-
issues.push({ severity: 'warning', code: 'compatibility.partial', message: '
|
|
231
|
+
issues.push({ severity: 'warning', code: 'compatibility.partial', message: engineMsg('core.consult.compatPartial') });
|
|
231
232
|
break;
|
|
232
233
|
case 'unsupported':
|
|
233
234
|
score = 0;
|
|
234
|
-
issues.push({ severity: 'error', code: 'compatibility.unsupported', message: '
|
|
235
|
+
issues.push({ severity: 'error', code: 'compatibility.unsupported', message: engineMsg('core.consult.compatUnsupported') });
|
|
235
236
|
break;
|
|
236
237
|
}
|
|
237
238
|
}
|
|
@@ -244,30 +245,30 @@ export function scoreIntegrity(data: ConsultSourceData): HealthDimension {
|
|
|
244
245
|
let score = 100;
|
|
245
246
|
if (data.manifest === null) {
|
|
246
247
|
score = 0;
|
|
247
|
-
issues.push({ severity: 'error', code: 'integrity.noManifest', message: '
|
|
248
|
+
issues.push({ severity: 'error', code: 'integrity.noManifest', message: engineMsg('core.consult.integrityNoManifest') });
|
|
248
249
|
} else {
|
|
249
250
|
for (const issue of data.manifestIssues) {
|
|
250
251
|
if (issue.severity === 'error') {
|
|
251
252
|
score -= 30;
|
|
252
|
-
issues.push({ severity: 'error', code: 'integrity.manifestInvalid', message:
|
|
253
|
+
issues.push({ severity: 'error', code: 'integrity.manifestInvalid', message: engineMsg('core.consult.manifestInvalid', { message: issue.message }), evidence: issue.path });
|
|
253
254
|
} else {
|
|
254
255
|
score -= 10;
|
|
255
|
-
issues.push({ severity: 'warning', code: 'integrity.manifestWarning', message:
|
|
256
|
+
issues.push({ severity: 'warning', code: 'integrity.manifestWarning', message: engineMsg('core.consult.manifestWarning', { message: issue.message }), evidence: issue.path });
|
|
256
257
|
}
|
|
257
258
|
}
|
|
258
259
|
}
|
|
259
260
|
for (const c of data.checksumIssues) {
|
|
260
261
|
score -= 30;
|
|
261
|
-
issues.push({ severity: 'error', code: 'integrity.checksumMismatch', message:
|
|
262
|
+
issues.push({ severity: 'error', code: 'integrity.checksumMismatch', message: engineMsg('core.consult.checksumMismatch', { reason: c }) });
|
|
262
263
|
}
|
|
263
264
|
// 源无 checksum 表(manifest 存在但 checksums 缺失)→ warning(轻度完整性顾虑)
|
|
264
265
|
if (data.manifest !== null && data.checksums === null) {
|
|
265
266
|
score -= 10;
|
|
266
|
-
issues.push({ severity: 'warning', code: 'integrity.noChecksums', message: '
|
|
267
|
+
issues.push({ severity: 'warning', code: 'integrity.noChecksums', message: engineMsg('core.consult.noChecksums') });
|
|
267
268
|
}
|
|
268
269
|
for (const z of data.zipSlipIssues) {
|
|
269
270
|
score -= 30;
|
|
270
|
-
issues.push({ severity: 'error', code: 'integrity.zipSlip', message:
|
|
271
|
+
issues.push({ severity: 'error', code: 'integrity.zipSlip', message: engineMsg('core.consult.zipSlip', { path: z }) });
|
|
271
272
|
}
|
|
272
273
|
return { id: 'integrity', score: clampScore(score), verdict: dimensionVerdict(issues), issues };
|
|
273
274
|
}
|
|
@@ -278,7 +279,7 @@ export function scoreSections(data: ConsultSourceData): HealthDimension {
|
|
|
278
279
|
let score = 100;
|
|
279
280
|
for (const sid of data.missingSections) {
|
|
280
281
|
score -= 20;
|
|
281
|
-
issues.push({ severity: 'warning', code: 'sections.missing', message:
|
|
282
|
+
issues.push({ severity: 'warning', code: 'sections.missing', message: engineMsg('core.consult.sectionDataMissing', { section: sid }), evidence: sid });
|
|
282
283
|
}
|
|
283
284
|
// 分区数据不可解析(manifest 声明但 sections 中无对应数据且非 missingSections 覆盖)
|
|
284
285
|
if (data.manifest !== null) {
|
|
@@ -287,7 +288,7 @@ export function scoreSections(data: ConsultSourceData): HealthDimension {
|
|
|
287
288
|
if (data.missingSections.includes(sid)) continue;
|
|
288
289
|
if (!data.sections.has(sid)) {
|
|
289
290
|
score -= 30;
|
|
290
|
-
issues.push({ severity: 'error', code: 'sections.unparseable', message:
|
|
291
|
+
issues.push({ severity: 'error', code: 'sections.unparseable', message: engineMsg('core.consult.sectionUnparseable', { section: sid }), evidence: sid });
|
|
291
292
|
}
|
|
292
293
|
}
|
|
293
294
|
}
|
|
@@ -369,12 +370,12 @@ export function scoreConsistency(data: ConsultSourceData): HealthDimension {
|
|
|
369
370
|
const dangling = [...referenced].filter((ref) => !declared.has(ref));
|
|
370
371
|
if (dangling.length > 0) {
|
|
371
372
|
score -= Math.min(dangling.length * 15, 45);
|
|
372
|
-
const shown = dangling.slice(0, 5).join('
|
|
373
|
-
const more = dangling.length > 5 ?
|
|
373
|
+
const shown = dangling.slice(0, 5).join(engineMsg('core.consult.listSeparator'));
|
|
374
|
+
const more = dangling.length > 5 ? engineMsg('core.consult.andMore', { count: dangling.length }) : '';
|
|
374
375
|
issues.push({
|
|
375
376
|
severity: 'warning',
|
|
376
377
|
code: 'consistency.danglingCredentialRef',
|
|
377
|
-
message:
|
|
378
|
+
message: engineMsg('core.consult.danglingCredentialRef', { count: dangling.length, shown, more }),
|
|
378
379
|
evidence: dangling.join(', '),
|
|
379
380
|
});
|
|
380
381
|
}
|
|
@@ -387,7 +388,7 @@ export function scoreSensitive(data: ConsultSourceData): HealthDimension {
|
|
|
387
388
|
let score = 100;
|
|
388
389
|
if (data.containsSecrets && !data.encrypted) {
|
|
389
390
|
score -= 40;
|
|
390
|
-
issues.push({ severity: 'error', code: 'sensitive.unencryptedSecrets', message: '
|
|
391
|
+
issues.push({ severity: 'error', code: 'sensitive.unencryptedSecrets', message: engineMsg('core.consult.unencryptedSecrets') });
|
|
391
392
|
}
|
|
392
393
|
const hitCount = data.sensitiveHits.length;
|
|
393
394
|
if (hitCount > 0) {
|
|
@@ -396,7 +397,7 @@ export function scoreSensitive(data: ConsultSourceData): HealthDimension {
|
|
|
396
397
|
issues.push({
|
|
397
398
|
severity: 'warning',
|
|
398
399
|
code: 'sensitive.hits',
|
|
399
|
-
message:
|
|
400
|
+
message: engineMsg('core.consult.sensitiveHits', { count: hitCount }),
|
|
400
401
|
});
|
|
401
402
|
}
|
|
402
403
|
return { id: 'sensitive', score: clampScore(score), verdict: dimensionVerdict(issues), issues };
|
|
@@ -410,10 +411,10 @@ export function scoreMigratability(data: ConsultSourceData): HealthDimension {
|
|
|
410
411
|
if (m === null) {
|
|
411
412
|
// 未评估可迁移性 = warning 级 → needs-attention(60),与 warning 标签一致(不落到 critical)
|
|
412
413
|
score = 60;
|
|
413
|
-
issues.push({ severity: 'warning', code: 'migratability.notEvaluated', message: '
|
|
414
|
+
issues.push({ severity: 'warning', code: 'migratability.notEvaluated', message: engineMsg('core.consult.migratabilityNotEvaluated') });
|
|
414
415
|
} else if (!m.ok) {
|
|
415
416
|
score = 0;
|
|
416
|
-
issues.push({ severity: 'error', code: 'migratability.failed', message: '
|
|
417
|
+
issues.push({ severity: 'error', code: 'migratability.failed', message: engineMsg('core.consult.migratabilityFailed') });
|
|
417
418
|
for (const e of m.errors) {
|
|
418
419
|
issues.push({ severity: 'error', code: 'migratability.error', message: e });
|
|
419
420
|
}
|
|
@@ -429,7 +430,7 @@ export function scoreMigratability(data: ConsultSourceData): HealthDimension {
|
|
|
429
430
|
issues.push({
|
|
430
431
|
severity: 'warning',
|
|
431
432
|
code: 'migratability.conflicts',
|
|
432
|
-
message:
|
|
433
|
+
message: engineMsg('core.consult.conflicts', { count: m.fatalConflicts }),
|
|
433
434
|
});
|
|
434
435
|
}
|
|
435
436
|
if (m.warnings > 0) {
|
|
@@ -437,7 +438,7 @@ export function scoreMigratability(data: ConsultSourceData): HealthDimension {
|
|
|
437
438
|
issues.push({
|
|
438
439
|
severity: 'warning',
|
|
439
440
|
code: 'migratability.warning',
|
|
440
|
-
message:
|
|
441
|
+
message: engineMsg('core.consult.warnings', { count: m.warnings }),
|
|
441
442
|
});
|
|
442
443
|
}
|
|
443
444
|
}
|
|
@@ -30,6 +30,7 @@ import { atomicWriteFile } from '../utils/atomic-write.ts';
|
|
|
30
30
|
import { maskHighEntropy, redact } from '../security/redaction.ts';
|
|
31
31
|
import { scanAndRedact } from '../security/secret-scanner.ts';
|
|
32
32
|
import { sha256Hex } from '../utils/hashing.ts';
|
|
33
|
+
import { coreText, engineMsg } from './messages-core.ts';
|
|
33
34
|
|
|
34
35
|
// ---------- 常量 ----------
|
|
35
36
|
|
|
@@ -335,7 +336,7 @@ export class MigrationStore {
|
|
|
335
336
|
await this.io.mkdir(this.dir, { recursive: true });
|
|
336
337
|
let guard = 0;
|
|
337
338
|
while (await this.io.exists(target)) {
|
|
338
|
-
if (++guard > 8) return { ok: false, entry, error: '
|
|
339
|
+
if (++guard > 8) return { ok: false, entry, error: engineMsg('core.migrationHistory.filenameCollision') };
|
|
339
340
|
filename = makeHistoryFilename(new Date(at + guard), entry.kind);
|
|
340
341
|
target = path.join(this.dir, filename);
|
|
341
342
|
}
|
|
@@ -420,10 +421,23 @@ export function summarizeHistory(entries: StoredMigrationHistoryEntry[]): Migrat
|
|
|
420
421
|
|
|
421
422
|
/** 导出报告(纯函数)。渲染文本统一过 redact() 兜底(安全不变量)。 */
|
|
422
423
|
export function renderExport(entries: StoredMigrationHistoryEntry[], format: ExportFormat, locale: 'zh' | 'en' = 'zh'): string {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
424
|
+
// 显式 locale 形参(不是全局语言运行时):从本域目录直接取对应语言的文案,语义与改造前逐字一致。
|
|
425
|
+
const T = (key: Parameters<typeof coreText>[1]): string => coreText(locale, key);
|
|
426
|
+
const L = {
|
|
427
|
+
title: T('core.migrationHistory.title'),
|
|
428
|
+
total: T('core.migrationHistory.total'),
|
|
429
|
+
empty: T('core.migrationHistory.empty'),
|
|
430
|
+
kind: T('core.migrationHistory.kind'),
|
|
431
|
+
time: T('core.migrationHistory.time'),
|
|
432
|
+
result: T('core.migrationHistory.result'),
|
|
433
|
+
sections: T('core.migrationHistory.sections'),
|
|
434
|
+
detail: T('core.migrationHistory.detail'),
|
|
435
|
+
};
|
|
436
|
+
const resultLabel = (r: MigrationResult): string => r === 'success'
|
|
437
|
+
? T('core.migrationHistory.resultSuccess')
|
|
438
|
+
: r === 'failed'
|
|
439
|
+
? T('core.migrationHistory.resultFailed')
|
|
440
|
+
: T('core.migrationHistory.resultSkipped');
|
|
427
441
|
|
|
428
442
|
if (format === 'json') {
|
|
429
443
|
const stats = summarizeHistory(entries);
|