aigroup-workflow 1.0.0 → 1.0.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.
@@ -41,40 +41,81 @@ export async function input(message, defaultValue = '') {
41
41
  }
42
42
 
43
43
  /**
44
- * 多选菜单
44
+ * 多选菜单 — 方向键移动,空格切换选中,回车确认
45
45
  * @param {string} message
46
46
  * @param {{ name: string, value: string, checked?: boolean }[]} choices
47
47
  * @returns {Promise<string[]>}
48
48
  */
49
49
  export async function multiSelect(message, choices) {
50
- console.log(`\n ? ${message}`)
51
- console.log('')
52
-
53
50
  const selected = new Set(
54
51
  choices.filter(c => c.checked).map(c => c.value)
55
52
  )
53
+ let cursor = 0
54
+
55
+ function render() {
56
+ // 移动光标到列表起始位置并清除下方内容
57
+ process.stdout.write(`\x1B[${choices.length + 1}A`)
58
+ process.stdout.write('\x1B[0J')
59
+ choices.forEach((c, i) => {
60
+ const pointer = i === cursor ? '❯' : ' '
61
+ const mark = selected.has(c.value) ? '◉' : '◯'
62
+ console.log(` ${pointer} ${mark} ${c.name}`)
63
+ })
64
+ process.stdout.write(' ↑↓ 移动 空格 切换 回车 确认')
65
+ }
56
66
 
67
+ // 首次绘制
68
+ console.log(`\n ? ${message}`)
57
69
  choices.forEach((c, i) => {
58
- const mark = selected.has(c.value) ? '' : ''
59
- console.log(` ${mark} ${i + 1}. ${c.name}`)
70
+ const pointer = i === cursor ? '' : ' '
71
+ const mark = selected.has(c.value) ? '◉' : '◯'
72
+ console.log(` ${pointer} ${mark} ${c.name}`)
60
73
  })
74
+ process.stdout.write(' ↑↓ 移动 空格 切换 回车 确认')
61
75
 
62
- const rl = createRL()
63
76
  return new Promise(resolve => {
64
- rl.question(`\n 输入编号切换选择,逗号分隔,直接回车确认 (如: 1,3): `, answer => {
65
- rl.close()
66
- if (answer.trim()) {
67
- const toggles = answer.split(',').map(s => parseInt(s.trim()) - 1)
68
- for (const idx of toggles) {
69
- if (idx >= 0 && idx < choices.length) {
70
- const val = choices[idx].value
71
- if (selected.has(val)) selected.delete(val)
72
- else selected.add(val)
73
- }
74
- }
77
+ const { stdin } = process
78
+ const wasRaw = stdin.isRaw
79
+ stdin.setRawMode(true)
80
+ stdin.resume()
81
+ stdin.setEncoding('utf-8')
82
+
83
+ function onData(key) {
84
+ // Ctrl+C
85
+ if (key === '\x03') {
86
+ cleanup()
87
+ process.exit(0)
75
88
  }
76
- resolve([...selected])
77
- })
89
+ // 回车 — 确认
90
+ if (key === '\r' || key === '\n') {
91
+ cleanup()
92
+ // 清除提示行并显示最终选择
93
+ process.stdout.write('\r\x1B[K\n')
94
+ return resolve([...selected])
95
+ }
96
+ // 空格 — 切换选中
97
+ if (key === ' ') {
98
+ const val = choices[cursor].value
99
+ if (selected.has(val)) selected.delete(val)
100
+ else selected.add(val)
101
+ render()
102
+ return
103
+ }
104
+ // 方向键(上: \x1B[A, 下: \x1B[B)
105
+ if (key === '\x1B[A' || key === '\x1B[B') {
106
+ if (key === '\x1B[A') cursor = (cursor - 1 + choices.length) % choices.length
107
+ else cursor = (cursor + 1) % choices.length
108
+ render()
109
+ }
110
+ }
111
+
112
+ function cleanup() {
113
+ stdin.removeListener('data', onData)
114
+ stdin.setRawMode(wasRaw ?? false)
115
+ stdin.pause()
116
+ }
117
+
118
+ stdin.on('data', onData)
78
119
  })
79
120
  }
80
121
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aigroup-workflow",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "AI 团队协作框架 — 通过角色派遣、工作流管道和 Harness 传感器驱动 AI 协作开发",
5
5
  "type": "module",
6
6
  "bin": {
@@ -28,5 +28,8 @@
28
28
  "license": "MIT",
29
29
  "engines": {
30
30
  "node": ">=18.0.0"
31
+ },
32
+ "dependencies": {
33
+ "aigroup-workflow": "^1.0.0"
31
34
  }
32
35
  }