nothumanallowed 13.2.58 → 13.2.59

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": "13.2.58",
3
+ "version": "13.2.59",
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": {
@@ -2877,24 +2877,57 @@ export async function cmdUI(args) {
2877
2877
  sendToken('[Reading GitHub...] ');
2878
2878
  try {
2879
2879
  const gh = await import('../services/github.mjs');
2880
- const issues = await withTimeout(gh.listIssues(config, config.githubRepo || '', 10), 'GitHubAgent');
2881
- toolData = typeof issues === 'string' ? issues : JSON.stringify(issues);
2880
+ if (!config.github?.token) {
2881
+ toolData = 'GitHub token not configured. Run: nha config set github-token YOUR_PAT';
2882
+ } else {
2883
+ const parts = [];
2884
+ // Notifications (always available)
2885
+ try {
2886
+ const notifs = await withTimeout(gh.listNotifications(config, 15), 'GitHubAgent-notifs');
2887
+ if (notifs) parts.push('## GitHub Notifications\n' + notifs);
2888
+ } catch (e) { /* skip */ }
2889
+ // Issues/PRs on configured repo if available
2890
+ const repo = config.github?.defaultRepo || '';
2891
+ if (repo) {
2892
+ try {
2893
+ const issues = await withTimeout(gh.listIssues(config, repo, 'open', 10), 'GitHubAgent-issues');
2894
+ if (issues) parts.push('## Open Issues (' + repo + ')\n' + issues);
2895
+ } catch (e) { /* skip */ }
2896
+ try {
2897
+ const prs = await withTimeout(gh.listPRs(config, repo, 'open', 10), 'GitHubAgent-prs');
2898
+ if (prs) parts.push('## Open PRs (' + repo + ')\n' + prs);
2899
+ } catch (e) { /* skip */ }
2900
+ }
2901
+ toolData = parts.length > 0 ? parts.join('\n\n') : 'No GitHub data available.';
2902
+ }
2882
2903
  } catch (e) { toolData = `GitHub read failed: ${e.message}`; }
2883
2904
 
2884
2905
  } else if (agent === 'NotionAgent') {
2885
2906
  sendToken('[Searching Notion...] ');
2886
2907
  try {
2887
2908
  const nt = await import('../services/notion.mjs');
2888
- const results = await withTimeout(nt.search(config, stepPrompt, 10), 'NotionAgent');
2889
- toolData = typeof results === 'string' ? results : JSON.stringify(results);
2909
+ if (!config.notion?.token) {
2910
+ toolData = 'Notion token not configured. Run: nha config set notion-token YOUR_TOKEN';
2911
+ } else {
2912
+ const results = await withTimeout(nt.search(config, stepPrompt, 10), 'NotionAgent');
2913
+ toolData = typeof results === 'string' ? results : JSON.stringify(results);
2914
+ }
2890
2915
  } catch (e) { toolData = `Notion search failed: ${e.message}`; }
2891
2916
 
2892
2917
  } else if (agent === 'SlackAgent') {
2893
2918
  sendToken('[Reading Slack...] ');
2894
2919
  try {
2895
2920
  const sl = await import('../services/slack.mjs');
2896
- const channels = await withTimeout(sl.listChannels(config, 10), 'SlackAgent');
2897
- toolData = typeof channels === 'string' ? channels : JSON.stringify(channels);
2921
+ if (!config.slack?.token) {
2922
+ toolData = 'Slack token not configured. Run: nha config set slack-token xoxb-YOUR_TOKEN';
2923
+ } else {
2924
+ const parts = [];
2925
+ try {
2926
+ const channels = await withTimeout(sl.listChannels(config, 10), 'SlackAgent-channels');
2927
+ if (channels) parts.push('## Slack Channels\n' + (typeof channels === 'string' ? channels : JSON.stringify(channels)));
2928
+ } catch (e) { /* skip */ }
2929
+ toolData = parts.length > 0 ? parts.join('\n\n') : 'No Slack data available.';
2930
+ }
2898
2931
  } catch (e) { toolData = `Slack read failed: ${e.message}`; }
2899
2932
 
2900
2933
  } else if (agent === 'DriveAgent') {
package/src/config.mjs CHANGED
@@ -102,6 +102,7 @@ const DEFAULT_CONFIG = {
102
102
  },
103
103
  github: {
104
104
  token: '',
105
+ defaultRepo: '',
105
106
  },
106
107
  notion: {
107
108
  token: '',
@@ -264,6 +265,8 @@ export function setConfigValue(key, value) {
264
265
  'proactive-deadlines': 'ops.proactive.deadlines',
265
266
  'github-token': 'github.token',
266
267
  'gh-token': 'github.token',
268
+ 'github-repo': 'github.defaultRepo',
269
+ 'gh-repo': 'github.defaultRepo',
267
270
  'notion-token': 'notion.token',
268
271
  'slack-token': 'slack.token',
269
272
  'name': 'profile.name',
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.2.58';
8
+ export const VERSION = '13.2.59';
9
9
  export const BASE_URL = 'https://nothumanallowed.com/cli';
10
10
  export const API_BASE = 'https://nothumanallowed.com/api/v1';
11
11
 
@@ -1326,7 +1326,7 @@ function renderGitHub(el){
1326
1326
  // Header: user profile + repo input
1327
1327
  var userHtml='';
1328
1328
  if(user&&user.login){
1329
- userHtml='<div style="display:flex;align-items:center;gap:10px;margin-bottom:14px;padding:10px 14px;background:var(--bg2);border-radius:var(--r);border:1px solid var(--border)">'+(user.avatar?'<img src="'+esc(user.avatar)+'" style="width:36px;height:36px;border-radius:50%;object-fit:cover" alt="">':'')+'<div><div style="font-weight:700;font-size:13px;color:var(--green)">@'+esc(user.login)+'</div>'+(user.name?'<div style="font-size:11px;color:var(--dim)">'+esc(user.name)+'</div>':'')+'</div></div>';
1329
+ userHtml='<div style="display:flex;align-items:center;gap:10px;margin-bottom:14px;padding:10px 14px;background:var(--bg2);border-radius:var(--r);border:1px solid var(--border)">'+(user.avatar?'<img src="'+esc(user.avatar)+'" style="width:36px;height:36px;border-radius:50%;object-fit:cover" alt="">':'')+'<div style="flex:1"><div style="font-weight:700;font-size:13px;color:var(--green)">@'+esc(user.login)+'</div>'+(user.name?'<div style="font-size:11px;color:var(--dim)">'+esc(user.name)+'</div>':'')+'</div><button onclick="disconnectService(\\x27github-token\\x27,function(el){ghData=null;renderGitHub(el)})" style="background:var(--bg3);border:1px solid var(--red);color:var(--red);padding:4px 10px;border-radius:var(--r);font-size:11px">Disconnect</button></div>';
1330
1330
  }
1331
1331
  var h=userHtml+'<div style="display:flex;gap:8px;margin-bottom:8px;flex-wrap:wrap"><input type="text" id="ghRepo" placeholder="owner/repo" value="'+esc(ghRepo)+'" style="flex:1;min-width:180px;font-size:13px;padding:10px 14px" onkeydown="if(event.key===\\x27Enter\\x27)loadGhIssues()"><button onclick="loadGhIssues()" style="background:var(--green3);color:var(--bg);padding:8px 16px;border-radius:var(--r);font-weight:700;font-size:12px">Issues</button><button onclick="loadGhPRs()" style="background:var(--cyan);color:var(--bg);padding:8px 16px;border-radius:var(--r);font-weight:700;font-size:12px">PRs</button></div>';
1332
1332
  // My repos as clickable pills
@@ -1366,17 +1366,19 @@ function renderGitHub(el){
1366
1366
  renderGhData(r);
1367
1367
  });
1368
1368
  }
1369
- function loadGhIssues(){var inp=document.getElementById('ghRepo');if(!inp||!inp.value.trim())return;ghRepo=inp.value.trim();var el=document.getElementById('content');el.innerHTML='<div style="text-align:center;padding:40px"><div class="spinner"></div></div>';apiGet('/api/github/issues?repo='+encodeURIComponent(ghRepo)).then(function(r){if(ghData){ghData.issues=r.issues||[];ghData.prs=ghData.prs||[];ghData.repo=r.repo}else{ghData={issues:r.issues||[],prs:[],notifications:[]}}renderGitHub(document.getElementById('content'))})}
1369
+ function loadGhIssues(){var inp=document.getElementById('ghRepo');if(!inp||!inp.value.trim())return;ghRepo=inp.value.trim();apiPost('/api/config',{key:'github-repo',value:ghRepo}).catch(function(){});var el=document.getElementById('content');el.innerHTML='<div style="text-align:center;padding:40px"><div class="spinner"></div></div>';apiGet('/api/github/issues?repo='+encodeURIComponent(ghRepo)).then(function(r){if(ghData){ghData.issues=r.issues||[];ghData.prs=ghData.prs||[];ghData.repo=r.repo}else{ghData={issues:r.issues||[],prs:[],notifications:[]}}renderGitHub(document.getElementById('content'))})}
1370
1370
  function loadGhPRs(){var inp=document.getElementById('ghRepo');if(!inp||!inp.value.trim())return;ghRepo=inp.value.trim();var el=document.getElementById('content');el.innerHTML='<div style="text-align:center;padding:40px"><div class="spinner"></div></div>';apiGet('/api/github/prs?repo='+encodeURIComponent(ghRepo)).then(function(r){if(ghData){ghData.prs=r.prs||[];ghData.issues=ghData.issues||[];ghData.repo=r.repo}else{ghData={prs:r.prs||[],issues:[],notifications:[]}}renderGitHub(document.getElementById('content'))})}
1371
1371
  function ghMarkRead(){apiPost('/api/github/mark-read',{}).then(function(){if(ghData)ghData.notifications=[];renderGitHub(document.getElementById('content'))})}
1372
1372
 
1373
1373
  // ---- NOTION ----
1374
1374
  function renderNotion(el){
1375
1375
  apiGet('/api/notion/search?q=').then(function(r){
1376
- var banner=r&&r.error?setupBanner('Notion','nha config set notion-token YOUR_INTEGRATION_TOKEN')+'<div style="color:var(--dim);font-size:12px;padding:8px 0">Get an Integration Token from notion.so/my-integrations → New integration → Internal → copy Secret</div>':'';
1377
- el.innerHTML=banner+'<div style="display:flex;gap:8px;margin-bottom:16px"><input type="text" id="notionQuery" placeholder="Search Notion pages..." style="flex:1;font-size:13px;padding:10px 14px" onkeydown="if(event.key===\\x27Enter\\x27)searchNotion()"><button onclick="searchNotion()" style="background:var(--green3);color:var(--bg);padding:8px 16px;border-radius:var(--r);font-weight:700;font-size:12px">Search</button></div><div id="notionResults"></div>';
1376
+ var isOk=!(r&&r.error);
1377
+ var banner=isOk?'':''+setupBanner('Notion','nha config set notion-token YOUR_INTEGRATION_TOKEN')+'<div style="color:var(--dim);font-size:12px;padding:8px 0">Get an Integration Token from notion.so/my-integrations New integration → Internal → copy Secret</div>';
1378
+ var disconnectBtn=isOk?'<button onclick="disconnectService(\\x27notion-token\\x27,renderNotion)" style="background:var(--bg3);border:1px solid var(--red);color:var(--red);padding:4px 10px;border-radius:var(--r);font-size:11px;margin-bottom:12px">Disconnect Notion</button>':'';
1379
+ el.innerHTML=banner+disconnectBtn+'<div style="display:flex;gap:8px;margin-bottom:16px"><input type="text" id="notionQuery" placeholder="Search Notion pages..." style="flex:1;font-size:13px;padding:10px 14px" onkeydown="if(event.key===\\x27Enter\\x27)searchNotion()">'+(isOk?'<button onclick="searchNotion()" style="background:var(--green3);color:var(--bg);padding:8px 16px;border-radius:var(--r);font-weight:700;font-size:12px">Search</button>':'<button style="background:var(--bg3);color:var(--dim);padding:8px 16px;border-radius:var(--r);font-size:12px" disabled>Search</button>')+'</div><div id="notionResults"></div>';
1378
1380
  }).catch(function(){
1379
- el.innerHTML=setupBanner('Notion','nha config set notion-token YOUR_INTEGRATION_TOKEN')+'<div style="display:flex;gap:8px;margin-bottom:16px"><input type="text" id="notionQuery" placeholder="Search Notion pages..." style="flex:1;font-size:13px;padding:10px 14px"><button style="background:var(--green3);color:var(--bg);padding:8px 16px;border-radius:var(--r);font-weight:700;font-size:12px" disabled>Search</button></div>';
1381
+ el.innerHTML=setupBanner('Notion','nha config set notion-token YOUR_INTEGRATION_TOKEN')+'<div style="display:flex;gap:8px;margin-bottom:16px"><input type="text" id="notionQuery" placeholder="Search Notion pages..." style="flex:1;font-size:13px;padding:10px 14px"><button style="background:var(--bg3);color:var(--dim);padding:8px 16px;border-radius:var(--r);font-size:12px" disabled>Search</button></div>';
1380
1382
  });
1381
1383
  }
1382
1384
  function searchNotion(){
@@ -1399,6 +1401,13 @@ function loadNotionPage(id){
1399
1401
  }
1400
1402
 
1401
1403
  // ---- SLACK ----
1404
+ function disconnectService(configKey,renderFn){
1405
+ if(!confirm('Remove this connection? You can reconnect anytime.'))return;
1406
+ apiPost('/api/config',{key:configKey,value:''}).then(function(){
1407
+ var el=document.getElementById('content');
1408
+ if(el&&renderFn)renderFn(el);
1409
+ }).catch(function(){});
1410
+ }
1402
1411
  function setupBanner(service,cmd){return '<div style="display:flex;align-items:center;gap:12px;padding:12px 16px;background:var(--bg2);border:1px solid var(--border);border-left:3px solid var(--amber);border-radius:var(--r);margin-bottom:14px;font-size:12px"><span style="font-size:20px">&#128274;</span><div><div style="color:var(--fg);font-weight:600;margin-bottom:2px">'+esc(service)+' not configured</div><div style="color:var(--dim);font-family:var(--mono);font-size:11px">'+esc(cmd)+'</div></div></div>';}
1403
1412
  var slackData=null;
1404
1413
  function renderSlack(el){
@@ -1407,7 +1416,7 @@ function renderSlack(el){
1407
1416
  if(r&&r.error){el.innerHTML=setupBanner('Slack','nha config set slack-token xoxb-YOUR_TOKEN')+'<div style="color:var(--dim);font-size:12px;padding:8px 0">Get a Bot Token from api.slack.com/apps → OAuth &amp; Permissions → Bot Token Scopes: channels:read, channels:history, users:read</div>';return}
1408
1417
  slackData=r;
1409
1418
  var channels=r.channels||[];
1410
- var h='<div class="section-title">Channels ('+channels.length+')</div>';
1419
+ var h='<div style="display:flex;align-items:center;margin-bottom:8px"><div class="section-title" style="margin:0;flex:1">Channels ('+channels.length+')</div><button onclick="disconnectService(\\x27slack-token\\x27,renderSlack)" style="background:var(--bg3);border:1px solid var(--red);color:var(--red);padding:4px 10px;border-radius:var(--r);font-size:11px">Disconnect</button></div>';
1411
1420
  if(channels.length===0){h+='<div class="card" style="text-align:center;color:var(--dim);padding:20px">No channels found</div>'}
1412
1421
  channels.forEach(function(c){h+='<div class="card" style="padding:10px 14px;cursor:pointer" onclick="loadSlackChannel(\\x27'+esc(c.id)+'\\x27,\\x27'+esc(c.name)+'\\x27)"><span style="color:var(--green);font-weight:700">#'+esc(c.name)+'</span> <span style="font-size:10px;color:var(--dim)">'+c.members+' members</span>'+(c.purpose?'<div style="font-size:11px;color:var(--dim);margin-top:2px">'+esc(c.purpose)+'</div>':'')+'</div>'});
1413
1422
  h+='<div id="slackMessages"></div>';