@liangjiehappy/dsh-plugin-mfgabc 0.0.0-stage → 0.1.1
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 +44 -2
- package/README.zh-CN.md +43 -0
- package/cordis.patch.yml +5 -0
- package/lib/core.js +57 -0
- package/lib/index.js +100 -0
- package/package.json +36 -4
package/README.md
CHANGED
|
@@ -1,3 +1,45 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-plugin-mfgabc
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Read-only mfgabc.com tools for DeepSeek Harness: standards pages, industrial city guides, process clusters, and cross-border compliance pages.
|
|
4
|
+
|
|
5
|
+
中文说明见 [README.zh-CN.md](README.zh-CN.md).
|
|
6
|
+
|
|
7
|
+
## Tools
|
|
8
|
+
|
|
9
|
+
| Tool | Purpose |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `mfgabc_standard` | Standard number → standards page (status/title/link) |
|
|
12
|
+
| `mfgabc_city` | Industrial city guide page |
|
|
13
|
+
| `mfgabc_process` | Process cluster page (process + city) |
|
|
14
|
+
| `mfgabc_compliance` | Cross-border compliance page (category + country) |
|
|
15
|
+
| `mfgabc_page` | Inspect any path on the site |
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
dsh plugin --profile web add @liangjiehappy/dsh-plugin-mfgabc
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Config
|
|
24
|
+
|
|
25
|
+
```yaml
|
|
26
|
+
- insert:
|
|
27
|
+
- id: dsh-plugin-mfgabc
|
|
28
|
+
name: "@liangjiehappy/dsh-plugin-mfgabc"
|
|
29
|
+
config:
|
|
30
|
+
baseUrl: "https://www.mfgabc.com"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Zero-config works; the default base URL is `https://www.mfgabc.com`.
|
|
34
|
+
|
|
35
|
+
## Permissions
|
|
36
|
+
|
|
37
|
+
- Outbound HTTPS GET to `www.mfgabc.com` only (configurable `baseUrl`)
|
|
38
|
+
- No file reads or writes, no credential access, no shell
|
|
39
|
+
- Read-only: no form submission, no login, no writes
|
|
40
|
+
|
|
41
|
+
## Limitations
|
|
42
|
+
|
|
43
|
+
- mfgabc is mostly static; tools return page status/title/link, not full text
|
|
44
|
+
- Standard slugs are normalized from the standard number; some may 404 and the real status is returned
|
|
45
|
+
- The site blocks AI training crawlers with 403; this plugin uses a plain UA for public pages
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# dsh-plugin-mfgabc
|
|
2
|
+
|
|
3
|
+
mfgabc.com 只读查询插件:标准页、产业带城市、工艺集群、跨境合规、任意站内页。
|
|
4
|
+
|
|
5
|
+
English docs: [README.md](README.md).
|
|
6
|
+
|
|
7
|
+
## 工具
|
|
8
|
+
|
|
9
|
+
| 工具 | 作用 |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `mfgabc_standard` | 标准号 → 标准页(状态/标题/链接) |
|
|
12
|
+
| `mfgabc_city` | 城市产业带页 |
|
|
13
|
+
| `mfgabc_process` | 工艺集群页(工艺 + 城市) |
|
|
14
|
+
| `mfgabc_compliance` | 跨境合规页(品类 + 国家) |
|
|
15
|
+
| `mfgabc_page` | 任意站内路径查询 |
|
|
16
|
+
|
|
17
|
+
## 安装
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
dsh plugin --profile web add @liangjiehappy/dsh-plugin-mfgabc
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 配置
|
|
24
|
+
|
|
25
|
+
```yaml
|
|
26
|
+
- insert:
|
|
27
|
+
- id: dsh-plugin-mfgabc
|
|
28
|
+
name: "@liangjiehappy/dsh-plugin-mfgabc"
|
|
29
|
+
config:
|
|
30
|
+
baseUrl: "https://www.mfgabc.com"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 权限声明
|
|
34
|
+
|
|
35
|
+
- 只对 `www.mfgabc.com` 发 HTTPS GET
|
|
36
|
+
- 不读写文件、不读凭证、不执行 shell
|
|
37
|
+
- 只读:不提交表单、不登录、不写数据
|
|
38
|
+
|
|
39
|
+
## 限制
|
|
40
|
+
|
|
41
|
+
- mfgabc 以静态页为主,工具返回页面状态/标题/链接,不做全文提取
|
|
42
|
+
- 标准页 slug 由标准号规范化生成;个别标准可能 404,工具会如实返回状态码
|
|
43
|
+
- 站点对 AI 训练爬虫有 403 策略;本插件以普通 UA 访问公开页面
|
package/cordis.patch.yml
ADDED
package/lib/core.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// dsh-plugin-mfgabc · 纯函数:站内路径构造与 HTML 解析
|
|
2
|
+
export const DEFAULT_BASE = 'https://www.mfgabc.com'
|
|
3
|
+
|
|
4
|
+
export function normalizeBase(base) {
|
|
5
|
+
const b = (base || DEFAULT_BASE).trim().replace(/\/+$/, '')
|
|
6
|
+
if (!/^https?:\/\//i.test(b)) throw new Error('baseUrl 必须以 http(s):// 开头')
|
|
7
|
+
return b
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function slugify(s) {
|
|
11
|
+
return String(s || '')
|
|
12
|
+
.trim()
|
|
13
|
+
.toLowerCase()
|
|
14
|
+
.replace(/[\/\s_.]+/g, '-')
|
|
15
|
+
.replace(/[^a-z0-9\u4e00-\u9fa5-]+/g, '')
|
|
16
|
+
.replace(/-+/g, '-')
|
|
17
|
+
.replace(/^-|-$/g, '')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** 标准号 → mfgabc 标准页 slug:ISO 4703-1977 → ISO-4703-1977 */
|
|
21
|
+
export function normalizeStandard(no) {
|
|
22
|
+
return String(no || '')
|
|
23
|
+
.trim()
|
|
24
|
+
.toUpperCase()
|
|
25
|
+
.replace(/[\/\s_]+/g, '-')
|
|
26
|
+
.replace(/\./g, '-')
|
|
27
|
+
.replace(/-+/g, '-')
|
|
28
|
+
.replace(/^-|-$/g, '')
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function buildSiteUrl(base, path) {
|
|
32
|
+
if (!isSafePath(path)) throw new Error('非法站内路径')
|
|
33
|
+
return normalizeBase(base) + path
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function isSafePath(path) {
|
|
37
|
+
if (typeof path !== 'string' || !path.startsWith('/')) return false
|
|
38
|
+
if (path.includes('..') || path.includes('//')) return false
|
|
39
|
+
if (/[\s"'<>\\]/.test(path)) return false
|
|
40
|
+
return path.length <= 512
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function extractTitle(html) {
|
|
44
|
+
const m = String(html || '').match(/<title[^>]*>([\s\S]*?)<\/title>/i)
|
|
45
|
+
if (!m) return ''
|
|
46
|
+
return decodeEntities(m[1]).replace(/\s+/g, ' ').trim().slice(0, 200)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function decodeEntities(s) {
|
|
50
|
+
return String(s)
|
|
51
|
+
.replace(/&/g, '&')
|
|
52
|
+
.replace(/</g, '<')
|
|
53
|
+
.replace(/>/g, '>')
|
|
54
|
+
.replace(/"/g, '"')
|
|
55
|
+
.replace(/'|'/g, "'")
|
|
56
|
+
.replace(/ /g, ' ')
|
|
57
|
+
}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// dsh-plugin-mfgabc · mfgabc.com 只读页面查询
|
|
2
|
+
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_BASE, normalizeBase, normalizeStandard, slugify,
|
|
5
|
+
buildSiteUrl, isSafePath, extractTitle,
|
|
6
|
+
} from './core.js'
|
|
7
|
+
|
|
8
|
+
export const name = 'dsh-plugin-mfgabc'
|
|
9
|
+
export const inject = ['tools']
|
|
10
|
+
|
|
11
|
+
const text = (value) => [{ type: 'text', text: JSON.stringify(value, null, 2) }]
|
|
12
|
+
const headers = { 'user-agent': 'dsh-plugin-mfgabc/0.1', accept: 'text/html' }
|
|
13
|
+
|
|
14
|
+
export function apply(ctx, config = {}) {
|
|
15
|
+
const base = normalizeBase(config.baseUrl)
|
|
16
|
+
|
|
17
|
+
async function fetchPage(path, signal) {
|
|
18
|
+
const url = buildSiteUrl(base, path)
|
|
19
|
+
const r = await fetch(url, { headers, signal, redirect: 'follow' })
|
|
20
|
+
const html = await r.text()
|
|
21
|
+
return {
|
|
22
|
+
ok: r.ok,
|
|
23
|
+
status: r.status,
|
|
24
|
+
url: r.url || url,
|
|
25
|
+
title: extractTitle(html),
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
ctx.tools.register(defineTool({
|
|
30
|
+
name: 'mfgabc_standard',
|
|
31
|
+
description: '查 mfgabc.com 标准页:给标准号(如 ISO 4703-1977、GB/T 9114-2010),返回页面状态、标题与官方链接。',
|
|
32
|
+
parameters: {
|
|
33
|
+
number: { type: 'string', required: true, description: '标准号,如“ISO 4703-1977”' },
|
|
34
|
+
},
|
|
35
|
+
output: { schema: { type: 'json' }, render: (_a, v) => text(v) },
|
|
36
|
+
isConcurrencySafe: () => true,
|
|
37
|
+
async execute(args, exec) {
|
|
38
|
+
const slug = normalizeStandard(args.number)
|
|
39
|
+
return { slug, ...(await fetchPage(`/standards/s/${slug}/`, exec.signal)) }
|
|
40
|
+
},
|
|
41
|
+
}))
|
|
42
|
+
|
|
43
|
+
ctx.tools.register(defineTool({
|
|
44
|
+
name: 'mfgabc_city',
|
|
45
|
+
description: '查 mfgabc.com 产业带城市页(如 dongguan、shenzhen)。',
|
|
46
|
+
parameters: {
|
|
47
|
+
city: { type: 'string', required: true, description: '城市英文 slug,如 dongguan' },
|
|
48
|
+
},
|
|
49
|
+
output: { schema: { type: 'json' }, render: (_a, v) => text(v) },
|
|
50
|
+
isConcurrencySafe: () => true,
|
|
51
|
+
async execute(args, exec) {
|
|
52
|
+
const slug = slugify(args.city)
|
|
53
|
+
return { city: slug, ...(await fetchPage(`/cities/${slug}/`, exec.signal)) }
|
|
54
|
+
},
|
|
55
|
+
}))
|
|
56
|
+
|
|
57
|
+
ctx.tools.register(defineTool({
|
|
58
|
+
name: 'mfgabc_process',
|
|
59
|
+
description: '查 mfgabc.com 工艺集群页(城市 + 工艺,如 dongguan + stamping-die)。',
|
|
60
|
+
parameters: {
|
|
61
|
+
process: { type: 'string', required: true, description: '工艺 slug,如 stamping-die' },
|
|
62
|
+
city: { type: 'string', required: true, description: '城市 slug,如 dongguan' },
|
|
63
|
+
},
|
|
64
|
+
output: { schema: { type: 'json' }, render: (_a, v) => text(v) },
|
|
65
|
+
isConcurrencySafe: () => true,
|
|
66
|
+
async execute(args, exec) {
|
|
67
|
+
const p = slugify(args.process), c = slugify(args.city)
|
|
68
|
+
return { process: p, city: c, ...(await fetchPage(`/guide/clusters/${p}/${c}/`, exec.signal)) }
|
|
69
|
+
},
|
|
70
|
+
}))
|
|
71
|
+
|
|
72
|
+
ctx.tools.register(defineTool({
|
|
73
|
+
name: 'mfgabc_compliance',
|
|
74
|
+
description: '查 mfgabc.com 跨境合规页(品类 + 国家,如 plastic-products + singapore)。',
|
|
75
|
+
parameters: {
|
|
76
|
+
category: { type: 'string', required: true, description: '品类 slug,如 plastic-products' },
|
|
77
|
+
country: { type: 'string', required: true, description: '国家 slug,如 singapore' },
|
|
78
|
+
},
|
|
79
|
+
output: { schema: { type: 'json' }, render: (_a, v) => text(v) },
|
|
80
|
+
isConcurrencySafe: () => true,
|
|
81
|
+
async execute(args, exec) {
|
|
82
|
+
const cat = slugify(args.category), c = slugify(args.country)
|
|
83
|
+
return { category: cat, country: c, ...(await fetchPage(`/compliance/${cat}-${c}/`, exec.signal)) }
|
|
84
|
+
},
|
|
85
|
+
}))
|
|
86
|
+
|
|
87
|
+
ctx.tools.register(defineTool({
|
|
88
|
+
name: 'mfgabc_page',
|
|
89
|
+
description: '取 mfgabc.com 任意站内页面的状态、标题与最终链接(用于标准/材料/指南等已知路径)。',
|
|
90
|
+
parameters: {
|
|
91
|
+
path: { type: 'string', required: true, description: '站内路径,以 / 开头,如 /standards/' },
|
|
92
|
+
},
|
|
93
|
+
output: { schema: { type: 'json' }, render: (_a, v) => text(v) },
|
|
94
|
+
isConcurrencySafe: () => true,
|
|
95
|
+
async execute(args, exec) {
|
|
96
|
+
if (!isSafePath(args.path)) throw new Error('path 必须是站内绝对路径(以 / 开头,不含 .. 或 //)')
|
|
97
|
+
return fetchPage(args.path, exec.signal)
|
|
98
|
+
},
|
|
99
|
+
}))
|
|
100
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liangjiehappy/dsh-plugin-mfgabc",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "mfgabc.com 制造业内容查询:标准页、产业带城市、工艺集群、跨境合规。只访问 www.mfgabc.com。",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib",
|
|
9
|
+
"cordis.patch.yml",
|
|
10
|
+
"README.md",
|
|
11
|
+
"README.zh-CN.md"
|
|
12
|
+
],
|
|
13
|
+
"dsh": {
|
|
14
|
+
"bundle": {
|
|
15
|
+
"patch": "./cordis.patch.yml"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"dsh": ">=0.2.0"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@deepseek-ai/cordis": "*",
|
|
23
|
+
"@deepseek-ai/dsh-tools": "*"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"deepseek-harness",
|
|
27
|
+
"dsh",
|
|
28
|
+
"dsh-plugin",
|
|
29
|
+
"mfgabc",
|
|
30
|
+
"manufacturing",
|
|
31
|
+
"standards",
|
|
32
|
+
"supply-chain"
|
|
33
|
+
],
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"scripts": {
|
|
36
|
+
"test": "node --test"
|
|
37
|
+
}
|
|
38
|
+
}
|