Skill: jdl-external-skills/i-logisitics-skill (version 1.0.1)

--- name: i-logistics-skill description: 京东国际物流数据查询技能 核心能力：支持物流轨迹追踪、国际运营指标查询、跨境小包体验指标查询三大功能模块。 1.国际物流轨迹追踪技能 功能描述：查询国际物流单号的实时物流轨迹信息。 支持的单号类型： - FS 开头的京东订单号 - JDW 开头的京东运单号 - 客户运单号 - 承运商运单号 核心能力： - 实时查询物流轨迹 2.供应链运营指标查询 功能描述：可按多种维度查询、对比分析供应链运营指标数据 支持查询如下指标： - 海外仓入库下单件数 - 海外仓入库及时率 - 头程在途体积 - 海外仓入库下单sku数 - 海外仓入库体积 - 海外仓实际出库重量 - 发货及时率 - 海外仓入库重量 - 海外仓入库单量 - 海外仓出库及时率 - 退件件量 - 海外仓目标入库件数 - 海外仓库位合格率 - 海外仓高位拣选比例 - 海外仓蓝牙拣选使用率 - 海外仓入库sku数 - ATTSCAN及时率 - 海外仓配Ascan及时率 - 海外仓24H尾单关闭率 - 头程渗透率 - 海外仓机区D类库存占比 - 海外仓实际出库体积 - 海外仓上架准确率 - 海外仓目标出库单量 - 海外仓目标出库件数 - 海外仓实际出库单量 - 海外仓配Dscan及时率 - 海外仓入库下单量 - 海外仓入库件数 - 退件上架及时率 - 海外仓仓容利用率 - 收货准确率 - 海外仓实际出库件数 - 海外仓退货验收单量 - 全程履约率（供应链） - 全程履约率（跨境小包） --- # joy-logistics-skill — 国际物流 Skills 全集 Complete collection of multi Logistics skills for OpenClaw agents. ## Included Skills | Skill | Category | Description | |-------|----------|-------------| | joy-logistics-trace | logistics-trace-query | 国际物流轨迹明细查询 | | joy-logistics-indicator | indicators-query | 国际供应链、跨境小包相关指标查询 | ## Documentation See `README.md` for the complete setup guide (in Chinese).

path: README.md
content: # 京东国际物流数据查询技能

> 本项目是京东国际物流数据查询技能，提供物流轨迹追踪、国际供应链运营、跨境小包体验指标查询两大功能模块。

## 项目结构

```
joy-logistics-skill-260423/
├── .joycode/
│   └── rules/              # JoyCode规则配置
├── skills/
│   ├── joy-logistics-indicator/    # 供应链运营指标查询技能
│   └── joy-logistics-trace/        # 国际物流轨迹追踪技能
├── .gitignore              # Git忽略文件配置
├── README.md               # 项目说明文档
└── SKILL.md                # 技能详细说明文档
```

## 1. Skills 总览

| # | Skill 名称 | 功能 | 分类 |
|---|-----------|----|----|
| 1 | **joy-logistics-indicator** | 国际供应链运营指标查询技能 | 文档 |
| 2 | **joy-logistics-trace** | 国际物流轨迹追踪技能 | 文档 |

## 2. 前置准备

### 2.1 安装基础工具

```bash
# 安装 ClawHub CLI（用于从 ClawHub 安装 Skills）
npm i -g clawhub
```

### 2. 配置权限

MAC/Linux
```bash
cat > ~/.env << 'EOF'
# 京东物流 API 配置
[REDACTED_SECRET] 
EOF
```

Windows
```powershell
[Environment]::SetEnvironmentVariable("token", "66Pi3xz*******yzNHvRNJgeJsqtSkn7fcJ4", "User")
```

## 3. Skills 安装


```bash
# 登录 ClawHub（需 GitHub 账号）
clawhub login

# 安装单个 skill
clawhub install joy-logistics-indicator --dir ~/.workspace/skills

# 批量安装所有国际物流 skills
for skill in joy-logistics-indicator joy-logistics-trace; do
  clawhub install "$skill" --dir ~/.workspace/skills --force
done
```

### 4. 验证安装

在和openclaw的对话中输入：

```
列出我安装的国际物流相关 skills
```

path: skills/joy-logistics-trace/scripts/get_tracking_data.js
content: const https = require('https');

// 从环境变量获取 token
const [REDACTED_SECRET];

// 接收入参：只需要 1 个参数，多个单号用英文逗号分隔
const args = process.argv.slice(2);
const [referenceNumbersStr] = args;

// 检查入参
if (!referenceNumbersStr || referenceNumbersStr.trim() === '') {
  console.error('❌ 请传入单号，多个单号用英文逗号分隔，例如：node query.js "JD123,JD456"');
  process.exit(1);
}

// 切割成数组，并自动去空、去重
const referenceNumbers = referenceNumbersStr
  .split(',')
  .map(item => item.trim())
  .filter(Boolean);

if (referenceNumbers.length === 0) {
  console.error('❌ 未传入有效单号');
  process.exit(1);
}

// 构建 referenceList
const referenceList = referenceNumbers.map(num => ({
  customerCode: "",
  referenceNumber: num,
  referenceType: 0
}));

// ===========================
// 构造请求体（完全匹配 curl）
// ===========================
const postData = JSON.stringify([
  {
    "includeFields": ["waybill"],
    "locale": "zh-CN",
    "referenceList": referenceList,  // 自动填入 1个/多个单号
    "scope": 4,
    "timeZone": "UTC+08:00"
  }
]);

// ===========================
// 请求配置
// ===========================
const options = {
  hostname: 'lop-proxy.ochama.com',
  port: 443,
  path: '/global/trackingOpenExport/queryTrackingBatch',
  method: 'POST',
  headers: {
    'LOP-DN': 'ifop.skill.eu.outer.jd.com',
    'Content-Type': 'application/json',
    'token': token,
    'Content-Length': Buffer.byteLength(postData)
  },
  rejectUnauthorized: false
};

console.log('✅ 准备查询单号：', referenceNumbers);
console.log('✅ 请求体：\n', postData);

// ===========================
// 发送请求
// ===========================
const req = https.request(options, (res) => {
  let chunks = [];
  res.on('data', d => chunks.push(d));
  res.on('end', () => {
    const result = Buffer.concat(chunks).toString('utf8');
    console.log('\n========================================');
    console.log('✅ 返回结果：');
    try {
      console.log(JSON.stringify(JSON.parse(result), null, 2));
    } catch (e) {
      console.log(result);
    }
  });
});

req.on('error', (e) => {
  console.error('❌ 请求失败：', e);
});

req.write(postData);
req.end();

path: skills/joy-logistics-indicator/scripts/get_cross_board_data.js
content: /*
 * @Author: wangyu516 [REDACTED_SECRET]
 * @Date: 2026-04-17 01:06:29
 * @LastEditors: wangyu516 [REDACTED_SECRET]
 * @LastEditTime: 2026-04-23 17:19:23
 * @FilePath: /joy-logistics/scripts/get_cross_board_data.js
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
const https = require('https');
const fs = require('fs');
const path = require('path');

// 自动从 ~/.env 读取 joy_token
// let token = '';
// try {
//   const envPath = path.join(process.env.HOME, '.env');
//   const envContent = fs.readFileSync(envPath, 'utf8');
//   const match = envContent.match(/^joy_token=(.+)$/m);
//   if (match) [REDACTED_SECRET]);
// } catch (err) {}

// 从环境变量获取 token
const [REDACTED_SECRET];

if (!token) {
  console.error('❌ 未从 ~/.env 读取到 joy_token');
  process.exit(1);
}

// ===========================
// 入参：2 个  dateList, dims
// ===========================
const args = process.argv.slice(2);
console.log("length:" + args.length);

// ===========================
// 数组转换函数（和原版完全一样）
// ===========================
function toArray(val) {
  if (!val) return [];
  let str = val.trim();
  if (str === '' || str === '.' || str.startsWith('\\') || str.startsWith('"')) return [];
  return str.split(',').map(i => i.trim()).filter(Boolean);
}

const [dateList, dims] = args;

const postData = JSON.stringify([
  {
    dateList: toArray(dateList),
    dims: toArray(dims)
  }
]);

const options = {
  hostname: 'us-api.jd.com',
  port: 443,
  path: [REDACTED_SECRET],
  method: 'POST',
  headers: {
    'LOP-DN': 'iplat.skill.http.outer.jd.com',
    'Content-Type': 'application/json',
    'token': token,
    'Content-Length': Buffer.byteLength(postData)
  },
  rejectUnauthorized: false
};

console.log('✅ 发送请求体：\n', postData);

const req = https.request(options, (res) => {
  let chunks = [];
  res.on('data', d => chunks.push(d));
  res.on('end', () => {
    const result = Buffer.concat(chunks).toString('utf8');
    console.log('\n========================================');
    console.log('✅ 返回结果：');
    try { console.log(JSON.stringify(JSON.parse(result), null, 2)); } catch { console.log(result); }
  });
});

req.on('error', e => console.error('❌ 请求失败：', e));
req.write(postData);
req.end();

path: skills/joy-logistics-indicator/scripts/get_isc_data.js
content: const https = require('https');
const [REDACTED_SECRET];

const args = process.argv.slice(2);
console.log("length:" + args.length);

// ===========================
// 🔥 WINDOWS 终极兼容函数
// 空 / . / \ / \" 全都变 []
// ===========================
function toArray(val) {
  if (!val) return [];
  let str = val.trim();
  if (str === '' || str === '.' || str.startsWith('\\') || str.startsWith('"')) return [];
  return str.split(',').map(i => i.trim()).filter(Boolean);
}

const [
  dims,
  monthList,
  indicatorCode,
  dateList,
  warehouseNoList,
  warehouseNameList,
  continentList,
  customerCodeList
] = args;

const postData = JSON.stringify([
  {
    dims: toArray(dims),
    monthList: toArray(monthList),
    indicatorCode,
    dateList: toArray(dateList),
    warehouseNoList: toArray(warehouseNoList),
    warehouseNameList: toArray(warehouseNameList),
    continentList: toArray(continentList),
    customerCodeList: toArray(customerCodeList)
  }
]);

const options = {
  hostname: 'us-api.jd.com',
  port: 443,
  path: [REDACTED_SECRET],
  method: 'POST',
  headers: {
    'LOP-DN': 'iplat.skill.http.outer.jd.com',
    'Content-Type': 'application/json',
    'token': token,
    'Content-Length': Buffer.byteLength(postData)
  },
  rejectUnauthorized: false
};

console.log('✅ 发送请求体：\n', postData);

const req = https.request(options, (res) => {
  let chunks = [];
  res.on('data', d => chunks.push(d));
  res.on('end', () => {
    const result = Buffer.concat(chunks).toString('utf8');
    console.log('\n========================================');
    console.log('✅ 返回结果：');
    try { console.log(JSON.stringify(JSON.parse(result), null, 2)); } catch { console.log(result); }
  });
});

req.on('error', e => console.error('❌ 请求失败：', e));
req.write(postData);
req.end();

Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)