@optima-chat/bi-cli 0.2.0 → 0.3.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.
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA8BpC,wBAAgB,iBAAiB,IAAI,OAAO,CAsP3C"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuCpC,wBAAgB,iBAAiB,IAAI,OAAO,CAgP3C"}
@@ -2,7 +2,7 @@ import { Command } from 'commander';
2
2
  import axios from 'axios';
3
3
  import ora from 'ora';
4
4
  import chalk from 'chalk';
5
- import { setConfig, clearAuth, getConfig } from '../config/index.js';
5
+ import { clearAuth, getConfig, saveTokens, saveUser, getConfigPath, ENV_CONFIG, } from '../config/index.js';
6
6
  import { success, error, info } from '../utils/output.js';
7
7
  export function createAuthCommand() {
8
8
  const auth = new Command('auth').description('Authentication commands');
@@ -12,38 +12,26 @@ export function createAuthCommand() {
12
12
  .description('Login with OAuth 2.0 Device Flow')
13
13
  .option('--env <environment>', 'Environment (production|stage|development)', 'production')
14
14
  .action(async (options) => {
15
- const { env } = options;
16
- // Set URLs based on environment
17
- const authUrls = {
18
- production: 'https://auth.optima.chat',
19
- stage: 'https://auth-stage.optima.chat',
20
- development: 'http://localhost:4000',
21
- };
22
- const backendUrls = {
23
- production: 'https://bi-api.optima.chat',
24
- stage: 'https://bi-api-stage.optima.chat',
25
- development: 'http://localhost:3001',
26
- };
27
- const authUrl = authUrls[env];
28
- const backendUrl = backendUrls[env];
29
- if (!authUrl || !backendUrl) {
15
+ const env = options.env;
16
+ // Validate environment
17
+ if (!['production', 'stage', 'development'].includes(env)) {
30
18
  error(`Invalid environment: ${env}`);
31
19
  process.exit(1);
32
20
  }
33
- setConfig('environment', env);
34
- setConfig('authUrl', authUrl);
35
- setConfig('backendUrl', backendUrl);
21
+ const envConfig = ENV_CONFIG[env];
22
+ const { authUrl, clientId } = envConfig;
36
23
  info(`Logging in to ${env} environment...`);
24
+ info(`Auth URL: ${authUrl}`);
37
25
  try {
38
26
  // Step 1: Request device code
39
27
  const spinner = ora('Requesting device code...').start();
40
- const deviceCodeRes = await axios.post(`${authUrl}/api/v1/oauth/device/authorize`, { client_id: 'bi-cli-aqkutatj' });
28
+ const deviceCodeRes = await axios.post(`${authUrl}/api/v1/oauth/device/authorize`, { client_id: clientId });
41
29
  spinner.succeed('Device code received');
42
30
  const { device_code, user_code, verification_uri, verification_uri_complete, expires_in, interval, } = deviceCodeRes.data;
43
31
  // Use verification_uri_complete if available (includes code pre-filled)
44
32
  const browserUrl = verification_uri_complete || verification_uri;
45
33
  // Step 2: Display authorization instructions
46
- console.log(chalk.bold('\n📋 Authorization Required:\n'));
34
+ console.log(chalk.bold('\n Authorization Required:\n'));
47
35
  if (verification_uri_complete) {
48
36
  console.log(` Opening browser with pre-filled code: ${chalk.yellow.bold(user_code)}`);
49
37
  console.log(` URL: ${chalk.cyan(verification_uri_complete)}\n`);
@@ -68,7 +56,7 @@ export function createAuthCommand() {
68
56
  try {
69
57
  const tokenRes = await axios.post(`${authUrl}/api/v1/oauth/device/token`, new URLSearchParams({
70
58
  grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
71
- client_id: 'bi-cli-aqkutatj',
59
+ client_id: clientId,
72
60
  device_code,
73
61
  }), {
74
62
  headers: {
@@ -97,21 +85,18 @@ export function createAuthCommand() {
97
85
  break;
98
86
  }
99
87
  catch (err) {
100
- const error = err;
101
- const errorCode = error.response?.data?.error;
88
+ const axiosErr = err;
89
+ const errorCode = axiosErr.response?.data?.error;
102
90
  if (errorCode === 'authorization_pending') {
103
- // Continue polling
104
91
  pollSpinner.text = `Waiting for authorization... (attempt ${pollCount})`;
105
92
  continue;
106
93
  }
107
94
  else if (errorCode === 'slow_down') {
108
- // Increase interval
109
95
  pollSpinner.text = `Slowing down polling... (attempt ${pollCount})`;
110
96
  await new Promise((resolve) => setTimeout(resolve, 5000));
111
97
  continue;
112
98
  }
113
99
  else {
114
- // Unexpected error
115
100
  pollSpinner.fail(`Polling failed: ${errorCode || 'unknown error'}`);
116
101
  throw err;
117
102
  }
@@ -123,20 +108,26 @@ export function createAuthCommand() {
123
108
  process.exit(1);
124
109
  }
125
110
  pollSpinner.succeed();
126
- // Step 5: Save tokens
127
- setConfig('accessToken', token.access_token);
128
- setConfig('refreshToken', token.refresh_token);
129
- // Step 6: Fetch user info (optional - just for display)
111
+ // Step 5: Fetch user info and save tokens
112
+ let userInfo;
130
113
  try {
131
- const userInfo = await axios.get(`${authUrl}/api/v1/users/me`, {
114
+ const userRes = await axios.get(`${authUrl}/api/v1/users/me`, {
132
115
  headers: { Authorization: `Bearer ${token.access_token}` },
133
116
  });
134
- success(`Logged in as ${chalk.bold(userInfo.data.email)} (${userInfo.data.role})`);
117
+ userInfo = userRes.data;
135
118
  }
136
- catch (userInfoErr) {
137
- // If fetching user info fails, still consider login successful
138
- success('Login successful! Token saved.');
119
+ catch {
120
+ // User info fetch failed, continue without it
139
121
  }
122
+ // Step 6: Save tokens to ~/.optima/token.json
123
+ saveTokens(token.access_token, token.refresh_token, token.expires_in, env, userInfo ? { id: userInfo.id, email: userInfo.email, name: userInfo.name } : undefined);
124
+ if (userInfo) {
125
+ success(`Logged in as ${chalk.bold(userInfo.email)} (${userInfo.role})`);
126
+ }
127
+ else {
128
+ success('Login successful!');
129
+ }
130
+ info(`Token saved to ${getConfigPath()}`);
140
131
  }
141
132
  catch (err) {
142
133
  const errorMsg = err instanceof Error ? err.message : 'Unknown error';
@@ -147,10 +138,11 @@ export function createAuthCommand() {
147
138
  // auth logout
148
139
  auth
149
140
  .command('logout')
150
- .description('Logout and clear stored credentials')
141
+ .description('Logout and delete ~/.optima/token.json')
151
142
  .action(() => {
152
143
  clearAuth();
153
144
  success('Logged out successfully');
145
+ info(`Deleted ${getConfigPath()}`);
154
146
  });
155
147
  // auth whoami
156
148
  auth
@@ -166,13 +158,20 @@ export function createAuthCommand() {
166
158
  const userInfo = await axios.get(`${cfg.authUrl}/api/v1/users/me`, {
167
159
  headers: { Authorization: `Bearer ${cfg.accessToken}` },
168
160
  });
169
- console.log(chalk.bold('\n👤 Current User:\n'));
161
+ // Update user info in token.json
162
+ saveUser({
163
+ id: userInfo.data.id,
164
+ email: userInfo.data.email,
165
+ name: userInfo.data.name,
166
+ });
167
+ console.log(chalk.bold('\n Current User:\n'));
170
168
  console.log(` Email: ${chalk.cyan(userInfo.data.email)}`);
171
169
  console.log(` Role: ${chalk.yellow(userInfo.data.role)}`);
172
170
  if (userInfo.data.merchant_id) {
173
171
  console.log(` Merchant ID: ${chalk.gray(userInfo.data.merchant_id)}`);
174
172
  }
175
- console.log(` Environment: ${chalk.green(cfg.environment)}\n`);
173
+ console.log(` Environment: ${chalk.green(cfg.environment)}`);
174
+ console.log(` Config: ${chalk.gray(getConfigPath())}\n`);
176
175
  }
177
176
  catch (err) {
178
177
  const axiosError = err;
@@ -186,28 +185,21 @@ export function createAuthCommand() {
186
185
  process.exit(1);
187
186
  }
188
187
  });
189
- // auth switch
188
+ // auth status
190
189
  auth
191
- .command('switch')
192
- .description('Switch environment')
193
- .option('--env <environment>', 'Environment (production|stage|development)', 'production')
194
- .action((options) => {
195
- const { env } = options;
196
- const backendUrls = {
197
- production: 'https://bi-api.optima.chat',
198
- stage: 'https://bi-api-stage.optima.chat',
199
- development: 'http://localhost:3001',
200
- };
201
- const backendUrl = backendUrls[env];
202
- if (!backendUrl) {
203
- error(`Invalid environment: ${env}`);
204
- process.exit(1);
190
+ .command('status')
191
+ .description('Show authentication status')
192
+ .action(() => {
193
+ const cfg = getConfig();
194
+ console.log(chalk.bold('\n Authentication Status:\n'));
195
+ console.log(` Environment: ${chalk.green(cfg.environment)}`);
196
+ console.log(` Auth URL: ${chalk.cyan(cfg.authUrl)}`);
197
+ console.log(` Backend URL: ${chalk.cyan(cfg.backendUrl)}`);
198
+ console.log(` Config file: ${chalk.gray(getConfigPath())}`);
199
+ console.log(` Authenticated: ${cfg.accessToken ? chalk.green('Yes') : chalk.red('No')}\n`);
200
+ if (!cfg.accessToken) {
201
+ info('Run "bi-cli auth login" to authenticate');
205
202
  }
206
- setConfig('environment', env);
207
- setConfig('backendUrl', backendUrl);
208
- clearAuth(); // Clear tokens when switching environment
209
- success(`Switched to ${env} environment`);
210
- info('Please login again: bi-cli auth login');
211
203
  });
212
204
  return auth;
213
205
  }
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAyB1D,MAAM,UAAU,iBAAiB;IAC/B,MAAM,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC;IAExE,aAAa;IACb,IAAI;SACD,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,kCAAkC,CAAC;SAC/C,MAAM,CAAC,qBAAqB,EAAE,4CAA4C,EAAE,YAAY,CAAC;SACzF,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACxB,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;QAExB,gCAAgC;QAChC,MAAM,QAAQ,GAAG;YACf,UAAU,EAAE,0BAA0B;YACtC,KAAK,EAAE,gCAAgC;YACvC,WAAW,EAAE,uBAAuB;SACrC,CAAC;QAEF,MAAM,WAAW,GAAG;YAClB,UAAU,EAAE,4BAA4B;YACxC,KAAK,EAAE,kCAAkC;YACzC,WAAW,EAAE,uBAAuB;SACrC,CAAC;QAEF,MAAM,OAAO,GAAG,QAAQ,CAAC,GAA4B,CAAC,CAAC;QACvD,MAAM,UAAU,GAAG,WAAW,CAAC,GAA+B,CAAC,CAAC;QAEhE,IAAI,CAAC,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC;YAC5B,KAAK,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,SAAS,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAC9B,SAAS,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC9B,SAAS,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QAEpC,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,CAAC;QAE5C,IAAI,CAAC;YACH,8BAA8B;YAC9B,MAAM,OAAO,GAAG,GAAG,CAAC,2BAA2B,CAAC,CAAC,KAAK,EAAE,CAAC;YACzD,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,IAAI,CACpC,GAAG,OAAO,gCAAgC,EAC1C,EAAE,SAAS,EAAE,iBAAiB,EAAE,CACjC,CAAC;YACF,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;YAExC,MAAM,EACJ,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,yBAAyB,EACzB,UAAU,EACV,QAAQ,GACT,GAAG,aAAa,CAAC,IAAI,CAAC;YAEvB,wEAAwE;YACxE,MAAM,UAAU,GAAG,yBAAyB,IAAI,gBAAgB,CAAC;YAEjE,6CAA6C;YAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gCAAgC,CAAC,CAAC,CAAC;YAC1D,IAAI,yBAAyB,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,2CAA2C,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;gBACvF,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC;YACnE,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;gBAC3D,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACpE,CAAC;YAED,qCAAqC;YACrC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;YAC/C,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC;YACvB,IAAI,CAAC,8BAA8B,CAAC,CAAC;YAErC,yBAAyB;YACzB,MAAM,WAAW,GAAG,GAAG,CAAC,8BAA8B,CAAC,CAAC,KAAK,EAAE,CAAC;YAChE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,MAAM,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,IAAI,CAAC;YAEhD,IAAI,KAAK,GAAyB,IAAI,CAAC;YACvC,IAAI,SAAS,GAAG,CAAC,CAAC;YAElB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;gBAC9B,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC;gBACrE,SAAS,EAAE,CAAC;gBAEZ,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAG/B,GAAG,OAAO,4BAA4B,EACtC,IAAI,eAAe,CAAC;wBAClB,UAAU,EAAE,8CAA8C;wBAC1D,SAAS,EAAE,iBAAiB;wBAC5B,WAAW;qBACZ,CAAC,EACF;wBACE,OAAO,EAAE;4BACP,cAAc,EAAE,mCAAmC;yBACpD;qBACF,CACF,CAAC;oBAEF,kFAAkF;oBAClF,IAAI,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;wBAC7B,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;wBACtC,IAAI,SAAS,KAAK,uBAAuB,EAAE,CAAC;4BAC1C,WAAW,CAAC,IAAI,GAAG,yCAAyC,SAAS,GAAG,CAAC;4BACzE,SAAS;wBACX,CAAC;6BAAM,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;4BACrC,WAAW,CAAC,IAAI,GAAG,oCAAoC,SAAS,GAAG,CAAC;4BACpE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;4BAC1D,SAAS;wBACX,CAAC;6BAAM,CAAC;4BACN,WAAW,CAAC,IAAI,CAAC,mBAAmB,SAAS,EAAE,CAAC,CAAC;4BACjD,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;wBACnD,CAAC;oBACH,CAAC;oBAED,KAAK,GAAG,QAAQ,CAAC,IAAqB,CAAC;oBACvC,WAAW,CAAC,IAAI,GAAG,kCAAkC,SAAS,WAAW,CAAC;oBAC1E,MAAM;gBACR,CAAC;gBAAC,OAAO,GAAY,EAAE,CAAC;oBACtB,MAAM,KAAK,GAAG,GAAmD,CAAC;oBAClE,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC;oBAE9C,IAAI,SAAS,KAAK,uBAAuB,EAAE,CAAC;wBAC1C,mBAAmB;wBACnB,WAAW,CAAC,IAAI,GAAG,yCAAyC,SAAS,GAAG,CAAC;wBACzE,SAAS;oBACX,CAAC;yBAAM,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;wBACrC,oBAAoB;wBACpB,WAAW,CAAC,IAAI,GAAG,oCAAoC,SAAS,GAAG,CAAC;wBACpE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;wBAC1D,SAAS;oBACX,CAAC;yBAAM,CAAC;wBACN,mBAAmB;wBACnB,WAAW,CAAC,IAAI,CAAC,mBAAmB,SAAS,IAAI,eAAe,EAAE,CAAC,CAAC;wBACpE,MAAM,GAAG,CAAC;oBACZ,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,WAAW,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;gBAC1C,KAAK,CAAC,kBAAkB,CAAC,CAAC;gBAC1B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,WAAW,CAAC,OAAO,EAAE,CAAC;YAEtB,sBAAsB;YACtB,SAAS,CAAC,aAAa,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;YAC7C,SAAS,CAAC,cAAc,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;YAE/C,wDAAwD;YACxD,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAW,GAAG,OAAO,kBAAkB,EAAE;oBACvE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,CAAC,YAAY,EAAE,EAAE;iBAC3D,CAAC,CAAC;gBACH,OAAO,CAAC,gBAAgB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;YACrF,CAAC;YAAC,OAAO,WAAW,EAAE,CAAC;gBACrB,+DAA+D;gBAC/D,OAAO,CAAC,gCAAgC,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACtE,KAAK,CAAC,iBAAiB,QAAQ,EAAE,CAAC,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,cAAc;IACd,IAAI;SACD,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,qCAAqC,CAAC;SAClD,MAAM,CAAC,GAAG,EAAE;QACX,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEL,cAAc;IACd,IAAI;SACD,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,+BAA+B,CAAC;SAC5C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;QAExB,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YACrB,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAW,GAAG,GAAG,CAAC,OAAO,kBAAkB,EAAE;gBAC3E,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,GAAG,CAAC,WAAW,EAAE,EAAE;aACxD,CAAC,CAAC;YAEH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC;YAChD,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC3D,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC3D,IAAI,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YACzE,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAClE,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,UAAU,GAAG,GAAyC,CAAC;YAC7D,IAAI,UAAU,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;gBACxC,KAAK,CAAC,sDAAsD,CAAC,CAAC;YAChE,CAAC;iBAAM,CAAC;gBACN,MAAM,QAAQ,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;gBACtE,KAAK,CAAC,8BAA8B,QAAQ,EAAE,CAAC,CAAC;YAClD,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,cAAc;IACd,IAAI;SACD,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,oBAAoB,CAAC;SACjC,MAAM,CAAC,qBAAqB,EAAE,4CAA4C,EAAE,YAAY,CAAC;SACzF,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;QAClB,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;QAExB,MAAM,WAAW,GAAG;YAClB,UAAU,EAAE,4BAA4B;YACxC,KAAK,EAAE,kCAAkC;YACzC,WAAW,EAAE,uBAAuB;SACrC,CAAC;QAEF,MAAM,UAAU,GAAG,WAAW,CAAC,GAA+B,CAAC,CAAC;QAChE,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,KAAK,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,SAAS,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;QAC9B,SAAS,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;QACpC,SAAS,EAAE,CAAC,CAAC,0CAA0C;QAEvD,OAAO,CAAC,eAAe,GAAG,cAAc,CAAC,CAAC;QAC1C,IAAI,CAAC,uCAAuC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEL,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EACL,SAAS,EACT,SAAS,EACT,UAAU,EACV,QAAQ,EACR,aAAa,EACb,UAAU,GAEX,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AA0B1D,MAAM,UAAU,iBAAiB;IAC/B,MAAM,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,yBAAyB,CAAC,CAAC;IAExE,aAAa;IACb,IAAI;SACD,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,kCAAkC,CAAC;SAC/C,MAAM,CAAC,qBAAqB,EAAE,4CAA4C,EAAE,YAAY,CAAC;SACzF,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;QACxB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAkB,CAAC;QAEvC,uBAAuB;QACvB,IAAI,CAAC,CAAC,YAAY,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1D,KAAK,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;YACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,SAAS,CAAC;QAExC,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC,CAAC;QAC5C,IAAI,CAAC,aAAa,OAAO,EAAE,CAAC,CAAC;QAE7B,IAAI,CAAC;YACH,8BAA8B;YAC9B,MAAM,OAAO,GAAG,GAAG,CAAC,2BAA2B,CAAC,CAAC,KAAK,EAAE,CAAC;YACzD,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,IAAI,CACpC,GAAG,OAAO,gCAAgC,EAC1C,EAAE,SAAS,EAAE,QAAQ,EAAE,CACxB,CAAC;YACF,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;YAExC,MAAM,EACJ,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,yBAAyB,EACzB,UAAU,EACV,QAAQ,GACT,GAAG,aAAa,CAAC,IAAI,CAAC;YAEvB,wEAAwE;YACxE,MAAM,UAAU,GAAG,yBAAyB,IAAI,gBAAgB,CAAC;YAEjE,6CAA6C;YAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC,CAAC;YACxD,IAAI,yBAAyB,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,2CAA2C,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;gBACvF,OAAO,CAAC,GAAG,CAAC,UAAU,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,IAAI,CAAC,CAAC;YACnE,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;gBAC3D,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACpE,CAAC;YAED,qCAAqC;YACrC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;YAC/C,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC;YACvB,IAAI,CAAC,8BAA8B,CAAC,CAAC;YAErC,yBAAyB;YACzB,MAAM,WAAW,GAAG,GAAG,CAAC,8BAA8B,CAAC,CAAC,KAAK,EAAE,CAAC;YAChE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC7B,MAAM,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,IAAI,CAAC;YAEhD,IAAI,KAAK,GAAyB,IAAI,CAAC;YACvC,IAAI,SAAS,GAAG,CAAC,CAAC;YAElB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;gBAC9B,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC;gBACrE,SAAS,EAAE,CAAC;gBAEZ,IAAI,CAAC;oBACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAG/B,GAAG,OAAO,4BAA4B,EACtC,IAAI,eAAe,CAAC;wBAClB,UAAU,EAAE,8CAA8C;wBAC1D,SAAS,EAAE,QAAQ;wBACnB,WAAW;qBACZ,CAAC,EACF;wBACE,OAAO,EAAE;4BACP,cAAc,EAAE,mCAAmC;yBACpD;qBACF,CACF,CAAC;oBAEF,kFAAkF;oBAClF,IAAI,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;wBAC7B,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;wBACtC,IAAI,SAAS,KAAK,uBAAuB,EAAE,CAAC;4BAC1C,WAAW,CAAC,IAAI,GAAG,yCAAyC,SAAS,GAAG,CAAC;4BACzE,SAAS;wBACX,CAAC;6BAAM,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;4BACrC,WAAW,CAAC,IAAI,GAAG,oCAAoC,SAAS,GAAG,CAAC;4BACpE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;4BAC1D,SAAS;wBACX,CAAC;6BAAM,CAAC;4BACN,WAAW,CAAC,IAAI,CAAC,mBAAmB,SAAS,EAAE,CAAC,CAAC;4BACjD,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;wBACnD,CAAC;oBACH,CAAC;oBAED,KAAK,GAAG,QAAQ,CAAC,IAAqB,CAAC;oBACvC,WAAW,CAAC,IAAI,GAAG,kCAAkC,SAAS,WAAW,CAAC;oBAC1E,MAAM;gBACR,CAAC;gBAAC,OAAO,GAAY,EAAE,CAAC;oBACtB,MAAM,QAAQ,GAAG,GAAmD,CAAC;oBACrE,MAAM,SAAS,GAAG,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC;oBAEjD,IAAI,SAAS,KAAK,uBAAuB,EAAE,CAAC;wBAC1C,WAAW,CAAC,IAAI,GAAG,yCAAyC,SAAS,GAAG,CAAC;wBACzE,SAAS;oBACX,CAAC;yBAAM,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;wBACrC,WAAW,CAAC,IAAI,GAAG,oCAAoC,SAAS,GAAG,CAAC;wBACpE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;wBAC1D,SAAS;oBACX,CAAC;yBAAM,CAAC;wBACN,WAAW,CAAC,IAAI,CAAC,mBAAmB,SAAS,IAAI,eAAe,EAAE,CAAC,CAAC;wBACpE,MAAM,GAAG,CAAC;oBACZ,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,WAAW,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;gBAC1C,KAAK,CAAC,kBAAkB,CAAC,CAAC;gBAC1B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YAED,WAAW,CAAC,OAAO,EAAE,CAAC;YAEtB,0CAA0C;YAC1C,IAAI,QAA8B,CAAC;YACnC,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,GAAG,CAAW,GAAG,OAAO,kBAAkB,EAAE;oBACtE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,CAAC,YAAY,EAAE,EAAE;iBAC3D,CAAC,CAAC;gBACH,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;YAC1B,CAAC;YAAC,MAAM,CAAC;gBACP,8CAA8C;YAChD,CAAC;YAED,8CAA8C;YAC9C,UAAU,CACR,KAAK,CAAC,YAAY,EAClB,KAAK,CAAC,aAAa,EACnB,KAAK,CAAC,UAAU,EAChB,GAAG,EACH,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CACvF,CAAC;YAEF,IAAI,QAAQ,EAAE,CAAC;gBACb,OAAO,CAAC,gBAAgB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,IAAI,GAAG,CAAC,CAAC;YAC3E,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,mBAAmB,CAAC,CAAC;YAC/B,CAAC;YACD,IAAI,CAAC,kBAAkB,aAAa,EAAE,EAAE,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACtE,KAAK,CAAC,iBAAiB,QAAQ,EAAE,CAAC,CAAC;YACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,cAAc;IACd,IAAI;SACD,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,wCAAwC,CAAC;SACrD,MAAM,CAAC,GAAG,EAAE;QACX,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,yBAAyB,CAAC,CAAC;QACnC,IAAI,CAAC,WAAW,aAAa,EAAE,EAAE,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEL,cAAc;IACd,IAAI;SACD,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,+BAA+B,CAAC;SAC5C,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;QAExB,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YACrB,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAW,GAAG,GAAG,CAAC,OAAO,kBAAkB,EAAE;gBAC3E,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,GAAG,CAAC,WAAW,EAAE,EAAE;aACxD,CAAC,CAAC;YAEH,iCAAiC;YACjC,QAAQ,CAAC;gBACP,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE;gBACpB,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK;gBAC1B,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI;aACzB,CAAC,CAAC;YAEH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAC9C,OAAO,CAAC,GAAG,CAAC,YAAY,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC3D,OAAO,CAAC,GAAG,CAAC,WAAW,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC3D,IAAI,QAAQ,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBAC9B,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YACzE,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAC9D,OAAO,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC,CAAC;QAC5D,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,UAAU,GAAG,GAAyC,CAAC;YAC7D,IAAI,UAAU,CAAC,QAAQ,EAAE,MAAM,KAAK,GAAG,EAAE,CAAC;gBACxC,KAAK,CAAC,sDAAsD,CAAC,CAAC;YAChE,CAAC;iBAAM,CAAC;gBACN,MAAM,QAAQ,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;gBACtE,KAAK,CAAC,8BAA8B,QAAQ,EAAE,CAAC,CAAC;YAClD,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,cAAc;IACd,IAAI;SACD,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,4BAA4B,CAAC;SACzC,MAAM,CAAC,GAAG,EAAE;QACX,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;QAExB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7D,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE5F,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YACrB,IAAI,CAAC,yCAAyC,CAAC,CAAC;QAClD,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -1,21 +1,89 @@
1
- import Conf from 'conf';
1
+ export type Environment = 'production' | 'stage' | 'development';
2
+ interface UserData {
3
+ id: string;
4
+ email: string;
5
+ name?: string;
6
+ }
7
+ interface EnvironmentConfig {
8
+ authUrl: string;
9
+ backendUrl: string;
10
+ clientId: string;
11
+ }
12
+ export declare const ENV_CONFIG: Record<Environment, EnvironmentConfig>;
13
+ /**
14
+ * 获取当前环境
15
+ * 优先级:BI_CLI_ENV 环境变量 > token.json 的 env 字段 > 默认 production
16
+ */
17
+ export declare function getCurrentEnvironment(): Environment;
18
+ /**
19
+ * 获取当前环境的配置信息
20
+ */
21
+ export declare function getCurrentEnvConfig(): EnvironmentConfig;
22
+ /**
23
+ * 保存认证令牌到 ~/.optima/token.json
24
+ */
25
+ export declare function saveTokens(access_token: string, refresh_token: string, expires_in: number, env: Environment, user?: UserData): void;
26
+ /**
27
+ * 获取访问令牌
28
+ * 优先级:BI_CLI_TOKEN > OPTIMA_TOKEN > ~/.optima/token.json
29
+ */
30
+ export declare function getAccessToken(): string | null;
31
+ /**
32
+ * 获取 refresh token
33
+ */
34
+ export declare function getRefreshToken(): string | null;
35
+ /**
36
+ * 获取 token 过期时间
37
+ */
38
+ export declare function getTokenExpiresAt(): number | null;
39
+ /**
40
+ * 检查 token 是否过期
41
+ */
42
+ export declare function isTokenExpired(): boolean;
43
+ /**
44
+ * 检查是否已认证
45
+ */
46
+ export declare function isAuthenticated(): boolean;
47
+ /**
48
+ * 保存用户信息到 token.json
49
+ */
50
+ export declare function saveUser(user: UserData): void;
51
+ /**
52
+ * 获取当前用户信息
53
+ */
54
+ export declare function getUser(): UserData | null;
55
+ /**
56
+ * 清除配置(登出)- 删除 token.json
57
+ */
58
+ export declare function clearAuth(): void;
59
+ /**
60
+ * 获取配置文件路径
61
+ */
62
+ export declare function getConfigPath(): string;
63
+ /**
64
+ * 获取 BI API URL
65
+ * 优先级:BI_CLI_BACKEND_URL 环境变量 > 当前环境配置
66
+ */
67
+ export declare function getBackendUrl(): string;
68
+ /**
69
+ * 获取 Auth API URL
70
+ * 优先级:BI_CLI_AUTH_URL 环境变量 > 当前环境配置
71
+ */
72
+ export declare function getAuthUrl(): string;
2
73
  export interface CliConfig {
3
- environment: 'production' | 'stage' | 'development';
74
+ environment: Environment;
4
75
  authUrl: string;
5
76
  backendUrl: string;
6
77
  accessToken?: string;
7
78
  refreshToken?: string;
8
79
  }
9
- export declare const config: Conf<CliConfig>;
10
80
  /**
11
- * Get CLI configuration.
12
- *
13
- * Supports environment variables for CI/development:
14
- * - BI_CLI_TOKEN: Access token (overrides stored token)
15
- * - BI_CLI_BACKEND_URL: Backend URL (overrides stored URL)
16
- * - BI_CLI_AUTH_URL: Auth URL (overrides stored URL)
81
+ * Get CLI configuration (兼容旧接口)
17
82
  */
18
83
  export declare function getConfig(): CliConfig;
19
- export declare function setConfig(key: keyof CliConfig, value: any): void;
20
- export declare function clearAuth(): void;
84
+ /**
85
+ * Set config (兼容旧接口 - 现在只支持保存 token)
86
+ */
87
+ export declare function setConfig(key: keyof CliConfig, value: string): void;
88
+ export {};
21
89
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,YAAY,GAAG,OAAO,GAAG,aAAa,CAAC;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,MAAM,iBAQjB,CAAC;AAEH;;;;;;;GAOG;AACH,wBAAgB,SAAS,IAAI,SAAS,CAQrC;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,SAAS,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI,CAMhE;AAED,wBAAgB,SAAS,IAAI,IAAI,CAGhC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,OAAO,GAAG,aAAa,CAAC;AAKjE,UAAU,QAAQ;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAcD,UAAU,iBAAiB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,WAAW,EAAE,iBAAiB,CAgB7D,CAAC;AAmFF;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,WAAW,CAenD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,iBAAiB,CAGvD;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,WAAW,EAChB,IAAI,CAAC,EAAE,QAAQ,GACd,IAAI,CAWN;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAc9C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,GAAG,IAAI,CAG/C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAGjD;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CASxC;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAM7C;AAED;;GAEG;AACH,wBAAgB,OAAO,IAAI,QAAQ,GAAG,IAAI,CAGzC;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,IAAI,CAEhC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAKtC;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAKnC;AAID,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,SAAS,CAQrC;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAanE"}
@@ -1,39 +1,263 @@
1
- import Conf from 'conf';
2
- export const config = new Conf({
3
- projectName: 'optima-bi-cli',
4
- defaults: {
5
- environment: 'production',
1
+ import { readFileSync, existsSync, writeFileSync, mkdirSync, unlinkSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { homedir } from 'os';
4
+ // ============== 环境配置常量 ==============
5
+ export const ENV_CONFIG = {
6
+ production: {
7
+ authUrl: 'https://auth.optima.onl',
8
+ backendUrl: 'https://bi-api.optima.onl',
9
+ clientId: 'bi-cli-wl18yjdk',
10
+ },
11
+ stage: {
12
+ authUrl: 'https://auth.stage.optima.onl',
13
+ backendUrl: 'https://bi-api.stage.optima.onl',
14
+ clientId: 'bi-cli-gqqcui4k',
15
+ },
16
+ development: {
6
17
  authUrl: 'https://auth.optima.chat',
7
18
  backendUrl: 'https://bi-api.optima.chat',
19
+ clientId: 'bi-cli-aqkutatj',
8
20
  },
9
- encryptionKey: 'optima-bi-cli-secret-key-change-in-production',
10
- });
21
+ };
22
+ // ============== Token 文件路径 ==============
23
+ const OPTIMA_DIR = join(homedir(), '.optima');
24
+ const TOKEN_FILE = join(OPTIMA_DIR, 'token.json');
25
+ // ============== 环境映射 ==============
26
+ /**
27
+ * 将 token.json 的 env 字段映射到 Environment 类型
28
+ */
29
+ function tokenEnvToEnvironment(tokenEnv) {
30
+ switch (tokenEnv) {
31
+ case 'prod':
32
+ return 'production';
33
+ case 'stage':
34
+ return 'stage';
35
+ case 'ci':
36
+ return 'development';
37
+ default:
38
+ return 'production';
39
+ }
40
+ }
41
+ /**
42
+ * 将 Environment 类型映射到 token.json 的 env 字段
43
+ */
44
+ function environmentToTokenEnv(env) {
45
+ switch (env) {
46
+ case 'production':
47
+ return 'prod';
48
+ case 'stage':
49
+ return 'stage';
50
+ case 'development':
51
+ return 'ci';
52
+ default:
53
+ return 'prod';
54
+ }
55
+ }
56
+ // ============== Token 文件操作 ==============
57
+ /**
58
+ * 从 ~/.optima/token.json 读取 token 数据
59
+ */
60
+ function getOptimaToken() {
61
+ if (!existsSync(TOKEN_FILE)) {
62
+ return null;
63
+ }
64
+ try {
65
+ const content = readFileSync(TOKEN_FILE, 'utf-8');
66
+ return JSON.parse(content);
67
+ }
68
+ catch {
69
+ // 文件读取或解析失败
70
+ return null;
71
+ }
72
+ }
73
+ /**
74
+ * 保存 token 到 ~/.optima/token.json
75
+ */
76
+ function saveOptimaToken(token) {
77
+ mkdirSync(OPTIMA_DIR, { recursive: true });
78
+ writeFileSync(TOKEN_FILE, JSON.stringify(token, null, 2), 'utf-8');
79
+ }
80
+ /**
81
+ * 删除 ~/.optima/token.json
82
+ */
83
+ function deleteOptimaToken() {
84
+ try {
85
+ if (existsSync(TOKEN_FILE)) {
86
+ unlinkSync(TOKEN_FILE);
87
+ }
88
+ }
89
+ catch {
90
+ // 忽略删除失败
91
+ }
92
+ }
93
+ // ============== 公开 API ==============
94
+ /**
95
+ * 获取当前环境
96
+ * 优先级:BI_CLI_ENV 环境变量 > token.json 的 env 字段 > 默认 production
97
+ */
98
+ export function getCurrentEnvironment() {
99
+ // 1. 优先从环境变量读取
100
+ const envFromEnv = process.env.BI_CLI_ENV;
101
+ if (envFromEnv && ['production', 'stage', 'development'].includes(envFromEnv)) {
102
+ return envFromEnv;
103
+ }
104
+ // 2. 从 token.json 读取
105
+ const token = getOptimaToken();
106
+ if (token?.env) {
107
+ return tokenEnvToEnvironment(token.env);
108
+ }
109
+ // 3. 默认使用生产环境
110
+ return 'production';
111
+ }
112
+ /**
113
+ * 获取当前环境的配置信息
114
+ */
115
+ export function getCurrentEnvConfig() {
116
+ const env = getCurrentEnvironment();
117
+ return ENV_CONFIG[env];
118
+ }
119
+ /**
120
+ * 保存认证令牌到 ~/.optima/token.json
121
+ */
122
+ export function saveTokens(access_token, refresh_token, expires_in, env, user) {
123
+ const expires_at = Date.now() + expires_in * 1000;
124
+ const token = {
125
+ env: environmentToTokenEnv(env),
126
+ access_token,
127
+ refresh_token,
128
+ token_type: 'Bearer',
129
+ expires_at,
130
+ user,
131
+ };
132
+ saveOptimaToken(token);
133
+ }
134
+ /**
135
+ * 获取访问令牌
136
+ * 优先级:BI_CLI_TOKEN > OPTIMA_TOKEN > ~/.optima/token.json
137
+ */
138
+ export function getAccessToken() {
139
+ // 1. 优先从 BI_CLI_TOKEN 环境变量读取
140
+ if (process.env.BI_CLI_TOKEN) {
141
+ return process.env.BI_CLI_TOKEN;
142
+ }
143
+ // 2. 从 OPTIMA_TOKEN 环境变量读取(兼容 optima-agent)
144
+ if (process.env.OPTIMA_TOKEN) {
145
+ return process.env.OPTIMA_TOKEN;
146
+ }
147
+ // 3. 从 token.json 读取
148
+ const token = getOptimaToken();
149
+ return token?.access_token ?? null;
150
+ }
151
+ /**
152
+ * 获取 refresh token
153
+ */
154
+ export function getRefreshToken() {
155
+ const token = getOptimaToken();
156
+ return token?.refresh_token ?? null;
157
+ }
158
+ /**
159
+ * 获取 token 过期时间
160
+ */
161
+ export function getTokenExpiresAt() {
162
+ const token = getOptimaToken();
163
+ return token?.expires_at ?? null;
164
+ }
165
+ /**
166
+ * 检查 token 是否过期
167
+ */
168
+ export function isTokenExpired() {
169
+ // 环境变量 token 不检查过期
170
+ if (process.env.BI_CLI_TOKEN || process.env.OPTIMA_TOKEN) {
171
+ return false;
172
+ }
173
+ const expiresAt = getTokenExpiresAt();
174
+ if (!expiresAt)
175
+ return true;
176
+ return Date.now() >= expiresAt;
177
+ }
178
+ /**
179
+ * 检查是否已认证
180
+ */
181
+ export function isAuthenticated() {
182
+ return getAccessToken() !== null;
183
+ }
184
+ /**
185
+ * 保存用户信息到 token.json
186
+ */
187
+ export function saveUser(user) {
188
+ const token = getOptimaToken();
189
+ if (token) {
190
+ token.user = user;
191
+ saveOptimaToken(token);
192
+ }
193
+ }
194
+ /**
195
+ * 获取当前用户信息
196
+ */
197
+ export function getUser() {
198
+ const token = getOptimaToken();
199
+ return token?.user ?? null;
200
+ }
201
+ /**
202
+ * 清除配置(登出)- 删除 token.json
203
+ */
204
+ export function clearAuth() {
205
+ deleteOptimaToken();
206
+ }
207
+ /**
208
+ * 获取配置文件路径
209
+ */
210
+ export function getConfigPath() {
211
+ return TOKEN_FILE;
212
+ }
213
+ /**
214
+ * 获取 BI API URL
215
+ * 优先级:BI_CLI_BACKEND_URL 环境变量 > 当前环境配置
216
+ */
217
+ export function getBackendUrl() {
218
+ if (process.env.BI_CLI_BACKEND_URL) {
219
+ return process.env.BI_CLI_BACKEND_URL;
220
+ }
221
+ return getCurrentEnvConfig().backendUrl;
222
+ }
223
+ /**
224
+ * 获取 Auth API URL
225
+ * 优先级:BI_CLI_AUTH_URL 环境变量 > 当前环境配置
226
+ */
227
+ export function getAuthUrl() {
228
+ if (process.env.BI_CLI_AUTH_URL) {
229
+ return process.env.BI_CLI_AUTH_URL;
230
+ }
231
+ return getCurrentEnvConfig().authUrl;
232
+ }
11
233
  /**
12
- * Get CLI configuration.
13
- *
14
- * Supports environment variables for CI/development:
15
- * - BI_CLI_TOKEN: Access token (overrides stored token)
16
- * - BI_CLI_BACKEND_URL: Backend URL (overrides stored URL)
17
- * - BI_CLI_AUTH_URL: Auth URL (overrides stored URL)
234
+ * Get CLI configuration (兼容旧接口)
18
235
  */
19
236
  export function getConfig() {
20
237
  return {
21
- environment: config.get('environment'),
22
- authUrl: process.env.BI_CLI_AUTH_URL || config.get('authUrl'),
23
- backendUrl: process.env.BI_CLI_BACKEND_URL || config.get('backendUrl'),
24
- accessToken: process.env.BI_CLI_TOKEN || config.get('accessToken'),
25
- refreshToken: config.get('refreshToken'),
238
+ environment: getCurrentEnvironment(),
239
+ authUrl: getAuthUrl(),
240
+ backendUrl: getBackendUrl(),
241
+ accessToken: getAccessToken() ?? undefined,
242
+ refreshToken: getRefreshToken() ?? undefined,
26
243
  };
27
244
  }
245
+ /**
246
+ * Set config (兼容旧接口 - 现在只支持保存 token)
247
+ */
28
248
  export function setConfig(key, value) {
29
- // Clear the key first if it exists and value is an object
30
- if (config.has(key) && typeof value === 'object' && value !== null) {
31
- config.delete(key);
249
+ if (key === 'accessToken' || key === 'refreshToken') {
250
+ const token = getOptimaToken();
251
+ if (token) {
252
+ if (key === 'accessToken') {
253
+ token.access_token = value;
254
+ }
255
+ else {
256
+ token.refresh_token = value;
257
+ }
258
+ saveOptimaToken(token);
259
+ }
32
260
  }
33
- config.set(key, value);
34
- }
35
- export function clearAuth() {
36
- config.delete('accessToken');
37
- config.delete('refreshToken');
261
+ // environment, authUrl, backendUrl 现在通过环境变量或 token.json 的 env 字段控制
38
262
  }
39
263
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAUxB,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,IAAI,CAAY;IACxC,WAAW,EAAE,eAAe;IAC5B,QAAQ,EAAE;QACR,WAAW,EAAE,YAAY;QACzB,OAAO,EAAE,0BAA0B;QACnC,UAAU,EAAE,4BAA4B;KACzC;IACD,aAAa,EAAE,+CAA+C;CAC/D,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO;QACL,WAAW,EAAE,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC;QACtC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC;QAC7D,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC;QACtE,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC;QAClE,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC;KACzC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAoB,EAAE,KAAU;IACxD,0DAA0D;IAC1D,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;IAC7B,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/bi-cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "Optima BI CLI - AI-friendly business intelligence tool",
6
6
  "main": "dist/index.js",
@@ -2,7 +2,15 @@ import { Command } from 'commander';
2
2
  import axios from 'axios';
3
3
  import ora from 'ora';
4
4
  import chalk from 'chalk';
5
- import { setConfig, clearAuth, getConfig } from '../config/index.js';
5
+ import {
6
+ clearAuth,
7
+ getConfig,
8
+ saveTokens,
9
+ saveUser,
10
+ getConfigPath,
11
+ ENV_CONFIG,
12
+ type Environment,
13
+ } from '../config/index.js';
6
14
  import { success, error, info } from '../utils/output.js';
7
15
 
8
16
  interface DeviceCodeResponse {
@@ -24,6 +32,7 @@ interface TokenResponse {
24
32
  interface UserInfo {
25
33
  id: string;
26
34
  email: string;
35
+ name?: string;
27
36
  role: 'merchant' | 'admin';
28
37
  merchant_id?: string;
29
38
  }
@@ -37,41 +46,26 @@ export function createAuthCommand(): Command {
37
46
  .description('Login with OAuth 2.0 Device Flow')
38
47
  .option('--env <environment>', 'Environment (production|stage|development)', 'production')
39
48
  .action(async (options) => {
40
- const { env } = options;
49
+ const env = options.env as Environment;
41
50
 
42
- // Set URLs based on environment
43
- const authUrls = {
44
- production: 'https://auth.optima.chat',
45
- stage: 'https://auth-stage.optima.chat',
46
- development: 'http://localhost:4000',
47
- };
48
-
49
- const backendUrls = {
50
- production: 'https://bi-api.optima.chat',
51
- stage: 'https://bi-api-stage.optima.chat',
52
- development: 'http://localhost:3001',
53
- };
54
-
55
- const authUrl = authUrls[env as keyof typeof authUrls];
56
- const backendUrl = backendUrls[env as keyof typeof backendUrls];
57
-
58
- if (!authUrl || !backendUrl) {
51
+ // Validate environment
52
+ if (!['production', 'stage', 'development'].includes(env)) {
59
53
  error(`Invalid environment: ${env}`);
60
54
  process.exit(1);
61
55
  }
62
56
 
63
- setConfig('environment', env);
64
- setConfig('authUrl', authUrl);
65
- setConfig('backendUrl', backendUrl);
57
+ const envConfig = ENV_CONFIG[env];
58
+ const { authUrl, clientId } = envConfig;
66
59
 
67
60
  info(`Logging in to ${env} environment...`);
61
+ info(`Auth URL: ${authUrl}`);
68
62
 
69
63
  try {
70
64
  // Step 1: Request device code
71
65
  const spinner = ora('Requesting device code...').start();
72
66
  const deviceCodeRes = await axios.post<DeviceCodeResponse>(
73
67
  `${authUrl}/api/v1/oauth/device/authorize`,
74
- { client_id: 'bi-cli-aqkutatj' }
68
+ { client_id: clientId }
75
69
  );
76
70
  spinner.succeed('Device code received');
77
71
 
@@ -88,7 +82,7 @@ export function createAuthCommand(): Command {
88
82
  const browserUrl = verification_uri_complete || verification_uri;
89
83
 
90
84
  // Step 2: Display authorization instructions
91
- console.log(chalk.bold('\n📋 Authorization Required:\n'));
85
+ console.log(chalk.bold('\n Authorization Required:\n'));
92
86
  if (verification_uri_complete) {
93
87
  console.log(` Opening browser with pre-filled code: ${chalk.yellow.bold(user_code)}`);
94
88
  console.log(` URL: ${chalk.cyan(verification_uri_complete)}\n`);
@@ -121,7 +115,7 @@ export function createAuthCommand(): Command {
121
115
  `${authUrl}/api/v1/oauth/device/token`,
122
116
  new URLSearchParams({
123
117
  grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
124
- client_id: 'bi-cli-aqkutatj',
118
+ client_id: clientId,
125
119
  device_code,
126
120
  }),
127
121
  {
@@ -151,20 +145,17 @@ export function createAuthCommand(): Command {
151
145
  pollSpinner.text = `Authorization successful after ${pollCount} attempts`;
152
146
  break;
153
147
  } catch (err: unknown) {
154
- const error = err as { response?: { data?: { error?: string } } };
155
- const errorCode = error.response?.data?.error;
148
+ const axiosErr = err as { response?: { data?: { error?: string } } };
149
+ const errorCode = axiosErr.response?.data?.error;
156
150
 
157
151
  if (errorCode === 'authorization_pending') {
158
- // Continue polling
159
152
  pollSpinner.text = `Waiting for authorization... (attempt ${pollCount})`;
160
153
  continue;
161
154
  } else if (errorCode === 'slow_down') {
162
- // Increase interval
163
155
  pollSpinner.text = `Slowing down polling... (attempt ${pollCount})`;
164
156
  await new Promise((resolve) => setTimeout(resolve, 5000));
165
157
  continue;
166
158
  } else {
167
- // Unexpected error
168
159
  pollSpinner.fail(`Polling failed: ${errorCode || 'unknown error'}`);
169
160
  throw err;
170
161
  }
@@ -179,20 +170,32 @@ export function createAuthCommand(): Command {
179
170
 
180
171
  pollSpinner.succeed();
181
172
 
182
- // Step 5: Save tokens
183
- setConfig('accessToken', token.access_token);
184
- setConfig('refreshToken', token.refresh_token);
185
-
186
- // Step 6: Fetch user info (optional - just for display)
173
+ // Step 5: Fetch user info and save tokens
174
+ let userInfo: UserInfo | undefined;
187
175
  try {
188
- const userInfo = await axios.get<UserInfo>(`${authUrl}/api/v1/users/me`, {
176
+ const userRes = await axios.get<UserInfo>(`${authUrl}/api/v1/users/me`, {
189
177
  headers: { Authorization: `Bearer ${token.access_token}` },
190
178
  });
191
- success(`Logged in as ${chalk.bold(userInfo.data.email)} (${userInfo.data.role})`);
192
- } catch (userInfoErr) {
193
- // If fetching user info fails, still consider login successful
194
- success('Login successful! Token saved.');
179
+ userInfo = userRes.data;
180
+ } catch {
181
+ // User info fetch failed, continue without it
182
+ }
183
+
184
+ // Step 6: Save tokens to ~/.optima/token.json
185
+ saveTokens(
186
+ token.access_token,
187
+ token.refresh_token,
188
+ token.expires_in,
189
+ env,
190
+ userInfo ? { id: userInfo.id, email: userInfo.email, name: userInfo.name } : undefined
191
+ );
192
+
193
+ if (userInfo) {
194
+ success(`Logged in as ${chalk.bold(userInfo.email)} (${userInfo.role})`);
195
+ } else {
196
+ success('Login successful!');
195
197
  }
198
+ info(`Token saved to ${getConfigPath()}`);
196
199
  } catch (err: unknown) {
197
200
  const errorMsg = err instanceof Error ? err.message : 'Unknown error';
198
201
  error(`Login failed: ${errorMsg}`);
@@ -203,10 +206,11 @@ export function createAuthCommand(): Command {
203
206
  // auth logout
204
207
  auth
205
208
  .command('logout')
206
- .description('Logout and clear stored credentials')
209
+ .description('Logout and delete ~/.optima/token.json')
207
210
  .action(() => {
208
211
  clearAuth();
209
212
  success('Logged out successfully');
213
+ info(`Deleted ${getConfigPath()}`);
210
214
  });
211
215
 
212
216
  // auth whoami
@@ -226,13 +230,21 @@ export function createAuthCommand(): Command {
226
230
  headers: { Authorization: `Bearer ${cfg.accessToken}` },
227
231
  });
228
232
 
229
- console.log(chalk.bold('\n👤 Current User:\n'));
233
+ // Update user info in token.json
234
+ saveUser({
235
+ id: userInfo.data.id,
236
+ email: userInfo.data.email,
237
+ name: userInfo.data.name,
238
+ });
239
+
240
+ console.log(chalk.bold('\n Current User:\n'));
230
241
  console.log(` Email: ${chalk.cyan(userInfo.data.email)}`);
231
242
  console.log(` Role: ${chalk.yellow(userInfo.data.role)}`);
232
243
  if (userInfo.data.merchant_id) {
233
244
  console.log(` Merchant ID: ${chalk.gray(userInfo.data.merchant_id)}`);
234
245
  }
235
- console.log(` Environment: ${chalk.green(cfg.environment)}\n`);
246
+ console.log(` Environment: ${chalk.green(cfg.environment)}`);
247
+ console.log(` Config: ${chalk.gray(getConfigPath())}\n`);
236
248
  } catch (err: unknown) {
237
249
  const axiosError = err as { response?: { status?: number } };
238
250
  if (axiosError.response?.status === 401) {
@@ -245,32 +257,23 @@ export function createAuthCommand(): Command {
245
257
  }
246
258
  });
247
259
 
248
- // auth switch
260
+ // auth status
249
261
  auth
250
- .command('switch')
251
- .description('Switch environment')
252
- .option('--env <environment>', 'Environment (production|stage|development)', 'production')
253
- .action((options) => {
254
- const { env } = options;
262
+ .command('status')
263
+ .description('Show authentication status')
264
+ .action(() => {
265
+ const cfg = getConfig();
255
266
 
256
- const backendUrls = {
257
- production: 'https://bi-api.optima.chat',
258
- stage: 'https://bi-api-stage.optima.chat',
259
- development: 'http://localhost:3001',
260
- };
267
+ console.log(chalk.bold('\n Authentication Status:\n'));
268
+ console.log(` Environment: ${chalk.green(cfg.environment)}`);
269
+ console.log(` Auth URL: ${chalk.cyan(cfg.authUrl)}`);
270
+ console.log(` Backend URL: ${chalk.cyan(cfg.backendUrl)}`);
271
+ console.log(` Config file: ${chalk.gray(getConfigPath())}`);
272
+ console.log(` Authenticated: ${cfg.accessToken ? chalk.green('Yes') : chalk.red('No')}\n`);
261
273
 
262
- const backendUrl = backendUrls[env as keyof typeof backendUrls];
263
- if (!backendUrl) {
264
- error(`Invalid environment: ${env}`);
265
- process.exit(1);
274
+ if (!cfg.accessToken) {
275
+ info('Run "bi-cli auth login" to authenticate');
266
276
  }
267
-
268
- setConfig('environment', env);
269
- setConfig('backendUrl', backendUrl);
270
- clearAuth(); // Clear tokens when switching environment
271
-
272
- success(`Switched to ${env} environment`);
273
- info('Please login again: bi-cli auth login');
274
277
  });
275
278
 
276
279
  return auth;
@@ -1,50 +1,339 @@
1
- import Conf from 'conf';
1
+ import { readFileSync, existsSync, writeFileSync, mkdirSync, unlinkSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { homedir } from 'os';
2
4
 
3
- export interface CliConfig {
4
- environment: 'production' | 'stage' | 'development';
5
+ // ============== 类型定义 ==============
6
+
7
+ export type Environment = 'production' | 'stage' | 'development';
8
+
9
+ // token.json 中的 env 字段值
10
+ type TokenEnv = 'prod' | 'stage' | 'ci';
11
+
12
+ interface UserData {
13
+ id: string;
14
+ email: string;
15
+ name?: string;
16
+ }
17
+
18
+ /**
19
+ * ~/.optima/token.json 文件结构(与 optima-agent/commerce-cli 共享)
20
+ */
21
+ interface OptimaToken {
22
+ env: TokenEnv;
23
+ access_token: string;
24
+ refresh_token?: string;
25
+ token_type: string;
26
+ expires_at: number;
27
+ user?: UserData;
28
+ }
29
+
30
+ interface EnvironmentConfig {
5
31
  authUrl: string;
6
32
  backendUrl: string;
7
- accessToken?: string;
8
- refreshToken?: string;
33
+ clientId: string;
9
34
  }
10
35
 
11
- export const config = new Conf<CliConfig>({
12
- projectName: 'optima-bi-cli',
13
- defaults: {
14
- environment: 'production',
36
+ // ============== 环境配置常量 ==============
37
+
38
+ export const ENV_CONFIG: Record<Environment, EnvironmentConfig> = {
39
+ production: {
40
+ authUrl: 'https://auth.optima.onl',
41
+ backendUrl: 'https://bi-api.optima.onl',
42
+ clientId: 'bi-cli-wl18yjdk',
43
+ },
44
+ stage: {
45
+ authUrl: 'https://auth.stage.optima.onl',
46
+ backendUrl: 'https://bi-api.stage.optima.onl',
47
+ clientId: 'bi-cli-gqqcui4k',
48
+ },
49
+ development: {
15
50
  authUrl: 'https://auth.optima.chat',
16
51
  backendUrl: 'https://bi-api.optima.chat',
52
+ clientId: 'bi-cli-aqkutatj',
17
53
  },
18
- encryptionKey: 'optima-bi-cli-secret-key-change-in-production',
19
- });
54
+ };
55
+
56
+ // ============== Token 文件路径 ==============
57
+
58
+ const OPTIMA_DIR = join(homedir(), '.optima');
59
+ const TOKEN_FILE = join(OPTIMA_DIR, 'token.json');
60
+
61
+ // ============== 环境映射 ==============
20
62
 
21
63
  /**
22
- * Get CLI configuration.
23
- *
24
- * Supports environment variables for CI/development:
25
- * - BI_CLI_TOKEN: Access token (overrides stored token)
26
- * - BI_CLI_BACKEND_URL: Backend URL (overrides stored URL)
27
- * - BI_CLI_AUTH_URL: Auth URL (overrides stored URL)
64
+ * token.json 的 env 字段映射到 Environment 类型
28
65
  */
29
- export function getConfig(): CliConfig {
30
- return {
31
- environment: config.get('environment'),
32
- authUrl: process.env.BI_CLI_AUTH_URL || config.get('authUrl'),
33
- backendUrl: process.env.BI_CLI_BACKEND_URL || config.get('backendUrl'),
34
- accessToken: process.env.BI_CLI_TOKEN || config.get('accessToken'),
35
- refreshToken: config.get('refreshToken'),
66
+ function tokenEnvToEnvironment(tokenEnv: TokenEnv): Environment {
67
+ switch (tokenEnv) {
68
+ case 'prod':
69
+ return 'production';
70
+ case 'stage':
71
+ return 'stage';
72
+ case 'ci':
73
+ return 'development';
74
+ default:
75
+ return 'production';
76
+ }
77
+ }
78
+
79
+ /**
80
+ * 将 Environment 类型映射到 token.json 的 env 字段
81
+ */
82
+ function environmentToTokenEnv(env: Environment): TokenEnv {
83
+ switch (env) {
84
+ case 'production':
85
+ return 'prod';
86
+ case 'stage':
87
+ return 'stage';
88
+ case 'development':
89
+ return 'ci';
90
+ default:
91
+ return 'prod';
92
+ }
93
+ }
94
+
95
+ // ============== Token 文件操作 ==============
96
+
97
+ /**
98
+ * 从 ~/.optima/token.json 读取 token 数据
99
+ */
100
+ function getOptimaToken(): OptimaToken | null {
101
+ if (!existsSync(TOKEN_FILE)) {
102
+ return null;
103
+ }
104
+
105
+ try {
106
+ const content = readFileSync(TOKEN_FILE, 'utf-8');
107
+ return JSON.parse(content) as OptimaToken;
108
+ } catch {
109
+ // 文件读取或解析失败
110
+ return null;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * 保存 token 到 ~/.optima/token.json
116
+ */
117
+ function saveOptimaToken(token: OptimaToken): void {
118
+ mkdirSync(OPTIMA_DIR, { recursive: true });
119
+ writeFileSync(TOKEN_FILE, JSON.stringify(token, null, 2), 'utf-8');
120
+ }
121
+
122
+ /**
123
+ * 删除 ~/.optima/token.json
124
+ */
125
+ function deleteOptimaToken(): void {
126
+ try {
127
+ if (existsSync(TOKEN_FILE)) {
128
+ unlinkSync(TOKEN_FILE);
129
+ }
130
+ } catch {
131
+ // 忽略删除失败
132
+ }
133
+ }
134
+
135
+ // ============== 公开 API ==============
136
+
137
+ /**
138
+ * 获取当前环境
139
+ * 优先级:BI_CLI_ENV 环境变量 > token.json 的 env 字段 > 默认 production
140
+ */
141
+ export function getCurrentEnvironment(): Environment {
142
+ // 1. 优先从环境变量读取
143
+ const envFromEnv = process.env.BI_CLI_ENV as Environment;
144
+ if (envFromEnv && ['production', 'stage', 'development'].includes(envFromEnv)) {
145
+ return envFromEnv;
146
+ }
147
+
148
+ // 2. 从 token.json 读取
149
+ const token = getOptimaToken();
150
+ if (token?.env) {
151
+ return tokenEnvToEnvironment(token.env);
152
+ }
153
+
154
+ // 3. 默认使用生产环境
155
+ return 'production';
156
+ }
157
+
158
+ /**
159
+ * 获取当前环境的配置信息
160
+ */
161
+ export function getCurrentEnvConfig(): EnvironmentConfig {
162
+ const env = getCurrentEnvironment();
163
+ return ENV_CONFIG[env];
164
+ }
165
+
166
+ /**
167
+ * 保存认证令牌到 ~/.optima/token.json
168
+ */
169
+ export function saveTokens(
170
+ access_token: string,
171
+ refresh_token: string,
172
+ expires_in: number,
173
+ env: Environment,
174
+ user?: UserData
175
+ ): void {
176
+ const expires_at = Date.now() + expires_in * 1000;
177
+ const token: OptimaToken = {
178
+ env: environmentToTokenEnv(env),
179
+ access_token,
180
+ refresh_token,
181
+ token_type: 'Bearer',
182
+ expires_at,
183
+ user,
36
184
  };
185
+ saveOptimaToken(token);
186
+ }
187
+
188
+ /**
189
+ * 获取访问令牌
190
+ * 优先级:BI_CLI_TOKEN > OPTIMA_TOKEN > ~/.optima/token.json
191
+ */
192
+ export function getAccessToken(): string | null {
193
+ // 1. 优先从 BI_CLI_TOKEN 环境变量读取
194
+ if (process.env.BI_CLI_TOKEN) {
195
+ return process.env.BI_CLI_TOKEN;
196
+ }
197
+
198
+ // 2. 从 OPTIMA_TOKEN 环境变量读取(兼容 optima-agent)
199
+ if (process.env.OPTIMA_TOKEN) {
200
+ return process.env.OPTIMA_TOKEN;
201
+ }
202
+
203
+ // 3. 从 token.json 读取
204
+ const token = getOptimaToken();
205
+ return token?.access_token ?? null;
206
+ }
207
+
208
+ /**
209
+ * 获取 refresh token
210
+ */
211
+ export function getRefreshToken(): string | null {
212
+ const token = getOptimaToken();
213
+ return token?.refresh_token ?? null;
214
+ }
215
+
216
+ /**
217
+ * 获取 token 过期时间
218
+ */
219
+ export function getTokenExpiresAt(): number | null {
220
+ const token = getOptimaToken();
221
+ return token?.expires_at ?? null;
222
+ }
223
+
224
+ /**
225
+ * 检查 token 是否过期
226
+ */
227
+ export function isTokenExpired(): boolean {
228
+ // 环境变量 token 不检查过期
229
+ if (process.env.BI_CLI_TOKEN || process.env.OPTIMA_TOKEN) {
230
+ return false;
231
+ }
232
+
233
+ const expiresAt = getTokenExpiresAt();
234
+ if (!expiresAt) return true;
235
+ return Date.now() >= expiresAt;
236
+ }
237
+
238
+ /**
239
+ * 检查是否已认证
240
+ */
241
+ export function isAuthenticated(): boolean {
242
+ return getAccessToken() !== null;
37
243
  }
38
244
 
39
- export function setConfig(key: keyof CliConfig, value: any): void {
40
- // Clear the key first if it exists and value is an object
41
- if (config.has(key) && typeof value === 'object' && value !== null) {
42
- config.delete(key);
245
+ /**
246
+ * 保存用户信息到 token.json
247
+ */
248
+ export function saveUser(user: UserData): void {
249
+ const token = getOptimaToken();
250
+ if (token) {
251
+ token.user = user;
252
+ saveOptimaToken(token);
43
253
  }
44
- config.set(key, value);
45
254
  }
46
255
 
256
+ /**
257
+ * 获取当前用户信息
258
+ */
259
+ export function getUser(): UserData | null {
260
+ const token = getOptimaToken();
261
+ return token?.user ?? null;
262
+ }
263
+
264
+ /**
265
+ * 清除配置(登出)- 删除 token.json
266
+ */
47
267
  export function clearAuth(): void {
48
- config.delete('accessToken');
49
- config.delete('refreshToken');
268
+ deleteOptimaToken();
269
+ }
270
+
271
+ /**
272
+ * 获取配置文件路径
273
+ */
274
+ export function getConfigPath(): string {
275
+ return TOKEN_FILE;
276
+ }
277
+
278
+ /**
279
+ * 获取 BI API URL
280
+ * 优先级:BI_CLI_BACKEND_URL 环境变量 > 当前环境配置
281
+ */
282
+ export function getBackendUrl(): string {
283
+ if (process.env.BI_CLI_BACKEND_URL) {
284
+ return process.env.BI_CLI_BACKEND_URL;
285
+ }
286
+ return getCurrentEnvConfig().backendUrl;
287
+ }
288
+
289
+ /**
290
+ * 获取 Auth API URL
291
+ * 优先级:BI_CLI_AUTH_URL 环境变量 > 当前环境配置
292
+ */
293
+ export function getAuthUrl(): string {
294
+ if (process.env.BI_CLI_AUTH_URL) {
295
+ return process.env.BI_CLI_AUTH_URL;
296
+ }
297
+ return getCurrentEnvConfig().authUrl;
298
+ }
299
+
300
+ // ============== 兼容性 API(保留旧接口) ==============
301
+
302
+ export interface CliConfig {
303
+ environment: Environment;
304
+ authUrl: string;
305
+ backendUrl: string;
306
+ accessToken?: string;
307
+ refreshToken?: string;
308
+ }
309
+
310
+ /**
311
+ * Get CLI configuration (兼容旧接口)
312
+ */
313
+ export function getConfig(): CliConfig {
314
+ return {
315
+ environment: getCurrentEnvironment(),
316
+ authUrl: getAuthUrl(),
317
+ backendUrl: getBackendUrl(),
318
+ accessToken: getAccessToken() ?? undefined,
319
+ refreshToken: getRefreshToken() ?? undefined,
320
+ };
321
+ }
322
+
323
+ /**
324
+ * Set config (兼容旧接口 - 现在只支持保存 token)
325
+ */
326
+ export function setConfig(key: keyof CliConfig, value: string): void {
327
+ if (key === 'accessToken' || key === 'refreshToken') {
328
+ const token = getOptimaToken();
329
+ if (token) {
330
+ if (key === 'accessToken') {
331
+ token.access_token = value;
332
+ } else {
333
+ token.refresh_token = value;
334
+ }
335
+ saveOptimaToken(token);
336
+ }
337
+ }
338
+ // environment, authUrl, backendUrl 现在通过环境变量或 token.json 的 env 字段控制
50
339
  }