dsh-config-manager 0.1.63 → 0.1.65
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 +66 -14
- package/README.zh-CN.md +43 -13
- package/lib/adapters/agent-instructions.d.ts +3 -3
- package/lib/adapters/agent-instructions.js +5 -3
- package/lib/adapters/agent-presets.d.ts +3 -3
- package/lib/adapters/agent-presets.js +5 -3
- package/lib/adapters/credentials.d.ts +3 -3
- package/lib/adapters/credentials.js +20 -23
- package/lib/adapters/file-collection.d.ts +43 -0
- package/lib/adapters/file-collection.js +130 -18
- package/lib/adapters/index.d.ts +1 -0
- package/lib/adapters/index.js +11 -0
- package/lib/adapters/json-section.d.ts +32 -0
- package/lib/adapters/json-section.js +61 -0
- package/lib/adapters/mcp.d.ts +3 -3
- package/lib/adapters/mcp.js +16 -19
- package/lib/adapters/plugin-files.d.ts +3 -3
- package/lib/adapters/plugin-files.js +11 -14
- package/lib/adapters/plugins.d.ts +3 -3
- package/lib/adapters/plugins.js +39 -42
- package/lib/adapters/prompts.d.ts +3 -3
- package/lib/adapters/prompts.js +16 -20
- package/lib/adapters/providers.d.ts +3 -3
- package/lib/adapters/providers.js +23 -26
- package/lib/adapters/sessions.d.ts +97 -1
- package/lib/adapters/sessions.js +455 -15
- package/lib/adapters/settings.d.ts +3 -3
- package/lib/adapters/settings.js +23 -26
- package/lib/adapters/skills.d.ts +3 -3
- package/lib/adapters/skills.js +5 -3
- package/lib/adapters/test-helpers.d.ts +8 -0
- package/lib/adapters/test-helpers.js +8 -0
- package/lib/adapters/ui.d.ts +3 -3
- package/lib/adapters/ui.js +14 -17
- package/lib/adapters/workspaces.d.ts +22 -0
- package/lib/adapters/workspaces.js +237 -16
- package/lib/cli/index.d.ts +46 -4
- package/lib/cli/index.js +170 -34
- package/lib/cli/sessions-repair.d.ts +28 -0
- package/lib/cli/sessions-repair.js +206 -0
- package/lib/client.d.ts +464 -173
- package/lib/client.js +14414 -8888
- package/lib/core/analyzer.d.ts +71 -5
- package/lib/core/analyzer.js +409 -112
- package/lib/core/backup-plan.d.ts +7 -1
- package/lib/core/backup-plan.js +15 -8
- package/lib/core/backup.d.ts +53 -2
- package/lib/core/backup.js +120 -24
- package/lib/core/boot-paths.d.ts +14 -0
- package/lib/core/boot-paths.js +28 -0
- package/lib/core/boot-rescue.d.ts +21 -0
- package/lib/core/boot-rescue.js +57 -1
- package/lib/core/boot-safety.d.ts +50 -0
- package/lib/core/boot-safety.js +211 -0
- package/lib/core/conflict-decisions.d.ts +16 -0
- package/lib/core/conflict-decisions.js +21 -0
- package/lib/core/crash-report.d.ts +15 -12
- package/lib/core/crash-report.js +33 -40
- package/lib/core/credential-status.d.ts +15 -0
- package/lib/core/credential-status.js +13 -0
- package/lib/core/exporter.d.ts +18 -0
- package/lib/core/exporter.js +115 -3
- package/lib/core/importer.d.ts +15 -2
- package/lib/core/importer.js +10 -3
- package/lib/core/index.d.ts +2 -0
- package/lib/core/index.js +3 -0
- package/lib/core/journal.d.ts +74 -5
- package/lib/core/journal.js +127 -12
- package/lib/core/messages.d.ts +54 -0
- package/lib/core/messages.js +110 -0
- package/lib/core/migration-consult.js +0 -4
- package/lib/core/model-tools.js +6 -9
- package/lib/core/path-mapping.d.ts +11 -0
- package/lib/core/path-mapping.js +28 -0
- package/lib/core/phase3-host.d.ts +79 -6
- package/lib/core/phase3-host.js +223 -73
- package/lib/core/phase4-crash-child.js +0 -1
- package/lib/core/plugin-cli.js +22 -2
- package/lib/core/reconcile.d.ts +8 -1
- package/lib/core/reconcile.js +12 -4
- package/lib/core/recovery-orchestrator.js +1 -1
- package/lib/core/restore.js +10 -4
- package/lib/core/rollback.js +1 -1
- package/lib/core/run-registry.d.ts +63 -3
- package/lib/core/run-registry.js +74 -4
- package/lib/core/session-meta.d.ts +27 -8
- package/lib/core/session-meta.js +59 -32
- package/lib/core/session-repair.d.ts +89 -0
- package/lib/core/session-repair.js +118 -0
- package/lib/core/session-select.d.ts +50 -0
- package/lib/core/session-select.js +137 -0
- package/lib/core/startup-barrier.d.ts +15 -0
- package/lib/core/startup-barrier.js +24 -2
- package/lib/core/transaction-coordinator.js +3 -3
- package/lib/core/types.d.ts +250 -0
- package/lib/core/validator.js +0 -1
- package/lib/index.d.ts +368 -6
- package/lib/index.js +884 -3365
- package/lib/market/index-parser.d.ts +2 -1
- package/lib/market/index-parser.js +27 -6
- package/lib/market/my-repo.d.ts +0 -1
- package/lib/market/my-repo.js +0 -6
- package/lib/market/prepare.d.ts +9 -0
- package/lib/market/prepare.js +5 -31
- package/lib/market/reader.js +0 -1
- package/lib/market/security.js +3 -9
- package/lib/profiles/dsh-profile-launcher.d.ts +141 -0
- package/lib/profiles/dsh-profile-launcher.js +396 -0
- package/lib/profiles/dsh-profile-manager.d.ts +49 -15
- package/lib/profiles/dsh-profile-manager.js +151 -48
- package/lib/profiles/dsh-profile-runtime.d.ts +83 -0
- package/lib/profiles/dsh-profile-runtime.js +194 -0
- package/lib/profiles/dsh-profile-shared.d.ts +117 -10
- package/lib/profiles/dsh-profile-shared.js +12 -0
- package/lib/profiles/index.d.ts +10 -3
- package/lib/profiles/index.js +10 -3
- package/lib/profiles/process-control.d.ts +37 -0
- package/lib/profiles/process-control.js +75 -0
- package/lib/routes/backup.d.ts +9 -0
- package/lib/routes/backup.js +99 -0
- package/lib/routes/consult.d.ts +9 -0
- package/lib/routes/consult.js +134 -0
- package/lib/routes/context.d.ts +9 -0
- package/lib/routes/context.js +2 -0
- package/lib/routes/history.d.ts +9 -0
- package/lib/routes/history.js +53 -0
- package/lib/routes/import.d.ts +9 -0
- package/lib/routes/import.js +390 -0
- package/lib/routes/index.d.ts +10 -0
- package/lib/routes/index.js +27 -0
- package/lib/routes/kit.d.ts +99 -0
- package/lib/routes/kit.js +161 -0
- package/lib/routes/market.d.ts +9 -0
- package/lib/routes/market.js +256 -0
- package/lib/routes/me.d.ts +9 -0
- package/lib/routes/me.js +170 -0
- package/lib/routes/prefs.d.ts +9 -0
- package/lib/routes/prefs.js +103 -0
- package/lib/routes/profiles.d.ts +9 -0
- package/lib/routes/profiles.js +250 -0
- package/lib/routes/recovery.d.ts +9 -0
- package/lib/routes/recovery.js +137 -0
- package/lib/routes/snapshots.d.ts +9 -0
- package/lib/routes/snapshots.js +214 -0
- package/lib/routes/sync.d.ts +9 -0
- package/lib/routes/sync.js +783 -0
- package/lib/schema/config.d.ts +10 -9
- package/lib/schema/config.js +78 -96
- package/lib/schema/index.d.ts +8 -1
- package/lib/schema/index.js +13 -1
- package/lib/schema/manifest.d.ts +2 -0
- package/lib/schema/manifest.js +1 -0
- package/lib/schema/section-registry.d.ts +211 -0
- package/lib/schema/section-registry.js +285 -0
- package/lib/schema/types.d.ts +13 -3
- package/lib/schema/versions.d.ts +11 -6
- package/lib/schema/versions.js +27 -1
- package/lib/security/secret-scanner.js +1 -1
- package/lib/security/zip-security.d.ts +8 -5
- package/lib/security/zip-security.js +20 -90
- package/lib/sync/ancestor.d.ts +11 -0
- package/lib/sync/ancestor.js +20 -0
- package/lib/sync/autosync-config.js +9 -18
- package/lib/sync/autosync-scheduler.d.ts +7 -2
- package/lib/sync/autosync-scheduler.js +35 -17
- package/lib/sync/backup-schedule-config.js +0 -1
- package/lib/sync/blob-store.d.ts +85 -0
- package/lib/sync/blob-store.js +85 -0
- package/lib/sync/git/git-transport.d.ts +28 -5
- package/lib/sync/git/git-transport.js +170 -24
- package/lib/sync/github-auth.d.ts +0 -1
- package/lib/sync/github-auth.js +0 -2
- package/lib/sync/layout.d.ts +16 -2
- package/lib/sync/layout.js +48 -7
- package/lib/sync/risk.d.ts +18 -12
- package/lib/sync/risk.js +17 -28
- package/lib/sync/session-tombstones.d.ts +39 -0
- package/lib/sync/session-tombstones.js +125 -0
- package/lib/sync/sync-config.d.ts +26 -3
- package/lib/sync/sync-config.js +40 -3
- package/lib/sync/sync-engine.d.ts +140 -12
- package/lib/sync/sync-engine.js +266 -49
- package/lib/sync/sync-history.js +0 -1
- package/lib/sync/sync-selection.d.ts +18 -0
- package/lib/sync/sync-selection.js +50 -24
- package/lib/sync/sync-state.d.ts +31 -4
- package/lib/sync/sync-state.js +38 -6
- package/lib/sync/transport.d.ts +103 -0
- package/lib/sync/transport.js +121 -0
- package/lib/sync/ui-prefs.d.ts +4 -2
- package/lib/sync/ui-prefs.js +6 -4
- package/lib/sync/webdav/webdav-transport.d.ts +36 -4
- package/lib/sync/webdav/webdav-transport.js +242 -43
- package/lib/ui/dsh-profiles-view.d.ts +52 -9
- package/lib/ui/dsh-profiles-view.js +80 -13
- package/lib/ui/export-flow.d.ts +2 -2
- package/lib/ui/export-flow.js +63 -17
- package/lib/ui/i18n.d.ts +12 -2
- package/lib/ui/i18n.js +25 -4
- package/lib/ui/import-log.d.ts +72 -0
- package/lib/ui/import-log.js +110 -0
- package/lib/ui/import-stepper.d.ts +14 -0
- package/lib/ui/import-stepper.js +18 -0
- package/lib/ui/import-wizard.d.ts +106 -3
- package/lib/ui/import-wizard.js +125 -7
- package/lib/ui/mid-ellipsis.d.ts +31 -0
- package/lib/ui/mid-ellipsis.js +39 -0
- package/lib/ui/my-configs-view.d.ts +136 -0
- package/lib/ui/my-configs-view.js +127 -0
- package/lib/ui/progress.js +6 -0
- package/lib/ui/report.d.ts +26 -0
- package/lib/ui/report.js +37 -0
- package/lib/ui/runs-view.d.ts +128 -0
- package/lib/ui/runs-view.js +123 -0
- package/lib/ui/select-model.d.ts +51 -0
- package/lib/ui/select-model.js +84 -0
- package/lib/ui/selection-model.d.ts +118 -2
- package/lib/ui/selection-model.js +291 -4
- package/lib/ui/snapshots-view.d.ts +116 -0
- package/lib/ui/snapshots-view.js +141 -0
- package/lib/ui/sync-settings-view.d.ts +295 -0
- package/lib/ui/sync-settings-view.js +280 -0
- package/lib/ui/test-helpers.d.ts +7 -1
- package/lib/ui/test-helpers.js +4 -1
- package/lib/ui/types.d.ts +8 -1
- package/lib/utils/env-lock.d.ts +77 -5
- package/lib/utils/env-lock.js +171 -57
- package/lib/utils/logger.d.ts +17 -13
- package/lib/utils/logger.js +79 -41
- package/lib/utils/paths.d.ts +1 -1
- package/lib/utils/paths.js +2 -2
- package/lib/utils/session-log.d.ts +70 -0
- package/lib/utils/session-log.js +347 -0
- package/lib/utils/zip.d.ts +49 -5
- package/lib/utils/zip.js +240 -51
- package/lib/utils/zstd-frame.d.ts +44 -0
- package/lib/utils/zstd-frame.js +115 -0
- package/package.json +4 -2
- package/src/adapters/agent-instructions.ts +5 -3
- package/src/adapters/agent-presets.ts +5 -3
- package/src/adapters/credentials.ts +19 -22
- package/src/adapters/file-collection.test.ts +256 -0
- package/src/adapters/file-collection.ts +129 -17
- package/src/adapters/index.ts +12 -1
- package/src/adapters/json-section.ts +73 -0
- package/src/adapters/mcp.ts +16 -19
- package/src/adapters/plugin-files.ts +11 -14
- package/src/adapters/plugins.test.ts +1 -1
- package/src/adapters/plugins.ts +39 -42
- package/src/adapters/prompts.ts +16 -20
- package/src/adapters/providers.ts +22 -25
- package/src/adapters/roundtrip.test.ts +44 -0
- package/src/adapters/sessions.test.ts +400 -1
- package/src/adapters/sessions.ts +435 -16
- package/src/adapters/settings.ts +22 -25
- package/src/adapters/skills.ts +5 -3
- package/src/adapters/test-helpers.ts +8 -0
- package/src/adapters/ui.ts +14 -17
- package/src/adapters/workspaces.test.ts +226 -2
- package/src/adapters/workspaces.ts +247 -16
- package/src/cli/index.ts +180 -37
- package/src/cli/sessions-repair.ts +229 -0
- package/src/client/CLIENT_DEPENDENCIES.md +3 -1
- package/src/client/ConfigManagerSection.tsx +50 -46
- package/src/client/about/AboutPanel.tsx +22 -8
- package/src/client/about/about-view.test.ts +53 -6
- package/src/client/about/about-view.ts +26 -2
- package/src/client/api.ts +195 -242
- package/src/client/client-types.ts +2 -2
- package/src/client/common/ConfirmDialog.tsx +3 -2
- package/src/client/common/ContentPicker.tsx +53 -24
- package/src/client/common/CopyButton.tsx +74 -0
- package/src/client/common/ErrorBanner.tsx +3 -2
- package/src/client/common/Icon.tsx +116 -0
- package/src/client/common/Modal.tsx +29 -8
- package/src/client/common/Motion.tsx +70 -0
- package/src/client/common/ProgressBar.tsx +18 -9
- package/src/client/common/ReportView.tsx +128 -54
- package/src/client/common/RunsCenter.tsx +378 -0
- package/src/client/common/Select.tsx +223 -0
- package/src/client/common/Skeleton.tsx +128 -0
- package/src/client/common/client-route-parity.test.ts +171 -0
- package/src/client/common/http-usage-guard.test.ts +163 -0
- package/src/client/common/http.test.ts +225 -0
- package/src/client/common/http.ts +238 -0
- package/src/client/common/morph-icons.test.ts +206 -0
- package/src/client/common/morph-icons.ts +89 -0
- package/src/client/common/plan-text-redaction.test.ts +29 -7
- package/src/client/common/progress-view.test.ts +33 -1
- package/src/client/common/progress-view.ts +17 -0
- package/src/client/common/routes.ts +130 -0
- package/src/client/common/runs-center-guard.test.ts +44 -0
- package/src/client/common/ui.tsx +48 -5
- package/src/client/config-manager.module.css +877 -35
- package/src/client/export/ExportView.tsx +27 -3
- package/src/client/history/HistoryPanel.tsx +30 -30
- package/src/client/history/history-api.ts +34 -61
- package/src/client/icon-layer-guard.test.ts +137 -0
- package/src/client/import/ImportLogPanel.tsx +136 -0
- package/src/client/import/ImportWizardView.tsx +455 -838
- package/src/client/import/PathMappingForm.tsx +12 -1
- package/src/client/import/import-wizard-split.test.ts +101 -0
- package/src/client/import/import-wizard-steps.tsx +352 -0
- package/src/client/import/use-import-wizard-controller.ts +476 -0
- package/src/client/index.ts +4 -6
- package/src/client/locales.ts +258 -123
- package/src/client/lucide-icons.d.ts +11 -0
- package/src/client/market/MarketPanel.tsx +39 -37
- package/src/client/market/MyConfigsInstall.tsx +93 -0
- package/src/client/market/MyConfigsList.tsx +121 -0
- package/src/client/market/MyConfigsLoginCard.tsx +100 -0
- package/src/client/market/MyConfigsView.tsx +148 -476
- package/src/client/market/MyConfigsWizard.tsx +252 -0
- package/src/client/market/market-api.test.ts +36 -0
- package/src/client/market/market-api.ts +13 -70
- package/src/client/market/market-view.ts +1 -1
- package/src/client/market/my-configs-api.ts +17 -71
- package/src/client/market/my-configs-split.test.ts +58 -0
- package/src/client/overview/OverviewPanel.tsx +5 -48
- package/src/client/profiles/ProfilesPanel.tsx +422 -215
- package/src/client/recovery/RecoveryPanel.tsx +121 -5
- package/src/client/recovery/incident-api.ts +91 -0
- package/src/client/recovery/recovery-api.ts +15 -65
- package/src/client/recovery/recovery-locales.ts +56 -0
- package/src/client/recovery/recovery-view.ts +71 -0
- package/src/client/run-store.test.ts +593 -3
- package/src/client/run-store.ts +430 -80
- package/src/client/snapshots/BackupScheduleCard.tsx +434 -0
- package/src/client/snapshots/RestorePlanView.tsx +8 -5
- package/src/client/snapshots/SnapshotsEmptyState.tsx +31 -0
- package/src/client/snapshots/SnapshotsListTable.tsx +97 -0
- package/src/client/snapshots/SnapshotsPanel.tsx +55 -630
- package/src/client/sync/AutosyncCard.tsx +84 -0
- package/src/client/sync/ChannelConfigDialog.tsx +266 -0
- package/src/client/sync/DecryptPasswordCard.tsx +48 -0
- package/src/client/sync/SecurityOptionsCard.tsx +83 -0
- package/src/client/sync/SyncChannelEntryCard.tsx +78 -0
- package/src/client/sync/SyncConfirmView.tsx +10 -8
- package/src/client/sync/SyncHistoryView.tsx +3 -2
- package/src/client/sync/SyncSectionPickerDialog.tsx +182 -0
- package/src/client/sync/SyncSettingsView.test.ts +85 -0
- package/src/client/sync/SyncSettingsView.tsx +247 -667
- package/src/client/sync/history-model.ts +4 -10
- package/src/client/sync/sync-api.ts +59 -100
- package/src/client/sync/sync-locales.ts +16 -2
- package/src/client/sync/sync-view-v2.test.ts +30 -4
- package/src/client/sync/sync-view.ts +67 -17
- package/src/core/analyzer-mapping.test.ts +55 -0
- package/src/core/analyzer.ts +458 -111
- package/src/core/apply-order.test.ts +182 -0
- package/src/core/backup-plan.test.ts +141 -0
- package/src/core/backup-plan.ts +16 -8
- package/src/core/backup.test.ts +310 -0
- package/src/core/backup.ts +174 -23
- package/src/core/base-path-rebase.test.ts +97 -0
- package/src/core/boot-paths.test.ts +35 -0
- package/src/core/boot-paths.ts +29 -0
- package/src/core/boot-rescue.test.ts +108 -0
- package/src/core/boot-rescue.ts +57 -1
- package/src/core/boot-safety.test.ts +138 -0
- package/src/core/boot-safety.ts +248 -0
- package/src/core/conflict-decisions.ts +34 -0
- package/src/core/crash-report.test.ts +25 -41
- package/src/core/crash-report.ts +34 -41
- package/src/core/credential-status.test.ts +35 -0
- package/src/core/credential-status.ts +25 -0
- package/src/core/export-coupling.test.ts +255 -0
- package/src/core/exporter.ts +110 -3
- package/src/core/finalize-order.test.ts +82 -0
- package/src/core/import-sessions-visibility.test.ts +93 -0
- package/src/core/importer.ts +21 -3
- package/src/core/incident-wiring.test.ts +96 -0
- package/src/core/index.ts +10 -0
- package/src/core/journal.test.ts +59 -2
- package/src/core/journal.ts +152 -10
- package/src/core/messages.ts +110 -0
- package/src/core/migration-consult.ts +0 -5
- package/src/core/migration-history.test.ts +3 -5
- package/src/core/model-tools.test.ts +0 -14
- package/src/core/model-tools.ts +6 -8
- package/src/core/path-mapping.ts +33 -0
- package/src/core/phase3-consistency.test.ts +1 -1
- package/src/core/phase3-host.ts +248 -70
- package/src/core/phase3-p2b-fingerprint.test.ts +0 -1
- package/src/core/phase3-production-integration.test.ts +1 -1
- package/src/core/phase4-crash-child.ts +0 -1
- package/src/core/phase4-crash-injection.test.ts +1 -3
- package/src/core/plugin-cli.fs.test.ts +54 -2
- package/src/core/plugin-cli.ts +21 -2
- package/src/core/reconcile.test.ts +62 -0
- package/src/core/reconcile.ts +20 -5
- package/src/core/recovery-orchestrator.test.ts +13 -1
- package/src/core/recovery-orchestrator.ts +1 -1
- package/src/core/restore.ts +10 -4
- package/src/core/rollback.ts +1 -1
- package/src/core/run-registry-runs.test.ts +71 -0
- package/src/core/run-registry.test.ts +58 -7
- package/src/core/run-registry.ts +96 -5
- package/src/core/session-meta.test.ts +59 -1
- package/src/core/session-meta.ts +62 -29
- package/src/core/session-repair.test.ts +91 -0
- package/src/core/session-repair.ts +203 -0
- package/src/core/session-select.test.ts +73 -0
- package/src/core/session-select.ts +131 -0
- package/src/core/smoke.test.ts +5 -3
- package/src/core/startup-barrier.ts +29 -2
- package/src/core/transaction-coordinator.ts +3 -3
- package/src/core/types.ts +253 -0
- package/src/core/validator.ts +0 -1
- package/src/index.sync.test.ts +8 -0
- package/src/index.ts +611 -2922
- package/src/market/git-file-writer.test.ts +1 -1
- package/src/market/index-parser.ts +29 -6
- package/src/market/market.test.ts +146 -1
- package/src/market/my-repo.test.ts +57 -4
- package/src/market/my-repo.ts +0 -7
- package/src/market/prepare.ts +12 -32
- package/src/market/reader.ts +0 -1
- package/src/market/security.ts +3 -11
- package/src/profiles/dsh-profile-launcher.test.ts +359 -0
- package/src/profiles/dsh-profile-launcher.ts +473 -0
- package/src/profiles/dsh-profile-manager.test.ts +123 -59
- package/src/profiles/dsh-profile-manager.ts +148 -51
- package/src/profiles/dsh-profile-runtime.test.ts +196 -0
- package/src/profiles/dsh-profile-runtime.ts +228 -0
- package/src/profiles/dsh-profile-shared.ts +126 -9
- package/src/profiles/index.ts +30 -4
- package/src/profiles/process-control.ts +99 -0
- package/src/routes/backup.ts +103 -0
- package/src/routes/consult.ts +139 -0
- package/src/routes/context.ts +10 -0
- package/src/routes/history.ts +56 -0
- package/src/routes/import.ts +399 -0
- package/src/routes/index.ts +36 -0
- package/src/routes/kit.ts +223 -0
- package/src/routes/market.ts +275 -0
- package/src/routes/me.ts +168 -0
- package/src/routes/prefs.ts +104 -0
- package/src/routes/profiles.ts +252 -0
- package/src/routes/recovery.ts +113 -0
- package/src/routes/snapshots.ts +219 -0
- package/src/routes/sync.ts +810 -0
- package/src/schema/config.ts +96 -91
- package/src/schema/index.ts +33 -1
- package/src/schema/manifest.ts +3 -0
- package/src/schema/registry.test.ts +293 -0
- package/src/schema/section-registry.ts +463 -0
- package/src/schema/types.ts +13 -3
- package/src/schema/versions.ts +31 -1
- package/src/security/secret-scanner.ts +1 -1
- package/src/security/security.test.ts +145 -2
- package/src/security/zip-security.ts +20 -92
- package/src/sync/ancestor.test.ts +0 -1
- package/src/sync/ancestor.ts +23 -0
- package/src/sync/autosync-config.ts +9 -18
- package/src/sync/autosync-scheduler.test.ts +60 -3
- package/src/sync/autosync-scheduler.ts +45 -19
- package/src/sync/backup-schedule-config.ts +0 -1
- package/src/sync/backup-scheduler.test.ts +15 -2
- package/src/sync/blob-store.test.ts +191 -0
- package/src/sync/blob-store.ts +139 -0
- package/src/sync/git/git-transport.test.ts +203 -1
- package/src/sync/git/git-transport.ts +173 -24
- package/src/sync/github-auth.ts +0 -2
- package/src/sync/layout.ts +62 -8
- package/src/sync/risk.test.ts +32 -1
- package/src/sync/risk.ts +26 -31
- package/src/sync/session-tombstones.test.ts +87 -0
- package/src/sync/session-tombstones.ts +123 -0
- package/src/sync/sync-config.test.ts +132 -0
- package/src/sync/sync-config.ts +47 -6
- package/src/sync/sync-credentials.test.ts +77 -0
- package/src/sync/sync-engine.test.ts +799 -8
- package/src/sync/sync-engine.ts +322 -51
- package/src/sync/sync-history.ts +0 -1
- package/src/sync/sync-selection.test.ts +43 -7
- package/src/sync/sync-selection.ts +56 -24
- package/src/sync/sync-state.test.ts +83 -0
- package/src/sync/sync-state.ts +58 -7
- package/src/sync/transport.ts +191 -0
- package/src/sync/ui-prefs.ts +10 -6
- package/src/sync/webdav/webdav-transport.test.ts +122 -2
- package/src/sync/webdav/webdav-transport.ts +256 -37
- package/src/ui/dsh-profiles-view.test.ts +87 -12
- package/src/ui/dsh-profiles-view.ts +106 -17
- package/src/ui/export-flow.ts +65 -18
- package/src/ui/i18n.test.ts +147 -0
- package/src/ui/i18n.ts +25 -4
- package/src/ui/import-log.test.ts +106 -0
- package/src/ui/import-log.ts +158 -0
- package/src/ui/import-stepper.test.ts +25 -1
- package/src/ui/import-stepper.ts +18 -0
- package/src/ui/import-wizard.test.ts +168 -2
- package/src/ui/import-wizard.ts +175 -8
- package/src/ui/market-import.test.ts +0 -1
- package/src/ui/mid-ellipsis.test.ts +160 -0
- package/src/ui/mid-ellipsis.ts +37 -0
- package/src/ui/my-configs-view.test.ts +222 -0
- package/src/ui/my-configs-view.ts +206 -0
- package/src/ui/progress.ts +6 -0
- package/src/ui/report.test.ts +32 -2
- package/src/ui/report.ts +52 -0
- package/src/ui/runs-view.test.ts +152 -0
- package/src/ui/runs-view.ts +207 -0
- package/src/ui/select-model.test.ts +75 -0
- package/src/ui/select-model.ts +92 -0
- package/src/ui/selection-model.test.ts +315 -12
- package/src/ui/selection-model.ts +327 -4
- package/src/ui/snapshots-view.test.ts +228 -0
- package/src/ui/snapshots-view.ts +233 -0
- package/src/ui/sync-settings-view.test.ts +348 -0
- package/src/ui/sync-settings-view.ts +516 -0
- package/src/ui/test-helpers.ts +8 -1
- package/src/ui/types.ts +10 -1
- package/src/utils/env-lock.test.ts +290 -107
- package/src/utils/env-lock.ts +209 -54
- package/src/utils/logger.test.ts +178 -1
- package/src/utils/logger.ts +81 -44
- package/src/utils/paths.ts +2 -2
- package/src/utils/session-log.test.ts +136 -0
- package/src/utils/session-log.ts +344 -0
- package/src/utils/zip.test.ts +284 -0
- package/src/utils/zip.ts +226 -52
- package/src/utils/zstd-frame.test.ts +80 -0
- package/src/utils/zstd-frame.ts +131 -0
- package/lib/core/config-lifecycle.d.ts +0 -180
- package/lib/core/config-lifecycle.js +0 -481
- package/lib/core/config-snapshot.d.ts +0 -135
- package/lib/core/config-snapshot.js +0 -424
- package/lib/core/config-state.d.ts +0 -70
- package/lib/core/config-state.js +0 -177
- package/lib/core/undo.d.ts +0 -73
- package/lib/core/undo.js +0 -87
- package/lib/core/watcher.d.ts +0 -101
- package/lib/core/watcher.js +0 -219
- package/src/client/lifecycle/LifecyclePanel.tsx +0 -525
- package/src/client/lifecycle/lifecycle-api.ts +0 -249
- package/src/core/config-lifecycle.test.ts +0 -727
- package/src/core/config-lifecycle.ts +0 -573
- package/src/core/config-snapshot.test.ts +0 -369
- package/src/core/config-snapshot.ts +0 -522
- package/src/core/config-state.test.ts +0 -381
- package/src/core/config-state.ts +0 -207
- package/src/core/phase1-wiring.test.ts +0 -139
- package/src/core/undo.ts +0 -116
- package/src/core/watcher.test.ts +0 -326
- package/src/core/watcher.ts +0 -263
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
*
|
|
7
7
|
* 文件内容以真实文件进入 ZIP(custom/skills/… 等前缀由 exporter 按 SECTION_FILE_PREFIXES 处理)。
|
|
8
8
|
* 幂等:相对路径 + 内容 SHA-256 hash 比对(重复导入 → Skip)。
|
|
9
|
+
*
|
|
10
|
+
* 导出的**单分区字节闸门**(审计 core-flow F-12 / sync#F-12):累计到 MAX_FILE_SECTION_BYTES 后,
|
|
11
|
+
* 放不下的单元**整块**剔除并写进告警(见 export())。覆盖 skills / agentPresets / sessions;
|
|
12
|
+
* agentInstructions(单文件 AGENTS.md)与 self(白名单配置小文件)各自覆写 export,不在本闸门射程内。
|
|
9
13
|
*/
|
|
10
14
|
import path from 'node:path';
|
|
11
15
|
import { sha256Hex } from '../utils/hashing.js';
|
|
@@ -13,7 +17,40 @@ import { isReservedInternalRel, normalizePath } from '../utils/paths.js';
|
|
|
13
17
|
import { msgOf, zhMsg } from '../core/messages.js';
|
|
14
18
|
import { linkWarnings, listFilesDetailed } from './link-report.js';
|
|
15
19
|
import { defaultUnitId, unitAllowed, unitsFromFiles } from './units.js';
|
|
20
|
+
import { validateJsonSection } from './json-section.js';
|
|
21
|
+
/**
|
|
22
|
+
* 文件类分区导出的**单分区累计字节闸门**:分区内文件内容合计放不下的单元整块剔除(见 export())。
|
|
23
|
+
*
|
|
24
|
+
* 取值依据(不是随手拍的数):
|
|
25
|
+
* 1) **对称性** —— 导入侧对上传的备份包有硬上限 256 MiB(MAX_UPLOAD_BYTES,src/index.ts 与
|
|
26
|
+
* src/routes/kit.ts 的上传路径);导出侧此前**没有任何体积约束**,于是会出现「导出成功、
|
|
27
|
+
* 传不回来」(审计 core-flow F-12 / sync#F-12)。取同一个 256 MiB 作**单分区**上限:
|
|
28
|
+
* 任何单个分区都落在导入侧上传路径能收的范围内。
|
|
29
|
+
* 2) **内存峰值** —— 导出时文件内容以完整 Uint8Array 驻留内存(ZIP 组装前全量在内存里),同步通道
|
|
30
|
+
* 还要再写一份。闸门把「单分区常驻」钳在 256 MiB 以内(峰值 ≈ 上限 + 正在读的那个单元),
|
|
31
|
+
* 不再是「会话附件多大就多吃多少」。
|
|
32
|
+
* 3) **与既有同类上限同量级** —— MAX_MARKET_ZIP_BYTES = 64 MiB、DEFAULT_MAX_JSON_BYTES = 64 MiB、
|
|
33
|
+
* MAX_LOCAL_TARBALL_BYTES = 100 MiB、MAX_PATCH_FILE_BYTES = 2 MiB。文件类分区装的是**用户真实
|
|
34
|
+
* 文件**,所以取「导入侧能收」的 256 MiB,而不是为省内存随意调小(那会平白少带用户数据)。
|
|
35
|
+
* 4) **为什么按分区而不是按整包** —— 整包体积由用户勾选跨分区决定;闸门要能给出「哪些分区、哪些
|
|
36
|
+
* 单元没进去」的可执行信息,落在分区/单元层才可解释。
|
|
37
|
+
*
|
|
38
|
+
* 超限时**绝不静默**:被整块剔除的单元清单进 ExportSection.warnings(导出报告可见)。
|
|
39
|
+
*/
|
|
40
|
+
export const MAX_FILE_SECTION_BYTES = 256 * 1024 * 1024;
|
|
41
|
+
/** 字节闸门告警里最多列出的单元数(其余折叠成 "(+ N)",避免大分区把报告撑爆;与 link-report 同口径) */
|
|
42
|
+
const MAX_UNITS_PER_GATE_WARNING = 5;
|
|
43
|
+
/** 告警文案里的体积(人类可读;纯数值格式化,不含用户可见散文) */
|
|
44
|
+
function formatBytes(bytes) {
|
|
45
|
+
if (bytes < 1024)
|
|
46
|
+
return `${bytes} B`;
|
|
47
|
+
if (bytes < 1024 * 1024)
|
|
48
|
+
return `${(bytes / 1024).toFixed(1)} KiB`;
|
|
49
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MiB`;
|
|
50
|
+
}
|
|
16
51
|
export class FileCollectionAdapter {
|
|
52
|
+
/** 文件集合:`relativePath` 是身份而非配置 → 永不被导入时的前缀映射改写(见 ConfigAdapter.fileCollection) */
|
|
53
|
+
fileCollection = true;
|
|
17
54
|
/**
|
|
18
55
|
* 最小可拆单元的 id(相对 baseDir 的路径)。
|
|
19
56
|
*
|
|
@@ -31,6 +68,16 @@ export class FileCollectionAdapter {
|
|
|
31
68
|
const prefix = this.baseDir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
32
69
|
return rel.replace(new RegExp('^' + prefix + '[\\\\/]'), '');
|
|
33
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* 单分区累计字节上限(缺省 MAX_FILE_SECTION_BYTES = 256 MiB,见该常量注释)。
|
|
73
|
+
*
|
|
74
|
+
* 生产代码不覆写;留成受保护方法只为让测试能构造「超限」场景(真实阈值 256 MiB 无法在单测里
|
|
75
|
+
* 造出来而不吃掉 256 MiB 内存)。若要给用户配置入口,应走 ExportOptions(src/core/types.ts),
|
|
76
|
+
* 而不是在子类里飘一个隐式默认值。
|
|
77
|
+
*/
|
|
78
|
+
sectionByteLimit() {
|
|
79
|
+
return MAX_FILE_SECTION_BYTES;
|
|
80
|
+
}
|
|
34
81
|
/**
|
|
35
82
|
* 条目级选择(Phase 1):只导出白名单命中的单元。
|
|
36
83
|
*
|
|
@@ -66,6 +113,12 @@ export class FileCollectionAdapter {
|
|
|
66
113
|
if (restricted !== null)
|
|
67
114
|
warnings.push(...restricted.warnings);
|
|
68
115
|
const keep = restricted?.keep ?? null;
|
|
116
|
+
// ① 先按「单元」分组(零 I/O:只看路径)。单元的成员文件**不保证**在遍历结果里连续,
|
|
117
|
+
// 必须整组一起判定,否则同一单元会被拦腰劈开(半个技能目录 / 半个会话目录)。
|
|
118
|
+
// `considered` 保序记录,收尾按它还原改造前的文件顺序(未触发闸门时逐项一致)。
|
|
119
|
+
const considered = [];
|
|
120
|
+
const unitOrder = [];
|
|
121
|
+
const unitEntries = new Map();
|
|
69
122
|
for (const rel of rels) {
|
|
70
123
|
const relPath = this.relPathOf(rel);
|
|
71
124
|
const unitId = this.unitIdOf(relPath);
|
|
@@ -73,8 +126,59 @@ export class FileCollectionAdapter {
|
|
|
73
126
|
continue;
|
|
74
127
|
if (!unitAllowed(allow, `${this.id}:${unitId}`))
|
|
75
128
|
continue;
|
|
76
|
-
|
|
77
|
-
|
|
129
|
+
let members = unitEntries.get(unitId);
|
|
130
|
+
if (members === undefined) {
|
|
131
|
+
members = [];
|
|
132
|
+
unitEntries.set(unitId, members);
|
|
133
|
+
unitOrder.push(unitId);
|
|
134
|
+
}
|
|
135
|
+
members.push({ rel, relPath });
|
|
136
|
+
considered.push(rel);
|
|
137
|
+
}
|
|
138
|
+
// ② 逐单元读取 + 累计字节闸门(审计 core-flow F-12 / sync#F-12)。超出 sectionByteLimit() 的
|
|
139
|
+
// 单元**整块**不进备份(仓库语义:单元不可拆分 —— 宁可少带,不可半带);一旦判定该单元放不下,
|
|
140
|
+
// 它的剩余文件不再读盘(省 I/O,也不为「统计精确」多吃内存)。放不下的单元跳过后**继续尝试
|
|
141
|
+
// 后面的单元**:一个巨型会话不该把它之后的所有内容一起带走(后面的小单元仍可能入选)。
|
|
142
|
+
const limit = this.sectionByteLimit();
|
|
143
|
+
let usedBytes = 0;
|
|
144
|
+
const droppedUnits = [];
|
|
145
|
+
const keptByRel = new Map();
|
|
146
|
+
for (const unitId of unitOrder) {
|
|
147
|
+
const room = limit - usedBytes;
|
|
148
|
+
const pending = [];
|
|
149
|
+
let unitBytes = 0;
|
|
150
|
+
for (const member of unitEntries.get(unitId) ?? []) {
|
|
151
|
+
const data = await ctx.fs.readFile(member.rel);
|
|
152
|
+
unitBytes += data.byteLength;
|
|
153
|
+
if (unitBytes > room)
|
|
154
|
+
break;
|
|
155
|
+
pending.push({ rel: member.rel, file: { relativePath: member.relPath, data, contentHash: sha256Hex(data) } });
|
|
156
|
+
}
|
|
157
|
+
if (unitBytes > room) {
|
|
158
|
+
droppedUnits.push(unitId);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
usedBytes += unitBytes;
|
|
162
|
+
for (const p of pending)
|
|
163
|
+
keptByRel.set(p.rel, p.file);
|
|
164
|
+
}
|
|
165
|
+
// ③ 按 ① 的顺序落盘(未触发闸门时与改造前的文件顺序逐项一致)
|
|
166
|
+
for (const rel of considered) {
|
|
167
|
+
const file = keptByRel.get(rel);
|
|
168
|
+
if (file !== undefined)
|
|
169
|
+
files.push(file);
|
|
170
|
+
}
|
|
171
|
+
// 绝不静默:被整块剔除的单元写进告警(导出报告可见),并给出上限与实际保留量
|
|
172
|
+
if (droppedUnits.length > 0) {
|
|
173
|
+
const shown = droppedUnits.slice(0, MAX_UNITS_PER_GATE_WARNING);
|
|
174
|
+
const rest = droppedUnits.length - shown.length;
|
|
175
|
+
warnings.push(msgOf(ctx)('adapter.fileSectionByteLimit', {
|
|
176
|
+
type: this.displayName,
|
|
177
|
+
limit: formatBytes(limit),
|
|
178
|
+
kept: formatBytes(usedBytes),
|
|
179
|
+
count: String(droppedUnits.length),
|
|
180
|
+
detail: (rest > 0 ? [...shown, `(+ ${rest})`] : shown).join(', '),
|
|
181
|
+
}));
|
|
78
182
|
}
|
|
79
183
|
if (rels.length === 0)
|
|
80
184
|
warnings.push(msgOf(ctx)('adapter.dirEmpty', { type: this.displayName }));
|
|
@@ -152,25 +256,33 @@ export class FileCollectionAdapter {
|
|
|
152
256
|
await ctx.target.fs.writeFile(path.join(this.baseDir, ref), file.data);
|
|
153
257
|
return { ok: true };
|
|
154
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* 结构校验(5 个文件类分区共用:skills / agentPresets / agentInstructions / sessions / self)。
|
|
261
|
+
*
|
|
262
|
+
* **整段样板都接入共享骨架 `validateJsonSection`** —— t7 接入 version 守卫与形状检查收尾,t11 接入
|
|
263
|
+
* object 守卫;dataVersion 由注册表按 `this.id` 派生,等价于此前的字面量 `!== 1`
|
|
264
|
+
* (SECTION_DATA_VERSION = 1)。本类里已无手写样板。
|
|
265
|
+
*
|
|
266
|
+
* object 守卫的**文案**为什么还要参数:文件类分区历史上用的是**专用消息键**
|
|
267
|
+
* `adapter.validate.fileSection`('文件分区数据必须是对象',不含 `{subject}` 占位符),与骨架缺省的
|
|
268
|
+
* `adapter.validate.object` + `{subject}` 是**键**级差异 —— 第 5 参 subject 补不了它。t11 给骨架加了
|
|
269
|
+
* 可选第 6 参 `objectMessageKey`,这里传专用键:5 个分区的用户可见报错文案与改造前**逐字相同**,
|
|
270
|
+
* 同时不放任何手写样板。等价由 src/adapters/file-collection.test.ts 与 outputs/t7-equiv/ 的差分脚本钉住。
|
|
271
|
+
*/
|
|
155
272
|
async validate(data, msg = zhMsg) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
else {
|
|
167
|
-
for (const f of data.files) {
|
|
168
|
-
if (f === null || typeof f !== 'object' || typeof f.relativePath !== 'string' || f.relativePath === '') {
|
|
169
|
-
issues.push({ path: 'files[]', message: msg('adapter.validate.fileRelativePath'), severity: 'error' });
|
|
273
|
+
// 第 5 参 subject 传 this.id 即骨架缺省语义(专用键不含 {subject},取值不影响输出)
|
|
274
|
+
return validateJsonSection(this.id, data, msg, (section, issues) => {
|
|
275
|
+
if (!Array.isArray(section.files)) {
|
|
276
|
+
issues.push({ path: 'files', message: msg('adapter.validate.array', { subject: 'files' }), severity: 'error' });
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
for (const f of section.files) {
|
|
280
|
+
if (f === null || typeof f !== 'object' || typeof f.relativePath !== 'string' || f.relativePath === '') {
|
|
281
|
+
issues.push({ path: 'files[]', message: msg('adapter.validate.fileRelativePath'), severity: 'error' });
|
|
282
|
+
}
|
|
170
283
|
}
|
|
171
284
|
}
|
|
172
|
-
}
|
|
173
|
-
return { valid: issues.filter((i) => i.severity === 'error').length === 0, issues };
|
|
285
|
+
}, this.id, 'adapter.validate.fileSection');
|
|
174
286
|
}
|
|
175
287
|
}
|
|
176
288
|
//# sourceMappingURL=file-collection.js.map
|
package/lib/adapters/index.d.ts
CHANGED
|
@@ -55,3 +55,4 @@ export { PluginFilesAdapter, DEFAULT_PLUGIN_FILE_WHITELIST } from './plugin-file
|
|
|
55
55
|
export { SessionsAdapter } from './sessions.ts';
|
|
56
56
|
export { SelfAdapter, SELF_CONFIG_FILES } from './self.ts';
|
|
57
57
|
export { FileCollectionAdapter } from './file-collection.ts';
|
|
58
|
+
export { validateJsonSection, type SectionIssues } from './json-section.ts';
|
package/lib/adapters/index.js
CHANGED
|
@@ -52,4 +52,15 @@ export { PluginFilesAdapter, DEFAULT_PLUGIN_FILE_WHITELIST } from './plugin-file
|
|
|
52
52
|
export { SessionsAdapter } from './sessions.js';
|
|
53
53
|
export { SelfAdapter, SELF_CONFIG_FILES } from './self.js';
|
|
54
54
|
export { FileCollectionAdapter } from './file-collection.js';
|
|
55
|
+
/* JSON 分区共享校验骨架(本导出是其接入点)。收敛轨迹:
|
|
56
|
+
* · t31 抽出骨架,settings / ui / providers / plugins / mcp / prompts / credentials /
|
|
57
|
+
* pluginFiles 八个分区的样板并入;
|
|
58
|
+
* · t7 接上 workspaces.ts 与 file-collection.ts 基类的 version 守卫 + 形状检查收尾;
|
|
59
|
+
* · t11 给骨架加了可选第 6 参 `objectMessageKey`(object 错误的文案键,缺省
|
|
60
|
+
* `adapter.validate.object`),file-collection 的 object 守卫也并入并沿用文件类分区原专用键
|
|
61
|
+
* `adapter.validate.fileSection`,故 5 个文件类分区的用户可见报错文案逐字不变。
|
|
62
|
+
* 现状:**9 个分区全部走共享骨架**(settings / ui / providers / plugins / mcp / prompts /
|
|
63
|
+
* credentialsStatus / pluginFiles / workspaces),文件类基类(skills / agentPresets /
|
|
64
|
+
* agentInstructions / sessions / self)同样走它 —— src/adapters 下不再有任何手写 validate 样板。 */
|
|
65
|
+
export { validateJsonSection } from './json-section.js';
|
|
55
66
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { SectionId } from '../schema/types.ts';
|
|
2
|
+
import type { MsgFunc, zh } from '../core/messages.ts';
|
|
3
|
+
import type { ValidationResult } from '../core/types.ts';
|
|
4
|
+
/** 校验问题列表(各 adapter 的形状检查直接 push 到这里,与历史 `issues` 数组同一形状)。 */
|
|
5
|
+
export type SectionIssues = ValidationResult['issues'];
|
|
6
|
+
/**
|
|
7
|
+
* JSON 分区通用结构校验骨架。
|
|
8
|
+
*
|
|
9
|
+
* 执行顺序(与改造前逐字一致,保证行为等价):
|
|
10
|
+
* 1. object 守卫:非对象 → **直接返回**单条 `objectMessageKey` 错误(缺省 `adapter.validate.object`;后续检查不再执行);
|
|
11
|
+
* 2. version 守卫:`version !== sectionMeta(sectionId).dataVersion` → push 一条 `version` 错误,
|
|
12
|
+
* **不提前返回**(继续做形状检查,与历史实现一致);
|
|
13
|
+
* 3. `shape` 回调:分区特有的载荷形状检查(可选)。
|
|
14
|
+
*
|
|
15
|
+
* @param sectionId 分区 id —— 同时是 object 错误的默认 subject 与 dataVersion 的查表键
|
|
16
|
+
* @param data 反序列化后的分区载荷(来自不可信备份 → 必须按 unknown 处理)
|
|
17
|
+
* @param msg 文案翻译器(adapter 的 `validate(data, msg = zhMsg)` 原样传入)
|
|
18
|
+
* @param shape 分区特有的形状检查(在 version 守卫之后调用)
|
|
19
|
+
* @param subject object 错误里的显示名;缺省 = sectionId。历史上 credentials 用的是
|
|
20
|
+
* `'credentials'`(而非分区 id `credentialsStatus`),此参数为保留该原文案而存在 ——
|
|
21
|
+
* 改文案属独立的行为变更,不在本任务射程内。
|
|
22
|
+
* @param objectMessageKey object 错误的**消息键**(t11 新增,可选);缺省 `adapter.validate.object`
|
|
23
|
+
* (`'{subject} 数据必须是对象'`)。为什么需要它:文件类分区历史上用的是专用键
|
|
24
|
+
* `adapter.validate.fileSection`(`'文件分区数据必须是对象'`,**不含** `{subject}` 占位符),
|
|
25
|
+
* 那是**键**级差异 —— `subject` 参数补不了它(把 subject 拼成"文件分区"后中文模板仍多一个空格),
|
|
26
|
+
* 而硬换键会让 skills / agentPresets / agentInstructions / sessions / self 五个分区的用户可见
|
|
27
|
+
* 报错文案一起变。有了这个可选键,那处也能并入骨架而文案逐字不变。
|
|
28
|
+
* 键必须存在于 `src/core/messages.ts` 目录(`MsgFunc` 形参是 string,编译器只能校验到键名集合)。
|
|
29
|
+
*/
|
|
30
|
+
export declare function validateJsonSection<S extends {
|
|
31
|
+
version?: unknown;
|
|
32
|
+
}>(sectionId: SectionId, data: unknown, msg: MsgFunc, shape?: (section: S, issues: SectionIssues) => void, subject?: string, objectMessageKey?: keyof typeof zh): ValidationResult;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON 分区 adapter 的共享骨架(t31,批次 4)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么存在:改动前 9 个「有 JSON 载荷」的分区的 `validate()` 都以**同一段样板**开头 ——
|
|
5
|
+
* 先是 object 守卫,再是 `data.version !== 1` 守卫,最后才是各分区自己的载荷形状检查;
|
|
6
|
+
* 这段样板在每个文件里逐字抄了一遍(审计 sync#F-08 / infra#C1)。本模块把它收敛为一份,
|
|
7
|
+
* 并让「期望版本」直接取自注册表 `dataVersion`(不再各写 `!== 1` 字面量)。
|
|
8
|
+
*
|
|
9
|
+
* 与注册表的分工:结构校验的**描述符**(zipPath / 载荷形态 / dataVersion)在
|
|
10
|
+
* `src/schema/section-registry.ts`;本模块只提供「按该描述符执行校验」的通用算法,
|
|
11
|
+
* 各 adapter 仍负责自己特有的形状检查(用 `shape` 回调注入)。
|
|
12
|
+
*
|
|
13
|
+
* 分层:只 import schema 与 core 的类型 —— 不 import node 内置模块(client bundle 自包含铁律)。
|
|
14
|
+
*/
|
|
15
|
+
import { sectionMeta } from '../schema/section-registry.js';
|
|
16
|
+
/**
|
|
17
|
+
* JSON 分区通用结构校验骨架。
|
|
18
|
+
*
|
|
19
|
+
* 执行顺序(与改造前逐字一致,保证行为等价):
|
|
20
|
+
* 1. object 守卫:非对象 → **直接返回**单条 `objectMessageKey` 错误(缺省 `adapter.validate.object`;后续检查不再执行);
|
|
21
|
+
* 2. version 守卫:`version !== sectionMeta(sectionId).dataVersion` → push 一条 `version` 错误,
|
|
22
|
+
* **不提前返回**(继续做形状检查,与历史实现一致);
|
|
23
|
+
* 3. `shape` 回调:分区特有的载荷形状检查(可选)。
|
|
24
|
+
*
|
|
25
|
+
* @param sectionId 分区 id —— 同时是 object 错误的默认 subject 与 dataVersion 的查表键
|
|
26
|
+
* @param data 反序列化后的分区载荷(来自不可信备份 → 必须按 unknown 处理)
|
|
27
|
+
* @param msg 文案翻译器(adapter 的 `validate(data, msg = zhMsg)` 原样传入)
|
|
28
|
+
* @param shape 分区特有的形状检查(在 version 守卫之后调用)
|
|
29
|
+
* @param subject object 错误里的显示名;缺省 = sectionId。历史上 credentials 用的是
|
|
30
|
+
* `'credentials'`(而非分区 id `credentialsStatus`),此参数为保留该原文案而存在 ——
|
|
31
|
+
* 改文案属独立的行为变更,不在本任务射程内。
|
|
32
|
+
* @param objectMessageKey object 错误的**消息键**(t11 新增,可选);缺省 `adapter.validate.object`
|
|
33
|
+
* (`'{subject} 数据必须是对象'`)。为什么需要它:文件类分区历史上用的是专用键
|
|
34
|
+
* `adapter.validate.fileSection`(`'文件分区数据必须是对象'`,**不含** `{subject}` 占位符),
|
|
35
|
+
* 那是**键**级差异 —— `subject` 参数补不了它(把 subject 拼成"文件分区"后中文模板仍多一个空格),
|
|
36
|
+
* 而硬换键会让 skills / agentPresets / agentInstructions / sessions / self 五个分区的用户可见
|
|
37
|
+
* 报错文案一起变。有了这个可选键,那处也能并入骨架而文案逐字不变。
|
|
38
|
+
* 键必须存在于 `src/core/messages.ts` 目录(`MsgFunc` 形参是 string,编译器只能校验到键名集合)。
|
|
39
|
+
*/
|
|
40
|
+
export function validateJsonSection(sectionId, data, msg, shape, subject = sectionId, objectMessageKey = 'adapter.validate.object') {
|
|
41
|
+
if (data === null || typeof data !== 'object') {
|
|
42
|
+
return {
|
|
43
|
+
valid: false,
|
|
44
|
+
issues: [{ path: '$', message: msg(objectMessageKey, { subject }), severity: 'error' }],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const section = data;
|
|
48
|
+
const issues = [];
|
|
49
|
+
const expectedVersion = sectionMeta(sectionId).dataVersion;
|
|
50
|
+
if (section.version !== expectedVersion) {
|
|
51
|
+
issues.push({
|
|
52
|
+
path: 'version',
|
|
53
|
+
message: msg('adapter.validate.version', { value: String(section.version) }),
|
|
54
|
+
severity: 'error',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (shape !== undefined)
|
|
58
|
+
shape(section, issues);
|
|
59
|
+
return { valid: issues.filter((i) => i.severity === 'error').length === 0, issues };
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=json-section.js.map
|
package/lib/adapters/mcp.d.ts
CHANGED
|
@@ -18,9 +18,9 @@ export declare function extractMcpServers(lines: {
|
|
|
18
18
|
export declare function buildMcpPatchLine(lineId: string, server: McpServerEntry): Record<string, unknown>;
|
|
19
19
|
export declare class McpAdapter implements ConfigAdapter<McpExportSection> {
|
|
20
20
|
readonly id: 'mcp';
|
|
21
|
-
readonly displayName
|
|
22
|
-
readonly defaultIncluded
|
|
23
|
-
readonly portability:
|
|
21
|
+
readonly displayName: string;
|
|
22
|
+
readonly defaultIncluded: boolean;
|
|
23
|
+
readonly portability: import("../schema/section-registry.ts").SectionPortability;
|
|
24
24
|
export(ctx: HostContext, _options: ExportOptions): Promise<ExportSection<McpExportSection>>;
|
|
25
25
|
analyzeImport(data: McpExportSection, ctx: ImportContext): Promise<PlanItem[]>;
|
|
26
26
|
applyItem(item: PlanItem, ctx: ImportContext): Promise<ApplyResult>;
|
package/lib/adapters/mcp.js
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { isDeepStrictEqual } from 'node:util';
|
|
10
10
|
import { msgOf, zhMsg } from '../core/messages.js';
|
|
11
|
+
import { sectionMeta } from '../schema/section-registry.js';
|
|
12
|
+
import { validateJsonSection } from './json-section.js';
|
|
11
13
|
import { USER_PATCH_FILE } from './plugins.js';
|
|
12
14
|
/** 从 patch 行数组中提取 MCP server 条目(以 config.serverName 存在为判定) */
|
|
13
15
|
export function extractMcpServers(lines) {
|
|
@@ -77,9 +79,10 @@ function newLineId(serverName) {
|
|
|
77
79
|
}
|
|
78
80
|
export class McpAdapter {
|
|
79
81
|
id = 'mcp';
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
// 元数据唯一来源 = 注册表(t31):不再与 ui/export-flow.ts 的导出目录各写一份
|
|
83
|
+
displayName = sectionMeta('mcp').displayName;
|
|
84
|
+
defaultIncluded = sectionMeta('mcp').defaultIncluded;
|
|
85
|
+
portability = sectionMeta('mcp').portability;
|
|
83
86
|
async export(ctx, _options) {
|
|
84
87
|
const warnings = [];
|
|
85
88
|
let lines = [];
|
|
@@ -155,24 +158,18 @@ export class McpAdapter {
|
|
|
155
158
|
return { ok: true, needsRestart: true, message: msg('adapter.mcpWritten', { serverName }) };
|
|
156
159
|
}
|
|
157
160
|
async validate(data, msg = zhMsg) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
for (const s of data.servers) {
|
|
170
|
-
if (s === null || typeof s !== 'object' || typeof s.serverName !== 'string' || s.serverName === '') {
|
|
171
|
-
issues.push({ path: 'servers[]', message: msg('adapter.validate.serverName'), severity: 'error' });
|
|
161
|
+
return validateJsonSection('mcp', data, msg, (section, issues) => {
|
|
162
|
+
if (!Array.isArray(section.servers)) {
|
|
163
|
+
issues.push({ path: 'servers', message: msg('adapter.validate.array', { subject: 'servers' }), severity: 'error' });
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
for (const s of section.servers) {
|
|
167
|
+
if (s === null || typeof s !== 'object' || typeof s.serverName !== 'string' || s.serverName === '') {
|
|
168
|
+
issues.push({ path: 'servers[]', message: msg('adapter.validate.serverName'), severity: 'error' });
|
|
169
|
+
}
|
|
172
170
|
}
|
|
173
171
|
}
|
|
174
|
-
}
|
|
175
|
-
return { valid: issues.filter((i) => i.severity === 'error').length === 0, issues };
|
|
172
|
+
});
|
|
176
173
|
}
|
|
177
174
|
}
|
|
178
175
|
//# sourceMappingURL=mcp.js.map
|
|
@@ -4,9 +4,9 @@ import type { ApplyResult, ConfigAdapter, ExportOptions, ExportSection, ExportUn
|
|
|
4
4
|
export declare const DEFAULT_PLUGIN_FILE_WHITELIST: readonly string[];
|
|
5
5
|
export declare class PluginFilesAdapter implements ConfigAdapter<FilesSection> {
|
|
6
6
|
readonly id: 'pluginFiles';
|
|
7
|
-
readonly displayName
|
|
8
|
-
readonly defaultIncluded
|
|
9
|
-
readonly portability:
|
|
7
|
+
readonly displayName: string;
|
|
8
|
+
readonly defaultIncluded: boolean;
|
|
9
|
+
readonly portability: import("../schema/section-registry.ts").SectionPortability;
|
|
10
10
|
private readonly whitelist;
|
|
11
11
|
/** 约定配置目录(相对 ~/.dsh 根,如 'plugin-config');递归收集其下所有文件。undefined = 不收集。 */
|
|
12
12
|
private readonly collectDir?;
|
|
@@ -11,12 +11,15 @@ import { msgOf, zhMsg } from '../core/messages.js';
|
|
|
11
11
|
import { linkWarnings, listFilesDetailed } from './link-report.js';
|
|
12
12
|
import { isPathSafe, isReservedInternalRel } from '../utils/paths.js';
|
|
13
13
|
import { unitAllowed, unitsFromFiles } from './units.js';
|
|
14
|
+
import { sectionMeta } from '../schema/section-registry.js';
|
|
15
|
+
import { validateJsonSection } from './json-section.js';
|
|
14
16
|
export const DEFAULT_PLUGIN_FILE_WHITELIST = ['dsh-ssh.json', 'pet.json'];
|
|
15
17
|
export class PluginFilesAdapter {
|
|
16
18
|
id = 'pluginFiles';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
// 元数据唯一来源 = 注册表(t31):不再与 ui/export-flow.ts 的导出目录各写一份
|
|
20
|
+
displayName = sectionMeta('pluginFiles').displayName;
|
|
21
|
+
defaultIncluded = sectionMeta('pluginFiles').defaultIncluded;
|
|
22
|
+
portability = sectionMeta('pluginFiles').portability;
|
|
20
23
|
whitelist;
|
|
21
24
|
/** 约定配置目录(相对 ~/.dsh 根,如 'plugin-config');递归收集其下所有文件。undefined = 不收集。 */
|
|
22
25
|
collectDir;
|
|
@@ -138,17 +141,11 @@ export class PluginFilesAdapter {
|
|
|
138
141
|
return { ok: true };
|
|
139
142
|
}
|
|
140
143
|
async validate(data, msg = zhMsg) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
issues.push({ path: 'version', message: msg('adapter.validate.version', { value: String(data.version) }), severity: 'error' });
|
|
147
|
-
}
|
|
148
|
-
if (!Array.isArray(data.files)) {
|
|
149
|
-
issues.push({ path: 'files', message: msg('adapter.validate.array', { subject: 'files' }), severity: 'error' });
|
|
150
|
-
}
|
|
151
|
-
return { valid: issues.filter((i) => i.severity === 'error').length === 0, issues };
|
|
144
|
+
return validateJsonSection('pluginFiles', data, msg, (section, issues) => {
|
|
145
|
+
if (!Array.isArray(section.files)) {
|
|
146
|
+
issues.push({ path: 'files', message: msg('adapter.validate.array', { subject: 'files' }), severity: 'error' });
|
|
147
|
+
}
|
|
148
|
+
});
|
|
152
149
|
}
|
|
153
150
|
}
|
|
154
151
|
//# sourceMappingURL=plugin-files.js.map
|
|
@@ -20,9 +20,9 @@ export declare const PNPM_WORKSPACE_REL: (profile: string | undefined) => string
|
|
|
20
20
|
export declare const MAX_PATCH_FILE_BYTES: number;
|
|
21
21
|
export declare class PluginsAdapter implements ConfigAdapter<PluginsSection> {
|
|
22
22
|
readonly id: 'plugins';
|
|
23
|
-
readonly displayName
|
|
24
|
-
readonly defaultIncluded
|
|
25
|
-
readonly portability:
|
|
23
|
+
readonly displayName: string;
|
|
24
|
+
readonly defaultIncluded: boolean;
|
|
25
|
+
readonly portability: import("../schema/section-registry.ts").SectionPortability;
|
|
26
26
|
/** 插件自身包名:导出 plugins 分区时不列自己(避免备份里出现「当前正在生成备份的插件」的自引用条目) */
|
|
27
27
|
private readonly selfName;
|
|
28
28
|
/** T1:本地源(link:/file:)插件打包钩子;未注入 = 不打包(保持改造前行为) */
|
package/lib/adapters/plugins.js
CHANGED
|
@@ -13,11 +13,13 @@
|
|
|
13
13
|
import { isDeepStrictEqual } from 'node:util';
|
|
14
14
|
import { sha256Hex } from '../utils/hashing.js';
|
|
15
15
|
import { installSpecFor, resolveProfileNameFromArgv } from '../core/plugin-cli.js';
|
|
16
|
-
import {
|
|
16
|
+
import { LOCAL_PLUGIN_DIR } from '../core/local-plugin-pack.js';
|
|
17
17
|
import { msgOf, zhMsg } from '../core/messages.js';
|
|
18
18
|
import { isPathSafe, normalizePath } from '../utils/paths.js';
|
|
19
19
|
import { PLUGIN_PATCH_REF_PREFIX } from '../core/backup.js';
|
|
20
20
|
import { parsePnpmPatchedDependencies, sanitizePnpmWorkspacePatches } from './pnpm-workspace.js';
|
|
21
|
+
import { sectionMeta } from '../schema/section-registry.js';
|
|
22
|
+
import { validateJsonSection } from './json-section.js';
|
|
21
23
|
export const USER_PATCH_FILE = 'cordis.patch.yml';
|
|
22
24
|
/** tarball 字节 → base64(零依赖,避免 Buffer 在浏览器侧类型问题) */
|
|
23
25
|
function bytesToBase64(data) {
|
|
@@ -108,9 +110,10 @@ function entriesOfRaw(raw) {
|
|
|
108
110
|
}
|
|
109
111
|
export class PluginsAdapter {
|
|
110
112
|
id = 'plugins';
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
// 元数据唯一来源 = 注册表(t31):不再与 ui/export-flow.ts 的导出目录各写一份
|
|
114
|
+
displayName = sectionMeta('plugins').displayName;
|
|
115
|
+
defaultIncluded = sectionMeta('plugins').defaultIncluded;
|
|
116
|
+
portability = sectionMeta('plugins').portability;
|
|
114
117
|
/** 插件自身包名:导出 plugins 分区时不列自己(避免备份里出现「当前正在生成备份的插件」的自引用条目) */
|
|
115
118
|
selfName;
|
|
116
119
|
/** T1:本地源(link:/file:)插件打包钩子;未注入 = 不打包(保持改造前行为) */
|
|
@@ -629,47 +632,41 @@ export class PluginsAdapter {
|
|
|
629
632
|
return { ok: true, needsRestart: true, message: msg('adapter.patchWritten', { ref }) };
|
|
630
633
|
}
|
|
631
634
|
async validate(data, msg = zhMsg) {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
}
|
|
636
|
-
if (data.version !== 1) {
|
|
637
|
-
issues.push({ path: 'version', message: msg('adapter.validate.version', { value: String(data.version) }), severity: 'error' });
|
|
638
|
-
}
|
|
639
|
-
if (!Array.isArray(data.plugins)) {
|
|
640
|
-
issues.push({ path: 'plugins', message: msg('adapter.validate.array', { subject: 'plugins' }), severity: 'error' });
|
|
641
|
-
}
|
|
642
|
-
if (data.patch !== undefined && !Array.isArray(data.patch)) {
|
|
643
|
-
issues.push({ path: 'patch', message: msg('adapter.validate.array', { subject: 'patch' }), severity: 'error' });
|
|
644
|
-
}
|
|
645
|
-
if (data.pnpmWorkspace !== undefined && data.pnpmWorkspace !== null && typeof data.pnpmWorkspace !== 'string') {
|
|
646
|
-
issues.push({ path: 'pnpmWorkspace', message: msg('adapter.validate.string', { subject: 'pnpmWorkspace' }), severity: 'error' });
|
|
647
|
-
}
|
|
648
|
-
// T1:本地插件 tarball 载荷(缺省合法;存在时逐条校验形状与路径安全)
|
|
649
|
-
if (data.localTarballs !== undefined) {
|
|
650
|
-
if (!Array.isArray(data.localTarballs)) {
|
|
651
|
-
issues.push({ path: 'localTarballs', message: msg('adapter.validate.array', { subject: 'localTarballs' }), severity: 'error' });
|
|
635
|
+
return validateJsonSection('plugins', data, msg, (section, issues) => {
|
|
636
|
+
if (!Array.isArray(section.plugins)) {
|
|
637
|
+
issues.push({ path: 'plugins', message: msg('adapter.validate.array', { subject: 'plugins' }), severity: 'error' });
|
|
652
638
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
639
|
+
if (section.patch !== undefined && !Array.isArray(section.patch)) {
|
|
640
|
+
issues.push({ path: 'patch', message: msg('adapter.validate.array', { subject: 'patch' }), severity: 'error' });
|
|
641
|
+
}
|
|
642
|
+
if (section.pnpmWorkspace !== undefined && section.pnpmWorkspace !== null && typeof section.pnpmWorkspace !== 'string') {
|
|
643
|
+
issues.push({ path: 'pnpmWorkspace', message: msg('adapter.validate.string', { subject: 'pnpmWorkspace' }), severity: 'error' });
|
|
644
|
+
}
|
|
645
|
+
// T1:本地插件 tarball 载荷(缺省合法;存在时逐条校验形状与路径安全)
|
|
646
|
+
if (section.localTarballs !== undefined) {
|
|
647
|
+
if (!Array.isArray(section.localTarballs)) {
|
|
648
|
+
issues.push({ path: 'localTarballs', message: msg('adapter.validate.array', { subject: 'localTarballs' }), severity: 'error' });
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
section.localTarballs.forEach((t, i) => {
|
|
652
|
+
if (t === null || typeof t !== 'object') {
|
|
653
|
+
issues.push({ path: `localTarballs[${i}]`, message: msg('adapter.validate.object', { subject: 'localTarballs[]' }), severity: 'error' });
|
|
654
|
+
return;
|
|
662
655
|
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
656
|
+
for (const field of ['packageName', 'version', 'relativePath', 'base64']) {
|
|
657
|
+
if (typeof t[field] !== 'string' || t[field] === '') {
|
|
658
|
+
issues.push({ path: `localTarballs[${i}].${field}`, message: msg('adapter.validate.string', { subject: field }), severity: 'error' });
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
// 相对路径必须落在 LOCAL_PLUGIN_DIR 之下且不含穿越段(防写 homeDir 外)
|
|
662
|
+
const rel = typeof t.relativePath === 'string' ? t.relativePath.replace(/\\/g, '/') : '';
|
|
663
|
+
if (rel !== '' && (!rel.startsWith(`${LOCAL_PLUGIN_DIR}/`) || rel.includes('..'))) {
|
|
664
|
+
issues.push({ path: `localTarballs[${i}].relativePath`, message: msg('adapter.validate.localTarballPath', { path: rel }), severity: 'error' });
|
|
665
|
+
}
|
|
666
|
+
});
|
|
667
|
+
}
|
|
670
668
|
}
|
|
671
|
-
}
|
|
672
|
-
return { valid: issues.filter((i) => i.severity === 'error').length === 0, issues };
|
|
669
|
+
});
|
|
673
670
|
}
|
|
674
671
|
}
|
|
675
672
|
//# sourceMappingURL=plugins.js.map
|
|
@@ -20,9 +20,9 @@ export declare function mergePromptIntoLine(raw: unknown, prompt: PromptExportEn
|
|
|
20
20
|
export declare function buildPromptLine(lineId: string, prompt: PromptExportEntry): Record<string, unknown>;
|
|
21
21
|
export declare class PromptsAdapter implements ConfigAdapter<PromptsExportSection> {
|
|
22
22
|
readonly id: 'prompts';
|
|
23
|
-
readonly displayName
|
|
24
|
-
readonly defaultIncluded
|
|
25
|
-
readonly portability:
|
|
23
|
+
readonly displayName: string;
|
|
24
|
+
readonly defaultIncluded: boolean;
|
|
25
|
+
readonly portability: import("../schema/section-registry.ts").SectionPortability;
|
|
26
26
|
export(ctx: HostContext, _options: ExportOptions): Promise<ExportSection<PromptsExportSection>>;
|
|
27
27
|
analyzeImport(data: PromptsExportSection, ctx: ImportContext): Promise<PlanItem[]>;
|
|
28
28
|
applyItem(item: PlanItem, ctx: ImportContext): Promise<ApplyResult>;
|