@geekbeer/minion 2.50.2 → 2.53.2
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/lib/capability-checker.js +27 -4
- package/core/routes/health.js +14 -1
- package/core/routes/skills.js +16 -9
- package/core/routes/workflows.js +5 -0
- package/core/stores/workflow-store.js +5 -1
- package/linux/routes/chat.js +18 -16
- package/package.json +1 -1
- package/win/routes/chat.js +18 -17
|
@@ -11,6 +11,7 @@ const path = require('path')
|
|
|
11
11
|
const { execSync } = require('child_process')
|
|
12
12
|
const { config } = require('../config')
|
|
13
13
|
const { IS_WINDOWS, buildExtendedPath } = require('./platform')
|
|
14
|
+
const variableStore = require('../stores/variable-store')
|
|
14
15
|
|
|
15
16
|
const CACHE_TTL_MS = 300000 // 5 minutes
|
|
16
17
|
|
|
@@ -79,8 +80,19 @@ function checkTool(name) {
|
|
|
79
80
|
const TOOL_NAMES = ['git', 'node', 'npx', 'claude', 'docker', 'tmux']
|
|
80
81
|
|
|
81
82
|
/**
|
|
82
|
-
* Get all
|
|
83
|
-
*
|
|
83
|
+
* Get all available environment variable keys (variables + secrets).
|
|
84
|
+
* Returns deduplicated key names without values (secrets stay hidden).
|
|
85
|
+
* @returns {string[]}
|
|
86
|
+
*/
|
|
87
|
+
function getEnvVarKeys() {
|
|
88
|
+
const varKeys = variableStore.listKeys('variables')
|
|
89
|
+
const secretKeys = variableStore.listKeys('secrets')
|
|
90
|
+
return [...new Set([...varKeys, ...secretKeys])]
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get all capabilities (MCP servers + CLI tools + env var keys), cached for 5 minutes.
|
|
95
|
+
* @returns {{ mcp_servers: { name: string, configured: boolean }[], cli_tools: { name: string, available: boolean, version?: string }[], env_var_keys: string[] }}
|
|
84
96
|
*/
|
|
85
97
|
function getCapabilities() {
|
|
86
98
|
const now = Date.now()
|
|
@@ -90,8 +102,9 @@ function getCapabilities() {
|
|
|
90
102
|
|
|
91
103
|
const mcp_servers = getMcpServers()
|
|
92
104
|
const cli_tools = TOOL_NAMES.map(name => checkTool(name))
|
|
105
|
+
const env_var_keys = getEnvVarKeys()
|
|
93
106
|
|
|
94
|
-
cachedResult = { mcp_servers, cli_tools }
|
|
107
|
+
cachedResult = { mcp_servers, cli_tools, env_var_keys }
|
|
95
108
|
cachedAt = now
|
|
96
109
|
return cachedResult
|
|
97
110
|
}
|
|
@@ -102,4 +115,14 @@ function clearCapabilityCache() {
|
|
|
102
115
|
cachedAt = 0
|
|
103
116
|
}
|
|
104
117
|
|
|
105
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Check arbitrary tool names on-demand (not cached).
|
|
120
|
+
* Used by readiness checks to verify skill-declared cli_tools.
|
|
121
|
+
* @param {string[]} names - Tool names to check
|
|
122
|
+
* @returns {{ name: string, available: boolean, version?: string }[]}
|
|
123
|
+
*/
|
|
124
|
+
function checkTools(names) {
|
|
125
|
+
return names.map(name => checkTool(name))
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
module.exports = { getCapabilities, clearCapabilityCache, checkTools }
|
package/core/routes/health.js
CHANGED
|
@@ -5,13 +5,14 @@
|
|
|
5
5
|
* - GET /api/health - Health check
|
|
6
6
|
* - GET /api/status - Get current status
|
|
7
7
|
* - POST /api/status - Update status
|
|
8
|
+
* - POST /api/capabilities/check-tools - Check arbitrary CLI tools on-demand
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
const { version } = require('../../package.json')
|
|
11
12
|
const { config, isHqConfigured } = require('../config')
|
|
12
13
|
const { sendHeartbeat } = require('../api')
|
|
13
14
|
const { getLlmServices, isLlmCommandConfigured } = require('../lib/llm-checker')
|
|
14
|
-
const { getCapabilities } = require('../lib/capability-checker')
|
|
15
|
+
const { getCapabilities, checkTools } = require('../lib/capability-checker')
|
|
15
16
|
|
|
16
17
|
function maskToken(token) {
|
|
17
18
|
if (!token || token.length < 8) return token ? '***' : ''
|
|
@@ -105,6 +106,18 @@ async function healthRoutes(fastify) {
|
|
|
105
106
|
|
|
106
107
|
return { success: true }
|
|
107
108
|
})
|
|
109
|
+
|
|
110
|
+
// Check arbitrary CLI tools on-demand
|
|
111
|
+
fastify.post('/api/capabilities/check-tools', async (request, reply) => {
|
|
112
|
+
const { tools } = request.body || {}
|
|
113
|
+
if (!Array.isArray(tools) || tools.length === 0) {
|
|
114
|
+
reply.code(400)
|
|
115
|
+
return { error: 'tools must be a non-empty array of tool names' }
|
|
116
|
+
}
|
|
117
|
+
// Limit to 20 tools per request to avoid abuse
|
|
118
|
+
const limited = tools.slice(0, 20).filter(t => typeof t === 'string' && t.length > 0)
|
|
119
|
+
return { cli_tools: checkTools(limited) }
|
|
120
|
+
})
|
|
108
121
|
}
|
|
109
122
|
|
|
110
123
|
module.exports = {
|
package/core/routes/skills.js
CHANGED
|
@@ -58,17 +58,24 @@ async function writeSkillToLocal(name, { content, description, display_name, typ
|
|
|
58
58
|
await fs.mkdir(skillDir, { recursive: true })
|
|
59
59
|
await fs.mkdir(filesDir, { recursive: true })
|
|
60
60
|
|
|
61
|
-
//
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
61
|
+
// If content already has frontmatter, write as-is; otherwise build frontmatter
|
|
62
|
+
const hasFrontmatter = content.startsWith('---\n')
|
|
63
|
+
let fileContent
|
|
64
|
+
if (hasFrontmatter) {
|
|
65
|
+
fileContent = content
|
|
66
|
+
} else {
|
|
67
|
+
const frontmatterLines = [
|
|
68
|
+
`name: ${name}`,
|
|
69
|
+
display_name ? `display_name: ${display_name}` : null,
|
|
70
|
+
type ? `type: ${type}` : null,
|
|
71
|
+
`description: ${description || ''}`,
|
|
72
|
+
].filter(Boolean).join('\n')
|
|
73
|
+
fileContent = `---\n${frontmatterLines}\n---\n\n${content}`
|
|
74
|
+
}
|
|
68
75
|
|
|
69
76
|
await fs.writeFile(
|
|
70
77
|
path.join(skillDir, 'SKILL.md'),
|
|
71
|
-
|
|
78
|
+
fileContent,
|
|
72
79
|
'utf-8'
|
|
73
80
|
)
|
|
74
81
|
|
|
@@ -128,7 +135,7 @@ async function pushSkillToHQ(name) {
|
|
|
128
135
|
name: metadata.name || name,
|
|
129
136
|
display_name: metadata.display_name || metadata.name || name,
|
|
130
137
|
description: metadata.description || '',
|
|
131
|
-
content:
|
|
138
|
+
content: rawContent,
|
|
132
139
|
type: metadata.type || 'workflow',
|
|
133
140
|
files,
|
|
134
141
|
}),
|
package/core/routes/workflows.js
CHANGED
|
@@ -176,6 +176,7 @@ async function workflowRoutes(fastify, opts) {
|
|
|
176
176
|
pipeline_skill_names: pipelineSkillNames,
|
|
177
177
|
content: workflow.content || '',
|
|
178
178
|
project_id: effectiveProjectId,
|
|
179
|
+
...(workflow.pipeline_steps?.length > 0 && { pipeline_steps: workflow.pipeline_steps }),
|
|
179
180
|
}),
|
|
180
181
|
})
|
|
181
182
|
|
|
@@ -244,6 +245,10 @@ async function workflowRoutes(fastify, opts) {
|
|
|
244
245
|
const updatedWorkflows = await workflowStore.upsertByName({
|
|
245
246
|
name: workflow.name,
|
|
246
247
|
pipeline_skill_names: workflow.pipeline_skill_names,
|
|
248
|
+
pipeline_steps: (workflow.pipeline || []).map(step => ({
|
|
249
|
+
assigned_role: step.assigned_role,
|
|
250
|
+
requires_review: step.requires_review || false,
|
|
251
|
+
})),
|
|
247
252
|
content: workflow.content || '',
|
|
248
253
|
project_id: workflow.project_id || null,
|
|
249
254
|
})
|
|
@@ -82,7 +82,7 @@ async function findByName(name) {
|
|
|
82
82
|
* Upsert a workflow by name.
|
|
83
83
|
* If exists: updates definition only (preserves schedule/local state).
|
|
84
84
|
* If new: creates with inactive schedule.
|
|
85
|
-
* @param {object} workflowData - { name, pipeline_skill_names, content, project_id }
|
|
85
|
+
* @param {object} workflowData - { name, pipeline_skill_names, pipeline_steps, content, project_id }
|
|
86
86
|
* @returns {Promise<Array>} Updated workflows array
|
|
87
87
|
*/
|
|
88
88
|
async function upsertByName(workflowData) {
|
|
@@ -99,11 +99,15 @@ async function upsertByName(workflowData) {
|
|
|
99
99
|
if (workflowData.project_id !== undefined) {
|
|
100
100
|
workflows[index].project_id = workflowData.project_id
|
|
101
101
|
}
|
|
102
|
+
if (workflowData.pipeline_steps !== undefined) {
|
|
103
|
+
workflows[index].pipeline_steps = workflowData.pipeline_steps
|
|
104
|
+
}
|
|
102
105
|
} else {
|
|
103
106
|
workflows.push({
|
|
104
107
|
id: crypto.randomUUID(),
|
|
105
108
|
name: workflowData.name,
|
|
106
109
|
pipeline_skill_names: workflowData.pipeline_skill_names,
|
|
110
|
+
pipeline_steps: workflowData.pipeline_steps || [],
|
|
107
111
|
content: workflowData.content || '',
|
|
108
112
|
project_id: workflowData.project_id || null,
|
|
109
113
|
cron_expression: '',
|
package/linux/routes/chat.js
CHANGED
|
@@ -22,9 +22,8 @@ const path = require('path')
|
|
|
22
22
|
const { verifyToken } = require('../../core/lib/auth')
|
|
23
23
|
const { config } = require('../../core/config')
|
|
24
24
|
const chatStore = require('../../core/stores/chat-store')
|
|
25
|
-
const memoryStore = require('../../core/stores/memory-store')
|
|
26
|
-
const dailyLogStore = require('../../core/stores/daily-log-store')
|
|
27
25
|
const { runEndOfDay } = require('../../core/lib/end-of-day')
|
|
26
|
+
const { DATA_DIR } = require('../../core/lib/platform')
|
|
28
27
|
|
|
29
28
|
/** @type {import('child_process').ChildProcess | null} */
|
|
30
29
|
let activeChatChild = null
|
|
@@ -205,21 +204,24 @@ async function chatRoutes(fastify) {
|
|
|
205
204
|
async function buildContextPrefix(message, context, sessionId) {
|
|
206
205
|
const parts = []
|
|
207
206
|
|
|
208
|
-
//
|
|
207
|
+
// Tell the LLM where to find memory and daily logs (content is NOT injected)
|
|
209
208
|
if (!sessionId) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
209
|
+
const memoryDir = require('path').join(DATA_DIR, 'memory')
|
|
210
|
+
const dailyLogDir = require('path').join(DATA_DIR, 'daily-logs')
|
|
211
|
+
parts.push(
|
|
212
|
+
'[長期記憶・デイリーログについて]',
|
|
213
|
+
'あなたには長期記憶(メモリ)とデイリーログがあります。内容は毎回読み込まれません。',
|
|
214
|
+
'必要なときだけ以下のファイルを読んで参照してください:',
|
|
215
|
+
`- メモリ索引: ${memoryDir}/MEMORY.md(概要一覧。詳細は個別の .md ファイルを読む)`,
|
|
216
|
+
`- デイリーログ: ${dailyLogDir}/YYYY-MM-DD.md(日付別の作業記録)`,
|
|
217
|
+
'',
|
|
218
|
+
'参照すべきタイミング:',
|
|
219
|
+
'- 過去の作業や決定事項を思い出す必要があるとき',
|
|
220
|
+
'- ユーザーの好みやフィードバックを確認したいとき',
|
|
221
|
+
'- 以前の作業の続きをするとき',
|
|
222
|
+
'- わからないことがあり、過去に記録した情報が役立ちそうなとき',
|
|
223
|
+
''
|
|
224
|
+
)
|
|
223
225
|
}
|
|
224
226
|
|
|
225
227
|
if (context) {
|
package/package.json
CHANGED
package/win/routes/chat.js
CHANGED
|
@@ -18,9 +18,7 @@ const path = require('path')
|
|
|
18
18
|
const { verifyToken } = require('../../core/lib/auth')
|
|
19
19
|
const { config } = require('../../core/config')
|
|
20
20
|
const chatStore = require('../../core/stores/chat-store')
|
|
21
|
-
const
|
|
22
|
-
const dailyLogStore = require('../../core/stores/daily-log-store')
|
|
23
|
-
const { buildExtendedPath } = require('../../core/lib/platform')
|
|
21
|
+
const { buildExtendedPath, DATA_DIR } = require('../../core/lib/platform')
|
|
24
22
|
const { runEndOfDay } = require('../../core/lib/end-of-day')
|
|
25
23
|
|
|
26
24
|
let activeChatChild = null
|
|
@@ -168,21 +166,24 @@ async function chatRoutes(fastify) {
|
|
|
168
166
|
async function buildContextPrefix(message, context, sessionId) {
|
|
169
167
|
const parts = []
|
|
170
168
|
|
|
171
|
-
//
|
|
169
|
+
// Tell the LLM where to find memory and daily logs (content is NOT injected)
|
|
172
170
|
if (!sessionId) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
171
|
+
const memoryDir = require('path').join(DATA_DIR, 'memory')
|
|
172
|
+
const dailyLogDir = require('path').join(DATA_DIR, 'daily-logs')
|
|
173
|
+
parts.push(
|
|
174
|
+
'[長期記憶・デイリーログについて]',
|
|
175
|
+
'あなたには長期記憶(メモリ)とデイリーログがあります。内容は毎回読み込まれません。',
|
|
176
|
+
'必要なときだけ以下のファイルを読んで参照してください:',
|
|
177
|
+
`- メモリ索引: ${memoryDir}/MEMORY.md(概要一覧。詳細は個別の .md ファイルを読む)`,
|
|
178
|
+
`- デイリーログ: ${dailyLogDir}/YYYY-MM-DD.md(日付別の作業記録)`,
|
|
179
|
+
'',
|
|
180
|
+
'参照すべきタイミング:',
|
|
181
|
+
'- 過去の作業や決定事項を思い出す必要があるとき',
|
|
182
|
+
'- ユーザーの好みやフィードバックを確認したいとき',
|
|
183
|
+
'- 以前の作業の続きをするとき',
|
|
184
|
+
'- わからないことがあり、過去に記録した情報が役立ちそうなとき',
|
|
185
|
+
''
|
|
186
|
+
)
|
|
186
187
|
}
|
|
187
188
|
|
|
188
189
|
if (context) {
|