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.
@@ -21,15 +21,15 @@ const oauth = require('../core/oauth');
21
21
  const { ask, askSecret, confirm } = require('../services/input');
22
22
 
23
23
  const options = [
24
- { name: 'name', type: 'string', valueName: 'text', desc: '供应商名称' },
24
+ { name: 'name', type: 'string', valueName: 'text', desc: 'Provider name' },
25
25
  { name: 'protocol', type: 'string', valueName: 'p', desc: 'openai / anthropic / responses' },
26
- { name: 'base-url', type: 'string', valueName: 'url', desc: '接口地址' },
26
+ { name: 'base-url', type: 'string', valueName: 'url', desc: 'Base URL' },
27
27
  { name: 'api-key', type: 'string', valueName: 'key', desc: 'API Key' },
28
- { name: 'model', type: 'list', valueName: 'id', desc: '模型 ID(可重复或逗号分隔)' },
29
- { name: 'oauth-provider', type: 'string', valueName: 'id', desc: '使用已连接的 OAuth 账户' },
30
- { name: 'review-model', type: 'string', valueName: 'id', desc: '自动审查模型 ID' },
31
- { name: 'context-window', type: 'number', valueName: 'n', desc: '上下文窗口(可选)' },
32
- { name: 'yes', alias: 'y', type: 'boolean', desc: '跳过确认' }
28
+ { name: 'model', type: 'list', valueName: 'id', desc: 'Model ID (repeatable or comma-separated)' },
29
+ { name: 'oauth-provider', type: 'string', valueName: 'id', desc: 'Use a connected OAuth account' },
30
+ { name: 'review-model', type: 'string', valueName: 'id', desc: 'Auto review model ID' },
31
+ { name: 'context-window', type: 'number', valueName: 'n', desc: 'Context window (optional)' },
32
+ { name: 'yes', alias: 'y', type: 'boolean', desc: 'Skip confirmation' }
33
33
  ];
34
34
 
35
35
  function list() {
@@ -37,15 +37,15 @@ function list() {
37
37
  const providers = config.providers || [];
38
38
  print.blank();
39
39
  if (!providers.length) {
40
- print.hint('还没有供应商。运行 dgxay provider add 或 dgxay config init');
40
+ print.hint('No providers yet. Run dgxay provider add or dgxay config init');
41
41
  print.blank();
42
42
  return 0;
43
43
  }
44
- print.heading(`供应商(${providers.length})`);
44
+ print.heading(`Providers (${providers.length})`);
45
45
  const rows = providers.map((provider, index) => [
46
46
  String(index + 1),
47
- index === 0 ? COLORS.accent('默认') : '',
48
- provider.id === config.activeProviderId ? COLORS.green('当前') : '',
47
+ index === 0 ? COLORS.accent('default') : '',
48
+ provider.id === config.activeProviderId ? COLORS.green('active') : '',
49
49
  provider.name,
50
50
  settings.PROTOCOL_META[provider.protocol || 'openai'].short,
51
51
  provider.baseUrl,
@@ -58,17 +58,17 @@ function list() {
58
58
  { title: '#', max: 3 },
59
59
  { title: '', max: 4 },
60
60
  { title: '', max: 4 },
61
- { title: '名称', max: 16 },
62
- { title: '协议', max: 16 },
61
+ { title: 'Name', max: 16 },
62
+ { title: 'Protocol', max: 16 },
63
63
  { title: 'Base URL', max: 40 },
64
- { title: '模型', max: 30 },
65
- { title: '审查模型', max: 18 },
66
- { title: '认证', max: 16 }
64
+ { title: 'Models', max: 30 },
65
+ { title: 'Review model', max: 18 },
66
+ { title: 'Auth', max: 16 }
67
67
  ],
68
68
  rows
69
69
  );
70
70
  print.blank();
71
- print.hint('供应商顺序有意义:第一个是默认供应商,也是未配置审查模型时的回退来源');
71
+ print.hint('Provider order matters: the first one is the default provider and the fallback source when no review model is configured');
72
72
  print.blank();
73
73
  return 0;
74
74
  }
@@ -84,7 +84,7 @@ async function add(opts) {
84
84
 
85
85
  if (interactive) {
86
86
  if (!opts.protocol) {
87
- const answer = await ask('协议 [1] OpenAI ChatCompletions [2] Anthropic Messages [3] OpenAI Responses : ');
87
+ const answer = await ask('Protocol [1] OpenAI ChatCompletions [2] Anthropic Messages [3] OpenAI Responses : ');
88
88
  const index = Number(String(answer || '').trim()) || 1;
89
89
  protocol = ['openai', 'anthropic', 'responses'][index - 1] || 'openai';
90
90
  }
@@ -93,15 +93,15 @@ async function add(opts) {
93
93
  baseUrl = String(answer || '').trim() || settings.PROTOCOL_META[protocol].basePlaceholder;
94
94
  }
95
95
  if (!name) {
96
- const answer = await ask('供应商名称: ');
96
+ const answer = await ask('Provider name: ');
97
97
  name = String(answer || '').trim();
98
98
  }
99
99
  if (!oauthProvider && apiKey === undefined) {
100
- const secret = await askSecret('API Key(本地模型可留空): ');
100
+ const secret = await askSecret('API Key (may be empty for local models): ');
101
101
  apiKey = secret === null ? undefined : secret;
102
102
  }
103
103
  if (!models.length) {
104
- const answer = await ask('模型 ID(多个用逗号分隔): ');
104
+ const answer = await ask('Model ID (separate multiple with commas): ');
105
105
  models = String(answer || '')
106
106
  .split(/[,,\s]+/)
107
107
  .filter(Boolean);
@@ -118,14 +118,14 @@ async function add(opts) {
118
118
  oauthProvider,
119
119
  reviewModelId: opts.reviewModelId
120
120
  });
121
- print.ok(`已添加供应商「${result.provider.name}」(${result.provider.id})`);
121
+ print.ok(`Provider added: ${result.provider.name} (${result.provider.id})`);
122
122
  return 0;
123
123
  }
124
124
 
125
125
  function edit(ref, opts) {
126
126
  const provider = settings.findProvider(ref);
127
127
  if (!provider) {
128
- print.fail(`找不到供应商:${ref}`);
128
+ print.fail(`Provider not found: ${ref}`);
129
129
  return 1;
130
130
  }
131
131
  const result = settings.upsertProvider({
@@ -139,28 +139,28 @@ function edit(ref, opts) {
139
139
  oauthProvider: opts.oauthProvider,
140
140
  reviewModelId: opts.reviewModelId
141
141
  });
142
- print.ok(`已更新供应商「${result.provider.name}」`);
142
+ print.ok(`Provider updated: ${result.provider.name}`);
143
143
  return 0;
144
144
  }
145
145
 
146
146
  async function remove(ref, opts) {
147
147
  const provider = settings.findProvider(ref);
148
148
  if (!provider) {
149
- print.fail(`找不到供应商:${ref}`);
149
+ print.fail(`Provider not found: ${ref}`);
150
150
  return 1;
151
151
  }
152
152
  if (!opts.yes && process.stdin.isTTY) {
153
- const ok = await confirm(`删除供应商「${provider.name}」及其密钥?`, false);
153
+ const ok = await confirm(`Delete provider "${provider.name}" and its API key?`, false);
154
154
  if (!ok) {
155
- print.hint('已取消');
155
+ print.hint('Cancelled');
156
156
  return 1;
157
157
  }
158
158
  }
159
159
  const config = settings.removeProvider(provider.id);
160
- print.ok(`已删除「${provider.name}」`);
161
- if (!config.providers?.length) print.hint('已经没有供应商了,运行 dgxay config init 重新配置');
160
+ print.ok(`Deleted "${provider.name}"`);
161
+ if (!config.providers?.length) print.hint('No providers left; run dgxay config init to reconfigure');
162
162
  else if (config.activeProviderId !== settings.readConfig().activeProviderId) {
163
- print.hint(`当前供应商已切换为「${(config.providers || []).find((p) => p.id === config.activeProviderId)?.name || '未知'}」`);
163
+ print.hint(`Active provider switched to "${(config.providers || []).find((p) => p.id === config.activeProviderId)?.name || 'unknown'}"`);
164
164
  }
165
165
  return 0;
166
166
  }
@@ -168,36 +168,36 @@ async function remove(ref, opts) {
168
168
  function use(ref) {
169
169
  const provider = settings.findProvider(ref);
170
170
  if (!provider) {
171
- print.fail(`找不到供应商:${ref}`);
171
+ print.fail(`Provider not found: ${ref}`);
172
172
  return 1;
173
173
  }
174
174
  const model = provider.models?.[0];
175
175
  if (!model) {
176
- print.fail(`供应商 ${provider.name} 没有模型`);
176
+ print.fail(`Provider ${provider.name} has no models`);
177
177
  return 1;
178
178
  }
179
179
  settings.saveConfig({ activeProviderId: provider.id, activeModelId: model.id });
180
- print.ok(`当前供应商:${provider.name} / ${model.name || model.id}`);
180
+ print.ok(`Active provider: ${provider.name} / ${model.name || model.id}`);
181
181
  return 0;
182
182
  }
183
183
 
184
184
  function review(ref, opts) {
185
185
  const provider = settings.findProvider(ref);
186
186
  if (!provider) {
187
- print.fail(`找不到供应商:${ref}`);
187
+ print.fail(`Provider not found: ${ref}`);
188
188
  return 1;
189
189
  }
190
190
  if (opts.reviewModel === undefined) {
191
191
  const model = (provider.models || []).find((m) => m.id === provider.reviewModelId);
192
- if (model) print.write(`${provider.name} 的审查模型:${model.name || model.id}(${model.id})`);
193
- else print.write(`${provider.name} 未配置审查模型,自动审查时会回退到默认供应商`);
192
+ if (model) print.write(`Review model for ${provider.name}: ${model.name || model.id} (${model.id})`);
193
+ else print.write(`${provider.name} has no review model configured; auto review falls back to the default provider`);
194
194
  return 0;
195
195
  }
196
196
  const models = provider.models || [];
197
197
  const target = models.find((m) => m.id === opts.reviewModel);
198
198
  if (opts.reviewModel && !target) {
199
- print.fail(`供应商 ${provider.name} 下没有模型 ${opts.reviewModel}`);
200
- print.hint(`可用:${models.map((m) => m.id).join(', ')}`);
199
+ print.fail(`Provider ${provider.name} has no model ${opts.reviewModel}`);
200
+ print.hint(`Available: ${models.map((m) => m.id).join(', ')}`);
201
201
  return 1;
202
202
  }
203
203
  const next = (settings.readConfig().providers || []).map((p) =>
@@ -205,10 +205,10 @@ function review(ref, opts) {
205
205
  );
206
206
  settings.saveConfig({ providers: next });
207
207
  if (target) {
208
- print.ok(`${provider.name} 的自动审查模型:${target.name || target.id}`);
209
- print.hint('现在可以在 /permission 中选择「自动审查」');
208
+ print.ok(`Auto review model for ${provider.name}: ${target.name || target.id}`);
209
+ print.hint('You can now select "Auto review" in /permission');
210
210
  } else {
211
- print.ok(`已清除 ${provider.name} 的审查模型`);
211
+ print.ok(`Cleared the review model for ${provider.name}`);
212
212
  }
213
213
  return 0;
214
214
  }
@@ -216,37 +216,37 @@ function review(ref, opts) {
216
216
  function move(ref, direction) {
217
217
  const dir = direction === 'up' || direction === 'u' || direction === '-1' ? -1 : 1;
218
218
  settings.moveProvider(ref, dir);
219
- print.ok(`已${dir < 0 ? '上移' : '下移'}「${settings.findProvider(ref)?.name || ref}」`);
219
+ print.ok(`${dir < 0 ? 'Moved up' : 'Moved down'} "${settings.findProvider(ref)?.name || ref}"`);
220
220
  return list();
221
221
  }
222
222
 
223
223
  function oauthAccounts() {
224
224
  const list = oauth.listProviders();
225
225
  print.blank();
226
- print.heading('OAuth 账户');
226
+ print.heading('OAuth accounts');
227
227
  const rows = list.map((item) => [
228
228
  item.name,
229
229
  item.subtitle,
230
230
  item.connection && !item.connection.expired
231
- ? COLORS.green('已连接')
231
+ ? COLORS.green('connected')
232
232
  : item.connection?.expired
233
- ? COLORS.yellow('已过期')
234
- : '未连接',
233
+ ? COLORS.yellow('expired')
234
+ : 'not connected',
235
235
  item.connection?.account || '',
236
- item.redirectMode === 'manual' ? '手动授权码' : '系统浏览器'
236
+ item.redirectMode === 'manual' ? 'manual auth code' : 'system browser'
237
237
  ]);
238
238
  print.table(
239
239
  [
240
- { title: '平台', max: 12 },
241
- { title: '账户类型', max: 24 },
242
- { title: '状态', max: 8 },
243
- { title: '账号', max: 30 },
244
- { title: '授权方式', max: 12 }
240
+ { title: 'Platform', max: 12 },
241
+ { title: 'Account type', max: 24 },
242
+ { title: 'Status', max: 8 },
243
+ { title: 'Account', max: 30 },
244
+ { title: 'Auth method', max: 12 }
245
245
  ],
246
246
  rows
247
247
  );
248
248
  print.blank();
249
- print.hint('dgxay oauth connect <平台> 连接账户;连接后可用 dgxay provider add --oauth-provider <平台>');
249
+ print.hint('dgxay oauth connect <platform> to connect an account; then use dgxay provider add --oauth-provider <platform>');
250
250
  print.blank();
251
251
  return 0;
252
252
  }
@@ -263,33 +263,33 @@ async function run({ argv }) {
263
263
  return add(opts);
264
264
  case 'edit':
265
265
  case 'set': {
266
- if (!rest[0]) throw Object.assign(new Error('用法:dgxay provider edit <名称> [选项]'), { userError: true });
266
+ if (!rest[0]) throw Object.assign(new Error('Usage: dgxay provider edit <name> [options]'), { userError: true });
267
267
  return edit(rest[0], opts);
268
268
  }
269
269
  case 'rm':
270
270
  case 'remove':
271
271
  case 'delete': {
272
- if (!rest[0]) throw Object.assign(new Error('用法:dgxay provider rm <名称>'), { userError: true });
272
+ if (!rest[0]) throw Object.assign(new Error('Usage: dgxay provider rm <name>'), { userError: true });
273
273
  return remove(rest[0], opts);
274
274
  }
275
275
  case 'use': {
276
- if (!rest[0]) throw Object.assign(new Error('用法:dgxay provider use <名称>'), { userError: true });
276
+ if (!rest[0]) throw Object.assign(new Error('Usage: dgxay provider use <name>'), { userError: true });
277
277
  return use(rest[0]);
278
278
  }
279
279
  case 'mv':
280
280
  case 'move': {
281
- if (!rest[0]) throw Object.assign(new Error('用法:dgxay provider mv <名称> up|down'), { userError: true });
281
+ if (!rest[0]) throw Object.assign(new Error('Usage: dgxay provider mv <name> up|down'), { userError: true });
282
282
  return move(rest[0], rest[1] || 'down');
283
283
  }
284
284
  case 'review': {
285
285
  if (!rest[0]) {
286
286
  const config = settings.readConfig();
287
- const rows = (config.providers || []).map((p) => [p.name, p.reviewModelId || '(未配置)']);
287
+ const rows = (config.providers || []).map((p) => [p.name, p.reviewModelId || '(not configured)']);
288
288
  print.blank();
289
289
  print.table(
290
290
  [
291
- { title: '供应商', max: 20 },
292
- { title: '审查模型', max: 30 }
291
+ { title: 'Provider', max: 20 },
292
+ { title: 'Review model', max: 30 }
293
293
  ],
294
294
  rows
295
295
  );
@@ -301,8 +301,8 @@ async function run({ argv }) {
301
301
  case 'oauth':
302
302
  return oauthAccounts();
303
303
  default:
304
- print.fail(`未知子命令:${action}`);
305
- print.hint('可用:list / add / edit / rm / use / mv / review / oauth');
304
+ print.fail(`Unknown subcommand: ${action}`);
305
+ print.hint('Available: list / add / edit / rm / use / mv / review / oauth');
306
306
  return 1;
307
307
  }
308
308
  }
@@ -310,17 +310,17 @@ async function run({ argv }) {
310
310
  module.exports = {
311
311
  name: 'provider',
312
312
  aliases: ['prov'],
313
- summary: '供应商与审查模型管理',
313
+ summary: 'Provider and review model management',
314
314
  usage: 'dgxay provider <list|add|edit|rm|use|mv|review>',
315
315
  options,
316
316
  subcommands: [
317
- ['list', '列出所有供应商'],
318
- ['add', '新增供应商'],
319
- ['edit <名称>', '修改供应商'],
320
- ['rm <名称>', '删除供应商'],
321
- ['use <名称>', '设为当前供应商'],
322
- ['mv <名称> up|down', '调整顺序'],
323
- ['review [名称] [--model id]', '查看 / 设置自动审查模型']
317
+ ['list', 'List all providers'],
318
+ ['add', 'Add a provider'],
319
+ ['edit <name>', 'Edit a provider'],
320
+ ['rm <name>', 'Delete a provider'],
321
+ ['use <name>', 'Set as the active provider'],
322
+ ['mv <name> up|down', 'Reorder providers'],
323
+ ['review [name] [--model id]', 'View / set the auto review model']
324
324
  ],
325
325
  examples: [
326
326
  'dgxay provider list',
@@ -19,30 +19,30 @@ const { StreamRenderer } = require('../cli/render');
19
19
  const { resolveChatArg } = require('./_shared');
20
20
 
21
21
  const options = [
22
- { name: 'prompt', alias: 'p', type: 'string', valueName: 'text', desc: '提示词' },
23
- { name: 'mode', alias: 'm', type: 'string', valueName: 'mode', desc: 'chat / work(默认 chat)' },
22
+ { name: 'prompt', alias: 'p', type: 'string', valueName: 'text', desc: 'Prompt' },
23
+ { name: 'mode', alias: 'm', type: 'string', valueName: 'mode', desc: 'chat / work (default chat)' },
24
24
  { name: 'permission', type: 'string', valueName: 'level', desc: 'none / normal / auto / full' },
25
- { name: 'workspace', alias: 'C', type: 'string', valueName: 'dir', desc: '工作空间目录' },
26
- { name: 'provider', type: 'string', valueName: 'name', desc: '供应商 id 或名称' },
27
- { name: 'model', type: 'string', valueName: 'id', desc: '模型 id' },
28
- { name: 'skill', type: 'string', valueName: 'name', desc: '启用的技能' },
29
- { name: 'resume', alias: 'r', type: 'string', valueName: 'id|index', desc: '在指定会话上继续' },
30
- { name: 'continue', alias: 'c', type: 'boolean', desc: '在最近的会话上继续' },
31
- { name: 'output', alias: 'o', type: 'string', valueName: 'text|json', desc: '输出格式,默认 text' },
32
- { name: 'yes', alias: 'y', type: 'boolean', desc: '自动同意授权请求(危险)' },
33
- { name: 'quiet', alias: 'q', type: 'boolean', desc: '只输出回答正文' }
25
+ { name: 'workspace', alias: 'C', type: 'string', valueName: 'dir', desc: 'Workspace directory' },
26
+ { name: 'provider', type: 'string', valueName: 'name', desc: 'Provider id or name' },
27
+ { name: 'model', type: 'string', valueName: 'id', desc: 'Model id' },
28
+ { name: 'skill', type: 'string', valueName: 'name', desc: 'Skill to enable' },
29
+ { name: 'resume', alias: 'r', type: 'string', valueName: 'id|index', desc: 'Continue a conversation by index or id' },
30
+ { name: 'continue', alias: 'c', type: 'boolean', desc: 'Continue the most recent conversation' },
31
+ { name: 'output', alias: 'o', type: 'string', valueName: 'text|json', desc: 'Output format, default text' },
32
+ { name: 'yes', alias: 'y', type: 'boolean', desc: 'Auto-approve permission requests (dangerous)' },
33
+ { name: 'quiet', alias: 'q', type: 'boolean', desc: 'Only print the reply text' }
34
34
  ];
35
35
 
36
36
  async function run({ argv, globalOptions, runtime }) {
37
37
  const { options: opts, positionals } = parseArgs(argv, options);
38
38
  const prompt = String(opts.prompt || positionals.join(' ') || runtime.prompt || '').trim();
39
39
  if (!prompt) {
40
- throw Object.assign(new Error('缺少提示词:请使用 -p "..." 或直接跟问题'), { userError: true });
40
+ throw Object.assign(new Error('Missing prompt: use -p "..." or pass the question directly'), { userError: true });
41
41
  }
42
42
 
43
43
  const config = settings.readConfig();
44
44
  if (!config.providers?.length) {
45
- throw Object.assign(new Error('尚未配置供应商,请先运行 dgxay config init'), { userError: true });
45
+ throw Object.assign(new Error('No provider configured. Run dgxay config init first'), { userError: true });
46
46
  }
47
47
 
48
48
  const mode = String(opts.mode || runtime.mode || 'chat') === 'work' ? 'work' : 'chat';
@@ -148,11 +148,11 @@ function persistChat({ chat, prompt, mode, permission, result, history }) {
148
148
  files: result.files,
149
149
  usage: result.usage || null
150
150
  });
151
- if (!target.title || target.title === '新对话') target.title = sessions.titleFrom(prompt);
151
+ if (!target.title || target.title === 'New conversation') target.title = sessions.titleFrom(prompt);
152
152
  sessions.saveChat(target);
153
153
  return target;
154
154
  } catch (err) {
155
- if (process.env.DGXAY_DEBUG === '1') process.stderr.write(`[session] 保存失败:${err.message}\n`);
155
+ if (process.env.DGXAY_DEBUG === '1') process.stderr.write(`[session] save failed: ${err.message}\n`);
156
156
  return null;
157
157
  }
158
158
  }
@@ -160,13 +160,13 @@ function persistChat({ chat, prompt, mode, permission, result, history }) {
160
160
  module.exports = {
161
161
  name: 'run',
162
162
  aliases: [],
163
- summary: '单次执行:把提示词发给模型并输出结果',
164
- usage: 'dgxay run -p "提示词" [-C 目录] [-m work] [--permission auto]',
163
+ summary: 'One-shot: send a prompt and print the reply',
164
+ usage: 'dgxay run -p "prompt" [-C dir] [-m work] [--permission auto]',
165
165
  options,
166
166
  examples: [
167
- 'dgxay run -p "解释这个仓库的目录结构" -C .',
168
- 'dgxay run -p "给 README 补充安装说明" -m work -C ./project --permission normal',
169
- 'dgxay run -p "写一个快排函数" -o json'
167
+ 'dgxay run -p "explain the structure of this repo" -C .',
168
+ 'dgxay run -p "add install notes to the README" -m work -C ./project',
169
+ 'dgxay run -p "write a quicksort function" -o json'
170
170
  ],
171
171
  run
172
172
  };
@@ -16,7 +16,7 @@ const skills = require('../services/skills');
16
16
  const cfg = require('../services/config');
17
17
  const settings = require('../services/settings');
18
18
 
19
- const options = [{ name: 'json', type: 'boolean', desc: '输出 JSON' }];
19
+ const options = [{ name: 'json', type: 'boolean', desc: 'Output JSON' }];
20
20
 
21
21
  async function run({ argv }) {
22
22
  const { action: rawAction, rest, options: opts } = actionFirst(argv, options);
@@ -34,9 +34,9 @@ async function run({ argv }) {
34
34
  return 0;
35
35
  }
36
36
  print.blank();
37
- print.heading(`技能(${settings.homeRelative(cfg.SKILLS_DIR)})`);
37
+ print.heading(`Skills (${settings.homeRelative(cfg.SKILLS_DIR)})`);
38
38
  if (!list.length) {
39
- print.hint(' 还没有技能。放一个 name.md 或 <目录>/SKILL.md 到技能目录即可。');
39
+ print.hint(' No skills yet. Drop a name.md or <dir>/SKILL.md into the skills directory.');
40
40
  print.blank();
41
41
  return 0;
42
42
  }
@@ -44,24 +44,24 @@ async function run({ argv }) {
44
44
  print.table(
45
45
  [
46
46
  { title: '#', max: 3 },
47
- { title: '名称', max: 24 },
48
- { title: '描述', max: 60 },
49
- { title: '文件', max: 24 }
47
+ { title: 'Name', max: 24 },
48
+ { title: 'Description', max: 60 },
49
+ { title: 'File', max: 24 }
50
50
  ],
51
51
  rows
52
52
  );
53
53
  print.blank();
54
- print.hint('在对话中使用 /skill <名称> 启用;单次运行可加 --skill <名称>');
54
+ print.hint('Enable with /skill <name> in a conversation; for a single run add --skill <name>');
55
55
  print.blank();
56
56
  return 0;
57
57
  }
58
58
 
59
59
  if (action === 'show' || action === 'cat') {
60
60
  const name = rest[0];
61
- if (!name) throw Object.assign(new Error('用法:dgxay skill show <名称>'), { userError: true });
61
+ if (!name) throw Object.assign(new Error('Usage: dgxay skill show <name>'), { userError: true });
62
62
  const skill = skills.readSkill(name);
63
63
  if (!skill) {
64
- print.fail(`找不到技能:${name}`);
64
+ print.fail(`Skill not found: ${name}`);
65
65
  return 1;
66
66
  }
67
67
  print.blank();
@@ -73,21 +73,21 @@ async function run({ argv }) {
73
73
  return 0;
74
74
  }
75
75
 
76
- print.fail(`未知子命令:${action}`);
77
- print.hint('可用:list / show / path');
76
+ print.fail(`Unknown command: ${action}`);
77
+ print.hint('Available: list / show / path');
78
78
  return 1;
79
79
  }
80
80
 
81
81
  module.exports = {
82
82
  name: 'skill',
83
83
  aliases: ['skills'],
84
- summary: '技能列表与查看',
84
+ summary: 'List and view skills',
85
85
  usage: 'dgxay skill <list|show|path>',
86
86
  options,
87
87
  subcommands: [
88
- ['list', '列出技能'],
89
- ['show <名称>', '查看技能正文'],
90
- ['path', '显示技能目录']
88
+ ['list', 'List skills'],
89
+ ['show <name>', 'View skill content'],
90
+ ['path', 'Show the skills directory']
91
91
  ],
92
92
  examples: ['dgxay skill list', 'dgxay skill show review', 'dgxay skill path'],
93
93
  run
@@ -16,7 +16,7 @@ const { parseArgs, actionFirst } = require('../cli/args');
16
16
  const { COLORS } = require('../cli/ansi');
17
17
  const settings = require('../services/settings');
18
18
 
19
- const options = [{ name: 'both', alias: 'b', type: 'boolean', desc: '同时写入配置(默认只设当前进程)' }];
19
+ const options = [{ name: 'both', alias: 'b', type: 'boolean', desc: 'Also persist to config (default only sets the current process)' }];
20
20
 
21
21
  async function run({ argv }) {
22
22
  const { action, rest, options: opts } = actionFirst(argv, options);
@@ -26,12 +26,12 @@ async function run({ argv }) {
26
26
  const workspace = config.work?.workspace || process.cwd();
27
27
  print.blank();
28
28
  print.keyValue([
29
- { label: '当前工作空间', value: workspace },
30
- { label: '进程目录', value: process.cwd() },
31
- { label: '最近使用', value: (config.work?.recentWorkspaces || []).slice(0, 5).join('\n') || '(无)', multiline: true }
29
+ { label: 'Current workspace', value: workspace },
30
+ { label: 'Process directory', value: process.cwd() },
31
+ { label: 'Recent', value: (config.work?.recentWorkspaces || []).slice(0, 5).join('\n') || '(none)', multiline: true }
32
32
  ]);
33
33
  print.blank();
34
- print.hint('dgxay workspace set <目录> 设置;对话中可用 /cd');
34
+ print.hint('Set it with dgxay workspace set <dir>; inside a conversation use /cd');
35
35
  print.blank();
36
36
  return 0;
37
37
  }
@@ -40,11 +40,11 @@ async function run({ argv }) {
40
40
  const recents = config.work?.recentWorkspaces || [];
41
41
  print.blank();
42
42
  if (!recents.length) {
43
- print.hint('还没有设置过工作空间');
43
+ print.hint('No workspace has been set yet');
44
44
  print.blank();
45
45
  return 0;
46
46
  }
47
- print.heading('最近使用的工作空间');
47
+ print.heading('Recent workspaces');
48
48
  recents.forEach((item, index) => {
49
49
  const exists = fs.existsSync(item) ? COLORS.green('✓') : COLORS.red('✗');
50
50
  print.write(` ${status(index + 1)} ${exists} ${item}`);
@@ -55,23 +55,23 @@ async function run({ argv }) {
55
55
 
56
56
  if (action === 'set' || action === 'use' || action === 'cd') {
57
57
  const target = rest[0] || '';
58
- if (!target) throw Object.assign(new Error('用法:dgxay workspace set <目录>'), { userError: true });
58
+ if (!target) throw Object.assign(new Error('Usage: dgxay workspace set <dir>'), { userError: true });
59
59
  const resolved = path.resolve(target);
60
60
  try {
61
- if (!fs.statSync(resolved).isDirectory()) throw new Error('不是文件夹');
61
+ if (!fs.statSync(resolved).isDirectory()) throw new Error('Not a directory');
62
62
  } catch {
63
- print.fail(`目录不存在:${resolved}`);
63
+ print.fail(`Directory not found: ${resolved}`);
64
64
  return 1;
65
65
  }
66
66
  settings.setWorkspace(resolved);
67
- print.ok(`工作空间:${resolved}`);
67
+ print.ok(`Workspace: ${resolved}`);
68
68
  void opts;
69
69
  return 0;
70
70
  }
71
71
 
72
72
  if (action === 'clear' || action === 'unset') {
73
73
  settings.setWorkspace('');
74
- print.ok('已清除工作空间');
74
+ print.ok('Workspace cleared');
75
75
  return 0;
76
76
  }
77
77
 
@@ -86,14 +86,14 @@ function status(index) {
86
86
  module.exports = {
87
87
  name: 'workspace',
88
88
  aliases: ['ws'],
89
- summary: '工作空间管理',
90
- usage: 'dgxay workspace [set|list|clear] [目录]',
89
+ summary: 'Workspace management',
90
+ usage: 'dgxay workspace [set|list|clear] [dir]',
91
91
  options,
92
92
  subcommands: [
93
- ['show', '显示当前工作空间'],
94
- ['set <目录>', '设置工作空间'],
95
- ['list', '查看最近使用'],
96
- ['clear', '清除']
93
+ ['show', 'Show current workspace'],
94
+ ['set <dir>', 'Set the workspace'],
95
+ ['list', 'Show recent workspaces'],
96
+ ['clear', 'Clear']
97
97
  ],
98
98
  examples: ['dgxay workspace set ./project', 'dgxay workspace list'],
99
99
  run