@make-u-free/migi 0.5.17 → 0.5.19

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 +66 -21
  2. package/package.json +1 -1
package/bin/migi.js CHANGED
@@ -75,9 +75,10 @@ const agent = new MigiAgent({ context, promptFn, apiKey, model, name: agentName,
75
75
  try {
76
76
  await agent.chat(
77
77
  `起動した。以下の手順で今日の状況を確認して、簡潔にダッシュボードを表示してから、今一番優先すべきことを1つだけ提案して:\n` +
78
- `1. todos/${today}.md を read_file で読んで未完了タスクを確認\n` +
79
- `2. .migi/memory/next-actions.md があれば読む\n` +
80
- `3. ダッシュボード(完了済み・未完了の件数サマリー)をコンパクトに出して、一言で「今日はこれから」と提案する\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` +
81
82
  `(詳細な説明はいらない。テンポよく)`
82
83
  )
83
84
  } catch (err) {
@@ -127,14 +128,14 @@ async function readChatInput() {
127
128
  const PCONT = ' '
128
129
  const lines = ['']
129
130
  let curLine = 0
131
+ let cursorPos = 0 // 行内のカーソル位置(文字インデックス)
130
132
  let drawnLines = 0
131
- let cursorLine = 0 // カーソルの物理行(drawn area 先頭からの offset)
133
+ let cursorLine = 0 // カーソルの物理行(drawn area 先頭からの offset)
132
134
  let drawPending = false
133
135
 
134
136
  emitKeypressEvents(process.stdin)
135
137
  if (process.stdin.isTTY) process.stdin.setRawMode(true)
136
138
 
137
- // ペースト等の連続入力をまとめて1回の描画にするためのデバウンス
138
139
  function scheduleDraw() {
139
140
  if (drawPending) return
140
141
  drawPending = true
@@ -145,7 +146,7 @@ async function readChatInput() {
145
146
  const w = process.stdout.columns || 80
146
147
  const newLines = [
147
148
  ...lines.map((l, i) => chalk.cyan(i === 0 ? PFIRST : PCONT) + l),
148
- chalk.dim('─'.repeat(w - 1)), // w-1: 行末での自動折り返し防止
149
+ chalk.dim('─'.repeat(w - 1)),
149
150
  chalk.dim(` ✦ ${model} · Alt+Enterで改行 / Enterで送信`)
150
151
  ]
151
152
  const oldDrawnLines = drawnLines
@@ -153,30 +154,25 @@ async function readChatInput() {
153
154
 
154
155
  let buf = ''
155
156
 
156
- // ① drawn area 先頭まで戻る(cursorLine = カーソルが今いる物理行)
157
157
  if (cursorLine > 0) buf += `\x1b[${cursorLine}A`
158
158
  buf += '\r'
159
159
 
160
- // ② 各行を上書き。「先クリア→描画」ではなく「描画→行末クリア」でちらつき防止
161
160
  for (let i = 0; i < newLines.length; i++) {
162
161
  buf += newLines[i] + '\x1b[K'
163
162
  if (i < newLines.length - 1) buf += '\r\n'
164
163
  }
165
164
 
166
- // ③ 行数が減った場合、余分な古い行をクリア
167
165
  for (let i = newLines.length; i < oldDrawnLines; i++) {
168
166
  buf += '\r\n\x1b[2K'
169
167
  }
170
168
 
171
- // ④ curLine の行まで戻る
172
- // step②+③後のカーソル位置は max(新行数, 旧行数)-1 行目
173
169
  const linesFromBottom = Math.max(drawnLines, oldDrawnLines) - 1 - curLine
174
170
  if (linesFromBottom > 0) buf += `\x1b[${linesFromBottom}A`
175
171
  buf += '\r'
176
172
 
177
- // ⑤ カーソルを入力内容の末尾へ(全角文字は2カラム幅なので displayWidth を使う)
173
+ // カーソルをcursorPosの位置へ(末尾ではなく現在位置)
178
174
  const prefix = curLine === 0 ? PFIRST : PCONT
179
- buf += `\x1b[${prefix.length + displayWidth(lines[curLine]) + 1}G`
175
+ buf += `\x1b[${prefix.length + displayWidth(lines[curLine].slice(0, cursorPos)) + 1}G`
180
176
 
181
177
  cursorLine = curLine
182
178
  process.stdout.write(buf)
@@ -186,7 +182,11 @@ async function readChatInput() {
186
182
 
187
183
  const onKey = (str, key) => {
188
184
  if (!key) {
189
- if (str) { lines[curLine] += str; scheduleDraw() }
185
+ if (str) {
186
+ lines[curLine] = lines[curLine].slice(0, cursorPos) + str + lines[curLine].slice(cursorPos)
187
+ cursorPos += str.length
188
+ scheduleDraw()
189
+ }
190
190
  return
191
191
  }
192
192
 
@@ -195,17 +195,19 @@ async function readChatInput() {
195
195
  process.stdout.write(`\x1b[${drawnLines - 1 - curLine}B\n`)
196
196
  process.stdin.removeListener('keypress', onKey)
197
197
  if (process.stdin.isTTY) process.stdin.setRawMode(false)
198
- resolve(null) // null = 終了シグナル(メインループで後処理)
198
+ resolve(null)
199
199
  }
200
200
 
201
201
  if (key.name === 'return') {
202
- // Alt+Enter(macOS: Option+Enter)または Shift+Enter → 改行
203
202
  if (key.meta || key.shift) {
204
- lines.splice(curLine + 1, 0, '')
203
+ // カーソル位置で行を分割して改行
204
+ const rest = lines[curLine].slice(cursorPos)
205
+ lines[curLine] = lines[curLine].slice(0, cursorPos)
206
+ lines.splice(curLine + 1, 0, rest)
205
207
  curLine++
208
+ cursorPos = 0
206
209
  scheduleDraw()
207
210
  } else {
208
- // Enter → 送信(保留中の描画があれば先に確定)
209
211
  if (drawPending) { drawPending = false; draw() }
210
212
  const content = lines.join('\n').trim()
211
213
  if (!content) return
@@ -218,10 +220,15 @@ async function readChatInput() {
218
220
  }
219
221
 
220
222
  if (key.name === 'backspace') {
221
- if (lines[curLine].length > 0) {
222
- lines[curLine] = lines[curLine].slice(0, -1)
223
+ if (cursorPos > 0) {
224
+ lines[curLine] = lines[curLine].slice(0, cursorPos - 1) + lines[curLine].slice(cursorPos)
225
+ cursorPos--
223
226
  scheduleDraw()
224
227
  } else if (curLine > 0) {
228
+ // 行頭でbackspace → 前の行に結合
229
+ const prev = lines[curLine - 1]
230
+ cursorPos = prev.length
231
+ lines[curLine - 1] = prev + lines[curLine]
225
232
  lines.splice(curLine, 1)
226
233
  curLine--
227
234
  scheduleDraw()
@@ -229,8 +236,46 @@ async function readChatInput() {
229
236
  return
230
237
  }
231
238
 
239
+ if (key.name === 'delete') {
240
+ if (cursorPos < lines[curLine].length) {
241
+ lines[curLine] = lines[curLine].slice(0, cursorPos) + lines[curLine].slice(cursorPos + 1)
242
+ scheduleDraw()
243
+ }
244
+ return
245
+ }
246
+
247
+ if (key.name === 'left') {
248
+ if (cursorPos > 0) { cursorPos--; scheduleDraw() }
249
+ else if (curLine > 0) { curLine--; cursorPos = lines[curLine].length; scheduleDraw() }
250
+ return
251
+ }
252
+
253
+ if (key.name === 'right') {
254
+ if (cursorPos < lines[curLine].length) { cursorPos++; scheduleDraw() }
255
+ else if (curLine < lines.length - 1) { curLine++; cursorPos = 0; scheduleDraw() }
256
+ return
257
+ }
258
+
259
+ if (key.name === 'up' && curLine > 0) {
260
+ curLine--
261
+ cursorPos = Math.min(cursorPos, lines[curLine].length)
262
+ scheduleDraw()
263
+ return
264
+ }
265
+
266
+ if (key.name === 'down' && curLine < lines.length - 1) {
267
+ curLine++
268
+ cursorPos = Math.min(cursorPos, lines[curLine].length)
269
+ scheduleDraw()
270
+ return
271
+ }
272
+
273
+ if (key.name === 'home') { cursorPos = 0; scheduleDraw(); return }
274
+ if (key.name === 'end') { cursorPos = lines[curLine].length; scheduleDraw(); return }
275
+
232
276
  if (str && !key.ctrl && !key.meta) {
233
- lines[curLine] += str
277
+ lines[curLine] = lines[curLine].slice(0, cursorPos) + str + lines[curLine].slice(cursorPos)
278
+ cursorPos += str.length
234
279
  scheduleDraw()
235
280
  }
236
281
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@make-u-free/migi",
3
- "version": "0.5.17",
3
+ "version": "0.5.19",
4
4
  "description": "Your AI right-hand agent. Works anywhere, with any LLM API.",
5
5
  "type": "module",
6
6
  "bin": {