nothumanallowed 3.2.0 → 3.4.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 +1 -1
- package/src/commands/ui.mjs +70 -37
- package/src/services/web-ui.mjs +25 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.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": {
|
package/src/commands/ui.mjs
CHANGED
|
@@ -14,8 +14,8 @@ import fs from 'fs';
|
|
|
14
14
|
import path from 'path';
|
|
15
15
|
import { loadConfig } from '../config.mjs';
|
|
16
16
|
import { callLLM, callAgent, parseAgentFile } from '../services/llm.mjs';
|
|
17
|
-
import { getUnreadImportant } from '../services/google-gmail.mjs';
|
|
18
|
-
import { getTodayEvents } from '../services/google-calendar.mjs';
|
|
17
|
+
import { getUnreadImportant, getMessage, listMessages, sendEmail, createDraft } from '../services/google-gmail.mjs';
|
|
18
|
+
import { getTodayEvents, getUpcomingEvents, createEvent, updateEvent, getEventsForDate } from '../services/google-calendar.mjs';
|
|
19
19
|
import {
|
|
20
20
|
getTasks,
|
|
21
21
|
addTask,
|
|
@@ -87,19 +87,7 @@ RULES:
|
|
|
87
87
|
- Dates: today is {{TODAY}}. The user's timezone is {{TIMEZONE}}.
|
|
88
88
|
`.trim();
|
|
89
89
|
|
|
90
|
-
// ──
|
|
91
|
-
|
|
92
|
-
import {
|
|
93
|
-
listMessages,
|
|
94
|
-
getMessage,
|
|
95
|
-
sendEmail,
|
|
96
|
-
createDraft,
|
|
97
|
-
} from '../services/google-gmail.mjs';
|
|
98
|
-
|
|
99
|
-
import {
|
|
100
|
-
getUpcomingEvents,
|
|
101
|
-
createEvent,
|
|
102
|
-
} from '../services/google-calendar.mjs';
|
|
90
|
+
// ── Tool execution (all imports are at top of file) ──────────
|
|
103
91
|
|
|
104
92
|
function parseActions(text) {
|
|
105
93
|
const actions = [];
|
|
@@ -189,6 +177,40 @@ async function executeTool(action, params, config) {
|
|
|
189
177
|
});
|
|
190
178
|
return `Event "${params.summary}" created for ${fmtTime(params.start)} - ${fmtTime(params.end)}.`;
|
|
191
179
|
}
|
|
180
|
+
case 'calendar_move': {
|
|
181
|
+
await updateEvent(config, 'primary', params.eventId, {
|
|
182
|
+
start: { dateTime: new Date(params.newStart).toISOString() },
|
|
183
|
+
end: { dateTime: new Date(params.newEnd).toISOString() },
|
|
184
|
+
});
|
|
185
|
+
return `Event ${params.eventId} moved to ${fmtTime(params.newStart)} - ${fmtTime(params.newEnd)}.`;
|
|
186
|
+
}
|
|
187
|
+
case 'calendar_tomorrow': {
|
|
188
|
+
const tomorrow = new Date();
|
|
189
|
+
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
190
|
+
const events = await getEventsForDate(config, tomorrow);
|
|
191
|
+
if (events.length === 0) return 'No events scheduled for tomorrow.';
|
|
192
|
+
return events.map((e, i) => {
|
|
193
|
+
const time = e.isAllDay ? 'All day' : `${fmtTime(e.start)} - ${fmtTime(e.end)}`;
|
|
194
|
+
return `${i + 1}. ${time} — ${e.summary}${e.location ? ' @ ' + e.location : ''}`;
|
|
195
|
+
}).join('\n');
|
|
196
|
+
}
|
|
197
|
+
case 'task_move': {
|
|
198
|
+
const { moveTask } = await import('../services/task-store.mjs');
|
|
199
|
+
const today = new Date().toISOString().split('T')[0];
|
|
200
|
+
const toDate = params.toDate === 'tomorrow'
|
|
201
|
+
? new Date(new Date().setDate(new Date().getDate() + 1)).toISOString().split('T')[0]
|
|
202
|
+
: params.toDate;
|
|
203
|
+
const moved = moveTask(params.id, today, toDate);
|
|
204
|
+
return moved ? `Task #${params.id} moved to ${toDate}.` : `Task #${params.id} not found.`;
|
|
205
|
+
}
|
|
206
|
+
case 'notify_remind': {
|
|
207
|
+
const delay = params.atTime ? Math.max(0, new Date(params.atTime).getTime() - Date.now()) : 60000;
|
|
208
|
+
setTimeout(async () => {
|
|
209
|
+
const { notify } = await import('../services/notification.mjs');
|
|
210
|
+
notify('Reminder', params.message, config);
|
|
211
|
+
}, delay);
|
|
212
|
+
return `Reminder set: "${params.message}" at ${params.atTime || 'in 1 minute'}.`;
|
|
213
|
+
}
|
|
192
214
|
case 'task_list': {
|
|
193
215
|
const tasks = getTasks();
|
|
194
216
|
if (tasks.length === 0) return 'No tasks for today.';
|
|
@@ -428,11 +450,17 @@ export async function cmdUI(args) {
|
|
|
428
450
|
return;
|
|
429
451
|
}
|
|
430
452
|
|
|
431
|
-
// GET /api/calendar
|
|
453
|
+
// GET /api/calendar?date=YYYY-MM-DD
|
|
432
454
|
if (method === 'GET' && pathname === '/api/calendar') {
|
|
433
455
|
try {
|
|
434
|
-
const
|
|
435
|
-
|
|
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] });
|
|
436
464
|
} catch (e) {
|
|
437
465
|
sendJSON(res, 200, { events: [], error: e.message });
|
|
438
466
|
}
|
|
@@ -528,28 +556,33 @@ export async function cmdUI(args) {
|
|
|
528
556
|
const { textParts, actions } = parseActions(response);
|
|
529
557
|
const textResponse = textParts.join('\n\n');
|
|
530
558
|
|
|
531
|
-
// Execute
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
559
|
+
// Execute ALL tool actions and collect results
|
|
560
|
+
const toolResults = [];
|
|
561
|
+
for (const { action, params } of actions) {
|
|
562
|
+
try {
|
|
563
|
+
const result = await executeTool(action, params, config);
|
|
564
|
+
toolResults.push({ action, result: typeof result === 'object' ? JSON.stringify(result) : String(result) });
|
|
565
|
+
} catch (e) {
|
|
566
|
+
toolResults.push({ action, result: `Error: ${e.message}` });
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
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');
|
|
549
580
|
}
|
|
581
|
+
} else {
|
|
582
|
+
fullResponse = textResponse;
|
|
550
583
|
}
|
|
551
584
|
|
|
552
|
-
sendJSON(res, 200, { response:
|
|
585
|
+
sendJSON(res, 200, { response: fullResponse, toolResults, actions });
|
|
553
586
|
} catch (e) {
|
|
554
587
|
sendJSON(res, 200, { response: null, error: e.message });
|
|
555
588
|
}
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -279,8 +279,11 @@ function sendChat(){
|
|
|
279
279
|
apiPost('/api/chat',{message:msg,history:chatHistory.slice(0,-1)}).then(function(r){
|
|
280
280
|
chatHistory.pop();
|
|
281
281
|
if(r&&r.response){chatHistory.push({role:'assistant',content:r.response})}
|
|
282
|
-
else{chatHistory.push({role:'assistant',content:'Error:
|
|
282
|
+
else if(r&&r.error){chatHistory.push({role:'assistant',content:'Error: '+r.error})}
|
|
283
|
+
else{chatHistory.push({role:'assistant',content:'Error: no response from server'})}
|
|
283
284
|
renderMessages();
|
|
285
|
+
// Refresh data if an action was executed
|
|
286
|
+
if(r&&r.actions&&r.actions.length>0){loadDash().catch(function(){})}
|
|
284
287
|
});
|
|
285
288
|
}
|
|
286
289
|
|
|
@@ -340,13 +343,29 @@ function renderEmails(el){
|
|
|
340
343
|
}
|
|
341
344
|
|
|
342
345
|
// ---- CALENDAR ----
|
|
346
|
+
var calDate = new Date().toISOString().split('T')[0];
|
|
343
347
|
function renderCalendar(el){
|
|
344
|
-
var
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
348
|
+
var h='<div style="display:flex;gap:8px;align-items:center;margin-bottom:12px">'+
|
|
349
|
+
'<button class="btn btn--secondary" onclick="calNav(-1)"><</button>'+
|
|
350
|
+
'<span style="flex:1;text-align:center;font-weight:700;color:var(--bright)">'+calDate+(calDate===new Date().toISOString().split('T')[0]?' (today)':'')+'</span>'+
|
|
351
|
+
'<button class="btn btn--secondary" onclick="calNav(1)">></button>'+
|
|
352
|
+
'<button class="btn btn--secondary" onclick="calDate=new Date().toISOString().split(\\x27T\\x27)[0];renderCalendar(document.getElementById(\\x27content\\x27))">Today</button>'+
|
|
353
|
+
'</div><div id="calEvents"><div style="text-align:center;padding:20px"><div class="spinner"></div></div></div>';
|
|
349
354
|
el.innerHTML=h;
|
|
355
|
+
apiGet('/api/calendar?date='+calDate).then(function(r){
|
|
356
|
+
var ev=(r&&r.events)||[];
|
|
357
|
+
var ce=document.getElementById('calEvents');if(!ce)return;
|
|
358
|
+
if(ev.length===0){ce.innerHTML='<div class="card" style="text-align:center;color:var(--dim);padding:20px">No events on '+calDate+'</div>';return}
|
|
359
|
+
var out='';ev.forEach(function(x){
|
|
360
|
+
out+='<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>';
|
|
361
|
+
});
|
|
362
|
+
ce.innerHTML=out;
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
function calNav(dir){
|
|
366
|
+
var d=new Date(calDate);d.setDate(d.getDate()+dir);
|
|
367
|
+
calDate=d.toISOString().split('T')[0];
|
|
368
|
+
renderCalendar(document.getElementById('content'));
|
|
350
369
|
}
|
|
351
370
|
|
|
352
371
|
// ---- AGENTS ----
|