dsh-config-manager 0.1.69 → 0.1.71
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 +59 -18
- package/README.zh-CN.md +29 -9
- package/lib/adapters/credentials.js +6 -3
- package/lib/adapters/file-collection.d.ts +21 -1
- package/lib/adapters/file-collection.js +32 -8
- package/lib/adapters/mcp.d.ts +12 -2
- package/lib/adapters/mcp.js +30 -13
- package/lib/adapters/plugin-files.d.ts +8 -0
- package/lib/adapters/plugin-files.js +36 -4
- package/lib/adapters/plugins.d.ts +28 -2
- package/lib/adapters/plugins.js +204 -55
- package/lib/adapters/prompts.d.ts +12 -2
- package/lib/adapters/prompts.js +34 -19
- package/lib/adapters/providers.js +5 -4
- package/lib/adapters/self.d.ts +20 -0
- package/lib/adapters/self.js +73 -0
- package/lib/adapters/sessions.d.ts +8 -0
- package/lib/adapters/sessions.js +47 -1
- package/lib/adapters/settings.d.ts +21 -3
- package/lib/adapters/settings.js +44 -7
- package/lib/adapters/skills.d.ts +36 -4
- package/lib/adapters/skills.js +222 -3
- package/lib/adapters/test-helpers.d.ts +31 -2
- package/lib/adapters/test-helpers.js +42 -5
- package/lib/adapters/workspaces.js +97 -5
- package/lib/cli/actions.d.ts +50 -3
- package/lib/cli/actions.js +103 -11
- package/lib/cli/help.d.ts +65 -0
- package/lib/cli/help.js +517 -0
- package/lib/cli/import-source.d.ts +32 -0
- package/lib/cli/import-source.js +178 -0
- package/lib/cli/index.d.ts +18 -2
- package/lib/cli/index.js +118 -90
- package/lib/cli/web/client-script.d.ts +8 -0
- package/lib/cli/web/client-script.js +11 -0
- package/lib/cli/web/http.d.ts +5 -0
- package/lib/cli/web/http.js +2 -1
- package/lib/cli/web/page.d.ts +16 -6
- package/lib/cli/web/page.js +102 -25
- package/lib/cli/web/routes.js +24 -5
- package/lib/cli/web/server.js +23 -2
- package/lib/client.d.ts +1019 -36
- package/lib/client.js +5522 -1564
- package/lib/core/analyzer.d.ts +15 -1
- package/lib/core/analyzer.js +114 -13
- package/lib/core/backup-plan.js +17 -1
- package/lib/core/backup.d.ts +8 -0
- package/lib/core/backup.js +28 -6
- package/lib/core/cache-cleaner.d.ts +10 -0
- package/lib/core/cache-cleaner.js +63 -22
- package/lib/core/checkpoint.d.ts +362 -0
- package/lib/core/checkpoint.js +1309 -0
- package/lib/core/journal.d.ts +37 -0
- package/lib/core/journal.js +69 -0
- package/lib/core/messages.d.ts +13 -0
- package/lib/core/messages.js +26 -0
- package/lib/core/model-tools.js +3 -0
- package/lib/core/patch-layers.d.ts +83 -0
- package/lib/core/patch-layers.js +110 -0
- package/lib/core/restore.d.ts +21 -0
- package/lib/core/restore.js +37 -3
- package/lib/core/rollback.js +6 -3
- package/lib/core/self-update.d.ts +52 -0
- package/lib/core/self-update.js +70 -0
- package/lib/core/session-health.d.ts +29 -5
- package/lib/core/session-health.js +28 -3
- package/lib/core/types.d.ts +126 -0
- package/lib/foreign/antigravity.d.ts +28 -0
- package/lib/foreign/antigravity.js +157 -0
- package/lib/foreign/bundle.d.ts +25 -0
- package/lib/foreign/bundle.js +79 -0
- package/lib/foreign/chatgpt.d.ts +6 -0
- package/lib/foreign/chatgpt.js +25 -0
- package/lib/foreign/claude-code.d.ts +3 -0
- package/lib/foreign/claude-code.js +85 -0
- package/lib/foreign/claude-sessions.d.ts +108 -0
- package/lib/foreign/claude-sessions.js +299 -0
- package/lib/foreign/cline.d.ts +6 -0
- package/lib/foreign/cline.js +27 -0
- package/lib/foreign/codex.d.ts +83 -0
- package/lib/foreign/codex.js +348 -0
- package/lib/foreign/continue.d.ts +9 -0
- package/lib/foreign/continue.js +65 -0
- package/lib/foreign/copilot.d.ts +39 -0
- package/lib/foreign/copilot.js +95 -0
- package/lib/foreign/crush.d.ts +11 -0
- package/lib/foreign/crush.js +57 -0
- package/lib/foreign/cursor.d.ts +87 -0
- package/lib/foreign/cursor.js +171 -0
- package/lib/foreign/dsh.d.ts +30 -0
- package/lib/foreign/dsh.js +101 -0
- package/lib/foreign/dsh4.d.ts +3 -0
- package/lib/foreign/dsh4.js +13 -0
- package/lib/foreign/gemini.d.ts +7 -0
- package/lib/foreign/gemini.js +44 -0
- package/lib/foreign/goose.d.ts +11 -0
- package/lib/foreign/goose.js +53 -0
- package/lib/foreign/grokbuild.d.ts +8 -0
- package/lib/foreign/grokbuild.js +25 -0
- package/lib/foreign/hermes.d.ts +2 -0
- package/lib/foreign/hermes.js +78 -0
- package/lib/foreign/kernel.d.ts +132 -0
- package/lib/foreign/kernel.js +569 -0
- package/lib/foreign/kilocode.d.ts +11 -0
- package/lib/foreign/kilocode.js +51 -0
- package/lib/foreign/kimi.d.ts +7 -0
- package/lib/foreign/kimi.js +47 -0
- package/lib/foreign/mimocode.d.ts +11 -0
- package/lib/foreign/mimocode.js +51 -0
- package/lib/foreign/openclaw.d.ts +7 -0
- package/lib/foreign/openclaw.js +46 -0
- package/lib/foreign/opencode.d.ts +11 -0
- package/lib/foreign/opencode.js +52 -0
- package/lib/foreign/pi.d.ts +7 -0
- package/lib/foreign/pi.js +48 -0
- package/lib/foreign/platform-paths.d.ts +66 -0
- package/lib/foreign/platform-paths.js +141 -0
- package/lib/foreign/qoder.d.ts +10 -0
- package/lib/foreign/qoder.js +49 -0
- package/lib/foreign/qwen.d.ts +7 -0
- package/lib/foreign/qwen.js +45 -0
- package/lib/foreign/read-antigravity.d.ts +57 -0
- package/lib/foreign/read-antigravity.js +504 -0
- package/lib/foreign/read-chatgpt.d.ts +20 -0
- package/lib/foreign/read-chatgpt.js +509 -0
- package/lib/foreign/read-claude-code.d.ts +24 -0
- package/lib/foreign/read-claude-code.js +234 -0
- package/lib/foreign/read-cline.d.ts +53 -0
- package/lib/foreign/read-cline.js +479 -0
- package/lib/foreign/read-codex.d.ts +75 -0
- package/lib/foreign/read-codex.js +842 -0
- package/lib/foreign/read-continue.d.ts +87 -0
- package/lib/foreign/read-continue.js +489 -0
- package/lib/foreign/read-copilot.d.ts +42 -0
- package/lib/foreign/read-copilot.js +267 -0
- package/lib/foreign/read-crush.d.ts +54 -0
- package/lib/foreign/read-crush.js +478 -0
- package/lib/foreign/read-cursor.d.ts +141 -0
- package/lib/foreign/read-cursor.js +705 -0
- package/lib/foreign/read-dsh.d.ts +43 -0
- package/lib/foreign/read-dsh.js +205 -0
- package/lib/foreign/read-dsh4.d.ts +14 -0
- package/lib/foreign/read-dsh4.js +27 -0
- package/lib/foreign/read-gemini.d.ts +55 -0
- package/lib/foreign/read-gemini.js +273 -0
- package/lib/foreign/read-goose.d.ts +25 -0
- package/lib/foreign/read-goose.js +322 -0
- package/lib/foreign/read-grokbuild.d.ts +34 -0
- package/lib/foreign/read-grokbuild.js +455 -0
- package/lib/foreign/read-hermes.d.ts +74 -0
- package/lib/foreign/read-hermes.js +690 -0
- package/lib/foreign/read-kilocode.d.ts +17 -0
- package/lib/foreign/read-kilocode.js +46 -0
- package/lib/foreign/read-kimi.d.ts +63 -0
- package/lib/foreign/read-kimi.js +719 -0
- package/lib/foreign/read-mimocode.d.ts +12 -0
- package/lib/foreign/read-mimocode.js +56 -0
- package/lib/foreign/read-openclaw.d.ts +51 -0
- package/lib/foreign/read-openclaw.js +445 -0
- package/lib/foreign/read-opencode.d.ts +150 -0
- package/lib/foreign/read-opencode.js +896 -0
- package/lib/foreign/read-pi.d.ts +56 -0
- package/lib/foreign/read-pi.js +411 -0
- package/lib/foreign/read-qoder.d.ts +54 -0
- package/lib/foreign/read-qoder.js +317 -0
- package/lib/foreign/read-qwen.d.ts +40 -0
- package/lib/foreign/read-qwen.js +326 -0
- package/lib/foreign/read-reasonix.d.ts +66 -0
- package/lib/foreign/read-reasonix.js +537 -0
- package/lib/foreign/read-teleagent.d.ts +15 -0
- package/lib/foreign/read-teleagent.js +68 -0
- package/lib/foreign/read-trae.d.ts +67 -0
- package/lib/foreign/read-trae.js +492 -0
- package/lib/foreign/read-vibe.d.ts +28 -0
- package/lib/foreign/read-vibe.js +364 -0
- package/lib/foreign/read-workbuddy.d.ts +49 -0
- package/lib/foreign/read-workbuddy.js +346 -0
- package/lib/foreign/read-zcode.d.ts +12 -0
- package/lib/foreign/read-zcode.js +38 -0
- package/lib/foreign/read-zed.d.ts +30 -0
- package/lib/foreign/read-zed.js +473 -0
- package/lib/foreign/reasonix.d.ts +6 -0
- package/lib/foreign/reasonix.js +20 -0
- package/lib/foreign/registry.d.ts +196 -0
- package/lib/foreign/registry.js +573 -0
- package/lib/foreign/session-ir.d.ts +186 -0
- package/lib/foreign/session-ir.js +427 -0
- package/lib/foreign/session-read.d.ts +102 -0
- package/lib/foreign/session-read.js +254 -0
- package/lib/foreign/session-source.d.ts +216 -0
- package/lib/foreign/session-source.js +453 -0
- package/lib/foreign/source-modules.d.ts +45 -0
- package/lib/foreign/source-modules.js +52 -0
- package/lib/foreign/sqlite.d.ts +61 -0
- package/lib/foreign/sqlite.js +404 -0
- package/lib/foreign/teleagent.d.ts +11 -0
- package/lib/foreign/teleagent.js +53 -0
- package/lib/foreign/trae.d.ts +6 -0
- package/lib/foreign/trae.js +20 -0
- package/lib/foreign/truth-table.d.ts +62 -0
- package/lib/foreign/truth-table.js +333 -0
- package/lib/foreign/types.d.ts +272 -0
- package/lib/foreign/types.js +2 -0
- package/lib/foreign/vibe.d.ts +6 -0
- package/lib/foreign/vibe.js +23 -0
- package/lib/foreign/workbuddy.d.ts +7 -0
- package/lib/foreign/workbuddy.js +45 -0
- package/lib/foreign/zcode.d.ts +11 -0
- package/lib/foreign/zcode.js +51 -0
- package/lib/foreign/zed.d.ts +11 -0
- package/lib/foreign/zed.js +53 -0
- package/lib/index.d.ts +154 -13
- package/lib/index.js +661 -84
- package/lib/market/github-repos.d.ts +28 -0
- package/lib/market/github-repos.js +43 -1
- package/lib/market/types.d.ts +1 -3
- package/lib/profiles/dsh-profile-manager.d.ts +54 -2
- package/lib/profiles/dsh-profile-manager.js +182 -11
- package/lib/profiles/dsh-profile-shared.d.ts +47 -0
- package/lib/profiles/dsh-profile-shared.js +15 -1
- package/lib/profiles/index.d.ts +1 -1
- package/lib/profiles/index.js +1 -1
- package/lib/routes/consult.js +51 -5
- package/lib/routes/foreign-context.d.ts +43 -0
- package/lib/routes/foreign-context.js +65 -0
- package/lib/routes/foreign.d.ts +11 -0
- package/lib/routes/foreign.js +208 -0
- package/lib/routes/import.d.ts +8 -0
- package/lib/routes/import.js +22 -1
- package/lib/routes/index.d.ts +2 -2
- package/lib/routes/index.js +4 -0
- package/lib/routes/kit.d.ts +4 -3
- package/lib/routes/market.js +0 -1
- package/lib/routes/prefs.d.ts +2 -1
- package/lib/routes/prefs.js +14 -2
- package/lib/routes/recovery.js +363 -3
- package/lib/routes/session-export.d.ts +117 -0
- package/lib/routes/session-export.js +270 -0
- package/lib/routes/snapshots.js +12 -2
- package/lib/routes/sync.js +82 -10
- package/lib/security/redaction.d.ts +14 -0
- package/lib/security/redaction.js +24 -9
- package/lib/security/secret-scanner.d.ts +27 -0
- package/lib/security/secret-scanner.js +54 -1
- package/lib/sync/autosync-scheduler.d.ts +13 -1
- package/lib/sync/autosync-scheduler.js +49 -26
- package/lib/sync/backup-files.js +6 -0
- package/lib/sync/gist/gist-transport.d.ts +91 -0
- package/lib/sync/gist/gist-transport.js +406 -0
- package/lib/sync/gist/messages.d.ts +22 -0
- package/lib/sync/gist/messages.js +46 -0
- package/lib/sync/s3/messages.d.ts +53 -0
- package/lib/sync/s3/messages.js +83 -0
- package/lib/sync/s3/s3-providers.d.ts +78 -0
- package/lib/sync/s3/s3-providers.js +156 -0
- package/lib/sync/s3/s3-transport.d.ts +126 -0
- package/lib/sync/s3/s3-transport.js +551 -0
- package/lib/sync/s3/sigv4.d.ts +107 -0
- package/lib/sync/s3/sigv4.js +196 -0
- package/lib/sync/sync-config.d.ts +250 -4
- package/lib/sync/sync-config.js +658 -57
- package/lib/sync/sync-engine.d.ts +1 -0
- package/lib/sync/sync-engine.js +4 -2
- package/lib/sync/sync-history.d.ts +1 -1
- package/lib/sync/webdav/webdav-transport.d.ts +31 -3
- package/lib/sync/webdav/webdav-transport.js +102 -18
- package/lib/ui/commands.d.ts +4 -3
- package/lib/ui/commands.js +41 -9
- package/lib/ui/disk-usage-view.d.ts +44 -0
- package/lib/ui/disk-usage-view.js +55 -1
- package/lib/ui/dsh-profiles-view.d.ts +53 -0
- package/lib/ui/dsh-profiles-view.js +56 -0
- package/lib/ui/foreign-view.d.ts +162 -0
- package/lib/ui/foreign-view.js +225 -0
- package/lib/ui/i18n.d.ts +77 -0
- package/lib/ui/i18n.js +164 -0
- package/lib/ui/session-inventory-view.d.ts +106 -0
- package/lib/ui/session-inventory-view.js +58 -0
- package/lib/ui/session-layout-view.d.ts +265 -0
- package/lib/ui/session-layout-view.js +271 -0
- package/lib/ui/sync-repository-picker.d.ts +98 -0
- package/lib/ui/sync-repository-picker.js +145 -0
- package/lib/ui/sync-settings-view.d.ts +143 -4
- package/lib/ui/sync-settings-view.js +231 -7
- package/lib/ui/types.d.ts +47 -0
- package/lib/utils/asar-read.d.ts +113 -0
- package/lib/utils/asar-read.js +523 -0
- package/lib/utils/env-lock.js +7 -2
- package/lib/utils/patch-yaml.d.ts +25 -0
- package/lib/utils/patch-yaml.js +62 -0
- package/lib/utils/paths.d.ts +10 -1
- package/lib/utils/paths.js +24 -3
- package/lib/utils/recursive-walk.js +12 -13
- package/lib/utils/session-format.d.ts +35 -2
- package/lib/utils/session-format.js +131 -5
- package/lib/utils/session-health-scan.d.ts +7 -1
- package/lib/utils/session-health-scan.js +369 -12
- package/lib/utils/session-layout-repair-service.d.ts +98 -0
- package/lib/utils/session-layout-repair-service.js +457 -0
- package/lib/utils/session-log-repair.d.ts +27 -0
- package/lib/utils/session-log-repair.js +233 -62
- package/lib/utils/session-repair-service.d.ts +32 -3
- package/lib/utils/session-repair-service.js +148 -9
- package/lib/utils/session-row-facts.d.ts +73 -0
- package/lib/utils/session-row-facts.js +182 -0
- package/lib/utils/session-verify.d.ts +118 -0
- package/lib/utils/session-verify.js +705 -0
- package/lib/utils/shared-constants.d.ts +59 -0
- package/lib/utils/shared-constants.js +71 -0
- package/package.json +1 -1
- package/src/adapters/credentials.test.ts +27 -0
- package/src/adapters/credentials.ts +6 -3
- package/src/adapters/file-collection.ts +33 -8
- package/src/adapters/files.test.ts +222 -0
- package/src/adapters/mcp.test.ts +43 -0
- package/src/adapters/mcp.ts +37 -14
- package/src/adapters/plugin-files.ts +34 -4
- package/src/adapters/plugins.test.ts +241 -0
- package/src/adapters/plugins.ts +201 -53
- package/src/adapters/prompts.test.ts +49 -0
- package/src/adapters/prompts.ts +41 -20
- package/src/adapters/providers.test.ts +16 -0
- package/src/adapters/providers.ts +4 -3
- package/src/adapters/self.test.ts +77 -0
- package/src/adapters/self.ts +75 -0
- package/src/adapters/sessions.test.ts +77 -0
- package/src/adapters/sessions.ts +47 -1
- package/src/adapters/settings.test.ts +78 -0
- package/src/adapters/settings.ts +42 -6
- package/src/adapters/skills.ts +221 -3
- package/src/adapters/test-helpers.ts +43 -5
- package/src/adapters/workspaces-dup-id.test.ts +144 -0
- package/src/adapters/workspaces.test.ts +10 -0
- package/src/adapters/workspaces.ts +97 -5
- package/src/cli/actions.test.ts +117 -2
- package/src/cli/actions.ts +132 -12
- package/src/cli/help.ts +570 -0
- package/src/cli/import-source.test.ts +193 -0
- package/src/cli/import-source.ts +229 -0
- package/src/cli/index.ts +129 -94
- package/src/cli/web/client-script.ts +12 -0
- package/src/cli/web/console-fixes.test.ts +36 -0
- package/src/cli/web/http.ts +7 -1
- package/src/cli/web/page.ts +108 -25
- package/src/cli/web/routes.ts +23 -4
- package/src/cli/web/script-anchor.test.ts +33 -0
- package/src/cli/web/server.ts +28 -2
- package/src/cli/web/web.test.ts +447 -4
- package/src/client/ConfigManagerSection.tsx +118 -63
- package/src/client/about/AboutPanel.tsx +42 -3
- package/src/client/about/PluginUpdateDialog.tsx +185 -0
- package/src/client/about/ReleaseBody.tsx +144 -0
- package/src/client/about/ReleaseNotesDialog.tsx +3 -130
- package/src/client/about/about-view.ts +7 -5
- package/src/client/about/plugin-update-view.test.ts +25 -0
- package/src/client/about/plugin-update-view.ts +26 -0
- package/src/client/about/release-notes-view.test.ts +33 -0
- package/src/client/about/release-notes-view.ts +34 -0
- package/src/client/api.ts +145 -1
- package/src/client/common/Icon.tsx +3 -0
- package/src/client/common/RunsCenter.tsx +8 -2
- package/src/client/common/Select.tsx +9 -2
- package/src/client/common/info-hint-guard.test.ts +63 -18
- package/src/client/common/plan-text-redaction.test.ts +193 -8
- package/src/client/common/routes.ts +15 -0
- package/src/client/config-manager.module.css +506 -354
- package/src/client/css-scale-guard.test.ts +122 -0
- package/src/client/css-token-guard.test.ts +82 -0
- package/src/client/environment/EnvironmentPanel.tsx +45 -16
- package/src/client/{snapshots → environment/maintenance}/DiskUsageCard.tsx +21 -17
- package/src/client/environment/profiles-incomplete-ui.test.ts +103 -0
- package/src/client/export/ExportView.tsx +9 -2
- package/src/client/{snapshots → home}/BackupScheduleCard.tsx +13 -4
- package/src/client/home/HomePanel.tsx +69 -157
- package/src/client/icon-layer-guard.test.ts +1 -1
- package/src/client/import/ForeignImportView.tsx +318 -0
- package/src/client/import/ImportWizardView.tsx +3 -1
- package/src/client/import/foreign-import-view-guard.test.ts +195 -0
- package/src/client/import/import-file-select.test.ts +6 -6
- package/src/client/import/import-wizard-steps.tsx +17 -1
- package/src/client/import/use-import-wizard-controller.ts +3 -3
- package/src/client/index.ts +1 -1
- package/src/client/library/LibraryActions.tsx +31 -34
- package/src/client/library/LibraryPanel.tsx +4 -1
- package/src/client/{snapshots → library}/RestorePlanView.tsx +1 -1
- package/src/client/{snapshots → library}/files-layout.test.ts +2 -2
- package/src/client/{snapshots → library}/report-dismiss.test.ts +26 -3
- package/src/client/library/task-panel-visibility.test.ts +25 -17
- package/src/client/locales.ts +278 -36
- package/src/client/lucide-icons.d.ts +1 -0
- package/src/client/market/MarketPanel.tsx +11 -2
- package/src/client/recovery/IncompleteCopiesSection.tsx +132 -0
- package/src/client/recovery/RecoveryPanel.tsx +486 -59
- package/src/client/recovery/recovery-api.ts +30 -0
- package/src/client/recovery/recovery-incomplete-copies.test.ts +151 -0
- package/src/client/recovery/recovery-locales.test.ts +88 -0
- package/src/client/recovery/recovery-locales.ts +321 -6
- package/src/client/recovery/recovery-panel-layout.test.ts +52 -0
- package/src/client/recovery/recovery-view.ts +92 -2
- package/src/client/run-store.test.ts +201 -89
- package/src/client/run-store.ts +114 -143
- package/src/client/session-export/session-export-view.test.ts +103 -0
- package/src/client/session-export/session-export-view.ts +118 -0
- package/src/client/sync/ChannelConfigDialog.tsx +219 -14
- package/src/client/sync/SyncChannelEntryCard.tsx +52 -4
- package/src/client/sync/SyncLogList.tsx +1 -1
- package/src/client/sync/SyncPanel.tsx +166 -102
- package/src/client/sync/SyncRepositoryPicker.tsx +216 -0
- package/src/client/sync/SyncSettingsView.test.ts +6 -1
- package/src/client/sync/history-model.test.ts +94 -57
- package/src/client/sync/history-model.ts +44 -25
- package/src/client/sync/sync-api.test.ts +56 -0
- package/src/client/sync/sync-api.ts +92 -0
- package/src/client/sync/sync-locales.ts +162 -2
- package/src/client/sync/sync-view.test.ts +3 -8
- package/src/client/sync/sync-view.ts +111 -21
- package/src/core/analyzer-cache.test.ts +47 -0
- package/src/core/analyzer.ts +115 -14
- package/src/core/backup-plan.test.ts +35 -0
- package/src/core/backup-plan.ts +19 -1
- package/src/core/backup.test.ts +37 -1
- package/src/core/backup.ts +27 -6
- package/src/core/cache-cleaner.test.ts +120 -1
- package/src/core/cache-cleaner.ts +59 -22
- package/src/core/checkpoint.test.ts +665 -0
- package/src/core/checkpoint.ts +1614 -0
- package/src/core/credential-plan-consistency.test.ts +93 -0
- package/src/core/incident-wiring.test.ts +6 -2
- package/src/core/journal.test.ts +70 -0
- package/src/core/journal.ts +68 -0
- package/src/core/messages.ts +26 -0
- package/src/core/model-tools.ts +3 -0
- package/src/core/patch-layers.test.ts +94 -0
- package/src/core/patch-layers.ts +150 -0
- package/src/core/restore.ts +59 -3
- package/src/core/rollback.ts +6 -3
- package/src/core/section-content-consistency.test.ts +185 -0
- package/src/core/self-update.test.ts +110 -0
- package/src/core/self-update.ts +118 -0
- package/src/core/session-health.test.ts +91 -1
- package/src/core/session-health.ts +56 -9
- package/src/core/types.ts +127 -1
- package/src/foreign/antigravity.test.ts +271 -0
- package/src/foreign/antigravity.ts +188 -0
- package/src/foreign/bundle.ts +108 -0
- package/src/foreign/chatgpt.test.ts +279 -0
- package/src/foreign/chatgpt.ts +30 -0
- package/src/foreign/claude-code.test.ts +234 -0
- package/src/foreign/claude-code.ts +106 -0
- package/src/foreign/claude-sessions-bytes.test.ts +227 -0
- package/src/foreign/claude-sessions.test.ts +180 -0
- package/src/foreign/claude-sessions.ts +461 -0
- package/src/foreign/cline.test.ts +274 -0
- package/src/foreign/cline.ts +32 -0
- package/src/foreign/codex.test.ts +585 -0
- package/src/foreign/codex.ts +409 -0
- package/src/foreign/continue.test.ts +365 -0
- package/src/foreign/continue.ts +73 -0
- package/src/foreign/copilot.test.ts +273 -0
- package/src/foreign/copilot.ts +133 -0
- package/src/foreign/crush.test.ts +234 -0
- package/src/foreign/crush.ts +66 -0
- package/src/foreign/cursor.test.ts +509 -0
- package/src/foreign/cursor.ts +259 -0
- package/src/foreign/dsh.test.ts +198 -0
- package/src/foreign/dsh.ts +117 -0
- package/src/foreign/dsh4.test.ts +127 -0
- package/src/foreign/dsh4.ts +15 -0
- package/src/foreign/file-budget.test.ts +256 -0
- package/src/foreign/fixtures/antigravity/README.md +18 -0
- package/src/foreign/fixtures/antigravity/basic/gemini/antigravity/mcp_config.json +13 -0
- package/src/foreign/fixtures/antigravity/basic/gemini/config/mcp_config.json +24 -0
- package/src/foreign/fixtures/antigravity/empty/gemini/antigravity/mcp_config.json +0 -0
- package/src/foreign/fixtures/antigravity/empty/gemini/antigravity/mcp_oauth_tokens.json +0 -0
- package/src/foreign/fixtures/antigravity/empty/gemini/config/mcp_config.json +0 -0
- package/src/foreign/fixtures/codex/README.md +31 -0
- package/src/foreign/fixtures/codex/basic/.agents/skills/hello/SKILL.md +6 -0
- package/src/foreign/fixtures/codex/basic/.agents/skills/wrapper/nested/SKILL.md +6 -0
- package/src/foreign/fixtures/codex/basic/.codex/AGENTS.md +4 -0
- package/src/foreign/fixtures/codex/basic/.codex/config.toml +28 -0
- package/src/foreign/fixtures/codex/malformed/.codex/config.toml +3 -0
- package/src/foreign/fixtures/codex/override/.codex/AGENTS.md +1 -0
- package/src/foreign/fixtures/codex/override/.codex/AGENTS.override.md +3 -0
- package/src/foreign/fixtures/codex/sessions/.codex/archived_sessions/rollout-2026-10-05T09-00-00-22222222-2222-4222-8222-222222222222.jsonl +2 -0
- package/src/foreign/fixtures/codex/sessions/.codex/sessions/2026/10/06/rollout-2026-10-06T10-00-00-11111111-1111-4111-8111-111111111111.jsonl +15 -0
- package/src/foreign/fixtures/codex/sessions/.codex/sessions/2026/10/06/rollout-2026-10-06T11-00-00-33333333-3333-4333-8333-333333333333.jsonl +2 -0
- package/src/foreign/fixtures/codex/sessions/.codex/sessions/2026/10/06/rollout-2026-10-06T11-30-00-55555555-5555-4555-8555-555555555555.jsonl +2 -0
- package/src/foreign/fixtures/codex/sessions/.codex/sessions/2026/10/06/rollout-2026-10-06T12-00-00-44444444-4444-4444-8444-444444444444.jsonl +2 -0
- package/src/foreign/fixtures/codex/sessions/.codex/sessions/notes.jsonl +1 -0
- package/src/foreign/fixtures/copilot/README.md +22 -0
- package/src/foreign/fixtures/copilot/basic/copilot-instructions.md +3 -0
- package/src/foreign/fixtures/copilot/basic/instructions/empty.instructions.md +1 -0
- package/src/foreign/fixtures/copilot/basic/instructions/repo.instructions.md +5 -0
- package/src/foreign/fixtures/copilot/basic/mcp-config.json +24 -0
- package/src/foreign/fixtures/copilot/basic/skills/hello/SKILL.md +6 -0
- package/src/foreign/fixtures/copilot/overridden/mcp-config.json +10 -0
- package/src/foreign/fixtures/cursor/README.md +17 -0
- package/src/foreign/fixtures/cursor/alt/.cursor/mcp.json +5 -0
- package/src/foreign/fixtures/cursor/basic/.cursor/mcp.json +18 -0
- package/src/foreign/fixtures/cursor/basic/.cursor/rules/agent.mdc +5 -0
- package/src/foreign/fixtures/cursor/basic/.cursor/rules/always.mdc +6 -0
- package/src/foreign/fixtures/cursor/basic/.cursor/rules/auto.mdc +7 -0
- package/src/foreign/fixtures/cursor/basic/.cursor/rules/manual.mdc +3 -0
- package/src/foreign/fixtures/cursor/basic/.cursor/skills/.hidden/SKILL.md +6 -0
- package/src/foreign/fixtures/cursor/basic/.cursor/skills/hello/SKILL.md +6 -0
- package/src/foreign/fixtures/cursor/basic/.cursor/skills/wrapper/nested/SKILL.md +6 -0
- package/src/foreign/fixtures/cursor/basic/.cursor/skills/wrapper/nested/notes.md +1 -0
- package/src/foreign/fixtures/cursor/basic/.cursorrules +1 -0
- package/src/foreign/fixtures/cursor/basic/project/.cursor/mcp.json +9 -0
- package/src/foreign/fixtures/cursor/basic/project/.cursor/rules/project-always.mdc +5 -0
- package/src/foreign/fixtures/cursor/basic/project/.cursor/skills/hello/SKILL.md +6 -0
- package/src/foreign/fixtures/cursor/basic/project/.cursorrules +1 -0
- package/src/foreign/fixtures/cursor/empty/.cursor/mcp.json +0 -0
- package/src/foreign/fixtures/cursor/malformed/.cursor/mcp.json +3 -0
- package/src/foreign/fixtures/cursor/malformed/.cursor/rules/broken.mdc +6 -0
- package/src/foreign/fixtures/cursor/shape/.cursor/mcp.json +3 -0
- package/src/foreign/fixtures/hermes/README.md +14 -0
- package/src/foreign/fixtures/hermes/basic/SOUL.md +3 -0
- package/src/foreign/fixtures/hermes/basic/config.yaml +48 -0
- package/src/foreign/fixtures/hermes/basic/dotenv.fixture +1 -0
- package/src/foreign/fixtures/hermes/basic/memories/MEMORY.md +1 -0
- package/src/foreign/fixtures/hermes/basic/memories/USER.md +1 -0
- package/src/foreign/fixtures/hermes/basic/skills/se-team-design/SKILL.md +6 -0
- package/src/foreign/fixtures/hermes/basic/skills/se-team-design/examples/usage.md +1 -0
- package/src/foreign/fixtures/hermes/basic/skills/software-development/dogfood/SKILL.md +6 -0
- package/src/foreign/fixtures/hermes/basic/skills/software-development/dogfood/notes.md +1 -0
- package/src/foreign/fixtures/hermes/basic/state.db +1 -0
- package/src/foreign/fixtures/hermes/empty/config.yaml +0 -0
- package/src/foreign/gemini.test.ts +291 -0
- package/src/foreign/gemini.ts +52 -0
- package/src/foreign/goose.test.ts +196 -0
- package/src/foreign/goose.ts +62 -0
- package/src/foreign/grokbuild.test.ts +246 -0
- package/src/foreign/grokbuild.ts +30 -0
- package/src/foreign/hermes.test.ts +545 -0
- package/src/foreign/hermes.ts +86 -0
- package/src/foreign/kernel-credentials.test.ts +88 -0
- package/src/foreign/kernel-workspaces.test.ts +88 -0
- package/src/foreign/kernel.ts +584 -0
- package/src/foreign/kilocode.test.ts +186 -0
- package/src/foreign/kilocode.ts +60 -0
- package/src/foreign/kimi.test.ts +259 -0
- package/src/foreign/kimi.ts +55 -0
- package/src/foreign/mcp-value-shape.test.ts +286 -0
- package/src/foreign/mimocode.test.ts +178 -0
- package/src/foreign/mimocode.ts +60 -0
- package/src/foreign/openclaw.test.ts +248 -0
- package/src/foreign/openclaw.ts +54 -0
- package/src/foreign/opencode.test.ts +376 -0
- package/src/foreign/opencode.ts +61 -0
- package/src/foreign/pi.test.ts +275 -0
- package/src/foreign/pi.ts +56 -0
- package/src/foreign/platform-paths.ts +156 -0
- package/src/foreign/qoder.test.ts +266 -0
- package/src/foreign/qoder.ts +57 -0
- package/src/foreign/qwen.test.ts +203 -0
- package/src/foreign/qwen.ts +53 -0
- package/src/foreign/read-antigravity.ts +569 -0
- package/src/foreign/read-chatgpt.ts +506 -0
- package/src/foreign/read-claude-code.ts +264 -0
- package/src/foreign/read-cline.ts +517 -0
- package/src/foreign/read-codex.ts +823 -0
- package/src/foreign/read-continue.ts +557 -0
- package/src/foreign/read-copilot.ts +304 -0
- package/src/foreign/read-crush.ts +503 -0
- package/src/foreign/read-cursor.ts +778 -0
- package/src/foreign/read-dsh.ts +215 -0
- package/src/foreign/read-dsh4.ts +35 -0
- package/src/foreign/read-gemini.ts +306 -0
- package/src/foreign/read-goose.ts +333 -0
- package/src/foreign/read-grokbuild.ts +475 -0
- package/src/foreign/read-hermes.ts +724 -0
- package/src/foreign/read-kilocode.ts +55 -0
- package/src/foreign/read-kimi.ts +768 -0
- package/src/foreign/read-mimocode.ts +66 -0
- package/src/foreign/read-openclaw.ts +505 -0
- package/src/foreign/read-opencode.ts +994 -0
- package/src/foreign/read-pi.ts +459 -0
- package/src/foreign/read-qoder.ts +351 -0
- package/src/foreign/read-qwen.ts +342 -0
- package/src/foreign/read-reasonix.ts +590 -0
- package/src/foreign/read-teleagent.ts +82 -0
- package/src/foreign/read-trae.ts +488 -0
- package/src/foreign/read-vibe.ts +353 -0
- package/src/foreign/read-workbuddy.ts +374 -0
- package/src/foreign/read-zcode.ts +48 -0
- package/src/foreign/read-zed.ts +479 -0
- package/src/foreign/reasonix.test.ts +336 -0
- package/src/foreign/reasonix.ts +25 -0
- package/src/foreign/registry.test.ts +377 -0
- package/src/foreign/registry.ts +750 -0
- package/src/foreign/session-ir.test.ts +189 -0
- package/src/foreign/session-ir.ts +614 -0
- package/src/foreign/session-read.ts +295 -0
- package/src/foreign/session-source.ts +625 -0
- package/src/foreign/skill-file-caps.test.ts +171 -0
- package/src/foreign/source-modules.ts +86 -0
- package/src/foreign/source-registry.test.ts +190 -0
- package/src/foreign/sqlite.test.ts +313 -0
- package/src/foreign/sqlite.ts +446 -0
- package/src/foreign/teleagent.test.ts +147 -0
- package/src/foreign/teleagent.ts +62 -0
- package/src/foreign/trae.test.ts +316 -0
- package/src/foreign/trae.ts +25 -0
- package/src/foreign/truncation-report.test.ts +238 -0
- package/src/foreign/truth-table.ts +453 -0
- package/src/foreign/types.ts +312 -0
- package/src/foreign/vibe.test.ts +209 -0
- package/src/foreign/vibe.ts +28 -0
- package/src/foreign/workbuddy.test.ts +207 -0
- package/src/foreign/workbuddy.ts +53 -0
- package/src/foreign/zcode.test.ts +224 -0
- package/src/foreign/zcode.ts +60 -0
- package/src/foreign/zed.test.ts +240 -0
- package/src/foreign/zed.ts +62 -0
- package/src/index.facade.test.ts +254 -16
- package/src/index.ts +704 -82
- package/src/market/github-repos.test.ts +98 -1
- package/src/market/github-repos.ts +63 -1
- package/src/market/types.ts +3 -3
- package/src/profiles/dsh-profile-incomplete-copy.test.ts +177 -0
- package/src/profiles/dsh-profile-manager.test.ts +37 -0
- package/src/profiles/dsh-profile-manager.ts +188 -13
- package/src/profiles/dsh-profile-shared.ts +55 -1
- package/src/profiles/index.ts +2 -1
- package/src/routes/consult.ts +53 -4
- package/src/routes/foreign-context.ts +89 -0
- package/src/routes/foreign.test.ts +443 -0
- package/src/routes/foreign.ts +226 -0
- package/src/routes/import.ts +23 -1
- package/src/routes/index.ts +6 -2
- package/src/routes/kit.ts +4 -3
- package/src/routes/market.ts +0 -1
- package/src/routes/prefs.ts +15 -1
- package/src/routes/recovery.test.ts +167 -0
- package/src/routes/recovery.ts +331 -1
- package/src/routes/session-export.ts +308 -0
- package/src/routes/snapshots.ts +12 -2
- package/src/routes/sync.ts +91 -7
- package/src/security/redaction.test.ts +149 -0
- package/src/security/redaction.ts +25 -9
- package/src/security/secret-scanner.test.ts +186 -0
- package/src/security/secret-scanner.ts +57 -1
- package/src/sync/autosync-risk-tier.test.ts +61 -0
- package/src/sync/autosync-scheduler.test.ts +48 -1
- package/src/sync/autosync-scheduler.ts +50 -26
- package/src/sync/backup-files.ts +5 -0
- package/src/sync/gist/gist-msgkeys-catalog.test.ts +33 -0
- package/src/sync/gist/gist-msgkeys.test.ts +71 -0
- package/src/sync/gist/gist-transport.test.ts +308 -0
- package/src/sync/gist/gist-transport.ts +550 -0
- package/src/sync/gist/messages.ts +49 -0
- package/src/sync/retention-prune-all-off.test.ts +50 -0
- package/src/sync/s3/cloud-config.test.ts +283 -0
- package/src/sync/s3/messages.ts +102 -0
- package/src/sync/s3/s3-delete-index-404.test.ts +170 -0
- package/src/sync/s3/s3-delete-index-unreadable.test.ts +141 -0
- package/src/sync/s3/s3-msgkeys.test.ts +101 -0
- package/src/sync/s3/s3-providers.ts +213 -0
- package/src/sync/s3/s3-transport.test.ts +394 -0
- package/src/sync/s3/s3-transport.ts +651 -0
- package/src/sync/s3/s3-upload-index-404.test.ts +171 -0
- package/src/sync/s3/sigv4.test.ts +219 -0
- package/src/sync/s3/sigv4.ts +283 -0
- package/src/sync/sync-config.test.ts +237 -5
- package/src/sync/sync-config.ts +841 -52
- package/src/sync/sync-engine-download-tombstone.test.ts +73 -0
- package/src/sync/sync-engine.ts +5 -3
- package/src/sync/sync-history.ts +1 -1
- package/src/sync/webdav/webdav-delete-index-404.test.ts +178 -0
- package/src/sync/webdav/webdav-delete-index-unreadable.test.ts +143 -0
- package/src/sync/webdav/webdav-msgkeys.test.ts +53 -0
- package/src/sync/webdav/webdav-transport.test.ts +9 -5
- package/src/sync/webdav/webdav-transport.ts +99 -17
- package/src/sync/webdav/webdav-upload-index-404.test.ts +177 -0
- package/src/ui/commands.test.ts +4 -1
- package/src/ui/commands.ts +46 -12
- package/src/ui/disk-usage-view.test.ts +63 -1
- package/src/ui/disk-usage-view.ts +93 -1
- package/src/ui/dsh-profiles-incomplete-view.test.ts +102 -0
- package/src/ui/dsh-profiles-view.ts +94 -0
- package/src/ui/foreign-view.test.ts +241 -0
- package/src/ui/foreign-view.ts +362 -0
- package/src/ui/i18n.ts +164 -0
- package/src/ui/mid-ellipsis.test.ts +5 -10
- package/src/ui/session-inventory-view.test.ts +142 -2
- package/src/ui/session-inventory-view.ts +127 -0
- package/src/ui/session-layout-view.test.ts +361 -0
- package/src/ui/session-layout-view.ts +444 -0
- package/src/ui/sync-repository-picker.test.ts +130 -0
- package/src/ui/sync-repository-picker.ts +180 -0
- package/src/ui/sync-settings-view.test.ts +166 -0
- package/src/ui/sync-settings-view.ts +319 -9
- package/src/ui/types.ts +42 -0
- package/src/utils/asar-read.test.ts +330 -0
- package/src/utils/asar-read.ts +606 -0
- package/src/utils/env-lock.test.ts +55 -0
- package/src/utils/env-lock.ts +6 -1
- package/src/utils/patch-yaml.test.ts +112 -0
- package/src/utils/patch-yaml.ts +72 -0
- package/src/utils/paths.test.ts +63 -0
- package/src/utils/paths.ts +25 -3
- package/src/utils/recursive-walk.test.ts +20 -0
- package/src/utils/recursive-walk.ts +12 -13
- package/src/utils/session-format.test.ts +113 -2
- package/src/utils/session-format.ts +127 -5
- package/src/utils/session-health-scan.test.ts +364 -1
- package/src/utils/session-health-scan.ts +434 -15
- package/src/utils/session-layout-repair-service.test.ts +362 -0
- package/src/utils/session-layout-repair-service.ts +568 -0
- package/src/utils/session-log-repair.test.ts +260 -1
- package/src/utils/session-log-repair.ts +294 -55
- package/src/utils/session-repair-service.test.ts +148 -1
- package/src/utils/session-repair-service.ts +165 -10
- package/src/utils/session-row-facts.test.ts +159 -0
- package/src/utils/session-row-facts.ts +187 -0
- package/src/utils/session-verify.test.ts +762 -0
- package/src/utils/session-verify.ts +784 -0
- package/src/utils/shared-constants.ts +82 -0
|
@@ -10,6 +10,8 @@ export declare class MemFs implements FileSystemFacade {
|
|
|
10
10
|
ensureDir?: FileSystemFacade['ensureDir'];
|
|
11
11
|
/** 可选(issue #45):绝对路径 realpath。测试按需注入;缺省维持「宿主不支持」的旧行为。 */
|
|
12
12
|
realpathDir?: FileSystemFacade['realpathDir'];
|
|
13
|
+
/** 可选(只读预览):目录体积上界。测试按需注入;缺省维持「宿主不支持」的旧行为(`link:` 体积按 0)。 */
|
|
14
|
+
dirSizeBytes?: FileSystemFacade['dirSizeBytes'];
|
|
13
15
|
private readonly homeDir;
|
|
14
16
|
constructor(homeDir: string);
|
|
15
17
|
private key;
|
|
@@ -63,6 +65,11 @@ declare class AutoRegisterMap extends Map<string, {
|
|
|
63
65
|
export declare class MemSettings implements SettingsFacade {
|
|
64
66
|
/** 已注册命名空间(对齐真实 dsh-settings:插件激活时注册;未注册的 describe/replace 抛错) */
|
|
65
67
|
registered: Set<string>;
|
|
68
|
+
/**
|
|
69
|
+
* 可选(宿主能力探测):**默认不提供** ⇒ 既有测试继续覆盖「逐名 describe」回退路径;
|
|
70
|
+
* 需要验证快路径的测试自行挂上(真实宿主 DshSettingsFacade 始终提供)。
|
|
71
|
+
*/
|
|
72
|
+
describeAll?: SettingsFacade['describeAll'];
|
|
66
73
|
/** 有值的命名空间自动视为已注册 */
|
|
67
74
|
ns: AutoRegisterMap;
|
|
68
75
|
describe(namespace: string, _opts?: {
|
|
@@ -100,16 +107,36 @@ export declare class MemWorkspace implements WorkspaceFacade {
|
|
|
100
107
|
writeRecord(r: WorkspaceRecord): Promise<void>;
|
|
101
108
|
removeRecord(id: string): Promise<void>;
|
|
102
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* 内存 patch 门面,**按层分桶**(issue #71)。
|
|
112
|
+
*
|
|
113
|
+
* `lines` 仍是**用户(home)层**的桶 —— 绝大多数既有测试只关心「一行进、一行出」,
|
|
114
|
+
* 直接操作 `lines` 即可,语义与改造前完全一致。其它层(profile 层)走 `byFile`:
|
|
115
|
+
* 缺省空桶,因此「读两层」的调用方在旧测试里读到的 profile 层就是空的,不会污染断言。
|
|
116
|
+
*
|
|
117
|
+
* 分层用 `byFile(rel)` 显式取桶,避免测试里手写路径字符串。
|
|
118
|
+
*/
|
|
103
119
|
export declare class MemPatch implements PatchFileFacade {
|
|
120
|
+
/** 用户(home)层桶:`cordis.patch.yml`。 */
|
|
104
121
|
lines: Map<string, {
|
|
105
122
|
lineId: string;
|
|
106
123
|
raw: unknown;
|
|
107
124
|
}>;
|
|
108
|
-
|
|
125
|
+
/** 其它层桶:层路径 → 行表(profile 层等)。 */
|
|
126
|
+
byFile: Map<string, Map<string, {
|
|
127
|
+
lineId: string;
|
|
128
|
+
raw: unknown;
|
|
129
|
+
}>>;
|
|
130
|
+
/** 取(必要时建)某一层的桶;用户层恒为 `lines`(与旧测试兼容)。 */
|
|
131
|
+
bucket(file: string): Map<string, {
|
|
132
|
+
lineId: string;
|
|
133
|
+
raw: unknown;
|
|
134
|
+
}>;
|
|
135
|
+
readPatchLines(file: string): Promise<{
|
|
109
136
|
lineId: string;
|
|
110
137
|
raw: unknown;
|
|
111
138
|
}[]>;
|
|
112
|
-
applyPatchChanges(
|
|
139
|
+
applyPatchChanges(file: string, changes: {
|
|
113
140
|
lineId: string;
|
|
114
141
|
raw: unknown;
|
|
115
142
|
action: 'insert' | 'update' | 'remove';
|
|
@@ -138,6 +165,8 @@ export declare class MockHostContext implements HostContext {
|
|
|
138
165
|
fs: MemFs;
|
|
139
166
|
/** 可选(issue #45):会话存储端口;测试按需注入(缺省 = 宿主未提供该能力)。 */
|
|
140
167
|
sessions?: HostContext['sessions'];
|
|
168
|
+
/** 可选(issue #71):技能服务端口;测试按需注入(缺省 = 退回纯目录扫描)。 */
|
|
169
|
+
skills?: HostContext['skills'];
|
|
141
170
|
constructor(platform: string, homeDir: string, profile?: string);
|
|
142
171
|
}
|
|
143
172
|
export declare function makeContext(platform: string, homeDir: string, profile?: string): MockHostContext;
|
|
@@ -6,6 +6,7 @@ import { normalizePath } from '../utils/paths.js';
|
|
|
6
6
|
import { createLogger } from '../utils/logger.js';
|
|
7
7
|
import { sha256Hex } from '../utils/hashing.js';
|
|
8
8
|
import { zhMsg } from '../core/messages.js';
|
|
9
|
+
import { USER_PATCH_FILE } from '../core/patch-layers.js';
|
|
9
10
|
export class MemFs {
|
|
10
11
|
files = new Map();
|
|
11
12
|
/** 可选(issue #37):详细的链接遍历。测试按需注入;缺省走 listRecursive 回退路径。 */
|
|
@@ -14,6 +15,8 @@ export class MemFs {
|
|
|
14
15
|
ensureDir;
|
|
15
16
|
/** 可选(issue #45):绝对路径 realpath。测试按需注入;缺省维持「宿主不支持」的旧行为。 */
|
|
16
17
|
realpathDir;
|
|
18
|
+
/** 可选(只读预览):目录体积上界。测试按需注入;缺省维持「宿主不支持」的旧行为(`link:` 体积按 0)。 */
|
|
19
|
+
dirSizeBytes;
|
|
17
20
|
homeDir;
|
|
18
21
|
constructor(homeDir) {
|
|
19
22
|
this.homeDir = homeDir;
|
|
@@ -95,6 +98,11 @@ class AutoRegisterMap extends Map {
|
|
|
95
98
|
export class MemSettings {
|
|
96
99
|
/** 已注册命名空间(对齐真实 dsh-settings:插件激活时注册;未注册的 describe/replace 抛错) */
|
|
97
100
|
registered = new Set();
|
|
101
|
+
/**
|
|
102
|
+
* 可选(宿主能力探测):**默认不提供** ⇒ 既有测试继续覆盖「逐名 describe」回退路径;
|
|
103
|
+
* 需要验证快路径的测试自行挂上(真实宿主 DshSettingsFacade 始终提供)。
|
|
104
|
+
*/
|
|
105
|
+
describeAll;
|
|
98
106
|
/** 有值的命名空间自动视为已注册 */
|
|
99
107
|
ns = new AutoRegisterMap(this.registered);
|
|
100
108
|
async describe(namespace, _opts) {
|
|
@@ -167,17 +175,44 @@ export class MemWorkspace {
|
|
|
167
175
|
async writeRecord(r) { this.records.set(r.id, r); }
|
|
168
176
|
async removeRecord(id) { this.records.delete(id); }
|
|
169
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* 内存 patch 门面,**按层分桶**(issue #71)。
|
|
180
|
+
*
|
|
181
|
+
* `lines` 仍是**用户(home)层**的桶 —— 绝大多数既有测试只关心「一行进、一行出」,
|
|
182
|
+
* 直接操作 `lines` 即可,语义与改造前完全一致。其它层(profile 层)走 `byFile`:
|
|
183
|
+
* 缺省空桶,因此「读两层」的调用方在旧测试里读到的 profile 层就是空的,不会污染断言。
|
|
184
|
+
*
|
|
185
|
+
* 分层用 `byFile(rel)` 显式取桶,避免测试里手写路径字符串。
|
|
186
|
+
*/
|
|
170
187
|
export class MemPatch {
|
|
188
|
+
/** 用户(home)层桶:`cordis.patch.yml`。 */
|
|
171
189
|
lines = new Map();
|
|
172
|
-
|
|
173
|
-
|
|
190
|
+
/** 其它层桶:层路径 → 行表(profile 层等)。 */
|
|
191
|
+
byFile = new Map();
|
|
192
|
+
/** 取(必要时建)某一层的桶;用户层恒为 `lines`(与旧测试兼容)。 */
|
|
193
|
+
bucket(file) {
|
|
194
|
+
if (file === USER_PATCH_FILE)
|
|
195
|
+
return this.lines;
|
|
196
|
+
let bucket = this.byFile.get(file);
|
|
197
|
+
if (bucket === undefined) {
|
|
198
|
+
bucket = new Map();
|
|
199
|
+
this.byFile.set(file, bucket);
|
|
200
|
+
}
|
|
201
|
+
return bucket;
|
|
202
|
+
}
|
|
203
|
+
async readPatchLines(file) {
|
|
204
|
+
if (file === USER_PATCH_FILE)
|
|
205
|
+
return [...this.lines.values()];
|
|
206
|
+
const bucket = this.byFile.get(file);
|
|
207
|
+
return bucket === undefined ? [] : [...bucket.values()];
|
|
174
208
|
}
|
|
175
|
-
async applyPatchChanges(
|
|
209
|
+
async applyPatchChanges(file, changes) {
|
|
210
|
+
const bucket = this.bucket(file);
|
|
176
211
|
for (const c of changes) {
|
|
177
212
|
if (c.action === 'remove')
|
|
178
|
-
|
|
213
|
+
bucket.delete(c.lineId);
|
|
179
214
|
else
|
|
180
|
-
|
|
215
|
+
bucket.set(c.lineId, { lineId: c.lineId, raw: c.raw });
|
|
181
216
|
}
|
|
182
217
|
}
|
|
183
218
|
}
|
|
@@ -224,6 +259,8 @@ export class MockHostContext {
|
|
|
224
259
|
fs;
|
|
225
260
|
/** 可选(issue #45):会话存储端口;测试按需注入(缺省 = 宿主未提供该能力)。 */
|
|
226
261
|
sessions;
|
|
262
|
+
/** 可选(issue #71):技能服务端口;测试按需注入(缺省 = 退回纯目录扫描)。 */
|
|
263
|
+
skills;
|
|
227
264
|
constructor(platform, homeDir, profile) {
|
|
228
265
|
this.platform = platform;
|
|
229
266
|
this.homeDir = homeDir;
|
|
@@ -29,6 +29,50 @@ export function isCreatableWorkspacePath(path, platform = process.platform) {
|
|
|
29
29
|
function reasonOf(error) {
|
|
30
30
|
return error instanceof Error ? error.message : String(error);
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* 按记录 id 归并工作区记录(audit-foreign foreign-F2;与上游内核 FIX-foreign 同一口径)。
|
|
34
|
+
*
|
|
35
|
+
* 为什么必须归并:记录 id 由 `projectKeyOf(path)` 派生(多对一 —— 分隔符 run 会被折叠),
|
|
36
|
+
* 同一目录的两种写法(Windows 反斜杠/正斜杠、posix `/a/b` 与 `/a//b`)会产出**同一个 id 的两条记录**。
|
|
37
|
+
* 不归并的话:计划里出现同 id 的两条 Create(一次决策命中两条)、applyItem 按 id 只能取到第一条
|
|
38
|
+
* → 第二条记录的 path/title/sessionIds 静默消失(analysis.valid 仍为 true,零告警)。
|
|
39
|
+
*
|
|
40
|
+
* 归并规则:`sessionIds` 取**并集**(按 `sessionIdKey` 裸键去重,保持先到顺序;两种命名形态
|
|
41
|
+
* 指向同一条会话时只留一条),`path`/`title` 取**先到者**(与内核侧一致)。
|
|
42
|
+
* 返回顺序 = 首次出现顺序;`duplicateCount` 供调用方在计划里显式标注(绝不静默)。
|
|
43
|
+
*/
|
|
44
|
+
function mergeWorkspaceRecordsById(records) {
|
|
45
|
+
const order = [];
|
|
46
|
+
const byId = new Map();
|
|
47
|
+
for (const rec of records) {
|
|
48
|
+
// 纵深防御(t73 的 F2):非对象记录直接跳过。第三方包可能带 null;validate 已拒(workspaces[]),
|
|
49
|
+
// 生产不可达 —— 但归并是**新增**调用点,不让它成为又一条内部 TypeError 的来源。
|
|
50
|
+
const raw = rec;
|
|
51
|
+
if (raw === null || typeof raw !== 'object')
|
|
52
|
+
continue;
|
|
53
|
+
// 只接受字符串元素(t73 的 F1):`sessionIdKey` 的入参契约是字符串,数字/null 元素会让它抛
|
|
54
|
+
// TypeError(base 上这些元素根本不经过 sessionIdKey —— 归并去重是新增调用点)。非法元素丢弃。
|
|
55
|
+
const ids = Array.isArray(rec.sessionIds)
|
|
56
|
+
? rec.sessionIds.filter((sid) => typeof sid === 'string')
|
|
57
|
+
: [];
|
|
58
|
+
const hit = byId.get(rec.id);
|
|
59
|
+
if (hit === undefined) {
|
|
60
|
+
byId.set(rec.id, { rec: { ...rec, sessionIds: [...ids] }, duplicateCount: 1 });
|
|
61
|
+
order.push(rec.id);
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
hit.duplicateCount += 1;
|
|
65
|
+
const seen = new Set(hit.rec.sessionIds.map((s) => sessionIdKey(s)));
|
|
66
|
+
for (const sid of ids) {
|
|
67
|
+
const key = sessionIdKey(sid);
|
|
68
|
+
if (seen.has(key))
|
|
69
|
+
continue;
|
|
70
|
+
seen.add(key);
|
|
71
|
+
hit.rec.sessionIds.push(sid);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return order.map((id) => byId.get(id));
|
|
75
|
+
}
|
|
32
76
|
export class WorkspacesAdapter {
|
|
33
77
|
id = 'workspaces';
|
|
34
78
|
displayName = 'Workspaces';
|
|
@@ -62,7 +106,11 @@ export class WorkspacesAdapter {
|
|
|
62
106
|
async analyzeImport(data, ctx) {
|
|
63
107
|
const msg = ctx.msg;
|
|
64
108
|
const items = [];
|
|
65
|
-
|
|
109
|
+
// audit-foreign foreign-F2(适配器侧加固):同一 id 的多条记录(同一目录的多种写法 → 同一个
|
|
110
|
+
// 派生 id)必须先**归并**再规划。否则会产出同 id 的两条 Create(用户一次决策命中两条,
|
|
111
|
+
// 逐条决策语义错乱),且 applyItem 按 id 只能取到第一条 → 第二条记录的 path/title/sessionIds
|
|
112
|
+
// 静默消失。归并口径与上游内核一致:sessionIds 取并集(按裸键去重),path/title 取先到者。
|
|
113
|
+
for (const { rec, duplicateCount } of mergeWorkspaceRecordsById(data.workspaces)) {
|
|
66
114
|
const id = `workspace:${rec.id}`;
|
|
67
115
|
/** issue #45:本工作区拥有的会话 id 随计划项带上(导入选择器据此联动勾选会话) */
|
|
68
116
|
const ownedSessions = {
|
|
@@ -70,24 +118,35 @@ export class WorkspacesAdapter {
|
|
|
70
118
|
// 第二判据:sessionIds 覆盖不到的会话按「cwd 目录键相同」认领(与导出侧同一口径)
|
|
71
119
|
projectKey: projectKeyOf(rec.path),
|
|
72
120
|
};
|
|
121
|
+
// 归并发生时的可见标注(raw key=value,与既有 detail 的 current=/imported= 同风格;
|
|
122
|
+
// 绝不静默:计划里看得见「这条是被归并过的」)
|
|
123
|
+
const mergeDetail = duplicateCount > 1
|
|
124
|
+
? `duplicateIdRecords=${duplicateCount} mergedSessionIds=${rec.sessionIds.length}`
|
|
125
|
+
: '';
|
|
73
126
|
const existing = (await ctx.target.workspace.listRecords()).find((r) => r.id === rec.id);
|
|
74
127
|
if (!existing) {
|
|
75
128
|
items.push({
|
|
76
129
|
id, kind: 'Create', adapter: 'workspaces',
|
|
77
130
|
...ownedSessions,
|
|
131
|
+
...(mergeDetail !== '' ? { detail: mergeDetail } : {}),
|
|
78
132
|
description: msg('adapter.workspaceCreate', { title: rec.title ?? rec.id, path: rec.path }), severity: 'info',
|
|
79
133
|
target: { adapter: 'workspaces', ref: rec.id },
|
|
80
134
|
});
|
|
81
135
|
}
|
|
82
136
|
else if (isDeepStrictEqual(existing, rec)) {
|
|
83
|
-
items.push({
|
|
137
|
+
items.push({
|
|
138
|
+
id, kind: 'Skip', adapter: 'workspaces', ...ownedSessions,
|
|
139
|
+
...(mergeDetail !== '' ? { detail: mergeDetail } : {}),
|
|
140
|
+
description: msg('adapter.workspaceSame', { id: rec.id }), severity: 'info',
|
|
141
|
+
});
|
|
84
142
|
}
|
|
85
143
|
else {
|
|
86
144
|
items.push({
|
|
87
145
|
id, kind: 'Conflict', adapter: 'workspaces',
|
|
88
146
|
...ownedSessions,
|
|
89
147
|
description: msg('adapter.workspaceDiff', { id: rec.id }),
|
|
90
|
-
detail: `current=${JSON.stringify(existing)} imported=${JSON.stringify(rec)}
|
|
148
|
+
detail: (`current=${JSON.stringify(existing)} imported=${JSON.stringify(rec)}`
|
|
149
|
+
+ (mergeDetail !== '' ? ' ' + mergeDetail : '')).slice(0, 200),
|
|
91
150
|
severity: 'warning', target: { adapter: 'workspaces', ref: rec.id },
|
|
92
151
|
});
|
|
93
152
|
}
|
|
@@ -111,8 +170,19 @@ export class WorkspacesAdapter {
|
|
|
111
170
|
if (!ref)
|
|
112
171
|
return { ok: false, message: ctx.msg('adapter.missingTargetRef') };
|
|
113
172
|
const data = ctx.sections.get('workspaces');
|
|
114
|
-
|
|
115
|
-
|
|
173
|
+
// audit-foreign foreign-F2(适配器侧加固):同一 id 可能有多条记录(同一目录的多种写法派生同一 id)。
|
|
174
|
+
// 此前 find() 恒取第一条 → 第二条记录的 path/title/sessionIds 静默丢失(analysis.valid 仍为 true、
|
|
175
|
+
// 零告警)。这里取**全部**同 id 记录并按同一口径归并后写入 —— 绝不静默丢弃。同 id 的两条计划项
|
|
176
|
+
// 即便都执行,也只是重复写同一条归并结果(幂等)。
|
|
177
|
+
// t73 的 F2(纵深防御,两入口行为一致):非数组 / 含 null 记录的畸形载荷一律不当成记录集 ——
|
|
178
|
+
// `r.id` 直接取会在 null 上抛(validate 已拒 ⇒ 生产不可达,但这里也不让它成为新的内部 TypeError 来源)。
|
|
179
|
+
const allRecords = data === undefined || !Array.isArray(data.workspaces) ? [] : data.workspaces;
|
|
180
|
+
const sameIdRecords = allRecords.filter((r) => {
|
|
181
|
+
const raw = r;
|
|
182
|
+
return raw !== null && typeof raw === 'object' && r.id === ref;
|
|
183
|
+
});
|
|
184
|
+
const rec = sameIdRecords.length === 0 ? undefined : mergeWorkspaceRecordsById(sameIdRecords)[0]?.rec;
|
|
185
|
+
if (rec === undefined)
|
|
116
186
|
return { ok: false, message: ctx.msg('adapter.workspaceMissing', { ref }) };
|
|
117
187
|
const notes = [];
|
|
118
188
|
// issue #45 已知缺口①:备份里的工作区路径在本机不存在时,DSH registry.create() 的
|
|
@@ -195,6 +265,28 @@ export class WorkspacesAdapter {
|
|
|
195
265
|
for (const w of section.workspaces) {
|
|
196
266
|
if (w === null || typeof w !== 'object' || typeof w.id !== 'string' || typeof w.path !== 'string') {
|
|
197
267
|
issues.push({ path: 'workspaces[]', message: msg('adapter.validate.workspaceIdentity'), severity: 'error' });
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
// ui-F3:sessionIds 是会话可见性的必需字段(docs/spec/bundle-format-v1.md §6),
|
|
271
|
+
// 而 analyzeImport / finalizeImport 直接读 rec.sessionIds.length —— 缺它有两条后果:
|
|
272
|
+
// ① validate 放过后 analyzeImport 抛内部 TypeError → 整包被拦下且文案不可行动;
|
|
273
|
+
// ② 即便绕过,工作区记录也失去会话归属。这里按「必需数组」显式报出字段名。
|
|
274
|
+
if (!Array.isArray(w.sessionIds)) {
|
|
275
|
+
issues.push({ path: `workspaces.${String(w.id)}.sessionIds`, message: msg('adapter.validate.array', { subject: 'sessionIds' }), severity: 'error' });
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
// t73 的 F1:**元素级**校验 —— 归并去重会对每个元素调 sessionIdKey(字符串契约),
|
|
279
|
+
// 非字符串元素会让 analyzeImport / applyItem 抛内部 TypeError(validate 放行 ⇒ 整包被拦、文案不可行动)。
|
|
280
|
+
// 这里显式报出下标,让这种包在 validate 阶段就被拦下。
|
|
281
|
+
w.sessionIds.forEach((sid, i) => {
|
|
282
|
+
if (typeof sid !== 'string') {
|
|
283
|
+
issues.push({
|
|
284
|
+
path: `workspaces.${String(w.id)}.sessionIds[${i}]`,
|
|
285
|
+
message: msg('adapter.validate.string', { subject: `sessionIds[${i}]` }),
|
|
286
|
+
severity: 'error',
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
});
|
|
198
290
|
}
|
|
199
291
|
}
|
|
200
292
|
}
|
package/lib/cli/actions.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { readSafeModeMarkerSync } from '../core/phase3-host.ts';
|
|
|
4
4
|
import { type SnapshotMeta } from '../core/restore.ts';
|
|
5
5
|
import { type BackupFileMeta } from '../sync/backup-files.ts';
|
|
6
6
|
import { type SessionHealthScanResult } from '../utils/session-health-scan.ts';
|
|
7
|
+
import type { SessionVerifyResult } from '../utils/session-verify.ts';
|
|
7
8
|
/** 进程是否存活(不发送信号,只探测)。EPERM = 存在但无权限发信号 → 仍算存活。 */
|
|
8
9
|
export declare function isProcessAlive(pid: number): boolean;
|
|
9
10
|
/** 一个在跑的 DSH 实例(来自 `<root>/running/<profile>.json` 心跳)。 */
|
|
@@ -229,25 +230,71 @@ export interface SessionLogRepairRow {
|
|
|
229
230
|
/** 备份文件名(与日志同目录,回滚只认台账,不认用户给的路径) */
|
|
230
231
|
backupName?: string;
|
|
231
232
|
repairId?: string;
|
|
233
|
+
/**
|
|
234
|
+
* 写后真 codec 复验结论(**逐字段透传** service 的 SessionVerifyResult,不改造/不丢字段)。
|
|
235
|
+
* JSON 消费者必须据它区分三态:verified+equivalentToReadPath(现役读盘可读)/
|
|
236
|
+
* verified+!equivalentToReadPath(只有迁移链能还原)/ !verified(未验证,原因见 reason)。
|
|
237
|
+
* 预览路径不跑复验门 ⇒ 这一项缺省。
|
|
238
|
+
*/
|
|
239
|
+
verify?: SessionVerifyResult;
|
|
240
|
+
/** 确定性失败(reason='verify-failed')时:本次备份的自动回滚是否成功(false = 目标仍是修复后字节) */
|
|
241
|
+
rolledBack?: boolean;
|
|
232
242
|
message: string;
|
|
233
243
|
}
|
|
234
244
|
export interface InlineRepairOutcome {
|
|
235
245
|
ok: boolean;
|
|
236
246
|
dryRun: boolean;
|
|
237
247
|
rows: SessionLogRepairRow[];
|
|
238
|
-
/**
|
|
248
|
+
/**
|
|
249
|
+
* 离线出口命令(可复制去终端)。
|
|
250
|
+
*
|
|
251
|
+
* **不是本入口的等价实现** —— 见 `repairSessionLogInline` 的能力边界:`sessions repair` 只做
|
|
252
|
+
* 布局归位与重复 id 隔离,不改写会话字节;字节级离线通道只有救急台 `dcm web`。
|
|
253
|
+
*/
|
|
239
254
|
commands: string[];
|
|
240
255
|
error?: string;
|
|
241
256
|
}
|
|
257
|
+
/**
|
|
258
|
+
* 真 codec 复验结论 → 一句人话(**三态**;服务层 utils/session-verify.ts 的定义为准)。
|
|
259
|
+
*
|
|
260
|
+
* · verified && equivalentToReadPath → 「现役读盘可读」= header.version === catalog.currentVersion === 已装版本,
|
|
261
|
+
* DSH 的现役读盘路径此刻就能直接读它;
|
|
262
|
+
* · verified && !equivalentToReadPath → 只有**迁移链**能还原(pre-v4 日志:官方 resolveCurrentLog 对本代之前的
|
|
263
|
+
* 代际返回 undefined,即「没有现役日志」);
|
|
264
|
+
* · !verified → 「**未验证**」= 本机跑不了真 codec 门(如 available catalog 缺席 / 代际对不上 /
|
|
265
|
+
* 缺子会话事实)——**这是最常见的一态,必须说出来**,绝不能让它看起来像成功;
|
|
266
|
+
* · verify 缺失(改造前的旧结果 / 预览路径)→ 空串:调用方保持原文案,绝不臆造「已验证」。
|
|
267
|
+
*/
|
|
268
|
+
export declare function sessionVerifyNoteOf(verify: SessionVerifyResult | undefined): string;
|
|
269
|
+
/** 会话修复行的文案入参(只吃机器可读事实 —— 便于单测与两边共用)。 */
|
|
270
|
+
export interface SessionRepairRowFacts {
|
|
271
|
+
ok: boolean;
|
|
272
|
+
reason?: string;
|
|
273
|
+
droppedRows?: number;
|
|
274
|
+
backupName?: string;
|
|
275
|
+
rolledBack?: boolean;
|
|
276
|
+
verify?: SessionVerifyResult;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* 会话修复行 → message(CLI 与离线救急台**同一份**文案)。
|
|
280
|
+
*
|
|
281
|
+
* 成功路径按 verify 分三态;**!verified 时不出现无限定的成功表述**(先声明未验证,再如实说写入已生效);
|
|
282
|
+
* verify 缺失时**逐字保持改造前的文案**(向后兼容,不臆造);verify-failed 时说明已自动回滚 + 官方错误 detail。
|
|
283
|
+
*/
|
|
284
|
+
export declare function sessionRepairRowMessage(facts: SessionRepairRowFacts): string;
|
|
242
285
|
/**
|
|
243
286
|
* **就地修复「重放重复行」**(离线救急台 /sessions 页的写入口)。
|
|
244
287
|
*
|
|
245
288
|
* 能力边界(**不得放宽**):
|
|
246
289
|
* - 只做 `session-repair-service` 已有的那一类 —— 字节相同 + seq 相同的重放重复行(零损失);
|
|
247
290
|
* 其余类别(合成 closer / seq 空洞 / 不可解析行 / 容器非法 / header 不可读 / 子代理缺父)
|
|
248
|
-
*
|
|
291
|
+
* **只报告**,绝不在这里扩张(设计稿 §10.3/§10.4 的 G-23 界限)。
|
|
292
|
+
* - **离线出口只有一个**:救急台 `dsh-config-manager web`(别名 `dcm web`)—— 它调用的就是本函数。
|
|
293
|
+
* CLI 的 `sessions repair`(加 `--fix`/`--apply` 才落盘)**不是**字节级修复的等价命令:
|
|
294
|
+
* 它只做**布局归位**(按首帧 cwd 把目录搬回 `projectKeyOf(cwd)`)与**重复 id 隔离**,不碰会话字节。
|
|
295
|
+
* 此前把 `sessions repair --apply` 写成「等价命令」是不实表述(已订正,见下面的 `commands`)。
|
|
249
296
|
* - 三道写入门由服务层自持:单元必须解析到会话根内 / 无 `session.lock` / 文件不在 30s 静止期内;
|
|
250
|
-
* 「DSH 已停」这一条由 `checkWriteGates`
|
|
297
|
+
* 「DSH 已停」这一条由 `checkWriteGates` 在这里补上(与 CLI 写动作共用同一道写入门,
|
|
251
298
|
* 比应用内 T8 通道更严:T8 跑在 DSH 内部,靠静止期而非停机)。
|
|
252
299
|
* - 与 CLI 同源:预览-应用指纹一致(TOCTOU)/ 时间戳备份 / 原子换入 / 写后复验,全在服务层。
|
|
253
300
|
*
|
package/lib/cli/actions.js
CHANGED
|
@@ -19,6 +19,7 @@ import { EXPORTS_RETENTION_DEFAULT_MS, MARKET_RETENTION_DEFAULT_MS, TMP_RETENTIO
|
|
|
19
19
|
import { scanDiskUsage } from '../core/disk-usage.js';
|
|
20
20
|
import { readSafeModeMarkerSync, safeModeMarkerPath } from '../core/phase3-host.js';
|
|
21
21
|
import { listSnapshots } from '../core/restore.js';
|
|
22
|
+
import { readInstalledVersion, resolveProfileDir } from '../core/plugin-cli.js';
|
|
22
23
|
import { DshProfileError, DshProfileManager } from '../profiles/dsh-profile-manager.js';
|
|
23
24
|
import { DshProfileLauncher, LAUNCHES_FILENAME, parseLaunches } from '../profiles/dsh-profile-launcher.js';
|
|
24
25
|
import { DshProfileRuntimeRegistry, parseRuntimeRecord, RUNTIME_STALE_MS } from '../profiles/dsh-profile-runtime.js';
|
|
@@ -345,15 +346,74 @@ export async function checkWriteGates(controlRoots, options = { needsDshStopped:
|
|
|
345
346
|
}
|
|
346
347
|
return { ok: true };
|
|
347
348
|
}
|
|
349
|
+
/* ----------------------------------------------- 会话修复行的文案(纯函数,可单测) */
|
|
350
|
+
/**
|
|
351
|
+
* 真 codec 复验结论 → 一句人话(**三态**;服务层 utils/session-verify.ts 的定义为准)。
|
|
352
|
+
*
|
|
353
|
+
* · verified && equivalentToReadPath → 「现役读盘可读」= header.version === catalog.currentVersion === 已装版本,
|
|
354
|
+
* DSH 的现役读盘路径此刻就能直接读它;
|
|
355
|
+
* · verified && !equivalentToReadPath → 只有**迁移链**能还原(pre-v4 日志:官方 resolveCurrentLog 对本代之前的
|
|
356
|
+
* 代际返回 undefined,即「没有现役日志」);
|
|
357
|
+
* · !verified → 「**未验证**」= 本机跑不了真 codec 门(如 available catalog 缺席 / 代际对不上 /
|
|
358
|
+
* 缺子会话事实)——**这是最常见的一态,必须说出来**,绝不能让它看起来像成功;
|
|
359
|
+
* · verify 缺失(改造前的旧结果 / 预览路径)→ 空串:调用方保持原文案,绝不臆造「已验证」。
|
|
360
|
+
*/
|
|
361
|
+
export function sessionVerifyNoteOf(verify) {
|
|
362
|
+
if (verify === undefined)
|
|
363
|
+
return '';
|
|
364
|
+
if (verify.verified) {
|
|
365
|
+
return verify.equivalentToReadPath
|
|
366
|
+
? '真 codec 复验通过(现役读盘可读)。'
|
|
367
|
+
: '真 codec 复验通过(迁移链可还原,非现役读盘)。';
|
|
368
|
+
}
|
|
369
|
+
return '未验证:本机无法运行真 codec 复验(' + verify.reason + ')。';
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* 会话修复行 → message(CLI 与离线救急台**同一份**文案)。
|
|
373
|
+
*
|
|
374
|
+
* 成功路径按 verify 分三态;**!verified 时不出现无限定的成功表述**(先声明未验证,再如实说写入已生效);
|
|
375
|
+
* verify 缺失时**逐字保持改造前的文案**(向后兼容,不臆造);verify-failed 时说明已自动回滚 + 官方错误 detail。
|
|
376
|
+
*/
|
|
377
|
+
export function sessionRepairRowMessage(facts) {
|
|
378
|
+
const dropped = String(facts.droppedRows ?? 0);
|
|
379
|
+
const backup = String(facts.backupName ?? '(未落盘)');
|
|
380
|
+
if (!facts.ok) {
|
|
381
|
+
if (facts.reason === 'verify-failed') {
|
|
382
|
+
const rolled = facts.rolledBack === true
|
|
383
|
+
? '已自动回滚到修复前字节'
|
|
384
|
+
: facts.rolledBack === false
|
|
385
|
+
? '已自动回滚未成功(目标仍是修复后字节,需人工处理)'
|
|
386
|
+
: '已自动回滚(服务层未回传结果,请以目标字节为准)';
|
|
387
|
+
const detail = facts.verify !== undefined && !facts.verify.verified && facts.verify.detail !== undefined && facts.verify.detail !== ''
|
|
388
|
+
? ';官方错误:' + facts.verify.detail
|
|
389
|
+
: '';
|
|
390
|
+
return '未修复(verify-failed):真 codec 复验未通过,' + rolled + detail + '。';
|
|
391
|
+
}
|
|
392
|
+
return '未修复(' + (facts.reason ?? 'unknown') + '):原文件未改动。';
|
|
393
|
+
}
|
|
394
|
+
if (facts.verify === undefined) {
|
|
395
|
+
// 向后兼容:没有复验结论就不添油加醋(改造前逐字如此)
|
|
396
|
+
return '已丢弃 ' + dropped + ' 行重放重复事件;备份 ' + backup;
|
|
397
|
+
}
|
|
398
|
+
if (facts.verify.verified) {
|
|
399
|
+
return '已丢弃 ' + dropped + ' 行重放重复事件;备份 ' + backup + '。' + sessionVerifyNoteOf(facts.verify);
|
|
400
|
+
}
|
|
401
|
+
return sessionVerifyNoteOf(facts.verify)
|
|
402
|
+
+ '写入已生效(已丢弃 ' + dropped + ' 行重放重复事件;备份 ' + backup + ')——本机 DSH 能否现役读它**没有被证明**,可用 repairId 回滚。';
|
|
403
|
+
}
|
|
348
404
|
/**
|
|
349
405
|
* **就地修复「重放重复行」**(离线救急台 /sessions 页的写入口)。
|
|
350
406
|
*
|
|
351
407
|
* 能力边界(**不得放宽**):
|
|
352
408
|
* - 只做 `session-repair-service` 已有的那一类 —— 字节相同 + seq 相同的重放重复行(零损失);
|
|
353
409
|
* 其余类别(合成 closer / seq 空洞 / 不可解析行 / 容器非法 / header 不可读 / 子代理缺父)
|
|
354
|
-
*
|
|
410
|
+
* **只报告**,绝不在这里扩张(设计稿 §10.3/§10.4 的 G-23 界限)。
|
|
411
|
+
* - **离线出口只有一个**:救急台 `dsh-config-manager web`(别名 `dcm web`)—— 它调用的就是本函数。
|
|
412
|
+
* CLI 的 `sessions repair`(加 `--fix`/`--apply` 才落盘)**不是**字节级修复的等价命令:
|
|
413
|
+
* 它只做**布局归位**(按首帧 cwd 把目录搬回 `projectKeyOf(cwd)`)与**重复 id 隔离**,不碰会话字节。
|
|
414
|
+
* 此前把 `sessions repair --apply` 写成「等价命令」是不实表述(已订正,见下面的 `commands`)。
|
|
355
415
|
* - 三道写入门由服务层自持:单元必须解析到会话根内 / 无 `session.lock` / 文件不在 30s 静止期内;
|
|
356
|
-
* 「DSH 已停」这一条由 `checkWriteGates`
|
|
416
|
+
* 「DSH 已停」这一条由 `checkWriteGates` 在这里补上(与 CLI 写动作共用同一道写入门,
|
|
357
417
|
* 比应用内 T8 通道更严:T8 跑在 DSH 内部,靠静止期而非停机)。
|
|
358
418
|
* - 与 CLI 同源:预览-应用指纹一致(TOCTOU)/ 时间戳备份 / 原子换入 / 写后复验,全在服务层。
|
|
359
419
|
*
|
|
@@ -363,12 +423,16 @@ export async function checkWriteGates(controlRoots, options = { needsDshStopped:
|
|
|
363
423
|
export async function repairSessionLogInline(options, controlRoots) {
|
|
364
424
|
const base = {
|
|
365
425
|
ok: true, dryRun: !options.apply, rows: [],
|
|
366
|
-
|
|
426
|
+
// 不得再把 `sessions repair --apply` 说成等价命令:它只做布局归位与重复 id 隔离,不改写会话字节。
|
|
427
|
+
commands: [
|
|
428
|
+
'dsh-config-manager web # 离线救急台:字节级就地修复的唯一离线通道(别名 dcm web)',
|
|
429
|
+
'dsh-config-manager sessions repair # 只做布局归位与重复 id 隔离,不改写会话字节(--fix/--apply 才落盘)',
|
|
430
|
+
],
|
|
367
431
|
};
|
|
368
432
|
if (options.unitIds.length === 0)
|
|
369
433
|
return { ...base, ok: false, error: '没有选中任何会话单元。' };
|
|
370
434
|
if (options.apply) {
|
|
371
|
-
// 与
|
|
435
|
+
// 与 CLI 写动作共用同一道写入门:改写会话字节必须先停 DSH(+ SAFE MODE + 环境锁)
|
|
372
436
|
const gate = await checkWriteGates(controlRoots, { needsDshStopped: true });
|
|
373
437
|
if (!gate.ok)
|
|
374
438
|
return { ...base, ok: false, error: gate.reason };
|
|
@@ -388,7 +452,8 @@ export async function repairSessionLogInline(options, controlRoots) {
|
|
|
388
452
|
...(preview.expect !== undefined ? { expect: preview.expect } : {}),
|
|
389
453
|
message: preview.ok
|
|
390
454
|
? '可零损失修复:将丢弃 ' + String(preview.droppedRows ?? 0) + ' 行重放重复事件。'
|
|
391
|
-
: '不可修复(' + (preview.reason ?? 'unknown') + '
|
|
455
|
+
: '不可修复(' + (preview.reason ?? 'unknown') + '):这一类只报告,本入口绝不改写它的字节;'
|
|
456
|
+
+ '字节级离线出口是救急台 dsh-config-manager web(sessions repair 只做布局归位与重复 id 隔离)。',
|
|
392
457
|
});
|
|
393
458
|
continue;
|
|
394
459
|
}
|
|
@@ -397,18 +462,22 @@ export async function repairSessionLogInline(options, controlRoots) {
|
|
|
397
462
|
homeDir: options.home, dataDir: options.dataDir, unitId,
|
|
398
463
|
...(expect !== undefined ? { expect } : {}),
|
|
399
464
|
});
|
|
400
|
-
|
|
401
|
-
|
|
465
|
+
// 文案与结构化字段同源:verify 逐字段透传(JSON 消费者据它区分三态),message 由纯函数分派
|
|
466
|
+
const facts = {
|
|
402
467
|
ok: applied.ok,
|
|
403
468
|
...(applied.reason !== undefined ? { reason: applied.reason } : {}),
|
|
404
469
|
...(applied.droppedRows !== undefined ? { droppedRows: applied.droppedRows } : {}),
|
|
470
|
+
...(applied.backupName !== undefined ? { backupName: applied.backupName } : {}),
|
|
471
|
+
...(applied.rolledBack !== undefined ? { rolledBack: applied.rolledBack } : {}),
|
|
472
|
+
...(applied.verify !== undefined ? { verify: applied.verify } : {}),
|
|
473
|
+
};
|
|
474
|
+
rows.push({
|
|
475
|
+
unitId,
|
|
476
|
+
...facts,
|
|
405
477
|
...(applied.bytesBefore !== undefined ? { bytesBefore: applied.bytesBefore } : {}),
|
|
406
478
|
...(applied.bytesAfter !== undefined ? { bytesAfter: applied.bytesAfter } : {}),
|
|
407
|
-
...(applied.backupName !== undefined ? { backupName: applied.backupName } : {}),
|
|
408
479
|
...(applied.repairId !== undefined ? { repairId: applied.repairId } : {}),
|
|
409
|
-
message:
|
|
410
|
-
? '已丢弃 ' + String(applied.droppedRows ?? 0) + ' 行重放重复事件;备份 ' + String(applied.backupName ?? '(未落盘)')
|
|
411
|
-
: '未修复(' + (applied.reason ?? 'unknown') + '):原文件未改动。',
|
|
480
|
+
message: sessionRepairRowMessage(facts),
|
|
412
481
|
});
|
|
413
482
|
}
|
|
414
483
|
return { ...base, ok: rows.every((r) => r.ok || !options.apply), rows };
|
|
@@ -782,6 +851,27 @@ export async function unlockEncryptedBackup(exportsDir, fileName, password) {
|
|
|
782
851
|
function isDangerousRestoreKind(kind) {
|
|
783
852
|
return kind === 'hostFileRestore' || kind === 'hostFileRemove' || kind === 'fileRestore' || kind === 'fileRemove' || kind === 'pluginRemove';
|
|
784
853
|
}
|
|
854
|
+
/** 本机 DSH 包名(T8-F3;与 core/restore.ts 的 `DSH_PACKAGE_NAME` 同值 —— 两处读的是同一个文件)。 */
|
|
855
|
+
const DSH_PACKAGE_NAME = '@deepseek-ai/dsh';
|
|
856
|
+
/**
|
|
857
|
+
* 目标档案当前的 DSH 版本(T8-F3;离线 CLI 的 best-effort 来源)。
|
|
858
|
+
*
|
|
859
|
+
* 为什么是这个来源:CLI 恰恰在 **DSH 已经起不来** 的场景下运行,没有「运行时权威版本」可问
|
|
860
|
+
* (那是宿主侧的东西:`HostContext.dshVersion` / `profileContext.installAnchor`)。这里与
|
|
861
|
+
* `core/restore.ts` 的兜底、档案页的 `DshProfileMeta.dshVersion` **读的是同一个文件**
|
|
862
|
+
* (`profiles/<p>/node_modules/@deepseek-ai/dsh/package.json`),所以显式传出不改变数值,
|
|
863
|
+
* 但把「版本判定来源」固定在一处(将来 CLI 若拿到更好的来源只改这里),且不再让 core 猜一次。
|
|
864
|
+
* 读不到 → undefined:core 按「版本未知」处理(不猜、不产出「版本不同」告警)。
|
|
865
|
+
*/
|
|
866
|
+
function currentProfileDshVersion(paths) {
|
|
867
|
+
try {
|
|
868
|
+
return readInstalledVersion(resolveProfileDir(paths.homeDir, paths.profile), DSH_PACKAGE_NAME) ?? undefined;
|
|
869
|
+
}
|
|
870
|
+
catch {
|
|
871
|
+
// 档案名非法 / 目录不可读 → 与「没装」同样处理:不猜版本(绝不因此让恢复计划失败)
|
|
872
|
+
return undefined;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
785
875
|
/**
|
|
786
876
|
* 取某个快照的**恢复计划**(只读;与 CLI \`restore --dry-run\` 同一实现)。
|
|
787
877
|
*
|
|
@@ -796,6 +886,7 @@ export async function planSnapshotRestore(paths, snapshotId) {
|
|
|
796
886
|
homeDir: paths.homeDir,
|
|
797
887
|
profile: paths.profile,
|
|
798
888
|
snapshotsRoot: paths.snapshotsDir,
|
|
889
|
+
currentDshVersion: currentProfileDshVersion(paths),
|
|
799
890
|
});
|
|
800
891
|
return {
|
|
801
892
|
ok: true,
|
|
@@ -837,6 +928,7 @@ export async function runSnapshotRestore(paths, snapshotId) {
|
|
|
837
928
|
homeDir: paths.homeDir,
|
|
838
929
|
profile: paths.profile,
|
|
839
930
|
snapshotsRoot: paths.snapshotsDir,
|
|
931
|
+
currentDshVersion: currentProfileDshVersion(paths),
|
|
840
932
|
});
|
|
841
933
|
return {
|
|
842
934
|
ok: report.failed.length === 0,
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 离线 CLI 帮助文案的单一事实源(2026-10 整理)。
|
|
3
|
+
*
|
|
4
|
+
* 帮助分两层,都由本文件渲染,**绝不在 index.ts 里再散写一遍文案**:
|
|
5
|
+
* - 速查页(`dcm help`):按风险分组的命令表 + 通用选项,目标是「30 行内扫一眼就知道用哪个」;
|
|
6
|
+
* - 详情页(`dcm <命令> --help` / `dcm help <命令>`):说明 / 选项 / 退出码 / 示例。
|
|
7
|
+
*
|
|
8
|
+
* 两条渲染约定(改文案前先读):
|
|
9
|
+
* 1. 速查页的「用法」列**只用 ASCII**(占位符写 `<file|path>` 而不是 `<文件|路径>`):
|
|
10
|
+
* CJK 是双宽字符,混进 padEnd 对齐的一列会让整页参差。
|
|
11
|
+
* 2. 退出码必须与实现一致 —— 判定逻辑在各 run* 函数里,这里只是结论;改了行为要同步改这里。
|
|
12
|
+
*/
|
|
13
|
+
export declare const IMPORT_SOURCE_IDS: readonly string[];
|
|
14
|
+
/** 详情页里的一个「左列 + 右列」条目(选项 / 退出码 / 子命令都用它) */
|
|
15
|
+
export interface HelpEntry {
|
|
16
|
+
/** 左列,只用 ASCII */
|
|
17
|
+
readonly flag: string;
|
|
18
|
+
/** 右列说明(中文) */
|
|
19
|
+
readonly desc: string;
|
|
20
|
+
}
|
|
21
|
+
export interface HelpSection {
|
|
22
|
+
readonly title: string;
|
|
23
|
+
readonly entries: readonly HelpEntry[];
|
|
24
|
+
}
|
|
25
|
+
export interface CommandHelp {
|
|
26
|
+
/** 命令名(`dcm <name> --help` 与 `dcm help <name>` 的键) */
|
|
27
|
+
readonly name: string;
|
|
28
|
+
/** 详情页首行:`<name> — <title>` */
|
|
29
|
+
readonly title: string;
|
|
30
|
+
/** 速查页里那一行的用法片段(ASCII only、尽量短) */
|
|
31
|
+
readonly usage: string;
|
|
32
|
+
/** 速查页里那一行的摘要(中文、一行) */
|
|
33
|
+
readonly summary: string;
|
|
34
|
+
/** 详情页「用法」段(不含 `dcm` 前缀,每项一行) */
|
|
35
|
+
readonly usageLines: readonly string[];
|
|
36
|
+
/** 详情页「说明」段(每项一行) */
|
|
37
|
+
readonly description: readonly string[];
|
|
38
|
+
/** 详情页的键值段,按声明顺序渲染 */
|
|
39
|
+
readonly sections: readonly HelpSection[];
|
|
40
|
+
/** 详情页「示例」 */
|
|
41
|
+
readonly examples: readonly string[];
|
|
42
|
+
}
|
|
43
|
+
export interface HelpRow {
|
|
44
|
+
/** 用法片段(ASCII only) */
|
|
45
|
+
readonly usage: string;
|
|
46
|
+
/** 一行摘要 */
|
|
47
|
+
readonly summary: string;
|
|
48
|
+
/** 该行指向的详情页(CommandHelp.name;`sessions` 有三行指向同一页) */
|
|
49
|
+
readonly help: string;
|
|
50
|
+
}
|
|
51
|
+
export interface HelpGroup {
|
|
52
|
+
readonly title: string;
|
|
53
|
+
readonly rows: readonly HelpRow[];
|
|
54
|
+
}
|
|
55
|
+
/** 通用选项(所有命令共有)——命令专属选项只出现在各自的详情页里 */
|
|
56
|
+
export declare const GENERAL_OPTIONS: readonly HelpEntry[];
|
|
57
|
+
/** 分组顺序 = 推荐阅读顺序:先诊断、再备份、再修复、最后才是危险的重装 */
|
|
58
|
+
export declare const HELP_GROUPS: readonly HelpGroup[];
|
|
59
|
+
export declare const COMMAND_HELP: readonly CommandHelp[];
|
|
60
|
+
/** 速查页「用法」列的宽度(全表统一,保证摘要起始列一致) */
|
|
61
|
+
export declare function usageColumnWidth(): number;
|
|
62
|
+
/** 速查页(`dcm help`):分组命令表 + 通用选项 + 上手顺序 */
|
|
63
|
+
export declare function renderOverview(version: string): string[];
|
|
64
|
+
/** 单命令详情页;不认识的名字返回 null(调用方决定怎么报错) */
|
|
65
|
+
export declare function renderCommandHelp(name: string, version: string): string[] | null;
|