@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 CHANGED
@@ -1,3 +1,45 @@
1
- # Temporary Holding Version
1
+ # dsh-plugin-mfgabc
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
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
@@ -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 访问公开页面
@@ -0,0 +1,5 @@
1
+ - insert:
2
+ - id: dsh-plugin-mfgabc
3
+ name: "@liangjiehappy/dsh-plugin-mfgabc"
4
+ config:
5
+ baseUrl: "https://www.mfgabc.com"
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(/&amp;/g, '&')
52
+ .replace(/&lt;/g, '<')
53
+ .replace(/&gt;/g, '>')
54
+ .replace(/&quot;/g, '"')
55
+ .replace(/&#39;|&apos;/g, "'")
56
+ .replace(/&nbsp;/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.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
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
+ }