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
|
@@ -7,6 +7,7 @@ import assert from 'node:assert/strict';
|
|
|
7
7
|
|
|
8
8
|
import { ConfigManagerApiError } from '../api.ts';
|
|
9
9
|
import { SYNC_API, SYNC_WEBDAV_CREDENTIAL_REF, SyncApi } from './sync-api.ts';
|
|
10
|
+
import { zhUiT } from '../../ui/i18n.ts';
|
|
10
11
|
|
|
11
12
|
interface FetchCall {
|
|
12
13
|
url: string;
|
|
@@ -57,7 +58,7 @@ test('S-01 api.status():GET 到 /sync/status,解析配置/凭据/上次同
|
|
|
57
58
|
// 经读取函数解除闭包赋值导致的 CFA 窄化(called 在回调内赋值,外部保持 null 窄化)
|
|
58
59
|
const lastCall = (): FetchCall | null => called;
|
|
59
60
|
|
|
60
|
-
const api = new SyncApi();
|
|
61
|
+
const api = new SyncApi(zhUiT);
|
|
61
62
|
const result = await api.status();
|
|
62
63
|
assert.equal(result.configured, true);
|
|
63
64
|
assert.equal(result.repoUrl, 'https://github.com/u/r.git');
|
|
@@ -73,7 +74,7 @@ test('S-02 api.push():POST /sync/push,请求体携带 repoUrl/token', async
|
|
|
73
74
|
return jsonResponse(200, { ok: true, snapshotId: 'sync-1', sections: ['settings'], warnings: [] });
|
|
74
75
|
});
|
|
75
76
|
|
|
76
|
-
const api = new SyncApi();
|
|
77
|
+
const api = new SyncApi(zhUiT);
|
|
77
78
|
const result = await api.push({ repoUrl: 'https://github.com/u/r.git', token: 'ghp_secret' });
|
|
78
79
|
assert.equal(result.ok, true);
|
|
79
80
|
assert.equal(result.snapshotId, 'sync-1');
|
|
@@ -97,7 +98,7 @@ test('S-03 api.pull():POST /sync/pull,strategy 缺省透传 merge,响应
|
|
|
97
98
|
});
|
|
98
99
|
});
|
|
99
100
|
|
|
100
|
-
const api = new SyncApi();
|
|
101
|
+
const api = new SyncApi(zhUiT);
|
|
101
102
|
const result = await api.pull({ repoUrl: 'https://github.com/u/r.git', strategy: 'merge' });
|
|
102
103
|
assert.equal(result.changes.length, 1);
|
|
103
104
|
assert.equal(result.changes[0]?.kind, 'Conflict');
|
|
@@ -109,7 +110,7 @@ test('S-03 api.pull():POST /sync/pull,strategy 缺省透传 merge,响应
|
|
|
109
110
|
|
|
110
111
|
test('S-04 错误映射:4xx 携带 error → ConfigManagerApiError', async () => {
|
|
111
112
|
installFetchMock(() => jsonResponse(400, { error: 'repoUrl is required' }));
|
|
112
|
-
const api = new SyncApi();
|
|
113
|
+
const api = new SyncApi(zhUiT);
|
|
113
114
|
await assert.rejects(api.push({ repoUrl: '' }), (err: unknown) => {
|
|
114
115
|
assert.ok(err instanceof ConfigManagerApiError);
|
|
115
116
|
assert.match(err.message, /repoUrl is required/);
|
|
@@ -120,7 +121,7 @@ test('S-04 错误映射:4xx 携带 error → ConfigManagerApiError', async ()
|
|
|
120
121
|
test('S-05 服务未挂载:404(非 JSON 体)→ ConfigManagerApiError 提示插件未加载', async () => {
|
|
121
122
|
// 路由不存在时宿主返回 404 但无 JSON error → readJson 兜底为「插件未挂载」提示
|
|
122
123
|
installFetchMock(() => new Response('Not Found', { status: 404 }));
|
|
123
|
-
const api = new SyncApi();
|
|
124
|
+
const api = new SyncApi(zhUiT);
|
|
124
125
|
await assert.rejects(api.status(), (err: unknown) => {
|
|
125
126
|
assert.ok(err instanceof ConfigManagerApiError);
|
|
126
127
|
assert.match(err.message, /未挂载/);
|
|
@@ -141,7 +142,7 @@ test('S-06 api.githubStart():POST /sync/github/start,解析 flowId/userCode/
|
|
|
141
142
|
return jsonResponse(200, body);
|
|
142
143
|
});
|
|
143
144
|
|
|
144
|
-
const api = new SyncApi();
|
|
145
|
+
const api = new SyncApi(zhUiT);
|
|
145
146
|
const result = await api.githubStart();
|
|
146
147
|
assert.equal(result.flowId, 'flow-1');
|
|
147
148
|
assert.equal(result.userCode, 'ABCD-EFGH');
|
|
@@ -157,7 +158,7 @@ test('S-07 api.githubPoll():POST /sync/github/poll 携带 flowId;pending 透
|
|
|
157
158
|
return jsonResponse(200, { status: 'pending', pollDelayMs: 5000 });
|
|
158
159
|
});
|
|
159
160
|
|
|
160
|
-
const api = new SyncApi();
|
|
161
|
+
const api = new SyncApi(zhUiT);
|
|
161
162
|
const result = await api.githubPoll('flow-1');
|
|
162
163
|
assert.equal(result.status, 'pending');
|
|
163
164
|
assert.equal(result.pollDelayMs, 5000);
|
|
@@ -168,7 +169,7 @@ test('S-07 api.githubPoll():POST /sync/github/poll 携带 flowId;pending 透
|
|
|
168
169
|
|
|
169
170
|
test('S-08 api.githubPoll() 成功 → 响应只含状态,token 永不回传', async () => {
|
|
170
171
|
installFetchMock(() => jsonResponse(200, { status: 'success', credentialConfigured: true }));
|
|
171
|
-
const api = new SyncApi();
|
|
172
|
+
const api = new SyncApi(zhUiT);
|
|
172
173
|
const result = await api.githubPoll('flow-1');
|
|
173
174
|
assert.equal(result.status, 'success');
|
|
174
175
|
assert.equal(result.credentialConfigured, true);
|
|
@@ -182,7 +183,7 @@ test('S-09 api.githubCancel():POST /sync/github/cancel 携带 flowId', async (
|
|
|
182
183
|
calls.push(call);
|
|
183
184
|
return jsonResponse(200, { ok: true });
|
|
184
185
|
});
|
|
185
|
-
const api = new SyncApi();
|
|
186
|
+
const api = new SyncApi(zhUiT);
|
|
186
187
|
const result = await api.githubCancel('flow-1');
|
|
187
188
|
assert.equal(result.ok, true);
|
|
188
189
|
assert.equal(calls[0]?.url, SYNC_API.githubCancel);
|
|
@@ -206,7 +207,7 @@ test('S-10 api.snapshotsList():POST /sync/snapshots-list,解析倒序快照
|
|
|
206
207
|
calls.push(call);
|
|
207
208
|
return jsonResponse(200, body);
|
|
208
209
|
});
|
|
209
|
-
const api = new SyncApi();
|
|
210
|
+
const api = new SyncApi(zhUiT);
|
|
210
211
|
const result = await api.snapshotsList({ repoUrl: 'https://github.com/u/r.git' });
|
|
211
212
|
assert.equal(result.ok, true);
|
|
212
213
|
assert.equal(result.snapshots.length, 2);
|
|
@@ -230,7 +231,7 @@ test('S-11 api.sync():POST /sync/sync,请求体携带 snapshotId;响应含
|
|
|
230
231
|
calls.push(call);
|
|
231
232
|
return jsonResponse(200, body);
|
|
232
233
|
});
|
|
233
|
-
const api = new SyncApi();
|
|
234
|
+
const api = new SyncApi(zhUiT);
|
|
234
235
|
const result = await api.sync({ repoUrl: 'https://github.com/u/r.git', snapshotId: 'sync-3' });
|
|
235
236
|
assert.equal(result.syncSessionId, 'sess-1');
|
|
236
237
|
assert.equal(result.items.length, 1);
|
|
@@ -250,7 +251,7 @@ test('S-12 api.applyItems():POST /sync/apply-items,携带 adoptions(含 Co
|
|
|
250
251
|
calls.push(call);
|
|
251
252
|
return jsonResponse(200, body);
|
|
252
253
|
});
|
|
253
|
-
const api = new SyncApi();
|
|
254
|
+
const api = new SyncApi(zhUiT);
|
|
254
255
|
const result = await api.applyItems({
|
|
255
256
|
syncSessionId: 'sess-1',
|
|
256
257
|
adoptions: [
|
|
@@ -273,7 +274,7 @@ test('S-13 api.cancel():POST /sync/cancel 携带 syncSessionId', async () => {
|
|
|
273
274
|
calls.push(call);
|
|
274
275
|
return jsonResponse(200, { ok: true });
|
|
275
276
|
});
|
|
276
|
-
const api = new SyncApi();
|
|
277
|
+
const api = new SyncApi(zhUiT);
|
|
277
278
|
const result = await api.cancel('sess-1');
|
|
278
279
|
assert.equal(result.ok, true);
|
|
279
280
|
assert.equal(calls[0]?.url, SYNC_API.cancel);
|
|
@@ -297,7 +298,7 @@ test('S-14 api.autosyncStatus():GET /sync/autosync 返回 { git, webdav },
|
|
|
297
298
|
return jsonResponse(200, body);
|
|
298
299
|
});
|
|
299
300
|
const lastCall = (): FetchCall | null => called;
|
|
300
|
-
const api = new SyncApi();
|
|
301
|
+
const api = new SyncApi(zhUiT);
|
|
301
302
|
const result = await api.autosyncStatus('git');
|
|
302
303
|
assert.equal(result.enabled, true);
|
|
303
304
|
assert.equal(result.interval, '30m');
|
|
@@ -319,7 +320,7 @@ test('S-15 api.autosyncUpdate():POST /sync/autosync,请求体携带 transpor
|
|
|
319
320
|
calls.push(call);
|
|
320
321
|
return jsonResponse(200, body);
|
|
321
322
|
});
|
|
322
|
-
const api = new SyncApi();
|
|
323
|
+
const api = new SyncApi(zhUiT);
|
|
323
324
|
const result = await api.autosyncUpdate({ transport: 'webdav', enabled: true, interval: '60m' });
|
|
324
325
|
assert.equal(result.enabled, true);
|
|
325
326
|
assert.equal(result.interval, '60m');
|
|
@@ -345,7 +346,7 @@ test('S-16 api.history():GET /sync/history,解析 { entries }(含 autosync
|
|
|
345
346
|
],
|
|
346
347
|
};
|
|
347
348
|
installFetchMock(() => jsonResponse(200, body));
|
|
348
|
-
const api = new SyncApi();
|
|
349
|
+
const api = new SyncApi(zhUiT);
|
|
349
350
|
const result = await api.history();
|
|
350
351
|
assert.equal(result.entries.length, 2);
|
|
351
352
|
assert.equal(result.entries[0]?.kind, 'apply');
|
|
@@ -374,7 +375,7 @@ test('S-18 api.status():webdav 通道 → 解析 webdav 配置状态(url/use
|
|
|
374
375
|
return jsonResponse(200, body);
|
|
375
376
|
});
|
|
376
377
|
const lastCall = (): FetchCall | null => called;
|
|
377
|
-
const api = new SyncApi();
|
|
378
|
+
const api = new SyncApi(zhUiT);
|
|
378
379
|
const result = await api.status();
|
|
379
380
|
assert.equal(result.webdav?.url, 'https://dav.example.com/dav/config');
|
|
380
381
|
assert.equal(result.webdav?.username, 'alice', 'status 可回传 username 值(非敏感,供表单回填)');
|
|
@@ -390,7 +391,7 @@ test('S-19 api.push():transport=webdav → 请求体携带顶层扁平 url/use
|
|
|
390
391
|
calls.push(call);
|
|
391
392
|
return jsonResponse(200, { ok: true, snapshotId: 'sync-w1', sections: [], warnings: [] });
|
|
392
393
|
});
|
|
393
|
-
const api = new SyncApi();
|
|
394
|
+
const api = new SyncApi(zhUiT);
|
|
394
395
|
const result = await api.push({
|
|
395
396
|
transport: 'webdav',
|
|
396
397
|
url: 'https://dav.example.com/dav/config', username: 'alice', password: 'secret-pass',
|
|
@@ -413,7 +414,7 @@ test('S-20 api.pull():transport=webdav 请求体透传扁平 webdav 配置', a
|
|
|
413
414
|
calls.push(call);
|
|
414
415
|
return jsonResponse(200, { ok: true, snapshotId: 'sync-w1', changes: [], needsReview: false });
|
|
415
416
|
});
|
|
416
|
-
const api = new SyncApi();
|
|
417
|
+
const api = new SyncApi(zhUiT);
|
|
417
418
|
await api.pull({ transport: 'webdav', url: 'https://dav.example.com/dav/config', username: 'alice', password: 'secret-pass' });
|
|
418
419
|
assert.equal(calls[0]?.url, SYNC_API.pull);
|
|
419
420
|
const sent = JSON.parse(String(calls[0]?.init?.body ?? '{}')) as Record<string, unknown>;
|
|
@@ -428,7 +429,7 @@ test('S-21 git 通道缺省:不带 transport → 请求体仍只含 git 字段
|
|
|
428
429
|
calls.push(call);
|
|
429
430
|
return jsonResponse(200, { ok: true, snapshotId: 'sync-1', sections: [], warnings: [] });
|
|
430
431
|
});
|
|
431
|
-
const api = new SyncApi();
|
|
432
|
+
const api = new SyncApi(zhUiT);
|
|
432
433
|
await api.push({ repoUrl: 'https://github.com/u/r.git', token: 't' });
|
|
433
434
|
const sent = JSON.parse(String(calls[0]?.init?.body ?? '{}')) as Record<string, unknown>;
|
|
434
435
|
assert.equal(sent['transport'], undefined, '缺省不声明 transport(Host 视为 git)');
|
|
@@ -442,7 +443,7 @@ test('S-22 api.push():高级(自定义导出)模式 → 请求体携带 se
|
|
|
442
443
|
calls.push(call);
|
|
443
444
|
return jsonResponse(200, { ok: true, snapshotId: 'sync-sel', sections: ['settings'], warnings: [] });
|
|
444
445
|
});
|
|
445
|
-
const api = new SyncApi();
|
|
446
|
+
const api = new SyncApi(zhUiT);
|
|
446
447
|
// 高级模式:传勾选分区
|
|
447
448
|
await api.push({ repoUrl: 'https://github.com/u/r.git', sections: ['settings', 'skills'] });
|
|
448
449
|
assert.equal(calls.length, 1);
|
|
@@ -474,7 +475,7 @@ test('S-23 api.status():解析 syncSections(可同步分区目录,无 secr
|
|
|
474
475
|
return jsonResponse(200, body);
|
|
475
476
|
});
|
|
476
477
|
const lastCall = (): FetchCall | null => called;
|
|
477
|
-
const api = new SyncApi();
|
|
478
|
+
const api = new SyncApi(zhUiT);
|
|
478
479
|
const result = await api.status();
|
|
479
480
|
assert.equal(result.syncSections?.length, 2);
|
|
480
481
|
assert.equal(result.syncSections?.[0]?.id, 'settings');
|
|
@@ -493,7 +494,7 @@ test('S-24 api.status():解析 syncSelection(持久化分区选择,UI 回
|
|
|
493
494
|
return jsonResponse(200, body);
|
|
494
495
|
});
|
|
495
496
|
const lastCall = (): FetchCall | null => called;
|
|
496
|
-
const api = new SyncApi();
|
|
497
|
+
const api = new SyncApi(zhUiT);
|
|
497
498
|
const result = await api.status();
|
|
498
499
|
assert.equal(result.syncSelection?.mode, 'advanced');
|
|
499
500
|
assert.deepEqual(result.syncSelection?.sections, ['settings', 'skills']);
|
|
@@ -506,7 +507,7 @@ test('S-25 api.saveSelection():POST /sync/selection 携带 transport + mode +
|
|
|
506
507
|
calls.push(call);
|
|
507
508
|
return jsonResponse(200, { ok: true, transport: 'webdav', mode: 'advanced', sections: ['settings', 'skills'] });
|
|
508
509
|
});
|
|
509
|
-
const api = new SyncApi();
|
|
510
|
+
const api = new SyncApi(zhUiT);
|
|
510
511
|
const result = await api.saveSelection({ transport: 'webdav', mode: 'advanced', sections: ['settings', 'skills'] });
|
|
511
512
|
assert.equal(result.mode, 'advanced');
|
|
512
513
|
assert.equal(calls.length, 1);
|
|
@@ -524,7 +525,7 @@ test('S-26 api.push():加密快照 → 请求体携带 encrypt/encryptPassword
|
|
|
524
525
|
calls.push(call);
|
|
525
526
|
return jsonResponse(200, { ok: true, snapshotId: 'sync-enc', sections: ['settings'], warnings: [] });
|
|
526
527
|
});
|
|
527
|
-
const api = new SyncApi();
|
|
528
|
+
const api = new SyncApi(zhUiT);
|
|
528
529
|
await api.push({
|
|
529
530
|
repoUrl: 'https://github.com/u/r.git',
|
|
530
531
|
encrypt: true,
|
|
@@ -544,7 +545,7 @@ test('S-27 api.pull():拉取加密快照 → 请求体携带 decryptPassword
|
|
|
544
545
|
calls.push(call);
|
|
545
546
|
return jsonResponse(200, { ok: true, snapshotId: 'sync-enc', changes: [], needsReview: false });
|
|
546
547
|
});
|
|
547
|
-
const api = new SyncApi();
|
|
548
|
+
const api = new SyncApi(zhUiT);
|
|
548
549
|
await api.pull({ repoUrl: 'https://github.com/u/r.git', decryptPassword: 'pw-12345678' });
|
|
549
550
|
assert.equal(calls[0]?.url, SYNC_API.pull);
|
|
550
551
|
const sent = JSON.parse(String(calls[0]?.init?.body ?? '{}')) as Record<string, unknown>;
|
|
@@ -557,7 +558,7 @@ test('S-28 api.status():syncSelection 含 encrypt/includeSecrets 开关(UI
|
|
|
557
558
|
syncSelection: { mode: 'advanced', sections: ['settings'], encrypt: true, includeSecrets: true },
|
|
558
559
|
};
|
|
559
560
|
installFetchMock(() => jsonResponse(200, body));
|
|
560
|
-
const api = new SyncApi();
|
|
561
|
+
const api = new SyncApi(zhUiT);
|
|
561
562
|
const result = await api.status();
|
|
562
563
|
assert.equal(result.syncSelection?.encrypt, true);
|
|
563
564
|
assert.equal(result.syncSelection?.includeSecrets, true);
|
|
@@ -576,7 +577,7 @@ test('S-28b api.status():syncSelectionByChannel / autosyncByChannel 按通道
|
|
|
576
577
|
},
|
|
577
578
|
};
|
|
578
579
|
installFetchMock(() => jsonResponse(200, body));
|
|
579
|
-
const api = new SyncApi();
|
|
580
|
+
const api = new SyncApi(zhUiT);
|
|
580
581
|
const result = await api.status();
|
|
581
582
|
assert.equal(result.syncSelectionByChannel?.git.mode, 'default', 'git 通道选择独立');
|
|
582
583
|
assert.equal(result.syncSelectionByChannel?.webdav.mode, 'advanced');
|
|
@@ -592,7 +593,7 @@ test('S-29 api.saveUiPrefs():POST /sync/ui-prefs 携带 lastSyncChannel(磁
|
|
|
592
593
|
calls.push(call);
|
|
593
594
|
return jsonResponse(200, { ok: true, lastSyncChannel: 'webdav' });
|
|
594
595
|
});
|
|
595
|
-
const api = new SyncApi();
|
|
596
|
+
const api = new SyncApi(zhUiT);
|
|
596
597
|
const result = await api.saveUiPrefs({ lastSyncChannel: 'webdav' });
|
|
597
598
|
assert.equal(result.lastSyncChannel, 'webdav');
|
|
598
599
|
assert.equal(calls.length, 1);
|
|
@@ -608,7 +609,7 @@ test('S-30 api.status():lastSyncChannel 回填(磁盘 ui-prefs;UI 通道
|
|
|
608
609
|
lastSyncChannel: 'webdav',
|
|
609
610
|
};
|
|
610
611
|
installFetchMock(() => jsonResponse(200, body));
|
|
611
|
-
const api = new SyncApi();
|
|
612
|
+
const api = new SyncApi(zhUiT);
|
|
612
613
|
const result = await api.status();
|
|
613
614
|
assert.equal(result.lastSyncChannel, 'webdav');
|
|
614
615
|
});
|
|
@@ -619,7 +620,7 @@ test('S-31 api.githubListRepositories():GET 列举仓库(不设 method,只
|
|
|
619
620
|
calls.push(call)
|
|
620
621
|
return jsonResponse(200, { ok: true, repos: [REPO_SUMMARY] })
|
|
621
622
|
})
|
|
622
|
-
const api = new SyncApi()
|
|
623
|
+
const api = new SyncApi(zhUiT)
|
|
623
624
|
const result = await api.githubListRepositories()
|
|
624
625
|
assert.equal(calls.length, 1)
|
|
625
626
|
assert.equal(calls[0]?.url, SYNC_API.githubRepositories)
|
|
@@ -634,7 +635,7 @@ test('S-32 api.githubCreateRepository():POST 新建仓库,请求体不含 pr
|
|
|
634
635
|
calls.push(call)
|
|
635
636
|
return jsonResponse(200, { ok: true, repo: REPO_SUMMARY })
|
|
636
637
|
})
|
|
637
|
-
const api = new SyncApi()
|
|
638
|
+
const api = new SyncApi(zhUiT)
|
|
638
639
|
const result = await api.githubCreateRepository(' dsh-configs ', ' 我的配置 ')
|
|
639
640
|
assert.equal(calls[0]?.url, SYNC_API.githubRepositories)
|
|
640
641
|
assert.equal(calls[0]?.init?.method, 'POST')
|
|
@@ -651,8 +652,31 @@ test('S-33 api.githubCreateRepository():描述为空时不发送 description
|
|
|
651
652
|
calls.push(call)
|
|
652
653
|
return jsonResponse(200, { ok: true, repo: REPO_SUMMARY })
|
|
653
654
|
})
|
|
654
|
-
const api = new SyncApi()
|
|
655
|
+
const api = new SyncApi(zhUiT)
|
|
655
656
|
await api.githubCreateRepository('dsh-configs', ' ')
|
|
656
657
|
const sent = JSON.parse(String(calls[0]?.init?.body ?? '{}')) as Record<string, unknown>
|
|
657
658
|
assert.ok(!('description' in sent), '空描述不占字段(与 GitHub 默认描述口径一致)')
|
|
658
659
|
});
|
|
660
|
+
|
|
661
|
+
test('S-34 api.rollback():POST /sync/rollback 透传 full=false 与 failed(未回滚项 + 人工提示)', async () => {
|
|
662
|
+
const body = {
|
|
663
|
+
ok: true,
|
|
664
|
+
full: false,
|
|
665
|
+
failed: [{ item: 'credentialsStatus:DEEPSEEK_API_KEY', reason: 'DSH 不回读凭据值,无法自动恢复', manualHint: '请重新补录该凭据' }],
|
|
666
|
+
}
|
|
667
|
+
const calls: FetchCall[] = []
|
|
668
|
+
installFetchMock((call) => {
|
|
669
|
+
calls.push(call)
|
|
670
|
+
return jsonResponse(200, body)
|
|
671
|
+
})
|
|
672
|
+
const api = new SyncApi(zhUiT)
|
|
673
|
+
const result = await api.rollback({ restoreId: 'rest-9' })
|
|
674
|
+
assert.equal(result.full, false)
|
|
675
|
+
assert.equal(result.failed?.length, 1, '未回滚项必须透传(旧实现只回 ok/full,界面据此误报「已回滚」)')
|
|
676
|
+
assert.equal(result.failed?.[0]?.item, 'credentialsStatus:DEEPSEEK_API_KEY')
|
|
677
|
+
assert.equal(result.failed?.[0]?.manualHint, '请重新补录该凭据')
|
|
678
|
+
assert.equal(calls[0]?.url, SYNC_API.rollback)
|
|
679
|
+
assert.equal(calls[0]?.init?.method, 'POST')
|
|
680
|
+
const sent = JSON.parse(String(calls[0]?.init?.body ?? '{}')) as Record<string, unknown>
|
|
681
|
+
assert.equal(sent['restoreId'], 'rest-9')
|
|
682
|
+
});
|
|
@@ -37,7 +37,7 @@ import type { ConsultReport } from '../../core/migration-consult.ts';
|
|
|
37
37
|
import { getJson, LONG_REQUEST_TIMEOUT_MS, postJson, type RequestOptions } from '../common/http.ts';
|
|
38
38
|
import { CONFIG_MANAGER_API, SYNC_API } from '../common/routes.ts';
|
|
39
39
|
import type { ExportPreviewResponse } from '../api.ts';
|
|
40
|
-
import {
|
|
40
|
+
import type { UiT } from '../../ui/i18n.ts';
|
|
41
41
|
import { repoCreateBody } from '../../ui/sync-repository-picker.ts';
|
|
42
42
|
|
|
43
43
|
/** 同步端点常量:**唯一来源** = `common/routes.ts`(W4 单点化),此处重导出保持既有导入面。 */
|
|
@@ -97,6 +97,30 @@ export interface SyncStatusResponse {
|
|
|
97
97
|
autosync?: AutosyncStatusResponse;
|
|
98
98
|
/** 全部通道的自动同步状态(git/webdav 各自独立;UI 按当前 tab 取对应通道) */
|
|
99
99
|
autosyncByChannel?: Record<SyncTransportType, AutosyncStatusResponse>;
|
|
100
|
+
/**
|
|
101
|
+
* issue #79:git 工作副本与配置地址的关系(host 只读自检)。
|
|
102
|
+
* - `{ facts }` = 自检成功(origin 是否已跟随 repoUrl)
|
|
103
|
+
* - `{ error }` = 自检读不出来(git 不可用 / 工作副本异常)——**如实回传**,不伪装成「不存在」
|
|
104
|
+
*/
|
|
105
|
+
workDir?: { facts: SyncWorkDirFacts } | { error: string };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** git 工作副本自检事实(与宿主 GitWorkDirFacts 同形;无任何敏感值)。 */
|
|
109
|
+
export interface SyncWorkDirFacts {
|
|
110
|
+
/** 工作副本路径 */
|
|
111
|
+
path: string;
|
|
112
|
+
/** `.git` 是否存在 */
|
|
113
|
+
exists: boolean;
|
|
114
|
+
/** 当前 origin(读不出 → null) */
|
|
115
|
+
origin: string | null;
|
|
116
|
+
/** 单独配置的 push URL(未单独配置 → null) */
|
|
117
|
+
pushUrl: string | null;
|
|
118
|
+
/** fetch / push 地址是否都已跟随 repoUrl */
|
|
119
|
+
match: boolean;
|
|
120
|
+
/** 未上行的本地提交数(仅 detail 自检时给出,否则 null) */
|
|
121
|
+
ahead: number | null;
|
|
122
|
+
/** 工作树是否有未提交改动(仅 detail 自检时给出,否则 null) */
|
|
123
|
+
dirty: boolean | null;
|
|
100
124
|
}
|
|
101
125
|
|
|
102
126
|
/** 同步密码的保存状态(只回布尔;密码值永不回传浏览器)。 */
|
|
@@ -384,9 +408,39 @@ export interface ApplyItemsResponse {
|
|
|
384
408
|
* 旧宿主不返回 → undefined(按「无未生效项」处理,不误报)。
|
|
385
409
|
*/
|
|
386
410
|
ineffective?: { itemId: string; adapter: string; message?: string }[];
|
|
411
|
+
/**
|
|
412
|
+
* 「整体回滚是否完整」(诚实性,2026-10)。`rolledBack=true` 只说「触发了整体回滚」,
|
|
413
|
+
* 不代表每一项都补偿成功(典型:原本已存在的凭据值 DSH 不可回读 → 无法自动恢复)。
|
|
414
|
+
* 此时引擎把失败项并入 `warnings`,并置 `rollbackFull=false`;界面据此**不得**
|
|
415
|
+
* 显示成「已整体回滚」,必须列出未恢复项。
|
|
416
|
+
* 旧宿主不返回 → undefined(按旧的「已整体回滚」文案处理,不误报)。
|
|
417
|
+
*/
|
|
418
|
+
rollbackFull?: boolean;
|
|
387
419
|
result: unknown;
|
|
388
420
|
}
|
|
389
421
|
|
|
422
|
+
/** POST /sync/rollback 响应:一键回滚的诚实结果(full=false 时 failed 列出未回滚项)。 */
|
|
423
|
+
export interface SyncRollbackResponse {
|
|
424
|
+
ok: boolean;
|
|
425
|
+
/** 是否**每一项**都补偿成功(false = 部分回滚,配置可能停留在中间状态) */
|
|
426
|
+
full: boolean;
|
|
427
|
+
/**
|
|
428
|
+
* 未回滚项(full=false 时非空)。`reason` = 为什么没能恢复;`manualHint` = 人工怎么补
|
|
429
|
+
* (如「请重新补录该凭据」)。旧宿主不返回 → undefined(按「无未回滚项」处理)。
|
|
430
|
+
*/
|
|
431
|
+
failed?: SyncRollbackFailedItem[];
|
|
432
|
+
/** 同步历史写入失败(回滚本身已完成;仅提示) */
|
|
433
|
+
historyWriteError?: string;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/** 单条未回滚项。 */
|
|
437
|
+
export interface SyncRollbackFailedItem {
|
|
438
|
+
/** 形如 `<adapter>:<ref>` */
|
|
439
|
+
item: string;
|
|
440
|
+
reason: string;
|
|
441
|
+
manualHint?: string;
|
|
442
|
+
}
|
|
443
|
+
|
|
390
444
|
/* ---------------------------------------------------------------- 自动同步 */
|
|
391
445
|
|
|
392
446
|
/** 统一间隔类型。 */
|
|
@@ -402,6 +456,14 @@ export interface AutosyncStatusResponse {
|
|
|
402
456
|
lastRunAt?: string;
|
|
403
457
|
lastRunStatus?: AutosyncRunStatus;
|
|
404
458
|
lastRunMessage?: string;
|
|
459
|
+
/**
|
|
460
|
+
* issue #79:本轮跳过的**结构化原因码**(界面按码取字典,绝不渲染裸枚举)。
|
|
461
|
+
* 取值与同步历史的 skipReason 同一套:conflict / mutation-locked / encrypted /
|
|
462
|
+
* unconfigured / upToDate / unchanged。
|
|
463
|
+
*/
|
|
464
|
+
lastRunSkipReason?: string;
|
|
465
|
+
/** 跳过涉及的分区数(当前仅 conflict:远端另有 N 个分区待确认) */
|
|
466
|
+
lastRunSkipCount?: number;
|
|
405
467
|
consecutiveFailures: number;
|
|
406
468
|
/** 距上次自动同步已过 ms(host 计算,供 UI 倒计时/立即触发判断) */
|
|
407
469
|
elapsedMs: number;
|
|
@@ -539,15 +601,27 @@ const SYNC_OPTS: RequestOptions = { timeoutMs: LONG_REQUEST_TIMEOUT_MS, timeoutK
|
|
|
539
601
|
/** 远程同步浏览器半数据入口(备份与迁移页第 4 个 tab 的注入业务面) */
|
|
540
602
|
export class SyncApi {
|
|
541
603
|
readonly t: UiT
|
|
542
|
-
constructor(t: UiT
|
|
604
|
+
constructor(t: UiT) {
|
|
543
605
|
this.t = t
|
|
544
606
|
}
|
|
545
607
|
|
|
546
|
-
/** 读取同步状态(配置 / 凭据 / 上次同步时间 /
|
|
608
|
+
/** 读取同步状态(配置 / 凭据 / 上次同步时间 / 分区数 / 工作副本自检) */
|
|
547
609
|
async status(): Promise<SyncStatusResponse> {
|
|
548
610
|
return getJson<SyncStatusResponse>(SYNC_API.status, this.t, SYNC_OPTS);
|
|
549
611
|
}
|
|
550
612
|
|
|
613
|
+
/**
|
|
614
|
+
* 重建 git 工作副本(issue #79 的自救入口)。
|
|
615
|
+
*
|
|
616
|
+
* - `relink`:只把 origin / push URL 重指向当前配置地址(非破坏性,不碰工作树与本地提交);
|
|
617
|
+
* - `reclone`:删除工作副本后重新 clone(**丢弃未上行的本地提交**)→ 必须带 `confirm: true`。
|
|
618
|
+
*
|
|
619
|
+
* 写动作:host 侧过 mutation gate(SAFE MODE / 环境锁)。
|
|
620
|
+
*/
|
|
621
|
+
async workdirReset(payload: { mode: 'relink' | 'reclone'; confirm?: boolean }): Promise<{ ok: boolean; mode: string; workDir: { facts: SyncWorkDirFacts } }> {
|
|
622
|
+
return postJson<{ ok: boolean; mode: string; workDir: { facts: SyncWorkDirFacts } }>(SYNC_API.workdirReset, payload, this.t, SYNC_OPTS);
|
|
623
|
+
}
|
|
624
|
+
|
|
551
625
|
/**
|
|
552
626
|
* 分区条目清单(复用 /export-preview;**只读**,不写任何内容)。
|
|
553
627
|
*
|
|
@@ -698,9 +772,9 @@ export class SyncApi {
|
|
|
698
772
|
return postJson<{ ok: boolean; lastSyncChannel?: SyncTransportType }>(SYNC_API.uiPrefs, payload, this.t, SYNC_OPTS);
|
|
699
773
|
}
|
|
700
774
|
|
|
701
|
-
/** 一键回滚:按 restoreId 调用 backup→rollback */
|
|
702
|
-
async rollback(payload: { restoreId: string }): Promise<
|
|
703
|
-
return postJson<
|
|
775
|
+
/** 一键回滚:按 restoreId 调用 backup→rollback(full=false 时 failed 列出未回滚项与人工提示) */
|
|
776
|
+
async rollback(payload: { restoreId: string }): Promise<SyncRollbackResponse> {
|
|
777
|
+
return postJson<SyncRollbackResponse>(SYNC_API.rollback, payload, this.t, SYNC_OPTS);
|
|
704
778
|
}
|
|
705
779
|
|
|
706
780
|
/** Phase 7 迁移前咨询(只读健康评分 + 建议):对远端快照生成咨询报告。 */
|