@geekbeer/minion 2.48.3 → 2.49.1

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.
@@ -48,15 +48,15 @@ function parseFrontmatter(content) {
48
48
  * @param {string} opts.content - Skill body (markdown without frontmatter)
49
49
  * @param {string} [opts.description] - Skill description for frontmatter
50
50
  * @param {string} [opts.display_name] - Display name for frontmatter
51
- * @param {Array<{filename: string, content: string}>} [opts.references] - Reference files
52
- * @returns {Promise<{path: string, references_count: number}>}
51
+ * @param {Array<{path: string, content?: string}>} [opts.files] - Skill files from HQ storage
52
+ * @returns {Promise<{path: string, files_count: number}>}
53
53
  */
54
- async function writeSkillToLocal(name, { content, description, display_name, type, references = [] }) {
54
+ async function writeSkillToLocal(name, { content, description, display_name, type, files = [] }) {
55
55
  const skillDir = path.join(config.HOME_DIR, '.claude', 'skills', name)
56
- const referencesDir = path.join(skillDir, 'references')
56
+ const filesDir = path.join(skillDir, 'files')
57
57
 
58
58
  await fs.mkdir(skillDir, { recursive: true })
59
- await fs.mkdir(referencesDir, { recursive: true })
59
+ await fs.mkdir(filesDir, { recursive: true })
60
60
 
61
61
  // Build frontmatter with all available metadata
62
62
  const frontmatterLines = [
@@ -72,15 +72,15 @@ async function writeSkillToLocal(name, { content, description, display_name, typ
72
72
  'utf-8'
73
73
  )
74
74
 
75
- // Write reference files
76
- for (const ref of references) {
77
- if (ref.filename && ref.content) {
78
- const safeFilename = path.basename(ref.filename)
79
- await fs.writeFile(path.join(referencesDir, safeFilename), ref.content, 'utf-8')
75
+ // Write skill files
76
+ for (const file of files) {
77
+ if (file.path && file.content) {
78
+ const safeFilename = path.basename(file.path)
79
+ await fs.writeFile(path.join(filesDir, safeFilename), file.content, 'utf-8')
80
80
  }
81
81
  }
82
82
 
83
- return { path: skillDir, references_count: references.length }
83
+ return { path: skillDir, files_count: files.length }
84
84
  }
85
85
 
86
86
  /**
@@ -99,17 +99,27 @@ async function pushSkillToHQ(name) {
99
99
  const rawContent = await fs.readFile(skillMdPath, 'utf-8')
100
100
  const { metadata, body } = parseFrontmatter(rawContent)
101
101
 
102
- // Read references
103
- const referencesDir = path.join(skillDir, 'references')
104
- const references = []
102
+ // Read skill files
103
+ const filesDir = path.join(skillDir, 'files')
104
+ const files = []
105
105
  try {
106
- const refEntries = await fs.readdir(referencesDir)
107
- for (const filename of refEntries) {
108
- const refContent = await fs.readFile(path.join(referencesDir, filename), 'utf-8')
109
- references.push({ filename, content: refContent })
106
+ const fileEntries = await fs.readdir(filesDir)
107
+ for (const filename of fileEntries) {
108
+ const fileContent = await fs.readFile(path.join(filesDir, filename), 'utf-8')
109
+ files.push({ path: filename, content: fileContent })
110
110
  }
111
111
  } catch {
112
- // No references directory
112
+ // No files directory — try legacy references/ for backward compatibility
113
+ try {
114
+ const legacyDir = path.join(skillDir, 'references')
115
+ const legacyEntries = await fs.readdir(legacyDir)
116
+ for (const filename of legacyEntries) {
117
+ const fileContent = await fs.readFile(path.join(legacyDir, filename), 'utf-8')
118
+ files.push({ path: filename, content: fileContent })
119
+ }
120
+ } catch {
121
+ // No files at all
122
+ }
113
123
  }
114
124
 
115
125
  return api.request('/skills', {
@@ -120,7 +130,7 @@ async function pushSkillToHQ(name) {
120
130
  description: metadata.description || '',
121
131
  content: body,
122
132
  type: metadata.type || 'workflow',
123
- references,
133
+ files,
124
134
  }),
125
135
  })
126
136
  }
@@ -243,7 +253,7 @@ async function skillRoutes(fastify, opts) {
243
253
  description: skill.description,
244
254
  display_name: skill.display_name,
245
255
  type: skill.type,
246
- references: skill.references || [],
256
+ files: skill.files || [],
247
257
  })
248
258
 
249
259
  console.log(`[Skills] Skill fetched and deployed: ${name}`)
@@ -277,6 +277,23 @@ async function runWorkflow(workflow, options = {}) {
277
277
  log_file: logFile,
278
278
  })
279
279
 
280
+ // Extract summary from execution log file (captured via tmux pipe-pane)
281
+ let summary = result.success
282
+ ? `All skills completed successfully: ${pipelineSkillNames.join(', ')}`
283
+ : `Workflow failed: ${result.error || 'unknown error'}`
284
+ try {
285
+ const logData = await logManager.readLog(executionId, { tail: 200 })
286
+ if (logData && logData.content && logData.content.trim().length > 0) {
287
+ const MAX_SUMMARY_LENGTH = 10000
288
+ const content = logData.content.trim()
289
+ summary = content.length > MAX_SUMMARY_LENGTH
290
+ ? content.slice(-MAX_SUMMARY_LENGTH)
291
+ : content
292
+ }
293
+ } catch (err) {
294
+ console.error(`[WorkflowRunner] Failed to read log for summary: ${err.message}`)
295
+ }
296
+
280
297
  // Report outcome via local API (same data the execution-report skill used to send)
281
298
  try {
282
299
  const resp = await fetch(`http://localhost:${config.AGENT_PORT || 8080}/api/executions/${executionId}/outcome`, {
@@ -284,9 +301,7 @@ async function runWorkflow(workflow, options = {}) {
284
301
  headers: { 'Content-Type': 'application/json' },
285
302
  body: JSON.stringify({
286
303
  outcome,
287
- summary: result.success
288
- ? `All skills completed successfully: ${pipelineSkillNames.join(', ')}`
289
- : `Workflow failed: ${result.error || 'unknown error'}`,
304
+ summary,
290
305
  }),
291
306
  })
292
307
  if (!resp.ok) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekbeer/minion",
3
- "version": "2.48.3",
3
+ "version": "2.49.1",
4
4
  "description": "AI Agent runtime for Minion - manages status and skill deployment on VPS",
5
5
  "main": "linux/server.js",
6
6
  "bin": {
@@ -183,12 +183,19 @@ async function executeWorkflowSession(workflow, executionId, skillNames, options
183
183
  // Close log stream
184
184
  try { logStream.end() } catch { /* ignore */ }
185
185
 
186
+ // Capture output for summary
187
+ const MAX_SUMMARY_LENGTH = 10000
188
+ const output = outputBuffer.trim()
189
+ const capturedOutput = output.length > MAX_SUMMARY_LENGTH
190
+ ? output.slice(-MAX_SUMMARY_LENGTH)
191
+ : output
192
+
186
193
  if (exitCode === 0) {
187
194
  console.log(`[WorkflowRunner] Workflow ${workflow.name} completed successfully`)
188
- resolve({ success: true, sessionName })
195
+ resolve({ success: true, sessionName, output: capturedOutput })
189
196
  } else {
190
197
  console.error(`[WorkflowRunner] Workflow ${workflow.name} failed with exit code: ${exitCode}`)
191
- resolve({ success: false, error: `Exit code: ${exitCode}`, sessionName })
198
+ resolve({ success: false, error: `Exit code: ${exitCode}`, sessionName, output: capturedOutput })
192
199
  }
193
200
  })
194
201
  })
@@ -261,6 +268,13 @@ async function runWorkflow(workflow, options = {}) {
261
268
  log_file: logFile,
262
269
  })
263
270
 
271
+ // Use captured output as summary, falling back to generic message
272
+ const summary = (result.output && result.output.length > 0)
273
+ ? result.output
274
+ : result.success
275
+ ? `All skills completed successfully: ${pipelineSkillNames.join(', ')}`
276
+ : `Workflow failed: ${result.error || 'unknown error'}`
277
+
264
278
  // Report outcome via local API
265
279
  try {
266
280
  const resp = await fetch(`http://localhost:${config.AGENT_PORT || 8080}/api/executions/${executionId}/outcome`, {
@@ -268,9 +282,7 @@ async function runWorkflow(workflow, options = {}) {
268
282
  headers: { 'Content-Type': 'application/json' },
269
283
  body: JSON.stringify({
270
284
  outcome,
271
- summary: result.success
272
- ? `All skills completed successfully: ${pipelineSkillNames.join(', ')}`
273
- : `Workflow failed: ${result.error || 'unknown error'}`,
285
+ summary,
274
286
  }),
275
287
  })
276
288
  if (!resp.ok) {