@raolin2025/claude-code-node 2.8.0 → 2.8.1

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@raolin2025/claude-code-node",
3
- "version": "2.8.0",
3
+ "version": "2.8.1",
4
4
  "description": "Node.js AI Code Agent CLI - Zero dependencies, pure JavaScript, security hardened, multi-channel notifications, Telegram & QQ Bot remote programming, rich media upload, multi-account management",
5
5
  "type": "module",
6
6
  "main": "src/core/index.js",
@@ -4,10 +4,13 @@
4
4
  // 只负责「头标」的绘制与配色,与 CLI 框架解耦。
5
5
  // 以后要替换/升级头标,只需修改本文件并保持接口不变即可。
6
6
  //
7
- // 头标内容: CC-NODE 艺术字
8
- // CC : 两个 C, 10列宽 x 4行高 (扁平, 蓝渐变)
9
- // NODE : 四个字母, 5列宽 x 4行高 (绿渐变)
10
- // 上下严格对齐 (20列 x 8行)
7
+ // 头标内容: CC-NODE 机械臂机器人艺术字(v2,取自 log/headpiece.js)
8
+ // CC = 一对机械眼睛(带 ◉◉ 瞳孔,蓝渐变 5 行)
9
+ // N = 左臂,向左侧伸展 ──┼
10
+ // O = 圆形身体/躯干(白色)
11
+ // D = 右臂,向右侧伸展 ┼──
12
+ // E = 手持工具箱/锤子(黄色 ╔═══╗)
13
+ // 上下总宽 20 字符,总高 10 行,严格对齐
11
14
  //
12
15
  // 接口:
13
16
  // renderHeadpiece({ colWidth = 24 } = {})
@@ -17,39 +20,38 @@
17
20
  // width 头标原始可见宽度
18
21
  // ============================================================
19
22
 
20
- // ---- 头标原始数据(20列 x 8行)----
21
- // CC 部分(蓝渐变, 4行)
23
+ // ---- 头标原始数据(20列 x 10行)----
24
+ // CC 部分(机械眼睛,蓝渐变,5 行;每行统一右填充至 20 列保证对齐)
22
25
  const CC = [
23
- '╔════════╗╔════════╗',
24
- '██║ ██║ ',
25
- '██║ ██║ ',
26
- '╚════════╝╚════════╝',
26
+ '\x1b[38;5;81m ╭────╮╭────╮\x1b[0m',
27
+ '\x1b[38;5;75m ╱ ◉◉ ╲╱ ◉◉ ╲\x1b[0m',
28
+ '\x1b[38;5;69m │ ◉◉ ││ ◉◉ │\x1b[0m',
29
+ '\x1b[38;5;63m │ ││ │\x1b[0m',
30
+ '\x1b[38;5;57m ╰────╯╰────╯\x1b[0m',
27
31
  ]
28
32
 
29
- // NODE 部分(绿渐变, 4行)
33
+ // NODE 部分(左臂绿 + 身体白 + 右臂绿 + 工具箱黄,5 行)
30
34
  const NODE = [
31
- '╔╗╔═╗╔═══╗╔═══╗╔═══╗',
32
- '║║║ ║║ ║║ ║║ ║',
33
- '║╚╝ ║║ ║║ ║╠═══╣',
34
- '╚═══╝╚═══╝╚═══╝╚═══╝',
35
+ '\x1b[38;5;82m╱───┐\x1b[0m\x1b[38;5;15m┌───┐\x1b[0m\x1b[38;5;82m┌───╲\x1b[0m\x1b[38;5;220m╔═══╗\x1b[0m',
36
+ '\x1b[38;5;118m│N │\x1b[0m\x1b[38;5;15m│ │\x1b[0m\x1b[38;5;118m│D │\x1b[0m\x1b[38;5;220m║ ║\x1b[0m',
37
+ '\x1b[38;5;154m│ │\x1b[0m\x1b[38;5;15m│ │\x1b[0m\x1b[38;5;154m│ │\x1b[0m\x1b[38;5;220m╠═══╣\x1b[0m',
38
+ '\x1b[38;5;190m──┼ │\x1b[0m\x1b[38;5;15m│ │\x1b[0m\x1b[38;5;190m│ ┼─\x1b[0m\x1b[38;5;220m║ ║\x1b[0m',
39
+ '\x1b[38;5;226m╲───┘\x1b[0m\x1b[38;5;15m└───┘\x1b[0m\x1b[38;5;226m└───╱\x1b[0m\x1b[38;5;220m╚═══╝\x1b[0m',
35
40
  ]
36
41
 
37
- // ---- 配色(渐变)----
38
- // CC 蓝色渐变(深 浅)
39
- const BLUE = [81, 75, 69, 63]
40
- // NODE 绿色渐变(深 → 浅)
41
- const GREEN = [82, 118, 154, 190]
42
+ // 合并全部行
43
+ const RAW_LINES = [...CC, ...NODE]
42
44
 
43
- // 给每一行按对应色号上色
44
- function colorize(lines, colors) {
45
- return lines.map((line, i) => `\x1b[38;5;${colors[i]}m${line}\x1b[0m`)
46
- }
47
-
48
- // 去掉 ANSI 转义码,返回真实可见长度
45
+ // ---- 配色工具 ----
49
46
  function stripAnsi(s) {
50
47
  return s.replace(/\x1b\[[0-9;]*m/g, '')
51
48
  }
52
49
 
50
+ /** 去掉尾部 ANSI reset 码,供拼接填充空格时保持颜色连续 */
51
+ function trimTrailingReset(s) {
52
+ return s.replace(/\x1b\[0m\s*$/, '')
53
+ }
54
+
53
55
  /**
54
56
  * 渲染头标。
55
57
  * @param {Object} [opts]
@@ -57,23 +59,33 @@ function stripAnsi(s) {
57
59
  * @returns {{ lines: string[], height: number, width: number }}
58
60
  */
59
61
  export function renderHeadpiece({ colWidth = 24 } = {}) {
60
- // 1. 原始可见宽度
61
- const width = stripAnsi(CC[0]).length // 20
62
+ // 1. 原始可见宽度(取最宽一行)
63
+ const width = Math.max(...RAW_LINES.map(stripAnsi).map(s => s.length))
64
+ const height = RAW_LINES.length // 10
62
65
 
63
- // 2. 合并 CC + NODE,分别上色
64
- const rawLines = [...colorize(CC, BLUE), ...colorize(NODE, GREEN)]
65
- const height = rawLines.length // 8
66
+ // 2. 逐行补齐到统一宽度 width(右填充空格,保证右边缘对齐;空格放 ANSI reset 之前)
67
+ const padded = RAW_LINES.map((line) => {
68
+ const plain = stripAnsi(line)
69
+ const missing = width - plain.length
70
+ if (missing <= 0) return line
71
+ // 保留前导 ANSI 与尾部 reset:在 reset 前补空格
72
+ const leadingAnsi = line.match(/^(\x1b\[[0-9;]*m)+/)?.[0] || ''
73
+ const body = line.slice(leadingAnsi.length)
74
+ const trailingAnsi = body.match(/(\x1b\[0m)+$/)?.[0] || ''
75
+ const inner = body.slice(0, body.length - trailingAnsi.length)
76
+ return leadingAnsi + inner + ' '.repeat(missing) + trailingAnsi
77
+ })
66
78
 
67
- // 3. 在 colWidth 内居中填充(若 colWidth < width 则不做填充,原样返回)
79
+ // 3. 在 colWidth 内居中填充(若 colWidth <= width 则不做填充,原样返回)
68
80
  if (colWidth <= width) {
69
- return { lines: rawLines, height, width }
81
+ return { lines: padded, height, width }
70
82
  }
71
83
 
72
84
  const totalPad = colWidth - width
73
85
  const leftPad = Math.floor(totalPad / 2)
74
86
  const rightPad = totalPad - leftPad
75
87
 
76
- const lines = rawLines.map((line) => {
88
+ const lines = padded.map((line) => {
77
89
  const leadingAnsi = line.match(/^(\x1b\[[0-9;]*m)+/)?.[0] || ''
78
90
  const trailingAnsi = line.match(/(\x1b\[0m)+$/)?.[0] || '\x1b[0m'
79
91
  const plain = stripAnsi(line)