@make-u-free/migi 0.3.6 → 0.3.8

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/bin/migi.js CHANGED
@@ -66,7 +66,17 @@ 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
81
  // ---- 複数行入力(空行で送信)----
72
82
  async function readMultiLine() {
@@ -75,7 +85,7 @@ async function readMultiLine() {
75
85
  const onLine = (line) => {
76
86
  if (line === '' && lines.length > 0) {
77
87
  rl.removeListener('line', onLine)
78
- // 入力ボックス下辺 + 欄外ステータス
88
+ // 入力ボックス下辺(欄の閉じ)+ 欄外ガイド
79
89
  console.log(sep())
80
90
  console.log(chalk.dim(` ✦ ${model} · Enterで改行 / 空行で送信`))
81
91
  resolve(lines.join('\n'))
@@ -91,10 +101,8 @@ async function readMultiLine() {
91
101
 
92
102
  // ---- メインループ ----
93
103
  async function prompt() {
94
- // 入力ボックス上辺
95
- console.log('\n' + sep())
96
- console.log(chalk.bold.cyan(` ${userName || 'あなた'}`))
97
- console.log(sep())
104
+ // 入力ボックス上辺(ユーザー名をセパレーターに埋め込む)
105
+ console.log('\n' + sepWithLabel(chalk.bold.cyan(userName || 'あなた')))
98
106
 
99
107
  const input = (await readMultiLine()).trim()
100
108
  if (!input) return prompt()
@@ -139,9 +147,7 @@ async function prompt() {
139
147
  if (parsed) {
140
148
  const skill = resolveSkill(parsed.name, process.cwd())
141
149
  if (skill) {
142
- console.log('\n' + sep())
143
- console.log(chalk.bold.cyan(` ${agentName}`) + chalk.dim(` [スキル: ${parsed.name}]`))
144
- console.log(sep())
150
+ console.log('\n' + sepWithLabel(chalk.bold.cyan(agentName) + chalk.dim(` [スキル: ${parsed.name}]`)))
145
151
  const expanded = expandSkill(skill.content, parsed.args)
146
152
  try {
147
153
  const reply = await agent.chat(expanded)
@@ -158,9 +164,7 @@ async function prompt() {
158
164
  }
159
165
 
160
166
  // --- 通常チャット ---
161
- console.log('\n' + sep())
162
- console.log(chalk.bold.cyan(` ${agentName}`))
163
- console.log(sep())
167
+ console.log('\n' + sepWithLabel(chalk.bold.cyan(agentName)))
164
168
  try {
165
169
  const reply = await agent.chat(input)
166
170
  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.6",
3
+ "version": "0.3.8",
4
4
  "description": "Your AI right-hand agent. Works anywhere, with any LLM API.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/agent.js CHANGED
@@ -4,6 +4,7 @@ import { homedir } from 'os'
4
4
  import { toolSchemas, teamsToolSchema, executeTool } from './tools.js'
5
5
  import { createPermissionChecker } from './permissions.js'
6
6
  import { httpsAgent } from './tls.js'
7
+ import { Spinner } from './spinner.js'
7
8
 
8
9
  export class MigiAgent {
9
10
  constructor({ context = '', promptFn = null, apiKey = null, model = 'gpt-4.1-2025-04-14', name = 'Migi', userName = '', teamsWebhookUrl = '' } = {}) {
@@ -92,13 +93,17 @@ ${userNameLine}
92
93
  ...this.history
93
94
  ]
94
95
 
96
+ const spinner = new Spinner()
97
+
95
98
  while (true) {
99
+ spinner.start('考え中…')
96
100
  const response = await this.client.chat.completions.create({
97
101
  model: this.model,
98
102
  messages,
99
103
  tools: this.tools,
100
104
  tool_choice: 'auto'
101
105
  })
106
+ spinner.stop()
102
107
 
103
108
  const choice = response.choices[0]
104
109
  messages.push(choice.message)
@@ -117,21 +122,23 @@ ${userNameLine}
117
122
  const args = JSON.parse(toolCall.function.arguments)
118
123
  const name = toolCall.function.name
119
124
 
120
- console.log(chalk.dim(`\n [${name}]`))
125
+ console.log(chalk.dim(` ${name}`))
121
126
 
122
127
  const approved = await this.checkPermission(name, args)
123
128
  let result
124
129
 
125
130
  if (approved) {
131
+ spinner.start(`実行中: ${name}`)
126
132
  try {
127
133
  result = await executeTool(name, args, {
128
- teamsWebhookUrl: this.teamsWebhookUrl,
129
- apiKey: this.apiKey,
130
- model: this.model
131
- })
134
+ teamsWebhookUrl: this.teamsWebhookUrl,
135
+ apiKey: this.apiKey,
136
+ model: this.model
137
+ })
132
138
  } catch (err) {
133
139
  result = `エラー: ${err.message}`
134
140
  }
141
+ spinner.stop()
135
142
  } else {
136
143
  result = 'ユーザーによりキャンセルされました'
137
144
  console.log(chalk.dim(' → キャンセル'))
package/src/spinner.js ADDED
@@ -0,0 +1,34 @@
1
+ import chalk from 'chalk'
2
+
3
+ const FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
4
+
5
+ export class Spinner {
6
+ constructor() {
7
+ this._frame = 0
8
+ this._timer = null
9
+ this._text = ''
10
+ }
11
+
12
+ start(text = '考え中…') {
13
+ this._text = text
14
+ this._frame = 0
15
+ this._timer = setInterval(() => {
16
+ const icon = chalk.cyan(FRAMES[this._frame % FRAMES.length])
17
+ process.stdout.write(`\r ${icon} ${chalk.dim(this._text)} `)
18
+ this._frame++
19
+ }, 80)
20
+ }
21
+
22
+ update(text) {
23
+ this._text = text
24
+ }
25
+
26
+ stop() {
27
+ if (this._timer) {
28
+ clearInterval(this._timer)
29
+ this._timer = null
30
+ // 行をクリア
31
+ process.stdout.write('\r' + ' '.repeat((process.stdout.columns || 80)) + '\r')
32
+ }
33
+ }
34
+ }