nothumanallowed 3.2.0 → 3.3.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.2.0",
3
+ "version": "3.3.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": {
@@ -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
- // ── Reuse the executeTool and parseActions logic from chat.mjs ──────────
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.';
@@ -528,28 +550,26 @@ export async function cmdUI(args) {
528
550
  const { textParts, actions } = parseActions(response);
529
551
  const textResponse = textParts.join('\n\n');
530
552
 
531
- // Execute non-destructive tool actions automatically
553
+ // Execute tool actions — all actions are now executed directly
532
554
  let toolResult = null;
555
+ let executedAction = null;
533
556
  if (actions.length > 0) {
534
557
  const { action, params } = actions[0];
535
- // Skip destructive actions in web UI for safety (gmail_send, gmail_reply, calendar_create)
536
- const safeActions = new Set([
537
- 'gmail_list', 'gmail_read', 'gmail_draft',
538
- 'calendar_today', 'calendar_upcoming',
539
- 'task_list', 'task_add', 'task_done',
540
- ]);
541
- if (safeActions.has(action)) {
542
- try {
543
- toolResult = await executeTool(action, params, config);
544
- } catch (e) {
545
- toolResult = `Error: ${e.message}`;
546
- }
547
- } else {
548
- toolResult = `[Action "${action}" requires confirmation. Use nha chat in terminal for write operations.]`;
558
+ executedAction = action;
559
+ try {
560
+ toolResult = await executeTool(action, params, config);
561
+ } catch (e) {
562
+ toolResult = `Error executing ${action}: ${e.message}`;
549
563
  }
550
564
  }
551
565
 
552
- sendJSON(res, 200, { response: textResponse, toolResult, actions });
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
+ }
571
+
572
+ sendJSON(res, 200, { response: fullResponse, toolResult, actions });
553
573
  } catch (e) {
554
574
  sendJSON(res, 200, { response: null, error: e.message });
555
575
  }
@@ -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: no response'})}
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