@yemi33/minions 0.1.58 → 0.1.59

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,33 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.59 (2026-03-30)
4
+
5
+ ### Engine
6
+ - engine.js
7
+ - engine/ado.js
8
+ - engine/cli.js
9
+ - engine/consolidation.js
10
+ - engine/github.js
11
+ - engine/lifecycle.js
12
+ - engine/llm.js
13
+ - engine/preflight.js
14
+ - engine/queries.js
15
+ - engine/shared.js
16
+ - engine/spawn-agent.js
17
+
18
+ ### Dashboard
19
+ - dashboard.js
20
+ - dashboard/js/command-center.js
21
+ - dashboard/js/live-stream.js
22
+ - dashboard/js/modal-qa.js
23
+ - dashboard/js/refresh.js
24
+ - dashboard/js/render-inbox.js
25
+ - dashboard/js/render-kb.js
26
+ - dashboard/js/render-plans.js
27
+ - dashboard/js/render-prs.js
28
+ - dashboard/js/render-work-items.js
29
+ - dashboard/js/settings.js
30
+
3
31
  ## 0.1.58 (2026-03-30)
4
32
 
5
33
  ### Engine
@@ -44,7 +44,7 @@ function ccSaveState() {
44
44
  // Keep last 30 messages for display
45
45
  const toSave = _ccMessages.slice(-30);
46
46
  localStorage.setItem('cc-messages', JSON.stringify(toSave));
47
- } catch {} // localStorage might be full
47
+ } catch { /* localStorage might be full */ }
48
48
  }
49
49
 
50
50
  function ccUpdateSessionIndicator() {
@@ -58,7 +58,7 @@ function renderLiveChatMessage(raw) {
58
58
  }
59
59
 
60
60
  continue;
61
- } catch {}
61
+ } catch { /* JSON parse fallback */ }
62
62
  }
63
63
 
64
64
  // Fallback: raw text (stderr, non-JSON lines)
@@ -88,7 +88,7 @@ function startLiveStream(agentId) {
88
88
  try {
89
89
  const chunk = JSON.parse(e.data);
90
90
  renderLiveChatMessage(chunk);
91
- } catch {}
91
+ } catch (e) { console.error('live-stream:', e.message); }
92
92
  };
93
93
 
94
94
  liveEventSource.addEventListener('done', function() {
@@ -137,7 +137,7 @@ async function refreshLiveOutput() {
137
137
  renderLiveChatMessage(text);
138
138
  if (wasAtBottom) el.scrollTop = el.scrollHeight;
139
139
  }
140
- } catch {}
140
+ } catch (e) { console.error('live-stream reload:', e.message); }
141
141
  }
142
142
 
143
143
  async function sendSteering() {
@@ -16,7 +16,7 @@ const _qaSessions = new Map(); // persist conversations across modal open/close
16
16
  try {
17
17
  const saved = JSON.parse(localStorage.getItem('qa-sessions') || '{}');
18
18
  for (const [k, v] of Object.entries(saved)) _qaSessions.set(k, v);
19
- } catch {}
19
+ } catch { /* optional */ }
20
20
  function _saveQaSessions() {
21
21
  try {
22
22
  const obj = {};
@@ -24,7 +24,7 @@ function _saveQaSessions() {
24
24
  const entries = [..._qaSessions.entries()].slice(-10);
25
25
  for (const [k, v] of entries) obj[k] = { ...v, threadHtml: (v.threadHtml || '').slice(0, 50000) };
26
26
  localStorage.setItem('qa-sessions', JSON.stringify(obj));
27
- } catch {}
27
+ } catch { /* localStorage might be full */ }
28
28
  }
29
29
 
30
30
  function modalAskAboutSelection() {
@@ -293,13 +293,13 @@ async function qaReplacePrd(planFile) {
293
293
  method: 'POST', headers: { 'Content-Type': 'application/json' },
294
294
  body: JSON.stringify({ file: existingPrd.file })
295
295
  });
296
- } catch {}
296
+ } catch (e) { console.error('plan pause:', e.message); }
297
297
  try {
298
298
  await fetch('/api/plans/regenerate', {
299
299
  method: 'POST', headers: { 'Content-Type': 'application/json' },
300
300
  body: JSON.stringify({ source: existingPrd.file })
301
301
  });
302
- } catch {}
302
+ } catch (e) { console.error('plan regenerate:', e.message); }
303
303
  }
304
304
 
305
305
  planExecute(planFile, project, null);
@@ -61,7 +61,7 @@ let _statusStream = null;
61
61
  try {
62
62
  _statusStream = new EventSource('/api/status-stream');
63
63
  _statusStream.onmessage = (e) => {
64
- try { _processStatusUpdate(JSON.parse(e.data)); } catch {}
64
+ try { _processStatusUpdate(JSON.parse(e.data)); } catch (e2) { console.error('status-stream:', e2.message); }
65
65
  };
66
66
  _statusStream.onerror = () => {
67
67
  // Fall back to polling
@@ -82,4 +82,4 @@ switchPage(currentPage);
82
82
  try {
83
83
  const _hotReload = new EventSource('/api/hot-reload');
84
84
  _hotReload.onmessage = (e) => { if (e.data === 'reload') location.reload(); };
85
- } catch {}
85
+ } catch { /* expected */ }
@@ -142,7 +142,7 @@ async function openInboxInExplorer(name) {
142
142
  method: 'POST', headers: { 'Content-Type': 'application/json' },
143
143
  body: JSON.stringify({ name })
144
144
  });
145
- } catch {}
145
+ } catch (e) { console.error('inbox open:', e.message); }
146
146
  }
147
147
 
148
148
  function openQuickNoteModal() {
@@ -174,9 +174,9 @@ async function submitQuickNote() {
174
174
  body: JSON.stringify({ title: title || 'Quick note', what: content || title })
175
175
  });
176
176
  if (res.ok) {
177
- try { closeModal(); } catch {}
177
+ try { closeModal(); } catch { /* expected */ }
178
178
  refresh();
179
- try { showToast('cmd-toast', 'Note saved to inbox', true); } catch {}
179
+ try { showToast('cmd-toast', 'Note saved to inbox', true); } catch { /* expected */ }
180
180
  }
181
181
  else { const d = await res.json().catch(() => ({})); alert('Error: ' + (d.error || 'unknown')); }
182
182
  } catch (e) { alert('Error saving note: ' + e.message); }
@@ -6,7 +6,7 @@ async function refreshKnowledgeBase() {
6
6
  try {
7
7
  _kbData = await fetch('/api/knowledge').then(r => r.json());
8
8
  renderKnowledgeBase();
9
- } catch {}
9
+ } catch (e) { console.error('kb refresh:', e.message); }
10
10
  }
11
11
 
12
12
  function renderKnowledgeBase() {
@@ -36,10 +36,10 @@ async function _submitCreatePlan() {
36
36
  });
37
37
  const data = await res.json();
38
38
  if (res.ok) {
39
- try { closeModal(); } catch {}
39
+ try { closeModal(); } catch { /* expected */ }
40
40
  refreshPlans();
41
41
  refresh();
42
- try { showToast('cmd-toast', 'Plan "' + data.file + '" created — click Execute to convert to PRD', true); } catch {}
42
+ try { showToast('cmd-toast', 'Plan "' + data.file + '" created — click Execute to convert to PRD', true); } catch { /* expected */ }
43
43
  } else {
44
44
  alert('Failed: ' + (data.error || 'unknown'));
45
45
  }
@@ -50,7 +50,7 @@ async function refreshPlans() {
50
50
  try {
51
51
  const plans = await fetch('/api/plans').then(r => r.json());
52
52
  renderPlans(plans);
53
- } catch {}
53
+ } catch (e) { console.error('plans refresh:', e.message); }
54
54
  }
55
55
 
56
56
  /**
@@ -135,9 +135,9 @@ async function _submitLinkPr() {
135
135
  });
136
136
  const data = await res.json();
137
137
  if (res.ok) {
138
- try { closeModal(); } catch {}
138
+ try { closeModal(); } catch { /* expected */ }
139
139
  refresh();
140
- try { showToast('cmd-toast', 'PR ' + (data.id || '') + ' linked' + (autoObserve ? ' (auto-observe on)' : ''), true); } catch {}
140
+ try { showToast('cmd-toast', 'PR ' + (data.id || '') + ' linked' + (autoObserve ? ' (auto-observe on)' : ''), true); } catch { /* expected */ }
141
141
  } else {
142
142
  alert('Failed: ' + (data.error || 'unknown'));
143
143
  }
@@ -341,10 +341,10 @@ async function _submitCreateWorkItem() {
341
341
  });
342
342
  const data = await res.json();
343
343
  if (res.ok) {
344
- try { closeModal(); } catch {}
344
+ try { closeModal(); } catch { /* expected */ }
345
345
  wakeEngine();
346
346
  refresh();
347
- try { showToast('cmd-toast', 'Work item ' + (data.id || '') + ' created', true); } catch {}
347
+ try { showToast('cmd-toast', 'Work item ' + (data.id || '') + ' created', true); } catch { /* expected */ }
348
348
  } else {
349
349
  alert('Failed: ' + (data.error || 'unknown'));
350
350
  }
@@ -147,7 +147,7 @@ async function addProject() {
147
147
  });
148
148
  const addData = await addRes.json();
149
149
  if (!addRes.ok) { alert('Failed: ' + (addData.error || 'unknown')); return; }
150
- try { showToast('cmd-toast', 'Project "' + addData.name + '" added — restart engine to pick it up', true); } catch {}
150
+ try { showToast('cmd-toast', 'Project "' + addData.name + '" added — restart engine to pick it up', true); } catch { /* expected */ }
151
151
  refresh();
152
152
  } catch (e) { alert('Error: ' + e.message); }
153
153
  }
package/dashboard.js CHANGED
@@ -124,11 +124,11 @@ if (fs.existsSync(dashDir)) {
124
124
  _reloadTimer = setTimeout(rebuildDashboardHtml, 300); // debounce 300ms
125
125
  };
126
126
  // Watch top-level files (styles.css, layout.html)
127
- try { fs.watch(dashDir, scheduleReload); } catch {}
127
+ try { fs.watch(dashDir, scheduleReload); } catch { /* optional */ }
128
128
  // Watch subdirectories (pages/, js/)
129
129
  for (const sub of ['pages', 'js']) {
130
130
  const subDir = path.join(dashDir, sub);
131
- if (fs.existsSync(subDir)) try { fs.watch(subDir, scheduleReload); } catch {}
131
+ if (fs.existsSync(subDir)) try { fs.watch(subDir, scheduleReload); } catch { /* optional */ }
132
132
  }
133
133
  }
134
134
 
@@ -145,7 +145,7 @@ function getVerifyGuides() {
145
145
  const planFile = planSlug + '.json';
146
146
  guides.push({ file: f, planFile });
147
147
  }
148
- } catch {}
148
+ } catch (e) { console.error('getVerifyGuides:', e.message); }
149
149
  return guides;
150
150
  }
151
151
 
@@ -273,7 +273,7 @@ try {
273
273
  const age = Date.now() - new Date(saved.lastActiveAt || 0).getTime();
274
274
  if (age < CC_SESSION_EXPIRY_MS) ccSession = saved;
275
275
  }
276
- } catch {}
276
+ } catch { /* optional */ }
277
277
 
278
278
  // Static system prompt — baked into session on creation, never changes
279
279
  const CC_STATIC_SYSTEM_PROMPT = `You are the Command Center AI for a software engineering minions called "Minions."
@@ -459,7 +459,7 @@ try {
459
459
  }
460
460
  }
461
461
  }
462
- } catch {}
462
+ } catch { /* optional */ }
463
463
 
464
464
  function persistDocSessions() {
465
465
  const obj = {};
@@ -687,12 +687,12 @@ function cleanDispatchEntries(matchFn) {
687
687
  try {
688
688
  const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim());
689
689
  if (pid) process.kill(pid, 'SIGTERM');
690
- } catch {}
691
- try { fs.unlinkSync(pidFile); } catch {}
690
+ } catch { /* process may be dead */ }
691
+ try { fs.unlinkSync(pidFile); } catch { /* cleanup */ }
692
692
  // Clean up temp prompt files
693
- try { fs.unlinkSync(path.join(engineDir, 'tmp', `prompt-${d.id}.md`)); } catch {}
694
- try { fs.unlinkSync(path.join(engineDir, 'tmp', `sysprompt-${d.id}.md`)); } catch {}
695
- try { fs.unlinkSync(path.join(engineDir, 'tmp', `sysprompt-${d.id}.md.tmp`)); } catch {}
693
+ try { fs.unlinkSync(path.join(engineDir, 'tmp', `prompt-${d.id}.md`)); } catch { /* cleanup */ }
694
+ try { fs.unlinkSync(path.join(engineDir, 'tmp', `sysprompt-${d.id}.md`)); } catch { /* cleanup */ }
695
+ try { fs.unlinkSync(path.join(engineDir, 'tmp', `sysprompt-${d.id}.md.tmp`)); } catch { /* cleanup */ }
696
696
  }
697
697
  }
698
698
  dispatch[queue] = dispatch[queue].filter(d => !matchFn(d));
@@ -729,7 +729,7 @@ function killEnginePid(pid) {
729
729
  } else {
730
730
  process.kill(pid, 'SIGKILL');
731
731
  }
732
- } catch {}
732
+ } catch { /* process may be dead */ }
733
733
  }
734
734
 
735
735
  function restartEngine() {
@@ -846,7 +846,7 @@ const server = http.createServer(async (req, res) => {
846
846
  dispatch.completed = dispatch.completed.filter(d => !d.meta?.parentKey || d.meta.parentKey !== dispatchKey);
847
847
  return dispatch;
848
848
  }, { defaultValue: { pending: [], active: [], completed: [] } });
849
- } catch {}
849
+ } catch (e) { console.error('dispatch cleanup:', e.message); }
850
850
 
851
851
  // Clear cooldown so item isn't blocked by exponential backoff
852
852
  try {
@@ -856,7 +856,7 @@ const server = http.createServer(async (req, res) => {
856
856
  delete cooldowns[dispatchKey];
857
857
  safeWrite(cooldownPath, cooldowns);
858
858
  }
859
- } catch {}
859
+ } catch (e) { console.error('cooldown cleanup:', e.message); }
860
860
 
861
861
  return jsonReply(res, 200, { ok: true, id });
862
862
  } catch (e) { return jsonReply(res, 400, { error: e.message }); }
@@ -905,7 +905,7 @@ const server = http.createServer(async (req, res) => {
905
905
  if (key.includes(id)) { delete cooldowns[key]; cleaned = true; }
906
906
  }
907
907
  if (cleaned) safeWrite(cooldownPath, cooldowns);
908
- } catch {}
908
+ } catch (e) { console.error('cooldown cleanup:', e.message); }
909
909
 
910
910
  invalidateStatusCache();
911
911
  return jsonReply(res, 200, { ok: true, id, dispatchRemoved });
@@ -1164,7 +1164,7 @@ const server = http.createServer(async (req, res) => {
1164
1164
  safeWrite(wiPath, items);
1165
1165
  workItemSynced = true;
1166
1166
  }
1167
- } catch {}
1167
+ } catch (e) { console.error('work item sync:', e.message); }
1168
1168
  }
1169
1169
 
1170
1170
  return jsonReply(res, 200, { ok: true, item, workItemSynced });
@@ -1196,7 +1196,7 @@ const server = http.createServer(async (req, res) => {
1196
1196
  safeWrite(wiPath, filtered);
1197
1197
  cancelled = true;
1198
1198
  }
1199
- } catch {}
1199
+ } catch (e) { console.error('work item cleanup:', e.message); }
1200
1200
  }
1201
1201
  // Also check central work-items
1202
1202
  const centralPath = path.join(MINIONS_DIR, 'work-items.json');
@@ -1205,7 +1205,7 @@ const server = http.createServer(async (req, res) => {
1205
1205
  const before = items.length;
1206
1206
  const filtered = items.filter(w => !(w.sourcePlan === body.source && w.id === body.itemId));
1207
1207
  if (filtered.length < before) { safeWrite(centralPath, filtered); cancelled = true; }
1208
- } catch {}
1208
+ } catch (e) { console.error('central work item cleanup:', e.message); }
1209
1209
 
1210
1210
  // Clean dispatch entries for this item
1211
1211
  cleanDispatchEntries(d =>
@@ -1235,16 +1235,16 @@ const server = http.createServer(async (req, res) => {
1235
1235
  const status = JSON.parse(safeRead(statusPath) || '{}');
1236
1236
  if (status.pid) {
1237
1237
  if (process.platform === 'win32') {
1238
- try { require('child_process').execSync('taskkill /PID ' + status.pid + ' /F /T', { stdio: 'pipe', timeout: 5000 }); } catch {}
1238
+ try { require('child_process').execSync('taskkill /PID ' + status.pid + ' /F /T', { stdio: 'pipe', timeout: 5000 }); } catch { /* process may be dead */ }
1239
1239
  } else {
1240
- try { process.kill(status.pid, 'SIGTERM'); } catch {}
1240
+ try { process.kill(status.pid, 'SIGTERM'); } catch { /* process may be dead */ }
1241
1241
  }
1242
1242
  }
1243
1243
  status.status = 'idle';
1244
1244
  delete status.currentTask;
1245
1245
  delete status.dispatched;
1246
1246
  safeWrite(statusPath, status);
1247
- } catch {}
1247
+ } catch (e) { console.error('agent cancel:', e.message); }
1248
1248
 
1249
1249
  cancelled.push({ agent: d.agent, task: d.task });
1250
1250
  }
@@ -1291,7 +1291,7 @@ const server = http.createServer(async (req, res) => {
1291
1291
  res.write(`data: ${JSON.stringify(content)}\n\n`);
1292
1292
  offset = Buffer.byteLength(content, 'utf8');
1293
1293
  }
1294
- } catch {}
1294
+ } catch { /* optional */ }
1295
1295
 
1296
1296
  // Watch for changes using fs.watchFile (cross-platform, works on Windows)
1297
1297
  const watcher = () => {
@@ -1306,7 +1306,7 @@ const server = http.createServer(async (req, res) => {
1306
1306
  const chunk = buf.toString('utf8');
1307
1307
  if (chunk) res.write(`data: ${JSON.stringify(chunk)}\n\n`);
1308
1308
  }
1309
- } catch {}
1309
+ } catch { /* optional */ }
1310
1310
  };
1311
1311
 
1312
1312
  fs.watchFile(liveLogPath, { interval: 500 }, watcher);
@@ -1497,7 +1497,7 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
1497
1497
  const meta = `<!-- swept: ${new Date().toISOString()} | reason: ${reason} -->\n`;
1498
1498
  safeWrite(destPath, meta + content);
1499
1499
  safeUnlink(filePath);
1500
- } catch {}
1500
+ } catch (e) { console.error('kb archive:', e.message); }
1501
1501
  }
1502
1502
 
1503
1503
  // Process removals (stale/empty) — archive, not delete
@@ -1534,7 +1534,7 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
1534
1534
  safeWrite(path.join(destDir, entry.file), updated);
1535
1535
  safeUnlink(srcPath);
1536
1536
  reclassified++;
1537
- } catch {}
1537
+ } catch (e) { console.error('kb reclassify:', e.message); }
1538
1538
  }
1539
1539
 
1540
1540
  // Prune swept files older than 30 days
@@ -1545,9 +1545,9 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
1545
1545
  const fp = path.join(kbArchiveDir, f);
1546
1546
  try {
1547
1547
  if (Date.now() - fs.statSync(fp).mtimeMs > SWEPT_RETENTION_MS) { safeUnlink(fp); pruned++; }
1548
- } catch {}
1548
+ } catch { /* cleanup */ }
1549
1549
  }
1550
- } catch {}
1550
+ } catch { /* optional */ }
1551
1551
 
1552
1552
  const summary = `${merged} duplicates merged, ${removed} stale removed, ${reclassified} reclassified${pruned ? ', ' + pruned + ' old swept files pruned' : ''}`;
1553
1553
  safeWrite(path.join(ENGINE_DIR, 'kb-swept.json'), JSON.stringify({ timestamp: new Date().toISOString(), summary }));
@@ -1575,7 +1575,7 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
1575
1575
  const filePath = path.join(dir, f);
1576
1576
  const content = safeRead(filePath) || '';
1577
1577
  let updatedAt = '';
1578
- try { updatedAt = new Date(fs.statSync(filePath).mtimeMs).toISOString(); } catch {}
1578
+ try { updatedAt = new Date(fs.statSync(filePath).mtimeMs).toISOString(); } catch { /* optional */ }
1579
1579
  const isJson = f.endsWith('.json');
1580
1580
  if (isJson) {
1581
1581
  try {
@@ -1597,7 +1597,7 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
1597
1597
  revisionFeedback: plan.revision_feedback || null,
1598
1598
  sourcePlan: plan.source_plan || null,
1599
1599
  });
1600
- } catch {}
1600
+ } catch { /* JSON parse fallback */ }
1601
1601
  } else {
1602
1602
  const titleMatch = content.match(/^#\s+(?:Plan:\s*)?(.+)/m);
1603
1603
  const projectMatch = content.match(/\*\*Project:\*\*\s*(.+)/m);
@@ -1655,7 +1655,7 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
1655
1655
  if (!content) return jsonReply(res, 404, { error: 'not found' });
1656
1656
  // Find the actual file path for Last-Modified header + expose resolved relative path
1657
1657
  const planCandidates = [resolvePlanPath(file), path.join(PRD_DIR, file), path.join(PRD_DIR, 'guides', file), path.join(PLANS_DIR, file), path.join(PRD_DIR, 'archive', file), path.join(PLANS_DIR, 'archive', file)];
1658
- for (const p of planCandidates) { try { const st = fs.statSync(p); if (st) { res.setHeader('Last-Modified', st.mtime.toISOString()); res.setHeader('X-Resolved-Path', path.relative(MINIONS_DIR, p).replace(/\\/g, '/')); break; } } catch {} }
1658
+ for (const p of planCandidates) { try { const st = fs.statSync(p); if (st) { res.setHeader('Last-Modified', st.mtime.toISOString()); res.setHeader('X-Resolved-Path', path.relative(MINIONS_DIR, p).replace(/\\/g, '/')); break; } } catch { /* optional */ } }
1659
1659
  const contentType = file.endsWith('.json') ? 'application/json' : 'text/plain';
1660
1660
  res.setHeader('Content-Type', contentType + '; charset=utf-8');
1661
1661
  res.setHeader('Cache-Control', 'no-cache');
@@ -1699,7 +1699,7 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
1699
1699
  }
1700
1700
  }
1701
1701
  if (changed) safeWrite(wiPath, items);
1702
- } catch {}
1702
+ } catch (e) { console.error('resume work items:', e.message); }
1703
1703
  }
1704
1704
 
1705
1705
  // Clear dispatch completed entries for resumed items so they aren't dedup-blocked
@@ -1759,16 +1759,16 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
1759
1759
  const agentStatus = JSON.parse(safeRead(statusPath) || '{}');
1760
1760
  if (agentStatus.pid) {
1761
1761
  if (process.platform === 'win32') {
1762
- try { require('child_process').execSync('taskkill /PID ' + agentStatus.pid + ' /F /T', { stdio: 'pipe', timeout: 5000 }); } catch {}
1762
+ try { require('child_process').execSync('taskkill /PID ' + agentStatus.pid + ' /F /T', { stdio: 'pipe', timeout: 5000 }); } catch { /* process may be dead */ }
1763
1763
  } else {
1764
- try { process.kill(agentStatus.pid, 'SIGTERM'); } catch {}
1764
+ try { process.kill(agentStatus.pid, 'SIGTERM'); } catch { /* process may be dead */ }
1765
1765
  }
1766
1766
  }
1767
1767
  agentStatus.status = 'idle';
1768
1768
  delete agentStatus.currentTask;
1769
1769
  delete agentStatus.dispatched;
1770
1770
  safeWrite(statusPath, agentStatus);
1771
- } catch {}
1771
+ } catch (e) { console.error('agent reset:', e.message); }
1772
1772
  killedAgents.add(activeEntry.agent);
1773
1773
  }
1774
1774
  }
@@ -1785,7 +1785,7 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
1785
1785
  if (w.id) resetItemIds.add(w.id);
1786
1786
  }
1787
1787
  if (changed) safeWrite(wiPath, items);
1788
- } catch {}
1788
+ } catch (e) { console.error('reset work items:', e.message); }
1789
1789
  }
1790
1790
 
1791
1791
  // Remove dispatch active entries for reset items or killed agents.
@@ -1842,7 +1842,7 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
1842
1842
  }
1843
1843
 
1844
1844
  // Delete old PRD — agent will write replacement at same path
1845
- try { fs.unlinkSync(prdPath); } catch {}
1845
+ try { fs.unlinkSync(prdPath); } catch { /* cleanup */ }
1846
1846
 
1847
1847
  // Queue plan-to-prd regeneration with instructions to preserve completed items
1848
1848
  const wiPath = path.join(MINIONS_DIR, 'work-items.json');
@@ -1963,7 +1963,7 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
1963
1963
  if (filtered.length < items.length) {
1964
1964
  safeWrite(wiInfo.path, filtered);
1965
1965
  }
1966
- } catch {}
1966
+ } catch (e) { console.error('work item sync:', e.message); }
1967
1967
  }
1968
1968
 
1969
1969
  // Count plan items that have no work item yet (will auto-materialize)
@@ -2012,7 +2012,7 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
2012
2012
  cleaned += items.length - filtered.length;
2013
2013
  safeWrite(wiPath, filtered);
2014
2014
  }
2015
- } catch {}
2015
+ } catch (e) { console.error('plan cleanup:', e.message); }
2016
2016
  }
2017
2017
 
2018
2018
  // Clean up dispatch entries for this plan's items
@@ -2036,7 +2036,7 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
2036
2036
  }
2037
2037
  }
2038
2038
  if (changed) safeWrite(centralPath, centralItems);
2039
- } catch {}
2039
+ } catch (e) { console.error('plan-to-prd cleanup:', e.message); }
2040
2040
  }
2041
2041
 
2042
2042
  invalidateStatusCache();
@@ -2177,7 +2177,7 @@ If nothing to do, return: { "duplicates": [], "reclassify": [], "remove": [] }`;
2177
2177
  }
2178
2178
  }
2179
2179
  if (filtered.length < items.length) safeWrite(wiInfo.path, filtered);
2180
- } catch {}
2180
+ } catch (e) { console.error('work item deletion:', e.message); }
2181
2181
  }
2182
2182
  for (const itemId of deletedItemIds) {
2183
2183
  cleanDispatchEntries(d =>
@@ -2385,7 +2385,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
2385
2385
  // Move to archive
2386
2386
  const archiveDir = path.join(MINIONS_DIR, 'notes', 'archive');
2387
2387
  if (!fs.existsSync(archiveDir)) fs.mkdirSync(archiveDir, { recursive: true });
2388
- try { const _c = safeRead(inboxPath); safeWrite(path.join(archiveDir, `persisted-${name}`), _c); safeUnlink(inboxPath); } catch {}
2388
+ try { const _c = safeRead(inboxPath); safeWrite(path.join(archiveDir, `persisted-${name}`), _c); safeUnlink(inboxPath); } catch (e) { console.error('inbox archive:', e.message); }
2389
2389
 
2390
2390
  return jsonReply(res, 200, { ok: true, title });
2391
2391
  } catch (e) { return jsonReply(res, 400, { error: e.message }); }
@@ -2423,7 +2423,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
2423
2423
  // Move inbox item to archive
2424
2424
  const archiveDir = path.join(MINIONS_DIR, 'notes', 'archive');
2425
2425
  if (!fs.existsSync(archiveDir)) fs.mkdirSync(archiveDir, { recursive: true });
2426
- try { const _c = safeRead(inboxPath); safeWrite(path.join(archiveDir, `kb-${category}-${name}`), _c); safeUnlink(inboxPath); } catch {}
2426
+ try { const _c = safeRead(inboxPath); safeWrite(path.join(archiveDir, `kb-${category}-${name}`), _c); safeUnlink(inboxPath); } catch (e) { console.error('inbox archive:', e.message); }
2427
2427
 
2428
2428
  return jsonReply(res, 200, { ok: true, category, file: name });
2429
2429
  } catch (e) { return jsonReply(res, 400, { error: e.message }); }
@@ -2526,7 +2526,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
2526
2526
  fs.writeFileSync(psPath, psScript);
2527
2527
  try {
2528
2528
  selectedPath = execSync(`powershell -STA -NoProfile -ExecutionPolicy Bypass -File "${psPath}"`, { encoding: 'utf8', timeout: 120000 }).trim();
2529
- } finally { try { fs.unlinkSync(psPath); } catch {} }
2529
+ } finally { try { fs.unlinkSync(psPath); } catch { /* cleanup */ } }
2530
2530
  } else if (process.platform === 'darwin') {
2531
2531
  selectedPath = execSync(`osascript -e 'POSIX path of (choose folder with prompt "Select project folder")'`, { encoding: 'utf8', timeout: 120000 }).trim();
2532
2532
  } else {
@@ -2572,14 +2572,14 @@ What would you like to discuss or change? When you're happy, say "approve" and I
2572
2572
  remoteUrl.match(/https:\/\/dev\.azure\.com\/([^/]+)\/([^/]+)\/_git\/([^/\s]+)/);
2573
2573
  if (m) { detected.org = m[1]; detected.project = m[2]; detected.repoName = m[3]; }
2574
2574
  }
2575
- } catch {}
2575
+ } catch (e) { console.error('git remote detection:', e.message); }
2576
2576
  try {
2577
2577
  const pkgPath = path.join(target, 'package.json');
2578
2578
  if (fs.existsSync(pkgPath)) {
2579
2579
  const pkg = safeJson(pkgPath);
2580
2580
  if (pkg.name) detected.name = pkg.name.replace(/^@[^/]+\//, '');
2581
2581
  }
2582
- } catch {}
2582
+ } catch { /* optional */ }
2583
2583
  let description = '';
2584
2584
  try {
2585
2585
  const claudeMd = path.join(target, 'CLAUDE.md');
@@ -2587,7 +2587,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
2587
2587
  const lines = (safeRead(claudeMd) || '').split('\n').filter(l => l.trim() && !l.startsWith('#'));
2588
2588
  if (lines[0] && lines[0].length < 200) description = lines[0].trim();
2589
2589
  }
2590
- } catch {}
2590
+ } catch { /* optional */ }
2591
2591
 
2592
2592
  const name = body.name || detected.name;
2593
2593
  const prUrlBase = detected.repoHost === 'github'
@@ -3042,7 +3042,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
3042
3042
 
3043
3043
  // Also append to live-output.log so it shows in the chat view
3044
3044
  const liveLogPath = path.join(agentDir, 'live-output.log');
3045
- try { fs.appendFileSync(liveLogPath, '\n[human-steering] ' + message + '\n'); } catch {}
3045
+ try { fs.appendFileSync(liveLogPath, '\n[human-steering] ' + message + '\n'); } catch { /* optional */ }
3046
3046
 
3047
3047
  return jsonReply(res, 200, { ok: true, message: 'Steering message sent' });
3048
3048
  }},
package/engine/ado.js CHANGED
@@ -91,7 +91,7 @@ async function forEachActivePr(config, token, callback) {
91
91
  const updated = await callback(project, pr, prNum, orgBase);
92
92
  if (updated) projectUpdated++;
93
93
  } catch (err) {
94
- try { engine().log('warn', `Failed to poll status for ${pr.id}: ${err.message}`); } catch {}
94
+ try { engine().log('warn', `Failed to poll status for ${pr.id}: ${err.message}`); } catch { /* engine not available */ }
95
95
  }
96
96
  }
97
97
 
@@ -160,7 +160,7 @@ async function pollPrStatus(config) {
160
160
  if (newReviewStatus === 'approved') metrics[authorId].prsApproved = (metrics[authorId].prsApproved || 0) + 1;
161
161
  else metrics[authorId].prsRejected = (metrics[authorId].prsRejected || 0) + 1;
162
162
  shared.safeWrite(metricsPath, metrics);
163
- } catch {}
163
+ } catch (err) { try { engine().log('warn', `Metrics update: ${err.message}`); } catch { /* engine not available */ } }
164
164
  }
165
165
  }
166
166
  }