Skill: fangshan101-coder/cashback (version 1.2.2)

--- name: cashback description: 海外品牌官方商城返利（cashback）助手。通过多麦联盟渠道，为指定海外商家的购物订单提供返利查询与转链服务，三个能力：粘贴商品链接生成返利短链、查询商家返利比例、查看个人返利订单。当前仅支持 Adidas、Space NK NL（荷兰站）、designwebstore DE（德国站）三家，不在清单中的海外商家暂未开通。当用户发来这三家商家的商品链接，或提到"Adidas/阿迪达斯返利"、"Space NK 返利"、"designwebstore 返利"、"cashback"、"海淘返利"、"我的返利订单"时使用。不适用于：清单外的任何商家（包括 Amazon/Nike/iHerb/eBay/Shein 等）、快递查询、汇率换算。 version: 1.2.2 allowed-tools: Bash(node {baseDir}/scripts/run.mjs:*),Read({baseDir}/**),Read({baseDir}/../fx-base/**) metadata: openclaw: requires: env: - FX_AI_API_KEY primaryEnv: FX_AI_API_KEY --- > **CRITICAL** — 开始前 **必须**用 Read 工具读取 [`../fx-base/SKILL.md`](../fx-base/SKILL.md)，其中包含 feima-lab API 认证和请求规范。 > > fx-base 未安装？执行 `npx skills install fangshan101-coder/fx-base` 安装到同目录下。 # 海外购物返利助手 3 个能力覆盖海外购物返利全流程：粘贴链接转链 → 搜商家问返利 → 查返利订单。 ## 当前支持商家 | 商家名（`--store` 参数必须用此值）| 支持地区 | 域名匹配 | 用户可能的叫法 | |---|---|---|---| | `Adidas` | 全球/中国 | `*.adidas.com` / `*.adidas.cn` / `*.adidas.de` / `*.adidas.co.uk` 等所有 adidas 官方域名 | 阿迪达斯 / 阿迪 / adidas / Adidas | | `Space NK NL` | 荷兰 | `*.spacenk.com`（通常含 `/nl/` 或 `/en_NL/` 路径）| space nk / spacenk / Space NK 荷兰站 | | `designwebstore DE` | 德国 | `designwebstore.de` | designwebstore / design web store / designwebstore 德国站 | > **重要**：商家清单由多麦联盟后端决定，**不在上表中的商家一律不支持**（包括 Amazon、Nike、iHerb、eBay、Shein 等）。用户问清单外商家时直接告知暂不支持，**不要调 API 硬查**。 > > **商家名映射**：用户口头叫法（如"阿迪达斯"）必须先映射到左列的精确值（`Adidas`）再传给 `--store` 参数，否则 API 会返回 `store_not_found`。 ## 前置条件 - 环境变量 `FX_AI_API_KEY`：从 [feima-lab 开放平台](https://platform.feima.ai/) 登录获取。未设置时脚本会返回 `missing_api_key` 错误 - **数据流向**：用户提供的链接和查询会被发送到 `https://api-ai-brain.fenxianglife.com` 处理，请确保信任该服务后再使用 ## 快速开始 ```bash # 快捷命令（推荐，Claude 默认用这组） node {baseDir}/scripts/run.mjs convert "https://www.adidas.com/us/ultraboost-5-shoes/ID8841.html" node {baseDir}/scripts/run.mjs store "Adidas" node {baseDir}/scripts/run.mjs orders # 等价的标准调用（开发者调试用） node {baseDir}/scripts/run.mjs call link-convert --url "<URL>" node {baseDir}/scripts/run.mjs call store-rebate --store "Space NK NL" node {baseDir}/scripts/run.mjs call order-query --days 30 ``` ## 路由决策 | 用户意图 | 命令 | 渲染模板 | |---------|------|---------| | 发商品链接、要返利链接 | `run.mjs convert "<URL>"` | Read `{baseDir}/references/link-convert-output.md` | | 问某商家有没有返利、返利多少 | `run.mjs store "<精确商家名>"` | Read `{baseDir}/references/store-rebate-output.md` | | 查我的返利、我的订单 | `run.mjs orders` 或 `run.mjs orders --days N` | Read `{baseDir}/references/order-query-output.md` | ## 链接归属判断 调用接口前，**必须**先用域名/商家名判断是否在服务范围，避免无效 API 调用： | 输入类型 | 判断依据 | 动作 | |---------|---------|------| | 商品链接 | 域名匹配「支持商家表」的"域名匹配"列 | 调用 `convert` | | 商品链接 | 域名**不匹配**表中任何商家 | **不调 API**，告知"该商家暂未开通返利，目前仅支持 Adidas、Space NK NL、designwebstore DE 三家" | | 商家名 | 对照"用户可能的叫法"列，能映射到精确商家名 | 用映射后的值调用 `store` | | 商家名 | 无法映射到上表任何商家 | **不调 API**，告知同上 | | 查订单 | 直接调用，无需判断 | 调用 `orders` | ## 工作流 多接口 skill 必须**渐进式输出**——先告诉用户"正在查询"，不要等到 API 返回才出声： ``` Step 1 立即输出："正在查询 {商家名/订单/链接}..."（不等 API 返回） ↓ Step 2 判断链接/商家是否在服务范围（见"链接归属判断"） ↓ 不在 → 告知不支持并结束 ↓ 在 → 继续 Step 3 调用对应接口（见"路由决策"） ↓ Step 4 拿到 JSON，Read 对应渲染模板，输出结果 ↓ Step 5 用户继续追问 → 回到 Step 1 ``` 没有链接时先问用户要。 ## 错误处理 | 现象 | 用户可见提示 | 兜底动作 | |------|-------------|---------| | 用户发清单外商家的链接或名字 | "该商家暂未开通返利，目前仅支持 Adidas、Space NK NL、designwebstore DE 三家" | **不调 API**，直接回复 | | `store_not_found`（清单内商家名拼错）| "没找到该商家，商家名应为：Adidas / Space NK NL / designwebstore DE" | 用精确名称重试；若用户同时给了链接，改走 `convert` | | `no_available_plan` | "该商家暂无可用返利计划" | 告知可能是临时下线，建议稍后重试 | | `no_orders` | "近 {days} 天暂无返利订单" | 提示"通过返利链接购物后，订单通常需要 1-3 天才会出现" | | `api_unavailable` / HTTP 错误 | "服务暂时不可用，请稍后重试" | 建议 1 分钟后重试 | | `missing_api_key` | "请设置环境变量 `FX_AI_API_KEY`" | 给出 [feima-lab 开放平台](https://platform.feima.ai/) 链接 | | `missing_parameter` | "请发一下商品链接 / 请告诉我要查哪个商家" | 引导用户补充参数 | ## 不适用场景 以下情况**不要**调用本 Skill： - 清单外的任何海外商家（Amazon/Nike/iHerb/eBay/Shein 等） - 国内电商（淘宝/京东/拼多多/抖音/唯品会/美团等） - 快递物流查询 - 汇率换算、天气查询 ## 兼容性 - Claude Code / Claude.ai / OpenClaw 本地节点 - Node.js 18+（内置 fetch，无额外依赖） - 脚本路径解析基于 `import.meta.url`，支持 symlink 安装 ## 环境依赖 - Node.js 18+ - 环境变量 `FX_AI_API_KEY`：从 [feima-lab 开放平台](https://platform.feima.ai/) 登录获取

path: README.md
content: # cashback

[![ClawHub](https://img.shields.io/badge/ClawHub-cashback-blue)](https://clawhub.ai/fangshan101-coder/cashback)

> 海外品牌官方商城返利助手。粘贴链接生成返利短链、查商家返利比例、看自己的返利订单。

## 安装

```bash
# 先安装公共基础
npx skills install fangshan101-coder/fx-base

# 再安装 cashback
npx skills install fangshan101-coder/cashback
```

> `cashback` 依赖 `fx-base`，两个必须装在同一个 `.claude/skills/` 目录下。

## 配置

使用前需设置 API Key 环境变量：

```bash
export FX_AI_API_KEY="your-api-key"
```

从 [feima-lab 开放平台](https://platform.feima.ai/) 登录获取 API Key。

建议将 `export` 加入 `~/.zshrc` 或 `~/.bashrc` 使其永久生效。

## 核心能力

- **链接转返利短链** — 粘贴支持商家的商品链接，生成带返利追踪的短链和佣金信息
- **商家返利查询** — 问"某商家有没有返利"，返回返利比例和返利入口链接
- **个人订单查询** — 查看近 N 天的返利订单列表、状态和预估返利汇总

## 当前支持商家

| 商家 | 支持地区 | 域名匹配 |
|------|---------|---------|
| **Adidas** | 全球/中国 | `*.adidas.com` / `*.adidas.cn` / `*.adidas.de` / `*.adidas.co.uk` 等 |
| **Space NK NL** | 荷兰 | `*.spacenk.com`（通常含 `/nl/` 路径）|
| **designwebstore DE** | 德国 | `designwebstore.de` |

> 商家清单由多麦联盟后端决定。清单外商家（如 Amazon/Nike/iHerb/eBay/Shein 等）暂未开通返利。

## 使用方式

直接发商品链接或问商家名，无需任何指令：

```
https://www.adidas.com/us/ultraboost-5-shoes/ID8841.html
Adidas 有返利吗
我的返利订单
```

也可以明确意图：

```
帮我生成这个链接的返利短链
Space NK 荷兰站返利多少
查近 7 天的返利订单
```

## 输出示例

### 链接转链

```
### 🌍 Adidas

| 项目 | 详情 |
|------|------|
| 商品 | Ultraboost 5 Shoes |
| 返利 | **最高6%** |
| 商家 | Adidas |

👉 返利链接：https://s.duomai.com/xxx
```

### 商家返利查询

```
### 🏪 Space NK NL

| 项目 | 详情 |
|------|------|
| 返利比例 | **最高8%** |
| 所属地区 | 荷兰 |
| 返利链接 | https://s.duomai.com/xxx |
```

### 订单查询

```
### 📋 近 30 天返利订单

**汇总**：共 3 笔订单，预估返利 **¥82.50**

| 商家 | 订单金额 | 预估返利 | 状态 | 下单时间 |
|------|---------|---------|------|---------|
| Adidas | ¥899.00 | ¥53.94 | 已确认 | 2026-03-25 |
| Space NK NL | €65.00 | €5.20 | 待确认 | 2026-04-01 |
```

## 环境依赖

- Node.js 18+
- 环境变量 `FX_AI_API_KEY`（见上方配置说明）
- 依赖 skill：`fx-base`（提供公共请求层）


path: references/link-convert-output.md
content: # link-convert 输出模板

拿到 JSON 后**直接按模板填充输出**。

## 输出模板

```
### 🌍 {storeName}

| 项目 | 详情 |
|------|------|
| 商品 | {productName} |
| 返利 | **{commission}** |
| 商家 | {storeName} · {country} |

👉 返利链接：{shortUrl}

> 原始链接：{originalUrl}
```

- `productName` 不存在时省略商品行
- `country` 不存在时只显示 `{storeName}`
- `logoUrl` 如果存在可加在标题下方：`![{storeName}]({logoUrl})`

## 完整示例

<example>
用户：帮我转一下 https://www.adidas.com/us/ultraboost-5-shoes/ID8841.html

助手：

正在生成返利链接...

[调用 node {baseDir}/scripts/run.mjs convert "https://www.adidas.com/us/ultraboost-5-shoes/ID8841.html"]

### 🌍 Adidas

| 项目 | 详情 |
|------|------|
| 商品 | Ultraboost 5 Shoes |
| 返利 | **最高6%** |
| 商家 | Adidas |

👉 返利链接：https://s.duomai.com/xxx

> 原始链接：https://www.adidas.com/us/ultraboost-5-shoes/ID8841.html
</example>

<example>
用户：https://www.spacenk.com/nl/en_NL/skincare/xxx

助手：

正在生成返利链接...

[调用 node {baseDir}/scripts/run.mjs convert "https://www.spacenk.com/nl/en_NL/skincare/xxx"]

### 🌍 Space NK NL

| 项目 | 详情 |
|------|------|
| 返利 | **最高8%** |
| 商家 | Space NK NL · 荷兰 |

👉 返利链接：https://s.duomai.com/xxx

> 原始链接：https://www.spacenk.com/nl/en_NL/skincare/xxx
</example>

<example>
用户：帮我转一下 https://www.amazon.com/dp/B0xxxxx

助手：

该商家暂未开通返利，目前仅支持 Adidas、Space NK NL、designwebstore DE 三家。
</example>


path: references/order-query-output.md
content: # order-query 输出模板

拿到 JSON 后**直接按模板填充输出**。返回结构：`summary`（汇总）+ `orders`（订单列表）。

## 输出模板

```
### 📋 近 {days} 天返利订单

**汇总**：共 {summary.totalOrders} 笔订单，预估返利 **{summary.totalCommission}**

| 商家 | 订单金额 | 预估返利 | 状态 | 下单时间 |
|------|---------|---------|------|---------|
| {storeName} | {orderAmount} | {commission} | {status} | {orderTime} |
```

## 状态映射

渲染时把 API 状态值转成中文：

| API 状态值 | 用户可见 |
|-----------|---------|
| `pending` | 待确认 |
| `confirmed` | 已确认 |
| `paid` | 已到账 |
| `rejected` | 已拒绝 |

## 空订单处理

`orders` 为空或不存在时输出：

```
近 {days} 天暂无返利订单。

💡 通过返利链接购物后，订单通常需要 1-3 天才会出现在这里。
```

## 完整示例

<example>
用户：我的返利订单

助手：

正在查询返利订单...

[调用 node {baseDir}/scripts/run.mjs orders]

### 📋 近 30 天返利订单

**汇总**：共 3 笔订单，预估返利 **¥82.50**

| 商家 | 订单金额 | 预估返利 | 状态 | 下单时间 |
|------|---------|---------|------|---------|
| Adidas | ¥899.00 | ¥53.94 | 已确认 | 2026-03-25 |
| Space NK NL | €65.00 | €5.20 | 待确认 | 2026-04-01 |
| designwebstore DE | €120.00 | €8.40 | 待确认 | 2026-04-05 |
</example>

<example>
用户：最近有返利到账吗

助手：

正在查询返利订单...

[调用 node {baseDir}/scripts/run.mjs orders]

近 30 天暂无返利订单。

💡 通过返利链接购物后，订单通常需要 1-3 天才会出现在这里。
</example>


path: references/store-rebate-output.md
content: # store-rebate 输出模板

拿到 JSON 后**直接按模板填充输出**。

## 输出模板

```
### 🏪 {storeName}

{logoUrl 存在 → ![{storeName}]({logoUrl})}

| 项目 | 详情 |
|------|------|
| 返利比例 | **{commission}** |
| 所属地区 | {country} |
| 返利链接 | {shortUrl} |

通过上方返利链接进入 {storeName} 购物，订单确认后即可获得返利。
```

- `logoUrl` 不存在时省略图片行
- `country` 不存在时省略所属地区行
- `shortUrl` 不存在时省略返利链接行，并提示"该商家暂无可用返利计划"

## 完整示例

<example>
用户：Adidas 有返利吗？

助手：

正在查询 Adidas 的返利信息...

[调用 node {baseDir}/scripts/run.mjs store "Adidas"]

### 🏪 Adidas

| 项目 | 详情 |
|------|------|
| 返利比例 | **最高6%** |
| 返利链接 | https://s.duomai.com/xxx |

通过上方返利链接进入 Adidas 购物，订单确认后即可获得返利。
</example>

<example>
用户：Space NK 荷兰站返利多少？

助手：

正在查询 Space NK NL 的返利信息...

[调用 node {baseDir}/scripts/run.mjs store "Space NK NL"]

### 🏪 Space NK NL

| 项目 | 详情 |
|------|------|
| 返利比例 | **最高8%** |
| 所属地区 | 荷兰 |
| 返利链接 | https://s.duomai.com/xxx |

通过上方返利链接进入 Space NK NL 购物，订单确认后即可获得返利。
</example>

<example>
用户：iHerb 有返利吗？

助手：

该商家暂未开通返利，目前仅支持 Adidas、Space NK NL、designwebstore DE 三家。
</example>


path: scripts/link-convert.mjs
content: #!/usr/bin/env node
// name: link-convert
// description: 海外商品链接转返利短链，返回佣金信息和推广链接

import { fileURLToPath } from 'url';
import { join, dirname } from 'path';
import { existsSync } from 'fs';

// ── 加载公共库 ──
const _scriptDir = dirname(fileURLToPath(import.meta.url));
const _fxApiPath = join(_scriptDir, '../../fx-base/scripts/fx-api.mjs');
if (!existsSync(_fxApiPath)) {
  process.stderr.write(
    '{"status":"error","error_type":"missing_dependency","suggestion":"缺少 fx-base，请安装：npx skills install fangshan101-coder/fx-base"}\n'
  );
  process.exit(1);
}

const { fxCheckAuth, fxPost } = await import(_fxApiPath);

function help() {
  process.stdout.write(`用法: link-convert --url <海外商品链接> [选项]

必填:
  --url <链接>                    海外商品链接（Amazon/Nike/iHerb/adidas 等）

选项:
  --format json|table              输出格式（默认 json）
  --help                           显示此帮助

示例:
  link-convert --url "https://www.amazon.com/dp/B0xxxxx"
  link-convert --url "https://www.nike.com/t/air-max-90-mens-shoes-xxx"
  link-convert --url "https://www.iherb.com/pr/xxx" --format table

数据流向: 商品链接会被发送到 https://api-ai-brain.fenxianglife.com 进行转链
`);
  process.exit(0);
}

// ── 参数解析 ──
const args = process.argv.slice(2);
let url = '';
let format = 'json';

for (let i = 0; i < args.length; i++) {
  switch (args[i]) {
    case '--help':
    case '-h':
      help();
      break;
    case '--url':
      url = args[++i] || '';
      break;
    case '--format':
      format = args[++i] || 'json';
      break;
  }
}

if (!url) {
  process.stderr.write(
    '{"status":"error","error_type":"missing_parameter","missing":"url","suggestion":"请提供海外商品链接，例如 --url https://www.amazon.com/dp/B0xxxxx"}\n'
  );
  process.exit(1);
}

fxCheckAuth();

const body = { url };

const respText = await fxPost('skill/api/overseas/link-convert', body, '转链服务暂时不可用，请稍后重试');

let resp;
try {
  resp = JSON.parse(respText);
} catch (e) {
  process.stderr.write('{"status":"error","error_type":"api_unavailable","suggestion":"响应解析失败"}\n');
  process.exit(1);
}

const data = resp.data !== undefined ? resp.data : resp;

if (resp.code === 200 && data) {
  if (format === 'table') {
    for (const [k, v] of Object.entries(data)) {
      if (v !== null && v !== '' && v !== false) {
        process.stdout.write(`${k}: ${typeof v === 'object' ? JSON.stringify(v) : v}\n`);
      }
    }
  } else {
    process.stdout.write(JSON.stringify(data, null, 2) + '\n');
  }
} else {
  const msg = resp.message || '转链失败';
  const err = (data && typeof data === 'object' && data.errorMessage) ? data.errorMessage : msg;
  process.stdout.write(
    JSON.stringify({ status: 'error', message: err, suggestion: '请检查链接是否正确，确认是海外商家链接' }, null, 2) + '\n'
  );
}


path: scripts/order-query.mjs
content: #!/usr/bin/env node
// name: order-query
// description: 查询海外返利订单列表和金额汇总

import { fileURLToPath } from 'url';
import { join, dirname } from 'path';
import { existsSync } from 'fs';

// ── 加载公共库 ──
const _scriptDir = dirname(fileURLToPath(import.meta.url));
const _fxApiPath = join(_scriptDir, '../../fx-base/scripts/fx-api.mjs');
if (!existsSync(_fxApiPath)) {
  process.stderr.write(
    '{"status":"error","error_type":"missing_dependency","suggestion":"缺少 fx-base，请安装：npx skills install fangshan101-coder/fx-base"}\n'
  );
  process.exit(1);
}

const { fxCheckAuth, fxPost } = await import(_fxApiPath);

function help() {
  process.stdout.write(`用法: order-query [选项]

选项:
  --days <天数>                    查询最近几天的订单（默认 30）
  --format json|table              输出格式（默认 json）
  --help                           显示此帮助

示例:
  order-query                      # 查询最近30天订单
  order-query --days 7             # 查询最近7天订单
  order-query --days 90 --format table

数据流向: 订单查询会被发送到 https://api-ai-brain.fenxianglife.com 进行查询
`);
  process.exit(0);
}

// ── 参数解析 ──
const args = process.argv.slice(2);
let days = 30;
let format = 'json';

for (let i = 0; i < args.length; i++) {
  switch (args[i]) {
    case '--help':
    case '-h':
      help();
      break;
    case '--days':
      days = parseInt(args[++i] || '30', 10) || 30;
      break;
    case '--format':
      format = args[++i] || 'json';
      break;
  }
}

fxCheckAuth();

const body = { days };

const respText = await fxPost('skill/api/overseas/order-query', body, '订单查询服务暂时不可用，请稍后重试');

let resp;
try {
  resp = JSON.parse(respText);
} catch (e) {
  process.stderr.write('{"status":"error","error_type":"api_unavailable","suggestion":"响应解析失败"}\n');
  process.exit(1);
}

const data = resp.data !== undefined ? resp.data : resp;

if (resp.code === 200 && data) {
  if (format === 'table') {
    // 汇总信息
    if (data.summary) {
      process.stdout.write('--- 汇总 ---\n');
      for (const [k, v] of Object.entries(data.summary)) {
        process.stdout.write(`${k}: ${v}\n`);
      }
      process.stdout.write('\n');
    }
    // 订单列表
    if (data.orders && data.orders.length > 0) {
      process.stdout.write('--- 订单列表 ---\n');
      for (const order of data.orders) {
        for (const [k, v] of Object.entries(order)) {
          if (v !== null && v !== '' && v !== false) {
            process.stdout.write(`${k}: ${v}\n`);
          }
        }
        process.stdout.write('---\n');
      }
    }
  } else {
    process.stdout.write(JSON.stringify(data, null, 2) + '\n');
  }
} else {
  const msg = resp.message || '查询失败';
  const err = (data && typeof data === 'object' && data.errorMessage) ? data.errorMessage : msg;
  process.stdout.write(
    JSON.stringify({ status: 'error', message: err, suggestion: '订单查询失败，请稍后重试' }, null, 2) + '\n'
  );
}


path: scripts/run.mjs
content: #!/usr/bin/env node
// 统一执行引擎：调度脚本，支持快捷命令和标准调用

import { fileURLToPath } from 'url';
import { join, dirname } from 'path';
import { readdirSync, readFileSync, existsSync } from 'fs';
import { spawn } from 'child_process';

const _scriptDir = dirname(fileURLToPath(import.meta.url));

function usage() {
  process.stdout.write(`用法:
  快捷命令（推荐）:
    run.mjs convert "<海外商品链接>"          # 链接转返利短链
    run.mjs store "<商家名>"                 # 查商家返利
    run.mjs orders                           # 查返利订单（默认30天）
    run.mjs orders --days 7                  # 查最近7天订单

  标准调用:
    run.mjs call <接口名> [参数...]            # 调用指定接口
    run.mjs call link-convert --help          # 查看接口帮助

  辅助:
    run.mjs list                              # 列出所有可用接口
    run.mjs show <接口名>                     # 查看接口源码

数据流向: 链接和查询会被发送到 https://api-ai-brain.fenxianglife.com 进行处理
`);
}

function runScript(scriptPath, args) {
  return new Promise((_resolve, reject) => {
    const child = spawn(process.execPath, [scriptPath, ...args], {
      stdio: 'inherit',
      env: process.env,
    });
    child.on('close', (code) => {
      process.exit(code ?? 0);
    });
    child.on('error', reject);
  });
}

const args = process.argv.slice(2);
const cmd = args[0] || '';

switch (cmd) {
  case '--help':
  case '-h':
    usage();
    break;

  case 'list': {
    process.stdout.write('可用接口：\n');
    const files = readdirSync(_scriptDir)
      .filter(f => f.endsWith('.mjs') && f !== 'run.mjs')
      .sort();
    if (files.length === 0) {
      process.stdout.write('  (暂无接口)\n');
      break;
    }
    const rows = files.map(f => {
      const name = f.replace(/\.mjs$/, '');
      let desc = '';
      const content = readFileSync(join(_scriptDir, f), 'utf8');
      const m = content.match(/^\/\/\s*description:\s*(.+)/m);
      if (m) desc = m[1].trim();
      return [name, desc];
    });
    const w0 = Math.max(...rows.map(r => r[0].length));
    for (const [name, desc] of rows) {
      process.stdout.write(`  ${name.padEnd(w0)}  ${desc}\n`);
    }
    break;
  }

  case 'show': {
    const name = args[1] || '';
    if (!name) {
      process.stderr.write('错误: 请指定接口名\n');
      process.exit(1);
    }
    const mjsFile = join(_scriptDir, `${name}.mjs`);
    if (!existsSync(mjsFile)) {
      process.stderr.write(`错误: 接口 '${name}' 不存在\n`);
      process.exit(1);
    }
    process.stdout.write(readFileSync(mjsFile, 'utf8'));
    break;
  }

  case 'call': {
    const name = args[1] || '';
    if (!name) {
      process.stderr.write('错误: 请指定接口名\n');
      process.exit(1);
    }
    const mjsFile = join(_scriptDir, `${name}.mjs`);
    if (!existsSync(mjsFile)) {
      process.stderr.write(`错误: 接口 '${name}' 不存在，运行 'node run.mjs list' 查看可用接口\n`);
      process.exit(1);
    }
    await runScript(mjsFile, args.slice(2));
    break;
  }

  // 快捷命令：run.mjs convert "<链接>" → call link-convert --url "<链接>"
  case 'convert': {
    const url = args[1] || '';
    if (!url) {
      process.stderr.write('错误: 请提供海外商品链接，例如 run.mjs convert "https://www.amazon.com/dp/B0xxxxx"\n');
      process.exit(1);
    }
    const script = join(_scriptDir, 'link-convert.mjs');
    await runScript(script, ['--url', url, ...args.slice(2)]);
    break;
  }

  // 快捷命令：run.mjs store "<商家名>" → call store-rebate --store "<商家名>"
  case 'store': {
    const store = args[1] || '';
    if (!store) {
      process.stderr.write('错误: 请提供商家名称，例如 run.mjs store "iHerb"\n');
      process.exit(1);
    }
    const script = join(_scriptDir, 'store-rebate.mjs');
    await runScript(script, ['--store', store, ...args.slice(2)]);
    break;
  }

  // 快捷命令：run.mjs orders [--days N] → call order-query [--days N]
  case 'orders': {
    const script = join(_scriptDir, 'order-query.mjs');
    await runScript(script, args.slice(1));
    break;
  }

  default:
    usage();
    break;
}


path: scripts/store-rebate.mjs
content: #!/usr/bin/env node
// name: store-rebate
// description: 搜索海外商家，查询返利比例和佣金计划，生成返利链接

import { fileURLToPath } from 'url';
import { join, dirname } from 'path';
import { existsSync } from 'fs';

// ── 加载公共库 ──
const _scriptDir = dirname(fileURLToPath(import.meta.url));
const _fxApiPath = join(_scriptDir, '../../fx-base/scripts/fx-api.mjs');
if (!existsSync(_fxApiPath)) {
  process.stderr.write(
    '{"status":"error","error_type":"missing_dependency","suggestion":"缺少 fx-base，请安装：npx skills install fangshan101-coder/fx-base"}\n'
  );
  process.exit(1);
}

const { fxCheckAuth, fxPost } = await import(_fxApiPath);

function help() {
  process.stdout.write(`用法: store-rebate --store <商家名> [选项]

必填:
  --store <商家名>                 海外商家名称（如 iHerb、Nike、Amazon）

选项:
  --format json|table              输出格式（默认 json）
  --help                           显示此帮助

示例:
  store-rebate --store "iHerb"
  store-rebate --store "Nike"
  store-rebate --store "Amazon" --format table

数据流向: 商家查询会被发送到 https://api-ai-brain.fenxianglife.com 进行搜索
`);
  process.exit(0);
}

// ── 参数解析 ──
const args = process.argv.slice(2);
let storeName = '';
let format = 'json';

for (let i = 0; i < args.length; i++) {
  switch (args[i]) {
    case '--help':
    case '-h':
      help();
      break;
    case '--store':
      storeName = args[++i] || '';
      break;
    case '--format':
      format = args[++i] || 'json';
      break;
  }
}

if (!storeName) {
  process.stderr.write(
    '{"status":"error","error_type":"missing_parameter","missing":"store","suggestion":"请提供商家名称，例如 --store iHerb"}\n'
  );
  process.exit(1);
}

fxCheckAuth();

const body = { storeName };

const respText = await fxPost('skill/api/overseas/store-rebate', body, '商家查询服务暂时不可用，请稍后重试');

let resp;
try {
  resp = JSON.parse(respText);
} catch (e) {
  process.stderr.write('{"status":"error","error_type":"api_unavailable","suggestion":"响应解析失败"}\n');
  process.exit(1);
}

const data = resp.data !== undefined ? resp.data : resp;

if (resp.code === 200 && data) {
  if (format === 'table') {
    for (const [k, v] of Object.entries(data)) {
      if (v !== null && v !== '' && v !== false) {
        process.stdout.write(`${k}: ${typeof v === 'object' ? JSON.stringify(v) : v}\n`);
      }
    }
  } else {
    process.stdout.write(JSON.stringify(data, null, 2) + '\n');
  }
} else {
  const msg = resp.message || '查询失败';
  const err = (data && typeof data === 'object' && data.errorMessage) ? data.errorMessage : msg;
  process.stdout.write(
    JSON.stringify({ status: 'error', message: err, suggestion: '请检查商家名称是否正确' }, null, 2) + '\n'
  );
}


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