@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
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: "grant-balance"
|
|
3
|
-
description: "Use when the user wants to grant credits (bonus, 30-day expiry) to an Optima user — for promotional grants, compensation, referral rewards, etc. $1 = 700 credits via billing API; does not affect subscriptions."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# 赠送 USD 余额(Grant Balance)
|
|
7
|
-
|
|
8
|
-
当你需要为用户赠送 wallet USD 余额时,使用这个场景。金额按 $1=700 积分换算,经 billing API 入 **bonus 积分桶(30 天有效期)**(P15 钱包退役后语义),billing 服务在扣费时会优先消费 granted balance。
|
|
9
|
-
|
|
10
|
-
## 执行方式:使用 CLI 工具
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
optima-grant-balance <email|phone|userId> --amount <usd> [options]
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
**为什么使用 CLI 工具**:
|
|
17
|
-
- 自动通过 email/手机号/userId 查找 userId(cn 用户多为手机号;执行前打印 🎯 目标账号反查)
|
|
18
|
-
- 自动处理 SSH 隧道和数据库连接
|
|
19
|
-
- 不会影响现有订阅和已有余额(发放 bonus 积分(30 天有效期,重复执行会叠加发放))
|
|
20
|
-
- 自动留审计痕迹(credit_lot 行,幂等键前缀 `dev-skills-grant:`)
|
|
21
|
-
|
|
22
|
-
## 适用情况
|
|
23
|
-
|
|
24
|
-
- 奖励额外余额(推广、活动)
|
|
25
|
-
- 客户补偿(服务中断等)
|
|
26
|
-
- 推荐奖励
|
|
27
|
-
- 内部测试账户充值
|
|
28
|
-
|
|
29
|
-
## 快速操作
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
# 赠送 $5(Stage 环境,默认)
|
|
33
|
-
optima-grant-balance user@example.com --amount 5
|
|
34
|
-
|
|
35
|
-
# 赠送 $10 到 Prod
|
|
36
|
-
optima-grant-balance user@example.com --amount 10 --env prod
|
|
37
|
-
|
|
38
|
-
# 带描述(Reason 仅在 console 输出,不存 DB)
|
|
39
|
-
optima-grant-balance user@example.com --amount 20 --description "服务中断补偿" --env prod
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
> **单位是美元(USD)**。`--amount 5` 即赠送 $5.00 到 granted balance。
|
|
43
|
-
> 数据库底层用 micro-USD 精度(1 USD = 700 积分(P15 统一账本口径)
|
|
44
|
-
|
|
45
|
-
### 参数说明
|
|
46
|
-
|
|
47
|
-
| 参数 | 说明 | 默认值 |
|
|
48
|
-
|------|------|--------|
|
|
49
|
-
| `<email|phone|userId>` | 用户标识(必填;cn 支持手机号/userId) | - |
|
|
50
|
-
| `--amount <usd>` | USD 金额(必填,> 0) | - |
|
|
51
|
-
| `--description <text>` | 描述/原因(仅 console 输出) | - |
|
|
52
|
-
| `--env <env>` | 环境:stage, prod, cn-prod, cn-stage | stage |
|
|
53
|
-
|
|
54
|
-
> **cn-prod**:走 HTTPS(auth.yzsgo.com / billing-api.yzsgo.com),email 查找经 user-auth internal lookup API(无 SSH 隧道)。金额输入仍是 USD($1 = 700 积分 = ¥7 档积分口径一致)。
|
|
55
|
-
> **cn-stage(阿里云预发)**:同 cn-prod 走 HTTPS(auth.stage.optima.chat / billing-api.stage.optima.chat);M2M 凭证读 cn Infisical staging,需 `INFISICAL_CN_EMAIL`/`INFISICAL_CN_PASSWORD`。
|
|
56
|
-
|
|
57
|
-
## 与 grant-subscription 的区别
|
|
58
|
-
|
|
59
|
-
| | grant-balance | grant-subscription |
|
|
60
|
-
|---|---|---|
|
|
61
|
-
| 作用 | 追加 USD granted balance | 开通/切换订阅计划 |
|
|
62
|
-
| 现有余额 | 不影响(纯累加) | 重置 granted balance |
|
|
63
|
-
| 现有订阅 | 不影响 | 取消旧的,创建新的 |
|
|
64
|
-
| Token quota | 不影响 | 按计划更新 |
|
|
65
|
-
| 适用场景 | 奖励、补偿、推广 | 开通会员、升级计划 |
|
|
66
|
-
|
|
67
|
-
## 常见使用场景
|
|
68
|
-
|
|
69
|
-
### 场景 1:客户补偿
|
|
70
|
-
|
|
71
|
-
**用户请求**:"服务出了问题,给 xxx@gmail.com 补偿 $5"
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
optima-grant-balance xxx@gmail.com --amount 5 --description "Service outage compensation" --env prod
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### 场景 2:推荐奖励
|
|
78
|
-
|
|
79
|
-
**用户请求**:"xxx 推荐了新用户,奖励 $3"
|
|
80
|
-
|
|
81
|
-
```bash
|
|
82
|
-
optima-grant-balance xxx@gmail.com --amount 3 --description "Referral reward" --env prod
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### 场景 3:运营发放
|
|
86
|
-
|
|
87
|
-
**用户请求**:"给 xxx@gmail.com 充 $20 测试余额"
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
optima-grant-balance xxx@gmail.com --amount 20 --env stage
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
## 安全提醒
|
|
94
|
-
|
|
95
|
-
1. **Stage 优先**:默认操作 Stage 环境
|
|
96
|
-
2. **Prod 谨慎**:操作 Prod 前确认邮箱和金额
|
|
97
|
-
3. **纯追加**:不会影响现有余额和订阅(累加到 granted balance)
|
|
98
|
-
4. **Audit trail**:每次赠送对应一个 credit_lot(幂等键前缀 `dev-skills-grant:`,type=bonus)
|
|
99
|
-
|
|
100
|
-
## 相关命令
|
|
101
|
-
|
|
102
|
-
- `optima-grant-balance` - 赠送 USD 余额(主要方式)
|
|
103
|
-
- `optima-grant-subscription` - 开通订阅计划
|
|
104
|
-
- `optima-query-db` - 查询数据库验证结果(`GET /api/billing/balance(credits.byType.bonus)或 query-db credit_lot
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// P15 D8b(optima-billing docs/2026-06-11-p15-wallet-sunset-spec.md):
|
|
4
|
-
// USD 钱包已退役——原「SSH 直写 usd_wallets.granted_balance_micros」作废,
|
|
5
|
-
// 改调 billing 服务态端点(grantCredits → bonus 积分)。
|
|
6
|
-
// ⚠️ 语义变化:旧 wallet granted 无期限;积分 bonus 桶标准 30 天有效期。
|
|
7
|
-
import { randomUUID } from 'crypto';
|
|
8
|
-
import { callBilling, validateEnvCnProd } from './billing-http';
|
|
9
|
-
import { resolveTargetUser } from './grant-subscription';
|
|
10
|
-
|
|
11
|
-
function parseArgs(args: string[]): { identifier: string; amountUsd: number; description: string | null; env: string } {
|
|
12
|
-
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
13
|
-
console.log(`Usage: optima-grant-balance <email|phone|userId> --amount <usd> [options]
|
|
14
|
-
|
|
15
|
-
Grant credits to a user (bonus bucket, expires in 30 days).
|
|
16
|
-
Used for promotional grants, compensation, referral rewards, etc.
|
|
17
|
-
$1 = 700 credits (P15 unified ledger; the USD wallet is retired).
|
|
18
|
-
|
|
19
|
-
Target user: <email|phone|userId> (positional). phone/userId only on
|
|
20
|
-
cn-prod / cn-stage; AWS stage/prod resolve email only.
|
|
21
|
-
|
|
22
|
-
Options:
|
|
23
|
-
--amount <usd> USD amount to grant (required, e.g. 5 for $5.00 = 3500 credits)
|
|
24
|
-
--description <text> Description for audit trail (optional)
|
|
25
|
-
--env <env> Environment: stage, prod, cn-prod, cn-stage (default: stage)
|
|
26
|
-
-h, --help Show this help
|
|
27
|
-
|
|
28
|
-
Examples:
|
|
29
|
-
optima-grant-balance user@example.com --amount 5 --env prod
|
|
30
|
-
optima-grant-balance 18898654855 --amount 1 --env cn-prod # 手机号(cn 用户多为手机号注册)
|
|
31
|
-
optima-grant-balance user@example.com --amount 1 --env cn-stage # 阿里云预发`);
|
|
32
|
-
process.exit(0);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const identifier = args[0];
|
|
36
|
-
let amountUsd = 0;
|
|
37
|
-
let description: string | null = null;
|
|
38
|
-
let env = 'stage';
|
|
39
|
-
|
|
40
|
-
for (let i = 1; i < args.length; i++) {
|
|
41
|
-
if (args[i] === '--amount' && args[i + 1]) { amountUsd = parseFloat(args[++i]); }
|
|
42
|
-
else if (args[i] === '--description' && args[i + 1]) { description = args[++i]; }
|
|
43
|
-
else if (args[i] === '--env' && args[i + 1]) { env = args[++i]; }
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (!Number.isFinite(amountUsd) || amountUsd <= 0) {
|
|
47
|
-
console.error('--amount is required and must be > 0 (USD)');
|
|
48
|
-
process.exit(1);
|
|
49
|
-
}
|
|
50
|
-
validateEnvCnProd(env);
|
|
51
|
-
|
|
52
|
-
return { identifier, amountUsd, description, env };
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async function main() {
|
|
56
|
-
const { identifier, amountUsd, description, env } = parseArgs(process.argv.slice(2));
|
|
57
|
-
|
|
58
|
-
console.log(`\n🎁 Granting $${amountUsd.toFixed(2)} (${Math.round(amountUsd * 700)} credits) to ${identifier} [${env.toUpperCase()}]\n`);
|
|
59
|
-
if (description) console.log(` Reason: ${description}`);
|
|
60
|
-
|
|
61
|
-
// Shared resolver: classify→resolve→reverse-verify echo→phone-assert on cn
|
|
62
|
-
// (so phone/userId works for cn's phone-registered users, gateway#923);
|
|
63
|
-
// email-only via the RDS SSH tunnel on AWS.
|
|
64
|
-
const { userId } = await resolveTargetUser(env, identifier);
|
|
65
|
-
|
|
66
|
-
// 幂等键 per-invocation 生成、callBilling 的 5xx retry 复用同 body —— 「已
|
|
67
|
-
// commit 但响应 5xx」场景重试不双发(billing spec R2-M3)。
|
|
68
|
-
const { body } = await callBilling<{ success: boolean; lotId: string; credits: number }>(
|
|
69
|
-
env, 'POST', '/api/billing/admin/grant-credits',
|
|
70
|
-
{
|
|
71
|
-
userId,
|
|
72
|
-
amountUsd,
|
|
73
|
-
description: description ?? undefined,
|
|
74
|
-
idempotencyKey: `dev-skills-grant:${randomUUID()}`,
|
|
75
|
-
},
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
console.log(`✓ Granted ${body.credits} credits (lot ${body.lotId})`);
|
|
79
|
-
console.log(`\n✅ Done! ${identifier} received ${body.credits} bonus credits (expires in 30 days)\n`);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
main().catch(error => {
|
|
83
|
-
console.error('\n❌ Error:', error.message);
|
|
84
|
-
process.exit(1);
|
|
85
|
-
});
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
// P15 D8b(optima-billing docs/2026-06-11-p15-wallet-sunset-spec.md):
|
|
5
|
-
// USD 钱包已退役——原「SSH 直写 usd_wallets.granted_balance_micros」作废,
|
|
6
|
-
// 改调 billing 服务态端点(grantCredits → bonus 积分)。
|
|
7
|
-
// ⚠️ 语义变化:旧 wallet granted 无期限;积分 bonus 桶标准 30 天有效期。
|
|
8
|
-
const crypto_1 = require("crypto");
|
|
9
|
-
const billing_http_1 = require("./billing-http");
|
|
10
|
-
const grant_subscription_1 = require("./grant-subscription");
|
|
11
|
-
function parseArgs(args) {
|
|
12
|
-
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
13
|
-
console.log(`Usage: optima-grant-balance <email|phone|userId> --amount <usd> [options]
|
|
14
|
-
|
|
15
|
-
Grant credits to a user (bonus bucket, expires in 30 days).
|
|
16
|
-
Used for promotional grants, compensation, referral rewards, etc.
|
|
17
|
-
$1 = 700 credits (P15 unified ledger; the USD wallet is retired).
|
|
18
|
-
|
|
19
|
-
Target user: <email|phone|userId> (positional). phone/userId only on
|
|
20
|
-
cn-prod / cn-stage; AWS stage/prod resolve email only.
|
|
21
|
-
|
|
22
|
-
Options:
|
|
23
|
-
--amount <usd> USD amount to grant (required, e.g. 5 for $5.00 = 3500 credits)
|
|
24
|
-
--description <text> Description for audit trail (optional)
|
|
25
|
-
--env <env> Environment: stage, prod, cn-prod, cn-stage (default: stage)
|
|
26
|
-
-h, --help Show this help
|
|
27
|
-
|
|
28
|
-
Examples:
|
|
29
|
-
optima-grant-balance user@example.com --amount 5 --env prod
|
|
30
|
-
optima-grant-balance 18898654855 --amount 1 --env cn-prod # 手机号(cn 用户多为手机号注册)
|
|
31
|
-
optima-grant-balance user@example.com --amount 1 --env cn-stage # 阿里云预发`);
|
|
32
|
-
process.exit(0);
|
|
33
|
-
}
|
|
34
|
-
const identifier = args[0];
|
|
35
|
-
let amountUsd = 0;
|
|
36
|
-
let description = null;
|
|
37
|
-
let env = 'stage';
|
|
38
|
-
for (let i = 1; i < args.length; i++) {
|
|
39
|
-
if (args[i] === '--amount' && args[i + 1]) {
|
|
40
|
-
amountUsd = parseFloat(args[++i]);
|
|
41
|
-
}
|
|
42
|
-
else if (args[i] === '--description' && args[i + 1]) {
|
|
43
|
-
description = args[++i];
|
|
44
|
-
}
|
|
45
|
-
else if (args[i] === '--env' && args[i + 1]) {
|
|
46
|
-
env = args[++i];
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
if (!Number.isFinite(amountUsd) || amountUsd <= 0) {
|
|
50
|
-
console.error('--amount is required and must be > 0 (USD)');
|
|
51
|
-
process.exit(1);
|
|
52
|
-
}
|
|
53
|
-
(0, billing_http_1.validateEnvCnProd)(env);
|
|
54
|
-
return { identifier, amountUsd, description, env };
|
|
55
|
-
}
|
|
56
|
-
async function main() {
|
|
57
|
-
const { identifier, amountUsd, description, env } = parseArgs(process.argv.slice(2));
|
|
58
|
-
console.log(`\n🎁 Granting $${amountUsd.toFixed(2)} (${Math.round(amountUsd * 700)} credits) to ${identifier} [${env.toUpperCase()}]\n`);
|
|
59
|
-
if (description)
|
|
60
|
-
console.log(` Reason: ${description}`);
|
|
61
|
-
// Shared resolver: classify→resolve→reverse-verify echo→phone-assert on cn
|
|
62
|
-
// (so phone/userId works for cn's phone-registered users, gateway#923);
|
|
63
|
-
// email-only via the RDS SSH tunnel on AWS.
|
|
64
|
-
const { userId } = await (0, grant_subscription_1.resolveTargetUser)(env, identifier);
|
|
65
|
-
// 幂等键 per-invocation 生成、callBilling 的 5xx retry 复用同 body —— 「已
|
|
66
|
-
// commit 但响应 5xx」场景重试不双发(billing spec R2-M3)。
|
|
67
|
-
const { body } = await (0, billing_http_1.callBilling)(env, 'POST', '/api/billing/admin/grant-credits', {
|
|
68
|
-
userId,
|
|
69
|
-
amountUsd,
|
|
70
|
-
description: description ?? undefined,
|
|
71
|
-
idempotencyKey: `dev-skills-grant:${(0, crypto_1.randomUUID)()}`,
|
|
72
|
-
});
|
|
73
|
-
console.log(`✓ Granted ${body.credits} credits (lot ${body.lotId})`);
|
|
74
|
-
console.log(`\n✅ Done! ${identifier} received ${body.credits} bonus credits (expires in 30 days)\n`);
|
|
75
|
-
}
|
|
76
|
-
main().catch(error => {
|
|
77
|
-
console.error('\n❌ Error:', error.message);
|
|
78
|
-
process.exit(1);
|
|
79
|
-
});
|