nothumanallowed 3.3.0 → 3.5.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nothumanallowed",
3
- "version": "3.3.0",
3
+ "version": "3.5.0",
4
4
  "description": "NotHumanAllowed — 38 AI agents for security, code, DevOps, data & daily ops. Ask agents directly, plan your day with 5 specialist agents, manage tasks, connect Gmail + Calendar.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -450,11 +450,17 @@ export async function cmdUI(args) {
450
450
  return;
451
451
  }
452
452
 
453
- // GET /api/calendar
453
+ // GET /api/calendar?date=YYYY-MM-DD
454
454
  if (method === 'GET' && pathname === '/api/calendar') {
455
455
  try {
456
- const events = await getTodayEvents(config);
457
- sendJSON(res, 200, { events });
456
+ const dateParam = url.searchParams.get('date');
457
+ let events;
458
+ if (dateParam && dateParam !== new Date().toISOString().split('T')[0]) {
459
+ events = await getEventsForDate(config, new Date(dateParam));
460
+ } else {
461
+ events = await getTodayEvents(config);
462
+ }
463
+ sendJSON(res, 200, { events, date: dateParam || new Date().toISOString().split('T')[0] });
458
464
  } catch (e) {
459
465
  sendJSON(res, 200, { events: [], error: e.message });
460
466
  }
@@ -550,26 +556,33 @@ export async function cmdUI(args) {
550
556
  const { textParts, actions } = parseActions(response);
551
557
  const textResponse = textParts.join('\n\n');
552
558
 
553
- // Execute tool actions all actions are now executed directly
554
- let toolResult = null;
555
- let executedAction = null;
556
- if (actions.length > 0) {
557
- const { action, params } = actions[0];
558
- executedAction = action;
559
+ // Execute ALL tool actions and collect results
560
+ const toolResults = [];
561
+ for (const { action, params } of actions) {
559
562
  try {
560
- toolResult = await executeTool(action, params, config);
563
+ const result = await executeTool(action, params, config);
564
+ toolResults.push({ action, result: typeof result === 'object' ? JSON.stringify(result) : String(result) });
561
565
  } catch (e) {
562
- toolResult = `Error executing ${action}: ${e.message}`;
566
+ toolResults.push({ action, result: `Error: ${e.message}` });
563
567
  }
564
568
  }
565
569
 
566
- // Append tool result to response so user sees what actually happened
567
- let fullResponse = textResponse || '';
568
- if (toolResult && executedAction) {
569
- fullResponse += '\n\n---\n' + executedAction + ' result: ' + (typeof toolResult === 'object' ? JSON.stringify(toolResult, null, 2) : String(toolResult));
570
+ let fullResponse;
571
+ if (toolResults.length > 0) {
572
+ // Second LLM call with real tool results — forces the LLM to use actual data
573
+ const toolContext = toolResults.map(t => `[${t.action} result]: ${t.result}`).join('\n\n');
574
+ const followUp = `The user asked: "${body.message}"\n\nI executed these tools and got REAL results:\n\n${toolContext}\n\nNow respond to the user based ONLY on the REAL data above. Do NOT invent or fabricate any information. Present the actual results clearly.`;
575
+ try {
576
+ fullResponse = await callLLM(config, chatSystemPrompt, followUp);
577
+ } catch {
578
+ // Fallback: show raw results
579
+ fullResponse = toolResults.map(t => `${t.action}: ${t.result}`).join('\n\n');
580
+ }
581
+ } else {
582
+ fullResponse = textResponse;
570
583
  }
571
584
 
572
- sendJSON(res, 200, { response: fullResponse, toolResult, actions });
585
+ sendJSON(res, 200, { response: fullResponse, toolResults, actions });
573
586
  } catch (e) {
574
587
  sendJSON(res, 200, { response: null, error: e.message });
575
588
  }
@@ -343,13 +343,65 @@ function renderEmails(el){
343
343
  }
344
344
 
345
345
  // ---- CALENDAR ----
346
- function renderCalendar(el){
347
- var ev=dash.events;
348
- if(ev.length===0){el.innerHTML='<div class="card" style="text-align:center;color:var(--dim);padding:30px">No events today</div>';return}
349
- var h='';ev.forEach(function(x){
350
- h+='<div class="card event"><span class="event__time">'+(x.isAllDay?'All day':fmtTime(x.start)+' - '+fmtTime(x.end))+'</span><span class="event__title">'+esc(x.summary)+'</span>'+(x.location?'<span class="event__location">'+esc(x.location)+'</span>':'')+'</div>';
346
+ var calOffset = 0;
347
+ function renderCalendar(el) {
348
+ var today = new Date();
349
+ var target = new Date(today);
350
+ target.setDate(today.getDate() + calOffset);
351
+ var yyyy = target.getFullYear();
352
+ var mm = String(target.getMonth() + 1).padStart(2, '0');
353
+ var dd = String(target.getDate()).padStart(2, '0');
354
+ var dateStr = yyyy + '-' + mm + '-' + dd;
355
+ var dayName = target.toLocaleDateString('en', { weekday: 'long', month: 'long', day: 'numeric' });
356
+ var isToday = calOffset === 0;
357
+
358
+ var h = '<div style="display:flex;align-items:center;gap:8px;margin-bottom:16px;flex-wrap:wrap">' +
359
+ '<button class="btn btn--secondary" onclick="calOffset--;renderCalendar(document.getElementById(\\x27content\\x27))">&larr; Prev</button>' +
360
+ '<div style="flex:1;text-align:center"><div style="font-size:16px;font-weight:700;color:var(--bright)">' + esc(dayName) + '</div>' +
361
+ '<div style="font-size:11px;color:var(--dim)">' + dateStr + (isToday ? ' (today)' : '') + '</div></div>' +
362
+ '<button class="btn btn--secondary" onclick="calOffset++;renderCalendar(document.getElementById(\\x27content\\x27))">Next &rarr;</button>' +
363
+ '</div>';
364
+
365
+ if (!isToday) {
366
+ h += '<div style="text-align:center;margin-bottom:12px"><button class="btn btn--secondary" onclick="calOffset=0;renderCalendar(document.getElementById(\\x27content\\x27))">Go to Today</button></div>';
367
+ }
368
+
369
+ h += '<div id="calEvents"><div style="text-align:center;padding:30px"><div class="spinner"></div><div style="color:var(--dim);margin-top:8px">Loading events...</div></div></div>';
370
+ el.innerHTML = h;
371
+
372
+ apiGet('/api/calendar?date=' + dateStr).then(function(r) {
373
+ var ev = (r && r.events) || [];
374
+ var ce = document.getElementById('calEvents');
375
+ if (!ce) return;
376
+ if (ev.length === 0) {
377
+ ce.innerHTML = '<div class="card" style="text-align:center;color:var(--dim);padding:30px">No events on ' + esc(dayName) + '</div>';
378
+ return;
379
+ }
380
+ var out = '<div style="color:var(--cyan);font-size:11px;margin-bottom:8px">' + ev.length + ' event' + (ev.length > 1 ? 's' : '') + '</div>';
381
+ ev.forEach(function(x) {
382
+ var timeStr = x.isAllDay ? 'All day' : fmtTime(x.start) + ' — ' + fmtTime(x.end);
383
+ out += '<div class="card" style="padding:14px">' +
384
+ '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">' +
385
+ '<span style="color:var(--amber);font-weight:700;font-size:13px">' + esc(timeStr) + '</span>' +
386
+ '</div>' +
387
+ '<div style="color:var(--bright);font-size:14px;font-weight:600;margin-bottom:4px">' + esc(x.summary) + '</div>';
388
+ if (x.location) {
389
+ out += '<div style="color:var(--dim);font-size:11px">📍 ' + esc(x.location) + '</div>';
390
+ }
391
+ if (x.attendees && x.attendees.length > 0) {
392
+ var names = x.attendees.map(function(a) { return a.name || a.email }).join(', ');
393
+ out += '<div style="color:var(--dim);font-size:11px;margin-top:4px">👥 ' + esc(names) + '</div>';
394
+ }
395
+ if (x.description) {
396
+ out += '<div style="color:var(--dim);font-size:11px;margin-top:4px;border-top:1px solid var(--border);padding-top:6px">' + esc(x.description.slice(0, 200)) + '</div>';
397
+ }
398
+ if (x.hangoutLink) {
399
+ out += '<div style="margin-top:6px"><a href="' + esc(x.hangoutLink) + '" target="_blank" style="color:var(--cyan);font-size:11px">🔗 Join video call</a></div>';
400
+ }
401
+ out += '</div>';
402
+ });
403
+ ce.innerHTML = out;
351
404
  });
352
- el.innerHTML=h;
353
405
  }
354
406
 
355
407
  // ---- AGENTS ----