@optima-chat/dev-skills 0.9.3 → 0.11.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/.claude/commands/trace-user.md +270 -208
- package/.claude/skills/account/SKILL.md +1 -1
- package/.claude/skills/entitlement/SKILL.md +1 -1
- package/.claude/skills/grant-credits/SKILL.md +66 -0
- package/.claude/skills/grant-subscription/SKILL.md +1 -1
- package/.codex/skills/account/SKILL.md +1 -1
- package/.codex/skills/entitlement/SKILL.md +1 -1
- package/.codex/skills/grant-credits/SKILL.md +66 -0
- package/AGENTS.md +2 -2
- package/README.md +2 -2
- package/bin/cli.js +2 -2
- package/bin/helpers/billing-http.ts +1 -1
- package/bin/helpers/grant-credits.ts +119 -0
- package/bin/helpers/grant-subscription.ts +1 -1
- package/dist/bin/helpers/billing-http.js +1 -1
- package/dist/bin/helpers/grant-credits.js +104 -0
- package/dist/bin/helpers/grant-subscription.js +1 -1
- package/package.json +3 -2
- package/.claude/skills/grant-balance/SKILL.md +0 -106
- package/.codex/skills/grant-balance/SKILL.md +0 -104
- package/bin/helpers/grant-balance.ts +0 -85
- package/dist/bin/helpers/grant-balance.js +0 -79
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "grant-credits"
|
|
3
|
+
description: "当用户请求赠送积分、发放积分、加积分、grant credits、充值积分、赠送余额(旧称)、奖励、补偿、推荐奖励、运营发放时,使用此技能。支持 Stage、Prod、cn-prod、cn-stage 四个环境;标识符支持邮箱/手机号/userId。"
|
|
4
|
+
allowed-tools: ["Bash"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 发放积分(Grant Credits)
|
|
8
|
+
|
|
9
|
+
为用户赠送积分(**bonus 积分桶,30 天有效期**)。经 billing 服务态端点 `POST /api/billing/admin/grant-credits` 入账,扣费时优先消费。
|
|
10
|
+
|
|
11
|
+
> **命名历史**:本命令原名 `grant-credits`(按积分)→ 余额时代曾改名 `grant-balance` + 改吃 USD → P15 钱包退役回归积分后改回 `grant-credits` + `--credits` 原生按积分。`optima-grant-balance` 仍作**废弃别名**保留(会打弃用提示)。
|
|
12
|
+
|
|
13
|
+
## 执行方式:使用 CLI 工具
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
optima-grant-credits <email|phone|userId> --credits <n> [options]
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**为什么用 CLI**:自动通过 email/手机号/userId 查 userId(cn 走 HTTP lookup、AWS 走 SSH 隧道)+ 执行前打印 `🎯 目标账号` 反查 + 留审计痕迹(credit_lot,幂等键前缀 `dev-skills-grant:`)+ 不影响订阅和已有积分(纯累加 bonus 桶)。
|
|
20
|
+
|
|
21
|
+
### 参数
|
|
22
|
+
|
|
23
|
+
| 参数 | 说明 | 默认 |
|
|
24
|
+
|------|------|------|
|
|
25
|
+
| `<email\|phone\|userId>` | 用户标识(必填;cn 支持手机号/userId) | - |
|
|
26
|
+
| `--credits <n>` | **赠送积分数(整数 ≥1,主单位)** | - |
|
|
27
|
+
| `--amount <usd>` | 备选:按 USD 赠送($1 = 700 积分)。`--credits` / `--amount` **二选一** | - |
|
|
28
|
+
| `--description <text>` | 描述/原因(存入 credit lot(审计痕迹)) | - |
|
|
29
|
+
| `--env <env>` | stage, prod, cn-prod, cn-stage | stage |
|
|
30
|
+
|
|
31
|
+
## 快速操作
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# 送 10000 积分(Prod)
|
|
35
|
+
optima-grant-credits user@example.com --credits 10000 --env prod
|
|
36
|
+
|
|
37
|
+
# cn-prod 手机号用户送 5000 积分
|
|
38
|
+
optima-grant-credits 18898654855 --credits 5000 --env cn-prod
|
|
39
|
+
|
|
40
|
+
# 按 USD 送(= 3500 积分),补偿场景
|
|
41
|
+
optima-grant-credits user@example.com --amount 5 --description "服务中断补偿" --env prod
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
> 单位默认是**积分**。要按美元用 `--amount`($1=700 积分)。两者只能给一个。
|
|
45
|
+
|
|
46
|
+
## 适用场景
|
|
47
|
+
奖励/活动、客户补偿、推荐奖励、内部测试账户充值。
|
|
48
|
+
|
|
49
|
+
## 与 grant-subscription 的区别
|
|
50
|
+
|
|
51
|
+
| | grant-credits | grant-subscription |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| 作用 | 追加 bonus 积分(30 天) | 开通/切换订阅计划 |
|
|
54
|
+
| 现有积分 | 不影响(纯累加) | 重置 granted |
|
|
55
|
+
| 现有订阅 | 不影响 | 取消旧的、建新的 |
|
|
56
|
+
| 适用 | 奖励、补偿、推广 | 开会员、升级计划 |
|
|
57
|
+
|
|
58
|
+
## 安全提醒
|
|
59
|
+
1. **Prod / cn-prod 谨慎**:执行前确认打印的 `🎯 目标账号`(手机/email/userId)与积分数。
|
|
60
|
+
2. **纯追加**:不影响现有积分和订阅;重复执行会叠加。
|
|
61
|
+
3. **30 天有效期**:bonus 桶到期作废。
|
|
62
|
+
|
|
63
|
+
## 相关命令
|
|
64
|
+
- `optima-grant-subscription` - 开通订阅
|
|
65
|
+
- `optima-account status` - 查用户订阅+权益
|
|
66
|
+
- `optima-query-db` / billing `GET /api/billing/balance` - 核对积分余额
|
|
@@ -56,6 +56,6 @@ optima-account unban 18898654855 --env cn-prod
|
|
|
56
56
|
|
|
57
57
|
## 相关命令
|
|
58
58
|
|
|
59
|
-
- `optima-grant-subscription` / `optima-grant-
|
|
59
|
+
- `optima-grant-subscription` / `optima-grant-credits` - 开通会员 / 赠送积分
|
|
60
60
|
- `optima-entitlement` - 产品权益授予/撤销/查询
|
|
61
61
|
- `optima-query-db` - 直查数据库核对(如 `is_active` / `banned_at`)
|
|
@@ -52,4 +52,4 @@ optima-entitlement revoke user@example.com --product-key scout-gift --reason "
|
|
|
52
52
|
## 相关命令
|
|
53
53
|
|
|
54
54
|
- `optima-account status` - 查看用户订阅+权益汇总
|
|
55
|
-
- `optima-grant-subscription` / `optima-grant-
|
|
55
|
+
- `optima-grant-subscription` / `optima-grant-credits` - 开通会员 / 赠送积分
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "grant-credits"
|
|
3
|
+
description: "当用户请求赠送积分、发放积分、加积分、grant credits、充值积分、赠送余额(旧称)、奖励、补偿、推荐奖励、运营发放时,使用此技能。支持 Stage、Prod、cn-prod、cn-stage 四个环境;标识符支持邮箱/手机号/userId。"
|
|
4
|
+
allowed-tools: ["Bash"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 发放积分(Grant Credits)
|
|
8
|
+
|
|
9
|
+
为用户赠送积分(**bonus 积分桶,30 天有效期**)。经 billing 服务态端点 `POST /api/billing/admin/grant-credits` 入账,扣费时优先消费。
|
|
10
|
+
|
|
11
|
+
> **命名历史**:本命令原名 `grant-credits`(按积分)→ 余额时代曾改名 `grant-balance` + 改吃 USD → P15 钱包退役回归积分后改回 `grant-credits` + `--credits` 原生按积分。`optima-grant-balance` 仍作**废弃别名**保留(会打弃用提示)。
|
|
12
|
+
|
|
13
|
+
## 执行方式:使用 CLI 工具
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
optima-grant-credits <email|phone|userId> --credits <n> [options]
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**为什么用 CLI**:自动通过 email/手机号/userId 查 userId(cn 走 HTTP lookup、AWS 走 SSH 隧道)+ 执行前打印 `🎯 目标账号` 反查 + 留审计痕迹(credit_lot,幂等键前缀 `dev-skills-grant:`)+ 不影响订阅和已有积分(纯累加 bonus 桶)。
|
|
20
|
+
|
|
21
|
+
### 参数
|
|
22
|
+
|
|
23
|
+
| 参数 | 说明 | 默认 |
|
|
24
|
+
|------|------|------|
|
|
25
|
+
| `<email\|phone\|userId>` | 用户标识(必填;cn 支持手机号/userId) | - |
|
|
26
|
+
| `--credits <n>` | **赠送积分数(整数 ≥1,主单位)** | - |
|
|
27
|
+
| `--amount <usd>` | 备选:按 USD 赠送($1 = 700 积分)。`--credits` / `--amount` **二选一** | - |
|
|
28
|
+
| `--description <text>` | 描述/原因(存入 credit lot(审计痕迹)) | - |
|
|
29
|
+
| `--env <env>` | stage, prod, cn-prod, cn-stage | stage |
|
|
30
|
+
|
|
31
|
+
## 快速操作
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# 送 10000 积分(Prod)
|
|
35
|
+
optima-grant-credits user@example.com --credits 10000 --env prod
|
|
36
|
+
|
|
37
|
+
# cn-prod 手机号用户送 5000 积分
|
|
38
|
+
optima-grant-credits 18898654855 --credits 5000 --env cn-prod
|
|
39
|
+
|
|
40
|
+
# 按 USD 送(= 3500 积分),补偿场景
|
|
41
|
+
optima-grant-credits user@example.com --amount 5 --description "服务中断补偿" --env prod
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
> 单位默认是**积分**。要按美元用 `--amount`($1=700 积分)。两者只能给一个。
|
|
45
|
+
|
|
46
|
+
## 适用场景
|
|
47
|
+
奖励/活动、客户补偿、推荐奖励、内部测试账户充值。
|
|
48
|
+
|
|
49
|
+
## 与 grant-subscription 的区别
|
|
50
|
+
|
|
51
|
+
| | grant-credits | grant-subscription |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| 作用 | 追加 bonus 积分(30 天) | 开通/切换订阅计划 |
|
|
54
|
+
| 现有积分 | 不影响(纯累加) | 重置 granted |
|
|
55
|
+
| 现有订阅 | 不影响 | 取消旧的、建新的 |
|
|
56
|
+
| 适用 | 奖励、补偿、推广 | 开会员、升级计划 |
|
|
57
|
+
|
|
58
|
+
## 安全提醒
|
|
59
|
+
1. **Prod / cn-prod 谨慎**:执行前确认打印的 `🎯 目标账号`(手机/email/userId)与积分数。
|
|
60
|
+
2. **纯追加**:不影响现有积分和订阅;重复执行会叠加。
|
|
61
|
+
3. **30 天有效期**:bonus 桶到期作废。
|
|
62
|
+
|
|
63
|
+
## 相关命令
|
|
64
|
+
- `optima-grant-subscription` - 开通订阅
|
|
65
|
+
- `optima-account status` - 查用户订阅+权益
|
|
66
|
+
- `optima-query-db` / billing `GET /api/billing/balance` - 核对积分余额
|
package/AGENTS.md
CHANGED
|
@@ -10,7 +10,7 @@ Prefer the installed CLI tools over reimplementing long shell workflows:
|
|
|
10
10
|
- `optima-show-env <service> <stage|prod> [options]`
|
|
11
11
|
- `optima-generate-test-token [options]`
|
|
12
12
|
- `optima-grant-subscription <email> [options]`
|
|
13
|
-
- `optima-grant-
|
|
13
|
+
- `optima-grant-credits <email|phone|userId> --credits <n> [options]`
|
|
14
14
|
- `optima-product <create|update|add-channel|toggle-channel|show> [options]` — manage paid-plugin marketplace Products + Stripe channels (Wave 1.5 admin endpoints; stage default)
|
|
15
15
|
- `optima-entitlement <grant|revoke|list> [options]` — admin-grant / revoke / list paid-plugin entitlements (refuses revoke of PAYMENT / PARTNER source)
|
|
16
16
|
- `optima-plugin <show|set-paid|set-default> [options]` — flip a plugin's skills-side paid/free state (isPaid) + defaultForUser (the user-facing gate; pairs with optima-product for the billing side)
|
|
@@ -27,7 +27,7 @@ After `npm install -g @optima-chat/dev-skills`, this package installs skills und
|
|
|
27
27
|
- `generate-test-token`
|
|
28
28
|
- `read-code`
|
|
29
29
|
- `grant-subscription`
|
|
30
|
-
- `grant-
|
|
30
|
+
- `grant-credits`
|
|
31
31
|
- `restart-ecs`
|
|
32
32
|
- `use-commerce-cli`
|
|
33
33
|
|
package/README.md
CHANGED
|
@@ -106,11 +106,11 @@ Claude:
|
|
|
106
106
|
| `optima-generate-test-token` | 生成测试 token | `optima-generate-test-token --business-name "测试店铺"` |
|
|
107
107
|
| `optima-discount` | 优惠码管理 | `optima-discount create --code LAUNCH20 --percent 20 --env stage` |
|
|
108
108
|
| `optima-grant-subscription` | 开通/切换订阅 | `optima-grant-subscription 18898654855 --plan pro-cn --env cn-prod` |
|
|
109
|
-
| `optima-grant-
|
|
109
|
+
| `optima-grant-credits` | 赠送积分 | `optima-grant-credits user@example.com --credits 10000 --env prod`(`optima-grant-balance` 为废弃别名)|
|
|
110
110
|
| `optima-entitlement` | 产品权益 grant/revoke/list | `optima-entitlement grant 18898654855 --product-key scout-gift --justification "..." --env cn-prod` |
|
|
111
111
|
| `optima-account` | 账号 status/ban/unban | `optima-account ban user@example.com --reason "abuse" --env prod` |
|
|
112
112
|
|
|
113
|
-
> **4 环境 + 标识符**:`grant-subscription` / `grant-
|
|
113
|
+
> **4 环境 + 标识符**:`grant-subscription` / `grant-credits` / `entitlement` / `account` 均支持 `stage` / `prod` / `cn-prod` / `cn-stage`。标识符 `<email\|phone\|userId>`——**cn-prod / cn-stage 用户多为手机号注册**,三种均可;AWS stage/prod 仅 email。`ban`/`unban` 及 `account status` 的禁用态读取需 admin-用户凭证(Infisical `/shared-secrets/credentials`;cn 另需 `INFISICAL_CN_EMAIL/PASSWORD`)。
|
|
114
114
|
|
|
115
115
|
**特点**:
|
|
116
116
|
- ✅ 支持 CI、Stage、Prod 三个环境(query-db)
|
package/bin/cli.js
CHANGED
|
@@ -34,7 +34,7 @@ switch (command) {
|
|
|
34
34
|
log(' optima-show-env <service> [env] Show service env vars', 'cyan');
|
|
35
35
|
log(' optima-verify-health <service> [--env cn|prod|all] Probe L1-L5 上线健康', 'cyan');
|
|
36
36
|
log(' optima-generate-test-token [--env production] Generate test token', 'cyan');
|
|
37
|
-
log(' optima-grant-
|
|
37
|
+
log(' optima-grant-credits <email|phone|userId> --credits <n> [--env] Grant credits (bonus, 30d)', 'cyan');
|
|
38
38
|
log(' optima-grant-subscription <email|phone|userId> --plan <p> [--env] Grant subscription', 'cyan');
|
|
39
39
|
log(' optima-logs <service> [--env] [--since] [--grep] [-n] View logs (cn=SLS 直连/aws=CloudWatch)', 'cyan');
|
|
40
40
|
log(' /restart-ecs <service> [env] Restart ECS service (skill)', 'cyan');
|
|
@@ -49,7 +49,7 @@ switch (command) {
|
|
|
49
49
|
log('\nExamples:', 'yellow');
|
|
50
50
|
log(' /logs commerce-backend 100 prod', 'cyan');
|
|
51
51
|
log(' optima-query-db user-auth "SELECT COUNT(*) FROM users" prod', 'cyan');
|
|
52
|
-
log(' optima-grant-
|
|
52
|
+
log(' optima-grant-credits user@example.com --credits 10000 --env prod', 'cyan');
|
|
53
53
|
|
|
54
54
|
log('\nMore Info:', 'yellow');
|
|
55
55
|
log(' optima-dev-skills --version Show version', 'cyan');
|
|
@@ -41,7 +41,7 @@ export function validateEnv(env: string): 'stage' | 'prod' {
|
|
|
41
41
|
/**
|
|
42
42
|
* Variant for commands that support all four envs (stage/prod/cn-prod/cn-stage)
|
|
43
43
|
* because they reach billing / skills / user-auth over HTTPS only — e.g.
|
|
44
|
-
* grant-
|
|
44
|
+
* grant-credits, grant-subscription, entitlement, account, and optima-plugin
|
|
45
45
|
* (set-paid/set-default/show). Commands that resolve users via the AWS RDS SSH
|
|
46
46
|
* tunnel (which does not exist for cn — Aliyun VPC-internal RDS) stay on
|
|
47
47
|
* validateEnv so a cn typo fails fast instead of dying inside tunnel setup.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// 发放积分(bonus 积分桶,30 天有效期)。调 billing 服务态端点
|
|
4
|
+
// POST /api/billing/admin/grant-credits(P15 钱包退役后的统一账本)。
|
|
5
|
+
//
|
|
6
|
+
// 历史:本命令原名 grant-credits(按积分),余额时代曾改名 grant-balance + 改吃 USD;
|
|
7
|
+
// P15 钱包退役回归积分后,名字/单位一直没改回 —— 现在改回 grant-credits + --credits
|
|
8
|
+
// 原生按积分发;--amount <usd> 作为按 USD 的兼容入口($1=700 积分);
|
|
9
|
+
// optima-grant-balance 作为废弃别名保留。
|
|
10
|
+
import { basename } from 'path';
|
|
11
|
+
import { randomUUID } from 'crypto';
|
|
12
|
+
import { callBilling, validateEnvCnProd } from './billing-http';
|
|
13
|
+
import { resolveTargetUser } from './grant-subscription';
|
|
14
|
+
|
|
15
|
+
const CREDITS_PER_USD = 700;
|
|
16
|
+
|
|
17
|
+
interface Parsed {
|
|
18
|
+
identifier: string;
|
|
19
|
+
credits: number | null;
|
|
20
|
+
amountUsd: number | null;
|
|
21
|
+
description: string | null;
|
|
22
|
+
env: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function parseArgs(args: string[]): Parsed {
|
|
26
|
+
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
27
|
+
console.log(`Usage: optima-grant-credits <email|phone|userId> --credits <n> [options]
|
|
28
|
+
|
|
29
|
+
Grant credits to a user (bonus bucket, expires in 30 days).
|
|
30
|
+
Used for promotional grants, compensation, referral rewards, etc.
|
|
31
|
+
|
|
32
|
+
Target user: <email|phone|userId> (positional). phone/userId only on
|
|
33
|
+
cn-prod / cn-stage; AWS stage/prod resolve email only.
|
|
34
|
+
|
|
35
|
+
Options:
|
|
36
|
+
--credits <n> Credits to grant (integer >= 1). Primary unit.
|
|
37
|
+
--amount <usd> Alt: grant by USD ($1 = ${CREDITS_PER_USD} credits). Provide exactly one of --credits / --amount.
|
|
38
|
+
--description <text> Description for audit trail (optional)
|
|
39
|
+
--env <env> Environment: stage, prod, cn-prod, cn-stage (default: stage)
|
|
40
|
+
-h, --help Show this help
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
43
|
+
optima-grant-credits user@example.com --credits 10000 --env prod
|
|
44
|
+
optima-grant-credits 18898654855 --credits 5000 --env cn-prod # 手机号(cn 用户多为手机号注册)
|
|
45
|
+
optima-grant-credits user@example.com --amount 5 --env prod # 按 USD(= 3500 积分)`);
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const identifier = args[0];
|
|
50
|
+
let credits: number | null = null;
|
|
51
|
+
let amountUsd: number | null = null;
|
|
52
|
+
let description: string | null = null;
|
|
53
|
+
let env = 'stage';
|
|
54
|
+
|
|
55
|
+
for (let i = 1; i < args.length; i++) {
|
|
56
|
+
if (args[i] === '--credits' && args[i + 1]) { credits = parseInt(args[++i], 10); }
|
|
57
|
+
else if (args[i] === '--amount' && args[i + 1]) { amountUsd = parseFloat(args[++i]); }
|
|
58
|
+
else if (args[i] === '--description' && args[i + 1]) { description = args[++i]; }
|
|
59
|
+
else if (args[i] === '--env' && args[i + 1]) { env = args[++i]; }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Exactly one of --credits / --amount (mirrors billing endpoint's oneOf).
|
|
63
|
+
if ((credits !== null) === (amountUsd !== null)) {
|
|
64
|
+
console.error('提供且只能提供 --credits <n> 或 --amount <usd> 之一');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
if (credits !== null && (!Number.isInteger(credits) || credits < 1)) {
|
|
68
|
+
console.error('--credits 必须是 >= 1 的整数');
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
if (amountUsd !== null && (!Number.isFinite(amountUsd) || amountUsd <= 0)) {
|
|
72
|
+
console.error('--amount 必须 > 0 (USD)');
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
validateEnvCnProd(env);
|
|
76
|
+
|
|
77
|
+
return { identifier, credits, amountUsd, description, env };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function main() {
|
|
81
|
+
// Deprecation notice when invoked via the legacy alias `optima-grant-balance`.
|
|
82
|
+
if (basename(process.argv[1] || '').includes('grant-balance')) {
|
|
83
|
+
console.warn('⚠️ optima-grant-balance 已更名为 optima-grant-credits(P15 钱包退役后回归积分)。请改用 `optima-grant-credits --credits <n>`;本别名仍可用,后续弃用。\n');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const { identifier, credits, amountUsd, description, env } = parseArgs(process.argv.slice(2));
|
|
87
|
+
|
|
88
|
+
const creditsDisplay = credits ?? Math.round((amountUsd as number) * CREDITS_PER_USD);
|
|
89
|
+
console.log(`\n🎁 Granting ${creditsDisplay} credits${amountUsd !== null ? ` ($${amountUsd.toFixed(2)})` : ''} to ${identifier} [${env.toUpperCase()}]\n`);
|
|
90
|
+
if (description) console.log(` Reason: ${description}`);
|
|
91
|
+
|
|
92
|
+
// Shared resolver: classify→resolve→reverse-verify echo→phone-assert on cn
|
|
93
|
+
// (so phone/userId works for cn's phone-registered users, gateway#923);
|
|
94
|
+
// email-only via the RDS SSH tunnel on AWS.
|
|
95
|
+
const { userId } = await resolveTargetUser(env, identifier);
|
|
96
|
+
|
|
97
|
+
// amountCredits(原生积分)与 amountUsd(USD 折算)二选一,对应 billing 端点的 oneOf。
|
|
98
|
+
const amountField = credits !== null ? { amountCredits: credits } : { amountUsd };
|
|
99
|
+
|
|
100
|
+
// 幂等键 per-invocation 生成、callBilling 的 5xx retry 复用同 body —— 「已
|
|
101
|
+
// commit 但响应 5xx」场景重试不双发(billing spec R2-M3)。
|
|
102
|
+
const { body } = await callBilling<{ success: boolean; lotId: string; credits: number }>(
|
|
103
|
+
env, 'POST', '/api/billing/admin/grant-credits',
|
|
104
|
+
{
|
|
105
|
+
userId,
|
|
106
|
+
...amountField,
|
|
107
|
+
description: description ?? undefined,
|
|
108
|
+
idempotencyKey: `dev-skills-grant:${randomUUID()}`,
|
|
109
|
+
},
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
console.log(`✓ Granted ${body.credits} credits (lot ${body.lotId})`);
|
|
113
|
+
console.log(`\n✅ Done! ${identifier} received ${body.credits} bonus credits (expires in 30 days)\n`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
main().catch(error => {
|
|
117
|
+
console.error('\n❌ Error:', error.message);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
});
|
|
@@ -119,7 +119,7 @@ Options:
|
|
|
119
119
|
/**
|
|
120
120
|
* Resolve a CLI identifier (`<email|phone|userId>`) to a userId + verified
|
|
121
121
|
* account identity, handling the AWS-vs-cn split. Shared by grant-subscription,
|
|
122
|
-
* grant-
|
|
122
|
+
* grant-credits, the optima-entitlement subcommands, and optima-account so all
|
|
123
123
|
* four accept the same identifier forms (gateway#923: phone/userId on cn).
|
|
124
124
|
*
|
|
125
125
|
* - AWS (stage/prod): email-only via the RDS SSH tunnel; no internal HTTP
|
|
@@ -49,7 +49,7 @@ function validateEnv(env) {
|
|
|
49
49
|
/**
|
|
50
50
|
* Variant for commands that support all four envs (stage/prod/cn-prod/cn-stage)
|
|
51
51
|
* because they reach billing / skills / user-auth over HTTPS only — e.g.
|
|
52
|
-
* grant-
|
|
52
|
+
* grant-credits, grant-subscription, entitlement, account, and optima-plugin
|
|
53
53
|
* (set-paid/set-default/show). Commands that resolve users via the AWS RDS SSH
|
|
54
54
|
* tunnel (which does not exist for cn — Aliyun VPC-internal RDS) stay on
|
|
55
55
|
* validateEnv so a cn typo fails fast instead of dying inside tunnel setup.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
// 发放积分(bonus 积分桶,30 天有效期)。调 billing 服务态端点
|
|
5
|
+
// POST /api/billing/admin/grant-credits(P15 钱包退役后的统一账本)。
|
|
6
|
+
//
|
|
7
|
+
// 历史:本命令原名 grant-credits(按积分),余额时代曾改名 grant-balance + 改吃 USD;
|
|
8
|
+
// P15 钱包退役回归积分后,名字/单位一直没改回 —— 现在改回 grant-credits + --credits
|
|
9
|
+
// 原生按积分发;--amount <usd> 作为按 USD 的兼容入口($1=700 积分);
|
|
10
|
+
// optima-grant-balance 作为废弃别名保留。
|
|
11
|
+
const path_1 = require("path");
|
|
12
|
+
const crypto_1 = require("crypto");
|
|
13
|
+
const billing_http_1 = require("./billing-http");
|
|
14
|
+
const grant_subscription_1 = require("./grant-subscription");
|
|
15
|
+
const CREDITS_PER_USD = 700;
|
|
16
|
+
function parseArgs(args) {
|
|
17
|
+
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
18
|
+
console.log(`Usage: optima-grant-credits <email|phone|userId> --credits <n> [options]
|
|
19
|
+
|
|
20
|
+
Grant credits to a user (bonus bucket, expires in 30 days).
|
|
21
|
+
Used for promotional grants, compensation, referral rewards, etc.
|
|
22
|
+
|
|
23
|
+
Target user: <email|phone|userId> (positional). phone/userId only on
|
|
24
|
+
cn-prod / cn-stage; AWS stage/prod resolve email only.
|
|
25
|
+
|
|
26
|
+
Options:
|
|
27
|
+
--credits <n> Credits to grant (integer >= 1). Primary unit.
|
|
28
|
+
--amount <usd> Alt: grant by USD ($1 = ${CREDITS_PER_USD} credits). Provide exactly one of --credits / --amount.
|
|
29
|
+
--description <text> Description for audit trail (optional)
|
|
30
|
+
--env <env> Environment: stage, prod, cn-prod, cn-stage (default: stage)
|
|
31
|
+
-h, --help Show this help
|
|
32
|
+
|
|
33
|
+
Examples:
|
|
34
|
+
optima-grant-credits user@example.com --credits 10000 --env prod
|
|
35
|
+
optima-grant-credits 18898654855 --credits 5000 --env cn-prod # 手机号(cn 用户多为手机号注册)
|
|
36
|
+
optima-grant-credits user@example.com --amount 5 --env prod # 按 USD(= 3500 积分)`);
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
const identifier = args[0];
|
|
40
|
+
let credits = null;
|
|
41
|
+
let amountUsd = null;
|
|
42
|
+
let description = null;
|
|
43
|
+
let env = 'stage';
|
|
44
|
+
for (let i = 1; i < args.length; i++) {
|
|
45
|
+
if (args[i] === '--credits' && args[i + 1]) {
|
|
46
|
+
credits = parseInt(args[++i], 10);
|
|
47
|
+
}
|
|
48
|
+
else if (args[i] === '--amount' && args[i + 1]) {
|
|
49
|
+
amountUsd = parseFloat(args[++i]);
|
|
50
|
+
}
|
|
51
|
+
else if (args[i] === '--description' && args[i + 1]) {
|
|
52
|
+
description = args[++i];
|
|
53
|
+
}
|
|
54
|
+
else if (args[i] === '--env' && args[i + 1]) {
|
|
55
|
+
env = args[++i];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Exactly one of --credits / --amount (mirrors billing endpoint's oneOf).
|
|
59
|
+
if ((credits !== null) === (amountUsd !== null)) {
|
|
60
|
+
console.error('提供且只能提供 --credits <n> 或 --amount <usd> 之一');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
if (credits !== null && (!Number.isInteger(credits) || credits < 1)) {
|
|
64
|
+
console.error('--credits 必须是 >= 1 的整数');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
if (amountUsd !== null && (!Number.isFinite(amountUsd) || amountUsd <= 0)) {
|
|
68
|
+
console.error('--amount 必须 > 0 (USD)');
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
(0, billing_http_1.validateEnvCnProd)(env);
|
|
72
|
+
return { identifier, credits, amountUsd, description, env };
|
|
73
|
+
}
|
|
74
|
+
async function main() {
|
|
75
|
+
// Deprecation notice when invoked via the legacy alias `optima-grant-balance`.
|
|
76
|
+
if ((0, path_1.basename)(process.argv[1] || '').includes('grant-balance')) {
|
|
77
|
+
console.warn('⚠️ optima-grant-balance 已更名为 optima-grant-credits(P15 钱包退役后回归积分)。请改用 `optima-grant-credits --credits <n>`;本别名仍可用,后续弃用。\n');
|
|
78
|
+
}
|
|
79
|
+
const { identifier, credits, amountUsd, description, env } = parseArgs(process.argv.slice(2));
|
|
80
|
+
const creditsDisplay = credits ?? Math.round(amountUsd * CREDITS_PER_USD);
|
|
81
|
+
console.log(`\n🎁 Granting ${creditsDisplay} credits${amountUsd !== null ? ` ($${amountUsd.toFixed(2)})` : ''} to ${identifier} [${env.toUpperCase()}]\n`);
|
|
82
|
+
if (description)
|
|
83
|
+
console.log(` Reason: ${description}`);
|
|
84
|
+
// Shared resolver: classify→resolve→reverse-verify echo→phone-assert on cn
|
|
85
|
+
// (so phone/userId works for cn's phone-registered users, gateway#923);
|
|
86
|
+
// email-only via the RDS SSH tunnel on AWS.
|
|
87
|
+
const { userId } = await (0, grant_subscription_1.resolveTargetUser)(env, identifier);
|
|
88
|
+
// amountCredits(原生积分)与 amountUsd(USD 折算)二选一,对应 billing 端点的 oneOf。
|
|
89
|
+
const amountField = credits !== null ? { amountCredits: credits } : { amountUsd };
|
|
90
|
+
// 幂等键 per-invocation 生成、callBilling 的 5xx retry 复用同 body —— 「已
|
|
91
|
+
// commit 但响应 5xx」场景重试不双发(billing spec R2-M3)。
|
|
92
|
+
const { body } = await (0, billing_http_1.callBilling)(env, 'POST', '/api/billing/admin/grant-credits', {
|
|
93
|
+
userId,
|
|
94
|
+
...amountField,
|
|
95
|
+
description: description ?? undefined,
|
|
96
|
+
idempotencyKey: `dev-skills-grant:${(0, crypto_1.randomUUID)()}`,
|
|
97
|
+
});
|
|
98
|
+
console.log(`✓ Granted ${body.credits} credits (lot ${body.lotId})`);
|
|
99
|
+
console.log(`\n✅ Done! ${identifier} received ${body.credits} bonus credits (expires in 30 days)\n`);
|
|
100
|
+
}
|
|
101
|
+
main().catch(error => {
|
|
102
|
+
console.error('\n❌ Error:', error.message);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
});
|
|
@@ -117,7 +117,7 @@ Options:
|
|
|
117
117
|
/**
|
|
118
118
|
* Resolve a CLI identifier (`<email|phone|userId>`) to a userId + verified
|
|
119
119
|
* account identity, handling the AWS-vs-cn split. Shared by grant-subscription,
|
|
120
|
-
* grant-
|
|
120
|
+
* grant-credits, the optima-entitlement subcommands, and optima-account so all
|
|
121
121
|
* four accept the same identifier forms (gateway#923: phone/userId on cn).
|
|
122
122
|
*
|
|
123
123
|
* - AWS (stage/prod): email-only via the RDS SSH tunnel; no internal HTTP
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optima-chat/dev-skills",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Claude Code Skills for Optima development team - cross-environment collaboration tools",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"optima-account": "dist/bin/helpers/account.js",
|
|
9
9
|
"optima-entitlement": "dist/bin/helpers/entitlement.js",
|
|
10
10
|
"optima-generate-test-token": "dist/bin/helpers/generate-test-token.js",
|
|
11
|
-
"optima-grant-
|
|
11
|
+
"optima-grant-credits": "dist/bin/helpers/grant-credits.js",
|
|
12
|
+
"optima-grant-balance": "dist/bin/helpers/grant-credits.js",
|
|
12
13
|
"optima-grant-subscription": "dist/bin/helpers/grant-subscription.js",
|
|
13
14
|
"optima-logs": "dist/bin/helpers/logs.js",
|
|
14
15
|
"optima-plugin": "dist/bin/helpers/plugin.js",
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: "grant-balance"
|
|
3
|
-
description: "当用户请求赠送余额、充值 USD 余额、grant balance、加余额、奖励、补偿、推荐奖励、运营发放时,使用此技能。支持 Stage、Prod、cn-prod、cn-stage 四个环境。"
|
|
4
|
-
allowed-tools: ["Bash"]
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# 赠送 USD 余额(Grant Balance)
|
|
8
|
-
|
|
9
|
-
当你需要为用户赠送 wallet USD 余额时,使用这个场景。金额按 $1=700 积分换算,经 billing API 入 **bonus 积分桶(30 天有效期)**(P15 钱包退役后语义),billing 服务在扣费时会优先消费 granted balance。
|
|
10
|
-
|
|
11
|
-
## 执行方式:使用 CLI 工具
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
optima-grant-balance <email|phone|userId> --amount <usd> [options]
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
**为什么使用 CLI 工具**:
|
|
18
|
-
- 自动通过 email/手机号/userId 查找 userId(cn 用户多为手机号;执行前打印 🎯 目标账号反查)
|
|
19
|
-
- 自动处理 SSH 隧道和数据库连接
|
|
20
|
-
- 不会影响现有订阅和已有余额(发放 bonus 积分(30 天有效期,重复执行会叠加发放))
|
|
21
|
-
- 自动留审计痕迹(credit_lot 行,幂等键前缀 `dev-skills-grant:`)
|
|
22
|
-
|
|
23
|
-
## 适用情况
|
|
24
|
-
|
|
25
|
-
- 奖励额外余额(推广、活动)
|
|
26
|
-
- 客户补偿(服务中断等)
|
|
27
|
-
- 推荐奖励
|
|
28
|
-
- 内部测试账户充值
|
|
29
|
-
|
|
30
|
-
## 快速操作
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
# 赠送 $5(Stage 环境,默认)
|
|
34
|
-
optima-grant-balance user@example.com --amount 5
|
|
35
|
-
|
|
36
|
-
# 赠送 $10 到 Prod
|
|
37
|
-
optima-grant-balance user@example.com --amount 10 --env prod
|
|
38
|
-
|
|
39
|
-
# 带描述(Reason 仅在 console 输出,不存 DB)
|
|
40
|
-
optima-grant-balance user@example.com --amount 20 --description "服务中断补偿" --env prod
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
> **单位是美元(USD)**。`--amount 5` 即赠送 $5.00 到 granted balance。
|
|
44
|
-
> 数据库底层用 micro-USD 精度(1 USD = 700 积分(P15 统一账本口径)
|
|
45
|
-
|
|
46
|
-
### 参数说明
|
|
47
|
-
|
|
48
|
-
| 参数 | 说明 | 默认值 |
|
|
49
|
-
|------|------|--------|
|
|
50
|
-
| `<email|phone|userId>` | 用户标识(必填;cn 支持手机号/userId) | - |
|
|
51
|
-
| `--amount <usd>` | USD 金额(必填,> 0) | - |
|
|
52
|
-
| `--description <text>` | 描述/原因(仅 console 输出) | - |
|
|
53
|
-
| `--env <env>` | 环境:stage, prod, cn-prod, cn-stage | stage |
|
|
54
|
-
|
|
55
|
-
> **cn-prod(国内环境)**:全程 HTTPS(auth.yzsgo.com / billing-api.yzsgo.com),email 查找走 user-auth internal lookup API(无 SSH 隧道)。金额输入仍是 USD($1 = 700 积分,与 CN ¥1 = 100 积分同一账本单位)。例:`optima-grant-balance user@example.com --amount 1 --env cn-prod`
|
|
56
|
-
>
|
|
57
|
-
> **cn-stage(阿里云预发)**:同 cn-prod 走 HTTPS(auth.stage.optima.chat / billing-api.stage.optima.chat)。M2M 凭证读 cn Infisical **staging** /shared-secrets/oauth-clients,运行时需 `INFISICAL_CN_EMAIL`/`INFISICAL_CN_PASSWORD`(admin user)。例:`optima-grant-balance user@example.com --amount 1 --env cn-stage`
|
|
58
|
-
|
|
59
|
-
## 与 grant-subscription 的区别
|
|
60
|
-
|
|
61
|
-
| | grant-balance | grant-subscription |
|
|
62
|
-
|---|---|---|
|
|
63
|
-
| 作用 | 追加 USD granted balance | 开通/切换订阅计划 |
|
|
64
|
-
| 现有余额 | 不影响(纯累加) | 重置 granted balance |
|
|
65
|
-
| 现有订阅 | 不影响 | 取消旧的,创建新的 |
|
|
66
|
-
| Token quota | 不影响 | 按计划更新 |
|
|
67
|
-
| 适用场景 | 奖励、补偿、推广 | 开通会员、升级计划 |
|
|
68
|
-
|
|
69
|
-
## 常见使用场景
|
|
70
|
-
|
|
71
|
-
### 场景 1:客户补偿
|
|
72
|
-
|
|
73
|
-
**用户请求**:"服务出了问题,给 xxx@gmail.com 补偿 $5"
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
optima-grant-balance xxx@gmail.com --amount 5 --description "Service outage compensation" --env prod
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### 场景 2:推荐奖励
|
|
80
|
-
|
|
81
|
-
**用户请求**:"xxx 推荐了新用户,奖励 $3"
|
|
82
|
-
|
|
83
|
-
```bash
|
|
84
|
-
optima-grant-balance xxx@gmail.com --amount 3 --description "Referral reward" --env prod
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### 场景 3:运营发放
|
|
88
|
-
|
|
89
|
-
**用户请求**:"给 xxx@gmail.com 充 $20 测试余额"
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
optima-grant-balance xxx@gmail.com --amount 20 --env stage
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
## 安全提醒
|
|
96
|
-
|
|
97
|
-
1. **Stage 优先**:默认操作 Stage 环境
|
|
98
|
-
2. **Prod 谨慎**:操作 Prod 前确认邮箱和金额
|
|
99
|
-
3. **纯追加**:不会影响现有余额和订阅(累加到 granted balance)
|
|
100
|
-
4. **Audit trail**:每次赠送对应一个 credit_lot(幂等键前缀 `dev-skills-grant:`,type=bonus)
|
|
101
|
-
|
|
102
|
-
## 相关命令
|
|
103
|
-
|
|
104
|
-
- `optima-grant-balance` - 赠送 USD 余额(主要方式)
|
|
105
|
-
- `optima-grant-subscription` - 开通订阅计划
|
|
106
|
-
- `optima-query-db` - 查询数据库验证结果(`GET /api/billing/balance(credits.byType.bonus)或 query-db credit_lot
|