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
package/lib/cli/web/page.d.ts
CHANGED
|
@@ -9,15 +9,22 @@ export interface PageChrome {
|
|
|
9
9
|
paths: RescuePaths;
|
|
10
10
|
active: 'home' | 'disk' | 'sessions' | 'profiles' | 'unlock' | 'restore' | 'export' | 'reinstall';
|
|
11
11
|
}
|
|
12
|
+
export declare function esc(value: string): string;
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
+
* **只转义、不脱敏**的展示出口:唯一用途是救急台**有意**回传给终端用户的「能力 URL」
|
|
15
|
+
* (启动器从子进程日志抓到的带 token 的认证 URL)。
|
|
14
16
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
17
|
+
* 为什么必须与 esc() 分开(cli-F1):esc() 先过安全侧 redact(),而 redact 的 URL_QUERY_RE
|
|
18
|
+
* 会把 `?token=…` 的值抹成 ***REDACTED*** —— 那正是认证 URL 的形态,于是页面给出一条必然
|
|
19
|
+
* 401 的死链(/profiles 的「打开实例」入口 + 启动结果页)。这些 URL 与终端里打印的 bootstrap
|
|
20
|
+
* URL 同一性质:只给拿到会话 cookie 的人,本来就该原样可见。
|
|
21
|
+
* 纪律:**只允许**用于本层自己签发/抓取的能力 URL;其余一切文本仍走 esc()。
|
|
18
22
|
*/
|
|
19
|
-
export declare function
|
|
23
|
+
export declare function escCapability(value: string): string;
|
|
20
24
|
export declare function formatBytes(bytes: number): string;
|
|
25
|
+
type Cell = string | {
|
|
26
|
+
html: string;
|
|
27
|
+
};
|
|
21
28
|
export declare function renderLayout(chrome: PageChrome, body: string, subtitle?: string): string;
|
|
22
29
|
/** 独立极简页(403/404 用;不依赖任何目录事实,避免在错误路径上再读盘)。 */
|
|
23
30
|
export declare function renderMessagePage(title: string, message: string, hint?: string): string;
|
|
@@ -113,7 +120,9 @@ export declare function renderConfirmForm(options: {
|
|
|
113
120
|
note?: string;
|
|
114
121
|
}): string;
|
|
115
122
|
/** 写动作结果页(完成 / 失败共用;结果如实逐条列)。 */
|
|
116
|
-
export declare function renderResultPage(title: string,
|
|
123
|
+
export declare function renderResultPage(title: string,
|
|
124
|
+
/** 逐条结果:默认过 esc()(脱敏+转义);`{ html }` 仅用于已自行转义的能力 URL 行 */
|
|
125
|
+
lines: readonly Cell[], version: string, paths: RescuePaths, kind: 'ok' | 'bad' | 'warn' | string,
|
|
117
126
|
/** 「返回上一页」在禁用 JS 时的落点(有 JS 时走 history.back(),回到列表页并由状态恢复脚本定位) */
|
|
118
127
|
backHref?: string): string;
|
|
119
128
|
/** 残留锁页:展示锁状态 + 显式回收表单(活锁一律不给可点的回收理由)。 */
|
|
@@ -135,3 +144,4 @@ export declare function renderReinstallPage(items: ReadonlyArray<{
|
|
|
135
144
|
export declare function renderVerifyPage(result: BackupVerifyResult, version: string, paths: RescuePaths): string;
|
|
136
145
|
/** 档案页:列表 + 启停表单(每个可启动档案一张卡;不可启动的写明原因)。 */
|
|
137
146
|
export declare function renderProfilesPage(outcome: ProfilesOutcome, version: string, paths: RescuePaths, actionToken: string, done: string, result: string): string;
|
|
147
|
+
export {};
|
package/lib/cli/web/page.js
CHANGED
|
@@ -157,13 +157,29 @@ const SKELETON = '<div class="skeleton" aria-hidden="true">'
|
|
|
157
157
|
* 失败原因直接渲染出来,里面可能夹带形如 `"apiKey": "…"` / `?token=…` 的内容(§7 纪律:
|
|
158
158
|
* 展示文本渲染前一律过 `redact()`,插件 UI 与 CLI 都遵守,这里不能例外)。
|
|
159
159
|
*/
|
|
160
|
-
|
|
161
|
-
return
|
|
160
|
+
function escapeHtml(value) {
|
|
161
|
+
return value
|
|
162
162
|
.replace(/&/g, '&')
|
|
163
163
|
.replace(/</g, '<')
|
|
164
164
|
.replace(/>/g, '>')
|
|
165
165
|
.replace(/"/g, '"');
|
|
166
166
|
}
|
|
167
|
+
export function esc(value) {
|
|
168
|
+
return escapeHtml(redact(value));
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* **只转义、不脱敏**的展示出口:唯一用途是救急台**有意**回传给终端用户的「能力 URL」
|
|
172
|
+
* (启动器从子进程日志抓到的带 token 的认证 URL)。
|
|
173
|
+
*
|
|
174
|
+
* 为什么必须与 esc() 分开(cli-F1):esc() 先过安全侧 redact(),而 redact 的 URL_QUERY_RE
|
|
175
|
+
* 会把 `?token=…` 的值抹成 ***REDACTED*** —— 那正是认证 URL 的形态,于是页面给出一条必然
|
|
176
|
+
* 401 的死链(/profiles 的「打开实例」入口 + 启动结果页)。这些 URL 与终端里打印的 bootstrap
|
|
177
|
+
* URL 同一性质:只给拿到会话 cookie 的人,本来就该原样可见。
|
|
178
|
+
* 纪律:**只允许**用于本层自己签发/抓取的能力 URL;其余一切文本仍走 esc()。
|
|
179
|
+
*/
|
|
180
|
+
export function escCapability(value) {
|
|
181
|
+
return escapeHtml(value);
|
|
182
|
+
}
|
|
167
183
|
export function formatBytes(bytes) {
|
|
168
184
|
if (bytes < 1024)
|
|
169
185
|
return String(bytes) + ' B';
|
|
@@ -203,13 +219,19 @@ function section(title, body) {
|
|
|
203
219
|
return '<h2>' + esc(title) + '</h2><section class="card">' + body + '</section>';
|
|
204
220
|
}
|
|
205
221
|
/* ------------------------------------------------------------ 布局 */
|
|
222
|
+
/**
|
|
223
|
+
* 救急台是**多页**的(首页 / 会话 / 恢复 / 磁盘 …),所以「本页」这个词必须能落地:
|
|
224
|
+
* 要么指向**本页内真实存在**的入口,要么**点名到页**(C1d 口径,captain 裁决)。
|
|
225
|
+
* 页面名在这里只定义一次,导航与跨页指引共用,免得两处说法漂移。
|
|
226
|
+
*/
|
|
227
|
+
const RESTORE_PAGE_LABEL = '恢复';
|
|
206
228
|
function renderHeader(chrome, subtitle) {
|
|
207
229
|
const items = [
|
|
208
230
|
['home', '/', '首页'],
|
|
209
231
|
['disk', '/disk', '磁盘占用'],
|
|
210
232
|
['sessions', '/sessions', '会话体检'],
|
|
211
233
|
['profiles', '/profiles', '档案与实例'],
|
|
212
|
-
['restore', '/restore',
|
|
234
|
+
['restore', '/restore', RESTORE_PAGE_LABEL],
|
|
213
235
|
['export', '/export', '导出'],
|
|
214
236
|
['unlock', '/unlock', '解锁'],
|
|
215
237
|
['reinstall', '/reinstall', '重装'],
|
|
@@ -287,6 +309,8 @@ export function renderHomePage(input) {
|
|
|
287
309
|
* 用户找不到某个按钮时会以为是坏了,而不是「这台机器离线做不到」。把边界写在最上面最省事。
|
|
288
310
|
*/
|
|
289
311
|
function capabilityBody() {
|
|
312
|
+
// 两段文案都经 rows() 的 esc(note) 渲染(HTML 转义):这里写 <strong> 会被转义成字面标签、
|
|
313
|
+
// 写 ** 会显示成字面星号 —— 两种都不行,所以这些说明里不放任何强调标记(C1d)。
|
|
290
314
|
const can = [
|
|
291
315
|
['看', '实例心跳 / SAFE MODE / 残留锁 / 快照 / 备份产物 / 磁盘占用 / 会话体检 / 档案'],
|
|
292
316
|
['自检备份', '每个导出产物一键做结构与完整性校验(与命令行 verify 同一实现)'],
|
|
@@ -297,11 +321,11 @@ function capabilityBody() {
|
|
|
297
321
|
['清磁盘', '可重建缓存与过期导出产物(导入前快照与同步数据永不在候选集内)'],
|
|
298
322
|
['回收残留锁', '仅当持有进程被确证不存在时(活锁一律拒绝)'],
|
|
299
323
|
['启停实例', '把某个档案作为独立实例启动,或停止它(含手动启动的外部实例)'],
|
|
300
|
-
['重装 DSH', '卸载并重装全局 DSH ——
|
|
324
|
+
['重装 DSH', '卸载并重装全局 DSH —— 需要终端里打印的 6 位确认码,页面里看不到它'],
|
|
301
325
|
];
|
|
302
326
|
const cannot = [
|
|
303
|
-
['导入配置(把包写回本机)', '
|
|
304
|
-
['看运行中 DSH 的配置值', '离线读不到 settings / plugins / mcp
|
|
327
|
+
['导入配置(把包写回本机)', '结构化分区的值必须经 DSH 服务门面写入 —— 用 GUI(本页能做导出与恢复,不做导入)'],
|
|
328
|
+
['看运行中 DSH 的配置值', '离线读不到 settings / plugins / mcp 等结构化分区的值;但加密备份解锁后能看到包内文件清单'],
|
|
305
329
|
['同步通道(git / WebDAV)', '通道密码与令牌存在 DSH credentials 里,离线取不到'],
|
|
306
330
|
['凭据值', '凭据不可回读,任何时候都不显示'],
|
|
307
331
|
];
|
|
@@ -378,7 +402,10 @@ function snapshotsBody(snapshots, unreadable = false) {
|
|
|
378
402
|
String(s.entryCount),
|
|
379
403
|
]);
|
|
380
404
|
return renderTable(['ID', '创建时间', '来源备份', '状态', '条目数'], rows)
|
|
381
|
-
|
|
405
|
+
// C1d 口径:救急台是多页的 ⇒ 这里必须**点名到页**,不能再用空泛的「本页不提供」
|
|
406
|
+
// 抹掉用户在本工具里已经能做的事(恢复写入口在 「恢复」页,POST /restore/run)。
|
|
407
|
+
+ '<p class="muted">恢复(restore)是写动作,本页(首页)不提供;请在「' + RESTORE_PAGE_LABEL
|
|
408
|
+
+ '」页执行(先看逐项计划,确认后才落盘)。命令行侧可用 <code>dsh-config-manager restore --dry-run</code> 先看计划。</p>';
|
|
382
409
|
}
|
|
383
410
|
/**
|
|
384
411
|
* 备份名 → 不透明校验 id(sha256 前 16 位 hex)。
|
|
@@ -418,6 +445,8 @@ function offlineBody() {
|
|
|
418
445
|
+ '导入后的工作区登记(必须经 workspace registry)——「看不到」不等于「没有」。</p>';
|
|
419
446
|
}
|
|
420
447
|
/* ------------------------------------------------------------ 磁盘占用 */
|
|
448
|
+
/** 磁盘清理卡的标题:保留期说明要按名字指向它 —— 同一事实只有一处措辞(C1d)。 */
|
|
449
|
+
const DISK_CLEANUP_SECTION_TITLE = '清理磁盘(写动作)';
|
|
421
450
|
export function renderDiskPage(report, version, paths, actionToken, done) {
|
|
422
451
|
const chrome = { version, paths, active: 'disk' };
|
|
423
452
|
const rows = DISK_USAGE_AREAS.map((area) => {
|
|
@@ -441,16 +470,20 @@ export function renderDiskPage(report, version, paths, actionToken, done) {
|
|
|
441
470
|
+ unreadableAreas.map((area) => '<code>' + esc(area) + '</code>').join('、') + '。</p>');
|
|
442
471
|
const retention = '<p class="muted">定时备份保留最近 ' + String(report.backupRetention.keepLast)
|
|
443
472
|
+ ' 个(最新一份 ' + esc(formatBytes(report.backupRetention.latestBackupBytes)) + ','
|
|
444
|
-
|
|
473
|
+
// C1d:清理的写入口**就在本页下一张卡**(/disk/cleanup,见 :DISK_CLEANUP_SECTION_TITLE),
|
|
474
|
+
// 旧文案「本页不提供」与它自相矛盾。按裁决 (a) 指向本页真实存在的入口。
|
|
475
|
+
+ esc(formatIso(report.backupRetention.latestBackupAt)) + ')。清理是写动作,就在本页下方「'
|
|
476
|
+
+ DISK_CLEANUP_SECTION_TITLE + '」卡里执行(需显式确认)。</p>';
|
|
445
477
|
const parts = [section('磁盘占用(只读体检)', summary + renderTable(['子区', '体积', '文件数', '回收策略', '已超期'], rows) + retention)];
|
|
446
478
|
if (done === 'cleaned')
|
|
447
479
|
parts.unshift(banner('ok', '清理已完成', '结果见下方逐条明细(本次操作的回执)。'));
|
|
448
480
|
const cleanable = report.reclaimableBytes + report.expiredBytes;
|
|
449
|
-
parts.push(section(
|
|
481
|
+
parts.push(section(DISK_CLEANUP_SECTION_TITLE, renderConfirmForm({
|
|
450
482
|
action: '/disk/cleanup',
|
|
451
483
|
token: actionToken,
|
|
452
484
|
title: '清理缓存与过期导出产物',
|
|
453
|
-
|
|
485
|
+
// 本行经 renderConfirmForm 的 esc():不能写 markup(会被转义),也不能写 **(会显示字面星号)⇒ 去标记
|
|
486
|
+
consequence: '可重建区(tmp / 市场缓存 / 市场工作副本)按勾选整块清理;导出产物只在勾选时、且只按保留期回收。'
|
|
454
487
|
+ '导入前快照与同步数据永远不在候选集内。当前可回收约 ' + formatBytes(report.reclaimableBytes)
|
|
455
488
|
+ ',已超保留期约 ' + formatBytes(report.expiredBytes) + '。',
|
|
456
489
|
submitLabel: '按勾选执行清理',
|
|
@@ -524,8 +557,39 @@ function repairBody(plan, actionToken) {
|
|
|
524
557
|
*
|
|
525
558
|
* 能力边界(不得放宽):应用内/页面侧只做「字节相同 + seq 相同的重放重复行」这一零损失类;
|
|
526
559
|
* 合成 closer / seq 空洞 / 不可解析行 / 容器非法 / header 不可读 / 子代理缺父 一律只报告,
|
|
527
|
-
*
|
|
560
|
+
* 出路是本页的就地修复入口(可零损失修项会给出按钮)或**保留原样**。这条界线来自设计稿 §10.3/§10.4,
|
|
561
|
+
* 页面必须照实呈现。
|
|
562
|
+
*
|
|
563
|
+
* 说法纪律(C1b,与 src/cli/actions.ts 的 C1 修复同源):`sessions repair [--fix]` **不改写会话字节**
|
|
564
|
+
* (只做会话布局归位与重复 id 隔离),因此本段**绝不**能把它写成「重放去重」的等价命令 —— 那是把两件
|
|
565
|
+
* 不同的事说成一条通道,用户会以为「修不了重放重复行是因为命令没敲对」。反过来,
|
|
566
|
+
* 「修复一:会话布局归位」卡里的等价命令是**成立**的(本页与 CLI 走同一实现),**刻意保留**,
|
|
567
|
+
* 别在收尾时一刀切删掉。
|
|
568
|
+
*
|
|
569
|
+
* C1c:会话页顶部的 fixHint 此前写着「本页不提供」,与这一段、「修复一」卡(:591「本页按同一实现执行」)
|
|
570
|
+
* **自相矛盾** —— 同一事实两处说法必然漂移。这里把「本页提供哪些写入口」也收成单一事实源
|
|
571
|
+
* (PAGE_SESSION_WRITE_ENTRIES),fixHint 只渲染它;同时把本段里当强调用的字面 `**` 改成真 <strong>。
|
|
572
|
+
*/
|
|
573
|
+
/**
|
|
574
|
+
* 会话页写入口的**单一事实源**(C1c)。
|
|
575
|
+
*
|
|
576
|
+
* 只允许这一处说「本页提供/不提供哪些写动作」;任何页面文案要提这件事,都必须引用本常量。
|
|
577
|
+
*/
|
|
578
|
+
const PAGE_SESSION_WRITE_ENTRIES = '修复是写动作,须先把 DSH 停掉。本页<strong>提供</strong>两个写入口:'
|
|
579
|
+
+ '「修复一:会话布局归位」(布局归位与重复 id 隔离,与本机 CLI 的 <code>sessions repair --apply</code> 同一实现)与'
|
|
580
|
+
+ '「修复二:重放重复行」(字节级零损失就地修复,发现可修项时才给出按钮);'
|
|
581
|
+
+ '两者都要过与 CLI 同源的写入门(SAFE MODE / 残留锁 / DSH 已停止)。'
|
|
582
|
+
+ '其余类别(合成 closer / seq 空洞 / 子代理缺父 …)本页只报告,原因见「修复二」段的职责边界。';
|
|
583
|
+
/**
|
|
584
|
+
* `sessions repair [--fix]` 的**职责边界**(C1b 立的说法,C1c 抽成常量以便多处引用而只有一处措辞)。
|
|
585
|
+
*
|
|
586
|
+
* 渲染逐字不变(R1-02b 断言 /职责边界/、/sessions repair \[--fix\]/、/不改写会话字节/、/dcm web/、
|
|
587
|
+
* /修复选中的会话(零损失)/)。
|
|
528
588
|
*/
|
|
589
|
+
const SESSIONS_REPAIR_BOUNDARY = '<code>sessions repair [--fix]</code> 只做会话'
|
|
590
|
+
+ '<strong>布局归位</strong>与<strong>重复 id 隔离</strong>,<strong>不改写会话字节</strong>,'
|
|
591
|
+
+ '所以修不了重放重复行;离线<strong>字节级</strong>通道就是本救急台(<code>dcm web</code> 打开的这一页):'
|
|
592
|
+
+ '发现可零损失修项时,本段会列出清单并给出「修复选中的会话(零损失)」按钮,无需任何命令行动作。';
|
|
529
593
|
function inlineRepairBody(view, gate, actionToken) {
|
|
530
594
|
if (view === null) {
|
|
531
595
|
return '<p class="muted">未探测(本次体检没有跑到可修项扫描)。</p>';
|
|
@@ -533,13 +597,15 @@ function inlineRepairBody(view, gate, actionToken) {
|
|
|
533
597
|
const head = '<p class="muted">探测了 <strong>' + String(view.probed) + '</strong> 条存在深档问题的会话:'
|
|
534
598
|
+ '其中 <strong>' + String(view.fixable.length) + '</strong> 条存在<strong>零损失</strong>可修项'
|
|
535
599
|
+ '(重放重复行 —— 字节相同且 seq 相同的副本,丢弃即恢复)。</p>';
|
|
600
|
+
// 本段的出口只指向**本救急台自己**的就地修复入口:sessions repair 不改写会话字节,不能当等价通道。
|
|
601
|
+
// 文案取自单一事实源(C1c)——别在这里另写一套说法。
|
|
602
|
+
const boundary = '<p class="muted">职责边界:' + SESSIONS_REPAIR_BOUNDARY + '</p>';
|
|
536
603
|
if (view.fixable.length === 0) {
|
|
537
604
|
const why = view.blocked.length === 0 ? ''
|
|
538
605
|
: '<p class="muted">其余不可修的原因分布:'
|
|
539
606
|
+ view.blocked.map((b) => '<code>' + esc(b.reason) + '</code> × ' + String(b.count)).join('、')
|
|
540
|
-
+ '
|
|
541
|
-
return head + '<p class="muted">本次没有发现可零损失修复的会话。</p>' + why
|
|
542
|
-
+ '<p class="muted">等价命令:<code>dsh-config-manager sessions repair --apply</code></p>';
|
|
607
|
+
+ '。这些类别按设计<strong>只报告</strong>,不解压改写会话字节。</p>';
|
|
608
|
+
return head + '<p class="muted">本次没有发现可零损失修复的会话。</p>' + why + boundary;
|
|
543
609
|
}
|
|
544
610
|
const gateNote = gate !== null && !gate.ok
|
|
545
611
|
? '<p class="muted">注意:写入门当前是关闭状态(见上方「写入门状态」),提交会被如实拒绝。</p>'
|
|
@@ -552,9 +618,11 @@ function inlineRepairBody(view, gate, actionToken) {
|
|
|
552
618
|
action: '/sessions/inline-repair',
|
|
553
619
|
token: actionToken,
|
|
554
620
|
title: '就地修复重放重复行',
|
|
555
|
-
consequence
|
|
621
|
+
// 本段走 renderConfirmForm 的 esc():consequence 里写 markup 会被转义、写 ** 会渲染成字面星号
|
|
622
|
+
// (C1c 修的就是这个),所以这里不带任何强调标记,事实措辞不变。
|
|
623
|
+
consequence: '对选中的那一条会话:丢弃字节相同且 seq 相同的重放重复事件,写前重跑连续性/引用完整性校验'
|
|
556
624
|
+ '(不过就拒绝),时间戳备份就地保留,临时文件 + rename 原子换入,写后复验。'
|
|
557
|
-
+ '合成 closer / seq 空洞 /
|
|
625
|
+
+ '合成 closer / seq 空洞 / 子代理缺父不在本入口的修复范围内(只报告)。',
|
|
558
626
|
submitLabel: '修复选中的会话(零损失)',
|
|
559
627
|
danger: false,
|
|
560
628
|
checklist: view.fixable.map((f, i) => ({
|
|
@@ -565,6 +633,7 @@ function inlineRepairBody(view, gate, actionToken) {
|
|
|
565
633
|
})),
|
|
566
634
|
note: '前置条件:SAFE MODE 未激活、无残留锁、DSH 已停止、会话目录无 session.lock、日志不在最近 30s 内被写过。',
|
|
567
635
|
})
|
|
636
|
+
+ boundary
|
|
568
637
|
+ gateNote;
|
|
569
638
|
}
|
|
570
639
|
function policyLabel(policy) {
|
|
@@ -611,9 +680,9 @@ inline = null) {
|
|
|
611
680
|
row.sizeBytes === undefined ? '—' : formatBytes(row.sizeBytes),
|
|
612
681
|
row.issues.map((i) => i.code + (i.detail === undefined ? '' : '(' + i.detail + ')')).join(' '),
|
|
613
682
|
]);
|
|
683
|
+
// C1c:旧文案说「本页不提供」,与同页「修复一」卡(本页确实提供该写动作)自相矛盾 —— 改为单一事实源。
|
|
614
684
|
const fixHint = problems.length > 0
|
|
615
|
-
? '<p class="muted"
|
|
616
|
-
+ '先用 <code>dsh-config-manager sessions repair</code> 看计划,加 <code>--apply</code> 才落盘。</p>'
|
|
685
|
+
? '<p class="muted">' + PAGE_SESSION_WRITE_ENTRIES + '</p>'
|
|
617
686
|
: '';
|
|
618
687
|
parts.push(section('需要处理的会话(' + String(problems.length) + ')', renderTable(['严重级', '会话单元', '格式版本', '体积', '问题'], rows) + fixHint));
|
|
619
688
|
if (done === 'repaired')
|
|
@@ -670,13 +739,15 @@ export function renderConfirmForm(options) {
|
|
|
670
739
|
+ '</details>';
|
|
671
740
|
}
|
|
672
741
|
/** 写动作结果页(完成 / 失败共用;结果如实逐条列)。 */
|
|
673
|
-
export function renderResultPage(title,
|
|
742
|
+
export function renderResultPage(title,
|
|
743
|
+
/** 逐条结果:默认过 esc()(脱敏+转义);`{ html }` 仅用于已自行转义的能力 URL 行 */
|
|
744
|
+
lines, version, paths, kind,
|
|
674
745
|
/** 「返回上一页」在禁用 JS 时的落点(有 JS 时走 history.back(),回到列表页并由状态恢复脚本定位) */
|
|
675
746
|
backHref = '/') {
|
|
676
747
|
const chrome = { version, paths, active: 'home' };
|
|
677
748
|
const tone = kind === 'ok' ? 'ok' : kind === 'bad' ? 'bad' : 'warn';
|
|
678
749
|
const body = banner(tone, title, lines.length === 0 ? '(无更多信息)' : '')
|
|
679
|
-
+ section('逐条结果', '<ul class="resultList">' + lines.map((l) => '<li>' +
|
|
750
|
+
+ section('逐条结果', '<ul class="resultList">' + lines.map((l) => '<li>' + cellHtml(l) + '</li>').join('') + '</ul>')
|
|
680
751
|
+ '<p class="backRow"><a href="' + esc(backHref) + '" data-dcm-back>← 返回上一页并恢复原位置</a>'
|
|
681
752
|
+ ' · <a href="/">返回首页</a> · <a href="/sessions">会话体检</a> · <a href="/disk">磁盘占用</a></p>';
|
|
682
753
|
return renderLayout(chrome, body, paths.homeDir + ' · 写动作结果');
|
|
@@ -705,7 +776,8 @@ export function renderLockPage(lock, version, paths, actionToken, done) {
|
|
|
705
776
|
const stale = lock.state === 'STALE_LOCK_DETECTED';
|
|
706
777
|
parts.push(banner(stale ? 'warn' : 'info', '锁状态:' + lock.state, stale
|
|
707
778
|
? '持有进程已被确证不存在(或 ownership 是崩溃残留):可以显式回收。'
|
|
708
|
-
|
|
779
|
+
// banner() 的 text 走 esc() ⇒ 不放强调标记(写 markup 会被转义、写 ** 会显示星号,C1d)
|
|
780
|
+
: '非残留(活锁或无法判定):不会自动回收。'));
|
|
709
781
|
parts.push(section('明细', kv([
|
|
710
782
|
['锁目录', lock.locksDir],
|
|
711
783
|
['状态', lock.state],
|
|
@@ -747,7 +819,8 @@ export function renderUnlockPage(encrypted, version, paths, actionToken, done) {
|
|
|
747
819
|
action: '/unlock/run',
|
|
748
820
|
token: actionToken,
|
|
749
821
|
title: '解锁加密备份',
|
|
750
|
-
|
|
822
|
+
// 本行经 renderConfirmForm 的 esc():去标记(C1d,理由同上)
|
|
823
|
+
consequence: '会在内存中解出明文 ZIP 并列出条目清单;不写盘、不回传内容、不自动导入。密码区分大小写,忘记无法找回。',
|
|
751
824
|
submitLabel: '解锁并列出清单',
|
|
752
825
|
danger: false,
|
|
753
826
|
hidden: { id: verifyIdOf(b.name) },
|
|
@@ -824,7 +897,9 @@ export function renderExportPage(sections, unavailable, version, paths, actionTo
|
|
|
824
897
|
description: '该分区的文件类内容(凭据类文件永不进备份)',
|
|
825
898
|
checked: true,
|
|
826
899
|
}));
|
|
827
|
-
|
|
900
|
+
// C1d:banner 的 text 走 esc() —— 写 markup 会被转义成字面标签、写 ** 会渲染成字面星号,
|
|
901
|
+
// 所以这两种强调标记都不能用,只能去标记(与 :544 / :685 / :918 同一口径)。
|
|
902
|
+
const body = banner('info', '只导出离线能读到的分区', 'DSH 没在跑时,settings / providers / mcp 等结构化分区的值必须经 DSH 服务读取,因此不在归档里。'
|
|
828
903
|
+ '宁可如实少导,也不给一个「声称含设置、实际为空」的假备份。')
|
|
829
904
|
+ '<p class="muted">离线不可收集:' + unavailable.map((id) => '<code>' + esc(id) + '</code>').join('、') + '</p>'
|
|
830
905
|
+ renderConfirmForm({
|
|
@@ -849,7 +924,8 @@ export function renderReinstallPage(items, version, paths, actionToken) {
|
|
|
849
924
|
checked: it.defaultOn,
|
|
850
925
|
}));
|
|
851
926
|
const body = banner('bad', '这是本页最危险的动作', '它会卸载全局 @deepseek-ai/dsh 再重装(程序步),勾选数据类还会清空 ~/.dsh 的设置 / 插件 / 会话与凭据。'
|
|
852
|
-
|
|
927
|
+
// banner() 的 text 走 esc() ⇒ 去标记(C1d)
|
|
928
|
+
+ '执行需要输入只在终端里打印的 6 位确认码 —— 页面里看不到它。')
|
|
853
929
|
+ renderConfirmForm({
|
|
854
930
|
action: '/reinstall/plan',
|
|
855
931
|
token: actionToken,
|
|
@@ -903,7 +979,8 @@ export function renderProfilesPage(outcome, version, paths, actionToken, done, r
|
|
|
903
979
|
row.running
|
|
904
980
|
? (row.owned ? '运行中(本插件启动)' : '运行中(外部实例)') + (row.port === null ? '' : ' · :' + String(row.port))
|
|
905
981
|
: '未运行',
|
|
906
|
-
|
|
982
|
+
// 能力 URL:必须原样(含 token)—— 过 esc() 会被 redact 抹掉,链接点开必然 401(cli-F1)
|
|
983
|
+
{ html: row.url === null ? '—' : '<a href="' + escCapability(row.url) + '">打开实例</a>' },
|
|
907
984
|
]);
|
|
908
985
|
parts.push(section('本机档案(' + String(outcome.rows.length) + ')', renderTable(['档案', '形态', '构成', '依赖', '实例状态', '入口'], rows)));
|
|
909
986
|
if (outcome.rows.length === 0) {
|
package/lib/cli/web/routes.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 救急台路由(阶段 2):**只读页面 +
|
|
2
|
+
* 救急台路由(阶段 2):**只读页面 + 一组显式写动作**(写路由不在此处计数 —— 清单以
|
|
3
|
+
* `GET /healthz` 的 `writeRoutes` 为准:它由路由声明派生,与实现同源、不会漂移)。
|
|
3
4
|
*
|
|
4
5
|
* 每条路由都经 `src/routes/kit.ts` 的 `endpoint()` 声明(围栏 / 方法白名单 / 统一错误映射一份实现)。
|
|
5
6
|
*
|
|
@@ -11,12 +12,12 @@
|
|
|
11
12
|
* 副作用描述与确认文案都在服务端渲染,前端 JS 不参与决策(原本也没有前端 JS)。
|
|
12
13
|
*/
|
|
13
14
|
import { randomUUID } from 'node:crypto';
|
|
14
|
-
import { endpoint, RouteError, writeJson } from '../../routes/kit.js';
|
|
15
|
+
import { endpoint, routeSpecOf, RouteError, writeJson } from '../../routes/kit.js';
|
|
15
16
|
import { checkWriteGates, cleanupDisk, collectVerifyResults, exportOfflineBackup, repairSessionLogInline, launchProfile, planDshReinstall, planSnapshotRestore, readBackups, readDiskUsage, readProfiles, readRescueStatus, readSessionsHealth, recoverStaleEnvironmentLock, repairSessions, runDshReinstall, runSnapshotRestore, stopProfile, unlockEncryptedBackup, } from '../actions.js';
|
|
16
17
|
import { REINSTALL_ITEMS } from '../../core/reinstall.js';
|
|
17
18
|
import { createExec } from './exec.js';
|
|
18
19
|
import { writeHtml } from './http.js';
|
|
19
|
-
import { renderDiskPage, renderExportPage, renderHomePage, renderLockPage, renderMessagePage, renderProfilesPage, renderReinstallPage, renderRestorePage, renderResultPage, renderSessionsPage, renderUnlockPage, renderVerifyPage, verifyIdOf, } from './page.js';
|
|
20
|
+
import { escCapability, renderDiskPage, renderExportPage, renderHomePage, renderLockPage, renderMessagePage, renderProfilesPage, renderReinstallPage, renderRestorePage, renderResultPage, renderSessionsPage, renderUnlockPage, renderVerifyPage, verifyIdOf, } from './page.js';
|
|
20
21
|
/**
|
|
21
22
|
* 救急台的错误渲染器:把 RouteError 渲染成 **HTML 错误页**(而不是插件 API 形状的裸 JSON)。
|
|
22
23
|
* 页面是给人看的,用户在浏览器里收到 `{"error":"…"}` 只会以为坏了(验收 F3)。
|
|
@@ -98,13 +99,20 @@ export function buildConsoleRoutes(context) {
|
|
|
98
99
|
const token = () => issueActionToken(context);
|
|
99
100
|
// 本地别名:救急台的每条路由都带上 HTML 错误渲染器(kit 的统一出口仍在,只是形状换成页面)
|
|
100
101
|
const consoleEndpoint = (spec, handler) => endpoint({ ...spec, errorRenderer: renderConsoleError }, handler);
|
|
101
|
-
|
|
102
|
+
/**
|
|
103
|
+
* /healthz 的写路由自述:**由已声明的路由派生**(数组构造完再赋值),杜绝手写清单漂移(cli-F6:
|
|
104
|
+
* 此前只列 3 项能力名,与真实 11 条写路由不符)。
|
|
105
|
+
*/
|
|
106
|
+
let writeRoutes = [];
|
|
107
|
+
const routes = [
|
|
102
108
|
// ---------------------------------------------------------------- 只读
|
|
103
109
|
consoleEndpoint({ path: '/healthz', methods: ['GET'] }, (_req, res) => {
|
|
104
110
|
writeJson(res, 200, {
|
|
105
111
|
ok: true, service: 'dcm-rescue-console', readOnly: false, version, startedAt: context.startedAt,
|
|
106
112
|
// 写能力与只读页的区分:脚本/自检据此判断这台服务能做什么
|
|
107
113
|
writes: ['sessions-repair', 'disk-cleanup', 'recover-stale-lock'],
|
|
114
|
+
// 全部写路由(由声明派生,cli-F6)
|
|
115
|
+
writeRoutes,
|
|
108
116
|
});
|
|
109
117
|
}),
|
|
110
118
|
consoleEndpoint({ path: '/', methods: ['GET'] }, async (_req, res) => {
|
|
@@ -274,7 +282,8 @@ export function buildConsoleRoutes(context) {
|
|
|
274
282
|
const lines = result.ok
|
|
275
283
|
? [
|
|
276
284
|
result.message,
|
|
277
|
-
|
|
285
|
+
// 能力 URL:必须原样(含 token)—— 过 esc() 会被 redact 抹掉,链接点开必然 401(cli-F1)
|
|
286
|
+
...(result.url === undefined ? [] : [{ html: '认证 URL:<code>' + escCapability(result.url) + '</code>' }]),
|
|
278
287
|
...(result.port === undefined ? [] : ['端口:' + String(result.port)]),
|
|
279
288
|
...(result.pid === undefined ? [] : ['PID:' + String(result.pid)]),
|
|
280
289
|
...(result.logFile === undefined ? [] : ['日志:' + result.logFile]),
|
|
@@ -402,6 +411,16 @@ export function buildConsoleRoutes(context) {
|
|
|
402
411
|
res.end();
|
|
403
412
|
}),
|
|
404
413
|
];
|
|
414
|
+
// 自述与实现同源:从已声明的路由读回(routeSpecOf),非 GET 方法按声明原样列出
|
|
415
|
+
writeRoutes = routes
|
|
416
|
+
.flatMap((route) => {
|
|
417
|
+
const spec = routeSpecOf(route);
|
|
418
|
+
if (spec === undefined)
|
|
419
|
+
return [];
|
|
420
|
+
return spec.methods.filter((method) => method !== 'GET').map((method) => method + ' ' + spec.path);
|
|
421
|
+
})
|
|
422
|
+
.sort();
|
|
423
|
+
return routes;
|
|
405
424
|
}
|
|
406
425
|
export { renderMessagePage };
|
|
407
426
|
//# sourceMappingURL=routes.js.map
|
package/lib/cli/web/server.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { randomBytes, timingSafeEqual } from 'node:crypto';
|
|
14
14
|
import http from 'node:http';
|
|
15
|
-
import { isLoopbackRequest, registerRoutes, RouteError } from '../../routes/kit.js';
|
|
15
|
+
import { isLoopbackRequest, registerRoutes, routeSpecOf, RouteError } from '../../routes/kit.js';
|
|
16
16
|
import { openInBrowser } from './browser.js';
|
|
17
17
|
import { writeHtml } from './http.js';
|
|
18
18
|
import { renderMessagePage } from './page.js';
|
|
@@ -33,6 +33,19 @@ function readCookie(req, name) {
|
|
|
33
33
|
}
|
|
34
34
|
return undefined;
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* 把请求目标解析成救急台自己的 URL(**唯一**入口)。
|
|
38
|
+
*
|
|
39
|
+
* 为什么不能直接 new URL(req.url, 'http://127.0.0.1'):以 `//` 开头的目标是**协议相对 URL**,
|
|
40
|
+
* 会被解析成 authority=x / pathname='/' —— 于是 `GET //evil` 悄悄落到首页(cli-F7),
|
|
41
|
+
* absolute-form(`http://host/x`)同理。这里先折叠成 origin-form 再解析:任何非
|
|
42
|
+
* `/path?query` 形态都落到「未知路径」(404),而不是被当成首页。
|
|
43
|
+
*/
|
|
44
|
+
function consoleRequestUrl(raw) {
|
|
45
|
+
const target = raw ?? '/';
|
|
46
|
+
const pathOnly = target.startsWith('/') && !target.startsWith('//') ? target : '/' + target.replace(/^\/+/, '');
|
|
47
|
+
return new URL(pathOnly, 'http://127.0.0.1');
|
|
48
|
+
}
|
|
36
49
|
function constantTimeEquals(a, b) {
|
|
37
50
|
const left = Buffer.from(a, 'utf8');
|
|
38
51
|
const right = Buffer.from(b, 'utf8');
|
|
@@ -85,7 +98,7 @@ export async function startConsoleServer(options) {
|
|
|
85
98
|
}, options.idleTimeoutMs);
|
|
86
99
|
};
|
|
87
100
|
const handle = async (req, res) => {
|
|
88
|
-
const url =
|
|
101
|
+
const url = consoleRequestUrl(req.url);
|
|
89
102
|
touchIdle();
|
|
90
103
|
// 第一道:与宿主路由同一套 loopback + 同源围栏(连 bootstrap 也过)
|
|
91
104
|
if (!isLoopbackRequest(req)) {
|
|
@@ -119,6 +132,14 @@ export async function startConsoleServer(options) {
|
|
|
119
132
|
writeHtml(res, 404, renderMessagePage('页面不存在', '没有这个路径:' + url.pathname, '可用页面:/(首页)、/disk、/sessions、/healthz'));
|
|
120
133
|
return;
|
|
121
134
|
}
|
|
135
|
+
// 方法白名单(cli-F4):kit 的 405 出口写的是 **JSON**(给插件 API 客户端用),而救急台是
|
|
136
|
+
// 人看的页面。这里按**同一条声明**(routeSpecOf 读回的方法白名单)先判一次,让 405 也走 HTML;
|
|
137
|
+
// kit handler 内那道判定仍在(纵深防御,不依赖本处)。
|
|
138
|
+
const spec = routeSpecOf(route);
|
|
139
|
+
if (spec !== undefined && !spec.methods.includes(req.method)) {
|
|
140
|
+
writeHtml(res, 405, renderMessagePage('方法不被允许', '这个地址只接受 ' + spec.methods.join(' / ') + ' 请求(收到 ' + String(req.method ?? '') + ')。', '可用页面:/(首页)、/disk、/sessions、/lock、/profiles、/healthz'));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
122
143
|
// kit 的 handler 自带方法白名单 + 顶层错误映射。
|
|
123
144
|
// 但 kit 的错误出口写的是 **JSON**(那是给 API 客户端用的形状)——救急台是人看的页面,
|
|
124
145
|
// 因此这里把 RouteError 的语义包成 HTML 错误页(验收 F3:页面不该吐裸 JSON)。
|