dsh-config-manager 0.1.0
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 +216 -0
- package/README.zh-CN.md +218 -0
- package/cordis.patch.yml +45 -0
- package/dsh.bundle.patch +21 -0
- package/dsh.client +39 -0
- package/lib/adapters/agent-presets.d.ts +13 -0
- package/lib/adapters/agent-presets.js +14 -0
- package/lib/adapters/agent-presets.js.map +1 -0
- package/lib/adapters/credentials.d.ts +36 -0
- package/lib/adapters/credentials.js +121 -0
- package/lib/adapters/credentials.js.map +1 -0
- package/lib/adapters/file-collection.d.ts +14 -0
- package/lib/adapters/file-collection.js +102 -0
- package/lib/adapters/file-collection.js.map +1 -0
- package/lib/adapters/index.d.ts +38 -0
- package/lib/adapters/index.js +46 -0
- package/lib/adapters/index.js.map +1 -0
- package/lib/adapters/mcp.d.ts +27 -0
- package/lib/adapters/mcp.js +175 -0
- package/lib/adapters/mcp.js.map +1 -0
- package/lib/adapters/plugin-files.d.ts +15 -0
- package/lib/adapters/plugin-files.js +91 -0
- package/lib/adapters/plugin-files.js.map +1 -0
- package/lib/adapters/plugins.d.ts +13 -0
- package/lib/adapters/plugins.js +177 -0
- package/lib/adapters/plugins.js.map +1 -0
- package/lib/adapters/prompts.d.ts +29 -0
- package/lib/adapters/prompts.js +228 -0
- package/lib/adapters/prompts.js.map +1 -0
- package/lib/adapters/providers.d.ts +33 -0
- package/lib/adapters/providers.js +143 -0
- package/lib/adapters/providers.js.map +1 -0
- package/lib/adapters/sessions.d.ts +14 -0
- package/lib/adapters/sessions.js +15 -0
- package/lib/adapters/sessions.js.map +1 -0
- package/lib/adapters/settings.d.ts +23 -0
- package/lib/adapters/settings.js +142 -0
- package/lib/adapters/settings.js.map +1 -0
- package/lib/adapters/skills.d.ts +13 -0
- package/lib/adapters/skills.js +14 -0
- package/lib/adapters/skills.js.map +1 -0
- package/lib/adapters/test-helpers.d.ts +99 -0
- package/lib/adapters/test-helpers.js +192 -0
- package/lib/adapters/test-helpers.js.map +1 -0
- package/lib/adapters/ui.d.ts +26 -0
- package/lib/adapters/ui.js +88 -0
- package/lib/adapters/ui.js.map +1 -0
- package/lib/adapters/workspaces.d.ts +12 -0
- package/lib/adapters/workspaces.js +92 -0
- package/lib/adapters/workspaces.js.map +1 -0
- package/lib/client.d.ts +377 -0
- package/lib/client.js +2598 -0
- package/lib/client.js.map +1 -0
- package/lib/core/analyzer.d.ts +35 -0
- package/lib/core/analyzer.js +563 -0
- package/lib/core/analyzer.js.map +1 -0
- package/lib/core/backup.d.ts +29 -0
- package/lib/core/backup.js +184 -0
- package/lib/core/backup.js.map +1 -0
- package/lib/core/exporter.d.ts +37 -0
- package/lib/core/exporter.js +222 -0
- package/lib/core/exporter.js.map +1 -0
- package/lib/core/importer.d.ts +42 -0
- package/lib/core/importer.js +25 -0
- package/lib/core/importer.js.map +1 -0
- package/lib/core/index.d.ts +12 -0
- package/lib/core/index.js +11 -0
- package/lib/core/index.js.map +1 -0
- package/lib/core/rollback.d.ts +9 -0
- package/lib/core/rollback.js +136 -0
- package/lib/core/rollback.js.map +1 -0
- package/lib/core/types.d.ts +331 -0
- package/lib/core/types.js +18 -0
- package/lib/core/types.js.map +1 -0
- package/lib/core/validator.d.ts +18 -0
- package/lib/core/validator.js +77 -0
- package/lib/core/validator.js.map +1 -0
- package/lib/index.d.ts +51 -0
- package/lib/index.js +875 -0
- package/lib/index.js.map +1 -0
- package/lib/migrations/index.d.ts +29 -0
- package/lib/migrations/index.js +56 -0
- package/lib/migrations/index.js.map +1 -0
- package/lib/migrations/v1-to-v2.d.ts +9 -0
- package/lib/migrations/v1-to-v2.js +10 -0
- package/lib/migrations/v1-to-v2.js.map +1 -0
- package/lib/profiles/index.d.ts +4 -0
- package/lib/profiles/index.js +5 -0
- package/lib/profiles/index.js.map +1 -0
- package/lib/profiles/profile-manager.d.ts +102 -0
- package/lib/profiles/profile-manager.js +522 -0
- package/lib/profiles/profile-manager.js.map +1 -0
- package/lib/schema/config.d.ts +28 -0
- package/lib/schema/config.js +136 -0
- package/lib/schema/config.js.map +1 -0
- package/lib/schema/manifest.d.ts +28 -0
- package/lib/schema/manifest.js +109 -0
- package/lib/schema/manifest.js.map +1 -0
- package/lib/schema/types.d.ts +169 -0
- package/lib/schema/types.js +8 -0
- package/lib/schema/types.js.map +1 -0
- package/lib/schema/versions.d.ts +27 -0
- package/lib/schema/versions.js +50 -0
- package/lib/schema/versions.js.map +1 -0
- package/lib/security/encryption.d.ts +41 -0
- package/lib/security/encryption.js +152 -0
- package/lib/security/encryption.js.map +1 -0
- package/lib/security/index.d.ts +16 -0
- package/lib/security/index.js +17 -0
- package/lib/security/index.js.map +1 -0
- package/lib/security/integrity.d.ts +30 -0
- package/lib/security/integrity.js +78 -0
- package/lib/security/integrity.js.map +1 -0
- package/lib/security/redaction.d.ts +26 -0
- package/lib/security/redaction.js +95 -0
- package/lib/security/redaction.js.map +1 -0
- package/lib/security/secret-scanner.d.ts +48 -0
- package/lib/security/secret-scanner.js +253 -0
- package/lib/security/secret-scanner.js.map +1 -0
- package/lib/security/zip-security.d.ts +27 -0
- package/lib/security/zip-security.js +154 -0
- package/lib/security/zip-security.js.map +1 -0
- package/lib/ui/conflict-view.d.ts +28 -0
- package/lib/ui/conflict-view.js +49 -0
- package/lib/ui/conflict-view.js.map +1 -0
- package/lib/ui/errors.d.ts +17 -0
- package/lib/ui/errors.js +76 -0
- package/lib/ui/errors.js.map +1 -0
- package/lib/ui/export-flow.d.ts +62 -0
- package/lib/ui/export-flow.js +79 -0
- package/lib/ui/export-flow.js.map +1 -0
- package/lib/ui/import-wizard.d.ts +67 -0
- package/lib/ui/import-wizard.js +169 -0
- package/lib/ui/import-wizard.js.map +1 -0
- package/lib/ui/path-mapping.d.ts +38 -0
- package/lib/ui/path-mapping.js +75 -0
- package/lib/ui/path-mapping.js.map +1 -0
- package/lib/ui/progress.d.ts +27 -0
- package/lib/ui/progress.js +76 -0
- package/lib/ui/progress.js.map +1 -0
- package/lib/ui/report.d.ts +21 -0
- package/lib/ui/report.js +146 -0
- package/lib/ui/report.js.map +1 -0
- package/lib/ui/test-helpers.d.ts +62 -0
- package/lib/ui/test-helpers.js +147 -0
- package/lib/ui/test-helpers.js.map +1 -0
- package/lib/ui/types.d.ts +129 -0
- package/lib/ui/types.js +21 -0
- package/lib/ui/types.js.map +1 -0
- package/lib/utils/hashing.d.ts +17 -0
- package/lib/utils/hashing.js +41 -0
- package/lib/utils/hashing.js.map +1 -0
- package/lib/utils/json.d.ts +24 -0
- package/lib/utils/json.js +76 -0
- package/lib/utils/json.js.map +1 -0
- package/lib/utils/logger.d.ts +39 -0
- package/lib/utils/logger.js +82 -0
- package/lib/utils/logger.js.map +1 -0
- package/lib/utils/paths.d.ts +31 -0
- package/lib/utils/paths.js +132 -0
- package/lib/utils/paths.js.map +1 -0
- package/lib/utils/zip.d.ts +54 -0
- package/lib/utils/zip.js +285 -0
- package/lib/utils/zip.js.map +1 -0
- package/package.json +109 -0
- package/src/adapters/agent-presets.ts +14 -0
- package/src/adapters/credentials.test.ts +90 -0
- package/src/adapters/credentials.ts +141 -0
- package/src/adapters/file-collection.ts +110 -0
- package/src/adapters/files.test.ts +113 -0
- package/src/adapters/index.ts +69 -0
- package/src/adapters/mcp.test.ts +96 -0
- package/src/adapters/mcp.ts +181 -0
- package/src/adapters/plugin-files.ts +96 -0
- package/src/adapters/plugins.test.ts +72 -0
- package/src/adapters/plugins.ts +176 -0
- package/src/adapters/prompts.test.ts +110 -0
- package/src/adapters/prompts.ts +226 -0
- package/src/adapters/providers.test.ts +125 -0
- package/src/adapters/providers.ts +161 -0
- package/src/adapters/roundtrip.test.ts +188 -0
- package/src/adapters/sessions.ts +15 -0
- package/src/adapters/settings.test.ts +93 -0
- package/src/adapters/settings.ts +165 -0
- package/src/adapters/skills.ts +14 -0
- package/src/adapters/test-helpers.ts +207 -0
- package/src/adapters/ui.test.ts +56 -0
- package/src/adapters/ui.ts +106 -0
- package/src/adapters/workspaces.test.ts +79 -0
- package/src/adapters/workspaces.ts +95 -0
- package/src/client/CLIENT_DEPENDENCIES.md +101 -0
- package/src/client/ConfigManagerSection.tsx +60 -0
- package/src/client/api.ts +270 -0
- package/src/client/client-types.ts +27 -0
- package/src/client/common/ErrorBanner.tsx +68 -0
- package/src/client/common/ProgressBar.tsx +49 -0
- package/src/client/common/ReportView.tsx +117 -0
- package/src/client/common/ui.tsx +165 -0
- package/src/client/config-manager.module.css +759 -0
- package/src/client/css-modules.d.ts +8 -0
- package/src/client/export/ExportView.tsx +222 -0
- package/src/client/import/ConflictList.tsx +72 -0
- package/src/client/import/ImportWizardView.tsx +406 -0
- package/src/client/import/PathMappingForm.tsx +77 -0
- package/src/client/index.ts +65 -0
- package/src/client/locales.ts +182 -0
- package/src/core/analyzer.ts +631 -0
- package/src/core/backup.ts +212 -0
- package/src/core/exporter.ts +246 -0
- package/src/core/importer.ts +66 -0
- package/src/core/index.ts +39 -0
- package/src/core/rollback.ts +140 -0
- package/src/core/smoke.test.ts +717 -0
- package/src/core/types.ts +343 -0
- package/src/core/validator.ts +84 -0
- package/src/index.ts +942 -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 +280 -0
- package/src/profiles/profile-manager.ts +606 -0
- package/src/schema/config.ts +137 -0
- package/src/schema/manifest.ts +124 -0
- package/src/schema/types.ts +179 -0
- package/src/schema/versions.ts +55 -0
- package/src/security/encryption.ts +180 -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 +275 -0
- package/src/security/security.test.ts +796 -0
- package/src/security/zip-security.ts +180 -0
- package/src/ui/conflict-view.test.ts +62 -0
- package/src/ui/conflict-view.ts +65 -0
- package/src/ui/errors.test.ts +44 -0
- package/src/ui/errors.ts +95 -0
- package/src/ui/export-flow.test.ts +75 -0
- package/src/ui/export-flow.ts +128 -0
- package/src/ui/import-wizard.test.ts +128 -0
- package/src/ui/import-wizard.ts +208 -0
- package/src/ui/path-mapping.test.ts +67 -0
- package/src/ui/path-mapping.ts +103 -0
- package/src/ui/progress.test.ts +42 -0
- package/src/ui/progress.ts +90 -0
- package/src/ui/report.test.ts +93 -0
- package/src/ui/report.ts +140 -0
- package/src/ui/test-helpers.ts +177 -0
- package/src/ui/types.ts +193 -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 +122 -0
- package/src/utils/zip.ts +332 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rollback(规范 §17 / 设计 §8.2):导入失败时逆序执行快照条目的补偿动作。
|
|
3
|
+
*
|
|
4
|
+
* 诚实原则:
|
|
5
|
+
* - 尽力回滚:单项失败不停止其余补偿,最终如实报告 full / partial;
|
|
6
|
+
* - credential 值 DSH 永不回读 → existed=true 的凭据无法自动恢复原值,
|
|
7
|
+
* 如实标记 failed + manualHint(人工补录);
|
|
8
|
+
* - settings 回滚仍走 expectedRevision 乐观锁,避免覆盖导入后用户的新修改。
|
|
9
|
+
*/
|
|
10
|
+
import { resolveFileTarget } from "./backup.js";
|
|
11
|
+
/** 逆序补偿单条快照条目;返回 null=成功,否则为失败原因 */
|
|
12
|
+
async function compensateOne(entry, ctx, store) {
|
|
13
|
+
switch (entry.kind) {
|
|
14
|
+
case 'settingsNamespace': {
|
|
15
|
+
try {
|
|
16
|
+
if (!entry.existed) {
|
|
17
|
+
// 原目标不存在该 namespace:若导入已创建它,DSH settings 无删除语义 → 无法恢复「不存在」
|
|
18
|
+
let current = null;
|
|
19
|
+
try {
|
|
20
|
+
current = await ctx.settings.describe(entry.ref);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
current = null;
|
|
24
|
+
}
|
|
25
|
+
if (current === null)
|
|
26
|
+
return null; // 本来就没有且未创建 → 无需恢复
|
|
27
|
+
return {
|
|
28
|
+
reason: '该 namespace 由导入创建,DSH settings 无删除语义',
|
|
29
|
+
manualHint: `namespace "${entry.ref}" 需人工删除或合并`,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
// 用当前 revision 作乐观锁基准:读时即锁,冲突则如实失败(不覆盖并发修改)
|
|
33
|
+
const current = await ctx.settings.describe(entry.ref);
|
|
34
|
+
await ctx.settings.replace(entry.ref, entry.before, current.revision);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
return { reason: err instanceof Error ? err.message : String(err), manualHint: `settings namespace "${entry.ref}" 需人工核对` };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
case 'credential': {
|
|
42
|
+
if (entry.existed) {
|
|
43
|
+
// 值不可回读:无法自动恢复原值
|
|
44
|
+
return {
|
|
45
|
+
reason: 'DSH 不回读凭据值,无法自动恢复',
|
|
46
|
+
manualHint: `凭据 "${entry.ref}" 请人工重新填写`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
await ctx.credentials.unset(entry.ref);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
return { reason: err instanceof Error ? err.message : String(err) };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
case 'patchLine': {
|
|
58
|
+
try {
|
|
59
|
+
const file = entry.ref.split('\u0000')[0] ?? 'cordis.patch.yml';
|
|
60
|
+
const lineId = entry.ref.includes('\u0000') ? entry.ref.split('\u0000')[1] : entry.ref;
|
|
61
|
+
await ctx.patchFile.applyPatchChanges(file, [
|
|
62
|
+
{ lineId, raw: entry.before, action: entry.before === null ? 'remove' : 'update' },
|
|
63
|
+
]);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
return { reason: err instanceof Error ? err.message : String(err), manualHint: `patch 行 "${entry.ref}" 需人工核对` };
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
case 'file': {
|
|
71
|
+
try {
|
|
72
|
+
const abs = resolveFileTarget(ctx, entry.adapter, entry.ref);
|
|
73
|
+
if (entry.existed && entry.copiedTo && store) {
|
|
74
|
+
const data = await store.readBlob(entry.snapshotId ?? '', entry.copiedTo);
|
|
75
|
+
await ctx.fs.writeFile(abs, data);
|
|
76
|
+
}
|
|
77
|
+
else if (!entry.existed) {
|
|
78
|
+
// 原文件不存在 → 删除导入写入的文件
|
|
79
|
+
if (await ctx.fs.exists(abs))
|
|
80
|
+
await ctx.fs.remove(abs);
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
return { reason: err instanceof Error ? err.message : String(err), manualHint: `文件 "${entry.ref}" 需人工恢复` };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
case 'workspaceRecord': {
|
|
89
|
+
try {
|
|
90
|
+
if (entry.before === null) {
|
|
91
|
+
await ctx.workspace.removeRecord?.(entry.ref);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
await ctx.workspace.writeRecord(entry.before);
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
return { reason: err instanceof Error ? err.message : String(err), manualHint: `workspace "${entry.ref}" 需人工核对` };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
default:
|
|
103
|
+
return { reason: `未知快照条目类型 ${entry.kind}` };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** 回滚:逆序补偿全部条目;返回诚实报告(full / partial) */
|
|
107
|
+
export async function rollback(opts) {
|
|
108
|
+
const { ctx, snapshot, store, adapters } = opts;
|
|
109
|
+
const restored = [];
|
|
110
|
+
const failed = [];
|
|
111
|
+
// 逆序遍历;adapter 自带的 rollback? 优先,否则引擎通用补偿
|
|
112
|
+
const entries = [...snapshot.entries].reverse();
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
const adapter = adapters?.find((a) => a.id === entry.adapter);
|
|
115
|
+
let error = null;
|
|
116
|
+
if (adapter?.rollback) {
|
|
117
|
+
try {
|
|
118
|
+
await adapter.rollback([entry], ctx);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
error = { reason: err instanceof Error ? err.message : String(err) };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
error = await compensateOne(entry, ctx, store);
|
|
126
|
+
}
|
|
127
|
+
if (error === null) {
|
|
128
|
+
restored.push(`${entry.adapter}:${entry.ref}`);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
failed.push({ item: `${entry.adapter}:${entry.ref}`, reason: error.reason, manualHint: error.manualHint });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return { full: failed.length === 0, restored, failed };
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=rollback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rollback.js","sourceRoot":"","sources":["../../src/core/rollback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 核心引擎契约类型(对齐 Docs/design/architecture.md §13.2/§13.3/§13.5)。
|
|
3
|
+
*
|
|
4
|
+
* 关键解耦原则:核心引擎只依赖这里的接口,绝不 import DSH 运行时包。
|
|
5
|
+
* HostContext 是 m3 定义、m5 实现的 DSH Service 门面(研究报告 §3.2 的叶子方法最小集),
|
|
6
|
+
* 测试用内存 mock 即可驱动完整导出→导入往返。
|
|
7
|
+
*/
|
|
8
|
+
import type { EncryptionInfo, Manifest, SectionId, WorkspaceRecord } from '../schema/types.ts';
|
|
9
|
+
import type { Logger } from '../utils/logger.ts';
|
|
10
|
+
export interface ExportOptions {
|
|
11
|
+
/** 是否包含真实秘密(必须配合 encryption 提供者;缺省 false = 只导状态) */
|
|
12
|
+
includeSecrets: boolean;
|
|
13
|
+
/** 仅导出指定分区(缺省 = 全部默认包含分区) */
|
|
14
|
+
only?: SectionId[];
|
|
15
|
+
/** 导出文件路径(缺省自动生成 dsh-config-<date>.zip) */
|
|
16
|
+
outPath?: string;
|
|
17
|
+
}
|
|
18
|
+
/** adapter.export() 的产出:数据 + 文件 + 报告计数 + 告警 */
|
|
19
|
+
export interface ExportSection<T = unknown> {
|
|
20
|
+
sectionId: SectionId;
|
|
21
|
+
data: T;
|
|
22
|
+
/** 文件类分区(skills/agentPresets/pluginFiles/sessions)以真实文件形式进入 ZIP */
|
|
23
|
+
files?: {
|
|
24
|
+
relativePath: string;
|
|
25
|
+
data: Uint8Array;
|
|
26
|
+
}[];
|
|
27
|
+
counts: Record<string, number>;
|
|
28
|
+
warnings: string[];
|
|
29
|
+
}
|
|
30
|
+
export interface ValidationResult {
|
|
31
|
+
valid: boolean;
|
|
32
|
+
issues: {
|
|
33
|
+
path: string;
|
|
34
|
+
message: string;
|
|
35
|
+
severity: 'error' | 'warning';
|
|
36
|
+
}[];
|
|
37
|
+
}
|
|
38
|
+
export interface SensitiveHit {
|
|
39
|
+
path: string;
|
|
40
|
+
field: string;
|
|
41
|
+
}
|
|
42
|
+
export interface SecretScanner {
|
|
43
|
+
/** 递归扫描 + 剥离敏感字段值;返回清洗后的数据与命中清单(不泄值) */
|
|
44
|
+
scanAndRedact(data: unknown): {
|
|
45
|
+
sanitized: unknown;
|
|
46
|
+
hits: SensitiveHit[];
|
|
47
|
+
};
|
|
48
|
+
/** 文本级扫描(文件类分区内容),供强化版使用 */
|
|
49
|
+
scanText?(text: string): SensitiveHit[];
|
|
50
|
+
}
|
|
51
|
+
export interface NamespaceInfo {
|
|
52
|
+
value: unknown;
|
|
53
|
+
base?: unknown;
|
|
54
|
+
revision: number;
|
|
55
|
+
applies?: string[];
|
|
56
|
+
secrets: {
|
|
57
|
+
path: string[];
|
|
58
|
+
set: boolean;
|
|
59
|
+
}[];
|
|
60
|
+
}
|
|
61
|
+
export interface SettingsFacade {
|
|
62
|
+
/** 读某 namespace(redactSecrets 剥离密钥值);返回含乐观锁 revision */
|
|
63
|
+
describe(namespace: string, opts?: {
|
|
64
|
+
redactSecrets?: boolean;
|
|
65
|
+
}): Promise<NamespaceInfo>;
|
|
66
|
+
/** 整体替换(导入/回滚主通道);expectedRevision 不一致时抛 SETTINGS_CONFLICT 类错误 */
|
|
67
|
+
replace(namespace: string, value: unknown, expectedRevision?: number): Promise<void>;
|
|
68
|
+
/** 部分更新(未来 Merge 策略用) */
|
|
69
|
+
update?(namespace: string, patch: unknown, expectedRevision?: number): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
export interface CredentialsFacade {
|
|
72
|
+
/** 只返回状态,永不返回值 */
|
|
73
|
+
describe(ref: string): Promise<{
|
|
74
|
+
configured: boolean;
|
|
75
|
+
source?: string;
|
|
76
|
+
writable?: boolean;
|
|
77
|
+
}>;
|
|
78
|
+
set(ref: string, value: string): Promise<void>;
|
|
79
|
+
unset(ref: string): Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
export interface PluginInfo {
|
|
82
|
+
name: string;
|
|
83
|
+
version: string;
|
|
84
|
+
enabled: boolean;
|
|
85
|
+
isBundle?: boolean;
|
|
86
|
+
inBundles?: string[];
|
|
87
|
+
}
|
|
88
|
+
export interface PluginsFacade {
|
|
89
|
+
listInstalled(): Promise<PluginInfo[]>;
|
|
90
|
+
install(pkg: string): Promise<{
|
|
91
|
+
needsRestart: boolean;
|
|
92
|
+
}>;
|
|
93
|
+
}
|
|
94
|
+
export interface WorkspaceFacade {
|
|
95
|
+
listRecords(): Promise<WorkspaceRecord[]>;
|
|
96
|
+
writeRecord(record: WorkspaceRecord): Promise<void>;
|
|
97
|
+
removeRecord?(id: string): Promise<void>;
|
|
98
|
+
}
|
|
99
|
+
export interface PatchChange {
|
|
100
|
+
lineId: string;
|
|
101
|
+
raw: unknown;
|
|
102
|
+
action: 'insert' | 'update' | 'remove';
|
|
103
|
+
}
|
|
104
|
+
export interface PatchFileFacade {
|
|
105
|
+
readPatchLines(file: string): Promise<{
|
|
106
|
+
lineId: string;
|
|
107
|
+
raw: unknown;
|
|
108
|
+
}[]>;
|
|
109
|
+
applyPatchChanges(file: string, changes: PatchChange[]): Promise<void>;
|
|
110
|
+
}
|
|
111
|
+
export interface FileSystemFacade {
|
|
112
|
+
readFile(relPath: string): Promise<Uint8Array>;
|
|
113
|
+
writeFile(relPath: string, data: Uint8Array): Promise<void>;
|
|
114
|
+
exists(relPath: string): Promise<boolean>;
|
|
115
|
+
copy(from: string, to: string): Promise<void>;
|
|
116
|
+
remove(relPath: string): Promise<void>;
|
|
117
|
+
listRecursive(dir: string): Promise<string[]>;
|
|
118
|
+
mkdir(dir: string): Promise<void>;
|
|
119
|
+
}
|
|
120
|
+
/** DSH 运行时门面:m3 只依赖此接口;m5 用真实 ctx.settings/credentials/… 实现 */
|
|
121
|
+
export interface HostContext {
|
|
122
|
+
platform: string;
|
|
123
|
+
arch: string;
|
|
124
|
+
homeDir: string;
|
|
125
|
+
dshVersion: string;
|
|
126
|
+
log: Logger;
|
|
127
|
+
settings: SettingsFacade;
|
|
128
|
+
credentials: CredentialsFacade;
|
|
129
|
+
plugins: PluginsFacade;
|
|
130
|
+
workspace: WorkspaceFacade;
|
|
131
|
+
patchFile: PatchFileFacade;
|
|
132
|
+
fs: FileSystemFacade;
|
|
133
|
+
}
|
|
134
|
+
export type PlanItemKind = 'Create' | 'Update' | 'Skip' | 'Conflict' | 'Install' | 'MissingSecret' | 'MissingDependency' | 'PathMapping' | 'Warning' | 'Error';
|
|
135
|
+
export type ItemResolution = 'keepCurrent' | 'useImported' | 'review';
|
|
136
|
+
export type GlobalConflictStrategy = 'merge' | 'replace' | 'skipExisting';
|
|
137
|
+
export interface ConflictDecision {
|
|
138
|
+
itemId: string;
|
|
139
|
+
resolution: ItemResolution;
|
|
140
|
+
}
|
|
141
|
+
export interface PathMapping {
|
|
142
|
+
oldPrefix: string;
|
|
143
|
+
newPrefix: string;
|
|
144
|
+
appliesTo: ('workspaces' | 'mcp' | 'pluginConfig' | 'skills')[];
|
|
145
|
+
}
|
|
146
|
+
export interface PathIssue {
|
|
147
|
+
kind: 'missing' | 'platformMismatch' | 'homeMismatch';
|
|
148
|
+
value: string;
|
|
149
|
+
mappedTo?: string;
|
|
150
|
+
}
|
|
151
|
+
export interface SnapshotTarget {
|
|
152
|
+
adapter: SectionId;
|
|
153
|
+
ref: string;
|
|
154
|
+
}
|
|
155
|
+
export interface PlanItem {
|
|
156
|
+
id: string;
|
|
157
|
+
kind: PlanItemKind;
|
|
158
|
+
adapter: SectionId;
|
|
159
|
+
description: string;
|
|
160
|
+
detail?: string;
|
|
161
|
+
severity: 'info' | 'warning' | 'error';
|
|
162
|
+
conflict?: ConflictDecision;
|
|
163
|
+
pathMapping?: PathMapping;
|
|
164
|
+
missingDependency?: string;
|
|
165
|
+
target?: SnapshotTarget;
|
|
166
|
+
}
|
|
167
|
+
export interface ApplyResult {
|
|
168
|
+
ok: boolean;
|
|
169
|
+
message?: string;
|
|
170
|
+
needsRestart?: boolean;
|
|
171
|
+
}
|
|
172
|
+
export interface ImportAnalysis {
|
|
173
|
+
valid: boolean;
|
|
174
|
+
errors: string[];
|
|
175
|
+
warnings: string[];
|
|
176
|
+
compatibility: 'excellent' | 'good' | 'partial' | 'unsupported';
|
|
177
|
+
sectionsInZip: SectionId[];
|
|
178
|
+
pluginSummary: {
|
|
179
|
+
installed: number;
|
|
180
|
+
toInstall: number;
|
|
181
|
+
};
|
|
182
|
+
pathIssues: PathIssue[];
|
|
183
|
+
secretCount: number;
|
|
184
|
+
dependencyIssues: {
|
|
185
|
+
item: string;
|
|
186
|
+
dependency: string;
|
|
187
|
+
}[];
|
|
188
|
+
}
|
|
189
|
+
export interface ImportDecisions {
|
|
190
|
+
strategy: GlobalConflictStrategy;
|
|
191
|
+
resolutions: Record<string, ItemResolution>;
|
|
192
|
+
pathMappings: PathMapping[];
|
|
193
|
+
}
|
|
194
|
+
export interface ImportPlan {
|
|
195
|
+
items: PlanItem[];
|
|
196
|
+
globalStrategy: GlobalConflictStrategy;
|
|
197
|
+
pathMappings: PathMapping[];
|
|
198
|
+
missingSecrets: {
|
|
199
|
+
ref: string;
|
|
200
|
+
required: boolean;
|
|
201
|
+
}[];
|
|
202
|
+
needsRestart: boolean;
|
|
203
|
+
estimatedActions: Record<SectionId, number>;
|
|
204
|
+
}
|
|
205
|
+
export interface ExecutedItem {
|
|
206
|
+
itemId: string;
|
|
207
|
+
status: 'ok' | 'skipped' | 'failed';
|
|
208
|
+
message?: string;
|
|
209
|
+
}
|
|
210
|
+
export interface ImportResult {
|
|
211
|
+
ok: boolean;
|
|
212
|
+
executed: ExecutedItem[];
|
|
213
|
+
needsRestart: boolean;
|
|
214
|
+
missingSecrets: string[];
|
|
215
|
+
warnings: string[];
|
|
216
|
+
rollback: RollbackReport | null;
|
|
217
|
+
snapshotId: string | null;
|
|
218
|
+
}
|
|
219
|
+
export interface ImportContext {
|
|
220
|
+
manifest: Manifest;
|
|
221
|
+
targetPlatform: string;
|
|
222
|
+
/** 目标 DSH 门面(adapter 比较目标状态 / 写入 / 读取数据用) */
|
|
223
|
+
target: HostContext;
|
|
224
|
+
/** 已由 PathMapper 处理后的各分区最终数据(adapter.applyItem 从这取写入内容) */
|
|
225
|
+
sections: Map<SectionId, unknown>;
|
|
226
|
+
pathMappings: PathMapping[];
|
|
227
|
+
resolutions: Record<string, ItemResolution>;
|
|
228
|
+
/** 用户补录的秘密值(仅内存,永不落盘/日志) */
|
|
229
|
+
secretInputs: Record<string, string>;
|
|
230
|
+
decryptedCredentials?: Map<string, string>;
|
|
231
|
+
log: Logger;
|
|
232
|
+
}
|
|
233
|
+
export type SnapshotEntryKind = 'settingsNamespace' | 'credential' | 'patchLine' | 'file' | 'workspaceRecord';
|
|
234
|
+
export interface SnapshotEntry {
|
|
235
|
+
kind: SnapshotEntryKind;
|
|
236
|
+
adapter: SectionId;
|
|
237
|
+
ref: string;
|
|
238
|
+
/** 原值(credential 条目不含值,仅 existed 标志) */
|
|
239
|
+
before: unknown;
|
|
240
|
+
revision?: number;
|
|
241
|
+
/** file 条目:原文件副本在快照存储中的位置 */
|
|
242
|
+
copiedTo?: string;
|
|
243
|
+
/** credential/file 条目:原目标是否存在 */
|
|
244
|
+
existed?: boolean;
|
|
245
|
+
/** 所属快照 id(file 条目回滚读取 blob 时使用) */
|
|
246
|
+
snapshotId?: string;
|
|
247
|
+
}
|
|
248
|
+
export interface Snapshot {
|
|
249
|
+
id: string;
|
|
250
|
+
createdAt: string;
|
|
251
|
+
sourceZip: string;
|
|
252
|
+
entries: SnapshotEntry[];
|
|
253
|
+
}
|
|
254
|
+
/** 快照存储(默认文件实现见 core/backup.ts;测试可用内存实现) */
|
|
255
|
+
export interface SnapshotStore {
|
|
256
|
+
save(snapshot: Snapshot, blobs?: Map<string, Uint8Array>): Promise<string>;
|
|
257
|
+
load(id: string): Promise<Snapshot>;
|
|
258
|
+
readBlob(id: string, blobPath: string): Promise<Uint8Array>;
|
|
259
|
+
}
|
|
260
|
+
export interface RollbackReport {
|
|
261
|
+
full: boolean;
|
|
262
|
+
restored: string[];
|
|
263
|
+
failed: {
|
|
264
|
+
item: string;
|
|
265
|
+
reason: string;
|
|
266
|
+
manualHint?: string;
|
|
267
|
+
}[];
|
|
268
|
+
}
|
|
269
|
+
export interface CompatibilityInput {
|
|
270
|
+
sourceDsh: string;
|
|
271
|
+
targetDsh: string;
|
|
272
|
+
sourcePlatform: string;
|
|
273
|
+
targetPlatform: string;
|
|
274
|
+
schemaVersion: number;
|
|
275
|
+
missingSections: SectionId[];
|
|
276
|
+
}
|
|
277
|
+
export type CompatibilityScore = 'excellent' | 'good' | 'partial' | 'unsupported';
|
|
278
|
+
export interface ExportReport {
|
|
279
|
+
included: {
|
|
280
|
+
section: SectionId;
|
|
281
|
+
counts: Record<string, number>;
|
|
282
|
+
}[];
|
|
283
|
+
excluded: SectionId[];
|
|
284
|
+
security: {
|
|
285
|
+
secretsExcluded: boolean;
|
|
286
|
+
containsSecrets: boolean;
|
|
287
|
+
encrypted: boolean;
|
|
288
|
+
redactedHits: number;
|
|
289
|
+
};
|
|
290
|
+
file: {
|
|
291
|
+
name: string;
|
|
292
|
+
sizeBytes: number;
|
|
293
|
+
};
|
|
294
|
+
warnings: string[];
|
|
295
|
+
}
|
|
296
|
+
export type Portability = 'portable' | 'deviceSpecific' | 'platformSpecific';
|
|
297
|
+
export interface ConfigAdapter<TSection = unknown> {
|
|
298
|
+
readonly id: SectionId;
|
|
299
|
+
readonly displayName: string;
|
|
300
|
+
readonly defaultIncluded: boolean;
|
|
301
|
+
readonly portability: Portability;
|
|
302
|
+
/** 读取当前 DSH 该类别配置 → 导出数据(无秘密值) */
|
|
303
|
+
export(ctx: HostContext, options: ExportOptions): Promise<ExportSection<TSection>>;
|
|
304
|
+
/** 分析导入数据与目标 DSH 的差异 → 计划项(纯计算,零写入) */
|
|
305
|
+
analyzeImport(data: TSection, ctx: ImportContext): Promise<PlanItem[]>;
|
|
306
|
+
/** 执行单个计划项(Importer 引擎按阶段调度) */
|
|
307
|
+
applyItem(item: PlanItem, ctx: ImportContext): Promise<ApplyResult>;
|
|
308
|
+
/** 结构校验 */
|
|
309
|
+
validate(data: TSection): Promise<ValidationResult>;
|
|
310
|
+
/** 可选:导入前快照(缺省用引擎通用快照) */
|
|
311
|
+
snapshot?(targets: SnapshotTarget[], ctx: HostContext): Promise<SnapshotEntry[]>;
|
|
312
|
+
/** 可选:针对本 adapter 的补偿动作 */
|
|
313
|
+
rollback?(entries: SnapshotEntry[], ctx: HostContext): Promise<void>;
|
|
314
|
+
}
|
|
315
|
+
export interface EncryptionProvider {
|
|
316
|
+
encrypt(plaintext: string): Promise<{
|
|
317
|
+
blob: Uint8Array;
|
|
318
|
+
info: EncryptionInfo;
|
|
319
|
+
}>;
|
|
320
|
+
/** authTag 校验失败必须抛错 */
|
|
321
|
+
decrypt(blob: Uint8Array, info: EncryptionInfo, password: string): Promise<string>;
|
|
322
|
+
}
|
|
323
|
+
/** 导入被确认前拒绝执行(安全阀) */
|
|
324
|
+
export declare class ImportNotConfirmedError extends Error {
|
|
325
|
+
constructor();
|
|
326
|
+
}
|
|
327
|
+
/** 导入失败:触发回滚后抛出,携带结果供 UI 展示 */
|
|
328
|
+
export declare class ImportFailedError extends Error {
|
|
329
|
+
readonly result: ImportResult;
|
|
330
|
+
constructor(message: string, result: ImportResult);
|
|
331
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/* ---------------- 错误类型 ---------------- */
|
|
2
|
+
/** 导入被确认前拒绝执行(安全阀) */
|
|
3
|
+
export class ImportNotConfirmedError extends Error {
|
|
4
|
+
constructor() {
|
|
5
|
+
super('导入未确认:必须显式 confirm 后才允许修改任何数据');
|
|
6
|
+
this.name = 'ImportNotConfirmedError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/** 导入失败:触发回滚后抛出,携带结果供 UI 展示 */
|
|
10
|
+
export class ImportFailedError extends Error {
|
|
11
|
+
result;
|
|
12
|
+
constructor(message, result) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = 'ImportFailedError';
|
|
15
|
+
this.result = result;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAoUA,4CAA4C;AAE5C,sBAAsB;AACtB,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAChD;QACE,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAED,+BAA+B;AAC/B,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,MAAM,CAAe;IAC9B,YAAY,OAAe,EAAE,MAAoB;QAC/C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SectionId } from '../schema/types.ts';
|
|
2
|
+
import type { CompatibilityInput, CompatibilityScore, ValidationResult } from './types.ts';
|
|
3
|
+
export { validateManifest } from '../schema/manifest.ts';
|
|
4
|
+
export { validateSectionData } from '../schema/config.ts';
|
|
5
|
+
/** 校验 ZIP 内分区数据集合(空对象=合法);返回合并的校验结果 */
|
|
6
|
+
export declare function validateSections(sections: ReadonlyMap<SectionId, unknown>): ValidationResult;
|
|
7
|
+
/**
|
|
8
|
+
* 兼容性评分(规则驱动,不凭感觉):
|
|
9
|
+
* unsupported — schema 超出本插件支持范围(过高/过低)
|
|
10
|
+
* partial — 跨平台、分区缺失、或备份 DSH 比目标新
|
|
11
|
+
* good — 备份 DSH 比目标旧(向后兼容)且其余正常
|
|
12
|
+
* excellent — 同平台、无缺失、schema 支持
|
|
13
|
+
*/
|
|
14
|
+
export declare function computeCompatibility(input: CompatibilityInput): CompatibilityScore;
|
|
15
|
+
/** 兼容性得分的可读描述(UI 报告用) */
|
|
16
|
+
export declare function describeCompatibility(score: CompatibilityScore): string;
|
|
17
|
+
/** 用 describeVersion 生成 schema 状态的用户可读说明 */
|
|
18
|
+
export declare function describeSchemaStatus(schemaVersion: number): string;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 整体校验与兼容性评分(规范 §18 完整性 / §30 兼容性评分 / 导入后校验)。
|
|
3
|
+
*/
|
|
4
|
+
import { validateManifest } from "../schema/manifest.js";
|
|
5
|
+
import { validateSectionData } from "../schema/config.js";
|
|
6
|
+
import { canImport, describeVersion } from "../schema/versions.js";
|
|
7
|
+
export { validateManifest } from "../schema/manifest.js";
|
|
8
|
+
export { validateSectionData } from "../schema/config.js";
|
|
9
|
+
/** 校验 ZIP 内分区数据集合(空对象=合法);返回合并的校验结果 */
|
|
10
|
+
export function validateSections(sections) {
|
|
11
|
+
const issues = [];
|
|
12
|
+
for (const [sectionId, data] of sections) {
|
|
13
|
+
const sectionIssues = validateSectionData(sectionId, data);
|
|
14
|
+
for (const issue of sectionIssues) {
|
|
15
|
+
issues.push({ ...issue, path: `${sectionId}:${issue.path}` });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return { valid: issues.every((i) => i.severity !== 'error'), issues };
|
|
19
|
+
}
|
|
20
|
+
function parseVersion(v) {
|
|
21
|
+
const m = /^(\d+)\.(\d+)(?:\.(\d+))?(?:-(?:rc\.?)?(\d+))?/i.exec(v);
|
|
22
|
+
if (!m)
|
|
23
|
+
return { major: 0, minor: 0, patch: 0, pre: 0 };
|
|
24
|
+
return { major: Number(m[1]), minor: Number(m[2]), patch: Number(m[3] ?? 0), pre: Number(m[4] ?? Infinity) };
|
|
25
|
+
}
|
|
26
|
+
/** 版本比较:-1=a<b,0=相等,1=a>b(预发布 < 正式版) */
|
|
27
|
+
function compareVersions(a, b) {
|
|
28
|
+
for (const k of ['major', 'minor', 'patch']) {
|
|
29
|
+
if (a[k] !== b[k])
|
|
30
|
+
return a[k] < b[k] ? -1 : 1;
|
|
31
|
+
}
|
|
32
|
+
if (a.pre !== b.pre)
|
|
33
|
+
return a.pre < b.pre ? -1 : 1;
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 兼容性评分(规则驱动,不凭感觉):
|
|
38
|
+
* unsupported — schema 超出本插件支持范围(过高/过低)
|
|
39
|
+
* partial — 跨平台、分区缺失、或备份 DSH 比目标新
|
|
40
|
+
* good — 备份 DSH 比目标旧(向后兼容)且其余正常
|
|
41
|
+
* excellent — 同平台、无缺失、schema 支持
|
|
42
|
+
*/
|
|
43
|
+
export function computeCompatibility(input) {
|
|
44
|
+
if (!canImport(input.schemaVersion))
|
|
45
|
+
return 'unsupported';
|
|
46
|
+
let score = 'excellent';
|
|
47
|
+
if (input.sourcePlatform !== input.targetPlatform)
|
|
48
|
+
score = 'partial';
|
|
49
|
+
if (input.missingSections.length > 0)
|
|
50
|
+
score = 'partial';
|
|
51
|
+
const src = parseVersion(input.sourceDsh);
|
|
52
|
+
const tgt = parseVersion(input.targetDsh);
|
|
53
|
+
const cmp = compareVersions(src, tgt);
|
|
54
|
+
if (cmp > 0) {
|
|
55
|
+
// 备份来自更新的 DSH → 可能有目标版本不认识的配置
|
|
56
|
+
score = 'partial';
|
|
57
|
+
}
|
|
58
|
+
else if (cmp < 0) {
|
|
59
|
+
// 备份来自更旧的 DSH → 目标向后兼容
|
|
60
|
+
score = 'good';
|
|
61
|
+
}
|
|
62
|
+
return score;
|
|
63
|
+
}
|
|
64
|
+
/** 兼容性得分的可读描述(UI 报告用) */
|
|
65
|
+
export function describeCompatibility(score) {
|
|
66
|
+
switch (score) {
|
|
67
|
+
case 'excellent': return 'Excellent — 完美兼容(同平台、无缺失、schema 支持)';
|
|
68
|
+
case 'good': return 'Good — 兼容(旧版备份导入新版 DSH)';
|
|
69
|
+
case 'partial': return 'Partial — 部分兼容(跨平台/分区缺失/版本超前,需人工确认)';
|
|
70
|
+
case 'unsupported': return 'Unsupported — 不受支持(schema 超出范围)';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** 用 describeVersion 生成 schema 状态的用户可读说明 */
|
|
74
|
+
export function describeSchemaStatus(schemaVersion) {
|
|
75
|
+
return describeVersion(schemaVersion);
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/core/validator.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-config-manager — host half.
|
|
3
|
+
*
|
|
4
|
+
* Mounts the backup / export / import engine (src/core Exporter + Importer
|
|
5
|
+
* three-stage flow) behind the `/api/dsh-config-manager/*` route family that
|
|
6
|
+
* the browser half (`./client`) calls, and wraps the real DSH host services
|
|
7
|
+
* into the engine's `HostContext` facade (src/core/types.ts):
|
|
8
|
+
*
|
|
9
|
+
* ctx.settings -> SettingsFacade (@deepseek-ai/dsh-settings)
|
|
10
|
+
* ctx.credentials -> CredentialsFacade (@deepseek-ai/dsh-credentials)
|
|
11
|
+
* ctx.pluginInventory + -> PluginsFacade (@deepseek-ai/dsh-host-plugin-inventory
|
|
12
|
+
* ctx.pluginMarketplace + @deepseek-ai/dsh-plugin-marketplace, web)
|
|
13
|
+
* ctx.workspaceRegistry -> WorkspaceFacade (@deepseek-ai/dsh-workspace)
|
|
14
|
+
* ~/.dsh/cordis.patch.yml-> PatchFileFacade (js-yaml)
|
|
15
|
+
* $DSH_HOME files -> FileSystemFacade (node:fs, home-relative)
|
|
16
|
+
* resolveDshHome() -> homeDir (@deepseek-ai/dsh-home-paths)
|
|
17
|
+
*
|
|
18
|
+
* Security posture (mirrors the verified @linxin666/dsh-ssh@0.1.12 routes):
|
|
19
|
+
* - every route carries the loopback-only + same-origin trust fence
|
|
20
|
+
* (isLoopbackRequest); LAN-exposed deployments never serve these endpoints;
|
|
21
|
+
* - uploads/exported ZIPs are staged under $DSH_HOME/dsh-config-manager/{tmp,exports}
|
|
22
|
+
* and every `path`/`zipPath` reference is confined to those roots;
|
|
23
|
+
* - the encryption password is in-memory only: used to derive the AES-256-GCM
|
|
24
|
+
* key for secrets.enc, never written to any file, manifest, or log;
|
|
25
|
+
* - the import execute endpoint refuses to run without `confirm: true`
|
|
26
|
+
* (core ImportNotConfirmedError safety valve).
|
|
27
|
+
*
|
|
28
|
+
* Optional services are read with ctx.get() at call time (never injected), so
|
|
29
|
+
* the engine keeps working in profiles without the web-only marketplace or
|
|
30
|
+
* workspace services; hard dependencies are the core `settings`/`credentials`
|
|
31
|
+
* services present in every profile.
|
|
32
|
+
*/
|
|
33
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
34
|
+
/** Stable cordis plugin name — must match the cordis.patch.yml row id. */
|
|
35
|
+
export declare const name = "config-manager";
|
|
36
|
+
/** Services required before the engine can mount (present in every profile). */
|
|
37
|
+
export declare const inject: string[];
|
|
38
|
+
/** Plugin config (composition entry); the loader applies it as-is. */
|
|
39
|
+
export interface Config {
|
|
40
|
+
/** Master switch; defaults to true. */
|
|
41
|
+
enabled?: boolean;
|
|
42
|
+
/** Data root override; defaults to $DSH_HOME/dsh-config-manager. */
|
|
43
|
+
dataDir?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Mount the config-manager engine: host context, adapters, and the
|
|
47
|
+
* /api/dsh-config-manager routes (when a webServer is present).
|
|
48
|
+
* @param ctx - host plugin context carrying settings/credentials/webServer.
|
|
49
|
+
* @param config - resolved plugin config.
|
|
50
|
+
*/
|
|
51
|
+
export declare function apply(ctx: Context, config?: Config): void;
|