@geekbeer/minion 2.60.0 → 2.67.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/core/api.js +110 -0
- package/core/lib/config-warnings.js +85 -0
- package/core/lib/reflection-scheduler.js +1 -5
- package/core/lib/revision-watcher.js +12 -1
- package/core/lib/step-poller.js +12 -1
- package/core/lib/thread-watcher.js +359 -0
- package/core/routes/daemons.js +34 -0
- package/core/routes/help-threads.js +189 -0
- package/docs/api-reference.md +195 -0
- package/docs/environment-setup.md +75 -7
- package/linux/minion-cli.sh +6 -0
- package/linux/server.js +15 -2
- package/package.json +1 -1
- package/rules/core.md +45 -0
- package/win/minion-cli.ps1 +12 -2
- package/win/server.js +15 -2
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project thread routes (local API on minion)
|
|
3
|
+
*
|
|
4
|
+
* Endpoints:
|
|
5
|
+
* - GET /api/help-threads - List open threads in minion's projects
|
|
6
|
+
* - POST /api/help-threads - Create a new thread (proxied to HQ)
|
|
7
|
+
* - GET /api/help-threads/:id - Get thread detail with messages
|
|
8
|
+
* - POST /api/help-threads/:id/messages - Post a message to a thread
|
|
9
|
+
* - POST /api/help-threads/:id/resolve - Resolve a thread
|
|
10
|
+
* - POST /api/help-threads/:id/cancel - Cancel a thread
|
|
11
|
+
* - DELETE /api/help-threads/:id - Permanently delete a thread (PM only)
|
|
12
|
+
* - GET /api/project-memories - Search project memories
|
|
13
|
+
* - POST /api/project-memories - Create a project memory
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const { verifyToken } = require('../lib/auth')
|
|
17
|
+
const api = require('../api')
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {import('fastify').FastifyInstance} fastify
|
|
21
|
+
*/
|
|
22
|
+
async function helpThreadRoutes(fastify) {
|
|
23
|
+
// List open threads
|
|
24
|
+
fastify.get('/api/help-threads', async (request, reply) => {
|
|
25
|
+
if (!verifyToken(request)) {
|
|
26
|
+
reply.code(401)
|
|
27
|
+
return { success: false, error: 'Unauthorized' }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
const data = await api.getOpenHelpThreads()
|
|
32
|
+
return { success: true, threads: data.threads || [] }
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(`[HelpThreads] List error: ${error.message}`)
|
|
35
|
+
reply.code(500)
|
|
36
|
+
return { success: false, error: error.message }
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
// Create thread
|
|
41
|
+
fastify.post('/api/help-threads', async (request, reply) => {
|
|
42
|
+
if (!verifyToken(request)) {
|
|
43
|
+
reply.code(401)
|
|
44
|
+
return { success: false, error: 'Unauthorized' }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const data = await api.createHelpThread(request.body)
|
|
49
|
+
return { success: true, thread: data.thread }
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error(`[HelpThreads] Create error: ${error.message}`)
|
|
52
|
+
reply.code(error.statusCode || 500)
|
|
53
|
+
return { success: false, error: error.message }
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// Get thread detail
|
|
58
|
+
fastify.get('/api/help-threads/:id', async (request, reply) => {
|
|
59
|
+
if (!verifyToken(request)) {
|
|
60
|
+
reply.code(401)
|
|
61
|
+
return { success: false, error: 'Unauthorized' }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
const data = await api.getHelpThread(request.params.id)
|
|
66
|
+
return { success: true, thread: data.thread, messages: data.messages }
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error(`[HelpThreads] Get error: ${error.message}`)
|
|
69
|
+
reply.code(error.statusCode || 500)
|
|
70
|
+
return { success: false, error: error.message }
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Post message
|
|
75
|
+
fastify.post('/api/help-threads/:id/messages', async (request, reply) => {
|
|
76
|
+
if (!verifyToken(request)) {
|
|
77
|
+
reply.code(401)
|
|
78
|
+
return { success: false, error: 'Unauthorized' }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const data = await api.postHelpMessage(request.params.id, request.body)
|
|
83
|
+
return { success: true, message: data.message }
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.error(`[HelpThreads] Message error: ${error.message}`)
|
|
86
|
+
reply.code(error.statusCode || 500)
|
|
87
|
+
return { success: false, error: error.message }
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
// Resolve thread
|
|
92
|
+
fastify.post('/api/help-threads/:id/resolve', async (request, reply) => {
|
|
93
|
+
if (!verifyToken(request)) {
|
|
94
|
+
reply.code(401)
|
|
95
|
+
return { success: false, error: 'Unauthorized' }
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const { resolution } = request.body || {}
|
|
100
|
+
const data = await api.resolveHelpThread(request.params.id, resolution)
|
|
101
|
+
return { success: true, thread: data.thread }
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error(`[HelpThreads] Resolve error: ${error.message}`)
|
|
104
|
+
reply.code(error.statusCode || 500)
|
|
105
|
+
return { success: false, error: error.message }
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
// Permanently delete thread (PM only)
|
|
110
|
+
fastify.delete('/api/help-threads/:id', async (request, reply) => {
|
|
111
|
+
if (!verifyToken(request)) {
|
|
112
|
+
reply.code(401)
|
|
113
|
+
return { success: false, error: 'Unauthorized' }
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
const data = await api.deleteHelpThread(request.params.id)
|
|
118
|
+
return { success: true, deleted: data.deleted }
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error(`[HelpThreads] Delete error: ${error.message}`)
|
|
121
|
+
reply.code(error.statusCode || 500)
|
|
122
|
+
return { success: false, error: error.message }
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
// Cancel thread
|
|
127
|
+
fastify.post('/api/help-threads/:id/cancel', async (request, reply) => {
|
|
128
|
+
if (!verifyToken(request)) {
|
|
129
|
+
reply.code(401)
|
|
130
|
+
return { success: false, error: 'Unauthorized' }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const { reason } = request.body || {}
|
|
135
|
+
const data = await api.cancelHelpThread(request.params.id, reason)
|
|
136
|
+
return { success: true, thread: data.thread }
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error(`[HelpThreads] Cancel error: ${error.message}`)
|
|
139
|
+
reply.code(error.statusCode || 500)
|
|
140
|
+
return { success: false, error: error.message }
|
|
141
|
+
}
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
// Search project memories
|
|
145
|
+
fastify.get('/api/project-memories', async (request, reply) => {
|
|
146
|
+
if (!verifyToken(request)) {
|
|
147
|
+
reply.code(401)
|
|
148
|
+
return { success: false, error: 'Unauthorized' }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const { project_id, search, category, tags, status } = request.query || {}
|
|
153
|
+
if (!project_id) {
|
|
154
|
+
reply.code(400)
|
|
155
|
+
return { success: false, error: 'project_id is required' }
|
|
156
|
+
}
|
|
157
|
+
const data = await api.searchProjectMemories(project_id, {
|
|
158
|
+
search,
|
|
159
|
+
category,
|
|
160
|
+
tags: tags ? tags.split(',') : undefined,
|
|
161
|
+
status,
|
|
162
|
+
})
|
|
163
|
+
return { success: true, memories: data.memories || [] }
|
|
164
|
+
} catch (error) {
|
|
165
|
+
console.error(`[ProjectMemories] Search error: ${error.message}`)
|
|
166
|
+
reply.code(error.statusCode || 500)
|
|
167
|
+
return { success: false, error: error.message }
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
// Create project memory
|
|
172
|
+
fastify.post('/api/project-memories', async (request, reply) => {
|
|
173
|
+
if (!verifyToken(request)) {
|
|
174
|
+
reply.code(401)
|
|
175
|
+
return { success: false, error: 'Unauthorized' }
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
const data = await api.createProjectMemory(request.body)
|
|
180
|
+
return { success: true, memory: data.memory }
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.error(`[ProjectMemories] Create error: ${error.message}`)
|
|
183
|
+
reply.code(error.statusCode || 500)
|
|
184
|
+
return { success: false, error: error.message }
|
|
185
|
+
}
|
|
186
|
+
})
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
module.exports = { helpThreadRoutes }
|
package/docs/api-reference.md
CHANGED
|
@@ -244,6 +244,174 @@ Supported `cli_type`: `claude-code`, `gemini`, `codex`
|
|
|
244
244
|
|
|
245
245
|
Note: Claude Code の場合、書き込み先は `settings.local.json`(サーバー再起動時に上書きされない)。
|
|
246
246
|
|
|
247
|
+
### Daemon Status (デーモン監視)
|
|
248
|
+
|
|
249
|
+
バックグラウンドデーモンの稼働状態を確認する。
|
|
250
|
+
|
|
251
|
+
| Method | Endpoint | Description |
|
|
252
|
+
|--------|----------|-------------|
|
|
253
|
+
| GET | `/api/daemons/status` | 全デーモンのステータス一覧 |
|
|
254
|
+
|
|
255
|
+
GET `/api/daemons/status` response:
|
|
256
|
+
```json
|
|
257
|
+
{
|
|
258
|
+
"success": true,
|
|
259
|
+
"daemons": {
|
|
260
|
+
"step_poller": { "running": true, "last_poll_at": "2026-03-19T15:30:00.000Z" },
|
|
261
|
+
"revision_watcher": { "running": true, "last_poll_at": "2026-03-19T15:30:05.000Z" },
|
|
262
|
+
"thread_watcher": { "running": true, "last_poll_at": "2026-03-19T15:29:52.000Z" },
|
|
263
|
+
"reflection_scheduler": { "running": true, "next_run": "2026-03-20T03:00:00.000Z" },
|
|
264
|
+
"heartbeat": { "running": true, "last_beat_at": "2026-03-19T15:30:10.000Z" }
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
| Daemon | 概要 |
|
|
270
|
+
|--------|------|
|
|
271
|
+
| `step_poller` | ワークフローステップの取得・実行(30秒間隔) |
|
|
272
|
+
| `revision_watcher` | リビジョン要求の検知(30秒間隔、PMのみ) |
|
|
273
|
+
| `thread_watcher` | プロジェクトスレッドの監視・LLM評価(15秒間隔) |
|
|
274
|
+
| `reflection_scheduler` | 1日1回の振り返り(cron) |
|
|
275
|
+
| `heartbeat` | HQへのハートビート(30秒間隔) |
|
|
276
|
+
|
|
277
|
+
### Project Threads (プロジェクトスレッド)
|
|
278
|
+
|
|
279
|
+
プロジェクト内のコミュニケーションチャネル。ブロッカー共有やチーム議論に使う。
|
|
280
|
+
リクエストは HQ にプロキシされる。
|
|
281
|
+
|
|
282
|
+
| Method | Endpoint | Description |
|
|
283
|
+
|--------|----------|-------------|
|
|
284
|
+
| GET | `/api/help-threads` | 参加プロジェクトのオープンスレッド一覧 |
|
|
285
|
+
| POST | `/api/help-threads` | スレッドを起票 |
|
|
286
|
+
| GET | `/api/help-threads/:id` | スレッド詳細 + メッセージ一覧 |
|
|
287
|
+
| POST | `/api/help-threads/:id/messages` | スレッドにメッセージを投稿 |
|
|
288
|
+
| POST | `/api/help-threads/:id/resolve` | スレッドを解決済みにする |
|
|
289
|
+
| POST | `/api/help-threads/:id/cancel` | スレッドをキャンセル |
|
|
290
|
+
| DELETE | `/api/help-threads/:id` | スレッドを完全削除(PMのみ) |
|
|
291
|
+
|
|
292
|
+
POST `/api/help-threads` body (ヘルプスレッド起票):
|
|
293
|
+
```json
|
|
294
|
+
{
|
|
295
|
+
"project_id": "uuid",
|
|
296
|
+
"thread_type": "help",
|
|
297
|
+
"title": "ランサーズの2FA認証コードが必要",
|
|
298
|
+
"description": "ログイン時に2段階認証を要求された。メールで届く6桁コードの入力が必要。",
|
|
299
|
+
"mentions": ["role:pm"],
|
|
300
|
+
"context": {
|
|
301
|
+
"category": "auth",
|
|
302
|
+
"attempted_resolution": "保存済み認証情報で再ログイン試行済み、2FA必須"
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
POST `/api/help-threads` body (ディスカッションスレッド起票):
|
|
308
|
+
```json
|
|
309
|
+
{
|
|
310
|
+
"project_id": "uuid",
|
|
311
|
+
"thread_type": "discussion",
|
|
312
|
+
"title": "デプロイ手順の確認",
|
|
313
|
+
"description": "本番デプロイ前にステージングで確認するフローに変えたい。意見ある?",
|
|
314
|
+
"mentions": ["role:engineer"]
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
| Field | Type | Required | Description |
|
|
319
|
+
|-------|------|----------|-------------|
|
|
320
|
+
| `project_id` | string | Yes | プロジェクト UUID |
|
|
321
|
+
| `thread_type` | string | No | `help`(デフォルト)or `discussion` |
|
|
322
|
+
| `title` | string | Yes | スレッドの要約 |
|
|
323
|
+
| `description` | string | Yes | 詳細説明 |
|
|
324
|
+
| `mentions` | string[] | No | メンション対象。形式: `role:engineer`, `role:pm`, `minion:<minion_id>`, `user` |
|
|
325
|
+
| `context` | object | No | 任意のメタデータ(category, urgency, workflow_execution_id等) |
|
|
326
|
+
|
|
327
|
+
**thread_type の違い:**
|
|
328
|
+
- `help`: ブロッカー解決。`resolve` で解決
|
|
329
|
+
- `discussion`: チーム内ディスカッション。`close` で完了
|
|
330
|
+
|
|
331
|
+
**メンションルール:**
|
|
332
|
+
- メンションされたミニオンは優先的にスレッドを評価する
|
|
333
|
+
- メンションがない場合、全チームメンバーがLLMで関連性を判定してから参加
|
|
334
|
+
- トークン消費を抑えるため、当事者が明確な場合はメンションを推奨
|
|
335
|
+
- ミニオンが自力で解決できない場合、`@user` メンション付きで返信して人間に助けを求める
|
|
336
|
+
|
|
337
|
+
POST `/api/help-threads/:id/messages` body:
|
|
338
|
+
```json
|
|
339
|
+
{
|
|
340
|
+
"content": "関連するプロジェクトメモリーが見つかりました: ...",
|
|
341
|
+
"mentions": ["user"]
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
| Field | Type | Required | Description |
|
|
346
|
+
|-------|------|----------|-------------|
|
|
347
|
+
| `content` | string | Yes | メッセージ本文 |
|
|
348
|
+
| `attachments` | object | No | 添付ファイル情報(JSON) |
|
|
349
|
+
| `mentions` | string[] | No | メンション対象 |
|
|
350
|
+
|
|
351
|
+
POST `/api/help-threads/:id/resolve` body:
|
|
352
|
+
```json
|
|
353
|
+
{
|
|
354
|
+
"resolution": "ユーザーから2FAコード(123456)を受け取りログイン成功"
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
POST `/api/help-threads/:id/cancel` body (optional):
|
|
359
|
+
```json
|
|
360
|
+
{
|
|
361
|
+
"reason": "誤って起票したため取り消し"
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
スレッドのステータスは Supabase Realtime で配信されるため、ポーリングに加えて
|
|
366
|
+
HQ ダッシュボードではリアルタイムに更新が表示される。
|
|
367
|
+
|
|
368
|
+
### Project Memories (プロジェクト共有知識)
|
|
369
|
+
|
|
370
|
+
プロジェクトレベルのチーム共有知識ベース。ヘルプスレッドの解決知見を蓄積して再利用する。
|
|
371
|
+
リクエストは HQ にプロキシされる。
|
|
372
|
+
|
|
373
|
+
| Method | Endpoint | Description |
|
|
374
|
+
|--------|----------|-------------|
|
|
375
|
+
| GET | `/api/project-memories` | メモリー検索。Query: `?project_id=&search=&category=&tags=&status=` |
|
|
376
|
+
| POST | `/api/project-memories` | メモリーを投稿 |
|
|
377
|
+
|
|
378
|
+
GET Query Parameters:
|
|
379
|
+
|
|
380
|
+
| Param | Required | Description |
|
|
381
|
+
|-------|----------|-------------|
|
|
382
|
+
| `project_id` | Yes | プロジェクト UUID |
|
|
383
|
+
| `search` | No | タイトル・内容でのテキスト検索 |
|
|
384
|
+
| `category` | No | カテゴリフィルター |
|
|
385
|
+
| `tags` | No | タグフィルター(カンマ区切り) |
|
|
386
|
+
| `status` | No | `active`(デフォルト), `outdated`, `archived` |
|
|
387
|
+
|
|
388
|
+
POST `/api/project-memories` body:
|
|
389
|
+
```json
|
|
390
|
+
{
|
|
391
|
+
"project_id": "uuid",
|
|
392
|
+
"title": "ランサーズは2FA必須",
|
|
393
|
+
"content": "ランサーズはログイン時に2段階認証を要求する。メールで届くコードが必要なため、人間へのエスカレーションが必須。team_timeout=30sが適切。",
|
|
394
|
+
"category": "auth",
|
|
395
|
+
"tags": ["lancers", "2fa", "login"],
|
|
396
|
+
"source_thread_id": "uuid"
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
| Field | Type | Required | Description |
|
|
401
|
+
|-------|------|----------|-------------|
|
|
402
|
+
| `project_id` | string | Yes | プロジェクト UUID |
|
|
403
|
+
| `title` | string | Yes | 知見のタイトル |
|
|
404
|
+
| `content` | string | Yes | 知見の内容 |
|
|
405
|
+
| `category` | string | Yes | `auth`, `environment`, `know-how`, `decision`, `preference` |
|
|
406
|
+
| `tags` | string[] | No | 自由タグ(検索用) |
|
|
407
|
+
| `source_thread_id` | string | No | 知見の出典ヘルプスレッド UUID |
|
|
408
|
+
|
|
409
|
+
**推奨ワークフロー:**
|
|
410
|
+
1. ブロッカー発生 → `GET /api/project-memories?project_id=...&category=auth&search=2fa` で既知の知見を検索
|
|
411
|
+
2. 該当あり → 知見に基づいて自己解決 or 即エスカレーション
|
|
412
|
+
3. 該当なし → `POST /api/help-threads` でブロッカー起票
|
|
413
|
+
4. 解決後 → `POST /api/project-memories` で知見を蓄積
|
|
414
|
+
|
|
247
415
|
### Commands
|
|
248
416
|
|
|
249
417
|
| Method | Endpoint | Description |
|
|
@@ -601,3 +769,30 @@ Response:
|
|
|
601
769
|
| POST | `/api/minion/skills` | スキル登録/更新(新バージョン自動作成) |
|
|
602
770
|
|
|
603
771
|
スキルはバージョン管理される。push ごとに新バージョンが作成され、ファイルは Supabase Storage に保存される。
|
|
772
|
+
|
|
773
|
+
### Help Threads (HQ)
|
|
774
|
+
|
|
775
|
+
| Method | Endpoint | Description |
|
|
776
|
+
|--------|----------|-------------|
|
|
777
|
+
| POST | `/api/minion/help-threads` | ブロッカースレッドを起票 |
|
|
778
|
+
| GET | `/api/minion/help-threads/open` | 参加プロジェクトの未解決スレッド一覧 |
|
|
779
|
+
| GET | `/api/minion/help-threads/:id` | スレッド詳細 + メッセージ一覧 |
|
|
780
|
+
| POST | `/api/minion/help-threads/:id/messages` | スレッドにメッセージを投稿 |
|
|
781
|
+
| PATCH | `/api/minion/help-threads/:id/resolve` | スレッドを解決済みにする。Body: `{resolution}` |
|
|
782
|
+
| PATCH | `/api/minion/help-threads/:id/cancel` | スレッドをキャンセル。Body: `{reason?}` |
|
|
783
|
+
| DELETE | `/api/minion/help-threads/:id` | スレッドを完全削除(PMのみ)。メッセージもCASCADE削除 |
|
|
784
|
+
| PATCH | `/api/minion/help-threads/:id/escalate` | スレッドを手動エスカレーション |
|
|
785
|
+
|
|
786
|
+
ローカルエージェントの `/api/help-threads` は上記 HQ API へのプロキシ。
|
|
787
|
+
詳細なリクエスト/レスポンス仕様はローカル API セクションの「Help Threads」を参照。
|
|
788
|
+
|
|
789
|
+
### Project Memories (HQ)
|
|
790
|
+
|
|
791
|
+
| Method | Endpoint | Description |
|
|
792
|
+
|--------|----------|-------------|
|
|
793
|
+
| POST | `/api/minion/project-memories` | プロジェクトメモリーを投稿 |
|
|
794
|
+
| GET | `/api/minion/project-memories` | メモリー検索。Query: `?project_id=&search=&category=&tags=&status=` |
|
|
795
|
+
| PATCH | `/api/minion/project-memories/:id` | メモリーを更新。Body: `{title?, content?, category?, tags?, status?}` |
|
|
796
|
+
|
|
797
|
+
ローカルエージェントの `/api/project-memories` は上記 HQ API へのプロキシ。
|
|
798
|
+
詳細なリクエスト/レスポンス仕様はローカル API セクションの「Project Memories」を参照。
|
|
@@ -28,9 +28,20 @@ requires:
|
|
|
28
28
|
|
|
29
29
|
## MCP サーバーの設定
|
|
30
30
|
|
|
31
|
-
MCP
|
|
31
|
+
MCPサーバーの設定ファイルは使用するCLIツールによって異なる。
|
|
32
|
+
いずれも LLM から直接編集可能(パーミッション設定とは異なり、API経由は不要)。
|
|
32
33
|
|
|
33
|
-
###
|
|
34
|
+
### CLI別の設定ファイル
|
|
35
|
+
|
|
36
|
+
| CLI | 設定ファイル | フォーマット | 編集方法 |
|
|
37
|
+
|-----|------------|------------|---------|
|
|
38
|
+
| Claude Code | `.mcp.json`(プロジェクトルート) | JSON | Edit/Write ツールで直接編集 |
|
|
39
|
+
| Gemini CLI | `.gemini/settings.json` | JSON | Edit/Write ツールで直接編集 |
|
|
40
|
+
| Codex CLI | `~/.codex/config.toml` | TOML | `codex mcp add/remove` コマンド推奨 |
|
|
41
|
+
|
|
42
|
+
### Claude Code
|
|
43
|
+
|
|
44
|
+
設定ファイル: `.mcp.json`(プロジェクトルート)または `~/.mcp.json`(ユーザーレベル)
|
|
34
45
|
|
|
35
46
|
```json
|
|
36
47
|
{
|
|
@@ -43,9 +54,8 @@ MCP サーバーは `~/.mcp.json` に JSON 形式で設定する。このファ
|
|
|
43
54
|
}
|
|
44
55
|
```
|
|
45
56
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
1. `~/.mcp.json` が存在しない場合は新規作成する
|
|
57
|
+
**設定の追加・変更手順:**
|
|
58
|
+
1. `.mcp.json` が存在しない場合は新規作成する
|
|
49
59
|
2. 既存の場合は内容を読み取り、`mcpServers` オブジェクトにエントリを追加する
|
|
50
60
|
3. 既存エントリを壊さないよう注意する
|
|
51
61
|
|
|
@@ -54,10 +64,54 @@ MCP サーバーは `~/.mcp.json` に JSON 形式で設定する。このファ
|
|
|
54
64
|
cat ~/.mcp.json 2>/dev/null || echo '(not found)'
|
|
55
65
|
```
|
|
56
66
|
|
|
67
|
+
**スコープの優先順:**
|
|
68
|
+
1. ローカル (`~/.claude.json` 内のプロジェクト固有設定) — 最優先
|
|
69
|
+
2. プロジェクト (`.mcp.json`) — チーム共有
|
|
70
|
+
3. ユーザー (`~/.claude.json`) — 全プロジェクト共通
|
|
71
|
+
|
|
72
|
+
### Gemini CLI
|
|
73
|
+
|
|
74
|
+
設定ファイル: `.gemini/settings.json`(プロジェクト)または `~/.gemini/settings.json`(ユーザーレベル)
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"mcpServers": {
|
|
79
|
+
"<server-name>": {
|
|
80
|
+
"command": "<起動コマンド>",
|
|
81
|
+
"args": ["<引数1>", "<引数2>"],
|
|
82
|
+
"timeout": 30000
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
追加フィールド: `cwd`(作業ディレクトリ)、`timeout`(ミリ秒)、`trust`(確認プロンプト省略)、`includeTools`/`excludeTools`(ツールフィルタ)
|
|
89
|
+
|
|
90
|
+
### Codex CLI
|
|
91
|
+
|
|
92
|
+
設定ファイル: `.codex/config.toml`(プロジェクト)または `~/.codex/config.toml`(ユーザーレベル)
|
|
93
|
+
|
|
94
|
+
```toml
|
|
95
|
+
[mcp_servers.<server-name>]
|
|
96
|
+
command = "<起動コマンド>"
|
|
97
|
+
args = ["<引数1>", "<引数2>"]
|
|
98
|
+
startup_timeout_sec = 10.0
|
|
99
|
+
tool_timeout_sec = 60.0
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**注意:** `.codex/` ディレクトリは LLM からの直接編集が制限される場合がある。以下のコマンドを使用すること:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
codex mcp add <name> --command "<command>" --args "<arg1>,<arg2>"
|
|
106
|
+
codex mcp remove <name>
|
|
107
|
+
codex mcp list
|
|
108
|
+
```
|
|
109
|
+
|
|
57
110
|
### よく使う MCP サーバーの設定例
|
|
58
111
|
|
|
59
112
|
#### Playwright(ブラウザ自動化)
|
|
60
113
|
|
|
114
|
+
**Claude Code / Gemini CLI:**
|
|
61
115
|
```json
|
|
62
116
|
{
|
|
63
117
|
"mcpServers": {
|
|
@@ -69,10 +123,18 @@ cat ~/.mcp.json 2>/dev/null || echo '(not found)'
|
|
|
69
123
|
}
|
|
70
124
|
```
|
|
71
125
|
|
|
126
|
+
**Codex CLI:**
|
|
127
|
+
```toml
|
|
128
|
+
[mcp_servers.playwright]
|
|
129
|
+
command = "npx"
|
|
130
|
+
args = ["-y", "@playwright/mcp@latest"]
|
|
131
|
+
```
|
|
132
|
+
|
|
72
133
|
`npx -y` により、未インストールでも自動ダウンロード・実行される。事前の `npm install` は不要。
|
|
73
134
|
|
|
74
135
|
#### Supabase(データベース)
|
|
75
136
|
|
|
137
|
+
**Claude Code / Gemini CLI:**
|
|
76
138
|
```json
|
|
77
139
|
{
|
|
78
140
|
"mcpServers": {
|
|
@@ -83,14 +145,20 @@ cat ~/.mcp.json 2>/dev/null || echo '(not found)'
|
|
|
83
145
|
}
|
|
84
146
|
```
|
|
85
147
|
|
|
148
|
+
**Codex CLI:**
|
|
149
|
+
```toml
|
|
150
|
+
[mcp_servers.supabase]
|
|
151
|
+
url = "http://<supabase-host>:54321/mcp?read_only=true&features=database,docs"
|
|
152
|
+
```
|
|
153
|
+
|
|
86
154
|
URL ベースの MCP サーバーは `url` フィールドで指定する(`command`/`args` は不要)。
|
|
87
155
|
|
|
88
156
|
### 注意事項
|
|
89
157
|
|
|
90
|
-
-
|
|
158
|
+
- MCP設定ファイルはLLMから直接編集できる(パーミッション設定ファイルとは異なり書き込み保護がない)
|
|
91
159
|
- `npx -y <package>` 形式を使えば、グローバルインストールなしで MCP サーバーを起動できる
|
|
92
160
|
- サーバー名はスキルの `requires.mcp_servers` と一致させる必要がある(例: `playwright`)
|
|
93
|
-
-
|
|
161
|
+
- Claude Code では `.mcp.json`(プロジェクトルート)が推奨。`~/.claude/settings.json` の `mcpServers` には設定しない
|
|
94
162
|
|
|
95
163
|
---
|
|
96
164
|
|
package/linux/minion-cli.sh
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
# sudo minion-cli restart # Restart agent service (root)
|
|
13
13
|
# minion-cli status # Get current status
|
|
14
14
|
# minion-cli health # Health check
|
|
15
|
+
# minion-cli daemons # Daemon status
|
|
15
16
|
# minion-cli diagnose # Run full service diagnostics
|
|
16
17
|
# minion-cli set-status busy "Running X" # Set status and task
|
|
17
18
|
# minion-cli set-status online # Set status only
|
|
@@ -814,6 +815,7 @@ CFEOF
|
|
|
814
815
|
echo "Useful commands:"
|
|
815
816
|
echo " minion-cli status # Agent status"
|
|
816
817
|
echo " minion-cli health # Health check"
|
|
818
|
+
echo " minion-cli daemons # Daemon status"
|
|
817
819
|
echo " sudo minion-cli restart # Restart agent"
|
|
818
820
|
echo " sudo minion-cli stop # Stop agent"
|
|
819
821
|
if [ "$PROC_MGR" = "systemd" ]; then
|
|
@@ -1219,6 +1221,10 @@ case "${1:-}" in
|
|
|
1219
1221
|
curl -s "$AGENT_URL/api/health" | jq .
|
|
1220
1222
|
;;
|
|
1221
1223
|
|
|
1224
|
+
daemons)
|
|
1225
|
+
curl -s "$AGENT_URL/api/daemons/status" | jq .
|
|
1226
|
+
;;
|
|
1227
|
+
|
|
1222
1228
|
diagnose)
|
|
1223
1229
|
echo "Running diagnostics..."
|
|
1224
1230
|
echo ""
|
package/linux/server.js
CHANGED
|
@@ -43,6 +43,7 @@ const routineStore = require('../core/stores/routine-store')
|
|
|
43
43
|
// Heartbeat interval: fixed at 30s (not user-configurable)
|
|
44
44
|
const HEARTBEAT_INTERVAL_MS = 30_000
|
|
45
45
|
let heartbeatTimer = null
|
|
46
|
+
let lastBeatAt = null
|
|
46
47
|
|
|
47
48
|
// Linux-specific modules
|
|
48
49
|
const workflowRunner = require('./workflow-runner')
|
|
@@ -50,10 +51,14 @@ const routineRunner = require('./routine-runner')
|
|
|
50
51
|
const { cleanupTtyd, killStaleTtydProcesses } = require('./routes/terminal')
|
|
51
52
|
const { startTerminalProxy, stopTerminalProxy } = require('./terminal-proxy')
|
|
52
53
|
|
|
54
|
+
// Config warnings (included in heartbeat)
|
|
55
|
+
const { getConfigWarnings } = require('../core/lib/config-warnings')
|
|
56
|
+
|
|
53
57
|
// Pull-model daemons (from core/)
|
|
54
58
|
const stepPoller = require('../core/lib/step-poller')
|
|
55
59
|
const revisionWatcher = require('../core/lib/revision-watcher')
|
|
56
60
|
const reflectionScheduler = require('../core/lib/reflection-scheduler')
|
|
61
|
+
const threadWatcher = require('../core/lib/thread-watcher')
|
|
57
62
|
const runningTasks = require('../core/lib/running-tasks')
|
|
58
63
|
|
|
59
64
|
// Shared routes (from core/)
|
|
@@ -68,6 +73,8 @@ const { memoryRoutes } = require('../core/routes/memory')
|
|
|
68
73
|
const { dailyLogRoutes } = require('../core/routes/daily-logs')
|
|
69
74
|
const { sudoersRoutes } = require('../core/routes/sudoers')
|
|
70
75
|
const { permissionRoutes } = require('../core/routes/permissions')
|
|
76
|
+
const { helpThreadRoutes } = require('../core/routes/help-threads')
|
|
77
|
+
const { daemonRoutes } = require('../core/routes/daemons')
|
|
71
78
|
|
|
72
79
|
// Linux-specific routes
|
|
73
80
|
const { commandRoutes, getProcessManager, getAllowedCommands } = require('./routes/commands')
|
|
@@ -113,6 +120,7 @@ async function shutdown(signal) {
|
|
|
113
120
|
stepPoller.stop()
|
|
114
121
|
revisionWatcher.stop()
|
|
115
122
|
reflectionScheduler.stop()
|
|
123
|
+
threadWatcher.stop()
|
|
116
124
|
workflowRunner.stopAll()
|
|
117
125
|
routineRunner.stopAll()
|
|
118
126
|
|
|
@@ -270,6 +278,8 @@ async function registerAllRoutes(app) {
|
|
|
270
278
|
await app.register(dailyLogRoutes)
|
|
271
279
|
await app.register(sudoersRoutes)
|
|
272
280
|
await app.register(permissionRoutes)
|
|
281
|
+
await app.register(helpThreadRoutes)
|
|
282
|
+
await app.register(daemonRoutes, { heartbeatStatus: () => ({ running: !!heartbeatTimer, last_beat_at: lastBeatAt }) })
|
|
273
283
|
|
|
274
284
|
// Linux-specific routes
|
|
275
285
|
await app.register(commandRoutes)
|
|
@@ -353,14 +363,16 @@ async function start() {
|
|
|
353
363
|
// Send initial online heartbeat
|
|
354
364
|
const { getStatus } = require('../core/routes/health')
|
|
355
365
|
const { currentTask } = getStatus()
|
|
356
|
-
sendHeartbeat({ status: 'online', current_task: currentTask, running_tasks: runningTasks.getAll(), version }).catch(err => {
|
|
366
|
+
sendHeartbeat({ status: 'online', current_task: currentTask, running_tasks: runningTasks.getAll(), config_warnings: getConfigWarnings(), version }).catch(err => {
|
|
357
367
|
console.error('[Heartbeat] Initial heartbeat failed:', err.message)
|
|
358
368
|
})
|
|
359
369
|
|
|
360
370
|
// Start periodic heartbeat
|
|
361
371
|
heartbeatTimer = setInterval(() => {
|
|
362
372
|
const { currentStatus, currentTask } = getStatus()
|
|
363
|
-
sendHeartbeat({ status: currentStatus, current_task: currentTask, running_tasks: runningTasks.getAll(), version }).
|
|
373
|
+
sendHeartbeat({ status: currentStatus, current_task: currentTask, running_tasks: runningTasks.getAll(), config_warnings: getConfigWarnings(), version }).then(() => {
|
|
374
|
+
lastBeatAt = new Date().toISOString()
|
|
375
|
+
}).catch(err => {
|
|
364
376
|
console.error('[Heartbeat] Periodic heartbeat failed:', err.message)
|
|
365
377
|
})
|
|
366
378
|
}, HEARTBEAT_INTERVAL_MS)
|
|
@@ -369,6 +381,7 @@ async function start() {
|
|
|
369
381
|
// Start Pull-model daemons
|
|
370
382
|
stepPoller.start()
|
|
371
383
|
revisionWatcher.start()
|
|
384
|
+
threadWatcher.start(runQuickLlmCall)
|
|
372
385
|
} else {
|
|
373
386
|
console.log('[Server] Running in standalone mode (no HQ connection)')
|
|
374
387
|
}
|
package/package.json
CHANGED
package/rules/core.md
CHANGED
|
@@ -67,6 +67,51 @@ curl -X POST -H "Authorization: Bearer $API_TOKEN" -H "Content-Type: application
|
|
|
67
67
|
|
|
68
68
|
対応CLI: `claude-code` (.claude/settings.local.json), `gemini` (.gemini/settings.json), `codex` (.codex/config.toml)
|
|
69
69
|
|
|
70
|
+
#### MCP Server Configuration
|
|
71
|
+
|
|
72
|
+
MCPサーバーの設定は各CLIの設定ファイルを直接編集して行う(APIは不要)。
|
|
73
|
+
パーミッション(allow/deny)とは異なり、MCP設定ファイルはLLMから直接編集可能。
|
|
74
|
+
|
|
75
|
+
| CLI | 設定ファイル | 編集方法 |
|
|
76
|
+
|-----|------------|---------|
|
|
77
|
+
| Claude Code | `.mcp.json`(プロジェクトルート) | 直接編集(Write/Edit ツール) |
|
|
78
|
+
| Gemini CLI | `.gemini/settings.json` | 直接編集 |
|
|
79
|
+
| Codex CLI | `.codex/config.toml` | `codex mcp add/remove` コマンドを使用 |
|
|
80
|
+
|
|
81
|
+
**Claude Code** — `.mcp.json` を編集:
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"mcpServers": {
|
|
85
|
+
"playwright": {
|
|
86
|
+
"command": "npx",
|
|
87
|
+
"args": ["-y", "@playwright/mcp@latest"]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Gemini CLI** — `.gemini/settings.json` の `mcpServers` を編集:
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"mcpServers": {
|
|
97
|
+
"playwright": {
|
|
98
|
+
"command": "npx",
|
|
99
|
+
"args": ["-y", "@playwright/mcp@latest"],
|
|
100
|
+
"timeout": 30000
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Codex CLI** — `codex mcp add` コマンド、または `~/.codex/config.toml` を編集:
|
|
107
|
+
```toml
|
|
108
|
+
[mcp_servers.playwright]
|
|
109
|
+
command = "npx"
|
|
110
|
+
args = ["-y", "@playwright/mcp@latest"]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Note: Codex CLI の `.codex/` ディレクトリはLLMからの直接編集が制限される場合がある。その場合は `codex mcp add` コマンドを使用すること。
|
|
114
|
+
|
|
70
115
|
### HQ API
|
|
71
116
|
|
|
72
117
|
`$HQ_URL/api/minion/*` — 認証: `Authorization: Bearer $API_TOKEN`
|