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.
@@ -0,0 +1,276 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * 界面文案:默认英文,可用 DGXAY_LANG=zh 切回中文。
5
+ *
6
+ * 只负责「界面」文字;AI 回复语言由系统提示决定(见 core/prompt.js)。
7
+ */
8
+
9
+ const EN = {
10
+ // 启动 / 横幅
11
+ tagline: 'multi-protocol AI coding assistant',
12
+ hint_start: 'Type / for commands · ! for shell · ↑ history · Ctrl+C to interrupt · Ctrl+D to exit',
13
+
14
+ // 状态行
15
+ status_model: 'model',
16
+ status_workspace: 'workspace',
17
+ status_permission: 'permission',
18
+ status_mode: 'mode',
19
+ mode_chat: 'chat',
20
+ mode_work: 'work',
21
+
22
+ // 权限
23
+ perm_none: 'no permission',
24
+ perm_normal: 'normal',
25
+ perm_auto: 'auto review',
26
+ perm_full: 'full access',
27
+
28
+ // 对话
29
+ you: 'You',
30
+ assistant: 'DgxayCode',
31
+ thinking: 'Thinking',
32
+ thought_for: 'Thought for',
33
+ thinking_now: 'Thinking…',
34
+ tokens: 'tokens',
35
+ in_out: 'in /',
36
+ out: 'out',
37
+ no_content: '(the model returned nothing)',
38
+ generation_error: 'Error',
39
+ stopped: 'Stopped',
40
+ interrupted: 'Interrupting…',
41
+ waiting_confirm: 'waiting for your confirmation',
42
+ reviewing: 'auto-reviewing',
43
+ review_allow: 'auto-review allowed',
44
+ review_suspect: 'auto-review flagged this, asking you',
45
+ empty_input: 'Nothing to send',
46
+
47
+ // 授权
48
+ approval_title: 'Permission required',
49
+ approval_tool: 'AI wants to run a tool',
50
+ approval_terminal: 'AI wants to run a shell command',
51
+ approval_op: 'operation',
52
+ approval_ask: 'Allow this?',
53
+ approval_yes: '[y] yes',
54
+ approval_no: '[n] no',
55
+ approval_allowed: 'allowed',
56
+ approval_denied: 'denied',
57
+ approval_timeout: 'timed out',
58
+ approval_noninteractive: 'not an interactive terminal, denied automatically',
59
+
60
+ // 输入框
61
+ box_placeholder: 'Ask anything…',
62
+ box_hint: 'Enter to send · \\ to continue · Tab to complete · ↑ history',
63
+
64
+ // 斜杠命令菜单
65
+ menu_title: 'Commands',
66
+ menu_hint: '↑↓ select · Tab complete · Enter run · Esc close',
67
+
68
+ // 文件 / 工具
69
+ tool_list: 'List',
70
+ tool_read: 'Read',
71
+ tool_write: 'Write',
72
+ tool_mkdir: 'Create dir',
73
+ tool_delete: 'Delete',
74
+ tool_command: 'Run',
75
+ tool_fetch: 'Fetch',
76
+ tool_mcp: 'Install MCP',
77
+ file_created: 'created',
78
+ file_updated: 'updated',
79
+ file_deleted: 'deleted',
80
+ chars: 'chars',
81
+ lines: 'lines',
82
+ items: 'items',
83
+ exit_code: 'exit code',
84
+ no_output: 'no output',
85
+
86
+ // 斜杠命令输出
87
+ cmd_unknown: 'Unknown command',
88
+ cmd_help_hint: 'Type /help to list all commands',
89
+ new_chat: 'Started a new conversation',
90
+ restored: 'Restored',
91
+ messages: 'messages',
92
+ deleted: 'Deleted',
93
+ renamed: 'Renamed to',
94
+ no_chats: 'No saved conversations yet',
95
+ compressed: 'Context compressed',
96
+ compress_failed: 'Compression failed',
97
+ compress_running: 'Compressing context…',
98
+ compress_nothing: 'Nothing to compress in this conversation',
99
+ wait_current: 'Please wait for the current reply to finish',
100
+ no_model: 'No model configured. Run dgxay config init',
101
+ model_switched: 'Switched to',
102
+ provider_switched: 'Switched to',
103
+ skill_enabled: 'Skill enabled for this conversation',
104
+ skill_none: 'No skills installed. Put a name.md or <dir>/SKILL.md into ~/.dcb/skills',
105
+ skill_not_found: 'Skill not found',
106
+ skills_off: 'Skill disabled',
107
+ perms_title: 'Permissions',
108
+ perm_set: 'Permission set to',
109
+ perm_auto_unavailable: 'Auto review unavailable: no review model configured',
110
+ perm_full_warning: 'Full access lets the AI run any command and write any file without asking',
111
+ mode_set: 'Mode set to',
112
+ workspace_set: 'Workspace',
113
+ dir_not_found: 'Directory not found',
114
+ not_a_dir: 'Not a directory',
115
+ no_workspace: 'no workspace selected',
116
+ context_title: 'Context',
117
+ used: 'used',
118
+ remaining: 'remaining',
119
+ context_note: 'Estimated from character count; real usage is reported by the model.',
120
+ mcp_title: 'MCP servers',
121
+ mcp_none: 'No MCP servers. Add one with dgxay mcp add',
122
+ mcp_unknown: 'Unknown /mcp action',
123
+ bye: 'Bye. Run dgxay -c to continue the last conversation.',
124
+ cancelled: 'Cancelled',
125
+ session_not_found: 'Conversation not found',
126
+ delete_confirm: 'Delete this conversation?',
127
+ terminal_running: 'A command is already running',
128
+ command_empty: 'Enter a command first',
129
+ perm_denied_terminal: 'No permission to run shell commands',
130
+ model_list_title: 'Models',
131
+ provider_list_title: 'Providers',
132
+ current: 'current',
133
+
134
+ // 键盘提示
135
+ key_hint_and: 'and',
136
+
137
+
138
+ // 错误
139
+ err_title: 'Error',
140
+ err_network: 'Network error',
141
+ err_unauthorized: 'Unauthorized: check your API key or reconnect the account'
142
+ };
143
+
144
+ const ZH = {
145
+ tagline: '多协议 AI 编码助手',
146
+ hint_start: '输入 / 查看命令 · ! 执行终端 · ↑ 历史 · Ctrl+C 中断 · Ctrl+D 退出',
147
+ status_model: '模型',
148
+ status_workspace: '工作空间',
149
+ status_permission: '权限',
150
+ status_mode: '模式',
151
+ mode_chat: '对话',
152
+ mode_work: '工作',
153
+ perm_none: '无权限',
154
+ perm_normal: '普通权限',
155
+ perm_auto: '自动审查',
156
+ perm_full: '完全权限',
157
+ you: '你',
158
+ assistant: 'DgxayCode',
159
+ thinking: '思考',
160
+ thought_for: '已思考',
161
+ thinking_now: '思考中…',
162
+ tokens: 'tokens',
163
+ in_out: 'in /',
164
+ out: 'out',
165
+ no_content: '(模型没有返回内容)',
166
+ generation_error: '出错了',
167
+ stopped: '已停止',
168
+ interrupted: '正在中断…',
169
+ waiting_confirm: '等待确认',
170
+ reviewing: '正在自动审查',
171
+ review_allow: '自动审查放行',
172
+ review_suspect: '自动审查判定可疑,转交确认',
173
+ empty_input: '没有可发送的内容',
174
+ approval_title: '需要授权',
175
+ approval_tool: 'AI 请求执行操作',
176
+ approval_terminal: 'AI 请求执行终端命令',
177
+ approval_op: '操作',
178
+ approval_ask: '允许执行吗?',
179
+ approval_yes: '[y] 允许',
180
+ approval_no: '[n] 拒绝',
181
+ approval_allowed: '允许',
182
+ approval_denied: '已拒绝',
183
+ approval_timeout: '等待超时,已拒绝',
184
+ approval_noninteractive: '当前不是交互终端,已自动拒绝',
185
+ box_placeholder: '问点什么…',
186
+ box_hint: 'Enter 发送 · \\ 续行 · Tab 补全 · ↑ 历史',
187
+ menu_title: '斜杠命令',
188
+ menu_hint: '↑↓ 选择 · Tab 补全 · Enter 执行 · Esc 关闭',
189
+ tool_list: '列出目录',
190
+ tool_read: '读取文件',
191
+ tool_write: '写入文件',
192
+ tool_mkdir: '创建目录',
193
+ tool_delete: '删除',
194
+ tool_command: '执行命令',
195
+ tool_fetch: '访问网络',
196
+ tool_mcp: '安装 MCP',
197
+ file_created: '创建',
198
+ file_updated: '更新',
199
+ file_deleted: '删除',
200
+ chars: '字符',
201
+ lines: '行',
202
+ items: '项',
203
+ exit_code: '退出码',
204
+ no_output: '无输出',
205
+ cmd_unknown: '未知命令',
206
+ cmd_help_hint: '输入 /help 查看全部命令',
207
+ new_chat: '已开始新对话',
208
+ restored: '已恢复',
209
+ messages: '条消息',
210
+ deleted: '已删除',
211
+ renamed: '已重命名为',
212
+ no_chats: '还没有历史对话',
213
+ compressed: '上下文已压缩',
214
+ compress_failed: '压缩失败',
215
+ compress_running: '正在压缩上下文…',
216
+ compress_nothing: '当前对话还没有可压缩的内容',
217
+ wait_current: '请等待当前回复结束',
218
+ no_model: '还没有可用模型,运行 dgxay config init',
219
+ model_switched: '已切换到',
220
+ provider_switched: '已切换到',
221
+ skill_enabled: '已在本次对话启用技能',
222
+ skill_none: '还没有安装技能。把 name.md 或 <目录>/SKILL.md 放到 ~/.dcb/skills',
223
+ skill_not_found: '未找到该技能',
224
+ skills_off: '已关闭技能',
225
+ perms_title: '权限',
226
+ perm_set: '权限已切换为',
227
+ perm_auto_unavailable: '自动审查不可用:尚未配置审查模型',
228
+ perm_full_warning: '完全权限下 AI 可以执行任意命令、读写任意文件,且不会询问',
229
+ mode_set: '模式已切换为',
230
+ workspace_set: '工作空间',
231
+ dir_not_found: '目录不存在',
232
+ not_a_dir: '不是文件夹',
233
+ no_workspace: '未选择工作空间',
234
+ context_title: '上下文',
235
+ used: '已用',
236
+ remaining: '剩余',
237
+ context_note: '按字符启发式估算,实际 token 以模型 usage 为准。',
238
+ mcp_title: 'MCP Server',
239
+ mcp_none: '还没有 MCP Server,用 dgxay mcp add 添加',
240
+ mcp_unknown: '未知的 /mcp 子命令',
241
+ bye: '再见。用 dgxay -c 继续上一次对话。',
242
+ cancelled: '已取消',
243
+ session_not_found: '找不到会话',
244
+ delete_confirm: '删除这段对话?',
245
+ terminal_running: '已有命令正在执行',
246
+ command_empty: '请输入要执行的终端命令',
247
+ perm_denied_terminal: '无权限模式禁止执行终端命令',
248
+ model_list_title: '模型',
249
+ provider_list_title: '供应商',
250
+ current: '当前',
251
+ key_hint_and: '与',
252
+ err_title: '出错了',
253
+ err_network: '网络错误',
254
+ err_unauthorized: '未授权:检查 API Key 或重新连接账户'
255
+ };
256
+
257
+ const LANG = String(process.env.DGXAY_LANG || process.env.DGXAY_LANGUAGE || 'en').toLowerCase();
258
+ const TABLE = LANG.startsWith('zh') || LANG === 'cn' ? ZH : EN;
259
+
260
+ const LANGUAGES = { en: EN, zh: ZH };
261
+
262
+ /** 取文案;缺失时回退英文,再回退 key 本身(避免界面出现 undefined) */
263
+ function t(key, ...args) {
264
+ const table = TABLE[key] !== undefined ? TABLE : EN;
265
+ const raw = table[key] !== undefined ? table[key] : key;
266
+ return String(raw).replace(/\{(\d+)\}/g, (m, index) => {
267
+ const value = args[Number(index)];
268
+ return value === undefined ? m : String(value);
269
+ });
270
+ }
271
+
272
+ function lang() {
273
+ return TABLE === ZH ? 'zh' : 'en';
274
+ }
275
+
276
+ module.exports = { t, lang, LANGUAGES, EN, ZH };
package/src/cli/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  /**
4
- * CLI 调度入口:全局选项 → 子命令分发 → 无参数时进入交互模式。
4
+ * CLI 调度入口:全局选项 → 子命令分发 → 无参数时Start the interactive shell。
5
5
  */
6
6
 
7
7
  const { COLORS } = require('./ansi');
@@ -11,23 +11,23 @@ const print = require('./print');
11
11
  const { VERSION, BIN } = require('../services/version');
12
12
 
13
13
  const GLOBAL_OPTIONS = [
14
- { name: 'help', alias: 'h', type: 'boolean', desc: '显示帮助' },
15
- { name: 'version', alias: 'v', type: 'boolean', desc: '显示版本号' },
16
- { name: 'home', type: 'string', valueName: 'dir', desc: '覆盖数据目录(默认 ~/.dcb,也可用 DGXAY_HOME)' },
17
- { name: 'debug', type: 'boolean', desc: '输出调试信息与堆栈' },
18
- { name: 'no-color', type: 'boolean', desc: '关闭彩色输出(等同 NO_COLOR=1)' },
19
- { name: 'print', alias: 'p', type: 'boolean', desc: '单次运行:发送提示词后输出结果并退出' },
20
- { name: 'prompt', type: 'string', valueName: 'text', desc: '单次运行的提示词' },
21
- { name: 'output', alias: 'o', type: 'string', valueName: 'format', desc: '输出格式:text / json(配合 --print)' },
22
- { name: 'mode', alias: 'm', type: 'string', valueName: 'mode', desc: '模式:chat / work' },
23
- { name: 'permission', type: 'string', valueName: 'level', desc: '权限:none / normal / auto / full' },
24
- { name: 'workspace', alias: 'C', type: 'string', valueName: 'dir', desc: '工作空间目录' },
25
- { name: 'model', type: 'string', valueName: 'id', desc: '指定模型' },
26
- { name: 'provider', type: 'string', valueName: 'name', desc: '指定供应商' },
27
- { name: 'skill', type: 'string', valueName: 'name', desc: '本次运行启用的技能' },
28
- { name: 'resume', alias: 'r', type: 'string', valueName: 'id|index', desc: '恢复指定会话' },
29
- { name: 'continue', alias: 'c', type: 'boolean', desc: '恢复最近一次会话' },
30
- { name: 'yes', alias: 'y', type: 'boolean', desc: '自动同意所有授权请求(仅单次运行,慎用)' }
14
+ { name: 'help', alias: 'h', type: 'boolean', desc: 'Show help' },
15
+ { name: 'version', alias: 'v', type: 'boolean', desc: 'Show version' },
16
+ { name: 'home', type: 'string', valueName: 'dir', desc: 'Override the data directory (default ~/.dcb)' },
17
+ { name: 'debug', type: 'boolean', desc: 'Print debug information and stack traces' },
18
+ { name: 'no-color', type: 'boolean', desc: 'Disable colors (same as NO_COLOR=1)' },
19
+ { name: 'print', alias: 'p', type: 'boolean', desc: 'One-shot: send a prompt, print the reply, exit' },
20
+ { name: 'prompt', type: 'string', valueName: 'text', desc: 'Prompt for the one-shot run' },
21
+ { name: 'output', alias: 'o', type: 'string', valueName: 'format', desc: 'Output format: text / json' },
22
+ { name: 'mode', alias: 'm', type: 'string', valueName: 'mode', desc: 'Mode: chat / work' },
23
+ { name: 'permission', type: 'string', valueName: 'level', desc: 'Permission: none / normal / auto / full' },
24
+ { name: 'workspace', alias: 'C', type: 'string', valueName: 'dir', desc: 'Workspace directory' },
25
+ { name: 'model', type: 'string', valueName: 'id', desc: 'Model id' },
26
+ { name: 'provider', type: 'string', valueName: 'name', desc: 'Provider id or name' },
27
+ { name: 'skill', type: 'string', valueName: 'name', desc: 'Skill to enable for this run' },
28
+ { name: 'resume', alias: 'r', type: 'string', valueName: 'id|index', desc: 'Resume a conversation by index or id' },
29
+ { name: 'continue', alias: 'c', type: 'boolean', desc: 'Resume the most recent conversation' },
30
+ { name: 'yes', alias: 'y', type: 'boolean', desc: 'Auto-approve all permission requests (one-shot only)' }
31
31
  ];
32
32
 
33
33
  const LOGO = [
@@ -42,33 +42,33 @@ const LOGO = [
42
42
  function showBanner() {
43
43
  for (const line of LOGO) process.stdout.write(`${COLORS.accent(line)}\n`);
44
44
  process.stdout.write(
45
- `${COLORS.faint(` v${VERSION} · 多协议 AI 编码助手 · 输入 /help 查看命令 · Ctrl+C 退出`)}\n\n`
45
+ `${COLORS.faint(` v${VERSION} · multi-protocol AI coding assistant · /help for commands · Ctrl+C to exit`)}\n\n`
46
46
  );
47
47
  }
48
48
 
49
49
  function showHelp() {
50
- process.stdout.write(`\n${COLORS.bold(`${BIN} — DgxayCode 命令行版`)} ${COLORS.faint(`v${VERSION}`)}\n\n`);
51
- process.stdout.write(`${COLORS.faint('用法')}\n ${BIN} [选项] [命令] [参数…]\n\n`);
52
- process.stdout.write(`${COLORS.faint('常用命令')}\n`);
50
+ process.stdout.write(`\n${COLORS.bold(`${BIN} — DgxayCode CLI`)} ${COLORS.faint(`v${VERSION}`)}\n\n`);
51
+ process.stdout.write(`${COLORS.faint('Usage')}\n ${BIN} [options] [command] [args...]\n\n`);
52
+ process.stdout.write(`${COLORS.faint('Quick start')}\n`);
53
53
  const rows = [
54
- [`${BIN}`, '进入交互模式'],
55
- [`${BIN} "帮我写一个 Python 脚本"`, '单次执行后退出'],
56
- [`${BIN} run -p "..." -C ./project`, '指定工作空间单次执行'],
57
- [`${BIN} config init`, '首次配置(填写供应商与 API Key)'],
58
- [`${BIN} doctor`, '自检:配置、目录、模型连通性'],
59
- [`${BIN} <命令> --help`, '查看某个命令的详细用法']
54
+ [`${BIN}`, 'Start the interactive shell'],
55
+ [`${BIN} "write a python script"`, 'Ask once and exit'],
56
+ [`${BIN} run -p "..." -C ./project`, 'One-shot with a workspace'],
57
+ [`${BIN} config init`, 'First-time setup (provider + API key)'],
58
+ [`${BIN} doctor`, 'Self-check: config, paths, connectivity'],
59
+ [`${BIN} <command> --help`, 'Show detailed usage for a command']
60
60
  ];
61
61
  const width = Math.max(...rows.map(([cmd]) => cmd.length));
62
62
  for (const [cmd, desc] of rows) {
63
63
  process.stdout.write(` ${COLORS.cyan(cmd.padEnd(width))} ${COLORS.faint(desc)}\n`);
64
64
  }
65
- process.stdout.write(`\n${COLORS.faint('子命令')}\n`);
65
+ process.stdout.write(`\n${COLORS.faint('Commands')}\n`);
66
66
  const nameWidth = Math.max(...COMMANDS.map((cmd) => cmd.name.length));
67
67
  for (const cmd of COMMANDS) {
68
68
  const aliases = cmd.aliases?.length ? COLORS.faint(` (${cmd.aliases.join(', ')})`) : '';
69
69
  process.stdout.write(` ${COLORS.accent(cmd.name.padEnd(nameWidth))} ${cmd.summary || ''}${aliases}\n`);
70
70
  }
71
- process.stdout.write(`\n${COLORS.faint('全局选项')}\n`);
71
+ process.stdout.write(`\n${COLORS.faint('Global options')}\n`);
72
72
  const flags = GLOBAL_OPTIONS.map((opt) => {
73
73
  const alias = opt.alias ? `-${opt.alias}, ` : ' ';
74
74
  const value = opt.type !== 'boolean' ? ` <${opt.valueName || opt.type}>` : '';
@@ -79,9 +79,9 @@ function showHelp() {
79
79
  process.stdout.write(` ${COLORS.cyan(flag.padEnd(flagWidth))} ${COLORS.faint(desc)}\n`);
80
80
  }
81
81
  process.stdout.write(
82
- `\n${COLORS.faint('说明')} 配置与对话保存在 ${COLORS.faint('~/.dcb')}(可用 DGXAY_HOME 覆盖),可用 ${COLORS.faint(
82
+ `\n${COLORS.faint('Notes')} Configuration and conversations live in ${COLORS.faint('~/.dcb')} (override with DGXAY_HOME). Run ${COLORS.faint(
83
83
  `${BIN} config path`
84
- )} 查看。\n\n`
84
+ )} to see the paths.\n\n`
85
85
  );
86
86
  }
87
87
 
@@ -194,7 +194,7 @@ async function main(argv) {
194
194
  } catch (err) {
195
195
  if (err?.userError) {
196
196
  print.fail(err.message);
197
- print.hint(`运行 ${BIN} ${command.name} --help 查看用法`);
197
+ print.hint(`Run ${BIN} ${command.name} --help for usage`);
198
198
  return 2;
199
199
  }
200
200
  print.fail(err?.message || String(err));
@@ -203,7 +203,7 @@ async function main(argv) {
203
203
  }
204
204
  }
205
205
 
206
- // 不是子命令:整串参数当作单次运行的提示词;否则进入交互模式
206
+ // 不是子命令:整串参数当作单次运行的提示词;否则Start the interactive shell
207
207
  const prompt = parsed.positionals.join(' ').trim();
208
208
  const repl = require('./repl');
209
209
  try {
package/src/cli/print.js CHANGED
@@ -103,29 +103,29 @@ function usage(command) {
103
103
  write(`${COLORS.bold(`dgxay ${command.name}`)}${command.summary ? COLORS.faint(` — ${command.summary}`) : ''}`);
104
104
  if (command.usage) {
105
105
  blank();
106
- write(COLORS.faint('用法'));
106
+ write(COLORS.faint('Usage'));
107
107
  write(` ${command.usage}`);
108
108
  }
109
109
  if (command.examples?.length) {
110
110
  blank();
111
- write(COLORS.faint('示例'));
111
+ write(COLORS.faint('Examples'));
112
112
  for (const example of command.examples) write(` ${COLORS.cyan(example)}`);
113
113
  }
114
114
  if (command.options?.length) {
115
115
  blank();
116
- write(COLORS.faint('选项'));
116
+ write(COLORS.faint('Options'));
117
117
  const rows = command.options.map((opt) => {
118
118
  const alias = opt.alias ? [].concat(opt.alias).map((a) => (a.length === 1 ? `-${a}` : a)).join(', ') : '';
119
119
  const name = `--${opt.name}${opt.type && opt.type !== 'boolean' ? ` <${opt.valueName || opt.type}>` : ''}`;
120
120
  return [alias ? `${alias}, ${name}` : name, opt.desc || ''];
121
121
  });
122
- rows.push(['-h, --help', '显示帮助']);
122
+ rows.push(['-h, --help', 'Show help']);
123
123
  const width = Math.max(...rows.map(([flag]) => displayWidth(flag)));
124
124
  for (const [flag, desc] of rows) write(` ${COLORS.cyan(padWidth(flag, width))} ${COLORS.faint(desc)}`);
125
125
  }
126
126
  if (command.subcommands?.length) {
127
127
  blank();
128
- write(COLORS.faint('子命令'));
128
+ write(COLORS.faint('Commands'));
129
129
  const width = Math.max(...command.subcommands.map(([, name]) => displayWidth(name)));
130
130
  for (const [name, desc] of command.subcommands) write(` ${COLORS.accent(padWidth(name, width))} ${desc}`);
131
131
  }