nothumanallowed 13.2.39 → 13.2.41
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 +42 -31
- package/src/constants.mjs +1 -1
- package/src/services/llm.mjs +40 -10
- package/src/services/web-ui.mjs +9 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nothumanallowed",
|
|
3
|
-
"version": "13.2.
|
|
3
|
+
"version": "13.2.41",
|
|
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
|
@@ -2546,25 +2546,30 @@ export async function cmdUI(args) {
|
|
|
2546
2546
|
const plannerLang = (() => { const LANG_MAP2 = {en:'English',it:'Italian',es:'Spanish',fr:'French',de:'German',pt:'Portuguese',zh:'Chinese',ja:'Japanese',ar:'Arabic',hi:'Hindi',ru:'Russian',nl:'Dutch',pl:'Polish',tr:'Turkish',ko:'Korean'}; const lc = (config?.language||'it').slice(0,2); return LANG_MAP2[lc]||'Italian'; })();
|
|
2547
2547
|
|
|
2548
2548
|
// ── Fast keyword-based planning (no LLM call needed for common patterns) ──────
|
|
2549
|
-
// Detect task intent from keywords — avoids sending the full task through SENTINEL
|
|
2550
2549
|
const taskLow = task.toLowerCase();
|
|
2551
|
-
const hasEmail
|
|
2552
|
-
const hasCalendar
|
|
2553
|
-
const hasSearch
|
|
2554
|
-
const hasCanvas
|
|
2555
|
-
const hasGitHub
|
|
2556
|
-
const hasSlack
|
|
2557
|
-
const hasNotion
|
|
2558
|
-
const hasBriefing
|
|
2559
|
-
const hasFinance
|
|
2560
|
-
const hasSecurity
|
|
2550
|
+
const hasEmail = /email|mail|inbox|posta/i.test(taskLow);
|
|
2551
|
+
const hasCalendar = /calendar|agenda|calendari|eventi|schedule/i.test(taskLow);
|
|
2552
|
+
const hasSearch = /cerca|search|notizie|news|ultime|latest|web|internet|tendenz|trend/i.test(taskLow);
|
|
2553
|
+
const hasCanvas = /html|dashboard|visua|report|grafico|chart/i.test(taskLow);
|
|
2554
|
+
const hasGitHub = /github|git|issue|pr|pull request/i.test(taskLow);
|
|
2555
|
+
const hasSlack = /slack|channel|messag/i.test(taskLow);
|
|
2556
|
+
const hasNotion = /notion|note|page/i.test(taskLow);
|
|
2557
|
+
const hasBriefing = /briefing|analisi|analizza|summary|sommario|riassunto|riepiloga|valutazione|valuta/i.test(taskLow);
|
|
2558
|
+
const hasFinance = /finance|mercato|market|stock|trading|finanz|investiment|cripto/i.test(taskLow);
|
|
2559
|
+
const hasSecurity = /security|sicurezza|vulnerabilit|audit|pentest|rischi|dipendenz/i.test(taskLow);
|
|
2560
|
+
const hasStrategy = /strateg|competitiv|posizionament|raccomandaz|competitive|positioning/i.test(taskLow);
|
|
2561
|
+
const hasReputation = /reputazion|reputation|online|brand|review|recension/i.test(taskLow);
|
|
2562
|
+
const hasCode = /codice|code|refactor|debug|bug|sviluppo|software|npm|package/i.test(taskLow);
|
|
2563
|
+
const hasWriting = /scrivi|write|articolo|article|blog|testo|text|documento|document/i.test(taskLow);
|
|
2564
|
+
const hasData = /dati|data|dataset|csv|json|analizza i dati|pattern|statistich/i.test(taskLow);
|
|
2565
|
+
const hasTranslate = /traduci|translate|traduzione|translation/i.test(taskLow);
|
|
2566
|
+
|
|
2567
|
+
const it = plannerLang === 'Italian';
|
|
2561
2568
|
|
|
2562
2569
|
// Extract a clean short search query from the task (to avoid SENTINEL flagging long task strings)
|
|
2563
2570
|
const extractSearchQuery = (t) => {
|
|
2564
|
-
|
|
2565
|
-
const m = t.match(/(?:cerca|search|find|ricerca|notizie su|news about|latest on|aggiornamenti su|ultime su)\s+(.{5,80}?)(?:\s+(?:e |and |per |for |poi |then )|[,\n]|$)/i);
|
|
2571
|
+
const m = t.match(/(?:cerca|search|find|ricerca|notizie su|news about|latest on|aggiornamenti su|ultime su|tendenz|trend)\s+(.{5,80}?)(?:\s+(?:e |and |per |for |poi |then )|[,\n]|$)/i);
|
|
2566
2572
|
if (m) return m[1].trim();
|
|
2567
|
-
// Strip leading instruction prefix (everything before the first colon)
|
|
2568
2573
|
const stripped = t.replace(/^[^:]+:\s*/,'').split(/[,\n]/)[0].slice(0,100).trim();
|
|
2569
2574
|
return stripped || t.slice(0,80).trim();
|
|
2570
2575
|
};
|
|
@@ -2573,29 +2578,35 @@ export async function cmdUI(args) {
|
|
|
2573
2578
|
// Build plan directly from keywords — reliable, fast, no SENTINEL risk
|
|
2574
2579
|
const buildKeywordPlan = () => {
|
|
2575
2580
|
const steps = [];
|
|
2576
|
-
if (hasEmail)
|
|
2577
|
-
if (hasCalendar) steps.push({icon:'\u{1F4C5}',agent:'CalendarAgent',label:
|
|
2578
|
-
if (hasGitHub)
|
|
2579
|
-
if (hasSlack)
|
|
2580
|
-
if (hasNotion)
|
|
2581
|
-
if (hasSearch || (!hasEmail && !hasCalendar && !hasGitHub && !hasSlack)) {
|
|
2582
|
-
steps.push({icon:'\u{1F50D}',agent:'WebSearchAgent',label:
|
|
2581
|
+
if (hasEmail) steps.push({icon:'\u{1F4E7}',agent:'EmailAgent', label:it?'Controlla email':'Check emails', prompt:'Read the latest unread emails and identify urgent items, deadlines, and required actions'});
|
|
2582
|
+
if (hasCalendar) steps.push({icon:'\u{1F4C5}',agent:'CalendarAgent', label:it?'Rivedi calendario':'Review calendar', prompt:'Check today\'s events and identify any scheduling conflicts or important meetings'});
|
|
2583
|
+
if (hasGitHub) steps.push({icon:'\u{1F4BB}',agent:'GitHubAgent', label:'GitHub', prompt:'Read open issues and pull requests, identify what needs attention'});
|
|
2584
|
+
if (hasSlack) steps.push({icon:'\u{1F4AC}',agent:'SlackAgent', label:'Slack', prompt:'Check recent Slack messages and identify important conversations'});
|
|
2585
|
+
if (hasNotion) steps.push({icon:'\u{1F4DD}',agent:'NotionAgent', label:'Notion', prompt:'Search Notion for relevant pages and notes'});
|
|
2586
|
+
if (hasSearch || hasReputation || (!hasEmail && !hasCalendar && !hasGitHub && !hasSlack)) {
|
|
2587
|
+
steps.push({icon:'\u{1F50D}',agent:'WebSearchAgent',label:it?'Ricerca web':'Web search',prompt:searchQuery});
|
|
2583
2588
|
}
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2589
|
+
// Specialist agents — can stack multiple
|
|
2590
|
+
if (hasSecurity) steps.push({icon:'\u{1F6E1}',agent:'cassandra', label:it?'CASSANDRA \u2014 Rischi sicurezza':'CASSANDRA \u2014 Security risks', prompt:'Analyze the collected data and identify security risks, vulnerabilities and concrete recommendations'});
|
|
2591
|
+
if (hasFinance) steps.push({icon:'\u{1F4B0}',agent:'mercury', label:it?'MERCURY \u2014 Analisi mercato':'MERCURY \u2014 Market analysis', prompt:'Analyze the financial data and market trends from the collected information'});
|
|
2592
|
+
if (hasStrategy) steps.push({icon:'\u{265F}', agent:'athena', label:it?'ATHENA \u2014 Strategia':'ATHENA \u2014 Strategy', prompt:'Based on the collected data, produce strategic analysis with competitive positioning and concrete recommendations'});
|
|
2593
|
+
if (hasReputation) steps.push({icon:'\u{1F52D}',agent:'oracle', label:it?'ORACLE \u2014 Reputazione':'ORACLE \u2014 Reputation', prompt:'Analyze the online reputation data, sentiment and brand positioning from the collected information'});
|
|
2594
|
+
if (hasCode) steps.push({icon:'\u{1F527}',agent:'forge', label:it?'FORGE \u2014 Analisi codice':'FORGE \u2014 Code analysis', prompt:'Analyze the code, dependencies and technical issues identified in the data'});
|
|
2595
|
+
if (hasWriting) steps.push({icon:'\u{1F58A}',agent:'quill', label:it?'QUILL \u2014 Redazione':'QUILL \u2014 Writing', prompt:'Write a polished, professional document based on all the collected information'});
|
|
2596
|
+
if (hasData) steps.push({icon:'\u{1F4CA}',agent:'DataAnalystAgent',label:it?'Analisi dati':'Data analysis', prompt:'Analyze the data and extract key patterns, trends and insights'});
|
|
2597
|
+
if (hasTranslate) steps.push({icon:'\u{1F310}',agent:'polyglot', label:it?'POLYGLOT \u2014 Traduzione':'POLYGLOT \u2014 Translation', prompt:'Translate the content as requested, maintaining meaning and style'});
|
|
2598
|
+
// If no specialist added but we have data, add HERALD for synthesis
|
|
2599
|
+
const hasSpecialist = hasSecurity || hasFinance || hasStrategy || hasReputation || hasCode || hasWriting || hasData || hasTranslate;
|
|
2600
|
+
if (!hasSpecialist && (hasBriefing || steps.length > 0)) {
|
|
2601
|
+
steps.push({icon:'\u{1F4F0}',agent:'HERALD',label:it?'HERALD \u2014 Briefing esecutivo':'HERALD \u2014 Executive briefing',prompt:'Based on ALL the data collected by the previous steps, write a complete executive briefing with priorities, findings, and strategic recommendations. Do NOT invent data — only use what was provided.'});
|
|
2590
2602
|
}
|
|
2591
|
-
if (hasCanvas) steps.push({icon:'\u{1F4CA}',agent:'CanvasAgent',label:
|
|
2603
|
+
if (hasCanvas) steps.push({icon:'\u{1F4CA}',agent:'CanvasAgent',label:it?'Dashboard HTML':'HTML Dashboard',prompt:'Create a professional HTML dashboard report with the briefing data'});
|
|
2592
2604
|
return steps;
|
|
2593
2605
|
};
|
|
2594
2606
|
|
|
2595
|
-
// Use keyword plan directly
|
|
2596
|
-
// Only fall back to LLM planning for genuinely ambiguous tasks
|
|
2607
|
+
// Use keyword plan directly — only fall back to LLM for genuinely ambiguous tasks
|
|
2597
2608
|
const keywordSteps = buildKeywordPlan();
|
|
2598
|
-
const taskIsComplex = !hasEmail && !hasCalendar && !hasSearch && !hasGitHub && !hasSlack && !hasBriefing && keywordSteps.length <= 1;
|
|
2609
|
+
const taskIsComplex = !hasEmail && !hasCalendar && !hasSearch && !hasGitHub && !hasSlack && !hasBriefing && !hasStrategy && !hasReputation && !hasCode && !hasWriting && !hasData && keywordSteps.length <= 1;
|
|
2599
2610
|
|
|
2600
2611
|
try {
|
|
2601
2612
|
let steps;
|
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.
|
|
8
|
+
export const VERSION = '13.2.41';
|
|
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/llm.mjs
CHANGED
|
@@ -624,10 +624,30 @@ function getProviderHeaders(provider, apiKey) {
|
|
|
624
624
|
}
|
|
625
625
|
|
|
626
626
|
/** Parse a complete SSE text body (already read via res.text()) and call onToken per token. */
|
|
627
|
+
/**
|
|
628
|
+
* Qwen3 sometimes emits entire paragraphs as a single token with no spaces/newlines.
|
|
629
|
+
* This restores markdown structure: newlines before headings, list items, numbered lists.
|
|
630
|
+
* Only applied to non-HTML content (inside HTML tags is left untouched).
|
|
631
|
+
*/
|
|
632
|
+
function fixQwen3Markdown(text) {
|
|
633
|
+
// Don't touch HTML content
|
|
634
|
+
if (/<[a-zA-Z]/.test(text) && text.includes('</')) return text;
|
|
635
|
+
return text
|
|
636
|
+
// newline before markdown headings (##, ###, etc.) not at start
|
|
637
|
+
.replace(/([^\n])(#{1,6}\s)/g, '$1\n$2')
|
|
638
|
+
// newline before list items (- or * at word boundary) not at start
|
|
639
|
+
.replace(/([^\n])(\n?[-*]\s)/g, '$1\n$2')
|
|
640
|
+
// newline before numbered list items (1. 2. etc.) not at start
|
|
641
|
+
.replace(/([^\n])(\n?\d+\.\s)/g, '$1\n$2')
|
|
642
|
+
// newline before --- separators
|
|
643
|
+
.replace(/([^\n])(---)/g, '$1\n$2');
|
|
644
|
+
}
|
|
645
|
+
|
|
627
646
|
function parseSSEText(text, format, onToken) {
|
|
628
647
|
let fullText = '';
|
|
629
648
|
let thinkBuf = '';
|
|
630
649
|
let inThink = false;
|
|
650
|
+
let isHtmlOutput = false;
|
|
631
651
|
|
|
632
652
|
for (const line of text.split('\n')) {
|
|
633
653
|
if (!line.startsWith('data: ')) continue;
|
|
@@ -661,11 +681,16 @@ function parseSSEText(text, format, onToken) {
|
|
|
661
681
|
}
|
|
662
682
|
}
|
|
663
683
|
if (out) {
|
|
664
|
-
//
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
684
|
+
// Detect HTML output on first meaningful token
|
|
685
|
+
if (!isHtmlOutput && (out.includes('<div') || out.includes('<!DOCTYPE') || out.includes('<html'))) {
|
|
686
|
+
isHtmlOutput = true;
|
|
687
|
+
}
|
|
688
|
+
if (!isHtmlOutput) {
|
|
689
|
+
out = fixQwen3Markdown(out);
|
|
690
|
+
const insideTag = fullText.lastIndexOf('<') > fullText.lastIndexOf('>');
|
|
691
|
+
if (fullText && out && !insideTag && !/[\s\n]$/.test(fullText) && !/^[\s\n.,;:!?)\]}'">]/.test(out)) {
|
|
692
|
+
out = ' ' + out;
|
|
693
|
+
}
|
|
669
694
|
}
|
|
670
695
|
fullText += out;
|
|
671
696
|
if (onToken) onToken(out);
|
|
@@ -685,6 +710,7 @@ async function streamSSEWithCallback(res, format, onToken) {
|
|
|
685
710
|
let fullText = '';
|
|
686
711
|
let thinkBuf = ''; // accumulates <think>...</think> content to suppress
|
|
687
712
|
let inThink = false;
|
|
713
|
+
let isHtmlOutput = false;
|
|
688
714
|
|
|
689
715
|
while (true) {
|
|
690
716
|
const { done, value } = await reader.read();
|
|
@@ -730,11 +756,15 @@ async function streamSSEWithCallback(res, format, onToken) {
|
|
|
730
756
|
}
|
|
731
757
|
}
|
|
732
758
|
if (out) {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
if (
|
|
737
|
-
out =
|
|
759
|
+
if (!isHtmlOutput && (out.includes('<div') || out.includes('<!DOCTYPE') || out.includes('<html'))) {
|
|
760
|
+
isHtmlOutput = true;
|
|
761
|
+
}
|
|
762
|
+
if (!isHtmlOutput) {
|
|
763
|
+
out = fixQwen3Markdown(out);
|
|
764
|
+
const insideTag2 = fullText.lastIndexOf('<') > fullText.lastIndexOf('>');
|
|
765
|
+
if (fullText && out && !insideTag2 && !/[\s\n]$/.test(fullText) && !/^[\s\n.,;:!?)\]}'">]/.test(out)) {
|
|
766
|
+
out = ' ' + out;
|
|
767
|
+
}
|
|
738
768
|
}
|
|
739
769
|
fullText += out;
|
|
740
770
|
if (onToken) onToken(out);
|
package/src/services/web-ui.mjs
CHANGED
|
@@ -2852,6 +2852,7 @@ var studioState = {
|
|
|
2852
2852
|
nodes: [], // [{icon,agent,label,status:'waiting'|'running'|'done'|'error'}]
|
|
2853
2853
|
log: [], // [{agent,icon,text,time,type:'agent'|'system'|'error'}]
|
|
2854
2854
|
result: '',
|
|
2855
|
+
canvas: null, // HTML canvas content if generated
|
|
2855
2856
|
running: false,
|
|
2856
2857
|
planned: false
|
|
2857
2858
|
};
|
|
@@ -2971,14 +2972,14 @@ function renderStudioResult() {
|
|
|
2971
2972
|
if (!el) return;
|
|
2972
2973
|
if (!studioState.result) { el.style.display = 'none'; return; }
|
|
2973
2974
|
el.style.display = 'block';
|
|
2974
|
-
var
|
|
2975
|
-
var body =
|
|
2975
|
+
var hasCanvas = !!(studioState.canvas);
|
|
2976
|
+
var body = hasCanvas
|
|
2976
2977
|
? '<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap"><span style="color:var(--dim);font-size:13px">✓ ' + t('canvas_generated') + '</span><button onclick="openCanvasPanel()" style="padding:6px 14px;background:var(--greendim);border:1px solid var(--green3);border-radius:8px;color:var(--green);font-size:12px;cursor:pointer;font-weight:700">▣ ' + t('canvas_open') + '</button></div>'
|
|
2977
2978
|
: '<div class="md-body">' + renderMd(studioState.result) + '</div>';
|
|
2978
2979
|
el.innerHTML = '<div class="studio-result__title">✓ ' + t('workflow_complete') + '</div>' + body;
|
|
2979
|
-
// Show
|
|
2980
|
+
// Show canvas button in toolbar whenever canvas data exists
|
|
2980
2981
|
var canvasBtn = document.getElementById('studioCanvasBtn');
|
|
2981
|
-
if (canvasBtn) canvasBtn.style.display =
|
|
2982
|
+
if (canvasBtn) canvasBtn.style.display = hasCanvas ? '' : 'none';
|
|
2982
2983
|
}
|
|
2983
2984
|
|
|
2984
2985
|
function studioSetNodeStatus(idx, status) {
|
|
@@ -2998,6 +2999,7 @@ async function runStudio() {
|
|
|
2998
2999
|
studioState.nodes = [];
|
|
2999
3000
|
studioState.log = [];
|
|
3000
3001
|
studioState.result = '';
|
|
3002
|
+
studioState.canvas = null;
|
|
3001
3003
|
studioState.running = true;
|
|
3002
3004
|
studioState.planned = false;
|
|
3003
3005
|
renderStudioNodes();
|
|
@@ -3233,6 +3235,7 @@ function runStudioStep(idx, node, task, context, stepDef, signal) {
|
|
|
3233
3235
|
}
|
|
3234
3236
|
if (ev.canvas) {
|
|
3235
3237
|
canvasHtml = ev.canvas;
|
|
3238
|
+
studioState.canvas = ev.canvas;
|
|
3236
3239
|
// Render canvas immediately when received — don't wait for step resolution
|
|
3237
3240
|
var cf2 = document.getElementById('canvasFrame');
|
|
3238
3241
|
var cp2 = document.getElementById('canvasPanel');
|
|
@@ -3240,10 +3243,10 @@ function runStudioStep(idx, node, task, context, stepDef, signal) {
|
|
|
3240
3243
|
cf2.srcdoc = canvasHtml;
|
|
3241
3244
|
cp2.classList.add('open');
|
|
3242
3245
|
var ct2 = document.getElementById('canvasTitle');
|
|
3243
|
-
if (ct2) ct2.textContent =
|
|
3246
|
+
if (ct2) ct2.textContent = \x27Studio Report\x27;
|
|
3244
3247
|
}
|
|
3245
3248
|
var scb = document.getElementById('studioCanvasBtn');
|
|
3246
|
-
if (scb) scb.style.display =
|
|
3249
|
+
if (scb) scb.style.display = \x27\x27;
|
|
3247
3250
|
}
|
|
3248
3251
|
if (ev.usage) { studioAddTokens(ev.usage.input||0, ev.usage.output||0); }
|
|
3249
3252
|
else if (ev.token && !isStatus) { studioTokens.out += Math.ceil(ev.token.length/4); studioUpdateTokenBar(); }
|