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
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 宿主斜杠命令 /rollback(别名 /rw)—— 不打开设置面板也能回退(对齐 dsh-rewind 的 /rewind、/undo)。
|
|
3
|
+
*
|
|
4
|
+
* 语义(用户 2026-10-12 确认方案 A):
|
|
5
|
+
* /rollback → 当前**会话**的可回退点列表(回合号 / 时间 / 类型 / 状态 / 可回退性)
|
|
6
|
+
* /rollback <id> → 回退到该点,走**与 HTTP 路由同源**的那道写入门:
|
|
7
|
+
* runWithMutationLock(= SAFE MODE 门 + 跨进程/跨 kind 环境锁)
|
|
8
|
+
* → 引擎 preview(零写入)→ 引擎 rewind(userConfirmed=true)
|
|
9
|
+
* 引擎回的 confirmation-required / protected-point / record-incomplete 一律翻成可读错误结果,
|
|
10
|
+
* **绝不绕过**(命令入口没有「确认按钮」,用户敲下 id 就是那次确认;其余门照旧全量生效)。
|
|
11
|
+
*
|
|
12
|
+
* 纪律(与 src/core/model-tools.ts 的 registerModelTools 同口径):
|
|
13
|
+
* · 命令服务**惰取**:一律 ctx.get('commands'),绝不属性访问 ctx.commands、绝不放进 inject ——
|
|
14
|
+
* 未组合该服务的部署必须照常启动(命令是可选能力,不是硬依赖);
|
|
15
|
+
* **读的时机是装配期一次**(见 registerRollbackCommand):Cordis 的 ctx.get 在 apply 期只能拿到
|
|
16
|
+
* **已 apply** 的服务,所以 `commands` 行晚于本插件时 `/rollback` 不会注册(只 warn 一行、无重试入口)。
|
|
17
|
+
* DSH 内置插件与本插件的实际 apply 顺序**未坐实**(asar 不可直接读、本机 profile 无相关行);
|
|
18
|
+
* 要彻底消除这个窗口需要 `ctx.inject(['commands'])` 式的「服务就绪再注册」回调 —— 未做,如实记在这里。
|
|
19
|
+
* · 注册失败只 warn:命令挂不上不得影响其它装配(宿主启动 = blocker);
|
|
20
|
+
* · 用户可见文案一律走宿主字典 engineMsg(key: command.rollback.*),**取文案那一刻**解析语言;
|
|
21
|
+
* · 本模块不 import @deepseek-ai/dsh-commands 的运行时值(只做结构化窄化),core 保持与 DSH 解耦。
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { engineMsg } from './engine-locale.ts'
|
|
25
|
+
import { EnvironmentLockUnavailableError } from '../utils/env-lock.ts'
|
|
26
|
+
import type { MutationLockPort } from '../utils/env-lock.ts'
|
|
27
|
+
import type {
|
|
28
|
+
RollbackPointSummary,
|
|
29
|
+
RollbackRewindResult,
|
|
30
|
+
RollbackSegmentResult,
|
|
31
|
+
} from './rollback-point.ts'
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* 命令结果(与 @deepseek-ai/dsh-commands 的 `CommandResult` **逐字同形**)。
|
|
35
|
+
*
|
|
36
|
+
* 为什么在这里自己声明而不是 import 那门包的类型:`src/core/**` 的架构边界(tests/architecture-boundaries.test.ts
|
|
37
|
+
* 的 core allow 表)只允许 node 内置 / core 内部 / schema / utils / security / migrations / js-yaml ——
|
|
38
|
+
* `@deepseek-ai/*` 仅允许出现在 `src/index.ts` 与 `src/client/`。core 必须保持与 DSH 解耦,
|
|
39
|
+
* 所以这里做**结构化窄化**;两边一旦漂移,`command-rollback.test.ts` 的编译期断言会红。
|
|
40
|
+
*/
|
|
41
|
+
export type CommandResult =
|
|
42
|
+
| { readonly kind: 'success'; readonly text?: string; readonly sourceEventSeq?: number }
|
|
43
|
+
| { readonly kind: 'error'; readonly text: string }
|
|
44
|
+
|
|
45
|
+
/** 命令名(无前导斜杠)与别名。 */
|
|
46
|
+
export const ROLLBACK_COMMAND_NAME = 'rollback'
|
|
47
|
+
export const ROLLBACK_COMMAND_ALIAS = 'rw'
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 命令定义 id:/rw 别名是**第二条定义** —— 同一个 definitionId(客户端按 definitionId 做身份化行为,
|
|
51
|
+
* 别名与主名必须被视作同一条命令)。
|
|
52
|
+
*/
|
|
53
|
+
export const ROLLBACK_COMMAND_DEFINITION_ID = 'dsh-config-manager/rollback'
|
|
54
|
+
|
|
55
|
+
/** 命令服务惰取回调(调用期读 ctx.get('commands');未组合返回 undefined)。 */
|
|
56
|
+
export type CommandServiceReader = () => CommandServiceLike | undefined | null
|
|
57
|
+
|
|
58
|
+
/** 一条已注册命令的最小形状(避免把 DSH 类型变成本插件的硬依赖)。 */
|
|
59
|
+
export interface CommandDefinitionLike {
|
|
60
|
+
readonly name: string
|
|
61
|
+
readonly description: string
|
|
62
|
+
readonly definitionId?: string
|
|
63
|
+
readonly input?: { readonly hint: string; readonly attachments?: boolean }
|
|
64
|
+
readonly handler: (invocation: CommandInvocationLike) => CommandResult | Promise<CommandResult>
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** 一次命令调用的最小形状(只读用到的字段)。 */
|
|
68
|
+
export interface CommandInvocationLike {
|
|
69
|
+
readonly agent: unknown
|
|
70
|
+
/** 命令名之后的原文(含分隔空白)。 */
|
|
71
|
+
readonly rawInput: string
|
|
72
|
+
/** 派发 UI 持有的取消信号(透传给回退执行)。 */
|
|
73
|
+
readonly signal?: AbortSignal
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** 命令服务的最小形状(ctx.get('commands') 的结构化窄化)。 */
|
|
77
|
+
export interface CommandServiceLike {
|
|
78
|
+
register(definition: CommandDefinitionLike): unknown
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** 宿主提供的回退能力(由 src/index.ts 装配;测试用假的实现即可)。 */
|
|
82
|
+
export interface RollbackCommandHost {
|
|
83
|
+
/** 当前 agent 所属会话(拿不准则 ok:false —— 绝不猜)。 */
|
|
84
|
+
agentSession(agent: unknown): AgentSessionFacts
|
|
85
|
+
/** 列出该会话的回退点(含存储栈状态;只读)。 */
|
|
86
|
+
list(sessionId: string): Promise<RollbackCommandListResult>
|
|
87
|
+
/**
|
|
88
|
+
* 执行回退:runWithMutationLock → SAFE MODE → 引擎 preview → 引擎 rewind。
|
|
89
|
+
*
|
|
90
|
+
* 被 SAFE MODE / 环境锁挡住时**抛 EnvironmentLockUnavailableError**(与 HTTP 路由同口径),
|
|
91
|
+
* 由本模块翻成可读错误结果。
|
|
92
|
+
*/
|
|
93
|
+
rewind(input: RollbackRewindExecution): Promise<RollbackRewindResult>
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 回退执行入参。
|
|
98
|
+
*
|
|
99
|
+
* 只带 id + 取消信号:引擎 `rewind({ id, userConfirmed: true })` 的**写入面**已经由该点的记录
|
|
100
|
+
* 决定(不是调用方临时指定路径),多传会话/分块只会制造「两处口径」;会话事实只供只读列表过滤用。
|
|
101
|
+
*/
|
|
102
|
+
export interface RollbackRewindExecution {
|
|
103
|
+
readonly id: string
|
|
104
|
+
readonly signal?: AbortSignal
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** 列表结果(引擎 RollbackListResult 的可测子集)。 */
|
|
108
|
+
export interface RollbackCommandListResult {
|
|
109
|
+
ok: boolean
|
|
110
|
+
storage: { available: boolean; root: string; detail?: string }
|
|
111
|
+
points: readonly RollbackPointSummary[]
|
|
112
|
+
error?: string
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** 当前 agent 的会话事实(宽进严出:形状不符即 ok:false)。 */
|
|
116
|
+
export type AgentSessionFacts =
|
|
117
|
+
| { ok: true; sessionId: string; chunks: readonly string[] }
|
|
118
|
+
| { ok: false; detail: string }
|
|
119
|
+
|
|
120
|
+
/** 绝对路径判定(win32 盘符 + POSIX 前缀 + UNC;纯函数,不引 node:path)。 */
|
|
121
|
+
export function isAbsolutePath(value: string): boolean {
|
|
122
|
+
if (value.startsWith('/') || value.startsWith('\\')) return true
|
|
123
|
+
return /^[A-Za-z]:[\\/]/.test(value)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 从 agent 窄化会话事实。
|
|
128
|
+
*
|
|
129
|
+
* **不猜**:agent.session.id 读不出来就退回 agent.id(DSH 的 Agent.id 就是会话 id);
|
|
130
|
+
* 两者都读不出 → ok:false(命令如实报「拿不到当前会话」,而不是列全网的点)。
|
|
131
|
+
* 工作区分块只认**绝对路径**的 cwd(与 rollbackSessionBindingOf 同一口径)。
|
|
132
|
+
*/
|
|
133
|
+
export function agentSessionFactsOf(agent: unknown): AgentSessionFacts {
|
|
134
|
+
if (agent === null || typeof agent !== 'object') return { ok: false, detail: 'agent-not-object' }
|
|
135
|
+
const rec = agent as { id?: unknown; session?: unknown }
|
|
136
|
+
let sessionId: string | undefined
|
|
137
|
+
let cwd: string | undefined
|
|
138
|
+
const session = rec.session
|
|
139
|
+
if (session !== null && typeof session === 'object') {
|
|
140
|
+
const s = session as { id?: unknown; header?: unknown }
|
|
141
|
+
if (typeof s.id === 'string' && s.id !== '') sessionId = s.id
|
|
142
|
+
const header = s.header
|
|
143
|
+
if (header !== null && typeof header === 'object') {
|
|
144
|
+
const value = (header as { cwd?: unknown }).cwd
|
|
145
|
+
if (typeof value === 'string' && value !== '') cwd = value
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (sessionId === undefined && typeof rec.id === 'string' && rec.id !== '') sessionId = rec.id
|
|
149
|
+
if (sessionId === undefined) return { ok: false, detail: 'session-id-missing' }
|
|
150
|
+
const chunks = cwd !== undefined && isAbsolutePath(cwd) ? [cwd] : []
|
|
151
|
+
return { ok: true, sessionId, chunks }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** 解析结果:空输入 = 只读列表;单个 token = 目标点 id;其余 = invalid。 */
|
|
155
|
+
export type RollbackCommandInput =
|
|
156
|
+
| { kind: 'list' }
|
|
157
|
+
| { kind: 'rewind'; id: string }
|
|
158
|
+
| { kind: 'invalid'; detail: string }
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* 解析 rawInput(命令名之后的原文,含分隔空白)。
|
|
162
|
+
* 语法只有两种:空 = 列表;单个非空 token = 目标 id。多 token 一律 invalid。
|
|
163
|
+
*/
|
|
164
|
+
export function parseRollbackCommand(rawInput: string): RollbackCommandInput {
|
|
165
|
+
const trimmed = (rawInput ?? '').trim()
|
|
166
|
+
if (trimmed === '') return { kind: 'list' }
|
|
167
|
+
const parts = trimmed.split(/\s+/)
|
|
168
|
+
if (parts.length !== 1) return { kind: 'invalid', detail: 'too-many-arguments' }
|
|
169
|
+
return { kind: 'rewind', id: parts[0] ?? '' }
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* ------------------------------------------------------------------ 渲染 */
|
|
173
|
+
|
|
174
|
+
function isoOf(createdAt: number): string {
|
|
175
|
+
if (!Number.isFinite(createdAt)) return '?'
|
|
176
|
+
try {
|
|
177
|
+
return new Date(createdAt).toISOString()
|
|
178
|
+
} catch {
|
|
179
|
+
return '?'
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/** 点状态:受保护 / 捕获不完整 / 正常(三者互斥,按引擎字段的优先级分派)。 */
|
|
184
|
+
function stateLabel(point: RollbackPointSummary): string {
|
|
185
|
+
if (point.protected) return engineMsg('command.rollback.stateProtected')
|
|
186
|
+
if (point.incomplete) return engineMsg('command.rollback.stateIncomplete')
|
|
187
|
+
return engineMsg('command.rollback.stateNormal')
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** 该点两态各自的「可回退 / 不可回退」摘要(诚实:按段逐项说,再给总判)。 */
|
|
191
|
+
function restorableLabel(point: RollbackPointSummary): string {
|
|
192
|
+
const segments = point.segments ?? []
|
|
193
|
+
const parts: string[] = []
|
|
194
|
+
for (const segment of segments) {
|
|
195
|
+
const label = segment.restorable ? engineMsg('command.rollback.restorableYes') : engineMsg('command.rollback.restorableNo')
|
|
196
|
+
parts.push(
|
|
197
|
+
engineMsg('command.rollback.segmentLabel', {
|
|
198
|
+
state: engineMsg(segment.state === 'workspace' ? 'command.rollback.segmentWorkspace' : 'command.rollback.segmentSession'),
|
|
199
|
+
label,
|
|
200
|
+
}),
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
if (parts.length === 0) return engineMsg('command.rollback.restorableNo')
|
|
204
|
+
const any = segments.some((segment) => segment.restorable)
|
|
205
|
+
return engineMsg('command.rollback.restorableSummary', {
|
|
206
|
+
parts: parts.join(engineMsg('command.rollback.listSeparator')),
|
|
207
|
+
verdict: any ? engineMsg('command.rollback.restorableYes') : engineMsg('command.rollback.restorableNo'),
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function turnLabel(point: RollbackPointSummary): string {
|
|
212
|
+
return point.turn === null ? engineMsg('command.rollback.turnUnknown') : String(point.turn)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function kindLabel(point: RollbackPointSummary): string {
|
|
216
|
+
return engineMsg(point.kind === 'guard' ? 'command.rollback.kindGuard' : 'command.rollback.kindAuto')
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** 渲染只读列表(本会话没有点时给「本会话没有」,绝不冒充「全库为空」)。 */
|
|
220
|
+
export function renderRollbackList(result: RollbackCommandListResult, sessionId: string): CommandResult {
|
|
221
|
+
if (!result.storage.available) {
|
|
222
|
+
return {
|
|
223
|
+
kind: 'error',
|
|
224
|
+
text: engineMsg('command.rollback.storageUnavailable', { detail: result.storage.detail ?? result.storage.root }),
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (result.error !== undefined && result.error !== '') {
|
|
228
|
+
return { kind: 'error', text: engineMsg('command.rollback.listFailed', { detail: result.error }) }
|
|
229
|
+
}
|
|
230
|
+
const points = (result.points ?? []).filter((point) => point.sessionId === sessionId)
|
|
231
|
+
if (points.length === 0) return { kind: 'error', text: engineMsg('command.rollback.empty') }
|
|
232
|
+
const lines = points.map((point, index) =>
|
|
233
|
+
engineMsg('command.rollback.listRow', {
|
|
234
|
+
index: String(index + 1),
|
|
235
|
+
id: point.id,
|
|
236
|
+
turn: turnLabel(point),
|
|
237
|
+
createdAt: isoOf(point.createdAt),
|
|
238
|
+
kind: kindLabel(point),
|
|
239
|
+
state: stateLabel(point),
|
|
240
|
+
restorable: restorableLabel(point),
|
|
241
|
+
}),
|
|
242
|
+
)
|
|
243
|
+
return { kind: 'success', text: [engineMsg('command.rollback.listTitle'), ...lines].join('\n') }
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/** 段结果的一行技术事实(定位失败用;**不是**文案分派的语义依据)。 */
|
|
247
|
+
function segmentFacts(segments: readonly RollbackSegmentResult[] | undefined): string {
|
|
248
|
+
if (segments === undefined || segments.length === 0) return ''
|
|
249
|
+
return segments
|
|
250
|
+
.map((segment) => segment.state + '/' + segment.status + (segment.reasonCode !== undefined ? '(' + segment.reasonCode + ')' : ''))
|
|
251
|
+
.join(',')
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** 把引擎结果翻成命令结果(失败一律带机器码 + 技术细节;processed 的段事实不隐藏)。 */
|
|
255
|
+
export function renderRewindResult(result: RollbackRewindResult, id: string): CommandResult {
|
|
256
|
+
const detail = result.detail ?? ''
|
|
257
|
+
if (result.ok && result.outcome === 'restored') {
|
|
258
|
+
return { kind: 'success', text: engineMsg('command.rollback.rewindRestored', { id, detail }) }
|
|
259
|
+
}
|
|
260
|
+
if (result.outcome === 'partial') {
|
|
261
|
+
// 「部分恢复」既不是成功也不是泛化失败:逐段事实必须上屏(含被跳过的段)。
|
|
262
|
+
return {
|
|
263
|
+
kind: 'error',
|
|
264
|
+
text: engineMsg('command.rollback.rewindPartial', {
|
|
265
|
+
id,
|
|
266
|
+
segments: engineMsg('command.rollback.segmentFacts', { facts: segmentFacts(result.segments) }),
|
|
267
|
+
detail,
|
|
268
|
+
}),
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
kind: 'error',
|
|
273
|
+
text: engineMsg('command.rollback.rewindFailed', { id, code: String(result.code), detail }),
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/* ------------------------------------------------------------------ 执行 */
|
|
278
|
+
|
|
279
|
+
/** 命令依赖(index.ts 装配;测试直接构造)。 */
|
|
280
|
+
export interface RollbackCommandDeps {
|
|
281
|
+
readonly host: RollbackCommandHost
|
|
282
|
+
/** mutation lock 端口(index.ts 传 host.mutationLock;测试可传 undefined 或假端口)。 */
|
|
283
|
+
readonly mutationLock?: MutationLockPort
|
|
284
|
+
/** SAFE MODE 同步谓词(与 HTTP 路由同一份 host.safeModeIsBlocked)。 */
|
|
285
|
+
readonly isBlocked?: () => boolean
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* 构造命令处理器(**纯编排**:不注册、不读 ctx)。
|
|
290
|
+
*
|
|
291
|
+
* 带参数时:parser → agentSession(只用于「这次是不是列表」的会话判定)→ host.rewind。
|
|
292
|
+
* host.rewind 内部才是那道门:runWithMutationLock → SAFE MODE → 引擎 preview → 引擎 rewind
|
|
293
|
+
* EnvironmentLockUnavailableError(SAFE MODE / 环境锁被挡)在此翻成可读错误结果。
|
|
294
|
+
* 任何未预期异常也翻成错误结果 —— 命令处理器抛异常会让整条命令生命周期报泛化失败,
|
|
295
|
+
* UI 只看到一句「失败」;这里如实把原因说清楚。
|
|
296
|
+
*/
|
|
297
|
+
export function makeRollbackCommandHandler(
|
|
298
|
+
deps: RollbackCommandDeps,
|
|
299
|
+
): (invocation: CommandInvocationLike) => Promise<CommandResult> {
|
|
300
|
+
return async (invocation) => {
|
|
301
|
+
const parsed = parseRollbackCommand(invocation.rawInput)
|
|
302
|
+
if (parsed.kind === 'invalid') {
|
|
303
|
+
return { kind: 'error', text: engineMsg('command.rollback.usageInvalid', { detail: parsed.detail }) }
|
|
304
|
+
}
|
|
305
|
+
const facts = deps.host.agentSession(invocation.agent)
|
|
306
|
+
if (!facts.ok) {
|
|
307
|
+
return { kind: 'error', text: engineMsg('command.rollback.sessionUnavailable', { detail: facts.detail }) }
|
|
308
|
+
}
|
|
309
|
+
if (parsed.kind === 'list') {
|
|
310
|
+
try {
|
|
311
|
+
return renderRollbackList(await deps.host.list(facts.sessionId), facts.sessionId)
|
|
312
|
+
} catch (error) {
|
|
313
|
+
return { kind: 'error', text: engineMsg('command.rollback.listFailed', { detail: errorText(error) }) }
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
try {
|
|
317
|
+
const execution: RollbackRewindExecution = {
|
|
318
|
+
id: parsed.id,
|
|
319
|
+
...(invocation.signal !== undefined ? { signal: invocation.signal } : {}),
|
|
320
|
+
}
|
|
321
|
+
return renderRewindResult(await deps.host.rewind(execution), parsed.id)
|
|
322
|
+
} catch (error) {
|
|
323
|
+
if (error instanceof EnvironmentLockUnavailableError) {
|
|
324
|
+
return {
|
|
325
|
+
kind: 'error',
|
|
326
|
+
text: engineMsg('command.rollback.mutationLocked', { reason: error.reason, id: parsed.id }),
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return {
|
|
330
|
+
kind: 'error',
|
|
331
|
+
text: engineMsg('command.rollback.rewindFailed', { id: parsed.id, code: 'exception', detail: errorText(error) }),
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function errorText(error: unknown): string {
|
|
338
|
+
return error instanceof Error ? error.message : String(error)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/* ------------------------------------------------------------------ 注册 */
|
|
342
|
+
|
|
343
|
+
/** 注册所需的依赖面(命令服务惰取回调 + 宿主日志 + 命令依赖)。 */
|
|
344
|
+
export interface RollbackCommandRegistrationOptions {
|
|
345
|
+
/** 惰取命令服务:实现必须是「调用期」的 ctx.get('commands')(绝不属性访问、绝不进 inject)。 */
|
|
346
|
+
readonly readCommands: CommandServiceReader
|
|
347
|
+
readonly deps: RollbackCommandDeps
|
|
348
|
+
/** 只 warn:注册失败/服务缺失不得影响其它装配。 */
|
|
349
|
+
readonly log?: { warn(message: string, meta?: unknown): void }
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* 注册 /rollback 与 /rw(两条定义 = 同一 definitionId)。
|
|
354
|
+
*
|
|
355
|
+
* 服务缺失 → warn 后**安静返回**(未组合 commands 的部署照常启动、不抛错);
|
|
356
|
+
* 服务存在但 register 抛错 → warn(其余装配不受影响)。
|
|
357
|
+
* @returns 反注册函数(重复调用安全)。
|
|
358
|
+
*/
|
|
359
|
+
export function registerRollbackCommand(options: RollbackCommandRegistrationOptions): () => void {
|
|
360
|
+
const disposers: (() => void)[] = []
|
|
361
|
+
let service: CommandServiceLike | undefined
|
|
362
|
+
try {
|
|
363
|
+
service = options.readCommands() ?? undefined
|
|
364
|
+
} catch (error) {
|
|
365
|
+
options.log?.warn(engineMsg('command.rollback.serviceUnavailable', { detail: errorText(error) }))
|
|
366
|
+
return () => {}
|
|
367
|
+
}
|
|
368
|
+
if (service === undefined || typeof service.register !== 'function') {
|
|
369
|
+
options.log?.warn(engineMsg('command.rollback.serviceUnavailable', { detail: 'commands-service-missing' }))
|
|
370
|
+
return () => {}
|
|
371
|
+
}
|
|
372
|
+
const handler = makeRollbackCommandHandler(options.deps)
|
|
373
|
+
const definitions: readonly CommandDefinitionLike[] = [
|
|
374
|
+
{
|
|
375
|
+
name: ROLLBACK_COMMAND_NAME,
|
|
376
|
+
definitionId: ROLLBACK_COMMAND_DEFINITION_ID,
|
|
377
|
+
description: engineMsg('command.rollback.commandDesc'),
|
|
378
|
+
input: { hint: engineMsg('command.rollback.commandInputHint') },
|
|
379
|
+
handler,
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
name: ROLLBACK_COMMAND_ALIAS,
|
|
383
|
+
definitionId: ROLLBACK_COMMAND_DEFINITION_ID,
|
|
384
|
+
description: engineMsg('command.rollback.commandDescAlias'),
|
|
385
|
+
input: { hint: engineMsg('command.rollback.commandInputHint') },
|
|
386
|
+
handler,
|
|
387
|
+
},
|
|
388
|
+
]
|
|
389
|
+
for (const definition of definitions) {
|
|
390
|
+
try {
|
|
391
|
+
const disposer = service.register(definition)
|
|
392
|
+
if (typeof disposer === 'function') disposers.push(disposer as () => void)
|
|
393
|
+
} catch (error) {
|
|
394
|
+
options.log?.warn(engineMsg('command.rollback.registerFailed', { name: definition.name, detail: errorText(error) }))
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return () => {
|
|
398
|
+
for (const dispose of disposers.splice(0)) {
|
|
399
|
+
try {
|
|
400
|
+
dispose()
|
|
401
|
+
} catch (error) {
|
|
402
|
+
options.log?.warn(engineMsg('command.rollback.registerFailed', { name: 'dispose', detail: errorText(error) }))
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
@@ -19,6 +19,7 @@ import { SECTION_JSON_PATHS, SECTION_FILE_PREFIXES, isFileSection } from '../sch
|
|
|
19
19
|
import { scanAndRedact, scanText } from '../security/secret-scanner.ts';
|
|
20
20
|
import type { Manifest, SectionId } from '../schema/types.ts';
|
|
21
21
|
import type { ConsultSourceData, ConsultSourceRef, MigratabilityResult } from './migration-consult.ts';
|
|
22
|
+
import { engineMsg } from './messages-core.ts';
|
|
22
23
|
|
|
23
24
|
export interface ConsultSourceReaderOptions {
|
|
24
25
|
/** 计算可迁移性(宿主注入;缺省 null = 不评估) */
|
|
@@ -75,11 +76,11 @@ export async function readExportZipSource(
|
|
|
75
76
|
const parsed = JSON.parse(archive.readEntryText(MANIFEST_FILE));
|
|
76
77
|
manifestIssues = validateManifest(parsed);
|
|
77
78
|
} catch {
|
|
78
|
-
manifestIssues = [{ path: '$', message: '
|
|
79
|
+
manifestIssues = [{ path: '$', message: engineMsg('core.consult.manifestUnparsable'), severity: 'error' }];
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
} else {
|
|
82
|
-
manifestIssues = [{ path: '$', message: '
|
|
83
|
+
manifestIssues = [{ path: '$', message: engineMsg('core.consult.manifestMissing'), severity: 'error' }];
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
// 3. checksums(捕获不匹配,不抛错)
|
|
@@ -94,8 +95,8 @@ export async function readExportZipSource(
|
|
|
94
95
|
}
|
|
95
96
|
const result = verifyChecksumsJson(entries, archive.readEntryText(CHECKSUMS_FILE));
|
|
96
97
|
checksums = result.ok ? {} : null;
|
|
97
|
-
for (const m of result.mismatches) checksumIssues.push(
|
|
98
|
-
for (const m of result.missing) checksumIssues.push(
|
|
98
|
+
for (const m of result.mismatches) checksumIssues.push(engineMsg('core.consult.hashMismatch', { name: m }));
|
|
99
|
+
for (const m of result.missing) checksumIssues.push(engineMsg('core.consult.entryMissing', { name: m }));
|
|
99
100
|
} catch (err) {
|
|
100
101
|
checksumIssues.push(err instanceof Error ? err.message : String(err));
|
|
101
102
|
}
|
|
@@ -205,8 +206,8 @@ export function buildLocalSnapshotSource(
|
|
|
205
206
|
sections: sectionFlags,
|
|
206
207
|
security: { containsSecrets: false, encrypted: false, encryption: null },
|
|
207
208
|
};
|
|
208
|
-
const manifestIssues = input.verify.ok ? [] : [{ path: '$', message: input.verify.reason ?? '
|
|
209
|
-
const checksumIssues = input.verify.ok ? [] : [input.verify.reason ?? '
|
|
209
|
+
const manifestIssues = input.verify.ok ? [] : [{ path: '$', message: input.verify.reason ?? engineMsg('core.consult.snapshotIntegrityFailed'), severity: 'error' as const }];
|
|
210
|
+
const checksumIssues = input.verify.ok ? [] : [input.verify.reason ?? engineMsg('core.consult.snapshotIntegrityFailed')];
|
|
210
211
|
const migratability: MigratabilityResult = {
|
|
211
212
|
ok: input.restorePlan.errors.length === 0,
|
|
212
213
|
itemCount: input.restorePlan.itemCount,
|