@logictan/dsh-config-manager 0.1.60
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/LICENSE +21 -0
- package/README.md +105 -0
- package/cordis.patch.yml +21 -0
- package/lib/adapters/agent-instructions.d.ts +13 -0
- package/lib/adapters/agent-instructions.js +46 -0
- package/lib/adapters/agent-presets.d.ts +13 -0
- package/lib/adapters/agent-presets.js +14 -0
- package/lib/adapters/credentials.d.ts +37 -0
- package/lib/adapters/credentials.js +122 -0
- package/lib/adapters/file-collection.d.ts +15 -0
- package/lib/adapters/file-collection.js +127 -0
- package/lib/adapters/index.d.ts +57 -0
- package/lib/adapters/index.js +55 -0
- package/lib/adapters/link-report.d.ts +16 -0
- package/lib/adapters/link-report.js +47 -0
- package/lib/adapters/mcp.d.ts +28 -0
- package/lib/adapters/mcp.js +178 -0
- package/lib/adapters/plugin-files.d.ts +18 -0
- package/lib/adapters/plugin-files.js +142 -0
- package/lib/adapters/plugins.d.ts +41 -0
- package/lib/adapters/plugins.js +603 -0
- package/lib/adapters/pnpm-workspace.d.ts +26 -0
- package/lib/adapters/pnpm-workspace.js +147 -0
- package/lib/adapters/prompts.d.ts +30 -0
- package/lib/adapters/prompts.js +231 -0
- package/lib/adapters/providers.d.ts +34 -0
- package/lib/adapters/providers.js +155 -0
- package/lib/adapters/self.d.ts +17 -0
- package/lib/adapters/self.js +71 -0
- package/lib/adapters/sessions.d.ts +14 -0
- package/lib/adapters/sessions.js +15 -0
- package/lib/adapters/settings.d.ts +28 -0
- package/lib/adapters/settings.js +165 -0
- package/lib/adapters/skills.d.ts +13 -0
- package/lib/adapters/skills.js +14 -0
- package/lib/adapters/test-helpers.d.ts +125 -0
- package/lib/adapters/test-helpers.js +236 -0
- package/lib/adapters/ui.d.ts +27 -0
- package/lib/adapters/ui.js +89 -0
- package/lib/adapters/workspaces.d.ts +13 -0
- package/lib/adapters/workspaces.js +106 -0
- package/lib/client.d.ts +1026 -0
- package/lib/client.js +10047 -0
- package/lib/core/analyzer.d.ts +99 -0
- package/lib/core/analyzer.js +934 -0
- package/lib/core/backup.d.ts +138 -0
- package/lib/core/backup.js +513 -0
- package/lib/core/boot-rescue.d.ts +146 -0
- package/lib/core/boot-rescue.js +618 -0
- package/lib/core/cache-cleaner.d.ts +31 -0
- package/lib/core/cache-cleaner.js +95 -0
- package/lib/core/config-lifecycle.d.ts +180 -0
- package/lib/core/config-lifecycle.js +481 -0
- package/lib/core/config-snapshot.d.ts +135 -0
- package/lib/core/config-snapshot.js +424 -0
- package/lib/core/config-state.d.ts +70 -0
- package/lib/core/config-state.js +177 -0
- package/lib/core/consult-source.d.ts +58 -0
- package/lib/core/consult-source.js +260 -0
- package/lib/core/crash-report.d.ts +84 -0
- package/lib/core/crash-report.js +317 -0
- package/lib/core/exporter.d.ts +68 -0
- package/lib/core/exporter.js +375 -0
- package/lib/core/ghost-sweep.d.ts +19 -0
- package/lib/core/ghost-sweep.js +52 -0
- package/lib/core/importer.d.ts +60 -0
- package/lib/core/importer.js +29 -0
- package/lib/core/index.d.ts +14 -0
- package/lib/core/index.js +14 -0
- package/lib/core/journal.d.ts +197 -0
- package/lib/core/journal.js +418 -0
- package/lib/core/local-plugin-host.d.ts +35 -0
- package/lib/core/local-plugin-host.js +120 -0
- package/lib/core/local-plugin-pack.d.ts +135 -0
- package/lib/core/local-plugin-pack.js +278 -0
- package/lib/core/messages.d.ts +310 -0
- package/lib/core/messages.js +621 -0
- package/lib/core/migration-consult.d.ts +117 -0
- package/lib/core/migration-consult.js +363 -0
- package/lib/core/migration-history.d.ts +153 -0
- package/lib/core/migration-history.js +411 -0
- package/lib/core/model-tools.d.ts +50 -0
- package/lib/core/model-tools.js +148 -0
- package/lib/core/msg-types.d.ts +8 -0
- package/lib/core/msg-types.js +6 -0
- package/lib/core/phase3-child-crash.d.ts +1 -0
- package/lib/core/phase3-child-crash.js +87 -0
- package/lib/core/phase3-host.d.ts +138 -0
- package/lib/core/phase3-host.js +359 -0
- package/lib/core/phase3-prod-child.d.ts +1 -0
- package/lib/core/phase3-prod-child.js +35 -0
- package/lib/core/phase4-crash-child.d.ts +1 -0
- package/lib/core/phase4-crash-child.js +103 -0
- package/lib/core/plugin-cli.d.ts +150 -0
- package/lib/core/plugin-cli.js +497 -0
- package/lib/core/reconcile.d.ts +120 -0
- package/lib/core/reconcile.js +389 -0
- package/lib/core/recovery-orchestrator.d.ts +94 -0
- package/lib/core/recovery-orchestrator.js +327 -0
- package/lib/core/restore.d.ts +162 -0
- package/lib/core/restore.js +703 -0
- package/lib/core/rollback.d.ts +12 -0
- package/lib/core/rollback.js +145 -0
- package/lib/core/run-registry.d.ts +85 -0
- package/lib/core/run-registry.js +157 -0
- package/lib/core/startup-barrier.d.ts +53 -0
- package/lib/core/startup-barrier.js +77 -0
- package/lib/core/types.d.ts +515 -0
- package/lib/core/types.js +27 -0
- package/lib/core/undo.d.ts +73 -0
- package/lib/core/undo.js +87 -0
- package/lib/core/validator.d.ts +18 -0
- package/lib/core/validator.js +77 -0
- package/lib/core/verify-recovery.d.ts +21 -0
- package/lib/core/verify-recovery.js +256 -0
- package/lib/core/watcher.d.ts +101 -0
- package/lib/core/watcher.js +219 -0
- package/lib/index.d.ts +238 -0
- package/lib/index.js +2764 -0
- package/lib/migrations/index.d.ts +29 -0
- package/lib/migrations/index.js +56 -0
- package/lib/migrations/v1-to-v2.d.ts +9 -0
- package/lib/migrations/v1-to-v2.js +10 -0
- package/lib/profiles/index.d.ts +4 -0
- package/lib/profiles/index.js +5 -0
- package/lib/profiles/profile-manager.d.ts +106 -0
- package/lib/profiles/profile-manager.js +543 -0
- package/lib/schema/config.d.ts +28 -0
- package/lib/schema/config.js +165 -0
- package/lib/schema/index.d.ts +24 -0
- package/lib/schema/index.js +26 -0
- package/lib/schema/manifest.d.ts +28 -0
- package/lib/schema/manifest.js +109 -0
- package/lib/schema/tombstones.d.ts +46 -0
- package/lib/schema/tombstones.js +64 -0
- package/lib/schema/types.d.ts +232 -0
- package/lib/schema/types.js +8 -0
- package/lib/schema/versions.d.ts +27 -0
- package/lib/schema/versions.js +50 -0
- package/lib/security/encryption.d.ts +85 -0
- package/lib/security/encryption.js +279 -0
- package/lib/security/index.d.ts +16 -0
- package/lib/security/index.js +17 -0
- package/lib/security/integrity.d.ts +30 -0
- package/lib/security/integrity.js +78 -0
- package/lib/security/redaction.d.ts +26 -0
- package/lib/security/redaction.js +95 -0
- package/lib/security/secret-scanner.d.ts +86 -0
- package/lib/security/secret-scanner.js +404 -0
- package/lib/security/vault.d.ts +59 -0
- package/lib/security/vault.js +151 -0
- package/lib/security/zip-security.d.ts +27 -0
- package/lib/security/zip-security.js +154 -0
- package/lib/sync/autosync-config.d.ts +39 -0
- package/lib/sync/autosync-config.js +151 -0
- package/lib/sync/autosync-scheduler.d.ts +139 -0
- package/lib/sync/autosync-scheduler.js +564 -0
- package/lib/sync/fs.d.ts +18 -0
- package/lib/sync/fs.js +49 -0
- package/lib/sync/git/git-transport.d.ts +100 -0
- package/lib/sync/git/git-transport.js +437 -0
- package/lib/sync/github-auth.d.ts +131 -0
- package/lib/sync/github-auth.js +264 -0
- package/lib/sync/layout.d.ts +43 -0
- package/lib/sync/layout.js +203 -0
- package/lib/sync/snapshot-json.d.ts +9 -0
- package/lib/sync/snapshot-json.js +107 -0
- package/lib/sync/sync-config.d.ts +81 -0
- package/lib/sync/sync-config.js +281 -0
- package/lib/sync/sync-engine.d.ts +269 -0
- package/lib/sync/sync-engine.js +591 -0
- package/lib/sync/sync-history.d.ts +42 -0
- package/lib/sync/sync-history.js +78 -0
- package/lib/sync/sync-selection.d.ts +29 -0
- package/lib/sync/sync-selection.js +127 -0
- package/lib/sync/sync-session.d.ts +40 -0
- package/lib/sync/sync-session.js +54 -0
- package/lib/sync/sync-state.d.ts +37 -0
- package/lib/sync/sync-state.js +108 -0
- package/lib/sync/transport.d.ts +75 -0
- package/lib/sync/transport.js +55 -0
- package/lib/sync/ui-prefs.d.ts +34 -0
- package/lib/sync/ui-prefs.js +109 -0
- package/lib/sync/webdav/webdav-transport.d.ts +77 -0
- package/lib/sync/webdav/webdav-transport.js +451 -0
- package/lib/ui/errors.d.ts +19 -0
- package/lib/ui/errors.js +81 -0
- package/lib/ui/export-flow.d.ts +82 -0
- package/lib/ui/export-flow.js +98 -0
- package/lib/ui/i18n.d.ts +289 -0
- package/lib/ui/i18n.js +581 -0
- package/lib/ui/migration-consult-view.d.ts +91 -0
- package/lib/ui/migration-consult-view.js +115 -0
- package/lib/ui/progress.d.ts +38 -0
- package/lib/ui/progress.js +87 -0
- package/lib/ui/report.d.ts +23 -0
- package/lib/ui/report.js +153 -0
- package/lib/ui/test-helpers.d.ts +69 -0
- package/lib/ui/test-helpers.js +154 -0
- package/lib/ui/types.d.ts +257 -0
- package/lib/ui/types.js +21 -0
- package/lib/utils/atomic-write.d.ts +88 -0
- package/lib/utils/atomic-write.js +399 -0
- package/lib/utils/env-lock.d.ts +393 -0
- package/lib/utils/env-lock.js +930 -0
- package/lib/utils/hashing.d.ts +17 -0
- package/lib/utils/hashing.js +41 -0
- package/lib/utils/json.d.ts +24 -0
- package/lib/utils/json.js +76 -0
- package/lib/utils/logger.d.ts +39 -0
- package/lib/utils/logger.js +82 -0
- package/lib/utils/paths.d.ts +42 -0
- package/lib/utils/paths.js +189 -0
- package/lib/utils/proxy.d.ts +69 -0
- package/lib/utils/proxy.js +455 -0
- package/lib/utils/recursive-walk.d.ts +24 -0
- package/lib/utils/recursive-walk.js +134 -0
- package/lib/utils/zip.d.ts +54 -0
- package/lib/utils/zip.js +285 -0
- package/package.json +188 -0
- package/src/adapters/agent-instructions.ts +48 -0
- package/src/adapters/agent-presets.ts +14 -0
- package/src/adapters/credentials.test.ts +90 -0
- package/src/adapters/credentials.ts +143 -0
- package/src/adapters/file-collection.ts +137 -0
- package/src/adapters/files.test.ts +353 -0
- package/src/adapters/index.ts +94 -0
- package/src/adapters/link-report.test.ts +65 -0
- package/src/adapters/link-report.ts +61 -0
- package/src/adapters/mcp.test.ts +96 -0
- package/src/adapters/mcp.ts +185 -0
- package/src/adapters/plugin-files.ts +146 -0
- package/src/adapters/plugins.test.ts +326 -0
- package/src/adapters/plugins.ts +615 -0
- package/src/adapters/pnpm-workspace.test.ts +87 -0
- package/src/adapters/pnpm-workspace.ts +150 -0
- package/src/adapters/prompts.test.ts +110 -0
- package/src/adapters/prompts.ts +230 -0
- package/src/adapters/providers.test.ts +126 -0
- package/src/adapters/providers.ts +173 -0
- package/src/adapters/roundtrip.test.ts +190 -0
- package/src/adapters/self.test.ts +92 -0
- package/src/adapters/self.ts +75 -0
- package/src/adapters/sessions.ts +15 -0
- package/src/adapters/settings.test.ts +100 -0
- package/src/adapters/settings.ts +187 -0
- package/src/adapters/skills.ts +14 -0
- package/src/adapters/test-helpers.ts +248 -0
- package/src/adapters/ui.test.ts +57 -0
- package/src/adapters/ui.ts +108 -0
- package/src/adapters/workspaces.test.ts +106 -0
- package/src/adapters/workspaces.ts +109 -0
- package/src/client/ConfigManagerSection.tsx +90 -0
- package/src/client/api.ts +66 -0
- package/src/client/client-types.ts +18 -0
- package/src/client/common/ErrorBanner.tsx +73 -0
- package/src/client/common/Icon.tsx +129 -0
- package/src/client/common/Modal.tsx +173 -0
- package/src/client/common/ToastViewport.tsx +73 -0
- package/src/client/common/toast-store.test.ts +192 -0
- package/src/client/common/toast-store.ts +181 -0
- package/src/client/common/toast-types.ts +7 -0
- package/src/client/common/ui.tsx +342 -0
- package/src/client/config-manager.module.css +2971 -0
- package/src/client/css-modules.d.ts +8 -0
- package/src/client/index.ts +65 -0
- package/src/client/locales.ts +56 -0
- package/src/client/lucide-icons.d.ts +38 -0
- package/src/client/run-store.test.ts +223 -0
- package/src/client/run-store.ts +372 -0
- package/src/client/sync/SyncConfirmView.tsx +379 -0
- package/src/client/sync/SyncHistoryView.test.ts +40 -0
- package/src/client/sync/SyncHistoryView.tsx +220 -0
- package/src/client/sync/SyncSettingsView.tsx +1535 -0
- package/src/client/sync/history-model.test.ts +194 -0
- package/src/client/sync/history-model.ts +195 -0
- package/src/client/sync/sync-api.test.ts +585 -0
- package/src/client/sync/sync-api.ts +543 -0
- package/src/client/sync/sync-locales.ts +416 -0
- package/src/client/sync/sync-push-preview.test.ts +52 -0
- package/src/client/sync/sync-view-v2.test.ts +213 -0
- package/src/client/sync/sync-view.test.ts +487 -0
- package/src/client/sync/sync-view.ts +759 -0
- package/src/core/analyzer.ts +1068 -0
- package/src/core/backup.ts +605 -0
- package/src/core/boot-rescue.test.ts +847 -0
- package/src/core/boot-rescue.ts +737 -0
- package/src/core/cache-cleaner.test.ts +169 -0
- package/src/core/cache-cleaner.ts +121 -0
- package/src/core/config-lifecycle.test.ts +727 -0
- package/src/core/config-lifecycle.ts +573 -0
- package/src/core/config-snapshot.test.ts +369 -0
- package/src/core/config-snapshot.ts +522 -0
- package/src/core/config-state.test.ts +381 -0
- package/src/core/config-state.ts +207 -0
- package/src/core/consult-source.test.ts +199 -0
- package/src/core/consult-source.ts +293 -0
- package/src/core/crash-report.test.ts +380 -0
- package/src/core/crash-report.ts +369 -0
- package/src/core/exporter.ts +417 -0
- package/src/core/ghost-sweep.test.ts +94 -0
- package/src/core/ghost-sweep.ts +67 -0
- package/src/core/importer.ts +83 -0
- package/src/core/index.ts +56 -0
- package/src/core/journal.test.ts +257 -0
- package/src/core/journal.ts +518 -0
- package/src/core/local-plugin-host.ts +152 -0
- package/src/core/local-plugin-pack.test.ts +359 -0
- package/src/core/local-plugin-pack.ts +363 -0
- package/src/core/messages.test.ts +54 -0
- package/src/core/messages.ts +664 -0
- package/src/core/migration-consult.test.ts +315 -0
- package/src/core/migration-consult.ts +494 -0
- package/src/core/migration-history.test.ts +319 -0
- package/src/core/migration-history.ts +484 -0
- package/src/core/model-tools.test.ts +190 -0
- package/src/core/model-tools.ts +208 -0
- package/src/core/msg-types.ts +10 -0
- package/src/core/phase3-child-crash.ts +95 -0
- package/src/core/phase3-host.ts +411 -0
- package/src/core/phase3-p1.test.ts +212 -0
- package/src/core/phase3-p2b-fingerprint.test.ts +189 -0
- package/src/core/phase3-prod-child.ts +36 -0
- package/src/core/phase3-production-integration.test.ts +286 -0
- package/src/core/phase4-crash-child.ts +101 -0
- package/src/core/phase4-crash-injection.test.ts +166 -0
- package/src/core/plugin-cli.fs.test.ts +184 -0
- package/src/core/plugin-cli.test.ts +137 -0
- package/src/core/plugin-cli.ts +563 -0
- package/src/core/reconcile.test.ts +392 -0
- package/src/core/reconcile.ts +498 -0
- package/src/core/recovery-orchestrator.test.ts +145 -0
- package/src/core/recovery-orchestrator.ts +366 -0
- package/src/core/restore-manage.test.ts +94 -0
- package/src/core/restore.ts +849 -0
- package/src/core/rollback.ts +151 -0
- package/src/core/run-progress.test.ts +237 -0
- package/src/core/run-registry.test.ts +232 -0
- package/src/core/run-registry.ts +209 -0
- package/src/core/smoke.test.ts +842 -0
- package/src/core/startup-barrier.ts +99 -0
- package/src/core/types.ts +542 -0
- package/src/core/undo.ts +116 -0
- package/src/core/validator.ts +84 -0
- package/src/core/verify-recovery.ts +265 -0
- package/src/core/watcher.test.ts +326 -0
- package/src/core/watcher.ts +263 -0
- package/src/index.facade.test.ts +265 -0
- package/src/index.sync.test.ts +217 -0
- package/src/index.ts +2975 -0
- package/src/migrations/index.ts +71 -0
- package/src/migrations/v1-to-v2.ts +17 -0
- package/src/profiles/index.ts +8 -0
- package/src/profiles/profile-manager.test.ts +282 -0
- package/src/profiles/profile-manager.ts +630 -0
- package/src/schema/config.ts +165 -0
- package/src/schema/index.ts +71 -0
- package/src/schema/manifest-schema.test.ts +519 -0
- package/src/schema/manifest.ts +124 -0
- package/src/schema/tombstones.test.ts +131 -0
- package/src/schema/tombstones.ts +89 -0
- package/src/schema/types.ts +245 -0
- package/src/schema/versions.ts +55 -0
- package/src/security/encryption.ts +335 -0
- package/src/security/index.ts +16 -0
- package/src/security/integrity.ts +102 -0
- package/src/security/redaction.ts +101 -0
- package/src/security/secret-scanner.ts +445 -0
- package/src/security/security.test.ts +1215 -0
- package/src/security/vault.test.ts +164 -0
- package/src/security/vault.ts +198 -0
- package/src/security/zip-security.ts +180 -0
- package/src/sync/autosync-config.test.ts +147 -0
- package/src/sync/autosync-config.ts +179 -0
- package/src/sync/autosync-scheduler.test.ts +490 -0
- package/src/sync/autosync-scheduler.ts +646 -0
- package/src/sync/fs.ts +48 -0
- package/src/sync/git/git-transport.test.ts +673 -0
- package/src/sync/git/git-transport.ts +491 -0
- package/src/sync/github-auth.test.ts +280 -0
- package/src/sync/github-auth.ts +356 -0
- package/src/sync/layout.test.ts +270 -0
- package/src/sync/layout.ts +222 -0
- package/src/sync/snapshot-json.test.ts +119 -0
- package/src/sync/snapshot-json.ts +128 -0
- package/src/sync/sync-config.test.ts +310 -0
- package/src/sync/sync-config.ts +299 -0
- package/src/sync/sync-engine.test.ts +1074 -0
- package/src/sync/sync-engine.ts +754 -0
- package/src/sync/sync-history.test.ts +116 -0
- package/src/sync/sync-history.ts +120 -0
- package/src/sync/sync-selection.test.ts +186 -0
- package/src/sync/sync-selection.ts +143 -0
- package/src/sync/sync-session.test.ts +143 -0
- package/src/sync/sync-session.ts +77 -0
- package/src/sync/sync-state.test.ts +164 -0
- package/src/sync/sync-state.ts +131 -0
- package/src/sync/transport.test.ts +111 -0
- package/src/sync/transport.ts +118 -0
- package/src/sync/ui-prefs.test.ts +152 -0
- package/src/sync/ui-prefs.ts +135 -0
- package/src/sync/webdav/webdav-transport.test.ts +871 -0
- package/src/sync/webdav/webdav-transport.ts +535 -0
- package/src/ui/errors.test.ts +47 -0
- package/src/ui/errors.ts +100 -0
- package/src/ui/export-flow.test.ts +87 -0
- package/src/ui/export-flow.ts +156 -0
- package/src/ui/i18n.ts +590 -0
- package/src/ui/migration-consult-view.test.ts +151 -0
- package/src/ui/migration-consult-view.ts +178 -0
- package/src/ui/progress.test.ts +47 -0
- package/src/ui/progress.ts +102 -0
- package/src/ui/report.test.ts +101 -0
- package/src/ui/report.ts +146 -0
- package/src/ui/test-helpers.ts +184 -0
- package/src/ui/types.ts +325 -0
- package/src/utils/atomic-write.test.ts +312 -0
- package/src/utils/atomic-write.ts +422 -0
- package/src/utils/env-lock.test.ts +999 -0
- package/src/utils/env-lock.ts +1086 -0
- package/src/utils/hashing.ts +53 -0
- package/src/utils/json.ts +77 -0
- package/src/utils/logger.ts +114 -0
- package/src/utils/paths.ts +176 -0
- package/src/utils/proxy.test.ts +465 -0
- package/src/utils/proxy.ts +493 -0
- package/src/utils/recursive-walk.test.ts +148 -0
- package/src/utils/recursive-walk.ts +145 -0
- package/src/utils/zip.ts +332 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { SettingsAdapter } from './settings.js';
|
|
2
|
+
import { UiAdapter } from './ui.js';
|
|
3
|
+
import { ProvidersAdapter } from './providers.js';
|
|
4
|
+
import { PluginsAdapter } from './plugins.js';
|
|
5
|
+
import { McpAdapter } from './mcp.js';
|
|
6
|
+
import { PromptsAdapter } from './prompts.js';
|
|
7
|
+
import { SkillsAdapter } from './skills.js';
|
|
8
|
+
import { AgentPresetsAdapter } from './agent-presets.js';
|
|
9
|
+
import { AgentInstructionsAdapter } from './agent-instructions.js';
|
|
10
|
+
import { WorkspacesAdapter } from './workspaces.js';
|
|
11
|
+
import { CredentialsAdapter } from './credentials.js';
|
|
12
|
+
import { PluginFilesAdapter } from './plugin-files.js';
|
|
13
|
+
import { SessionsAdapter } from './sessions.js';
|
|
14
|
+
import { SelfAdapter } from './self.js';
|
|
15
|
+
/** 组装默认 adapter 列表(pluginFiles/sessions 恒挂载但 defaultIncluded=false,用户勾选才导出) */
|
|
16
|
+
export function createAdapters(options = {}) {
|
|
17
|
+
const namespaces = options.namespaces ?? [];
|
|
18
|
+
const adapters = [
|
|
19
|
+
new SettingsAdapter(namespaces),
|
|
20
|
+
new UiAdapter(namespaces),
|
|
21
|
+
new ProvidersAdapter(),
|
|
22
|
+
new PluginsAdapter(options.selfPluginName, options.localPluginPack),
|
|
23
|
+
new McpAdapter(),
|
|
24
|
+
new PromptsAdapter(),
|
|
25
|
+
new SkillsAdapter(),
|
|
26
|
+
new AgentPresetsAdapter(),
|
|
27
|
+
new AgentInstructionsAdapter(),
|
|
28
|
+
new WorkspacesAdapter(),
|
|
29
|
+
new CredentialsAdapter({ namespaces, refs: options.credentialsRefs }),
|
|
30
|
+
new PluginFilesAdapter(options.pluginFiles, options.pluginFilesDir),
|
|
31
|
+
];
|
|
32
|
+
// self 分区:插件自身配置(同步/市场/偏好),portable 默认包含;'' = 不挂载
|
|
33
|
+
if (options.selfDir !== '') {
|
|
34
|
+
adapters.push(new SelfAdapter(options.selfDir ?? 'dsh-config-manager'));
|
|
35
|
+
}
|
|
36
|
+
if (options.includeSessions)
|
|
37
|
+
adapters.push(new SessionsAdapter());
|
|
38
|
+
return adapters;
|
|
39
|
+
}
|
|
40
|
+
export { SettingsAdapter } from './settings.js';
|
|
41
|
+
export { UiAdapter, isUiNamespace, KNOWN_UI_NAMESPACE_PREFIXES, UI_MIGRATION_NOTES } from './ui.js';
|
|
42
|
+
export { ProvidersAdapter, DEFAULT_PROVIDER_NAMESPACES } from './providers.js';
|
|
43
|
+
export { PluginsAdapter, USER_PATCH_FILE } from './plugins.js';
|
|
44
|
+
export { McpAdapter, extractMcpServers, buildMcpPatchLine } from './mcp.js';
|
|
45
|
+
export { PromptsAdapter, extractPrompts, mergePromptIntoLine, buildPromptLine } from './prompts.js';
|
|
46
|
+
export { SkillsAdapter } from './skills.js';
|
|
47
|
+
export { AgentPresetsAdapter } from './agent-presets.js';
|
|
48
|
+
export { AgentInstructionsAdapter } from './agent-instructions.js';
|
|
49
|
+
export { WorkspacesAdapter } from './workspaces.js';
|
|
50
|
+
export { CredentialsAdapter, defaultCredentialRefs } from './credentials.js';
|
|
51
|
+
export { PluginFilesAdapter, DEFAULT_PLUGIN_FILE_WHITELIST } from './plugin-files.js';
|
|
52
|
+
export { SessionsAdapter } from './sessions.js';
|
|
53
|
+
export { SelfAdapter, SELF_CONFIG_FILES } from './self.js';
|
|
54
|
+
export { FileCollectionAdapter } from './file-collection.js';
|
|
55
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 文件类分区的「链接目录」报告(issue #37)。
|
|
3
|
+
*
|
|
4
|
+
* 背景:备份静默跳过 junction/符号链接,用户拿到的仍是「成功」,却少了整块内容。
|
|
5
|
+
* 修复分两步:① `utils/recursive-walk.ts` 跟随链接收集内容;② 本模块把「跟随了什么、
|
|
6
|
+
* 跳过了什么、为什么跳过」变成备份报告里可见的告警 —— 缺了 ②,用户依然无从察觉缺失。
|
|
7
|
+
*
|
|
8
|
+
* 纯函数(除 listFilesDetailed 的 IO 委托外),两个 adapter 共用,避免文案再次漂移。
|
|
9
|
+
*/
|
|
10
|
+
import type { FileSystemFacade } from '../core/types.ts';
|
|
11
|
+
import type { MsgFunc } from '../core/messages.ts';
|
|
12
|
+
import type { RecursiveListing } from '../utils/recursive-walk.ts';
|
|
13
|
+
/** 取遍历结果:宿主未实现 listRecursiveDetailed(旧版/测试 mock)时回退,行为与旧版一致。 */
|
|
14
|
+
export declare function listFilesDetailed(fs: FileSystemFacade, dir: string): Promise<RecursiveListing>;
|
|
15
|
+
/** 把遍历结果转成告警行(无链接时返回空数组 —— 不制造噪音)。 */
|
|
16
|
+
export declare function linkWarnings(msg: MsgFunc, type: string, listing: RecursiveListing): string[];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** 跳过原因 → 消息 key(与 SkippedLink.reason 一一对应,穷尽映射) */
|
|
2
|
+
const REASON_KEY = {
|
|
3
|
+
loop: 'adapter.linkReason.loop',
|
|
4
|
+
'outside-home': 'adapter.linkReason.outsideHome',
|
|
5
|
+
broken: 'adapter.linkReason.broken',
|
|
6
|
+
unreadable: 'adapter.linkReason.unreadable',
|
|
7
|
+
'too-deep': 'adapter.linkReason.tooDeep',
|
|
8
|
+
};
|
|
9
|
+
/** 单条原因下最多列出的路径数(其余折叠为计数,避免把报告撑爆) */
|
|
10
|
+
const MAX_PATHS_PER_REASON = 5;
|
|
11
|
+
/** 取遍历结果:宿主未实现 listRecursiveDetailed(旧版/测试 mock)时回退,行为与旧版一致。 */
|
|
12
|
+
export async function listFilesDetailed(fs, dir) {
|
|
13
|
+
if (fs.listRecursiveDetailed !== undefined)
|
|
14
|
+
return fs.listRecursiveDetailed(dir);
|
|
15
|
+
return { paths: await fs.listRecursive(dir), skippedLinks: [], followedLinks: 0, unreadableDirs: [] };
|
|
16
|
+
}
|
|
17
|
+
/** 把遍历结果转成告警行(无链接时返回空数组 —— 不制造噪音)。 */
|
|
18
|
+
export function linkWarnings(msg, type, listing) {
|
|
19
|
+
const out = [];
|
|
20
|
+
if (listing.followedLinks > 0) {
|
|
21
|
+
out.push(msg('adapter.linksFollowed', { type, count: String(listing.followedLinks) }));
|
|
22
|
+
}
|
|
23
|
+
if (listing.skippedLinks.length > 0) {
|
|
24
|
+
const byReason = new Map();
|
|
25
|
+
for (const s of listing.skippedLinks) {
|
|
26
|
+
const arr = byReason.get(s.reason) ?? [];
|
|
27
|
+
arr.push(s.path);
|
|
28
|
+
byReason.set(s.reason, arr);
|
|
29
|
+
}
|
|
30
|
+
const detail = [...byReason.entries()].map(([reason, paths]) => {
|
|
31
|
+
const shown = paths.slice(0, MAX_PATHS_PER_REASON).join(', ');
|
|
32
|
+
const more = paths.length > MAX_PATHS_PER_REASON ? ` (+ ${paths.length - MAX_PATHS_PER_REASON})` : '';
|
|
33
|
+
return `${msg(REASON_KEY[reason])} ${paths.length} 个: ${shown}${more}`;
|
|
34
|
+
}).join(';');
|
|
35
|
+
out.push(msg('adapter.linksSkipped', { type, count: String(listing.skippedLinks.length), detail }));
|
|
36
|
+
}
|
|
37
|
+
if (listing.unreadableDirs.length > 0) {
|
|
38
|
+
const shown = listing.unreadableDirs.slice(0, MAX_PATHS_PER_REASON).join(', ');
|
|
39
|
+
const more = listing.unreadableDirs.length > MAX_PATHS_PER_REASON
|
|
40
|
+
? ` (+ ${listing.unreadableDirs.length - MAX_PATHS_PER_REASON})` : '';
|
|
41
|
+
out.push(msg('adapter.dirsUnreadable', {
|
|
42
|
+
type, count: String(listing.unreadableDirs.length), detail: `${shown}${more}`,
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=link-report.js.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { MsgFunc } from '../core/messages.ts';
|
|
2
|
+
import type { McpServerEntry } from '../schema/types.ts';
|
|
3
|
+
import type { ApplyResult, ConfigAdapter, ExportOptions, ExportSection, HostContext, ImportContext, PlanItem, ValidationResult } from '../core/types.ts';
|
|
4
|
+
/** 导出记录:McpServerEntry 之外附加来源 patch 行 id(导入写回定位用) */
|
|
5
|
+
export interface McpExportEntry extends McpServerEntry {
|
|
6
|
+
sourceLineId: string;
|
|
7
|
+
}
|
|
8
|
+
export interface McpExportSection {
|
|
9
|
+
version: 1;
|
|
10
|
+
servers: McpExportEntry[];
|
|
11
|
+
}
|
|
12
|
+
/** 从 patch 行数组中提取 MCP server 条目(以 config.serverName 存在为判定) */
|
|
13
|
+
export declare function extractMcpServers(lines: {
|
|
14
|
+
lineId: string;
|
|
15
|
+
raw: unknown;
|
|
16
|
+
}[]): McpExportEntry[];
|
|
17
|
+
/** 由导出条目构造写回 patch 行 raw(单行形态,与 dsh-mcp-client 组合 config 语义一致) */
|
|
18
|
+
export declare function buildMcpPatchLine(lineId: string, server: McpServerEntry): Record<string, unknown>;
|
|
19
|
+
export declare class McpAdapter implements ConfigAdapter<McpExportSection> {
|
|
20
|
+
readonly id: 'mcp';
|
|
21
|
+
readonly displayName = "MCP Servers";
|
|
22
|
+
readonly defaultIncluded = true;
|
|
23
|
+
readonly portability: 'platformSpecific';
|
|
24
|
+
export(ctx: HostContext, _options: ExportOptions): Promise<ExportSection<McpExportSection>>;
|
|
25
|
+
analyzeImport(data: McpExportSection, ctx: ImportContext): Promise<PlanItem[]>;
|
|
26
|
+
applyItem(item: PlanItem, ctx: ImportContext): Promise<ApplyResult>;
|
|
27
|
+
validate(data: McpExportSection, msg?: MsgFunc): Promise<ValidationResult>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcp 分区 adapter(设计 §3.3/§1.2/§15):
|
|
3
|
+
* 数据源 = 组合 patch 中 dsh-mcp-client 行的 config(研究报告 §2.2:MCP 无 settings 面/无管理 API)。
|
|
4
|
+
* 导入 = 写 profile cordis.patch.yml 插行(needsRestart 生效);依赖检测(npx 等)由 analyzer 的
|
|
5
|
+
* dependencyChecker 执行(§15:缺失不阻塞,标记 Requires Attention)。
|
|
6
|
+
*
|
|
7
|
+
* patch 行 raw 支持两种形态:单行 { id, name, config } 与块 { insert: [{ id, name, config }] }。
|
|
8
|
+
*/
|
|
9
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
10
|
+
import { msgOf, zhMsg } from '../core/messages.js';
|
|
11
|
+
import { USER_PATCH_FILE } from './plugins.js';
|
|
12
|
+
/** 从 patch 行数组中提取 MCP server 条目(以 config.serverName 存在为判定) */
|
|
13
|
+
export function extractMcpServers(lines) {
|
|
14
|
+
const servers = [];
|
|
15
|
+
for (const line of lines) {
|
|
16
|
+
for (const entry of entriesOf(line.raw)) {
|
|
17
|
+
const config = entry.config;
|
|
18
|
+
if (config === null || typeof config !== 'object')
|
|
19
|
+
continue;
|
|
20
|
+
const c = config;
|
|
21
|
+
const serverName = c['serverName'];
|
|
22
|
+
if (typeof serverName !== 'string' || serverName === '')
|
|
23
|
+
continue;
|
|
24
|
+
const type = typeof c['url'] === 'string' && c['url'] !== '' ? 'streamable-http' : 'stdio';
|
|
25
|
+
servers.push({
|
|
26
|
+
serverName,
|
|
27
|
+
type,
|
|
28
|
+
command: typeof c['command'] === 'string' ? c['command'] : undefined,
|
|
29
|
+
args: Array.isArray(c['args']) ? c['args'] : undefined,
|
|
30
|
+
env: c['env'] !== null && typeof c['env'] === 'object' ? c['env'] : undefined,
|
|
31
|
+
cwd: typeof c['cwd'] === 'string' ? c['cwd'] : undefined,
|
|
32
|
+
url: typeof c['url'] === 'string' ? c['url'] : undefined,
|
|
33
|
+
headers: c['headers'] !== null && typeof c['headers'] === 'object' ? c['headers'] : undefined,
|
|
34
|
+
sourceLineId: line.lineId,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return servers;
|
|
39
|
+
}
|
|
40
|
+
/** patch 行 → 可枚举的 entry 列表(兼容单行与 insert 块) */
|
|
41
|
+
function entriesOf(raw) {
|
|
42
|
+
if (raw === null || typeof raw !== 'object')
|
|
43
|
+
return [];
|
|
44
|
+
const obj = raw;
|
|
45
|
+
if (Array.isArray(obj['insert'])) {
|
|
46
|
+
return obj['insert']
|
|
47
|
+
.filter((e) => e !== null && typeof e === 'object')
|
|
48
|
+
.map((e) => e);
|
|
49
|
+
}
|
|
50
|
+
if (obj['id'] !== undefined || obj['name'] !== undefined) {
|
|
51
|
+
return [obj];
|
|
52
|
+
}
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
/** 由导出条目构造写回 patch 行 raw(单行形态,与 dsh-mcp-client 组合 config 语义一致) */
|
|
56
|
+
export function buildMcpPatchLine(lineId, server) {
|
|
57
|
+
const config = { serverName: server.serverName };
|
|
58
|
+
if (server.type === 'streamable-http') {
|
|
59
|
+
config['url'] = server.url;
|
|
60
|
+
if (server.headers !== undefined)
|
|
61
|
+
config['headers'] = server.headers;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
config['command'] = server.command;
|
|
65
|
+
if (server.args !== undefined)
|
|
66
|
+
config['args'] = server.args;
|
|
67
|
+
if (server.env !== undefined)
|
|
68
|
+
config['env'] = server.env;
|
|
69
|
+
if (server.cwd !== undefined)
|
|
70
|
+
config['cwd'] = server.cwd;
|
|
71
|
+
}
|
|
72
|
+
return { id: lineId, name: 'dsh-mcp-client', config };
|
|
73
|
+
}
|
|
74
|
+
function newLineId(serverName) {
|
|
75
|
+
const slug = serverName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
76
|
+
return `mcp-${slug || 'server'}`;
|
|
77
|
+
}
|
|
78
|
+
export class McpAdapter {
|
|
79
|
+
id = 'mcp';
|
|
80
|
+
displayName = 'MCP Servers';
|
|
81
|
+
defaultIncluded = true;
|
|
82
|
+
portability = 'platformSpecific';
|
|
83
|
+
async export(ctx, _options) {
|
|
84
|
+
const warnings = [];
|
|
85
|
+
let lines = [];
|
|
86
|
+
try {
|
|
87
|
+
lines = await ctx.patchFile.readPatchLines(USER_PATCH_FILE);
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
warnings.push(msgOf(ctx)('adapter.patchReadFailedMCP', { reason: err instanceof Error ? err.message : String(err) }));
|
|
91
|
+
}
|
|
92
|
+
const servers = extractMcpServers(lines);
|
|
93
|
+
return {
|
|
94
|
+
sectionId: 'mcp',
|
|
95
|
+
data: { version: 1, servers },
|
|
96
|
+
counts: { servers: servers.length },
|
|
97
|
+
warnings,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
async analyzeImport(data, ctx) {
|
|
101
|
+
const msg = ctx.msg;
|
|
102
|
+
const items = [];
|
|
103
|
+
const targetLines = await ctx.target.patchFile.readPatchLines(USER_PATCH_FILE);
|
|
104
|
+
const targetServers = extractMcpServers(targetLines);
|
|
105
|
+
for (const server of data.servers) {
|
|
106
|
+
const id = `mcp:${server.serverName}`;
|
|
107
|
+
const existing = targetServers.find((s) => s.serverName === server.serverName);
|
|
108
|
+
const comparable = { ...server };
|
|
109
|
+
delete comparable.sourceLineId;
|
|
110
|
+
if (!existing) {
|
|
111
|
+
const lineId = server.sourceLineId && targetLines.some((l) => l.lineId === server.sourceLineId)
|
|
112
|
+
? `${server.sourceLineId}-imported`
|
|
113
|
+
: (server.sourceLineId ?? newLineId(server.serverName));
|
|
114
|
+
items.push({
|
|
115
|
+
id, kind: 'Create', adapter: 'mcp',
|
|
116
|
+
description: msg('adapter.mcpCreate', { serverName: server.serverName }),
|
|
117
|
+
detail: `${server.type === 'stdio' ? `${server.command} ${(server.args ?? []).join(' ')}` : server.url}`,
|
|
118
|
+
severity: 'info',
|
|
119
|
+
target: { adapter: 'mcp', ref: lineId },
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
const existingComparable = { ...existing };
|
|
124
|
+
delete existingComparable.sourceLineId;
|
|
125
|
+
if (isDeepStrictEqual(existingComparable, comparable)) {
|
|
126
|
+
items.push({ id, kind: 'Skip', adapter: 'mcp', description: msg('adapter.mcpSame', { serverName: server.serverName }), severity: 'info' });
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
items.push({
|
|
130
|
+
id, kind: 'Conflict', adapter: 'mcp',
|
|
131
|
+
description: msg('adapter.mcpDiff', { serverName: server.serverName }),
|
|
132
|
+
detail: `current=${JSON.stringify(existingComparable)} imported=${JSON.stringify(comparable)}`.slice(0, 200),
|
|
133
|
+
severity: 'warning',
|
|
134
|
+
target: { adapter: 'mcp', ref: existing.sourceLineId },
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return items;
|
|
140
|
+
}
|
|
141
|
+
async applyItem(item, ctx) {
|
|
142
|
+
const msg = ctx.msg;
|
|
143
|
+
const serverName = item.id.replace(/^mcp:/, '');
|
|
144
|
+
const data = ctx.sections.get('mcp');
|
|
145
|
+
const server = data?.servers.find((s) => s.serverName === serverName);
|
|
146
|
+
if (!server)
|
|
147
|
+
return { ok: false, message: msg('adapter.mcpMissing', { serverName }) };
|
|
148
|
+
const ref = item.target?.ref;
|
|
149
|
+
if (!ref)
|
|
150
|
+
return { ok: false, message: msg('adapter.missingTargetRef') };
|
|
151
|
+
const raw = buildMcpPatchLine(ref, server);
|
|
152
|
+
await ctx.target.patchFile.applyPatchChanges(USER_PATCH_FILE, [
|
|
153
|
+
{ lineId: ref, raw, action: item.kind === 'Create' ? 'insert' : 'update' },
|
|
154
|
+
]);
|
|
155
|
+
return { ok: true, needsRestart: true, message: msg('adapter.mcpWritten', { serverName }) };
|
|
156
|
+
}
|
|
157
|
+
async validate(data, msg = zhMsg) {
|
|
158
|
+
const issues = [];
|
|
159
|
+
if (data === null || typeof data !== 'object') {
|
|
160
|
+
return { valid: false, issues: [{ path: '$', message: msg('adapter.validate.object', { subject: 'mcp' }), severity: 'error' }] };
|
|
161
|
+
}
|
|
162
|
+
if (data.version !== 1) {
|
|
163
|
+
issues.push({ path: 'version', message: msg('adapter.validate.version', { value: String(data.version) }), severity: 'error' });
|
|
164
|
+
}
|
|
165
|
+
if (!Array.isArray(data.servers)) {
|
|
166
|
+
issues.push({ path: 'servers', message: msg('adapter.validate.array', { subject: 'servers' }), severity: 'error' });
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
for (const s of data.servers) {
|
|
170
|
+
if (s === null || typeof s !== 'object' || typeof s.serverName !== 'string' || s.serverName === '') {
|
|
171
|
+
issues.push({ path: 'servers[]', message: msg('adapter.validate.serverName'), severity: 'error' });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return { valid: issues.filter((i) => i.severity === 'error').length === 0, issues };
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { MsgFunc } from '../core/messages.ts';
|
|
2
|
+
import type { FilesSection } from '../schema/types.ts';
|
|
3
|
+
import type { ApplyResult, ConfigAdapter, ExportOptions, ExportSection, HostContext, ImportContext, PlanItem, ValidationResult } from '../core/types.ts';
|
|
4
|
+
export declare const DEFAULT_PLUGIN_FILE_WHITELIST: readonly string[];
|
|
5
|
+
export declare class PluginFilesAdapter implements ConfigAdapter<FilesSection> {
|
|
6
|
+
readonly id: 'pluginFiles';
|
|
7
|
+
readonly displayName = "Plugin Files";
|
|
8
|
+
readonly defaultIncluded = false;
|
|
9
|
+
readonly portability: 'deviceSpecific';
|
|
10
|
+
private readonly whitelist;
|
|
11
|
+
/** 约定配置目录(相对 ~/.dsh 根,如 'plugin-config');递归收集其下所有文件。undefined = 不收集。 */
|
|
12
|
+
private readonly collectDir?;
|
|
13
|
+
constructor(whitelist?: string[], collectDir?: string);
|
|
14
|
+
export(ctx: HostContext, _options: ExportOptions): Promise<ExportSection<FilesSection>>;
|
|
15
|
+
analyzeImport(data: FilesSection, ctx: ImportContext): Promise<PlanItem[]>;
|
|
16
|
+
applyItem(item: PlanItem, ctx: ImportContext): Promise<ApplyResult>;
|
|
17
|
+
validate(data: FilesSection, msg?: MsgFunc): Promise<ValidationResult>;
|
|
18
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pluginFiles 分区 adapter(可选,设计 §3.3/§1.2):
|
|
3
|
+
* 数据源 = 插件自有配置文件(相对 ~/.dsh 根):
|
|
4
|
+
* 1. 白名单固定文件(dsh-ssh.json、pet.json 等,避免扫描整个主目录);
|
|
5
|
+
* 2. 约定的插件配置目录(collectDir,如 plugin-config/)递归收集其下所有文件。
|
|
6
|
+
* relativePath 一律是「相对 ~/.dsh 根」的完整路径(与白名单文件一致),
|
|
7
|
+
* 导入时按同一相对路径写回原位置。默认关闭(defaultIncluded=false,用户显式勾选才导出)。
|
|
8
|
+
*/
|
|
9
|
+
import { sha256Hex } from '../utils/hashing.js';
|
|
10
|
+
import { msgOf, zhMsg } from '../core/messages.js';
|
|
11
|
+
import { linkWarnings, listFilesDetailed } from './link-report.js';
|
|
12
|
+
import { isPathSafe, isReservedInternalRel } from '../utils/paths.js';
|
|
13
|
+
export const DEFAULT_PLUGIN_FILE_WHITELIST = ['dsh-ssh.json', 'pet.json'];
|
|
14
|
+
export class PluginFilesAdapter {
|
|
15
|
+
id = 'pluginFiles';
|
|
16
|
+
displayName = 'Plugin Files';
|
|
17
|
+
defaultIncluded = false;
|
|
18
|
+
portability = 'deviceSpecific';
|
|
19
|
+
whitelist;
|
|
20
|
+
/** 约定配置目录(相对 ~/.dsh 根,如 'plugin-config');递归收集其下所有文件。undefined = 不收集。 */
|
|
21
|
+
collectDir;
|
|
22
|
+
constructor(whitelist = [...DEFAULT_PLUGIN_FILE_WHITELIST], collectDir) {
|
|
23
|
+
this.whitelist = whitelist;
|
|
24
|
+
if (collectDir !== undefined && collectDir !== '' && !isPathSafe(collectDir)) {
|
|
25
|
+
throw new Error(`pluginFiles collectDir 非法(须为相对 ~/.dsh 根的安全路径): ${collectDir}`);
|
|
26
|
+
}
|
|
27
|
+
this.collectDir = collectDir === '' ? undefined : collectDir;
|
|
28
|
+
}
|
|
29
|
+
async export(ctx, _options) {
|
|
30
|
+
const files = [];
|
|
31
|
+
const seen = new Set();
|
|
32
|
+
// 1) 白名单固定文件(不存在则跳过,dsh-ssh.json 等为按需创建)
|
|
33
|
+
for (const rel of this.whitelist) {
|
|
34
|
+
try {
|
|
35
|
+
const data = await ctx.fs.readFile(rel);
|
|
36
|
+
files.push({ relativePath: rel, data, contentHash: sha256Hex(data) });
|
|
37
|
+
seen.add(rel);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
/* 白名单文件不存在则跳过 */
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// 2) 约定配置目录递归收集(相对 ~/.dsh 根的完整路径;与白名单文件去重)
|
|
44
|
+
// issue #37:与 skills 等同一条遍历(跟随 junction/符号链接 + 跳过留痕)
|
|
45
|
+
let listing = { paths: [], skippedLinks: [], followedLinks: 0, unreadableDirs: [] };
|
|
46
|
+
if (this.collectDir !== undefined) {
|
|
47
|
+
try {
|
|
48
|
+
listing = await listFilesDetailed(ctx.fs, this.collectDir);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// 目录不存在视为空
|
|
52
|
+
}
|
|
53
|
+
const rels = listing.paths;
|
|
54
|
+
for (const rel of rels) {
|
|
55
|
+
if (seen.has(rel))
|
|
56
|
+
continue;
|
|
57
|
+
try {
|
|
58
|
+
const data = await ctx.fs.readFile(rel);
|
|
59
|
+
files.push({ relativePath: rel, data, contentHash: sha256Hex(data) });
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
sectionId: 'pluginFiles',
|
|
68
|
+
data: { version: 1, files },
|
|
69
|
+
counts: { files: files.length },
|
|
70
|
+
warnings: linkWarnings(msgOf(ctx), this.displayName, listing),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
async analyzeImport(data, ctx) {
|
|
74
|
+
const msg = ctx.msg;
|
|
75
|
+
const items = [];
|
|
76
|
+
for (const file of data.files) {
|
|
77
|
+
const id = `pluginFile:${file.relativePath}`;
|
|
78
|
+
// F23 修复:不可信 import 不得写内部 control-plane namespace(snapshots/transactions/locks/safe-mode)
|
|
79
|
+
if (isReservedInternalRel(file.relativePath)) {
|
|
80
|
+
items.push({
|
|
81
|
+
id, kind: 'Error', adapter: 'pluginFiles',
|
|
82
|
+
description: msg('adapter.pluginFileReserved', { path: file.relativePath }), severity: 'error',
|
|
83
|
+
});
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
let current = null;
|
|
87
|
+
try {
|
|
88
|
+
current = await ctx.target.fs.readFile(file.relativePath);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
current = null;
|
|
92
|
+
}
|
|
93
|
+
if (current === null) {
|
|
94
|
+
items.push({
|
|
95
|
+
id, kind: 'Create', adapter: 'pluginFiles',
|
|
96
|
+
description: msg('adapter.pluginFileCreate', { path: file.relativePath }), severity: 'info',
|
|
97
|
+
target: { adapter: 'pluginFiles', ref: file.relativePath },
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
else if (sha256Hex(current) === file.contentHash) {
|
|
101
|
+
items.push({ id, kind: 'Skip', adapter: 'pluginFiles', description: msg('adapter.fileSame', { path: file.relativePath }), severity: 'info' });
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
items.push({
|
|
105
|
+
id, kind: 'Conflict', adapter: 'pluginFiles',
|
|
106
|
+
description: msg('adapter.fileDiff', { path: file.relativePath }), severity: 'warning',
|
|
107
|
+
target: { adapter: 'pluginFiles', ref: file.relativePath },
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return items;
|
|
112
|
+
}
|
|
113
|
+
async applyItem(item, ctx) {
|
|
114
|
+
const ref = item.target?.ref;
|
|
115
|
+
if (!ref)
|
|
116
|
+
return { ok: false, message: ctx.msg('adapter.missingTargetRef') };
|
|
117
|
+
// F23 修复:apply 前拒绝写内部 control-plane namespace(纵深防御,analyzeImport 已标 Error)
|
|
118
|
+
if (isReservedInternalRel(ref)) {
|
|
119
|
+
return { ok: false, message: ctx.msg('adapter.pluginFileReserved', { path: ref }) };
|
|
120
|
+
}
|
|
121
|
+
const data = ctx.sections.get('pluginFiles');
|
|
122
|
+
const file = data?.files.find((f) => f.relativePath === ref);
|
|
123
|
+
if (!file)
|
|
124
|
+
return { ok: false, message: ctx.msg('adapter.dataMissingFile', { ref }) };
|
|
125
|
+
await ctx.target.fs.writeFile(ref, file.data);
|
|
126
|
+
return { ok: true };
|
|
127
|
+
}
|
|
128
|
+
async validate(data, msg = zhMsg) {
|
|
129
|
+
const issues = [];
|
|
130
|
+
if (data === null || typeof data !== 'object') {
|
|
131
|
+
return { valid: false, issues: [{ path: '$', message: msg('adapter.validate.object', { subject: 'pluginFiles' }), severity: 'error' }] };
|
|
132
|
+
}
|
|
133
|
+
if (data.version !== 1) {
|
|
134
|
+
issues.push({ path: 'version', message: msg('adapter.validate.version', { value: String(data.version) }), severity: 'error' });
|
|
135
|
+
}
|
|
136
|
+
if (!Array.isArray(data.files)) {
|
|
137
|
+
issues.push({ path: 'files', message: msg('adapter.validate.array', { subject: 'files' }), severity: 'error' });
|
|
138
|
+
}
|
|
139
|
+
return { valid: issues.filter((i) => i.severity === 'error').length === 0, issues };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=plugin-files.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { PackLocalPluginsResult } from '../core/local-plugin-pack.ts';
|
|
2
|
+
import type { MsgFunc } from '../core/messages.ts';
|
|
3
|
+
import type { PluginEntry, PluginsSection } from '../schema/types.ts';
|
|
4
|
+
import type { ApplyResult, ConfigAdapter, ExportOptions, ExportSection, HostContext, ImportContext, PlanItem, ValidationResult } from '../core/types.ts';
|
|
5
|
+
export declare const USER_PATCH_FILE = "cordis.patch.yml";
|
|
6
|
+
/**
|
|
7
|
+
* 本地源插件打包钩子(由宿主注入,见 src/index.ts createAdapters)。
|
|
8
|
+
* 返回打包结果(含字节与重写后的 spec);不注入 = 不做本地源打包(保持旧行为)。
|
|
9
|
+
*/
|
|
10
|
+
export type LocalPluginPackHook = (plugins: PluginEntry[], ctx: HostContext) => Promise<PackLocalPluginsResult>;
|
|
11
|
+
/** 本地插件 tarball 解包到 homeDir 内的固定缓存目录(相对 $DSH_HOME)。 */
|
|
12
|
+
export declare const LOCAL_TARBALL_CACHE_REL = "dsh-config-manager/local-plugins";
|
|
13
|
+
/** 归档内相对路径 → 缓存目录下的安全文件名(拒绝任何路径穿越)。 */
|
|
14
|
+
export declare function localTarballCacheName(relativePath: string): string;
|
|
15
|
+
/** profile 目录相对 $DSH_HOME 的路径(patches/ 与 pnpm-workspace.yaml 都挂在这里)。 */
|
|
16
|
+
export declare const PNPM_PROFILE_DIR: (profile: string | undefined) => string;
|
|
17
|
+
/** pnpm-workspace.yaml 相对 $DSH_HOME 的路径(plugins 分区内按「插件安装配置」管理)。 */
|
|
18
|
+
export declare const PNPM_WORKSPACE_REL: (profile: string | undefined) => string;
|
|
19
|
+
/** 单个 patch 文件随备份迁移的体积上限(issue #35;patch 是纯文本,超过说明放错了东西)。 */
|
|
20
|
+
export declare const MAX_PATCH_FILE_BYTES: number;
|
|
21
|
+
export declare class PluginsAdapter implements ConfigAdapter<PluginsSection> {
|
|
22
|
+
readonly id: 'plugins';
|
|
23
|
+
readonly displayName = "Plugins";
|
|
24
|
+
readonly defaultIncluded = true;
|
|
25
|
+
readonly portability: 'portable';
|
|
26
|
+
/** 插件自身包名:导出 plugins 分区时不列自己(避免备份里出现「当前正在生成备份的插件」的自引用条目) */
|
|
27
|
+
private readonly selfName;
|
|
28
|
+
/** T1:本地源(link:/file:)插件打包钩子;未注入 = 不打包(保持改造前行为) */
|
|
29
|
+
private readonly localPack;
|
|
30
|
+
constructor(selfName?: string, localPack?: LocalPluginPackHook);
|
|
31
|
+
export(ctx: HostContext, _options: ExportOptions): Promise<ExportSection<PluginsSection>>;
|
|
32
|
+
/**
|
|
33
|
+
* 导入后目标机**可能**存在的 patch 文件集合(相对 profile 目录)——issue #35。
|
|
34
|
+
* = 备份携带的 patchFiles ∪ 目标机本来就有的文件。只用于判定「声明能否被满足」,
|
|
35
|
+
* 不做任何写入(写入在 applyItem 内、且先于 pnpm-workspace.yaml)。
|
|
36
|
+
*/
|
|
37
|
+
private patchAvailability;
|
|
38
|
+
analyzeImport(data: PluginsSection, ctx: ImportContext): Promise<PlanItem[]>;
|
|
39
|
+
applyItem(item: PlanItem, ctx: ImportContext): Promise<ApplyResult>;
|
|
40
|
+
validate(data: PluginsSection, msg?: MsgFunc): Promise<ValidationResult>;
|
|
41
|
+
}
|