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,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 报告渲染(规范 §21 导出报告 / §22 导入报告 / §17 回滚报告,m6-ui)。
|
|
3
|
+
*
|
|
4
|
+
* 纯文本渲染:输出用户可读的多行文本(未来 React 客户端可直接替换为组件渲染)。
|
|
5
|
+
* 导入报告按分区统计:从 ExecutedItem.itemId 前缀推断所属分区(与 adapters 的 id 规则一致)。
|
|
6
|
+
*/
|
|
7
|
+
import type { SectionId } from '../schema/types.ts';
|
|
8
|
+
import type { ExecutedItem, ExportReport, ImportResult, RollbackReport } from '../core/types.ts';
|
|
9
|
+
import type { ImportResultAction, ImportSectionStat } from './types.ts';
|
|
10
|
+
export declare function renderExportReport(report: ExportReport): string;
|
|
11
|
+
/** 从 itemId 前缀推断所属分区(与 adapters id 规则对齐;未知归 'other') */
|
|
12
|
+
export declare function sectionFromItemId(itemId: string): SectionId | 'other';
|
|
13
|
+
/** 按分区聚合执行结果(统计 + 明细) */
|
|
14
|
+
export declare function importSectionStats(executed: readonly ExecutedItem[]): ImportSectionStat[];
|
|
15
|
+
/** 导入报告渲染(含回滚状态;§22 动作按钮由 suggestedActions 给出) */
|
|
16
|
+
export declare function renderImportReport(result: ImportResult): string;
|
|
17
|
+
/** 结果页动作按钮(§22:Fix Issues / View Details / Done) */
|
|
18
|
+
export declare function suggestedActions(result: ImportResult): ImportResultAction[];
|
|
19
|
+
/** 回滚报告渲染(full / partial + 人工恢复清单) */
|
|
20
|
+
export declare function renderRollbackReport(rr: RollbackReport): string;
|
|
21
|
+
export declare function formatBytes(n: number): string;
|
package/lib/ui/report.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/* ---------------- §21 导出报告 ---------------- */
|
|
2
|
+
export function renderExportReport(report) {
|
|
3
|
+
const lines = ['Backup Created', ''];
|
|
4
|
+
lines.push('Included:');
|
|
5
|
+
for (const { section, counts } of report.included) {
|
|
6
|
+
const detail = Object.entries(counts)
|
|
7
|
+
.map(([k, v]) => `${v} ${k}`)
|
|
8
|
+
.join(', ');
|
|
9
|
+
lines.push(` ✓ ${section}${detail !== '' ? ` (${detail})` : ''}`);
|
|
10
|
+
}
|
|
11
|
+
lines.push('');
|
|
12
|
+
if (report.excluded.length > 0) {
|
|
13
|
+
lines.push('Excluded:');
|
|
14
|
+
for (const s of report.excluded)
|
|
15
|
+
lines.push(` ○ ${s}`);
|
|
16
|
+
lines.push('');
|
|
17
|
+
}
|
|
18
|
+
lines.push('Security:');
|
|
19
|
+
lines.push(` ✓ API Keys excluded: ${report.security.secretsExcluded ? 'yes' : 'no'}`);
|
|
20
|
+
lines.push(` ✓ Contains secrets: ${report.security.containsSecrets ? 'yes (encrypted)' : 'no'}`);
|
|
21
|
+
lines.push(` ✓ Encrypted: ${report.security.encrypted ? 'yes' : 'no'}`);
|
|
22
|
+
if (report.security.redactedHits > 0)
|
|
23
|
+
lines.push(` ⚠ ${report.security.redactedHits} sensitive field(s) redacted`);
|
|
24
|
+
lines.push('');
|
|
25
|
+
lines.push(`File: ${report.file.name} (${formatBytes(report.file.sizeBytes)})`);
|
|
26
|
+
for (const w of report.warnings)
|
|
27
|
+
lines.push(` ⚠ ${w}`);
|
|
28
|
+
return lines.join('\n');
|
|
29
|
+
}
|
|
30
|
+
/* ---------------- §22 导入报告 ---------------- */
|
|
31
|
+
/** 从 itemId 前缀推断所属分区(与 adapters id 规则对齐;未知归 'other') */
|
|
32
|
+
export function sectionFromItemId(itemId) {
|
|
33
|
+
if (itemId.startsWith('settings:'))
|
|
34
|
+
return 'settings';
|
|
35
|
+
if (itemId.startsWith('ui:'))
|
|
36
|
+
return 'ui';
|
|
37
|
+
if (itemId.startsWith('provider:'))
|
|
38
|
+
return 'providers';
|
|
39
|
+
if (itemId.startsWith('plugin:') || itemId.startsWith('patch:'))
|
|
40
|
+
return 'plugins';
|
|
41
|
+
if (itemId.startsWith('mcp:'))
|
|
42
|
+
return 'mcp';
|
|
43
|
+
if (itemId.startsWith('prompt:'))
|
|
44
|
+
return 'prompts';
|
|
45
|
+
if (itemId.startsWith('workspace:'))
|
|
46
|
+
return 'workspaces';
|
|
47
|
+
if (itemId.startsWith('secret:'))
|
|
48
|
+
return 'credentialsStatus';
|
|
49
|
+
if (itemId.startsWith('skills:'))
|
|
50
|
+
return 'skills';
|
|
51
|
+
if (itemId.startsWith('agentPresets:'))
|
|
52
|
+
return 'agentPresets';
|
|
53
|
+
if (itemId.startsWith('pluginFiles:'))
|
|
54
|
+
return 'pluginFiles';
|
|
55
|
+
if (itemId.startsWith('sessions:'))
|
|
56
|
+
return 'sessions';
|
|
57
|
+
return 'other';
|
|
58
|
+
}
|
|
59
|
+
/** 按分区聚合执行结果(统计 + 明细) */
|
|
60
|
+
export function importSectionStats(executed) {
|
|
61
|
+
const bySection = new Map();
|
|
62
|
+
for (const e of executed) {
|
|
63
|
+
const section = sectionFromItemId(e.itemId);
|
|
64
|
+
let stat = bySection.get(section);
|
|
65
|
+
if (!stat) {
|
|
66
|
+
stat = { section: section, ok: 0, skipped: 0, failed: 0, items: [] };
|
|
67
|
+
bySection.set(section, stat);
|
|
68
|
+
}
|
|
69
|
+
if (e.status === 'ok')
|
|
70
|
+
stat.ok += 1;
|
|
71
|
+
else if (e.status === 'skipped')
|
|
72
|
+
stat.skipped += 1;
|
|
73
|
+
else
|
|
74
|
+
stat.failed += 1;
|
|
75
|
+
stat.items.push(e);
|
|
76
|
+
}
|
|
77
|
+
return [...bySection.values()];
|
|
78
|
+
}
|
|
79
|
+
/** 导入报告渲染(含回滚状态;§22 动作按钮由 suggestedActions 给出) */
|
|
80
|
+
export function renderImportReport(result) {
|
|
81
|
+
const lines = [result.ok ? 'Import Complete' : 'Import Failed', ''];
|
|
82
|
+
const stats = importSectionStats(result.executed);
|
|
83
|
+
for (const s of stats) {
|
|
84
|
+
const parts = [];
|
|
85
|
+
if (s.ok > 0)
|
|
86
|
+
parts.push(`✓ ${s.ok} imported/restored`);
|
|
87
|
+
if (s.skipped > 0)
|
|
88
|
+
parts.push(`- ${s.skipped} skipped`);
|
|
89
|
+
if (s.failed > 0)
|
|
90
|
+
parts.push(`✗ ${s.failed} failed`);
|
|
91
|
+
lines.push(`${s.section}: ${parts.join(' ') || 'no changes'}`);
|
|
92
|
+
// 失败项给出可操作原因(§23)
|
|
93
|
+
for (const it of s.items) {
|
|
94
|
+
if (it.status === 'failed') {
|
|
95
|
+
lines.push(` Reason: ${it.message ?? '未知原因'}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (result.missingSecrets.length > 0) {
|
|
100
|
+
lines.push(`Secrets: ⚠ ${result.missingSecrets.length} credentials need to be entered`);
|
|
101
|
+
}
|
|
102
|
+
if (result.needsRestart) {
|
|
103
|
+
lines.push('Restart required: 插件/MCP 变更将在重启 DSH 后生效');
|
|
104
|
+
}
|
|
105
|
+
for (const w of result.warnings)
|
|
106
|
+
lines.push(`⚠ ${w}`);
|
|
107
|
+
if (result.rollback) {
|
|
108
|
+
lines.push('');
|
|
109
|
+
lines.push(renderRollbackReport(result.rollback));
|
|
110
|
+
}
|
|
111
|
+
return lines.join('\n');
|
|
112
|
+
}
|
|
113
|
+
/** 结果页动作按钮(§22:Fix Issues / View Details / Done) */
|
|
114
|
+
export function suggestedActions(result) {
|
|
115
|
+
const actions = [];
|
|
116
|
+
if (result.executed.some((e) => e.status === 'failed'))
|
|
117
|
+
actions.push('fixIssues');
|
|
118
|
+
if (result.executed.length > 0 || result.warnings.length > 0)
|
|
119
|
+
actions.push('viewDetails');
|
|
120
|
+
actions.push('done');
|
|
121
|
+
return actions;
|
|
122
|
+
}
|
|
123
|
+
/* ---------------- §17 回滚报告 ---------------- */
|
|
124
|
+
/** 回滚报告渲染(full / partial + 人工恢复清单) */
|
|
125
|
+
export function renderRollbackReport(rr) {
|
|
126
|
+
if (rr.full) {
|
|
127
|
+
return 'Rollback: 已完整恢复导入前的配置。';
|
|
128
|
+
}
|
|
129
|
+
const lines = ['Rollback partially completed.'];
|
|
130
|
+
lines.push('These items may require manual recovery:');
|
|
131
|
+
for (const f of rr.failed) {
|
|
132
|
+
lines.push(` - ${f.item}: ${f.reason}${f.manualHint ? ` (${f.manualHint})` : ''}`);
|
|
133
|
+
}
|
|
134
|
+
if (rr.restored.length > 0)
|
|
135
|
+
lines.push(`Restored: ${rr.restored.length} item(s)`);
|
|
136
|
+
return lines.join('\n');
|
|
137
|
+
}
|
|
138
|
+
/* ---------------- 工具 ---------------- */
|
|
139
|
+
export function formatBytes(n) {
|
|
140
|
+
if (n < 1024)
|
|
141
|
+
return `${n} B`;
|
|
142
|
+
if (n < 1024 * 1024)
|
|
143
|
+
return `${(n / 1024).toFixed(1)} KB`;
|
|
144
|
+
return `${(n / (1024 * 1024)).toFixed(1)} MB`;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/ui/report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI 层测试辅助(m6-ui):mock core 调用与样本数据。
|
|
3
|
+
* 仅供 src/ui/*.test.ts 使用,不参与生产构建语义。
|
|
4
|
+
*/
|
|
5
|
+
import type { Manifest } from '../schema/types.ts';
|
|
6
|
+
import type { ExportReport, ImportAnalysis, ImportDecisions, ImportPlan, ImportResult, PlanItem, RollbackReport } from '../core/types.ts';
|
|
7
|
+
import type { ExportPort } from './export-flow.ts';
|
|
8
|
+
import type { ImportPort } from './types.ts';
|
|
9
|
+
/** 样本 manifest(UI 测试不关心真实字段,仅类型占位) */
|
|
10
|
+
export declare function makeManifest(): Manifest;
|
|
11
|
+
export declare function makeExportReport(overrides?: Partial<ExportReport>): ExportReport;
|
|
12
|
+
/** 内存 ExportPort mock:记录调用参数,返回固定结果 */
|
|
13
|
+
export declare class MockExportPort implements ExportPort {
|
|
14
|
+
calls: {
|
|
15
|
+
includeSecrets: boolean;
|
|
16
|
+
only?: string[];
|
|
17
|
+
}[];
|
|
18
|
+
result: {
|
|
19
|
+
zipPath: string;
|
|
20
|
+
manifest: Manifest;
|
|
21
|
+
report: ExportReport;
|
|
22
|
+
};
|
|
23
|
+
constructor(report?: ExportReport);
|
|
24
|
+
export(opts: {
|
|
25
|
+
includeSecrets: boolean;
|
|
26
|
+
only?: string[];
|
|
27
|
+
}): Promise<{
|
|
28
|
+
zipPath: string;
|
|
29
|
+
manifest: Manifest;
|
|
30
|
+
report: ExportReport;
|
|
31
|
+
}>;
|
|
32
|
+
}
|
|
33
|
+
export declare function makeAnalysis(overrides?: Partial<ImportAnalysis>): ImportAnalysis;
|
|
34
|
+
export declare function makePlanItem(overrides?: Partial<PlanItem>): PlanItem;
|
|
35
|
+
export declare function makePlan(overrides?: Partial<ImportPlan>): ImportPlan;
|
|
36
|
+
export declare function makeRollbackReport(overrides?: Partial<RollbackReport>): RollbackReport;
|
|
37
|
+
export declare function makeImportResult(overrides?: Partial<ImportResult>): ImportResult;
|
|
38
|
+
/** 内存 ImportPort mock:可编排各阶段返回与调用记录 */
|
|
39
|
+
export declare class MockImportPort implements ImportPort {
|
|
40
|
+
analysis: ImportAnalysis;
|
|
41
|
+
plan: ImportPlan;
|
|
42
|
+
result: ImportResult;
|
|
43
|
+
analyzeCalls: number;
|
|
44
|
+
planCalls: ImportDecisions[];
|
|
45
|
+
executeCalls: {
|
|
46
|
+
confirm: boolean;
|
|
47
|
+
secretInputs?: Record<string, string>;
|
|
48
|
+
rollbackOnError: boolean;
|
|
49
|
+
}[];
|
|
50
|
+
constructor(opts?: {
|
|
51
|
+
analysis?: ImportAnalysis;
|
|
52
|
+
plan?: ImportPlan;
|
|
53
|
+
result?: ImportResult;
|
|
54
|
+
});
|
|
55
|
+
analyzeImport(): Promise<ImportAnalysis>;
|
|
56
|
+
createImportPlan(_zip: string, decisions: ImportDecisions): Promise<ImportPlan>;
|
|
57
|
+
executeImportPlan(_zip: string, _plan: ImportPlan, opts: {
|
|
58
|
+
confirm: boolean;
|
|
59
|
+
secretInputs?: Record<string, string>;
|
|
60
|
+
rollbackOnError: boolean;
|
|
61
|
+
}): Promise<ImportResult>;
|
|
62
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/** 样本 manifest(UI 测试不关心真实字段,仅类型占位) */
|
|
2
|
+
export function makeManifest() {
|
|
3
|
+
return {
|
|
4
|
+
schemaVersion: 1,
|
|
5
|
+
exporter: { name: 'dsh-config-manager-test', version: '0.0.0' },
|
|
6
|
+
source: { dshVersion: '0.1.0-rc.6', platform: 'win32', arch: 'x64' },
|
|
7
|
+
exportedAt: '2026-08-14T12:00:00.000Z',
|
|
8
|
+
sections: {
|
|
9
|
+
settings: true, ui: false, providers: false, plugins: false, mcp: false, prompts: false,
|
|
10
|
+
skills: false, agentPresets: false, workspaces: false, pluginFiles: false,
|
|
11
|
+
credentialsStatus: false, secrets: false, sessions: false,
|
|
12
|
+
},
|
|
13
|
+
security: { containsSecrets: false, encrypted: false, encryption: null },
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export function makeExportReport(overrides = {}) {
|
|
17
|
+
return {
|
|
18
|
+
included: [
|
|
19
|
+
{ section: 'settings', counts: { namespaces: 3 } },
|
|
20
|
+
{ section: 'plugins', counts: { plugins: 8 } },
|
|
21
|
+
],
|
|
22
|
+
excluded: ['sessions', 'pluginFiles'],
|
|
23
|
+
security: { secretsExcluded: true, containsSecrets: false, encrypted: false, redactedHits: 2 },
|
|
24
|
+
file: { name: 'dsh-config-2026-08-14.zip', sizeBytes: 20480 },
|
|
25
|
+
warnings: [],
|
|
26
|
+
...overrides,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** 内存 ExportPort mock:记录调用参数,返回固定结果 */
|
|
30
|
+
export class MockExportPort {
|
|
31
|
+
calls = [];
|
|
32
|
+
result;
|
|
33
|
+
constructor(report = makeExportReport()) {
|
|
34
|
+
this.result = {
|
|
35
|
+
zipPath: report.file.name,
|
|
36
|
+
manifest: makeManifest(),
|
|
37
|
+
report,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async export(opts) {
|
|
41
|
+
this.calls.push({ includeSecrets: opts.includeSecrets, only: opts.only });
|
|
42
|
+
return this.result;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/* ---------------- Import mock ---------------- */
|
|
46
|
+
export function makeAnalysis(overrides = {}) {
|
|
47
|
+
return {
|
|
48
|
+
valid: true,
|
|
49
|
+
errors: [],
|
|
50
|
+
warnings: [],
|
|
51
|
+
compatibility: 'good',
|
|
52
|
+
sectionsInZip: ['settings', 'plugins', 'mcp', 'prompts'],
|
|
53
|
+
pluginSummary: { installed: 6, toInstall: 2 },
|
|
54
|
+
pathIssues: [],
|
|
55
|
+
secretCount: 3,
|
|
56
|
+
dependencyIssues: [],
|
|
57
|
+
...overrides,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function makePlanItem(overrides = {}) {
|
|
61
|
+
return {
|
|
62
|
+
id: 'settings:general',
|
|
63
|
+
kind: 'Create',
|
|
64
|
+
adapter: 'settings',
|
|
65
|
+
description: '创建设置 general',
|
|
66
|
+
severity: 'info',
|
|
67
|
+
...overrides,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export function makePlan(overrides = {}) {
|
|
71
|
+
return {
|
|
72
|
+
items: [
|
|
73
|
+
makePlanItem({ id: 'settings:a', kind: 'Update', description: '更新设置 a' }),
|
|
74
|
+
makePlanItem({ id: 'settings:b', kind: 'Create', description: '创建设置 b' }),
|
|
75
|
+
makePlanItem({ id: 'plugin:x', kind: 'Install', adapter: 'plugins', description: '安装插件 x' }),
|
|
76
|
+
makePlanItem({ id: 'plugin:y', kind: 'Skip', adapter: 'plugins', description: '插件 y 已一致' }),
|
|
77
|
+
makePlanItem({ id: 'prompt:p', kind: 'Create', adapter: 'prompts', description: '创建提示 p' }),
|
|
78
|
+
makePlanItem({ id: 'mcp:m', kind: 'Create', adapter: 'mcp', description: '创建 MCP m' }),
|
|
79
|
+
makePlanItem({ id: 'secret:K1', kind: 'MissingSecret', adapter: 'credentialsStatus', description: '凭据 K1 需要补录' }),
|
|
80
|
+
],
|
|
81
|
+
globalStrategy: 'merge',
|
|
82
|
+
pathMappings: [],
|
|
83
|
+
missingSecrets: [{ ref: 'K1', required: true }],
|
|
84
|
+
needsRestart: true,
|
|
85
|
+
estimatedActions: {
|
|
86
|
+
settings: 2, ui: 0, providers: 0, plugins: 1, mcp: 1, prompts: 1,
|
|
87
|
+
skills: 0, agentPresets: 0, workspaces: 0, pluginFiles: 0,
|
|
88
|
+
credentialsStatus: 0, secrets: 0, sessions: 0,
|
|
89
|
+
},
|
|
90
|
+
...overrides,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export function makeRollbackReport(overrides = {}) {
|
|
94
|
+
return {
|
|
95
|
+
full: false,
|
|
96
|
+
restored: ['settings:a'],
|
|
97
|
+
failed: [{ item: 'plugin:x', reason: '安装失败', manualHint: '请手动安装' }],
|
|
98
|
+
...overrides,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
export function makeImportResult(overrides = {}) {
|
|
102
|
+
return {
|
|
103
|
+
ok: true,
|
|
104
|
+
executed: [
|
|
105
|
+
{ itemId: 'settings:a', status: 'ok' },
|
|
106
|
+
{ itemId: 'settings:b', status: 'ok' },
|
|
107
|
+
{ itemId: 'plugin:x', status: 'ok', message: '需要重启生效' },
|
|
108
|
+
{ itemId: 'plugin:y', status: 'skipped' },
|
|
109
|
+
{ itemId: 'prompt:p', status: 'ok' },
|
|
110
|
+
{ itemId: 'mcp:m', status: 'ok' },
|
|
111
|
+
{ itemId: 'secret:K1', status: 'skipped', message: '凭据未提供' },
|
|
112
|
+
],
|
|
113
|
+
needsRestart: true,
|
|
114
|
+
missingSecrets: ['K1'],
|
|
115
|
+
warnings: [],
|
|
116
|
+
rollback: null,
|
|
117
|
+
snapshotId: 'snap-1',
|
|
118
|
+
...overrides,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/** 内存 ImportPort mock:可编排各阶段返回与调用记录 */
|
|
122
|
+
export class MockImportPort {
|
|
123
|
+
analysis;
|
|
124
|
+
plan;
|
|
125
|
+
result;
|
|
126
|
+
analyzeCalls = 0;
|
|
127
|
+
planCalls = [];
|
|
128
|
+
executeCalls = [];
|
|
129
|
+
constructor(opts = {}) {
|
|
130
|
+
this.analysis = opts.analysis ?? makeAnalysis();
|
|
131
|
+
this.plan = opts.plan ?? makePlan();
|
|
132
|
+
this.result = opts.result ?? makeImportResult();
|
|
133
|
+
}
|
|
134
|
+
async analyzeImport() {
|
|
135
|
+
this.analyzeCalls += 1;
|
|
136
|
+
return this.analysis;
|
|
137
|
+
}
|
|
138
|
+
async createImportPlan(_zip, decisions) {
|
|
139
|
+
this.planCalls.push(decisions);
|
|
140
|
+
return this.plan;
|
|
141
|
+
}
|
|
142
|
+
async executeImportPlan(_zip, _plan, opts) {
|
|
143
|
+
this.executeCalls.push(opts);
|
|
144
|
+
return this.result;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=test-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-helpers.js","sourceRoot":"","sources":["../../src/ui/test-helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI 层共享类型(m6-ui,框架无关)。
|
|
3
|
+
*
|
|
4
|
+
* 设计原则(对齐 Docs/design/architecture.md §12.2 与规范 §28/§29):
|
|
5
|
+
* - 本模块为纯 TypeScript 逻辑层,不引入 React / 打包器 / 任何运行时依赖;
|
|
6
|
+
* - 未来 React 客户端(src/client/)直接消费本层的控制器输出(渲染文本 / 状态快照);
|
|
7
|
+
* - UI 层不直接 import core 的类实现,只依赖 core/types.ts 的纯类型 + 注入的「端口」
|
|
8
|
+
* (ExportPort / ImportPort,宿主在 settings.section 挂载时把真实 Exporter/Importer 接入)。
|
|
9
|
+
*/
|
|
10
|
+
import type { SectionId } from '../schema/types.ts';
|
|
11
|
+
import type { CompatibilityScore, ImportAnalysis, ImportDecisions, ImportPlan, ImportResult, ItemResolution, PathIssue, PlanItem, Portability, RollbackReport } from '../core/types.ts';
|
|
12
|
+
export type ExportMode = 'quick' | 'custom';
|
|
13
|
+
/** Custom Export 分组(规范 §1 分类;automation 组在 DSH 中无对应分区,UI 标注说明) */
|
|
14
|
+
export type ExportGroup = 'general' | 'ai' | 'extensions' | 'mcp' | 'customization' | 'automation' | 'workspace' | 'ui' | 'optional';
|
|
15
|
+
/** 分类树节点(与 adapters 的 displayName/defaultIncluded/portability 对齐;宿主可注入覆盖) */
|
|
16
|
+
export interface ExportCategory {
|
|
17
|
+
id: SectionId;
|
|
18
|
+
label: string;
|
|
19
|
+
description: string;
|
|
20
|
+
defaultIncluded: boolean;
|
|
21
|
+
portability: Portability;
|
|
22
|
+
group: ExportGroup;
|
|
23
|
+
/** 涉及秘密状态(如 credentialsStatus):UI 需展示安全提示但绝不显示值 */
|
|
24
|
+
sensitive?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface ExportGroupDef {
|
|
27
|
+
id: ExportGroup;
|
|
28
|
+
label: string;
|
|
29
|
+
/** automation 组在 DSH 无对应配置时的说明 */
|
|
30
|
+
note?: string;
|
|
31
|
+
}
|
|
32
|
+
/** Custom Export 分组目录(规范 §1;automation 组 DSH 无对应分区,仅说明) */
|
|
33
|
+
export declare const EXPORT_GROUPS: readonly ExportGroupDef[];
|
|
34
|
+
/** Quick Export 推荐项 = defaultIncluded 且非 deviceSpecific(设计 §11.1) */
|
|
35
|
+
export declare function isQuickRecommended(c: ExportCategory): boolean;
|
|
36
|
+
export interface ProgressEvent {
|
|
37
|
+
/** 阶段 id(见 progress.ts 的 STAGE_TEXTS) */
|
|
38
|
+
stage: string;
|
|
39
|
+
detail?: string;
|
|
40
|
+
/** 阶段序号(从 1 起,供 UI 显示 n/m) */
|
|
41
|
+
step?: number;
|
|
42
|
+
/** 阶段总数 */
|
|
43
|
+
total?: number;
|
|
44
|
+
}
|
|
45
|
+
export type ProgressListener = (event: ProgressEvent) => void;
|
|
46
|
+
export type ImportStep = 'select' | 'analyzing' | 'compatibility' | 'preview' | 'conflicts' | 'path-mapping' | 'secrets' | 'importing' | 'result';
|
|
47
|
+
/** Preview 摘要(规范 §10 示例的数值化版本) */
|
|
48
|
+
export interface ImportPreviewSummary {
|
|
49
|
+
/** 将更新的配置项数(Create+Update+Install 合计) */
|
|
50
|
+
willChange: number;
|
|
51
|
+
/** 已存在且一致的项(Skip) */
|
|
52
|
+
unchanged: number;
|
|
53
|
+
settingsUpdates: number;
|
|
54
|
+
pluginsInstalled: number;
|
|
55
|
+
pluginsToInstall: number;
|
|
56
|
+
mcpAdds: number;
|
|
57
|
+
prompts: number;
|
|
58
|
+
pathMappingsNeeded: number;
|
|
59
|
+
secretsNeeded: number;
|
|
60
|
+
conflicts: number;
|
|
61
|
+
needsRestart: boolean;
|
|
62
|
+
}
|
|
63
|
+
/** 向导状态快照(React 客户端可直接绑定渲染) */
|
|
64
|
+
export interface WizardSnapshot {
|
|
65
|
+
step: ImportStep;
|
|
66
|
+
zipPath: string | null;
|
|
67
|
+
analysis: ImportAnalysis | null;
|
|
68
|
+
plan: ImportPlan | null;
|
|
69
|
+
result: ImportResult | null;
|
|
70
|
+
/** 导入执行的回滚策略(场景 E:默认 true 整体回滚) */
|
|
71
|
+
rollbackOnError: boolean;
|
|
72
|
+
errors: string[];
|
|
73
|
+
}
|
|
74
|
+
/** 单个冲突项的视图数据:当前值 vs 导入值摘要 + 用户决策 */
|
|
75
|
+
export interface ConflictViewItem {
|
|
76
|
+
item: PlanItem;
|
|
77
|
+
currentSummary?: string;
|
|
78
|
+
importedSummary?: string;
|
|
79
|
+
resolution: ItemResolution | null;
|
|
80
|
+
}
|
|
81
|
+
/** 路径映射编辑器的单条记录(旧前缀 → 新前缀;未解析时 newPrefix 为空串) */
|
|
82
|
+
export interface PathMappingDraft {
|
|
83
|
+
/** 关联的原始路径问题值(一条 issue 一条 draft;批量映射用 oldPrefix 聚合) */
|
|
84
|
+
oldPrefix: string;
|
|
85
|
+
newPrefix: string;
|
|
86
|
+
issue?: PathIssue;
|
|
87
|
+
/** 应用范围(缺省 [] = 全部相关分区,与 core applyMappingsToSections 语义一致) */
|
|
88
|
+
appliesTo: PathMappingAppliesTo[];
|
|
89
|
+
}
|
|
90
|
+
/** 与 core PathMapping.appliesTo 对齐的取值(留空数组 = 全应用) */
|
|
91
|
+
export type PathMappingAppliesTo = 'workspaces' | 'mcp' | 'pluginConfig' | 'skills';
|
|
92
|
+
export interface CompatibilityView {
|
|
93
|
+
score: CompatibilityScore;
|
|
94
|
+
sourceDsh: string;
|
|
95
|
+
targetDsh: string;
|
|
96
|
+
description: string;
|
|
97
|
+
}
|
|
98
|
+
/** 导入结果按分区的统计(report.ts 用) */
|
|
99
|
+
export interface ImportSectionStat {
|
|
100
|
+
section: SectionId;
|
|
101
|
+
ok: number;
|
|
102
|
+
skipped: number;
|
|
103
|
+
failed: number;
|
|
104
|
+
items: {
|
|
105
|
+
itemId: string;
|
|
106
|
+
status: 'ok' | 'skipped' | 'failed';
|
|
107
|
+
message?: string;
|
|
108
|
+
}[];
|
|
109
|
+
}
|
|
110
|
+
export type ImportResultAction = 'fixIssues' | 'viewDetails' | 'done';
|
|
111
|
+
export interface RollbackView {
|
|
112
|
+
report: RollbackReport | null;
|
|
113
|
+
/** 是否有可展示的人工恢复清单(partial 回滚时) */
|
|
114
|
+
hasManualRecovery: boolean;
|
|
115
|
+
}
|
|
116
|
+
/** UI 层与 core 的导入端口(宿主注入真实 Importer;测试注入内存 mock) */
|
|
117
|
+
export interface ImportPort {
|
|
118
|
+
analyzeImport(zipPath: string): Promise<ImportAnalysis>;
|
|
119
|
+
createImportPlan(zipPath: string, decisions: ImportDecisions): Promise<ImportPlan>;
|
|
120
|
+
executeImportPlan(zipPath: string, plan: ImportPlan, opts: {
|
|
121
|
+
/** 用户确认(安全阀,非 true 拒绝执行) */
|
|
122
|
+
confirm: boolean;
|
|
123
|
+
secretInputs?: Record<string, string>;
|
|
124
|
+
/** 显式回滚策略:true=任一项失败整体回滚(场景 E);false=单项失败继续(§34.17) */
|
|
125
|
+
rollbackOnError: boolean;
|
|
126
|
+
}): Promise<ImportResult>;
|
|
127
|
+
}
|
|
128
|
+
/** 选项构造辅助:从 PlanItem 提取稳定决策键(与 core analyzer.applyItemResolution 的 id 语义一致) */
|
|
129
|
+
export declare function itemDecisionKey(item: PlanItem): string;
|
package/lib/ui/types.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Custom Export 分组目录(规范 §1;automation 组 DSH 无对应分区,仅说明) */
|
|
2
|
+
export const EXPORT_GROUPS = [
|
|
3
|
+
{ id: 'general', label: 'General' },
|
|
4
|
+
{ id: 'ai', label: 'AI' },
|
|
5
|
+
{ id: 'extensions', label: 'Extensions' },
|
|
6
|
+
{ id: 'mcp', label: 'MCP / Tools' },
|
|
7
|
+
{ id: 'customization', label: 'Customization' },
|
|
8
|
+
{ id: 'automation', label: 'Automation', note: 'DSH 当前无 Workflows / Commands 配置文件(运行时注册),无迁移内容' },
|
|
9
|
+
{ id: 'workspace', label: 'Workspace' },
|
|
10
|
+
{ id: 'ui', label: 'UI' },
|
|
11
|
+
{ id: 'optional', label: 'Optional Data' },
|
|
12
|
+
];
|
|
13
|
+
/** Quick Export 推荐项 = defaultIncluded 且非 deviceSpecific(设计 §11.1) */
|
|
14
|
+
export function isQuickRecommended(c) {
|
|
15
|
+
return c.defaultIncluded && c.portability !== 'deviceSpecific';
|
|
16
|
+
}
|
|
17
|
+
/** 选项构造辅助:从 PlanItem 提取稳定决策键(与 core analyzer.applyItemResolution 的 id 语义一致) */
|
|
18
|
+
export function itemDecisionKey(item) {
|
|
19
|
+
return item.id;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ui/types.ts"],"names":[],"mappings":"AA2CA,2DAA2D;AAC3D,MAAM,CAAC,MAAM,aAAa,GAA8B;IACtD,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;IACnC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE;IACzC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE;IACnC,EAAE,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,eAAe,EAAE;IAC/C,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,gDAAgD,EAAE;IACjG,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE;IACvC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE;IACzB,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,eAAe,EAAE;CAClC,CAAC;AAEX,qEAAqE;AACrE,MAAM,UAAU,kBAAkB,CAAC,CAAiB;IAClD,OAAO,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC,WAAW,KAAK,gBAAgB,CAAC;AACjE,CAAC;AAkID,+EAA+E;AAC/E,MAAM,UAAU,eAAe,CAAC,IAAc;IAC5C,OAAO,IAAI,CAAC,EAAE,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare function sha256Hex(data: Uint8Array | string): string;
|
|
2
|
+
export declare function hashFile(filePath: string): Promise<string>;
|
|
3
|
+
/** 生成一组 ZIP 相对路径 → SHA-256 的校验表(路径必须为 ZIP 内正斜杠相对路径) */
|
|
4
|
+
export declare function buildChecksums(entries: {
|
|
5
|
+
name: string;
|
|
6
|
+
data: Uint8Array;
|
|
7
|
+
}[]): Record<string, string>;
|
|
8
|
+
export interface ChecksumVerifyResult {
|
|
9
|
+
ok: boolean;
|
|
10
|
+
mismatches: string[];
|
|
11
|
+
missing: string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 校验:checksums 表内每个相对路径必须在 entries 中存在且 SHA-256 一致。
|
|
15
|
+
* entries 中多余的文件(如 manifest.json / checksums.json 自身)不参与校验。
|
|
16
|
+
*/
|
|
17
|
+
export declare function verifyChecksums(entries: ReadonlyMap<string, Uint8Array>, checksums: Record<string, string>): ChecksumVerifyResult;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SHA-256 完整性工具(integrity/checksums.json 的生成与校验)。
|
|
3
|
+
* m4 的 security/integrity.ts 可在此之上强化(本模块已实现规范 §18 全部语义)。
|
|
4
|
+
*/
|
|
5
|
+
import crypto from 'node:crypto';
|
|
6
|
+
import fs from 'node:fs/promises';
|
|
7
|
+
export function sha256Hex(data) {
|
|
8
|
+
return crypto.createHash('sha256').update(data).digest('hex');
|
|
9
|
+
}
|
|
10
|
+
export async function hashFile(filePath) {
|
|
11
|
+
const data = await fs.readFile(filePath);
|
|
12
|
+
return sha256Hex(data);
|
|
13
|
+
}
|
|
14
|
+
/** 生成一组 ZIP 相对路径 → SHA-256 的校验表(路径必须为 ZIP 内正斜杠相对路径) */
|
|
15
|
+
export function buildChecksums(entries) {
|
|
16
|
+
const checksums = {};
|
|
17
|
+
for (const e of entries) {
|
|
18
|
+
checksums[e.name] = sha256Hex(e.data);
|
|
19
|
+
}
|
|
20
|
+
return checksums;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 校验:checksums 表内每个相对路径必须在 entries 中存在且 SHA-256 一致。
|
|
24
|
+
* entries 中多余的文件(如 manifest.json / checksums.json 自身)不参与校验。
|
|
25
|
+
*/
|
|
26
|
+
export function verifyChecksums(entries, checksums) {
|
|
27
|
+
const mismatches = [];
|
|
28
|
+
const missing = [];
|
|
29
|
+
for (const [relPath, expected] of Object.entries(checksums)) {
|
|
30
|
+
const data = entries.get(relPath);
|
|
31
|
+
if (data === undefined) {
|
|
32
|
+
missing.push(relPath);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (sha256Hex(data) !== expected) {
|
|
36
|
+
mismatches.push(relPath);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return { ok: mismatches.length === 0 && missing.length === 0, mismatches, missing };
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=hashing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hashing.js","sourceRoot":"","sources":["../../src/utils/hashing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAElC,MAAM,UAAU,SAAS,CAAC,IAAyB;IACjD,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAgB;IAC7C,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,cAAc,CAAC,OAA6C;IAC1E,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAQD;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAwC,EACxC,SAAiC;IAEjC,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtB,SAAS;QACX,CAAC;QACD,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC;YACjC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,UAAU,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;AACtF,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON 深度保护:解析/序列化/克隆带嵌套深度上限(防 JSON 深度攻击,规范 §19.5)。
|
|
3
|
+
* 解析分两段:JSON.parse 可能因引擎栈限制抛 RangeError(捕获并归一),
|
|
4
|
+
* 再对结果做显式栈 walk 检查深度(避免 walk 自身递归爆栈)。
|
|
5
|
+
*/
|
|
6
|
+
export declare const DEFAULT_MAX_JSON_DEPTH = 64;
|
|
7
|
+
export declare const DEFAULT_MAX_JSON_BYTES: number;
|
|
8
|
+
export declare class JsonDepthError extends Error {
|
|
9
|
+
constructor(message?: string);
|
|
10
|
+
}
|
|
11
|
+
/** 测量对象/数组的嵌套深度(迭代式显式栈,不会递归爆栈;二进制视为叶子) */
|
|
12
|
+
export declare function measureDepth(value: unknown): number;
|
|
13
|
+
/** 深度保护解析:超限抛 JsonDepthError,非法 JSON 抛 SyntaxError */
|
|
14
|
+
export declare function parseJsonSafe(text: string, opts?: {
|
|
15
|
+
maxDepth?: number;
|
|
16
|
+
maxBytes?: number;
|
|
17
|
+
}): unknown;
|
|
18
|
+
/** 深度保护序列化:先测深度再 stringify(默认不缩进) */
|
|
19
|
+
export declare function stringifyJsonSafe(value: unknown, opts?: {
|
|
20
|
+
maxDepth?: number;
|
|
21
|
+
space?: number;
|
|
22
|
+
}): string;
|
|
23
|
+
/** 深度保护深拷贝(迭代式,安全) */
|
|
24
|
+
export declare function deepClone<T>(value: T, maxDepth?: number): T;
|