@tokensapi/dsh-plugin-check 0.1.0 → 0.2.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 CHANGED
@@ -16,6 +16,9 @@ npx @tokensapi/dsh-plugin-check --skip-smoke
16
16
 
17
17
  # 机器可读输出(CI / 市场门禁)
18
18
  npx @tokensapi/dsh-plugin-check --json
19
+
20
+ # 体检一个已发布的 npm 包(市场上架审核用)
21
+ npx @tokensapi/dsh-plugin-check --package @scope/name@1.2.3 --runtime 0.1.3-alpha.1
19
22
  ```
20
23
 
21
24
  退出码:`0` 合格,`1` 存在 error(`--strict` 时 warning 也计入)。冒烟失败时加 `--keep-workspace` 保留临时工作区排查。
@@ -71,4 +74,6 @@ npx @tokensapi/dsh-plugin-check --json
71
74
 
72
75
  ## 上架流程中的位置
73
76
 
74
- 市场上架要求本工具体检通过:提交插件版本后,门禁会以相同规则复检并记录"验证于运行时 x.y.z"。本地先跑一遍,提交即通过。
77
+ 1. 开发者:发布 npm 版本前本地跑体检,全绿再发。
78
+ 2. 管理员:在仓库 Actions 的 **Plugin Check** workflow 填「包名@版本」手动触发,体检报告生成在该次运行的 Summary。
79
+ 3. 上架:后台 publish 对话框把这次运行的链接填入「检查记录链接」——链接的红/绿即审核证据,`reviewed_version` 随上架落库。存在 error 的版本不满足上架条件。
@@ -17,18 +17,20 @@
17
17
  import { resolve } from 'node:path'
18
18
  import { checkManifest } from '../lib/manifest-check.mjs'
19
19
  import { checkSmoke } from '../lib/smoke-check.mjs'
20
+ import { fetchPackage } from '../lib/fetch-package.mjs'
20
21
 
21
22
  const args = process.argv.slice(2)
22
- const options = { dir: process.cwd(), runtime: undefined, skipSmoke: false, keepWorkspace: false, strict: false, json: false }
23
+ const options = { dir: process.cwd(), package: undefined, runtime: undefined, skipSmoke: false, keepWorkspace: false, strict: false, json: false }
23
24
  for (let index = 0; index < args.length; index += 1) {
24
25
  const arg = args[index]
25
26
  if (arg === '--runtime') { options.runtime = args[++index]; continue }
27
+ if (arg === '--package') { options.package = args[++index]; continue }
26
28
  if (arg === '--skip-smoke') { options.skipSmoke = true; continue }
27
29
  if (arg === '--keep-workspace') { options.keepWorkspace = true; continue }
28
30
  if (arg === '--strict') { options.strict = true; continue }
29
31
  if (arg === '--json') { options.json = true; continue }
30
32
  if (arg === '--help' || arg === '-h') {
31
- process.stdout.write('用法: dsh-plugin-check [插件目录] [--runtime <version>] [--skip-smoke] [--keep-workspace] [--strict] [--json]\n')
33
+ process.stdout.write('用法: dsh-plugin-check [插件目录] [--package <name@version>] [--runtime <version>] [--skip-smoke] [--keep-workspace] [--strict] [--json]\n')
32
34
  process.exit(0)
33
35
  }
34
36
  if (arg.startsWith('--')) {
@@ -41,6 +43,16 @@ for (let index = 0; index < args.length; index += 1) {
41
43
  const findings = []
42
44
  const phases = []
43
45
 
46
+ if (options.package !== undefined) {
47
+ const fetched = fetchPackage(options.package)
48
+ if ('error' in fetched) {
49
+ process.stderr.write(`无法获取 ${options.package}: ${fetched.error}
50
+ `)
51
+ process.exit(1)
52
+ }
53
+ options.dir = fetched.dir
54
+ }
55
+
44
56
  const manifestResult = checkManifest(options.dir, { runtime: options.runtime })
45
57
  findings.push(...manifestResult.findings)
46
58
  phases.push({ phase: 'manifest', findings: manifestResult.findings })
@@ -0,0 +1,44 @@
1
+ /* ============================================================
2
+ * 已发布包获取:npm pack 指定 spec 并解包,供市场门禁按
3
+ * "包名@版本"体检(而不是本地目录)。
4
+ * ============================================================ */
5
+ import { mkdtempSync, mkdirSync, readdirSync } from 'node:fs'
6
+ import { spawnSync } from 'node:child_process'
7
+ import { tmpdir } from 'node:os'
8
+ import { join } from 'node:path'
9
+ import { runNpm } from './npm.mjs'
10
+
11
+ const FETCH_TIMEOUT_MS = 180_000
12
+
13
+ /**
14
+ * 拉取并解包一个已发布的 npm 包。
15
+ * @param {string} spec - 如 "@scope/name@1.2.3"(建议锁定精确版本)。
16
+ * @returns {{ dir: string } | { error: string }} dir 为解出的包根目录
17
+ * (临时位置,由调用方决定何时清理)。
18
+ */
19
+ export function fetchPackage(spec) {
20
+ const workspace = mkdtempSync(join(tmpdir(), 'dsh-plugin-fetch-'))
21
+ const pack = runNpm(['pack', spec, '--pack-destination', workspace], workspace, FETCH_TIMEOUT_MS)
22
+ if (pack.status !== 0) {
23
+ return { error: `npm pack ${spec} 失败: ${(pack.stderr || pack.stdout || '').trim().split('\n').slice(-3).join(' ')}` }
24
+ }
25
+ const tarball = readdirSync(workspace).find(name => name.endsWith('.tgz'))
26
+ if (tarball === undefined) return { error: 'npm pack 未产出 tgz' }
27
+ const extractDir = join(workspace, 'extracted')
28
+ mkdirSync(extractDir)
29
+ // Windows 自带 bsdtar,macOS/Linux 自带 tar;相对路径调用避开
30
+ // MSYS tar 对盘符路径的误判。
31
+ const extract = spawnSync('tar', ['-xzf', tarball, '-C', 'extracted'], {
32
+ cwd: workspace,
33
+ encoding: 'utf8',
34
+ timeout: FETCH_TIMEOUT_MS,
35
+ shell: process.platform === 'win32',
36
+ })
37
+ if (extract.status !== 0) {
38
+ return { error: `解包失败: ${(extract.stderr || '').trim().split('\n').slice(-2).join(' ')}` }
39
+ }
40
+ // npm 打包约定顶层目录名为 package/。
41
+ const [root] = readdirSync(extractDir)
42
+ if (root === undefined) return { error: '解包结果为空' }
43
+ return { dir: join(extractDir, root) }
44
+ }
package/lib/npm.mjs ADDED
@@ -0,0 +1,13 @@
1
+ /* npm 子进程调用:统一 --ignore-scripts,被检代码没有机会在检查器
2
+ * 进程里执行安装钩子。 */
3
+ import { spawnSync } from 'node:child_process'
4
+
5
+ export function runNpm(args, cwd, timeout) {
6
+ return spawnSync(process.platform === 'win32' ? 'npm.cmd' : 'npm', args, {
7
+ cwd,
8
+ encoding: 'utf8',
9
+ timeout,
10
+ shell: process.platform === 'win32',
11
+ env: { ...process.env, npm_config_ignore_scripts: 'true' },
12
+ })
13
+ }
@@ -16,6 +16,7 @@ import { spawnSync } from 'node:child_process'
16
16
  import { mkdtempSync, readFileSync, rmSync, writeFileSync, existsSync, readdirSync } from 'node:fs'
17
17
  import { tmpdir } from 'node:os'
18
18
  import { join, resolve } from 'node:path'
19
+ import { runNpm } from './npm.mjs'
19
20
 
20
21
  const RUNNER_TIMEOUT_MS = 90_000
21
22
  const INSTALL_TIMEOUT_MS = 300_000
@@ -76,15 +77,6 @@ writeFileSync(resultPath, JSON.stringify(results))
76
77
  process.exit(0)
77
78
  `
78
79
 
79
- function runNpm(args, cwd, timeout) {
80
- return spawnSync(process.platform === 'win32' ? 'npm.cmd' : 'npm', args, {
81
- cwd,
82
- encoding: 'utf8',
83
- timeout,
84
- shell: process.platform === 'win32',
85
- env: { ...process.env, npm_config_ignore_scripts: 'true' },
86
- })
87
- }
88
80
 
89
81
  /**
90
82
  * 对插件目录执行隔离冒烟。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokensapi/dsh-plugin-check",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "TokensCowork/DSH \u63d2\u4ef6\u5408\u683c\u6027\u4f53\u68c0:\u4e00\u6761\u547d\u4ee4\u5224\u65ad\u63d2\u4ef6\u80fd\u5426\u5b89\u5168\u88c5\u5165\u5bbf\u4e3b,\u4e0d\u628a Cowork \u641e\u5d29\u3002",
5
5
  "type": "module",
6
6
  "bin": {