@geekbeer/minion 3.55.1 → 3.58.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/db/migrations/20260510100000_secrets_workspace.js +36 -0
- package/core/db/migrations/20260511100000_variables_workspace.js +37 -0
- package/core/lib/session-env.js +96 -0
- package/core/lib/step-poller.js +8 -3
- package/core/lib/template-expander.js +20 -6
- package/core/routes/variables.js +67 -17
- package/core/stores/variable-store.js +278 -76
- package/docs/api-reference.md +66 -7
- package/linux/routine-runner.js +49 -11
- package/linux/workflow-runner.js +19 -8
- package/package.json +1 -1
- package/roles/engineer.md +3 -1
- package/roles/pm.md +6 -2
- package/rules/core.md +21 -12
- package/win/routine-runner.js +35 -8
- package/win/workflow-runner.js +12 -5
package/roles/engineer.md
CHANGED
|
@@ -28,7 +28,9 @@
|
|
|
28
28
|
|
|
29
29
|
1. **まずプロジェクトメモリーを検索** — `GET /api/project-memories?project_id=...&search=キーワード` で過去の知見を確認
|
|
30
30
|
2. **自己解決不可なら即ヘルプスレッドを起票** — `POST /api/threads` で `thread_type: "help"` を作成。`attempted_resolution` に試したことを記載
|
|
31
|
-
3.
|
|
31
|
+
3. **人間にしか解決できない問題は即エスカレーション** — 認証コード、パスワード、外部承認など
|
|
32
|
+
- 当事者が特定できる場合は **`GET /api/minion/me/project/<project_id>/members` で `user_id` を引いて `mentions: ["user:<auth_user_id>"]` で個別指名** (display_name 重複時の誤通知を避けるため)
|
|
33
|
+
- 誰でも対応可能な問題なら `mentions: ["user"]` (generic)
|
|
32
34
|
4. **解決後はスレッドを resolve し、知見をプロジェクトメモリーに保存**
|
|
33
35
|
|
|
34
36
|
**スキルを失敗終了させる前に、必ずヘルプスレッドでエスカレーションすること。**
|
package/roles/pm.md
CHANGED
|
@@ -48,14 +48,18 @@ PMとして、ブロッカーの解決を主導する責務がある:
|
|
|
48
48
|
|
|
49
49
|
### 自分がブロッカーに遭遇した場合
|
|
50
50
|
1. **プロジェクトメモリーを検索** — 過去の知見で解決できないか確認
|
|
51
|
-
2.
|
|
51
|
+
2. **自己解決不可ならヘルプスレッドを起票** — PMが解決できない問題は人間にエスカレーション
|
|
52
|
+
- 特定の人にしか分からない問題なら **`GET /api/minion/me/project/<project_id>/members` で `user_id` を引いて `mentions: ["user:<auth_user_id>"]` で個別指名**
|
|
53
|
+
- 誰でも良い性質の問題なら `mentions: ["user"]` (generic)
|
|
52
54
|
3. **解決後はスレッドを resolve し、知見をプロジェクトメモリーに保存**
|
|
53
55
|
|
|
54
56
|
### エンジニアからのヘルプスレッドに対応する場合
|
|
55
57
|
1. **thread_watcher が自動で通知するので、`role:pm` 宛のスレッドに回答する**
|
|
56
|
-
2.
|
|
58
|
+
2. **自分で解決できない場合は人間にエスカレーション** — 当事者が特定できるなら個別指名 (`user:<auth_user_id>`)、不明なら `user` (generic)
|
|
57
59
|
3. **解決策が汎用的なら、プロジェクトメモリーへの保存を促す**
|
|
58
60
|
|
|
61
|
+
display_name はワークスペース内で一意とは限らない。同名問題を避けるため、**generic `user` より個別指名 (`user:<id>`) を優先する**こと。`user_id` の取得方法は `~/.minion/docs/api-reference.md` の「Project Members / Workspace Members」セクションを参照。
|
|
62
|
+
|
|
59
63
|
詳細は `~/.minion/rules/core.md` の「Blocker Handling」セクションを参照。
|
|
60
64
|
|
|
61
65
|
## Routine (従来方式)
|
package/rules/core.md
CHANGED
|
@@ -220,10 +220,11 @@ Routine 実行中は以下もtmuxセッション環境で利用可能:
|
|
|
220
220
|
- `MINION_EXECUTION_ID` — 実行UUID
|
|
221
221
|
- `MINION_ROUTINE_ID` — ルーティンUUID
|
|
222
222
|
- `MINION_ROUTINE_NAME` — ルーティン名
|
|
223
|
+
- `MINION_ROUTINE_WORKSPACE_ID` — ルーティンが特定ワークスペースにバインドされている場合のワークスペースUUID(未バインドなら空文字)
|
|
223
224
|
|
|
224
|
-
|
|
225
|
+
**変数**(ワークスペース変数・プロジェクト変数・ワークフロー変数・ミニオン変数)はスキル本文の `{{VAR_NAME}}` テンプレートとして実行時に展開される。スキル作成時にパラメータ化したい値は `{{変数名}}` で記述すること。展開優先順位: ワークスペース < プロジェクト < ワークフロー < ミニオン(後者が優先)。ミニオンが最終オーバーライドとなる設計で、ミニオン運用者がHQ側のデフォルトを差し替えられる経路を保証する。ミニオン変数はさらにミニオン全体スコープとワークスペース別スコープに分かれ、当該ワークスペースのコンテキストで動く実行時はWS別がミニオン全体を上書きする。`/api/variables/*` は `?workspace_id=<uuid>` でスコープ指定(省略時はミニオン全体)。
|
|
225
226
|
|
|
226
|
-
|
|
227
|
+
**シークレット**はワークスペース別にスコープされ、ミニオンローカルのSQLite (`secrets(workspace_id, key, value)`) に保存される。ワークスペース未指定(`workspace_id=''`)はミニオン全体のスコープで、サーバー起動時に `process.env` にロードされ全子プロセスで `$SECRET_NAME` として利用可能。ワークスペース別シークレット(`workspace_id=<uuid>`)は `process.env` にはロードされず、当該ワークスペースのコンテキストで動くランナー(ワークフロー/WSバインドされたルーティン/チャットセッション)にのみ実行時注入される。同名キーが両スコープに存在する場合はワークスペース別が優先。スキル側は常に `$KEY` で参照すればよく、どちらのスコープから来た値かを意識する必要はない。シークレット値はHQ DBに保存されることはなく、HQはpass-throughとして中継するのみ。
|
|
227
228
|
|
|
228
229
|
デイリーログやメモリーから変数・シークレットの値を推測して使用してはならない。変数は `{{VAR_NAME}}` テンプレートとして定義し、シークレットは環境変数として参照すること。
|
|
229
230
|
|
|
@@ -321,7 +322,8 @@ API詳細は `~/.minion/docs/api-reference.md` の「Todos」セクションを
|
|
|
321
322
|
"thread_type": "help",
|
|
322
323
|
"title": "問題の要約(1行)",
|
|
323
324
|
"content": "状況の詳細説明",
|
|
324
|
-
"mentions": ["
|
|
325
|
+
"mentions": ["user:<auth_user_id>"], // 特定の人に聞くなら個別指名 (推奨)
|
|
326
|
+
// 誰でも良いなら ["user"] / ["role:pm"] 等
|
|
325
327
|
"context": {
|
|
326
328
|
"category": "auth|environment|external-service|information|approval",
|
|
327
329
|
"attempted_resolution": "試行した内容"
|
|
@@ -335,7 +337,7 @@ API詳細は `~/.minion/docs/api-reference.md` の「Todos」セクションを
|
|
|
335
337
|
"thread_type": "help",
|
|
336
338
|
"title": "問題の要約(1行)",
|
|
337
339
|
"content": "状況の詳細説明",
|
|
338
|
-
"mentions": ["user"],
|
|
340
|
+
"mentions": ["user:<auth_user_id>"], // 個別指名 (推奨)。誰でも良いなら ["user"]
|
|
339
341
|
"context": {
|
|
340
342
|
"category": "auth|environment|external-service|information|approval",
|
|
341
343
|
"attempted_resolution": "試行した内容"
|
|
@@ -365,18 +367,25 @@ API詳細は `~/.minion/docs/api-reference.md` の「Todos」セクションを
|
|
|
365
367
|
|
|
366
368
|
### メンションの使い分け
|
|
367
369
|
|
|
368
|
-
| 状況 | メンション |
|
|
369
|
-
|
|
370
|
-
|
|
|
371
|
-
|
|
|
372
|
-
|
|
|
373
|
-
|
|
|
374
|
-
|
|
|
370
|
+
| 状況 | メンション | 備考 |
|
|
371
|
+
|------|-----------|------|
|
|
372
|
+
| 特定の人間を指名(推奨) | `["user:<auth_user_id>"]` | 事前に Members API で `user_id` を解決すること |
|
|
373
|
+
| PMに判断を仰ぐ | `["role:pm"]` | プロジェクト紐づきスレッドのみ有効 |
|
|
374
|
+
| エンジニアの知見が必要 | `["role:engineer"]` | プロジェクト紐づきスレッドのみ有効 |
|
|
375
|
+
| 特定ミニオンに聞く | `["minion:<minion_id>"]` | |
|
|
376
|
+
| 誰でも良いから人間に聞く | `["user"]` | プロジェクト紐づきならプロジェクト人間メンバー、紐づきがなければワークスペース人間メンバー全員 |
|
|
377
|
+
| チーム全体に共有 | `[]`(メンションなし) | |
|
|
378
|
+
|
|
379
|
+
**人間メンバーの user_id 解決:**
|
|
380
|
+
- プロジェクト紐づきスレッド: `GET /api/minion/me/project/<project_id>/members` で `humans[].user_id` を取得
|
|
381
|
+
- ワークスペーススレッド: `GET /api/minion/workspaces/<workspace_id>/members` で `humans[].user_id` を取得
|
|
382
|
+
|
|
383
|
+
display_name が同じユーザーが同一ワークスペースに複数いる可能性があるため、原則として個別指名 (`user:<id>`) を優先する。「誰でも良い」場合のみ generic `user` を使う。
|
|
375
384
|
|
|
376
385
|
### 重要なルール
|
|
377
386
|
|
|
378
387
|
- **スレッド起票時は `attempted_resolution` を必ず含める。** 何を試したか不明だと、回答者が同じことを提案してしまう。
|
|
379
|
-
-
|
|
388
|
+
- **人間にしか解決できない問題(認証コード入力、外部サービスのパスワード等)は即メンション付き** で起票する。自己解決を試みて時間を浪費しないこと。特定の人にしか分からないことなら個別指名 (`user:<id>`)、誰でも良い性質の問題なら `user`(generic) を使う。
|
|
380
389
|
- **ブロッカーが解決したらスレッドを `resolve` する。** 放置しない。
|
|
381
390
|
- **解決策をプロジェクトメモリーに保存する。** 同じブロッカーに再度遭遇する他のミニオンの助けになる。
|
|
382
391
|
|
package/win/routine-runner.js
CHANGED
|
@@ -12,12 +12,14 @@ const { stripAnsi } = require('../core/lib/strip-ansi')
|
|
|
12
12
|
const fs = require('fs').promises
|
|
13
13
|
const fsSync = require('fs')
|
|
14
14
|
|
|
15
|
-
const { config } = require('../core/config')
|
|
15
|
+
const { config, isHqConfigured } = require('../core/config')
|
|
16
|
+
const api = require('../core/api')
|
|
16
17
|
const executionStore = require('../core/stores/execution-store')
|
|
17
18
|
const routineStore = require('../core/stores/routine-store')
|
|
18
19
|
const logManager = require('../core/lib/log-manager')
|
|
19
20
|
const { activeSessions } = require('./workflow-runner')
|
|
20
21
|
const { expandSkillTemplates, restoreSkillTemplates } = require('../core/lib/template-expander')
|
|
22
|
+
const { buildSpawnEnv } = require('../core/lib/session-env')
|
|
21
23
|
const { getActivePrimary } = require('../core/llm-plugins/lib/active')
|
|
22
24
|
const os = require('os')
|
|
23
25
|
|
|
@@ -28,6 +30,25 @@ function sleep(ms) {
|
|
|
28
30
|
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
29
31
|
}
|
|
30
32
|
|
|
33
|
+
/**
|
|
34
|
+
* Fetch workspace-scoped variables for a routine from HQ.
|
|
35
|
+
* Mirrors the Linux runner; see that file for full docs.
|
|
36
|
+
*/
|
|
37
|
+
async function fetchWorkspaceVars(workspaceId) {
|
|
38
|
+
if (!workspaceId || !isHqConfigured()) return {}
|
|
39
|
+
try {
|
|
40
|
+
const result = await api.request(`/workspaces/${workspaceId}/variables`)
|
|
41
|
+
const vars = {}
|
|
42
|
+
for (const v of (result?.variables || [])) {
|
|
43
|
+
if (v && typeof v.key === 'string') vars[v.key] = String(v.value ?? '')
|
|
44
|
+
}
|
|
45
|
+
return vars
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.error(`[RoutineRunner] Failed to fetch workspace vars (${workspaceId}): ${err.message}`)
|
|
48
|
+
return {}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
31
52
|
function generateSessionName(routineId, executionId) {
|
|
32
53
|
const routineShort = routineId ? routineId.substring(0, 8) : 'manual'
|
|
33
54
|
const execShort = executionId ? executionId.substring(0, 4) : ''
|
|
@@ -67,10 +88,15 @@ async function executeRoutineSession(routine, executionId, skillNames) {
|
|
|
67
88
|
console.log(`[RoutineRunner] Session: ${sessionName}`)
|
|
68
89
|
console.log(`[RoutineRunner] Log file: ${logFile}`)
|
|
69
90
|
|
|
70
|
-
//
|
|
91
|
+
// Fetch HQ workspace variables when the routine is bound to a workspace.
|
|
92
|
+
// Minion variables (minion-wide ∪ WS-scoped, resolved inside the expander
|
|
93
|
+
// via workspaceId) override these as the final layer.
|
|
94
|
+
const workspaceVars = await fetchWorkspaceVars(routine.workspace_id)
|
|
95
|
+
|
|
96
|
+
// Expand {{VAR}} templates in SKILL.md files
|
|
71
97
|
let expandedOriginals = new Map()
|
|
72
98
|
try {
|
|
73
|
-
expandedOriginals = await expandSkillTemplates(skillNames)
|
|
99
|
+
expandedOriginals = await expandSkillTemplates(skillNames, workspaceVars, routine.workspace_id || '')
|
|
74
100
|
if (expandedOriginals.size > 0) {
|
|
75
101
|
console.log(`[RoutineRunner] Expanded templates in ${expandedOriginals.size} skill(s)`)
|
|
76
102
|
}
|
|
@@ -101,14 +127,15 @@ async function executeRoutineSession(routine, executionId, skillNames) {
|
|
|
101
127
|
throw new Error('No LLM configured. Set a Primary plugin via /api/llm/config or LLM_COMMAND in minion.env')
|
|
102
128
|
}
|
|
103
129
|
|
|
104
|
-
// PATH, HOME, USERPROFILE
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
130
|
+
// PATH, HOME, USERPROFILE are inherited; workspace-scoped secrets are
|
|
131
|
+
// merged in via buildSpawnEnv() so a routine only sees secrets relevant
|
|
132
|
+
// to the workspace it is bound to.
|
|
133
|
+
const env = buildSpawnEnv(routine.workspace_id || '', {
|
|
108
134
|
MINION_EXECUTION_ID: executionId,
|
|
109
135
|
MINION_ROUTINE_ID: routine.id,
|
|
110
136
|
MINION_ROUTINE_NAME: routine.name,
|
|
111
|
-
|
|
137
|
+
MINION_ROUTINE_WORKSPACE_ID: routine.workspace_id || '',
|
|
138
|
+
})
|
|
112
139
|
|
|
113
140
|
const logDir = path.dirname(logFile)
|
|
114
141
|
await fs.mkdir(logDir, { recursive: true })
|
package/win/workflow-runner.js
CHANGED
|
@@ -24,6 +24,7 @@ const executionStore = require('../core/stores/execution-store')
|
|
|
24
24
|
const workflowStore = require('../core/stores/workflow-store')
|
|
25
25
|
const logManager = require('../core/lib/log-manager')
|
|
26
26
|
const { expandSkillTemplates, restoreSkillTemplates } = require('../core/lib/template-expander')
|
|
27
|
+
const { buildSpawnEnv } = require('../core/lib/session-env')
|
|
27
28
|
const { getActivePrimary } = require('../core/llm-plugins/lib/active')
|
|
28
29
|
const os = require('os')
|
|
29
30
|
|
|
@@ -142,10 +143,11 @@ async function executeWorkflowSession(workflow, executionId, skillNames, options
|
|
|
142
143
|
console.log(`[WorkflowRunner] Log file: ${logFile}`)
|
|
143
144
|
console.log(`[WorkflowRunner] HOME: ${homeDir}`)
|
|
144
145
|
|
|
145
|
-
// Expand {{VAR}} templates in SKILL.md files with minion variables
|
|
146
|
+
// Expand {{VAR}} templates in SKILL.md files with minion variables effective
|
|
147
|
+
// for this workflow's workspace (minion-wide ∪ WS-scoped, WS wins).
|
|
146
148
|
let expandedOriginals = new Map()
|
|
147
149
|
try {
|
|
148
|
-
expandedOriginals = await expandSkillTemplates(skillNames)
|
|
150
|
+
expandedOriginals = await expandSkillTemplates(skillNames, {}, workflow.workspace_id || '')
|
|
149
151
|
if (expandedOriginals.size > 0) {
|
|
150
152
|
console.log(`[WorkflowRunner] Expanded templates in ${expandedOriginals.size} skill(s)`)
|
|
151
153
|
}
|
|
@@ -178,8 +180,9 @@ async function executeWorkflowSession(workflow, executionId, skillNames, options
|
|
|
178
180
|
throw new Error('No LLM configured. Set a Primary plugin via /api/llm/config or LLM_COMMAND in minion.env')
|
|
179
181
|
}
|
|
180
182
|
|
|
181
|
-
// PATH, HOME, USERPROFILE
|
|
182
|
-
//
|
|
183
|
+
// PATH, HOME, USERPROFILE are inherited from process.env (set at startup);
|
|
184
|
+
// workspace-scoped secrets are merged in via buildSpawnEnv() so this
|
|
185
|
+
// session only sees secrets relevant to its workspace context.
|
|
183
186
|
|
|
184
187
|
// Open log file for streaming writes
|
|
185
188
|
const logDir = path.dirname(logFile)
|
|
@@ -195,7 +198,11 @@ async function executeWorkflowSession(workflow, executionId, skillNames, options
|
|
|
195
198
|
cols: 200,
|
|
196
199
|
rows: 50,
|
|
197
200
|
cwd: homeDir,
|
|
198
|
-
env:
|
|
201
|
+
env: buildSpawnEnv(workflow.workspace_id || '', {
|
|
202
|
+
MINION_EXECUTION_ID: executionId,
|
|
203
|
+
MINION_WORKFLOW_ID: workflow.id || '',
|
|
204
|
+
MINION_WORKFLOW_WORKSPACE_ID: workflow.workspace_id || '',
|
|
205
|
+
}),
|
|
199
206
|
})
|
|
200
207
|
|
|
201
208
|
// Track session
|