@stardustlc/dsh-dream 0.5.1 → 0.6.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/CHANGELOG.md +13 -0
- package/README.en.md +29 -12
- package/README.md +33 -16
- package/lib/bridge.d.ts +205 -2
- package/lib/bridge.js +1053 -6
- package/lib/client.js +515 -26
- package/lib/evidence.d.ts +15 -0
- package/lib/evidence.js +123 -0
- package/lib/knowledge-store.d.ts +21 -5
- package/lib/knowledge-store.js +271 -41
- package/lib/knowledge.d.ts +29 -0
- package/lib/knowledge.js +29 -0
- package/lib/mask.d.ts +3 -1
- package/lib/mask.js +8 -2
- package/lib/retrieval.d.ts +12 -0
- package/lib/retrieval.js +68 -3
- package/lib/tools.js +376 -72
- package/lib/web.d.ts +48 -1
- package/lib/web.js +153 -13
- package/package.json +2 -2
- package/skills/dream-protocol/SKILL.md +9 -4
package/lib/mask.js
CHANGED
|
@@ -22,12 +22,18 @@ function looksHighEntropy(text) {
|
|
|
22
22
|
return /[a-z]/.test(text) && (/[A-Z]/.test(text) || /[0-9]/.test(text));
|
|
23
23
|
}
|
|
24
24
|
/** 对文本做脱敏;无命中时原样返回。 */
|
|
25
|
-
export function maskSecrets(text) {
|
|
25
|
+
export function maskSecrets(text, publicReferences = []) {
|
|
26
26
|
let out = text;
|
|
27
27
|
for (const { re, label } of SECRET_PATTERNS) {
|
|
28
28
|
out = out.replace(re, '[已脱敏·' + label + ']');
|
|
29
29
|
}
|
|
30
30
|
out = out.replace(CRED_ASSIGN, (_m, key, sep) => key + sep + '[已脱敏·凭据]');
|
|
31
|
-
|
|
31
|
+
const references = new Set(publicReferences.filter(isDreamReference));
|
|
32
|
+
out = out.replace(LONG_TOKEN, (m) => (references.has(m) || !looksHighEntropy(m) ? m : '[已脱敏·长令牌]'));
|
|
32
33
|
return out;
|
|
33
34
|
}
|
|
35
|
+
/** 只认可插件生成的引用形状;不得把任意 *Id / *Hash 字段当作脱敏豁免。 */
|
|
36
|
+
export function isDreamReference(value) {
|
|
37
|
+
return /^(?:lsn|evd|evt|brg)_[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value)
|
|
38
|
+
|| /^pvw_[0-9a-f]{24}$/i.test(value);
|
|
39
|
+
}
|
package/lib/retrieval.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export interface RetrievalQuery {
|
|
|
22
22
|
packageVersion?: string;
|
|
23
23
|
/** 显式包名上下文;与 query 文本一起用于识别 applicability[].package(R3)。 */
|
|
24
24
|
packageName?: string;
|
|
25
|
+
/** 任务目标平台;宿主工具缺省使用当前系统,跨平台任务可显式指定。 */
|
|
26
|
+
platform?: string;
|
|
25
27
|
/** 是否返回 candidate;默认 true(面板/审计需要)。dream_context 默认传 false(R1)。 */
|
|
26
28
|
includeCandidates?: boolean;
|
|
27
29
|
/** 是否保留 independentSupportCount===0 且非 usable 的条目;默认 true。dream_context 传 false(R1)。 */
|
|
@@ -73,6 +75,13 @@ export declare function rankInversionCount(rankedLessonIds: string[], result: {
|
|
|
73
75
|
reason: string;
|
|
74
76
|
}>;
|
|
75
77
|
}): number;
|
|
78
|
+
/** skipped.reason 的中文标签(面板与工具共用;未知 reason 原样返回)。 */
|
|
79
|
+
export declare function skippedReasonLabel(reason: string): string;
|
|
80
|
+
/**
|
|
81
|
+
* 浏览态(无 query 上下文)下一条经验的确定性扣留原因;usable 返回 undefined。
|
|
82
|
+
* 与 retrieveLessons 的优先级一致:no-evidence 先于 candidate-hold;version-mismatch 需 query/包名,不适用。
|
|
83
|
+
*/
|
|
84
|
+
export declare function deterministicHoldReason(lesson: Pick<Lesson, 'state' | 'independentSupportCount'>): string | undefined;
|
|
76
85
|
/** 解析 limit/maxChars,套用默认值与硬上限。 */
|
|
77
86
|
export declare function resolveRetrievalBudget(q: Pick<RetrievalQuery, 'limit' | 'maxChars'>): {
|
|
78
87
|
limit: number;
|
|
@@ -80,6 +89,9 @@ export declare function resolveRetrievalBudget(q: Pick<RetrievalQuery, 'limit' |
|
|
|
80
89
|
};
|
|
81
90
|
/** 简单 semver 条件匹配:支持 = / > / >= / < / <= / ^ / ~、逗号或空格 AND、|| OR、x/* 通配。 */
|
|
82
91
|
export declare function versionSatisfies(versionText: string, rangeText: string): boolean;
|
|
92
|
+
export declare function normalizePlatform(value: string): string;
|
|
93
|
+
/** 显式任务平台优先,其次无歧义的任务文本,最后宿主平台。 */
|
|
94
|
+
export declare function taskPlatform(query: string, explicit?: string, fallback?: string): string | undefined;
|
|
83
95
|
/**
|
|
84
96
|
* 任务相关经验检索。只返回 global 或与查询项目/工作区精确匹配的记录;
|
|
85
97
|
* 未知项目(未给 projectId/workspaceRoot)时只返回 global,绝不跨项目扫描。
|
package/lib/retrieval.js
CHANGED
|
@@ -142,6 +142,37 @@ export function rankInversionCount(rankedLessonIds, result) {
|
|
|
142
142
|
}
|
|
143
143
|
return inversions;
|
|
144
144
|
}
|
|
145
|
+
const SKIPPED_REASON_LABELS = {
|
|
146
|
+
'state:rejected': '已驳回',
|
|
147
|
+
'state:stale': '已过期(待复核)',
|
|
148
|
+
'state:disputed': '冲突未解决',
|
|
149
|
+
'candidate-hold': '候选未审阅(默认不注入)',
|
|
150
|
+
'no-evidence': '无独立证据',
|
|
151
|
+
'version-mismatch': '版本条件不匹配',
|
|
152
|
+
'platform-mismatch': '平台条件不匹配',
|
|
153
|
+
limit: '超出条数上限',
|
|
154
|
+
'budget-stop': '预算放不下',
|
|
155
|
+
budget: '预算放不下(旧值)',
|
|
156
|
+
};
|
|
157
|
+
/** skipped.reason 的中文标签(面板与工具共用;未知 reason 原样返回)。 */
|
|
158
|
+
export function skippedReasonLabel(reason) {
|
|
159
|
+
return SKIPPED_REASON_LABELS[reason] ?? reason;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* 浏览态(无 query 上下文)下一条经验的确定性扣留原因;usable 返回 undefined。
|
|
163
|
+
* 与 retrieveLessons 的优先级一致:no-evidence 先于 candidate-hold;version-mismatch 需 query/包名,不适用。
|
|
164
|
+
*/
|
|
165
|
+
export function deterministicHoldReason(lesson) {
|
|
166
|
+
if (lesson.state === 'rejected')
|
|
167
|
+
return 'state:rejected';
|
|
168
|
+
if (lesson.state === 'stale')
|
|
169
|
+
return 'state:stale';
|
|
170
|
+
if (lesson.state === 'disputed')
|
|
171
|
+
return 'state:disputed';
|
|
172
|
+
if (lesson.state !== 'usable')
|
|
173
|
+
return lesson.independentSupportCount === 0 ? 'no-evidence' : 'candidate-hold';
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
145
176
|
/** 解析 limit/maxChars,套用默认值与硬上限。 */
|
|
146
177
|
export function resolveRetrievalBudget(q) {
|
|
147
178
|
const rawLimit = q.limit;
|
|
@@ -257,9 +288,34 @@ function packageIdentified(pkg, q, queryText) {
|
|
|
257
288
|
return true;
|
|
258
289
|
return queryText.includes(normalizedPkg);
|
|
259
290
|
}
|
|
291
|
+
export function normalizePlatform(value) {
|
|
292
|
+
const key = value.trim().toLowerCase();
|
|
293
|
+
if (['win32', 'win64', 'windows', 'win', '微软windows'].includes(key))
|
|
294
|
+
return 'windows';
|
|
295
|
+
if (['darwin', 'macos', 'mac', 'osx', 'os x'].includes(key))
|
|
296
|
+
return 'macos';
|
|
297
|
+
if (['linux', 'gnu/linux'].includes(key))
|
|
298
|
+
return 'linux';
|
|
299
|
+
return key;
|
|
300
|
+
}
|
|
301
|
+
/** 显式任务平台优先,其次无歧义的任务文本,最后宿主平台。 */
|
|
302
|
+
export function taskPlatform(query, explicit, fallback) {
|
|
303
|
+
if (trimmed(explicit))
|
|
304
|
+
return normalizePlatform(explicit);
|
|
305
|
+
const platforms = [];
|
|
306
|
+
if (/\b(?:windows|win32|win64)\b/i.test(query))
|
|
307
|
+
platforms.push('windows');
|
|
308
|
+
if (/\b(?:linux|ubuntu|debian|fedora)\b/i.test(query))
|
|
309
|
+
platforms.push('linux');
|
|
310
|
+
if (/\b(?:macos|darwin|osx)\b/i.test(query))
|
|
311
|
+
platforms.push('macos');
|
|
312
|
+
return platforms.length === 1 ? platforms[0] : fallback ? normalizePlatform(fallback) : undefined;
|
|
313
|
+
}
|
|
260
314
|
function matchApplicability(lesson, q, queryText) {
|
|
261
|
-
const out = { packages: [], versions: [], platforms: [], versionMismatch: false };
|
|
315
|
+
const out = { packages: [], versions: [], platforms: [], versionMismatch: false, platformMismatch: false };
|
|
262
316
|
const packageVersion = trimmed(q.packageVersion);
|
|
317
|
+
const currentPlatform = taskPlatform(q.query, q.platform);
|
|
318
|
+
const platformChecks = [];
|
|
263
319
|
const identifiedVersionChecks = [];
|
|
264
320
|
for (const entry of lesson.applicability) {
|
|
265
321
|
const pkg = trimmed(entry.package);
|
|
@@ -274,11 +330,16 @@ function matchApplicability(lesson, q, queryText) {
|
|
|
274
330
|
out.versions.push(versions);
|
|
275
331
|
}
|
|
276
332
|
const platform = trimmed(entry.platform);
|
|
277
|
-
if (
|
|
278
|
-
|
|
333
|
+
if (currentPlatform !== undefined) {
|
|
334
|
+
const ok = platform === undefined || ['*', 'any', 'all'].includes(normalizePlatform(platform))
|
|
335
|
+
|| platform.split(/[,|/]/).some(item => normalizePlatform(item) === currentPlatform);
|
|
336
|
+
platformChecks.push(ok);
|
|
337
|
+
if (ok && platform !== undefined && !out.platforms.includes(platform))
|
|
338
|
+
out.platforms.push(platform);
|
|
279
339
|
}
|
|
280
340
|
}
|
|
281
341
|
out.versionMismatch = identifiedVersionChecks.length > 0 && identifiedVersionChecks.every((ok) => !ok);
|
|
342
|
+
out.platformMismatch = platformChecks.length > 0 && platformChecks.every((ok) => !ok);
|
|
282
343
|
return out;
|
|
283
344
|
}
|
|
284
345
|
function queryTerms(query) {
|
|
@@ -424,6 +485,10 @@ export function retrieveLessons(lessons, evidence, q) {
|
|
|
424
485
|
}
|
|
425
486
|
// R3 优先于 R1 的候选扣留:包名已识别但版本不满足时,reason 必须是 version-mismatch。
|
|
426
487
|
const applicability = matchApplicability(lesson, q, queryText);
|
|
488
|
+
if (applicability.platformMismatch) {
|
|
489
|
+
skipped.push({ lessonId: lesson.id, reason: 'platform-mismatch' });
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
427
492
|
if (applicability.versionMismatch) {
|
|
428
493
|
skipped.push({ lessonId: lesson.id, reason: 'version-mismatch' });
|
|
429
494
|
continue;
|