@make-u-free/migi 0.5.19 → 0.5.21

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
@@ -73,16 +73,28 @@ const agent = new MigiAgent({ context, promptFn, apiKey, model, name: agentName,
73
73
  const today = new Date().toISOString().split('T')[0]
74
74
  console.log('\n' + chalk.bold.cyan(`─── ${agentName} `) + chalk.dim('─'.repeat(Math.max(0, (process.stdout.columns || 80) - agentName.length - 5))))
75
75
  try {
76
- await agent.chat(
77
- `起動した。以下の手順で今日の状況を確認して、簡潔にダッシュボードを表示してから、今一番優先すべきことを1つだけ提案して:\n` +
78
- `1. todos/${today}.md を read_file で読んで未完了タスクを確認(ファイルがなければスキップ)\n` +
79
- `2. search_content で「- \\[ \\]」を .company/ ディレクトリ全体から検索して、部署ごとの未完了タスクも集約する\n` +
80
- `3. .migi/memory/next-actions.md があれば読む\n` +
81
- `4. todos/ と .company/ の両方を合わせたダッシュボード(未完了の件数サマリー、ソース別)をコンパクトに出して、一言で「今日はこれから」と提案する\n` +
82
- `(詳細な説明はいらない。テンポよく)`
83
- )
76
+ const _abort = new AbortController()
77
+ const _sigint = () => { process.stdout.write(chalk.yellow('\n キャンセルしました\n')); _abort.abort() }
78
+ process.once('SIGINT', _sigint)
79
+ try {
80
+ await agent.chat(
81
+ `起動した。以下の手順で今日の状況を確認して、簡潔にダッシュボードを表示してから、今一番優先すべきことを1つだけ提案して:\n` +
82
+ `1. todos/${today}.md を read_file で読んで未完了タスクを確認(ファイルがなければスキップ)\n` +
83
+ `2. search_content で「- \\[ \\]」を .company/ ディレクトリ全体から検索して、部署ごとの未完了タスクも集約する\n` +
84
+ `3. .migi/memory/next-actions.md があれば読む\n` +
85
+ `4. todos/ と .company/ の両方を合わせたダッシュボード(未完了の件数サマリー、ソース別)をコンパクトに出して、一言で「今日はこれから」と提案する\n` +
86
+ ` - 未完了タスクは 1. 2. 3. と通し番号を付けて表示する(ファイルには書かない、表示だけ)\n` +
87
+ ` - ユーザーが「N番完了」と言ったら、その番号のタスクを特定してファイルの [ ] を [x] に書き換える\n` +
88
+ `(詳細な説明はいらない。テンポよく)`,
89
+ _abort.signal
90
+ )
91
+ } finally {
92
+ process.removeListener('SIGINT', _sigint)
93
+ }
84
94
  } catch (err) {
85
- console.error(chalk.red(' 起動チェック失敗: ' + err.message))
95
+ if (err.name !== 'AbortError') {
96
+ console.error(chalk.red(' 起動チェック失敗: ' + err.message))
97
+ }
86
98
  }
87
99
  }
88
100
 
@@ -191,11 +203,22 @@ async function readChatInput() {
191
203
  }
192
204
 
193
205
  if (key.ctrl && key.name === 'c') {
194
- if (drawPending) { drawPending = false; draw() }
195
- process.stdout.write(`\x1b[${drawnLines - 1 - curLine}B\n`)
196
- process.stdin.removeListener('keypress', onKey)
197
- if (process.stdin.isTTY) process.stdin.setRawMode(false)
198
- resolve(null)
206
+ const isEmpty = lines.every(l => l.length === 0)
207
+ if (!isEmpty) {
208
+ // バッファをクリアして再描画(終了しない)
209
+ lines.splice(0, lines.length, '')
210
+ curLine = 0
211
+ cursorPos = 0
212
+ scheduleDraw()
213
+ } else {
214
+ // 空の状態で Ctrl+C → ヒントだけ出してそのまま
215
+ process.stdout.write(`\x1b[${drawnLines - 1 - curLine}B\r\n`)
216
+ process.stdout.write(chalk.dim(' 終了するには /exit を入力してください') + '\r\n')
217
+ drawnLines = 0
218
+ cursorLine = 0
219
+ draw()
220
+ }
221
+ return
199
222
  }
200
223
 
201
224
  if (key.name === 'return') {
@@ -338,6 +361,14 @@ async function prompt() {
338
361
  return prompt()
339
362
  }
340
363
 
364
+ // --- Ctrl+C で処理キャンセル(アプリ継続)---
365
+ const abortController = new AbortController()
366
+ const sigintHandler = () => {
367
+ process.stdout.write(chalk.yellow('\n キャンセルしました\n'))
368
+ abortController.abort()
369
+ }
370
+ process.once('SIGINT', sigintHandler)
371
+
341
372
  // --- スキルルーティング ---
342
373
  const parsed = parseSkillInput(input)
343
374
  if (parsed) {
@@ -346,12 +377,15 @@ async function prompt() {
346
377
  console.log('\n' + sepWithLabel(chalk.bold.cyan(agentName) + chalk.dim(` [スキル: ${parsed.name}]`)))
347
378
  const expanded = expandSkill(skill.content, parsed.args)
348
379
  try {
349
- await agent.chat(expanded)
380
+ await agent.chat(expanded, abortController.signal)
350
381
  } catch (err) {
351
- console.error(chalk.red('\n エラー: ' + err.message + '\n'))
382
+ if (err.name !== 'AbortError') console.error(chalk.red('\n エラー: ' + err.message + '\n'))
383
+ } finally {
384
+ process.removeListener('SIGINT', sigintHandler)
352
385
  }
353
386
  return prompt()
354
387
  } else {
388
+ process.removeListener('SIGINT', sigintHandler)
355
389
  console.log(chalk.yellow(`\n スキル「${parsed.name}」が見つかりません。`))
356
390
  console.log(chalk.dim(` .migi/skills/${parsed.name}.md を作成してください。`))
357
391
  return prompt()
@@ -361,9 +395,11 @@ async function prompt() {
361
395
  // --- 通常チャット ---
362
396
  console.log('\n' + sepWithLabel(chalk.bold.cyan(agentName)))
363
397
  try {
364
- await agent.chat(input)
398
+ await agent.chat(input, abortController.signal)
365
399
  } catch (err) {
366
- console.error(chalk.red('\n エラー: ' + err.message + '\n'))
400
+ if (err.name !== 'AbortError') console.error(chalk.red('\n エラー: ' + err.message + '\n'))
401
+ } finally {
402
+ process.removeListener('SIGINT', sigintHandler)
367
403
  }
368
404
 
369
405
  prompt()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@make-u-free/migi",
3
- "version": "0.5.19",
3
+ "version": "0.5.21",
4
4
  "description": "Your AI right-hand agent. Works anywhere, with any LLM API.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -29,13 +29,19 @@
29
29
 
30
30
  ## ダッシュボードを求められたとき
31
31
 
32
- 今日のTODOファイルを読んで、以下の形式で表示する:
32
+ 今日のTODOファイルと .company/ 以下の未完了タスクをまとめて、以下の形式で表示する:
33
33
 
34
34
  ```
35
35
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
36
36
  ダッシュボード - YYYY-MM-DD
37
37
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
38
38
  TODO: X件未完了 / Y件完了
39
- [未完了タスクの一覧]
39
+ 1. タスクA
40
+ 2. タスクB
41
+ 3. タスクC
40
42
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
41
43
  ```
44
+
45
+ - 未完了タスクは **通し番号(1. 2. 3.)を付けて表示する**(ファイルには書かない)
46
+ - ユーザーが「N番完了」と言ったらその番号のタスクを特定し、ファイルの `[ ]` を `[x]` に書き換える
47
+ - ユーザーが「N番削除」と言ったらその行をファイルから削除する
package/src/agent.js CHANGED
@@ -206,7 +206,7 @@ JSON形式のみで返答(他のテキスト不要):
206
206
  this.history = cleaned
207
207
  }
208
208
 
209
- async chat(userMessage) {
209
+ async chat(userMessage, signal = null) {
210
210
  this._sanitizeHistory()
211
211
  this.history.push({ role: 'user', content: userMessage })
212
212
 
@@ -225,7 +225,8 @@ JSON形式のみで返答(他のテキスト不要):
225
225
  messages,
226
226
  tools: this.tools,
227
227
  tool_choice: 'auto',
228
- stream: true
228
+ stream: true,
229
+ ...(signal ? { signal } : {})
229
230
  })
230
231
 
231
232
  let content = ''