@optima-chat/dev-skills 0.7.8 → 0.7.10

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.
@@ -20,31 +20,40 @@ interface DatabaseConfig {
20
20
  const SERVICE_DB_MAP = {
21
21
  'commerce-backend': {
22
22
  ci: { container: 'commerce-postgres', user: 'commerce', password: 'commerce123', database: 'commerce' },
23
- stage: { userKey: 'COMMERCE_DB_USER', passwordKey: 'COMMERCE_DB_PASSWORD', database: 'optima_stage_commerce' },
23
+ stage: { userKey: 'COMMERCE_DB_USER', passwordKey: 'COMMERCE_DB_PASSWORD', database: 'optima_commerce' },
24
24
  prod: { userKey: 'COMMERCE_DB_USER', passwordKey: 'COMMERCE_DB_PASSWORD', database: 'optima_commerce' }
25
25
  },
26
26
  'user-auth': {
27
27
  ci: { container: 'user-auth-postgres-1', user: 'userauth', password: 'password123', database: 'userauth' },
28
- stage: { userKey: 'AUTH_DB_USER', passwordKey: 'AUTH_DB_PASSWORD', database: 'optima_stage_auth' },
28
+ stage: { userKey: 'AUTH_DB_USER', passwordKey: 'AUTH_DB_PASSWORD', database: 'optima_auth' },
29
29
  prod: { userKey: 'AUTH_DB_USER', passwordKey: 'AUTH_DB_PASSWORD', database: 'optima_auth' }
30
30
  },
31
- 'mcp-host': {
32
- ci: { container: 'mcp-host-db-1', user: 'mcp_user', password: 'mcp_password', database: 'mcp_host' },
33
- stage: { userKey: 'MCP_DB_USER', passwordKey: 'MCP_DB_PASSWORD', database: 'optima_stage_mcp' },
34
- prod: { userKey: 'MCP_DB_USER', passwordKey: 'MCP_DB_PASSWORD', database: 'optima_mcp' }
35
- },
36
31
  'agentic-chat': {
37
32
  ci: { container: 'optima-postgres', user: 'postgres', password: 'postgres123', database: 'optima_chat' },
38
- stage: { userKey: 'CHAT_DB_USER', passwordKey: 'CHAT_DB_PASSWORD', database: 'optima_stage_chat' },
33
+ stage: { userKey: 'CHAT_DB_USER', passwordKey: 'CHAT_DB_PASSWORD', database: 'optima_chat' },
39
34
  prod: { userKey: 'CHAT_DB_USER', passwordKey: 'CHAT_DB_PASSWORD', database: 'optima_chat' }
35
+ },
36
+ 'bi-backend': {
37
+ ci: null, // CI 环境暂无 BI 数据库
38
+ stage: { userKey: 'BI_DB_USER', passwordKey: 'BI_DB_PASSWORD', database: 'optima_bi' },
39
+ prod: { userKey: 'BI_DB_USER', passwordKey: 'BI_DB_PASSWORD', database: 'optima_bi' }
40
+ },
41
+ 'session-gateway': {
42
+ ci: null, // CI 环境暂无 session-gateway 数据库
43
+ stage: { userKey: 'SHELL_DB_USER', passwordKey: 'SHELL_DB_PASSWORD', database: 'optima_shell' },
44
+ prod: { userKey: 'AI_SHELL_DB_USER', passwordKey: 'AI_SHELL_DB_PASSWORD', database: 'optima_ai_shell' }
40
45
  }
41
46
  };
42
47
 
43
- const EC2_HOSTS = {
44
- stage: '54.179.132.102',
45
- prod: '18.136.25.239'
48
+ // Stage Prod 独立的 RDS 实例
49
+ const RDS_HOSTS = {
50
+ stage: 'optima-stage-postgres.ctg866o0ehac.ap-southeast-1.rds.amazonaws.com',
51
+ prod: 'optima-prod-postgres.ctg866o0ehac.ap-southeast-1.rds.amazonaws.com'
46
52
  };
47
53
 
54
+ // 统一使用 Shared EC2 作为跳板机
55
+ const EC2_HOST = '13.251.46.219';
56
+
48
57
  function getGitHubVariable(name: string): string {
49
58
  return execSync(`gh variable get ${name} -R Optima-Chat/optima-dev-skills`, { encoding: 'utf-8' }).trim();
50
59
  }
@@ -165,7 +174,7 @@ async function main() {
165
174
  if (args.length < 2) {
166
175
  console.error('Usage: query-db.ts <service> <sql> [environment]');
167
176
  console.error('');
168
- console.error('Services: commerce-backend, user-auth, mcp-host, agentic-chat');
177
+ console.error('Services: commerce-backend, user-auth, agentic-chat, bi-backend, session-gateway');
169
178
  console.error('Environments: ci (default), stage, prod');
170
179
  console.error('');
171
180
  console.error('Example: query-db.ts user-auth "SELECT COUNT(*) FROM users" prod');
@@ -182,6 +191,14 @@ async function main() {
182
191
 
183
192
  const serviceConfig = SERVICE_DB_MAP[service as keyof typeof SERVICE_DB_MAP][environment as 'ci' | 'stage' | 'prod'];
184
193
 
194
+ if (!serviceConfig) {
195
+ console.error(`Service ${service} is not available in ${environment.toUpperCase()} environment.`);
196
+ if (environment === 'ci') {
197
+ console.error('Try using stage or prod environment instead.');
198
+ }
199
+ process.exit(1);
200
+ }
201
+
185
202
  console.log(`\n🔍 Querying ${service} (${environment.toUpperCase()})...`);
186
203
 
187
204
  if (environment === 'ci') {
@@ -197,27 +214,52 @@ async function main() {
197
214
  { encoding: 'utf-8' }
198
215
  );
199
216
 
217
+ console.log('\n' + result);
218
+ } else if (environment === 'stage') {
219
+ // Stage 环境:直连 RDS(Stage RDS 在公有子网,可以本地直连)
220
+ const infisicalConfig = getInfisicalConfig();
221
+ console.log('✓ Loaded Infisical config from GitHub Variables');
222
+
223
+ const token = getInfisicalToken(infisicalConfig);
224
+ console.log('✓ Obtained Infisical access token');
225
+
226
+ const secrets = getInfisicalSecrets(infisicalConfig, token, 'staging');
227
+ console.log('✓ Retrieved database credentials from Infisical');
228
+
229
+ const { userKey, passwordKey, database } = serviceConfig as any;
230
+ const dbHost = RDS_HOSTS.stage;
231
+ const dbUser = secrets[userKey];
232
+ const dbPassword = secrets[passwordKey];
233
+
234
+ if (!dbUser || !dbPassword) {
235
+ throw new Error(`Database credentials not found in Infisical for ${service}. Keys: ${userKey}, ${passwordKey}`);
236
+ }
237
+
238
+ const result = queryDatabase(dbHost, 5432, dbUser, dbPassword, database, sql);
200
239
  console.log('\n' + result);
201
240
  } else {
202
- // Stage/Prod 环境:通过 SSH 隧道访问 RDS
241
+ // Prod 环境:通过 SSH 隧道访问 RDS(Prod RDS 在私有子网)
203
242
  const infisicalConfig = getInfisicalConfig();
204
243
  console.log('✓ Loaded Infisical config from GitHub Variables');
205
244
 
206
245
  const token = getInfisicalToken(infisicalConfig);
207
246
  console.log('✓ Obtained Infisical access token');
208
247
 
209
- const secrets = getInfisicalSecrets(infisicalConfig, token, environment === 'stage' ? 'staging' : 'prod');
248
+ const secrets = getInfisicalSecrets(infisicalConfig, token, 'prod');
210
249
  console.log('✓ Retrieved database credentials from Infisical');
211
250
 
212
251
  const { userKey, passwordKey, database } = serviceConfig as any;
213
- const dbHost = secrets.DATABASE_HOST;
252
+ const dbHost = RDS_HOSTS.prod;
214
253
  const dbUser = secrets[userKey];
215
254
  const dbPassword = secrets[passwordKey];
216
255
 
217
- const localPort = environment === 'stage' ? 15432 : 15433;
218
- const ec2Host = EC2_HOSTS[environment as 'stage' | 'prod'];
256
+ if (!dbUser || !dbPassword) {
257
+ throw new Error(`Database credentials not found in Infisical for ${service}. Keys: ${userKey}, ${passwordKey}`);
258
+ }
259
+
260
+ const localPort = 15433;
219
261
 
220
- setupSSHTunnel(ec2Host, dbHost, localPort);
262
+ setupSSHTunnel(EC2_HOST, dbHost, localPort);
221
263
 
222
264
  // 等待隧道建立
223
265
  await new Promise(resolve => setTimeout(resolve, 1000));
@@ -39,29 +39,37 @@ const fs = __importStar(require("fs"));
39
39
  const SERVICE_DB_MAP = {
40
40
  'commerce-backend': {
41
41
  ci: { container: 'commerce-postgres', user: 'commerce', password: 'commerce123', database: 'commerce' },
42
- stage: { userKey: 'COMMERCE_DB_USER', passwordKey: 'COMMERCE_DB_PASSWORD', database: 'optima_stage_commerce' },
42
+ stage: { userKey: 'COMMERCE_DB_USER', passwordKey: 'COMMERCE_DB_PASSWORD', database: 'optima_commerce' },
43
43
  prod: { userKey: 'COMMERCE_DB_USER', passwordKey: 'COMMERCE_DB_PASSWORD', database: 'optima_commerce' }
44
44
  },
45
45
  'user-auth': {
46
46
  ci: { container: 'user-auth-postgres-1', user: 'userauth', password: 'password123', database: 'userauth' },
47
- stage: { userKey: 'AUTH_DB_USER', passwordKey: 'AUTH_DB_PASSWORD', database: 'optima_stage_auth' },
47
+ stage: { userKey: 'AUTH_DB_USER', passwordKey: 'AUTH_DB_PASSWORD', database: 'optima_auth' },
48
48
  prod: { userKey: 'AUTH_DB_USER', passwordKey: 'AUTH_DB_PASSWORD', database: 'optima_auth' }
49
49
  },
50
- 'mcp-host': {
51
- ci: { container: 'mcp-host-db-1', user: 'mcp_user', password: 'mcp_password', database: 'mcp_host' },
52
- stage: { userKey: 'MCP_DB_USER', passwordKey: 'MCP_DB_PASSWORD', database: 'optima_stage_mcp' },
53
- prod: { userKey: 'MCP_DB_USER', passwordKey: 'MCP_DB_PASSWORD', database: 'optima_mcp' }
54
- },
55
50
  'agentic-chat': {
56
51
  ci: { container: 'optima-postgres', user: 'postgres', password: 'postgres123', database: 'optima_chat' },
57
- stage: { userKey: 'CHAT_DB_USER', passwordKey: 'CHAT_DB_PASSWORD', database: 'optima_stage_chat' },
52
+ stage: { userKey: 'CHAT_DB_USER', passwordKey: 'CHAT_DB_PASSWORD', database: 'optima_chat' },
58
53
  prod: { userKey: 'CHAT_DB_USER', passwordKey: 'CHAT_DB_PASSWORD', database: 'optima_chat' }
54
+ },
55
+ 'bi-backend': {
56
+ ci: null, // CI 环境暂无 BI 数据库
57
+ stage: { userKey: 'BI_DB_USER', passwordKey: 'BI_DB_PASSWORD', database: 'optima_bi' },
58
+ prod: { userKey: 'BI_DB_USER', passwordKey: 'BI_DB_PASSWORD', database: 'optima_bi' }
59
+ },
60
+ 'session-gateway': {
61
+ ci: null, // CI 环境暂无 session-gateway 数据库
62
+ stage: { userKey: 'SHELL_DB_USER', passwordKey: 'SHELL_DB_PASSWORD', database: 'optima_shell' },
63
+ prod: { userKey: 'AI_SHELL_DB_USER', passwordKey: 'AI_SHELL_DB_PASSWORD', database: 'optima_ai_shell' }
59
64
  }
60
65
  };
61
- const EC2_HOSTS = {
62
- stage: '54.179.132.102',
63
- prod: '18.136.25.239'
66
+ // Stage Prod 独立的 RDS 实例
67
+ const RDS_HOSTS = {
68
+ stage: 'optima-stage-postgres.ctg866o0ehac.ap-southeast-1.rds.amazonaws.com',
69
+ prod: 'optima-prod-postgres.ctg866o0ehac.ap-southeast-1.rds.amazonaws.com'
64
70
  };
71
+ // 统一使用 Shared EC2 作为跳板机
72
+ const EC2_HOST = '13.251.46.219';
65
73
  function getGitHubVariable(name) {
66
74
  return (0, child_process_1.execSync)(`gh variable get ${name} -R Optima-Chat/optima-dev-skills`, { encoding: 'utf-8' }).trim();
67
75
  }
@@ -157,7 +165,7 @@ async function main() {
157
165
  if (args.length < 2) {
158
166
  console.error('Usage: query-db.ts <service> <sql> [environment]');
159
167
  console.error('');
160
- console.error('Services: commerce-backend, user-auth, mcp-host, agentic-chat');
168
+ console.error('Services: commerce-backend, user-auth, agentic-chat, bi-backend, session-gateway');
161
169
  console.error('Environments: ci (default), stage, prod');
162
170
  console.error('');
163
171
  console.error('Example: query-db.ts user-auth "SELECT COUNT(*) FROM users" prod');
@@ -170,6 +178,13 @@ async function main() {
170
178
  process.exit(1);
171
179
  }
172
180
  const serviceConfig = SERVICE_DB_MAP[service][environment];
181
+ if (!serviceConfig) {
182
+ console.error(`Service ${service} is not available in ${environment.toUpperCase()} environment.`);
183
+ if (environment === 'ci') {
184
+ console.error('Try using stage or prod environment instead.');
185
+ }
186
+ process.exit(1);
187
+ }
173
188
  console.log(`\n🔍 Querying ${service} (${environment.toUpperCase()})...`);
174
189
  if (environment === 'ci') {
175
190
  // CI 环境:通过 SSH + Docker Exec
@@ -180,21 +195,41 @@ async function main() {
180
195
  const result = (0, child_process_1.execSync)(`sshpass -p "${ciPassword}" ssh -o StrictHostKeyChecking=no ${ciUser}@${ciHost} "docker exec ${container} psql -U ${user} -d ${database} -c \\"${sql}\\""`, { encoding: 'utf-8' });
181
196
  console.log('\n' + result);
182
197
  }
198
+ else if (environment === 'stage') {
199
+ // Stage 环境:直连 RDS(Stage RDS 在公有子网,可以本地直连)
200
+ const infisicalConfig = getInfisicalConfig();
201
+ console.log('✓ Loaded Infisical config from GitHub Variables');
202
+ const token = getInfisicalToken(infisicalConfig);
203
+ console.log('✓ Obtained Infisical access token');
204
+ const secrets = getInfisicalSecrets(infisicalConfig, token, 'staging');
205
+ console.log('✓ Retrieved database credentials from Infisical');
206
+ const { userKey, passwordKey, database } = serviceConfig;
207
+ const dbHost = RDS_HOSTS.stage;
208
+ const dbUser = secrets[userKey];
209
+ const dbPassword = secrets[passwordKey];
210
+ if (!dbUser || !dbPassword) {
211
+ throw new Error(`Database credentials not found in Infisical for ${service}. Keys: ${userKey}, ${passwordKey}`);
212
+ }
213
+ const result = queryDatabase(dbHost, 5432, dbUser, dbPassword, database, sql);
214
+ console.log('\n' + result);
215
+ }
183
216
  else {
184
- // Stage/Prod 环境:通过 SSH 隧道访问 RDS
217
+ // Prod 环境:通过 SSH 隧道访问 RDS(Prod RDS 在私有子网)
185
218
  const infisicalConfig = getInfisicalConfig();
186
219
  console.log('✓ Loaded Infisical config from GitHub Variables');
187
220
  const token = getInfisicalToken(infisicalConfig);
188
221
  console.log('✓ Obtained Infisical access token');
189
- const secrets = getInfisicalSecrets(infisicalConfig, token, environment === 'stage' ? 'staging' : 'prod');
222
+ const secrets = getInfisicalSecrets(infisicalConfig, token, 'prod');
190
223
  console.log('✓ Retrieved database credentials from Infisical');
191
224
  const { userKey, passwordKey, database } = serviceConfig;
192
- const dbHost = secrets.DATABASE_HOST;
225
+ const dbHost = RDS_HOSTS.prod;
193
226
  const dbUser = secrets[userKey];
194
227
  const dbPassword = secrets[passwordKey];
195
- const localPort = environment === 'stage' ? 15432 : 15433;
196
- const ec2Host = EC2_HOSTS[environment];
197
- setupSSHTunnel(ec2Host, dbHost, localPort);
228
+ if (!dbUser || !dbPassword) {
229
+ throw new Error(`Database credentials not found in Infisical for ${service}. Keys: ${userKey}, ${passwordKey}`);
230
+ }
231
+ const localPort = 15433;
232
+ setupSSHTunnel(EC2_HOST, dbHost, localPort);
198
233
  // 等待隧道建立
199
234
  await new Promise(resolve => setTimeout(resolve, 1000));
200
235
  const result = queryDatabase('localhost', localPort, dbUser, dbPassword, database, sql);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/dev-skills",
3
- "version": "0.7.8",
3
+ "version": "0.7.10",
4
4
  "description": "Claude Code Skills for Optima development team - cross-environment collaboration tools",
5
5
  "main": "index.js",
6
6
  "bin": {