@yemi33/minions 0.1.2437 → 0.1.2438

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.
@@ -205,17 +205,32 @@ async function kbSweep() {
205
205
  }
206
206
 
207
207
  let _memorySearchUiLoading = false;
208
+ // Lazily loads /assets/memory-search.js, then opens the modal.
209
+ //
210
+ // Both failure paths matter (W-ms5dlone012i457a-c):
211
+ // - script.onerror -> the network/404 case
212
+ // - script.onload but window.MinionsMemorySearch still undefined -> the
213
+ // script was served but did not register (e.g. a truncated/empty body, or
214
+ // it threw while evaluating). Dereferencing .open() here used to raise an
215
+ // uncaught TypeError.
216
+ // In every path the loading latch must be cleared, otherwise the early-return
217
+ // below permanently and silently bricks the button for the rest of the session.
208
218
  function openMemorySearchModal() {
209
219
  if (window.MinionsMemorySearch) return window.MinionsMemorySearch.open();
210
220
  if (_memorySearchUiLoading) return;
211
221
  _memorySearchUiLoading = true;
212
222
  const script = document.createElement('script');
213
223
  script.src = '/assets/memory-search.js';
214
- script.onload = () => window.MinionsMemorySearch.open();
215
- script.onerror = () => {
224
+ const fail = () => {
216
225
  _memorySearchUiLoading = false;
217
226
  showToast('kb-sweep-toast', 'Memory search UI failed to load', false);
218
227
  };
228
+ script.onload = () => {
229
+ _memorySearchUiLoading = false;
230
+ if (!window.MinionsMemorySearch) return fail();
231
+ window.MinionsMemorySearch.open();
232
+ };
233
+ script.onerror = fail;
219
234
  document.head.appendChild(script);
220
235
  }
221
236
 
@@ -262,7 +277,24 @@ async function submitKbEntry(e) {
262
277
 
263
278
  async function kbOpenItem(category, file) {
264
279
  try {
265
- const content = await fetch('/api/knowledge/' + category + '/' + encodeURIComponent(file)).then(r => r.text());
280
+ const res = await fetch('/api/knowledge/' + category + '/' + encodeURIComponent(file));
281
+ // Without this check a 404/500 body was rendered as if it were the entry,
282
+ // and a 200-with-empty-body opened a completely blank modal with no error
283
+ // (W-ms5dlone012i457a-c). Surface the failure instead of rendering nothing.
284
+ if (!res.ok) {
285
+ document.getElementById('modal-title').textContent = file;
286
+ const failBody = document.getElementById('modal-body');
287
+ failBody.replaceChildren();
288
+ const msg = document.createElement('p');
289
+ msg.className = 'empty';
290
+ msg.textContent = res.status === 404
291
+ ? 'This knowledge entry no longer exists on disk (404). It may have been renamed or swept.'
292
+ : 'Could not load this knowledge entry (HTTP ' + res.status + ').';
293
+ failBody.appendChild(msg);
294
+ document.getElementById('modal').classList.add('open');
295
+ return;
296
+ }
297
+ const content = await res.text();
266
298
  const display = content.replace(/^---[\s\S]*?---\n*/m, '');
267
299
  document.getElementById('modal-title').textContent = file;
268
300
  const modalBody = document.getElementById('modal-body');
package/dashboard.js CHANGED
@@ -9080,7 +9080,11 @@ const server = http.createServer(async (req, res) => {
9080
9080
  MINIONS_DIR,
9081
9081
  );
9082
9082
  const kbCatDir = path.join(MINIONS_DIR, 'knowledge', cat);
9083
- const content = safeRead(path.join(kbCatDir, file));
9083
+ // safeReadOrNull (not safeRead): safeRead collapses ENOENT to '', which
9084
+ // made this 404 guard dead code and served a missing entry as 200 with an
9085
+ // empty body — render-kb.js#kbOpenItem then opened a blank modal with no
9086
+ // error. Present-but-empty still reads as '' and correctly returns 200.
9087
+ const content = safeReadOrNull(path.join(kbCatDir, file));
9084
9088
  if (content === null) return jsonReply(res, 404, { error: 'not found', code: 'not-found' });
9085
9089
  res.setHeader('Content-Type', 'text/plain; charset=utf-8');
9086
9090
  res.end(content);
@@ -15825,7 +15829,9 @@ What would you like to discuss or change? When you're happy, say "approve" and I
15825
15829
  catch { return jsonReply(res, 400, { error: 'invalid path' }); }
15826
15830
  const agentsDir = path.join(MINIONS_DIR, 'agents');
15827
15831
  if (!safePath.startsWith(agentsDir + path.sep)) return jsonReply(res, 400, { error: 'path must be within agents/' });
15828
- const content = _agentApiCall('readOutputFile', safeRead, safePath);
15832
+ // safeReadOrNull (not safeRead) so a missing log 404s instead of being
15833
+ // served as 200 with an empty body — see the KB read above.
15834
+ const content = _agentApiCall('readOutputFile', safeReadOrNull, safePath);
15829
15835
  if (content === null) return jsonReply(res, 404, { error: 'not found' });
15830
15836
  res.setHeader('Content-Type', 'text/plain; charset=utf-8');
15831
15837
  res.setHeader('Cache-Control', 'no-cache');
@@ -15834,7 +15840,11 @@ What would you like to discuss or change? When you're happy, say "approve" and I
15834
15840
 
15835
15841
  // Knowledge base
15836
15842
  { method: 'GET', path: '/assets/memory-search.js', desc: 'Serve the lazy-loaded structured memory search UI', handler: (req, res) => {
15837
- const content = safeRead(path.join(MINIONS_DIR, 'dashboard', 'js', 'memory-search.js'));
15843
+ // safeReadOrNull (not safeRead): a 200 with an empty body still fires
15844
+ // the loader's script.onload, leaving window.MinionsMemorySearch
15845
+ // undefined so openMemorySearchModal() throws. 404 lets script.onerror
15846
+ // surface the intended "failed to load" toast instead.
15847
+ const content = safeReadOrNull(path.join(MINIONS_DIR, 'dashboard', 'js', 'memory-search.js'));
15838
15848
  if (content == null) { res.statusCode = 404; return res.end('not found'); }
15839
15849
  res.setHeader('Content-Type', 'application/javascript; charset=utf-8');
15840
15850
  res.setHeader('Cache-Control', 'no-cache');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.2437",
3
+ "version": "0.1.2438",
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"