@huicai/cli 2026.709.53670 → 2026.710.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@huicai/cli",
3
- "version": "2026.709.53670",
4
- "versionDisplay": "2026.07.09.53670",
3
+ "version": "2026.710.0",
4
+ "versionDisplay": "2026.07.10",
5
5
  "description": "在终端运行的智能体 CLI:以 HuiCai_AI 平台的 OpenAI 兼容 /v1 为模型后端,在用户本机执行文件/命令工具。",
6
6
  "type": "module",
7
7
  "bin": {
package/src/banner.js ADDED
@@ -0,0 +1,83 @@
1
+ // 启动欢迎横幅:渐变 ASCII 字标 + 上下文信息 + 快捷提示(对标 Claude CLI 进入时的欢迎屏)。
2
+ // 零依赖;真彩(COLORTERM=truecolor)时走 24-bit 青→紫渐变,仅 16 色时退化为青色,NO_COLOR/非 TTY 输出朴素字标。
3
+
4
+ import { c, colorEnabled } from './colors.js';
5
+
6
+ // 5 行块字(每字形 5 列宽,字间 1 空格)。
7
+ const FONT = {
8
+ H: ['█ █', '█ █', '█████', '█ █', '█ █'],
9
+ U: ['█ █', '█ █', '█ █', '█ █', '█████'],
10
+ I: ['█████', ' █ ', ' █ ', ' █ ', '█████'],
11
+ C: ['█████', '█ ', '█ ', '█ ', '█████'],
12
+ A: ['█████', '█ █', '█████', '█ █', '█ █'],
13
+ ' ': [' ', ' ', ' ', ' ', ' '],
14
+ };
15
+
16
+ function wordmark(word) {
17
+ const rows = ['', '', '', '', ''];
18
+ [...word].forEach((ch, idx) => {
19
+ const g = FONT[ch] || FONT[' '];
20
+ for (let r = 0; r < 5; r++) rows[r] += (idx ? ' ' : '') + g[r];
21
+ });
22
+ return rows;
23
+ }
24
+
25
+ const truecolor = colorEnabled && /truecolor|24bit/i.test(process.env.COLORTERM || '');
26
+ const lerp = (a, b, t) => Math.round(a + (b - a) * t);
27
+
28
+ // 按列做水平渐变;无真彩退化为青色;无色原样返回。
29
+ function gradientRow(row, from, to) {
30
+ if (!colorEnabled) return row;
31
+ const chars = [...row];
32
+ const n = chars.length;
33
+ let out = '';
34
+ for (let i = 0; i < n; i++) {
35
+ const ch = chars[i];
36
+ if (ch === ' ') { out += ' '; continue; }
37
+ if (!truecolor) { out += `\x1b[36m${ch}`; continue; }
38
+ const t = n <= 1 ? 0 : i / (n - 1);
39
+ out += `\x1b[38;2;${lerp(from[0], to[0], t)};${lerp(from[1], to[1], t)};${lerp(from[2], to[2], t)}m${ch}`;
40
+ }
41
+ return out + '\x1b[0m';
42
+ }
43
+
44
+ const PAD = ' ';
45
+ const FROM = [0, 229, 255]; // 青
46
+ const TO = [168, 85, 247]; // 紫
47
+
48
+ /**
49
+ * 生成欢迎横幅字符串(不含结尾换行)。
50
+ * @param {object} p
51
+ * @param {string} p.model 当前模型 / 平台目标
52
+ * @param {string} p.cwd 工作目录
53
+ * @param {string} [p.version] 版本展示串
54
+ * @param {boolean} [p.platform] 是否平台伪模型(agent-/workflow-/datahuman-)
55
+ * @param {boolean} [p.yolo] 是否已开自动放行
56
+ * @param {string} [p.consult] 混合模式咨询目标展示名
57
+ * @param {boolean} [p.ink] 是否 ink 富终端(附注一行)
58
+ */
59
+ export function renderWelcome({ model, cwd, version, platform, yolo, consult, ink } = {}) {
60
+ const cols = process.stdout.columns || 60;
61
+ const sep = c.gray('─'.repeat(Math.min(Math.max(cols - 2, 24), 50)));
62
+ const L = [''];
63
+
64
+ if (colorEnabled) {
65
+ for (const row of wordmark('HUICAI')) L.push(PAD + gradientRow(row, FROM, TO));
66
+ } else {
67
+ L.push(PAD + 'H U I C A I');
68
+ }
69
+
70
+ L.push('');
71
+ L.push(PAD + c.bold('HuiCai AI') + c.gray(' · 终端智能体') + (version ? c.gray(' v' + version) : '')
72
+ + (ink ? c.gray(' · ink') : ''));
73
+ L.push(PAD + sep);
74
+ L.push(PAD + c.gray(platform ? '目标 ' : '模型 ') + c.cyan(model || c.gray('(未设置,/model 设置)'))
75
+ + (platform ? c.gray(' · 平台编排(无本机工具)') : ''));
76
+ L.push(PAD + c.gray('目录 ') + cwd);
77
+ if (consult) L.push(PAD + c.gray('咨询 ') + c.magenta(consult) + c.gray(' · 混合模式(本机工具 + 平台咨询)'));
78
+ if (yolo) L.push(PAD + c.yellow('⚠ 自动放行(yolo) 已开:写文件/执行命令不再逐次确认'));
79
+ L.push('');
80
+ L.push(PAD + c.magenta('✦ ') + c.gray('/help 命令 · @文件 引用 · !命令 直通 shell · Ctrl+C 中断'));
81
+
82
+ return L.join('\n');
83
+ }
package/src/commands.js CHANGED
@@ -217,6 +217,15 @@ const BUILTINS = [
217
217
  ctx.print(ctx.cwd);
218
218
  },
219
219
  },
220
+ {
221
+ name: 'markdown', desc: '切换助手回复的 Markdown 渲染(TUI 富文本;关闭则显示原始文本,便于复制)',
222
+ run(ctx) {
223
+ const next = ctx.config.markdown === false; // 当前关→开,否则→关
224
+ ctx.config.markdown = next;
225
+ saveConfig({ markdown: next });
226
+ ctx.print('Markdown 渲染:' + (next ? '开(下一条回复起生效)' : '关(显示原始 Markdown 文本)'));
227
+ },
228
+ },
220
229
  {
221
230
  name: 'init', desc: '让智能体调研项目并生成/完善 HUICAI.md',
222
231
  run() {
package/src/config.js CHANGED
@@ -43,6 +43,8 @@ export function loadConfig() {
43
43
  memoryEnabled: process.env.HUICAI_MEMORY === '0' ? false : file.memory !== false,
44
44
  // 思考过程流式展示:默认开;配置 showReasoning:false 或 HUICAI_REASONING=0 关闭
45
45
  showReasoning: process.env.HUICAI_REASONING === '0' ? false : file.showReasoning !== false,
46
+ // 助手回复 Markdown 渲染(TUI 富文本):默认开;配置 markdown:false 或 HUICAI_MARKDOWN=0 关闭(显示原始文本)
47
+ markdown: process.env.HUICAI_MARKDOWN === '0' ? false : file.markdown !== false,
46
48
  // 客户端来源标识(对话落库审计用):默认 cli;VSCode 扩展进程内置 HUICAI_CLIENT=vscode
47
49
  client: (process.env.HUICAI_CLIENT || 'cli').trim().toLowerCase(),
48
50
  };
Binary file
package/src/repl.js CHANGED
@@ -12,6 +12,7 @@ import { makeConsultTool } from './consult.js';
12
12
  import { runSlash } from './commands.js';
13
13
  import { expandAtMentions, buildUserContent, runBangCommand, loadHistory, appendHistory } from './input.js';
14
14
  import { makeSkillTools } from './skills.js';
15
+ import { renderWelcome } from './banner.js';
15
16
 
16
17
  /** 汇集动态工具:本地技能(load_skill)+ 本地 MCP 工具 + dispatch_agent 子智能体。返回 {extraTools, clients}。 */
17
18
  export async function buildExtraTools(config, cwd) {
@@ -31,19 +32,15 @@ export async function buildExtraTools(config, cwd) {
31
32
  return { extraTools, clients: mcp.clients };
32
33
  }
33
34
 
34
- function banner(config, cwd, permissions) {
35
- process.stdout.write(c.bold(c.magenta('\n huicai')) + c.gray(' · 终端智能体') + '\n');
36
- const platform = /^(agent|workflow|datahuman)-/.test(String(config.model || ''));
37
- process.stdout.write(
38
- c.gray(` ${platform ? '目标' : '模型'} ${config.model || '(未设置, /model 设置)'}`
39
- + `${platform ? ' · 平台编排(分享页同款对话,无本机工具)' : ''} · 目录 ${cwd}`) + '\n',
40
- );
41
- process.stdout.write(
42
- c.gray(
43
- ` ${permissions.isYolo() ? '⚠ 自动放行(yolo) 已开 · ' : ''}` +
44
- '/help 命令 · @文件 引用 · !命令 直通 shell · Ctrl+C 中断本回合',
45
- ) + '\n',
46
- );
35
+ function banner(config, cwd, permissions, version) {
36
+ process.stdout.write(renderWelcome({
37
+ model: config.model,
38
+ cwd,
39
+ version,
40
+ platform: /^(agent|workflow|datahuman)-/.test(String(config.model || '')),
41
+ yolo: permissions.isYolo(),
42
+ consult: config.consult ? (config.consultLabel || config.consult) : null,
43
+ }) + '\n');
47
44
  }
48
45
 
49
46
  export async function startRepl({ config, cwd, yolo, initialPrompt, session, version }) {
@@ -66,7 +63,7 @@ export async function startRepl({ config, cwd, yolo, initialPrompt, session, ver
66
63
  else process.stdout.write('\n' + c.gray('输入 /exit 退出。') + '\n');
67
64
  });
68
65
 
69
- banner(config, cwd, permissions);
66
+ banner(config, cwd, permissions, version);
70
67
  echoResumed(session);
71
68
  const { extraTools, clients } = await buildExtraTools(config, cwd); // 连接 MCP(若已配置)
72
69
 
package/src/tui/app.js CHANGED
@@ -14,6 +14,8 @@ import React, { useState, useRef, useReducer, useEffect, useMemo } from 'react';
14
14
  import { render, Box, Text, Static, useInput, useApp } from 'ink';
15
15
  import { runTurn } from '../agent.js';
16
16
  import { toolLabel } from '../render.js';
17
+ import { renderMarkdown, looksLikeMarkdown } from '../markdown.js';
18
+ import { renderWelcome } from '../banner.js';
17
19
  import { createSession, saveSession } from '../session.js';
18
20
  import { buildExtraTools } from '../repl.js';
19
21
  import { closeMcp } from '../mcp.js';
@@ -79,7 +81,11 @@ function App({ config, cwd, session: initialSession, extraTools, yolo, initialPr
79
81
  };
80
82
  const flushLive = () => {
81
83
  if (liveRef.current) {
82
- addLog('assistant', liveRef.current);
84
+ // 定稿时把助手正文渲染为 Markdown(ink <Text> 原样保留内嵌 ANSI);流式期间仍显示原文,完成即定稿为富文本。
85
+ // 纯散文(无 Markdown 结构)直接留原文,避免无谓处理与边角改动。
86
+ const raw = liveRef.current;
87
+ const md = config.markdown !== false && looksLikeMarkdown(raw);
88
+ addLog('assistant', md ? renderMarkdown(raw) : raw);
83
89
  liveRef.current = '';
84
90
  }
85
91
  };
@@ -466,7 +472,15 @@ function LogLine({ item }) {
466
472
  * 启动 ink TUI。先(在 ink 接管屏幕前)连接 MCP 并打印连接信息,再进入全屏界面;退出后关闭 MCP。
467
473
  */
468
474
  export async function runInk({ config, cwd, session, yolo, initialPrompt, version }) {
469
- process.stdout.write(`\n huicai · 终端智能体(ink TUI) · ${config.model}\n`);
475
+ process.stdout.write(renderWelcome({
476
+ model: config.model,
477
+ cwd,
478
+ version,
479
+ platform: /^(agent|workflow|datahuman)-/.test(String(config.model || '')),
480
+ yolo,
481
+ consult: config.consult ? (config.consultLabel || config.consult) : null,
482
+ ink: true,
483
+ }) + '\n');
470
484
  const { extraTools, clients } = await buildExtraTools(config, cwd);
471
485
  const { waitUntilExit } = render(
472
486
  h(App, { config, cwd, session, extraTools, yolo, initialPrompt, version, onExit: () => closeMcp(clients) }),