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
|
@@ -20,6 +20,7 @@ import type { SelectionSection } from '../../ui/selection-model.ts'
|
|
|
20
20
|
import {
|
|
21
21
|
initialSessionPicks, pickedSessionIds, sessionPickerSelection,
|
|
22
22
|
} from '../../ui/sync-settings-view.ts'
|
|
23
|
+
import type { UiT } from '../../ui/i18n.ts'
|
|
23
24
|
import { DEFAULT_SYNC_SESSIONS_LIMIT, syncSectionGroups } from './sync-view.ts'
|
|
24
25
|
import type { SyncSectionOption } from './sync-view.ts'
|
|
25
26
|
import css from '../config-manager.module.css'
|
|
@@ -30,8 +31,10 @@ import css from '../config-manager.module.css'
|
|
|
30
31
|
* (与导出选择器一致的弹窗语义),因此底部只有「完成」—— 没有「取消」
|
|
31
32
|
* (取消会让用户以为改动被丢弃)。
|
|
32
33
|
*/
|
|
33
|
-
export function SyncSectionPickerDialog({ open, t, cmT, sectionName, catalog, sections, sessionsLimit, sessionsInclude, sessionNode, sessionPending, sessionFailed, onToggleSection, onSessionsLimit, onSessionsInclude, onClose }: {
|
|
34
|
+
export function SyncSectionPickerDialog({ open, t, cmT, uiT, sectionName, catalog, sections, sessionsLimit, sessionsInclude, sessionNode, sessionPending, sessionFailed, onToggleSection, onSessionsLimit, onSessionsInclude, onClose }: {
|
|
34
35
|
t: TranslateNS<'config-manager-sync'>
|
|
36
|
+
/** ui 命名空间的翻译器(UiT):分区描述与分组说明的**字典键**由它解析(英文界面零中文) */
|
|
37
|
+
uiT: UiT
|
|
35
38
|
/** config-manager 命名空间的翻译器:ContentPicker 的搜索/全选/合计文案来自它 */
|
|
36
39
|
cmT: TranslateNS<'config-manager'>
|
|
37
40
|
open: boolean
|
|
@@ -119,7 +122,7 @@ export function SyncSectionPickerDialog({ open, t, cmT, sectionName, catalog, se
|
|
|
119
122
|
/* 分组勾选目录:与「导出备份·自定义模式」同构(分组 Card + 名称/描述/徽章),
|
|
120
123
|
分区名走 section-labels 单一映射 —— 与导出选择器显示**同一个中文名**。 */
|
|
121
124
|
<div className={css.groupList}>
|
|
122
|
-
{syncSectionGroups(catalog).map((g) => (
|
|
125
|
+
{syncSectionGroups(catalog, uiT).map((g) => (
|
|
123
126
|
<Card key={g.group} className={css.groupCard}>
|
|
124
127
|
<div className={css.groupHeader}>
|
|
125
128
|
<span className={css.groupLabel}>{g.label}</span>
|
|
@@ -137,9 +140,15 @@ export function SyncSectionPickerDialog({ open, t, cmT, sectionName, catalog, se
|
|
|
137
140
|
<span className={css.categoryName}>{sectionName(s.id)}</span>
|
|
138
141
|
<span className={css.categoryDesc}>{s.description}</span>
|
|
139
142
|
{s.portability === 'portable' && <Badge kind="info">{t('mode.sectionPortable')}</Badge>}
|
|
143
|
+
{s.portability === 'platformSpecific' && (
|
|
144
|
+
<Badge kind="warn">{t('mode.sectionPlatformSpecific')}</Badge>
|
|
145
|
+
)}
|
|
140
146
|
{s.portability === 'deviceSpecific' && (
|
|
141
147
|
<Badge kind="warn">{t('mode.sectionDeviceSpecific')}</Badge>
|
|
142
148
|
)}
|
|
149
|
+
{/* issue #78:MCP 的机器相关内容(绝对路径 command / cwd、缺运行时)走 ⓘ,
|
|
150
|
+
与「机制说明进 InfoHint」的同一条纪律(见 info-hint-guard)。 */}
|
|
151
|
+
{s.id === 'mcp' && <InfoHint text={t('mode.mcpHint')} label={t('common.infoHint')} />}
|
|
143
152
|
{s.defaultIncluded && <Badge kind="ok">{t('mode.sectionRecommended')}</Badge>}
|
|
144
153
|
</span>
|
|
145
154
|
}
|
|
@@ -60,6 +60,8 @@ test('t42: 组件按职责物理拆分成独立文件(各自导出 + 主文件
|
|
|
60
60
|
['SecurityOptionsCard', 'SecurityOptionsCard.tsx'],
|
|
61
61
|
['DecryptPasswordCard', 'DecryptPasswordCard.tsx'],
|
|
62
62
|
['AutosyncCard', 'AutosyncCard.tsx'],
|
|
63
|
+
// issue #79:工作副本卡(含确认弹窗 + 宿主调用 + 回执)自成文件,主文件只装配 —— 行数棘轮因此不必上调
|
|
64
|
+
['WorkDirCard', 'WorkDirCard.tsx'],
|
|
63
65
|
]
|
|
64
66
|
for (const [name, file] of units) {
|
|
65
67
|
// 主文件:必须 import 并渲染该单元
|
|
@@ -92,7 +94,10 @@ test('t42: 组件按职责物理拆分成独立文件(各自导出 + 主文件
|
|
|
92
94
|
// · 云端点表单 12 个字段进出 state(校验 / 组装 / 就绪判定都已下沉 ui 层,这里是 state 通道);
|
|
93
95
|
// · 多两张通道卡;对话框改为收单个 form 快照后,调用点反而少了几行;
|
|
94
96
|
// · /sync/status → 四通道回填 + 云端点非密字段回填。
|
|
95
|
-
|
|
97
|
+
// 1580 → 1585(t3:英文界面零中文)。增量是**装配接线**:分区选择弹窗新增 uiT 注入
|
|
98
|
+
// (分区描述 / 分组说明改为字典键后,弹窗内需要 ui 字典翻译器才能解析;判定逻辑在 ui 层)。
|
|
99
|
+
// 同一轮把 11 处 toast 的「全角冒号 + 详情」拼接改为 t('common.labelSeparator'),行数不变。
|
|
100
|
+
assert.ok(viewLines <= 1585, '主文件行数必须保持在拆分后的量级(实际 ' + viewLines + ' 行)')
|
|
96
101
|
})
|
|
97
102
|
|
|
98
103
|
test('t42: 通道卡必须是渲染函数(内联组件 = 每次渲染新类型 → 子树重挂、Select 展开态清零)', () => {
|
|
@@ -106,6 +111,20 @@ test('t42: 通道卡必须是渲染函数(内联组件 = 每次渲染新类型
|
|
|
106
111
|
assert.match(viewSource, /\{renderChannelCard\('webdav'\)\}/, 'webdav 通道卡必须经渲染函数调用')
|
|
107
112
|
})
|
|
108
113
|
|
|
114
|
+
test('工作副本「重建」按钮必须在请求在途时转加载态(用户报告:点了没有任何反馈)', () => {
|
|
115
|
+
// 真机用户报告:点「重新克隆工作副本」后整卡没有任何变化,只有结束时才跳出 toast —— reclone 要删目录 +
|
|
116
|
+
// 重新 clone(可达数十秒),期间用户无从判断是否在执行。守卫钉住三条:在途态由本卡自持、两个出口都转
|
|
117
|
+
// 加载态并互相禁用、失败也必须收掉加载态;任一条回退即变红。
|
|
118
|
+
const src = readSource(fileURLToPath(new URL('./WorkDirCard.tsx', import.meta.url)))
|
|
119
|
+
assert.match(src, /const \[pending, setPending\] = useState<'relink' \| 'reclone' \| null>\(null\)/, '在途态必须是本卡自持的 relink/reclone 判别式状态')
|
|
120
|
+
assert.match(src, /loading=\{pending === 'reclone'\}/, '重新克隆按钮必须在自身请求在途时显示加载态')
|
|
121
|
+
assert.match(src, /loading=\{pending === 'relink'\}/, '重指向按钮同理')
|
|
122
|
+
assert.match(src, /disabled=\{busy \|\| pending !== null\}/, '在途时必须同时禁用两个出口(防重复点击)')
|
|
123
|
+
const start = src.indexOf('const reset = async')
|
|
124
|
+
const body = src.slice(start, start + 900)
|
|
125
|
+
assert.match(body, /finally \{[\s\S]*setPending\(null\)/, '失败也必须收掉加载态(否则按钮会永远转圈)')
|
|
126
|
+
})
|
|
127
|
+
|
|
109
128
|
test('t42: 断开 git 通道必须同步复位内存登录态(令牌槽位被删 = 已登出,否则登录入口恒隐藏)', () => {
|
|
110
129
|
// 真机用户报告:点「断开配置」删掉的是 SYNC_CREDENTIAL_REF —— 与 GitHub 登录**同一个槽位**,
|
|
111
130
|
// 但 githubSignedIn 当时不复位,登录块恒隐藏,用户以为要重启 profile 才能重新登录。
|
|
@@ -28,7 +28,7 @@ export function UnreadableSnapshotsBanner({
|
|
|
28
28
|
<Banner kind="warn">
|
|
29
29
|
{t('snapshots.unreadableHint', {
|
|
30
30
|
n: String(items.length),
|
|
31
|
-
files: items.map((u) => baseName(u.file)).join('
|
|
31
|
+
files: items.map((u) => baseName(u.file)).join(t('common.listSeparator')),
|
|
32
32
|
})}
|
|
33
33
|
</Banner>
|
|
34
34
|
)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 工作副本卡(issue #79;t42 物理拆分:渲染段自成文件,主文件只装配)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么需要它:改仓库地址后同步失败时,App 内此前**没有任何自救路径** —— 只能手工
|
|
5
|
+
* `git remote set-url`,或删掉 `<dataDir>/sync/work` 重来。这里给出工作副本的只读事实
|
|
6
|
+
* (路径 / origin / 与配置地址是否一致)与两条出口:
|
|
7
|
+
* - 「重指向仓库地址」= host 的 relink(非破坏性:只改 git 配置,不碰工作树与本地提交);
|
|
8
|
+
* - 「重新克隆工作副本」= host 的 reclone(**丢弃未上行的本地提交**)→ danger 二次确认。
|
|
9
|
+
*
|
|
10
|
+
* 约定(与 ChannelClearConfirmDialog 同族):确认弹窗、宿主调用与终局回执都在本文件内自持,
|
|
11
|
+
* 调用方只传「渲染所需的数据 + 变更通知」;判定在 `src/ui/sync-settings-view.ts`(可测)。
|
|
12
|
+
*/
|
|
13
|
+
import { useState } from 'react'
|
|
14
|
+
import type { TranslateNS } from '../client-types.ts'
|
|
15
|
+
import type { SyncApi, SyncStatusResponse } from './sync-api.ts'
|
|
16
|
+
import { Badge, Button, Card } from '../common/ui.tsx'
|
|
17
|
+
import { InfoHint } from '../common/InfoHint.tsx'
|
|
18
|
+
import { ConfirmDialog } from '../common/ConfirmDialog.tsx'
|
|
19
|
+
import { toast } from '../common/toast-store.ts'
|
|
20
|
+
import { redact } from '../../security/redaction.ts'
|
|
21
|
+
import {
|
|
22
|
+
canRecloneWorkdir, formatSyncUrlPreview, needsWorkdirRelink, workdirStateBadgeKind, workdirStateKey,
|
|
23
|
+
} from '../../ui/sync-settings-view.ts'
|
|
24
|
+
import css from '../config-manager.module.css'
|
|
25
|
+
|
|
26
|
+
export function WorkDirCard({ t, api, workDir, busy, onChanged }: {
|
|
27
|
+
t: TranslateNS<'config-manager-sync'>
|
|
28
|
+
api: SyncApi
|
|
29
|
+
/** GET /sync/status 的 workDir 字段(非 git 通道 / 未配置时 undefined) */
|
|
30
|
+
workDir: SyncStatusResponse['workDir']
|
|
31
|
+
busy: boolean
|
|
32
|
+
/** 重建成功后重拉状态(调用方负责它的状态源) */
|
|
33
|
+
onChanged: () => void
|
|
34
|
+
}) {
|
|
35
|
+
/** 重新克隆的二次确认(破坏性:丢弃未上行的本地提交) */
|
|
36
|
+
const [recloneOpen, setRecloneOpen] = useState(false)
|
|
37
|
+
/** 本次发起的出口(relink / reclone):请求在途时卡片按钮就地转加载态。
|
|
38
|
+
* 为什么必须有:reclone 要删目录 + 重新 clone(真机可达数十秒),此前点了只有 toast 在**结束**时才响,
|
|
39
|
+
* 用户无从判断是否正在执行,容易重复点击或以为没反应。 */
|
|
40
|
+
const [pending, setPending] = useState<'relink' | 'reclone' | null>(null)
|
|
41
|
+
const stateKey = workdirStateKey(workDir)
|
|
42
|
+
const badgeKind = workdirStateBadgeKind(stateKey)
|
|
43
|
+
const facts = workDir !== undefined && 'facts' in workDir ? workDir.facts : null
|
|
44
|
+
|
|
45
|
+
const reset = async (mode: 'relink' | 'reclone'): Promise<void> => {
|
|
46
|
+
setRecloneOpen(false)
|
|
47
|
+
setPending(mode)
|
|
48
|
+
try {
|
|
49
|
+
await api.workdirReset(mode === 'reclone' ? { mode, confirm: true } : { mode })
|
|
50
|
+
toast.ok(t(mode === 'relink' ? 'toast.workdirRelinked' : 'toast.workdirRecloned'))
|
|
51
|
+
onChanged()
|
|
52
|
+
} catch (err) {
|
|
53
|
+
toast.error(t('toast.workdirResetFailed') + t('common.labelSeparator') + redact(err instanceof Error ? err.message : String(err)))
|
|
54
|
+
} finally {
|
|
55
|
+
// 无论成功/失败都要收掉加载态,否则按钮会永远转圈(状态重拉由 onChanged 负责)
|
|
56
|
+
setPending(null)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<Card>
|
|
62
|
+
<span className={css.groupLabel}>{t('workdir.title')} <InfoHint text={t('workdir.hint')} label={t('common.infoHint')} /></span>
|
|
63
|
+
{stateKey !== null && badgeKind !== null && (
|
|
64
|
+
<div className={css.statRow}>
|
|
65
|
+
<Badge kind={badgeKind}>{t(stateKey)}</Badge>
|
|
66
|
+
</div>
|
|
67
|
+
)}
|
|
68
|
+
{workDir === undefined ? (
|
|
69
|
+
<span className={css.categoryDesc}>{t('workdir.unknown')}</span>
|
|
70
|
+
) : (
|
|
71
|
+
<div className={css.factGrid} style={{ marginTop: 8 }}>
|
|
72
|
+
<div className={css.factCell} style={{ gridColumn: '1 / -1' }}>
|
|
73
|
+
<span className={css.factLabel}>{t('workdir.path')}</span>
|
|
74
|
+
<span className={css.factValue}>
|
|
75
|
+
<span className={css.mono}>{formatSyncUrlPreview(facts?.path ?? t('workdir.unknown'))}</span>
|
|
76
|
+
</span>
|
|
77
|
+
</div>
|
|
78
|
+
<div className={css.factCell} style={{ gridColumn: '1 / -1' }}>
|
|
79
|
+
<span className={css.factLabel}>{t('workdir.origin')}</span>
|
|
80
|
+
<span className={css.factValue}>
|
|
81
|
+
<span className={css.mono}>
|
|
82
|
+
{facts === null || facts.origin === null ? t('workdir.unknown') : formatSyncUrlPreview(facts.origin)}
|
|
83
|
+
</span>
|
|
84
|
+
</span>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
)}
|
|
88
|
+
<div className={css.actionRowTop}>
|
|
89
|
+
{needsWorkdirRelink(workDir) && (
|
|
90
|
+
<Button disabled={busy || pending !== null} loading={pending === 'relink'} onClick={() => { void reset('relink') }}>
|
|
91
|
+
{t('workdir.relink')}
|
|
92
|
+
</Button>
|
|
93
|
+
)}
|
|
94
|
+
{canRecloneWorkdir(workDir) && (
|
|
95
|
+
<Button variant="danger" disabled={busy || pending !== null} loading={pending === 'reclone'} onClick={() => { setRecloneOpen(true) }}>
|
|
96
|
+
{t('workdir.reclone')}
|
|
97
|
+
</Button>
|
|
98
|
+
)}
|
|
99
|
+
</div>
|
|
100
|
+
<ConfirmDialog
|
|
101
|
+
open={recloneOpen}
|
|
102
|
+
danger
|
|
103
|
+
title={t('workdir.recloneConfirmTitle')}
|
|
104
|
+
message={t('workdir.recloneConfirmMessage')}
|
|
105
|
+
confirmLabel={t('workdir.recloneConfirm')}
|
|
106
|
+
cancelLabel={t('common.cancel')}
|
|
107
|
+
onConfirm={() => reset('reclone')}
|
|
108
|
+
onCancel={() => { setRecloneOpen(false) }}
|
|
109
|
+
/>
|
|
110
|
+
</Card>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
@@ -14,7 +14,8 @@ import type { SyncHistoryEntry } from './sync-api.ts';
|
|
|
14
14
|
import { en as syncEn, zh as syncZh } from './sync-locales.ts';
|
|
15
15
|
import {
|
|
16
16
|
autosyncBadgeKind, autosyncStatusLabel, describeSkipReason, directionLabel, formatDateTime,
|
|
17
|
-
formatDateTimeFull, midEllipsis, projectAutosyncEntry, projectSyncHistoryEntries,
|
|
17
|
+
formatDateTimeFull, midEllipsis, projectAutosyncEntry, projectSyncHistoryEntries, skipReasonKey,
|
|
18
|
+
summarizeSyncHistory,
|
|
18
19
|
} from './history-model.ts';
|
|
19
20
|
import type { AutosyncHistoryEntry } from './sync-api.ts';
|
|
20
21
|
|
|
@@ -79,17 +80,20 @@ test('directionLabel / autosyncStatusLabel:方向与状态映射(走字典
|
|
|
79
80
|
assert.equal(autosyncStatusLabel('partial', enT), 'Partial');
|
|
80
81
|
});
|
|
81
82
|
|
|
82
|
-
test('describeSkipReason
|
|
83
|
+
test('describeSkipReason:七类已知原因全部走字典(F1 收口:不再有硬编码中文)', () => {
|
|
83
84
|
assert.equal(describeSkipReason('conflict', zhT), syncZh['history.autosyncReasonConflict']);
|
|
84
85
|
assert.equal(describeSkipReason('no-remote', zhT), syncZh['history.autosyncReasonNoRemote']);
|
|
85
86
|
assert.equal(describeSkipReason('not-configured', zhT), syncZh['history.autosyncReasonNotConfigured']);
|
|
86
87
|
assert.equal(describeSkipReason('network', zhT), syncZh['history.autosyncReasonNetwork']);
|
|
87
88
|
assert.equal(describeSkipReason('conflict', enT), syncEn['history.autosyncReasonConflict']);
|
|
88
|
-
// F1
|
|
89
|
-
|
|
90
|
-
assert.equal(describeSkipReason('encrypted',
|
|
89
|
+
// F1 收口(t3):encrypted / mutation-locked / 未知 三类也已补键,en 界面下不再透出中文
|
|
90
|
+
assert.equal(describeSkipReason('encrypted', zhT), syncZh['history.autosyncReasonEncrypted']);
|
|
91
|
+
assert.equal(describeSkipReason('encrypted', enT), syncEn['history.autosyncReasonEncrypted']);
|
|
92
|
+
assert.equal(describeSkipReason('mutation-locked', zhT), syncZh['history.autosyncReasonMutationLocked']);
|
|
93
|
+
assert.equal(describeSkipReason(undefined, zhT), syncZh['history.autosyncReasonUnknown']);
|
|
94
|
+
assert.equal(describeSkipReason(undefined, enT), syncEn['history.autosyncReasonUnknown']);
|
|
95
|
+
// 未知原因仍原样透出宿主回传的串(不吞信息)
|
|
91
96
|
assert.equal(describeSkipReason('weird', zhT), 'weird');
|
|
92
|
-
assert.equal(describeSkipReason(undefined, zhT), '未知');
|
|
93
97
|
});
|
|
94
98
|
|
|
95
99
|
// issue #31:宿主统一以 'mutation-locked' 落历史(不细分 LOCKED/STALE)→ 界面不得透出裸 token。
|
|
@@ -217,16 +221,45 @@ test('client-F1:en 界面下自动同步行的三个标签必须全是英文
|
|
|
217
221
|
assert.equal(row.status, 'Skipped');
|
|
218
222
|
});
|
|
219
223
|
|
|
220
|
-
test('client-F1
|
|
224
|
+
test('client-F1 源码守卫:标签函数体不得含中文字面量;跳过原因一律经 skipReasonKey 取字典键', () => {
|
|
221
225
|
const src = fs.readFileSync(new URL('./history-model.ts', import.meta.url), 'utf8');
|
|
222
|
-
for (const fn of ['directionLabel', 'autosyncStatusLabel']) {
|
|
226
|
+
for (const fn of ['directionLabel', 'autosyncStatusLabel', 'describeSkipReason']) {
|
|
223
227
|
const start = src.indexOf('export function ' + fn);
|
|
224
228
|
assert.ok(start >= 0, fn + ' 必须存在(守卫需同步更新)');
|
|
225
229
|
const end = src.indexOf('\n}', start);
|
|
226
230
|
const body = src.slice(start, end < 0 ? src.length : end);
|
|
227
231
|
assert.doesNotMatch(body, /[\u4e00-\u9fff]/, fn + ' 函数体内不得含中文字面量');
|
|
228
232
|
}
|
|
233
|
+
// issue #79:映射抽到 skipReasonKey(历史行与自动同步状态行共用一份),守卫落点随之挪到它,
|
|
234
|
+
// 但硬约束不变:**文案只许来自字典**,且 describeSkipReason 不得再自带第二份 switch。
|
|
235
|
+
const mapStart = src.indexOf('export function skipReasonKey');
|
|
236
|
+
assert.ok(mapStart >= 0, 'skipReasonKey 必须存在(守卫需同步更新)');
|
|
237
|
+
const mapEnd = src.indexOf('\n}', mapStart);
|
|
238
|
+
const mapBody = src.slice(mapStart, mapEnd < 0 ? src.length : mapEnd);
|
|
229
239
|
for (const key of ['history.autosyncReasonConflict', 'history.autosyncReasonNoRemote', 'history.autosyncReasonNotConfigured', 'history.autosyncReasonNetwork']) {
|
|
230
|
-
assert.ok(
|
|
240
|
+
assert.ok(mapBody.includes("'" + key + "'"), 'skipReasonKey 必须映射字典键 ' + key);
|
|
231
241
|
}
|
|
242
|
+
const reasonStart = src.indexOf('export function describeSkipReason');
|
|
243
|
+
const reasonEnd = src.indexOf('\n}', reasonStart);
|
|
244
|
+
const reasonBody = src.slice(reasonStart, reasonEnd < 0 ? src.length : reasonEnd);
|
|
245
|
+
assert.ok(reasonBody.includes('skipReasonKey('), 'describeSkipReason 必须经 skipReasonKey 取键');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
/* ================================================================ issue #79 */
|
|
249
|
+
|
|
250
|
+
test('issue #79:skipReasonKey —— 新旧码都映射到字典键,未知码返回 null(不猜)', () => {
|
|
251
|
+
assert.equal(skipReasonKey('conflict'), 'history.autosyncReasonConflict');
|
|
252
|
+
assert.equal(skipReasonKey('not-configured'), 'history.autosyncReasonNotConfigured');
|
|
253
|
+
// 宿主同一语义两处命名:历史写 'unconfigured',两处必须同一文案
|
|
254
|
+
assert.equal(skipReasonKey('unconfigured'), 'history.autosyncReasonNotConfigured');
|
|
255
|
+
assert.equal(skipReasonKey('upToDate'), 'history.autosyncReasonUpToDate');
|
|
256
|
+
assert.equal(skipReasonKey('unchanged'), 'history.autosyncReasonUnchanged');
|
|
257
|
+
assert.equal(skipReasonKey('mutation-locked'), 'history.autosyncReasonMutationLocked');
|
|
258
|
+
assert.equal(skipReasonKey('future-code-from-newer-host'), null, '未知码不猜');
|
|
259
|
+
assert.equal(skipReasonKey(undefined), null);
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test('issue #79:describeSkipReason 未知码保留宿主原串(不吞信息)', () => {
|
|
263
|
+
assert.equal(describeSkipReason('brand-new-reason', zhT), 'brand-new-reason');
|
|
264
|
+
assert.equal(describeSkipReason(undefined, zhT), syncZh['history.autosyncReasonUnknown']);
|
|
232
265
|
});
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* + 自动同步 kind=autosync),投影需统一处理两源,并生成自动同步跳过冲突的可读明细。
|
|
7
7
|
*/
|
|
8
8
|
import type { AutosyncHistoryEntry, SyncHistoryEntry } from './sync-api.ts'
|
|
9
|
+
// 跳过原因码 → 字典键的映射键类型(**type-only**:不把 zh/en 目录按值带进本条 import)
|
|
10
|
+
import type { SyncKey } from './sync-locales.ts'
|
|
9
11
|
import type { TranslateNS } from '../client-types.ts'
|
|
10
12
|
|
|
11
13
|
/** 同步命名空间翻译器(本文件的标签一律走它 —— 硬编码中文在英文界面下会原样透出)。 */
|
|
@@ -84,29 +86,42 @@ export function autosyncStatusLabel(status: AutosyncHistoryEntry['status'], t: S
|
|
|
84
86
|
/**
|
|
85
87
|
* 跳过原因 → 可读描述(host 透传语义;未知原因回退原串)。
|
|
86
88
|
*
|
|
87
|
-
* client-F1
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* 补键后这里一并字典化,见 findings.md 的 client-F1 defer 段。
|
|
89
|
+
* client-F1(本次收口):conflict / no-remote / not-configured / network / encrypted /
|
|
90
|
+
* mutation-locked / 未知 **七类全部**走 history.autosyncReason* 字典键 —— 此前后三类是
|
|
91
|
+
* 硬编码中文(sync-locales.ts 当时不可写),英文界面下会原样透出。
|
|
91
92
|
*/
|
|
92
|
-
export function
|
|
93
|
+
export function skipReasonKey(reason: string | undefined): SyncKey | null {
|
|
93
94
|
switch (reason) {
|
|
94
|
-
case 'conflict': return
|
|
95
|
-
case 'no-remote': return
|
|
96
|
-
case 'not-configured':
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
case '
|
|
95
|
+
case 'conflict': return 'history.autosyncReasonConflict';
|
|
96
|
+
case 'no-remote': return 'history.autosyncReasonNoRemote';
|
|
97
|
+
case 'not-configured':
|
|
98
|
+
// issue #79:宿主同一语义两处命名(历史写 'unconfigured',旧口径是 'not-configured')→ 同一文案
|
|
99
|
+
case 'unconfigured': return 'history.autosyncReasonNotConfigured';
|
|
100
|
+
case 'network': return 'history.autosyncReasonNetwork';
|
|
101
|
+
case 'encrypted': return 'history.autosyncReasonEncrypted';
|
|
102
|
+
// issue #79:状态行新增两类(无变化 / 已是最新)——此前会落到 default 渲染裸码
|
|
103
|
+
case 'upToDate': return 'history.autosyncReasonUpToDate';
|
|
104
|
+
case 'unchanged': return 'history.autosyncReasonUnchanged';
|
|
100
105
|
// issue #31:宿主侧的分类锁判定(LOCKED/STALE/UNKNOWN)统一以 'mutation-locked' 落历史,
|
|
101
106
|
// 客户端拿不到细分 reason → 文案必须同时覆盖「活锁占用」与「残留锁需回收」两种可能,
|
|
102
107
|
// 并给出可操作方向(否则界面只显示裸 token,用户无从判断要不要处理)。
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
default: return reason ?? '未知';
|
|
108
|
+
case 'mutation-locked': return 'history.autosyncReasonMutationLocked';
|
|
109
|
+
// 未知原因:没有字典键(调用方决定回退策略)
|
|
110
|
+
default: return null;
|
|
107
111
|
}
|
|
108
112
|
}
|
|
109
113
|
|
|
114
|
+
/**
|
|
115
|
+
* 跳过原因码 → 可读描述(历史行与自动同步状态行**共用同一份映射**)。
|
|
116
|
+
*
|
|
117
|
+
* 参数取「码 → 文案」的最小取词器(只要吃 SyncKey 即可),这样 UiT / 组件 t / 活目录
|
|
118
|
+
* 三种取词器都能直接传入,不必为了类型对齐再造一个包装。
|
|
119
|
+
*/
|
|
120
|
+
export function describeSkipReason(reason: string | undefined, t: (key: SyncKey) => string): string {
|
|
121
|
+
const key = skipReasonKey(reason);
|
|
122
|
+
return key === null ? (reason ?? t('history.autosyncReasonUnknown')) : t(key);
|
|
123
|
+
}
|
|
124
|
+
|
|
110
125
|
/** 把一条自动同步记录投影为展示行(摘要文本 + 可展开的被跳过冲突分区明细)。 */
|
|
111
126
|
export interface AutosyncHistoryRow {
|
|
112
127
|
id: string;
|