nothumanallowed 15.1.27 → 15.1.29
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": "15.1.
|
|
3
|
+
"version": "15.1.29",
|
|
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 = '15.1.
|
|
8
|
+
export const VERSION = '15.1.29';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
|
@@ -108,6 +108,16 @@ class SandboxManager {
|
|
|
108
108
|
const MAX_RETRIES = 3;
|
|
109
109
|
this._stoppedByUser = false;
|
|
110
110
|
|
|
111
|
+
// Server version banner — lets the user verify their `nha ui` process is
|
|
112
|
+
// actually running the latest code (npm install only updates files on disk;
|
|
113
|
+
// the running process must be killed and restarted to pick them up).
|
|
114
|
+
if (_attempt === 1) {
|
|
115
|
+
try {
|
|
116
|
+
const { VERSION } = await import('../../constants.mjs');
|
|
117
|
+
emit({ type: 'status', msg: `nha sandbox manager v${VERSION} — if this is older than what you installed, kill nha ui and restart it (the running process won't pick up new code by itself)` });
|
|
118
|
+
} catch { /* non-fatal */ }
|
|
119
|
+
}
|
|
120
|
+
|
|
111
121
|
// Kill any existing sandbox
|
|
112
122
|
if (this.isRunning()) {
|
|
113
123
|
emit({ type: 'phase', phase: 'cleanup', msg: 'Stopping previous sandbox...' });
|
|
@@ -714,7 +714,12 @@ calendar_update(eventId, summary?, location?, description?, start?, end?)
|
|
|
714
714
|
calendar_delete(eventId) — Delete an event you have a REAL eventId for. Same rules as update: never invent, never use placeholders.
|
|
715
715
|
calendar_move(eventId, newStart, newEnd) — Reschedule.
|
|
716
716
|
calendar_find(query, daysAhead?) — Search events by name. Returns eventIds. Use ONLY when you don't already have the id.
|
|
717
|
-
|
|
717
|
+
- daysAhead default is 7 — pass 30 or 60 for broader search if not found in 7.
|
|
718
|
+
- Query is matched case-insensitively against summary AND description.
|
|
719
|
+
- If a user names an event ambiguously (e.g. "Italiano della BMW" via voice-to-text typo for "Tagliando della BMW"), try BOTH the literal query AND alternative spellings.
|
|
720
|
+
calendar_today() / calendar_tomorrow() / calendar_date(date) / calendar_upcoming(hours?) / calendar_week(startDate?) / calendar_month(month?) — Read-only listings.
|
|
721
|
+
- **calendar_week with NO arguments** returns the CURRENT calendar week (Mon..Sun). Use this when the user says "questa settimana" / "this week". Do NOT pass startDate — let the tool compute the right Monday. Only pass startDate when the user explicitly names a different week.
|
|
722
|
+
- **"elimina gli appuntamenti di [date]"** → call calendar_date(date) FIRST to get real eventIds, then calendar_delete with each real id.
|
|
718
723
|
schedule_meeting(clientName, subject, location, durationMinutes, dateFrom, dateTo) — Find optimal slots considering travel time.
|
|
719
724
|
|
|
720
725
|
### Gmail / IMAP
|
|
@@ -1494,7 +1499,18 @@ export async function executeTool(action, params, config) {
|
|
|
1494
1499
|
}
|
|
1495
1500
|
|
|
1496
1501
|
case 'calendar_week': {
|
|
1497
|
-
|
|
1502
|
+
// Default to MONDAY of the current ISO week, not "today". When a user
|
|
1503
|
+
// asks "questa settimana"/"this week", they mean Mon..Sun of the calendar
|
|
1504
|
+
// week — not "next 7 days from today". If they want the latter they can
|
|
1505
|
+
// pass startDate explicitly.
|
|
1506
|
+
const isoMondayOfCurrentWeek = () => {
|
|
1507
|
+
const d = new Date();
|
|
1508
|
+
const day = d.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat
|
|
1509
|
+
const offset = day === 0 ? -6 : 1 - day; // shift back to Monday
|
|
1510
|
+
const monday = new Date(d.getTime() + offset * 86400000);
|
|
1511
|
+
return `${monday.getFullYear()}-${String(monday.getMonth() + 1).padStart(2, '0')}-${String(monday.getDate()).padStart(2, '0')}`;
|
|
1512
|
+
};
|
|
1513
|
+
const startDate = params.startDate || isoMondayOfCurrentWeek();
|
|
1498
1514
|
const from = new Date(startDate + 'T00:00:00');
|
|
1499
1515
|
const to = new Date(from.getTime() + 7 * 86400000);
|
|
1500
1516
|
const events = await listEvents(config, 'primary', from, to);
|
|
@@ -1561,25 +1577,57 @@ export async function executeTool(action, params, config) {
|
|
|
1561
1577
|
}
|
|
1562
1578
|
|
|
1563
1579
|
case 'calendar_find': {
|
|
1564
|
-
const
|
|
1565
|
-
const
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1580
|
+
const queryRaw = (params.query || '').trim();
|
|
1581
|
+
const query = queryRaw.toLowerCase();
|
|
1582
|
+
// Token-level fuzzy match: handles voice-to-text typos like
|
|
1583
|
+
// "Italiano della BMW" matching event "Tagliando BMW" via the shared
|
|
1584
|
+
// significant token "BMW". Stop-words and articles are ignored.
|
|
1585
|
+
const STOP_WORDS = new Set(['il','la','i','le','gli','un','una','di','del','dello','della','dei','degli','delle','a','al','allo','alla','ai','agli','alle','con','per','su','da','in','e','o','che','the','a','an','of','for','to','in','on','with','and','or','my','your']);
|
|
1586
|
+
const tokens = query.split(/\s+/).filter(t => t.length >= 3 && !STOP_WORDS.has(t));
|
|
1587
|
+
|
|
1588
|
+
const requestedDays = params.daysAhead || 30;
|
|
1589
|
+
// Try the requested range first, then auto-broaden to 90 days if empty.
|
|
1590
|
+
// Voice users frequently underestimate how far ahead an event is.
|
|
1591
|
+
const tryRange = async (days) => {
|
|
1592
|
+
const from = new Date();
|
|
1593
|
+
const to = new Date(from.getTime() + days * 86400000);
|
|
1594
|
+
const events = await listEvents(config, 'primary', from, to);
|
|
1569
1595
|
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1596
|
+
// Strict substring match first
|
|
1597
|
+
let matches = events.filter(e =>
|
|
1598
|
+
(e.summary || '').toLowerCase().includes(query) ||
|
|
1599
|
+
(e.description || '').toLowerCase().includes(query)
|
|
1600
|
+
);
|
|
1601
|
+
|
|
1602
|
+
// Fuzzy fallback: any significant token (3+ chars, no stop-word) matches
|
|
1603
|
+
if (matches.length === 0 && tokens.length > 0) {
|
|
1604
|
+
matches = events.filter(e => {
|
|
1605
|
+
const hay = ((e.summary || '') + ' ' + (e.description || '')).toLowerCase();
|
|
1606
|
+
return tokens.some(t => hay.includes(t));
|
|
1607
|
+
});
|
|
1608
|
+
}
|
|
1609
|
+
return { events, matches };
|
|
1610
|
+
};
|
|
1574
1611
|
|
|
1575
|
-
|
|
1612
|
+
let { matches } = await tryRange(requestedDays);
|
|
1613
|
+
let effectiveDays = requestedDays;
|
|
1614
|
+
if (matches.length === 0 && requestedDays < 90) {
|
|
1615
|
+
const broad = await tryRange(90);
|
|
1616
|
+
matches = broad.matches;
|
|
1617
|
+
effectiveDays = 90;
|
|
1618
|
+
}
|
|
1576
1619
|
|
|
1620
|
+
if (matches.length === 0) {
|
|
1621
|
+
return `No events found matching "${queryRaw}" in the next ${effectiveDays} days (tried fuzzy match on tokens: ${tokens.join(', ') || '(none)'}). Try calendar_week or calendar_month for a broader view.`;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
const widened = effectiveDays > requestedDays ? ` (auto-broadened to ${effectiveDays} days)` : '';
|
|
1577
1625
|
return matches.map((e, i) => {
|
|
1578
1626
|
const time = e.isAllDay ? 'All day' : `${formatTime(e.start)} - ${formatTime(e.end)}`;
|
|
1579
1627
|
const date = e.start.split('T')[0];
|
|
1580
1628
|
const loc = e.location ? ` | Location: ${e.location}` : '';
|
|
1581
1629
|
return `${i + 1}. [eventId: ${e.id}] ${date} ${time} — ${e.summary}${loc}`;
|
|
1582
|
-
}).join('\n');
|
|
1630
|
+
}).join('\n') + (widened ? `\n${widened}` : '');
|
|
1583
1631
|
}
|
|
1584
1632
|
|
|
1585
1633
|
case 'calendar_update': {
|