@make-u-free/migi 0.3.7 → 0.3.9

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.
Files changed (2) hide show
  1. package/bin/migi.js +71 -28
  2. package/package.json +1 -1
package/bin/migi.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import '../src/tls.js' // 企業CA(Zscaler等)を起動直後に読み込む
3
- import readline from 'readline'
3
+ import readline, { emitKeypressEvents } from 'readline'
4
4
  import chalk from 'chalk'
5
5
  import dotenv from 'dotenv'
6
6
  import { MigiAgent } from '../src/agent.js'
@@ -66,37 +66,84 @@ console.log(chalk.dim(' /exit 終了\n'))
66
66
 
67
67
  const agent = new MigiAgent({ context, promptFn, apiKey, model, name: agentName, userName, teamsWebhookUrl })
68
68
 
69
- function sep() { return chalk.dim('─'.repeat(process.stdout.columns || 80)) }
69
+ function sep() {
70
+ const w = process.stdout.columns || 80
71
+ return chalk.dim('─'.repeat(w))
72
+ }
73
+
74
+ function sepWithLabel(label) {
75
+ const w = process.stdout.columns || 80
76
+ const left = '── ' + label + ' '
77
+ const right = '─'.repeat(Math.max(0, w - left.length))
78
+ return chalk.dim(left + right)
79
+ }
70
80
 
71
- // ---- 複数行入力(空行で送信)----
72
- async function readMultiLine() {
73
- const lines = []
81
+ // ---- チャット入力(Enter送信 / Shift+Enter改行)----
82
+ async function readChatInput() {
74
83
  return new Promise((resolve) => {
75
- const onLine = (line) => {
76
- if (line === '' && lines.length > 0) {
77
- rl.removeListener('line', onLine)
78
- // 入力ボックス下辺 + 欄外ステータス
79
- console.log(sep())
80
- console.log(chalk.dim(` ✦ ${model} · Enterで改行 / 空行で送信`))
81
- resolve(lines.join('\n'))
82
- } else {
83
- lines.push(line)
84
- process.stdout.write(chalk.cyan(' '))
84
+ const lines = ['']
85
+
86
+ emitKeypressEvents(process.stdin)
87
+ if (process.stdin.isTTY) process.stdin.setRawMode(true)
88
+ process.stdout.write(chalk.cyan(' '))
89
+
90
+ const onKey = (str, key) => {
91
+ if (!key) {
92
+ // IME確定などの複合文字
93
+ if (str) { lines[lines.length - 1] += str; process.stdout.write(str) }
94
+ return
95
+ }
96
+
97
+ // Ctrl+C
98
+ if (key.ctrl && key.name === 'c') {
99
+ console.log(chalk.cyan('\n\n お疲れ様でした!またね。\n'))
100
+ process.exit(0)
101
+ }
102
+
103
+ if (key.name === 'return') {
104
+ if (key.shift) {
105
+ // Shift+Enter → 改行
106
+ lines.push('')
107
+ process.stdout.write('\n ')
108
+ } else {
109
+ // Enter → 送信
110
+ const content = lines.join('\n').trim()
111
+ if (!content) return // 空は無視
112
+ process.stdin.removeListener('keypress', onKey)
113
+ if (process.stdin.isTTY) process.stdin.setRawMode(false)
114
+ process.stdout.write('\n')
115
+ console.log(sep())
116
+ console.log(chalk.dim(` ✦ ${model} · Shift+Enterで改行 / Enterで送信`))
117
+ resolve(content)
118
+ }
119
+ return
120
+ }
121
+
122
+ if (key.name === 'backspace') {
123
+ const cur = lines[lines.length - 1]
124
+ if (cur.length > 0) {
125
+ lines[lines.length - 1] = cur.slice(0, -1)
126
+ process.stdout.write('\b \b')
127
+ }
128
+ return
129
+ }
130
+
131
+ if (str && !key.ctrl && !key.meta) {
132
+ lines[lines.length - 1] += str
133
+ process.stdout.write(str)
85
134
  }
86
135
  }
87
- process.stdout.write(chalk.cyan(' '))
88
- rl.on('line', onLine)
136
+
137
+ process.stdin.on('keypress', onKey)
89
138
  })
90
139
  }
91
140
 
92
141
  // ---- メインループ ----
93
142
  async function prompt() {
94
- // 入力ボックス上辺
95
- console.log('\n' + sep())
96
- console.log(chalk.bold.cyan(` ${userName || 'あなた'}`))
97
- console.log(sep())
143
+ // 入力ボックス上辺(ユーザー名をセパレーターに埋め込む)
144
+ console.log('\n' + sepWithLabel(chalk.bold.cyan(userName || 'あなた')))
98
145
 
99
- const input = (await readMultiLine()).trim()
146
+ const input = (await readChatInput()).trim()
100
147
  if (!input) return prompt()
101
148
 
102
149
  // --- ビルトインコマンド ---
@@ -139,9 +186,7 @@ async function prompt() {
139
186
  if (parsed) {
140
187
  const skill = resolveSkill(parsed.name, process.cwd())
141
188
  if (skill) {
142
- console.log('\n' + sep())
143
- console.log(chalk.bold.cyan(` ${agentName}`) + chalk.dim(` [スキル: ${parsed.name}]`))
144
- console.log(sep())
189
+ console.log('\n' + sepWithLabel(chalk.bold.cyan(agentName) + chalk.dim(` [スキル: ${parsed.name}]`)))
145
190
  const expanded = expandSkill(skill.content, parsed.args)
146
191
  try {
147
192
  const reply = await agent.chat(expanded)
@@ -158,9 +203,7 @@ async function prompt() {
158
203
  }
159
204
 
160
205
  // --- 通常チャット ---
161
- console.log('\n' + sep())
162
- console.log(chalk.bold.cyan(` ${agentName}`))
163
- console.log(sep())
206
+ console.log('\n' + sepWithLabel(chalk.bold.cyan(agentName)))
164
207
  try {
165
208
  const reply = await agent.chat(input)
166
209
  console.log('\n' + reply + '\n')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@make-u-free/migi",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "Your AI right-hand agent. Works anywhere, with any LLM API.",
5
5
  "type": "module",
6
6
  "bin": {