@yemi33/minions 0.1.126 → 0.1.128

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/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.128 (2026-04-01)
4
+
5
+ ### Engine
6
+ - engine.js
7
+ - engine/dispatch.js
8
+ - engine/lifecycle.js
9
+ - engine/timeout.js
10
+
11
+ ### Dashboard
12
+ - dashboard.js
13
+ - dashboard/js/render-work-items.js
14
+
15
+ ### Other
16
+ - test/unit.test.js
17
+
18
+ ## 0.1.127 (2026-04-01)
19
+
20
+ ### Engine
21
+ - engine.js
22
+ - engine/meeting.js
23
+
24
+ ### Dashboard
25
+ - dashboard/js/render-kb.js
26
+ - dashboard/js/render-schedules.js
27
+
3
28
  ## 0.1.126 (2026-04-01)
4
29
 
5
30
  ### Engine
@@ -147,15 +147,14 @@ async function submitKbEntry() {
147
147
  const title = document.getElementById('kb-new-title').value;
148
148
  const content = document.getElementById('kb-new-content').value;
149
149
  if (!title || !content) { alert('Title and content are required'); return; }
150
- try { closeModal(); } catch { /* may not be open */ }
151
- showToast('cmd-toast', 'KB entry created', true);
152
150
  try {
153
151
  const res = await fetch('/api/knowledge', {
154
152
  method: 'POST', headers: { 'Content-Type': 'application/json' },
155
153
  body: JSON.stringify({ category, title, content })
156
154
  });
157
- if (res.ok) { refreshKnowledgeBase(); } else { const d = await res.json().catch(() => ({})); alert('KB create failed: ' + (d.error || 'unknown')); openNewKbModal(); }
158
- } catch (e) { alert('Error: ' + e.message); openNewKbModal(); }
155
+ if (res.ok) { closeModal(); refreshKnowledgeBase(); showToast('cmd-toast', 'KB entry created', true); }
156
+ else { const d = await res.json().catch(() => ({})); alert('KB create failed: ' + (d.error || 'unknown')); }
157
+ } catch (e) { alert('Error: ' + e.message); }
159
158
  }
160
159
 
161
160
  async function kbOpenItem(category, file) {
@@ -366,8 +366,8 @@ function _scheduleFormHtml(sched, isEdit) {
366
366
  const priorities = ['high', 'medium', 'low'];
367
367
  const typeOpts = types.map(t => '<option value="' + t + '"' + ((sched.type || 'implement') === t ? ' selected' : '') + '>' + t + '</option>').join('');
368
368
  const priOpts = priorities.map(p => '<option value="' + p + '"' + ((sched.priority || 'medium') === p ? ' selected' : '') + '>' + p + '</option>').join('');
369
- const projOpts = '<option value="">Any</option>' + cmdProjects.map(p => '<option value="' + escHtml(p.name) + '"' + (sched.project === p.name ? ' selected' : '') + '>' + escHtml(p.name) + '</option>').join('');
370
- const agentOpts = '<option value="">Auto</option>' + cmdAgents.map(a => '<option value="' + escHtml(a.id) + '"' + (sched.agent === a.id ? ' selected' : '') + '>' + escHtml(a.name) + '</option>').join('');
369
+ const projOpts = '<option value="">Any</option>' + (cmdProjects || []).map(p => '<option value="' + escHtml(p.name) + '"' + (sched.project === p.name ? ' selected' : '') + '>' + escHtml(p.name) + '</option>').join('');
370
+ const agentOpts = '<option value="">Auto</option>' + (cmdAgents || []).map(a => '<option value="' + escHtml(a.id) + '"' + (sched.agent === a.id ? ' selected' : '') + '>' + escHtml(a.name) + '</option>').join('');
371
371
 
372
372
  const inputStyle = 'display:block;width:100%;margin-top:4px;padding:6px 8px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text);font-size:var(--text-md);font-family:inherit';
373
373
  const pillStyle = 'display:inline-block;padding:4px 10px;margin:2px;border:1px solid var(--border);border-radius:12px;cursor:pointer;font-size:11px;color:var(--text);background:var(--bg);user-select:none;transition:all 0.15s';
@@ -94,7 +94,7 @@ function editWorkItem(id, source) {
94
94
  if (!item) return;
95
95
  const types = ['implement', 'fix', 'review', 'plan', 'verify', 'investigate', 'refactor', 'test', 'docs'];
96
96
  const priorities = ['critical', 'high', 'medium', 'low'];
97
- const agentOpts = cmdAgents.map(a => '<option value="' + escHtml(a.id) + '"' + (item.agent === a.id ? ' selected' : '') + '>' + escHtml(a.name) + '</option>').join('');
97
+ const agentOpts = (cmdAgents || []).map(a => '<option value="' + escHtml(a.id) + '"' + (item.agent === a.id ? ' selected' : '') + '>' + escHtml(a.name) + '</option>').join('');
98
98
  const typeOpts = types.map(t => '<option value="' + t + '"' + ((item.type || 'implement') === t ? ' selected' : '') + '>' + t + '</option>').join('');
99
99
  const priOpts = priorities.map(p => '<option value="' + p + '"' + ((item.priority || 'medium') === p ? ' selected' : '') + '>' + p + '</option>').join('');
100
100
 
package/dashboard.js CHANGED
@@ -3057,7 +3057,10 @@ What would you like to discuss or change? When you're happy, say "approve" and I
3057
3057
  try {
3058
3058
  const body = await readBody(req);
3059
3059
  const configPath = path.join(MINIONS_DIR, 'config.json');
3060
- const config = safeJson(configPath);
3060
+ const config = safeJson(configPath) || {};
3061
+ if (!config.engine) config.engine = {};
3062
+ if (!config.claude) config.claude = {};
3063
+ if (!config.agents) config.agents = {};
3061
3064
 
3062
3065
  if (body.engine) {
3063
3066
  // Validate and apply engine settings
@@ -86,8 +86,8 @@ function completeDispatch(id, result = 'success', reason = '', resultSummary = '
86
86
  if (reason) item.reason = reason;
87
87
  if (resultSummary) item.resultSummary = resultSummary;
88
88
  delete item.prompt;
89
- if (dispatch.completed.length >= 100) {
90
- dispatch.completed = dispatch.completed.slice(-99);
89
+ if (dispatch.completed.length > 100) {
90
+ dispatch.completed = dispatch.completed.slice(-100);
91
91
  }
92
92
  dispatch.completed.push(item);
93
93
  return dispatch;
@@ -1161,7 +1161,7 @@ function runPostCompletionHooks(dispatchItem, agentId, code, stdout, config) {
1161
1161
  return d.includes(branchSlug) && fs.statSync(path.join(worktreeRoot, d)).isDirectory();
1162
1162
  });
1163
1163
  // Only remove if no other active dispatch uses this branch
1164
- const dispatch = e.getDispatch();
1164
+ const dispatch = getDispatch();
1165
1165
  const otherActive = ((dispatch.active || []).concat(dispatch.pending || [])).some(d =>
1166
1166
  d.id !== dispatchItem.id && d.meta?.branch && shared.sanitizeBranch && shared.sanitizeBranch(d.meta.branch) === branchSlug
1167
1167
  );
@@ -1208,10 +1208,10 @@ function runPostCompletionHooks(dispatchItem, agentId, code, stdout, config) {
1208
1208
  wi._retryCount = retries + 1;
1209
1209
  delete wi.dispatched_at;
1210
1210
  delete wi.dispatched_to;
1211
- e.log('info', `Auto-retry ${retries + 1}/3 for ${meta.item.id} (no PR created)`);
1211
+ log('info', `Auto-retry ${retries + 1}/3 for ${meta.item.id} (no PR created)`);
1212
1212
  } else {
1213
1213
  wi.status = 'failed';
1214
- e.log('warn', `${meta.item.id} failed after 3 retries — no PR created`);
1214
+ log('warn', `${meta.item.id} failed after 3 retries — no PR created`);
1215
1215
  }
1216
1216
  shared.safeWrite(wiPath, items);
1217
1217
  }
package/engine/meeting.js CHANGED
@@ -179,6 +179,7 @@ function discoverMeetingWork(config) {
179
179
  * Called from runPostCompletionHooks when type === 'meeting'.
180
180
  */
181
181
  function collectMeetingFindings(meetingId, agentId, roundName, output) {
182
+ const e = engine();
182
183
  const meeting = getMeeting(meetingId);
183
184
  if (!meeting) return;
184
185
 
package/engine/timeout.js CHANGED
@@ -130,7 +130,7 @@ function checkTimeouts(config) {
130
130
  // Optimization: only read file if recent activity (avoids reading stale 1MB logs)
131
131
  let completedViaOutput = false;
132
132
  try {
133
- if (silentMs > 600000) throw 'skip'; // No point reading a file silent for >10min
133
+ if (silentMs > 600000) throw new Error('skip'); // No point reading a file silent for >10min
134
134
  const liveLog = safeRead(liveLogPath);
135
135
  if (liveLog && liveLog.includes('"type":"result"')) {
136
136
  completedViaOutput = true;
package/engine.js CHANGED
@@ -1036,7 +1036,7 @@ function materializePlansAsWorkItems(config) {
1036
1036
  plan.status = 'approved';
1037
1037
  plan.approvedAt = new Date().toISOString();
1038
1038
  plan.approvedBy = 'auto-mode';
1039
- safeWrite(prdPath, plan);
1039
+ safeWrite(path.join(PRD_DIR, file), plan);
1040
1040
  log('info', `Auto-approved plan: ${file}`);
1041
1041
  } else {
1042
1042
  continue; // Skip — waiting for human approval
@@ -1185,8 +1185,10 @@ function materializePlansAsWorkItems(config) {
1185
1185
  // Pre-create shared feature branch if branch_strategy is shared-branch
1186
1186
  if (plan.branch_strategy === 'shared-branch' && plan.feature_branch) {
1187
1187
  try {
1188
- const root = path.resolve(project.localPath);
1189
- const mainBranch = project.mainBranch || 'main';
1188
+ const firstProject = itemsByProject.values().next().value?.project;
1189
+ if (!firstProject?.localPath) throw new Error('no project with localPath');
1190
+ const root = path.resolve(firstProject.localPath);
1191
+ const mainBranch = firstProject.mainBranch || 'main';
1190
1192
  const branch = sanitizeBranch(plan.feature_branch);
1191
1193
  // Create branch from main (idempotent — ignores if exists)
1192
1194
  exec(`git branch "${branch}" "${mainBranch}" 2>/dev/null || true`, { cwd: root, stdio: 'pipe' });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.126",
3
+ "version": "0.1.128",
4
4
  "description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
5
5
  "bin": {
6
6
  "minions": "bin/minions.js"