nothumanallowed 13.5.176 → 13.5.177
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 +41 -0
- package/src/constants.mjs +1 -1
- package/src/services/web-ui.mjs +66 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.5.
|
|
3
|
+
"version": "13.5.177",
|
|
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/commands/ui.mjs
CHANGED
|
@@ -694,6 +694,47 @@ export async function cmdUI(args) {
|
|
|
694
694
|
return;
|
|
695
695
|
}
|
|
696
696
|
|
|
697
|
+
// GET /api/weather?location=<city> — live weather via wttr.in (no API key)
|
|
698
|
+
if (method === 'GET' && pathname === '/api/weather') {
|
|
699
|
+
const loc = (urlObj.searchParams.get('location') || config.location || '').trim();
|
|
700
|
+
if (!loc) { sendJSON(res, 400, { error: 'location required' }); return; }
|
|
701
|
+
try {
|
|
702
|
+
const wttrRes = await fetch(`https://wttr.in/${encodeURIComponent(loc)}?format=j1`, {
|
|
703
|
+
headers: { 'User-Agent': 'nha-cli/1.0' },
|
|
704
|
+
signal: AbortSignal.timeout(8000),
|
|
705
|
+
});
|
|
706
|
+
if (!wttrRes.ok) { sendJSON(res, 502, { error: `wttr.in ${wttrRes.status}` }); return; }
|
|
707
|
+
const w = await wttrRes.json();
|
|
708
|
+
const cur = w.current_condition?.[0];
|
|
709
|
+
const area = w.nearest_area?.[0];
|
|
710
|
+
if (!cur) { sendJSON(res, 404, { error: 'No weather data' }); return; }
|
|
711
|
+
const forecast = (w.weather || []).slice(0, 3).map(d => ({
|
|
712
|
+
date: d.date,
|
|
713
|
+
maxC: d.maxtempC,
|
|
714
|
+
minC: d.mintempC,
|
|
715
|
+
desc: d.hourly?.[4]?.weatherDesc?.[0]?.value || '',
|
|
716
|
+
rain: d.hourly?.[4]?.chanceofrain || '0',
|
|
717
|
+
}));
|
|
718
|
+
sendJSON(res, 200, {
|
|
719
|
+
city: area?.areaName?.[0]?.value || loc,
|
|
720
|
+
country: area?.country?.[0]?.value || '',
|
|
721
|
+
tempC: cur.temp_C,
|
|
722
|
+
feelsC: cur.FeelsLikeC,
|
|
723
|
+
humidity: cur.humidity,
|
|
724
|
+
windKmph: cur.windspeedKmph,
|
|
725
|
+
windDir: cur.winddir16Point,
|
|
726
|
+
uvIndex: cur.uvIndex,
|
|
727
|
+
desc: cur.weatherDesc?.[0]?.value || '',
|
|
728
|
+
cloudcover: cur.cloudcover,
|
|
729
|
+
forecast,
|
|
730
|
+
});
|
|
731
|
+
} catch (e) {
|
|
732
|
+
sendJSON(res, 502, { error: e.message });
|
|
733
|
+
}
|
|
734
|
+
logRequest(method, pathname, 200, Date.now() - start);
|
|
735
|
+
return;
|
|
736
|
+
}
|
|
737
|
+
|
|
697
738
|
// GET /api/status
|
|
698
739
|
if (method === 'GET' && pathname === '/api/status') {
|
|
699
740
|
const { loadTokens: loadTokSt } = await import('../services/token-store.mjs');
|
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 = '13.5.
|
|
8
|
+
export const VERSION = '13.5.177';
|
|
9
9
|
export const BASE_URL = 'https://nothumanallowed.com/cli';
|
|
10
10
|
export const API_BASE = 'https://nothumanallowed.com/api/v1';
|
|
11
11
|
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -11,8 +11,8 @@ var currentView = 'dashboard';
|
|
|
11
11
|
var chatHistory = [];
|
|
12
12
|
var activeConvId = null;
|
|
13
13
|
var convList = [];
|
|
14
|
-
var dash = {emails:[],events:[],tasks:[],plan:null,status:null};
|
|
15
|
-
var dashLoaded = {emails:false,events:false,tasks:false,contacts:false,notes:false,drive:false,github:false,notion:false,slack:false};
|
|
14
|
+
var dash = {emails:[],events:[],tasks:[],plan:null,status:null,weather:null};
|
|
15
|
+
var dashLoaded = {emails:false,events:false,tasks:false,contacts:false,notes:false,drive:false,github:false,notion:false,slack:false,weather:false};
|
|
16
16
|
var chatStreaming = false;
|
|
17
17
|
var chatAbortController = null;
|
|
18
18
|
|
|
@@ -286,11 +286,43 @@ function apiPost(p,b,m){return fetch(API+p,{method:m||'POST',headers:{'Content-T
|
|
|
286
286
|
function apiPatch(p){return fetch(API+p,{method:'PATCH'}).then(function(r){return r.ok?r.json():null}).catch(function(){return null})}
|
|
287
287
|
|
|
288
288
|
// ---- LOAD DATA ----
|
|
289
|
+
function loadWeather(){
|
|
290
|
+
// Try browser geolocation first, fall back to IP geolocation, then saved config
|
|
291
|
+
var savedLoc=localStorage.getItem('nha_weather_location');
|
|
292
|
+
function fetchWeather(loc){
|
|
293
|
+
apiGet('/api/weather?location='+encodeURIComponent(loc)).then(function(r){
|
|
294
|
+
if(r&&r.tempC){dash.weather=r;dashLoaded.weather=true;if(currentView==='dashboard')render();}
|
|
295
|
+
}).catch(function(){});
|
|
296
|
+
}
|
|
297
|
+
if(savedLoc){fetchWeather(savedLoc);return;}
|
|
298
|
+
if(navigator.geolocation){
|
|
299
|
+
navigator.geolocation.getCurrentPosition(function(pos){
|
|
300
|
+
// Reverse geocode via nominatim (free, no key)
|
|
301
|
+
fetch('https://nominatim.openstreetmap.org/reverse?lat='+pos.coords.latitude+'&lon='+pos.coords.longitude+'&format=json',{headers:{'User-Agent':'nha-cli/1.0'}})
|
|
302
|
+
.then(function(r){return r.json();})
|
|
303
|
+
.then(function(d){
|
|
304
|
+
var city=d.address&&(d.address.city||d.address.town||d.address.village||d.address.county||'');
|
|
305
|
+
if(city){localStorage.setItem('nha_weather_location',city);fetchWeather(city);}
|
|
306
|
+
}).catch(function(){});
|
|
307
|
+
},function(){
|
|
308
|
+
// Geoloc denied — IP fallback
|
|
309
|
+
fetch('https://ipapi.co/json/').then(function(r){return r.json();}).then(function(d){
|
|
310
|
+
var city=d.city||'';if(city){localStorage.setItem('nha_weather_location',city);fetchWeather(city);}
|
|
311
|
+
}).catch(function(){});
|
|
312
|
+
},{timeout:5000});
|
|
313
|
+
} else {
|
|
314
|
+
fetch('https://ipapi.co/json/').then(function(r){return r.json();}).then(function(d){
|
|
315
|
+
var city=d.city||'';if(city){localStorage.setItem('nha_weather_location',city);fetchWeather(city);}
|
|
316
|
+
}).catch(function(){});
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
289
320
|
function loadDash(){
|
|
290
321
|
// Load each API independently - render as each arrives (emails are slow)
|
|
291
322
|
apiGet('/api/status').then(function(r){dash.status=r;render()});
|
|
292
323
|
apiGet('/api/tasks').then(function(r){dash.tasks=(r&&r.tasks)||[];dashLoaded.tasks=true;updateBadges();render()});
|
|
293
324
|
apiGet('/api/calendar').then(function(r){dash.events=(r&&r.events)||[];dashLoaded.events=true;updateBadges();render()});
|
|
325
|
+
if(!dashLoaded.weather)loadWeather();
|
|
294
326
|
return apiGet('/api/emails?page=0&pageSize=25').then(function(r){dash.emails=(r&&r.emails)||[];dash._emailHasMore=r&&r.hasMore;dashLoaded.emails=true;emailPage=0;updateBadges();render()});
|
|
295
327
|
}
|
|
296
328
|
function loadAgents(){return apiGet('/api/agents').then(function(r){agentsList=(r&&r.agents)||[]})}
|
|
@@ -358,11 +390,28 @@ function renderDash(el){
|
|
|
358
390
|
var done=t.filter(function(x){return x.status==='done'}).length;
|
|
359
391
|
var pend=t.length-done;
|
|
360
392
|
var pct=t.length>0?Math.round(done/t.length*100):0;
|
|
393
|
+
var weatherCard;
|
|
394
|
+
if(dashLoaded.weather&&dash.weather){
|
|
395
|
+
var wm=dash.weather;
|
|
396
|
+
var wIcons={Sunny:'☀',Clear:'☀','Partly Cloudy':'⛅','Partly cloudy':'⛅',Cloudy:'☁',Overcast:'☁','Light rain':'🌧','Patchy light drizzle':'🌧','Moderate rain':'🌧','Heavy rain':'🌧',Rain:'🌧',Drizzle:'🌧',Snow:'❄','Light snow':'❄',Fog:'🌫',Mist:'🌫',Thunder:'⚡','Thundery outbreaks':'⚡'};
|
|
397
|
+
var wIcon=wIcons[wm.desc]||'🌥';
|
|
398
|
+
weatherCard='<div class="card" style="cursor:default"><div class="card__title" style="display:flex;align-items:center;justify-content:space-between">'+
|
|
399
|
+
'<span>'+esc(wm.city)+(wm.country?', '+esc(wm.country.slice(0,2)):'')+'</span>'+
|
|
400
|
+
'<span style="font-size:10px;color:var(--dim);cursor:pointer" onclick="nhaSetWeatherLocation()">✎ change</span>'+
|
|
401
|
+
'</div>'+
|
|
402
|
+
'<div class="card__value" style="font-size:28px">'+wIcon+' '+esc(wm.tempC)+'°C</div>'+
|
|
403
|
+
'<div class="card__sub">'+esc(wm.desc)+' · feels '+esc(wm.feelsC)+'°C · 💧'+esc(wm.humidity)+'%</div>'+
|
|
404
|
+
'</div>';
|
|
405
|
+
} else {
|
|
406
|
+
weatherCard='<div class="card" style="cursor:default"><div class="card__title" style="display:flex;align-items:center;justify-content:space-between"><span>Weather</span><span style="font-size:10px;color:var(--dim);cursor:pointer" onclick="nhaSetWeatherLocation()">✎ set location</span></div>'+
|
|
407
|
+
'<div class="card__value" style="font-size:22px">--</div>'+
|
|
408
|
+
'<div class="card__sub">'+(dashLoaded.weather?'No data':'Loading...')+'</div></div>';
|
|
409
|
+
}
|
|
361
410
|
var h='<div class="dash-grid">'+
|
|
362
411
|
'<div class="card"><div class="card__title">Tasks</div><div class="card__value">'+pend+'</div><div class="card__sub">'+done+'/'+t.length+' done ('+pct+'%)</div></div>'+
|
|
363
412
|
'<div class="card"><div class="card__title">Emails</div><div class="card__value">'+(dashLoaded.emails?e.length:'<span class="spinner" style="width:14px;height:14px;display:inline-block;vertical-align:middle"></span>')+'</div><div class="card__sub">'+(dashLoaded.emails?(e.length>0?esc(e[0].from):'Inbox zero'):'Loading...')+'</div></div>'+
|
|
364
413
|
'<div class="card"><div class="card__title">Events</div><div class="card__value">'+ev.length+'</div><div class="card__sub">'+(ev.length>0?esc(ev[0].summary):'No events')+'</div></div>'+
|
|
365
|
-
|
|
414
|
+
weatherCard+
|
|
366
415
|
'</div>';
|
|
367
416
|
if(ev.length>0){h+='<div class="section-title">Events</div>';ev.slice(0,5).forEach(function(x){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>'})}
|
|
368
417
|
if(e.length>0){h+='<div class="section-title">Emails</div>';e.slice(0,5).forEach(function(x){h+='<div class="card email"><div class="email__header"><span class="email__from">'+esc(x.from)+'</span><span class="email__date">'+esc(x.date)+'</span></div><div class="email__subject">'+esc(x.subject)+'</div><div class="email__snippet">'+esc((x.snippet||'').slice(0,120))+'</div></div>'})}
|
|
@@ -3830,6 +3879,20 @@ function handleDaemonEvent(msg) {
|
|
|
3830
3879
|
}
|
|
3831
3880
|
}
|
|
3832
3881
|
|
|
3882
|
+
function nhaSetWeatherLocation() {
|
|
3883
|
+
var current = localStorage.getItem('nha_weather_location') || '';
|
|
3884
|
+
var city = prompt('Enter your city for weather (e.g. "Rome", "Viterbo, Italy"):', current);
|
|
3885
|
+
if (city === null) return;
|
|
3886
|
+
city = city.trim();
|
|
3887
|
+
if (!city) { localStorage.removeItem('nha_weather_location'); dash.weather = null; dashLoaded.weather = false; render(); return; }
|
|
3888
|
+
localStorage.setItem('nha_weather_location', city);
|
|
3889
|
+
dash.weather = null; dashLoaded.weather = false;
|
|
3890
|
+
render();
|
|
3891
|
+
apiGet('/api/weather?location=' + encodeURIComponent(city)).then(function(r) {
|
|
3892
|
+
if (r && r.tempC) { dash.weather = r; dashLoaded.weather = true; render(); }
|
|
3893
|
+
}).catch(function() {});
|
|
3894
|
+
}
|
|
3895
|
+
|
|
3833
3896
|
function npmUpdate() {
|
|
3834
3897
|
var existing = document.getElementById('npmUpdateModal');
|
|
3835
3898
|
if (existing) existing.remove();
|