dgxay-code-cli 1.0.0 → 1.1.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.
@@ -19,17 +19,17 @@ const { ask } = require('../services/input');
19
19
 
20
20
  const options = [
21
21
  { name: 'client-id', type: 'string', valueName: 'id', desc: 'OAuth Client ID' },
22
- { name: 'client-secret', type: 'string', valueName: 'secret', desc: 'OAuth Client Secret(可选)' },
23
- { name: 'authorize-url', type: 'string', valueName: 'url', desc: '授权端点' },
24
- { name: 'token-url', type: 'string', valueName: 'url', desc: '令牌端点' },
25
- { name: 'scopes', type: 'string', valueName: 'text', desc: '权限范围' },
26
- { name: 'code', type: 'string', valueName: 'code', desc: '手动流程:直接提交授权码(code#state)' },
27
- { name: 'no-browser', type: 'boolean', desc: '不自动打开浏览器,只打印授权链接' },
28
- { name: 'yes', alias: 'y', type: 'boolean', desc: '跳过确认' }
22
+ { name: 'client-secret', type: 'string', valueName: 'secret', desc: 'OAuth Client Secret (optional)' },
23
+ { name: 'authorize-url', type: 'string', valueName: 'url', desc: 'Authorize endpoint' },
24
+ { name: 'token-url', type: 'string', valueName: 'url', desc: 'Token endpoint' },
25
+ { name: 'scopes', type: 'string', valueName: 'text', desc: 'Permission scope' },
26
+ { name: 'code', type: 'string', valueName: 'code', desc: 'Manual flow: submit the auth code directly (code#state)' },
27
+ { name: 'no-browser', type: 'boolean', desc: 'Do not open the browser, only print the authorize link' },
28
+ { name: 'yes', alias: 'y', type: 'boolean', desc: 'Skip confirmation' }
29
29
  ];
30
30
 
31
31
  function formatExpiry(ts) {
32
- if (!ts) return '长期有效';
32
+ if (!ts) return 'never expires';
33
33
  const date = new Date(ts);
34
34
  const pad = (value) => String(value).padStart(2, '0');
35
35
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(
@@ -40,10 +40,10 @@ function formatExpiry(ts) {
40
40
  function list() {
41
41
  const providers = oauth.listProviders();
42
42
  print.blank();
43
- print.heading('账户连接');
43
+ print.heading('Account connections');
44
44
  const rows = providers.map((item) => {
45
45
  const connection = item.connection;
46
- const status = !connection ? '未连接' : connection.expired ? '已过期' : '已连接';
46
+ const status = !connection ? 'not connected' : connection.expired ? 'expired' : 'connected';
47
47
  const tone = !connection ? (value) => value : connection.expired ? COLORS.yellow : COLORS.green;
48
48
  return [
49
49
  item.id,
@@ -52,24 +52,24 @@ function list() {
52
52
  tone(status),
53
53
  connection?.account || '',
54
54
  connection ? formatExpiry(connection.expiresAt) : '',
55
- item.redirectMode === 'manual' ? '手动授权码' : '系统浏览器'
55
+ item.redirectMode === 'manual' ? 'manual auth code' : 'system browser'
56
56
  ];
57
57
  });
58
58
  print.table(
59
59
  [
60
60
  { title: 'ID', max: 10 },
61
- { title: '平台', max: 10 },
62
- { title: '账户类型', max: 24 },
63
- { title: '状态', max: 8 },
64
- { title: '账号', max: 28 },
65
- { title: '有效期', max: 18 },
66
- { title: '授权方式', max: 12 }
61
+ { title: 'Platform', max: 10 },
62
+ { title: 'Account type', max: 24 },
63
+ { title: 'Status', max: 8 },
64
+ { title: 'Account', max: 28 },
65
+ { title: 'Expires', max: 18 },
66
+ { title: 'Auth method', max: 12 }
67
67
  ],
68
68
  rows
69
69
  );
70
70
  print.blank();
71
- print.hint('dgxay oauth connect <平台> 连接 · dgxay oauth disconnect <平台> 断开');
72
- print.hint('连接后可在供应商中使用 OAuth:dgxay provider edit <名称> --oauth-provider <平台>');
71
+ print.hint('dgxay oauth connect <platform> to connect · dgxay oauth disconnect <platform> to disconnect');
72
+ print.hint('After connecting, enable OAuth on a provider: dgxay provider edit <name> --oauth-provider <platform>');
73
73
  print.blank();
74
74
  return 0;
75
75
  }
@@ -77,14 +77,14 @@ function list() {
77
77
  async function connect(id, opts) {
78
78
  const def = oauth.PROVIDERS[id];
79
79
  if (!def) {
80
- print.fail(`不支持的平台:${id}(可选 openai / anthropic / xai / google)`);
80
+ print.fail(`Unsupported platform: ${id} (choose openai / anthropic / xai / google)`);
81
81
  return 1;
82
82
  }
83
83
  const current = oauth.listProviders().find((item) => item.id === id);
84
84
  if (current.connection && !current.connection.expired && !opts.yes && process.stdin.isTTY) {
85
- const answer = await ask(`${def.name} 已连接(${current.connection.account})。重新授权会覆盖现有令牌,继续?[y/N] `);
85
+ const answer = await ask(`${def.name} is already connected (${current.connection.account}). Re-authorizing overwrites the existing token. Continue? [y/N] `);
86
86
  if (!/^y/i.test(String(answer || '').trim())) {
87
- print.hint('已取消');
87
+ print.hint('Cancelled');
88
88
  return 1;
89
89
  }
90
90
  }
@@ -97,56 +97,56 @@ async function connect(id, opts) {
97
97
  } catch (err) {
98
98
  print.fail(err.message);
99
99
  if (/Client ID/i.test(err.message)) {
100
- print.hint(`Google 需要先创建桌面应用 OAuth 客户端:dgxay oauth client google --client-id <ID>`);
100
+ print.hint(`Google requires a desktop-app OAuth client first: dgxay oauth client google --client-id <ID>`);
101
101
  }
102
102
  return 1;
103
103
  }
104
104
 
105
105
  print.blank();
106
- print.heading(`连接 ${def.name}`);
106
+ print.heading(`Connect ${def.name}`);
107
107
  print.hint(def.hint);
108
108
  print.blank();
109
- if (flow.browserOpened) print.ok('已打开系统浏览器,请在浏览器中完成授权');
109
+ if (flow.browserOpened) print.ok('Opened the system browser; complete authorization in the browser');
110
110
  else {
111
- print.warn('无法自动打开浏览器,请手动访问下面的链接:');
111
+ print.warn('Could not open the browser automatically; open the link below manually:');
112
112
  }
113
113
  print.blank();
114
114
  process.stdout.write(`${COLORS.cyan(flow.authUrl)}\n`);
115
115
  print.blank();
116
116
 
117
117
  if (flow.mode === 'manual') {
118
- print.write('浏览器授权后会显示一段授权码(形如 code#state),把它粘贴到这里:');
118
+ print.write('After authorizing in the browser, copy the auth code (like code#state) and paste it here:');
119
119
  let code = opts.code;
120
120
  if (!code) {
121
121
  if (!process.stdin.isTTY) {
122
- print.fail('非交互环境请使用 --code <授权码>');
122
+ print.fail('In non-interactive environments use --code <auth code>');
123
123
  return 1;
124
124
  }
125
- code = await ask('授权码: ');
125
+ code = await ask('Auth code: ');
126
126
  }
127
127
  if (!code) {
128
- print.fail('授权码为空');
128
+ print.fail('Auth code is empty');
129
129
  return 1;
130
130
  }
131
131
  try {
132
132
  const connection = await oauth.complete(flow.id, code);
133
- print.ok(`${def.name} 账户已连接:${connection.account}`);
133
+ print.ok(`${def.name} account connected: ${connection.account}`);
134
134
  return 0;
135
135
  } catch (err) {
136
- print.fail(err.message || '授权失败');
136
+ print.fail(err.message || 'Authorization failed');
137
137
  return 1;
138
138
  }
139
139
  }
140
140
 
141
- process.stdout.write(`${COLORS.faint('等待浏览器回调完成授权…(Ctrl+C 取消)')}\n`);
141
+ process.stdout.write(`${COLORS.faint('Waiting for the browser callback to finish authorization... (Ctrl+C to cancel)')}\n`);
142
142
  try {
143
143
  const connection = await oauth.wait(flow.id);
144
144
  print.blank();
145
- print.ok(`${def.name} 账户已连接:${connection.account}`);
146
- print.hint('在供应商里启用:dgxay provider edit <名称> --oauth-provider ' + id);
145
+ print.ok(`${def.name} account connected: ${connection.account}`);
146
+ print.hint('Enable it on a provider: dgxay provider edit <name> --oauth-provider ' + id);
147
147
  return 0;
148
148
  } catch (err) {
149
- print.fail(err.message || '授权失败');
149
+ print.fail(err.message || 'Authorization failed');
150
150
  return 1;
151
151
  }
152
152
  }
@@ -154,24 +154,24 @@ async function connect(id, opts) {
154
154
  function disconnect(id, opts) {
155
155
  const def = oauth.PROVIDERS[id];
156
156
  if (!def) {
157
- print.fail(`不支持的平台:${id}`);
157
+ print.fail(`Unsupported platform: ${id}`);
158
158
  return 1;
159
159
  }
160
160
  const current = oauth.listProviders().find((item) => item.id === id);
161
161
  if (!current?.connection) {
162
- print.warn(`${def.name} 尚未连接`);
162
+ print.warn(`${def.name} is not connected`);
163
163
  return 1;
164
164
  }
165
165
  oauth.disconnect(id);
166
- print.ok(`已断开 ${def.name} 账户(${current.connection.account})`);
167
- print.hint('使用该账户的供应商将无法请求,直到重新连接或改用 API Key');
166
+ print.ok(`Disconnected ${def.name} account (${current.connection.account})`);
167
+ print.hint('Providers using this account cannot make requests until you reconnect or switch to an API Key');
168
168
  return 0;
169
169
  }
170
170
 
171
171
  function saveClient(id, opts) {
172
172
  const def = oauth.PROVIDERS[id];
173
173
  if (!def) {
174
- print.fail(`不支持的平台:${id}`);
174
+ print.fail(`Unsupported platform: ${id}`);
175
175
  return 1;
176
176
  }
177
177
  const patch = {};
@@ -181,24 +181,24 @@ function saveClient(id, opts) {
181
181
  if (!Object.keys(patch).length) {
182
182
  const current = oauth.listProviders().find((item) => item.id === id);
183
183
  print.blank();
184
- print.heading(`${def.name} OAuth 客户端`);
184
+ print.heading(`${def.name} OAuth client`);
185
185
  print.keyValue([
186
- { label: 'Client ID', value: current.clientId ? `${current.clientId.slice(0, 8)}…` : '(空)' },
187
- { label: 'Client Secret', value: current.hasSecret ? '已设置' : '未设置' },
188
- { label: '授权端点', value: current.authorizeUrl },
189
- { label: '令牌端点', value: current.tokenUrl },
190
- { label: '权限范围', value: current.scopes },
191
- { label: '回调地址', value: current.redirectUri }
186
+ { label: 'Client ID', value: current.clientId ? `${current.clientId.slice(0, 8)}…` : '(empty)' },
187
+ { label: 'Client Secret', value: current.hasSecret ? 'set' : 'not set' },
188
+ { label: 'Authorize endpoint', value: current.authorizeUrl },
189
+ { label: 'Token endpoint', value: current.tokenUrl },
190
+ { label: 'Permission scope', value: current.scopes },
191
+ { label: 'Redirect URI', value: current.redirectUri }
192
192
  ]);
193
193
  print.blank();
194
- print.hint(`修改:dgxay oauth client ${id} --client-id <ID> [--client-secret <Secret>]`);
194
+ print.hint(`Modify: dgxay oauth client ${id} --client-id <ID> [--client-secret <Secret>]`);
195
195
  print.blank();
196
196
  return 0;
197
197
  }
198
198
  try {
199
199
  const saved = oauth.saveClient(id, patch);
200
- print.ok(`已保存 ${def.name} 的 OAuth 客户端配置`);
201
- print.hint(`现在可以连接:dgxay oauth connect ${saved.id}`);
200
+ print.ok(`Saved OAuth client config for ${def.name}`);
201
+ print.hint(`You can connect now: dgxay oauth connect ${saved.id}`);
202
202
  return 0;
203
203
  } catch (err) {
204
204
  print.fail(err.message);
@@ -213,33 +213,33 @@ async function run({ argv }) {
213
213
 
214
214
  if (action === 'list' || action === 'ls') return list();
215
215
  if (action === 'connect' || action === 'login') {
216
- if (!target) throw Object.assign(new Error('用法:dgxay oauth connect <openai|anthropic|xai|google>'), { userError: true });
216
+ if (!target) throw Object.assign(new Error('Usage: dgxay oauth connect <openai|anthropic|xai|google>'), { userError: true });
217
217
  return connect(target, opts);
218
218
  }
219
219
  if (action === 'disconnect' || action === 'logout') {
220
- if (!target) throw Object.assign(new Error('用法:dgxay oauth disconnect <平台>'), { userError: true });
220
+ if (!target) throw Object.assign(new Error('Usage: dgxay oauth disconnect <platform>'), { userError: true });
221
221
  return disconnect(target, opts);
222
222
  }
223
223
  if (action === 'client') {
224
- if (!target) throw Object.assign(new Error('用法:dgxay oauth client <平台> [--client-id ...]'), { userError: true });
224
+ if (!target) throw Object.assign(new Error('Usage: dgxay oauth client <platform> [--client-id ...]'), { userError: true });
225
225
  return saveClient(target, opts);
226
226
  }
227
- print.fail(`未知子命令:${action}`);
228
- print.hint('可用:list / connect / disconnect / client');
227
+ print.fail(`Unknown subcommand: ${action}`);
228
+ print.hint('Available: list / connect / disconnect / client');
229
229
  return 1;
230
230
  }
231
231
 
232
232
  module.exports = {
233
233
  name: 'oauth',
234
234
  aliases: ['account'],
235
- summary: 'OAuth 账户连接',
235
+ summary: 'OAuth account connections',
236
236
  usage: 'dgxay oauth <list|connect|disconnect|client>',
237
237
  options,
238
238
  subcommands: [
239
- ['list', '查看各平台连接状态'],
240
- ['connect <平台>', '连接(系统浏览器 + PKCE)'],
241
- ['disconnect <平台>', '断开并删除本地令牌'],
242
- ['client <平台>', '查看 / 修改 OAuth 客户端配置']
239
+ ['list', 'View connection status per platform'],
240
+ ['connect <platform>', 'Connect (system browser + PKCE)'],
241
+ ['disconnect <platform>', 'Disconnect and delete the local token'],
242
+ ['client <platform>', 'View / modify OAuth client config']
243
243
  ],
244
244
  examples: ['dgxay oauth list', 'dgxay oauth connect anthropic', 'dgxay oauth client google --client-id xxx.apps.googleusercontent.com'],
245
245
  run
@@ -25,23 +25,23 @@ function overview() {
25
25
  const available = settings.availablePermissions(config);
26
26
  const reviewer = resolveReviewer(config, config.activeProviderId);
27
27
  print.blank();
28
- print.heading('权限');
28
+ print.heading('Permission');
29
29
  for (const [key, meta] of Object.entries(settings.PERMISSIONS)) {
30
30
  const usable = available.includes(key);
31
31
  const active = current === key;
32
32
  print.write(
33
- ` ${active ? COLORS.accent('❯') : ' '} ${COLORS.accent(key.padEnd(8))} ${usable ? meta.label : COLORS.faint(`${meta.label}(不可用)`)}`
33
+ ` ${active ? COLORS.accent('❯') : ' '} ${COLORS.accent(key.padEnd(8))} ${usable ? meta.label : COLORS.faint(`${meta.label} (unavailable)`)}`
34
34
  );
35
35
  print.write(` ${COLORS.faint(meta.desc)}`);
36
36
  }
37
37
  print.blank();
38
38
  if (reviewer) {
39
- print.hint(`自动审查模型:${reviewer.provider.name} / ${reviewer.modelId}(来源:${reviewer.source === 'own' ? '当前供应商' : '默认供应商'})`);
39
+ print.hint(`Review model: ${reviewer.provider.name} / ${reviewer.modelId} (from: ${reviewer.source === 'own' ? 'current provider' : 'default provider'})`);
40
40
  } else {
41
- print.hint('尚未配置审查模型,自动审查不可用。用 dgxay provider review <供应商> --model <模型ID> 设置');
41
+ print.hint('No review model configured, so auto review is unavailable. Set one with dgxay provider review <provider> --model <model-id>');
42
42
  }
43
43
  if (config.ui?.permission === 'auto' && !available.includes('auto')) {
44
- print.warn('配置里的自动审查已失效,当前按普通权限运行');
44
+ print.warn('Auto review from config is no longer valid; running with normal permission');
45
45
  }
46
46
  print.blank();
47
47
  print.hint('dgxay permission set <none|normal|auto|full>');
@@ -58,20 +58,20 @@ async function run({ argv, runtime }) {
58
58
 
59
59
  if (action === 'set' || action === 'use') {
60
60
  const level = rest[0];
61
- if (!level) throw Object.assign(new Error('用法:dgxay permission set <none|normal|auto|full>'), { userError: true });
61
+ if (!level) throw Object.assign(new Error('Usage: dgxay permission set <none|normal|auto|full>'), { userError: true });
62
62
  if (!settings.PERMISSIONS[level]) {
63
- print.fail('权限只能是 none / normal / auto / full');
63
+ print.fail('Permission must be one of none / normal / auto / full');
64
64
  return 1;
65
65
  }
66
66
  if (level === 'auto' && !settings.hasReviewModel(config)) {
67
- print.fail('自动审查不可用:当前或默认供应商没有配置有效的审查模型');
68
- print.hint('先运行:dgxay provider review <供应商> --model <模型ID>');
67
+ print.fail('Auto review unavailable: neither the current nor the default provider has a valid review model');
68
+ print.hint('Run first: dgxay provider review <provider> --model <model-id>');
69
69
  return 1;
70
70
  }
71
71
  settings.setPermission(level);
72
- print.ok(`权限已设置为:${settings.PERMISSIONS[level].label}`);
72
+ print.ok(`Permission set to: ${settings.PERMISSIONS[level].label}`);
73
73
  if (level === 'full') {
74
- print.warn('完全权限下 AI 可以执行任意命令、读写任意文件,且不会询问');
74
+ print.warn('With full access the AI can run any command and read or write any file without asking');
75
75
  }
76
76
  void runtime;
77
77
  return 0;
@@ -80,28 +80,28 @@ async function run({ argv, runtime }) {
80
80
  if (settings.PERMISSIONS[action]) {
81
81
  const level = action;
82
82
  if (level === 'auto' && !settings.hasReviewModel(config)) {
83
- print.fail('自动审查不可用:请先配置审查模型');
83
+ print.fail('Auto review unavailable: configure a review model first');
84
84
  return 1;
85
85
  }
86
86
  settings.setPermission(level);
87
- print.ok(`权限已设置为:${settings.PERMISSIONS[level].label}`);
87
+ print.ok(`Permission set to: ${settings.PERMISSIONS[level].label}`);
88
88
  return 0;
89
89
  }
90
90
 
91
- print.fail(`未知用法:${action}`);
92
- print.hint('可用:list / set <档位>');
91
+ print.fail(`Unknown usage: ${action}`);
92
+ print.hint('Available: list / set <level>');
93
93
  return 1;
94
94
  }
95
95
 
96
96
  module.exports = {
97
97
  name: 'permission',
98
98
  aliases: ['perm'],
99
- summary: '四档权限:查看与切换',
100
- usage: 'dgxay permission [list|show|set <档位>]',
99
+ summary: 'Four permission levels: show and switch',
100
+ usage: 'dgxay permission [list|show|set <level>]',
101
101
  options,
102
102
  subcommands: [
103
- ['list', '查看权限与可用性'],
104
- ['set <档位>', '切换权限(写入配置)']
103
+ ['list', 'Show permissions and availability'],
104
+ ['set <level>', 'Switch permission (writes config)']
105
105
  ],
106
106
  examples: ['dgxay permission', 'dgxay permission set normal', 'dgxay permission set auto'],
107
107
  run