nothumanallowed 16.0.10 → 16.0.11

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": "16.0.10",
3
+ "version": "16.0.11",
4
4
  "description": "NotHumanAllowed — 38 AI agents, 80 tools, Studio (visual agentic workflows). Email, calendar, browser automation, screen capture, canvas, cron/heartbeat, Alexandria E2E messaging, GitHub, Notion, Slack, voice chat, free AI (Liara), 28 languages. Zero-dependency CLI.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/constants.mjs CHANGED
@@ -5,7 +5,7 @@ import { fileURLToPath } from 'url';
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
7
7
 
8
- export const VERSION = '16.0.10';
8
+ export const VERSION = '16.0.11';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -1908,6 +1908,52 @@ class TelegramResponder {
1908
1908
  async _tryDirectFreshCalendarAction(userMessage, config) {
1909
1909
  if (!userMessage || typeof userMessage !== 'string') return null;
1910
1910
  const lower = userMessage.toLowerCase().normalize('NFD').replace(/[̀-ͯ]/g, '');
1911
+ const chatId = this._lastDirectAuditChatId;
1912
+ const { executeTool: _executeToolPre } = await import('./tool-executor.mjs');
1913
+
1914
+ // ─── ANAPHORIC delete + CONFIRMATION yes ────────────────────────────────
1915
+ // If the previous turn ran a LIST/LAST-SHOWN and the user now says
1916
+ // "cancellalo / eliminalo / quello / si / conferma / fallo", resolve the
1917
+ // referent from this._lastContextByChatId[chatId].lastCalendarEvents.
1918
+ const isAnaphoric = /\b(cancell|elimin|rimuov)[aeiloy]+(lo|la|li|le|gli)?\b/.test(lower)
1919
+ && !this._extractCalendarProposal(userMessage).date
1920
+ && !this._extractCalendarProposal(userMessage).title;
1921
+ const isYesConfirm = /^\s*(s[ìi]\b|si\s|sì\s|ok\b|okay\b|certo\b|certamente\b|d'?accordo\b|fai|fallo|procedi|esegui|conferm[oa]|yes\b|yep\b|confirm\b|do\s*it|go\s*ahead)/i.test(userMessage.trim());
1922
+ if (chatId && (isAnaphoric || isYesConfirm)) {
1923
+ const ctx = this._lastContextByChatId[chatId] || {};
1924
+ const pendingEvents = ctx.lastCalendarEvents || ctx.pendingDeleteEvents || [];
1925
+ // Strict: only auto-execute if the previous turn LIST/proposal had a
1926
+ // single deletable event, or if pendingDelete is explicitly set.
1927
+ const eligible = ctx.pendingDeleteEvents && ctx.pendingDeleteEvents.length > 0
1928
+ ? ctx.pendingDeleteEvents
1929
+ : (pendingEvents.length === 1 ? pendingEvents : null);
1930
+ if (eligible && eligible.length > 0) {
1931
+ let ok = 0, ko = 0;
1932
+ const failed = [];
1933
+ for (const ev of eligible) {
1934
+ if (!ev.eventId) { ko++; failed.push(ev.summary || '(no id)'); continue; }
1935
+ try {
1936
+ await _executeToolPre('calendar_delete', { eventId: ev.eventId }, config);
1937
+ ok++;
1938
+ } catch (e) {
1939
+ ko++;
1940
+ failed.push(`${ev.summary || ev.eventId} (${e.message?.slice(0, 60) || 'err'})`);
1941
+ }
1942
+ }
1943
+ // Clear the pending state so we don't double-delete on next yes.
1944
+ delete this._lastContextByChatId[chatId].pendingDeleteEvents;
1945
+ delete this._lastContextByChatId[chatId].lastCalendarEvents;
1946
+ try { (await import('./telegram-context.mjs')).saveTelegramContext(this._lastContextByChatId); } catch {}
1947
+
1948
+ const subject = eligible.length === 1 ? `"${eligible[0].summary}"` : `${eligible.length} appuntamenti`;
1949
+ const lines = [`Ho cancellato ${subject}.`];
1950
+ if (ko > 0) lines.push(`Non sono riuscito a cancellarne ${ko}: ${failed.slice(0, 3).join(', ')}`);
1951
+ this._recordAudit(chatId, { tool: 'calendar_delete', success: ok > 0, summary: `cancellati ${ok}` });
1952
+ return { action: 'calendar_delete', success: ok > 0, message: lines.join('\n') };
1953
+ }
1954
+ // No eligible referent — fall through; the LLM will ask for clarification.
1955
+ }
1956
+
1911
1957
 
1912
1958
  const MONTHS_IT = { gennaio:1, febbraio:2, marzo:3, aprile:4, maggio:5, giugno:6, luglio:7, agosto:8, settembre:9, ottobre:10, novembre:11, dicembre:12 };
1913
1959
  const MONTHS_EN = { january:1, february:2, march:3, april:4, may:5, june:6, july:7, august:8, september:9, october:10, november:11, december:12, jan:1, feb:2, mar:3, apr:4, jun:6, jul:7, aug:8, sep:9, oct:10, nov:11, dec:12 };
@@ -2090,54 +2136,44 @@ class TelegramResponder {
2090
2136
 
2091
2137
  // ─── LIST intents ──────────────────────────────────────────────────────
2092
2138
  if (isList && !isDelete && !isVerify && !isCreate && !isMove) {
2093
- // "appuntamenti di oggi"
2094
- if (/\b(oggi|today)\b/.test(lower)) {
2095
- try {
2096
- const out = await executeTool('calendar_today', {}, config);
2097
- return { action: 'calendar_today', success: true, message: String(out) };
2098
- } catch (e) { return { action: 'calendar_today', success: false, message: `Errore: ${e.message}` }; }
2099
- }
2100
- // "appuntamenti di domani"
2101
- if (/\b(domani|tomorrow)\b/.test(lower)) {
2139
+ // Helper that runs the tool, parses the events and remembers them for
2140
+ // anaphoric resolution in the NEXT turn ("cancellalo", "spostali tutti").
2141
+ const runListAndRemember = async (toolName, args, actionKey) => {
2102
2142
  try {
2103
- const out = await executeTool('calendar_tomorrow', {}, config);
2104
- return { action: 'calendar_tomorrow', success: true, message: String(out) };
2105
- } catch (e) { return { action: 'calendar_tomorrow', success: false, message: `Errore: ${e.message}` }; }
2106
- }
2107
- // "appuntamenti della settimana"
2108
- if (/\b(settimana|week|questa\s+settimana|this\s+week)\b/.test(lower)) {
2109
- try {
2110
- const out = await executeTool('calendar_week', {}, config);
2111
- return { action: 'calendar_week', success: true, message: String(out) };
2112
- } catch (e) { return { action: 'calendar_week', success: false, message: `Errore: ${e.message}` }; }
2113
- }
2114
- // "appuntamenti di maggio" — month name + optional year
2143
+ const out = await executeTool(toolName, args, config);
2144
+ const events = this._parseEventsFromToolOutput(String(out));
2145
+ if (chatId) {
2146
+ const prev = this._lastContextByChatId[chatId] || {};
2147
+ this._lastContextByChatId[chatId] = {
2148
+ ...prev,
2149
+ lastCalendarEvents: events,
2150
+ lastCalendarListAt: Date.now(),
2151
+ lastCalendarSource: { tool: toolName, args },
2152
+ };
2153
+ try { (await import('./telegram-context.mjs')).saveTelegramContext(this._lastContextByChatId); } catch {}
2154
+ }
2155
+ return { action: actionKey, success: true, message: String(out) };
2156
+ } catch (e) { return { action: actionKey, success: false, message: `Errore: ${e.message}` }; }
2157
+ };
2158
+
2159
+ if (/\b(oggi|today)\b/.test(lower))
2160
+ return await runListAndRemember('calendar_today', {}, 'calendar_today');
2161
+ if (/\b(domani|tomorrow)\b/.test(lower))
2162
+ return await runListAndRemember('calendar_tomorrow', {}, 'calendar_tomorrow');
2163
+ if (/\b(settimana|week|questa\s+settimana|this\s+week)\b/.test(lower))
2164
+ return await runListAndRemember('calendar_week', {}, 'calendar_week');
2115
2165
  const monthMatch = lower.match(new RegExp(`\\b(${Object.keys(MONTH_MAP).join('|')})(?:\\s+(20\\d{2}))?\\b`));
2116
2166
  if (monthMatch) {
2117
2167
  const monthNum = MONTH_MAP[monthMatch[1]];
2118
2168
  const yearNum = parseInt(monthMatch[2] || String(new Date().getFullYear()), 10);
2119
- // calendar_month accepts a month string like "2026-05"
2120
2169
  const monthStr = `${yearNum}-${String(monthNum).padStart(2, '0')}`;
2121
- try {
2122
- const out = await executeTool('calendar_month', { month: monthStr }, config);
2123
- return { action: 'calendar_month', success: true, message: String(out) };
2124
- } catch (e) { return { action: 'calendar_month', success: false, message: `Errore: ${e.message}` }; }
2170
+ return await runListAndRemember('calendar_month', { month: monthStr }, 'calendar_month');
2125
2171
  }
2126
- // "appuntamenti del 15 maggio" — specific date
2127
2172
  const dateExtracted = this._extractCalendarProposal(userMessage);
2128
- if (dateExtracted.date) {
2129
- try {
2130
- const out = await executeTool('calendar_date', { date: dateExtracted.date }, config);
2131
- return { action: 'calendar_date', success: true, message: String(out) };
2132
- } catch (e) { return { action: 'calendar_date', success: false, message: `Errore: ${e.message}` }; }
2133
- }
2134
- // Generic "appuntamenti prossimi" → upcoming 48h
2135
- if (/\b(prossim|next|upcoming|in\s+arrivo)/.test(lower)) {
2136
- try {
2137
- const out = await executeTool('calendar_upcoming', { hours: 48 }, config);
2138
- return { action: 'calendar_upcoming', success: true, message: String(out) };
2139
- } catch (e) { return { action: 'calendar_upcoming', success: false, message: `Errore: ${e.message}` }; }
2140
- }
2173
+ if (dateExtracted.date)
2174
+ return await runListAndRemember('calendar_date', { date: dateExtracted.date }, 'calendar_date');
2175
+ if (/\b(prossim|next|upcoming|in\s+arrivo)/.test(lower))
2176
+ return await runListAndRemember('calendar_upcoming', { hours: 48 }, 'calendar_upcoming');
2141
2177
  // Fall through — let the LLM handle ambiguous list requests.
2142
2178
  }
2143
2179