@optima-chat/dev-skills 0.7.20 → 0.7.21

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.
@@ -32,6 +32,10 @@
32
32
  - `commerce-rq-worker` - RQ 后台任务
33
33
  - `commerce-rq-scheduler` - RQ 定时调度
34
34
  - `optima-logistics` - 物流服务(仅 Stage/Prod)
35
+ - `billing` - 计费服务(仅 Stage/Prod)
36
+ - `browser-backend` - 浏览器自动化服务(仅 Stage/Prod)
37
+ - `optima-generation` - 内容生成服务(仅 Stage/Prod)
38
+ - `optima-generation-worker` - 内容生成 Worker(仅 Stage/Prod)
35
39
  - `lines` (可选): 显示行数,默认 50
36
40
  - `environment` (可选): 环境,默认 ci
37
41
  - `ci` - CI 持续集成环境(开发环境,默认)
@@ -128,6 +132,10 @@ aws logs get-log-events --log-group-name /ecs/commerce-backend-stage --log-strea
128
132
  - `commerce-rq-worker` → `/ecs/commerce-rq-worker-stage`
129
133
  - `commerce-rq-scheduler` → `/ecs/commerce-rq-scheduler-stage`
130
134
  - `optima-logistics` → `/ecs/optima-logistics-stage`
135
+ - `billing` → `/ecs/billing-stage`
136
+ - `browser-backend` → `/ecs/browser-backend-stage`
137
+ - `optima-generation` → `/ecs/optima-generation-stage`
138
+ - `optima-generation-worker` → `/ecs/optima-generation-worker-stage`
131
139
 
132
140
  ### 2. Prod 环境(environment = "prod")
133
141
 
@@ -167,6 +175,10 @@ aws logs get-log-events --log-group-name /ecs/commerce-backend-prod --log-stream
167
175
  - `commerce-rq-worker` → `/ecs/commerce-rq-worker-prod`
168
176
  - `commerce-rq-scheduler` → `/ecs/commerce-rq-scheduler-prod`
169
177
  - `optima-logistics` → `/ecs/optima-logistics-prod`
178
+ - `billing` → `/ecs/billing-prod`
179
+ - `browser-backend` → `/ecs/browser-backend-prod`
180
+ - `optima-generation` → `/ecs/optima-generation-prod`
181
+ - `optima-generation-worker` → `/ecs/optima-generation-worker-prod`
170
182
 
171
183
  **注意**: `optima-store` 仅在 Stage 环境部署
172
184
 
@@ -47,6 +47,10 @@ optima-query-db commerce-backend "SELECT * FROM products LIMIT 5" prod
47
47
  - `agentic-chat` - AI 聊天服务数据库
48
48
  - `bi-backend` - BI 后端数据库
49
49
  - `session-gateway` - AI Shell 网关数据库
50
+ - `optima-logistics` - 物流服务数据库
51
+ - `billing` - 计费服务数据库
52
+ - `browser-backend` - 浏览器自动化服务数据库
53
+ - `optima-generation` - 内容生成服务数据库
50
54
  - `sql` (必需): SQL 查询语句(用引号包裹)
51
55
  - `environment` (可选): 环境,默认 ci
52
56
  - `ci` - CI 持续集成环境(开发环境,默认)
@@ -245,9 +249,22 @@ pkill -f "ssh.*15432:${DATABASE_HOST}:5432"
245
249
  - 用户: Infisical `AI_SHELL_DB_USER`
246
250
  - 密码: Infisical `AI_SHELL_DB_PASSWORD`
247
251
 
252
+ - `billing`:
253
+ - 数据库: `optima_billing_stage`
254
+ - 凭证: Infisical `/services/billing` → `DATABASE_URL`
255
+
256
+ - `browser-backend`:
257
+ - 数据库: `optima_stage_browser`
258
+ - 凭证: Infisical `/services/browser-backend` → `DATABASE_URL`
259
+
260
+ - `optima-generation`:
261
+ - 数据库: `optima_generation_stage`
262
+ - 凭证: Infisical `/services/optima-generation` → `DATABASE_URL`
263
+
248
264
  **说明**:
249
265
  - Infisical 配置从 GitHub Variables 获取
250
266
  - 数据库密钥从 Infisical 动态获取(项目: optima-secrets-v2, 环境: staging, 路径: /shared-secrets/database-users)
267
+ - billing、browser-backend、optima-generation 的凭证存在各自服务路径的 DATABASE_URL 中
251
268
  - Stage RDS: `optima-stage-postgres.ctg866o0ehac.ap-southeast-1.rds.amazonaws.com`
252
269
  - Shared EC2 IP: `3.0.210.113`
253
270
  - SSH 隧道: 本地端口 `15432` → Shared EC2 → Stage RDS `5432`
@@ -343,9 +360,22 @@ pkill -f "ssh.*15433:${DATABASE_HOST}:5432"
343
360
  - 用户: Infisical `AI_SHELL_DB_USER`
344
361
  - 密码: Infisical `AI_SHELL_DB_PASSWORD`
345
362
 
363
+ - `billing`:
364
+ - 数据库: `optima_billing`
365
+ - 凭证: Infisical `/services/billing` → `DATABASE_URL`
366
+
367
+ - `browser-backend`:
368
+ - 数据库: `optima_browser`
369
+ - 凭证: Infisical `/services/browser-backend` → `DATABASE_URL`
370
+
371
+ - `optima-generation`:
372
+ - 数据库: `optima_generation`
373
+ - 凭证: Infisical `/services/optima-generation` → `DATABASE_URL`
374
+
346
375
  **说明**:
347
376
  - Infisical 配置从 GitHub Variables 获取
348
377
  - 数据库密钥从 Infisical 动态获取(项目: optima-secrets-v2, 环境: prod, 路径: /shared-secrets/database-users)
378
+ - billing、browser-backend、optima-generation 的凭证存在各自服务路径的 DATABASE_URL 中
349
379
  - Prod RDS: `optima-prod-postgres.ctg866o0ehac.ap-southeast-1.rds.amazonaws.com`
350
380
  - Shared EC2 IP: `3.0.210.113`
351
381
  - SSH 隧道: 本地端口 `15433` → Shared EC2 → Prod RDS `5432`
@@ -31,6 +31,10 @@
31
31
  - `optima-scout` - 产品研究工具
32
32
  - `ai-shell-web-ui` - Shell Web UI
33
33
  - `optima-store` - 商城前端(仅 Stage)
34
+ - `billing` - 计费服务
35
+ - `browser-backend` - 浏览器自动化服务
36
+ - `optima-generation` - 内容生成服务
37
+ - `optima-generation-worker` - 内容生成 Worker
34
38
  - `pgbouncer` - 连接池(仅 Stage)
35
39
  - `environment` (可选): 环境,默认 stage
36
40
  - `stage` - Stage 预发布环境(默认,更安全)
@@ -93,6 +97,10 @@ aws ecs update-service \
93
97
  - `optima-scout-stage`
94
98
  - `ai-shell-web-ui-stage`
95
99
  - `optima-store-stage`
100
+ - `billing-stage`
101
+ - `browser-backend-stage`
102
+ - `optima-generation-stage`
103
+ - `optima-generation-worker-stage`
96
104
  - `pgbouncer-stage`
97
105
 
98
106
  ### 2. Prod 环境重启(environment = "prod")
@@ -126,6 +134,10 @@ aws ecs update-service \
126
134
  - `bi-dashboard-prod`
127
135
  - `optima-scout-prod`
128
136
  - `ai-shell-web-ui-prod`
137
+ - `billing-prod`
138
+ - `browser-backend-prod`
139
+ - `optima-generation-prod`
140
+ - `optima-generation-worker-prod`
129
141
 
130
142
  **注意**: `optima-store` 和 `pgbouncer` 仅在 Stage 环境部署
131
143
 
@@ -0,0 +1,46 @@
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
+ ],
43
+ "deny": [],
44
+ "ask": []
45
+ }
46
+ }
package/bin/cli.js CHANGED
@@ -38,6 +38,7 @@ switch (command) {
38
38
 
39
39
  log('\nSupported Services:', 'yellow');
40
40
  log(' commerce-backend user-auth mcp-host agentic-chat optima-logistics', 'cyan');
41
+ log(' optima-scout billing browser-backend optima-generation', 'cyan');
41
42
 
42
43
  log('\nEnvironments:', 'yellow');
43
44
  log(' stage (default) prod', 'cyan');
@@ -47,6 +47,21 @@ const SERVICE_DB_MAP = {
47
47
  ci: null,
48
48
  stage: { userKey: 'LOGISTICS_DB_USER', passwordKey: 'LOGISTICS_DB_PASSWORD', database: 'optima_stage_logistics' },
49
49
  prod: { userKey: 'LOGISTICS_DB_USER', passwordKey: 'LOGISTICS_DB_PASSWORD', database: 'optima_logistics' }
50
+ },
51
+ 'billing': {
52
+ ci: null,
53
+ stage: { databaseUrlPath: '/services/billing', databaseUrlKey: 'DATABASE_URL' },
54
+ prod: { databaseUrlPath: '/services/billing', databaseUrlKey: 'DATABASE_URL' }
55
+ },
56
+ 'browser-backend': {
57
+ ci: null,
58
+ stage: { databaseUrlPath: '/services/browser-backend', databaseUrlKey: 'DATABASE_URL' },
59
+ prod: { databaseUrlPath: '/services/browser-backend', databaseUrlKey: 'DATABASE_URL' }
60
+ },
61
+ 'optima-generation': {
62
+ ci: null,
63
+ stage: { databaseUrlPath: '/services/optima-generation', databaseUrlKey: 'DATABASE_URL' },
64
+ prod: { databaseUrlPath: '/services/optima-generation', databaseUrlKey: 'DATABASE_URL' }
50
65
  }
51
66
  };
52
67
 
@@ -59,6 +74,21 @@ const RDS_HOSTS = {
59
74
  // 统一使用 BI Data ARM Host 作为跳板机
60
75
  const EC2_HOST = '3.0.210.113';
61
76
 
77
+ function parseDatabaseUrl(url: string): { user: string; password: string; host: string; port: number; database: string } {
78
+ // postgresql://user:password@host:port/database?params
79
+ const match = url.match(/^postgresql:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/([^?]+)/);
80
+ if (!match) {
81
+ throw new Error(`Failed to parse DATABASE_URL: ${url}`);
82
+ }
83
+ return {
84
+ user: decodeURIComponent(match[1]),
85
+ password: decodeURIComponent(match[2]),
86
+ host: match[3],
87
+ port: parseInt(match[4]),
88
+ database: match[5]
89
+ };
90
+ }
91
+
62
92
  function getGitHubVariable(name: string): string {
63
93
  return execSync(`gh variable get ${name} -R Optima-Chat/optima-dev-skills`, { encoding: 'utf-8' }).trim();
64
94
  }
@@ -179,7 +209,7 @@ async function main() {
179
209
  if (args.length < 2) {
180
210
  console.error('Usage: query-db.ts <service> <sql> [environment]');
181
211
  console.error('');
182
- console.error('Services: commerce-backend, user-auth, agentic-chat, bi-backend, session-gateway');
212
+ console.error('Services: commerce-backend, user-auth, agentic-chat, bi-backend, session-gateway, optima-logistics, billing, browser-backend, optima-generation');
183
213
  console.error('Environments: ci (default), stage, prod');
184
214
  console.error('');
185
215
  console.error('Example: query-db.ts user-auth "SELECT COUNT(*) FROM users" prod');
@@ -228,19 +258,42 @@ async function main() {
228
258
  const token = getInfisicalToken(infisicalConfig);
229
259
  console.log('✓ Obtained Infisical access token');
230
260
 
231
- // 数据库凭证存储在 Infisical 的 /shared-secrets/database-users 路径
232
- // Stage 从 staging 环境读取,Prod 从 prod 环境读取
233
261
  const infisicalEnv = environment === 'stage' ? 'staging' : 'prod';
234
- const secrets = getInfisicalSecrets(infisicalConfig, token, infisicalEnv, '/shared-secrets/database-users');
235
- console.log('✓ Retrieved database credentials from Infisical');
236
-
237
- const { userKey, passwordKey, database } = serviceConfig as any;
238
- const dbHost = RDS_HOSTS[environment as 'stage' | 'prod'];
239
- const dbUser = secrets[userKey];
240
- const dbPassword = secrets[passwordKey];
241
-
242
- if (!dbUser || !dbPassword) {
243
- throw new Error(`Database credentials not found in Infisical for ${service}. Keys: ${userKey}, ${passwordKey}`);
262
+ let dbUser: string;
263
+ let dbPassword: string;
264
+ let dbHost: string;
265
+ let database: string;
266
+
267
+ if ('databaseUrlPath' in (serviceConfig as any)) {
268
+ // 从服务路径获取 DATABASE_URL 并解析
269
+ const { databaseUrlPath, databaseUrlKey } = serviceConfig as any;
270
+ const secrets = getInfisicalSecrets(infisicalConfig, token, infisicalEnv, databaseUrlPath);
271
+ console.log(`✓ Retrieved DATABASE_URL from Infisical (path: ${databaseUrlPath})`);
272
+
273
+ const databaseUrl = secrets[databaseUrlKey];
274
+ if (!databaseUrl) {
275
+ throw new Error(`DATABASE_URL not found in Infisical at ${databaseUrlPath}`);
276
+ }
277
+
278
+ const parsed = parseDatabaseUrl(databaseUrl);
279
+ dbUser = parsed.user;
280
+ dbPassword = parsed.password;
281
+ dbHost = parsed.host;
282
+ database = parsed.database;
283
+ } else {
284
+ // 从 shared-secrets/database-users 获取凭证
285
+ const secrets = getInfisicalSecrets(infisicalConfig, token, infisicalEnv, '/shared-secrets/database-users');
286
+ console.log('✓ Retrieved database credentials from Infisical');
287
+
288
+ const { userKey, passwordKey } = serviceConfig as any;
289
+ database = (serviceConfig as any).database;
290
+ dbHost = RDS_HOSTS[environment as 'stage' | 'prod'];
291
+ dbUser = secrets[userKey];
292
+ dbPassword = secrets[passwordKey];
293
+
294
+ if (!dbUser || !dbPassword) {
295
+ throw new Error(`Database credentials not found in Infisical for ${service}. Keys: ${userKey}, ${passwordKey}`);
296
+ }
244
297
  }
245
298
 
246
299
  const localPort = environment === 'stage' ? 15432 : 15433;
@@ -20,7 +20,10 @@ const SUPPORTED_SERVICES = [
20
20
  'optima-scout',
21
21
  'mcp-host',
22
22
  'shopify-backend',
23
- 'optima-logistics'
23
+ 'optima-logistics',
24
+ 'billing',
25
+ 'browser-backend',
26
+ 'optima-generation'
24
27
  ];
25
28
 
26
29
  // 环境到 Infisical environment 的映射
File without changes
@@ -66,6 +66,21 @@ const SERVICE_DB_MAP = {
66
66
  ci: null,
67
67
  stage: { userKey: 'LOGISTICS_DB_USER', passwordKey: 'LOGISTICS_DB_PASSWORD', database: 'optima_stage_logistics' },
68
68
  prod: { userKey: 'LOGISTICS_DB_USER', passwordKey: 'LOGISTICS_DB_PASSWORD', database: 'optima_logistics' }
69
+ },
70
+ 'billing': {
71
+ ci: null,
72
+ stage: { databaseUrlPath: '/services/billing', databaseUrlKey: 'DATABASE_URL' },
73
+ prod: { databaseUrlPath: '/services/billing', databaseUrlKey: 'DATABASE_URL' }
74
+ },
75
+ 'browser-backend': {
76
+ ci: null,
77
+ stage: { databaseUrlPath: '/services/browser-backend', databaseUrlKey: 'DATABASE_URL' },
78
+ prod: { databaseUrlPath: '/services/browser-backend', databaseUrlKey: 'DATABASE_URL' }
79
+ },
80
+ 'optima-generation': {
81
+ ci: null,
82
+ stage: { databaseUrlPath: '/services/optima-generation', databaseUrlKey: 'DATABASE_URL' },
83
+ prod: { databaseUrlPath: '/services/optima-generation', databaseUrlKey: 'DATABASE_URL' }
69
84
  }
70
85
  };
71
86
  // Stage 和 Prod 独立的 RDS 实例
@@ -75,6 +90,20 @@ const RDS_HOSTS = {
75
90
  };
76
91
  // 统一使用 BI Data ARM Host 作为跳板机
77
92
  const EC2_HOST = '3.0.210.113';
93
+ function parseDatabaseUrl(url) {
94
+ // postgresql://user:password@host:port/database?params
95
+ const match = url.match(/^postgresql:\/\/([^:]+):([^@]+)@([^:]+):(\d+)\/([^?]+)/);
96
+ if (!match) {
97
+ throw new Error(`Failed to parse DATABASE_URL: ${url}`);
98
+ }
99
+ return {
100
+ user: decodeURIComponent(match[1]),
101
+ password: decodeURIComponent(match[2]),
102
+ host: match[3],
103
+ port: parseInt(match[4]),
104
+ database: match[5]
105
+ };
106
+ }
78
107
  function getGitHubVariable(name) {
79
108
  return (0, child_process_1.execSync)(`gh variable get ${name} -R Optima-Chat/optima-dev-skills`, { encoding: 'utf-8' }).trim();
80
109
  }
@@ -170,7 +199,7 @@ async function main() {
170
199
  if (args.length < 2) {
171
200
  console.error('Usage: query-db.ts <service> <sql> [environment]');
172
201
  console.error('');
173
- console.error('Services: commerce-backend, user-auth, agentic-chat, bi-backend, session-gateway');
202
+ console.error('Services: commerce-backend, user-auth, agentic-chat, bi-backend, session-gateway, optima-logistics, billing, browser-backend, optima-generation');
174
203
  console.error('Environments: ci (default), stage, prod');
175
204
  console.error('');
176
205
  console.error('Example: query-db.ts user-auth "SELECT COUNT(*) FROM users" prod');
@@ -206,17 +235,38 @@ async function main() {
206
235
  console.log('✓ Loaded Infisical config from GitHub Variables');
207
236
  const token = getInfisicalToken(infisicalConfig);
208
237
  console.log('✓ Obtained Infisical access token');
209
- // 数据库凭证存储在 Infisical 的 /shared-secrets/database-users 路径
210
- // Stage 从 staging 环境读取,Prod 从 prod 环境读取
211
238
  const infisicalEnv = environment === 'stage' ? 'staging' : 'prod';
212
- const secrets = getInfisicalSecrets(infisicalConfig, token, infisicalEnv, '/shared-secrets/database-users');
213
- console.log('✓ Retrieved database credentials from Infisical');
214
- const { userKey, passwordKey, database } = serviceConfig;
215
- const dbHost = RDS_HOSTS[environment];
216
- const dbUser = secrets[userKey];
217
- const dbPassword = secrets[passwordKey];
218
- if (!dbUser || !dbPassword) {
219
- throw new Error(`Database credentials not found in Infisical for ${service}. Keys: ${userKey}, ${passwordKey}`);
239
+ let dbUser;
240
+ let dbPassword;
241
+ let dbHost;
242
+ let database;
243
+ if ('databaseUrlPath' in serviceConfig) {
244
+ // 从服务路径获取 DATABASE_URL 并解析
245
+ const { databaseUrlPath, databaseUrlKey } = serviceConfig;
246
+ const secrets = getInfisicalSecrets(infisicalConfig, token, infisicalEnv, databaseUrlPath);
247
+ console.log(`✓ Retrieved DATABASE_URL from Infisical (path: ${databaseUrlPath})`);
248
+ const databaseUrl = secrets[databaseUrlKey];
249
+ if (!databaseUrl) {
250
+ throw new Error(`DATABASE_URL not found in Infisical at ${databaseUrlPath}`);
251
+ }
252
+ const parsed = parseDatabaseUrl(databaseUrl);
253
+ dbUser = parsed.user;
254
+ dbPassword = parsed.password;
255
+ dbHost = parsed.host;
256
+ database = parsed.database;
257
+ }
258
+ else {
259
+ // 从 shared-secrets/database-users 获取凭证
260
+ const secrets = getInfisicalSecrets(infisicalConfig, token, infisicalEnv, '/shared-secrets/database-users');
261
+ console.log('✓ Retrieved database credentials from Infisical');
262
+ const { userKey, passwordKey } = serviceConfig;
263
+ database = serviceConfig.database;
264
+ dbHost = RDS_HOSTS[environment];
265
+ dbUser = secrets[userKey];
266
+ dbPassword = secrets[passwordKey];
267
+ if (!dbUser || !dbPassword) {
268
+ throw new Error(`Database credentials not found in Infisical for ${service}. Keys: ${userKey}, ${passwordKey}`);
269
+ }
220
270
  }
221
271
  const localPort = environment === 'stage' ? 15432 : 15433;
222
272
  setupSSHTunnel(EC2_HOST, dbHost, localPort);
@@ -13,7 +13,10 @@ const SUPPORTED_SERVICES = [
13
13
  'optima-scout',
14
14
  'mcp-host',
15
15
  'shopify-backend',
16
- 'optima-logistics'
16
+ 'optima-logistics',
17
+ 'billing',
18
+ 'browser-backend',
19
+ 'optima-generation'
17
20
  ];
18
21
  // 环境到 Infisical environment 的映射
19
22
  const ENV_MAP = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/dev-skills",
3
- "version": "0.7.20",
3
+ "version": "0.7.21",
4
4
  "description": "Claude Code Skills for Optima development team - cross-environment collaboration tools",
5
5
  "main": "index.js",
6
6
  "bin": {