@liangjiehappy/dsh-plugin-mj7 0.0.0-stage → 0.1.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 +45 -2
- package/cordis.patch.yml +5 -0
- package/lib/core.js +71 -0
- package/lib/index.js +97 -0
- package/package.json +35 -4
package/README.md
CHANGED
|
@@ -1,3 +1,46 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-plugin-mj7
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
模极社(mj7.cn)只读数据插件:在 DSH 里查标准、产品、HS 关联、贸易术语、单证和汇率。
|
|
4
|
+
|
|
5
|
+
## 工具
|
|
6
|
+
|
|
7
|
+
| 工具 | 作用 |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `mj7_search` | 关键词搜索标准/产品/材料 |
|
|
10
|
+
| `mj7_hot` | 热门品类 |
|
|
11
|
+
| `mj7_hs` | HS 编码联想标准 |
|
|
12
|
+
| `mj7_terms` | Incoterms 术语 |
|
|
13
|
+
| `mj7_docs` | 外贸单证清单 |
|
|
14
|
+
| `mj7_fx` | 人民币汇率 |
|
|
15
|
+
|
|
16
|
+
## 安装
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
dsh plugin --profile web add dsh-plugin-mj7
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
或发布后:`dsh plugin --profile web add dsh-plugin-mj7`
|
|
23
|
+
|
|
24
|
+
## 配置
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
- insert:
|
|
28
|
+
- id: dsh-plugin-mj7
|
|
29
|
+
name: dsh-plugin-mj7
|
|
30
|
+
config:
|
|
31
|
+
baseUrl: "https://www.mj7.cn"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
零配置可用,默认 https://www.mj7.cn。
|
|
35
|
+
|
|
36
|
+
## 权限声明
|
|
37
|
+
|
|
38
|
+
- 只对 `www.mj7.cn` 发 HTTPS GET(可配置 baseUrl)
|
|
39
|
+
- 不读写文件、不读凭证、不执行 shell
|
|
40
|
+
- 只读:不登录、不下单、不写数据
|
|
41
|
+
|
|
42
|
+
## 限制
|
|
43
|
+
|
|
44
|
+
- 依赖 mj7.cn 公开 API(`/api/search`、`/api/hot`、`/api/hs`、`/api/terms`、`/api/docs`、`/api/fx`)
|
|
45
|
+
- API 变更可能导致工具失败;失败会返回真实 HTTP 错误
|
|
46
|
+
- 结果只做摘要与筛选,完整内容请打开站内页面
|
package/cordis.patch.yml
ADDED
package/lib/core.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// dsh-plugin-mj7 · 纯函数:URL 构造与 API 结果摘要(无副作用、不依赖网络)
|
|
2
|
+
export const DEFAULT_BASE = 'https://www.mj7.cn'
|
|
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 buildUrl(base, path, params = {}) {
|
|
11
|
+
const u = new URL(path, base + '/')
|
|
12
|
+
for (const [k, v] of Object.entries(params)) {
|
|
13
|
+
if (v !== undefined && v !== null && v !== '') u.searchParams.set(k, String(v))
|
|
14
|
+
}
|
|
15
|
+
return u.toString()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function asLimit(n, def = 6, max = 50) {
|
|
19
|
+
const v = Number(n)
|
|
20
|
+
if (!Number.isFinite(v) || v <= 0) return def
|
|
21
|
+
return Math.min(Math.floor(v), max)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function pickItem(it) {
|
|
25
|
+
const out = {}
|
|
26
|
+
for (const k of ['id', 'standard_no', 'org', 'title', 'title_cn', '_title', 'name', 'code', 'cn', 'en', 'url', 'type']) {
|
|
27
|
+
if (it && it[k] !== undefined) out[k] = it[k]
|
|
28
|
+
}
|
|
29
|
+
return out
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function summarizeSearch(json, limit = 6) {
|
|
33
|
+
if (!json || json.code !== 200) throw new Error((json && json.msg) || 'mj7 search 失败')
|
|
34
|
+
const groups = (json.groups || []).map((g) => ({
|
|
35
|
+
key: g.key,
|
|
36
|
+
name: g.name,
|
|
37
|
+
total: g.total,
|
|
38
|
+
items: (g.items || []).slice(0, limit).map(pickItem),
|
|
39
|
+
}))
|
|
40
|
+
return { total: json.total ?? 0, kw: json.kw || '', groups }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function summarizeHot(json, limit = 30) {
|
|
44
|
+
if (!json || json.code !== 200) throw new Error((json && json.msg) || 'mj7 hot 失败')
|
|
45
|
+
return { items: (json.items || []).slice(0, limit) }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function summarizeHs(json, limit = 10) {
|
|
49
|
+
if (!json || json.code !== 200) throw new Error((json && json.msg) || 'mj7 hs 失败')
|
|
50
|
+
return {
|
|
51
|
+
hs: json.hs || '',
|
|
52
|
+
chapter: json.chapter || '',
|
|
53
|
+
total: (json.data || []).length,
|
|
54
|
+
items: (json.data || []).slice(0, limit).map(pickItem),
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function summarizeList(json, limit = 10) {
|
|
59
|
+
if (!json || json.code !== 200) throw new Error((json && json.msg) || 'mj7 查询失败')
|
|
60
|
+
return {
|
|
61
|
+
total: json.total ?? (json.data || []).length,
|
|
62
|
+
items: (json.data || []).slice(0, limit),
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function summarizeFx(json, currency = 'USD') {
|
|
67
|
+
if (!json || json.code !== 200) throw new Error((json && json.msg) || 'mj7 fx 失败')
|
|
68
|
+
const cur = String(currency || 'USD').toUpperCase()
|
|
69
|
+
const rates = json.rates || {}
|
|
70
|
+
return { base: json.base || 'CNY', currency: cur, rate: rates[cur] ?? null, rates }
|
|
71
|
+
}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// dsh-plugin-mj7 · 模极社 mj7.cn 只读数据工具
|
|
2
|
+
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
3
|
+
import {
|
|
4
|
+
buildUrl, normalizeBase, asLimit, summarizeSearch, summarizeHot,
|
|
5
|
+
summarizeHs, summarizeList, summarizeFx,
|
|
6
|
+
} from './core.js'
|
|
7
|
+
|
|
8
|
+
export const name = 'dsh-plugin-mj7'
|
|
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-mj7/0.1', accept: 'application/json' }
|
|
13
|
+
|
|
14
|
+
export function apply(ctx, config = {}) {
|
|
15
|
+
const base = normalizeBase(config.baseUrl)
|
|
16
|
+
|
|
17
|
+
async function getJson(path, params, signal) {
|
|
18
|
+
const r = await fetch(buildUrl(base, path, params), { headers, signal })
|
|
19
|
+
if (!r.ok) throw new Error(`mj7 API HTTP ${r.status} (${path})`)
|
|
20
|
+
return r.json()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
ctx.tools.register(defineTool({
|
|
24
|
+
name: 'mj7_search',
|
|
25
|
+
description: '搜索模极社(mj7.cn):标准、产品、材料。返回总数与分组摘要,含站内详情标识。',
|
|
26
|
+
parameters: {
|
|
27
|
+
kw: { type: 'string', required: true, description: '关键词,如“法兰”“ISO 4703”' },
|
|
28
|
+
limit: { type: 'number', description: '每组返回条数,默认 6' },
|
|
29
|
+
},
|
|
30
|
+
output: { schema: { type: 'json' }, render: (_a, v) => text(v) },
|
|
31
|
+
isConcurrencySafe: () => true,
|
|
32
|
+
async execute(args, exec) {
|
|
33
|
+
const json = await getJson('/api/search', { kw: args.kw }, exec.signal)
|
|
34
|
+
return summarizeSearch(json, asLimit(args.limit))
|
|
35
|
+
},
|
|
36
|
+
}))
|
|
37
|
+
|
|
38
|
+
ctx.tools.register(defineTool({
|
|
39
|
+
name: 'mj7_hot',
|
|
40
|
+
description: '模极社热门品类/关键词列表。',
|
|
41
|
+
parameters: {},
|
|
42
|
+
output: { schema: { type: 'json' }, render: (_a, v) => text(v) },
|
|
43
|
+
isConcurrencySafe: () => true,
|
|
44
|
+
async execute(_args, exec) {
|
|
45
|
+
return summarizeHot(await getJson('/api/hot', {}, exec.signal))
|
|
46
|
+
},
|
|
47
|
+
}))
|
|
48
|
+
|
|
49
|
+
ctx.tools.register(defineTool({
|
|
50
|
+
name: 'mj7_hs',
|
|
51
|
+
description: '按 HS 编码联想相关标准(mj7.cn HS 检索)。',
|
|
52
|
+
parameters: {
|
|
53
|
+
code: { type: 'string', required: true, description: 'HS 编码,如 73181500' },
|
|
54
|
+
limit: { type: 'number', description: '返回条数,默认 10' },
|
|
55
|
+
},
|
|
56
|
+
output: { schema: { type: 'json' }, render: (_a, v) => text(v) },
|
|
57
|
+
isConcurrencySafe: () => true,
|
|
58
|
+
async execute(args, exec) {
|
|
59
|
+
const json = await getJson('/api/hs', { code: args.code }, exec.signal)
|
|
60
|
+
return summarizeHs(json, asLimit(args.limit, 10))
|
|
61
|
+
},
|
|
62
|
+
}))
|
|
63
|
+
|
|
64
|
+
ctx.tools.register(defineTool({
|
|
65
|
+
name: 'mj7_terms',
|
|
66
|
+
description: '查 Incoterms 贸易术语(EXW/FOB/CIF 等)的责任划分。',
|
|
67
|
+
parameters: { q: { type: 'string', description: '关键词,留空返回全部' } },
|
|
68
|
+
output: { schema: { type: 'json' }, render: (_a, v) => text(v) },
|
|
69
|
+
isConcurrencySafe: () => true,
|
|
70
|
+
async execute(args, exec) {
|
|
71
|
+
return summarizeList(await getJson('/api/terms', { q: args.q || '' }, exec.signal), 10)
|
|
72
|
+
},
|
|
73
|
+
}))
|
|
74
|
+
|
|
75
|
+
ctx.tools.register(defineTool({
|
|
76
|
+
name: 'mj7_docs',
|
|
77
|
+
description: '查外贸单证清单(商业发票、装箱单、原产地证等)。',
|
|
78
|
+
parameters: { q: { type: 'string', description: '关键词,留空返回全部' } },
|
|
79
|
+
output: { schema: { type: 'json' }, render: (_a, v) => text(v) },
|
|
80
|
+
isConcurrencySafe: () => true,
|
|
81
|
+
async execute(args, exec) {
|
|
82
|
+
return summarizeList(await getJson('/api/docs', { q: args.q || '' }, exec.signal), 10)
|
|
83
|
+
},
|
|
84
|
+
}))
|
|
85
|
+
|
|
86
|
+
ctx.tools.register(defineTool({
|
|
87
|
+
name: 'mj7_fx',
|
|
88
|
+
description: '查人民币汇率(基准 CNY,默认 USD)。',
|
|
89
|
+
parameters: { currency: { type: 'string', description: '目标币种,默认 USD' } },
|
|
90
|
+
output: { schema: { type: 'json' }, render: (_a, v) => text(v) },
|
|
91
|
+
isConcurrencySafe: () => true,
|
|
92
|
+
async execute(args, exec) {
|
|
93
|
+
return summarizeFx(await getJson('/api/fx', { from: (args.currency || 'USD') }, exec.signal),
|
|
94
|
+
args.currency || 'USD')
|
|
95
|
+
},
|
|
96
|
+
}))
|
|
97
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liangjiehappy/dsh-plugin-mj7",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "模极社 mj7.cn 只读数据工具:标准/产品搜索、HS 联想、Incoterms、贸易单证、人民币汇率。只访问 www.mj7.cn。",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "lib/index.js",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib",
|
|
9
|
+
"cordis.patch.yml",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"dsh": {
|
|
13
|
+
"bundle": {
|
|
14
|
+
"patch": "./cordis.patch.yml"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"engines": {
|
|
18
|
+
"dsh": ">=0.2.0"
|
|
19
|
+
},
|
|
20
|
+
"peerDependencies": {
|
|
21
|
+
"@deepseek-ai/cordis": "*",
|
|
22
|
+
"@deepseek-ai/dsh-tools": "*"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"deepseek-harness",
|
|
26
|
+
"dsh",
|
|
27
|
+
"dsh-plugin",
|
|
28
|
+
"mj7",
|
|
29
|
+
"standards",
|
|
30
|
+
"manufacturing",
|
|
31
|
+
"trade"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"scripts": {
|
|
35
|
+
"test": "node --test"
|
|
36
|
+
}
|
|
37
|
+
}
|