@make-u-free/migi 0.4.7 → 0.5.0
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 +16 -6
- package/package.json +1 -1
- package/src/agent.js +61 -8
package/bin/migi.js
CHANGED
|
@@ -149,12 +149,11 @@ async function readChatInput() {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
if (key.ctrl && key.name === 'c') {
|
|
152
|
-
if (drawPending) { drawPending = false; draw() }
|
|
152
|
+
if (drawPending) { drawPending = false; draw() }
|
|
153
153
|
process.stdout.write(`\x1b[${drawnLines - 1 - curLine}B\n`)
|
|
154
154
|
process.stdin.removeListener('keypress', onKey)
|
|
155
155
|
if (process.stdin.isTTY) process.stdin.setRawMode(false)
|
|
156
|
-
|
|
157
|
-
process.exit(0)
|
|
156
|
+
resolve(null) // null = 終了シグナル(メインループで後処理)
|
|
158
157
|
}
|
|
159
158
|
|
|
160
159
|
if (key.name === 'return') {
|
|
@@ -198,18 +197,29 @@ async function readChatInput() {
|
|
|
198
197
|
})
|
|
199
198
|
}
|
|
200
199
|
|
|
200
|
+
// ---- セッション終了(サマリー保存 → 挨拶 → exit) ----
|
|
201
|
+
async function gracefulExit() {
|
|
202
|
+
const saved = await agent.saveSummary(cwd)
|
|
203
|
+
if (saved) {
|
|
204
|
+
console.log(chalk.dim(`\n セッションを記録しました → ${saved}`))
|
|
205
|
+
}
|
|
206
|
+
console.log(chalk.cyan(`\n お疲れ様でした!またね。\n`))
|
|
207
|
+
process.exit(0)
|
|
208
|
+
}
|
|
209
|
+
|
|
201
210
|
// ---- メインループ ----
|
|
202
211
|
async function prompt() {
|
|
203
212
|
// 入力ボックス上辺(ユーザー名をセパレーターに埋め込む)
|
|
204
213
|
console.log('\n' + sepWithLabel(chalk.bold.cyan(userName || 'あなた')))
|
|
205
214
|
|
|
206
|
-
const
|
|
215
|
+
const rawInput = await readChatInput()
|
|
216
|
+
if (rawInput === null) return gracefulExit() // Ctrl+C
|
|
217
|
+
const input = rawInput.trim()
|
|
207
218
|
if (!input) return prompt()
|
|
208
219
|
|
|
209
220
|
// --- ビルトインコマンド ---
|
|
210
221
|
if (input === '/exit' || input === '/quit') {
|
|
211
|
-
|
|
212
|
-
process.exit(0)
|
|
222
|
+
return gracefulExit()
|
|
213
223
|
}
|
|
214
224
|
|
|
215
225
|
if (input === '/config') {
|
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import OpenAI from 'openai'
|
|
2
2
|
import chalk from 'chalk'
|
|
3
3
|
import { homedir } from 'os'
|
|
4
|
+
import { existsSync, appendFileSync, mkdirSync } from 'fs'
|
|
5
|
+
import { join, dirname } from 'path'
|
|
4
6
|
import { toolSchemas, teamsToolSchema, executeTool } from './tools.js'
|
|
5
7
|
import { createPermissionChecker } from './permissions.js'
|
|
6
8
|
import { httpsAgent } from './tls.js'
|
|
@@ -45,14 +47,18 @@ ${userNameLine}
|
|
|
45
47
|
- 「どうしますか?」と聞く前に、自分でできることをやりきる
|
|
46
48
|
- 完了したらまとめて報告する。途中経過は簡潔に
|
|
47
49
|
|
|
48
|
-
##
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
50
|
+
## メモリと文脈の継続
|
|
51
|
+
- グローバルメモリ: ${homedir()}/.migi/memory.md(ユーザーの好み・習慣・横断的な情報)
|
|
52
|
+
- ワークスペースメモリ: ${cwd}/.migi/memory.md(このプロジェクト固有の情報・決定事項)
|
|
53
|
+
- 形式: "## YYYY-MM-DD" の見出しの下に箇条書きで記録。既存ファイルがあれば追記
|
|
54
|
+
- ユーザーが「覚えておいて」「remember」と言ったら必ず書き出す
|
|
55
|
+
- 言われなくても、以下は自発的に記録する:
|
|
56
|
+
- 重要な意思決定・方針転換
|
|
57
|
+
- ユーザーの好み・こだわり・やり方のクセ
|
|
58
|
+
- 繰り返し登場するテーマやプロジェクト
|
|
59
|
+
- 「次回やること」として明確になったタスク
|
|
60
|
+
- セッション開始時にメモリの内容を参照し、前回の続きから自然に入る
|
|
61
|
+
- 過去の記録と矛盾することをユーザーが言ったら「前回と変わりましたか?」と確認する
|
|
56
62
|
|
|
57
63
|
## 環境
|
|
58
64
|
- 今日の日付: ${new Date().toISOString().split('T')[0]}
|
|
@@ -67,6 +73,53 @@ ${userNameLine}
|
|
|
67
73
|
(context ? `\n## ロードされたコンテキスト\n${context}` : '')
|
|
68
74
|
}
|
|
69
75
|
|
|
76
|
+
// セッションの会話をサマリーして memory.md に保存する
|
|
77
|
+
async saveSummary(cwd) {
|
|
78
|
+
// ユーザー発言が2回未満なら保存しない(短すぎるセッション)
|
|
79
|
+
const userTurns = this.history.filter(m => m.role === 'user').length
|
|
80
|
+
if (userTurns < 2) return null
|
|
81
|
+
|
|
82
|
+
const spinner = new Spinner()
|
|
83
|
+
spinner.start('セッションを記録中…')
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
const response = await this.client.chat.completions.create({
|
|
87
|
+
model: this.model,
|
|
88
|
+
messages: [
|
|
89
|
+
{ role: 'system', content: this.systemPrompt },
|
|
90
|
+
...this.history,
|
|
91
|
+
{
|
|
92
|
+
role: 'user',
|
|
93
|
+
content: `このセッションを次回の文脈引き継ぎ用に要約してください。
|
|
94
|
+
以下の形式で箇条書き3〜6行。日本語で簡潔に(1行50字以内)。
|
|
95
|
+
|
|
96
|
+
- 話し合ったこと・決定したこと
|
|
97
|
+
- 完了したこと・作ったもの
|
|
98
|
+
- ユーザーについて学んだこと(好み・やり方など)
|
|
99
|
+
- 次回やること(あれば)
|
|
100
|
+
|
|
101
|
+
形式:「- 〜」の箇条書きのみ。見出しや前置きは不要。`
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const summary = response.choices[0].message.content.trim()
|
|
107
|
+
const today = new Date().toISOString().split('T')[0]
|
|
108
|
+
const entry = `\n## ${today}\n${summary}\n`
|
|
109
|
+
|
|
110
|
+
const memPath = join(cwd, '.migi', 'memory.md')
|
|
111
|
+
const dir = dirname(memPath)
|
|
112
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true })
|
|
113
|
+
appendFileSync(memPath, entry, 'utf-8')
|
|
114
|
+
|
|
115
|
+
spinner.stop()
|
|
116
|
+
return memPath
|
|
117
|
+
} catch (err) {
|
|
118
|
+
spinner.stop()
|
|
119
|
+
return null
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
70
123
|
// tool_calls に対応する tool 結果がない壊れた履歴を修復する
|
|
71
124
|
_sanitizeHistory() {
|
|
72
125
|
const cleaned = []
|