dsh-plugin-compat-check 0.1.4 → 0.1.6
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 +39 -17
- package/THIRD_PARTY_NOTICES.md +139 -0
- package/index.js +282 -53
- package/kernel/lib/author-ci-output.mjs +188 -0
- package/kernel/lib/author-ci-policy.mjs +285 -0
- package/kernel/lib/catalog.mjs +38 -0
- package/kernel/lib/contracts.mjs +88 -0
- package/kernel/lib/dependency-graph.mjs +650 -0
- package/kernel/lib/extract.mjs +14 -0
- package/kernel/lib/finding-guidance.mjs +72 -0
- package/kernel/lib/finding-review-store.mjs +245 -0
- package/kernel/lib/finding-review.mjs +338 -0
- package/kernel/lib/functional-health-contract.mjs +337 -0
- package/kernel/lib/issue-report.mjs +217 -0
- package/kernel/lib/observation.mjs +19 -9
- package/kernel/lib/report-identity-worker.mjs +153 -0
- package/kernel/lib/report-identity.mjs +15 -0
- package/kernel/lib/report-service.mjs +196 -11
- package/kernel/lib/report.mjs +76 -11
- package/kernel/lib/source-analysis.mjs +24 -6
- package/kernel/lib/upgrade-capture-worker.mjs +20 -0
- package/kernel/lib/upgrade-cleanup-worker.mjs +28 -0
- package/kernel/lib/upgrade-contract.mjs +471 -0
- package/kernel/lib/upgrade-input.mjs +309 -0
- package/kernel/lib/upgrade-preview.mjs +256 -0
- package/kernel/lib/upgrade-worker.mjs +50 -0
- package/kernel/lib/version.mjs +1 -1
- package/kernel/lib/worker-analysis.mjs +16 -1
- package/kernel/lib/workflow-panels.mjs +706 -0
- package/kernel/rules/README.md +5 -5
- package/lib/client.js +2974 -69
- package/lib/dependency-graph.js +651 -0
- package/lib/finding-guidance.js +73 -0
- package/lib/finding-review.js +339 -0
- package/lib/functional-health-contract.js +338 -0
- package/lib/report-contract.js +88 -0
- package/lib/upgrade-contract.js +472 -0
- package/lib/workflow-panels.js +707 -0
- package/package.json +10 -5
- package/scripts/prepublish-check.mjs +28 -13
- package/scripts/stage-contract.mjs +91 -29
- package/scripts/stage-kernel.mjs +3 -2
- package/skill/SKILL.md +90 -39
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-compat-check",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Checks installed DSH plugins
|
|
3
|
+
"version": "0.1.6",
|
|
4
|
+
"description": "Checks installed DSH plugins and previews upgrade risks, with source locations, dependency views, review records and evidence limits. Includes a panel and agent tool.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "index.js",
|
|
@@ -29,10 +29,12 @@
|
|
|
29
29
|
"cordis.patch.yml",
|
|
30
30
|
"kernel/",
|
|
31
31
|
"scripts/",
|
|
32
|
-
"LICENSE"
|
|
32
|
+
"LICENSE",
|
|
33
|
+
"THIRD_PARTY_NOTICES.md"
|
|
33
34
|
],
|
|
34
35
|
"engines": {
|
|
35
|
-
"node": "^22.19.0 || >=24"
|
|
36
|
+
"node": "^22.19.0 || >=24",
|
|
37
|
+
"dsh": ">=0.2.0-rc.2"
|
|
36
38
|
},
|
|
37
39
|
"scripts": {
|
|
38
40
|
"prepack": "node scripts/stage-skill.mjs && node scripts/stage-contract.mjs && node scripts/stage-kernel.mjs",
|
|
@@ -49,7 +51,10 @@
|
|
|
49
51
|
"compatibility",
|
|
50
52
|
"health-check",
|
|
51
53
|
"cordis",
|
|
52
|
-
"agent-skills"
|
|
54
|
+
"agent-skills",
|
|
55
|
+
"static-analysis",
|
|
56
|
+
"dependency-analysis",
|
|
57
|
+
"upgrade"
|
|
53
58
|
],
|
|
54
59
|
"repository": {
|
|
55
60
|
"type": "git",
|
|
@@ -32,15 +32,19 @@ const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
|
32
32
|
const PLUGIN = path.resolve(HERE, '..');
|
|
33
33
|
const REPO = path.resolve(PLUGIN, '..');
|
|
34
34
|
|
|
35
|
-
function fail(lines) {
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
async function fail(lines) {
|
|
36
|
+
// CI captures stderr through a pipe. Wait for the complete diagnostic to drain
|
|
37
|
+
// before exiting, including failures near the end of a large TAP transcript.
|
|
38
|
+
await new Promise((resolve, reject) => process.stderr.write(
|
|
39
|
+
`\n✗ 发布前检查未通过,已中止:\n\n${lines.join('\n')}\n\n发布是不可撤回的。修好再发。\n`,
|
|
40
|
+
error => error ? reject(error) : resolve(),
|
|
41
|
+
));
|
|
38
42
|
process.exit(1);
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
// ── ① 仓库在不在旁边 ──
|
|
42
46
|
if (!fs.existsSync(path.join(REPO, 'lib', 'version.mjs'))) {
|
|
43
|
-
fail([
|
|
47
|
+
await fail([
|
|
44
48
|
`在 ${REPO} 下找不到 lib/version.mjs。`,
|
|
45
49
|
'这个包必须在**仓库检出里**发布(它需要内核来核对版本、跑测试)。',
|
|
46
50
|
]);
|
|
@@ -50,7 +54,7 @@ if (!fs.existsSync(path.join(REPO, 'lib', 'version.mjs'))) {
|
|
|
50
54
|
const kernel = await import(pathToFileURL(path.join(REPO,'lib','version.mjs')).href);
|
|
51
55
|
const pkg = JSON.parse(fs.readFileSync(path.join(PLUGIN, 'package.json'), 'utf8'));
|
|
52
56
|
if (pkg.version !== kernel.TOOL_VERSION) {
|
|
53
|
-
fail([
|
|
57
|
+
await fail([
|
|
54
58
|
`版本不一致:`,
|
|
55
59
|
` plugin/package.json version = ${pkg.version}`,
|
|
56
60
|
` lib/version.mjs TOOL_VERSION = ${kernel.TOOL_VERSION}`,
|
|
@@ -62,7 +66,7 @@ if (pkg.version !== kernel.TOOL_VERSION) {
|
|
|
62
66
|
|
|
63
67
|
// ── ③ 私有标记必须已经去掉(否则 npm 会拒绝,报错还绕) ──
|
|
64
68
|
if (pkg.private === true) {
|
|
65
|
-
fail([
|
|
69
|
+
await fail([
|
|
66
70
|
'plugin/package.json 里还写着 `"private": true`,npm 会拒绝发布。',
|
|
67
71
|
' 要去掉它 —— 但**先确认版本号已经定下来**(见 docs/Plan.md §1、§6)。',
|
|
68
72
|
]);
|
|
@@ -70,16 +74,27 @@ if (pkg.private === true) {
|
|
|
70
74
|
|
|
71
75
|
// ── ④ 测试必须全过 ──
|
|
72
76
|
const summaryDir=fs.mkdtempSync(path.join(os.tmpdir(),'dsc-release-'));
|
|
77
|
+
const file=process.env.DSC_TEST_TAP ? path.resolve(process.env.DSC_TEST_TAP) : path.join(summaryDir,'tests.tap');
|
|
78
|
+
const stderrFile=`${file}.stderr`;
|
|
79
|
+
let stage='tests';
|
|
73
80
|
try {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
fs.mkdirSync(path.dirname(file),{recursive:true});
|
|
82
|
+
const stdout=fs.openSync(file,'w'),stderr=fs.openSync(stderrFile,'w');
|
|
83
|
+
try {
|
|
84
|
+
// Write directly to files so a failing suite survives both pipe truncation
|
|
85
|
+
// and execFileSync's output buffer limit. Keep the transcript for artifacts.
|
|
86
|
+
execFileSync(process.execPath, ['tools/run-tests.mjs','--test-reporter=tap'], {
|
|
87
|
+
cwd: REPO, stdio: ['ignore', stdout, stderr], timeout: 600000,env:{...process.env,DSH_HOME:path.join(summaryDir,'state')},
|
|
88
|
+
});
|
|
89
|
+
} finally {fs.closeSync(stdout);fs.closeSync(stderr);}
|
|
90
|
+
stage='docs';
|
|
78
91
|
execFileSync(process.execPath,['tools/doc-check.mjs','--test-summary',file],{cwd:REPO,stdio:'pipe'});
|
|
79
92
|
} catch (error) {
|
|
80
|
-
const out =
|
|
81
|
-
|
|
82
|
-
|
|
93
|
+
const out = stage==='tests'
|
|
94
|
+
? [file,stderrFile].filter(p=>fs.existsSync(p)).map(p=>fs.readFileSync(p,'utf8')).join('')
|
|
95
|
+
: `${error.stdout ?? ''}${error.stderr ?? ''}`;
|
|
96
|
+
await fail(['仓库的测试或文档检查没有全过:', '', out.trim() || error.message || String(error), '',
|
|
97
|
+
` 完整测试输出:${file}`,` 测试标准错误:${stderrFile}`,
|
|
83
98
|
' 跑 `npm test` 看全部输出。']);
|
|
84
99
|
}
|
|
85
100
|
|
|
@@ -1,39 +1,101 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/** Keep host/browser
|
|
2
|
+
/** Keep host/browser presentation artifacts byte-reproducible from pure sources. */
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
const plugin = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."),
|
|
7
7
|
root = path.dirname(plugin);
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
8
|
+
const client = path.join(plugin, "lib/client.js");
|
|
9
|
+
let next = fs.readFileSync(client, "utf8");
|
|
10
|
+
const outputs = [];
|
|
11
|
+
for (const item of [
|
|
12
|
+
{
|
|
13
|
+
source: "dependency-graph",
|
|
14
|
+
host: "dependency-graph",
|
|
15
|
+
label: "DEPENDENCY GRAPH",
|
|
16
|
+
global: "DependencyGraphContract",
|
|
17
|
+
exports:
|
|
18
|
+
"buildDependencyGraph:buildDependencyGraph, validateDependencyGraph:validateDependencyGraph",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
source: "finding-review",
|
|
22
|
+
host: "finding-review",
|
|
23
|
+
label: "FINDING REVIEW",
|
|
24
|
+
global: "FindingReviewContract",
|
|
25
|
+
exports:
|
|
26
|
+
"REVIEW_STATUS_LABELS:REVIEW_STATUS_LABELS, REVIEW_LIMITS:REVIEW_LIMITS, validateReviewInput:validateReviewInput, validateReviewEnvelope:validateReviewEnvelope",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
source: "functional-health-contract",
|
|
30
|
+
host: "functional-health-contract",
|
|
31
|
+
label: "FUNCTIONAL HEALTH CONTRACT",
|
|
32
|
+
global: "FunctionalHealthContract",
|
|
33
|
+
exports:
|
|
34
|
+
"validateFunctionalHealthResult:validateFunctionalHealthResult, canonicalFunctionalManifest:canonicalFunctionalManifest",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
source: "workflow-panels",
|
|
38
|
+
host: "workflow-panels",
|
|
39
|
+
label: "WORKFLOW PANELS",
|
|
40
|
+
global: "WorkflowPanelFactory",
|
|
41
|
+
exports:
|
|
42
|
+
"createDependencyPanel:createDependencyPanel, createFindingReviewPanel:createFindingReviewPanel, createFunctionalHealthPanel:createFunctionalHealthPanel",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
source: "contracts",
|
|
46
|
+
host: "report-contract",
|
|
47
|
+
label: "REPORT CONTRACT",
|
|
48
|
+
global: "ReportContract",
|
|
49
|
+
exports: "assertEnvelope: assertEnvelope, catalogLines: catalogLines",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
source: "upgrade-contract",
|
|
53
|
+
host: "upgrade-contract",
|
|
54
|
+
label: "UPGRADE CONTRACT",
|
|
55
|
+
global: "UpgradeContract",
|
|
56
|
+
exports:
|
|
57
|
+
"assertUpgradePreview: assertUpgradePreview, SUPPORTED_PREVIEW_VERSIONS: SUPPORTED_PREVIEW_VERSIONS",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
source: "finding-guidance",
|
|
61
|
+
host: "finding-guidance",
|
|
62
|
+
label: "FINDING GUIDANCE",
|
|
63
|
+
global: "FindingGuidance",
|
|
64
|
+
exports: "nextSteps: nextSteps",
|
|
65
|
+
},
|
|
36
66
|
]) {
|
|
67
|
+
const sourcePath = `lib/${item.source}.mjs`;
|
|
68
|
+
const source = fs.readFileSync(path.join(root, sourcePath), "utf8");
|
|
69
|
+
if (/^import\s/m.test(source))
|
|
70
|
+
throw new Error(
|
|
71
|
+
"Browser presentation source must not import dependencies: " + sourcePath,
|
|
72
|
+
);
|
|
73
|
+
const start = ` // BEGIN GENERATED ${item.label}`;
|
|
74
|
+
const end = ` // END GENERATED ${item.label}`;
|
|
75
|
+
const block =
|
|
76
|
+
start +
|
|
77
|
+
`\n var ${item.global} = (function () {\n` +
|
|
78
|
+
source.replace(/^export /gm, "") +
|
|
79
|
+
`\nreturn { ${item.exports} };\n })();\n` +
|
|
80
|
+
end;
|
|
81
|
+
const a = next.indexOf(start),
|
|
82
|
+
b = next.indexOf(end);
|
|
83
|
+
if (a >= 0 && b > a)
|
|
84
|
+
next = next.slice(0, a) + block + next.slice(b + end.length);
|
|
85
|
+
else {
|
|
86
|
+
const marker = ' var React = require("react");';
|
|
87
|
+
if (!next.includes(marker))
|
|
88
|
+
throw new Error("Missing client injection marker");
|
|
89
|
+
next = next.replace(marker, block + "\n\n" + marker);
|
|
90
|
+
}
|
|
91
|
+
outputs.push([
|
|
92
|
+
path.join(plugin, `lib/${item.host}.js`),
|
|
93
|
+
`// Generated from ${sourcePath}; run node plugin/scripts/stage-contract.mjs\n` +
|
|
94
|
+
source,
|
|
95
|
+
]);
|
|
96
|
+
}
|
|
97
|
+
outputs.unshift([client, next]);
|
|
98
|
+
for (const [file, value] of outputs) {
|
|
37
99
|
if (fs.existsSync(file) && fs.readFileSync(file, "utf8") === value) continue;
|
|
38
100
|
if (process.argv.includes("--check"))
|
|
39
101
|
throw new Error(
|
package/scripts/stage-kernel.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Stage the single-source lib/rules tree into the npm plugin. Include transitive
|
|
4
4
|
* AST, observation, state and worker modules; only opt-in process/browser runners
|
|
5
|
-
* are excluded. Root LICENSE
|
|
5
|
+
* are excluded. Root LICENSE and third-party notices are copied at pack time. Kernel copies are ignored
|
|
6
6
|
* and postpack removes them; independent artifact execution tests completeness.
|
|
7
7
|
*/
|
|
8
8
|
|
|
@@ -33,7 +33,8 @@ fs.rmSync(DEST, { recursive: true, force: true });
|
|
|
33
33
|
fs.mkdirSync(path.join(DEST, 'lib'), { recursive: true });
|
|
34
34
|
fs.mkdirSync(path.join(DEST, 'rules'), { recursive: true });
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
for (const file of ['LICENSE','THIRD_PARTY_NOTICES.md'])
|
|
37
|
+
fs.copyFileSync(path.join(REPO,file),path.join(PLUGIN,file));
|
|
37
38
|
|
|
38
39
|
for (const f of KERNEL_LIBS) {
|
|
39
40
|
const src = path.join(REPO, 'lib', f);
|
package/skill/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: dsh-plugin-compat-check
|
|
3
|
-
description: 当用户询问已安装DSH
|
|
3
|
+
description: 当用户询问已安装DSH插件是否适配当前版本、升级前对比,或排查更新后插件不工作、设置页/面板消失、工具无响应、did not activate和兼容声明时使用。Use when checking installed DeepSeek Harness plugin compatibility, comparing versions before upgrading, investigating post-update failures or missing features, or verifying peerDependencies and engines.dsh declarations.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# dsh-plugin-compat-check
|
|
@@ -13,6 +13,28 @@ description: 当用户询问已安装DSH插件是否适配当前版本,或排
|
|
|
13
13
|
|
|
14
14
|
如果**当前会话已经注册了 `compat_check` 工具**(插件半边提供的对话入口,跑的是同一个内核),优先用它;没有就按下面的命令跑 CLI。两者结论同源,不要为了"多一点信息"去绕别的路。
|
|
15
15
|
|
|
16
|
+
## 升级前对比
|
|
17
|
+
|
|
18
|
+
用户要比较当前与目标版本时,已注册工具优先调用 `compat_check({"upgradeTo":"0.2.1-rc.2"})`,需要时指定实际 `profile`;当前版本由运行宿主解析,读取返回的 `upgradePreview`,普通 `report`、baseline/cache为null。没有工具时使用仓库 CLI 的独立预检模式,先明确 profile、当前精确版本和目标精确版本,再运行:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
node <repo>/bin/compat-check.mjs --nm <profile或node_modules目录> --dsh-version 0.2.0-rc.2 --upgrade-to 0.2.1-rc.2 --json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
此模式的 `--dsh-version` 是**当前精确版本**,`--upgrade-to` 是目标精确版本;当前已认证目录仅为 `0.2.0-rc.2` 和 `0.2.1-rc.2`。未知版本或版本范围返回 `status=unsupported-version`、退出3并标明未认证,不能用邻近目录替代。普通文本输出省略 `--json`;此模式不接受 `--quiet`、探针/启动参数、规则/目录覆盖、基线参数或故障报告,可带无操作的 `--no-baseline`。
|
|
25
|
+
|
|
26
|
+
JSON 使用独立的 `schemaVersion=1 / kind=plugin-compat-check/upgrade-preview`;读取 `currentReport`、`targetReport`、带插件身份的 `changes`、`summary` 与 `limitations`。它对**同一份已安装制品**做静态版本对比:不执行插件、不启动或升级宿主,不读取旁置/环境探针、profile豁免、基线或缓存,也不写状态。新增/恶化风险含致命项时退出2,其余新增/恶化风险退出1,无新增/恶化风险退出0;输入/扫描失败或未认证版本为3。保留提取不完整、coverage/vacuous和客户端未验证限制;0仍可能有未变化的旧问题。差异是目录与声明策略下的预测,不能据此认定升级后业务通过,也不能代替目标宿主的运行时与业务验收。
|
|
27
|
+
|
|
28
|
+
## 依赖、人工处置与功能健康记录
|
|
29
|
+
|
|
30
|
+
普通报告的`dependencyGraph`只解释依赖和潜在传播:保留host/client/未知端、必需/可选/子作用域、候选提供者、loader禁用/未知状态及覆盖预算。提供声明不是实际提供证明,环或路径不是实测故障;不跨端补造提供者,不因未找到候选就说宿主缺服务,也不据此自动装包。
|
|
31
|
+
|
|
32
|
+
HTTP/tool envelope的`reviews`是独立人工记录,四种状态为pending/reviewed/false-positive/fixed。已复核、误报或已修复不消除内核发现、不隐藏新风险、不改变退出码/基线,也不授予compatibility豁免。记录绑定报告发布时的源码身份、目标/观察路径/模式、插件/DSH精确版本、工具/规则/目录及finding证据;变化后的needs-review必须重新核实,不能沿用旧误报/修复。只能按用户明确处置意图保存状态与依据,不因读到发现就自动标记已处理。坏文件/超限或busy须转述,不能覆盖或清空记录;进程崩溃可能留下.lock/.reviews-*.tmp,刷新不自动回收,确认没有任何保存任务后才可清理已核实孤立的lock/tmp,保留JSON和基线。
|
|
33
|
+
|
|
34
|
+
可选功能健康执行器仅在仓库`tools/functional-health.mjs`;默认review只审阅声明。普通兼容检查、健康记录导入及作者提供清单均不构成执行授权;不得自动添加执行开关。仅在用户已明确授权所选制品的安装、宿主/插件执行及HTTP/DOM测量后运行,必要时使用Chrome。声明与本地USTAR制品须校验SHA-256、包名/精确版本及DSH精确版本,预算为32项、请求/导航3秒、HTTP响应64KiB、整轮180秒;不接受作者脚本或跳过身份检查。私有profile不是OS沙箱,安装可能联网,不能借用用户账户/模型配置。
|
|
35
|
+
|
|
36
|
+
面板只离线导入用户选择的历史健康JSON;摘要不是签名,版本相符也不证明当前安装制品一致。保留制品/声明身份、时间、检查范围、失败/取消及清理证据,不能把历史通过改写成当前业务通过,也不改变静态报告。完整操作及声明格式见仓库`docs/guide.md`;面板能力随0.1.5提供,执行器仅在仓库提供。
|
|
37
|
+
|
|
16
38
|
## 怎么跑
|
|
17
39
|
|
|
18
40
|
CLI 只随仓库提供,npm 插件包没有 CLI bin。定位仓库检出,根依赖尚未就绪时需在授权范围内执行 `npm ci --ignore-scripts`;仓库必须同时有 `bin/compat-check.mjs`、`lib/`、`rules/`。先定位它,再跑:
|
|
@@ -69,46 +91,71 @@ report_status=$?
|
|
|
69
91
|
|
|
70
92
|
## 输出怎么读
|
|
71
93
|
|
|
94
|
+
下面是当前仓库源码对固定合成夹具的可复现输出,运行命令为 `node bin/compat-check.mjs --nm test/fixtures/labels --dsh-version 0.2.1-rc.2 --no-baseline`,预期退出2。它用于解释报告字段,不代表真实插件业务验收;当前版本为0.1.6,历史输出不追改。
|
|
95
|
+
|
|
96
|
+
```text
|
|
97
|
+
插件数: 4 有运行时面: 否(方法级结论降为「疑似」)
|
|
98
|
+
目标 DSH:0.2.1-rc.2
|
|
99
|
+
参考目录:0.2.1-rc.2 · SHA-256:90b4ae484ebc6660c53e5c9ad14ba657581534b30e8222c636c759e19587f743
|
|
100
|
+
目录认证范围:0.2.1-rc.2;仅核验内置目录字节及对应精确版本的集成;不代表业务验收或运行时观测。
|
|
101
|
+
|
|
102
|
+
工具版本: 0.1.6 证据覆盖有限: 4 个插件
|
|
103
|
+
结论: 可用 2 部分可用 1 不兼容 1 (其中 2 个「可用」没有已验证调用,不等于业务通过)
|
|
104
|
+
|
|
105
|
+
不兼容 @label/broken-client@1.0.0
|
|
106
|
+
证据覆盖: 有限;已验证调用 0
|
|
107
|
+
覆盖限制: source-unresolved: ./lib/does-not-exist.js
|
|
108
|
+
致命 / 客户端入口不可交付 [确定] (声明) @ -
|
|
109
|
+
影响(推断,非实测): 声明的客户端入口不可交付,宿主可能拒绝加载客户端
|
|
110
|
+
依据: 客户端入口 ./lib/does-not-exist.js 不存在或不可读
|
|
111
|
+
下一步: 检查该插件 package.json 的 dsh.client 与 exports["./client"] 客户端入口声明,并在实际安装制品中核对入口文件是否存在、可读且已随包交付。
|
|
112
|
+
下一步: 把已装插件的精确版本与制品文件清单对照;如需作者处理,提供缺失入口的包内相对位置,不猜测修复版本。
|
|
113
|
+
下一步: 补充同一目标的浏览器加载结果,并实际操作客户端功能、核验实际功能结果;静态入口发现不等于业务失败已实测。
|
|
114
|
+
部分可用 @label/broken-service@1.0.0
|
|
115
|
+
证据覆盖: 有限;已验证调用 0
|
|
116
|
+
覆盖限制: noSuchServiceAnywhere 未采样
|
|
117
|
+
降级 / 依赖服务待确认 [疑似] noSuchServiceAnywhere @ index.js:12
|
|
118
|
+
影响(推断,非实测): 插件必需inject的激活前提尚未确认;需同profile服务观测,不能推断已缺失或已挂起
|
|
119
|
+
依据: 未采样不等于不存在;仅列出待核实依赖
|
|
120
|
+
下一步: 该依赖仍待确认:补充同一 profile、DSH 版本与有效采样时间的服务观测;省略键或未采样不能确认服务缺失,也不能确认插件挂起。
|
|
121
|
+
下一步: 在报告给出的源码位置检查顶层必需 inject 与激活前提,再对照实际 loader 状态;依赖声明本身不能证明已经挂起。
|
|
122
|
+
下一步: 核对服务提供者的包声明与实际运行状态;提供声明只是线索,不自动安装依赖或认定某包能提供该服务。
|
|
123
|
+
可用 @label/healthy@1.0.0 [无已验证调用]
|
|
124
|
+
证据覆盖: 有限;已验证调用 0
|
|
125
|
+
可用 @label/real-service@1.0.0 [无已验证调用]
|
|
126
|
+
证据覆盖: 有限;已验证调用 0
|
|
127
|
+
覆盖限制: settings 未采样
|
|
128
|
+
无证据可判(只出现名字,没有调用点): settings
|
|
129
|
+
|
|
130
|
+
依赖关系: 服务依赖 2;潜在声明环 0
|
|
131
|
+
@label/broken-service → noSuchServiceAnywhere [host/必需];候选提供者:未定位(不等于宿主缺失)
|
|
132
|
+
@label/real-service → settings [host/必需];候选提供者:未定位(不等于宿主缺失)
|
|
133
|
+
提供声明仅为候选;同端路径及环只表示潜在影响,不证明实际挂起或失败;client 包 inject 不当作 host 服务。
|
|
134
|
+
关系覆盖限制: 静态提取覆盖不完整或未声明,关系可能缺失
|
|
135
|
+
关系覆盖限制: 部分插件未提供可映射 loader 条目,状态为未知
|
|
136
|
+
关系覆盖限制: 部分源码存在提取诊断,关系可能缺失
|
|
137
|
+
|
|
138
|
+
说明: 确定(certain)表示当前证据足以支持该条发现,可来自明确静态事实或合格运行时观测;疑似(suspected)表示当前证据不足以确定该条发现。
|
|
139
|
+
impactBasis=measured/inferred 分别表示影响有对应实测依据/影响由证据推断;确定发现不等于影响已实测。官方目录不是运行时面,未观测不等于缺失。
|
|
140
|
+
没有已验证调用仍可能存在服务依赖或客户端功能;调用核验、无发现和覆盖完整均不等于业务验收通过。
|
|
141
|
+
下一步是核实建议;本工具不会自动安装、升级或修改配置与源码。
|
|
72
142
|
```
|
|
73
|
-
插件数: 4 有运行时面: 是
|
|
74
|
-
|
|
75
|
-
采样说明: 旧格式探针未绑定 profile/DSH 版本;仅使用显式记录的服务,不推断缺项
|
|
76
|
-
工具版本: 0.1.4 证据覆盖有限: 4 个插件
|
|
77
|
-
结论: 可用 3 部分可用 1 不兼容 0 (其中 1 个「可用」是空洞的:它没有任何可检查的依赖)
|
|
78
|
-
|
|
79
|
-
部分可用 dsh-keep-awake@0.2.0
|
|
80
|
-
功能失效 / 宿主方法缺失 settings.register @ lib/index.js:466
|
|
81
|
-
影响(推断,非实测): 插件的设置页/设置项会消失
|
|
82
|
-
依据: 运行时方法集没有此方法;源码存在未被方法能力检查保护的宿主调用
|
|
83
|
-
客户端半边(命令行测不到,需界面验证): locale, slots
|
|
84
|
-
已过滤(判为噪音/有兜底): jobs.onJobsChanged
|
|
85
|
-
无证据可判(只出现名字,没有调用点): timer
|
|
86
|
-
可用 @omdsh-dev/dsh-plugin-check@0.1.0
|
|
87
|
-
可用 dsh-pet@0.3.6
|
|
88
|
-
客户端半边(命令行测不到,需界面验证): commandUi, connection, locale, remote, remote.commands, slots
|
|
89
|
-
已过滤(判为噪音/有兜底): llm.listProviders, llm.listConfigurableProviders
|
|
90
|
-
可用 dsh-plugin-compat-check-probe@0.1.1 [空洞的结论:无可检查对象]
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
> ⚠️ 上面这段是**从真实运行里抄的**,而且**有一条测试盯着它**(`test/skill.test.mjs`:
|
|
94
|
-
> 把这段示例抽出来与真实输出逐行比对)。它曾经是编的 —— 里面写着
|
|
95
|
-
> `jobs.onJobsChanged @ lib/index.js:591` 是"降级",而查源码 :590 是
|
|
96
|
-
> `if (jobs !== undefined && typeof jobs.onJobsChanged === 'function')`,
|
|
97
|
-
> **作者明明写了能力检测**,那是一条**假阳性**(已修)。
|
|
98
|
-
> 教训:**示例输出也必须从运行里抄**,否则 skill 会教 agent 去期待一个不存在的结论。
|
|
99
143
|
|
|
100
144
|
- **总结论**每插件一个:`可用` / `部分可用` / `不兼容` / `未知`。
|
|
101
|
-
- **API发现**通常包括位置;loader/声明事实可能没有源码行,不得编造位置。发现包括:严重度(`致命` / `功能失效` / `降级`)、类别(`宿主服务缺失` / `宿主方法缺失` /
|
|
145
|
+
- **API发现**通常包括位置;loader/声明事实可能没有源码行,不得编造位置。发现包括:严重度(`致命` / `功能失效` / `降级`)、类别(`宿主服务缺失` / `宿主方法缺失` / `依赖服务待确认` / `声明与实测不符` / `声明范围不兼容` / `宿主条目未激活`)、`服务.方法`、`@ 文件:行`。
|
|
102
146
|
- `影响` 与 `依据` 是给人验证用的:告诉用户**凭什么**这么判,而不是只给一个红叉。
|
|
103
|
-
-
|
|
104
|
-
- `[
|
|
105
|
-
-
|
|
147
|
+
- `下一步` 来自同一纯呈现模块,在面板、CLI、agent文本和故障报告中给出与发现证据匹配的核实步骤。优先转述报告原有步骤及真实检查位置;不把建议当成已执行修复,不编造替代API、修复版本或命令。未知依赖仍为“待确认”,先补同一profile、DSH版本与时间的观测;明确absent也须区分顶层必需inject与可选/子作用域,不从依赖未知推断插件挂起。检查入口用实际安装制品,声明冲突复核package.json与目标版本,FAILED先读本机失败原因,PENDING核对依赖提供者。工具不会自动安装、升级、修改配置或源码。
|
|
148
|
+
- `[确定]`(`certain`):当前证据足以支持该条发现;可以来自明确静态事实(如声明的客户端入口文件不存在),也可以来自合格运行时观测。确定性不说明业务影响已经实测。
|
|
149
|
+
- `[疑似]`(`suspected`):当前证据不足以确定该条发现;已有其它运行时观测也不能证明这个调用已核验。转述时保留「疑似」,不能抹平成确定。
|
|
150
|
+
- `[无已验证调用]`(`vacuous=true`):本轮未发现冲突,但`coverage.verifiedCalls=0`。插件仍可能依赖DSH服务或包含客户端功能,不能解释成“没有使用服务”或“没有依赖”。转述具体coverage限制;调用核验和覆盖完整也不等于业务通过。
|
|
151
|
+
- `客户端半边(命令行测不到,需界面验证)`:客户端源码/入口可做静态检查,但这份报告没有完成客户端业务验收。需要实际操作并核验UI状态、请求或持久化结果;元素出现不等于业务成功。
|
|
106
152
|
- `已过滤(判为噪音/有兜底)`:报了但被判定为不构成问题(例如插件自己写了 `typeof x?.y === 'function'` 能力检测)。过滤与弃权**也是结论的一部分**,要如实转述,不要只报红叉。
|
|
107
153
|
- `无证据可判`:只出现名字、没有调用点。这是弃权,不是清白。
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
|
|
111
|
-
|
|
154
|
+
- **分别读取确定性与影响依据**(`certainty`与`impactBasis`字段):
|
|
155
|
+
- **影响**上方标了「**推断,非实测**」的,表示根据静态事实或运行时证据推断影响,
|
|
156
|
+
**没有实测对应业务结果**。例如静态确认客户端入口文件不存在,可以推断加载风险,
|
|
157
|
+
但没有观测浏览器中的实际失败;方法缺失案例也可能依据运行时方法面和源码调用点,
|
|
158
|
+
推断「用户可能失去什么功能」。不要把这个方法案例当成所有发现都已有运行时观测。
|
|
112
159
|
**转述时必须保留这个限定**,不要说成"确定会消失"。
|
|
113
160
|
实测有过一条 certain 级假阳性:工具说「设置页会消失」,而作者把能力检测写在了
|
|
114
161
|
一个辅助函数里、早就兜住了,还 log 了降级行为。
|
|
@@ -117,13 +164,13 @@ report_status=$?
|
|
|
117
164
|
同一个插件在「规则表还没覆盖这个方法」和「已经覆盖」的两个版本下,
|
|
118
165
|
结论可能从「影响面未知」变成「推断:可能影响设置页」—— 不带版本,用户无法判断该不该信。
|
|
119
166
|
|
|
120
|
-
##
|
|
167
|
+
## 普通体检退出码
|
|
121
168
|
|
|
122
169
|
| 码 | 含义 |
|
|
123
170
|
|---|---|
|
|
124
171
|
| `0` | 可用(未发现问题,仍需检查 coverage / vacuous) |
|
|
125
172
|
| `1` | 部分可用或未知;保留具体发现与证据限制 |
|
|
126
|
-
| `2` |
|
|
173
|
+
| `2` | 不兼容(存在致命发现,保留具体类别与影响依据) |
|
|
127
174
|
| `3` | **无法判定**——工具/输入出了问题,**这不是插件的结论** |
|
|
128
175
|
|
|
129
176
|
`3` 必须与插件结论严格分开:`--nm` 指了不存在的目录、探针报告不是合法 JSON、渲染层抛异常,都退 `3`。看到 `3` 就说「这次没查成」,**绝不能说成"不兼容"或"部分可用"**(用的 flag 也对不上,这类混码见过)。
|
|
@@ -133,7 +180,7 @@ CI 里可以直接用:`0` 过,`1`/`2` 按你的策略处理,`3` 是**工
|
|
|
133
180
|
## 判据:这个工具的三条硬规矩
|
|
134
181
|
|
|
135
182
|
**1. 确定性与去处分开。**
|
|
136
|
-
`certainty
|
|
183
|
+
`certainty`只有`certain`与`suspected`;过滤、守卫、弃权是独立去处。确定性描述发现是否有足够证据,与`impactBasis=measured/inferred`分别解释:静态客户端入口缺失可为`certain + inferred`,明确loader状态可为`certain + measured`。目录不是运行时面;没有合格运行时证据的方法缺失推断保留疑似,但不能将所有静态事实降为疑似。未观测或省略键不等于服务不存在;已有运行时面也不保证每条发现确定。
|
|
137
184
|
|
|
138
185
|
**2. 误报和漏报都要关注,漏报可能表现为「沉默」。**
|
|
139
186
|
判不准时一律**降级**,不升格成确定:假阳性会让用户去做不必要的处置(改配置、换版本),成本高且磨损信任。但反过来也要盯住——**假阴性不产出红字,它产出沉默**,而用户会把沉默当成「一切正常」。所以:
|
|
@@ -165,4 +212,8 @@ CI 里可以直接用:`0` 过,`1`/`2` 按你的策略处理,`3` 是**工
|
|
|
165
212
|
|
|
166
213
|
只读目标node_modules同级的独立`compatibility.json`,形如`{"sample@1.0.0":["0.2.1-rc.2"]}`。只有插件名、插件精确版本与DSH精确版本全匹配才豁免范围冲突;不使用包内兼容声明代替授权。无效记录整条忽略(其它有效记录仍用)并限制覆盖;缺文件为空豁免,可读性/JSON错误、非普通文件或超过64KiB则豁免未观测。不得代用户写豁免,豁免不绕过非法字段,也不证明API或业务成功。
|
|
167
214
|
|
|
168
|
-
CLI的`--dsh-version`及probe-boot采集值、宿主自己的DSH版本用于目录选择:DSH≥0.2.1-rc.2使用独立rc.2目录,其余/未知使用旧0.2.0-rc.2目录,显式`--catalog`优先。未知版本不猜声明,未来DSH未经认证。单独文件probe不自动补目标版本,需给`--dsh-version`。目录不等于运行时面。当前契约/验收/后续见仓库docs/Plan.md,统计见docs/current-state.json;公开安装以npm registry为准。
|
|
215
|
+
普通体检中,CLI的`--dsh-version`及probe-boot采集值、宿主自己的DSH版本用于目录选择:DSH≥0.2.1-rc.2使用独立rc.2目录,其余/未知使用旧0.2.0-rc.2目录,显式`--catalog`优先。未知版本不猜声明,未来DSH未经认证。单独文件probe不自动补目标版本,需给`--dsh-version`。目录不等于运行时面。当前契约/验收/后续见仓库docs/Plan.md,统计见docs/current-state.json;公开安装以npm registry为准。
|
|
216
|
+
|
|
217
|
+
普通报告另有 `catalog`:目标版本、参考目录版本、SHA-256、selection、verified、certifiedVersions及warning。转述时同时给出目标与目录身份;fallback/override、未知身份和未认证提示不得省略,verified仅表示内置目录与已验收精确版本匹配,不是业务认证。内置目录摘要不符、同名插件重复安装(含alias及不同版本)会明确无法判定,不允许转述为无冲突;普通报告失败不推进基线。仓库YAML修复仅涉及锁文件等工具依赖,不属于npm插件运行时依赖。新目录治理流程见仓库 `docs/maintaining.md#api目录候选审查`。
|
|
218
|
+
|
|
219
|
+
对observationVersion=1探针始终校验采样时间:未来偏差最多5分钟(含边界),缺失/非法或超限时撤回该文件的服务及loader证据,不推断FAILED/PENDING或确定方法缺失;普通体检另保留24小时有效期及profile/DSH绑定。转述observation.notes中的原因,保留静态发现和待验证项,不修正原采样时间、不把时钟异常当插件不兼容;修复时钟/重采样后再显式刷新。旧未绑定报告仍只使用显式键,不能补造绑定。仓库CI依赖安全工具不属于npm运行时功能。
|