@perrylink/dsh-plugin-doctor 0.1.3 → 0.1.4

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 CHANGED
@@ -63,5 +63,11 @@ SURVEY.md 全渠道检测方法梳理 + 判据出处
63
63
 
64
64
  ## 状态
65
65
 
66
- WIP 工作夹(非 git 仓,同 `dsh-ticktick-handoff` 口径)。检测器本体零依赖、可独立运行;
67
- 后续如需发布,可参照工作区发布流程另立仓库。
66
+ 正式仓库:GitHub `PerryLink/dsh-plugin-doctor`(MIT Apache-2.0),npm `@perrylink/dsh-plugin-doctor`
67
+ (latest=0.1.3,2026-09-07)。CI 用法:
68
+
69
+ ```powershell
70
+ npx --yes @perrylink/dsh-plugin-doctor@0.1.3 --repo . --no-smoke --only "静态·包结构,静态·cordis 契约扫描"
71
+ ```
72
+
73
+ 35 个插件仓已内置 `.github/workflows/plugin-doctor.yml`(install→build→npx 静态 R/K 门禁)。
@@ -65,6 +65,8 @@ export function addChecks(doctor, ctx) {
65
65
  }
66
66
  const candidates = new Map()
67
67
  for (const { f, text } of all) {
68
+ // 局部类型参数(如 createState(ctx: { credentials: ... }),非 cordis Context)——跳过该文件
69
+ if (/ctx\s*:\s*\{/.test(text)) continue
68
70
  for (const m of text.matchAll(/ctx\.([A-Za-z_$][\w$]*)/g)) {
69
71
  const name = m[1]
70
72
  if (CTX_INTRINSIC.has(name) || injectList.has(name)) continue
@@ -100,8 +102,20 @@ export function addChecks(doctor, ctx) {
100
102
  for (let i = 0; i < lines.length; i++) {
101
103
  const line = lines[i]
102
104
  if (!/(setInterval|setTimeout|setImmediate|process\.on|addEventListener\()/.test(line)) continue
105
+ // 变量级清理检测:同文件存在 clearTimeout/clearInterval/unref/removeEventListener 对应清理 → 自清理,跳过
106
+ // (变量声明可能在上一行,如三元表达式换行的 `const timer = cond\n ? setInterval(...)`)
107
+ let varMatch = line.match(/(?:const|let)\s+([A-Za-z_$][\w$]*)\s*=/)
108
+ if (!varMatch && i > 0) varMatch = lines[i - 1].match(/(?:const|let)\s+([A-Za-z_$][\w$]*)\s*=/)
109
+ const listenerCleaned = line.includes('addEventListener') && /removeEventListener\(/.test(text)
110
+ if (varMatch) {
111
+ const name = varMatch[1]
112
+ const timerCleaned = new RegExp(`clear(?:Timeout|Interval)\\(\\s*${name}\\b|${name}\\??\\.\\s*unref\\s*\\(`).test(text)
113
+ if (timerCleaned || listenerCleaned) continue
114
+ } else if (listenerCleaned) {
115
+ continue
116
+ }
103
117
  const before = lines.slice(Math.max(0, i - 3), i).join('\n')
104
- if (!/ctx\.effect|ctx\.scope|ctx\.on\b/.test(before) && !/return\s*\(\)\s*=>/.test(before + line)) {
118
+ if (!/ctx\.effect|ctx\.on\b/.test(before) && !/return\s*\(\)\s*=>/.test(before + line)) {
105
119
  hits.push(`${short(f)}:${i + 1} ${line.trim()}`)
106
120
  }
107
121
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@perrylink/dsh-plugin-doctor",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Zero-dependency static + sandbox smoke detector for DeepSeek Harness (dsh) plugins: package-structure gates (R), cordis contract scans (K), keyless-headless sandbox smoke (D), and ecosystem-listing checks (CC).",
5
5
  "type": "module",
6
6
  "main": "doctor.mjs",