@optima-chat/dev-skills 0.7.31 → 0.7.32
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/skills/grant-balance/SKILL.md +102 -0
- package/.claude/skills/grant-subscription/SKILL.md +1 -1
- package/.codex/skills/grant-balance/SKILL.md +101 -0
- package/AGENTS.md +2 -2
- package/bin/cli.js +2 -2
- package/bin/helpers/{grant-credits.ts → grant-balance.ts} +30 -20
- package/dist/bin/helpers/generate-test-token.js +0 -0
- package/dist/bin/helpers/{grant-credits.js → grant-balance.js} +24 -24
- package/dist/bin/helpers/query-db.js +0 -0
- package/dist/bin/helpers/show-env.js +0 -0
- package/package.json +2 -2
- package/.claude/settings.local.json +0 -51
- package/.claude/skills/grant-credits/SKILL.md +0 -107
- package/.codex/skills/grant-credits/SKILL.md +0 -28
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "grant-balance"
|
|
3
|
+
description: "当用户请求赠送余额、充值 USD 余额、grant balance、加余额、奖励、补偿、推荐奖励、运营发放时,使用此技能。支持 Stage、Prod 两个环境。"
|
|
4
|
+
allowed-tools: ["Bash"]
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 赠送 USD 余额(Grant Balance)
|
|
8
|
+
|
|
9
|
+
当你需要为用户赠送 wallet USD 余额时,使用这个场景。金额会加到 `usd_wallets.granted_balance_micros`,billing 服务在扣费时会优先消费 granted balance。
|
|
10
|
+
|
|
11
|
+
## 执行方式:使用 CLI 工具
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
optima-grant-balance <email> --amount <usd> [options]
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**为什么使用 CLI 工具**:
|
|
18
|
+
- 自动通过 email 查找 userId(跨 user-auth 数据库)
|
|
19
|
+
- 自动处理 SSH 隧道和数据库连接
|
|
20
|
+
- 不会影响现有订阅和已有余额(纯追加到 granted balance)
|
|
21
|
+
- 自动写入 audit trail(`usd_wallet_topups` source=admin_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 = 1,000,000 micros),CLI 自动换算。
|
|
45
|
+
|
|
46
|
+
### 参数说明
|
|
47
|
+
|
|
48
|
+
| 参数 | 说明 | 默认值 |
|
|
49
|
+
|------|------|--------|
|
|
50
|
+
| `<email>` | 用户邮箱(必填) | - |
|
|
51
|
+
| `--amount <usd>` | USD 金额(必填,> 0) | - |
|
|
52
|
+
| `--description <text>` | 描述/原因(仅 console 输出) | - |
|
|
53
|
+
| `--env <env>` | 环境:stage, prod | stage |
|
|
54
|
+
|
|
55
|
+
## 与 grant-subscription 的区别
|
|
56
|
+
|
|
57
|
+
| | grant-balance | grant-subscription |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| 作用 | 追加 USD granted balance | 开通/切换订阅计划 |
|
|
60
|
+
| 现有余额 | 不影响(纯累加) | 重置 granted balance |
|
|
61
|
+
| 现有订阅 | 不影响 | 取消旧的,创建新的 |
|
|
62
|
+
| Token quota | 不影响 | 按计划更新 |
|
|
63
|
+
| 适用场景 | 奖励、补偿、推广 | 开通会员、升级计划 |
|
|
64
|
+
|
|
65
|
+
## 常见使用场景
|
|
66
|
+
|
|
67
|
+
### 场景 1:客户补偿
|
|
68
|
+
|
|
69
|
+
**用户请求**:"服务出了问题,给 xxx@gmail.com 补偿 $5"
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
optima-grant-balance xxx@gmail.com --amount 5 --description "Service outage compensation" --env prod
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 场景 2:推荐奖励
|
|
76
|
+
|
|
77
|
+
**用户请求**:"xxx 推荐了新用户,奖励 $3"
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
optima-grant-balance xxx@gmail.com --amount 3 --description "Referral reward" --env prod
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 场景 3:运营发放
|
|
84
|
+
|
|
85
|
+
**用户请求**:"给 xxx@gmail.com 充 $20 测试余额"
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
optima-grant-balance xxx@gmail.com --amount 20 --env stage
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 安全提醒
|
|
92
|
+
|
|
93
|
+
1. **Stage 优先**:默认操作 Stage 环境
|
|
94
|
+
2. **Prod 谨慎**:操作 Prod 前确认邮箱和金额
|
|
95
|
+
3. **纯追加**:不会影响现有余额和订阅(累加到 granted balance)
|
|
96
|
+
4. **Audit trail**:每次赠送会插入一条 `usd_wallet_topups` 记录(source=`admin_grant`)
|
|
97
|
+
|
|
98
|
+
## 相关命令
|
|
99
|
+
|
|
100
|
+
- `optima-grant-balance` - 赠送 USD 余额(主要方式)
|
|
101
|
+
- `optima-grant-subscription` - 开通订阅计划
|
|
102
|
+
- `optima-query-db` - 查询数据库验证结果(`SELECT granted_balance_micros FROM usd_wallets WHERE user_id=...`)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "grant-balance"
|
|
3
|
+
description: "Use when the user wants to grant USD wallet balance to an Optima user — for promotional grants, compensation, referral rewards, etc. Adds to granted_balance_micros without affecting subscriptions."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 赠送 USD 余额(Grant Balance)
|
|
7
|
+
|
|
8
|
+
当你需要为用户赠送 wallet USD 余额时,使用这个场景。金额会加到 `usd_wallets.granted_balance_micros`,billing 服务在扣费时会优先消费 granted balance。
|
|
9
|
+
|
|
10
|
+
## 执行方式:使用 CLI 工具
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
optima-grant-balance <email> --amount <usd> [options]
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**为什么使用 CLI 工具**:
|
|
17
|
+
- 自动通过 email 查找 userId(跨 user-auth 数据库)
|
|
18
|
+
- 自动处理 SSH 隧道和数据库连接
|
|
19
|
+
- 不会影响现有订阅和已有余额(纯追加到 granted balance)
|
|
20
|
+
- 自动写入 audit trail(`usd_wallet_topups` source=admin_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 = 1,000,000 micros),CLI 自动换算。
|
|
44
|
+
|
|
45
|
+
### 参数说明
|
|
46
|
+
|
|
47
|
+
| 参数 | 说明 | 默认值 |
|
|
48
|
+
|------|------|--------|
|
|
49
|
+
| `<email>` | 用户邮箱(必填) | - |
|
|
50
|
+
| `--amount <usd>` | USD 金额(必填,> 0) | - |
|
|
51
|
+
| `--description <text>` | 描述/原因(仅 console 输出) | - |
|
|
52
|
+
| `--env <env>` | 环境:stage, prod | stage |
|
|
53
|
+
|
|
54
|
+
## 与 grant-subscription 的区别
|
|
55
|
+
|
|
56
|
+
| | grant-balance | grant-subscription |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| 作用 | 追加 USD granted balance | 开通/切换订阅计划 |
|
|
59
|
+
| 现有余额 | 不影响(纯累加) | 重置 granted balance |
|
|
60
|
+
| 现有订阅 | 不影响 | 取消旧的,创建新的 |
|
|
61
|
+
| Token quota | 不影响 | 按计划更新 |
|
|
62
|
+
| 适用场景 | 奖励、补偿、推广 | 开通会员、升级计划 |
|
|
63
|
+
|
|
64
|
+
## 常见使用场景
|
|
65
|
+
|
|
66
|
+
### 场景 1:客户补偿
|
|
67
|
+
|
|
68
|
+
**用户请求**:"服务出了问题,给 xxx@gmail.com 补偿 $5"
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
optima-grant-balance xxx@gmail.com --amount 5 --description "Service outage compensation" --env prod
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 场景 2:推荐奖励
|
|
75
|
+
|
|
76
|
+
**用户请求**:"xxx 推荐了新用户,奖励 $3"
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
optima-grant-balance xxx@gmail.com --amount 3 --description "Referral reward" --env prod
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 场景 3:运营发放
|
|
83
|
+
|
|
84
|
+
**用户请求**:"给 xxx@gmail.com 充 $20 测试余额"
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
optima-grant-balance xxx@gmail.com --amount 20 --env stage
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 安全提醒
|
|
91
|
+
|
|
92
|
+
1. **Stage 优先**:默认操作 Stage 环境
|
|
93
|
+
2. **Prod 谨慎**:操作 Prod 前确认邮箱和金额
|
|
94
|
+
3. **纯追加**:不会影响现有余额和订阅(累加到 granted balance)
|
|
95
|
+
4. **Audit trail**:每次赠送会插入一条 `usd_wallet_topups` 记录(source=`admin_grant`)
|
|
96
|
+
|
|
97
|
+
## 相关命令
|
|
98
|
+
|
|
99
|
+
- `optima-grant-balance` - 赠送 USD 余额(主要方式)
|
|
100
|
+
- `optima-grant-subscription` - 开通订阅计划
|
|
101
|
+
- `optima-query-db` - 查询数据库验证结果(`SELECT granted_balance_micros FROM usd_wallets WHERE user_id=...`)
|
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-balance <email> --amount <usd> [options]`
|
|
14
14
|
|
|
15
15
|
For code-reading tasks across Optima repositories, use `gh` commands against `Optima-Chat/<repo>`.
|
|
16
16
|
|
|
@@ -24,7 +24,7 @@ After `npm install -g @optima-chat/dev-skills`, this package installs skills und
|
|
|
24
24
|
- `generate-test-token`
|
|
25
25
|
- `read-code`
|
|
26
26
|
- `grant-subscription`
|
|
27
|
-
- `grant-
|
|
27
|
+
- `grant-balance`
|
|
28
28
|
- `restart-ecs`
|
|
29
29
|
- `use-commerce-cli`
|
|
30
30
|
|
package/bin/cli.js
CHANGED
|
@@ -33,7 +33,7 @@ switch (command) {
|
|
|
33
33
|
log(' optima-query-db <service> "<sql>" [env] Query database', 'cyan');
|
|
34
34
|
log(' optima-show-env <service> [env] Show service env vars', 'cyan');
|
|
35
35
|
log(' optima-generate-test-token [--env production] Generate test token', 'cyan');
|
|
36
|
-
log(' optima-grant-
|
|
36
|
+
log(' optima-grant-balance <email> --amount <usd> [--env] Grant USD wallet balance', 'cyan');
|
|
37
37
|
log(' optima-grant-subscription <email> --plan <p> [--env] Grant subscription', 'cyan');
|
|
38
38
|
log(' /logs <service> [lines] [env] View service logs (skill)', 'cyan');
|
|
39
39
|
log(' /restart-ecs <service> [env] Restart ECS service (skill)', 'cyan');
|
|
@@ -48,7 +48,7 @@ switch (command) {
|
|
|
48
48
|
log('\nExamples:', 'yellow');
|
|
49
49
|
log(' /logs commerce-backend 100 prod', 'cyan');
|
|
50
50
|
log(' optima-query-db user-auth "SELECT COUNT(*) FROM users" prod', 'cyan');
|
|
51
|
-
log(' optima-grant-
|
|
51
|
+
log(' optima-grant-balance user@example.com --amount 5 --env prod', 'cyan');
|
|
52
52
|
|
|
53
53
|
log('\nMore Info:', 'yellow');
|
|
54
54
|
log(' optima-dev-skills --version Show version', 'cyan');
|
|
@@ -2,46 +2,57 @@
|
|
|
2
2
|
|
|
3
3
|
import { getInfisicalConfig, getInfisicalToken, resolveUserId, connectBillingDB, escapeSQL } from './db-utils';
|
|
4
4
|
|
|
5
|
-
function parseArgs(args: string[]): { email: string;
|
|
5
|
+
function parseArgs(args: string[]): { email: string; amountUsd: number; description: string | null; env: string } {
|
|
6
6
|
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
7
|
-
console.log(`Usage: optima-grant-
|
|
7
|
+
console.log(`Usage: optima-grant-balance <email> --amount <usd> [options]
|
|
8
|
+
|
|
9
|
+
Add USD balance to a user's wallet (granted_balance_micros).
|
|
10
|
+
Used for promotional grants, compensation, referral rewards, etc.
|
|
8
11
|
|
|
9
12
|
Options:
|
|
10
|
-
--amount <
|
|
11
|
-
--
|
|
12
|
-
--description <text> Description (optional)
|
|
13
|
+
--amount <usd> USD amount to grant (required, e.g. 5 for $5.00)
|
|
14
|
+
--description <text> Description for audit trail (optional)
|
|
13
15
|
--env <env> Environment: stage, prod (default: stage)
|
|
14
|
-
-h, --help Show this help
|
|
16
|
+
-h, --help Show this help
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
optima-grant-balance user@example.com --amount 5 --env prod
|
|
20
|
+
optima-grant-balance user@example.com --amount 10 --description "Service outage compensation"`);
|
|
15
21
|
process.exit(0);
|
|
16
22
|
}
|
|
17
23
|
|
|
18
24
|
const email = args[0];
|
|
19
|
-
let
|
|
20
|
-
let type = 'bonus';
|
|
25
|
+
let amountUsd = 0;
|
|
21
26
|
let description: string | null = null;
|
|
22
27
|
let env = 'stage';
|
|
23
28
|
|
|
24
29
|
for (let i = 1; i < args.length; i++) {
|
|
25
|
-
if (args[i] === '--amount' && args[i + 1]) {
|
|
26
|
-
else if (args[i] === '--type' && args[i + 1]) { type = args[++i]; }
|
|
30
|
+
if (args[i] === '--amount' && args[i + 1]) { amountUsd = parseFloat(args[++i]); }
|
|
27
31
|
else if (args[i] === '--description' && args[i + 1]) { description = args[++i]; }
|
|
28
32
|
else if (args[i] === '--env' && args[i + 1]) { env = args[++i]; }
|
|
29
33
|
}
|
|
30
34
|
|
|
31
|
-
if (
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
if (!Number.isFinite(amountUsd) || amountUsd <= 0) {
|
|
36
|
+
console.error('--amount is required and must be > 0 (USD)');
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
if (!['stage', 'prod'].includes(env)) {
|
|
40
|
+
console.error('Env must be stage or prod (billing DB not available in CI)');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
34
43
|
|
|
35
|
-
return { email,
|
|
44
|
+
return { email, amountUsd, description, env };
|
|
36
45
|
}
|
|
37
46
|
|
|
38
47
|
async function main() {
|
|
39
|
-
const { email,
|
|
48
|
+
const { email, amountUsd, description, env } = parseArgs(process.argv.slice(2));
|
|
40
49
|
const infisicalConfig = getInfisicalConfig();
|
|
41
50
|
const token = getInfisicalToken(infisicalConfig);
|
|
42
51
|
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
// 1 USD = 1,000,000 micros. Round to integer micros.
|
|
53
|
+
const amountMicros = Math.round(amountUsd * 1_000_000);
|
|
54
|
+
console.log(`\n🎁 Granting $${amountUsd.toFixed(2)} to ${email} [${env.toUpperCase()}]\n`);
|
|
55
|
+
if (description) console.log(` Reason: ${description}`);
|
|
45
56
|
|
|
46
57
|
const userId = await resolveUserId(email, env, infisicalConfig, token);
|
|
47
58
|
const billing = await connectBillingDB(env, infisicalConfig, token);
|
|
@@ -49,7 +60,6 @@ async function main() {
|
|
|
49
60
|
|
|
50
61
|
const now = new Date().toISOString();
|
|
51
62
|
const safeUserId = escapeSQL(userId);
|
|
52
|
-
const safeDesc = escapeSQL(description || `Admin ${type} grant`);
|
|
53
63
|
|
|
54
64
|
console.log(`Granting to wallet...`);
|
|
55
65
|
const txSQL = `
|
|
@@ -64,7 +74,7 @@ ON CONFLICT (user_id) DO NOTHING;
|
|
|
64
74
|
UPDATE usd_wallets SET granted_balance_micros = granted_balance_micros + ${amountMicros}, updated_at = '${now}'
|
|
65
75
|
WHERE user_id = '${safeUserId}';
|
|
66
76
|
|
|
67
|
-
-- Record topup for audit trail
|
|
77
|
+
-- Record topup for audit trail (source='admin_grant' aligns with billing service convention)
|
|
68
78
|
INSERT INTO usd_wallet_topups (id, wallet_id, amount_micros, service_fee_micros, net_credit_micros, status, source, service_namespace, created_at, completed_at)
|
|
69
79
|
SELECT gen_random_uuid(), w.id, ${amountMicros}, 0, ${amountMicros}, 'completed', 'admin_grant', 'platform', '${now}', '${now}'
|
|
70
80
|
FROM usd_wallets w WHERE w.user_id = '${safeUserId}';
|
|
@@ -72,7 +82,7 @@ FROM usd_wallets w WHERE w.user_id = '${safeUserId}';
|
|
|
72
82
|
COMMIT;
|
|
73
83
|
`.trim();
|
|
74
84
|
bq(txSQL);
|
|
75
|
-
console.log(`✓
|
|
85
|
+
console.log(`✓ Granted $${amountUsd.toFixed(2)} to wallet`);
|
|
76
86
|
|
|
77
87
|
const balanceMicros = bq(`SELECT granted_balance_micros FROM usd_wallets WHERE user_id='${safeUserId}'`);
|
|
78
88
|
const balanceUsd = (parseInt(balanceMicros, 10) / 1000000).toFixed(2);
|
|
File without changes
|
|
@@ -4,27 +4,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
const db_utils_1 = require("./db-utils");
|
|
5
5
|
function parseArgs(args) {
|
|
6
6
|
if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
|
|
7
|
-
console.log(`Usage: optima-grant-
|
|
7
|
+
console.log(`Usage: optima-grant-balance <email> --amount <usd> [options]
|
|
8
|
+
|
|
9
|
+
Add USD balance to a user's wallet (granted_balance_micros).
|
|
10
|
+
Used for promotional grants, compensation, referral rewards, etc.
|
|
8
11
|
|
|
9
12
|
Options:
|
|
10
|
-
--amount <
|
|
11
|
-
--
|
|
12
|
-
--description <text> Description (optional)
|
|
13
|
+
--amount <usd> USD amount to grant (required, e.g. 5 for $5.00)
|
|
14
|
+
--description <text> Description for audit trail (optional)
|
|
13
15
|
--env <env> Environment: stage, prod (default: stage)
|
|
14
|
-
-h, --help Show this help
|
|
16
|
+
-h, --help Show this help
|
|
17
|
+
|
|
18
|
+
Examples:
|
|
19
|
+
optima-grant-balance user@example.com --amount 5 --env prod
|
|
20
|
+
optima-grant-balance user@example.com --amount 10 --description "Service outage compensation"`);
|
|
15
21
|
process.exit(0);
|
|
16
22
|
}
|
|
17
23
|
const email = args[0];
|
|
18
|
-
let
|
|
19
|
-
let type = 'bonus';
|
|
24
|
+
let amountUsd = 0;
|
|
20
25
|
let description = null;
|
|
21
26
|
let env = 'stage';
|
|
22
27
|
for (let i = 1; i < args.length; i++) {
|
|
23
28
|
if (args[i] === '--amount' && args[i + 1]) {
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
else if (args[i] === '--type' && args[i + 1]) {
|
|
27
|
-
type = args[++i];
|
|
29
|
+
amountUsd = parseFloat(args[++i]);
|
|
28
30
|
}
|
|
29
31
|
else if (args[i] === '--description' && args[i + 1]) {
|
|
30
32
|
description = args[++i];
|
|
@@ -33,32 +35,30 @@ Options:
|
|
|
33
35
|
env = args[++i];
|
|
34
36
|
}
|
|
35
37
|
}
|
|
36
|
-
if (
|
|
37
|
-
console.error('--amount is required and must be
|
|
38
|
-
process.exit(1);
|
|
39
|
-
}
|
|
40
|
-
if (!['bonus', 'referral'].includes(type)) {
|
|
41
|
-
console.error(`Unknown type: ${type}. Available: bonus, referral`);
|
|
38
|
+
if (!Number.isFinite(amountUsd) || amountUsd <= 0) {
|
|
39
|
+
console.error('--amount is required and must be > 0 (USD)');
|
|
42
40
|
process.exit(1);
|
|
43
41
|
}
|
|
44
42
|
if (!['stage', 'prod'].includes(env)) {
|
|
45
43
|
console.error('Env must be stage or prod (billing DB not available in CI)');
|
|
46
44
|
process.exit(1);
|
|
47
45
|
}
|
|
48
|
-
return { email,
|
|
46
|
+
return { email, amountUsd, description, env };
|
|
49
47
|
}
|
|
50
48
|
async function main() {
|
|
51
|
-
const { email,
|
|
49
|
+
const { email, amountUsd, description, env } = parseArgs(process.argv.slice(2));
|
|
52
50
|
const infisicalConfig = (0, db_utils_1.getInfisicalConfig)();
|
|
53
51
|
const token = (0, db_utils_1.getInfisicalToken)(infisicalConfig);
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
// 1 USD = 1,000,000 micros. Round to integer micros.
|
|
53
|
+
const amountMicros = Math.round(amountUsd * 1000000);
|
|
54
|
+
console.log(`\n🎁 Granting $${amountUsd.toFixed(2)} to ${email} [${env.toUpperCase()}]\n`);
|
|
55
|
+
if (description)
|
|
56
|
+
console.log(` Reason: ${description}`);
|
|
56
57
|
const userId = await (0, db_utils_1.resolveUserId)(email, env, infisicalConfig, token);
|
|
57
58
|
const billing = await (0, db_utils_1.connectBillingDB)(env, infisicalConfig, token);
|
|
58
59
|
const bq = billing.query;
|
|
59
60
|
const now = new Date().toISOString();
|
|
60
61
|
const safeUserId = (0, db_utils_1.escapeSQL)(userId);
|
|
61
|
-
const safeDesc = (0, db_utils_1.escapeSQL)(description || `Admin ${type} grant`);
|
|
62
62
|
console.log(`Granting to wallet...`);
|
|
63
63
|
const txSQL = `
|
|
64
64
|
BEGIN;
|
|
@@ -72,7 +72,7 @@ ON CONFLICT (user_id) DO NOTHING;
|
|
|
72
72
|
UPDATE usd_wallets SET granted_balance_micros = granted_balance_micros + ${amountMicros}, updated_at = '${now}'
|
|
73
73
|
WHERE user_id = '${safeUserId}';
|
|
74
74
|
|
|
75
|
-
-- Record topup for audit trail
|
|
75
|
+
-- Record topup for audit trail (source='admin_grant' aligns with billing service convention)
|
|
76
76
|
INSERT INTO usd_wallet_topups (id, wallet_id, amount_micros, service_fee_micros, net_credit_micros, status, source, service_namespace, created_at, completed_at)
|
|
77
77
|
SELECT gen_random_uuid(), w.id, ${amountMicros}, 0, ${amountMicros}, 'completed', 'admin_grant', 'platform', '${now}', '${now}'
|
|
78
78
|
FROM usd_wallets w WHERE w.user_id = '${safeUserId}';
|
|
@@ -80,7 +80,7 @@ FROM usd_wallets w WHERE w.user_id = '${safeUserId}';
|
|
|
80
80
|
COMMIT;
|
|
81
81
|
`.trim();
|
|
82
82
|
bq(txSQL);
|
|
83
|
-
console.log(`✓
|
|
83
|
+
console.log(`✓ Granted $${amountUsd.toFixed(2)} to wallet`);
|
|
84
84
|
const balanceMicros = bq(`SELECT granted_balance_micros FROM usd_wallets WHERE user_id='${safeUserId}'`);
|
|
85
85
|
const balanceUsd = (parseInt(balanceMicros, 10) / 1000000).toFixed(2);
|
|
86
86
|
console.log(`\n✅ Done! ${email} now has $${balanceUsd} granted balance\n`);
|
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optima-chat/dev-skills",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.32",
|
|
4
4
|
"description": "Claude Code Skills for Optima development team - cross-environment collaboration tools",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"optima-generate-test-token": "dist/bin/helpers/generate-test-token.js",
|
|
10
10
|
"optima-show-env": "dist/bin/helpers/show-env.js",
|
|
11
11
|
"optima-grant-subscription": "dist/bin/helpers/grant-subscription.js",
|
|
12
|
-
"optima-grant-
|
|
12
|
+
"optima-grant-balance": "dist/bin/helpers/grant-balance.js"
|
|
13
13
|
},
|
|
14
14
|
"scripts": {
|
|
15
15
|
"postinstall": "node scripts/install.js",
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"WebSearch",
|
|
5
|
-
"WebFetch(domain:code.claude.com)",
|
|
6
|
-
"WebFetch(domain:platform.claude.com)",
|
|
7
|
-
"WebFetch(domain:github.com)",
|
|
8
|
-
"Bash(gh repo view:*)",
|
|
9
|
-
"Bash(gh repo clone:*)",
|
|
10
|
-
"Bash(gh repo list:*)",
|
|
11
|
-
"Read(//private/tmp/optima-docs/**)",
|
|
12
|
-
"Read(//tmp/optima-docs/**)",
|
|
13
|
-
"Bash(git init:*)",
|
|
14
|
-
"Bash(gh repo create:*)",
|
|
15
|
-
"Read(//private/tmp/optima-workspace/**)",
|
|
16
|
-
"Read(//tmp/optima-workspace/**)",
|
|
17
|
-
"Read(//tmp/optima-workspace/.claude/commands/**)",
|
|
18
|
-
"Bash(git add:*)",
|
|
19
|
-
"Bash(git push:*)",
|
|
20
|
-
"Bash(find:*)",
|
|
21
|
-
"Bash(git commit:*)",
|
|
22
|
-
"Bash(aws logs get-log-events:*)",
|
|
23
|
-
"Bash(npm install:*)",
|
|
24
|
-
"Bash(optima-dev-skills:*)",
|
|
25
|
-
"Bash(optima-generate-test-token:*)",
|
|
26
|
-
"Bash(optima-query-db:*)",
|
|
27
|
-
"Bash(gh variable set:*)",
|
|
28
|
-
"Bash(npm publish:*)",
|
|
29
|
-
"Bash(python3:*)",
|
|
30
|
-
"Bash(gh api:*)",
|
|
31
|
-
"Bash(curl -s http://auth.optima.chat/openapi.json)",
|
|
32
|
-
"Bash(curl -s https://auth.optima.chat/openapi.json)",
|
|
33
|
-
"Bash(cat:*)",
|
|
34
|
-
"Bash(node /Users/verypro/optima-dev-skills/scripts/install.js:*)",
|
|
35
|
-
"Bash(aws logs tail:*)",
|
|
36
|
-
"Bash(grep:*)",
|
|
37
|
-
"Bash(npm view:*)",
|
|
38
|
-
"Bash(npm version:*)",
|
|
39
|
-
"Bash(git checkout:*)",
|
|
40
|
-
"Bash(git pull:*)",
|
|
41
|
-
"Bash(node scripts/install.js:*)",
|
|
42
|
-
"Bash(gh issue:*)",
|
|
43
|
-
"Bash(npm run:*)",
|
|
44
|
-
"Bash(gh pr:*)",
|
|
45
|
-
"Bash(node:*)",
|
|
46
|
-
"Bash(echo \"exit: $?\")"
|
|
47
|
-
],
|
|
48
|
-
"deny": [],
|
|
49
|
-
"ask": []
|
|
50
|
-
}
|
|
51
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: "grant-credits"
|
|
3
|
-
description: "当用户请求赠送 credits、充值余额、grant credits、加余额、奖励积分、补偿、推荐奖励时,使用此技能。支持 Stage、Prod 两个环境。"
|
|
4
|
-
allowed-tools: ["Bash"]
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# 赠送余额(Grant Credits)
|
|
8
|
-
|
|
9
|
-
当你需要为用户赠送额外 wallet 余额时,使用这个场景。赠送的额度会加到 `usd_wallets.granted_balance_micros`。
|
|
10
|
-
|
|
11
|
-
## 执行方式:使用 CLI 工具
|
|
12
|
-
|
|
13
|
-
**重要**:使用 `optima-grant-credits` CLI 工具:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
optima-grant-credits <email> --amount <n> [options]
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
**为什么使用 CLI 工具**:
|
|
20
|
-
- 自动通过 email 查找 userId(跨 user-auth 数据库)
|
|
21
|
-
- 自动处理 SSH 隧道和数据库连接
|
|
22
|
-
- 不会影响现有订阅和已有余额(纯追加到 granted balance)
|
|
23
|
-
- 一条命令完成操作
|
|
24
|
-
|
|
25
|
-
## 适用情况
|
|
26
|
-
|
|
27
|
-
- 赠送额外余额(奖励、补偿、推广等)
|
|
28
|
-
- 推荐奖励
|
|
29
|
-
- 运营活动发放
|
|
30
|
-
- 客户补偿
|
|
31
|
-
|
|
32
|
-
## 快速操作
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
# 赠送 100 credits ($1.00),Stage 环境(默认)
|
|
36
|
-
optima-grant-credits user@example.com --amount 100
|
|
37
|
-
|
|
38
|
-
# 赠送 500 credits ($5.00),Prod 环境
|
|
39
|
-
optima-grant-credits user@example.com --amount 500 --env prod
|
|
40
|
-
|
|
41
|
-
# 推荐奖励
|
|
42
|
-
optima-grant-credits user@example.com --amount 200 --type referral --env prod
|
|
43
|
-
|
|
44
|
-
# 自定义描述
|
|
45
|
-
optima-grant-credits user@example.com --amount 300 --description "客户补偿 - 服务中断" --env prod
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
> 1 credit = $0.01 = 10,000 micros。--amount 500 即赠送 $5.00 到 granted balance。
|
|
49
|
-
|
|
50
|
-
### 参数说明
|
|
51
|
-
|
|
52
|
-
| 参数 | 说明 | 默认值 |
|
|
53
|
-
|------|------|--------|
|
|
54
|
-
| `<email>` | 用户邮箱(必填) | - |
|
|
55
|
-
| `--amount <n>` | Credits 数量(必填,>=1,1 credit = $0.01) | - |
|
|
56
|
-
| `--type <type>` | 类型:bonus, referral | bonus |
|
|
57
|
-
| `--description <text>` | 描述(可选) | Auto-generated |
|
|
58
|
-
| `--env <env>` | 环境:stage, prod | stage |
|
|
59
|
-
|
|
60
|
-
## 与 grant-subscription 的区别
|
|
61
|
-
|
|
62
|
-
| | grant-credits | grant-subscription |
|
|
63
|
-
|---|---|---|
|
|
64
|
-
| 作用 | 追加 granted balance | 开通/切换订阅计划 |
|
|
65
|
-
| 现有余额 | 不影响(纯累加) | 重置 granted balance |
|
|
66
|
-
| 现有订阅 | 不影响 | 取消旧的,创建新的 |
|
|
67
|
-
| Token quota | 不影响 | 按计划更新 |
|
|
68
|
-
| 适用场景 | 奖励、补偿、推广 | 开通会员、升级计划 |
|
|
69
|
-
|
|
70
|
-
## 常见使用场景
|
|
71
|
-
|
|
72
|
-
### 场景 1:奖励余额
|
|
73
|
-
|
|
74
|
-
**用户请求**:"给 xxx@gmail.com 加 200 credits"
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
optima-grant-credits xxx@gmail.com --amount 200 --env prod
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### 场景 2:推荐奖励
|
|
81
|
-
|
|
82
|
-
**用户请求**:"xxx 推荐了新用户,给他 referral 奖励 300"
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
optima-grant-credits xxx@gmail.com --amount 300 --type referral --env prod
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### 场景 3:客户补偿
|
|
89
|
-
|
|
90
|
-
**用户请求**:"服务出了问题,补偿 xxx $5"
|
|
91
|
-
|
|
92
|
-
```bash
|
|
93
|
-
optima-grant-credits xxx@gmail.com --amount 500 --description "服务中断补偿" --env prod
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## 安全提醒
|
|
97
|
-
|
|
98
|
-
1. **Stage 优先**:默认操作 Stage 环境
|
|
99
|
-
2. **Prod 谨慎**:操作 Prod 前确认邮箱和数量
|
|
100
|
-
3. **纯追加**:不会影响现有余额和订阅(累加到 granted balance)
|
|
101
|
-
4. **无过期**:granted balance 不会自动过期
|
|
102
|
-
|
|
103
|
-
## 相关命令
|
|
104
|
-
|
|
105
|
-
- `optima-grant-credits` - 赠送余额(主要方式)
|
|
106
|
-
- `optima-grant-subscription` - 开通订阅计划
|
|
107
|
-
- `optima-query-db` - 查询数据库验证结果
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: "grant-credits"
|
|
3
|
-
description: "Use when the user wants to add bonus or referral balance to an Optima user's wallet without changing their subscription."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Grant Credits
|
|
7
|
-
|
|
8
|
-
Use this skill when the user asks to add credits directly.
|
|
9
|
-
|
|
10
|
-
## Preferred Command
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
optima-grant-credits <email> --amount <n> [options]
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
## Examples
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
optima-grant-credits user@example.com --amount 100
|
|
20
|
-
optima-grant-credits user@example.com --amount 500 --env prod
|
|
21
|
-
optima-grant-credits user@example.com --amount 300 --type referral --env prod
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Guidance
|
|
25
|
-
|
|
26
|
-
- Default to `stage`.
|
|
27
|
-
- Confirm the email and amount before using `prod`.
|
|
28
|
-
- This operation appends to the user's wallet granted balance and does not replace their subscription. Amount is in credits (1 credit = $0.01).
|